VirtualBox

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

Last change on this file since 2833 was 2776, checked in by vboxsync, 18 years ago

Release statistics, dumping them to the release log upon VM destruction. (total + halt w/ breakdown)

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