HOWTO Use QEMU with LinuxLink

Overview

Qemu is an open source machine emulator that can be useful for embedded design and testing. Using LinuxLink tools with Qemu is easy, as the platform files built can be fed directly to Qemu with minimal configuration. The Qemu Manual covers much of the functionality provided by Qemu along with advanced configuration examples not covered here.

Timesys provides Qemu within the target cross toolchain in the SDK. To enable Qemu, enable the Qemu option within Toolchain Configuration. The installed SDK toolchain will then need to be added to your PATH via:

$ export PATH=/path/to/sdk/toolchain/bin:$PATH

This will ensure the cross tools and Timesys provided Qemu are found first in your path.

Target Selections

Qemu supports a large variety of targets. This document will focus on the use of the ARM Versatile baseboard, Arm Versatile Express, and the PC (x86 or x86_64 processor) emulated systems. These are directly supported by the qemu_versatile, qemu_vexpress, qemu_x86, and qemu_x86_64 LinuxLink targets, respectively. Other targets will work with Qemu, but may require customizing the kernel configuration for the hardware that Qemu emulates on those targets.

Arm Versatile / Versatile Express

Qemu supports the ARM Versatile and Versatile Express targets through the qemu-system-arm utility. The basic qemu invocation would be:

$ qemu-system-arm -M versatilepb
$ qemu-system-arm -M vexpress-a9

X86

Qemu defaults to x86 emulation when invoked as qemu. The basic qemu invocation for an x86 target would be:

$ qemu

For x86_64 emulation, invoke:

$ qemu-system-x86_64

LinuxLink Output Formats for Qemu

The Timesys LinuxLink factory produces all of the input files that Qemu needs. The following are included in all platform builds:

  • kernel image
    • zImage
    • bzImage
    • etc
  • root filesystem (RFS)
    • rootfs.ext2.gz
    • rootfs.tar.gz
    • etc

Installing the platform development environment will provide the above along with a cross toolchain for further target development and debugging.

Linux Kernel

The Linux kernel can come in several formats. Typically for the qemu_versatile target, the image format will be zImage. The x86/x86_64 targets default to bzImage. These kernel images can be passed directly to the Qemu invocation.

RFS as EXTFS

The RFS can be generated into a compressed EXTFS image if so configured by the LinuxLink Factory. This can be uncompressed and passed directly to the Qemu invocation.

zcat rootfs.ext2.gz > rootfs.ext2

Additionally, this can be converted to ext3 using:

tune2fs -j rootfs.ext2

Converting from ext3 to ext4:

tune2fs -O extents,uninit_bg,dir_index rootfs.ext2

When ready, qemu is passed the following options (along with -append to tell the kernel what device to mount as root):

-append 'root=/dev/sda rw' -drive file=rootfs.ext2

RFS as RAW disk

The most basic LinuxLink RFS output format is the vanilla compressed tar archive. This can be used to generate a raw disk that can then be passed to Qemu. The following procedure steps through a common setup.

  1. A new image is created (named rootfs.raw) using dd. This creates a sparse file of 1 gigabyte.
    img=rootfs.raw
    rm -rf $img
    dd if=/dev/zero of=$img bs=1 count=1 seek=1G
    
  2. We set up a partition table using the GNU Parted utility.
    parted $img mklabel msdos
    parted $img mkpart primary ext2 0G 1G
    parted $img  set 1 boot on
    
  3. We can get the offset of our partition from within the image by using the following command:
    offset=$(parted $img unit B print 2>&1 | grep '^ 1' | awk '{print $2}' | sed -re 's/[MB]$//')
    
  4. We then use the offset to loop mount the partition, create the filesystem, and copy the contents from our rootfs.tar.gz archive:
    loop=$(sudo losetup -f)
    sudo losetup -o $offset $loop $img
    sudo mkfs.ext2 $loop
    sudo mount $loop /mnt
    sudo tar -C /mnt -xzf rootfs.tar.gz
    sudo umount /mnt
    sudo losetup -d $loop
    

Additionally, on x86 targets we can use the EXTLinux bootloader as a simple way to boot our system from this raw image.

sudo losetup -o $offset $loop $img
sudo mkfs.ext2 $loop
sudo mount $loop /mnt
sudo extlinux -i /mnt
sudo cp extlinux.conf /mnt/
sudo umount /mnt
sudo losetup -d $loop
dd if=/usr/share/syslinux/mbr.bin of=$img conv=notrunc

RFS over NFS

It is often simpler to use NFS for development with an embedded target. This can be done with Qemu as well. The rootfs.tar.gz can be uncompressed into an existing NFS setup and then mounted on the Qemu target.

The Qemu -append option allows additional arguments to be passed to the Linux kernel. Here is an example of how to specify the NFS root configuration via -append:

-append "root=/dev/nfs nfsroot=192.168.1.1:/srv/nfs/target rw ip=192.168.1.2::192.168.1.1:255.255.255.0" 

If dhcp is in use, this can be simplified to the following:

-append "root=/dev/nfs rw ip=dhcp" 

Qemu QCOW

The RFS images can also be converted to a native Qemu format using the qemu-img utility.

qemu-img convert -O qcow2 rootfs.ext2 rootfs.qcow2

QCOW2 supports a copy-on-write mechanism to make snapshots and roll backs. A backing file for the qcow2 image can be created at the same time that the file system is converted.

qemu-img convert -o backing_file=rootfs.ext2 -O qcow2 rootfs.ext2 rootfs.qcow2

Network Configuration

Qemu provides several mechanisms for network connectivity to the emulated target.

The most basic is the user mode network. This requires no host setup, but it is not as flexible. This is configured by the following qemu options:

-net user

Another option is to use -net tap. The following example shows the host setup involved of bridging the host interface and a tap interface used by Qemu.

  1. A bridge is created (br0) and associated with an existing interface (eth0). Then dhclient is used to configure the new bridge.
    brctl addbr br0
    brctl setfd br0 0
    brctl addif br0 eth0
    dhclient br0 # or static config
    
  2. A tap interface is created and added to the bridge. It is set up to allow the myuser host account to open and use the device.
    tap_iface=$(tunctl -b -u myuser)
    ifconfig $tap_iface 0.0.0.0 promisc up
    brctl addif br0 tap0
    
  3. You can review this configuration using:
    brctl show
  4. Invoking Qemu for this configuration involves the following qemu options:
    -net nic,macaddr=ff:ff:ff:00:00:01 -net tap,script=no,ifname=$tap_iface
  5. After running qemu, the tap interface can be disabled using:
    tunctl -d $tap_iface
    ifconfig eth0 down
    ifconfig br0 down
    brctl delif br0 eth0
    brctl delbr br0
    

Examples of running Qemu

Invoking qemu generaly involves bringing together all of the above described parts:

  • qemu system emulation type
    • qemu
    • qemu-system-arm
    • other qemu utility
  • kernel
    • -kernel zImage
    • -kernel bzImage
  • RFS or other storage
  • networking

While there are several graphical Qemu front-ends, running qemu from a command prompt is generally the easiest and most flexible way. In the following examples, we use -nographic to get the serial/console output of our Qemu target. An alternative -curses option is available for using curses/ncurses to draw the text mode output.

x86 target, file backed RFS, User mode network

qemu -kernel bzImage-2.6.39 \
  -append 'root=/dev/sda rw' \
  -drive file=rootfs.ext2 \
  -net nic -net user \
  -nographic

x86 target, raw disk backed RFS, user mode network

qemu -kernel bzImage \
  -append 'root=/dev/hda1 rw' \
  -drive file=rootfs.raw,format=raw \
  -curses

Arm Versatile, file backed RFS, tap network

qemu-system-arm \
  -kernel zImage \
  -M versatilepb -nographic \
  -append "console=tty0 console=ttyAMA0 root=/dev/sda" \
  -net nic,macaddr=ff:ff:ff:00:00:01 -net tap,script=no,ifname=$tap_iface \
  -drive file=rootfs.ext2

Arm Versatile Express, file backed RFS as MMC, user network

qemu-system-arm \
  -M vexpress-a9 \
  -kernel ./zImage \
  -nographic \
  -drive file=rootfs.ext2,if=sd,cache=writeback \
  -append "root=/dev/mmcblk0 rw console=ttyAMA0,115200" 

Other Uses

Testing u-boot

Instead of booting a kernel, the u-boot image can be used with the Qemu -kernel option to start u-boot and continue loading over the network or via another storage device.

qemu-system-arm -M versatilepb -nographic -kernel u-boot

Debugging with GDBServer

With Qemu networking configured, gdbserver can be used on the Qemu target and attached from the host with the cross gdb included within the LinuxLink SDK.

Console over SSH/Dropbear

With Qemu networking configured, a remote console to the Qemu target can be setup over dropbear or openssh as long as one of the two is included within the RFS.