
01
在虛擬機(jī)管理器
(Bao Hypervisor)
中適配 RH850 系列
本節(jié)重點(diǎn)描述將 Bao虛擬機(jī)管理器(Bao Hypervisor)移植到瑞薩 RH850/U2Axx 架構(gòu)的過(guò)程,闡述 Bao 如何利用該平臺(tái)的虛擬化擴(kuò)展實(shí)現(xiàn)高效且安全的隔離環(huán)境。我們將從 Bao 的設(shè)計(jì)理念出發(fā),逐步拆解其配置過(guò)程、初始化流程及運(yùn)行時(shí)操作。最后,我們?cè)敿?xì)研究RH850/U2Axx架構(gòu)支持,詳細(xì)探討B(tài)ao如何利用其關(guān)鍵硬件特性來(lái)實(shí)現(xiàn)虛擬化支持。
1.1 Bao虛擬機(jī)管理器架構(gòu)特性概述
Bao 是一款于2020 年開源發(fā)布的開源靜態(tài)分區(qū)型虛擬機(jī)管理器(Static Partitioning Hypervisor)。其架構(gòu)設(shè)計(jì)核心針對(duì)混合關(guān)鍵性(Mixed-criticality)系統(tǒng),致力于通過(guò)強(qiáng)隔離機(jī)制實(shí)現(xiàn)故障域隔離,并保障系統(tǒng)的實(shí)時(shí)性與功能安全。其實(shí)現(xiàn)僅包含一個(gè)極簡(jiǎn)的、位于特權(quán)級(jí)的軟件層,借助 ISA 虛擬化支持構(gòu)成靜態(tài)分區(qū)型虛擬機(jī)管理器架構(gòu):資源在虛擬機(jī)實(shí)例化(Instantiation)時(shí)完成靜態(tài)物理劃分。內(nèi)存資源通過(guò)兩階段地址轉(zhuǎn)換保護(hù)機(jī)制實(shí)施靜態(tài)分區(qū);I/O 訪問(wèn)遵循純直通架構(gòu);虛擬中斷直接映射到物理中斷;且虛擬 CPU 與物理 CPU 之間維持 1:1 的靜態(tài)綁定,無(wú)需調(diào)度器。Bao沒有外部依賴(例如運(yùn)行在特權(quán) VM中的不可信通用操作系統(tǒng),如 Linux),因此擁有極小的可信計(jì)算基(TCB)。它作為一個(gè)獨(dú)立組件運(yùn)行,僅依賴標(biāo)準(zhǔn)固件來(lái)初始化系統(tǒng)和執(zhí)行平臺(tái)特定任務(wù)(例如電源管理、時(shí)鐘初始化等)。
Bao 最初針對(duì) Armv8-A 體系結(jié)構(gòu)開發(fā),其主線版本目前已支持 32 位與 64 位的 Armv8-A、Armv8-R 以及 RISC-V 架構(gòu)。為進(jìn)一步拓展其在汽車電子領(lǐng)域的應(yīng)用,目前的開發(fā)工作正致力于引入對(duì)瑞薩(Renesas)RH850/U2Axx 以及英飛凌(Infineon)TriCore AURIX TC4x 微控制器系列的支持。為實(shí)現(xiàn)跨平臺(tái)的高效復(fù)用,Bao 在體系結(jié)構(gòu)相關(guān)代碼與體系結(jié)構(gòu)無(wú)關(guān)代碼之間保持了清晰的邏輯解耦。負(fù)責(zé)底層操作的組件(例如寄存器訪問(wèn)、異常處理、外設(shè)和中斷控制器的配置與模擬等)被封裝在架構(gòu)特定模塊中。而核心虛擬機(jī)管理器功能(如共享內(nèi)存管理、Hypercall 接口、虛擬機(jī)生命周期管理、內(nèi)存追蹤等)則在通用的架構(gòu)無(wú)關(guān)層實(shí)現(xiàn),并在所有支持的平臺(tái)間共享。
02
Bao 的配置邏輯
與運(yùn)行基礎(chǔ)
在深入 Bao 與 RH850/U2Axx 架構(gòu)的集成之前,有必要先了解其整體架構(gòu)與上層運(yùn)行方式。本節(jié)概述了 Bao 的配置與初始化流程,涵蓋了虛擬機(jī)如何實(shí)例化、硬件資源如何被分區(qū)、以及系統(tǒng)如何從引導(dǎo)過(guò)渡到完全運(yùn)行狀態(tài)的基本步驟。通過(guò)理解這些基礎(chǔ)知識(shí),讀者將能更好地理解下一節(jié)中 Bao 如何利用 RH850/U2Axx 的虛擬化擴(kuò)展來(lái)實(shí)現(xiàn)架構(gòu)相關(guān)特性的細(xì)節(jié)。
2.1 配置文件
Bao虛擬機(jī)管理器需要用戶提供兩項(xiàng)輸入:(i) 一份虛擬機(jī)管理器配置文件; (ii) 一份或多份客戶機(jī)(Guest)鏡像。配置通過(guò)專用的 C 源文件指定,該文件定義了平臺(tái)的硬件資源(如 CPU 核心、內(nèi)存區(qū)域、設(shè)備和通信通道)如何在虛擬機(jī)間被劃分。在 Bao 中,CPU 核心、內(nèi)存區(qū)域和中斷始終遵循嚴(yán)格的獨(dú)占分配原則,不可共享。針對(duì)特定的硬件設(shè)備與通信資源(如共享內(nèi)存或?qū)S玫奶摂M機(jī)間通信接口),系統(tǒng)允許在受控條件下實(shí)施物理共享,以支撐高效的客戶機(jī)間通信。
#include <config.h>
// Load guests' image
VM_IMAGE(img1_name, "/path/to/vm1/binary.bin");
VM_IMAGE(img2_name, "/path/to/vm2/binary.bin");
struct config config = {
// Shared memory region configuration
.shmemlist_size = N,
.shmemlist = (struct shmem[]) {
[0] = {/*shared memory config*/,},
[1] = {/*shared memory config*/,},
...
[N] = {/*shared memory config*/,}
},
// Guests Configuration
.vmlist_size = NUM_VMs,
.vmlist = {
{ /* VM 0 Config*/},
{ /* VM 1 Config*/},
...
{ /* VM N Config*/},
}
};
Listing 2.1:Bao虛擬機(jī)管理器配置文件框架。
從技術(shù)角度看,Bao的配置文件遵循Listing 2.1所示的框架。配置文件需要一個(gè)名為config的全局變量,類型為struct config,它包含兩個(gè)不同的列表:(i)共享內(nèi)存區(qū)域列表(.shmemlist)和(ii)虛擬機(jī)列表(.vmlist)。共享內(nèi)存列表是可選的,可在配置中省略,但虛擬機(jī)列表為必需,至少要包含一個(gè)虛擬機(jī)的配置。此外,對(duì)每個(gè)列表,都必須使用參數(shù).shmemlist_size和.vmlist_size指定列表大小。
關(guān)于客戶機(jī)鏡像,Bao支持兩種提供VM二進(jìn)制文件的方法:(i)內(nèi)置鏡像和(ii)外部加載鏡像。在第一種情況下,客戶機(jī)鏡像在構(gòu)建時(shí)通過(guò)VM_IMAGE宏嵌入到虛擬機(jī)管理器二進(jìn)制中,如Listing 2.1所示。此方法簡(jiǎn)單方便,但對(duì)大型鏡像或出于性能原因更傾向于使用更快的內(nèi)存區(qū)域的系統(tǒng)可能不理想。在第二種情況下,客戶機(jī)鏡像由外部引導(dǎo)程序或等效機(jī)制在系統(tǒng)啟動(dòng)時(shí)加載。此方法可通過(guò)允許鏡像“就地”使用而無(wú)需額外復(fù)制來(lái)減少啟動(dòng)時(shí)間并優(yōu)化內(nèi)存使用。在基于MPU的系統(tǒng)(如RH850/U2Axx)中,強(qiáng)烈建議采用第二種方法,因?yàn)槿绻麑㈢R像嵌入Bao二進(jìn)制文件中,手動(dòng)為虛擬機(jī)鏡像分配空間可能很困難。
struct vm_config
{
struct
{
vaddr_t base_addr;
paddr_t load_addr;
size_t size;
bool separately_loaded;
bool inplace;
} image;
vaddr_t entry;
cpumap_t cpu_affinity;
colormap_t colors;
struct vm_platform platform;
};
Listing 2.2:VM 配置結(jié)構(gòu)體。
上面提到的VM列表(.vmlist)中的每個(gè)條目都由一個(gè)vm_config結(jié)構(gòu)表示,其定義如Listing 2.2所示。vm_config 結(jié)構(gòu)指定由虛擬機(jī)管理器實(shí)例化的每個(gè)虛擬機(jī)的配置。VM 列表中的每一項(xiàng)對(duì)應(yīng)一個(gè)獨(dú)立的 客戶機(jī)(VM) 配置,定義其鏡像、內(nèi)存布局、CPU 親和性、緩存著色 (Cache Coloring)以及平臺(tái)特定細(xì)節(jié)。對(duì)于每個(gè) 客戶機(jī)(VM),Bao 定義以下參數(shù):
image - 一個(gè)結(jié)構(gòu)體,包含 Bao 用于決定是否加載客戶機(jī)鏡像及加載位置的信息;
entry - 定義客戶機(jī)地址空間中的入口點(diǎn)地址;
cpu_affinity - 對(duì)應(yīng)一個(gè)位圖,表示分配給該 客戶機(jī)(VM) 的首選物理 CPU。如果該值在配置文件中對(duì)所有 客戶機(jī)(VM) 互斥,則每個(gè) 客戶機(jī)(VM) 分配的物理 CPU 按位圖確定。否則,CPU 分配由虛擬機(jī)管理器定義;
colors - 分配給該 客戶機(jī)(VM) 的共享 LLC 緩存顏色(或分區(qū));
platform - 虛擬化平臺(tái)的描述,定義分配給 VM 的物理需求和資源。
struct vm_platform
{
size_t cpu_num;
size_t region_num;
struct vm_mem_region *regions;
size_t ipc_num;
struct ipc *ipcs;
size_t dev_num;
struct vm_dev_region *devs;
bool mmu;
struct arch_vm_platform arch;
}
Listing 2.3:虛擬機(jī)平臺(tái)配置結(jié)構(gòu)體。
客戶機(jī)(VM) 平臺(tái)描述由 vm_platform 結(jié)構(gòu)體表示。該結(jié)構(gòu)體允許用戶定義每個(gè)虛擬平臺(tái)的特性。通過(guò)自定義它,用戶可以根據(jù)虛擬機(jī)的特定工作負(fù)載和應(yīng)用需求調(diào)整虛擬平臺(tái)。如Listing 2.3所示,VM 平臺(tái)配置包括:
cpu_num - 定義分配給虛擬機(jī)的 CPU 數(shù)量;
region_num - 定義分配給虛擬機(jī)的內(nèi)存區(qū)域數(shù)量;
regions - struct vm_mem_region 類型的數(shù)組,按基地址和大小描述分配給VM的所有內(nèi)存區(qū)域;
ipc_num - 定義分配給虛擬機(jī)的 IPC 數(shù)量;
ipcs - struct ipc 類型的數(shù)組,每個(gè)條目對(duì)應(yīng)一個(gè)用于與其他VM通信的IPC元素規(guī)范;
dev_num - 對(duì)應(yīng)分配給 VM 的設(shè)備或外設(shè)數(shù)量;
devs - struct vm_dev_region 類型的數(shù)組,每個(gè)條目對(duì)應(yīng)一個(gè)分配給VM的外設(shè)內(nèi)存區(qū)域規(guī)范;
mmu - 指示是否使用 MMU 作為內(nèi)存保護(hù)機(jī)制;
arch - 允許定義與架構(gòu)相關(guān)的參數(shù)。
2.2 初始化流程
在啟動(dòng)配置文件所定義的客戶機(jī)(VM)之前,Bao 遵循一套確定的結(jié)構(gòu)化初始化流程,旨在構(gòu)建內(nèi)部元數(shù)據(jù)結(jié)構(gòu)并為各執(zhí)行域編排虛擬化運(yùn)行環(huán)境。該初始化過(guò)程分為七個(gè)獨(dú)立階段,最終把客戶機(jī)啟動(dòng)并穩(wěn)定運(yùn)行于虛擬機(jī)管理器之上。各階段包括:(1) 早期啟動(dòng),(2) CPU 初始化,(3) 內(nèi)存初始化,(4) 平臺(tái)初始化,(5) 中斷初始化,(6) VMM 初始化,(7) VM 啟動(dòng)與運(yùn)行。
在以下小節(jié)中,我們概述 Bao 在這些階段的核心初始化流程,重點(diǎn)闡述系統(tǒng)如何從上電復(fù)位過(guò)渡到全量運(yùn)行狀態(tài)。關(guān)于特定體系結(jié)構(gòu)的底層例程及非通用邏輯,將在后續(xù)章節(jié)深入探討。
2.2.1 早期啟動(dòng)
執(zhí)行從底層啟動(dòng)代碼開始,這是一段極簡(jiǎn)的匯編例程,負(fù)責(zé)將 CPU 置于確定的硬件初態(tài)。盡管此階段的實(shí)現(xiàn)具有架構(gòu)依賴性,但其功能邏輯在跨平臺(tái)設(shè)計(jì)中保持高度一致。此階段 Bao 執(zhí)行若干關(guān)鍵操作,包括:
禁用中斷;
指定一個(gè)主 CPU 執(zhí)行關(guān)鍵初始化步驟并管理全局內(nèi)存;
初始化關(guān)鍵寄存器,如控制中斷、異常行為和內(nèi)存保護(hù)的寄存器;
初始化 RAM 和其他關(guān)鍵平臺(tái)級(jí)組件;
在非統(tǒng)一內(nèi)存平臺(tái)(例如 RH850/U2Axx)上將數(shù)據(jù)從閃存復(fù)制到 RAM;
初始化棧。
此外,Bao 保存了指向每 CPU 數(shù)據(jù)結(jié)構(gòu)體的指針,該結(jié)構(gòu)體作為內(nèi)部控制實(shí)體的根節(jié)點(diǎn)。該指針存儲(chǔ)在為此專用的系統(tǒng)寄存器中。該結(jié)構(gòu)體在Bao的初始化和運(yùn)行操作中會(huì)被頻繁訪問(wèn)。完成這些步驟后,Bao 將控制權(quán)將移交至 C 運(yùn)行時(shí)初始化環(huán)境。
2.2.2 CPU 初始化
此階段標(biāo)志著 C 語(yǔ)言環(huán)境初始化的啟動(dòng)。此時(shí),虛擬機(jī)管理器執(zhí)行三項(xiàng)主要任務(wù):
使用啟動(dòng)階段配置的指針初始化主CPU 控制結(jié)構(gòu)體構(gòu)建;
建立核間消息機(jī)制,Bao 使用該機(jī)制在物理核間通信與同步;
與架構(gòu)相關(guān)的 CPU 初始化。對(duì)于 RH850/U2Axx,包括啟動(dòng)從核并配置與異常相關(guān)的寄存器。
2.2.3 內(nèi)存初始化
Bao 的內(nèi)存初始化分為兩個(gè)主要階段。首先,Bao 配置 MPU,以定義并啟用其自身運(yùn)行所需的關(guān)鍵內(nèi)存區(qū)域,包括虛擬機(jī)管理器的代碼和數(shù)據(jù)段,以及早期初始化階段建立的每個(gè)CPU核控制結(jié)構(gòu)體。一旦這些區(qū)域正確配置,Bao 啟用 MPU 以確保對(duì)內(nèi)存的受控訪問(wèn)。關(guān)于虛擬化上下文中 MPU 配置的更多技術(shù)細(xì)節(jié)將在下一節(jié)討論。
在第二階段,Bao建立用于跟蹤和管理虛擬機(jī)管理器與客戶機(jī)(VM)之間物理內(nèi)存分配的元數(shù)據(jù)機(jī)制。為此,它將內(nèi)存組織為頁(yè)面池,每個(gè)頁(yè)面池代表一段連續(xù)的物理內(nèi)存。每個(gè)頁(yè)面池與一個(gè)位圖相關(guān)聯(lián),該位圖跟蹤哪些頁(yè)面是空閑的,哪些已被分配。Bao 維護(hù)著平臺(tái)上所有物理內(nèi)存區(qū)域的頁(yè)面池列表,從而能夠監(jiān)控內(nèi)部及各虛擬分區(qū)的內(nèi)存使用情況。
2.2.4 平臺(tái)初始化
平臺(tái)初始化階段負(fù)責(zé)設(shè)置 Bao 正常運(yùn)行所依賴的硬件組件,尤其在缺少固件初始化的平臺(tái)上。在此階段,Bao配置其自身執(zhí)行以及虛擬化環(huán)境正常運(yùn)行所需的基本平臺(tái)級(jí)子系統(tǒng)。此外,Bao允許開發(fā)者以用戶定義函數(shù)的形式提供可選的自定義平臺(tái)初始化例程,該例程在默認(rèn)初始化序列之后執(zhí)行,以執(zhí)行任何可能需要的平臺(tái)特定設(shè)置。
該階段完全依賴于平臺(tái)。對(duì)于 Renesas RH850/U2Axx 系列,當(dāng)前移植中的默認(rèn)平臺(tái)初始化包括對(duì)外設(shè)總線保護(hù)、模塊待機(jī)、MCU 時(shí)鐘子系統(tǒng)和 I/O 端口的配置。
2.2.5 中斷初始化
中斷初始化階段相對(duì)簡(jiǎn)單,因?yàn)?Bao 僅需一個(gè)中斷來(lái)支持處理器間通信。該中斷用于在核間消息機(jī)制中發(fā)出 IPI 信號(hào)。首先,Bao 執(zhí)行與架構(gòu)相關(guān)的初始化,主要包括映射平臺(tái)中斷控制器。對(duì)于 Renesas RH850/U2Axx 系列,這包括配置外圍總線上的所有中斷控制器以及IPIR。完成此映射后,Bao保留并啟用IPI中斷供自己使用。虛擬機(jī)的中斷分配與配置在下一階段完成。
2.2.6 VMM 初始化
VMM 初始化階段是 Bao 啟動(dòng)過(guò)程中最關(guān)鍵的步驟之一。此時(shí),虛擬機(jī)管理器應(yīng)用用戶配置文件中定義的設(shè)置,并配置架構(gòu)層面的虛擬化控制,為每個(gè)客戶機(jī)(VM)的執(zhí)行做好準(zhǔn)備。
Bao首先配置底層架構(gòu)提供的虛擬化控制項(xiàng),并根據(jù)配置文件中指定的親和性將虛擬CPU分配給物理CPU。如果未定義明確的親和性,Bao會(huì)按順序分配剩余的CPU并為每個(gè)客戶機(jī)(VM)指定一個(gè)主CPU。然后它為所有虛擬機(jī)和 vCPU 的內(nèi)部數(shù)據(jù)結(jié)構(gòu)體保留內(nèi)存并相應(yīng)填充。一旦這些結(jié)構(gòu)體就位,虛擬機(jī)管理器對(duì)每個(gè)虛擬機(jī)和 vCPU 執(zhí)行任何必需的架構(gòu)相關(guān)設(shè)置,并根據(jù)虛擬機(jī)配置和鏡像位置創(chuàng)建每個(gè)虛擬機(jī)的地址空間。最后,Bao 為每個(gè)虛擬機(jī)分配外設(shè)和中斷,并初始化用戶定義的所有共享內(nèi)存區(qū)域,以建立虛擬機(jī)間的通信通道。
2.2.7 虛擬機(jī)啟動(dòng)與運(yùn)行
虛擬機(jī)啟動(dòng)與運(yùn)行階段標(biāo)志著Bao的初始化流程全部完成。此時(shí)所有虛擬機(jī)均已完全配置并準(zhǔn)備就緒;剩下的任務(wù)是將控制權(quán)從虛擬機(jī)管理器交給客戶機(jī)。在此之前,Bao 將所有未分配的物理 CPU,以及被分配給虛擬機(jī)但配置為保持非活動(dòng)的 CPU,按照架構(gòu)定義的機(jī)制置入低功耗掉電模式。然后通過(guò)一段用匯編實(shí)現(xiàn)的簡(jiǎn)短上下文切換例程將執(zhí)行控制交給客戶機(jī)。
由于所有資源在初始化期間已靜態(tài)劃分,Bao 在虛擬機(jī)啟動(dòng)后不執(zhí)行調(diào)度或動(dòng)態(tài)重配置。系統(tǒng)運(yùn)行時(shí)主要由客戶機(jī)在其分配的資源上獨(dú)立執(zhí)行構(gòu)成。Bao 僅在必要時(shí)介入,例如捕獲并模擬客戶機(jī)無(wú)法直接訪問(wèn)的特權(quán)或共享資源訪問(wèn),或注入未中斷直通到客戶機(jī)的中斷。