《自己动手写操作系统》学习笔记(五)
来源:互联网 发布: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坐标)
int
10H ;出口参数:无
;准备切换到保护模式
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
int
21h;
;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
div
bl
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
- 《自己动手写操作系统》学习笔记(五)
- 自己动手写操作系统学习笔记
- <<自己动手写操作系统>>学习笔记(一)---后记
- 自己动手写操作系统学习笔记1
- 《自己动手写操作系统》学习笔记(四)
- 《自己动手写操作系统》学习笔记(六)
- 自己动手写操作系统学习笔记(一)
- 自己动手写操作系统 笔记
- 自己动手写操作系统(五)
- 自己动手写操作系统笔记1
- 开始学习“自己动手写操作系统”
- 《自己动手写操作系统》学习笔记 之 hello world
- <<自己动手写操作系统>>学习笔记(一)---MBR,PBR,BPB,文件系统
- 自己动手写操作系统--笔记之安装DOS
- 自己动手写操作系统笔记之helloworld
- [自己动手写操作系统]的学习实践【第一章】
- 开篇:学习 《自己动手写操作系统 》于渊
- 《自己动手写嵌入式操作系统》阅读笔记之操作系统小知识
- ITOO之界面显示、级联、模糊显示
- Vuejs——(8)Vuejs组件的定义
- 关于string,stringBuilder,stringBuffer
- [leetcode]15. 3Sum
- maven+springMVC+mysql+mybatis+velocity+事务整合
- 《自己动手写操作系统》学习笔记(五)
- mysql5.7安装和使用--CentOS操作系统
- 刷刷笔试题~~[矩阵]
- hive on spark VS SparkSQL VS hive on tez
- 创建和准备Oracle样例数据库
- 在mac中搭建asp.net环境并开发第一个程序
- 《自己动手写操作系统》学习笔记(四)
- LeetCode 41 First Missing Positive(丢失的第一个正数)
- Oracle 单行函数练习