Hi Eric,
On 2026/1/17 18:02, Eric Auger wrote:
Hi Tao,
On 12/24/25 4:46 AM, Tao Tang wrote:
Introduce qos-smmuv3, a reusable library for SMMUv3-related qtest
operations. This module encapsulates common tasks like:
- SMMUv3 initialization (enabling, configuring command/event queues)
- Stream Table Entry (STE) and Context Descriptor (CD) setup
- Multi-level page table construction (L0-L3 for 4KB granules)
- Support for Stage 1, Stage 2, and nested translation modes
- Could be easily extended to support multi-space testing infrastructure
(Non-Secure, Secure, Root, Realm)
The library provides high-level abstractions that allow test code to
focus on IOMMU behavior validation rather than low-level register
manipulation and page table encoding. Key features include:
- Provide memory allocation for translation structures with proper
alignment
- Helper functions to build valid STEs/CDs for different translation
scenarios
- Page table walkers that handle address offset calculations per
security space
This infrastructure is designed to be used by iommu-testdev-based tests
and future SMMUv3 test suites, reducing code duplication and improving
test maintainability.
Signed-off-by: Tao Tang<[email protected]>
Reviewed-by: Pierrick Bouvier<[email protected]>
Reviewed-by: Fabiano Rosas<[email protected]>
---
MAINTAINERS | 6 +
tests/qtest/libqos/meson.build | 3 +
tests/qtest/libqos/qos-smmuv3.c | 633 ++++++++++++++++++++++++++++++++
tests/qtest/libqos/qos-smmuv3.h | 256 +++++++++++++
4 files changed, 898 insertions(+)
create mode 100644 tests/qtest/libqos/qos-smmuv3.c
create mode 100644 tests/qtest/libqos/qos-smmuv3.h
------------------------------<snip>------------------------------
------------------------------<snip>------------------------------
+
+uint32_t qsmmu_trigger_dma(QSMMUTestContext *ctx)
qsmmu_trigger_dma and qsmmu_single_translation helpers which do not really
relate to SMMU but rather relate to the pci
test dev. put them in a specific section of this file or move them in a
separate file. They could be reused by other non SMMU specific tests
Agreed — that’s a better separation. I’ll move these two helpers out of
qos-smmuv3 into a generic libqos helper (something like
qos-iommu-testdev.[ch]).
+{
+ uint32_t result, attrs_val;
+
+ /* Program DMA parameters */
+ qpci_io_writel(ctx->dev, ctx->bar, ITD_REG_DMA_GVA_LO,
+ (uint32_t)ctx->config.dma_iova);
+ qpci_io_writel(ctx->dev, ctx->bar, ITD_REG_DMA_GVA_HI,
+ (uint32_t)(ctx->config.dma_iova >> 32));
+ qpci_io_writel(ctx->dev, ctx->bar, ITD_REG_DMA_LEN,
+ ctx->config.dma_len);
+
+ /* Build and write DMA attributes based on device security state. */
+ attrs_val = qsmmu_build_dma_attrs(QSMMU_SPACE_NONSECURE);
+ qpci_io_writel(ctx->dev, ctx->bar, ITD_REG_DMA_ATTRS, attrs_val);
+
+ /* Flip status */
+ /* Arm iommu-testdev so the next read triggers DMA */
+ qpci_io_writel(ctx->dev, ctx->bar, ITD_REG_DMA_DBELL, ITD_DMA_DBELL_ARM);
+
+ /* Trigger DMA */
+ qpci_io_readl(ctx->dev, ctx->bar, ITD_REG_DMA_TRIGGERING);
+
+ /* Poll for DMA completion */
+ for (int i = 0; i < 1000; i++) {
+ result = qpci_io_readl(ctx->dev, ctx->bar, ITD_REG_DMA_RESULT);
+ if (result != ITD_DMA_RESULT_BUSY) {
+ ctx->dma_result = result;
+ break;
+ }
+ g_usleep(1000);
+ }
+
+ /* Fallback for timeout */
+ if (ctx->dma_result == ITD_DMA_RESULT_BUSY) {
+ ctx->dma_result = ITD_DMA_ERR_TX_FAIL;
+ }
+
+ return ctx->dma_result;
+}
+
+bool qsmmu_validate_test_result(QSMMUTestContext *ctx)
+{
+ uint32_t expected = qsmmu_expected_dma_result(ctx);
+ g_test_message("-> Validating result: expected=0x%x actual=0x%x",
+ expected, ctx->dma_result);
+ return (ctx->dma_result == expected);
+}
+
+QSMMUSpace qsmmu_sec_sid_to_space(QSMMUSecSID sec_sid)
+{
+ switch (sec_sid) {
+ case QSMMU_SEC_SID_NONSECURE:
+ return QSMMU_SPACE_NONSECURE;
+ default:
+ g_assert_not_reached();
+ }
+}
+
+uint64_t qsmmu_space_offset(QSMMUSpace sp)
+{
+ switch (sp) {
+ case QSMMU_SPACE_NONSECURE:
+ return QSMMU_SPACE_OFFS_NS;
+ default:
+ g_assert_not_reached();
+ }
+}
+
+void qsmmu_single_translation(QSMMUTestContext *ctx)
+{
+ uint32_t config_result;
+ uint32_t dma_result;
+
+ /* Configure SMMU translation */
+ config_result = qsmmu_setup_and_enable_translation(ctx);
+ g_assert_cmpuint(config_result, ==, 0);
+
+ /* Trigger DMA operation */
+ dma_result = qsmmu_trigger_dma(ctx);
+ if (dma_result != 0) {
+ g_test_message("DMA failed: mode=%u result=0x%x",
+ ctx->config.trans_mode, dma_result);
+ } else {
+ g_test_message("-> DMA succeeded: mode=%u", ctx->config.trans_mode);
+ }
+
+ /* Validate test result */
+ g_assert_true(qsmmu_validate_test_result(ctx));
+}
+
------------------------------<snip>------------------------------
------------------------------<snip>------------------------------
diff --git a/tests/qtest/libqos/qos-smmuv3.h b/tests/qtest/libqos/qos-smmuv3.h
new file mode 100644
index 0000000000..375778517f
--- /dev/null
+++ b/tests/qtest/libqos/qos-smmuv3.h
@@ -0,0 +1,256 @@
+/*
+ * QOS SMMUv3 Module
+ *
+ * This module provides SMMUv3-specific helper functions for libqos tests,
+ * encapsulating SMMUv3 setup, and assertions.
+ *
+ * Copyright (c) 2025 Phytium Technology
+ *
+ * Author:
+ * Tao Tang<[email protected]>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef QTEST_LIBQOS_SMMUV3_H
+#define QTEST_LIBQOS_SMMUV3_H
+
+#include "hw/misc/iommu-testdev.h"
+
+/*
+ * SMMU MMIO register base. We hardcode this as base_memmap is 'static const'
+ * in hw/arm/virt.c and not directly accessible here.
+ */
+#define VIRT_SMMU_BASE 0x0000000009050000ull
+
+/* SMMU queue and table base addresses */
+#define QSMMU_CMDQ_BASE_ADDR 0x000000000e16b000ull
+#define QSMMU_EVENTQ_BASE_ADDR 0x000000000e170000ull
+
+/*
+ * Translation tables and descriptors for a mapping of
+ * - IOVA(Stage 1 only)
you mentionned you also support S1 + S2
Yes there should be `- IOVA(Stage 1 and nested translation stage)`.
+ * - IPA (Stage 2 only)
+ * to GPA.
+ *
+ * The translation is based on the Arm architecture with the following
+ * prerequisites:
+ * - Granule size: 4KB pages.
would be nice to support 64kB as well in the future. Can be done later
though.
+ * - Page table levels: 4 levels (L0, L1, L2, L3), starting at level 0.
+ * - IOVA size: The walk resolves a IOVA: 0x8080604567
well this is passed as a test config parameter and this is does not
sound relevant to hardcode it.
I initially wanted dma_iova to be configurable and have the page-table
builder follow it, but I didn’t find a clean way to keep the table
construction in sync.
So for now I’ll likely drop QSMMUTestConfig.dma_iova and consistently
use the fixed QSMMU_IOVA for both table setup and DMA, to avoid a
misleading knob. We can revisit later to make IOVA + tables
configurable, and potentially add 64KB granule support as well.
Thanks,
Tao