ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

QEMU虚拟机实战:从x86到ARM64与RISC-V的跨架构模拟

QEMU虚拟机实战:从x86到ARM64与RISC-V的跨架构模拟 QEMU 是一个开源虚拟化项目既能在一台 x86 电脑上模拟出另一台 x86 虚拟机也能直接运行 ARM、RISC-V 等异构架构的系统镜像还能作为普通虚拟机管理程序启动 Linux、Windows 以及麒麟 V10、统信 UOS 等国产操作系统。这篇文章从 QEMU 的两个核心工作模式讲起先说明它为什么能做到跨架构再给出 Linux 和 Windows 环境的安装方式然后分别用最小命令跑通 x86、ARM64、RISC-V 三种架构的虚拟机接着分析网络、磁盘和显示设备的工程化配置最后整理常见的启动报错、排查顺序和生产环境建议。阅读这篇文章不需要太多前置知识只要会用基础 Linux 命令行就能跟着操作完成一个可运行的 QEMU 虚拟机。1. 先理解 QEMU 的工作模式、加速器和多架构原理QEMU 的定位不是单一的“虚拟机软件”而是一套能够模拟 CPU、内存、外设和整机硬件的工具集。只有理解了它的工作模式后面调试参数时才不会盲目试错。1.1 全系统模拟与用户态模拟QEMU 有两种主要工作模式。第一种是全系统模拟System Emulation。它负责模拟出一台完整机器包括 CPU、内存、磁盘控制器、网卡、显示适配器和 BIOS/UEFI 固件。虚拟机内部的操作系统认为自己运行在真实硬件上实际上所有指令都会经过 QEMU 的翻译或加速器处理后执行。日常使用的qemu-system-x86_64、qemu-system-aarch64、qemu-system-riscv64都属于这个模式。第二种是用户态模拟User-mode Emulation。这个模式只模拟 CPU 指令集不模拟整机硬件适用于在 x86 主机上直接运行 ARM 或 RISC-V 编译出来的单个可执行文件。典型命令是qemu-aarch64、qemu-riscv64。在嵌入式交叉编译和 CI 测试场景中用户态模拟常被用来快速验证某个二进制文件能否在当前架构上运行但它不能启动完整操作系统。本文后面讲的都是全系统模拟因为它的使用场景更广也是很多人接触 QEMU 时的第一需求。1.2 TCG、KVM、WHXP 与硬件加速的关系QEMU 默认使用 TCGTiny Code Generator做动态二进制翻译。它会把目标架构的指令翻译成宿主机 CPU 可以执行的指令所以 x86 主机能够模拟 ARM、RISC-V 甚至 MIPS。TCG 的优势是跨架构能力强代价是性能远低于本机执行。如果宿主机和虚拟机架构一致并且宿主机提供了硬件虚拟化能力就可以绕过 TCG 使用“加速器”。Linux 下最常见的是 KVM对应参数是-accel kvm。Windows 下常见的是 WHPXWindows Hypervisor Platform对应参数是-accel whpx。macOS 下可以使用 Hypervisor.framework对应参数是-accel hvf。判断是否真的用上了加速器可以在 QEMU 启动命令里加-accel help查看当前环境支持的加速方式也可以看启动日志中的-accel kvm是否成功启用。很多新手遇到“虚拟机极慢”的问题根本原因就是 TCG 模式在纯软件翻译而不是硬件加速。加速器所属平台适用场景启动参数示例KVMLinuxx86 宿主运行 x86 虚拟机性能接近原生-accel kvmWHPXWindows 10/11x86 宿主运行 x86 虚拟机-accel whpxHVFmacOSx86 宿主运行 x86 虚拟机-accel hvfTCG所有平台跨架构模拟如 x86 上跑 ARM、RISC-V不写加速参数或-accel tcg1.3 QEMU 为什么能同时支持 x86、ARM、RISC-VQEMU 把“机器模型”与“CPU 型号”拆开管理。机器模型决定主板上有什么设备例如 ARM 的-M virt是一套虚拟化友好设备集合RISC-V 的-M virt也是一套标准虚拟设备集合。CPU 型号决定指令集特性例如 ARM 可以使用-cpu cortex-a57、-cpu neoverse-n1x86 可以使用-cpu host或-cpu max。因此一套 QEMU 二进制程序可以对应多个目标架构。Debian/Ubuntu 的qemu-system元包会同时安装多个架构的系统模拟器启动命令也会从qemu-system-x86_64、qemu-system-aarch64、qemu-system-riscv64等不同入口进入。理解这种分层设计后就不会把“模拟器”和“某个架构”绑定死。2. 环境准备依赖、安装与基础校验QEMU 在主流操作系统上都有安装方式。下面按 Linux 和 Windows 分别给出命令然后在 2.4 节统一做版本和加速能力校验。2.1 Debian/Ubuntu 系列安装Debian/Ubuntu 可以直接使用软件源安装。推荐安装qemu-system和qemu-utils前者提供全系统模拟器后者提供qemu-img等镜像管理工具。sudo apt update sudo apt install qemu-system qemu-utils如果只想安装某个架构的模拟器可以精确安装子包sudo apt install qemu-system-x86 qemu-system-arm qemu-system-aarch64 qemu-system-riscv64安装完成后先确认命令存在which qemu-system-x86_64 qemu-system-x86_64 --version2.2 CentOS/RHEL/Fedora 系列安装在 Fedora 上可以直接用 dnf 安装sudo dnf install qemu-system-x86-core qemu-system-aarch64 qemu-system-riscv qemu-imgCentOS Stream 或 RHEL 使用 yum 时包名可能稍有差异。如果源里没有 aarch64 或 riscv 子包至少先安装主包再通过模块源补齐。原项目或发行版文档没有明确指定版本时落地前最好先执行一次dnf info qemu-system-*确认可用的包名称。2.3 Windows 环境安装Windows 下安装 QEMU 的方式是从官方发布页下载对应 Windows 的压缩包解压后把包含qemu-system-x86_64.exe的目录添加到系统 PATH 环境变量。这里不建议把安装文件放到带空格或中文的路径下避免后续脚本拼接命令时出现路径解析问题。安装完成后打开新的 PowerShell 或 CMD 窗口验证qemu-system-x86_64.exe --version如果命令找不到检查是否在环境变量 PATH 中正确添加了 QEMU 的 bin 目录并重新打开终端。2.4 版本与加速状态校验清单在开始创建虚拟机之前建议花两分钟做一次环境检查把问题和依赖项提前暴露出来。检查项Linux 方法Windows 方法基础命令可用qemu-system-x86_64 --version同上多架构模拟器存在ls /usr/bin/qemu-system-*dir QEMU安装目录KVM 设备存在ls -l /dev/kvm不适用WHPX 是否启用不适用systeminfo查看 Hyper-V 相关选项镜像工具可用qemu-img --versionqemu-img.exe --version注意不要只验证“命令能输出版本号”就认为环境正常。跨架构虚拟机对 CPU、内存和固件文件的要求更高后面每一次启动命令都值得单独验证。3. 在 x86 主机上跑通 Linux 虚拟机这一节用一个最小可运行场景打通从创建磁盘、启动安装到进入系统的完整链路后续所有复杂参数都可以基于这条命令理解。3.1 创建磁盘镜像先用qemu-img创建一块精简分配的 qcow2 格式虚拟磁盘。qcow2 的特点是写多少占多少宿主机空间同时支持快照和压缩。qemu-img create -f qcow2 disk.qcow2 40G创建完成后查看磁盘信息qemu-img info disk.qcow2正常输出中virtual size是 40 GiBdisk size很小说明还没有实际写入大量数据。这里不要把虚拟磁盘大小设置过小Linux 桌面系统建议至少 40GB服务器系统可以 20GB 到 30GB。3.2 从 ISO 启动安装准备好一个 Linux ISO例如 Ubuntu Desktop 或 Debian 的安装镜像然后用下面的命令启动虚拟机。qemu-system-x86_64 \ -m 4096 \ -smp 4 \ -accel kvm \ -drive filedisk.qcow2,formatqcow2,ifvirtio \ -cdrom /path/to/your-linux.iso \ -boot d \ -nic user,modelvirtio-net-pci \ -display gtk启动后 QEMU 会打开图形窗口虚拟机从光驱引导进入 ISO 安装界面。按正常 Linux 安装流程分区、设置用户、完成安装即可。安装完成后去掉-cdrom和-boot d再次启动就能进入磁盘系统。qemu-system-x86_64 \ -m 4096 \ -smp 4 \ -accel kvm \ -drive filedisk.qcow2,formatqcow2,ifvirtio \ -nic user,modelvirtio-net-pci \ -display gtk3.3 常用启动参数拆解很多初学者觉得 QEMU 命令难记是因为没有拆解参数。每个参数的意义如下表所示。参数作用常见值说明-m 4096分配内存单位 MB2048、4096、8192内存不足会导致系统卡死或 OOM-smp 4分配 CPU 核心数2、4、8不要超过宿主机物理核数-accel kvm启用硬件加速kvm、whpx、hvf、tcg架构一致时优先硬件加速-drive filedisk.qcow2,formatqcow2,ifvirtio指定磁盘文件可加cachewritebackifvirtio性能更好-cdrom xxx.iso挂载光驱实际 ISO 路径安装完成后建议移除-boot d指定引导顺序d 表示光驱c 表示磁盘安装后改为磁盘引导-nic user,modelvirtio-net-pci配置用户态网络可改用桥接网络默认网关为 10.0.2.2-display gtk图形显示前端gtk、sdl、none、vnc无桌面环境要用 vnc在 QEMU 的用户态网络模式下虚拟机内部的默认网段通常是 10.0.2.0/24虚拟机自己通常拿到的 IP 是 10.0.2.15网关是 10.0.2.2。这个地址在网络排错时经常被提到因此单独说明一下。3.4 运行国产操作系统时的常见注意点在 x86 虚拟机中安装麒麟 V10、统信 UOS 等国产操作系统命令结构与普通 Linux 基本一致但有几个细节容易出问题。第一引导固件。部分国产系统镜像要求 UEFI 启动而 QEMU 默认是 SeaBIOS 传统引导。此时需要加-bios /usr/share/OVMF/OVMF_CODE.fd或使用对应的 UEFI 固件参数。第二显示设备。某些系统桌面环境需要特定显示驱动如果默认 VGA 花屏可以尝试-vga virtio或-device virtio-vga。第三磁盘控制器。老版本系统可能缺少 virtio 驱动此时可以把ifvirtio改成ifide先保证能安装进系统再补驱动。这些步骤不复杂但需要在安装前确认系统镜像的引导方式是 UEFI 还是 legacy。判断错误时最常见的现象就是启动后黑屏或停在 GRUB 加载阶段。4. 跨架构模拟在 x86 主机上运行 ARM64 与 RISC-VQEMU 的跨架构能力是它的重要卖点。在嵌入式开发、ARM 服务器软件适配和 RISC-V 实验场景中经常需要在 x86 开发机上启动其他架构的完整系统。4.1 在 x86 主机上跑一个 ARM64 虚拟机先确认qemu-system-aarch64是否已安装which qemu-system-aarch64ARM64 虚拟机需要选择合适的机器模型和固件。最常用的是-M virt它是一套为虚拟化优化的设备模型配合 UEFI 固件使用。qemu-system-aarch64 \ -M virt \ -cpu cortex-a57 \ -m 4096 \ -smp 4 \ -accel tcg,threadmulti \ -bios /path/to/QEMU_EFI.fd \ -drive filearm64-disk.qcow2,formatqcow2,ifvirtio \ -cdrom /path/to/arm64.iso \ -nic user,modelvirtio-net-pci \ -serial mon:stdio这里的关键点是-cpu cortex-a57指定 ARM CPU 型号-M virt指定虚拟机器模型。如果缺少-bios很多 ARM64 镜像无法启动因为它没有可用的固件入口。不同发行版提供的QEMU_EFI.fd路径不同落地前要通过find / -name QEMU_EFI.fd 2/dev/null确认实际路径。由于 x86 宿主机模拟 ARM64 属于跨架构翻译KVM 无法直接使用默认会走 TCG 模式速度比同架构虚拟机慢很多。学习、测试和 CI 验证可以接受生产级性能则不推荐依赖 TCG。4.2 运行一个 RISC-V 系统RISC-V 是开放指令集架构QEMU 的virt机器模型对 RISC-V 同样有完善支持。假设已经准备好 RISC-V 的 Linux 内核镜像Image和根文件系统rootfs.ext4可以用类似命令启动qemu-system-riscv64 \ -M virt \ -m 2048 \ -smp 2 \ -kernel /path/to/Image \ -drive file/path/to/rootfs.ext4,formatraw,ifvirtio \ -append root/dev/vda rw consolettyS0 \ -nographic-kernel直接加载内核-append传入内核启动参数consolettyS0让内核输出到串口设备-nographic则把串口重定向到当前终端。这种启动方式非常适合做 RISC-V 内核实验或操作系统课程设计也常用于验证自己编译的 RISC-V 内核能否启动。如果手上没有编译好的 RISC-V 内核和根文件系统可以先从发行版构建系统下载预编译产物或者参考官方提供的测试镜像。不同发行版的 RISC-V 根文件系统格式可能是 ext4、uboot 镜像或 squashfs需要根据镜像类型调整-drive参数。4.3 跨架构模拟的性能限制与接口差异跨架构模拟的性能主要受 TCG 翻译效率影响。同样一台 x86 主机跑 x86 虚拟机可以接近原生速度跑 ARM64 虚拟机大概只能达到原生性能的十分之一甚至更低。这是动态二进制翻译的原理性限制不是 QEMU 参数没调好。另一个容易踩坑的地方是设备模型差异。-M virt下的 ARM64 和 RISC-V 默认不使用 PC 上的 IDE、VGA 等设备网卡和磁盘控制器建议使用 virtio 设备。如果某个镜像在 ARM 下找不到磁盘优先检查-drive的ifvirtio和内核启动参数root/dev/vda是否匹配。注意跨架构环境下的镜像、固件、内核和根文件系统必须属于同一个目标架构。把 x86 的 ISO 传给qemu-system-riscv64启动时会直接报错或卡死。5. 网络、串口和显示的工程化配置虚拟机启动只是第一步。真实开发中用户需要 SSH 登录虚拟机、需要多台虚拟机互通、需要查看串口日志还需要对磁盘做快照保护系统。这一节把这些工程化配置分开说明。5.1 用户态网络与端口转发QEMU 默认的-nic user模式已经提供了 NAT 网络。虚拟机可以主动访问外网但宿主机无法直接访问虚拟机内部服务。解决方案是使用hostfwd做端口转发。qemu-system-x86_64 \ -m 2048 \ -smp 2 \ -accel kvm \ -drive filedisk.qcow2,formatqcow2,ifvirtio \ -netdev user,idnet0,hostfwdtcp::2222-:22 \ -device virtio-net-pci,netdevnet0启动后通过宿主机 2222 端口就能 SSH 到虚拟机的 22 端口ssh -p 2222 user127.0.0.1这种模式适合单台虚拟机的开发和调试不需要宿主机 root 权限也不用手工创建网桥是学习阶段最稳妥的网络方案。5.2 桥接网络与多机互通如果需要在宿主机、虚拟机以及多台虚拟机之间直接互通推荐使用桥接网络。Linux 下可以通过ip命令创建网桥再让 QEMU 使用 tap 设备接入网桥。先准备宿主机网络环境sudo ip link add br0 type bridge sudo ip link set br0 up然后创建 tap 设备并挂到网桥sudo ip tuntap add dev tap0 mode tap sudo ip link set tap0 master br0 sudo ip link set tap0 upQEMU 启动时使用 tap 设备qemu-system-x86_64 \ -m 2048 \ -smp 2 \ -accel kvm \ -drive filedisk.qcow2,formatqcow2,ifvirtio \ -netdev tap,idnet0,ifnametap0,scriptno,downscriptno \ -device virtio-net-pci,netdevnet0桥接模式需要宿主机具备足够的网络权限脚本自动化时还要注意scriptno,downscriptno避免 QEMU 自带脚本干扰已经手工配置好的网桥。如果虚拟机内网卡始终无法获取 IP先检查网桥和 tap 设备的链路状态再在虚拟机内部执行ip addr查看网卡是否被识别。5.3 串口重定向没有图形界面也能调试嵌入式开发和内核调试中串口输出是最重要的观察窗口。QEMU 有几个常用串口参数。-serial stdio把串口重定向到当前终端适合命令行环境。-serial mon:stdio把串口和 QEMU 监视器都放到当前终端功能更完整。用-nographic时QEMU 会自动把串口绑定到当前终端比较适合无显示环境的服务器。调试 ARM64 和 RISC-V guest 时建议把内核启动参数中的consolettyS0和-serial stdio一起使用这样内核日志会输出到同一终端。5.4 磁盘快照与系统恢复qcow2 格式支持内部快照可以在重大操作前保存磁盘状态。qemu-img snapshot -c before-update disk.qcow2 qemu-img snapshot -l disk.qcow2从快照恢复qemu-img snapshot -a before-update disk.qcow2这些操作必须在虚拟机停机或磁盘没有被写入的情况下进行。不要在虚拟机运行期间直接对正在使用的disk.qcow2执行快照回滚否则可能损坏文件系统。生产环境更推荐使用外部快照或备份整个镜像配合定期备份策略使用。6. 常见问题与排错链路QEMU 的报错信息往往很短但大多数问题都能从日志和参数中找到根因。下面按现象、原因、检查方式和处理建议组织。6.1 KVM 不可用导致的启动失败现象启动命令报错Could not access KVM kernel module: Permission denied或/dev/kvm不存在。可能原因宿主机的 KVM 模块没有加载或者当前用户没有/dev/kvm设备的访问权限。检查方式ls -l /dev/kvm如果文件不存在加载模块sudo modprobe kvm_intel如果是 AMD CPU则加载kvm_amd。如果文件存在但没有权限把用户加入kvm组并重新登录sudo usermod -aG kvm $USER处理建议先确认宿主机 CPU 是否支持虚拟化再确认模块加载状态。虚拟机运行在 VMware Workstation 或 VirtualBox 内部时还需要在宿主虚拟机设置中启用嵌套虚拟化。6.2 Windows 下 WHPX 无法使用现象在 Windows 上执行-accel whpx启动失败提示whpx: No accelerator found或failed to initialize WHPX。可能原因Windows 没有启用 Hypervisor Platform 功能或者 Windows 版本不支持 WHPX。检查方式打开“启用或关闭 Windows 功能”确认“Hypervisor Platform”已勾选。也可以使用系统信息命令查看。处理建议启用后重启系统再回到 QEMU 命令确认加速器生效。如果仍然失败可以暂时改用 TCG 验证虚拟机是否能启动但要注意性能会明显下降。6.3 跨架构虚拟机黑屏或串口无输出现象启动 ARM64 或 RISC-V 虚拟机后图形窗口黑屏终端也没有任何输出。可能原因缺少 UEFI 固件、机器模型选择错误、内核启动参数不正确或图形设备型号不匹配。检查方式先用-serial stdio -display none去掉图形专门看串口输出。如果串口有日志就说明固件和内核已经启动问题出在显示设备上如果串口没有输出优先检查-bios、-M和-cpu三个参数。处理建议不要一开始就追求图形界面。先让系统通过串口控制台正常启动再补-display gtk或 VNC 显示参数。6.4 Windows 虚拟机无网络或显示异常现象Windows guest 安装完成后没有网卡驱动或显示分辨率异常、闪烁花屏。可能原因Windows 系统缺少 virtio 驱动或者显示设备与 Windows 显卡驱动不匹配。处理建议安装 Windows guest 前准备 virtio-win 驱动镜像在安装过程中通过“加载驱动程序”加载 virtio 网卡和磁盘控制器。显示异常可以尝试-vga virtio或-device vmware-svga然后安装对应驱动。实际项目中推荐固定一套参数组合写入启动脚本避免每次手动输入导致驱动识别不稳定。6.5 排错清单速查表现象第一检查项常用命令处理方向KVM 权限不足/dev/kvm是否可写ls -l /dev/kvm加入 kvm 组跨架构启动黑屏固件和串口输出-serial stdio -display none先串口后图形Windows 无网络virtio 驱动是否加载设备管理器中查看网卡加载 virtio-win 驱动ARM64 找不到磁盘内核 root 参数查看串口内核日志改root/dev/vda虚拟机极卡是否用了 TCG-accel help架构一致时启用 KVM/WHXP磁盘回滚损坏虚拟机是否运行中qemu-img snapshot -l停机后操作7. 最佳实践与扩展方向7.1 学习环境与生产环境的差异学习阶段可以直接使用命令行参数启动虚拟机状态文件放在当前目录方便清理和重建。生产环境则需要额外考虑几件事。配置外置化启动参数不要写死在脚本里使用变量或模板管理镜像路径、端口和 CPU 内存配额。日志与监控给 QEMU 加-daemonize配合日志文件或使用-D /var/log/qemu/qemu.log保存运行日志。权限与安全生产环境不建议用 root 直接运行 QEMU建议为虚拟机分配独立系统用户。虚拟机管理单纯使用命令行维护多台虚拟机非常痛苦建议引入libvirt和virt-manager统一管理。备份恢复qcow2 内部快照不能替代外层备份定期对镜像文件做离线备份。注意生产环境不要使用-snapshot参数作为持久化方案该参数会让所有写入都落在临时文件中虚拟机重启后数据丢失。7.2 用 libvirt 统一管理多虚拟机libvirt是 QEMU 上层常用的管理接口virt-manager则提供图形管理界面。使用 libvirt 后虚拟机配置以 XML 形式保存可以统一管理网络、存储池、快照和生命周期。安装和启动服务sudo apt install libvirt-daemon-system virt-manager sudo systemctl enable --now libvirtd然后用virsh list --all查看虚拟机状态。生产环境建议先通过virsh define导入 XML 定义再通过virsh start启动虚拟机而不是直接写 QEMU 命令行。7.3 扩展方向嵌入式开发、CI 验证与架构适配QEMU 还有一个非常重要的用途是嵌入式开发。可以利用 QEMU 模拟 ARM 开发板配合-nographic和网络桥接在宿主机编译内核再启动到虚拟开发板中验证。这种方式在没有物理开发板的情况下可以完成大部分驱动和系统集成验证工作。在 CI 中可以把 QEMU 作为跨架构测试执行环境。例如在 x86 的 GitLab Runner 上安装 QEMU启动 ARM64 系统容器或虚拟机验证产物在目标架构上的运行结果。这样能提前发现 x86 编译产物在 ARM 或 RISC-V 环境中可能出现的字节序、对齐和指令集问题。对新手来说比较有价值的练习路径是先跑通 x86 Linux 虚拟机然后尝试通过-nographic和串口调试 ARM64 虚拟机最后编译一个 RISC-V 内核放到 QEMU 中启动。每一步都能加深对硬件虚拟化、指令集和 Linux 启动流程的理解。这套技能在嵌入式开发、操作系统课程和服务器架构适配中都会反复用到。
返回列表