shr dl,4
shl ax,4
;Устанавливаем адрес сегмента стека
;в глобальной таблице дескрипторов
mov bx,offset gdt_ss
setgdtentry
;Перехватываем рестарт. Так как процессор i286 (а эта программа
;рассчитана именно на такой процессор) не имеет возможности
;возврата в реальный режим из защищенного, возврат в реальный
;режим будем производить следующим образом: перехватим рестарт,
;сгенерируем CPU Reset, после которого получим управление, когда
;процессор будет находится уже в реальном режиме. На процессоре
;i386 возврат в реальный режим происходит
;значительно проще и ”естественнее”.
push ds
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,0FFh
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
;Открываем адресную линию A20 для доступа свыше 1Мбайт.
;При закрытой линии адресное пространство
;”зацикливается” в пределах 1Мбайт
call enable_a20
;Сохраняем значение регистра SS для реального режима
mov real_ss,ss
;Переводим компилятор Turbo Assembler в улучшенный режим.
;IDEAL – это не команда и не оператор, это директива, влияющая
;только на интерпретацию дальнейших строк листинга
ideal
p286
;Загружаем регистр глобальной таблицы дескрипторов GDTR
lgdt [QWORD gdt_gdt] ;db 0Fh,01h,16h dw offset gdt_gdt
;Переводим процессор в защищенный режим
mov ax,0001h
lmsw ax ;db 0Fh,01h,F0h
;Переводим компилятор 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
;С этого места программа выполняется после перезапуска процессора