VirtualBox

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

Last change on this file since 1447 was 1417, checked in by vboxsync, 18 years ago

Adjusted comment.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette