- Timestamp:
- May 9, 2020 6:02:47 PM (5 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Bus/DevIommuAmd.cpp
r84225 r84227 3964 3964 * @returns VBox status code. 3965 3965 * @param pDevIns The IOMMU device instance. 3966 * @param uIova The I/O virtual address to translate. 3966 * @param uIova The I/O virtual address to translate. Must be 4K aligned! 3967 3967 * @param uDevId The device ID. 3968 * @param cbAccess The size of the access.3969 3968 * @param fAccess The access permissions (IOMMU_IO_PERM_XXX). This is the 3970 3969 * permissions for the access being made. … … 3976 3975 * @thread Any. 3977 3976 */ 3978 static int iommuAmdWalkIoPageTables(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uIova, size_t cbAccess, uint8_t fAccess, 3979 PCDTE_T pDte, IOMMUOP enmOp, PIOTLBE_T pIotlbe) 3980 { 3981 NOREF(cbAccess); 3977 static int iommuAmdWalkIoPageTables(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uIova, uint8_t fAccess, PCDTE_T pDte, 3978 IOMMUOP enmOp, PIOTLBE_T pIotlbe) 3979 { 3982 3980 Assert(pDte->n.u1Valid); 3981 /* The input I/O virtual address must be 4K page aligned. */ 3982 Assert(!(uIova & X86_PAGE_4K_OFFSET_MASK)); 3983 3983 3984 3984 /* If the translation is not valid, raise an I/O page fault. */ … … 4038 4038 return VERR_IOMMU_ADDR_TRANSLATION_FAILED; 4039 4039 } 4040 4041 /** @todo IOMMU: Split the rest of this into a separate function called 4042 * iommuAmdWalkIoPageDirectory() and call it for multi-page accesses. We can 4043 * avoid re-checking the DTE root-page table entry every time. */ 4040 4044 4041 4045 /* The virtual address bits indexing table. */ … … 4190 4194 } 4191 4195 4192 return VERR_NOT_IMPLEMENTED; 4196 /* Shouldn't really get here. */ 4197 return VERR_IOMMU_IPE_3; 4193 4198 } 4194 4199 … … 4202 4207 * @param uIova The I/O virtual address to lookup. 4203 4208 * @param cbAccess The size of the access. 4209 * @param fAccess The access permissions (IOMMU_IO_PERM_XXX). This is the 4210 * permissions for the access being made. 4204 4211 * @param enmOp The IOMMU operation being performed. 4205 * @param pIotlbe The IOTLBE to update. Only updated when VINF_SUCCESS is 4206 * returned, see remarks. 4207 * 4208 * @remarks Only the translated address and permission bits are updated in @a 4209 * pIotlbe when this function returns VINF_SUCCESS. Caller is expected to 4210 * have updated any other the fields already. 4212 * @param pGCPhysSpa Where to store the translated system physical address. Only 4213 * valid when translation succeeds and VINF_SUCCESS is 4214 * returned! 4211 4215 * 4212 4216 * @thread Any. 4213 4217 */ 4214 static int iommuAmdLookupDeviceTables(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uIova, size_t cbAccess, IOMMUOP enmOp, 4215 PIOTLBE_T pIotlbe) 4216 { 4217 Assert(pIotlbe->uMagic == IOMMU_IOTLBE_MAGIC); 4218 static int iommuAmdLookupDeviceTables(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uIova, size_t cbAccess, uint8_t fAccess, 4219 IOMMUOP enmOp, PRTGCPHYS pGCPhysSpa) 4220 { 4218 4221 PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU); 4219 4222 … … 4228 4231 else 4229 4232 { 4230 iommuAmdUpdateIotlbe(uIova, 0 /* cShift */, IOMMU_IO_PERM_READ_WRITE, pIotlbe);4233 *pGCPhysSpa = uIova; 4231 4234 return VINF_SUCCESS; 4232 4235 } … … 4253 4256 else 4254 4257 { 4255 iommuAmdUpdateIotlbe(uIova, 0 /* cShift */, IOMMU_IO_PERM_READ_WRITE, pIotlbe);4258 *pGCPhysSpa = uIova; 4256 4259 return VINF_SUCCESS; 4257 4260 } 4258 4261 4259 /* Walk the I/O page tables to translate and get permission bits for the IOVA access. */ 4260 rc = iommuAmdWalkIoPageTables(pDevIns, uDevId, uIova, cbAccess, IOMMU_IO_PERM_READ, &Dte, enmOp, pIotlbe); 4261 if (RT_FAILURE(rc)) 4262 Log((IOMMU_LOG_PFX ": I/O page table walk failed. rc=%Rrc\n")); 4262 /** @todo IOMMU: Perhaps do the <= 4K access case first, if the generic loop 4263 * below gets too expensive and when we have iommuAmdWalkIoPageDirectory. */ 4264 4265 IOTLBE_T Iotlbe; 4266 iommuAmdInitIotlbe(NIL_RTGCPHYS, 0 /* cShift */, IOMMU_IO_PERM_NONE, &Iotlbe); 4267 4268 uint64_t cbChecked = 0; 4269 uint64_t uBaseIova = uIova & X86_PAGE_4K_BASE_MASK; 4270 for (;;) 4271 { 4272 /* Walk the I/O page tables to translate and get permission bits for the IOVA access. */ 4273 rc = iommuAmdWalkIoPageTables(pDevIns, uDevId, uBaseIova, fAccess, &Dte, enmOp, &Iotlbe); 4274 if (RT_SUCCESS(rc)) 4275 { 4276 /* Record the translated base address (before continuing to check permission bits of any subsequent pages). */ 4277 if (cbChecked == 0) 4278 *pGCPhysSpa = Iotlbe.GCPhysSpa; 4279 4280 /** @todo IOMMU: Split large pages into 4K IOTLB entries and add to IOTLB cache. */ 4281 4282 uint64_t const cbPhysPage = UINT64_C(1) << Iotlbe.cShift; 4283 cbChecked += cbPhysPage; 4284 if (cbAccess <= cbChecked) 4285 break; 4286 uBaseIova += cbPhysPage; 4287 } 4288 else 4289 { 4290 Log((IOMMU_LOG_PFX ": I/O page table walk failed. uIova=%#RX64 uBaseIova=%#RX64 fAccess=%u rc=%Rrc\n", 4291 uIova, uBaseIova, fAccess, rc)); 4292 *pGCPhysSpa = NIL_RTGCPHYS; 4293 return rc; 4294 } 4295 } 4263 4296 4264 4297 return rc; … … 4294 4327 if (Ctrl.n.u1IommuEn) 4295 4328 { 4296 IOTLBE_T Iotlbe;4297 iommuAmdInitIotlbe(NIL_RTGCPHYS, 0 /* cShift */, IOMMU_IO_PERM_NONE, &Iotlbe);4298 4299 4329 /** @todo IOMMU: IOTLB cache lookup. */ 4300 4330 4301 4331 /* Lookup the IOVA from the device tables. */ 4302 int rc = iommuAmdLookupDeviceTables(pDevIns, uDevId, uIova, cbRead, IOMMUOP_MEM_READ, &Iotlbe); 4303 4304 /** @todo IOMMU: Cache translation. */ 4305 4306 *pGCPhysSpa = Iotlbe.GCPhysSpa; 4307 return rc; 4332 return iommuAmdLookupDeviceTables(pDevIns, uDevId, uIova, cbRead, IOMMU_IO_PERM_READ, IOMMUOP_MEM_READ, pGCPhysSpa); 4308 4333 } 4309 4334
Note:
See TracChangeset
for help on using the changeset viewer.