速懂X86虛擬化關鍵概念 - Intel EPT
內存虛擬化
現代多任務操作系統設計,一般進程之間使用不同的虛擬地址空間相互隔離, 在實現上:
- 操作系統負責維護進程頁表,映射虛擬地址到物理地址的關係;
- CPU的內存管理單元(MMU)負責執行地址轉換;
- CPU提供TLB(Translation lookaside buffer)緩存最近用到的轉換結果,加速轉換效率;
虛擬化技術引入後,內存地址空間更加複雜了,客戶機(Guest)和宿主機(Host)都有自己的地址空間:
- GVA: Guest虛擬地址
- GPA: Guest物理地址
- HVA: Host虛擬地址
- HPA: Host物理地址
顯而易見,Guest負責GVA和GPA之間的轉換;Host負責HVA和HPA之間的轉換;而GPA和HPA之間的轉換,就需要虛擬化層(Hypervisor)輔助了,這個過程一般被稱為內存虛擬化。
影子頁表
早期的X86 CPU硬體輔助虛擬化能力很不完善,所以Hypervisor需要通過軟體實現內存虛擬化。因此,Hypervisor為每個客戶機每套頁表額外再維護一套頁表,通常也稱為影子頁表。
同時, Hypervisor截獲客戶機裡面任何試圖修改客戶機頁表或者刷新TLB的操作,將GVA到GPA的的修改,轉變成GVA到GPA的修改。這些操作包括:
- 寫gCR3(Guest CR3)寄存器和原來一樣的內容,一般用作刷新TLB;
- 寫gCR3(Guest CR3)寄存器不同的物理地址,一般是發生了進程切換;
- 修改部分頁表,這時候必須調用INVLPG指令失效對應的TLB;
這樣,Guest中的頁表實際變成了虛擬頁表,Hypervisor截獲了Guest相關的修改操作並更新到影子頁表,而真正裝入物理MMU是影子頁表; Guest中GVA和GPA之間的轉換實際上變成了GVA與HPA的轉換,TLB中緩存的也是GVA和HPA的映射,Guest內存訪問沒有額外的地址轉換開銷。
當然,影子頁表也帶來了下面的主要缺點:
- Hypervisor 需要為每個客戶機的每個進程的頁表都要維護一套相應的影子頁表,這會帶來較大內存上的額外開銷;
- 客戶在讀寫CR3、執行INVLPG指令或客戶頁表不完整等情況下均會導致VM exit,這導致了內存虛擬化效率很低;
- 客戶機頁表和和影子頁表的同步也比較複雜;
Intel EPT技術
為了簡化內存虛擬化的實現,以及提升內存虛擬化的性能,Intel推出了EPT(Enhanced Page Table)技術,即在原有的頁表基礎上新增了EPT頁表實現另一次映射。這樣,GVA-GPA-HPA兩次地址轉換都由CPU硬體自動完成。