Skip to content
Carl Karsten edited this page Mar 26, 2026 · 1 revision

This is doable but requires working around the fact that the RPi PXE boot chain (SoC ROM → bootcode.bin → start.elf → kernel) is proprietary and not emulated by QEMU. Here are the approaches:

Option 1: Direct kernel boot + NFS (simplest, same end result)

Skip the PXE phase entirely — QEMU loads the kernel directly, then NFS-mounts the same root as the real RPis. This is the most practical approach for testing.

  # Run on tweed (has eth-local on VLAN 21)
  # Create a TAP interface bridged with eth-local
  sudo ip tuntap add dev tap-qemu mode tap user pi
  sudo ip link set tap-qemu master br-fpgas  # or bridge with eth-local
  sudo ip link set tap-qemu up

  # Boot QEMU with the same kernel and NFS root
  qemu-system-aarch64 \
    -machine virt -cpu cortex-a72 -m 1G -smp 4 \
    -kernel /srv/nfs/rpi/bookworm/boot/kernel8.img \
    -dtb /srv/nfs/rpi/bookworm/boot/bcm2711-rpi-4-b.dtb \
    -append "root=/dev/nfs nfsroot=10.21.0.1:/srv/nfs/rpi/bookworm/root,v3,tcp rw ip=dhcp" \
    -netdev tap,id=net0,ifname=tap-qemu,script=no,downscript=no \
    -device virtio-net-pci,netdev=net0 \
    -nographic

Problem: The RPi kernel (kernel8.img) is compiled for RPi hardware (bcm2711/bcm2835), not QEMU's virt machine. The DTB won't match either. You'd need a generic aarch64 kernel.

Option 2: QEMU virt + UEFI PXE (actual network boot)

Use UEFI firmware with PXE support. This does a real DHCP → TFTP → kernel boot over the network, but uses standard UEFI PXE rather than the RPi-specific boot chain.

  # Needs: qemu-efi-aarch64 (provides AAVMF firmware)
  qemu-system-aarch64 \
    -machine virt -cpu cortex-a72 -m 1G -smp 4 \
    -bios /usr/share/qemu-efi-aarch64/QEMU_EFI.fd \
    -netdev tap,id=net0,ifname=tap-qemu,script=no,downscript=no \
    -device virtio-net-pci,netdev=net0 \
    -nographic

This would need tweed's dnsmasq configured to serve a GRUB EFI or generic aarch64 kernel via TFTP for the QEMU VM's MAC address.

Option 3: QEMU raspi3b machine (closest to real hardware)

QEMU has -machine raspi3b but it doesn't emulate the PXE boot ROM. You'd need to pre-load kernel8.img via -kernel:

  qemu-system-aarch64 \
    -machine raspi3b -m 1G \
    -kernel /srv/nfs/rpi/bookworm/boot/kernel8.img \
    -dtb /srv/nfs/rpi/bookworm/boot/bcm2710-rpi-3-b-plus.dtb \
    -append "root=/dev/nfs nfsroot=10.21.0.1:/srv/nfs/rpi/bookworm/root,v3,tcp rw ip=dhcp" \
    -netdev tap,id=net0,ifname=tap-qemu,script=no,downscript=no \
    -device usb-net,netdev=net0 \
    -nographic

Problem: QEMU's raspi3b emulation is incomplete — USB networking is limited, and the kernel may not boot fully.

Key constraints

  1. Network: The VM must be on VLAN 21 to reach tweed's DHCP (10.21.0.1). VLAN 21 is local-only on GSM7252PS-S2, so the VM should run on tweed with a TAP bridged to eth-local.
  2. Kernel: The RPi kernel (kernel8.img) is built for RPi hardware. For QEMU's virt machine you need a generic aarch64 kernel (e.g., Debian's linux-image-arm64). For QEMU's raspi3b machine, the RPi kernel might work but QEMU's BCM2835 emulation is incomplete.
  3. NFS root: The overlayroot setup (overlayroot=tmpfs) will work the same in QEMU — the VM mounts the NFS root read-only with a tmpfs overlay, identical to real RPis.
  4. No RPi PXE emulation: QEMU cannot replicate the RPi's serial-number-based TFTP path (//start.elf). The closest is UEFI PXE which uses standard DHCP/TFTP.

Clone this wiki locally