ARTICLE DETAIL

资讯详情

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

QEMU 跨架构模拟实战:从 x86 到 ARM64 的虚拟机搭建指南

QEMU 跨架构模拟实战:从 x86 到 ARM64 的虚拟机搭建指南 当初第一次在 x86 机器上跑qemu-system-aarch64看着屏幕上弹出 ARM64 版 Alpine 的安装界面我是真有点兴奋的。后来又在 Windows 上拿 QEMU 装 openEuler 的 ARM 虚拟机再后来干脆在手机 Termux 里折腾 QEMU一路下来踩的坑比学的命令还多。如果你正在搜“qemu 操作”大概率也是想搞清楚怎么装、怎么启动、怎么跑 ARM64 系统、怎么在 Windows 或手机上用。这篇就把我实际验证过的流程和教训全部写出来按场景给命令、给参数、给排查思路你照着操作基本能一次跑通。1. 先分清 QEMU 的两种工作模式别等装完才发现用错了很多人把 QEMU 理解成“虚拟机软件”这个说法不算错但会误导你的使用方式。QEMU 实际上分两条完全不同的路线全系统模拟和用户态模拟。它们对应的命令不一样、应用场景不一样连安装包都经常是分开的。1.1 全系统模拟把一整台机器演出来我们平时说的qemu-system-x86_64、qemu-system-aarch64属于全系统模拟。它直接模拟一整台电脑CPU、内存、主板芯片组、硬盘控制器、网卡、显卡、USB 控制器……客户机操作系统根本不知道自己跑在虚拟机里它会像在真机上一样做硬件探测、加载驱动。你可以用它做这些事在同一台 x86 电脑上运行 ARM64 版本的 Linux 发行版比如 openEuler、Alpine、Debian 的 aarch64 镜像在没有 GUI 的服务器上跑一个纯命令行虚拟机做测试调试内核、交叉编译后的镜像因为你可以完全控制机器参数模拟嵌入式设备的环境比如 ARM 开发板。全系统模拟的代价是性能开销大。CPU 每条指令都要经过翻译后面我会详细讲。1.2 用户态模拟只翻译单个程序另一条路线是用户态模拟对应命令是qemu-aarch64、qemu-arm、qemu-x86_64这类不带-system的。它只模拟一个 CPU 和 Linux 的系统调用接口用来直接运行单个可执行文件不模拟整机。典型用法是# 在 x86 Linux 上直接运行 ARM64 的二进制文件 qemu-aarch64-static ./my_arm64_program # 配合 binfmt_misc可以直接执行 ARM 架构的程序 sudo update-binfmts --enable qemu-aarch64做嵌入式开发的人经常用它跑交叉编译产物或者配合 Docker 在 x86 上构建多架构镜像。日常折腾虚拟机一般用不到用户态模式但你得知道区别否则找错命令很容易一脸懵。1.3 TCG、KVM 和硬件加速到底怎么回事QEMU 默认的翻译执行引擎叫 TCGTiny Code Generator它是一种动态二进制翻译器把客户机的 ARM 指令实时翻译成宿主机的 x86 指令。好处是跨架构也能跑坏处是慢通常比原生慢一个数量级以上。如果想提速需要硬件辅助虚拟化这时候就要分清加速器加速器所在平台能不能跨架构KVMLinux只能同架构x86 宿主机只能加速 x86 客户机HVFmacOS一般只用于 x86 / x64 客户机WHPXWindows同样只能加速 x86 客户机TCG所有平台可以模拟任意架构但无硬件加速这里有个很容易误解的点很多人以为在 x86 电脑上用 KVM 就能“加速模拟 ARM64”不能。KVM 是让 CPU 直接运行客户机的同架构指令ARM64 指令在 x86 CPU 上根本无法直接执行所以跨架构模拟只能走 TCG。你会在 x86 上跑qemu-system-aarch64时看到它默认用 TCG这是正常的别去折腾 KVM 了。明白了这个底层逻辑后面遇到“为什么这么慢”“为什么 KVM 用不了”之类的问题你自己就能判断了。2. 装好 QEMU 之后第一台虚拟机该怎么拉起来我建议别一上来就玩 ARM64先在你本机架构上跑通一个最简单的 Linux 虚拟机把 QEMU 的基本操作搞熟。等你理解了启动参数的套路再切到 ARM64 也不会慌。2.1 不同平台的安装选择QEMU 在各主流平台都有现成安装方式我按平台列一下LinuxDebian/Ubuntusudo apt install qemu-system-x86 qemu-system-arm qemu-utilsFedora/RHEL 用dnf install qemu-kvm这里注意 Debian 系把模拟器和工具拆得比较细。macOSbrew install qemuHomebrew 会一起装好常见固件和工具。Windows去 qemu.org 下载官方 Windows 安装包或者直接用包管理器winget install --id QEMU.QEMU -e安装完记得把安装目录加入 PATH或者直接用完整路径调用qemu-system-aarch64.exe。安卓 Termuxpkg install qemu-system-aarch64 qemu-utils后面专门有一节讲。安装完测试一下qemu-system-x86_64 --version qemu-img --version看到版本号就说明基础环境没问题。2.2 qemu-img创建磁盘镜像的基本功QEMU 不像 VirtualBox 那样有图形化向导磁盘镜像是用命令创建的。我先说最常用的格式区别raw就是裸数据性能好但不支持快照多大文件占多大空间qcow2QEMU 独有的写时复制格式创建时只占用实际写入的大小支持快照、压缩、加密是日常使用首选。创建一块 8G 的 qcow2 磁盘qemu-img create -f qcow2 disk.img 8G查看镜像信息qemu-img info disk.img后面如果需要扩容qemu-img resize disk.img 12G注意 resize 只是调大镜像文件客户机里面的分区表不会自动变需进系统用分区工具扩展这块到最后的坑位再展开。2.3 一个最小可用启动命令以 x86_64 宿主机跑 Alpine Linux 为例先把安装 ISO 下载下来然后执行qemu-system-x86_64 \ -m 2048 \ -smp 2 \ -enable-kvm \ -cdrom alpine-virt-3.20.0-x86_64.iso \ -drive filedisk.img,formatqcow2,ifvirtio \ -netdev user,idn1,hostfwdtcp::2222-:22 \ -device virtio-net-pci,netdevn1 \ -boot d \ -nographic这行命令的参数逐个解释一下-m 2048内存 2G。-smp 2两个 vCPU。-enable-kvmLinux 宿主机且是 x86 客户机时使用硬件加速速度会快很多。-cdrom挂载 ISO 光驱。-drive filedisk.img,formatqcow2,ifvirtio挂载磁盘接口用 virtio性能比模拟 IDE 好。-netdev user,idn1,hostfwdtcp::2222-:22用户态网络并把宿主机的 2222 端口转发到客户机的 22 端口。-device virtio-net-pci,netdevn1给客户机添加一张 virtio 网卡。-boot d优先从光驱启动。-nographic不使用图形窗口串口输出直接打到当前终端适合服务器和无桌面环境。装完系统后重启去掉-cdrom和-boot d从磁盘启动qemu-system-x86_64 \ -m 2048 -smp 2 -enable-kvm \ -drive filedisk.img,formatqcow2,ifvirtio \ -netdev user,idn1,hostfwdtcp::2222-:22 \ -device virtio-net-pci,netdevn1 \ -nographic主机上用ssh -p 2222 root127.0.0.1就能连进虚拟机用户态网络模式下客户机的 IP 固定是 10.0.2.15端口转发都在宿主机 127.0.0.1 上监听这个常识后面排查网络时会用到。3. 真正折腾的开始用 qemu-system-aarch64 模拟 ARM64跨架构模拟是你搜索 QEMU 时最常碰到的话题尤其是“qemu模拟arm64”。这个玩法在调试 ARM 软件、测试 aarch64 发行版时几乎是刚需。我先给你打好心理预期这玩意儿跑起来是能用的但不要指望它有物理机性能一个简单的安装流程可能要等十几分钟甚至更久属正常现象。3.1 为什么跨架构模拟会这么慢前面说了TCG 要边翻译边执行每条 ARM 指令都被拆成若干条 x86 微操作再来执行等效于指令级解释。加上要模拟内存管理、中断、DMA 等整个系统的开销非常大。实测感受大概是在 i5 级别的 x86 CPU 上跑 ARM64 Alpine 的文本安装界面每一次按键响应都有明显延迟如果跑带桌面的 openEuler开机到登录可能要几分钟。这不是你命令写错了纯粹是物理规律。想缓解的话可以用-cpu max让 QEMU 启用支持的最大特性集某些场景比固定cortex-a57更快用 virtio 半虚拟化设备别用模拟的 IDE 网卡内存和 CPU 别给太少2G 内存两个核是最低要求不要同时开图形界面和多个后台任务。3.2 跑通 Alpine ARM64 的完整启动命令以宿主 Debian/Ubuntu 为例先装好需要的固件sudo apt install qemu-system-arm qemu-efi-aarch64qemu-efi-aarch64提供 UEFI 固件ARM64 的 virt 机器没有传统 BIOS必须用 UEFI 引导很多新手卡在这一步。然后下载 ARM64 版 Alpine ISOwget https://dl-cdn.alpinelinux.org/alpine/v3.20/releases/aarch64/alpine-virt-3.20.0-aarch64.iso qemu-img create -f qcow2 alpine-arm64.img 8G启动命令qemu-system-aarch64 \ -M virt \ -cpu max \ -m 2048 \ -smp 2 \ -bios /usr/share/qemu-efi-aarch64/QEMU_EFI.fd \ -cdrom alpine-virt-3.20.0-aarch64.iso \ -drive filealpine-arm64.img,formatqcow2,ifvirtio \ -netdev user,idn1,hostfwdtcp::2222-:22 \ -device virtio-net-pci,netdevn1 \ -serial stdio -display none这里的参数有几点和 x86 不同-M virtARM64 下最通用的虚拟机型没有具体主板型号就是一个标准 ARM 虚拟平台。-cpu max让 TCG 放开手脚启用所有支持的特性兼容性最好。-bios指定 UEFI 固件文件。不同发行版路径不一样Debian 系常见于/usr/share/qemu-efi-aarch64/QEMU_EFI.fdFedora 系在/usr/share/edk2/aarch64/QEMU_EFI.fd。-serial stdio -display none把串口输出到当前终端。如果你用-nographic要注意ARM64 机器的串口设备名是ttyAMA0某些发行版引导时需要追加consolettyAMA0参数才能看到输出。如果你发现串口没有显示可以在 UEFI 启动菜单里按e编辑内核命令行追加consolettyAMA0。这个细节不同版本略有差异按你实际镜像调整。3.3 Alpine 的安装与网络检查进入 Alpine 安装界面后用root登录默认无密码执行setup-alpine按提示选择键盘、主机名、网络等。网络这里不用慌张QEMU 的用户态网络会自动提供 DHCP客户机一般能拿到 10.0.2.15 这个地址。装到磁盘时执行setup-disk选择把系统写入/dev/vda也就是我们挂载的 virtio 磁盘。写完后重启。第二次启动时去掉光盘参数qemu-system-aarch64 \ -M virt -cpu max -m 2048 -smp 2 \ -bios /usr/share/qemu-efi-aarch64/QEMU_EFI.fd \ -drive filealpine-arm64.img,formatqcow2,ifvirtio \ -netdev user,idn1,hostfwdtcp::2222-:22 \ -device virtio-net-pci,netdevn1 \ -serial stdio -display none登录后用ip a确认有eth0和 IP 地址再测一下外网ping -c 3 223.5.5.5如果能通说明网络没问题。之后你就能在客户机里apk add装各种软件了。4. Windows 上装 openEuler ARM 虚拟机一次完整的跨架构实操记录“windows使用qemu安装openeuler arm虚拟机”是很多人搜的热词。为什么大家愿意在 Windows 上折腾这个因为想体验 openEuler 的 ARM64 版本但手头没有 ARM 服务器。我完整走了一遍把链路整理出来这里有个容易误导人的认知QEMU 在 Windows 上可以模拟任意架构的客户机但 WHPX 加速只对 x86 客户机有效ARM64 客户机依然是纯 TCG 模拟所以在 Windows 上装 openEuler ARM 会明显比本机架构慢要有心理准备。4.1 镜像下载与固件准备openEuler 的 aarch64 ISO 去官方仓库找比如 22.03 LTS 版本的 aarch64 目录https://repo.openeuler.org/openEuler-22.03-LTS/ISO/aarch64/下载openEuler-22.03-LTS-aarch64-dvd.iso文件比较大接近 4GB注意磁盘空间。Windows 版 QEMU 安装包在qemu.org装完后在安装目录的share子目录下一般能找到edk2-aarch64-code.fd这就是 ARM64 的 UEFI 固件。如果找不到我建议先在 WSL 或 Linux 机器上装一个qemu-efi-aarch64包把固件拷过来用。这是比较稳妥的做法别自己猜路径。创建磁盘qemu-img create -f qcow2 openeuler-arm64.img 32GopenEuler 默认安装会比 Alpine 占空间32G 起步比较安心。4.2 启动安装的完整命令Windows 上用 CMD 或 PowerShell 都行注意 PowerShell 换行用反引号CMD 用^。CMD 下命令是qemu-system-aarch64.exe ^ -M virt ^ -cpu cortex-a72 ^ -smp 4 ^ -m 4096 ^ -bios edk2-aarch64-code.fd ^ -cdrom openEuler-22.03-LTS-aarch64-dvd.iso ^ -drive fileopeneuler-arm64.img,formatqcow2,ifvirtio ^ -netdev user,idn1,hostfwdtcp::2223-:22 ^ -device virtio-net-pci,netdevn1 ^ -device virtio-gpu-pci ^ -device virtio-keyboard-pci ^ -device virtio-tablet-pci ^ -vnc 127.0.0.1:1有两处我必须强调第一ARM64 的 virt 机器默认没有显示设备和输入设备你不加下面这三行VNC 里会没有画面、没有键盘鼠标-device virtio-gpu-pci -device virtio-keyboard-pci -device virtio-tablet-pci第二VNC 监听地址写成127.0.0.1:1是只允许本机连接端口是 5901。别用:1的写法暴露到局域网除非你知道自己在做什么。用 VNC Viewer 连接127.0.0.1:5901会看到 openEuler 的安装界面。安装过程里选择“服务器”或者带桌面的版本都可以磁盘选我们挂载的 virtio 盘软件源默认走光盘镜像不用联网也能装完。4.3 装完后的启动参数与使用建议安装完成后去掉-cdrom参数再次启动qemu-system-aarch64.exe ^ -M virt ^ -cpu cortex-a72 ^ -smp 4 ^ -m 4096 ^ -bios edk2-aarch64-code.fd ^ -drive fileopeneuler-arm64.img,formatqcow2,ifvirtio ^ -netdev user,idn1,hostfwdtcp::2223-:22 ^ -device virtio-net-pci,netdevn1 ^ -device virtio-gpu-pci ^ -device virtio-keyboard-pci ^ -device virtio-tablet-pci ^ -vnc 127.0.0.1:1如果你设置了打开 SSH 服务宿主机直接ssh -p 2223 root127.0.0.1整体感受是安装阶段最煎熬图形界面卡顿明显建议耐着性子把必选项配置完就尽快跳到重启进了系统以后纯命令行 SSH 会话比 VNC 图形界面流畅得多日常维护完全够用。5. 手机上的极限操作Termux 里装 QEMU 跑 ARM64在手机上折腾 QEMU 属于“能跑就行”的快乐。我知道这很不实用但你要是和我一样出门在外想随时掏出手机看一眼 ARM64 环境会理解这种执念。Termux 是安卓上的终端模拟器它提供了完整的 Linux 用户态环境能直接装 QEMU。5.1 Termux 环境准备首先更新源并安装软件包pkg update pkg install qemu-system-aarch64 qemu-utils这个包比较大大概几百兆建议在 Wi-Fi 环境下装。装完确认qemu-system-aarch64 --version再给 Termux 开放存储权限方便把镜像放到共享目录termux-setup-storage镜像文件建议放在~/storage/downloads这样的位置和电脑互传方便。5.2 在 Termux 里启动 Alpine ARM64手机性能有限我建议跑最小化的 Alpine不要跑桌面。用 Alpine 的 virt ISO 配合 UEFI 固件启动命令和电脑上差不多qemu-system-aarch64 \ -M virt \ -cpu max \ -m 1024 \ -smp 2 \ -bios /data/data/com.termux/files/usr/share/qemu/edk2-aarch64-code.fd \ -cdrom alpine-virt-3.20.0-aarch64.iso \ -drive filealpine-arm64.img,formatqcow2,ifvirtio \ -netdev user,idn1,hostfwdtcp::2222-:22 \ -device virtio-net-pci,netdevn1 \ -nographicTermux 的 QEMU 包一般会把固件装在$PREFIX/share/qemu/下你可以先用find找一下find $PREFIX/share/qemu -name *aarch64*如果确实没有固件退而求其次下载 Alpine 的 aarch64 netboot 文件vmlinuz-virt、initramfs-virt用内核直载方式启动qemu-system-aarch64 \ -M virt -cpu max -m 1024 -smp 2 \ -kernel vmlinuz-virt \ -initrd initramfs-virt \ -append consolettyAMA0 \ -drive filealpine-arm64.img,formatqcow2,ifvirtio \ -netdev user,idn1,hostfwdtcp::2222-:22 \ -device virtio-net-pci,netdevn1 \ -nographic这个方式的优点是省掉 UEFI 层启动快一点点缺点是 modloop模块镜像得自己处理不同 Alpine 小版本的参数有差异。我的建议是能搞到 UEFI 固件就用标准方式省心。5.3 手机模拟的性能和心态建议实测在骁龙 8 系手机上1024M 内存跑 Alpine ARM64 的安装一个setup-alpine交互要等好几秒才刷新一次界面输错一个字符都让你崩溃。更现实的做法是提前把安装命令想好少打交互式命令或者直接在电脑上把系统装好再把磁盘镜像传到手机上用把-m调小到 768M给手机系统留内存免得整个机器卡死不要开图形界面。手机跑 QEMU 最大的价值不是性能而是验证“ARM64 架构的软件在这个环境下的基本行为”。想真正干活还是老老实实用电脑。6. 这些坑我替你们踩过了QEMU 常见问题的排查思路最后这部分是纯干货每个问题都是我在不同系统上切实遇到过的我按“现象 → 原因 → 解法”的方式写你可以直接对照。6.1 提示 KVM 不可用或加速失效现象在 Linux 上启动虚拟机报Could not access KVM kernel module: No such file or directory kvm_init_vcpu failed: Invalid argument原因宿主机的/dev/kvm不存在或者 CPU 不支持嵌套虚拟化。排查ls -l /dev/kvm cat /proc/cpuinfo | grep -c vmx解法物理机上装好 KVM 模块或者确保用户在kvm组云服务器/虚拟机里跑 QEMU 要打开嵌套虚拟化选项如果只是跨架构模拟 ARM64直接去掉-enable-kvmQEMU 默认会走 TCG。要特别强调x86 宿主机上模拟 ARM64KVM 本来就帮不上忙别在加速上浪费时间。6.2 卡在 UEFI 黑屏或者找不到固件现象启动qemu-system-aarch64报Could not load ROM file: /usr/share/qemu-efi-aarch64/QEMU_EFI.fd或者启动后屏幕一直黑。原因没有安装 ARM64 的 UEFI 固件包或者-bios路径写错了。解法Debian/Ubuntu 装qemu-efi-aarch64Fedora 装edk2-aarch64确认固件路径后用-bios指定绝对路径。黑屏还有一个可能原因你用了-display none但客户机的内核输出到了图形设备而不是串口。这时候把参数改成-serial stdio -display none或者干脆开 VNC能看到画面再判断。6.3 客户机网络不通SSH 连不上现象客户机能登录但ping外网不通或者宿主机ssh -p 2222 root127.0.0.1连接被拒。排查顺序客户机里先看ip a有没有拿到 10.0.2.x 地址没有地址就执行udhcpc -i eth0或者检查 DHCP 客户端能 ping 通网关但上不了外网检查宿主机 DNS/etc/resolv.conf是否正常SSH 连不上先确认客户机里 sshd 启动了service sshd start确认hostfwd的宿主机端口没被占用netstat -ano | findstr 2222Windows或ss -lntp | grep 2222Linux。另外注意用户态网络模式下从宿主机连客户机只能用hostfwd转发的端口不能直接连接客户机的 IP因为 10.0.2.0/24 是 QEMU 内部的 NAT 网段。6.4 磁盘空间不够怎么给镜像扩容现象客户机提示磁盘满。解法先在宿主机扩大镜像qemu-img resize alpine-arm64.img 8G然后进客户机扩展分区和文件系统。以 Alpine 的 ext4 为例# 查看分区情况 fdisk -l /dev/vda # 用 parted 或 fdisk 扩展分区找到一个空闲空间并扩大分区 # 扩展根分区后让内核重读分区表 partprobe /dev/vda # 扩展文件系统 resize2fs /dev/vda2如果是 btrfsbtrfs filesystem resize max /扩容这个操作没什么黑科技就是分区工具 文件系统工具两件事。记住resize 镜像文件只是把容器变大了客户机里的分区表不会自动变。6.5 进来慢、卡顿严重有没有优化手段除了换硬件QEMU 侧能做的优化如下磁盘和网卡都用 virtio 设备不要用ifide或模拟 e1000尽量用-cpu max而不是老旧的cortex-a57给足内存跨架构模拟场景 2G 内存和 1G 内存差距很大不需要图形的时候用-nographic或-display none图形渲染开销省掉一大截如果是 x86 客户机在 x86 宿主机上务必开 KVM性能差距是数量级的。我自己的习惯是把所有常用的启动参数写成一个启动脚本放在项目目录里避免每次敲一长串命令。比如 Linux 下写个run.shWindows 下写个run.bat参数变更只改脚本即可。最后的建议QEMU 这东西入门门槛主要不在命令而在对“模拟 vs 虚拟化”的理解。你只要记住同架构用 KVM 加速跨架构认命用 TCG设备尽量选 virtio网络优先用 user 模式加端口转发就足够应付绝大多数场景。我个人实际操作中最常被问到的问题其实是“为什么这么慢”每次回答完都会补一句跨架构模拟能跑通已经是胜利慢才是常态。希望这篇能帮你少走点弯路少熬几个夜。
返回列表