VirtualBox

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

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

todo comment.

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