VirtualBox

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

Last change on this file since 1184 was 914, checked in by vboxsync, 18 years ago

PVMR0 changes for darwin.

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