VirtualBox

Changeset 82401 in vbox for trunk/src/VBox/Devices/Audio


Ignore:
Timestamp:
Dec 4, 2019 11:33:29 PM (5 years ago)
Author:
vboxsync
Message:

DevHDA: Handle some partial/multiple register accesses (both reads and writes) in ring-0. In the read case IOM may upon our request translate a byte or word access that exactly matches the desired register into a dword access spanning multiple registers. We can only safely handle these if we know there won't be any VINF_IOM_R3_MMIO_READ statuses showing up. Fortunately we can tell that from the pfnRead functions. In the write case, the access may be a byte write to a 16-bit, 24-bit or 32-bit register. We just supply the missing bits and do it. Mind we only support doing this if it's the first byte in the register that's being accessed, but that seems to do the trick almost all of the time. bugref:9218

Location:
trunk/src/VBox/Devices/Audio
Files:
2 edited

Legend:

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

    r82399 r82401  
    532532};
    533533
     534#endif /* IN_RING3 */
     535
    534536/**
    535537 * 32-bit size indexed masks, i.e. g_afMasks[2 bytes] = 0xffff.
     
    540542};
    541543
    542 #endif /* IN_RING3 */
    543544
    544545
     
    29812982}
    29822983
    2983 #endif /* IN_RING3 */
     2984#else   /* !IN_RING3 */
     2985
     2986/**
     2987 * Checks if a dword read starting with @a idxRegDsc is safe.
     2988 *
     2989 * We can guarentee it only standard reader callbacks are used.
     2990 * @returns true if it will always succeed, false if it may return back to
     2991 *          ring-3 or we're just not sure.
     2992 * @param   idxRegDsc       The first register descriptor in the DWORD being read.
     2993 */
     2994DECLINLINE(bool) hdaIsMultiReadSafeInRZ(unsigned idxRegDsc)
     2995{
     2996    int32_t cbLeft = 4; /* signed on purpose */
     2997    do
     2998    {
     2999        if (   g_aHdaRegMap[idxRegDsc].pfnRead == hdaRegReadU24
     3000            || g_aHdaRegMap[idxRegDsc].pfnRead == hdaRegReadU16
     3001            || g_aHdaRegMap[idxRegDsc].pfnRead == hdaRegReadU8
     3002            || g_aHdaRegMap[idxRegDsc].pfnRead == hdaRegReadUnimpl)
     3003        { /* okay */ }
     3004        else
     3005        {
     3006            Log4(("hdaIsMultiReadSafeInRZ: idxRegDsc=%u %s\n", idxRegDsc, g_aHdaRegMap[idxRegDsc].abbrev));
     3007            return false;
     3008        }
     3009
     3010        idxRegDsc++;
     3011        if (idxRegDsc < RT_ELEMENTS(g_aHdaRegMap))
     3012            cbLeft -= g_aHdaRegMap[idxRegDsc].offset - g_aHdaRegMap[idxRegDsc - 1].offset;
     3013        else
     3014            break;
     3015    } while (cbLeft > 0);
     3016    return true;
     3017}
     3018
     3019
     3020#endif /* !IN_RING3 */
     3021
    29843022
    29853023/* MMIO callbacks */
     
    30293067                STAM_COUNTER_INC(&pThis->aStatRegReads[idxRegDsc]);
    30303068            }
     3069#ifndef IN_RING3
     3070            else if (!hdaIsMultiReadSafeInRZ(idxRegDsc))
     3071
     3072            {
     3073                STAM_COUNTER_INC(&pThis->aStatRegReadsToR3[idxRegDsc]);
     3074                rc = VINF_IOM_R3_MMIO_READ;
     3075            }
     3076#endif
    30313077            else
    30323078            {
     
    30353081                 * ASSUMES that only DWORD reads have sideeffects.
    30363082                 */
    3037 #ifdef IN_RING3
    3038                 STAM_COUNTER_INC(&pThis->StatRegMultiReads);
     3083                STAM_COUNTER_INC(&pThis->CTX_SUFF_Z(StatRegMultiReads));
     3084                Log4(("hdaMmioRead: multi read: %#x LB %#x %s\n", off, cb, g_aHdaRegMap[idxRegDsc].abbrev));
    30393085                uint32_t u32Value = 0;
    30403086                unsigned cbLeft   = 4;
     
    30453091
    30463092                    rc = g_aHdaRegMap[idxRegDsc].pfnRead(pDevIns, pThis, idxRegDsc, &u32Tmp);
    3047                     Log3Func(("\tRead %s[%db] => %x (%Rrc)*\n", g_aHdaRegMap[idxRegDsc].abbrev, cbReg, u32Tmp, VBOXSTRICTRC_VAL(rc)));
     3093                    Log4Func(("\tRead %s[%db] => %x (%Rrc)*\n", g_aHdaRegMap[idxRegDsc].abbrev, cbReg, u32Tmp, VBOXSTRICTRC_VAL(rc)));
    30483094                    STAM_COUNTER_INC(&pThis->aStatRegReads[idxRegDsc]);
     3095#ifdef IN_RING3
    30493096                    if (rc != VINF_SUCCESS)
    30503097                        break;
     3098#else
     3099                    AssertMsgBreak(rc == VINF_SUCCESS, ("rc=%Rrc - impossible, we sanitized the readers!\n", VBOXSTRICTRC_VAL(rc)));
     3100#endif
    30513101                    u32Value |= (u32Tmp & g_afMasks[cbReg]) << ((4 - cbLeft) * 8);
    30523102
     
    30603110                else
    30613111                    Assert(!IOM_SUCCESS(rc));
    3062 #else  /* !IN_RING3 */
    3063                 /* Take the easy way out. */
    3064                 STAM_COUNTER_INC(&pThis->aStatRegReadsToR3[idxRegDsc]);
    3065                 rc = VINF_IOM_R3_MMIO_READ;
    3066 #endif /* !IN_RING3 */
    30673112            }
    30683113        }
     
    31973242#ifdef LOG_ENABLED
    31983243    uint32_t const u32LogOldValue = idxRegDsc >= 0 ? pThis->au32Regs[idxRegMem] : UINT32_MAX;
    3199     if (idxRegDsc == -1)
    3200         Log3Func(("@%#05x u32=%#010x cb=%d\n", (uint32_t)off, *(uint32_t const *)pv, cb));
    3201     else
    3202         Log3Func(("@%#05x u%u=%#0*RX64 %s\n", (uint32_t)off, cb * 8, 2 + cb * 2, u64Value, g_aHdaRegMap[idxRegDsc].abbrev));
    32033244#endif
    32043245
     
    32093250    if (idxRegDsc >= 0 && g_aHdaRegMap[idxRegDsc].size == cb)
    32103251    {
     3252        Log3Func(("@%#05x u%u=%#0*RX64 %s\n", (uint32_t)off, cb * 8, 2 + cb * 2, u64Value, g_aHdaRegMap[idxRegDsc].abbrev));
    32113253        rc = hdaWriteReg(pDevIns, pThis, idxRegDsc, u64Value, "");
    32123254        Log3Func(("\t%#x -> %#x\n", u32LogOldValue, idxRegMem != UINT32_MAX ? pThis->au32Regs[idxRegMem] : UINT32_MAX));
     3255    }
     3256    /*
     3257     * Sub-register access.  Supply missing bits as needed.
     3258     */
     3259    else if (   idxRegDsc >= 0
     3260             && cb < g_aHdaRegMap[idxRegDsc].size)
     3261    {
     3262        u64Value |=   pThis->au32Regs[g_aHdaRegMap[idxRegDsc].mem_idx]
     3263                    & g_afMasks[g_aHdaRegMap[idxRegDsc].size]
     3264                    & ~g_afMasks[cb];
     3265        Log4Func(("@%#05x u%u=%#0*RX64 cb=%#x cbReg=%x %s\n"
     3266                  "\tSupplying missing bits (%#x): %#llx -> %#llx ...\n",
     3267                  (uint32_t)off, cb * 8, 2 + cb * 2, u64Value, cb, g_aHdaRegMap[idxRegDsc].size, g_aHdaRegMap[idxRegDsc].abbrev,
     3268                  g_afMasks[g_aHdaRegMap[idxRegDsc].size] & ~g_afMasks[cb], u64Value & g_afMasks[cb], u64Value));
     3269        rc = hdaWriteReg(pDevIns, pThis, idxRegDsc, u64Value, "");
     3270        Log4Func(("\t%#x -> %#x\n", u32LogOldValue, idxRegMem != UINT32_MAX ? pThis->au32Regs[idxRegMem] : UINT32_MAX));
     3271        STAM_COUNTER_INC(&pThis->CTX_SUFF_Z(StatRegSubWrite));
    32133272    }
    32143273    /*
     
    32183277    {
    32193278#ifdef IN_RING3
    3220         if (idxRegDsc >= 0 && g_aHdaRegMap[idxRegDsc].size != cb)
    3221             Log3Func(("\tSize mismatch: %RU32 (reg) vs %u (access)!!\n", g_aHdaRegMap[idxRegDsc].size, cb));
     3279        if (idxRegDsc == -1)
     3280            Log4Func(("@%#05x u32=%#010x cb=%d\n", (uint32_t)off, *(uint32_t const *)pv, cb));
     3281        else if (g_aHdaRegMap[idxRegDsc].size == cb)
     3282            Log4Func(("@%#05x u%u=%#0*RX64 %s\n", (uint32_t)off, cb * 8, 2 + cb * 2, u64Value, g_aHdaRegMap[idxRegDsc].abbrev));
     3283        else
     3284            Log4Func(("@%#05x u%u=%#0*RX64 %s - mismatch cbReg=%u\n", (uint32_t)off, cb * 8, 2 + cb * 2, u64Value,
     3285                      g_aHdaRegMap[idxRegDsc].abbrev, g_aHdaRegMap[idxRegDsc].size));
    32223286
    32233287        /*
     
    32383302                u64Value <<= cbBefore * 8;
    32393303                u64Value  |= pThis->au32Regs[idxRegMem] & g_afMasks[cbBefore];
    3240                 Log3Func(("\tWithin register, supplied %u leading bits: %#llx -> %#llx ...\n",
     3304                Log4Func(("\tWithin register, supplied %u leading bits: %#llx -> %#llx ...\n",
    32413305                          cbBefore * 8, ~g_afMasks[cbBefore] & u64Value, u64Value));
    3242                 STAM_COUNTER_INC(&pThis->StatRegMultiWrites);
     3306                STAM_COUNTER_INC(&pThis->CTX_SUFF_Z(StatRegMultiWrites));
    32433307            }
    32443308            else
     
    32463310        }
    32473311        else
    3248             STAM_COUNTER_INC(&pThis->StatRegMultiWrites);
    3249 
     3312        {
     3313            Log4(("hdaMmioWrite: multi write: %s\n", g_aHdaRegMap[idxRegDsc].abbrev));
     3314            STAM_COUNTER_INC(&pThis->CTX_SUFF_Z(StatRegMultiWrites));
     3315        }
    32503316
    32513317        /* Loop thru the write area, it may cover multiple registers. */
     
    32613327                {
    32623328                    u64Value |= pThis->au32Regs[idxRegMem] & g_afMasks[cbReg] & ~g_afMasks[cb];
    3263                     Log3Func(("\tSupplying missing bits (%#x): %#llx -> %#llx ...\n",
     3329                    Log4Func(("\tSupplying missing bits (%#x): %#llx -> %#llx ...\n",
    32643330                              g_afMasks[cbReg] & ~g_afMasks[cb], u64Value & g_afMasks[cb], u64Value));
    32653331                }
     
    32683334# endif
    32693335                rc = hdaWriteReg(pDevIns, pThis, idxRegDsc, u64Value, "*");
    3270                 Log3Func(("\t%#x -> %#x\n", uLogOldVal, pThis->au32Regs[idxRegMem]));
     3336                Log4Func(("\t%#x -> %#x\n", uLogOldVal, pThis->au32Regs[idxRegMem]));
    32713337            }
    32723338            else
     
    47174783    AssertRCReturn(rc, rc);
    47184784
     4785    /** @todo r=bird: The IOMMMIO_FLAGS_READ_DWORD flag isn't entirely optimal,
     4786     * as several frequently used registers aren't dword sized.  6.0 and earlier
     4787     * will go to ring-3 to handle accesses to any such register, where-as 6.1 and
     4788     * later will do trivial register reads in ring-0.   Real optimal code would use
     4789     * IOMMMIO_FLAGS_READ_PASSTHRU and do the necessary extra work to deal with
     4790     * anything the guest may throw at us. */
    47194791    rc = PDMDevHlpPCIIORegionCreateMmio(pDevIns, 0, 0x4000, PCI_ADDRESS_SPACE_MEM, hdaMmioWrite, hdaMmioRead, NULL /*pvUser*/,
    47204792                                        IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_PASSTHRU, "HDA", &pThis->hMmio);
     
    50775149                               g_aHdaRegMap[i].desc, "Regs/%03x-%s-Writes-ToR3", g_aHdaRegMap[i].offset, g_aHdaRegMap[i].abbrev);
    50785150    }
    5079     PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegMultiReads,     STAMTYPE_COUNTER, "RegMultiReads",      STAMUNIT_OCCURENCES, "Register read not targeting just one register");
    5080     PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegMultiWrites,    STAMTYPE_COUNTER, "RegMultiWrites",     STAMUNIT_OCCURENCES, "Register writes not targeting just one register");
     5151    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegMultiReadsR3,   STAMTYPE_COUNTER, "RegMultiReadsR3",    STAMUNIT_OCCURENCES, "Register read not targeting just one register, handled in ring-3");
     5152    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegMultiReadsRZ,   STAMTYPE_COUNTER, "RegMultiReadsRZ",    STAMUNIT_OCCURENCES, "Register read not targeting just one register, handled in ring-0");
     5153    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegMultiWritesR3,  STAMTYPE_COUNTER, "RegMultiWritesR3",   STAMUNIT_OCCURENCES, "Register writes not targeting just one register, handled in ring-3");
     5154    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegMultiWritesRZ,  STAMTYPE_COUNTER, "RegMultiWritesRZ",   STAMUNIT_OCCURENCES, "Register writes not targeting just one register, handled in ring-0");
     5155    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegSubWriteR3,     STAMTYPE_COUNTER, "RegSubWritesR3",     STAMUNIT_OCCURENCES, "Trucated register writes, handled in ring-3");
     5156    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegSubWriteRZ,     STAMTYPE_COUNTER, "RegSubWritesRZ",     STAMUNIT_OCCURENCES, "Trucated register writes, handled in ring-0");
    50815157    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegUnknownReads,   STAMTYPE_COUNTER, "RegUnknownReads",    STAMUNIT_OCCURENCES, "Reads of unknown registers.");
    50825158    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegUnknownWrites,  STAMTYPE_COUNTER, "RegUnknownWrites",   STAMUNIT_OCCURENCES, "Writes to unknown registers.");
  • trunk/src/VBox/Devices/Audio/DevHDA.h

    r82399 r82401  
    209209    STAMCOUNTER             aStatRegWrites[HDA_NUM_REGS];
    210210    STAMCOUNTER             aStatRegWritesToR3[HDA_NUM_REGS];
    211     STAMCOUNTER             StatRegMultiReads;
    212     STAMCOUNTER             StatRegMultiWrites;
     211    STAMCOUNTER             StatRegMultiReadsRZ;
     212    STAMCOUNTER             StatRegMultiReadsR3;
     213    STAMCOUNTER             StatRegMultiWritesRZ;
     214    STAMCOUNTER             StatRegMultiWritesR3;
     215    STAMCOUNTER             StatRegSubWriteRZ;
     216    STAMCOUNTER             StatRegSubWriteR3;
    213217    STAMCOUNTER             StatRegUnknownReads;
    214218    STAMCOUNTER             StatRegUnknownWrites;
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