背景
在現(xiàn)代嵌入式應(yīng)用場景中,嵌入式系統(tǒng)正進行著向通用系統(tǒng)和混合關(guān)鍵系統(tǒng)的方向發(fā)展的演變。越來越多的功能被集成,這些任務(wù)往往有著不同的可靠性、實時性的要求,同時又有著將不同關(guān)鍵任務(wù)進行相互隔離的需求。一個典型的例子是車載系統(tǒng)必須確保那些影響汽車安全行駛的組件,不會受到車載娛樂系統(tǒng)崩潰的影響,而這兩者也有著不同的要求與驗證等級。近年來,伴隨著具有多核處理器架構(gòu)的嵌入式計算平臺的產(chǎn)生與發(fā)展,在單一片上系統(tǒng)(SoC)上部署多個復(fù)雜任務(wù)成為可能。但受限于多核處理器硬件設(shè)計的特殊性,傳統(tǒng)操作系統(tǒng)很難做到在將多任務(wù)進行隔離的前提下,還能充分利用片上系統(tǒng)多核優(yōu)勢的要求。同時考慮到嵌入式應(yīng)用領(lǐng)域需求的多樣性,單一的軟件系統(tǒng)可能很難進行多場景下的需求適配。一種可行的解決方案是,由不同的操作系統(tǒng)各自負責(zé)其擅長的領(lǐng)域,并執(zhí)行相應(yīng)的關(guān)鍵任務(wù),而由一個虛擬機監(jiān)控程序來對這些客戶操作系統(tǒng)(Guest OS)進行監(jiān)管。虛擬化技術(shù)給這種技術(shù)設(shè)計提供了便利。使用硬件平臺提供的虛擬化技術(shù)(如 x86 的(非)根模式 [(Non-)Root Mode] 與 VMX 指令集),可以做到為不同的 Guest OS 分配不同的虛擬設(shè)備資源(如 CPU 與內(nèi)存等),它們與實際物理設(shè)備構(gòu)成映射關(guān)系,但彼此之間相互隔離。此項目面向支持 H 拓展的 64 位 RISC-V 指令集平臺,基于 Rust 語言實現(xiàn)了一個 Type-1 型虛擬機監(jiān)控平臺,其具備運行并管理多個相互隔離的 Guest OS 的能力。
Rust-Shyper (RISC-V) 框架設(shè)計
此項目從 Rust-Shyper (Armv8) 移植,并針對 RISC-V 所支持的虛擬化拓展指令進行特化。項目還包含了管理虛擬機(MVM)中用戶態(tài)的 CLI 工具、用戶態(tài)守護進程(Daemon)以及內(nèi)核模塊,整體框架如下圖所示。Rust-Shyper 提供了下列功能:
- 對系統(tǒng)所有關(guān)鍵資源和狀態(tài)進行統(tǒng)一管理和隔離
- 提供一套完整的核間通信機制
- 提供多種設(shè)備模擬策略,能夠為 VM 提供虛擬磁盤、虛擬網(wǎng)卡等 Virt I/O 模擬設(shè)備
- 為 VM 模擬 SBI 接口,使之能夠使用原有 M 模式下的底層接口
設(shè)備模擬與 Virt I/O 虛擬化
Rust-Shyper 提供的設(shè)備模擬策略包括全直通、全模擬、半模擬三種:全直通的物理設(shè)備由某個虛擬機獨占,全模擬由 Rust-Shyper 捕獲并模擬對設(shè)備的一切操作,半模擬由 Rust-Shyper 捕獲設(shè)備操作,并借助物理設(shè)備進行訪問行為的模擬。對于被模擬的設(shè)備,客戶機按照傳輸協(xié)議,讀寫設(shè)備的特定地址,此時會觸發(fā)客戶頁缺失異常(Load / Store guest-page fault),Rust-Shyper 捕獲并解析這些異常,并根據(jù)設(shè)備種類進行不同方式的設(shè)備模擬,流程如下圖所示。Rust-Shyper 中的半模擬設(shè)備以磁盤模擬為例,為了充分利用 Linux 中較為成熟的原生驅(qū)動,并提高 Rust-Shyper 的性能與可移植性,Rust-Shyper 可以將 GVM 中的 IO 請求轉(zhuǎn)發(fā)給 MVM 中的內(nèi)核模塊,并利用 MVM 中的原生驅(qū)動完成設(shè)備的讀寫。
Rust-Shyper 同時實現(xiàn)了一個虛擬交換機,客戶操作系統(tǒng)所裝載的 virtio-net 虛擬網(wǎng)卡將連接到 Rust-Shyper 中的虛擬交換機,后者將按照規(guī)則將網(wǎng)絡(luò)包轉(zhuǎn)發(fā)到物理網(wǎng)卡中。對于模擬設(shè)備,我們會為 VM 創(chuàng)建模擬設(shè)備的設(shè)備樹項目,使其能夠感知到模擬設(shè)備的存在。
在不使用 AIA 拓展時,RISC-V 的中斷分發(fā)需要設(shè)置在發(fā)生中斷時陷入到 Rust-Shyper 中,從 PLIC 中獲取外部中斷號,然后將中斷分發(fā)給對應(yīng)虛擬機,下圖黑色實線展示了外部中斷發(fā)生時的一般流程。但頻繁的 VM-Exit 會帶來一定的性能問題,尤其是應(yīng)對 PCI 高速設(shè)備的中斷時。在引入 AIA 拓展后,可以由 APLIC 以寫 Interrupt File 的形式向?qū)?yīng)的特權(quán)級或者 VM 注入中斷,直通設(shè)備的中斷可以直達 VM 而無需陷入 Rust-Shyper,由此提高了 VM 的中斷處理性能。如下圖彩色實線所示。
此外,除了 APLIC 可以往 Interrupt File 中直接注入中斷外,未來的實現(xiàn)會允許 PCI 設(shè)備通過 MSI 信號直接注入中斷,避免其陷入 Hypervisor。
[!NOTE] Rust-Shyper 對 Sstc 與 Svnapot 拓展的支持 RISC-V Sstc 拓展提供了 VS 模式下的計時器,使得 GVM 不需要陷入更高特權(quán)級或者進行 SBI 調(diào)用也可以設(shè)置計時器并產(chǎn)生中斷;Svnapot 拓展使得頁表可以支持高達 64 KiB 的頁面,從而降低高內(nèi)存負載下 TLB 的壓力。Rust-Shyper 已經(jīng)實現(xiàn)了對這兩個拓展的支持,但尚未進行完備的測試。
Rust-Shyper 使用指南
從倉庫^1中下載源碼后,安裝下列軟件依賴:
Rust Nightly
riscv64-linux-gnu-gcc 交叉編譯工具鏈
cargo-binutils (Optional)
qemu-system-riscv64 >= 8.2.0
然后進入 cli 目錄編譯用戶態(tài)運行的 Rust-Shyper CLI,并從 tools 目錄中獲取編譯好的內(nèi)核模塊。它們均需要打包進 MVM 的鏡像中。
MVM 的配置
MVM 是用于對其他虛擬機進行管理的管理 VM,運行 Linux,可以通過內(nèi)核模塊和用戶態(tài)命令行工具(CLI)與 Rust-Shyper 通信,以此完成管理 VM 的任務(wù)。
倉庫中提供了 5.15 版本內(nèi)核的鏡像:image/Image_5.15.100-riscv-starfive,具有較為完整的功能(開啟了大部分常用的內(nèi)核選項)和兼容性。
可以Ubuntu base image為基礎(chǔ),構(gòu)建本項目使用的 Linux rootfs,或者可以使用已經(jīng)配置好的鏡像 [^2]。該鏡像的用戶名與密碼均為 root.
[!NOTE] 關(guān)于 Ubuntu 對 RISC-V 的支持與鏡像構(gòu)建 要了解更多關(guān)于 Ubuntu 對 RISC-V 的支持,參見https://ubuntu.com/download/risc-v;Ubuntu base image 是一個很小的 Linux rootfs,支持 apt 安裝程序,并自帶基本的 gnu 命令行工具,可供用戶從零構(gòu)建包含完整軟件包 rootfs,可參見Ubuntu Base官方。
對 MVM 的配置詳見倉庫 src/config/qemu_riscv64_def.rs,該文件配置了 MVM 的模擬設(shè)備、直通設(shè)備、中間物理內(nèi)存(IPA)起始地址與大小、內(nèi)核啟動參數(shù)、內(nèi)核加載地址、CPU 數(shù)目等等。這部分并非完全固定,可以根據(jù)自己的需求在一定范圍內(nèi)做動態(tài)的更改。
Rust-Shyper 的啟動
使用下列命令編譯并連接 RISC-V 版本的 Rust-Shyper:
ARCH=riscv64 make
使用下列命令運行:
ARCH=riscv64 make run
GVM 的啟動與配置Step.1 安裝內(nèi)核模塊
insmod shyper_riscv64.ko
Step.2 啟動 Rust-Shyper 守護進程
chmod +x shyper./shyper system daemon [mediated-cfg.json] &
mediated-cfg.json(本目錄下存在的 shypercli-config.json 就是一個參考)用于配置其他 Guest VM 的 Virt I/O 中介磁盤,示例如下:
{ "mediated": [ "/root/vm0_ubuntu.img", // 此處配置第1個GVM的中介磁盤 "/root/vm0_ubuntu_2.img", // 此處配置第2個VM的中介磁盤 "/root/vm0_busybox.img" // 此處配置第3個VM的中介磁盤 ]}
其中列表每一項既可以寫分區(qū)名(如/dev/sda1),又可以寫磁盤鏡像名。
Step.3 通過配置文件來配置GVM
./shyper vm config
本目錄下(./vm1_config_riscv.json)提供了配置文件的示例(鏈接中的 Step 3)。
Step.4 啟動客戶虛擬機
./shyper vm boot
按照啟動的順序排序。MVM 的 VMID 為 0,第一個啟動的 GVM 的 VMID 為 1,可以通過./shyper vm list 查看當(dāng)前配置的各個VM的信息。
Step.5 與客戶虛擬機交互
首先從外部連接到 MVM:
ssh root@localhost -p 5555
然后通過 minicom 連接 hvc1,監(jiān)控 GVM 的串口輸出:
minicom -D /dev/hvc1 -b 115200
這樣便可以與 GVM 交互了:
本項目鏡像中帶有的GVM鏡像vm0_ubuntu.img,其用戶名為root,密碼為vm1.
通過 AIA 啟動 Rust-Shyper
需要將 qemu-system-riscv64 升級到 9.0.2,并使用支持 AIA 的內(nèi)核版本(如 6.10)。并使用配置好的支持 AIA 啟動的鏡像 [^3]。
使用如下命令編譯使用 AIA 的 RISC-V 版本的 Rust-Shyper:
ARCH=riscv64 IRQ=aia AIA_GUESTS=3 make
并使用如下命令運行:
ARCH=riscv64 IRQ=aia AIA_GUESTS=3 make run
IRQ=[plic|aia]:選擇中斷的方式,當(dāng)沒有輸入該參數(shù)時,默認(rèn)是plic AIA_GUESTS=nnn:需要為每個 HART 模擬的 interrupt file 的數(shù)量,也是將要運行 VM 的數(shù)量,當(dāng)沒有輸入該參數(shù)時,默認(rèn)是 3
啟動GVM時的配置
鏡像中提供的配置示例(./vm1_config_riscv_aia.json),相較于 PLIC,需要將模擬中斷的設(shè)備替換為APLIC:
{ "name": "aplic@d000000", "base_ipa": "0xd000000", "length": "0x8000", "cfg_num": 2, "cfg_list": [ 0, 0 ], "type": "EMU_DEVICE_T_APLIC"},
VM 多核啟動時,關(guān)于 IMSIC 的地址映射
由于在多核啟動時,會向不同的 Hart 中寫 IPI 中斷號,但由于 GuestOS 不認(rèn)為自己處于虛擬化模式下,會訪問每個 Hart 的 S-mode 的 Interrupt File,所以需要建立地址映射,以便可以找到正確的 Guest Interrupt File.
若當(dāng)前hart的分配情況為:
MVM:Hart0
GVM:Hart1、2、3
GVM:Hart2、3
由于 MVM 是單核啟動,所以無需建立地址映射。GVM1 應(yīng)建立以下映射:
由于使用的是 Hart1、2、3,其正確的 Guest Interrupt File 地址應(yīng)為0x28006000、0x2800a000、0x2800e000,但 VM 會認(rèn)為自己的所用的是 Hart0、1、2,他會訪問的地址是0x28000000、0x28004000、0x28008000,所以應(yīng)建立以下映射關(guān)系,VM 才會正確訪問到對應(yīng)的 Interrupt File
"passthrough_device": { "passthrough_device_list": [ { "base_ipa": "0x28000000", "base_pa": "0x28006000", "length": "0x1000" }, { "base_ipa": "0x28004000", "base_pa": "0x2800a000", "length": "0x1000" }, { "base_ipa": "0x28008000", "base_pa": "0x2800e000", "length": "0x1000" } ]},
相應(yīng)的,GVM2 應(yīng)該映射如下:
"passthrough_device": { "passthrough_device_list": [ { "base_ipa": "0x28000000", "base_pa": "0x28006000", "length": "0x1000" }, { "base_ipa": "0x28004000", "base_pa": "0x2800a000", "length": "0x1000" }, { "base_ipa": "0x28008000", "base_pa": "0x2800e000", "length": "0x1000" } ]},
-
嵌入式
+關(guān)注
關(guān)注
5082文章
19118瀏覽量
305102 -
操作系統(tǒng)
+關(guān)注
關(guān)注
37文章
6818瀏覽量
123326 -
RISC-V
+關(guān)注
關(guān)注
45文章
2277瀏覽量
46156
發(fā)布評論請先 登錄
相關(guān)推薦
評論