VirtualBox

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

Last change on this file since 1799 was 1480, checked in by vboxsync, 18 years ago

No longer require contiguous memory for the VM structure.
Did long overdue IOCtl cleanup wrt R3/R0 pointers.

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