Linux雲計算底層技術之一文讀懂 Qemu 模擬器

本文首發於我的公眾號 Linux雲計算網路(id: cloud_dev),號內有 10T 書籍和視頻資源,後台回復「1024」即可領取,歡迎大家關注,第一時間掌握技術乾貨!

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);
// 第五步,創建 vCPU 個數的線程並運行虛擬機。
ioctl(kvm->vcpus->vcpu_fd, KVM_RUN, 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 架構同理。

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

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

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

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

Qemu 的使用

1. 源碼下載

centos:sudo apt-get install qemu
ubuntu:sudo yum install qemu -y
安裝包:
$wget http://wiki.qemu-project.org/download/qemu-2.0.0.tar.bz2
$tar xjvf qemu-2.0.0.tar.bz2
Git:
$git clone git://git.qemu-project.org/qemu.git

2. 編譯及安裝

$cd qemu-2.0.0 //如果使用的是git下載的源碼,執行cd qemu
$./configure --enable-kvm --enable-debug --enable-vnc --enable-werror --target-list="x86_64-softmmu"
$make -j8
$sudo make install

configure 腳本用於生成 Makefile,其選項可以用 ./configure --help 查看。

這裡使用到的選項含義如下: - --enable-kvm:編譯 KVM 模塊,使 Qemu 可以利用 KVM 來訪問硬體提供的虛擬化服務。 - --enable-vnc:啟用 VNC。 - --enalbe-werror:編譯時,將所有的警告當作錯誤處理。 - --target-list:選擇目標機器的架構。默認是將所有的架構都編譯,但為了更快的完成編譯,指定需要的架構即可。

安裝好之後,會生成如下應用程序:

  • ivshmem-client/server:這是一個 guest 和 host 共享內存的應用程序,遵循 C/S 的架構。
  • qemu-ga:這是一個不利用網路實現 guest 和 host 之間交互的應用程序(使用 virtio-serial),運行在 guest 中。
  • qemu-io:這是一個執行 Qemu I/O 操作的命令行工具。
  • qemu-system-x86_64:Qemu 的核心應用程序,虛擬機就由它創建的。
  • qemu-img:創建虛擬機鏡像文件的工具,下面有例子說明。
  • qemu-nbd:磁碟掛載工具。

下面通過創建虛擬機操作來對這些工具有個初步的認識。

3. 創建虛擬機

  • 使用qemu-img創建虛擬機鏡像

虛擬機鏡像用來模擬虛擬機的硬碟,在啟動虛擬機之前需要創建鏡像文件。

qemu-img create -f qcow2 test-vm-1.qcow2 10G

-f 選項用於指定鏡像的格式,qcow2 格式是 Qemu 最常用的鏡像格式,採用來寫時複製技術來優化性能。test-vm-1.qcow2 是鏡像文件的名字,10G是鏡像文件大小。鏡像文件創建完成後,可使用 qemu-system-x86 來啟動x86 架構的虛擬機:

  • 使用 qemu-system-x86 來啟動 x86 架構的虛擬機

qemu-system-x86_64 test-vm-1.qcow2

因為 test-vm-1.qcow2 中並未給虛擬機安裝操作系統,所以會提示 「No bootable device」,無可啟動設備。

  • 啟動 VM 安裝操作系統鏡像

qemu-system-x86_64 -m 2048 -enable-kvm test-vm-1.qcow2 -cdrom ./Centos-Desktop-x86_64-20-1.iso

-m 指定虛擬機內存大小,默認單位是 MB, -enable-kvm 使用 KVM 進行加速,-cdrom 添加 fedora 的安裝鏡像。可在彈出的窗口中操作虛擬機,安裝操作系統,安裝完成後重起虛擬機便會從硬碟 ( test-vm-1.qcow2 ) 啟動。之後再啟動虛擬機只需要執行:

qemu-system-x86_64 -m 2048 -enable-kvm test-vm-1.qcow2

qemu-img 支持非常多種的文件格式,可以通過 qemu-img -h 查看 其中 raw 和 qcow2 是比較常用的兩種,raw 是 qemu-img 命令默認的,qcow2 是 qemu 目前推薦的鏡像格式,是功能最多的格式。這些知識後面會有文章來專門講述。

這篇文章寫得有點長,可能是 Qemu 唯一一篇文章,這並不是說 Qemu 不重要,而是我們平時在使用過程中主要把它當工具用,遇到不懂的查就行了,當然,如果你覺得看代碼爽一點,非常鼓勵,如果看了有什麼心得,我們可以一起交流交流。好了,老鐵們,看在我深夜一點還在寫乾貨給你們,就給我點個贊吧。


公眾號後台回復「加群」,帶你進入高手如雲交流群

我的公眾號 Linux雲計算網路(id: cloud_dev) ,號內有 10T 書籍和視頻資源,後台回復 「1024」 即可領取,分享的內容包括但不限於 Linux、網路、雲計算虛擬化、容器Docker、OpenStack、Kubernetes、工具、SDN、OVS、DPDK、Go、Python、C/C++編程技術等內容,歡迎大家關注。


推薦閱讀:

在qemu中模擬設備
NVMe 用戶空間驅動(二):實現1
QEMU虛擬機編譯使用實踐
QEMU虛擬機中如何安裝Virtio驅動

TAG:雲計算 | 虛擬化 | QEMU |