From: Tao Tang Date: Thu, 25 Sep 2025 15:35:50 +0000 (+0800) Subject: tests/qtest: Add SMMUv3 bare-metal test using iommu-testdev X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d8d19c31b220142641370f275e8423d5f93e1840;p=thirdparty%2Fqemu.git tests/qtest: Add SMMUv3 bare-metal test using iommu-testdev 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 Tested-by: Pierrick Bouvier Reviewed-by: Pierrick Bouvier Message-ID: <20260119161112.3841386-9-tangtao1634@phytium.com.cn> [PMD: Cover tests/qtest/iommu-smmuv3-test.c in MAINTAINERS] Signed-off-by: Philippe Mathieu-Daudé --- diff --git a/MAINTAINERS b/MAINTAINERS index dc31be033e..1fd495ddd5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -222,6 +222,7 @@ S: Maintained F: hw/arm/smmu* F: include/hw/arm/smmu* F: tests/functional/aarch64/test_smmu.py +F: tests/qtest/iommu-smmuv3-test.c AVR TCG CPUs M: Michael Rolnik diff --git a/tests/qtest/iommu-smmuv3-test.c b/tests/qtest/iommu-smmuv3-test.c new file mode 100644 index 0000000000..cced49a9b6 --- /dev/null +++ b/tests/qtest/iommu-smmuv3-test.c @@ -0,0 +1,132 @@ +/* + * 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) 2026 Phytium Technology + * + * Author: + * Tao Tang + * + * 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 uint64_t smmuv3_expected_gpa(uint64_t iova) +{ + return qsmmu_space_offset(QSMMU_SPACE_NONSECURE) + + QSMMU_L3_PTE_VAL + (iova & 0xfff); +} + +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; + + if (!qtest_has_machine("virt")) { + g_test_skip("virt machine not available"); + return; + } + + /* 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_gpa = smmuv3_expected_gpa(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_gpa = smmuv3_expected_gpa(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_gpa = smmuv3_expected_gpa(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 0f053fb56d..a8b09d065f 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -264,6 +264,9 @@ 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') and + config_all_devices.has_key('CONFIG_ARM_VIRT') ? + ['iommu-smmuv3-test'] : []) + \ qtests_cxl + \ ['arm-cpu-features', 'numa-test',