On this page

 

1. Introduction

Embedded software development relies on embedded hardware devices, such as development boards, external module devices, etc., but if the debugging work has nothing to do with peripherals, only the kernel debugging can be simulated using QEMU without purchasing hardware.

It’s available for Linux and Windows hosts and emulated PowerPC, ARM, MIPS, and SPARC targets. QEMU takes the approach of providing a minimal translation layer between the host and target processor. The host processor is the one running the emulator, and the target processor is what’s being emulated.

The following is a detailed introduction to the process of setting up QEMU development environment.

 

2. Environment

2.1 Used environment

* Ubuntu-18.04.1

OR:

* PC:Windows10

* Virtual Machine:VirtualBox-5.18

* Virtual OS:Ubuntu-18.04.1

* Simulated development board: vexpress-a9

2.2 Tools used when setting up the environment

* qemu-4.2.0

* linux-4.4.157 (Linux Kernel)

* u-boot-2021.01

* busybox-1.31.1

* arm-linux-gnueabi-gcc

Put all related files in  /home/joe/qemu

3. Install cross-compilation tools

# sudo apt install gcc-arm-linux-gnueabi

 

Check if the installation is successful

$ arm-linux-gnueabi-gcc -v

Using built-in specs.

COLLECT_GCC=arm-linux-gnueabi-gcc

COLLECT_LTO_WRAPPER=/usr/lib/gcc-cross/arm-linux-gnueabi/7/lto-wrapper

Target: arm-linux-gnueabi

Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 7.5.0-3ubuntu1~18.04'--with-bugurl=file:///usr

Thread model: posix

gcc version 7.5.0(Ubuntu/Linaro 7.5.0-3ubuntu1~18.04)

 

4. Configure and Compile the Linux kernel

4.1 Download Linux Kernel

Download the required kernel version from www.kernel.org.

Here I download the relatively latest long-term supported kernel version linux-4.4.157

wget https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.4.157.tar.xz  to /qemu directory

4.2 Unzip the Linux kernel

# tar xvJf linux-4.4.157.tar.xz

4.3 Compile Linux Kernel

// Enter the kernel source file directory

# cd linux-4.4.157

make CROSS_COMPILE=arm-linux-gnueabi- ARCH=arm vexpress_defconfig

make CROSS_COMPILE=arm-linux-gnueabi- ARCH=arm menuconfig

If running menuconfig shows that the ncurses package is missing, just run the following command to install it)

$ sudo apt-get install libncurses5-dev

Enter the menu configuration and make the following settings

Kernel menuconfig System Type option with Enable the L2x0 outer cache controller left unchecked

Kernel menuconfig Kernel Features option with Use the ARM EABI to compile the kernel enabled

Compile with cross toolchain

Command make CROSS_COMPILE=arm-linux-gnueabi- ARCH=arm to compile the Linux kernel with the cross toolchain

After successful compilation, Generate a kernel image file under the directory

arch/arm/boot, zImage and dtb can be copied into a separate folder for convenient use

Commands copying zImage and the vexpress-v2p-ca9.dtb device tree out of arch/arm/boot

 

5. Install QEMU Tools

5.1 Install QEMU

* wget https://download.qemu.org/qemu-4.2.0.tar.xz

* tar xvJf qemu-4.2.0.tar.xz

* cd qemu-4.2.0

5.2 Install dependent packages before configuring QEMU

# apt install zlib1g-dev
# apt install libglib2.0-0 libglib2.0-dev
# apt install libsdl1.2-dev
# apt install libpixman-1-dev libfdt-dev

In order to prevent the files from being messy after compilation, create the builder directory as the intermediate target path for compilation.

Shell commands entering qemu-4.2.0 and creating a build directory for QEMU compilation

Configure, compile and install QEMU.

QEMU configure command with --target-list=arm-softmmu followed by make and make install

5.3 Configure QEMU to support all boards under the arm architecture

# ../configure --target-list=arm-softmmu --audio-drv-list=

If pixman is missing when the following prompt appears,

use sudo apt-get install libpixman-1-dev to install it.

5.4 View QEMU version

Terminal panel: qemu-system-arm --version reports QEMU emulator version 4.2.0

5.5 View development boards supported by QEMU

Terminal panel: qemu-system-arm -M help lists vexpress-a15 and vexpress-a9 ARM Versatile Express boards

5.6 Run QEMU

# qemu-system-arm -M vexpress-a9 -m 512M -kernel ./zImage -dtb ./vexpress-v2p-ca9.dtb -nographic -append “console=ttyAMA0”

OR:

$pwd

/home/joe/qemu

# qemu-system-arm -M vexpress-a9 -m 512M -kernel linux-4.4.157/arch/arm/boot/zImage -dtb linux-4.4.157/arch/arm/boot/dts/vexpress-v2p-ca9.dtb -nographic -append “console=ttyAMA0”

In order to better testing and start qemu, you can create the startup script start.sh, and give the script permission to run chmod +x start.sh

 

#!/bin/bash

 

qemu-system-arm \

-M vexpress-a9 \

-m 512M \

-kernel /home/joe/qemu/linux-4.4.157/arch/arm/boot/zImage \

-dtb /home/joe/qemu/linux-4.4.157/arch/arm/boot/dts/vexpress-v2p-ca9.dtb \

-nographic \

-append “console=ttyAMA0”

 

6. Make a root file system

Use busybox to make a simple root file system.

6.1 Download busybox tool

Download busybox from https://busybox.net/downloads/

# wget https://busybox.net/downloads/busybox-1.31.1.tar.bz2

# tar xjvf busybox-1.31.1.tar.bz2

# cd busybox-1.31.1

# make defconfig

# make CROSS_COMPILE=arm-linux-gnueabi-

# make install CROSS_COMPILE=arm-linux-gnueabi-

The following information is prompted, indicating that the installation is successful.

Busybox install message advising to make the busybox binary setuid root so all applets work properly

After the installation is complete, the generated target file defaults to the ./_install directory.

Terminal panel: ls _install/ shows the bin, linuxrc, sbin and usr directories created by busybox

 

6.2 Generate root file system

6.2.1 compile and install busybox

# mkdir rootfs

# sudo cp -r _install/* rootfs/

6.2.2 Add glibc library, add loader and dynamic library in the root file system

# sudo cp -r _install/* rootfs/

# sudo cp -p /usr/arm-linux-gnueabi/lib/* rootfs/lib/

6.2.3 Create 4 tty terminal devices (c stands for character device, 4 is the major device number, and 1~4 are the minor device numbers respectively)

Commands creating rootfs/dev and four tty character devices with mknod

 

6.3 Make SD card file system image

6.3.1 Generate an empty SD card image

# dd if=/dev/zero of=rootfs.ext3 bs=1M count=32

6.3.2 Format SD card as ext3 file system

# mkfs.ext3 rootfs.ext3

6.3.3 Burn rootfs to SD card

# sudo mount -t ext3 rootfs.ext3 /mnt -o loop

# sudo cp -rf rootfs/* /mnt/

# sudo umount /mnt

 

7. Verify

7.1 Start Qemu

Run the following command to test, check if the compiled kernel can run successfully

# sudo qemu-system-arm -M vexpress-a9 -m 512M -kernel ~/qemu/zImage -dtb ~/qemu/vexpress-v2p-ca9.dtb -nographic -append “console=ttyAMA0”

Or using Script:

Terminal running sudo qemu-system-arm with vexpress-a9, 512M memory, zImage, dtb and console=ttyAMA0

List explaining the QEMU options m 512M, kernel, dtb, nographic and append console parameter

 

In the above test, the kernel will report panic, suggesting that we lack the root file system.

QEMU boot log ending in kernel panic: VFS unable to mount root fs on unknown-block

The above problem is due to the busybox tool generated in the x86 environment.

We used make install when install busybox, so you should use

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- install

 

The compilation tool generates the busybox tool used by the arm platform

# file rootfs/bin/busybox

rootfs/bin/busybox: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-, for GNU/Linux 3.2.0, BuildID[sha1]=cbcd33b8d6c946cb19408a5e8e714de554c87f52, stripped

 

7.2 Verify again

QEMU boot log: ext3 root mounted, /etc/init.d/rcS missing, console active, uname -a shows Linux 4.4.157 armv7l

Now, Qemu has started the Linux kernel and mounted the file system successfully, and can interact with the system with simple functions through the serial terminal. The problem of not being able to run /etc/init.d/rcS in the printing process, you only need to add the /etc/init.d/rcS file. The content of the file can be a prompt statement.

Terminal panel: cat /etc/init.d/rcS prints the prompt line Hello Qemu Linux!

 

7.3 Exit QEMU

Two ways to exit qemu

* In another terminal input: killall qemu-system-arm

* In Qemu input:  Ctrl+A, then X

QEMU: Terminated

 

8. Start the Linux kernel through u-boot

Embedded system usually include: u-boot, kernel, rootfs, and appfs. The positional relationship of these parts on the ARM development board shown in the figure below

 

BootLoader BootParameters Kernel Rootfs Appfs

 

Rootfs can run in board or PC

 

8.1 Prepare U-boot

8.1.1 Download u-boot

https://ftp.denx.de/pub/u-boot/,   we use: u-boot-2021.01.tar.bz2

# tar -jxvf u-boot-2021.01.tar.bz2

8.1.2 Compile u-boot

# vim Makefile

CROSS_COMPILE = arm-linux-gnueabi-

# vim config.mk

ARCH = arm

u-boot config.mk before the edit: ARCH := $(CONFIG_SYS_ARCH:"%"=%) highlighted above the CPU settingsu-boot config.mk after the edit: the ARCH line set to ARCH := arm, highlighted above the CPU settings

# make vexpress_ca9x4_defconfig, error

Terminal error from make vexpress_ca9x4_defconfig in u-boot-2021.01 because bison is not found

Need :  sudo apt install bison

sudo apt install flex

Successful make vexpress_ca9x4_defconfig in u-boot-2021.01 writing configuration to .config

then:     # make -j4    error

Compiler error showing a bad value generic-armv7-a for the -mtune switch during make

Need :   export CROSS_COMPILE=arm-linux-gnueabi-

export ARCH=arm

again:  # make vexpress_ca9x4_defconfig

# make -j4

 

 8.1.3 Test, start u-boot

Terminal pwd command showing the working directory /home/joe/qemu

$ sudo qemu-system-arm -M vexpress-a9 -m 512M -kernel u-boot-2021.01/u-boot -nographic

 

8.2 Kernel configuration compilation

Use u-boot to boot the kernel image:

Need to compile the kernel into uImage format,

Need to specify the load address of uImage in memory

Specify when compiling the kernel: make LOADADDR=? uImage -j4

 

# cd /home/joe/qemu/linux-4.4.157

# make LOADADDR=0x60003000 uImage -j4

 

After u-boot compilation is finished, a mkimage file will be generated under the tool folder, copy this file to the bin folder under the cross compiler directory.

Command copying u-boot-2021.01/tools/mkimage into the cross compiler bin directory

Listing of /usr/arm-linux-gnueabi/bin showing mkimage alongside ld, nm and objcopy

$ cd qemu/linux-4.4.157

Command make LOADADDR=0x60003000 uImage -j4 run in the linux-4.4.157 directory

Error:

Build error stating the mkimage command was not found so U-Boot images will not be built

$ sudo apt install u-boot-tools

Rerunning make LOADADDR=0x60003000 uImage -j4 in the linux-4.4.157 directory

Get uImage

Build output stating arch/arm/boot/uImage is ready, confirmed with an ls command

9. QEMU network function settings

When the Qemu virtual machine starts on u-boot, uImage needs to be loaded into the memory, and uImage can be downloaded to the specified address in the memory through the TFTP server.

9.1 Check whether the host kernel supports the tun/tap module

Terminal ls /dev/net/ output showing the tun device present on the host

// Install the two tools that the bridged network depends on

# sudo apt install uml-utilities bridge-utils

Create tun device file: /dev/net/tun (usually created automatically)

Modify the /etc/network/interfaces (configure the network, restart to take effect)

# sudo vim /etc/network/interfaces

auto loiface lo inet loopbackauto enp0s3          // name of virtual network cardauto br0iface br0 inet dhcpbridge_ports enp0s3

Partial ifconfig output showing the enp0s3 interface and its inet address

 

9.2 Reboot

# reboot

Then check Qemu’s network environment

Partial ifconfig output after reboot showing the br0 bridge interface and its inet address

The virtual network port br0 is the network port for the communication between the Qemu virtual machine and the Linux host.

 

10. Install TFTP server

Create a TFTP server to download uImage to the memory when launching uImage for the Qemu simulation development board

 

10.1 Install tftp tool

 

$ apt-get install tftp-hpa tftpd-hpa xinetd

 

10.2 Modify the configuration file and set the TFTP server directory

# sudo vim /etc/default/tftpd-hpa

……

TFTP_DIRECTORY=”/home/joe/tftpboot”

……

10.3 Create a tftp directory on the Linux host

# mkdir /home/joe/tftpboot

# chmod 777 /home/joe/tftpboot

 

10.4 Restart the tftp service

# sudo /etc/init.d/tftpd-hpa restart

 

10.5 Set kernel startup parameters in u-boot

copy uImage and vexpress-v2p-ca9.dtb to tftpboot

Listing of the tftpboot directory containing uImage and vexpress-v2p-ca9.dtb

Start Qemu to verify

 

$ sudo qemu-system-arm -M vexpress-a9 -m 512M -kernel u-boot-2021.01/u-boot -nographic -net nic -net tap,ifname=tap0 -sd rootfs.ext3

 

Now, the rootfs directory is a simple root file system, which can be made into a mirror file, and the mirror file can be burned to the development board, or the Linux kernel can be started by u-boot in Qemu and mounted on the mirror file. It can also be set to boot via NFS network file system.

 

11. Mount NFS file system

11.1 Install and configure NFS service

11.1.1 Install

$ sudo apt install nfs-kernel-server

 

11.1.2  Configuration

$ sudo mkdir /home/joe/qemu/rootfs

$ sudo chown nobody:nogroup /home/joe/qemu/rootfs

$ sudo chmod 777 /home/joe/qemu/rootfs

$ sudo nano /etc/exports

Add:  /home/joe/qemu/rootfs *(rw,sync,no_root_squash)

 

Restart nfs server:

$ sudo /etc/init.d/nfs-kernel-server  restart

Or: $systemctl restart nfs-kernel-server

 

Check whether the NFS shared directory is created

$ sudo showmount -e

When using the NFS network file system, the Linux host needs to close the system firewall, otherwise, abnormalities will occur when the system is running.

 

Conclusion

Hopefully, with the help of this blog, you know more about QEMU. There’s not a single, fixed way to emulate with QEMU. Explore different techniques and see what works for you. Familiarize yourself with the knowledge and you will be surprised at how it can help you in unexpected ways.

Frequently asked questions

What can QEMU be used for in embedded Linux development?

If the debugging has nothing to do with peripherals, kernel debugging can be simulated with QEMU without purchasing hardware. It runs on Linux and Windows hosts and can emulate PowerPC, ARM, MIPS and SPARC targets.

What tools are needed to build an emulated ARM Linux environment with QEMU?

The example uses Ubuntu 18.04.1 (directly, or in VirtualBox on Windows 10), QEMU 4.2.0, a Linux kernel, u-boot, busybox 1.31.1 and the arm-linux-gnueabi-gcc cross-compiler, with the vexpress-a9 board as the simulated development board.

Why does the kernel panic when first booted in QEMU?

The first boot panics because the kernel finds no usable root file system. The busybox had been built for the x86 host, so it has to be rebuilt with make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- install. After that, QEMU boots the kernel and mounts the file system.

How do you exit QEMU?

There are two ways. Inside QEMU, press Ctrl+A and then X. From another terminal, end the process with killall qemu-system-arm. Either way, QEMU reports that it has terminated.

Can QEMU boot the kernel through u-boot?

Yes. Build u-boot with vexpress_ca9x4_defconfig, compile the kernel as a uImage with a load address (LOADADDR=0x60003000 in the example), and start u-boot in QEMU. The uImage can be loaded into memory from a TFTP server, and the root file system can be mounted over NFS.

New engineering articles by email.

Keep reading

Have a display project in mind?

Talk to an engineer about the display your application needs.