master
h 259 lines 9.81 KB
Raw
1 /*
2 * QOS Intel IOMMU (VT-d) Module
3 *
4 * This module provides Intel IOMMU-specific helper functions for libqos tests,
5 * encapsulating VT-d setup, assertion, and cleanup operations.
6 *
7 * Copyright (c) 2026 Fengyuan Yu <15fengyuan@gmail.com>
8 *
9 * SPDX-License-Identifier: GPL-2.0-or-later
10 */
11
12 #ifndef QTEST_LIBQOS_INTEL_IOMMU_H
13 #define QTEST_LIBQOS_INTEL_IOMMU_H
14
15 #include "hw/misc/iommu-testdev.h"
16 #include "hw/i386/intel_iommu_internal.h"
17
18 /*
19 * Guest memory layout for IOMMU structures.
20 * All structures are placed in guest physical memory inside the 512MB RAM.
21 * Using 256MB mark (0x10000000) as base to ensure all structures fit in RAM.
22 */
23 #define QVTD_MEM_BASE 0x10000000ULL
24
25 /* Root Entry Table: 256 entries * 16 bytes = 4KB */
26 #define QVTD_ROOT_TABLE_BASE (QVTD_MEM_BASE + 0x00000000)
27
28 /* Context Entry Table: 256 entries, 16B (legacy) or 32B (scalable) per entry */
29 #define QVTD_CONTEXT_TABLE_BASE (QVTD_MEM_BASE + 0x00001000)
30
31 /* Page Tables: 4-level hierarchy for 48-bit address translation */
32 #define QVTD_PT_L4_BASE (QVTD_MEM_BASE + 0x00010000) /* PML4 */
33 #define QVTD_PT_L3_BASE (QVTD_MEM_BASE + 0x00011000) /* PDPT */
34 #define QVTD_PT_L2_BASE (QVTD_MEM_BASE + 0x00012000) /* PD */
35 #define QVTD_PT_L1_BASE (QVTD_MEM_BASE + 0x00013000) /* PT */
36
37 /*
38 * Invalidation Queue.
39 * IQA_REG bits[2:0] = QS, entries = 1 << (QS + 8), each entry 16 bytes.
40 */
41 #define QVTD_IQ_BASE (QVTD_MEM_BASE + 0x00020000)
42 #define QVTD_IQ_QS 0 /* QS=0 → 256 entries */
43 #define QVTD_IQ_DESC_SIZE 16 /* 128-bit descriptor (iq_dw=0) */
44 #define QVTD_IQT_SHIFT 4 /* IQT_REG[18:4] is the tail index */
45
46 /*
47 * Invalidation Wait Descriptor with Status Write (VT-d 6.5.2.8).
48 * The IOMMU writes QVTD_INV_WAIT_DATA to QVTD_INV_WAIT_ADDR after all
49 * preceding invalidation descriptors complete.
50 */
51 #define QVTD_INV_WAIT_ADDR (QVTD_MEM_BASE + 0x00040000)
52 #define QVTD_INV_WAIT_DATA 0x1u
53
54 /*
55 * Fault Event MSI configuration.
56 */
57 #define QVTD_FAULT_IRQ_ADDR 0xfee00000 /* APIC base */
58 #define QVTD_FAULT_IRQ_DATA 0x0
59
60 /* Scalable mode PASID structures */
61 #define QVTD_PASID_DIR_BASE (QVTD_MEM_BASE + 0x00030000)
62 #define QVTD_PASID_TABLE_BASE (QVTD_MEM_BASE + 0x00031000)
63
64 /* Page table entry size (8 bytes per PTE) */
65 #define QVTD_PTE_SIZE sizeof(uint64_t)
66
67 /* FSPTPTR mask: same as VTD_SM_PASID_ENTRY_SSPTPTR, bits[63:12] */
68 #define QVTD_SM_PASID_ENTRY_FSPTPTR VTD_SM_PASID_ENTRY_SSPTPTR
69
70 /* Default Domain ID for single-domain tests */
71 #define QVTD_DOMAIN_ID 0
72
73 /* Test IOVA and target physical address */
74 #define QVTD_IOVA 0x0000000010200567ull
75 #define QVTD_PT_VAL (QVTD_MEM_BASE + 0x00100000)
76
77 /*
78 * Translation modes supported by Intel IOMMU
79 */
80 typedef enum QVTDTransMode {
81 QVTD_TM_LEGACY_PT, /* Legacy pass-through mode */
82 QVTD_TM_LEGACY_TRANS, /* Legacy translated mode (4-level paging) */
83 QVTD_TM_SCALABLE_PT, /* Scalable pass-through mode */
84 QVTD_TM_SCALABLE_SLT, /* Scalable Second Level Translation */
85 QVTD_TM_SCALABLE_FLT, /* Scalable First Level Translation */
86 } QVTDTransMode;
87
88 static inline bool qvtd_is_scalable(QVTDTransMode mode)
89 {
90 return mode == QVTD_TM_SCALABLE_PT ||
91 mode == QVTD_TM_SCALABLE_SLT ||
92 mode == QVTD_TM_SCALABLE_FLT;
93 }
94
95 typedef struct QVTDTestConfig {
96 QVTDTransMode trans_mode; /* Translation mode */
97 uint64_t dma_gpa; /* GPA for readback validation */
98 uint32_t dma_len; /* DMA length for testing */
99 uint32_t expected_result; /* Expected DMA result */
100 } QVTDTestConfig;
101
102 typedef struct QVTDTestContext {
103 QTestState *qts; /* QTest state handle */
104 QPCIDevice *dev; /* PCI device handle */
105 QPCIBar bar; /* PCI BAR for MMIO access */
106 QVTDTestConfig config; /* Test configuration */
107 uint64_t iommu_base; /* Intel IOMMU base address */
108 uint32_t trans_status; /* Translation configuration status */
109 uint32_t dma_result; /* DMA operation result */
110 uint16_t sid; /* Source ID (bus:devfn) */
111 } QVTDTestContext;
112
113 /*
114 * qvtd_setup_and_enable_translation - Complete translation setup and enable
115 *
116 * @ctx: Test context containing configuration and device handles
117 *
118 * Returns: Translation status (0 = success, non-zero = error)
119 *
120 * This function performs the complete translation setup sequence:
121 * 1. Builds VT-d structures (root/context entry, page tables)
122 * 2. Programs IOMMU registers and enables translation
123 * 3. Returns configuration status
124 */
125 uint32_t qvtd_setup_and_enable_translation(QVTDTestContext *ctx);
126
127 /*
128 * qvtd_build_translation - Build Intel IOMMU translation structures
129 *
130 * @qts: QTest state handle
131 * @mode: Translation mode (pass-through or translated)
132 * @sid: Source ID (bus:devfn)
133 *
134 * Returns: Build status (0 = success, non-zero = error)
135 *
136 * Constructs all necessary VT-d translation structures in guest memory:
137 * - Root Entry for the device's bus
138 * - Context Entry for the device
139 * - Complete 4-level page table hierarchy (if translated mode)
140 */
141 uint32_t qvtd_build_translation(QTestState *qts, QVTDTransMode mode,
142 uint16_t sid);
143
144 /*
145 * qvtd_program_regs - Program Intel IOMMU registers and enable translation
146 *
147 * @qts: QTest state handle
148 * @iommu_base: IOMMU base address
149 * @mode: Translation mode (scalable modes set RTADDR SMT bit)
150 *
151 * Programs IOMMU registers with the following sequence:
152 * 1. Set root table pointer (SRTP), with SMT bit for scalable mode
153 * 2. Setup invalidation queue (QIE)
154 * 3. Configure fault event MSI
155 * 4. Enable translation (TE)
156 *
157 * Each step verifies completion via GSTS register read-back.
158 */
159 void qvtd_program_regs(QTestState *qts, uint64_t iommu_base,
160 QVTDTransMode mode);
161
162 /*
163 * qvtd_setup_translation_tables - Setup complete VT-d page table hierarchy
164 *
165 * @qts: QTest state handle
166 * @iova: Input Virtual Address to translate
167 * @mode: Translation mode
168 *
169 * This builds the 4-level page table structure for translating
170 * the given IOVA to PA through Intel VT-d. The structure is:
171 * - PML4 (Level 4): IOVA bits [47:39]
172 * - PDPT (Level 3): IOVA bits [38:30]
173 * - PD (Level 2): IOVA bits [29:21]
174 * - PT (Level 1): IOVA bits [20:12]
175 * - Page offset: IOVA bits [11:0]
176 *
177 * The function writes all necessary Page Table Entries (PTEs) to guest
178 * memory using qtest_writeq(), setting up the complete translation path
179 * that the VT-d hardware will traverse during DMA operations.
180 */
181 void qvtd_setup_translation_tables(QTestState *qts, uint64_t iova,
182 QVTDTransMode mode);
183
184 /* Calculate expected DMA result */
185 uint32_t qvtd_expected_dma_result(QVTDTestContext *ctx);
186
187 /* Build DMA attributes for Intel VT-d */
188 uint32_t qvtd_build_dma_attrs(void);
189
190 /* High-level test execution helpers */
191 void qvtd_run_translation_case(QTestState *qts, QPCIDevice *dev,
192 QPCIBar bar, uint64_t iommu_base,
193 const QVTDTestConfig *cfg);
194
195 /*
196 * qvtd_iommu_args - Build the -device intel-iommu command-line fragment
197 * for the requested translation mode.
198 */
199 const char *qvtd_iommu_args(QVTDTransMode mode);
200
201 /*
202 * qvtd_check_caps - Check whether the running QEMU exposes the ECAP bits
203 * required by @mode. Calls g_test_skip() and returns
204 * false when a required capability is missing.
205 */
206 bool qvtd_check_caps(QTestState *qts, QVTDTransMode mode);
207
208 /*
209 * qvtd_setup_qtest_pci_device - Create a QPCIBus, locate the iommu-testdev
210 * PCI function, enable it and map BAR0.
211 *
212 * On success, *pcibus and *bar are populated and the returned QPCIDevice
213 * must be released by the caller via g_free().
214 */
215 QPCIDevice *qvtd_setup_qtest_pci_device(QTestState *qts, QPCIBus **pcibus,
216 QPCIBar *bar);
217
218 /*
219 * qvtd_leaf_pte_addr - Address of the leaf (L1) PTE for @iova, assuming
220 * the hierarchy was built by
221 * qvtd_setup_translation_tables() with 4 KB leaves.
222 */
223 uint64_t qvtd_leaf_pte_addr(uint64_t iova);
224
225 /*
226 * qvtd_make_leaf_pte - Build a leaf PTE value mapping @pa, for the
227 * 4-level / 4 KB-leaf layout used by
228 * qvtd_setup_translation_tables().
229 * Selects FLT or SLT/legacy attributes from @mode.
230 */
231 uint64_t qvtd_make_leaf_pte(uint64_t pa, QVTDTransMode mode);
232
233 /*
234 * qvtd_submit_inv_wait_and_poll - Submit an Invalidation Wait Descriptor
235 * with Status Write and poll until the
236 * IOMMU writes the expected status data.
237 *
238 * Asserts on timeout. Returns the new tail index.
239 */
240 uint32_t qvtd_submit_inv_wait_and_poll(QTestState *qts, uint64_t iommu_base,
241 uint32_t tail);
242
243 /*
244 * qvtd_submit_iotlb_global_inv - global IOTLB invalidation.
245 * qvtd_submit_iotlb_domain_inv - domain-selective IOTLB invalidation.
246 * qvtd_submit_iotlb_page_inv - page-selective IOTLB invalidation;
247 * @addr must be 4 KB aligned. @am
248 * selects the address mask per VT-d
249 * 6.5.2.4 (am=0 → single 4 KB page).
250 */
251 uint32_t qvtd_submit_iotlb_global_inv(QTestState *qts, uint64_t iommu_base,
252 uint32_t tail);
253 uint32_t qvtd_submit_iotlb_domain_inv(QTestState *qts, uint64_t iommu_base,
254 uint16_t domain_id, uint32_t tail);
255 uint32_t qvtd_submit_iotlb_page_inv(QTestState *qts, uint64_t iommu_base,
256 uint16_t domain_id, uint64_t addr,
257 uint8_t am, uint32_t tail);
258
259 #endif /* QTEST_LIBQOS_INTEL_IOMMU_H */