VirtualBox

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

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

VMM: don't overwrite errors

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 85.8 KB
Line 
1/* $Id: VM.cpp 6347 2008-01-11 20:17:34Z 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 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 AssertMsgFailed(("Add error message for rc=%d (%Vrc)\n", rc, rc));
275 }
276 if (pszError && !pVM->vm.s.fErrorSet)
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 STAMR3Dump(pVM, "*");
1448#else
1449 LogRel(("************************* Statistics *************************\n"));
1450 STAMR3DumpToReleaseLog(pVM, "*");
1451 LogRel(("********************* End of statistics **********************\n"));
1452#endif
1453
1454 /*
1455 * Destroy the VM components.
1456 */
1457 int rc = TMR3Term(pVM);
1458 AssertRC(rc);
1459#ifdef VBOX_WITH_DEBUGGER
1460 rc = DBGCTcpTerminate(pVM, pVM->vm.s.pvDBGC);
1461 pVM->vm.s.pvDBGC = NULL;
1462#endif
1463 AssertRC(rc);
1464 rc = DBGFR3Term(pVM);
1465 AssertRC(rc);
1466 rc = PDMR3Term(pVM);
1467 AssertRC(rc);
1468 rc = EMR3Term(pVM);
1469 AssertRC(rc);
1470 rc = IOMR3Term(pVM);
1471 AssertRC(rc);
1472 rc = CSAMR3Term(pVM);
1473 AssertRC(rc);
1474 rc = PATMR3Term(pVM);
1475 AssertRC(rc);
1476 rc = TRPMR3Term(pVM);
1477 AssertRC(rc);
1478 rc = SELMR3Term(pVM);
1479 AssertRC(rc);
1480 rc = REMR3Term(pVM);
1481 AssertRC(rc);
1482 rc = HWACCMR3Term(pVM);
1483 AssertRC(rc);
1484 rc = PGMR3Term(pVM);
1485 AssertRC(rc);
1486 rc = VMMR3Term(pVM); /* Terminates the ring-0 code! */
1487 AssertRC(rc);
1488 rc = CPUMR3Term(pVM);
1489 AssertRC(rc);
1490 rc = STAMR3Term(pVM);
1491 AssertRC(rc);
1492 rc = PDMR3CritSectTerm(pVM);
1493 AssertRC(rc);
1494 /* MM is destroyed later in vmR3DestroyFinalBit() for heap reasons. */
1495
1496 /*
1497 * We're done in this thread.
1498 */
1499 pVM->fForcedActions = VM_FF_TERMINATE;
1500 LogFlow(("vmR3Destroy: returning %Vrc\n", VINF_EM_TERMINATE));
1501 return VINF_EM_TERMINATE;
1502}
1503
1504
1505/**
1506 * Does the final part of the VM destruction.
1507 * This is called by EMT in it's final stage or by the VMR3Destroy caller.
1508 *
1509 * @param pVM VM Handle.
1510 */
1511void vmR3DestroyFinalBit(PVM pVM)
1512{
1513 /*
1514 * Free the event semaphores associated with the request packets.
1515 */
1516 unsigned cReqs = 0;
1517 for (unsigned i = 0; i < ELEMENTS(pVM->vm.s.apReqFree); i++)
1518 {
1519 PVMREQ pReq = pVM->vm.s.apReqFree[i];
1520 pVM->vm.s.apReqFree[i] = NULL;
1521 for (; pReq; pReq = pReq->pNext, cReqs++)
1522 {
1523 pReq->enmState = VMREQSTATE_INVALID;
1524 RTSemEventDestroy(pReq->EventSem);
1525 }
1526 }
1527 Assert(cReqs == pVM->vm.s.cReqFree); NOREF(cReqs);
1528
1529 /*
1530 * Kill all queued requests. (There really shouldn't be any!)
1531 */
1532 for (unsigned i = 0; i < 10; i++)
1533 {
1534 PVMREQ pReqHead = (PVMREQ)ASMAtomicXchgPtr((void *volatile *)&pVM->vm.s.pReqs, NULL);
1535 AssertMsg(!pReqHead, ("This isn't supposed to happen! VMR3Destroy caller has to serialize this.\n"));
1536 if (!pReqHead)
1537 break;
1538 for (PVMREQ pReq = pReqHead; pReq; pReq = pReq->pNext)
1539 {
1540 ASMAtomicXchgSize(&pReq->iStatus, VERR_INTERNAL_ERROR);
1541 ASMAtomicXchgSize(&pReq->enmState, VMREQSTATE_INVALID);
1542 RTSemEventSignal(pReq->EventSem);
1543 RTThreadSleep(2);
1544 RTSemEventDestroy(pReq->EventSem);
1545 }
1546 /* give them a chance to respond before we free the request memory. */
1547 RTThreadSleep(32);
1548 }
1549
1550 /*
1551 * Modify state and then terminate MM.
1552 * (MM must be delayed until this point so we don't destroy the callbacks and the request packet.)
1553 */
1554 vmR3SetState(pVM, VMSTATE_TERMINATED);
1555 int rc = MMR3Term(pVM);
1556 AssertRC(rc);
1557
1558 /*
1559 * Tell GVMM that it can destroy the VM now.
1560 */
1561 rc = SUPCallVMMR0Ex(pVM->pVMR0, VMMR0_DO_GVMM_DESTROY_VM, 0, NULL);
1562 AssertRC(rc);
1563 rc = SUPTerm();
1564 AssertRC(rc);
1565
1566 RTLogFlush(NULL);
1567}
1568
1569
1570/**
1571 * Enumerates the VMs in this process.
1572 *
1573 * @returns Pointer to the next VM.
1574 * @returns NULL when no more VMs.
1575 * @param pVMPrev The previous VM
1576 * Use NULL to start the enumeration.
1577 */
1578VMR3DECL(PVM) VMR3EnumVMs(PVM pVMPrev)
1579{
1580 /*
1581 * This is quick and dirty. It has issues with VM being
1582 * destroyed during the enumeration.
1583 */
1584 if (pVMPrev)
1585 return pVMPrev->pNext;
1586 return g_pVMsHead;
1587}
1588
1589
1590/**
1591 * Registers an at VM destruction callback.
1592 *
1593 * @returns VBox status code.
1594 * @param pfnAtDtor Pointer to callback.
1595 * @param pvUser User argument.
1596 */
1597VMR3DECL(int) VMR3AtDtorRegister(PFNVMATDTOR pfnAtDtor, void *pvUser)
1598{
1599 /*
1600 * Check if already registered.
1601 */
1602 VM_ATDTOR_LOCK();
1603 PVMATDTOR pCur = g_pVMAtDtorHead;
1604 while (pCur)
1605 {
1606 if (pfnAtDtor == pCur->pfnAtDtor)
1607 {
1608 VM_ATDTOR_UNLOCK();
1609 AssertMsgFailed(("Already registered at destruction callback %p!\n", pfnAtDtor));
1610 return VERR_INVALID_PARAMETER;
1611 }
1612
1613 /* next */
1614 pCur = pCur->pNext;
1615 }
1616 VM_ATDTOR_UNLOCK();
1617
1618 /*
1619 * Allocate new entry.
1620 */
1621 PVMATDTOR pVMAtDtor = (PVMATDTOR)RTMemAlloc(sizeof(*pVMAtDtor));
1622 if (!pVMAtDtor)
1623 return VERR_NO_MEMORY;
1624
1625 VM_ATDTOR_LOCK();
1626 pVMAtDtor->pfnAtDtor = pfnAtDtor;
1627 pVMAtDtor->pvUser = pvUser;
1628 pVMAtDtor->pNext = g_pVMAtDtorHead;
1629 g_pVMAtDtorHead = pVMAtDtor;
1630 VM_ATDTOR_UNLOCK();
1631
1632 return VINF_SUCCESS;
1633}
1634
1635
1636/**
1637 * Deregisters an at VM destruction callback.
1638 *
1639 * @returns VBox status code.
1640 * @param pfnAtDtor Pointer to callback.
1641 */
1642VMR3DECL(int) VMR3AtDtorDeregister(PFNVMATDTOR pfnAtDtor)
1643{
1644 /*
1645 * Find it, unlink it and free it.
1646 */
1647 VM_ATDTOR_LOCK();
1648 PVMATDTOR pPrev = NULL;
1649 PVMATDTOR pCur = g_pVMAtDtorHead;
1650 while (pCur)
1651 {
1652 if (pfnAtDtor == pCur->pfnAtDtor)
1653 {
1654 if (pPrev)
1655 pPrev->pNext = pCur->pNext;
1656 else
1657 g_pVMAtDtorHead = pCur->pNext;
1658 pCur->pNext = NULL;
1659 VM_ATDTOR_UNLOCK();
1660
1661 RTMemFree(pCur);
1662 return VINF_SUCCESS;
1663 }
1664
1665 /* next */
1666 pPrev = pCur;
1667 pCur = pCur->pNext;
1668 }
1669 VM_ATDTOR_UNLOCK();
1670
1671 return VERR_INVALID_PARAMETER;
1672}
1673
1674
1675/**
1676 * Walks the list of at VM destructor callbacks.
1677 * @param pVM The VM which is about to be destroyed.
1678 */
1679static void vmR3AtDtor(PVM pVM)
1680{
1681 /*
1682 * Find it, unlink it and free it.
1683 */
1684 VM_ATDTOR_LOCK();
1685 for (PVMATDTOR pCur = g_pVMAtDtorHead; pCur; pCur = pCur->pNext)
1686 pCur->pfnAtDtor(pVM, pCur->pvUser);
1687 VM_ATDTOR_UNLOCK();
1688}
1689
1690
1691/**
1692 * Reset the current VM.
1693 *
1694 * @returns VBox status code.
1695 * @param pVM VM to reset.
1696 */
1697VMR3DECL(int) VMR3Reset(PVM pVM)
1698{
1699 int rc = VINF_SUCCESS;
1700
1701 /*
1702 * Check the state.
1703 */
1704 if (!pVM)
1705 return VERR_INVALID_PARAMETER;
1706 if ( pVM->enmVMState != VMSTATE_RUNNING
1707 && pVM->enmVMState != VMSTATE_SUSPENDED)
1708 {
1709 AssertMsgFailed(("Invalid VM state %d\n", pVM->enmVMState));
1710 return VERR_VM_INVALID_VM_STATE;
1711 }
1712
1713 /*
1714 * Queue reset request to the emulation thread
1715 * and wait for it to be processed.
1716 */
1717 PVMREQ pReq = NULL;
1718 rc = VMR3ReqCall(pVM, &pReq, 0, (PFNRT)vmR3Reset, 1, pVM);
1719 while (rc == VERR_TIMEOUT)
1720 rc = VMR3ReqWait(pReq, RT_INDEFINITE_WAIT);
1721 if (VBOX_SUCCESS(rc))
1722 rc = pReq->iStatus;
1723 VMR3ReqFree(pReq);
1724
1725 return rc;
1726}
1727
1728
1729/**
1730 * Worker which checks integrity of some internal structures.
1731 * This is yet another attempt to track down that AVL tree crash.
1732 */
1733static void vmR3CheckIntegrity(PVM pVM)
1734{
1735#ifdef VBOX_STRICT
1736 int rc = PGMR3CheckIntegrity(pVM);
1737 AssertReleaseRC(rc);
1738#endif
1739}
1740
1741
1742/**
1743 * Reset request processor.
1744 *
1745 * This is called by the emulation thread as a response to the
1746 * reset request issued by VMR3Reset().
1747 *
1748 * @returns VBox status code.
1749 * @param pVM VM to reset.
1750 */
1751static DECLCALLBACK(int) vmR3Reset(PVM pVM)
1752{
1753 /*
1754 * As a safety precaution we temporarily change the state while resetting.
1755 * (If VMR3Reset was not called from EMT we might have change state... let's ignore that fact for now.)
1756 */
1757 VMSTATE enmVMState = pVM->enmVMState;
1758 Assert(enmVMState == VMSTATE_SUSPENDED || enmVMState == VMSTATE_RUNNING);
1759 vmR3SetState(pVM, VMSTATE_RESETTING);
1760 vmR3CheckIntegrity(pVM);
1761
1762
1763 /*
1764 * Reset the VM components.
1765 */
1766 PATMR3Reset(pVM);
1767 CSAMR3Reset(pVM);
1768 PGMR3Reset(pVM); /* We clear VM RAM in PGMR3Reset. It's vital PDMR3Reset is executed
1769 * _afterwards_. E.g. ACPI sets up RAM tables during init/reset. */
1770 MMR3Reset(pVM);
1771 PDMR3Reset(pVM);
1772 SELMR3Reset(pVM);
1773 TRPMR3Reset(pVM);
1774 vmR3AtReset(pVM);
1775 REMR3Reset(pVM);
1776 IOMR3Reset(pVM);
1777 CPUMR3Reset(pVM);
1778 TMR3Reset(pVM);
1779 EMR3Reset(pVM);
1780 HWACCMR3Reset(pVM); /* This must come *after* PATM, CSAM, CPUM, SELM and TRPM. */
1781
1782#ifdef LOG_ENABLED
1783 /*
1784 * Debug logging.
1785 */
1786 RTLogPrintf("\n\nThe VM was reset:\n");
1787 DBGFR3Info(pVM, "cpum", "verbose", NULL);
1788#endif
1789
1790 /*
1791 * Restore the state.
1792 */
1793 vmR3CheckIntegrity(pVM);
1794 Assert(pVM->enmVMState == VMSTATE_RESETTING);
1795 vmR3SetState(pVM, enmVMState);
1796
1797 return VINF_EM_RESET;
1798}
1799
1800
1801/**
1802 * Walks the list of at VM reset callbacks and calls them
1803 *
1804 * @returns VBox status code.
1805 * Any failure is fatal.
1806 * @param pVM The VM which is being reset.
1807 */
1808static int vmR3AtReset(PVM pVM)
1809{
1810 /*
1811 * Walk the list and call them all.
1812 */
1813 int rc = VINF_SUCCESS;
1814 for (PVMATRESET pCur = pVM->vm.s.pAtReset; pCur; pCur = pCur->pNext)
1815 {
1816 /* do the call */
1817 switch (pCur->enmType)
1818 {
1819 case VMATRESETTYPE_DEV:
1820 rc = pCur->u.Dev.pfnCallback(pCur->u.Dev.pDevIns, pCur->pvUser);
1821 break;
1822 case VMATRESETTYPE_INTERNAL:
1823 rc = pCur->u.Internal.pfnCallback(pVM, pCur->pvUser);
1824 break;
1825 case VMATRESETTYPE_EXTERNAL:
1826 pCur->u.External.pfnCallback(pCur->pvUser);
1827 break;
1828 default:
1829 AssertMsgFailed(("Invalid at-reset type %d!\n", pCur->enmType));
1830 return VERR_INTERNAL_ERROR;
1831 }
1832
1833 if (VBOX_FAILURE(rc))
1834 {
1835 AssertMsgFailed(("At-reset handler %s failed with rc=%d\n", pCur->pszDesc, rc));
1836 return rc;
1837 }
1838 }
1839
1840 return VINF_SUCCESS;
1841}
1842
1843
1844/**
1845 * Internal registration function
1846 */
1847static int vmr3AtResetRegister(PVM pVM, void *pvUser, const char *pszDesc, PVMATRESET *ppNew)
1848{
1849 /*
1850 * Allocate restration structure.
1851 */
1852 PVMATRESET pNew = (PVMATRESET)MMR3HeapAlloc(pVM, MM_TAG_VM, sizeof(*pNew));
1853 if (pNew)
1854 {
1855 /* fill data. */
1856 pNew->pNext = NULL;
1857 pNew->pszDesc = pszDesc;
1858 pNew->pvUser = pvUser;
1859
1860 /* insert */
1861 *pVM->vm.s.ppAtResetNext = pNew;
1862 pVM->vm.s.ppAtResetNext = &pNew->pNext;
1863
1864 *ppNew = pNew;
1865 return VINF_SUCCESS;
1866 }
1867 return VERR_NO_MEMORY;
1868}
1869
1870
1871/**
1872 * Registers an at VM reset callback.
1873 *
1874 * @returns VBox status code.
1875 * @param pVM The VM.
1876 * @param pDevInst Device instance.
1877 * @param pfnCallback Callback function.
1878 * @param pvUser User argument.
1879 * @param pszDesc Description (optional).
1880 */
1881VMR3DECL(int) VMR3AtResetRegister(PVM pVM, PPDMDEVINS pDevInst, PFNVMATRESET pfnCallback, void *pvUser, const char *pszDesc)
1882{
1883 /*
1884 * Validate.
1885 */
1886 if (!pDevInst)
1887 {
1888 AssertMsgFailed(("pDevIns is NULL!\n"));
1889 return VERR_INVALID_PARAMETER;
1890 }
1891
1892 /*
1893 * Create the new entry.
1894 */
1895 PVMATRESET pNew;
1896 int rc = vmr3AtResetRegister(pVM, pvUser, pszDesc, &pNew);
1897 if (VBOX_SUCCESS(rc))
1898 {
1899 /*
1900 * Fill in type data.
1901 */
1902 pNew->enmType = VMATRESETTYPE_DEV;
1903 pNew->u.Dev.pfnCallback = pfnCallback;
1904 pNew->u.Dev.pDevIns = pDevInst;
1905 }
1906
1907 return rc;
1908}
1909
1910
1911/**
1912 * Registers an at VM reset internal callback.
1913 *
1914 * @returns VBox status code.
1915 * @param pVM The VM.
1916 * @param pfnCallback Callback function.
1917 * @param pvUser User argument.
1918 * @param pszDesc Description (optional).
1919 */
1920VMR3DECL(int) VMR3AtResetRegisterInternal(PVM pVM, PFNVMATRESETINT pfnCallback, void *pvUser, const char *pszDesc)
1921{
1922 /*
1923 * Validate.
1924 */
1925 if (!pfnCallback)
1926 {
1927 AssertMsgFailed(("pfnCallback is NULL!\n"));
1928 return VERR_INVALID_PARAMETER;
1929 }
1930
1931 /*
1932 * Create the new entry.
1933 */
1934 PVMATRESET pNew;
1935 int rc = vmr3AtResetRegister(pVM, pvUser, pszDesc, &pNew);
1936 if (VBOX_SUCCESS(rc))
1937 {
1938 /*
1939 * Fill in type data.
1940 */
1941 pNew->enmType = VMATRESETTYPE_INTERNAL;
1942 pNew->u.Internal.pfnCallback = pfnCallback;
1943 }
1944
1945 return rc;
1946}
1947
1948
1949/**
1950 * Registers an at VM reset external callback.
1951 *
1952 * @returns VBox status code.
1953 * @param pVM The VM.
1954 * @param pfnCallback Callback function.
1955 * @param pvUser User argument.
1956 * @param pszDesc Description (optional).
1957 */
1958VMR3DECL(int) VMR3AtResetRegisterExternal(PVM pVM, PFNVMATRESETEXT pfnCallback, void *pvUser, const char *pszDesc)
1959{
1960 /*
1961 * Validate.
1962 */
1963 if (!pfnCallback)
1964 {
1965 AssertMsgFailed(("pfnCallback is NULL!\n"));
1966 return VERR_INVALID_PARAMETER;
1967 }
1968
1969 /*
1970 * Create the new entry.
1971 */
1972 PVMATRESET pNew;
1973 int rc = vmr3AtResetRegister(pVM, pvUser, pszDesc, &pNew);
1974 if (VBOX_SUCCESS(rc))
1975 {
1976 /*
1977 * Fill in type data.
1978 */
1979 pNew->enmType = VMATRESETTYPE_EXTERNAL;
1980 pNew->u.External.pfnCallback = pfnCallback;
1981 }
1982
1983 return rc;
1984}
1985
1986
1987/**
1988 * Unlinks and frees a callback.
1989 *
1990 * @returns Pointer to the next callback structure.
1991 * @param pVM The VM.
1992 * @param pCur The one to free.
1993 * @param pPrev The one before pCur.
1994 */
1995static PVMATRESET vmr3AtResetFree(PVM pVM, PVMATRESET pCur, PVMATRESET pPrev)
1996{
1997 /*
1998 * Unlink it.
1999 */
2000 PVMATRESET pNext = pCur->pNext;
2001 if (pPrev)
2002 {
2003 pPrev->pNext = pNext;
2004 if (!pNext)
2005 pVM->vm.s.ppAtResetNext = &pPrev->pNext;
2006 }
2007 else
2008 {
2009 pVM->vm.s.pAtReset = pNext;
2010 if (!pNext)
2011 pVM->vm.s.ppAtResetNext = &pVM->vm.s.pAtReset;
2012 }
2013
2014 /*
2015 * Free it.
2016 */
2017 MMR3HeapFree(pCur);
2018
2019 return pNext;
2020}
2021
2022
2023/**
2024 * Deregisters an at VM reset callback.
2025 *
2026 * @returns VBox status code.
2027 * @param pVM The VM.
2028 * @param pDevInst Device instance.
2029 * @param pfnCallback Callback function.
2030 */
2031VMR3DECL(int) VMR3AtResetDeregister(PVM pVM, PPDMDEVINS pDevInst, PFNVMATRESET pfnCallback)
2032{
2033 int rc = VERR_VM_ATRESET_NOT_FOUND;
2034 PVMATRESET pPrev = NULL;
2035 PVMATRESET pCur = pVM->vm.s.pAtReset;
2036 while (pCur)
2037 {
2038 if ( pCur->enmType == VMATRESETTYPE_DEV
2039 && pCur->u.Dev.pDevIns == pDevInst
2040 && (!pfnCallback || pCur->u.Dev.pfnCallback == pfnCallback))
2041 {
2042 pCur = vmr3AtResetFree(pVM, pCur, pPrev);
2043 rc = VINF_SUCCESS;
2044 }
2045 else
2046 {
2047 pPrev = pCur;
2048 pCur = pCur->pNext;
2049 }
2050 }
2051
2052 AssertRC(rc);
2053 return rc;
2054}
2055
2056
2057/**
2058 * Deregisters an at VM reset internal callback.
2059 *
2060 * @returns VBox status code.
2061 * @param pVM The VM.
2062 * @param pfnCallback Callback function.
2063 */
2064VMR3DECL(int) VMR3AtResetDeregisterInternal(PVM pVM, PFNVMATRESETINT pfnCallback)
2065{
2066 int rc = VERR_VM_ATRESET_NOT_FOUND;
2067 PVMATRESET pPrev = NULL;
2068 PVMATRESET pCur = pVM->vm.s.pAtReset;
2069 while (pCur)
2070 {
2071 if ( pCur->enmType == VMATRESETTYPE_INTERNAL
2072 && pCur->u.Internal.pfnCallback == pfnCallback)
2073 {
2074 pCur = vmr3AtResetFree(pVM, pCur, pPrev);
2075 rc = VINF_SUCCESS;
2076 }
2077 else
2078 {
2079 pPrev = pCur;
2080 pCur = pCur->pNext;
2081 }
2082 }
2083
2084 AssertRC(rc);
2085 return rc;
2086}
2087
2088
2089/**
2090 * Deregisters an at VM reset external callback.
2091 *
2092 * @returns VBox status code.
2093 * @param pVM The VM.
2094 * @param pfnCallback Callback function.
2095 */
2096VMR3DECL(int) VMR3AtResetDeregisterExternal(PVM pVM, PFNVMATRESETEXT pfnCallback)
2097{
2098 int rc = VERR_VM_ATRESET_NOT_FOUND;
2099 PVMATRESET pPrev = NULL;
2100 PVMATRESET pCur = pVM->vm.s.pAtReset;
2101 while (pCur)
2102 {
2103 if ( pCur->enmType == VMATRESETTYPE_INTERNAL
2104 && pCur->u.External.pfnCallback == pfnCallback)
2105 {
2106 pCur = vmr3AtResetFree(pVM, pCur, pPrev);
2107 rc = VINF_SUCCESS;
2108 }
2109 else
2110 {
2111 pPrev = pCur;
2112 pCur = pCur->pNext;
2113 }
2114 }
2115
2116 AssertRC(rc);
2117 return rc;
2118}
2119
2120
2121/**
2122 * Gets the current VM state.
2123 *
2124 * @returns The current VM state.
2125 * @param pVM VM handle.
2126 * @thread Any
2127 */
2128VMR3DECL(VMSTATE) VMR3GetState(PVM pVM)
2129{
2130 return pVM->enmVMState;
2131}
2132
2133
2134/**
2135 * Gets the state name string for a VM state.
2136 *
2137 * @returns Pointer to the state name. (readonly)
2138 * @param enmState The state.
2139 */
2140VMR3DECL(const char *) VMR3GetStateName(VMSTATE enmState)
2141{
2142 switch (enmState)
2143 {
2144 case VMSTATE_CREATING: return "CREATING";
2145 case VMSTATE_CREATED: return "CREATED";
2146 case VMSTATE_RUNNING: return "RUNNING";
2147 case VMSTATE_LOADING: return "LOADING";
2148 case VMSTATE_LOAD_FAILURE: return "LOAD_FAILURE";
2149 case VMSTATE_SAVING: return "SAVING";
2150 case VMSTATE_SUSPENDED: return "SUSPENDED";
2151 case VMSTATE_RESETTING: return "RESETTING";
2152 case VMSTATE_GURU_MEDITATION: return "GURU_MEDIATION";
2153 case VMSTATE_OFF: return "OFF";
2154 case VMSTATE_DESTROYING: return "DESTROYING";
2155 case VMSTATE_TERMINATED: return "TERMINATED";
2156 default:
2157 AssertMsgFailed(("Unknown state %d\n", enmState));
2158 return "Unknown!\n";
2159 }
2160}
2161
2162
2163/**
2164 * Sets the current VM state.
2165 *
2166 * @returns The current VM state.
2167 * @param pVM VM handle.
2168 * @param enmStateNew The new state.
2169 */
2170void vmR3SetState(PVM pVM, VMSTATE enmStateNew)
2171{
2172 VMSTATE enmStateOld = pVM->enmVMState;
2173 pVM->enmVMState = enmStateNew;
2174 LogRel(("Changing the VM state from '%s' to '%s'.\n", VMR3GetStateName(enmStateOld), VMR3GetStateName(enmStateNew)));
2175
2176 /*
2177 * Call the at state change callbacks.
2178 */
2179 for (PVMATSTATE pCur = pVM->vm.s.pAtState; pCur; pCur = pCur->pNext)
2180 {
2181 pCur->pfnAtState(pVM, enmStateNew, enmStateOld, pCur->pvUser);
2182 if (pVM->enmVMState == VMSTATE_DESTROYING)
2183 break;
2184 AssertMsg(pVM->enmVMState == enmStateNew,
2185 ("You are not allowed to change the state while in the change callback, except "
2186 "from destroying the VM. There are restrictions in the way the state changes "
2187 "are propagated up to the EM execution loop and it makes the program flow very "
2188 "difficult to follow.\n"));
2189 }
2190}
2191
2192
2193/**
2194 * Registers a VM state change callback.
2195 *
2196 * You are not allowed to call any function which changes the VM state from a
2197 * state callback, except VMR3Destroy().
2198 *
2199 * @returns VBox status code.
2200 * @param pVM VM handle.
2201 * @param pfnAtState Pointer to callback.
2202 * @param pvUser User argument.
2203 * @thread Any.
2204 */
2205VMR3DECL(int) VMR3AtStateRegister(PVM pVM, PFNVMATSTATE pfnAtState, void *pvUser)
2206{
2207 LogFlow(("VMR3AtStateRegister: pfnAtState=%p pvUser=%p\n", pfnAtState, pvUser));
2208
2209 /*
2210 * Validate input.
2211 */
2212 if (!pfnAtState)
2213 {
2214 AssertMsgFailed(("callback is required\n"));
2215 return VERR_INVALID_PARAMETER;
2216 }
2217
2218 /*
2219 * Make sure we're in EMT (to avoid the logging).
2220 */
2221 PVMREQ pReq;
2222 int rc = VMR3ReqCall(pVM, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3AtStateRegister, 3, pVM, pfnAtState, pvUser);
2223 if (VBOX_FAILURE(rc))
2224 return rc;
2225 rc = pReq->iStatus;
2226 VMR3ReqFree(pReq);
2227
2228 LogFlow(("VMR3AtStateRegister: returns %Vrc\n", rc));
2229 return rc;
2230}
2231
2232
2233/**
2234 * Registers a VM state change callback.
2235 *
2236 * @returns VBox status code.
2237 * @param pVM VM handle.
2238 * @param pfnAtState Pointer to callback.
2239 * @param pvUser User argument.
2240 * @thread EMT
2241 */
2242static DECLCALLBACK(int) vmR3AtStateRegister(PVM pVM, PFNVMATSTATE pfnAtState, void *pvUser)
2243{
2244 /*
2245 * Allocate a new record.
2246 */
2247
2248 PVMATSTATE pNew = (PVMATSTATE)MMR3HeapAlloc(pVM, MM_TAG_VM, sizeof(*pNew));
2249 if (!pNew)
2250 return VERR_NO_MEMORY;
2251
2252 /* fill */
2253 pNew->pfnAtState = pfnAtState;
2254 pNew->pvUser = pvUser;
2255 pNew->pNext = NULL;
2256
2257 /* insert */
2258 *pVM->vm.s.ppAtStateNext = pNew;
2259 pVM->vm.s.ppAtStateNext = &pNew->pNext;
2260
2261 return VINF_SUCCESS;
2262}
2263
2264
2265/**
2266 * Deregisters a VM state change callback.
2267 *
2268 * @returns VBox status code.
2269 * @param pVM VM handle.
2270 * @param pfnAtState Pointer to callback.
2271 * @param pvUser User argument.
2272 * @thread Any.
2273 */
2274VMR3DECL(int) VMR3AtStateDeregister(PVM pVM, PFNVMATSTATE pfnAtState, void *pvUser)
2275{
2276 LogFlow(("VMR3AtStateDeregister: pfnAtState=%p pvUser=%p\n", pfnAtState, pvUser));
2277
2278 /*
2279 * Validate input.
2280 */
2281 if (!pfnAtState)
2282 {
2283 AssertMsgFailed(("callback is required\n"));
2284 return VERR_INVALID_PARAMETER;
2285 }
2286
2287 /*
2288 * Make sure we're in EMT (to avoid the logging).
2289 */
2290 PVMREQ pReq;
2291 int rc = VMR3ReqCall(pVM, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3AtStateDeregister, 3, pVM, pfnAtState, pvUser);
2292 if (VBOX_FAILURE(rc))
2293 return rc;
2294 rc = pReq->iStatus;
2295 VMR3ReqFree(pReq);
2296
2297 LogFlow(("VMR3AtStateDeregister: returns %Vrc\n", rc));
2298 return rc;
2299}
2300
2301
2302/**
2303 * Deregisters a VM state change callback.
2304 *
2305 * @returns VBox status code.
2306 * @param pVM VM handle.
2307 * @param pfnAtState Pointer to callback.
2308 * @param pvUser User argument.
2309 * @thread EMT
2310 */
2311static DECLCALLBACK(int) vmR3AtStateDeregister(PVM pVM, PFNVMATSTATE pfnAtState, void *pvUser)
2312{
2313 LogFlow(("vmR3AtStateDeregister: pfnAtState=%p pvUser=%p\n", pfnAtState, pvUser));
2314
2315 /*
2316 * Search the list for the entry.
2317 */
2318 PVMATSTATE pPrev = NULL;
2319 PVMATSTATE pCur = pVM->vm.s.pAtState;
2320 while ( pCur
2321 && pCur->pfnAtState == pfnAtState
2322 && pCur->pvUser == pvUser)
2323 {
2324 pPrev = pCur;
2325 pCur = pCur->pNext;
2326 }
2327 if (!pCur)
2328 {
2329 AssertMsgFailed(("pfnAtState=%p was not found\n", pfnAtState));
2330 return VERR_FILE_NOT_FOUND;
2331 }
2332
2333 /*
2334 * Unlink it.
2335 */
2336 if (pPrev)
2337 {
2338 pPrev->pNext = pCur->pNext;
2339 if (!pCur->pNext)
2340 pVM->vm.s.ppAtStateNext = &pPrev->pNext;
2341 }
2342 else
2343 {
2344 pVM->vm.s.pAtState = pCur->pNext;
2345 if (!pCur->pNext)
2346 pVM->vm.s.ppAtStateNext = &pVM->vm.s.pAtState;
2347 }
2348
2349 /*
2350 * Free it.
2351 */
2352 pCur->pfnAtState = NULL;
2353 pCur->pNext = NULL;
2354 MMR3HeapFree(pCur);
2355
2356 return VINF_SUCCESS;
2357}
2358
2359
2360/**
2361 * Registers a VM error callback.
2362 *
2363 * @returns VBox status code.
2364 * @param pVM The VM handle.
2365 * @param pfnAtError Pointer to callback.
2366 * @param pvUser User argument.
2367 * @thread Any.
2368 */
2369VMR3DECL(int) VMR3AtErrorRegister(PVM pVM, PFNVMATERROR pfnAtError, void *pvUser)
2370{
2371 LogFlow(("VMR3AtErrorRegister: pfnAtError=%p pvUser=%p\n", pfnAtError, pvUser));
2372
2373 /*
2374 * Validate input.
2375 */
2376 if (!pfnAtError)
2377 {
2378 AssertMsgFailed(("callback is required\n"));
2379 return VERR_INVALID_PARAMETER;
2380 }
2381
2382 /*
2383 * Make sure we're in EMT (to avoid the logging).
2384 */
2385 PVMREQ pReq;
2386 int rc = VMR3ReqCall(pVM, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3AtErrorRegister, 3, pVM, pfnAtError, pvUser);
2387 if (VBOX_FAILURE(rc))
2388 return rc;
2389 rc = pReq->iStatus;
2390 VMR3ReqFree(pReq);
2391
2392 LogFlow(("VMR3AtErrorRegister: returns %Vrc\n", rc));
2393 return rc;
2394}
2395
2396
2397/**
2398 * Registers a VM error callback.
2399 *
2400 * @returns VBox status code.
2401 * @param pVM The VM handle.
2402 * @param pfnAtError Pointer to callback.
2403 * @param pvUser User argument.
2404 * @thread EMT
2405 */
2406static DECLCALLBACK(int) vmR3AtErrorRegister(PVM pVM, PFNVMATERROR pfnAtError, void *pvUser)
2407{
2408 /*
2409 * Allocate a new record.
2410 */
2411
2412 PVMATERROR pNew = (PVMATERROR)MMR3HeapAlloc(pVM, MM_TAG_VM, sizeof(*pNew));
2413 if (!pNew)
2414 return VERR_NO_MEMORY;
2415
2416 /* fill */
2417 pNew->pfnAtError = pfnAtError;
2418 pNew->pvUser = pvUser;
2419 pNew->pNext = NULL;
2420
2421 /* insert */
2422 *pVM->vm.s.ppAtErrorNext = pNew;
2423 pVM->vm.s.ppAtErrorNext = &pNew->pNext;
2424
2425 return VINF_SUCCESS;
2426}
2427
2428
2429/**
2430 * Deregisters a VM error callback.
2431 *
2432 * @returns VBox status code.
2433 * @param pVM The VM handle.
2434 * @param pfnAtError Pointer to callback.
2435 * @param pvUser User argument.
2436 * @thread Any.
2437 */
2438VMR3DECL(int) VMR3AtErrorDeregister(PVM pVM, PFNVMATERROR pfnAtError, void *pvUser)
2439{
2440 LogFlow(("VMR3AtErrorDeregister: pfnAtError=%p pvUser=%p\n", pfnAtError, pvUser));
2441
2442 /*
2443 * Validate input.
2444 */
2445 if (!pfnAtError)
2446 {
2447 AssertMsgFailed(("callback is required\n"));
2448 return VERR_INVALID_PARAMETER;
2449 }
2450
2451 /*
2452 * Make sure we're in EMT (to avoid the logging).
2453 */
2454 PVMREQ pReq;
2455 int rc = VMR3ReqCall(pVM, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3AtErrorDeregister, 3, pVM, pfnAtError, pvUser);
2456 if (VBOX_FAILURE(rc))
2457 return rc;
2458 rc = pReq->iStatus;
2459 VMR3ReqFree(pReq);
2460
2461 LogFlow(("VMR3AtErrorDeregister: returns %Vrc\n", rc));
2462 return rc;
2463}
2464
2465
2466/**
2467 * Deregisters a VM error callback.
2468 *
2469 * @returns VBox status code.
2470 * @param pVM The VM handle.
2471 * @param pfnAtError Pointer to callback.
2472 * @param pvUser User argument.
2473 * @thread EMT
2474 */
2475static DECLCALLBACK(int) vmR3AtErrorDeregister(PVM pVM, PFNVMATERROR pfnAtError, void *pvUser)
2476{
2477 LogFlow(("vmR3AtErrorDeregister: pfnAtError=%p pvUser=%p\n", pfnAtError, pvUser));
2478
2479 /*
2480 * Search the list for the entry.
2481 */
2482 PVMATERROR pPrev = NULL;
2483 PVMATERROR pCur = pVM->vm.s.pAtError;
2484 while ( pCur
2485 && pCur->pfnAtError == pfnAtError
2486 && pCur->pvUser == pvUser)
2487 {
2488 pPrev = pCur;
2489 pCur = pCur->pNext;
2490 }
2491 if (!pCur)
2492 {
2493 AssertMsgFailed(("pfnAtError=%p was not found\n", pfnAtError));
2494 return VERR_FILE_NOT_FOUND;
2495 }
2496
2497 /*
2498 * Unlink it.
2499 */
2500 if (pPrev)
2501 {
2502 pPrev->pNext = pCur->pNext;
2503 if (!pCur->pNext)
2504 pVM->vm.s.ppAtErrorNext = &pPrev->pNext;
2505 }
2506 else
2507 {
2508 pVM->vm.s.pAtError = pCur->pNext;
2509 if (!pCur->pNext)
2510 pVM->vm.s.ppAtErrorNext = &pVM->vm.s.pAtError;
2511 }
2512
2513 /*
2514 * Free it.
2515 */
2516 pCur->pfnAtError = NULL;
2517 pCur->pNext = NULL;
2518 MMR3HeapFree(pCur);
2519
2520 return VINF_SUCCESS;
2521}
2522
2523
2524/**
2525 * Ellipsis to va_list wrapper for calling pfnAtError.
2526 */
2527static void vmR3SetErrorWorkerDoCall(PVM pVM, PVMATERROR pCur, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...)
2528{
2529 va_list va;
2530 va_start(va, pszFormat);
2531 pCur->pfnAtError(pVM, pCur->pvUser, rc, RT_SRC_POS_ARGS, pszFormat, va);
2532 va_end(va);
2533}
2534
2535
2536/**
2537 * This is a worker function for GC and Ring-0 calls to VMSetError and VMSetErrorV.
2538 * The message is found in VMINT.
2539 *
2540 * @param pVM The VM handle.
2541 * @thread EMT.
2542 */
2543VMR3DECL(void) VMR3SetErrorWorker(PVM pVM)
2544{
2545 VM_ASSERT_EMT(pVM);
2546 AssertReleaseMsgFailed(("And we have a winner! You get to implement Ring-0 and GC VMSetErrorV! Contrats!\n"));
2547
2548 /*
2549 * Unpack the error (if we managed to format one).
2550 */
2551 PVMERROR pErr = pVM->vm.s.pErrorR3;
2552 const char *pszFile = NULL;
2553 const char *pszFunction = NULL;
2554 uint32_t iLine = 0;
2555 const char *pszMessage;
2556 int32_t rc = VERR_MM_HYPER_NO_MEMORY;
2557 if (pErr)
2558 {
2559 AssertCompile(sizeof(const char) == sizeof(uint8_t));
2560 if (pErr->offFile)
2561 pszFile = (const char *)pErr + pErr->offFile;
2562 iLine = pErr->iLine;
2563 if (pErr->offFunction)
2564 pszFunction = (const char *)pErr + pErr->offFunction;
2565 if (pErr->offMessage)
2566 pszMessage = (const char *)pErr + pErr->offMessage;
2567 else
2568 pszMessage = "No message!";
2569 }
2570 else
2571 pszMessage = "No message! (Failed to allocate memory to put the error message in!)";
2572
2573 /*
2574 * Call the at error callbacks.
2575 */
2576 for (PVMATERROR pCur = pVM->vm.s.pAtError; pCur; pCur = pCur->pNext)
2577 vmR3SetErrorWorkerDoCall(pVM, pCur, rc, RT_SRC_POS_ARGS, "%s", pszMessage);
2578}
2579
2580
2581/**
2582 * Worker which calls everyone listening to the VM error messages.
2583 *
2584 * @param pVM The VM handle.
2585 * @param rc The VBox status code.
2586 * @param RT_SRC_POS_DECL The source position of this error.
2587 * @param pszFormat Format string.
2588 * @param pArgs Pointer to the format arguments.
2589 * @thread EMT
2590 */
2591DECLCALLBACK(void) vmR3SetErrorV(PVM pVM, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list *pArgs)
2592{
2593#ifdef LOG_ENABLED
2594 /*
2595 * Log the error.
2596 */
2597 RTLogPrintf("VMSetError: %s(%d) %s\n", pszFile, iLine, pszFunction);
2598 va_list va3;
2599 va_copy(va3, *pArgs);
2600 RTLogPrintfV(pszFormat, va3);
2601 va_end(va3);
2602#endif
2603
2604 /*
2605 * Prevent overwriting of the previous error.
2606 */
2607 if (pVM->vm.s.fErrorSet)
2608 return;
2609
2610 pVM->vm.s.fErrorSet = true;
2611
2612 /*
2613 * Make a copy of the message.
2614 */
2615 vmSetErrorCopy(pVM, rc, RT_SRC_POS_ARGS, pszFormat, *pArgs);
2616
2617 /*
2618 * Call the at error callbacks.
2619 */
2620 for (PVMATERROR pCur = pVM->vm.s.pAtError; pCur; pCur = pCur->pNext)
2621 {
2622 va_list va2;
2623 va_copy(va2, *pArgs);
2624 pCur->pfnAtError(pVM, pCur->pvUser, rc, RT_SRC_POS_ARGS, pszFormat, va2);
2625 va_end(va2);
2626 }
2627}
2628
2629
2630/**
2631 * Registers a VM runtime error callback.
2632 *
2633 * @returns VBox status code.
2634 * @param pVM The VM handle.
2635 * @param pfnAtRuntimeError Pointer to callback.
2636 * @param pvUser User argument.
2637 * @thread Any.
2638 */
2639VMR3DECL(int) VMR3AtRuntimeErrorRegister(PVM pVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser)
2640{
2641 LogFlow(("VMR3AtRuntimeErrorRegister: pfnAtRuntimeError=%p pvUser=%p\n", pfnAtRuntimeError, pvUser));
2642
2643 /*
2644 * Validate input.
2645 */
2646 if (!pfnAtRuntimeError)
2647 {
2648 AssertMsgFailed(("callback is required\n"));
2649 return VERR_INVALID_PARAMETER;
2650 }
2651
2652 /*
2653 * Make sure we're in EMT (to avoid the logging).
2654 */
2655 PVMREQ pReq;
2656 int rc = VMR3ReqCall(pVM, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3AtRuntimeErrorRegister, 3, pVM, pfnAtRuntimeError, pvUser);
2657 if (VBOX_FAILURE(rc))
2658 return rc;
2659 rc = pReq->iStatus;
2660 VMR3ReqFree(pReq);
2661
2662 LogFlow(("VMR3AtRuntimeErrorRegister: returns %Vrc\n", rc));
2663 return rc;
2664}
2665
2666
2667/**
2668 * Registers a VM runtime error callback.
2669 *
2670 * @returns VBox status code.
2671 * @param pVM The VM handle.
2672 * @param pfnAtRuntimeError Pointer to callback.
2673 * @param pvUser User argument.
2674 * @thread EMT
2675 */
2676static DECLCALLBACK(int) vmR3AtRuntimeErrorRegister(PVM pVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser)
2677{
2678 /*
2679 * Allocate a new record.
2680 */
2681
2682 PVMATRUNTIMEERROR pNew = (PVMATRUNTIMEERROR)MMR3HeapAlloc(pVM, MM_TAG_VM, sizeof(*pNew));
2683 if (!pNew)
2684 return VERR_NO_MEMORY;
2685
2686 /* fill */
2687 pNew->pfnAtRuntimeError = pfnAtRuntimeError;
2688 pNew->pvUser = pvUser;
2689 pNew->pNext = NULL;
2690
2691 /* insert */
2692 *pVM->vm.s.ppAtRuntimeErrorNext = pNew;
2693 pVM->vm.s.ppAtRuntimeErrorNext = &pNew->pNext;
2694
2695 return VINF_SUCCESS;
2696}
2697
2698
2699/**
2700 * Deregisters a VM runtime error callback.
2701 *
2702 * @returns VBox status code.
2703 * @param pVM The VM handle.
2704 * @param pfnAtRuntimeError Pointer to callback.
2705 * @param pvUser User argument.
2706 * @thread Any.
2707 */
2708VMR3DECL(int) VMR3AtRuntimeErrorDeregister(PVM pVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser)
2709{
2710 LogFlow(("VMR3AtRuntimeErrorDeregister: pfnAtRuntimeError=%p pvUser=%p\n", pfnAtRuntimeError, pvUser));
2711
2712 /*
2713 * Validate input.
2714 */
2715 if (!pfnAtRuntimeError)
2716 {
2717 AssertMsgFailed(("callback is required\n"));
2718 return VERR_INVALID_PARAMETER;
2719 }
2720
2721 /*
2722 * Make sure we're in EMT (to avoid the logging).
2723 */
2724 PVMREQ pReq;
2725 int rc = VMR3ReqCall(pVM, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3AtRuntimeErrorDeregister, 3, pVM, pfnAtRuntimeError, pvUser);
2726 if (VBOX_FAILURE(rc))
2727 return rc;
2728 rc = pReq->iStatus;
2729 VMR3ReqFree(pReq);
2730
2731 LogFlow(("VMR3AtRuntimeErrorDeregister: returns %Vrc\n", rc));
2732 return rc;
2733}
2734
2735
2736/**
2737 * Deregisters a VM runtime error callback.
2738 *
2739 * @returns VBox status code.
2740 * @param pVM The VM handle.
2741 * @param pfnAtRuntimeError Pointer to callback.
2742 * @param pvUser User argument.
2743 * @thread EMT
2744 */
2745static DECLCALLBACK(int) vmR3AtRuntimeErrorDeregister(PVM pVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser)
2746{
2747 LogFlow(("vmR3AtRuntimeErrorDeregister: pfnAtRuntimeError=%p pvUser=%p\n", pfnAtRuntimeError, pvUser));
2748
2749 /*
2750 * Search the list for the entry.
2751 */
2752 PVMATRUNTIMEERROR pPrev = NULL;
2753 PVMATRUNTIMEERROR pCur = pVM->vm.s.pAtRuntimeError;
2754 while ( pCur
2755 && pCur->pfnAtRuntimeError == pfnAtRuntimeError
2756 && pCur->pvUser == pvUser)
2757 {
2758 pPrev = pCur;
2759 pCur = pCur->pNext;
2760 }
2761 if (!pCur)
2762 {
2763 AssertMsgFailed(("pfnAtRuntimeError=%p was not found\n", pfnAtRuntimeError));
2764 return VERR_FILE_NOT_FOUND;
2765 }
2766
2767 /*
2768 * Unlink it.
2769 */
2770 if (pPrev)
2771 {
2772 pPrev->pNext = pCur->pNext;
2773 if (!pCur->pNext)
2774 pVM->vm.s.ppAtRuntimeErrorNext = &pPrev->pNext;
2775 }
2776 else
2777 {
2778 pVM->vm.s.pAtRuntimeError = pCur->pNext;
2779 if (!pCur->pNext)
2780 pVM->vm.s.ppAtRuntimeErrorNext = &pVM->vm.s.pAtRuntimeError;
2781 }
2782
2783 /*
2784 * Free it.
2785 */
2786 pCur->pfnAtRuntimeError = NULL;
2787 pCur->pNext = NULL;
2788 MMR3HeapFree(pCur);
2789
2790 return VINF_SUCCESS;
2791}
2792
2793
2794/**
2795 * Ellipsis to va_list wrapper for calling pfnAtRuntimeError.
2796 */
2797static void vmR3SetRuntimeErrorWorkerDoCall(PVM pVM, PVMATRUNTIMEERROR pCur, bool fFatal,
2798 const char *pszErrorID,
2799 const char *pszFormat, ...)
2800{
2801 va_list va;
2802 va_start(va, pszFormat);
2803 pCur->pfnAtRuntimeError(pVM, pCur->pvUser, fFatal, pszErrorID, pszFormat, va);
2804 va_end(va);
2805}
2806
2807
2808/**
2809 * This is a worker function for GC and Ring-0 calls to VMSetError and VMSetErrorV.
2810 * The message is found in VMINT.
2811 *
2812 * @param pVM The VM handle.
2813 * @thread EMT.
2814 */
2815VMR3DECL(void) VMR3SetRuntimeErrorWorker(PVM pVM)
2816{
2817 VM_ASSERT_EMT(pVM);
2818 AssertReleaseMsgFailed(("And we have a winner! You get to implement Ring-0 and GC VMSetRuntimeErrorV! Contrats!\n"));
2819
2820 /*
2821 * Unpack the error (if we managed to format one).
2822 */
2823 PVMRUNTIMEERROR pErr = pVM->vm.s.pRuntimeErrorR3;
2824 const char *pszErrorID = NULL;
2825 const char *pszMessage;
2826 bool fFatal = false;
2827 if (pErr)
2828 {
2829 AssertCompile(sizeof(const char) == sizeof(uint8_t));
2830 if (pErr->offErrorID)
2831 pszErrorID = (const char *)pErr + pErr->offErrorID;
2832 if (pErr->offMessage)
2833 pszMessage = (const char *)pErr + pErr->offMessage;
2834 else
2835 pszMessage = "No message!";
2836 fFatal = pErr->fFatal;
2837 }
2838 else
2839 pszMessage = "No message! (Failed to allocate memory to put the error message in!)";
2840
2841 /*
2842 * Call the at runtime error callbacks.
2843 */
2844 for (PVMATRUNTIMEERROR pCur = pVM->vm.s.pAtRuntimeError; pCur; pCur = pCur->pNext)
2845 vmR3SetRuntimeErrorWorkerDoCall(pVM, pCur, fFatal, pszErrorID, "%s", pszMessage);
2846}
2847
2848
2849/**
2850 * Worker which calls everyone listening to the VM runtime error messages.
2851 *
2852 * @param pVM The VM handle.
2853 * @param fFatal Whether it is a fatal error or not.
2854 * @param pszErrorID Error ID string.
2855 * @param pszFormat Format string.
2856 * @param pArgs Pointer to the format arguments.
2857 * @thread EMT
2858 */
2859DECLCALLBACK(void) vmR3SetRuntimeErrorV(PVM pVM, bool fFatal,
2860 const char *pszErrorID,
2861 const char *pszFormat, va_list *pArgs)
2862{
2863 /*
2864 * Make a copy of the message.
2865 */
2866 vmSetRuntimeErrorCopy(pVM, fFatal, pszErrorID, pszFormat, *pArgs);
2867
2868 /*
2869 * Call the at error callbacks.
2870 */
2871 for (PVMATRUNTIMEERROR pCur = pVM->vm.s.pAtRuntimeError; pCur; pCur = pCur->pNext)
2872 {
2873 va_list va2;
2874 va_copy(va2, *pArgs);
2875 pCur->pfnAtRuntimeError(pVM, pCur->pvUser, fFatal, pszErrorID, pszFormat, va2);
2876 va_end(va2);
2877 }
2878}
2879
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