[Назад] [Далее]

10.4.5. Нереальный режим

Как мы уже знаем, при изменении режима скрытые части сегментных регистров сохраняют содержимое своих дескрипторов и ими можно пользоваться. Мы осуществили эту возможность в нашем первом примере, когда значения, занесенные в сегментные регистры в реальном режиме, использовались в защищенном. Возникает вопрос — а если сделать наоборот? В защищенном режиме загрузить сегментные регистры дескрипторами 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
; и все - теперь процессор находится в реальном режиме
; с неограниченными сегментами

п»ї
"target=_blank><\/a>") //-->