User Rating: 5 / 5

Star ActiveStar ActiveStar ActiveStar ActiveStar Active
 

A lot of people are interested in a Raspberry Pi and want to get some idea about the operating system running on Pi without the need to buy a Pi first. I actually searched for a convenient way to test a backup script called raspiBackup I wrote for the Raspberry Pi. A nice way to evaluate Raspbian or to run any tests is to use QEMU to emulate the Raspberry Pi. Note that special Pi hardware like GPIO et al cannot be simulated. It's just the processor which is simulated. You need a Raspbian image and a system with Linux or Windows. Today I configured my system to run a Pi in QEMU and in the following article I explain step by step how I installed and configured QEMU on my Debian based Linux. The image has a networking connection right after startup and will use the existing host network connection  with NAT. Finally a script is provided which executes the steps described and simplifies the image creation process.

 

1. Quickstart

 

1.1 Installation of QEMU

Prerequisite:  Host CPU supports hardware virtualisation. Test it with 
egrep '^flags.*(vmx|svm)' /proc/cpuinfo
If you don't get an output you most probably cannot run the ARM emulation.
 
a) sudo apt-get install kvm qemu qemu-kvm-extras
 

1.2 Download of an Raspbianimage and the corresponding Linux kernel for qemu (wheezy, stretch or buster)

Following commands assume you want to emulate a wheezy image. Has to be updated accordingly when stretch or buster is used.

a) wget http://downloads.raspberrypi.org/raspbian/images/2012-12-16-wheezy-raspbian/2012-12-16-wheezy-raspbian.zip
b) unzip  2012-12-16-wheezy-raspbian.zip
c) wget https://github.com/dhruvvyas90/qemu-rpi-kernel/blob/master/kernel-qemu-3.10.25-wheezy
 

1.3 Modify image so it can start with qemu

a) file  2012-12-16-wheezy-raspbian.img
Multiply the startsector of partition 2 with 512 and use this as the offset in the following command
b) sudo mount 2012-12-16-wheezy-raspbian.zip -o offset=62914560 /mnt
c) sudo nano /mnt/etc/ld.so.preload
Comment out the first line and insert # in front of the line
d) sudo umount /mnt

1.4 Start Image

sudo qemu-system-arm -kernel kernel-qemu -cpu arm1176 -m 256 -M versatilepb -no-reboot -append "root=/dev/sda2 panic=1" -hda 2012-12-16-wheezy-raspbian.img -net nic -net tap,ifname=tap0,vlan=0 
 

1.5 Logon and configure

a) Logon with userid pi and password raspberry
Change the keyboard layout and time zone accordingly. Disk resizse doesn't work with raspi-config. See below for instructions.
d) startx

 

Now you can tes the simulated Pi. Note there is not much free space on the disk.
If you want do use the whole host screen for your Pi use <CTRL><ALT>f. The same keys will revert the setting. <CTRL> <ALT>2 opens a QEMU monitor which may be interesting for people who want to understand the internals of QEMU. <CTRL><ALT>1 opens the normal console window again.
 
 

2. Resize the virtual disk

 

The virtual disk of the distributed Raspbian image is about 2GB and there is not much space left. If you want to increase the disk size follow the following steps:
 

2.1  Create a virtual qcow disk

qcow disks use real disk space only if the virtual disk needs this space. As an alternative the current img disk can be expanded but will use the virtual disk space also on the host disk even it's not fully used.
 
a) sudo shutdown -h now (on Raspberry guest)
b) qemu-img convert -f raw -O qcow2 2012-12-16-wheezy-raspbian.img raspbian.qcow (on host)
 

2.2 Increase the size of the virtual disk

a) qemu-img resize raspbian.qcow +6G (on host)
b) sudo qemu-system-arm -kernel kernel-qemu -cpu arm1176 -m 256 -M versatilepb -no-reboot -append "root=/dev/sda2 panic=1" -hda
raspian.qcow -net nic -net tap,ifname=tap0,vlan=0  (on host)
c) No use raspi-config to resize the virtual sd card or execute steps d-f
d) PART_START=$(parted /dev/sda -ms unit s p |grep “^2″ | cut -f 2 -d:); echo -e " p\nd\n2\nn\np\n2\n$PART_START\np\n\nw\n" | sudo fdisk /dev/sda (on Raspberry guest)
e) sudo shutdown -r now (on Raspberry guest)
f) sudo resize2fs /dev/sda2 (on Raspberry guest)
 

2.3 Definition on /dev/mmcblk0px

Some programs need /dev/mmcblk0p1 and /dev/mmcblk0p2. Create following definitions in /etc/udev/rules.d/90-qemu.rules to get them created at boot time:
 
KERNEL=="sda", SYMLINK+="mmcblk0"
KERNEL=="sda?", SYMLINK+="mmcblk0p%n"
KERNEL=="sda2", SYMLINK+="root"
 

3. Script to prepare an image for qemu emulator

If you have to convert multiple images the following script written by me will speed up the preparation process and execute the preparation steps mentioned above.

 

4. Network connection setup for the Images

In order to allow qemu to connect via the hostsystem to the external network there has to exist a bridge and you have to connect your existing network interface eth0 to a bridge. I used following definitions in /etc/network/interfaces

auto lo
iface lo inet loopback

auto eth0
iface eth0 inet manual

auto br0
iface br0 inet dhcp
bridge_ports eth0
   bridge_stp off
   bridge_fd 0
   bridge_maxwait 0
 

5. Start an Image

I want to get my KVM image to get the same IP address all the time. So it's important to use the same MAC all the time. I use the following script to get this done:

#!/bin/bash 
DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
F=$DIR/macdict.txt
found=0
if [ -e $F ]; then
    if grep -q "^$1 " $F; then
        mac=$(grep "^$1 " $F | cut -d ' ' -f 2)
        found=1
        echo "Reusing mac $mac for $1"
    fi
fi
if (( ! found )); then
    # generate a random mac address for the qemu nic
    mac=$(printf 'DE:AD:BE:EF:%02X:%02X\n' $((RANDOM%256)) $((RANDOM%256)))
    echo "$1 $mac" >> $F
    echo "Generated mac $mac for $1"
fi
sudo qemu-system-arm -kernel $DIR/kernel-qemu -cpu arm1176 -m 256 -M versatilepb -no-reboot -append "root=/dev/sda2 panic=1" -hda $DIR/$1 -net nic,macaddr=$mac  -net tap

 

References

QEMU RPI kernels

HOWTO: Virtual Raspbian on Qemu in Ubuntu Linux 12.10

Emulate a Raspberry Pi with Qemu+ KVM

 

Gotchas with QEMU emulation and Raspberry

I use the emulation primaily to test raspiBackup.sh. The tst of the restore of a backuped image requires direct access from the host to an empty image. This is possible when following commands are executed

sudo losetup -d /dev/loop0
sudo losetup /dev/loop0 raspiBackupRestore.img
kpartx -av /dev/loop0

Now it's possible to access /dev/loop0 from the host and to restore the backup. But unfortunately the restore of the tar and rsync backup worked fine but the started VM reported filesystem errors. In contrast the dd backup didn't create any issues. It took me some time to find out the root cause: I use a quite old raspbian image to backup which was created somewhere in 2014. That's why the image uses the contents of the fake-hwclock to get it's actual time and that's in 2014 (It's now 2015 already). tar and rsync restore change the filesystem of the image and write the actual date the restore was executed in the filesystem so the booting image detects that the filesystem was changed in the future and asks to execute fsck. The dd restore doesn't change the filesystem so there is no issue during boot. The fix of this was to execute the following commands at the end of the restore

mount /dev/loop0p2 /mnt
echo $(date +"%Y-%m-%d %T") > /mnt/etc/fake-hwclock.data
umount /mnt

That way the fake-hwclock of the old raspbian images was set to the actual time and the image starts not any more in 2014.

 

Raspberry emulation in a Docker container

 

If you want to start a Raspberry in a Docker container, you can access this git repository from Luke Childs - dockerpi. There you will find a Dockerfile and README describing how to build and use the Docker image. You can use any image. The default is a Busterimage 2019-09-26-raspbian-buster-lite. Access is either via ssh via the local port 5022 or directly on the console. Unfortunately I can't use it for raspiBackup because /dev/mmcblk0p1 incl /boot is missing and only /dev/mmcblk0p2 exists as root. 

However, it is a fully functional original Buster RaspianOS.
Add comment

*** Note ***

Comments are welcome. But in order to reject spam posts please consider following rules:
  1. Comments with string http are rejected with message You have no rights to use this tag
  2. All comments are reviewed by hand and thus it usually takes one day until a comment will be published.