| .. SPDX-License-Identifier: GPL-2.0-or-later |
| |
| 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*`` |