Текст программы:
;в защищённом режиме вывод фиксированных символов на экран
.386P ;(1) разрешение трансляции всех, в том числе и
;привилегированных команд МП 386 и 486
;структура для описания дескрипторов сегмента
descr struc ;(2)
limit dw 0 ;(3) граница (биты 0…15)
base_l dw 0 ;(4) база, биты 0…15
base_m db 0 ;(5) база, биты 16…23
attr_1 db 0 ;(6) байт атрибутов 1
attr_2 db 0 ;(7) граница (биты 16…19) и атрибуты 2
base_h db 0 ;(8) база, биты 24…31
descr ends ;(9)
;структура для описания дескрипторов ловушек
trap struc ;(10)
offs_1 dw 0 ;(11)
sel dw 16 ;(12)
rsrv db 0 ;(13)
attr db 8Fh ;(14)
offs_h dw 0 ;(15)
trap ends ;(16)
data segment use16 ;(17) 16-разрядное приложение
;таблица глобальных дескрипторов GDT
gdt_0 label word ;(18)
gdt_null descr<0,0,0,0,0,0>;(19) селектор 0-обязательный нулевой дескриптор
gdt_data descr;(20) селектор 8-сегмент данных
gdt_code descr;(21) селектор 16-сегмент команд
gdt_stack descr<255,0,0,92h,0,0> ;(22) селектор 24, сегмент стека
gdt_screen descr<4095,8000h,0Bh,92h,0,0>;(23) селектор 32, видеобуфер
gdt_size=$-gdt_null ;(24)размер GDT
idt label word ;(25)
trap 32 dup () ;(26)
idt_size=$-idt ;(27)
pdescr dq 0 ;(28) псевдодескриптор для LGDT
sym db 1 ;(29) символ для вывода на экран
real_sp dw 0 ;(30) ячейка для хранения SP
real_ss dw 0 ;(31) ячейка для хранения SS
pos dw 950 ;(32)
mes db 27,'Lets go back to the Real Mode!',27,'[0m$' ;(33)
string db '++++++++++' ;(34) строка
len=$-string ;(35) её размер
data_size=$-gdt_null ;(36) размер сегмента данных
data ends ;(37) конец сегмента данных
text segment 'code' use16 ;(38) начало сегмента команд. Будем работать
;в 16-разрядном режиме
assume CS:text,DS:data ;(39)
begin label word ;(40)
;Обработчик всех исключений
dummy_exc proc ;(41)
pop EAX ;(42)
pop EAX ;(43)
mov SI,offset string+5;(44)
mov AX,1111b ;(45)
jmp home ;(46)
dummy_exc endp ;(47)
main proc ;(48)
xor EAX,EAX ;(49) очистка EAX
mov AX,data ;(50) инициализация DS
mov DS,AX ;(51) в реальном режиме
;вычислим 32-битовый линейный адрес сегмента данных и загрузим его в дескриптор
;сегмента данных в таблице GDT. В регистре АХ уже находится сегментный адрес.
shl EAX,4 ;(52) умножим его на 16
mov EBP,EAX ;(53) сохраняем его в EBP
mov EBX, offset gdt_data;(54) на BX адрес дескриптора
mov [EBX].base_l,AX ;(55) загрузим младшую часть базы
rol EAX,16 ;(56) обмен старшей и младшей частей EAX
mov [EBX].base_m,AL ;(57) загрузим среднюю часть базы
;аналогично для линейного адреса сегмента команд
xor EAX,EAX ;(58) очищаем EAX
mov AX,CS ;(59) берем адрес сегмента команд
shl EAX,4 ;(60) умножаем его на 16
mov EBX,offset gdt_code ;(61) адрес дескриптора
mov [EBX].base_l,AX ;(62) загрузим младшую часть базы
rol EAX,16 ;(63) обмен старшей и младшей частей EAX
mov [EBX].base_m,AL ;(64) загружаем среднюю часть базы
;аналогично для линейного адреса сегмента стека
xor EAX,EAX ;(65) очищаем EAX
mov AX,SS ;(66) берем адрес сегмента стека
shl EAX,4 ;(67) умножаем его на 16
mov EBX,offset gdt_stack;(68) адрес дескриптора
mov [EBX].base_l,AX ;(69) загрузим младшую часть базы
rol EAX,16 ;(70) обмен старшей и младшей частей EAX
mov [EBX].base_m,AL ;(71) загружаем среднюю часть базы
;подготовим псевдодескриптор pdescr и загрузим регистр GDTR
mov dword ptr pdescr+2,EBP;(72) база GDT, биты 0…31
mov word ptr pdescr, gdt_size-1;(73) граница GDT
lgdt pdescr ;(74) загрузим регистр GDTR
;подготовимся к переходу в защищённый режим
cli ;(75) запрет аппаратных прерываний
;загрузим IDTR
mov word ptr pdescr, idt_size-1;(80) граница IDT
xor EAX,EAX ;(81)EAX=0
mov AX,offset idt ;(82) смещение idt в сегменте данных
add EAX,EBP ;(83) плюс линейный адрес сегмента данных
mov dword ptr pdescr+2,EAX;(84) адрес IDT в pdescr
lidt pdescr ;(85) загрузка IDTR
;переходим в защищённый режим
mov EAX,CR0 ;(86) получим слово состояния машины
or EAX,1 ;(87) установим бит PE
mov CR0,EAX ;(88) запишем назад слово состояния
;теперь процессор работает в защищённом режиме
;загружаем в CS:IP селектор:смещение точки continue
;и заодно очищаем очередь команд
db 0Eah ;(89) код команды far jmp
dw offset continue ;(90) смещение
dw 16 ;(91) селектор сегмента команд
continue: ;(92)
;делаем адресуемыми данными
mov AX,8 ;(93) селектор сегмента данных
mov DS,AX ;(94)
;делаем адресуемым стек
mov AX,24 ;(95) селектор сегмента стек
mov SS,AX ;(96)
home: mov si,offset string;(97)
mov si,offset string;(98)
mov cx,len ;(99)
mov ah,74h ;(100)
mov di,1600 ;(101)
scr: lodsb ;(102)
stosw ;(103)
loop scr ;(104)
;инициализируем ES и выводим символы
mov AX,32 ;(105) селектор сегмента видеобуфера
mov ES,AX ;(106)
mov BX,800 ;(107) начальное смещение на экране
mov CX,640 ;(108) число выводимых символов
mov AX,word ptr sym ;(109) начальный символ с атрибутами
screen: mov ES:[BX],AX ;(110) вывод в видеобуфер
add BX,2 ;(111) сместимся в видеобуфере
inc AX ;(112) следующий символ
loop screen ;(113) цикл вывода на экран
;подготовим переход в реальный режим
;сформируем и загрузим дескрипторы для реального режима
mov gdt_data.limit,0FFFFh;(114) граница сегмента данных
mov gdt_code.limit,0FFFFh;(115) граница сегмента кода
mov gdt_stack.limit,0FFFFh;(116) граница сегмента стека
mov gdt_Screen.limit,0FFFFh;(117) граница доп. сегмента
mov AX,8 ;(118) загружаем теневой регистр
mov DS,AX ;(119) сегмента данных
mov Ax,24 ;(120) загружаем теневой регистр
mov SS,AX ;(121) сегмента стека
mov AX,32 ;(122) загружаем теневой регистр
mov ES,AX ;(123) дополнительного сегмента
;выполним дальний переход для того, чтобы заново загрузить
;селектор в регистр CS и модифицируем его теневой регистр
db 0EAh ;(124) командой дальнего перехода
dw offset go ;(125) загрузим теневой регистр
dw 16 ;(126) сегмента команд
;переключим режим процессора
go: mov EAX,CR0 ;(127) получим содержимое CR0
and EAX,0fffffffeh ;(128) сбросим бит PE
mov CR0,EAX ;(129) запишем назад в CR0
db 0EAh ;(130) код команды far jmp
dw offset return ;(131) смещение
dw text ;(126) сегмент
;теперь процессор снова работает в реальном режиме
;восстановим операционную среду реального режима
return: mov AX,data ;(133) восстановим адресуемость
mov DS,AX ;(134) данных
mov AX,stk ;(135) адресуемость
mov SS,AX ;(136) стека
mov SP,256 ;(137)
mov SS,real_ss ;(138)
;Восстановим состояние регистра IDTR реального режима
mov ax,3ffh ;(139) граница таблицы векторов
mov word ptr pdescr,AX;(140)
mov eax,0 ;(141) смещение таблицы векторов
mov dword ptr pdescr+2,EAX;(142)
lidt pdescr ;(143) загрузим pdescr IDTR
;разрешим аппаратные и немаскируемые прерывания
sti ;(144) разрешение прерываний
;проверим выполнение функций DOS после возврата в реальный режим
mov AH,09h ;(145) функции вывода на экран строки
mov EDX,offset mes ;(146) адрес строки
int 21h ;(147) вызов DOS
mov AX,4C00h ;(148) завершаем программу
int 21h ;(149) обычным образом
main endp ;(150) конец главной процедуры
code_size=$-main ;(151) размер сегмента команд
text ends ;(152) конец сегмента команд
stk segment stack 'stack' ;(153) начало сегмента стека
db 256 dup ('^') ;(154)
stk ends ;(155) конец сегмента стека
end main ;(156) конец программы
|