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