加入星計(jì)劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴(kuò)散
  • 作品版權(quán)保護(hù)
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長(zhǎng)期合作伙伴
立即加入
  • 正文
    • 綜述
    • AArch64的虛擬化
    • 虛擬化的損耗
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請(qǐng)入駐 產(chǎn)業(yè)圖譜

萬(wàn)字剖析 Armv8 架構(gòu)虛擬化

2022/07/13
2064
閱讀需 43 分鐘
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

綜述

本文描述了Armv8-A AArch64的虛擬化支持。包括stage 2頁(yè)表轉(zhuǎn)換,虛擬異常,以及陷阱。本文介紹了一些基礎(chǔ)的硬件輔助虛擬化理論以及一些Hypervisor如何利用這些虛擬化特性的例子。文本不會(huì)講述某一具體的Hypervisor軟件是如何工作的以及如何開發(fā)一款Hypervisor軟件。通過(guò)閱讀本文,你可以學(xué)到兩種類型的Hypervisor以及它們是如何映射到Arm的異常級(jí)別。你將能解釋陷阱是如何工作的以及其是如何被用來(lái)進(jìn)行各種模擬操作。你將能描述Hypervisor可以產(chǎn)生什么虛擬異常以及產(chǎn)生這些虛擬異常的機(jī)制。理解本文內(nèi)容需要一定基礎(chǔ),本文假定你熟悉ARMv8體系結(jié)構(gòu)的異常模型和內(nèi)存管理。

虛擬化簡(jiǎn)介

這里我們將介紹一些基礎(chǔ)的Hypervisor和虛擬化的理論知識(shí)。如果你已經(jīng)有一定的基礎(chǔ)或是已經(jīng)熟悉了這些概念,可以跳過(guò)這部分內(nèi)容。我們用Hypervisor這個(gè)詞來(lái)定義一種負(fù)責(zé)創(chuàng)建,管理以及調(diào)度虛擬機(jī)(Virtual Machines, VMs)的軟件。

虛擬化為什么重要?

虛擬化是一種在現(xiàn)代云計(jì)算和企業(yè)基礎(chǔ)架構(gòu)中廣泛使用的技術(shù)。開發(fā)人員用虛擬機(jī)在一個(gè)硬件平臺(tái)上運(yùn)行多個(gè)不同的操作系統(tǒng)來(lái)開發(fā)和測(cè)試軟件,以避免對(duì)主計(jì)算環(huán)境造成可能的破壞。虛擬化技術(shù)服務(wù)器上非常流行,大多數(shù)面向服務(wù)器的處理器都需要支持虛擬化功能,這是因?yàn)樘摂M化能給數(shù)據(jù)中心服務(wù)器帶來(lái)如下一些需要的特性:

  • 隔離:利用虛擬化可以對(duì)同一個(gè)物理核上運(yùn)行的虛擬機(jī)進(jìn)行隔離。這使得相互間不可信的的計(jì)算環(huán)境可以共享同一套硬件環(huán)境。例如,兩個(gè)競(jìng)爭(zhēng)對(duì)手可以共享同一個(gè)物理機(jī)器而又不能訪問(wèn)對(duì)方的數(shù)據(jù)。高可用性:虛擬化可以在不同的物理機(jī)器之間無(wú)縫透明地遷移負(fù)載。這個(gè)技術(shù)廣泛用于將負(fù)載從出錯(cuò)的硬件平臺(tái)遷移至其他可用平臺(tái),以便維護(hù)和替換出錯(cuò)的硬件而不影響服務(wù)。負(fù)載均衡:為了降低數(shù)據(jù)中心硬件和功耗成本,需要盡可能充分地利用硬件平臺(tái)資源。將負(fù)載均衡地遷移到不同地物理機(jī)上,有利用充分利用物理機(jī)資源,降低功耗,同時(shí)為租戶提供最佳性能。沙箱:虛擬機(jī)可以作為一個(gè)沙箱來(lái)為運(yùn)行在其中的應(yīng)用屏蔽其他軟件的干擾,或者避免其干擾其他軟件。例如在虛擬機(jī)中運(yùn)行特定軟件,可以避免該軟件的bug或病毒導(dǎo)致物理機(jī)器上的其他軟件損壞。

Hypervisor的兩種類型

Hypervisor通常被分成兩種類型,獨(dú)立類型Type 1和寄生類型 Type 2。我們先看看Type 2類型的Hypervisor。對(duì)于Type 2類型的Hypervisor,其寄生的宿主操作系統(tǒng)擁有對(duì)硬件平臺(tái)和資源(包括CPU物理內(nèi)存…)的全部控制權(quán)。下圖展示了Type 2類型的Hypervisor。

 

宿主操作系統(tǒng),指的是直接運(yùn)行在硬件平臺(tái)上并為Type 2類型的Hypervisor提供運(yùn)行環(huán)境的操作系統(tǒng)。這類Hypervisor可以充分利用宿主操作系統(tǒng)對(duì)物理硬件的管理功能,而Hypervisor只需提供虛擬化相關(guān)功能即可。不知你是否使用過(guò)Virtual Box或是VMware Workstation, 這類軟件就是Type 2類型的Hypervisor。

接下來(lái),看看獨(dú)立類型的Type 1 Hypervisor, 如下圖。這類Hypervisor沒有宿主操作系統(tǒng)。其直接運(yùn)行在物理硬件之上,直接管理各種物理資源,同時(shí)管理并運(yùn)行客戶機(jī)操作系統(tǒng)。

 

開源社區(qū)常見的Hypervisor, Xen (Type 1) 和 KVM (Type 2)就分屬這兩種不同的類型。

全虛擬化和半虛擬化

關(guān)于虛擬機(jī),經(jīng)典定義是:虛擬機(jī)是一個(gè)獨(dú)立的隔離的計(jì)算環(huán)境,這種計(jì)算環(huán)境讓使用者看起來(lái)就像在使用真實(shí)的物理機(jī)器一樣。盡管我們可以在基于ARM的硬件平臺(tái)上模擬真實(shí)硬件,但這通常不是最有效的做法,因此我們常常不這么做。例如,模擬一個(gè)真實(shí)的以太網(wǎng)設(shè)備是非常慢的,這是因?yàn)閷?duì)任何一個(gè)模擬寄存器的訪問(wèn)都會(huì)陷入到Hypervisor當(dāng)中進(jìn)行模擬。比起直接訪問(wèn)物理寄存器來(lái)說(shuō),這種操作的代價(jià)要昂貴得多。一個(gè)替代方案是修改客戶操作系統(tǒng),使之意識(shí)到自身運(yùn)行在虛擬機(jī)當(dāng)中,通過(guò)在Hypervisor中模擬一個(gè)虛擬設(shè)備來(lái)給客戶機(jī)使用。以此來(lái)?yè)Q取更好得I/O性能。嚴(yán)格來(lái)說(shuō),全虛擬化需要完全模擬真實(shí)硬件,性能上會(huì)比較差。開源項(xiàng)目Xen推進(jìn)了半虛擬化,通過(guò)修改客戶機(jī)操作系統(tǒng)的核心部分使其更適合在虛擬環(huán)境中運(yùn)行,以此來(lái)提高性能。

另一個(gè)使用半虛擬化的原因是早期的體系結(jié)構(gòu)并不是為虛擬化而設(shè)計(jì)的,存在虛擬化漏洞。因?yàn)樘摂M化要求所有敏感指令或訪問(wèn)敏感資源的指令都能被截獲模擬。對(duì)于存在虛擬化漏洞的體系結(jié)構(gòu),則需要通過(guò)半虛擬化的方案來(lái)填補(bǔ)漏洞。而今,大多數(shù)體系機(jī)構(gòu)都支持硬件輔助虛擬化,包括Arm。這使得操作系統(tǒng)的核心部分無(wú)需修改也能獲得較好得性能。只有少數(shù)存儲(chǔ)和網(wǎng)絡(luò)相關(guān)的I/O設(shè)備仍然采用半虛擬化的方案來(lái)改善性能,這類半虛擬化的方案如,virtio 和 Xen PV Bus。

虛擬機(jī)(VM)和虛擬CPU (vCPU)

有必要區(qū)分虛擬機(jī)(VM)和虛擬CPU(vCPU)。這有利于理解本文的后續(xù)部分。例如,一個(gè)內(nèi)存頁(yè)面可以分配給一個(gè)虛擬機(jī),因此所有屬于該VM的vCPUs都可以訪問(wèn)它。而一個(gè)虛擬中斷只是針對(duì)某個(gè)vCPU,因此只有該vCPU可以收到。虛擬機(jī)(VM)和虛擬CPU(vCPU)的關(guān)系如下圖所示。

 

注意:ARM體系結(jié)構(gòu)定義了處理單元(Processing Element, PE)一詞,現(xiàn)代CPU可能包含多個(gè)內(nèi)核或線程,PE用來(lái)指代單一的執(zhí)行單元。同樣的這里的vCPU嚴(yán)格來(lái)說(shuō)應(yīng)該是vPE。

AArch64的虛擬化

對(duì)于ARMv8, Hypervisor運(yùn)行在EL2異常級(jí)別。只有運(yùn)行在EL2或更高異常級(jí)別的軟件才可以訪問(wèn)并配置各項(xiàng)虛擬化功能。

  • Stage 2轉(zhuǎn)換EL1/0指令和寄存器訪問(wèn)注入虛擬異常

安全狀態(tài)和非安全狀態(tài)下的異常級(jí)別及可運(yùn)行的軟件如下圖所示:

注意:安全狀態(tài)的EL2用灰色顯示是因?yàn)?,安全狀態(tài)的EL2并不總是可用,這是Armv8.4-A引入的特性。

Stage 2 轉(zhuǎn)換

什么是Stage 2 轉(zhuǎn)換?

Stage 2 轉(zhuǎn)換允許Hypervisor控制虛擬機(jī)的內(nèi)存視圖。具體來(lái)說(shuō),其可以控制虛擬機(jī)是否可以訪問(wèn)特定的某一塊物理內(nèi)存,以及該內(nèi)存塊出現(xiàn)在虛擬機(jī)內(nèi)存空間的位置。這種能力對(duì)于虛擬機(jī)的隔離和沙箱功能來(lái)說(shuō)至關(guān)重要。這使得虛擬機(jī)只能看到分配給它自己的物理內(nèi)存。為了支持Stage 2 轉(zhuǎn)換, 需要增加一個(gè)頁(yè)表,我們稱之為Stage 2頁(yè)表。操作系統(tǒng)控制的頁(yè)表轉(zhuǎn)換稱之為stage 1轉(zhuǎn)換,負(fù)責(zé)將虛擬機(jī)視角的虛擬地址轉(zhuǎn)換為虛擬機(jī)視角的物理地址。而stage 2頁(yè)表由Hypervisor控制,負(fù)責(zé)將虛擬機(jī)視角的物理地址轉(zhuǎn)換為真實(shí)的物理地址。虛擬機(jī)視角的物理地址在Armv8中有特定的詞描述,叫中間物理地址(intermediate Physical Address, IPA)。

stage 2轉(zhuǎn)換表的格式和stage 1的類似,但也有些屬性的處理不太一樣,例如,判斷內(nèi)存類型 是normal 還是 device的信息被直接編碼進(jìn)了表里,而不是通過(guò)查詢MAIR_ELx寄存器。

VMID

每一個(gè)虛擬機(jī)都被分配一個(gè)ID號(hào),稱之為VMID。這個(gè)ID號(hào)用于標(biāo)記某個(gè)特定的TLB項(xiàng)屬于哪一個(gè)VM。VMID使得不同的VM可以共享同一塊TLB緩存。VMID存儲(chǔ)在寄存器VTTBR_EL2中,可以是8或16比特,由VTCR_EL2.vs比特位控制,其中16比特的VMID支持是在armv8.1-A中擴(kuò)展的,是可選的。需注意,EL2和EL3的地址轉(zhuǎn)換不需要VMID標(biāo)記,因?yàn)樗鼈儾恍枰猻tage 2轉(zhuǎn)換。

VMID vs ASID

TLB項(xiàng)也可以用ASID(Address Space Identifier)標(biāo)記,每個(gè)應(yīng)用都被操作系統(tǒng)分配有一個(gè)ASID,所有屬于同一個(gè)應(yīng)用的TLB項(xiàng)都有相同的ASID。這使得不同應(yīng)用可以共享同一塊TLB緩存。每一個(gè)VM有它自己的ASID空間。例如兩個(gè)不同的VMs同時(shí)使用ASID 5,但指的是不同的東西。對(duì)于虛擬機(jī)而言,通常VMID會(huì)結(jié)合ASID同時(shí)使用。

屬性整合和覆蓋

stage 1 和 stage 2映射都包含屬性,例如存儲(chǔ)類型,訪問(wèn)權(quán)限等。內(nèi)存管理單元(MMU)會(huì)將兩個(gè)階段的屬性整合成一個(gè)最終屬性,整合的原則是選擇更有限制的屬性。且看如下例子:

在上面的例子中,Device屬性比起Normal屬性更具限制性,因此最終結(jié)果是Device屬性。同樣的原理,如果你將順序調(diào)換一下也不會(huì)改變最終的屬性。

屬性整合在大多數(shù)情況下都可以工作。但有些時(shí)候,例如在VM的早期啟動(dòng)階段,Hypervisor希望改變默認(rèn)的行為,則可以通過(guò)如下寄存器比特來(lái)實(shí)現(xiàn)。

  • HCR_EL2.CD: 控制所有stage 1屬性為Non-cacheable。HCR_EL2.DC:強(qiáng)制所有stage 1屬性為Normal,Write-Back Cacheable。HCR_EL2.FWB (Armv8.4-A引入):使用stage 2屬性覆蓋stage 1屬性,而不是使用默認(rèn)的限制性整合原則。

模擬MMIO

與物理機(jī)器的物理地址空間類似,VM的IPA地址空間包含了內(nèi)存與外圍設(shè)備兩種區(qū)域。如下圖所示:

 

VM使用外圍設(shè)備區(qū)域來(lái)訪問(wèn)其看到的物理外圍設(shè)備,這其中包含了直通設(shè)備和虛擬外圍設(shè)備。虛擬設(shè)備完全由Hypervisor模擬,如下圖所示

一個(gè)直通設(shè)備被直接分配給VM并映射到IPA地址空間,這使得VM中的軟件可用直接訪問(wèn)真實(shí)的物理硬件。一個(gè)虛擬的外圍設(shè)備由Hypervisor模擬,其stage 2的轉(zhuǎn)換項(xiàng)被標(biāo)記為fault。雖然VM中的軟件看來(lái)其是直接與物理設(shè)備交互,但實(shí)際上這一訪問(wèn)會(huì)導(dǎo)致stage 2轉(zhuǎn)換fault,從而進(jìn)入相應(yīng)的異常處理程序由Hypervisor模擬。

為了模擬一個(gè)外圍設(shè)備,Hypervisor需要知道哪一個(gè)外圍設(shè)備被訪問(wèn),外圍設(shè)備的哪一個(gè)寄存器被訪問(wèn),是讀訪問(wèn)還是寫訪問(wèn),訪問(wèn)長(zhǎng)度是多少,以及使用哪些寄存器來(lái)傳送數(shù)據(jù)。

當(dāng)處理stage 1 faults時(shí),F(xiàn)AR_ELx寄存器包含了觸發(fā)異常的虛擬地址。但虛擬地址不是給Hypervisor用的,Hypervisor通常不會(huì)知道客戶操作系統(tǒng)如何配置虛擬地址空間的映射。對(duì)于stage 2 faults,有一個(gè)專門的寄存器HPFAR_EL2,該寄存器會(huì)報(bào)告發(fā)生錯(cuò)誤的IPA地址。IPA地址空間由Hypervisor控制,因此可用利用此寄存器里的信息來(lái)進(jìn)行必要的模擬。

ESR_ELx寄存器用于報(bào)告發(fā)生異常的相關(guān)信息。當(dāng)loads或stores一個(gè)通用寄存器觸發(fā)stage 2 fault時(shí),相關(guān)異常信息由這些寄存器提供。這些信息包含了,訪問(wèn)的長(zhǎng)度,訪問(wèn)的原地址或目的地址。Hypervisor可以以此來(lái)判斷對(duì)虛擬外圍設(shè)備訪問(wèn)的權(quán)限。下圖展示了一個(gè) 陷入(trapping) – 模擬(emulating) 的訪問(wèn)過(guò)程。

  1. VM里的軟件嘗試訪問(wèn)虛擬外圍設(shè)備,這個(gè)例子當(dāng)中是虛擬UART的接收FIFO。該訪問(wèn)被stage 2轉(zhuǎn)換block住,導(dǎo)致一個(gè)abort異常被路由到EL2。
  • 異常處理程序查詢ESR_EL2關(guān)于異常的信息,如訪問(wèn)長(zhǎng)度,目的寄存器,是load還是store操作。異常處理程序查詢HPFAR_EL2,取得發(fā)生abort的IPA地址。
  1. Hypervisor通過(guò)ESR_EL2和HPFAR_EL2里的相關(guān)信息對(duì)相關(guān)虛擬外圍設(shè)備作模擬,模擬完成后通過(guò)ERET指令返回vCPU,并從發(fā)生異常的下一條指令繼續(xù)執(zhí)行。

系統(tǒng)內(nèi)存管理單元(System Memory Management Units, SMMUs)

到目前為止,我們只考慮了從處理器發(fā)起的各種訪問(wèn)。我們還需要考慮其他主設(shè)備如DMA控制器發(fā)起的訪問(wèn)。我們需要一種方法來(lái)擴(kuò)展stage 2映射以保護(hù)這些主設(shè)備的地址空間。如果一個(gè)DMA控制器沒有使用虛擬化,那它看起來(lái)應(yīng)該如下圖所示:

DMA控制器通常由內(nèi)核驅(qū)動(dòng)編程控制。內(nèi)核驅(qū)動(dòng)會(huì)確保不違背操作系統(tǒng)層面的內(nèi)存保護(hù)原則,即一個(gè)應(yīng)用不能使用DMA訪問(wèn)其沒有權(quán)限訪問(wèn)的其他應(yīng)用的內(nèi)存。

下面讓我們考慮操作系統(tǒng)運(yùn)行在虛擬機(jī)中的場(chǎng)景。

在這個(gè)系統(tǒng)中,Hyperviosr通過(guò)stage 2映射來(lái)隔離不同VMs的地址空間。這是基于Hypervisor控制的stage 2映射表實(shí)現(xiàn)的。而驅(qū)動(dòng)則直接與DMA控制器交互,這會(huì)產(chǎn)生兩個(gè)問(wèn)題:

  • 隔離:DMA控制器訪問(wèn)在虛擬機(jī)之間沒有了隔離,這破壞了虛擬機(jī)的沙箱功能。地址空間:利用兩級(jí)映射轉(zhuǎn)換,使內(nèi)核看到的PAs實(shí)際上是IPAs。但DMA控制器看到的仍然是PAs。因此DMA控制器和內(nèi)核看到的是不同的地址空間,為了解決這個(gè)問(wèn)題,每當(dāng)VM與DMA控制器交互時(shí)就需要陷入到Hypervisor中做必要的轉(zhuǎn)換。這種處理方式是極其沒有效率的,且容易出錯(cuò)。

解決的辦法是將stage 2的機(jī)制推廣到DMA控制器。這么做的話,這些主設(shè)備控制器也需要一個(gè)MMU,Armv8稱之為SMMU(通常也稱為IOMMU)。

Hypervisor負(fù)責(zé)配置SMMU,以使DMA控制器看到的物理地址空間與kenrel看到的物理地址空間相同。這樣就能解決上述兩個(gè)問(wèn)題。

指令的陷入與模擬

有時(shí)Hypervisor需要模擬一些操作,例如VM里運(yùn)行的軟件試圖配置處理器的一些屬性,如電源管理或是緩存一致性時(shí)。通常你不會(huì)允許VM直接配置這些屬性,因?yàn)檫@會(huì)打破隔離性,從而影響其他VMs。這就需要通過(guò)以陷入的方式產(chǎn)生異常,在異常處理程序中做相應(yīng)的模擬。Armv8包含一些陷入控制來(lái)幫助實(shí)現(xiàn) 陷入(trapping) – 模擬(emulating)。如果對(duì)相應(yīng)操作配置了陷入,則這種操作發(fā)生時(shí)會(huì)陷入到更高的異常級(jí)別,便于Hypervisor模擬。

舉個(gè)例子,執(zhí)行等待中斷指令WFI通過(guò)會(huì)使CPU進(jìn)入低功耗狀態(tài)。然而,當(dāng)配置HCR_EL2.TWI==1時(shí),如果在EL0/EL1執(zhí)行WFI則會(huì)導(dǎo)致EL2的異常。(注:陷入不是為虛擬化而設(shè)計(jì)的,有陷入到EL3和EL1的異常,但異常對(duì)虛擬化實(shí)現(xiàn)至關(guān)重要。)

對(duì)于 WFI的例子里, 操作系統(tǒng)通過(guò)在一個(gè)idle loop里執(zhí)行 WFI指令,但虛擬機(jī)中的操作系統(tǒng)執(zhí)行該指令時(shí),會(huì)陷入到Hypervisor里模擬,這時(shí)Hypervisor通常會(huì)調(diào)度另一個(gè)vCPU執(zhí)行。

 

寄存器的訪問(wèn)

陷入 – 模擬的另一個(gè)用途是用來(lái)呈現(xiàn)虛擬寄存器的值。例如寄存器ID_AA64MMFR0_EL1是用來(lái)報(bào)告處理器內(nèi)存相關(guān)特性的,操作系統(tǒng)可能會(huì)讀取該寄存器來(lái)決定在內(nèi)核中開啟或關(guān)閉某些特性。Hypervisor可能會(huì)給VM呈現(xiàn)一個(gè)與實(shí)際物理寄存器不同的值。這是怎么實(shí)現(xiàn)的呢?首先Hypervisor需要開啟對(duì)該寄存器讀操作的陷入。然后,在陷入的異常處理中判斷異常相關(guān)的信息并進(jìn)行模擬。在如下例子中,就是設(shè)置一個(gè)虛擬的值,然后ERET返回。

避免陷入

陷入 – 模擬 的開銷是很大的。這種操作需要先陷入到EL2,然后由Hypervisor做相應(yīng)模擬再返回客戶操作系統(tǒng)。對(duì)于某些寄存器如 ID_AA64MMFR0_EL1,操作系統(tǒng)并不經(jīng)常訪問(wèn),陷入 – 模擬的開銷還是可以接受的。但對(duì)于某些經(jīng)常訪問(wèn)的寄存器以及性能敏感的代碼,陷入太頻繁會(huì)對(duì)系統(tǒng)性能造成很大影響。對(duì)于這些情況,我們需要盡可能地優(yōu)化 陷入。

  • MIDR_EL1: 存有處理器類型信息MPIDR_EL1:親和性配置

Hypervisor可能希望在訪問(wèn)上述兩個(gè)寄存器時(shí)不要總是陷入。對(duì)這些寄存器,Armv8提供了與其對(duì)應(yīng)的不需要陷入的版本。Hypervisor可以在進(jìn)入VM 時(shí)先配置好這些寄存器的值。當(dāng)VM中讀到 MIDR_EL1 / MPIDR_EL1時(shí)會(huì)自動(dòng)返回VPIDR_EL2 / VMPIDR_EL2的值而不發(fā)生陷入。

  • VPIDR_EL2:讀取 MIDR_EL1返回 VPIDR_EL2的值避免陷入VMPIDR_EL2:讀取 MPIDR_EL1返回 VMPIDR_EL2的值避免陷入

注意:VPIDR_EL2 / VMPIDR_EL2 在硬件reset后沒有初始化的值,它們必須由軟件啟動(dòng)代碼初始化一個(gè)合理的值。

異常虛擬化

中斷是硬件通知軟件的機(jī)制,在一個(gè)使用虛擬化的系統(tǒng)中,中斷處理會(huì)變得更為復(fù)雜。有些中斷會(huì)由Hypervisor直接處理,有些中斷被分配給了VM,需要由VM中的處理程序處理,并且還有可能在接收到這個(gè)中斷時(shí),對(duì)應(yīng)的VM并沒有被調(diào)度運(yùn)行。這意味著我們不僅需要支持在EL2中直接處理中斷,還需要一種機(jī)制能將收到的中斷轉(zhuǎn)發(fā)給相應(yīng)VM的vCPU。Armv8提供了vIRQs, vFIQs, 和vSErrors來(lái)支持虛擬中斷。這些中斷的行為和物理中斷(IRQs, FIQs, 和 SErrors)類似,只不過(guò)只有當(dāng)系統(tǒng)運(yùn)行在EL0/1是才會(huì)收到,運(yùn)行在EL2/3是收不到虛擬中斷的。

開啟虛擬中斷

虛擬中斷也是根據(jù)中斷類型控制的。為了發(fā)送虛擬中斷到EL0/1, Hypervisor需要設(shè)置 HCR_EL2中相應(yīng)的中斷路由比特位。例如,開啟vIRQ,你需要設(shè)置 HCR_EL2.IMO, 這意味著物理IRQ中斷將被發(fā)送到EL2,同時(shí)虛擬中斷將被發(fā)送到EL1。理論上,Armv8可以配置成VM直接接收物理FIQs和虛擬IRQs。但在實(shí)際應(yīng)用中,通常配置VM只接收虛擬中斷。

產(chǎn)生虛擬中斷

有兩種方式產(chǎn)生虛擬中斷:

  1. 配置HCR_EL2,由內(nèi)部CPU核產(chǎn)生使用GICv2及以上版本的外部中斷控制器

我們先來(lái)看第一種機(jī)制,HCR_EL2中有如下的控制比特位

  • VI: 配置vIRQVF: 配置vFIQVSE: 配置vSError

設(shè)置上述比特位等同于中斷控制器向vCPU發(fā)送中斷信號(hào)。和常規(guī)物理中斷一樣,虛擬中斷受PSTATE控制。這種機(jī)制簡(jiǎn)單易用,但有個(gè)明顯的缺點(diǎn),需要由Hypervisor來(lái)模擬中斷控制器的相關(guān)操作,一系列的 陷入 – 模擬將帶來(lái)性能上的開銷。

第二種方式是使用Arm的通用中斷控制器(Generic Interrupt Controller, GIC)來(lái)產(chǎn)生虛擬中斷。從GICv2版本開始,GIC可以通過(guò)物理CPU interface 和 虛擬CPU interface發(fā)送物理中斷和虛擬中斷。見下圖:

這兩個(gè)CPU interface是等同的,區(qū)別是一個(gè)發(fā)送物理中斷信號(hào),另一個(gè)發(fā)送虛擬中斷信號(hào)。Hypervisor可以將虛擬CPU interface映射給VM,以便VM可以直接和GIC通信。這種方式的好處是Hypervisor只需建立映射,不需要做任何模擬,從而提升了性能。(PS:虛擬化性能提升的關(guān)鍵就在優(yōu)化陷入,減少次數(shù),優(yōu)化流程)

中斷轉(zhuǎn)發(fā)給vCPU的例子

上面介紹了虛擬中斷是如何開啟和生產(chǎn)的。讓我們來(lái)看一個(gè)中斷轉(zhuǎn)發(fā)給vCPU的例子。考慮一個(gè)物理外圍設(shè)備,該設(shè)備被分配給了某個(gè)VM,如下圖所示:

具體步驟如下:

  1. 物理外圍設(shè)備發(fā)送中斷信號(hào)給GIC。GIC產(chǎn)生物理中斷異常,可能是IRQ或FIQ。由于配置了HCR_EL2.IMO/FMO,這些異常會(huì)被路由到EL2。Hyperviosr發(fā)現(xiàn)該設(shè)備已被分配給了某個(gè)VM,于是檢查需要將該中斷信號(hào)轉(zhuǎn)發(fā)給哪個(gè)vCPU。Hypervisor配置了GIC將該物理中斷以虛擬中斷的形式轉(zhuǎn)給某個(gè)vCPU。GIC于是發(fā)送vIRQ/vFIQ信號(hào),如果此時(shí)還運(yùn)行在EL2,這些信號(hào)會(huì)被忽略。Hypervisor將控制權(quán)返還給vCPU。處理器運(yùn)行在EL0或EL1,來(lái)自GIC的虛擬中斷被接收(受PSTATE控制)。

上面的例子展示了如何將一個(gè)物理中斷以虛擬中斷的形式轉(zhuǎn)發(fā)給VM。如果是一個(gè)沒有物理中斷對(duì)應(yīng)的純虛擬中斷,Hypervisor可以直接注入虛擬中斷。

中斷屏蔽

我們知道中斷屏蔽比特位PSTATE.I, PSTATE.F, PSTATE.A分別對(duì)應(yīng)IRQs, FIQs和SErrors。如果運(yùn)行在虛擬化環(huán)境中,這些比特位的工作方式有些許不同。

例如,對(duì)于IRQs,設(shè)置HCR_EL2.IMO意味著

  • 物理IRQ路由至EL2對(duì)EL0/EL1開啟vIRQs

這同時(shí)也改變了PSTATE.I 屏蔽的含義, 當(dāng)運(yùn)行在EL0/EL1是,如果 HCR_E2.IMO==1, PSTATE.I針對(duì)的是虛擬的vIRQs而非物理的pIRQs。

時(shí)鐘虛擬化

Arm體系結(jié)構(gòu)中,每個(gè)處理器上都有一組通用時(shí)鐘。通用時(shí)鐘由一組比較器組成,用來(lái)與系統(tǒng)計(jì)數(shù)器比較。當(dāng)比較器的值小于等于系統(tǒng)計(jì)數(shù)器時(shí)便會(huì)產(chǎn)生時(shí)鐘中斷。在下圖中,我們可以看到系統(tǒng)中通用時(shí)鐘由黃色框部分組成。

下圖展示了虛擬化系統(tǒng)中運(yùn)行兩個(gè)vCPU的時(shí)序。

物理世界的時(shí)間(墻上時(shí)間)4ms里,每個(gè)vCPU各運(yùn)行了2ms。如果我們?cè)O(shè)置vCPU0的比較器在T=0之后的3ms產(chǎn)生一個(gè)中斷,那么你希望實(shí)際在哪個(gè)墻上時(shí)間點(diǎn)產(chǎn)生中斷呢?是vCPU0的虛擬時(shí)間的2ms,也就是墻上時(shí)間3ms那個(gè)點(diǎn)還是 vCPU0虛擬時(shí)間3ms的那個(gè)點(diǎn)?

實(shí)際上,Arm體系結(jié)構(gòu)同時(shí)支持上述兩種設(shè)置,這取決于你使用何種虛擬化方案。讓我們看看這是如何實(shí)現(xiàn)的。

運(yùn)行在vCPU上的軟件可以訪問(wèn)如下兩種時(shí)鐘

  • EL1物理時(shí)鐘EL1虛擬時(shí)鐘

EL1物理時(shí)鐘會(huì)與系統(tǒng)計(jì)數(shù)器模塊直接比較,使用的是絕對(duì)的墻上時(shí)間。而EL1虛擬時(shí)鐘與虛擬計(jì)數(shù)器比較。虛擬計(jì)數(shù)器是在物理計(jì)數(shù)器的基礎(chǔ)上減去一個(gè)偏移。Hypervisor負(fù)責(zé)為當(dāng)前調(diào)度運(yùn)行的vCPU指定對(duì)應(yīng)的偏移寄存器。這種方式使得虛擬時(shí)間只會(huì)覆蓋vCPU實(shí)際運(yùn)行的那部分時(shí)間。

 

下圖展示了虛擬時(shí)間運(yùn)作的原理

在一個(gè)6ms的時(shí)段里,每個(gè)vCPU分別運(yùn)行了3ms。Hypervisor可以使用偏移寄存器來(lái)將vCPU的時(shí)間調(diào)整為其實(shí)際運(yùn)行的時(shí)間。

虛擬化主機(jī)擴(kuò)展(Virtualization Host Extensions, VHE)

圖21顯示了一個(gè)Type 1類型的虛擬化系統(tǒng)的軟件棧與異常級(jí)別的對(duì)應(yīng)關(guān)系,Hypervisor部分運(yùn)行在EL2,VMs運(yùn)行在EL0/1。

 

然而,對(duì)于一個(gè)Type 2類型的系統(tǒng),其軟件棧與異常級(jí)別的對(duì)應(yīng)關(guān)系可能如下圖所示:

通常,寄主操作系統(tǒng)的內(nèi)核部分運(yùn)行在EL1,控制虛擬化的部分運(yùn)行在EL2。然而,這種設(shè)計(jì)有一個(gè)明顯的問(wèn)題。VHE之前的Hypervisor通常需要設(shè)計(jì)成high-visor和low-visor兩部分,前者運(yùn)行在EL1,后者運(yùn)行在EL2。分層設(shè)計(jì)在系統(tǒng)運(yùn)行時(shí)會(huì)造成很多不必要的上下文切換,帶來(lái)不少設(shè)計(jì)上的復(fù)雜性和性能開銷。為了解決這個(gè)問(wèn)題,虛擬化主機(jī)擴(kuò)展 (Virtualization Host Extensions, VHE)應(yīng)運(yùn)而生。該特性由Armv8.1-A引入,可以讓寄主操作系統(tǒng)的內(nèi)核部分直接運(yùn)行在EL2上。

將主機(jī)操作系統(tǒng)運(yùn)行在EL2

VHE由系統(tǒng)寄存器 HCR_EL2中的兩個(gè)比特位控制

  • E2H:VHE使能位TGE:當(dāng)VHE使能時(shí),控制EL0是Guest還是Host
|         Running in        | E2H | TGE |
|---------------------------|-----|-----|
|Guest kernel (EL1)         |  1  |  0  |
|Guest application (EL0)    |  1  |  0  | 
|Host kernel (EL2)          |  1  |  1* |
|Host application (EL0)     |  1  |  1  |

當(dāng)發(fā)生異常從VM退出到Hypervisor時(shí),TGE將會(huì)初始化為0,軟件需要先設(shè)置這一比特,再繼續(xù)運(yùn)行host kernel的主代碼。

一個(gè)典型的配置如下圖:

虛擬地址空間

在VHE引入之前,EL0/1的虛擬地址空間看起來(lái)如下。EL0/1分兩塊區(qū)域,上面是內(nèi)核空間,下面是用戶空間。EL2只有一個(gè)空間,Hypervisor通常不需要運(yùn)行應(yīng)用,因此沒有必要?jiǎng)澐謨?nèi)核與用戶空間。同理,EL0/1虛擬地址空間支持ASID,但EL2不需要支持。

當(dāng)VHE引入之后,EL2可以直接運(yùn)行操作系統(tǒng)代碼。因此需要將地址空間劃分和ASID的支持添加進(jìn)來(lái)。同樣,通過(guò)設(shè)置 HCR_EL2.E2H來(lái)解決。

當(dāng)運(yùn)行在EL0時(shí),HCR_EL2.TGE控制使用EL1還是EL2空間,當(dāng)應(yīng)用運(yùn)行在Guest OS (TGE==0)為前者,運(yùn)行在Host OS(TGE==1)為后者。

重定向寄存器訪問(wèn)

除了會(huì)使用不同的地址空間映射,VHE還有一個(gè)問(wèn)題需要解決,那就寄存器訪問(wèn)。運(yùn)行在EL2的內(nèi)核仍然會(huì)嘗試訪問(wèn)*_EL1的寄存器。為了運(yùn)行無(wú)需修改的內(nèi)核,我們需要將EL1的寄存器重定向到EL2。當(dāng)你設(shè)置E2H后,這一切就會(huì)由硬件實(shí)現(xiàn)。

但是,重定向又會(huì)帶來(lái)一個(gè)新的問(wèn)題,那就是Hypervisor完全可能在某些情況下,例如當(dāng)執(zhí)行任務(wù)切換時(shí), 訪問(wèn)真正EL1的寄存器。為了解決這個(gè)問(wèn)題,Arm架構(gòu)引入了一種新的別名機(jī)制,以_EL12或_EL02結(jié)尾。如下例,就可以在ECH==1的EL2訪問(wèn)TTBR0_EL1。

異常

通常系統(tǒng)寄存器 HCR_EL2.IMO/FMO/AMO的這幾個(gè)比特位可以用來(lái)控制物理異常被路由至EL1或EL2。當(dāng)運(yùn)行在EL0且TGE==1時(shí),HCR_EL2路由比特將會(huì)被忽略,所有物理異常(除了那些由SCR_EL3控制的會(huì)被路由至EL3)全部路由到EL2。這是因?yàn)镠ost OS里運(yùn)行的應(yīng)用是Host OS的一部分,而Host OS運(yùn)行在EL2。

嵌套虛擬化

Hypervisor可以運(yùn)行在VM中,這稱之為嵌套虛擬化。

我們將第一個(gè)Hypervisor稱為Host Hypervisor,VM中運(yùn)行的Hypervisor稱為Guest Hypervisor。

在Armv8.3-A之前,Guest Hypervisor可以運(yùn)行在EL0。但這種設(shè)計(jì)需要大量軟件模擬,不僅軟件開發(fā)困難,性能也很差。Armv8.3-A增加了一些新的特性,可以讓Guest Hypervisor運(yùn)行在EL1。而Armv8.4-A引入的一些新特性,使得這一過(guò)程更有效率,雖然仍然需要Host Hypervisor參與做一些額外的工作。

Guest Hypervisor訪問(wèn)虛擬化控制接口

我們并不希望Guest Hypervisor能直接訪問(wèn)虛擬化控制接口,因?yàn)檫@么做會(huì)破壞VM的沙箱機(jī)制,使得虛擬機(jī)能夠看到Host平臺(tái)的信息。當(dāng)Guest Hypervisor運(yùn)行在EL1,并訪問(wèn)虛擬化控制接口時(shí),HCR_EL2中新的控制比特位可以使這些操作陷入到Host Hypervisor(EL2)以便模擬。

  • HCR_EL2.NV:開啟硬件輔助嵌套虛擬化HCR_EL2.NV1:開啟額外需要陷入的操作HCR_EL2.NV2:開啟重定向到內(nèi)存VNCR_EL2:當(dāng)NV2==1時(shí),指向一個(gè)內(nèi)存中的結(jié)構(gòu)體

Armv8.3-A添加了NV和NV1控制比特。在此之前,從EL1訪問(wèn)*_EL2寄存器時(shí)的行為是未定義的,通常是會(huì)產(chǎn)生一個(gè)EL1的異常。而控制比特NV和NV1使得這種訪問(wèn)可以被陷入到EL2。這就使得Guest Hypervisor可以運(yùn)行在EL1,同時(shí)由運(yùn)行在EL2的Host Hypervisor來(lái)模擬這些操作。NV還會(huì)導(dǎo)致EL1運(yùn)行ERET陷入到EL2。

下圖展示了Guest Hypervisor如何創(chuàng)建并啟動(dòng)虛擬機(jī):

 

  1. 從EL1訪問(wèn)*_EL2寄存器將導(dǎo)致Guest Hypervisor陷入到EL2。Host Hypervisor記錄Guest Hypervisor創(chuàng)建的相關(guān)配置。Guest Hypervisor嘗試進(jìn)入其創(chuàng)建的虛擬機(jī),此時(shí)ERET指令會(huì)陷入到EL2。Host Hypervisor根據(jù)Guest Hypervisor的配置,設(shè)置相關(guān)寄存器以便啟動(dòng)VM,清理掉NV比特位,最后進(jìn)入Guest Hypervisor創(chuàng)建的Guest運(yùn)行。

按上述的方法, 在Guest Hypervisor訪問(wèn)任何一個(gè)*_EL2寄存器時(shí)都會(huì)發(fā)生陷入。切換操作如 任務(wù)切換,vCPU切換,VMs切換都會(huì)訪問(wèn)大量寄存器,每次陷入都會(huì)導(dǎo)致異常的進(jìn)入與返回,從而帶來(lái)嚴(yán)重的 陷入 – 模擬性能問(wèn)題。(回憶前面的內(nèi)容, 虛擬化性能提升的關(guān)鍵就在優(yōu)化陷入,減少次數(shù),優(yōu)化流程)。Armv8.4-A提供了一個(gè)更好的方案,當(dāng)NV2被設(shè)置時(shí),從EL1訪問(wèn)*_EL2寄存器將會(huì)被重定向到一塊內(nèi)存區(qū)域。Guest Hypervisor可以多次讀寫這塊寄存器區(qū)域而不發(fā)生陷入。只有當(dāng)最后運(yùn)行ERET時(shí),才會(huì)陷入到EL2。而后,Host Hypervisor可以從該內(nèi)存區(qū)域中提取相關(guān)配置并代Guest Hypervisor執(zhí)行相關(guān)操作。

 

  1. 從EL1訪問(wèn)*_EL2寄存器將會(huì)被重定向到一塊內(nèi)存區(qū)域,該內(nèi)存區(qū)域的地址由Host Hypervisor在 VNCR_EL2中指定。Guest Hypervisor嘗試進(jìn)入其創(chuàng)建的虛擬機(jī),此時(shí)ERET指令會(huì)陷入到EL2Host Hypervisor從內(nèi)存中提取配置信息,設(shè)置相關(guān)寄存器,以便啟動(dòng)VM,清理掉NV比特位,最后進(jìn)入Guest Hypervisor創(chuàng)建的Guest運(yùn)行。

這個(gè)改進(jìn)方法相比之前的方法會(huì)減少陷入到Host Hypervisor的次數(shù),從而提升了性能。

安全世界虛擬化

虛擬化擴(kuò)展最早是在Armv7-A引入的。在Armv7-A中的Hyp模式等同于AArch32中的EL2,僅僅在非安全世界才存在。作為一個(gè)可選特性,Armv8.4-A增加了安全世界下EL2的支持。支持安全世界EL2的處理器,需配置EL3下的SCR_EL3.EEL2比特位來(lái)開啟這一特性。設(shè)置了這一比特位,才允許使用安全狀態(tài)下的虛擬化功能。

在安全世界虛擬化之前,EL3通常用于運(yùn)行安全狀態(tài)切換軟件和平臺(tái)固件。然而從設(shè)計(jì)上來(lái)說(shuō),我們希望EL3中運(yùn)行的軟件越少越好,因?yàn)樵胶?jiǎn)單才會(huì)更安全。安全狀態(tài)虛擬化使得我們可以將平臺(tái)固件移到EL1中運(yùn)行,由虛擬化來(lái)隔離平臺(tái)固件和可信操作系統(tǒng)內(nèi)核。下圖展示了這一理念:

安全EL2與兩個(gè)IPA空間

Arm體系結(jié)構(gòu)定義了安全世界和非安全世界兩個(gè)物理地址空間。在非安全狀態(tài)下,stage 1轉(zhuǎn)換的的輸出總是非安全的,因此只需要一個(gè)IPA空間來(lái)給stage 2使用。然而,對(duì)于安全世界,stage 1的輸出可能是安全的也能是非安全的。Stage 1轉(zhuǎn)換表中的NS比特位控制使用安全地址還是非安全地址。這意味著在安全世界,需要兩個(gè)IPA地址空間。

與stage 1表不同,stage 2轉(zhuǎn)換表中沒有NS比特位。因?yàn)閷?duì)于一個(gè)特定的IPA空間,要么全都是安全地址,要么全都是非安全的,因此只需要由一個(gè)寄存器比特位來(lái)確定IPA空間。通常來(lái)說(shuō),非安全地址經(jīng)過(guò)stage 2轉(zhuǎn)換仍然是非安全地址,安全地址經(jīng)過(guò)stage 2轉(zhuǎn)換仍然是安全地址。

虛擬化的損耗

虛擬化的損耗主要在于虛擬機(jī)和Hypervisor切換需要保存和恢復(fù)寄存器。Armv8系統(tǒng)中,最少需要對(duì)如下寄存器做處理

  • 31 x 64-bit通用寄存器(x0…x30)32 x 128-bit浮點(diǎn)/SIMD寄存器(V0…V31)兩個(gè)棧寄存器(SP_EL0, SP_EL1)

使用LDP和STP指令,Hypervisor需要運(yùn)行33條指令來(lái)存儲(chǔ)和恢復(fù)這些寄存器。虛擬化最終的損耗不僅取決于硬件還取決于Hypervisor的設(shè)計(jì)。

Arm

Arm

ARM公司是一家知識(shí)產(chǎn)權(quán)(IP)供應(yīng)商,主要為國(guó)際上其他的電子公司提供高性能RISC處理器、外設(shè)和系統(tǒng)芯片技術(shù)授權(quán)。目前,ARM公司的處理器內(nèi)核已經(jīng)成為便攜通訊、手持計(jì)算設(shè)備、多媒體數(shù)字消費(fèi)品等方案的RISC標(biāo)準(zhǔn)。公司1990年11月由Acorn、Apple和VLSI合并而成。

ARM公司是一家知識(shí)產(chǎn)權(quán)(IP)供應(yīng)商,主要為國(guó)際上其他的電子公司提供高性能RISC處理器、外設(shè)和系統(tǒng)芯片技術(shù)授權(quán)。目前,ARM公司的處理器內(nèi)核已經(jīng)成為便攜通訊、手持計(jì)算設(shè)備、多媒體數(shù)字消費(fèi)品等方案的RISC標(biāo)準(zhǔn)。公司1990年11月由Acorn、Apple和VLSI合并而成。收起

查看更多

相關(guān)推薦

電子產(chǎn)業(yè)圖譜

針對(duì)嵌入式人工智能,物聯(lián)網(wǎng)等專業(yè)技術(shù)分享和交流平臺(tái),內(nèi)容涉及arm,linux,android等各方面。

Arm64 ?;厮?>
				</a>
							</li>
						<li id=
  • Linux BSP實(shí)戰(zhàn)課(中斷篇):中斷控制器的驅(qū)動(dòng)實(shí)現(xiàn)
  • 查看更多