分頁機制是 80x86 內(nèi)存管理機制的第二種機制,分段機制用于把虛擬地址轉(zhuǎn)換為線性地址,而分頁機制用于把線性地址轉(zhuǎn)換為物理地址。分頁機制可以用于任何一種分段機制,也可以理解為先有分段機制才有分頁機制,這是由于歷史原因,分段機制要比分頁機制更輕,先出現(xiàn)的分段后出現(xiàn)的分頁。
處理器的分頁機制用于把線性地址劃分成一個個的頁面,這些劃分成頁面的線性地址會被映射到物理空間的頁面上。
我們知道分段的保護措施有兩種,一種是利用任務(wù)之間的保護;一種是利用內(nèi)存段和寄存器之間的保護。
分頁機制有幾種頁面級的保護措施,分段機制和保護措施可以和分頁機制的保護措施一起使用,也可以使用分頁機制的保護措施替換分段機制的保護。
比如分頁機制可以在頁面的基礎(chǔ)上加強讀/寫保護。另外,在頁面單元上,分頁機制還提供了用戶和超級用戶兩級保護。
分頁機制可以通過 CR0 控制寄存器的 PG 這個標(biāo)志位來判斷是否開啟分頁機制;如果 PG = 1 ,則表示啟用分頁操作,處理器會使用本節(jié)描述的機制將線性地址轉(zhuǎn)換為物理地址。如果 PG = 0,則表示禁用分頁機制,此時分段產(chǎn)生的線性地址會被直接用作物理地址。
分段機制和分頁機制還有一個區(qū)別就是:分段機制可以在任意可變長度的內(nèi)存上進行操作,而分頁機制只能對固定大小的頁面(內(nèi)存塊)進行操作。分頁機制把線性和物理地址空間都劃分成頁面。線性地址空間中的頁面都可以映射在物理地址空間內(nèi),如下圖所示。
80x86 使用 4K (2 ^ 12) 字節(jié)固定大小的頁面,每個頁面均是 4KB,并且對齊于 4KB 地址邊界處。這表示分頁機制會把 4GB 劃分成為以 4KB 為基礎(chǔ)的頁面,共劃分 1M(1048576) 個,線性地址的低 12 bit 位可以直接作為頁內(nèi)偏移量,也可直接作為物理地址的低 12 位。
現(xiàn)在我們知道線性地址空間會經(jīng)過分頁機制映射到物理內(nèi)存空間上,這是一個正常能夠映射到的情況,如果映射不到怎么辦?也就是說包含線性地址空間的頁面不在物理內(nèi)存中怎么辦?此時處理器就會產(chǎn)生一個頁錯誤異常。頁錯誤異常的處理程序會讓操作系統(tǒng)從磁盤中把相應(yīng)的頁面加載到物理內(nèi)存中。當(dāng)頁面加載到物理內(nèi)存中后,會從異常處理程序中返回,使得處于異常指令的位置繼續(xù)向下執(zhí)行指令。
頁錯誤異常是分頁機制實現(xiàn)換入換出過程中出現(xiàn)頻次非常高的一種異常機制,它就好像 bug 一樣如影隨形,而且頻繁的頁面換入換出操作會很耗費處理器資源,所以為了減少頻繁換入換出的操作,采用了一種局部性原理的方式:把經(jīng)常訪問的頁目錄和相關(guān)頁 "保存" 起來,這里采用了一種硬件實現(xiàn),即轉(zhuǎn)換查找緩沖區(qū)(Translation Lookaside Buffer)。有了 TLB,處理器會先從 TLB 中查找相關(guān)頁,TLB 中不存在的頁才會從內(nèi)存中進行讀取,此時的 TLB 相當(dāng)于是內(nèi)存的一個副本。
頁表結(jié)構(gòu)
頁表中每個頁表項的大小為 32 位,其中 20 位來存放物理基地址,剩余的 12 位存放可用于存放頁面是否存在等屬性信息。如果線性地址索引的頁表項被標(biāo)注為存在,則表示該項有效,我們可以從中取得物理地址;如果線性地址索引的頁表項不存在,那么訪問物理頁面就會產(chǎn)生異常。
下面是一個線性地址到物理地址的變換過程圖。
可以看到,80x86 使用了兩級頁,這是為了減少頁的數(shù)量所設(shè)計的,因為雖然每個頁字節(jié)是 4K,共有 2 ^ 20 (1MB)個頁,總共占據(jù) 4MB 大小,但實際上應(yīng)用程序一次用不到這么多頁,會造成資源浪費,所以采用了一種分層的設(shè)計方式。
第一級稱為頁目錄(page directory),它被存放在 1 個 4K 頁面中,因為一共有 2 ^ 10 次方(1 MB)個頁目錄,每個目錄是 4 字節(jié),所以是在一個 4K 頁面中。線性地址的最高十位(22 - 31 位)用作一級表(頁目錄)中的索引來訪問二級表。
第二級稱為頁表(page table),它和頁目錄一樣,也是占據(jù)一個頁面,最多含有 1K 個 4 字節(jié)的頁表。頁表項會存儲 20 位的物理地址,線性地址中的 12 - 21 位作為頁表的索引,用于獲取含有 20 位物理地址的頁表項。頁表項的 20 位物理基地址和線性地址中的低 12 位一起合成最終的 32 位物理地址。
頁表項結(jié)構(gòu)
現(xiàn)在我們知道線性地址的低 12 位和頁表存儲的 20 位可以合成物理地址,頁表項除了能夠存儲地址外,還有一些其他的屬性,下面是頁表項的結(jié)構(gòu)圖。
這里需要特別注意的是,頁目錄的結(jié)構(gòu)和頁表的結(jié)構(gòu)是一樣的,只不過他倆描述的主體不一樣,一個描述的是頁目錄,一個描述的是頁表。
- P -- 位 0 是存在(Present)標(biāo)志,用于指明表項對地址轉(zhuǎn)換是否有效。P = 1 表示有效,P = 0 表示無效,在頁的轉(zhuǎn)換過程中,如果說涉及的頁目錄或頁表的表項無效,也就是頁面沒有再物理地址中,就會產(chǎn)生一個異常。如果 P = 0 ,那么除了表項無效外,其余的 bit 位可以自由使用。R/W -- 位 1 是讀/寫(Read/Write)標(biāo)志,當(dāng) R/W = 1 時,表示該頁可以被讀、寫和執(zhí)行;當(dāng) R/W = 0 時,表示該頁只讀或可執(zhí)行;當(dāng)處理器運行在超級用戶權(quán)限下(0、1、2)時,此位不會發(fā)生作用。U/S -- 位 2 是用戶/超級用戶(User/Supervisor)標(biāo)識,如果此位為 0 ,表示任意特權(quán)級下面的應(yīng)用程序都可以訪問,如果此位為 1 ,那么頁面只能允許在特權(quán)級為 0、1、2 也就是超級用戶特權(quán)級下才能訪問。A -- 位 5 是已訪問(Accessed)標(biāo)志,此位僅用于統(tǒng)計頁面的訪問情況,如果頁面已經(jīng)訪問過,就會置 1,但是操作系統(tǒng)會通過定期復(fù)位來重置此標(biāo)識位。D -- 位 6 是頁面已修改(Dirty)標(biāo)志,也就是我們常說的"臟位",當(dāng)處理器對頁面執(zhí)行寫操作時,就會設(shè)置對應(yīng)頁面的 D 標(biāo)志。AVL -- 保留字段,這個字段專門提供給程序使用。
根據(jù)上面字段的描述,可以看到頁目錄和頁表項中的 P 位為分頁技術(shù)的虛擬存儲提供了必要的標(biāo)識,若線性地址空間中的頁面存在于物理內(nèi)存中,那么對應(yīng)的表項 P = 1,并且該表項中含有相應(yīng)的物理地址。頁面不在物理內(nèi)存中的表項 P = 0 。如果程序訪問物理內(nèi)存中不存在的頁面,處理器就會產(chǎn)生一個缺頁異常。此時操作系統(tǒng)就會利用這個異常把缺少的頁面從磁盤調(diào)入內(nèi)存,把相應(yīng)的物理地址放在表項中,返回程序繼續(xù)執(zhí)行引起異常的指令并且設(shè)置 P = 1。
A 和 D 這兩個標(biāo)志位是實現(xiàn)虛擬存儲的基礎(chǔ),這兩個標(biāo)志位可以定期檢測指定的頁面是否訪問過并且是否可以讀寫,從而判斷哪些頁面可以移出到磁盤。比如一個頁面從磁盤讀入內(nèi)存后,它的 D 標(biāo)志位為 0 ,那么當(dāng)頁被移除磁盤時,它的 D 位還是 0 的話,就可以判斷這個頁面無需調(diào)入磁盤。D = 1 表示頁面已經(jīng)被修改過,就需要將其寫回到磁盤上。