VirtualBox

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

最後變更 在這個檔案從4071是 4071,由 vboxsync 提交於 18 年 前

Biggest check-in ever. New source code headers for all (C) innotek files.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette