`

(第三章 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
分享到:
评论

相关推荐

    电气控制与S7-1500 PLC应用技术第七章 S7-1500 PLC的软件编程.ppt

    ### 电气控制与S7-1500 PLC应用技术:第七章 S7-1500 PLC的软件编程 #### 7.1 S7-1500 PLC的数据结构 **7.1.1 S7-1500 PLC的数据存储区** S7-1500 PLC的数据存储区主要包括以下部分: - **M 区**:内存区域,...

    第三章x86的虚拟存储系统.pdf

    而LDT是进程级的描述符表,每个进程都拥有自己的LDT,用于定义其局部段。GDT和LDT的位置由GDTR和LDTR两个特殊的寄存器指定,这样处理器就能快速定位到相应的描述符表,从而完成地址转换。 逻辑地址向线性地址转换的...

    自己动手写操作系统

    第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...

    操作系统:06第六章_存储管理(左加).ppt

    3. **虚拟地址和段选择符**: - 虚拟地址由47位的段选择符和32位的偏移量组成。 - 段选择符包括16位的索引、2位的特权级和1位的类型标志,指示GDT还是LDT。 4. **分页机制**: - **控制寄存器CR0**:PE位(保护...

    《从实模式到保护模式》第15章代码修改

    《从实模式到保护模式》第15章主要讲解了计算机操作系统中的模式转换,特别是从传统的8086实模式转换到更高级的x86保护模式的过程。这一过程是现代操作系统实现内存管理和多任务的基础。在实模式下,CPU的操作受限,...

    第4章80x86保护模式及其编程.rar_80x86保护模式及其编程

    80x86保护模式是Intel 80x86系列处理器的一种运行模式,它引入了先进的内存管理和安全...《Linux内核编程》第4章80x86保护模式及其编程的PDF文档会详细讲解这些内容,是深入理解保护模式和Linux内核编程的良好资源。

    自己动手写操作系统 电子工业出版社 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-...

    80x86汇编语言程序设计

    第三章可能会讲解内存模型和段机制。80x86处理器使用分段的内存管理方式,每个程序可以有多个数据段、代码段等,通过段选择子和偏移地址来定位内存中的数据。这涉及到DS、CS等段寄存器的使用,以及理解段描述符表...

    intel 手册三卷2012

    第三章着重于介绍保护模式下的内存管理,涵盖了段的使用、分页机制、物理地址空间、逻辑地址与线性地址的转换,以及PAE和PSE-36分页机制。这些机制确保了多任务环境下的内存安全性和隔离性,是现代操作系统的核心...

    X86_64体系结构(系统程序员手册)

    所有的INTEL64和IA32处理器在加电或者复位之后,直接进入实模式(参见第九章处理器管理和初始化)。然后,由软件初始化过程实现从实模式到保护模式的切换。如果最终需要进入IA32e模式,则也由软件初始化过程实现从...

    自己动手写操作系统 第二版

    #### 第3章:保护模式(Protect Mode) - **认识保护模式**:介绍保护模式的基本概念及其与实模式的区别。 - **保护模式的运行环境**:讨论保护模式下的硬件环境和软件需求。 - **GDT(Global Descriptor Table)...

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

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

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

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

    Intel IA-32 Spec V3 chapter2学习笔记

    在《Intel IA-32 Spec V3》的第二章中,系统架构综述部分介绍了Intel IA-32架构的基础概念及其关键组件。IA-32架构自Intel 386处理器家族起便提供了广泛的支持,不仅适用于操作系统(OS)和系统开发软件,还支持多种...

Global site tag (gtag.js) - Google Analytics