Changeset 84101 in vbox for trunk/src/VBox/Devices
- Timestamp:
- Apr 30, 2020 12:54:05 PM (5 years ago)
- svn:sync-xref-src-repo-rev:
- 137690
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Bus/DevIommuAmd.cpp
r84089 r84101 569 569 /** The 32-bit unsigned integer view. */ 570 570 uint32_t au32[8]; 571 /** The 64-bit unsigned integer view. */ 572 uint64_t au64[4]; 571 573 } DEV_TAB_ENTRY_T; 572 574 AssertCompileSize(DEV_TAB_ENTRY_T, 32); 575 #define IOMMU_DEV_TAB_ENTRY_QWORD_0_VALID_MASK UINT64_C(0x7fffffffffffff83) 576 #define IOMMU_DEV_TAB_ENTRY_QWORD_1_VALID_MASK UINT64_C(0xfffffbffffffffff) 577 #define IOMMU_DEV_TAB_ENTRY_QWORD_2_VALID_MASK UINT64_C(0xf70fffffffffffff) 578 #define IOMMU_DEV_TAB_ENTRY_QWORD_3_VALID_MASK UINT64_C(0xffc0000000000000) 579 /** Pointer to a device table entry. */ 580 typedef DEV_TAB_ENTRY_T *PDEVTAB_ENTRY_T; 581 /** Pointer to a const device table entry. */ 582 typedef DEV_TAB_ENTRY_T const *PCDEV_TAB_ENTRY_T; 573 583 574 584 /** … … 843 853 844 854 /** 845 * Event logtypes.846 * In accordance with the AMD spec. 847 */ 848 typedef enum EVTLOGTYPE849 { 850 EVTLOGTYPE_RSVD = 0,851 EVTLOGTYPE_MASTER_ABORT,852 EVTLOGTYPE_TARGET_ABORT,853 EVTLOGTYPE_DATA_ERROR854 } EVTLOGTYPE;855 AssertCompileSize( EVTLOGTYPE, 4);855 * Hardware event types. 856 * In accordance with the AMD spec. 857 */ 858 typedef enum HWEVTTYPE 859 { 860 HWEVTTYPE_RSVD = 0, 861 HWEVTTYPE_MASTER_ABORT, 862 HWEVTTYPE_TARGET_ABORT, 863 HWEVTTYPE_DATA_ERROR 864 } HWEVTTYPE; 865 AssertCompileSize(HWEVTTYPE, 4); 856 866 857 867 /** … … 873 883 uint16_t u1ReadWrite : 1; /**< Bit 53 - RW: Read/Write. */ 874 884 uint16_t u1Rsvd1 : 1; /**< Bit 54 - Reserved. */ 875 uint16_t u1Rsvd Zero : 1;/**< Bit 55 - RZ: Reserved bit not Zero or invalid level encoding. */885 uint16_t u1RsvdNotZero : 1; /**< Bit 55 - RZ: Reserved bit not Zero or invalid level encoding. */ 876 886 uint16_t u1Translation : 1; /**< Bit 56 - TN: Translation. */ 877 887 uint16_t u3Rsvd0 : 3; /**< Bits 59:57 - Reserved. */ 878 888 uint16_t u4EvtCode : 4; /**< Bits 63:60 - Event code. */ 879 uint32_t u2Rsvd1 : 2; /**< Bits 65:64 - Reserved. */ 880 uint32_t u30AddrLo : 2; /**< Bits 95:66 - Address: Device Virtual Address (Lo). */ 881 uint32_t u30AddrHi; /**< Bits 127:96 - Address: Device Virtual Address (Hi). */ 889 uint64_t u64Addr; /**< Bits 127:64 - Address: Device Virtual Address. */ 882 890 } n; 883 891 /** The 32-bit unsigned integer view. */ … … 885 893 } EVT_ILLEGAL_DEV_TAB_ENTRY_T; 886 894 AssertCompileSize(EVT_ILLEGAL_DEV_TAB_ENTRY_T, 16); 895 /** Pointer to an illegal device table entry event. */ 896 typedef EVT_ILLEGAL_DEV_TAB_ENTRY_T *PEVT_ILLEGAL_DEV_TAB_ENTRY_T; 887 897 888 898 /** … … 904 914 uint16_t u1ReadWrite : 1; /**< Bit 53 - RW: Read/Write. */ 905 915 uint16_t u1Perm : 1; /**< Bit 54 - PE: Permission Indicator. */ 906 uint16_t u1Rsvd Zero : 1;/**< Bit 55 - RZ: Reserved bit not Zero or invalid level encoding. */916 uint16_t u1RsvdNotZero : 1; /**< Bit 55 - RZ: Reserved bit not Zero or invalid level encoding. */ 907 917 uint16_t u1Translation : 1; /**< Bit 56 - TN: Translation. */ 908 918 uint16_t u3Rsvd0 : 3; /**< Bit 59:57 - Reserved. */ … … 1125 1135 } IOMMU_BAR_T; 1126 1136 AssertCompileSize(IOMMU_BAR_T, 8); 1127 #define IOMMU_BAR_VALID_MASK UINT64_C(0xffffffffffffc001)1137 #define IOMMU_BAR_VALID_MASK UINT64_C(0xffffffffffffc001) 1128 1138 1129 1139 /** … … 1971 1981 typedef PPR_LOG_OVERFLOW_EARLY_T PPR_LOG_B_OVERFLOW_EARLY_T; 1972 1982 1983 /** 1984 * IOMMU operation types. 1985 */ 1986 typedef enum IOMMUOP 1987 { 1988 /** Address translation request. */ 1989 IOMMUOP_TRANSLATE_REQ = 0, 1990 /** Memory read request. */ 1991 IOMMUOP_MEM_READ, 1992 /** Memory write request. */ 1993 IOMMUOP_MEM_WRITE, 1994 /** Interrupt request. */ 1995 IOMMUOP_INTR_REQ, 1996 /** Command request. */ 1997 IOMMUOP_CMD 1998 } IOMMUOP; 1999 AssertCompileSize(IOMMUOP, 4); 2000 1973 2001 1974 2002 /** … … 3164 3192 3165 3193 /** 3166 * Constructs a DEV_TAB_HARDWARE_ERROR event.3167 *3168 * @param uDevId The device ID.3169 * @param GCPhysDevTab The device table system physical address.3170 * @param fTranslation Whether this is an translation or transaction request.3171 * @param fInterrupt Whether the transaction was an interrupt or memory3172 * request.3173 * @param fReadWrite Whether the transaction was read-write or read-only.3174 * Only meaninful when @a fTranslate is @c false and3175 * @a fInterrupt is false.3176 * @param pEvent Where to store the constructed event.3177 *3178 * @thread Any.3179 */3180 static void iommuAmdMakeDevTabHwErrorEvent(uint16_t uDevId, RTGCPHYS GCPhysDevTab, bool fTranslation, bool fReadWrite,3181 bool fInterrupt, PEVT_GENERIC_T pEvent)3182 {3183 memset(pEvent, 0, sizeof(*pEvent));3184 PEVT_DEV_TAB_HW_ERROR_T pDevTabHwErr = (PEVT_DEV_TAB_HW_ERROR_T)pEvent;3185 pDevTabHwErr->n.u16DevId = uDevId;3186 pDevTabHwErr->n.u1Intr = fInterrupt;3187 pDevTabHwErr->n.u1ReadWrite = fReadWrite;3188 pDevTabHwErr->n.u1Translation = fTranslation;3189 pDevTabHwErr->n.u2Type = EVTLOGTYPE_TARGET_ABORT;3190 pDevTabHwErr->n.u4EvtCode = IOMMU_EVT_DEV_TAB_HW_ERROR;3191 pDevTabHwErr->n.u64Addr = GCPhysDevTab;3192 }3193 3194 3195 /**3196 3194 * Sets an event in the hardware error registers. 3197 3195 * … … 3217 3215 3218 3216 /** 3217 * Constructs a DEV_TAB_HARDWARE_ERROR event. 3218 * 3219 * @param uDevId The device ID. 3220 * @param GCPhysDevTab The system physical address of the failed device table 3221 * access. 3222 * @param fOperation The operation being performed. 3223 * @param pEvent Where to store the constructed event. 3224 * 3225 * @thread Any. 3226 */ 3227 static void iommuAmdMakeDevTabHwErrorEvent(uint16_t uDevId, RTGCPHYS GCPhysDevTabEntry, IOMMUOP enmOp, PEVT_GENERIC_T pEvent) 3228 { 3229 memset(pEvent, 0, sizeof(*pEvent)); 3230 AssertCompile(sizeof(EVT_DEV_TAB_HW_ERROR_T) == sizeof(EVT_GENERIC_T)); 3231 PEVT_DEV_TAB_HW_ERROR_T pDevTabHwErr = (PEVT_DEV_TAB_HW_ERROR_T)pEvent; 3232 pDevTabHwErr->n.u16DevId = uDevId; 3233 pDevTabHwErr->n.u1Intr = RT_BOOL(enmOp == IOMMUOP_INTR_REQ); 3234 pDevTabHwErr->n.u1ReadWrite = RT_BOOL(enmOp == IOMMUOP_MEM_WRITE); 3235 pDevTabHwErr->n.u1Translation = RT_BOOL(enmOp == IOMMUOP_TRANSLATE_REQ); 3236 pDevTabHwErr->n.u2Type = enmOp == IOMMUOP_CMD ? HWEVTTYPE_DATA_ERROR : HWEVTTYPE_TARGET_ABORT; 3237 pDevTabHwErr->n.u4EvtCode = IOMMU_EVT_DEV_TAB_HW_ERROR; 3238 pDevTabHwErr->n.u64Addr = GCPhysDevTabEntry; 3239 } 3240 3241 3242 /** 3243 * Raises a DEV_TAB_HARDWARE_ERROR event. 3244 * 3245 * @param pDevIns The IOMMU device instance. 3246 * @param uDevId The device ID. 3247 * @param GCPhysDevTabEntry The system physical address of the failed device 3248 * table access. 3249 * @param enmOp The operation being performed by the IOMMU. 3250 */ 3251 static void iommuAmdRaiseDevTabHwErrorEvent(PPDMDEVINS pDevIns, uint16_t uDevId, RTGCPHYS GCPhysDevTabEntry, IOMMUOP enmOp) 3252 { 3253 EVT_GENERIC_T Event; 3254 iommuAmdMakeDevTabHwErrorEvent(uDevId, GCPhysDevTabEntry, enmOp, &Event); 3255 iommuAmdSetHwError(pDevIns, &Event); 3256 iommuAmdWriteEvtLogEntry(pDevIns, &Event); 3257 if (enmOp != IOMMUOP_CMD) 3258 iommuAmdSetPciTargetAbort(pDevIns); 3259 } 3260 3261 3262 /** 3263 * Constructs an ILLEGAL_DEV_TAB_ENTRY event. 3264 * 3265 * @param uDevId The device ID. 3266 * @param uDva The device virtual address. 3267 * @param fRsvdNotZero Whether reserved bits in the device table entry were not 3268 * zero. 3269 * @param enmOp The operation being performed. 3270 * @param pEvent Where to store the constructed event. 3271 */ 3272 static void iommuAmdMakeIllegalDevTabEntryEvent(uint16_t uDevId, uint64_t uDva, bool fRsvdNotZero, IOMMUOP enmOp, 3273 PEVT_GENERIC_T pEvent) 3274 { 3275 memset(pEvent, 0, sizeof(*pEvent)); 3276 AssertCompile(sizeof(EVT_ILLEGAL_DEV_TAB_ENTRY_T) == sizeof(EVT_GENERIC_T)); 3277 PEVT_ILLEGAL_DEV_TAB_ENTRY_T pIllegalDteErr = (PEVT_ILLEGAL_DEV_TAB_ENTRY_T)pEvent; 3278 pIllegalDteErr->n.u16DevId = uDevId; 3279 pIllegalDteErr->n.u1Interrupt = RT_BOOL(enmOp == IOMMUOP_INTR_REQ); 3280 pIllegalDteErr->n.u1ReadWrite = RT_BOOL(enmOp == IOMMUOP_MEM_WRITE); 3281 pIllegalDteErr->n.u1RsvdNotZero = fRsvdNotZero; 3282 pIllegalDteErr->n.u1Translation = RT_BOOL(enmOp == IOMMUOP_TRANSLATE_REQ); 3283 pIllegalDteErr->n.u4EvtCode = IOMMU_EVT_ILLEGAL_DEV_TAB_ENTRY; 3284 pIllegalDteErr->n.u64Addr = uDva & ~UINT64_C(0x3); 3285 /** @todo r=ramshankar: Not sure why the last 2 bits are marked as reserved by the 3286 * IOMMU spec here but not for this field for I/O page fault event. */ 3287 Assert(!(uDva & UINT64_C(0x3))); 3288 } 3289 3290 3291 /** 3292 * Raises an ILLEGAL_DEV_TAB_ENTRY event. 3293 * 3294 * @param pDevIns The IOMMU instance data. 3295 * @param uDevId The device ID. 3296 * @param uDva The device virtual address. 3297 * @param fRsvdNotZero Whether reserved bits in the device table entry were not 3298 * zero. 3299 * @param enmOp The operation being performed. 3300 */ 3301 static void iommuAmdRaiseIllegalDevTabEntryEvent(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uDva, bool fRsvdNotZero, 3302 IOMMUOP enmOp) 3303 { 3304 EVT_GENERIC_T Event; 3305 iommuAmdMakeIllegalDevTabEntryEvent(uDevId, uDva, fRsvdNotZero, enmOp, &Event); 3306 iommuAmdWriteEvtLogEntry(pDevIns, &Event); 3307 if (enmOp != IOMMUOP_CMD) 3308 iommuAmdSetPciTargetAbort(pDevIns); 3309 } 3310 3311 3312 /** 3219 3313 * Reads a device table entry from guest memory given the device ID. 3220 3314 * … … 3222 3316 * @param pDevIns The IOMMU device instance. 3223 3317 * @param uDevId The device ID. 3318 * @param enmOp The operation being performed by the IOMMU. 3224 3319 * @param pDevTabEntry Where to store the device table entry. 3225 3320 * 3226 3321 * @thread Any. 3227 3322 */ 3228 static int iommuAmdReadDevTabEntry(PPDMDEVINS pDevIns, uint16_t uDevId, DEV_TAB_ENTRY_T *pDevTabEntry)3323 static int iommuAmdReadDevTabEntry(PPDMDEVINS pDevIns, uint16_t uDevId, IOMMUOP enmOp, DEV_TAB_ENTRY_T *pDevTabEntry) 3229 3324 { 3230 3325 PCIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU); … … 3245 3340 if (RT_FAILURE(rc)) 3246 3341 { 3247 EVT_GENERIC_T Event; 3248 iommuAmdMakeDevTabHwErrorEvent(uDevId, 3249 GCPhysDevTab, 3250 true /* fTranslation */, 3251 false /* fReadWrite */, 3252 false /* fInterrupt */, 3253 &Event); 3254 iommuAmdSetHwError(pDevIns, &Event); 3255 iommuAmdWriteEvtLogEntry(pDevIns, &Event); 3256 iommuAmdSetPciTargetAbort(pDevIns); 3257 Log((IOMMU_LOG_PFX ": Failed to read device table entry at %#RGp. rc=%Rrc -> target abort\n", GCPhysDevTabEntry, rc)); 3342 Log((IOMMU_LOG_PFX ": Failed to read device table entry at %#RGp. rc=%Rrc\n", GCPhysDevTabEntry, rc)); 3343 iommuAmdRaiseDevTabHwErrorEvent(pDevIns, uDevId, GCPhysDevTabEntry, enmOp); 3258 3344 } 3259 3345 … … 3277 3363 { 3278 3364 RT_NOREF(pDevIns, uDevId, uDva, cbRead, pGCPhysOut); 3279 return VERR_NOT_IMPLEMENTED; 3365 3366 Assert(pDevIns); 3367 Assert(pGCPhysOut); 3368 3369 PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU); 3370 IOMMUOP const enmOp = IOMMUOP_TRANSLATE_REQ; 3371 3372 /* Addresses are forwarded without translation when the IOMMU is disabled. */ 3373 IOMMU_CTRL_T const Ctrl = iommuAmdGetCtrl(pThis); 3374 if (Ctrl.n.u1IommuEn) 3375 { 3376 /** @todo IOTLB cache lookup. */ 3377 3378 /* Read the device table entry. */ 3379 DEV_TAB_ENTRY_T DevTabEntry; 3380 int rc = iommuAmdReadDevTabEntry(pDevIns, uDevId, enmOp, &DevTabEntry); 3381 if (RT_SUCCESS(rc)) 3382 { 3383 /* Addresses are forwarded without translation when DTE.V is 0. */ 3384 if (DevTabEntry.n.u1Valid) 3385 { 3386 /* Validate bits 127:0 of the device table entry when DTE.V is 1. */ 3387 uint64_t const fRsvdQword0 = DevTabEntry.au64[0] & ~IOMMU_DEV_TAB_ENTRY_QWORD_0_VALID_MASK; 3388 uint64_t const fRsvdQword1 = DevTabEntry.au64[1] & ~IOMMU_DEV_TAB_ENTRY_QWORD_1_VALID_MASK; 3389 if ( fRsvdQword0 3390 || fRsvdQword1) 3391 { 3392 Log((IOMMU_LOG_PFX ":DTE invalid reserved bits ([0]=%#RX64 [1]=%#RX64)\n", fRsvdQword0, fRsvdQword1)); 3393 iommuAmdRaiseIllegalDevTabEntryEvent(pDevIns, uDevId, uDva, true /* fRsvdNotZero */, enmOp); 3394 return VERR_GENERAL_FAILURE; /** @todo IOMMU: Change this. */ 3395 } 3396 3397 /** @todo IOMMU: Traverse the I/O page table and translate. */ 3398 return VERR_NOT_IMPLEMENTED; 3399 } 3400 } 3401 else 3402 { 3403 Log((IOMMU_LOG_PFX ":Failed to read device table entry. uDevId=%#x rc=%Rrc\n", uDevId, rc)); 3404 return VERR_GENERAL_FAILURE; /** @todo IOMMU: Change this. */ 3405 } 3406 } 3407 3408 *pGCPhysOut = uDva; 3409 return VINF_SUCCESS; 3280 3410 } 3281 3411 … … 3381 3511 case IOMMU_PCI_OFF_BASE_ADDR_REG_LO: 3382 3512 { 3383 IOMMU_BAR_T const IommuBar = pThis->IommuBar; 3384 if (!IommuBar.n.u1Enable) 3513 if (pThis->IommuBar.n.u1Enable) 3385 3514 { 3386 pThis->IommuBar.au32[0] = u32Value & IOMMU_BAR_VALID_MASK; 3515 rcStrict = VINF_SUCCESS; 3516 Log((IOMMU_LOG_PFX ": Writing Base Address (Lo) when it's already enabled -> Ignored\n")); 3517 break; 3518 } 3519 3520 pThis->IommuBar.au32[0] = u32Value & IOMMU_BAR_VALID_MASK; 3521 if (pThis->IommuBar.n.u1Enable) 3522 { 3387 3523 Assert(pThis->hMmio == NIL_IOMMMIOHANDLE); 3388 Assert(!pThis->ExtFeat.n.u1PerfCounterSup); /* 16K aligned when performance counters aren't supported. */ 3389 uint64_t const fAlignMask = UINT64_C(0xffffffffffffc000); 3390 RTGCPHYS const GCPhysMmioBase = RT_MAKE_U64(pThis->IommuBar.au32[0] & fAlignMask, pThis->IommuBar.au32[1]); 3524 Assert(!pThis->ExtFeat.n.u1PerfCounterSup); /* Base is 16K aligned when performance counters aren't supported. */ 3525 RTGCPHYS const GCPhysMmioBase = RT_MAKE_U64(pThis->IommuBar.au32[0] & 0xffffc000, pThis->IommuBar.au32[1]); 3391 3526 rcStrict = PDMDevHlpMmioMap(pDevIns, pThis->hMmio, GCPhysMmioBase); 3392 3527 if (RT_FAILURE(rcStrict)) 3393 3528 Log((IOMMU_LOG_PFX ": Failed to map IOMMU MMIO region at %#RGp. rc=%Rrc\n", GCPhysMmioBase, rcStrict)); 3394 3529 } 3395 else3396 {3397 rcStrict = VINF_SUCCESS;3398 Log((IOMMU_LOG_PFX ": Writing Base Address (Lo) when it's already enabled -> Ignored\n"));3399 }3400 3530 break; 3401 3531 } … … 3403 3533 case IOMMU_PCI_OFF_BASE_ADDR_REG_HI: 3404 3534 { 3405 IOMMU_BAR_T const IommuBar = pThis->IommuBar; 3406 if (!IommuBar.n.u1Enable) 3535 if (!pThis->IommuBar.n.u1Enable) 3407 3536 pThis->IommuBar.au32[1] = u32Value; 3408 3537 else
Note:
See TracChangeset
for help on using the changeset viewer.