VirtualBox

Changeset 37504 in vbox for trunk/src/VBox/Devices/PC


Ignore:
Timestamp:
Jun 16, 2011 4:36:24 PM (14 years ago)
Author:
vboxsync
Message:

DevHPET: More cleaning up...

File:
1 edited

Legend:

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

    r37501 r37504  
    110110/** The version of the saved state. */
    111111#define HPET_SAVED_STATE_VERSION       2
    112 
    113112/** Empty saved state */
    114113#define HPET_SAVED_STATE_VERSION_EMPTY 1
     
    217216
    218217    /** If we emulate ICH9 HPET (different frequency).
    219      * @todo different number of timers  */
    220     uint8_t              fIch9;
     218     * @todo different number of timers */
     219    bool                 fIch9;
    221220    uint8_t              padding0[7];
    222221} HpetState;
     
    248247}
    249248
    250 DECLINLINE(uint64_t) hpetTicksToNs(HpetState* pThis, uint64_t value)
     249DECLINLINE(uint64_t) hpetTicksToNs(HpetState *pThis, uint64_t value)
    251250{
    252251    return (ASMMultU64ByU32DivByU32(value,  (uint32_t)(pThis->u64Capabilities >> 32), FS_PER_NS));
    253252}
    254253
    255 DECLINLINE(uint64_t) nsToHpetTicks(HpetState* pThis, uint64_t u64Value)
     254DECLINLINE(uint64_t) nsToHpetTicks(HpetState const *pThis, uint64_t u64Value)
    256255{
    257256    return (ASMMultU64ByU32DivByU32(u64Value, FS_PER_NS, (uint32_t)(pThis->u64Capabilities >> 32)));
    258257}
    259258
    260 DECLINLINE(uint64_t) hpetGetTicks(HpetState* pThis)
     259DECLINLINE(uint64_t) hpetGetTicks(HpetState const *pThis)
    261260{
    262261    /*
     
    282281                                uint64_t u64Mask)
    283282{
    284     return (!(u64OldValue & u64Mask) && !!(u64NewValue & u64Mask));
     283    return !(u64OldValue & u64Mask)
     284        && !!(u64NewValue & u64Mask);
    285285}
    286286
     
    289289                                    uint64_t u64Mask)
    290290{
    291     return (!!(u64OldValue & u64Mask) && !(u64NewValue & u64Mask));
     291    return !!(u64OldValue & u64Mask)
     292        && !(u64NewValue & u64Mask);
    292293}
    293294
     
    377378}
    378379
    379 static uint32_t getTimerIrq(struct HpetTimer *pHpetTimer)
     380
     381/**
     382 * Reads a HPET timer register.
     383 *
     384 * @returns VBox strict status code.
     385 * @param   pThis               The HPET instance.
     386 * @param   iTimerNo            The timer index.
     387 * @param   iTimerReg           The index of the timer register to read.
     388 * @param   pu32Value           Where to return the register value.
     389 *
     390 * @remarks ASSUMES the caller does holds the HPET lock.
     391 */
     392static int hpetTimerRegRead32(HpetState const *pThis, uint32_t iTimerNo, uint32_t iTimerReg, uint32_t *pu32Value)
     393{
     394    if (iTimerNo >= HPET_NUM_TIMERS)
     395    {
     396        static unsigned s_cOccurences = 0;
     397        if (s_cOccurences++ < 10)
     398            LogRel(("HPET: using timer above configured range: %d\n", iTimerNo));
     399        *pu32Value = 0;
     400        return VINF_SUCCESS;
     401    }
     402
     403    HpetTimer const *pHpetTimer = &pThis->aTimers[iTimerNo];
     404    uint32_t u32Value;
     405    switch (iTimerReg)
     406    {
     407        case HPET_TN_CFG:
     408            u32Value = (uint32_t)pHpetTimer->u64Config;
     409            Log(("read HPET_TN_CFG on %d: %#x\n", iTimerNo, u32Value));
     410            break;
     411
     412        case HPET_TN_CFG + 4:
     413            u32Value = (uint32_t)(pHpetTimer->u64Config >> 32);
     414            Log(("read HPET_TN_CFG+4 on %d: %#x\n", iTimerNo, u32Value));
     415            break;
     416
     417        case HPET_TN_CMP:
     418            u32Value = (uint32_t)pHpetTimer->u64Cmp;
     419            Log(("read HPET_TN_CMP on %d: %#x (%#llx)\n", pHpetTimer->idxTimer, u32Value, pHpetTimer->u64Cmp));
     420            break;
     421
     422        case HPET_TN_CMP + 4:
     423            u32Value = (uint32_t)(pHpetTimer->u64Cmp >> 32);
     424            Log(("read HPET_TN_CMP+4 on %d: %#x (%#llx)\n", pHpetTimer->idxTimer, u32Value, pHpetTimer->u64Cmp));
     425            break;
     426
     427        case HPET_TN_ROUTE:
     428            u32Value = (uint32_t)(pHpetTimer->u64Fsb >> 32); /** @todo Looks wrong, but since it's not supported, who cares. */
     429            Log(("read HPET_TN_ROUTE on %d: %#x\n", iTimerNo, u32Value));
     430            break;
     431
     432        default:
     433        {
     434            static unsigned s_cOccurences = 0;
     435            if (s_cOccurences++ < 10)
     436                LogRel(("invalid HPET register read %d on %d\n", iTimerReg, pHpetTimer->idxTimer));
     437            u32Value = 0;
     438            break;
     439        }
     440    }
     441    *pu32Value = u32Value;
     442    return VINF_SUCCESS;
     443}
     444
     445
     446/**
     447 * Read a 32-bit HPET register.
     448 *
     449 * @returns Strict VBox status code.
     450 * @param   pThis               The HPET state.
     451 * @param   idxReg              The register to read.
     452 * @param   pu32Value           Where to return the register value.
     453 */
     454static int hpetConfigRegRead32(HpetState const *pThis, uint32_t idxReg, uint32_t *pu32Value)
     455{
     456    uint32_t u32Value;
     457    switch (idxReg)
     458    {
     459        case HPET_ID:
     460            u32Value = (uint32_t)pThis->u64Capabilities;
     461            Log(("read HPET_ID: %#x\n", u32Value));
     462            break;
     463
     464        case HPET_PERIOD:
     465            u32Value = (uint32_t)(pThis->u64Capabilities >> 32);
     466            Log(("read HPET_PERIOD: %#x\n", u32Value));
     467            break;
     468
     469        case HPET_CFG:
     470            u32Value = (uint32_t)pThis->u64HpetConfig;
     471            Log(("read HPET_CFG: %#x\n", u32Value));
     472            break;
     473
     474        case HPET_CFG + 4:
     475            u32Value = (uint32_t)(pThis->u64HpetConfig >> 32);
     476            Log(("read of HPET_CFG + 4: %#x\n", u32Value));
     477            break;
     478
     479        case HPET_COUNTER:
     480        case HPET_COUNTER + 4:
     481        {
     482            uint64_t u64Ticks;
     483            if (pThis->u64HpetConfig & HPET_CFG_ENABLE)
     484                u64Ticks = hpetGetTicks(pThis);
     485            else
     486                u64Ticks = pThis->u64HpetCounter;
     487            /** @todo is it correct? */
     488            u32Value = (idxReg == HPET_COUNTER) ? (uint32_t)u64Ticks : (uint32_t)(u64Ticks >> 32);
     489            Log(("read HPET_COUNTER: %s part value %x (%#llx)\n",
     490                 (idxReg == HPET_COUNTER) ? "low" : "high", u32Value, u64Ticks));
     491            break;
     492        }
     493
     494        case HPET_STATUS:
     495            Log(("read HPET_STATUS\n"));
     496            u32Value = (uint32_t)pThis->u64Isr;
     497            break;
     498
     499        default:
     500            Log(("invalid HPET register read: %x\n", idxReg));
     501            u32Value = 0;
     502            break;
     503    }
     504
     505    *pu32Value = u32Value;
     506    return VINF_SUCCESS;
     507}
     508
     509
     510/**
     511 * 32-bit write to a HPET timer register.
     512 *
     513 * @returns Strict VBox status code.
     514 *
     515 * @param   pThis           The HPET state.
     516 * @param   idxReg          The register being written to.
     517 * @param   u32NewValue     The value being written.
     518 */
     519static int hpetTimerRegWrite32(HpetState *pThis, uint32_t iTimerNo, uint32_t iTimerReg, uint32_t u32NewValue)
     520{
     521    if (iTimerNo >= HPET_NUM_TIMERS)
     522    {
     523        LogRel(("HPET: using timer above configured range: %d\n", iTimerNo));
     524        return VINF_SUCCESS;
     525    }
     526    HpetTimer *pHpetTimer = &pThis->aTimers[iTimerNo];
     527
     528    /** @todo iOldValue is only used by in HPET_TN_CFG, so this is a waste of
     529     *   time. */
     530    uint32_t u32Temp;
     531    int rc = hpetTimerRegRead32(pThis, iTimerNo, iTimerReg, &u32Temp);
     532    if (RT_FAILURE(rc))
     533        return rc;
     534    uint64_t iOldValue = u32Temp;
     535
     536    switch (iTimerReg)
     537    {
     538        case HPET_TN_CFG:
     539        {
     540            Log(("write HPET_TN_CFG: %d: %x\n", iTimerNo, u32NewValue));
     541
     542            uint64_t u64Mask = HPET_TN_CFG_WRITE_MASK;
     543            if ((pHpetTimer->u64Config & HPET_TN_PERIODIC_CAP) != 0)
     544                u64Mask |= HPET_TN_PERIODIC;
     545
     546            if ((pHpetTimer->u64Config & HPET_TN_SIZE_CAP) != 0)
     547                u64Mask |= HPET_TN_32BIT;
     548            else
     549                u32NewValue &= ~HPET_TN_32BIT;
     550
     551            if ((u32NewValue & HPET_TN_32BIT) != 0)
     552            {
     553                Log(("setting timer %d to 32-bit mode\n", iTimerNo));
     554                pHpetTimer->u64Cmp    = (uint32_t)pHpetTimer->u64Cmp;
     555                pHpetTimer->u64Period = (uint32_t)pHpetTimer->u64Period;
     556            }
     557            if ((u32NewValue & HPET_TN_INT_TYPE) == HPET_TIMER_TYPE_LEVEL)
     558            {
     559                LogRel(("level-triggered config not yet supported\n"));
     560                AssertFailed();
     561            }
     562
     563            /* We only care about lower 32-bits so far */
     564            pHpetTimer->u64Config = hpetUpdateMasked(u32NewValue, iOldValue, u64Mask);
     565            break;
     566        }
     567
     568        case HPET_TN_CFG + 4: /* Interrupt capabilities */
     569        {
     570            Log(("write HPET_TN_CFG + 4, useless\n"));
     571            break;
     572        }
     573
     574        case HPET_TN_CMP: /* lower bits of comparator register */
     575        {
     576            Log(("write HPET_TN_CMP on %d: %x\n", iTimerNo, u32NewValue));
     577            if (pHpetTimer->u64Config & HPET_TN_PERIODIC)
     578            {
     579                u32NewValue &= hpetInvalidValue(pHpetTimer) >> 1;
     580                pHpetTimer->u64Period = (pHpetTimer->u64Period & UINT64_C(0xffffffff00000000))
     581                                      | u32NewValue;
     582            }
     583
     584            pHpetTimer->u64Cmp = (pHpetTimer->u64Cmp & UINT64_C(0xffffffff00000000))
     585                               | u32NewValue;
     586
     587            pHpetTimer->u64Config &= ~HPET_TN_SETVAL;
     588            Log2(("after HPET_TN_CMP cmp=%llx per=%llx\n", pHpetTimer->u64Cmp, pHpetTimer->u64Period));
     589
     590            if (pThis->u64HpetConfig & HPET_CFG_ENABLE)
     591                hpetProgramTimer(pHpetTimer);
     592            break;
     593        }
     594
     595        case HPET_TN_CMP + 4: /* upper bits of comparator register */
     596        {
     597            Log(("write HPET_TN_CMP + 4 on %d: %x\n", iTimerNo, u32NewValue));
     598            if (hpet32bitTimer(pHpetTimer))
     599                break;
     600
     601            if (pHpetTimer->u64Config & HPET_TN_PERIODIC)
     602                pHpetTimer->u64Period = RT_MAKE_U64(pHpetTimer->u64Period, u32NewValue);
     603            pHpetTimer->u64Cmp = RT_MAKE_U64(pHpetTimer->u64Cmp, u32NewValue);
     604
     605            Log2(("after HPET_TN_CMP+4 cmp=%llx per=%llx tmr=%d\n", pHpetTimer->u64Cmp, pHpetTimer->u64Period, iTimerNo));
     606
     607            pHpetTimer->u64Config &= ~HPET_TN_SETVAL;
     608
     609            if (pThis->u64HpetConfig & HPET_CFG_ENABLE)
     610                hpetProgramTimer(pHpetTimer);
     611            break;
     612        }
     613
     614        case HPET_TN_ROUTE:
     615        {
     616            Log(("write HPET_TN_ROUTE\n"));
     617            break;
     618        }
     619
     620        case HPET_TN_ROUTE + 4:
     621        {
     622            Log(("write HPET_TN_ROUTE + 4\n"));
     623            break;
     624        }
     625
     626        default:
     627        {
     628            LogRel(("invalid timer register write: %d\n", iTimerReg));
     629            AssertFailed();
     630            break;
     631        }
     632    }
     633
     634    return VINF_SUCCESS;
     635}
     636
     637
     638/**
     639 * 32-bit write to a config register.
     640 *
     641 * @returns Strict VBox status code.
     642 *
     643 * @param   pThis           The HPET state.
     644 * @param   idxReg          The register being written to.
     645 * @param   u32NewValue     The value being written.
     646 */
     647static int hpetConfigRegWrite32(HpetState *pThis, uint32_t idxReg, uint32_t u32NewValue)
     648{
     649    int rc = VINF_SUCCESS;
     650    switch (idxReg)
     651    {
     652        case HPET_ID:
     653        case HPET_ID + 4:
     654        {
     655            Log(("write HPET_ID, useless\n"));
     656            break;
     657        }
     658
     659        case HPET_CFG:
     660        {
     661            uint32_t const iOldValue = (uint32_t)(pThis->u64HpetConfig);
     662            Log(("write HPET_CFG: %x (old %x)\n", u32NewValue, iOldValue));
     663
     664            /*
     665             * This check must be here, before actual update, as hpetLegacyMode
     666             * may request retry in R3 - so we must keep state intact.
     667             */
     668            if (   ((iOldValue ^ u32NewValue) & HPET_CFG_LEGACY)
     669                && pThis->pHpetHlpR3 != NIL_RTR3PTR)
     670            {
     671#ifdef IN_RING3
     672                rc = pThis->pHpetHlpR3->pfnSetLegacyMode(pThis->pDevInsR3, RT_BOOL(u32NewValue & HPET_CFG_LEGACY));
     673                if (rc != VINF_SUCCESS)
     674                    break;
     675#else
     676                rc = VINF_IOM_HC_MMIO_WRITE;
     677                break;
     678#endif
     679            }
     680
     681            pThis->u64HpetConfig = hpetUpdateMasked(u32NewValue, iOldValue, HPET_CFG_WRITE_MASK);
     682
     683            if (hpetBitJustSet(iOldValue, u32NewValue, HPET_CFG_ENABLE))
     684            {
     685/** @todo Only get the time stamp once when reprogramming? */
     686                /* Enable main counter and interrupt generation. */
     687                pThis->u64HpetOffset = hpetTicksToNs(pThis, pThis->u64HpetCounter)
     688                                     - TMTimerGet(pThis->aTimers[0].CTX_SUFF(pTimer));
     689                for (uint32_t i = 0; i < HPET_NUM_TIMERS; i++)
     690                    if (pThis->aTimers[i].u64Cmp != hpetInvalidValue(&pThis->aTimers[i]))
     691                        hpetProgramTimer(&pThis->aTimers[i]);
     692            }
     693            else if (hpetBitJustCleared(iOldValue, u32NewValue, HPET_CFG_ENABLE))
     694            {
     695                /* Halt main counter and disable interrupt generation. */
     696                pThis->u64HpetCounter = hpetGetTicks(pThis);
     697                for (uint32_t i = 0; i < HPET_NUM_TIMERS; i++)
     698                    TMTimerStop(pThis->aTimers[i].CTX_SUFF(pTimer));
     699            }
     700            break;
     701        }
     702
     703        case HPET_CFG + 4:
     704        {
     705            /** @todo why do we let the guest write to the high bits but not
     706             *        read them? */
     707            pThis->u64HpetConfig = hpetUpdateMasked((uint64_t)u32NewValue << 32,
     708                                                    pThis->u64HpetConfig,
     709                                                    UINT64_C(0xffffffff00000000));
     710            Log(("write HPET_CFG + 4: %x -> %#llx\n", u32NewValue, pThis->u64HpetConfig));
     711            break;
     712        }
     713
     714        case HPET_STATUS:
     715        {
     716            /* Clear ISR for all set bits in u32NewValue, see p. 14 of the HPET spec. */
     717            pThis->u64Isr &= ~((uint64_t)u32NewValue);
     718            Log(("write HPET_STATUS: %x -> ISR=%#llx\n", u32NewValue, pThis->u64Isr));
     719            break;
     720        }
     721
     722        case HPET_STATUS + 4:
     723        {
     724            Log(("write HPET_STATUS + 4: %x\n", u32NewValue));
     725            if (u32NewValue != 0)
     726            {
     727                static unsigned s_cOccurrences = 0;
     728                if (s_cOccurrences++ < 10)
     729                    LogRel(("Writing HPET_STATUS + 4 with non-zero, ignored\n"));
     730            }
     731            break;
     732        }
     733
     734        case HPET_COUNTER:
     735        {
     736            pThis->u64HpetCounter = RT_MAKE_U64(u32NewValue, pThis->u64HpetCounter);
     737            Log(("write HPET_COUNTER: %#x -> %llx\n", u32NewValue, pThis->u64HpetCounter));
     738            break;
     739        }
     740
     741        case HPET_COUNTER + 4:
     742        {
     743            pThis->u64HpetCounter = RT_MAKE_U64(pThis->u64HpetCounter, u32NewValue);
     744            Log(("write HPET_COUNTER + 4: %#x -> %llx\n", u32NewValue, pThis->u64HpetCounter));
     745            break;
     746        }
     747
     748        default:
     749            LogRel(("invalid HPET config write: %x\n", idxReg));
     750            break;
     751    }
     752
     753    return rc;
     754}
     755
     756
     757/* -=-=-=-=-=- MMIO callbacks -=-=-=-=-=- */
     758
     759
     760/**
     761 * @callback_method_impl{FNIOMMMIOREAD}
     762 */
     763PDMBOTHCBDECL(int)  hpetMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
     764{
     765    HpetState      *pThis  = PDMINS_2_DATA(pDevIns, HpetState*);
     766    uint32_t const  idxReg = (uint32_t)(GCPhysAddr - HPET_BASE);
     767
     768    LogFlow(("hpetMMIORead (%d): %llx (%x)\n", cb, (uint64_t)GCPhysAddr, idxReg));
     769    DEVHPET_LOCK_RETURN(pThis, VINF_IOM_HC_MMIO_READ);
     770
     771    int rc = VINF_SUCCESS;
     772    switch (cb)
     773    {
     774        case 4:
     775            if (idxReg >= 0x100 && idxReg < 0x400)
     776                rc = hpetTimerRegRead32(pThis,
     777                                        (idxReg - 0x100) / 0x20,
     778                                        (idxReg - 0x100) % 0x20,
     779                                        (uint32_t *)pv);
     780            else
     781                rc = hpetConfigRegRead32(pThis, idxReg, (uint32_t *)pv);
     782            break;
     783
     784        case 8:
     785        {
     786            /* Unaligned accesses not allowed */
     787            if (RT_UNLIKELY(idxReg % 8 != 0))
     788            {
     789                rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "idxReg=%#x cb=8\n", idxReg);
     790                break;
     791            }
     792
     793            /* Split the access except for timing sensitive registers.  The
     794               others assume the protection of the lock. */
     795            PRTUINT64U pValue = (PRTUINT64U)pv;
     796            if (idxReg == HPET_COUNTER)
     797            {
     798                /* When reading HPET counter we must read it in a single read,
     799                   to avoid unexpected time jumps on 32-bit overflow. */
     800                pValue->u = (pThis->u64HpetConfig & HPET_CFG_ENABLE) != 0
     801                          ? hpetGetTicks(pThis)
     802                          : pThis->u64HpetCounter;
     803                rc = VINF_SUCCESS;
     804            }
     805            else if (idxReg >= 0x100 && idxReg < 0x400)
     806            {
     807                uint32_t iTimer    = (idxReg - 0x100) / 0x20;
     808                uint32_t iTimerReg = (idxReg - 0x100) % 0x20;
     809                rc = hpetTimerRegRead32(pThis, iTimer, iTimerReg, &pValue->s.Lo);
     810                if (rc == VINF_SUCCESS)
     811                    rc = hpetTimerRegRead32(pThis, iTimer, iTimerReg + 4, &pValue->s.Hi);
     812            }
     813            else
     814            {
     815                /* for most 8-byte accesses we just split them, happens under lock anyway. */
     816                rc = hpetConfigRegRead32(pThis, idxReg, &pValue->s.Lo);
     817                if (rc == VINF_SUCCESS)
     818                    rc = hpetConfigRegRead32(pThis, idxReg + 4, &pValue->s.Hi);
     819            }
     820            break;
     821        }
     822
     823        case 1:
     824        case 2:
     825            Log(("Narrow read: %d\n", cb));
     826            rc = VINF_SUCCESS;
     827            break;
     828
     829        default:
     830            AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */
     831            rc = VINF_SUCCESS;
     832    }
     833
     834    DEVHPET_UNLOCK(pThis);
     835    return rc;
     836}
     837
     838
     839/**
     840 * @callback_method_impl{FNIOMMMIOWRITE}
     841 */
     842PDMBOTHCBDECL(int) hpetMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
     843{
     844    HpetState  *pThis  = PDMINS_2_DATA(pDevIns, HpetState*);
     845    uint32_t    idxReg = (uint32_t)(GCPhysAddr - HPET_BASE);
     846    LogFlow(("hpetMMIOWrite: cb=%u reg=%03x (%RGp) val=%llx\n",
     847             cb, idxReg, GCPhysAddr, cb == 4 ? *(uint32_t *)pv : cb == 8 ? *(uint64_t *)pv : 0xdeadbeef));
     848
     849    DEVHPET_LOCK_RETURN(pThis, VINF_IOM_HC_MMIO_WRITE);
     850
     851    int rc;
     852    switch (cb)
     853    {
     854        case 4:
     855            if (idxReg >= 0x100 && idxReg < 0x400)
     856                rc = hpetTimerRegWrite32(pThis,
     857                                         (idxReg - 0x100) / 0x20,
     858                                         (idxReg - 0x100) % 0x20,
     859                                         *(uint32_t const *)pv);
     860            else
     861                rc = hpetConfigRegWrite32(pThis, idxReg, *(uint32_t const *)pv);
     862            break;
     863
     864        case 8:
     865        {
     866            /* Unaligned accesses are not allowed. */
     867            if (RT_UNLIKELY(idxReg % 8 != 0))
     868            {
     869                rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "idxReg=%#x cb=8\n", idxReg);
     870                break;
     871            }
     872
     873            /* Split the access and rely on the locking to prevent trouble. */
     874            RTUINT64U uValue;
     875            uValue.u = *(uint64_t const *)pv;
     876            if (idxReg >= 0x100 && idxReg < 0x400)
     877            {
     878                uint32_t iTimer    = (idxReg - 0x100) / 0x20;
     879                uint32_t iTimerReg = (idxReg - 0x100) % 0x20;
     880/** @todo Consider handling iTimerReg == HPET_TN_CMP specially here */
     881                rc = hpetTimerRegWrite32(pThis, iTimer, iTimerReg, uValue.s.Lo);
     882                if (RT_LIKELY(rc == VINF_SUCCESS))
     883                    rc = hpetTimerRegWrite32(pThis, iTimer, iTimerReg + 4, uValue.s.Hi);
     884            }
     885            else
     886            {
     887                rc = hpetConfigRegWrite32(pThis, idxReg, uValue.s.Lo);
     888                if (RT_LIKELY(rc == VINF_SUCCESS))
     889                    rc = hpetConfigRegWrite32(pThis, idxReg + 4, uValue.s.Hi);
     890            }
     891            break;
     892        }
     893
     894        case 1:
     895        case 2:
     896            Log(("Narrow write: %d\n", cb));
     897            rc = VINF_SUCCESS;
     898            break;
     899
     900        default:
     901            AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */
     902            rc = VERR_INTERNAL_ERROR;
     903            break;
     904    }
     905
     906    DEVHPET_UNLOCK(pThis);
     907    return rc;
     908}
     909
     910#ifdef IN_RING3
     911
     912/* -=-=-=-=-=- Timer Callback Processing -=-=-=-=-=- */
     913
     914/**
     915 * Gets the IRQ of an HPET timer.
     916 *
     917 * @returns IRQ number.
     918 * @param   pHpetTimer          The HPET timer.
     919 */
     920static uint32_t hpetTimerCbGetIrq(struct HpetTimer const *pHpetTimer)
    380921{
    381922    /*
     
    394935}
    395936
    396 static int hpetTimerRegRead32(HpetState *pThis,
    397                               uint32_t   iTimerNo,
    398                               uint32_t   iTimerReg,
    399                               uint32_t  *pValue)
    400 {
    401     if (iTimerNo >= HPET_NUM_TIMERS)
    402     {
    403         LogRel(("HPET: using timer above configured range: %d\n", iTimerNo));
    404         return VINF_SUCCESS;
    405     }
    406 
    407     HpetTimer *pHpetTimer = &pThis->aTimers[iTimerNo];
    408     switch (iTimerReg)
    409     {
    410         case HPET_TN_CFG:
    411             Log(("read HPET_TN_CFG on %d\n", pHpetTimer->idxTimer));
    412             *pValue = (uint32_t)(pHpetTimer->u64Config);
    413             break;
    414         case HPET_TN_CFG + 4:
    415             Log(("read HPET_TN_CFG+4 on %d\n", pHpetTimer->idxTimer));
    416             *pValue = (uint32_t)(pHpetTimer->u64Config >> 32);
    417             break;
    418         case HPET_TN_CMP:
    419             Log(("read HPET_TN_CMP on %d, cmp=%llx\n", pHpetTimer->idxTimer, pHpetTimer->u64Cmp));
    420             *pValue = (uint32_t)(pHpetTimer->u64Cmp);
    421             break;
    422         case HPET_TN_CMP + 4:
    423             Log(("read HPET_TN_CMP+4 on %d, cmp=%llx\n", pHpetTimer->idxTimer, pHpetTimer->u64Cmp));
    424             *pValue = (uint32_t)(pHpetTimer->u64Cmp >> 32);
    425             break;
    426         case HPET_TN_ROUTE:
    427             Log(("read HPET_TN_ROUTE on %d\n", pHpetTimer->idxTimer));
    428             *pValue = (uint32_t)(pHpetTimer->u64Fsb >> 32);
    429             break;
    430         default:
    431             LogRel(("invalid HPET register read %d on %d\n", iTimerReg, pHpetTimer->idxTimer));
    432             *pValue = 0;
    433             break;
    434         }
    435 
    436     return VINF_SUCCESS;
    437 }
    438 
    439 static int hpetConfigRegRead32(HpetState *pThis,
    440                                uint32_t   iIndex,
    441                                uint32_t  *pValue)
    442 {
    443     switch (iIndex)
    444     {
    445         case HPET_ID:
    446             Log(("read HPET_ID\n"));
    447             *pValue = (uint32_t)(pThis->u64Capabilities);
    448             break;
    449         case HPET_PERIOD:
    450             Log(("read HPET_PERIOD\n"));
    451             *pValue = (uint32_t)(pThis->u64Capabilities >> 32);
    452             break;
    453         case HPET_CFG:
    454             Log(("read HPET_CFG\n"));
    455             *pValue = (uint32_t)(pThis->u64HpetConfig);
    456             break;
    457         case HPET_CFG + 4:
    458             Log(("read of HPET_CFG + 4\n"));
    459             *pValue = (uint32_t)(pThis->u64HpetConfig >> 32);
    460             break;
    461         case HPET_COUNTER:
    462         case HPET_COUNTER + 4:
    463         {
    464             uint64_t u64Ticks;
    465             if (pThis->u64HpetConfig & HPET_CFG_ENABLE)
    466                 u64Ticks = hpetGetTicks(pThis);
    467             else
    468                 u64Ticks = pThis->u64HpetCounter;
    469             /** @todo: is it correct? */
    470             *pValue = (iIndex == HPET_COUNTER) ? (uint32_t)u64Ticks : (uint32_t)(u64Ticks >> 32);
    471             Log(("read HPET_COUNTER: %s part value %x\n", (iIndex == HPET_COUNTER) ? "low" : "high", *pValue));
    472             break;
    473         }
    474         case HPET_STATUS:
    475             Log(("read HPET_STATUS\n"));
    476             *pValue = (uint32_t)(pThis->u64Isr);
    477             break;
    478         default:
    479             Log(("invalid HPET register read: %x\n", iIndex));
    480             *pValue = 0;
    481             break;
    482     }
    483     return VINF_SUCCESS;
    484 }
    485 
    486 static int hpetTimerRegWrite32(HpetState *pThis,
    487                                uint32_t   iTimerNo,
    488                                uint32_t   iTimerReg,
    489                                uint32_t   iNewValue)
    490 {
    491     uint32_t    u32Temp;
    492     int         rc;
    493 
    494     if (iTimerNo >= HPET_NUM_TIMERS)
    495     {
    496         LogRel(("HPET: using timer above configured range: %d\n", iTimerNo));
    497         return VINF_SUCCESS;
    498     }
    499 
    500     HpetTimer *pHpetTimer = &pThis->aTimers[iTimerNo];
    501     rc = hpetTimerRegRead32(pThis, iTimerNo, iTimerReg, &u32Temp);
    502     if (RT_FAILURE(rc))
    503         return rc;
    504     uint64_t iOldValue = u32Temp;
    505 
    506     switch (iTimerReg)
    507     {
    508         case HPET_TN_CFG:
    509         {
    510             uint64_t u64Mask = HPET_TN_CFG_WRITE_MASK;
    511 
    512             Log(("write HPET_TN_CFG: %d: %x\n", iTimerNo, iNewValue));
    513 
    514             if ((pHpetTimer->u64Config & HPET_TN_PERIODIC_CAP) != 0)
    515                 u64Mask |= HPET_TN_PERIODIC;
    516 
    517             if ((pHpetTimer->u64Config & HPET_TN_SIZE_CAP) != 0)
    518                 u64Mask |= HPET_TN_32BIT;
    519             else
    520                 iNewValue &= ~HPET_TN_32BIT;
    521 
    522             if ((iNewValue & HPET_TN_32BIT) != 0)
    523             {
    524                 Log(("setting timer %d to 32-bit mode\n", iTimerNo));
    525                 pHpetTimer->u64Cmp    = (uint32_t)pHpetTimer->u64Cmp;
    526                 pHpetTimer->u64Period = (uint32_t)pHpetTimer->u64Period;
    527             }
    528             if ((iNewValue & HPET_TN_INT_TYPE) == HPET_TIMER_TYPE_LEVEL)
    529             {
    530                 LogRel(("level-triggered config not yet supported\n"));
    531                 AssertFailed();
    532             }
    533             /* We only care about lower 32-bits so far */
    534             pHpetTimer->u64Config = hpetUpdateMasked(iNewValue, iOldValue, u64Mask);
    535             break;
    536         }
    537 
    538         case HPET_TN_CFG + 4: /* Interrupt capabilities */
    539         {
    540             Log(("write HPET_TN_CFG + 4, useless\n"));
    541             break;
    542         }
    543 
    544         case HPET_TN_CMP: /* lower bits of comparator register */
    545         {
    546             Log(("write HPET_TN_CMP on %d: %x\n", iTimerNo, iNewValue));
    547             if (pHpetTimer->u64Config & HPET_TN_PERIODIC)
    548             {
    549                 iNewValue &= hpetInvalidValue(pHpetTimer) >> 1;
    550                 pHpetTimer->u64Period = (pHpetTimer->u64Period & UINT64_C(0xffffffff00000000))
    551                                       | iNewValue;
    552             }
    553 
    554             pHpetTimer->u64Cmp = (pHpetTimer->u64Cmp & UINT64_C(0xffffffff00000000))
    555                                | iNewValue;
    556 
    557             pHpetTimer->u64Config &= ~HPET_TN_SETVAL;
    558             Log2(("after HPET_TN_CMP cmp=%llx per=%llx\n", pHpetTimer->u64Cmp, pHpetTimer->u64Period));
    559 
    560             if (pThis->u64HpetConfig & HPET_CFG_ENABLE)
    561                 hpetProgramTimer(pHpetTimer);
    562             break;
    563         }
    564 
    565         case HPET_TN_CMP + 4: /* upper bits of comparator register */
    566         {
    567             Log(("write HPET_TN_CMP + 4 on %d: %x\n", iTimerNo, iNewValue));
    568             if (hpet32bitTimer(pHpetTimer))
    569                 break;
    570 
    571             if (pHpetTimer->u64Config & HPET_TN_PERIODIC)
    572                 pHpetTimer->u64Period = (pHpetTimer->u64Period & UINT64_C(0xffffffff))
    573                                       | ((uint64_t)iNewValue << 32);
    574 
    575             pHpetTimer->u64Cmp = (pHpetTimer->u64Cmp & UINT64_C(0xffffffff))
    576                                | ((uint64_t)iNewValue << 32);
    577 
    578             Log2(("after HPET_TN_CMP+4 cmp=%llx per=%llx\n", pHpetTimer->u64Cmp, pHpetTimer->u64Period));
    579 
    580             pHpetTimer->u64Config &= ~HPET_TN_SETVAL;
    581 
    582             if (pThis->u64HpetConfig & HPET_CFG_ENABLE)
    583                 hpetProgramTimer(pHpetTimer);
    584             break;
    585         }
    586 
    587         case HPET_TN_ROUTE:
    588         {
    589             Log(("write HPET_TN_ROUTE\n"));
    590             break;
    591         }
    592 
    593         case HPET_TN_ROUTE + 4:
    594         {
    595             Log(("write HPET_TN_ROUTE + 4\n"));
    596             break;
    597         }
    598 
    599         default:
    600         {
    601             LogRel(("invalid timer register write: %d\n", iTimerReg));
    602             AssertFailed();
    603             break;
    604         }
    605     }
    606 
    607     return VINF_SUCCESS;
    608 }
    609 
    610 static int hpetLegacyMode(HpetState* pThis,
    611                           bool       fActivate)
    612 {
    613     int rc = VINF_SUCCESS;
    614 #ifndef IN_RING3
    615     /* Don't do anything complicated outside of R3 */
    616     rc =  VINF_IOM_HC_MMIO_WRITE;
    617 #else /* IN_RING3 */
    618     if (pThis->pHpetHlpR3)
    619         rc = pThis->pHpetHlpR3->pfnSetLegacyMode(pThis->pDevInsR3, fActivate);
    620 #endif
    621     return rc;
    622 }
    623 
    624 static int hpetConfigRegWrite32(HpetState* pThis,
    625                                 uint32_t   iIndex,
    626                                 uint32_t   iNewValue)
    627 {
    628     int rc = VINF_SUCCESS;
    629 
    630     switch (iIndex)
    631     {
    632         case HPET_ID:
    633         case HPET_ID + 4:
    634         {
    635             Log(("write HPET_ID, useless\n"));
    636             break;
    637         }
    638 
    639         case HPET_CFG:
    640         {
    641             uint32_t const iOldValue = (uint32_t)(pThis->u64HpetConfig);
    642             Log(("write HPET_CFG: %x (old %x)\n", iNewValue, iOldValue));
    643 
    644             /*
    645              * This check must be here, before actual update, as hpetLegacyMode
    646              * may request retry in R3 - so we must keep state intact.
    647              */
    648             if (hpetBitJustSet(iOldValue, iNewValue, HPET_CFG_LEGACY))
    649                 rc = hpetLegacyMode(pThis, true);
    650             else if (hpetBitJustCleared(iOldValue, iNewValue, HPET_CFG_LEGACY))
    651                 rc = hpetLegacyMode(pThis, false);
    652             if (rc != VINF_SUCCESS)
    653                 return rc;
    654 
    655             pThis->u64HpetConfig = hpetUpdateMasked(iNewValue, iOldValue, HPET_CFG_WRITE_MASK);
    656             if (hpetBitJustSet(iOldValue, iNewValue, HPET_CFG_ENABLE))
    657             {
    658                 /* Enable main counter and interrupt generation. */
    659                 pThis->u64HpetOffset = hpetTicksToNs(pThis, pThis->u64HpetCounter)
    660                                      - TMTimerGet(pThis->aTimers[0].CTX_SUFF(pTimer));
    661                 for (uint32_t i = 0; i < HPET_NUM_TIMERS; i++)
    662                     if (pThis->aTimers[i].u64Cmp != hpetInvalidValue(&pThis->aTimers[i]))
    663                         hpetProgramTimer(&pThis->aTimers[i]);
    664             }
    665             else if (hpetBitJustCleared(iOldValue, iNewValue, HPET_CFG_ENABLE))
    666             {
    667                 /* Halt main counter and disable interrupt generation. */
    668                 pThis->u64HpetCounter = hpetGetTicks(pThis);
    669                 for (uint32_t i = 0; i < HPET_NUM_TIMERS; i++)
    670                     TMTimerStop(pThis->aTimers[i].CTX_SUFF(pTimer));
    671             }
    672             break;
    673         }
    674 
    675         case HPET_CFG + 4:
    676         {
    677             Log(("write HPET_CFG + 4: %x\n", iNewValue));
    678             pThis->u64HpetConfig = hpetUpdateMasked((uint64_t)iNewValue << 32,
    679                                                     pThis->u64HpetConfig,
    680                                                     UINT64_C(0xffffffff00000000));
    681             break;
    682         }
    683 
    684         case HPET_STATUS:
    685         {
    686             Log(("write HPET_STATUS: %x\n", iNewValue));
    687             // clear ISR for all set bits in iNewValue, see p. 14 of HPET spec
    688             pThis->u64Isr &= ~((uint64_t)iNewValue);
    689             break;
    690         }
    691 
    692         case HPET_STATUS + 4:
    693         {
    694             Log(("write HPET_STATUS + 4: %x\n", iNewValue));
    695             if (iNewValue != 0)
    696                 LogRel(("Writing HPET_STATUS + 4 with non-zero, ignored\n"));
    697             break;
    698         }
    699 
    700         case HPET_COUNTER:
    701         {
    702             pThis->u64HpetCounter = (pThis->u64HpetCounter & UINT64_C(0xffffffff00000000)) | iNewValue;
    703             Log(("write HPET_COUNTER: %#x -> %llx\n",
    704                  iNewValue, pThis->u64HpetCounter));
    705             break;
    706         }
    707 
    708         case HPET_COUNTER + 4:
    709         {
    710             pThis->u64HpetCounter = (pThis->u64HpetCounter & UINT64_C(0xffffffff))
    711                                   | (((uint64_t)iNewValue) << 32);
    712             Log(("write HPET_COUNTER + 4: %#x -> %llx\n",
    713                  iNewValue, pThis->u64HpetCounter));
    714             break;
    715         }
    716 
    717         default:
    718             LogRel(("invalid HPET config write: %x\n", iIndex));
    719             break;
    720     }
    721 
    722     return rc;
    723 }
    724 
    725 PDMBOTHCBDECL(int)  hpetMMIORead(PPDMDEVINS pDevIns,
    726                                  void *     pvUser,
    727                                  RTGCPHYS   GCPhysAddr,
    728                                  void *     pv,
    729                                  unsigned   cb)
    730 {
    731     HpetState * pThis  = PDMINS_2_DATA(pDevIns, HpetState*);
    732     int         rc     = VINF_SUCCESS;
    733     uint32_t    iIndex = (uint32_t)(GCPhysAddr - HPET_BASE);
    734 
    735     LogFlow(("hpetMMIORead (%d): %llx (%x)\n", cb, (uint64_t)GCPhysAddr, iIndex));
    736     DEVHPET_LOCK_RETURN(pThis, VINF_IOM_HC_MMIO_READ);
    737 
    738     switch (cb)
    739     {
    740         case 1:
    741         case 2:
    742             Log(("Narrow read: %d\n", cb));
    743             rc = VINF_SUCCESS;
    744             break;
    745         case 4:
    746         {
    747             if (iIndex >= 0x100 && iIndex < 0x400)
    748                 rc = hpetTimerRegRead32(pThis, (iIndex - 0x100) / 0x20, (iIndex - 0x100) % 0x20, (uint32_t*)pv);
    749             else
    750                 rc = hpetConfigRegRead32(pThis, iIndex, (uint32_t*)pv);
    751             break;
    752         }
    753         case 8:
    754         {
    755             union
    756             {
    757                 uint32_t u32[2];
    758                 uint64_t u64;
    759             } value;
    760 
    761             /* Unaligned accesses not allowed */
    762             if (iIndex % 8 != 0)
    763             {
    764                 AssertMsgFailed(("Unaligned HPET read access\n"));
    765                 rc = VINF_SUCCESS;
    766                 break;
    767             }
    768             if (iIndex >= 0x100 && iIndex < 0x400)
    769             {
    770                 uint32_t iTimer = (iIndex - 0x100) / 0x20;
    771                 uint32_t iTimerReg = (iIndex - 0x100) % 0x20;
    772 
    773                 /* for most 8-byte accesses we just split them, happens under lock anyway. */
    774                 rc = hpetTimerRegRead32(pThis, iTimer, iTimerReg, &value.u32[0]);
    775                 if (RT_UNLIKELY(rc != VINF_SUCCESS))
    776                     break;
    777                 rc = hpetTimerRegRead32(pThis, iTimer, iTimerReg + 4, &value.u32[1]);
    778             }
    779             else
    780             {
    781                 if (iIndex == HPET_COUNTER)
    782                 {
    783                     /* When reading HPET counter we must read it in a single read,
    784                        to avoid unexpected time jumps on 32-bit overflow. */
    785                     value.u64 = (pThis->u64HpetConfig & HPET_CFG_ENABLE) != 0
    786                               ? hpetGetTicks(pThis)
    787                               : pThis->u64HpetCounter;
    788                     rc = VINF_SUCCESS;
    789                 }
    790                 else
    791                 {
    792                     /* for most 8-byte accesses we just split them, happens under lock anyway. */
    793 
    794                     rc = hpetConfigRegRead32(pThis, iIndex, &value.u32[0]);
    795                     if (RT_UNLIKELY(rc != VINF_SUCCESS))
    796                         break;
    797                     rc = hpetConfigRegRead32(pThis, iIndex+4, &value.u32[1]);
    798                 }
    799             }
    800             if (rc == VINF_SUCCESS)
    801                 *(uint64_t*)pv = value.u64;
    802             break;
    803         }
    804 
    805         default:
    806             AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */
    807             rc = VINF_SUCCESS;
    808     }
    809 
    810     DEVHPET_UNLOCK(pThis);
    811     return rc;
    812 }
    813 
    814 PDMBOTHCBDECL(int) hpetMMIOWrite(PPDMDEVINS pDevIns,
    815                                  void  *    pvUser,
    816                                  RTGCPHYS   GCPhysAddr,
    817                                  void *     pv,
    818                                  unsigned   cb)
    819 {
    820     HpetState  *pThis  = PDMINS_2_DATA(pDevIns, HpetState*);
    821     uint32_t    iIndex = (uint32_t)(GCPhysAddr - HPET_BASE);
    822     int         rc     = VINF_SUCCESS;
    823 
    824     LogFlow(("hpetMMIOWrite (%d): %llx (%x) <- %x\n",
    825              cb, (uint64_t)GCPhysAddr, iIndex, cb >= 4 ? *(uint32_t*)pv : 0xdeadbeef));
    826 
    827     DEVHPET_LOCK_RETURN(pThis, VINF_IOM_HC_MMIO_WRITE);
    828 
    829     switch (cb)
    830     {
    831         case 1:
    832         case 2:
    833             Log(("Narrow write: %d\n", cb));
    834             rc = VINF_SUCCESS;
    835             break;
    836         case 4:
    837         {
    838             if (iIndex >= 0x100 && iIndex < 0x400)
    839                 rc = hpetTimerRegWrite32(pThis,
    840                                          (iIndex - 0x100) / 0x20,
    841                                          (iIndex - 0x100) % 0x20,
    842                                          *(uint32_t*)pv);
    843             else
    844                 rc = hpetConfigRegWrite32(pThis, iIndex, *(uint32_t*)pv);
    845             break;
    846         }
    847 
    848         case 8:
    849         {
    850             /* Unaligned accesses not allowed */
    851             if (iIndex % 8 != 0)
    852             {
    853                 AssertMsgFailed(("Unaligned HPET write access\n"));
    854                 rc = VINF_SUCCESS;
    855                 break;
    856             }
    857 
    858 
    859             // for 8-byte accesses we just split them, happens under lock anyway
    860             union
    861             {
    862                 uint32_t u32[2];
    863                 uint64_t u64;
    864             } value;
    865             value.u64 = *(uint64_t*)pv;
    866             if (iIndex >= 0x100 && iIndex < 0x400)
    867             {
    868                 uint32_t iTimer = (iIndex - 0x100) / 0x20;
    869                 uint32_t iTimerReg = (iIndex - 0x100) % 0x20;
    870 
    871                 rc = hpetTimerRegWrite32(pThis, iTimer, iTimerReg, value.u32[0]);
    872                 if (RT_LIKELY(rc == VINF_SUCCESS))
    873                     rc = hpetTimerRegWrite32(pThis, iTimer, iTimerReg + 4, value.u32[1]);
    874             }
    875             else
    876             {
    877                 rc = hpetConfigRegWrite32(pThis, iIndex, value.u32[0]);
    878                 if (RT_LIKELY(rc == VINF_SUCCESS))
    879                     rc = hpetConfigRegWrite32(pThis, iIndex+4, value.u32[1]);
    880             }
    881             break;
    882         }
    883 
    884         default:
    885             AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */
    886             rc = VERR_INTERNAL_ERROR;
    887             break;
    888     }
    889 
    890     DEVHPET_UNLOCK(pThis);
    891     return rc;
    892 }
    893 
    894 #ifdef IN_RING3
    895 
    896 /** @todo move the saved state stuff down before the timer.  */
    897 
    898 static int hpetSaveTimer(HpetTimer *pHpetTimer, PSSMHANDLE pSSM)
    899 {
    900     TMR3TimerSave(pHpetTimer->pTimerR3, pSSM);
    901     SSMR3PutU8(pSSM,  pHpetTimer->u8Wrap);
    902     SSMR3PutU64(pSSM, pHpetTimer->u64Config);
    903     SSMR3PutU64(pSSM, pHpetTimer->u64Cmp);
    904     SSMR3PutU64(pSSM, pHpetTimer->u64Fsb);
    905     return SSMR3PutU64(pSSM, pHpetTimer->u64Period);
    906 }
    907 
    908 static int hpetLoadTimer(HpetTimer *pHpetTimer, PSSMHANDLE pSSM)
    909 {
    910     TMR3TimerLoad(pHpetTimer->pTimerR3, pSSM);
    911     SSMR3GetU8(pSSM,  &pHpetTimer->u8Wrap);
    912     SSMR3GetU64(pSSM, &pHpetTimer->u64Config);
    913     SSMR3GetU64(pSSM, &pHpetTimer->u64Cmp);
    914     SSMR3GetU64(pSSM, &pHpetTimer->u64Fsb);
    915     return SSMR3GetU64(pSSM, &pHpetTimer->u64Period);
    916 }
    917 
    918 /**
    919  * @copydoc FNSSMDEVLIVEEXEC
    920  */
    921 static DECLCALLBACK(int) hpetLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
    922 {
    923     HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
    924 
    925     SSMR3PutU8(pSSM, HPET_NUM_TIMERS);
    926 
    927     return VINF_SSM_DONT_CALL_AGAIN;
    928 }
    929 
    930 /**
    931  * Saves a state of the HPET device.
     937
     938/**
     939 * Used by hpetTimerCb to update the IRQ status.
    932940 *
    933  * @returns VBox status code.
    934  * @param   pDevIns     The device instance.
    935  * @param   pSSMHandle  The handle to save the state to.
    936  */
    937 static DECLCALLBACK(int) hpetSaveExec(PPDMDEVINS pDevIns,
    938                                       PSSMHANDLE pSSM)
    939 {
    940     HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
    941     uint32_t   iTimer;
    942     int        rc;
    943 
    944     /* The config. */
    945     hpetLiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
    946 
    947     for (iTimer = 0; iTimer < HPET_NUM_TIMERS; iTimer++)
    948     {
    949         rc = hpetSaveTimer(&pThis->aTimers[iTimer], pSSM);
    950         AssertRCReturn(rc, rc);
    951     }
    952 
    953     SSMR3PutU64(pSSM, pThis->u64HpetOffset);
    954     SSMR3PutU64(pSSM, pThis->u64Capabilities);
    955     SSMR3PutU64(pSSM, pThis->u64HpetConfig);
    956     SSMR3PutU64(pSSM, pThis->u64Isr);
    957     SSMR3PutU64(pSSM, pThis->u64HpetCounter);
    958 
    959     return VINF_SUCCESS;
    960 }
    961 
    962 /**
    963  * Loads a HPET device state.
    964  *
    965  * @returns VBox status code.
    966  * @param   pDevIns     The device instance.
    967  * @param   pSSMHandle  The handle to the saved state.
    968  * @param   uVersion    The data unit version number.
    969  * @param   uPass           The data pass.
    970  */
    971 static DECLCALLBACK(int) hpetLoadExec(PPDMDEVINS pDevIns,
    972                                       PSSMHANDLE pSSM,
    973                                       uint32_t   uVersion,
    974                                       uint32_t   uPass)
    975 {
    976     HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
    977 
    978     if (uVersion == HPET_SAVED_STATE_VERSION_EMPTY)
    979         return VINF_SUCCESS;
    980 
    981     if (uVersion != HPET_SAVED_STATE_VERSION)
    982         return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
    983 
    984     uint8_t u8NumTimers;
    985 
    986     int rc = SSMR3GetU8(pSSM, &u8NumTimers);
    987     AssertRCReturn(rc, rc);
    988     if (u8NumTimers != HPET_NUM_TIMERS)
    989         return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - wrong number of timers: saved=%#x config=%#x"), u8NumTimers, HPET_NUM_TIMERS);
    990 
    991     if (uPass != SSM_PASS_FINAL)
    992         return VINF_SUCCESS;
    993 
    994     for (uint32_t iTimer = 0; iTimer < HPET_NUM_TIMERS; iTimer++)
    995     {
    996         rc = hpetLoadTimer(&pThis->aTimers[iTimer], pSSM);
    997         AssertRCReturn(rc, rc);
    998     }
    999 
    1000     SSMR3GetU64(pSSM, &pThis->u64HpetOffset);
    1001     SSMR3GetU64(pSSM, &pThis->u64Capabilities);
    1002     SSMR3GetU64(pSSM, &pThis->u64HpetConfig);
    1003     SSMR3GetU64(pSSM, &pThis->u64Isr);
    1004     SSMR3GetU64(pSSM, &pThis->u64HpetCounter);
    1005 
    1006     return VINF_SUCCESS;
    1007 }
    1008 
    1009 static void hpetIrqUpdate(struct HpetTimer *pHpetTimer)
    1010 {
    1011     uint32_t   irq   = getTimerIrq(pHpetTimer);
    1012     HpetState *pThis = pHpetTimer->CTX_SUFF(pHpet);
    1013 
     941 * @param   pThis               The HPET device state.
     942 * @param   pHpetTimer          The HPET timer.
     943 */
     944static void hpetTimerCbUpdateIrq(HpetState *pThis, struct HpetTimer *pHpetTimer)
     945{
    1014946    /** @todo: is it correct? */
    1015947    if (   !!(pHpetTimer->u64Config & HPET_TN_ENABLE)
    1016948        && !!(pThis->u64HpetConfig & HPET_CFG_ENABLE))
    1017949    {
     950        uint32_t irq = hpetTimerCbGetIrq(pHpetTimer);
    1018951        Log4(("HPET: raising IRQ %d\n", irq));
    1019952
    1020         /* ISR bits are only set in level-triggered mode */
     953        /* ISR bits are only set in level-triggered mode. */
    1021954        if ((pHpetTimer->u64Config & HPET_TN_INT_TYPE) == HPET_TIMER_TYPE_LEVEL)
    1022955            pThis->u64Isr |= (uint64_t)(1 << pHpetTimer->idxTimer);
    1023956
    1024         /* We trigger flip/flop in edge-triggered mode and do nothing in level-triggered mode yet */
     957        /* We trigger flip/flop in edge-triggered mode and do nothing in
     958           level-triggered mode yet. */
    1025959        if ((pHpetTimer->u64Config & HPET_TN_INT_TYPE) == HPET_TIMER_TYPE_EDGE)
    1026960            pThis->pHpetHlpR3->pfnSetIrq(pThis->CTX_SUFF(pDevIns), irq, PDM_IRQ_LEVEL_FLIP_FLOP);
    1027961        else
    1028962            AssertFailed();
    1029         /* @todo: implement IRQs in level-triggered mode */
     963        /** @todo: implement IRQs in level-triggered mode */
    1030964    }
    1031965}
     
    1038972 * @param   pvUser          Pointer to the HPET timer state.
    1039973 */
    1040 static DECLCALLBACK(void) hpetTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
     974static DECLCALLBACK(void) hpetTimerCb(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
    1041975{
    1042976    HpetState *pThis      = PDMINS_2_DATA(pDevIns, HpetState *);
     
    10711005
    10721006    /* Should it really be under lock, does it really matter? */
    1073     hpetIrqUpdate(pHpetTimer);
     1007    hpetTimerCbUpdateIrq(pThis, pHpetTimer);
    10741008
    10751009    PDMCritSectLeave(&pThis->csLock);
    10761010}
    10771011
    1078 /**
    1079  * Relocation notification.
    1080  *
    1081  * @returns VBox status.
    1082  * @param   pDevIns     The device instance data.
    1083  * @param   offDelta    The delta relative to the old address.
     1012
     1013/* -=-=-=-=-=- DBGF Info Handlers -=-=-=-=-=- */
     1014
     1015
     1016/**
     1017 * @callback_method_impl{FNDBGFHANDLERDEV}
     1018 */
     1019static DECLCALLBACK(void) hpetInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
     1020{
     1021    HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
     1022
     1023    pHlp->pfnPrintf(pHlp,
     1024                    "HPET status:\n"
     1025                    " config = %016RX64\n"
     1026                    " offset = %016RX64 counter = %016RX64 isr = %016RX64\n"
     1027                    " legacy mode is %s\n",
     1028                    pThis->u64HpetConfig,
     1029                    pThis->u64HpetOffset, pThis->u64HpetCounter, pThis->u64Isr,
     1030                    !!(pThis->u64HpetConfig & HPET_CFG_LEGACY) ? "on" : "off");
     1031    pHlp->pfnPrintf(pHlp,
     1032                    "Timers:\n");
     1033    for (unsigned i = 0; i < HPET_NUM_TIMERS; i++)
     1034    {
     1035        pHlp->pfnPrintf(pHlp, " %d: comparator=%016RX64 period(hidden)=%016RX64 cfg=%016RX64\n",
     1036                        pThis->aTimers[i].idxTimer,
     1037                        pThis->aTimers[i].u64Cmp,
     1038                        pThis->aTimers[i].u64Period,
     1039                        pThis->aTimers[i].u64Config);
     1040    }
     1041}
     1042
     1043
     1044/* -=-=-=-=-=- Saved State -=-=-=-=-=- */
     1045
     1046
     1047/**
     1048 * @callback_method_impl{FNSSMDEVLIVEEXEC}
     1049 */
     1050static DECLCALLBACK(int) hpetLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
     1051{
     1052    HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
     1053
     1054    SSMR3PutU8(pSSM, HPET_NUM_TIMERS);
     1055
     1056    return VINF_SSM_DONT_CALL_AGAIN;
     1057}
     1058
     1059
     1060/**
     1061 * @callback_method_impl{FNSSMDEVSAVEEXEC}
     1062 */
     1063static DECLCALLBACK(int) hpetSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
     1064{
     1065    HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
     1066
     1067    /*
     1068     * The config.
     1069     */
     1070    hpetLiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
     1071
     1072    /*
     1073     * The state.
     1074     */
     1075    for (uint32_t iTimer = 0; iTimer < HPET_NUM_TIMERS; iTimer++)
     1076    {
     1077        HpetTimer *pHpetTimer = &pThis->aTimers[iTimer];
     1078        TMR3TimerSave(pHpetTimer->pTimerR3, pSSM);
     1079        SSMR3PutU8(pSSM,  pHpetTimer->u8Wrap);
     1080        SSMR3PutU64(pSSM, pHpetTimer->u64Config);
     1081        SSMR3PutU64(pSSM, pHpetTimer->u64Cmp);
     1082        SSMR3PutU64(pSSM, pHpetTimer->u64Fsb);
     1083        SSMR3PutU64(pSSM, pHpetTimer->u64Period);
     1084    }
     1085
     1086    SSMR3PutU64(pSSM, pThis->u64HpetOffset);
     1087    SSMR3PutU64(pSSM, pThis->u64Capabilities);
     1088    SSMR3PutU64(pSSM, pThis->u64HpetConfig);
     1089    SSMR3PutU64(pSSM, pThis->u64Isr);
     1090    return SSMR3PutU64(pSSM, pThis->u64HpetCounter);
     1091}
     1092
     1093
     1094/**
     1095 * @callback_method_impl{FNSSMDEVLOADEXEC}
     1096 */
     1097static DECLCALLBACK(int) hpetLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
     1098{
     1099    HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
     1100
     1101    /*
     1102     * Version checks.
     1103     */
     1104    if (uVersion == HPET_SAVED_STATE_VERSION_EMPTY)
     1105        return VINF_SUCCESS;
     1106    if (uVersion != HPET_SAVED_STATE_VERSION)
     1107        return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
     1108
     1109    /*
     1110     * The config.
     1111     */
     1112    uint8_t cTimers;
     1113    int rc = SSMR3GetU8(pSSM, &cTimers);
     1114    AssertRCReturn(rc, rc);
     1115    if (cTimers != HPET_NUM_TIMERS)
     1116        return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - wrong number of timers: saved=%#x config=%#x"),
     1117                                cTimers, HPET_NUM_TIMERS);
     1118
     1119    if (uPass != SSM_PASS_FINAL)
     1120        return VINF_SUCCESS;
     1121
     1122    /*
     1123     * The state.
     1124     */
     1125    for (uint32_t iTimer = 0; iTimer < HPET_NUM_TIMERS; iTimer++)
     1126    {
     1127        HpetTimer *pHpetTimer = &pThis->aTimers[iTimer];
     1128        TMR3TimerLoad(pHpetTimer->pTimerR3, pSSM);
     1129        SSMR3GetU8(pSSM,  &pHpetTimer->u8Wrap);
     1130        SSMR3GetU64(pSSM, &pHpetTimer->u64Config);
     1131        SSMR3GetU64(pSSM, &pHpetTimer->u64Cmp);
     1132        SSMR3GetU64(pSSM, &pHpetTimer->u64Fsb);
     1133        SSMR3GetU64(pSSM, &pHpetTimer->u64Period);
     1134    }
     1135
     1136    SSMR3GetU64(pSSM, &pThis->u64HpetOffset);
     1137    SSMR3GetU64(pSSM, &pThis->u64Capabilities);
     1138    SSMR3GetU64(pSSM, &pThis->u64HpetConfig);
     1139    SSMR3GetU64(pSSM, &pThis->u64Isr);
     1140    return SSMR3GetU64(pSSM, &pThis->u64HpetCounter);
     1141}
     1142
     1143
     1144/* -=-=-=-=-=- PDMDEVREG -=-=-=-=-=- */
     1145
     1146
     1147/**
     1148 * @interface_method_impl{PDMDEVREG,pfnRelocate}
    10841149 */
    10851150static DECLCALLBACK(void) hpetRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
     
    11001165}
    11011166
    1102 /**
    1103  * Reset notification.
    1104  *
    1105  * @returns VBox status.
    1106  * @param   pDevIns     The device instance data.
     1167
     1168/**
     1169 * @interface_method_impl{PDMDEVREG,pfnReset}
    11071170 */
    11081171static DECLCALLBACK(void) hpetReset(PPDMDEVINS pDevIns)
     
    11311194        pHpetTimer->u8Wrap     = 0;
    11321195        pHpetTimer->u64Cmp     = hpetInvalidValue(pHpetTimer);
     1196        /** @todo shouldn't we stop any active timers at this point? */
    11331197    }
    11341198    pThis->u64HpetCounter = 0;
     
    11481212
    11491213    /* Notify PIT/RTC devices */
    1150     hpetLegacyMode(pThis, false);
    1151 }
    1152 
    1153 /**
    1154  * Info handler, device version.
    1155  *
    1156  * @param   pDevIns     Device instance which registered the info.
    1157  * @param   pHlp        Callback functions for doing output.
    1158  * @param   pszArgs     Argument string. Optional and specific to the handler.
    1159  */
    1160 static DECLCALLBACK(void) hpetInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
    1161 {
    1162     HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
    1163 
    1164     pHlp->pfnPrintf(pHlp,
    1165                     "HPET status:\n"
    1166                     " config = %016RX64\n"
    1167                     " offset = %016RX64 counter = %016RX64 isr = %016RX64\n"
    1168                     " legacy mode is %s\n",
    1169                     pThis->u64HpetConfig,
    1170                     pThis->u64HpetOffset, pThis->u64HpetCounter, pThis->u64Isr,
    1171                     !!(pThis->u64HpetConfig & HPET_CFG_LEGACY) ? "on" : "off");
    1172     pHlp->pfnPrintf(pHlp,
    1173                     "Timers:\n");
    1174     for (unsigned i = 0; i < HPET_NUM_TIMERS; i++)
    1175     {
    1176         pHlp->pfnPrintf(pHlp, " %d: comparator=%016RX64 period(hidden)=%016RX64 cfg=%016RX64\n",
    1177                         pThis->aTimers[i].idxTimer,
    1178                         pThis->aTimers[i].u64Cmp,
    1179                         pThis->aTimers[i].u64Period,
    1180                         pThis->aTimers[i].u64Config);
    1181     }
     1214    if (pThis->pHpetHlpR3)
     1215        pThis->pHpetHlpR3->pfnSetLegacyMode(pDevIns, false /*fActive*/);
    11821216}
    11831217
     
    11881222static DECLCALLBACK(int) hpetConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
    11891223{
     1224    PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
    11901225    HpetState   *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
    1191     int          rc;
    11921226
    11931227    /* Only one HPET device now, as we use fixed MMIO region. */
     
    11951229
    11961230    /*
    1197      * Validate configuration.
     1231     * Validate and read the configuration.
    11981232     */
    1199     if (!CFGMR3AreValuesValid(pCfg,
    1200                               "GCEnabled\0"
    1201                               "R0Enabled\0"
    1202                               "ICH9\0"))
    1203         return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
    1204 
    1205     /* Query configuration. */
     1233    PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "GCEnabled|R0Enabled|ICH9", "");
     1234
    12061235    bool fRCEnabled;
    1207     rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fRCEnabled, true);
     1236    int rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fRCEnabled, true);
    12081237    if (RT_FAILURE(rc))
    12091238        return PDMDEV_SET_ERROR(pDevIns, rc,
     
    12161245                                N_("Configuration error: failed to read R0Enabled as boolean"));
    12171246
    1218     bool fIch9;
    1219     rc = CFGMR3QueryBoolDef(pCfg, "ICH9", &fIch9, false);
     1247    rc = CFGMR3QueryBoolDef(pCfg, "ICH9", &pThis->fIch9, false);
    12201248    if (RT_FAILURE(rc))
    12211249        return PDMDEV_SET_ERROR(pDevIns, rc,
     
    12281256    pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
    12291257    pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
    1230     pThis->fIch9     = (uint8_t)fIch9;
    12311258
    12321259    rc = PDMDevHlpCritSectInit(pDevIns, &pThis->csLock, RT_SRC_POS, "HPET#%u", pDevIns->iInstance);
    12331260    AssertRCReturn(rc, rc);
    12341261
    1235     /* Init timers. */
     1262    /* Init the HPET timers. */
    12361263    for (unsigned i = 0; i < HPET_NUM_TIMERS; i++)
    12371264    {
     
    12431270        pHpetTimer->pHpetRC  = PDMINS_2_DATA_RCPTR(pDevIns);
    12441271
    1245         rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, hpetTimer, pHpetTimer,
    1246                                         TMTIMER_FLAGS_NO_CRIT_SECT, "HPET Timer",
    1247                                         &pThis->aTimers[i].pTimerR3);
     1272        rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, hpetTimerCb, pHpetTimer,
     1273                                    TMTIMER_FLAGS_NO_CRIT_SECT, "HPET Timer",
     1274                                    &pThis->aTimers[i].pTimerR3);
    12481275        AssertRCReturn(rc, rc);
    12491276        pThis->aTimers[i].pTimerRC = TMTimerRCPtr(pThis->aTimers[i].pTimerR3);
     
    12521279    }
    12531280
     1281    /* This must be done prior to registering the HPET, right? */
    12541282    hpetReset(pDevIns);
    12551283
     
    12941322    AssertRCReturn(rc, rc);
    12951323
    1296     /**
    1297      * @todo Register statistics.
    1298      */
     1324    /* Register an info callback. */
    12991325    PDMDevHlpDBGFInfoRegister(pDevIns, "hpet", "Display HPET status. (no arguments)", hpetInfo);
    13001326
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