/**
 * @interface_method_impl{PDMINETWORKUP,pfnSendBuf}
 */
PDMBOTHCBDECL(int) drvDedicatedNicUp_SendBuf(PPDMINETWORKUP pInterface, PPDMSCATTERGATHER pSgBuf, bool fOnWorkerThread)
{
    PDRVDEDICATEDNIC  pThis = RT_FROM_MEMBER(pInterface, DRVDEDICATEDNIC, CTX_SUFF(INetworkUp));
    STAM_PROFILE_START(&pThis->StatTransmit, a);

    AssertPtr(pSgBuf);
    Assert(pSgBuf->fFlags == (PDMSCATTERGATHER_FLAGS_MAGIC | PDMSCATTERGATHER_FLAGS_OWNER_1));
    Assert(pSgBuf->cbUsed <= pSgBuf->cbAvailable);
#ifdef IN_RING0
    Assert(pSgBuf == &pThis->XmitSg);
#endif
    Assert(PDMCritSectIsOwner(&pThis->XmitLock));

#ifdef IN_RING0
    /*
     * Tell the driver to send the packet.
     */

    return VERR_INTERNAL_ERROR_4;

#else  /* IN_RING3 */
    /*
     * Call ring-0 to start the transfer.
     */
    int rc = PDMDrvHlpCallR0(pThis->pDrvInsR3, DRVDEDICATEDNICR0OP_SEND, pSgBuf->cbUsed);
    if (RT_FAILURE(rc) && rc != VERR_NET_DOWN)
        rc = VERR_NET_NO_BUFFER_SPACE;
    pSgBuf->fFlags = 0;
    return rc;
#endif /* IN_RING3 */
}
/**
 * Check if this VCPU currently owns the IOM lock exclusively.
 *
 * @returns bool owner/not owner
 * @param   pVM         Pointer to the VM.
 */
VMMDECL(bool) IOMIsLockWriteOwner(PVM pVM)
{
#ifdef IOM_WITH_CRIT_SECT_RW
    return PDMCritSectRwIsInitialized(&pVM->iom.s.CritSect)
        && PDMCritSectRwIsWriteOwner(&pVM->iom.s.CritSect);
#else
    return PDMCritSectIsOwner(&pVM->iom.s.CritSect);
#endif
}
Exemple #3
0
/**
 * Reads a HPET timer register.
 *
 * @returns VBox strict status code.
 * @param   pThis               The HPET instance.
 * @param   iTimerNo            The timer index.
 * @param   iTimerReg           The index of the timer register to read.
 * @param   pu32Value           Where to return the register value.
 *
 * @remarks ASSUMES the caller does holds the HPET lock.
 */
static int hpetTimerRegRead32(HpetState const *pThis, uint32_t iTimerNo, uint32_t iTimerReg, uint32_t *pu32Value)
{
    Assert(PDMCritSectIsOwner(&pThis->csLock));

    if (   iTimerNo >= RT_ELEMENTS(pThis->aTimers) /* parfait */
        || iTimerNo >= HPET_CAP_GET_TIMERS(pThis->u32Capabilities))
    {
        static unsigned s_cOccurences = 0;
        if (s_cOccurences++ < 10)
            LogRel(("HPET: using timer above configured range: %d\n", iTimerNo));
        *pu32Value = 0;
        return VINF_SUCCESS;
    }

    HpetTimer const *pHpetTimer = &pThis->aTimers[iTimerNo];
    uint32_t u32Value;
    switch (iTimerReg)
    {
        case HPET_TN_CFG:
            u32Value = (uint32_t)pHpetTimer->u64Config;
            Log(("read HPET_TN_CFG on %d: %#x\n", iTimerNo, u32Value));
            break;

        case HPET_TN_CFG + 4:
            u32Value = (uint32_t)(pHpetTimer->u64Config >> 32);
            Log(("read HPET_TN_CFG+4 on %d: %#x\n", iTimerNo, u32Value));
            break;

        case HPET_TN_CMP:
            u32Value = (uint32_t)pHpetTimer->u64Cmp;
            Log(("read HPET_TN_CMP on %d: %#x (%#llx)\n", pHpetTimer->idxTimer, u32Value, pHpetTimer->u64Cmp));
            break;

        case HPET_TN_CMP + 4:
            u32Value = (uint32_t)(pHpetTimer->u64Cmp >> 32);
            Log(("read HPET_TN_CMP+4 on %d: %#x (%#llx)\n", pHpetTimer->idxTimer, u32Value, pHpetTimer->u64Cmp));
            break;

        case HPET_TN_ROUTE:
            u32Value = (uint32_t)(pHpetTimer->u64Fsb >> 32); /** @todo Looks wrong, but since it's not supported, who cares. */
            Log(("read HPET_TN_ROUTE on %d: %#x\n", iTimerNo, u32Value));
            break;

        default:
        {
            static unsigned s_cOccurences = 0;
            if (s_cOccurences++ < 10)
                LogRel(("invalid HPET register read %d on %d\n", iTimerReg, pHpetTimer->idxTimer));
            u32Value = 0;
            break;
        }
    }
    *pu32Value = u32Value;
    return VINF_SUCCESS;
}
/**
 * @interface_method_impl{PDMINETWORKUP,pfnAllocBuf}
 */
PDMBOTHCBDECL(int) drvDedicatedNicUp_AllocBuf(PPDMINETWORKUP pInterface, size_t cbMin,
                                              PCPDMNETWORKGSO pGso,  PPPDMSCATTERGATHER ppSgBuf)
{
    PDRVDEDICATEDNIC    pThis = RT_FROM_MEMBER(pInterface, DRVDEDICATEDNIC, CTX_SUFF(INetworkUp));
    Assert(PDMCritSectIsOwner(&pThis->XmitLock));

    /*
     * If the net is down, we can return immediately.
     */
    if (pThis->fLinkDown)
        return VERR_NET_DOWN;

#ifdef IN_RING0
    /** @todo Ask the driver for a buffer, atomically if we're called on EMT.  */
    return VERR_TRY_AGAIN;

#else  /* IN_RING3 */
    /*
     * Are we busy or is the request too big?
     */
    if (RT_UNLIKELY((pThis->XmitSg.fFlags & PDMSCATTERGATHER_FLAGS_MAGIC_MASK) == PDMSCATTERGATHER_FLAGS_MAGIC))
        return VERR_TRY_AGAIN;
    if (cbMin > sizeof(pThis->abXmitBuf))
        return VERR_NO_MEMORY;

    /*
     * Initialize the S/G buffer and return.
     */
    pThis->XmitSg.fFlags         = PDMSCATTERGATHER_FLAGS_MAGIC | PDMSCATTERGATHER_FLAGS_OWNER_1;
    pThis->XmitSg.cbUsed         = 0;
    pThis->XmitSg.cbAvailable    = sizeof(pThis->abXmitBuf);
    pThis->XmitSg.pvAllocator    = NULL;
    if (!pGso)
    {
        pThis->XmitSg.pvUser     = NULL;
        pThis->XmitGso.u8Type    = PDMNETWORKGSOTYPE_INVALID;
    }
    else
    {
        pThis->XmitSg.pvUser     = &pThis->XmitGso;
        pThis->XmitGso           = *pGso;
    }
    pThis->XmitSg.cSegs          = 1;
    pThis->XmitSg.aSegs[0].cbSeg = pThis->XmitSg.cbAvailable;
    pThis->XmitSg.aSegs[0].pvSeg = &pThis->abXmitBuf[0];

# if 0 /* poison */
    memset(pThis->XmitSg.aSegs[0].pvSeg, 'F', pThis->XmitSg.aSegs[0].cbSeg);
# endif

    *ppSgBuf = &pThis->XmitSg;
    return VINF_SUCCESS;
#endif /* IN_RING3 */
}
/**
 * @interface_method_impl{PDMINETWORKUP,pfnFreeBuf}
 */
PDMBOTHCBDECL(int) drvDedicatedNicUp_FreeBuf(PPDMINETWORKUP pInterface, PPDMSCATTERGATHER pSgBuf)
{
    PDRVDEDICATEDNIC  pThis = RT_FROM_MEMBER(pInterface, DRVDEDICATEDNIC, CTX_SUFF(INetworkUp));
    Assert(pSgBuf->fFlags == (PDMSCATTERGATHER_FLAGS_MAGIC | PDMSCATTERGATHER_FLAGS_OWNER_1));
    Assert(pSgBuf->cbUsed <= pSgBuf->cbAvailable);
    Assert(PDMCritSectIsOwner(&pThis->XmitLock));

    if (pSgBuf)
    {
#ifdef IN_RING0
        // ...
#else
        Assert(pSgBuf == &pThis->XmitSg);
        Assert((pSgBuf->fFlags & PDMSCATTERGATHER_FLAGS_MAGIC_MASK) == PDMSCATTERGATHER_FLAGS_MAGIC);
        pSgBuf->fFlags = 0;
#endif
    }

    return VINF_SUCCESS;
}
Exemple #6
0
/**
 * 32-bit write to a HPET timer 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 hpetTimerRegWrite32(HpetState *pThis, uint32_t iTimerNo, uint32_t iTimerReg, uint32_t u32NewValue)
{
    Assert(!PDMCritSectIsOwner(&pThis->csLock) || TMTimerIsLockOwner(pThis->aTimers[0].CTX_SUFF(pTimer)));

    if (   iTimerNo >= RT_ELEMENTS(pThis->aTimers) /* parfait */
        || iTimerNo >= HPET_CAP_GET_TIMERS(pThis->u32Capabilities))
    {
        static unsigned s_cOccurences = 0;
        if (s_cOccurences++ < 10)
            LogRel(("HPET: using timer above configured range: %d\n", iTimerNo));
        return VINF_SUCCESS;
    }
    HpetTimer *pHpetTimer = &pThis->aTimers[iTimerNo];

    switch (iTimerReg)
    {
        case HPET_TN_CFG:
        {
            DEVHPET_LOCK_RETURN(pThis, VINF_IOM_R3_MMIO_WRITE);
            Log(("write HPET_TN_CFG: %d: %x\n", iTimerNo, u32NewValue));
            uint64_t const iOldValue = (uint32_t)pHpetTimer->u64Config;

            uint64_t u64Mask = HPET_TN_CFG_WRITE_MASK;
            if (pHpetTimer->u64Config & HPET_TN_PERIODIC_CAP)
                u64Mask |= HPET_TN_PERIODIC;

            if (pHpetTimer->u64Config & HPET_TN_SIZE_CAP)
                u64Mask |= HPET_TN_32BIT;
            else
                u32NewValue &= ~HPET_TN_32BIT;

            if (u32NewValue & HPET_TN_32BIT)
            {
                Log(("setting timer %d to 32-bit mode\n", iTimerNo));
                pHpetTimer->u64Cmp    = (uint32_t)pHpetTimer->u64Cmp;
                pHpetTimer->u64Period = (uint32_t)pHpetTimer->u64Period;
            }
            if ((u32NewValue & HPET_TN_INT_TYPE) == HPET_TIMER_TYPE_LEVEL)
            {
                static unsigned s_cOccurences = 0;
                if (s_cOccurences++ < 10)
                    LogRel(("level-triggered config not yet supported\n"));
                AssertFailed();
            }

            /* We only care about lower 32-bits so far */
            pHpetTimer->u64Config = hpetUpdateMasked(u32NewValue, iOldValue, u64Mask);
            DEVHPET_UNLOCK(pThis);
            break;
        }

        case HPET_TN_CFG + 4: /* Interrupt capabilities */
        {
            Log(("write HPET_TN_CFG + 4, useless\n"));
            break;
        }

        case HPET_TN_CMP: /* lower bits of comparator register */
        {
            DEVHPET_LOCK_BOTH_RETURN(pThis, VINF_IOM_R3_MMIO_WRITE);
            Log(("write HPET_TN_CMP on %d: %#x\n", iTimerNo, u32NewValue));

            if (pHpetTimer->u64Config & HPET_TN_PERIODIC)
            {
                u32NewValue &= hpetInvalidValue(pHpetTimer) >> 1; /** @todo check this in the docs and add a not why? */
                pHpetTimer->u64Period = RT_MAKE_U64(u32NewValue, pHpetTimer->u64Period);
            }
            pHpetTimer->u64Cmp     = RT_MAKE_U64(u32NewValue, pHpetTimer->u64Cmp);
            pHpetTimer->u64Config &= ~HPET_TN_SETVAL;
            Log2(("after HPET_TN_CMP cmp=%#llx per=%#llx\n", pHpetTimer->u64Cmp, pHpetTimer->u64Period));

            if (pThis->u64HpetConfig & HPET_CFG_ENABLE)
                hpetProgramTimer(pHpetTimer);
            DEVHPET_UNLOCK_BOTH(pThis);
            break;
        }

        case HPET_TN_CMP + 4: /* upper bits of comparator register */
        {
            DEVHPET_LOCK_BOTH_RETURN(pThis, VINF_IOM_R3_MMIO_WRITE);
            Log(("write HPET_TN_CMP + 4 on %d: %#x\n", iTimerNo, u32NewValue));
            if (!hpet32bitTimer(pHpetTimer))
            {
                if (pHpetTimer->u64Config & HPET_TN_PERIODIC)
                    pHpetTimer->u64Period = RT_MAKE_U64(pHpetTimer->u64Period, u32NewValue);
                pHpetTimer->u64Cmp = RT_MAKE_U64(pHpetTimer->u64Cmp, u32NewValue);

                Log2(("after HPET_TN_CMP+4 cmp=%llx per=%llx tmr=%d\n", pHpetTimer->u64Cmp, pHpetTimer->u64Period, iTimerNo));

                pHpetTimer->u64Config &= ~HPET_TN_SETVAL;

                if (pThis->u64HpetConfig & HPET_CFG_ENABLE)
                    hpetProgramTimer(pHpetTimer);
            }
            DEVHPET_UNLOCK_BOTH(pThis);
            break;
        }

        case HPET_TN_ROUTE:
        {
            Log(("write HPET_TN_ROUTE\n"));
            break;
        }

        case HPET_TN_ROUTE + 4:
        {
            Log(("write HPET_TN_ROUTE + 4\n"));
            break;
        }

        default:
        {
            static unsigned s_cOccurences = 0;
            if (s_cOccurences++ < 10)
                LogRel(("invalid timer register write: %d\n", iTimerReg));
            break;
        }
    }
/**
 * 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;
}
/**
 * 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;
}
Exemple #9
0
/**
 * Check if this VCPU currently owns the IOM lock.
 *
 * @returns bool owner/not owner
 * @param   pVM         Pointer to the VM.
 */
VMMDECL(bool) IOMIsLockOwner(PVM pVM)
{
    return PDMCritSectIsOwner(&pVM->iom.s.CritSect);
}