`

(第三章 7)LDT

阅读更多

先展示一下效果图:

 

 

 

直接看代码:

      注意到这段代码是在P38  “3.2.1海阔凭鱼跃”那段代码基础上加上LDT得到的,新添加的代码会着重标注出来的^_^

 

; ==========================================

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

 

 

[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

 

 

; 下面显示一个字符串

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                              ; 即是,将选择子SelectorLDT加载到寄存器LDTR中

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]

 

 

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

 

 

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

 

 

***********************************************************************************************************************************

代码说明及注意:

 

一、LDT段描述符属性——DA_LDT

DA_LDT      EQU   82h   ; 局部描述符表段类型值

 

 98h=0000,0000,1000,0010b,也就是将

     TYPE设置为0010,表示为LDT。见P36

     S设置为0,表示是系统段/门描述符(如果S=1,表示是数据段/代码段描述符)。见P36

     P设置为1,表示在内存中存在。见P35

 

二、通过比较LDT和GDT来深入理解LDT

 

1. “LDT的描述符被包含在GDT中”

 

     “LDT段在GDT段中的地位”和“其他段在GDT段中的地位”平等,只不过其特定的属性表明了他的身份——DA_LDT。他就好像一个混迹市井的贤士高人,不显山露水,但深藏绝技;而这个绝技就是LDT段中可以完成和GDT段类似的功能——定义若干段描述符,只不过LDT中定义的段是局部的!

     关键代码:

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_LDT:    Descriptor       0,        LDTLen - 1, DA_LDT	; LDT
LABEL_DESC_VIDEO:  Descriptor 0B8000h,            0ffffh, DA_DRW	; 显存首地址

 

     下面在LDT中定义一个局部段描述符,和在GDT中定义段描述符有两点区别:

1)在LDT中,不用定义第一个段为空段(全0);

2)在LDT中,所有段的选择子都需要在后面再“或操作”(“+”) SA_STL。注意到SA_STL  equ  4,故实际上是将LDT中定义的局部段的选择子第2位TI置1(表示从LDT中查找段描述符;TI=0表示从GDT中找)处理!

 

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

 

2. “GDT和LDT不干扰程序流程”

    GDT和LDT存在的价值只是负责被查找(查找GDT直接根据GDTR——一步;而查找LDT之前由先要由GDT中LDT的描述符找到LDT的信息——两步),从中找到想要的段的信息。例如,在执行下面代码时,就要查找GDT:

...
[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			; 堆栈段选择子
...
 

 

三、LDT的价值

     在上例的LDT只有一个代码段。不难想象,我们还可以在其中增加更多的段,例如数据段、堆栈段等,这样一来,我们可以把一个单独的任务所用到的东西封装在一个LDT中,这种思想是我们在后面章节中的多任务处理的一个雏形。

 

 

 

  • 大小: 20.8 KB
分享到:
评论

相关推荐

    自己动手写操作系统

    第3章 保护模式(Protect Mode)37 3.1 认识保护模式37 3.1.1 GDT(Global Descriptor Table) 42 3.1.2 实模式到保护模式,不一般的jmp45 3.1.3 描述符属性47 3.2 保护模式进阶50 3.2.1 海阔凭鱼跃50 3.2.2 LDT...

    自己动手写操作系统 电子工业出版社 pdf

    第3章 保护模式(Protect Mode)37 3.1 认识保护模式37 3.1.1 GDT(Global Descriptor Table) 42 3.1.2 实模式到保护模式,不一般的jmp45 3.1.3 描述符属性47 3.2 保护模式进阶50 3.2.1 海阔凭鱼跃50 3.2.2 LDT...

    自己动手写操作系统 pdf

    第3章 保护模式(Protect Mode)37 3.1 认识保护模式37 3.1.1 GDT(Global Des criptor Table) 42 3.1.2 实模式到保护模式,不一般的jmp45 3.1.3 描述符属性47 3.2 保护模式进阶50 3.2.1 海阔凭鱼跃50 3.2.2 LDT...

    x86 x64体系探索及编程part3

    目录 第一篇 x86 基础 第1 章数与数据类型2 1.1 数 2 1.1.1 数字 2 1.1.2 二进制数 3 1.1.3 二进制数的排列 3 1.1.4 十六进制数 5 1.1.5 八进制数与十进制数 5 1.2 数据类型 6 1.2.1 integer 数 6 1.2.2 floating-...

    x86 x64体系探索及编程part4

    目录 第一篇 x86 基础 第1 章数与数据类型2 1.1 数 2 1.1.1 数字 2 1.1.2 二进制数 3 1.1.3 二进制数的排列 3 1.1.4 十六进制数 5 1.1.5 八进制数与十进制数 5 1.2 数据类型 6 1.2.1 integer 数 6 1.2.2 floating-...

    x86 x64体系探索及编程 part2

    目录 第一篇 x86 基础 第1 章数与数据类型2 1.1 数 2 1.1.1 数字 2 1.1.2 二进制数 3 1.1.3 二进制数的排列 3 1.1.4 十六进制数 5 1.1.5 八进制数与十进制数 5 1.2 数据类型 6 1.2.1 integer 数 6 1.2.2 floating-...

    x86 x64体系探索及编程part1

    目录 第一篇 x86 基础 第1 章数与数据类型2 1.1 数 2 1.1.1 数字 2 1.1.2 二进制数 3 1.1.3 二进制数的排列 3 1.1.4 十六进制数 5 1.1.5 八进制数与十进制数 5 1.2 数据类型 6 1.2.1 integer 数 6 1.2.2 floating-...

    自己动手写操作系统(含源代码).part2

    第三,实践类的操作系统书籍还是太少了,以至于你要想看看别人是怎么做的,除了读以《操作系统:设计与实现》为代表的极少数书籍之外,就是一头扎进源代码中,而结果有时相当令人气馁。我自己也气馁过,所以我在第二...

    自己动手写操作系统(含源代码).part1

    第三,实践类的操作系统书籍还是太少了,以至于你要想看看别人是怎么做的,除了读以《操作系统:设计与实现》为代表的极少数书籍之外,就是一头扎进源代码中,而结果有时相当令人气馁。我自己也气馁过,所以我在第二...

    微机课后题目答案 答案

    微机课后题目答案啊 微机接口技术练习题解 第1章 绪论 1. 计算机分那几类?各有什么特点? 答:传统上分为三类:大型主机、小型机、微型机。大型主机一般为高性能的并行处理系统...第3章 8086指令系统及寻址方式

Global site tag (gtag.js) - Google Analytics