VirtualBox

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

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

Fixed init order assertion in TMR3Init/PDM.

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