使用QEMU TCG模拟一个硬件虚拟化环境
本文将介绍如何使用 QEMU TCG 模拟的方式,构建一个支持硬件虚拟化的环境,使得能够在该模拟器环境下启动一个 KVM 虚拟机。
编译最新 QEMU
首先需要下载并编译 QEMU,我们以 x86_64 架构为例,QEMU 选择使用最新版本。
# 下载最新仓库
$ git clone https://git.qemu-project.org/qemu.git
$ cd qemu
# 配置编译目标
$ ./configure --target-list=x86_64-softmmu
# 编译
$ make -j$(nproc)
准备 Linux 内核(选用 6.12.0)
接下来,需要准备 Linux 内核,我这里选用的是 6.12.0 版本。硬件虚拟化技术使用 AMD-V,需要在 menuconfig 中启用 KVM for AMD processor support
。
# 下载 6.12 版本内核
$ wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.12.tar.xz
$ tar -xvf linux-6.12.tar.xz
# 配置选项
$ cd linux-6.12
$ make ARCH=x86_64 defconfig
$ make menuconfig
# Virtualization
# -> Kernel-based Virtual Machine (KVM) support
# -> KVM for AMD processors support
# 编译
$ make -j$(nproc)
注意,在启用指定的 menuconfig 选项时,建议标记为
Y
直接包含进内核中,而非标记为M
以模块形式动态加载。
准备根文件系统(基于 Buildroot)
有了 QEMU 和 Linux 内核,还需要有根文件系统,才能够正常工作。这里我使用的是 Buildroot,只需要简单的配置,它就能够自动化构建一个根文件系统。
# 下载 buildroot
https://buildroot.org/download.html
# 配置选项
$ make menuconfig
# Target options
# -> Target Architecture (i386)
# -> (X) x86_64
# Filesystem images
# -> [*] ext2/3/4 root filesystem
# 编译
$ make -j$(nproc)
Buildroot 构建过程涉及联网下载对应的软件包,如果网络超时的情况,可以 ^c
中断,make clean
后再重新编译。
在 WSL2 环境下构建时,由于 PATH 环境变量包含了 Windows 下的某些软件,因此可能导致无法编译:
Your PATH contains spaces, TABs, and/or newline (\n) characters. This doesn't work. Fix you PATH.
此时可以使用命令
export PATH=$(echo "$PATH" | tr -d ' \t\n')
暂时将 PATH 路径的空格去除,再重新编译。
模拟器启动参数
上述编译都完成后,将得到的内核 bzImage
(位于 arch/x86/boot/bzImage
)和根文件系统 rootfs.ext2
(位于 output/images/rootfs.ext2
)拷贝到同一目录下。
QEMU 启动脚本示例如下所示:
/your_path_of_qemu/build/qemu-system-x86_64 \
-machine q35,accel=tcg \
-cpu EPYC-v4,+svm \
-m 8G \
-smp 4 \
-kernel bzImage \
-append "rootwait root=/dev/vda ro console=ttyS0" \
-drive file=rootfs.ext2,format=raw,id=hd0,if=none \
-device virtio-blk-pci,drive=hd0 \
-nographic \
KVM 虚拟机测试
在完成了虚拟化环境的构建后,便可以开始测试了。这里参考 100 行 C 代码创建一个 KVM 虚拟机,以很少的代码量构建一个最小的 hypervisor。
将 kvm-vmm 和 guest 在本地编译好后放入 rootfs.ext2
中,启动模拟器运行,结果如下图所示:
在该模拟器中运行一个完整的 QEMU/KVM 虚拟机理论也是可行的,但是我使用的 buildroot 生成的根文件系统缺乏 QEMU 运行所需的完整的动态链接库。
静态编译 QEMU 是一种选择,但是也比较繁琐,需要为本机准备大量的静态库,在此没有进行测试。