VirtualBox

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

Last change on this file since 1272 was 1187, checked in by vboxsync, 18 years ago

sync HEAD with 1.3: Better error messages if vboxdrv could not be accessed on Linux

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 82.6 KB
Line 
1/* $Id: VM.cpp 1187 2007-03-04 20:23:31Z 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 VMR3Relocate(pVM, 0); /* paranoia */
1131 vmR3SetState(pVM, VMSTATE_SUSPENDED);
1132 }
1133 else
1134 {
1135 vmR3SetState(pVM, VMSTATE_LOAD_FAILURE);
1136 rc = VMSetError(pVM, rc, RT_SRC_POS, N_("Failed to restore VM state from '%s' (%Vrc)"), pszFilename, rc);
1137 }
1138
1139 return rc;
1140}
1141
1142
1143/**
1144 * Power Off the VM.
1145 *
1146 * @returns 0 on success.
1147 * @returns VBox error code on failure.
1148 * @param pVM VM which should be destroyed.
1149 * @thread Any thread.
1150 * @vmstate Suspended, Running, Guru Mediation, Load Failure
1151 * @vmstateto Off
1152 */
1153VMR3DECL(int) VMR3PowerOff(PVM pVM)
1154{
1155 LogFlow(("VMR3PowerOff: pVM=%p\n", pVM));
1156
1157 /*
1158 * Validate input.
1159 */
1160 if (!pVM)
1161 {
1162 AssertMsgFailed(("Invalid VM pointer\n"));
1163 return VERR_INVALID_PARAMETER;
1164 }
1165
1166 /*
1167 * Request the operation in EMT.
1168 */
1169 PVMREQ pReq;
1170 int rc = VMR3ReqCall(pVM, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3PowerOff, 1, pVM);
1171 if (VBOX_SUCCESS(rc))
1172 {
1173 rc = pReq->iStatus;
1174 VMR3ReqFree(pReq);
1175 }
1176
1177 LogFlow(("VMR3PowerOff: returns %Vrc\n", rc));
1178 return rc;
1179}
1180
1181
1182/**
1183 * Power Off the VM.
1184 *
1185 * @returns 0 on success.
1186 * @returns VBox error code on failure.
1187 * @param pVM VM which should be destroyed.
1188 * @thread EMT.
1189 */
1190static DECLCALLBACK(int) vmR3PowerOff(PVM pVM)
1191{
1192 LogFlow(("vmR3PowerOff: pVM=%p\n", pVM));
1193
1194 /*
1195 * The Windows guest additions might have performed a VMMDevPowerState_PowerOff()
1196 * request which was not completed yet. Later, the Windows guest shuts down via
1197 * ACPI and we find the VMSTATE_OFF. Just ignore the second power-off request.
1198 */
1199 /** @todo r=bird: We should find a proper solution to this problem. This is just a workaround.
1200 * Guest code should really run after we've entered VMSTATE_OFF really... */
1201 if (pVM->enmVMState == VMSTATE_OFF)
1202 return VINF_EM_OFF;
1203
1204 /*
1205 * Validate input.
1206 */
1207 if ( pVM->enmVMState != VMSTATE_RUNNING
1208 && pVM->enmVMState != VMSTATE_SUSPENDED
1209 && pVM->enmVMState != VMSTATE_LOAD_FAILURE
1210 && pVM->enmVMState != VMSTATE_GURU_MEDITATION)
1211 {
1212 AssertMsgFailed(("Invalid VM state %d\n", pVM->enmVMState));
1213 return VERR_VM_INVALID_VM_STATE;
1214 }
1215
1216 /*
1217 * For debugging purposes, we will log a summary of the guest state at this point.
1218 */
1219 if (pVM->enmVMState != VMSTATE_GURU_MEDITATION)
1220 {
1221 /** @todo make the state dumping at VMR3PowerOff optional. */
1222 RTLogRelPrintf("****************** Guest state at power off ******************\n");
1223 DBGFR3Info(pVM, "cpumguest", "verbose", DBGFR3InfoLogRelHlp());
1224 RTLogRelPrintf("***\n");
1225 DBGFR3Info(pVM, "mode", NULL, DBGFR3InfoLogRelHlp());
1226 RTLogRelPrintf("***\n");
1227 DBGFR3Info(pVM, "activetimers", NULL, DBGFR3InfoLogRelHlp());
1228 RTLogRelPrintf("***\n");
1229 DBGFR3Info(pVM, "gdt", NULL, DBGFR3InfoLogRelHlp());
1230 /** @todo dump guest call stack. */
1231#if 1 // temporary while debugging #1589
1232 RTLogRelPrintf("***\n");
1233 DBGFR3Info(pVM, "pit", NULL, DBGFR3InfoLogRelHlp());
1234 //RTLogRelPrintf("***\n");
1235 //DBGFR3Info(pVM, "handlers", NULL, DBGFR3InfoLogRelHlp());
1236 uint32_t esp = CPUMGetGuestESP(pVM);
1237 if ( CPUMGetGuestSS(pVM) == 0
1238 && esp < _64K)
1239 {
1240 RTLogRelPrintf("***\n"
1241 "ss:sp=0000:%04x ", esp);
1242 void *pv;
1243 int rc = PGMPhysGCPtr2HCPtr(pVM, esp, &pv);
1244 if (VBOX_SUCCESS(rc))
1245 {
1246 const uint8_t *pb = (uint8_t *)((uintptr_t)pv & ~(uintptr_t)0x3f);
1247 RTLogRelPrintf("pb=%p pv=%p\n"
1248 "%.*Rhxd\n", pb, pv,
1249 PAGE_SIZE - ((uintptr_t)pb & PAGE_OFFSET_MASK), pb);
1250 }
1251 else
1252 RTLogRelPrintf("rc=%Vrc\n", rc);
1253 /* grub ... */
1254 if (esp < 0x2000 && esp > 0x1fc0)
1255 {
1256 int rc = PGMPhysGCPtr2HCPtr(pVM, 0x8000, &pv);
1257 if (VBOX_SUCCESS(rc))
1258 RTLogRelPrintf("0000:8000 TO 0000:87ff: pv=%p\n"
1259 "%.*Rhxd\n", pv, 0x8000, pv);
1260 }
1261 /* microsoft cdrom hang ... */
1262 if (true)
1263 {
1264 int rc = PGMPhysGCPtr2HCPtr(pVM, 0x20000, &pv);
1265 if (VBOX_SUCCESS(rc))
1266 RTLogRelPrintf("2000:0000 TO 2000:01ff: pv=%p\n"
1267 "%.*Rhxd\n", pv, 0x200, pv);
1268 }
1269 }
1270#endif
1271 RTLogRelPrintf("************** End of Guest state at power off ***************\n");
1272 }
1273
1274 /*
1275 * Change the state to OFF and notify the components.
1276 */
1277 vmR3SetState(pVM, VMSTATE_OFF);
1278 PDMR3PowerOff(pVM);
1279
1280 return VINF_EM_OFF;
1281}
1282
1283
1284/**
1285 * Destroys the VM.
1286 * The VM must be powered off (or never really powered on) to call this function.
1287 * The VM handle is destroyed and can no longer be used up successful return.
1288 *
1289 * @returns 0 on success.
1290 * @returns VBox error code on failure.
1291 * @param pVM VM which should be destroyed.
1292 * @thread Any thread but the emulation thread.
1293 * @vmstate Off, Created
1294 * @vmstateto N/A
1295 */
1296VMR3DECL(int) VMR3Destroy(PVM pVM)
1297{
1298 LogFlow(("VMR3Destroy: pVM=%p\n", pVM));
1299
1300 /*
1301 * Validate input.
1302 */
1303 if (!pVM)
1304 return VERR_INVALID_PARAMETER;
1305 if ( pVM->enmVMState != VMSTATE_OFF
1306 && pVM->enmVMState != VMSTATE_CREATED)
1307 {
1308 AssertMsgFailed(("Invalid VM state %d\n", pVM->enmVMState));
1309 return VERR_VM_INVALID_VM_STATE;
1310 }
1311
1312 /*
1313 * Unlink the VM and change it's state to destroying.
1314 */
1315/** @todo lock this when we start having multiple machines in a process... */
1316 PVM pPrev = NULL;
1317 PVM pCur = g_pVMsHead;
1318 while (pCur && pCur != pVM)
1319 {
1320 pPrev = pCur;
1321 pCur = pCur->pNext;
1322 }
1323 if (!pCur)
1324 {
1325 AssertMsgFailed(("pVM=%p is INVALID!\n", pVM));
1326 return VERR_INVALID_PARAMETER;
1327 }
1328 if (pPrev)
1329 pPrev->pNext = pCur->pNext;
1330 else
1331 g_pVMsHead = pCur->pNext;
1332
1333 vmR3SetState(pVM, VMSTATE_DESTROYING);
1334
1335
1336 /*
1337 * Notify registered at destruction listeners.
1338 * (That's the debugger console.)
1339 */
1340 vmR3AtDtor(pVM);
1341
1342 pVM->pNext = g_pVMsHead;
1343 g_pVMsHead = pVM;
1344
1345 /*
1346 * If we are the EMT we'll delay the cleanup till later.
1347 */
1348 if (VM_IS_EMT(pVM))
1349 {
1350 pVM->vm.s.fEMTDoesTheCleanup = true;
1351 VM_FF_SET(pVM, VM_FF_TERMINATE);
1352 }
1353 else
1354 {
1355 /*
1356 * Request EMT to do the larger part of the destruction.
1357 */
1358 PVMREQ pReq = NULL;
1359 int rc = VMR3ReqCall(pVM, &pReq, 0, (PFNRT)vmR3Destroy, 1, pVM);
1360 while (rc == VERR_TIMEOUT)
1361 rc = VMR3ReqWait(pReq, RT_INDEFINITE_WAIT);
1362 if (VBOX_SUCCESS(rc))
1363 rc = pReq->iStatus;
1364 VMR3ReqFree(pReq);
1365
1366 /*
1367 * Wait for the EMT thread to terminate.
1368 */
1369 VM_FF_SET(pVM, VM_FF_TERMINATE);
1370 uint64_t u64Start = RTTimeMilliTS();
1371 do
1372 {
1373 VMR3NotifyFF(pVM, false);
1374 rc = RTThreadWait(pVM->ThreadEMT, 1000, NULL);
1375 } while ( RTTimeMilliTS() - u64Start < 30000 /* 30 sec */
1376 && rc == VERR_TIMEOUT);
1377 AssertMsgRC(rc, ("EMT thread wait failed, rc=%Vrc\n", rc));
1378
1379 /*
1380 * Now do the final bit where the heap and VM structures are freed up.
1381 */
1382 vmR3DestroyFinalBit(pVM);
1383 }
1384
1385 LogFlow(("VMR3Destroy: returns VINF_SUCCESS\n"));
1386 return VINF_SUCCESS;
1387}
1388
1389
1390/**
1391 * Internal destruction worker. This will do nearly all of the
1392 * job, including quitting the emulation thread.
1393 *
1394 * @returns VBox status.
1395 * @param pVM VM handle.
1396 */
1397DECLCALLBACK(int) vmR3Destroy(PVM pVM)
1398{
1399 LogFlow(("vmR3Destroy: pVM=%p\n", pVM));
1400 VM_ASSERT_EMT(pVM);
1401
1402 /*
1403 * Dump statistics to the log.
1404 */
1405#if defined(VBOX_WITH_STATISTICS) || defined(LOG_ENABLED)
1406 RTLogFlags(NULL, "nodisabled nobuffered");
1407#endif
1408#ifdef VBOX_WITH_STATISTICS
1409 STAMR3Dump(pVM, "*");
1410#endif /* VBOX_WITH_STATISTICS */
1411
1412 /*
1413 * Destroy the VM components.
1414 */
1415 int rc = TMR3Term(pVM);
1416 AssertRC(rc);
1417 rc = DBGCTcpTerminate(pVM, pVM->vm.s.pvDBGC);
1418 pVM->vm.s.pvDBGC = NULL;
1419 AssertRC(rc);
1420 rc = DBGFR3Term(pVM);
1421 AssertRC(rc);
1422 rc = PDMR3Term(pVM);
1423 AssertRC(rc);
1424 rc = EMR3Term(pVM);
1425 AssertRC(rc);
1426 rc = IOMR3Term(pVM);
1427 AssertRC(rc);
1428 rc = CSAMR3Term(pVM);
1429 AssertRC(rc);
1430 rc = PATMR3Term(pVM);
1431 AssertRC(rc);
1432 rc = TRPMR3Term(pVM);
1433 AssertRC(rc);
1434 rc = SELMR3Term(pVM);
1435 AssertRC(rc);
1436 rc = REMR3Term(pVM);
1437 AssertRC(rc);
1438 rc = HWACCMR3Term(pVM);
1439 AssertRC(rc);
1440 rc = VMMR3Term(pVM);
1441 AssertRC(rc);
1442 rc = PGMR3Term(pVM);
1443 AssertRC(rc);
1444 rc = CPUMR3Term(pVM);
1445 AssertRC(rc);
1446 rc = STAMR3Term(pVM);
1447 AssertRC(rc);
1448 rc = PDMR3CritSectTerm(pVM);
1449 AssertRC(rc);
1450 /* MM is destroyed later in vmR3DestroyFinalBit() for heap reasons. */
1451
1452 /*
1453 * We're done in this thread.
1454 */
1455 pVM->fForcedActions = VM_FF_TERMINATE;
1456 LogFlow(("vmR3Destroy: returning %Vrc\n", VINF_EM_TERMINATE));
1457 return VINF_EM_TERMINATE;
1458}
1459
1460
1461/**
1462 * Does the final part of the VM destruction.
1463 * This is called by EMT in it's final stage or by the VMR3Destroy caller.
1464 *
1465 * @param pVM VM Handle.
1466 */
1467void vmR3DestroyFinalBit(PVM pVM)
1468{
1469 /*
1470 * Free the event semaphores associated with the request packets.s
1471 */
1472 unsigned cReqs = 0;
1473 for (unsigned i = 0; i < ELEMENTS(pVM->vm.s.apReqFree); i++)
1474 {
1475 PVMREQ pReq = pVM->vm.s.apReqFree[i];
1476 pVM->vm.s.apReqFree[i] = NULL;
1477 for (; pReq; pReq = pReq->pNext, cReqs++)
1478 {
1479 pReq->enmState = VMREQSTATE_INVALID;
1480 RTSemEventDestroy(pReq->EventSem);
1481 }
1482 }
1483 Assert(cReqs == pVM->vm.s.cReqFree); NOREF(cReqs);
1484
1485 /*
1486 * Kill all queued requests. (There really shouldn't be any!)
1487 */
1488 for (unsigned i = 0; i < 10; i++)
1489 {
1490 PVMREQ pReqHead = (PVMREQ)ASMAtomicXchgPtr((void *volatile *)&pVM->vm.s.pReqs, NULL);
1491 AssertMsg(!pReqHead, ("This isn't supposed to happen! VMR3Destroy caller has to serialize this.\n"));
1492 if (!pReqHead)
1493 break;
1494 for (PVMREQ pReq = pReqHead; pReq; pReq = pReq->pNext)
1495 {
1496 ASMAtomicXchgSize(&pReq->iStatus, VERR_INTERNAL_ERROR);
1497 ASMAtomicXchgSize(&pReq->enmState, VMREQSTATE_INVALID);
1498 RTSemEventSignal(pReq->EventSem);
1499 RTThreadSleep(2);
1500 RTSemEventDestroy(pReq->EventSem);
1501 }
1502 /* give them a chance to respond before we free the request memory. */
1503 RTThreadSleep(32);
1504 }
1505
1506 /*
1507 * Modify state and then terminate MM.
1508 * (MM must be delayed until this point so we don't destroy the callbacks and the request packet.)
1509 */
1510 vmR3SetState(pVM, VMSTATE_TERMINATED);
1511 int rc = MMR3Term(pVM);
1512 AssertRC(rc);
1513
1514 /*
1515 * Free the VM structure.
1516 */
1517 rc = SUPContFree(pVM);
1518 AssertRC(rc);
1519 rc = SUPTerm();
1520 AssertRC(rc);
1521
1522 RTLogFlush(NULL);
1523}
1524
1525
1526/**
1527 * Enumerates the VMs in this process.
1528 *
1529 * @returns Pointer to the next VM.
1530 * @returns NULL when no more VMs.
1531 * @param pVMPrev The previous VM
1532 * Use NULL to start the enumeration.
1533 */
1534VMR3DECL(PVM) VMR3EnumVMs(PVM pVMPrev)
1535{
1536 /*
1537 * This is quick and dirty. It has issues with VM being
1538 * destroyed during the enumeration.
1539 */
1540 if (pVMPrev)
1541 return pVMPrev->pNext;
1542 return g_pVMsHead;
1543}
1544
1545
1546/**
1547 * Registers an at VM destruction callback.
1548 *
1549 * @returns VBox status code.
1550 * @param pfnAtDtor Pointer to callback.
1551 * @param pvUser User argument.
1552 */
1553VMR3DECL(int) VMR3AtDtorRegister(PFNVMATDTOR pfnAtDtor, void *pvUser)
1554{
1555 /*
1556 * Check if already registered.
1557 */
1558 VM_ATDTOR_LOCK();
1559 PVMATDTOR pCur = g_pVMAtDtorHead;
1560 while (pCur)
1561 {
1562 if (pfnAtDtor == pCur->pfnAtDtor)
1563 {
1564 VM_ATDTOR_UNLOCK();
1565 AssertMsgFailed(("Already registered at destruction callback %p!\n", pfnAtDtor));
1566 return VERR_INVALID_PARAMETER;
1567 }
1568
1569 /* next */
1570 pCur = pCur->pNext;
1571 }
1572 VM_ATDTOR_UNLOCK();
1573
1574 /*
1575 * Allocate new entry.
1576 */
1577 PVMATDTOR pVMAtDtor = (PVMATDTOR)RTMemAlloc(sizeof(*pVMAtDtor));
1578 if (!pVMAtDtor)
1579 return VERR_NO_MEMORY;
1580
1581 VM_ATDTOR_LOCK();
1582 pVMAtDtor->pfnAtDtor = pfnAtDtor;
1583 pVMAtDtor->pvUser = pvUser;
1584 pVMAtDtor->pNext = g_pVMAtDtorHead;
1585 g_pVMAtDtorHead = pVMAtDtor;
1586 VM_ATDTOR_UNLOCK();
1587
1588 return VINF_SUCCESS;
1589}
1590
1591
1592/**
1593 * Deregisters an at VM destruction callback.
1594 *
1595 * @returns VBox status code.
1596 * @param pfnAtDtor Pointer to callback.
1597 */
1598VMR3DECL(int) VMR3AtDtorDeregister(PFNVMATDTOR pfnAtDtor)
1599{
1600 /*
1601 * Find it, unlink it and free it.
1602 */
1603 VM_ATDTOR_LOCK();
1604 PVMATDTOR pPrev = NULL;
1605 PVMATDTOR pCur = g_pVMAtDtorHead;
1606 while (pCur)
1607 {
1608 if (pfnAtDtor == pCur->pfnAtDtor)
1609 {
1610 if (pPrev)
1611 pPrev->pNext = pCur->pNext;
1612 else
1613 g_pVMAtDtorHead = pCur->pNext;
1614 pCur->pNext = NULL;
1615 VM_ATDTOR_UNLOCK();
1616
1617 RTMemFree(pCur);
1618 return VINF_SUCCESS;
1619 }
1620
1621 /* next */
1622 pPrev = pCur;
1623 pCur = pCur->pNext;
1624 }
1625 VM_ATDTOR_UNLOCK();
1626
1627 return VERR_INVALID_PARAMETER;
1628}
1629
1630
1631/**
1632 * Walks the list of at VM destructor callbacks.
1633 * @param pVM The VM which is about to be destroyed.
1634 */
1635static void vmR3AtDtor(PVM pVM)
1636{
1637 /*
1638 * Find it, unlink it and free it.
1639 */
1640 VM_ATDTOR_LOCK();
1641 for (PVMATDTOR pCur = g_pVMAtDtorHead; pCur; pCur = pCur->pNext)
1642 pCur->pfnAtDtor(pVM, pCur->pvUser);
1643 VM_ATDTOR_UNLOCK();
1644}
1645
1646
1647/**
1648 * Reset the current VM.
1649 *
1650 * @returns VBox status code.
1651 * @param pVM VM to reset.
1652 */
1653VMR3DECL(int) VMR3Reset(PVM pVM)
1654{
1655 int rc = VINF_SUCCESS;
1656
1657 /*
1658 * Check the state.
1659 */
1660 if (!pVM)
1661 return VERR_INVALID_PARAMETER;
1662 if ( pVM->enmVMState != VMSTATE_RUNNING
1663 && pVM->enmVMState != VMSTATE_SUSPENDED)
1664 {
1665 AssertMsgFailed(("Invalid VM state %d\n", pVM->enmVMState));
1666 return VERR_VM_INVALID_VM_STATE;
1667 }
1668
1669 /*
1670 * Queue reset request to the emulation thread
1671 * and wait for it to be processed.
1672 */
1673 PVMREQ pReq = NULL;
1674 rc = VMR3ReqCall(pVM, &pReq, 0, (PFNRT)vmR3Reset, 1, pVM);
1675 while (rc == VERR_TIMEOUT)
1676 rc = VMR3ReqWait(pReq, RT_INDEFINITE_WAIT);
1677 if (VBOX_SUCCESS(rc))
1678 rc = pReq->iStatus;
1679 VMR3ReqFree(pReq);
1680
1681 return rc;
1682}
1683
1684
1685/**
1686 * Worker which checks integrity of some internal structures.
1687 * This is yet another attempt to track down that AVL tree crash.
1688 */
1689static void vmR3CheckIntegrity(PVM pVM)
1690{
1691#ifdef VBOX_STRICT
1692 int rc = PGMR3CheckIntegrity(pVM);
1693 AssertReleaseRC(rc);
1694#endif
1695}
1696
1697
1698/**
1699 * Reset request processor.
1700 *
1701 * This is called by the emulation thread as a response to the
1702 * reset request issued by VMR3Reset().
1703 *
1704 * @returns VBox status code.
1705 * @param pVM VM to reset.
1706 */
1707static DECLCALLBACK(int) vmR3Reset(PVM pVM)
1708{
1709 /*
1710 * As a safety precaution we temporarily change the state while resetting.
1711 * (If VMR3Reset was not called from EMT we might have change state... let's ignore that fact for now.)
1712 */
1713 VMSTATE enmVMState = pVM->enmVMState;
1714 Assert(enmVMState == VMSTATE_SUSPENDED || enmVMState == VMSTATE_RUNNING);
1715 vmR3SetState(pVM, VMSTATE_RESETTING);
1716 vmR3CheckIntegrity(pVM);
1717
1718
1719 /*
1720 * Reset the VM components.
1721 */
1722 PATMR3Reset(pVM);
1723 CSAMR3Reset(pVM);
1724 PGMR3Reset(pVM); /* We clear VM RAM in PGMR3Reset. It's vital PDMR3Reset is executed
1725 * _afterwards_. E.g. ACPI sets up RAM tables during init/reset. */
1726 PDMR3Reset(pVM);
1727 SELMR3Reset(pVM);
1728 TRPMR3Reset(pVM);
1729 vmR3AtReset(pVM);
1730 REMR3Reset(pVM);
1731 IOMR3Reset(pVM);
1732 CPUMR3Reset(pVM);
1733 TMR3Reset(pVM);
1734 EMR3Reset(pVM);
1735 HWACCMR3Reset(pVM); /* This must come *after* PATM, CSAM, CPUM, SELM and TRPM. */
1736
1737#ifdef LOG_ENABLED
1738 /*
1739 * Debug logging.
1740 */
1741 RTLogPrintf("\n\nThe VM was reset:\n");
1742 DBGFR3Info(pVM, "cpum", "verbose", NULL);
1743#endif
1744
1745 /*
1746 * Restore the state.
1747 */
1748 vmR3CheckIntegrity(pVM);
1749 Assert(pVM->enmVMState == VMSTATE_RESETTING);
1750 vmR3SetState(pVM, enmVMState);
1751
1752 return VINF_EM_RESET;
1753}
1754
1755
1756/**
1757 * Walks the list of at VM reset callbacks and calls them
1758 *
1759 * @returns VBox status code.
1760 * Any failure is fatal.
1761 * @param pVM The VM which is being reset.
1762 */
1763static int vmR3AtReset(PVM pVM)
1764{
1765 /*
1766 * Walk the list and call them all.
1767 */
1768 int rc = VINF_SUCCESS;
1769 for (PVMATRESET pCur = pVM->vm.s.pAtReset; pCur; pCur = pCur->pNext)
1770 {
1771 /* do the call */
1772 switch (pCur->enmType)
1773 {
1774 case VMATRESETTYPE_DEV:
1775 rc = pCur->u.Dev.pfnCallback(pCur->u.Dev.pDevIns, pCur->pvUser);
1776 break;
1777 case VMATRESETTYPE_INTERNAL:
1778 rc = pCur->u.Internal.pfnCallback(pVM, pCur->pvUser);
1779 break;
1780 case VMATRESETTYPE_EXTERNAL:
1781 pCur->u.External.pfnCallback(pCur->pvUser);
1782 break;
1783 default:
1784 AssertMsgFailed(("Invalid at-reset type %d!\n", pCur->enmType));
1785 return VERR_INTERNAL_ERROR;
1786 }
1787
1788 if (VBOX_FAILURE(rc))
1789 {
1790 AssertMsgFailed(("At-reset handler %s failed with rc=%d\n", pCur->pszDesc, rc));
1791 return rc;
1792 }
1793 }
1794
1795 return VINF_SUCCESS;
1796}
1797
1798
1799/**
1800 * Internal registration function
1801 */
1802static int vmr3AtResetRegister(PVM pVM, void *pvUser, const char *pszDesc, PVMATRESET *ppNew)
1803{
1804 /*
1805 * Allocate restration structure.
1806 */
1807 PVMATRESET pNew = (PVMATRESET)MMR3HeapAlloc(pVM, MM_TAG_VM, sizeof(*pNew));
1808 if (pNew)
1809 {
1810 /* fill data. */
1811 pNew->pNext = NULL;
1812 pNew->pszDesc = pszDesc;
1813 pNew->pvUser = pvUser;
1814
1815 /* insert */
1816 *pVM->vm.s.ppAtResetNext = pNew;
1817 pVM->vm.s.ppAtResetNext = &pNew->pNext;
1818
1819 return VINF_SUCCESS;
1820 }
1821 return VERR_NO_MEMORY;
1822}
1823
1824
1825/**
1826 * Registers an at VM reset callback.
1827 *
1828 * @returns VBox status code.
1829 * @param pVM The VM.
1830 * @param pDevInst Device instance.
1831 * @param pfnCallback Callback function.
1832 * @param pvUser User argument.
1833 * @param pszDesc Description (optional).
1834 */
1835VMR3DECL(int) VMR3AtResetRegister(PVM pVM, PPDMDEVINS pDevInst, PFNVMATRESET pfnCallback, void *pvUser, const char *pszDesc)
1836{
1837 /*
1838 * Validate.
1839 */
1840 if (!pDevInst)
1841 {
1842 AssertMsgFailed(("pDevIns is NULL!\n"));
1843 return VERR_INVALID_PARAMETER;
1844 }
1845
1846 /*
1847 * Create the new entry.
1848 */
1849 PVMATRESET pNew;
1850 int rc = vmr3AtResetRegister(pVM, pvUser, pszDesc, &pNew);
1851 if (VBOX_SUCCESS(rc))
1852 {
1853 /*
1854 * Fill in type data.
1855 */
1856 pNew->enmType = VMATRESETTYPE_DEV;
1857 pNew->u.Dev.pfnCallback = pfnCallback;
1858 pNew->u.Dev.pDevIns = pDevInst;
1859 }
1860
1861 return rc;
1862}
1863
1864
1865/**
1866 * Registers an at VM reset internal callback.
1867 *
1868 * @returns VBox status code.
1869 * @param pVM The VM.
1870 * @param pfnCallback Callback function.
1871 * @param pvUser User argument.
1872 * @param pszDesc Description (optional).
1873 */
1874VMR3DECL(int) VMR3AtResetRegisterInternal(PVM pVM, PFNVMATRESETINT pfnCallback, void *pvUser, const char *pszDesc)
1875{
1876 /*
1877 * Validate.
1878 */
1879 if (!pfnCallback)
1880 {
1881 AssertMsgFailed(("pfnCallback is NULL!\n"));
1882 return VERR_INVALID_PARAMETER;
1883 }
1884
1885 /*
1886 * Create the new entry.
1887 */
1888 PVMATRESET pNew;
1889 int rc = vmr3AtResetRegister(pVM, pvUser, pszDesc, &pNew);
1890 if (VBOX_SUCCESS(rc))
1891 {
1892 /*
1893 * Fill in type data.
1894 */
1895 pNew->enmType = VMATRESETTYPE_INTERNAL;
1896 pNew->u.Internal.pfnCallback = pfnCallback;
1897 }
1898
1899 return rc;
1900}
1901
1902
1903/**
1904 * Registers an at VM reset external callback.
1905 *
1906 * @returns VBox status code.
1907 * @param pVM The VM.
1908 * @param pfnCallback Callback function.
1909 * @param pvUser User argument.
1910 * @param pszDesc Description (optional).
1911 */
1912VMR3DECL(int) VMR3AtResetRegisterExternal(PVM pVM, PFNVMATRESETEXT pfnCallback, void *pvUser, const char *pszDesc)
1913{
1914 /*
1915 * Validate.
1916 */
1917 if (!pfnCallback)
1918 {
1919 AssertMsgFailed(("pfnCallback is NULL!\n"));
1920 return VERR_INVALID_PARAMETER;
1921 }
1922
1923 /*
1924 * Create the new entry.
1925 */
1926 PVMATRESET pNew;
1927 int rc = vmr3AtResetRegister(pVM, pvUser, pszDesc, &pNew);
1928 if (VBOX_SUCCESS(rc))
1929 {
1930 /*
1931 * Fill in type data.
1932 */
1933 pNew->enmType = VMATRESETTYPE_EXTERNAL;
1934 pNew->u.External.pfnCallback = pfnCallback;
1935 }
1936
1937 return rc;
1938}
1939
1940
1941/**
1942 * Unlinks and frees a callback.
1943 *
1944 * @returns Pointer to the next callback structure.
1945 * @param pVM The VM.
1946 * @param pCur The one to free.
1947 * @param pPrev The one before pCur.
1948 */
1949static PVMATRESET vmr3AtResetFree(PVM pVM, PVMATRESET pCur, PVMATRESET pPrev)
1950{
1951 /*
1952 * Unlink it.
1953 */
1954 PVMATRESET pNext = pCur->pNext;
1955 if (pPrev)
1956 {
1957 pPrev->pNext = pNext;
1958 if (!pNext)
1959 pVM->vm.s.ppAtResetNext = &pPrev->pNext;
1960 }
1961 else
1962 {
1963 pVM->vm.s.pAtReset = pNext;
1964 if (!pNext)
1965 pVM->vm.s.ppAtResetNext = &pVM->vm.s.pAtReset;
1966 }
1967
1968 /*
1969 * Free it.
1970 */
1971 MMR3HeapFree(pCur);
1972
1973 return pNext;
1974}
1975
1976
1977/**
1978 * Deregisters an at VM reset callback.
1979 *
1980 * @returns VBox status code.
1981 * @param pVM The VM.
1982 * @param pDevInst Device instance.
1983 * @param pfnCallback Callback function.
1984 */
1985VMR3DECL(int) VMR3AtResetDeregister(PVM pVM, PPDMDEVINS pDevInst, PFNVMATRESET pfnCallback)
1986{
1987 int rc = VERR_VM_ATRESET_NOT_FOUND;
1988 PVMATRESET pPrev = NULL;
1989 PVMATRESET pCur = pVM->vm.s.pAtReset;
1990 while (pCur)
1991 {
1992 if ( pCur->enmType == VMATRESETTYPE_DEV
1993 && pCur->u.Dev.pDevIns == pDevInst
1994 && (!pfnCallback || pCur->u.Dev.pfnCallback == pfnCallback))
1995 {
1996 pCur = vmr3AtResetFree(pVM, pCur, pPrev);
1997 rc = VINF_SUCCESS;
1998 }
1999 else
2000 {
2001 pPrev = pCur;
2002 pCur = pCur->pNext;
2003 }
2004 }
2005
2006 AssertRC(rc);
2007 return rc;
2008}
2009
2010
2011/**
2012 * Deregisters an at VM reset internal callback.
2013 *
2014 * @returns VBox status code.
2015 * @param pVM The VM.
2016 * @param pfnCallback Callback function.
2017 */
2018VMR3DECL(int) VMR3AtResetDeregisterInternal(PVM pVM, PFNVMATRESETINT pfnCallback)
2019{
2020 int rc = VERR_VM_ATRESET_NOT_FOUND;
2021 PVMATRESET pPrev = NULL;
2022 PVMATRESET pCur = pVM->vm.s.pAtReset;
2023 while (pCur)
2024 {
2025 if ( pCur->enmType == VMATRESETTYPE_INTERNAL
2026 && pCur->u.Internal.pfnCallback == pfnCallback)
2027 {
2028 pCur = vmr3AtResetFree(pVM, pCur, pPrev);
2029 rc = VINF_SUCCESS;
2030 }
2031 else
2032 {
2033 pPrev = pCur;
2034 pCur = pCur->pNext;
2035 }
2036 }
2037
2038 AssertRC(rc);
2039 return rc;
2040}
2041
2042
2043/**
2044 * Deregisters an at VM reset external callback.
2045 *
2046 * @returns VBox status code.
2047 * @param pVM The VM.
2048 * @param pfnCallback Callback function.
2049 */
2050VMR3DECL(int) VMR3AtResetDeregisterExternal(PVM pVM, PFNVMATRESETEXT pfnCallback)
2051{
2052 int rc = VERR_VM_ATRESET_NOT_FOUND;
2053 PVMATRESET pPrev = NULL;
2054 PVMATRESET pCur = pVM->vm.s.pAtReset;
2055 while (pCur)
2056 {
2057 if ( pCur->enmType == VMATRESETTYPE_INTERNAL
2058 && pCur->u.External.pfnCallback == pfnCallback)
2059 {
2060 pCur = vmr3AtResetFree(pVM, pCur, pPrev);
2061 rc = VINF_SUCCESS;
2062 }
2063 else
2064 {
2065 pPrev = pCur;
2066 pCur = pCur->pNext;
2067 }
2068 }
2069
2070 AssertRC(rc);
2071 return rc;
2072}
2073
2074
2075/**
2076 * Gets the current VM state.
2077 *
2078 * @returns The current VM state.
2079 * @param pVM VM handle.
2080 * @thread Any
2081 */
2082VMR3DECL(VMSTATE) VMR3GetState(PVM pVM)
2083{
2084 return pVM->enmVMState;
2085}
2086
2087
2088/**
2089 * Gets the state name string for a VM state.
2090 *
2091 * @returns Pointer to the state name. (readonly)
2092 * @param enmState The state.
2093 */
2094VMR3DECL(const char *) VMR3GetStateName(VMSTATE enmState)
2095{
2096 switch (enmState)
2097 {
2098 case VMSTATE_CREATING: return "CREATING";
2099 case VMSTATE_CREATED: return "CREATED";
2100 case VMSTATE_RUNNING: return "RUNNING";
2101 case VMSTATE_LOADING: return "LOADING";
2102 case VMSTATE_LOAD_FAILURE: return "LOAD_FAILURE";
2103 case VMSTATE_SAVING: return "SAVING";
2104 case VMSTATE_SUSPENDED: return "SUSPENDED";
2105 case VMSTATE_RESETTING: return "RESETTING";
2106 case VMSTATE_GURU_MEDITATION: return "GURU_MEDIATION";
2107 case VMSTATE_OFF: return "OFF";
2108 case VMSTATE_DESTROYING: return "DESTROYING";
2109 case VMSTATE_TERMINATED: return "TERMINATED";
2110 default:
2111 AssertMsgFailed(("Unknown state %d\n", enmState));
2112 return "Unknown!\n";
2113 }
2114}
2115
2116
2117/**
2118 * Sets the current VM state.
2119 *
2120 * @returns The current VM state.
2121 * @param pVM VM handle.
2122 * @param enmStateNew The new state.
2123 */
2124static void vmR3SetState(PVM pVM, VMSTATE enmStateNew)
2125{
2126 VMSTATE enmStateOld = pVM->enmVMState;
2127 pVM->enmVMState = enmStateNew;
2128 LogRel(("Changing the VM state from '%s' to '%s'.\n", VMR3GetStateName(enmStateOld), VMR3GetStateName(enmStateNew)));
2129
2130 /*
2131 * Call the at state change callbacks.
2132 */
2133 for (PVMATSTATE pCur = pVM->vm.s.pAtState; pCur; pCur = pCur->pNext)
2134 {
2135 pCur->pfnAtState(pVM, enmStateNew, enmStateOld, pCur->pvUser);
2136 if (pVM->enmVMState == VMSTATE_DESTROYING)
2137 break;
2138 AssertMsg(pVM->enmVMState == enmStateNew,
2139 ("You are not allowed to change the state while in the change callback, except "
2140 "from destroying the VM. There are restrictions in the way the state changes "
2141 "are propagated up to the EM execution loop and it makes the program flow very "
2142 "difficult to follow.\n"));
2143 }
2144}
2145
2146
2147/**
2148 * Registers a VM state change callback.
2149 *
2150 * You are not allowed to call any function which changes the VM state from a
2151 * state callback, except VMR3Destroy().
2152 *
2153 * @returns VBox status code.
2154 * @param pVM VM handle.
2155 * @param pfnAtState Pointer to callback.
2156 * @param pvUser User argument.
2157 * @thread Any.
2158 */
2159VMR3DECL(int) VMR3AtStateRegister(PVM pVM, PFNVMATSTATE pfnAtState, void *pvUser)
2160{
2161 LogFlow(("VMR3AtStateRegister: pfnAtState=%p pvUser=%p\n", pfnAtState, pvUser));
2162
2163 /*
2164 * Validate input.
2165 */
2166 if (!pfnAtState)
2167 {
2168 AssertMsgFailed(("callback is required\n"));
2169 return VERR_INVALID_PARAMETER;
2170 }
2171
2172 /*
2173 * Make sure we're in EMT (to avoid the logging).
2174 */
2175 PVMREQ pReq;
2176 int rc = VMR3ReqCall(pVM, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3AtStateRegister, 3, pVM, pfnAtState, pvUser);
2177 if (VBOX_FAILURE(rc))
2178 return rc;
2179 rc = pReq->iStatus;
2180 VMR3ReqFree(pReq);
2181
2182 LogFlow(("VMR3AtStateRegister: returns %Vrc\n", rc));
2183 return rc;
2184}
2185
2186
2187/**
2188 * Registers a VM state change callback.
2189 *
2190 * @returns VBox status code.
2191 * @param pVM VM handle.
2192 * @param pfnAtState Pointer to callback.
2193 * @param pvUser User argument.
2194 * @thread EMT
2195 */
2196static DECLCALLBACK(int) vmR3AtStateRegister(PVM pVM, PFNVMATSTATE pfnAtState, void *pvUser)
2197{
2198 /*
2199 * Allocate a new record.
2200 */
2201
2202 PVMATSTATE pNew = (PVMATSTATE)MMR3HeapAlloc(pVM, MM_TAG_VM, sizeof(*pNew));
2203 if (!pNew)
2204 return VERR_NO_MEMORY;
2205
2206 /* fill */
2207 pNew->pfnAtState = pfnAtState;
2208 pNew->pvUser = pvUser;
2209 pNew->pNext = NULL;
2210
2211 /* insert */
2212 *pVM->vm.s.ppAtStateNext = pNew;
2213 pVM->vm.s.ppAtStateNext = &pNew->pNext;
2214
2215 return VINF_SUCCESS;
2216}
2217
2218
2219/**
2220 * Deregisters a VM state change callback.
2221 *
2222 * @returns VBox status code.
2223 * @param pVM VM handle.
2224 * @param pfnAtState Pointer to callback.
2225 * @param pvUser User argument.
2226 * @thread Any.
2227 */
2228VMR3DECL(int) VMR3AtStateDeregister(PVM pVM, PFNVMATSTATE pfnAtState, void *pvUser)
2229{
2230 LogFlow(("VMR3AtStateDeregister: pfnAtState=%p pvUser=%p\n", pfnAtState, pvUser));
2231
2232 /*
2233 * Validate input.
2234 */
2235 if (!pfnAtState)
2236 {
2237 AssertMsgFailed(("callback is required\n"));
2238 return VERR_INVALID_PARAMETER;
2239 }
2240
2241 /*
2242 * Make sure we're in EMT (to avoid the logging).
2243 */
2244 PVMREQ pReq;
2245 int rc = VMR3ReqCall(pVM, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3AtStateDeregister, 3, pVM, pfnAtState, pvUser);
2246 if (VBOX_FAILURE(rc))
2247 return rc;
2248 rc = pReq->iStatus;
2249 VMR3ReqFree(pReq);
2250
2251 LogFlow(("VMR3AtStateDeregister: returns %Vrc\n", rc));
2252 return rc;
2253}
2254
2255
2256/**
2257 * Deregisters a VM state change callback.
2258 *
2259 * @returns VBox status code.
2260 * @param pVM VM handle.
2261 * @param pfnAtState Pointer to callback.
2262 * @param pvUser User argument.
2263 * @thread EMT
2264 */
2265static DECLCALLBACK(int) vmR3AtStateDeregister(PVM pVM, PFNVMATSTATE pfnAtState, void *pvUser)
2266{
2267 LogFlow(("vmR3AtStateDeregister: pfnAtState=%p pvUser=%p\n", pfnAtState, pvUser));
2268
2269 /*
2270 * Search the list for the entry.
2271 */
2272 PVMATSTATE pPrev = NULL;
2273 PVMATSTATE pCur = pVM->vm.s.pAtState;
2274 while ( pCur
2275 && pCur->pfnAtState == pfnAtState
2276 && pCur->pvUser == pvUser)
2277 {
2278 pPrev = pCur;
2279 pCur = pCur->pNext;
2280 }
2281 if (!pCur)
2282 {
2283 AssertMsgFailed(("pfnAtState=%p was not found\n", pfnAtState));
2284 return VERR_FILE_NOT_FOUND;
2285 }
2286
2287 /*
2288 * Unlink it.
2289 */
2290 if (pPrev)
2291 {
2292 pPrev->pNext = pCur->pNext;
2293 if (!pCur->pNext)
2294 pVM->vm.s.ppAtStateNext = &pPrev->pNext;
2295 }
2296 else
2297 {
2298 pVM->vm.s.pAtState = pCur->pNext;
2299 if (!pCur->pNext)
2300 pVM->vm.s.ppAtStateNext = &pVM->vm.s.pAtState;
2301 }
2302
2303 /*
2304 * Free it.
2305 */
2306 pCur->pfnAtState = NULL;
2307 pCur->pNext = NULL;
2308 MMR3HeapFree(pCur);
2309
2310 return VINF_SUCCESS;
2311}
2312
2313
2314/**
2315 * Registers a VM error callback.
2316 *
2317 * @returns VBox status code.
2318 * @param pVM The VM handle.
2319 * @param pfnAtError Pointer to callback.
2320 * @param pvUser User argument.
2321 * @thread Any.
2322 */
2323VMR3DECL(int) VMR3AtErrorRegister(PVM pVM, PFNVMATERROR pfnAtError, void *pvUser)
2324{
2325 LogFlow(("VMR3AtErrorRegister: pfnAtError=%p pvUser=%p\n", pfnAtError, pvUser));
2326
2327 /*
2328 * Validate input.
2329 */
2330 if (!pfnAtError)
2331 {
2332 AssertMsgFailed(("callback is required\n"));
2333 return VERR_INVALID_PARAMETER;
2334 }
2335
2336 /*
2337 * Make sure we're in EMT (to avoid the logging).
2338 */
2339 PVMREQ pReq;
2340 int rc = VMR3ReqCall(pVM, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3AtErrorRegister, 3, pVM, pfnAtError, pvUser);
2341 if (VBOX_FAILURE(rc))
2342 return rc;
2343 rc = pReq->iStatus;
2344 VMR3ReqFree(pReq);
2345
2346 LogFlow(("VMR3AtErrorRegister: returns %Vrc\n", rc));
2347 return rc;
2348}
2349
2350
2351/**
2352 * Registers a VM error callback.
2353 *
2354 * @returns VBox status code.
2355 * @param pVM The VM handle.
2356 * @param pfnAtError Pointer to callback.
2357 * @param pvUser User argument.
2358 * @thread EMT
2359 */
2360static DECLCALLBACK(int) vmR3AtErrorRegister(PVM pVM, PFNVMATERROR pfnAtError, void *pvUser)
2361{
2362 /*
2363 * Allocate a new record.
2364 */
2365
2366 PVMATERROR pNew = (PVMATERROR)MMR3HeapAlloc(pVM, MM_TAG_VM, sizeof(*pNew));
2367 if (!pNew)
2368 return VERR_NO_MEMORY;
2369
2370 /* fill */
2371 pNew->pfnAtError = pfnAtError;
2372 pNew->pvUser = pvUser;
2373 pNew->pNext = NULL;
2374
2375 /* insert */
2376 *pVM->vm.s.ppAtErrorNext = pNew;
2377 pVM->vm.s.ppAtErrorNext = &pNew->pNext;
2378
2379 return VINF_SUCCESS;
2380}
2381
2382
2383/**
2384 * Deregisters a VM error callback.
2385 *
2386 * @returns VBox status code.
2387 * @param pVM The VM handle.
2388 * @param pfnAtError Pointer to callback.
2389 * @param pvUser User argument.
2390 * @thread Any.
2391 */
2392VMR3DECL(int) VMR3AtErrorDeregister(PVM pVM, PFNVMATERROR pfnAtError, void *pvUser)
2393{
2394 LogFlow(("VMR3AtErrorDeregister: pfnAtError=%p pvUser=%p\n", pfnAtError, pvUser));
2395
2396 /*
2397 * Validate input.
2398 */
2399 if (!pfnAtError)
2400 {
2401 AssertMsgFailed(("callback is required\n"));
2402 return VERR_INVALID_PARAMETER;
2403 }
2404
2405 /*
2406 * Make sure we're in EMT (to avoid the logging).
2407 */
2408 PVMREQ pReq;
2409 int rc = VMR3ReqCall(pVM, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3AtErrorDeregister, 3, pVM, pfnAtError, pvUser);
2410 if (VBOX_FAILURE(rc))
2411 return rc;
2412 rc = pReq->iStatus;
2413 VMR3ReqFree(pReq);
2414
2415 LogFlow(("VMR3AtErrorDeregister: returns %Vrc\n", rc));
2416 return rc;
2417}
2418
2419
2420/**
2421 * Deregisters a VM error callback.
2422 *
2423 * @returns VBox status code.
2424 * @param pVM The VM handle.
2425 * @param pfnAtError Pointer to callback.
2426 * @param pvUser User argument.
2427 * @thread EMT
2428 */
2429static DECLCALLBACK(int) vmR3AtErrorDeregister(PVM pVM, PFNVMATERROR pfnAtError, void *pvUser)
2430{
2431 LogFlow(("vmR3AtErrorDeregister: pfnAtError=%p pvUser=%p\n", pfnAtError, pvUser));
2432
2433 /*
2434 * Search the list for the entry.
2435 */
2436 PVMATERROR pPrev = NULL;
2437 PVMATERROR pCur = pVM->vm.s.pAtError;
2438 while ( pCur
2439 && pCur->pfnAtError == pfnAtError
2440 && pCur->pvUser == pvUser)
2441 {
2442 pPrev = pCur;
2443 pCur = pCur->pNext;
2444 }
2445 if (!pCur)
2446 {
2447 AssertMsgFailed(("pfnAtError=%p was not found\n", pfnAtError));
2448 return VERR_FILE_NOT_FOUND;
2449 }
2450
2451 /*
2452 * Unlink it.
2453 */
2454 if (pPrev)
2455 {
2456 pPrev->pNext = pCur->pNext;
2457 if (!pCur->pNext)
2458 pVM->vm.s.ppAtErrorNext = &pPrev->pNext;
2459 }
2460 else
2461 {
2462 pVM->vm.s.pAtError = pCur->pNext;
2463 if (!pCur->pNext)
2464 pVM->vm.s.ppAtErrorNext = &pVM->vm.s.pAtError;
2465 }
2466
2467 /*
2468 * Free it.
2469 */
2470 pCur->pfnAtError = NULL;
2471 pCur->pNext = NULL;
2472 MMR3HeapFree(pCur);
2473
2474 return VINF_SUCCESS;
2475}
2476
2477
2478/**
2479 * Ellipsis to va_list wrapper for calling pfnAtError.
2480 */
2481static void vmR3SetErrorWorkerDoCall(PVM pVM, PVMATERROR pCur, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...)
2482{
2483 va_list va;
2484 va_start(va, pszFormat);
2485 pCur->pfnAtError(pVM, pCur->pvUser, rc, RT_SRC_POS_ARGS, pszFormat, va);
2486 va_end(va);
2487}
2488
2489
2490/**
2491 * This is a worker function for GC and Ring-0 calls to VMSetError and VMSetErrorV.
2492 * The message is found in VMINT.
2493 *
2494 * @param pVM The VM handle.
2495 * @thread EMT.
2496 */
2497VMR3DECL(void) VMR3SetErrorWorker(PVM pVM)
2498{
2499 VM_ASSERT_EMT(pVM);
2500 AssertReleaseMsgFailed(("And we have a winner! You get to implement Ring-0 and GC VMSetErrorV! Contrats!\n"));
2501
2502 /*
2503 * Unpack the error (if we managed to format one).
2504 */
2505 PVMERROR pErr = pVM->vm.s.pErrorR3;
2506 const char *pszFile = NULL;
2507 const char *pszFunction = NULL;
2508 uint32_t iLine = 0;
2509 const char *pszMessage;
2510 int32_t rc = VERR_MM_HYPER_NO_MEMORY;
2511 if (pErr)
2512 {
2513 AssertCompile(sizeof(const char) == sizeof(uint8_t));
2514 if (pErr->offFile)
2515 pszFile = (const char *)pErr + pErr->offFile;
2516 iLine = pErr->iLine;
2517 if (pErr->offFunction)
2518 pszFunction = (const char *)pErr + pErr->offFunction;
2519 if (pErr->offMessage)
2520 pszMessage = (const char *)pErr + pErr->offMessage;
2521 else
2522 pszMessage = "No message!";
2523 }
2524 else
2525 pszMessage = "No message! (Failed to allocate memory to put the error message in!)";
2526
2527 /*
2528 * Call the at error callbacks.
2529 */
2530 for (PVMATERROR pCur = pVM->vm.s.pAtError; pCur; pCur = pCur->pNext)
2531 vmR3SetErrorWorkerDoCall(pVM, pCur, rc, RT_SRC_POS_ARGS, "%s", pszMessage);
2532}
2533
2534
2535/**
2536 * Worker which calls everyone listening to the VM error messages.
2537 *
2538 * @param pVM The VM handle.
2539 * @param rc The VBox status code.
2540 * @param RT_SRC_POS_DECL The source position of this error.
2541 * @param pszFormat Format string.
2542 * @param pArgs Pointer to the format arguments.
2543 * @thread EMT
2544 */
2545DECLCALLBACK(void) vmR3SetErrorV(PVM pVM, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list *pArgs)
2546{
2547 /*
2548 * Make a copy of the message.
2549 */
2550 vmSetErrorCopy(pVM, rc, RT_SRC_POS_ARGS, pszFormat, *pArgs);
2551
2552 /*
2553 * Call the at error callbacks.
2554 */
2555 for (PVMATERROR pCur = pVM->vm.s.pAtError; pCur; pCur = pCur->pNext)
2556 {
2557 va_list va2;
2558 va_copy(va2, *pArgs);
2559 pCur->pfnAtError(pVM, pCur->pvUser, rc, RT_SRC_POS_ARGS, pszFormat, va2);
2560 va_end(va2);
2561 }
2562}
2563
2564
2565/**
2566 * Registers a VM runtime error callback.
2567 *
2568 * @returns VBox status code.
2569 * @param pVM The VM handle.
2570 * @param pfnAtRuntimeError Pointer to callback.
2571 * @param pvUser User argument.
2572 * @thread Any.
2573 */
2574VMR3DECL(int) VMR3AtRuntimeErrorRegister(PVM pVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser)
2575{
2576 LogFlow(("VMR3AtRuntimeErrorRegister: pfnAtRuntimeError=%p pvUser=%p\n", pfnAtRuntimeError, pvUser));
2577
2578 /*
2579 * Validate input.
2580 */
2581 if (!pfnAtRuntimeError)
2582 {
2583 AssertMsgFailed(("callback is required\n"));
2584 return VERR_INVALID_PARAMETER;
2585 }
2586
2587 /*
2588 * Make sure we're in EMT (to avoid the logging).
2589 */
2590 PVMREQ pReq;
2591 int rc = VMR3ReqCall(pVM, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3AtRuntimeErrorRegister, 3, pVM, pfnAtRuntimeError, pvUser);
2592 if (VBOX_FAILURE(rc))
2593 return rc;
2594 rc = pReq->iStatus;
2595 VMR3ReqFree(pReq);
2596
2597 LogFlow(("VMR3AtRuntimeErrorRegister: returns %Vrc\n", rc));
2598 return rc;
2599}
2600
2601
2602/**
2603 * Registers a VM runtime error callback.
2604 *
2605 * @returns VBox status code.
2606 * @param pVM The VM handle.
2607 * @param pfnAtRuntimeError Pointer to callback.
2608 * @param pvUser User argument.
2609 * @thread EMT
2610 */
2611static DECLCALLBACK(int) vmR3AtRuntimeErrorRegister(PVM pVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser)
2612{
2613 /*
2614 * Allocate a new record.
2615 */
2616
2617 PVMATRUNTIMEERROR pNew = (PVMATRUNTIMEERROR)MMR3HeapAlloc(pVM, MM_TAG_VM, sizeof(*pNew));
2618 if (!pNew)
2619 return VERR_NO_MEMORY;
2620
2621 /* fill */
2622 pNew->pfnAtRuntimeError = pfnAtRuntimeError;
2623 pNew->pvUser = pvUser;
2624 pNew->pNext = NULL;
2625
2626 /* insert */
2627 *pVM->vm.s.ppAtRuntimeErrorNext = pNew;
2628 pVM->vm.s.ppAtRuntimeErrorNext = &pNew->pNext;
2629
2630 return VINF_SUCCESS;
2631}
2632
2633
2634/**
2635 * Deregisters a VM runtime error callback.
2636 *
2637 * @returns VBox status code.
2638 * @param pVM The VM handle.
2639 * @param pfnAtRuntimeError Pointer to callback.
2640 * @param pvUser User argument.
2641 * @thread Any.
2642 */
2643VMR3DECL(int) VMR3AtRuntimeErrorDeregister(PVM pVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser)
2644{
2645 LogFlow(("VMR3AtRuntimeErrorDeregister: pfnAtRuntimeError=%p pvUser=%p\n", pfnAtRuntimeError, pvUser));
2646
2647 /*
2648 * Validate input.
2649 */
2650 if (!pfnAtRuntimeError)
2651 {
2652 AssertMsgFailed(("callback is required\n"));
2653 return VERR_INVALID_PARAMETER;
2654 }
2655
2656 /*
2657 * Make sure we're in EMT (to avoid the logging).
2658 */
2659 PVMREQ pReq;
2660 int rc = VMR3ReqCall(pVM, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3AtRuntimeErrorDeregister, 3, pVM, pfnAtRuntimeError, pvUser);
2661 if (VBOX_FAILURE(rc))
2662 return rc;
2663 rc = pReq->iStatus;
2664 VMR3ReqFree(pReq);
2665
2666 LogFlow(("VMR3AtRuntimeErrorDeregister: returns %Vrc\n", rc));
2667 return rc;
2668}
2669
2670
2671/**
2672 * Deregisters a VM runtime error callback.
2673 *
2674 * @returns VBox status code.
2675 * @param pVM The VM handle.
2676 * @param pfnAtRuntimeError Pointer to callback.
2677 * @param pvUser User argument.
2678 * @thread EMT
2679 */
2680static DECLCALLBACK(int) vmR3AtRuntimeErrorDeregister(PVM pVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser)
2681{
2682 LogFlow(("vmR3AtRuntimeErrorDeregister: pfnAtRuntimeError=%p pvUser=%p\n", pfnAtRuntimeError, pvUser));
2683
2684 /*
2685 * Search the list for the entry.
2686 */
2687 PVMATRUNTIMEERROR pPrev = NULL;
2688 PVMATRUNTIMEERROR pCur = pVM->vm.s.pAtRuntimeError;
2689 while ( pCur
2690 && pCur->pfnAtRuntimeError == pfnAtRuntimeError
2691 && pCur->pvUser == pvUser)
2692 {
2693 pPrev = pCur;
2694 pCur = pCur->pNext;
2695 }
2696 if (!pCur)
2697 {
2698 AssertMsgFailed(("pfnAtRuntimeError=%p was not found\n", pfnAtRuntimeError));
2699 return VERR_FILE_NOT_FOUND;
2700 }
2701
2702 /*
2703 * Unlink it.
2704 */
2705 if (pPrev)
2706 {
2707 pPrev->pNext = pCur->pNext;
2708 if (!pCur->pNext)
2709 pVM->vm.s.ppAtRuntimeErrorNext = &pPrev->pNext;
2710 }
2711 else
2712 {
2713 pVM->vm.s.pAtRuntimeError = pCur->pNext;
2714 if (!pCur->pNext)
2715 pVM->vm.s.ppAtRuntimeErrorNext = &pVM->vm.s.pAtRuntimeError;
2716 }
2717
2718 /*
2719 * Free it.
2720 */
2721 pCur->pfnAtRuntimeError = NULL;
2722 pCur->pNext = NULL;
2723 MMR3HeapFree(pCur);
2724
2725 return VINF_SUCCESS;
2726}
2727
2728
2729/**
2730 * Ellipsis to va_list wrapper for calling pfnAtRuntimeError.
2731 */
2732static void vmR3SetRuntimeErrorWorkerDoCall(PVM pVM, PVMATRUNTIMEERROR pCur, bool fFatal,
2733 const char *pszErrorID,
2734 const char *pszFormat, ...)
2735{
2736 va_list va;
2737 va_start(va, pszFormat);
2738 pCur->pfnAtRuntimeError(pVM, pCur->pvUser, fFatal, pszErrorID, pszFormat, va);
2739 va_end(va);
2740}
2741
2742
2743/**
2744 * This is a worker function for GC and Ring-0 calls to VMSetError and VMSetErrorV.
2745 * The message is found in VMINT.
2746 *
2747 * @param pVM The VM handle.
2748 * @thread EMT.
2749 */
2750VMR3DECL(void) VMR3SetRuntimeErrorWorker(PVM pVM)
2751{
2752 VM_ASSERT_EMT(pVM);
2753 AssertReleaseMsgFailed(("And we have a winner! You get to implement Ring-0 and GC VMSetRuntimeErrorV! Contrats!\n"));
2754
2755 /*
2756 * Unpack the error (if we managed to format one).
2757 */
2758 PVMRUNTIMEERROR pErr = pVM->vm.s.pRuntimeErrorR3;
2759 const char *pszErrorID = NULL;
2760 const char *pszMessage;
2761 bool fFatal = false;
2762 if (pErr)
2763 {
2764 AssertCompile(sizeof(const char) == sizeof(uint8_t));
2765 if (pErr->offErrorID)
2766 pszErrorID = (const char *)pErr + pErr->offErrorID;
2767 if (pErr->offMessage)
2768 pszMessage = (const char *)pErr + pErr->offMessage;
2769 else
2770 pszMessage = "No message!";
2771 fFatal = pErr->fFatal;
2772 }
2773 else
2774 pszMessage = "No message! (Failed to allocate memory to put the error message in!)";
2775
2776 /*
2777 * Call the at runtime error callbacks.
2778 */
2779 for (PVMATRUNTIMEERROR pCur = pVM->vm.s.pAtRuntimeError; pCur; pCur = pCur->pNext)
2780 vmR3SetRuntimeErrorWorkerDoCall(pVM, pCur, fFatal, pszErrorID, "%s", pszMessage);
2781}
2782
2783
2784/**
2785 * Worker which calls everyone listening to the VM runtime error messages.
2786 *
2787 * @param pVM The VM handle.
2788 * @param fFatal Whether it is a fatal error or not.
2789 * @param pszErrorID Error ID string.
2790 * @param pszFormat Format string.
2791 * @param pArgs Pointer to the format arguments.
2792 * @thread EMT
2793 */
2794DECLCALLBACK(void) vmR3SetRuntimeErrorV(PVM pVM, bool fFatal,
2795 const char *pszErrorID,
2796 const char *pszFormat, va_list *pArgs)
2797{
2798 /*
2799 * Make a copy of the message.
2800 */
2801 vmSetRuntimeErrorCopy(pVM, fFatal, pszErrorID, pszFormat, *pArgs);
2802
2803 /*
2804 * Call the at error callbacks.
2805 */
2806 for (PVMATRUNTIMEERROR pCur = pVM->vm.s.pAtRuntimeError; pCur; pCur = pCur->pNext)
2807 {
2808 va_list va2;
2809 va_copy(va2, *pArgs);
2810 pCur->pfnAtRuntimeError(pVM, pCur->pvUser, fFatal, pszErrorID, pszFormat, va2);
2811 va_end(va2);
2812 }
2813}
2814
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