VM.cpp revision 65bee08da2ae66d098423e06e27ad06f69e4aa63
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync * VM - Virtual Machine
e64031e20c39650a7bc902a3e1aba613b9415deevboxsync * Copyright (C) 2006-2007 Sun Microsystems, Inc.
05afe08870681beb0792f384475077c988916762vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
05afe08870681beb0792f384475077c988916762vboxsync * available from http://www.virtualbox.org. This file is free software;
05afe08870681beb0792f384475077c988916762vboxsync * you can redistribute it and/or modify it under the terms of the GNU
05afe08870681beb0792f384475077c988916762vboxsync * General Public License (GPL) as published by the Free Software
05afe08870681beb0792f384475077c988916762vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
05afe08870681beb0792f384475077c988916762vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
05afe08870681beb0792f384475077c988916762vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
05afe08870681beb0792f384475077c988916762vboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
05afe08870681beb0792f384475077c988916762vboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
05afe08870681beb0792f384475077c988916762vboxsync * additional information or have any questions.
05afe08870681beb0792f384475077c988916762vboxsync/** @page pg_vm VM API
05afe08870681beb0792f384475077c988916762vboxsync * This is the encapsulating bit. It provides the APIs that Main and VBoxBFE
05afe08870681beb0792f384475077c988916762vboxsync * use to create a VMM instance for running a guest in. It also provides
05afe08870681beb0792f384475077c988916762vboxsync * facilities for queuing request for execution in EMT (serialization purposes
05afe08870681beb0792f384475077c988916762vboxsync * mostly) and for reporting error back to the VMM user (Main/VBoxBFE).
05afe08870681beb0792f384475077c988916762vboxsync * @section sec_vm_design Design Critique / Things To Do
05afe08870681beb0792f384475077c988916762vboxsync * In hindsight this component is a big design mistake, all this stuff really
05afe08870681beb0792f384475077c988916762vboxsync * belongs in the VMM component. It just seemed like a kind of ok idea at a
05afe08870681beb0792f384475077c988916762vboxsync * time when the VMM bit was a bit vague. 'VM' also happend to be the name of
05afe08870681beb0792f384475077c988916762vboxsync * the per-VM instance structure (see vm.h), so it kind of made sense. However
05afe08870681beb0792f384475077c988916762vboxsync * as it turned out, VMM(.cpp) is almost empty all it provides in ring-3 is some
a8f65e585466d1267633cea76b4f97a69b7f1cc0vboxsync * minor functionally and some "routing" services.
a8f65e585466d1267633cea76b4f97a69b7f1cc0vboxsync * Fixing this is just a matter of some more or less straight forward
05afe08870681beb0792f384475077c988916762vboxsync * refactoring, the question is just when someone will get to it.
05afe08870681beb0792f384475077c988916762vboxsync/*******************************************************************************
05afe08870681beb0792f384475077c988916762vboxsync* Header Files *
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync*******************************************************************************/
05afe08870681beb0792f384475077c988916762vboxsync/*******************************************************************************
05afe08870681beb0792f384475077c988916762vboxsync* Structures and Typedefs *
05afe08870681beb0792f384475077c988916762vboxsync*******************************************************************************/
05afe08870681beb0792f384475077c988916762vboxsync * VM destruction callback registration record.
05afe08870681beb0792f384475077c988916762vboxsynctypedef struct VMATDTOR
05afe08870681beb0792f384475077c988916762vboxsync /** Pointer to the next record in the list. */
05afe08870681beb0792f384475077c988916762vboxsync /** Pointer to the callback function. */
05afe08870681beb0792f384475077c988916762vboxsync /** The user argument. */
05afe08870681beb0792f384475077c988916762vboxsync/** Pointer to a VM destruction callback registration record. */
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync/*******************************************************************************
05afe08870681beb0792f384475077c988916762vboxsync* Global Variables *
05afe08870681beb0792f384475077c988916762vboxsync*******************************************************************************/
05afe08870681beb0792f384475077c988916762vboxsync/** Pointer to the list of VMs. */
05afe08870681beb0792f384475077c988916762vboxsync/** Pointer to the list of at VM destruction callbacks. */
05afe08870681beb0792f384475077c988916762vboxsync/** Lock the g_pVMAtDtorHead list. */
05afe08870681beb0792f384475077c988916762vboxsync#define VM_ATDTOR_LOCK() do { } while (0)
05afe08870681beb0792f384475077c988916762vboxsync/** Unlock the g_pVMAtDtorHead list. */
05afe08870681beb0792f384475077c988916762vboxsync#define VM_ATDTOR_UNLOCK() do { } while (0)
05afe08870681beb0792f384475077c988916762vboxsync/*******************************************************************************
05afe08870681beb0792f384475077c988916762vboxsync* Internal Functions *
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync*******************************************************************************/
09776500e6fe37b0613ab81ad127c6c14639386bvboxsyncstatic int vmR3CreateUVM(uint32_t cCpus, PUVM *ppUVM);
09776500e6fe37b0613ab81ad127c6c14639386bvboxsyncstatic int vmR3CreateU(PUVM pUVM, uint32_t cCpus, PFNCFGMCONSTRUCTOR pfnCFGMConstructor, void *pvUserCFGM);
09776500e6fe37b0613ab81ad127c6c14639386bvboxsyncstatic int vmR3InitDoCompleted(PVM pVM, VMINITCOMPLETED enmWhat);
09776500e6fe37b0613ab81ad127c6c14639386bvboxsyncstatic DECLCALLBACK(size_t) vmR3LogPrefixCallback(PRTLOGGER pLogger, char *pchBuf, size_t cchBuf, void *pvUser);
09776500e6fe37b0613ab81ad127c6c14639386bvboxsyncstatic DECLCALLBACK(int) vmR3Suspend(PVM pVM, bool fFatal);
09776500e6fe37b0613ab81ad127c6c14639386bvboxsyncstatic DECLCALLBACK(int) vmR3Save(PVM pVM, const char *pszFilename, SSMAFTER enmAfter, PFNVMPROGRESS pfnProgress, void *pvUser, PSSMHANDLE *ppSSM);
09776500e6fe37b0613ab81ad127c6c14639386bvboxsyncstatic DECLCALLBACK(int) vmR3Load(PVM pVM, const char *pszFilename, PFNVMPROGRESS pfnProgress, void *pvUser);
09776500e6fe37b0613ab81ad127c6c14639386bvboxsyncstatic void vmR3DestroyUVM(PUVM pUVM, uint32_t cMilliesEMTWait);
09776500e6fe37b0613ab81ad127c6c14639386bvboxsyncstatic DECLCALLBACK(int) vmR3AtStateRegisterU(PUVM pUVM, PFNVMATSTATE pfnAtState, void *pvUser);
09776500e6fe37b0613ab81ad127c6c14639386bvboxsyncstatic DECLCALLBACK(int) vmR3AtStateDeregisterU(PUVM pUVM, PFNVMATSTATE pfnAtState, void *pvUser);
09776500e6fe37b0613ab81ad127c6c14639386bvboxsyncstatic DECLCALLBACK(int) vmR3AtErrorRegisterU(PUVM pUVM, PFNVMATERROR pfnAtError, void *pvUser);
09776500e6fe37b0613ab81ad127c6c14639386bvboxsyncstatic DECLCALLBACK(int) vmR3AtErrorDeregisterU(PUVM pUVM, PFNVMATERROR pfnAtError, void *pvUser);
09776500e6fe37b0613ab81ad127c6c14639386bvboxsyncstatic int vmR3SetErrorU(PUVM pUVM, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...);
09776500e6fe37b0613ab81ad127c6c14639386bvboxsyncstatic DECLCALLBACK(int) vmR3AtRuntimeErrorRegisterU(PUVM pUVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser);
09776500e6fe37b0613ab81ad127c6c14639386bvboxsyncstatic DECLCALLBACK(int) vmR3AtRuntimeErrorDeregisterU(PUVM pUVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser);
05afe08870681beb0792f384475077c988916762vboxsync * Do global VMM init.
05afe08870681beb0792f384475077c988916762vboxsync * @returns VBox status code.
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync * Only once.
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync static bool volatile s_fDone = false;
05afe08870681beb0792f384475077c988916762vboxsync * We're done.
05afe08870681beb0792f384475077c988916762vboxsync * Creates a virtual machine by calling the supplied configuration constructor.
05afe08870681beb0792f384475077c988916762vboxsync * On successful returned the VM is powered, i.e. VMR3PowerOn() should be
05afe08870681beb0792f384475077c988916762vboxsync * called to start the execution.
05afe08870681beb0792f384475077c988916762vboxsync * @returns 0 on success.
05afe08870681beb0792f384475077c988916762vboxsync * @returns VBox error code on failure.
05afe08870681beb0792f384475077c988916762vboxsync * @param cCpus Number of virtual CPUs for the new VM.
05afe08870681beb0792f384475077c988916762vboxsync * @param pfnVMAtError Pointer to callback function for setting VM
05afe08870681beb0792f384475077c988916762vboxsync * errors. This was added as an implicit call to
05afe08870681beb0792f384475077c988916762vboxsync * VMR3AtErrorRegister() since there is no way the
05afe08870681beb0792f384475077c988916762vboxsync * caller can get to the VM handle early enough to
05afe08870681beb0792f384475077c988916762vboxsync * do this on its own.
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync * This is called in the context of an EMT.
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync * @param pvUserVM The user argument passed to pfnVMAtError.
05afe08870681beb0792f384475077c988916762vboxsync * @param pfnCFGMConstructor Pointer to callback function for constructing the VM configuration tree.
05afe08870681beb0792f384475077c988916762vboxsync * This is called in the context of an EMT0.
05afe08870681beb0792f384475077c988916762vboxsync * @param pvUserCFGM The user argument passed to pfnCFGMConstructor.
05afe08870681beb0792f384475077c988916762vboxsync * @param ppVM Where to store the 'handle' of the created VM.
09776500e6fe37b0613ab81ad127c6c14639386bvboxsyncVMMR3DECL(int) VMR3Create(uint32_t cCpus, PFNVMATERROR pfnVMAtError, void *pvUserVM, PFNCFGMCONSTRUCTOR pfnCFGMConstructor, void *pvUserCFGM, PVM *ppVM)
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync LogFlow(("VMR3Create: cCpus=%RU32 pfnVMAtError=%p pvUserVM=%p pfnCFGMConstructor=%p pvUserCFGM=%p ppVM=%p\n",
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync cCpus, pfnVMAtError, pvUserVM, pfnCFGMConstructor, pvUserCFGM, ppVM));
05afe08870681beb0792f384475077c988916762vboxsync * Because of the current hackiness of the applications
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync * we'll have to initialize global stuff from here.
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync * Later the applications will take care of this in a proper way.
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync static bool fGlobalInitDone = false;
05afe08870681beb0792f384475077c988916762vboxsync * Validate input.
05afe08870681beb0792f384475077c988916762vboxsync AssertLogRelMsgReturn(cCpus > 0 && cCpus <= VMM_MAX_CPU_COUNT, ("%RU32\n", cCpus), VERR_TOO_MANY_CPUS);
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync * Create the UVM so we can register the at-error callback
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync * and consoliate a bit of cleanup code.
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync rc = VMR3AtErrorRegisterU(pUVM, pfnVMAtError, pvUserVM);
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync * Initialize the support library creating the session for this VM.
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync * Call vmR3CreateU in the EMT thread and wait for it to finish.
05afe08870681beb0792f384475077c988916762vboxsync * Note! VMCPUID_ANY is used here because VMR3ReqQueueU would have trouble
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync * submitting a request to a specific VCPU without a pVM. So, to make
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync * sure init is running on EMT(0), vmR3EmulationThreadWithId makes sure
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync * that only EMT(0) is servicing VMCPUID_ANY requests when pVM is NULL.
05afe08870681beb0792f384475077c988916762vboxsync rc = VMR3ReqCallU(pUVM, VMCPUID_ANY, &pReq, RT_INDEFINITE_WAIT, 0, (PFNRT)vmR3CreateU, 4,
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync LogFlow(("VMR3Create: returns VINF_SUCCESS *ppVM=%p\n", *ppVM));
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync AssertMsgFailed(("VMR3ReqCall failed rc=%Rrc\n", rc));
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync * An error occurred during VM creation. Set the error message directly
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync * using the initial callback, as the callback list doesn't exist yet.
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync pszError = N_("VirtualBox can't operate in VMX root mode. "
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync "Please disable the KVM kernel extension, recompile your kernel and reboot");
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync pszError = N_("VirtualBox can't operate in VMX root mode. Please close all other virtualization programs.");
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync pszError = N_("VMMR0 driver version mismatch. Please terminate all VMs, make sure that "
05afe08870681beb0792f384475077c988916762vboxsync "VBoxNetDHCP is not running and try again. If you still get this error, "
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync "re-install VirtualBox");
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync pszError = N_("One of the kernel modules was not successfully loaded. Make sure "
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync "that no kernel modules from an older version of VirtualBox exist. "
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync "Then try to recompile and reload the kernel modules by executing "
05afe08870681beb0792f384475077c988916762vboxsync "'/etc/init.d/vboxdrv setup' as root");
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync pszError = N_("VT-x/AMD-V is either not available on your host or disabled. "
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync "VirtualBox requires this hardware extension to emulate more than one "
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync "guest CPU");
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync pszError = N_("Because the host kernel is too old, VirtualBox cannot enable the VT-x "
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync "extension. Either upgrade your kernel to Linux 2.6.13 or later or disable "
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync "the VT-x extension in the VM settings. Note that without VT-x you have "
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync "to reduce the number of guest CPUs to one");
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync pszError = N_("Because the host kernel is too old, VirtualBox cannot enable the VT-x "
05afe08870681beb0792f384475077c988916762vboxsync "extension. Either upgrade your kernel or disable the VT-x extension in the "
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync "VM settings. Note that without VT-x you have to reduce the number of guest "
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync "CPUs to one");
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync * An error occurred at support library initialization time (before the
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync * VM could be created). Set the error message directly using the
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync * initial callback, as the callback list doesn't exist yet.
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync const char *pszError;
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync pszError = N_("VirtualBox kernel driver not loaded. The vboxdrv kernel module "
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync "was either not loaded or /dev/vboxdrv is not set up properly. "
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync "Re-setup the kernel module by executing "
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync "'/etc/init.d/vboxdrv setup' as root");
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync pszError = N_("VirtualBox kernel driver not loaded");
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync pszError = N_("VirtualBox kernel driver cannot be opened");
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync /* This should only happen if the executable wasn't hardened - bad code/build. */
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync pszError = N_("VirtualBox kernel driver not accessible, permission problem. "
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync "Re-install VirtualBox. If you are building it yourself, you "
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync "should make sure it installed correctly and that the setuid "
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync "bit is set on the executables calling VMR3Create.");
05afe08870681beb0792f384475077c988916762vboxsync /* This should only happen when mixing builds or with the usual /dev/vboxdrv access issues. */
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync pszError = N_("VirtualBox KEXT is not accessible, permission problem. "
05afe08870681beb0792f384475077c988916762vboxsync "If you have built VirtualBox yourself, make sure that you do not "
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync "have the vboxdrv KEXT from a different build or installation loaded.");
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync pszError = N_("VirtualBox kernel driver is not accessible, permission problem. "
05afe08870681beb0792f384475077c988916762vboxsync "If you have built VirtualBox yourself, make sure that you do "
05afe08870681beb0792f384475077c988916762vboxsync "not have the vboxdrv kernel module from a different build or "
05afe08870681beb0792f384475077c988916762vboxsync "installation loaded. Also, make sure the vboxdrv udev rule gives "
05afe08870681beb0792f384475077c988916762vboxsync "you the permission you need to access the device.");
05afe08870681beb0792f384475077c988916762vboxsync pszError = N_("VirtualBox kernel driver is not accessible, permission problem.");
05afe08870681beb0792f384475077c988916762vboxsync# else /* solaris, freebsd, ++. */
05afe08870681beb0792f384475077c988916762vboxsync pszError = N_("VirtualBox kernel module is not accessible, permission problem. "
05afe08870681beb0792f384475077c988916762vboxsync "If you have built VirtualBox yourself, make sure that you do "
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync "not have the vboxdrv kernel module from a different install loaded.");
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync case VERR_INVALID_HANDLE: /** @todo track down and fix this error. */
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync pszError = N_("VirtualBox kernel driver not installed. The vboxdrv kernel module "
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync "was either not loaded or /dev/vboxdrv was not created for some "
05afe08870681beb0792f384475077c988916762vboxsync "reason. Re-setup the kernel module by executing "
05afe08870681beb0792f384475077c988916762vboxsync "'/etc/init.d/vboxdrv setup' as root");
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync pszError = N_("VirtualBox kernel driver not installed");
09776500e6fe37b0613ab81ad127c6c14639386bvboxsync pszError = N_("VirtualBox support library out of memory");
e0e7da0420be1398d23ffa9953686d3a43619abdvboxsync pszError = N_("The VirtualBox support driver which is running is from a different "
e0e7da0420be1398d23ffa9953686d3a43619abdvboxsync "version of VirtualBox. You can correct this by stopping all "
e0e7da0420be1398d23ffa9953686d3a43619abdvboxsync "running instances of VirtualBox and reinstalling the software.");
e0e7da0420be1398d23ffa9953686d3a43619abdvboxsync pszError = N_("Unknown error initializing kernel driver");
e0e7da0420be1398d23ffa9953686d3a43619abdvboxsync AssertMsgFailed(("Add error message for rc=%d (%Rrc)\n", rc, rc));
return rc;
uint32_t 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",
#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_TICKS_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_TICKS_PER_CALL, "Profiling halted state blocking.", "/PROF/VM/CPU%d/Halt/Block", idCpu);
rc = STAMR3RegisterF(pVM, &pUVM->aCpus[idCpu].vm.s.StatHaltTimers, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_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.");
#ifdef VBOX_WITH_VMI
return VINF_SUCCESS;
#ifdef VBOX_WITH_VMI
return rc;
int rc2;
return VINF_SUCCESS;
return rc;
return rc;
return rc;
return VINF_SUCCESS;
static DECLCALLBACK(size_t) vmR3LogPrefixCallback(PRTLOGGER pLogger, char *pchBuf, size_t cchBuf, void *pvUser)
if (pUVCpu)
if (!pVM)
return VERR_INVALID_PARAMETER;
return rc;
return VINF_SUCCESS;
return VERR_VM_INVALID_VM_STATE;
return VINF_SUCCESS;
return rc;
return rc;
return VERR_VM_INVALID_VM_STATE;
return VINF_EM_SUSPEND;
return VINF_EM_SUSPEND;
if (!pVM)
return VERR_INVALID_PARAMETER;
return rc;
return VINF_EM_RESUME;
return VERR_VM_INVALID_VM_STATE;
return VINF_EM_RESUME;
VMMR3DECL(int) VMR3Save(PVM pVM, const char *pszFilename, bool fContinueAfterwards, PFNVMPROGRESS pfnProgress, void *pvUser)
LogFlow(("VMR3Save: pVM=%p pszFilename=%p:{%s} fContinueAfterwards=%RTbool pfnProgress=%p pvUser=%p\n",
&& pSSM)
return rc;
static DECLCALLBACK(int) vmR3Save(PVM pVM, const char *pszFilename, SSMAFTER enmAfter, PFNVMPROGRESS pfnProgress, void *pvUser, PSSMHANDLE *ppSSM)
LogFlow(("vmR3Save: pVM=%p pszFilename=%p:{%s} enmAfter=%d pfnProgress=%p pvUser=%p ppSSM=%p\n", pVM, pszFilename, pszFilename, enmAfter, pfnProgress, pvUser, ppSSM));
if (pVM->vm.s.fPreventSaveState) /** @todo Incorporate VMINT::fPreventSaveState into the VMSTATE. There is a defect for this. */
return VERR_VM_SAVE_STATE_NOT_ALLOWED;
int rc;
vmR3SetState(pVM, VMSTATE_SAVING); /** @todo Should probably use a different state for live snapshots and/or live migration. Will fix the state machine later. */
return rc;
LogFlow(("VMR3Load: pVM=%p pszFilename=%p:{%s} pfnProgress=%p pvUser=%p\n", pVM, pszFilename, pszFilename, pfnProgress, pvUser));
if (!pVM)
return VERR_INVALID_PARAMETER;
if (!pszFilename)
return VERR_INVALID_PARAMETER;
int rc = VMR3ReqCall(pVM, 0 /* VCPU 0 */, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3Load, 4, pVM, pszFilename, pfnProgress, pvUser);
return rc;
static DECLCALLBACK(int) vmR3Load(PVM pVM, const char *pszFilename, PFNVMPROGRESS pfnProgress, void *pvUser)
LogFlow(("vmR3Load: pVM=%p pszFilename=%p:{%s} pfnProgress=%p pvUser=%p\n", pVM, pszFilename, pszFilename, pfnProgress, pvUser));
return VMSetError(pVM, VERR_VM_INVALID_VM_STATE, RT_SRC_POS, N_("Invalid VM state (%s) for restoring state from '%s'"),
/* Not paranoia anymore; the saved guest might use different hypervisor selectors. We must call VMR3Relocate. */
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. Please discard the saved state before starting the virtual machine"), pszFilename);
return rc;
if (!pVM)
return VERR_INVALID_PARAMETER;
int rc = VMR3ReqCall(pVM, VMCPUID_ALL_REVERSE, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3PowerOff, 1, pVM);
return rc;
return VERR_VM_INVALID_VM_STATE;
return VINF_EM_OFF;
return VINF_EM_OFF;
if (!pVM)
return VERR_INVALID_PARAMETER;
* Request EMT to do the larger part of the destruction. (in reverse order as VCPU 0 does the real cleanup)
int rc = VMR3ReqCallU(pUVM, VMCPUID_ALL_REVERSE, &pReq, RT_INDEFINITE_WAIT, 0, (PFNRT)vmR3Destroy, 1, pVM);
return VINF_SUCCESS;
return VINF_EM_TERMINATE;
#ifdef VBOX_WITH_STATISTICS
#ifdef VBOX_WITH_DEBUGGER
return VINF_EM_TERMINATE;
NULL);
unsigned cReqs = 0;
AssertMsg(!pReqHead, ("This isn't supposed to happen! VMR3Destroy caller has to serialize this.\n"));
if (!pReqHead)
AssertMsg(!pReqHead, ("This isn't supposed to happen! VMR3Destroy caller has to serialize this.\n"));
if (!pReqHead)
#ifdef LOG_ENABLED
if (pVMPrev)
while (pCur)
return VERR_INVALID_PARAMETER;
if (!pVMAtDtor)
return VERR_NO_MEMORY;
return VINF_SUCCESS;
while (pCur)
if (pPrev)
return VINF_SUCCESS;
return VERR_INVALID_PARAMETER;
if (!pVM)
return VERR_INVALID_PARAMETER;
return VERR_VM_INVALID_VM_STATE;
return rc;
#ifdef VBOX_STRICT
return VINF_EM_RESET;
* (If VMR3Reset was not called from EMT we might have change state... let's ignore that fact for now.)
#ifdef LOG_ENABLED
return VINF_EM_RESET;
case VMATRESETTYPE_DEV:
case VMATRESETTYPE_INTERNAL:
case VMATRESETTYPE_EXTERNAL:
return VERR_INTERNAL_ERROR;
return rc;
return VINF_SUCCESS;
if (pNew)
return VINF_SUCCESS;
return VERR_NO_MEMORY;
VMMR3DECL(int) VMR3AtResetRegister(PVM pVM, PPDMDEVINS pDevInst, PFNVMATRESET pfnCallback, void *pvUser, const char *pszDesc)
if (!pDevInst)
return VERR_INVALID_PARAMETER;
return rc;
VMMR3DECL(int) VMR3AtResetRegisterInternal(PVM pVM, PFNVMATRESETINT pfnCallback, void *pvUser, const char *pszDesc)
if (!pfnCallback)
return VERR_INVALID_PARAMETER;
return rc;
VMMR3DECL(int) VMR3AtResetRegisterExternal(PVM pVM, PFNVMATRESETEXT pfnCallback, void *pvUser, const char *pszDesc)
if (!pfnCallback)
return VERR_INVALID_PARAMETER;
return rc;
if (pPrev)
if (!pNext)
if (!pNext)
return pNext;
while (pCur)
&& ( !pfnCallback
return rc;
while (pCur)
return rc;
while (pCur)
return rc;
switch (enmState)
switch (enmStateOld)
case VMSTATE_OFF:
LogRel(("Changing the VM state from '%s' to '%s'.\n", VMR3GetStateName(enmStateOld), VMR3GetStateName(enmStateNew)));
if (!pfnAtState)
return VERR_INVALID_PARAMETER;
int rc = VMR3ReqCall(pVM, VMCPUID_ANY, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3AtStateRegisterU, 3, pVM->pUVM, pfnAtState, pvUser);
return rc;
return rc;
if (!pNew)
return VERR_NO_MEMORY;
return VINF_SUCCESS;
if (!pfnAtState)
return VERR_INVALID_PARAMETER;
int rc = VMR3ReqCall(pVM, VMCPUID_ANY, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3AtStateDeregisterU, 3, pVM->pUVM, pfnAtState, pvUser);
return rc;
return rc;
while ( pCur
if (!pCur)
return VERR_FILE_NOT_FOUND;
if (pPrev)
return VINF_SUCCESS;
int rc = VMR3ReqCallU(pUVM, VMCPUID_ANY, &pReq, RT_INDEFINITE_WAIT, 0, (PFNRT)vmR3AtErrorRegisterU, 3, pUVM, pfnAtError, pvUser);
return rc;
return rc;
if (!pNew)
return VERR_NO_MEMORY;
return VINF_SUCCESS;
if (!pfnAtError)
return VERR_INVALID_PARAMETER;
int rc = VMR3ReqCall(pVM, VMCPUID_ANY, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3AtErrorDeregisterU, 3, pVM->pUVM, pfnAtError, pvUser);
return rc;
return rc;
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! Contrats!\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
VMMR3DECL(int) VMR3AtRuntimeErrorRegister(PVM pVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser)
LogFlow(("VMR3AtRuntimeErrorRegister: pfnAtRuntimeError=%p pvUser=%p\n", pfnAtRuntimeError, pvUser));
if (!pfnAtRuntimeError)
return VERR_INVALID_PARAMETER;
int rc = VMR3ReqCall(pVM, VMCPUID_ANY, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3AtRuntimeErrorRegisterU, 3, pVM->pUVM, pfnAtRuntimeError, pvUser);
return rc;
return rc;
static DECLCALLBACK(int) vmR3AtRuntimeErrorRegisterU(PUVM pUVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser)
if (!pNew)
return VERR_NO_MEMORY;
return VINF_SUCCESS;
VMMR3DECL(int) VMR3AtRuntimeErrorDeregister(PVM pVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser)
LogFlow(("VMR3AtRuntimeErrorDeregister: pfnAtRuntimeError=%p pvUser=%p\n", pfnAtRuntimeError, pvUser));
if (!pfnAtRuntimeError)
return VERR_INVALID_PARAMETER;
int rc = VMR3ReqCall(pVM, VMCPUID_ANY, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3AtRuntimeErrorDeregisterU, 3, pVM->pUVM, pfnAtRuntimeError, pvUser);
return rc;
return rc;
static DECLCALLBACK(int) vmR3AtRuntimeErrorDeregisterU(PUVM pUVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser)
LogFlow(("vmR3AtRuntimeErrorDeregisterU: pfnAtRuntimeError=%p pvUser=%p\n", pfnAtRuntimeError, pvUser));
while ( pCur
if (!pCur)
return VERR_FILE_NOT_FOUND;
if (pPrev)
return VINF_SUCCESS;
static int vmR3SetRuntimeErrorCommon(PVM pVM, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, va_list *pVa)
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;
if (!pUVCpu)
return NIL_RTTHREAD;