|
| [Назад] [Далее] | |
Как мы уже знаем, при изменении режима скрытые части сегментных регистров сохраняют содержимое своих дескрипторов и ими можно пользоваться. Мы осуществили эту возможность в нашем первом примере, когда значения, занесенные в сегментные регистры в реальном режиме, использовались в защищенном. Возникает вопрос — а если сделать наоборот? В защищенном режиме загрузить сегментные регистры дескрипторами 4-гигабайтных сегментов с базой 0 и перейти в реальный режим? Оказывается, что это прекрасно срабатывает, и мы попадем в особый режим, который был обнаружен одновременно разными программистами и называется нереальным режимом (unreal mode), большим реальным режимом (BRM) или реальным flat-режимом (RFM). Чтобы перейти в нереальный режим, надо загрузить в CS перед переходом в реальный режим дескриптор 16-битного сегмента кода с базой 0 и лимитом 4 Гб и в остальные сегментные регистры — точно такие же дескрипторы сегментов данных.
Теперь весь дальнейший код программы, написанный для реального режима, больше не ограничен рамками 64-килобайтных сегментов и способен работать с любыми массивами. Можно подумать, что первый же обработчик прерывания от таймера загрузит в CS нормальное значение и все станет как обычно, но нет. Оказывается, что при создании дескриптора в скрытой части сегментного регистра в реальном режиме процессор не трогает поле лимита, а только изменяет базу: что бы мы ни записали в сегментный регистр, сегмент будет иметь размер 4 Гб. Если попробовать вернуться в DOS — DOS будет по-прежнему работать. Можно запускать программы такого рода:
.model tiny
.code
org 100h
start: xor ax,ax
mov ds,ax ; DS = 0
; вывести символ в видеопамять:
mov word ptr ds:[0B8000h],8403h
ret
end start
и они тоже будут работать. Единственное, что отключает этот режим, — программы, переключающиеся в защищенный режим и обратно, устанавливающие границы сегментов в 64 Кб, например любые программы, использующие расширители DOS.
Нереальный режим — идеальный вариант для программ, которые хотят пользоваться 32-битной адресацией и свободно обращаться ко всем прерываниям BIOS и DOS (традиционный способ состоял бы в работе в защищенном режиме с переключением в V86 для вызова BIOS или DOS, как это делается в случае DPMI).
Для переключения в этот режим можно воспользоваться, например, такой процедурой:
; область данных:
GDT label byte
db 8 dup(0) ; нулевой дескриптор
; 16-битный 4 Гб сегмент:
db 0FFh,0FFh,0,0,0,1001001b,11001111b,0
gdtr dw 16 ; размер GDI
gdt_base dd ? ; линейный адрес GDT
; код программы
; определить линейный адрес GDT
xor еах,еах
mov ax,cs
shl eax,4
add ax,offset GDT
; загрузить GDT из одного дескриптора (не считая нулевого)
mov gdt_base,eax
lgdt fword ptr gdtr
; перейти в защищенный режим
cli
mov eax,cr0
or al,1
mov cr0,eax
jmp start_PM ; сбросить очередь предвыборки
; Intel рекомендует
start_PM: ; делать jmp после каждой смены режима
; загрузить все сегментные регистры дескриптором с лимитом 4 Гб
mov ax,8 ; 8 - селектор нашего дескриптора
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax ; перейти в реальный режим
mov eax,cr0
and al,0FEh
mov cr0,eax
jmp exit_PM
exit_PM:
; записать что-нибудь в каждый сегментный регистр
хог ах,ах
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax
sti
mov ax,cs
mov ds,ax
; и все - теперь процессор находится в реальном режиме
; с неограниченными сегментами