📄 汇编006.txt
字号:
BASE32 DD 0
LIMIT16 DW 0
PreDesc ENDS
局部描述表寄存器LDTR规定了当前任中使用的局部描述表LDT,LDTR类似于一个段寄存,它的长度为32位,一个16位的寄存器和对程序员来讲不可见的高速缓冲存储器。每一个任务的局部描述符表作为一个特殊的系统段,它由定义在全局描述符表GDT中的描述符来描述,前面已提到过一个任务只能有一张全局描述符表GDT和一张中断描述符表IDT,但可以有多张局部描述行表LDT,而每一张局部描述符表都由定义在GDT中的描述符来确定。通常将描述LDT的选择子装入到LDTR,LDTR根据选择子从全局描述符表中取出对应的描述符,并把LDT的基址及界限信息保存到对程序员来讲不可见的高速缓冲存储器,随后就可以对LDT进行访问。当前任务中的所有段都由GDT中的描述符来描述。
_________ ____________________________________________________
| |______| | | |
| LDTR |______| 32位基址 | 32位界限 |12位属性 |
|_______| |___________________|_____________________|_________|
中断描述符表和全局描述符表一样,长度为48位。32位段基址和16位界限。
如何从实式模式切换到保护模式下呢?通常来讲,要两个步骤:1.作好切换到保护模式下的准备;2.切换到保护模式。主要准备工作就是建立全局描述符表,并使GDTR指向GDT,因为切换到保护模式下,至少要将代码段的选择子装入到CS中,看程序片段:
;定义好描述符的结构
DESCRIPTOR STRUCT
LIMIT DW 0;段界限
BASEL DW 0;段基址的低16位
BASEM DB 0;段基址的16~23位
ATTRIBUTES DW 0;段属性
BASEH DB 0;段基址的高8位,24~31
DESCRIPTOR ENDS
;定义好伪描述符
PDESC STRUCT
LIMIT DW 0
BASE DD 0
PDESC ENDS
;通常要定义一个段间跳转的宏,这样的话就可以保证在进入保护模式时将代码段的选择子装入到CS寄存器
JUMP MACRO selector,offset
DB 0EAH
DW offsetv;段偏移
DW selector;段选择子
ENDM
;打开A20地址线
PUSH AX
IN AL,92H
OR AL,2
OUT 92H,AL
POP AX
;关闭A20地址线
PUSH AX
IN AL,92H
AND AL,0FDH
OUT 92H,AL
POP AX
;切换到保护模式下,将CR0寄存中的第0位置1
MOV EAX,CR0
OR CR0,1
MOV CR0,EAX
其它的部分就要根据具体的应用来写, 下面的例子是如何在保护模下访问820000H单元开始的内容,看程序:
.386P
data segment use16
GDT LABEL BYTE;定义全局描述符表
DUMMY DESCRIPTOR<>;空描述符,它有特定义的含义,空描述符可以保证GDT中的第1个描述符永远不会被访问
CODE DESCRIPTOR<0FFFFH,,,SAttr,>;代码段的描述符
CODE_SEL=CODE-GDT;代码段描述符的选择子
DATAS DESCRIPTOR<0FFFFH,0H,82H,DAttr,>;源数据段描述符,即820000H
DATAS_SEL=DATAS-GDT;源数据段选择子
GDTLEN=$-GDT
VGDTR DESCRIPTOR<GDTLEN-1,>
data ends
code segment use16
assume cs:code,ds:data
start:
mov ax,data
mov ds,ax
mov bx,16
mul bx;设置全局描述表GDT基址,因为现在还处在实模式下,所以段地址要左移4位
add ax,offset GDT
adc dx,0
mov word ptr VGDTR.BASE,ax;设置全局描述符表寄存器GDTR的内容
mov word ptr VGDTR.BASE+2,dx
;设置代码段描述符
mov ax,cs
mul bx
mov CODE.BASEL,ax
mov CODE.BASEM,dl
mov CODE.BASEH,dh
;以下部分你可以根据实际的应用来编写
.........
...........
;加载GDTR
LGDT QWORD PTR VGDTR
CLI;关中断
;打开A20地址线
;切换到保护模式
mov eax,cr0
or eax,1
mov cr0,eax
JUMP <CODE_SEL>,<OFFSET VIRTUAL>;清指令预取队列,真正进入保护模式
........
........
virutal:
;add your code here according to your needs
............
;回到实模式
;关闭A20地址线
STI;开中断
code ends
end start
上述的程序片段是随手写的,可根据需要自已加以调整,不过有点要说明。
a.通常来讲,从实模式下切换到保护模式下只要将CR0寄存器中的最低位设置为1就可以了。但是,此时CS的内容仍然是实模式下的内容,所以加了一条段间跳转指令JUMP <CODE_SEL>,<OFFSET VIRTUAL>,执行完这条指令就可以将代码段选择子CODE_SEL装入到段寄存器CS中,同时也可以刷新指令预取队列。
b.LGDT QWORD PTR VGDTR,该指令的功能是将VGDTR的内容装入到全局描述符表寄存器GDTR中。
c.上面的代码片段中并没有建立中断描述符表IDT,这样的话就要求整个程序必须运行在关中断情况下进行。
d.为了访问1M以上的存储单元,应该打开A20地址线,在WINDOWS下只需加载HIMEM.SYS就可以了。能不能进入保护模式只与是否加载HIMEM.SYS有关,与处理器工作在实方式下还是在保护方式下无关。也就是说,只要加载HIMEM.SYS,就算处理器当前处在实模式下,A20地址线关闭,处理器也一样可以进入保护模式。
下集预告:
80386ASM程序设计基础(十二)---任务切换
80386ASM程序设计基础(十三)---80386中断和异常
80386ASM程序设计基础(十四)---分页管理机制
80386ASM程序设计基础(十五)---V86模式
敬请关注,谢谢。
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -