How to Emulate RaspberryPi 2 using QEMU ?

We need to compile recent qemu source code since it has added support for Raspberry Pi, to do that, follow below steps,

$ mkdir workspace
$ cd workspace
$ git clone --recursive git://git.qemu-project.org/qemu.git
$ cd qemu
$ mkdir build
$  cd build
$  ../configure
$  make
$ cd workspace

You can download the latest Raspbian image from http://ftp.jaist.ac.jp/pub/raspberrypi/raspbian_lite/images/

$ wget -c http://ftp.jaist.ac.jp/pub/raspberrypi/raspbian_lite/images/raspbian_lite-2020-02-14/2020-02-13-raspbian-buster-lite.zip
$ unzip 2020-02-13-raspbian-buster-lite.zip 

Above command will create 2020-02-13-raspbian-buster-lite.img

Now, lets copy kernel image, dtb and command line information from the first partition of the 2020-02-13-raspbian-buster-lite.img as,

$ fdisk -l 2020-02-13-raspbian-buster-lite.img
Disk 2020-02-13-raspbian-buster-lite.img: 1.74 GiB, 1849688064 bytes, 3612672 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x738a4d67

Device                               Boot  Start     End Sectors  Size Id Type
2020-02-13-raspbian-buster-lite.img1        8192  532479  524288  256M  c W95 FAT32 (LBA)
2020-02-13-raspbian-buster-lite.img2      532480 3612671 3080192  1.5G 83 Linux
$ mkdir /tmp/rpi
$ sudo mount ./2020-02-13-raspbian-buster-lite.img /tmp/rpi/ -oloop,offset=$((8192*512))

With above command, you can see we are able to mount the Raspbian filesystem on /mnt/tmp folder, so we can copy the contents inside to our machine as,

$ mkdir binaries
$ cd binaries
$  cp -f /tmp/rpi/{kernel7.img,bcm2709-rpi-2-b.dtb,cmdline.txt} .

Now, you can unmount the Raspbian filesystem.

$ sudo umount /tmp/rpi

Now, we can use below command to run the QEMU with the Raspberry Pi binaries so as we can emulate the Raspberry Pi on our machine.

qemu-system-arm -M raspi2 -kernel ./kernel7.img -dtb ./bcm2709-rpi-2-b.dtb -sd ./2020-02-13-raspbian-buster-lite.img -serial stdio -append "$(<cmdline.txt)"

The kernel may possibly fail to reset, so when it prints sysrq: SysRq: Resetting, like as shown in below image just kill QEMU via Ctrl+C or closing its window.

Mount the image again and copy the updated command line cmdline.txt file as,

$ sudo mount ./2020-02-13-raspbian-buster-lite.img /tmp/rpi/ -oloop,offset=$((8192*512))
 $ cp -r /tmp/rpi/cmdline.txt .

Now you can run the QEMU again using above comamnd,

$ qemu-system-arm -M raspi2 -kernel ./kernel7.img -dtb ./bcm2709-rpi-2-b.dtb -sd ./2020-02-13-raspbian-buster-lite.img -serial stdio -append "$(<cmdline.txt)"

But with this still, you will get a Login prompt on UI but you wont be able to enter username and password due to some limitations of RPi QEMU, to resolve this we will get the console on your machines terminal, so you need to change cmdline.txt as, ( add console=ttyAM0 and -serial stdio )

console=serial0,115200 console=ttyAMA0 root=PARTUUID=738a4d67-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait -serial stdio

Now, if you start again the qemu, you can see the console logs on your machine terminal and can type username “pi” and password “raspberry” which are default Raspbian username and password.

Now cross compile the helloworld program which we can copy to the root filesystem as,

$ vim helloworld.c
#include <stdio.h>
int main(int argc, char **argv) {
    printf("hello world\n");
    return 0;
}

Now, lets try to understand cross compilation i.e. compile on x86 which will generate binary for ARM and to run on ARM.

for this, we need set of tools which are called as cross compiler or standard word is “toolchain” which helps to compile for ARM on x86 as,

 $ git clone https://github.com/raspberrypi/tools --depth 1
 $ cd tools
$ git branch
* master

export toolchain path

 $ export PATH=$PATH:/home/myuser/rpi/tools/arm-bcm2708/arm-bcm2708-linux-gnueabi/bin
 $ arm-bcm2708-linux-gnueabi-gcc -o helloworld helloworld.c

here, as we see, for native compilation we have used only gcc, but for cross compilation we have to use arm-bcm2708-linux-gnueabi-gcc i.e. cross gcc.

Now, if we check, how output binary is generated, we will see as,

 $ file helloworld
helloworld: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.3, for GNU/Linux 3.1.9, not stripped

Now we will copy this cross compiled binary on RPi qemu as,

$ fdisk -l 2017-07-05-raspbian-jessie-lite.img
Disk 2017-07-05-raspbian-jessie-lite.img: 2 GiB, 2147483648 bytes, 4194304 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x007c305b

Device                               Boot Start     End Sectors  Size Id Type
2017-07-05-raspbian-jessie-lite.img1       8192   93596   85405 41.7M  c W95 FAT32 (LBA)
2017-07-05-raspbian-jessie-lite.img2      94208 4194303 4100096    2G 83 Linux
$ sudo mkdir /mnt/tmp
$ sudo mount ./2017-07-05-raspbian-jessie-lite.img /mnt/tmp/ -oloop,offset=$((94208*512))

Here, we are mounting second partition of Rpi image 2017-07-05-raspbian-jessie-lite.img so that we can copy our cross compiled binary into Rpi root filesystem, for this important to note is, the start offset for second partition of image 2017-07-05-raspbian-jessie-lite.img2 (94208 in our case) should be same used in “offset” of mount command as shown in bold above,

$ sudo cp helloworld /mnt/tmp/home/pi/
$ sudo umount /mnt/tmp
$ /home/myuser/rpi/qemu/qemu/build/arm-softmmu/qemu-system-arm -M raspi2 -kernel ./kernel7.img \
-dtb ./bcm2709-rpi-2-b.dtb -sd ./2017-07-05-raspbian-jessie-lite.img \
-serial stdio \
-append "$(<cmdline.txt)"

Now, this will boot Rpi and on shell you will get console, type “pi” as username & “raspberry” as password to get RPi console,

and on Rpi console, you can go to /home/pi and run the helloworld binary we compiled.

Leave a Comment