Create QEMU virtual machine for ARM system — Do 17 Oktober 2024

你好,世界!

QEMU 是非常著名和常用的自由软件虚拟机。所谓虚拟机就是在一个操作系统(host)下运行另一个操作系统(guest)的环境。比如,我现在使用的电脑是运行在 Intel x86 平台的64位 GNU GUIX 发行版,而我想测试一下 ARMHF 平台 GNU/Linux 系统下的一些程序,我就可以在我的 GUIX 系统下运行 QEMU,并让 QEMU 运行一个虚拟的 ARMHF 平台的 GNU/Linux 系统。这个 QEMU 的虚拟系统能够真实地反映我要测试的程序在 ARMHF 平台的表现,而我省去了寻找 ARMHF 硬件和安装调试软硬件的过程。

ARMHF 是32位的平台。使用 QEMU 模拟 ARMHF 和通常模拟 Intel x86 平台的64位系统有所不同——模拟 ARM 平台通常需要指定启动项:或者是 BIOS,或者是 kernel。我们具体来看一些 QEMU 的使用过程。

在虚拟机上安装 ARMHF 的某个 GNU 发行版

通常来说,Debian GNU/Linx 会发布很多平台的安装镜像文件,所以我们可以从 Debian GNU/Linux 的发行版做一个示例。

方法一:直接下载别人发布的 Debian GNU/Linux 虚拟硬盘

已经有人做了 Debian GNU/Linux 发行版在各个平台的虚拟硬盘文件,并发布出来供大家测试和使用。这个方法最简单,省去了许多步骤。我们应该感谢他们,比如成为 自由软件基金会的会员 就是一个帮助自由软件社区的好方法。

一个更新比较快的 Debian GNU/Linux 发行版 QEMU 虚拟硬盘下载的网站是:DQIB。其中包括了 ARMHF 的 QEMU 虚拟硬盘镜像文件(qcow2 格式),包括相应的内核文件。你下载之后可以按照其 readme.txt 文件提供的如下命令直接运行。

qemu-system-arm -machine 'virt' -cpu 'cortex-a15' -m 1G \
                -device virtio-blk-device,drive=hd -drive file=image.qcow2,if=none,id=hd \
                -device virtio-net-device,netdev=net0 -netdev user,id=net0,hostfwd=tcp::2222-:22 \
                -kernel kernel -initrd initrd -nographic -append "root=LABEL=rootfs console=ttyAMA0"

使用 root:root 登录虚拟机之后,你就象通常使用 Debian GNU/Linux 电脑一样使用 QEMU 虚拟机。

方法二:在我们刚才创建的虚拟硬盘上安装 Debian GNU/Linux 发行版

第一步:定义虚拟机的硬盘

你可以把 QEMU 虚拟机 guest 想象成一块在 host 上的硬盘。你可以使用以下命令在 host 机器上定义该硬盘:

qemu-img create -f qcow2 armhf-image-debian.qcow2 20G  # 20G harddisk image in qcow2 format

此命令创建一个大小为20G、文件格式为 qcow2 的虚拟硬盘。该硬盘会作为安装和运行虚拟机的空间。

第二步:下载启动的内核文件

ARMHF 的虚拟机需要指定内核或 BIOS 才能正常启动,所以我们要先下载 ARMHF 对应的 Debian GNU/Linux 内核文件。下载命令和地址如下:

curl -O http://ftp.us.debian.org/debian/dists/stable/main/installer-armhf/current/images/cdrom/initrd.gz
curl -O http://ftp.us.debian.org/debian/dists/stable/main/installer-armhf/current/images/cdrom/vmlinuz

注意这两个文件是为在虚拟硬盘上安装 Debian GNU/Linux 而准备的内核文件。

第三步:下载 Debian GNU/Linux 发行版的安装镜像文件

就象正常在电脑上安装 Debian GNU/Linux 发行版一样,我们需要先下载一个安装镜像文件,比如当前的 iso-cd:

curl -0 https://cdimage.debian.org/debian-cd/current/armhf/iso-cd/debian-12.7.0-armhf-netinst.iso

第四步:在虚拟硬盘上安装 Debian GNU/Linux 发行版

有了以上的三个文件之后,我们就可以使用以下命令在我们创建的虚拟硬盘上安装 Debian GNU/Linux:

qemu-system-arm -m 4G -M virt -cpu max -smp 4 \
  -initrd "./initrd.gz" \
  -kernel "./vmlinuz" \
  -append "console=ttyAMA0" \
  -drive file=./debian-12.7.0-armhf-netinst.iso,id=cdrom,if=none,media=cdrom \
    -device virtio-scsi-device \
    -device scsi-cd,drive=cdrom \
  -drive file="./armhf-image-debian.qcow2",id=hd,if=none,media=disk \
    -device virtio-scsi-device \
    -device scsi-hd,drive=hd \
  -netdev user,id=net0,hostfwd=tcp::2222-:22 \
    -device virtio-net-device,netdev=net0 \
  -nographic

运行之后,你会看到 Debian GNU/Linux 的非图形化安装界面。正常安装,注意使用整个虚拟硬盘不分区安装。安装最后不要选择重启选项。

第五步:安装完成后导出运行内核文件

在安装完成界面,不要选择重启,而是选择返回。返回到安装菜单后,选择运行终端(Execute a shell)项。然后,执行下列命令导出运行内核文件。

# 启用 root SSH
chroot /target sh -c "echo 'PermitRootLogin yes' > /etc/ssh/sshd_config.d/root_ssh.conf"
chroot /target sh -c "mkdir -p /var/run/sshd && /sbin/sshd -D"

# 复制导出运行内核文件
scp -P 2222 root@localhost:/boot/vmlinuz ./vmlinuz-from-guest
scp -P 2222 root@localhost:/boot/initrd.img ./initrd-from-guest.img

# 使用 ctrl + c 停止 sshd,并
chroot /target sh -c "rm /etc/ssh/sshd_config.d/root_ssh.conf"

# 关闭虚拟机
poweroff

当然还有其他方法从虚拟硬盘中导出运行内核文件,比如关闭虚拟机之后可以在电脑主机上挂载虚拟机硬盘文件:armhf-image.qcow2,然后再复制内核文件。此处留给读者去学习。

最后一步:正常使用虚拟机

安装完成并导出运行内核文件后,我们就可以正常使用该虚拟硬盘上的虚拟机。

qemu-system-arm -m 4G -M virt -cpu max -smp 4 \
  -initrd "./initrd-from-guest.img" \
  -kernel "./vmlinuz-from-guest" \
  -append "root=LABEL=rootfs console=ttyAMA0" \
  -drive file="./armhf-image-debian.qcow2",id=hd,if=none,media=disk \
    -device virtio-scsi-device \
    -device scsi-hd,drive=hd \
  -netdev user,id=net0,hostfwd=tcp::2222-:22 \
    -device virtio-net-device,netdev=net0 \
  -nographic

进一步安装一个完全自由的 GNU 发行版

Debain GNU/Linux 现在不是自由软件基金会认可的 完全自由的操作系统。我们的目标当然是使用完全自由的操作系统,无论是在电脑上,还是在虚拟机上。有了上面的 Debian GNU/Linux 为基础,我们可以安装 ARM 平台的 GNU GUIX 发行版作为完全自由的操作系统。

首先,我们正常启动安装配置好的 Debian GNU/Linux 虚拟机。在虚拟机登录后,可以下载 GUIX 的 ARMHF 二进制发布。

curl -0 https://ftpmirror.gnu.org/gnu/guix/guix-binary-1.4.0.armhf-linux.tar.xz

然后按照 GUIX 的 二进制安装说明 在虚拟机里安装 GUIX。或者直接在虚拟机里通过 Debian GNU/Linux 安装 GUIX:

sudo apt install guix
guix pull

之后,你需要定义一个你想要的 GUIX 的配置文件: config.scm,可以参考 Using the GUIX Configuration System。 然后,你在安装好 GUIX 的虚拟机里使用 GUIX 强大的镜像生成工具做一个 ARMHF 的 GUIX 镜像:

guix system image --image-type=qcow2 --image-size=10G config.scm

这个可能需要一点时间,之后你会看到有一个新生成的 .qcow2 文件。你可以把它改名为 armhf-image-guix.qcow2。你可以使用 scp 把这个文件从虚拟机里拷贝出来,然后把其内核文件也复制出来。这样,你就有了一个可以运行的 ARMHF 平台下的 GUIX 的 QEMU 虚拟机。你可以这样运行它:

qemu-system-arm -m 4G -M virt -cpu max -smp 4 \
  -initrd "./initrd-from-guest.img" \
  -kernel "./vmlinuz-from-guest" \
  -append "root=LABEL=rootfs console=ttyAMA0" \
  -drive file="./armhf-image-guix.qcow2",id=hd,if=none,media=disk \
    -device virtio-scsi-device \
    -device scsi-hd,drive=hd \
  -netdev user,id=net0,hostfwd=tcp::2222-:22 \
    -device virtio-net-device,netdev=net0 \
  -nographic

你还可以修改系统配置文件更新这个 GUIX 虚拟机系统:

guix system reconfigure /etc/config.scm

希望你了解了 QEMU 虚拟机的制作步骤。

如果你对 QEMU 虚拟机系统还有问题,立伯乐或许可以帮你。

让 QEMU 带你进入自由软件的美好世界!