Emulating a Raspberry Pi

Have you ever wanted to run the Raspbian operating system, but haven't invested in a Raspberry Pi yet?

While I've been developing directly on the Pi itself, you can use this information to guide your development when preparing for the actual hardware. What I learned in this area was avantageous in helping me understand the bootstrap procedures for the Pi and ARM hardware layouts in general.

It's possible to run the stock ARM disk image of Raspbian on your Ubuntu Linux (or other) computer, using the QEMU suite of system emulators and a compile of the Linux kernel which I will walk you through.

You're going to learn the commands of how to compile your own kernel for ARM architecture! This was a common skill that Linux users learned the hard way in the 1990s. Before the convenience of Plug-and-Play (think around the time of 386- and 486-class PCs), we had to do this every time we added new devices to the system.

I'll walk you through the procedure below. Just be sure that you have the necessary packages already installed on your Ubuntu system. This includes qemu-system-arm, gcc-arm-none-eabi, and any surrounding dependencies either the system or yourself thinks you may require.

You'll need a few things before starting.

  • Download the archive of the Linux 4.15.5 kernel here. (This was current when I did this in February 2018.)
  • Download this text file with build configuration parameters for the aforementioned kernel.
  • Download a Raspbian software image. The most recent version I've tested this with is the 2018-04-18 version.

    This is an easy tutorial. I find that it's best to let the Unix commands speak for themselves so the reader has the benefit of learning what to expect from the computer, as well as giving them the courage to try modifying the commands.

    $ cd ~/rpi-qemu/
    $ ls -l
    total 1835008
    -rw-r--r-- 1 drw drw 1776761413 Apr 26 22:37 2018-04-18-raspbian-stretch.zip
    -rw-r--r-- 1 drw drw  102193944 Apr 26 22:35 linux-4.15.5.tar.xz
    -rw-r--r-- 1 drw drw      81011 Apr 26 21:54 qemu-kernel-config.txt
    $ unzip 2018-04-18-raspbian-stretch.zip
    Archive:  2018-04-18-raspbian-stretch.zip
      inflating: 2018-04-18-raspbian-stretch.img
    $ ls -l *.img
    -rw-r--r-- 1 drw drw 4953473024 Apr 18 02:24 2018-04-18-raspbian-stretch.img
    $ file 2018-04-18-raspbian-stretch.img
    2018-04-18-raspbian-stretch.img: DOS/MBR boot sector; partition 1 : 
    ID=0xc, start-CHS (0x0,130,3), end-CHS (0x6,1,1), startsector 8192, 
    88262 sectors; partition 2 : ID=0x83, start-CHS (0x6,30,25), end-CHS 
    (0x25a,57,31), startsector 98304, 9576448 sectors
    $ qemu-img convert -f raw -O qcow2 2018-04-18-raspbian-stretch.img raspbian.qcow
    $ file raspbian.qcow
    raspbian.qcow: QEMU QCOW Image (v3), 4953473024 bytes
    $ qemu-img info raspbian.qcow
    image: raspbian.qcow
    file format: qcow2
    virtual size: 4.6G (4953473024 bytes)
    disk size: 4.1G
    cluster_size: 65536
    Format specific information:
        compat: 1.1
        lazy refcounts: false
        refcount bits: 16
        corrupt: false
    $ tar -Jxvf linux-4.15.5.tar.xz
    $ cd linux-4.15.5/
    $ cp ~/rpi-qemu/qemu-kernel-config.txt .config
    $ make -j 4 -k CC="ccache arm-none-eabi-gcc" ARCH=arm CROSS_COMPILE=arm-none-eabi- dtbs zImage
    $ cp arch/arm/boot/zImage ~/rpi-qemu/kernel.img
    $ cp arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dtb ~/rpi-qemu/
    $ cd ~/rpi-qemu/
    $ ls -l kernel.img
    -rwxrwxr-x 1 drw drw 3452376 Apr 26 22:58 kernel.img
    $ file kernel.img
    kernel.img: Linux kernel ARM boot executable zImage (little-endian)
    $ ls -l vexpress-v2p-ca15-tc1.dtb
    -rw-rw-r-- 1 drw drw 13106 Apr 26 22:58 vexpress-v2p-ca15-tc1.dtb
    $ file vexpress-v2p-ca15-tc1.dtb
    vexpress-v2p-ca15-tc1.dtb: Device Tree Blob version 17, size=13106, boot 
    CPU=0, string block size=922, DT structure block size=12128
    $ qemu-system-arm -cpu cortex-a15 -m 1024 -M vexpress-a15 -serial stdio -drive file=raspbian.qcow,if=sd -kernel kernel.img -dtb vexpress-v2p-ca15-tc1.dtb -no-reboot

    If you've done everything properly, you should eventually see a login console in your shell prompt, as well as another window representing the system's graphics output.

    While the graphical interface will load and log you in automatically, you may log into the console with Raspbian's default username of "pi", and password of "raspberry".

    pi@raspberrypi:~$ uname -a
    Linux raspberrypi 4.15.5 #1 SMP Thu Apr 26 22:56:55 EDT 2018 armv7l GNU/Linux
    pi@raspberrypi:~$ cat /proc/cpuinfo
    processor	: 0
    model name	: ARMv7 Processor rev 1 (v7l)
    BogoMIPS	: 125.00
    Features	: half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm 
    CPU implementer	: 0x41
    CPU architecture: 7
    CPU variant	: 0x2
    CPU part	: 0xc0f
    CPU revision	: 1
    Hardware	: ARM-Versatile Express
    Revision	: 0000
    Serial		: 0000000000000000

    What you've accomplished:

    You learned how to compile a bootable kernel image, and you've learned how to configure and run a cross-platform emulator, along with managing disk images. These are necessary routines to starting your own adventures in embedded computing. What you learn by continuing down this path will set you up with the skills to bring new experiences to computers of all sizes.

    Exercises which remain for the reader include getting networking enabled into the emulated machine, and resizing the SD card image to give you more disk space to work with. Let me know if you'd like me to add your tutorials related to this topic here.

    Maybe your development system is different, so if your result is other than what is shown here, or if you have questions, ask me anything. I will try and help!

    E-Mail Contact: Doug Winslow <winslowdoug@gmail.com>