Hi Tao, On 12/24/25 4:46 AM, Tao Tang wrote: > Add a qtest suite that validates ARM SMMUv3 translation without guest > firmware or OS. The tests leverage iommu-testdev to trigger DMA > operations and the qos-smmuv3 library to configure IOMMU translation > structures. > > This test suite targets the virt machine and 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) > - Design to extended to support multiple security spaces > (Non-Secure, Secure, Root, Realm) > > Each test case follows this sequence: > 1. Initialize SMMUv3 with appropriate command/event queues > 2. Build translation tables (STE/CD/PTE) for the target scenario > 3. Configure iommu-testdev with IOVA and DMA attributes via MMIO > 4. Trigger DMA and validate successful translation > 5. Verify data integrity through a deterministic write-read pattern > > This bare-metal approach provides deterministic IOMMU testing with > minimal dependencies, making failures directly attributable to the SMMU > translation path. > > Signed-off-by: Tao Tang <[email protected]> > Tested-by: Pierrick Bouvier <[email protected]> > Reviewed-by: Pierrick Bouvier <[email protected]> > --- > tests/qtest/iommu-smmuv3-test.c | 121 ++++++++++++++++++++++++++++++++ > tests/qtest/meson.build | 1 + > 2 files changed, 122 insertions(+) > create mode 100644 tests/qtest/iommu-smmuv3-test.c > > diff --git a/tests/qtest/iommu-smmuv3-test.c b/tests/qtest/iommu-smmuv3-test.c > new file mode 100644 > index 0000000000..b612f5ca6c > --- /dev/null > +++ b/tests/qtest/iommu-smmuv3-test.c > @@ -0,0 +1,121 @@ > +/* > + * QTest for SMMUv3 with iommu-testdev > + * > + * This QTest file is used to test the SMMUv3 with iommu-testdev so that we > can > + * test SMMUv3 without any guest kernel or firmware. > + * > + * Copyright (c) 2025 Phytium Technology > + * > + * Author: > + * Tao Tang <[email protected]> > + * > + * SPDX-License-Identifier: GPL-2.0-or-later > + */ > + > +#include "qemu/osdep.h" > +#include "libqtest.h" > +#include "libqos/pci.h" > +#include "libqos/generic-pcihost.h" > +#include "hw/pci/pci_regs.h" > +#include "hw/misc/iommu-testdev.h" > +#include "libqos/qos-smmuv3.h" > + > +#define DMA_LEN 4 > + > +static void save_fn(QPCIDevice *dev, int devfn, void *data) > +{ > + QPCIDevice **pdev = (QPCIDevice **) data; > + > + *pdev = dev; > +} > + > +static QPCIDevice *setup_qtest_pci_device(QTestState *qts, QGenericPCIBus > *gbus, > + QPCIBar *bar) > +{ > + QPCIDevice *dev = NULL; > + > + qpci_init_generic(gbus, qts, NULL, false); > + > + qpci_device_foreach(&gbus->bus, IOMMU_TESTDEV_VENDOR_ID, > + IOMMU_TESTDEV_DEVICE_ID, save_fn, &dev); > + g_assert(dev); > + > + qpci_device_enable(dev); > + *bar = qpci_iomap(dev, 0, NULL); > + g_assert_false(bar->is_io); > + > + return dev; > +} > + > +static void run_smmuv3_translation(const QSMMUTestConfig *cfg) > +{ > + QTestState *qts; > + QGenericPCIBus gbus; > + QPCIDevice *dev; > + QPCIBar bar; > + > + /* Initialize QEMU environment for SMMU testing */ > + qts = qtest_init("-machine virt,acpi=off,gic-version=3,iommu=smmuv3 " > + "-smp 1 -m 512 -cpu max -net none " > + "-device iommu-testdev"); > + > + /* Setup and configure PCI device */ > + dev = setup_qtest_pci_device(qts, &gbus, &bar); > + g_assert(dev); > + > + g_test_message("### SMMUv3 translation mode=%d sec_sid=%d ###", > + cfg->trans_mode, cfg->sec_sid); > + qsmmu_run_translation_case(qts, dev, bar, VIRT_SMMU_BASE, cfg); > + qtest_quit(qts); > +} > + > +static void test_smmuv3_ns_s1_only(void) > +{ > + QSMMUTestConfig cfg = { > + .trans_mode = QSMMU_TM_S1_ONLY, > + .sec_sid = QSMMU_SEC_SID_NONSECURE, > + .dma_iova = QSMMU_IOVA, > + .dma_len = DMA_LEN, > + .expected_result = 0, > + }; > + > + run_smmuv3_translation(&cfg); > +} > + > +static void test_smmuv3_ns_s2_only(void) > +{ > + QSMMUTestConfig cfg = { > + .trans_mode = QSMMU_TM_S2_ONLY, > + .sec_sid = QSMMU_SEC_SID_NONSECURE, > + .dma_iova = QSMMU_IOVA, > + .dma_len = DMA_LEN, > + .expected_result = 0, > + }; > + > + run_smmuv3_translation(&cfg); > +} > + > +static void test_smmuv3_ns_nested(void) > +{ > + QSMMUTestConfig cfg = { > + .trans_mode = QSMMU_TM_NESTED, > + .sec_sid = QSMMU_SEC_SID_NONSECURE, > + .dma_iova = QSMMU_IOVA, > + .dma_len = DMA_LEN, > + .expected_result = 0, > + }; > + > + run_smmuv3_translation(&cfg); > +} > + > +int main(int argc, char **argv) > +{ > + g_test_init(&argc, &argv, NULL); > + qtest_add_func("/iommu-testdev/translation/ns-s1-only", > + test_smmuv3_ns_s1_only); > + qtest_add_func("/iommu-testdev/translation/ns-s2-only", > + test_smmuv3_ns_s2_only); > + qtest_add_func("/iommu-testdev/translation/ns-nested", > + test_smmuv3_ns_nested); > + return g_test_run(); > +} > diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build > index 669d07c06b..e2d2e68092 100644 > --- a/tests/qtest/meson.build > +++ b/tests/qtest/meson.build > @@ -263,6 +263,7 @@ qtests_aarch64 = \ > config_all_devices.has_key('CONFIG_TPM_TIS_I2C') ? ['tpm-tis-i2c-test'] : > []) + \ > (config_all_devices.has_key('CONFIG_ASPEED_SOC') ? qtests_aspeed64 : []) + > \ > (config_all_devices.has_key('CONFIG_NPCM8XX') ? qtests_npcm8xx : []) + \ > + (config_all_devices.has_key('CONFIG_IOMMU_TESTDEV') ? > ['iommu-smmuv3-test'] : []) + \ One question: since it can only run along with VIRT machine, how do we make sure this only runs with that machine enabled?
Thanks Eric > qtests_cxl + > \ > ['arm-cpu-features', > 'numa-test',
