While developing software for the Raspberry Pi, it quickly became a pain to constantly have switch SD cards for testing purposes.
So I was looking for an option to emulate a Raspberry Pi locally which would allow me to speed up testing and have a faster feedback cycle. A nice side effect: I could tidy up my messy desk (a bit)!
Before you start
Make sure you install the following packages:
sudo apt install qemu-system-arm
You will need two thing: A Raspbian Lite image and a custom kernel for QEMU.
Raspbian Lite
You can get Raspbian Lite from the official site.
Kernel
As I learned, the standard kernel cannot be used together with QEMU. The community standard seems to be the kernels you can find in the dhruvvyas90/qemu-rpi-kernel repository. That’s what worked for me, too. so, simply clone the repository:
git clone https://github.com/dhruvvyas90/qemu-rpi-kernel.git
Preparing the virtual disk
You should now have everything you need: QEMU, custom kernels and a Raspbian Lite image. But to use the Raspbian Lite image with QEMU, you will need to:
- extract the image from the downloaded zip file
- convert it to a more efficient type
- extend the disk
- extend the second partition and filesystem
- change some configuration files before first boot.
First, unzip the Raspbian Lite zip file you just downloaded:
unzip 2018-04-18-raspbian-stretch-lite.zip
Converted it to a more native and flexible image type which allows multiple snapshots and much more:
qemu-img convert -f raw -O qcow2 2018-04-18-raspbian-stretch-lite.img 2018-04-18-raspbian-stretch-lite.qcow2
The “native” and
Extended it by 6G (or whatever you like):
qemu-img resize 2018-04-18-raspbian-stretch-lite.qcow2 +6G
To access the disk, the Network Block Device driver needs to be loaded:
sudo modprobe nbd
Connect the image as a block device:
sudo qemu-nbd -c /dev/nbd0 2018-04-18-raspbian-stretch-lite.qcow2
Use cfdisk
to delete and recreate the primary partition /dev/sda2
:
sudo cfdisk /dev/nbd0
Extend the file system:
sudo e2fsck -f /dev/nbd0p2
sudo resize2fs /dev/nbd0p2
Now, the wiki from the custom kernel repository states, that you must edit 2 files. Therefore you will need to mount the second partition:
sudo mkdir /mnt/nbd0p2
sudo mount /dev/nbd0p2 /mnt/nbd0p2
Comment (with # symbol) the first (and only) line in /mnt/nbd0p2/etc/ld.so.preload
:
Then create the file /mnt/nbd0p2/etc/udev/rules.d/90-qemu.rules
and put the following lines in it:
KERNEL=="sda", SYMLINK+="mmcblk0"
KERNEL=="sda?", SYMLINK+="mmcblk0p%n"
KERNEL=="sda2", SYMLINK+="root"
Finally do some cleanup:
sudo umount /mnt/nbd0p2
sudo qemu-nbd -d /dev/nbd0
sudo rmmod nbd
Booting QEMU with Raspbian Lite
The boot command for qemu-system-arm
is rather complex but not complicated. You can take what you find on the wiki and adapt the flags for -kernel
, -dtb
and -hda
accordingly.
qemu-system-arm \
-kernel qemu-rpi-kernel/kernel-qemu-4.9.59-stretch \
-cpu arm1176 \
-m 256 \
-M versatilepb \
-dtb qemu-rpi-kernel/versatile-pb.dtb \
-no-reboot \
-append "root=/dev/sda2 panic=1 rootfstype=ext4 rw" \
-net nic \
-net user,hostfwd=tcp::5022-:22 \
-hda 2018-04-18-raspbian-stretch-lite.qcow2
Set up SSH
Now, in your machine, you can run sudo raspi-config and enable the SSH server (in the “Interfacing Options” menu at time of writing).
In my experience, the emulation is OK, but could be faster. The resolution in QEMU is quite small, so I suggest you enable SSH in the “Interfacing Options” with sudo raspi-config
. Now, you can connect into the QEMU with e.g. pi@localhost -p5022
.