1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
| ;Программа транслируется в COM - файл:
; TASM demo.asm
; Tlink demo.obj /t
; Demo.asm
.386p ; Разрешение трансляции
; всех инструкций 80386
Gdt_Descriptor STRUC ; Шаблон дескриптора GDT
Seg_Limit dw 0 ; Длина сегмента
Base_Lo_Word dw 0 ; Младшие 16 бит базового
; адреса
Base_Hi_Byte db 0 ; Биты 16..23 базового адр.
Acces_Rights db 0 ; Байт прав доступа
Limit&Acces db 0 ; +
Base_Top_Byte db 0 ; Биты 24..31 базового адр. !
Gdt_Descriptor ENDS
Idt_Descriptor STRUC ; Шаблон дескриптора IDT
Int_Offset dw 0 ; Точка входа в процедуру
; обработки прерывания
Int_Selector dw 0 ; Селектор сегмента в GDT
db 0 ;
Access db 0 ; Права доступа
dw 0 ;
Idt_Descriptor ENDS
Code_Seg_Access Equ 10011011b ; Байт прав доступа деск-
; риптора сегмента кода
Data_Seg_Access Equ 10010011b ; Байт прав доступа деск-
; риптора сегмента данных
Data_Seg_Access_2 Equ 00010011b
Disable_Bit20 Equ 11011101b ; Код команды 8042 для за-
; крывания линии A20
Enable_Bit20 Equ 11011111b ; Код команды 8042 для от-
; крывания линии A20
Port_A Equ 060h ; Порт A 8042
Status_port Equ 064h ; Порт состояния 8042
Cmos_Port Equ 070h ; Адрес порта CMOS-памяти
; Макро для записи базового адреса сегмента в дескриптор
FILLDESCR MACRO Seg_Addr,Offset_Addr,Descr
xor edx,edx ; EDX := 0
xor ecx,ecx ; ECX := 0
mov dx,Seg_Addr ; Сегментная часть
mov cx,offset Offset_Addr ; Смещение
call Form_32Bit_Address ; CX:DX := линейный
; адрес
mov &Descr.Base_Lo_Word,dx ; Занесение базового
mov &Descr.Base_Hi_Byte,cl ; адреса в дескрип-
mov &Descr.Base_Top_Byte,ch ; тор !
ENDM
CSEG SEGMENT Para USE16 public 'code'
ASSUME cs:Cseg,ds:Cseg
org 100h
start: jmp Main
;********************** НАЧАЛО ДАННЫХ **********************
; Глобальная дескрипторная таблица GDT
EVEN
Gdt label word
;********** Дескриптор, описывающий саму таблицу GDT **********
Gdt_Desc EQU $-gdt ; Селектор дескриптора
Gdt1 Gdt_Descriptor <gdt_leng-1,,,data_seg_access,>; !
;****** Дескриптор, описывающий сегмент Cseg как кодовый ******
Cs_Code EQU $-gdt ; Селектор дескриптора
Gdt2 Gdt_Descriptor<0FFFFh,,,code_seg_access,>; !
;** Дескриптор, описывающий Cseg как сегмент данных с пределом*
;** 0FFFEh. Он будет использоваться также в роли стекового. ***
Cs_Data EQU $-gdt ; Селектор дескриптора
Gdt3 Gdt_Descriptor<0FFFFh,,,data_seg_access,>; !
SSEG_SELECTOR EQU $-gdt ; Селектор дескриптора
Gdt4 Gdt_Descriptor<511,,,data_seg_access,>;
;** Дескриптор, описывающий Cseg как сегмент данных с пределом*
;** 0FFFEh. Он будет использоваться также в роли стекового. ***
Cs_Data_2 EQU $-gdt ; Селектор дескриптора
Gdt3_2 Gdt_Descriptor<0FFFFh,,,data_seg_access_2,>; !
;************* Дескриптор, описывающий таблицу IDT *************
Idt_Pointer Gdt_Descriptor<idt_leng-1,,,data_seg_access>
;** Дескриптор, описывающий таблицу IDT реального режима *******
Idt_Real Gdt_Descriptor<3FFh,,,data_seg_access>
;********* Дескриптор, описывающий сегмент видеопамяти *********
Video_Desc EQU $-gdt ; Селектор дескриптора
GdtB800 Gdt_Descriptor<0FFFh,8000h,0bh,data_seg_access>; !
Gdt_Leng EQU $-gdt ; Длина таблицы GDT
;Таблица дескрипторов прерываний IDT.
EVEN
Idt label word
ex0 Idt_Descriptor<offset ex0_proc,cs_code,0,10000111b,0>
ex1 Idt_Descriptor<offset ex1_proc,cs_code,0,10000111b,0>
ex2 Idt_Descriptor<offset ex2_proc,cs_code,0,10000110b,0>
ex3 Idt_Descriptor<offset ex3_proc,cs_code,0,10000111b,0>
ex4 Idt_Descriptor<offset ex4_proc,cs_code,0,10000111b,0>
ex5 Idt_Descriptor<offset ex5_proc,cs_code,0,10000111b,0>
ex6 Idt_Descriptor<offset ex6_proc,cs_code,0,10000111b,0>
ex7 Idt_Descriptor<offset ex7_proc,cs_code,0,10000111b,0>
ex8 Idt_Descriptor<offset ex8_proc,cs_code,0,10000111b,0>
ex9 Idt_Descriptor<offset ex9_proc,cs_code,0,10000111b,0>
ex10 Idt_Descriptor<offset ex10_proc,cs_code,0,10000111b,0>
ex11 Idt_Descriptor<offset ex11_proc,cs_code,0,10000111b,0>
ex12 Idt_Descriptor<offset ex12_proc,cs_code,0,10000111b,0>
ex13 Idt_Descriptor<offset ex13_proc,cs_code,0,10000111b,0>
ex14 Idt_Descriptor<offset ex14_proc,cs_code,0,10000111b,0>
ex15 Idt_Descriptor<offset ex15_proc,cs_code,0,10000111b,0>
ex16 Idt_Descriptor<offset ex16_proc,cs_code,0,10000111b,0>
Idt_Descriptor 22 dup(<>)
Int39 Idt_Descriptor<offset int10_proc,cs_code,0,10000110b,0>
Idt_Leng EQU $-Idt ; Длина таблицы IDT
Real_Jump dd ? ; Адрес межсегментного
; перехода в реальном режиме
Protect_Jump dd ? ; Адрес межсегментного пере-
; хода в защищенном режиме
event11 db 'Missing segment$'
Mess db 'PROTECTED MODE$'
Gate_Failure db "Error open A20$"
;********************** КОНЕЦ ДАННЫХ **********************
Main:
FillDescr cs,Gdt,Gdt1 ; !!!Формирование 32-разряд-
; ного адреса из CS:GDT и
; запись его в дескриптор
; с номером Gdt_Desc.
FillDescr cs,0,gdt2 ; Дескриптор Cs_Code ука-
; зывает на CSEG как на
; кодовый сегмент.
FillDescr cs,0,gdt3 ; !!!Дескриптор Cs_Data ука-
; зывает на CSEG как на
; сегмент данных.
FillDescr cs,0,gdt4;!!!!
FillDescr cs, 0,gdt3_2
FillDescr cs,Idt,Idt_Pointer ; !!!!Дескриптор Idt_Pointer
; указывает на IDT.
cli ; Запрет прерываний
mov al,8fh ; Запрет немаскируемых
out cmos_port,al ; прерываний
jmp short $+2
mov ah,Enable_Bit20 ; Открываем адрес-
call Gate_A20 ; ную линию A20
or al,al ; Если произошла
jz A20_Opened ; ошибка, то
mov dx,offset Gate_Failure ; выдать сообщение
mov ah,9 ; на экран, разре-
int 21h ; шить прерывания и
sti ; вернуться в DOS
int 20h
A20_Opened:
lea di,Real_Jump ; Формирование адреса
mov word ptr [di],offset Real ; для перехода
mov word ptr [di+2],cs ; в реальный режим
lea di,Protect_Jump ; Формирование адреса
mov word ptr [di], offset Protect ; для перехода
mov word ptr [di+2],Cs_Code ; в защищенный
; режим
lgdt Gdt1 ; Загрузка GDTR
lidt Idt_Pointer ; Загрузка IDTR
mov eax,cr0 ; Переходим в защищенный
or eax,1 ; режим, устанавливая
mov cr0,eax ; бит 0 в регистре CR0
jmp dword ptr Protect_Jump ; Переход на метку
; Protect
; Работа в защищенном режиме.
Protect:
mov ax, Cs_Data_2
mov ax,Cs_Data
mov ss,ax ; Регистры DS, ES и SS
mov ds,ax ; содержат селектор
mov es,ax ; сегмента Cs_Data
call My_Proc ; Вызов рабочей процедуры
mov eax,cr0 ; Переходим в реальный
and eax,0FFFFFFFEh ; режим, сбрасывая бит 0 !
mov cr0,eax ; регистра CR0
jmp dword ptr Real_Jump ; Косвенный межсегмент-
; ный переход на метку
; Real
; Работа в реальном режиме.
Real: lidt Idt_Real ; Загружаем регистр IDTR
; для работы в реальном
; режиме
mov dx,cs ; Восстанавливаем
mov ds,dx ; сегментные
mov ss,dx ; регистры
mov ah,Disable_Bit20 ; Закрытие адресной
call Gate_A20 ; линии A20
sti ; Разрешение прерываний
int 20h ; Выход в DOS
ex0_proc: iret ; Обработчики особых
ex1_proc: iret ; ситуаций
ex2_proc: iret ; Здесь установлены
ex3_proc: iret ; заглушки вместо
ex4_proc: iret ; обработчиков
ex5_proc: iret
ex6_proc: iret
ex7_proc: iret
ex8_proc: iret
ex9_proc: iret
ex10_proc: iret
ex11_proc:
lea bx,event11 ; Адрес сообщения
mov dx,200Dh ; Координаты вывода
int 39d ; Вывод строки на экран
iret
ex12_proc: iret
ex13_proc: iret
ex14_proc: iret
ex15_proc: iret
ex16_proc: iret
;**************************************************************
;Управление прохождением сигнала A20
;ВХОД: (AH)=0DDH установить A20 всегда равным нулю
; (AH)=0DFh открыть адресный разряд A20
;ВЫХОД: (AL)=0 8042 принял команду
; (AH)=2 сбой
;**************************************************************
Gate_A20 PROC
cli ; Запрет прерываний
call Empty_8042
jnz Gate_1
mov al,0d1h ; Выдаем команду 8042 для
out Status_Port,al ; записи в выходной порт
call Empty_8042
jnz Gate_1
mov al,ah ; Записываем в порт A 8042
out Port_A,al ; код команды
call Empty_8042
Gate_1: ret
Gate_A20 ENDP
;**************************************************************
;Ждать пока буфер 8042 не опустеет
;Вход: нет
;Выход:(AL)=0 буфер пуст
; (AL)=2 не пуст
;**************************************************************
Empty_8042 PROC
push cx
xor cx,cx ; CX = 0 (256 повторений)
Empty_1: in al,Status_Port ; Порт 8042
and al,00000010b ; Бит 2 очищен ?
loopnz Empty_1
pop cx
ret
Empty_8042 ENDP
;**************************************************************
; Формирование 32-разрядного адреса
; Вход : CX:DX - адрес в формате <сегмент:смещение>
; Выход: CX:DX - 32-разрядный линейный адрес
Form_32Bit_Address PROC
shl edx,4
add edx,ecx
mov ecx,edx
shr ecx,16
ret
Form_32Bit_Address ENDP
;**************************************************************
; Процедура вывода строки на экран, работает в качестве
; обработчика прерывания.
; Вход : DS:BX - адрес сообщения
; DL - строка экрана
; DH - колонка экрана
;**************************************************************
Int10_Proc Proc Near ; Обработчик прерывания
pusha ; INT 39d
xor cx,cx ; Очистка CX
mov cl,dh ; CL = колонка
sal cl,1 ; CL = CL*2
xor dh,dh ; DX = строка
imul dx,160d ; Умножаем на число байт в строке
add dx,cx ; Прибавляем смещение в строке
; Результат: DX = смещение в
; видеопамяти
mov di,dx ; DI = смещение в этом сегменте
m: mov ax,[bx] ; AL = очередной символ строки
cmp al,'$' ; Конец строки ?
jz Ex ; Да - выход
mov cx,es:[di] ; Получить атрибут в CH
mov ah,ch ; AX = символ с атрибутом
stosw ; Записать символ в видеопамять
inc bx ; Перейти к следующему символу
jmp short m
ex: popa
iret ; Возврат из прерывания
Int10_Proc Endp
;**************************************************************
;Процедура выполняющая какие-либо действия в защищенном режиме
;**************************************************************
MY_PROC PROC
pusha
push es
push Video_Desc ; В регистр ES заносим се-
pop es ; лектор сегмента видеопа-
; мяти
mov dh,0fh ; Очищаем экран
call Paint_Screen
lea bx, mess ; Адрес сообщения
mov dx,200Ch ; Координаты вывода
int 39d ; Вывод строки на экран
mov ax, cs_data_2
mov ds, ax
pop es
popa
ret
MY_PROC ENDP
;**************************************************************
; Процедура очищает экран и устанавливает цвета в соответствии
; с заданным атрибутом.
; Вход : ES - селектор дескриптора текстового видеобуфера
; DH - атрибут.
;**************************************************************
PAINT_SCREEN PROC
push cx si di es
mov cx,80*25 ; Размер видеопамяти (слов)
xor si,si ; SI и DI установим на
xor di,di ; начало видеопамяти
Paint1: lodsw ; Увеличиваем смещение в
; видеопамяти
mov ah,dh ; Байт атрибута символа
mov al,20h ; Код символа "ПРОБЕЛ"
stosw ; Записываем символ с ат-
; рибутом в видеопамять
loop Paint1 ; Повторить для каждого
; символа на экране
pop es di si cx
RET
PAINT_SCREEN ENDP
Cseg Ends
End start |