VirtualBox

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

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

Added the NoDmik() macro.

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