Installing Debian 11 for armhf in QEMU on an M-series Mac
I needed to run a 32-bit ARM Debian image in QEMU on my M-series Mac to build some custom armhf software, mainly cuz statically cross-compiling anything remotely complicated sucks to the point where slow emulation of an armhf system felt preferable.
I didn't find a comprehensive guide for this, and I ran into some issues that took a moment to resolve, so I figured I'd detail the steps here for future reference.
This guide assumes you have QEMU installed. If you don't, you can install it with brew install qemu
.
On Linux just use your package manager to install QEMU.
1. Download the netinst image
Current QEMU (9.0.2) seems to only support up to Debian 11, so you need to grab the 11.10.0 installer image.
wget https://cdimage.debian.org/mirror/cdimage/archive/11.10.0/armhf/iso-cd/debian-11.10.0-armhf-netinst.iso
2. Create a disk image
Create a disk image to install the OS on.
qemu-img create -f qcow2 debian-11.10.0-armhf.img 10G
This will create a 10GB disk image named debian-11.10.0-armhf.img
.
3. Grab initrd.gz and vmlinuz from the ISO
You'll need these files to boot the installer and later the installed OS as there won't be a bootloader installed.
If you're unable to mount the ISO for some reason, I've zipped them up here. Note that this is for the 11.10.0-armhf netinst image only.
Mount the ISO and copy the initrd.gz
and vmlinuz
files to your working directory.
mkdir iso && sudo mount -o loop debian-11.10.0-armhf-netinst.iso iso
iso
directory.
cp iso/install.ahf/initrd.gz .
cp iso/install.ahf/vmlinuz .
initrd.gz
and vmlinuz
files to your working directory. 4. Install
Run the following command to install the OS. Note that we're booting up with 2GB of RAM which is the maximum a 32-bit ARM system can address. If you boot up with more, the installer will fail.
qemu-system-arm \
-M virt \
-m 2G \
-cpu max \
-kernel vmlinuz \
-initrd initrd.gz \
-drive file=debian-11.10.0-armhf-netinst.iso,if=none,id=cd,media=cdrom,read-only -device virtio-blk-device,drive=cd \
-drive file=debian-11.10.0-armhf.img,if=none,id=hd -device virtio-blk-device,drive=hd -device virtio-net-device,netdev=net0 \
-netdev user,id=net0 \
-serial stdio
Fixing "No device for installation media was detected"
The installer will most likely fail to detect the installation media as QEMU will mount stuff under /dev/vda
& vdb
instead of the usual places.
When you get the "No device for installation media was detected." screen, select "No" and then "Yes" in the following screen to specify another device. Select "cdrom" as the type, and try either /dev/vda
or /dev/vdb
as the device; you might have to try both- the installer will loop around if it can't find the correct device. For me, it was /dev/vdb
.
Once you've selected the correct device, the installer should continue as expected.
Touch grass for a bit
As it's emulating the environment, the installation will take a while (probably an hour or two). You will need to press enter here and there, but the first leg of it is long enough to cook dinner.
GRUB install fails
GRUB install will fail as it's unable to install the bootloader to the disk image. This is fine; you can ignore it and select "Continue without boot loader" in the menu.
It will tell you:
"No boot loader has been installed, either because you chose not to or because your specific architecture doesn't support a boot loader yet. You will need to boot manually with the /vmlinuz kernel on partition /dev/vda1
and root=/dev/vda2
passed as a kernel argument."
5. Finish and boot to Debian
Once the installation is complete, you want to make a copy of the image so you can mess around with a fresh installation later if you mess something up without having to reinstall.
You can boot the installed OS with the following command:
qemu-system-arm \
-M virt -m 2G
-smp cpus=2,maxcpus=2 \
-cpu cortex-a15 \
-kernel ./vmlinuz-5.10.0-31-armmp-lpae \
-initrd ./initrd.img-5.10.0-31-armmp-lpae \
-drive file=debian-11.10.0-armhf.img,if=none,id=hd \
-device virtio-blk-device,drive=hd \
-nographic \
-device virtio-net-device,netdev=net0 -netdev user,id=net0 \
--append "root=/dev/debian-vg/root console=ttyAMA0,115200 loglevel=7"