master
c 140 lines 3.71 KB
Raw
1 /*
2 * QTest for Intel IOMMU (VT-d) with iommu-testdev
3 *
4 * This QTest file is used to test the Intel IOMMU with iommu-testdev so that
5 * we can test VT-d without any guest kernel or firmware.
6 *
7 * Copyright (c) 2026 Fengyuan Yu <15fengyuan@gmail.com>
8 *
9 * SPDX-License-Identifier: GPL-2.0-or-later
10 */
11
12 #include "qemu/osdep.h"
13 #include "libqtest.h"
14 #include "libqos/pci.h"
15 #include "libqos/pci-pc.h"
16 #include "hw/i386/intel_iommu_internal.h"
17 #include "hw/misc/iommu-testdev.h"
18 #include "libqos/qos-intel-iommu.h"
19
20 #define DMA_LEN 4
21
22 static uint64_t intel_iommu_expected_gpa(uint64_t iova)
23 {
24 return (QVTD_PT_VAL & VTD_PAGE_MASK_4K) + (iova & 0xfff);
25 }
26
27 static void run_intel_iommu_translation(const QVTDTestConfig *cfg)
28 {
29 QTestState *qts;
30 QPCIBus *pcibus;
31 QPCIDevice *dev;
32 QPCIBar bar;
33
34 if (!qtest_has_machine("q35")) {
35 g_test_skip("q35 machine not available");
36 return;
37 }
38
39 /* Initialize QEMU environment for Intel IOMMU testing */
40 qts = qtest_initf("-machine q35 -smp 1 -m 512 -net none "
41 "%s -device iommu-testdev",
42 qvtd_iommu_args(cfg->trans_mode));
43
44 /* Check CAP/ECAP capabilities for required translation mode */
45 if (!qvtd_check_caps(qts, cfg->trans_mode)) {
46 qtest_quit(qts);
47 return;
48 }
49
50 /* Setup and configure IOMMU-testdev PCI device */
51 dev = qvtd_setup_qtest_pci_device(qts, &pcibus, &bar);
52 g_assert(dev);
53
54 g_test_message("### Intel IOMMU translation mode=%d ###", cfg->trans_mode);
55 qvtd_run_translation_case(qts, dev, bar, Q35_HOST_BRIDGE_IOMMU_ADDR, cfg);
56 g_free(dev);
57 qpci_free_pc(pcibus);
58 qtest_quit(qts);
59 }
60
61 static void test_intel_iommu_legacy_pt(void)
62 {
63 QVTDTestConfig cfg = {
64 .trans_mode = QVTD_TM_LEGACY_PT,
65 .dma_gpa = QVTD_IOVA, /* pass-through: GPA == IOVA */
66 .dma_len = DMA_LEN,
67 .expected_result = 0,
68 };
69
70 run_intel_iommu_translation(&cfg);
71 }
72
73 static void test_intel_iommu_legacy_trans(void)
74 {
75 QVTDTestConfig cfg = {
76 .trans_mode = QVTD_TM_LEGACY_TRANS,
77 .dma_gpa = intel_iommu_expected_gpa(QVTD_IOVA),
78 .dma_len = DMA_LEN,
79 .expected_result = 0,
80 };
81
82 run_intel_iommu_translation(&cfg);
83 }
84
85 static void test_intel_iommu_scalable_pt(void)
86 {
87 QVTDTestConfig cfg = {
88 .trans_mode = QVTD_TM_SCALABLE_PT,
89 .dma_gpa = QVTD_IOVA, /* pass-through: GPA == IOVA */
90 .dma_len = DMA_LEN,
91 .expected_result = 0,
92 };
93
94 run_intel_iommu_translation(&cfg);
95 }
96
97 static void test_intel_iommu_scalable_slt(void)
98 {
99 QVTDTestConfig cfg = {
100 .trans_mode = QVTD_TM_SCALABLE_SLT,
101 .dma_gpa = intel_iommu_expected_gpa(QVTD_IOVA),
102 .dma_len = DMA_LEN,
103 .expected_result = 0,
104 };
105
106 run_intel_iommu_translation(&cfg);
107 }
108
109 static void test_intel_iommu_scalable_flt(void)
110 {
111 QVTDTestConfig cfg = {
112 .trans_mode = QVTD_TM_SCALABLE_FLT,
113 .dma_gpa = intel_iommu_expected_gpa(QVTD_IOVA),
114 .dma_len = DMA_LEN,
115 .expected_result = 0,
116 };
117
118 run_intel_iommu_translation(&cfg);
119 }
120
121 int main(int argc, char **argv)
122 {
123 g_test_init(&argc, &argv, NULL);
124
125 /* Legacy mode tests */
126 qtest_add_func("/iommu-testdev/intel/legacy-pt",
127 test_intel_iommu_legacy_pt);
128 qtest_add_func("/iommu-testdev/intel/legacy-trans",
129 test_intel_iommu_legacy_trans);
130
131 /* Scalable mode tests */
132 qtest_add_func("/iommu-testdev/intel/scalable-pt",
133 test_intel_iommu_scalable_pt);
134 qtest_add_func("/iommu-testdev/intel/scalable-slt",
135 test_intel_iommu_scalable_slt);
136 qtest_add_func("/iommu-testdev/intel/scalable-flt",
137 test_intel_iommu_scalable_flt);
138
139 return g_test_run();
140 }