<<

Instituto Superior de Engenharia do Porto Mestrado em Engenharia Eletrotécnica e de Computadores Arquitetura de Computadores

Machine emulation with QEMU and cross-compilation

Introduction

This lesson addresses the execution of systems on software emulated machines using the QEMU software.

Two different machines will be considered, one with a x86-64 processor and another with 32 bit ARM processor. specifically, in the case of the ARM machine, the emulate processor is the ARM1176, the same processor core used, for instance, in the original board.

A Linux system is composed by the kernel - a , with a few megabytes , containing the basic services - and least a , the root file system. This file system should contain the essential directories (e.g., /dev), and required utilities (, ip) and software (e.g., web server). Typically, the kernel file (also known as kernel image) is stored in a different partition, the boot partition. Additionally, there is usually software that must be installed in specific places of the storage device, in order to support the initial phase of the system start-up (). This software is usually denominated boot loader (e.g., GNU GRUB). Finally, the system image is a file that contains the exact contents of the target storage device, including the boot loader, the boot partition and partition containing the root file system.

QEMU is a software for machine emulation, supporting several types of computers with processors from both architectures. The supported machines for the x86-64 can be queried using qemu-system-x86_64 -M ? while qemu-system-arm -M ? can be used to obtain the list of supported machines with A32 bit ARM processors. For a given machine, it is also possible to see the list of supported processors. For instance, to see the list of supported processors for the x86_64 default machine, : qemu-system-x86_64 -cpu ?

Both programs (qemu-system-arm and qemu-system-x86_64) share some features and common command line parameters. Of special interest is the capacity of acting as a boot loader for Linux systems. By using, the -kernel parameter, it is possible to specify the file containing the kernel of the Linux system to be used in the emulated machine. Therefore, it is not necessary to a boot loader nor to include the Linux kernel in the system image.

Machine emulation with QEMU and cross-compilation 1/7 ARCOM – MEEC – ISEP – 2020/2021

Exercises

Create a new (e.g., lab2) to store all the files and directories mentioned in the following exercises. As a good practice, since the computers can be used by several students, this directory should be under a directory named upon you student number or name. i.e.: -p ~/student_number/lab2 ~/student_number/lab2

1- The x86_64 system

Building the core commands and utilities

We will start by creating a very simplistic root filesystem image, containing a shell and a small set of commands (, , , , mount, free, ). To obtain those commands, we will use the BusyBox utility. BusyBox provides, in the same , a wide variety of traditional commands for Unix-like systems.

In what follows, we’ll configure and compile BusyBox to provide a shell and both the ls and uname commands. Check Busybox’s homepage, and download the source code of the latest stable version to your project directory (alternatively, you can use the version available at the web page). For instance: http://busybox.net/downloads/busybox-XXX.tar.bz2

Extract the archive files: xvf busybox-XXX.tar.bz2

Change the current directory to the created folder. Configure and compile BusyBox: allnoconfig

# Invoke setup menu (requires qt3-devel package) make xconfig #or, for text mode (requires ncurses-devel package): make

Choose the following options:

• Under "Settings" (right side panel): • “Include busybox applet” • Below "Settings -> Build Options": • "Build BusyBox as a static binary" • Below "Settings -> Tuning" (but not immediately following): • “Command line editing” • Back to the left side panel, below "Applets": • Coreutils -> cat, df, ls, uname • Linux System utilities -> mount

Machine emulation with QEMU and cross-compilation 2/7 ARCOM – MEEC – ISEP – 2020/2021 • Process utilities -> free, ps • Shells -> ash. Make sure that the “Use internal glob() imple- mentation” sub-option is selected.

Save your configuration, the configuration screen and generate the executable1: make -j 2 #if you have a quad core CPU, use -j 4

At the end of the procedure, you should the busybox file in the current directory. file busybox cd ..

Creation of the root file system image

In the initial , type: if=/dev/zero of=rootfs-x86_64.img bs=4M count=1

The above command creates an empty file with a size of 4MiB. This file will be used as a virtual storage device. It will contain the root file system of our minimal Linux system.

Create a directory to use as a mount point for the file system in rootfs-x86_64.img. mkdir m

However, at this point, rootfs-x86_64.img is still blank. Next, we will create an empty EXT4 file system on rootfs-x86.img (using the .ext4 command), and we will mount it on m. These operations must be performed as root: mkfs.ext4 rootfs-x86_64.img mount rootfs-x86_64.img m

From this point on, every operation on m will be reflected to the file system in rootfs- x86_64.img. Let us start by creating some of the standard directories: cd m mkdir bin dev proc

Finally, copy the busybox executable to the bin directory of the target file system and create the auxiliary symbolic links that provide access to the commands chosen during the configuration phase:

1 In case of error, make sure the glibc-static.i686 and glibc-devel.i686 packages are installed (dnf install)

Machine emulation with QEMU and cross-compilation 3/7 ARCOM – MEEC – ISEP – 2020/2021

../busybox-XXX/busybox bin/ #replace XXX with the correct suffix cd bin -s busybox cat ln -s busybox ps ln -s busybox df ln -s busybox free ln -s busybox ls ln -s busybox uname ln -s busybox mount ln -s busybox ash cd ../.. umount m #unmount rootfs-x86_64.img exit ls m

After this sequence of commands, the m directory should be empty. That can be verified by the output of the ls m command.

Emulation

For simplicity, the Linux kernel will be the one used by the machine. Therefore, to start the emulation of our minimal Linux system, type: qemu-system-x86_64 -kernel YYY \ -append "root=800 =/bin/ash" \ -drive file=rootfs-x86_64.img,format=raw where YYY should be the absolute pathname of the kernel image used by your system (e.g., /boot/vmlinuz…). Check the /boot directory to find out the complete file name or just use the tab key to autocomplete.

Write down the output of the following commands (the commands should be executed in the emulated machine). Note that you can use the shift+”page up” and shift+”page down” key combinations to scroll the screen output up and down. mount -t proc proc /proc cat /proc/cpuinfo #just the model name field free #just the first line df ps # just the processes not enclosed in [] # and just the PID and Command columns

Machine emulation with QEMU and cross-compilation 4/7 ARCOM – MEEC – ISEP – 2020/2021 2 - The ARM system

Building the core commands and utilities

As for the x86_64 case, we will build a root file system based on the BusyBox utility. However, in this case, it is not possible to use the host compiler and to build the executable, since this Fedora distribution supports development just for x86 targets. In order to do that, a cross- compilation toolchain for the ARM processor will be required. Typically, a toolchain contains compiler(es), an assembler, a linker and the main libraries (e.g., the library). It may also include additional development tools (e.g., debugger, code profiler). A cross-compilation toolchain allow us to build software to architectures other than the host architecture. There are publicly available pre-built cross-compilation toolchains for ARM processors (see, e.g., https://elinux.org/Toolchains). In the present case, we will use a prebuilt toolchain specially targeted for the Raspberry Pi system using the software. Buildroot allows us to create a toolchain from the scratch, and, in the process, to choose the suitable versions of the compiler and C library, among several other configuration parameters. This tool will be studied in more detail in future lessons. The toolchain is available in the lesson webpage.

Download the toolchain file and extract its contents.

Create a copy of the BusyBox build directory: cp -a busybox-xxx busybox-arm (where xxx is the busybox version in use)

Cross-compile busybox: cd busybox-arm make clean make CROSS_COMPILE=ZZZ where ZZZ is the absolute pathname prefix to the toolchain utilities in your system (for instance, "/home/arcom1x/student_number/lab2/arm-buildroot-linux- uclibcgnueabihf_sdk-buildroot/bin/arm-linux-").

Check if the generated file has the correct architecture (ARM): file busybox

Creation of the root file system image cp rootfs-x86_64.img rootfs-arm.img su mount rootfs-arm.img m cp busybox-arm/busybox m/bin/ umount m exit

Machine emulation with QEMU and cross-compilation 5/7 ARCOM – MEEC – ISEP – 2020/2021

Emulation

For this system, we will use the kernel-qemu-4.14.50-stretch kernel image and associated device blob/binary (DTB) file (obtained from https://github.com/dhruvvyas90/qemu-rpi-kernel). Both files are provided in the web page. qemu-system-arm -M versatilepb -cpu arm1176 \ -kernel kernel-qemu-4.14.50-stretch \ -dtb versatile-pb.dtb \ -append "root=800 init=/bin/ash console=tty1" \ -drive file=rootfs-arm.img,format=raw

Take note of the output of the following commands: mount -t proc proc /proc cat /proc/cpuinfo #just the model name field free #just the first line df ps # just the processes not enclosed in [] # and just the PID and Command columns

Summary During this class you should have become familiar with the following tools, procedures and concepts: • dd, to transfer data from one file to another (eventually creating the latter)2 • Using a file as virtual drive • mkfs.ext4, to create an empty EXT4 file system on a storage device (a virtual one, in this case) • mount, to manually mount a file system onto a directory (mount point). • It is possible to use a gcc based cross-compilation toolchains to build programs to an architecture other than the host architecture (in this case, the target was the ARM architecture while the host was x86_64 system) • qemu-system-x86_64, to emulate a x86_64 PC • qemu-system-arm, to emulate a 32 bit system (from the given set of supported machines and processors) • Using the -kernel and -append QEMU parameters to avoid the installation of the and Linux kernel image on the emulated system.

2 The origin of the name of this command is uncertain. You can think of it as one of the following combinations “Data/Disk/Device ”. Machine emulation with QEMU and cross-compilation 6/7 ARCOM – MEEC – ISEP – 2020/2021 Document • 2018-10-01 – created by Jorge Estrela da Silva ([email protected])

Machine emulation with QEMU and cross-compilation 7/7 ARCOM – MEEC – ISEP – 2020/2021