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
|
;============================================================================
;保护模式下使用中断IDT
;编译选项请参见 makefile TAB = 8
;============================================================================
.686p
Include pm.inc
option casemap:none
Stack_Len = 1024 ;堆栈大小
;----------------------------------------------------------------------------
GdtSeg Segment use32 ;全局描述符
GDT label byte
Dummy: Descriptor 0, 0, 0 ; 空描述符
Normal: Descriptor 0, 0ffffh, DA_DRW ; Normal 描述符
g_VideoDesc: Descriptor 0B8000h, 0ffffh, DA_DRW ; 显存首地址
g_Code16Desc: Descriptor 0, 0ffffh, DA_C ;非一致代码段16位
g_DataDesc: Descriptor 0, DataLen-1, DA_DRWA ;数据段
g_StackDesc: Descriptor 0, Stack_Len-1, DA_DRWA ;堆栈段
g_IdtCode32Desc: Descriptor 0,IdtCode32SegLen-1, DA_CR or DA_32 ; 非一致代码段, 32
;----------------------------------------------------------------------------
NormalSelector equ Normal - GDT ;规范段选择子
Code16Selector equ g_Code16Desc - GDT ;代码段选择子
g_DataSelector equ g_DataDesc - GDT ;数据段
g_VideoSelector equ g_VideoDesc - GDT ;视频段选择子
g_StackSelector equ g_StackDesc - GDT ;堆栈段
g_IdtCodeSelector equ g_IdtCode32Desc - GDT ;中断代码段
;----------------------------------------------------------------------------
GDTLen equ $ - GDT ;GDT长度
_GDT_Ptr word GDTLen-1 ;VGDT
dword 0
_IDT_Ptr word 0 ;VIDT
dword 0
_RegSp word ? ;用于保存SS:SP
_RegSs word ?
GdtSeg Ends
;============================================================================
StackSeg Segment use32 ;堆栈段
byte Stack_Len dup (0)
StackSeg Ends
;============================================================================
DataSeg Segment use32 ;数据段
SzMessage byte "Other Interrupt, 0h-19h 21h - 7fh", 0
SzInterrupt byte "Clock Interrupt 20h!", 0
SzUser byte "User Interrupt! 80h", 0
_byImreg byte 0 ;中断屏蔽寄存器(IMREG)值
_dwFlags dword 0 ;标记
DataLen equ $ - DataSeg ;数据段长度
DataSeg Ends
;============================================================================
IdtCode32Seg Segment use32 ;IDT中断代码段
SpuriousHandlerEntry equ $ - IdtCode32Seg;其他类型的中断
SpuriousHandler Proc
mov ah, 0Ch ; 0000: 黑底 1100: 红字
mov esi, offset SzMessage
mov edi, (80 * 7 + 5) * 2 ; 屏幕第 7 行, 第 5 列。
mov ecx, sizeof SzMessage ;显示的字符串
@@: lodsb
stosw
loop @b
iretd
SpuriousHandler Endp
;----------------------------------------------------------------------------
ClockHandlerEntry equ $ - IdtCode32Seg;时钟中断
ClockHandler Proc
mov ah, 0Ch ; 0000: 黑底 1100: 红字
mov esi, offset SzInterrupt
mov edi, (80 * 6 + 5) * 2 ; 屏幕第 6 行, 第 5 列。
mov ecx, sizeof SzInterrupt ;显示的字符串
dec dword ptr ds:[_dwFlags]
@@: lodsb
stosw
loop @b
mov eax, dword ptr ds:[_dwFlags] ;显示随机数
stosw
shr eax, 16
stosw
int 10h ;调用自定义中断
mov al, 20h
out 20h, al ;发送EOI, 通知中断控制器中断处理完毕
iretd
ClockHandler Endp
;----------------------------------------------------------------------------
UserIntHandlerEntry equ $ - IdtCode32Seg;80H用户自己的中断
UserIntHandler Proc
mov ah, 0Ch ; 0000: 黑底 1100: 红字
mov esi, offset SzUser
mov edi, (80 * 5 + 5) * 2 ; 屏幕第 5 行, 第 5 列。
mov ecx, sizeof SzUser ;显示的字符串
@@: lodsb
stosw
loop @b
iretd
UserIntHandler Endp
;----------------------------------------------------------------------------
IdtCode32SegLen equ $ - IdtCode32Seg ;段长度
IdtCode32Seg Ends
;============================================================================
IdtSeg Segment use32 ;中断描述符
IDT label byte
; 门 目标选择子, 偏移, DCount, 属性
repeat 32
Gate g_IdtCodeSelector, SpuriousHandlerEntry, 0, DA_386IGate
endm
;时钟中断20h
Gate g_IdtCodeSelector, ClockHandlerEntry, 0, DA_386IGate
repeat 95
Gate g_IdtCodeSelector, SpuriousHandlerEntry, 0, DA_386IGate
endm
;自定义中断80h
Gate g_IdtCodeSelector, UserIntHandlerEntry, 0, DA_386IGate
IDTLen equ $ - IDT ;段长度
IdtSeg Ends
;============================================================================
Code16Seg Segment use16
_Delay Proc ;延时过程
nop
nop
nop
nop
ret
_Delay Endp
;----------------------------------------------------------------------------
;设置8259A中断控制器 从20h-->28h
;----------------------------------------------------------------------------
_SetProcteMode8259A Proc uses es
in al, 21h
mov byte ptr ds:[_byImreg], al ; 保存中断屏蔽寄存器(IMREG)值
mov al, 011h
out 020h, al ; 主8259, ICW1.
call _Delay
out 0A0h, al ; 从8259, ICW1.
call _Delay
mov al, 020h ; IRQ0 对应中断向量 0x20
out 021h, al ; 主8259, ICW2.
call _Delay
mov al, 028h ; IRQ8 对应中断向量 0x28
out 0A1h, al ; 从8259, ICW2.
call _Delay
mov al, 004h ; IR2 对应从8259
out 021h, al ; 主8259, ICW3.
call _Delay
mov al, 002h ; 对应主8259的 IR2
out 0A1h, al ; 从8259, ICW3.
call _Delay
mov al, 001h
out 021h, al ; 主8259, ICW4.
call _Delay
out 0A1h, al ; 从8259, ICW4.
call _Delay
;----------------------------------------------------------------------------
;需要开启某个中断只需要将某一位复位即可
;----------------------------------------------------------------------------
;mov al, 11111111b ; 屏蔽主8259所有中断
mov al, 11111110b ; 仅仅开启定时器中断
out 021h, al ; 主8259, OCW1.
call _Delay
mov al, 11111111b ; 屏蔽从8259所有中断
out 0A1h, al ; 从8259, OCW1.
call _Delay
ret
_SetProcteMode8259A Endp
;----------------------------------------------------------------------------
;设置8259A符合实模式要求, 这个有点问题, 再Bochs里面跑不了
;----------------------------------------------------------------------------
_SetRealmode8259A Proc
mov al, 017h
out 020h, al ; 主8259, ICW1.
call _Delay
mov al, 008h ; IRQ0 对应中断向量 0x8
out 021h, al ; 主8259, ICW2.
call _Delay
mov al, 001h
out 021h, al ; 主8259, ICW4.
call _Delay
mov al, byte ptr ds:[_byImreg] ;恢复中断屏蔽寄存器(IMREG)的原值
out 021h, al
call _Delay
ret
_SetRealmode8259A Endp
;----------------------------------------------------------------------------
_GoToProtect Proc ;返回实模式
xchg bx, bx
call _SetRealmode8259A ;设置实模式中断
mov ax, NormalSelector
mov fs, ax ;规范选择子
mov es, ax
mov ds, ax
mov ss, ax
mov eax, cr0 ;关PE位, 进入实模式
and al, 0feh
mov cr0, eax
;刷新段选择子缓冲区, 退回实模式
Jmp16 <seg StartCode >, < offset _RetProtect >
_GoToProtect Endp
;----------------------------------------------------------------------------
_ProtectEntry Proc
mov ax, g_DataSelector
mov ds, ax ; 数据段选择子
mov es, ax
mov ax, g_VideoSelector
mov gs, ax ; 视频段选择子
mov es, ax
mov ax, g_StackSelector
mov ss, ax ; 堆栈段选择子
mov esp, Stack_Len
mov eax, 2000
mov dword ptr ds:[_dwFlags],eax ; 初始化中断20次
call _SetProcteMode8259A ;初始化8259A中断控制器
int 080h ;没有开中断就可用调用中断门
sti
@@: cmp dword ptr ds:[_dwFlags], 0
jnz @b
call _GoToProtect ;返回实模式
_ProtectEntry Endp
Code16Seg Ends
;============================================================================
StartCode Segment use16
_InitGdt Proc uses es ;初始化全局描述符表
local _Idt_Ptr:fword
xor eax, eax
mov ax, GdtSeg
mov es, ax ;es-->全局描述符表
;----------------------------------------------------------------------------
shl eax, 4
add eax, offset GDT
mov dword ptr es:[_GDT_Ptr+2], eax ;初始化VGDT描述符
;----------------------------------------------------------------------------
xor eax, eax
mov ax, IdtSeg
shl eax, 4
add eax, offset IDT
mov word ptr ss:[_Idt_Ptr], IDTLen - 1 ;VIDT限长
mov dword ptr ss:[_Idt_Ptr+2], eax ;初始化VIDT描述符
;----------------------------------------------------------------------------
xor eax, eax
mov ax, Code16Seg ;初始化十六位的代码段
shl eax, 4
mov word ptr es:[g_Code16Desc+2], ax ;段基址低位
shr eax, 16
mov byte ptr es:[g_Code16Desc+4], al ;段基址高地址低位
mov byte ptr es:[g_Code16Desc+7], ah ;段基址高地址高位
;----------------------------------------------------------------------------
xor eax, eax ;数据段
mov ax, DataSeg
shl eax, 4
mov word ptr es:[g_DataSelector+2], ax
shr eax, 16
mov byte ptr es:[g_DataSelector+4], al
mov byte ptr es:[g_DataSelector+7], ah
;----------------------------------------------------------------------------
xor eax, eax ;中断代码段
mov ax, IdtCode32Seg
shl eax, 4
mov word ptr es:[g_IdtCode32Desc+2], ax
shr eax, 16
mov byte ptr es:[g_IdtCode32Desc+4], al
mov byte ptr es:[g_IdtCode32Desc+7], ah
;----------------------------------------------------------------------------
xor eax, eax ;堆栈段
mov ax, StackSeg
shl eax, 4
mov word ptr es:[g_StackDesc+2], ax
shr eax, 16
mov byte ptr es:[g_StackDesc+4], al
mov byte ptr es:[g_StackDesc+7], ah
;----------------------------------------------------------------------------
sidt fword ptr es:[_IDT_Ptr] ;保存IDT
lgdt fword ptr es:[_GDT_Ptr] ;装载GDT
lidt fword ptr ss:[_Idt_Ptr] ;装载IDT
ret
_InitGdt Endp
;============================================================================
Jmain Proc
mov ax, GdtSeg
mov ds, ax
call _InitGdt ;装载GDT和IDT
_EnableA20 ;关中断开A20地址线
cli
mov eax, cr0
or eax, 1
mov cr0, eax ;开启分段, 进入保护模式
;----------------------------------------------------------------------------
Jmp16 Code16Selector, <offset _ProtectEntry> ;跳入保护模式
Jmain Endp
;============================================================================
_RetProtect Proc ;返回保护模式
mov ax, GdtSeg
mov ds, ax
mov ax, ds:[ _RegSs ] ;恢复SS:SP
mov ss, ax
mov ax, ds:[ _RegSp ]
mov sp, ax
lidt fword ptr ds:[_IDT_Ptr] ;恢复IDT
_DisableA20 ;关A20地址线, 开中断
sti
mov ax, 4c00h
int 21h
_RetProtect Endp
StartCode Ends
End Jmain
|