master
c 138 lines 3.6 KB
Raw
1 /*
2 * QTest for SMMUv3 with iommu-testdev
3 *
4 * This QTest file is used to test the SMMUv3 with iommu-testdev so that we can
5 * test SMMUv3 without any guest kernel or firmware.
6 *
7 * Copyright (c) 2026 Phytium Technology
8 *
9 * Author:
10 * Tao Tang <tangtao1634@phytium.com.cn>
11 *
12 * SPDX-License-Identifier: GPL-2.0-or-later
13 */
14
15 #include "qemu/osdep.h"
16 #include "libqtest.h"
17 #include "libqos/pci.h"
18 #include "libqos/generic-pcihost.h"
19 #include "hw/pci/pci_regs.h"
20 #include "hw/misc/iommu-testdev.h"
21 #include "libqos/qos-smmuv3.h"
22
23 #define DMA_LEN 4
24
25 static uint64_t smmuv3_expected_gpa(uint64_t iova)
26 {
27 return qsmmu_space_offset(QSMMU_SPACE_NONSECURE) +
28 QSMMU_L3_PTE_VAL + (iova & 0xfff);
29 }
30
31 static void save_fn(QPCIDevice *dev, int devfn, void *data)
32 {
33 QPCIDevice **pdev = (QPCIDevice **) data;
34
35 *pdev = dev;
36 }
37
38 static QPCIDevice *setup_qtest_pci_device(QTestState *qts, QGenericPCIBus *gbus,
39 QPCIBar *bar)
40 {
41 QPCIDevice *dev = NULL;
42
43 qpci_init_generic(gbus, qts, NULL, false);
44
45 qpci_device_foreach(&gbus->bus, IOMMU_TESTDEV_VENDOR_ID,
46 IOMMU_TESTDEV_DEVICE_ID, save_fn, &dev);
47 g_assert(dev);
48
49 qpci_device_enable(dev);
50 *bar = qpci_iomap(dev, 0, NULL);
51 g_assert_false(bar->is_io);
52
53 return dev;
54 }
55
56 static void run_smmuv3_translation(const QSMMUTestConfig *cfg)
57 {
58 QTestState *qts;
59 QGenericPCIBus gbus;
60 QPCIDevice *dev;
61 QPCIBar bar;
62
63 if (!qtest_has_machine("virt")) {
64 g_test_skip("virt machine not available");
65 return;
66 }
67 if (!qtest_has_device("arm-gicv3")) {
68 /* This can happen for a KVM-only build: qtest uses the TCG GICv3 */
69 g_test_skip("gicv3 not available");
70 return;
71 }
72
73 /* Initialize QEMU environment for SMMU testing */
74 qts = qtest_init("-machine virt,acpi=off,gic-version=3,iommu=smmuv3 "
75 "-smp 1 -m 512 -cpu max -net none "
76 "-device iommu-testdev");
77
78 /* Setup and configure PCI device */
79 dev = setup_qtest_pci_device(qts, &gbus, &bar);
80 g_assert(dev);
81
82 g_test_message("### SMMUv3 translation mode=%d sec_sid=%d ###",
83 cfg->trans_mode, cfg->sec_sid);
84 qsmmu_run_translation_case(qts, dev, bar, VIRT_SMMU_BASE, cfg);
85 g_free(dev);
86 qtest_quit(qts);
87 }
88
89 static void test_smmuv3_ns_s1_only(void)
90 {
91 QSMMUTestConfig cfg = {
92 .trans_mode = QSMMU_TM_S1_ONLY,
93 .sec_sid = QSMMU_SEC_SID_NONSECURE,
94 .dma_gpa = smmuv3_expected_gpa(QSMMU_IOVA),
95 .dma_len = DMA_LEN,
96 .expected_result = 0,
97 };
98
99 run_smmuv3_translation(&cfg);
100 }
101
102 static void test_smmuv3_ns_s2_only(void)
103 {
104 QSMMUTestConfig cfg = {
105 .trans_mode = QSMMU_TM_S2_ONLY,
106 .sec_sid = QSMMU_SEC_SID_NONSECURE,
107 .dma_gpa = smmuv3_expected_gpa(QSMMU_IOVA),
108 .dma_len = DMA_LEN,
109 .expected_result = 0,
110 };
111
112 run_smmuv3_translation(&cfg);
113 }
114
115 static void test_smmuv3_ns_nested(void)
116 {
117 QSMMUTestConfig cfg = {
118 .trans_mode = QSMMU_TM_NESTED,
119 .sec_sid = QSMMU_SEC_SID_NONSECURE,
120 .dma_gpa = smmuv3_expected_gpa(QSMMU_IOVA),
121 .dma_len = DMA_LEN,
122 .expected_result = 0,
123 };
124
125 run_smmuv3_translation(&cfg);
126 }
127
128 int main(int argc, char **argv)
129 {
130 g_test_init(&argc, &argv, NULL);
131 qtest_add_func("/iommu-testdev/translation/ns-s1-only",
132 test_smmuv3_ns_s1_only);
133 qtest_add_func("/iommu-testdev/translation/ns-s2-only",
134 test_smmuv3_ns_s2_only);
135 qtest_add_func("/iommu-testdev/translation/ns-nested",
136 test_smmuv3_ns_nested);
137 return g_test_run();
138 }