Сегмент данных размером 4 Гб
Простая программка, переводящая процессор в защищенный режим, загружающая FS селектором 4-х гигабайтного сегмента данных и переключающаяся обратно в реальный режим.
; fs4gb.asm ; Программа, устанавливающая размер сегмента, адерсуемого регистром FS, 4 Гб .model tiny .code .386p org 100h ;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; Структуры ; ;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Сегментный дескриптор segment_descriptor struct limit_low dw 0 ; Младшие два байта поля Segment limit base_low dw 0 ; Младшие два байта поля Base Address base_high0 db 0 ; Второй байт поля Base Address type_and_permit db 0 ; Флаги flags db 0 ; Ещё одни флаги base_high1 db 0 ; Старший байт поля Base Address segment_descriptor ends ; Регистр, описывающий GDT table_register struct limit dw 0 ; Table Limit base dd 0 ; Linear Base Address table_register ends ;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; Код ; ;;;;;;;;;;;;;;;;;;;;;;;;;; start: ; Подготавливаем DS push cs pop ds ; Открываем вентиль A20 call open_A20 ; Запрещаем прерывания call disable_interrupts ; Инициалиируем GDT call initialize_gdt ; Переключаем режим call set_PE ; загрузить новый селектор в регистр FS mov ax, 8 mov fs, ax call clear_PE call enable_interrupts ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Данные ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Глобальная таблица дескрипторов GDT label byte ; Нулевой дескриптор segment_descriptor <> ; Дескриптор сегмента данных, базовый адрес 0, размер 4Gb, Read-Write segment_descriptor <0ffffh, 0, 0, 10010010b, 10001111b, 0> ; 10010010b - 1001, C/D - 0, 0, R/W - 1, 0 ; 10001111b - G - 1, 000, Limit - 1111 ; Данные для загрузки в GDTR gdtr table_register <$ - GDT - 1, 0> ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Служебные функции ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Открывает вентиль A20 open_A20: in al, 92h or al, 2 out 92h, al ret ; Инициализирует GDT initialize_gdt: ; Вычисляем линейный адрес начала массива дескрипторов call cs_to_eax add eax, offset GDT ; Записываем его в структуру mov dword ptr gdtr.base, eax ; Загружаем GDTR lgdt fword ptr gdtr ret ; Запрещает маскируемые и немаскируемые прерывания disable_interrupts: cli ; запретить прерывания in al, 70h ; индексный порт CMOS or al, 80h ; установка бита 7 в нем запрещает NMI out 70h, al ret ; Разрешает маскируемые и немаскируемые прерывания enable_interrupts: in al, 70h ; индексный порт CMOS and al, 7Fh ; сброс бита 7 отменяет блокирование NMI out 70h, al sti ; разрешить прерывания ret ; Устанавливает флаг PE set_PE: mov eax, cr0 ; прочитать регистр CR0 or al, 1 ; установить бит PE, mov cr0, eax ; с этого момента мы в защищенном режиме ret ; Сбрасывает флаг PE clear_PE: mov eax, cr0 ; прочитать CR0 and al, 0FEh ; сбросить бит PE mov cr0, eax ; с этого момента мы в реальном режиме ret ; Вычисляет линейный адрес начала сегмента кода cs_to_eax: mov eax, 0 mov ax, cs shl eax, 4 ret end start |
После выполнения этой программы можно делать, например, такие вещи:
… mov eax, 10000000 ; десять мегабайт mov word ptr fs:[eax], 1234h … |
И оно будет работать! Примерно это и называется unreal-режимом.