Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

QEMU

Introduction

QEMU (Quick Emulator) is a versatile open-source machine emulator and virtualizer. As an emulator, it can run operating systems and programs for one architecture on a completely different architecture (e.g., ARM on x86). As a virtualizer, combined with KVM or Xen, it achieves near-native performance by executing guest code directly on the host CPU.

QEMU is the de facto standard userspace component for KVM-based virtualization on Linux. It provides device emulation, machine modeling, firmware loading, and management interfaces that complement KVM’s kernel-level CPU and memory virtualization.

Architecture Overview

flowchart TB
    subgraph QEMU_Process["QEMU Process"]
        subgraph Core
            MAIN[Main Event Loop]
            TCG["TCG - Tiny Code Generator<br>Software Emulation"]
            KVM_IF["KVM Interface<br>/dev/kvm ioctl"]
            QOM[QOM - Object Model]
        end
        subgraph Device_Emulation["Device Emulation"]
            BLK["Block Devices<br>virtio-blk, IDE, SCSI, NVMe"]
            NET["Network Devices<br>virtio-net, e1000, rtl8139"]
            GPU["Graphics<br>virtio-gpu, VGA, QXL"]
            USB["USB Controllers<br>xHCI, EHCI, UHCI"]
            CHAR["Character Devices<br>serial, console, sockets"]
            AUDIO["Audio<br>intel-hda, AC97"]
        end
        subgraph Machine_Model["Machine Model"]
            MACHINE["Machine Type<br>q35, i440fx, virt"]
            BIOS["BIOS/UEFI<br>SeaBIOS, OVMF"]
            ACPI[ACPI Tables]
            IRQ[Interrupt Routing]
        end
        subgraph Management
            QMP["QMP Protocol<br>JSON-based control"]
            HMP["HMP Monitor<br>Human-friendly CLI"]
            QGA[QEMU Guest Agent]
        end
    end

    TCG -->|Software emulation| MAIN
    KVM_IF -->|Hardware acceleration| MAIN
    MAIN --> BLK
    MAIN --> NET
    MAIN --> GPU
    QOM -->|Manages| BLK
    QOM -->|Manages| NET
    QOM -->|Manages| GPU

QEMU Operating Modes

Full System Emulation

QEMU emulates an entire machine, including CPU, memory, and all peripherals. The guest OS runs unmodified.

# x86_64 system emulation (no KVM — pure software)
qemu-system-x86_64 \
  -machine q35 \
  -cpu qemu64 \
  -m 2048 \
  -drive file=disk.qcow2,format=qcow2 \
  -cdrom install.iso \
  -boot d \
  -display gtk

# ARM system emulation on x86 host
qemu-system-aarch64 \
  -machine virt \
  -cpu cortex-a72 \
  -m 4096 \
  -drive file=arm64-disk.qcow2,if=virtio \
  -kernel Image \
  -dtb virt.dtb \
  -append "root=/dev/vda console=ttyAMA0" \
  -nographic

# RISC-V system emulation
qemu-system-riscv64 \
  -machine virt \
  -cpu rv64 \
  -m 1024 \
  -kernel Image \
  -append "root=/dev/vda" \
  -drive file=riscv64-disk.qcow2,if=virtio \
  -nographic

User-Mode Emulation

QEMU can run individual Linux binaries compiled for another architecture without a full system:

# Run an ARM binary on x86 host
qemu-aarch64 ./hello_arm64

# Run with a custom library path (chroot-like)
qemu-aarch64 -L /usr/aarch64-linux-gnu/ ./hello_arm64

# Register binfmt_misc for transparent execution
# (usually done by the qemu-user-binfmt package)
echo ':qemu-aarch64:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/bin/qemu-aarch64:' \
  > /proc/sys/fs/binfmt_misc/register

# Now ARM binaries can be executed directly!
./hello_arm64  # Transparently runs via qemu-aarch64

KVM Acceleration

When running on a Linux host with KVM, QEMU delegates CPU execution to the kernel:

# KVM-accelerated x86 on x86
qemu-system-x86_64 -enable-kvm -cpu host -m 4096 ...

# Check acceleration status
qemu-system-x86_64 -accel help
# Accelerators: kvm, tcg

# Performance comparison
# TCG (software): ~5-10% of native
# KVM (hardware): ~95-99% of native

Device Emulation

QEMU provides hundreds of emulated devices. These fall into several categories:

Device Categories

flowchart TB
    subgraph Storage
        IDE["IDE/ATA PIIX4, ICH6"]
        SCSI[SCSI LSI53C895A, virtio-scsi]
        NVMe_NVMe[NVMe]
        VIRTIO_BLK[virtio-blk]
        FLOPPY[Floppy]
        SD[SD card]
    end
    subgraph Network
        E1000[Intel e1000]
        RTL8139[Realtek RTL8139]
        VIRTIO_NET[virtio-net]
        VMXNET3[VMware vmxnet3]
    end
    subgraph Display
        VGA["VGA/Cirrus"]
        QXL["QXL (SPICE)"]
        VIRTIO_GPU[virtio-gpu]
        BOCHS[Bochs Display]
    end
    subgraph USB
        XHCI[xHCI]
        EHCI[EHCI]
        UHCI[UHCI]
    end

Device Emulation Flow

When a guest accesses an emulated device, the flow is:

sequenceDiagram
    participant Guest
    participant KVM
    participant QEMU
    participant Device as Emulated Device
    participant Host as Host Resource

    Guest->>KVM: OUT instruction to I/O port 0x3F8
    KVM->>KVM: VM Exit (I/O instruction)
    KVM->>QEMU: KVM_EXIT_IO (port 0x3F8, data=0x41)
    QEMU->>QEMU: Lookup device by I/O port
    QEMU->>Device: Serial port write callback
    Device->>Host: Write to pty/socket/file
    QEMU->>KVM: ioctl(KVM_RUN) - resume guest

Adding Devices

# Add a virtio NIC
qemu-system-x86_64 \
  -device virtio-net-pci,netdev=net0,mac=52:54:00:12:34:56 \
  -netdev tap,id=net0,script=no,downscript=no

# Add a virtio disk
qemu-system-x86_64 \
  -device virtio-blk-pci,drive=drv0,bootindex=1 \
  -drive file=disk.qcow2,format=qcow2,if=none,id=drv0 \
  -drive file=scratch.raw,format=raw,if=none,id=drv1 \
  -device virtio-blk-pci,drive=drv1

# Add a USB controller and device
qemu-system-x86_64 \
  -device qemu-xhci,id=xhci \
  -device usb-storage,drive=usbstick,bus=xhci.0 \
  -drive file=usb.img,format=raw,if=none,id=usbstick

# Hot-plug a device at runtime via QMP
# {"execute": "device_add", "arguments": {"driver": "virtio-net-pci", "id": "nic1", "netdev": "net1"}}

QOM (QEMU Object Model)

QOM is QEMU’s object-oriented framework for modeling all objects in the system: devices, buses, machines, backends, and more.

QOM Hierarchy

flowchart TB
    ROOT[container] --> MACHINE[machine]
    ROOT --> PERIPHERAL[peripheral]
    ROOT --> BACKEND[backend]
    
    MACHINE --> Q35[q35 machine]
    Q35 --> ICH9[ICH9 LPC]
    Q35 --> PCIE[PCIe Root Port]
    
    PERIPHERAL --> PCI_DEV[pci-device]
    PCI_DEV --> VIRTIO[virtio-pci-device]
    VIRTIO --> VNET[virtio-net-pci]
    VIRTIO --> VBLK[virtio-blk-pci]
    PCI_DEV --> E1000[e1000]
    
    BACKEND --> BLOCK[blk-backend]
    BLOCK --> RAW[raw]
    BLOCK --> QCOW2[qcow2]
    BACKEND --> NETDEV[netdev]
    NETDEV --> TAP[tap]
    NETDEV --> USER[user]

QOM Device Model

Each emulated device is a QOM object with:

  • Properties — configurable parameters (e.g., MAC address, drive)
  • Realize — initialization when the device becomes “real”
  • Methods — MMIO/PIO read/write callbacks, reset, etc.
/* QOM device definition (simplified) */
static void my_device_class_init(ObjectClass *klass, void *data) {
    DeviceClass *dc = DEVICE_CLASS(klass);
    
    dc->desc = "My Custom Device";
    dc->realize = my_device_realize;
    dc->reset = my_device_reset;
    
    /* Define properties */
    object_class_property_add_bool(klass, "enabled",
        my_device_get_enabled, my_device_set_enabled);
}

/* Register the device type */
static const TypeInfo my_device_info = {
    .name = "my-device",
    .parent = "pci-device",
    .instance_size = sizeof(MyDevice),
    .class_init = my_device_class_init,
};

/* Query QOM tree from QEMU monitor */
/* (qemu) qom-tree /machine/unattached/device[0] */

Querying QOM

# List QOM tree from QEMU monitor
(qemu) qom-list /
# (qemu) qom-list /machine
# (qemu) qom-get /machine/unattached/isa-serial[0] backend

# QMP JSON API
echo '{"execute": "qom-list", "arguments": {"path": "/"}}' | \
  socat - UNIX-CONNECT:/tmp/qemu-monitor.sock

Machine Types

QEMU defines machine types that specify the chipset, bus topology, and default devices:

x86 Machine Types

MachineChipsetDefaultUse Case
pc (i440fx)Intel 440FXIDE, PCILegacy compatibility
q35Intel Q35/ICH9PCIe, AHCIModern workloads
microvmMinimalvirtio-mmioMicroVMs, fast boot
isapcISA onlyISA devicesVery old OSes
# List available machine types
qemu-system-x86_64 -machine help

# q35 is recommended for modern VMs
qemu-system-x86_64 -machine q35,accel=kvm \
  -cpu host \
  -m 4096 \
  -drive file=disk.qcow2,format=qcow2,if=none,id=drv0 \
  -device virtio-blk-pci,drive=drv0 \
  ...

# microvm for minimal, fast-booting VMs
qemu-system-x86_64 -machine microvm,accel=kvm \
  -cpu host \
  -m 512 \
  -kernel bzImage \
  -append "console=ttyS0" \
  -nographic
# Boots in ~125ms with Firecracker-like performance

ARM Machine Types

# List ARM64 machine types
qemu-system-aarch64 -machine help

# virt is the standard ARM virtual platform
qemu-system-aarch64 -machine virt \
  -cpu cortex-a72 \
  -m 2048 \
  -drive file=arm64.qcow2,if=virtio \
  -nographic

Virtio

Virtio is the paravirtualized I/O framework that provides high-performance device emulation. Instead of emulating real hardware (which causes many VM exits), virtio uses shared memory ring buffers between guest and host.

Virtio Architecture

flowchart LR
    subgraph Guest
        APP[Application] --> VFS[Kernel VFS]
        VFS --> VF[virtio Frontend Driver]
        VF --> VRING["Virtqueue<br>Available Ring / Used Ring"]
    end
    subgraph Host
        VRING -->|shared memory| VB[virtio Backend]
        VB --> VHOST["vhost-net / vhost-user / QEMU"]
        VHOST --> HOST[Host Resource]
    end

Virtio Transport Types

TransportMechanismPerformance
virtio-pciPCI config space + MMIOHigh
virtio-mmioMemory-mapped I/OHigh (ARM)
vhost-netIn-kernel virtio backendVery high
vhost-userUserspace backend (DPDK)Highest

Virtio Devices

# virtio-blk — block device
qemu-system-x86_64 \
  -device virtio-blk-pci,drive=drv0 \
  -drive file=disk.qcow2,format=qcow2,if=none,id=drv0

# virtio-scsi — SCSI controller (supports many LUNs)
qemu-system-x86_64 \
  -device virtio-scsi-pci,id=scsi0 \
  -device scsi-hd,bus=scsi0.0,drive=drv0 \
  -drive file=disk.qcow2,format=qcow2,if=none,id=drv0

# virtio-net — network device
qemu-system-x86_64 \
  -device virtio-net-pci,netdev=net0 \
  -netdev tap,id=net0,script=no,vhost=on

# virtio-gpu — graphics
qemu-system-x86_64 \
  -device virtio-gpu-pci \
  -display gtk,gl=on

# virtio-fs — shared filesystem (virtiofsd)
qemu-system-x86_64 \
  -chardev socket,id=char0,path=/tmp/vhost-fs.sock \
  -device vhost-user-fs-pci,chardev=char0,tag=myfs

# virtio-vsock — host-guest communication
qemu-system-x86_64 \
  -device vhost-vsock-pci,guest-cid=3

Virtio Performance

# Benchmark virtio-blk vs IDE
# virtio-blk: ~500K IOPS (4K random read)
# IDE emulation: ~10K IOPS (4K random read)
# ~50x improvement

# Benchmark virtio-net vs e1000
# virtio-net: ~10 Gbps
# e1000: ~1 Gbps
# vhost-net adds another ~30% improvement over QEMU backend

QEMU Image Formats

QCOW2

QCOW2 (QEMU Copy-On-Write version 2) is the most commonly used disk image format:

# Create a QCOW2 image
qemu-img create -f qcow2 disk.qcow2 50G

# QCOW2 features:
# - Sparse allocation (only uses host space as needed)
# - Snapshots (internal and external)
# - Compression (zlib, zstd)
# - Encryption (LUKS)
# - Backing files (copy-on-write chains)

# Create with backing file (copy-on-write)
qemu-img create -f qcow2 -b base.qcow2 -F qcow2 overlay.qcow2

# Inspect image
qemu-img info disk.qcow2
# image: disk.qcow2
# file format: qcow2
# virtual size: 50 GiB (53687091200 bytes)
# disk size: 1.2 GiB
# cluster_size: 65536
# Format specific information:
#     compat: 1.1
#     compression type: zlib
#     lazy refcounts: false
#     refcount bits: 16
#     corrupt: false
#     extended l2: false

# Create snapshot
qemu-img snapshot -c snap1 disk.qcow2

# List snapshots
qemu-img snapshot -l disk.qcow2

# Convert between formats
qemu-img convert -f qcow2 -O raw disk.qcow2 disk.raw

Image Format Comparison

FormatSparseSnapshotsCompressionBacking Files
qcow2
raw✅*
vmdk
vdi
vhdx

*Raw images are sparse when created on a filesystem that supports sparse files.

QMP (QEMU Machine Protocol)

QMP is a JSON-based protocol for controlling QEMU programmatically:

QMP Connection

# Start QEMU with QMP socket
qemu-system-x86_64 \
  -qmp unix:/tmp/qmp.sock,server,nowait \
  ...

# Connect via socat
socat - UNIX-CONNECT:/tmp/qmp.sock

# Initial handshake
# QMP sends: {"QMP": {"version": {"qemu": {"micro": 0, "minor": 2, "major": 8}}, "capabilities": []}}
# Send: {"execute": "qmp_capabilities"}
# Response: {"return": {}}

Common QMP Commands

# Query VM status
{"execute": "query-status"}

# Query CPUs
{"execute": "query-cpus-fast"}

# Query block devices
{"execute": "query-block"}

# Take a screenshot
{"execute": "screendump", "arguments": {"filename": "/tmp/screen.ppm"}}

# Create a snapshot
{"execute": "blockdev-snapshot-sync", "arguments": {
    "device": "drv0",
    "snapshot-file": "/tmp/snap.qcow2"
}}

# Hot-plug a CPU
{"execute": "device_add", "arguments": {
    "driver": "virtio-net-pci",
    "id": "nic1",
    "netdev": "net1"
}}

# Migrate to another host
{"execute": "migrate", "arguments": {
    "uri": "tcp:destination:4444"
}}

# Query migration status
{"execute": "query-migrate"}

libvirt Integration

libvirt is the most common management layer for QEMU/KVM:

# Define a VM from XML
virsh define vm.xml

# Start/stop
virsh start myvm
virsh shutdown myvm
virsh destroy myvm  # Force stop

# List VMs
virsh list --all

# Connect to console
virsh console myvm

# Live migrate
virsh migrate --live myvm qemu+ssh://dest/system

# Snapshot
virsh snapshot-create-as myvm snap1 "Before update"
virsh snapshot-revert myvm snap1

Buildroot / Yocto Integration

QEMU is heavily used in embedded Linux development:

# Buildroot: run QEMU target
cd buildroot
make qemu_x86_64_defconfig
make
qemu-system-x86_64 \
  -M pc \
  -kernel output/images/bzImage \
  -drive file=output/images/rootfs.ext4,if=virtio,format=raw \
  -append "root=/dev/vda console=ttyS0" \
  -nographic \
  -net nic,model=virtio \
  -net user

# Yocto: run QEMU target
runqemu qemux86-64 nographic

Cross-Architecture Emulation Summary

HostGuestQEMU CommandNotes
x86_64ARM64qemu-system-aarch64Full system emulation
x86_64ARM32qemu-system-armFull system emulation
x86_64RISC-Vqemu-system-riscv64Full system emulation
x86_64MIPSqemu-system-mipsFull system emulation
x86_64x86_64qemu-system-x86_64 -enable-kvmHardware-accelerated
x86_64ARM binaryqemu-aarch64User-mode (single binary)

References

  1. Bellard, F. (2005). “QEMU, a Fast and Portable Dynamic Translator.” USENIX Annual Technical Conference.
  2. QEMU Documentation. https://www.qemu.org/docs/master/
  3. Rusty Russell. “Virtio: Towards a De-Facto Standard for Virtual I/O Devices.” ACM SIGOPS Operating Systems Review, 2008.
  4. QEMU Source Code. https://gitlab.com/qemu-project/qemu

Further Reading