VirtualBox

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

Last change on this file since 3068 was 2984, checked in by vboxsync, 18 years ago

configurable halt method. (still using the old stuff)

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