iommu-testdev — IOMMU test device for bare-metal testing

Overview

iommu-testdev is a minimal, test-only PCI device designed to exercise IOMMU translation (such as ARM SMMUv3) without requiring firmware or a guest OS. Tests can populate IOMMU translation tables with known values and trigger DMA operations that flow through the IOMMU translation path. It is not a faithful PCIe endpoint and must be considered a QEMU-internal test vehicle.

Key Features

  • Bare-metal IOMMU testing: No guest kernel or firmware required

  • Configurable DMA attributes: Supports address space configuration via MMIO registers

  • Deterministic verification: Write-then-read DMA pattern with automatic result checking

Status

  • Location: hw/misc/iommu-testdev.c

  • Header: include/hw/misc/iommu-testdev.h

  • Build guard: CONFIG_IOMMU_TESTDEV

Device Interface

The device exposes a single PCI BAR0 with 32-bit MMIO registers:

  • ITD_REG_DMA_TRIGGERING (0x00): Read triggers DMA and consumes the armed request

  • ITD_REG_DMA_GVA_LO (0x04): DMA IOVA bits [31:0]

  • ITD_REG_DMA_GVA_HI (0x08): DMA IOVA bits [63:32]

  • ITD_REG_DMA_GPA_LO (0x1C): DMA GPA bits [31:0] for readback validation

  • ITD_REG_DMA_GPA_HI (0x20): DMA GPA bits [63:32] for readback validation

  • ITD_REG_DMA_LEN (0x0C): DMA transfer length

  • ITD_REG_DMA_RESULT (0x10): DMA result (0=success, 0xffffffff=idle, 0xfffffffe=armed)

  • ITD_REG_DMA_DBELL (0x14): Write 1 to arm DMA, write 0 to disarm. Arming only marks the request and sets BUSY (no latch/check), but it provides an explicit gate for qtests and leaves room for async/latching.

  • ITD_REG_DMA_ATTRS (0x18): DMA attributes which shadow some fields in MemTxAttrs:

    • bit[0]: secure (1=Secure, 0=Non-Secure)

    • bits[2:1]: ArmSecuritySpace (0=Secure, 1=Non-Secure)

    • bit[3]: space_valid (1=space is valid, 0=ignore space and default to Non-Secure) space field in MemTxAttrs is consumed only when space_valid is set. For Secure/Non-Secure, secure and space must match; mismatches return ITD_DMA_ERR_BAD_ATTRS. Other bits are reserved but can be wired up easily if future tests need to pass extra attributes.

Translation Setup Workflow

iommu-testdev never builds SMMU/AMD-Vi/RISC-V IOMMU structures on its own. Architecture-specific construction lives entirely in qtest/libqos helpers. Those helpers populate guest memory with page tables/architecture-specific structures and program the emulated IOMMU registers directly. See the qsmmu_setup_and_enable_translation() function in tests/qtest/libqos/qos-smmuv3.c for an example of how SMMUv3 translation is set up for this device.

DMA Operation Flow

Arming semantics:

  • Writing DMA_DBELL with bit0=1 marks the request armed and sets DMA_RESULT to BUSY. It does not latch GVA/LEN/ATTRS; values are sampled when DMA_TRIGGERING is read.

  • Writing DMA_DBELL with bit0=0 disarms the request and sets DMA_RESULT to IDLE.

  • Reading DMA_TRIGGERING consumes the armed request and clears the armed state, even on error.

The flow would be split into these steps, mainly for timing control and debuggability: qtests can easily exercise and assert distinct paths (NOT_ARMED, BAD_LEN, TX/RD failures, mismatch) instead of having all side effects hidden behind a single step: 1. Test programs IOMMU translation tables 2. Test configures DMA IOVA (GVA_LO/HI), GPA for readback, length, and attributes 3. Test writes 1 to DMA_DBELL to arm the operation 4. Test reads DMA_TRIGGERING to execute DMA 5. Test polls DMA_RESULT:

  • 0x00000000: Success

  • 0xFFFFFFFE: Armed (waiting for trigger). DMA runs synchronously, so BUSY is not observed once the trigger read completes.

  • 0xDEAD0006: Bad attrs (secure/space mismatch for S/NS)

  • 0xDEAD000X: Various error codes

The device performs a write-then-read sequence using a known pattern (0x12345678) and verifies data integrity automatically.

Running the qtest

The SMMUv3 test suite uses this device and covers multiple translation modes:

cd build
QTEST_QEMU_BINARY=./qemu-system-aarch64 \\
    ./tests/qtest/iommu-smmuv3-test --tap -k

This test suite exercises:

  • Stage 1 only translation

  • Stage 2 only translation

  • Nested (Stage 1 + Stage 2) translation

Instantiation

The device is not wired into any board by default. Tests instantiate it via QEMU command line:

-device iommu-testdev

For ARM platforms with SMMUv3:

-M virt,iommu=smmuv3 -device iommu-testdev

When the IOMMU sits on the same PCI root complex (pci.0), the device is placed behind it automatically. For other PCI topologies, specify the bus explicitly.

Limitations

  • No realistic PCIe enumeration, MSI/MSI-X, or interrupt handling

  • No ATS/PRI support

  • No actual device functionality beyond DMA test pattern

  • Test-only; not suitable for production or machine realism

  • Address space support (Secure/Root/Realm) is architecture-dependent and gated by space_valid

  • Readback uses the programmed GPA and reads via system memory, avoiding a second IOMMU access for the readback step

See also

  • tests/qtest/iommu-smmuv3-test.c — SMMUv3 test suite

  • tests/qtest/libqos/qos-smmuv3.{c,h} — SMMUv3 test library

  • SMMUv3 emulation: hw/arm/smmu*