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

LDT使用初步

在本节中,我们将添加一个LDT段,在段中打印一个字符L,从而学习如何利用程序的LDT段。程序的执行流程随之也会发生变化,我们将分析代码和分析代码结构。

一、概要分析:

在上一节的基础上,我们增加一个段LDT和一个LDT中的一个段codeA。需要注意的是,LDT存在的前提是GDT,因为LDT本身是一个段中,需要由GDT中的信息,得到基地址。另外,这个场景,给出了段选择子,我们如何去索引描述符呢?思考以后,我们知道,我们需要判断但选择子属于GDT还是LDT中的段——这个需要通过选择子的第二位来判断。

我们来理一下程序的执行流程:

初始在实模式下,初始化GDT段描述符,做好进入保护模式的准备工作,经过一个长跳转,进入
保护模式32位代码段,加载相关段选择子,打印相关字符串信息,加载ldtr,进入局部任务codeA段
局部任务段codeA:打印字符,跳转到GDT中的code16段;
code16段:初始化相关寄存器,然后重新跳回实模式(通过jmp )

代码如下:

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
代码如下:
; ==========================================
; pmtest3.asm
; 编译方法:nasm pmtest3.asm -o pmtest3.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 ; Data
LABEL_DESC_STACK: Descriptor 0, TopOfStack, DA_DRWA + DA_32 ; Stack, 32 位
LABEL_DESC_LDT: Descriptor 0, LDTLen - 1, DA_LDT ; LDT
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
SelectorStack equ LABEL_DESC_STACK - LABEL_GDT
SelectorLDT equ LABEL_DESC_LDT - 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
  ; 初始化 LDT 在 GDT 中的描述符
  xor eax, eax
  mov ax, ds
  shl eax, 4
  add eax, LABEL_LDT
  mov word [LABEL_DESC_LDT + 2], ax
  shr eax, 16
  mov byte [LABEL_DESC_LDT + 4], al
  mov byte [LABEL_DESC_LDT + 7], ah
  ; 初始化 LDT 中的描述符
  xor eax, eax
  mov ax, ds
  shl eax, 4
  add eax, LABEL_CODE_A
  mov word [LABEL_LDT_DESC_CODEA + 2], ax
  shr eax, 16
  mov byte [LABEL_LDT_DESC_CODEA + 4], al
  mov byte [LABEL_LDT_DESC_CODEA + 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 eax, cr0
  or eax, 1
  mov cr0, eax
  ; 真正进入保护模式
  jmp dword SelectorCode32:0 ; 执行这一句会把 SelectorCode32 装入 cs, 并跳转到 Code32Selector:0 处
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
LABEL_REAL_ENTRY: ; 从保护模式跳回到实模式就到了这里
  mov ax, cs
  mov ds, ax
  mov es, ax
  mov ss, ax
  mov sp, [SPValueInRealMode]
  in al, 92h ; ┓
  and al, 11111101b ; ┣ 关闭 A20 地址线
  out 92h, al ; ┛
  sti ; 开中断
  mov ax, 4c00h ; ┓
  int 21h ; ┛回到 DOS
; END of [SECTION .s16]
 
&nbsp;
[SECTION .s32]; 32 位代码段. 由实模式跳入.
[BITS 32]
LABEL_SEG_CODE32:
  mov ax, SelectorData
  mov ds, ax ; 数据段选择子
  mov ax, SelectorVideo
  mov gs, ax ; 视频段选择子
  mov ax, SelectorStack
  mov ss, ax ; 堆栈段选择子
  mov esp, TopOfStack
 
&nbsp;
  ; 下面显示一个字符串
  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
  add edi, 2
  jmp .1
.2: ; 显示完毕
  call DispReturn
  ; Load LDT
  mov ax, SelectorLDT
  lldt ax
  jmp SelectorLDTCodeA:0 ; 跳入局部任务
; ------------------------------------------------------------------------
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]
 
&nbsp;
; 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]
 
&nbsp;
; LDT
[SECTION .ldt]
ALIGN 32
LABEL_LDT:
; 段基址 段界限 , 属性
LABEL_LDT_DESC_CODEA: Descriptor 0, CodeALen - 1, DA_C + DA_32 ; Code, 32 位
LDTLen equ $ - LABEL_LDT
; LDT 选择子
SelectorLDTCodeA equ LABEL_LDT_DESC_CODEA - LABEL_LDT + SA_TIL
; END of [SECTION .ldt]
 
&nbsp;
; CodeA (LDT, 32 位代码段)
[SECTION .la]
ALIGN 32
[BITS 32]
LABEL_CODE_A:
  mov ax, SelectorVideo
  mov gs, ax ; 视频段选择子(目的)
  mov edi, (80 * 12 + 0) * 2 ; 屏幕第 10 行, 第 0 列。
  mov ah, 0Ch ; 0000: 黑底 1100: 红字
  mov al, 'L'
  mov [gs:edi], ax
  ; 准备经由16位代码段跳回实模式
  jmp SelectorCode16:0
CodeALen equ $ - LABEL_CODE_A
; END of [SECTION .la]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值