80386開始支持存儲器分頁管理機制。分頁機制是存儲器管理機制的第3二部分。段管理機制實現虛擬地址(由段和偏移構成的邏輯地址)到線性地址的轉換,分頁管理機制實現線性地址到物理地址的轉換。如果不啟用分頁管理機制,那么線性地址就是物理地址。本文將介紹80386的存儲器分頁管理機制和線性地址如何轉換為物理地址。
<一>存儲器分頁管理機制
在保護模式下,控制寄存器CR0中的最高位PG位控制分頁管理機制是否生效。如果PG=1,分頁機制生效,把線性地址轉換為物理地址。如果PG=0,分頁機制無效,線性地址就直接作為物理地址。必須注意,只有在保護方式下分頁機制才可能生效。只有在保證使PE位為1的前提下,才能夠使PG位為1,否則將引起通用保護故障。
分頁機制把線性地址空間和物理地址空間分別劃分為大小相同的塊。這樣的塊稱之為頁。通過在線性地址空間的頁與物理地址空間的頁之間建立的映射,分頁機制實現線性地址到物理地址的轉換。線性地址空間的頁與物理地址空間的頁之間的映射可根據需要而確定,可根據需要而改變。線性地址空間的任何一頁,可以映射為物理地址空間中的任何一頁。
采用分頁管理機制實現線性地址到物理地址轉換映射的主要目的是便于實現虛擬存儲器。不象段的大小可變,頁的大小是相等并固定的。根據程序的邏輯劃分段,而根據實現虛擬存儲器的方便劃分頁。
在80386中,頁的大小固定為4K字節,每一頁的邊界地址必須是4K的倍數。因此,4G大小的地址空間被劃分為1M個頁,頁的開始地址具有“XXXXX000H”的形式。為此,我們把頁開始地址的高20位XXXXXH稱為頁碼。線性地址空間頁的頁碼也就是頁開始邊界線性地址的高20位;物理地址空間頁的頁碼也就是頁開始邊界物理地址的高20位。可見,頁碼左移12位就是頁的開始地址,所以頁碼規定了頁。
由于頁的大小固定為4K字節,且頁的邊界是4K的倍數,所以在把32位線性地址轉換成32位物理地址的過程中,低12位地址保持不變。也就是說,線性地址的低12位就是物理地址的低12位。假設分頁機制采用的轉換映射把線性地址空間的XXXXXH頁映射到物理地址空間的YYYYYH頁,那么線性地址XXXXXxxxH被轉換為YYYYYxxxH。因此,線性地址到物理地址的轉換要解決的是線性地址空間的頁到物理地址空間的頁的映射,也就是線性地址高20位到物理地址高20位的轉換。
<二>線性地址到物理地址的轉換
1.映射表結構
線性地址空間的頁到物理地址空間的頁之間的映射用表來描述。由于4G的地址空間劃分為1M個頁,因此,如果用一張表來描述這種映射,那么該映射表就要有1M個表項,若每個表項占用4個字節,那么該映射表就要占用4M字節。為避免映射表占用如此巨大的存儲器資源,所以80386把頁映射表分為兩級。
頁映射表的第一級稱為頁目錄表,存儲在一個4K字節的物理頁中。頁目錄表共有1K個表項,其中,每個表項為4字節長,包含對應第二級表所在物理地址空間頁的頁碼。頁映射表的第二級稱為頁表,每張頁表也安排在一個4K字節的頁中。每張頁表都有1K個表項,每個表項為4字節長,包含對應物理地址空間頁的頁碼。由于頁目錄表和頁表均由1K個表項組成,所以使用10位的索引就能指定表項,即用10位的索引值乘以4加基地址就得到了表項的物理地址。
下圖顯示了由頁目錄表和頁表構成的頁映射表結構。從圖中可見,控制寄存器CR3指定頁目錄表;頁目錄表可以指定1K個頁表,這些頁表可以分散存放在任意的物理頁中,而不需要連續存放;每張頁表可以指定1K個物理地址空間的頁,這些物理地址空間的頁可以任意地分散在物理地址空間中。需要注意的是,存儲頁目錄表和頁表的基地址是對齊在4K字節邊界上的。
2.表項格式
頁目錄表和頁表中的表項都采用如下圖所示的格式。從圖中可見,最高20位(位12—位31)包含物理地址空間頁的頁碼,也就是物理地址的高20位。低12位包含頁的屬性。下圖所示的屬性中內容為0的位是Intel公司為80486等處理器所保留的位,在為80386編程使用到它們時必須設置為0。在位9至位11的AVL字段供軟件使用。表項的最低位是存在屬性位,記作P。P位表示該表項是否有效。P=1表項有效;P=0表項無效,此時表項中的其余各位均可供軟件使用,80386不解釋P=0的表項中的任何其它的位。在通過頁目錄表和頁表進行的線性地址到物理地址的轉換過程中,無論在頁目錄表還是在頁表中遇到無效表項,都會引起頁故障。其它屬性位的作用在下文中介紹。
頁目錄表或頁
表的表項格式 BIT31—BIT12 BIT11—BIT9 BIT8 BIT7 BIT6 BIT5 BIT4 BIT3 BIT2 BIT1 BIT0 物理頁碼 AVL 0 0 D A 0 0 U/S R/W P
3.線性地址到物理地址的轉換
分頁管理機制通過上述頁目錄表和頁表實現32位線性地址到32位物理地址的轉換。控制寄存器CR3的高20位作為頁目錄表所在物理頁的頁碼。首先把線性地址的最高10位(即位22至位31)作為頁目錄表的索引,對應表項所包含的頁碼指定頁表;然后,再把線性地址的中間10位(即位12至位21)作為所指定的頁目錄表中的頁表項的索引,對應表項所包含的頁碼指定物理地址空間中的一頁;最后,把所指定的物理頁的頁碼作為高20位,把線性地址的低12位不加改變地作為32位物理地址的低12位。
為了避免在每次存儲器訪問時都要訪問內存中的頁表,以便提高訪問內存的速度,80386處理器的硬件把最近使用的線性—物理地址轉換函數存儲在處理器內部的頁轉換高速緩存中。在訪問存儲器頁表之前總是先查閱高速緩存,僅當必須的轉換不在高速緩存中時,才訪問存儲器中的兩級頁表。頁轉換高速緩存也稱為頁轉換查找緩存,記為TLB。
在分頁機制轉換高速緩存中的數據與頁表中數據的相關性,不是由80386處理器進行維護的,而必須由操作系統軟件保存,也就是說,處理器不知道軟件什么時候會修改頁表,在一個合理的系統中,頁表只能由操作系統修改,操作系統可以直接地在軟件修改頁表后通過刷新高速緩存來保證相關性。高速緩存的刷新通過裝入處理器控制寄存器CR3完成,實際過程可能用如下的兩條指令實現:
mov eax,cr3
mov cr3,eax
一個重要的修改頁表項的特殊情況不需要對頁轉換高速緩存刷新,這種情況是指修改不存在表項的任一部分,即使P位本身從P=0改變為P=1時也一樣,因為無效的表項不會存入高速緩存。因此,當無效的表項被改變時,不需要刷新高速緩存。這表明在從磁盤上讀入一頁使其存在時,不必刷新高速緩存。
在一個多處理器系統中,必須特別注意是否在一個處理器中執行的程序,會改變可能由另外的處理器同時訪問的頁表。在80386處理器中,每當要更新頁表項并設置D位和A位時,通過使用不可分的讀/修改/寫周期支持多處理器的配置。對于頁表項的軟件更新需要借助于使用LOCK前綴,從而保證修改頁表的指令工作在不可分的讀/修改/寫周期中。在改變一個可能由另外的處理器使用的頁表之前,最好使用一條加鎖的AND指令在一個不可分的操作中將P位清除為0,然后,該表項可根據要求進行修改,并隨后把P位置成1而使表項成為可用。當修改頁表項時必須及時通知(通常使用中斷方式)系統中該表項已被高速緩存的所有處理器刷新各自的頁轉換高速緩存,以撤消該表項的舊拷貝。在表項的舊拷貝被刷新之前,各處理器仍可繼續訪問舊的頁,并可以設置正被修改的表項的D位。如果這樣做引起表項修改失敗,則分頁機制高速緩存最好在標記為不存在之后,并在對表項進行另外的修改之前進行刷新。
4.不存在的頁表
采用上述頁映射表結構,存儲全部1K張頁表需要4M字節,此外還需要4K字節用于存儲頁目錄表。這樣的兩級頁映射表似乎反而比單一的整張頁映射表多占用4K字節。其實不然,事實上不需要在內存中存儲完整的兩級頁映射表。兩級頁映射表結構中對于線性地址空間中不存在的或未使用的部分不必分配頁表。除必須給頁目錄表分配物理頁外,僅當在需要時才給頁表分配物理頁,于是頁映射表的大小就對應于實際使用的線性地址空間大小。因為任何一個實際運行的程序使用的線性地址空間都遠小于4G字節,所以用于分配給頁表的物理頁也遠小于4M字節。
頁目錄表項中的存在位P表明對應頁表是否有效。如果P=1,表明對應頁表有效,可利用它進行地址轉換;如果P=0,表明對應頁表無效。如果試圖通過無效的頁表進行線性地址到物理地址的轉換,那么將引起頁故障。因此,頁目錄表項中的屬性位P使得操作系統只需給覆蓋實際使用的線性地址范圍的頁表分配物理頁。
頁目錄表項中的屬性位P頁可用于把頁表存儲在虛擬存儲器中。當發生由于所需頁表無效而引起的頁故障時,頁故障處理程序再申請物理頁,從磁盤上把對應的頁表讀入,并把對應頁目錄表項中的P位置1。換言之,可以當需要時才為所要的頁表分配物理頁。這樣頁表占用的物理頁數量可降到最小。
5.頁的共享
由上述頁映射表結構可見,分頁機制沒有全局頁和局部頁的規定。每一個任務可使用自己的頁映射表獨立地實現線性地址到物理地址的轉換。但是,如果使每一個任務所用的頁映射表具有部分相同的映射,那么也就可以實現部分頁的共享。
常用的實現頁共享的方法是線性地址空間的共享,也就是不同任務的部分相同的線性地址空間的映射信息相同,具體表現為部分頁表相同或頁表內的部分表項的頁碼相同。例如,如果任務A和任務B分別使用的頁目錄表A和頁目錄表B內的第0項中的頁碼相同,也就是頁表0相同,那么任務A和任務B的00000000H至003FFFFFH線性地址空間就映射到相同的物理頁。再如,任務A和任務B使用的頁表0不同,但這兩張頁表內第0至第0FFH項的頁碼對應相同,那么任務A和任務B的00000000H至000FFFFFH線性地址空間就映射到相同的物理頁。
需要注意的是,共享的頁表最好由兩個頁目錄中同樣的目錄項所指定。這一點很重要,因為它保證了在兩個任務中同樣的線性地址范圍將映射到該全局區域。
<三>頁級保護和虛擬存儲器支持
1.頁級保護
80386不僅提供段級保護,也提供頁級保護。分頁機制只區分兩種特權級。特權級0、1和2統稱為系統特權級,特權級3稱為用戶特權級。在上圖所示頁目錄表和頁表的表項中的保護屬性位R/W和U/S就是用于對頁進行保護。
表項的位1是讀寫屬性位,記作R/W。R/W位指示該表項所指定的頁是否可讀、寫或執行。若R/W=1,對表項所指定的頁可進行讀、寫或執行;若R/W=0,對表項所指定的頁可讀或執行,但不能對該指定的頁寫入。但是,R/W位對頁的寫保護只在處理器處于用戶特權級時發揮作用;當處理器處于系統特權級時,R/W位被忽略,即總可以讀、寫或執行。
表項的位2是用戶/系統屬性位,記作U/S。U/S位指示該表項所指定的頁是否是用戶級頁。若U/S=1,表項所指定的頁是用戶級頁,可由任何特權級下執行的程序訪問;如果U/S=0,表項所指定的頁是系統級頁,只能由系統特權級下執行的程序訪問。下表列出了上述屬性位R/W和U/S所確定的頁級保護下,用戶級程序和系統級程序分別具有的對用戶級頁和系統級頁進行操作的權限。
頁級
保護
屬性 U/S R/W 用戶級訪問權限系統級訪問權限 0 0 無讀/寫/執行 0 1 無讀/寫/執行 1 0 讀/執行讀/寫/執行 1 1 讀/寫/執行讀/寫/執行
由上表可見,用戶級頁可以規定為只允許讀/執行或規定為讀/寫/執行。系統級頁對于系統級程序總是可讀/寫/執行,而對用戶級程序總是不可訪問的。于分段機制一樣,外層用戶級執行的程序只能訪問用戶級的頁,而內層系統級執行的程序,既可訪問系統級頁,也可訪問用戶級頁。與分段機制不同的是,在內層系統級執行的程序,對任何頁都有讀/寫/執行訪問權,即使規定為只允許讀/執行的用戶頁,內層系統級程序也對該頁有寫訪問權。
頁目錄表項中的保護屬性位R/W和U/S對由該表項指定頁表所指定的全部1K各頁起到保護作用。所以,對頁訪問時引用的保護屬性位R/W和U/S的值是組合計算頁目錄表項和頁表項中的保護屬性位的值所得。下表列出了組合計算前后的保護屬性位的值,組合計算是“與”操作。
組合頁的
保護>屬性目錄表項U/S 頁表項U/S 組合U/S 目錄表項R/W 頁表項R/W 組合R/W 0 0 0 0 0 0 0 1 0 0 1 0 1 0 0 1 0 0 1 1 1 1 1 1
正如在80386地址轉換機制中分頁機制在分段機制之后起作用一樣,由分頁機制支持的頁級保護也在由分段機制支持的段級保護之后起作用。先測試有關的段級保護,如果啟用分頁機制,那么在檢查通過后,再測試頁級保護。如果段的類型為讀/寫,而頁規定為只允許讀/執行,那么不允許寫;如果段的類型為只讀/執行,那么不論頁保護如何,也不允許寫。
頁級保護的檢查是在線性地址轉換為物理地址的過程中進行的,如果違反頁保護屬性的規定,對頁進行訪問(讀/寫/執行),那么將引起頁異常。
2.對虛擬存儲器的支持
頁表項中的P位是支持采用分頁機制虛擬存儲器的關鍵。P=1,表示表項指定的頁存在于物理存儲器中,并且表項的高20位是物理頁的頁碼;P=0,表示該線性地址空間中的頁所對應的物理地址空中的頁不在物理存儲器中。如果程序訪問不存在的頁,會引起頁異常,這樣操作系統可把該不存在的頁從磁盤上讀入,把所在物理頁的頁碼填入對應表項并把表項中的P位置為1,然后使引起異常的程序恢復運行。
此外,表項中的訪問位A和寫標志位D也用于支持有效地實現虛擬存儲器。
表項的位5是訪問屬性位,記作A。在為了訪問某存儲單元而進行線性地址到物理地址的轉換過程中,處理器總是把頁目錄表內的對應表項和其所指定頁表內的對應表項中的A位置1,除非頁表或頁不存在,或者訪問違反保護屬性規定。所以,A=1表示已訪問過對應的物理頁。處理器永不清除A位。通過周期性地檢測及清除A位,操作系統就可確定哪些頁在最近一段時間未被訪問過。當存儲器資源緊缺時,這些最近未被訪問的頁很可能就被選擇出來,將它們從內存換出到磁盤上去。
表項的位6是寫標志位,記作D。在為了訪問某存儲單元而進行線性地址到物理地址的轉換過程中,如果是寫訪問并且可以寫訪問,處理器就把頁表內對應表項中的D位置1,但并不把頁目錄表內對應表項中的D置1。當某頁從磁盤上讀入內存時,頁表中對應對應表項的D位被清0。所以,D=1表示已寫過對應的物理頁。當某頁需要從內存換出到磁盤上時,如果該頁的D位為1,那么必須進行寫操作(把內存中的頁寫入磁盤時,處理器并不清除對應頁表項的D位)。但是,如果要寫到磁盤上的頁的D位為0,那么不需要實際的磁盤寫操作,而只要簡單地放棄內存中該頁即可。因為內存中的頁與磁盤中的頁具有完全相同的內容。
<四>頁異常
啟用分頁機制后,線性地址不再直接等于物理地址,線性地址要經過分頁機制轉換才成為物理地址。在轉換過程中,如果出現下列情況之一就會引起頁異常:
(1)涉及的頁目錄表內的表項或頁表內的表項中的P=0,即涉及到頁不在內存;
(2)發現試圖違反頁保護屬性的規定而對頁進行訪問。
報告頁異常的中斷向量號是14(0EH)。頁異常屬于故障類異常。在進入故障處理程序時,保存的指令指針CS及EIP指向發生故障的指令。一旦引起頁故障的原因被排除后,即可從頁故障處理程序通過一條IRET指令,直接地重新執行產生故障的指令。
當頁故障發生時,處理器把引起頁故障的線性地址裝入CR2。頁故障處理程序可以利用該線性地址確定對應的頁目錄項和頁表項。
頁故障還在堆棧中提供一個出錯碼,出錯碼的格式如下圖所示。其中,U位表示引起故障程序的特權級,U=1表示用戶特權級(特權級3),U=0表示系統特權級(特權級0、1或2);W位表示訪問類型,W=0表示讀/執行,W=1表示寫;P位表示異常類型,P=0表示頁不存在故障,P=1表示保護故障。頁故障的響應處理模式同其它故障一樣。
出錯碼
的格式 BIT15—BIT3 BIT2 BIT1 BIT0 未使用 U W P
<五>演示分頁機制的實例(實例十)
下面給出一個演示如何啟用分頁管理機制的實例。該實例的邏輯功能是,在屏幕上顯示一條表示已啟用分頁管理機制的提示信息。該實例演示內容包括:初始化頁目錄表和部分頁表;啟用分頁管理機制;關閉分頁管理機制等。該實例假設系統至少有4M字節物理內存。
1.演示步驟和源程序清單
為了簡單化,實例只有一個任務,并且沒有局部描述符表和中斷描述符表,不允許中斷,也不考慮發生異常,甚至沒有使用堆棧。實例執行步驟如下:
(1)在實模式下為進入保護模式作初始化;
(2)切換到保護模式后進入臨時代碼段,把部分演示代碼傳送到預定的內存,然后轉演示代碼段;
(3)建立頁目錄表;
(4)建立頁表;
(5)啟用分頁管理機制;
(6)演示在分頁管理機制啟用后的程序執行和數據存取;
(7)關閉分頁管理機制;
(8)退出保護模式,結束。
實例十源程序清單如下:
;名稱:ASM10.ASM
;功能:演示使用分頁管理機制
;編譯:TASM ASM10.ASM
;連接:TLINK ASM10.OBJ
;============================================================================
INCLUDE 386SCD.INC
;============================================================================
PDT_AD = 200000h ;頁目錄表所在物理頁的地址
PT0_AD = 202000h ;頁表0所在物理頁的地址
PT1_AD = 201000h ;頁表1所在物理頁的地址
PhVB_AD = 0b8000h ;物理視頻緩沖區地址
LoVB_AD = 0f0000h ;程序使用的邏輯視頻緩沖區地址
MPVB_AD = 301000h ;線性地址0B8000H所映射的物理地址
PhSC_AD = 303000h ;部分演示代碼所在內存的物理地址
LoSC_AD = 402000h ;部分演示代碼的邏輯地址
;============================================================================
GDTSeg SEGMENT PARA USE16 ;全局描述符表數據段(16位)
;----------------------------------------------------------------------------
;全局描述符表GDT
GDT LABEL BYTE
;空描述符
DUMMY Desc <>
;規范段描述符及選擇子
Normal Desc <0ffffh,,,ATDW,,>
Normal_Sel = Normal-GDT
;頁目錄表所在段描述符(在保護方式下初始化時用)及選擇子
PDT Desc <0fffh,PDT_AD AND 0ffffh,PDT_AD SHR 16,ATDW,,>
PDT_Sel = PDT-GDT
;頁表0所在段描述符(在保護方式下初始化時用)及選擇子
PT0 Desc <0fffh,PT0_AD AND 0ffffh,PT0_AD SHR 16,ATDW,,>
PT0_Sel = PT0-GDT
;頁表1所在段描述符(在保護方式下初始化時用)及選擇子
PT1 Desc <0fffh,PT1_AD AND 0ffffh,PT1_AD SHR 16,ATDW,,>
PT1_Sel = PT1-GDT
;邏輯視頻緩沖區段描述符及選擇子
LoVideo Desc <3999,LoVB_AD AND 0ffffh,LoVB_AD SHR 16,ATDW,,>
LoVideo_Sel = LoVideo-GDT
;邏輯上的部分演示代碼段的描述符及選擇子
LoCode Desc <SCodeLen-1,LoSC_AD AND 0ffffh,LoSC_AD SHR 16,ATCE,,>
LoCode_Sel = LoCode-GDT
;預定內存區域(用于部分演示代碼)的段描述符及選擇子
TPSCode Desc <SCodeLen-1,PhSC_AD AND 0ffffh,PhSC_AD SHR 16,ATDW,,>
TPSCode_Sel = TPSCode-GDT
;----------------------------------------------------------------------------
;以下是需額外初始化的描述符
EFFGDT LABEL BYTE
;臨時代碼段描述符及選擇子
TempCode Desc <0ffffh,TempCodeSeg,,ATCE,,>
TempCode_Sel = TempCode-GDT
;演示代碼段描述符及選擇子
DemoCode Desc <DemoCodeLen-1,DemoCodeSeg,,ATCE,,>
DemoCode_Sel = DemoCode-GDT
;演示任務數據段描述符及選擇子
DemoData Desc <DemoDataLen-1,DemoDataSeg,,ATDW,,>
DemoData_Sel = DemoData-GDT
;初始化時要移動的代碼段描述符及選擇子(移動時作為數據對待)
SCode Desc <SCodeLen-1,SCodeSeg,,ATDR,,>
SCode_Sel = SCode-GDT
;----------------------------------------------------------------------------
GDTLen = $-GDT ;全局描述符表長度
GDNum = ($-EFFGDT)/(SIZE Desc) ;需特殊處理的描述符數
;----------------------------------------------------------------------------
GDTSeg ENDS ;全局描述符表段定義結束
;============================================================================
;這部分代碼在初始化時被復制到預定的內存區域,其功能是在屏幕上顯示提示信息
;----------------------------------------------------------------------------
SCodeSeg SEGMENT PARA USE16
ASSUME CS:SCodeSeg,DS:DemoDataSeg
;----------------------------------------------------------------------------
SBegin PROC FAR
mov ax,LoVideo_Sel
mov es,ax
mov di,0
mov ah,17h
mov cx,MessLen
S1: lodsb
stosw
loop S1
JUMP16 DemoCode_Sel,Demo3
SBegin ENDP
;----------------------------------------------------------------------------
MLen = $-SBegin
SCodeLen = $
SCodeSeg ENDS
;============================================================================
DemoDataSeg SEGMENT PARA USE16 ;演示任務數據段
Mess DB 'Page is OK!'
MessLen = $-Mess
DemoDataLen = $
DemoDataSeg ENDS
;============================================================================
DemoCodeSeg SEGMENT PARA USE16 ;演示任務代碼段
ASSUME CS:DemoCodeSeg
;----------------------------------------------------------------------------
DemoBegin PROC FAR
mov ax,PDT_Sel
mov es,ax
xor di,di
mov cx,1024
xor eax,eax ;先把全部表項置成無效
rep stosd ;再置表項0和表項1
mov DWORD PTR es:[0],PT0_AD OR (USU+RWW+PL)
mov DWORD PTR es:[4],PT1_AD OR (USU+RWW+PL)
mov ax,PT0_Sel ;初始化頁表0
mov es,ax
xor di,di
mov cx,1024
xor eax,eax
or eax,USU+RWW+PL
Demo1: stosd
add eax,1000h ;先全部置成對應等地址的
loop Demo1 ;物理頁,再特別設置兩廣表項
mov di,(PhVB_AD SHR 12)*4
mov DWORD PTR es:[di],MPVB_AD+USS+RWW+PL
mov di,(LoVB_AD SHR 12)*4
mov DWORD PTR es:[di],PhVB_AD+USU+RWR+PL
mov ax,PT1_Sel ;初始化頁表1
mov es,ax
xor di,di
mov cx,1024
mov eax,400000h
Demo2: stosd ;先把全部表項設置為無效
add eax,1000h
loop Demo2 ;再特別設置1項
mov di,((LoSC_AD SHR 12)AND 3ffh)*4
mov DWORD PTR es:[di],PhSC_AD+USU+RWR+PL
mov eax,PDT_AD
mov cr3,eax
mov eax,cr0
or eax,80000000h
mov cr0,eax
jmp SHORT PageE
PageE: mov ax,DemoData_Sel
mov ds,ax
mov si,OFFSET Mess
JUMP16 LoCode_Sel,SBegin
Demo3: mov eax,cr0
and eax,7fffffffh ;關閉分頁機制
mov cr0,eax
jmp SHORT PageD
PageD: mov ax,Normal_Sel
JUMP16 TempCode_Sel,ToDOS
DemoBegin ENDP
;----------------------------------------------------------------------------
DemoCodeLen = $
DemoCodeSeg ENDS
;============================================================================
TempCodeSeg SEGMENT PARA USE16 ;臨時任務的代碼段
ASSUME CS:TempCodeSeg
;----------------------------------------------------------------------------
Virtual PROC FAR
cld ;為演示在啟用分頁機制后執
mov ax,SCode_Sel ;行位于較高線性地址空間中
mov ds,ax ;的代碼作準備
mov ax,TPSCode_Sel
mov es,ax
mov si,OFFSET SBegin
mov di,si
mov cx,MLen ;把分頁演示代碼復制到預定
rep movsb ;內存
JUMP16 DemoCode_Sel,DemoBegin
ToDOS: mov ds,ax
mov es,ax
mov eax,cr0 ;準備返回實模式
and al,11111110b
mov cr0,eax
JUMP16 <SEG Real>,<OFFSET Real>
Virtual ENDP
;----------------------------------------------------------------------------
TempCodeSeg ENDS
;============================================================================
RCodeSeg SEGMENT PARA USE16 ;實方式的初始化代碼和數據
ASSUME CS:RCodeSeg,DS:RCodeSeg
;----------------------------------------------------------------------------
VGDTR PDesc <GDTLen-1,>
;----------------------------------------------------------------------------
Start PROC
push cs
pop ds
cld
call InitGDT ;初始化全局描述符表GDT
EnableA20
lgdt QWORD PTR VGDTR ;裝載GDTR
cli ;關中斷
mov eax,cr0
or al,1
mov cr0,eax
JUMP16 <TempCode_Sel>,<OFFSET Virtual>
Real: DisableA20
sti
mov ax,4c00h
int 21h
Start ENDP
;----------------------------------------------------------------------------
InitGDT PROC
push ds
mov ax,GDTSeg
mov ds,ax
mov cx,GDNum
mov si,OFFSET EFFGDT
InitG: mov ax,[si].BaseL
movzx eax,ax
shl eax,4
shld edx,eax,16
mov WORD PTR [si].BaseL,ax
mov BYTE PTR [si].BaseM,dl
mov BYTE PTR [si].BaseH,dh
add si,SIZE Desc
loop InitG
pop ds
mov bx,16
mov ax,GDTSeg
mul bx
mov WORD PTR VGDTR.Base,ax
mov WORD PTR VGDTR.Base+2,dx
ret
InitGDT ENDP
;----------------------------------------------------------------------------
RCodeSeg ENDS
END Start
2.關于實例十的說明
上述演示程序的許多內容與其它實例相同,下面僅就演示分頁管理機制方面的內容作些說明:
(1)部分演示代碼的移動
為了充分說明分頁機制所實現的線性地址到物理地址的轉換,在初始化時把部分演示代碼移動到預定的內存區域。預定的內存區域從00303000H開始,即頁碼為00303H的物理頁。該部分演示代碼的功能是顯示指定的字符串。在進入保護模式后做此初始化工作的原因是預定的內存區域在擴展內存中,注意初始化時還沒有啟用分頁機制。
(2)頁映射表的初始化
頁目錄表安排在頁碼為00200H的物理頁中,頁表0安排在頁碼為00202H的物理頁中,頁表1安排在頁碼為00201H的物理頁中。演示程序涉及的線性地址空間不超過007FFFFFH,所以只使用兩張頁表,為此頁目錄表中的其它項被置為無效(P=0)。
頁表0把線性地址空間中的00000000H—003FFFFFH映射到物理地址空間中。實例在初始化頁表0時,使該線性地址空間直接映射到相同地址的物理地址空間,除線性地址空間中頁碼為000B8H和000F0H這兩頁以外。000B8H頁被映射到頁碼為00301H的物理頁,而000F0H頁被映射到頁碼為000B8H的物理頁。
頁表1把線性地址空間中的00400000H—007FFFFFH映射到物理地址空間中。實例在初始化頁表1時,似乎使該線性地址空間直接映射到相同地址的物理地址空間,但是處理對應線性地址空間中00402H的表項被另外設置外,其它表項中的P位為0,也即表示對應物理頁不存在。初始化后,頁表1的第2項把線性地址空間中的00402H頁映射到頁碼為00303H的物理頁,也就是存放部分演示代碼的指定內存區域。
(3)啟動分頁管理機制
在建立好頁映射表后,啟用分頁機制所要做的操作是簡單的,只要把控制寄存器CR0中的最高位,也就是PG位置1。具體指令如下:
mov eax,cr0
or eax,80000000h
mov cr0,eax
jmp SHORT PageE
PageE: ...
在啟用分頁機制前,線性地址就是物理地址;在啟用分頁機制后,線性地址要通過分頁機制的轉換,才成為物理地址。盡管使用一條轉移指令,可清除預取隊列,但隨后在取指令時使用的線性地址就要經過分頁機制轉換才成為物理地址。為了順利過渡,在啟用分頁機制之后的過渡代碼段,仍要維持線性地址等同于物理地址。為了作到這一點,在建立也映射表時,必須使實現過渡的代碼所在的線性地址空間頁映射到具有相同地址的物理地址空間頁。實例中頁表0就做到了這一點。
(4)關閉分頁管理機制
只要把控制寄存器CR0中的PG位清0,便關閉了分頁機制。在這一過渡階段,也要保持地址轉換前后的一致。
(5)地址轉換的演示
在啟用分頁機制之后,就轉移到位于線性地址空間中00402000H處開始的代碼,該部分代碼的功能是顯示提示信息"Page is OK!"。實際上這部分代碼存放在從物理地址00303000H開始的物理內存區域中,是在初始化時被移到此區域的。
在顯示提示信息時,要把顯示的ASCII字符和顯示屬性填到線性地址空間中000F0000H開始的區域中,而不是000B8000H開始的區域。從初始化時建立的映射表可見,線性地址空間中的000F0H頁,被映射到物理地址空間中的000B8H頁。所以,向線性地址空間中的000F0H頁寫,實際上是向物理地址空間中的000B8H頁寫,也就是真正顯示。
(6)頁級保護的說明
在進入保護模式之后,特權級一直是0,所以,無論系統級和用戶級頁,無論只能讀/執行,還是讀/執行/寫,總是可進行各種形式的訪問。