How to run the ARM version of Debian on x86 with QEMU
I want to set up an Infrastructure as Code (IaC) for my machines running at home, including ARM devices, with a complete virtualized environment for tests. And since some of my devices are running on ARM, that's how I found myself playing around with libvirt+QEMU to have ARM systems running headless on my x86 computer.
I never found resources how to do it exactly like I wanted, I fought against a lot of boot errors in the process.
Finally, I succeeded with Debian ARM, here are the steps.
# Create a virtual disk
qemu-img create -f qcow2 debian.qcow2 8G
# Download debian ARM iso
wget - "https://cdimage.debian.org/debian-cd/current/armhf/iso-dvd/debian-11.6.0-armhf-DVD-1.iso"
# Mount the debian ARM iso
mkdir mnt
sudo mount -o loop debian-11.6.0-armhf-DVD-1.iso ./mnt
# Find the path to boot files
head -n 10 mnt/boot/grub/grub.cfg
# Copy boot files from the ISO to the host
cp mnt/install.ahf/vmlinuz ./
cp mnt/install.ahf/initrd.gz ./
# Unmount the ISO
sudo umount ./mnt
Now that we've extracted the boot files, let's install Debian from the ISO.
sudo qemu-system-arm \
-machine virt \
-cpu cortex-a15 \
-m 1024 \
-nographic \
-kernel ./vmlinuz \
-initrd ./initrd.gz \
-netdev user,id=n0 -device virtio-net-device,netdev=n0 \
-drive file=./debian.qcow2,if=none,format=qcow2,id=hd0 -device virtio-blk-device,drive=hd0 \
-drive file=./debian-11.6.0-armhf-DVD-1.iso,if=none,format=raw,id=hd1 -device virtio-blk-device,drive=hd1
The Debian installer won't be happy, don't worry, follow those steps to access a shell to fix the issue:
We now have access to a shell:
# Check drives, you should see "virtio_blk virtio0: [vda]"
dmseg
# Mount the ISO directly in /cdrom
modprobe isofs
mount /dev/vda1 /cdrom
# Close the shell
exit
Back to the Debian installer, we can use the ISO as an installation media:
Follow the normal steps of the installer, when done, you will be back to the menu and finish the installation:
After the installation steps, you will end up in a boot loop and you can force-close the virtual machine with the shortcut Ctrl-A X
.
We can extract the boot files from the virtual disk:
# Find the path of the boot files
sudo virt-ls -l ./debian.qcow2 /boot
# Copy the boot files from virtual disk to the host
sudo virt-copy-out -a ./debian.qcow2 /boot/initrd.img-5.10.0-23-armmp-lpae ./
sudo virt-copy-out -a ./debian.qcow2 /boot/vmlinuz-5.10.0-23-armmp-lpae ./
Start the virtual machine with the boot files as qemu arguments:
sudo qemu-system-arm \
-machine virt \
-cpu cortex-a15 \
-m 1024 \
-nographic \
-append "root=/dev/vda2" \
-kernel ./vmlinuz-5.10.0-23-armmp-lpae \
-initrd ./initrd.img-5.10.0-23-armmp-lpae \
-netdev user,id=n0 -device virtio-net-device,netdev=n0 \
-drive file=./debian.qcow2,if=none,format=qcow2,id=hd0 -device virtio-blk-device,drive=hd0
Once we're logged in, we can install SSH to simulate remote access:
root@debian:~# echo 'deb http://deb.debian.org/debian/ bullseye main' >> /etc/apt/sources.list
root@debian:~# apt update && apt install -y openssh-server
root@debian:~# sed -i '/#PermitRootLogin/c PermitRootLogin yes' /etc/ssh/sshd_config
You can force-close the virtual machine with the shortcut Ctrl-A X
.
You can run the virtual machine in the background with a port forwarding of host:5555 -> vm:22
:
sudo qemu-system-arm \
-machine virt \
-cpu cortex-a15 \
-m 1024 \
-daemonize \
-display none \
-append "root=/dev/vda2" \
-kernel ./vmlinuz-5.10.0-23-armmp-lpae \
-initrd ./initrd.img-5.10.0-23-armmp-lpae \
-netdev user,id=net0,hostfwd=tcp::5555-:22 -device virtio-net-device,netdev=net0 \
-drive file=./debian.qcow2,if=none,format=qcow2,id=hd0 -device virtio-blk-device,drive=hd0
ssh root@localhost -p 5555 -o "StrictHostKeyChecking=no"
🎉