VirtualBox

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

Last change on this file since 882 was 872, checked in by vboxsync, 18 years ago

Compile fix

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

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