您的位置:首页 > 其它

操作系统开发系列—4.LDT

2016-04-09 22:30 316 查看
一直以来,我们把所有的段描述符都放在GDT中,而不管它属于内核还是用户程序,为了有效地在任务之间实施隔离,处理器建议每个任务都应当具有自己的描述符表,称为局部描述符表LDT,并且把专属于自己的那些段放到LDT中。

和GDT一样,LDT也是用来存放描述符的。不同之处在于,LDT只属于某个任务。或者说,每个任务都有自己的LDT,每个任务私有的段,都应当在LDT中进行描述。另外,LDT的第1个描述符,也就是0号槽位,也是有效的、可以使用的。

[SECTION .gdt]
; GDT
;                                                                         段基址,        段界限     ,                              属性
LABEL_GDT:	                      Descriptor          0,                0,                                         0                  ; 空描述符
LABEL_DESC_CODE32: Descriptor           0,             SegCode32Len - 1,    DA_C + DA_32   ; 非一致代码段
LABEL_DESC_VIDEO:    Descriptor    0B8000h,     0ffffh,                              DA_DRW	       ; 显存首地址
LABEL_DESC_LDT:    Descriptor       0,        LDTLen - 1, DA_LDT	; LDT
; GDT 结束

GdtLen		equ	$ - LABEL_GDT	; GDT长度
GdtPtr		dw	GdtLen - 1	; GDT界限
dd	0		; GDT基地址

; GDT 选择子
SelectorCode32		equ	LABEL_DESC_CODE32	- LABEL_GDT
SelectorVideo		equ	LABEL_DESC_VIDEO	- LABEL_GDT
SelectorLDT		equ	LABEL_DESC_LDT		- LABEL_GDT

[SECTION .s16]
[BITS	16]
LABEL_BEGIN:
mov	ax, cs
mov	ds, ax
mov	es, ax
mov	ss, ax
mov	sp, 0100h

; 初始化 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

; 初始化 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,
; 并跳转到 SelectorCode32:0  处
; END of [SECTION .s16]


GDTR全局描述符寄存器:48位,高32位存放GDT基址,低16为存放GDT限长。
LDTR局部描述符寄存器:16位,高13为存放LDT在GDT中的索引值。

LDTR寄存器只用于指向当前任务的LDT。每当发生任务切换时,LDTR的内容被更新以指向新任务的LDT。如果选择子的TI被置为1则系统将从当前LDT中寻找相应描述符。当用到SelectorLDTCodeA时,系统会从LDT中找到LABEL_LDT_DESC_CODEA描述符,并跳转到相应的段中。在用LDT前需要先用lldt指令加载ldtr,lldt的操作数是GDT中用来描述LDT的描述符。

; 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 选择子,SA_TIL将此选择子的TI位置为1.
SelectorLDTCodeA	equ	LABEL_LDT_DESC_CODEA	- LABEL_LDT + SA_TIL
; END of [SECTION .ldt]


使用方法如下:

LABEL_SEG_CODE32:
...
; Load LDT
mov	ax, SelectorLDT
lldt	ax

jmp	SelectorLDTCodeA:0	; 跳入局部任务


下面是最终运行的代码块:

; 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

jmp	$
CodeALen	equ	$ - LABEL_CODE_A
; END of [SECTION .la]


运行结果如下:









源码及软盘映像
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: