VirtualBox

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

Last change on this file since 2273 was 2233, checked in by vboxsync, 18 years ago

put pack the double-power-off workaround

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