Changeset 84023 in vbox for trunk/src/VBox/Devices
- Timestamp:
- Apr 27, 2020 7:37:58 PM (5 years ago)
- svn:sync-xref-src-repo-rev:
- 137593
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Bus/DevIommuAmd.cpp
r83999 r84023 21 21 *********************************************************************************************************************************/ 22 22 #define LOG_GROUP LOG_GROUP_DEV_IOMMU 23 #include <VBox/msi.h> 23 24 #include <VBox/vmm/pdmdev.h> 24 25 #include <VBox/AssertGuest.h> … … 375 376 RT_BF_ASSERT_COMPILE_CHECKS(IOMMU_BF_MSI_MAP_CAPHDR_, UINT32_C(0), UINT32_MAX, 376 377 (CAP_ID, CAP_PTR, EN, FIXED, RSVD_18_28, CAP_TYPE)); 378 /** @} */ 379 380 /** 381 * @name IOMMU Status Register Bits. 382 * In accordance with the AMD spec. 383 * @{ 384 */ 385 /** EventOverflow: Event log overflow. */ 386 #define IOMMU_STATUS_EVT_LOG_OVERFLOW RT_BIT_64(0) 387 /** EventLogInt: Event log interrupt. */ 388 #define IOMMU_STATUS_EVT_LOG_INTR RT_BIT_64(1) 389 /** ComWaitInt: Completion wait interrupt. */ 390 #define IOMMU_STATUS_COMPLETION_WAIT_INTR RT_BIT_64(2) 391 /** EventLogRun: Event log is running. */ 392 #define IOMMU_STATUS_EVT_LOG_RUNNING RT_BIT_64(3) 393 /** CmdBufRun: Command buffer is running. */ 394 #define IOMMU_STATUS_CMD_BUF_RUNNING RT_BIT_64(4) 395 /** PprOverflow: Peripheral page request log overflow. */ 396 #define IOMMU_STATUS_PPR_LOG_OVERFLOW RT_BIT_64(5) 397 /** PprInt: Peripheral page request log interrupt. */ 398 #define IOMMU_STATUS_PPR_LOG_INTR RT_BIT_64(6) 399 /** PprLogRun: Peripheral page request log is running. */ 400 #define IOMMU_STATUS_PPR_LOG_RUN RT_BIT_64(7) 401 /** GALogRun: Guest virtual-APIC log is running. */ 402 #define IOMMU_STATUS_GA_LOG_RUN RT_BIT_64(8) 403 /** GALOverflow: Guest virtual-APIC log overflow. */ 404 #define IOMMU_STATUS_GA_LOG_OVERFLOW RT_BIT_64(9) 405 /** GAInt: Guest virtual-APIC log interrupt. */ 406 #define IOMMU_STATUS_GA_LOG_INTR RT_BIT_64(10) 407 /** PprOvrflwB: PPR Log B overflow. */ 408 #define IOMMU_STATUS_PPR_LOG_B_OVERFLOW RT_BIT_64(11) 409 /** PprLogActive: PPR Log B is active. */ 410 #define IOMMU_STATUS_PPR_LOG_B_ACTIVE RT_BIT_64(12) 411 /** EvtOvrflwB: Event log B overflow. */ 412 #define IOMMU_STATUS_EVT_LOG_B_OVERFLOW RT_BIT_64(15) 413 /** EventLogActive: Event log B active. */ 414 #define IOMMU_STATUS_EVT_LOG_B_ACTIVE RT_BIT_64(16) 415 /** PprOvrflwEarlyB: PPR log B overflow early warning. */ 416 #define IOMMU_STATUS_PPR_LOG_B_OVERFLOW_EARLY RT_BIT_64(17) 417 /** PprOverflowEarly: PPR log overflow early warning. */ 418 #define IOMMU_STATUS_PPR_LOG_OVERFLOW_EARLY RT_BIT_64(18) 377 419 /** @} */ 378 420 … … 767 809 } EVT_GENERIC_T; 768 810 AssertCompileSize(EVT_GENERIC_T, 16); 811 /** Pointer to a generic event log entry. */ 812 typedef EVT_GENERIC_T *PEVT_GENERIC_T; 813 /** Pointer to a const generic event log entry. */ 814 typedef const EVT_GENERIC_T *PCEVT_GENERIC_T; 769 815 770 816 /** … … 2105 2151 2106 2152 #ifndef VBOX_DEVICE_STRUCT_TESTCASE 2107 2108 /** 2109 * Gets the buffer length length corresponding to a base address. 2153 /** 2154 * Gets the number of buffer entries given a base register's encoded length. 2110 2155 * 2111 * @param uEncodedLen The length to decode (power-of-2 encoded). 2112 * @param pcEntries Where to store the number of entries. Optional, can be 2113 * NULL. 2114 * @param pcbBuffer Where to store the size of the buffer. Optional, can be 2115 * NULL. 2156 * @returns Number of buffer entries. 2157 * @param uEncodedLen The length (power-of-2 encoded). 2158 */ 2159 DECLINLINE(uint32_t) iommuAmdGetBaseBufEntryCount(uint8_t uEncodedLen) 2160 { 2161 Assert(uEncodedLen > 7); 2162 return 2 << (uEncodedLen - 1); 2163 } 2164 2165 2166 /** 2167 * Gets the length of the buffer given a base register's encoded length. 2116 2168 * 2117 * @remarks Both @a pcEntries and @a pcbBuffer cannot both be NULL. 2118 */ 2119 static void iommuAmdGetBaseBufferLength(uint8_t uEncodedLen, uint32_t *pcEntries, uint32_t *pcbBuffer) 2120 { 2121 uint32_t cEntries; 2122 uint32_t cbBuffer; 2123 if (uEncodedLen > 7) 2124 { 2125 cEntries = 2 << (uEncodedLen - 1); 2126 cbBuffer = *pcEntries << 4; 2127 } 2128 else 2129 cEntries = cbBuffer = 0; 2130 2131 Assert(pcEntries || pcbBuffer); 2132 if (pcEntries) 2133 *pcEntries = cEntries; 2134 if (pcbBuffer) 2135 *pcbBuffer = cbBuffer; 2169 * @returns The length of the buffer in bytes. 2170 * @param uEncodedLen The length (power-of-2 encoded). 2171 */ 2172 DECLINLINE(uint32_t) iommuAmdGetBaseBufLength(uint8_t uEncodedLen) 2173 { 2174 Assert(uEncodedLen > 7); 2175 return (2 << (uEncodedLen - 1)) << 4; 2136 2176 } 2137 2177 2138 2178 2139 DECL _FORCE_INLINE(IOMMU_STATUS_T) iommuAmdGetStatus(PCIOMMU pThis)2179 DECLINLINE(IOMMU_STATUS_T) iommuAmdGetStatus(PCIOMMU pThis) 2140 2180 { 2141 2181 IOMMU_STATUS_T Status; … … 2145 2185 2146 2186 2147 DECL _FORCE_INLINE(IOMMU_CTRL_T) iommuAmdGetCtrl(PCIOMMU pThis)2187 DECLINLINE(IOMMU_CTRL_T) iommuAmdGetCtrl(PCIOMMU pThis) 2148 2188 { 2149 2189 IOMMU_CTRL_T Ctrl; 2150 2190 Ctrl.u64 = ASMAtomicReadU64((volatile uint64_t *)&pThis->Ctrl.u64); 2151 2191 return Ctrl; 2192 } 2193 2194 2195 /** 2196 * Determines whether MSI is enabled for the IOMMU. This influences interrupt 2197 * handling in IOMMU. 2198 * 2199 * @note There should be a PCIDevXxx function for this. 2200 */ 2201 static bool iommuAmdIsMsiEnabled(PPDMPCIDEV pDevIns) 2202 { 2203 uint16_t const uMsgCtl = PDMPciDevGetWord(pDevIns, IOMMU_PCI_OFF_MSI_CAP_HDR + VBOX_MSI_CAP_MESSAGE_CONTROL); 2204 return RT_BOOL(uMsgCtl & VBOX_PCI_MSI_FLAGS_ENABLE); 2152 2205 } 2153 2206 … … 2507 2560 * In our emulation, we ignore the write entirely. 2508 2561 */ 2509 uint32_t const offBuf = u64Value & IOMMU_CMD_BUF_HEAD_PTR_VALID_MASK; 2510 CMD_BUF_BAR_T const CmdBufBar = pThis->CmdBufBaseAddr; 2511 uint32_t cbBuf; 2512 iommuAmdGetBaseBufferLength(CmdBufBar.n.u4Len, NULL, &cbBuf); 2562 uint32_t const offBuf = u64Value & IOMMU_CMD_BUF_HEAD_PTR_VALID_MASK; 2563 CMD_BUF_BAR_T const CmdBufBar = pThis->CmdBufBaseAddr; 2564 uint32_t const cbBuf = iommuAmdGetBaseBufLength(CmdBufBar.n.u4Len); 2513 2565 if (offBuf >= cbBuf) 2514 2566 { … … 2754 2806 * This is because most registers are 64-bit and aligned on 8-byte boundaries but 2755 2807 * some are really 32-bit registers aligned on an 8-byte boundary. We cannot assume 2756 * guests will only perform 32-bit reads on those 32-bit registers that are aligned2757 * on 8-byte boundaries.2808 * software will only perform 32-bit reads on those 32-bit registers that are 2809 * aligned on 8-byte boundaries. 2758 2810 * 2759 2811 * @returns Strict VBox status code. … … 2915 2967 *puResult = uReg; 2916 2968 return VINF_SUCCESS; 2969 } 2970 2971 2972 static int iommuAmdWriteEventLogEntry(PPDMDEVINS pDevIns, PCEVT_GENERIC_T pEvent) 2973 { 2974 PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU); 2975 IOMMU_STATUS_T const Status = iommuAmdGetStatus(pThis); 2976 2977 /* Check if event logging is active and the log has not overflowed. */ 2978 if ( Status.n.u1EvtLogRunning 2979 && !Status.n.u1EvtOverflow) 2980 { 2981 /* Figure out the event log entry offset. */ 2982 EVT_LOG_TAIL_PTR_T const TailPtr = pThis->EvtLogTailPtr; 2983 uint32_t const offEvtLogEntry = TailPtr.n.u15Ptr << 4; 2984 2985 /* Ensure the event log entry is within limits. */ 2986 uint32_t const uEvtLogLen = iommuAmdGetBaseBufLength(pThis->EvtLogBaseAddr.n.u4Len); 2987 if (offEvtLogEntry < uEvtLogLen) 2988 { 2989 /* Write the event log entry to memory. */ 2990 RTGCPHYS const GCPhysEvtLog = pThis->EvtLogBaseAddr.n.u40Base; 2991 RTGCPHYS const GCPhysEvtLogEntry = GCPhysEvtLog + offEvtLogEntry; 2992 int rc = PDMDevHlpPCIPhysWrite(pDevIns, GCPhysEvtLogEntry, pEvent, sizeof(*pEvent)); 2993 if (RT_FAILURE(rc)) 2994 Log((IOMMU_LOG_PFX ": Failed to write event log entry at %#RGp. rc=%Rrc\n", GCPhysEvtLogEntry, rc)); 2995 2996 /* Increment the event log tail pointer. */ 2997 pThis->EvtLogTailPtr.n.u15Ptr += sizeof(*pEvent); 2998 2999 /* Check if software wants to receive an interrupt when the event log is updated. */ 3000 IOMMU_CTRL_T const Ctrl = iommuAmdGetCtrl(pThis); 3001 if (Ctrl.n.u1EvtIntrEn) 3002 { 3003 /* Signal the event log interrupt. */ 3004 ASMAtomicOrU64(&pThis->Status.u64, IOMMU_STATUS_EVT_LOG_INTR); 3005 /** @todo IOMMU: Generate the interrupt. */ 3006 } 3007 } 3008 } 2917 3009 } 2918 3010 … … 3151 3243 { 3152 3244 CMD_BUF_BAR_T const CmdBufBar = pThis->CmdBufBaseAddr; 3153 uint32_t cEntries; 3154 uint32_t cbBuffer; 3155 uint8_t const uEncodedLen = CmdBufBar.n.u4Len; 3156 iommuAmdGetBaseBufferLength(uEncodedLen, &cEntries, &cbBuffer); 3245 uint8_t const uEncodedLen = CmdBufBar.n.u4Len; 3246 uint32_t const cEntries = iommuAmdGetBaseBufEntryCount(uEncodedLen); 3247 uint32_t const cbBuffer = iommuAmdGetBaseBufLength(uEncodedLen); 3157 3248 pHlp->pfnPrintf(pHlp, " Command buffer BAR = %#RX64\n", CmdBufBar.u64); 3158 3249 if (fVerbose) … … 3166 3257 { 3167 3258 EVT_LOG_BAR_T const EvtLogBar = pThis->EvtLogBaseAddr; 3168 uint32_t cEntries; 3169 uint32_t cbBuffer; 3170 uint8_t const uEncodedLen = EvtLogBar.n.u4Len; 3171 iommuAmdGetBaseBufferLength(uEncodedLen, &cEntries, &cbBuffer); 3259 uint8_t const uEncodedLen = EvtLogBar.n.u4Len; 3260 uint32_t const cEntries = iommuAmdGetBaseBufEntryCount(uEncodedLen); 3261 uint32_t const cbBuffer = iommuAmdGetBaseBufLength(uEncodedLen); 3172 3262 pHlp->pfnPrintf(pHlp, " Event log BAR = %#RX64\n", EvtLogBar.u64); 3173 3263 if (fVerbose) … … 3288 3378 { 3289 3379 PPR_LOG_BAR_T PprLogBar = pThis->PprLogBaseAddr; 3290 uint32_t cEntries; 3291 uint32_t cbBuffer; 3292 uint8_t const uEncodedLen = PprLogBar.n.u4Len; 3293 iommuAmdGetBaseBufferLength(uEncodedLen, &cEntries, &cbBuffer); 3380 uint8_t const uEncodedLen = PprLogBar.n.u4Len; 3381 uint32_t const cEntries = iommuAmdGetBaseBufEntryCount(uEncodedLen); 3382 uint32_t const cbBuffer = iommuAmdGetBaseBufLength(uEncodedLen); 3294 3383 pHlp->pfnPrintf(pHlp, " PPR Log BAR = %#RX64\n", PprLogBar.u64); 3295 3384 if (fVerbose) … … 3325 3414 { 3326 3415 GALOG_BAR_T const GALogBar = pThis->GALogBaseAddr; 3327 uint32_t cEntries; 3328 uint32_t cbBuffer; 3329 uint8_t const uEncodedLen = GALogBar.n.u4Len; 3330 iommuAmdGetBaseBufferLength(uEncodedLen, &cEntries, &cbBuffer); 3416 uint8_t const uEncodedLen = GALogBar.n.u4Len; 3417 uint32_t const cEntries = iommuAmdGetBaseBufEntryCount(uEncodedLen); 3418 uint32_t const cbBuffer = iommuAmdGetBaseBufLength(uEncodedLen); 3331 3419 pHlp->pfnPrintf(pHlp, " Guest Log BAR = %#RX64\n", GALogBar.u64); 3332 3420 if (fVerbose) … … 3347 3435 { 3348 3436 PPR_LOG_B_BAR_T PprLogBBar = pThis->PprLogBBaseAddr; 3349 uint32_t cEntries; 3350 uint32_t cbBuffer; 3351 uint8_t const uEncodedLen = PprLogBBar.n.u4Len; 3352 iommuAmdGetBaseBufferLength(uEncodedLen, &cEntries, &cbBuffer); 3437 uint8_t const uEncodedLen = PprLogBBar.n.u4Len; 3438 uint32_t const cEntries = iommuAmdGetBaseBufEntryCount(uEncodedLen); 3439 uint32_t const cbBuffer = iommuAmdGetBaseBufLength(uEncodedLen); 3353 3440 pHlp->pfnPrintf(pHlp, " PPR Log B BAR = %#RX64\n", PprLogBBar.u64); 3354 3441 if (fVerbose) … … 3362 3449 { 3363 3450 EVT_LOG_B_BAR_T EvtLogBBar = pThis->EvtLogBBaseAddr; 3364 uint32_t cEntries; 3365 uint32_t cbBuffer; 3366 uint8_t const uEncodedLen = EvtLogBBar.n.u4Len; 3367 iommuAmdGetBaseBufferLength(uEncodedLen, &cEntries, &cbBuffer); 3451 uint8_t const uEncodedLen = EvtLogBBar.n.u4Len; 3452 uint32_t const cEntries = iommuAmdGetBaseBufEntryCount(uEncodedLen); 3453 uint32_t const cbBuffer = iommuAmdGetBaseBufLength(uEncodedLen); 3368 3454 pHlp->pfnPrintf(pHlp, " Event Log B BAR = %#RX64\n", EvtLogBBar.u64); 3369 3455 if (fVerbose)
Note:
See TracChangeset
for help on using the changeset viewer.