6. Режим виртуального 8086.

(V86 и EV86)

 

Прикладные программы для 8086 могут исполняться на 32-разрядных процессорах, как в реальном режиме, так и в режиме виртуального 8086 (V86), кото­рый является особым состоянием задачи защищенного режима. Назначение этого режима — формирование виртуальной машины, эмулирующей процессор 8086. Виртуальная машина формируется программными средствами операцион­ной системы — монитором V86, который поддерживается специальными аппа­ратными средствами процессора. Режим V86 позволяет пользоваться аппарат­ными средствами поддержки многозадачности. В этом режиме работает защита и механизм страничной переадресации, позволяющий адресоваться к любой области 4-гигабайтного пространства физической памяти, где формируется структура, аналогично адресному пространству памяти процессора 8086 (1Мб). Выполнение приложе­ний 8086 в среде V86 возможно параллельно с приложениями защищенного режима. Страничная переадресация позволяет параллельно выполняться несколь­ким задачам V86 с возможностью совместного использования общих областей кода операционной системы и разделения реальных аппаратных ресурсов компьютера. Режим V86 появился с процессором 80386, в процессорах Pentium и последних моделях 486 появилось его расширение — EV86 (Enhanced Virtual 8086). Цель этого расширения заключалась в переносе ряда функций формиро­вания виртуальной машины с программного обеспечения на аппаратные средст­ва процессора, что существенно повышает ее производительность.

Монитор V86 представляет собой модуль 32-битного программного кода, ис­полняющийся с CPL=0. Он содержит обработчики прерываний и исключений, средства инициализации задач V86 и эмуляции операций ввода/вывода. Мони­тор тесно связан с обработчиком исключения #GP, через который в основном и происходит общение с приложениями 8086.

Приложение реального режима может работать только в среде своей ОС (например, MS-DOS) и пользоваться ее сервисами. В V86, ОС реального режима может работать на той же виртуальной машине, что и приложение, а может и эмулироваться сред­ствами ОС защищенного режима. Первый способ проще — здесь в V86 может быть запущена традиционная ОС (например, MS-DOS). Второй способ требует затрат на разработку эмуляции, но только в этом случае можно получить все преимущества реальной многозадачности.

В режиме V86 программе доступны все регистры 8086, а с помощью префик­са изменения разрядности операндов — и их 32-битные расширения. В качестве сегментных регистров через префиксы замены сегментов возможно использова­ние и регистров GS и FS, которых в реальном 8086 нет. То есть виртуальный режим эмулирует реальный режим тогоже процессора (с доступным для него набором команд реального режима). По умолчанию адресация 16-битная, но с помощью префикса изменения разрядности адреса возможно использование 32-битной адресации. По­пытка выполнения инструкций, ориентированных на использование операцион­ной системой и допустимых только для защищенного режима — LTR, STR, LLDT, SLDT, LAP, LSL, ARPL, VERR и VERW, - вызовет исключение #UD.

Модель памяти в режиме V86 имеет некоторые особенности. Одним из ос­новных различий реального и защищенного режимов является трактовка содер­жимого сегментных регистров. В режиме V86, как и в реальном, для получения линейного адреса содержимое сегментных регистров сдвигается на четыре раз­ряда влево и суммируется с эффективным адресом. Один мегабайт (точнее, область 0-10FFEFh) адресуемого таким образом пространства с помощью стра­ничной трансляции может отображаться в любую область 4 Гбайт физической памяти. С помощью страничной трансляции можно добиться «сворачивания в кольцо» памяти размером 1 Мбайт, свойственного 8086 (отобразив адреса выше FFFFFh на ту же физическую память, что и начинающиеся с нуля). Поскольку таблица трансляции задается управляющим регистром CR3, в многозадачном окружении при переключении задач автоматически загрузится и требуемая таблица трансляции. Превышение исполнительным адресом границы 64 Кбайт (в том числе при 32-битной адресации) вызывает исключение #SS или #GP. На­стоящий 8086 в таком случае переходит к нулевым адресам того же сегмента, как бы свернувшегося в кольцо. Все программы, запущенные в режиме V86, выполняются со всеми проверками защиты. Они автоматически получают уровень привилегий 3, то есть минимальные привилегии (реальный режим подразумевает уровень привилегий 0). Попытка выполнения привилегированных инструкций вызывает исключение #GP. К этим инструкциям относятся LIDT, LGDT, LMSW, CTS, HLT, a также операции с регист­рами DRn, TRn, CRn, MSR.

В режиме V86 понятие чувствительности к уровню привилегий при вводе/выводе (IOPL-sensitive) имеет особую трактовку. Инструкции ввода/вы­вода IN, OUT, (REP) INS, (REP) OUTS в режиме V86 не чувствительны к IOPL, а управление доступом к портам осуществляется только через битовую карту ввода/вывода в сегменте состояния задачи (см. предыдущую главу). Попытка обращения к запрещен­ным портам вызовет исключение #GP. Битовая карта может быть усеченной (это достигается сочетанием лимита TSS и смещения карты разрешения), тогда «отрезанные» адреса будут соответствовать запрещенным портам.

Особую проблему в режиме V86 составляет обработка прерываний — как программных, так и аппаратных. Здесь чувствительными являются инструк­ции INT n, PUSHF, POPF, STI, CLI и IRET, которые могут воздействовать на флаг прерываний IF. Однако инструкции INT3, INTO и BOUND не чувствительны к IOPL.

Если установить IOPL=3, то задача, исполняемая в V86, будет выполняться с максимальной производительностью, имея возможность непосредственно управ­лять флагом прерываний IF. Однако для многозадачных систем защищенного режима такие «вольности» не допустимы, поскольку ОС может быть легко лишена возможности управления системой. Чтобы этого не происходило, ОС до­лжна сделать виртуальным флаг IF для задач V86, для чего устанавливают IOPL<3. Это приводит к тому, что все чувствительные инструкции задачи V86, приводящие к изменениям флага IF, будут вызывать исключения-отка­зы, по которым будет производиться переключение в монитор виртуальных машин (часть многозадачной ОС защищенного режима). Однако частая об­работка этих исключений значительно снизит производительность виртуаль­ной машины V86.

Инструкции INT n, которые широко используются, например, в сервисах DOS и BIOS, приводят к выходу из режима V86. Все прерывания и исключения влекут за собой смену уровня привилегий на уровень операционной системы защищенного режима. Если IOPL<3, то все прерывания через исключения-отказы приводят к выходу в монитор виртуальной машины. При IOPL<3 прерывания вызывают исполнения соответствующих процедур защищенного режима, кото­рые задаются ОС (приложения 8086 «не понимают» таких обработчиков). Обработчик, заданный ОС, может распознать, что прерывание пришло из V86, по образу регистра EFLAGS в стеке. Далее ОС может либо обработать это прерыва­ние самостоятельно, эмулируя выполнение требуемых функций, либо переслать его к ОС реального режима, работающей в V86 (reflecting interrupt — отраже­ние прерывания). Частые переключения режимов (задач), которые происходят при выполнении прерываний, снижают производительность.

Приложение 8086, которое должно обрабатывать аппаратные прерывания, может получать их как в реальном виде (как внешние прерывания), так и в виртуальном. В режиме V86 виртуализация прерываний выполняется программно монитором ОС.

В конечном итоге ОС защищенного режима может прозрачно для приложе­ния 8086, работающего в режиме V86, эмулировать окружение обычной машины 8086, включая прерывания и перехват обращения к портам. Однако при IOPL<3, обеспечивающем устойчивость системы с полной виртуализацией, производи­тельность виртуальной машины будет низкой.

Проблему виртуализации прерываний позволяет разрешить расширенный режим — EV86 (у процессоров Pentium). При IOPL=3 приложение 8086 по-прежнему имеет возможность управления флагом IF (инструкциями CLI, STI). Изменения касаются работы при IOPL<3. Теперь чувствительные инструкции не вызывают безусловного исклю­чения-отказа, а воздействуют на виртуальную версию флага прерываний VIF в регистре EFLAGS. Этот флаг не влияет на восприятие процессором внешних (маскируемых) прерываний, а лишь указывает на состояние задачи EV86 — разрешила или запретила она обработку прерываний. При этом, во-первых, повышается производительность — инструкции CLI и STI теперь не приводят к отказам, а во-вторых, упрощается монитор, обеспечивающий программную виртуализацию флага прерываний (в V86 монитор должен был отслеживать все инструкции, влия­ющие на IFCLI, STI, PUSHF, POPF, INT и IRET). Аппаратная виртуализация флага приводит к значительному повышению производительности.

Режим EV86 включается установкой бита VME в регистре CR4. В этом режиме сегмент состояния задачи TSS-386 приобретает новую 32-байтную структуру арту перенаправления прерываний (interrupt redirection bitmap). По структу­ре она напоминает карту разрешения портов ввода/вывода и располагается в TSS прямо перед ней - слово IO_BITMAP_OFFSET является указателем на ее конец (см. предыдущую главу рис. 5.2). Каждый бит карты перенаправления соответствует одному из 256 (32x8) программных прерываний, вызываемых инструкцией INT п. На программные прерывания, вызываемые иным образом, исключения и аппарат­ные прерывания карта перенаправления действия не оказывает. Если бит уста­новлен, то соответствующее прерывание вызовет исключение-отказ с выходом из EV86 в монитор. Если бит сброшен, прерывание обрабатывается процедурой реального режима без выхода из EV86.

Для работы с IOPL<3 предназначены новые флаги — VIF и VIP. Эти флаги может анализировать и модифицировать только монитор, работающий на уров­не CPL=0. Теперь инструкции задачи EV86, связанные с флагом IF, не приводят к выходу в монитор по исключению-отказу, а воздействуют только на флаг VIF, не затрагивая реального флага управления прерываниями IF, Однако этот факт от приложения EV86 скрывается — везде вместо IF подставляется VIF. Флаг VIF является указателем для монитора на состояние задачи EV86 — запрещены или разрешены прерывания. Если монитор должен сообщить задаче EV86 о внеш­нем прерывании, то в случае, если прерывания задачей разрешены, он это может сделать сразу. Если прерывания запрещены (VIF=0), монитор установит флаг ожидающего прерывания VIР. Теперь, как только задача EV86 попытается разрешить прерывания, исполнив инструкцию STI или иным способом, до фак­тической установки флага VIF выработается исключение-отказ #GP, по которому монитор получит управление и вызовет процедуру обслуживания ожидающего прерывания. Флаги VIF и VIР позволяют существенно упростить виртуализацию прерываний монитором и повысить производительность.

Новые возможности виртуализации прерываний работают при IOPL<3, однако инструкция PUSHF в режиме EV86 симулирует IОРL=3, так что задача EV86 не сможет определить свой реальный IOPL по образу регистра EFLAGS в стеке. Пове­дение процессора в режиме EV86 при IOPL=3 иначе как удивительным не назовешь, но для такого «беззащитного» варианта этот режим, пожалуй, и не нужен.

Вход в режим V86 - установка бита VM в регистре EFLAGS — возможен одним из двух способов:

 

· Выполнение инструкции IRET в 32-битном режиме, когда образ EFLAGS со­хранен в стеке с установленным битом VM (при CPL=0, иначе бит VM не установится);

· Переключение на задачу-386, у которой в TSS образ EFLAGS имеет установленный бит VM.

 

При использовании режима EV86 необходимо также установить бит VME в регистре CR4.

Выход из режима V86 (EV86) возможен только при обработке прерывания. Если вызываемая процедура имеет CPL=0, то бит VM будет сброшен, и она будет выполняться в защищенном режиме. Если ее CPL>0, произойдет исключение #GP — нарушение защиты. Если прерывание вызывает переключение задач, со­стояние регистров с установленным флагом VM сохранится в TSS старой задачи, к которой можно будет вернуться. Новый режим (защищенный или V86) уста­новится в соответствии с TSS новой задачи.

Значение бита VM не может быть изменено никакими другими способами; кроме того, его значение не может быть прочитано — при любом программном сохранении регистра флагов значение VM всегда показывается нулевым. Так что приложение, выполняемое в среде V86, никак не может ни переключить режим процессора, ни распознать, в каком режиме — реальном или виртуальном - оно исполняется. Это, конечно же, справедливо при корректно построенном мо­ниторе виртуальной машины V86, являющимся частью ОС защищенного режи­ма. Процессор для этого предоставляет все необходимые аппаратные средства, позволяющие выполнить полную эмуляцию 8086.