VM.cpp revision 827838e6676f326eada0163afbc53a681352033a
b0dfb334954c0552bb583967a3077ec88fd00471vboxsync * VM - Virtual Machine
d6aa6429f99fb7648883eb612f8a52b9aaf3bff4vboxsync * Copyright (C) 2006-2013 Oracle Corporation
b0dfb334954c0552bb583967a3077ec88fd00471vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
b0dfb334954c0552bb583967a3077ec88fd00471vboxsync * available from http://www.virtualbox.org. This file is free software;
b0dfb334954c0552bb583967a3077ec88fd00471vboxsync * you can redistribute it and/or modify it under the terms of the GNU
b0dfb334954c0552bb583967a3077ec88fd00471vboxsync * General Public License (GPL) as published by the Free Software
b0dfb334954c0552bb583967a3077ec88fd00471vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
b0dfb334954c0552bb583967a3077ec88fd00471vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
b0dfb334954c0552bb583967a3077ec88fd00471vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
aba0e602e244ae7c4f11b50fc6d2440f5a762038vboxsync/** @page pg_vm VM API
aba0e602e244ae7c4f11b50fc6d2440f5a762038vboxsync * This is the encapsulating bit. It provides the APIs that Main and VBoxBFE
aba0e602e244ae7c4f11b50fc6d2440f5a762038vboxsync * use to create a VMM instance for running a guest in. It also provides
aba0e602e244ae7c4f11b50fc6d2440f5a762038vboxsync * facilities for queuing request for execution in EMT (serialization purposes
aba0e602e244ae7c4f11b50fc6d2440f5a762038vboxsync * mostly) and for reporting error back to the VMM user (Main/VBoxBFE).
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * @section sec_vm_design Design Critique / Things To Do
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * In hindsight this component is a big design mistake, all this stuff really
b0dfb334954c0552bb583967a3077ec88fd00471vboxsync * belongs in the VMM component. It just seemed like a kind of ok idea at a
b0dfb334954c0552bb583967a3077ec88fd00471vboxsync * time when the VMM bit was a kind of vague. 'VM' also happened to be the name
b0dfb334954c0552bb583967a3077ec88fd00471vboxsync * of the per-VM instance structure (see vm.h), so it kind of made sense.
b0dfb334954c0552bb583967a3077ec88fd00471vboxsync * However as it turned out, VMM(.cpp) is almost empty all it provides in ring-3
b0dfb334954c0552bb583967a3077ec88fd00471vboxsync * is some minor functionally and some "routing" services.
64e0c74b525c440a571ce06f3eb6234d75913d76vboxsync * Fixing this is just a matter of some more or less straight forward
d6aa6429f99fb7648883eb612f8a52b9aaf3bff4vboxsync * refactoring, the question is just when someone will get to it. Moving the EMT
d6aa6429f99fb7648883eb612f8a52b9aaf3bff4vboxsync * would be a good start.
c312e1b81dffe42e0fb766020fb8defaeade05d6vboxsync/*******************************************************************************
c312e1b81dffe42e0fb766020fb8defaeade05d6vboxsync* Header Files *
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync*******************************************************************************/
b0dfb334954c0552bb583967a3077ec88fd00471vboxsync#if defined(VBOX_WITH_DTRACE_R3) && !defined(VBOX_WITH_NATIVE_DTRACE)
54828795a553ed0731f308ebda81675ad2c39d58vboxsync/*******************************************************************************
b0dfb334954c0552bb583967a3077ec88fd00471vboxsync* Global Variables *
b0dfb334954c0552bb583967a3077ec88fd00471vboxsync*******************************************************************************/
b0dfb334954c0552bb583967a3077ec88fd00471vboxsync/** Pointer to the list of VMs. */
50f0e2e83362e100d306a411980d555d46aa00a8vboxsync/*******************************************************************************
50f0e2e83362e100d306a411980d555d46aa00a8vboxsync* Internal Functions *
54828795a553ed0731f308ebda81675ad2c39d58vboxsync*******************************************************************************/
b0dfb334954c0552bb583967a3077ec88fd00471vboxsyncstatic int vmR3CreateUVM(uint32_t cCpus, PCVMM2USERMETHODS pVmm2UserMethods, PUVM *ppUVM);
b0dfb334954c0552bb583967a3077ec88fd00471vboxsyncstatic int vmR3CreateU(PUVM pUVM, uint32_t cCpus, PFNCFGMCONSTRUCTOR pfnCFGMConstructor, void *pvUserCFGM);
b0dfb334954c0552bb583967a3077ec88fd00471vboxsyncstatic int vmR3InitDoCompleted(PVM pVM, VMINITCOMPLETED enmWhat);
b0dfb334954c0552bb583967a3077ec88fd00471vboxsyncstatic DECLCALLBACK(size_t) vmR3LogPrefixCallback(PRTLOGGER pLogger, char *pchBuf, size_t cchBuf, void *pvUser);
8d29e9dc0d280b7b26834132b9ce14a3a845a7fdvboxsyncstatic void vmR3DestroyUVM(PUVM pUVM, uint32_t cMilliesEMTWait);
80523be8dba75b5eb32569fd72ddf54f3b009025vboxsyncstatic bool vmR3ValidateStateTransition(VMSTATE enmStateOld, VMSTATE enmStateNew);
80523be8dba75b5eb32569fd72ddf54f3b009025vboxsyncstatic void vmR3DoAtState(PVM pVM, PUVM pUVM, VMSTATE enmStateNew, VMSTATE enmStateOld);
80523be8dba75b5eb32569fd72ddf54f3b009025vboxsyncstatic int vmR3TrySetState(PVM pVM, const char *pszWho, unsigned cTransitions, ...);
80523be8dba75b5eb32569fd72ddf54f3b009025vboxsyncstatic void vmR3SetStateLocked(PVM pVM, PUVM pUVM, VMSTATE enmStateNew, VMSTATE enmStateOld);
80523be8dba75b5eb32569fd72ddf54f3b009025vboxsyncstatic void vmR3SetState(PVM pVM, VMSTATE enmStateNew, VMSTATE enmStateOld);
80523be8dba75b5eb32569fd72ddf54f3b009025vboxsyncstatic int vmR3SetErrorU(PUVM pUVM, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...);
80523be8dba75b5eb32569fd72ddf54f3b009025vboxsync * Do global VMM init.
80523be8dba75b5eb32569fd72ddf54f3b009025vboxsync * @returns VBox status code.
80523be8dba75b5eb32569fd72ddf54f3b009025vboxsync * Only once.
b3d4b85739cf74a503b1f8bbb7c7f4de26c1c09fvboxsync static bool volatile s_fDone = false;
b3d4b85739cf74a503b1f8bbb7c7f4de26c1c09fvboxsync#if defined(VBOX_WITH_DTRACE_R3) && !defined(VBOX_WITH_NATIVE_DTRACE)
b3d4b85739cf74a503b1f8bbb7c7f4de26c1c09fvboxsync SUPR3TracerRegisterModule(~(uintptr_t)0, "VBoxVMM", &g_VTGObjHeader, (uintptr_t)&g_VTGObjHeader,
b3d4b85739cf74a503b1f8bbb7c7f4de26c1c09fvboxsync * We're done.
b3d4b85739cf74a503b1f8bbb7c7f4de26c1c09fvboxsync * Creates a virtual machine by calling the supplied configuration constructor.
5d05aa26ae1949e6f0bbc149d8b8e39495710ac7vboxsync * On successful returned the VM is powered, i.e. VMR3PowerOn() should be
5d05aa26ae1949e6f0bbc149d8b8e39495710ac7vboxsync * called to start the execution.
5d05aa26ae1949e6f0bbc149d8b8e39495710ac7vboxsync * @returns 0 on success.
5d05aa26ae1949e6f0bbc149d8b8e39495710ac7vboxsync * @returns VBox error code on failure.
5d05aa26ae1949e6f0bbc149d8b8e39495710ac7vboxsync * @param cCpus Number of virtual CPUs for the new VM.
5d05aa26ae1949e6f0bbc149d8b8e39495710ac7vboxsync * @param pVmm2UserMethods An optional method table that the VMM can use
5d05aa26ae1949e6f0bbc149d8b8e39495710ac7vboxsync * to make the user perform various action, like
b3d4b85739cf74a503b1f8bbb7c7f4de26c1c09fvboxsync * for instance state saving.
b3d4b85739cf74a503b1f8bbb7c7f4de26c1c09fvboxsync * @param pfnVMAtError Pointer to callback function for setting VM
b3d4b85739cf74a503b1f8bbb7c7f4de26c1c09fvboxsync * errors. This was added as an implicit call to
8d29e9dc0d280b7b26834132b9ce14a3a845a7fdvboxsync * VMR3AtErrorRegister() since there is no way the
8d29e9dc0d280b7b26834132b9ce14a3a845a7fdvboxsync * caller can get to the VM handle early enough to
b60e4b0625949fd68ed97f1353e2174c5b3192e5vboxsync * do this on its own.
b60e4b0625949fd68ed97f1353e2174c5b3192e5vboxsync * This is called in the context of an EMT.
8d29e9dc0d280b7b26834132b9ce14a3a845a7fdvboxsync * @param pvUserVM The user argument passed to pfnVMAtError.
8d29e9dc0d280b7b26834132b9ce14a3a845a7fdvboxsync * @param pfnCFGMConstructor Pointer to callback function for constructing the VM configuration tree.
8d29e9dc0d280b7b26834132b9ce14a3a845a7fdvboxsync * This is called in the context of an EMT0.
8d29e9dc0d280b7b26834132b9ce14a3a845a7fdvboxsync * @param pvUserCFGM The user argument passed to pfnCFGMConstructor.
5d05aa26ae1949e6f0bbc149d8b8e39495710ac7vboxsync * @param ppVM Where to optionally store the 'handle' of the
8d29e9dc0d280b7b26834132b9ce14a3a845a7fdvboxsync * created VM.
8d29e9dc0d280b7b26834132b9ce14a3a845a7fdvboxsync * @param ppUVM Where to optionally store the user 'handle' of
8d29e9dc0d280b7b26834132b9ce14a3a845a7fdvboxsync * the created VM, this includes one reference as
64e0c74b525c440a571ce06f3eb6234d75913d76vboxsync * if VMR3RetainUVM() was called. The caller
1e2bc03fd1fc133bd3a066b1557471e157df78f6vboxsync * *MUST* remember to pass the returned value to
1e2bc03fd1fc133bd3a066b1557471e157df78f6vboxsync * VMR3ReleaseUVM() once done with the handle.
1e2bc03fd1fc133bd3a066b1557471e157df78f6vboxsyncVMMR3DECL(int) VMR3Create(uint32_t cCpus, PCVMM2USERMETHODS pVmm2UserMethods,
1e2bc03fd1fc133bd3a066b1557471e157df78f6vboxsync PFNCFGMCONSTRUCTOR pfnCFGMConstructor, void *pvUserCFGM,
1e2bc03fd1fc133bd3a066b1557471e157df78f6vboxsync LogFlow(("VMR3Create: cCpus=%RU32 pVmm2UserMethods=%p pfnVMAtError=%p pvUserVM=%p pfnCFGMConstructor=%p pvUserCFGM=%p ppVM=%p ppUVM=%p\n",
052deaa01d8fcd5cec4dff857833538940b751c3vboxsync cCpus, pVmm2UserMethods, pfnVMAtError, pvUserVM, pfnCFGMConstructor, pvUserCFGM, ppVM, ppUVM));
26bef2fb65df80a28b9972e0a43a92be367417d9vboxsync AssertPtrReturn(pVmm2UserMethods, VERR_INVALID_POINTER);
1e2bc03fd1fc133bd3a066b1557471e157df78f6vboxsync AssertReturn(pVmm2UserMethods->u32Magic == VMM2USERMETHODS_MAGIC, VERR_INVALID_PARAMETER);
1e2bc03fd1fc133bd3a066b1557471e157df78f6vboxsync AssertReturn(pVmm2UserMethods->u32Version == VMM2USERMETHODS_VERSION, VERR_INVALID_PARAMETER);
1e2bc03fd1fc133bd3a066b1557471e157df78f6vboxsync AssertPtrNullReturn(pVmm2UserMethods->pfnSaveState, VERR_INVALID_POINTER);
1e2bc03fd1fc133bd3a066b1557471e157df78f6vboxsync AssertPtrNullReturn(pVmm2UserMethods->pfnNotifyEmtInit, VERR_INVALID_POINTER);
1e2bc03fd1fc133bd3a066b1557471e157df78f6vboxsync AssertPtrNullReturn(pVmm2UserMethods->pfnNotifyEmtTerm, VERR_INVALID_POINTER);
1e2bc03fd1fc133bd3a066b1557471e157df78f6vboxsync AssertPtrNullReturn(pVmm2UserMethods->pfnNotifyPdmtInit, VERR_INVALID_POINTER);
39a628c9e979cb2355caa57eb099b13cb922783cvboxsync AssertPtrNullReturn(pVmm2UserMethods->pfnNotifyPdmtTerm, VERR_INVALID_POINTER);
1e2bc03fd1fc133bd3a066b1557471e157df78f6vboxsync AssertReturn(pVmm2UserMethods->u32EndMagic == VMM2USERMETHODS_MAGIC, VERR_INVALID_PARAMETER);
d308e8fdb9e4d827ed10d26d1581d265602f6f46vboxsync AssertPtrNullReturn(pfnVMAtError, VERR_INVALID_POINTER);
d308e8fdb9e4d827ed10d26d1581d265602f6f46vboxsync AssertPtrNullReturn(pfnCFGMConstructor, VERR_INVALID_POINTER);
5bcfdf9ef0306239498361e5021d008ad77bf539vboxsync AssertReturn(ppVM || ppUVM, VERR_INVALID_PARAMETER);
5bcfdf9ef0306239498361e5021d008ad77bf539vboxsync * Because of the current hackiness of the applications
5bcfdf9ef0306239498361e5021d008ad77bf539vboxsync * we'll have to initialize global stuff from here.
5bcfdf9ef0306239498361e5021d008ad77bf539vboxsync * Later the applications will take care of this in a proper way.
5bcfdf9ef0306239498361e5021d008ad77bf539vboxsync static bool fGlobalInitDone = false;
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * Validate input.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync AssertLogRelMsgReturn(cCpus > 0 && cCpus <= VMM_MAX_CPU_COUNT, ("%RU32\n", cCpus), VERR_TOO_MANY_CPUS);
5bcfdf9ef0306239498361e5021d008ad77bf539vboxsync * Create the UVM so we can register the at-error callback
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * and consolidate a bit of cleanup code.
b83d9b1072dd8491c7ffe37830e8fd10f2dba561vboxsync int rc = vmR3CreateUVM(cCpus, pVmm2UserMethods, &pUVM);
5bcfdf9ef0306239498361e5021d008ad77bf539vboxsync rc = VMR3AtErrorRegister(pUVM, pfnVMAtError, pvUserVM);
5bcfdf9ef0306239498361e5021d008ad77bf539vboxsync * Initialize the support library creating the session for this VM.
7dbde0174637fbfd00c50b383f654e46878eaa8evboxsync * Call vmR3CreateU in the EMT thread and wait for it to finish.
2077a9092ce42fb009a3ab89b095ec02af18213evboxsync * Note! VMCPUID_ANY is used here because VMR3ReqQueueU would have trouble
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * submitting a request to a specific VCPU without a pVM. So, to make
5bcfdf9ef0306239498361e5021d008ad77bf539vboxsync * sure init is running on EMT(0), vmR3EmulationThreadWithId makes sure
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * that only EMT(0) is servicing VMCPUID_ANY requests when pVM is NULL.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync rc = VMR3ReqCallU(pUVM, VMCPUID_ANY, &pReq, RT_INDEFINITE_WAIT, VMREQFLAGS_VBOX_STATUS,
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync (PFNRT)vmR3CreateU, 4, pUVM, cCpus, pfnCFGMConstructor, pvUserCFGM);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync LogFlow(("VMR3Create: returns VINF_SUCCESS (pVM=%p, pUVM=%p\n", pUVM->pVM, pUVM));
7dbde0174637fbfd00c50b383f654e46878eaa8evboxsync AssertMsgFailed(("VMR3ReqCallU failed rc=%Rrc\n", rc));
5bcfdf9ef0306239498361e5021d008ad77bf539vboxsync * An error occurred during VM creation. Set the error message directly
5bcfdf9ef0306239498361e5021d008ad77bf539vboxsync * using the initial callback, as the callback list might not exist yet.
846739bf4fe90231599e8de3a8c792ae2851b1d1vboxsync const char *pszError;
5bcfdf9ef0306239498361e5021d008ad77bf539vboxsync pszError = N_("VirtualBox can't operate in VMX root mode. "
5bcfdf9ef0306239498361e5021d008ad77bf539vboxsync "Please disable the KVM kernel extension, recompile your kernel and reboot");
846739bf4fe90231599e8de3a8c792ae2851b1d1vboxsync pszError = N_("VirtualBox can't operate in VMX root mode. Please close all other virtualization programs.");
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync pszError = N_("VT-x/AMD-V is either not available on your host or disabled. "
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync "This hardware extension is required by the VM configuration");
5bcfdf9ef0306239498361e5021d008ad77bf539vboxsync pszError = N_("VirtualBox can't enable the AMD-V extension. "
5bcfdf9ef0306239498361e5021d008ad77bf539vboxsync "Please disable the KVM kernel extension, recompile your kernel and reboot");
5bcfdf9ef0306239498361e5021d008ad77bf539vboxsync pszError = N_("VirtualBox can't enable the AMD-V extension. Please close all other virtualization programs.");
#ifdef RT_OS_LINUX
if (pszError)
const char *pszError;
switch (rc)
#ifdef RT_OS_LINUX
#ifdef VBOX_WITH_HARDENING
# if defined(RT_OS_DARWIN)
#ifdef RT_OS_LINUX
case VERR_NO_MEMORY:
case VERR_VERSION_MISMATCH:
return rc;
uint32_t i;
for (i = 0; i < cCpus; i++)
for (i = 0; i < cCpus; i++)
for (i = 0; i < cCpus; i++)
for (i = 0; i < cCpus; i++)
return VINF_SUCCESS;
for (i = 0; i < cCpus; i++)
return rc;
static int vmR3CreateU(PUVM pUVM, uint32_t cCpus, PFNCFGMCONSTRUCTOR pfnCFGMConstructor, void *pvUserCFGM)
AssertLogRelMsgRC(rc, ("Configuration error: Querying \"NumCPUs\" as integer failed, rc=%Rrc\n", rc));
AssertLogRelMsgFailed(("Configuration error: \"NumCPUs\"=%RU32 and VMR3CreateVM::cCpus=%RU32 does not match!\n",
AssertLogRelMsgRC(rc, ("Configuration error: Querying \"CpuExecutionCap\" as integer failed, rc=%Rrc\n", rc));
#ifdef VBOX_WITH_DEBUGGER
#ifdef LOG_ENABLED
return VINF_SUCCESS;
#ifdef VBOX_WITH_DEBUGGER
return rc;
return rc;
int rc;
return 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.");
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);
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);
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);
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);
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);
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);
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.");
#ifdef VBOX_WITH_REM
#ifdef VBOX_WITH_REM
return VINF_SUCCESS;
#ifdef VBOX_WITH_REM
return rc;
return rc;
return rc;
return rc;
#ifdef LOG_ENABLED
static DECLCALLBACK(size_t) vmR3LogPrefixCallback(PRTLOGGER pLogger, char *pchBuf, size_t cchBuf, void *pvUser)
if (pUVCpu)
return rc;
return VINF_SUCCESS;
int rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_DESCENDING | VMMEMTRENDEZVOUS_FLAGS_STOP_ON_ERROR,
return rc;
return rc;
return VINF_EM_SUSPEND;
int rc = VMMR3EmtRendezvous(pUVM->pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_DESCENDING | VMMEMTRENDEZVOUS_FLAGS_STOP_ON_ERROR,
return rc;
return rc;
return VINF_EM_RESUME;
int rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_DESCENDING | VMMEMTRENDEZVOUS_FLAGS_STOP_ON_ERROR,
return rc;
int rc;
switch (enmVMState)
case VMSTATE_RUNNING_LS:
case VMSTATE_SUSPENDED_EXT_LS:
case VMSTATE_DEBUGGING_LS:
case VMSTATE_OFF_LS:
case VMSTATE_FATAL_ERROR_LS:
case VMSTATE_POWERING_OFF_LS:
case VMSTATE_RESETTING_LS:
return rc;
*pfSuspended = true;
return VINF_EM_SUSPEND;
*pfSuspended = true;
else if (rc > 0)
return rc;
return rc;
static DECLCALLBACK(int) vmR3Save(PVM pVM, uint32_t cMsMaxDowntime, const char *pszFilename, PCSSMSTRMOPS pStreamOps, void *pvStreamOpsUser,
bool fSkipStateChanges)
LogFlow(("vmR3Save: pVM=%p cMsMaxDowntime=%u pszFilename=%p:{%s} pStreamOps=%p pvStreamOpsUser=%p enmAfter=%d pfnProgress=%p pvProgressUser=%p ppSSM=%p\n",
pVM, cMsMaxDowntime, pszFilename, pszFilename, pStreamOps, pvStreamOpsUser, enmAfter, pfnProgress, pvProgressUser, ppSSM));
if (!fSkipStateChanges)
rc = SSMR3Save(pVM, pszFilename, pStreamOps, pvStreamOpsUser, enmAfter, pfnProgress, pvProgressUser);
if (!fSkipStateChanges)
return rc;
bool fSkipStateChanges)
&& pSSM)
rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_DESCENDING | VMMEMTRENDEZVOUS_FLAGS_STOP_ON_ERROR,
RTThreadSleep(250); /** @todo Live Migration: fix this polling wait by some smart use of multiple release event semaphores.. */
rc2 = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, vmR3LiveDoStep1Cleanup, pfSuspended);
return rc;
VMMR3DECL(int) VMR3Save(PUVM pUVM, const char *pszFilename, bool fContinueAfterwards, PFNVMPROGRESS pfnProgress, void *pvUser, bool *pfSuspended)
LogFlow(("VMR3Save: pUVM=%p pszFilename=%p:{%s} fContinueAfterwards=%RTbool pfnProgress=%p pvUser=%p pfSuspended=%p\n",
*pfSuspended = false;
return rc;
VMMR3_INT_DECL(int) VMR3SaveFT(PUVM pUVM, PCSSMSTRMOPS pStreamOps, void *pvStreamOpsUser, bool *pfSuspended, bool fSkipStateChanges)
*pfSuspended = false;
return rc;
VMMR3DECL(int) VMR3Teleport(PUVM pUVM, uint32_t cMsMaxDowntime, PCSSMSTRMOPS pStreamOps, void *pvStreamOpsUser,
LogFlow(("VMR3Teleport: pUVM=%p cMsMaxDowntime=%u pStreamOps=%p pvStreamOps=%p pfnProgress=%p pvProgressUser=%p\n",
*pfSuspended = false;
return rc;
static DECLCALLBACK(int) vmR3Load(PUVM pUVM, const char *pszFilename, PCSSMSTRMOPS pStreamOps, void *pvStreamOpsUser,
bool fSkipStateChanges)
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));
if (!fSkipStateChanges)
return rc;
rc = SSMR3Load(pVM, pszFilename, pStreamOps, pvStreamOpsUser, SSMAFTER_RESUME, pfnProgress, pvProgressUser);
if (!fSkipStateChanges)
if (!fSkipStateChanges)
return rc;
VMMR3DECL(int) VMR3LoadFromFile(PUVM pUVM, const char *pszFilename, PFNVMPROGRESS pfnProgress, void *pvUser)
pUVM, pszFilename, (uintptr_t)NULL /*pStreamOps*/, (uintptr_t)NULL /*pvStreamOpsUser*/, pfnProgress, pvUser,
return rc;
LogFlow(("VMR3LoadFromStream: pUVM=%p pStreamOps=%p pvStreamOpsUser=%p pfnProgress=%p pvProgressUser=%p\n",
return rc;
LogFlow(("VMR3LoadFromStreamFT: pUVM=%p pStreamOps=%p pvStreamOpsUser=%p\n", pUVM, pStreamOps, pvStreamOpsUser));
return rc;
return rc;
return VINF_EM_OFF;
int rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_DESCENDING | VMMEMTRENDEZVOUS_FLAGS_STOP_ON_ERROR,
return rc;
if (!pUVM)
return VERR_INVALID_VM_HANDLE;
return rc;
return VINF_SUCCESS;
#ifdef VBOX_WITH_STATISTICS
#ifdef VBOX_WITH_DEBUGGER
#ifdef VBOX_WITH_REM
return VINF_EM_TERMINATE;
NULL);
unsigned cReqs = 0;
if (!pReqHead)
if (!pReqHead)
if (!pReqHead)
if (!pReqHead)
#ifdef LOG_ENABLED
#ifdef VBOX_STRICT
return rc;
#ifdef VBOX_WITH_REM
#ifdef LOG_ENABLED
: VINF_EM_SUSPEND; /** @todo VINF_EM_SUSPEND has lower priority than VINF_EM_RESET, so fix races. Perhaps add a new code for this combined case. */
int rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_DESCENDING | VMMEMTRENDEZVOUS_FLAGS_STOP_ON_ERROR,
return rc;
return cRefs;
if (!pUVM)
if (!cRefs)
return cRefs;
return pUuid;
return enmVMState >= VMSTATE_CREATING && enmVMState <= VMSTATE_TERMINATED ? enmVMState : VMSTATE_TERMINATED;
return VMSTATE_TERMINATED;
switch (enmState)
#ifdef VBOX_STRICT
switch (enmStateOld)
case VMSTATE_CREATING:
AssertMsgReturn(enmStateNew == VMSTATE_CREATED, ("%s -> %s\n", VMR3GetStateName(enmStateOld), VMR3GetStateName(enmStateNew)), false);
case VMSTATE_CREATED:
case VMSTATE_LOADING:
case VMSTATE_POWERING_ON:
case VMSTATE_RESUMING:
case VMSTATE_RUNNING:
case VMSTATE_RUNNING_LS:
case VMSTATE_RUNNING_FT:
case VMSTATE_RESETTING:
AssertMsgReturn(enmStateNew == VMSTATE_RUNNING, ("%s -> %s\n", VMR3GetStateName(enmStateOld), VMR3GetStateName(enmStateNew)), false);
case VMSTATE_RESETTING_LS:
case VMSTATE_SUSPENDING:
AssertMsgReturn(enmStateNew == VMSTATE_SUSPENDED, ("%s -> %s\n", VMR3GetStateName(enmStateOld), VMR3GetStateName(enmStateNew)), false);
case VMSTATE_SUSPENDING_LS:
case VMSTATE_SUSPENDED:
case VMSTATE_SUSPENDED_LS:
case VMSTATE_SUSPENDED_EXT_LS:
case VMSTATE_SAVING:
AssertMsgReturn(enmStateNew == VMSTATE_SUSPENDED, ("%s -> %s\n", VMR3GetStateName(enmStateOld), VMR3GetStateName(enmStateNew)), false);
case VMSTATE_DEBUGGING:
case VMSTATE_DEBUGGING_LS:
case VMSTATE_POWERING_OFF:
AssertMsgReturn(enmStateNew == VMSTATE_OFF, ("%s -> %s\n", VMR3GetStateName(enmStateOld), VMR3GetStateName(enmStateNew)), false);
case VMSTATE_POWERING_OFF_LS:
case VMSTATE_OFF:
AssertMsgReturn(enmStateNew == VMSTATE_DESTROYING, ("%s -> %s\n", VMR3GetStateName(enmStateOld), VMR3GetStateName(enmStateNew)), false);
case VMSTATE_OFF_LS:
AssertMsgReturn(enmStateNew == VMSTATE_OFF, ("%s -> %s\n", VMR3GetStateName(enmStateOld), VMR3GetStateName(enmStateNew)), false);
case VMSTATE_FATAL_ERROR:
AssertMsgReturn(enmStateNew == VMSTATE_POWERING_OFF, ("%s -> %s\n", VMR3GetStateName(enmStateOld), VMR3GetStateName(enmStateNew)), false);
case VMSTATE_FATAL_ERROR_LS:
case VMSTATE_GURU_MEDITATION:
case VMSTATE_LOAD_FAILURE:
AssertMsgReturn(enmStateNew == VMSTATE_POWERING_OFF, ("%s -> %s\n", VMR3GetStateName(enmStateOld), VMR3GetStateName(enmStateNew)), false);
case VMSTATE_DESTROYING:
AssertMsgReturn(enmStateNew == VMSTATE_TERMINATED, ("%s -> %s\n", VMR3GetStateName(enmStateOld), VMR3GetStateName(enmStateNew)), false);
case VMSTATE_TERMINATED:
AssertMsgFailedReturn(("%s -> %s\n", VMR3GetStateName(enmStateOld), VMR3GetStateName(enmStateNew)), false);
LogRel(("Changing the VM state from '%s' to '%s'.\n", VMR3GetStateName(enmStateOld), VMR3GetStateName(enmStateNew)));
#ifdef VBOX_STRICT
for (unsigned i = 0; i < cTransitions; i++)
for (unsigned i = 0; i < cTransitions; i++)
pszWho, VMR3GetStateName(enmStateOld), VMR3GetStateName(enmStateNew), VMR3GetStateName(enmStateCur)));
pszWho, VMR3GetStateName(enmStateOld), VMR3GetStateName(enmStateNew), VMR3GetStateName(enmStateCur)));
for (unsigned i = 0; i < cTransitions; i++)
AssertMsgFailed(("%s - state=%s, see release log for full details. Check the cTransitions passed us.\n",
return rc;
* immediately by the VMM and not by VMEmt.cpp when it's all over.
if (!pNew)
return VERR_NO_MEMORY;
return VINF_SUCCESS;
while ( pCur
if (!pCur)
return VERR_FILE_NOT_FOUND;
if (pPrev)
return VINF_SUCCESS;
if (!pNew)
return VERR_NO_MEMORY;
return VINF_SUCCESS;
while ( pCur
if (!pCur)
return VERR_FILE_NOT_FOUND;
if (pPrev)
return VINF_SUCCESS;
static void vmR3SetErrorWorkerDoCall(PVM pVM, PVMATERROR pCur, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...)
AssertReleaseMsgFailed(("And we have a winner! You get to implement Ring-0 and GC VMSetErrorV! Congrats!\n"));
const char *pszMessage;
if (pErr)
return rc;
DECLCALLBACK(void) vmR3SetErrorUV(PUVM pUVM, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list *pArgs)
#ifdef LOG_ENABLED
bool fCalledSomeone = false;
fCalledSomeone = true;
return rcRet;
VMMR3DECL(int) VMR3AtRuntimeErrorRegister(PUVM pUVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser)
LogFlow(("VMR3AtRuntimeErrorRegister: pfnAtRuntimeError=%p pvUser=%p\n", pfnAtRuntimeError, pvUser));
if (!pNew)
return VERR_NO_MEMORY;
return VINF_SUCCESS;
VMMR3DECL(int) VMR3AtRuntimeErrorDeregister(PUVM pUVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser)
LogFlow(("VMR3AtRuntimeErrorDeregister: pfnAtRuntimeError=%p pvUser=%p\n", pfnAtRuntimeError, pvUser));
while ( pCur
if (!pCur)
return VERR_FILE_NOT_FOUND;
if (pPrev)
return VINF_SUCCESS;
static DECLCALLBACK(VBOXSTRICTRC) vmR3SetRuntimeErrorChangeState(PVM pVM, PVMCPU pVCpu, void *pvUser)
return rc;
return VINF_EM_SUSPEND;
static int vmR3SetRuntimeErrorCommon(PVM pVM, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, va_list *pVa)
int rc;
rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_DESCENDING | VMMEMTRENDEZVOUS_FLAGS_STOP_ON_ERROR,
return rc;
static int vmR3SetRuntimeErrorCommonF(PVM pVM, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...)
return rc;
AssertReleaseMsgFailed(("And we have a winner! You get to implement Ring-0 and GC VMSetRuntimeErrorV! Congrats!\n"));
if (pErr)
DECLCALLBACK(int) vmR3SetRuntimeError(PVM pVM, uint32_t fFlags, const char *pszErrorId, char *pszMessage)
return rc;
DECLCALLBACK(int) vmR3SetRuntimeErrorV(PVM pVM, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, va_list *pVa)
return pUVCpu
: NIL_VMCPUID;
if (!pUVCpu)
return NIL_RTNATIVETHREAD;
if (!pUVCpu)
return NIL_RTNATIVETHREAD;
if (!pUVCpu)
return NIL_RTTHREAD;
VMMR3DECL(int) VMR3GetCpuCoreAndPackageIdFromCpuId(PUVM pUVM, VMCPUID idCpu, uint32_t *pidCpuCore, uint32_t *pidCpuPackage)
return VERR_INVALID_CPU_ID;
#ifdef VBOX_WITH_MULTI_CORE
*pidCpuPackage = 0;
*pidCpuCore = 0;
return VINF_SUCCESS;
return VINF_EM_WAIT_SIPI;
return VINF_SUCCESS;
return VINF_SUCCESS;