Changeset 89552 in vbox
- Timestamp:
- Jun 8, 2021 5:35:06 AM (3 years ago)
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/iommu-intel.h
r89430 r89552 250 250 /** Pointer to a const context entry. */ 251 251 typedef VTD_CONTEXT_ENTRY_T const *PCVTD_CONTEXT_ENTRY_T; 252 AssertCompileSize(VTD_CONTEXT_ENTRY_T, 16); 252 253 253 254 /** Context Entry: Qword 0 valid mask. */ … … 511 512 RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_FLP_ENTRY_, UINT64_C(0), UINT64_MAX, 512 513 (P, RW, US, PWT, PCD, A, IGN_6, RSVD_7, IGN_9_8, EA, IGN_11, ADDR, IGN_62_52, XD)); 513 514 /** First-Level Paging Entry. */515 typedef uint64_t VTD_FLP_ENTRY_T;516 514 /** @} */ 517 515 … … 894 892 | VTD_BF_SL_PTE_IGN_10_MASK | VTD_BF_SL_PTE_ADDR_MASK \ 895 893 | VTD_BF_SL_PTE_IGN_61_52_MASK | VTD_BF_SL_PTE_IGN_63_MASK) 896 /** @} */897 898 899 /** @name Second-Level Generic Paging Entry.900 * In accordance with the Intel spec.901 * @{ */902 /** Second-Level Paging Entry. */903 typedef uint64_t VTD_SLP_ENTRY_T;904 /** Pointer to a second-level paging entry. */905 typedef uint64_t *PVTD_SLP_ENTRY_T;906 /** Pointer to a const second-level paging entry. */907 typedef uint64_t const *CPVTD_SLP_ENTRY_T;908 894 /** @} */ 909 895 -
trunk/src/VBox/Devices/Bus/DevIommuIntel.cpp
r89548 r89552 187 187 kDmarDiag_At_Lm_RootEntry_Read_Failed, 188 188 kDmarDiag_At_Lm_RootEntry_Rsvd, 189 kDmarDiag_At_Lm_Slpptr_Read_Failed,190 189 kDmarDiag_At_Lm_Tt_Invalid, 191 190 kDmarDiag_At_Lm_Ut_At_Block, … … 200 199 kDmarDiag_At_Xm_Pte_Sllps_Invalid, 201 200 kDmarDiag_At_Xm_Read_Pte_Failed, 201 kDmarDiag_At_Xm_Slpptr_Read_Failed, 202 202 203 203 /* CCMD_REG faults. */ … … 261 261 DMARDIAG_DESC(At_Lm_RootEntry_Read_Failed), 262 262 DMARDIAG_DESC(At_Lm_RootEntry_Rsvd ), 263 DMARDIAG_DESC(At_Lm_Slpptr_Read_Failed ),264 263 DMARDIAG_DESC(At_Lm_Tt_Invalid ), 265 264 DMARDIAG_DESC(At_Lm_Ut_At_Block ), … … 274 273 DMARDIAG_DESC(At_Xm_Pte_Sllps_Invalid ), 275 274 DMARDIAG_DESC(At_Xm_Read_Pte_Failed ), 275 DMARDIAG_DESC(At_Xm_Slpptr_Read_Failed ), 276 276 277 277 /* CCMD_REG faults. */ … … 555 555 uint8_t cPagingLevel; 556 556 uint8_t afPadding[5]; 557 /** The first-level page-table pointer. */558 uint64_t uFlPtPtr;559 /** The second-level page-table pointer. */560 uint64_t uSlPtPtr;557 /** The address of the first-level page-table. */ 558 uint64_t GCPhysFlPt; 559 /** The address of second-level page-table. */ 560 uint64_t GCPhysSlPt; 561 561 } DMARMEMREQAUX; 562 562 /** Pointer to a DMA memory request output. */ … … 1617 1617 case kDmarDiag_At_Lm_RootEntry_Read_Failed: enmAtFault = VTDATFAULT_LRT_1; break; 1618 1618 case kDmarDiag_At_Lm_RootEntry_Rsvd: enmAtFault = VTDATFAULT_LRT_3; break; 1619 case kDmarDiag_At_Lm_Slpptr_Read_Failed: enmAtFault = VTDATFAULT_LCT_4_3; break;1620 1619 case kDmarDiag_At_Lm_Tt_Invalid: enmAtFault = VTDATFAULT_LCT_4_2; break; 1621 1620 case kDmarDiag_At_Lm_Ut_At_Block: enmAtFault = VTDATFAULT_LCT_5; break; … … 1634 1633 case kDmarDiag_At_Xm_Pte_Sllps_Invalid: enmAtFault = fLm ? VTDATFAULT_LSL_2 : VTDATFAULT_SSL_3; break; 1635 1634 case kDmarDiag_At_Xm_Read_Pte_Failed: enmAtFault = fLm ? VTDATFAULT_LSL_1 : VTDATFAULT_SSL_1; break; 1635 case kDmarDiag_At_Xm_Slpptr_Read_Failed: enmAtFault = fLm ? VTDATFAULT_LCT_4_3 : VTDATFAULT_SSL_4; break; 1636 1636 1637 1637 /* Shouldn't ever happen. */ … … 2110 2110 2111 2111 /** 2112 * Reads a second-level page-table pointer from guest memory.2113 *2114 * @returns VBox status code.2115 * @param pDevIns The IOMMU device instance.2116 * @param GCPhysSlPtPtr The physical address of the SLPTPTR.2117 * @param pSlpEntry Where to store the read SLPTPTR.2118 */2119 static int dmarDrReadSecondLevelPtPtr(PPDMDEVINS pDevIns, RTGCPHYS GCPhysSlPtPtr, PVTD_SLP_ENTRY_T pSlpEntry)2120 {2121 /* We don't verify bits 63:HAW of GCPhysSlPtPtr is 0 since reading from such an address should fail anyway. */2122 return PDMDevHlpPhysReadMeta(pDevIns, GCPhysSlPtPtr, pSlpEntry, sizeof(*pSlpEntry));2123 }2124 2125 2126 /**2127 2112 * Validates and updates the output I/O page of a translation. 2128 2113 * … … 2156 2141 2157 2142 /** 2158 * Performs second level translation .2159 * 2160 * This is a DMA address 2143 * Performs second level translation by walking the I/O page tables. 2144 * 2145 * This is a DMA address-lookup callback function which performs the translation 2161 2146 * (and access control) as part of the lookup. 2162 2147 * … … 2203 2188 * Unlike AMD IOMMU paging, here there is no feature for "skipping" levels. 2204 2189 */ 2205 uint64_t uPtEntity = pMemReqAux->uSlPtPtr; 2206 int8_t iLevel = pMemReqAux->cPagingLevel - 1; 2207 uint8_t cLevelShift = X86_PAGE_4K_SHIFT + (iLevel * 9); 2208 Assert(iLevel >= 2); 2209 for (;;) 2210 { 2190 uint64_t uPtEntity = pMemReqAux->GCPhysSlPt; 2191 for (int8_t idxLevel = pMemReqAux->cPagingLevel - 1; idxLevel >= 0; idxLevel--) 2192 { 2193 /* 2194 * Read the paging entry for the current level. 2195 */ 2196 uint8_t const cLevelShift = X86_PAGE_4K_SHIFT + (idxLevel * 9); 2197 { 2198 uint64_t const idxPte = (uAddrIn >> cLevelShift) & UINT64_C(0x1ff); 2199 uint64_t const offPte = idxPte << 3; 2200 RTGCPHYS const GCPhysPtEntity = (uPtEntity & X86_PAGE_BASE_MASK) | offPte; 2201 int const rc = PDMDevHlpPhysReadMeta(pDevIns, GCPhysPtEntity, &uPtEntity, sizeof(uPtEntity)); 2202 if (RT_SUCCESS(rc)) 2203 { /* likely */ } 2204 else 2205 { 2206 if ((GCPhysPtEntity & X86_PAGE_BASE_MASK) == pMemReqAux->GCPhysSlPt) 2207 dmarAtFaultRecord(pDevIns, kDmarDiag_At_Xm_Slpptr_Read_Failed, pMemReqIn, pMemReqAux); 2208 else 2209 dmarAtFaultRecord(pDevIns, kDmarDiag_At_Xm_Read_Pte_Failed, pMemReqIn, pMemReqAux); 2210 break; 2211 } 2212 } 2213 2211 2214 /* 2212 2215 * Check I/O permissions. 2213 2216 * This must be done prior to check reserved bits for properly reporting errors SSL.2 and SSL.3. 2214 *2215 2217 * See Intel spec. 7.1.3 "Fault conditions and Remapping hardware behavior for various request". 2216 2218 */ … … 2230 2232 * Validate reserved bits of the current paging entry. 2231 2233 */ 2232 if (!(uPtEntity & ~s_auPtEntityRsvd[i Level]))2234 if (!(uPtEntity & ~s_auPtEntityRsvd[idxLevel])) 2233 2235 { /* likely */ } 2234 2236 else … … 2243 2245 AssertCompile(VTD_BF_SL_PDE_PS_MASK == VTD_BF_SL_PDPE_PS_MASK); 2244 2246 uint8_t const fLargePage = RT_BF_GET(uPtEntity, VTD_BF_SL_PDE_PS); 2245 if (fLargePage && i Level > 0)2247 if (fLargePage && idxLevel > 0) 2246 2248 { 2247 Assert(i Level == 1 || iLevel == 2);/* Is guaranteed by the reserved bits check above. */2249 Assert(idxLevel == 1 || idxLevel == 2); /* Is guaranteed by the reserved bits check above. */ 2248 2250 uint8_t const fSllpsMask = RT_BF_GET(pThis->fCapReg, VTD_BF_CAP_REG_SLLPS); 2249 if (fSllpsMask & RT_BIT(i Level - 1))2251 if (fSllpsMask & RT_BIT(idxLevel - 1)) 2250 2252 { 2251 2253 /* … … 2267 2269 * If this is the final PTE, compute the translation address and we're done. 2268 2270 */ 2269 if (i Level == 0)2271 if (idxLevel == 0) 2270 2272 { 2271 2273 RTGCPHYS const GCPhysBase = uPtEntity & X86_GET_PAGE_BASE_MASK(cLevelShift); 2272 2274 return dmarDrUpdateIoPageOut(pDevIns, GCPhysBase, cLevelShift, fPtPerm, pMemReqIn, pMemReqAux, pIoPageOut); 2273 }2274 2275 /*2276 * Move to the next level.2277 */2278 --iLevel;2279 cLevelShift = X86_PAGE_4K_SHIFT + (iLevel * 9);2280 2281 /*2282 * Read the paging entry for the next level.2283 */2284 {2285 uint16_t const idxPte = (uAddrIn >> cLevelShift) & UINT64_C(0x1ff);2286 uint64_t const offPte = idxPte << 3;2287 RTGCPHYS const GCPhysPtEntity = uPtEntity | offPte;2288 int const rc = PDMDevHlpPhysReadMeta(pDevIns, GCPhysPtEntity, &uPtEntity, sizeof(uPtEntity));2289 if (RT_SUCCESS(rc))2290 { /* likely */ }2291 else2292 {2293 dmarAtFaultRecord(pDevIns, kDmarDiag_At_Xm_Read_Pte_Failed, pMemReqIn, pMemReqAux);2294 break;2295 }2296 2275 } 2297 2276 } … … 2340 2319 static int dmarDrMemRangeLookup(PPDMDEVINS pDevIns, PFNDMADDRLOOKUP pfnLookup, PDMARMEMREQREMAP pMemReqRemap) 2341 2320 { 2321 AssertPtr(pfnLookup); 2322 2342 2323 RTGCPHYS GCPhysAddr = NIL_RTGCPHYS; 2343 2324 DMARMEMREQIN MemReqIn = pMemReqRemap->In; … … 2479 2460 if (dmarDrLegacyModeIsAwValid(pThis, &CtxEntry, &cPagingLevel)) 2480 2461 { 2481 /* Read the SLPTPTR from guest memory. */ 2482 VTD_SLP_ENTRY_T SlPtPtr; 2483 RTGCPHYS const GCPhysSlPtPtr = uCtxEntryQword0 & VTD_BF_0_CONTEXT_ENTRY_SLPTPTR_MASK; 2484 rc = dmarDrReadSecondLevelPtPtr(pDevIns, GCPhysSlPtPtr, &SlPtPtr); 2485 if (RT_SUCCESS(rc)) 2486 { 2487 /* Finally... perform second-level translation. */ 2488 pMemReqAux->uSlPtPtr = SlPtPtr; 2489 pMemReqAux->cPagingLevel = cPagingLevel; 2490 return dmarDrMemRangeLookup(pDevIns, dmarDrSecondLevelTranslate, pMemReqRemap); 2491 } 2492 dmarAtFaultRecord(pDevIns, kDmarDiag_At_Lm_Slpptr_Read_Failed, pMemReqIn, pMemReqAux); 2462 /* 2463 * The second-level page table is located at the physical address specified 2464 * in the context entry with which we can finally perform second-level translation. 2465 */ 2466 pMemReqAux->cPagingLevel = cPagingLevel; 2467 pMemReqAux->GCPhysSlPt = uCtxEntryQword0 & VTD_BF_0_CONTEXT_ENTRY_SLPTPTR_MASK; 2468 Assert(!(pMemReqAux->GCPhysSlPt & X86_PAGE_OFFSET_MASK)); 2469 return dmarDrMemRangeLookup(pDevIns, dmarDrSecondLevelTranslate, pMemReqRemap); 2493 2470 } 2494 2471 else
Note:
See TracChangeset
for help on using the changeset viewer.