VirtualBox

Changeset 36971 in vbox


Ignore:
Timestamp:
May 5, 2011 12:11:42 PM (14 years ago)
Author:
vboxsync
Message:

HPET: cleanup, correct timers init per ICH9 spec, fix overflow hanling

File:
1 edited

Legend:

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

    r36870 r36971  
    9595#define HPET_CFG_WRITE_MASK      0x3
    9696
    97 #define HPET_TN_INT_TYPE                      (1 << 1)
    98 #define HPET_TN_ENABLE                        (1 << 2)
    99 #define HPET_TN_PERIODIC                      (1 << 3)
    100 #define HPET_TN_PERIODIC_CAP                  (1 << 4)
    101 #define HPET_TN_SIZE_CAP                      (1 << 5)
    102 #define HPET_TN_SETVAL                        (1 << 6)
    103 #define HPET_TN_32BIT                         (1 << 8)
    104 #define HPET_TN_INT_ROUTE_MASK                0x3e00
    105 #define HPET_TN_CFG_WRITE_MASK                0x3f4e
     97#define HPET_TN_INT_TYPE                      RT_BIT_64(1)
     98#define HPET_TN_ENABLE                        RT_BIT_64(2)
     99#define HPET_TN_PERIODIC                      RT_BIT_64(3)
     100#define HPET_TN_PERIODIC_CAP                  RT_BIT_64(4)
     101#define HPET_TN_SIZE_CAP                      RT_BIT_64(5)
     102#define HPET_TN_SETVAL                        RT_BIT_64(6)
     103#define HPET_TN_32BIT                         RT_BIT_64(8)
     104#define HPET_TN_INT_ROUTE_MASK                UINT64_C(0x3e00)
     105#define HPET_TN_CFG_WRITE_MASK                UINT64_C(0x3e46)
    106106#define HPET_TN_INT_ROUTE_SHIFT               9
    107107#define HPET_TN_INT_ROUTE_CAP_SHIFT           32
     
    191191    PDMCRITSECT          csLock;
    192192
    193     /* If we emulate ICH9 HPET (different frequency and counter rollover behavior
    194        in 32-bit mode). */
     193    /* If we emulate ICH9 HPET (different frequency). */
    195194    uint8_t              fIch9;
    196195    uint8_t              padding0[7];
     
    233232}
    234233
    235 static uint32_t hpetTimeAfter32(uint64_t a, uint64_t b)
     234DECLINLINE(bool) hpet32bitTimer(HpetTimer *pTimer)
     235{
     236    uint64_t u64Cfg = pTimer->u64Config;
     237
     238    return ((u64Cfg & HPET_TN_SIZE_CAP) == 0) || ((u64Cfg & HPET_TN_32BIT) != 0);
     239}
     240
     241DECLINLINE(uint64_t) hpetInvalidValue(HpetTimer *pTimer)
     242{
     243    return hpet32bitTimer(pTimer) ? ~0U : ~0ULL;
     244}
     245
     246DECLINLINE(uint32_t) hpetTimeAfter32(uint64_t a, uint64_t b)
    236247{
    237248    return ((int32_t)(b) - (int32_t)(a) <= 0);
    238249}
    239250
    240 static uint32_t hpetTimeAfter64(uint64_t a, uint64_t b)
     251DECLINLINE(uint32_t) hpetTimeAfter64(uint64_t a, uint64_t b)
    241252{
    242253    return ((int64_t)(b) - (int64_t)(a) <= 0);
    243254}
    244255
    245 static uint64_t hpetTicksToNs(HpetState* pThis, uint64_t value)
     256DECLINLINE(uint64_t) hpetTicksToNs(HpetState* pThis, uint64_t value)
    246257{
    247258    return (ASMMultU64ByU32DivByU32(value,  (uint32_t)(pThis->u64Capabilities >> 32), FS_PER_NS));
    248259}
    249260
    250 static uint64_t nsToHpetTicks(HpetState* pThis, uint64_t u64Value)
     261DECLINLINE(uint64_t) nsToHpetTicks(HpetState* pThis, uint64_t u64Value)
    251262{
    252263    return (ASMMultU64ByU32DivByU32(u64Value, FS_PER_NS, (uint32_t)(pThis->u64Capabilities >> 32)));
    253264}
    254265
    255 static uint64_t hpetGetTicks(HpetState* pThis)
     266DECLINLINE(uint64_t) hpetGetTicks(HpetState* pThis)
    256267{
    257268    /*
     
    263274}
    264275
    265 static uint64_t hpetUpdateMasked(uint64_t u64NewValue,
    266                                  uint64_t u64OldValue,
    267                                  uint64_t u64Mask)
     276DECLINLINE(uint64_t) hpetUpdateMasked(uint64_t u64NewValue,
     277                                      uint64_t u64OldValue,
     278                                      uint64_t u64Mask)
    268279{
    269280    u64NewValue &= u64Mask;
     
    272283}
    273284
    274 static bool hpetBitJustSet(uint64_t u64OldValue,
    275                            uint64_t u64NewValue,
    276                            uint64_t u64Mask)
     285DECLINLINE(bool) hpetBitJustSet(uint64_t u64OldValue,
     286                                uint64_t u64NewValue,
     287                                uint64_t u64Mask)
    277288{
    278289    return (!(u64OldValue & u64Mask) && !!(u64NewValue & u64Mask));
    279290}
    280291
    281 static bool hpetBitJustCleared(uint64_t u64OldValue,
    282                                uint64_t u64NewValue,
    283                                uint64_t u64Mask)
     292DECLINLINE(bool) hpetBitJustCleared(uint64_t u64OldValue,
     293                                    uint64_t u64NewValue,
     294                                    uint64_t u64Mask)
    284295{
    285296    return (!!(u64OldValue & u64Mask) && !(u64NewValue & u64Mask));
     
    290301{
    291302
    292     if (pTimer->u64Config & HPET_TN_32BIT)
     303    if (hpet32bitTimer(pTimer))
    293304    {
    294305        uint32_t u32Diff;
     
    317328  {
    318329      /* While loop is suboptimal */
    319       if (pTimer->u64Config & HPET_TN_32BIT)
     330      if (hpet32bitTimer(pTimer))
    320331      {
    321332          while (hpetTimeAfter32(u64Now, pTimer->u64Cmp))
     
    343354    u64Diff = hpetComputeDiff(pTimer, u64Ticks);
    344355
    345     /* HPET spec says in one-shot 32-bit mode, generate an interrupt when
     356    /*
     357     * HPET spec says in one-shot 32-bit mode, generate an interrupt when
    346358     * counter wraps in addition to an interrupt with comparator match.
    347      *
    348      * ICH9 spec doesn't mention that, so we disable wraparound behavior for ICH9,
    349      * see public trac defect #8707.
    350359     */
    351     if (!pTimer->CTX_SUFF(pHpet)->fIch9)
    352     {
    353         if (    (pTimer->u64Config & HPET_TN_32BIT)
    354             && !(pTimer->u64Config & HPET_TN_PERIODIC))
    355         {
    356             u32TillWrap = 0xffffffff - (uint32_t)u64Ticks;
    357             if (u32TillWrap < (uint32_t)u64Diff)
    358             {
    359                 u64Diff = u32TillWrap;
    360                 pTimer->u8Wrap = 1;
    361             }
     360    if (    hpet32bitTimer(pTimer)
     361        && !(pTimer->u64Config & HPET_TN_PERIODIC))
     362    {
     363        u32TillWrap = 0xffffffff - (uint32_t)u64Ticks + 1;
     364        if (u32TillWrap < (uint32_t)u64Diff)
     365        {
     366            Log(("wrap on timer %d: till=%u ticks=%lld diff64=%lld\n",
     367                 pTimer->u8TimerNumber, u32TillWrap, u64Ticks, u64Diff));
     368            u64Diff = u32TillWrap;
     369            pTimer->u8Wrap = 1;
    362370        }
    363371    }
     
    388396        && (pTimer->CTX_SUFF(pHpet)->u64HpetConfig & HPET_CFG_LEGACY))
    389397        return (pTimer->u8TimerNumber == 0) ? 0 : 8;
    390        
     398
    391399    return (pTimer->u64Config & HPET_TN_INT_ROUTE_MASK) >> HPET_TN_INT_ROUTE_SHIFT;
    392400}
     
    511519        case HPET_TN_CFG:
    512520        {
     521            uint64_t u64Mask = HPET_TN_CFG_WRITE_MASK;
     522
    513523            Log(("write HPET_TN_CFG: %d: %x\n", iTimerNo, iNewValue));
     524
     525            if ((pTimer->u64Config & HPET_TN_PERIODIC_CAP) != 0)
     526                u64Mask |= HPET_TN_PERIODIC;
     527
     528            if ((pTimer->u64Config & HPET_TN_SIZE_CAP) != 0)
     529                u64Mask |= HPET_TN_32BIT;
     530            else
     531                iNewValue &= ~HPET_TN_32BIT;
     532
    514533            if ((iNewValue & HPET_TN_32BIT) != 0)
    515534            {
    516                 Log(("setting timer to 32-bit mode\n"));
    517                 pTimer->u64Cmp = (uint32_t)pTimer->u64Cmp;
     535                Log(("setting timer %d to 32-bit mode\n", iTimerNo));
     536                pTimer->u64Cmp    = (uint32_t)pTimer->u64Cmp;
    518537                pTimer->u64Period = (uint32_t)pTimer->u64Period;
    519538            }
     
    525544            /** We only care about lower 32-bits so far */
    526545            pTimer->u64Config =
    527                     hpetUpdateMasked(iNewValue, iOldValue, HPET_TN_CFG_WRITE_MASK);
     546                    hpetUpdateMasked(iNewValue, iOldValue, u64Mask);
    528547            break;
    529548        }
     
    536555        {
    537556            Log(("write HPET_TN_CMP on %d: %x\n", iTimerNo, iNewValue));
    538             if (pTimer->u64Config & HPET_TN_32BIT)
    539                 iNewValue = (uint32_t)iNewValue;
    540 
    541             if (pTimer->u64Config & HPET_TN_SETVAL)
    542             {
    543                 /* HPET_TN_SETVAL allows to adjust comparator w/o updating period, and it's cleared on access */
    544                 if (pTimer->u64Config & HPET_TN_32BIT)
    545                     pTimer->u64Config &= ~HPET_TN_SETVAL;
    546             }
    547             else if (pTimer->u64Config & HPET_TN_PERIODIC)
    548             {
    549                 iNewValue &= (pTimer->u64Config & HPET_TN_32BIT ? ~0U : ~0ULL) >> 1;
     557            if (pTimer->u64Config & HPET_TN_PERIODIC)
     558            {
     559                iNewValue &= hpetInvalidValue(pTimer) >> 1;
    550560                pTimer->u64Period = (pTimer->u64Period & 0xffffffff00000000ULL)
    551561                                  | iNewValue;
     
    555565                           | iNewValue;
    556566
     567            pTimer->u64Config &= ~HPET_TN_SETVAL;
    557568            Log2(("after HPET_TN_CMP cmp=%llx per=%llx\n", pTimer->u64Cmp, pTimer->u64Period));
    558569
     
    564575        {
    565576            Log(("write HPET_TN_CMP + 4 on %d: %x\n", iTimerNo, iNewValue));
    566             if (pTimer->u64Config & HPET_TN_32BIT)
     577            if (hpet32bitTimer(pTimer))
    567578                break;
    568579
    569             if (pTimer->u64Config & HPET_TN_SETVAL)
    570             {
    571                 /* HPET_TN_SETVAL allows to adjust comparator w/o updating period, and it's cleared on access */
    572                 pTimer->u64Config &= ~HPET_TN_SETVAL;
    573             }
    574             else if (pTimer->u64Config & HPET_TN_PERIODIC)
    575             {
    576                  pTimer->u64Period = (pTimer->u64Period & 0xffffffffULL)
     580            if (pTimer->u64Config & HPET_TN_PERIODIC)
     581            {
     582                pTimer->u64Period = (pTimer->u64Period & UINT64_C(0xffffffff))
    577583                                   | ((uint64_t)iNewValue << 32);
    578584            }
    579585
    580             pTimer->u64Cmp = (pTimer->u64Cmp & 0xffffffffULL)
     586            pTimer->u64Cmp = (pTimer->u64Cmp & UINT64_C(0xffffffff))
    581587                           | ((uint64_t)iNewValue << 32);
    582588
    583589            Log2(("after HPET_TN_CMP+4 cmp=%llx per=%llx\n", pTimer->u64Cmp, pTimer->u64Period));
     590
     591            pTimer->u64Config &= ~HPET_TN_SETVAL;
    584592
    585593            if (pThis->u64HpetConfig & HPET_CFG_ENABLE)
     
    665673                        - TMTimerGet(pThis->aTimers[0].CTX_SUFF(pTimer));
    666674                for (i = 0; i < HPET_NUM_TIMERS; i++)
    667                     if (pThis->aTimers[i].u64Cmp != ~0ULL)
     675                    if (pThis->aTimers[i].u64Cmp != hpetInvalidValue(&pThis->aTimers[i]))
    668676                        hpetProgramTimer(&pThis->aTimers[i]);
    669677            }
     
    10761084        TMTimerSetNano(pTmTimer, hpetTicksToNs(pThis, u64Diff));
    10771085    }
    1078     else if (    (pTimer->u64Config & HPET_TN_32BIT)
     1086    else if (    hpet32bitTimer(pTimer)
    10791087             && !(pTimer->u64Config & HPET_TN_PERIODIC))
    10801088    {
     
    11361144        HpetTimer *pTimer = &pThis->aTimers[i];
    11371145        pTimer->u8TimerNumber = i;
    1138         pTimer->u64Cmp = ~0ULL;
    11391146        /* capable of periodic operations and 64-bits */
    1140         pTimer->u64Config =  HPET_TN_PERIODIC_CAP | HPET_TN_SIZE_CAP;
     1147        if (pThis->fIch9)
     1148            pTimer->u64Config = (i == 0) ? 
     1149                    (HPET_TN_PERIODIC_CAP | HPET_TN_SIZE_CAP)
     1150                    :
     1151                    0;
     1152        else
     1153            pTimer->u64Config = HPET_TN_PERIODIC_CAP | HPET_TN_SIZE_CAP;
     1154       
    11411155        /* We can do all IRQs */
    11421156        uint32_t u32RoutingCap = 0xffffffff;
     
    11441158        pTimer->u64Period = 0ULL;
    11451159        pTimer->u8Wrap = 0;
     1160        pTimer->u64Cmp = hpetInvalidValue(pTimer);
    11461161    }
    11471162    pThis->u64HpetCounter = 0ULL;
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