VirtualBox

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

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

Initialize the halt method correctly. We cannot use the default in case init fails since ring-0 might not be initialized correctly at the time of failure.

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