Changeset 87528 in vbox
- Timestamp:
- Feb 2, 2021 9:56:46 AM (4 years ago)
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/iommu-amd.h
r87343 r87528 1425 1425 struct 1426 1426 { 1427 RT_GCC_EXTENSION uint64_t u52ExclLimit : 52; /**< Bits 51:0 - Exclusion Range Limit (last 12 bits are treated as 1s). */ 1428 RT_GCC_EXTENSION uint64_t u12Rsvd1 : 12; /**< Bits 63:52 - Reserved. */ 1427 RT_GCC_EXTENSION uint64_t u12Rsvd0 : 12; /**< Bits 63:52 - Reserved. */ 1428 RT_GCC_EXTENSION uint64_t u40ExclRangeLimit : 40; /**< Bits 51:12 - Exclusion Range Limit Address. */ 1429 RT_GCC_EXTENSION uint64_t u12Rsvd1 : 12; /**< Bits 63:52 - Reserved (treated as 1s). */ 1429 1430 } n; 1430 1431 /** The 64-bit unsigned integer view. */ -
trunk/src/VBox/Devices/Bus/DevIommuAmd.cpp
r87527 r87528 56 56 # define IOMMU_IOTLB_DOMAIN_ID_SHIFT 40 57 57 #endif 58 59 /** @name IOMMU_DEV_LOOKUP_F_XXX: I/O device lookup flags. 60 * @{ */ 61 /** The device lookup was successful. */ 62 #define IOMMU_DEV_LOOKUP_F_VALID RT_BIT(0) 63 /** Translation required. */ 64 #define IOMMU_DEV_LOOKUP_F_TRANSLATE RT_BIT(1) 65 /** Only DTE permissions apply. */ 66 #define IOMMU_DEV_LOOKUP_F_ONLY_DTE_PERM RT_BIT(2) 67 /** @} */ 58 68 59 69 … … 151 161 */ 152 162 #pragma pack(1) 153 typedef struct IODOMAIN 154 { 155 /** The domain ID assigned by software. */ 163 typedef struct IODEVICE 164 { 165 /** The device lookup flags, see IOMMU_DEV_LOOKUP_F_XXX. */ 166 uint8_t fFlags; 167 /** The DTE permission bits. */ 168 uint8_t fDtePerm; 169 /** The domain ID assigned for this device by software. */ 156 170 uint16_t uDomainId; 157 /** Whether the device ID is valid (if not, lookups must re-read DTE). */ 158 bool fValid; 159 bool afAlignment[1]; 160 } IODOMAIN; 171 } IODEVICE; 161 172 #pragma pack() 162 /** Pointer to an I/O d omainstruct. */163 typedef IOD OMAIN *PIODOMAIN;164 /** Pointer to a const I/O d omainstruct. */165 typedef IOD OMAIN *PCIODOMAIN;166 AssertCompileSize(IOD OMAIN, 4);173 /** Pointer to an I/O device struct. */ 174 typedef IODEVICE *PIODEVICE; 175 /** Pointer to a const I/O device struct. */ 176 typedef IODEVICE *PCIODEVICE; 177 AssertCompileSize(IODEVICE, 4); 167 178 168 179 /** … … 211 222 #ifdef IOMMU_WITH_IOTLBE_CACHE 212 223 /** L1 Cache - Maps [DeviceId] to [DomainId]. */ 213 PIOD OMAIN paDomainIds;224 PIODEVICE paDevices; 214 225 /** Pointer to array of allocated IOTLBEs. */ 215 226 PIOTLBE paIotlbes; … … 387 398 AssertCompileMemberAlignment(IOMMU, hMmio, 8); 388 399 #ifdef IOMMU_WITH_IOTLBE_CACHE 389 AssertCompileMemberAlignment(IOMMU, paD omainIds, 8);400 AssertCompileMemberAlignment(IOMMU, paDevices, 8); 390 401 AssertCompileMemberAlignment(IOMMU, paIotlbes, 8); 391 402 AssertCompileMemberAlignment(IOMMU, TreeIotlbe, 8); … … 771 782 772 783 773 DECL _FORCE_INLINE(IOMMU_STATUS_T) iommuAmdGetStatus(PCIOMMU pThis)784 DECLINLINE(IOMMU_STATUS_T) iommuAmdGetStatus(PCIOMMU pThis) 774 785 { 775 786 IOMMU_STATUS_T Status; … … 779 790 780 791 781 DECL _FORCE_INLINE(IOMMU_CTRL_T) iommuAmdGetCtrl(PCIOMMU pThis)792 DECLINLINE(IOMMU_CTRL_T) iommuAmdGetCtrl(PCIOMMU pThis) 782 793 { 783 794 IOMMU_CTRL_T Ctrl; … … 2560 2571 2561 2572 /** 2562 * Returns whether the I/O virtual address is to be excluded from translation and2563 * permission checks.2564 *2565 * @returns @c true if the DVA is excluded, @c false otherwise.2566 * @param pThis The IOMMU device state.2567 * @param pDte The device table entry.2568 * @param uIova The I/O virtual address.2569 *2570 * @remarks Ensure the exclusion range is enabled prior to calling this function.2571 *2572 * @thread Any.2573 */2574 static bool iommuAmdIsDvaInExclRange(PCIOMMU pThis, PCDTE_T pDte, uint64_t uIova)2575 {2576 /* Ensure the exclusion range is enabled. */2577 Assert(pThis->ExclRangeBaseAddr.n.u1ExclEnable);2578 2579 /* Check if the IOVA falls within the exclusion range. */2580 uint64_t const uIovaExclFirst = pThis->ExclRangeBaseAddr.n.u40ExclRangeBase << X86_PAGE_4K_SHIFT;2581 uint64_t const uIovaExclLast = pThis->ExclRangeLimit.n.u52ExclLimit;2582 if (uIovaExclLast - uIova >= uIovaExclFirst)2583 {2584 /* Check if device access to addresses in the exclusion range can be forwarded untranslated. */2585 if ( pThis->ExclRangeBaseAddr.n.u1AllowAll2586 || pDte->n.u1AllowExclusion)2587 return true;2588 }2589 return false;2590 }2591 2592 2593 /**2594 2573 * Reads a device table entry for the given the device ID. 2595 2574 * … … 2984 2963 2985 2964 /** 2965 * Updates the device lookup flags used for IOTLB caching. 2966 * This is a NOP when IOTLB caching is disabled. 2967 * 2968 * @param pIommu The IOMMU device. 2969 * @param uDevId The device ID. 2970 * @param pDte The DTE. 2971 * @param fFlags The device lookup flags, see IOMMU_DEV_LOOKUP_F_XXX. 2972 */ 2973 DECL_FORCE_INLINE(void) iommuAmdDteLookupUpdate(PIOMMU pIommu, uint16_t uDevId, PCDTE_T pDte, uint8_t fFlags) 2974 { 2975 #ifdef IOMMU_WITH_IOTLBE_CACHE 2976 pIommu->paDevices[uDevId].fFlags = fFlags; 2977 pIommu->paDevices[uDevId].uDomainId = pDte->n.u16DomainId; 2978 pIommu->paDevices[uDevId].fDtePerm = (pDte->au64[0] >> IOMMU_IO_PERM_SHIFT) & IOMMU_IO_PERM_MASK; 2979 #else 2980 RT_NOREF3(pIommu, uDevId, fFlags); 2981 #endif 2982 } 2983 2984 2985 /** 2986 2986 * Looks up an I/O virtual address from the device table. 2987 2987 * … … 3022 3022 if (RT_LIKELY(!fRsvd0 && !fRsvd1)) 3023 3023 { 3024 /* If the IOVA is subject to address exclusion, addresses are forwarded without translation. */ 3025 if ( !pThis->ExclRangeBaseAddr.n.u1ExclEnable /** @todo lock or make atomic read! */ 3026 || !iommuAmdIsDvaInExclRange(pThis, &Dte, uIova)) 3024 /* Note: Addresses are not subject to exclusion as we do -not- support remote IOTLBs. */ 3025 IOWALKRESULT WalkResult; 3026 RT_ZERO(WalkResult); 3027 rc = iommuAmdPreTranslateChecks(pDevIns, uDevId, uIova, fPerm, &Dte, enmOp, &WalkResult); 3028 if (rc == VINF_SUCCESS) 3027 3029 { 3028 IOWALKRESULT WalkResult; 3029 RT_ZERO(WalkResult); 3030 rc = iommuAmdPreTranslateChecks(pDevIns, uDevId, uIova, fPerm, &Dte, enmOp, &WalkResult); 3031 if (rc == VINF_SUCCESS) 3030 /* Walk the I/O page tables to translate the IOVA and check permissions for the 3031 remaining pages in the access. */ 3032 size_t cbRemaining = cbAccess; 3033 uint64_t uIovaPage = uIova & X86_PAGE_4K_BASE_MASK; 3034 uint64_t offIova = uIova & X86_PAGE_4K_OFFSET_MASK; 3035 uint64_t cbPages = 0; 3036 IOWALKRESULT WalkResultPrev; 3037 RT_ZERO(WalkResultPrev); 3038 for (;;) 3032 3039 { 3033 /* Walk the I/O page tables to translate the IOVA and check permissions for the 3034 remaining pages in the access. */ 3035 size_t cbRemaining = cbAccess; 3036 uint64_t uIovaPage = uIova & X86_PAGE_4K_BASE_MASK; 3037 uint64_t offIova = uIova & X86_PAGE_4K_OFFSET_MASK; 3038 uint64_t cbPages = 0; 3039 IOWALKRESULT WalkResultPrev; 3040 RT_ZERO(WalkResultPrev); 3041 for (;;) 3040 rc = iommuAmdIoPageTableWalk(pDevIns, uDevId, uIovaPage, fPerm, &Dte, enmOp, &WalkResult); 3041 if (RT_SUCCESS(rc)) 3042 3042 { 3043 rc = iommuAmdIoPageTableWalk(pDevIns, uDevId, uIovaPage, fPerm, &Dte, enmOp, &WalkResult); 3044 if (RT_SUCCESS(rc)) 3043 /* Store the translated address before continuing to access more pages. */ 3044 Assert(WalkResult.cShift >= X86_PAGE_4K_SHIFT); 3045 if (cbRemaining == cbAccess) 3045 3046 { 3046 /* Store the translated address before continuing to access more pages. */ 3047 Assert(WalkResult.cShift >= X86_PAGE_4K_SHIFT); 3048 if (cbRemaining == cbAccess) 3049 { 3050 uint64_t const offMask = ~(UINT64_C(0xffffffffffffffff) << WalkResult.cShift); 3051 uint64_t const offSpa = uIova & offMask; 3052 Assert(!(WalkResult.GCPhysSpa & offMask)); 3053 GCPhysSpa = WalkResult.GCPhysSpa | offSpa; 3054 3055 /* Store the walk result from the first page. */ 3056 WalkResultPrev = WalkResult; 3057 } 3058 /* Check if addresses translated so far result in a physically contiguous region. */ 3059 else if (iommuAmdDteLookupIsAccessContig(&WalkResultPrev, &WalkResult)) 3060 WalkResultPrev = WalkResult; 3061 else 3062 { 3063 STAM_COUNTER_INC(&pThis->StatDteLookupNonContig); 3064 break; 3065 } 3066 3067 /* Check if we need to access more pages. */ 3068 uint64_t const cbPage = RT_BIT_64(WalkResult.cShift); 3069 if (cbRemaining > cbPage - offIova) 3070 { 3071 cbRemaining -= (cbPage - offIova); /* Calculate how much more we need to access. */ 3072 cbPages += cbPage; /* Update size of all pages read thus far. */ 3073 uIovaPage += cbPage; /* Update address of the next access. */ 3074 offIova = 0; /* After first page, all pages are accessed from off 0. */ 3075 } 3076 else 3077 { 3078 cbRemaining = 0; 3079 break; 3080 } 3047 uint64_t const offMask = ~(UINT64_C(0xffffffffffffffff) << WalkResult.cShift); 3048 uint64_t const offSpa = uIova & offMask; 3049 Assert(!(WalkResult.GCPhysSpa & offMask)); 3050 GCPhysSpa = WalkResult.GCPhysSpa | offSpa; 3051 3052 /* Store the walk result from the first page. */ 3053 WalkResultPrev = WalkResult; 3054 } 3055 /* Check if addresses translated so far result in a physically contiguous region. */ 3056 else if (iommuAmdDteLookupIsAccessContig(&WalkResultPrev, &WalkResult)) 3057 WalkResultPrev = WalkResult; 3058 else 3059 { 3060 STAM_COUNTER_INC(&pThis->StatDteLookupNonContig); 3061 break; 3062 } 3063 3064 /* Check if we need to access more pages. */ 3065 uint64_t const cbPage = RT_BIT_64(WalkResult.cShift); 3066 if (cbRemaining > cbPage - offIova) 3067 { 3068 cbRemaining -= (cbPage - offIova); /* Calculate how much more we need to access. */ 3069 cbPages += cbPage; /* Update size of all pages read thus far. */ 3070 uIovaPage += cbPage; /* Update address of the next access. */ 3071 offIova = 0; /* After first page, all pages are accessed from off 0. */ 3081 3072 } 3082 3073 else 3083 3074 { 3084 /* Translation failed. */ 3085 GCPhysSpa = NIL_RTGCPHYS; 3086 cbRemaining = cbAccess; 3075 cbRemaining = 0; 3087 3076 break; 3088 3077 } 3089 3078 } 3090 3091 /* Update how much contiguous memory was accessed. */ 3092 cbContiguous = cbAccess - cbRemaining; 3079 else 3080 { 3081 /* Translation failed. */ 3082 GCPhysSpa = NIL_RTGCPHYS; 3083 cbRemaining = cbAccess; 3084 break; 3085 } 3093 3086 } 3094 else if (rc == VINF_IOMMU_ADDR_TRANSLATION_DISABLED) 3095 { 3096 /* Translation is disabled for this device (root paging mode is 0). */ 3097 GCPhysSpa = uIova; 3098 cbContiguous = cbAccess; 3099 rc = VINF_SUCCESS; 3100 3101 /* Paranoia. */ 3102 Assert(WalkResult.cShift == 0); 3103 Assert(WalkResult.GCPhysSpa == uIova); 3104 Assert((WalkResult.fPerm & fPerm) == fPerm); 3105 /** @todo IOMMU: Add to IOLTB cache. */ 3106 } 3107 else 3108 { 3109 /* Translation failed or access is denied. */ 3110 GCPhysSpa = NIL_RTGCPHYS; 3111 cbContiguous = 0; 3112 Assert(RT_FAILURE(rc)); 3113 } 3087 3088 /* Update how much contiguous memory was accessed. */ 3089 cbContiguous = cbAccess - cbRemaining; 3090 3091 /* Update that addresses requires translation (cumulative permissions of DTE and I/O page tables apply). */ 3092 iommuAmdDteLookupUpdate(pThis, uDevId, &Dte, IOMMU_DEV_LOOKUP_F_VALID | IOMMU_DEV_LOOKUP_F_TRANSLATE); 3093 } 3094 else if (rc == VINF_IOMMU_ADDR_TRANSLATION_DISABLED) 3095 { 3096 /* 3097 * Translation is disabled for this device (root paging mode is 0). 3098 * GPA=SPA, but the permission bits are important and controls accesses. 3099 */ 3100 /* . */ 3101 GCPhysSpa = uIova; 3102 cbContiguous = cbAccess; 3103 rc = VINF_SUCCESS; 3104 3105 /* Paranoia. */ 3106 Assert(WalkResult.cShift == 0); 3107 Assert(WalkResult.GCPhysSpa == uIova); 3108 Assert((WalkResult.fPerm & fPerm) == fPerm); 3109 3110 /* Update that addresses don't require translation (only permissions of DTE apply). */ 3111 iommuAmdDteLookupUpdate(pThis, uDevId, &Dte, IOMMU_DEV_LOOKUP_F_VALID | IOMMU_DEV_LOOKUP_F_ONLY_DTE_PERM); 3114 3112 } 3115 3113 else 3116 3114 { 3117 /* T he IOVA is subject to address exclusion, forward untranslated. */3118 /** @todo IOMMU: Add to IOLTB cache. */3119 GCPhysSpa = uIova;3120 cbContiguous = cbAccess;3115 /* Translation failed or access is denied. */ 3116 GCPhysSpa = NIL_RTGCPHYS; 3117 cbContiguous = 0; 3118 Assert(RT_FAILURE(rc)); 3121 3119 } 3122 3120 } … … 3137 3135 * See AMD IOMMU spec. "Table 5: Feature Enablement for Address Translation". 3138 3136 */ 3139 /** @todo IOMMU: Add to IOLTB cache. */3140 3137 GCPhysSpa = uIova; 3141 3138 cbContiguous = cbAccess; 3139 3140 /* Update that addresses don't require translation (nor any permissions). */ 3141 iommuAmdDteLookupUpdate(pThis, uDevId, &Dte, IOMMU_DEV_LOOKUP_F_VALID); 3142 3142 } 3143 3143 } … … 3312 3312 return VINF_SUCCESS; 3313 3313 } 3314 3315 3314 3316 3315 … … 4248 4247 pHlp->pfnPrintf(pHlp, " Exclusion Range Limit = %#RX64\n", ExclRangeLimit.u64); 4249 4248 if (fVerbose) 4250 pHlp->pfnPrintf(pHlp, " Range limit = %#RX64\n", ExclRangeLimit.n.u52ExclLimit); 4249 { 4250 pHlp->pfnPrintf(pHlp, " Range limit = %#RX64\n", 4251 (ExclRangeLimit.n.u40ExclRangeLimit << X86_PAGE_4K_SHIFT) | X86_PAGE_4K_OFFSET_MASK); 4252 } 4251 4253 } 4252 4254 /* Extended Feature Register. */ … … 4996 4998 #ifdef IOMMU_WITH_IOTLBE_CACHE 4997 4999 /* Destroy level 1 cache. */ 4998 if (pThis->paD omainIds)4999 { 5000 PDMDevHlpMMHeapFree(pDevIns, pThis->paD omainIds);5001 pThis->paD omainIds = NULL;5000 if (pThis->paDevices) 5001 { 5002 PDMDevHlpMMHeapFree(pDevIns, pThis->paDevices); 5003 pThis->paDevices = NULL; 5002 5004 } 5003 5005 … … 5247 5249 * of how code, features and devices around the IOMMU changes. 5248 5250 */ 5249 size_t const cbD omains = sizeof(IODOMAIN) * UINT16_MAX;5250 pThis->paD omainIds = (PIODOMAIN)PDMDevHlpMMHeapAllocZ(pDevIns, cbDomains);5251 if (!pThis->paD omainIds)5251 size_t const cbDevices = sizeof(IODEVICE) * UINT16_MAX; 5252 pThis->paDevices = (PIODEVICE)PDMDevHlpMMHeapAllocZ(pDevIns, cbDevices); 5253 if (!pThis->paDevices) 5252 5254 { 5253 5255 return PDMDevHlpVMSetError(pDevIns, VERR_NO_MEMORY, RT_SRC_POS, 5254 N_("Failed to allocate %zu bytes from the hyperheap for the IOMMU level 1 cache."), 5255 cbDomains); 5256 N_("Failed to allocate %zu bytes from the hyperheap for the IOMMU level 1 cache."), cbDevices); 5256 5257 } 5257 5258 … … 5274 5275 RTListInit(&pThis->LstLruIotlbe); 5275 5276 5276 LogRel(("%s: Allocated %zu bytes from the hyperheap for the IOTLB cache\n", IOMMU_LOG_PFX, cbD omains + cbIotlbes));5277 LogRel(("%s: Allocated %zu bytes from the hyperheap for the IOTLB cache\n", IOMMU_LOG_PFX, cbDevices + cbIotlbes)); 5277 5278 #endif 5278 5279
Note:
See TracChangeset
for help on using the changeset viewer.