Прикладные
программы для 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 монитор должен был
отслеживать все инструкции, влияющие на IF — CLI,
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.