2022/09
qemu
qemu-user
qemu-architecture
qemu-system-architecture
(2022/9/18) QEMU for beginner, starting from few simple examples so to reduce the hurdle to get familiar with qemu.
(latest update on 2022/10/1)
Table of Contents
From Linux Q&A-What is qemu?, we learn that there are 3 modes supported by qmue:
QEMU user mode
It is much more easier to try with QEMU user mode. Users just need to be familiar with Linux shell command, and a basic programming skill, hello world level, in C language. We will start with 2 examples :
QEMU system mode
After then, the third example will be running QEMU system mode. To run QEMU system mode, it requires an image file containing a complete operating system to run, instead of a single Linux program to run on QEMU user mode. First we pick an old Linux version running on i386. Then pick the target of Raspberry Pi, which is a very popular SBC (Single Board Computer) based on ARM CPU. We will use the Raspberry Pi image, running Debian based Linux called Raspbian, on QEMU system mode simulation.
One (easy, but not recommended) way to install qemu
is to use package installation. It will install both both user
and system
modes of qemu
. However, it installed qemu version 2.5.0
on Ubuntu 16.04, which is relatively old version.
Recommend to use newer version, by following instruction from https://www.qemu.org/download/
. By the time I download, the latest version was 7.1.0
. It requires Python 3.8
than Ubuntu 16.04
default Python 3.5
. So I chose version 5.0.0 arbitrarily which just works.
Check Linux Q&A: QEMU - nothing shows up after QEMU VNC server running for explanation of qemu ./configure
option.
qemu-x86_64
and qemu-i386
hello world
on Linux native environmemtWith x86_64 system used for Linux, qemu is not really needed to run x86_64 programs like hello_world
. However, we still can use qemu to simulate x86_64 program, like we do for native x86_64 program.
Let's start with hello world
program running on Linux native x86_64 environment.
use vi
or other editor program to create hello.c
file content like below
then compile and execute hello
program on Linux
We can check the file attribute with Linux command file
to see the attritube of hello
is executable at x86_64 ELF 64-bit LSB mode, and hello32
is executable at Intel 80386 (nornally use i386 for short) ELF 32-bit LSB mode.
hello world
on qemuFirst, we install qemu
user mode and run the hello
program.
Keep in mind that the naming convention of qemu user mode command is qemu-arctecture
where architecture can be arm
(ARM 32bit version), aarch64
(ARM 64bit), i386
(x86 32bit), x86_64
(x86 64 bit), etc. In next section, we will introduction qemu system mode. The naming convention is qemu-system-architecture
. You can see what the difference is.
Let's see how we can execute the hello
programs on qemu.
Till now, it is quite easy and straight forward to use qemu
to simulate and run x86 programs.
qemu-aarch64
To run QEMU simulation for ARM CPU, we need, at least, a hello world
program in ARM binary code to demostrate qemu-arm
and qemu-aarch64
features. We are going to build the hello world
binary by installing the cross compiler of gcc
for ARM first.
We can build ARM binary code on x86 CPU with cross compiler. 'Cross' means to build a binary code for one CPU when it is running on another CPU. x86 is the one of the most popular and power CPU. We can use it to build the binary code for another CPU, like ARM, RISC-V, or other embedded types of CPU, which can save development and compilation time due to powerful x86 CPU, and many tools available.
According to wikipedia, a toolchain is a set of programming tools that is used to perform a complex software development task or to create a software product, which is typically another computer program or a set of related programs. In general, the tools forming a toolchain are executed consecutively so the output or resulting environment state of each tool becomes the input or starting environment for the next one, but the term is also used when referring to a set of related tools that are not necessarily executed consecutively.
A simple software development toolchain may consist of a compiler and linker (which transform the source code into an executable program), libraries (which provide interfaces to the operating system), and a debugger (which is used to test and debug created programs).
We use the following command to install ARM64 gcc
tool chain, using the same hello.c
as in Running hello world on Linux native environmemt
Now we have a executable ARM64 binary of hello-arm64
, which can be executed on QEMU. We can find the file attribute of hello-arm64
is ELF 64-bit LSB executable based on ARM aarch64.
Now we succeed in running qemu-architecture
to simulate ARM CPU in user mode. Next is to run qemu-system-architecture
in system mode.
qemu-system-i386
It requires an OS image to run in QEMU system mode. We use old Linux 0.11 version as it is relatively simple.
Check the following www.oldlinux.org
web and copy the link of file 'Linux 0.11 on qemu-12.5.i386.zip'
The link is http://www.oldlinux.org/Linux.old/qemu-images/Linux 0.11 on qemu-12.5.i386.zip.
Now follow the commands to execute qemu-system-386
.
Now Linux 0.11 is running on qemu-system-i386
. You may find many commands not found, like uname
, lspci
, lscpu
, etc. Those available are vi
, awk
, fdisk
, but there are i386 assembler as86
, linker ld86
programs available, and gcc
and hello.c
as well.
qemu-system-arm
running Raspberry Pi in command modeNow come to more challenging one. I failed so many time trying to get Raspberry Pi image working. The easiest way is to create a script file of the following content, from this article.
Though I don't know why and how this script works. At least, it proves to be working, non-GUI mode (maybe due the the image is 'lite' version). The next step is to work on Raspberry Pi version with GUI mode (next example), and understand how it works. Check :arrow_right:Next article - QEMU for Advanced
Below are some screen shots.
Fig. - Running shell script to launch qemu
Raspberry Pi image. qemu
create another screen, though showing nothing.
Fig. - Same as above, without qemu
screen
Fig. - Boot up sequences show Welcome to Raspbian GNU/Linux 10 (buster)!
Fig. - Prompt for login user id and pass word input. The standard ones are pi
and raspberry
respectively.
Fig. - Successfully login to Raspbian
Fig. - Shell command uname -a
to check Linux kernel version
qemu-system-arm
running Raspberry Pi in GUI modeFollowing from previous examples and Emuation using Qemu's native raspi2/3 machine, we modified the script by using newer Raspberry Pi images of full version, so we can run startx
command in RPi to enter GUI mode.
Here is the script.
After launch Raspberry Pi successfully (Difference is, this time, it shows on qemu
screen, instead of terminal
due to removal of qemu -nogrphic
option). If qemu
screen still shows in command line mode, we can enter Raspberry Pi specific command startx
to ente GUI mode.
Below are some screen shots.
Fig. - Launch shell script to download files from internet, including .img, .dtb, kernel. After downloading the image files, and it takes some time to boot up qemu
, at that moment I suspect the system was down, but not.
Fig. - qemu
launch Raspberry Pi (on another screen)
Fig. - qemu
lauch Raspberry Pi into GUI mode
Fig. - Raspberry Pi GUI boot from qemu
Fig. - Raspberry Pi terminal
shows the Linux kernel version
Fig. - Raspberry Pi running a game. Unfortunately, it does not support mouse operation. That requires further mouse driver setting at qemu
.
This is a separate line to distinguish between Beginner and Avanced
2022/09
qemu
qemu-user
qemu-architecture
qemu-system-architecture
(2022/9/23) QEMU for advanced, after completing previous examples, moves on to next step to build own version of kernel images for any x86 Linux and Raspberry Pi BIOS images
(latest update on 2022/10/8)
So far, we use the images and kernel from the internet prepared by others. It will not work with combination of newer firmware with older kernels (I tried and failed so many timmes). I am tringing to see how to generate the kernel file from official Raspberry Pi images so we can upgrade the firmware and running under qemu
. Also try to understand the parameters of qemu
so we can experiments more, like ssh
to QEMU RPi. Or we can use the mouse in Raspberry Pi GUI mode.
Before jumping into examples, there are couples of prerequisites.
qemu-system-
examples of different optionsqemu-system-
Block Device Optionsqemu-img
usagelosetup
(my preference) or mount, or nbd
to check the contents of img
, .iso
, and so on images files.qemu-system-
examples of different optionsI found it is not easy to set the qemu-system-
options right to get it working, there are basic options needed to launch qemu-system-
successfully. Few examples are listed.
-kernel kernel*
and -dtb *.dtb
Option 1 for qemu-system-arm
: Use -drive
console=ttyAMA0
can be removed from -append
, no impact.panic=1
(or any number N
to replace 1
) in -append
, it asks qemu-system-
to wait 1
(or N
) seconds before system to reboot due to kernel panic.-M
is selected, no need to specify -cpu
, as CPU is machine dependent. But when I use -M versatilpb
and remove -cpu arm1176
, it does not work.-net user,hostfwd=tcp::2222-:22 -net nic
: set up the networking stack and forward the SSH port. Trying to use, but failed -device virtio-net-device,netdev=unet -netdev user,hostfwd=tcp:127.0.0.1:2222-:22,id=unet
Option 2 for qemu-system-arm
: Use -hda
Replace the line
-drive "file=2019-09-26-raspbian-buster-lite.img,index=0,media=disk,format=raw"
by
-hda 2019-09-26-raspbian-buster-lite.img
.
Check qemu-system- : QEMU Block Device Options for more detail explanation.
Option 3 for qemu-system-arm
: Use .qcow2
as the image file.
Then replace the line
-drive "file=2019-09-26-raspbian-buster-lite.img,index=0,media=disk,format=raw"
by
-hda disk.qcow2
Option 4 for qemu-system-arm
: Add -blockdev
option
It works though not sure if improves or not. However, need to input the file name in both -drive
and -blockdev
, or it reports error.
Option 5 for qemu-system-arm
Use root=/dev/mmcblk0p2
See below QEMU Advanced Example 2 : Build Raspberry Pi image from downloaded image and buildroot for kernel and .dtb for 32 bit ARM
Option 6 for qemu-system-arm
: Add -device virtio-blk-device,drive=hd0
option when -M virtio
is selected. It won't work with -M versstilepb
.
Check below option 11 for example. The reason why it failed with -M versatilepb
is explained in this article stackoverflow - Enabling virtio_blk_device for qemu.
virtio-blk-device is a VirtIO device that relies solely on memory-mapped IO (MMIO) and not on the PCI-bus. This does not work with Qemu's default machine type pc-i440fx-X.Y, or at least not out of the box.
Similarly, it failed for -M versatilepb
to support -device virtio-net-device,netdev=unet
with error message below.
-kernel vmlinuz
and -initrd initrd.gz
or initrd initrd.img
Option 11 for qemu-system-arm
Option 12 for qemu-system-aarch64
qemu-system-aarch64 -M virt -cpu cortex-a57 -smp 2 -m 1024 -nographic
: run the ARM64 virtual platform emulator with 1GB RAM (or can input as -m 1G
) and 2 Cortex-A57 cores with no GUI support.
-drive if=none,file=ubuntu-16.04-server-cloudimg-arm64-uefi1.img,id=hd0
: use the Ubuntu image file
-device virtio-blk-device,drive=hd0
: mount drive from above as a block device
-drive file=user-data.img,format=raw
: use the configuration data image file
Check QEMU document page 34 about Block device options
The QEMU block device handling options have a long history and have gone through several iterations as the featureset and complexity of the block layer have grown. Many online guides to QEMU often reference older and deprecatedoptions, which can lead to confusion. The recommended modern way to describe disks is to use a combination of
-device
to specify the hardware device and-blockdev
to describe the backend. The device defines what the guest sees and the backend describes how QEMU handles the data.
qemu
can support many formats, qcow2
format is recommended.
.qcow
is a file format for disk image files used by QEMU. It stands for "QEMU Copy On Write" and uses a disk storage optimization strategy that delays allocation of storage until it is actually needed. Files in qcow format can contain a variety of disk images which are generally associated with specific guest operating systems. Three versions of the format exist: qcow, qcow2 and qcow3. From wiki-qcow
Check Native emulation of Rpi2/3 using Qemu's Raspi2/3 machine, and Rasbperry Pi Linux kernel for more details
.img
and .iso
mount
for .img
Check the content of OS images by mount
ing images to Linux drives.
You should see something like this:
You see that the filesystem (.img2) starts at sector 532480. Now take that value and multiply it by 512, in this case it’s 512 * 532480 = 272629760 bytes. Use this value as an offset in the following command:
Similarly for .img1
, which contains the kernel
and .dtb
.
Read Raspberry Pi on QEMU for more details
mount
for .iso
Check Building a Debian Buster QEMU image for AARCH64 for more details
I succeeded in following this article Building a Debian Buster QEMU image for AARCH64, after upgrading to qemu version 5.0.0
on my Ubuntu 16.04 by source compiling.
This article serves my intention well to use any downloadable Linux image and extract initrd
and vmlinuz
from that image required for qemu
. So it is a 2-step approach.
disk.qcow2
content can be empty for now. It is recommended to use the format of .qcow2
Copy-On-Write format.qemu-system-aarch64
by using the following command.After successfully launching the Debian image, it starts installation which takes really some time. (Remember the root
password you key in, and user id and password you create.) After installation complete, the system prompt
Click <Continue>
(When I tried another example by installing Ubuntu (not Debian), it reports an error message. This error can be ignore and skip the step of installing boot loader, then complete rest of the installation.)
and now, we can press CTRL-a, then x
to quie qemu
.
disk.qcow2
with initrd
and vmlinuz
I add hostfwd=tcp:127.0.0.1:2222-:22,
(not in original article) after -netdev user
to allow host to ssh
via -p 2222
Now we can run Debian on qemu
of ARM 64bit aarch64 architecture for any Debian images in the future. Or in theory, for all architectures.
A : This example combines the following articles
buildroot
and how to make
.buidroot make bcmxxxx_defconfig
for different Raspberry Pi boards.qemu command line and options
with kernel zImage
and .dtb
from buildroot
, and .img
from downloads.raspberrypi.comBelow are the commands for this example:
A : This example follows Raspberry Pi Documentation - The Linux kernel
Enter the following commands to build the sources and Device Tree files. There are several config's for ARM 32 bits or 64 bits, and different versions of kernels (refer to above article for more details). I pick this one of Pi 3+, which I am familiar with.
Note
To speed up compilation on multiprocessor systems, and get some improvement on single processor ones, use make -j n
, where n is the number of processors. You can use the nproc
command, like make -j $(nproc)
to see how many processors you have. Alternatively, feel free to experiment and see what works!
The file locations are scattered across serveral directories:
Launch qemu
with the options from previous example.
Unfortunately, it failed to boot, and stopped at
There are some information mentioned in stackexchange - Kernel and QEMU : Unable to mount root fs error, which maybe worthwhile to spend some time to look into it in more details.
This error message means that the kernel is unable to mount the partition you requested to be /. This would happen for example if you gave it an empty disk image (my hunch is this is your case) - the kernel in the VM sees an unpartitioned drive, there is no /dev/sda1 just /dev/sda. To overcome this follow the instructions in the guide you have used - download a bootable ISO image and use it to install system into the VM image. When raw disk image is used, it can be directly partitioned with utilities like gdisk, fdisk or parted.
Another possibility is, that there you are trying to mount a filesystem for which the kernel doesn't have a driver. This usually happens when one uses a kernel, that has most drivers in loadable modules on initrd and the initrd isn't loaded (hence the kernel lacks the ability to understand the particular filesystem).
If you made a full installation of Debian, I would expect it having installed the kernel as well. Hence it should be possible to bring up the VM without the -kernel option at all, since the VM BIOS should be able to boot the installed system right away as a real BIOS would do - by loading bootloader from MBR (or EFI partition, although the UEFI support in Qemu/KVM is still rather new AFAIK).
vmlinuz
and initrd.gz
) for 32 bit ARMFollow this article Easy way to run qemu Debian OS - 使用qemu-system-arm安裝系統(armhf) to run qemu
from download image.
Suse - Running Virtual Machines with qemu-system-ARCH REPORT DOCUMENTATION - Using Devices in QEMU : Quite some useful tips to run QEMU.
QEMU related articles and issues
qemu
application I learned so far.QEMU examples programs from internet
qemu
application I learned so far.
qemu
. It is worthwhile to spend time to study more here.qemu
.QEMU Q&A
qemu-system-i386: -m 16: drive with bus=0, unit=0 (index=0) exists
, fix it with 可以把參數重新用手動輸入的方式敲,不要直接複製,因爲複製過程中可能複製了一些我們沒注意到的字符導致程序不識別;
I download the Rapsberry OS
image
https://downloads.raspberrypi.org/raspios_armhf/images/raspios_armhf-2021-01-12/2021-01-11-raspios-buster-armhf.zipthe kernel kernel-qemu-4.19.50-buster and versatile-pb-buster.dtb
from https://github.com/dhruvvyas90/qemu-rpi-kernel and run with
version 5.2.0:$ qemu-system-arm -dtb ./versatile-pb-buster.dtb -kernel ./kernel-qemu-
4.19.50-buster -cpu arm1176 -m 256 -M versatilepb
Cross compiler
Raspberry Pi related
Buildroot
Linux boot sequence
Cross compiler
:arrow_left:Previous article - back to marconi's blog
:arrow_right:Next article - QEMU simulation ith hardware board
:arrow_up:back to marconi's blog