80386ASM程式設計基礎(十一) (轉)

gugu99發表於2008-05-26
80386ASM程式設計基礎(十一) (轉)[@more@]

 主要介紹地址暫存器和控制暫存器以及在中實方式下與保護方式下的切換
  80386新增了一組控制暫存器CR0,CR1,CR2,CR3和一組系統地址暫存器GDTR,LDTR,IDTR,TR,它們全部都是32位的。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,禁用分頁管理機制,此時由分段管理部件產生的線性地址就是實體地址。;PG=1,啟用分頁管理機制,此時由分段管理部件產生的線性地址須再經過分頁管理機制才能得到最終的實體地址。
  MP,EM,TS,ET用於控制浮點協處理器的操作。
  CR2和CR3控制暫存器由分頁管理機制使用。CR2用於發生頁異常時報告出錯資訊。當發生頁故障時,處理器會將當前的線性地址儲存在CR2。CR3用於儲存頁表在中的起始實體地址,由於頁表是對齊的,所以僅高20位有效,低12位必須為0。
  全域性描述符表GDT,區域性描述符表LDT和中斷描述符表IDT在保護模式下是特殊的段,也就是說處理器將這些線性表當段一個特殊的段來處理,它包含了對段機制所用的重要資料。為了能夠更地進位這些段,386處理器採用特殊的暫存器儲存這種段的基地址和界限,這種暫存器就是系統地址寄存。在80386下系統地址暫存器有:全域性描述符表暫存器GDTR,區域性描述符表暫存器LDTR,中斷描述符表IDTR,任務狀態段暫存器TR。全域性描述符表暫存器GDTR,長度為48位,其中高32位是基址,低16位含界限。由於GDT本身不可以由GDT內的描述符來描述,所以處理使用GDTR暫存器為GDT這樣的特殊段提供一個偽描述符,即是說:
 
  |  |
  |________________|  全域性描述符表暫存器GDTR
  |  |  ________________________________
  |  GDT  |______|  |  |
  |________________|______| 32位基址  |  16界限 |
  |  |  |___________________|___________|
  |  |
因為段選擇子只用了13位來表描述表中的號,即是說最多可以有8192個描述符,而每個描述符是8個位元組。而在80386處理器下將全域性描述表作為一個特殊的系統段,那麼段的界限實際上就是8192*8,所以段的界限用16位就可以了。通常情況下,如果GDT有N個描述符,那麼GDT的段界限為N*8-1,這個偽描述符也就是全域性描述符暫存器內容可以用結體定義成:
  PreDesc STRUCT
  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 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 or,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
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 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 ,;清指令預取佇列,真正進入保護模式
  ........
  ........
  virutal:
  ;add your code here according to your needs
  ............
  ;回到真實模式
  ;關閉A20地址線
  STI;開中斷
code ends
end start
上述的程式片段是隨手寫的,可根據需要自已加以調整,不過有點要說明。
a.通常來講,從真實模式下切換到保護模式下只要將CR0暫存器中的最低位設定為1就可以了。但是,此時CS的內容仍然是真實模式下的內容,所以加了一條段間跳轉指令JUMP ,,完這條指令就可以將程式碼段選擇子CODE_SEL裝入到段暫存器CS中,同時也可以重新整理指令預取佇列。 
b.LGDT QWORD PTR VGDTR,該指令的功能是將VGDTR的內容裝入到全域性描述符表暫存器GDTR中。
c.上面的程式碼片段中並沒有建立中斷描述符表IDT,這樣的話就要求整個程式必須執行在關中斷情況下進行。
d.為了訪問1M以上的儲存單元,應該開啟A20地址線,在下只需載入HIMEM.SYS就可以了。能不能進入保護模式只與是否載入HIMEM.SYS有關,與處理器工作在實方式下還是在保護方式下無關。也就是說,只要載入HIMEM.SYS,就算處理器當前處在真實模式下,A20地址線關閉,處理器也一樣可以進入保護模式。
下集預告:
80386ASM基礎(十二)---任務切換
80386ASM程式設計基礎(十三)---80386中斷和異常
80386ASM程式設計基礎(十四)---分頁管理機制
80386ASM程式設計基礎(十五)---V86模式
敬請關注,謝謝。 
 


 


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10748419/viewspace-1004599/,如需轉載,請註明出處,否則將追究法律責任。

相關文章