KVM原理與架構系列之四 記憶體虛擬化篇
記憶體虛擬化
1. 客戶機實體地址空間
在物理機上,虛擬地址通過Guest頁表即可轉換為實體地址。但是在虛擬化環境中,由於VMM和VM都需要獨立的地址空間,則產生了衝突。
為實現記憶體虛擬化,讓客戶機使用一個隔離的、從零開始且具有連續的記憶體空間,KVM 引入一層新的地址空間,即客戶機實體地址空間 (Guest Physical Address, GPA),該地址空間並不是真正的實體地址空間,它只是宿主機(Host主機)虛擬地址空間在Guest地址空間的一個對映。
對Guest來說,客戶機實體地址空間都是從零開始的連續地址空間,但對於宿主機來說,客戶機的實體地址空間並不一定是連續的,客戶機實體地址空間有可能對映在若干個不連續的宿主機地址區間,如下圖所示:
由於物理MMU只能通過Host機的實體地址(Host Physical Address, HPA)進行定址,所以實現記憶體虛擬化,關鍵是需要將Guest機的虛擬地址(Guest Virtual Address, GVA)轉換為HPA。傳統的實現方案中,這個過程需要經歷:GVAàGPAàHVAàHPA的轉換過程,需要對地址進行多次轉換,而且需要KVM的介入,效率非常低。為提供GVA到HPA的地址轉換效率,KVM提供了兩種地址轉換方式:
1、影子頁表(Shadow Page Table),是純軟體的實現方式
2、基於硬體特性的地址轉換。如基於Intel
EPT(Extended Page Table ,擴充套件頁表),或AMD
NPT(Nested Page Table,巢狀頁表)
2. 影子頁表
2.1 基本原理
由於記憶體虛擬化在將GVA轉換為HPA的過程中,需要經歷多次轉換,無法直接使用Guest機頁表和CR3。使用影子頁表(Shadow
Page Table)可以實現客戶機虛擬地址(GVA)到宿主機實體地址(HPA)的直接轉換,與傳統方式的轉換過程對比如下:
影子頁表中記錄的是GVA跟HPA的對應關係,每個頁表項指向的都是宿主機的實體地址。由於客戶機中每個程序都有自己的虛擬地址空間,所以 KVM 需要為客戶機中的每個程序頁表都要維護一套相應的影子頁表。
在Guest機訪問記憶體時,VMM在物理MMU中載入的是Guest機當前頁表所對應的影子頁表,從而實現GVA到HPA的直接轉換。
Guest機中的每一個頁表項都有一個影子頁表項與之相對應。為了快速檢索Guest機頁表所對應的的影子頁表,KVM 為每個客戶機都維護了一個雜湊表,影子頁表和Guest機頁表通過此雜湊表進行對映,基本原理如下:
對於每一個Guest機來說,Guest機的頁目錄/頁表都有唯一的GPA,通過頁目錄/頁表的GPA就可以在雜湊連結串列中快速地找到對應的影子頁目錄/頁表。在檢索雜湊表時,KVM 把Guest頁目錄/頁表的客戶機實體地址低10位作為鍵值進行索引,根據其鍵值定位到對應的連結串列,然後遍歷此連結串列找到對應的影子頁目錄/頁表。當然,如果沒有找到對應的影子頁目錄/頁表,則說明影子頁表項和Guest頁表項的對應關係還沒有建立 ,此時KVM 會為其分配新的物理頁,並建立起Guest頁目錄/頁表和對應的影子頁目錄/頁表之間的對映。
2.2 影子頁表的建立與更新
影子頁表的建立和更新過程交織在一起,影子頁表的建立和更新主要發生在如下3中情況下:
1.Guest OS修改Guest CR3暫存器。由於相關指令為敏感指令,所以相關操作會被VMM截獲,此時VMM會根據相關情況進行影子頁表的維護。比如,當客戶機切換程序時,客戶機作業系統會把待切換程序的頁表基址載入 CR3,而該特權指令將被VMM截獲,進行新的處理,即在雜湊表中找到與此頁表基址對應的影子頁表基址,載入客戶機 CR3,使客戶機在恢復執行時 CR3 實際指向的是新切換程序對應的影子頁表。
2.因Guest機頁表和影子頁表不一致而觸發的缺頁異常,此時也會VM-Exit到VMM,進而可進行相關維護操作。
3.Guest OS中執行INVLPG指令重新整理TLB時,由於INVLPG指令為敏感指令,所以該操作也會被VMM進行截獲,並進行影子頁表相關維護操作。
其中,第2中情況發生機率最高,相關處理也最複雜。如下做重點描述。不同的缺頁異常,處理方式不用,常見的缺頁異常包括如下3類:
1.影子頁表初始化時產生的缺頁異常。在虛擬機器執行之初,VMM中與Guest機頁表對應的影子頁表都沒有建立,而物理CR3中載入的卻是影子頁目錄地址,所以,此時任何的記憶體操作都會引發異常,如果此時Guest機的相應頁表已經建立,那麼處理這種異常即是建立相應的影子頁表即可;如果Guest機的頁表項尚未建立,那就是Guest機自身的缺頁異常,即為如下的第2中情況。
2.Guest機上的缺頁異常。如果Guest OS尚未給這個GVA分配Guest機物理頁,即相應的Guest機頁表項尚未建立,此時將引發缺頁異常。另外,當Guest機訪問的Guest頁表項存在位(Present Bit)為0,或相關訪問許可權不匹配時,也將引發缺頁異常。
3.VMM將Host機物理頁換出到硬碟上時引發的缺頁異常。
影子頁表缺頁異常的預設處理流程:
VMM截獲缺頁異常(VM-Exit),並檢查此異常是否由Guest即自身引發,如果是,則將直接返回Guest OS(Vm-Entry),然後由Guest OS自身的page fault流程處理;如果不是,則為影子頁表和Guest機頁表不一致導致,這樣的異常也叫“影子缺頁異常”,此時,VMM會根據Guest機頁表同步影子頁表,過程如下:
1.VMM根據Guest機頁表項建立影子頁目錄和頁表結構
2. VMM根據發生缺頁異常的GVA,在Guest機頁表的相應表項中得到對應的GPA
3.VMM根據GPA,在GPA與HPA的對映表中(通過之前描述的HASH表建立),得到相應的HPA,再將HPA填入到影子頁表的相應表項中。
影子頁表和Guest機頁表不是時刻同步的,只有在需要時才進行通過,從某種角度看,影子頁表可以看做是Guest頁表的TLB,常稱為虛擬TLB(VTLB)。
影子頁表解決了傳統IA32架構下的記憶體虛擬化問題,由於影子頁表可被載入物理 MMU 為客戶機直接定址使用, 所以客戶機的大多數記憶體訪問都可以在沒有KVM 介入的情況下正常執行,沒有額外的地址轉換開銷,也就大大提高了客戶機執行的效率。但也有比較明顯的缺點:
1.實現複雜。影子頁表同步需要考慮各種情況。
2.記憶體開銷大。需要為每個Guest機程序維護一個影子頁表。
3. EPT 頁表
3.1 基本原理
為解決影子頁表的問題,Intel和AMD都提供了相應的硬體技術,直接在硬體上支援GPA到HPA的轉換,從而大大降低了記憶體虛擬化的難度,並提升了相關效能。本文主要描述Intel EPT技術。
EPT 技術在原有Guest機頁表對GVA到GPA轉換的基礎上,又引入了 EPT 頁表來實現GPA到HPA轉換,這兩次地址轉換都是由硬體自動完成,可高效的實現地址轉換。Guest執行時,Guest頁表被載入 CR3,而 EPT 頁表被載入專門的 EPT 頁表指標暫存器 EPTP。從GVA到HPA的具體轉換過程如下(以經典的2級頁表為例):
完整的地址翻譯流程描述為:
1. Guest OS載入Guest程序的gCR3,gCR3中存放的是Guest程序頁目錄表的GPA。
2. 處於非根模式的CPU的MMU查詢硬體EPT TLB,如果有所請求的GPA到HPA的對映,則使用其對應的HPA作為Guest頁目錄表的基址。
3. 如沒有所請求的GPA到HPA的對映,則查詢EPT,獲得gCR3所對映的HPA,並將其作為Guest頁目錄表的基址。
4. 根據GVA獲得頁目錄偏移(圖中的Dir Offset),獲得用於索引Guest頁表的基址,該地址為GPA。
5. 再由VCPU的MMU查詢硬體EPT TLB,如果有所請求的GPA到HPA的對映,則使用其對應的HPA作為Guest頁表的基址。
6. 如沒有所請求的GPA到HPA的對映,則查詢EPT,將其轉換為HPA,使用該HPA再加上GVA中的頁表偏移(圖中的Table Offset),即可得到PTE(頁表項)的GPA。
7. 再由VCPU的MMU查詢硬體EPT TLB,如果有所請求的GPA到HPA的對映,則其對應的HPA加上GVA中的Offset即為最終的宿主機實體地址(HPA)。
8. 如沒有所請求的GPA到HPA的對映,則查詢EPT,將其轉換為HPA,使用該HPA加上GVA中的Offset即為最終的宿主機實體地址(HPA)。
EPT頁表實現GPA到HPA的轉換的原理,與Guest頁表實現GVA到GPA的轉換原理相同,需要經歷多級頁表的查詢,圖中沒有詳細畫出。假設Guest機有m級頁表,宿主機EPT有n級,在TLB均miss的最壞情況下,會產生m*n次記憶體訪問,完成一次客戶機的地址翻譯,EPT硬體通過增大硬體EPT TLB來儘量減少記憶體訪問。
3.2 EPT缺頁異常處理
在GPA到HPA轉換的過程中,由於缺頁、寫許可權不足等原因也會導致客戶機退出,產生 EPT 異常。對於 EPT 缺頁異常,處理過程大致如下:
1.KVM 首先根據引起異常的GHA,對映到對應的HVA;
2. 然後為此虛擬地址分配新的物理頁;
3.最後 KVM 再更新 EPT 頁表,建立起引起異常的GPA到HPA的對映。
EPT 頁表相對於影子頁表,其實現方式大大簡化,主要地址轉換工作都由硬體自動完成,而且Guest內部的缺頁異常也不會導致VM-Exit,因此Guest執行效能更好,開銷更小。
本文非原創,尊重他人勞動成果,轉載自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=14528823&id=4203732