VirtualBox

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

Last change on this file since 2663 was 2508, checked in by vboxsync, 18 years ago

Drop the poweroff workaround as the problem should be fixed now. (And if it isn't I wish to know.)

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