分頁機制是 80x86 內(nèi)存管理機制的第二種機制,分段機制用于把虛擬地址轉(zhuǎn)換為線性地址,而分頁機制用于把線性地址轉(zhuǎn)換為物理地址。分頁機制可以用于任何一種分段機制,也可以理解為先有分段機制才有分頁機制,這是由于歷史原因,分段機制要比分頁機制更輕,先出現(xiàn)的分段后出現(xiàn)的分頁。
處理器的分頁機制用于把線性地址劃分成一個個的頁面,這些劃分成頁面的線性地址會被映射到物理空間的頁面上。
我們知道分段的保護措施有兩種,一種是利用任務(wù)之間的保護;一種是利用內(nèi)存段和寄存器之間的保護。
分頁機制有幾種頁面級的保護措施,分段機制和保護措施可以和分頁機制的保護措施一起使用,也可以使用分頁機制的保護措施替換分段機制的保護。
比如分頁機制可以在頁面的基礎(chǔ)上加強讀/寫保護。另外,在頁面單元上,分頁機制還提供了用戶和超級用戶兩級保護。
分頁機制可以通過 CR0 控制寄存器的 PG 這個標志位來判斷是否開啟分頁機制;如果 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)存中。當頁面加載到物理內(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 相當于是內(nèi)存的一個副本。
頁表結(jié)構(gòu)
頁表中每個頁表項的大小為 32 位,其中 20 位來存放物理基地址,剩余的 12 位存放可用于存放頁面是否存在等屬性信息。如果線性地址索引的頁表項被標注為存在,則表示該項有效,我們可以從中取得物理地址;如果線性地址索引的頁表項不存在,那么訪問物理頁面就會產(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)標志,用于指明表項對地址轉(zhuǎn)換是否有效。P = 1 表示有效,P = 0 表示無效,在頁的轉(zhuǎn)換過程中,如果說涉及的頁目錄或頁表的表項無效,也就是頁面沒有再物理地址中,就會產(chǎn)生一個異常。如果 P = 0 ,那么除了表項無效外,其余的 bit 位可以自由使用。R/W -- 位 1 是讀/寫(Read/Write)標志,當 R/W = 1 時,表示該頁可以被讀、寫和執(zhí)行;當 R/W = 0 時,表示該頁只讀或可執(zhí)行;當處理器運行在超級用戶權(quán)限下(0、1、2)時,此位不會發(fā)生作用。U/S -- 位 2 是用戶/超級用戶(User/Supervisor)標識,如果此位為 0 ,表示任意特權(quán)級下面的應(yīng)用程序都可以訪問,如果此位為 1 ,那么頁面只能允許在特權(quán)級為 0、1、2 也就是超級用戶特權(quán)級下才能訪問。A -- 位 5 是已訪問(Accessed)標志,此位僅用于統(tǒng)計頁面的訪問情況,如果頁面已經(jīng)訪問過,就會置 1,但是操作系統(tǒng)會通過定期復(fù)位來重置此標識位。D -- 位 6 是頁面已修改(Dirty)標志,也就是我們常說的"臟位",當處理器對頁面執(zhí)行寫操作時,就會設(shè)置對應(yīng)頁面的 D 標志。AVL -- 保留字段,這個字段專門提供給程序使用。
根據(jù)上面字段的描述,可以看到頁目錄和頁表項中的 P 位為分頁技術(shù)的虛擬存儲提供了必要的標識,若線性地址空間中的頁面存在于物理內(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 這兩個標志位是實現(xiàn)虛擬存儲的基礎(chǔ),這兩個標志位可以定期檢測指定的頁面是否訪問過并且是否可以讀寫,從而判斷哪些頁面可以移出到磁盤。比如一個頁面從磁盤讀入內(nèi)存后,它的 D 標志位為 0 ,那么當頁被移除磁盤時,它的 D 位還是 0 的話,就可以判斷這個頁面無需調(diào)入磁盤。D = 1 表示頁面已經(jīng)被修改過,就需要將其寫回到磁盤上。