VirtualBox

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

Last change on this file since 7471 was 7471, checked in by vboxsync, 17 years ago

Rewrote VT-x & AMD-V mode changes. Requires the MP apis in our runtime to function properly. (only tested Windows)

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