Changeset 67376 in vbox for trunk/src/VBox/Devices/Audio
- Timestamp:
- Jun 13, 2017 3:01:46 PM (8 years ago)
- svn:sync-xref-src-repo-rev:
- 116096
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DevHDA.cpp
r67362 r67376 56 56 //#define HDA_AS_PCI_EXPRESS 57 57 #define VBOX_WITH_INTEL_HDA 58 59 /* Installs a DMA access handler (via PGM callback) to monitor 60 * HDA's DMA operations, that is, writing / reading audio stream data. 61 * 62 * !!! Note: Certain guests are *that* timing sensitive that when enabling !!! 63 * !!! such a handler will mess up audio completely (e.g. Windows 7). !!! */ 64 //#define HDA_USE_DMA_ACCESS_HANDLER 65 #ifdef HDA_USE_DMA_ACCESS_HANDLER 66 # include <VBox/vmm/pgm.h> 67 #endif 68 69 /* Uses the DMA access handler to read the written DMA audio (output) data. 70 * Only valid if HDA_USE_DMA_ACCESS_HANDLER is set. 71 * 72 * Also see the note / warning for HDA_USE_DMA_ACCESS_HANDLER. */ 73 //# define HDA_USE_DMA_ACCESS_HANDLER_WRITING 58 74 59 75 #if defined(VBOX_WITH_HP_HDA) … … 551 567 /** Circular buffer (FIFO) for holding DMA'ed data. */ 552 568 R3PTRTYPE(PRTCIRCBUF) pCircBuf; 569 # ifdef HDA_USE_DMA_ACCESS_HANDLER 570 /** List of DMA handlers. */ 571 RTLISTANCHORR3 lstDMAHandlers; 572 #endif 553 573 } HDASTREAMSTATE, *PHDASTREAMSTATE; 554 574 … … 574 594 R3PTRTYPE(PAUDMIXSINK) pMixSink; 575 595 } HDAMIXERSINK, *PHDAMIXERSINK; 596 597 #if defined (DEBUG) || defined(HDA_USE_DMA_ACCESS_HANDLER) 598 typedef struct HDASTREAMDBGINFO 599 { 600 /** Critical section to serialize access if needed. */ 601 RTCRITSECT CritSect; 602 uint32_t Padding1[2]; 603 /** Number of total read accesses. */ 604 uint64_t cReadsTotal; 605 /** Number of total DMA bytes read. */ 606 uint64_t cbReadTotal; 607 /** Timestamp (in ns) of last read access. */ 608 uint64_t tsLastReadNs; 609 /** Number of total write accesses. */ 610 uint64_t cWritesTotal; 611 /** Number of total DMA bytes written. */ 612 uint64_t cbWrittenTotal; 613 /** Number of total write accesses since last iteration (Hz). */ 614 uint64_t cWritesHz; 615 /** Number of total DMA bytes written since last iteration (Hz). */ 616 uint64_t cbWrittenHz; 617 /** Timestamp (in ns) of beginning a new write slot. */ 618 uint64_t tsWriteSlotBegin; 619 /** Number of current silence samples in a (consecutive) row. */ 620 uint64_t csSilence; 621 /** Number of silent samples in a row to consider an audio block as audio gap (silence). */ 622 uint64_t cSilenceThreshold; 623 /** How many bytes to skip in an audio stream before detecting silence. 624 * (useful for intros and silence at the beginning of a song). */ 625 uint64_t cbSilenceReadMin; 626 } HDASTREAMDBGINFO ,*PHDASTREAMDBGINFO; 627 #endif /* defined (DEBUG) || defined(HDA_USE_DMA_ACCESS_HANDLER) */ 576 628 577 629 /** … … 614 666 /** Internal state of this stream. */ 615 667 HDASTREAMSTATE State; 668 #ifdef DEBUG 669 /** Debug information. */ 670 HDASTREAMDBGINFO Dbg; 671 #endif 616 672 } HDASTREAM, *PHDASTREAM; 617 673 … … 657 713 R3PTRTYPE(PAUDMIXSTREAM) pMixStrm; 658 714 } HDADRIVERSTREAM, *PHDADRIVERSTREAM; 715 716 #ifdef HDA_USE_DMA_ACCESS_HANDLER 717 typedef struct HDADMAACCESSHANDLER 718 { 719 /** Node for storing this handler in our list in HDASTREAMSTATE. */ 720 RTLISTNODER3 Node; 721 /** Pointer to stream to which this access handler is assigned to. */ 722 R3PTRTYPE(PHDASTREAM) pStream; 723 /** Access handler type handle. */ 724 PGMPHYSHANDLERTYPE hAccessHandlerType; 725 /** First address this handler uses. */ 726 RTGCPHYS GCPhysFirst; 727 /** Last address this handler uses. */ 728 RTGCPHYS GCPhysLast; 729 /** Actual BDLE address to handle. */ 730 RTGCPHYS BDLEAddr; 731 /** Actual BDLE buffer size to handle. */ 732 RTGCPHYS BDLESize; 733 /** Whether the access handler has been registered or not. */ 734 bool fRegistered; 735 uint8_t Padding[3]; 736 } HDADMAACCESSHANDLER, *PHDADMAACCESSHANDLER; 737 #endif 659 738 660 739 /** … … 887 966 static void hdaStreamLock(PHDASTREAM pStream); 888 967 static void hdaStreamUnlock(PHDASTREAM pStream); 968 # ifdef HDA_USE_DMA_ACCESS_HANDLER 969 static bool hdaStreamRegisterDMAHandlers(PHDASTATE pThis, PHDASTREAM pStream); 970 static void hdaStreamUnregisterDMAHandlers(PHDASTATE pThis, PHDASTREAM pStream); 971 # endif 889 972 #endif /* IN_RING3 */ 890 973 /** @} */ … … 920 1003 */ 921 1004 #ifdef IN_RING3 922 static void hdaDoTransfers(PHDASTATE pThis); 1005 # ifdef HDA_USE_DMA_ACCESS_HANDLER 1006 static DECLCALLBACK(VBOXSTRICTRC) hdaDMAAccessHandler(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys, void *pvPhys, void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType, PGMACCESSORIGIN enmOrigin, void *pvUser); 1007 # endif 1008 static void hdaDoTransfers(PHDASTATE pThis); 923 1009 #endif /* IN_RING3 */ 924 1010 /** @} */ … … 1613 1699 AssertReturn(uSD <= HDA_MAX_STREAMS, VERR_INVALID_PARAMETER); 1614 1700 1701 #ifdef HDA_USE_DMA_ACCESS_HANDLER 1702 RTListInit(&pStream->State.lstDMAHandlers); 1703 #endif 1704 1615 1705 int rc = RTCritSectInit(&pStream->State.CritSect); 1616 1706 if (RT_SUCCESS(rc)) … … 1746 1836 HDA_STREAM_REG(pThis, BDPL, uSD) = 0; 1747 1837 1838 #ifdef HDA_USE_DMA_ACCESS_HANDLER 1839 hdaStreamUnregisterDMAHandlers(pThis, pStream); 1840 #endif 1841 1748 1842 int rc2 = hdaStreamInit(pThis, pStream, uSD); 1749 1843 AssertRC(rc2); … … 2332 2426 LogFunc(("[SD%RU8]: Updating LVI to %RU16\n", uSD, pStream->u16LVI)); 2333 2427 2428 # ifdef HDA_USE_DMA_ACCESS_HANDLER 2429 if (hdaGetDirFromSD(uSD) == PDMAUDIODIR_OUT) 2430 { 2431 /* Try registering the DMA handlers. 2432 * As we can't be sure in which order LVI + BDL base are set, try registering in both routines. */ 2433 if (hdaStreamRegisterDMAHandlers(pThis, pStream)) 2434 LogFunc(("[SD%RU8] DMA logging enabled\n", pStream->u8SD)); 2435 } 2436 # endif 2437 2334 2438 /* Reset BDLE state. */ 2335 2439 RT_ZERO(pStream->State.BDLE); … … 2832 2936 RT_ZERO(pStream->State.BDLE); 2833 2937 pStream->State.uCurBDLE = 0; 2938 2939 # ifdef HDA_USE_DMA_ACCESS_HANDLER 2940 if (hdaGetDirFromSD(uSD) == PDMAUDIODIR_OUT) 2941 { 2942 /* Try registering the DMA handlers. 2943 * As we can't be sure in which order LVI + BDL base are set, try registering in both routines. */ 2944 if (hdaStreamRegisterDMAHandlers(pThis, pStream)) 2945 LogFunc(("[SD%RU8] DMA logging enabled\n", pStream->u8SD)); 2946 } 2947 # endif 2834 2948 2835 2949 LogFlowFunc(("[SD%RU8]: BDLBase=0x%x\n", pStream->u8SD, pStream->u64BDLBase)); … … 2983 3097 2984 3098 #ifdef IN_RING3 3099 # ifdef HDA_USE_DMA_ACCESS_HANDLER 3100 /** 3101 * Registers access handlers for a stream's BDLE DMA accesses. 3102 * 3103 * @returns @true if registration was successful, @false if not. 3104 * @param pThis HDA state. 3105 * @param pStream HDA stream to register BDLE access handlers for. 3106 */ 3107 static bool hdaStreamRegisterDMAHandlers(PHDASTATE pThis, PHDASTREAM pStream) 3108 { 3109 /* At least LVI and the BDL base must be set. */ 3110 if ( !pStream->u16LVI 3111 || !pStream->u64BDLBase) 3112 { 3113 return false; 3114 } 3115 3116 hdaStreamUnregisterDMAHandlers(pThis, pStream); 3117 3118 LogFunc(("Registering ...\n")); 3119 3120 int rc = VINF_SUCCESS; 3121 3122 /* 3123 * Create BDLE ranges. 3124 */ 3125 3126 struct BDLERANGE 3127 { 3128 RTGCPHYS uAddr; 3129 uint32_t uSize; 3130 } arrRanges[16]; /** @todo Use a define. */ 3131 3132 size_t cRanges = 0; 3133 3134 for (uint16_t i = 0; i < pStream->u16LVI + 1; i++) 3135 { 3136 HDABDLE BDLE; 3137 rc = hdaBDLEFetch(pThis, &BDLE, pStream->u64BDLBase, i /* Index */); 3138 if (RT_FAILURE(rc)) 3139 break; 3140 3141 bool fAddRange = true; 3142 BDLERANGE *pRange; 3143 3144 if (cRanges) 3145 { 3146 pRange = &arrRanges[cRanges - 1]; 3147 3148 /* Is the current range a direct neighbor of the current BLDE? */ 3149 if ((pRange->uAddr + pRange->uSize) == BDLE.Desc.u64BufAdr) 3150 { 3151 /* Expand the current range by the current BDLE's size. */ 3152 pRange->uSize += BDLE.Desc.u32BufSize; 3153 3154 /* Adding a new range in this case is not needed anymore. */ 3155 fAddRange = false; 3156 3157 LogFunc(("Expanding range %zu by %RU32 (%RU32 total now)\n", cRanges - 1, BDLE.Desc.u32BufSize, pRange->uSize)); 3158 } 3159 } 3160 3161 /* Do we need to add a new range? */ 3162 if ( fAddRange 3163 && cRanges < RT_ELEMENTS(arrRanges)) 3164 { 3165 pRange = &arrRanges[cRanges]; 3166 3167 pRange->uAddr = BDLE.Desc.u64BufAdr; 3168 pRange->uSize = BDLE.Desc.u32BufSize; 3169 3170 LogFunc(("Adding range %zu - 0x%x (%RU32)\n", cRanges, pRange->uAddr, pRange->uSize)); 3171 3172 cRanges++; 3173 } 3174 } 3175 3176 LogFunc(("%zu ranges total\n", cRanges)); 3177 3178 /* 3179 * Register all ranges as DMA access handlers. 3180 */ 3181 3182 for (size_t i = 0; i < cRanges; i++) 3183 { 3184 BDLERANGE *pRange = &arrRanges[i]; 3185 3186 PHDADMAACCESSHANDLER pHandler = (PHDADMAACCESSHANDLER)RTMemAllocZ(sizeof(HDADMAACCESSHANDLER)); 3187 if (!pHandler) 3188 { 3189 rc = VERR_NO_MEMORY; 3190 break; 3191 } 3192 3193 RTListAppend(&pStream->State.lstDMAHandlers, &pHandler->Node); 3194 3195 pHandler->pStream = pStream; /* Save a back reference to the owner. */ 3196 3197 char szDesc[32]; 3198 RTStrPrintf(szDesc, sizeof(szDesc), "HDA[SD%RU8 - RANGE%02zu]", pStream->u8SD, i); 3199 3200 int rc2 = PGMR3HandlerPhysicalTypeRegister(PDMDevHlpGetVM(pThis->pDevInsR3), PGMPHYSHANDLERKIND_WRITE, 3201 hdaDMAAccessHandler, 3202 NULL, NULL, NULL, 3203 NULL, NULL, NULL, 3204 szDesc, &pHandler->hAccessHandlerType); 3205 AssertRCBreak(rc2); 3206 3207 pHandler->BDLEAddr = pRange->uAddr; 3208 pHandler->BDLESize = pRange->uSize; 3209 3210 /* Get first and last pages of the BDLE range. */ 3211 RTGCPHYS pgFirst = pRange->uAddr & ~PAGE_OFFSET_MASK; 3212 RTGCPHYS pgLast = RT_ALIGN(pgFirst + pRange->uSize, PAGE_SIZE); 3213 3214 /* Calculate the region size (in pages). */ 3215 RTGCPHYS regionSize = RT_ALIGN(pgLast - pgFirst, PAGE_SIZE); 3216 3217 pHandler->GCPhysFirst = pgFirst; 3218 pHandler->GCPhysLast = pHandler->GCPhysFirst + (regionSize - 1); 3219 3220 LogFunc(("\tRegistering region '%s': 0x%x - 0x%x (region size: %zu)\n", 3221 szDesc, pHandler->GCPhysFirst, pHandler->GCPhysLast, regionSize)); 3222 LogFunc(("\tBDLE @ 0x%x - 0x%x (%RU32)\n", 3223 pHandler->BDLEAddr, pHandler->BDLEAddr + pHandler->BDLESize, pHandler->BDLESize)); 3224 3225 rc2 = PGMHandlerPhysicalRegister(PDMDevHlpGetVM(pThis->pDevInsR3), 3226 pHandler->GCPhysFirst, pHandler->GCPhysLast, 3227 pHandler->hAccessHandlerType, pHandler, NIL_RTR0PTR, NIL_RTRCPTR, 3228 szDesc); 3229 AssertRCBreak(rc2); 3230 3231 pHandler->fRegistered = true; 3232 } 3233 3234 LogFunc(("Registration ended with rc=%Rrc\n", rc)); 3235 3236 return RT_SUCCESS(rc); 3237 } 3238 3239 /** 3240 * Unregisters access handlers of a stream's BDLEs. 3241 * 3242 * @param pThis HDA state. 3243 * @param pStream HDA stream to unregister BDLE access handlers for. 3244 */ 3245 static void hdaStreamUnregisterDMAHandlers(PHDASTATE pThis, PHDASTREAM pStream) 3246 { 3247 LogFunc(("\n")); 3248 3249 PHDADMAACCESSHANDLER pHandler, pHandlerNext; 3250 RTListForEachSafe(&pStream->State.lstDMAHandlers, pHandler, pHandlerNext, HDADMAACCESSHANDLER, Node) 3251 { 3252 if (!pHandler->fRegistered) /* Handler not registered? Skip. */ 3253 continue; 3254 3255 LogFunc(("Unregistering 0x%x - 0x%x (%zu)\n", 3256 pHandler->GCPhysFirst, pHandler->GCPhysLast, pHandler->GCPhysLast - pHandler->GCPhysFirst)); 3257 3258 int rc2 = PGMHandlerPhysicalDeregister(PDMDevHlpGetVM(pThis->pDevInsR3), 3259 pHandler->GCPhysFirst); 3260 AssertRC(rc2); 3261 3262 RTListNodeRemove(&pHandler->Node); 3263 3264 RTMemFree(pHandler); 3265 pHandler = NULL; 3266 } 3267 3268 Assert(RTListIsEmpty(&pStream->State.lstDMAHandlers)); 3269 } 3270 # endif /* HDA_USE_DMA_ACCESS_HANDLER */ 3271 2985 3272 #ifdef LOG_ENABLED 2986 3273 static void hdaBDLEDumpAll(PHDASTATE pThis, uint64_t u64BDLBase, uint16_t cBDLE) … … 3808 4095 STAM_PROFILE_STOP(&pThis->StatTimer, a); 3809 4096 } 4097 4098 #ifdef HDA_USE_DMA_ACCESS_HANDLER 4099 /** 4100 * HC access handler for the FIFO. 4101 * 4102 * @returns VINF_SUCCESS if the handler have carried out the operation. 4103 * @returns VINF_PGM_HANDLER_DO_DEFAULT if the caller should carry out the access operation. 4104 * @param pVM VM Handle. 4105 * @param pVCpu The cross context CPU structure for the calling EMT. 4106 * @param GCPhys The physical address the guest is writing to. 4107 * @param pvPhys The HC mapping of that address. 4108 * @param pvBuf What the guest is reading/writing. 4109 * @param cbBuf How much it's reading/writing. 4110 * @param enmAccessType The access type. 4111 * @param enmOrigin Who is making the access. 4112 * @param pvUser User argument. 4113 */ 4114 static DECLCALLBACK(VBOXSTRICTRC) hdaDMAAccessHandler(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys, void *pvPhys, 4115 void *pvBuf, size_t cbBuf, 4116 PGMACCESSTYPE enmAccessType, PGMACCESSORIGIN enmOrigin, void *pvUser) 4117 { 4118 RT_NOREF(pVM, pVCpu, pvPhys, pvBuf, enmOrigin); 4119 4120 PHDADMAACCESSHANDLER pHandler = (PHDADMAACCESSHANDLER)pvUser; 4121 AssertPtr(pHandler); 4122 4123 PHDASTREAM pStream = pHandler->pStream; 4124 AssertPtr(pStream); 4125 4126 Assert(GCPhys >= pHandler->GCPhysFirst); 4127 Assert(GCPhys <= pHandler->GCPhysLast); 4128 Assert(enmAccessType == PGMACCESSTYPE_WRITE); 4129 4130 /* Not within BDLE range? Bail out. */ 4131 if ( (GCPhys < pHandler->BDLEAddr) 4132 || (GCPhys + cbBuf > pHandler->BDLEAddr + pHandler->BDLESize)) 4133 { 4134 return VINF_PGM_HANDLER_DO_DEFAULT; 4135 } 4136 4137 switch(enmAccessType) 4138 { 4139 case PGMACCESSTYPE_WRITE: 4140 { 4141 # ifdef DEBUG 4142 PHDASTREAMDBGINFO pStreamDbg = &pStream->Dbg; 4143 4144 const uint64_t tsNowNs = RTTimeNanoTS(); 4145 const uint32_t tsElapsedMs = (tsNowNs - pStreamDbg->tsWriteSlotBegin) / 1000 / 1000; 4146 4147 uint64_t cWritesHz = ASMAtomicReadU64(&pStreamDbg->cWritesHz); 4148 uint64_t cbWrittenHz = ASMAtomicReadU64(&pStreamDbg->cbWrittenHz); 4149 4150 if (tsElapsedMs >= (1000 / HDA_TIMER_HZ)) 4151 { 4152 LogFunc(("[SD%RU8] %RU32ms elapsed, cbWritten=%RU64, cWritten=%RU64 -- %RU32 bytes on average per time slot (%zums)\n", 4153 pStream->u8SD, tsElapsedMs, cbWrittenHz, cWritesHz, 4154 ASMDivU64ByU32RetU32(cbWrittenHz, cWritesHz ? cWritesHz : 1), 1000 / HDA_TIMER_HZ)); 4155 4156 pStreamDbg->tsWriteSlotBegin = tsNowNs; 4157 4158 cWritesHz = 0; 4159 cbWrittenHz = 0; 4160 } 4161 4162 cWritesHz += 1; 4163 cbWrittenHz += cbBuf; 4164 4165 ASMAtomicIncU64(&pStreamDbg->cWritesTotal); 4166 ASMAtomicAddU64(&pStreamDbg->cbWrittenTotal, cbBuf); 4167 4168 ASMAtomicWriteU64(&pStreamDbg->cWritesHz, cWritesHz); 4169 ASMAtomicWriteU64(&pStreamDbg->cbWrittenHz, cbWrittenHz); 4170 4171 LogFunc(("[SD%RU8] Writing %3zu @ 0x%x (off %zu)\n", 4172 pStream->u8SD, cbBuf, GCPhys, GCPhys - pHandler->BDLEAddr)); 4173 4174 LogFunc(("[SD%RU8] cWrites=%RU64, cbWritten=%RU64 -> %RU32 bytes on average\n", 4175 pStream->u8SD, pStreamDbg->cWritesTotal, pStreamDbg->cbWrittenTotal, 4176 ASMDivU64ByU32RetU32(pStreamDbg->cbWrittenTotal, pStreamDbg->cWritesTotal))); 4177 # endif 4178 4179 # ifdef VBOX_AUDIO_DEBUG_DUMP_PCM_DATA 4180 RTFILE fh; 4181 RTFileOpen(&fh, VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH "hdaDMAAccessWrite.pcm", 4182 RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE); 4183 RTFileWrite(fh, pvBuf, cbBuf, NULL); 4184 RTFileClose(fh); 4185 # endif 4186 4187 # ifdef HDA_USE_DMA_ACCESS_HANDLER_WRITING 4188 PRTCIRCBUF pCircBuf = pStream->State.pCircBuf; 4189 AssertPtr(pCircBuf); 4190 4191 uint8_t *pbBuf = (uint8_t *)pvBuf; 4192 while (cbBuf) 4193 { 4194 /* Make sure we only copy as much as the stream's FIFO can hold (SDFIFOS, 18.2.39). */ 4195 void *pvChunk; 4196 size_t cbChunk; 4197 RTCircBufAcquireWriteBlock(pCircBuf, cbBuf, &pvChunk, &cbChunk); 4198 4199 if (cbChunk) 4200 { 4201 memcpy(pvChunk, pbBuf, cbChunk); 4202 4203 pbBuf += cbChunk; 4204 Assert(cbBuf >= cbChunk); 4205 cbBuf -= cbChunk; 4206 } 4207 else 4208 { 4209 //AssertMsg(RTCircBufFree(pCircBuf), ("No more space but still %zu bytes to write\n", cbBuf)); 4210 break; 4211 } 4212 4213 LogFunc(("[SD%RU8] cbChunk=%zu\n", pStream->u8SD, cbChunk)); 4214 4215 RTCircBufReleaseWriteBlock(pCircBuf, cbChunk); 4216 } 4217 # endif /* HDA_USE_DMA_ACCESS_HANDLER_WRITING */ 4218 break; 4219 } 4220 4221 default: 4222 AssertMsgFailed(("Access type not implemented\n")); 4223 break; 4224 } 4225 4226 return VINF_PGM_HANDLER_DO_DEFAULT; 4227 } 4228 #endif /* HDA_USE_DMA_ACCESS_HANDLER */ 3810 4229 3811 4230 /**
Note:
See TracChangeset
for help on using the changeset viewer.