VirtualBox

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

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

Not required.

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