HOWTO Use QEMU with LinuxLink
Table of Contents
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.
- 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
- 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
- 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]$//')
- 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.
- 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
- 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
- You can review this configuration using:
brctl show
- 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
- 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.