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