Changeset 89476 in vbox for trunk/src/VBox/Devices
- Timestamp:
- Jun 3, 2021 8:58:51 AM (4 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Bus/DevIommuIntel.cpp
r89455 r89476 54 54 #define DMAR_IS_MMIO_OFF_VALID(a_off) ( (a_off) < DMAR_MMIO_GROUP_0_OFF_END \ 55 55 || (a_off) - DMAR_MMIO_GROUP_1_OFF_FIRST < DMAR_MMIO_GROUP_1_SIZE) 56 57 /** Gets the page offset mask given the number of bits to shift. */58 #define DMAR_GET_PAGE_OFF_MASK(a_cShift) (~(UINT64_C(0xffffffffffffffff) << (a_cShift)))59 56 60 57 /** Acquires the DMAR lock but returns with the given busy error code on failure. */ … … 476 473 477 474 /** 478 * I/O TLB entry.479 */ 480 typedef struct DMARIO TLBE481 { 482 /** The system-physical base address of the translation. */475 * I/O Page. 476 */ 477 typedef struct DMARIOPAGE 478 { 479 /** The base DMA address of a page. */ 483 480 RTGCPHYS GCPhysBase; 484 /** The domain ID of the translated region. */485 uint 16_t idDomain;486 /** The permissions granted. */481 /** The page shift. */ 482 uint8_t cShift; 483 /** The permissions of this page (DMAR_PERM_XXX). */ 487 484 uint8_t fPerm; 488 /** The page shift of the translation. */ 489 uint8_t cShift; 490 } DMARIOTLBE; 491 /** Pointer to an IOTLB entry. */ 492 typedef DMARIOTLBE *PDMARIOTLBE; 493 /** Pointer to a const IOTLB entry. */ 494 typedef DMARIOTLBE const *PCDMARIOTLBE; 495 AssertCompileSizeAlignment(DMARIOTLBE, 4); 496 497 /** 498 * DMA Memory Request. 499 */ 500 typedef struct DMARMEMREQ 501 { 502 /** The address being accessed. */ 503 uint64_t uDmaAddr; 504 /** The size of the access (in bytes). */ 505 size_t cbDma; 506 /** The requested permissions (DMAR_PERM_XXX). */ 507 uint8_t fReqPerm; 485 } DMARIOPAGE; 486 /** Pointer to an I/O page. */ 487 typedef DMARIOPAGE *PDMARIOPAGE; 488 /** Pointer to a const I/O address range. */ 489 typedef DMARIOPAGE const *PCDMARIOPAGE; 490 491 /** 492 * I/O Address Range. 493 */ 494 typedef struct DMARIOADDRRANGE 495 { 496 /** The starting DMA address of this range. */ 497 uint64_t uAddr; 498 /** The size of the range (in bytes). */ 499 size_t cb; 500 /** The permissions of this range (DMAR_PERM_XXX). */ 501 uint8_t fPerm; 502 } DMARIOADDRRANGE; 503 /** Pointer to an I/O address range. */ 504 typedef DMARIOADDRRANGE *PDMARIOADDRRANGE; 505 /** Pointer to a const I/O address range. */ 506 typedef DMARIOADDRRANGE const *PCDMARIOADDRRANGE; 507 508 /** 509 * DMA Memory Request (Input). 510 */ 511 typedef struct DMARMEMREQIN 512 { 513 /** The address range being accessed. */ 514 DMARIOADDRRANGE AddrRange; 508 515 /** The source device ID (bus, device, function). */ 509 516 uint16_t idDevice; … … 514 521 /** The request type. */ 515 522 VTDREQTYPE enmReqType; 516 } DMARMEMREQ; 517 /** Pointer to a DMA memory request. */ 518 typedef DMARMEMREQ *PDMARMEMREQ; 519 /** Pointer to a const DMA memory request. */ 520 typedef DMARMEMREQ const *PCDMARMEMREQ; 521 522 /** 523 * DMA Memory Request Remapping Information. 524 */ 525 typedef struct DMARMEMREQREMAP 526 { 527 /* The DMA memory request. */ 528 DMARMEMREQ Req; 523 } DMARMEMREQIN; 524 /** Pointer to a DMA memory request input. */ 525 typedef DMARMEMREQIN *PDMARMEMREQIN; 526 /** Pointer to a const DMA memory input. */ 527 typedef DMARMEMREQIN const *PCDMARMEMREQIN; 528 529 /** 530 * DMA Memory Request (Output). 531 */ 532 typedef struct DMARMEMREQOUT 533 { 534 /** The address range of the translated region. */ 535 DMARIOADDRRANGE AddrRange; 536 /** The domain ID of the translated region. */ 537 uint16_t idDomain; 538 } DMARMEMREQOUT; 539 /** Pointer to a DMA memory request output. */ 540 typedef DMARMEMREQOUT *PDMARMEMREQOUT; 541 /** Pointer to a const DMA memory request output. */ 542 typedef DMARMEMREQOUT const *PCDMARMEMREQOUT; 543 544 /** 545 * DMA Memory Request (Auxiliary Info). 546 * These get updated and used as part of the translation process. 547 */ 548 typedef struct DMARMEMREQAUX 549 { 529 550 /** The table translation mode (VTD_TTM_XXX). */ 530 551 uint8_t fTtm; 531 552 /** The fault processing disabled (FPD) bit. */ 532 553 uint8_t fFpd; 533 534 /** The IOTLBE result for this remapping. */ 535 DMARIOTLBE Iotlbe; 536 /** The size of the contiguous translated region (in bytes). */ 537 size_t cbContiguous; 554 /** The paging level of the translation. */ 555 uint8_t cPagingLevel; 556 uint8_t afPadding[5]; 557 /** The first-level page-table pointer (base). */ 558 uint64_t uFlptPtr; 559 /** The second-level page-table pointer (base). */ 560 uint64_t uSlptPtr; 561 } DMARMEMREQAUX; 562 /** Pointer to a DMA memory request output. */ 563 typedef DMARMEMREQAUX *PDMARMEMREQAUX; 564 /** Pointer to a const DMA memory request output. */ 565 typedef DMARMEMREQAUX const *PCDMARMEMREQAUX; 566 567 /** 568 * DMA Memory Request Remapping Information. 569 */ 570 typedef struct DMARMEMREQREMAP 571 { 572 /** The DMA memory request input. */ 573 DMARMEMREQIN In; 574 /** DMA memory request auxiliary information. */ 575 DMARMEMREQAUX Aux; 576 /** The DMA memory request output. */ 577 DMARMEMREQOUT Out; 538 578 } DMARMEMREQREMAP; 539 579 /** Pointer to a DMA remap info. */ … … 541 581 /** Pointer to a const DMA remap info. */ 542 582 typedef DMARMEMREQREMAP const *PCDMARMEMREQREMAP; 583 584 typedef DECLCALLBACKTYPE(int, FNDMAADDRTRANSLATE,(PPDMDEVINS pDevIns, PCDMARMEMREQIN pMemReqIn, PCDMARMEMREQAUX pMemReqAux, 585 PDMARIOPAGE pIoPageOut)); 586 typedef FNDMAADDRTRANSLATE *PFNDMAADDRTRANSLATE; 543 587 544 588 … … 1501 1545 1502 1546 /** 1503 * Records an address translation fault .1547 * Records an address translation fault (extended version). 1504 1548 * 1505 1549 * @param pDevIns The IOMMU device instance. 1506 1550 * @param enmDiag The diagnostic reason. 1507 1551 * @param enmAtFault The address translation fault reason. 1508 * @param pMemReqRemap The DMA memory request remapping info. 1509 */ 1510 static void dmarAtFaultRecord(PPDMDEVINS pDevIns, DMARDIAG enmDiag, VTDATFAULT enmAtFault, PCDMARMEMREQREMAP pMemReqRemap) 1552 * @param pMemReqIn The DMA memory request input. 1553 * @param pMemReqAux The DMA memory request auxiliary info. 1554 */ 1555 static void dmarAtFaultRecordEx(PPDMDEVINS pDevIns, DMARDIAG enmDiag, VTDATFAULT enmAtFault, PCDMARMEMREQIN pMemReqIn, 1556 PCDMARMEMREQAUX pMemReqAux) 1511 1557 { 1512 1558 /* … … 1514 1560 * in the contex entry, scalable-mode context entry etc. 1515 1561 */ 1516 if (!pMemReq Remap->fFpd)1517 { 1518 uint16_t const idDevice = pMemReq Remap->Req.idDevice;1519 uint8_t const fType1 = pMemReq Remap->Req.enmReqType & RT_BIT(1);1520 uint8_t const fType2 = pMemReq Remap->Req.enmReqType & RT_BIT(0);1521 uint8_t const fExec = pMemReq Remap->Req.fReqPerm & DMAR_PERM_EXE;1522 uint8_t const fPriv = pMemReq Remap->Req.fReqPerm & DMAR_PERM_PRIV;1523 bool const fHasPasid = PCIPASID_IS_VALID(pMemReq Remap->Req.Pasid);1524 uint32_t const uPasid = PCIPASID_VAL(pMemReq Remap->Req.Pasid);1525 PCIADDRTYPE const enmAt = pMemReq Remap->Req.enmAddrType;1562 if (!pMemReqAux->fFpd) 1563 { 1564 uint16_t const idDevice = pMemReqIn->idDevice; 1565 uint8_t const fType1 = pMemReqIn->enmReqType & RT_BIT(1); 1566 uint8_t const fType2 = pMemReqIn->enmReqType & RT_BIT(0); 1567 uint8_t const fExec = pMemReqIn->AddrRange.fPerm & DMAR_PERM_EXE; 1568 uint8_t const fPriv = pMemReqIn->AddrRange.fPerm & DMAR_PERM_PRIV; 1569 bool const fHasPasid = PCIPASID_IS_VALID(pMemReqIn->Pasid); 1570 uint32_t const uPasid = PCIPASID_VAL(pMemReqIn->Pasid); 1571 PCIADDRTYPE const enmAt = pMemReqIn->enmAddrType; 1526 1572 1527 1573 uint64_t const uFrcdHi = RT_BF_MAKE(VTD_BF_1_FRCD_REG_SID, idDevice) … … 1535 1581 | RT_BF_MAKE(VTD_BF_1_FRCD_REG_T1, fType1) 1536 1582 | RT_BF_MAKE(VTD_BF_1_FRCD_REG_F, 1); 1537 uint64_t const uFrcdLo = pMemReq Remap->Req.uDmaAddr & X86_PAGE_BASE_MASK;1583 uint64_t const uFrcdLo = pMemReqIn->AddrRange.uAddr & X86_PAGE_BASE_MASK; 1538 1584 dmarPrimaryFaultRecord(pDevIns, enmDiag, uFrcdHi, uFrcdLo); 1539 1585 } 1586 } 1587 1588 1589 /** 1590 * Records an address translation fault. 1591 * 1592 * @param pDevIns The IOMMU device instance. 1593 * @param enmDiag The diagnostic reason. 1594 * @param enmAtFault The address translation fault reason. 1595 * @param pMemReqRemap The DMA memory request remapping info. 1596 */ 1597 static void dmarAtFaultRecord(PPDMDEVINS pDevIns, DMARDIAG enmDiag, VTDATFAULT enmAtFault, PCDMARMEMREQREMAP pMemReqRemap) 1598 { 1599 dmarAtFaultRecordEx(pDevIns, enmDiag, enmAtFault, &pMemReqRemap->In, &pMemReqRemap->Aux); 1540 1600 } 1541 1601 … … 1997 2057 1998 2058 /** 1999 * Validates the output address of a translation and updates the IOTLB entry for the 2000 * given memory request remapping. 2059 * Validates and updates the output I/O page of a translation. 2001 2060 * 2002 2061 * @returns VBox status code. 2003 * @param pDevIns The IOMMU device instance. 2004 * @param GCPhysBase The output address of the translation. 2005 * @param cShift The page shift of the translation. 2006 * @param fPerm The permissions granted for the translated. 2007 * @param idDomain The domain ID of the translated region. 2008 * @param pMemReqRemap The DMA memory request remapping info. 2009 */ 2010 static int dmarDrValidateAndUpdateIotlbe(PPDMDEVINS pDevIns, RTGCPHYS GCPhysBase, uint8_t cShift, uint8_t fPerm, 2011 uint16_t idDomain, PDMARMEMREQREMAP pMemReqRemap) 2012 { 2013 Assert( pMemReqRemap->fTtm == VTD_TTM_LEGACY_MODE 2014 || pMemReqRemap->fTtm == VTD_TTM_SCALABLE_MODE); 2062 * @param pDevIns The IOMMU device instance. 2063 * @param GCPhysBase The output address of the translation. 2064 * @param cShift The page shift of the translated address. 2065 * @param fPerm The permissions granted for the translated region. 2066 * @param pMemReqIn The DMA memory request input. 2067 * @param pMemReqAux The DMA memory request auxiliary info. 2068 * @param pIoPageOut Where to store the output of the translation. 2069 */ 2070 static int dmarDrUpdateIoPageOut(PPDMDEVINS pDevIns, RTGCPHYS GCPhysBase, uint8_t cShift, uint8_t fPerm, 2071 PCDMARMEMREQIN pMemReqIn, PCDMARMEMREQAUX pMemReqAux, PDMARIOPAGE pIoPageOut) 2072 { 2015 2073 Assert(!(GCPhysBase & X86_PAGE_4K_OFFSET_MASK)); 2016 2074 … … 2018 2076 if (GCPhysBase - VBOX_MSI_ADDR_BASE >= VBOX_MSI_ADDR_SIZE) 2019 2077 { 2020 pMemReqRemap->Iotlbe.GCPhysBase = GCPhysBase; 2021 pMemReqRemap->Iotlbe.cShift = cShift; 2022 pMemReqRemap->Iotlbe.fPerm = fPerm; 2023 pMemReqRemap->Iotlbe.idDomain = idDomain; 2078 pIoPageOut->GCPhysBase = GCPhysBase; 2079 pIoPageOut->cShift = cShift; 2080 pIoPageOut->fPerm = fPerm; 2024 2081 return VINF_SUCCESS; 2025 2082 } 2026 2083 2027 if (pMemReq Remap->fTtm == VTD_TTM_LEGACY_MODE)2028 dmarAtFaultRecord (pDevIns, kDmarDiag_Atf_Lgn_4, VTDATFAULT_LGN_4, pMemReqRemap);2084 if (pMemReqAux->fTtm == VTD_TTM_LEGACY_MODE) 2085 dmarAtFaultRecordEx(pDevIns, kDmarDiag_Atf_Lgn_4, VTDATFAULT_LGN_4, pMemReqIn, pMemReqAux); 2029 2086 else 2030 dmarAtFaultRecord (pDevIns, kDmarDiag_Atf_Sgn_8, VTDATFAULT_SGN_8, pMemReqRemap);2087 dmarAtFaultRecordEx(pDevIns, kDmarDiag_Atf_Sgn_8, VTDATFAULT_SGN_8, pMemReqIn, pMemReqAux); 2031 2088 return VERR_IOMMU_ADDR_TRANSLATION_FAILED; 2032 2089 } … … 2037 2094 * 2038 2095 * @returns VBox status code. 2039 * @param pDevIns The IOMMU device instance. 2040 * @param SlpEntry The second-level paging entry. 2041 * @param cPagingLevel The paging level. 2042 * @param idDomain The domain ID for the translation. 2043 * @param pMemReqRemap The DMA memory request remapping info. 2044 */ 2045 static int dmarDrSecondLevelTranslate(PPDMDEVINS pDevIns, VTD_SLP_ENTRY_T SlpEntry, uint8_t cPagingLevel, uint16_t idDomain, 2046 PDMARMEMREQREMAP pMemReqRemap) 2096 * @param pDevIns The IOMMU device instance. 2097 * @param pMemReqIn The DMA memory request input. 2098 * @param pMemReqAux The DMA memory request auxiliary info. 2099 * @param pIoPageOut Where to store the output of the translation. 2100 */ 2101 static DECLCALLBACK(int) dmarDrSecondLevelTranslate(PPDMDEVINS pDevIns, PCDMARMEMREQIN pMemReqIn, PCDMARMEMREQAUX pMemReqAux, 2102 PDMARIOPAGE pIoPageOut) 2047 2103 { 2048 2104 PCDMAR pThis = PDMDEVINS_2_DATA(pDevIns, PCDMAR); 2105 2106 /* Sanity. */ 2107 Assert(pIoPageOut); 2108 Assert(pMemReqIn->AddrRange.fPerm & (DMAR_PERM_READ | DMAR_PERM_WRITE)); 2109 Assert( pMemReqAux->fTtm == VTD_TTM_LEGACY_MODE 2110 || pMemReqAux->fTtm == VTD_TTM_SCALABLE_MODE); 2049 2111 2050 2112 /* Mask of valid paging entry bits. */ … … 2055 2117 VTD_SL_PML5E_VALID_MASK }; 2056 2118 2057 /* Mask of valid large-page (1GB, 2MB) paging entries. */2058 static uint64_t const s_auLargePageRsvd[] = { 0,2059 VTD_SL_PDE2M_VALID_MASK,2060 VTD_SL_PDPE1G_VALID_MASK,2061 0,2062 0 };2063 2064 2119 /* Paranoia. */ 2065 Assert(cPagingLevel >= 3 && cPagingLevel <= 5); 2066 AssertCompile(RT_ELEMENTS(s_auPtEntityRsvd) == RT_ELEMENTS(s_auLargePageRsvd)); 2120 Assert(pMemReqAux->cPagingLevel >= 3 && pMemReqAux->cPagingLevel <= 5); 2067 2121 AssertCompile(RT_ELEMENTS(s_auPtEntityRsvd) == 5); 2068 2122 2069 2123 /* Second-level translations restricts input address to an implementation-specific MGAW. */ 2070 uint64_t const uDmaAddr = pMemReq Remap->Req.uDmaAddr;2124 uint64_t const uDmaAddr = pMemReqIn->AddrRange.uAddr; 2071 2125 if (!(uDmaAddr & pThis->fInvMgawMask)) 2072 2126 { /* likely */ } 2073 2127 else 2074 2128 { 2075 if (pMemReq Remap->fTtm == VTD_TTM_LEGACY_MODE)2076 dmarAtFaultRecord (pDevIns, kDmarDiag_Atf_Lgn_1_1, VTDATFAULT_LGN_1_1, pMemReqRemap);2129 if (pMemReqAux->fTtm == VTD_TTM_LEGACY_MODE) 2130 dmarAtFaultRecordEx(pDevIns, kDmarDiag_Atf_Lgn_1_1, VTDATFAULT_LGN_1_1, pMemReqIn, pMemReqAux); 2077 2131 else 2078 dmarAtFaultRecord (pDevIns, kDmarDiag_Atf_Sgn_5, VTDATFAULT_SGN_5, pMemReqRemap);2132 dmarAtFaultRecordEx(pDevIns, kDmarDiag_Atf_Sgn_5, VTDATFAULT_SGN_5, pMemReqIn, pMemReqAux); 2079 2133 return VERR_IOMMU_ADDR_TRANSLATION_FAILED; 2080 2134 } … … 2084 2138 * Unlike AMD IOMMU paging, here there is no feature for "skipping" levels. 2085 2139 */ 2086 uint64_t uPtEntity = SlpEntry;2087 for (int8_t iLevel = cPagingLevel - 1; iLevel >= 0; iLevel--)2140 uint64_t uPtEntity = pMemReqAux->uSlptPtr; 2141 for (int8_t iLevel = pMemReqAux->cPagingLevel - 1; iLevel >= 0; iLevel--) 2088 2142 { 2089 2143 /* 2090 2144 * Read the paging entry for the current level. 2091 2145 */ 2092 uint8_t const cLevelShift = 12 + ((iLevel - 1)* 9);2146 uint8_t const cLevelShift = X86_PAGE_4K_SHIFT + (iLevel * 9); 2093 2147 { 2094 2148 uint16_t const idxPte = (uDmaAddr >> cLevelShift) & UINT64_C(0x1ff); … … 2100 2154 else 2101 2155 { 2102 if (pMemReq Remap->fTtm == VTD_TTM_LEGACY_MODE)2103 dmarAtFaultRecord (pDevIns, kDmarDiag_Atf_Lsl_1, VTDATFAULT_LSL_1, pMemReqRemap);2156 if (pMemReqAux->fTtm == VTD_TTM_LEGACY_MODE) 2157 dmarAtFaultRecordEx(pDevIns, kDmarDiag_Atf_Lsl_1, VTDATFAULT_LSL_1, pMemReqIn, pMemReqAux); 2104 2158 else 2105 dmarAtFaultRecord (pDevIns, kDmarDiag_Atf_Ssl_1, VTDATFAULT_SSL_1, pMemReqRemap);2159 dmarAtFaultRecordEx(pDevIns, kDmarDiag_Atf_Ssl_1, VTDATFAULT_SSL_1, pMemReqIn, pMemReqAux); 2106 2160 return VERR_IOMMU_ADDR_TRANSLATION_FAILED; 2107 2161 } … … 2114 2168 * See Intel spec. 7.1.3 "Fault conditions and Remapping hardware behavior for various request". 2115 2169 */ 2116 uint8_t const fReqPerm = pMemReq Remap->Req.fReqPerm & pThis->fPermValidMask;2170 uint8_t const fReqPerm = pMemReqIn->AddrRange.fPerm & pThis->fPermValidMask; 2117 2171 uint8_t const fPtPerm = uPtEntity & pThis->fPermValidMask; 2172 Assert(!(fReqPerm & DMAR_PERM_EXE)); /* No Execute-requests support yet. */ 2173 Assert(pThis->fExtCapReg & VTD_BF_ECAP_REG_SLADS_MASK); /* No Second-level access/dirty support. */ 2118 2174 if ((fPtPerm & fReqPerm) == fReqPerm) 2119 2175 { /* likely */ } 2120 2176 else 2121 2177 { 2122 if (pMemReq Remap->fTtm == VTD_TTM_LEGACY_MODE)2123 dmarAtFaultRecord (pDevIns, kDmarDiag_Atf_Lsl_2, VTDATFAULT_LSL_2, pMemReqRemap);2178 if (pMemReqAux->fTtm == VTD_TTM_LEGACY_MODE) 2179 dmarAtFaultRecordEx(pDevIns, kDmarDiag_Atf_Lsl_2, VTDATFAULT_LSL_2, pMemReqIn, pMemReqAux); 2124 2180 else 2125 dmarAtFaultRecord (pDevIns, kDmarDiag_Atf_Ssl_2, VTDATFAULT_SSL_2, pMemReqRemap);2181 dmarAtFaultRecordEx(pDevIns, kDmarDiag_Atf_Ssl_2, VTDATFAULT_SSL_2, pMemReqIn, pMemReqAux); 2126 2182 return VERR_IOMMU_ADDR_TRANSLATION_FAILED; 2127 2183 } … … 2134 2190 else 2135 2191 { 2136 if (pMemReq Remap->fTtm == VTD_TTM_LEGACY_MODE)2137 dmarAtFaultRecord (pDevIns, kDmarDiag_Atf_Lsl_2, VTDATFAULT_LSL_2, pMemReqRemap);2192 if (pMemReqAux->fTtm == VTD_TTM_LEGACY_MODE) 2193 dmarAtFaultRecordEx(pDevIns, kDmarDiag_Atf_Lsl_2, VTDATFAULT_LSL_2, pMemReqIn, pMemReqAux); 2138 2194 else 2139 dmarAtFaultRecord (pDevIns, kDmarDiag_Atf_Ssl_3, VTDATFAULT_SSL_3, pMemReqRemap);2195 dmarAtFaultRecordEx(pDevIns, kDmarDiag_Atf_Ssl_3, VTDATFAULT_SSL_3, pMemReqIn, pMemReqAux); 2140 2196 return VERR_IOMMU_ADDR_TRANSLATION_FAILED; 2141 2197 } … … 2152 2208 if (fSllpsMask & RT_BIT(iLevel - 1)) 2153 2209 { 2154 RTGCPHYS const GCPhysBase = uPtEntity & ~(RT_BIT_64(cLevelShift) - 1); 2155 return dmarDrValidateAndUpdateIotlbe(pDevIns, GCPhysBase, cLevelShift, fPtPerm, idDomain, pMemReqRemap); 2210 /* 2211 * We don't support MTS (asserted below), hence IPAT and EMT fields of the paging entity are ignored. 2212 * All other reserved bits are identical to the regular page-size paging entity which we've already 2213 * checked above. 2214 */ 2215 Assert(!(pThis->fExtCapReg & VTD_BF_ECAP_REG_MTS_MASK)); 2216 2217 RTGCPHYS const GCPhysBase = uPtEntity & X86_GET_PAGE_BASE_MASK(cLevelShift); 2218 return dmarDrUpdateIoPageOut(pDevIns, GCPhysBase, cLevelShift, fPtPerm, pMemReqIn, pMemReqAux, pIoPageOut); 2156 2219 } 2157 2220 2158 if (pMemReq Remap->fTtm == VTD_TTM_LEGACY_MODE)2159 dmarAtFaultRecord (pDevIns, kDmarDiag_Atf_Lsl_2_LargePage, VTDATFAULT_LSL_2, pMemReqRemap);2221 if (pMemReqAux->fTtm == VTD_TTM_LEGACY_MODE) 2222 dmarAtFaultRecordEx(pDevIns, kDmarDiag_Atf_Lsl_2_LargePage, VTDATFAULT_LSL_2, pMemReqIn, pMemReqAux); 2160 2223 else 2161 dmarAtFaultRecord (pDevIns, kDmarDiag_Atf_Ssl_3_LargePage, VTDATFAULT_SSL_3, pMemReqRemap);2224 dmarAtFaultRecordEx(pDevIns, kDmarDiag_Atf_Ssl_3_LargePage, VTDATFAULT_SSL_3, pMemReqIn, pMemReqAux); 2162 2225 return VERR_IOMMU_ADDR_TRANSLATION_FAILED; 2163 2226 } … … 2168 2231 if (iLevel == 0) 2169 2232 { 2170 RTGCPHYS const GCPhysBase = uPtEntity & ~(RT_BIT_64(cLevelShift) - 1);2171 return dmarDr ValidateAndUpdateIotlbe(pDevIns, GCPhysBase, cLevelShift, fPtPerm, idDomain, pMemReqRemap);2233 RTGCPHYS const GCPhysBase = uPtEntity & X86_GET_PAGE_BASE_MASK(cLevelShift); 2234 return dmarDrUpdateIoPageOut(pDevIns, GCPhysBase, cLevelShift, fPtPerm, pMemReqIn, pMemReqAux, pIoPageOut); 2172 2235 } 2173 2236 } … … 2179 2242 2180 2243 /** 2181 * Handles remapping of DMA address requests in legacy mode. 2244 * Checks whether two consecutive I/O page results of a DMA memory request form a 2245 * physically contiguous region. 2246 * 2247 * @returns @c true if the I/O pages are contiguous, @c false otherwise. 2248 * @param pIoPagePrev The previous I/O page. 2249 * @param pIoPage The current I/O page. 2250 */ 2251 static bool dmarIsIoPageAccessContig(PCDMARIOPAGE pIoPagePrev, PCDMARIOPAGE pIoPage) 2252 { 2253 /* Paranoia: Permissions for pages of a DMA memory request must be identical. */ 2254 Assert(pIoPagePrev->fPerm == pIoPage->fPerm); 2255 2256 size_t const cbPrev = RT_BIT_64(pIoPagePrev->cShift); 2257 RTGCPHYS const GCPhysPrev = pIoPagePrev->GCPhysBase; 2258 RTGCPHYS const GCPhys = pIoPage->GCPhysBase; 2259 uint64_t const offMaskPrev = X86_GET_PAGE_OFFSET_MASK(pIoPagePrev->cShift); 2260 uint64_t const offMask = X86_GET_PAGE_OFFSET_MASK(pIoPage->cShift); 2261 2262 /* Paranoia: Ensure offset bits are 0. */ 2263 Assert(!(GCPhysPrev & offMaskPrev)); 2264 Assert(!(GCPhys & offMask)); 2265 2266 if ((GCPhysPrev & ~offMaskPrev) + cbPrev == (GCPhys & ~offMask)) 2267 return true; 2268 return false; 2269 } 2270 2271 2272 /** 2273 * Looks up the range of addresses for a DMA memory request remapping. 2274 * 2275 * @returns VBox status code. 2276 * @param pDevIns The IOMMU device instance. 2277 * @param pfnTranslate The DMA address translation function. 2278 * @param pMemReqRemap The DMA memory request remapping info. 2279 */ 2280 static int dmarDrMemRangeLookup(PPDMDEVINS pDevIns, PFNDMAADDRTRANSLATE pfnTranslate, PDMARMEMREQREMAP pMemReqRemap) 2281 { 2282 RTGCPHYS GCPhysAddr = NIL_RTGCPHYS; 2283 DMARMEMREQIN MemReqIn = pMemReqRemap->In; 2284 uint64_t const uAddrIn = pMemReqRemap->In.AddrRange.uAddr; 2285 size_t const cbAddrIn = pMemReqRemap->In.AddrRange.cb; 2286 uint64_t uAddrInBase = pMemReqRemap->In.AddrRange.uAddr & X86_PAGE_4K_BASE_MASK; 2287 uint64_t offAddrIn = pMemReqRemap->In.AddrRange.uAddr & X86_PAGE_4K_OFFSET_MASK; 2288 size_t cbRemaining = cbAddrIn; 2289 2290 int rc; 2291 DMARIOPAGE IoPagePrev; 2292 RT_ZERO(IoPagePrev); 2293 for (;;) 2294 { 2295 /* Update the input memory request with the next address in our range that needs translation. */ 2296 MemReqIn.AddrRange.uAddr = uAddrInBase; 2297 MemReqIn.AddrRange.cb = cbRemaining; /* Not currently accessed by pfnTranslate, but keep things consistent. */ 2298 2299 DMARIOPAGE IoPage; 2300 rc = pfnTranslate(pDevIns, &MemReqIn, &pMemReqRemap->Aux, &IoPage); 2301 if (RT_SUCCESS(rc)) 2302 { 2303 Assert(IoPage.cShift >= X86_PAGE_4K_SHIFT); 2304 2305 /* Store the translated address before continuing to access more pages. */ 2306 if (cbRemaining == cbAddrIn) 2307 { 2308 uint64_t const fIoPageMask = X86_GET_PAGE_OFFSET_MASK(IoPage.cShift); 2309 uint64_t const offAddrOut = uAddrIn & fIoPageMask; 2310 Assert(!(IoPage.GCPhysBase & fIoPageMask)); 2311 GCPhysAddr = IoPage.GCPhysBase | offAddrOut; 2312 } 2313 /* Check if addresses translated so far result in a physically contiguous region. */ 2314 else if (!dmarIsIoPageAccessContig(&IoPagePrev, &IoPage)) 2315 { 2316 rc = VERR_OUT_OF_RANGE; 2317 break; 2318 } 2319 2320 /* Store the I/O page lookup from the first/previous access. */ 2321 IoPagePrev = IoPage; 2322 2323 /* Check if we need to access more pages. */ 2324 size_t const cbPage = RT_BIT_64(IoPage.cShift); 2325 if (cbRemaining > cbPage - offAddrIn) 2326 { 2327 cbRemaining -= (cbPage - offAddrIn); /* Calculate how much more we need to access. */ 2328 uAddrInBase += cbPage; /* Update address of the next access. */ 2329 offAddrIn = 0; /* After first page, all pages are accessed from offset 0. */ 2330 } 2331 else 2332 { 2333 /* Caller (PDM) doesn't expect more data accessed than what was requested. */ 2334 cbRemaining = 0; 2335 break; 2336 } 2337 } 2338 else 2339 break; 2340 } 2341 2342 pMemReqRemap->Out.AddrRange.uAddr = GCPhysAddr; 2343 pMemReqRemap->Out.AddrRange.cb = cbAddrIn - cbRemaining; 2344 pMemReqRemap->Out.AddrRange.fPerm = IoPagePrev.fPerm; 2345 return rc; 2346 } 2347 2348 2349 /** 2350 * Handles legacy mode DMA address remapping. 2182 2351 * 2183 2352 * @returns VBox status code. … … 2188 2357 static int dmarDrLegacyModeRemapAddr(PPDMDEVINS pDevIns, uint64_t uRtaddrReg, PDMARMEMREQREMAP pMemReqRemap) 2189 2358 { 2190 Assert(pMemReqRemap-> fTtm == VTD_TTM_LEGACY_MODE); /* Paranoia. */2359 Assert(pMemReqRemap->Aux.fTtm == VTD_TTM_LEGACY_MODE); /* Paranoia. */ 2191 2360 2192 2361 /* Read the root-entry from guest memory. */ 2193 uint8_t const idxRootEntry = RT_HI_U8(pMemReqRemap-> Req.idDevice);2362 uint8_t const idxRootEntry = RT_HI_U8(pMemReqRemap->In.idDevice); 2194 2363 VTD_ROOT_ENTRY_T RootEntry; 2195 2364 int rc = dmarDrReadRootEntry(pDevIns, uRtaddrReg, idxRootEntry, &RootEntry); … … 2208 2377 /* Read the context-entry from guest memory. */ 2209 2378 RTGCPHYS const GCPhysCtxTable = RT_BF_GET(uRootEntryQword0, VTD_BF_0_ROOT_ENTRY_CTP); 2210 uint8_t const idxCtxEntry = RT_LO_U8(pMemReqRemap-> Req.idDevice);2379 uint8_t const idxCtxEntry = RT_LO_U8(pMemReqRemap->In.idDevice); 2211 2380 VTD_CONTEXT_ENTRY_T CtxEntry; 2212 2381 rc = dmarDrReadCtxEntry(pDevIns, GCPhysCtxTable, idxCtxEntry, &CtxEntry); … … 2217 2386 2218 2387 /* Note the FPD bit which software can use to supress translation faults from here on in. */ 2219 pMemReqRemap-> fFpd = RT_BF_GET(uCtxEntryQword0, VTD_BF_0_CONTEXT_ENTRY_FPD);2388 pMemReqRemap->Aux.fFpd = RT_BF_GET(uCtxEntryQword0, VTD_BF_0_CONTEXT_ENTRY_FPD); 2220 2389 2221 2390 /* Check if the context-entry is present (must be done before validating reserved bits). */ … … 2228 2397 { 2229 2398 /* Get the domain ID for this mapping. */ 2230 uint16_t constidDomain = RT_BF_GET(uCtxEntryQword1, VTD_BF_1_CONTEXT_ENTRY_DID);2399 pMemReqRemap->Out.idDomain = RT_BF_GET(uCtxEntryQword1, VTD_BF_1_CONTEXT_ENTRY_DID); 2231 2400 2232 2401 /* Validate the translation type (TT). */ … … 2241 2410 * through SLPTPTR. Translated requests and Translation Requests are blocked. 2242 2411 */ 2243 if (pMemReqRemap-> Req.enmAddrType == PCIADDRTYPE_UNTRANSLATED)2412 if (pMemReqRemap->In.enmAddrType == PCIADDRTYPE_UNTRANSLATED) 2244 2413 { 2245 2414 /* Validate the address width and get the paging level. */ … … 2248 2417 { 2249 2418 /* Read the SLPTPTR from guest memory. */ 2419 VTD_SLP_ENTRY_T SlptPtr; 2250 2420 RTGCPHYS const GCPhysSlptPtr = uCtxEntryQword0 & VTD_BF_0_CONTEXT_ENTRY_SLPTPTR_MASK; 2251 VTD_SLP_ENTRY_T SlpEntry; 2252 rc = dmarDrReadSlpPtr(pDevIns, GCPhysSlptPtr, &SlpEntry); 2421 rc = dmarDrReadSlpPtr(pDevIns, GCPhysSlptPtr, &SlptPtr); 2253 2422 if (RT_SUCCESS(rc)) 2254 2423 { 2255 2424 /* Finally... perform second-level translation. */ 2256 return dmarDrSecondLevelTranslate(pDevIns, SlpEntry, cPagingLevel, idDomain, 2257 pMemReqRemap); 2425 pMemReqRemap->Aux.uSlptPtr = SlptPtr; 2426 pMemReqRemap->Aux.cPagingLevel = cPagingLevel; 2427 return dmarDrMemRangeLookup(pDevIns, dmarDrSecondLevelTranslate, pMemReqRemap); 2258 2428 } 2259 2429 dmarAtFaultRecord(pDevIns, kDmarDiag_Atf_Lct_4_3, VTDATFAULT_LCT_4_3, pMemReqRemap); … … 2276 2446 if (pThis->fExtCapReg & VTD_BF_ECAP_REG_PT_MASK) 2277 2447 { 2278 if (pMemReqRemap-> Req.enmAddrType == PCIADDRTYPE_UNTRANSLATED)2448 if (pMemReqRemap->In.enmAddrType == PCIADDRTYPE_UNTRANSLATED) 2279 2449 { 2280 2450 if (dmarDrLegacyModeIsAwValid(pThis, &CtxEntry, NULL /* pcPagingLevel */)) 2281 2451 { 2282 pMemReqRemap->Iotlbe.GCPhysBase = pMemReqRemap->Req.uDmaAddr & X86_PAGE_4K_BASE_MASK;2283 pMemReqRemap->Iotlbe.cShift = X86_PAGE_4K_SHIFT;2284 p MemReqRemap->Iotlbe.fPerm = DMAR_PERM_ALL;2285 p MemReqRemap->Iotlbe.idDomain = idDomain;2286 p MemReqRemap->cbContiguous = pMemReqRemap->Req.cbDma;2452 PDMARMEMREQOUT pOut = &pMemReqRemap->Out; 2453 PCDMARMEMREQIN pIn = &pMemReqRemap->In; 2454 pOut->AddrRange.uAddr = pIn->AddrRange.uAddr & X86_PAGE_4K_BASE_MASK; 2455 pOut->AddrRange.cb = pIn->AddrRange.cb; 2456 pOut->AddrRange.fPerm = DMAR_PERM_ALL; 2287 2457 return VINF_SUCCESS; 2288 2458 } … … 2431 2601 DMARMEMREQREMAP MemReqRemap; 2432 2602 RT_ZERO(MemReqRemap); 2433 MemReqRemap. Req.uDmaAddr= uIova;2434 MemReqRemap. Req.cbDma= cbIova;2435 MemReqRemap. Req.fReqPerm= fReqPerm;2436 MemReqRemap. Req.idDevice= idDevice;2437 MemReqRemap. Req.Pasid= NIL_PCIPASID;2438 MemReqRemap. Req.enmAddrType= PCIADDRTYPE_UNTRANSLATED;2439 MemReqRemap. Req.enmReqType= enmReqType;2440 MemReqRemap. fTtm= fTtm;2441 MemReqRemap. Iotlbe.GCPhysBase= NIL_RTGCPHYS;2603 MemReqRemap.In.AddrRange.uAddr = uIova; 2604 MemReqRemap.In.AddrRange.cb = cbIova; 2605 MemReqRemap.In.AddrRange.fPerm = fReqPerm; 2606 MemReqRemap.In.idDevice = idDevice; 2607 MemReqRemap.In.Pasid = NIL_PCIPASID; 2608 MemReqRemap.In.enmAddrType = PCIADDRTYPE_UNTRANSLATED; 2609 MemReqRemap.In.enmReqType = enmReqType; 2610 MemReqRemap.Aux.fTtm = fTtm; 2611 MemReqRemap.Out.AddrRange.uAddr = NIL_RTGCPHYS; 2442 2612 2443 2613 int rc; … … 2474 2644 } 2475 2645 2476 *pcbContiguous = MemReqRemap.cbContiguous; 2477 *pGCPhysSpa = MemReqRemap.Iotlbe.GCPhysBase 2478 | (uIova & DMAR_GET_PAGE_OFF_MASK(MemReqRemap.Iotlbe.cShift)); 2646 *pcbContiguous = MemReqRemap.Out.AddrRange.cb; 2647 *pGCPhysSpa = MemReqRemap.Out.AddrRange.uAddr; 2479 2648 return rc; 2480 2649 }
Note:
See TracChangeset
for help on using the changeset viewer.