QEMU ELI5 — Part 4, Machine, CPU & More

Tuna Cici
8 min readJun 10, 2023

--

QEMU But For Beginners | Part 4 — Machine, CPU & More

This story is a copy of my original GitHub repository called QEMU_Starter. Also available at https://github.com/TunaCici/QEMU_Starter

Previous Part 3. Hello World

Configurations

Like every machine in the real-world, every QEMU machine can be different. The CPU architecture, memory size, devices, disks, displays and so on. Each of these settings can be customized. For example, you can create a QEMU machine with Cortex A72 CPU, 8GiB RAM and devices like USB-Storage, Intel E1000 Network Card, AHCI HDD, UART, Console... QEMU is greatly configurable. You have many devices and options to choose from!

You can basically create your own machine. Just like building a custom computer!

QEMU is capable of emulating many devices and CPUs!1 However, as you know already, emulation is expensive! If your intention is to have a performant, maybe even near-native, machines then using emulated devices is not a good choice. Especially emulating a CPU architecture.

To achieve good performance QEMU needs to act like a Virtual Machine with the help of configurations like Accelerators and Virtiodevices. Now, at this exact point we are faced with two options:

  • Use QEMU as an Emulator: In this approach, QEMU emulates all the hardware devices and the CPU architecture. This is the default mode of operation and is suitable for compatibility with a wide range of guest operating systems and architectures. However, the performance might not be optimal due to the overhead of emulation.
  • Use QEMU as a Virtual Machine: In this approach, QEMU is configured to take advantage of Accelerators, such as KVM or leverage hardware device virtualization (aka. virtIO). VirtIO devices are paravirtualized devices that offer efficient communication between the guest and host OS.2 By using these technologies, QEMU can achieve significantly better performance and reduce the emulation overhead.

More on virtIO devices later. They are pretty cool and useful! You can also configure QEMU to be half emulator and half virtualizor. For example, using KVM in combination with the Intel E1000 Network Card.

How you configure your QEMU machine will depend on your specific needs. If performance is a priority, utilizing QEMU with Acceleratorsand virtIO devices is highly recommended. Now, enough talking. Let's go over the configurations!

Important Note: Some qemu-systems might have additional configurations. However, the ones explained in this guide should be more than enough. If you want to learn more, be sure to check the given references!

Machine

Usage (type -machine help to get a list of all targets):

$ qemu-system-x86_64 -machine [target]

Specifies which machine to be emulated. Defines some base values such as the CPU, memory and devices. For example the machine pc-i440fx represents a classic PC based on the Intel 440FX chipset. The specific default values can vary depending on the machine type and version. In the case of the pc-i440fx machine type, the default configuration includes an Intel Pentium processor, 128MB of RAM, and other standard PC components.

Another good example would be the raspi3b machine. This machine, as you might have guessed, represents a Raspberry Pi 3b that has Cortex A53 (4 cores) and 1GiB RAM.

More about raspi3b here: https://www.qemu.org/docs/master/system/arm/raspi.html

Important Note: Any of the default values can be overridden! It is pretty common to do so. This means you can have a raspi3b with 16GiB RAM!

Which machine should you choose can be confusing. There might be too many options. If you are confused use either of the following machines:

  • q35: Represents a modern PC (Available on qemu-system-x86_64) 3
  • virt: Represents a machine suitable for virtualization (Available on qemu-system-aarch64) 4

CPU

Usage (type -cpu help to get a list of all CPUs)

$ qemu-system-x86_64 -cpu [target],[features]

Specifies which the CPU to be emulated. Defines the CPU architecture (ARMv8, x86…), ABI, layout (NUMA), core count, caches, registers, and feature flags. For example Cortex A53, will define an ARMv8-A CPU with 2 Cores @ 2.00GHz and L1-2-3 Caches. The exact numbers and CPu features depends on your QEMU version and the type of machine you use.

Additionally, you can set some CPUID feature flags. Each CPU has different features that can be enabled/disabled. The code snippet at the start will also list all available CPUID flags. For example, to define a Intel Core i7-8700K CPU with AVX (Advanced Vector Extensions) use:

$ qemu-system-x86_64 -cpu SandyBridge,+avx

The official QEMU documentations doesn’t really help you on how CPUID flags can be used or implemented. If you know a good source on this, feel free to contact me!

Which CPU and CPUID flags should you choose can be, again, confusing. If you are confused use the following CPU:

  • host: Passes the host CPU model features, model, stepping, exactly to the guest. (Requires an Hypervisor) 5

Core Count (vCPU / SMP)

The -cpu [target] option in QEMU defines a default core count (vCPU). However, you may want to increase it to improve performance. To do so, you can combine the -cpu option with -smp. For example, to define a Cortex A53 CPU with 8 Cores, use -smp 8:

$ qemu-system-aarch64 -cpu cortex-a53 -smp 8

Symmetric MultiProcessing (SMP) is used to specify the number of virtual CPUs (vCPUs) for the QEMU machine.6 Increasing the core count can enhance the performance of your guest OS, provided that your host CPU has enough cores. Therefore, it is highly recommended to specify the -smp option in your QEMU virtual machines.

Accelerator

The -accel [hypervisor] option in QEMU defines the Hypervisor to be used. This uses Hardware Acceleration (Optional) to speed up the -cpu substantially. Refer to the previous sections for more information about accelerators and Hypervisors.

In order to use the -accel option, the compatible -cpu option needs to be defined. Also, the qemu-system-* you are using MUST be similar to your host's architecture. For example, qemu-system-x86_64 can only be used with -accel option if your host CPU is also x86_64.

Here’s a quick checklist to see if your guest machine can be used with -accel option or not.

If you pass both of these, then you can safely use the -accel option. By the way, this is also knows as virtualization. It is a big topic, I know. Refer to previous sections for more info on this.

The -accel [hypervisor] needs to know which Hypervisor to use. Here's the current list of Hypervisors supported by QEMU:

  • kvm: On GNU/Linux systems (a.k.a Linux-KVM)
  • whpx: On Windows 10/11 systems (a.k.a Hyper-V)
  • hvf: On Apple macOS systems (a.k.a Hypervisor.Framework)

Again, refer to Hardware Acceleration (Optional) for more information on them.

An example usage of -accel [hypervisor]:

$ qemu-system-aarch64 -cpu host -smp 4 -accel hvf

Memory

Usage (type -m help for more information):

$ qemu-system-x86_64 -m [size]

Specifies the amount of memory (RAM) allocated to the guest. The amount of memory is immediately allocated. Meaning, if you specify a 4GiB RAM than that fixed amount of memory is given to the guest and does NOT dynamically shrinks/grows.

The important thing to note here is that the amount of memory you specify should be within the limits of your host system’s available physical memory. Allocating excessive memory to the virtual machine may impact the performance of both the host and the guest.

The default [size] unit is Mebibyte (MiB). Meaning -m 1024 will be equal 1024 MiB (1GiB). You can, however, specify the memory size using suffixes like k, M, G, T. They, in order, refer to kibibyte, Mebibyte, Gibibyte and Tebibyte.

An example machine with 4GiB would use:

$ qemu-system-x86_64 -m 4G

Disks

Usage (for help refer to QEMU Source Code):

$ qemu-system-x86_64 -drive [option],[option],[...]

Specifies a new drive. Generally defines a storage device, such as a disk image, that can be attached to the machine. It allows you to configure the storage options and provide access to files or block devices within the machine. You can specify more than one drives.

Sound complicated? Well, think of this options as an SSD, HDD or any type of Storage device that is attached to the machine.

As you can see from the Usage, -drive has many options. The exact list of options depends on your QEMU version and qemu-system. However, most of the time you will using just a few of them. Here is a list of the most commonly used -drive options.

Important Note: Most of the time you will be using multiple options. For example, file=[option], is commonly used in combination with format=[option]. Which options should you use depends on entirely your needs.

file=[option]

Specifies the path to the disk image file. An example usage would be:

$ qemu-system-x86_64 -drive file=/home/mike/machines/disks/archlinux0.img

index: Specifies the index or position of the drive attachment. media: Specifies the type of media, such as disk, CD-ROM, etc. snapshot: Enables snapshot mode for the drive.

format=[option]

Specifies the format of the disk image. Commonly used formats include raw, qcow2, vmdk, etc. An example usage would be:

$ qemu-system-x86_64 -drive file=archlinux0.qcow2,format=qcow2

If not specified, QEMU will try to guess the file format. It is recommended to specify a format just in case. Refer to qemu-img for more information on formats.

if=[option]

Specifies the interface type of the storage device. The guest must include the necessary driver. Commonly used interfaces include IDE, SCSCI, VIRTIO, PFLASH etc. An example usage would be:

$ qemu-system-x86_64 -drive file=archlinux0.qcow2,format=qcow2,if=virtio

index=[option]

Specifies the index or position of the drive. The order of drive is important if you have multiple drives specified. Generally, Bootloaders will try to boot the first drive. The index order depends entirely on your needs. An example usage would be:

$ qemu-system-x86_64 -drive file=archlinux0.qcow2,format=qcow2,if=virtio,index=1 \
-drive file=ubuntu0.qcow2,format=qcow2,if=virtio,index=2

media=[option]

Specifies the media type of the drive. Commonly used options include cdrom, disk, etc. An example usage would be:

$ qemu-system-x86_64 -drive file=windows11_setup.img,format=raw,if=virtio,index=1,media=cdrom

readonly=[option]

Specifies if the drive should be marked as readonly. This is generally used with CD-ROM medias or PFLASH drives as to protect the drive. You can set this value to on to mark that drive as readonly. An example usage would be:

$ qemu-system-x86_64 -drive file=efi.fd,format=raw,if=pflash,readonly=on

If not specified, the drive will be both readable and writable.

Now, there are many possibilities with the -drive. You can have specify many drives, ROMs, storage devices and etc. It might be confusing to decide which option to use and where. So, I wrote some of the most common use cases to help you decide.

  • General Drive (SSD/HDD): Use this type for large storage devices. (e.g. Install OS, Backup files)
  • Optical Drive (CD/DVD): Use this for installation images. (e.g. ubuntu-arm64.iso, archboot.aarch64.iso)
  • Flash ROM: Use this for readonly drives. (e.g. EFI)

Here’s a simple usage:

# Flash ROM
-drive file=edk2-aarch64-code.fd,format=raw,if=pflash,readonly=on,index=1
# Optical Drive (CD/DVD)
-drive file=ubuntu-arm64.iso,format=raw,media=cdrom,index=2
# General Drive (SSD/HDD)
-drive file=disk0.qcow2,format=qcow2,if=virtio,index=3
-drive file=disk1.vdi,format=vdi,if=virtio,index=4

Next Part 5. Devices, VirtIO & More

--

--

Tuna Cici

Simple software engineer who likes the share the stuff he learns 👻 Mainly writing about software things&stuff