Qemu 架構

Qemu 是純軟件實現的虛擬化模擬器,幾乎可以模擬任何硬件設備,我們最熟悉的就是能夠模擬一臺能夠獨立運行操作系統的虛擬機,虛擬機認為自己和硬件打交道,但其實是和 Qemu 模擬出來的硬件打交道,Qemu 將這些指令轉譯給真正的硬件。

正因為 Qemu 是純軟件實現的,所有的指令都要經 Qemu 過一手,性能非常低,所以,在生產環境中,大多數的做法都是配合 KVM 來完成虛擬化工作,因為 KVM 是硬件輔助的虛擬化技術,主要負責 比較繁瑣的 CPU 和內存虛擬化,而 Qemu 則負責 I/O 虛擬化,兩者合作各自發揮自身的優勢,相得益彰。

Qemu 架構

從本質上看,虛擬出的每個虛擬機對應 host 上的一個 Qemu 進程,而虛擬機的執行線程(如 CPU 線程、I/O 線程等)對應 Qemu 進程的一個線程。下面通過一個虛擬機啟動過程看看 Qemu 是如何與 KVM 交互的。

// 第一步,獲取到 KVM 句柄

kvmfd = open("/dev/kvm", O_RDWR);

// 第二步,創建虛擬機,獲取到虛擬機句柄。

vmfd = ioctl(kvmfd, KVM_CREATE_VM, 0);

// 第三步,為虛擬機映射內存,還有其他的 PCI,信號處理的初始化。

ioctl(kvmfd, KVM_SET_USER_MEMORY_REGION, &mem);

// 第四步,將虛擬機鏡像映射到內存,相當於物理機的 boot 過程,把鏡像映射到內存。

// 第五步,創建 vCPU,併為 vCPU 分配內存空間。

ioctl(kvmfd, KVM_CREATE_VCPU, vcpuid);
vcpu->kvm_run_mmap_size = ioctl(kvm->dev_fd, KVM_GET_VCPU_MMAP_SIZE, 0);

// 第六步,線程進入循環,並捕獲虛擬機退出原因,做相應的處理。

for (;;) {
ioctl(KVM_RUN)
switch (exit_reason) {
case KVM_EXIT_IO: /* ... */
case KVM_EXIT_HLT: /* ... */
}
}
// 這裡的退出並不一定是虛擬機關機,
// 虛擬機如果遇到 I/O 操作,訪問硬件設備,缺頁中斷等都會退出執行,
// 退出執行可以理解為將 CPU 執行上下文返回到 Qemu。

Qemu 源碼結構

Qemu 軟件虛擬化實現的思路是採用二進制指令翻譯技術,主要是提取 guest 代碼,然後將其翻譯成 TCG 中間代碼,最後再將中間代碼翻譯成 host 指定架構的代碼,如 x86 體系就翻譯成其支持的代碼形式,ARM 架構同理。

Qemu 架構

所以,從宏觀上看,源碼結構主要包含以下幾個部分:

  • /vl.c:最主要的模擬循環,虛擬機環境初始化,和 CPU 的執行。
  • /target-arch/translate.c:將 guest 代碼翻譯成不同架構的 TCG 操作碼。
  • /tcg/tcg.c:主要的 TCG 代碼。
  • /tcg/arch/tcg-target.c:將 TCG 代碼轉化生成主機代碼。
  • /cpu-exec.c:主要尋找下一個二進制翻譯代碼塊,如果沒有找到就請求得到下一個代碼塊,並且操作生成的代碼塊。

其中,涉及的主要幾個函數如下:

Qemu 架構

知道了這個總體的代碼結構,再去具體瞭解每一個模塊可能會相對容易一點。


分享到:


相關文章: