一个操作系统的实现(2):分段机制

先对分段机制中必须用到的一些名词作一个解释:

段选择符:又称端选择子,是段的一个16位标识符。它并不直接指向段,而是指向段选择符表中定义段的段描述符。它有三个字段内容:请求特权级RPL(Request Privilege Level)、表指示标志TI(Table Index)、索引值(Index)

一个操作系统的实现(2):分段机制_第1张图片

段描述符:段描述符石GDT和LDT表中的一个数据结构项,用来向处理器提供一个有关段的位置和大小信息以及访问控制的状态信息。包含三个主要字段:段基地址、段限长、和段属性。段描述符通常由编译器、连接器、加载器或者操作系统来创建。

一个操作系统的实现(2):分段机制_第2张图片

段描述符表: 是段描述符的一个数组。

一个操作系统的实现(2):分段机制_第3张图片

接下来看一下适用分段机制将逻辑地址转化为线性地址的步骤:

1)使用段选择符中的偏移值(段索引)在GDT或LDT表中定位相应的段描述符.(仅当一个新的段选择符加载到段寄存器中是才需要这一步)

2)利用段选择符检验段的访问权限和范围,以确保该段可访问。

3)把段描述符中取到的段基地址加到偏移量上,最后形成一个线性地址。

从《一个操作系统的实现》的源码来理解分段机制:

org	07c00h								
	jmp	LABEL_BEGIN

[SECTION .gdt]
; GDT
;                              段基址,       段界限     , 属性
LABEL_GDT:	   Descriptor       0,                0, 0           ; 空描述符
LABEL_DESC_CODE32: Descriptor       0, SegCode32Len - 1, DA_C + DA_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 选择子
SelectorCode32		equ	LABEL_DESC_CODE32	- LABEL_GDT
SelectorLDT		equ	LABEL_DESC_LDT		- LABEL_GDT
SelectorVideo		equ	LABEL_DESC_VIDEO	- LABEL_GDT	
; END of [SECTION .gdt]

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

	; a)初始化 32 位代码段描述符
	xor	eax, eax
	mov	ax, cs                             ;把代码段基地址内容赋值给ax
	shl	eax, 4                             ;左移4为相当与*16
	add	eax, LABEL_SEG_CODE32              ;把加上段相对代码段的偏移地址,等于段的基地址
	mov	word [LABEL_DESC_CODE32 + 2], ax   ;将该基地址分别填充到段描述符的 2 3 4 7字节上去
	shr	eax, 16
	mov	byte [LABEL_DESC_CODE32 + 4], al
	mov	byte [LABEL_DESC_CODE32 + 7], ah

	; 初始化 LDT 在 GDT 中的描述符             L1)为了从全局描述符表中找到局部描述符表在内存中的地址
	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 中的描述符                    L2)再从局部描述符表中找到相应段在内存中的地址
	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
			
	; b)为加载 GDTR 作准备
	xor	eax, eax
	mov	ax, ds
	shl	eax, 4
	add	eax, LABEL_GDT		; eax <- gdt 基地址
	mov	dword [GdtPtr + 2], eax	; [GdtPtr + 2] <- gdt 基地址

	; c)加载 GDTR
	lgdt	[GdtPtr]	
						
	; d)关中断
	cli

	; e)打开地址线A20
	in	al, 92h								
	or	al, 00000010b
	out	92h, al								

	; f)准备切换到保护模式
	mov	eax, cr0
	or	eax, 1
	mov	cr0, eax

	; g)真正进入保护模式
	jmp	dword SelectorCode32:0	; 执行这一句会把 SelectorCode32 装入 cs, 
					; 并跳转到 Code32Selector:0  处
; END of [SECTION .s16]


[SECTION .s32]; 32 位代码段. 由实模式跳入.
[BITS	32]

LABEL_SEG_CODE32:
	mov	ax, SelectorVideo					
	mov	gs, ax			; 视频段选择子(目的)		1)把SelectorVideo段段选择子加载到段寄存器gs中

	mov	edi, (80 * 11 + 79) * 2	; 屏幕第 11 行, 第 79 列。
	mov	ah, 0Ch			; 0000: 黑底    1100: 红字
	mov	al, 'P'
	mov	[gs:edi], ax		;3)根据段选择子在GDT中找到相应的段描述符,获得段基地址,再加上偏移量,就得到了实际物理地址,把数据写入该地址,这里是把数据写到显存中 			
	jmp	SelectorLDTCodeA:0	; L3)跳入局部任务	

	; 到此停止
	jmp	$

SegCode32Len	equ	$ - LABEL_SEG_CODE32
; END of [SECTION .s32]

; 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]


; 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]


可以看到最终得到物理地址并写数据需一行代码,但是前面需要做许多准备工作:a、b、c、d、e、f、g。具体内容看代码和批注。

上面讲到的是加载全局描述符表GDT,但是还有一个局部描述符表LDT没有涉及,那么LDT和GDT有什么区别呢,从上面代码上可以看到,LDT可以看做是GDT中的一个段,不过这个段里的内容是一张段描述符表。这两张表的关系如下图:

一个操作系统的实现(2):分段机制_第4张图片

整个虚拟地址空间共含有2^14个段(段选择子索引值为12位,不是应该只有2^12个段吗?),一半空间由GDT映射,另一般则由LDT映射。GDT所映射的一半虚拟地址空间是系统所有任务共有的,而LDT映射的另一半则在任务切换时被改变(这应该就是内核空间与用户空间的概念吧)。

一个操作系统的实现(2):分段机制_第5张图片









你可能感兴趣的:(一个操作系统的实现(2):分段机制)