VirtualBox

Changeset 88353 in vbox for trunk/src


Ignore:
Timestamp:
Apr 2, 2021 9:52:41 PM (4 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
143597
Message:

Forward ported r143589+r143590 from 6.1: DevHPET: Corrected the HPET_TN_SETVAL behavior. The default for periodic timers is to write the accumulator, setting HPET_TN_SETVAL enables writing both comparator and accumulator. Better info. Some OS specific notes. ​Doxygen fix. oem2ticketref:40

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/PC/DevHPET.cpp

    r88352 r88353  
    22/** @file
    33 * HPET virtual device - High Precision Event Timer emulation.
     4 *
     5 * This implementation is based on the (generic) Intel IA-PC HPET specification
     6 * and the Intel ICH9 datasheet.
     7 *
     8 * Typical windows 1809 usage (efi, smp) is to do repated one-shots and
     9 * a variable rate.  The reprogramming sequence is as follows (all accesses
     10 * are 32-bit):
     11 *  -# counter register read.
     12 *  -# timer 0: config register read.
     13 *  -# timer 0: write 0x134 to config register.
     14 *  -# timer 0: write comparator register.
     15 *  -# timer 0: write 0x134 to config register.
     16 *  -# timer 0: read comparator register.
     17 *  -# counter register read.
     18 *
     19 * Typical linux will configure the timer at Hz but not necessarily enable
     20 * interrupts (HPET_TN_ENABLE not set).  It would be nice to emulate this
     21 * mode without using timers.
     22 *
    423 */
    524
     
    1433 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
    1534 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
    16  */
    17 
    18 /* This implementation is based on the (generic) Intel IA-PC HPET specification
    19  * and the Intel ICH9 datasheet.
    2035 */
    2136
     
    132147#define HPET_TN_PERIODIC_CAP            RT_BIT_64(4)
    133148#define HPET_TN_SIZE_CAP                RT_BIT_64(5)
    134 #define HPET_TN_SETVAL                  RT_BIT_64(6)
     149#define HPET_TN_SETVAL                  RT_BIT_64(6)    /**< Periodic timers only: Change COMPARATOR as well as ACCUMULATOR. */
    135150#define HPET_TN_32BIT                   RT_BIT_64(8)
    136151#define HPET_TN_INT_ROUTE_MASK          UINT64_C(0x3e00)
     
    723738            {
    724739                DEVHPET_LOCK_BOTH_RETURN(pDevIns, pThis, VINF_IOM_R3_MMIO_WRITE);
    725                 Log(("HPET[%u]: write32 HPET_TN_CMP: %#x\n", iTimerNo, u32NewValue));
    726740                uint64_t fConfig = ASMAtomicUoReadU64(&pHpetTimer->u64Config);
    727 
    728 /** @todo r=bird: This is wrong.  Specification says: "By writing this bit to a 1, the software is then allowed to directly set a periodic timer’s accumulator."
    729  * See https://wiki.osdev.org/HPET and hpet_clkevt_set_state_periodic() in linux. */
     741                Log(("HPET[%u]: write32 HPET_TN_CMP: %#x (fCfg=%#RX32)\n", iTimerNo, u32NewValue, (uint32_t)fConfig));
     742
    730743                if (fConfig & HPET_TN_PERIODIC)
    731744                    ASMAtomicUoWriteU64(&pHpetTimer->u64Period, RT_MAKE_U64(u32NewValue, RT_HI_U32(pHpetTimer->u64Period)));
    732                 ASMAtomicUoWriteU64(&pHpetTimer->u64Cmp, RT_MAKE_U64(u32NewValue, RT_HI_U32(pHpetTimer->u64Cmp)));
     745
     746                if (!(fConfig & HPET_TN_PERIODIC) || (fConfig & HPET_TN_SETVAL))
     747                    ASMAtomicUoWriteU64(&pHpetTimer->u64Cmp, RT_MAKE_U64(u32NewValue, RT_HI_U32(pHpetTimer->u64Cmp)));
     748
    733749                ASMAtomicAndU64(&pHpetTimer->u64Config, ~HPET_TN_SETVAL);
    734750                Log2(("HPET[%u]: after32 HPET_TN_CMP cmp=%#llx per=%#llx\n", iTimerNo, pHpetTimer->u64Cmp, pHpetTimer->u64Period));
     
    740756            }
    741757
     758            /** @todo figure out how exactly it behaves wrt to HPET_TN_SETVAL   */
    742759            case HPET_TN_CMP + 4: /* upper bits of comparator register */
    743760            {
     
    747764                if (!hpet32bitTimerEx(fConfig))
    748765                {
    749                     Log(("HPET[%u]: write32 HPET_TN_CMP + 4: %#x\n", iTimerNo, u32NewValue));
    750 /** @todo r=bird: This is wrong.  Specification says: "By writing this bit to a 1, the software is then allowed to directly set a periodic timer’s accumulator."
    751  * See https://wiki.osdev.org/HPET and hpet_clkevt_set_state_periodic() in linux. */
     766                    Log(("HPET[%u]: write32 HPET_TN_CMP + 4: %#x (fCfg=%#RX32)\n", iTimerNo, u32NewValue, (uint32_t)fConfig));
    752767                    if (fConfig & HPET_TN_PERIODIC)
    753768                        ASMAtomicUoWriteU64(&pHpetTimer->u64Period, RT_MAKE_U64(RT_LO_U32(pHpetTimer->u64Period), u32NewValue));
    754                     ASMAtomicUoWriteU64(&pHpetTimer->u64Cmp, RT_MAKE_U64(RT_LO_U32(pHpetTimer->u64Cmp), u32NewValue));
     769
     770                    if (!(fConfig & HPET_TN_PERIODIC) || (fConfig & HPET_TN_SETVAL))
     771                        ASMAtomicUoWriteU64(&pHpetTimer->u64Cmp, RT_MAKE_U64(RT_LO_U32(pHpetTimer->u64Cmp), u32NewValue));
     772
    755773                    ASMAtomicAndU64(&pHpetTimer->u64Config, ~HPET_TN_SETVAL);
    756774                    Log2(("HPET[%u]: after32 HPET_TN_CMP+4: cmp=%#llx per=%#llx\n", iTimerNo, pHpetTimer->u64Cmp, pHpetTimer->u64Period));
     
    760778                }
    761779                else
    762                     Log(("HPET[%u]: write32 HPET_TN_CMP + 4: %#x - but timer is 32-bit!!\n", iTimerNo, u32NewValue));
     780                    Log(("HPET[%u]: write32 HPET_TN_CMP + 4: %#x - but timer is 32-bit!! (fCfg=%#RX32)\n", iTimerNo, u32NewValue, (uint32_t)fConfig));
    763781                DEVHPET_UNLOCK_BOTH(pDevIns, pThis);
    764782                break;
     
    793811 * @param   iTimerNo        The timer being written to.
    794812 * @param   iTimerReg       The register being written to.
    795  * @param   u32NewValue     The value being written.
     813 * @param   u64NewValue     The value being written.
    796814 *
    797815 * @remarks The caller should not hold any locks.
     
    818836            {
    819837                DEVHPET_LOCK_BOTH_RETURN(pDevIns, pThis, VINF_IOM_R3_MMIO_WRITE);
    820                 Log(("HPET[%u]: write64 HPET_TN_CMP: %#RX64\n", iTimerNo, u64NewValue));
    821838                uint64_t fConfig = ASMAtomicUoReadU64(&pHpetTimer->u64Config);
    822 
    823 /** @todo r=bird: This is wrong.  Specification says: "By writing this bit to a 1, the software is then allowed to directly set a periodic timer’s accumulator."
    824  * See https://wiki.osdev.org/HPET and hpet_clkevt_set_state_periodic() in linux. */
     839                Log(("HPET[%u]: write64 HPET_TN_CMP: %#RX64 (fCfg=%#RX64)\n", iTimerNo, u64NewValue, (uint32_t)fConfig));
     840
     841                /** @todo not sure if this is right, but it is consistent with the 32-bit config
     842                 *        change behaviour and defensive wrt mixups. */
     843                if (!hpet32bitTimerEx(fConfig))
     844                { /* likely */ }
     845                else
     846                    u64NewValue = (uint32_t)u64NewValue;
     847
    825848                if (fConfig & HPET_TN_PERIODIC)
    826849                    ASMAtomicUoWriteU64(&pHpetTimer->u64Period, u64NewValue);
    827                 ASMAtomicUoWriteU64(&pHpetTimer->u64Cmp, u64NewValue);
     850
     851                if (!(fConfig & HPET_TN_PERIODIC) || (fConfig & HPET_TN_SETVAL))
     852                    ASMAtomicUoWriteU64(&pHpetTimer->u64Cmp, u64NewValue);
     853
    828854                ASMAtomicAndU64(&pHpetTimer->u64Config, ~HPET_TN_SETVAL);
    829855                Log2(("HPET[%u]: after64 HPET_TN_CMP cmp=%#llx per=%#llx\n", iTimerNo, pHpetTimer->u64Cmp, pHpetTimer->u64Period));
     
    13801406    for (unsigned i = 0; i < RT_ELEMENTS(pThis->aTimers); i++)
    13811407    {
    1382         pHlp->pfnPrintf(pHlp, " %d: comparator=%016RX64 period(hidden)=%016RX64 cfg=%016RX64\n",
     1408        static const struct
     1409        {
     1410            const char *psz;
     1411            uint32_t cch;
     1412            uint32_t fFlags;
     1413        } s_aFlags[] =
     1414        {
     1415            { RT_STR_TUPLE(" lvl"),     HPET_TN_INT_TYPE },
     1416            { RT_STR_TUPLE(" en"),      HPET_TN_ENABLE },
     1417            { RT_STR_TUPLE(" per"),     HPET_TN_PERIODIC },
     1418            { RT_STR_TUPLE(" cap_per"), HPET_TN_PERIODIC_CAP },
     1419            { RT_STR_TUPLE(" cap_64"),  HPET_TN_SIZE_CAP },
     1420            { RT_STR_TUPLE(" setval"),  HPET_TN_SETVAL },
     1421            { RT_STR_TUPLE(" 32b"),     HPET_TN_32BIT },
     1422        };
     1423        char        szTmp[64];
     1424        uint64_t    fCfg = pThis->aTimers[i].u64Config;
     1425        size_t      off  = 0;
     1426        for (unsigned j = 0; j < RT_ELEMENTS(s_aFlags); j++)
     1427            if (fCfg & s_aFlags[j].fFlags)
     1428            {
     1429                memcpy(&szTmp[off], s_aFlags[j].psz, s_aFlags[j].cch);
     1430                off  += s_aFlags[j].cch;
     1431                fCfg &= ~(uint64_t)s_aFlags[j].fFlags;
     1432            }
     1433        szTmp[off] = '\0';
     1434        Assert(off < sizeof(szTmp));
     1435
     1436        pHlp->pfnPrintf(pHlp,
     1437                        " %d: comparator=%016RX64 accumulator=%016RX64 (%RU64 ns)\n"
     1438                         "        config=%016RX64 irq=%d%s\n",
    13831439                        pThis->aTimers[i].idxTimer,
    13841440                        pThis->aTimers[i].u64Cmp,
    13851441                        pThis->aTimers[i].u64Period,
    1386                         pThis->aTimers[i].u64Config);
     1442                        hpetTicksToNs(pThis, pThis->aTimers[i].u64Period),
     1443                        pThis->aTimers[i].u64Config,
     1444                        hpetR3TimerGetIrq(pThis, &pThis->aTimers[i], pThis->aTimers[i].u64Config),
     1445                        szTmp);
    13871446    }
    13881447}
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