VirtualBox

source: vbox/trunk/src/VBox/Devices/Bus/DevIommuIntel.cpp@ 89307

Last change on this file since 89307 was 89307, checked in by vboxsync, 4 years ago

Intel IOMMU: bugref:9967 Fix second-level large page support bitmask.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 160.9 KB
Line 
1/* $Id: DevIommuIntel.cpp 89307 2021-05-27 06:16:37Z vboxsync $ */
2/** @file
3 * IOMMU - Input/Output Memory Management Unit - Intel implementation.
4 */
5
6/*
7 * Copyright (C) 2021 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_DEV_IOMMU
23#include "VBoxDD.h"
24#include "DevIommuIntel.h"
25
26#include <iprt/mem.h>
27#include <iprt/string.h>
28
29
30/*********************************************************************************************************************************
31* Defined Constants And Macros *
32*********************************************************************************************************************************/
33/** Gets the low uint32_t of a uint64_t or something equivalent.
34 *
35 * This is suitable for casting constants outside code (since RT_LO_U32 can't be
36 * used as it asserts for correctness when compiling on certain compilers). */
37#define DMAR_LO_U32(a) (uint32_t)(UINT32_MAX & (a))
38
39/** Gets the high uint32_t of a uint64_t or something equivalent.
40 *
41 * This is suitable for casting constants outside code (since RT_HI_U32 can't be
42 * used as it asserts for correctness when compiling on certain compilers). */
43#define DMAR_HI_U32(a) (uint32_t)((a) >> 32)
44
45/** Asserts MMIO access' offset and size are valid or returns appropriate error
46 * code suitable for returning from MMIO access handlers. */
47#define DMAR_ASSERT_MMIO_ACCESS_RET(a_off, a_cb) \
48 do { \
49 AssertReturn((a_cb) == 4 || (a_cb) == 8, VINF_IOM_MMIO_UNUSED_FF); \
50 AssertReturn(!((a_off) & ((a_cb) - 1)), VINF_IOM_MMIO_UNUSED_FF); \
51 } while (0)
52
53/** Checks if the MMIO offset is valid. */
54#define DMAR_IS_MMIO_OFF_VALID(a_off) ( (a_off) < DMAR_MMIO_GROUP_0_OFF_END \
55 || (a_off) - DMAR_MMIO_GROUP_1_OFF_FIRST < DMAR_MMIO_GROUP_1_SIZE)
56
57/** Acquires the DMAR lock but returns with the given busy error code on failure. */
58#define DMAR_LOCK_RET(a_pDevIns, a_pThisCC, a_rcBusy) \
59 do { \
60 if ((a_pThisCC)->CTX_SUFF(pIommuHlp)->pfnLock((a_pDevIns), (a_rcBusy)) == VINF_SUCCESS) \
61 { /* likely */ } \
62 else \
63 return (a_rcBusy); \
64 } while (0)
65
66/** Acquires the DMAR lock (not expected to fail). */
67#ifdef IN_RING3
68# define DMAR_LOCK(a_pDevIns, a_pThisCC) (a_pThisCC)->CTX_SUFF(pIommuHlp)->pfnLock((a_pDevIns), VERR_IGNORED)
69#else
70# define DMAR_LOCK(a_pDevIns, a_pThisCC) \
71 do { \
72 int const rcLock = (a_pThisCC)->CTX_SUFF(pIommuHlp)->pfnLock((a_pDevIns), VINF_SUCCESS); \
73 AssertRC(rcLock); \
74 } while (0)
75#endif
76
77/** Release the DMAR lock. */
78#define DMAR_UNLOCK(a_pDevIns, a_pThisCC) (a_pThisCC)->CTX_SUFF(pIommuHlp)->pfnUnlock(a_pDevIns)
79
80/** Asserts that the calling thread owns the DMAR lock. */
81#define DMAR_ASSERT_LOCK_IS_OWNER(a_pDevIns, a_pThisCC) \
82 do { \
83 Assert((a_pThisCC)->CTX_SUFF(pIommuHlp)->pfnLockIsOwner(a_pDevIns)); \
84 RT_NOREF1(a_pThisCC); \
85 } while (0)
86
87/** Asserts that the calling thread does not own the DMAR lock. */
88#define DMAR_ASSERT_LOCK_IS_NOT_OWNER(a_pDevIns, a_pThisCC) \
89 do { \
90 Assert((a_pThisCC)->CTX_SUFF(pIommuHlp)->pfnLockIsOwner(a_pDevIns) == false); \
91 RT_NOREF1(a_pThisCC); \
92 } while (0)
93
94/** The number of fault recording registers our implementation supports.
95 * Normal guest operation shouldn't trigger faults anyway, so we only support the
96 * minimum number of registers (which is 1).
97 *
98 * See Intel VT-d spec. 10.4.2 "Capability Register" (CAP_REG.NFR). */
99#define DMAR_FRCD_REG_COUNT UINT32_C(1)
100
101/** Offset of first register in group 0. */
102#define DMAR_MMIO_GROUP_0_OFF_FIRST VTD_MMIO_OFF_VER_REG
103/** Offset of last register in group 0 (inclusive). */
104#define DMAR_MMIO_GROUP_0_OFF_LAST VTD_MMIO_OFF_MTRR_PHYSMASK9_REG
105/** Last valid offset in group 0 (exclusive). */
106#define DMAR_MMIO_GROUP_0_OFF_END (DMAR_MMIO_GROUP_0_OFF_LAST + 8 /* sizeof MTRR_PHYSMASK9_REG */)
107/** Size of the group 0 (in bytes). */
108#define DMAR_MMIO_GROUP_0_SIZE (DMAR_MMIO_GROUP_0_OFF_END - DMAR_MMIO_GROUP_0_OFF_FIRST)
109/**< Implementation-specific MMIO offset of IVA_REG. */
110#define DMAR_MMIO_OFF_IVA_REG 0xe50
111/**< Implementation-specific MMIO offset of IOTLB_REG. */
112#define DMAR_MMIO_OFF_IOTLB_REG 0xe58
113/**< Implementation-specific MMIO offset of FRCD_LO_REG. */
114#define DMAR_MMIO_OFF_FRCD_LO_REG 0xe70
115/**< Implementation-specific MMIO offset of FRCD_HI_REG. */
116#define DMAR_MMIO_OFF_FRCD_HI_REG 0xe78
117AssertCompile(!(DMAR_MMIO_OFF_FRCD_LO_REG & 0xf));
118
119/** Offset of first register in group 1. */
120#define DMAR_MMIO_GROUP_1_OFF_FIRST VTD_MMIO_OFF_VCCAP_REG
121/** Offset of last register in group 1 (inclusive). */
122#define DMAR_MMIO_GROUP_1_OFF_LAST (DMAR_MMIO_OFF_FRCD_LO_REG + 8) * DMAR_FRCD_REG_COUNT
123/** Last valid offset in group 1 (exclusive). */
124#define DMAR_MMIO_GROUP_1_OFF_END (DMAR_MMIO_GROUP_1_OFF_LAST + 8 /* sizeof FRCD_HI_REG */)
125/** Size of the group 1 (in bytes). */
126#define DMAR_MMIO_GROUP_1_SIZE (DMAR_MMIO_GROUP_1_OFF_END - DMAR_MMIO_GROUP_1_OFF_FIRST)
127
128/** DMAR implementation's major version number (exposed to software).
129 * We report 6 as the major version since we support queued-invalidations as
130 * software may make assumptions based on that.
131 *
132 * See Intel VT-d spec. 10.4.7 "Context Command Register" (CCMD_REG.CAIG). */
133#define DMAR_VER_MAJOR 6
134/** DMAR implementation's minor version number (exposed to software). */
135#define DMAR_VER_MINOR 0
136
137/** Number of domain supported (0=16, 1=64, 2=256, 3=1K, 4=4K, 5=16K, 6=64K,
138 * 7=Reserved). */
139#define DMAR_ND 6
140
141/** Release log prefix string. */
142#define DMAR_LOG_PFX "Intel-IOMMU"
143/** The current saved state version. */
144#define DMAR_SAVED_STATE_VERSION 1
145
146
147/*********************************************************************************************************************************
148* Structures and Typedefs *
149*********************************************************************************************************************************/
150/**
151 * DMAR error diagnostics.
152 * Sorted alphabetically so it's easier to add and locate items, no other reason.
153 *
154 * @note Members of this enum are used as array indices, so no gaps in enum
155 * values are not allowed. Update g_apszDmarDiagDesc when you modify
156 * fields in this enum.
157 */
158typedef enum
159{
160 /* No error, this must be zero! */
161 kDmarDiag_None = 0,
162
163 /* Address Translation Faults. */
164 kDmarDiag_Atf_Lct_1,
165 kDmarDiag_Atf_Lct_2,
166 kDmarDiag_Atf_Lct_3,
167 kDmarDiag_Atf_Lct_4_1,
168 kDmarDiag_Atf_Lct_4_2,
169 kDmarDiag_Atf_Lct_4_3,
170 kDmarDiag_Atf_Lrt_1,
171 kDmarDiag_Atf_Lrt_2,
172 kDmarDiag_Atf_Lrt_3,
173 kDmarDiag_Atf_Rta_1_1,
174 kDmarDiag_Atf_Rta_1_2,
175 kDmarDiag_Atf_Rta_1_3,
176
177 /* CCMD_REG faults. */
178 kDmarDiag_CcmdReg_NotSupported,
179 kDmarDiag_CcmdReg_Qi_Enabled,
180 kDmarDiag_CcmdReg_Ttm_Invalid,
181
182 /* IQA_REG faults. */
183 kDmarDiag_IqaReg_Dsc_Fetch_Error,
184 kDmarDiag_IqaReg_Dw_128_Invalid,
185 kDmarDiag_IqaReg_Dw_256_Invalid,
186
187 /* Invalidation Queue Error Info. */
188 kDmarDiag_Iqei_Dsc_Type_Invalid,
189 kDmarDiag_Iqei_Inv_Wait_Dsc_0_1_Rsvd,
190 kDmarDiag_Iqei_Inv_Wait_Dsc_2_3_Rsvd,
191 kDmarDiag_Iqei_Inv_Wait_Dsc_Invalid,
192 kDmarDiag_Iqei_Ttm_Rsvd,
193
194 /* IQT_REG faults. */
195 kDmarDiag_IqtReg_Qt_Invalid,
196 kDmarDiag_IqtReg_Qt_NotAligned,
197
198 /* Compatibility Format Interrupt Faults. */
199 kDmarDiag_Ir_Cfi_Blocked,
200
201 /* Remappable Format Interrupt Faults. */
202 kDmarDiag_Ir_Rfi_Intr_Index_Invalid,
203 kDmarDiag_Ir_Rfi_Irte_Mode_Invalid,
204 kDmarDiag_Ir_Rfi_Irte_Not_Present,
205 kDmarDiag_Ir_Rfi_Irte_Read_Failed,
206 kDmarDiag_Ir_Rfi_Irte_Rsvd,
207 kDmarDiag_Ir_Rfi_Irte_Svt_Bus,
208 kDmarDiag_Ir_Rfi_Irte_Svt_Masked,
209 kDmarDiag_Ir_Rfi_Irte_Svt_Rsvd,
210 kDmarDiag_Ir_Rfi_Rsvd,
211
212 /* Member for determining array index limit. */
213 kDmarDiag_End,
214
215 /* Usual 32-bit type size hack. */
216 kDmarDiag_32Bit_Hack = 0x7fffffff
217} DMARDIAG;
218AssertCompileSize(DMARDIAG, 4);
219
220/** DMAR diagnostic enum description expansion.
221 * The below construct ensures typos in the input to this macro are caught
222 * during compile time. */
223#define DMARDIAG_DESC(a_Name) RT_CONCAT(kDmarDiag_, a_Name) < kDmarDiag_End ? RT_STR(a_Name) : "Ignored"
224
225/** DMAR diagnostics description for members in DMARDIAG. */
226static const char *const g_apszDmarDiagDesc[] =
227{
228 DMARDIAG_DESC(None ),
229 DMARDIAG_DESC(Atf_Lct_1 ),
230 DMARDIAG_DESC(Atf_Lct_2 ),
231 DMARDIAG_DESC(Atf_Lct_3 ),
232 DMARDIAG_DESC(Atf_Lct_4_1 ),
233 DMARDIAG_DESC(Atf_Lct_4_2 ),
234 DMARDIAG_DESC(Atf_Lct_4_3 ),
235 DMARDIAG_DESC(Atf_Lrt_1 ),
236 DMARDIAG_DESC(Atf_Lrt_2 ),
237 DMARDIAG_DESC(Atf_Lrt_3 ),
238 DMARDIAG_DESC(Atf_Rta_1_1 ),
239 DMARDIAG_DESC(Atf_Rta_1_2 ),
240 DMARDIAG_DESC(Atf_Rta_1_3 ),
241 DMARDIAG_DESC(CcmdReg_NotSupported ),
242 DMARDIAG_DESC(CcmdReg_Qi_Enabled ),
243 DMARDIAG_DESC(CcmdReg_Ttm_Invalid ),
244 DMARDIAG_DESC(IqaReg_Dsc_Fetch_Error ),
245 DMARDIAG_DESC(IqaReg_Dw_128_Invalid ),
246 DMARDIAG_DESC(IqaReg_Dw_256_Invalid ),
247 DMARDIAG_DESC(Iqei_Dsc_Type_Invalid ),
248 DMARDIAG_DESC(Iqei_Inv_Wait_Dsc_0_1_Rsvd),
249 DMARDIAG_DESC(Iqei_Inv_Wait_Dsc_2_3_Rsvd),
250 DMARDIAG_DESC(Iqei_Inv_Wait_Dsc_Invalid ),
251 DMARDIAG_DESC(Iqei_Ttm_Rsvd ),
252 DMARDIAG_DESC(IqtReg_Qt_Invalid ),
253 DMARDIAG_DESC(IqtReg_Qt_NotAligned ),
254 DMARDIAG_DESC(Ir_Cfi_Blocked ),
255 DMARDIAG_DESC(Ir_Rfi_Intr_Index_Invalid ),
256 DMARDIAG_DESC(Ir_Rfi_Irte_Mode_Invalid ),
257 DMARDIAG_DESC(Ir_Rfi_Irte_Not_Present ),
258 DMARDIAG_DESC(Ir_Rfi_Irte_Read_Failed ),
259 DMARDIAG_DESC(Ir_Rfi_Irte_Rsvd ),
260 DMARDIAG_DESC(Ir_Rfi_Irte_Svt_Bus ),
261 DMARDIAG_DESC(Ir_Rfi_Irte_Svt_Masked ),
262 DMARDIAG_DESC(Ir_Rfi_Irte_Svt_Rsvd ),
263 DMARDIAG_DESC(Ir_Rfi_Rsvd ),
264 /* kDmarDiag_End */
265};
266AssertCompile(RT_ELEMENTS(g_apszDmarDiagDesc) == kDmarDiag_End);
267#undef DMARDIAG_DESC
268
269/**
270 * The shared DMAR device state.
271 */
272typedef struct DMAR
273{
274 /** IOMMU device index. */
275 uint32_t idxIommu;
276 /** DMAR magic. */
277 uint32_t u32Magic;
278
279 /** Registers (group 0). */
280 uint8_t abRegs0[DMAR_MMIO_GROUP_0_SIZE];
281 /** Registers (group 1). */
282 uint8_t abRegs1[DMAR_MMIO_GROUP_1_SIZE];
283
284 /** @name Lazily activated registers.
285 * These are the active values for lazily activated registers. Software is free to
286 * modify the actual register values while remapping/translation is enabled but they
287 * take effect only when explicitly signaled by software, hence we need to hold the
288 * active values separately.
289 * @{ */
290 /** Currently active IRTA_REG. */
291 uint64_t uIrtaReg;
292 /** Currently active RTADDR_REG. */
293 uint64_t uRtaddrReg;
294 /** @} */
295
296 /** @name Register copies for a tiny bit faster and more convenient access.
297 * @{ */
298 /** Copy of VER_REG. */
299 uint8_t uVerReg;
300 /** Alignment. */
301 uint8_t abPadding[7];
302 /** Copy of CAP_REG. */
303 uint64_t fCapReg;
304 /** Copy of ECAP_REG. */
305 uint64_t fExtCapReg;
306 /** @} */
307
308 /** Host-address width (HAW) mask. */
309 uint64_t fHawMask;
310 /** Maximum guest-address width (MGAW) mask. */
311 uint64_t fMgawMask;
312
313 /** The event semaphore the invalidation-queue thread waits on. */
314 SUPSEMEVENT hEvtInvQueue;
315 /** Padding. */
316 uint32_t uPadding0;
317 /** Error diagnostic. */
318 DMARDIAG enmDiag;
319 /** The MMIO handle. */
320 IOMMMIOHANDLE hMmio;
321
322#ifdef VBOX_WITH_STATISTICS
323 STAMCOUNTER StatMmioReadR3; /**< Number of MMIO reads in R3. */
324 STAMCOUNTER StatMmioReadRZ; /**< Number of MMIO reads in RZ. */
325 STAMCOUNTER StatMmioWriteR3; /**< Number of MMIO writes in R3. */
326 STAMCOUNTER StatMmioWriteRZ; /**< Number of MMIO writes in RZ. */
327
328 STAMCOUNTER StatMsiRemapCfiR3; /**< Number of compatibility-format interrupts remap requests in R3. */
329 STAMCOUNTER StatMsiRemapCfiRZ; /**< Number of compatibility-format interrupts remap requests in RZ. */
330 STAMCOUNTER StatMsiRemapRfiR3; /**< Number of remappable-format interrupts remap requests in R3. */
331 STAMCOUNTER StatMsiRemapRfiRZ; /**< Number of remappable-format interrupts remap requests in RZ. */
332
333 STAMCOUNTER StatMemReadR3; /**< Number of memory read translation requests in R3. */
334 STAMCOUNTER StatMemReadRZ; /**< Number of memory read translation requests in RZ. */
335 STAMCOUNTER StatMemWriteR3; /**< Number of memory write translation requests in R3. */
336 STAMCOUNTER StatMemWriteRZ; /**< Number of memory write translation requests in RZ. */
337
338 STAMCOUNTER StatMemBulkReadR3; /**< Number of memory read bulk translation requests in R3. */
339 STAMCOUNTER StatMemBulkReadRZ; /**< Number of memory read bulk translation requests in RZ. */
340 STAMCOUNTER StatMemBulkWriteR3; /**< Number of memory write bulk translation requests in R3. */
341 STAMCOUNTER StatMemBulkWriteRZ; /**< Number of memory write bulk translation requests in RZ. */
342
343 STAMCOUNTER StatCcInvDsc; /**< Number of Context-cache descriptors processed. */
344 STAMCOUNTER StatIotlbInvDsc; /**< Number of IOTLB descriptors processed. */
345 STAMCOUNTER StatDevtlbInvDsc; /**< Number of Device-TLB descriptors processed. */
346 STAMCOUNTER StatIecInvDsc; /**< Number of Interrupt-Entry cache descriptors processed. */
347 STAMCOUNTER StatInvWaitDsc; /**< Number of Invalidation wait descriptors processed. */
348 STAMCOUNTER StatPasidIotlbInvDsc; /**< Number of PASID-based IOTLB descriptors processed. */
349 STAMCOUNTER StatPasidCacheInvDsc; /**< Number of PASID-cache descriptors processed. */
350 STAMCOUNTER StatPasidDevtlbInvDsc; /**< Number of PASID-based device-TLB descriptors processed. */
351#endif
352} DMAR;
353/** Pointer to the DMAR device state. */
354typedef DMAR *PDMAR;
355/** Pointer to the const DMAR device state. */
356typedef DMAR const *PCDMAR;
357AssertCompileMemberAlignment(DMAR, abRegs0, 8);
358AssertCompileMemberAlignment(DMAR, abRegs1, 8);
359
360/**
361 * The ring-3 DMAR device state.
362 */
363typedef struct DMARR3
364{
365 /** Device instance. */
366 PPDMDEVINSR3 pDevInsR3;
367 /** The IOMMU helper. */
368 R3PTRTYPE(PCPDMIOMMUHLPR3) pIommuHlpR3;
369 /** The invalidation-queue thread. */
370 R3PTRTYPE(PPDMTHREAD) pInvQueueThread;
371} DMARR3;
372/** Pointer to the ring-3 DMAR device state. */
373typedef DMARR3 *PDMARR3;
374/** Pointer to the const ring-3 DMAR device state. */
375typedef DMARR3 const *PCDMARR3;
376
377/**
378 * The ring-0 DMAR device state.
379 */
380typedef struct DMARR0
381{
382 /** Device instance. */
383 PPDMDEVINSR0 pDevInsR0;
384 /** The IOMMU helper. */
385 R0PTRTYPE(PCPDMIOMMUHLPR0) pIommuHlpR0;
386} DMARR0;
387/** Pointer to the ring-0 IOMMU device state. */
388typedef DMARR0 *PDMARR0;
389/** Pointer to the const ring-0 IOMMU device state. */
390typedef DMARR0 const *PCDMARR0;
391
392/**
393 * The raw-mode DMAR device state.
394 */
395typedef struct DMARRC
396{
397 /** Device instance. */
398 PPDMDEVINSRC pDevInsRC;
399 /** The IOMMU helper. */
400 RCPTRTYPE(PCPDMIOMMUHLPRC) pIommuHlpRC;
401} DMARRC;
402/** Pointer to the raw-mode DMAR device state. */
403typedef DMARRC *PDMARRC;
404/** Pointer to the const raw-mode DMAR device state. */
405typedef DMARRC const *PCIDMARRC;
406
407/** The DMAR device state for the current context. */
408typedef CTX_SUFF(DMAR) DMARCC;
409/** Pointer to the DMAR device state for the current context. */
410typedef CTX_SUFF(PDMAR) PDMARCC;
411/** Pointer to the const DMAR device state for the current context. */
412typedef CTX_SUFF(PDMAR) const PCDMARCC;
413
414/**
415 * Type of DMAR originated events that generate interrupts.
416 */
417typedef enum DMAREVENTTYPE
418{
419 /** Invalidation completion event. */
420 DMAREVENTTYPE_INV_COMPLETE = 0,
421 /** Fault event. */
422 DMAREVENTTYPE_FAULT
423} DMAREVENTTYPE;
424
425/**
426 * DMA Address Remapping Information.
427 */
428typedef struct DMARADDRMAP
429{
430 /** The device ID (bus, device, function). */
431 uint16_t idDevice;
432 /** The extended attributes of the request (VTD_REQ_ATTR_XXX). */
433 uint8_t fReqAttr;
434 /** Padding. */
435 uint8_t bPadding;
436 /** The PASID if present, can be NIL_PCIPASID. */
437 PCIPASID Pasid;
438 /* The address type of the memory request. */
439 PCIADDRTYPE enmAddrType;
440 /** The type of the translation request. */
441 VTDREQTYPE enmReqType;
442 /** The DMA address being accessed. */
443 uint64_t uDmaAddr;
444 /** The size of the DMA access (in bytes). */
445 size_t cbDma;
446
447 /** @todo Might have to split the result fields below into a separate structure and
448 * store extra info like cPageShift, permissions and attributes. */
449 /** The translated system-physical address (HPA). */
450 RTGCPHYS GCPhysSpa;
451 /** The size of the contiguous translated region (in bytes). */
452 size_t cbContiguous;
453} DMARADDRMAP;
454/** Pointer to a DMA address remapping object. */
455typedef DMARADDRMAP *PDMARADDRMAP;
456/** Pointer to a const DMA address remapping object. */
457typedef DMARADDRMAP const *PCDMARADDRMAP;
458
459
460/*********************************************************************************************************************************
461* Global Variables *
462*********************************************************************************************************************************/
463/**
464 * Read-write masks for DMAR registers (group 0).
465 */
466static uint32_t const g_au32RwMasks0[] =
467{
468 /* Offset Register Low High */
469 /* 0x000 VER_REG */ VTD_VER_REG_RW_MASK,
470 /* 0x004 Reserved */ 0,
471 /* 0x008 CAP_REG */ DMAR_LO_U32(VTD_CAP_REG_RW_MASK), DMAR_HI_U32(VTD_CAP_REG_RW_MASK),
472 /* 0x010 ECAP_REG */ DMAR_LO_U32(VTD_ECAP_REG_RW_MASK), DMAR_HI_U32(VTD_ECAP_REG_RW_MASK),
473 /* 0x018 GCMD_REG */ VTD_GCMD_REG_RW_MASK,
474 /* 0x01c GSTS_REG */ VTD_GSTS_REG_RW_MASK,
475 /* 0x020 RTADDR_REG */ DMAR_LO_U32(VTD_RTADDR_REG_RW_MASK), DMAR_HI_U32(VTD_RTADDR_REG_RW_MASK),
476 /* 0x028 CCMD_REG */ DMAR_LO_U32(VTD_CCMD_REG_RW_MASK), DMAR_HI_U32(VTD_CCMD_REG_RW_MASK),
477 /* 0x030 Reserved */ 0,
478 /* 0x034 FSTS_REG */ VTD_FSTS_REG_RW_MASK,
479 /* 0x038 FECTL_REG */ VTD_FECTL_REG_RW_MASK,
480 /* 0x03c FEDATA_REG */ VTD_FEDATA_REG_RW_MASK,
481 /* 0x040 FEADDR_REG */ VTD_FEADDR_REG_RW_MASK,
482 /* 0x044 FEUADDR_REG */ VTD_FEUADDR_REG_RW_MASK,
483 /* 0x048 Reserved */ 0, 0,
484 /* 0x050 Reserved */ 0, 0,
485 /* 0x058 AFLOG_REG */ DMAR_LO_U32(VTD_AFLOG_REG_RW_MASK), DMAR_HI_U32(VTD_AFLOG_REG_RW_MASK),
486 /* 0x060 Reserved */ 0,
487 /* 0x064 PMEN_REG */ 0, /* RO as we don't support PLMR and PHMR. */
488 /* 0x068 PLMBASE_REG */ 0, /* RO as we don't support PLMR. */
489 /* 0x06c PLMLIMIT_REG */ 0, /* RO as we don't support PLMR. */
490 /* 0x070 PHMBASE_REG */ 0, 0, /* RO as we don't support PHMR. */
491 /* 0x078 PHMLIMIT_REG */ 0, 0, /* RO as we don't support PHMR. */
492 /* 0x080 IQH_REG */ DMAR_LO_U32(VTD_IQH_REG_RW_MASK), DMAR_HI_U32(VTD_IQH_REG_RW_MASK),
493 /* 0x088 IQT_REG */ DMAR_LO_U32(VTD_IQT_REG_RW_MASK), DMAR_HI_U32(VTD_IQT_REG_RW_MASK),
494 /* 0x090 IQA_REG */ DMAR_LO_U32(VTD_IQA_REG_RW_MASK), DMAR_HI_U32(VTD_IQA_REG_RW_MASK),
495 /* 0x098 Reserved */ 0,
496 /* 0x09c ICS_REG */ VTD_ICS_REG_RW_MASK,
497 /* 0x0a0 IECTL_REG */ VTD_IECTL_REG_RW_MASK,
498 /* 0x0a4 IEDATA_REG */ VTD_IEDATA_REG_RW_MASK,
499 /* 0x0a8 IEADDR_REG */ VTD_IEADDR_REG_RW_MASK,
500 /* 0x0ac IEUADDR_REG */ VTD_IEUADDR_REG_RW_MASK,
501 /* 0x0b0 IQERCD_REG */ DMAR_LO_U32(VTD_IQERCD_REG_RW_MASK), DMAR_HI_U32(VTD_IQERCD_REG_RW_MASK),
502 /* 0x0b8 IRTA_REG */ DMAR_LO_U32(VTD_IRTA_REG_RW_MASK), DMAR_HI_U32(VTD_IRTA_REG_RW_MASK),
503 /* 0x0c0 PQH_REG */ DMAR_LO_U32(VTD_PQH_REG_RW_MASK), DMAR_HI_U32(VTD_PQH_REG_RW_MASK),
504 /* 0x0c8 PQT_REG */ DMAR_LO_U32(VTD_PQT_REG_RW_MASK), DMAR_HI_U32(VTD_PQT_REG_RW_MASK),
505 /* 0x0d0 PQA_REG */ DMAR_LO_U32(VTD_PQA_REG_RW_MASK), DMAR_HI_U32(VTD_PQA_REG_RW_MASK),
506 /* 0x0d8 Reserved */ 0,
507 /* 0x0dc PRS_REG */ VTD_PRS_REG_RW_MASK,
508 /* 0x0e0 PECTL_REG */ VTD_PECTL_REG_RW_MASK,
509 /* 0x0e4 PEDATA_REG */ VTD_PEDATA_REG_RW_MASK,
510 /* 0x0e8 PEADDR_REG */ VTD_PEADDR_REG_RW_MASK,
511 /* 0x0ec PEUADDR_REG */ VTD_PEUADDR_REG_RW_MASK,
512 /* 0x0f0 Reserved */ 0, 0,
513 /* 0x0f8 Reserved */ 0, 0,
514 /* 0x100 MTRRCAP_REG */ DMAR_LO_U32(VTD_MTRRCAP_REG_RW_MASK), DMAR_HI_U32(VTD_MTRRCAP_REG_RW_MASK),
515 /* 0x108 MTRRDEF_REG */ 0, 0, /* RO as we don't support MTS. */
516 /* 0x110 Reserved */ 0, 0,
517 /* 0x118 Reserved */ 0, 0,
518 /* 0x120 MTRR_FIX64_00000_REG */ 0, 0, /* RO as we don't support MTS. */
519 /* 0x128 MTRR_FIX16K_80000_REG */ 0, 0,
520 /* 0x130 MTRR_FIX16K_A0000_REG */ 0, 0,
521 /* 0x138 MTRR_FIX4K_C0000_REG */ 0, 0,
522 /* 0x140 MTRR_FIX4K_C8000_REG */ 0, 0,
523 /* 0x148 MTRR_FIX4K_D0000_REG */ 0, 0,
524 /* 0x150 MTRR_FIX4K_D8000_REG */ 0, 0,
525 /* 0x158 MTRR_FIX4K_E0000_REG */ 0, 0,
526 /* 0x160 MTRR_FIX4K_E8000_REG */ 0, 0,
527 /* 0x168 MTRR_FIX4K_F0000_REG */ 0, 0,
528 /* 0x170 MTRR_FIX4K_F8000_REG */ 0, 0,
529 /* 0x178 Reserved */ 0, 0,
530 /* 0x180 MTRR_PHYSBASE0_REG */ 0, 0, /* RO as we don't support MTS. */
531 /* 0x188 MTRR_PHYSMASK0_REG */ 0, 0,
532 /* 0x190 MTRR_PHYSBASE1_REG */ 0, 0,
533 /* 0x198 MTRR_PHYSMASK1_REG */ 0, 0,
534 /* 0x1a0 MTRR_PHYSBASE2_REG */ 0, 0,
535 /* 0x1a8 MTRR_PHYSMASK2_REG */ 0, 0,
536 /* 0x1b0 MTRR_PHYSBASE3_REG */ 0, 0,
537 /* 0x1b8 MTRR_PHYSMASK3_REG */ 0, 0,
538 /* 0x1c0 MTRR_PHYSBASE4_REG */ 0, 0,
539 /* 0x1c8 MTRR_PHYSMASK4_REG */ 0, 0,
540 /* 0x1d0 MTRR_PHYSBASE5_REG */ 0, 0,
541 /* 0x1d8 MTRR_PHYSMASK5_REG */ 0, 0,
542 /* 0x1e0 MTRR_PHYSBASE6_REG */ 0, 0,
543 /* 0x1e8 MTRR_PHYSMASK6_REG */ 0, 0,
544 /* 0x1f0 MTRR_PHYSBASE7_REG */ 0, 0,
545 /* 0x1f8 MTRR_PHYSMASK7_REG */ 0, 0,
546 /* 0x200 MTRR_PHYSBASE8_REG */ 0, 0,
547 /* 0x208 MTRR_PHYSMASK8_REG */ 0, 0,
548 /* 0x210 MTRR_PHYSBASE9_REG */ 0, 0,
549 /* 0x218 MTRR_PHYSMASK9_REG */ 0, 0,
550};
551AssertCompile(sizeof(g_au32RwMasks0) == DMAR_MMIO_GROUP_0_SIZE);
552
553/**
554 * Read-only Status, Write-1-to-clear masks for DMAR registers (group 0).
555 */
556static uint32_t const g_au32Rw1cMasks0[] =
557{
558 /* Offset Register Low High */
559 /* 0x000 VER_REG */ 0,
560 /* 0x004 Reserved */ 0,
561 /* 0x008 CAP_REG */ 0, 0,
562 /* 0x010 ECAP_REG */ 0, 0,
563 /* 0x018 GCMD_REG */ 0,
564 /* 0x01c GSTS_REG */ 0,
565 /* 0x020 RTADDR_REG */ 0, 0,
566 /* 0x028 CCMD_REG */ 0, 0,
567 /* 0x030 Reserved */ 0,
568 /* 0x034 FSTS_REG */ VTD_FSTS_REG_RW1C_MASK,
569 /* 0x038 FECTL_REG */ 0,
570 /* 0x03c FEDATA_REG */ 0,
571 /* 0x040 FEADDR_REG */ 0,
572 /* 0x044 FEUADDR_REG */ 0,
573 /* 0x048 Reserved */ 0, 0,
574 /* 0x050 Reserved */ 0, 0,
575 /* 0x058 AFLOG_REG */ 0, 0,
576 /* 0x060 Reserved */ 0,
577 /* 0x064 PMEN_REG */ 0,
578 /* 0x068 PLMBASE_REG */ 0,
579 /* 0x06c PLMLIMIT_REG */ 0,
580 /* 0x070 PHMBASE_REG */ 0, 0,
581 /* 0x078 PHMLIMIT_REG */ 0, 0,
582 /* 0x080 IQH_REG */ 0, 0,
583 /* 0x088 IQT_REG */ 0, 0,
584 /* 0x090 IQA_REG */ 0, 0,
585 /* 0x098 Reserved */ 0,
586 /* 0x09c ICS_REG */ VTD_ICS_REG_RW1C_MASK,
587 /* 0x0a0 IECTL_REG */ 0,
588 /* 0x0a4 IEDATA_REG */ 0,
589 /* 0x0a8 IEADDR_REG */ 0,
590 /* 0x0ac IEUADDR_REG */ 0,
591 /* 0x0b0 IQERCD_REG */ 0, 0,
592 /* 0x0b8 IRTA_REG */ 0, 0,
593 /* 0x0c0 PQH_REG */ 0, 0,
594 /* 0x0c8 PQT_REG */ 0, 0,
595 /* 0x0d0 PQA_REG */ 0, 0,
596 /* 0x0d8 Reserved */ 0,
597 /* 0x0dc PRS_REG */ 0,
598 /* 0x0e0 PECTL_REG */ 0,
599 /* 0x0e4 PEDATA_REG */ 0,
600 /* 0x0e8 PEADDR_REG */ 0,
601 /* 0x0ec PEUADDR_REG */ 0,
602 /* 0x0f0 Reserved */ 0, 0,
603 /* 0x0f8 Reserved */ 0, 0,
604 /* 0x100 MTRRCAP_REG */ 0, 0,
605 /* 0x108 MTRRDEF_REG */ 0, 0,
606 /* 0x110 Reserved */ 0, 0,
607 /* 0x118 Reserved */ 0, 0,
608 /* 0x120 MTRR_FIX64_00000_REG */ 0, 0,
609 /* 0x128 MTRR_FIX16K_80000_REG */ 0, 0,
610 /* 0x130 MTRR_FIX16K_A0000_REG */ 0, 0,
611 /* 0x138 MTRR_FIX4K_C0000_REG */ 0, 0,
612 /* 0x140 MTRR_FIX4K_C8000_REG */ 0, 0,
613 /* 0x148 MTRR_FIX4K_D0000_REG */ 0, 0,
614 /* 0x150 MTRR_FIX4K_D8000_REG */ 0, 0,
615 /* 0x158 MTRR_FIX4K_E0000_REG */ 0, 0,
616 /* 0x160 MTRR_FIX4K_E8000_REG */ 0, 0,
617 /* 0x168 MTRR_FIX4K_F0000_REG */ 0, 0,
618 /* 0x170 MTRR_FIX4K_F8000_REG */ 0, 0,
619 /* 0x178 Reserved */ 0, 0,
620 /* 0x180 MTRR_PHYSBASE0_REG */ 0, 0,
621 /* 0x188 MTRR_PHYSMASK0_REG */ 0, 0,
622 /* 0x190 MTRR_PHYSBASE1_REG */ 0, 0,
623 /* 0x198 MTRR_PHYSMASK1_REG */ 0, 0,
624 /* 0x1a0 MTRR_PHYSBASE2_REG */ 0, 0,
625 /* 0x1a8 MTRR_PHYSMASK2_REG */ 0, 0,
626 /* 0x1b0 MTRR_PHYSBASE3_REG */ 0, 0,
627 /* 0x1b8 MTRR_PHYSMASK3_REG */ 0, 0,
628 /* 0x1c0 MTRR_PHYSBASE4_REG */ 0, 0,
629 /* 0x1c8 MTRR_PHYSMASK4_REG */ 0, 0,
630 /* 0x1d0 MTRR_PHYSBASE5_REG */ 0, 0,
631 /* 0x1d8 MTRR_PHYSMASK5_REG */ 0, 0,
632 /* 0x1e0 MTRR_PHYSBASE6_REG */ 0, 0,
633 /* 0x1e8 MTRR_PHYSMASK6_REG */ 0, 0,
634 /* 0x1f0 MTRR_PHYSBASE7_REG */ 0, 0,
635 /* 0x1f8 MTRR_PHYSMASK7_REG */ 0, 0,
636 /* 0x200 MTRR_PHYSBASE8_REG */ 0, 0,
637 /* 0x208 MTRR_PHYSMASK8_REG */ 0, 0,
638 /* 0x210 MTRR_PHYSBASE9_REG */ 0, 0,
639 /* 0x218 MTRR_PHYSMASK9_REG */ 0, 0,
640};
641AssertCompile(sizeof(g_au32Rw1cMasks0) == DMAR_MMIO_GROUP_0_SIZE);
642
643/**
644 * Read-write masks for DMAR registers (group 1).
645 */
646static uint32_t const g_au32RwMasks1[] =
647{
648 /* Offset Register Low High */
649 /* 0xe00 VCCAP_REG */ DMAR_LO_U32(VTD_VCCAP_REG_RW_MASK), DMAR_HI_U32(VTD_VCCAP_REG_RW_MASK),
650 /* 0xe08 VCMD_EO_REG */ DMAR_LO_U32(VTD_VCMD_EO_REG_RW_MASK), DMAR_HI_U32(VTD_VCMD_EO_REG_RW_MASK),
651 /* 0xe10 VCMD_REG */ 0, 0, /* RO: VCS not supported. */
652 /* 0xe18 VCMDRSVD_REG */ 0, 0,
653 /* 0xe20 VCRSP_REG */ 0, 0, /* RO: VCS not supported. */
654 /* 0xe28 VCRSPRSVD_REG */ 0, 0,
655 /* 0xe30 Reserved */ 0, 0,
656 /* 0xe38 Reserved */ 0, 0,
657 /* 0xe40 Reserved */ 0, 0,
658 /* 0xe48 Reserved */ 0, 0,
659 /* 0xe50 IVA_REG */ DMAR_LO_U32(VTD_IVA_REG_RW_MASK), DMAR_HI_U32(VTD_IVA_REG_RW_MASK),
660 /* 0xe58 IOTLB_REG */ DMAR_LO_U32(VTD_IOTLB_REG_RW_MASK), DMAR_HI_U32(VTD_IOTLB_REG_RW_MASK),
661 /* 0xe60 Reserved */ 0, 0,
662 /* 0xe68 Reserved */ 0, 0,
663 /* 0xe70 FRCD_REG_LO */ DMAR_LO_U32(VTD_FRCD_REG_LO_RW_MASK), DMAR_HI_U32(VTD_FRCD_REG_LO_RW_MASK),
664 /* 0xe78 FRCD_REG_HI */ DMAR_LO_U32(VTD_FRCD_REG_HI_RW_MASK), DMAR_HI_U32(VTD_FRCD_REG_HI_RW_MASK),
665};
666AssertCompile(sizeof(g_au32RwMasks1) == DMAR_MMIO_GROUP_1_SIZE);
667AssertCompile((DMAR_MMIO_OFF_FRCD_LO_REG - DMAR_MMIO_GROUP_1_OFF_FIRST) + DMAR_FRCD_REG_COUNT * 2 * sizeof(uint64_t) );
668
669/**
670 * Read-only Status, Write-1-to-clear masks for DMAR registers (group 1).
671 */
672static uint32_t const g_au32Rw1cMasks1[] =
673{
674 /* Offset Register Low High */
675 /* 0xe00 VCCAP_REG */ 0, 0,
676 /* 0xe08 VCMD_EO_REG */ 0, 0,
677 /* 0xe10 VCMD_REG */ 0, 0,
678 /* 0xe18 VCMDRSVD_REG */ 0, 0,
679 /* 0xe20 VCRSP_REG */ 0, 0,
680 /* 0xe28 VCRSPRSVD_REG */ 0, 0,
681 /* 0xe30 Reserved */ 0, 0,
682 /* 0xe38 Reserved */ 0, 0,
683 /* 0xe40 Reserved */ 0, 0,
684 /* 0xe48 Reserved */ 0, 0,
685 /* 0xe50 IVA_REG */ 0, 0,
686 /* 0xe58 IOTLB_REG */ 0, 0,
687 /* 0xe60 Reserved */ 0, 0,
688 /* 0xe68 Reserved */ 0, 0,
689 /* 0xe70 FRCD_REG_LO */ DMAR_LO_U32(VTD_FRCD_REG_LO_RW1C_MASK), DMAR_HI_U32(VTD_FRCD_REG_LO_RW1C_MASK),
690 /* 0xe78 FRCD_REG_HI */ DMAR_LO_U32(VTD_FRCD_REG_HI_RW1C_MASK), DMAR_HI_U32(VTD_FRCD_REG_HI_RW1C_MASK),
691};
692AssertCompile(sizeof(g_au32Rw1cMasks1) == DMAR_MMIO_GROUP_1_SIZE);
693
694/** Array of RW masks for each register group. */
695static uint8_t const *g_apbRwMasks[] = { (uint8_t *)&g_au32RwMasks0[0], (uint8_t *)&g_au32RwMasks1[0] };
696
697/** Array of RW1C masks for each register group. */
698static uint8_t const *g_apbRw1cMasks[] = { (uint8_t *)&g_au32Rw1cMasks0[0], (uint8_t *)&g_au32Rw1cMasks1[0] };
699
700/* Masks arrays must be identical in size (even bounds checking code assumes this). */
701AssertCompile(sizeof(g_apbRw1cMasks) == sizeof(g_apbRwMasks));
702
703/** Array of valid domain-ID bits. */
704static uint16_t const g_auNdMask[] = { 0xf, 0x3f, 0xff, 0x3ff, 0xfff, 0x3fff, 0xffff, 0 };
705AssertCompile(RT_ELEMENTS(g_auNdMask) >= DMAR_ND);
706
707
708#ifndef VBOX_DEVICE_STRUCT_TESTCASE
709/** @todo Add IOMMU struct size/alignment verification, see
710 * Devices/testcase/Makefile.kmk and
711 * Devices/testcase/tstDeviceStructSize[RC].cpp */
712
713/**
714 * Returns the supported adjusted guest-address width (SAGAW) given the maximum
715 * guest address width (MGAW).
716 *
717 * @returns The CAP_REG.SAGAW value.
718 * @param uMgaw The CAP_REG.MGAW value.
719 */
720static uint8_t vtdCapRegGetSagaw(uint8_t uMgaw)
721{
722 /*
723 * It doesn't make sense to me that a CPU (or IOMMU hardware) will support 5-level paging
724 * but not 4 or 3 level paging. So smaller page-table levels are always OR'ed in.
725 *
726 * The values below (57, 48, 39 bits) represents the levels of page-table walks for
727 * 4KB base page size.
728 * See Intel VT-d spec. 10.4.2 "Capability Register".
729 */
730 ++uMgaw;
731 uint8_t const fSagaw = uMgaw >= 57 ? RT_BIT(3) | RT_BIT(2) | RT_BIT(1)
732 : uMgaw >= 48 ? RT_BIT(2) | RT_BIT(1)
733 : uMgaw >= 39 ? RT_BIT(1)
734 : 0;
735 return fSagaw;
736}
737
738
739/**
740 * Returns whether the interrupt remapping (IR) fault is qualified or not.
741 *
742 * @returns @c true if qualified, @c false otherwise.
743 * @param enmIrFault The interrupt remapping fault condition.
744 */
745static bool vtdIrFaultIsQualified(VTDIRFAULT enmIrFault)
746{
747 switch (enmIrFault)
748 {
749 case VTDIRFAULT_IRTE_NOT_PRESENT:
750 case VTDIRFAULT_IRTE_PRESENT_RSVD:
751 case VTDIRFAULT_IRTE_PRESENT_INVALID:
752 case VTDIRFAULT_PID_READ_FAILED:
753 case VTDIRFAULT_PID_RSVD:
754 return true;
755 default:
756 return false;
757 }
758}
759
760
761/**
762 * Returns table translation mode's descriptive name.
763 *
764 * @returns The descriptive name.
765 * @param uTtm The RTADDR_REG.TTM value.
766 */
767static const char* vtdRtaddrRegGetTtmDesc(uint8_t uTtm)
768{
769 Assert(!(uTtm & 3));
770 static const char* s_apszTtmNames[] =
771 {
772 "Legacy Mode",
773 "Scalable Mode",
774 "Reserved",
775 "Abort-DMA Mode"
776 };
777 return s_apszTtmNames[uTtm & (RT_ELEMENTS(s_apszTtmNames) - 1)];
778}
779
780
781/**
782 * Gets the index of the group the register belongs to given its MMIO offset.
783 *
784 * @returns The group index.
785 * @param offReg The MMIO offset of the register.
786 * @param cbReg The size of the access being made (for bounds checking on
787 * debug builds).
788 */
789DECLINLINE(uint8_t) dmarRegGetGroupIndex(uint16_t offReg, uint8_t cbReg)
790{
791 uint16_t const offLast = offReg + cbReg - 1;
792 AssertCompile(DMAR_MMIO_GROUP_0_OFF_FIRST == 0);
793 AssertMsg(DMAR_IS_MMIO_OFF_VALID(offLast), ("off=%#x cb=%u\n", offReg, cbReg));
794 return !(offLast < DMAR_MMIO_GROUP_0_OFF_END);
795}
796
797
798/**
799 * Gets the group the register belongs to given its MMIO offset.
800 *
801 * @returns Pointer to the first element of the register group.
802 * @param pThis The shared DMAR device state.
803 * @param offReg The MMIO offset of the register.
804 * @param cbReg The size of the access being made (for bounds checking on
805 * debug builds).
806 * @param pIdxGroup Where to store the index of the register group the register
807 * belongs to.
808 */
809DECLINLINE(uint8_t *) dmarRegGetGroup(PDMAR pThis, uint16_t offReg, uint8_t cbReg, uint8_t *pIdxGroup)
810{
811 *pIdxGroup = dmarRegGetGroupIndex(offReg, cbReg);
812 uint8_t *apbRegs[] = { &pThis->abRegs0[0], &pThis->abRegs1[0] };
813 return apbRegs[*pIdxGroup];
814}
815
816
817/**
818 * Const/read-only version of dmarRegGetGroup.
819 *
820 * @copydoc dmarRegGetGroup
821 */
822DECLINLINE(uint8_t const*) dmarRegGetGroupRo(PCDMAR pThis, uint16_t offReg, uint8_t cbReg, uint8_t *pIdxGroup)
823{
824 *pIdxGroup = dmarRegGetGroupIndex(offReg, cbReg);
825 uint8_t const *apbRegs[] = { &pThis->abRegs0[0], &pThis->abRegs1[0] };
826 return apbRegs[*pIdxGroup];
827}
828
829
830/**
831 * Writes a 32-bit register with the exactly the supplied value.
832 *
833 * @param pThis The shared DMAR device state.
834 * @param offReg The MMIO offset of the register.
835 * @param uReg The 32-bit value to write.
836 */
837static void dmarRegWriteRaw32(PDMAR pThis, uint16_t offReg, uint32_t uReg)
838{
839 uint8_t idxGroup;
840 uint8_t *pabRegs = dmarRegGetGroup(pThis, offReg, sizeof(uint32_t), &idxGroup);
841 NOREF(idxGroup);
842 *(uint32_t *)(pabRegs + offReg) = uReg;
843}
844
845
846/**
847 * Writes a 64-bit register with the exactly the supplied value.
848 *
849 * @param pThis The shared DMAR device state.
850 * @param offReg The MMIO offset of the register.
851 * @param uReg The 64-bit value to write.
852 */
853static void dmarRegWriteRaw64(PDMAR pThis, uint16_t offReg, uint64_t uReg)
854{
855 uint8_t idxGroup;
856 uint8_t *pabRegs = dmarRegGetGroup(pThis, offReg, sizeof(uint64_t), &idxGroup);
857 NOREF(idxGroup);
858 *(uint64_t *)(pabRegs + offReg) = uReg;
859}
860
861
862/**
863 * Reads a 32-bit register with exactly the value it contains.
864 *
865 * @returns The raw register value.
866 * @param pThis The shared DMAR device state.
867 * @param offReg The MMIO offset of the register.
868 */
869static uint32_t dmarRegReadRaw32(PCDMAR pThis, uint16_t offReg)
870{
871 uint8_t idxGroup;
872 uint8_t const *pabRegs = dmarRegGetGroupRo(pThis, offReg, sizeof(uint32_t), &idxGroup);
873 NOREF(idxGroup);
874 return *(uint32_t *)(pabRegs + offReg);
875}
876
877
878/**
879 * Reads a 64-bit register with exactly the value it contains.
880 *
881 * @returns The raw register value.
882 * @param pThis The shared DMAR device state.
883 * @param offReg The MMIO offset of the register.
884 */
885static uint64_t dmarRegReadRaw64(PCDMAR pThis, uint16_t offReg)
886{
887 uint8_t idxGroup;
888 uint8_t const *pabRegs = dmarRegGetGroupRo(pThis, offReg, sizeof(uint64_t), &idxGroup);
889 NOREF(idxGroup);
890 return *(uint64_t *)(pabRegs + offReg);
891}
892
893
894/**
895 * Reads a 32-bit register with exactly the value it contains along with their
896 * corresponding masks
897 *
898 * @param pThis The shared DMAR device state.
899 * @param offReg The MMIO offset of the register.
900 * @param puReg Where to store the raw 32-bit register value.
901 * @param pfRwMask Where to store the RW mask corresponding to this register.
902 * @param pfRw1cMask Where to store the RW1C mask corresponding to this register.
903 */
904static void dmarRegReadRaw32Ex(PCDMAR pThis, uint16_t offReg, uint32_t *puReg, uint32_t *pfRwMask, uint32_t *pfRw1cMask)
905{
906 uint8_t idxGroup;
907 uint8_t const *pabRegs = dmarRegGetGroupRo(pThis, offReg, sizeof(uint32_t), &idxGroup);
908 Assert(idxGroup < RT_ELEMENTS(g_apbRwMasks));
909 uint8_t const *pabRwMasks = g_apbRwMasks[idxGroup];
910 uint8_t const *pabRw1cMasks = g_apbRw1cMasks[idxGroup];
911 *puReg = *(uint32_t *)(pabRegs + offReg);
912 *pfRwMask = *(uint32_t *)(pabRwMasks + offReg);
913 *pfRw1cMask = *(uint32_t *)(pabRw1cMasks + offReg);
914}
915
916
917/**
918 * Reads a 64-bit register with exactly the value it contains along with their
919 * corresponding masks.
920 *
921 * @param pThis The shared DMAR device state.
922 * @param offReg The MMIO offset of the register.
923 * @param puReg Where to store the raw 64-bit register value.
924 * @param pfRwMask Where to store the RW mask corresponding to this register.
925 * @param pfRw1cMask Where to store the RW1C mask corresponding to this register.
926 */
927static void dmarRegReadRaw64Ex(PCDMAR pThis, uint16_t offReg, uint64_t *puReg, uint64_t *pfRwMask, uint64_t *pfRw1cMask)
928{
929 uint8_t idxGroup;
930 uint8_t const *pabRegs = dmarRegGetGroupRo(pThis, offReg, sizeof(uint64_t), &idxGroup);
931 Assert(idxGroup < RT_ELEMENTS(g_apbRwMasks));
932 uint8_t const *pabRwMasks = g_apbRwMasks[idxGroup];
933 uint8_t const *pabRw1cMasks = g_apbRw1cMasks[idxGroup];
934 *puReg = *(uint64_t *)(pabRegs + offReg);
935 *pfRwMask = *(uint64_t *)(pabRwMasks + offReg);
936 *pfRw1cMask = *(uint64_t *)(pabRw1cMasks + offReg);
937}
938
939
940/**
941 * Writes a 32-bit register as it would be when written by software.
942 * This will preserve read-only bits, mask off reserved bits and clear RW1C bits.
943 *
944 * @returns The value that's actually written to the register.
945 * @param pThis The shared DMAR device state.
946 * @param offReg The MMIO offset of the register.
947 * @param uReg The 32-bit value to write.
948 * @param puPrev Where to store the register value prior to writing.
949 */
950static uint32_t dmarRegWrite32(PDMAR pThis, uint16_t offReg, uint32_t uReg, uint32_t *puPrev)
951{
952 /* Read current value from the 32-bit register. */
953 uint32_t uCurReg;
954 uint32_t fRwMask;
955 uint32_t fRw1cMask;
956 dmarRegReadRaw32Ex(pThis, offReg, &uCurReg, &fRwMask, &fRw1cMask);
957 *puPrev = uCurReg;
958
959 uint32_t const fRoBits = uCurReg & ~fRwMask; /* Preserve current read-only and reserved bits. */
960 uint32_t const fRwBits = uReg & fRwMask; /* Merge newly written read/write bits. */
961 uint32_t const fRw1cBits = uReg & fRw1cMask; /* Clear 1s written to RW1C bits. */
962 uint32_t const uNewReg = (fRoBits | fRwBits) & ~fRw1cBits;
963
964 /* Write new value to the 32-bit register. */
965 dmarRegWriteRaw32(pThis, offReg, uNewReg);
966 return uNewReg;
967}
968
969
970/**
971 * Writes a 64-bit register as it would be when written by software.
972 * This will preserve read-only bits, mask off reserved bits and clear RW1C bits.
973 *
974 * @returns The value that's actually written to the register.
975 * @param pThis The shared DMAR device state.
976 * @param offReg The MMIO offset of the register.
977 * @param uReg The 64-bit value to write.
978 * @param puPrev Where to store the register value prior to writing.
979 */
980static uint64_t dmarRegWrite64(PDMAR pThis, uint16_t offReg, uint64_t uReg, uint64_t *puPrev)
981{
982 /* Read current value from the 64-bit register. */
983 uint64_t uCurReg;
984 uint64_t fRwMask;
985 uint64_t fRw1cMask;
986 dmarRegReadRaw64Ex(pThis, offReg, &uCurReg, &fRwMask, &fRw1cMask);
987 *puPrev = uCurReg;
988
989 uint64_t const fRoBits = uCurReg & ~fRwMask; /* Preserve current read-only and reserved bits. */
990 uint64_t const fRwBits = uReg & fRwMask; /* Merge newly written read/write bits. */
991 uint64_t const fRw1cBits = uReg & fRw1cMask; /* Clear 1s written to RW1C bits. */
992 uint64_t const uNewReg = (fRoBits | fRwBits) & ~fRw1cBits;
993
994 /* Write new value to the 64-bit register. */
995 dmarRegWriteRaw64(pThis, offReg, uNewReg);
996 return uNewReg;
997}
998
999
1000/**
1001 * Reads a 32-bit register as it would be when read by software.
1002 *
1003 * @returns The register value.
1004 * @param pThis The shared DMAR device state.
1005 * @param offReg The MMIO offset of the register.
1006 */
1007static uint32_t dmarRegRead32(PCDMAR pThis, uint16_t offReg)
1008{
1009 return dmarRegReadRaw32(pThis, offReg);
1010}
1011
1012
1013/**
1014 * Reads a 64-bit register as it would be when read by software.
1015 *
1016 * @returns The register value.
1017 * @param pThis The shared DMAR device state.
1018 * @param offReg The MMIO offset of the register.
1019 */
1020static uint64_t dmarRegRead64(PCDMAR pThis, uint16_t offReg)
1021{
1022 return dmarRegReadRaw64(pThis, offReg);
1023}
1024
1025
1026/**
1027 * Modifies a 32-bit register.
1028 *
1029 * @param pThis The shared DMAR device state.
1030 * @param offReg The MMIO offset of the register.
1031 * @param fAndMask The AND mask (applied first).
1032 * @param fOrMask The OR mask.
1033 * @remarks This does NOT apply RO or RW1C masks while modifying the
1034 * register.
1035 */
1036static void dmarRegChangeRaw32(PDMAR pThis, uint16_t offReg, uint32_t fAndMask, uint32_t fOrMask)
1037{
1038 uint32_t uReg = dmarRegReadRaw32(pThis, offReg);
1039 uReg = (uReg & fAndMask) | fOrMask;
1040 dmarRegWriteRaw32(pThis, offReg, uReg);
1041}
1042
1043
1044/**
1045 * Modifies a 64-bit register.
1046 *
1047 * @param pThis The shared DMAR device state.
1048 * @param offReg The MMIO offset of the register.
1049 * @param fAndMask The AND mask (applied first).
1050 * @param fOrMask The OR mask.
1051 * @remarks This does NOT apply RO or RW1C masks while modifying the
1052 * register.
1053 */
1054static void dmarRegChangeRaw64(PDMAR pThis, uint16_t offReg, uint64_t fAndMask, uint64_t fOrMask)
1055{
1056 uint64_t uReg = dmarRegReadRaw64(pThis, offReg);
1057 uReg = (uReg & fAndMask) | fOrMask;
1058 dmarRegWriteRaw64(pThis, offReg, uReg);
1059}
1060
1061
1062/**
1063 * Checks if the invalidation-queue is empty.
1064 *
1065 * Extended version which optionally returns the current queue head and tail
1066 * offsets.
1067 *
1068 * @returns @c true if empty, @c false otherwise.
1069 * @param pThis The shared DMAR device state.
1070 * @param poffQh Where to store the queue head offset. Optional, can be NULL.
1071 * @param poffQt Where to store the queue tail offset. Optional, can be NULL.
1072 */
1073static bool dmarInvQueueIsEmptyEx(PCDMAR pThis, uint32_t *poffQh, uint32_t *poffQt)
1074{
1075 /* Read only the low-32 bits of the queue head and queue tail as high bits are all RsvdZ.*/
1076 uint32_t const uIqtReg = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_IQT_REG);
1077 uint32_t const uIqhReg = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_IQH_REG);
1078
1079 /* Don't bother masking QT, QH since other bits are RsvdZ. */
1080 Assert(!(uIqtReg & ~VTD_BF_IQT_REG_QT_MASK));
1081 Assert(!(uIqhReg & ~VTD_BF_IQH_REG_QH_MASK));
1082 if (poffQh)
1083 *poffQh = uIqhReg;
1084 if (poffQt)
1085 *poffQt = uIqtReg;
1086 return uIqtReg == uIqhReg;
1087}
1088
1089
1090/**
1091 * Checks if the invalidation-queue is empty.
1092 *
1093 * @returns @c true if empty, @c false otherwise.
1094 * @param pThis The shared DMAR device state.
1095 */
1096static bool dmarInvQueueIsEmpty(PCDMAR pThis)
1097{
1098 return dmarInvQueueIsEmptyEx(pThis, NULL /* poffQh */, NULL /* poffQt */);
1099}
1100
1101
1102/**
1103 * Checks if the invalidation-queue is capable of processing requests.
1104 *
1105 * @returns @c true if the invalidation-queue can process requests, @c false
1106 * otherwise.
1107 * @param pThis The shared DMAR device state.
1108 */
1109static bool dmarInvQueueCanProcessRequests(PCDMAR pThis)
1110{
1111 /* Check if queued-invalidation is enabled. */
1112 uint32_t const uGstsReg = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_GSTS_REG);
1113 if (uGstsReg & VTD_BF_GSTS_REG_QIES_MASK)
1114 {
1115 /* Check if there are no invalidation-queue or timeout errors. */
1116 uint32_t const uFstsReg = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_FSTS_REG);
1117 if (!(uFstsReg & (VTD_BF_FSTS_REG_IQE_MASK | VTD_BF_FSTS_REG_ITE_MASK)))
1118 return true;
1119 }
1120 return false;
1121}
1122
1123
1124/**
1125 * Wakes up the invalidation-queue thread if there are requests to be processed.
1126 *
1127 * @param pDevIns The IOMMU device instance.
1128 */
1129static void dmarInvQueueThreadWakeUpIfNeeded(PPDMDEVINS pDevIns)
1130{
1131 PDMAR pThis = PDMDEVINS_2_DATA(pDevIns, PDMAR);
1132 PCDMARCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PCDMARCC);
1133 Log4Func(("\n"));
1134
1135 DMAR_ASSERT_LOCK_IS_OWNER(pDevIns, pThisCC);
1136
1137 if ( dmarInvQueueCanProcessRequests(pThis)
1138 && !dmarInvQueueIsEmpty(pThis))
1139 {
1140 Log4Func(("Signaling the invalidation-queue thread\n"));
1141 PDMDevHlpSUPSemEventSignal(pDevIns, pThis->hEvtInvQueue);
1142 }
1143}
1144
1145
1146/**
1147 * Raises an event on behalf of the DMAR.
1148 *
1149 * These are events that are generated by the DMAR itself (like faults and
1150 * invalidation completion notifications).
1151 *
1152 * @param pDevIns The IOMMU device instance.
1153 * @param enmEventType The DMAR event type.
1154 *
1155 * @remarks The DMAR lock must be held while calling this function.
1156 */
1157static void dmarEventRaiseInterrupt(PPDMDEVINS pDevIns, DMAREVENTTYPE enmEventType)
1158{
1159 uint16_t offCtlReg;
1160 uint32_t fIntrMaskedMask;
1161 uint32_t fIntrPendingMask;
1162 uint16_t offMsiAddrLoReg;
1163 uint16_t offMsiAddrHiReg;
1164 uint16_t offMsiDataReg;
1165 switch (enmEventType)
1166 {
1167 case DMAREVENTTYPE_INV_COMPLETE:
1168 {
1169 offCtlReg = VTD_MMIO_OFF_IECTL_REG;
1170 fIntrMaskedMask = VTD_BF_IECTL_REG_IM_MASK;
1171 fIntrPendingMask = VTD_BF_IECTL_REG_IP_MASK;
1172 offMsiAddrLoReg = VTD_MMIO_OFF_IEADDR_REG;
1173 offMsiAddrHiReg = VTD_MMIO_OFF_IEUADDR_REG;
1174 offMsiDataReg = VTD_MMIO_OFF_IEDATA_REG;
1175 break;
1176 }
1177
1178 case DMAREVENTTYPE_FAULT:
1179 {
1180 offCtlReg = VTD_MMIO_OFF_FECTL_REG;
1181 fIntrMaskedMask = VTD_BF_FECTL_REG_IM_MASK;
1182 fIntrPendingMask = VTD_BF_FECTL_REG_IP_MASK;
1183 offMsiAddrLoReg = VTD_MMIO_OFF_FEADDR_REG;
1184 offMsiAddrHiReg = VTD_MMIO_OFF_FEUADDR_REG;
1185 offMsiDataReg = VTD_MMIO_OFF_FEDATA_REG;
1186 break;
1187 }
1188
1189 default:
1190 {
1191 /* Shouldn't ever happen. */
1192 AssertMsgFailedReturnVoid(("DMAR event type %#x unknown!\n", enmEventType));
1193 }
1194 }
1195
1196 /* Check if software has masked the interrupt. */
1197 PDMAR pThis = PDMDEVINS_2_DATA(pDevIns, PDMAR);
1198 uint32_t uCtlReg = dmarRegReadRaw32(pThis, offCtlReg);
1199 if (!(uCtlReg & fIntrMaskedMask))
1200 {
1201 /*
1202 * Interrupt is unmasked, raise it.
1203 * Interrupts generated by the DMAR have trigger mode and level as 0.
1204 * See Intel spec. 5.1.6 "Remapping Hardware Event Interrupt Programming".
1205 */
1206 MSIMSG Msi;
1207 Msi.Addr.au32[0] = dmarRegReadRaw32(pThis, offMsiAddrLoReg);
1208 Msi.Addr.au32[1] = (pThis->fExtCapReg & VTD_BF_ECAP_REG_EIM_MASK) ? dmarRegReadRaw32(pThis, offMsiAddrHiReg) : 0;
1209 Msi.Data.u32 = dmarRegReadRaw32(pThis, offMsiDataReg);
1210 Assert(Msi.Data.n.u1Level == 0);
1211 Assert(Msi.Data.n.u1TriggerMode == 0);
1212
1213 PCDMARCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PCDMARCC);
1214 pThisCC->CTX_SUFF(pIommuHlp)->pfnSendMsi(pDevIns, &Msi, 0 /* uTagSrc */);
1215
1216 /* Clear interrupt pending bit. */
1217 uCtlReg &= ~fIntrPendingMask;
1218 dmarRegWriteRaw32(pThis, offCtlReg, uCtlReg);
1219 }
1220 else
1221 {
1222 /* Interrupt is masked, set the interrupt pending bit. */
1223 uCtlReg |= fIntrPendingMask;
1224 dmarRegWriteRaw32(pThis, offCtlReg, uCtlReg);
1225 }
1226}
1227
1228
1229/**
1230 * Raises an interrupt in response to a fault event.
1231 *
1232 * @param pDevIns The IOMMU device instance.
1233 *
1234 * @remarks This assumes the caller has already set the required status bits in the
1235 * FSTS_REG (namely one or more of PPF, PFO, IQE, ICE or ITE bits).
1236 */
1237static void dmarFaultEventRaiseInterrupt(PPDMDEVINS pDevIns)
1238{
1239 PDMAR pThis = PDMDEVINS_2_DATA(pDevIns, PDMAR);
1240 PCDMARCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PCDMARCC);
1241 DMAR_ASSERT_LOCK_IS_OWNER(pDevIns, pThisCC);
1242
1243#ifdef RT_STRICT
1244 {
1245 uint32_t const uFstsReg = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_FSTS_REG);
1246 uint32_t const fFaultMask = VTD_BF_FSTS_REG_PPF_MASK | VTD_BF_FSTS_REG_PFO_MASK
1247 /* | VTD_BF_FSTS_REG_APF_MASK | VTD_BF_FSTS_REG_AFO_MASK */ /* AFL not supported */
1248 /* | VTD_BF_FSTS_REG_ICE_MASK | VTD_BF_FSTS_REG_ITE_MASK */ /* Device-TLBs not supported */
1249 | VTD_BF_FSTS_REG_IQE_MASK;
1250 Assert(uFstsReg & fFaultMask);
1251 }
1252#endif
1253 dmarEventRaiseInterrupt(pDevIns, DMAREVENTTYPE_FAULT);
1254}
1255
1256
1257#ifdef IN_RING3
1258/**
1259 * Raises an interrupt in response to an invalidation (complete) event.
1260 *
1261 * @param pDevIns The IOMMU device instance.
1262 */
1263static void dmarR3InvEventRaiseInterrupt(PPDMDEVINS pDevIns)
1264{
1265 PDMAR pThis = PDMDEVINS_2_DATA(pDevIns, PDMAR);
1266 PCDMARCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PCDMARCC);
1267 DMAR_ASSERT_LOCK_IS_OWNER(pDevIns, pThisCC);
1268
1269 uint32_t const uIcsReg = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_ICS_REG);
1270 if (!(uIcsReg & VTD_BF_ICS_REG_IWC_MASK))
1271 {
1272 dmarRegChangeRaw32(pThis, VTD_MMIO_OFF_ICS_REG, UINT32_MAX, VTD_BF_ICS_REG_IWC_MASK);
1273 dmarEventRaiseInterrupt(pDevIns, DMAREVENTTYPE_INV_COMPLETE);
1274 }
1275}
1276#endif /* IN_RING3 */
1277
1278
1279/**
1280 * Checks if a primary fault can be recorded.
1281 *
1282 * @returns @c true if the fault can be recorded, @c false otherwise.
1283 * @param pDevIns The IOMMU device instance.
1284 * @param pThis The shared DMAR device state.
1285 *
1286 * @remarks Warning: This function has side-effects wrt the DMAR register state. Do
1287 * NOT call it unless there is a fault condition!
1288 */
1289static bool dmarPrimaryFaultCanRecord(PPDMDEVINS pDevIns, PDMAR pThis)
1290{
1291 PCDMARCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PCDMARCC);
1292 DMAR_ASSERT_LOCK_IS_OWNER(pDevIns, pThisCC);
1293
1294 uint32_t uFstsReg = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_FSTS_REG);
1295 if (uFstsReg & VTD_BF_FSTS_REG_PFO_MASK)
1296 return false;
1297
1298 /*
1299 * If we add more FRCD registers, we'll have to loop through them here.
1300 * Since we support only one FRCD_REG, we don't support "compression of multiple faults",
1301 * nor do we need to increment FRI.
1302 *
1303 * See Intel VT-d spec. 7.2.1 "Primary Fault Logging".
1304 */
1305 AssertCompile(DMAR_FRCD_REG_COUNT == 1);
1306 uint64_t const uFrcdRegHi = dmarRegReadRaw64(pThis, DMAR_MMIO_OFF_FRCD_HI_REG);
1307 if (uFrcdRegHi & VTD_BF_1_FRCD_REG_F_MASK)
1308 {
1309 uFstsReg |= VTD_BF_FSTS_REG_PFO_MASK;
1310 dmarRegWriteRaw32(pThis, VTD_MMIO_OFF_FSTS_REG, uFstsReg);
1311 return false;
1312 }
1313
1314 return true;
1315}
1316
1317
1318/**
1319 * Records a primary fault.
1320 *
1321 * @param pDevIns The IOMMU device instance.
1322 * @param enmDiag The diagnostic reason.
1323 * @param uFrcdHi The FRCD_HI_REG value for this fault.
1324 * @param uFrcdLo The FRCD_LO_REG value for this fault.
1325 */
1326static void dmarPrimaryFaultRecord(PPDMDEVINS pDevIns, DMARDIAG enmDiag, uint64_t uFrcdHi, uint64_t uFrcdLo)
1327{
1328 PDMAR pThis = PDMDEVINS_2_DATA(pDevIns, PDMAR);
1329 PCDMARCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PCDMARCC);
1330
1331 DMAR_LOCK(pDevIns, pThisCC);
1332
1333 /* Update the diagnostic reason. */
1334 pThis->enmDiag = enmDiag;
1335
1336 /* We don't support advance fault logging. */
1337 Assert(!(dmarRegRead32(pThis, VTD_MMIO_OFF_GSTS_REG) & VTD_BF_GSTS_REG_AFLS_MASK));
1338
1339 if (dmarPrimaryFaultCanRecord(pDevIns, pThis))
1340 {
1341 /* Update the fault recording registers with the fault information. */
1342 dmarRegWriteRaw64(pThis, DMAR_MMIO_OFF_FRCD_HI_REG, uFrcdHi);
1343 dmarRegWriteRaw64(pThis, DMAR_MMIO_OFF_FRCD_LO_REG, uFrcdLo);
1344
1345 /* Set the Pending Primary Fault (PPF) field in the status register. */
1346 dmarRegChangeRaw32(pThis, VTD_MMIO_OFF_FSTS_REG, UINT32_MAX, VTD_BF_FSTS_REG_PPF_MASK);
1347
1348 /* Raise interrupt if necessary. */
1349 dmarFaultEventRaiseInterrupt(pDevIns);
1350 }
1351
1352 DMAR_UNLOCK(pDevIns, pThisCC);
1353}
1354
1355
1356/**
1357 * Records an interrupt request fault.
1358 *
1359 * @param pDevIns The IOMMU device instance.
1360 * @param enmDiag The diagnostic reason.
1361 * @param enmIrFault The interrupt fault reason.
1362 * @param idDevice The device ID (bus, device, function).
1363 * @param idxIntr The interrupt index.
1364 */
1365static void dmarIrFaultRecord(PPDMDEVINS pDevIns, DMARDIAG enmDiag, VTDIRFAULT enmIrFault, uint16_t idDevice, uint16_t idxIntr)
1366{
1367 uint64_t const uFrcdHi = RT_BF_MAKE(VTD_BF_1_FRCD_REG_SID, idDevice)
1368 | RT_BF_MAKE(VTD_BF_1_FRCD_REG_FR, enmIrFault)
1369 | RT_BF_MAKE(VTD_BF_1_FRCD_REG_F, 1);
1370 uint64_t const uFrcdLo = (uint64_t)idxIntr << 48;
1371 dmarPrimaryFaultRecord(pDevIns, enmDiag, uFrcdHi, uFrcdLo);
1372}
1373
1374
1375/**
1376 * Records a qualified interrupt request fault.
1377 *
1378 * Qualified faults are those that can be suppressed by software using the FPD bit
1379 * in the IRTE.
1380 *
1381 * @param pDevIns The IOMMU device instance.
1382 * @param enmDiag The diagnostic reason.
1383 * @param enmIrFault The interrupt fault reason.
1384 * @param idDevice The device ID (bus, device, function).
1385 * @param idxIntr The interrupt index.
1386 * @param pIrte The IRTE that caused this fault.
1387 */
1388static void dmarIrFaultRecordQualified(PPDMDEVINS pDevIns, DMARDIAG enmDiag, VTDIRFAULT enmIrFault, uint16_t idDevice,
1389 uint16_t idxIntr, PCVTD_IRTE_T pIrte)
1390{
1391 Assert(vtdIrFaultIsQualified(enmIrFault));
1392 Assert(pIrte);
1393 if (!(pIrte->au64[0] & VTD_BF_0_IRTE_FPD_MASK))
1394 return dmarIrFaultRecord(pDevIns, enmDiag, enmIrFault, idDevice, idxIntr);
1395}
1396
1397
1398/**
1399 * Records an address translation fault.
1400 *
1401 * @param pDevIns The IOMMU device instance.
1402 * @param enmDiag The diagnostic reason.
1403 * @param enmAtFault The address translation fault reason.
1404 * @param pAddrRemap The DMA address remap info.
1405 */
1406static void dmarAtFaultRecord(PPDMDEVINS pDevIns, DMARDIAG enmDiag, VTDATFAULT enmAtFault, PCDMARADDRMAP pAddrRemap)
1407{
1408 uint8_t const fType1 = pAddrRemap->enmReqType & RT_BIT(1);
1409 uint8_t const fType2 = pAddrRemap->enmReqType & RT_BIT(0);
1410 uint8_t const fExec = pAddrRemap->fReqAttr & VTD_REQ_ATTR_EXE;
1411 uint8_t const fPriv = pAddrRemap->fReqAttr & VTD_REQ_ATTR_PRIV;
1412 uint64_t const uFrcdHi = RT_BF_MAKE(VTD_BF_1_FRCD_REG_SID, pAddrRemap->idDevice)
1413 | RT_BF_MAKE(VTD_BF_1_FRCD_REG_T2, fType2)
1414 | RT_BF_MAKE(VTD_BF_1_FRCD_REG_PP, PCIPASID_IS_VALID(pAddrRemap->Pasid))
1415 | RT_BF_MAKE(VTD_BF_1_FRCD_REG_EXE, fExec)
1416 | RT_BF_MAKE(VTD_BF_1_FRCD_REG_PRIV, fPriv)
1417 | RT_BF_MAKE(VTD_BF_1_FRCD_REG_FR, enmAtFault)
1418 | RT_BF_MAKE(VTD_BF_1_FRCD_REG_PV, PCIPASID_VAL(pAddrRemap->Pasid))
1419 | RT_BF_MAKE(VTD_BF_1_FRCD_REG_AT, pAddrRemap->enmAddrType)
1420 | RT_BF_MAKE(VTD_BF_1_FRCD_REG_T1, fType1)
1421 | RT_BF_MAKE(VTD_BF_1_FRCD_REG_F, 1);
1422 uint64_t const uFrcdLo = pAddrRemap->uDmaAddr & X86_PAGE_BASE_MASK;
1423 dmarPrimaryFaultRecord(pDevIns, enmDiag, uFrcdHi, uFrcdLo);
1424}
1425
1426
1427/**
1428 * Records a qualified address translation fault.
1429 *
1430 * Qualified faults are those that can be suppressed by software using the FPD bit
1431 * in the contex entry, scalable-mode context entry etc.
1432 *
1433 * This is to be used when Device-TLB, and PASIDs are not supported or for requests
1434 * where the device-TLB and PASID is not relevant/present.
1435 *
1436 * @param pDevIns The IOMMU device instance.
1437 * @param enmDiag The diagnostic reason.
1438 * @param enmAtFault The address translation fault reason.
1439 * @param pAddrRemap The DMA address remap info.
1440 * @param uPagingEntryQw0 The first qword of the paging entry.
1441 */
1442static void dmarAtFaultQualifiedRecord(PPDMDEVINS pDevIns, DMARDIAG enmDiag, VTDATFAULT enmAtFault, PCDMARADDRMAP pAddrRemap,
1443 uint64_t uPagingEntryQw0)
1444{
1445 AssertCompile( VTD_BF_0_CONTEXT_ENTRY_FPD_MASK == 0x2
1446 && VTD_BF_0_SM_CONTEXT_ENTRY_FPD_MASK == 0x2
1447 && VTD_BF_0_SM_CONTEXT_ENTRY_FPD_MASK == 0x2
1448 && VTD_BF_SM_PASID_DIR_ENTRY_FPD_MASK == 0x2
1449 && VTD_BF_0_SM_PASID_TBL_ENTRY_FPD_MASK == 0x2);
1450 if (!(uPagingEntryQw0 & VTD_BF_0_CONTEXT_ENTRY_FPD_MASK))
1451 dmarAtFaultRecord(pDevIns, enmDiag, enmAtFault, pAddrRemap);
1452}
1453
1454
1455/**
1456 * Records an IQE fault.
1457 *
1458 * @param pDevIns The IOMMU device instance.
1459 * @param enmIqei The IQE information.
1460 * @param enmDiag The diagnostic reason.
1461 */
1462static void dmarIqeFaultRecord(PPDMDEVINS pDevIns, DMARDIAG enmDiag, VTDIQEI enmIqei)
1463{
1464 PDMAR pThis = PDMDEVINS_2_DATA(pDevIns, PDMAR);
1465 PCDMARCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PCDMARCC);
1466
1467 DMAR_LOCK(pDevIns, pThisCC);
1468
1469 /* Update the diagnostic reason. */
1470 pThis->enmDiag = enmDiag;
1471
1472 /* Set the error bit. */
1473 uint32_t const fIqe = RT_BF_MAKE(VTD_BF_FSTS_REG_IQE, 1);
1474 dmarRegChangeRaw32(pThis, VTD_MMIO_OFF_FSTS_REG, UINT32_MAX, fIqe);
1475
1476 /* Set the error information. */
1477 uint64_t const fIqei = RT_BF_MAKE(VTD_BF_IQERCD_REG_IQEI, enmIqei);
1478 dmarRegChangeRaw64(pThis, VTD_MMIO_OFF_IQERCD_REG, UINT64_MAX, fIqei);
1479
1480 dmarFaultEventRaiseInterrupt(pDevIns);
1481
1482 DMAR_UNLOCK(pDevIns, pThisCC);
1483}
1484
1485
1486/**
1487 * Handles writes to GCMD_REG.
1488 *
1489 * @returns Strict VBox status code.
1490 * @param pDevIns The IOMMU device instance.
1491 * @param uGcmdReg The value written to GCMD_REG.
1492 */
1493static VBOXSTRICTRC dmarGcmdRegWrite(PPDMDEVINS pDevIns, uint32_t uGcmdReg)
1494{
1495 PDMAR pThis = PDMDEVINS_2_DATA(pDevIns, PDMAR);
1496 uint32_t const uGstsReg = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_GSTS_REG);
1497 uint32_t const fChanged = uGstsReg ^ uGcmdReg;
1498 uint64_t const fExtCapReg = pThis->fExtCapReg;
1499
1500 /* Queued-invalidation. */
1501 if ( (fExtCapReg & VTD_BF_ECAP_REG_QI_MASK)
1502 && (fChanged & VTD_BF_GCMD_REG_QIE_MASK))
1503 {
1504 if (uGcmdReg & VTD_BF_GCMD_REG_QIE_MASK)
1505 {
1506 dmarRegChangeRaw32(pThis, VTD_MMIO_OFF_GSTS_REG, UINT32_MAX, VTD_BF_GSTS_REG_QIES_MASK);
1507 dmarInvQueueThreadWakeUpIfNeeded(pDevIns);
1508 }
1509 else
1510 {
1511 dmarRegChangeRaw32(pThis, VTD_MMIO_OFF_GSTS_REG, ~VTD_BF_GSTS_REG_QIES_MASK, 0 /* fOrMask */);
1512 dmarRegWriteRaw32(pThis, VTD_MMIO_OFF_IQH_REG, 0);
1513 }
1514 }
1515
1516 if (fExtCapReg & VTD_BF_ECAP_REG_IR_MASK)
1517 {
1518 /* Set Interrupt Remapping Table Pointer (SIRTP). */
1519 if (uGcmdReg & VTD_BF_GCMD_REG_SIRTP_MASK)
1520 {
1521 /** @todo Perform global invalidation of all interrupt-entry cache when ESIRTPS is
1522 * supported. */
1523 pThis->uIrtaReg = dmarRegReadRaw64(pThis, VTD_MMIO_OFF_IRTA_REG);
1524 dmarRegChangeRaw32(pThis, VTD_MMIO_OFF_GSTS_REG, UINT32_MAX, VTD_BF_GSTS_REG_IRTPS_MASK);
1525 }
1526
1527 /* Interrupt remapping. */
1528 if (fChanged & VTD_BF_GCMD_REG_IRE_MASK)
1529 {
1530 if (uGcmdReg & VTD_BF_GCMD_REG_IRE_MASK)
1531 dmarRegChangeRaw32(pThis, VTD_MMIO_OFF_GSTS_REG, UINT32_MAX, VTD_BF_GSTS_REG_IRES_MASK);
1532 else
1533 dmarRegChangeRaw32(pThis, VTD_MMIO_OFF_GSTS_REG, ~VTD_BF_GSTS_REG_IRES_MASK, 0 /* fOrMask */);
1534 }
1535
1536 /* Compatibility format interrupts. */
1537 if (fChanged & VTD_BF_GCMD_REG_CFI_MASK)
1538 {
1539 if (uGcmdReg & VTD_BF_GCMD_REG_CFI_MASK)
1540 dmarRegChangeRaw32(pThis, VTD_MMIO_OFF_GSTS_REG, UINT32_MAX, VTD_BF_GSTS_REG_CFIS_MASK);
1541 else
1542 dmarRegChangeRaw32(pThis, VTD_MMIO_OFF_GSTS_REG, ~VTD_BF_GSTS_REG_CFIS_MASK, 0 /* fOrMask */);
1543 }
1544 }
1545
1546 /* Set Root Table Pointer (SRTP). */
1547 if (uGcmdReg & VTD_BF_GCMD_REG_SRTP_MASK)
1548 {
1549 /** @todo Perform global invalidation of all remapping translation caches when
1550 * ESRTPS is supported. */
1551 pThis->uRtaddrReg = dmarRegReadRaw64(pThis, VTD_MMIO_OFF_RTADDR_REG);
1552 dmarRegChangeRaw32(pThis, VTD_MMIO_OFF_GSTS_REG, UINT32_MAX, VTD_BF_GSTS_REG_RTPS_MASK);
1553 }
1554
1555 /* Translation (DMA remapping). */
1556 if (fChanged & VTD_BF_GCMD_REG_TE_MASK)
1557 {
1558 if (uGcmdReg & VTD_BF_GCMD_REG_TE_MASK)
1559 dmarRegChangeRaw32(pThis, VTD_MMIO_OFF_GSTS_REG, UINT32_MAX, VTD_BF_GSTS_REG_TES_MASK);
1560 else
1561 dmarRegChangeRaw32(pThis, VTD_MMIO_OFF_GSTS_REG, ~VTD_BF_GSTS_REG_TES_MASK, 0 /* fOrMask */);
1562 }
1563
1564 return VINF_SUCCESS;
1565}
1566
1567
1568/**
1569 * Handles writes to CCMD_REG.
1570 *
1571 * @returns Strict VBox status code.
1572 * @param pDevIns The IOMMU device instance.
1573 * @param offReg The MMIO register offset.
1574 * @param cbReg The size of the MMIO access (in bytes).
1575 * @param uCcmdReg The value written to CCMD_REG.
1576 */
1577static VBOXSTRICTRC dmarCcmdRegWrite(PPDMDEVINS pDevIns, uint16_t offReg, uint8_t cbReg, uint64_t uCcmdReg)
1578{
1579 /* At present, we only care about responding to high 32-bits writes, low 32-bits are data. */
1580 if (offReg + cbReg > VTD_MMIO_OFF_CCMD_REG + 4)
1581 {
1582 /* Check if we need to invalidate the context-context. */
1583 bool const fIcc = RT_BF_GET(uCcmdReg, VTD_BF_CCMD_REG_ICC);
1584 if (fIcc)
1585 {
1586 PDMAR pThis = PDMDEVINS_2_DATA(pDevIns, PDMAR);
1587 uint8_t const uMajorVersion = RT_BF_GET(pThis->uVerReg, VTD_BF_VER_REG_MAX);
1588 if (uMajorVersion < 6)
1589 {
1590 /* Register-based invalidation can only be used when queued-invalidations are not enabled. */
1591 uint32_t const uGstsReg = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_GSTS_REG);
1592 if (!(uGstsReg & VTD_BF_GSTS_REG_QIES_MASK))
1593 {
1594 /* Verify table translation mode is legacy. */
1595 uint8_t const fTtm = RT_BF_GET(pThis->uRtaddrReg, VTD_BF_RTADDR_REG_TTM);
1596 if (fTtm == VTD_TTM_LEGACY_MODE)
1597 {
1598 /** @todo Invalidate. */
1599 return VINF_SUCCESS;
1600 }
1601 pThis->enmDiag = kDmarDiag_CcmdReg_Ttm_Invalid;
1602 }
1603 else
1604 pThis->enmDiag = kDmarDiag_CcmdReg_Qi_Enabled;
1605 }
1606 else
1607 pThis->enmDiag = kDmarDiag_CcmdReg_NotSupported;
1608 dmarRegChangeRaw64(pThis, VTD_MMIO_OFF_GSTS_REG, ~VTD_BF_CCMD_REG_CAIG_MASK, 0 /* fOrMask */);
1609 }
1610 }
1611 return VINF_SUCCESS;
1612}
1613
1614
1615/**
1616 * Handles writes to FECTL_REG.
1617 *
1618 * @returns Strict VBox status code.
1619 * @param pDevIns The IOMMU device instance.
1620 * @param uFectlReg The value written to FECTL_REG.
1621 */
1622static VBOXSTRICTRC dmarFectlRegWrite(PPDMDEVINS pDevIns, uint32_t uFectlReg)
1623{
1624 /*
1625 * If software unmasks the interrupt when the interrupt is pending, we must raise
1626 * the interrupt now (which will consequently clear the interrupt pending (IP) bit).
1627 */
1628 if ( (uFectlReg & VTD_BF_FECTL_REG_IP_MASK)
1629 && ~(uFectlReg & VTD_BF_FECTL_REG_IM_MASK))
1630 dmarEventRaiseInterrupt(pDevIns, DMAREVENTTYPE_FAULT);
1631 return VINF_SUCCESS;
1632}
1633
1634
1635/**
1636 * Handles writes to FSTS_REG.
1637 *
1638 * @returns Strict VBox status code.
1639 * @param pDevIns The IOMMU device instance.
1640 * @param uFstsReg The value written to FSTS_REG.
1641 * @param uPrev The value in FSTS_REG prior to writing it.
1642 */
1643static VBOXSTRICTRC dmarFstsRegWrite(PPDMDEVINS pDevIns, uint32_t uFstsReg, uint32_t uPrev)
1644{
1645 /*
1646 * If software clears other status bits in FSTS_REG (pertaining to primary fault logging),
1647 * the interrupt pending (IP) bit must be cleared.
1648 *
1649 * See Intel VT-d spec. 10.4.10 "Fault Event Control Register".
1650 */
1651 uint32_t const fChanged = uPrev ^ uFstsReg;
1652 if (fChanged & ( VTD_BF_FSTS_REG_ICE_MASK | VTD_BF_FSTS_REG_ITE_MASK
1653 | VTD_BF_FSTS_REG_IQE_MASK | VTD_BF_FSTS_REG_PFO_MASK))
1654 {
1655 PDMAR pThis = PDMDEVINS_2_DATA(pDevIns, PDMAR);
1656 dmarRegChangeRaw32(pThis, VTD_MMIO_OFF_FECTL_REG, ~VTD_BF_FECTL_REG_IP_MASK, 0 /* fOrMask */);
1657 }
1658 return VINF_SUCCESS;
1659}
1660
1661
1662/**
1663 * Handles writes to IQT_REG.
1664 *
1665 * @returns Strict VBox status code.
1666 * @param pDevIns The IOMMU device instance.
1667 * @param offReg The MMIO register offset.
1668 * @param uIqtReg The value written to IQT_REG.
1669 */
1670static VBOXSTRICTRC dmarIqtRegWrite(PPDMDEVINS pDevIns, uint16_t offReg, uint64_t uIqtReg)
1671{
1672 /* We only care about the low 32-bits, high 32-bits are reserved. */
1673 Assert(offReg == VTD_MMIO_OFF_IQT_REG);
1674 PDMAR pThis = PDMDEVINS_2_DATA(pDevIns, PDMAR);
1675
1676 /* Paranoia. */
1677 Assert(!(uIqtReg & ~VTD_BF_IQT_REG_QT_MASK));
1678
1679 uint32_t const offQt = uIqtReg;
1680 uint64_t const uIqaReg = dmarRegReadRaw64(pThis, VTD_MMIO_OFF_IQA_REG);
1681 uint8_t const fDw = RT_BF_GET(uIqaReg, VTD_BF_IQA_REG_DW);
1682
1683 /* If the descriptor width is 256-bits, the queue tail offset must be aligned accordingly. */
1684 if ( fDw != VTD_IQA_REG_DW_256_BIT
1685 || !(offQt & RT_BIT(4)))
1686 dmarInvQueueThreadWakeUpIfNeeded(pDevIns);
1687 else
1688 {
1689 /* Hardware treats bit 4 as RsvdZ in this situation, so clear it. */
1690 dmarRegChangeRaw32(pThis, offReg, ~RT_BIT(4), 0 /* fOrMask */);
1691 dmarIqeFaultRecord(pDevIns, kDmarDiag_IqtReg_Qt_NotAligned, VTDIQEI_QUEUE_TAIL_MISALIGNED);
1692 }
1693 return VINF_SUCCESS;
1694}
1695
1696
1697/**
1698 * Handles writes to IQA_REG.
1699 *
1700 * @returns Strict VBox status code.
1701 * @param pDevIns The IOMMU device instance.
1702 * @param offReg The MMIO register offset.
1703 * @param uIqaReg The value written to IQA_REG.
1704 */
1705static VBOXSTRICTRC dmarIqaRegWrite(PPDMDEVINS pDevIns, uint16_t offReg, uint64_t uIqaReg)
1706{
1707 /* At present, we only care about the low 32-bits, high 32-bits are data. */
1708 Assert(offReg == VTD_MMIO_OFF_IQA_REG); NOREF(offReg);
1709
1710 /** @todo What happens if IQA_REG is written when dmarInvQueueCanProcessRequests
1711 * returns true? The Intel VT-d spec. doesn't state anywhere that it
1712 * cannot happen or that it's ignored when it does happen. */
1713
1714 PDMAR pThis = PDMDEVINS_2_DATA(pDevIns, PDMAR);
1715 uint8_t const fDw = RT_BF_GET(uIqaReg, VTD_BF_IQA_REG_DW);
1716 if (fDw == VTD_IQA_REG_DW_256_BIT)
1717 {
1718 bool const fSupports256BitDw = (pThis->fExtCapReg & (VTD_BF_ECAP_REG_SMTS_MASK | VTD_BF_ECAP_REG_ADMS_MASK));
1719 if (fSupports256BitDw)
1720 { /* likely */ }
1721 else
1722 dmarIqeFaultRecord(pDevIns, kDmarDiag_IqaReg_Dw_256_Invalid, VTDIQEI_INVALID_DESCRIPTOR_WIDTH);
1723 }
1724 /* else: 128-bit descriptor width is validated lazily, see explanation in dmarR3InvQueueProcessRequests. */
1725
1726 return VINF_SUCCESS;
1727}
1728
1729
1730/**
1731 * Handles writes to ICS_REG.
1732 *
1733 * @returns Strict VBox status code.
1734 * @param pDevIns The IOMMU device instance.
1735 * @param uIcsReg The value written to ICS_REG.
1736 */
1737static VBOXSTRICTRC dmarIcsRegWrite(PPDMDEVINS pDevIns, uint32_t uIcsReg)
1738{
1739 /*
1740 * If the IP field is set when software services the interrupt condition,
1741 * (by clearing the IWC field), the IP field must be cleared.
1742 */
1743 if (!(uIcsReg & VTD_BF_ICS_REG_IWC_MASK))
1744 {
1745 PDMAR pThis = PDMDEVINS_2_DATA(pDevIns, PDMAR);
1746 dmarRegChangeRaw32(pThis, VTD_MMIO_OFF_IECTL_REG, ~VTD_BF_IECTL_REG_IP_MASK, 0 /* fOrMask */);
1747 }
1748 return VINF_SUCCESS;
1749}
1750
1751
1752/**
1753 * Handles writes to IECTL_REG.
1754 *
1755 * @returns Strict VBox status code.
1756 * @param pDevIns The IOMMU device instance.
1757 * @param uIectlReg The value written to IECTL_REG.
1758 */
1759static VBOXSTRICTRC dmarIectlRegWrite(PPDMDEVINS pDevIns, uint32_t uIectlReg)
1760{
1761 /*
1762 * If software unmasks the interrupt when the interrupt is pending, we must raise
1763 * the interrupt now (which will consequently clear the interrupt pending (IP) bit).
1764 */
1765 if ( (uIectlReg & VTD_BF_IECTL_REG_IP_MASK)
1766 && ~(uIectlReg & VTD_BF_IECTL_REG_IM_MASK))
1767 dmarEventRaiseInterrupt(pDevIns, DMAREVENTTYPE_INV_COMPLETE);
1768 return VINF_SUCCESS;
1769}
1770
1771
1772/**
1773 * Handles writes to FRCD_REG (High 64-bits).
1774 *
1775 * @returns Strict VBox status code.
1776 * @param pDevIns The IOMMU device instance.
1777 * @param offReg The MMIO register offset.
1778 * @param cbReg The size of the MMIO access (in bytes).
1779 * @param uFrcdHiReg The value written to FRCD_REG.
1780 * @param uPrev The value in FRCD_REG prior to writing it.
1781 */
1782static VBOXSTRICTRC dmarFrcdHiRegWrite(PPDMDEVINS pDevIns, uint16_t offReg, uint8_t cbReg, uint64_t uFrcdHiReg, uint64_t uPrev)
1783{
1784 /* We only care about responding to high 32-bits, low 32-bits are read-only. */
1785 if (offReg + cbReg > DMAR_MMIO_OFF_FRCD_HI_REG + 4)
1786 {
1787 /*
1788 * If software cleared the RW1C F (fault) bit in all FRCD_REGs, hardware clears the
1789 * Primary Pending Fault (PPF) and the interrupt pending (IP) bits. Our implementation
1790 * has only 1 FRCD register.
1791 *
1792 * See Intel VT-d spec. 10.4.10 "Fault Event Control Register".
1793 */
1794 AssertCompile(DMAR_FRCD_REG_COUNT == 1);
1795 uint64_t const fChanged = uPrev ^ uFrcdHiReg;
1796 if (fChanged & VTD_BF_1_FRCD_REG_F_MASK)
1797 {
1798 Assert(!(uFrcdHiReg & VTD_BF_1_FRCD_REG_F_MASK)); /* Software should only ever be able to clear this bit. */
1799 PDMAR pThis = PDMDEVINS_2_DATA(pDevIns, PDMAR);
1800 dmarRegChangeRaw32(pThis, VTD_MMIO_OFF_FSTS_REG, ~VTD_BF_FSTS_REG_PPF_MASK, 0 /* fOrMask */);
1801 dmarRegChangeRaw32(pThis, VTD_MMIO_OFF_FECTL_REG, ~VTD_BF_FECTL_REG_IP_MASK, 0 /* fOrMask */);
1802 }
1803 }
1804 return VINF_SUCCESS;
1805}
1806
1807
1808/**
1809 * Performs a PCI target abort for a DMA remapping (DR) operation.
1810 *
1811 * @param pDevIns The IOMMU device instance.
1812 */
1813static void dmarDrTargetAbort(PPDMDEVINS pDevIns)
1814{
1815 /** @todo r=ramshankar: I don't know for sure if a PCI target abort is caused or not
1816 * as the Intel VT-d spec. is vague. Wording seems to suggest it does, but
1817 * who knows. */
1818 PPDMPCIDEV pPciDev = pDevIns->apPciDevs[0];
1819 uint16_t const u16Status = PDMPciDevGetStatus(pPciDev) | VBOX_PCI_STATUS_SIG_TARGET_ABORT;
1820 PDMPciDevSetStatus(pPciDev, u16Status);
1821}
1822
1823
1824/**
1825 * Checks whether the address width (AW) is supported by our hardware
1826 * implementation for legacy mode address translation.
1827 *
1828 * @returns @c true if it's supported, @c false otherwise.
1829 * @param pThis The shared DMAR device state.
1830 * @param pCtxEntry The context entry.
1831 */
1832static bool dmarDrLegacyModeIsAwValid(PCDMAR pThis, PCVTD_CONTEXT_ENTRY_T pCtxEntry)
1833{
1834 uint8_t const fAw = RT_BF_GET(pCtxEntry->au64[1], VTD_BF_1_CONTEXT_ENTRY_AW);
1835 uint8_t const fSagaw = RT_BF_GET(pThis->fCapReg, VTD_BF_CAP_REG_SAGAW);
1836 uint8_t const fAwMask = RT_BIT(fAw);
1837 Assert(!(fSagaw & ~(RT_BIT(1) | RT_BIT(2) | RT_BIT(3))));
1838 return fAw < 4 ? RT_BOOL(fSagaw & fAwMask) : false;
1839}
1840
1841
1842/**
1843 * Reads a root entry from guest memory.
1844 *
1845 * @returns VBox status code.
1846 * @param pDevIns The IOMMU device instance.
1847 * @param uRtaddrReg The current RTADDR_REG value.
1848 * @param idxRootEntry The index of the root entry to read.
1849 * @param pRootEntry Where to store the read root entry.
1850 */
1851static int dmarDrReadRootEntry(PPDMDEVINS pDevIns, uint64_t uRtaddrReg, uint8_t idxRootEntry, PVTD_ROOT_ENTRY_T pRootEntry)
1852{
1853 size_t const cbRootEntry = sizeof(*pRootEntry);
1854 RTGCPHYS const GCPhysRootEntry = (uRtaddrReg & VTD_BF_RTADDR_REG_RTA_MASK) + (idxRootEntry * cbRootEntry);
1855 return PDMDevHlpPhysReadMeta(pDevIns, GCPhysRootEntry, pRootEntry, cbRootEntry);
1856}
1857
1858
1859/**
1860 * Reads a context entry from guest memory.
1861 *
1862 * @returns VBox status code.
1863 * @param pDevIns The IOMMU device instance.
1864 * @param GCPhysCtxTable The physical address of the context table.
1865 * @param idxCtxEntry The index of the context entry to read.
1866 * @param pCtxEntry Where to store the read context entry.
1867 */
1868static int dmarDrReadCtxEntry(PPDMDEVINS pDevIns, RTGCPHYS GCPhysCtxTable, uint8_t idxCtxEntry, PVTD_CONTEXT_ENTRY_T pCtxEntry)
1869{
1870 size_t const cbCtxEntry = sizeof(*pCtxEntry);
1871 RTGCPHYS const GCPhysCtxEntry = GCPhysCtxTable + (idxCtxEntry * cbCtxEntry);
1872 return PDMDevHlpPhysReadMeta(pDevIns, GCPhysCtxEntry, pCtxEntry, cbCtxEntry);
1873}
1874
1875
1876/**
1877 * Handles remapping of DMA address requests in legacy mode.
1878 *
1879 * @returns VBox status code.
1880 * @param pDevIns The IOMMU device instance.
1881 * @param uRtaddrReg The current RTADDR_REG value.
1882 * @param pAddrRemap The DMA address remap info.
1883 */
1884static int dmarDrLegacyModeRemapAddr(PPDMDEVINS pDevIns, uint64_t uRtaddrReg, PDMARADDRMAP pAddrRemap)
1885{
1886 uint8_t const idxRootEntry = RT_HI_U8(pAddrRemap->idDevice);
1887 VTD_ROOT_ENTRY_T RootEntry;
1888 int rc = dmarDrReadRootEntry(pDevIns, uRtaddrReg, idxRootEntry, &RootEntry);
1889 if (RT_SUCCESS(rc))
1890 {
1891 uint64_t const uRootEntryQword0 = RootEntry.au64[0];
1892 uint64_t const uRootEntryQword1 = RootEntry.au64[1];
1893 bool const fRootEntryPresent = RT_BF_GET(uRootEntryQword0, VTD_BF_0_ROOT_ENTRY_P);
1894 if (fRootEntryPresent)
1895 {
1896 if ( !(uRootEntryQword0 & ~VTD_ROOT_ENTRY_0_VALID_MASK)
1897 && !(uRootEntryQword1 & ~VTD_ROOT_ENTRY_1_VALID_MASK))
1898 {
1899 RTGCPHYS const GCPhysCtxTable = RT_BF_GET(uRootEntryQword0, VTD_BF_0_ROOT_ENTRY_CTP);
1900 uint8_t const idxCtxEntry = RT_LO_U8(pAddrRemap->idDevice);
1901 VTD_CONTEXT_ENTRY_T CtxEntry;
1902 /* We don't verify bits 63:HAW of GCPhysCtxTable is 0 since reading from such an address should fail anyway. */
1903 rc = dmarDrReadCtxEntry(pDevIns, GCPhysCtxTable, idxCtxEntry, &CtxEntry);
1904 if (RT_SUCCESS(rc))
1905 {
1906 uint64_t const uCtxEntryQword0 = CtxEntry.au64[0];
1907 uint64_t const uCtxEntryQword1 = CtxEntry.au64[1];
1908 bool const fCtxEntryPresent = RT_BF_GET(uCtxEntryQword0, VTD_BF_0_CONTEXT_ENTRY_P);
1909 if (fCtxEntryPresent)
1910 {
1911 if ( !(uCtxEntryQword0 & ~VTD_CONTEXT_ENTRY_0_VALID_MASK)
1912 && !(uCtxEntryQword1 & ~VTD_CONTEXT_ENTRY_1_VALID_MASK))
1913 {
1914 PCDMAR pThis = PDMDEVINS_2_DATA(pDevIns, PCDMAR);
1915 uint8_t const fTt = RT_BF_GET(uCtxEntryQword0, VTD_BF_0_CONTEXT_ENTRY_TT);
1916 switch (fTt)
1917 {
1918 case 0:
1919 {
1920 if (pAddrRemap->enmAddrType == PCIADDRTYPE_UNTRANSLATED)
1921 {
1922 if (dmarDrLegacyModeIsAwValid(pThis, &CtxEntry))
1923 {
1924
1925 return VERR_NOT_IMPLEMENTED;
1926 }
1927 else
1928 dmarAtFaultQualifiedRecord(pDevIns, kDmarDiag_Atf_Lct_4_1, VTDATFAULT_LCT_4_1,
1929 pAddrRemap, uCtxEntryQword0);
1930 }
1931 Log4Func(("Translation type blocks translated and translation requests\n"));
1932 return VERR_IOMMU_ADDR_TRANSLATION_FAILED;
1933 }
1934
1935 case 2:
1936 {
1937 if (pThis->fExtCapReg & VTD_BF_ECAP_REG_PT_MASK)
1938 {
1939 pAddrRemap->GCPhysSpa = pAddrRemap->uDmaAddr;
1940 pAddrRemap->cbContiguous = pAddrRemap->cbDma;
1941 return VINF_SUCCESS;
1942 }
1943 RT_FALL_THRU();
1944 }
1945
1946 case 1:
1947 {
1948 Assert(!(pThis->fExtCapReg & VTD_BF_ECAP_REG_DT_MASK));
1949 RT_FALL_THRU();
1950 }
1951
1952 default:
1953 {
1954 dmarAtFaultQualifiedRecord(pDevIns, kDmarDiag_Atf_Lct_4_2, VTDATFAULT_LCT_4_2, pAddrRemap,
1955 uCtxEntryQword0);
1956 break;
1957 }
1958 }
1959 }
1960 else
1961 dmarAtFaultQualifiedRecord(pDevIns, kDmarDiag_Atf_Lct_3, VTDATFAULT_LCT_3, pAddrRemap,
1962 uCtxEntryQword0);
1963 }
1964 else
1965 dmarAtFaultQualifiedRecord(pDevIns, kDmarDiag_Atf_Lct_2, VTDATFAULT_LCT_2, pAddrRemap,
1966 uCtxEntryQword0);
1967 }
1968 else
1969 dmarAtFaultRecord(pDevIns, kDmarDiag_Atf_Lct_1, VTDATFAULT_LCT_1, pAddrRemap);
1970 }
1971 else
1972 dmarAtFaultRecord(pDevIns, kDmarDiag_Atf_Lrt_3, VTDATFAULT_LRT_3, pAddrRemap);
1973 }
1974 else
1975 dmarAtFaultRecord(pDevIns, kDmarDiag_Atf_Lrt_2, VTDATFAULT_LRT_2, pAddrRemap);
1976 }
1977 else
1978 dmarAtFaultRecord(pDevIns, kDmarDiag_Atf_Lrt_1, VTDATFAULT_LRT_1, pAddrRemap);
1979 return VERR_IOMMU_ADDR_TRANSLATION_FAILED;
1980}
1981
1982
1983/**
1984 * Handles remapping of DMA address requests in scalable mode.
1985 *
1986 * @returns VBox status code.
1987 * @param pDevIns The IOMMU device instance.
1988 * @param uRtaddrReg The current RTADDR_REG value.
1989 * @param pAddrRemap The DMA address remap info.
1990 */
1991static int dmarDrScalableModeRemapAddr(PPDMDEVINS pDevIns, uint64_t uRtaddrReg, PDMARADDRMAP pAddrRemap)
1992{
1993 PCDMAR pThis = PDMDEVINS_2_DATA(pDevIns, PDMAR);
1994 if (pThis->fExtCapReg & VTD_BF_ECAP_REG_SMTS_MASK)
1995 {
1996 RT_NOREF1(uRtaddrReg);
1997 return VERR_NOT_IMPLEMENTED;
1998 }
1999
2000 dmarAtFaultRecord(pDevIns, kDmarDiag_Atf_Rta_1_3, VTDATFAULT_RTA_1_3, pAddrRemap);
2001 return VERR_IOMMU_ADDR_TRANSLATION_FAILED;
2002}
2003
2004
2005/**
2006 * Memory access bulk (one or more 4K pages) request from a device.
2007 *
2008 * @returns VBox status code.
2009 * @param pDevIns The IOMMU device instance.
2010 * @param idDevice The device ID (bus, device, function).
2011 * @param cIovas The number of addresses being accessed.
2012 * @param pauIovas The I/O virtual addresses for each page being accessed.
2013 * @param fFlags The access flags, see PDMIOMMU_MEM_F_XXX.
2014 * @param paGCPhysSpa Where to store the translated physical addresses.
2015 *
2016 * @thread Any.
2017 */
2018static DECLCALLBACK(int) iommuIntelMemBulkAccess(PPDMDEVINS pDevIns, uint16_t idDevice, size_t cIovas, uint64_t const *pauIovas,
2019 uint32_t fFlags, PRTGCPHYS paGCPhysSpa)
2020{
2021 RT_NOREF6(pDevIns, idDevice, cIovas, pauIovas, fFlags, paGCPhysSpa);
2022 return VERR_NOT_IMPLEMENTED;
2023}
2024
2025
2026/**
2027 * Memory access transaction from a device.
2028 *
2029 * @returns VBox status code.
2030 * @param pDevIns The IOMMU device instance.
2031 * @param idDevice The device ID (bus, device, function).
2032 * @param uIova The I/O virtual address being accessed.
2033 * @param cbIova The size of the access.
2034 * @param fFlags The access flags, see PDMIOMMU_MEM_F_XXX.
2035 * @param pGCPhysSpa Where to store the translated system physical address.
2036 * @param pcbContiguous Where to store the number of contiguous bytes translated
2037 * and permission-checked.
2038 *
2039 * @thread Any.
2040 */
2041static DECLCALLBACK(int) iommuIntelMemAccess(PPDMDEVINS pDevIns, uint16_t idDevice, uint64_t uIova, size_t cbIova,
2042 uint32_t fFlags, PRTGCPHYS pGCPhysSpa, size_t *pcbContiguous)
2043{
2044 /* Validate. */
2045 AssertPtr(pDevIns);
2046 AssertPtr(pGCPhysSpa);
2047 AssertPtr(pcbContiguous);
2048 Assert(cbIova > 0); /** @todo Are we going to support ZLR (zero-length reads to write-only pages)? */
2049 Assert(!(fFlags & ~PDMIOMMU_MEM_F_VALID_MASK));
2050
2051 PDMAR pThis = PDMDEVINS_2_DATA(pDevIns, PDMAR);
2052 PCDMARCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PCDMARCC);
2053
2054 DMAR_LOCK(pDevIns, pThisCC);
2055 uint32_t const uGstsReg = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_GSTS_REG);
2056 uint64_t const uRtaddrReg = pThis->uRtaddrReg;
2057 DMAR_UNLOCK(pDevIns, pThisCC);
2058
2059 if (uGstsReg & VTD_BF_GSTS_REG_TES_MASK)
2060 {
2061 VTDREQTYPE enmReqType;
2062 if (fFlags & PDMIOMMU_MEM_F_READ)
2063 {
2064 enmReqType = VTDREQTYPE_READ;
2065 STAM_COUNTER_INC(&pThis->CTX_SUFF_Z(StatMemRead));
2066 }
2067 else
2068 {
2069 enmReqType = VTDREQTYPE_WRITE;
2070 STAM_COUNTER_INC(&pThis->CTX_SUFF_Z(StatMemWrite));
2071 }
2072
2073 DMARADDRMAP AddrRemap;
2074 AddrRemap.idDevice = idDevice;
2075 AddrRemap.Pasid = NIL_PCIPASID;
2076 AddrRemap.enmAddrType = PCIADDRTYPE_UNTRANSLATED;
2077 AddrRemap.enmReqType = enmReqType;
2078 AddrRemap.uDmaAddr = uIova;
2079 AddrRemap.cbDma = cbIova;
2080 AddrRemap.GCPhysSpa = NIL_RTGCPHYS;
2081 AddrRemap.cbContiguous = 0;
2082
2083 int rc;
2084 uint8_t const fTtm = RT_BF_GET(uRtaddrReg, VTD_BF_RTADDR_REG_TTM);
2085 switch (fTtm)
2086 {
2087 case VTD_TTM_LEGACY_MODE:
2088 {
2089 rc = dmarDrLegacyModeRemapAddr(pDevIns, uRtaddrReg, &AddrRemap);
2090 break;
2091 }
2092
2093 case VTD_TTM_SCALABLE_MODE:
2094 {
2095 rc = dmarDrScalableModeRemapAddr(pDevIns, uRtaddrReg, &AddrRemap);
2096 break;
2097 }
2098
2099 case VTD_TTM_ABORT_DMA_MODE:
2100 {
2101 rc = VERR_IOMMU_ADDR_TRANSLATION_FAILED;
2102 if (pThis->fExtCapReg & VTD_BF_ECAP_REG_ADMS_MASK)
2103 dmarDrTargetAbort(pDevIns);
2104 else
2105 dmarAtFaultRecord(pDevIns, kDmarDiag_Atf_Rta_1_1, VTDATFAULT_RTA_1_1, &AddrRemap);
2106 break;
2107 }
2108
2109 default:
2110 {
2111 rc = VERR_IOMMU_ADDR_TRANSLATION_FAILED;
2112 dmarAtFaultRecord(pDevIns, kDmarDiag_Atf_Rta_1_2, VTDATFAULT_RTA_1_2, &AddrRemap);
2113 break;
2114 }
2115 }
2116
2117 *pcbContiguous = AddrRemap.cbContiguous;
2118 *pGCPhysSpa = AddrRemap.GCPhysSpa;
2119 return rc;
2120 }
2121
2122 *pGCPhysSpa = uIova;
2123 *pcbContiguous = cbIova;
2124 return VINF_SUCCESS;
2125}
2126
2127
2128/**
2129 * Reads an IRTE from guest memory.
2130 *
2131 * @returns VBox status code.
2132 * @param pDevIns The IOMMU device instance.
2133 * @param uIrtaReg The IRTA_REG.
2134 * @param idxIntr The interrupt index.
2135 * @param pIrte Where to store the read IRTE.
2136 */
2137static int dmarIrReadIrte(PPDMDEVINS pDevIns, uint64_t uIrtaReg, uint16_t idxIntr, PVTD_IRTE_T pIrte)
2138{
2139 Assert(idxIntr < VTD_IRTA_REG_GET_ENTRY_COUNT(uIrtaReg));
2140
2141 size_t const cbIrte = sizeof(*pIrte);
2142 RTGCPHYS const GCPhysIrte = (uIrtaReg & VTD_BF_IRTA_REG_IRTA_MASK) + (idxIntr * cbIrte);
2143 return PDMDevHlpPhysReadMeta(pDevIns, GCPhysIrte, pIrte, cbIrte);
2144}
2145
2146
2147/**
2148 * Remaps the source MSI to the destination MSI given the IRTE.
2149 *
2150 * @param fExtIntrMode Whether extended interrupt mode is enabled (i.e
2151 * IRTA_REG.EIME).
2152 * @param pIrte The IRTE used for the remapping.
2153 * @param pMsiIn The source MSI (currently unused).
2154 * @param pMsiOut Where to store the remapped MSI.
2155 */
2156static void dmarIrRemapFromIrte(bool fExtIntrMode, PCVTD_IRTE_T pIrte, PCMSIMSG pMsiIn, PMSIMSG pMsiOut)
2157{
2158 NOREF(pMsiIn);
2159 uint64_t const uIrteQword0 = pIrte->au64[0];
2160
2161 /*
2162 * Let's start with a clean slate and preserve unspecified bits if the need arises.
2163 * For instance, address bits 1:0 is supposed to be "ignored" by remapping hardware,
2164 * but it's not clear if hardware zeroes out these bits in the remapped MSI or if
2165 * it copies it from the source MSI.
2166 */
2167 RT_ZERO(*pMsiOut);
2168 pMsiOut->Addr.n.u1DestMode = RT_BF_GET(uIrteQword0, VTD_BF_0_IRTE_DM);
2169 pMsiOut->Addr.n.u1RedirHint = RT_BF_GET(uIrteQword0, VTD_BF_0_IRTE_RH);
2170 pMsiOut->Addr.n.u12Addr = VBOX_MSI_ADDR_BASE >> VBOX_MSI_ADDR_SHIFT;
2171 if (fExtIntrMode)
2172 {
2173 /*
2174 * Apparently the DMAR stuffs the high 24-bits of the destination ID into the
2175 * high 24-bits of the upper 32-bits of the message address, see @bugref{9967#c22}.
2176 */
2177 uint32_t const idDest = RT_BF_GET(uIrteQword0, VTD_BF_0_IRTE_DST);
2178 pMsiOut->Addr.n.u8DestId = idDest;
2179 pMsiOut->Addr.n.u32Rsvd0 = idDest & UINT32_C(0xffffff00);
2180 }
2181 else
2182 pMsiOut->Addr.n.u8DestId = RT_BF_GET(uIrteQword0, VTD_BF_0_IRTE_DST_XAPIC);
2183
2184 pMsiOut->Data.n.u8Vector = RT_BF_GET(uIrteQword0, VTD_BF_0_IRTE_V);
2185 pMsiOut->Data.n.u3DeliveryMode = RT_BF_GET(uIrteQword0, VTD_BF_0_IRTE_DLM);
2186 pMsiOut->Data.n.u1Level = 1;
2187 pMsiOut->Data.n.u1TriggerMode = RT_BF_GET(uIrteQword0, VTD_BF_0_IRTE_TM);
2188}
2189
2190
2191/**
2192 * Handles remapping of interrupts in remappable interrupt format.
2193 *
2194 * @returns VBox status code.
2195 * @param pDevIns The IOMMU device instance.
2196 * @param uIrtaReg The IRTA_REG.
2197 * @param idDevice The device ID (bus, device, function).
2198 * @param pMsiIn The source MSI.
2199 * @param pMsiOut Where to store the remapped MSI.
2200 */
2201static int dmarIrRemapIntr(PPDMDEVINS pDevIns, uint64_t uIrtaReg, uint16_t idDevice, PCMSIMSG pMsiIn, PMSIMSG pMsiOut)
2202{
2203 Assert(pMsiIn->Addr.dmar_remap.fIntrFormat == VTD_INTR_FORMAT_REMAPPABLE);
2204
2205 /* Validate reserved bits in the interrupt request. */
2206 AssertCompile(VTD_REMAPPABLE_MSI_ADDR_VALID_MASK == UINT32_MAX);
2207 if (!(pMsiIn->Data.u32 & ~VTD_REMAPPABLE_MSI_DATA_VALID_MASK))
2208 {
2209 /* Compute the index into the interrupt remap table. */
2210 uint16_t const uHandleHi = RT_BF_GET(pMsiIn->Addr.au32[0], VTD_BF_REMAPPABLE_MSI_ADDR_HANDLE_HI);
2211 uint16_t const uHandleLo = RT_BF_GET(pMsiIn->Addr.au32[0], VTD_BF_REMAPPABLE_MSI_ADDR_HANDLE_LO);
2212 uint16_t const uHandle = uHandleLo | (uHandleHi << 15);
2213 bool const fSubHandleValid = RT_BF_GET(pMsiIn->Addr.au32[0], VTD_BF_REMAPPABLE_MSI_ADDR_SHV);
2214 uint16_t const idxIntr = fSubHandleValid
2215 ? uHandle + RT_BF_GET(pMsiIn->Data.u32, VTD_BF_REMAPPABLE_MSI_DATA_SUBHANDLE)
2216 : uHandle;
2217
2218 /* Validate the index. */
2219 uint32_t const cEntries = VTD_IRTA_REG_GET_ENTRY_COUNT(uIrtaReg);
2220 if (idxIntr < cEntries)
2221 {
2222 /** @todo Implement and read IRTE from interrupt-entry cache here. */
2223
2224 /* Read the interrupt remap table entry (IRTE) at the index. */
2225 VTD_IRTE_T Irte;
2226 int rc = dmarIrReadIrte(pDevIns, uIrtaReg, idxIntr, &Irte);
2227 if (RT_SUCCESS(rc))
2228 {
2229 /* Check if the IRTE is present (this must be done -before- checking reserved bits). */
2230 uint64_t const uIrteQword0 = Irte.au64[0];
2231 uint64_t const uIrteQword1 = Irte.au64[1];
2232 bool const fPresent = RT_BF_GET(uIrteQword0, VTD_BF_0_IRTE_P);
2233 if (fPresent)
2234 {
2235 /* Validate reserved bits in the IRTE. */
2236 bool const fExtIntrMode = RT_BF_GET(uIrtaReg, VTD_BF_IRTA_REG_EIME);
2237 uint64_t const fQw0ValidMask = fExtIntrMode ? VTD_IRTE_0_X2APIC_VALID_MASK : VTD_IRTE_0_XAPIC_VALID_MASK;
2238 if ( !(uIrteQword0 & ~fQw0ValidMask)
2239 && !(uIrteQword1 & ~VTD_IRTE_1_VALID_MASK))
2240 {
2241 /* Validate requester id (the device ID) as configured in the IRTE. */
2242 bool fSrcValid;
2243 DMARDIAG enmIrDiag;
2244 uint8_t const fSvt = RT_BF_GET(uIrteQword1, VTD_BF_1_IRTE_SVT);
2245 switch (fSvt)
2246 {
2247 case VTD_IRTE_SVT_NONE:
2248 {
2249 fSrcValid = true;
2250 enmIrDiag = kDmarDiag_None;
2251 break;
2252 }
2253
2254 case VTD_IRTE_SVT_VALIDATE_MASK:
2255 {
2256 static uint16_t const s_afValidMasks[] = { 0xffff, 0xfffb, 0xfff9, 0xfff8 };
2257 uint8_t const idxMask = RT_BF_GET(uIrteQword1, VTD_BF_1_IRTE_SQ) & 3;
2258 uint16_t const fValidMask = s_afValidMasks[idxMask];
2259 uint16_t const idSource = RT_BF_GET(uIrteQword1, VTD_BF_1_IRTE_SID);
2260 fSrcValid = (idDevice & fValidMask) == (idSource & fValidMask);
2261 enmIrDiag = kDmarDiag_Ir_Rfi_Irte_Svt_Masked;
2262 break;
2263 }
2264
2265 case VTD_IRTE_SVT_VALIDATE_BUS_RANGE:
2266 {
2267 uint16_t const idSource = RT_BF_GET(uIrteQword1, VTD_BF_1_IRTE_SID);
2268 uint8_t const uBusFirst = RT_HI_U8(idSource);
2269 uint8_t const uBusLast = RT_LO_U8(idSource);
2270 uint8_t const idDeviceBus = idDevice >> VBOX_PCI_BUS_SHIFT;
2271 fSrcValid = (idDeviceBus >= uBusFirst && idDeviceBus <= uBusLast);
2272 enmIrDiag = kDmarDiag_Ir_Rfi_Irte_Svt_Bus;
2273 break;
2274 }
2275
2276 default:
2277 {
2278 fSrcValid = false;
2279 enmIrDiag = kDmarDiag_Ir_Rfi_Irte_Svt_Bus;
2280 break;
2281 }
2282 }
2283
2284 if (fSrcValid)
2285 {
2286 uint8_t const fPostedMode = RT_BF_GET(uIrteQword0, VTD_BF_0_IRTE_IM);
2287 if (!fPostedMode)
2288 {
2289 dmarIrRemapFromIrte(fExtIntrMode, &Irte, pMsiIn, pMsiOut);
2290 return VINF_SUCCESS;
2291 }
2292 dmarIrFaultRecordQualified(pDevIns, kDmarDiag_Ir_Rfi_Irte_Mode_Invalid,
2293 VTDIRFAULT_IRTE_PRESENT_RSVD, idDevice, idxIntr, &Irte);
2294 }
2295 else
2296 dmarIrFaultRecordQualified(pDevIns, enmIrDiag, VTDIRFAULT_IRTE_PRESENT_RSVD, idDevice, idxIntr,
2297 &Irte);
2298 }
2299 else
2300 dmarIrFaultRecordQualified(pDevIns, kDmarDiag_Ir_Rfi_Irte_Rsvd, VTDIRFAULT_IRTE_PRESENT_RSVD,
2301 idDevice, idxIntr, &Irte);
2302 }
2303 else
2304 dmarIrFaultRecordQualified(pDevIns, kDmarDiag_Ir_Rfi_Irte_Not_Present, VTDIRFAULT_IRTE_NOT_PRESENT,
2305 idDevice, idxIntr, &Irte);
2306 }
2307 else
2308 dmarIrFaultRecord(pDevIns, kDmarDiag_Ir_Rfi_Irte_Read_Failed, VTDIRFAULT_IRTE_READ_FAILED, idDevice, idxIntr);
2309 }
2310 else
2311 dmarIrFaultRecord(pDevIns, kDmarDiag_Ir_Rfi_Intr_Index_Invalid, VTDIRFAULT_INTR_INDEX_INVALID, idDevice, idxIntr);
2312 }
2313 else
2314 dmarIrFaultRecord(pDevIns, kDmarDiag_Ir_Rfi_Rsvd, VTDIRFAULT_REMAPPABLE_INTR_RSVD, idDevice, 0 /* idxIntr */);
2315 return VERR_IOMMU_INTR_REMAP_DENIED;
2316}
2317
2318
2319/**
2320 * Interrupt remap request from a device.
2321 *
2322 * @returns VBox status code.
2323 * @param pDevIns The IOMMU device instance.
2324 * @param idDevice The device ID (bus, device, function).
2325 * @param pMsiIn The source MSI.
2326 * @param pMsiOut Where to store the remapped MSI.
2327 */
2328static DECLCALLBACK(int) iommuIntelMsiRemap(PPDMDEVINS pDevIns, uint16_t idDevice, PCMSIMSG pMsiIn, PMSIMSG pMsiOut)
2329{
2330 /* Validate. */
2331 Assert(pDevIns);
2332 Assert(pMsiIn);
2333 Assert(pMsiOut);
2334 RT_NOREF1(idDevice);
2335
2336 PDMAR pThis = PDMDEVINS_2_DATA(pDevIns, PDMAR);
2337 PCDMARCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PCDMARCC);
2338
2339 /* Lock and read all registers required for interrupt remapping up-front. */
2340 DMAR_LOCK(pDevIns, pThisCC);
2341 uint32_t const uGstsReg = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_GSTS_REG);
2342 uint64_t const uIrtaReg = pThis->uIrtaReg;
2343 DMAR_UNLOCK(pDevIns, pThisCC);
2344
2345 /* Check if interrupt remapping is enabled. */
2346 if (uGstsReg & VTD_BF_GSTS_REG_IRES_MASK)
2347 {
2348 bool const fIsRemappable = RT_BF_GET(pMsiIn->Addr.au32[0], VTD_BF_REMAPPABLE_MSI_ADDR_INTR_FMT);
2349 if (!fIsRemappable)
2350 {
2351 /* Handle compatibility format interrupts. */
2352 STAM_COUNTER_INC(&pThis->CTX_SUFF_Z(StatMsiRemapCfi));
2353
2354 /* If EIME is enabled or CFIs are disabled, block the interrupt. */
2355 if ( (uIrtaReg & VTD_BF_IRTA_REG_EIME_MASK)
2356 || !(uGstsReg & VTD_BF_GSTS_REG_CFIS_MASK))
2357 {
2358 dmarIrFaultRecord(pDevIns, kDmarDiag_Ir_Cfi_Blocked, VTDIRFAULT_CFI_BLOCKED, idDevice, 0 /* idxIntr */);
2359 return VERR_IOMMU_INTR_REMAP_DENIED;
2360 }
2361
2362 /* Interrupt isn't subject to remapping, pass-through the interrupt. */
2363 *pMsiOut = *pMsiIn;
2364 return VINF_SUCCESS;
2365 }
2366
2367 /* Handle remappable format interrupts. */
2368 STAM_COUNTER_INC(&pThis->CTX_SUFF_Z(StatMsiRemapRfi));
2369 return dmarIrRemapIntr(pDevIns, uIrtaReg, idDevice, pMsiIn, pMsiOut);
2370 }
2371
2372 /* Interrupt-remapping isn't enabled, all interrupts are pass-through. */
2373 *pMsiOut = *pMsiIn;
2374 return VINF_SUCCESS;
2375}
2376
2377
2378/**
2379 * @callback_method_impl{FNIOMMMIONEWWRITE}
2380 */
2381static DECLCALLBACK(VBOXSTRICTRC) dmarMmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
2382{
2383 RT_NOREF1(pvUser);
2384 DMAR_ASSERT_MMIO_ACCESS_RET(off, cb);
2385
2386 PDMAR pThis = PDMDEVINS_2_DATA(pDevIns, PDMAR);
2387 STAM_COUNTER_INC(&pThis->CTX_SUFF_Z(StatMmioWrite));
2388
2389 uint16_t const offReg = off;
2390 uint16_t const offLast = offReg + cb - 1;
2391 if (DMAR_IS_MMIO_OFF_VALID(offLast))
2392 {
2393 PCDMARCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PCDMARCC);
2394 DMAR_LOCK_RET(pDevIns, pThisCC, VINF_IOM_R3_MMIO_WRITE);
2395
2396 uint64_t uPrev = 0;
2397 uint64_t const uRegWritten = cb == 8 ? dmarRegWrite64(pThis, offReg, *(uint64_t *)pv, &uPrev)
2398 : dmarRegWrite32(pThis, offReg, *(uint32_t *)pv, (uint32_t *)&uPrev);
2399 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
2400 switch (off)
2401 {
2402 case VTD_MMIO_OFF_GCMD_REG: /* 32-bit */
2403 {
2404 rcStrict = dmarGcmdRegWrite(pDevIns, uRegWritten);
2405 break;
2406 }
2407
2408 case VTD_MMIO_OFF_CCMD_REG: /* 64-bit */
2409 case VTD_MMIO_OFF_CCMD_REG + 4:
2410 {
2411 rcStrict = dmarCcmdRegWrite(pDevIns, offReg, cb, uRegWritten);
2412 break;
2413 }
2414
2415 case VTD_MMIO_OFF_FSTS_REG: /* 32-bit */
2416 {
2417 rcStrict = dmarFstsRegWrite(pDevIns, uRegWritten, uPrev);
2418 break;
2419 }
2420
2421 case VTD_MMIO_OFF_FECTL_REG: /* 32-bit */
2422 {
2423 rcStrict = dmarFectlRegWrite(pDevIns, uRegWritten);
2424 break;
2425 }
2426
2427 case VTD_MMIO_OFF_IQT_REG: /* 64-bit */
2428 /* VTD_MMIO_OFF_IQT_REG + 4: */ /* High 32-bits reserved. */
2429 {
2430 rcStrict = dmarIqtRegWrite(pDevIns, offReg, uRegWritten);
2431 break;
2432 }
2433
2434 case VTD_MMIO_OFF_IQA_REG: /* 64-bit */
2435 /* VTD_MMIO_OFF_IQA_REG + 4: */ /* High 32-bits data. */
2436 {
2437 rcStrict = dmarIqaRegWrite(pDevIns, offReg, uRegWritten);
2438 break;
2439 }
2440
2441 case VTD_MMIO_OFF_ICS_REG: /* 32-bit */
2442 {
2443 rcStrict = dmarIcsRegWrite(pDevIns, uRegWritten);
2444 break;
2445 }
2446
2447 case VTD_MMIO_OFF_IECTL_REG: /* 32-bit */
2448 {
2449 rcStrict = dmarIectlRegWrite(pDevIns, uRegWritten);
2450 break;
2451 }
2452
2453 case DMAR_MMIO_OFF_FRCD_HI_REG: /* 64-bit */
2454 case DMAR_MMIO_OFF_FRCD_HI_REG + 4:
2455 {
2456 rcStrict = dmarFrcdHiRegWrite(pDevIns, offReg, cb, uRegWritten, uPrev);
2457 break;
2458 }
2459 }
2460
2461 DMAR_UNLOCK(pDevIns, pThisCC);
2462 LogFlowFunc(("offReg=%#x uRegWritten=%#RX64 rc=%Rrc\n", offReg, uRegWritten, VBOXSTRICTRC_VAL(rcStrict)));
2463 return rcStrict;
2464 }
2465
2466 return VINF_IOM_MMIO_UNUSED_FF;
2467}
2468
2469
2470/**
2471 * @callback_method_impl{FNIOMMMIONEWREAD}
2472 */
2473static DECLCALLBACK(VBOXSTRICTRC) dmarMmioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
2474{
2475 RT_NOREF1(pvUser);
2476 DMAR_ASSERT_MMIO_ACCESS_RET(off, cb);
2477
2478 PDMAR pThis = PDMDEVINS_2_DATA(pDevIns, PDMAR);
2479 STAM_COUNTER_INC(&pThis->CTX_SUFF_Z(StatMmioRead));
2480
2481 uint16_t const offReg = off;
2482 uint16_t const offLast = offReg + cb - 1;
2483 if (DMAR_IS_MMIO_OFF_VALID(offLast))
2484 {
2485 PCDMARCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PCDMARCC);
2486 DMAR_LOCK_RET(pDevIns, pThisCC, VINF_IOM_R3_MMIO_READ);
2487
2488 if (cb == 8)
2489 {
2490 *(uint64_t *)pv = dmarRegRead64(pThis, offReg);
2491 LogFlowFunc(("offReg=%#x pv=%#RX64\n", offReg, *(uint64_t *)pv));
2492 }
2493 else
2494 {
2495 *(uint32_t *)pv = dmarRegRead32(pThis, offReg);
2496 LogFlowFunc(("offReg=%#x pv=%#RX32\n", offReg, *(uint32_t *)pv));
2497 }
2498
2499 DMAR_UNLOCK(pDevIns, pThisCC);
2500 return VINF_SUCCESS;
2501 }
2502
2503 return VINF_IOM_MMIO_UNUSED_FF;
2504}
2505
2506
2507#ifdef IN_RING3
2508/**
2509 * Process requests in the invalidation queue.
2510 *
2511 * @param pDevIns The IOMMU device instance.
2512 * @param pvRequests The requests to process.
2513 * @param cbRequests The size of all requests (in bytes).
2514 * @param fDw The descriptor width (VTD_IQA_REG_DW_128_BIT or
2515 * VTD_IQA_REG_DW_256_BIT).
2516 * @param fTtm The table translation mode. Must not be VTD_TTM_RSVD.
2517 */
2518static void dmarR3InvQueueProcessRequests(PPDMDEVINS pDevIns, void const *pvRequests, uint32_t cbRequests, uint8_t fDw,
2519 uint8_t fTtm)
2520{
2521#define DMAR_IQE_FAULT_RECORD_RET(a_enmDiag, a_enmIqei) \
2522 do \
2523 { \
2524 dmarIqeFaultRecord(pDevIns, (a_enmDiag), (a_enmIqei)); \
2525 return; \
2526 } while (0)
2527
2528 PDMAR pThis = PDMDEVINS_2_DATA(pDevIns, PDMAR);
2529 PCDMARR3 pThisR3 = PDMDEVINS_2_DATA_CC(pDevIns, PCDMARR3);
2530
2531 DMAR_ASSERT_LOCK_IS_NOT_OWNER(pDevIns, pThisR3);
2532 Assert(fTtm != VTD_TTM_RSVD); /* Should've beeen handled by caller. */
2533
2534 /*
2535 * The below check is redundant since we check both TTM and DW for each
2536 * descriptor type we process. However, the error reported by hardware
2537 * may differ hence this is kept commented out but not removed from the code
2538 * if we need to change this in the future.
2539 *
2540 * In our implementation, we would report the descriptor type as invalid,
2541 * while on real hardware it may report descriptor width as invalid.
2542 * The Intel VT-d spec. is not clear which error takes preceedence.
2543 */
2544#if 0
2545 /*
2546 * Verify that 128-bit descriptors are not used when operating in scalable mode.
2547 * We don't check this while software writes IQA_REG but defer it until now because
2548 * RTADDR_REG can be updated lazily (via GCMD_REG.SRTP). The 256-bit descriptor check
2549 * -IS- performed when software writes IQA_REG since it only requires checking against
2550 * immutable hardware features.
2551 */
2552 if ( fTtm != VTD_TTM_SCALABLE_MODE
2553 || fDw != VTD_IQA_REG_DW_128_BIT)
2554 { /* likely */ }
2555 else
2556 DMAR_IQE_FAULT_RECORD_RET(kDmarDiag_IqaReg_Dw_128_Invalid, VTDIQEI_INVALID_DESCRIPTOR_WIDTH);
2557#endif
2558
2559 /*
2560 * Process requests in FIFO order.
2561 */
2562 uint8_t const cbDsc = fDw == VTD_IQA_REG_DW_256_BIT ? 32 : 16;
2563 for (uint32_t offDsc = 0; offDsc < cbRequests; offDsc += cbDsc)
2564 {
2565 uint64_t const *puDscQwords = (uint64_t const *)((uintptr_t)pvRequests + offDsc);
2566 uint64_t const uQword0 = puDscQwords[0];
2567 uint64_t const uQword1 = puDscQwords[1];
2568 uint8_t const fDscType = VTD_GENERIC_INV_DSC_GET_TYPE(uQword0);
2569 switch (fDscType)
2570 {
2571 case VTD_INV_WAIT_DSC_TYPE:
2572 {
2573 /* Validate descriptor type. */
2574 if ( fTtm == VTD_TTM_LEGACY_MODE
2575 || fDw == VTD_IQA_REG_DW_256_BIT)
2576 { /* likely */ }
2577 else
2578 DMAR_IQE_FAULT_RECORD_RET(kDmarDiag_Iqei_Inv_Wait_Dsc_Invalid, VTDIQEI_INVALID_DESCRIPTOR_TYPE);
2579
2580 /* Validate reserved bits. */
2581 uint64_t const fValidMask0 = !(pThis->fExtCapReg & VTD_BF_ECAP_REG_PDS_MASK)
2582 ? VTD_INV_WAIT_DSC_0_VALID_MASK & ~VTD_BF_0_INV_WAIT_DSC_PD_MASK
2583 : VTD_INV_WAIT_DSC_0_VALID_MASK;
2584 if ( !(uQword0 & ~fValidMask0)
2585 && !(uQword1 & ~VTD_INV_WAIT_DSC_1_VALID_MASK))
2586 { /* likely */ }
2587 else
2588 DMAR_IQE_FAULT_RECORD_RET(kDmarDiag_Iqei_Inv_Wait_Dsc_0_1_Rsvd, VTDIQEI_RSVD_FIELD_VIOLATION);
2589
2590 if (fDw == VTD_IQA_REG_DW_256_BIT)
2591 {
2592 if ( !puDscQwords[2]
2593 && !puDscQwords[3])
2594 { /* likely */ }
2595 else
2596 DMAR_IQE_FAULT_RECORD_RET(kDmarDiag_Iqei_Inv_Wait_Dsc_2_3_Rsvd, VTDIQEI_RSVD_FIELD_VIOLATION);
2597 }
2598
2599 /* Perform status write (this must be done prior to generating the completion interrupt). */
2600 bool const fSw = RT_BF_GET(uQword0, VTD_BF_0_INV_WAIT_DSC_SW);
2601 if (fSw)
2602 {
2603 uint32_t const uStatus = RT_BF_GET(uQword0, VTD_BF_0_INV_WAIT_DSC_STDATA);
2604 RTGCPHYS const GCPhysStatus = uQword1 & VTD_BF_1_INV_WAIT_DSC_STADDR_MASK;
2605 int const rc = PDMDevHlpPhysWrite(pDevIns, GCPhysStatus, (void const*)&uStatus, sizeof(uStatus));
2606 AssertRC(rc);
2607 }
2608
2609 /* Generate invalidation event interrupt. */
2610 bool const fIf = RT_BF_GET(uQword0, VTD_BF_0_INV_WAIT_DSC_IF);
2611 if (fIf)
2612 {
2613 DMAR_LOCK(pDevIns, pThisR3);
2614 dmarR3InvEventRaiseInterrupt(pDevIns);
2615 DMAR_UNLOCK(pDevIns, pThisR3);
2616 }
2617
2618 STAM_COUNTER_INC(&pThis->StatInvWaitDsc);
2619 break;
2620 }
2621
2622 case VTD_CC_INV_DSC_TYPE: STAM_COUNTER_INC(&pThis->StatCcInvDsc); break;
2623 case VTD_IOTLB_INV_DSC_TYPE: STAM_COUNTER_INC(&pThis->StatIotlbInvDsc); break;
2624 case VTD_DEV_TLB_INV_DSC_TYPE: STAM_COUNTER_INC(&pThis->StatDevtlbInvDsc); break;
2625 case VTD_IEC_INV_DSC_TYPE: STAM_COUNTER_INC(&pThis->StatIecInvDsc); break;
2626 case VTD_P_IOTLB_INV_DSC_TYPE: STAM_COUNTER_INC(&pThis->StatPasidIotlbInvDsc); break;
2627 case VTD_PC_INV_DSC_TYPE: STAM_COUNTER_INC(&pThis->StatPasidCacheInvDsc); break;
2628 case VTD_P_DEV_TLB_INV_DSC_TYPE: STAM_COUNTER_INC(&pThis->StatPasidDevtlbInvDsc); break;
2629 default:
2630 {
2631 /* Stop processing further requests. */
2632 LogFunc(("Invalid descriptor type: %#x\n", fDscType));
2633 DMAR_IQE_FAULT_RECORD_RET(kDmarDiag_Iqei_Dsc_Type_Invalid, VTDIQEI_INVALID_DESCRIPTOR_TYPE);
2634 }
2635 }
2636 }
2637#undef DMAR_IQE_FAULT_RECORD_RET
2638}
2639
2640
2641/**
2642 * The invalidation-queue thread.
2643 *
2644 * @returns VBox status code.
2645 * @param pDevIns The IOMMU device instance.
2646 * @param pThread The command thread.
2647 */
2648static DECLCALLBACK(int) dmarR3InvQueueThread(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
2649{
2650 NOREF(pThread);
2651 LogFlowFunc(("\n"));
2652
2653 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
2654 return VINF_SUCCESS;
2655
2656 /*
2657 * Pre-allocate the maximum size of the invalidation queue allowed by the spec.
2658 * This prevents trashing the heap as well as deal with out-of-memory situations
2659 * up-front while starting the VM. It also simplifies the code from having to
2660 * dynamically grow/shrink the allocation based on how software sizes the queue.
2661 * Guests normally don't alter the queue size all the time, but that's not an
2662 * assumption we can make.
2663 */
2664 uint8_t const cMaxPages = 1 << VTD_BF_IQA_REG_QS_MASK;
2665 size_t const cbMaxQs = cMaxPages << X86_PAGE_SHIFT;
2666 void *pvRequests = RTMemAllocZ(cbMaxQs);
2667 AssertPtrReturn(pvRequests, VERR_NO_MEMORY);
2668
2669 PDMAR pThis = PDMDEVINS_2_DATA(pDevIns, PDMAR);
2670 PCDMARR3 pThisR3 = PDMDEVINS_2_DATA_CC(pDevIns, PCDMARR3);
2671
2672 while (pThread->enmState == PDMTHREADSTATE_RUNNING)
2673 {
2674 /*
2675 * Sleep until we are woken up.
2676 */
2677 {
2678 int const rc = PDMDevHlpSUPSemEventWaitNoResume(pDevIns, pThis->hEvtInvQueue, RT_INDEFINITE_WAIT);
2679 AssertLogRelMsgReturn(RT_SUCCESS(rc) || rc == VERR_INTERRUPTED, ("%Rrc\n", rc), rc);
2680 if (RT_UNLIKELY(pThread->enmState != PDMTHREADSTATE_RUNNING))
2681 break;
2682 }
2683
2684 DMAR_LOCK(pDevIns, pThisR3);
2685 if (dmarInvQueueCanProcessRequests(pThis))
2686 {
2687 uint32_t offQueueHead;
2688 uint32_t offQueueTail;
2689 bool const fIsEmpty = dmarInvQueueIsEmptyEx(pThis, &offQueueHead, &offQueueTail);
2690 if (!fIsEmpty)
2691 {
2692 /*
2693 * Get the current queue size, descriptor width, queue base address and the
2694 * table translation mode while the lock is still held.
2695 */
2696 uint64_t const uIqaReg = dmarRegReadRaw64(pThis, VTD_MMIO_OFF_IQA_REG);
2697 uint8_t const cQueuePages = 1 << (uIqaReg & VTD_BF_IQA_REG_QS_MASK);
2698 uint32_t const cbQueue = cQueuePages << X86_PAGE_SHIFT;
2699 uint8_t const fDw = RT_BF_GET(uIqaReg, VTD_BF_IQA_REG_DW);
2700 uint8_t const fTtm = RT_BF_GET(pThis->uRtaddrReg, VTD_BF_RTADDR_REG_TTM);
2701 RTGCPHYS const GCPhysRequests = (uIqaReg & VTD_BF_IQA_REG_IQA_MASK) + offQueueHead;
2702
2703 /* Paranoia. */
2704 Assert(cbQueue <= cbMaxQs);
2705 Assert(!(offQueueTail & ~VTD_BF_IQT_REG_QT_MASK));
2706 Assert(!(offQueueHead & ~VTD_BF_IQH_REG_QH_MASK));
2707 Assert(fDw != VTD_IQA_REG_DW_256_BIT || !(offQueueTail & RT_BIT(4)));
2708 Assert(fDw != VTD_IQA_REG_DW_256_BIT || !(offQueueHead & RT_BIT(4)));
2709 Assert(offQueueHead < cbQueue);
2710
2711 /*
2712 * A table translation mode of "reserved" isn't valid for any descriptor type.
2713 * However, RTADDR_REG can be modified in parallel to invalidation-queue processing,
2714 * but if ESRTPS is support, we will perform a global invalidation when software
2715 * changes RTADDR_REG, or it's the responsibility of software to do it explicitly.
2716 * So caching TTM while reading all descriptors should not be a problem.
2717 *
2718 * Also, validate the queue tail offset as it's mutable by software.
2719 */
2720 if ( fTtm != VTD_TTM_RSVD
2721 && offQueueTail < cbQueue)
2722 {
2723 /* Don't hold the lock while reading (a potentially large amount of) requests */
2724 DMAR_UNLOCK(pDevIns, pThisR3);
2725
2726 int rc;
2727 uint32_t cbRequests;
2728 if (offQueueTail > offQueueHead)
2729 {
2730 /* The requests have not wrapped around, read them in one go. */
2731 cbRequests = offQueueTail - offQueueHead;
2732 rc = PDMDevHlpPhysReadMeta(pDevIns, GCPhysRequests, pvRequests, cbRequests);
2733 }
2734 else
2735 {
2736 /* The requests have wrapped around, read forward and wrapped-around. */
2737 uint32_t const cbForward = cbQueue - offQueueHead;
2738 rc = PDMDevHlpPhysReadMeta(pDevIns, GCPhysRequests, pvRequests, cbForward);
2739
2740 uint32_t const cbWrapped = offQueueTail;
2741 if ( RT_SUCCESS(rc)
2742 && cbWrapped > 0)
2743 {
2744 rc = PDMDevHlpPhysReadMeta(pDevIns, GCPhysRequests + cbForward,
2745 (void *)((uintptr_t)pvRequests + cbForward), cbWrapped);
2746 }
2747 cbRequests = cbForward + cbWrapped;
2748 }
2749
2750 /* Re-acquire the lock since we need to update device state. */
2751 DMAR_LOCK(pDevIns, pThisR3);
2752
2753 if (RT_SUCCESS(rc))
2754 {
2755 /* Indicate to software we've fetched all requests. */
2756 dmarRegWriteRaw64(pThis, VTD_MMIO_OFF_IQH_REG, offQueueTail);
2757
2758 /* Don't hold the lock while processing requests. */
2759 DMAR_UNLOCK(pDevIns, pThisR3);
2760
2761 /* Process all requests. */
2762 Assert(cbRequests <= cbQueue);
2763 dmarR3InvQueueProcessRequests(pDevIns, pvRequests, cbRequests, fDw, fTtm);
2764
2765 /*
2766 * We've processed all requests and the lock shouldn't be held at this point.
2767 * Using 'continue' here allows us to skip re-acquiring the lock just to release
2768 * it again before going back to the thread loop. It's a bit ugly but it certainly
2769 * helps with performance.
2770 */
2771 DMAR_ASSERT_LOCK_IS_NOT_OWNER(pDevIns, pThisR3);
2772 continue;
2773 }
2774 else
2775 dmarIqeFaultRecord(pDevIns, kDmarDiag_IqaReg_Dsc_Fetch_Error, VTDIQEI_FETCH_DESCRIPTOR_ERR);
2776 }
2777 else
2778 {
2779 if (fTtm == VTD_TTM_RSVD)
2780 dmarIqeFaultRecord(pDevIns, kDmarDiag_Iqei_Ttm_Rsvd, VTDIQEI_INVALID_TTM);
2781 else
2782 {
2783 Assert(offQueueTail >= cbQueue);
2784 dmarIqeFaultRecord(pDevIns, kDmarDiag_IqtReg_Qt_Invalid, VTDIQEI_INVALID_TAIL_PTR);
2785 }
2786 }
2787 }
2788 }
2789 DMAR_UNLOCK(pDevIns, pThisR3);
2790 }
2791
2792 RTMemFree(pvRequests);
2793 pvRequests = NULL;
2794
2795 LogFlowFunc(("Invalidation-queue thread terminating\n"));
2796 return VINF_SUCCESS;
2797}
2798
2799
2800/**
2801 * Wakes up the invalidation-queue thread so it can respond to a state
2802 * change.
2803 *
2804 * @returns VBox status code.
2805 * @param pDevIns The IOMMU device instance.
2806 * @param pThread The invalidation-queue thread.
2807 *
2808 * @thread EMT.
2809 */
2810static DECLCALLBACK(int) dmarR3InvQueueThreadWakeUp(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
2811{
2812 RT_NOREF(pThread);
2813 LogFlowFunc(("\n"));
2814 PCDMAR pThis = PDMDEVINS_2_DATA(pDevIns, PDMAR);
2815 return PDMDevHlpSUPSemEventSignal(pDevIns, pThis->hEvtInvQueue);
2816}
2817
2818
2819/**
2820 * @callback_method_impl{FNDBGFHANDLERDEV}
2821 */
2822static DECLCALLBACK(void) dmarR3DbgInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
2823{
2824 PCDMAR pThis = PDMDEVINS_2_DATA(pDevIns, PDMAR);
2825 PCDMARR3 pThisR3 = PDMDEVINS_2_DATA_CC(pDevIns, PCDMARR3);
2826 bool const fVerbose = RTStrCmp(pszArgs, "verbose") == 0;
2827
2828 /*
2829 * We lock the device to get a consistent register state as it is
2830 * ASSUMED pHlp->pfnPrintf is expensive, so we copy the registers (the
2831 * ones we care about here) into temporaries and release the lock ASAP.
2832 *
2833 * Order of register being read and outputted is in accordance with the
2834 * spec. for no particular reason.
2835 * See Intel VT-d spec. 10.4 "Register Descriptions".
2836 */
2837 DMAR_LOCK(pDevIns, pThisR3);
2838
2839 DMARDIAG const enmDiag = pThis->enmDiag;
2840 uint32_t const uVerReg = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_VER_REG);
2841 uint64_t const uCapReg = dmarRegReadRaw64(pThis, VTD_MMIO_OFF_CAP_REG);
2842 uint64_t const uEcapReg = dmarRegReadRaw64(pThis, VTD_MMIO_OFF_ECAP_REG);
2843 uint32_t const uGcmdReg = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_GCMD_REG);
2844 uint32_t const uGstsReg = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_GSTS_REG);
2845 uint64_t const uRtaddrReg = dmarRegReadRaw64(pThis, VTD_MMIO_OFF_RTADDR_REG);
2846 uint64_t const uCcmdReg = dmarRegReadRaw64(pThis, VTD_MMIO_OFF_CCMD_REG);
2847 uint32_t const uFstsReg = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_FSTS_REG);
2848 uint32_t const uFectlReg = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_FECTL_REG);
2849 uint32_t const uFedataReg = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_FEDATA_REG);
2850 uint32_t const uFeaddrReg = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_FEADDR_REG);
2851 uint32_t const uFeuaddrReg = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_FEUADDR_REG);
2852 uint64_t const uAflogReg = dmarRegReadRaw64(pThis, VTD_MMIO_OFF_AFLOG_REG);
2853 uint32_t const uPmenReg = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_PMEN_REG);
2854 uint32_t const uPlmbaseReg = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_PLMBASE_REG);
2855 uint32_t const uPlmlimitReg = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_PLMLIMIT_REG);
2856 uint64_t const uPhmbaseReg = dmarRegReadRaw64(pThis, VTD_MMIO_OFF_PHMBASE_REG);
2857 uint64_t const uPhmlimitReg = dmarRegReadRaw64(pThis, VTD_MMIO_OFF_PHMLIMIT_REG);
2858 uint64_t const uIqhReg = dmarRegReadRaw64(pThis, VTD_MMIO_OFF_IQH_REG);
2859 uint64_t const uIqtReg = dmarRegReadRaw64(pThis, VTD_MMIO_OFF_IQT_REG);
2860 uint64_t const uIqaReg = dmarRegReadRaw64(pThis, VTD_MMIO_OFF_IQA_REG);
2861 uint32_t const uIcsReg = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_ICS_REG);
2862 uint32_t const uIectlReg = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_IECTL_REG);
2863 uint32_t const uIedataReg = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_IEDATA_REG);
2864 uint32_t const uIeaddrReg = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_IEADDR_REG);
2865 uint32_t const uIeuaddrReg = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_IEUADDR_REG);
2866 uint64_t const uIqercdReg = dmarRegReadRaw64(pThis, VTD_MMIO_OFF_IQERCD_REG);
2867 uint64_t const uIrtaReg = dmarRegReadRaw64(pThis, VTD_MMIO_OFF_IRTA_REG);
2868 uint64_t const uPqhReg = dmarRegReadRaw64(pThis, VTD_MMIO_OFF_PQH_REG);
2869 uint64_t const uPqtReg = dmarRegReadRaw64(pThis, VTD_MMIO_OFF_PQT_REG);
2870 uint64_t const uPqaReg = dmarRegReadRaw64(pThis, VTD_MMIO_OFF_PQA_REG);
2871 uint32_t const uPrsReg = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_PRS_REG);
2872 uint32_t const uPectlReg = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_PECTL_REG);
2873 uint32_t const uPedataReg = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_PEDATA_REG);
2874 uint32_t const uPeaddrReg = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_PEADDR_REG);
2875 uint32_t const uPeuaddrReg = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_PEUADDR_REG);
2876 uint64_t const uMtrrcapReg = dmarRegReadRaw64(pThis, VTD_MMIO_OFF_MTRRCAP_REG);
2877 uint64_t const uMtrrdefReg = dmarRegReadRaw64(pThis, VTD_MMIO_OFF_MTRRDEF_REG);
2878
2879 DMAR_UNLOCK(pDevIns, pThisR3);
2880
2881 const char *const pszDiag = enmDiag < RT_ELEMENTS(g_apszDmarDiagDesc) ? g_apszDmarDiagDesc[enmDiag] : "(Unknown)";
2882 pHlp->pfnPrintf(pHlp, "Intel-IOMMU:\n");
2883 pHlp->pfnPrintf(pHlp, " Diag = %s\n", pszDiag);
2884
2885 /*
2886 * Non-verbose output.
2887 */
2888 if (!fVerbose)
2889 {
2890 pHlp->pfnPrintf(pHlp, " VER_REG = %#RX32\n", uVerReg);
2891 pHlp->pfnPrintf(pHlp, " CAP_REG = %#RX64\n", uCapReg);
2892 pHlp->pfnPrintf(pHlp, " ECAP_REG = %#RX64\n", uEcapReg);
2893 pHlp->pfnPrintf(pHlp, " GCMD_REG = %#RX32\n", uGcmdReg);
2894 pHlp->pfnPrintf(pHlp, " GSTS_REG = %#RX32\n", uGstsReg);
2895 pHlp->pfnPrintf(pHlp, " RTADDR_REG = %#RX64\n", uRtaddrReg);
2896 pHlp->pfnPrintf(pHlp, " CCMD_REG = %#RX64\n", uCcmdReg);
2897 pHlp->pfnPrintf(pHlp, " FSTS_REG = %#RX32\n", uFstsReg);
2898 pHlp->pfnPrintf(pHlp, " FECTL_REG = %#RX32\n", uFectlReg);
2899 pHlp->pfnPrintf(pHlp, " FEDATA_REG = %#RX32\n", uFedataReg);
2900 pHlp->pfnPrintf(pHlp, " FEADDR_REG = %#RX32\n", uFeaddrReg);
2901 pHlp->pfnPrintf(pHlp, " FEUADDR_REG = %#RX32\n", uFeuaddrReg);
2902 pHlp->pfnPrintf(pHlp, " AFLOG_REG = %#RX64\n", uAflogReg);
2903 pHlp->pfnPrintf(pHlp, " PMEN_REG = %#RX32\n", uPmenReg);
2904 pHlp->pfnPrintf(pHlp, " PLMBASE_REG = %#RX32\n", uPlmbaseReg);
2905 pHlp->pfnPrintf(pHlp, " PLMLIMIT_REG = %#RX32\n", uPlmlimitReg);
2906 pHlp->pfnPrintf(pHlp, " PHMBASE_REG = %#RX64\n", uPhmbaseReg);
2907 pHlp->pfnPrintf(pHlp, " PHMLIMIT_REG = %#RX64\n", uPhmlimitReg);
2908 pHlp->pfnPrintf(pHlp, " IQH_REG = %#RX64\n", uIqhReg);
2909 pHlp->pfnPrintf(pHlp, " IQT_REG = %#RX64\n", uIqtReg);
2910 pHlp->pfnPrintf(pHlp, " IQA_REG = %#RX64\n", uIqaReg);
2911 pHlp->pfnPrintf(pHlp, " ICS_REG = %#RX32\n", uIcsReg);
2912 pHlp->pfnPrintf(pHlp, " IECTL_REG = %#RX32\n", uIectlReg);
2913 pHlp->pfnPrintf(pHlp, " IEDATA_REG = %#RX32\n", uIedataReg);
2914 pHlp->pfnPrintf(pHlp, " IEADDR_REG = %#RX32\n", uIeaddrReg);
2915 pHlp->pfnPrintf(pHlp, " IEUADDR_REG = %#RX32\n", uIeuaddrReg);
2916 pHlp->pfnPrintf(pHlp, " IQERCD_REG = %#RX64\n", uIqercdReg);
2917 pHlp->pfnPrintf(pHlp, " IRTA_REG = %#RX64\n", uIrtaReg);
2918 pHlp->pfnPrintf(pHlp, " PQH_REG = %#RX64\n", uPqhReg);
2919 pHlp->pfnPrintf(pHlp, " PQT_REG = %#RX64\n", uPqtReg);
2920 pHlp->pfnPrintf(pHlp, " PQA_REG = %#RX64\n", uPqaReg);
2921 pHlp->pfnPrintf(pHlp, " PRS_REG = %#RX32\n", uPrsReg);
2922 pHlp->pfnPrintf(pHlp, " PECTL_REG = %#RX32\n", uPectlReg);
2923 pHlp->pfnPrintf(pHlp, " PEDATA_REG = %#RX32\n", uPedataReg);
2924 pHlp->pfnPrintf(pHlp, " PEADDR_REG = %#RX32\n", uPeaddrReg);
2925 pHlp->pfnPrintf(pHlp, " PEUADDR_REG = %#RX32\n", uPeuaddrReg);
2926 pHlp->pfnPrintf(pHlp, " MTRRCAP_REG = %#RX64\n", uMtrrcapReg);
2927 pHlp->pfnPrintf(pHlp, " MTRRDEF_REG = %#RX64\n", uMtrrdefReg);
2928 pHlp->pfnPrintf(pHlp, "\n");
2929 return;
2930 }
2931
2932 /*
2933 * Verbose output.
2934 */
2935 pHlp->pfnPrintf(pHlp, " VER_REG = %#RX32\n", uVerReg);
2936 {
2937 pHlp->pfnPrintf(pHlp, " MAJ = %#x\n", RT_BF_GET(uVerReg, VTD_BF_VER_REG_MAX));
2938 pHlp->pfnPrintf(pHlp, " MIN = %#x\n", RT_BF_GET(uVerReg, VTD_BF_VER_REG_MIN));
2939 }
2940 pHlp->pfnPrintf(pHlp, " CAP_REG = %#RX64\n", uCapReg);
2941 {
2942 uint8_t const uMgaw = RT_BF_GET(uCapReg, VTD_BF_CAP_REG_MGAW);
2943 uint8_t const uNfr = RT_BF_GET(uCapReg, VTD_BF_CAP_REG_NFR);
2944 pHlp->pfnPrintf(pHlp, " ND = %u\n", RT_BF_GET(uCapReg, VTD_BF_CAP_REG_ND));
2945 pHlp->pfnPrintf(pHlp, " AFL = %RTbool\n", RT_BF_GET(uCapReg, VTD_BF_CAP_REG_AFL));
2946 pHlp->pfnPrintf(pHlp, " RWBF = %RTbool\n", RT_BF_GET(uCapReg, VTD_BF_CAP_REG_RWBF));
2947 pHlp->pfnPrintf(pHlp, " PLMR = %RTbool\n", RT_BF_GET(uCapReg, VTD_BF_CAP_REG_PLMR));
2948 pHlp->pfnPrintf(pHlp, " PHMR = %RTbool\n", RT_BF_GET(uCapReg, VTD_BF_CAP_REG_PHMR));
2949 pHlp->pfnPrintf(pHlp, " CM = %RTbool\n", RT_BF_GET(uCapReg, VTD_BF_CAP_REG_CM));
2950 pHlp->pfnPrintf(pHlp, " SAGAW = %#x\n", RT_BF_GET(uCapReg, VTD_BF_CAP_REG_SAGAW));
2951 pHlp->pfnPrintf(pHlp, " MGAW = %#x (%u bits)\n", uMgaw, uMgaw + 1);
2952 pHlp->pfnPrintf(pHlp, " ZLR = %RTbool\n", RT_BF_GET(uCapReg, VTD_BF_CAP_REG_ZLR));
2953 pHlp->pfnPrintf(pHlp, " FRO = %#x bytes\n", RT_BF_GET(uCapReg, VTD_BF_CAP_REG_FRO));
2954 pHlp->pfnPrintf(pHlp, " SLLPS = %#x\n", RT_BF_GET(uCapReg, VTD_BF_CAP_REG_SLLPS));
2955 pHlp->pfnPrintf(pHlp, " PSI = %RTbool\n", RT_BF_GET(uCapReg, VTD_BF_CAP_REG_PSI));
2956 pHlp->pfnPrintf(pHlp, " NFR = %u (%u FRCD register%s)\n", uNfr, uNfr + 1, uNfr > 0 ? "s" : "");
2957 pHlp->pfnPrintf(pHlp, " MAMV = %#x\n", RT_BF_GET(uCapReg, VTD_BF_CAP_REG_MAMV));
2958 pHlp->pfnPrintf(pHlp, " DWD = %RTbool\n", RT_BF_GET(uCapReg, VTD_BF_CAP_REG_DWD));
2959 pHlp->pfnPrintf(pHlp, " DRD = %RTbool\n", RT_BF_GET(uCapReg, VTD_BF_CAP_REG_DRD));
2960 pHlp->pfnPrintf(pHlp, " FL1GP = %RTbool\n", RT_BF_GET(uCapReg, VTD_BF_CAP_REG_FL1GP));
2961 pHlp->pfnPrintf(pHlp, " PI = %RTbool\n", RT_BF_GET(uCapReg, VTD_BF_CAP_REG_PI));
2962 pHlp->pfnPrintf(pHlp, " FL5LP = %RTbool\n", RT_BF_GET(uCapReg, VTD_BF_CAP_REG_FL5LP));
2963 pHlp->pfnPrintf(pHlp, " ESIRTPS = %RTbool\n", RT_BF_GET(uCapReg, VTD_BF_CAP_REG_ESIRTPS));
2964 pHlp->pfnPrintf(pHlp, " ESRTPS = %RTbool\n", RT_BF_GET(uCapReg, VTD_BF_CAP_REG_ESRTPS));
2965 }
2966 pHlp->pfnPrintf(pHlp, " ECAP_REG = %#RX64\n", uEcapReg);
2967 {
2968 uint8_t const uPss = RT_BF_GET(uEcapReg, VTD_BF_ECAP_REG_PSS);
2969 pHlp->pfnPrintf(pHlp, " C = %RTbool\n", RT_BF_GET(uEcapReg, VTD_BF_ECAP_REG_C));
2970 pHlp->pfnPrintf(pHlp, " QI = %RTbool\n", RT_BF_GET(uEcapReg, VTD_BF_ECAP_REG_QI));
2971 pHlp->pfnPrintf(pHlp, " DT = %RTbool\n", RT_BF_GET(uEcapReg, VTD_BF_ECAP_REG_DT));
2972 pHlp->pfnPrintf(pHlp, " IR = %RTbool\n", RT_BF_GET(uEcapReg, VTD_BF_ECAP_REG_IR));
2973 pHlp->pfnPrintf(pHlp, " EIM = %RTbool\n", RT_BF_GET(uEcapReg, VTD_BF_ECAP_REG_EIM));
2974 pHlp->pfnPrintf(pHlp, " PT = %RTbool\n", RT_BF_GET(uEcapReg, VTD_BF_ECAP_REG_PT));
2975 pHlp->pfnPrintf(pHlp, " SC = %RTbool\n", RT_BF_GET(uEcapReg, VTD_BF_ECAP_REG_SC));
2976 pHlp->pfnPrintf(pHlp, " IRO = %#x bytes\n", RT_BF_GET(uEcapReg, VTD_BF_ECAP_REG_IRO));
2977 pHlp->pfnPrintf(pHlp, " MHMV = %#x\n", RT_BF_GET(uEcapReg, VTD_BF_ECAP_REG_MHMV));
2978 pHlp->pfnPrintf(pHlp, " MTS = %RTbool\n", RT_BF_GET(uEcapReg, VTD_BF_ECAP_REG_MTS));
2979 pHlp->pfnPrintf(pHlp, " NEST = %RTbool\n", RT_BF_GET(uEcapReg, VTD_BF_ECAP_REG_NEST));
2980 pHlp->pfnPrintf(pHlp, " PRS = %RTbool\n", RT_BF_GET(uEcapReg, VTD_BF_ECAP_REG_PRS));
2981 pHlp->pfnPrintf(pHlp, " ERS = %RTbool\n", RT_BF_GET(uEcapReg, VTD_BF_ECAP_REG_ERS));
2982 pHlp->pfnPrintf(pHlp, " SRS = %RTbool\n", RT_BF_GET(uEcapReg, VTD_BF_ECAP_REG_SRS));
2983 pHlp->pfnPrintf(pHlp, " NWFS = %RTbool\n", RT_BF_GET(uEcapReg, VTD_BF_ECAP_REG_NWFS));
2984 pHlp->pfnPrintf(pHlp, " EAFS = %RTbool\n", RT_BF_GET(uEcapReg, VTD_BF_ECAP_REG_EAFS));
2985 pHlp->pfnPrintf(pHlp, " PSS = %u (%u bits)\n", uPss, uPss > 0 ? uPss + 1 : 0);
2986 pHlp->pfnPrintf(pHlp, " PASID = %RTbool\n", RT_BF_GET(uEcapReg, VTD_BF_ECAP_REG_PASID));
2987 pHlp->pfnPrintf(pHlp, " DIT = %RTbool\n", RT_BF_GET(uEcapReg, VTD_BF_ECAP_REG_DIT));
2988 pHlp->pfnPrintf(pHlp, " PDS = %RTbool\n", RT_BF_GET(uEcapReg, VTD_BF_ECAP_REG_PDS));
2989 pHlp->pfnPrintf(pHlp, " SMTS = %RTbool\n", RT_BF_GET(uEcapReg, VTD_BF_ECAP_REG_SMTS));
2990 pHlp->pfnPrintf(pHlp, " VCS = %RTbool\n", RT_BF_GET(uEcapReg, VTD_BF_ECAP_REG_VCS));
2991 pHlp->pfnPrintf(pHlp, " SLADS = %RTbool\n", RT_BF_GET(uEcapReg, VTD_BF_ECAP_REG_SLADS));
2992 pHlp->pfnPrintf(pHlp, " SLTS = %RTbool\n", RT_BF_GET(uEcapReg, VTD_BF_ECAP_REG_SLTS));
2993 pHlp->pfnPrintf(pHlp, " FLTS = %RTbool\n", RT_BF_GET(uEcapReg, VTD_BF_ECAP_REG_FLTS));
2994 pHlp->pfnPrintf(pHlp, " SMPWCS = %RTbool\n", RT_BF_GET(uEcapReg, VTD_BF_ECAP_REG_SMPWCS));
2995 pHlp->pfnPrintf(pHlp, " RPS = %RTbool\n", RT_BF_GET(uEcapReg, VTD_BF_ECAP_REG_RPS));
2996 pHlp->pfnPrintf(pHlp, " ADMS = %RTbool\n", RT_BF_GET(uEcapReg, VTD_BF_ECAP_REG_ADMS));
2997 pHlp->pfnPrintf(pHlp, " RPRIVS = %RTbool\n", RT_BF_GET(uEcapReg, VTD_BF_ECAP_REG_RPRIVS));
2998 }
2999 pHlp->pfnPrintf(pHlp, " GCMD_REG = %#RX32\n", uGcmdReg);
3000 {
3001 uint8_t const fCfi = RT_BF_GET(uGcmdReg, VTD_BF_GCMD_REG_CFI);
3002 pHlp->pfnPrintf(pHlp, " CFI = %u (%s)\n", fCfi, fCfi ? "Passthrough" : "Blocked");
3003 pHlp->pfnPrintf(pHlp, " SIRTP = %u\n", RT_BF_GET(uGcmdReg, VTD_BF_GCMD_REG_SIRTP));
3004 pHlp->pfnPrintf(pHlp, " IRE = %u\n", RT_BF_GET(uGcmdReg, VTD_BF_GCMD_REG_IRE));
3005 pHlp->pfnPrintf(pHlp, " QIE = %u\n", RT_BF_GET(uGcmdReg, VTD_BF_GCMD_REG_QIE));
3006 pHlp->pfnPrintf(pHlp, " WBF = %u\n", RT_BF_GET(uGcmdReg, VTD_BF_GCMD_REG_WBF));
3007 pHlp->pfnPrintf(pHlp, " EAFL = %u\n", RT_BF_GET(uGcmdReg, VTD_BF_GCMD_REG_SFL));
3008 pHlp->pfnPrintf(pHlp, " SFL = %u\n", RT_BF_GET(uGcmdReg, VTD_BF_GCMD_REG_SFL));
3009 pHlp->pfnPrintf(pHlp, " SRTP = %u\n", RT_BF_GET(uGcmdReg, VTD_BF_GCMD_REG_SRTP));
3010 pHlp->pfnPrintf(pHlp, " TE = %u\n", RT_BF_GET(uGcmdReg, VTD_BF_GCMD_REG_TE));
3011 }
3012 pHlp->pfnPrintf(pHlp, " GSTS_REG = %#RX32\n", uGstsReg);
3013 {
3014 uint8_t const fCfis = RT_BF_GET(uGstsReg, VTD_BF_GSTS_REG_CFIS);
3015 pHlp->pfnPrintf(pHlp, " CFIS = %u (%s)\n", fCfis, fCfis ? "Passthrough" : "Blocked");
3016 pHlp->pfnPrintf(pHlp, " IRTPS = %u\n", RT_BF_GET(uGstsReg, VTD_BF_GSTS_REG_IRTPS));
3017 pHlp->pfnPrintf(pHlp, " IRES = %u\n", RT_BF_GET(uGstsReg, VTD_BF_GSTS_REG_IRES));
3018 pHlp->pfnPrintf(pHlp, " QIES = %u\n", RT_BF_GET(uGstsReg, VTD_BF_GSTS_REG_QIES));
3019 pHlp->pfnPrintf(pHlp, " WBFS = %u\n", RT_BF_GET(uGstsReg, VTD_BF_GSTS_REG_WBFS));
3020 pHlp->pfnPrintf(pHlp, " AFLS = %u\n", RT_BF_GET(uGstsReg, VTD_BF_GSTS_REG_AFLS));
3021 pHlp->pfnPrintf(pHlp, " FLS = %u\n", RT_BF_GET(uGstsReg, VTD_BF_GSTS_REG_FLS));
3022 pHlp->pfnPrintf(pHlp, " RTPS = %u\n", RT_BF_GET(uGstsReg, VTD_BF_GSTS_REG_RTPS));
3023 pHlp->pfnPrintf(pHlp, " TES = %u\n", RT_BF_GET(uGstsReg, VTD_BF_GSTS_REG_TES));
3024 }
3025 pHlp->pfnPrintf(pHlp, " RTADDR_REG = %#RX64\n", uRtaddrReg);
3026 {
3027 uint8_t const uTtm = RT_BF_GET(uRtaddrReg, VTD_BF_RTADDR_REG_TTM);
3028 pHlp->pfnPrintf(pHlp, " RTA = %#RX64\n", uRtaddrReg & VTD_BF_RTADDR_REG_RTA_MASK);
3029 pHlp->pfnPrintf(pHlp, " TTM = %u (%s)\n", uTtm, vtdRtaddrRegGetTtmDesc(uTtm));
3030 }
3031 pHlp->pfnPrintf(pHlp, " CCMD_REG = %#RX64\n", uCcmdReg);
3032 pHlp->pfnPrintf(pHlp, " FSTS_REG = %#RX32\n", uFstsReg);
3033 {
3034 pHlp->pfnPrintf(pHlp, " PFO = %u\n", RT_BF_GET(uFstsReg, VTD_BF_FSTS_REG_PFO));
3035 pHlp->pfnPrintf(pHlp, " PPF = %u\n", RT_BF_GET(uFstsReg, VTD_BF_FSTS_REG_PPF));
3036 pHlp->pfnPrintf(pHlp, " AFO = %u\n", RT_BF_GET(uFstsReg, VTD_BF_FSTS_REG_AFO));
3037 pHlp->pfnPrintf(pHlp, " APF = %u\n", RT_BF_GET(uFstsReg, VTD_BF_FSTS_REG_APF));
3038 pHlp->pfnPrintf(pHlp, " IQE = %u\n", RT_BF_GET(uFstsReg, VTD_BF_FSTS_REG_IQE));
3039 pHlp->pfnPrintf(pHlp, " ICS = %u\n", RT_BF_GET(uFstsReg, VTD_BF_FSTS_REG_ICE));
3040 pHlp->pfnPrintf(pHlp, " ITE = %u\n", RT_BF_GET(uFstsReg, VTD_BF_FSTS_REG_ITE));
3041 pHlp->pfnPrintf(pHlp, " FRI = %u\n", RT_BF_GET(uFstsReg, VTD_BF_FSTS_REG_FRI));
3042 }
3043 pHlp->pfnPrintf(pHlp, " FECTL_REG = %#RX32\n", uFectlReg);
3044 {
3045 pHlp->pfnPrintf(pHlp, " IM = %RTbool\n", RT_BF_GET(uFectlReg, VTD_BF_FECTL_REG_IM));
3046 pHlp->pfnPrintf(pHlp, " IP = %RTbool\n", RT_BF_GET(uFectlReg, VTD_BF_FECTL_REG_IP));
3047 }
3048 pHlp->pfnPrintf(pHlp, " FEDATA_REG = %#RX32\n", uFedataReg);
3049 pHlp->pfnPrintf(pHlp, " FEADDR_REG = %#RX32\n", uFeaddrReg);
3050 pHlp->pfnPrintf(pHlp, " FEUADDR_REG = %#RX32\n", uFeuaddrReg);
3051 pHlp->pfnPrintf(pHlp, " AFLOG_REG = %#RX64\n", uAflogReg);
3052 pHlp->pfnPrintf(pHlp, " PMEN_REG = %#RX32\n", uPmenReg);
3053 pHlp->pfnPrintf(pHlp, " PLMBASE_REG = %#RX32\n", uPlmbaseReg);
3054 pHlp->pfnPrintf(pHlp, " PLMLIMIT_REG = %#RX32\n", uPlmlimitReg);
3055 pHlp->pfnPrintf(pHlp, " PHMBASE_REG = %#RX64\n", uPhmbaseReg);
3056 pHlp->pfnPrintf(pHlp, " PHMLIMIT_REG = %#RX64\n", uPhmlimitReg);
3057 pHlp->pfnPrintf(pHlp, " IQH_REG = %#RX64\n", uIqhReg);
3058 pHlp->pfnPrintf(pHlp, " IQT_REG = %#RX64\n", uIqtReg);
3059 pHlp->pfnPrintf(pHlp, " IQA_REG = %#RX64\n", uIqaReg);
3060 {
3061 uint8_t const fDw = RT_BF_GET(uIqaReg, VTD_BF_IQA_REG_DW);
3062 uint8_t const fQs = RT_BF_GET(uIqaReg, VTD_BF_IQA_REG_QS);
3063 uint8_t const cQueuePages = 1 << fQs;
3064 pHlp->pfnPrintf(pHlp, " DW = %u (%s)\n", fDw, fDw == VTD_IQA_REG_DW_128_BIT ? "128-bit" : "256-bit");
3065 pHlp->pfnPrintf(pHlp, " QS = %u (%u page%s)\n", fQs, cQueuePages, cQueuePages > 1 ? "s" : "");
3066 }
3067 pHlp->pfnPrintf(pHlp, " ICS_REG = %#RX32\n", uIcsReg);
3068 {
3069 pHlp->pfnPrintf(pHlp, " IWC = %u\n", RT_BF_GET(uIcsReg, VTD_BF_ICS_REG_IWC));
3070 }
3071 pHlp->pfnPrintf(pHlp, " IECTL_REG = %#RX32\n", uIectlReg);
3072 {
3073 pHlp->pfnPrintf(pHlp, " IM = %RTbool\n", RT_BF_GET(uIectlReg, VTD_BF_IECTL_REG_IM));
3074 pHlp->pfnPrintf(pHlp, " IP = %RTbool\n", RT_BF_GET(uIectlReg, VTD_BF_IECTL_REG_IP));
3075 }
3076 pHlp->pfnPrintf(pHlp, " IEDATA_REG = %#RX32\n", uIedataReg);
3077 pHlp->pfnPrintf(pHlp, " IEADDR_REG = %#RX32\n", uIeaddrReg);
3078 pHlp->pfnPrintf(pHlp, " IEUADDR_REG = %#RX32\n", uIeuaddrReg);
3079 pHlp->pfnPrintf(pHlp, " IQERCD_REG = %#RX64\n", uIqercdReg);
3080 {
3081 pHlp->pfnPrintf(pHlp, " ICESID = %#RX32\n", RT_BF_GET(uIqercdReg, VTD_BF_IQERCD_REG_ICESID));
3082 pHlp->pfnPrintf(pHlp, " ITESID = %#RX32\n", RT_BF_GET(uIqercdReg, VTD_BF_IQERCD_REG_ITESID));
3083 pHlp->pfnPrintf(pHlp, " IQEI = %#RX32\n", RT_BF_GET(uIqercdReg, VTD_BF_IQERCD_REG_IQEI));
3084 }
3085 pHlp->pfnPrintf(pHlp, " IRTA_REG = %#RX64\n", uIrtaReg);
3086 {
3087 uint32_t const cIrtEntries = VTD_IRTA_REG_GET_ENTRY_COUNT(uIrtaReg);
3088 uint32_t const cbIrt = sizeof(VTD_IRTE_T) * cIrtEntries;
3089 pHlp->pfnPrintf(pHlp, " IRTA = %#RX64\n", uIrtaReg & VTD_BF_IRTA_REG_IRTA_MASK);
3090 pHlp->pfnPrintf(pHlp, " EIME = %RTbool\n", RT_BF_GET(uIrtaReg, VTD_BF_IRTA_REG_EIME));
3091 pHlp->pfnPrintf(pHlp, " S = %u entries (%u bytes)\n", cIrtEntries, cbIrt);
3092 }
3093 pHlp->pfnPrintf(pHlp, " PQH_REG = %#RX64\n", uPqhReg);
3094 pHlp->pfnPrintf(pHlp, " PQT_REG = %#RX64\n", uPqtReg);
3095 pHlp->pfnPrintf(pHlp, " PQA_REG = %#RX64\n", uPqaReg);
3096 pHlp->pfnPrintf(pHlp, " PRS_REG = %#RX32\n", uPrsReg);
3097 pHlp->pfnPrintf(pHlp, " PECTL_REG = %#RX32\n", uPectlReg);
3098 pHlp->pfnPrintf(pHlp, " PEDATA_REG = %#RX32\n", uPedataReg);
3099 pHlp->pfnPrintf(pHlp, " PEADDR_REG = %#RX32\n", uPeaddrReg);
3100 pHlp->pfnPrintf(pHlp, " PEUADDR_REG = %#RX32\n", uPeuaddrReg);
3101 pHlp->pfnPrintf(pHlp, " MTRRCAP_REG = %#RX64\n", uMtrrcapReg);
3102 pHlp->pfnPrintf(pHlp, " MTRRDEF_REG = %#RX64\n", uMtrrdefReg);
3103 pHlp->pfnPrintf(pHlp, "\n");
3104}
3105
3106
3107/**
3108 * Initializes all registers in the DMAR unit.
3109 *
3110 * @param pDevIns The IOMMU device instance.
3111 */
3112static void dmarR3RegsInit(PPDMDEVINS pDevIns)
3113{
3114 PDMAR pThis = PDMDEVINS_2_DATA(pDevIns, PDMAR);
3115
3116 /*
3117 * Wipe all registers (required on reset).
3118 */
3119 RT_ZERO(pThis->abRegs0);
3120 RT_ZERO(pThis->abRegs1);
3121
3122 /*
3123 * Initialize registers not mutable by software prior to initializing other registers.
3124 */
3125 /* VER_REG */
3126 {
3127 pThis->uVerReg = RT_BF_MAKE(VTD_BF_VER_REG_MIN, DMAR_VER_MINOR)
3128 | RT_BF_MAKE(VTD_BF_VER_REG_MAX, DMAR_VER_MAJOR);
3129 dmarRegWriteRaw64(pThis, VTD_MMIO_OFF_VER_REG, pThis->uVerReg);
3130 }
3131
3132 uint8_t const fFlts = 1; /* First-Level translation support. */
3133 uint8_t const fSlts = 1; /* Second-Level translation support. */
3134 uint8_t const fPt = 1; /* Pass-Through support. */
3135 uint8_t const fSmts = fFlts & fSlts & fPt; /* Scalable mode translation support.*/
3136 uint8_t const fNest = 0; /* Nested translation support. */
3137
3138 /* CAP_REG */
3139 {
3140 uint8_t cGstPhysAddrBits;
3141 uint8_t cGstLinearAddrBits;
3142 PDMDevHlpCpuGetGuestAddrWidths(pDevIns, &cGstPhysAddrBits, &cGstLinearAddrBits);
3143
3144 uint8_t const fFl1gp = 1; /* First-Level 1GB pages support. */
3145 uint8_t const fFl5lp = 1; /* First-level 5-level paging support (PML5E). */
3146 uint8_t const fSl2mp = 1; /* Second-Level 2MB pages support. */
3147 uint8_t const fSl2gp = fSl2mp & 1; /* Second-Level 1GB pages support. */
3148 uint8_t const fSllps = fSl2mp | (fSl2gp << 1); /* Second-Level large page Support. */
3149 uint8_t const fMamv = (fSl2gp ? X86_PAGE_1G_SHIFT /* Maximum address mask value (for 2nd-level invalidations). */
3150 : X86_PAGE_2M_SHIFT)
3151 - X86_PAGE_4K_SHIFT;
3152 uint8_t const fNd = DMAR_ND; /* Number of domains supported. */
3153 uint8_t const fPsi = 1; /* Page selective invalidation. */
3154 uint8_t const uMgaw = cGstPhysAddrBits - 1; /* Maximum guest address width. */
3155 uint8_t const uSagaw = vtdCapRegGetSagaw(uMgaw); /* Supported adjust guest address width. */
3156 uint16_t const offFro = DMAR_MMIO_OFF_FRCD_LO_REG >> 4; /* MMIO offset of FRCD registers. */
3157 uint8_t const fEsrtps = 1; /* Enhanced SRTPS (auto invalidate cache on SRTP). */
3158 uint8_t const fEsirtps = 1; /* Enhanced SIRTPS (auto invalidate cache on SIRTP). */
3159 AssertCompile(DMAR_ND <= 6);
3160
3161 pThis->fCapReg = RT_BF_MAKE(VTD_BF_CAP_REG_ND, fNd)
3162 | RT_BF_MAKE(VTD_BF_CAP_REG_AFL, 0) /* Advanced fault logging not supported. */
3163 | RT_BF_MAKE(VTD_BF_CAP_REG_RWBF, 0) /* Software need not flush write-buffers. */
3164 | RT_BF_MAKE(VTD_BF_CAP_REG_PLMR, 0) /* Protected Low-Memory Region not supported. */
3165 | RT_BF_MAKE(VTD_BF_CAP_REG_PHMR, 0) /* Protected High-Memory Region not supported. */
3166 | RT_BF_MAKE(VTD_BF_CAP_REG_CM, 1) /* Software should invalidate on mapping structure changes. */
3167 | RT_BF_MAKE(VTD_BF_CAP_REG_SAGAW, fSlts & uSagaw)
3168 | RT_BF_MAKE(VTD_BF_CAP_REG_MGAW, uMgaw)
3169 | RT_BF_MAKE(VTD_BF_CAP_REG_ZLR, 1) /** @todo Figure out if/how to support zero-length reads. */
3170 | RT_BF_MAKE(VTD_BF_CAP_REG_FRO, offFro)
3171 | RT_BF_MAKE(VTD_BF_CAP_REG_SLLPS, fSlts & fSllps)
3172 | RT_BF_MAKE(VTD_BF_CAP_REG_PSI, fPsi)
3173 | RT_BF_MAKE(VTD_BF_CAP_REG_NFR, DMAR_FRCD_REG_COUNT - 1)
3174 | RT_BF_MAKE(VTD_BF_CAP_REG_MAMV, fPsi & fMamv)
3175 | RT_BF_MAKE(VTD_BF_CAP_REG_DWD, 1)
3176 | RT_BF_MAKE(VTD_BF_CAP_REG_DRD, 1)
3177 | RT_BF_MAKE(VTD_BF_CAP_REG_FL1GP, fFlts & fFl1gp)
3178 | RT_BF_MAKE(VTD_BF_CAP_REG_PI, 0) /* Posted Interrupts not supported. */
3179 | RT_BF_MAKE(VTD_BF_CAP_REG_FL5LP, fFlts & fFl5lp)
3180 | RT_BF_MAKE(VTD_BF_CAP_REG_ESIRTPS, fEsirtps)
3181 | RT_BF_MAKE(VTD_BF_CAP_REG_ESRTPS, fEsrtps);
3182 dmarRegWriteRaw64(pThis, VTD_MMIO_OFF_CAP_REG, pThis->fCapReg);
3183
3184 pThis->fHawMask = ~(UINT64_MAX << cGstPhysAddrBits);
3185 pThis->fMgawMask = pThis->fHawMask;
3186 }
3187
3188 /* ECAP_REG */
3189 {
3190 uint8_t const fQi = 1; /* Queued-invalidations. */
3191 uint8_t const fIr = !!(DMAR_ACPI_DMAR_FLAGS & ACPI_DMAR_F_INTR_REMAP); /* Interrupt remapping support. */
3192 uint8_t const fMhmv = 0xf; /* Maximum handle mask value. */
3193 uint16_t const offIro = DMAR_MMIO_OFF_IVA_REG >> 4; /* MMIO offset of IOTLB registers. */
3194 uint8_t const fEim = 1; /* Extended interrupt mode.*/
3195 uint8_t const fAdms = 1; /* Abort DMA mode support. */
3196
3197 pThis->fExtCapReg = RT_BF_MAKE(VTD_BF_ECAP_REG_C, 0) /* Accesses don't snoop CPU cache. */
3198 | RT_BF_MAKE(VTD_BF_ECAP_REG_QI, fQi)
3199 | RT_BF_MAKE(VTD_BF_ECAP_REG_DT, 0) /* Device-TLBs not supported. */
3200 | RT_BF_MAKE(VTD_BF_ECAP_REG_IR, fQi & fIr)
3201 | RT_BF_MAKE(VTD_BF_ECAP_REG_EIM, fIr & fEim)
3202 | RT_BF_MAKE(VTD_BF_ECAP_REG_PT, fPt)
3203 | RT_BF_MAKE(VTD_BF_ECAP_REG_SC, 0) /* Snoop control not supported. */
3204 | RT_BF_MAKE(VTD_BF_ECAP_REG_IRO, offIro)
3205 | RT_BF_MAKE(VTD_BF_ECAP_REG_MHMV, fIr & fMhmv)
3206 | RT_BF_MAKE(VTD_BF_ECAP_REG_MTS, 0) /* Memory type not supported. */
3207 | RT_BF_MAKE(VTD_BF_ECAP_REG_NEST, fNest)
3208 | RT_BF_MAKE(VTD_BF_ECAP_REG_PRS, 0) /* 0 as DT not supported. */
3209 | RT_BF_MAKE(VTD_BF_ECAP_REG_ERS, 0) /* Execute request not supported. */
3210 | RT_BF_MAKE(VTD_BF_ECAP_REG_SRS, 0) /* Supervisor request not supported. */
3211 | RT_BF_MAKE(VTD_BF_ECAP_REG_NWFS, 0) /* 0 as DT not supported. */
3212 | RT_BF_MAKE(VTD_BF_ECAP_REG_EAFS, 0) /** @todo figure out if EAFS is required? */
3213 | RT_BF_MAKE(VTD_BF_ECAP_REG_PSS, 0) /* 0 as PASID not supported. */
3214 | RT_BF_MAKE(VTD_BF_ECAP_REG_PASID, 0) /* PASID support. */
3215 | RT_BF_MAKE(VTD_BF_ECAP_REG_DIT, 0) /* 0 as DT not supported. */
3216 | RT_BF_MAKE(VTD_BF_ECAP_REG_PDS, 0) /* 0 as DT not supported. */
3217 | RT_BF_MAKE(VTD_BF_ECAP_REG_SMTS, fSmts)
3218 | RT_BF_MAKE(VTD_BF_ECAP_REG_VCS, 0) /* 0 as PASID not supported (commands seem PASID specific). */
3219 | RT_BF_MAKE(VTD_BF_ECAP_REG_SLADS, 0) /* Second-level accessed/dirty not supported. */
3220 | RT_BF_MAKE(VTD_BF_ECAP_REG_SLTS, fSlts)
3221 | RT_BF_MAKE(VTD_BF_ECAP_REG_FLTS, fFlts)
3222 | RT_BF_MAKE(VTD_BF_ECAP_REG_SMPWCS, 0) /* 0 as PASID not supported. */
3223 | RT_BF_MAKE(VTD_BF_ECAP_REG_RPS, 0) /* We don't support RID_PASID field in SM context entry. */
3224 | RT_BF_MAKE(VTD_BF_ECAP_REG_ADMS, fAdms)
3225 | RT_BF_MAKE(VTD_BF_ECAP_REG_RPRIVS, 0); /* 0 as SRS not supported. */
3226 dmarRegWriteRaw64(pThis, VTD_MMIO_OFF_ECAP_REG, pThis->fExtCapReg);
3227 }
3228
3229 /*
3230 * Initialize registers mutable by software.
3231 */
3232 /* FECTL_REG */
3233 {
3234 uint32_t const uCtl = RT_BF_MAKE(VTD_BF_FECTL_REG_IM, 1);
3235 dmarRegWriteRaw32(pThis, VTD_MMIO_OFF_FECTL_REG, uCtl);
3236 }
3237
3238 /* ICETL_REG */
3239 {
3240 uint32_t const uCtl = RT_BF_MAKE(VTD_BF_IECTL_REG_IM, 1);
3241 dmarRegWriteRaw32(pThis, VTD_MMIO_OFF_IECTL_REG, uCtl);
3242 }
3243
3244#ifdef VBOX_STRICT
3245 Assert(!RT_BF_GET(pThis->fExtCapReg, VTD_BF_ECAP_REG_PRS)); /* PECTL_REG - Reserved if don't support PRS. */
3246 Assert(!RT_BF_GET(pThis->fExtCapReg, VTD_BF_ECAP_REG_MTS)); /* MTRRCAP_REG - Reserved if we don't support MTS. */
3247#endif
3248}
3249
3250
3251/**
3252 * @interface_method_impl{PDMDEVREG,pfnReset}
3253 */
3254static DECLCALLBACK(void) iommuIntelR3Reset(PPDMDEVINS pDevIns)
3255{
3256 PCDMARR3 pThisR3 = PDMDEVINS_2_DATA_CC(pDevIns, PCDMARR3);
3257 LogFlowFunc(("\n"));
3258
3259 DMAR_LOCK(pDevIns, pThisR3);
3260 dmarR3RegsInit(pDevIns);
3261 DMAR_UNLOCK(pDevIns, pThisR3);
3262}
3263
3264
3265/**
3266 * @interface_method_impl{PDMDEVREG,pfnDestruct}
3267 */
3268static DECLCALLBACK(int) iommuIntelR3Destruct(PPDMDEVINS pDevIns)
3269{
3270 PDMAR pThis = PDMDEVINS_2_DATA(pDevIns, PDMAR);
3271 PCDMARR3 pThisR3 = PDMDEVINS_2_DATA_CC(pDevIns, PCDMARR3);
3272 LogFlowFunc(("\n"));
3273
3274 DMAR_LOCK(pDevIns, pThisR3);
3275
3276 if (pThis->hEvtInvQueue != NIL_SUPSEMEVENT)
3277 {
3278 PDMDevHlpSUPSemEventClose(pDevIns, pThis->hEvtInvQueue);
3279 pThis->hEvtInvQueue = NIL_SUPSEMEVENT;
3280 }
3281
3282 DMAR_UNLOCK(pDevIns, pThisR3);
3283 return VINF_SUCCESS;
3284}
3285
3286
3287/**
3288 * @interface_method_impl{PDMDEVREG,pfnConstruct}
3289 */
3290static DECLCALLBACK(int) iommuIntelR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
3291{
3292 RT_NOREF(pCfg);
3293
3294 PDMAR pThis = PDMDEVINS_2_DATA(pDevIns, PDMAR);
3295 PDMARR3 pThisR3 = PDMDEVINS_2_DATA_CC(pDevIns, PDMARR3);
3296 pThisR3->pDevInsR3 = pDevIns;
3297
3298 LogFlowFunc(("iInstance=%d\n", iInstance));
3299 NOREF(iInstance);
3300
3301 /*
3302 * Register the IOMMU with PDM.
3303 */
3304 PDMIOMMUREGR3 IommuReg;
3305 RT_ZERO(IommuReg);
3306 IommuReg.u32Version = PDM_IOMMUREGCC_VERSION;
3307 IommuReg.pfnMemAccess = iommuIntelMemAccess;
3308 IommuReg.pfnMemBulkAccess = iommuIntelMemBulkAccess;
3309 IommuReg.pfnMsiRemap = iommuIntelMsiRemap;
3310 IommuReg.u32TheEnd = PDM_IOMMUREGCC_VERSION;
3311 int rc = PDMDevHlpIommuRegister(pDevIns, &IommuReg, &pThisR3->CTX_SUFF(pIommuHlp), &pThis->idxIommu);
3312 if (RT_FAILURE(rc))
3313 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to register ourselves as an IOMMU device"));
3314 if (pThisR3->CTX_SUFF(pIommuHlp)->u32Version != PDM_IOMMUHLPR3_VERSION)
3315 return PDMDevHlpVMSetError(pDevIns, VERR_VERSION_MISMATCH, RT_SRC_POS,
3316 N_("IOMMU helper version mismatch; got %#x expected %#x"),
3317 pThisR3->CTX_SUFF(pIommuHlp)->u32Version, PDM_IOMMUHLPR3_VERSION);
3318 if (pThisR3->CTX_SUFF(pIommuHlp)->u32TheEnd != PDM_IOMMUHLPR3_VERSION)
3319 return PDMDevHlpVMSetError(pDevIns, VERR_VERSION_MISMATCH, RT_SRC_POS,
3320 N_("IOMMU helper end-version mismatch; got %#x expected %#x"),
3321 pThisR3->CTX_SUFF(pIommuHlp)->u32TheEnd, PDM_IOMMUHLPR3_VERSION);
3322 AssertPtr(pThisR3->pIommuHlpR3->pfnLock);
3323 AssertPtr(pThisR3->pIommuHlpR3->pfnUnlock);
3324 AssertPtr(pThisR3->pIommuHlpR3->pfnLockIsOwner);
3325 AssertPtr(pThisR3->pIommuHlpR3->pfnSendMsi);
3326
3327 /*
3328 * Use PDM's critical section (via helpers) for the IOMMU device.
3329 */
3330 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
3331 AssertRCReturn(rc, rc);
3332
3333 /*
3334 * Initialize PCI configuration registers.
3335 */
3336 PPDMPCIDEV pPciDev = pDevIns->apPciDevs[0];
3337 PDMPCIDEV_ASSERT_VALID(pDevIns, pPciDev);
3338
3339 /* Header. */
3340 PDMPciDevSetVendorId(pPciDev, DMAR_PCI_VENDOR_ID); /* Intel */
3341 PDMPciDevSetDeviceId(pPciDev, DMAR_PCI_DEVICE_ID); /* VirtualBox DMAR device */
3342 PDMPciDevSetRevisionId(pPciDev, DMAR_PCI_REVISION_ID); /* VirtualBox specific device implementation revision */
3343 PDMPciDevSetClassBase(pPciDev, VBOX_PCI_CLASS_SYSTEM); /* System Base Peripheral */
3344 PDMPciDevSetClassSub(pPciDev, VBOX_PCI_SUB_SYSTEM_OTHER); /* Other */
3345 PDMPciDevSetHeaderType(pPciDev, 0); /* Single function, type 0 */
3346 PDMPciDevSetSubSystemId(pPciDev, DMAR_PCI_DEVICE_ID); /* VirtualBox DMAR device */
3347 PDMPciDevSetSubSystemVendorId(pPciDev, DMAR_PCI_VENDOR_ID); /* Intel */
3348
3349 /** @todo Chipset spec says PCI Express Capability Id. Relevant for us? */
3350 PDMPciDevSetStatus(pPciDev, 0);
3351 PDMPciDevSetCapabilityList(pPciDev, 0);
3352
3353 /** @todo VTBAR at 0x180? */
3354
3355 /*
3356 * Register the PCI function with PDM.
3357 */
3358 rc = PDMDevHlpPCIRegister(pDevIns, pPciDev);
3359 AssertLogRelRCReturn(rc, rc);
3360
3361 /** @todo Register MSI but what's the MSI capability offset? */
3362#if 0
3363 /*
3364 * Register MSI support for the PCI device.
3365 * This must be done -after- registering it as a PCI device!
3366 */
3367#endif
3368
3369 /*
3370 * Register MMIO region.
3371 */
3372 AssertCompile(!(DMAR_MMIO_BASE_PHYSADDR & X86_PAGE_4K_OFFSET_MASK));
3373 rc = PDMDevHlpMmioCreateAndMap(pDevIns, DMAR_MMIO_BASE_PHYSADDR, DMAR_MMIO_SIZE, dmarMmioWrite, dmarMmioRead,
3374 IOMMMIO_FLAGS_READ_DWORD_QWORD | IOMMMIO_FLAGS_WRITE_DWORD_QWORD_ZEROED, "Intel-IOMMU",
3375 &pThis->hMmio);
3376 AssertLogRelRCReturn(rc, rc);
3377
3378 /*
3379 * Register debugger info items.
3380 */
3381 rc = PDMDevHlpDBGFInfoRegister(pDevIns, "iommu", "Display IOMMU state.", dmarR3DbgInfo);
3382 AssertLogRelRCReturn(rc, rc);
3383
3384#ifdef VBOX_WITH_STATISTICS
3385 /*
3386 * Statistics.
3387 */
3388 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatMmioReadR3, STAMTYPE_COUNTER, "R3/MmioRead", STAMUNIT_OCCURENCES, "Number of MMIO reads in R3");
3389 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatMmioReadRZ, STAMTYPE_COUNTER, "RZ/MmioRead", STAMUNIT_OCCURENCES, "Number of MMIO reads in RZ.");
3390
3391 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatMmioWriteR3, STAMTYPE_COUNTER, "R3/MmioWrite", STAMUNIT_OCCURENCES, "Number of MMIO writes in R3.");
3392 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatMmioWriteRZ, STAMTYPE_COUNTER, "RZ/MmioWrite", STAMUNIT_OCCURENCES, "Number of MMIO writes in RZ.");
3393
3394 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatMsiRemapCfiR3, STAMTYPE_COUNTER, "R3/MsiRemapCfi", STAMUNIT_OCCURENCES, "Number of compatibility-format interrupt remap requests in R3.");
3395 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatMsiRemapCfiRZ, STAMTYPE_COUNTER, "RZ/MsiRemapCfi", STAMUNIT_OCCURENCES, "Number of compatibility-format interrupt remap requests in RZ.");
3396 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatMsiRemapRfiR3, STAMTYPE_COUNTER, "R3/MsiRemapRfi", STAMUNIT_OCCURENCES, "Number of remappable-format interrupt remap requests in R3.");
3397 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatMsiRemapRfiRZ, STAMTYPE_COUNTER, "RZ/MsiRemapRfi", STAMUNIT_OCCURENCES, "Number of remappable-format interrupt remap requests in RZ.");
3398
3399 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatMemReadR3, STAMTYPE_COUNTER, "R3/MemRead", STAMUNIT_OCCURENCES, "Number of memory read translation requests in R3.");
3400 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatMemReadRZ, STAMTYPE_COUNTER, "RZ/MemRead", STAMUNIT_OCCURENCES, "Number of memory read translation requests in RZ.");
3401
3402 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatMemWriteR3, STAMTYPE_COUNTER, "R3/MemWrite", STAMUNIT_OCCURENCES, "Number of memory write translation requests in R3.");
3403 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatMemWriteRZ, STAMTYPE_COUNTER, "RZ/MemWrite", STAMUNIT_OCCURENCES, "Number of memory write translation requests in RZ.");
3404
3405 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatMemBulkReadR3, STAMTYPE_COUNTER, "R3/MemBulkRead", STAMUNIT_OCCURENCES, "Number of memory bulk read translation requests in R3.");
3406 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatMemBulkReadRZ, STAMTYPE_COUNTER, "RZ/MemBulkRead", STAMUNIT_OCCURENCES, "Number of memory bulk read translation requests in RZ.");
3407
3408 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatMemBulkWriteR3, STAMTYPE_COUNTER, "R3/MemBulkWrite", STAMUNIT_OCCURENCES, "Number of memory bulk write translation requests in R3.");
3409 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatMemBulkWriteRZ, STAMTYPE_COUNTER, "RZ/MemBulkWrite", STAMUNIT_OCCURENCES, "Number of memory bulk write translation requests in RZ.");
3410
3411 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatCcInvDsc, STAMTYPE_COUNTER, "R3/QI/CcInv", STAMUNIT_OCCURENCES, "Number of cc_inv_dsc processed.");
3412 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatIotlbInvDsc, STAMTYPE_COUNTER, "R3/QI/IotlbInv", STAMUNIT_OCCURENCES, "Number of iotlb_inv_dsc processed.");
3413 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatDevtlbInvDsc, STAMTYPE_COUNTER, "R3/QI/DevtlbInv", STAMUNIT_OCCURENCES, "Number of dev_tlb_inv_dsc processed.");
3414 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatIecInvDsc, STAMTYPE_COUNTER, "R3/QI/IecInv", STAMUNIT_OCCURENCES, "Number of iec_inv processed.");
3415 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatInvWaitDsc, STAMTYPE_COUNTER, "R3/QI/InvWait", STAMUNIT_OCCURENCES, "Number of inv_wait_dsc processed.");
3416 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatPasidIotlbInvDsc, STAMTYPE_COUNTER, "R3/QI/PasidIotlbInv", STAMUNIT_OCCURENCES, "Number of p_iotlb_inv_dsc processed.");
3417 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatPasidCacheInvDsc, STAMTYPE_COUNTER, "R3/QI/PasidCacheInv", STAMUNIT_OCCURENCES, "Number of pc_inv_dsc pprocessed.");
3418 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatPasidDevtlbInvDsc, STAMTYPE_COUNTER, "R3/QI/PasidDevtlbInv", STAMUNIT_OCCURENCES, "Number of p_dev_tlb_inv_dsc processed.");
3419#endif
3420
3421 /*
3422 * Initialize registers.
3423 */
3424 dmarR3RegsInit(pDevIns);
3425
3426 /*
3427 * Create invalidation-queue thread and semaphore.
3428 */
3429 char szInvQueueThread[32];
3430 RT_ZERO(szInvQueueThread);
3431 RTStrPrintf(szInvQueueThread, sizeof(szInvQueueThread), "IOMMU-QI-%u", iInstance);
3432 rc = PDMDevHlpThreadCreate(pDevIns, &pThisR3->pInvQueueThread, pThis, dmarR3InvQueueThread, dmarR3InvQueueThreadWakeUp,
3433 0 /* cbStack */, RTTHREADTYPE_IO, szInvQueueThread);
3434 AssertLogRelRCReturn(rc, rc);
3435
3436 rc = PDMDevHlpSUPSemEventCreate(pDevIns, &pThis->hEvtInvQueue);
3437 AssertLogRelRCReturn(rc, rc);
3438
3439 /*
3440 * Log some of the features exposed to software.
3441 */
3442 uint32_t const uVerReg = pThis->uVerReg;
3443 uint8_t const cMgawBits = RT_BF_GET(pThis->fCapReg, VTD_BF_CAP_REG_MGAW) + 1;
3444 uint8_t const fSagaw = RT_BF_GET(pThis->fCapReg, VTD_BF_CAP_REG_SAGAW);
3445 uint16_t const offFrcd = RT_BF_GET(pThis->fCapReg, VTD_BF_CAP_REG_FRO);
3446 uint16_t const offIva = RT_BF_GET(pThis->fExtCapReg, VTD_BF_ECAP_REG_IRO);
3447 LogRel(("%s: VER=%u.%u CAP=%#RX64 ECAP=%#RX64 (MGAW=%u bits, SAGAW=%#x HAW_Mask=%#RX64 FRO=%#x, IRO=%#x) mapped at %#RGp\n",
3448 DMAR_LOG_PFX, RT_BF_GET(uVerReg, VTD_BF_VER_REG_MAX), RT_BF_GET(uVerReg, VTD_BF_VER_REG_MIN),
3449 pThis->fCapReg, pThis->fExtCapReg, cMgawBits, fSagaw, pThis->fHawMask, offFrcd, offIva, DMAR_MMIO_BASE_PHYSADDR));
3450
3451 return VINF_SUCCESS;
3452}
3453
3454#else
3455
3456/**
3457 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
3458 */
3459static DECLCALLBACK(int) iommuIntelRZConstruct(PPDMDEVINS pDevIns)
3460{
3461 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
3462 PDMAR pThis = PDMDEVINS_2_DATA(pDevIns, PDMAR);
3463 PDMARCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDMARCC);
3464 pThisCC->CTX_SUFF(pDevIns) = pDevIns;
3465
3466 /* We will use PDM's critical section (via helpers) for the IOMMU device. */
3467 int rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
3468 AssertRCReturn(rc, rc);
3469
3470 /* Set up the MMIO RZ handlers. */
3471 rc = PDMDevHlpMmioSetUpContext(pDevIns, pThis->hMmio, dmarMmioWrite, dmarMmioRead, NULL /* pvUser */);
3472 AssertRCReturn(rc, rc);
3473
3474 /* Set up the IOMMU RZ callbacks. */
3475 PDMIOMMUREGCC IommuReg;
3476 RT_ZERO(IommuReg);
3477 IommuReg.u32Version = PDM_IOMMUREGCC_VERSION;
3478 IommuReg.idxIommu = pThis->idxIommu;
3479 IommuReg.pfnMemAccess = iommuIntelMemAccess;
3480 IommuReg.pfnMemBulkAccess = iommuIntelMemBulkAccess;
3481 IommuReg.pfnMsiRemap = iommuIntelMsiRemap;
3482 IommuReg.u32TheEnd = PDM_IOMMUREGCC_VERSION;
3483
3484 rc = PDMDevHlpIommuSetUpContext(pDevIns, &IommuReg, &pThisCC->CTX_SUFF(pIommuHlp));
3485 AssertRCReturn(rc, rc);
3486 AssertPtrReturn(pThisCC->CTX_SUFF(pIommuHlp), VERR_IOMMU_IPE_1);
3487 AssertReturn(pThisCC->CTX_SUFF(pIommuHlp)->u32Version == CTX_MID(PDM_IOMMUHLP,_VERSION), VERR_VERSION_MISMATCH);
3488 AssertReturn(pThisCC->CTX_SUFF(pIommuHlp)->u32TheEnd == CTX_MID(PDM_IOMMUHLP,_VERSION), VERR_VERSION_MISMATCH);
3489 AssertPtr(pThisCC->CTX_SUFF(pIommuHlp)->pfnLock);
3490 AssertPtr(pThisCC->CTX_SUFF(pIommuHlp)->pfnUnlock);
3491 AssertPtr(pThisCC->CTX_SUFF(pIommuHlp)->pfnLockIsOwner);
3492 AssertPtr(pThisCC->CTX_SUFF(pIommuHlp)->pfnSendMsi);
3493
3494 return VINF_SUCCESS;
3495}
3496
3497#endif
3498
3499
3500/**
3501 * The device registration structure.
3502 */
3503PDMDEVREG const g_DeviceIommuIntel =
3504{
3505 /* .u32Version = */ PDM_DEVREG_VERSION,
3506 /* .uReserved0 = */ 0,
3507 /* .szName = */ "iommu-intel",
3508 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
3509 /* .fClass = */ PDM_DEVREG_CLASS_PCI_BUILTIN,
3510 /* .cMaxInstances = */ 1,
3511 /* .uSharedVersion = */ 42,
3512 /* .cbInstanceShared = */ sizeof(DMAR),
3513 /* .cbInstanceCC = */ sizeof(DMARCC),
3514 /* .cbInstanceRC = */ sizeof(DMARRC),
3515 /* .cMaxPciDevices = */ 1,
3516 /* .cMaxMsixVectors = */ 0,
3517 /* .pszDescription = */ "IOMMU (Intel)",
3518#if defined(IN_RING3)
3519 /* .pszRCMod = */ "VBoxDDRC.rc",
3520 /* .pszR0Mod = */ "VBoxDDR0.r0",
3521 /* .pfnConstruct = */ iommuIntelR3Construct,
3522 /* .pfnDestruct = */ iommuIntelR3Destruct,
3523 /* .pfnRelocate = */ NULL,
3524 /* .pfnMemSetup = */ NULL,
3525 /* .pfnPowerOn = */ NULL,
3526 /* .pfnReset = */ iommuIntelR3Reset,
3527 /* .pfnSuspend = */ NULL,
3528 /* .pfnResume = */ NULL,
3529 /* .pfnAttach = */ NULL,
3530 /* .pfnDetach = */ NULL,
3531 /* .pfnQueryInterface = */ NULL,
3532 /* .pfnInitComplete = */ NULL,
3533 /* .pfnPowerOff = */ NULL,
3534 /* .pfnSoftReset = */ NULL,
3535 /* .pfnReserved0 = */ NULL,
3536 /* .pfnReserved1 = */ NULL,
3537 /* .pfnReserved2 = */ NULL,
3538 /* .pfnReserved3 = */ NULL,
3539 /* .pfnReserved4 = */ NULL,
3540 /* .pfnReserved5 = */ NULL,
3541 /* .pfnReserved6 = */ NULL,
3542 /* .pfnReserved7 = */ NULL,
3543#elif defined(IN_RING0)
3544 /* .pfnEarlyConstruct = */ NULL,
3545 /* .pfnConstruct = */ iommuIntelRZConstruct,
3546 /* .pfnDestruct = */ NULL,
3547 /* .pfnFinalDestruct = */ NULL,
3548 /* .pfnRequest = */ NULL,
3549 /* .pfnReserved0 = */ NULL,
3550 /* .pfnReserved1 = */ NULL,
3551 /* .pfnReserved2 = */ NULL,
3552 /* .pfnReserved3 = */ NULL,
3553 /* .pfnReserved4 = */ NULL,
3554 /* .pfnReserved5 = */ NULL,
3555 /* .pfnReserved6 = */ NULL,
3556 /* .pfnReserved7 = */ NULL,
3557#elif defined(IN_RC)
3558 /* .pfnConstruct = */ iommuIntelRZConstruct,
3559 /* .pfnReserved0 = */ NULL,
3560 /* .pfnReserved1 = */ NULL,
3561 /* .pfnReserved2 = */ NULL,
3562 /* .pfnReserved3 = */ NULL,
3563 /* .pfnReserved4 = */ NULL,
3564 /* .pfnReserved5 = */ NULL,
3565 /* .pfnReserved6 = */ NULL,
3566 /* .pfnReserved7 = */ NULL,
3567#else
3568# error "Not in IN_RING3, IN_RING0 or IN_RC!"
3569#endif
3570 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
3571};
3572
3573#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
3574
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette