VirtualBox

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

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

More SMP groundwork.

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