Raspberry Pi and QEMU
What is QEMU?
QEMU is a generic and open source machine emulator and visualizer. It emulates full machines (boards) of different architectures and is useful for both application and kernel development. The CPU itself could be fully emulated (together with devices, memories and so on) or work with a hypervisor such as KVM or Xen.
If support for your hardware is missing, then it is a fairly easy task to write a stub driver that your application can interface. The most fun part for kernel development is so connect GDB (CONFIG_KGDB) to a running kernel, set breakpoints and step through the kernel code.
What about Raspberry Pi and QEMU?
My normal procedure is to build a custom root file system with Buildroot , clone the kernel source code and build the kernel. This is also my preferred workflow as I have control on what I actually running, but sometimes it could be handy to just take an already built setup and use it.
I'm currently doing some work with the Raspberry Pi 3b+ which is using an Raspbian image, so why not emulate it?
QEMU provides models of the following Raspberry Pi Boards:
|Number of cores
QEMU provides support for the following devices:
- ARM1176JZF-S, Cortex-A7 or Cortex-A53 CPU
- Interrupt controller
- DMA controller
- Clock and reset controller (CPRMAN)
- System Timer
- GPIO controller
- Serial ports (BCM2835 AUX - 16550 based - and PL011)
- Random Number Generator (RNG)
- Frame Buffer
- USB host (USBH)
- GPIO controller
- SD/MMC host controller
- SoC thermal sensor
- USB2 host controller (DWC2 and MPHI)
- MailBox controller (MBOX)
- VideoCore firmware (property)
However, it still lacks support for these:
- Peripheral SPI controller (SPI)
- Analog to Digital Converter (ADC)
- Pulse Width Modulation (PWM)
Set it up
You will need to have qemu-system-aarch64, you could either build it from source  or let your Linux distribution install it for you.
If you are using Arch Linux, then you could use pacman
sudo pacman -Sy qemu-system-aarch64
You will also need to do download and extract the Raspian image you want to use
wget https://downloads.raspberrypi.org/raspios_lite_arm64/images/raspios_lite_arm64-2022-09-26/2022-09-22-raspios-bullseye-arm64-lite.img.xz unxz 2022-09-22-raspios-bullseye-arm64-lite.img.xz
Loopback mount image
The image could be loopback mounted in order to extract the kernel and devicetree. First we need to figure out the first free loopback device
sudo losetup -f /dev/loop8
Then we could use that device to mount:
sudo losetup /dev/loop8 ./2022-09-22-raspios-bullseye-armhf-lite.img -P
The -P option force the kernel to scan the partition table. As the sector size of the image is 512 bytes we could omit the --sector-size.
Mount the boot partition and root filesystem
mkdir ./boot ./rootfs sudo mount /dev/loop8p1 ./boot/ sudo mount /dev/loop8p2 ./rootfs/
Copy kernel and dtb
cp boot/bcm2710-rpi-3-b.dtb . cp boot/kernel8.img .
If you have any modification you want to do on the root filesystem, do it now before we unmount everything.
sudo umount ./boot/ sudo umount ./rootfs/
QEMU requires the image size to be a power of 2, so resize the image to 2GB
qemu-img resize ./2022-09-22-raspios-bullseye-armhf-lite.img 2G
Very note that this will lose data if you make the image smaller than it currently is
Wrap it up
Everything is now ready for start QEMU. The parameters are quite self-explained
qemu-system-aarch64 \ -M raspi3b \ -cpu cortex-a72 \ -append "rw earlyprintk loglevel=8 console=ttyAMA0,115200 root=/dev/mmcblk0p2 rootdelay=1" \ -serial stdio \ -dtb ./bcm2710-rpi-3-b.dtb \ -sd ./2022-09-22-raspios-bullseye-armhf-lite.img \ -kernel kernel8.img \ -m 1G -smp 4
Here we go
raspberrypi login: pi Password: Linux raspberrypi 5.10.103-v8+ #1529 SMP PREEMPT Tue Mar 8 12:26:46 GMT 2022 aarch64 The programs included with the Debian GNU/Linux system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law. pi@raspberrypi:~$
QEMU is fun. It is a good way to explore stuff like ftrace, step through kernel code or simple run your application on a virtual board. You do not allways have to build everything yourself, sometimes a raspian image could be what you need.