VirtualBox

source: vbox/trunk/src/VBox/VMM/VM.cpp@ 18743

Last change on this file since 18743 was 18645, checked in by vboxsync, 16 years ago

VMSetRuntimeError[V] refactoring: fFatal -> fFlags, may return informational status codes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 100.8 KB
Line 
1/* $Id: VM.cpp 18645 2009-04-02 15:38:31Z vboxsync $ */
2/** @file
3 * VM - Virtual Machine
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22/** @page pg_vm VM API
23 *
24 * This is the encapsulating bit. It provides the APIs that Main and VBoxBFE
25 * use to create a VMM instance for running a guest in. It also provides
26 * facilities for queuing request for execution in EMT (serialization purposes
27 * mostly) and for reporting error back to the VMM user (Main/VBoxBFE).
28 *
29 *
30 * @section sec_vm_design Design Critique / Things To Do
31 *
32 * In hindsight this component is a big design mistake, all this stuff really
33 * belongs in the VMM component. It just seemed like a kind of ok idea at a
34 * time when the VMM bit was a bit vague. 'VM' also happend to be the name of
35 * the per-VM instance structure (see vm.h), so it kind of made sense. However
36 * as it turned out, VMM(.cpp) is almost empty all it provides in ring-3 is some
37 * minor functionally and some "routing" services.
38 *
39 * Fixing this is just a matter of some more or less straight forward
40 * refactoring, the question is just when someone will get to it.
41 *
42 */
43
44/*******************************************************************************
45* Header Files *
46*******************************************************************************/
47#define LOG_GROUP LOG_GROUP_VM
48#include <VBox/cfgm.h>
49#include <VBox/vmm.h>
50#include <VBox/gvmm.h>
51#include <VBox/mm.h>
52#include <VBox/cpum.h>
53#include <VBox/selm.h>
54#include <VBox/trpm.h>
55#include <VBox/dbgf.h>
56#include <VBox/pgm.h>
57#include <VBox/pdmapi.h>
58#include <VBox/pdmcritsect.h>
59#include <VBox/em.h>
60#include <VBox/rem.h>
61#include <VBox/tm.h>
62#include <VBox/stam.h>
63#include <VBox/patm.h>
64#ifdef VBOX_WITH_VMI
65# include <VBox/parav.h>
66#endif
67#include <VBox/csam.h>
68#include <VBox/iom.h>
69#include <VBox/ssm.h>
70#include <VBox/hwaccm.h>
71#include "VMInternal.h"
72#include <VBox/vm.h>
73#include <VBox/uvm.h>
74
75#include <VBox/sup.h>
76#include <VBox/dbg.h>
77#include <VBox/err.h>
78#include <VBox/param.h>
79#include <VBox/log.h>
80#include <iprt/assert.h>
81#include <iprt/alloc.h>
82#include <iprt/asm.h>
83#include <iprt/env.h>
84#include <iprt/string.h>
85#include <iprt/time.h>
86#include <iprt/semaphore.h>
87#include <iprt/thread.h>
88
89
90/*******************************************************************************
91* Structures and Typedefs *
92*******************************************************************************/
93/**
94 * VM destruction callback registration record.
95 */
96typedef struct VMATDTOR
97{
98 /** Pointer to the next record in the list. */
99 struct VMATDTOR *pNext;
100 /** Pointer to the callback function. */
101 PFNVMATDTOR pfnAtDtor;
102 /** The user argument. */
103 void *pvUser;
104} VMATDTOR;
105/** Pointer to a VM destruction callback registration record. */
106typedef VMATDTOR *PVMATDTOR;
107
108
109/*******************************************************************************
110* Global Variables *
111*******************************************************************************/
112/** Pointer to the list of VMs. */
113static PUVM g_pUVMsHead = NULL;
114
115/** Pointer to the list of at VM destruction callbacks. */
116static PVMATDTOR g_pVMAtDtorHead = NULL;
117/** Lock the g_pVMAtDtorHead list. */
118#define VM_ATDTOR_LOCK() do { } while (0)
119/** Unlock the g_pVMAtDtorHead list. */
120#define VM_ATDTOR_UNLOCK() do { } while (0)
121
122
123/*******************************************************************************
124* Internal Functions *
125*******************************************************************************/
126static int vmR3CreateUVM(uint32_t cCPUs, PUVM *ppUVM);
127static int vmR3CreateU(PUVM pUVM, uint32_t cCPUs, PFNCFGMCONSTRUCTOR pfnCFGMConstructor, void *pvUserCFGM);
128static int vmR3InitRing3(PVM pVM, PUVM pUVM);
129static int vmR3InitVMCpu(PVM pVM);
130static int vmR3InitRing0(PVM pVM);
131static int vmR3InitGC(PVM pVM);
132static int vmR3InitDoCompleted(PVM pVM, VMINITCOMPLETED enmWhat);
133static DECLCALLBACK(int) vmR3PowerOn(PVM pVM);
134static DECLCALLBACK(int) vmR3Suspend(PVM pVM);
135static DECLCALLBACK(int) vmR3Resume(PVM pVM);
136static DECLCALLBACK(int) vmR3Save(PVM pVM, const char *pszFilename, PFNVMPROGRESS pfnProgress, void *pvUser);
137static DECLCALLBACK(int) vmR3Load(PVM pVM, const char *pszFilename, PFNVMPROGRESS pfnProgress, void *pvUser);
138static DECLCALLBACK(int) vmR3PowerOff(PVM pVM);
139static void vmR3DestroyUVM(PUVM pUVM);
140static void vmR3AtDtor(PVM pVM);
141static int vmR3AtResetU(PUVM pUVM);
142static DECLCALLBACK(int) vmR3Reset(PVM pVM);
143static DECLCALLBACK(int) vmR3AtStateRegisterU(PUVM pUVM, PFNVMATSTATE pfnAtState, void *pvUser);
144static DECLCALLBACK(int) vmR3AtStateDeregisterU(PUVM pUVM, PFNVMATSTATE pfnAtState, void *pvUser);
145static DECLCALLBACK(int) vmR3AtErrorRegisterU(PUVM pUVM, PFNVMATERROR pfnAtError, void *pvUser);
146static DECLCALLBACK(int) vmR3AtErrorDeregisterU(PUVM pUVM, PFNVMATERROR pfnAtError, void *pvUser);
147static int vmR3SetErrorU(PUVM pUVM, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...);
148static DECLCALLBACK(int) vmR3AtRuntimeErrorRegisterU(PUVM pUVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser);
149static DECLCALLBACK(int) vmR3AtRuntimeErrorDeregisterU(PUVM pUVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser);
150
151
152/**
153 * Do global VMM init.
154 *
155 * @returns VBox status code.
156 */
157VMMR3DECL(int) VMR3GlobalInit(void)
158{
159 /*
160 * Only once.
161 */
162 static bool volatile s_fDone = false;
163 if (s_fDone)
164 return VINF_SUCCESS;
165
166 /*
167 * We're done.
168 */
169 s_fDone = true;
170 return VINF_SUCCESS;
171}
172
173
174
175/**
176 * Creates a virtual machine by calling the supplied configuration constructor.
177 *
178 * On successful returned the VM is powered, i.e. VMR3PowerOn() should be
179 * called to start the execution.
180 *
181 * @returns 0 on success.
182 * @returns VBox error code on failure.
183 * @param cCPUs Number of virtual CPUs for the new VM.
184 * @param pfnVMAtError Pointer to callback function for setting VM errors.
185 * This is called in the EM.
186 * @param pvUserVM The user argument passed to pfnVMAtError.
187 * @param pfnCFGMConstructor Pointer to callback function for constructing the VM configuration tree.
188 * This is called in the EM.
189 * @param pvUserCFGM The user argument passed to pfnCFGMConstructor.
190 * @param ppVM Where to store the 'handle' of the created VM.
191 */
192VMMR3DECL(int) VMR3Create(uint32_t cCPUs, PFNVMATERROR pfnVMAtError, void *pvUserVM, PFNCFGMCONSTRUCTOR pfnCFGMConstructor, void *pvUserCFGM, PVM *ppVM)
193{
194 LogFlow(("VMR3Create: cCPUs=%RU32 pfnVMAtError=%p pvUserVM=%p pfnCFGMConstructor=%p pvUserCFGM=%p ppVM=%p\n", cCPUs, pfnVMAtError, pvUserVM, pfnCFGMConstructor, pvUserCFGM, ppVM));
195
196 /*
197 * Because of the current hackiness of the applications
198 * we'll have to initialize global stuff from here.
199 * Later the applications will take care of this in a proper way.
200 */
201 static bool fGlobalInitDone = false;
202 if (!fGlobalInitDone)
203 {
204 int rc = VMR3GlobalInit();
205 if (RT_FAILURE(rc))
206 return rc;
207 fGlobalInitDone = true;
208 }
209
210 /*
211 * Validate input.
212 */
213#ifdef VBOX_WITH_SMP_GUESTS
214 AssertLogRelMsgReturn(cCPUs > 0 && cCPUs <= VMCPU_MAX_CPU_COUNT, ("%RU32\n", cCPUs), VERR_INVALID_PARAMETER);
215#else
216 AssertLogRelMsgReturn(cCPUs == 1, ("%RU32\n", cCPUs), VERR_INVALID_PARAMETER);
217#endif
218
219 /*
220 * Create the UVM so we can register the at-error callback
221 * and consoliate a bit of cleanup code.
222 */
223 PUVM pUVM;
224 int rc = vmR3CreateUVM(cCPUs, &pUVM);
225 if (RT_FAILURE(rc))
226 return rc;
227 if (pfnVMAtError)
228 rc = VMR3AtErrorRegisterU(pUVM, pfnVMAtError, pvUserVM);
229 if (RT_SUCCESS(rc))
230 {
231 /*
232 * Initialize the support library creating the session for this VM.
233 */
234 rc = SUPR3Init(&pUVM->vm.s.pSession);
235 if (RT_SUCCESS(rc))
236 {
237 /*
238 * Call vmR3CreateU in the EMT thread and wait for it to finish.
239 */
240 PVMREQ pReq;
241 /** @todo SMP: VMREQDEST_ANY -> VMREQDEST_CPU0 */
242 rc = VMR3ReqCallU(pUVM, VMREQDEST_ANY, &pReq, RT_INDEFINITE_WAIT, 0, (PFNRT)vmR3CreateU,
243 4, pUVM, cCPUs, pfnCFGMConstructor, pvUserCFGM);
244 if (RT_SUCCESS(rc))
245 {
246 rc = pReq->iStatus;
247 VMR3ReqFree(pReq);
248 if (RT_SUCCESS(rc))
249 {
250 /*
251 * Success!
252 */
253 *ppVM = pUVM->pVM;
254 LogFlow(("VMR3Create: returns VINF_SUCCESS *ppVM=%p\n", *ppVM));
255 return VINF_SUCCESS;
256 }
257 }
258 else
259 AssertMsgFailed(("VMR3ReqCall failed rc=%Rrc\n", rc));
260
261 /*
262 * An error occurred during VM creation. Set the error message directly
263 * using the initial callback, as the callback list doesn't exist yet.
264 */
265 const char *pszError = NULL;
266 switch (rc)
267 {
268 case VERR_VMX_IN_VMX_ROOT_MODE:
269#ifdef RT_OS_LINUX
270 pszError = N_("VirtualBox can't operate in VMX root mode. "
271 "Please disable the KVM kernel extension, recompile your kernel and reboot");
272#else
273 pszError = N_("VirtualBox can't operate in VMX root mode. Please close all other virtualization programs.");
274#endif
275 break;
276
277 case VERR_VERSION_MISMATCH:
278 pszError = N_("VMMR0 driver version mismatch. Please terminate all VMs, make sure that "
279 "VBoxNetDHCP is not running and try again. If you still get this error, "
280 "re-install VirtualBox");
281 break;
282
283 default:
284 pszError = N_("Unknown error creating VM");
285 break;
286 }
287 vmR3SetErrorU(pUVM, rc, RT_SRC_POS, pszError, rc);
288 }
289 else
290 {
291 /*
292 * An error occurred at support library initialization time (before the
293 * VM could be created). Set the error message directly using the
294 * initial callback, as the callback list doesn't exist yet.
295 */
296 const char *pszError;
297 switch (rc)
298 {
299 case VERR_VM_DRIVER_LOAD_ERROR:
300#ifdef RT_OS_LINUX
301 pszError = N_("VirtualBox kernel driver not loaded. The vboxdrv kernel module "
302 "was either not loaded or /dev/vboxdrv is not set up properly. "
303 "Re-setup the kernel module by executing "
304 "'/etc/init.d/vboxdrv setup' as root");
305#else
306 pszError = N_("VirtualBox kernel driver not loaded");
307#endif
308 break;
309 case VERR_VM_DRIVER_OPEN_ERROR:
310 pszError = N_("VirtualBox kernel driver cannot be opened");
311 break;
312 case VERR_VM_DRIVER_NOT_ACCESSIBLE:
313#ifdef VBOX_WITH_HARDENING
314 /* This should only happen if the executable wasn't hardened - bad code/build. */
315 pszError = N_("VirtualBox kernel driver not accessible, permission problem. "
316 "Re-install VirtualBox. If you are building it yourself, you "
317 "should make sure it installed correctly and that the setuid "
318 "bit is set on the executables calling VMR3Create.");
319#else
320 /* This should only happen when mixing builds or with the usual /dev/vboxdrv access issues. */
321# if defined(RT_OS_DARWIN)
322 pszError = N_("VirtualBox KEXT is not accessible, permission problem. "
323 "If you have built VirtualBox yourself, make sure that you do not "
324 "have the vboxdrv KEXT from a different build or installation loaded.");
325# elif defined(RT_OS_LINUX)
326 pszError = N_("VirtualBox kernel driver is not accessible, permission problem. "
327 "If you have built VirtualBox yourself, make sure that you do "
328 "not have the vboxdrv kernel module from a different build or "
329 "installation loaded. Also, make sure the vboxdrv udev rule gives "
330 "you the permission you need to access the device.");
331# elif defined(RT_OS_WINDOWS)
332 pszError = N_("VirtualBox kernel driver is not accessible, permission problem.");
333# else /* solaris, freebsd, ++. */
334 pszError = N_("VirtualBox kernel module is not accessible, permission problem. "
335 "If you have built VirtualBox yourself, make sure that you do "
336 "not have the vboxdrv kernel module from a different install loaded.");
337# endif
338#endif
339 break;
340 case VERR_INVALID_HANDLE: /** @todo track down and fix this error. */
341 case VERR_VM_DRIVER_NOT_INSTALLED:
342#ifdef RT_OS_LINUX
343 pszError = N_("VirtualBox kernel driver not installed. The vboxdrv kernel module "
344 "was either not loaded or /dev/vboxdrv was not created for some "
345 "reason. Re-setup the kernel module by executing "
346 "'/etc/init.d/vboxdrv setup' as root");
347#else
348 pszError = N_("VirtualBox kernel driver not installed");
349#endif
350 break;
351 case VERR_NO_MEMORY:
352 pszError = N_("VirtualBox support library out of memory");
353 break;
354 case VERR_VERSION_MISMATCH:
355 case VERR_VM_DRIVER_VERSION_MISMATCH:
356 pszError = N_("The VirtualBox support driver which is running is from a different "
357 "version of VirtualBox. You can correct this by stopping all "
358 "running instances of VirtualBox and reinstalling the software.");
359 break;
360 default:
361 pszError = N_("Unknown error initializing kernel driver");
362 AssertMsgFailed(("Add error message for rc=%d (%Rrc)\n", rc, rc));
363 }
364 vmR3SetErrorU(pUVM, rc, RT_SRC_POS, pszError, rc);
365 }
366 }
367
368 /* cleanup */
369 vmR3DestroyUVM(pUVM);
370 LogFlow(("VMR3Create: returns %Rrc\n", rc));
371 return rc;
372}
373
374
375/**
376 * Creates the UVM.
377 *
378 * This will not initialize the support library even if vmR3DestroyUVM
379 * will terminate that.
380 *
381 * @returns VBox status code.
382 * @param cCPUs Number of virtual CPUs
383 * @param ppUVM Where to store the UVM pointer.
384 */
385static int vmR3CreateUVM(uint32_t cCPUs, PUVM *ppUVM)
386{
387 uint32_t i;
388
389 /*
390 * Create and initialize the UVM.
391 */
392 PUVM pUVM = (PUVM)RTMemAllocZ(RT_OFFSETOF(UVM, aCpus[cCPUs]));
393 AssertReturn(pUVM, VERR_NO_MEMORY);
394 pUVM->u32Magic = UVM_MAGIC;
395
396 AssertCompile(sizeof(pUVM->vm.s) <= sizeof(pUVM->vm.padding));
397 AssertRelease(sizeof(pUVM->vm.s) <= sizeof(pUVM->vm.padding));
398
399 pUVM->vm.s.ppAtResetNext = &pUVM->vm.s.pAtReset;
400 pUVM->vm.s.ppAtStateNext = &pUVM->vm.s.pAtState;
401 pUVM->vm.s.ppAtErrorNext = &pUVM->vm.s.pAtError;
402 pUVM->vm.s.ppAtRuntimeErrorNext = &pUVM->vm.s.pAtRuntimeError;
403 pUVM->vm.s.enmHaltMethod = VMHALTMETHOD_BOOTSTRAP;
404
405 /* Initialize the VMCPU array in the UVM. */
406 for (i = 0; i < cCPUs; i++)
407 {
408 pUVM->aCpus[i].pUVM = pUVM;
409 pUVM->aCpus[i].idCpu = i;
410 }
411
412 /* Allocate a TLS entry to store the VMINTUSERPERVMCPU pointer. */
413 int rc = RTTlsAllocEx(&pUVM->vm.s.idxTLS, NULL);
414 AssertRC(rc);
415 if (RT_SUCCESS(rc))
416 {
417 rc = RTSemEventCreate(&pUVM->vm.s.EventSemWait);
418 if (RT_SUCCESS(rc))
419 {
420 /*
421 * Init fundamental (sub-)components - STAM, MMR3Heap and PDMLdr.
422 */
423 rc = STAMR3InitUVM(pUVM);
424 if (RT_SUCCESS(rc))
425 {
426 rc = MMR3InitUVM(pUVM);
427 if (RT_SUCCESS(rc))
428 {
429 rc = PDMR3InitUVM(pUVM);
430 if (RT_SUCCESS(rc))
431 {
432 /*
433 * Start the emulation threads for all VMCPUs.
434 */
435 for (i = 0; i < cCPUs; i++)
436 {
437 rc = RTThreadCreate(&pUVM->aCpus[i].vm.s.ThreadEMT, vmR3EmulationThread, &pUVM->aCpus[i], _1M,
438 RTTHREADTYPE_EMULATION, RTTHREADFLAGS_WAITABLE, "EMT");
439 if (RT_FAILURE(rc))
440 break;
441
442 pUVM->aCpus[i].vm.s.NativeThreadEMT = RTThreadGetNative(pUVM->aCpus[i].vm.s.ThreadEMT);
443 }
444
445 if (RT_SUCCESS(rc))
446 {
447 *ppUVM = pUVM;
448 return VINF_SUCCESS;
449 }
450
451 /* bail out. */
452 while (i-- > 0)
453 {
454 /** @todo rainy day: terminate the EMTs. */
455 }
456 PDMR3TermUVM(pUVM);
457 }
458 MMR3TermUVM(pUVM);
459 }
460 STAMR3TermUVM(pUVM);
461 }
462 RTSemEventDestroy(pUVM->vm.s.EventSemWait);
463 }
464 RTTlsFree(pUVM->vm.s.idxTLS);
465 }
466 RTMemFree(pUVM);
467 return rc;
468}
469
470
471/**
472 * Creates and initializes the VM.
473 *
474 * @thread EMT
475 */
476static int vmR3CreateU(PUVM pUVM, uint32_t cCPUs, PFNCFGMCONSTRUCTOR pfnCFGMConstructor, void *pvUserCFGM)
477{
478 int rc = VINF_SUCCESS;
479
480 /*
481 * Load the VMMR0.r0 module so that we can call GVMMR0CreateVM.
482 */
483 rc = PDMR3LdrLoadVMMR0U(pUVM);
484 if (RT_FAILURE(rc))
485 {
486 /** @todo we need a cleaner solution for this (VERR_VMX_IN_VMX_ROOT_MODE).
487 * bird: what about moving the message down here? Main picks the first message, right? */
488 if (rc == VERR_VMX_IN_VMX_ROOT_MODE)
489 return rc; /* proper error message set later on */
490 return vmR3SetErrorU(pUVM, rc, RT_SRC_POS, N_("Failed to load VMMR0.r0"));
491 }
492
493 /*
494 * Request GVMM to create a new VM for us.
495 */
496 GVMMCREATEVMREQ CreateVMReq;
497 CreateVMReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
498 CreateVMReq.Hdr.cbReq = sizeof(CreateVMReq);
499 CreateVMReq.pSession = pUVM->vm.s.pSession;
500 CreateVMReq.pVMR0 = NIL_RTR0PTR;
501 CreateVMReq.pVMR3 = NULL;
502 CreateVMReq.cCPUs = cCPUs;
503 rc = SUPCallVMMR0Ex(NIL_RTR0PTR, VMMR0_DO_GVMM_CREATE_VM, 0, &CreateVMReq.Hdr);
504 if (RT_SUCCESS(rc))
505 {
506 PVM pVM = pUVM->pVM = CreateVMReq.pVMR3;
507 AssertRelease(VALID_PTR(pVM));
508 AssertRelease(pVM->pVMR0 == CreateVMReq.pVMR0);
509 AssertRelease(pVM->pSession == pUVM->vm.s.pSession);
510 AssertRelease(pVM->cCPUs == cCPUs);
511 AssertRelease(pVM->offVMCPU == RT_UOFFSETOF(VM, aCpus));
512
513 Log(("VMR3Create: Created pUVM=%p pVM=%p pVMR0=%p hSelf=%#x cCPUs=%RU32\n",
514 pUVM, pVM, pVM->pVMR0, pVM->hSelf, pVM->cCPUs));
515
516 /*
517 * Initialize the VM structure and our internal data (VMINT).
518 */
519 pVM->pUVM = pUVM;
520
521 for (uint32_t i = 0; i < pVM->cCPUs; i++)
522 {
523 pVM->aCpus[i].hNativeThread = pUVM->aCpus[i].vm.s.NativeThreadEMT;
524 Assert(pVM->aCpus[i].hNativeThread != NIL_RTNATIVETHREAD);
525 }
526
527
528 /*
529 * Init the configuration.
530 */
531 rc = CFGMR3Init(pVM, pfnCFGMConstructor, pvUserCFGM);
532 if (RT_SUCCESS(rc))
533 {
534 rc = CFGMR3QueryBoolDef(CFGMR3GetRoot(pVM), "HwVirtExtForced", &pVM->fHwVirtExtForced, false);
535 if (RT_SUCCESS(rc) && pVM->fHwVirtExtForced)
536 pVM->fHWACCMEnabled = true;
537
538 /*
539 * If executing in fake suplib mode disable RR3 and RR0 in the config.
540 */
541 const char *psz = RTEnvGet("VBOX_SUPLIB_FAKE");
542 if (psz && !strcmp(psz, "fake"))
543 {
544 CFGMR3RemoveValue(CFGMR3GetRoot(pVM), "RawR3Enabled");
545 CFGMR3InsertInteger(CFGMR3GetRoot(pVM), "RawR3Enabled", 0);
546 CFGMR3RemoveValue(CFGMR3GetRoot(pVM), "RawR0Enabled");
547 CFGMR3InsertInteger(CFGMR3GetRoot(pVM), "RawR0Enabled", 0);
548 }
549
550 /*
551 * Make sure the CPU count in the config data matches.
552 */
553 if (RT_SUCCESS(rc))
554 {
555 uint32_t cCPUsCfg;
556 rc = CFGMR3QueryU32Def(CFGMR3GetRoot(pVM), "NumCPUs", &cCPUsCfg, 1);
557 AssertLogRelMsgRC(rc, ("Configuration error: Querying \"NumCPUs\" as integer failed, rc=%Rrc\n", rc));
558 if (RT_SUCCESS(rc) && cCPUsCfg != cCPUs)
559 {
560 AssertLogRelMsgFailed(("Configuration error: \"NumCPUs\"=%RU32 and VMR3CreateVM::cCPUs=%RU32 does not match!\n",
561 cCPUsCfg, cCPUs));
562 rc = VERR_INVALID_PARAMETER;
563 }
564 }
565 if (RT_SUCCESS(rc))
566 {
567 /*
568 * Init the ring-3 components and ring-3 per cpu data, finishing it off
569 * by a relocation round (intermediate context finalization will do this).
570 */
571 rc = vmR3InitRing3(pVM, pUVM);
572 if (RT_SUCCESS(rc))
573 {
574 rc = vmR3InitVMCpu(pVM);
575 if (RT_SUCCESS(rc))
576 rc = PGMR3FinalizeMappings(pVM);
577 if (RT_SUCCESS(rc))
578 {
579
580 LogFlow(("Ring-3 init succeeded\n"));
581
582 /*
583 * Init the Ring-0 components.
584 */
585 rc = vmR3InitRing0(pVM);
586 if (RT_SUCCESS(rc))
587 {
588 /* Relocate again, because some switcher fixups depends on R0 init results. */
589 VMR3Relocate(pVM, 0);
590
591#ifdef VBOX_WITH_DEBUGGER
592 /*
593 * Init the tcp debugger console if we're building
594 * with debugger support.
595 */
596 void *pvUser = NULL;
597 rc = DBGCTcpCreate(pVM, &pvUser);
598 if ( RT_SUCCESS(rc)
599 || rc == VERR_NET_ADDRESS_IN_USE)
600 {
601 pUVM->vm.s.pvDBGC = pvUser;
602#endif
603 /*
604 * Init the Guest Context components.
605 */
606 rc = vmR3InitGC(pVM);
607 if (RT_SUCCESS(rc))
608 {
609 /*
610 * Now we can safely set the VM halt method to default.
611 */
612 rc = vmR3SetHaltMethodU(pUVM, VMHALTMETHOD_DEFAULT);
613 if (RT_SUCCESS(rc))
614 {
615 /*
616 * Set the state and link into the global list.
617 */
618 vmR3SetState(pVM, VMSTATE_CREATED);
619 pUVM->pNext = g_pUVMsHead;
620 g_pUVMsHead = pUVM;
621 return VINF_SUCCESS;
622 }
623 }
624#ifdef VBOX_WITH_DEBUGGER
625 DBGCTcpTerminate(pVM, pUVM->vm.s.pvDBGC);
626 pUVM->vm.s.pvDBGC = NULL;
627 }
628#endif
629 //..
630 }
631 }
632 vmR3Destroy(pVM);
633 }
634 }
635 //..
636
637 /* Clean CFGM. */
638 int rc2 = CFGMR3Term(pVM);
639 AssertRC(rc2);
640 }
641
642 /* Tell GVMM that it can destroy the VM now. */
643 int rc2 = SUPCallVMMR0Ex(CreateVMReq.pVMR0, VMMR0_DO_GVMM_DESTROY_VM, 0, NULL);
644 AssertRC(rc2);
645 pUVM->pVM = NULL;
646 }
647 else
648 vmR3SetErrorU(pUVM, rc, RT_SRC_POS, N_("VM creation failed (GVMM)"));
649
650 LogFlow(("vmR3Create: returns %Rrc\n", rc));
651 return rc;
652}
653
654
655/**
656 * Initializes all R3 components of the VM
657 */
658static int vmR3InitRing3(PVM pVM, PUVM pUVM)
659{
660 int rc;
661
662 /*
663 * Init all R3 components, the order here might be important.
664 */
665 rc = MMR3Init(pVM);
666 if (RT_SUCCESS(rc))
667 {
668 STAM_REG(pVM, &pVM->StatTotalInGC, STAMTYPE_PROFILE_ADV, "/PROF/VM/InGC", STAMUNIT_TICKS_PER_CALL, "Profiling the total time spent in GC.");
669 STAM_REG(pVM, &pVM->StatSwitcherToGC, STAMTYPE_PROFILE_ADV, "/PROF/VM/SwitchToGC", STAMUNIT_TICKS_PER_CALL, "Profiling switching to GC.");
670 STAM_REG(pVM, &pVM->StatSwitcherToHC, STAMTYPE_PROFILE_ADV, "/PROF/VM/SwitchToHC", STAMUNIT_TICKS_PER_CALL, "Profiling switching to HC.");
671 STAM_REG(pVM, &pVM->StatSwitcherSaveRegs, STAMTYPE_PROFILE_ADV, "/VM/Switcher/ToGC/SaveRegs", STAMUNIT_TICKS_PER_CALL,"Profiling switching to GC.");
672 STAM_REG(pVM, &pVM->StatSwitcherSysEnter, STAMTYPE_PROFILE_ADV, "/VM/Switcher/ToGC/SysEnter", STAMUNIT_TICKS_PER_CALL,"Profiling switching to GC.");
673 STAM_REG(pVM, &pVM->StatSwitcherDebug, STAMTYPE_PROFILE_ADV, "/VM/Switcher/ToGC/Debug", STAMUNIT_TICKS_PER_CALL,"Profiling switching to GC.");
674 STAM_REG(pVM, &pVM->StatSwitcherCR0, STAMTYPE_PROFILE_ADV, "/VM/Switcher/ToGC/CR0", STAMUNIT_TICKS_PER_CALL, "Profiling switching to GC.");
675 STAM_REG(pVM, &pVM->StatSwitcherCR4, STAMTYPE_PROFILE_ADV, "/VM/Switcher/ToGC/CR4", STAMUNIT_TICKS_PER_CALL, "Profiling switching to GC.");
676 STAM_REG(pVM, &pVM->StatSwitcherLgdt, STAMTYPE_PROFILE_ADV, "/VM/Switcher/ToGC/Lgdt", STAMUNIT_TICKS_PER_CALL, "Profiling switching to GC.");
677 STAM_REG(pVM, &pVM->StatSwitcherLidt, STAMTYPE_PROFILE_ADV, "/VM/Switcher/ToGC/Lidt", STAMUNIT_TICKS_PER_CALL, "Profiling switching to GC.");
678 STAM_REG(pVM, &pVM->StatSwitcherLldt, STAMTYPE_PROFILE_ADV, "/VM/Switcher/ToGC/Lldt", STAMUNIT_TICKS_PER_CALL, "Profiling switching to GC.");
679 STAM_REG(pVM, &pVM->StatSwitcherTSS, STAMTYPE_PROFILE_ADV, "/VM/Switcher/ToGC/TSS", STAMUNIT_TICKS_PER_CALL, "Profiling switching to GC.");
680 STAM_REG(pVM, &pVM->StatSwitcherJmpCR3, STAMTYPE_PROFILE_ADV, "/VM/Switcher/ToGC/JmpCR3", STAMUNIT_TICKS_PER_CALL,"Profiling switching to GC.");
681 STAM_REG(pVM, &pVM->StatSwitcherRstrRegs, STAMTYPE_PROFILE_ADV, "/VM/Switcher/ToGC/RstrRegs", STAMUNIT_TICKS_PER_CALL,"Profiling switching to GC.");
682
683 STAM_REL_REG(pVM, &pUVM->vm.s.StatHaltYield, STAMTYPE_PROFILE, "/PROF/VM/Halt/Yield", STAMUNIT_TICKS_PER_CALL, "Profiling halted state yielding.");
684 STAM_REL_REG(pVM, &pUVM->vm.s.StatHaltBlock, STAMTYPE_PROFILE, "/PROF/VM/Halt/Block", STAMUNIT_TICKS_PER_CALL, "Profiling halted state blocking.");
685 STAM_REL_REG(pVM, &pUVM->vm.s.StatHaltTimers,STAMTYPE_PROFILE, "/PROF/VM/Halt/Timers", STAMUNIT_TICKS_PER_CALL, "Profiling halted state timer tasks.");
686
687 STAM_REG(pVM, &pUVM->vm.s.StatReqAllocNew, STAMTYPE_COUNTER, "/VM/Req/AllocNew", STAMUNIT_OCCURENCES, "Number of VMR3ReqAlloc returning a new packet.");
688 STAM_REG(pVM, &pUVM->vm.s.StatReqAllocRaces, STAMTYPE_COUNTER, "/VM/Req/AllocRaces", STAMUNIT_OCCURENCES, "Number of VMR3ReqAlloc causing races.");
689 STAM_REG(pVM, &pUVM->vm.s.StatReqAllocRecycled, STAMTYPE_COUNTER, "/VM/Req/AllocRecycled", STAMUNIT_OCCURENCES, "Number of VMR3ReqAlloc returning a recycled packet.");
690 STAM_REG(pVM, &pUVM->vm.s.StatReqFree, STAMTYPE_COUNTER, "/VM/Req/Free", STAMUNIT_OCCURENCES, "Number of VMR3ReqFree calls.");
691 STAM_REG(pVM, &pUVM->vm.s.StatReqFreeOverflow, STAMTYPE_COUNTER, "/VM/Req/FreeOverflow", STAMUNIT_OCCURENCES, "Number of times the request was actually freed.");
692
693 rc = CPUMR3Init(pVM);
694 if (RT_SUCCESS(rc))
695 {
696 rc = HWACCMR3Init(pVM);
697 if (RT_SUCCESS(rc))
698 {
699 rc = PGMR3Init(pVM);
700 if (RT_SUCCESS(rc))
701 {
702 rc = REMR3Init(pVM);
703 if (RT_SUCCESS(rc))
704 {
705 rc = MMR3InitPaging(pVM);
706 if (RT_SUCCESS(rc))
707 rc = TMR3Init(pVM);
708 if (RT_SUCCESS(rc))
709 {
710 rc = VMMR3Init(pVM);
711 if (RT_SUCCESS(rc))
712 {
713 rc = SELMR3Init(pVM);
714 if (RT_SUCCESS(rc))
715 {
716 rc = TRPMR3Init(pVM);
717 if (RT_SUCCESS(rc))
718 {
719 rc = CSAMR3Init(pVM);
720 if (RT_SUCCESS(rc))
721 {
722 rc = PATMR3Init(pVM);
723 if (RT_SUCCESS(rc))
724 {
725#ifdef VBOX_WITH_VMI
726 rc = PARAVR3Init(pVM);
727 if (RT_SUCCESS(rc))
728 {
729#endif
730 rc = IOMR3Init(pVM);
731 if (RT_SUCCESS(rc))
732 {
733 rc = EMR3Init(pVM);
734 if (RT_SUCCESS(rc))
735 {
736 rc = DBGFR3Init(pVM);
737 if (RT_SUCCESS(rc))
738 {
739 rc = PDMR3Init(pVM);
740 if (RT_SUCCESS(rc))
741 {
742 rc = PGMR3InitDynMap(pVM);
743 if (RT_SUCCESS(rc))
744 rc = MMR3HyperInitFinalize(pVM);
745 if (RT_SUCCESS(rc))
746 rc = PATMR3InitFinalize(pVM);
747 if (RT_SUCCESS(rc))
748 rc = PGMR3InitFinalize(pVM);
749 if (RT_SUCCESS(rc))
750 rc = SELMR3InitFinalize(pVM);
751 if (RT_SUCCESS(rc))
752 rc = TMR3InitFinalize(pVM);
753 if (RT_SUCCESS(rc))
754 rc = VMMR3InitFinalize(pVM);
755 if (RT_SUCCESS(rc))
756 rc = REMR3InitFinalize(pVM);
757 if (RT_SUCCESS(rc))
758 rc = vmR3InitDoCompleted(pVM, VMINITCOMPLETED_RING3);
759 if (RT_SUCCESS(rc))
760 {
761 LogFlow(("vmR3InitRing3: returns %Rrc\n", VINF_SUCCESS));
762 return VINF_SUCCESS;
763 }
764 int rc2 = PDMR3Term(pVM);
765 AssertRC(rc2);
766 }
767 int rc2 = DBGFR3Term(pVM);
768 AssertRC(rc2);
769 }
770 int rc2 = EMR3Term(pVM);
771 AssertRC(rc2);
772 }
773 int rc2 = IOMR3Term(pVM);
774 AssertRC(rc2);
775 }
776#ifdef VBOX_WITH_VMI
777 int rc2 = PARAVR3Term(pVM);
778 AssertRC(rc2);
779 }
780#endif
781 int rc2 = PATMR3Term(pVM);
782 AssertRC(rc2);
783 }
784 int rc2 = CSAMR3Term(pVM);
785 AssertRC(rc2);
786 }
787 int rc2 = TRPMR3Term(pVM);
788 AssertRC(rc2);
789 }
790 int rc2 = SELMR3Term(pVM);
791 AssertRC(rc2);
792 }
793 int rc2 = VMMR3Term(pVM);
794 AssertRC(rc2);
795 }
796 int rc2 = TMR3Term(pVM);
797 AssertRC(rc2);
798 }
799 int rc2 = REMR3Term(pVM);
800 AssertRC(rc2);
801 }
802 int rc2 = PGMR3Term(pVM);
803 AssertRC(rc2);
804 }
805 int rc2 = HWACCMR3Term(pVM);
806 AssertRC(rc2);
807 }
808 //int rc2 = CPUMR3Term(pVM);
809 //AssertRC(rc2);
810 }
811 /* MMR3Term is not called here because it'll kill the heap. */
812 }
813
814 LogFlow(("vmR3InitRing3: returns %Rrc\n", rc));
815 return rc;
816}
817
818
819/**
820 * Initializes all VM CPU components of the VM
821 */
822static int vmR3InitVMCpu(PVM pVM)
823{
824 int rc = VINF_SUCCESS;
825 int rc2;
826
827 rc = CPUMR3InitCPU(pVM);
828 if (RT_SUCCESS(rc))
829 {
830 rc = HWACCMR3InitCPU(pVM);
831 if (RT_SUCCESS(rc))
832 {
833 rc = PGMR3InitCPU(pVM);
834 if (RT_SUCCESS(rc))
835 {
836 rc = TMR3InitCPU(pVM);
837 if (RT_SUCCESS(rc))
838 {
839 rc = VMMR3InitCPU(pVM);
840 if (RT_SUCCESS(rc))
841 {
842 rc = EMR3InitCPU(pVM);
843 if (RT_SUCCESS(rc))
844 {
845 LogFlow(("vmR3InitVMCpu: returns %Rrc\n", VINF_SUCCESS));
846 return VINF_SUCCESS;
847 }
848
849 rc2 = VMMR3TermCPU(pVM);
850 AssertRC(rc2);
851 }
852 rc2 = TMR3TermCPU(pVM);
853 AssertRC(rc2);
854 }
855 rc2 = PGMR3TermCPU(pVM);
856 AssertRC(rc2);
857 }
858 rc2 = HWACCMR3TermCPU(pVM);
859 AssertRC(rc2);
860 }
861 rc2 = CPUMR3TermCPU(pVM);
862 AssertRC(rc2);
863 }
864 LogFlow(("vmR3InitVMCpu: returns %Rrc\n", rc));
865 return rc;
866}
867
868
869/**
870 * Initializes all R0 components of the VM
871 */
872static int vmR3InitRing0(PVM pVM)
873{
874 LogFlow(("vmR3InitRing0:\n"));
875
876 /*
877 * Check for FAKE suplib mode.
878 */
879 int rc = VINF_SUCCESS;
880 const char *psz = RTEnvGet("VBOX_SUPLIB_FAKE");
881 if (!psz || strcmp(psz, "fake"))
882 {
883 /*
884 * Call the VMMR0 component and let it do the init.
885 */
886 rc = VMMR3InitR0(pVM);
887 }
888 else
889 Log(("vmR3InitRing0: skipping because of VBOX_SUPLIB_FAKE=fake\n"));
890
891 /*
892 * Do notifications and return.
893 */
894 if (RT_SUCCESS(rc))
895 rc = vmR3InitDoCompleted(pVM, VMINITCOMPLETED_RING0);
896
897 /** todo: move this to the VMINITCOMPLETED_RING0 notification handler once implemented */
898 if (RT_SUCCESS(rc))
899 rc = HWACCMR3InitFinalizeR0(pVM);
900
901 LogFlow(("vmR3InitRing0: returns %Rrc\n", rc));
902 return rc;
903}
904
905
906/**
907 * Initializes all GC components of the VM
908 */
909static int vmR3InitGC(PVM pVM)
910{
911 LogFlow(("vmR3InitGC:\n"));
912
913 /*
914 * Check for FAKE suplib mode.
915 */
916 int rc = VINF_SUCCESS;
917 const char *psz = RTEnvGet("VBOX_SUPLIB_FAKE");
918 if (!psz || strcmp(psz, "fake"))
919 {
920 /*
921 * Call the VMMR0 component and let it do the init.
922 */
923 rc = VMMR3InitRC(pVM);
924 }
925 else
926 Log(("vmR3InitGC: skipping because of VBOX_SUPLIB_FAKE=fake\n"));
927
928 /*
929 * Do notifications and return.
930 */
931 if (RT_SUCCESS(rc))
932 rc = vmR3InitDoCompleted(pVM, VMINITCOMPLETED_GC);
933 LogFlow(("vmR3InitGC: returns %Rrc\n", rc));
934 return rc;
935}
936
937
938/**
939 * Do init completed notifications.
940 * This notifications can fail.
941 *
942 * @param pVM The VM handle.
943 * @param enmWhat What's completed.
944 */
945static int vmR3InitDoCompleted(PVM pVM, VMINITCOMPLETED enmWhat)
946{
947
948 return VINF_SUCCESS;
949}
950
951
952/**
953 * Calls the relocation functions for all VMM components so they can update
954 * any GC pointers. When this function is called all the basic VM members
955 * have been updated and the actual memory relocation have been done
956 * by the PGM/MM.
957 *
958 * This is used both on init and on runtime relocations.
959 *
960 * @param pVM VM handle.
961 * @param offDelta Relocation delta relative to old location.
962 */
963VMMR3DECL(void) VMR3Relocate(PVM pVM, RTGCINTPTR offDelta)
964{
965 LogFlow(("VMR3Relocate: offDelta=%RGv\n", offDelta));
966
967 /*
968 * The order here is very important!
969 */
970 PGMR3Relocate(pVM, offDelta);
971 PDMR3LdrRelocateU(pVM->pUVM, offDelta);
972 PGMR3Relocate(pVM, 0); /* Repeat after PDM relocation. */
973 CPUMR3Relocate(pVM);
974 HWACCMR3Relocate(pVM);
975 SELMR3Relocate(pVM);
976 VMMR3Relocate(pVM, offDelta);
977 SELMR3Relocate(pVM); /* !hack! fix stack! */
978 TRPMR3Relocate(pVM, offDelta);
979 PATMR3Relocate(pVM);
980 CSAMR3Relocate(pVM, offDelta);
981 IOMR3Relocate(pVM, offDelta);
982 EMR3Relocate(pVM);
983 TMR3Relocate(pVM, offDelta);
984 DBGFR3Relocate(pVM, offDelta);
985 PDMR3Relocate(pVM, offDelta);
986}
987
988
989/**
990 * Power on the virtual machine.
991 *
992 * @returns 0 on success.
993 * @returns VBox error code on failure.
994 * @param pVM VM to power on.
995 * @thread Any thread.
996 * @vmstate Created
997 * @vmstateto Running
998 */
999VMMR3DECL(int) VMR3PowerOn(PVM pVM)
1000{
1001 LogFlow(("VMR3PowerOn: pVM=%p\n", pVM));
1002
1003 /*
1004 * Validate input.
1005 */
1006 if (!pVM)
1007 {
1008 AssertMsgFailed(("Invalid VM pointer\n"));
1009 return VERR_INVALID_PARAMETER;
1010 }
1011
1012 /*
1013 * Request the operation in EMT.
1014 */
1015 PVMREQ pReq;
1016 int rc = VMR3ReqCall(pVM, VMREQDEST_ANY, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3PowerOn, 1, pVM);
1017 if (RT_SUCCESS(rc))
1018 {
1019 rc = pReq->iStatus;
1020 VMR3ReqFree(pReq);
1021 }
1022
1023 LogFlow(("VMR3PowerOn: returns %Rrc\n", rc));
1024 return rc;
1025}
1026
1027
1028/**
1029 * Power on the virtual machine.
1030 *
1031 * @returns 0 on success.
1032 * @returns VBox error code on failure.
1033 * @param pVM VM to power on.
1034 * @thread EMT
1035 */
1036static DECLCALLBACK(int) vmR3PowerOn(PVM pVM)
1037{
1038 LogFlow(("vmR3PowerOn: pVM=%p\n", pVM));
1039
1040 /*
1041 * Validate input.
1042 */
1043 if (pVM->enmVMState != VMSTATE_CREATED)
1044 {
1045 AssertMsgFailed(("Invalid VM state %d\n", pVM->enmVMState));
1046 return VERR_VM_INVALID_VM_STATE;
1047 }
1048
1049 /*
1050 * Change the state, notify the components and resume the execution.
1051 */
1052 vmR3SetState(pVM, VMSTATE_RUNNING);
1053 PDMR3PowerOn(pVM);
1054
1055 return VINF_SUCCESS;
1056}
1057
1058
1059/**
1060 * Suspends a running VM.
1061 *
1062 * @returns 0 on success.
1063 * @returns VBox error code on failure.
1064 * @param pVM VM to suspend.
1065 * @thread Any thread.
1066 * @vmstate Running
1067 * @vmstateto Suspended
1068 */
1069VMMR3DECL(int) VMR3Suspend(PVM pVM)
1070{
1071 LogFlow(("VMR3Suspend: pVM=%p\n", pVM));
1072
1073 /*
1074 * Validate input.
1075 */
1076 if (!pVM)
1077 {
1078 AssertMsgFailed(("Invalid VM pointer\n"));
1079 return VERR_INVALID_PARAMETER;
1080 }
1081
1082 /*
1083 * Request the operation in EMT.
1084 */
1085 PVMREQ pReq;
1086 int rc = VMR3ReqCall(pVM, VMREQDEST_ANY, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3Suspend, 1, pVM);
1087 if (RT_SUCCESS(rc))
1088 {
1089 rc = pReq->iStatus;
1090 VMR3ReqFree(pReq);
1091 }
1092
1093 LogFlow(("VMR3Suspend: returns %Rrc\n", rc));
1094 return rc;
1095}
1096
1097
1098/**
1099 * Suspends a running VM and prevent state saving until the VM is resumed or stopped.
1100 *
1101 * @returns 0 on success.
1102 * @returns VBox error code on failure.
1103 * @param pVM VM to suspend.
1104 * @thread Any thread.
1105 * @vmstate Running
1106 * @vmstateto Suspended
1107 */
1108VMMR3DECL(int) VMR3SuspendNoSave(PVM pVM)
1109{
1110 pVM->vm.s.fPreventSaveState = true;
1111 return VMR3Suspend(pVM);
1112}
1113
1114
1115/**
1116 * Suspends a running VM.
1117 *
1118 * @returns 0 on success.
1119 * @returns VBox error code on failure.
1120 * @param pVM VM to suspend.
1121 * @thread EMT
1122 */
1123static DECLCALLBACK(int) vmR3Suspend(PVM pVM)
1124{
1125 LogFlow(("vmR3Suspend: pVM=%p\n", pVM));
1126
1127 /*
1128 * Validate input.
1129 */
1130 if (pVM->enmVMState != VMSTATE_RUNNING)
1131 {
1132 AssertMsgFailed(("Invalid VM state %d\n", pVM->enmVMState));
1133 return VERR_VM_INVALID_VM_STATE;
1134 }
1135
1136 /*
1137 * Change the state, notify the components and resume the execution.
1138 */
1139 vmR3SetState(pVM, VMSTATE_SUSPENDED);
1140 PDMR3Suspend(pVM);
1141
1142 return VINF_EM_SUSPEND;
1143}
1144
1145
1146/**
1147 * Resume VM execution.
1148 *
1149 * @returns 0 on success.
1150 * @returns VBox error code on failure.
1151 * @param pVM The VM to resume.
1152 * @thread Any thread.
1153 * @vmstate Suspended
1154 * @vmstateto Running
1155 */
1156VMMR3DECL(int) VMR3Resume(PVM pVM)
1157{
1158 LogFlow(("VMR3Resume: pVM=%p\n", pVM));
1159
1160 /*
1161 * Validate input.
1162 */
1163 if (!pVM)
1164 {
1165 AssertMsgFailed(("Invalid VM pointer\n"));
1166 return VERR_INVALID_PARAMETER;
1167 }
1168
1169 /*
1170 * Request the operation in EMT.
1171 */
1172 PVMREQ pReq;
1173 int rc = VMR3ReqCall(pVM, VMREQDEST_ANY, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3Resume, 1, pVM);
1174 if (RT_SUCCESS(rc))
1175 {
1176 rc = pReq->iStatus;
1177 VMR3ReqFree(pReq);
1178 }
1179
1180 LogFlow(("VMR3Resume: returns %Rrc\n", rc));
1181 return rc;
1182}
1183
1184
1185/**
1186 * Resume VM execution.
1187 *
1188 * @returns 0 on success.
1189 * @returns VBox error code on failure.
1190 * @param pVM The VM to resume.
1191 * @thread EMT
1192 */
1193static DECLCALLBACK(int) vmR3Resume(PVM pVM)
1194{
1195 LogFlow(("vmR3Resume: pVM=%p\n", pVM));
1196
1197 /*
1198 * Validate input.
1199 */
1200 if (pVM->enmVMState != VMSTATE_SUSPENDED)
1201 {
1202 AssertMsgFailed(("Invalid VM state %d\n", pVM->enmVMState));
1203 return VERR_VM_INVALID_VM_STATE;
1204 }
1205
1206 /*
1207 * Change the state, notify the components and resume the execution.
1208 */
1209 pVM->vm.s.fPreventSaveState = false;
1210 vmR3SetState(pVM, VMSTATE_RUNNING);
1211 PDMR3Resume(pVM);
1212
1213 return VINF_EM_RESUME;
1214}
1215
1216
1217/**
1218 * Save current VM state.
1219 *
1220 * To save and terminate the VM, the VM must be suspended before the call.
1221 *
1222 * @returns 0 on success.
1223 * @returns VBox error code on failure.
1224 * @param pVM VM which state should be saved.
1225 * @param pszFilename Name of the save state file.
1226 * @param pfnProgress Progress callback. Optional.
1227 * @param pvUser User argument for the progress callback.
1228 * @thread Any thread.
1229 * @vmstate Suspended
1230 * @vmstateto Unchanged state.
1231 */
1232VMMR3DECL(int) VMR3Save(PVM pVM, const char *pszFilename, PFNVMPROGRESS pfnProgress, void *pvUser)
1233{
1234 LogFlow(("VMR3Save: pVM=%p pszFilename=%p:{%s} pfnProgress=%p pvUser=%p\n", pVM, pszFilename, pszFilename, pfnProgress, pvUser));
1235
1236 /*
1237 * Validate input.
1238 */
1239 if (!pVM)
1240 {
1241 AssertMsgFailed(("Invalid VM pointer\n"));
1242 return VERR_INVALID_PARAMETER;
1243 }
1244 if (!pszFilename)
1245 {
1246 AssertMsgFailed(("Must specify a filename to save the state to, wise guy!\n"));
1247 return VERR_INVALID_PARAMETER;
1248 }
1249
1250 /*
1251 * Request the operation in EMT.
1252 */
1253 PVMREQ pReq;
1254 int rc = VMR3ReqCall(pVM, VMREQDEST_ANY, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3Save, 4, pVM, pszFilename, pfnProgress, pvUser);
1255 if (RT_SUCCESS(rc))
1256 {
1257 rc = pReq->iStatus;
1258 VMR3ReqFree(pReq);
1259 }
1260
1261 LogFlow(("VMR3Save: returns %Rrc\n", rc));
1262 return rc;
1263}
1264
1265
1266/**
1267 * Save current VM state.
1268 *
1269 * To save and terminate the VM, the VM must be suspended before the call.
1270 *
1271 * @returns 0 on success.
1272 * @returns VBox error code on failure.
1273 * @param pVM VM which state should be saved.
1274 * @param pszFilename Name of the save state file.
1275 * @param pfnProgress Progress callback. Optional.
1276 * @param pvUser User argument for the progress callback.
1277 * @thread EMT
1278 */
1279static DECLCALLBACK(int) vmR3Save(PVM pVM, const char *pszFilename, PFNVMPROGRESS pfnProgress, void *pvUser)
1280{
1281 LogFlow(("vmR3Save: pVM=%p pszFilename=%p:{%s} pfnProgress=%p pvUser=%p\n", pVM, pszFilename, pszFilename, pfnProgress, pvUser));
1282
1283 /*
1284 * Validate input.
1285 */
1286 if (pVM->enmVMState != VMSTATE_SUSPENDED)
1287 {
1288 AssertMsgFailed(("Invalid VM state %d\n", pVM->enmVMState));
1289 return VERR_VM_INVALID_VM_STATE;
1290 }
1291
1292 /* If we are in an inconsistent state, then we don't allow state saving. */
1293 if (pVM->vm.s.fPreventSaveState)
1294 {
1295 LogRel(("VMM: vmR3Save: saving the VM state is not allowed at this moment\n"));
1296 return VERR_VM_SAVE_STATE_NOT_ALLOWED;
1297 }
1298
1299 /*
1300 * Change the state and perform the save.
1301 */
1302 /** @todo implement progress support in SSM */
1303 vmR3SetState(pVM, VMSTATE_SAVING);
1304 int rc = SSMR3Save(pVM, pszFilename, SSMAFTER_CONTINUE, pfnProgress, pvUser);
1305 vmR3SetState(pVM, VMSTATE_SUSPENDED);
1306
1307 return rc;
1308}
1309
1310
1311/**
1312 * Loads a new VM state.
1313 *
1314 * To restore a saved state on VM startup, call this function and then
1315 * resume the VM instead of powering it on.
1316 *
1317 * @returns 0 on success.
1318 * @returns VBox error code on failure.
1319 * @param pVM VM which state should be saved.
1320 * @param pszFilename Name of the save state file.
1321 * @param pfnProgress Progress callback. Optional.
1322 * @param pvUser User argument for the progress callback.
1323 * @thread Any thread.
1324 * @vmstate Created, Suspended
1325 * @vmstateto Suspended
1326 */
1327VMMR3DECL(int) VMR3Load(PVM pVM, const char *pszFilename, PFNVMPROGRESS pfnProgress, void *pvUser)
1328{
1329 LogFlow(("VMR3Load: pVM=%p pszFilename=%p:{%s} pfnProgress=%p pvUser=%p\n", pVM, pszFilename, pszFilename, pfnProgress, pvUser));
1330
1331 /*
1332 * Validate input.
1333 */
1334 if (!pVM)
1335 {
1336 AssertMsgFailed(("Invalid VM pointer\n"));
1337 return VERR_INVALID_PARAMETER;
1338 }
1339 if (!pszFilename)
1340 {
1341 AssertMsgFailed(("Must specify a filename to load the state from, wise guy!\n"));
1342 return VERR_INVALID_PARAMETER;
1343 }
1344
1345 /*
1346 * Request the operation in EMT.
1347 */
1348 PVMREQ pReq;
1349 int rc = VMR3ReqCall(pVM, VMREQDEST_ANY, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3Load, 4, pVM, pszFilename, pfnProgress, pvUser);
1350 if (RT_SUCCESS(rc))
1351 {
1352 rc = pReq->iStatus;
1353 VMR3ReqFree(pReq);
1354 }
1355
1356 LogFlow(("VMR3Load: returns %Rrc\n", rc));
1357 return rc;
1358}
1359
1360
1361/**
1362 * Loads a new VM state.
1363 *
1364 * To restore a saved state on VM startup, call this function and then
1365 * resume the VM instead of powering it on.
1366 *
1367 * @returns 0 on success.
1368 * @returns VBox error code on failure.
1369 * @param pVM VM which state should be saved.
1370 * @param pszFilename Name of the save state file.
1371 * @param pfnProgress Progress callback. Optional.
1372 * @param pvUser User argument for the progress callback.
1373 * @thread EMT.
1374 */
1375static DECLCALLBACK(int) vmR3Load(PVM pVM, const char *pszFilename, PFNVMPROGRESS pfnProgress, void *pvUser)
1376{
1377 LogFlow(("vmR3Load: pVM=%p pszFilename=%p:{%s} pfnProgress=%p pvUser=%p\n", pVM, pszFilename, pszFilename, pfnProgress, pvUser));
1378
1379 /*
1380 * Validate input.
1381 */
1382 if ( pVM->enmVMState != VMSTATE_SUSPENDED
1383 && pVM->enmVMState != VMSTATE_CREATED)
1384 {
1385 AssertMsgFailed(("Invalid VM state %d\n", pVM->enmVMState));
1386 return VMSetError(pVM, VERR_VM_INVALID_VM_STATE, RT_SRC_POS, N_("Invalid VM state (%s) for restoring state from '%s'"),
1387 VMR3GetStateName(pVM->enmVMState), pszFilename);
1388 }
1389
1390 /*
1391 * Change the state and perform the load.
1392 */
1393 vmR3SetState(pVM, VMSTATE_LOADING);
1394 int rc = SSMR3Load(pVM, pszFilename, SSMAFTER_RESUME, pfnProgress, pvUser);
1395 if (RT_SUCCESS(rc))
1396 {
1397 /* Not paranoia anymore; the saved guest might use different hypervisor selectors. We must call VMR3Relocate. */
1398 VMR3Relocate(pVM, 0);
1399 vmR3SetState(pVM, VMSTATE_SUSPENDED);
1400 }
1401 else
1402 {
1403 vmR3SetState(pVM, VMSTATE_LOAD_FAILURE);
1404 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);
1405 }
1406
1407 return rc;
1408}
1409
1410
1411/**
1412 * Power Off the VM.
1413 *
1414 * @returns 0 on success.
1415 * @returns VBox error code on failure.
1416 * @param pVM VM which should be destroyed.
1417 * @thread Any thread.
1418 * @vmstate Suspended, Running, Guru Meditation, Load Failure
1419 * @vmstateto Off
1420 */
1421VMMR3DECL(int) VMR3PowerOff(PVM pVM)
1422{
1423 LogFlow(("VMR3PowerOff: pVM=%p\n", pVM));
1424
1425 /*
1426 * Validate input.
1427 */
1428 if (!pVM)
1429 {
1430 AssertMsgFailed(("Invalid VM pointer\n"));
1431 return VERR_INVALID_PARAMETER;
1432 }
1433
1434 /*
1435 * Request the operation in EMT.
1436 */
1437 PVMREQ pReq;
1438 int rc = VMR3ReqCall(pVM, VMREQDEST_ANY, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3PowerOff, 1, pVM);
1439 if (RT_SUCCESS(rc))
1440 {
1441 rc = pReq->iStatus;
1442 VMR3ReqFree(pReq);
1443 }
1444
1445 LogFlow(("VMR3PowerOff: returns %Rrc\n", rc));
1446 return rc;
1447}
1448
1449
1450/**
1451 * Power Off the VM.
1452 *
1453 * @returns 0 on success.
1454 * @returns VBox error code on failure.
1455 * @param pVM VM which should be destroyed.
1456 * @thread EMT.
1457 */
1458static DECLCALLBACK(int) vmR3PowerOff(PVM pVM)
1459{
1460 LogFlow(("vmR3PowerOff: pVM=%p\n", pVM));
1461
1462 /*
1463 * Validate input.
1464 */
1465 if ( pVM->enmVMState != VMSTATE_RUNNING
1466 && pVM->enmVMState != VMSTATE_SUSPENDED
1467 && pVM->enmVMState != VMSTATE_LOAD_FAILURE
1468 && pVM->enmVMState != VMSTATE_GURU_MEDITATION)
1469 {
1470 AssertMsgFailed(("Invalid VM state %d\n", pVM->enmVMState));
1471 return VERR_VM_INVALID_VM_STATE;
1472 }
1473
1474 /*
1475 * For debugging purposes, we will log a summary of the guest state at this point.
1476 */
1477 if (pVM->enmVMState != VMSTATE_GURU_MEDITATION)
1478 {
1479 /** @todo make the state dumping at VMR3PowerOff optional. */
1480 RTLogRelPrintf("****************** Guest state at power off ******************\n");
1481 DBGFR3Info(pVM, "cpumguest", "verbose", DBGFR3InfoLogRelHlp());
1482 RTLogRelPrintf("***\n");
1483 DBGFR3Info(pVM, "mode", NULL, DBGFR3InfoLogRelHlp());
1484 RTLogRelPrintf("***\n");
1485 DBGFR3Info(pVM, "activetimers", NULL, DBGFR3InfoLogRelHlp());
1486 RTLogRelPrintf("***\n");
1487 DBGFR3Info(pVM, "gdt", NULL, DBGFR3InfoLogRelHlp());
1488 /** @todo dump guest call stack. */
1489#if 1 // temporary while debugging #1589
1490 RTLogRelPrintf("***\n");
1491 uint32_t esp = CPUMGetGuestESP(pVM);
1492 if ( CPUMGetGuestSS(pVM) == 0
1493 && esp < _64K)
1494 {
1495 uint8_t abBuf[PAGE_SIZE];
1496 RTLogRelPrintf("***\n"
1497 "ss:sp=0000:%04x ", esp);
1498 uint32_t Start = esp & ~(uint32_t)63;
1499 int rc = PGMPhysSimpleReadGCPhys(pVM, abBuf, Start, 0x100);
1500 if (RT_SUCCESS(rc))
1501 RTLogRelPrintf("0000:%04x TO 0000:%04x:\n"
1502 "%.*Rhxd\n",
1503 Start, Start + 0x100 - 1,
1504 0x100, abBuf);
1505 else
1506 RTLogRelPrintf("rc=%Rrc\n", rc);
1507
1508 /* grub ... */
1509 if (esp < 0x2000 && esp > 0x1fc0)
1510 {
1511 rc = PGMPhysSimpleReadGCPhys(pVM, abBuf, 0x8000, 0x800);
1512 if (RT_SUCCESS(rc))
1513 RTLogRelPrintf("0000:8000 TO 0000:87ff:\n"
1514 "%.*Rhxd\n",
1515 0x800, abBuf);
1516 }
1517 /* microsoft cdrom hang ... */
1518 if (true)
1519 {
1520 rc = PGMPhysSimpleReadGCPhys(pVM, abBuf, 0x8000, 0x200);
1521 if (RT_SUCCESS(rc))
1522 RTLogRelPrintf("2000:0000 TO 2000:01ff:\n"
1523 "%.*Rhxd\n",
1524 0x200, abBuf);
1525 }
1526 }
1527#endif
1528 RTLogRelPrintf("************** End of Guest state at power off ***************\n");
1529 }
1530
1531 /*
1532 * Change the state to OFF and notify the components.
1533 */
1534 vmR3SetState(pVM, VMSTATE_OFF);
1535 PDMR3PowerOff(pVM);
1536
1537 return VINF_EM_OFF;
1538}
1539
1540
1541/**
1542 * Destroys the VM.
1543 * The VM must be powered off (or never really powered on) to call this function.
1544 * The VM handle is destroyed and can no longer be used up successful return.
1545 *
1546 * @returns VBox status code.
1547 * @param pVM VM which should be destroyed.
1548 * @thread Any thread but the emulation thread.
1549 * @vmstate Off, Created
1550 * @vmstateto N/A
1551 */
1552VMMR3DECL(int) VMR3Destroy(PVM pVM)
1553{
1554 LogFlow(("VMR3Destroy: pVM=%p\n", pVM));
1555
1556 /*
1557 * Validate input.
1558 */
1559 if (!pVM)
1560 return VERR_INVALID_PARAMETER;
1561 AssertPtrReturn(pVM, VERR_INVALID_POINTER);
1562 AssertMsgReturn( pVM->enmVMState == VMSTATE_OFF
1563 || pVM->enmVMState == VMSTATE_CREATED,
1564 ("Invalid VM state %d\n", pVM->enmVMState),
1565 VERR_VM_INVALID_VM_STATE);
1566
1567 /*
1568 * Change VM state to destroying and unlink the VM.
1569 */
1570 vmR3SetState(pVM, VMSTATE_DESTROYING);
1571
1572 /** @todo lock this when we start having multiple machines in a process... */
1573 PUVM pUVM = pVM->pUVM; AssertPtr(pUVM);
1574 if (g_pUVMsHead == pUVM)
1575 g_pUVMsHead = pUVM->pNext;
1576 else
1577 {
1578 PUVM pPrev = g_pUVMsHead;
1579 while (pPrev && pPrev->pNext != pUVM)
1580 pPrev = pPrev->pNext;
1581 AssertMsgReturn(pPrev, ("pUVM=%p / pVM=%p is INVALID!\n", pUVM, pVM), VERR_INVALID_PARAMETER);
1582
1583 pPrev->pNext = pUVM->pNext;
1584 }
1585 pUVM->pNext = NULL;
1586
1587 /*
1588 * Notify registered at destruction listeners.
1589 * (That's the debugger console.)
1590 */
1591 vmR3AtDtor(pVM);
1592
1593 /*
1594 * If we are the EMT we'll delay the cleanup till later.
1595 */
1596 if (VM_IS_EMT(pVM))
1597 {
1598 pUVM->vm.s.fEMTDoesTheCleanup = true;
1599 pUVM->vm.s.fTerminateEMT = true;
1600 VM_FF_SET(pVM, VM_FF_TERMINATE);
1601 }
1602 else
1603 {
1604 /*
1605 * Request EMT to do the larger part of the destruction.
1606 */
1607 PVMREQ pReq = NULL;
1608 int rc = VMR3ReqCallU(pUVM, VMREQDEST_ANY, &pReq, RT_INDEFINITE_WAIT, 0, (PFNRT)vmR3Destroy, 1, pVM);
1609 if (RT_SUCCESS(rc))
1610 rc = pReq->iStatus;
1611 AssertRC(rc);
1612 VMR3ReqFree(pReq);
1613
1614 /*
1615 * Wait for the EMT thread to terminate.
1616 */
1617 Assert(pUVM->vm.s.fTerminateEMT);
1618 /** @todo SMP */
1619 rc = RTThreadWait(pUVM->aCpus[0].vm.s.ThreadEMT, 30000, NULL);
1620 AssertMsgRC(rc, ("EMT thread wait failed, rc=%Rrc\n", rc));
1621
1622 /*
1623 * Now do the final bit where the heap and VM structures are freed up.
1624 */
1625 vmR3DestroyUVM(pUVM);
1626 }
1627
1628 LogFlow(("VMR3Destroy: returns VINF_SUCCESS\n"));
1629 return VINF_SUCCESS;
1630}
1631
1632
1633/**
1634 * Internal destruction worker.
1635 *
1636 * This will do nearly all of the job, including sacking the EMT.
1637 *
1638 * @returns VBox status.
1639 * @param pVM VM handle.
1640 */
1641DECLCALLBACK(int) vmR3Destroy(PVM pVM)
1642{
1643 PUVM pUVM = pVM->pUVM;
1644 NOREF(pUVM);
1645 LogFlow(("vmR3Destroy: pVM=%p pUVM=%p\n", pVM, pUVM));
1646 VM_ASSERT_EMT(pVM);
1647
1648 /*
1649 * Dump statistics to the log.
1650 */
1651#if defined(VBOX_WITH_STATISTICS) || defined(LOG_ENABLED)
1652 RTLogFlags(NULL, "nodisabled nobuffered");
1653#endif
1654#ifdef VBOX_WITH_STATISTICS
1655# ifndef DEBUG_dmik
1656 STAMR3Dump(pVM, "*");
1657# endif
1658#else
1659 LogRel(("************************* Statistics *************************\n"));
1660 STAMR3DumpToReleaseLog(pVM, "*");
1661 LogRel(("********************* End of statistics **********************\n"));
1662#endif
1663
1664 /*
1665 * Destroy the VM components.
1666 */
1667 int rc = TMR3Term(pVM);
1668 AssertRC(rc);
1669#ifdef VBOX_WITH_DEBUGGER
1670 rc = DBGCTcpTerminate(pVM, pUVM->vm.s.pvDBGC);
1671 pVM->pUVM->vm.s.pvDBGC = NULL;
1672#endif
1673 AssertRC(rc);
1674 rc = DBGFR3Term(pVM);
1675 AssertRC(rc);
1676 rc = PDMR3Term(pVM);
1677 AssertRC(rc);
1678 rc = EMR3Term(pVM);
1679 AssertRC(rc);
1680 rc = IOMR3Term(pVM);
1681 AssertRC(rc);
1682 rc = CSAMR3Term(pVM);
1683 AssertRC(rc);
1684 rc = PATMR3Term(pVM);
1685 AssertRC(rc);
1686 rc = TRPMR3Term(pVM);
1687 AssertRC(rc);
1688 rc = SELMR3Term(pVM);
1689 AssertRC(rc);
1690 rc = REMR3Term(pVM);
1691 AssertRC(rc);
1692 rc = HWACCMR3Term(pVM);
1693 AssertRC(rc);
1694 rc = PGMR3Term(pVM);
1695 AssertRC(rc);
1696 rc = VMMR3Term(pVM); /* Terminates the ring-0 code! */
1697 AssertRC(rc);
1698 rc = CPUMR3Term(pVM);
1699 AssertRC(rc);
1700 rc = PDMR3CritSectTerm(pVM);
1701 AssertRC(rc);
1702 rc = MMR3Term(pVM);
1703 AssertRC(rc);
1704
1705 /*
1706 * We're done in this thread (EMT).
1707 */
1708 ASMAtomicUoWriteBool(&pVM->pUVM->vm.s.fTerminateEMT, true);
1709 ASMAtomicWriteU32(&pVM->fForcedActions, VM_FF_TERMINATE);
1710 LogFlow(("vmR3Destroy: returning %Rrc\n", VINF_EM_TERMINATE));
1711 return VINF_EM_TERMINATE;
1712}
1713
1714
1715/**
1716 * Destroys the shared VM structure, leaving only UVM behind.
1717 *
1718 * This is called by EMT right before terminating.
1719 *
1720 * @param pUVM The UVM handle.
1721 */
1722void vmR3DestroyFinalBitFromEMT(PUVM pUVM)
1723{
1724 if (pUVM->pVM)
1725 {
1726 /*
1727 * Modify state and then terminate MM.
1728 * (MM must be delayed until this point so we don't destroy the callbacks and the request packet.)
1729 */
1730 vmR3SetState(pUVM->pVM, VMSTATE_TERMINATED);
1731
1732 /*
1733 * Tell GVMM to destroy the VM and free its resources.
1734 */
1735 int rc = SUPCallVMMR0Ex(pUVM->pVM->pVMR0, VMMR0_DO_GVMM_DESTROY_VM, 0, NULL);
1736 AssertRC(rc);
1737 pUVM->pVM = NULL;
1738 }
1739
1740 /*
1741 * Did EMT call VMR3Destroy and have to do it all?
1742 */
1743 if (pUVM->vm.s.fEMTDoesTheCleanup)
1744 vmR3DestroyUVM(pUVM);
1745}
1746
1747
1748/**
1749 * Destroys the UVM portion.
1750 *
1751 * This is called as the final step in the VM destruction or as the cleanup
1752 * in case of a creation failure. If EMT called VMR3Destroy, meaning
1753 * VMINTUSERPERVM::fEMTDoesTheCleanup is true, it will call this as
1754 * vmR3DestroyFinalBitFromEMT completes.
1755 *
1756 * @param pVM VM Handle.
1757 */
1758static void vmR3DestroyUVM(PUVM pUVM)
1759{
1760 /*
1761 * Terminate the EMT if still running (creation failure only).
1762 */
1763 if (!pUVM->vm.s.fTerminateEMT)
1764 {
1765 ASMAtomicUoWriteBool(&pUVM->vm.s.fTerminateEMT, true);
1766 if (pUVM->pVM)
1767 {
1768 VM_FF_SET(pUVM->pVM, VM_FF_TERMINATE);
1769 VMR3NotifyFF(pUVM->pVM, false);
1770 }
1771 RTSemEventSignal(pUVM->vm.s.EventSemWait);
1772
1773 /** @todo SMP */
1774 int rc2 = RTThreadWait(pUVM->aCpus[0].vm.s.ThreadEMT, 2000, NULL);
1775 AssertRC(rc2);
1776 }
1777 RTSemEventDestroy(pUVM->vm.s.EventSemWait);
1778 pUVM->vm.s.EventSemWait = NIL_RTSEMEVENT;
1779
1780 /*
1781 * Free the event semaphores associated with the request packets.
1782 */
1783 unsigned cReqs = 0;
1784 for (unsigned i = 0; i < RT_ELEMENTS(pUVM->vm.s.apReqFree); i++)
1785 {
1786 PVMREQ pReq = pUVM->vm.s.apReqFree[i];
1787 pUVM->vm.s.apReqFree[i] = NULL;
1788 for (; pReq; pReq = pReq->pNext, cReqs++)
1789 {
1790 pReq->enmState = VMREQSTATE_INVALID;
1791 RTSemEventDestroy(pReq->EventSem);
1792 }
1793 }
1794 Assert(cReqs == pUVM->vm.s.cReqFree); NOREF(cReqs);
1795
1796 /*
1797 * Kill all queued requests. (There really shouldn't be any!)
1798 */
1799 for (unsigned i = 0; i < 10; i++)
1800 {
1801 PVMREQ pReqHead = (PVMREQ)ASMAtomicXchgPtr((void *volatile *)&pUVM->vm.s.pReqs, NULL);
1802 AssertMsg(!pReqHead, ("This isn't supposed to happen! VMR3Destroy caller has to serialize this.\n"));
1803 if (!pReqHead)
1804 break;
1805 for (PVMREQ pReq = pReqHead; pReq; pReq = pReq->pNext)
1806 {
1807 ASMAtomicUoWriteSize(&pReq->iStatus, VERR_INTERNAL_ERROR);
1808 ASMAtomicWriteSize(&pReq->enmState, VMREQSTATE_INVALID);
1809 RTSemEventSignal(pReq->EventSem);
1810 RTThreadSleep(2);
1811 RTSemEventDestroy(pReq->EventSem);
1812 }
1813 /* give them a chance to respond before we free the request memory. */
1814 RTThreadSleep(32);
1815 }
1816
1817 /*
1818 * Make sure the VMMR0.r0 module and whatever else is unloaded.
1819 */
1820 PDMR3TermUVM(pUVM);
1821
1822 /*
1823 * Terminate the support library if initialized.
1824 */
1825 if (pUVM->vm.s.pSession)
1826 {
1827 int rc = SUPTerm();
1828 AssertRC(rc);
1829 pUVM->vm.s.pSession = NIL_RTR0PTR;
1830 }
1831
1832 /*
1833 * Destroy the MM heap and free the UVM structure.
1834 */
1835 MMR3TermUVM(pUVM);
1836 STAMR3TermUVM(pUVM);
1837
1838 RTTlsFree(pUVM->vm.s.idxTLS);
1839
1840 ASMAtomicUoWriteU32(&pUVM->u32Magic, UINT32_MAX);
1841 RTMemFree(pUVM);
1842
1843 RTLogFlush(NULL);
1844}
1845
1846
1847/**
1848 * Enumerates the VMs in this process.
1849 *
1850 * @returns Pointer to the next VM.
1851 * @returns NULL when no more VMs.
1852 * @param pVMPrev The previous VM
1853 * Use NULL to start the enumeration.
1854 */
1855VMMR3DECL(PVM) VMR3EnumVMs(PVM pVMPrev)
1856{
1857 /*
1858 * This is quick and dirty. It has issues with VM being
1859 * destroyed during the enumeration.
1860 */
1861 PUVM pNext;
1862 if (pVMPrev)
1863 pNext = pVMPrev->pUVM->pNext;
1864 else
1865 pNext = g_pUVMsHead;
1866 return pNext ? pNext->pVM : NULL;
1867}
1868
1869
1870/**
1871 * Registers an at VM destruction callback.
1872 *
1873 * @returns VBox status code.
1874 * @param pfnAtDtor Pointer to callback.
1875 * @param pvUser User argument.
1876 */
1877VMMR3DECL(int) VMR3AtDtorRegister(PFNVMATDTOR pfnAtDtor, void *pvUser)
1878{
1879 /*
1880 * Check if already registered.
1881 */
1882 VM_ATDTOR_LOCK();
1883 PVMATDTOR pCur = g_pVMAtDtorHead;
1884 while (pCur)
1885 {
1886 if (pfnAtDtor == pCur->pfnAtDtor)
1887 {
1888 VM_ATDTOR_UNLOCK();
1889 AssertMsgFailed(("Already registered at destruction callback %p!\n", pfnAtDtor));
1890 return VERR_INVALID_PARAMETER;
1891 }
1892
1893 /* next */
1894 pCur = pCur->pNext;
1895 }
1896 VM_ATDTOR_UNLOCK();
1897
1898 /*
1899 * Allocate new entry.
1900 */
1901 PVMATDTOR pVMAtDtor = (PVMATDTOR)RTMemAlloc(sizeof(*pVMAtDtor));
1902 if (!pVMAtDtor)
1903 return VERR_NO_MEMORY;
1904
1905 VM_ATDTOR_LOCK();
1906 pVMAtDtor->pfnAtDtor = pfnAtDtor;
1907 pVMAtDtor->pvUser = pvUser;
1908 pVMAtDtor->pNext = g_pVMAtDtorHead;
1909 g_pVMAtDtorHead = pVMAtDtor;
1910 VM_ATDTOR_UNLOCK();
1911
1912 return VINF_SUCCESS;
1913}
1914
1915
1916/**
1917 * Deregisters an at VM destruction callback.
1918 *
1919 * @returns VBox status code.
1920 * @param pfnAtDtor Pointer to callback.
1921 */
1922VMMR3DECL(int) VMR3AtDtorDeregister(PFNVMATDTOR pfnAtDtor)
1923{
1924 /*
1925 * Find it, unlink it and free it.
1926 */
1927 VM_ATDTOR_LOCK();
1928 PVMATDTOR pPrev = NULL;
1929 PVMATDTOR pCur = g_pVMAtDtorHead;
1930 while (pCur)
1931 {
1932 if (pfnAtDtor == pCur->pfnAtDtor)
1933 {
1934 if (pPrev)
1935 pPrev->pNext = pCur->pNext;
1936 else
1937 g_pVMAtDtorHead = pCur->pNext;
1938 pCur->pNext = NULL;
1939 VM_ATDTOR_UNLOCK();
1940
1941 RTMemFree(pCur);
1942 return VINF_SUCCESS;
1943 }
1944
1945 /* next */
1946 pPrev = pCur;
1947 pCur = pCur->pNext;
1948 }
1949 VM_ATDTOR_UNLOCK();
1950
1951 return VERR_INVALID_PARAMETER;
1952}
1953
1954
1955/**
1956 * Walks the list of at VM destructor callbacks.
1957 * @param pVM The VM which is about to be destroyed.
1958 */
1959static void vmR3AtDtor(PVM pVM)
1960{
1961 /*
1962 * Find it, unlink it and free it.
1963 */
1964 VM_ATDTOR_LOCK();
1965 for (PVMATDTOR pCur = g_pVMAtDtorHead; pCur; pCur = pCur->pNext)
1966 pCur->pfnAtDtor(pVM, pCur->pvUser);
1967 VM_ATDTOR_UNLOCK();
1968}
1969
1970
1971/**
1972 * Reset the current VM.
1973 *
1974 * @returns VBox status code.
1975 * @param pVM VM to reset.
1976 */
1977VMMR3DECL(int) VMR3Reset(PVM pVM)
1978{
1979 int rc = VINF_SUCCESS;
1980
1981 /*
1982 * Check the state.
1983 */
1984 if (!pVM)
1985 return VERR_INVALID_PARAMETER;
1986 if ( pVM->enmVMState != VMSTATE_RUNNING
1987 && pVM->enmVMState != VMSTATE_SUSPENDED)
1988 {
1989 AssertMsgFailed(("Invalid VM state %d\n", pVM->enmVMState));
1990 return VERR_VM_INVALID_VM_STATE;
1991 }
1992
1993 /*
1994 * Queue reset request to the emulation thread
1995 * and wait for it to be processed.
1996 */
1997 PVMREQ pReq = NULL;
1998 rc = VMR3ReqCall(pVM, VMREQDEST_ANY, &pReq, 0, (PFNRT)vmR3Reset, 1, pVM);
1999 while (rc == VERR_TIMEOUT)
2000 rc = VMR3ReqWait(pReq, RT_INDEFINITE_WAIT);
2001 if (RT_SUCCESS(rc))
2002 rc = pReq->iStatus;
2003 VMR3ReqFree(pReq);
2004
2005 return rc;
2006}
2007
2008
2009/**
2010 * Worker which checks integrity of some internal structures.
2011 * This is yet another attempt to track down that AVL tree crash.
2012 */
2013static void vmR3CheckIntegrity(PVM pVM)
2014{
2015#ifdef VBOX_STRICT
2016 int rc = PGMR3CheckIntegrity(pVM);
2017 AssertReleaseRC(rc);
2018#endif
2019}
2020
2021
2022/**
2023 * Reset request processor.
2024 *
2025 * This is called by the emulation thread as a response to the
2026 * reset request issued by VMR3Reset().
2027 *
2028 * @returns VBox status code.
2029 * @param pVM VM to reset.
2030 */
2031static DECLCALLBACK(int) vmR3Reset(PVM pVM)
2032{
2033 /*
2034 * As a safety precaution we temporarily change the state while resetting.
2035 * (If VMR3Reset was not called from EMT we might have change state... let's ignore that fact for now.)
2036 */
2037 VMSTATE enmVMState = pVM->enmVMState;
2038 Assert(enmVMState == VMSTATE_SUSPENDED || enmVMState == VMSTATE_RUNNING);
2039 vmR3SetState(pVM, VMSTATE_RESETTING);
2040 vmR3CheckIntegrity(pVM);
2041
2042
2043 /*
2044 * Reset the VM components.
2045 */
2046 PATMR3Reset(pVM);
2047 CSAMR3Reset(pVM);
2048 PGMR3Reset(pVM); /* We clear VM RAM in PGMR3Reset. It's vital PDMR3Reset is executed
2049 * _afterwards_. E.g. ACPI sets up RAM tables during init/reset. */
2050 MMR3Reset(pVM);
2051 PDMR3Reset(pVM);
2052 SELMR3Reset(pVM);
2053 TRPMR3Reset(pVM);
2054 vmR3AtResetU(pVM->pUVM);
2055 REMR3Reset(pVM);
2056 IOMR3Reset(pVM);
2057 CPUMR3Reset(pVM);
2058 TMR3Reset(pVM);
2059 EMR3Reset(pVM);
2060 HWACCMR3Reset(pVM); /* This must come *after* PATM, CSAM, CPUM, SELM and TRPM. */
2061
2062#ifdef LOG_ENABLED
2063 /*
2064 * Debug logging.
2065 */
2066 RTLogPrintf("\n\nThe VM was reset:\n");
2067 DBGFR3Info(pVM, "cpum", "verbose", NULL);
2068#endif
2069
2070 /*
2071 * Restore the state.
2072 */
2073 vmR3CheckIntegrity(pVM);
2074 Assert(pVM->enmVMState == VMSTATE_RESETTING);
2075 vmR3SetState(pVM, enmVMState);
2076
2077 return VINF_EM_RESET;
2078}
2079
2080
2081/**
2082 * Walks the list of at VM reset callbacks and calls them
2083 *
2084 * @returns VBox status code.
2085 * Any failure is fatal.
2086 * @param pUVM Pointe to the user mode VM structure.
2087 */
2088static int vmR3AtResetU(PUVM pUVM)
2089{
2090 /*
2091 * Walk the list and call them all.
2092 */
2093 int rc = VINF_SUCCESS;
2094 for (PVMATRESET pCur = pUVM->vm.s.pAtReset; pCur; pCur = pCur->pNext)
2095 {
2096 /* do the call */
2097 switch (pCur->enmType)
2098 {
2099 case VMATRESETTYPE_DEV:
2100 rc = pCur->u.Dev.pfnCallback(pCur->u.Dev.pDevIns, pCur->pvUser);
2101 break;
2102 case VMATRESETTYPE_INTERNAL:
2103 rc = pCur->u.Internal.pfnCallback(pUVM->pVM, pCur->pvUser);
2104 break;
2105 case VMATRESETTYPE_EXTERNAL:
2106 pCur->u.External.pfnCallback(pCur->pvUser);
2107 break;
2108 default:
2109 AssertMsgFailed(("Invalid at-reset type %d!\n", pCur->enmType));
2110 return VERR_INTERNAL_ERROR;
2111 }
2112
2113 if (RT_FAILURE(rc))
2114 {
2115 AssertMsgFailed(("At-reset handler %s failed with rc=%d\n", pCur->pszDesc, rc));
2116 return rc;
2117 }
2118 }
2119
2120 return VINF_SUCCESS;
2121}
2122
2123
2124/**
2125 * Internal registration function
2126 */
2127static int vmr3AtResetRegisterU(PUVM pUVM, void *pvUser, const char *pszDesc, PVMATRESET *ppNew)
2128{
2129 /*
2130 * Allocate restration structure.
2131 */
2132 PVMATRESET pNew = (PVMATRESET)MMR3HeapAllocU(pUVM, MM_TAG_VM, sizeof(*pNew));
2133 if (pNew)
2134 {
2135 /* fill data. */
2136 pNew->pszDesc = pszDesc;
2137 pNew->pvUser = pvUser;
2138
2139 /* insert */
2140 pNew->pNext = *pUVM->vm.s.ppAtResetNext;
2141 *pUVM->vm.s.ppAtResetNext = pNew;
2142 pUVM->vm.s.ppAtResetNext = &pNew->pNext;
2143
2144 *ppNew = pNew;
2145 return VINF_SUCCESS;
2146 }
2147 return VERR_NO_MEMORY;
2148}
2149
2150
2151/**
2152 * Registers an at VM reset callback.
2153 *
2154 * @returns VBox status code.
2155 * @param pVM The VM.
2156 * @param pDevInst Device instance.
2157 * @param pfnCallback Callback function.
2158 * @param pvUser User argument.
2159 * @param pszDesc Description (optional).
2160 */
2161VMMR3DECL(int) VMR3AtResetRegister(PVM pVM, PPDMDEVINS pDevInst, PFNVMATRESET pfnCallback, void *pvUser, const char *pszDesc)
2162{
2163 /*
2164 * Validate.
2165 */
2166 if (!pDevInst)
2167 {
2168 AssertMsgFailed(("pDevIns is NULL!\n"));
2169 return VERR_INVALID_PARAMETER;
2170 }
2171
2172 /*
2173 * Create the new entry.
2174 */
2175 PVMATRESET pNew;
2176 int rc = vmr3AtResetRegisterU(pVM->pUVM, pvUser, pszDesc, &pNew);
2177 if (RT_SUCCESS(rc))
2178 {
2179 /*
2180 * Fill in type data.
2181 */
2182 pNew->enmType = VMATRESETTYPE_DEV;
2183 pNew->u.Dev.pfnCallback = pfnCallback;
2184 pNew->u.Dev.pDevIns = pDevInst;
2185 }
2186
2187 return rc;
2188}
2189
2190
2191/**
2192 * Registers an at VM reset internal callback.
2193 *
2194 * @returns VBox status code.
2195 * @param pVM The VM.
2196 * @param pfnCallback Callback function.
2197 * @param pvUser User argument.
2198 * @param pszDesc Description (optional).
2199 */
2200VMMR3DECL(int) VMR3AtResetRegisterInternal(PVM pVM, PFNVMATRESETINT pfnCallback, void *pvUser, const char *pszDesc)
2201{
2202 /*
2203 * Validate.
2204 */
2205 if (!pfnCallback)
2206 {
2207 AssertMsgFailed(("pfnCallback is NULL!\n"));
2208 return VERR_INVALID_PARAMETER;
2209 }
2210
2211 /*
2212 * Create the new entry.
2213 */
2214 PVMATRESET pNew;
2215 int rc = vmr3AtResetRegisterU(pVM->pUVM, pvUser, pszDesc, &pNew);
2216 if (RT_SUCCESS(rc))
2217 {
2218 /*
2219 * Fill in type data.
2220 */
2221 pNew->enmType = VMATRESETTYPE_INTERNAL;
2222 pNew->u.Internal.pfnCallback = pfnCallback;
2223 }
2224
2225 return rc;
2226}
2227
2228
2229/**
2230 * Registers an at VM reset external callback.
2231 *
2232 * @returns VBox status code.
2233 * @param pVM The VM.
2234 * @param pfnCallback Callback function.
2235 * @param pvUser User argument.
2236 * @param pszDesc Description (optional).
2237 */
2238VMMR3DECL(int) VMR3AtResetRegisterExternal(PVM pVM, PFNVMATRESETEXT pfnCallback, void *pvUser, const char *pszDesc)
2239{
2240 /*
2241 * Validate.
2242 */
2243 if (!pfnCallback)
2244 {
2245 AssertMsgFailed(("pfnCallback is NULL!\n"));
2246 return VERR_INVALID_PARAMETER;
2247 }
2248
2249 /*
2250 * Create the new entry.
2251 */
2252 PVMATRESET pNew;
2253 int rc = vmr3AtResetRegisterU(pVM->pUVM, pvUser, pszDesc, &pNew);
2254 if (RT_SUCCESS(rc))
2255 {
2256 /*
2257 * Fill in type data.
2258 */
2259 pNew->enmType = VMATRESETTYPE_EXTERNAL;
2260 pNew->u.External.pfnCallback = pfnCallback;
2261 }
2262
2263 return rc;
2264}
2265
2266
2267/**
2268 * Unlinks and frees a callback.
2269 *
2270 * @returns Pointer to the next callback structure.
2271 * @param pUVM Pointer to the user mode VM structure.
2272 * @param pCur The one to free.
2273 * @param pPrev The one before pCur.
2274 */
2275static PVMATRESET vmr3AtResetFreeU(PUVM pUVM, PVMATRESET pCur, PVMATRESET pPrev)
2276{
2277 /*
2278 * Unlink it.
2279 */
2280 PVMATRESET pNext = pCur->pNext;
2281 if (pPrev)
2282 {
2283 pPrev->pNext = pNext;
2284 if (!pNext)
2285 pUVM->vm.s.ppAtResetNext = &pPrev->pNext;
2286 }
2287 else
2288 {
2289 pUVM->vm.s.pAtReset = pNext;
2290 if (!pNext)
2291 pUVM->vm.s.ppAtResetNext = &pUVM->vm.s.pAtReset;
2292 }
2293
2294 /*
2295 * Free it.
2296 */
2297 MMR3HeapFree(pCur);
2298
2299 return pNext;
2300}
2301
2302
2303/**
2304 * Deregisters an at VM reset callback.
2305 *
2306 * @returns VBox status code.
2307 * @param pVM The VM.
2308 * @param pDevIns Device instance.
2309 * @param pfnCallback Callback function.
2310 */
2311VMMR3DECL(int) VMR3AtResetDeregister(PVM pVM, PPDMDEVINS pDevIns, PFNVMATRESET pfnCallback)
2312{
2313 int rc = VERR_VM_ATRESET_NOT_FOUND;
2314 PVMATRESET pPrev = NULL;
2315 PVMATRESET pCur = pVM->pUVM->vm.s.pAtReset;
2316 while (pCur)
2317 {
2318 if ( pCur->enmType == VMATRESETTYPE_DEV
2319 && pCur->u.Dev.pDevIns == pDevIns
2320 && ( !pfnCallback
2321 || pCur->u.Dev.pfnCallback == pfnCallback))
2322 {
2323 pCur = vmr3AtResetFreeU(pVM->pUVM, pCur, pPrev);
2324 rc = VINF_SUCCESS;
2325 }
2326 else
2327 {
2328 pPrev = pCur;
2329 pCur = pCur->pNext;
2330 }
2331 }
2332
2333 AssertRC(rc);
2334 return rc;
2335}
2336
2337
2338/**
2339 * Deregisters an at VM reset internal callback.
2340 *
2341 * @returns VBox status code.
2342 * @param pVM The VM.
2343 * @param pfnCallback Callback function.
2344 */
2345VMMR3DECL(int) VMR3AtResetDeregisterInternal(PVM pVM, PFNVMATRESETINT pfnCallback)
2346{
2347 int rc = VERR_VM_ATRESET_NOT_FOUND;
2348 PVMATRESET pPrev = NULL;
2349 PVMATRESET pCur = pVM->pUVM->vm.s.pAtReset;
2350 while (pCur)
2351 {
2352 if ( pCur->enmType == VMATRESETTYPE_INTERNAL
2353 && pCur->u.Internal.pfnCallback == pfnCallback)
2354 {
2355 pCur = vmr3AtResetFreeU(pVM->pUVM, pCur, pPrev);
2356 rc = VINF_SUCCESS;
2357 }
2358 else
2359 {
2360 pPrev = pCur;
2361 pCur = pCur->pNext;
2362 }
2363 }
2364
2365 AssertRC(rc);
2366 return rc;
2367}
2368
2369
2370/**
2371 * Deregisters an at VM reset external callback.
2372 *
2373 * @returns VBox status code.
2374 * @param pVM The VM.
2375 * @param pfnCallback Callback function.
2376 */
2377VMMR3DECL(int) VMR3AtResetDeregisterExternal(PVM pVM, PFNVMATRESETEXT pfnCallback)
2378{
2379 int rc = VERR_VM_ATRESET_NOT_FOUND;
2380 PVMATRESET pPrev = NULL;
2381 PVMATRESET pCur = pVM->pUVM->vm.s.pAtReset;
2382 while (pCur)
2383 {
2384 if ( pCur->enmType == VMATRESETTYPE_INTERNAL
2385 && pCur->u.External.pfnCallback == pfnCallback)
2386 {
2387 pCur = vmr3AtResetFreeU(pVM->pUVM, pCur, pPrev);
2388 rc = VINF_SUCCESS;
2389 }
2390 else
2391 {
2392 pPrev = pCur;
2393 pCur = pCur->pNext;
2394 }
2395 }
2396
2397 AssertRC(rc);
2398 return rc;
2399}
2400
2401
2402/**
2403 * Gets the current VM state.
2404 *
2405 * @returns The current VM state.
2406 * @param pVM VM handle.
2407 * @thread Any
2408 */
2409VMMR3DECL(VMSTATE) VMR3GetState(PVM pVM)
2410{
2411 return pVM->enmVMState;
2412}
2413
2414
2415/**
2416 * Gets the state name string for a VM state.
2417 *
2418 * @returns Pointer to the state name. (readonly)
2419 * @param enmState The state.
2420 */
2421VMMR3DECL(const char *) VMR3GetStateName(VMSTATE enmState)
2422{
2423 switch (enmState)
2424 {
2425 case VMSTATE_CREATING: return "CREATING";
2426 case VMSTATE_CREATED: return "CREATED";
2427 case VMSTATE_RUNNING: return "RUNNING";
2428 case VMSTATE_LOADING: return "LOADING";
2429 case VMSTATE_LOAD_FAILURE: return "LOAD_FAILURE";
2430 case VMSTATE_SAVING: return "SAVING";
2431 case VMSTATE_SUSPENDED: return "SUSPENDED";
2432 case VMSTATE_RESETTING: return "RESETTING";
2433 case VMSTATE_GURU_MEDITATION: return "GURU_MEDITATION";
2434 case VMSTATE_OFF: return "OFF";
2435 case VMSTATE_DESTROYING: return "DESTROYING";
2436 case VMSTATE_TERMINATED: return "TERMINATED";
2437 default:
2438 AssertMsgFailed(("Unknown state %d\n", enmState));
2439 return "Unknown!\n";
2440 }
2441}
2442
2443
2444/**
2445 * Sets the current VM state.
2446 *
2447 * @returns The current VM state.
2448 * @param pVM VM handle.
2449 * @param enmStateNew The new state.
2450 */
2451void vmR3SetState(PVM pVM, VMSTATE enmStateNew)
2452{
2453 /*
2454 * Validate state machine transitions before doing the actual change.
2455 */
2456 VMSTATE enmStateOld = pVM->enmVMState;
2457 switch (enmStateOld)
2458 {
2459 case VMSTATE_OFF:
2460 Assert(enmStateNew != VMSTATE_GURU_MEDITATION);
2461 break;
2462
2463 default:
2464 /** @todo full validation. */
2465 break;
2466 }
2467
2468 pVM->enmVMState = enmStateNew;
2469 LogRel(("Changing the VM state from '%s' to '%s'.\n", VMR3GetStateName(enmStateOld), VMR3GetStateName(enmStateNew)));
2470
2471 /*
2472 * Call the at state change callbacks.
2473 */
2474 for (PVMATSTATE pCur = pVM->pUVM->vm.s.pAtState; pCur; pCur = pCur->pNext)
2475 {
2476 pCur->pfnAtState(pVM, enmStateNew, enmStateOld, pCur->pvUser);
2477 if (pVM->enmVMState == VMSTATE_DESTROYING)
2478 break;
2479 AssertMsg(pVM->enmVMState == enmStateNew,
2480 ("You are not allowed to change the state while in the change callback, except "
2481 "from destroying the VM. There are restrictions in the way the state changes "
2482 "are propagated up to the EM execution loop and it makes the program flow very "
2483 "difficult to follow.\n"));
2484 }
2485}
2486
2487
2488/**
2489 * Registers a VM state change callback.
2490 *
2491 * You are not allowed to call any function which changes the VM state from a
2492 * state callback, except VMR3Destroy().
2493 *
2494 * @returns VBox status code.
2495 * @param pVM VM handle.
2496 * @param pfnAtState Pointer to callback.
2497 * @param pvUser User argument.
2498 * @thread Any.
2499 */
2500VMMR3DECL(int) VMR3AtStateRegister(PVM pVM, PFNVMATSTATE pfnAtState, void *pvUser)
2501{
2502 LogFlow(("VMR3AtStateRegister: pfnAtState=%p pvUser=%p\n", pfnAtState, pvUser));
2503
2504 /*
2505 * Validate input.
2506 */
2507 if (!pfnAtState)
2508 {
2509 AssertMsgFailed(("callback is required\n"));
2510 return VERR_INVALID_PARAMETER;
2511 }
2512
2513 /*
2514 * Make sure we're in EMT (to avoid the logging).
2515 */
2516 PVMREQ pReq;
2517 int rc = VMR3ReqCall(pVM, VMREQDEST_ANY, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3AtStateRegisterU, 3, pVM->pUVM, pfnAtState, pvUser);
2518 if (RT_FAILURE(rc))
2519 return rc;
2520 rc = pReq->iStatus;
2521 VMR3ReqFree(pReq);
2522
2523 LogFlow(("VMR3AtStateRegister: returns %Rrc\n", rc));
2524 return rc;
2525}
2526
2527
2528/**
2529 * Registers a VM state change callback.
2530 *
2531 * @returns VBox status code.
2532 * @param pUVM Pointer to the user mode VM structure.
2533 * @param pfnAtState Pointer to callback.
2534 * @param pvUser User argument.
2535 * @thread EMT
2536 */
2537static DECLCALLBACK(int) vmR3AtStateRegisterU(PUVM pUVM, PFNVMATSTATE pfnAtState, void *pvUser)
2538{
2539 /*
2540 * Allocate a new record.
2541 */
2542
2543 PVMATSTATE pNew = (PVMATSTATE)MMR3HeapAllocU(pUVM, MM_TAG_VM, sizeof(*pNew));
2544 if (!pNew)
2545 return VERR_NO_MEMORY;
2546
2547 /* fill */
2548 pNew->pfnAtState = pfnAtState;
2549 pNew->pvUser = pvUser;
2550
2551 /* insert */
2552 pNew->pNext = *pUVM->vm.s.ppAtStateNext;
2553 *pUVM->vm.s.ppAtStateNext = pNew;
2554 pUVM->vm.s.ppAtStateNext = &pNew->pNext;
2555
2556 return VINF_SUCCESS;
2557}
2558
2559
2560/**
2561 * Deregisters a VM state change callback.
2562 *
2563 * @returns VBox status code.
2564 * @param pVM VM handle.
2565 * @param pfnAtState Pointer to callback.
2566 * @param pvUser User argument.
2567 * @thread Any.
2568 */
2569VMMR3DECL(int) VMR3AtStateDeregister(PVM pVM, PFNVMATSTATE pfnAtState, void *pvUser)
2570{
2571 LogFlow(("VMR3AtStateDeregister: pfnAtState=%p pvUser=%p\n", pfnAtState, pvUser));
2572
2573 /*
2574 * Validate input.
2575 */
2576 if (!pfnAtState)
2577 {
2578 AssertMsgFailed(("callback is required\n"));
2579 return VERR_INVALID_PARAMETER;
2580 }
2581
2582 /*
2583 * Make sure we're in EMT (to avoid the logging).
2584 */
2585 PVMREQ pReq;
2586 int rc = VMR3ReqCall(pVM, VMREQDEST_ANY, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3AtStateDeregisterU, 3, pVM->pUVM, pfnAtState, pvUser);
2587 if (RT_FAILURE(rc))
2588 return rc;
2589 rc = pReq->iStatus;
2590 VMR3ReqFree(pReq);
2591
2592 LogFlow(("VMR3AtStateDeregister: returns %Rrc\n", rc));
2593 return rc;
2594}
2595
2596
2597/**
2598 * Deregisters a VM state change callback.
2599 *
2600 * @returns VBox status code.
2601 * @param pUVM Pointer to the user mode VM structure.
2602 * @param pfnAtState Pointer to callback.
2603 * @param pvUser User argument.
2604 * @thread EMT
2605 */
2606static DECLCALLBACK(int) vmR3AtStateDeregisterU(PUVM pUVM, PFNVMATSTATE pfnAtState, void *pvUser)
2607{
2608 LogFlow(("vmR3AtStateDeregisterU: pfnAtState=%p pvUser=%p\n", pfnAtState, pvUser));
2609
2610 /*
2611 * Search the list for the entry.
2612 */
2613 PVMATSTATE pPrev = NULL;
2614 PVMATSTATE pCur = pUVM->vm.s.pAtState;
2615 while ( pCur
2616 && ( pCur->pfnAtState != pfnAtState
2617 || pCur->pvUser != pvUser))
2618 {
2619 pPrev = pCur;
2620 pCur = pCur->pNext;
2621 }
2622 if (!pCur)
2623 {
2624 AssertMsgFailed(("pfnAtState=%p was not found\n", pfnAtState));
2625 return VERR_FILE_NOT_FOUND;
2626 }
2627
2628 /*
2629 * Unlink it.
2630 */
2631 if (pPrev)
2632 {
2633 pPrev->pNext = pCur->pNext;
2634 if (!pCur->pNext)
2635 pUVM->vm.s.ppAtStateNext = &pPrev->pNext;
2636 }
2637 else
2638 {
2639 pUVM->vm.s.pAtState = pCur->pNext;
2640 if (!pCur->pNext)
2641 pUVM->vm.s.ppAtStateNext = &pUVM->vm.s.pAtState;
2642 }
2643
2644 /*
2645 * Free it.
2646 */
2647 pCur->pfnAtState = NULL;
2648 pCur->pNext = NULL;
2649 MMR3HeapFree(pCur);
2650
2651 return VINF_SUCCESS;
2652}
2653
2654
2655/**
2656 * Registers a VM error callback.
2657 *
2658 * @returns VBox status code.
2659 * @param pVM The VM handle.
2660 * @param pfnAtError Pointer to callback.
2661 * @param pvUser User argument.
2662 * @thread Any.
2663 */
2664VMMR3DECL(int) VMR3AtErrorRegister(PVM pVM, PFNVMATERROR pfnAtError, void *pvUser)
2665{
2666 return VMR3AtErrorRegisterU(pVM->pUVM, pfnAtError, pvUser);
2667}
2668
2669
2670/**
2671 * Registers a VM error callback.
2672 *
2673 * @returns VBox status code.
2674 * @param pUVM The VM handle.
2675 * @param pfnAtError Pointer to callback.
2676 * @param pvUser User argument.
2677 * @thread Any.
2678 */
2679VMMR3DECL(int) VMR3AtErrorRegisterU(PUVM pUVM, PFNVMATERROR pfnAtError, void *pvUser)
2680{
2681 LogFlow(("VMR3AtErrorRegister: pfnAtError=%p pvUser=%p\n", pfnAtError, pvUser));
2682 AssertPtrReturn(pfnAtError, VERR_INVALID_PARAMETER);
2683
2684 /*
2685 * Make sure we're in EMT (to avoid the logging).
2686 */
2687 PVMREQ pReq;
2688 int rc = VMR3ReqCallU(pUVM, VMREQDEST_ANY, &pReq, RT_INDEFINITE_WAIT, 0, (PFNRT)vmR3AtErrorRegisterU, 3, pUVM, pfnAtError, pvUser);
2689 if (RT_FAILURE(rc))
2690 return rc;
2691 rc = pReq->iStatus;
2692 VMR3ReqFree(pReq);
2693
2694 LogFlow(("VMR3AtErrorRegister: returns %Rrc\n", rc));
2695 return rc;
2696}
2697
2698
2699/**
2700 * Registers a VM error callback.
2701 *
2702 * @returns VBox status code.
2703 * @param pUVM Pointer to the user mode VM structure.
2704 * @param pfnAtError Pointer to callback.
2705 * @param pvUser User argument.
2706 * @thread EMT
2707 */
2708static DECLCALLBACK(int) vmR3AtErrorRegisterU(PUVM pUVM, PFNVMATERROR pfnAtError, void *pvUser)
2709{
2710 /*
2711 * Allocate a new record.
2712 */
2713
2714 PVMATERROR pNew = (PVMATERROR)MMR3HeapAllocU(pUVM, MM_TAG_VM, sizeof(*pNew));
2715 if (!pNew)
2716 return VERR_NO_MEMORY;
2717
2718 /* fill */
2719 pNew->pfnAtError = pfnAtError;
2720 pNew->pvUser = pvUser;
2721
2722 /* insert */
2723 pNew->pNext = *pUVM->vm.s.ppAtErrorNext;
2724 *pUVM->vm.s.ppAtErrorNext = pNew;
2725 pUVM->vm.s.ppAtErrorNext = &pNew->pNext;
2726
2727 return VINF_SUCCESS;
2728}
2729
2730
2731/**
2732 * Deregisters a VM error callback.
2733 *
2734 * @returns VBox status code.
2735 * @param pVM The VM handle.
2736 * @param pfnAtError Pointer to callback.
2737 * @param pvUser User argument.
2738 * @thread Any.
2739 */
2740VMMR3DECL(int) VMR3AtErrorDeregister(PVM pVM, PFNVMATERROR pfnAtError, void *pvUser)
2741{
2742 LogFlow(("VMR3AtErrorDeregister: pfnAtError=%p pvUser=%p\n", pfnAtError, pvUser));
2743
2744 /*
2745 * Validate input.
2746 */
2747 if (!pfnAtError)
2748 {
2749 AssertMsgFailed(("callback is required\n"));
2750 return VERR_INVALID_PARAMETER;
2751 }
2752
2753 /*
2754 * Make sure we're in EMT (to avoid the logging).
2755 */
2756 PVMREQ pReq;
2757 int rc = VMR3ReqCall(pVM, VMREQDEST_ANY, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3AtErrorDeregisterU, 3, pVM->pUVM, pfnAtError, pvUser);
2758 if (RT_FAILURE(rc))
2759 return rc;
2760 rc = pReq->iStatus;
2761 VMR3ReqFree(pReq);
2762
2763 LogFlow(("VMR3AtErrorDeregister: returns %Rrc\n", rc));
2764 return rc;
2765}
2766
2767
2768/**
2769 * Deregisters a VM error callback.
2770 *
2771 * @returns VBox status code.
2772 * @param pUVM Pointer to the user mode VM structure.
2773 * @param pfnAtError Pointer to callback.
2774 * @param pvUser User argument.
2775 * @thread EMT
2776 */
2777static DECLCALLBACK(int) vmR3AtErrorDeregisterU(PUVM pUVM, PFNVMATERROR pfnAtError, void *pvUser)
2778{
2779 LogFlow(("vmR3AtErrorDeregisterU: pfnAtError=%p pvUser=%p\n", pfnAtError, pvUser));
2780
2781 /*
2782 * Search the list for the entry.
2783 */
2784 PVMATERROR pPrev = NULL;
2785 PVMATERROR pCur = pUVM->vm.s.pAtError;
2786 while ( pCur
2787 && ( pCur->pfnAtError != pfnAtError
2788 || pCur->pvUser != pvUser))
2789 {
2790 pPrev = pCur;
2791 pCur = pCur->pNext;
2792 }
2793 if (!pCur)
2794 {
2795 AssertMsgFailed(("pfnAtError=%p was not found\n", pfnAtError));
2796 return VERR_FILE_NOT_FOUND;
2797 }
2798
2799 /*
2800 * Unlink it.
2801 */
2802 if (pPrev)
2803 {
2804 pPrev->pNext = pCur->pNext;
2805 if (!pCur->pNext)
2806 pUVM->vm.s.ppAtErrorNext = &pPrev->pNext;
2807 }
2808 else
2809 {
2810 pUVM->vm.s.pAtError = pCur->pNext;
2811 if (!pCur->pNext)
2812 pUVM->vm.s.ppAtErrorNext = &pUVM->vm.s.pAtError;
2813 }
2814
2815 /*
2816 * Free it.
2817 */
2818 pCur->pfnAtError = NULL;
2819 pCur->pNext = NULL;
2820 MMR3HeapFree(pCur);
2821
2822 return VINF_SUCCESS;
2823}
2824
2825
2826/**
2827 * Ellipsis to va_list wrapper for calling pfnAtError.
2828 */
2829static void vmR3SetErrorWorkerDoCall(PVM pVM, PVMATERROR pCur, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...)
2830{
2831 va_list va;
2832 va_start(va, pszFormat);
2833 pCur->pfnAtError(pVM, pCur->pvUser, rc, RT_SRC_POS_ARGS, pszFormat, va);
2834 va_end(va);
2835}
2836
2837
2838/**
2839 * This is a worker function for GC and Ring-0 calls to VMSetError and VMSetErrorV.
2840 * The message is found in VMINT.
2841 *
2842 * @param pVM The VM handle.
2843 * @thread EMT.
2844 */
2845VMMR3DECL(void) VMR3SetErrorWorker(PVM pVM)
2846{
2847 VM_ASSERT_EMT(pVM);
2848 AssertReleaseMsgFailed(("And we have a winner! You get to implement Ring-0 and GC VMSetErrorV! Contrats!\n"));
2849
2850 /*
2851 * Unpack the error (if we managed to format one).
2852 */
2853 PVMERROR pErr = pVM->vm.s.pErrorR3;
2854 const char *pszFile = NULL;
2855 const char *pszFunction = NULL;
2856 uint32_t iLine = 0;
2857 const char *pszMessage;
2858 int32_t rc = VERR_MM_HYPER_NO_MEMORY;
2859 if (pErr)
2860 {
2861 AssertCompile(sizeof(const char) == sizeof(uint8_t));
2862 if (pErr->offFile)
2863 pszFile = (const char *)pErr + pErr->offFile;
2864 iLine = pErr->iLine;
2865 if (pErr->offFunction)
2866 pszFunction = (const char *)pErr + pErr->offFunction;
2867 if (pErr->offMessage)
2868 pszMessage = (const char *)pErr + pErr->offMessage;
2869 else
2870 pszMessage = "No message!";
2871 }
2872 else
2873 pszMessage = "No message! (Failed to allocate memory to put the error message in!)";
2874
2875 /*
2876 * Call the at error callbacks.
2877 */
2878 for (PVMATERROR pCur = pVM->pUVM->vm.s.pAtError; pCur; pCur = pCur->pNext)
2879 vmR3SetErrorWorkerDoCall(pVM, pCur, rc, RT_SRC_POS_ARGS, "%s", pszMessage);
2880}
2881
2882
2883/**
2884 * Creation time wrapper for vmR3SetErrorUV.
2885 *
2886 * @returns rc.
2887 * @param pUVM Pointer to the user mode VM structure.
2888 * @param rc The VBox status code.
2889 * @param RT_SRC_POS_DECL The source position of this error.
2890 * @param pszFormat Format string.
2891 * @param ... The arguments.
2892 * @thread Any thread.
2893 */
2894static int vmR3SetErrorU(PUVM pUVM, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...)
2895{
2896 va_list va;
2897 va_start(va, pszFormat);
2898 vmR3SetErrorUV(pUVM, rc, pszFile, iLine, pszFunction, pszFormat, &va);
2899 va_end(va);
2900 return rc;
2901}
2902
2903
2904/**
2905 * Worker which calls everyone listening to the VM error messages.
2906 *
2907 * @param pUVM Pointer to the user mode VM structure.
2908 * @param rc The VBox status code.
2909 * @param RT_SRC_POS_DECL The source position of this error.
2910 * @param pszFormat Format string.
2911 * @param pArgs Pointer to the format arguments.
2912 * @thread EMT
2913 */
2914DECLCALLBACK(void) vmR3SetErrorUV(PUVM pUVM, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list *pArgs)
2915{
2916#ifdef LOG_ENABLED
2917 /*
2918 * Log the error.
2919 */
2920 RTLogPrintf("VMSetError: %s(%d) %s\n", pszFile, iLine, pszFunction);
2921 va_list va3;
2922 va_copy(va3, *pArgs);
2923 RTLogPrintfV(pszFormat, va3);
2924 va_end(va3);
2925 RTLogPrintf("\n");
2926#endif
2927
2928 /*
2929 * Make a copy of the message.
2930 */
2931 if (pUVM->pVM)
2932 vmSetErrorCopy(pUVM->pVM, rc, RT_SRC_POS_ARGS, pszFormat, *pArgs);
2933
2934 /*
2935 * Call the at error callbacks.
2936 */
2937 for (PVMATERROR pCur = pUVM->vm.s.pAtError; pCur; pCur = pCur->pNext)
2938 {
2939 va_list va2;
2940 va_copy(va2, *pArgs);
2941 pCur->pfnAtError(pUVM->pVM, pCur->pvUser, rc, RT_SRC_POS_ARGS, pszFormat, va2);
2942 va_end(va2);
2943 }
2944}
2945
2946
2947/**
2948 * Registers a VM runtime error callback.
2949 *
2950 * @returns VBox status code.
2951 * @param pVM The VM handle.
2952 * @param pfnAtRuntimeError Pointer to callback.
2953 * @param pvUser User argument.
2954 * @thread Any.
2955 */
2956VMMR3DECL(int) VMR3AtRuntimeErrorRegister(PVM pVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser)
2957{
2958 LogFlow(("VMR3AtRuntimeErrorRegister: pfnAtRuntimeError=%p pvUser=%p\n", pfnAtRuntimeError, pvUser));
2959
2960 /*
2961 * Validate input.
2962 */
2963 if (!pfnAtRuntimeError)
2964 {
2965 AssertMsgFailed(("callback is required\n"));
2966 return VERR_INVALID_PARAMETER;
2967 }
2968
2969 /*
2970 * Make sure we're in EMT (to avoid the logging).
2971 */
2972 PVMREQ pReq;
2973 int rc = VMR3ReqCall(pVM, VMREQDEST_ANY, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3AtRuntimeErrorRegisterU, 3, pVM->pUVM, pfnAtRuntimeError, pvUser);
2974 if (RT_FAILURE(rc))
2975 return rc;
2976 rc = pReq->iStatus;
2977 VMR3ReqFree(pReq);
2978
2979 LogFlow(("VMR3AtRuntimeErrorRegister: returns %Rrc\n", rc));
2980 return rc;
2981}
2982
2983
2984/**
2985 * Registers a VM runtime error callback.
2986 *
2987 * @returns VBox status code.
2988 * @param pUVM Pointer to the user mode VM structure.
2989 * @param pfnAtRuntimeError Pointer to callback.
2990 * @param pvUser User argument.
2991 * @thread EMT
2992 */
2993static DECLCALLBACK(int) vmR3AtRuntimeErrorRegisterU(PUVM pUVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser)
2994{
2995 /*
2996 * Allocate a new record.
2997 */
2998
2999 PVMATRUNTIMEERROR pNew = (PVMATRUNTIMEERROR)MMR3HeapAllocU(pUVM, MM_TAG_VM, sizeof(*pNew));
3000 if (!pNew)
3001 return VERR_NO_MEMORY;
3002
3003 /* fill */
3004 pNew->pfnAtRuntimeError = pfnAtRuntimeError;
3005 pNew->pvUser = pvUser;
3006
3007 /* insert */
3008 pNew->pNext = *pUVM->vm.s.ppAtRuntimeErrorNext;
3009 *pUVM->vm.s.ppAtRuntimeErrorNext = pNew;
3010 pUVM->vm.s.ppAtRuntimeErrorNext = &pNew->pNext;
3011
3012 return VINF_SUCCESS;
3013}
3014
3015
3016/**
3017 * Deregisters a VM runtime error callback.
3018 *
3019 * @returns VBox status code.
3020 * @param pVM The VM handle.
3021 * @param pfnAtRuntimeError Pointer to callback.
3022 * @param pvUser User argument.
3023 * @thread Any.
3024 */
3025VMMR3DECL(int) VMR3AtRuntimeErrorDeregister(PVM pVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser)
3026{
3027 LogFlow(("VMR3AtRuntimeErrorDeregister: pfnAtRuntimeError=%p pvUser=%p\n", pfnAtRuntimeError, pvUser));
3028
3029 /*
3030 * Validate input.
3031 */
3032 if (!pfnAtRuntimeError)
3033 {
3034 AssertMsgFailed(("callback is required\n"));
3035 return VERR_INVALID_PARAMETER;
3036 }
3037
3038 /*
3039 * Make sure we're in EMT (to avoid the logging).
3040 */
3041 PVMREQ pReq;
3042 int rc = VMR3ReqCall(pVM, VMREQDEST_ANY, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3AtRuntimeErrorDeregisterU, 3, pVM->pUVM, pfnAtRuntimeError, pvUser);
3043 if (RT_FAILURE(rc))
3044 return rc;
3045 rc = pReq->iStatus;
3046 VMR3ReqFree(pReq);
3047
3048 LogFlow(("VMR3AtRuntimeErrorDeregister: returns %Rrc\n", rc));
3049 return rc;
3050}
3051
3052
3053/**
3054 * Deregisters a VM runtime error callback.
3055 *
3056 * @returns VBox status code.
3057 * @param pUVM Pointer to the user mode VM structure.
3058 * @param pfnAtRuntimeError Pointer to callback.
3059 * @param pvUser User argument.
3060 * @thread EMT
3061 */
3062static DECLCALLBACK(int) vmR3AtRuntimeErrorDeregisterU(PUVM pUVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser)
3063{
3064 LogFlow(("vmR3AtRuntimeErrorDeregisterU: pfnAtRuntimeError=%p pvUser=%p\n", pfnAtRuntimeError, pvUser));
3065
3066 /*
3067 * Search the list for the entry.
3068 */
3069 PVMATRUNTIMEERROR pPrev = NULL;
3070 PVMATRUNTIMEERROR pCur = pUVM->vm.s.pAtRuntimeError;
3071 while ( pCur
3072 && ( pCur->pfnAtRuntimeError != pfnAtRuntimeError
3073 || pCur->pvUser != pvUser))
3074 {
3075 pPrev = pCur;
3076 pCur = pCur->pNext;
3077 }
3078 if (!pCur)
3079 {
3080 AssertMsgFailed(("pfnAtRuntimeError=%p was not found\n", pfnAtRuntimeError));
3081 return VERR_FILE_NOT_FOUND;
3082 }
3083
3084 /*
3085 * Unlink it.
3086 */
3087 if (pPrev)
3088 {
3089 pPrev->pNext = pCur->pNext;
3090 if (!pCur->pNext)
3091 pUVM->vm.s.ppAtRuntimeErrorNext = &pPrev->pNext;
3092 }
3093 else
3094 {
3095 pUVM->vm.s.pAtRuntimeError = pCur->pNext;
3096 if (!pCur->pNext)
3097 pUVM->vm.s.ppAtRuntimeErrorNext = &pUVM->vm.s.pAtRuntimeError;
3098 }
3099
3100 /*
3101 * Free it.
3102 */
3103 pCur->pfnAtRuntimeError = NULL;
3104 pCur->pNext = NULL;
3105 MMR3HeapFree(pCur);
3106
3107 return VINF_SUCCESS;
3108}
3109
3110
3111/**
3112 * Worker for VMR3SetRuntimeErrorWorker and vmR3SetRuntimeErrorV.
3113 *
3114 * This does the common parts after the error has been saved / retrieved.
3115 *
3116 * @returns VBox status code with modifications, see VMSetRuntimeErrorV.
3117 *
3118 * @param pVM The VM handle.
3119 * @param fFlags The error flags.
3120 * @param pszErrorId Error ID string.
3121 * @param pszFormat Format string.
3122 * @param pVa Pointer to the format arguments.
3123 */
3124static int vmR3SetRuntimeErrorCommon(PVM pVM, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, va_list *pVa)
3125{
3126 LogRel(("VM: Raising runtime error '%s' (fFlags=%#x)\n", pszErrorId, fFlags));
3127
3128 /*
3129 * Take actions before the call.
3130 */
3131 int rc = VINF_SUCCESS;
3132 if (fFlags & VMSETRTERR_FLAGS_FATAL)
3133 /** @todo Add some special VM state for the FATAL variant that isn't resumable.
3134 * It's too risky for 2.2.0, do after branching. */
3135 rc = VMR3SuspendNoSave(pVM);
3136 else if (fFlags & VMSETRTERR_FLAGS_SUSPEND)
3137 rc = VMR3Suspend(pVM);
3138
3139 /*
3140 * Do the callback round.
3141 */
3142 for (PVMATRUNTIMEERROR pCur = pVM->pUVM->vm.s.pAtRuntimeError; pCur; pCur = pCur->pNext)
3143 {
3144 va_list va;
3145 va_copy(va, *pVa);
3146 pCur->pfnAtRuntimeError(pVM, pCur->pvUser, fFlags, pszErrorId, pszFormat, va);
3147 va_end(va);
3148 }
3149
3150 return rc;
3151}
3152
3153
3154/**
3155 * Ellipsis to va_list wrapper for calling vmR3SetRuntimeErrorCommon.
3156 */
3157static int vmR3SetRuntimeErrorCommonF(PVM pVM, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...)
3158{
3159 va_list va;
3160 va_start(va, pszFormat);
3161 int rc = vmR3SetRuntimeErrorCommon(pVM, fFlags, pszErrorId, pszFormat, &va);
3162 va_end(va);
3163 return rc;
3164}
3165
3166
3167/**
3168 * This is a worker function for RC and Ring-0 calls to VMSetError and
3169 * VMSetErrorV.
3170 *
3171 * The message is found in VMINT.
3172 *
3173 * @returns VBox status code, see VMSetRuntimeError.
3174 * @param pVM The VM handle.
3175 * @thread EMT.
3176 */
3177VMMR3DECL(int) VMR3SetRuntimeErrorWorker(PVM pVM)
3178{
3179 VM_ASSERT_EMT(pVM);
3180 AssertReleaseMsgFailed(("And we have a winner! You get to implement Ring-0 and GC VMSetRuntimeErrorV! Congrats!\n"));
3181
3182 /*
3183 * Unpack the error (if we managed to format one).
3184 */
3185 const char *pszErrorId = "SetRuntimeError";
3186 const char *pszMessage = "No message!";
3187 uint32_t fFlags = VMSETRTERR_FLAGS_FATAL;
3188 PVMRUNTIMEERROR pErr = pVM->vm.s.pRuntimeErrorR3;
3189 if (pErr)
3190 {
3191 AssertCompile(sizeof(const char) == sizeof(uint8_t));
3192 if (pErr->offErrorId)
3193 pszErrorId = (const char *)pErr + pErr->offErrorId;
3194 if (pErr->offMessage)
3195 pszMessage = (const char *)pErr + pErr->offMessage;
3196 fFlags = pErr->fFlags;
3197 }
3198
3199 /*
3200 * Join cause with vmR3SetRuntimeErrorV.
3201 */
3202 return vmR3SetRuntimeErrorCommonF(pVM, fFlags, pszErrorId, "%s", pszMessage);
3203}
3204
3205
3206/**
3207 * Worker for VMSetRuntimeErrorV for doing the job on EMT in ring-3.
3208 *
3209 * @returns VBox status code with modifications, see VMSetRuntimeErrorV.
3210 *
3211 * @param pVM The VM handle.
3212 * @param fFlags The error flags.
3213 * @param pszErrorId Error ID string.
3214 * @param pszFormat Format string.
3215 * @param pVa Pointer to the format arguments.
3216 *
3217 * @thread EMT
3218 */
3219DECLCALLBACK(int) vmR3SetRuntimeErrorV(PVM pVM, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, va_list *pVa)
3220{
3221 /*
3222 * Make a copy of the message.
3223 */
3224 va_list va2;
3225 va_copy(va2, *pVa);
3226 vmSetRuntimeErrorCopy(pVM, fFlags, pszErrorId, pszFormat, va2);
3227 va_end(va2);
3228
3229 /*
3230 * Join paths with VMR3SetRuntimeErrorWorker.
3231 */
3232 return vmR3SetRuntimeErrorCommon(pVM, fFlags, pszErrorId, pszFormat, pVa);
3233}
3234
3235
3236/**
3237 * Returns the VMCPU id of the current EMT thread.
3238 *
3239 * @param pVM The VM handle.
3240 * @thread EMT
3241 */
3242VMMR3DECL(RTCPUID) VMR3GetVMCPUId(PVM pVM)
3243{
3244 PUVMCPU pUVMCPU = (PUVMCPU)RTTlsGet(pVM->pUVM->vm.s.idxTLS);
3245
3246 AssertMsg(pUVMCPU, ("RTTlsGet %d failed!\n", pVM->pUVM->vm.s.idxTLS));
3247 return pUVMCPU->idCpu;
3248}
3249
3250
3251/**
3252 * Returns the native handle of the current EMT VMCPU thread.
3253 *
3254 * @returns Handle if this is an EMT thread; NIL_RTNATIVETHREAD otherwise
3255 * @param pVM The VM handle.
3256 * @thread EMT
3257 */
3258VMMR3DECL(RTNATIVETHREAD) VMR3GetVMCPUNativeThread(PVM pVM)
3259{
3260 PUVMCPU pUVMCPU = (PUVMCPU)RTTlsGet(pVM->pUVM->vm.s.idxTLS);
3261
3262 if (!pUVMCPU)
3263 return NIL_RTNATIVETHREAD;
3264
3265 return pUVMCPU->vm.s.NativeThreadEMT;
3266}
3267
3268
3269/**
3270 * Returns the native handle of the current EMT VMCPU thread.
3271 *
3272 * @returns Handle if this is an EMT thread; NIL_RTNATIVETHREAD otherwise
3273 * @param pVM The VM handle.
3274 * @thread EMT
3275 */
3276VMMR3DECL(RTNATIVETHREAD) VMR3GetVMCPUNativeThreadU(PUVM pUVM)
3277{
3278 PUVMCPU pUVMCPU = (PUVMCPU)RTTlsGet(pUVM->vm.s.idxTLS);
3279
3280 if (!pUVMCPU)
3281 return NIL_RTNATIVETHREAD;
3282
3283 return pUVMCPU->vm.s.NativeThreadEMT;
3284}
3285
3286
3287/**
3288 * Returns the handle of the current EMT VMCPU thread.
3289 *
3290 * @returns Handle if this is an EMT thread; NIL_RTNATIVETHREAD otherwise
3291 * @param pVM The VM handle.
3292 * @thread EMT
3293 */
3294VMMR3DECL(RTTHREAD) VMR3GetVMCPUThread(PVM pVM)
3295{
3296 PUVMCPU pUVMCPU = (PUVMCPU)RTTlsGet(pVM->pUVM->vm.s.idxTLS);
3297
3298 if (!pUVMCPU)
3299 return NIL_RTTHREAD;
3300
3301 return pUVMCPU->vm.s.ThreadEMT;
3302}
3303
3304
3305/**
3306 * Returns the handle of the current EMT VMCPU thread.
3307 *
3308 * @returns Handle if this is an EMT thread; NIL_RTNATIVETHREAD otherwise
3309 * @param pVM The VM handle.
3310 * @thread EMT
3311 */
3312VMMR3DECL(RTTHREAD) VMR3GetVMCPUThreadU(PUVM pUVM)
3313{
3314 PUVMCPU pUVMCPU = (PUVMCPU)RTTlsGet(pUVM->vm.s.idxTLS);
3315
3316 if (!pUVMCPU)
3317 return NIL_RTTHREAD;
3318
3319 return pUVMCPU->vm.s.ThreadEMT;
3320}
3321
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette