/** * Converts a pool address to a physical address. * The specified allocation type must match with the address. * * @returns Physical address. * @returns NIL_RTHCPHYS if not found or eType is not matching. * @param pPool Pointer to the page pool. * @param pv The address to convert. * @thread The Emulation Thread. */ RTHCPHYS mmPagePoolPtr2Phys(PMMPAGEPOOL pPool, void *pv) { #ifdef IN_RING3 VM_ASSERT_EMT(pPool->pVM); #endif /* * Lookup the virtual address. */ PMMPPLOOKUPHCPTR pLookup = (PMMPPLOOKUPHCPTR)RTAvlPVGetBestFit(&pPool->pLookupVirt, pv, false); if (pLookup) { unsigned iPage = ((char *)pv - (char *)pLookup->pSubPool->pvPages) >> PAGE_SHIFT; if (iPage < pLookup->pSubPool->cPages) { /* * Convert the virtual address to a physical address. */ STAM_COUNTER_INC(&pPool->cToPhysCalls); AssertMsg( pLookup->pSubPool->paPhysPages[iPage].Phys && !(pLookup->pSubPool->paPhysPages[iPage].Phys & PAGE_OFFSET_MASK), ("Phys=%#x\n", pLookup->pSubPool->paPhysPages[iPage].Phys)); AssertMsg((uintptr_t)pLookup->pSubPool == pLookup->pSubPool->paPhysPages[iPage].uReserved, ("pSubPool=%p uReserved=%p\n", pLookup->pSubPool, pLookup->pSubPool->paPhysPages[iPage].uReserved)); return pLookup->pSubPool->paPhysPages[iPage].Phys + ((uintptr_t)pv & PAGE_OFFSET_MASK); } } return NIL_RTHCPHYS; }
/** * Attach network filter driver from bandwidth group. * * @returns VBox status code. * @param pUVM The user mode VM structure. * @param pDrvIns The driver instance. * @param pszBwGroup Name of the bandwidth group to attach to. * @param pFilter Pointer to the filter we attach. */ VMMR3_INT_DECL(int) PDMR3NsAttach(PUVM pUVM, PPDMDRVINS pDrvIns, const char *pszBwGroup, PPDMNSFILTER pFilter) { VM_ASSERT_EMT(pUVM->pVM); AssertPtrReturn(pFilter, VERR_INVALID_POINTER); AssertReturn(pFilter->pBwGroupR3 == NULL, VERR_ALREADY_EXISTS); RT_NOREF_PV(pDrvIns); PPDMNETSHAPER pShaper = pUVM->pdm.s.pNetShaper; LOCK_NETSHAPER_RETURN(pShaper); int rc = VINF_SUCCESS; PPDMNSBWGROUP pBwGroupNew = NULL; if (pszBwGroup) { pBwGroupNew = pdmNsBwGroupFindById(pShaper, pszBwGroup); if (pBwGroupNew) pdmNsBwGroupRef(pBwGroupNew); else rc = VERR_NOT_FOUND; } if (RT_SUCCESS(rc)) { PPDMNSBWGROUP pBwGroupOld = ASMAtomicXchgPtrT(&pFilter->pBwGroupR3, pBwGroupNew, PPDMNSBWGROUP); ASMAtomicWritePtr(&pFilter->pBwGroupR0, MMHyperR3ToR0(pUVM->pVM, pBwGroupNew)); if (pBwGroupOld) pdmNsBwGroupUnref(pBwGroupOld); pdmNsFilterLink(pFilter); } UNLOCK_NETSHAPER(pShaper); return rc; }
/** * Flush pending queues. * This is a forced action callback. * * @param pVM Pointer to the VM. * @thread Emulation thread only. */ VMMR3_INT_DECL(void) PDMR3QueueFlushAll(PVM pVM) { VM_ASSERT_EMT(pVM); LogFlow(("PDMR3QueuesFlush:\n")); /* * Only let one EMT flushing queues at any one time to preserve the order * and to avoid wasting time. The FF is always cleared here, because it's * only used to get someones attention. Queue inserts occurring during the * flush are caught using the pending bit. * * Note! We must check the force action and pending flags after clearing * the active bit! */ VM_FF_CLEAR(pVM, VM_FF_PDM_QUEUES); while (!ASMAtomicBitTestAndSet(&pVM->pdm.s.fQueueFlushing, PDM_QUEUE_FLUSH_FLAG_ACTIVE_BIT)) { ASMAtomicBitClear(&pVM->pdm.s.fQueueFlushing, PDM_QUEUE_FLUSH_FLAG_PENDING_BIT); for (PPDMQUEUE pCur = pVM->pUVM->pdm.s.pQueuesForced; pCur; pCur = pCur->pNext) if ( pCur->pPendingR3 || pCur->pPendingR0 || pCur->pPendingRC) pdmR3QueueFlush(pCur); ASMAtomicBitClear(&pVM->pdm.s.fQueueFlushing, PDM_QUEUE_FLUSH_FLAG_ACTIVE_BIT); /* We're done if there were no inserts while we were busy. */ if ( !ASMBitTest(&pVM->pdm.s.fQueueFlushing, PDM_QUEUE_FLUSH_FLAG_PENDING_BIT) && !VM_FF_ISPENDING(pVM, VM_FF_PDM_QUEUES)) break; VM_FF_CLEAR(pVM, VM_FF_PDM_QUEUES); } }
/** * Gets the HC Phys to the dummy page. * * The dummy page is used as a place holder to prevent potential bugs * from doing really bad things to the system. * * @returns Pointer to the dummy page. * @param pVM The cross context VM structure. * @thread The Emulation Thread. */ VMMR3DECL(RTHCPHYS) MMR3PageDummyHCPhys(PVM pVM) { VM_ASSERT_EMT(pVM); if (!pVM->mm.s.pvDummyPage) MMR3PageDummyHCPtr(pVM); return pVM->mm.s.HCPhysDummyPage; }
/** @interface_method_impl{PDMPCIHLPR3,pfnIsMMIOExBase} */ static DECLCALLBACK(bool) pdmR3PciHlp_IsMMIO2Base(PPDMDEVINS pDevIns, PPDMDEVINS pOwner, RTGCPHYS GCPhys) { PDMDEV_ASSERT_DEVINS(pDevIns); VM_ASSERT_EMT(pDevIns->Internal.s.pVMR3); bool fRc = PGMR3PhysMMIOExIsBase(pDevIns->Internal.s.pVMR3, pOwner, GCPhys); Log4(("pdmR3PciHlp_IsMMIOExBase: pOwner=%p GCPhys=%RGp -> %RTbool\n", pOwner, GCPhys, fRc)); return fRc; }
/** @interface_method_impl{PDMHPETHLPR3,pfnGetRCHelpers} */ static DECLCALLBACK(PCPDMHPETHLPRC) pdmR3HpetHlp_GetRCHelpers(PPDMDEVINS pDevIns) { PDMDEV_ASSERT_DEVINS(pDevIns); VM_ASSERT_EMT(pDevIns->Internal.s.pVMR3); RTRCPTR pRCHelpers = 0; int rc = PDMR3LdrGetSymbolRC(pDevIns->Internal.s.pVMR3, NULL, "g_pdmRCHpetHlp", &pRCHelpers); AssertReleaseRC(rc); AssertRelease(pRCHelpers); LogFlow(("pdmR3HpetHlp_GetGCHelpers: caller='%s'/%d: returns %RRv\n", pDevIns->pReg->szName, pDevIns->iInstance, pRCHelpers)); return pRCHelpers; }
/** * Gets the HC pointer to the dummy page. * * The dummy page is used as a place holder to prevent potential bugs * from doing really bad things to the system. * * @returns Pointer to the dummy page. * @param pVM The cross context VM structure. * @thread The Emulation Thread. */ VMMR3DECL(void *) MMR3PageDummyHCPtr(PVM pVM) { VM_ASSERT_EMT(pVM); if (!pVM->mm.s.pvDummyPage) { pVM->mm.s.pvDummyPage = mmR3PagePoolAlloc(pVM->mm.s.pPagePoolR3); AssertRelease(pVM->mm.s.pvDummyPage); pVM->mm.s.HCPhysDummyPage = mmPagePoolPtr2Phys(pVM->mm.s.pPagePoolR3, pVM->mm.s.pvDummyPage); AssertRelease(!(pVM->mm.s.HCPhysDummyPage & ~X86_PTE_PAE_PG_MASK)); } return pVM->mm.s.pvDummyPage; }
/** @interface_method_impl{PDMPCIRAWHLPR3,pfnGetR0Helpers} */ static DECLCALLBACK(PCPDMPCIRAWHLPR0) pdmR3PciRawHlp_GetR0Helpers(PPDMDEVINS pDevIns) { PDMDEV_ASSERT_DEVINS(pDevIns); VM_ASSERT_EMT(pDevIns->Internal.s.pVMR3); PCPDMHPETHLPR0 pR0Helpers = NIL_RTR0PTR; int rc = PDMR3LdrGetSymbolR0(pDevIns->Internal.s.pVMR3, NULL, "g_pdmR0PciRawHlp", &pR0Helpers); AssertReleaseRC(rc); AssertRelease(pR0Helpers); LogFlow(("pdmR3PciRawHlp_GetR0Helpers: caller='%s'/%d: returns %RHv\n", pDevIns->pReg->szName, pDevIns->iInstance, pR0Helpers)); return pR0Helpers; }
/** @interface_method_impl{PDMIOAPICHLPR3,pfnGetR0Helpers} */ static DECLCALLBACK(PCPDMIOAPICHLPR0) pdmR3IoApicHlp_GetR0Helpers(PPDMDEVINS pDevIns) { PDMDEV_ASSERT_DEVINS(pDevIns); PVM pVM = pDevIns->Internal.s.pVMR3; VM_ASSERT_EMT(pVM); PCPDMIOAPICHLPR0 pR0Helpers = 0; int rc = PDMR3LdrGetSymbolR0(pVM, NULL, "g_pdmR0IoApicHlp", &pR0Helpers); AssertReleaseRC(rc); AssertRelease(pR0Helpers); LogFlow(("pdmR3IoApicHlp_GetR0Helpers: caller='%s'/%d: returns %RHv\n", pDevIns->pReg->szName, pDevIns->iInstance, pR0Helpers)); return pR0Helpers; }
/** * Free an item. * * @param pQueue The queue. * @param pItem The item. */ DECLINLINE(void) pdmR3QueueFreeItem(PPDMQUEUE pQueue, PPDMQUEUEITEMCORE pItem) { VM_ASSERT_EMT(pQueue->pVMR3); int i = pQueue->iFreeHead; int iNext = (i + 1) % (pQueue->cItems + PDMQUEUE_FREE_SLACK); pQueue->aFreeItems[i].pItemR3 = pItem; if (pQueue->pVMRC) { pQueue->aFreeItems[i].pItemRC = MMHyperR3ToRC(pQueue->pVMR3, pItem); pQueue->aFreeItems[i].pItemR0 = MMHyperR3ToR0(pQueue->pVMR3, pItem); } if (!ASMAtomicCmpXchgU32(&pQueue->iFreeHead, iNext, i)) AssertMsgFailed(("huh? i=%d iNext=%d iFreeHead=%d iFreeTail=%d\n", i, iNext, pQueue->iFreeHead, pQueue->iFreeTail)); STAM_STATS({ ASMAtomicDecU32(&pQueue->cStatPending); });
/** @interface_method_impl{PDMPICHLPR3,pfnGetRCHelpers} */ static DECLCALLBACK(PCPDMPICHLPRC) pdmR3PicHlp_GetRCHelpers(PPDMDEVINS pDevIns) { PDMDEV_ASSERT_DEVINS(pDevIns); PVM pVM = pDevIns->Internal.s.pVMR3; VM_ASSERT_EMT(pVM); RTRCPTR pRCHelpers = NIL_RTRCPTR; if (!HMIsEnabled(pVM)) { int rc = PDMR3LdrGetSymbolRC(pVM, NULL, "g_pdmRCPicHlp", &pRCHelpers); AssertReleaseRC(rc); AssertRelease(pRCHelpers); } LogFlow(("pdmR3PicHlp_GetRCHelpers: caller='%s'/%d: returns %RRv\n", pDevIns->pReg->szName, pDevIns->iInstance, pRCHelpers)); return pRCHelpers; }
/** * Frees a page from the page pool. * * @param pPool Pointer to the page pool. * @param pv Pointer to the page to free. * I.e. pointer returned by mmR3PagePoolAlloc(). * @thread The Emulation Thread. */ DECLINLINE(void) mmR3PagePoolFree(PMMPAGEPOOL pPool, void *pv) { VM_ASSERT_EMT(pPool->pVM); STAM_COUNTER_INC(&pPool->cFreeCalls); /* * Lookup the virtual address. */ PMMPPLOOKUPHCPTR pLookup = (PMMPPLOOKUPHCPTR)RTAvlPVGetBestFit(&pPool->pLookupVirt, pv, false); if ( !pLookup || (uint8_t *)pv >= (uint8_t *)pLookup->pSubPool->pvPages + (pLookup->pSubPool->cPages << PAGE_SHIFT) ) { STAM_COUNTER_INC(&pPool->cErrors); AssertMsgFailed(("invalid pointer %p\n", pv)); return; } /* * Free the page. */ PMMPAGESUBPOOL pSubPool = pLookup->pSubPool; /* clear bitmap bit */ const unsigned iPage = ((uint8_t *)pv - (uint8_t *)pSubPool->pvPages) >> PAGE_SHIFT; #ifdef USE_INLINE_ASM_BIT_OPS Assert(ASMBitTest(pSubPool->auBitmap, iPage)); ASMBitClear(pSubPool->auBitmap, iPage); #else unsigned iBit = iPage % (sizeof(pSubPool->auBitmap[0]) * 8); unsigned iIndex = iPage / (sizeof(pSubPool->auBitmap[0]) * 8); pSubPool->auBitmap[iIndex] &= ~(1 << iBit); #endif /* update stats. */ pSubPool->cPagesFree++; #ifdef VBOX_WITH_STATISTICS pPool->cFreePages++; #endif if (pSubPool->cPagesFree == 1) { pSubPool->pNextFree = pPool->pHeadFree; pPool->pHeadFree = pSubPool; } }
/** * Changes the halt method. * * @returns VBox status code. * @param pUVM Pointer to the user mode VM structure. * @param enmHaltMethod The new halt method. * @thread EMT. */ int vmR3SetHaltMethodU(PUVM pUVM, VMHALTMETHOD enmHaltMethod) { PVM pVM = pUVM->pVM; Assert(pVM); VM_ASSERT_EMT(pVM); AssertReturn(enmHaltMethod > VMHALTMETHOD_INVALID && enmHaltMethod < VMHALTMETHOD_END, VERR_INVALID_PARAMETER); /* * Resolve default (can be overridden in the configuration). */ if (enmHaltMethod == VMHALTMETHOD_DEFAULT) { uint32_t u32; int rc = CFGMR3QueryU32(CFGMR3GetChild(CFGMR3GetRoot(pVM), "VM"), "HaltMethod", &u32); if (RT_SUCCESS(rc)) { enmHaltMethod = (VMHALTMETHOD)u32; if (enmHaltMethod <= VMHALTMETHOD_INVALID || enmHaltMethod >= VMHALTMETHOD_END) return VMSetError(pVM, VERR_INVALID_PARAMETER, RT_SRC_POS, N_("Invalid VM/HaltMethod value %d"), enmHaltMethod); } else if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_CHILD_NOT_FOUND) return VMSetError(pVM, rc, RT_SRC_POS, N_("Failed to Query VM/HaltMethod as uint32_t")); else enmHaltMethod = VMHALTMETHOD_GLOBAL_1; //enmHaltMethod = VMHALTMETHOD_1; //enmHaltMethod = VMHALTMETHOD_OLD; } LogRel(("VM: Halt method %s (%d)\n", vmR3GetHaltMethodName(enmHaltMethod), enmHaltMethod)); /* * Find the descriptor. */ unsigned i = 0; while ( i < RT_ELEMENTS(g_aHaltMethods) && g_aHaltMethods[i].enmHaltMethod != enmHaltMethod) i++; AssertReturn(i < RT_ELEMENTS(g_aHaltMethods), VERR_INVALID_PARAMETER); /* * This needs to be done while the other EMTs are not sleeping or otherwise messing around. */ return VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, vmR3SetHaltMethodCallback, (void *)(uintptr_t)i); }
VMMR3DECL(int) PDMR3NsDetach(PVM pVM, PPDMDRVINS pDrvIns, PPDMNSFILTER pFilter) { VM_ASSERT_EMT(pVM); AssertPtrReturn(pFilter, VERR_INVALID_POINTER); AssertPtrReturn(pFilter->pBwGroupR3, VERR_INVALID_POINTER); PUVM pUVM = pVM->pUVM; PPDMNETSHAPER pShaper = pUVM->pdm.s.pNetShaper; int rc = RTCritSectEnter(&pShaper->cs); AssertRC(rc); if (RT_SUCCESS(rc)) { pdmNsFilterUnlink(pFilter); PPDMNSBWGROUP pBwGroup = NULL; pBwGroup = ASMAtomicXchgPtrT(&pFilter->pBwGroupR3, NULL, PPDMNSBWGROUP); if (pBwGroup) pdmNsBwGroupUnref(pBwGroup); int rc2 = RTCritSectLeave(&pShaper->cs); AssertRC(rc2); } return rc; }
/** * Converts a pool physical address to a linear address. * The specified allocation type must match with the address. * * @returns Physical address. * @returns NULL if not found or eType is not matching. * @param pPool Pointer to the page pool. * @param HCPhys The address to convert. * @thread The Emulation Thread. */ void *mmPagePoolPhys2Ptr(PMMPAGEPOOL pPool, RTHCPHYS HCPhys) { #if 0 /** @todo have to fix the debugger, but until then this is going on my nerves. */ #ifdef IN_RING3 VM_ASSERT_EMT(pPool->pVM); #endif #endif /* * Lookup the virtual address. */ PMMPPLOOKUPHCPHYS pLookup = (PMMPPLOOKUPHCPHYS)RTAvlHCPhysGet(&pPool->pLookupPhys, HCPhys & X86_PTE_PAE_PG_MASK); if (pLookup) { STAM_COUNTER_INC(&pPool->cToVirtCalls); PSUPPAGE pPhysPage = pLookup->pPhysPage; PMMPAGESUBPOOL pSubPool = (PMMPAGESUBPOOL)pPhysPage->uReserved; unsigned iPage = pPhysPage - pSubPool->paPhysPages; return (char *)pSubPool->pvPages + (HCPhys & PAGE_OFFSET_MASK) + (iPage << PAGE_SHIFT); } return NULL; }
VMMR3DECL(int) PDMR3NsAttach(PVM pVM, PPDMDRVINS pDrvIns, const char *pcszBwGroup, PPDMNSFILTER pFilter) { VM_ASSERT_EMT(pVM); AssertPtrReturn(pFilter, VERR_INVALID_POINTER); AssertReturn(pFilter->pBwGroupR3 == NULL, VERR_ALREADY_EXISTS); PUVM pUVM = pVM->pUVM; PPDMNETSHAPER pShaper = pUVM->pdm.s.pNetShaper; PPDMNSBWGROUP pBwGroupOld = NULL; PPDMNSBWGROUP pBwGroupNew = NULL; int rc = RTCritSectEnter(&pShaper->cs); AssertRC(rc); if (RT_SUCCESS(rc)) { if (pcszBwGroup) { pBwGroupNew = pdmNsBwGroupFindById(pShaper, pcszBwGroup); if (pBwGroupNew) pdmNsBwGroupRef(pBwGroupNew); else rc = VERR_NOT_FOUND; } if (RT_SUCCESS(rc)) { pBwGroupOld = ASMAtomicXchgPtrT(&pFilter->pBwGroupR3, pBwGroupNew, PPDMNSBWGROUP); ASMAtomicWritePtr(&pFilter->pBwGroupR0, MMHyperR3ToR0(pVM, pBwGroupNew)); if (pBwGroupOld) pdmNsBwGroupUnref(pBwGroupOld); pdmNsFilterLink(pFilter); } int rc2 = RTCritSectLeave(&pShaper->cs); AssertRC(rc2); } return rc; }
/** * Detach network filter driver from bandwidth group. * * @returns VBox status code. * @param pUVM The user mode VM handle. * @param pDrvIns The driver instance. * @param pFilter Pointer to the filter we detach. */ VMMR3_INT_DECL(int) PDMR3NsDetach(PUVM pUVM, PPDMDRVINS pDrvIns, PPDMNSFILTER pFilter) { RT_NOREF_PV(pDrvIns); VM_ASSERT_EMT(pUVM->pVM); AssertPtrReturn(pFilter, VERR_INVALID_POINTER); /* Now, return quietly if the filter isn't attached since driver/device destructors are called on constructor failure. */ if (!pFilter->pBwGroupR3) return VINF_SUCCESS; AssertPtrReturn(pFilter->pBwGroupR3, VERR_INVALID_POINTER); PPDMNETSHAPER pShaper = pUVM->pdm.s.pNetShaper; LOCK_NETSHAPER_RETURN(pShaper); pdmNsFilterUnlink(pFilter); PPDMNSBWGROUP pBwGroup = ASMAtomicXchgPtrT(&pFilter->pBwGroupR3, NULL, PPDMNSBWGROUP); if (pBwGroup) pdmNsBwGroupUnref(pBwGroup); UNLOCK_NETSHAPER(pShaper); return VINF_SUCCESS; }
/** @interface_method_impl{PDMAPICHLPR3,pfnSendInitIpi} */ static DECLCALLBACK(void) pdmR3ApicHlp_SendInitIpi(PPDMDEVINS pDevIns, VMCPUID idCpu) { PDMDEV_ASSERT_DEVINS(pDevIns); VM_ASSERT_EMT(pDevIns->Internal.s.pVMR3); VMMR3SendInitIpi(pDevIns->Internal.s.pVMR3, idCpu); }
/** @interface_method_impl{PDMAPICHLPR3,pfnGetCpuId} */ static DECLCALLBACK(VMCPUID) pdmR3ApicHlp_GetCpuId(PPDMDEVINS pDevIns) { PDMDEV_ASSERT_DEVINS(pDevIns); VM_ASSERT_EMT(pDevIns->Internal.s.pVMR3); return VMMGetCpuId(pDevIns->Internal.s.pVMR3); }
/** * Initializes a critical section and inserts it into the list. * * @returns VBox status code. * @param pVM Pointer to the VM. * @param pCritSect The critical section. * @param pvKey The owner key. * @param RT_SRC_POS_DECL The source position. * @param pszName The name of the critical section (for statistics). * @param pszNameFmt Format string for naming the critical section. For * statistics and lock validation. * @param va Arguments for the format string. */ static int pdmR3CritSectInitOne(PVM pVM, PPDMCRITSECTINT pCritSect, void *pvKey, RT_SRC_POS_DECL, const char *pszNameFmt, va_list va) { VM_ASSERT_EMT(pVM); /* * Allocate the semaphore. */ AssertCompile(sizeof(SUPSEMEVENT) == sizeof(pCritSect->Core.EventSem)); int rc = SUPSemEventCreate(pVM->pSession, (PSUPSEMEVENT)&pCritSect->Core.EventSem); if (RT_SUCCESS(rc)) { /* Only format the name once. */ char *pszName = RTStrAPrintf2V(pszNameFmt, va); /** @todo plug the "leak"... */ if (pszName) { #ifndef PDMCRITSECT_STRICT pCritSect->Core.pValidatorRec = NULL; #else rc = RTLockValidatorRecExclCreate(&pCritSect->Core.pValidatorRec, # ifdef RT_LOCK_STRICT_ORDER RTLockValidatorClassForSrcPos(RT_SRC_POS_ARGS, "%s", pszName), # else NIL_RTLOCKVALCLASS, # endif RTLOCKVAL_SUB_CLASS_NONE, pCritSect, true, "%s", pszName); #endif if (RT_SUCCESS(rc)) { /* * Initialize the structure (first bit is c&p from RTCritSectInitEx). */ pCritSect->Core.u32Magic = RTCRITSECT_MAGIC; pCritSect->Core.fFlags = 0; pCritSect->Core.cNestings = 0; pCritSect->Core.cLockers = -1; pCritSect->Core.NativeThreadOwner = NIL_RTNATIVETHREAD; pCritSect->pVMR3 = pVM; pCritSect->pVMR0 = pVM->pVMR0; pCritSect->pVMRC = pVM->pVMRC; pCritSect->pvKey = pvKey; pCritSect->fAutomaticDefaultCritsect = false; pCritSect->fUsedByTimerOrSimilar = false; pCritSect->EventToSignal = NIL_RTSEMEVENT; pCritSect->pNext = pVM->pUVM->pdm.s.pCritSects; pCritSect->pszName = pszName; pVM->pUVM->pdm.s.pCritSects = pCritSect; STAMR3RegisterF(pVM, &pCritSect->StatContentionRZLock, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, NULL, "/PDM/CritSects/%s/ContentionRZLock", pCritSect->pszName); STAMR3RegisterF(pVM, &pCritSect->StatContentionRZUnlock,STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, NULL, "/PDM/CritSects/%s/ContentionRZUnlock", pCritSect->pszName); STAMR3RegisterF(pVM, &pCritSect->StatContentionR3, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, NULL, "/PDM/CritSects/%s/ContentionR3", pCritSect->pszName); #ifdef VBOX_WITH_STATISTICS STAMR3RegisterF(pVM, &pCritSect->StatLocked, STAMTYPE_PROFILE_ADV, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_OCCURENCE, NULL, "/PDM/CritSects/%s/Locked", pCritSect->pszName); #endif return VINF_SUCCESS; } RTStrFree(pszName); } else rc = VERR_NO_STR_MEMORY; SUPSemEventClose(pVM->pSession, (SUPSEMEVENT)pCritSect->Core.EventSem); } return rc; }
/** * Destroys a PDM thread. * * This will wakeup the thread, tell it to terminate, and wait for it terminate. * * @returns VBox status code. * This reflects the success off destroying the thread and not the exit code * of the thread as this is stored in *pRcThread. * @param pThread The thread to destroy. * @param pRcThread Where to store the thread exit code. Optional. * @thread The emulation thread (EMT). */ VMMR3DECL(int) PDMR3ThreadDestroy(PPDMTHREAD pThread, int *pRcThread) { /* * Assert sanity. */ AssertPtrReturn(pThread, VERR_INVALID_POINTER); AssertReturn(pThread->u32Version == PDMTHREAD_VERSION, VERR_INVALID_MAGIC); Assert(pThread->Thread != RTThreadSelf()); AssertPtrNullReturn(pRcThread, VERR_INVALID_POINTER); PVM pVM = pThread->Internal.s.pVM; VM_ASSERT_EMT(pVM); PUVM pUVM = pVM->pUVM; /* * Advance the thread to the terminating state. */ int rc = VINF_SUCCESS; if (pThread->enmState <= PDMTHREADSTATE_TERMINATING) { for (;;) { PDMTHREADSTATE enmState = pThread->enmState; switch (enmState) { case PDMTHREADSTATE_RUNNING: if (!pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_TERMINATING, enmState)) continue; rc = pdmR3ThreadWakeUp(pThread); break; case PDMTHREADSTATE_SUSPENDED: case PDMTHREADSTATE_SUSPENDING: case PDMTHREADSTATE_RESUMING: case PDMTHREADSTATE_INITIALIZING: if (!pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_TERMINATING, enmState)) continue; break; case PDMTHREADSTATE_TERMINATING: case PDMTHREADSTATE_TERMINATED: break; default: AssertMsgFailed(("enmState=%d\n", enmState)); rc = VERR_PDM_THREAD_IPE_2; break; } break; } } int rc2 = RTSemEventMultiSignal(pThread->Internal.s.BlockEvent); AssertRC(rc2); /* * Wait for it to terminate and the do cleanups. */ rc2 = RTThreadWait(pThread->Thread, RT_SUCCESS(rc) ? 60*1000 : 150, pRcThread); if (RT_SUCCESS(rc2)) { /* make it invalid. */ pThread->u32Version = 0xffffffff; pThread->enmState = PDMTHREADSTATE_INVALID; pThread->Thread = NIL_RTTHREAD; /* unlink */ RTCritSectEnter(&pUVM->pdm.s.ListCritSect); if (pUVM->pdm.s.pThreads == pThread) { pUVM->pdm.s.pThreads = pThread->Internal.s.pNext; if (!pThread->Internal.s.pNext) pUVM->pdm.s.pThreadsTail = NULL; } else { PPDMTHREAD pPrev = pUVM->pdm.s.pThreads; while (pPrev && pPrev->Internal.s.pNext != pThread) pPrev = pPrev->Internal.s.pNext; Assert(pPrev); if (pPrev) pPrev->Internal.s.pNext = pThread->Internal.s.pNext; if (!pThread->Internal.s.pNext) pUVM->pdm.s.pThreadsTail = pPrev; } pThread->Internal.s.pNext = NULL; RTCritSectLeave(&pUVM->pdm.s.ListCritSect); /* free the resources */ RTSemEventMultiDestroy(pThread->Internal.s.BlockEvent); pThread->Internal.s.BlockEvent = NIL_RTSEMEVENTMULTI; RTSemEventMultiDestroy(pThread->Internal.s.SleepEvent); pThread->Internal.s.SleepEvent = NIL_RTSEMEVENTMULTI; MMR3HeapFree(pThread); } else if (RT_SUCCESS(rc)) rc = rc2; return rc; }
/** * Allocates a page from the page pool. * * @returns Pointer to allocated page(s). * @returns NULL on failure. * @param pPool Pointer to the page pool. * @thread The Emulation Thread. */ DECLINLINE(void *) mmR3PagePoolAlloc(PMMPAGEPOOL pPool) { VM_ASSERT_EMT(pPool->pVM); STAM_COUNTER_INC(&pPool->cAllocCalls); /* * Walk free list. */ if (pPool->pHeadFree) { PMMPAGESUBPOOL pSub = pPool->pHeadFree; /* decrement free count and unlink if no more free entries. */ if (!--pSub->cPagesFree) pPool->pHeadFree = pSub->pNextFree; #ifdef VBOX_WITH_STATISTICS pPool->cFreePages--; #endif /* find free spot in bitmap. */ #ifdef USE_INLINE_ASM_BIT_OPS const int iPage = ASMBitFirstClear(pSub->auBitmap, pSub->cPages); if (iPage >= 0) { Assert(!ASMBitTest(pSub->auBitmap, iPage)); ASMBitSet(pSub->auBitmap, iPage); return (uint8_t *)pSub->pvPages + PAGE_SIZE * iPage; } #else unsigned *pu = &pSub->auBitmap[0]; unsigned *puEnd = &pSub->auBitmap[pSub->cPages / (sizeof(pSub->auBitmap) * 8)]; while (pu < puEnd) { unsigned u; if ((u = *pu) != ~0U) { unsigned iBit = 0; unsigned uMask = 1; while (iBit < sizeof(pSub->auBitmap[0]) * 8) { if (!(u & uMask)) { *pu |= uMask; return (uint8_t *)pSub->pvPages + PAGE_SIZE * (iBit + ((uint8_t *)pu - (uint8_t *)&pSub->auBitmap[0]) * 8); } iBit++; uMask <<= 1; } STAM_COUNTER_INC(&pPool->cErrors); AssertMsgFailed(("how odd, expected to find a free bit in %#x, but didn't\n", u)); } /* next */ pu++; } #endif STAM_COUNTER_INC(&pPool->cErrors); #ifdef VBOX_WITH_STATISTICS pPool->cFreePages++; #endif AssertMsgFailed(("how strange, expected to find a free bit in %p, but didn't (%d pages supposed to be free!)\n", pSub, pSub->cPagesFree + 1)); } /* * Allocate new subpool. */ unsigned cPages = !pPool->fLow ? 128 : 32; PMMPAGESUBPOOL pSub; int rc = MMHyperAlloc(pPool->pVM, RT_OFFSETOF(MMPAGESUBPOOL, auBitmap[cPages / (sizeof(pSub->auBitmap[0]) * 8)]) + (sizeof(SUPPAGE) + sizeof(MMPPLOOKUPHCPHYS)) * cPages + sizeof(MMPPLOOKUPHCPTR), 0, MM_TAG_MM_PAGE, (void **)&pSub); if (RT_FAILURE(rc)) return NULL; PSUPPAGE paPhysPages = (PSUPPAGE)&pSub->auBitmap[cPages / (sizeof(pSub->auBitmap[0]) * 8)]; Assert((uintptr_t)paPhysPages >= (uintptr_t)&pSub->auBitmap[1]); if (!pPool->fLow) { rc = SUPR3PageAllocEx(cPages, 0 /* fFlags */, &pSub->pvPages, NULL, paPhysPages); if (RT_FAILURE(rc)) rc = VMSetError(pPool->pVM, rc, RT_SRC_POS, N_("Failed to lock host %zd bytes of memory (out of memory)"), (size_t)cPages << PAGE_SHIFT); } else rc = SUPR3LowAlloc(cPages, &pSub->pvPages, NULL, paPhysPages); if (RT_SUCCESS(rc)) { /* * Setup the sub structure and allocate the requested page. */ pSub->cPages = cPages; pSub->cPagesFree= cPages - 1; pSub->paPhysPages = paPhysPages; memset(pSub->auBitmap, 0, cPages / 8); /* allocate first page. */ pSub->auBitmap[0] |= 1; /* link into free chain. */ pSub->pNextFree = pPool->pHeadFree; pPool->pHeadFree= pSub; /* link into main chain. */ pSub->pNext = pPool->pHead; pPool->pHead = pSub; /* update pool statistics. */ pPool->cSubPools++; pPool->cPages += cPages; #ifdef VBOX_WITH_STATISTICS pPool->cFreePages += cPages - 1; #endif /* * Initialize the physical pages with backpointer to subpool. */ unsigned i = cPages; while (i-- > 0) { AssertMsg(paPhysPages[i].Phys && !(paPhysPages[i].Phys & PAGE_OFFSET_MASK), ("i=%d Phys=%d\n", i, paPhysPages[i].Phys)); paPhysPages[i].uReserved = (RTHCUINTPTR)pSub; } /* * Initialize the physical lookup record with backpointers to the physical pages. */ PMMPPLOOKUPHCPHYS paLookupPhys = (PMMPPLOOKUPHCPHYS)&paPhysPages[cPages]; i = cPages; while (i-- > 0) { paLookupPhys[i].pPhysPage = &paPhysPages[i]; paLookupPhys[i].Core.Key = paPhysPages[i].Phys; RTAvlHCPhysInsert(&pPool->pLookupPhys, &paLookupPhys[i].Core); } /* * And the one record for virtual memory lookup. */ PMMPPLOOKUPHCPTR pLookupVirt = (PMMPPLOOKUPHCPTR)&paLookupPhys[cPages]; pLookupVirt->pSubPool = pSub; pLookupVirt->Core.Key = pSub->pvPages; RTAvlPVInsert(&pPool->pLookupVirt, &pLookupVirt->Core); /* return allocated page (first). */ return pSub->pvPages; } MMHyperFree(pPool->pVM, pSub); STAM_COUNTER_INC(&pPool->cErrors); if (pPool->fLow) VMSetError(pPool->pVM, rc, RT_SRC_POS, N_("Failed to expand page pool for memory below 4GB. Current size: %d pages"), pPool->cPages); AssertMsgFailed(("Failed to expand pool%s. rc=%Rrc poolsize=%d\n", pPool->fLow ? " (<4GB)" : "", rc, pPool->cPages)); return NULL; }
/** * Initialize the network shaper. * * @returns VBox status code * @param pVM Pointer to the VM. */ int pdmR3NetShaperInit(PVM pVM) { LogFlowFunc((": pVM=%p\n", pVM)); VM_ASSERT_EMT(pVM); PPDMNETSHAPER pNetShaper = NULL; int rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_NET_SHAPER, sizeof(PDMNETSHAPER), (void **)&pNetShaper); if (RT_SUCCESS(rc)) { PCFGMNODE pCfgRoot = CFGMR3GetRoot(pVM); PCFGMNODE pCfgNetShaper = CFGMR3GetChild(CFGMR3GetChild(pCfgRoot, "PDM"), "NetworkShaper"); pNetShaper->pVM = pVM; rc = RTCritSectInit(&pNetShaper->cs); if (RT_SUCCESS(rc)) { /* Create all bandwidth groups. */ PCFGMNODE pCfgBwGrp = CFGMR3GetChild(pCfgNetShaper, "BwGroups"); if (pCfgBwGrp) { for (PCFGMNODE pCur = CFGMR3GetFirstChild(pCfgBwGrp); pCur; pCur = CFGMR3GetNextChild(pCur)) { uint64_t cbMax; size_t cbName = CFGMR3GetNameLen(pCur) + 1; char *pszBwGrpId = (char *)RTMemAllocZ(cbName); if (!pszBwGrpId) { rc = VERR_NO_MEMORY; break; } rc = CFGMR3GetName(pCur, pszBwGrpId, cbName); AssertRC(rc); if (RT_SUCCESS(rc)) rc = CFGMR3QueryU64(pCur, "Max", &cbMax); if (RT_SUCCESS(rc)) rc = pdmNsBwGroupCreate(pNetShaper, pszBwGrpId, cbMax); RTMemFree(pszBwGrpId); if (RT_FAILURE(rc)) break; } } if (RT_SUCCESS(rc)) { PUVM pUVM = pVM->pUVM; AssertMsg(!pUVM->pdm.s.pNetShaper, ("Network shaper was already initialized\n")); char szDesc[64]; static unsigned s_iThread; RTStrPrintf(szDesc, sizeof(szDesc), "PDMNsTx-%d", ++s_iThread); rc = PDMR3ThreadCreate(pVM, &pNetShaper->hTxThread, pNetShaper, pdmR3NsTxThread, pdmR3NsTxWakeUp, 0, RTTHREADTYPE_IO, szDesc); if (RT_SUCCESS(rc)) { pUVM->pdm.s.pNetShaper = pNetShaper; return VINF_SUCCESS; } } RTCritSectDelete(&pNetShaper->cs); } MMR3HeapFree(pNetShaper); } LogFlowFunc((": pVM=%p rc=%Rrc\n", pVM, rc)); return rc; }
/** @interface_method_impl{PDMAPICHLPR3,pfnSendStartupIpi} */ static DECLCALLBACK(void) pdmR3ApicHlp_SendStartupIpi(PPDMDEVINS pDevIns, VMCPUID idCpu, uint32_t uVector) { PDMDEV_ASSERT_DEVINS(pDevIns); VM_ASSERT_EMT(pDevIns->Internal.s.pVMR3); VMMR3SendStartupIpi(pDevIns->Internal.s.pVMR3, idCpu, uVector); }
/** * Initialize the network shaper. * * @returns VBox status code * @param pVM The cross context VM structure. */ int pdmR3NetShaperInit(PVM pVM) { LogFlow(("pdmR3NetShaperInit: pVM=%p\n", pVM)); VM_ASSERT_EMT(pVM); PUVM pUVM = pVM->pUVM; AssertMsgReturn(!pUVM->pdm.s.pNetShaper, ("Network shaper was already initialized\n"), VERR_WRONG_ORDER); PPDMNETSHAPER pShaper; int rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_NET_SHAPER, sizeof(PDMNETSHAPER), (void **)&pShaper); if (RT_SUCCESS(rc)) { PCFGMNODE pCfgNetShaper = CFGMR3GetChild(CFGMR3GetChild(CFGMR3GetRoot(pVM), "PDM"), "NetworkShaper"); pShaper->pVM = pVM; rc = RTCritSectInit(&pShaper->Lock); if (RT_SUCCESS(rc)) { /* Create all bandwidth groups. */ PCFGMNODE pCfgBwGrp = CFGMR3GetChild(pCfgNetShaper, "BwGroups"); if (pCfgBwGrp) { for (PCFGMNODE pCur = CFGMR3GetFirstChild(pCfgBwGrp); pCur; pCur = CFGMR3GetNextChild(pCur)) { size_t cbName = CFGMR3GetNameLen(pCur) + 1; char *pszBwGrpId = (char *)RTMemAllocZ(cbName); if (pszBwGrpId) { rc = CFGMR3GetName(pCur, pszBwGrpId, cbName); if (RT_SUCCESS(rc)) { uint64_t cbMax; rc = CFGMR3QueryU64(pCur, "Max", &cbMax); if (RT_SUCCESS(rc)) rc = pdmNsBwGroupCreate(pShaper, pszBwGrpId, cbMax); } RTMemFree(pszBwGrpId); } else rc = VERR_NO_MEMORY; if (RT_FAILURE(rc)) break; } } if (RT_SUCCESS(rc)) { rc = PDMR3ThreadCreate(pVM, &pShaper->pTxThread, pShaper, pdmR3NsTxThread, pdmR3NsTxWakeUp, 0 /*cbStack*/, RTTHREADTYPE_IO, "PDMNsTx"); if (RT_SUCCESS(rc)) { pUVM->pdm.s.pNetShaper = pShaper; return VINF_SUCCESS; } } RTCritSectDelete(&pShaper->Lock); } MMR3HeapFree(pShaper); } LogFlow(("pdmR3NetShaperInit: pVM=%p rc=%Rrc\n", pVM, rc)); return rc; }