Using Qemu to emulate absent hardware

At the end of one of my training courses recently we got into a discussion about how to continue working with the code and configurations developed during the course after everybody had gone home and they no longer had a target board. I said, you could use qemu to emulate an ARM target that is rather similar to the one we actually use. Thinking about it a bit more, I realise that the situation is general and common enough to be useful to many people (or so I hope) and so I have written this tutorial.

The objective, then, is to use qemu [1] to create an arm926 environment that can run a typical embedded distribution (we use the Ångström distribution [2]), using an NFS root mount to a file system on the host PC.

Installing qemu

Qemu can emulate a wide range of processor types, including arm, cris, m68k, microblaze, mips, ppc and sh4. Each one is a separate executable: qemu-system-arm and qemu-system-mips for example. For each processor type, there are emulations of a number of hardware platforms. For arm, we have the ARM Integrator, RealView and Versatile development boards, the Nokia N800/810 and various others. I have chosen to use the Versatile board with an ARM926E core.

I have tested these instructions with qemu version 0.12.3 which comes with Ubuntu 10.04, so begin with

sudo apt-get install qemu-kvm-extras

This package includes emulators for all processor types as you can see by listing /usr/bin/qemu-system-*.

Compiling the kernel

Next you will need a kernel configuration to match the board. Get a copy of Linux from kernel.org - I am using 2.6.27 here - and create a fresh directory to keep everything in one place.
NOTE: for this you will need a toolchain (e.g. Ångström) and to have set the ARCH and CROSS_COMPILE shell variables.

mkdir ~/qemu
cd ~/qemu
tar xjf linux-2.6.27.tar.bz2
cd linux-2.6.27
make versatile_defconfig
make menuconfig

Enable these features
"Kernel Features->Use the ARM EABI to compile the kernel"
"File systems->Inotify file change notification support"
"File systems->Pseudo filesystems->Virtual memory file system support (former shm fs)"
Finally,

make zImage
cp arch/arm/boot/zImage ~/qemu

Or, you can download a pre-built copy of zImage.

Get the root file system

Here is a copy of the root file system. Download it, if you don't have it already, create a directory such as ~/rootdir and extract it there. You will have to make one small change because the Digi CCW9 target board we use for training has the serial console device as ttyS1 whereas on the Versatile it is ttyAMA0. Edit /etc/inittab and change the reference to ttyS1 to ttyAMA0. That's all.

Configuring the network

You need to configure a network interface so that you can communicate with the emulated target just as if it was a real board. The technique used here is to create a TUN/TAP network device and connect it to the qemu process, with the host PC tap interface being 192.168.1.1 and the target address being 192.168.1.101.
NOTE: Choose a pair of address on a different sub-net to any real network the PC is attached to otherwise the IP routing is going to get mixed up.

Install the uml-utilities package to get the tunctl command

sudo apt-get install uml-utilities

Then configure device tap1

sudo tunctl -u $(whoami) -t tap1
sudo ifconfig tap1 192.168.1.1
sudo route add -net 192.168.1.0 netmask 255.255.255.0 dev tap1
sudo sh -c "echo  1 > /proc/sys/net/ipv4/ip_forward"

Running qemu

Now at last, you can run qemu with this command (all on one line):

qemu-system-arm -m 64M -nographic -M versatilepb -kernel zImage
-append "console=ttyAMA0 root=/dev/nfs rw nfsroot=192.168.1.1:/home/ubuntu/rootdir ip=192.168.1.101"
-net nic -net tap,ifname=tap1,script=no

Lets dissect that a bit:

    -m 64M              Create a virtual machine with 64 MiB of RAM
    -nographic          Don't emulate a frame buffer device
    -M versatilebp      The board to emulate
    -kernel zImage      The kernel to use
    -append “...”       The kernel command line
    -net nic -net tap,ifname=tap1,script=no
                        Connect the emulated network adapter to device tap1 and do not
                        run the default script, /etc/qemu-ifup.

Now you should have a fully working emulated target. To exit qemu, type Ctrl-A x. Also, Ctrl-A h gives a brief help screen.

References

[1] QEMU Emulator User Documentation http://wiki.qemu.org/download/qemu-doc.html
[2] The Ångström Distribution http://www.angstrom-distribution.org/
Chris Simmonds