/** * @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 }
/** * 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; }
/** * 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; }
/** * 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); }