diff options
Diffstat (limited to 'src/VBox/VMM/VMMR3/VM.cpp')
| -rw-r--r-- | src/VBox/VMM/VMMR3/VM.cpp | 1037 |
1 files changed, 505 insertions, 532 deletions
diff --git a/src/VBox/VMM/VMMR3/VM.cpp b/src/VBox/VMM/VMMR3/VM.cpp index 0b280f65..36effa6a 100644 --- a/src/VBox/VMM/VMMR3/VM.cpp +++ b/src/VBox/VMM/VMMR3/VM.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2010 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; @@ -65,7 +65,7 @@ #include <VBox/vmm/iom.h> #include <VBox/vmm/ssm.h> #include <VBox/vmm/ftm.h> -#include <VBox/vmm/hwaccm.h> +#include <VBox/vmm/hm.h> #include "VMInternal.h" #include <VBox/vmm/vm.h> #include <VBox/vmm/uvm.h> @@ -90,46 +90,23 @@ /******************************************************************************* -* Structures and Typedefs * -*******************************************************************************/ -/** - * VM destruction callback registration record. - */ -typedef struct VMATDTOR -{ - /** Pointer to the next record in the list. */ - struct VMATDTOR *pNext; - /** Pointer to the callback function. */ - PFNVMATDTOR pfnAtDtor; - /** The user argument. */ - void *pvUser; -} VMATDTOR; -/** Pointer to a VM destruction callback registration record. */ -typedef VMATDTOR *PVMATDTOR; - - -/******************************************************************************* * Global Variables * *******************************************************************************/ /** Pointer to the list of VMs. */ static PUVM g_pUVMsHead = NULL; -/** Pointer to the list of at VM destruction callbacks. */ -static PVMATDTOR g_pVMAtDtorHead = NULL; -/** Lock the g_pVMAtDtorHead list. */ -#define VM_ATDTOR_LOCK() do { } while (0) -/** Unlock the g_pVMAtDtorHead list. */ -#define VM_ATDTOR_UNLOCK() do { } while (0) - /******************************************************************************* * Internal Functions * *******************************************************************************/ static int vmR3CreateUVM(uint32_t cCpus, PCVMM2USERMETHODS pVmm2UserMethods, PUVM *ppUVM); static int vmR3CreateU(PUVM pUVM, uint32_t cCpus, PFNCFGMCONSTRUCTOR pfnCFGMConstructor, void *pvUserCFGM); +static int vmR3ReadBaseConfig(PVM pVM, PUVM pUVM, uint32_t cCpus); static int vmR3InitRing3(PVM pVM, PUVM pUVM); static int vmR3InitRing0(PVM pVM); -static int vmR3InitGC(PVM pVM); +#ifdef VBOX_WITH_RAW_MODE +static int vmR3InitRC(PVM pVM); +#endif static int vmR3InitDoCompleted(PVM pVM, VMINITCOMPLETED enmWhat); #ifdef LOG_ENABLED static DECLCALLBACK(size_t) vmR3LogPrefixCallback(PRTLOGGER pLogger, char *pchBuf, size_t cchBuf, void *pvUser); @@ -193,15 +170,21 @@ VMMR3DECL(int) VMR3GlobalInit(void) * @param pfnCFGMConstructor Pointer to callback function for constructing the VM configuration tree. * This is called in the context of an EMT0. * @param pvUserCFGM The user argument passed to pfnCFGMConstructor. - * @param ppVM Where to store the 'handle' of the created VM. + * @param ppVM Where to optionally store the 'handle' of the + * created VM. + * @param ppUVM Where to optionally store the user 'handle' of + * the created VM, this includes one reference as + * if VMR3RetainUVM() was called. The caller + * *MUST* remember to pass the returned value to + * VMR3ReleaseUVM() once done with the handle. */ VMMR3DECL(int) VMR3Create(uint32_t cCpus, PCVMM2USERMETHODS pVmm2UserMethods, PFNVMATERROR pfnVMAtError, void *pvUserVM, PFNCFGMCONSTRUCTOR pfnCFGMConstructor, void *pvUserCFGM, - PVM *ppVM) + PVM *ppVM, PUVM *ppUVM) { - LogFlow(("VMR3Create: cCpus=%RU32 pVmm2UserMethods=%p pfnVMAtError=%p pvUserVM=%p pfnCFGMConstructor=%p pvUserCFGM=%p ppVM=%p\n", - cCpus, pVmm2UserMethods, pfnVMAtError, pvUserVM, pfnCFGMConstructor, pvUserCFGM, ppVM)); + LogFlow(("VMR3Create: cCpus=%RU32 pVmm2UserMethods=%p pfnVMAtError=%p pvUserVM=%p pfnCFGMConstructor=%p pvUserCFGM=%p ppVM=%p ppUVM=%p\n", + cCpus, pVmm2UserMethods, pfnVMAtError, pvUserVM, pfnCFGMConstructor, pvUserCFGM, ppVM, ppUVM)); if (pVmm2UserMethods) { @@ -213,11 +196,14 @@ VMMR3DECL(int) VMR3Create(uint32_t cCpus, PCVMM2USERMETHODS pVmm2UserMethods, AssertPtrNullReturn(pVmm2UserMethods->pfnNotifyEmtTerm, VERR_INVALID_POINTER); AssertPtrNullReturn(pVmm2UserMethods->pfnNotifyPdmtInit, VERR_INVALID_POINTER); AssertPtrNullReturn(pVmm2UserMethods->pfnNotifyPdmtTerm, VERR_INVALID_POINTER); + AssertPtrNullReturn(pVmm2UserMethods->pfnNotifyResetTurnedIntoPowerOff, VERR_INVALID_POINTER); AssertReturn(pVmm2UserMethods->u32EndMagic == VMM2USERMETHODS_MAGIC, VERR_INVALID_PARAMETER); } AssertPtrNullReturn(pfnVMAtError, VERR_INVALID_POINTER); AssertPtrNullReturn(pfnCFGMConstructor, VERR_INVALID_POINTER); - AssertPtrReturn(ppVM, VERR_INVALID_POINTER); + AssertPtrNullReturn(ppVM, VERR_INVALID_POINTER); + AssertPtrNullReturn(ppUVM, VERR_INVALID_POINTER); + AssertReturn(ppVM || ppUVM, VERR_INVALID_PARAMETER); /* * Because of the current hackiness of the applications @@ -247,7 +233,7 @@ VMMR3DECL(int) VMR3Create(uint32_t cCpus, PCVMM2USERMETHODS pVmm2UserMethods, if (RT_FAILURE(rc)) return rc; if (pfnVMAtError) - rc = VMR3AtErrorRegisterU(pUVM, pfnVMAtError, pvUserVM); + rc = VMR3AtErrorRegister(pUVM, pfnVMAtError, pvUserVM); if (RT_SUCCESS(rc)) { /* @@ -276,8 +262,14 @@ VMMR3DECL(int) VMR3Create(uint32_t cCpus, PCVMM2USERMETHODS pVmm2UserMethods, /* * Success! */ - *ppVM = pUVM->pVM; - LogFlow(("VMR3Create: returns VINF_SUCCESS *ppVM=%p\n", *ppVM)); + if (ppVM) + *ppVM = pUVM->pVM; + if (ppUVM) + { + VMR3RetainUVM(pUVM); + *ppUVM = pUVM; + } + LogFlow(("VMR3Create: returns VINF_SUCCESS (pVM=%p, pUVM=%p\n", pUVM->pVM, pUVM)); return VINF_SUCCESS; } } @@ -301,7 +293,7 @@ VMMR3DECL(int) VMR3Create(uint32_t cCpus, PCVMM2USERMETHODS pVmm2UserMethods, break; #ifndef RT_OS_DARWIN - case VERR_HWACCM_CONFIG_MISMATCH: + case VERR_HM_CONFIG_MISMATCH: pszError = N_("VT-x/AMD-V is either not available on your host or disabled. " "This hardware extension is required by the VM configuration"); break; @@ -354,7 +346,7 @@ VMMR3DECL(int) VMR3Create(uint32_t cCpus, PCVMM2USERMETHODS pVmm2UserMethods, "pack' which must be downloaded and installed separately"); break; - case VERR_PCI_PASSTHROUGH_NO_HWACCM: + case VERR_PCI_PASSTHROUGH_NO_HM: pszError = N_("PCI passthrough requires VT-x/AMD-V"); break; @@ -363,7 +355,7 @@ VMMR3DECL(int) VMR3Create(uint32_t cCpus, PCVMM2USERMETHODS pVmm2UserMethods, break; default: - if (VMR3GetErrorCountU(pUVM) == 0) + if (VMR3GetErrorCount(pUVM) == 0) pszError = RTErrGetFull(rc); else pszError = NULL; /* already set. */ @@ -525,13 +517,13 @@ static int vmR3CreateUVM(uint32_t cCpus, PCVMM2USERMETHODS pVmm2UserMethods, PUV /* * Init fundamental (sub-)components - STAM, MMR3Heap and PDMLdr. */ - rc = STAMR3InitUVM(pUVM); + rc = PDMR3InitUVM(pUVM); if (RT_SUCCESS(rc)) { - rc = MMR3InitUVM(pUVM); + rc = STAMR3InitUVM(pUVM); if (RT_SUCCESS(rc)) { - rc = PDMR3InitUVM(pUVM); + rc = MMR3InitUVM(pUVM); if (RT_SUCCESS(rc)) { /* @@ -539,8 +531,8 @@ static int vmR3CreateUVM(uint32_t cCpus, PCVMM2USERMETHODS pVmm2UserMethods, PUV */ for (i = 0; i < cCpus; i++) { - rc = RTThreadCreateF(&pUVM->aCpus[i].vm.s.ThreadEMT, vmR3EmulationThread, &pUVM->aCpus[i], _1M, - RTTHREADTYPE_EMULATION, RTTHREADFLAGS_WAITABLE, + rc = RTThreadCreateF(&pUVM->aCpus[i].vm.s.ThreadEMT, vmR3EmulationThread, &pUVM->aCpus[i], + _1M, RTTHREADTYPE_EMULATION, RTTHREADFLAGS_WAITABLE, cCpus > 1 ? "EMT-%u" : "EMT", i); if (RT_FAILURE(rc)) break; @@ -559,11 +551,11 @@ static int vmR3CreateUVM(uint32_t cCpus, PCVMM2USERMETHODS pVmm2UserMethods, PUV { /** @todo rainy day: terminate the EMTs. */ } - PDMR3TermUVM(pUVM); + MMR3TermUVM(pUVM); } - MMR3TermUVM(pUVM); + STAMR3TermUVM(pUVM); } - STAMR3TermUVM(pUVM); + PDMR3TermUVM(pUVM); } RTCritSectDelete(&pUVM->vm.s.AtErrorCritSect); } @@ -652,65 +644,7 @@ static int vmR3CreateU(PUVM pUVM, uint32_t cCpus, PFNCFGMCONSTRUCTOR pfnCFGMCons rc = CFGMR3Init(pVM, pfnCFGMConstructor, pvUserCFGM); if (RT_SUCCESS(rc)) { - PCFGMNODE pRoot = CFGMR3GetRoot(pVM); - rc = CFGMR3QueryBoolDef(pRoot, "HwVirtExtForced", &pVM->fHwVirtExtForced, false); - if (RT_SUCCESS(rc) && pVM->fHwVirtExtForced) - pVM->fHWACCMEnabled = true; - - /* - * If executing in fake suplib mode disable RR3 and RR0 in the config. - */ - const char *psz = RTEnvGet("VBOX_SUPLIB_FAKE"); - if (psz && !strcmp(psz, "fake")) - { - CFGMR3RemoveValue(pRoot, "RawR3Enabled"); - CFGMR3InsertInteger(pRoot, "RawR3Enabled", 0); - CFGMR3RemoveValue(pRoot, "RawR0Enabled"); - CFGMR3InsertInteger(pRoot, "RawR0Enabled", 0); - } - - /* - * Make sure the CPU count in the config data matches. - */ - if (RT_SUCCESS(rc)) - { - uint32_t cCPUsCfg; - rc = CFGMR3QueryU32Def(pRoot, "NumCPUs", &cCPUsCfg, 1); - AssertLogRelMsgRC(rc, ("Configuration error: Querying \"NumCPUs\" as integer failed, rc=%Rrc\n", rc)); - if (RT_SUCCESS(rc) && cCPUsCfg != cCpus) - { - AssertLogRelMsgFailed(("Configuration error: \"NumCPUs\"=%RU32 and VMR3CreateVM::cCpus=%RU32 does not match!\n", - cCPUsCfg, cCpus)); - rc = VERR_INVALID_PARAMETER; - } - } - - /* - * Get the CPU execution cap. - */ - if (RT_SUCCESS(rc)) - { - rc = CFGMR3QueryU32Def(pRoot, "CpuExecutionCap", &pVM->uCpuExecutionCap, 100); - AssertLogRelMsgRC(rc, ("Configuration error: Querying \"CpuExecutionCap\" as integer failed, rc=%Rrc\n", rc)); - } - - /* - * Get the VM name and UUID. - */ - if (RT_SUCCESS(rc)) - { - rc = CFGMR3QueryStringAllocDef(pRoot, "Name", &pUVM->vm.s.pszName, "<unknown>"); - AssertLogRelMsg(RT_SUCCESS(rc), ("Configuration error: Querying \"Name\" failed, rc=%Rrc\n", rc)); - } - - if (RT_SUCCESS(rc)) - { - rc = CFGMR3QueryBytes(pRoot, "UUID", &pUVM->vm.s.Uuid, sizeof(pUVM->vm.s.Uuid)); - if (rc == VERR_CFGM_VALUE_NOT_FOUND) - rc = VINF_SUCCESS; - AssertLogRelMsg(RT_SUCCESS(rc), ("Configuration error: Querying \"UUID\" failed, rc=%Rrc\n", rc)); - } - + rc = vmR3ReadBaseConfig(pVM, pUVM, cCpus); if (RT_SUCCESS(rc)) { /* @@ -741,17 +675,19 @@ static int vmR3CreateU(PUVM pUVM, uint32_t cCpus, PFNCFGMCONSTRUCTOR pfnCFGMCons * with debugger support. */ void *pvUser = NULL; - rc = DBGCTcpCreate(pVM, &pvUser); + rc = DBGCTcpCreate(pUVM, &pvUser); if ( RT_SUCCESS(rc) || rc == VERR_NET_ADDRESS_IN_USE) { pUVM->vm.s.pvDBGC = pvUser; #endif /* - * Init the Guest Context components. + * Init the Raw-Mode Context components. */ - rc = vmR3InitGC(pVM); +#ifdef VBOX_WITH_RAW_MODE + rc = vmR3InitRC(pVM); if (RT_SUCCESS(rc)) +#endif { /* * Now we can safely set the VM halt method to default. @@ -760,11 +696,9 @@ static int vmR3CreateU(PUVM pUVM, uint32_t cCpus, PFNCFGMCONSTRUCTOR pfnCFGMCons if (RT_SUCCESS(rc)) { /* - * Set the state and link into the global list. + * Set the state and we're done. */ vmR3SetState(pVM, VMSTATE_CREATED, VMSTATE_CREATING); - pUVM->pNext = g_pUVMsHead; - g_pUVMsHead = pUVM; #ifdef LOG_ENABLED RTLogSetCustomPrefixCallback(NULL, vmR3LogPrefixCallback, pUVM); @@ -773,7 +707,7 @@ static int vmR3CreateU(PUVM pUVM, uint32_t cCpus, PFNCFGMCONSTRUCTOR pfnCFGMCons } } #ifdef VBOX_WITH_DEBUGGER - DBGCTcpTerminate(pVM, pUVM->vm.s.pvDBGC); + DBGCTcpTerminate(pUVM, pUVM->vm.s.pvDBGC); pUVM->vm.s.pvDBGC = NULL; } #endif @@ -794,7 +728,7 @@ static int vmR3CreateU(PUVM pUVM, uint32_t cCpus, PFNCFGMCONSTRUCTOR pfnCFGMCons * Do automatic cleanups while the VM structure is still alive and all * references to it are still working. */ - PDMR3CritSectTerm(pVM); + PDMR3CritSectBothTerm(pVM); /* * Drop all references to VM and the VMCPU structures, then @@ -830,6 +764,92 @@ static int vmR3CreateU(PUVM pUVM, uint32_t cCpus, PFNCFGMCONSTRUCTOR pfnCFGMCons /** + * Reads the base configuation from CFGM. + * + * @returns VBox status code. + * @param pVM The cross context VM structure. + * @param pUVM The user mode VM structure. + * @param cCpus The CPU count given to VMR3Create. + */ +static int vmR3ReadBaseConfig(PVM pVM, PUVM pUVM, uint32_t cCpus) +{ + int rc; + PCFGMNODE pRoot = CFGMR3GetRoot(pVM); + + /* + * If executing in fake suplib mode disable RR3 and RR0 in the config. + */ + const char *psz = RTEnvGet("VBOX_SUPLIB_FAKE"); + if (psz && !strcmp(psz, "fake")) + { + CFGMR3RemoveValue(pRoot, "RawR3Enabled"); + CFGMR3InsertInteger(pRoot, "RawR3Enabled", 0); + CFGMR3RemoveValue(pRoot, "RawR0Enabled"); + CFGMR3InsertInteger(pRoot, "RawR0Enabled", 0); + } + + /* + * Base EM and HM config properties. + */ + Assert(pVM->fRecompileUser == false); /* ASSUMES all zeros at this point */ +#ifdef VBOX_WITH_RAW_MODE + bool fEnabled; + rc = CFGMR3QueryBoolDef(pRoot, "RawR3Enabled", &fEnabled, false); AssertRCReturn(rc, rc); + pVM->fRecompileUser = !fEnabled; + rc = CFGMR3QueryBoolDef(pRoot, "RawR0Enabled", &fEnabled, false); AssertRCReturn(rc, rc); + pVM->fRecompileSupervisor = !fEnabled; +# ifdef VBOX_WITH_RAW_RING1 + rc = CFGMR3QueryBoolDef(pRoot, "RawR1Enabled", &pVM->fRawRing1Enabled, false); +# endif + rc = CFGMR3QueryBoolDef(pRoot, "PATMEnabled", &pVM->fPATMEnabled, true); AssertRCReturn(rc, rc); + rc = CFGMR3QueryBoolDef(pRoot, "CSAMEnabled", &pVM->fCSAMEnabled, true); AssertRCReturn(rc, rc); + rc = CFGMR3QueryBoolDef(pRoot, "HMEnabled", &pVM->fHMEnabled, true); AssertRCReturn(rc, rc); +#else + pVM->fHMEnabled = true; +#endif + Assert(!pVM->fHMEnabledFixed); + LogRel(("VM: fHMEnabled=%RTbool (configured) fRecompileUser=%RTbool fRecompileSupervisor=%RTbool\n" + "VM: fRawRing1Enabled=%RTbool CSAM=%RTbool PATM=%RTbool\n", + pVM->fHMEnabled, pVM->fRecompileUser, pVM->fRecompileSupervisor, + pVM->fRawRing1Enabled, pVM->fCSAMEnabled, pVM->fPATMEnabled)); + + + /* + * Make sure the CPU count in the config data matches. + */ + uint32_t cCPUsCfg; + rc = CFGMR3QueryU32Def(pRoot, "NumCPUs", &cCPUsCfg, 1); + AssertLogRelMsgRCReturn(rc, ("Configuration error: Querying \"NumCPUs\" as integer failed, rc=%Rrc\n", rc), rc); + AssertLogRelMsgReturn(cCPUsCfg == cCpus, + ("Configuration error: \"NumCPUs\"=%RU32 and VMR3Create::cCpus=%RU32 does not match!\n", + cCPUsCfg, cCpus), + VERR_INVALID_PARAMETER); + + /* + * Get the CPU execution cap. + */ + rc = CFGMR3QueryU32Def(pRoot, "CpuExecutionCap", &pVM->uCpuExecutionCap, 100); + AssertLogRelMsgRCReturn(rc, ("Configuration error: Querying \"CpuExecutionCap\" as integer failed, rc=%Rrc\n", rc), rc); + + /* + * Get the VM name and UUID. + */ + rc = CFGMR3QueryStringAllocDef(pRoot, "Name", &pUVM->vm.s.pszName, "<unknown>"); + AssertLogRelMsgRCReturn(rc, ("Configuration error: Querying \"Name\" failed, rc=%Rrc\n", rc), rc); + + rc = CFGMR3QueryBytes(pRoot, "UUID", &pUVM->vm.s.Uuid, sizeof(pUVM->vm.s.Uuid)); + if (rc == VERR_CFGM_VALUE_NOT_FOUND) + rc = VINF_SUCCESS; + AssertLogRelMsgRCReturn(rc, ("Configuration error: Querying \"UUID\" failed, rc=%Rrc\n", rc), rc); + + rc = CFGMR3QueryBoolDef(pRoot, "PowerOffInsteadOfReset", &pVM->vm.s.fPowerOffInsteadOfReset, false); + AssertLogRelMsgRCReturn(rc, ("Configuration error: Querying \"PowerOffInsteadOfReset\" failed, rc=%Rrc\n", rc), rc); + + return VINF_SUCCESS; +} + + +/** * Register the calling EMT with GVM. * * @returns VBox status code. @@ -864,55 +884,59 @@ static int vmR3InitRing3(PVM pVM, PUVM pUVM) } /* - * Init all R3 components, the order here might be important. + * Register statistics. */ - rc = MMR3Init(pVM); - if (RT_SUCCESS(rc)) + STAM_REG(pVM, &pVM->StatTotalInGC, STAMTYPE_PROFILE_ADV, "/PROF/VM/InGC", STAMUNIT_TICKS_PER_CALL, "Profiling the total time spent in GC."); + STAM_REG(pVM, &pVM->StatSwitcherToGC, STAMTYPE_PROFILE_ADV, "/PROF/VM/SwitchToGC", STAMUNIT_TICKS_PER_CALL, "Profiling switching to GC."); + STAM_REG(pVM, &pVM->StatSwitcherToHC, STAMTYPE_PROFILE_ADV, "/PROF/VM/SwitchToHC", STAMUNIT_TICKS_PER_CALL, "Profiling switching to HC."); + STAM_REG(pVM, &pVM->StatSwitcherSaveRegs, STAMTYPE_PROFILE_ADV, "/VM/Switcher/ToGC/SaveRegs", STAMUNIT_TICKS_PER_CALL,"Profiling switching to GC."); + STAM_REG(pVM, &pVM->StatSwitcherSysEnter, STAMTYPE_PROFILE_ADV, "/VM/Switcher/ToGC/SysEnter", STAMUNIT_TICKS_PER_CALL,"Profiling switching to GC."); + STAM_REG(pVM, &pVM->StatSwitcherDebug, STAMTYPE_PROFILE_ADV, "/VM/Switcher/ToGC/Debug", STAMUNIT_TICKS_PER_CALL,"Profiling switching to GC."); + STAM_REG(pVM, &pVM->StatSwitcherCR0, STAMTYPE_PROFILE_ADV, "/VM/Switcher/ToGC/CR0", STAMUNIT_TICKS_PER_CALL, "Profiling switching to GC."); + STAM_REG(pVM, &pVM->StatSwitcherCR4, STAMTYPE_PROFILE_ADV, "/VM/Switcher/ToGC/CR4", STAMUNIT_TICKS_PER_CALL, "Profiling switching to GC."); + STAM_REG(pVM, &pVM->StatSwitcherLgdt, STAMTYPE_PROFILE_ADV, "/VM/Switcher/ToGC/Lgdt", STAMUNIT_TICKS_PER_CALL, "Profiling switching to GC."); + STAM_REG(pVM, &pVM->StatSwitcherLidt, STAMTYPE_PROFILE_ADV, "/VM/Switcher/ToGC/Lidt", STAMUNIT_TICKS_PER_CALL, "Profiling switching to GC."); + STAM_REG(pVM, &pVM->StatSwitcherLldt, STAMTYPE_PROFILE_ADV, "/VM/Switcher/ToGC/Lldt", STAMUNIT_TICKS_PER_CALL, "Profiling switching to GC."); + STAM_REG(pVM, &pVM->StatSwitcherTSS, STAMTYPE_PROFILE_ADV, "/VM/Switcher/ToGC/TSS", STAMUNIT_TICKS_PER_CALL, "Profiling switching to GC."); + STAM_REG(pVM, &pVM->StatSwitcherJmpCR3, STAMTYPE_PROFILE_ADV, "/VM/Switcher/ToGC/JmpCR3", STAMUNIT_TICKS_PER_CALL,"Profiling switching to GC."); + STAM_REG(pVM, &pVM->StatSwitcherRstrRegs, STAMTYPE_PROFILE_ADV, "/VM/Switcher/ToGC/RstrRegs", STAMUNIT_TICKS_PER_CALL,"Profiling switching to GC."); + + for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++) { - STAM_REG(pVM, &pVM->StatTotalInGC, STAMTYPE_PROFILE_ADV, "/PROF/VM/InGC", STAMUNIT_TICKS_PER_CALL, "Profiling the total time spent in GC."); - STAM_REG(pVM, &pVM->StatSwitcherToGC, STAMTYPE_PROFILE_ADV, "/PROF/VM/SwitchToGC", STAMUNIT_TICKS_PER_CALL, "Profiling switching to GC."); - STAM_REG(pVM, &pVM->StatSwitcherToHC, STAMTYPE_PROFILE_ADV, "/PROF/VM/SwitchToHC", STAMUNIT_TICKS_PER_CALL, "Profiling switching to HC."); - STAM_REG(pVM, &pVM->StatSwitcherSaveRegs, STAMTYPE_PROFILE_ADV, "/VM/Switcher/ToGC/SaveRegs", STAMUNIT_TICKS_PER_CALL,"Profiling switching to GC."); - STAM_REG(pVM, &pVM->StatSwitcherSysEnter, STAMTYPE_PROFILE_ADV, "/VM/Switcher/ToGC/SysEnter", STAMUNIT_TICKS_PER_CALL,"Profiling switching to GC."); - STAM_REG(pVM, &pVM->StatSwitcherDebug, STAMTYPE_PROFILE_ADV, "/VM/Switcher/ToGC/Debug", STAMUNIT_TICKS_PER_CALL,"Profiling switching to GC."); - STAM_REG(pVM, &pVM->StatSwitcherCR0, STAMTYPE_PROFILE_ADV, "/VM/Switcher/ToGC/CR0", STAMUNIT_TICKS_PER_CALL, "Profiling switching to GC."); - STAM_REG(pVM, &pVM->StatSwitcherCR4, STAMTYPE_PROFILE_ADV, "/VM/Switcher/ToGC/CR4", STAMUNIT_TICKS_PER_CALL, "Profiling switching to GC."); - STAM_REG(pVM, &pVM->StatSwitcherLgdt, STAMTYPE_PROFILE_ADV, "/VM/Switcher/ToGC/Lgdt", STAMUNIT_TICKS_PER_CALL, "Profiling switching to GC."); - STAM_REG(pVM, &pVM->StatSwitcherLidt, STAMTYPE_PROFILE_ADV, "/VM/Switcher/ToGC/Lidt", STAMUNIT_TICKS_PER_CALL, "Profiling switching to GC."); - STAM_REG(pVM, &pVM->StatSwitcherLldt, STAMTYPE_PROFILE_ADV, "/VM/Switcher/ToGC/Lldt", STAMUNIT_TICKS_PER_CALL, "Profiling switching to GC."); - STAM_REG(pVM, &pVM->StatSwitcherTSS, STAMTYPE_PROFILE_ADV, "/VM/Switcher/ToGC/TSS", STAMUNIT_TICKS_PER_CALL, "Profiling switching to GC."); - STAM_REG(pVM, &pVM->StatSwitcherJmpCR3, STAMTYPE_PROFILE_ADV, "/VM/Switcher/ToGC/JmpCR3", STAMUNIT_TICKS_PER_CALL,"Profiling switching to GC."); - STAM_REG(pVM, &pVM->StatSwitcherRstrRegs, STAMTYPE_PROFILE_ADV, "/VM/Switcher/ToGC/RstrRegs", STAMUNIT_TICKS_PER_CALL,"Profiling switching to GC."); - - for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++) - { - rc = STAMR3RegisterF(pVM, &pUVM->aCpus[idCpu].vm.s.StatHaltYield, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_NS_PER_CALL, "Profiling halted state yielding.", "/PROF/VM/CPU%d/Halt/Yield", idCpu); - AssertRC(rc); - rc = STAMR3RegisterF(pVM, &pUVM->aCpus[idCpu].vm.s.StatHaltBlock, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_NS_PER_CALL, "Profiling halted state blocking.", "/PROF/VM/CPU%d/Halt/Block", idCpu); - AssertRC(rc); - rc = STAMR3RegisterF(pVM, &pUVM->aCpus[idCpu].vm.s.StatHaltBlockOverslept, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_NS_PER_CALL, "Time wasted by blocking too long.", "/PROF/VM/CPU%d/Halt/BlockOverslept", idCpu); - AssertRC(rc); - rc = STAMR3RegisterF(pVM, &pUVM->aCpus[idCpu].vm.s.StatHaltBlockInsomnia, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_NS_PER_CALL, "Time slept when returning to early.","/PROF/VM/CPU%d/Halt/BlockInsomnia", idCpu); - AssertRC(rc); - rc = STAMR3RegisterF(pVM, &pUVM->aCpus[idCpu].vm.s.StatHaltBlockOnTime, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_NS_PER_CALL, "Time slept on time.", "/PROF/VM/CPU%d/Halt/BlockOnTime", idCpu); - AssertRC(rc); - rc = STAMR3RegisterF(pVM, &pUVM->aCpus[idCpu].vm.s.StatHaltTimers, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_NS_PER_CALL, "Profiling halted state timer tasks.", "/PROF/VM/CPU%d/Halt/Timers", idCpu); - AssertRC(rc); - } + rc = STAMR3RegisterF(pVM, &pUVM->aCpus[idCpu].vm.s.StatHaltYield, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_NS_PER_CALL, "Profiling halted state yielding.", "/PROF/CPU%d/VM/Halt/Yield", idCpu); + AssertRC(rc); + rc = STAMR3RegisterF(pVM, &pUVM->aCpus[idCpu].vm.s.StatHaltBlock, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_NS_PER_CALL, "Profiling halted state blocking.", "/PROF/CPU%d/VM/Halt/Block", idCpu); + AssertRC(rc); + rc = STAMR3RegisterF(pVM, &pUVM->aCpus[idCpu].vm.s.StatHaltBlockOverslept, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_NS_PER_CALL, "Time wasted by blocking too long.", "/PROF/CPU%d/VM/Halt/BlockOverslept", idCpu); + AssertRC(rc); + rc = STAMR3RegisterF(pVM, &pUVM->aCpus[idCpu].vm.s.StatHaltBlockInsomnia, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_NS_PER_CALL, "Time slept when returning to early.","/PROF/CPU%d/VM/Halt/BlockInsomnia", idCpu); + AssertRC(rc); + rc = STAMR3RegisterF(pVM, &pUVM->aCpus[idCpu].vm.s.StatHaltBlockOnTime, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_NS_PER_CALL, "Time slept on time.", "/PROF/CPU%d/VM/Halt/BlockOnTime", idCpu); + AssertRC(rc); + rc = STAMR3RegisterF(pVM, &pUVM->aCpus[idCpu].vm.s.StatHaltTimers, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_NS_PER_CALL, "Profiling halted state timer tasks.", "/PROF/CPU%d/VM/Halt/Timers", idCpu); + AssertRC(rc); + } - STAM_REG(pVM, &pUVM->vm.s.StatReqAllocNew, STAMTYPE_COUNTER, "/VM/Req/AllocNew", STAMUNIT_OCCURENCES, "Number of VMR3ReqAlloc returning a new packet."); - STAM_REG(pVM, &pUVM->vm.s.StatReqAllocRaces, STAMTYPE_COUNTER, "/VM/Req/AllocRaces", STAMUNIT_OCCURENCES, "Number of VMR3ReqAlloc causing races."); - STAM_REG(pVM, &pUVM->vm.s.StatReqAllocRecycled, STAMTYPE_COUNTER, "/VM/Req/AllocRecycled", STAMUNIT_OCCURENCES, "Number of VMR3ReqAlloc returning a recycled packet."); - STAM_REG(pVM, &pUVM->vm.s.StatReqFree, STAMTYPE_COUNTER, "/VM/Req/Free", STAMUNIT_OCCURENCES, "Number of VMR3ReqFree calls."); - STAM_REG(pVM, &pUVM->vm.s.StatReqFreeOverflow, STAMTYPE_COUNTER, "/VM/Req/FreeOverflow", STAMUNIT_OCCURENCES, "Number of times the request was actually freed."); - STAM_REG(pVM, &pUVM->vm.s.StatReqProcessed, STAMTYPE_COUNTER, "/VM/Req/Processed", STAMUNIT_OCCURENCES, "Number of processed requests (any queue)."); - STAM_REG(pVM, &pUVM->vm.s.StatReqMoreThan1, STAMTYPE_COUNTER, "/VM/Req/MoreThan1", STAMUNIT_OCCURENCES, "Number of times there are more than one request on the queue when processing it."); - STAM_REG(pVM, &pUVM->vm.s.StatReqPushBackRaces, STAMTYPE_COUNTER, "/VM/Req/PushBackRaces", STAMUNIT_OCCURENCES, "Number of push back races."); + STAM_REG(pVM, &pUVM->vm.s.StatReqAllocNew, STAMTYPE_COUNTER, "/VM/Req/AllocNew", STAMUNIT_OCCURENCES, "Number of VMR3ReqAlloc returning a new packet."); + STAM_REG(pVM, &pUVM->vm.s.StatReqAllocRaces, STAMTYPE_COUNTER, "/VM/Req/AllocRaces", STAMUNIT_OCCURENCES, "Number of VMR3ReqAlloc causing races."); + STAM_REG(pVM, &pUVM->vm.s.StatReqAllocRecycled, STAMTYPE_COUNTER, "/VM/Req/AllocRecycled", STAMUNIT_OCCURENCES, "Number of VMR3ReqAlloc returning a recycled packet."); + STAM_REG(pVM, &pUVM->vm.s.StatReqFree, STAMTYPE_COUNTER, "/VM/Req/Free", STAMUNIT_OCCURENCES, "Number of VMR3ReqFree calls."); + STAM_REG(pVM, &pUVM->vm.s.StatReqFreeOverflow, STAMTYPE_COUNTER, "/VM/Req/FreeOverflow", STAMUNIT_OCCURENCES, "Number of times the request was actually freed."); + STAM_REG(pVM, &pUVM->vm.s.StatReqProcessed, STAMTYPE_COUNTER, "/VM/Req/Processed", STAMUNIT_OCCURENCES, "Number of processed requests (any queue)."); + STAM_REG(pVM, &pUVM->vm.s.StatReqMoreThan1, STAMTYPE_COUNTER, "/VM/Req/MoreThan1", STAMUNIT_OCCURENCES, "Number of times there are more than one request on the queue when processing it."); + STAM_REG(pVM, &pUVM->vm.s.StatReqPushBackRaces, STAMTYPE_COUNTER, "/VM/Req/PushBackRaces", STAMUNIT_OCCURENCES, "Number of push back races."); - rc = CPUMR3Init(pVM); + /* + * Init all R3 components, the order here might be important. + * HM shall be initialized first! + */ + rc = HMR3Init(pVM); + if (RT_SUCCESS(rc)) + { + rc = MMR3Init(pVM); if (RT_SUCCESS(rc)) { - rc = HWACCMR3Init(pVM); + rc = CPUMR3Init(pVM); if (RT_SUCCESS(rc)) { rc = PGMR3Init(pVM); @@ -940,12 +964,14 @@ static int vmR3InitRing3(PVM pVM, PUVM pUVM) rc = TRPMR3Init(pVM); if (RT_SUCCESS(rc)) { +#ifdef VBOX_WITH_RAW_MODE rc = CSAMR3Init(pVM); if (RT_SUCCESS(rc)) { rc = PATMR3Init(pVM); if (RT_SUCCESS(rc)) { +#endif rc = IOMR3Init(pVM); if (RT_SUCCESS(rc)) { @@ -964,8 +990,10 @@ static int vmR3InitRing3(PVM pVM, PUVM pUVM) rc = PGMR3InitDynMap(pVM); if (RT_SUCCESS(rc)) rc = MMR3HyperInitFinalize(pVM); +#ifdef VBOX_WITH_RAW_MODE if (RT_SUCCESS(rc)) rc = PATMR3InitFinalize(pVM); +#endif if (RT_SUCCESS(rc)) rc = PGMR3InitFinalize(pVM); if (RT_SUCCESS(rc)) @@ -977,6 +1005,11 @@ static int vmR3InitRing3(PVM pVM, PUVM pUVM) rc = REMR3InitFinalize(pVM); #endif if (RT_SUCCESS(rc)) + { + PGMR3MemSetup(pVM, false /*fAtReset*/); + PDMR3MemSetup(pVM, false /*fAtReset*/); + } + if (RT_SUCCESS(rc)) rc = vmR3InitDoCompleted(pVM, VMINITCOMPLETED_RING3); if (RT_SUCCESS(rc)) { @@ -999,12 +1032,14 @@ static int vmR3InitRing3(PVM pVM, PUVM pUVM) int rc2 = IOMR3Term(pVM); AssertRC(rc2); } +#ifdef VBOX_WITH_RAW_MODE int rc2 = PATMR3Term(pVM); AssertRC(rc2); } int rc2 = CSAMR3Term(pVM); AssertRC(rc2); } +#endif int rc2 = TRPMR3Term(pVM); AssertRC(rc2); } @@ -1028,15 +1063,16 @@ static int vmR3InitRing3(PVM pVM, PUVM pUVM) int rc2 = PGMR3Term(pVM); AssertRC(rc2); } - int rc2 = HWACCMR3Term(pVM); - AssertRC(rc2); + //int rc2 = CPUMR3Term(pVM); + //AssertRC(rc2); } - //int rc2 = CPUMR3Term(pVM); - //AssertRC(rc2); + /* MMR3Term is not called here because it'll kill the heap. */ } - /* MMR3Term is not called here because it'll kill the heap. */ + int rc2 = HMR3Term(pVM); + AssertRC(rc2); } + LogFlow(("vmR3InitRing3: returns %Rrc\n", rc)); return rc; } @@ -1070,23 +1106,24 @@ static int vmR3InitRing0(PVM pVM) if (RT_SUCCESS(rc)) rc = vmR3InitDoCompleted(pVM, VMINITCOMPLETED_RING0); if (RT_SUCCESS(rc)) - rc = vmR3InitDoCompleted(pVM, VMINITCOMPLETED_HWACCM); + rc = vmR3InitDoCompleted(pVM, VMINITCOMPLETED_HM); - /** @todo Move this to the VMINITCOMPLETED_HWACCM notification handler. */ + /** @todo Move this to the VMINITCOMPLETED_HM notification handler. */ if (RT_SUCCESS(rc)) - CPUMR3SetHWVirtEx(pVM, HWACCMIsEnabled(pVM)); + CPUMR3SetHWVirtEx(pVM, HMIsEnabled(pVM)); LogFlow(("vmR3InitRing0: returns %Rrc\n", rc)); return rc; } +#ifdef VBOX_WITH_RAW_MODE /** - * Initializes all GC components of the VM + * Initializes all RC components of the VM */ -static int vmR3InitGC(PVM pVM) +static int vmR3InitRC(PVM pVM) { - LogFlow(("vmR3InitGC:\n")); + LogFlow(("vmR3InitRC:\n")); /* * Check for FAKE suplib mode. @@ -1101,16 +1138,17 @@ static int vmR3InitGC(PVM pVM) rc = VMMR3InitRC(pVM); } else - Log(("vmR3InitGC: skipping because of VBOX_SUPLIB_FAKE=fake\n")); + Log(("vmR3InitRC: skipping because of VBOX_SUPLIB_FAKE=fake\n")); /* * Do notifications and return. */ if (RT_SUCCESS(rc)) - rc = vmR3InitDoCompleted(pVM, VMINITCOMPLETED_GC); - LogFlow(("vmR3InitGC: returns %Rrc\n", rc)); + rc = vmR3InitDoCompleted(pVM, VMINITCOMPLETED_RC); + LogFlow(("vmR3InitRC: returns %Rrc\n", rc)); return rc; } +#endif /* VBOX_WITH_RAW_MODE */ /** @@ -1124,9 +1162,18 @@ static int vmR3InitDoCompleted(PVM pVM, VMINITCOMPLETED enmWhat) { int rc = VMMR3InitCompleted(pVM, enmWhat); if (RT_SUCCESS(rc)) - rc = HWACCMR3InitCompleted(pVM, enmWhat); + rc = HMR3InitCompleted(pVM, enmWhat); if (RT_SUCCESS(rc)) rc = PGMR3InitCompleted(pVM, enmWhat); +#ifndef VBOX_WITH_RAW_MODE + if (enmWhat == VMINITCOMPLETED_RING3) + { + if (RT_SUCCESS(rc)) + rc = SSMR3RegisterStub(pVM, "CSAM", 0); + if (RT_SUCCESS(rc)) + rc = SSMR3RegisterStub(pVM, "PATM", 0); + } +#endif return rc; } @@ -1176,7 +1223,7 @@ static DECLCALLBACK(size_t) vmR3LogPrefixCallback(PRTLOGGER pLogger, char *pchBu * @param pVM Pointer to the VM. * @param offDelta Relocation delta relative to old location. */ -VMMR3DECL(void) VMR3Relocate(PVM pVM, RTGCINTPTR offDelta) +VMMR3_INT_DECL(void) VMR3Relocate(PVM pVM, RTGCINTPTR offDelta) { LogFlow(("VMR3Relocate: offDelta=%RGv\n", offDelta)); @@ -1187,13 +1234,15 @@ VMMR3DECL(void) VMR3Relocate(PVM pVM, RTGCINTPTR offDelta) PDMR3LdrRelocateU(pVM->pUVM, offDelta); PGMR3Relocate(pVM, 0); /* Repeat after PDM relocation. */ CPUMR3Relocate(pVM); - HWACCMR3Relocate(pVM); + HMR3Relocate(pVM); SELMR3Relocate(pVM); VMMR3Relocate(pVM, offDelta); SELMR3Relocate(pVM); /* !hack! fix stack! */ TRPMR3Relocate(pVM, offDelta); +#ifdef VBOX_WITH_RAW_MODE PATMR3Relocate(pVM); CSAMR3Relocate(pVM, offDelta); +#endif IOMR3Relocate(pVM, offDelta); EMR3Relocate(pVM); TMR3Relocate(pVM, offDelta); @@ -1258,15 +1307,17 @@ static DECLCALLBACK(VBOXSTRICTRC) vmR3PowerOn(PVM pVM, PVMCPU pVCpu, void *pvUse * * @returns VBox status code. * - * @param pVM The VM to power on. + * @param pUVM The VM to power on. * * @thread Any thread. * @vmstate Created * @vmstateto PoweringOn+Running */ -VMMR3DECL(int) VMR3PowerOn(PVM pVM) +VMMR3DECL(int) VMR3PowerOn(PUVM pUVM) { - LogFlow(("VMR3PowerOn: pVM=%p\n", pVM)); + LogFlow(("VMR3PowerOn: pUVM=%p\n", pUVM)); + UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); + PVM pVM = pUVM->pVM; VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); /* @@ -1304,8 +1355,8 @@ static void vmR3SuspendDoWork(PVM pVM) */ static DECLCALLBACK(VBOXSTRICTRC) vmR3Suspend(PVM pVM, PVMCPU pVCpu, void *pvUser) { - LogFlow(("vmR3Suspend: pVM=%p pVCpu=%p/#%u\n", pVM, pVCpu, pVCpu->idCpu)); - Assert(!pvUser); NOREF(pvUser); + VMSUSPENDREASON enmReason = (VMSUSPENDREASON)(uintptr_t)pvUser; + LogFlow(("vmR3Suspend: pVM=%p pVCpu=%p/#%u enmReason=%d\n", pVM, pVCpu, pVCpu->idCpu, enmReason)); /* * The first EMT switches the state to suspending. If this fails because @@ -1319,6 +1370,7 @@ static DECLCALLBACK(VBOXSTRICTRC) vmR3Suspend(PVM pVM, PVMCPU pVCpu, void *pvUse VMSTATE_SUSPENDING_EXT_LS, VMSTATE_RUNNING_LS); if (RT_FAILURE(rc)) return rc; + pVM->pUVM->vm.s.enmSuspendReason = enmReason; } VMSTATE enmVMState = VMR3GetState(pVM); @@ -1352,29 +1404,45 @@ static DECLCALLBACK(VBOXSTRICTRC) vmR3Suspend(PVM pVM, PVMCPU pVCpu, void *pvUse * @returns VBox status code. When called on EMT, this will be a strict status * code that has to be propagated up the call stack. * - * @param pVM The VM to suspend. + * @param pUVM The VM to suspend. + * @param enmReason The reason for suspending. * * @thread Any thread. * @vmstate Running or RunningLS * @vmstateto Suspending + Suspended or SuspendingExtLS + SuspendedExtLS */ -VMMR3DECL(int) VMR3Suspend(PVM pVM) +VMMR3DECL(int) VMR3Suspend(PUVM pUVM, VMSUSPENDREASON enmReason) { - LogFlow(("VMR3Suspend: pVM=%p\n", pVM)); - VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); + LogFlow(("VMR3Suspend: pUVM=%p\n", pUVM)); + UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); + AssertReturn(enmReason > VMSUSPENDREASON_INVALID && enmReason < VMSUSPENDREASON_END, VERR_INVALID_PARAMETER); /* * Gather all the EMTs to make sure there are no races before * changing the VM state. */ - int rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_DESCENDING | VMMEMTRENDEZVOUS_FLAGS_STOP_ON_ERROR, - vmR3Suspend, NULL); + int rc = VMMR3EmtRendezvous(pUVM->pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_DESCENDING | VMMEMTRENDEZVOUS_FLAGS_STOP_ON_ERROR, + vmR3Suspend, (void *)(uintptr_t)enmReason); LogFlow(("VMR3Suspend: returns %Rrc\n", rc)); return rc; } /** + * Retrieves the reason for the most recent suspend. + * + * @returns Suspend reason. VMSUSPENDREASON_INVALID if no suspend has been done + * or the handle is invalid. + * @param pUVM The user mode VM handle. + */ +VMMR3DECL(VMSUSPENDREASON) VMR3GetSuspendReason(PUVM pUVM) +{ + UVM_ASSERT_VALID_EXT_RETURN(pUVM, VMSUSPENDREASON_INVALID); + return pUVM->vm.s.enmSuspendReason; +} + + +/** * EMT rendezvous worker for VMR3Resume. * * @returns VERR_VM_INVALID_VM_STATE or VINF_EM_RESUME. (This is a strict @@ -1382,12 +1450,12 @@ VMMR3DECL(int) VMR3Suspend(PVM pVM) * * @param pVM Pointer to the VM. * @param pVCpu Pointer to the VMCPU of the EMT. - * @param pvUser Ignored. + * @param pvUser Reason. */ static DECLCALLBACK(VBOXSTRICTRC) vmR3Resume(PVM pVM, PVMCPU pVCpu, void *pvUser) { - LogFlow(("vmR3Resume: pVM=%p pVCpu=%p/#%u\n", pVM, pVCpu, pVCpu->idCpu)); - Assert(!pvUser); NOREF(pvUser); + VMRESUMEREASON enmReason = (VMRESUMEREASON)(uintptr_t)pvUser; + LogFlow(("vmR3Resume: pVM=%p pVCpu=%p/#%u enmReason=%d\n", pVM, pVCpu, pVCpu->idCpu, enmReason)); /* * The first thread thru here tries to change the state. We shouldn't be @@ -1398,6 +1466,7 @@ static DECLCALLBACK(VBOXSTRICTRC) vmR3Resume(PVM pVM, PVMCPU pVCpu, void *pvUser int rc = vmR3TrySetState(pVM, "VMR3Resume", 1, VMSTATE_RESUMING, VMSTATE_SUSPENDED); if (RT_FAILURE(rc)) return rc; + pVM->pUVM->vm.s.enmResumeReason = enmReason; } VMSTATE enmVMState = VMR3GetState(pVM); @@ -1434,28 +1503,46 @@ static DECLCALLBACK(VBOXSTRICTRC) vmR3Resume(PVM pVM, PVMCPU pVCpu, void *pvUser * code that has to be propagated up the call stack. * * @param pVM The VM to resume. + * @param enmReason The reason we're resuming. * * @thread Any thread. * @vmstate Suspended * @vmstateto Running */ -VMMR3DECL(int) VMR3Resume(PVM pVM) +VMMR3DECL(int) VMR3Resume(PUVM pUVM, VMRESUMEREASON enmReason) { - LogFlow(("VMR3Resume: pVM=%p\n", pVM)); + LogFlow(("VMR3Resume: pUVM=%p\n", pUVM)); + UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); + PVM pVM = pUVM->pVM; VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); + AssertReturn(enmReason > VMRESUMEREASON_INVALID && enmReason < VMRESUMEREASON_END, VERR_INVALID_PARAMETER); /* * Gather all the EMTs to make sure there are no races before * changing the VM state. */ int rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_DESCENDING | VMMEMTRENDEZVOUS_FLAGS_STOP_ON_ERROR, - vmR3Resume, NULL); + vmR3Resume, (void *)(uintptr_t)enmReason); LogFlow(("VMR3Resume: returns %Rrc\n", rc)); return rc; } /** + * Retrieves the reason for the most recent resume. + * + * @returns Resume reason. VMRESUMEREASON_INVALID if no suspend has been + * done or the handle is invalid. + * @param pUVM The user mode VM handle. + */ +VMMR3DECL(VMRESUMEREASON) VMR3GetResumeReason(PUVM pUVM) +{ + UVM_ASSERT_VALID_EXT_RETURN(pUVM, VMRESUMEREASON_INVALID); + return pUVM->vm.s.enmResumeReason; +} + + +/** * EMT rendezvous worker for VMR3Save and VMR3Teleport that suspends the VM * after the live step has been completed. * @@ -1817,7 +1904,7 @@ static int vmR3SaveTeleport(PVM pVM, uint32_t cMsMaxDowntime, * * @returns VBox status code. * - * @param pVM The VM which state should be saved. + * @param pUVM The VM which state should be saved. * @param pszFilename The name of the save state file. * @param pStreamOps The stream methods. * @param pvStreamOpsUser The user argument to the stream methods. @@ -1832,16 +1919,18 @@ static int vmR3SaveTeleport(PVM pVM, uint32_t cMsMaxDowntime, * @vmstateto Saving+Suspended or * RunningLS+SuspendingLS+SuspendedLS+Saving+Suspended. */ -VMMR3DECL(int) VMR3Save(PVM pVM, const char *pszFilename, bool fContinueAfterwards, PFNVMPROGRESS pfnProgress, void *pvUser, bool *pfSuspended) +VMMR3DECL(int) VMR3Save(PUVM pUVM, const char *pszFilename, bool fContinueAfterwards, PFNVMPROGRESS pfnProgress, void *pvUser, bool *pfSuspended) { - LogFlow(("VMR3Save: pVM=%p pszFilename=%p:{%s} fContinueAfterwards=%RTbool pfnProgress=%p pvUser=%p pfSuspended=%p\n", - pVM, pszFilename, pszFilename, fContinueAfterwards, pfnProgress, pvUser, pfSuspended)); + LogFlow(("VMR3Save: pUVM=%p pszFilename=%p:{%s} fContinueAfterwards=%RTbool pfnProgress=%p pvUser=%p pfSuspended=%p\n", + pUVM, pszFilename, pszFilename, fContinueAfterwards, pfnProgress, pvUser, pfSuspended)); /* * Validate input. */ AssertPtr(pfSuspended); *pfSuspended = false; + UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); + PVM pVM = pUVM->pVM; VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); VM_ASSERT_OTHER_THREAD(pVM); AssertReturn(VALID_PTR(pszFilename), VERR_INVALID_POINTER); @@ -1863,13 +1952,6 @@ VMMR3DECL(int) VMR3Save(PVM pVM, const char *pszFilename, bool fContinueAfterwar /** * Save current VM state (used by FTM) * - * Can be used for both saving the state and creating snapshots. - * - * When called for a VM in the Running state, the saved state is created live - * and the VM is only suspended when the final part of the saving is preformed. - * The VM state will not be restored to Running in this case and it's up to the - * caller to call VMR3Resume if this is desirable. (The rational is that the - * caller probably wish to reconfigure the disks before resuming the VM.) * * @returns VBox status code. * @@ -1884,17 +1966,18 @@ VMMR3DECL(int) VMR3Save(PVM pVM, const char *pszFilename, bool fContinueAfterwar * @vmstateto Saving+Suspended or * RunningLS+SuspendingLS+SuspendedLS+Saving+Suspended. */ -VMMR3DECL(int) VMR3SaveFT(PVM pVM, PCSSMSTRMOPS pStreamOps, void *pvStreamOpsUser, bool *pfSuspended, - bool fSkipStateChanges) +VMMR3_INT_DECL(int) VMR3SaveFT(PUVM pUVM, PCSSMSTRMOPS pStreamOps, void *pvStreamOpsUser, bool *pfSuspended, bool fSkipStateChanges) { - LogFlow(("VMR3SaveFT: pVM=%p pStreamOps=%p pvSteamOpsUser=%p pfSuspended=%p\n", - pVM, pStreamOps, pvStreamOpsUser, pfSuspended)); + LogFlow(("VMR3SaveFT: pUVM=%p pStreamOps=%p pvSteamOpsUser=%p pfSuspended=%p\n", + pUVM, pStreamOps, pvStreamOpsUser, pfSuspended)); /* * Validate input. */ AssertPtr(pfSuspended); *pfSuspended = false; + UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); + PVM pVM = pUVM->pVM; VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); AssertReturn(pStreamOps, VERR_INVALID_PARAMETER); @@ -1915,7 +1998,7 @@ VMMR3DECL(int) VMR3SaveFT(PVM pVM, PCSSMSTRMOPS pStreamOps, void *pvStreamOpsUse * * @returns VBox status code. * - * @param pVM The VM which state should be saved. + * @param pUVM The VM which state should be saved. * @param cMsMaxDowntime The maximum downtime given as milliseconds. * @param pStreamOps The stream methods. * @param pvStreamOpsUser The user argument to the stream methods. @@ -1928,17 +2011,19 @@ VMMR3DECL(int) VMR3SaveFT(PVM pVM, PCSSMSTRMOPS pStreamOps, void *pvStreamOpsUse * @vmstateto Saving+Suspended or * RunningLS+SuspendingLS+SuspendedLS+Saving+Suspended. */ -VMMR3DECL(int) VMR3Teleport(PVM pVM, uint32_t cMsMaxDowntime, PCSSMSTRMOPS pStreamOps, void *pvStreamOpsUser, +VMMR3DECL(int) VMR3Teleport(PUVM pUVM, uint32_t cMsMaxDowntime, PCSSMSTRMOPS pStreamOps, void *pvStreamOpsUser, PFNVMPROGRESS pfnProgress, void *pvProgressUser, bool *pfSuspended) { - LogFlow(("VMR3Teleport: pVM=%p cMsMaxDowntime=%u pStreamOps=%p pvStreamOps=%p pfnProgress=%p pvProgressUser=%p\n", - pVM, cMsMaxDowntime, pStreamOps, pvStreamOpsUser, pfnProgress, pvProgressUser)); + LogFlow(("VMR3Teleport: pUVM=%p cMsMaxDowntime=%u pStreamOps=%p pvStreamOps=%p pfnProgress=%p pvProgressUser=%p\n", + pUVM, cMsMaxDowntime, pStreamOps, pvStreamOpsUser, pfnProgress, pvProgressUser)); /* * Validate input. */ AssertPtr(pfSuspended); *pfSuspended = false; + UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); + PVM pVM = pUVM->pVM; VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); VM_ASSERT_OTHER_THREAD(pVM); AssertPtrReturn(pStreamOps, VERR_INVALID_POINTER); @@ -1962,7 +2047,7 @@ VMMR3DECL(int) VMR3Teleport(PVM pVM, uint32_t cMsMaxDowntime, PCSSMSTRMOPS pStre * * @returns VBox status code. * - * @param pVM Pointer to the VM. + * @param pUVM Pointer to the VM. * @param pszFilename The name of the file. NULL if pStreamOps is used. * @param pStreamOps The stream methods. NULL if pszFilename is used. * @param pvStreamOpsUser The user argument to the stream methods. @@ -1973,19 +2058,21 @@ VMMR3DECL(int) VMR3Teleport(PVM pVM, uint32_t cMsMaxDowntime, PCSSMSTRMOPS pStre * * @thread EMT. */ -static DECLCALLBACK(int) vmR3Load(PVM pVM, const char *pszFilename, PCSSMSTRMOPS pStreamOps, void *pvStreamOpsUser, +static DECLCALLBACK(int) vmR3Load(PUVM pUVM, const char *pszFilename, PCSSMSTRMOPS pStreamOps, void *pvStreamOpsUser, PFNVMPROGRESS pfnProgress, void *pvProgressUser, bool fTeleporting, bool fSkipStateChanges) { int rc = VINF_SUCCESS; - LogFlow(("vmR3Load: pVM=%p pszFilename=%p:{%s} pStreamOps=%p pvStreamOpsUser=%p pfnProgress=%p pvProgressUser=%p fTeleporting=%RTbool\n", - pVM, pszFilename, pszFilename, pStreamOps, pvStreamOpsUser, pfnProgress, pvProgressUser, fTeleporting)); + LogFlow(("vmR3Load: pUVM=%p pszFilename=%p:{%s} pStreamOps=%p pvStreamOpsUser=%p pfnProgress=%p pvProgressUser=%p fTeleporting=%RTbool\n", + pUVM, pszFilename, pszFilename, pStreamOps, pvStreamOpsUser, pfnProgress, pvProgressUser, fTeleporting)); /* * Validate input (paranoia). */ - AssertPtr(pVM); + UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); + PVM pVM = pUVM->pVM; + VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); AssertPtrNull(pszFilename); AssertPtrNull(pStreamOps); AssertPtrNull(pfnProgress); @@ -1999,14 +2086,14 @@ static DECLCALLBACK(int) vmR3Load(PVM pVM, const char *pszFilename, PCSSMSTRMOPS * selectors and such are correct. */ rc = vmR3TrySetState(pVM, "VMR3Load", 2, - VMSTATE_LOADING, VMSTATE_CREATED, - VMSTATE_LOADING, VMSTATE_SUSPENDED); + VMSTATE_LOADING, VMSTATE_CREATED, + VMSTATE_LOADING, VMSTATE_SUSPENDED); if (RT_FAILURE(rc)) return rc; } pVM->vm.s.fTeleportedAndNotFullyResumedYet = fTeleporting; - uint32_t cErrorsPriorToSave = VMR3GetErrorCount(pVM); + uint32_t cErrorsPriorToSave = VMR3GetErrorCount(pUVM); rc = SSMR3Load(pVM, pszFilename, pStreamOps, pvStreamOpsUser, SSMAFTER_RESUME, pfnProgress, pvProgressUser); if (RT_SUCCESS(rc)) { @@ -2020,7 +2107,7 @@ static DECLCALLBACK(int) vmR3Load(PVM pVM, const char *pszFilename, PCSSMSTRMOPS if (!fSkipStateChanges) vmR3SetState(pVM, VMSTATE_LOAD_FAILURE, VMSTATE_LOADING); - if (cErrorsPriorToSave == VMR3GetErrorCount(pVM)) + if (cErrorsPriorToSave == VMR3GetErrorCount(pUVM)) rc = VMSetError(pVM, rc, RT_SRC_POS, N_("Unable to restore the virtual machine's saved state from '%s'. " "It may be damaged or from an older version of VirtualBox. " @@ -2049,24 +2136,24 @@ static DECLCALLBACK(int) vmR3Load(PVM pVM, const char *pszFilename, PCSSMSTRMOPS * @vmstate Created, Suspended * @vmstateto Loading+Suspended */ -VMMR3DECL(int) VMR3LoadFromFile(PVM pVM, const char *pszFilename, PFNVMPROGRESS pfnProgress, void *pvUser) +VMMR3DECL(int) VMR3LoadFromFile(PUVM pUVM, const char *pszFilename, PFNVMPROGRESS pfnProgress, void *pvUser) { - LogFlow(("VMR3LoadFromFile: pVM=%p pszFilename=%p:{%s} pfnProgress=%p pvUser=%p\n", - pVM, pszFilename, pszFilename, pfnProgress, pvUser)); + LogFlow(("VMR3LoadFromFile: pUVM=%p pszFilename=%p:{%s} pfnProgress=%p pvUser=%p\n", + pUVM, pszFilename, pszFilename, pfnProgress, pvUser)); /* * Validate input. */ - VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); + UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); AssertPtrReturn(pszFilename, VERR_INVALID_POINTER); /* * Forward the request to EMT(0). No need to setup a rendezvous here * since there is no execution taking place when this call is allowed. */ - int rc = VMR3ReqCallWait(pVM, 0 /*idDstCpu*/, (PFNRT)vmR3Load, 8, - pVM, pszFilename, (uintptr_t)NULL /*pStreamOps*/, (uintptr_t)NULL /*pvStreamOpsUser*/, pfnProgress, pvUser, - false /*fTeleporting*/, false /* fSkipStateChanges */); + int rc = VMR3ReqCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)vmR3Load, 8, + pUVM, pszFilename, (uintptr_t)NULL /*pStreamOps*/, (uintptr_t)NULL /*pvStreamOpsUser*/, pfnProgress, pvUser, + false /*fTeleporting*/, false /* fSkipStateChanges */); LogFlow(("VMR3LoadFromFile: returns %Rrc\n", rc)); return rc; } @@ -2077,7 +2164,7 @@ VMMR3DECL(int) VMR3LoadFromFile(PVM pVM, const char *pszFilename, PFNVMPROGRESS * * @returns VBox status code. * - * @param pVM Pointer to the VM. + * @param pUVM Pointer to the VM. * @param pStreamOps The stream methods. * @param pvStreamOpsUser The user argument to the stream methods. * @param pfnProgress Progress callback. Optional. @@ -2087,36 +2174,36 @@ VMMR3DECL(int) VMR3LoadFromFile(PVM pVM, const char *pszFilename, PFNVMPROGRESS * @vmstate Created, Suspended * @vmstateto Loading+Suspended */ -VMMR3DECL(int) VMR3LoadFromStream(PVM pVM, PCSSMSTRMOPS pStreamOps, void *pvStreamOpsUser, +VMMR3DECL(int) VMR3LoadFromStream(PUVM pUVM, PCSSMSTRMOPS pStreamOps, void *pvStreamOpsUser, PFNVMPROGRESS pfnProgress, void *pvProgressUser) { - LogFlow(("VMR3LoadFromStream: pVM=%p pStreamOps=%p pvStreamOpsUser=%p pfnProgress=%p pvProgressUser=%p\n", - pVM, pStreamOps, pvStreamOpsUser, pfnProgress, pvProgressUser)); + LogFlow(("VMR3LoadFromStream: pUVM=%p pStreamOps=%p pvStreamOpsUser=%p pfnProgress=%p pvProgressUser=%p\n", + pUVM, pStreamOps, pvStreamOpsUser, pfnProgress, pvProgressUser)); /* * Validate input. */ - VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); + UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); AssertPtrReturn(pStreamOps, VERR_INVALID_POINTER); /* * Forward the request to EMT(0). No need to setup a rendezvous here * since there is no execution taking place when this call is allowed. */ - int rc = VMR3ReqCallWait(pVM, 0 /*idDstCpu*/, (PFNRT)vmR3Load, 8, - pVM, (uintptr_t)NULL /*pszFilename*/, pStreamOps, pvStreamOpsUser, pfnProgress, pvProgressUser, - true /*fTeleporting*/, false /* fSkipStateChanges */); + int rc = VMR3ReqCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)vmR3Load, 8, + pUVM, (uintptr_t)NULL /*pszFilename*/, pStreamOps, pvStreamOpsUser, pfnProgress, pvProgressUser, + true /*fTeleporting*/, false /* fSkipStateChanges */); LogFlow(("VMR3LoadFromStream: returns %Rrc\n", rc)); return rc; } /** - * VMR3LoadFromFileFT for arbitrary file streams. + * Special version for the FT component, it skips state changes. * * @returns VBox status code. * - * @param pVM Pointer to the VM. + * @param pUVM The VM handle. * @param pStreamOps The stream methods. * @param pvStreamOpsUser The user argument to the stream methods. * @param pfnProgress Progress callback. Optional. @@ -2126,24 +2213,23 @@ VMMR3DECL(int) VMR3LoadFromStream(PVM pVM, PCSSMSTRMOPS pStreamOps, void *pvStre * @vmstate Created, Suspended * @vmstateto Loading+Suspended */ -VMMR3DECL(int) VMR3LoadFromStreamFT(PVM pVM, PCSSMSTRMOPS pStreamOps, void *pvStreamOpsUser) +VMMR3_INT_DECL(int) VMR3LoadFromStreamFT(PUVM pUVM, PCSSMSTRMOPS pStreamOps, void *pvStreamOpsUser) { - LogFlow(("VMR3LoadFromStreamFT: pVM=%p pStreamOps=%p pvStreamOpsUser=%p\n", - pVM, pStreamOps, pvStreamOpsUser)); + LogFlow(("VMR3LoadFromStreamFT: pUVM=%p pStreamOps=%p pvStreamOpsUser=%p\n", pUVM, pStreamOps, pvStreamOpsUser)); /* * Validate input. */ - VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); + UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); AssertPtrReturn(pStreamOps, VERR_INVALID_POINTER); /* * Forward the request to EMT(0). No need to setup a rendezvous here * since there is no execution taking place when this call is allowed. */ - int rc = VMR3ReqCallWait(pVM, 0 /*idDstCpu*/, (PFNRT)vmR3Load, 8, - pVM, (uintptr_t)NULL /*pszFilename*/, pStreamOps, pvStreamOpsUser, NULL, NULL, - true /*fTeleporting*/, true /* fSkipStateChanges */); + int rc = VMR3ReqCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)vmR3Load, 8, + pUVM, (uintptr_t)NULL /*pszFilename*/, pStreamOps, pvStreamOpsUser, NULL, NULL, + true /*fTeleporting*/, true /* fSkipStateChanges */); LogFlow(("VMR3LoadFromStream: returns %Rrc\n", rc)); return rc; } @@ -2183,7 +2269,7 @@ static DECLCALLBACK(VBOXSTRICTRC) vmR3PowerOff(PVM pVM, PVMCPU pVCpu, void *pvUs if (RT_FAILURE(rc)) return rc; if (rc >= 7) - SSMR3Cancel(pVM); + SSMR3Cancel(pVM->pUVM); } /* @@ -2211,13 +2297,13 @@ static DECLCALLBACK(VBOXSTRICTRC) vmR3PowerOff(PVM pVM, PVMCPU pVCpu, void *pvUs /** @todo make the state dumping at VMR3PowerOff optional. */ bool fOldBuffered = RTLogRelSetBuffering(true /*fBuffered*/); RTLogRelPrintf("****************** Guest state at power off ******************\n"); - DBGFR3Info(pVM, "cpumguest", "verbose", DBGFR3InfoLogRelHlp()); + DBGFR3Info(pVM->pUVM, "cpumguest", "verbose", DBGFR3InfoLogRelHlp()); RTLogRelPrintf("***\n"); - DBGFR3Info(pVM, "mode", NULL, DBGFR3InfoLogRelHlp()); + DBGFR3Info(pVM->pUVM, "mode", NULL, DBGFR3InfoLogRelHlp()); RTLogRelPrintf("***\n"); - DBGFR3Info(pVM, "activetimers", NULL, DBGFR3InfoLogRelHlp()); + DBGFR3Info(pVM->pUVM, "activetimers", NULL, DBGFR3InfoLogRelHlp()); RTLogRelPrintf("***\n"); - DBGFR3Info(pVM, "gdt", NULL, DBGFR3InfoLogRelHlp()); + DBGFR3Info(pVM->pUVM, "gdt", NULL, DBGFR3InfoLogRelHlp()); /** @todo dump guest call stack. */ #if 1 // "temporary" while debugging #1589 RTLogRelPrintf("***\n"); @@ -2267,6 +2353,7 @@ static DECLCALLBACK(VBOXSTRICTRC) vmR3PowerOff(PVM pVM, PVMCPU pVCpu, void *pvUs * Off or OffLS. */ PDMR3PowerOff(pVM); + DBGFR3PowerOff(pVM); PUVM pUVM = pVM->pUVM; RTCritSectEnter(&pUVM->vm.s.AtStateCritSect); @@ -2287,15 +2374,17 @@ static DECLCALLBACK(VBOXSTRICTRC) vmR3PowerOff(PVM pVM, PVMCPU pVCpu, void *pvUs * @returns VBox status code. When called on EMT, this will be a strict status * code that has to be propagated up the call stack. * - * @param pVM The handle of the VM to be powered off. + * @param pUVM The handle of the VM to be powered off. * * @thread Any thread. * @vmstate Suspended, Running, Guru Meditation, Load Failure * @vmstateto Off or OffLS */ -VMMR3DECL(int) VMR3PowerOff(PVM pVM) +VMMR3DECL(int) VMR3PowerOff(PUVM pUVM) { - LogFlow(("VMR3PowerOff: pVM=%p\n", pVM)); + LogFlow(("VMR3PowerOff: pUVM=%p\n", pUVM)); + UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); + PVM pVM = pUVM->pVM; VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); /* @@ -2324,54 +2413,34 @@ VMMR3DECL(int) VMR3PowerOff(PVM pVM) * @vmstate Off, Created * @vmstateto N/A */ -VMMR3DECL(int) VMR3Destroy(PVM pVM) +VMMR3DECL(int) VMR3Destroy(PUVM pUVM) { - LogFlow(("VMR3Destroy: pVM=%p\n", pVM)); + LogFlow(("VMR3Destroy: pUVM=%p\n", pUVM)); /* * Validate input. */ - if (!pVM) + if (!pUVM) return VERR_INVALID_VM_HANDLE; + UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); + PVM pVM = pUVM->pVM; VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); AssertLogRelReturn(!VM_IS_EMT(pVM), VERR_VM_THREAD_IS_EMT); /* - * Change VM state to destroying and unlink the VM. + * Change VM state to destroying and aall vmR3Destroy on each of the EMTs + * ending with EMT(0) doing the bulk of the cleanup. */ int rc = vmR3TrySetState(pVM, "VMR3Destroy", 1, VMSTATE_DESTROYING, VMSTATE_OFF); if (RT_FAILURE(rc)) return rc; - /** @todo lock this when we start having multiple machines in a process... */ - PUVM pUVM = pVM->pUVM; AssertPtr(pUVM); - if (g_pUVMsHead == pUVM) - g_pUVMsHead = pUVM->pNext; - else - { - PUVM pPrev = g_pUVMsHead; - while (pPrev && pPrev->pNext != pUVM) - pPrev = pPrev->pNext; - AssertMsgReturn(pPrev, ("pUVM=%p / pVM=%p is INVALID!\n", pUVM, pVM), VERR_INVALID_PARAMETER); - - pPrev->pNext = pUVM->pNext; - } - pUVM->pNext = NULL; - - /* - * Notify registered at destruction listeners. - */ - vmR3AtDtor(pVM); - - /* - * Call vmR3Destroy on each of the EMTs ending with EMT(0) doing the bulk - * of the cleanup. - */ - /* vmR3Destroy on all EMTs, ending with EMT(0). */ rc = VMR3ReqCallWait(pVM, VMCPUID_ALL_REVERSE, (PFNRT)vmR3Destroy, 1, pVM); AssertLogRelRC(rc); - /* Wait for EMTs and destroy the UVM. */ + /* + * Wait for EMTs to quit and destroy the UVM. + */ vmR3DestroyUVM(pUVM, 30000); LogFlow(("VMR3Destroy: returns VINF_SUCCESS\n")); @@ -2412,10 +2481,10 @@ DECLCALLBACK(int) vmR3Destroy(PVM pVM) RTLogFlags(NULL, "nodisabled nobuffered"); #endif #ifdef VBOX_WITH_STATISTICS - STAMR3Dump(pVM, "*"); + STAMR3Dump(pUVM, "*"); #else LogRel(("************************* Statistics *************************\n")); - STAMR3DumpToReleaseLog(pVM, "*"); + STAMR3DumpToReleaseLog(pUVM, "*"); LogRel(("********************* End of statistics **********************\n")); #endif @@ -2425,26 +2494,28 @@ DECLCALLBACK(int) vmR3Destroy(PVM pVM) int rc = TMR3Term(pVM); AssertRC(rc); #ifdef VBOX_WITH_DEBUGGER - rc = DBGCTcpTerminate(pVM, pUVM->vm.s.pvDBGC); + rc = DBGCTcpTerminate(pUVM, pUVM->vm.s.pvDBGC); pUVM->vm.s.pvDBGC = NULL; #endif AssertRC(rc); rc = FTMR3Term(pVM); AssertRC(rc); - rc = DBGFR3Term(pVM); - AssertRC(rc); rc = PDMR3Term(pVM); AssertRC(rc); + rc = DBGFR3Term(pVM); + AssertRC(rc); rc = IEMR3Term(pVM); AssertRC(rc); rc = EMR3Term(pVM); AssertRC(rc); rc = IOMR3Term(pVM); AssertRC(rc); +#ifdef VBOX_WITH_RAW_MODE rc = CSAMR3Term(pVM); AssertRC(rc); rc = PATMR3Term(pVM); AssertRC(rc); +#endif rc = TRPMR3Term(pVM); AssertRC(rc); rc = SELMR3Term(pVM); @@ -2453,7 +2524,7 @@ DECLCALLBACK(int) vmR3Destroy(PVM pVM) rc = REMR3Term(pVM); AssertRC(rc); #endif - rc = HWACCMR3Term(pVM); + rc = HMR3Term(pVM); AssertRC(rc); rc = PGMR3Term(pVM); AssertRC(rc); @@ -2462,7 +2533,7 @@ DECLCALLBACK(int) vmR3Destroy(PVM pVM) rc = CPUMR3Term(pVM); AssertRC(rc); SSMR3Term(pVM); - rc = PDMR3CritSectTerm(pVM); + rc = PDMR3CritSectBothTerm(pVM); AssertRC(rc); rc = MMR3Term(pVM); AssertRC(rc); @@ -2639,130 +2710,6 @@ static void vmR3DestroyUVM(PUVM pUVM, uint32_t cMilliesEMTWait) /** - * Enumerates the VMs in this process. - * - * @returns Pointer to the next VM. - * @returns NULL when no more VMs. - * @param pVMPrev The previous VM - * Use NULL to start the enumeration. - */ -VMMR3DECL(PVM) VMR3EnumVMs(PVM pVMPrev) -{ - /* - * This is quick and dirty. It has issues with VM being - * destroyed during the enumeration. - */ - PUVM pNext; - if (pVMPrev) - pNext = pVMPrev->pUVM->pNext; - else - pNext = g_pUVMsHead; - return pNext ? pNext->pVM : NULL; -} - - -/** - * Registers an at VM destruction callback. - * - * @returns VBox status code. - * @param pfnAtDtor Pointer to callback. - * @param pvUser User argument. - */ -VMMR3DECL(int) VMR3AtDtorRegister(PFNVMATDTOR pfnAtDtor, void *pvUser) -{ - /* - * Check if already registered. - */ - VM_ATDTOR_LOCK(); - PVMATDTOR pCur = g_pVMAtDtorHead; - while (pCur) - { - if (pfnAtDtor == pCur->pfnAtDtor) - { - VM_ATDTOR_UNLOCK(); - AssertMsgFailed(("Already registered at destruction callback %p!\n", pfnAtDtor)); - return VERR_INVALID_PARAMETER; - } - - /* next */ - pCur = pCur->pNext; - } - VM_ATDTOR_UNLOCK(); - - /* - * Allocate new entry. - */ - PVMATDTOR pVMAtDtor = (PVMATDTOR)RTMemAlloc(sizeof(*pVMAtDtor)); - if (!pVMAtDtor) - return VERR_NO_MEMORY; - - VM_ATDTOR_LOCK(); - pVMAtDtor->pfnAtDtor = pfnAtDtor; - pVMAtDtor->pvUser = pvUser; - pVMAtDtor->pNext = g_pVMAtDtorHead; - g_pVMAtDtorHead = pVMAtDtor; - VM_ATDTOR_UNLOCK(); - - return VINF_SUCCESS; -} - - -/** - * Deregisters an at VM destruction callback. - * - * @returns VBox status code. - * @param pfnAtDtor Pointer to callback. - */ -VMMR3DECL(int) VMR3AtDtorDeregister(PFNVMATDTOR pfnAtDtor) -{ - /* - * Find it, unlink it and free it. - */ - VM_ATDTOR_LOCK(); - PVMATDTOR pPrev = NULL; - PVMATDTOR pCur = g_pVMAtDtorHead; - while (pCur) - { - if (pfnAtDtor == pCur->pfnAtDtor) - { - if (pPrev) - pPrev->pNext = pCur->pNext; - else - g_pVMAtDtorHead = pCur->pNext; - pCur->pNext = NULL; - VM_ATDTOR_UNLOCK(); - - RTMemFree(pCur); - return VINF_SUCCESS; - } - - /* next */ - pPrev = pCur; - pCur = pCur->pNext; - } - VM_ATDTOR_UNLOCK(); - - return VERR_INVALID_PARAMETER; -} - - -/** - * Walks the list of at VM destructor callbacks. - * @param pVM The VM which is about to be destroyed. - */ -static void vmR3AtDtor(PVM pVM) -{ - /* - * Find it, unlink it and free it. - */ - VM_ATDTOR_LOCK(); - for (PVMATDTOR pCur = g_pVMAtDtorHead; pCur; pCur = pCur->pNext) - pCur->pfnAtDtor(pVM, pCur->pvUser); - VM_ATDTOR_UNLOCK(); -} - - -/** * Worker which checks integrity of some internal structures. * This is yet another attempt to track down that AVL tree crash. */ @@ -2836,19 +2783,12 @@ static DECLCALLBACK(VBOXSTRICTRC) vmR3Reset(PVM pVM, PVMCPU pVCpu, void *pvUser) */ if (pVCpu->idCpu == 0) { +#ifdef VBOX_WITH_RAW_MODE PATMR3Reset(pVM); CSAMR3Reset(pVM); - PGMR3Reset(pVM); /* We clear VM RAM in PGMR3Reset. It's vital PDMR3Reset is executed - * _afterwards_. E.g. ACPI sets up RAM tables during init/reset. */ -/** @todo PGMR3Reset should be called after PDMR3Reset really, because we'll trash OS <-> hardware - * communication structures residing in RAM when done in the other order. I.e. the device must be - * quiesced first, then we clear the memory and plan tables. Probably have to make these things - * explicit in some way, some memory setup pass or something. - * (Example: DevAHCI may assert if memory is zeroed before it has read the FIS.) - * - * @bugref{4467} - */ +#endif PDMR3Reset(pVM); + PGMR3Reset(pVM); SELMR3Reset(pVM); TRPMR3Reset(pVM); #ifdef VBOX_WITH_REM @@ -2856,23 +2796,25 @@ static DECLCALLBACK(VBOXSTRICTRC) vmR3Reset(PVM pVM, PVMCPU pVCpu, void *pvUser) #endif IOMR3Reset(pVM); CPUMR3Reset(pVM); - } - CPUMR3ResetCpu(pVCpu); - if (pVCpu->idCpu == 0) - { TMR3Reset(pVM); EMR3Reset(pVM); - HWACCMR3Reset(pVM); /* This must come *after* PATM, CSAM, CPUM, SELM and TRPM. */ + HMR3Reset(pVM); /* This must come *after* PATM, CSAM, CPUM, SELM and TRPM. */ #ifdef LOG_ENABLED /* * Debug logging. */ RTLogPrintf("\n\nThe VM was reset:\n"); - DBGFR3Info(pVM, "cpum", "verbose", NULL); + DBGFR3Info(pVM->pUVM, "cpum", "verbose", NULL); #endif /* + * Do memory setup. + */ + PGMR3MemSetup(pVM, true /*fAtReset*/); + PDMR3MemSetup(pVM, true /*fAtReset*/); + + /* * Since EMT(0) is the last to go thru here, it will advance the state. * When a live save is active, we will move on to SuspendingLS but * leave it for VMR3Reset to do the actual suspending due to deadlock risks. @@ -2914,13 +2856,23 @@ static DECLCALLBACK(VBOXSTRICTRC) vmR3Reset(PVM pVM, PVMCPU pVCpu, void *pvUser) * Reset the current VM. * * @returns VBox status code. - * @param pVM VM to reset. + * @param pUVM The VM to reset. */ -VMMR3DECL(int) VMR3Reset(PVM pVM) +VMMR3DECL(int) VMR3Reset(PUVM pUVM) { LogFlow(("VMR3Reset:\n")); + UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); + PVM pVM = pUVM->pVM; VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); + if (pVM->vm.s.fPowerOffInsteadOfReset) + { + if ( pUVM->pVmm2UserMethods + && pUVM->pVmm2UserMethods->pfnNotifyResetTurnedIntoPowerOff) + pUVM->pVmm2UserMethods->pfnNotifyResetTurnedIntoPowerOff(pUVM->pVmm2UserMethods, pUVM); + return VMR3PowerOff(pUVM); + } + /* * Gather all the EMTs to make sure there are no races before * changing the VM state. @@ -3350,7 +3302,7 @@ static void vmR3DoAtState(PVM pVM, PUVM pUVM, VMSTATE enmStateNew, VMSTATE enmSt for (PVMATSTATE pCur = pUVM->vm.s.pAtState; pCur; pCur = pCur->pNext) { - pCur->pfnAtState(pVM, enmStateNew, enmStateOld, pCur->pvUser); + pCur->pfnAtState(pUVM, enmStateNew, enmStateOld, pCur->pvUser); if ( enmStateNew != VMSTATE_DESTROYING && pVM->enmVMState == VMSTATE_DESTROYING) break; @@ -3522,7 +3474,7 @@ void vmR3SetGuruMeditation(PVM pVM) else if (enmStateCur == VMSTATE_RUNNING_LS) { vmR3SetStateLocked(pVM, pUVM, VMSTATE_GURU_MEDITATION_LS, VMSTATE_RUNNING_LS); - SSMR3Cancel(pVM); + SSMR3Cancel(pUVM); } RTCritSectLeave(&pUVM->vm.s.AtStateCritSect); @@ -3550,7 +3502,7 @@ void vmR3SetTerminated(PVM pVM) * @param pVM Pointer to the VM. * @thread Any thread. */ -VMMR3DECL(bool) VMR3TeleportedAndNotFullyResumedYet(PVM pVM) +VMMR3_INT_DECL(bool) VMR3TeleportedAndNotFullyResumedYet(PVM pVM) { VM_ASSERT_VALID_EXT_RETURN(pVM, false); return pVM->vm.s.fTeleportedAndNotFullyResumedYet; @@ -3564,12 +3516,12 @@ VMMR3DECL(bool) VMR3TeleportedAndNotFullyResumedYet(PVM pVM) * state callback. * * @returns VBox status code. - * @param pVM Pointer to the VM. + * @param pUVM The VM handle. * @param pfnAtState Pointer to callback. * @param pvUser User argument. * @thread Any. */ -VMMR3DECL(int) VMR3AtStateRegister(PVM pVM, PFNVMATSTATE pfnAtState, void *pvUser) +VMMR3DECL(int) VMR3AtStateRegister(PUVM pUVM, PFNVMATSTATE pfnAtState, void *pvUser) { LogFlow(("VMR3AtStateRegister: pfnAtState=%p pvUser=%p\n", pfnAtState, pvUser)); @@ -3577,12 +3529,11 @@ VMMR3DECL(int) VMR3AtStateRegister(PVM pVM, PFNVMATSTATE pfnAtState, void *pvUse * Validate input. */ AssertPtrReturn(pfnAtState, VERR_INVALID_PARAMETER); - VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); + UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); /* * Allocate a new record. */ - PUVM pUVM = pVM->pUVM; PVMATSTATE pNew = (PVMATSTATE)MMR3HeapAllocU(pUVM, MM_TAG_VM, sizeof(*pNew)); if (!pNew) return VERR_NO_MEMORY; @@ -3606,12 +3557,12 @@ VMMR3DECL(int) VMR3AtStateRegister(PVM pVM, PFNVMATSTATE pfnAtState, void *pvUse * Deregisters a VM state change callback. * * @returns VBox status code. - * @param pVM Pointer to the VM. + * @param pUVM The VM handle. * @param pfnAtState Pointer to callback. * @param pvUser User argument. * @thread Any. */ -VMMR3DECL(int) VMR3AtStateDeregister(PVM pVM, PFNVMATSTATE pfnAtState, void *pvUser) +VMMR3DECL(int) VMR3AtStateDeregister(PUVM pUVM, PFNVMATSTATE pfnAtState, void *pvUser) { LogFlow(("VMR3AtStateDeregister: pfnAtState=%p pvUser=%p\n", pfnAtState, pvUser)); @@ -3619,9 +3570,8 @@ VMMR3DECL(int) VMR3AtStateDeregister(PVM pVM, PFNVMATSTATE pfnAtState, void *pvU * Validate input. */ AssertPtrReturn(pfnAtState, VERR_INVALID_PARAMETER); - VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); + UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); - PUVM pUVM = pVM->pUVM; RTCritSectEnter(&pUVM->vm.s.AtStateCritSect); /* @@ -3676,28 +3626,12 @@ VMMR3DECL(int) VMR3AtStateDeregister(PVM pVM, PFNVMATSTATE pfnAtState, void *pvU * Registers a VM error callback. * * @returns VBox status code. - * @param pVM Pointer to the VM. - * @param pfnAtError Pointer to callback. - * @param pvUser User argument. - * @thread Any. - */ -VMMR3DECL(int) VMR3AtErrorRegister(PVM pVM, PFNVMATERROR pfnAtError, void *pvUser) -{ - VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); - return VMR3AtErrorRegisterU(pVM->pUVM, pfnAtError, pvUser); -} - - -/** - * Registers a VM error callback. - * - * @returns VBox status code. - * @param pUVM Pointer to the VM. + * @param pUVM The VM handle. * @param pfnAtError Pointer to callback. * @param pvUser User argument. * @thread Any. */ -VMMR3DECL(int) VMR3AtErrorRegisterU(PUVM pUVM, PFNVMATERROR pfnAtError, void *pvUser) +VMMR3DECL(int) VMR3AtErrorRegister(PUVM pUVM, PFNVMATERROR pfnAtError, void *pvUser) { LogFlow(("VMR3AtErrorRegister: pfnAtError=%p pvUser=%p\n", pfnAtError, pvUser)); @@ -3733,12 +3667,12 @@ VMMR3DECL(int) VMR3AtErrorRegisterU(PUVM pUVM, PFNVMATERROR pfnAtError, void * * Deregisters a VM error callback. * * @returns VBox status code. - * @param pVM Pointer to the VM. + * @param pUVM The VM handle. * @param pfnAtError Pointer to callback. * @param pvUser User argument. * @thread Any. */ -VMMR3DECL(int) VMR3AtErrorDeregister(PVM pVM, PFNVMATERROR pfnAtError, void *pvUser) +VMMR3DECL(int) VMR3AtErrorDeregister(PUVM pUVM, PFNVMATERROR pfnAtError, void *pvUser) { LogFlow(("VMR3AtErrorDeregister: pfnAtError=%p pvUser=%p\n", pfnAtError, pvUser)); @@ -3746,9 +3680,8 @@ VMMR3DECL(int) VMR3AtErrorDeregister(PVM pVM, PFNVMATERROR pfnAtError, void *pvU * Validate input. */ AssertPtrReturn(pfnAtError, VERR_INVALID_PARAMETER); - VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); + UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); - PUVM pUVM = pVM->pUVM; RTCritSectEnter(&pUVM->vm.s.AtErrorCritSect); /* @@ -3806,7 +3739,7 @@ static void vmR3SetErrorWorkerDoCall(PVM pVM, PVMATERROR pCur, int rc, RT_SRC_PO { va_list va; va_start(va, pszFormat); - pCur->pfnAtError(pVM, pCur->pvUser, rc, RT_SRC_POS_ARGS, pszFormat, va); + pCur->pfnAtError(pVM->pUVM, pCur->pvUser, rc, RT_SRC_POS_ARGS, pszFormat, va); va_end(va); } @@ -3818,7 +3751,7 @@ static void vmR3SetErrorWorkerDoCall(PVM pVM, PVMATERROR pCur, int rc, RT_SRC_PO * @param pVM Pointer to the VM. * @thread EMT. */ -VMMR3DECL(void) VMR3SetErrorWorker(PVM pVM) +VMMR3_INT_DECL(void) VMR3SetErrorWorker(PVM pVM) { VM_ASSERT_EMT(pVM); AssertReleaseMsgFailed(("And we have a winner! You get to implement Ring-0 and GC VMSetErrorV! Congrats!\n")); @@ -3866,24 +3799,9 @@ VMMR3DECL(void) VMR3SetErrorWorker(PVM pVM) * This can be used avoid double error messages. * * @returns The error count. - * @param pVM Pointer to the VM. + * @param pUVM The VM handle. */ -VMMR3DECL(uint32_t) VMR3GetErrorCount(PVM pVM) -{ - AssertPtrReturn(pVM, 0); - return VMR3GetErrorCountU(pVM->pUVM); -} - - -/** - * Gets the number of errors raised via VMSetError. - * - * This can be used avoid double error messages. - * - * @returns The error count. - * @param pVM Pointer to the VM. - */ -VMMR3DECL(uint32_t) VMR3GetErrorCountU(PUVM pUVM) +VMMR3_INT_DECL(uint32_t) VMR3GetErrorCount(PUVM pUVM) { AssertPtrReturn(pUVM, 0); AssertReturn(pUVM->u32Magic == UVM_MAGIC, 0); @@ -3960,7 +3878,7 @@ DECLCALLBACK(void) vmR3SetErrorUV(PUVM pUVM, int rc, RT_SRC_POS_DECL, const char { va_list va2; va_copy(va2, *pArgs); - pCur->pfnAtError(pUVM->pVM, pCur->pvUser, rc, RT_SRC_POS_ARGS, pszFormat, va2); + pCur->pfnAtError(pUVM, pCur->pvUser, rc, RT_SRC_POS_ARGS, pszFormat, va2); va_end(va2); fCalledSomeone = true; } @@ -3969,6 +3887,53 @@ DECLCALLBACK(void) vmR3SetErrorUV(PUVM pUVM, int rc, RT_SRC_POS_DECL, const char /** + * Sets the error message. + * + * @returns rc. Meaning you can do: + * @code + * return VM_SET_ERROR_U(pUVM, VERR_OF_YOUR_CHOICE, "descriptive message"); + * @endcode + * @param pUVM The user mode VM handle. + * @param rc VBox status code. + * @param RT_SRC_POS_DECL Use RT_SRC_POS. + * @param pszFormat Error message format string. + * @param ... Error message arguments. + * @thread Any + */ +VMMR3DECL(int) VMR3SetError(PUVM pUVM, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...) +{ + va_list va; + va_start(va, pszFormat); + int rcRet = VMR3SetErrorV(pUVM, rc, pszFile, iLine, pszFunction, pszFormat, va); + va_end(va); + return rcRet; +} + + +/** + * Sets the error message. + * + * @returns rc. Meaning you can do: + * @code + * return VM_SET_ERROR_U(pUVM, VERR_OF_YOUR_CHOICE, "descriptive message"); + * @endcode + * @param pUVM The user mode VM handle. + * @param rc VBox status code. + * @param RT_SRC_POS_DECL Use RT_SRC_POS. + * @param pszFormat Error message format string. + * @param va Error message arguments. + * @thread Any + */ +VMMR3DECL(int) VMR3SetErrorV(PUVM pUVM, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va) +{ + UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); + VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, VERR_INVALID_VM_HANDLE); + return VMSetErrorV(pUVM->pVM, rc, pszFile, iLine, pszFunction, pszFormat, va); +} + + + +/** * Registers a VM runtime error callback. * * @returns VBox status code. @@ -3977,7 +3942,7 @@ DECLCALLBACK(void) vmR3SetErrorUV(PUVM pUVM, int rc, RT_SRC_POS_DECL, const char * @param pvUser User argument. * @thread Any. */ -VMMR3DECL(int) VMR3AtRuntimeErrorRegister(PVM pVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser) +VMMR3DECL(int) VMR3AtRuntimeErrorRegister(PUVM pUVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser) { LogFlow(("VMR3AtRuntimeErrorRegister: pfnAtRuntimeError=%p pvUser=%p\n", pfnAtRuntimeError, pvUser)); @@ -3985,12 +3950,11 @@ VMMR3DECL(int) VMR3AtRuntimeErrorRegister(PVM pVM, PFNVMATRUNTIMEERROR pfnAtRu * Validate input. */ AssertPtrReturn(pfnAtRuntimeError, VERR_INVALID_PARAMETER); - VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); + UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); /* * Allocate a new record. */ - PUVM pUVM = pVM->pUVM; PVMATRUNTIMEERROR pNew = (PVMATRUNTIMEERROR)MMR3HeapAllocU(pUVM, MM_TAG_VM, sizeof(*pNew)); if (!pNew) return VERR_NO_MEMORY; @@ -4014,12 +3978,12 @@ VMMR3DECL(int) VMR3AtRuntimeErrorRegister(PVM pVM, PFNVMATRUNTIMEERROR pfnAtRu * Deregisters a VM runtime error callback. * * @returns VBox status code. - * @param pVM Pointer to the VM. + * @param pUVM The user mode VM handle. * @param pfnAtRuntimeError Pointer to callback. * @param pvUser User argument. * @thread Any. */ -VMMR3DECL(int) VMR3AtRuntimeErrorDeregister(PVM pVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser) +VMMR3DECL(int) VMR3AtRuntimeErrorDeregister(PUVM pUVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser) { LogFlow(("VMR3AtRuntimeErrorDeregister: pfnAtRuntimeError=%p pvUser=%p\n", pfnAtRuntimeError, pvUser)); @@ -4027,9 +3991,8 @@ VMMR3DECL(int) VMR3AtRuntimeErrorDeregister(PVM pVM, PFNVMATRUNTIMEERROR pfnAt * Validate input. */ AssertPtrReturn(pfnAtRuntimeError, VERR_INVALID_PARAMETER); - VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); + UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); - PUVM pUVM = pVM->pUVM; RTCritSectEnter(&pUVM->vm.s.AtErrorCritSect); /* @@ -4107,7 +4070,7 @@ static DECLCALLBACK(VBOXSTRICTRC) vmR3SetRuntimeErrorChangeState(PVM pVM, PVMCPU if (RT_FAILURE(rc)) return rc; if (rc == 2) - SSMR3Cancel(pVM); + SSMR3Cancel(pVM->pUVM); VM_FF_SET(pVM, VM_FF_CHECK_VM_STATE); } @@ -4133,6 +4096,7 @@ static DECLCALLBACK(VBOXSTRICTRC) vmR3SetRuntimeErrorChangeState(PVM pVM, PVMCPU static int vmR3SetRuntimeErrorCommon(PVM pVM, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, va_list *pVa) { LogRel(("VM: Raising runtime error '%s' (fFlags=%#x)\n", pszErrorId, fFlags)); + PUVM pUVM = pVM->pUVM; /* * Take actions before the call. @@ -4142,21 +4106,20 @@ static int vmR3SetRuntimeErrorCommon(PVM pVM, uint32_t fFlags, const char *pszEr rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_DESCENDING | VMMEMTRENDEZVOUS_FLAGS_STOP_ON_ERROR, vmR3SetRuntimeErrorChangeState, NULL); else if (fFlags & VMSETRTERR_FLAGS_SUSPEND) - rc = VMR3Suspend(pVM); + rc = VMR3Suspend(pUVM, VMSUSPENDREASON_RUNTIME_ERROR); else rc = VINF_SUCCESS; /* * Do the callback round. */ - PUVM pUVM = pVM->pUVM; RTCritSectEnter(&pUVM->vm.s.AtErrorCritSect); ASMAtomicIncU32(&pUVM->vm.s.cRuntimeErrors); for (PVMATRUNTIMEERROR pCur = pUVM->vm.s.pAtRuntimeError; pCur; pCur = pCur->pNext) { va_list va; va_copy(va, *pVa); - pCur->pfnAtRuntimeError(pVM, pCur->pvUser, fFlags, pszErrorId, pszFormat, va); + pCur->pfnAtRuntimeError(pUVM, pCur->pvUser, fFlags, pszErrorId, pszFormat, va); va_end(va); } RTCritSectLeave(&pUVM->vm.s.AtErrorCritSect); @@ -4188,7 +4151,7 @@ static int vmR3SetRuntimeErrorCommonF(PVM pVM, uint32_t fFlags, const char *pszE * @param pVM Pointer to the VM. * @thread EMT. */ -VMMR3DECL(int) VMR3SetRuntimeErrorWorker(PVM pVM) +VMMR3_INT_DECL(int) VMR3SetRuntimeErrorWorker(PVM pVM) { VM_ASSERT_EMT(pVM); AssertReleaseMsgFailed(("And we have a winner! You get to implement Ring-0 and GC VMSetRuntimeErrorV! Congrats!\n")); @@ -4286,11 +4249,11 @@ DECLCALLBACK(int) vmR3SetRuntimeErrorV(PVM pVM, uint32_t fFlags, const char *psz * This can be used avoid double error messages. * * @returns The runtime error count. - * @param pVM Pointer to the VM. + * @param pUVM The user mode VM handle. */ -VMMR3DECL(uint32_t) VMR3GetRuntimeErrorCount(PVM pVM) +VMMR3_INT_DECL(uint32_t) VMR3GetRuntimeErrorCount(PUVM pUVM) { - return pVM->pUVM->vm.s.cRuntimeErrors; + return pUVM->vm.s.cRuntimeErrors; } @@ -4301,7 +4264,7 @@ VMMR3DECL(uint32_t) VMR3GetRuntimeErrorCount(PVM pVM) * * @param pVM Pointer to the VM. */ -VMMR3DECL(RTCPUID) VMR3GetVMCPUId(PVM pVM) +VMMR3_INT_DECL(RTCPUID) VMR3GetVMCPUId(PVM pVM) { PUVMCPU pUVCpu = (PUVMCPU)RTTlsGet(pVM->pUVM->vm.s.idxTLS); return pUVCpu @@ -4350,28 +4313,10 @@ VMMR3DECL(RTNATIVETHREAD) VMR3GetVMCPUNativeThreadU(PUVM pUVM) * Returns the handle of the current EMT VMCPU thread. * * @returns Handle if this is an EMT thread; NIL_RTNATIVETHREAD otherwise - * @param pVM Pointer to the VM. - * @thread EMT - */ -VMMR3DECL(RTTHREAD) VMR3GetVMCPUThread(PVM pVM) -{ - PUVMCPU pUVCpu = (PUVMCPU)RTTlsGet(pVM->pUVM->vm.s.idxTLS); - - if (!pUVCpu) - return NIL_RTTHREAD; - - return pUVCpu->vm.s.ThreadEMT; -} - - -/** - * Returns the handle of the current EMT VMCPU thread. - * - * @returns Handle if this is an EMT thread; NIL_RTNATIVETHREAD otherwise - * @param pVM Pointer to the VM. + * @param pUVM The user mode VM handle. * @thread EMT */ -VMMR3DECL(RTTHREAD) VMR3GetVMCPUThreadU(PUVM pUVM) +VMMR3DECL(RTTHREAD) VMR3GetVMCPUThread(PUVM pUVM) { PUVMCPU pUVCpu = (PUVMCPU)RTTlsGet(pUVM->vm.s.idxTLS); @@ -4383,20 +4328,22 @@ VMMR3DECL(RTTHREAD) VMR3GetVMCPUThreadU(PUVM pUVM) /** - * Return the package and core id of a CPU. + * Return the package and core ID of a CPU. * * @returns VBOX status code. - * @param pVM Pointer to the VM. + * @param pUVM The user mode VM handle. * @param idCpu Virtual CPU to get the ID from. * @param pidCpuCore Where to store the core ID of the virtual CPU. * @param pidCpuPackage Where to store the package ID of the virtual CPU. * */ -VMMR3DECL(int) VMR3GetCpuCoreAndPackageIdFromCpuId(PVM pVM, VMCPUID idCpu, uint32_t *pidCpuCore, uint32_t *pidCpuPackage) +VMMR3DECL(int) VMR3GetCpuCoreAndPackageIdFromCpuId(PUVM pUVM, VMCPUID idCpu, uint32_t *pidCpuCore, uint32_t *pidCpuPackage) { /* * Validate input. */ + UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); + PVM pVM = pUVM->pVM; VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); AssertPtrReturn(pidCpuCore, VERR_INVALID_POINTER); AssertPtrReturn(pidCpuPackage, VERR_INVALID_POINTER); @@ -4438,12 +4385,12 @@ static DECLCALLBACK(int) vmR3HotUnplugCpu(PVM pVM, VMCPUID idCpu) * even without this. */ Log(("vmR3HotUnplugCpu for VCPU %u\n", idCpu)); - PGMR3ResetUnpluggedCpu(pVM, pVCpu); + PGMR3ResetCpu(pVM, pVCpu); PDMR3ResetCpu(pVCpu); TRPMR3ResetCpu(pVCpu); - CPUMR3ResetCpu(pVCpu); + CPUMR3ResetCpu(pVM, pVCpu); EMR3ResetCpu(pVCpu); - HWACCMR3ResetCpu(pVCpu); + HMR3ResetCpu(pVCpu); return VINF_EM_WAIT_SIPI; } @@ -4452,11 +4399,13 @@ static DECLCALLBACK(int) vmR3HotUnplugCpu(PVM pVM, VMCPUID idCpu) * Hot-unplugs a CPU from the guest. * * @returns VBox status code. - * @param pVM Pointer to the VM. + * @param pUVM The user mode VM handle. * @param idCpu Virtual CPU to perform the hot unplugging operation on. */ -VMMR3DECL(int) VMR3HotUnplugCpu(PVM pVM, VMCPUID idCpu) +VMMR3DECL(int) VMR3HotUnplugCpu(PUVM pUVM, VMCPUID idCpu) { + UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); + PVM pVM = pUVM->pVM; VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); AssertReturn(idCpu < pVM->cCpus, VERR_INVALID_CPU_ID); @@ -4464,7 +4413,7 @@ VMMR3DECL(int) VMR3HotUnplugCpu(PVM pVM, VMCPUID idCpu) * broadcast requests. Just note down somewhere that the CPU is * offline and send it to SPIP wait. Maybe modify VMCPUSTATE and push * it out of the EM loops when offline. */ - return VMR3ReqCallNoWait(pVM, idCpu, (PFNRT)vmR3HotUnplugCpu, 2, pVM, idCpu); + return VMR3ReqCallNoWaitU(pUVM, idCpu, (PFNRT)vmR3HotUnplugCpu, 2, pVM, idCpu); } @@ -4472,11 +4421,13 @@ VMMR3DECL(int) VMR3HotUnplugCpu(PVM pVM, VMCPUID idCpu) * Hot-plugs a CPU on the guest. * * @returns VBox status code. - * @param pVM Pointer to the VM. + * @param pUVM The user mode VM handle. * @param idCpu Virtual CPU to perform the hot plugging operation on. */ -VMMR3DECL(int) VMR3HotPlugCpu(PVM pVM, VMCPUID idCpu) +VMMR3DECL(int) VMR3HotPlugCpu(PUVM pUVM, VMCPUID idCpu) { + UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); + PVM pVM = pUVM->pVM; VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); AssertReturn(idCpu < pVM->cCpus, VERR_INVALID_CPU_ID); @@ -4493,8 +4444,10 @@ VMMR3DECL(int) VMR3HotPlugCpu(PVM pVM, VMCPUID idCpu) * @param uCpuExecutionCap New CPU execution cap in precent, 1-100. Where * 100 is max performance (default). */ -VMMR3DECL(int) VMR3SetCpuExecutionCap(PVM pVM, uint32_t uCpuExecutionCap) +VMMR3DECL(int) VMR3SetCpuExecutionCap(PUVM pUVM, uint32_t uCpuExecutionCap) { + UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); + PVM pVM = pUVM->pVM; VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); AssertReturn(uCpuExecutionCap > 0 && uCpuExecutionCap <= 100, VERR_INVALID_PARAMETER); @@ -4504,3 +4457,23 @@ VMMR3DECL(int) VMR3SetCpuExecutionCap(PVM pVM, uint32_t uCpuExecutionCap) return VINF_SUCCESS; } + +/** + * Control whether the VM should power off when resetting. + * + * @returns VBox status code. + * @param pUVM The user mode VM handle. + * @param fPowerOffInsteadOfReset Flag whether the VM should power off when + * resetting. + */ +VMMR3DECL(int) VMR3SetPowerOffInsteadOfReset(PUVM pUVM, bool fPowerOffInsteadOfReset) +{ + UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); + PVM pVM = pUVM->pVM; + VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); + + /* Note: not called from EMT. */ + pVM->vm.s.fPowerOffInsteadOfReset = fPowerOffInsteadOfReset; + return VINF_SUCCESS; +} + |
