主要介紹系統(tǒng)地址寄存器和控制寄存器以及在程序中實方式下與保護方式下的切換
80386處理器新增了一組控制寄存器CR0,CR1,CR2,CR3和一組系統(tǒng)地址寄存器GDTR,LDTR,IDTR,TR,它們?nèi)慷际?2位的。CR0包含了指定處理器工作方式的控制位,CR1保留未使用,CR2和CR3由分頁管理部件使用,CR0中的5~30位和CR3中的0~11位必須為0,分別介紹如下:
___________________________________________________________________________
|PG|0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |ET|TS|EM|MP|PE| CR0
|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|_ |__|
| Reserved | CR1
|__________________________________________________________________________|
| 頁故障線性地址 | CR2
|__________________________________________________________________________|
| 高20位頁表的起始物理地址 |低12位為0 | CR3
|_____________________________________________________|____________________|
PE標記用于指定處理器的工作模式。PE=0,處理器處于實模式;PE=1,處理器處于保護模式
PG標記用于指定處理器是否啟用分頁管理機制。PG=0,禁用分頁管理機制,此時由分段管理部件產(chǎn)生的線性地址就是物理地址。;PG=1,啟用分頁管理機制,此時由分段管理部件產(chǎn)生的線性地址須再經(jīng)過分頁管理機制才能得到最終的物理地址。
MP,EM,TS,ET用于控制浮點協(xié)處理器的操作。
CR2和CR3控制寄存器由分頁管理機制使用。CR2用于發(fā)生頁異常時報告出錯信息。當發(fā)生頁故障時,處理器會將當前的線性地址保存在CR2。CR3用于保存頁表在內(nèi)存中的起始物理地址,由于頁表是對齊的,所以僅高20位有效,低12位必須為0。
全局描述符表GDT,局部描述符表LDT和中斷描述符表IDT在保護模式下是特殊的段,也就是說處理器將這些線性表當段一個特殊的段來處理,它包含了對段機制所用的重要數(shù)據(jù)。為了能夠更快速地進位這些段,386處理器采用特殊的寄存器保存這種段的基地址和界限,這種寄存器就是系統(tǒng)地址寄存。在80386下系統(tǒng)地址寄存器有:全局描述符表寄存器GDTR,局部描述符表寄存器LDTR,中斷描述符表IDTR,任務(wù)狀態(tài)段寄存器TR。全局描述符表寄存器GDTR,長度為48位,其中高32位是基址,低16位含界限。由于GDT本身不可以由GDT內(nèi)的描述符來描述,所以處理使用GDTR寄存器為GDT這樣的特殊段提供一個偽描述符,即是說:
| |
|________________| 全局描述符表寄存器GDTR
| | ________________________________
| GDT |______| | |
|________________|______| 32位基址 | 16界限 |
| | |___________________|___________|
| |
因為段選擇子只用了13位來表描述表中的索引號,即是說最多可以有8192個描述符,而每個描述符是8個字節(jié)。而在80386處理器下將全局描述表作為一個特殊的系統(tǒng)段,那么段的界限實際上就是8192*8,所以段的界限用16位就可以了。通常情況下,如果GDT有N個描述符,那么GDT的段界限為N*8-1,這個偽描述符也就是全局描述符寄存器內(nèi)容可以用結(jié)體定義成:
PreDesc STRUCT
BASE32 DD 0
LIMIT16 DW 0
PreDesc ENDS
局部描述表寄存器LDTR規(guī)定了當前任中使用的局部描述表LDT,LDTR類似于一個段寄存,它的長度為32位,一個16位的寄存器和對程序員來講不可見的高速緩沖存儲器。每一個任務(wù)的局部描述符表作為一個特殊的系統(tǒng)段,它由定義在全局描述符表GDT中的描述符來描述,前面已提到過一個任務(wù)只能有一張全局描述符表GDT和一張中斷描述符表IDT,但可以有多張局部描述行表LDT,而每一張局部描述符表都由定義在GDT中的描述符來確定。通常將描述LDT的選擇子裝入到LDTR,LDTR根據(jù)選擇子從全局描述符表中取出對應(yīng)的描述符,并把LDT的基址及界限信息保存到對程序員來講不可見的高速緩沖存儲器,隨后就可以對LDT進行訪問。當前任務(wù)中的所有段都由GDT中的描述符來描述。
_________ ____________________________________________________
| |______| | | |
| LDTR |______| 32位基址 | 32位界限 |12位屬性 |
|_______| |___________________|_____________________|_________|
中斷描述符表和全局描述符表一樣,長度為48位。32位段基址和16位界限。
如何從實式模式切換到保護模式下呢?通常來講,要兩個步驟:1.作好切換到保護模式下的準備;2.切換到保護模式。主要準備工作就是建立全局描述符表,并使GDTR指向GDT,因為切換到保護模式下,至少要將代碼段的選擇子裝入到CS中,看程序片段:
;定義好描述符的結(jié)構(gòu)
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
;通常要定義一個段間跳轉(zhuǎn)的宏,這樣的話就可以保證在進入保護模式時將代碼段的選擇子裝入到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
;關(guān)閉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
其它的部分就要根據(jù)具體的應(yīng)用來寫, 下面的例子是如何在保護模下訪問820000H單元開始的內(nèi)容,看程序:
.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,>;源數(shù)據(jù)段描述符,即820000H
DATAS_SEL=DATAS-GDT;源數(shù)據(jù)段選擇子
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;設(shè)置全局描述表GDT基址,因為現(xiàn)在還處在實模式下,所以段地址要左移4位
add ax,offset GDT
adc dx,0
mov word ptr VGDTR.BASE,ax;設(shè)置全局描述符表寄存器GDTR的內(nèi)容
mov word ptr VGDTR.BASE+2,dx
;設(shè)置代碼段描述符
mov ax,cs
mul bx
mov CODE.BASEL,ax
mov CODE.BASEM,dl
mov CODE.BASEH,dh
;以下部分你可以根據(jù)實際的應(yīng)用來編寫
.........
...........
;加載GDTR
LGDT QWORD PTR VGDTR
CLI;關(guān)中斷
;打開A20地址線
;切換到保護模式
mov eax,cr0
or eax,1
mov cr0,eax
JUMP <CODE_SEL>,<OFFSET VIRTUAL>;清指令預(yù)取隊列,真正進入保護模式
........
........
virutal:
;add your code here according to your needs
............
;回到實模式
;關(guān)閉A20地址線
STI;開中斷
code ends
end start
上述的程序片段是隨手寫的,可根據(jù)需要自已加以調(diào)整,不過有點要說明。
a.通常來講,從實模式下切換到保護模式下只要將CR0寄存器中的最低位設(shè)置為1就可以了。但是,此時CS的內(nèi)容仍然是實模式下的內(nèi)容,所以加了一條段間跳轉(zhuǎn)指令JUMP <CODE_SEL>,<OFFSET VIRTUAL>,執(zhí)行完這條指令就可以將代碼段選擇子CODE_SEL裝入到段寄存器CS中,同時也可以刷新指令預(yù)取隊列。
b.LGDT QWORD PTR VGDTR,該指令的功能是將VGDTR的內(nèi)容裝入到全局描述符表寄存器GDTR中。
c.上面的代碼片段中并沒有建立中斷描述符表IDT,這樣的話就要求整個程序必須運行在關(guān)中斷情況下進行。
d.為了訪問1M以上的存儲單元,應(yīng)該打開A20地址線,在WINDOWS下只需加載HIMEM.SYS就可以了。能不能進入保護模式只與是否加載HIMEM.SYS有關(guān),與處理器工作在實方式下還是在保護方式下無關(guān)。也就是說,只要加載HIMEM.SYS,就算處理器當前處在實模式下,A20地址線關(guān)閉,處理器也一樣可以進入保護模式。