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  to create an arm926 environment that can run a typical embedded distribution (we use the Ångström distribution ), using an NFS root mount to a file system on the host PC.
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-*.
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)"
make zImage cp arch/arm/boot/zImage ~/qemu
Or, you can download a pre-built copy of zImage.
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.
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"
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.