There will be times when you will need to run your projects on a ‘virtual’ Raspberry Pi. Maybe you are too lazy to get up and plug power into your RasPi, maybe you are too savvy and hesitate to buy one or maybe you need some automation like we do in Isaax. With help of QEMU you can launch a virtual RasPi-like machine in minutes and though its barely possible to emulate real GPIO devices attached to the board, its still useful for prototyping and automated tests.
What is QEMU
QEMU is a machine emulator and helps running different (sometimes very exotic) boards on your PC without physically owning them. QEMU has a vast supported ARM-machines list, but you are not limited with it – you can ‘assemble’ and emulate most machines by just imitating their specs.Installation
Unfortunately QEMU is not the kind of software, where you justsudo apt install qemu
qemu-system-arm -M raspi2
…and watch your virtual RasPi boot. QEMU is ‘have you compiled it with those options enabled?’kind of software. Well, its still worth it and I’m going to help a bit here.
We’ll download the latest release and compile it with arm-systems support only (to speed things up):
$ wget https://download.qemu.org/qemu-2.12.0-rc0.tar.xz
$ tar xvJf qemu-2.12.0-rc0.tar.xz
$ cd qemu-2.12.0-rc0
$ ./configure --target-list=arm-softmmu,aarch64-softmmu
$ make
I’m on Ubuntu 16.04 but the steps should be similar for other platforms.
Preparing Raspbian OS image
That’s simple, just go ahead and grab the latest distribution (Stretch Lite):$ wget https://downloads.raspberrypi.org/raspbian_lite_latest
$ mv raspbian_lite_latest raspbian_lite_latest.zip
$ unzip raspbian_lite_latest.zip
Archive: raspbian_lite_latest.zip
inflating: 2018-03-13-raspbian-stretch-lite.img
2018-03-13-raspbian-stretch-lite.img
– is the latest raspbian at the moment of writing.
Now its recommended to transform the raw image to QEMU’s qcow2 format:
$ qemu-img convert -f raw -O qcow2 2018-03-13-raspbian-stretch-lite.img raspbian-lite.qcow2
We can also give the image some free space:
$ qemu-img resize raspbian-lite.qcow2 +1G
Image resized.
Check if the image is OK:
$ qemu-img info raspbian-lite.qcow2
image: raspbian-lite.qcow2
file format: qcow2
virtual size: 2.7G (2931818496 bytes)
disk size: 990M
cluster_size: 65536
Format specific information:
compat: 1.1
lazy refcounts: false
refcount bits: 16
corrupt: false
Getting the working kernel
We’ve downloaded and compiled QEMU, prepared Raspbian image and are ready to do something likeqemu-system-arm -M raspi2 -hda raspbian-lite.qcow2
. Oops, not yet. If you try to use raspi2
machine right away (and that is what everyone would actually expect) you’ll probably be staring at the void:
In fact, I wasn’t able to run qemu-system-arm -M raspi2
at all, I’ve tried multiple kernels, dtb’s etc – no luck.
There is one kernel out there though that proved to be working, so lets go ahead and download it:
$ curl https://github.com/dhruvvyas90/qemu-rpi-kernel/raw/master/kernel-qemu-4.4.34-jessie
Memorize the path to it for use in next section. And yes, we are going to use Jessie kernel with Stretch image.
Emulating RasPi
While its a pity we won’t be doing something as simple asqemu-system-arm -M raspi2
, we are going to do something different. We are going to learn how to emulate a general RasPi-like machine instead.
Fill in the paths to the kernel and qcow image and run the following command:
qemu-system-arm
-kernel /path/to/kernel-qemu-4.4.34-jessie
-append "root=/dev/sda2 panic=1 rootfstype=ext4 rw"
-hda /path/to/raspbian-lite.qcow2
-cpu arm1176
-m 256
-machine versatilepb
This time you’ll hopefully see the boot:
Now lets breakdown the options used here.
-kernel
– obviously we tell QEMU to use our downloaded kernel (since QEMU can’t run normal rasbian kernel)-append
– some options for the kernel: root partition, fs type etc-hda
– set the hard disk image, previously prepared withqemu-img
-machine
–versatilepb
– I couldn’t find what exactly VersatilePB is, but that’s the kind of machine that works with our kernel and disk image-m
– set available memory. Since we mimic RasPi withversatilepb
machine, we use its maximum, which is 256M-cpu
–arm1176
– an ARMv6 cpu type
raspi2
machine as I’ve noticed.
Guestfish and Isaax Agent
While experimenting with QEMU, I couldn’t find a way to do one simple thing: pass environment variables to the machine at start time. I needed that to be able to install Isaax Agent, and as it requires a project token it has to be somewhere inside the machine after start. What I wanted to do was basically this:curl -fsSL get.isaax.io | sh -s stable $ISAAX_TOKEN
But alas – no way to pass that variable from our host system.
I’ve spent many hours looking for a way to stick that token inside the machine and almost got desperate until suddenly was struck by the idea of mounting the disk image and copying the token as a file. If I could do this with a couple of commands and without any interaction – that would do.
And actually there is a way to do exactly that with a single command! Welcome guestfish – the guest filesystem shell tool, which can manipulate disk image files.
Now, on our PC, lets take raspbian-lite.qcow2
and create the token-file there:
sudo guestfish --rw -i -a raspbian-lite.qcow2 write /etc/isaax.token "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpX..."
Notice the sudo – this command works only with root privileges. Assuming the command produced no errors, we can launch our QEMU machine and log in. Now inside the machine I can type:
jwt=${cat /etc/isaax.token}; curl -fsSL get.isaax.io | sh -s stable $jwt
And that will start Isaax Agent installation.