VirtualBox

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

Last change on this file since 2476 was 2376, checked in by vboxsync, 18 years ago

1ns steps as well please.

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