Changes since v7: Following Pierrick’s feedback, this version fixes the uint64_t formatting issue (switching to PRIx64 to avoid %lx mismatches on non-LP64 platforms). I also validated the series with Pierrick’s qemu-ci workflow, and all jobs passed; the CI run is available at:
https://github.com/hnusdr/qemu/actions/runs/20476259310 Motivation ---------- Currently, thoroughly testing IOMMU emulation (e.g., ARM SMMUv3) requires a significant software stack. We need to boot a full guest operating system (like Linux) with the appropriate drivers (e.g., IOMMUFD) and rely on firmware (e.g., ACPI with IORT tables or Hafnium) to correctly configure the IOMMU and orchestrate DMA from a peripheral device. This dependency on a complex software stack presents several challenges: * High Barrier to Entry: Writing targeted tests for specific IOMMU features (like fault handling, specific translation regimes, etc.) becomes cumbersome. * Difficult to Debug: It's hard to distinguish whether a bug originates from the IOMMU emulation itself, the guest driver, the firmware tables, or the guest kernel's configuration. * Slow Iteration: The need to boot a full guest OS slows down the development and testing cycle. The primary goal of this work is to create a lightweight, self-contained testing environment that allows us to exercise the IOMMU's core logic directly at the qtest level, removing the need for any guest-side software. Our Approach: A Dedicated Test Framework ----------------------------------------- To achieve this, we introduce three main components: * A minimal hardware device: iommu-testdev * A reusable IOMMU helper library: libqos/qos-smmuv3 * A comprehensive qtest suite: iommu-smmuv3-test The iommu-testdev is intentionally not a conformant, general-purpose PCIe or platform device. It is a purpose-built, highly simplified "DMA engine" designed to be analogous to a minimal PCIe Root Complex that bypasses the full, realistic topology (Host Bridges, Switches, Endpoints) to provide a direct, programmable path for a DMA request to reach the IOMMU. Its sole purpose is to trigger a DMA transaction when its registers are written to, making it perfectly suited for direct control from a test environment like qtest. The Qtest Framework ------------------- The new qtest (iommu-smmuv3-test.c) serves as the "bare-metal driver" for both the IOMMU and the iommu-testdev. It leverages the libqos helper library to manually perform all the setup that would typically be handled by the guest kernel and firmware, but in a completely controlled and predictable manner: 1. IOMMU Configuration: It directly initializes the SMMU's registers to a known state using helper functions from qos-smmuv3. 2. Translation Structure Setup: It uses the libqos library to construct the necessary translation structures in memory, including Stream Table Entries (STEs), Context Descriptors (CDs), and Page Tables (PTEs). 3. DMA Trigger: It programs the iommu-testdev to initiate a DMA operation targeting a specific IOVA with configurable attributes. 4. Verification: It waits for the transaction to complete and verifies that the memory was accessed correctly after address translation by the IOMMU. This framework provides a solid and extensible foundation for validating the IOMMU's core translation paths. The current test suite covers: - Stage 1 only translation (VA -> PA via CD page tables) - Stage 2 only translation (IPA -> PA via STE S2 tables) - Nested translation (VA -> IPA -> PA, Stage 1 + Stage 2) The infrastructure is designed to be extended to support additional security spaces and IOMMU features. Testing: -------- QTEST_QEMU_BINARY=./build/qemu-system-aarch64 \ ./build/tests/qtest/iommu-smmuv3-test --tap -k If you want to check coverage report, please follow instructions below which are shared by Pierrick in previous review [1] # install gcovr if not already installed, `sudo apt install gcovr` # on ubuntu for example $ export CFLAGS="--coverage" $ ./configure --target-list=aarch64-softmmu $ ninja -C build $ QTEST_QEMU_BINARY=./build/qemu-system-aarch64 \ ./build/tests/qtest/iommu-smmuv3-test $ rm -rf build/coverage_html $ mkdir build/coverage_html $ gcovr \ --gcov-ignore-parse-errors suspicious_hits.warn \ --gcov-ignore-parse-errors negative_hits.warn \ --merge-mode-functions=separate \ --html-details build/coverage_html/index.html \ --filter 'hw/arm/smmu*' # check the version of gcovr if meeting some unsupported options error. # Upgrading to 8.4 version may resolve the error. $ gcovr --version $ pip install --user --upgrade gcovr $ echo file://$(pwd)/build/coverage_html/index.html # open this in browser by clicking on your terminal [1] https://lore.kernel.org/qemu-devel/[email protected]/ Major Changes from v7 to v8: ----------------------------- - Fix uint64_t formatting issue by using PRIx64 for portability - Validate the series with Pierrick's qemu-ci workflow; all jobs passed - This series is also saved in github repo [5] [5] https://github.com/hnusdr/qemu/tree/iommu-testdev-v8-community Major Changes from v6 to v7: ----------------------------- - Split the smmuv3-common.h work into smaller patches (registerfields conversion, NSCFG bits, helper setters) - Add MAINTAINERS entries for iommu-testdev and qos-smmuv3 helpers - Tighten documentation wording and update the DMA test pattern value - Simplify qtest PCI device discovery and rename QSMMU_IOVA constant - This series is also saved in github repo [4] [4] https://github.com/hnusdr/qemu/tree/iommu-testdev-v7-community Major Changes from v5 to v6: ----------------------------- - Split batch testing into individual test cases per translation mode - Removed cleanup functions and related codes or comments - Improved error handling with explicit assertions - Add coverage build and test instructions shared by Pierrick - Keep Reviewed-by and Tested-by from Pierrick's review - This series is also saved in github repo [2] [2] https://github.com/hnusdr/qemu/tree/iommu-testdev-v6-community Major Changes from v4 to v5: ----------------------------- - Remove a duplicated patch that was accidentally included in v4. Major Changes from v3 to v4: ----------------------------- 1. Added shared smmuv3-common.h so both the device and libqos consume the same STE/CD/register definitions as Alex suggested [3] 2. Slimmed iommu-testdev down to a pure DMA trigger with a tighter MMIO contract (new doorbell helper, simplified attributes/errors). 3. Updated `qos-smmuv3` and the qtest so they include the common header, honor per-test expected results, and rely solely on the streamlined device interface. 4. Compacted changes of v2 to v3. [3] https://lore.kernel.org/qemu-devel/[email protected]/ Major Changes from v2 to v3: ----------------------------- 1. Generalization/Renaming: rebranded `smmu-testdev` → `iommu-testdev` (code, headers, docs) to reflect the broadened scope. 2. Separation of concerns: iommu-testdev is now a pure DMA trigger; all SMMUv3-specific setup (STE/CD/page tables, multi-mode support, space offsets) lives in `qos-smmuv3.{c,h}` and is consumed by the new qtest. 3. Improved modularity & coverage: the stacked design (device + helper + qtest) made it straightforward to add S1/S2/Nested tests, a cleaner config system, and clearer validation logic. 4. Code/documentation quality: added tracepoints, better error handling/naming, and refreshed `docs/specs/iommu-testdev.rst` with the new layout. Future Work ----------- The current implementation focuses on basic translation path validation in the Non-Secure address space. Future extensions could include: * Multi-space testing (Secure, Root, Realm) for SMMUv3 * Support for other IOMMU types (Intel VT-d, AMD-Vi, RISC-V IOMMU) Tao Tang (7): hw/arm/smmuv3: Extract common definitions to smmuv3-common.h hw/arm/smmuv3-common: Define STE/CD fields via registerfields hw/misc: Introduce iommu-testdev for bare-metal IOMMU testing hw/arm/smmuv3-common: Add NSCFG bit definition for CD hw/arm/smmuv3-common: Add STE/CD set helpers for repeated field setup tests/qtest/libqos: Add SMMUv3 helper library tests/qtest: Add SMMUv3 bare-metal test using iommu-testdev MAINTAINERS | 13 + docs/specs/index.rst | 1 + docs/specs/iommu-testdev.rst | 112 ++++++ hw/arm/smmuv3-internal.h | 255 +------------ hw/misc/Kconfig | 5 + hw/misc/iommu-testdev.c | 271 ++++++++++++++ hw/misc/meson.build | 1 + hw/misc/trace-events | 10 + include/hw/arm/smmuv3-common.h | 423 +++++++++++++++++++++ include/hw/misc/iommu-testdev.h | 68 ++++ tests/qtest/iommu-smmuv3-test.c | 121 ++++++ tests/qtest/libqos/meson.build | 3 + tests/qtest/libqos/qos-smmuv3.c | 633 ++++++++++++++++++++++++++++++++ tests/qtest/libqos/qos-smmuv3.h | 256 +++++++++++++ tests/qtest/meson.build | 1 + 15 files changed, 1919 insertions(+), 254 deletions(-) create mode 100644 docs/specs/iommu-testdev.rst create mode 100644 hw/misc/iommu-testdev.c create mode 100644 include/hw/arm/smmuv3-common.h create mode 100644 include/hw/misc/iommu-testdev.h create mode 100644 tests/qtest/iommu-smmuv3-test.c create mode 100644 tests/qtest/libqos/qos-smmuv3.c create mode 100644 tests/qtest/libqos/qos-smmuv3.h -- 2.34.1
