VirtualBox

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

Last change on this file since 2121 was 2096, checked in by vboxsync, 18 years ago

Made error messages more detailed

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