VirtualBox

Changeset 44665 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Feb 13, 2013 11:44:45 AM (12 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
83758
Message:

DevIchIntelHDA.cpp: Fixed the MMIO access handlers.

File:
1 edited

Legend:

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

    r44647 r44665  
    22/** @file
    33 * DevIchIntelHD - VBox ICH Intel HD Audio Controller.
     4 *
     5 * @todo Exactly which datasheet PDF was used to produce this code? Would be
     6 *       great to know what to check the guest and emulation behavior against.
    47 */
    58
     
    5962# error "Please specify your HDA device vendor/device IDs"
    6063#endif
     64
     65/** @todo r=bird: Looking at what the linux driver (accidentally?) does when
     66 *        updating CORBWP, I belive that the ICH6 spec is wrong and that CORBRP
     67 *        is read only except for bit 15. The bit 15 implementation is, btw.,
     68 *        not according to Intel document number 301473-002, but not know
     69 *        exactly which document to check against, I might be mistaken
     70 *        here... */
     71#define BIRD_THINKS_CORBRP_IS_MOSTLY_RO
    6172
    6273#define HDA_NREGS 112
     
    529540DECLINLINE(void) hdaInitTransferDescriptor(PHDASTATE pThis, PHDABDLEDESC pBdle, uint8_t u8Strm,
    530541                                           PHDASTREAMTRANSFERDESC pStreamDesc);
    531 static int hdaMMIORegLookup(PHDASTATE pThis, uint32_t offReg);
    532542static void hdaFetchBdle(PHDASTATE pThis, PHDABDLEDESC pBdle, PHDASTREAMTRANSFERDESC pStreamDesc);
    533543#ifdef LOG_ENABLED
     
    540550*******************************************************************************/
    541551/* see 302349 p 6.2*/
    542 static const struct
     552static const struct HDAREGDESC
    543553{
    544554    /** Register offset in the register space. */
     
    558568    /** Full name. */
    559569    const char *name;
    560 } g_aIchIntelHDRegMap[HDA_NREGS] =
     570} g_aHdaRegMap[HDA_NREGS] =
    561571{
    562572    /* offset  size     read mask   write mask         read callback         write callback         abbrev      full name                     */
     
    579589    { 0x00044, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32          , hdaRegWriteBase         , "CORBUBASE" , "CORB Upper Base Address" },
    580590    { 0x00048, 0x00002, 0x000000FF, 0x000000FF, hdaRegReadU16          , hdaRegWriteCORBWP       , "CORBWP"    , "CORB Write Pointer" },
     591#ifdef OLD_REGISTER_TABLE
    581592    { 0x0004A, 0x00002, 0x000000FF, 0x000080FF, hdaRegReadU8           , hdaRegWriteCORBRP       , "CORBRP"    , "CORB Read Pointer" },
     593#else /** @todo 18.2.17 indicates that the 15th bit can be read as well as and written. hdaRegReadU8 is wrong, a special reader should be used. */
     594    { 0x0004A, 0x00002, 0x000080FF, 0x000080FF, hdaRegReadU16          , hdaRegWriteCORBRP       , "CORBRP"    , "CORB Read Pointer" },
     595#endif
    582596    { 0x0004C, 0x00001, 0x00000003, 0x00000003, hdaRegReadU8           , hdaRegWriteCORBCTL      , "CORBCTL"   , "CORB Control" },
    583597    { 0x0004D, 0x00001, 0x00000001, 0x00000001, hdaRegReadU8           , hdaRegWriteCORBSTS      , "CORBSTS"   , "CORB Status" },
     
    592606    { 0x00060, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32          , hdaRegWriteU32          , "IC"        , "Immediate Command" },
    593607    { 0x00064, 0x00004, 0x00000000, 0xFFFFFFFF, hdaRegReadU32          , hdaRegWriteUnimplemented, "IR"        , "Immediate Response" },
     608#ifdef OLD_REGISTER_TABLE
    594609    { 0x00068, 0x00004, 0x00000002, 0x00000002, hdaRegReadIRS          , hdaRegWriteIRS          , "IRS"       , "Immediate Command Status" },
     610#else /* 18.2.30 as well as the table says 16-bit. Linux accesses it as a 16-bit register. */
     611    { 0x00068, 0x00002, 0x00000002, 0x00000002, hdaRegReadIRS          , hdaRegWriteIRS          , "IRS"       , "Immediate Command Status" },
     612#endif
    595613    { 0x00070, 0x00004, 0xFFFFFFFF, 0xFFFFFF81, hdaRegReadU32          , hdaRegWriteBase         , "DPLBASE"   , "DMA Position Lower Base" },
    596614    { 0x00074, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32          , hdaRegWriteBase         , "DPUBASE"   , "DMA Position Upper Base" },
     
    685703};
    686704
     705/**
     706 * HDA register aliases (HDA spec 3.3.45).
     707 * @remarks Sorted by offReg.
     708 */
     709static const struct
     710{
     711    /** The alias register offset. */
     712    uint32_t    offReg;
     713    /** The register index. */
     714    int         idxAlias;
     715} g_aHdaRegAliases[] =
     716{
     717    { 0x2084, HDA_REG_IND_NAME(SD0LPIB) },
     718    { 0x20a4, HDA_REG_IND_NAME(SD1LPIB) },
     719    { 0x20c4, HDA_REG_IND_NAME(SD2LPIB) },
     720    { 0x20e4, HDA_REG_IND_NAME(SD3LPIB) },
     721    { 0x2104, HDA_REG_IND_NAME(SD4LPIB) },
     722    { 0x2124, HDA_REG_IND_NAME(SD5LPIB) },
     723    { 0x2144, HDA_REG_IND_NAME(SD6LPIB) },
     724    { 0x2164, HDA_REG_IND_NAME(SD7LPIB) },
     725};
     726
     727
    687728/** HDABDLEDESC field descriptors the v3+ saved state. */
    688729static SSMFIELD const g_aHdaBDLEDescFields[] =
     
    714755};
    715756
     757/**
     758 * 32-bit size indexed masks, i.e. g_afMasks[2 bytes] = 0xffff.
     759 */
     760static uint32_t const   g_afMasks[5] =
     761{
     762    UINT32_C(0), UINT32_C(0x000000ff), UINT32_C(0x0000ffff), UINT32_C(0xffffff00), UINT32_C(0xffffffff)
     763};
     764
    716765
    717766DECLINLINE(void) hdaUpdatePosBuf(PHDASTATE pThis, PHDASTREAMTRANSFERDESC pStreamDesc)
     
    761810}
    762811
    763 static int hdaMMIORegLookup(PHDASTATE pThis, uint32_t offReg)
     812/**
     813 * Looks up a register at the exact offset given by @a offReg.
     814 *
     815 * @returns Register index on success, -1 if not found.
     816 * @param   pThis               The HDA device state.
     817 * @param   offReg              The register offset.
     818 */
     819static int hdaRegLookup(PHDASTATE pThis, uint32_t offReg)
    764820{
    765821    /*
    766      * Aliases HDA spec 3.3.45
    767      */
    768     switch (offReg)
    769     {
    770         case 0x2084:
    771             return HDA_REG_IND_NAME(SD0LPIB);
    772         case 0x20A4:
    773             return HDA_REG_IND_NAME(SD1LPIB);
    774         case 0x20C4:
    775             return HDA_REG_IND_NAME(SD2LPIB);
    776         case 0x20E4:
    777             return HDA_REG_IND_NAME(SD3LPIB);
    778         case 0x2104:
    779             return HDA_REG_IND_NAME(SD4LPIB);
    780         case 0x2124:
    781             return HDA_REG_IND_NAME(SD5LPIB);
    782         case 0x2144:
    783             return HDA_REG_IND_NAME(SD6LPIB);
    784         case 0x2164:
    785             return HDA_REG_IND_NAME(SD7LPIB);
     822     * Aliases.
     823     */
     824    if (offReg >= g_aHdaRegAliases[0].offReg)
     825    {
     826        for (unsigned i = 0; i < RT_ELEMENTS(g_aHdaRegAliases); i++)
     827            if (offReg == g_aHdaRegAliases[i].offReg)
     828                return g_aHdaRegAliases[i].idxAlias;
     829        Assert(g_aHdaRegMap[RT_ELEMENTS(g_aHdaRegMap) - 1].offset < offReg);
     830        return -1;
    786831    }
    787832
     
    789834     * Binary search the
    790835     */
    791     int idxHigh = RT_ELEMENTS(g_aIchIntelHDRegMap);
     836    int idxEnd  = RT_ELEMENTS(g_aHdaRegMap);
    792837    int idxLow  = 0;
    793838    for (;;)
    794839    {
    795 #ifdef DEBUG_vvl
    796         Assert(   idxHigh >= 0
    797                && idxLow  >= 0);
     840        int idxMiddle = idxLow + (idxEnd - idxLow) / 2;
     841        if (offReg < g_aHdaRegMap[idxMiddle].offset)
     842        {
     843            if (idxLow == idxMiddle)
     844                break;
     845            idxEnd = idxMiddle;
     846        }
     847        else if (offReg > g_aHdaRegMap[idxMiddle].offset)
     848        {
     849            idxLow = idxMiddle + 1;
     850            if (idxLow >= idxEnd)
     851                break;
     852        }
     853        else
     854            return idxMiddle;
     855    }
     856
     857#ifdef RT_STRICT
     858    for (unsigned i = 0; i < RT_ELEMENTS(g_aHdaRegMap); i++)
     859        Assert(g_aHdaRegMap[i].offset != offReg);
    798860#endif
    799         if (   idxHigh < idxLow
    800             || idxHigh < 0)
    801             break;
    802         int idxMiddle = idxLow + (idxHigh - idxLow) / 2;
    803         if (offReg < g_aIchIntelHDRegMap[idxMiddle].offset)
    804             idxHigh = idxMiddle - 1;
    805         else if (offReg >= g_aIchIntelHDRegMap[idxMiddle].offset + g_aIchIntelHDRegMap[idxMiddle].size)
    806             idxLow  = idxMiddle + 1;
    807         else if (   offReg >= g_aIchIntelHDRegMap[idxMiddle].offset
    808                  && offReg <  g_aIchIntelHDRegMap[idxMiddle].offset + g_aIchIntelHDRegMap[idxMiddle].size)
     861    return -1;
     862}
     863
     864/**
     865 * Looks up a register covering the offset given by @a offReg.
     866 *
     867 * @returns Register index on success, -1 if not found.
     868 * @param   pThis               The HDA device state.
     869 * @param   offReg              The register offset.
     870 */
     871static int hdaRegLookupWithin(PHDASTATE pThis, uint32_t offReg)
     872{
     873    /*
     874     * Aliases.
     875     */
     876    if (offReg >= g_aHdaRegAliases[0].offReg)
     877    {
     878        for (unsigned i = 0; i < RT_ELEMENTS(g_aHdaRegAliases); i++)
     879        {
     880            uint32_t off = offReg - g_aHdaRegAliases[i].offReg;
     881            if (off < 4 && off < g_aHdaRegMap[g_aHdaRegAliases[i].idxAlias].size)
     882                return g_aHdaRegAliases[i].idxAlias;
     883        }
     884        Assert(g_aHdaRegMap[RT_ELEMENTS(g_aHdaRegMap) - 1].offset < offReg);
     885        return -1;
     886    }
     887
     888    /*
     889     * Binary search the
     890     */
     891    int idxEnd  = RT_ELEMENTS(g_aHdaRegMap);
     892    int idxLow  = 0;
     893    for (;;)
     894    {
     895        int idxMiddle = idxLow + (idxEnd - idxLow) / 2;
     896        if (offReg < g_aHdaRegMap[idxMiddle].offset)
     897        {
     898            if (idxLow == idxMiddle)
     899                break;
     900            idxEnd = idxMiddle;
     901        }
     902        else if (offReg >= g_aHdaRegMap[idxMiddle].offset + g_aHdaRegMap[idxMiddle].size)
     903        {
     904            idxLow = idxMiddle + 1;
     905            if (idxLow >= idxEnd)
     906                break;
     907        }
     908        else
    809909            return idxMiddle;
    810910    }
     911
     912#ifdef RT_STRICT
     913    for (unsigned i = 0; i < RT_ELEMENTS(g_aHdaRegMap); i++)
     914        Assert(offReg - g_aHdaRegMap[i].offset >= g_aHdaRegMap[i].size);
     915#endif
    811916    return -1;
    812917}
     918
    813919
    814920static int hdaCmdSync(PHDASTATE pThis, bool fLocal)
     
    9781084static int hdaRegReadU8(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
    9791085{
    980     Assert(((pThis->au32Regs[iReg] & g_aIchIntelHDRegMap[iReg].readable) & 0xffffff00) == 0);
     1086    Assert(((pThis->au32Regs[iReg] & g_aHdaRegMap[iReg].readable) & 0xffffff00) == 0);
    9811087    return hdaRegReadU32(pThis, iReg, pu32Value);
    9821088}
     
    9911097static int hdaRegReadU16(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
    9921098{
    993     Assert(((pThis->au32Regs[iReg] & g_aIchIntelHDRegMap[iReg].readable) & 0xffff0000) == 0);
     1099    Assert(((pThis->au32Regs[iReg] & g_aHdaRegMap[iReg].readable) & 0xffff0000) == 0);
    9941100    return hdaRegReadU32(pThis, iReg, pu32Value);
    9951101}
     
    10041110static int hdaRegReadU24(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
    10051111{
    1006     Assert(((pThis->au32Regs[iReg] & g_aIchIntelHDRegMap[iReg].readable) & 0xff000000) == 0);
     1112    Assert(((pThis->au32Regs[iReg] & g_aHdaRegMap[iReg].readable) & 0xff000000) == 0);
    10071113    return hdaRegReadU32(pThis, iReg, pu32Value);
    10081114}
     
    10171123static int hdaRegReadU32(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
    10181124{
    1019     *pu32Value = pThis->au32Regs[iReg] & g_aIchIntelHDRegMap[iReg].readable;
     1125    *pu32Value = pThis->au32Regs[iReg] & g_aHdaRegMap[iReg].readable;
    10201126    return VINF_SUCCESS;
    10211127}
     
    10231129static int hdaRegWriteU32(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
    10241130{
    1025     pThis->au32Regs[iReg]  = (u32Value & g_aIchIntelHDRegMap[iReg].writable)
    1026                            | (pThis->au32Regs[iReg] & ~g_aIchIntelHDRegMap[iReg].writable);
     1131    pThis->au32Regs[iReg]  = (u32Value & g_aHdaRegMap[iReg].writable)
     1132                           | (pThis->au32Regs[iReg] & ~g_aHdaRegMap[iReg].writable);
    10271133    return VINF_SUCCESS;
    10281134}
     
    11151221    if (u32Value & HDA_REG_FIELD_FLAG_MASK(CORBRP, RST))
    11161222        CORBRP(pThis) = 0;
     1223#ifndef BIRD_THINKS_CORBRP_IS_MOSTLY_RO
    11171224    else
    11181225        return hdaRegWriteU8(pThis, iReg, u32Value);
     1226#endif
    11191227    return VINF_SUCCESS;
    11201228}
     
    19262034{
    19272035    PHDASTATE   pThis  = PDMINS_2_DATA(pDevIns, PHDASTATE);
    1928     uint32_t    offReg = GCPhysAddr - pThis->MMIOBaseAddr;
    1929     int         idxReg = hdaMMIORegLookup(pThis, offReg);
    19302036    int         rc;
    1931     Assert(!(offReg & 3)); Assert(cb == 4);
     2037
     2038    /*
     2039     * Look up and log.
     2040     */
     2041    uint32_t        offReg = GCPhysAddr - pThis->MMIOBaseAddr;
     2042    int             idxReg = hdaRegLookup(pThis, offReg);
     2043#ifdef LOG_ENABLED
     2044    unsigned const  cbLog     = cb;
     2045    uint32_t        offRegLog = offReg;
     2046#endif
     2047
     2048    Log(("hdaMMIORead: offReg=%#x cb=%#x\n", offReg, cb));
     2049#define NEW_READ_CODE
     2050#ifdef NEW_READ_CODE
     2051    Assert(cb == 4); Assert((offReg & 3) == 0);
    19322052
    19332053    if (pThis->fInReset && idxReg != ICH6_HDA_REG_GCTL)
     
    19392059    if (idxReg != -1)
    19402060    {
    1941         rc = g_aIchIntelHDRegMap[idxReg].pfnRead(pThis, idxReg, (uint32_t *)pv);
    1942         Log(("hda: read %s[%x/%x]\n", g_aIchIntelHDRegMap[idxReg].abbrev, *(uint32_t *)pv));
     2061        /* ASSUMES gapless DWORD at end of map. */
     2062        if (g_aHdaRegMap[idxReg].size == 4)
     2063        {
     2064            /*
     2065             * Straight forward DWORD access.
     2066             */
     2067            rc = g_aHdaRegMap[idxReg].pfnRead(pThis, idxReg, (uint32_t *)pv);
     2068            Log(("hda: read %s => %x (%Rrc)\n", g_aHdaRegMap[idxReg].abbrev, *(uint32_t *)pv, rc));
     2069        }
     2070        else
     2071        {
     2072            /*
     2073             * Multi register read (unless there are trailing gaps).
     2074             * ASSUMES that only DWORD reads have sideeffects.
     2075             */
     2076            uint32_t u32Value = 0;
     2077            unsigned cbLeft   = 4;
     2078            do
     2079            {
     2080                uint32_t const  cbReg        = g_aHdaRegMap[idxReg].size;
     2081                uint32_t        u32Tmp       = 0;
     2082
     2083                rc = g_aHdaRegMap[idxReg].pfnRead(pThis, idxReg, &u32Tmp);
     2084                Log(("hda: read %s[%db] => %x (%Rrc)*\n", g_aHdaRegMap[idxReg].abbrev, cbReg, *(uint32_t *)pv, rc));
     2085                if (rc != VINF_SUCCESS)
     2086                    break;
     2087                u32Value |= (u32Tmp & g_afMasks[cbReg]) << ((4 - cbLeft) * 8);
     2088
     2089                cbLeft -= cbReg;
     2090                offReg += cbReg;
     2091                idxReg++;
     2092            } while (cbLeft > 0 && g_aHdaRegMap[idxReg].offset == offReg);
     2093
     2094            if (rc == VINF_SUCCESS)
     2095                *(uint32_t *)pv = u32Value;
     2096            else
     2097                Assert(!IOM_SUCCESS(rc));
     2098        }
    19432099    }
    19442100    else
     
    19472103        Log(("hda: hole at %x is accessed for read\n", offReg));
    19482104    }
     2105#else
     2106    if (idxReg != -1)
     2107    {
     2108        /** @todo r=bird: Accesses crossing register boundraries aren't handled
     2109         *        right from what I can tell?  If they are, please explain
     2110         *        what the rules are. */
     2111        uint32_t mask = 0;
     2112        uint32_t shift = (g_aHdaRegMap[idxReg].offset - offReg) % sizeof(uint32_t) * 8;
     2113        uint32_t u32Value = 0;
     2114        switch(cb)
     2115        {
     2116            case 1: mask = 0x000000ff; break;
     2117            case 2: mask = 0x0000ffff; break;
     2118            case 4:
     2119            /* 18.2 of the ICH6 datasheet defines the valid access widths as byte, word, and double word */
     2120            case 8:
     2121                mask = 0xffffffff;
     2122                cb = 4;
     2123                break;
     2124        }
     2125#if 0
     2126        /* Cross-register access. Mac guest hits this assert doing assumption 4 byte access to 3 byte registers e.g. {I,O}SDnCTL
     2127         */
     2128        //Assert((cb <= g_aHdaRegMap[idxReg].size - (offReg - g_aHdaRegMap[idxReg].offset)));
     2129        if (cb > g_aHdaRegMap[idxReg].size - (offReg - g_aHdaRegMap[idxReg].offset))
     2130        {
     2131            int off = cb - (g_aHdaRegMap[idxReg].size - (offReg - g_aHdaRegMap[idxReg].offset));
     2132            rc = hdaMMIORead(pDevIns, pvUser, GCPhysAddr + cb - off, (char *)pv + cb - off, off);
     2133            if (RT_FAILURE(rc))
     2134                AssertRCReturn (rc, rc);
     2135        }
     2136        //Assert(((offReg - g_aHdaRegMap[idxReg].offset) == 0));
     2137#endif
     2138        mask <<= shift;
     2139        rc = g_aHdaRegMap[idxReg].pfnRead(pThis, idxReg, &u32Value);
     2140        *(uint32_t *)pv |= (u32Value & mask);
     2141        Log(("hda: read %s[%x/%x]\n", g_aHdaRegMap[idxReg].abbrev, u32Value, *(uint32_t *)pv));
     2142    }
     2143    else
     2144    {
     2145        *(uint32_t *)pv = 0xFF;
     2146        Log(("hda: hole at %x is accessed for read\n", offReg));
     2147        rc = VINF_SUCCESS;
     2148    }
     2149#endif
     2150
     2151    /*
     2152     * Log the outcome.
     2153     */
     2154    if (cbLog == 4)
     2155        Log(("hdaMMIORead: @%#05x -> %#010x %Rrc\n", offRegLog, *(uint32_t *)pv, rc));
     2156    else if (cbLog == 2)
     2157        Log(("hdaMMIORead: @%#05x -> %#06x %Rrc\n", offRegLog, *(uint16_t *)pv, rc));
     2158    else if (cbLog == 1)
     2159        Log(("hdaMMIORead: @%#05x -> %#04x %Rrc\n", offRegLog, *(uint8_t *)pv, rc));
     2160    return rc;
     2161}
     2162
     2163
     2164DECLINLINE(int) hdaWriteReg(PHDASTATE pThis, int idxReg, uint32_t u32Value, char const *pszLog)
     2165{
     2166    if (pThis->fInReset && idxReg != ICH6_HDA_REG_GCTL)
     2167        Log(("hda: access to registers except GCTL is blocked while reset\n"));  /** @todo where is this enforced? */
     2168
     2169#ifdef LOG_ENABLED
     2170    uint32_t const u32CurValue = pThis->au32Regs[idxReg];
     2171#endif
     2172    int rc = g_aHdaRegMap[idxReg].pfnWrite(pThis, idxReg, u32Value);
     2173    Log(("hda: write %#x -> %s[%db]; %x => %x%s\n", u32Value, g_aHdaRegMap[idxReg].abbrev,
     2174         g_aHdaRegMap[idxReg].size, u32CurValue, pThis->au32Regs[idxReg], pszLog));
    19492175    return rc;
    19502176}
     
    19562182PDMBOTHCBDECL(int) hdaMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb)
    19572183{
    1958     PHDASTATE   pThis  = PDMINS_2_DATA(pDevIns, PHDASTATE);
     2184    PHDASTATE               pThis  = PDMINS_2_DATA(pDevIns, PHDASTATE);
     2185    int                     rc;
     2186
     2187    /*
     2188     * The behavior of accesses that aren't aligned on natural boundraries is
     2189     * undefined. Just reject them out right.
     2190     */
     2191    /** @todo IOM could check this, it could also split the 8 byte accesses for us. */
     2192    Assert(cb == 1 || cb == 2 || cb == 4 || cb == 8);
     2193    if (GCPhysAddr & (cb - 1))
     2194        return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "misaligned write access: GCPhysAddr=%RGp cb=%u\n", GCPhysAddr, cb);
     2195
     2196    /*
     2197     * Lookup and log the access.
     2198     */
    19592199    uint32_t    offReg = GCPhysAddr - pThis->MMIOBaseAddr;
    1960     int         idxReg = hdaMMIORegLookup(pThis, offReg);
    1961     int         rc;
    1962     Assert(!(offReg & 3)); Assert(cb == 4);
    1963 
    1964     if (pThis->fInReset && idxReg != ICH6_HDA_REG_GCTL)
    1965         Log(("hda: access to registers except GCTL is blocked while reset\n"));
    1966 
     2200    int         idxReg = hdaRegLookup(pThis, offReg);
     2201    uint64_t    u64Value;
     2202    if (cb == 4)        u64Value = *(uint32_t const *)pv;
     2203    else if (cb == 2)   u64Value = *(uint16_t const *)pv;
     2204    else if (cb == 1)   u64Value = *(uint8_t const *)pv;
     2205    else if (cb == 8)   u64Value = *(uint64_t const *)pv;
     2206    else
     2207        AssertReleaseMsgFailed(("%d\n", cb));
     2208
     2209#ifdef LOG_ENABLED
     2210    uint32_t const u32LogOldValue = idxReg != -1 ? pThis->au32Regs[idxReg] : UINT32_MAX;
     2211    uint32_t const offRegLog = offReg;
     2212    int      const idxRegLog = idxReg;
     2213    if (idxReg == -1)
     2214        Log(("hdaMMIOWrite: @%#05x u32=%#010x cb=%d\n", offReg, *(uint32_t const *)pv, cb));
     2215    else if (cb == 4)
     2216        Log(("hdaMMIOWrite: @%#05x u32=%#010x %s\n", offReg, *(uint32_t *)pv, g_aHdaRegMap[idxReg].abbrev));
     2217    else if (cb == 2)
     2218        Log(("hdaMMIOWrite: @%#05x u16=%#06x (%#010x) %s\n", offReg, *(uint16_t *)pv, *(uint32_t *)pv, g_aHdaRegMap[idxReg].abbrev));
     2219    else if (cb == 1)
     2220        Log(("hdaMMIOWrite: @%#05x u8=%#04x (%#010x) %s\n", offReg, *(uint8_t *)pv, *(uint32_t *)pv, g_aHdaRegMap[idxReg].abbrev));
     2221    if (idxReg != -1 && g_aHdaRegMap[idxReg].size != cb)
     2222        Log(("hdaMMIOWrite: size=%d != cb=%d!!\n", g_aHdaRegMap[idxReg].size, cb));
     2223#endif
     2224
     2225#define NEW_WRITE_CODE
     2226#ifdef NEW_WRITE_CODE
     2227    /*
     2228     * Try for a direct hit first.
     2229     */
     2230    if (idxReg != -1 && g_aHdaRegMap[idxReg].size == cb)
     2231        rc = hdaWriteReg(pThis, idxReg, u64Value, "");
     2232    /*
     2233     * Partial or multiple register access, loop thru the requested memory.
     2234     */
     2235    else
     2236    {
     2237        /* If it's an access beyond the start of the register, shift the input
     2238           value and fill in missing bits. Natural alignment rules means we
     2239           will only see 1 or 2 byte accesses of this kind, so no risk of
     2240           shifting out input values. */
     2241        if (idxReg == -1 && (idxReg = hdaRegLookupWithin(pThis, offReg)) != -1)
     2242        {
     2243            uint32_t const cbBefore = g_aHdaRegMap[idxReg].offset - offReg; Assert(cbBefore > 0 && cbBefore < 4);
     2244            offReg    -= cbBefore;
     2245            u64Value <<= cbBefore * 8;
     2246            u64Value  |= pThis->au32Regs[idxReg] & g_afMasks[cbBefore];
     2247            Log(("hdaMMIOWrite: Within register, supplied %u leading bits: %#llx -> %#llx ...\n",
     2248                 cbBefore * 8, ~g_afMasks[cbBefore] & u64Value, u64Value));
     2249        }
     2250
     2251        /* Loop thru the write area, it may covert multiple registers. */
     2252        rc = VINF_SUCCESS;
     2253        for (;;)
     2254        {
     2255            uint32_t cbReg;
     2256            if (idxReg != -1)
     2257            {
     2258                cbReg = g_aHdaRegMap[idxReg].size;
     2259                if (cb < cbReg)
     2260                {
     2261                    u64Value |= pThis->au32Regs[idxReg] & g_afMasks[cbReg] & ~g_afMasks[cb];
     2262                    Log(("hdaMMIOWrite: Supplying missing bits (%#x): %#llx -> %#llx ...\n",
     2263                         g_afMasks[cbReg] & ~g_afMasks[cb], u64Value & g_afMasks[cb], u64Value));
     2264                }
     2265                rc = hdaWriteReg(pThis, idxReg, u64Value, "*");
     2266            }
     2267            else
     2268            {
     2269                LogRel(("hda: Invalid write access @0x%x!\n", offReg));
     2270                cbReg = 1;
     2271            }
     2272            if (cbReg >= cb)
     2273                break;
     2274
     2275            /* advance */
     2276            offReg += cbReg;
     2277            cb     -= cbReg;
     2278            u64Value >>= cbReg * 8;
     2279            if (idxReg == -1)
     2280                idxReg = hdaRegLookup(pThis, offReg);
     2281            else
     2282            {
     2283                idxReg++;
     2284                if (   (unsigned)idxReg >= RT_ELEMENTS(g_aHdaRegMap)
     2285                    || g_aHdaRegMap[idxReg].offset != offReg)
     2286                    idxReg = -1;
     2287            }
     2288        }
     2289    }
     2290#else
    19672291    if (idxReg != -1)
    19682292    {
    1969 #ifdef LOG_ENABLED
    1970         uint32_t const u32CurValue = pThis->au32Regs[idxReg];
     2293        /** @todo r=bird: This looks like code for handling unaligned register
     2294         * accesses.  If it isn't, then add a comment explaining what you're
     2295         * trying to do here.  OTOH, if it is then it has the following
     2296         * issues:
     2297         *      -# You're calculating the wrong new value for the register.
     2298         *      -# You're not handling cross register accesses.  Imagine a
     2299         *       4-byte write starting at CORBCTL, or a 8-byte write.
     2300         *
     2301         * PS! consider dropping the 'offset' argument to pfnWrite/pfnRead as
     2302         * nobody seems to be using it and it just adds complexity when reading
     2303         * the code.
     2304         *
     2305         */
     2306        uint32_t u32CurValue = pThis->au32Regs[idxReg];
     2307        uint32_t u32NewValue;
     2308        uint32_t mask;
     2309        switch (cb)
     2310        {
     2311            case 1:
     2312                u32NewValue = *(uint8_t const *)pv;
     2313                mask = 0xff;
     2314                break;
     2315            case 2:
     2316                u32NewValue = *(uint16_t const *)pv;
     2317                mask = 0xffff;
     2318                break;
     2319            case 4:
     2320            case 8:
     2321                /* 18.2 of the ICH6 datasheet defines the valid access widths as byte, word, and double word */
     2322                u32NewValue = *(uint32_t const *)pv;
     2323                mask = 0xffffffff;
     2324                cb = 4;
     2325                break;
     2326            default:
     2327                AssertFailedReturn(VERR_INTERNAL_ERROR_4); /* shall not happen. */
     2328        }
     2329        /* cross-register access, see corresponding comment in hdaMMIORead */
     2330        uint32_t shift = (g_aHdaRegMap[idxReg].offset - offReg) % sizeof(uint32_t) * 8;
     2331        mask <<= shift;
     2332        u32NewValue <<= shift;
     2333        u32NewValue &= mask;
     2334        u32NewValue |= (u32CurValue & ~mask);
     2335
     2336        rc = g_aHdaRegMap[idxReg].pfnWrite(pThis, idxReg, u32NewValue);
     2337        Log(("hda: write %s:(%x) %x => %x\n", g_aHdaRegMap[idxReg].abbrev, u32NewValue,
     2338             u32CurValue, pThis->au32Regs[idxReg]));
     2339    }
     2340    else
     2341        rc = VINF_SUCCESS;
    19712342#endif
    1972         rc = g_aIchIntelHDRegMap[idxReg].pfnWrite(pThis, idxReg, *(uint32_t const *)pv);
    1973         Log(("hda: write %s:(%x) %x => %x\n", g_aIchIntelHDRegMap[idxReg].abbrev, *(uint32_t const *)pv,
    1974              u32CurValue, pThis->au32Regs[idxReg]));
    1975     }
    1976     else
    1977     {
    1978         LogRel(("hda: Invalid write access @0x%x\n", offReg));
    1979         rc = VINF_SUCCESS;
    1980     }
    1981 
    1982     Log(("hda: hole at %x is accessed for write\n", offReg));
     2343    Log(("hdaMMIOWrite: @%#05x %#x -> %#x\n", offRegLog, u32LogOldValue,
     2344         idxRegLog != -1 ? pThis->au32Regs[idxRegLog] : UINT32_MAX));
    19832345    return rc;
    19842346}
     
    19982360    int         rc;
    19992361
    2000     /* 18.2 of the ICH6 datasheet defines the valid access widths as byte, word, and double word */
     2362    /*
     2363     * 18.2 of the ICH6 datasheet defines the valid access widths as byte, word, and double word.
     2364     *
     2365     * Let IOM talk DWORDs when reading, saves a lot of complications. On
     2366     * writing though, we have to do it all ourselves because of sideeffects.
     2367     */
    20012368    Assert(enmType == PCI_ADDRESS_SPACE_MEM);
    20022369    rc = PDMDevHlpMMIORegister(pPciDev->pDevIns, GCPhysAddress, cb, NULL /*pvUser*/,
    2003                                IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_DWORD_READ_MISSING,
     2370#ifdef NEW_READ_CODE
     2371                               IOMMMIO_FLAGS_READ_DWORD |
     2372#else
     2373                               IOMMMIO_FLAGS_READ_PASSTHRU |
     2374#endif
     2375                               IOMMMIO_FLAGS_WRITE_PASSTHRU,
    20042376                               hdaMMIOWrite, hdaMMIORead, "ICH6_HDA");
    20052377
     
    22202592    int iReg = 0;
    22212593    for (; iReg < HDA_NREGS; ++iReg)
    2222         if (!RTStrICmp(g_aIchIntelHDRegMap[iReg].abbrev, pszArgs))
     2594        if (!RTStrICmp(g_aHdaRegMap[iReg].abbrev, pszArgs))
    22232595            return iReg;
    22242596    return -1;
     
    22312603           && iHdaIndex >= 0
    22322604           && iHdaIndex < HDA_NREGS);
    2233     pHlp->pfnPrintf(pHlp, "hda: %s: 0x%x\n", g_aIchIntelHDRegMap[iHdaIndex].abbrev, pThis->au32Regs[iHdaIndex]);
     2605    pHlp->pfnPrintf(pHlp, "hda: %s: 0x%x\n", g_aHdaRegMap[iHdaIndex].abbrev, pThis->au32Regs[iHdaIndex]);
    22342606}
    22352607
     
    26022974    AssertRC(rc);
    26032975#endif
     2976
     2977    /*
     2978     * Some debug assertions.
     2979     */
     2980    for (unsigned i = 0; i < RT_ELEMENTS(g_aHdaRegMap); i++)
     2981    {
     2982        struct HDAREGDESC const *pReg     = &g_aHdaRegMap[i];
     2983        struct HDAREGDESC const *pNextReg = i + 1 < RT_ELEMENTS(g_aHdaRegMap) ?  &g_aHdaRegMap[i + 1] : NULL;
     2984
     2985        /* binary search order. */
     2986        AssertReleaseMsg(!pNextReg || pReg->offset + pReg->size <= pNextReg->offset,
     2987                         ("[%#x] = {%#x LB %#x}  vs. [%#x] = {%#x LB %#x}\n",
     2988                          i, pReg->offset, pReg->size, i + 1, pNextReg->offset, pNextReg->size));
     2989
     2990        /* alignment. */
     2991        AssertReleaseMsg(   pReg->size == 1
     2992                         || (pReg->size == 2 && (pReg->offset & 1) == 0)
     2993                         || (pReg->size == 3 && (pReg->offset & 3) == 0)
     2994                         || (pReg->size == 4 && (pReg->offset & 3) == 0),
     2995                         ("[%#x] = {%#x LB %#x}\n", i, pReg->offset, pReg->size));
     2996
     2997        /* registers are packed into dwords - with 3 exceptions with gaps at the end of the dword. */
     2998        AssertRelease(((pReg->offset + pReg->size) & 3) == 0 || pNextReg);
     2999        if (pReg->offset & 3)
     3000        {
     3001            struct HDAREGDESC const *pPrevReg = i > 0 ?  &g_aHdaRegMap[i - 1] : NULL;
     3002            AssertReleaseMsg(pPrevReg, ("[%#x] = {%#x LB %#x}\n", i, pReg->offset, pReg->size));
     3003            if (pPrevReg)
     3004                AssertReleaseMsg(pPrevReg->offset + pPrevReg->size == pReg->offset,
     3005                                 ("[%#x] = {%#x LB %#x}  vs. [%#x] = {%#x LB %#x}\n",
     3006                                  i - 1, pPrevReg->offset, pPrevReg->size, i + 1, pReg->offset, pReg->size));
     3007        }
     3008#if 0
     3009        if ((pReg->offset + pReg->size) & 3)
     3010        {
     3011            AssertReleaseMsg(pNextReg, ("[%#x] = {%#x LB %#x}\n", i, pReg->offset, pReg->size));
     3012            if (pNextReg)
     3013                AssertReleaseMsg(pReg->offset + pReg->size == pNextReg->offset,
     3014                                 ("[%#x] = {%#x LB %#x}  vs. [%#x] = {%#x LB %#x}\n",
     3015                                  i, pReg->offset, pReg->size, i + 1,  pNextReg->offset, pNextReg->size));
     3016        }
     3017#endif
     3018
     3019        /* The final entry is a full dword, no gaps! Allows shortcuts. */
     3020        AssertReleaseMsg(pNextReg || ((pReg->offset + pReg->size) & 3) == 0,
     3021                         ("[%#x] = {%#x LB %#x}\n", i, pReg->offset, pReg->size));
     3022    }
    26043023
    26053024    return VINF_SUCCESS;
Note: See TracChangeset for help on using the changeset viewer.

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