/** @interface_method_impl{PDMAPICHLPR0,pfnSetInterruptFF} */ static DECLCALLBACK(void) pdmR0ApicHlp_SetInterruptFF(PPDMDEVINS pDevIns, PDMAPICIRQ enmType, VMCPUID idCpu) { PDMDEV_ASSERT_DEVINS(pDevIns); PVM pVM = pDevIns->Internal.s.pVMR0; PVMCPU pVCpu = &pVM->aCpus[idCpu]; AssertReturnVoid(idCpu < pVM->cCpus); LogFlow(("pdmR0ApicHlp_SetInterruptFF: CPU%d=caller=%p/%d: VM_FF_INTERRUPT %d -> 1 (CPU%d)\n", VMMGetCpuId(pVM), pDevIns, pDevIns->iInstance, VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC), idCpu)); switch (enmType) { case PDMAPICIRQ_UPDATE_PENDING: VMCPU_FF_SET(pVCpu, VMCPU_FF_UPDATE_APIC); break; case PDMAPICIRQ_HARDWARE: #ifdef VBOX_WITH_NEW_APIC VMCPU_ASSERT_EMT_OR_NOT_RUNNING(pVCpu); #endif VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC); break; case PDMAPICIRQ_NMI: VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI); break; case PDMAPICIRQ_SMI: VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_SMI); break; case PDMAPICIRQ_EXTINT: VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_PIC); break; default: AssertMsgFailed(("enmType=%d\n", enmType)); break; } /* We need to wake up the target CPU. */ if ( #ifdef VBOX_WITH_NEW_APIC /* We are already on EMT if enmType is PDMAPICIRQ_HARDWARE. Don't bother with poking! */ enmType != PDMAPICIRQ_HARDWARE && #endif VMMGetCpuId(pVM) != idCpu) { switch (VMCPU_GET_STATE(pVCpu)) { case VMCPUSTATE_STARTED_EXEC: GVMMR0SchedPokeEx(pVM, pVCpu->idCpu, false /* don't take the used lock */); break; case VMCPUSTATE_STARTED_HALTED: GVMMR0SchedWakeUpEx(pVM, pVCpu->idCpu, false /* don't take the used lock */); break; default: break; /* nothing to do in other states. */ } } }
/** @interface_method_impl{PDMDEVHLPRC,pfnGetCurrentCpuId} */ static DECLCALLBACK(VMCPUID) pdmR0DevHlp_GetCurrentCpuId(PPDMDEVINS pDevIns) { PDMDEV_ASSERT_DEVINS(pDevIns); VMCPUID idCpu = VMMGetCpuId(pDevIns->Internal.s.pVMR0); LogFlow(("pdmR0DevHlp_GetCurrentCpuId: caller='%p'/%d for CPU %u\n", pDevIns, pDevIns->iInstance, idCpu)); return idCpu; }
/** * Wrapper around CPUMIsGuestIn64BitCode. * * @returns VINF_SUCCESS. * @param pVM Pointer to the VM. * @param idCpu The current CPU ID. * @param pfIn64BitCode Where to return the result. */ static DECLCALLBACK(int) dbgfR3CpuIn64BitCode(PVM pVM, VMCPUID idCpu, bool *pfIn64BitCode) { Assert(idCpu == VMMGetCpuId(pVM)); PVMCPU pVCpu = VMMGetCpuById(pVM, idCpu); *pfIn64BitCode = CPUMIsGuestIn64BitCode(pVCpu); return VINF_SUCCESS; }
/** * Wrapper around CPUMGetGuestMode. * * @returns VINF_SUCCESS. * @param pVM Pointer to the VM. * @param idCpu The current CPU ID. * @param penmMode Where to return the mode. */ static DECLCALLBACK(int) dbgfR3CpuGetMode(PVM pVM, VMCPUID idCpu, CPUMMODE *penmMode) { Assert(idCpu == VMMGetCpuId(pVM)); PVMCPU pVCpu = VMMGetCpuById(pVM, idCpu); *penmMode = CPUMGetGuestMode(pVCpu); return VINF_SUCCESS; }
/** * Scan guest memory for an exact byte string. * * @returns VBox status code. * @param pUVM The user mode VM handle. * @param idCpu The ID of the CPU context to search in. * @param pAddress Where to store the mixed address. * @param puAlign The alignment restriction imposed on the search result. * @param pcbRange The number of bytes to scan. Passed as a pointer because * it may be 64-bit. * @param pabNeedle What to search for - exact search. * @param cbNeedle Size of the search byte string. * @param pHitAddress Where to put the address of the first hit. */ static DECLCALLBACK(int) dbgfR3MemScan(PUVM pUVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, PCRTGCUINTPTR pcbRange, RTGCUINTPTR *puAlign, const uint8_t *pabNeedle, size_t cbNeedle, PDBGFADDRESS pHitAddress) { PVM pVM = pUVM->pVM; VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); Assert(idCpu == VMMGetCpuId(pVM)); /* * Validate the input we use, PGM does the rest. */ RTGCUINTPTR cbRange = *pcbRange; if (!DBGFR3AddrIsValid(pUVM, pAddress)) return VERR_INVALID_POINTER; if (!VALID_PTR(pHitAddress)) return VERR_INVALID_POINTER; if (DBGFADDRESS_IS_HMA(pAddress)) return VERR_INVALID_POINTER; /* * Select DBGF worker by addressing mode. */ int rc; PVMCPU pVCpu = VMMGetCpuById(pVM, idCpu); PGMMODE enmMode = PGMGetGuestMode(pVCpu); if ( enmMode == PGMMODE_REAL || enmMode == PGMMODE_PROTECTED || DBGFADDRESS_IS_PHYS(pAddress) ) { RTGCPHYS GCPhysAlign = *puAlign; if (GCPhysAlign != *puAlign) return VERR_OUT_OF_RANGE; RTGCPHYS PhysHit; rc = PGMR3DbgScanPhysical(pVM, pAddress->FlatPtr, cbRange, GCPhysAlign, pabNeedle, cbNeedle, &PhysHit); if (RT_SUCCESS(rc)) DBGFR3AddrFromPhys(pUVM, pHitAddress, PhysHit); } else { #if GC_ARCH_BITS > 32 if ( ( pAddress->FlatPtr >= _4G || pAddress->FlatPtr + cbRange > _4G) && enmMode != PGMMODE_AMD64 && enmMode != PGMMODE_AMD64_NX) return VERR_DBGF_MEM_NOT_FOUND; #endif RTGCUINTPTR GCPtrHit; rc = PGMR3DbgScanVirtual(pVM, pVCpu, pAddress->FlatPtr, cbRange, *puAlign, pabNeedle, cbNeedle, &GCPtrHit); if (RT_SUCCESS(rc)) DBGFR3AddrFromFlat(pUVM, pHitAddress, GCPtrHit); } return rc; }
/** * Read guest memory. * * @returns VBox status code. * @param pUVM The user mode VM handle. * @param idCpu The ID of the CPU context to read memory from. * @param pAddress Where to start reading. * @param pvBuf Where to store the data we've read. * @param cbRead The number of bytes to read. */ static DECLCALLBACK(int) dbgfR3MemRead(PUVM pUVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, void *pvBuf, size_t cbRead) { PVM pVM = pUVM->pVM; VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); Assert(idCpu == VMMGetCpuId(pVM)); /* * Validate the input we use, PGM does the rest. */ if (!DBGFR3AddrIsValid(pUVM, pAddress)) return VERR_INVALID_POINTER; if (!VALID_PTR(pvBuf)) return VERR_INVALID_POINTER; /* * HMA is special */ int rc; if (DBGFADDRESS_IS_HMA(pAddress)) { if (DBGFADDRESS_IS_PHYS(pAddress)) rc = VERR_INVALID_POINTER; else rc = MMR3HyperReadGCVirt(pVM, pvBuf, pAddress->FlatPtr, cbRead); } else { /* * Select DBGF worker by addressing mode. */ PVMCPU pVCpu = VMMGetCpuById(pVM, idCpu); PGMMODE enmMode = PGMGetGuestMode(pVCpu); if ( enmMode == PGMMODE_REAL || enmMode == PGMMODE_PROTECTED || DBGFADDRESS_IS_PHYS(pAddress) ) rc = PGMPhysSimpleReadGCPhys(pVM, pvBuf, pAddress->FlatPtr, cbRead); else { #if GC_ARCH_BITS > 32 if ( ( pAddress->FlatPtr >= _4G || pAddress->FlatPtr + cbRead > _4G) && enmMode != PGMMODE_AMD64 && enmMode != PGMMODE_AMD64_NX) return VERR_PAGE_TABLE_NOT_PRESENT; #endif rc = PGMPhysSimpleReadGCPtr(pVCpu, pvBuf, pAddress->FlatPtr, cbRead); } } return rc; }
/** * Called on the EMT for the VCpu. * * @returns VBox status code. * * @param pVM The VM handle. * @param idCpu The ID of the CPU context. * @param pAddress The address. * @param fReadOnly Whether returning a read-only page is fine or not. * @param ppvR3Ptr Where to return the address. */ static DECLCALLBACK(int) dbgfR3AddrToVolatileR3PtrOnVCpu(PVM pVM, VMCPUID idCpu, PDBGFADDRESS pAddress, bool fReadOnly, void **ppvR3Ptr) { Assert(idCpu == VMMGetCpuId(pVM)); int rc; if (pAddress->fFlags & DBGFADDRESS_FLAGS_HMA) { rc = VERR_NOT_SUPPORTED; /** @todo create some dedicated errors for this stuff. */ /** @todo this may assert, create a debug version of this which doesn't. */ if (MMHyperIsInsideArea(pVM, pAddress->FlatPtr)) { void *pv = MMHyperRCToCC(pVM, (RTRCPTR)pAddress->FlatPtr); if (pv) { *ppvR3Ptr = pv; rc = VINF_SUCCESS; } } } else { /* * This is a tad ugly, but it gets the job done. */ PGMPAGEMAPLOCK Lock; if (pAddress->fFlags & DBGFADDRESS_FLAGS_PHYS) { if (fReadOnly) rc = PGMPhysGCPhys2CCPtrReadOnly(pVM, pAddress->FlatPtr, (void const **)ppvR3Ptr, &Lock); else rc = PGMPhysGCPhys2CCPtr(pVM, pAddress->FlatPtr, ppvR3Ptr, &Lock); } else { PVMCPU pVCpu = VMMGetCpuById(pVM, idCpu); if (fReadOnly) rc = PGMPhysGCPtr2CCPtrReadOnly(pVCpu, pAddress->FlatPtr, (void const **)ppvR3Ptr, &Lock); else rc = PGMPhysGCPtr2CCPtr(pVCpu, pAddress->FlatPtr, ppvR3Ptr, &Lock); } if (RT_SUCCESS(rc)) PGMPhysReleasePageMappingLock(pVM, &Lock); } return rc; }
/** * Executes the VMMDEV_TESTING_CMD_VALUE_REG command when the data is ready. * * @param pDevIns The PDM device instance. * @param pThis The instance VMMDev data. */ static void vmmdevTestingCmdExec_ValueReg(PPDMDEVINS pDevIns, VMMDevState *pThis) { char *pszRegNm = strchr(pThis->TestingData.String.sz, ':'); if (pszRegNm) { *pszRegNm++ = '\0'; pszRegNm = RTStrStrip(pszRegNm); } char *pszValueNm = RTStrStrip(pThis->TestingData.String.sz); size_t const cchValueNm = strlen(pszValueNm); if (cchValueNm && pszRegNm && *pszRegNm) { PUVM pUVM = PDMDevHlpGetUVM(pDevIns); PVM pVM = PDMDevHlpGetVM(pDevIns); VMCPUID idCpu = VMMGetCpuId(pVM); uint64_t u64Value; int rc2 = DBGFR3RegNmQueryU64(pUVM, idCpu, pszRegNm, &u64Value); if (RT_SUCCESS(rc2)) { const char *pszWarn = rc2 == VINF_DBGF_TRUNCATED_REGISTER ? " truncated" : ""; #if 1 /*!RTTestValue format*/ char szFormat[128], szValue[128]; RTStrPrintf(szFormat, sizeof(szFormat), "%%VR{%s}", pszRegNm); rc2 = DBGFR3RegPrintf(pUVM, idCpu, szValue, sizeof(szValue), szFormat); if (RT_SUCCESS(rc2)) VMMDEV_TESTING_OUTPUT(("testing: VALUE '%s'%*s: %16s {reg=%s}%s\n", pszValueNm, (ssize_t)cchValueNm - 12 > 48 ? 0 : 48 - ((ssize_t)cchValueNm - 12), "", szValue, pszRegNm, pszWarn)); else #endif VMMDEV_TESTING_OUTPUT(("testing: VALUE '%s'%*s: %'9llu (%#llx) [0] {reg=%s}%s\n", pszValueNm, (ssize_t)cchValueNm - 12 > 48 ? 0 : 48 - ((ssize_t)cchValueNm - 12), "", u64Value, u64Value, pszRegNm, pszWarn)); } else VMMDEV_TESTING_OUTPUT(("testing: error querying register '%s' for value '%s': %Rrc\n", pszRegNm, pszValueNm, rc2)); } else VMMDEV_TESTING_OUTPUT(("testing: malformed register value '%s'/'%s'\n", pszValueNm, pszRegNm)); }
/** @interface_method_impl{PDMAPICHLPR0,pfnGetCpuId} */ static DECLCALLBACK(VMCPUID) pdmR0ApicHlp_GetCpuId(PPDMDEVINS pDevIns) { PDMDEV_ASSERT_DEVINS(pDevIns); return VMMGetCpuId(pDevIns->Internal.s.pVMR0); }
/** * Check all registered modules for changes. * * @returns VBox status code. * @param pVM Pointer to the VM */ VMMR3DECL(int) PGMR3SharedModuleCheckAll(PVM pVM) { /* Queue the actual registration as we are under the IOM lock right now. Perform this operation on the way out. */ return VMR3ReqCallNoWait(pVM, VMCPUID_ANY_QUEUE, (PFNRT)pgmR3CheckSharedModulesHelper, 2, pVM, VMMGetCpuId(pVM)); }
/** * This is called on each EMT and will beat TM. * * @returns VINF_SUCCESS, test failure is reported via RTTEST. * @param pVM Pointer to the VM. * @param hTest The test handle. */ DECLCALLBACK(int) tstTMWorker(PVM pVM, RTTEST hTest) { VMCPUID idCpu = VMMGetCpuId(pVM); RTTestPrintfNl(hTest, RTTESTLVL_ALWAYS, "idCpu=%d STARTING\n", idCpu); /* * Create the test set. */ int rc; PTMTIMER apTimers[5]; for (size_t i = 0; i < RT_ELEMENTS(apTimers); i++) { rc = TMR3TimerCreateInternal(pVM, i & 1 ? TMCLOCK_VIRTUAL : TMCLOCK_VIRTUAL_SYNC, tstTMDummyCallback, NULL, "test timer", &apTimers[i]); RTTEST_CHECK_RET(hTest, RT_SUCCESS(rc), rc); } /* * The run loop. */ unsigned uPrevPct = 0; uint32_t const cLoops = 100000; for (uint32_t iLoop = 0; iLoop < cLoops; iLoop++) { size_t cLeft = RT_ELEMENTS(apTimers); unsigned i = iLoop % RT_ELEMENTS(apTimers); while (cLeft-- > 0) { PTMTIMER pTimer = apTimers[i]; if ( cLeft == RT_ELEMENTS(apTimers) / 2 && TMTimerIsActive(pTimer)) { rc = TMTimerStop(pTimer); RTTEST_CHECK_MSG(hTest, RT_SUCCESS(rc), (hTest, "TMTimerStop: %Rrc\n", rc)); } else { rc = TMTimerSetMicro(pTimer, 50 + cLeft); RTTEST_CHECK_MSG(hTest, RT_SUCCESS(rc), (hTest, "TMTimerSetMicro: %Rrc\n", rc)); } /* next */ i = (i + 1) % RT_ELEMENTS(apTimers); } if (i % 3) TMR3TimerQueuesDo(pVM); /* Progress report. */ unsigned uPct = (unsigned)(100.0 * iLoop / cLoops); if (uPct != uPrevPct) { uPrevPct = uPct; if (!(uPct % 10)) RTTestPrintfNl(hTest, RTTESTLVL_ALWAYS, "idCpu=%d - %3u%%\n", idCpu, uPct); } } RTTestPrintfNl(hTest, RTTESTLVL_ALWAYS, "idCpu=%d DONE\n", idCpu); return 0; }