1、前言
ARM架構虛擬化擴展(Virtualization Extension)是在2010年作為ARMv7架構的一部分引入的,它為虛擬化提供了架構支持。在此之前,ARM系統(tǒng)上的虛擬化解決方案都是基于半虛擬化(paravirtualization)的,并沒有被廣泛使用。
不過隨著ARM CPU的性能不斷提高,并從智能手機和平板電腦等移動設備向傳統(tǒng)服務器進軍,人們對ARM虛擬化的興趣也在增長,因為對ARM來說,支持虛擬化對它的生態(tài)建設起到很重要的作用。
于是,ARM虛擬化擴展就出現(xiàn)了,它的核心設計目標是構建ARM hypervisor,且它可以運行未經(jīng)修改的Guest OS,而不增加顯著的硬件復雜性,同時保持高水平的性能,而且也符合Popek和Goldberg的定理要求,關于這個定理,大家可以看下《一文讀懂虛擬化原理》文章。
2、CPU虛擬化
虛擬化擴展側(cè)重于在虛擬化上下文中支持現(xiàn)有的ISA,因此ARM沒打算改變ISA單個指令語義,而不單獨處理架構中限制虛擬化的指令。相反,虛擬化擴展引入了一種新的更高特權處理器執(zhí)行的模式,這個模式在ARMv7架構首次引入時稱為HYP(hypervisor)模式,在ARMv8架構以及之后稱為EL2。
ARM架構上的CPU模式如圖1所示,包括TrustZone(安全擴展)。TrustZone將模式分為安全和非安全兩個世界,這兩個世界與CPU模式是正交的。而且在EL3也提供了一種特殊模式:Monitor mode(監(jiān)控器模式),用于在安全和非安全世界之間切換。如果實現(xiàn)了TrustZone,盡管ARM CPU在安全模式下啟動,但ARM的引導加載程序(bootloaders)通常在早期階段過渡到非安全世界。安全世界用于可信計算場景,如數(shù)字版權管理。不過需要注意的是,最新的ARM架構已經(jīng)支持secure狀態(tài)下的EL2 Hypervisor了。
圖1 ARM處理器模式
不像以前的ARM架構支持多種kernel模式,ARMv8只有一個kernel模式:EL1。圖1中為支持虛擬機擴展而引入的名為EL2的新CPU特權級別(也成為異常級別,Exception Level, EL),它構建于現(xiàn)有的user(EL0)和kernel(EL1)級別上,是虛擬化拓展的中心。EL2以trap-and-emulate機制來支持虛擬化,它是嚴格地比其它CPU模式(EL0和EL1)擁有更多特權的CPU模式。
為了支持虛擬機VM,運行在EL2中的軟件可以配置捕獲(Trap)來自EL0或EL1的各種敏感指令和硬件中斷去EL2,這樣系統(tǒng)使用起來更靈活了。比如,不支持資源復用的分區(qū)hypervisor可能不會捕獲正常hypervisor會捕獲的某些指令。允許VM支持使用ARM調(diào)試寄存器而不是對它們進行Trap在某些情況下是可取的。如果想要模擬與正在使用的CPU不同的CPU,則有必要捕獲對CPU標識符寄存器的訪問,但沒有必要捕獲運行完整hypervisor所需的其它訪問。
為了允許VM與物理機相同的接口進行交互,同時將它們與系統(tǒng)的其余部分隔離,并防止它們獲得對硬件的完全訪問權,hypervisor在切換到VM之前要使能EL2中的虛擬化特性。然后VM將在EL0和EL1中正常執(zhí)行,直到達到需要hypervisor干預的某些條件。此時,硬件進入EL2,將控制權交接給hypervisor,然后hypervisor可以管理硬件并提供跨VM所需的隔離。一旦系統(tǒng)hypervisor處理了該條件,CPU就可以切換回EL0和EL1,VM就可以恢復執(zhí)行了。當在EL2中禁用所有虛擬化特性時,在EL1和EL0中運行的軟件就像在沒有虛擬化擴展的系統(tǒng)上運行一樣,在EL1中運行的軟件具有對硬件的完全訪問權限。
ARM架構允許將每個Trap配置為直接路由給在EL1的VM,而不是EL2的hypervisor。例如,由EL0引起的系統(tǒng)調(diào)用或頁表錯誤的Trap可以配置為直接路由到EL1,以便由Guest OS處理它們,而不需要hypervisor的干預。它避免在每次系統(tǒng)調(diào)用或頁表錯誤時轉(zhuǎn)到EL2,從而減少了虛擬化開銷。此外,所有進入EL2的Trap都可以被禁用,單個非虛擬化kernel可以在EL1中運行并完全控制系統(tǒng)。與EL1相比,EL2中可用的控制寄存器數(shù)量減少了。例如,EL2只有一個頁表基寄存器,而EL1可以使用兩個??梢哉f,通過減少EL2中可用的控制寄存器的數(shù)量,因此也相應減少需要操作的狀態(tài)數(shù)量,這樣可以簡化hypervisor的實現(xiàn)。
ARM的Virtualization Extensions提供了以下特性:
處理器在任何時間點都只能處于一種CPU模式,即EL0,EL1或EL2。從一種模式到另一種模式的實際轉(zhuǎn)換是原子的,但是從一種模式到另一種模式時根據(jù)需要保存和恢復狀態(tài)的過程不是原子的。
CPU模式可以通過執(zhí)行MRS指令來確定,MRS指令在任何模式下都可用。最開始的期望是無論有沒有虛擬機,應用程序和操作系統(tǒng)仍然使用相同的CPU模式運行。但在這種假設下,EL2執(zhí)行本身不能被虛擬化,并且不支持遞歸虛擬機,因為嵌套的hypervisor可以確定它不是運行在EL2。
EL2被設計用于虛擬化,但它只是一種更有特權的CPU模式,也可以用于其它目的。
每種模式由不同的頁表定義,都有自己完整線性地址空間。EL2有自己的translation regime,它定義了給定模式中使用的寄存器和頁表格式。然而,EL1/EL0共享一個translation regime,因此它們的地址空間和頁表都可以在EL1和EL0中訪問。因為每個TLB 條目都會被標記上translation regime,因此只有在當前活躍地址空間的translation regime匹配上TLB條目的標記,才能算作命中了。由于TLB條目標記,因此在EL2和其它CPU模式之間轉(zhuǎn)換時不需要刷新TLB內(nèi)容。
ARM有兩種類型的中斷:正常中斷(IRQ)和快速中斷(FIQ),以及對應處理器當前模式的兩個中斷標志。EL1中的軟件可以自由操作每種中斷類型的中斷標記而不會引發(fā)Trap。EL2可以配置每個中斷類型要么直接傳遞到EL1,要么Trap到EL2。當中斷直接傳遞給EL1時,由EL1直接配置的中斷標志控制真正的物理中斷。當中斷Trap到EL2時,由EL1直接配置的中斷標志控制虛擬中斷。
3、內(nèi)存虛擬化
HAPPY NEW YEAR
ARM引入了一組額外的頁表來將Guest physical address轉(zhuǎn)換成Host physical address,并將此作為虛擬化支持的一部分。在運行VM時,使用ARM的硬件支持使用虛擬化物理內(nèi)存,由VM管理的物理地址實際上是中間物理地址(Intermediate Physical Addresses, IPAs),也稱為來賓物理地址(Guest physical addresses, gPAs),需要轉(zhuǎn)換為主機物理地址(host physical addresses, hPAs)。因此,ARM提供了第二組頁表,stage-2 tables,用于將guest物理地址(gPAs)和host物理地址(hPAs)。EL2可以完全禁用或啟動Stage-2轉(zhuǎn)換。Stage-2頁表使用ARM新的LPAE(Large Physical Address Extension)頁表格式,與kernel模式使用的頁表有細微的區(qū)別。
圖2為ARM中完整的地址轉(zhuǎn)換機制。在stage-1階段,從virtual physical address到guest physical address轉(zhuǎn)換使用了三層頁表;在stage-2階段,從guest physical address到host physical address的轉(zhuǎn)換使用了四層頁表??梢允褂肏CR(Hyp Configuration Register)中的一個域段來啟用或禁用stage-2轉(zhuǎn)換。Stage-2第一層次(L1)頁表的基寄存器由Virtualization Translation Table Base Register(VTTBR)指定的,這兩個寄存器只能從EL2配置。
圖2 ARM上使用LPAE內(nèi)存長格式描述符的stage-1核stage-2頁表遍歷過程。虛擬地址(VA)首先轉(zhuǎn)換為guest PA,最后轉(zhuǎn)換為host PA。
4、中斷虛擬化
HAPPY NEW YEAR
ARM定義了通用中斷控制器(Generic Interrupt Controller, GIC)架構。GIC分配從設備到CPU的中斷,CPU查詢GIC來發(fā)現(xiàn)中斷的來源。在多核配置中,GIC尤其重要,因為它用于生成處理器間從一個CPU內(nèi)核到另一個CPU內(nèi)核的中斷(Inter-Processor Interrupts, IPIs)。GIC分為兩部分:distributor(分發(fā)器)和CPU interfaces(CPU接口)。系統(tǒng)中只有一個distributor,但每個CPU核心都有一個GIC CPU interface。CPU interface和distributor都通過Memory-Mapped interface(MMIO)訪問GIC。Distributor用于配置GIC,例如,設置中斷的CPU core affinity、完全啟用或禁用系統(tǒng)上的中斷、或?qū)PI發(fā)送到另一個CPU核心。CPU interface用于確認(ACK)和發(fā)送中斷結束(End-of-Interrupt, EOI)信號。例如,當一個CPU內(nèi)核接收到一個中斷時,它將在GIC CPU接口上讀取一個特殊寄存器,該寄存器對中斷進行ACK處理并返回中斷的編號。在CPU將從ACK寄存器中檢索到的值寫入CPU接口的EOI寄存器之前,將不會再次向CPU發(fā)出中斷。
可以將中斷配置為Trap到EL2或EL1。將所有中斷Trap到EL1并讓運行在EL1中的操作系統(tǒng)軟件直接處理它們是有效地,但在虛擬機環(huán)境中不起作用,因為hypervisor失去了對硬件的控制。將所有中斷Trao到EL2可確保hypervisor保留控制權,但需要在軟件中模擬虛擬中斷以向VM發(fā)送信號事件。由于中斷和虛擬中斷處理的每個步驟(如ACK和EOI)都必須經(jīng)過hypervisor,因此管理起來很麻煩,而且成本很高。
GIC以虛擬GIC(vGIC)的形式提供硬件虛擬化支持,因此不需要在軟件中由hypervisor模擬接收虛擬中斷。vGIC為每個CPU引入了一個vGIC CPU接口以及相應的hypervisor控制接口。虛擬機被配置為vGIC CPU接口,而不是GIC CPU接口。在vGIC hypervisor控制接口上,虛擬中斷是通過寫入特殊寄存器(list registers)來生成。vGIC CPU接口將虛擬中斷直接送到VM的kernel模式。因為vGIC CPU接口支持ACK和EOI,這些操作不再需要Trap到hypervisor去用軟件模擬了,從而減少了在CPU上接收中斷的開銷。例如,模擬的虛擬設備通常通過軟件API向hypervisor發(fā)起虛擬中斷,hypervisor可以通過將模擬設備的虛擬中斷號寫入list registers來利用vGIC。它使vGIC直接將虛擬機中斷送到kernel模式,并允許Guest OS的ACK和EOI虛擬中斷,而不會Trap到hypervisor。請注意,distributor仍然需要在軟件中模擬,并且VM對distributor的所有訪問必須Trap到hypervisor。例如,當一個虛擬CPU向另一個虛擬CPU發(fā)送一個虛擬IPI時,這個將Trap到hypervisor,hypervisor在軟件中模擬分發(fā)器的訪問,并在接收CPU的GIC hypervisor控制接口上編程list registers。
5、計時器虛擬化
HAPPY NEW YEAR
ARM定義了通用計時器架構(Generic Timer Architecture),其中包括對計時器虛擬化的支持。通用計時器提供一個計數(shù)器來實時測量時間的流逝,并為每個CPU提供一個計時器,它被編程為在一定時間后向CPU發(fā)起中斷。Hypervisor和Guest OS都可能使用計時器,但是為了提供隔離和保持控制,Guest OS不能直接配置和操作hypervisor使用的計時器。來自Guest OS的這種計時器訪問需要Trap到EL2,對于某些工作負載來說,相對頻繁的操作會帶來額外的開銷。Hypervisor也可能希望虛擬化VM時間,因為VM可以直接訪問計數(shù)器硬件,那就不符合虛擬化要求了。
ARM通過引入一個新的計數(shù)器(虛擬計數(shù)器)和一個新的計時器(虛擬計時器),為計時器提供虛擬化支持。可以將hypervisor配置為使用物理計時器,而將虛擬機配置為使用虛擬計時器。然后,虛擬機可以訪問、編程和取消虛擬計時器,而不會對EL2產(chǎn)生Trap。Kernel模式訪問物理計時器和計數(shù)器是由EL2控制的,但是在kernel模式下運行的軟件總是可以訪問虛擬計時器和虛擬計數(shù)器。此外,EL2配置一個偏移寄存器,它從物理計數(shù)器中減去,并在讀取虛擬計數(shù)器時作為返回值。請注意,在使用通用計時器之前,讀取計數(shù)器時內(nèi)存映射操作,因此頻繁操作讀取的話,通常會Trap到EL2并產(chǎn)生額外的開銷。