1. 概述 1.1. KVM簡(jiǎn)介 KVM是一個(gè)基于Linux內(nèi)核的虛擬機(jī),,它屬于完全虛擬化范疇,從Linux-2.6.20開始被包含在Linux內(nèi)核中,。KVM基于x86硬件虛擬化技術(shù),,它的運(yùn)行要求Intel VT-x或AMD SVM的支持。 一般認(rèn)為,,虛擬機(jī)監(jiān)控的實(shí)現(xiàn)模型有兩類:監(jiān)控模型(Hypervisor)和宿主機(jī)模型(Host-based),。由于監(jiān)控模型需要進(jìn)行處理器調(diào)度,,還需要實(shí)現(xiàn)各種驅(qū)動(dòng)程序,以支撐運(yùn)行其上的虛擬機(jī),,因此實(shí)現(xiàn)難度上一般要大于宿主機(jī)模型,。KVM的實(shí)現(xiàn)采用宿主機(jī)模型(Host-based),由于KVM是集成在Linux內(nèi)核中的,,因此可以自然地使用Linux內(nèi)核提供的內(nèi)存管理,、多處理器支持等功能,易于實(shí)現(xiàn),,而且還可以隨著Linux內(nèi)核的發(fā)展而發(fā)展,。另外,目前KVM的所有I/O虛擬化工作是借助Qemu完成的,,也顯著地降低了實(shí)現(xiàn)的工作量,。以上可以說是KVM的優(yōu)勢(shì)所在。 本文僅分析KVM中與Intel VT-x相關(guān)的實(shí)現(xiàn),,不考慮KVM中與AMD SVM相關(guān)的實(shí)現(xiàn),,因此有關(guān)術(shù)語的使用與Intel VT-x保持一致。
2. 處理器虛擬化 2.1. VT-x技術(shù) 我們知道處理器一般存在應(yīng)用編程接口和系統(tǒng)編程接口,。對(duì)于x86處理器來說,,應(yīng)用編程接口僅向應(yīng)用程序暴露了通用寄存器、RFLAGS,、RIP和一組非特權(quán)指令,,而系統(tǒng)編程接口向操作系統(tǒng)暴露了全部的ISA(Instruction Set Architecture)。傳統(tǒng)的進(jìn)程/線程模型也是對(duì)處理器的一種虛擬化,,但只是對(duì)處理器的應(yīng)用編程接口的虛擬化,,而所謂的系統(tǒng)虛擬化(system virtualization)是要實(shí)現(xiàn)處理器系統(tǒng)編程接口的虛擬化。從這個(gè)角度講,,系統(tǒng)虛擬化與進(jìn)程/線程模型相比并無本質(zhì)的區(qū)別,。 處理器虛擬化的本質(zhì)是分時(shí)共享。實(shí)現(xiàn)虛擬化需要兩個(gè)必要條件,,第一是能夠讀取和恢復(fù)處理器的當(dāng)前狀態(tài),,第二是有某種機(jī)制防止虛擬機(jī)對(duì)系統(tǒng)全局狀態(tài)進(jìn)行修改。 第一個(gè)必要條件沒有必要一定由硬件來實(shí)現(xiàn),,雖然硬件實(shí)現(xiàn)可能比軟件實(shí)現(xiàn)更為簡(jiǎn)單,。例如,x86處理器對(duì)多任務(wù),,也就是應(yīng)用編程接口虛擬化,,提供了硬件的支持,軟件通常只需要執(zhí)行一條指令,就可以實(shí)現(xiàn)任務(wù)切換,,處理器硬件負(fù)責(zé)保存當(dāng)前應(yīng)用編程接口的狀態(tài),,并為目標(biāo)任務(wù)恢復(fù)應(yīng)用編程接口的狀態(tài)。但操作系統(tǒng)并不一定要使用處理器提供的這種虛擬化機(jī)制,,完全可以使用軟件來完成應(yīng)用接口狀態(tài)的切換,。例如,Linux就沒有使用x86處理器提提供多任務(wù)機(jī)制,,完全依賴軟件實(shí)現(xiàn)任務(wù)切換,。 第二個(gè)必要條件一定要由硬件來實(shí)現(xiàn),通常處理器采用多模式操作(multi-mode operation)來確保這一點(diǎn),。在傳統(tǒng)x86處理器上,共有4種模式的操作,,也就是常說的4個(gè)特權(quán)級(jí),。虛擬機(jī)(這里指進(jìn)程/線程)通常運(yùn)行在特權(quán)級(jí)3上,而虛擬機(jī)監(jiān)控器(這里指操作系統(tǒng))運(yùn)行于特權(quán)級(jí)0上,,進(jìn)程/線程的所有訪問全局的操作,,如訪問共享的操作系統(tǒng)所在的地址空間,訪問I/O等等,,均會(huì)導(dǎo)致異常的發(fā)生,,被操作系統(tǒng)所截獲并處理,使操作系統(tǒng)有機(jī)會(huì)向進(jìn)程/線程提供一個(gè)虛擬的世界,。 系統(tǒng)虛擬化與進(jìn)程/線程模型相比并無本質(zhì)的區(qū)別,。x86處理器完全有機(jī)會(huì)以較小的代價(jià)提供對(duì)系統(tǒng)虛擬化的支持,但很可惜Intel沒有考慮那么長(zhǎng)遠(yuǎn),。x86的4個(gè)特權(quán)級(jí)對(duì)于實(shí)現(xiàn)系統(tǒng)虛擬化已經(jīng)足夠了,,但傳統(tǒng)的x86處理器上,許多特權(quán)指令要求必須在特權(quán)級(jí)0上執(zhí)行,,如LGDT,,因此通常操作系統(tǒng)都占用了特權(quán)級(jí)0,也就沒有特權(quán)級(jí)供虛擬機(jī)監(jiān)控器使用了,。為此,,許多基于傳統(tǒng)x86處理器的虛擬化軟件不得不采用ring deprivileging方法,讓操作系統(tǒng)運(yùn)行于特權(quán)級(jí)1,,而由虛擬機(jī)監(jiān)控器使用特權(quán)級(jí)0,。ring deprivileging方法帶來了許多問題,包括:ring aliasing,、address space compression,、nonfaulting accessing to privileged state、adverse impact on guest transitions、interrupt virtualization,、access to hidden state等問題,,通常將以上問題統(tǒng)稱為x86平臺(tái)的虛擬化漏洞。 ring aliasing問題是指,,采用ring deprivileging方法時(shí),,由于處理器的CPL保存在CS的低兩位,所以操作系統(tǒng)通過執(zhí)行PUSH CS指令和一條POP EAX指令可以很容易發(fā)現(xiàn)其目前不在特權(quán)級(jí)0上執(zhí)行,,這違背了虛擬化對(duì)操作系統(tǒng)透明的原則,。 address space compression問題是指,操作系統(tǒng)通常期望能夠訪問整個(gè)4GB線性地址空間,,但虛擬機(jī)監(jiān)控器可能也需要占用操作系統(tǒng)的一部分線性地址空間,,以便其能夠方便地訪問操作系統(tǒng)的地址空間。但如果操作系統(tǒng)是運(yùn)行于特權(quán)級(jí)1,,那么操作系統(tǒng)也同樣可以訪問虛擬機(jī)監(jiān)控器的存儲(chǔ)空間,,對(duì)虛擬機(jī)監(jiān)控器造成威脅。 nonfaulting accessing to privileged state問題是指,,Intel的特權(quán)級(jí)機(jī)制不能確保所有的訪問處理器狀態(tài)的指令在低特權(quán)級(jí)狀態(tài)下執(zhí)行時(shí)都產(chǎn)生故障(Fault),,這使得操作系統(tǒng)在訪問某些處理器狀態(tài)時(shí)虛擬機(jī)監(jiān)控器無法獲得控制,也就無法對(duì)這些指令進(jìn)行仿真,。例如,,IA-32的GDTR, LDTR, IDTR, TR包含了控制處理器狀態(tài)的指針,對(duì)這些寄存器的修改只能在特權(quán)級(jí)0進(jìn)行,,但IA-32允許在所有的特權(quán)級(jí)中讀取這些寄存器的值,。操作系統(tǒng)可以讀取這些寄存器的值,如果與真實(shí)的計(jì)算機(jī)上的值不同,,操作系統(tǒng)就可以認(rèn)為自己正運(yùn)行在虛擬機(jī)環(huán)境中,。 adverse impact on guest transitions問題是指,為加快系統(tǒng)調(diào)用的速度,,Intel引入了SYSENTER和SYSEXIT指令,,但SYSENTER指令總是將特權(quán)級(jí)切換到0,且從0以外的特權(quán)級(jí)執(zhí)行SYSEXIT指令將導(dǎo)致故障,。因此,,在采用ring deprivileging方法實(shí)現(xiàn)虛擬化時(shí),SYSENTER和SYSEXIT指令總是先陷入到虛擬機(jī)監(jiān)控器,,經(jīng)后者仿真后再交給操作系統(tǒng),,這使系統(tǒng)調(diào)用的速度減慢。 interrupt virtualization問題是指,,IA-32使用EFLAGS.IF位來控制中斷的屏蔽,,修改IF位需要在CPL<=IOPL的情況下進(jìn)行,,否則將產(chǎn)生故障。操作系統(tǒng)可能需要頻繁地修改IF位,,會(huì)頻繁地導(dǎo)致虛擬機(jī)監(jiān)控器的陷入,,影響系統(tǒng)性能。而且,,有些情況下,,虛擬機(jī)監(jiān)控器需要向虛擬機(jī)注入事件,但如果虛擬機(jī)正處于中斷屏蔽狀態(tài),,虛擬機(jī)監(jiān)控器就必須等待,,直到虛擬機(jī)打開中斷。虛擬機(jī)監(jiān)控器為了及時(shí)得知虛擬機(jī)已打開中斷,,也必須截獲操作系統(tǒng)對(duì)EFLAGS.IF位的修改,。 access to hidden state問題是指,IA-32處理器的某些狀態(tài),,例如段描述符高速緩存,,是無法通過指令訪問的。當(dāng)虛擬機(jī)切換時(shí),,IA-32沒有提供保存和恢復(fù)段描述符高速緩存的手段。也就是說,,上文所述的實(shí)現(xiàn)虛擬化的第一個(gè)必要條件,能夠讀取和恢復(fù)處理器的當(dāng)前狀態(tài),,并不完全具備,。 總之,雖然采用ring deprivileging方法可能實(shí)現(xiàn)系統(tǒng)虛擬化,,但具有很多缺陷,,且軟件上比較復(fù)雜。為此,,Intel提出了VT-x技術(shù)來解決系統(tǒng)虛擬化問題,,其主要思路是增加一個(gè)新的比0還高的特權(quán)級(jí),,通常稱之為特權(quán)級(jí)-1,,并在硬件上支持系統(tǒng)編程接口狀態(tài)的保存和恢復(fù),。 首先,VT-x提供了一套稱作VMX(Virtual Machine eXtension)的新的工作模式,工作在該模式下的處理器又具有兩類操作模式:VMX root operation和VMX non-root operation,。通常,,虛擬機(jī)監(jiān)控器運(yùn)行在VMX root operation模式下,,即所謂的特權(quán)級(jí)-1,,客戶操作系統(tǒng)運(yùn)行在VMX non-root operation模式下。VMX non-root operation模式仍保留4個(gè)特權(quán)級(jí),,對(duì)操作系統(tǒng)來說,,VMX non-root operation模式與傳統(tǒng)的x86處理器兼容,最大的差別在于當(dāng)虛擬機(jī)執(zhí)行一些訪問全局資源的指令時(shí)將導(dǎo)致虛擬機(jī)退出操作(VM exit),,從而使虛擬機(jī)監(jiān)控器獲得控制權(quán),,以便對(duì)訪問全局資源的指令進(jìn)行模擬。以后,,虛擬機(jī)監(jiān)控器可以通過虛擬機(jī)進(jìn)入操作(VM entry)使虛擬機(jī)重新獲得控制權(quán),。 其次,VT-x為系統(tǒng)編程接口狀態(tài)的切換提供硬件支持,。VT-x為每個(gè)虛擬機(jī)維護(hù)至少一個(gè)VMCS(Virtual Machine Control Structure)結(jié)構(gòu),,其中保存了虛擬機(jī)和虛擬機(jī)監(jiān)控器的系統(tǒng)編程接口狀態(tài)。當(dāng)執(zhí)行VM exit和VM entry操作時(shí),,VT-x自動(dòng)根據(jù)VMCS中的內(nèi)容完成虛擬機(jī)和虛擬機(jī)監(jiān)控器間的系統(tǒng)編程接口狀態(tài)切換,。為系統(tǒng)編程接口狀態(tài)的切換提供硬件支持是必要的,因?yàn)?/span>x86處理器的系統(tǒng)編程接口相比應(yīng)用編程接口要復(fù)雜的多,,且在不停的變化,,如較新的處理器可能增加一些MSR(Model Specific Register),這使得單獨(dú)依靠軟件來實(shí)現(xiàn)系統(tǒng)編程接口的保存和恢復(fù)工作變得十分復(fù)雜,。另外,,VT-x還提供了一組指令,使得虛擬機(jī)監(jiān)控器通過一條指令就可以完成虛擬機(jī)間的切換,。 VT-x解決了ring deprivileging方法的一系列問題,,從硬件上堵住了所謂的x86平臺(tái)的虛擬化漏洞。由于操作系統(tǒng)所在的VMX non-root operation模式仍具有4個(gè)特權(quán)級(jí),,使得ring aliasing問題不存在了,。同時(shí),由于SYSENTER和SYSEXIT指令所引起的adverse impact on guest transitions問題也不存在了,;由于VT-x在VM exit和VM entry時(shí)完成系統(tǒng)編程接口的切換,,也就是說虛擬機(jī)和虛擬機(jī)監(jiān)控器擁有各自的GDT,也就擁有了各自的地址空間,,解決了address space compression問題,。同時(shí),,虛擬機(jī)和虛擬機(jī)監(jiān)控器擁有各自的GDTR/IDTR等寄存器,在虛擬機(jī)中訪問這些寄存器無需陷入,,解決了nonfaulting accessing to privileged state問題,,再者,VMCS中保存了虛擬機(jī)的段描述符高速緩存,,因此在虛擬機(jī)切換時(shí)不會(huì)出現(xiàn)access to hidden state問題,;通過對(duì)VMCS進(jìn)行設(shè)置,可以使處理器在VMX non-root operation模式時(shí)的EFLAGS.IF失效,,即該標(biāo)志位不再對(duì)中斷屏蔽產(chǎn)生影響,,因此操作系統(tǒng)對(duì)EFLAGS.IF的頻繁操作不會(huì)導(dǎo)致頻繁的VM exit,解決了interrupt virtualization的問題,。 VT-x提供了完備的處理器虛擬化機(jī)制,,利用VT-x可以在單個(gè)硬件平臺(tái)上虛擬出任意數(shù)量的虛擬處理器VCPU。VT-x除了解決了處理器虛擬化的問題之外,,還為內(nèi)存虛擬化和I/O虛擬化提供了支撐,。在內(nèi)存虛擬化方面,VT-x為影子頁表的實(shí)現(xiàn)提供了支撐,,并且在較新的處理器中還提供了EPT機(jī)制,,進(jìn)一步提高了內(nèi)存虛擬化的效率。在I/O虛擬化方面,,通過I/O位圖機(jī)制可以方便地實(shí)現(xiàn)對(duì)Programmed I/O的虛擬化,,除此之外,VT-x還提供了中斷事件退出機(jī)制和中斷事件注入機(jī)制,,方便對(duì)設(shè)備中斷進(jìn)行虛擬化,。 2.2. KVM實(shí)現(xiàn) 作為VMM,,KVM分為兩部分,,分別是運(yùn)行于Kernel模式的KVM內(nèi)核模塊和運(yùn)行于User模式的Qemu模塊。這里的Kernel模式和User模式,,實(shí)際上指的是VMX根模式下的特權(quán)級(jí)0和特權(quán)級(jí)3,。另外,KVM將虛擬機(jī)所在的運(yùn)行模式稱為Guest模式,。所謂Guest模式,,實(shí)際上指的是VMX的非根模式。
利用VT-x技術(shù)的支持,,KVM中的每個(gè)虛擬機(jī)可具有多個(gè)虛擬處理器VCPU,,每個(gè)VCPU對(duì)應(yīng)一個(gè)Qemu線程,VCPU的創(chuàng)建,、初始化,、運(yùn)行以及退出處理都在Qemu線程上下文中進(jìn)行,,需要Kernel、User和Guest三種模式相互配合,,其工作模型如圖2.1所示,。Qemu線程與KVM內(nèi)核模塊間以ioctl的方式進(jìn)行交互,而KVM內(nèi)核模塊與客戶軟件之間通過VM Exit和VM entry操作進(jìn)行切換,。 Qemu線程以ioctl的方式指示KVM內(nèi)核模塊進(jìn)行VCPU的創(chuàng)建和初始化等操作,,主要指VMM創(chuàng)建VCPU運(yùn)行所需的各種數(shù)據(jù)結(jié)構(gòu)并初始化。其中很重要的一個(gè)數(shù)據(jù)結(jié)構(gòu)就是VMCS,,其初始化配置見附2,。 初始化工作完成之后,Qemu線程以ioctl的方式向KVM內(nèi)核模塊發(fā)出運(yùn)行VCPU的指示,,后者執(zhí)行VM entry操作,,將處理器由kernel模式切換到Guest模式,中止宿主機(jī)軟件,,轉(zhuǎn)而運(yùn)行客戶軟件,。注意,宿主機(jī)軟件被中止時(shí),,正處于Qemu線程上下文,,且正在執(zhí)行ioctl系統(tǒng)調(diào)用的kernel模式處理程序??蛻糗浖谶\(yùn)行過程中,,如發(fā)生異常或外部中斷等事件,,或執(zhí)行I/O操作,,可能導(dǎo)致VM exit,將處理器狀態(tài)由Guest模式切換回Kernel模式,。KVM內(nèi)核模塊檢查發(fā)生VM exit的原因,,如果VM exit由于I/O操作導(dǎo)致,則執(zhí)行系統(tǒng)調(diào)用返回操作,,將I/O操作交給處于User模式的Qemu線程來處理,,Qemu線程在處理完I/O操作后再次執(zhí)行ioctl,指示KVM切換處理器到Guest模式,,恢復(fù)客戶軟件的運(yùn)行,;如果VM exit由于其它原因?qū)е拢瑒t由KVM內(nèi)核模塊負(fù)責(zé)處理,,并在處理后切換處理器到Guest模式,,恢復(fù)客戶機(jī)的運(yùn)行。
3. 內(nèi)存虛擬化 3.1. VT-x內(nèi)存虛擬化介紹 3.1.1. 基于VTLB的內(nèi)存虛擬化 對(duì)于x86平臺(tái)來說,,處理器在加電或復(fù)位后處于實(shí)模式,,此后在操作系統(tǒng)的操縱下一般會(huì)先切換到非分頁保護(hù)模式,,最后在切換到分頁保護(hù)模式。VMM必須能夠滿足以上各種模式下的內(nèi)存虛擬化要求,,完全控制客戶機(jī)對(duì)物理地址的訪問,,實(shí)現(xiàn)虛擬機(jī)間物理內(nèi)存的隔離,并對(duì)客戶機(jī)保持透明,??蛻魴C(jī)絕大多數(shù)情況下將工作在分頁保護(hù)模式下,因此我們首先介紹客戶機(jī)工作在分頁保護(hù)模式時(shí)的內(nèi)存虛擬化,。 我們知道,,當(dāng)處理器未啟動(dòng)VMX模式時(shí),頁表機(jī)制確定了線性地址到物理地址的對(duì)應(yīng)關(guān)系,。為了加快地址轉(zhuǎn)換的效率,,減少地址轉(zhuǎn)換過程中的頁表訪問次數(shù),處理器使用TLB(Translation Lookaside Buffer)來緩存線性地址到物理地址的映射關(guān)系,。實(shí)際的地址轉(zhuǎn)換過程中,,處理器首先根據(jù)線性地址查找TLB,如果未發(fā)現(xiàn)該線性地址到物理地址的映射關(guān)系(TLB miss),,將根據(jù)頁表中的映射關(guān)系填充TLB(TLB fill),,然后再進(jìn)行地址轉(zhuǎn)換。因此,,頁表雖然確定了線性地址到物理地址的對(duì)應(yīng)關(guān)系,,但它并不直接控制線性地址到物理地址的轉(zhuǎn)換,這種轉(zhuǎn)換是由TLB控制的,。在不會(huì)導(dǎo)致地址轉(zhuǎn)換錯(cuò)誤的前提下,,處理器不要求TLB的內(nèi)容一定與頁表保持一致,例如一次進(jìn)程切換后,,TLB的內(nèi)容可能都是無效的,,但進(jìn)程的頁表卻是有效的,此時(shí)頁表和TLB是不一致的,,以后訪問內(nèi)存時(shí)會(huì)引發(fā)TLB miss,,并通過TLB fill令某個(gè)頁表項(xiàng)與某個(gè)TLB項(xiàng)保持一致,。 VT-x中可采用一種稱為Virtual TLB(VTLB)的技術(shù)來實(shí)現(xiàn)內(nèi)存虛擬化,,其思想就源于上述多級(jí)頁表與TLB間的交互機(jī)制,其工作機(jī)制如圖3.1所示,。VM的頁表并不直接控制線性地址到物理地址的轉(zhuǎn)換,,即CR3寄存器并不指向VM的頁目錄,而是指向VMM維護(hù)的影子頁表(Shadow Page Table),,因此線性地址到物理地址的轉(zhuǎn)換是由影子頁表和TLB來控制的,,影子頁表和TLB共同構(gòu)成了所謂的Virtual TLB,。VM可以任意修改其頁表,而不會(huì)導(dǎo)致VM exit,,由此可能產(chǎn)生兩種VM頁表與VTLB之間的不一致情況,。 第一種不一致是指VM的頁表擁有比影子頁表更多的訪問能力,可以利用頁面故障來修補(bǔ)這種不一致性,。例如VM頁表有某個(gè)線性地址到物理的對(duì)應(yīng)關(guān)系而影子頁表中卻沒有,,那么VM對(duì)該線性地址的訪問將導(dǎo)致頁面故障。VMM可以捕獲該異常,,進(jìn)而根據(jù)VM的頁表來修改影子頁表,。 第二種不一致是指VM的頁表的訪問能力不及影子頁表,那么一定是由于VM修改了自己的頁表,,并且把頁表的訪問權(quán)限降低了,,例如頁面交換將頁表項(xiàng)的P位置0,但該操作并不會(huì)馬上反映到TLB中,。此時(shí),,VM需要執(zhí)行INVLPG指令或重裝CR3寄存器來刷新TLB,VM在執(zhí)行INVLPG指令或重裝CR3寄存器時(shí)將導(dǎo)致VM exit,使VMM有機(jī)會(huì)根據(jù)VM的頁表來修改影子頁表,,從而修補(bǔ)這種不一致性,。 另外,處理器在進(jìn)行內(nèi)存訪問時(shí)會(huì)自動(dòng)修改頁表項(xiàng)的A位或D位,。A位在所有級(jí)別的頁表項(xiàng)中都存在,但在TLB entry中并不緩存A位,,原因是本次訪存操作涉及的各個(gè)級(jí)別的頁表項(xiàng)都允許本次訪問,,才會(huì)在TLB中生成一個(gè)entry,因此只要TLB中存在一個(gè)entry,,那么一定已經(jīng)將entry相關(guān)的各級(jí)頁表項(xiàng)都訪問過了,,各級(jí)頁表項(xiàng)的A位都是1。處理器在初次訪問一個(gè)頁表項(xiàng)時(shí),,將其A位置1,,但由軟件負(fù)責(zé)將A位清0。如果軟件將A位由1變成0,,它應(yīng)該使用INVLPG指令使對(duì)應(yīng)的TLB entry失效,。如果不這樣做,那么在訪存時(shí),,總是使用TLB中緩存的entry,,處理器認(rèn)為頁表項(xiàng)中的A位已經(jīng)是1了,從而不會(huì)將A位由0改為1,。在軟件看來,,好象該頁自將A位置0以來未曾被訪問過,,而實(shí)際情況并不是這樣。 D位僅在最后一級(jí)頁表中存在,,而且在TLB entry中也緩存D位,。當(dāng)首次寫一個(gè)頁時(shí),如果TLB entry不存在或其D位為0,,則將頁表項(xiàng)中的D位置1,,同A位相同,由軟件負(fù)責(zé)將D位置1,。如果軟件將PTE的D位由1變成0,,應(yīng)該使用INVLPG指令使對(duì)應(yīng)的TLB entry失效。如果不這樣做,,那么再次寫該頁時(shí),,總是優(yōu)先使用緩存的TLB entry,并且TLB entry的D位為1,,這時(shí)處理器認(rèn)為PTE的D位已經(jīng)是1了,,它不會(huì)再將其置1。在軟件看來,,好象該頁自將D位置0以來未曾被寫過,,而實(shí)際情況并不是這樣。 由于VM進(jìn)行內(nèi)存訪問實(shí)際使用的是影子頁表,,因此這種修改不能自動(dòng)反映到客戶頁表中,,從而導(dǎo)致客戶頁表和影子頁表的不一致。應(yīng)該有某種機(jī)制使VMM得以捕獲處理器對(duì)影子頁表的A位和D位的初次修改,,并更新VM頁表,,從而解決這種不一致性。 對(duì)于A位,,只要VMM不先于VM建立線性地址到物理地址的映射關(guān)系,,就可以確保捕獲客戶對(duì)內(nèi)存的訪問,進(jìn)而有機(jī)會(huì)確保影子頁表項(xiàng)和客戶頁表項(xiàng)在A位上的一致,。因?yàn)?,?dāng)客戶首次訪問某個(gè)線性地址時(shí),由于影子頁表中沒有該線性地址到物理地址的對(duì)應(yīng)關(guān)系,,將導(dǎo)致一次頁面故障,,VMM可以捕獲該故障,在影子頁表中建立線性地址到物理地址的對(duì)應(yīng)關(guān)系,,并將客戶頁表中相應(yīng)項(xiàng)的A位置1,。 對(duì)于D位,,VMM在影子頁表中建立線性地址到物理地址間的映射之初,,可以將頁置為只讀,,這樣當(dāng)VM對(duì)該頁進(jìn)行寫操作時(shí),將導(dǎo)致頁面故障,,使VMM獲得控制,,進(jìn)而有機(jī)會(huì)確保影子頁表項(xiàng)和VM頁表項(xiàng)在D位上的一致。
上面提到,,VMM必須能夠滿足以上各種處理器模式下的內(nèi)存虛擬化要求,,但由于VMX模式要求處理器必須工作在分頁保護(hù)模式下,因此VMM不可能允許客戶軟件將處理器切換到實(shí)模式或非分頁保護(hù)模式,,而只能在分頁保護(hù)模式下為客戶軟件模擬出類似實(shí)模式或非分頁保護(hù)模式的環(huán)境,。 可采用一個(gè)v86任務(wù)來模擬客戶機(jī)所需的實(shí)模式環(huán)境。我們知道,,v86軟件在執(zhí)行時(shí),,其邏輯地址經(jīng)16位分段機(jī)制轉(zhuǎn)換為20位線性地址,其后再經(jīng)過分頁機(jī)制轉(zhuǎn)換為物理地址,。因此,,在客戶機(jī)引導(dǎo)之初,VMM可以另客戶操作系統(tǒng)的實(shí)模式代碼執(zhí)行于一個(gè)v86任務(wù)中,,并為其構(gòu)造執(zhí)行所需的頁表結(jié)構(gòu),,從而接管客戶軟件對(duì)物理內(nèi)存訪問。 客戶的非分頁保護(hù)模式代碼實(shí)際上是執(zhí)行在分頁保護(hù)模式之下,,只不過通過影子CR0等機(jī)制使客戶察覺不到而已,。客戶邏輯地址經(jīng)32位分段機(jī)制轉(zhuǎn)換后為32位線性地址,,而后經(jīng)VMM構(gòu)造的頁表轉(zhuǎn)換為物理地址,,從而避免了客戶軟件對(duì)物理內(nèi)存的直接控制。 3.1.2. 基于EPT的內(nèi)存虛擬化 基于VTLB進(jìn)行內(nèi)存虛擬化時(shí),,因?yàn)榭蛻粼谧x寫CR3,、執(zhí)行INVLPG指令或客戶頁表不完整等情況下均會(huì)導(dǎo)致VM exit,這導(dǎo)致了內(nèi)存虛擬化效率很低,。較新的Intel處理器中引入了EPT(Extended Page Table)技術(shù),,用于提高內(nèi)存虛擬化的效率。 EPT引入了額外的一套頁表結(jié)構(gòu),,后者定義了客戶物理地址到主機(jī)物理地址之間的映射關(guān)系,,所有的客戶物理地址(如CR3給出的頁目錄基址、PDE給出的頁表基址,、PTE給出的頁基址等)須經(jīng)由EPT頁表結(jié)構(gòu)轉(zhuǎn)換后用于訪存,,其原理如圖3.2所示。
EPT由VMM控制,并且僅在處理器工作于非根模式時(shí)才參與地址轉(zhuǎn)換,。采用EPT后,,客戶在讀寫CR3和執(zhí)行INVLPG指令時(shí)不會(huì)導(dǎo)致VM exit,并且由于客戶頁表結(jié)構(gòu)自身導(dǎo)致的頁故障也不會(huì)導(dǎo)致VM exit,,因此極大地提高了內(nèi)存虛擬化的效率,,簡(jiǎn)化了內(nèi)存虛擬化的實(shí)現(xiàn)。 3.2. KVM實(shí)現(xiàn) 3.2.1. 客戶物理內(nèi)存管理 每個(gè)虛擬機(jī)都需要擁有一定數(shù)量的物理內(nèi)存,。物理內(nèi)存是寶貴的資源,,為了提高物理內(nèi)存的利用率,也為了在一臺(tái)計(jì)算機(jī)上運(yùn)行盡可能多的虛擬機(jī),,不能將一塊物理內(nèi)存固定劃分給某個(gè)虛擬機(jī)使用,,而應(yīng)該采用按需分配的方式。下面簡(jiǎn)述KVM的內(nèi)存管理原理,,參見圖3.3,。 PC機(jī)的物理內(nèi)存通常是不連續(xù)的,例如地址0xA0000至0xFFFFF,、0xE0000000至0xFFFFFFFF等通常留給BIOS ROM和MMIO而不是物理內(nèi)存,。設(shè)虛擬機(jī)包括n塊物理內(nèi)存,分別記做P1, P2, …, Pn,,每塊物理內(nèi)存的起始地址分別記做PB1, PB2, …, PBn,,每塊物理內(nèi)存的大小分別為PS1, PS2, …, PSn。 在虛擬機(jī)創(chuàng)建之初,,Qemu使用malloc()從其進(jìn)程地址空間中申請(qǐng)了一塊與虛擬機(jī)的物理內(nèi)存大小相等的區(qū)域,,設(shè)該區(qū)域的基地址為B。
接下來,,Qemu根據(jù)虛擬機(jī)的物理內(nèi)存布局,,將該區(qū)域劃分成n個(gè)子區(qū)域,分別記做V1, V2, …, Vn,,第i個(gè)子區(qū)域與第i塊物理內(nèi)存對(duì)應(yīng),,每個(gè)子區(qū)域的起始線性地址記做VB1, VB2, …, VBn,每個(gè)子區(qū)域的大小等于對(duì)應(yīng)的物理內(nèi)存塊的大小,,仍是PS1, PS2, …, PSn,。 然后,Qemu向KVM內(nèi)核模塊通告虛擬機(jī)的物理內(nèi)存布局,。KVM內(nèi)核模塊中使用slot結(jié)構(gòu)來記錄虛擬機(jī)的物理內(nèi)存布局,,每一個(gè)物理內(nèi)存塊對(duì)應(yīng)一個(gè)slot,其中記錄著該物理內(nèi)存塊的起始物理地址PBi,、大小PSi等信息,,還記錄了該物理內(nèi)存塊對(duì)應(yīng)的在Qemu線性地址空間中的子區(qū)域的起始地址VBi,。 當(dāng)發(fā)生由于頁故障引發(fā)的VM exit時(shí),VMM首先搜索客戶頁表,,如果客戶頁表中本身就不存在客戶線性地址GVA到客戶物理地址GPA的映射,,則將該異常事件回注給虛擬機(jī),由客戶軟件處理該頁故障,。如果在客戶頁表中存在GVA到GPA的映射,,則從客戶頁表中得到該GPA,,然后根據(jù)GPA得到其所屬的slot,,進(jìn)而得到該GPA對(duì)應(yīng)的Qemu地址空間中的主機(jī)線性地址HVA,然后通過linux內(nèi)核函數(shù)get_user_pages()確定HVA所對(duì)應(yīng)的主機(jī)物理地址HPA,,如果HVA到HPA的映射不存在,,get_user_pages()會(huì)分配物理內(nèi)存,然后再建立HVA到HPA的映射,。之后,,VMM可以使用該HPA來構(gòu)建影子頁表,即建立GVA到HPA的映射,。因此,,KVM系統(tǒng)中的虛擬機(jī)所使用的物理內(nèi)存是最終還是由Linux內(nèi)核來分配的。 3.2.2. VTLB實(shí)現(xiàn) 我們先來看一下VTLB的基本操作,??蛻粽嬲脑L存是通過影子頁表進(jìn)行的,如果影子頁表中存在客戶線性地址到物理地址的映射,,那么訪存操作就正常進(jìn)行了,。如果影子頁表中不存在客戶線性地址到物理地址的映射,那么將引發(fā)一次頁故障,,從而導(dǎo)致一次VM exit,。VMM獲得控制后,將首先根據(jù)引發(fā)異常的客戶線性地址去查找客戶頁表,,如果客戶頁表本身限制這次訪問,,如到物理地址的映射不存在、違反頁級(jí)保護(hù)規(guī)則等,,VMM將把異常事件回注給客戶,,由客戶操作系統(tǒng)處理該頁故障。如果客戶頁表允許本次訪問,,那么通常本次頁故障是由于影子頁表中不存在客戶線性地址到物理地址的映射引起的,,此時(shí)就需要根據(jù)客戶頁表的內(nèi)容來構(gòu)建相應(yīng)的影子頁表,或稱為對(duì)客戶頁表進(jìn)行影射(Shadowing),。 如圖所示,,SPD是PD的影子頁表,,SPT1/SPT2是PT1/PT2的影子頁表。由于客戶PDE和PTE給出的頁表基址和頁基址并不是真正的物理地址,,所以我們采用虛線表示PDE到客戶頁表以及PTE到普通客戶頁的映射關(guān)系,。
VMM中用于影子頁表的內(nèi)存是受限的,因此當(dāng)內(nèi)存緊張時(shí),,VMM可能回收一部分影子頁表,。例如,可能回收?qǐng)D中的影子頁表SPT2,,以后客戶訪問P1時(shí)將導(dǎo)致頁故障,,VMM將再次分配影子頁表,查詢客戶頁表,,并修補(bǔ)客戶線性地址到P1的映射,。 如果完全模擬物理TLB的行為,客戶機(jī)在切換CR3時(shí),,VMM需要清空整個(gè)VTLB,,使所有影子頁表的內(nèi)容無效。在多進(jìn)程客戶操作系統(tǒng)中,,CR3將被頻繁地切換,,某些影子頁表的內(nèi)容可能很快就會(huì)被再次用到,而重建影子頁表是一項(xiàng)十分耗時(shí)的工作,。因此,,采用完全模擬物理TLB行為的方法構(gòu)建VTLB在效率上是較差的。 提高效率的主要做法就是緩存影子頁表,,即客戶切換CR3時(shí)不清空影子頁表,。例如,假設(shè)客戶機(jī)上有兩個(gè)進(jìn)程A和B,,參見圖3,,在T1時(shí)刻之前A正在運(yùn)行,此時(shí)CR3指向進(jìn)程A的影子頁表,。在T1至T2時(shí)刻進(jìn)程B運(yùn)行,,此時(shí)CR3指向進(jìn)程B的影子頁表,但并不丟棄進(jìn)程A的影子頁表,。以后在T3時(shí)刻再次切換到進(jìn)程A時(shí),,原來A的影子頁表還可以重用,這就避免了全部重新構(gòu)建A的影子頁表,,提高了效率,。 為了實(shí)現(xiàn)緩存影子頁表的做法,必須意識(shí)到以下問題的存在:客戶可能在不通知VMM的情況下,,象修改普通內(nèi)存一樣修改影子頁表,。例如,,在進(jìn)程B運(yùn)行時(shí),客戶OS可能由于內(nèi)存的緊張,,將屬于進(jìn)程A的內(nèi)存換出,,并將相應(yīng)的頁表項(xiàng)的P位置0,而由于A不是當(dāng)前進(jìn)程,,所以客戶OS不會(huì)使用INVLPG指令刷新TLB,,VMM也就無從得知客戶修改了進(jìn)程A的頁表。以后,,當(dāng)進(jìn)程A恢復(fù)運(yùn)行時(shí),,由于影子頁表與客戶頁表不一致,將導(dǎo)致錯(cuò)誤,。 因此,,在采用緩存影子頁表的做法時(shí),,必須有某種機(jī)制保持客戶頁表與影子頁表間的一致性,,這可通過為客戶頁表所在的頁設(shè)置寫保護(hù)來實(shí)現(xiàn)。 首先必須區(qū)別普通客戶內(nèi)存和客戶頁表,,因?yàn)樾噬系目紤],,不能對(duì)所有的客戶頁面進(jìn)行寫保護(hù)。當(dāng)一個(gè)頁表沒有用于訪存時(shí),,VMM是無從知道該頁的身份的,。例如,客戶操作系統(tǒng)在初始化某張頁表時(shí),,VMM不能確定該頁是普通客戶內(nèi)存還是客戶頁表,,只有以后該表頁用于訪存時(shí),由于在VTLB中沒有影射,,將導(dǎo)致一次VTLB Fill,,并觸發(fā)VMM搜索客戶頁表結(jié)構(gòu),從而得知與引起頁面故障的客戶線性地址相關(guān)的客戶頁面的真實(shí)身份,。 VTLB Fill操作實(shí)際上在客戶頁表和影子頁表之間進(jìn)行了一次同步,,為了跟蹤客戶頁表的后續(xù)變化,應(yīng)該對(duì)客戶頁表進(jìn)行寫保護(hù),。注意,,客戶頁表也是通過影子頁表來訪問的,為了設(shè)置寫保護(hù)就必須知道影子頁表中訪問客戶頁表所使用的PTE,,為了做到這一點(diǎn),,KVM在影子頁表中建立客戶線性地址到物理地址的映射關(guān)系的同時(shí),還維護(hù)了物理地址到末級(jí)頁表PTE間的逆向映射,,即給定客戶頁面,,能夠方便地得到訪問該客戶頁面的末級(jí)頁表PTE,。圖中,紅色箭頭表示逆向映射,。同時(shí),,給定一個(gè)客戶頁面,如果其逆向映射存在,,那么正向映射一定存在,,即該客戶頁面可以通過影子頁表被訪問到。
當(dāng)VMM在VTLB Fill操作過程中識(shí)別一個(gè)客戶頁表,,如PT1,,就會(huì)通過逆向映射找到訪問其所需的影子頁表項(xiàng),如SPT2中的某個(gè)PTE,,將PTE的WP位置1,。以后,客戶對(duì)該客戶頁表的修改將導(dǎo)致VM exit,,從而使VMM有機(jī)會(huì)與客戶頁表保持同步,。 需注意的問題是,內(nèi)存的緊張可能導(dǎo)致SPT2被回收,,因此在識(shí)別到一個(gè)客戶頁表時(shí),,影子頁表中不一定總存在到客戶頁表的映射,也就不能為其設(shè)置寫保護(hù),。但以后客戶要修改該頁表時(shí),,總要首先在影子頁表中建立到它的映射,在建立映射時(shí),,VMM檢查該客戶頁面是否是客戶頁表且已被影射*,,如果是則置頁表項(xiàng)的WP位為1。 還有一種可能是,,影子頁表中存在到PT1的映射,,但PT1并沒有被影射。這時(shí),,VMM不對(duì)PT1進(jìn)行寫保護(hù),,客戶可隨意修改PT1,以后當(dāng)客戶使用PT1進(jìn)行訪存時(shí),,必然會(huì)引起一次VTLB Fill,,從而使VMM有機(jī)會(huì)影射該客戶頁表,與其同步,,并在SPT2沒有被回收的情況下設(shè)置對(duì)該客戶頁表的寫保護(hù),。 由以上分析中我們還可看出,客戶頁表可以很大,,但VMM沒有必要對(duì)它們?nèi)窟M(jìn)行影射,,VMM僅需影射那些真正用于訪存的客戶頁表,。 另外,當(dāng)客戶機(jī)切換到分頁保護(hù)模式之后,,可選擇采用多種分頁機(jī)制,,包括普通IA-32分頁機(jī)制、PAE分頁機(jī)制,、IA-32e分頁機(jī)制和PSE-36分頁機(jī)制,。為了簡(jiǎn)化實(shí)現(xiàn),KVM的影子頁表采用PAE分頁機(jī)制或IA-32e分頁機(jī)制實(shí)現(xiàn),,客戶的普通IA-32分頁機(jī)制和PSE-36分頁機(jī)制可以通過采用PAE分頁機(jī)制的影子頁表來模擬,。
|
|