- Timestamp:
- Jun 24, 2021 10:02:02 AM (4 years ago)
- svn:sync-xref-src-repo-rev:
- 145334
- Location:
- trunk/src/VBox/Devices/Audio
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DevHda.cpp
r89874 r89876 62 62 *********************************************************************************************************************************/ 63 63 //#define HDA_AS_PCI_EXPRESS 64 65 /* Installs a DMA access handler (via PGM callback) to monitor66 * HDA's DMA operations, that is, writing / reading audio stream data.67 *68 * !!! Note: Certain guests are *that* timing sensitive that when enabling !!!69 * !!! such a handler will mess up audio completely (e.g. Windows 7). !!! */70 //#define HDA_USE_DMA_ACCESS_HANDLER71 #ifdef HDA_USE_DMA_ACCESS_HANDLER72 # include <VBox/vmm/pgm.h>73 #endif74 64 75 65 /* Uses the DMA access handler to read the written DMA audio (output) data. … … 174 164 R3PTRTYPE(PAUDMIXSTREAM) pMixStrm; 175 165 } HDADRIVERSTREAM, *PHDADRIVERSTREAM; 176 177 #ifdef HDA_USE_DMA_ACCESS_HANDLER178 /**179 * Struct for keeping an HDA DMA access handler context.180 */181 typedef struct HDADMAACCESSHANDLER182 {183 /** Node for storing this handler in our list in HDASTREAMSTATE. */184 RTLISTNODER3 Node;185 /** Pointer to stream to which this access handler is assigned to. */186 R3PTRTYPE(PHDASTREAM) pStream;187 /** Access handler type handle. */188 PGMPHYSHANDLERTYPE hAccessHandlerType;189 /** First address this handler uses. */190 RTGCPHYS GCPhysFirst;191 /** Last address this handler uses. */192 RTGCPHYS GCPhysLast;193 /** Actual BDLE address to handle. */194 RTGCPHYS BDLEAddr;195 /** Actual BDLE buffer size to handle. */196 RTGCPHYS BDLESize;197 /** Whether the access handler has been registered or not. */198 bool fRegistered;199 uint8_t Padding[3];200 } HDADMAACCESSHANDLER, *PHDADMAACCESSHANDLER;201 #endif202 166 203 167 /** … … 345 309 static int hdaR3AddStream(PHDASTATER3 pThisCC, PPDMAUDIOSTREAMCFG pCfg); 346 310 static int hdaR3RemoveStream(PHDASTATER3 pThisCC, PPDMAUDIOSTREAMCFG pCfg); 347 # ifdef HDA_USE_DMA_ACCESS_HANDLER348 static DECLCALLBACK(VBOXSTRICTRC) hdaR3DmaAccessHandler(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys, void *pvPhys,349 void *pvBuf, size_t cbBuf,350 PGMACCESSTYPE enmAccessType, PGMACCESSORIGIN enmOrigin, void *pvUser);351 # endif352 311 #endif /* IN_RING3 */ 353 312 /** @} */ … … 1603 1562 AssertReturn(idxStream < RT_ELEMENTS(pThis->aStreams), VERR_INTERNAL_ERROR_3); /* paranoia^2: Bad g_aHdaRegMap. */ 1604 1563 1605 #ifdef HDA_USE_DMA_ACCESS_HANDLER1606 if (hdaGetDirFromSD(uSD) == PDMAUDIODIR_OUT)1607 {1608 /* Try registering the DMA handlers.1609 * As we can't be sure in which order LVI + BDL base are set, try registering in both routines. */1610 PHDASTREAM pStream = hdaGetStreamFromSD(pThis, idxStream);1611 if ( pStream1612 && hdaR3StreamRegisterDMAHandlers(pThis, pStream))1613 LogFunc(("[SD%RU8] DMA logging enabled\n", pStream->u8SD));1614 }1615 #endif1616 1617 1564 ASSERT_GUEST_LOGREL_MSG(u32Value <= UINT8_MAX, /* Should be covered by the register write mask, but just to make sure. */ 1618 1565 ("LVI for stream #%zu must not be bigger than %RU8\n", idxStream, UINT8_MAX - 1)); … … 1985 1932 DECLINLINE(VBOXSTRICTRC) hdaRegWriteSDBDPX(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value, uint8_t uSD) 1986 1933 { 1987 #ifndef HDA_USE_DMA_ACCESS_HANDLER1988 1934 RT_NOREF(uSD); 1989 1935 return hdaRegWriteU32(pDevIns, pThis, iReg, u32Value); 1990 #else1991 # ifdef IN_RING31992 if (hdaGetDirFromSD(uSD) == PDMAUDIODIR_OUT)1993 {1994 /* Try registering the DMA handlers.1995 * As we can't be sure in which order LVI + BDL base are set, try registering in both routines. */1996 PHDASTREAM pStream = hdaGetStreamFromSD(pThis, uSD);1997 if ( pStream1998 && hdaR3StreamRegisterDMAHandlers(pThis, pStream))1999 LogFunc(("[SD%RU8] DMA logging enabled\n", pStream->u8SD));2000 }2001 return hdaRegWriteU32(pDevIns, pThis, iReg, u32Value);2002 # else2003 RT_NOREF(pDevIns, pThis, iReg, u32Value, uSD);2004 return VINF_IOM_R3_MMIO_WRITE;2005 # endif2006 #endif2007 1936 } 2008 1937 … … 2726 2655 } 2727 2656 2728 # ifdef HDA_USE_DMA_ACCESS_HANDLER2729 /**2730 * HC access handler for the FIFO.2731 *2732 * @returns VINF_SUCCESS if the handler have carried out the operation.2733 * @returns VINF_PGM_HANDLER_DO_DEFAULT if the caller should carry out the access operation.2734 * @param pVM VM Handle.2735 * @param pVCpu The cross context CPU structure for the calling EMT.2736 * @param GCPhys The physical address the guest is writing to.2737 * @param pvPhys The HC mapping of that address.2738 * @param pvBuf What the guest is reading/writing.2739 * @param cbBuf How much it's reading/writing.2740 * @param enmAccessType The access type.2741 * @param enmOrigin Who is making the access.2742 * @param pvUser User argument.2743 */2744 static DECLCALLBACK(VBOXSTRICTRC) hdaR3DmaAccessHandler(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys, void *pvPhys,2745 void *pvBuf, size_t cbBuf,2746 PGMACCESSTYPE enmAccessType, PGMACCESSORIGIN enmOrigin, void *pvUser)2747 {2748 RT_NOREF(pVM, pVCpu, pvPhys, pvBuf, enmOrigin);2749 2750 PHDADMAACCESSHANDLER pHandler = (PHDADMAACCESSHANDLER)pvUser;2751 AssertPtr(pHandler);2752 2753 PHDASTREAM pStream = pHandler->pStream;2754 AssertPtr(pStream);2755 2756 Assert(GCPhys >= pHandler->GCPhysFirst);2757 Assert(GCPhys <= pHandler->GCPhysLast);2758 Assert(enmAccessType == PGMACCESSTYPE_WRITE);2759 2760 /* Not within BDLE range? Bail out. */2761 if ( (GCPhys < pHandler->BDLEAddr)2762 || (GCPhys + cbBuf > pHandler->BDLEAddr + pHandler->BDLESize))2763 {2764 return VINF_PGM_HANDLER_DO_DEFAULT;2765 }2766 2767 switch (enmAccessType)2768 {2769 case PGMACCESSTYPE_WRITE:2770 {2771 # ifdef DEBUG2772 const uint64_t tsNowNs = RTTimeNanoTS();2773 const uint32_t tsElapsedMs = (tsNowNs - pStream->Dbg.tsWriteSlotBegin) / 1000 / 1000;2774 2775 uint64_t cWritesHz = ASMAtomicReadU64(&pStream->Dbg.cWritesHz);2776 uint64_t cbWrittenHz = ASMAtomicReadU64(&pStream->Dbg.cbWrittenHz);2777 2778 if (tsElapsedMs >= (1000 / HDA_TIMER_HZ_DEFAULT))2779 {2780 LogFunc(("[SD%RU8] %RU32ms elapsed, cbWritten=%RU64, cWritten=%RU64 -- %RU32 bytes on average per time slot (%zums)\n",2781 pStream->u8SD, tsElapsedMs, cbWrittenHz, cWritesHz,2782 ASMDivU64ByU32RetU32(cbWrittenHz, cWritesHz ? cWritesHz : 1), 1000 / HDA_TIMER_HZ_DEFAULT));2783 2784 pStream->Dbg.tsWriteSlotBegin = tsNowNs;2785 2786 cWritesHz = 0;2787 cbWrittenHz = 0;2788 }2789 2790 cWritesHz += 1;2791 cbWrittenHz += cbBuf;2792 2793 ASMAtomicIncU64(&pStream->Dbg.cWritesTotal);2794 ASMAtomicAddU64(&pStream->Dbg.cbWrittenTotal, cbBuf);2795 2796 ASMAtomicWriteU64(&pStream->Dbg.cWritesHz, cWritesHz);2797 ASMAtomicWriteU64(&pStream->Dbg.cbWrittenHz, cbWrittenHz);2798 2799 LogFunc(("[SD%RU8] Writing %3zu @ 0x%x (off %zu)\n",2800 pStream->u8SD, cbBuf, GCPhys, GCPhys - pHandler->BDLEAddr));2801 2802 LogFunc(("[SD%RU8] cWrites=%RU64, cbWritten=%RU64 -> %RU32 bytes on average\n",2803 pStream->u8SD, pStream->Dbg.cWritesTotal, pStream->Dbg.cbWrittenTotal,2804 ASMDivU64ByU32RetU32(pStream->Dbg.cbWrittenTotal, pStream->Dbg.cWritesTotal)));2805 # endif2806 2807 # ifdef VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH2808 if (pThis->fDebugEnabled)2809 {2810 RTFILE fh;2811 RTFileOpen(&fh, VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH "hdaDMAAccessWrite.pcm",2812 RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);2813 RTFileWrite(fh, pvBuf, cbBuf, NULL);2814 RTFileClose(fh);2815 }2816 # endif2817 2818 # ifdef HDA_USE_DMA_ACCESS_HANDLER_WRITING2819 PRTCIRCBUF pCircBuf = pStream->State.pCircBuf;2820 AssertPtr(pCircBuf);2821 2822 uint8_t *pbBuf = (uint8_t *)pvBuf;2823 while (cbBuf)2824 {2825 /* Make sure we only copy as much as the stream's FIFO can hold (SDFIFOS, 18.2.39). */2826 void *pvChunk;2827 size_t cbChunk;2828 RTCircBufAcquireWriteBlock(pCircBuf, cbBuf, &pvChunk, &cbChunk);2829 2830 if (cbChunk)2831 {2832 memcpy(pvChunk, pbBuf, cbChunk);2833 2834 pbBuf += cbChunk;2835 Assert(cbBuf >= cbChunk);2836 cbBuf -= cbChunk;2837 }2838 else2839 {2840 //AssertMsg(RTCircBufFree(pCircBuf), ("No more space but still %zu bytes to write\n", cbBuf));2841 break;2842 }2843 2844 LogFunc(("[SD%RU8] cbChunk=%zu\n", pStream->u8SD, cbChunk));2845 2846 RTCircBufReleaseWriteBlock(pCircBuf, cbChunk);2847 }2848 # endif /* HDA_USE_DMA_ACCESS_HANDLER_WRITING */2849 break;2850 }2851 2852 default:2853 AssertMsgFailed(("Access type not implemented\n"));2854 break;2855 }2856 2857 return VINF_PGM_HANDLER_DO_DEFAULT;2858 }2859 # endif /* HDA_USE_DMA_ACCESS_HANDLER */2860 2861 2657 /** 2862 2658 * Soft reset of the device triggered via GCTL. … … 3588 3384 rc2 = hdaR3AddStream(pThisCC, &pStreamShared->State.Cfg); 3589 3385 AssertRC(rc2); 3590 3591 #ifdef HDA_USE_DMA_ACCESS_HANDLER3592 /* (Re-)install the DMA handler. */3593 hdaR3StreamRegisterDMAHandlers(pThis, pStreamShared);3594 #endif3595 3386 3596 3387 /* Use the LPIB to find the current scheduling position. If this isn't -
trunk/src/VBox/Devices/Audio/DevHdaStream.cpp
r89875 r89876 81 81 pStreamShared->State.fInReset = false; 82 82 pStreamShared->State.fRunning = false; 83 # ifdef HDA_USE_DMA_ACCESS_HANDLER84 RTListInit(&pStreamR3->State.lstDMAHandlers);85 # endif86 83 87 84 AssertPtr(pStreamR3->pHDAStateR3); … … 855 852 HDA_STREAM_REG(pThis, BDPU, uSD) = 0; 856 853 HDA_STREAM_REG(pThis, BDPL, uSD) = 0; 857 858 # ifdef HDA_USE_DMA_ACCESS_HANDLER859 hdaR3StreamUnregisterDMAHandlers(pThis, pStream);860 # endif861 854 862 855 /* Assign the default mixer sink to the stream. */ … … 2600 2593 } 2601 2594 2602 2603 # ifdef HDA_USE_DMA_ACCESS_HANDLER2604 /**2605 * Registers access handlers for a stream's BDLE DMA accesses.2606 *2607 * @returns true if registration was successful, false if not.2608 * @param pStream HDA stream to register BDLE access handlers for.2609 */2610 bool hdaR3StreamRegisterDMAHandlers(PHDASTREAM pStream)2611 {2612 /* At least LVI and the BDL base must be set. */2613 if ( !pStreamShared->u16LVI2614 || !pStreamShared->u64BDLBase)2615 {2616 return false;2617 }2618 2619 hdaR3StreamUnregisterDMAHandlers(pStream);2620 2621 LogFunc(("Registering ...\n"));2622 2623 int rc = VINF_SUCCESS;2624 2625 /*2626 * Create BDLE ranges.2627 */2628 2629 struct BDLERANGE2630 {2631 RTGCPHYS uAddr;2632 uint32_t uSize;2633 } arrRanges[16]; /** @todo Use a define. */2634 2635 size_t cRanges = 0;2636 2637 for (uint16_t i = 0; i < pStreamShared->u16LVI + 1; i++)2638 {2639 HDABDLE BDLE;2640 rc = hdaR3BDLEFetch(pDevIns, &BDLE, pStreamShared->u64BDLBase, i /* Index */);2641 if (RT_FAILURE(rc))2642 break;2643 2644 bool fAddRange = true;2645 BDLERANGE *pRange;2646 2647 if (cRanges)2648 {2649 pRange = &arrRanges[cRanges - 1];2650 2651 /* Is the current range a direct neighbor of the current BLDE? */2652 if ((pRange->uAddr + pRange->uSize) == BDLE.Desc.u64BufAddr)2653 {2654 /* Expand the current range by the current BDLE's size. */2655 pRange->uSize += BDLE.Desc.u32BufSize;2656 2657 /* Adding a new range in this case is not needed anymore. */2658 fAddRange = false;2659 2660 LogFunc(("Expanding range %zu by %RU32 (%RU32 total now)\n", cRanges - 1, BDLE.Desc.u32BufSize, pRange->uSize));2661 }2662 }2663 2664 /* Do we need to add a new range? */2665 if ( fAddRange2666 && cRanges < RT_ELEMENTS(arrRanges))2667 {2668 pRange = &arrRanges[cRanges];2669 2670 pRange->uAddr = BDLE.Desc.u64BufAddr;2671 pRange->uSize = BDLE.Desc.u32BufSize;2672 2673 LogFunc(("Adding range %zu - 0x%x (%RU32)\n", cRanges, pRange->uAddr, pRange->uSize));2674 2675 cRanges++;2676 }2677 }2678 2679 LogFunc(("%zu ranges total\n", cRanges));2680 2681 /*2682 * Register all ranges as DMA access handlers.2683 */2684 2685 for (size_t i = 0; i < cRanges; i++)2686 {2687 BDLERANGE *pRange = &arrRanges[i];2688 2689 PHDADMAACCESSHANDLER pHandler = (PHDADMAACCESSHANDLER)RTMemAllocZ(sizeof(HDADMAACCESSHANDLER));2690 if (!pHandler)2691 {2692 rc = VERR_NO_MEMORY;2693 break;2694 }2695 2696 RTListAppend(&pStream->State.lstDMAHandlers, &pHandler->Node);2697 2698 pHandler->pStream = pStream; /* Save a back reference to the owner. */2699 2700 char szDesc[32];2701 RTStrPrintf(szDesc, sizeof(szDesc), "HDA[SD%RU8 - RANGE%02zu]", pStream->u8SD, i);2702 2703 int rc2 = PGMR3HandlerPhysicalTypeRegister(PDMDevHlpGetVM(pStream->pHDAState->pDevInsR3), PGMPHYSHANDLERKIND_WRITE,2704 hdaDMAAccessHandler,2705 NULL, NULL, NULL,2706 NULL, NULL, NULL,2707 szDesc, &pHandler->hAccessHandlerType);2708 AssertRCBreak(rc2);2709 2710 pHandler->BDLEAddr = pRange->uAddr;2711 pHandler->BDLESize = pRange->uSize;2712 2713 /* Get first and last pages of the BDLE range. */2714 RTGCPHYS pgFirst = pRange->uAddr & ~PAGE_OFFSET_MASK;2715 RTGCPHYS pgLast = RT_ALIGN(pgFirst + pRange->uSize, PAGE_SIZE);2716 2717 /* Calculate the region size (in pages). */2718 RTGCPHYS regionSize = RT_ALIGN(pgLast - pgFirst, PAGE_SIZE);2719 2720 pHandler->GCPhysFirst = pgFirst;2721 pHandler->GCPhysLast = pHandler->GCPhysFirst + (regionSize - 1);2722 2723 LogFunc((" Registering region '%s': %#RGp - %#RGp (region size: %#zx)\n",2724 szDesc, pHandler->GCPhysFirst, pHandler->GCPhysLast, regionSize));2725 LogFunc((" BDLE @ %#RGp - %#RGp (%#RX32)\n",2726 pHandler->BDLEAddr, pHandler->BDLEAddr + pHandler->BDLESize, pHandler->BDLESize));2727 2728 rc2 = PGMHandlerPhysicalRegister(PDMDevHlpGetVM(pStream->pHDAState->pDevInsR3),2729 pHandler->GCPhysFirst, pHandler->GCPhysLast,2730 pHandler->hAccessHandlerType, pHandler, NIL_RTR0PTR, NIL_RTRCPTR,2731 szDesc);2732 AssertRCBreak(rc2);2733 2734 pHandler->fRegistered = true;2735 }2736 2737 LogFunc(("Registration ended with rc=%Rrc\n", rc));2738 2739 return RT_SUCCESS(rc);2740 }2741 2742 /**2743 * Unregisters access handlers of a stream's BDLEs.2744 *2745 * @param pStream HDA stream to unregister BDLE access handlers for.2746 */2747 void hdaR3StreamUnregisterDMAHandlers(PHDASTREAM pStream)2748 {2749 LogFunc(("\n"));2750 2751 PHDADMAACCESSHANDLER pHandler, pHandlerNext;2752 RTListForEachSafe(&pStream->State.lstDMAHandlers, pHandler, pHandlerNext, HDADMAACCESSHANDLER, Node)2753 {2754 if (!pHandler->fRegistered) /* Handler not registered? Skip. */2755 continue;2756 2757 LogFunc(("Unregistering 0x%x - 0x%x (%zu)\n",2758 pHandler->GCPhysFirst, pHandler->GCPhysLast, pHandler->GCPhysLast - pHandler->GCPhysFirst));2759 2760 int rc2 = PGMHandlerPhysicalDeregister(PDMDevHlpGetVM(pStream->pHDAState->pDevInsR3),2761 pHandler->GCPhysFirst);2762 AssertRC(rc2);2763 2764 RTListNodeRemove(&pHandler->Node);2765 2766 RTMemFree(pHandler);2767 pHandler = NULL;2768 }2769 2770 Assert(RTListIsEmpty(&pStream->State.lstDMAHandlers));2771 }2772 2773 # endif /* HDA_USE_DMA_ACCESS_HANDLER */2774 2775 2595 #endif /* IN_RING3 */ 2596 -
trunk/src/VBox/Devices/Audio/DevHdaStream.h
r89874 r89876 283 283 /** Circular buffer (FIFO) for holding DMA'ed data. */ 284 284 R3PTRTYPE(PRTCIRCBUF) pCircBuf; 285 #ifdef HDA_USE_DMA_ACCESS_HANDLER286 /** List of DMA handlers. */287 RTLISTANCHORR3 lstDMAHandlers;288 #endif289 285 /** The mixer sink this stream has registered AIO update callback with. 290 286 * This is NULL till we register it, typically in hdaR3StreamEnable. … … 347 343 PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3); 348 344 DECLCALLBACK(void) hdaR3StreamUpdateAsyncIoJob(PPDMDEVINS pDevIns, PAUDMIXSINK pSink, void *pvUser); 349 # ifdef HDA_USE_DMA_ACCESS_HANDLER350 bool hdaR3StreamRegisterDMAHandlers(PHDASTREAM pStream);351 void hdaR3StreamUnregisterDMAHandlers(PHDASTREAM pStream);352 # endif353 345 /** @} */ 354 346
Note:
See TracChangeset
for help on using the changeset viewer.