rust 基於 kvm 實現虛擬機
之前寫過用 rust 實現一個虛擬機的文章 (收藏,用 rust 實現一個迷你虛擬機,模擬 CPU 執行指令),該虛擬機是基於代碼解釋執行的,效率較低。評論區大神告知目前主流的實現方案是基於 kvm(Kernel-based Virtual Machine) 的,直接由系統調度,性能強悍,並且在 github 上開源了一個 kvmsample 例程。
https://github.com/BillXiang/kvmsample<
向大佬致敬:)
本回就來學一學關於 kvm 虛擬化相關的知識 (歡迎各路大神補充)
虛擬化技術的發展史
1961 年,IBM709 機器實現了分時系統,自此首個虛擬化技術誕生。IBM709 將 CPU 執行切分爲極短的時間片,每個時間片都可以用來調度不同的任務,通過時間片的輪詢,將一個 CPU 虛擬化爲多個 CPU,讓任務看起來像是同時在運行。分時系統可以說是虛擬化的雛形。
隨着軟硬件的發展,計算機各層從下往上都出現了虛擬化的應用,所謂虛擬化可以理解爲抽象或約定,抽象即標準,不同的參與方只要按約定提供標準的接口即能成功接入。
每一層的實現只需要知道下一層提供的接口而不需要知道具體的實現。目前廣爲人知的不同層之間的虛擬化技術如下:
KVM虛擬化原理
KVM 是 linux 內核中的一個虛擬特徵,它允許 qemu 這樣的用戶態程序直接在宿主機的 CPU 上安全地執行虛擬機系統代碼。
下面是運行不同虛擬機的宿主機:
KVM 通過 "軟件僞造" 的方式,實現虛擬的內存和 CPU(需要硬件支持虛擬化操作),並將其映射到真實的內存和 CPU 上。客戶端代碼運行於虛擬的內存和 CPU 中。(虛擬機內的程序的地址通過虛擬機的頁表映射到虛擬機的虛擬地址,虛擬地址經過 VMM 的頁表映射到真實的物理地址;虛擬 CPU 映射到系統線程,系統線程由系統調度)。客戶端通過 / dev/kvm 設備發起 ioctl 系統調用創建虛擬內存、虛擬 CPU 並運行虛擬機。
基本流程可以用如下的僞代碼表示:
// 打開dev/kvm設備
open(/dev/kvm)
// 創建虛擬機
ioctl(KVM_CREATE_VM)
// 創建虛擬CPU
IOCTL(KVM_CREATE_VCPU)
loop{
// 運行虛擬機
ioctl(KVM_RUN)
// Exit虛擬機(內核態到用戶態)
switch(exit_code){
case KVM_EXIT_IO:XXX,
case KVM_EXIT_HLT:xxxx
}
}
運行Rust編寫的KVM虛擬機
代碼需要在 Linux 系統中運行並且需要確保 CPU 支持虛擬化並開啓虛擬化功能,windows 中可以在任務管理器 -> 性能中查看是否開啓:
在 windows 中安裝虛擬機,需要確保打開了虛擬機的嵌套虛擬化功能,以 virtualbox 爲例,它創建的虛擬機默認是關閉嵌套虛擬化的,需要使用命令來打開:
以管理員權限打開 cmd,到 virtulbox 安裝目錄,運行下面的命令打開嵌套虛擬化功能:
# step1 列出所有安裝的虛擬機
./VBoxManage.exe list vms
# step2 打開嵌套虛擬化
./VBoxManage.exe modifyvm "改爲你需要打開的虛擬機的名稱" --nested-hw-virt on
運行成功後,可以看到選項可以勾選了:
下載源碼並按如下指令執行:
cd kvmsample
make
cp test*.bin kvmsample-rust
cd kvmsample-rust
cargo run
源碼分析
查看源代碼,其實和上述列出的僞代碼執行邏輯是相似的:
-
打開 / dev/kvm 設備完成初始化
-
創建虛擬機對象,返回虛擬機文件描述符和虛擬內存開始地址
-
把需要運行的程序打包成 ELF 格式的二進制文件並加載到 kvm 虛擬內存的初始地址處
-
創建虛擬 CPU
-
調用虛擬機的 run 方法開始運行,當遇到特殊的事件 (訪問設備寄存器、停止 CPU 等操作),虛擬機將 Exit 到用戶態並帶一個退出碼,通過匹配退出碼便可以得到相關的模擬輸出數據。
帶註釋版本的代碼我已上傳 Github,點擊 https://github.com/reganzm/hug_rust 即可跳轉,如有錯誤還請指正!(個人能力有限,涉及到的底層知識較多,感興趣的同學可以一起註釋共建這個庫)
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/UamJ1mOFc8GjyPWTeibgsw