Ejemplo n.º 1
0
static void hpetProgramTimer(HpetTimer *pHpetTimer)
{
    /* no wrapping on new timers */
    pHpetTimer->u8Wrap = 0;

    uint64_t u64Ticks = hpetGetTicks(pHpetTimer->CTX_SUFF(pHpet));
    hpetAdjustComparator(pHpetTimer, u64Ticks);

    uint64_t u64Diff = hpetComputeDiff(pHpetTimer, u64Ticks);

    /*
     * HPET spec says in one-shot 32-bit mode, generate an interrupt when
     * counter wraps in addition to an interrupt with comparator match.
     */
    if (    hpet32bitTimer(pHpetTimer)
        && !(pHpetTimer->u64Config & HPET_TN_PERIODIC))
    {
        uint32_t u32TillWrap = 0xffffffff - (uint32_t)u64Ticks + 1;
        if (u32TillWrap < (uint32_t)u64Diff)
        {
            Log(("wrap on timer %d: till=%u ticks=%lld diff64=%lld\n",
                 pHpetTimer->idxTimer, u32TillWrap, u64Ticks, u64Diff));
            u64Diff = u32TillWrap;
            pHpetTimer->u8Wrap = 1;
        }
    }

    /*
     * HACK ALERT! Avoid killing VM with interrupts.
     */
#if 1 /** @todo: HACK, rethink, may have negative impact on the guest */
    if (u64Diff == 0)
        u64Diff = 100000; /* 1 millisecond */
#endif

    Log4(("HPET: next IRQ in %lld ticks (%lld ns)\n", u64Diff, hpetTicksToNs(pHpetTimer->CTX_SUFF(pHpet), u64Diff)));
    TMTimerSetNano(pHpetTimer->CTX_SUFF(pTimer), hpetTicksToNs(pHpetTimer->CTX_SUFF(pHpet), u64Diff));
    hpetTimerSetFrequencyHint(pHpetTimer->CTX_SUFF(pHpet), pHpetTimer);
}
Ejemplo n.º 2
0
/**
 * 32-bit write to a config register.
 *
 * @returns Strict VBox status code.
 *
 * @param   pThis           The HPET state.
 * @param   idxReg          The register being written to.
 * @param   u32NewValue     The value being written.
 *
 * @remarks The caller should not hold the device lock, unless it also holds
 *          the TM lock.
 */
static int hpetConfigRegWrite32(HPET *pThis, uint32_t idxReg, uint32_t u32NewValue)
{
    Assert(!PDMCritSectIsOwner(&pThis->CritSect) || TMTimerIsLockOwner(pThis->aTimers[0].CTX_SUFF(pTimer)));

    int rc = VINF_SUCCESS;
    switch (idxReg)
    {
        case HPET_ID:
        case HPET_ID + 4:
        {
            Log(("write HPET_ID, useless\n"));
            break;
        }

        case HPET_CFG:
        {
            DEVHPET_LOCK_BOTH_RETURN(pThis, VINF_IOM_R3_MMIO_WRITE);
            uint32_t const iOldValue = (uint32_t)(pThis->u64HpetConfig);
            Log(("write HPET_CFG: %x (old %x)\n", u32NewValue, iOldValue));

            /*
             * This check must be here, before actual update, as hpetLegacyMode
             * may request retry in R3 - so we must keep state intact.
             */
            if (   ((iOldValue ^ u32NewValue) & HPET_CFG_LEGACY)
                && pThis->pHpetHlpR3 != NIL_RTR3PTR)
            {
#ifdef IN_RING3
                rc = pThis->pHpetHlpR3->pfnSetLegacyMode(pThis->pDevInsR3, RT_BOOL(u32NewValue & HPET_CFG_LEGACY));
                if (rc != VINF_SUCCESS)
#else
                rc = VINF_IOM_R3_MMIO_WRITE;
#endif
                {
                    DEVHPET_UNLOCK_BOTH(pThis);
                    break;
                }
            }

            pThis->u64HpetConfig = hpetUpdateMasked(u32NewValue, iOldValue, HPET_CFG_WRITE_MASK);

            uint32_t const cTimers = HPET_CAP_GET_TIMERS(pThis->u32Capabilities);
            if (hpetBitJustSet(iOldValue, u32NewValue, HPET_CFG_ENABLE))
            {
/** @todo Only get the time stamp once when reprogramming? */
                /* Enable main counter and interrupt generation. */
                pThis->u64HpetOffset = hpetTicksToNs(pThis, pThis->u64HpetCounter)
                                     - TMTimerGet(pThis->aTimers[0].CTX_SUFF(pTimer));
                for (uint32_t i = 0; i < cTimers; i++)
                    if (pThis->aTimers[i].u64Cmp != hpetInvalidValue(&pThis->aTimers[i]))
                        hpetProgramTimer(&pThis->aTimers[i]);
            }
            else if (hpetBitJustCleared(iOldValue, u32NewValue, HPET_CFG_ENABLE))
            {
                /* Halt main counter and disable interrupt generation. */
                pThis->u64HpetCounter = hpetGetTicks(pThis);
                for (uint32_t i = 0; i < cTimers; i++)
                    TMTimerStop(pThis->aTimers[i].CTX_SUFF(pTimer));
            }

            DEVHPET_UNLOCK_BOTH(pThis);
            break;
        }

        case HPET_CFG + 4:
        {
            DEVHPET_LOCK_RETURN(pThis, VINF_IOM_R3_MMIO_WRITE);
            pThis->u64HpetConfig = hpetUpdateMasked((uint64_t)u32NewValue << 32,
                                                    pThis->u64HpetConfig,
                                                    UINT64_C(0xffffffff00000000));
            Log(("write HPET_CFG + 4: %x -> %#llx\n", u32NewValue, pThis->u64HpetConfig));
            DEVHPET_UNLOCK(pThis);
            break;
        }

        case HPET_STATUS:
        {
            DEVHPET_LOCK_RETURN(pThis, VINF_IOM_R3_MMIO_WRITE);
            /* Clear ISR for all set bits in u32NewValue, see p. 14 of the HPET spec. */
            pThis->u64Isr &= ~((uint64_t)u32NewValue);
            Log(("write HPET_STATUS: %x -> ISR=%#llx\n", u32NewValue, pThis->u64Isr));
            DEVHPET_UNLOCK(pThis);
            break;
        }

        case HPET_STATUS + 4:
        {
            Log(("write HPET_STATUS + 4: %x\n", u32NewValue));
            if (u32NewValue != 0)
            {
                static unsigned s_cOccurrences = 0;
                if (s_cOccurrences++ < 10)
                    LogRel(("Writing HPET_STATUS + 4 with non-zero, ignored\n"));
            }
            break;
        }

        case HPET_COUNTER:
        {
            DEVHPET_LOCK_RETURN(pThis, VINF_IOM_R3_MMIO_WRITE);
            pThis->u64HpetCounter = RT_MAKE_U64(u32NewValue, RT_HI_U32(pThis->u64HpetCounter));
            Log(("write HPET_COUNTER: %#x -> %llx\n", u32NewValue, pThis->u64HpetCounter));
            DEVHPET_UNLOCK(pThis);
            break;
        }

        case HPET_COUNTER + 4:
        {
            DEVHPET_LOCK_RETURN(pThis, VINF_IOM_R3_MMIO_WRITE);
            pThis->u64HpetCounter = RT_MAKE_U64(RT_LO_U32(pThis->u64HpetCounter), u32NewValue);
            Log(("write HPET_COUNTER + 4: %#x -> %llx\n", u32NewValue, pThis->u64HpetCounter));
            DEVHPET_UNLOCK(pThis);
            break;
        }

        default:
        {
            static unsigned s_cOccurences = 0;
            if (s_cOccurences++ < 10)
                LogRel(("invalid HPET config write: %x\n", idxReg));
            break;
        }
    }

    return rc;
}
Ejemplo n.º 3
0
/**
 * Read a 32-bit HPET register.
 *
 * @returns Strict VBox status code.
 * @param   pThis               The HPET state.
 * @param   idxReg              The register to read.
 * @param   pu32Value           Where to return the register value.
 *
 * @remarks The caller must not own the device lock if HPET_COUNTER is read.
 */
static int hpetConfigRegRead32(HPET *pThis, uint32_t idxReg, uint32_t *pu32Value)
{
    Assert(!PDMCritSectIsOwner(&pThis->CritSect) || (idxReg != HPET_COUNTER && idxReg != HPET_COUNTER + 4));

    uint32_t u32Value;
    switch (idxReg)
    {
        case HPET_ID:
            DEVHPET_LOCK_RETURN(pThis, VINF_IOM_R3_MMIO_READ);
            u32Value = pThis->u32Capabilities;
            DEVHPET_UNLOCK(pThis);
            Log(("read HPET_ID: %#x\n", u32Value));
            break;

        case HPET_PERIOD:
            DEVHPET_LOCK_RETURN(pThis, VINF_IOM_R3_MMIO_READ);
            u32Value = pThis->u32Period;
            DEVHPET_UNLOCK(pThis);
            Log(("read HPET_PERIOD: %#x\n", u32Value));
            break;

        case HPET_CFG:
            DEVHPET_LOCK_RETURN(pThis, VINF_IOM_R3_MMIO_READ);
            u32Value = (uint32_t)pThis->u64HpetConfig;
            DEVHPET_UNLOCK(pThis);
            Log(("read HPET_CFG: %#x\n", u32Value));
            break;

        case HPET_CFG + 4:
            DEVHPET_LOCK_RETURN(pThis, VINF_IOM_R3_MMIO_READ);
            u32Value = (uint32_t)(pThis->u64HpetConfig >> 32);
            DEVHPET_UNLOCK(pThis);
            Log(("read of HPET_CFG + 4: %#x\n", u32Value));
            break;

        case HPET_COUNTER:
        case HPET_COUNTER + 4:
        {
            DEVHPET_LOCK_BOTH_RETURN(pThis, VINF_IOM_R3_MMIO_READ);

            uint64_t u64Ticks;
            if (pThis->u64HpetConfig & HPET_CFG_ENABLE)
                u64Ticks = hpetGetTicks(pThis);
            else
                u64Ticks = pThis->u64HpetCounter;

            DEVHPET_UNLOCK_BOTH(pThis);

            /** @todo is it correct? */
            u32Value = (idxReg == HPET_COUNTER) ? (uint32_t)u64Ticks : (uint32_t)(u64Ticks >> 32);
            Log(("read HPET_COUNTER: %s part value %x (%#llx)\n",
                 (idxReg == HPET_COUNTER) ? "low" : "high", u32Value, u64Ticks));
            break;
        }

        case HPET_STATUS:
            DEVHPET_LOCK_RETURN(pThis, VINF_IOM_R3_MMIO_READ);
            u32Value = (uint32_t)pThis->u64Isr;
            DEVHPET_UNLOCK(pThis);
            Log(("read HPET_STATUS: %#x\n", u32Value));
            break;

        default:
            Log(("invalid HPET register read: %x\n", idxReg));
            u32Value = 0;
            break;
    }

    *pu32Value = u32Value;
    return VINF_SUCCESS;
}