zoukankan      html  css  js  c++  java
  • 操作系统开发系列—4.LDT

    一直以来,我们把所有的段描述符都放在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]
    

    运行结果如下:

    一个码农的日常 

    源码及软盘映像

  • 相关阅读:
    变量和基本数据类型,深浅拷贝问题
    计算机系统与编程语言分类
    关于计算机硬件的基本知识
    Python学习之路——函数
    Python学习之路——Day06 元组
    day--07
    数据类型——可变不可变类型
    数字类型
    流程控制——while循环
    流程控制——if判断
  • 原文地址:https://www.cnblogs.com/joey-hua/p/5372903.html
Copyright © 2011-2022 走看看