VirtualBox

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

Last change on this file since 2858 was 2858, checked in by vboxsync, 17 years ago

mark statistics.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 84.8 KB
Line 
1/* $Id: VM.cpp 2858 2007-05-24 21:01:00Z 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 LogRel(("************************* Statistics *************************\n"));
1434 STAMR3DumpToReleaseLog(pVM, "*");
1435 LogRel(("********************* End of statistics **********************\n"));
1436#endif
1437
1438 /*
1439 * Destroy the VM components.
1440 */
1441 int rc = TMR3Term(pVM);
1442 AssertRC(rc);
1443 rc = DBGCTcpTerminate(pVM, pVM->vm.s.pvDBGC);
1444 pVM->vm.s.pvDBGC = NULL;
1445 AssertRC(rc);
1446 rc = DBGFR3Term(pVM);
1447 AssertRC(rc);
1448 rc = PDMR3Term(pVM);
1449 AssertRC(rc);
1450 rc = EMR3Term(pVM);
1451 AssertRC(rc);
1452 rc = IOMR3Term(pVM);
1453 AssertRC(rc);
1454 rc = CSAMR3Term(pVM);
1455 AssertRC(rc);
1456 rc = PATMR3Term(pVM);
1457 AssertRC(rc);
1458 rc = TRPMR3Term(pVM);
1459 AssertRC(rc);
1460 rc = SELMR3Term(pVM);
1461 AssertRC(rc);
1462 rc = REMR3Term(pVM);
1463 AssertRC(rc);
1464 rc = HWACCMR3Term(pVM);
1465 AssertRC(rc);
1466 rc = VMMR3Term(pVM);
1467 AssertRC(rc);
1468 rc = PGMR3Term(pVM);
1469 AssertRC(rc);
1470 rc = CPUMR3Term(pVM);
1471 AssertRC(rc);
1472 rc = STAMR3Term(pVM);
1473 AssertRC(rc);
1474 rc = PDMR3CritSectTerm(pVM);
1475 AssertRC(rc);
1476 /* MM is destroyed later in vmR3DestroyFinalBit() for heap reasons. */
1477
1478 /*
1479 * We're done in this thread.
1480 */
1481 pVM->fForcedActions = VM_FF_TERMINATE;
1482 LogFlow(("vmR3Destroy: returning %Vrc\n", VINF_EM_TERMINATE));
1483 return VINF_EM_TERMINATE;
1484}
1485
1486
1487/**
1488 * Does the final part of the VM destruction.
1489 * This is called by EMT in it's final stage or by the VMR3Destroy caller.
1490 *
1491 * @param pVM VM Handle.
1492 */
1493void vmR3DestroyFinalBit(PVM pVM)
1494{
1495 /*
1496 * Free the event semaphores associated with the request packets.s
1497 */
1498 unsigned cReqs = 0;
1499 for (unsigned i = 0; i < ELEMENTS(pVM->vm.s.apReqFree); i++)
1500 {
1501 PVMREQ pReq = pVM->vm.s.apReqFree[i];
1502 pVM->vm.s.apReqFree[i] = NULL;
1503 for (; pReq; pReq = pReq->pNext, cReqs++)
1504 {
1505 pReq->enmState = VMREQSTATE_INVALID;
1506 RTSemEventDestroy(pReq->EventSem);
1507 }
1508 }
1509 Assert(cReqs == pVM->vm.s.cReqFree); NOREF(cReqs);
1510
1511 /*
1512 * Kill all queued requests. (There really shouldn't be any!)
1513 */
1514 for (unsigned i = 0; i < 10; i++)
1515 {
1516 PVMREQ pReqHead = (PVMREQ)ASMAtomicXchgPtr((void *volatile *)&pVM->vm.s.pReqs, NULL);
1517 AssertMsg(!pReqHead, ("This isn't supposed to happen! VMR3Destroy caller has to serialize this.\n"));
1518 if (!pReqHead)
1519 break;
1520 for (PVMREQ pReq = pReqHead; pReq; pReq = pReq->pNext)
1521 {
1522 ASMAtomicXchgSize(&pReq->iStatus, VERR_INTERNAL_ERROR);
1523 ASMAtomicXchgSize(&pReq->enmState, VMREQSTATE_INVALID);
1524 RTSemEventSignal(pReq->EventSem);
1525 RTThreadSleep(2);
1526 RTSemEventDestroy(pReq->EventSem);
1527 }
1528 /* give them a chance to respond before we free the request memory. */
1529 RTThreadSleep(32);
1530 }
1531
1532 /*
1533 * Modify state and then terminate MM.
1534 * (MM must be delayed until this point so we don't destroy the callbacks and the request packet.)
1535 */
1536 vmR3SetState(pVM, VMSTATE_TERMINATED);
1537 int rc = MMR3Term(pVM);
1538 AssertRC(rc);
1539
1540 /*
1541 * Free the VM structure.
1542 */
1543 rc = SUPLowFree(pVM, RT_ALIGN_Z(sizeof(*pVM), PAGE_SIZE) >> PAGE_SHIFT);
1544 AssertRC(rc);
1545 rc = SUPTerm();
1546 AssertRC(rc);
1547
1548 RTLogFlush(NULL);
1549}
1550
1551
1552/**
1553 * Enumerates the VMs in this process.
1554 *
1555 * @returns Pointer to the next VM.
1556 * @returns NULL when no more VMs.
1557 * @param pVMPrev The previous VM
1558 * Use NULL to start the enumeration.
1559 */
1560VMR3DECL(PVM) VMR3EnumVMs(PVM pVMPrev)
1561{
1562 /*
1563 * This is quick and dirty. It has issues with VM being
1564 * destroyed during the enumeration.
1565 */
1566 if (pVMPrev)
1567 return pVMPrev->pNext;
1568 return g_pVMsHead;
1569}
1570
1571
1572/**
1573 * Registers an at VM destruction callback.
1574 *
1575 * @returns VBox status code.
1576 * @param pfnAtDtor Pointer to callback.
1577 * @param pvUser User argument.
1578 */
1579VMR3DECL(int) VMR3AtDtorRegister(PFNVMATDTOR pfnAtDtor, void *pvUser)
1580{
1581 /*
1582 * Check if already registered.
1583 */
1584 VM_ATDTOR_LOCK();
1585 PVMATDTOR pCur = g_pVMAtDtorHead;
1586 while (pCur)
1587 {
1588 if (pfnAtDtor == pCur->pfnAtDtor)
1589 {
1590 VM_ATDTOR_UNLOCK();
1591 AssertMsgFailed(("Already registered at destruction callback %p!\n", pfnAtDtor));
1592 return VERR_INVALID_PARAMETER;
1593 }
1594
1595 /* next */
1596 pCur = pCur->pNext;
1597 }
1598 VM_ATDTOR_UNLOCK();
1599
1600 /*
1601 * Allocate new entry.
1602 */
1603 PVMATDTOR pVMAtDtor = (PVMATDTOR)RTMemAlloc(sizeof(*pVMAtDtor));
1604 if (!pVMAtDtor)
1605 return VERR_NO_MEMORY;
1606
1607 VM_ATDTOR_LOCK();
1608 pVMAtDtor->pfnAtDtor = pfnAtDtor;
1609 pVMAtDtor->pvUser = pvUser;
1610 pVMAtDtor->pNext = g_pVMAtDtorHead;
1611 g_pVMAtDtorHead = pVMAtDtor;
1612 VM_ATDTOR_UNLOCK();
1613
1614 return VINF_SUCCESS;
1615}
1616
1617
1618/**
1619 * Deregisters an at VM destruction callback.
1620 *
1621 * @returns VBox status code.
1622 * @param pfnAtDtor Pointer to callback.
1623 */
1624VMR3DECL(int) VMR3AtDtorDeregister(PFNVMATDTOR pfnAtDtor)
1625{
1626 /*
1627 * Find it, unlink it and free it.
1628 */
1629 VM_ATDTOR_LOCK();
1630 PVMATDTOR pPrev = NULL;
1631 PVMATDTOR pCur = g_pVMAtDtorHead;
1632 while (pCur)
1633 {
1634 if (pfnAtDtor == pCur->pfnAtDtor)
1635 {
1636 if (pPrev)
1637 pPrev->pNext = pCur->pNext;
1638 else
1639 g_pVMAtDtorHead = pCur->pNext;
1640 pCur->pNext = NULL;
1641 VM_ATDTOR_UNLOCK();
1642
1643 RTMemFree(pCur);
1644 return VINF_SUCCESS;
1645 }
1646
1647 /* next */
1648 pPrev = pCur;
1649 pCur = pCur->pNext;
1650 }
1651 VM_ATDTOR_UNLOCK();
1652
1653 return VERR_INVALID_PARAMETER;
1654}
1655
1656
1657/**
1658 * Walks the list of at VM destructor callbacks.
1659 * @param pVM The VM which is about to be destroyed.
1660 */
1661static void vmR3AtDtor(PVM pVM)
1662{
1663 /*
1664 * Find it, unlink it and free it.
1665 */
1666 VM_ATDTOR_LOCK();
1667 for (PVMATDTOR pCur = g_pVMAtDtorHead; pCur; pCur = pCur->pNext)
1668 pCur->pfnAtDtor(pVM, pCur->pvUser);
1669 VM_ATDTOR_UNLOCK();
1670}
1671
1672
1673/**
1674 * Reset the current VM.
1675 *
1676 * @returns VBox status code.
1677 * @param pVM VM to reset.
1678 */
1679VMR3DECL(int) VMR3Reset(PVM pVM)
1680{
1681 int rc = VINF_SUCCESS;
1682
1683 /*
1684 * Check the state.
1685 */
1686 if (!pVM)
1687 return VERR_INVALID_PARAMETER;
1688 if ( pVM->enmVMState != VMSTATE_RUNNING
1689 && pVM->enmVMState != VMSTATE_SUSPENDED)
1690 {
1691 AssertMsgFailed(("Invalid VM state %d\n", pVM->enmVMState));
1692 return VERR_VM_INVALID_VM_STATE;
1693 }
1694
1695 /*
1696 * Queue reset request to the emulation thread
1697 * and wait for it to be processed.
1698 */
1699 PVMREQ pReq = NULL;
1700 rc = VMR3ReqCall(pVM, &pReq, 0, (PFNRT)vmR3Reset, 1, pVM);
1701 while (rc == VERR_TIMEOUT)
1702 rc = VMR3ReqWait(pReq, RT_INDEFINITE_WAIT);
1703 if (VBOX_SUCCESS(rc))
1704 rc = pReq->iStatus;
1705 VMR3ReqFree(pReq);
1706
1707 return rc;
1708}
1709
1710
1711/**
1712 * Worker which checks integrity of some internal structures.
1713 * This is yet another attempt to track down that AVL tree crash.
1714 */
1715static void vmR3CheckIntegrity(PVM pVM)
1716{
1717#ifdef VBOX_STRICT
1718 int rc = PGMR3CheckIntegrity(pVM);
1719 AssertReleaseRC(rc);
1720#endif
1721}
1722
1723
1724/**
1725 * Reset request processor.
1726 *
1727 * This is called by the emulation thread as a response to the
1728 * reset request issued by VMR3Reset().
1729 *
1730 * @returns VBox status code.
1731 * @param pVM VM to reset.
1732 */
1733static DECLCALLBACK(int) vmR3Reset(PVM pVM)
1734{
1735 /*
1736 * As a safety precaution we temporarily change the state while resetting.
1737 * (If VMR3Reset was not called from EMT we might have change state... let's ignore that fact for now.)
1738 */
1739 VMSTATE enmVMState = pVM->enmVMState;
1740 Assert(enmVMState == VMSTATE_SUSPENDED || enmVMState == VMSTATE_RUNNING);
1741 vmR3SetState(pVM, VMSTATE_RESETTING);
1742 vmR3CheckIntegrity(pVM);
1743
1744
1745 /*
1746 * Reset the VM components.
1747 */
1748 PATMR3Reset(pVM);
1749 CSAMR3Reset(pVM);
1750 PGMR3Reset(pVM); /* We clear VM RAM in PGMR3Reset. It's vital PDMR3Reset is executed
1751 * _afterwards_. E.g. ACPI sets up RAM tables during init/reset. */
1752 PDMR3Reset(pVM);
1753 SELMR3Reset(pVM);
1754 TRPMR3Reset(pVM);
1755 vmR3AtReset(pVM);
1756 REMR3Reset(pVM);
1757 IOMR3Reset(pVM);
1758 CPUMR3Reset(pVM);
1759 TMR3Reset(pVM);
1760 EMR3Reset(pVM);
1761 HWACCMR3Reset(pVM); /* This must come *after* PATM, CSAM, CPUM, SELM and TRPM. */
1762
1763#ifdef LOG_ENABLED
1764 /*
1765 * Debug logging.
1766 */
1767 RTLogPrintf("\n\nThe VM was reset:\n");
1768 DBGFR3Info(pVM, "cpum", "verbose", NULL);
1769#endif
1770
1771 /*
1772 * Restore the state.
1773 */
1774 vmR3CheckIntegrity(pVM);
1775 Assert(pVM->enmVMState == VMSTATE_RESETTING);
1776 vmR3SetState(pVM, enmVMState);
1777
1778 return VINF_EM_RESET;
1779}
1780
1781
1782/**
1783 * Walks the list of at VM reset callbacks and calls them
1784 *
1785 * @returns VBox status code.
1786 * Any failure is fatal.
1787 * @param pVM The VM which is being reset.
1788 */
1789static int vmR3AtReset(PVM pVM)
1790{
1791 /*
1792 * Walk the list and call them all.
1793 */
1794 int rc = VINF_SUCCESS;
1795 for (PVMATRESET pCur = pVM->vm.s.pAtReset; pCur; pCur = pCur->pNext)
1796 {
1797 /* do the call */
1798 switch (pCur->enmType)
1799 {
1800 case VMATRESETTYPE_DEV:
1801 rc = pCur->u.Dev.pfnCallback(pCur->u.Dev.pDevIns, pCur->pvUser);
1802 break;
1803 case VMATRESETTYPE_INTERNAL:
1804 rc = pCur->u.Internal.pfnCallback(pVM, pCur->pvUser);
1805 break;
1806 case VMATRESETTYPE_EXTERNAL:
1807 pCur->u.External.pfnCallback(pCur->pvUser);
1808 break;
1809 default:
1810 AssertMsgFailed(("Invalid at-reset type %d!\n", pCur->enmType));
1811 return VERR_INTERNAL_ERROR;
1812 }
1813
1814 if (VBOX_FAILURE(rc))
1815 {
1816 AssertMsgFailed(("At-reset handler %s failed with rc=%d\n", pCur->pszDesc, rc));
1817 return rc;
1818 }
1819 }
1820
1821 return VINF_SUCCESS;
1822}
1823
1824
1825/**
1826 * Internal registration function
1827 */
1828static int vmr3AtResetRegister(PVM pVM, void *pvUser, const char *pszDesc, PVMATRESET *ppNew)
1829{
1830 /*
1831 * Allocate restration structure.
1832 */
1833 PVMATRESET pNew = (PVMATRESET)MMR3HeapAlloc(pVM, MM_TAG_VM, sizeof(*pNew));
1834 if (pNew)
1835 {
1836 /* fill data. */
1837 pNew->pNext = NULL;
1838 pNew->pszDesc = pszDesc;
1839 pNew->pvUser = pvUser;
1840
1841 /* insert */
1842 *pVM->vm.s.ppAtResetNext = pNew;
1843 pVM->vm.s.ppAtResetNext = &pNew->pNext;
1844
1845 return VINF_SUCCESS;
1846 }
1847 return VERR_NO_MEMORY;
1848}
1849
1850
1851/**
1852 * Registers an at VM reset callback.
1853 *
1854 * @returns VBox status code.
1855 * @param pVM The VM.
1856 * @param pDevInst Device instance.
1857 * @param pfnCallback Callback function.
1858 * @param pvUser User argument.
1859 * @param pszDesc Description (optional).
1860 */
1861VMR3DECL(int) VMR3AtResetRegister(PVM pVM, PPDMDEVINS pDevInst, PFNVMATRESET pfnCallback, void *pvUser, const char *pszDesc)
1862{
1863 /*
1864 * Validate.
1865 */
1866 if (!pDevInst)
1867 {
1868 AssertMsgFailed(("pDevIns is NULL!\n"));
1869 return VERR_INVALID_PARAMETER;
1870 }
1871
1872 /*
1873 * Create the new entry.
1874 */
1875 PVMATRESET pNew;
1876 int rc = vmr3AtResetRegister(pVM, pvUser, pszDesc, &pNew);
1877 if (VBOX_SUCCESS(rc))
1878 {
1879 /*
1880 * Fill in type data.
1881 */
1882 pNew->enmType = VMATRESETTYPE_DEV;
1883 pNew->u.Dev.pfnCallback = pfnCallback;
1884 pNew->u.Dev.pDevIns = pDevInst;
1885 }
1886
1887 return rc;
1888}
1889
1890
1891/**
1892 * Registers an at VM reset internal callback.
1893 *
1894 * @returns VBox status code.
1895 * @param pVM The VM.
1896 * @param pfnCallback Callback function.
1897 * @param pvUser User argument.
1898 * @param pszDesc Description (optional).
1899 */
1900VMR3DECL(int) VMR3AtResetRegisterInternal(PVM pVM, PFNVMATRESETINT pfnCallback, void *pvUser, const char *pszDesc)
1901{
1902 /*
1903 * Validate.
1904 */
1905 if (!pfnCallback)
1906 {
1907 AssertMsgFailed(("pfnCallback is NULL!\n"));
1908 return VERR_INVALID_PARAMETER;
1909 }
1910
1911 /*
1912 * Create the new entry.
1913 */
1914 PVMATRESET pNew;
1915 int rc = vmr3AtResetRegister(pVM, pvUser, pszDesc, &pNew);
1916 if (VBOX_SUCCESS(rc))
1917 {
1918 /*
1919 * Fill in type data.
1920 */
1921 pNew->enmType = VMATRESETTYPE_INTERNAL;
1922 pNew->u.Internal.pfnCallback = pfnCallback;
1923 }
1924
1925 return rc;
1926}
1927
1928
1929/**
1930 * Registers an at VM reset external callback.
1931 *
1932 * @returns VBox status code.
1933 * @param pVM The VM.
1934 * @param pfnCallback Callback function.
1935 * @param pvUser User argument.
1936 * @param pszDesc Description (optional).
1937 */
1938VMR3DECL(int) VMR3AtResetRegisterExternal(PVM pVM, PFNVMATRESETEXT pfnCallback, void *pvUser, const char *pszDesc)
1939{
1940 /*
1941 * Validate.
1942 */
1943 if (!pfnCallback)
1944 {
1945 AssertMsgFailed(("pfnCallback is NULL!\n"));
1946 return VERR_INVALID_PARAMETER;
1947 }
1948
1949 /*
1950 * Create the new entry.
1951 */
1952 PVMATRESET pNew;
1953 int rc = vmr3AtResetRegister(pVM, pvUser, pszDesc, &pNew);
1954 if (VBOX_SUCCESS(rc))
1955 {
1956 /*
1957 * Fill in type data.
1958 */
1959 pNew->enmType = VMATRESETTYPE_EXTERNAL;
1960 pNew->u.External.pfnCallback = pfnCallback;
1961 }
1962
1963 return rc;
1964}
1965
1966
1967/**
1968 * Unlinks and frees a callback.
1969 *
1970 * @returns Pointer to the next callback structure.
1971 * @param pVM The VM.
1972 * @param pCur The one to free.
1973 * @param pPrev The one before pCur.
1974 */
1975static PVMATRESET vmr3AtResetFree(PVM pVM, PVMATRESET pCur, PVMATRESET pPrev)
1976{
1977 /*
1978 * Unlink it.
1979 */
1980 PVMATRESET pNext = pCur->pNext;
1981 if (pPrev)
1982 {
1983 pPrev->pNext = pNext;
1984 if (!pNext)
1985 pVM->vm.s.ppAtResetNext = &pPrev->pNext;
1986 }
1987 else
1988 {
1989 pVM->vm.s.pAtReset = pNext;
1990 if (!pNext)
1991 pVM->vm.s.ppAtResetNext = &pVM->vm.s.pAtReset;
1992 }
1993
1994 /*
1995 * Free it.
1996 */
1997 MMR3HeapFree(pCur);
1998
1999 return pNext;
2000}
2001
2002
2003/**
2004 * Deregisters an at VM reset callback.
2005 *
2006 * @returns VBox status code.
2007 * @param pVM The VM.
2008 * @param pDevInst Device instance.
2009 * @param pfnCallback Callback function.
2010 */
2011VMR3DECL(int) VMR3AtResetDeregister(PVM pVM, PPDMDEVINS pDevInst, PFNVMATRESET pfnCallback)
2012{
2013 int rc = VERR_VM_ATRESET_NOT_FOUND;
2014 PVMATRESET pPrev = NULL;
2015 PVMATRESET pCur = pVM->vm.s.pAtReset;
2016 while (pCur)
2017 {
2018 if ( pCur->enmType == VMATRESETTYPE_DEV
2019 && pCur->u.Dev.pDevIns == pDevInst
2020 && (!pfnCallback || pCur->u.Dev.pfnCallback == pfnCallback))
2021 {
2022 pCur = vmr3AtResetFree(pVM, pCur, pPrev);
2023 rc = VINF_SUCCESS;
2024 }
2025 else
2026 {
2027 pPrev = pCur;
2028 pCur = pCur->pNext;
2029 }
2030 }
2031
2032 AssertRC(rc);
2033 return rc;
2034}
2035
2036
2037/**
2038 * Deregisters an at VM reset internal callback.
2039 *
2040 * @returns VBox status code.
2041 * @param pVM The VM.
2042 * @param pfnCallback Callback function.
2043 */
2044VMR3DECL(int) VMR3AtResetDeregisterInternal(PVM pVM, PFNVMATRESETINT pfnCallback)
2045{
2046 int rc = VERR_VM_ATRESET_NOT_FOUND;
2047 PVMATRESET pPrev = NULL;
2048 PVMATRESET pCur = pVM->vm.s.pAtReset;
2049 while (pCur)
2050 {
2051 if ( pCur->enmType == VMATRESETTYPE_INTERNAL
2052 && pCur->u.Internal.pfnCallback == pfnCallback)
2053 {
2054 pCur = vmr3AtResetFree(pVM, pCur, pPrev);
2055 rc = VINF_SUCCESS;
2056 }
2057 else
2058 {
2059 pPrev = pCur;
2060 pCur = pCur->pNext;
2061 }
2062 }
2063
2064 AssertRC(rc);
2065 return rc;
2066}
2067
2068
2069/**
2070 * Deregisters an at VM reset external callback.
2071 *
2072 * @returns VBox status code.
2073 * @param pVM The VM.
2074 * @param pfnCallback Callback function.
2075 */
2076VMR3DECL(int) VMR3AtResetDeregisterExternal(PVM pVM, PFNVMATRESETEXT pfnCallback)
2077{
2078 int rc = VERR_VM_ATRESET_NOT_FOUND;
2079 PVMATRESET pPrev = NULL;
2080 PVMATRESET pCur = pVM->vm.s.pAtReset;
2081 while (pCur)
2082 {
2083 if ( pCur->enmType == VMATRESETTYPE_INTERNAL
2084 && pCur->u.External.pfnCallback == pfnCallback)
2085 {
2086 pCur = vmr3AtResetFree(pVM, pCur, pPrev);
2087 rc = VINF_SUCCESS;
2088 }
2089 else
2090 {
2091 pPrev = pCur;
2092 pCur = pCur->pNext;
2093 }
2094 }
2095
2096 AssertRC(rc);
2097 return rc;
2098}
2099
2100
2101/**
2102 * Gets the current VM state.
2103 *
2104 * @returns The current VM state.
2105 * @param pVM VM handle.
2106 * @thread Any
2107 */
2108VMR3DECL(VMSTATE) VMR3GetState(PVM pVM)
2109{
2110 return pVM->enmVMState;
2111}
2112
2113
2114/**
2115 * Gets the state name string for a VM state.
2116 *
2117 * @returns Pointer to the state name. (readonly)
2118 * @param enmState The state.
2119 */
2120VMR3DECL(const char *) VMR3GetStateName(VMSTATE enmState)
2121{
2122 switch (enmState)
2123 {
2124 case VMSTATE_CREATING: return "CREATING";
2125 case VMSTATE_CREATED: return "CREATED";
2126 case VMSTATE_RUNNING: return "RUNNING";
2127 case VMSTATE_LOADING: return "LOADING";
2128 case VMSTATE_LOAD_FAILURE: return "LOAD_FAILURE";
2129 case VMSTATE_SAVING: return "SAVING";
2130 case VMSTATE_SUSPENDED: return "SUSPENDED";
2131 case VMSTATE_RESETTING: return "RESETTING";
2132 case VMSTATE_GURU_MEDITATION: return "GURU_MEDIATION";
2133 case VMSTATE_OFF: return "OFF";
2134 case VMSTATE_DESTROYING: return "DESTROYING";
2135 case VMSTATE_TERMINATED: return "TERMINATED";
2136 default:
2137 AssertMsgFailed(("Unknown state %d\n", enmState));
2138 return "Unknown!\n";
2139 }
2140}
2141
2142
2143/**
2144 * Sets the current VM state.
2145 *
2146 * @returns The current VM state.
2147 * @param pVM VM handle.
2148 * @param enmStateNew The new state.
2149 */
2150static void vmR3SetState(PVM pVM, VMSTATE enmStateNew)
2151{
2152 VMSTATE enmStateOld = pVM->enmVMState;
2153 pVM->enmVMState = enmStateNew;
2154 LogRel(("Changing the VM state from '%s' to '%s'.\n", VMR3GetStateName(enmStateOld), VMR3GetStateName(enmStateNew)));
2155
2156 /*
2157 * Call the at state change callbacks.
2158 */
2159 for (PVMATSTATE pCur = pVM->vm.s.pAtState; pCur; pCur = pCur->pNext)
2160 {
2161 pCur->pfnAtState(pVM, enmStateNew, enmStateOld, pCur->pvUser);
2162 if (pVM->enmVMState == VMSTATE_DESTROYING)
2163 break;
2164 AssertMsg(pVM->enmVMState == enmStateNew,
2165 ("You are not allowed to change the state while in the change callback, except "
2166 "from destroying the VM. There are restrictions in the way the state changes "
2167 "are propagated up to the EM execution loop and it makes the program flow very "
2168 "difficult to follow.\n"));
2169 }
2170}
2171
2172
2173/**
2174 * Registers a VM state change callback.
2175 *
2176 * You are not allowed to call any function which changes the VM state from a
2177 * state callback, except VMR3Destroy().
2178 *
2179 * @returns VBox status code.
2180 * @param pVM VM handle.
2181 * @param pfnAtState Pointer to callback.
2182 * @param pvUser User argument.
2183 * @thread Any.
2184 */
2185VMR3DECL(int) VMR3AtStateRegister(PVM pVM, PFNVMATSTATE pfnAtState, void *pvUser)
2186{
2187 LogFlow(("VMR3AtStateRegister: pfnAtState=%p pvUser=%p\n", pfnAtState, pvUser));
2188
2189 /*
2190 * Validate input.
2191 */
2192 if (!pfnAtState)
2193 {
2194 AssertMsgFailed(("callback is required\n"));
2195 return VERR_INVALID_PARAMETER;
2196 }
2197
2198 /*
2199 * Make sure we're in EMT (to avoid the logging).
2200 */
2201 PVMREQ pReq;
2202 int rc = VMR3ReqCall(pVM, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3AtStateRegister, 3, pVM, pfnAtState, pvUser);
2203 if (VBOX_FAILURE(rc))
2204 return rc;
2205 rc = pReq->iStatus;
2206 VMR3ReqFree(pReq);
2207
2208 LogFlow(("VMR3AtStateRegister: returns %Vrc\n", rc));
2209 return rc;
2210}
2211
2212
2213/**
2214 * Registers a VM state change callback.
2215 *
2216 * @returns VBox status code.
2217 * @param pVM VM handle.
2218 * @param pfnAtState Pointer to callback.
2219 * @param pvUser User argument.
2220 * @thread EMT
2221 */
2222static DECLCALLBACK(int) vmR3AtStateRegister(PVM pVM, PFNVMATSTATE pfnAtState, void *pvUser)
2223{
2224 /*
2225 * Allocate a new record.
2226 */
2227
2228 PVMATSTATE pNew = (PVMATSTATE)MMR3HeapAlloc(pVM, MM_TAG_VM, sizeof(*pNew));
2229 if (!pNew)
2230 return VERR_NO_MEMORY;
2231
2232 /* fill */
2233 pNew->pfnAtState = pfnAtState;
2234 pNew->pvUser = pvUser;
2235 pNew->pNext = NULL;
2236
2237 /* insert */
2238 *pVM->vm.s.ppAtStateNext = pNew;
2239 pVM->vm.s.ppAtStateNext = &pNew->pNext;
2240
2241 return VINF_SUCCESS;
2242}
2243
2244
2245/**
2246 * Deregisters a VM state change callback.
2247 *
2248 * @returns VBox status code.
2249 * @param pVM VM handle.
2250 * @param pfnAtState Pointer to callback.
2251 * @param pvUser User argument.
2252 * @thread Any.
2253 */
2254VMR3DECL(int) VMR3AtStateDeregister(PVM pVM, PFNVMATSTATE pfnAtState, void *pvUser)
2255{
2256 LogFlow(("VMR3AtStateDeregister: pfnAtState=%p pvUser=%p\n", pfnAtState, pvUser));
2257
2258 /*
2259 * Validate input.
2260 */
2261 if (!pfnAtState)
2262 {
2263 AssertMsgFailed(("callback is required\n"));
2264 return VERR_INVALID_PARAMETER;
2265 }
2266
2267 /*
2268 * Make sure we're in EMT (to avoid the logging).
2269 */
2270 PVMREQ pReq;
2271 int rc = VMR3ReqCall(pVM, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3AtStateDeregister, 3, pVM, pfnAtState, pvUser);
2272 if (VBOX_FAILURE(rc))
2273 return rc;
2274 rc = pReq->iStatus;
2275 VMR3ReqFree(pReq);
2276
2277 LogFlow(("VMR3AtStateDeregister: returns %Vrc\n", rc));
2278 return rc;
2279}
2280
2281
2282/**
2283 * Deregisters a VM state change callback.
2284 *
2285 * @returns VBox status code.
2286 * @param pVM VM handle.
2287 * @param pfnAtState Pointer to callback.
2288 * @param pvUser User argument.
2289 * @thread EMT
2290 */
2291static DECLCALLBACK(int) vmR3AtStateDeregister(PVM pVM, PFNVMATSTATE pfnAtState, void *pvUser)
2292{
2293 LogFlow(("vmR3AtStateDeregister: pfnAtState=%p pvUser=%p\n", pfnAtState, pvUser));
2294
2295 /*
2296 * Search the list for the entry.
2297 */
2298 PVMATSTATE pPrev = NULL;
2299 PVMATSTATE pCur = pVM->vm.s.pAtState;
2300 while ( pCur
2301 && pCur->pfnAtState == pfnAtState
2302 && pCur->pvUser == pvUser)
2303 {
2304 pPrev = pCur;
2305 pCur = pCur->pNext;
2306 }
2307 if (!pCur)
2308 {
2309 AssertMsgFailed(("pfnAtState=%p was not found\n", pfnAtState));
2310 return VERR_FILE_NOT_FOUND;
2311 }
2312
2313 /*
2314 * Unlink it.
2315 */
2316 if (pPrev)
2317 {
2318 pPrev->pNext = pCur->pNext;
2319 if (!pCur->pNext)
2320 pVM->vm.s.ppAtStateNext = &pPrev->pNext;
2321 }
2322 else
2323 {
2324 pVM->vm.s.pAtState = pCur->pNext;
2325 if (!pCur->pNext)
2326 pVM->vm.s.ppAtStateNext = &pVM->vm.s.pAtState;
2327 }
2328
2329 /*
2330 * Free it.
2331 */
2332 pCur->pfnAtState = NULL;
2333 pCur->pNext = NULL;
2334 MMR3HeapFree(pCur);
2335
2336 return VINF_SUCCESS;
2337}
2338
2339
2340/**
2341 * Registers a VM error callback.
2342 *
2343 * @returns VBox status code.
2344 * @param pVM The VM handle.
2345 * @param pfnAtError Pointer to callback.
2346 * @param pvUser User argument.
2347 * @thread Any.
2348 */
2349VMR3DECL(int) VMR3AtErrorRegister(PVM pVM, PFNVMATERROR pfnAtError, void *pvUser)
2350{
2351 LogFlow(("VMR3AtErrorRegister: pfnAtError=%p pvUser=%p\n", pfnAtError, pvUser));
2352
2353 /*
2354 * Validate input.
2355 */
2356 if (!pfnAtError)
2357 {
2358 AssertMsgFailed(("callback is required\n"));
2359 return VERR_INVALID_PARAMETER;
2360 }
2361
2362 /*
2363 * Make sure we're in EMT (to avoid the logging).
2364 */
2365 PVMREQ pReq;
2366 int rc = VMR3ReqCall(pVM, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3AtErrorRegister, 3, pVM, pfnAtError, pvUser);
2367 if (VBOX_FAILURE(rc))
2368 return rc;
2369 rc = pReq->iStatus;
2370 VMR3ReqFree(pReq);
2371
2372 LogFlow(("VMR3AtErrorRegister: returns %Vrc\n", rc));
2373 return rc;
2374}
2375
2376
2377/**
2378 * Registers a VM error callback.
2379 *
2380 * @returns VBox status code.
2381 * @param pVM The VM handle.
2382 * @param pfnAtError Pointer to callback.
2383 * @param pvUser User argument.
2384 * @thread EMT
2385 */
2386static DECLCALLBACK(int) vmR3AtErrorRegister(PVM pVM, PFNVMATERROR pfnAtError, void *pvUser)
2387{
2388 /*
2389 * Allocate a new record.
2390 */
2391
2392 PVMATERROR pNew = (PVMATERROR)MMR3HeapAlloc(pVM, MM_TAG_VM, sizeof(*pNew));
2393 if (!pNew)
2394 return VERR_NO_MEMORY;
2395
2396 /* fill */
2397 pNew->pfnAtError = pfnAtError;
2398 pNew->pvUser = pvUser;
2399 pNew->pNext = NULL;
2400
2401 /* insert */
2402 *pVM->vm.s.ppAtErrorNext = pNew;
2403 pVM->vm.s.ppAtErrorNext = &pNew->pNext;
2404
2405 return VINF_SUCCESS;
2406}
2407
2408
2409/**
2410 * Deregisters a VM error callback.
2411 *
2412 * @returns VBox status code.
2413 * @param pVM The VM handle.
2414 * @param pfnAtError Pointer to callback.
2415 * @param pvUser User argument.
2416 * @thread Any.
2417 */
2418VMR3DECL(int) VMR3AtErrorDeregister(PVM pVM, PFNVMATERROR pfnAtError, void *pvUser)
2419{
2420 LogFlow(("VMR3AtErrorDeregister: pfnAtError=%p pvUser=%p\n", pfnAtError, pvUser));
2421
2422 /*
2423 * Validate input.
2424 */
2425 if (!pfnAtError)
2426 {
2427 AssertMsgFailed(("callback is required\n"));
2428 return VERR_INVALID_PARAMETER;
2429 }
2430
2431 /*
2432 * Make sure we're in EMT (to avoid the logging).
2433 */
2434 PVMREQ pReq;
2435 int rc = VMR3ReqCall(pVM, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3AtErrorDeregister, 3, pVM, pfnAtError, pvUser);
2436 if (VBOX_FAILURE(rc))
2437 return rc;
2438 rc = pReq->iStatus;
2439 VMR3ReqFree(pReq);
2440
2441 LogFlow(("VMR3AtErrorDeregister: returns %Vrc\n", rc));
2442 return rc;
2443}
2444
2445
2446/**
2447 * Deregisters a VM error callback.
2448 *
2449 * @returns VBox status code.
2450 * @param pVM The VM handle.
2451 * @param pfnAtError Pointer to callback.
2452 * @param pvUser User argument.
2453 * @thread EMT
2454 */
2455static DECLCALLBACK(int) vmR3AtErrorDeregister(PVM pVM, PFNVMATERROR pfnAtError, void *pvUser)
2456{
2457 LogFlow(("vmR3AtErrorDeregister: pfnAtError=%p pvUser=%p\n", pfnAtError, pvUser));
2458
2459 /*
2460 * Search the list for the entry.
2461 */
2462 PVMATERROR pPrev = NULL;
2463 PVMATERROR pCur = pVM->vm.s.pAtError;
2464 while ( pCur
2465 && pCur->pfnAtError == pfnAtError
2466 && pCur->pvUser == pvUser)
2467 {
2468 pPrev = pCur;
2469 pCur = pCur->pNext;
2470 }
2471 if (!pCur)
2472 {
2473 AssertMsgFailed(("pfnAtError=%p was not found\n", pfnAtError));
2474 return VERR_FILE_NOT_FOUND;
2475 }
2476
2477 /*
2478 * Unlink it.
2479 */
2480 if (pPrev)
2481 {
2482 pPrev->pNext = pCur->pNext;
2483 if (!pCur->pNext)
2484 pVM->vm.s.ppAtErrorNext = &pPrev->pNext;
2485 }
2486 else
2487 {
2488 pVM->vm.s.pAtError = pCur->pNext;
2489 if (!pCur->pNext)
2490 pVM->vm.s.ppAtErrorNext = &pVM->vm.s.pAtError;
2491 }
2492
2493 /*
2494 * Free it.
2495 */
2496 pCur->pfnAtError = NULL;
2497 pCur->pNext = NULL;
2498 MMR3HeapFree(pCur);
2499
2500 return VINF_SUCCESS;
2501}
2502
2503
2504/**
2505 * Ellipsis to va_list wrapper for calling pfnAtError.
2506 */
2507static void vmR3SetErrorWorkerDoCall(PVM pVM, PVMATERROR pCur, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...)
2508{
2509 va_list va;
2510 va_start(va, pszFormat);
2511 pCur->pfnAtError(pVM, pCur->pvUser, rc, RT_SRC_POS_ARGS, pszFormat, va);
2512 va_end(va);
2513}
2514
2515
2516/**
2517 * This is a worker function for GC and Ring-0 calls to VMSetError and VMSetErrorV.
2518 * The message is found in VMINT.
2519 *
2520 * @param pVM The VM handle.
2521 * @thread EMT.
2522 */
2523VMR3DECL(void) VMR3SetErrorWorker(PVM pVM)
2524{
2525 VM_ASSERT_EMT(pVM);
2526 AssertReleaseMsgFailed(("And we have a winner! You get to implement Ring-0 and GC VMSetErrorV! Contrats!\n"));
2527
2528 /*
2529 * Unpack the error (if we managed to format one).
2530 */
2531 PVMERROR pErr = pVM->vm.s.pErrorR3;
2532 const char *pszFile = NULL;
2533 const char *pszFunction = NULL;
2534 uint32_t iLine = 0;
2535 const char *pszMessage;
2536 int32_t rc = VERR_MM_HYPER_NO_MEMORY;
2537 if (pErr)
2538 {
2539 AssertCompile(sizeof(const char) == sizeof(uint8_t));
2540 if (pErr->offFile)
2541 pszFile = (const char *)pErr + pErr->offFile;
2542 iLine = pErr->iLine;
2543 if (pErr->offFunction)
2544 pszFunction = (const char *)pErr + pErr->offFunction;
2545 if (pErr->offMessage)
2546 pszMessage = (const char *)pErr + pErr->offMessage;
2547 else
2548 pszMessage = "No message!";
2549 }
2550 else
2551 pszMessage = "No message! (Failed to allocate memory to put the error message in!)";
2552
2553 /*
2554 * Call the at error callbacks.
2555 */
2556 for (PVMATERROR pCur = pVM->vm.s.pAtError; pCur; pCur = pCur->pNext)
2557 vmR3SetErrorWorkerDoCall(pVM, pCur, rc, RT_SRC_POS_ARGS, "%s", pszMessage);
2558}
2559
2560
2561/**
2562 * Worker which calls everyone listening to the VM error messages.
2563 *
2564 * @param pVM The VM handle.
2565 * @param rc The VBox status code.
2566 * @param RT_SRC_POS_DECL The source position of this error.
2567 * @param pszFormat Format string.
2568 * @param pArgs Pointer to the format arguments.
2569 * @thread EMT
2570 */
2571DECLCALLBACK(void) vmR3SetErrorV(PVM pVM, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list *pArgs)
2572{
2573#ifdef LOG_ENABLED
2574 /*
2575 * Log the error.
2576 */
2577 RTLogPrintf("VMSetError: %s(%d) %s\n", pszFile, iLine, pszFunction);
2578 va_list va3;
2579 va_copy(va3, *pArgs);
2580 RTLogPrintfV(pszFormat, va3);
2581 va_end(va3);
2582#endif
2583
2584 /*
2585 * Make a copy of the message.
2586 */
2587 vmSetErrorCopy(pVM, rc, RT_SRC_POS_ARGS, pszFormat, *pArgs);
2588
2589 /*
2590 * Call the at error callbacks.
2591 */
2592 for (PVMATERROR pCur = pVM->vm.s.pAtError; pCur; pCur = pCur->pNext)
2593 {
2594 va_list va2;
2595 va_copy(va2, *pArgs);
2596 pCur->pfnAtError(pVM, pCur->pvUser, rc, RT_SRC_POS_ARGS, pszFormat, va2);
2597 va_end(va2);
2598 }
2599}
2600
2601
2602/**
2603 * Registers a VM runtime error callback.
2604 *
2605 * @returns VBox status code.
2606 * @param pVM The VM handle.
2607 * @param pfnAtRuntimeError Pointer to callback.
2608 * @param pvUser User argument.
2609 * @thread Any.
2610 */
2611VMR3DECL(int) VMR3AtRuntimeErrorRegister(PVM pVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser)
2612{
2613 LogFlow(("VMR3AtRuntimeErrorRegister: pfnAtRuntimeError=%p pvUser=%p\n", pfnAtRuntimeError, pvUser));
2614
2615 /*
2616 * Validate input.
2617 */
2618 if (!pfnAtRuntimeError)
2619 {
2620 AssertMsgFailed(("callback is required\n"));
2621 return VERR_INVALID_PARAMETER;
2622 }
2623
2624 /*
2625 * Make sure we're in EMT (to avoid the logging).
2626 */
2627 PVMREQ pReq;
2628 int rc = VMR3ReqCall(pVM, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3AtRuntimeErrorRegister, 3, pVM, pfnAtRuntimeError, pvUser);
2629 if (VBOX_FAILURE(rc))
2630 return rc;
2631 rc = pReq->iStatus;
2632 VMR3ReqFree(pReq);
2633
2634 LogFlow(("VMR3AtRuntimeErrorRegister: returns %Vrc\n", rc));
2635 return rc;
2636}
2637
2638
2639/**
2640 * Registers a VM runtime error callback.
2641 *
2642 * @returns VBox status code.
2643 * @param pVM The VM handle.
2644 * @param pfnAtRuntimeError Pointer to callback.
2645 * @param pvUser User argument.
2646 * @thread EMT
2647 */
2648static DECLCALLBACK(int) vmR3AtRuntimeErrorRegister(PVM pVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser)
2649{
2650 /*
2651 * Allocate a new record.
2652 */
2653
2654 PVMATRUNTIMEERROR pNew = (PVMATRUNTIMEERROR)MMR3HeapAlloc(pVM, MM_TAG_VM, sizeof(*pNew));
2655 if (!pNew)
2656 return VERR_NO_MEMORY;
2657
2658 /* fill */
2659 pNew->pfnAtRuntimeError = pfnAtRuntimeError;
2660 pNew->pvUser = pvUser;
2661 pNew->pNext = NULL;
2662
2663 /* insert */
2664 *pVM->vm.s.ppAtRuntimeErrorNext = pNew;
2665 pVM->vm.s.ppAtRuntimeErrorNext = &pNew->pNext;
2666
2667 return VINF_SUCCESS;
2668}
2669
2670
2671/**
2672 * Deregisters a VM runtime error callback.
2673 *
2674 * @returns VBox status code.
2675 * @param pVM The VM handle.
2676 * @param pfnAtRuntimeError Pointer to callback.
2677 * @param pvUser User argument.
2678 * @thread Any.
2679 */
2680VMR3DECL(int) VMR3AtRuntimeErrorDeregister(PVM pVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser)
2681{
2682 LogFlow(("VMR3AtRuntimeErrorDeregister: pfnAtRuntimeError=%p pvUser=%p\n", pfnAtRuntimeError, pvUser));
2683
2684 /*
2685 * Validate input.
2686 */
2687 if (!pfnAtRuntimeError)
2688 {
2689 AssertMsgFailed(("callback is required\n"));
2690 return VERR_INVALID_PARAMETER;
2691 }
2692
2693 /*
2694 * Make sure we're in EMT (to avoid the logging).
2695 */
2696 PVMREQ pReq;
2697 int rc = VMR3ReqCall(pVM, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3AtRuntimeErrorDeregister, 3, pVM, pfnAtRuntimeError, pvUser);
2698 if (VBOX_FAILURE(rc))
2699 return rc;
2700 rc = pReq->iStatus;
2701 VMR3ReqFree(pReq);
2702
2703 LogFlow(("VMR3AtRuntimeErrorDeregister: returns %Vrc\n", rc));
2704 return rc;
2705}
2706
2707
2708/**
2709 * Deregisters a VM runtime error callback.
2710 *
2711 * @returns VBox status code.
2712 * @param pVM The VM handle.
2713 * @param pfnAtRuntimeError Pointer to callback.
2714 * @param pvUser User argument.
2715 * @thread EMT
2716 */
2717static DECLCALLBACK(int) vmR3AtRuntimeErrorDeregister(PVM pVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser)
2718{
2719 LogFlow(("vmR3AtRuntimeErrorDeregister: pfnAtRuntimeError=%p pvUser=%p\n", pfnAtRuntimeError, pvUser));
2720
2721 /*
2722 * Search the list for the entry.
2723 */
2724 PVMATRUNTIMEERROR pPrev = NULL;
2725 PVMATRUNTIMEERROR pCur = pVM->vm.s.pAtRuntimeError;
2726 while ( pCur
2727 && pCur->pfnAtRuntimeError == pfnAtRuntimeError
2728 && pCur->pvUser == pvUser)
2729 {
2730 pPrev = pCur;
2731 pCur = pCur->pNext;
2732 }
2733 if (!pCur)
2734 {
2735 AssertMsgFailed(("pfnAtRuntimeError=%p was not found\n", pfnAtRuntimeError));
2736 return VERR_FILE_NOT_FOUND;
2737 }
2738
2739 /*
2740 * Unlink it.
2741 */
2742 if (pPrev)
2743 {
2744 pPrev->pNext = pCur->pNext;
2745 if (!pCur->pNext)
2746 pVM->vm.s.ppAtRuntimeErrorNext = &pPrev->pNext;
2747 }
2748 else
2749 {
2750 pVM->vm.s.pAtRuntimeError = pCur->pNext;
2751 if (!pCur->pNext)
2752 pVM->vm.s.ppAtRuntimeErrorNext = &pVM->vm.s.pAtRuntimeError;
2753 }
2754
2755 /*
2756 * Free it.
2757 */
2758 pCur->pfnAtRuntimeError = NULL;
2759 pCur->pNext = NULL;
2760 MMR3HeapFree(pCur);
2761
2762 return VINF_SUCCESS;
2763}
2764
2765
2766/**
2767 * Ellipsis to va_list wrapper for calling pfnAtRuntimeError.
2768 */
2769static void vmR3SetRuntimeErrorWorkerDoCall(PVM pVM, PVMATRUNTIMEERROR pCur, bool fFatal,
2770 const char *pszErrorID,
2771 const char *pszFormat, ...)
2772{
2773 va_list va;
2774 va_start(va, pszFormat);
2775 pCur->pfnAtRuntimeError(pVM, pCur->pvUser, fFatal, pszErrorID, pszFormat, va);
2776 va_end(va);
2777}
2778
2779
2780/**
2781 * This is a worker function for GC and Ring-0 calls to VMSetError and VMSetErrorV.
2782 * The message is found in VMINT.
2783 *
2784 * @param pVM The VM handle.
2785 * @thread EMT.
2786 */
2787VMR3DECL(void) VMR3SetRuntimeErrorWorker(PVM pVM)
2788{
2789 VM_ASSERT_EMT(pVM);
2790 AssertReleaseMsgFailed(("And we have a winner! You get to implement Ring-0 and GC VMSetRuntimeErrorV! Contrats!\n"));
2791
2792 /*
2793 * Unpack the error (if we managed to format one).
2794 */
2795 PVMRUNTIMEERROR pErr = pVM->vm.s.pRuntimeErrorR3;
2796 const char *pszErrorID = NULL;
2797 const char *pszMessage;
2798 bool fFatal = false;
2799 if (pErr)
2800 {
2801 AssertCompile(sizeof(const char) == sizeof(uint8_t));
2802 if (pErr->offErrorID)
2803 pszErrorID = (const char *)pErr + pErr->offErrorID;
2804 if (pErr->offMessage)
2805 pszMessage = (const char *)pErr + pErr->offMessage;
2806 else
2807 pszMessage = "No message!";
2808 fFatal = pErr->fFatal;
2809 }
2810 else
2811 pszMessage = "No message! (Failed to allocate memory to put the error message in!)";
2812
2813 /*
2814 * Call the at runtime error callbacks.
2815 */
2816 for (PVMATRUNTIMEERROR pCur = pVM->vm.s.pAtRuntimeError; pCur; pCur = pCur->pNext)
2817 vmR3SetRuntimeErrorWorkerDoCall(pVM, pCur, fFatal, pszErrorID, "%s", pszMessage);
2818}
2819
2820
2821/**
2822 * Worker which calls everyone listening to the VM runtime error messages.
2823 *
2824 * @param pVM The VM handle.
2825 * @param fFatal Whether it is a fatal error or not.
2826 * @param pszErrorID Error ID string.
2827 * @param pszFormat Format string.
2828 * @param pArgs Pointer to the format arguments.
2829 * @thread EMT
2830 */
2831DECLCALLBACK(void) vmR3SetRuntimeErrorV(PVM pVM, bool fFatal,
2832 const char *pszErrorID,
2833 const char *pszFormat, va_list *pArgs)
2834{
2835 /*
2836 * Make a copy of the message.
2837 */
2838 vmSetRuntimeErrorCopy(pVM, fFatal, pszErrorID, pszFormat, *pArgs);
2839
2840 /*
2841 * Call the at error callbacks.
2842 */
2843 for (PVMATRUNTIMEERROR pCur = pVM->vm.s.pAtRuntimeError; pCur; pCur = pCur->pNext)
2844 {
2845 va_list va2;
2846 va_copy(va2, *pArgs);
2847 pCur->pfnAtRuntimeError(pVM, pCur->pvUser, fFatal, pszErrorID, pszFormat, va2);
2848 va_end(va2);
2849 }
2850}
2851
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