diff options
Diffstat (limited to 'src/VBox/VMM/VMMR3/PGM.cpp')
| -rw-r--r-- | src/VBox/VMM/VMMR3/PGM.cpp | 332 |
1 files changed, 146 insertions, 186 deletions
diff --git a/src/VBox/VMM/VMMR3/PGM.cpp b/src/VBox/VMM/VMMR3/PGM.cpp index b0487c62..126a06d1 100644 --- a/src/VBox/VMM/VMMR3/PGM.cpp +++ b/src/VBox/VMM/VMMR3/PGM.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2011 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -81,6 +81,12 @@ * code to do the work. All memory use for those page tables is located below * 4GB (this includes page tables for guest context mappings). * + * Note! The intermediate memory context is also used for 64-bit guest + * execution on 32-bit hosts. Because we need to load 64-bit registers + * prior to switching to guest context, we need to be in 64-bit mode + * first. So, HM has some 64-bit worker routines in VMMRC.rc that get + * invoked via the special world switcher code in LegacyToAMD64.asm. + * * * @subsection subsec_pgm_int_gc Guest Context Mappings * @@ -621,9 +627,10 @@ #endif #include <VBox/vmm/selm.h> #include <VBox/vmm/ssm.h> -#include <VBox/vmm/hwaccm.h> +#include <VBox/vmm/hm.h> #include "PGMInternal.h" #include <VBox/vmm/vm.h> +#include <VBox/vmm/uvm.h> #include "PGMInline.h" #include <VBox/dbg.h> @@ -652,22 +659,20 @@ static DECLCALLBACK(int) pgmR3RelocatePhysHandler(PAVLROGCPHYSNODECORE pNode, v static DECLCALLBACK(int) pgmR3RelocateVirtHandler(PAVLROGCPTRNODECORE pNode, void *pvUser); static DECLCALLBACK(int) pgmR3RelocateHyperVirtHandler(PAVLROGCPTRNODECORE pNode, void *pvUser); #ifdef VBOX_STRICT -static DECLCALLBACK(void) pgmR3ResetNoMorePhysWritesFlag(PVM pVM, VMSTATE enmState, VMSTATE enmOldState, void *pvUser); +static FNVMATSTATE pgmR3ResetNoMorePhysWritesFlag; #endif static int pgmR3ModeDataInit(PVM pVM, bool fResolveGCAndR0); static void pgmR3ModeDataSwitch(PVM pVM, PVMCPU pVCpu, PGMMODE enmShw, PGMMODE enmGst); static PGMMODE pgmR3CalcShadowMode(PVM pVM, PGMMODE enmGuestMode, SUPPAGINGMODE enmHostMode, PGMMODE enmShadowMode, VMMSWITCHER *penmSwitcher); #ifdef VBOX_WITH_DEBUGGER -/** @todo Convert the first two commands to 'info' items. */ -static DECLCALLBACK(int) pgmR3CmdRam(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs); -static DECLCALLBACK(int) pgmR3CmdError(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs); -static DECLCALLBACK(int) pgmR3CmdSync(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs); -static DECLCALLBACK(int) pgmR3CmdSyncAlways(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs); +static FNDBGCCMD pgmR3CmdError; +static FNDBGCCMD pgmR3CmdSync; +static FNDBGCCMD pgmR3CmdSyncAlways; # ifdef VBOX_STRICT -static DECLCALLBACK(int) pgmR3CmdAssertCR3(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs); +static FNDBGCCMD pgmR3CmdAssertCR3; # endif -static DECLCALLBACK(int) pgmR3CmdPhysToFile(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs); +static FNDBGCCMD pgmR3CmdPhysToFile; #endif @@ -702,7 +707,6 @@ static const DBGCVARDESC g_aPgmCountPhysWritesArgs[] = static const DBGCCMD g_aCmds[] = { /* pszCmd, cArgsMin, cArgsMax, paArgDesc, cArgDescs, fFlags, pfnHandler pszSyntax, ....pszDescription */ - { "pgmram", 0, 0, NULL, 0, 0, pgmR3CmdRam, "", "Display the ram ranges." }, { "pgmsync", 0, 0, NULL, 0, 0, pgmR3CmdSync, "", "Sync the CR3 page." }, { "pgmerror", 0, 1, &g_aPgmErrorArgs[0], 1, 0, pgmR3CmdError, "", "Enables inject runtime of errors into parts of PGM." }, { "pgmerroroff", 0, 1, &g_aPgmErrorArgs[0], 1, 0, pgmR3CmdError, "", "Disables inject runtime errors into parts of PGM." }, @@ -1227,9 +1231,6 @@ VMMR3DECL(int) PGMR3Init(PVM pVM) /* * Init the structure. */ -#ifdef PGM_WITHOUT_MAPPINGS - pVM->pgm.s.fMappingsDisabled = true; -#endif pVM->pgm.s.offVM = RT_OFFSETOF(VM, pgm.s); pVM->pgm.s.offVCpuPGM = RT_OFFSETOF(VMCPU, pgm.s); @@ -1368,7 +1369,7 @@ VMMR3DECL(int) PGMR3Init(PVM pVM) * Register callbacks, string formatters and the saved state data unit. */ #ifdef VBOX_STRICT - VMR3AtStateRegister(pVM, pgmR3ResetNoMorePhysWritesFlag, NULL); + VMR3AtStateRegister(pVM->pUVM, pgmR3ResetNoMorePhysWritesFlag, NULL); #endif PGMRegisterStringFormatTypes(); @@ -1890,6 +1891,8 @@ static int pgmR3InitStats(PVM pVM) PGM_REG_PROFILE(&pCpuStats->StatRZTrap0eTime2OutOfSyncHndObs, "/PGM/CPU%u/RZ/Trap0e/Time2/OutOfSyncObsHnd", "Profiling of the Trap0eHandler body when the cause is an obsolete handler page."); PGM_REG_PROFILE(&pCpuStats->StatRZTrap0eTime2SyncPT, "/PGM/CPU%u/RZ/Trap0e/Time2/SyncPT", "Profiling of the Trap0eHandler body when the cause is lazy syncing of a PT."); PGM_REG_PROFILE(&pCpuStats->StatRZTrap0eTime2WPEmulation, "/PGM/CPU%u/RZ/Trap0e/Time2/WPEmulation", "Profiling of the Trap0eHandler body when the cause is CR0.WP emulation."); + PGM_REG_PROFILE(&pCpuStats->StatRZTrap0eTime2Wp0RoUsHack, "/PGM/CPU%u/RZ/Trap0e/Time2/WP0R0USHack", "Profiling of the Trap0eHandler body when the cause is CR0.WP and netware hack to be enabled."); + PGM_REG_PROFILE(&pCpuStats->StatRZTrap0eTime2Wp0RoUsUnhack, "/PGM/CPU%u/RZ/Trap0e/Time2/WP0R0USUnhack", "Profiling of the Trap0eHandler body when the cause is CR0.WP and netware hack to be disabled."); PGM_REG_COUNTER(&pCpuStats->StatRZTrap0eConflicts, "/PGM/CPU%u/RZ/Trap0e/Conflicts", "The number of times #PF was caused by an undetected conflict."); PGM_REG_COUNTER(&pCpuStats->StatRZTrap0eHandlersMapping, "/PGM/CPU%u/RZ/Trap0e/Handlers/Mapping", "Number of traps due to access handlers in mappings."); PGM_REG_COUNTER(&pCpuStats->StatRZTrap0eHandlersOutOfSync, "/PGM/CPU%u/RZ/Trap0e/Handlers/OutOfSync", "Number of traps due to out-of-sync handled pages."); @@ -2164,6 +2167,7 @@ VMMR3DECL(int) PGMR3InitFinalize(PVM pVM) pVM->pgm.s.HCPhysInvMmioPg |= UINT64_C(0x000f0000000000); } + /** @todo query from CPUM. */ pVM->pgm.s.GCPhysInvAddrMask = 0; for (uint32_t iBit = cMaxPhysAddrWidth; iBit < 64; iBit++) pVM->pgm.s.GCPhysInvAddrMask |= RT_BIT_64(iBit); @@ -2238,13 +2242,13 @@ VMMR3_INT_DECL(int) PGMR3InitCompleted(PVM pVM, VMINITCOMPLETED enmWhat) { switch (enmWhat) { - case VMINITCOMPLETED_HWACCM: + case VMINITCOMPLETED_HM: #ifdef VBOX_WITH_PCI_PASSTHROUGH if (pVM->pgm.s.fPciPassthrough) { AssertLogRelReturn(pVM->pgm.s.fRamPreAlloc, VERR_PCI_PASSTHROUGH_NO_RAM_PREALLOC); - AssertLogRelReturn(HWACCMIsEnabled(pVM), VERR_PCI_PASSTHROUGH_NO_HWACCM); - AssertLogRelReturn(HWACCMIsNestedPagingActive(pVM), VERR_PCI_PASSTHROUGH_NO_NESTED_PAGING); + AssertLogRelReturn(HMIsEnabled(pVM), VERR_PCI_PASSTHROUGH_NO_HM); + AssertLogRelReturn(HMIsNestedPagingActive(pVM), VERR_PCI_PASSTHROUGH_NO_NESTED_PAGING); /* * Report assignments to the IOMMU (hope that's good enough for now). @@ -2376,7 +2380,7 @@ VMMR3DECL(void) PGMR3Relocate(PVM pVM, RTGCINTPTR offDelta) */ pVM->pgm.s.pvZeroPgR0 = MMHyperR3ToR0(pVM, pVM->pgm.s.pvZeroPgR3); #ifdef VBOX_WITH_2X_4GB_ADDR_SPACE - AssertRelease(pVM->pgm.s.pvZeroPgR0 != NIL_RTR0PTR || !VMMIsHwVirtExtForced(pVM)); + AssertRelease(pVM->pgm.s.pvZeroPgR0 != NIL_RTR0PTR || !HMIsEnabled(pVM)); #else AssertRelease(pVM->pgm.s.pvZeroPgR0 != NIL_RTR0PTR); #endif @@ -2470,7 +2474,7 @@ static DECLCALLBACK(int) pgmR3RelocateHyperVirtHandler(PAVLROGCPTRNODECORE pNode * @param pVM Pointer to the VM. * @param pVCpu Pointer to the VMCPU. */ -VMMR3DECL(void) PGMR3ResetUnpluggedCpu(PVM pVM, PVMCPU pVCpu) +VMMR3DECL(void) PGMR3ResetCpu(PVM pVM, PVMCPU pVCpu) { int rc = PGM_GST_PFN(Exit, pVCpu)(pVCpu); AssertRC(rc); @@ -2504,10 +2508,8 @@ VMMR3DECL(void) PGMR3ResetUnpluggedCpu(PVM pVM, PVMCPU pVCpu) * * @param pVM Pointer to the VM. */ -VMMR3DECL(void) PGMR3Reset(PVM pVM) +VMMR3_INT_DECL(void) PGMR3Reset(PVM pVM) { - int rc; - LogFlow(("PGMR3Reset:\n")); VM_ASSERT_EMT(pVM); @@ -2528,13 +2530,13 @@ VMMR3DECL(void) PGMR3Reset(PVM pVM) for (VMCPUID i = 0; i < pVM->cCpus; i++) { PVMCPU pVCpu = &pVM->aCpus[i]; - rc = PGM_GST_PFN(Exit, pVCpu)(pVCpu); - AssertRC(rc); + int rc = PGM_GST_PFN(Exit, pVCpu)(pVCpu); + AssertReleaseRC(rc); } #ifdef DEBUG - DBGFR3InfoLog(pVM, "mappings", NULL); - DBGFR3InfoLog(pVM, "handlers", "all nostat"); + DBGFR3_INFO_LOG(pVM, "mappings", NULL); + DBGFR3_INFO_LOG(pVM, "handlers", "all nostat"); #endif /* @@ -2544,8 +2546,8 @@ VMMR3DECL(void) PGMR3Reset(PVM pVM) { PVMCPU pVCpu = &pVM->aCpus[i]; - rc = PGMR3ChangeMode(pVM, pVCpu, PGMMODE_REAL); - AssertRC(rc); + int rc = PGMR3ChangeMode(pVM, pVCpu, PGMMODE_REAL); + AssertReleaseRC(rc); STAM_REL_COUNTER_RESET(&pVCpu->pgm.s.cGuestModeChanges); STAM_REL_COUNTER_RESET(&pVCpu->pgm.s.cA20Changes); @@ -2577,21 +2579,36 @@ VMMR3DECL(void) PGMR3Reset(PVM pVM) pVCpu->pgm.s.fSyncFlags |= PGM_SYNC_UPDATE_PAGE_BIT_VIRTUAL; VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3); pgmR3RefreshShadowModeAfterA20Change(pVCpu); - HWACCMFlushTLB(pVCpu); + HMFlushTLB(pVCpu); #endif } } - /* - * Reset (zero) RAM and shadow ROM pages. - */ - rc = pgmR3PhysRamReset(pVM); - if (RT_SUCCESS(rc)) - rc = pgmR3PhysRomReset(pVM); + pgmUnlock(pVM); +} - pgmUnlock(pVM); - AssertReleaseRC(rc); +/** + * Memory setup after VM construction or reset. + * + * @param pVM Pointer to the VM. + * @param fAtReset Indicates the context, after reset if @c true or after + * construction if @c false. + */ +VMMR3_INT_DECL(void) PGMR3MemSetup(PVM pVM, bool fAtReset) +{ + if (fAtReset) + { + pgmLock(pVM); + + int rc = pgmR3PhysRamZeroAll(pVM); + AssertReleaseRC(rc); + + rc = pgmR3PhysRomReset(pVM); + AssertReleaseRC(rc); + + pgmUnlock(pVM); + } } @@ -2600,11 +2617,11 @@ VMMR3DECL(void) PGMR3Reset(PVM pVM) * VM state change callback for clearing fNoMorePhysWrites after * a snapshot has been created. */ -static DECLCALLBACK(void) pgmR3ResetNoMorePhysWritesFlag(PVM pVM, VMSTATE enmState, VMSTATE enmOldState, void *pvUser) +static DECLCALLBACK(void) pgmR3ResetNoMorePhysWritesFlag(PUVM pUVM, VMSTATE enmState, VMSTATE enmOldState, void *pvUser) { if ( enmState == VMSTATE_RUNNING || enmState == VMSTATE_RESUMING) - pVM->pgm.s.fNoMorePhysWrites = false; + pUVM->pVM->pgm.s.fNoMorePhysWrites = false; NOREF(enmOldState); NOREF(pvUser); } #endif @@ -2719,6 +2736,7 @@ static DECLCALLBACK(void) pgmR3PhysInfo(PVM pVM, PCDBGFINFOHLP pHlp, const char pCur->pszDesc); } + /** * Dump the page directory to the log. * @@ -3172,7 +3190,7 @@ static PGMMODE pgmR3CalcShadowMode(PVM pVM, PGMMODE enmGuestMode, SUPPAGINGMODE case PGMMODE_REAL: case PGMMODE_PROTECTED: if ( enmShadowMode != PGMMODE_INVALID - && !HWACCMIsEnabled(pVM) /* always switch in hwaccm mode! */) + && !HMIsEnabled(pVM) /* always switch in hm mode! */) break; /* (no change) */ switch (enmHostMode) @@ -3327,9 +3345,9 @@ static PGMMODE pgmR3CalcShadowMode(PVM pVM, PGMMODE enmGuestMode, SUPPAGINGMODE return PGMMODE_INVALID; } /* Override the shadow mode is nested paging is active. */ - pVM->pgm.s.fNestedPaging = HWACCMIsNestedPagingActive(pVM); + pVM->pgm.s.fNestedPaging = HMIsNestedPagingActive(pVM); if (pVM->pgm.s.fNestedPaging) - enmShadowMode = HWACCMGetShwPagingMode(pVM); + enmShadowMode = HMGetShwPagingMode(pVM); *penmSwitcher = enmSwitcher; return enmShadowMode; @@ -3366,7 +3384,8 @@ VMMR3DECL(int) PGMR3ChangeMode(PVM pVM, PVMCPU pVCpu, PGMMODE enmGuestMode) enmShadowMode = pgmR3CalcShadowMode(pVM, enmGuestMode, pVM->pgm.s.enmHostMode, pVCpu->pgm.s.enmShadowMode, &enmSwitcher); #ifdef VBOX_WITH_RAW_MODE - if (enmSwitcher != VMMSWITCHER_INVALID) + if ( enmSwitcher != VMMSWITCHER_INVALID + && !HMIsEnabled(pVM)) { /* * Select new switcher. @@ -3561,7 +3580,7 @@ VMMR3DECL(int) PGMR3ChangeMode(PVM pVM, PVMCPU pVCpu, PGMMODE enmGuestMode) CPUMGetGuestCpuId(pVCpu, 1, &u32Dummy, &u32Dummy, &u32Dummy, &u32Features); if (!(u32Features & X86_CPUID_FEATURE_EDX_PAE)) return VMSetRuntimeError(pVM, VMSETRTERR_FLAGS_FATAL, "PAEmode", - N_("The guest is trying to switch to the PAE mode which is currently disabled by default in VirtualBox. PAE support can be enabled using the VM settings (General/Advanced)")); + N_("The guest is trying to switch to the PAE mode which is currently disabled by default in VirtualBox. PAE support can be enabled using the VM settings (System/Processor)")); GCPhysCR3 = CPUMGetGuestCR3(pVCpu) & X86_CR3_PAE_PAGE_MASK; rc = PGM_GST_NAME_PAE(Enter)(pVCpu, GCPhysCR3); @@ -3628,8 +3647,8 @@ VMMR3DECL(int) PGMR3ChangeMode(PVM pVM, PVMCPU pVCpu, PGMMODE enmGuestMode) rc = VINF_SUCCESS; } - /* Notify HWACCM as well. */ - HWACCMR3PagingModeChanged(pVM, pVCpu, pVCpu->pgm.s.enmShadowMode, pVCpu->pgm.s.enmGuestMode); + /* Notify HM as well. */ + HMR3PagingModeChanged(pVM, pVCpu, pVCpu->pgm.s.enmShadowMode, pVCpu->pgm.s.enmGuestMode); return rc; } @@ -3665,7 +3684,7 @@ int pgmR3ReEnterShadowModeAfterPoolFlush(PVM pVM, PVMCPU pVCpu) { pVCpu->pgm.s.enmShadowMode = PGMMODE_INVALID; int rc = PGMR3ChangeMode(pVM, pVCpu, PGMGetGuestMode(pVCpu)); - Assert(VMCPU_FF_ISSET(pVCpu, VMCPU_FF_PGM_SYNC_CR3)); + Assert(VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3)); AssertRCReturn(rc, rc); AssertRCSuccessReturn(rc, VERR_IPE_UNEXPECTED_INFO_STATUS); @@ -3695,75 +3714,27 @@ void pgmR3RefreshShadowModeAfterA20Change(PVMCPU pVCpu) #ifdef VBOX_WITH_DEBUGGER /** - * The '.pgmram' command. - * - * @returns VBox status. - * @param pCmd Pointer to the command descriptor (as registered). - * @param pCmdHlp Pointer to command helper functions. - * @param pVM Pointer to the current VM (if any). - * @param paArgs Pointer to (readonly) array of arguments. - * @param cArgs Number of arguments in the array. + * @callback_method_impl{FNDBGCCMD, The '.pgmerror' and '.pgmerroroff' commands.} */ -static DECLCALLBACK(int) pgmR3CmdRam(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs) +static DECLCALLBACK(int) pgmR3CmdError(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) { /* * Validate input. */ - NOREF(pCmd); NOREF(paArgs); NOREF(cArgs); - if (!pVM) - return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: The command requires a VM to be selected.\n"); - if (!pVM->pgm.s.pRamRangesXR3) - return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Sorry, no Ram is registered.\n"); - - /* - * Dump the ranges. - */ - int rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "From - To (incl) pvHC\n"); - PPGMRAMRANGE pRam; - for (pRam = pVM->pgm.s.pRamRangesXR3; pRam; pRam = pRam->pNextR3) - { - rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, - "%RGp - %RGp %p\n", - pRam->GCPhys, pRam->GCPhysLast, pRam->pvR3); - if (RT_FAILURE(rc)) - return rc; - } - - return VINF_SUCCESS; -} - - -/** - * The '.pgmerror' and '.pgmerroroff' commands. - * - * @returns VBox status. - * @param pCmd Pointer to the command descriptor (as registered). - * @param pCmdHlp Pointer to command helper functions. - * @param pVM Pointer to the current VM (if any). - * @param paArgs Pointer to (readonly) array of arguments. - * @param cArgs Number of arguments in the array. - */ -static DECLCALLBACK(int) pgmR3CmdError(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs) -{ - /* - * Validate input. - */ - if (!pVM) - return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: The command requires a VM to be selected.\n"); - AssertReturn(cArgs == 0 || (cArgs == 1 && paArgs[0].enmType == DBGCVAR_TYPE_STRING), - pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Hit bug in the parser.\n")); + DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM); + PVM pVM = pUVM->pVM; + DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, cArgs == 0 || (cArgs == 1 && paArgs[0].enmType == DBGCVAR_TYPE_STRING)); if (!cArgs) { /* * Print the list of error injection locations with status. */ - pCmdHlp->pfnPrintf(pCmdHlp, NULL, "PGM error inject locations:\n"); - pCmdHlp->pfnPrintf(pCmdHlp, NULL, " handy - %RTbool\n", pVM->pgm.s.fErrInjHandyPages); + DBGCCmdHlpPrintf(pCmdHlp, "PGM error inject locations:\n"); + DBGCCmdHlpPrintf(pCmdHlp, " handy - %RTbool\n", pVM->pgm.s.fErrInjHandyPages); } else { - /* * String switch on where to inject the error. */ @@ -3772,150 +3743,138 @@ static DECLCALLBACK(int) pgmR3CmdError(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM if (!strcmp(pszWhere, "handy")) ASMAtomicWriteBool(&pVM->pgm.s.fErrInjHandyPages, fNewState); else - return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid 'where' value: %s.\n", pszWhere); - pCmdHlp->pfnPrintf(pCmdHlp, NULL, "done\n"); + return DBGCCmdHlpPrintf(pCmdHlp, "error: Invalid 'where' value: %s.\n", pszWhere); + DBGCCmdHlpPrintf(pCmdHlp, "done\n"); } return VINF_SUCCESS; } /** - * The '.pgmsync' command. - * - * @returns VBox status. - * @param pCmd Pointer to the command descriptor (as registered). - * @param pCmdHlp Pointer to command helper functions. - * @param pVM Pointer to the current VM (if any). - * @param paArgs Pointer to (readonly) array of arguments. - * @param cArgs Number of arguments in the array. + * @callback_method_impl{FNDBGCCMD, The '.pgmsync' command.} */ -static DECLCALLBACK(int) pgmR3CmdSync(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs) +static DECLCALLBACK(int) pgmR3CmdSync(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) { - /** @todo SMP support */ - /* * Validate input. */ NOREF(pCmd); NOREF(paArgs); NOREF(cArgs); - if (!pVM) - return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: The command requires a VM to be selected.\n"); - - PVMCPU pVCpu = &pVM->aCpus[0]; + DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM); + PVMCPU pVCpu = VMMR3GetCpuByIdU(pUVM, DBGCCmdHlpGetCurrentCpu(pCmdHlp)); + if (!pVCpu) + return DBGCCmdHlpFail(pCmdHlp, pCmd, "Invalid CPU ID"); /* * Force page directory sync. */ VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3); - int rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Forcing page directory sync.\n"); + int rc = DBGCCmdHlpPrintf(pCmdHlp, "Forcing page directory sync.\n"); if (RT_FAILURE(rc)) return rc; return VINF_SUCCESS; } - #ifdef VBOX_STRICT + /** - * The '.pgmassertcr3' command. - * - * @returns VBox status. - * @param pCmd Pointer to the command descriptor (as registered). - * @param pCmdHlp Pointer to command helper functions. - * @param pVM Pointer to the current VM (if any). - * @param paArgs Pointer to (readonly) array of arguments. - * @param cArgs Number of arguments in the array. + * EMT callback for pgmR3CmdAssertCR3. + * + * @returns VBox status code. + * @param pUVM The user mode VM handle. + * @param pcErrors Where to return the error count. */ -static DECLCALLBACK(int) pgmR3CmdAssertCR3(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs) +static DECLCALLBACK(int) pgmR3CmdAssertCR3EmtWorker(PUVM pUVM, unsigned *pcErrors) { - /** @todo SMP support!! */ + PVM pVM = pUVM->pVM; + VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); + PVMCPU pVCpu = VMMGetCpu(pVM); + + *pcErrors = PGMAssertCR3(pVM, pVCpu, CPUMGetGuestCR3(pVCpu), CPUMGetGuestCR4(pVCpu)); + + return VINF_SUCCESS; +} + +/** + * @callback_method_impl{FNDBGCCMD, The '.pgmassertcr3' command.} + */ +static DECLCALLBACK(int) pgmR3CmdAssertCR3(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) +{ /* * Validate input. */ NOREF(pCmd); NOREF(paArgs); NOREF(cArgs); - if (!pVM) - return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: The command requires a VM to be selected.\n"); - - PVMCPU pVCpu = &pVM->aCpus[0]; + DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM); - int rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Checking shadow CR3 page tables for consistency.\n"); + int rc = DBGCCmdHlpPrintf(pCmdHlp, "Checking shadow CR3 page tables for consistency.\n"); if (RT_FAILURE(rc)) return rc; - PGMAssertCR3(pVM, pVCpu, CPUMGetGuestCR3(pVCpu), CPUMGetGuestCR4(pVCpu)); - - return VINF_SUCCESS; + unsigned cErrors = 0; + rc = VMR3ReqCallWaitU(pUVM, DBGCCmdHlpGetCurrentCpu(pCmdHlp), (PFNRT)pgmR3CmdAssertCR3EmtWorker, 2, pUVM, &cErrors); + if (RT_FAILURE(rc)) + return DBGCCmdHlpFail(pCmdHlp, pCmd, "VMR3ReqCallWaitU failed: %Rrc", rc); + if (cErrors > 0) + return DBGCCmdHlpFail(pCmdHlp, pCmd, "PGMAssertCR3: %u error(s)", cErrors); + return DBGCCmdHlpPrintf(pCmdHlp, "PGMAssertCR3: OK\n"); } -#endif /* VBOX_STRICT */ +#endif /* VBOX_STRICT */ /** - * The '.pgmsyncalways' command. - * - * @returns VBox status. - * @param pCmd Pointer to the command descriptor (as registered). - * @param pCmdHlp Pointer to command helper functions. - * @param pVM Pointer to the current VM (if any). - * @param paArgs Pointer to (readonly) array of arguments. - * @param cArgs Number of arguments in the array. + * @callback_method_impl{FNDBGCCMD, The '.pgmsyncalways' command.} */ -static DECLCALLBACK(int) pgmR3CmdSyncAlways(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs) +static DECLCALLBACK(int) pgmR3CmdSyncAlways(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) { - /** @todo SMP support!! */ - PVMCPU pVCpu = &pVM->aCpus[0]; - /* * Validate input. */ NOREF(pCmd); NOREF(paArgs); NOREF(cArgs); - if (!pVM) - return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: The command requires a VM to be selected.\n"); + DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM); + PVMCPU pVCpu = VMMR3GetCpuByIdU(pUVM, DBGCCmdHlpGetCurrentCpu(pCmdHlp)); + if (!pVCpu) + return DBGCCmdHlpFail(pCmdHlp, pCmd, "Invalid CPU ID"); /* * Force page directory sync. */ + int rc; if (pVCpu->pgm.s.fSyncFlags & PGM_SYNC_ALWAYS) { ASMAtomicAndU32(&pVCpu->pgm.s.fSyncFlags, ~PGM_SYNC_ALWAYS); - return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Disabled permanent forced page directory syncing.\n"); + rc = DBGCCmdHlpPrintf(pCmdHlp, "Disabled permanent forced page directory syncing.\n"); } else { ASMAtomicOrU32(&pVCpu->pgm.s.fSyncFlags, PGM_SYNC_ALWAYS); VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3); - return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Enabled permanent forced page directory syncing.\n"); + rc = DBGCCmdHlpPrintf(pCmdHlp, "Enabled permanent forced page directory syncing.\n"); } + return rc; } /** - * The '.pgmphystofile' command. - * - * @returns VBox status. - * @param pCmd Pointer to the command descriptor (as registered). - * @param pCmdHlp Pointer to command helper functions. - * @param pVM Pointer to the current VM (if any). - * @param paArgs Pointer to (readonly) array of arguments. - * @param cArgs Number of arguments in the array. + * @callback_method_impl{FNDBGCCMD, The '.pgmphystofile' command.} */ -static DECLCALLBACK(int) pgmR3CmdPhysToFile(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs) +static DECLCALLBACK(int) pgmR3CmdPhysToFile(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) { /* * Validate input. */ NOREF(pCmd); - if (!pVM) - return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: The command requires a VM to be selected.\n"); - if ( cArgs < 1 - || cArgs > 2 - || paArgs[0].enmType != DBGCVAR_TYPE_STRING - || ( cArgs > 1 - && paArgs[1].enmType != DBGCVAR_TYPE_STRING)) - return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: parser error, invalid arguments.\n"); - if ( cArgs >= 2 - && strcmp(paArgs[1].u.pszString, "nozero")) - return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid 2nd argument '%s', must be 'nozero'.\n", paArgs[1].u.pszString); + DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM); + PVM pVM = pUVM->pVM; + DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, cArgs == 1 || cArgs == 2); + DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, paArgs[0].enmType != DBGCVAR_TYPE_STRING); + if (cArgs == 2) + { + DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 1, paArgs[2].enmType != DBGCVAR_TYPE_STRING); + if (strcmp(paArgs[1].u.pszString, "nozero")) + return DBGCCmdHlpFail(pCmdHlp, pCmd, "Invalid 2nd argument '%s', must be 'nozero'.\n", paArgs[1].u.pszString); + } bool fIncZeroPgs = cArgs < 2; /* @@ -3924,12 +3883,12 @@ static DECLCALLBACK(int) pgmR3CmdPhysToFile(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, RTFILE hFile; int rc = RTFileOpen(&hFile, paArgs[0].u.pszString, RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_WRITE); if (RT_FAILURE(rc)) - return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: RTFileOpen(,'%s',) -> %Rrc.\n", paArgs[0].u.pszString, rc); + return DBGCCmdHlpPrintf(pCmdHlp, "error: RTFileOpen(,'%s',) -> %Rrc.\n", paArgs[0].u.pszString, rc); uint32_t cbRamHole = 0; - CFGMR3QueryU32Def(CFGMR3GetRoot(pVM), "RamHoleSize", &cbRamHole, MM_RAM_HOLE_SIZE_DEFAULT); + CFGMR3QueryU32Def(CFGMR3GetRootU(pUVM), "RamHoleSize", &cbRamHole, MM_RAM_HOLE_SIZE_DEFAULT); uint64_t cbRam = 0; - CFGMR3QueryU64Def(CFGMR3GetRoot(pVM), "RamSize", &cbRam, 0); + CFGMR3QueryU64Def(CFGMR3GetRootU(pUVM), "RamSize", &cbRam, 0); RTGCPHYS GCPhysEnd = cbRam + cbRamHole; /* @@ -3964,7 +3923,7 @@ static DECLCALLBACK(int) pgmR3CmdPhysToFile(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, { rc = RTFileWrite(hFile, abZeroPg, PAGE_SIZE, NULL); if (RT_FAILURE(rc)) - pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: RTFileWrite -> %Rrc at GCPhys=%RGp.\n", rc, GCPhys); + DBGCCmdHlpPrintf(pCmdHlp, "error: RTFileWrite -> %Rrc at GCPhys=%RGp.\n", rc, GCPhys); } } else @@ -3984,22 +3943,23 @@ static DECLCALLBACK(int) pgmR3CmdPhysToFile(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, rc = RTFileWrite(hFile, pvPage, PAGE_SIZE, NULL); PGMPhysReleasePageMappingLock(pVM, &Lock); if (RT_FAILURE(rc)) - pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: RTFileWrite -> %Rrc at GCPhys=%RGp.\n", rc, GCPhys); + DBGCCmdHlpPrintf(pCmdHlp, "error: RTFileWrite -> %Rrc at GCPhys=%RGp.\n", rc, GCPhys); } else - pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: PGMPhysGCPhys2CCPtrReadOnly -> %Rrc at GCPhys=%RGp.\n", rc, GCPhys); + DBGCCmdHlpPrintf(pCmdHlp, "error: PGMPhysGCPhys2CCPtrReadOnly -> %Rrc at GCPhys=%RGp.\n", rc, GCPhys); break; } default: AssertFailed(); - case PGMPAGETYPE_MMIO2_ALIAS_MMIO: case PGMPAGETYPE_MMIO: + case PGMPAGETYPE_MMIO2_ALIAS_MMIO: + case PGMPAGETYPE_SPECIAL_ALIAS_MMIO: if (fIncZeroPgs) { rc = RTFileWrite(hFile, abZeroPg, PAGE_SIZE, NULL); if (RT_FAILURE(rc)) - pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: RTFileWrite -> %Rrc at GCPhys=%RGp.\n", rc, GCPhys); + DBGCCmdHlpPrintf(pCmdHlp, "error: RTFileWrite -> %Rrc at GCPhys=%RGp.\n", rc, GCPhys); } break; } @@ -4015,7 +3975,7 @@ static DECLCALLBACK(int) pgmR3CmdPhysToFile(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, RTFileClose(hFile); if (RT_SUCCESS(rc)) - return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Successfully saved physical memory to '%s'.\n", paArgs[0].u.pszString); + return DBGCCmdHlpPrintf(pCmdHlp, "Successfully saved physical memory to '%s'.\n", paArgs[0].u.pszString); return VINF_SUCCESS; } |
