VirtualBox

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

Last change on this file since 400 was 234, checked in by vboxsync, 18 years ago

VMM: Added support for runtime error notifications (VMSetRuntimeError and friends).

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