3. Исследование работы IA-32 в защищенном режиме
Цель работы: Познакомится с особенностями написания программы для защищенного режима. На примере конкретной программы пронаблюдать механизмы формирования линейного адреса в различных режимах работы процессора.
Теоретическая часть
Основным режимом работы 32-битных процессоров семейства IA-32 является защищенный. В реальном режиме происходит лишь инициализация системы, иногда он используется для выполнения старых приложений для процессоров 8086/88 и 80286. Механизмы защиты, многозадачность, страничное преобразование, полноценное выполнение 32-битного кода и многие другие возможности 32-битных процессоров доступны лишь в защищенном режиме.
Прежде, чем перевести процессор в защищенный режим, следует подготовить дескрипторные таблицы (глобальную и для прерываний), а также таблицы, необходимые для страничного преобразования (если система собирается его использовать). Переход в защищенный режим происходит после выставления младшего бита в регистре CR0 (MSW), затем следует выполнить далекий межсегментный переход (FAR JUMP) для очистки кэша команд:
MOV EAX,1 MOV CR0,EAX JMP DWORD PTR [PMEntry]
При использовании 32-битной операционной системы для защищенного режима пользовательским программам нет необходимости в таких действиях. Среду для защищенного режима подготавливает сама операционная система. Прикладная программа может считать, что уже работает в линейном 4Гбайтном пространстве.
Пример для Windows (tasm32) | Пример для Linux (nasm) |
---|---|
.386 ; "плоская" модель - для защищенного режима MODEL FLAT .DATA ; сегмент данных Msg DB "Hello, world",0 .CODE ; сегмент кода Entry: ; точка входа в программу SUB EBX,EBX PUSH EBX ; флаги (0=MB_OK) PUSH EBX ; адрес текста заголовка PUSH OFFSET Msg ; адрес контента PUSH EBX ; дескриптор окна ; вызов WinAPI MessageBox(NULL,Msg,NULL,MB_OK) CALL MessageBoxA PUSH EBX ; код возврата ; вызов WinAPI ExitProcess(0) CALL ExitProcess END Entry |
section .data ; сегмент данных Msg: DB "Hello, world",10 section .code ; сегмент кода global _start _start: ; точка входа в программу MOV ECX,Msg ; адрес буфера MOV EDX,13 ; длина сообщения l1: MOV EBX,1 ; дескриптор файла (stdout) ; вызов write(1,Msg,13) MOV EAX,4 INT 80h CMP EAX,-4096 JA skip ; в EAX кол-во выведенных байт ADD ECX,EAX SUB EDX,EAX JNZ l1 ; при необходимости выводим остаток skip: SUB EBX,EBX ; код возврата ; вызов exit(0) MOV EAX,1 INT 80h HLT |
Если операционная система не предназначена для работы в защищенном режиме (например, DOS), можно использовать различные системные средства для перехода в защищенный режим. Наиболее предпочтительны следующие средства (в порядке уменьшения предпочтительности):
- DPMI - DOS Protected Mode Interface (реализован в DOS/4G, Quarterdeck DPMI, Borland DOS Extender, а также во всех версиях Windows).
- VCPI - Virtual Control Program Interface (реализуется драйвером EMS).
- INT 15h (реализуется BIOS).
DPMI обеспечивает программам для DOS доступ к памяти выше 1Мб, предоставляя программный интерфейс к некоторым функциям BIOS и DOS в защищенном режиме. Этот интерфейс содержит функции, позволяющие программам в защищенном режиме резервировать память, дескрипторы, вызывать код в режиме V86.
Прежде, чем воспользоваться сервисами DPMI, программа должна переключиться в защищенный режим с помощью предназначенной для этого функции. Для перехода в защищенный режим программа должна сделать межсегментный вызов (FAR CALL) по адресу, возвращаемому функцией:
MOV AX,1687h INT 2Fh
Если DPMI присутствует, и вызов прошел успешно, AX=0, DX содержит версию DPMI, SI содержит количество параграфов, необходимых для служебных данных DPMI, а ES:DI - адрес процедуры переключения в защищенный режим. В случае ошибки AX - не ноль. Перед тем, как вызвать процедуру переключения, программа резервирует память указанного размера и помещает в ES соответствующий сегментный адрес.
TEST AX,AX JNZ Error MOV [PM_Entry+2],ES MOV [PM_Entry],DI MOV BX,SI MOV AH,48h INT 21h ; резервируем память под служебные данные DPMI ; перед использованием функции 48h ; программа должна вернуть DOS неиспользуемую память ; при помощи функции 4Ah MOV ES,AX
Кроме этого, процедура переключения рассматривает младший бит в регистре AX как признак 32-битного режима. Если бит выставлен, то после переключения программа будет выполняться в 32-битном сегменте кода.
SUB AX,AX CALL DWORD PTR [PM_Entry] JC Error
Если переключение прошло успешно, флаг переноса (CF) равен 0. Программа работает в защищенном режиме. Сегментные регистры содержат селекторы дескрипторов сегментов с соответствующими базовыми адресами и пределами в 64К (ES содержит селектор сегмента с PSP, его предел - 256 байт). В дальнейшем доступны сервисы DPMI, которые вызываются при помощи программного прерывания INT 31h. Завершение программы защищенного режима возможно при помощи функции AH=4Ch прерывания INT 21h. Спецификация DPMI декларирует доступность лишь этой функции DOS. Однако многие реализации, например, DPMI в Microsoft Windows, обеспечивают функционирование и других функций DOS (01h-0Ch - ввод с клавиатуры, вывод на экран; 39h-43h - работа с файлами и каталогами и некоторые другие).
Вот некоторые сервисы DPMI INT 31h (подробнее см. Tech! Help v.6.0):
Номер функции (значение AX) | Назначение |
---|---|
0000h | Зарезервировать дескриптор в LDT |
0001h | Освободить дескриптор в LDT |
0002h | Конвертировать сегмент реального режима в дескриптор |
0006h | Получить базовый адрес сегмента |
0007h | Установить базовый адрес сегмента |
0008h | Установить предел сегмента |
0009h | Установить права доступа дескриптора |
000Bh | Получить дескриптор |
000Ch | Установить дескриптор |
0100h | Зарезервировать память в DOS |
0101h | Освободить память в DOS |
0102h | Изменить размер памяти, зарезервированной в DOS |
02xxh | Получение и установка прерываний и исключений для реального и защищенного режима |
0300h | Вызов программного прерывания в реальном режиме |
0301h - 0302h | Вызов процедуры в реальном режиме |
0303h | Зарезервировать новый шлюз переключения из реального в защищенный режим |
0304h | Освободить шлюз переключения из реального в защищенный режим |
0306h | Получить шлюзы переключения между режимами |
0400h | Получить версию DPMI |
0500h | Получить информацию о свободной памяти |
0501h | Зарезервировать блок памяти |
0502h | Освободить блок памяти |
0503h | Изменить размер зарезервированного блока памяти |
06xxh | Управление подкачкой |
и др. |
Задание:
1) Напишите программу для Windows или для Linux, выводящую значения сегментных регистров. По этим значениям выясните уровень привилегий, с которым запущена ваша программа, а также в какой дескрипторной таблице содержатся дескрипторы, соответствующие селекторам.
Для того, чтобы использовать в программе вызовы Windows API, в тексте программы следует определить соответствующие символы как внешние, с помощью следующих директив ассемблера:
INCLUDELIB import32.lib EXTRN MessageBoxA:NEAR EXTRN ExitProcess:NEAR
При компиляции программы, используйте опцию /ml для того, чтобы в объектный файл эти символы были включены с учетом регистра. Компоновщику TLINK32 следует указать опцию /Tpe, отвечающую за генерацию исполняемого файла для Win32. При необходимости также укажите при помощи /L путь к библиотеке import32.lib (например, D:ASMLIB).
Стандартной для Linux ассемблерной семантикой является семантика AT&T, которая существенно отличается от принятой Intel (например, TASM/MASM для DOS и Windows). Однако существуют и средства для использования семантики Intel: as86 или nasm. В данной работе приведены примеры для использования nasm. Чтобы транслировать исходный текст test32.asm в исполняемый файл, необходимы следующие команды:
nasm -f elf test32.asm ld test32.o -o test32
Опция -f в команде nasm указывает формат выходного файла - ELF (executable linux format). В результате работы ассемблера nasm получается объектный файл test32.o, который необходимо обработать редактором связей ld. Опция -o в команде ld задает имя выходного файла. Если ее не указывать, исполняемый файл будет записан в a.out.
2) Напишите программу для DOS, которая использует DPMI для переключения в защищенный режим. После переключения программа получает дескриптор, соответствующий...
Вариант N1 | ...сегменту кода,... | |
---|---|---|
Вариант N2 | ...сегменту данных,... | |
Вариант N3 | ...сегменту стека,... | |
Вариант N4 | ...сегменту ES,... |
...а затем выводит содержимое дескриптора и сравнивает его базовый адрес со значением в сегментном регистре в реальном режиме.
При написании этой программы придется использовать функцию 000Bh сервиса DPMI. Входные параметры:
AX=000Bh;
BX - селектор запрашиваемого дескриптора;
ES:DI - указатель на 8-байтный буфер под дескриптор;
После успешного выполнения функции флаг переноса (CF) должен быть очищен.
Для вывода на экран можно использовать функцию DOS AH=09h INT 21h.
Контрольные вопросы:
- Каков формат селектора сегмента? По результатам выполнения программ в заданиях 1 и 2 выясните, с каким уровнем привилегий выполняется ваша программа в защищенном режиме, в какой дескрипторной таблице хранятся соответствующие дескрипторы.
- Как задается базовый адрес сегмента в реальном и защищенном режиме?
- Как задается предел сегмента в реальном и защищенном режиме?
- Каков формат дескриптора сегмента? По результатам выполнения программы в задании 2 выясните: тип дескриптора, уровень привилегий дескриптора, атрибуты сегмента, базовый адрес сегмента, предел сегмента.