1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22#ifndef INTEL_IOMMU_H
23#define INTEL_IOMMU_H
24#include "hw/qdev.h"
25#include "sysemu/dma.h"
26#include "hw/i386/x86-iommu.h"
27#include "hw/i386/ioapic.h"
28#include "hw/pci/msi.h"
29#include "hw/sysbus.h"
30
31#define TYPE_INTEL_IOMMU_DEVICE "intel-iommu"
32#define INTEL_IOMMU_DEVICE(obj) \
33 OBJECT_CHECK(IntelIOMMUState, (obj), TYPE_INTEL_IOMMU_DEVICE)
34
35#define TYPE_INTEL_IOMMU_MEMORY_REGION "intel-iommu-iommu-memory-region"
36
37
38#define Q35_HOST_BRIDGE_IOMMU_ADDR 0xfed90000ULL
39
40#define VTD_PCI_BUS_MAX 256
41#define VTD_PCI_SLOT_MAX 32
42#define VTD_PCI_FUNC_MAX 8
43#define VTD_PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f)
44#define VTD_PCI_FUNC(devfn) ((devfn) & 0x07)
45#define VTD_SID_TO_BUS(sid) (((sid) >> 8) & 0xff)
46#define VTD_SID_TO_DEVFN(sid) ((sid) & 0xff)
47
48#define DMAR_REG_SIZE 0x230
49#define VTD_HOST_ADDRESS_WIDTH 39
50#define VTD_HAW_MASK ((1ULL << VTD_HOST_ADDRESS_WIDTH) - 1)
51
52#define DMAR_REPORT_F_INTR (1)
53
54#define VTD_MSI_ADDR_HI_MASK (0xffffffff00000000ULL)
55#define VTD_MSI_ADDR_HI_SHIFT (32)
56#define VTD_MSI_ADDR_LO_MASK (0x00000000ffffffffULL)
57
58typedef struct VTDContextEntry VTDContextEntry;
59typedef struct VTDContextCacheEntry VTDContextCacheEntry;
60typedef struct IntelIOMMUState IntelIOMMUState;
61typedef struct VTDAddressSpace VTDAddressSpace;
62typedef struct VTDIOTLBEntry VTDIOTLBEntry;
63typedef struct VTDBus VTDBus;
64typedef union VTD_IR_TableEntry VTD_IR_TableEntry;
65typedef union VTD_IR_MSIAddress VTD_IR_MSIAddress;
66typedef struct VTDIrq VTDIrq;
67typedef struct VTD_MSIMessage VTD_MSIMessage;
68typedef struct IntelIOMMUNotifierNode IntelIOMMUNotifierNode;
69
70
71struct VTDContextEntry {
72 uint64_t lo;
73 uint64_t hi;
74};
75
76struct VTDContextCacheEntry {
77
78
79
80 uint32_t context_cache_gen;
81 struct VTDContextEntry context_entry;
82};
83
84struct VTDAddressSpace {
85 PCIBus *bus;
86 uint8_t devfn;
87 AddressSpace as;
88 IOMMUMemoryRegion iommu;
89 MemoryRegion root;
90 MemoryRegion sys_alias;
91 MemoryRegion iommu_ir;
92 IntelIOMMUState *iommu_state;
93 VTDContextCacheEntry context_cache_entry;
94};
95
96struct VTDBus {
97 PCIBus* bus;
98 VTDAddressSpace *dev_as[0];
99};
100
101struct VTDIOTLBEntry {
102 uint64_t gfn;
103 uint16_t domain_id;
104 uint64_t slpte;
105 uint64_t mask;
106 uint8_t access_flags;
107};
108
109
110enum {
111 VTD_SQ_FULL = 0x00,
112 VTD_SQ_IGN_3 = 0x01,
113 VTD_SQ_IGN_2_3 = 0x02,
114 VTD_SQ_IGN_1_3 = 0x03,
115 VTD_SQ_MAX,
116};
117
118
119enum {
120 VTD_SVT_NONE = 0x00,
121 VTD_SVT_ALL = 0x01,
122 VTD_SVT_BUS = 0x02,
123 VTD_SVT_MAX,
124};
125
126
127union VTD_IR_TableEntry {
128 struct {
129#ifdef HOST_WORDS_BIGENDIAN
130 uint32_t __reserved_1:8;
131 uint32_t vector:8;
132 uint32_t irte_mode:1;
133 uint32_t __reserved_0:3;
134 uint32_t __avail:4;
135 uint32_t delivery_mode:3;
136 uint32_t trigger_mode:1;
137 uint32_t redir_hint:1;
138 uint32_t dest_mode:1;
139 uint32_t fault_disable:1;
140 uint32_t present:1;
141#else
142 uint32_t present:1;
143 uint32_t fault_disable:1;
144 uint32_t dest_mode:1;
145 uint32_t redir_hint:1;
146 uint32_t trigger_mode:1;
147 uint32_t delivery_mode:3;
148 uint32_t __avail:4;
149 uint32_t __reserved_0:3;
150 uint32_t irte_mode:1;
151 uint32_t vector:8;
152 uint32_t __reserved_1:8;
153#endif
154 uint32_t dest_id;
155 uint16_t source_id;
156#ifdef HOST_WORDS_BIGENDIAN
157 uint64_t __reserved_2:44;
158 uint64_t sid_vtype:2;
159 uint64_t sid_q:2;
160#else
161 uint64_t sid_q:2;
162 uint64_t sid_vtype:2;
163 uint64_t __reserved_2:44;
164#endif
165 } QEMU_PACKED irte;
166 uint64_t data[2];
167};
168
169#define VTD_IR_INT_FORMAT_COMPAT (0)
170#define VTD_IR_INT_FORMAT_REMAP (1)
171
172
173union VTD_IR_MSIAddress {
174 struct {
175#ifdef HOST_WORDS_BIGENDIAN
176 uint32_t __head:12;
177 uint32_t index_l:15;
178 uint32_t int_mode:1;
179 uint32_t sub_valid:1;
180 uint32_t index_h:1;
181 uint32_t __not_care:2;
182#else
183 uint32_t __not_care:2;
184 uint32_t index_h:1;
185 uint32_t sub_valid:1;
186 uint32_t int_mode:1;
187 uint32_t index_l:15;
188 uint32_t __head:12;
189#endif
190 } QEMU_PACKED addr;
191 uint32_t data;
192};
193
194
195struct VTDIrq {
196
197 uint8_t trigger_mode;
198 uint8_t vector;
199 uint8_t delivery_mode;
200 uint32_t dest;
201 uint8_t dest_mode;
202
203
204 uint8_t redir_hint;
205 uint8_t msi_addr_last_bits;
206};
207
208struct VTD_MSIMessage {
209 union {
210 struct {
211#ifdef HOST_WORDS_BIGENDIAN
212 uint32_t __addr_head:12;
213 uint32_t dest:8;
214 uint32_t __reserved:8;
215 uint32_t redir_hint:1;
216 uint32_t dest_mode:1;
217 uint32_t __not_used:2;
218#else
219 uint32_t __not_used:2;
220 uint32_t dest_mode:1;
221 uint32_t redir_hint:1;
222 uint32_t __reserved:8;
223 uint32_t dest:8;
224 uint32_t __addr_head:12;
225#endif
226 uint32_t __addr_hi;
227 } QEMU_PACKED;
228 uint64_t msi_addr;
229 };
230 union {
231 struct {
232#ifdef HOST_WORDS_BIGENDIAN
233 uint16_t trigger_mode:1;
234 uint16_t level:1;
235 uint16_t __resved:3;
236 uint16_t delivery_mode:3;
237 uint16_t vector:8;
238#else
239 uint16_t vector:8;
240 uint16_t delivery_mode:3;
241 uint16_t __resved:3;
242 uint16_t level:1;
243 uint16_t trigger_mode:1;
244#endif
245 uint16_t __resved1;
246 } QEMU_PACKED;
247 uint32_t msi_data;
248 };
249};
250
251
252#define VTD_IR_MSI_DATA (0)
253
254struct IntelIOMMUNotifierNode {
255 VTDAddressSpace *vtd_as;
256 QLIST_ENTRY(IntelIOMMUNotifierNode) next;
257};
258
259
260struct IntelIOMMUState {
261 X86IOMMUState x86_iommu;
262 MemoryRegion csrmem;
263 uint8_t csr[DMAR_REG_SIZE];
264 uint8_t wmask[DMAR_REG_SIZE];
265 uint8_t w1cmask[DMAR_REG_SIZE];
266 uint8_t womask[DMAR_REG_SIZE];
267 uint32_t version;
268
269 bool caching_mode;
270
271 dma_addr_t root;
272 bool root_extended;
273 bool dmar_enabled;
274
275 uint16_t iq_head;
276 uint16_t iq_tail;
277 dma_addr_t iq;
278 uint16_t iq_size;
279 bool qi_enabled;
280 uint8_t iq_last_desc_type;
281
282
283
284
285 uint16_t next_frcd_reg;
286
287 uint64_t cap;
288 uint64_t ecap;
289
290 uint32_t context_cache_gen;
291 GHashTable *iotlb;
292
293 GHashTable *vtd_as_by_busptr;
294 VTDBus *vtd_as_by_bus_num[VTD_PCI_BUS_MAX];
295
296 QLIST_HEAD(, IntelIOMMUNotifierNode) notifiers_list;
297
298
299 bool intr_enabled;
300 dma_addr_t intr_root;
301 uint32_t intr_size;
302 bool intr_eime;
303 OnOffAuto intr_eim;
304 bool buggy_eim;
305};
306
307
308
309
310VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn);
311
312#endif
313