一文看懂影子頁(yè)表和擴(kuò)展頁(yè)表
我是cloud3,前段時(shí)間有虛擬機(jī)出現(xiàn)內(nèi)存問(wèn)題,今天借著這個(gè)話題給大家介紹一下內(nèi)存虛擬化,也就是MMU虛擬化。
我們知道從intel的80386引入了保護(hù)模式后,內(nèi)存空間分為虛擬地址空間和物理地址空間。后引入頁(yè)表機(jī)制,把虛擬地址送往MMU,MMU查T(mén)LB不中的情況下,依次查頁(yè)表就可以找到對(duì)應(yīng)的物理地址。
(關(guān)于MMU的原理可以先看我的文章-圖解MMU)
在引入虛擬化技術(shù)后,內(nèi)存地址空間就變得復(fù)雜了,客戶機(jī)(Guest)和宿主機(jī)(Host)都有自己的地址空間。GuestOS本身有虛擬地址和物理地址。HostOS也有虛擬機(jī)地址和物理地址。那虛擬機(jī)如何訪問(wèn)到物理機(jī)上的物理地址呢?這就是今天我們要討論的內(nèi)存虛擬化技術(shù)。
首先標(biāo)記幾個(gè)概念:
- HPA:Host Physical Address
- HVA:Host Virtual Address
- GPA:Guest Physical Address
- GVA:Guest Virtual Address
- PDBR:頁(yè)目錄表物理基地址寄存器,X86上叫CR3
- EPT:擴(kuò)展頁(yè)表
ptr:這里用來(lái)描述指向某個(gè)頁(yè)表的寄存器
一.內(nèi)存虛擬化要解決的問(wèn)題
內(nèi)存虛擬化實(shí)際實(shí)現(xiàn)就是MMU虛擬化,要實(shí)現(xiàn)GVA -> GPA -> HVA -> HPA,而傳統(tǒng)MMU只能實(shí)現(xiàn)VA->PA的轉(zhuǎn)換。所以在虛擬化場(chǎng)景下要解決虛擬機(jī)里面的進(jìn)程如何訪問(wèn)物理機(jī)上的內(nèi)存這一問(wèn)題,也就是GVA->HPA的映射問(wèn)題。
在硬件輔助內(nèi)存虛擬化出現(xiàn)之前,這個(gè)過(guò)程是通過(guò)軟件實(shí)現(xiàn)的,即通過(guò)VMM來(lái)實(shí)現(xiàn)的。最典型的實(shí)現(xiàn)方式就是影子頁(yè)表技術(shù)。
二.影子頁(yè)表
(Shadow page table)
影子頁(yè)表我用一句話來(lái)描述就是:VMM把Guest和Host中的頁(yè)表合并成一個(gè)頁(yè)表,稱為影子頁(yè)表,來(lái)實(shí)現(xiàn)GVA->HPA映射。
變?yōu)椋?/p>
影子頁(yè)表需要實(shí)現(xiàn) GVA -> HPA的轉(zhuǎn)換。如何實(shí)現(xiàn)呢?有下面幾步:
1,GVA->GPA,VMM層的軟件會(huì)將guest Page Table本身使用的物理頁(yè)面設(shè)為write protected的,Guest在進(jìn)行GVA->GPA 時(shí),由于是只讀的,導(dǎo)致 VM exit, traps to VMM。(關(guān)于VM exit的過(guò)程我們?cè)贑PU虛擬化時(shí)再詳解)。
2, GPA -> HVA,這一過(guò)程由VMM軟件實(shí)現(xiàn)的,這個(gè)很容易理解,就是通用的malloc。
3, HVA->HPA,這一過(guò)程就是我們已知的使用物理MMU完成VMM進(jìn)程的虛擬內(nèi)存到物理內(nèi)存的轉(zhuǎn)換。
4, 把GVA -> HPA,這一路的映射關(guān)系記錄到頁(yè)表中,這個(gè)頁(yè)表就是影子頁(yè)表。
虛擬機(jī)頁(yè)表和影子頁(yè)表通過(guò)一個(gè)哈希表建立關(guān)聯(lián)(當(dāng)然也有其他的關(guān)聯(lián)方式),客戶機(jī)操作系統(tǒng)把當(dāng)前進(jìn)程的頁(yè)表基址載入PDBR時(shí)而VMM將會(huì)截獲這一特權(quán)指令,將進(jìn)程的影子頁(yè)表基址載入客戶機(jī)PDBR,使客戶機(jī)在恢復(fù)運(yùn)行時(shí)PDBR實(shí)際指向的是進(jìn)程對(duì)應(yīng)的影子頁(yè)表。這樣通過(guò)影子頁(yè)表就可以實(shí)現(xiàn)真正的內(nèi)存訪問(wèn)。
影子頁(yè)表實(shí)現(xiàn)非常復(fù)雜,需要為每個(gè)Guest中的每個(gè)進(jìn)程的Guest PT都維護(hù)一個(gè)對(duì)應(yīng)的Shadow PT。page fault和vm-exit的數(shù)量,也加重了CPU的負(fù)擔(dān)。為了提高效率,各個(gè)CPU廠家推出了硬件輔助MMU虛擬化的技術(shù)。
三.擴(kuò)展頁(yè)表技術(shù)/EPT
嵌套頁(yè)表技術(shù)/NPT
從Intel的Nehalem架構(gòu)開(kāi)始,EPT(Extended Page Tables)就作為CPU的一個(gè)特性加入到CPU硬件中去了。AMD也提供的類(lèi)似技術(shù)叫做NPT,即Nested Page Tables。
硬件層面引入EPTP寄存器,來(lái)指向EPT頁(yè)表基地址。Guest運(yùn)行時(shí),Guest頁(yè)表被載入PDBR,而 EPT 頁(yè)表被載入專(zhuān)門(mén)的EPT 頁(yè)表指針寄存器 EPTP。
GVA->GPA的轉(zhuǎn)換依然是通過(guò)查找原來(lái)頁(yè)表完成,而GPA->HPA的轉(zhuǎn)換則通過(guò)查找EPT來(lái)實(shí)現(xiàn),每個(gè)guest VM有一個(gè)由VMM維護(hù)的EPT。
具體過(guò)程
當(dāng)Guest中進(jìn)程訪問(wèn)GVA時(shí),CPU首先就要通過(guò)PDBR寄存器去找頁(yè)目錄,但是PDBR中存儲(chǔ)的地址是GPA,所以要到EPT中進(jìn)行GPA->HPA的轉(zhuǎn)換,這個(gè)轉(zhuǎn)換過(guò)程和物理MMU的工作流程相同。
找到了頁(yè)目錄的HPA基地址,再通過(guò)GVA中的Directory offset段,就找到頁(yè)表的VGA了,這個(gè)頁(yè)表VGA再去EPT中進(jìn)行GPA->HPA的轉(zhuǎn)換,就找到頁(yè)表VGA的HPA了。
重復(fù)上述過(guò)程,依次查找各級(jí)頁(yè)表,最終獲得該GVA對(duì)應(yīng)的HPA。如果是三級(jí)或者四級(jí)頁(yè)表,也是同樣的原理。
page fault處理
上面的查表過(guò)程是最理想的處處命中情況,那如果有page fault的情況如何處理呢?
如果Guest的頁(yè)表中沒(méi)有命中可直接由guest OS處理,不會(huì)產(chǎn)生vm-exit。如果在EPT中沒(méi)有命中,則產(chǎn)生EPT violation異常,這是Host中VMM層的page fault,不需要vm exit,只需要按照Host中的page fault處理就可以了。所以說(shuō)EPT/NPT MMU解耦了GVA->GPA轉(zhuǎn)換和GPA->HPA轉(zhuǎn)換之間的依賴關(guān)系。并且一個(gè)VM只需要一套EPT頁(yè)表,減少了內(nèi)存開(kāi)銷(xiāo),維護(hù)也比較簡(jiǎn)單。
四.看圖總結(jié)
最后我們直觀的看看引入虛擬化之后MMU的變化情況:
沒(méi)有虛擬化:
影子頁(yè)表:
EPT/NPT:
通過(guò)上面的對(duì)比圖,我們應(yīng)該能清楚的看到MMU虛擬化的整個(gè)設(shè)計(jì)思路。