關(guān)于從保護(hù)模式切換到實(shí)模式的相關(guān)說(shuō)明
參考于淵的《自己動(dòng)手寫(xiě)操作系統(tǒng)》第三章中從實(shí)模式切換到保護(hù)模式,最后有重新切回實(shí)模式的代碼(代碼如下),其中有幾點(diǎn)不太明白的,參考其他文章之后在此記錄一下。
其中還有不太明白的地方,希望大家能在下面 留個(gè)言幫我講明白,謝謝。
下面代碼有些宏定義沒(méi)貼出來(lái),應(yīng)該能看明白。
1
; ==========================================
2
; pmtest2.asm
3
; 編譯方法:nasm pmtest2.asm -o pmtest2.com
4
; ==========================================
5
6
%include "pm.inc" ; 常量, 宏, 以及一些說(shuō)明
7
8
org 0100h
9
jmp LABEL_BEGIN
10
11
[SECTION .gdt]
12
; GDT
13
; 段基址, 段界限 , 屬性
14
LABEL_GDT: Descriptor 0, 0, 0 ; 空描述符
15
LABEL_DESC_NORMAL: Descriptor 0, 0ffffh, DA_DRW ; ***注意此處為Normal 描述符*****
16
LABEL_DESC_CODE32: Descriptor 0, SegCode32Len - 1, DA_C + DA_32 ; 非一致代碼段, 32
17
LABEL_DESC_CODE16: Descriptor 0, 0ffffh, DA_C ; 非一致代碼段, 16
18
LABEL_DESC_DATA: Descriptor 0, DataLen - 1, DA_DRW ; Data
19
LABEL_DESC_STACK: Descriptor 0, TopOfStack, DA_DRWA + DA_32 ; Stack, 32 位
20
LABEL_DESC_TEST: Descriptor 0500000h, 0ffffh, DA_DRW
21
LABEL_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW ; 顯存首地址
22
; GDT 結(jié)束
23
24
GdtLen equ $ - LABEL_GDT ; GDT長(zhǎng)度
25
GdtPtr dw GdtLen - 1 ; GDT界限
26
dd 0 ; GDT基地址
27
28
; GDT 選擇子
29
SelectorNormal equ LABEL_DESC_NORMAL - LABEL_GDT
30
SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDT
31
SelectorCode16 equ LABEL_DESC_CODE16 - LABEL_GDT
32
SelectorData equ LABEL_DESC_DATA - LABEL_GDT
33
SelectorStack equ LABEL_DESC_STACK - LABEL_GDT
34
SelectorTest equ LABEL_DESC_TEST - LABEL_GDT
35
SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT
36
; END of [SECTION .gdt]
37
38
[SECTION .data1] ; 數(shù)據(jù)段
39
ALIGN 32
40
[BITS 32]
41
LABEL_DATA:
42
SPValueInRealMode dw 0
43
; 字符串
44
PMMessage: db "In Protect Mode now. ^-^", 0 ; 進(jìn)入保護(hù)模式后顯示此字符串
45
OffsetPMMessage equ PMMessage - $$
46
StrTest: db "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 0
47
OffsetStrTest equ StrTest - $$
48
DataLen equ $ - LABEL_DATA
49
; END of [SECTION .data1]
50
51
52
; 全局堆棧段
53
[SECTION .gs]
54
ALIGN 32
55
[BITS 32]
56
LABEL_STACK:
57
times 512 db 0
58
59
TopOfStack equ $ - LABEL_STACK - 1
60
61
; END of [SECTION .gs]
62
63
64
[SECTION .s16]
65
[BITS 16]
66
LABEL_BEGIN:
67
mov ax, cs
68
mov ds, ax
69
mov es, ax
70
mov ss, ax
71
mov sp, 0100h
72
73
mov [LABEL_GO_BACK_TO_REAL+3], ax
74
mov [SPValueInRealMode], sp
75
76
; 初始化 16 位代碼段描述符
77
mov ax, cs
78
movzx eax, ax
79
shl eax, 4
80
add eax, LABEL_SEG_CODE16
81
mov word [LABEL_DESC_CODE16 + 2], ax
82
shr eax, 16
83
mov byte [LABEL_DESC_CODE16 + 4], al
84
mov byte [LABEL_DESC_CODE16 + 7], ah
85
86
; 初始化 32 位代碼段描述符
87
xor eax, eax
88
mov ax, cs
89
shl eax, 4
90
add eax, LABEL_SEG_CODE32
91
mov word [LABEL_DESC_CODE32 + 2], ax
92
shr eax, 16
93
mov byte [LABEL_DESC_CODE32 + 4], al
94
mov byte [LABEL_DESC_CODE32 + 7], ah
95
96
; 初始化數(shù)據(jù)段描述符
97
xor eax, eax
98
mov ax, ds
99
shl eax, 4
100
add eax, LABEL_DATA
101
mov word [LABEL_DESC_DATA + 2], ax
102
shr eax, 16
103
mov byte [LABEL_DESC_DATA + 4], al
104
mov byte [LABEL_DESC_DATA + 7], ah
105
106
; 初始化堆棧段描述符
107
xor eax, eax
108
mov ax, ds
109
shl eax, 4
110
add eax, LABEL_STACK
111
mov word [LABEL_DESC_STACK + 2], ax
112
shr eax, 16
113
mov byte [LABEL_DESC_STACK + 4], al
114
mov byte [LABEL_DESC_STACK + 7], ah
115
116
; 為加載 GDTR 作準(zhǔn)備
117
xor eax, eax
118
mov ax, ds
119
shl eax, 4
120
add eax, LABEL_GDT ; eax <- gdt 基地址
121
mov dword [GdtPtr + 2], eax ; [GdtPtr + 2] <- gdt 基地址
122
123
; 加載 GDTR
124
lgdt [GdtPtr]
125
126
; 關(guān)中斷
127
cli
128
129
; 打開(kāi)地址線A20
130
in al, 92h
131
or al, 00000010b
132
out 92h, al
133
134
; 準(zhǔn)備切換到保護(hù)模式
135
mov eax, cr0
136
or eax, 1
137
mov cr0, eax
138
139
; 真正進(jìn)入保護(hù)模式
140
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;在此由實(shí)模式切進(jìn)保護(hù)模式;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
141
jmp dword SelectorCode32:0 ; 執(zhí)行這一句會(huì)把 SelectorCode32 裝入 cs, 并跳轉(zhuǎn)到 Code32Selector:0 處
142
143
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
144
145
LABEL_REAL_ENTRY: ; 從保護(hù)模式跳回到實(shí)模式就到了這里
146
mov ax, cs
147
mov ds, ax
148
mov es, ax
149
mov ss, ax
150
151
mov sp, [SPValueInRealMode]
152
153
in al, 92h ; ┓
154
and al, 11111101b ; ┣ 關(guān)閉 A20 地址線
155
out 92h, al ; ┛
156
157
sti ; 開(kāi)中斷
158
159
mov ax, 4c00h ; ┓
160
int 21h ; ┛回到 DOS
161
; END of [SECTION .s16]
162
163
164
[SECTION .s32]; 32 位代碼段. 由實(shí)模式跳入.
165
[BITS 32]
166
167
LABEL_SEG_CODE32:
168
mov ax, SelectorData
169
mov ds, ax ; 數(shù)據(jù)段選擇子
170
mov ax, SelectorTest
171
mov es, ax ; 測(cè)試段選擇子
172
mov ax, SelectorVideo
173
mov gs, ax ; 視頻段選擇子
174
175
mov ax, SelectorStack
176
mov ss, ax ; 堆棧段選擇子
177
178
mov esp, TopOfStack
179
180
181
; 下面顯示一個(gè)字符串
182
mov ah, 0Ch ; 0000: 黑底 1100: 紅字
183
xor esi, esi
184
xor edi, edi
185
mov esi, OffsetPMMessage ; 源數(shù)據(jù)偏移
186
mov edi, (80 * 10 + 0) * 2 ; 目的數(shù)據(jù)偏移。屏幕第 10 行, 第 0 列。
187
cld
188
.1:
189
lodsb
190
test al, al
191
jz .2
192
mov [gs:edi], ax
193
add edi, 2
194
jmp .1
195
.2: ; 顯示完畢
196
197
call DispReturn
198
199
call TestRead
200
call TestWrite
201
call TestRead
202
203
; 到此停止
204
;**********注意在此由32位代碼段跳至16位代碼段**********************
205
jmp SelectorCode16:0
206
207
; ------------------------------------------------------------------------
208
TestRead:
209
xor esi, esi
210
mov ecx, 8
211
.loop
212
mov al, [es:esi]
213
call DispAL
214
inc esi
215
loop .loop
216
217
call DispReturn
218
219
ret
220
; TestRead 結(jié)束-----------------------------------------------------------
221
222
223
; ------------------------------------------------------------------------
224
TestWrite:
225
push esi
226
push edi
227
xor esi, esi
228
xor edi, edi
229
mov esi, OffsetStrTest ; 源數(shù)據(jù)偏移
230
cld
231
.1:
232
lodsb
233
test al, al
234
jz .2
235
mov [es:edi], al
236
inc edi
237
jmp .1
238
.2:
239
240
pop edi
241
pop esi
242
243
ret
244
; TestWrite 結(jié)束----------------------------------------------------------
245
246
247
; ------------------------------------------------------------------------
248
; 顯示 AL 中的數(shù)字
249
; 默認(rèn)地:
250
; 數(shù)字已經(jīng)存在 AL 中
251
; edi 始終指向要顯示的下一個(gè)字符的位置
252
; 被改變的寄存器:
253
; ax, edi
254
; ------------------------------------------------------------------------
255
DispAL:
256
push ecx
257
push edx
258
259
mov ah, 0Ch ; 0000: 黑底 1100: 紅字
260
mov dl, al
261
shr al, 4
262
mov ecx, 2
263
.begin:
264
and al, 01111b
265
cmp al, 9
266
ja .1
267
add al, '0'
268
jmp .2
269
.1:
270
sub al, 0Ah
271
add al, 'A'
272
.2:
273
mov [gs:edi], ax
274
add edi, 2
275
276
mov al, dl
277
loop .begin
278
add edi, 2
279
280
pop edx
281
pop ecx
282
283
ret
284
; DispAL 結(jié)束-------------------------------------------------------------
285
286
287
; ------------------------------------------------------------------------
288
DispReturn:
289
push eax
290
push ebx
291
mov eax, edi
292
mov bl, 160
293
div bl
294
and eax, 0FFh
295
inc eax
296
mov bl, 160
297
mul bl
298
mov edi, eax
299
pop ebx
300
pop eax
301
302
ret
303
; DispReturn 結(jié)束---------------------------------------------------------
304
305
SegCode32Len equ $ - LABEL_SEG_CODE32
306
; END of [SECTION .s32]
307
308
309
; 16 位代碼段. 由 32 位代碼段跳入, 跳出后到實(shí)模式
310
[SECTION .s16code]
311
ALIGN 32
312
[BITS 16]
313
LABEL_SEG_CODE16:
314
; 跳回實(shí)模式:
315
;****************注意在此用normal選擇子對(duì)段寄存器進(jìn)行填充******************************
316
mov ax, SelectorNormal
317
mov ds, ax
318
mov es, ax
319
mov fs, ax
320
mov gs, ax
321
mov ss, ax
322
323
mov eax, cr0
324
and al, 11111110b
325
mov cr0, eax
326
327
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;在此由保護(hù)模式切進(jìn)實(shí)模式;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
328
LABEL_GO_BACK_TO_REAL:
329
jmp 0:LABEL_REAL_ENTRY ; 段地址會(huì)在程序開(kāi)始處被設(shè)置成正確的值
330
331
Code16Len equ $ - LABEL_SEG_CODE16
332
333
; END of [SECTION .s16code]
334
注意一.在由保護(hù)模式切換到實(shí)模式之前,用normal選擇子對(duì)段寄存器進(jìn)行填充。
原因:
在切換到實(shí)模式之前,把一個(gè)指向似乎沒(méi)有用的數(shù)據(jù)段的描述符Normal的選擇子裝載到DS和ES。這是為什么呢?
實(shí)模 式下 段描 述符 高速 緩沖 寄存 器的 內(nèi)容
|
段寄存器
|
段基地址
|
段界限(固定)
|
段屬性(固定)
|
存在性
|
特權(quán)級(jí)
|
已存取
|
粒度
|
擴(kuò)展方向
|
可讀性
|
可寫(xiě)性
|
可執(zhí)行
|
堆棧大小
|
一致特權(quán)
|
CS
|
當(dāng)前CS*16
|
0000FFFFH
|
Y
|
0
|
Y
|
B
|
U
|
Y
|
Y
|
Y
|
-
|
N
|
SS
|
當(dāng)前SS*16
|
0000FFFFH
|
Y
|
0
|
Y
|
B
|
U
|
Y
|
Y
|
N
|
W
|
-
|
DS
|
當(dāng)前DS*16
|
0000FFFFH
|
Y
|
0
|
Y
|
B
|
U
|
Y
|
Y
|
N
|
-
|
-
|
ES
|
當(dāng)前ES*16
|
0000FFFFH
|
Y
|
0
|
Y
|
B
|
U
|
Y
|
Y
|
N
|
-
|
-
|
FS
|
當(dāng)前FS*16
|
0000FFFFH
|
Y
|
0
|
Y
|
B
|
U
|
Y
|
Y
|
N
|
-
|
-
|
GS
|
當(dāng)前GS*16
|
0000FFFFH
|
Y
|
0
|
Y
|
B
|
U
|
Y
|
Y
|
N
|
-
|
-
|
在分段管理機(jī)制中,每個(gè)段寄存器都配有段描述符高速緩沖寄存器,這些高速緩沖寄存器在實(shí)方式下仍發(fā)揮作用,只是內(nèi)容上與保護(hù)模式下有所不同。如上表所示,其中“Y”表示“是”; “N”表示“否”;“B”表示字節(jié);“U”表示向上擴(kuò)展,“W”表示以字方式操作堆棧。段基地址仍是 32位,其值是相應(yīng)段寄存器值(段值)乘以16,在把段值裝載到段寄存器時(shí)刷新。由于其值是16位段值乘上16,所以在實(shí)模式下基地址實(shí)際上有效位只有20位。每個(gè)段的32位段界限都固定為0FFFFH,段屬性的許多位也是固定的。所謂固定是指在實(shí)方式下不可設(shè)置這些屬性值,只能繼續(xù)沿用保護(hù)方式下所設(shè)置的值。因此,在準(zhǔn)備結(jié)束保護(hù)模式回到實(shí)模式之前,要通過(guò)加載一個(gè)合適的描述符選擇子(如實(shí)例代碼中的Normal選擇子)到有關(guān)段寄存器,以使得對(duì)應(yīng)段描述符高速緩沖寄存器中含有合適的段界限和屬性。
也就是說(shuō),在實(shí)模式下裝載段寄存器并不會(huì)影響段告訴緩沖寄存器的值,比如段界限(其實(shí)在實(shí)模式也沒(méi)有必要改變,應(yīng)為段界限一直都是0ffffh),這也就是為甚麼所有講保護(hù)模式的樹(shù)在講到有保護(hù)模式切換到實(shí)模式時(shí)都要加載一個(gè)normal選擇子的原因了。
應(yīng)為必須在保護(hù)模式下設(shè)置好段高速緩沖寄存器的值,因?yàn)橐坏┑搅藢?shí)模式下就不能在改變了。
經(jīng)我試驗(yàn),對(duì)于normal的描述符,其最重要是段界限一定要設(shè)置為0ffffh,如果不是這樣,那莫在由保護(hù)模式跳轉(zhuǎn)到實(shí)模式后會(huì)發(fā)生錯(cuò)誤(對(duì)于上述代碼如果把normal描述符的段界限改為別的的話,在跳轉(zhuǎn)后會(huì)產(chǎn)生死循環(huán)的現(xiàn)象,具體是什么原因現(xiàn)在還不明確,哪位高人知道一定要告訴我啊~~)。其次就是屬性的設(shè)置一定要設(shè)置為可讀可寫(xiě)的,否則也會(huì)發(fā)生錯(cuò)誤.
注意二:不能從32位代碼段返回實(shí)模式,而只能從16位代碼段返回。
原因:(書(shū)中說(shuō)的)因?yàn)闊o(wú)法實(shí)現(xiàn)從32位代碼段返回時(shí)CS高速緩沖寄存器中的屬性符合實(shí)模式的要求(實(shí)模式不能改變段屬性)
對(duì)于這個(gè)解釋還是不太明確,如果哪位高人明白其中的來(lái)龍去脈的話,請(qǐng)一定在下面留個(gè)言,給我解釋一下,不勝感激.
posted on 2008-10-07 17:22
楊彬彬 閱讀(8058)
評(píng)論(4) 編輯 收藏 引用