《自己动手写操作系统》学习笔记(五)

来源:互联网 发布:2016中韩双边贸易数据 编辑:程序博客网 时间:2024/05/18 02:06

实模式------>保护模式------>实模式

一、“实模式--保护模式--实模式”的转换过程

1、“实模式--保护模式”的跳转

(1)准备GDT

(2)用lgdt加载gdtr

(3)打开A20

(4)置cr0的PE位

(5)跳转,进入保护模式

2、“保护模式--实模式”的跳转 

(比实模式--->保护模式要复杂一些,因为在准备结束保护模式回到实模式之前,需要加载一个合适的段描述符选择子到有关段寄存器,以使对应段描述符告诉缓冲寄存器中含有合适的段界限和属性,而且我们不能从32位代码段返回实模式,只能从16位代码段中返回。这是因为无法实现从32位代码段返回时CS高速缓冲寄存器中的属性符合实模式的要求【实模式不能改变段属性】,至于为什么不能从32位的保护模式直接跳转到实模式,可以参见这篇文章 http://www.techbulo.com/860.html

(1)从保护模式下的32位代码段跳转到保护模式下16位代码段

(2)在16位代码段下初始化除了cs寄存器外的所有其他段寄存器(以实现更新段描述符告诉缓冲寄存器的目的)

(3)置cr0的末位为0

(4)实现跳转,返回到实模式

二、《自己动手写操作系统》第三章pmtest2.asm中具体实现

1、实模式--保护模式--实模式”的跳转过程

实模式--保护模式--实模式”的跳转过程

2、代码实现

(1)、pm.inc中的宏定义

在程序中,我们定义属性时,使用了pm.inc中的宏定义DA_DRW、DA_C、DA_32、DA_DRW、DA_DRWA。下面让我来向大家解释这些宏定义。

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
DA   : Descriptor Attribute
D    : 数据段
C    : 代码段
S    : 系统段
R    : 只读
RW   : 读写
A    : 已访问
-----------------------------------------------------------
DA_32               EQU 4000h       ; 32 位段
DA_DPL0          EQU   00h        ; DPL = 0
DA_DPL1          EQU   20h        ; DPL = 1
DA_DPL2          EQU   40h        ; DPL = 2
DA_DPL3          EQU   60h        ; DPL = 3
-----------------------------------------------------------
存储段描述符类型值说明
-----------------------------------------------------------
DA_DR                  EQU 90h  ; 存在的只读数据段类型值
DA_DRW              EQU 92h  ; 存在的可读写数据段属性值
DA_DRWA            EQU 93h  ; 存在的已访问可读写数据段类型值
DA_C                     EQU 98h  ; 存在的只执行代码段属性值
DA_CR                  EQU 9Ah  ; 存在的可执行可读代码段属性值
DA_CCO               EQU 9Ch  ; 存在的只执行一致代码段属性值
DA_CCOR            EQU 9Eh  ; 存在的可执行可读一致代码段属性值
-----------------------------------------------------------
系统段描述符类型值说明
-----------------------------------------------------------
DA_LDT             EQU   82h       ; 局部描述符表段类型值
DA_TaskGate    EQU   85h       ; 任务门类型值
DA_386TSS      EQU   89h       ; 可用 386 任务状态段类型值
DA_386CGate   EQU   8Ch       ; 386 调用门类型值
DA_386IGate     EQU   8Eh       ; 386 中断门类型值
DA_386TGate    EQU   8Fh       ; 386 陷阱门类型值

(2)pmtest2.ASM文件

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
;=====================================================
;pmtest2.asm
;编译方法:nasm pmtest2.asm -o pmtest2.com
 
%include "pm.inc";常量,宏,以及一些说明
 
org 0100h
 jmp LABEL_BEGIN
 
[SECTION .gdt]
;GDT
; 段基址 段界限 段属性
LABEL_GDT: Descriptor 0, 0, 0 ;空描述符
LABEL_DESC_NORMAL: Descriptor 0, 0ffffh, DA_DRW ;Normal描述符
LABEL_DESC_CODE32: Descriptor 0, SegCode32Len-1, DA_C + DA_32 ;非一致代码段,32
LABEL_DESC_CODE16: Descriptor 0, 0ffffh, DA_C ;非一致代码段,16
LABEL_DESC_DATA: Descriptor 0, DataLen-1, DA_DRW + DA_DPL1 ;Data
LABEL_DESC_STACK: Descriptor 0, TopOfStack, DA_DRWA + DA_32 ;Stack,32位
LABEL_DESC_TEST: Descriptor 0500000h, 0ffffh, DA_DRW ;测试代码段
LABEL_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW ;显存首地址
;GDT 结束
 
GdtLen equ $ - LABEL_GDT ;GDT长度
GdtPtr dw GdtLen - 1 ;GDT界限
 dd 0 ;GDT基地址
 
;GDT选择子
SelectorNormal equ LABEL_DESC_NORMAL - LABEL_GDT
SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDT
SelectorCode16 equ LABEL_DESC_CODE16 - LABEL_GDT
SelectorData equ LABEL_DESC_DATA - LABEL_GDT + SA_RPL3
SelectorStack equ LABEL_DESC_STACK - LABEL_GDT
SelectorTest equ LABEL_DESC_TEST - LABEL_GDT
SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT
;END of [SECTION .gdt]
 
[SECTION .data1] ;数据段
ALIGN 32
[BITS 32]
LABEL_DATA:
SPValueInRealMode dw 0
;字符串
PMMessage: db "In Protect Mode now.", 0 ;进入保护模式后显示该字符串
OffsetPMMessage equ PMMessage - $
 
StrTest: db "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 0
OffsetStrTest equ StrTest - $
 
DataLen equ $ - LABEL_DATA
;END of [SECTION .data1]
 
;全局堆栈段
[SECTION .gs]
ALIGN 32
[BITS 32]
LABEL_STACK:
 times 512 db 0
TopOfStack equ $ - LABEL_STACK - 1
;END of [SECTION .gs]
 
[SECTION .s16]
[BITS 16]
LABEL_BEGIN:
 mov ax, cs
 mov ds, ax
 mov es, ax
 mov ss, ax
 mov sp, 0100h
 
mov [LABEL_GO_BACK_TO_REAL + 3], ax
 mov [SPValueInRealMode], sp
 
;初始化16位代码段描述符
 mov ax, cs
 movzx eax, ax
 shl eax, 4
 add eax, LABEL_SEG_CODE16
 mov word[LABEL_DESC_CODE16+2], ax
 shr eax, 16
 mov byte[LABEL_DESC_CODE16+4], al
 mov byte[LABEL_DESC_CODE16+7], ah
 
;初始化32位代码段描述符
 xor eax, eax
 mov ax, cs
 shl eax, 4
 add eax, LABEL_SEG_CODE32
 mov word[LABEL_DESC_CODE32+2], ax
 shr eax, 16
 mov byte[LABEL_DESC_CODE32+4], al
 mov byte[LABEL_DESC_CODE32+7], ah
 
;初始化数据段描述符
 xor eax, eax
 mov ax, ds
 shl eax, 4
 add eax, LABEL_DATA
 mov word[LABEL_DESC_DATA+2], ax
 shr eax, 16
 mov byte[LABEL_DESC_DATA+4], al
 mov byte[LABEL_DESC_DATA+7], ah
 
;初始化堆栈段描述符
 xor eax, eax
 mov ax, ds
 shl eax, 4
 add eax, LABEL_STACK
 mov word[LABEL_DESC_STACK+2], ax
 shr eax, 16
 mov byte[LABEL_DESC_STACK+4], al
 mov byte[LABEL_DESC_STACK+7], ah
 
;为加载GDTR作准备
 xor eax, eax
 mov ax, ds
 shl eax, 4
 add eax, LABEL_GDT ; eax <- gdt
 mov dword[GdtPtr+2], eax ; [GdtPtr+2] <- gdt 基地址
 
;加载GDTR
 lgdt [GdtPtr]
 
;关中断
 cli
 
;打开地址线A20
 in al, 92h
 or al, 00000010b
 out 92h, al
 
;清屏操作(用以指定色彩)
 mov ah, 06H ;功能06H和07H
 mov ch, 00 ;功能描述:初始化屏幕或滚屏
 mov cl, 00 ;入口参数:AH=06H——向上滚屏,07H——向下滚屏
 mov dh, 24 ;AL=滚动行数(0——清窗口)
 mov dl, 79 ;BH=空白区域的缺省属性
 mov bh, 7 ;(CH、CL)=窗口的左上角位置(Y坐标,X坐标)
 mov al, 00 ;(DH、DL)=窗口的右下角位置(Y坐标,X坐标)
 int10H ;出口参数:无
 
;准备切换到保护模式
 mov eax, cr0
 or eax, 1
 mov cr0, eax
 
;真正进入保护模式
 jmp dword SelectorCode32:0 ;执行这一句会把SelectorCode32装入cs,并跳转到SelectorCode32:0处
 
;......................................................................
;,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
 
LABEL_REAL_ENTRY: ;从保护模式跳回到实模式就到了这里
 mov ax, cs
 mov ds, ax
 mov es, ax
 mov ss, ax
 
mov sp, [SPValueInRealMode]
 
in al, 92h ;关闭A20地址线
 and al, 11111101b
 out 92h, al
 
sti ;开中断
 
;回到DOS
 mov ax, 4C00h
 int21h;
;END of [SECTION .s16]
 
[SECTION .s32] ;32位代码段,由实模式跳入
[BITS 32]
 
LABEL_SEG_CODE32:
 mov ax, SelectorData
 mov ds, ax ;数据段选择子
 mov ax, SelectorTest
 mov es, ax ;测试段选择子
 mov ax, SelectorVideo
 mov gs, ax ;视频段选择子
 
mov ax, SelectorStack
 mov ss, ax ;堆栈段选择子
 mov esp, TopOfStack
 
;下面显示一个字符串
 mov ah, 0Ch ;0000:黑底 1100:红字
 xor esi, esi
 xor edi, edi
 mov esi, OffsetPMMessage ;源数据偏移
 mov edi, (80*10+0)*2 ;目的数据偏移。屏幕第10行,第0列
 cld
.1:
 lodsb
 test al, al
 jz .2
 mov [gs:edi], ax ;将ax中的数据送入到显存
 add edi, 2
 jmp .1
.2: ;显示完毕
 
 call DispReturn
 
call TestRead
 call TestWrite
 Call TestRead
 
;到此停止
 jmp SelectorCode16:0
;---------------------------------------------------------------------------
 
TestRead:
 xor esi, esi
 mov ecx, 8
.loop:
 mov al, [es:esi]
 call DispAL
 inc esi
 loop .loop
 
call DispReturn
 
ret
;TestRead结束--------------------------------------------------------------
 
;--------------------------------------------------------------------------
TestWrite:
 push esi
 push edi
 xor esi, esi
 xor edi, edi
 mov esi, OffsetStrTest ;源数据偏移
 
.1:
 lodsb
 test al, al
 jz .2
 mov [es:edi], al
 inc edi
 jmp .1
.2:
 pop edi
 pop esi
 
ret
 
;TestWrite结束--------------------------------------------------------------
 
;---------------------------------------------------------------------------
;显示AL中的数字
;默认地:
; 数字已经存在AL中
; edi始终指向要显示的下一个字符的位置
;被改变的寄存器
; ax, edi
;---------------------------------------------------------------------------
 
DispAL:
 push ecx
 push edx
 
mov ah, 0Ch
 mov dl, al
 shr al, 4
 mov ecx, 2
.begin:
 and al, 01111b
 cmp al, 9
 ja .1
 add al,'0'
 jmp .2
.1:
 sub al, 0Ah
 add al,'A'
.2:
 mov [gs:edi], ax
 add edi, 2
 
mov al, dl
 loop .begin
 add edi, 2
 
 pop edx
 pop ecx
 
ret
;DispAL结束-----------------------------------------------------------------
 
;---------------------------------------------------------------------------
DispReturn:
 push eax
 push ebx
 mov eax, edi
 mov bl, 160
 divbl
 and eax, 0FFh
 inc eax
 mov bl, 160
 mul bl
 mov edi, eax
 pop ebx
 pop eax
 
ret
;DispReturn结束--------------------------------------------------------------
SegCode32Len equ $ - LABEL_SEG_CODE32
; END of [SECTION .s32]
 
;16位代码段,由32位代码段跳入,跳出后到实模式
[SECTION .s16code]
ALIGN 32
[BITS 16]
LABEL_SEG_CODE16:
 ;跳回实模式:
 mov ax, SelectorNormal
 mov ds, ax
 mov es, ax
 mov fs, ax
 mov gs, ax
 mov ss, ax
 
mov eax, cr0
 and al, 11111110b
 mov cr0, eax
 
LABEL_GO_BACK_TO_REAL:
 jmp 0:LABEL_REAL_ENTRY ;段地址会在程序开始处被设置成正确的值
 
Code16Len equ $-LABEL_SEG_CODE16
;END of [SECTION .s16code]
0 0
原创粉丝点击