Глава 10. Возврат в режим реальных адресов.
Практически защищённый режим процессора можно использовать двумя способами:
1. | Операционная система. Процессор входит в P-Mode при загрузке ОС и не возвращается в R-Mode. Примером таких ОС являются Windows 95 и старше либо специализированные ОС, управляющие контроллерами на базе 32-разрядных процессоров. |
2. | DOS-программа. Программа запускается в ОС, которая работает в R-Mode (например, MS-DOS), переходит в P-Mode, выполняет свою работу, возвращается обратно в R-Mode и завершает свою работу. Примеров множество: это hymem.sys, обеспечивающий через P-Mode работу с памятью выше 1-го мегабайта (XMS-память); также это игрушки, работающие через Dos4GW - предзагружаемую ОС защищённого режима; это Windows 3.xx. |
Второй способ, с возвратом в режим реальных адресов, предоставляет программисту больше возможностей - ведь не все пишут полнофункциональные операционные системы...
Фактически, переход в режим реальных адресов может быть только из защищённого режима и осуществляется сбросом бита PE в CR0:
mov eax,cr0 and al,0feh mov cr0,eax или так mov eax,cr0 btr eax,0 mov cr0,eax
Вы наверное уже догадались, что на самом деле не всё так просто. Действительно, выполнение трёх вышеприведенных команд переведёт процессор в R-Mode, но дальше он повиснет либо произойдёт аппаратный сброс, потому что программная среда не будет соответствовать режиму реальных адресов.
Для корректного перехода из P-Mode в R-Mode необходимо подготовить процессор следующим образом:
1. | Запретить прерывания (CLI). | ||||||||
2. | Передать управление в читаемый сегмент кода, имеющий предел в 64Кб (FFFFh). | ||||||||
3. | Загрузить в SS, DS, ES, FS и GS селекторы дескрипторов, имеющих следующие параметры:
Сегментные регистры должны быть загружены ненулевыми селекторами. Те сегментные регистры, в которые не будут загружены описанные выше значения, будут использоваться с атрибутами, установленными в защищённом режиме.
4.
| Сбросить флаг PE в CR0.
| 5.
| Выполнить команду far jmp на программу режима реальных адресов.
| 6.
| Загрузить в регистры SS, DS, ES, FS и GS необходимые значения или 0.
| 7.
| Разрешить прерывания (STI).
| |
В предыдущем примере (2) мы просто перевели процессор в защищённый режим, при этом не используя особенности прерываний в P-Mode и не подключали механизм виртуальной памяти. Реализация каждой из этих технологий немного усложнит возврат в R-Mode и в разделах, описывающих эти технологии будут приведены соответствующие примеры перехода в P-mode и возврата из него.
Здесь подразумевается, что вы уже ознакомились со всеми предыдущими главами, поэтому предварительного подробного описания перехода в R-Mode не будет и мы перейдём сразу к примеру.
Этот пример является полноценной программой и в нём без комментариев повторяется переход в P-Mode. Процесс подготовки дескрипторов и GDTR зависит от предназначения каждого примера и по этой причине я не вынес его в отдельную функцию а полностью описываю каждый раз.
Пример ориентирован на использование как самостоятельная .com-программа. Это сделано по следующим причинам:
1. | Пользоваться обычной программной средой - библиотеки языков высокого уровня, прерывания MS-DOS и прочими особенностями этой ОС из защищённого режима вы не сможете. |
2. | Размеры кода и данных в данном примере не большие и удобно использовать формат файла .com. |
3. | .com-программу можно просто загрузить в память как блок данных и, передав управление на смещение 100h, использовать как оверлей. |
4. | Вся мощь защищённого режима раскрывается при использовании 32-разрядного кода и данных. Инициализация защищённого режима должна происходить 16-разрядным кодом и 32-разрядные программы удобно использовать как отдельные модули. |
Также хочу обратить ваше внимание на то, что в этом примере адреса сегментов для защищённого режима совпадают с адресами сегментов, используемых в R-Mode. В результате, обращение к памяти происходит непосредственно через метки, определённые в исходнике (в предыдущем примере для этого требовалось из адреса метки вычитать адрес начала сегмента данных).
Пример используется вместе с файлом "pmode.lib".
Пример 3. Вход в защищённый режим и возврат в режим реальных адресов. include pmode.lib ;--------------------------------------------------------------------------- .386p pmode segment use16 assume cs:pmode, ds:pmode, es:pmode org 100h main proc far start: ;------------------------------------------------------------------------ ;------------------------------------------------------------------------ ; Определяем селекторы как константы. У всех у них биты TI = 0 (выборка ; дескрипторов производится из GDT), RPL = 00B - уровень привилегий - ; нулевой. Code_selector = 8 Stack_selector = 16 Data_selector = 24 Screen_selector = 32 R_Mode_Code = 40 ; Селектор дескриптора сегмента кода для возврата ; в режим реальных адресов. R_Mode_Data = 48 ; Селектор дескриптора сегментов стека и данных. ;------------------------------------------------------------------------ ; Сохраняем сегментные регистры, используемые в R-Mode: mov R_Mode_SS,ss mov R_Mode_DS,ds mov R_Mode_ES,es mov R_Mode_FS,fs mov R_Mode_GS,gs ; Подготавливаем адрес возврата в R-Mode: mov R_Mode_segment,cs lea ax,R_Mode_entry mov R_Mode_offset,ax ; Подготовка к переходу в защищённый режим: mov bx,offset GDT + 8 xor eax,eax mov edx,eax push cs pop ax shl eax,4 mov dx,1024 mov cl,10011000b call set_descriptor ; Code lea dx,Stack_seg_start add eax,edx mov dx,1024 mov cl,10010110b call set_descriptor ; Stack xor eax,eax mov ax,ds shl eax,4 mov dx,0ffffh mov cl,10010010b call set_descriptor ; Data mov eax,0b8000h mov edx,4000 mov cl,10010010b call set_descriptor ; Screen ; Готовим дополнительные дескрипторы для возврата в R-Mode: xor eax,eax push cs pop ax shl eax,4 ; EAX = физический адрес сегмента кода ; (и всех остальных сегментов, т.к. ; это .com-программа) mov edx,0ffffh mov cl,10011010b ; P=1, DPL=00b, S=1, Тип=101b, A=0 call set_descriptor ; R_Mode_Code mov cl,10010010b ; P=1, DPL=00b, S=1, Тип=001b, A=0 call set_descriptor ; R_Mode_Data ; Устанавливаем GDTR: xor eax,eax mov edx,eax mov ax,ds shl eax,4 lea dx,GDT add eax,edx mov GDT_adr,eax mov dx,55 ; Предел GDT = 8 * (1 + 6) - 1 mov GDT_lim,dx cli lgdt GDTR mov R_Mode_SP,sp ; Указатель на стек сохраняем в последний ; момент. ; Переходим в защищённый режим: mov eax,cr0 or al,1 mov cr0,eax ; Процессор в защищённом режиме db 0eah ; Команда far jmp Code_selector:P_Mode_entry. dw P_Mode_entry dw Code_selector ;------------------------------------------------------------------------ P_Mode_entry: mov ax,Screen_selector mov es,ax mov ax,Data_selector mov ds,ax mov ax,Stack_selector mov ss,ax mov sp,0 ; Сообщаем о входе в P-Mode (выводим ZS-строку): lea bx,Start_P_Mode_ZS mov di,480 call putzs ; Работа программы в защищённом режиме (здесь - только вывод строки): lea bx,P_Mode_ZS add di,160 call putzs ; Возвращаемся в режим реальных адресов. ; 1. Запретить прерывания (CLI). ; Прерывания уже запрещены при входе в P-Mode. ; 2. Передать управление в читаемый сегмент кода, имеющий предел в 64Кб. db 0eah ; Команда far jmp R_Mode_Code:Pre_R_Mode_entry. dw Pre_R_Mode_entry dw R_Mode_Code Pre_R_Mode_entry: ; 3. Загрузить в SS, DS, ES, FS и GS селекторы дескрипторов, имеющих ; следующие параметры: ; 1) Предел = 64 Кб (FFFFh) ; 2) Байтная гранулярность (G = 0) ; 3) Расширяется вверх (E = 0) ; 4) Записываемый (W = 1) ; 5) Присутствующий (P = 1) ; 6) Базовый адрес = любое значение mov ax,R_Mode_Data ; Селектор R_Mode_Data - "один на всех". mov ss,ax mov ds,ax mov es,ax mov fs,ax mov gs,ax ; 4. Сбросить флаг PE в CR0. mov eax,cr0 and al,0feh ; FEh = 1111'1110b mov cr0,eax ; 5. Выполнить команду far jump на программу режима реальных адресов. db 0eah R_Mode_offset dw ? ; Значения R_Mode_offset и R_Mode_segment R_Mode_segment dw ? ; сюда прописались перед входом в ; защищённый режим (в начале программы). ;------------------------------------------------------------------------ R_Mode_entry: ; 6. Загрузить в регистры SS, DS, ES, FS и GS необходимые значения или 0 ; (восстанавливаем сохранённые значения): mov ss,R_Mode_SS mov ds,R_Mode_DS mov es,R_Mode_ES mov fs,R_Mode_FS mov gs,R_Mode_GS mov sp,R_Mode_SP ; Восстанавливаем указатель стека ; непосредственно перед разрешением ; прерываний. ; 7. Разрешить прерывания (STI). sti ; Выводим ZS-строку "Back to real address mode..." lea bx,R_Mode_ZS mov ax,0b800h mov es,ax mov di,800 call putzs ; Функция putzs универсальна и работает ; в обоих режимах. int 20h ; Конец программы (здесь - выход в MS-DOS). ;------------------------------------------------------------------------ ; Вставка макросами кода функций, определённых в текстовом файле ; "pmode.lib": init_set_descriptor init_putzs ;------------------------------------------------------------------------ ; ZS-строка для вывода при входе в P-Mode: Start_P_Mode_ZS: db "Entering to protected mode...",0 ; ZS-строка для вывода при работе в P-Mode: P_Mode_ZS: db "Working in P-mode...",0 ; ZS-строка для вывода в R-Mode: R_Mode_ZS: db "Back to real address mode...",0 ;------------------------------------------------------------------------ ; Значения регистров, которые программа имела до перехода в P-Mode: R_Mode_SP dw ? R_Mode_SS dw ? R_Mode_DS dw ? R_Mode_ES dw ? R_Mode_FS dw ? R_Mode_GS dw ? ;------------------------------------------------------------------------ ; Образ регистра GDTR: GDTR label fword GDT_lim dw ? GDT_adr dd ? ;------------------------------------------------------------------------ GDT: dd ?,? ; 0-й дескриптор dd ?,? ; 1-й дескриптор (кода) dd ?,? ; 2-й дескриптор (стека) dd ?,? ; 3-й дескриптор (данных) dd ?,? ; 4-й дескриптор (видеопамяти) dd ?,? ; 5-й дескриптор (код для перехода в R-Mode) dd ?,? ; 6-й дескриптор (стек и данные для перехода в R-Mode) ;------------------------------------------------------------------------ db 1024 dup (?) ; Зарезервировано для стека. Stack_seg_start: ; Последняя метка программы - отсюда будет расти стек. ;------------------------------------------------------------------------ main endp pmode ends end start
Оглавление | Вопросы? Замечания? Пишите: sasm@narod.ru |
Copyright © Александр Семенко. |