This was last tested using QEMU 6.1.0 running on an Arch Linux x86_64 host. The goal is to get a 32-bit armv7 (armhf) Debian VM running in QEMU.

The author's lack of knowledge about Arm and QEMU probably make this process a bit more complex than it needs to be. This is a solution, but most likely not the best solution.

% qemu-system-arm --version
QEMU emulator version 6.1.0
Copyright (c) 2003-2021 Fabrice Bellard and the QEMU Project developers

Download Files

Download the latest armhf vmlinux kernel and initrd.gz initramfs from Debian.

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

Download the latest Debian armhf DVD ISO. Version debian-11.1.0-armhf-DVD-1.iso at time of writing.

curl -O -L https://cdimage.debian.org/debian-cd/current/armhf/iso-dvd/debian-11.1.0-armhf-DVD-1.iso

Install Debian

Create a disk for the Arm QEMU emulator image.

qemu-img create -f qcow2 debian-arm.sda.qcow2 100G

Boot the VM to install Debian.

qemu-system-arm \
  -m 4G \
  -machine type=virt \
  -cpu cortex-a7 \
  -smp 4 \
  -initrd "./initrd.gz" \
  -kernel "./vmlinuz" \
  -append "console=ttyAMA0" \
  -drive file="./debian-11.1.0-armhf-DVD-1.iso",id=cdrom,if=none,media=cdrom \
    -device virtio-scsi-device \
    -device scsi-cd,drive=cdrom \
  -drive file="./debian-arm.sda.qcow2",id=hd,if=none,media=disk \
    -device virtio-scsi-device \
    -device scsi-hd,drive=hd \
  -netdev user,id=net0,hostfwd=tcp::5555-:22 \
    -device virtio-net-device,netdev=net0 \
  -nographic

The installer will eventually error out when trying to install Grub. That is fine. Choose Continue.

┌────────────────┤ [!!] Install the GRUB boot loader ├────────────────┐
│                                                                     │
│                      GRUB installation failed                       │
│ The 'grub-pc' package failed to install into /target/. Without the  │
│ GRUB boot loader, the installed system will not boot.               │
│                                                                     │
│     <Go Back>                                        <Continue>     │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

When prompted at the menu choose Continue without boot loader, which should show this information.

┌─────────────────┤ [!] Continue without boot loader ├──────────────────┐
│                                                                       │
│                       No boot loader installed                        │
│ 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/sda1 and root=/dev/sda2 passed as a kernel argument.             │
│                                                                       │
│                              <Continue>                               │
│                                                                       │
└───────────────────────────────────────────────────────────────────────┘

When installation completes it is crucial to not reboot when prompted. Rather, choose Go Back at the Finish the installation menu.

┌───────────────────┤ [!!] Finish the installation ├────────────────────┐
│                                                                       │
│                         Installation complete                         │
│ Installation is complete, so it is time to boot into your new system. │
│ Make sure to remove the installation media, so that you boot into the │
│ new system rather than restarting the installation.                   │
│                                                                       │
│     <Go Back>                                          <Continue>     │
│                                                                       │
└───────────────────────────────────────────────────────────────────────┘

Choose to Execute a shell from the main installer menu. Start sshd on the Debian installation so that we can copy out the kernel and initramfs from the guest to the host.

chroot /target/ sh -c "mkdir -p /var/run/sshd && /sbin/sshd -D"

Use scp on the host machine to copy boot files out of the guest.

scp -P 5555 will@localhost:/boot/vmlinuz ./vmlinuz-from-guest \
  && scp -P 5555 will@localhost:/boot/initrd.img ./initrd.img-from-guest

Use ctrl + c or another mechanism to stop sshd and shut down the guest VM.

Run VM Normally

Modify a few of the options for subsequent "normal" booting into the VM after installing Debian.

Required:

  • -kernel will now reference the kernel copied from the guest vm, not the version downloaded from Debian
  • -initrd will now reference the initramfs copied from the guest vm, not the version downloaded from Debian
  • -append must have root=/dev/sda2 (or another valid /dev location) added in order to boot from the virtual hard drive.

Optional:

  • -drive for the cdrom is not needed at this point and can be removed
qemu-system-arm \
  -m 4G \
  -machine type=virt \
  -cpu cortex-a7 \
  -smp 4 \
  -initrd "./initrd.img-from-guest" \
  -kernel "./vmlinuz-from-guest" \
  -append "console=ttyAMA0 root=/dev/sda2" \
  -drive file="./debian-arm.sda.qcow2",id=hd,if=none,media=disk \
    -device virtio-scsi-device \
    -device scsi-hd,drive=hd \
  -netdev user,id=net0,hostfwd=tcp::5555-:22 \
    -device virtio-net-device,netdev=net0 \
  -nographic

Note: QEMU Arm Hardware is Picky

Please note that Arm emulated boards/machine types are extremely specific about the type of hardware they support. See the QEMU docs on choosing a board model. For example, the virt machine type (-M / -machine) only supports PCI ethernet devices. Specifying a board that supports 64-bit/aarch64 vs 32-bit boards has implications on the cpu and other options that will be allowed.

The orangepi-pc machine type requires exactly 1GB of RAM. The Raspberry Pi related machine types have similar restrictions. Boards that simulate physical hardware must accept parameters that align with that device type.

See this text here regarding the QEMU Arm Versatile Express boards.

Note that as this hardware does not have PCI, IDE or SCSI, the only available storage option is emulated SD card.

See some example errors here for qemu-system-arm configuration options that were incompatible with the selected machine type.

qemu-system-arm: This machine can only be used with 512MiB or 1GiB RAM
qemu-system-arm: This board can only be used with cortex-a7 CPU
qemu-system-arm: Unsupported NIC model: rtl8139
qemu-system-arm: Invalid SD card size: 100 GiB
SD card size has to be a power of 2, e.g. 128 GiB.

Citations