§ Возврат в режим реальных адресов
Практически защищённый режим процессора можно использовать двумя способами:- Операционная система. Процессор входит в P-Mode при загрузке ОС и не возвращается в R-Mode. Примером таких ОС являются Windows 95 и старше либо специализированные ОС, управляющие контроллерами на базе 32-разрядных процессоров.
- DOS-программа. Программа запускается в ОС, которая работает в R-Mode (например, MS-DOS), переходит в P-Mode, выполняет свою работу, возвращается обратно в R-Mode и завершает свою работу. Примеров множество: это hymem.sys, обеспечивающий через P-Mode работу с памятью выше 1-го мегабайта (XMS-память); также это игрушки, работающие через Dos4GW - предзагружаемую ОС защищённого режима; это Windows 3.xx.
Фактически, переход в режим реальных адресов может быть только из защищённого режима и осуществляется сбросом бита PE в CR0:
1mov eax, cr0 2and al, 0feh 3mov cr0, eaxили так:
1mov eax, cr0 2btr eax, 0 3mov cr0, eaxВы наверное уже догадались, что на самом деле не всё так просто. Действительно, выполнение трёх вышеприведенных команд переведёт процессор в R-Mode, но дальше он повиснет либо произойдёт аппаратный сброс, потому что программная среда не будет соответствовать режиму реальных адресов.
Для корректного перехода из P-Mode в R-Mode необходимо подготовить процессор следующим образом:
- Запретить прерывания (CLI)
- Передать управление в читаемый сегмент кода, имеющий предел в 64Кб (FFFFh)
- Предел = 64 Кб (FFFFh)
- Байтная гранулярность (G = 0)
- Расширяется вверх (E = 0)
- Записываемый (W = 1)
- Присутствующий (P = 1)
- Базовый адрес = любое значение
- Сбросить флаг PE в CR0
- Выполнить команду far jmp на программу режима реальных адресов
- Загрузить в регистры SS, DS, ES, FS и GS необходимые значения или 0
- Разрешить прерывания (STI)
Здесь подразумевается, что вы уже ознакомились со всеми предыдущими главами, поэтому предварительного подробного описания перехода в R-Mode не будет и мы перейдём сразу к примеру.
Этот пример является полноценной программой и в нём без комментариев повторяется переход в P-Mode. Процесс подготовки дескрипторов и GDTR зависит от предназначения каждого примера и по этой причине я не вынес его в отдельную функцию а полностью описываю каждый раз.
Пример ориентирован на использование как самостоятельная .com-программа. Это сделано по следующим причинам:
- Пользоваться обычной программной средой - библиотеки языков высокого уровня, прерывания MS-DOS и прочими особенностями этой ОС из защищённого режима вы не сможете.
- Размеры кода и данных в данном примере не большие и удобно использовать формат файла .com.
- COM-программу можно просто загрузить в память как блок данных и, передав управление на смещение 100h, использовать как оверлей.
- Вся мощь защищённого режима раскрывается при использовании 32-разрядного кода и данных. Инициализация защищённого режима должна происходить 16-разрядным кодом и 32-разрядные программы удобно использовать как отдельные модули.
Пример используется вместе с файлом "pmode.lib.asm".
Пример 3. Вход в защищённый режим и возврат в режим реальных адресов.
1 org 100h 2;------------------------------------------------------------------------ 3; Определяем селекторы как константы. У всех у них биты TI = 0 (выборка 4; дескрипторов производится из GDT), RPL = 00B - уровень привилегий - 5; нулевой. 6 7 Code_selector equ 8 8 Stack_selector equ 16 9 Data_selector equ 24 10 Screen_selector equ 32 11 R_Mode_Code equ 40 ; Селектор дескриптора сегмента кода для возврата в режим реальных адресов 12 R_Mode_Data equ 48 ; Селектор дескриптора сегментов стека и данных 13 14;------------------------------------------------------------------------ 15 16; Сохраняем сегментные регистры, используемые в R-Mode: 17 18 mov [R_Mode_SS], ss 19 mov [R_Mode_DS], ds 20 mov [R_Mode_ES], es 21 mov [R_Mode_FS], fs 22 mov [R_Mode_GS], gs 23 24; Подготавливаем адрес возврата в R-Mode: 25 26 mov [R_Mode_segment], cs 27 lea ax, [R_Mode_entry] 28 mov [R_Mode_offset], ax 29 30; Подготовка к переходу в защищённый режим: 31 32 mov bx, GDT + 8 33 xor eax, eax 34 mov edx, eax 35 36 push cs 37 pop ax 38 39 shl eax, 4 40 mov dx, 65535 41 mov cl, 10011000b 42 call set_descriptor ; Code 43 44 lea dx, [Stack_seg_start] 45 add eax, edx 46 mov dx, 1024 47 mov cl, 10010110b 48 call set_descriptor ; Stack 49 50 xor eax, eax 51 mov ax, ds 52 shl eax, 4 53 mov dx,0ffffh 54 mov cl, 10010010b 55 call set_descriptor ; Data 56 57 mov eax, 0b8000h 58 mov edx, 4000 59 mov cl, 10010010b 60 call set_descriptor ; Screen 61 62; Готовим дополнительные дескрипторы для возврата в R-Mode: 63 64 xor eax,eax 65 push cs 66 pop ax 67 shl eax, 4 ; EAX = физический адрес сегмента кода 68 ; (и всех остальных сегментов, т.к. 69 ; это .com-программа) 70 71 mov edx,0ffffh 72 mov cl, 10011010b ; P=1, DPL=00b, S=1, Тип=101b, A=0 73 call set_descriptor ; R_Mode_Code 74 75 mov cl, 10010010b ; P=1, DPL=00b, S=1, Тип=001b, A=0 76 call set_descriptor ; R_Mode_Data 77 78; Устанавливаем GDTR: 79 80 xor eax, eax 81 mov edx, eax 82 83 mov ax, ds 84 shl eax, 4 85 lea dx, [GDT] 86 add eax, edx 87 mov [GDT_adr],eax 88 89 mov dx, 55 ; Предел GDT = 8 * (1 + 6) - 1 90 mov [GDT_lim], dx 91 92 cli 93 lgdt [GDTR] 94 mov [R_Mode_SP], sp ; Указатель на стек сохраняем в последний момент. 95 96; Переходим в защищённый режим: 97 98 mov eax, cr0 99 or al, 1 100 mov cr0, eax 101 102; Процессор в защищённом режиме 103 104 db 0eah ; Команда far jmp Code_selector:P_Mode_entry. 105 dw P_Mode_entry 106 dw Code_selector 107 108 include "pmode.lib.asm" 109 110;------------------------------------------------------------------------ 111P_Mode_entry: 112 113 mov ax, Screen_selector 114 mov es, ax 115 116 mov ax, Data_selector 117 mov ds, ax 118 119 mov ax, Stack_selector 120 mov ss, ax 121 mov sp, 0 122 123; Сообщаем о входе в P-Mode (выводим ZS-строку): 124 125 lea bx, [Start_P_Mode_ZS] 126 mov di, 480 127 call putzs 128 129; Работа программы в защищённом режиме (здесь - только вывод строки): 130 131 lea bx, [P_Mode_ZS] 132 add di, 160 133 call putzs 134 135; ---------------------------------------------------------------------- 136; Возвращаемся в режим реальных адресов. 137; 1. Запретить прерывания (CLI). 138; Прерывания уже запрещены при входе в P-Mode. 139 140; 2. Передать управление в читаемый сегмент кода, имеющий предел в 64Кб. 141; ---------------------------------------------------------------------- 142 143 db 0eah ; Команда far jmp R_Mode_Code:Pre_R_Mode_entry. 144 dw Pre_R_Mode_entry 145 dw R_Mode_Code 146 147 148Pre_R_Mode_entry: 149 150; 3. Загрузить в SS, DS, ES, FS и GS селекторы дескрипторов, имеющих 151; следующие параметры: 152; 1) Предел = 64 Кб (FFFFh) 153; 2) Байтная гранулярность (G = 0) 154; 3) Расширяется вверх (E = 0) 155; 4) Записываемый (W = 1) 156; 5) Присутствующий (P = 1) 157; 6) Базовый адрес = любое значение 158 159 mov ax, R_Mode_Data ; Селектор R_Mode_Data - "один на всех". 160 mov ss, ax 161 mov ds, ax 162 mov es, ax 163 mov fs, ax 164 mov gs, ax 165 166; 4. Сбросить флаг PE в CR0. 167 168 mov eax, cr0 169 and al, 0feh ; FEh = 1111'1110b 170 mov cr0, eax 171 172; 5. Выполнить команду far jump на программу режима реальных адресов. 173 174 db 0eah 175 R_Mode_offset dw ? ; Значения R_Mode_offset и R_Mode_segment 176 R_Mode_segment dw ? ; сюда прописались перед входом в 177 ; защищённый режим (в начале программы). 178;------------------------------------------------------------------------ 179R_Mode_entry: 180 181; 6. Загрузить в регистры SS, DS, ES, FS и GS необходимые значения или 0 182; (восстанавливаем сохранённые значения): 183 184 mov ss, [R_Mode_SS] 185 mov ds, [R_Mode_DS] 186 mov es, [R_Mode_ES] 187 mov fs, [R_Mode_FS] 188 mov gs, [R_Mode_GS] 189 mov sp, [R_Mode_SP] ; Восстанавливаем указатель стека 190 ; непосредственно перед разрешением 191 ; прерываний. 192 193; 7. Разрешить прерывания (STI). 194 195 sti 196 197; Выводим ZS-строку "Back to real address mode..." 198 199 lea bx, [R_Mode_ZS] 200 mov ax, 0b800h 201 mov es, ax 202 mov di, 800 203 call putzs ; Функция putzs универсальна и работает 204 ; в обоих режимах. 205 206 int 20h ; Конец программы (здесь - выход в MS-DOS). 207 208;------------------------------------------------------------------------ 209; ZS-строка для вывода при входе в P-Mode: 210Start_P_Mode_ZS: db "Entering to protected mode...",0 211 212; ZS-строка для вывода при работе в P-Mode: 213P_Mode_ZS: db "Working in P-mode...",0 214 215; ZS-строка для вывода в R-Mode: 216R_Mode_ZS: db "Back to real address mode...",0 217 218;------------------------------------------------------------------------ 219; Значения регистров, которые программа имела до перехода в P-Mode: 220R_Mode_SP dw ? 221R_Mode_SS dw ? 222R_Mode_DS dw ? 223R_Mode_ES dw ? 224R_Mode_FS dw ? 225R_Mode_GS dw ? 226;------------------------------------------------------------------------ 227; Образ регистра GDTR: 228 229GDTR: 230GDT_lim dw ? 231GDT_adr dd ? 232;------------------------------------------------------------------------ 233GDT: 234 dd ?,? ; 0-й дескриптор 235 dd ?,? ; 1-й дескриптор (кода) 236 dd ?,? ; 2-й дескриптор (стека) 237 dd ?,? ; 3-й дескриптор (данных) 238 dd ?,? ; 4-й дескриптор (видеопамяти) 239 dd ?,? ; 5-й дескриптор (код для перехода в R-Mode) 240 dd ?,? ; 6-й дескриптор (стек и данные для перехода в R-Mode) 241;------------------------------------------------------------------------ 242 db 1024 dup (?) ; Зарезервировано для стека. 243 244Stack_seg_start: ; Последняя метка программы - отсюда будет расти стек.