Hi Eric,
On 2025/12/11 02:35, Eric Auger wrote:
On 11/26/25 4:45 PM, Tao Tang wrote:
Add a minimal PCI test device designed to exercise IOMMU translation
(such as ARM SMMUv3) without requiring guest firmware or OS. The device
provides MMIO registers to configure and trigger DMA operations with
controllable attributes (security state, address space), enabling
deterministic IOMMU testing.
Key features:
- Bare-metal IOMMU testing via simple MMIO interface
- Configurable DMA attributes for security states and address spaces
- Write-then-read verification pattern with automatic result checking
The device performs a deterministic DMA test pattern: write a known
value (0x88888888) to a configured IOVA, read it back, and verify data
integrity. Results are reported through a dedicated result register,
eliminating the need for complex interrupt handling or driver
infrastructure in tests.
This is purely a test device and not intended for production use or
machine realism. It complements existing test infrastructure like
pci-testdev but focuses specifically on IOMMU translation path
validation.
Signed-off-by: Tao Tang <[email protected]>
---
docs/specs/index.rst | 1 +
docs/specs/iommu-testdev.rst | 109 +++++++++++++
hw/misc/Kconfig | 5 +
hw/misc/iommu-testdev.c | 278 ++++++++++++++++++++++++++++++++
hw/misc/meson.build | 1 +
hw/misc/trace-events | 10 ++
include/hw/misc/iommu-testdev.h | 70 ++++++++
7 files changed, 474 insertions(+)
create mode 100644 docs/specs/iommu-testdev.rst
create mode 100644 hw/misc/iommu-testdev.c
create mode 100644 include/hw/misc/iommu-testdev.h
diff --git a/docs/specs/index.rst b/docs/specs/index.rst
index f19d73c9f6..1fc7fae6bb 100644
--- a/docs/specs/index.rst
+++ b/docs/specs/index.rst
@@ -39,3 +39,4 @@ guest hardware that is specific to QEMU.
riscv-iommu
riscv-aia
aspeed-intc
+ iommu-testdev
\ No newline at end of file
diff --git a/docs/specs/iommu-testdev.rst b/docs/specs/iommu-testdev.rst
new file mode 100644
index 0000000000..fdc7f2ee89
--- /dev/null
+++ b/docs/specs/iommu-testdev.rst
@@ -0,0 +1,109 @@
+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
double space
Thanks for catching it.
+ 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 MMIO registers:
all those regs are 32b?
Yes. All registers are 32-bit, little-endian, and only support 4-byte
accesses, as enforced by the MemoryRegionOps valid range. I’ll make this
explicit in the docs and in the register table to avoid any ambiguity.
+
+* ``ITD_REG_DMA_TRIGGERING`` (0x00): Reading triggers DMA execution
+* ``ITD_REG_DMA_GVA_LO`` (0x04): IOVA/GVA bits [31:0]
+* ``ITD_REG_DMA_GVA_HI`` (0x08): IOVA/GVA bits [63:32]
+* ``ITD_REG_DMA_LEN`` (0x0C): DMA transfer length
+* ``ITD_REG_DMA_RESULT`` (0x10): DMA operation result (0=success)
+* ``ITD_REG_DMA_DBELL`` (0x14): Write 1 to arm DMA
can you elaborate on this DMA_DBELL? It is not crystal clear to me.
The idea is to model a tiny, explicit DMA state machine instead of
having a single MMIO operation that implicitly does “configure + start +
complete”.
In this model:
* DMA_DBELL is just an “arm / doorbell” register.
* DMA_TRIGGERING is the “consume / execute” action.
* DMA_RESULT exposes the state/outcome.
This split is 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 write.
If you feel this is overkill for a qtest-only device, I'm open to
simplifying the interface (e.g. "write a register and immediately
execute DMA").
+* ``ITD_REG_DMA_ATTRS`` (0x18): DMA attributes
+
+ - bit[0]: secure (1=Secure, 0=Non-Secure)
+ - bits[2:1]: address space (0=Non-Secure, 1=Secure, 2=Root, 3=Realm)
I would simply remove Root and Realm for now. Are those bits part of
ITD_REG_DMA_ATTR?
Yes I just shadowed the MemTxAttrs. I'll remove the unused Root/Realm
definition.
+ Only these MemTxAttrs fields (``secure`` and ``space``) are consumed today;
+ 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
+------------------
+1. Test programs IOMMU translation tables
+2. Test configures DMA address (GVA_LO/HI), length, and attributes
+3. Test writes 1 to DMA_DBELL to arm the operation
+4. Test reads DMA_TRIGGERING to execute DMA
why do we need 3 and 4?
As previously described.
+5. Test polls DMA_RESULT:
+
+ - 0x00000000: Success
+ - 0xFFFFFFFE: Busy (still in progress)
+ - 0xDEAD000X: Various error codes
+
+The device performs a write-then-read sequence using a known pattern
+(0x88888888) and verifies data integrity automatically.
+
+Running the qtest
+-----------------
+The SMMUv3 test suite uses this device and covers multiple translation modes::
+
+ cd build-debug
+ 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
+* Multiple security spaces (Non-Secure, Secure, Root, Realm)
ditto
I'll remove it.
+
+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
does it work -device arm-smmuv3 multi instantiation too?
No. It only supports machine-wide SMMU (`iommu=smmuv3`) as SMMU base
address is hardcoded with 0x9050000 in tests/qtest/libqos/qos-smmuv3.h.
Should we support user-creatable SMMUv3 in this testdev?
+
+The device will be placed behind the IOMMU automatically.
+
+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
+
+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*``
diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
index fccd735c24..b5f6fdbd9c 100644
--- a/hw/misc/Kconfig
+++ b/hw/misc/Kconfig
@@ -25,6 +25,11 @@ config PCI_TESTDEV
default y if TEST_DEVICES
depends on PCI
+config IOMMU_TESTDEV
+ bool
+ default y if TEST_DEVICES
+ depends on PCI
+
config EDU
bool
default y if TEST_DEVICES
diff --git a/hw/misc/iommu-testdev.c b/hw/misc/iommu-testdev.c
new file mode 100644
index 0000000000..3182ccea4d
--- /dev/null
+++ b/hw/misc/iommu-testdev.c
@@ -0,0 +1,278 @@
+/*
+ * A test device for IOMMU
+ *
+ * This test device is a minimal IOMMU-aware device used to test the IOMMU.
how is it IOMMU aware? Isn't it "simply" a kinda PCIe DMA device
it behaves as other PCIe devices with s->dma_as =
pci_device_iommu_address_space(pdev);
no?
Sorry for the confusing wording. The device is not really "IOMMU-aware":
it is just a PCI DMA engine, and the tests are responsible
for programming the emulated IOMMU and wiring the device behind it, not
the iommu-testdev itself.
Thanks again for the review,
Tao