mov dl, ah
shr dl, 4
shl ax, 4
; Устанавливаем адрес сегмента стека ;
в глобальной таблице дескрипторов
mov bx, offset gdt_ss
setgdtentry
; Перехватываем рестарт.
pushds
mov ax, 40h
mov ds, ax
mov word ptr ds:[0067h], offset shutdown_return
mov word ptr ds:[0069h], cs
pop ds
; Запрещаем маскируемые прерывания
cli
in al, INT_MASK_PORT
or al, OFFh
out INT_MASK_PORT, al
mov al, 8Fh
out CMOS_PORT, al
jmp $+2 mov al, 5
out CMOS_PORT+1, al
ret
init_protected_mode ENDP
; Подпрограмма, переводящая процессор в защищенный режим
set_protected_mode PROC
; Открываем адресную линию А20 для доступа свыше 1 Мбайт
call enable_a20
; Сохранение значения регистра SS для реального режима
mov real_ss, ss
; Перевод компилятора Turbo Assembler в улучшенный режим.
; IDEAL – это не команда и не оператор, это директива, влияющая
; только на интерпретацию дальнейших строк листинга
ideal
р286
;Загружаем регистр глобальной таблицы дескрипторов GDTR
lgdt[QWORD gdt_gdt] ; db OFh,01h,16h dw offset gdt_gdt ;
Переводим процессор в защищенный режим
mov ax, 0001h
lmswax ; db OFh,01h,FOh
; Переводим компилятор Turbo Assembler назад в режим MASM
masm
.286
jmp far flush
; db 0EAh
; dw offset flush
; dw CS_DESCR
flush:
; Останавливаем в регистр SS селектор сегмента стека
mov ax, SS_DESCR
mov ss, ax
; Устанавливаем в регистр DS селектор сегмента данных
mov ax, DS_DESCR
mov ds, ax
; Записываем в строку qw символ 'L' и выходим из подпрограммы
mov byte ptr ds:[offset qw+2],'L'
ret
set_protected_mode ENDP
; Подпрограмма, возвращающая процессор в реальный режим
set_real_mode PROC
; Сохраняем значение регистра SP для реального режима
mov real_sp, sp
; Выполняем CPU Reset (рестарт процессора)
mov al, SHUT_DOWN
out STATUS_PORT, al
; Ждем, пока процессор перезапустится
wait_reset:
hlt
jmp wait_reset
; C этого места программа выполняется после перезапуска процессора
shutdown_return:
; Устанавливаем регистр DS в соответствии с регистром CS
pushcs
pop ds
; Восстанавливаем указатели на стек
; по ранее сохраненным значениям
mov ss, real_ss
mov sp, real_sp
; Закрываем адресную линию А20
call disable_a20
; Разрешаем немаскируемые прерывания
mov ax, 000dh
out CMOS_PORT, al
; Разрешаем маскируемые прерывания
in al, INT_MASK_PORT
and al, 0
out INT_MASK_PORT, al
sti
ret
set_real_mode ENDP
; Процедура, открывающая адресную линию А20. После открытия
; адресной линии программам будет доступна память свыше 1 Мбайт
enable_a20 PROC
mov al, A20_PORT
out STATUS_PORT, al
mov al, A20_ON
out KBD_PORT_A, al
ret