VirtualBox

Changeset 89680 in vbox


Ignore:
Timestamp:
Jun 14, 2021 1:25:44 PM (4 years ago)
Author:
vboxsync
Message:

DevIchAc97: Try deal with zero sized buffer descriptors (untested). Moved CIV advancing to ichac97R3StreamFetchBDLE, renaming it to ichac97R3StreamFetchNextBdle. Added four ASSERT_GUEST check on reserved BDLE bits and odd lengths. bugref:9890

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Audio/DevIchAc97.cpp

    r89664 r89680  
    2525#include <VBox/vmm/pdmaudioifs.h>
    2626#include <VBox/vmm/pdmaudioinline.h>
     27#include <VBox/AssertGuest.h>
    2728
    2829#include <iprt/assert.h>
     
    129130
    130131#define AC97_BD_LEN_MASK        0xFFFF              /**< Mask for the BDL buffer length. */
     132
     133#define AC97_BD_LEN_CTL_MBZ     UINT32_C(0x3fff0000) /**< Must-be-zero mask for AC97BDLE.ctl_len. */
    131134
    132135#define AC97_MAX_BDLE           32                  /**< Maximum number of BDLEs. */
     
    820823
    821824/**
    822  * Fetches the current BDLE (Buffer Descriptor List Entry) of an AC'97 audio stream.
    823  *
    824  * @returns VBox status code.
     825 * Fetches the next buffer descriptor (BDLE) updating the stream registers.
     826 *
     827 * This will skip zero length descriptors.
     828 *
     829 * @returns Zero, or AC97_SR_BCIS if skipped zero length buffer with IOC set.
    825830 * @param   pDevIns             The device instance.
    826831 * @param   pStream             AC'97 stream to fetch BDLE for.
    827  *
    828  * @remark  Uses CIV as BDLE index.
    829  */
    830 static void ichac97R3StreamFetchBDLE(PPDMDEVINS pDevIns, PAC97STREAM pStream)
    831 {
    832     PAC97BMREGS pRegs = &pStream->Regs;
    833 
    834     AC97BDLE BDLE;
    835     PDMDevHlpPCIPhysRead(pDevIns, pRegs->bdbar + pRegs->civ * sizeof(AC97BDLE), &BDLE, sizeof(AC97BDLE));
    836     pRegs->bd_valid   = 1;
    837 # ifndef RT_LITTLE_ENDIAN
    838 #  error "Please adapt the code (audio buffers are little endian)!"
    839 # else
    840     pRegs->bd.addr    = RT_H2LE_U32(BDLE.addr & ~3);
    841     pRegs->bd.ctl_len = RT_H2LE_U32(BDLE.ctl_len);
    842 # endif
    843     pRegs->picb       = pRegs->bd.ctl_len & AC97_BD_LEN_MASK;
    844     LogFlowFunc(("bd %2d addr=%#x ctl=%#06x len=%#x(%d bytes), bup=%RTbool, ioc=%RTbool\n",
    845                   pRegs->civ, pRegs->bd.addr, pRegs->bd.ctl_len >> 16,
    846                   pRegs->bd.ctl_len & AC97_BD_LEN_MASK,
    847                  (pRegs->bd.ctl_len & AC97_BD_LEN_MASK) << 1,  /** @todo r=andy Assumes 16bit samples. */
    848                   RT_BOOL(pRegs->bd.ctl_len & AC97_BD_BUP),
    849                   RT_BOOL(pRegs->bd.ctl_len & AC97_BD_IOC)));
    850     /** @todo r=bird: Several of the specificiation states that zero length BDL
    851      *        entries are okay, as long as they aren't at the head or end.  We
    852      *        should simply skip up to 30 empty ones, because otherwise the timer
    853      *        locking falls flat on its face. */
     832 * @param   pStreamCC           The AC'97 stream, ring-3 state.
     833 *
     834 * @remark  Updates CIV, PIV, BD and PICB.
     835 */
     836static uint32_t ichac97R3StreamFetchNextBdle(PPDMDEVINS pDevIns, PAC97STREAM pStream, PAC97STREAMR3 pStreamCC)
     837{
     838    RT_NOREF(pStreamCC);
     839    uint32_t fSrBcis = 0;
     840
     841    /*
     842     * Loop for skipping zero length entries.
     843     */
     844    for (;;)
     845    {
     846        /* Advance the buffer. */
     847        pStream->Regs.civ = pStream->Regs.piv;
     848        pStream->Regs.piv = (pStream->Regs.piv + 1) % AC97_MAX_BDLE;
     849
     850        /* Load it. */
     851        AC97BDLE Bdle = { 0, 0 };
     852        PDMDevHlpPCIPhysRead(pDevIns, pStream->Regs.bdbar + pStream->Regs.civ * sizeof(AC97BDLE), &Bdle, sizeof(AC97BDLE));
     853        pStream->Regs.bd_valid   = 1;
     854        pStream->Regs.bd.addr    = RT_H2LE_U32(Bdle.addr) & ~3;
     855        pStream->Regs.bd.ctl_len = RT_H2LE_U32(Bdle.ctl_len);
     856        pStream->Regs.picb       = pStream->Regs.bd.ctl_len & AC97_BD_LEN_MASK;
     857
     858        LogFlowFunc(("BDLE%02u: %#RX32 L %#x / LB %#x, ctl=%#06x\n",
     859                     pStream->Regs.civ, pStream->Regs.bd.addr, pStream->Regs.bd.ctl_len & AC97_BD_LEN_MASK,
     860                     (pStream->Regs.bd.ctl_len & AC97_BD_LEN_MASK) * PDMAudioPropsSampleSize(&pStreamCC->State.Cfg.Props),
     861                     pStream->Regs.bd.ctl_len >> 16,
     862                     pStream->Regs.bd.ctl_len & AC97_BD_IOC ? " ioc" : "",
     863                     pStream->Regs.bd.ctl_len & AC97_BD_BUP ? " bup" : ""));
     864
     865        /* Complain about any reserved bits set in CTL and ADDR: */
     866        ASSERT_GUEST_MSG(!(pStream->Regs.bd.ctl_len & AC97_BD_LEN_CTL_MBZ),
     867                         ("Reserved bits set: %#RX32\n", pStream->Regs.bd.ctl_len));
     868        ASSERT_GUEST_MSG(!(RT_H2LE_U32(Bdle.addr) & 3),
     869                         ("Reserved addr bits set: %#RX32\n", RT_H2LE_U32(Bdle.addr) ));
     870
     871        /* If the length is non-zero or if we've reached LVI, we're done regardless
     872           of what's been loaded.  Otherwise, we skip zero length buffers. */
     873        if (pStream->Regs.picb)
     874            break;
     875        if (pStream->Regs.civ == pStream->Regs.lvi)
     876        {
     877            LogFunc(("BDLE%02u is zero length! Can't skip (CIV=LVI). %#RX32 %#RX32\n", pStream->Regs.civ, Bdle.addr, Bdle.ctl_len));
     878            break;
     879        }
     880        LogFunc(("BDLE%02u is zero length! Skipping. %#RX32 %#RX32\n", pStream->Regs.civ, Bdle.addr, Bdle.ctl_len));
     881
     882        /* If the buffer has IOC set, make sure it's triggered by the caller. */
     883        if (   (pStream->Regs.bd.ctl_len & AC97_BD_IOC)
     884            && (pStream->Regs.bd.ctl_len & AC97_BD_IOC))
     885            fSrBcis |= AC97_SR_BCIS;
     886    }
     887
     888    /* 1.2.4.2 PCM Buffer Restrictions (in 302349-003) - #1  */
     889    ASSERT_GUEST_MSG(!(pStream->Regs.picb & 1),
     890                     ("Odd lengths buffers are not allowed: %#x (%d) samples\n",  pStream->Regs.picb, pStream->Regs.picb));
     891
     892    /* 1.2.4.2 PCM Buffer Restrictions (in 302349-003) - #2  */
     893    ASSERT_GUEST_MSG(pStream->Regs.picb > 0, ("Zero length buffers not allowed to terminate list (LVI=%u CIV=%u)\n",
     894                                              pStream->Regs.lvi, pStream->Regs.civ));
     895
     896    return fSrBcis;
    854897}
    855898
     
    26132656
    26142657            pRegs->sr &= ~AC97_SR_CELV;
    2615             pRegs->civ = pRegs->piv;
    2616             pRegs->piv = (pRegs->piv + 1) % AC97_MAX_BDLE;
    2617 
    2618             ichac97R3StreamFetchBDLE(pDevIns, pStream);
     2658            if (ichac97R3StreamFetchNextBdle(pDevIns, pStream, pStreamCC))
     2659                ichac97StreamUpdateSR(pDevIns, pThis, pStream, pRegs->sr | AC97_SR_BCIS);
    26192660            continue;
    26202661        }
     
    27172758            }
    27182759            else
    2719             {
    2720                 pRegs->civ = pRegs->piv;
    2721                 pRegs->piv = (pRegs->piv + 1) % AC97_MAX_BDLE;
    2722                 ichac97R3StreamFetchBDLE(pDevIns, pStream);
    2723             }
     2760                new_sr |= ichac97R3StreamFetchNextBdle(pDevIns, pStream, pStreamCC);
    27242761
    27252762            ichac97StreamUpdateSR(pDevIns, pThis, pStream, new_sr);
     
    30013038                                Log3Func(("[SD%RU8] Enable\n", pStream->u8SD));
    30023039
    3003                                 pRegs->civ = pRegs->piv;
    3004                                 pRegs->piv = (pRegs->piv + 1) % AC97_MAX_BDLE;
    3005 
    30063040                                pRegs->sr &= ~AC97_SR_DCH;
    30073041
    3008                                 /* Fetch the initial BDLE descriptor. */
    3009                                 ichac97R3StreamFetchBDLE(pDevIns, pStream);
     3042                                if (ichac97R3StreamFetchNextBdle(pDevIns, pStream, pStreamCC))
     3043                                    ichac97StreamUpdateSR(pDevIns, pThis, pStream, pRegs->sr | AC97_SR_BCIS);
    30103044# ifdef LOG_ENABLED
    30113045                                if (LogIsFlowEnabled())
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette