Table of Contents

qemu

What is QEMU?

QEMU is a machine emulator and virtualizer. It can run a full operating system for one CPU architecture on a host of a different architecture by translating instructions on the fly (emulation), or run a guest OS at near-native speed on a matching host architecture by delegating execution to the CPU's own hardware virtualization extensions (KVM acceleration).

These are two different jobs sharing one tool. Pure emulation is what makes QEMU useful for embedded work: you can boot an ARM or RISC-V Linux image on an x86 laptop and get a functioning target environment without owning the physical board, useful for testing a cross-compiled kernel or bootloader before ever touching real hardware. KVM-accelerated virtualization is what makes QEMU useful as a general-purpose VM host, running a same-architecture guest OS at speeds close to bare metal.

In embedded and HPC contexts, QEMU shows up for two distinct reasons: as a target for testing cross-compiled firmware or kernels (qemu-system-arm, qemu-system-riscv64) without hardware in hand, and as qemu-user, which runs a single foreign-architecture binary directly on the host by emulating just that one process rather than a whole machine.

Install

On Debian and Ubuntu:

sudo apt install qemu-system qemu-user-static

qemu-system-* provides full-machine emulation per target architecture; qemu-user-static provides single-binary emulation. On Fedora and RHEL:

sudo dnf install qemu-kvm qemu-user-static

To check whether the host supports hardware-accelerated virtualization (needed for KVM mode):

egrep -c '(vmx|svm)' /proc/cpuinfo   # nonzero means the CPU supports it
kvm-ok                                # on Ubuntu, reports whether KVM is usable

Practice

Booting a foreign-architecture Linux kernel directly, without a full disk image, is the fastest way to test a freshly cross-compiled kernel:

qemu-system-arm -M versatilepb -kernel zImage \
  -dtb versatile-pb.dtb -append "console=ttyAMA0" \
  -nographic

-M selects the emulated machine (board) type, which determines the memory map and available peripherals; -nographic redirects the emulated serial console to the host terminal instead of opening a graphical window, the natural mode for headless embedded testing.

qemu-user runs a single cross-compiled binary directly:

qemu-arm ./my_cross_compiled_binary

This works because qemu-user-static registers itself with the kernel's binfmt_misc mechanism, so a foreign-architecture ELF binary can be executed as if it were a native binary; QEMU is invoked transparently underneath.

Concepts

System mode vs user mode

System-mode QEMU (qemu-system-*) emulates an entire machine, CPU, memory, disk, network interface, peripherals, and boots a full OS image inside it. User-mode QEMU (qemu-arm, qemu-riscv64, etc.) emulates only the CPU instructions of a single process, translating foreign syscalls to the host kernel's native syscalls, which is much lighter weight when the goal is just “run this one binary.”

qemu-system-riscv64 -M virt -kernel Image -nographic   # full machine
qemu-riscv64 ./binary                                     # single process

KVM acceleration

When guest and host share the same CPU architecture, QEMU can hand off most instruction execution directly to the CPU via the kernel's KVM module rather than translating instructions in software. This is the difference between a VM running at near-native speed and one running at a fraction of native speed:

qemu-system-x86_64 -enable-kvm -m 4G -smp 4 -hda disk.img

Without -enable-kvm (or on a host without virtualization extensions), QEMU falls back to its software translation engine (TCG), which is what makes cross-architecture emulation possible at all but is considerably slower.

GDB integration

QEMU can expose a GDB remote-debugging stub, which lets gdb attach to and debug code running inside the emulated machine, kernel or bare-metal firmware included, as if it were a normal local process:

qemu-system-arm -M versatilepb -kernel zImage -s -S -nographic

-S freezes the CPU at startup; -s opens a GDB stub on localhost:1234. In another terminal:

gdb zImage
(gdb) target remote localhost:1234
(gdb) continue

This combination, QEMU as the target and GDB as the debugger, is the standard way to step through early boot code or a bare-metal firmware image without needing a physical JTAG probe.

Disk images

qemu-img creates and manipulates the virtual disk images system-mode QEMU boots from, typically in the copy-on-write qcow2 format so a base image can be reused across multiple VMs without duplicating storage:

qemu-img create -f qcow2 disk.qcow2 20G