VirtualBox

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

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

amd64 compile fixes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 73.3 KB
Line 
1/* $Id: VM.cpp 47 2007-01-15 18:29:09Z 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);
118
119
120/**
121 * Do global VMM init.
122 *
123 * @returns VBox status code.
124 */
125VMR3DECL(int) VMR3GlobalInit(void)
126{
127 /*
128 * Only once.
129 */
130 static bool fDone = false;
131 if (fDone)
132 return VINF_SUCCESS;
133
134 /*
135 * We're done.
136 */
137 fDone = true;
138 return VINF_SUCCESS;
139}
140
141
142
143/**
144 * Creates a virtual machine by calling the supplied configuration constructor.
145 *
146 * On successful returned the VM is powered, i.e. VMR3PowerOn() should be
147 * called to start the execution.
148 *
149 * @returns 0 on success.
150 * @returns VBox error code on failure.
151 * @param pfnVMAtError Pointer to callback function for setting VM errors.
152 * This is called in the EM.
153 * @param pvUserVM The user argument passed to pfnVMAtError.
154 * @param pfnCFGMConstructor Pointer to callback function for constructing the VM configuration tree.
155 * This is called in the EM.
156 * @param pvUserCFGM The user argument passed to pfnCFGMConstructor.
157 * @param ppVM Where to store the 'handle' of the created VM.
158 */
159VMR3DECL(int) VMR3Create(PFNVMATERROR pfnVMAtError, void *pvUserVM, PFNCFGMCONSTRUCTOR pfnCFGMConstructor, void *pvUserCFGM, PVM *ppVM)
160{
161 LogFlow(("VMR3Create: pfnVMAtError=%p pvUserVM=%p pfnCFGMConstructor=%p pvUserCFGM=%p ppVM=%p\n", pfnVMAtError, pvUserVM, pfnCFGMConstructor, pvUserCFGM, ppVM));
162
163 /*
164 * Because of the current hackiness of the applications
165 * we'll have to initialize global stuff from here.
166 * Later the applications will take care of this in a proper way.
167 */
168 static bool fGlobalInitDone = false;
169 if (!fGlobalInitDone)
170 {
171 int rc = VMR3GlobalInit();
172 if (VBOX_FAILURE(rc))
173 return rc;
174 fGlobalInitDone = true;
175 }
176
177 /*
178 * Init support library.
179 */
180 PSUPDRVSESSION pSession = NULL;
181 int rc = SUPInit(&pSession, 0);
182 if (VBOX_SUCCESS(rc))
183 {
184 /*
185 * Allocate memory for the VM structure.
186 */
187 RTHCPHYS HCPhysVM;
188 PVM pVM = (PVM)SUPContAlloc(RT_ALIGN_Z(sizeof(*pVM), PAGE_SIZE), &HCPhysVM);
189 if (pVM)
190 {
191 Log(("VMR3Create: Allocated pVM=%p HCPhysVM=%VHp\n", pVM, HCPhysVM));
192
193 /*
194 * Do basic init of the VM structure.
195 */
196 memset(pVM, 0, sizeof(*pVM));
197 pVM->pVMHC = pVM;
198 pVM->HCPhysVM = HCPhysVM;
199 pVM->pSession = pSession;
200 pVM->vm.s.offVM = RT_OFFSETOF(VM, vm.s);
201 pVM->vm.s.ppAtResetNext = &pVM->vm.s.pAtReset;
202 pVM->vm.s.ppAtStateNext = &pVM->vm.s.pAtState;
203 pVM->vm.s.ppAtErrorNext = &pVM->vm.s.pAtError;
204 rc = RTSemEventCreate(&pVM->vm.s.EventSemWait);
205 if (VBOX_FAILURE(rc))
206 {
207 AssertMsgFailed(("RTSemEventCreate -> rc=%Vrc\n", rc));
208 return rc;
209 }
210
211 /*
212 * Initialize STAM.
213 */
214 rc = STAMR3Init(pVM);
215 if (VBOX_SUCCESS(rc))
216 {
217 /*
218 * Create the EMT thread and make it do VM initialization and go sleep
219 * in EM waiting for requests.
220 */
221 VMEMULATIONTHREADARGS Args;
222 Args.pVM = pVM;
223 rc = RTThreadCreate(&pVM->ThreadEMT, &vmR3EmulationThread, &Args, _1M,
224 RTTHREADTYPE_EMULATION, RTTHREADFLAGS_WAITABLE, "EMT");
225 if (VBOX_SUCCESS(rc))
226 {
227 /*
228 * Issue a VM Create request and wait for it to complete.
229 */
230 PVMREQ pReq;
231 rc = VMR3ReqCall(pVM, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3Create, 5, pVM, pfnVMAtError, pvUserVM, pfnCFGMConstructor, pvUserCFGM);
232 if (VBOX_SUCCESS(rc))
233 {
234 rc = pReq->iStatus;
235 VMR3ReqFree(pReq);
236 if (VBOX_SUCCESS(rc))
237 {
238 *ppVM = pVM;
239 LogFlow(("VMR3Create: returns VINF_SUCCESS *ppVM=%p\n", pVM));
240 return VINF_SUCCESS;
241 }
242 AssertMsgFailed(("vmR3Create failed rc=%Vrc\n", rc));
243 }
244 else
245 AssertMsgFailed(("VMR3ReqCall failed rc=%Vrc\n", rc));
246
247 /* Forcefully terminate the emulation thread. */
248 VM_FF_SET(pVM, VM_FF_TERMINATE);
249 VMR3NotifyFF(pVM, false);
250 RTThreadWait(pVM->ThreadEMT, 1000, NULL);
251 }
252
253 int rc2 = STAMR3Term(pVM);
254 AssertRC(rc2);
255 }
256
257 /* cleanup the heap. */
258 int rc2 = MMR3Term(pVM);
259 AssertRC(rc2);
260
261 /* free VM memory */
262 rc2 = SUPContFree(pVM);
263 AssertRC(rc2);
264 }
265 else
266 {
267 AssertMsgFailed(("Failed to allocate %d bytes of contiguous memory\n", RT_ALIGN(sizeof(*pVM), PAGE_SIZE)));
268 rc = VERR_NO_MEMORY;
269 }
270
271 /* terminate SUPLib */
272 int rc2 = SUPTerm(false);
273 AssertRC(rc2);
274 }
275 else
276 {
277 const char *pszError;
278 /*
279 * An error occurred at support library initialization time (before the
280 * VM could be created). Set the error message directly using the
281 * initial callback, as the callback list doesn't exist yet.
282 */
283 switch (rc)
284 {
285 case VERR_VM_DRIVER_LOAD_ERROR:
286 pszError = N_("VirtualBox kernel driver not loaded");
287 break;
288 case VERR_VM_DRIVER_NOT_ACCESSIBLE:
289 pszError = N_("VirtualBox kernel driver not accessible, permission problem");
290 break;
291 case VERR_VM_DRIVER_NOT_INSTALLED:
292 pszError = N_("VirtualBox kernel driver not installed");
293 break;
294 case VERR_NO_MEMORY:
295 pszError = N_("VirtualBox support library out of memory");
296 break;
297 case VERR_VERSION_MISMATCH:
298 pszError = N_("VirtualBox support driver version mismatch");
299 break;
300 default:
301 pszError = N_("Unknown error initializing kernel driver (%Vrc)");
302 AssertMsgFailed(("Add error message for rc=%d (%Vrc)\n", rc, rc));
303 }
304 vmR3CallVMAtError(pfnVMAtError, pvUserVM, rc, RT_SRC_POS, pszError, rc);
305 }
306
307 LogFlow(("VMR3Create: returns %Vrc\n", rc));
308 return rc;
309}
310
311
312/**
313 * Wrapper for getting a correct va_list.
314 */
315static void vmR3CallVMAtError(PFNVMATERROR pfnVMAtError, void *pvUser, int rc, RT_SRC_POS_DECL, const char *pszError, ...)
316{
317 va_list va;
318 va_start(va, pszError);
319 pfnVMAtError(NULL, pvUser, rc, RT_SRC_POS_ARGS, pszError, va);
320 va_end(va);
321}
322
323
324/**
325 * Initializes the VM.
326 */
327static int vmR3Create(PVM pVM, PFNVMATERROR pfnVMAtError, void *pvUserVM, PFNCFGMCONSTRUCTOR pfnCFGMConstructor, void *pvUserCFGM)
328{
329 int rc = VINF_SUCCESS;
330
331 /* Register error callback if specified. */
332 if (pfnVMAtError)
333 rc = VMR3AtErrorRegister(pVM, pfnVMAtError, pvUserVM);
334 if (VBOX_SUCCESS(rc))
335 {
336 /*
337 * Init the configuration.
338 */
339 rc = CFGMR3Init(pVM, pfnCFGMConstructor, pvUserCFGM);
340 if (VBOX_SUCCESS(rc))
341 {
342 /*
343 * If executing in fake suplib mode disable RR3 and RR0 in the config.
344 */
345 const char *psz = getenv("VBOX_SUPLIB_FAKE");
346 if (psz && !strcmp(psz, "fake"))
347 {
348 CFGMR3RemoveValue(CFGMR3GetRoot(pVM), "RawR3Enabled");
349 CFGMR3InsertInteger(CFGMR3GetRoot(pVM), "RawR3Enabled", 0);
350 CFGMR3RemoveValue(CFGMR3GetRoot(pVM), "RawR0Enabled");
351 CFGMR3InsertInteger(CFGMR3GetRoot(pVM), "RawR0Enabled", 0);
352 }
353
354 /*
355 * Check if the required minimum of resources are available.
356 */
357 /** @todo Check if the required minimum of resources are available. */
358 if (VBOX_SUCCESS(rc))
359 {
360#if defined(__AMD64__)
361 pVM->fCSAMEnabled = false;
362 pVM->fPATMEnabled = false;
363 #ifndef __WIN__
364 pVM->fRawR0Enabled = false;
365 pVM->fRawR3Enabled = false;
366 #endif
367#endif
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.
813 *
814 * @returns 0 on success.
815 * @returns VBox error code on failure.
816 * @param pVM VM to suspend.
817 * @thread EMT
818 */
819static DECLCALLBACK(int) vmR3Suspend(PVM pVM)
820{
821 LogFlow(("vmR3Suspend: pVM=%p\n", pVM));
822
823 /*
824 * Validate input.
825 */
826 if (pVM->enmVMState != VMSTATE_RUNNING)
827 {
828 AssertMsgFailed(("Invalid VM state %d\n", pVM->enmVMState));
829 return VERR_VM_INVALID_VM_STATE;
830 }
831
832 /*
833 * Change the state, notify the components and resume the execution.
834 */
835 vmR3SetState(pVM, VMSTATE_SUSPENDED);
836 PDMR3Suspend(pVM);
837
838 return VINF_EM_SUSPEND;
839}
840
841
842/**
843 * Resume VM execution.
844 *
845 * @returns 0 on success.
846 * @returns VBox error code on failure.
847 * @param pVM The VM to resume.
848 * @thread Any thread.
849 * @vmstate Suspended
850 * @vmstateto Running
851 */
852VMR3DECL(int) VMR3Resume(PVM pVM)
853{
854 LogFlow(("VMR3Resume: pVM=%p\n", pVM));
855
856 /*
857 * Validate input.
858 */
859 if (!pVM)
860 {
861 AssertMsgFailed(("Invalid VM pointer\n"));
862 return VERR_INVALID_PARAMETER;
863 }
864
865 /*
866 * Request the operation in EMT.
867 */
868 PVMREQ pReq;
869 int rc = VMR3ReqCall(pVM, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3Resume, 1, pVM);
870 if (VBOX_SUCCESS(rc))
871 {
872 rc = pReq->iStatus;
873 VMR3ReqFree(pReq);
874 }
875
876 LogFlow(("VMR3Resume: returns %Vrc\n", rc));
877 return rc;
878}
879
880
881/**
882 * Resume VM execution.
883 *
884 * @returns 0 on success.
885 * @returns VBox error code on failure.
886 * @param pVM The VM to resume.
887 * @thread EMT
888 */
889static DECLCALLBACK(int) vmR3Resume(PVM pVM)
890{
891 LogFlow(("vmR3Resume: pVM=%p\n", pVM));
892
893 /*
894 * Validate input.
895 */
896 if (pVM->enmVMState != VMSTATE_SUSPENDED)
897 {
898 AssertMsgFailed(("Invalid VM state %d\n", pVM->enmVMState));
899 return VERR_VM_INVALID_VM_STATE;
900 }
901
902 /*
903 * Change the state, notify the components and resume the execution.
904 */
905 vmR3SetState(pVM, VMSTATE_RUNNING);
906 PDMR3Resume(pVM);
907
908 return VINF_EM_RESUME;
909}
910
911
912/**
913 * Save current VM state.
914 *
915 * To save and terminate the VM, the VM must be suspended before the call.
916 *
917 * @returns 0 on success.
918 * @returns VBox error code on failure.
919 * @param pVM VM which state should be saved.
920 * @param pszFilename Name of the save state file.
921 * @param pfnProgress Progress callback. Optional.
922 * @param pvUser User argument for the progress callback.
923 * @thread Any thread.
924 * @vmstate Suspended
925 * @vmstateto Unchanged state.
926 */
927VMR3DECL(int) VMR3Save(PVM pVM, const char *pszFilename, PFNVMPROGRESS pfnProgress, void *pvUser)
928{
929 LogFlow(("VMR3Save: pVM=%p pszFilename=%p:{%s} pfnProgress=%p pvUser=%p\n", pVM, pszFilename, pszFilename, pfnProgress, pvUser));
930
931 /*
932 * Validate input.
933 */
934 if (!pVM)
935 {
936 AssertMsgFailed(("Invalid VM pointer\n"));
937 return VERR_INVALID_PARAMETER;
938 }
939 if (!pszFilename)
940 {
941 AssertMsgFailed(("Must specify a filename to save the state to, wise guy!\n"));
942 return VERR_INVALID_PARAMETER;
943 }
944
945 /*
946 * Request the operation in EMT.
947 */
948 PVMREQ pReq;
949 int rc = VMR3ReqCall(pVM, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3Save, 4, pVM, pszFilename, pfnProgress, pvUser);
950 if (VBOX_SUCCESS(rc))
951 {
952 rc = pReq->iStatus;
953 VMR3ReqFree(pReq);
954 }
955
956 LogFlow(("VMR3Save: returns %Vrc\n", rc));
957 return rc;
958}
959
960
961/**
962 * Save current VM state.
963 *
964 * To save and terminate the VM, the VM must be suspended before the call.
965 *
966 * @returns 0 on success.
967 * @returns VBox error code on failure.
968 * @param pVM VM which state should be saved.
969 * @param pszFilename Name of the save state file.
970 * @param pfnProgress Progress callback. Optional.
971 * @param pvUser User argument for the progress callback.
972 * @thread EMT
973 */
974static DECLCALLBACK(int) vmR3Save(PVM pVM, const char *pszFilename, PFNVMPROGRESS pfnProgress, void *pvUser)
975{
976 LogFlow(("vmR3Save: pVM=%p pszFilename=%p:{%s} pfnProgress=%p pvUser=%p\n", pVM, pszFilename, pszFilename, pfnProgress, pvUser));
977
978 /*
979 * Validate input.
980 */
981 if (pVM->enmVMState != VMSTATE_SUSPENDED)
982 {
983 AssertMsgFailed(("Invalid VM state %d\n", pVM->enmVMState));
984 return VERR_VM_INVALID_VM_STATE;
985 }
986
987 /*
988 * Change the state and perform the save.
989 */
990 /** @todo implement progress support in SSM */
991 vmR3SetState(pVM, VMSTATE_SAVING);
992 int rc = SSMR3Save(pVM, pszFilename, SSMAFTER_CONTINUE, pfnProgress, pvUser);
993 vmR3SetState(pVM, VMSTATE_SUSPENDED);
994
995 return rc;
996}
997
998
999/**
1000 * Loads a new VM state.
1001 *
1002 * To restore a saved state on VM startup, call this function and then
1003 * resume the VM instead of powering it on.
1004 *
1005 * @returns 0 on success.
1006 * @returns VBox error code on failure.
1007 * @param pVM VM which state should be saved.
1008 * @param pszFilename Name of the save state file.
1009 * @param pfnProgress Progress callback. Optional.
1010 * @param pvUser User argument for the progress callback.
1011 * @thread Any thread.
1012 * @vmstate Created, Suspended
1013 * @vmstateto Suspended
1014 */
1015VMR3DECL(int) VMR3Load(PVM pVM, const char *pszFilename, PFNVMPROGRESS pfnProgress, void *pvUser)
1016{
1017 LogFlow(("VMR3Load: pVM=%p pszFilename=%p:{%s} pfnProgress=%p pvUser=%p\n", pVM, pszFilename, pszFilename, pfnProgress, pvUser));
1018
1019 /*
1020 * Validate input.
1021 */
1022 if (!pVM)
1023 {
1024 AssertMsgFailed(("Invalid VM pointer\n"));
1025 return VERR_INVALID_PARAMETER;
1026 }
1027 if (!pszFilename)
1028 {
1029 AssertMsgFailed(("Must specify a filename to load the state from, wise guy!\n"));
1030 return VERR_INVALID_PARAMETER;
1031 }
1032
1033 /*
1034 * Request the operation in EMT.
1035 */
1036 PVMREQ pReq;
1037 int rc = VMR3ReqCall(pVM, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3Load, 4, pVM, pszFilename, pfnProgress, pvUser);
1038 if (VBOX_SUCCESS(rc))
1039 {
1040 rc = pReq->iStatus;
1041 VMR3ReqFree(pReq);
1042 }
1043
1044 LogFlow(("VMR3Load: returns %Vrc\n", rc));
1045 return rc;
1046}
1047
1048
1049/**
1050 * Loads a new VM state.
1051 *
1052 * To restore a saved state on VM startup, call this function and then
1053 * resume the VM instead of powering it on.
1054 *
1055 * @returns 0 on success.
1056 * @returns VBox error code on failure.
1057 * @param pVM VM which state should be saved.
1058 * @param pszFilename Name of the save state file.
1059 * @param pfnProgress Progress callback. Optional.
1060 * @param pvUser User argument for the progress callback.
1061 * @thread EMT.
1062 */
1063static DECLCALLBACK(int) vmR3Load(PVM pVM, const char *pszFilename, PFNVMPROGRESS pfnProgress, void *pvUser)
1064{
1065 LogFlow(("vmR3Load: pVM=%p pszFilename=%p:{%s} pfnProgress=%p pvUser=%p\n", pVM, pszFilename, pszFilename, pfnProgress, pvUser));
1066
1067 /*
1068 * Validate input.
1069 */
1070 if ( pVM->enmVMState != VMSTATE_SUSPENDED
1071 && pVM->enmVMState != VMSTATE_CREATED)
1072 {
1073 AssertMsgFailed(("Invalid VM state %d\n", pVM->enmVMState));
1074 return VMSetError(pVM, VERR_VM_INVALID_VM_STATE, RT_SRC_POS, N_("Invalid VM state (%s) for restoring state from '%s'"),
1075 VMR3GetStateName(pVM->enmVMState), pszFilename);
1076 }
1077
1078 /*
1079 * Change the state and perform the load.
1080 */
1081 vmR3SetState(pVM, VMSTATE_LOADING);
1082 int rc = SSMR3Load(pVM, pszFilename, SSMAFTER_RESUME, pfnProgress, pvUser);
1083 if (VBOX_SUCCESS(rc))
1084 {
1085 VMR3Relocate(pVM, 0); /* paranoia */
1086 vmR3SetState(pVM, VMSTATE_SUSPENDED);
1087 }
1088 else
1089 {
1090 vmR3SetState(pVM, VMSTATE_LOAD_FAILURE);
1091 rc = VMSetError(pVM, rc, RT_SRC_POS, N_("Failed to restore VM state from '%s' (%Vrc)"), pszFilename, rc);
1092 }
1093
1094 return rc;
1095}
1096
1097
1098/**
1099 * Power Off the VM.
1100 *
1101 * @returns 0 on success.
1102 * @returns VBox error code on failure.
1103 * @param pVM VM which should be destroyed.
1104 * @thread Any thread.
1105 * @vmstate Suspended, Running, Guru Mediation, Load Failure
1106 * @vmstateto Off
1107 */
1108VMR3DECL(int) VMR3PowerOff(PVM pVM)
1109{
1110 LogFlow(("VMR3PowerOff: pVM=%p\n", pVM));
1111
1112 /*
1113 * Validate input.
1114 */
1115 if (!pVM)
1116 {
1117 AssertMsgFailed(("Invalid VM pointer\n"));
1118 return VERR_INVALID_PARAMETER;
1119 }
1120
1121 /*
1122 * Request the operation in EMT.
1123 */
1124 PVMREQ pReq;
1125 int rc = VMR3ReqCall(pVM, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3PowerOff, 1, pVM);
1126 if (VBOX_SUCCESS(rc))
1127 {
1128 rc = pReq->iStatus;
1129 VMR3ReqFree(pReq);
1130 }
1131
1132 LogFlow(("VMR3PowerOff: returns %Vrc\n", rc));
1133 return rc;
1134}
1135
1136
1137/**
1138 * Power Off the VM.
1139 *
1140 * @returns 0 on success.
1141 * @returns VBox error code on failure.
1142 * @param pVM VM which should be destroyed.
1143 * @thread EMT.
1144 */
1145static DECLCALLBACK(int) vmR3PowerOff(PVM pVM)
1146{
1147 LogFlow(("vmR3PowerOff: pVM=%p\n", pVM));
1148
1149 /*
1150 * Validate input.
1151 */
1152 if ( pVM->enmVMState != VMSTATE_RUNNING
1153 && pVM->enmVMState != VMSTATE_SUSPENDED
1154 && pVM->enmVMState != VMSTATE_LOAD_FAILURE
1155 && pVM->enmVMState != VMSTATE_GURU_MEDITATION)
1156 {
1157 AssertMsgFailed(("Invalid VM state %d\n", pVM->enmVMState));
1158 return VERR_VM_INVALID_VM_STATE;
1159 }
1160
1161 /*
1162 * For debugging purposes, we will log a summary of the guest state at this point.
1163 */
1164 if (pVM->enmVMState != VMSTATE_GURU_MEDITATION)
1165 {
1166 /** @todo make the state dumping at VMR3PowerOff optional. */
1167 RTLogRelPrintf("****************** Guest state at power off ******************\n");
1168 DBGFR3Info(pVM, "cpumguest", "verbose", DBGFR3InfoLogRelHlp());
1169 RTLogRelPrintf("***\n");
1170 DBGFR3Info(pVM, "mode", NULL, DBGFR3InfoLogRelHlp());
1171 RTLogRelPrintf("***\n");
1172 DBGFR3Info(pVM, "activetimers", NULL, DBGFR3InfoLogRelHlp());
1173 RTLogRelPrintf("***\n");
1174 DBGFR3Info(pVM, "gdt", NULL, DBGFR3InfoLogRelHlp());
1175 /** @todo dump guest call stack. */
1176#if 1 // temporary while debugging #1589
1177 RTLogRelPrintf("***\n");
1178 DBGFR3Info(pVM, "pit", NULL, DBGFR3InfoLogRelHlp());
1179 //RTLogRelPrintf("***\n");
1180 //DBGFR3Info(pVM, "handlers", NULL, DBGFR3InfoLogRelHlp());
1181 uint32_t esp = CPUMGetGuestESP(pVM);
1182 if ( CPUMGetGuestSS(pVM) == 0
1183 && esp < _64K)
1184 {
1185 RTLogRelPrintf("***\n"
1186 "ss:sp=0000:%04x ", esp);
1187 void *pv;
1188 int rc = PGMPhysGCPtr2HCPtr(pVM, esp, &pv);
1189 if (VBOX_SUCCESS(rc))
1190 {
1191 const uint8_t *pb = (uint8_t *)((uintptr_t)pv & ~(uintptr_t)0x3f);
1192 RTLogRelPrintf("pb=%p pv=%p\n"
1193 "%.*Rhxd\n", pb, pv,
1194 PAGE_SIZE - ((uintptr_t)pb & PAGE_OFFSET_MASK), pb);
1195 }
1196 else
1197 RTLogRelPrintf("rc=%Vrc\n", rc);
1198 /* grub ... */
1199 if (esp < 0x2000 && esp > 0x1fc0)
1200 {
1201 int rc = PGMPhysGCPtr2HCPtr(pVM, 0x8000, &pv);
1202 if (VBOX_SUCCESS(rc))
1203 RTLogRelPrintf("0000:8000 TO 0000:87ff: pv=%p\n"
1204 "%.*Rhxd\n", pv, 0x8000, pv);
1205 }
1206 /* microsoft cdrom hang ... */
1207 if (true)
1208 {
1209 int rc = PGMPhysGCPtr2HCPtr(pVM, 0x20000, &pv);
1210 if (VBOX_SUCCESS(rc))
1211 RTLogRelPrintf("2000:0000 TO 2000:01ff: pv=%p\n"
1212 "%.*Rhxd\n", pv, 0x200, pv);
1213 }
1214 }
1215#endif
1216 RTLogRelPrintf("************** End of Guest state at power off ***************\n");
1217 }
1218
1219 /*
1220 * Change the state to OFF and notify the components.
1221 */
1222 vmR3SetState(pVM, VMSTATE_OFF);
1223 PDMR3PowerOff(pVM);
1224
1225 return VINF_EM_OFF;
1226}
1227
1228
1229/**
1230 * Destroys the VM.
1231 * The VM must be powered off (or never really powered on) to call this function.
1232 * The VM handle is destroyed and can no longer be used up successful return.
1233 *
1234 * @returns 0 on success.
1235 * @returns VBox error code on failure.
1236 * @param pVM VM which should be destroyed.
1237 * @thread Any thread but the emulation thread.
1238 * @vmstate Off, Created
1239 * @vmstateto N/A
1240 */
1241VMR3DECL(int) VMR3Destroy(PVM pVM)
1242{
1243 LogFlow(("VMR3Destroy: pVM=%p\n", pVM));
1244
1245 /*
1246 * Validate input.
1247 */
1248 if (!pVM)
1249 return VERR_INVALID_PARAMETER;
1250 if ( pVM->enmVMState != VMSTATE_OFF
1251 && pVM->enmVMState != VMSTATE_CREATED)
1252 {
1253 AssertMsgFailed(("Invalid VM state %d\n", pVM->enmVMState));
1254 return VERR_VM_INVALID_VM_STATE;
1255 }
1256
1257 /*
1258 * Unlink the VM and change it's state to destroying.
1259 */
1260/** @todo lock this when we start having multiple machines in a process... */
1261 PVM pPrev = NULL;
1262 PVM pCur = g_pVMsHead;
1263 while (pCur && pCur != pVM)
1264 {
1265 pPrev = pCur;
1266 pCur = pCur->pNext;
1267 }
1268 if (!pCur)
1269 {
1270 AssertMsgFailed(("pVM=%p is INVALID!\n", pVM));
1271 return VERR_INVALID_PARAMETER;
1272 }
1273 if (pPrev)
1274 pPrev->pNext = pCur->pNext;
1275 else
1276 g_pVMsHead = pCur->pNext;
1277
1278 vmR3SetState(pVM, VMSTATE_DESTROYING);
1279
1280
1281 /*
1282 * Notify registered at destruction listeners.
1283 * (That's the debugger console.)
1284 */
1285 vmR3AtDtor(pVM);
1286
1287 pVM->pNext = g_pVMsHead;
1288 g_pVMsHead = pVM;
1289
1290 /*
1291 * If we are the EMT we'll delay the cleanup till later.
1292 */
1293 if (VM_IS_EMT(pVM))
1294 {
1295 pVM->vm.s.fEMTDoesTheCleanup = true;
1296 VM_FF_SET(pVM, VM_FF_TERMINATE);
1297 }
1298 else
1299 {
1300 /*
1301 * Request EMT to do the larger part of the destruction.
1302 */
1303 PVMREQ pReq = NULL;
1304 int rc = VMR3ReqCall(pVM, &pReq, 0, (PFNRT)vmR3Destroy, 1, pVM);
1305 while (rc == VERR_TIMEOUT)
1306 rc = VMR3ReqWait(pReq, RT_INDEFINITE_WAIT);
1307 if (VBOX_SUCCESS(rc))
1308 rc = pReq->iStatus;
1309 VMR3ReqFree(pReq);
1310
1311 /*
1312 * Wait for the EMT thread to terminate.
1313 */
1314 VM_FF_SET(pVM, VM_FF_TERMINATE);
1315 uint64_t u64Start = RTTimeMilliTS();
1316 do
1317 {
1318 VMR3NotifyFF(pVM, false);
1319 rc = RTThreadWait(pVM->ThreadEMT, 1000, NULL);
1320 } while ( RTTimeMilliTS() - u64Start < 30000 /* 30 sec */
1321 && rc == VERR_TIMEOUT);
1322 AssertMsgRC(rc, ("EMT thread wait failed, rc=%Vrc\n", rc));
1323
1324 /*
1325 * Now do the final bit where the heap and VM structures are freed up.
1326 */
1327 vmR3DestroyFinalBit(pVM);
1328 }
1329
1330 LogFlow(("VMR3Destroy: returns VINF_SUCCESS\n"));
1331 return VINF_SUCCESS;
1332}
1333
1334
1335/**
1336 * Internal destruction worker. This will do nearly all of the
1337 * job, including quitting the emulation thread.
1338 *
1339 * @returns VBox status.
1340 * @param pVM VM handle.
1341 */
1342DECLCALLBACK(int) vmR3Destroy(PVM pVM)
1343{
1344 LogFlow(("vmR3Destroy: pVM=%p\n", pVM));
1345 VM_ASSERT_EMT(pVM);
1346
1347 /*
1348 * Dump statistics to the log.
1349 */
1350#if defined(VBOX_WITH_STATISTICS) || defined(LOG_ENABLED)
1351 RTLogFlags(NULL, "nodisabled nobuffered");
1352#endif
1353#ifdef VBOX_WITH_STATISTICS
1354 STAMR3Dump(pVM, "*");
1355#endif /* VBOX_WITH_STATISTICS */
1356
1357 /*
1358 * Destroy the VM components.
1359 */
1360 int rc = TMR3Term(pVM);
1361 AssertRC(rc);
1362 rc = DBGCTcpTerminate(pVM, pVM->vm.s.pvDBGC);
1363 pVM->vm.s.pvDBGC = NULL;
1364 AssertRC(rc);
1365 rc = DBGFR3Term(pVM);
1366 AssertRC(rc);
1367 rc = PDMR3Term(pVM);
1368 AssertRC(rc);
1369 rc = EMR3Term(pVM);
1370 AssertRC(rc);
1371 rc = IOMR3Term(pVM);
1372 AssertRC(rc);
1373 rc = CSAMR3Term(pVM);
1374 AssertRC(rc);
1375 rc = PATMR3Term(pVM);
1376 AssertRC(rc);
1377 rc = TRPMR3Term(pVM);
1378 AssertRC(rc);
1379 rc = SELMR3Term(pVM);
1380 AssertRC(rc);
1381 rc = REMR3Term(pVM);
1382 AssertRC(rc);
1383 rc = HWACCMR3Term(pVM);
1384 AssertRC(rc);
1385 rc = VMMR3Term(pVM);
1386 AssertRC(rc);
1387 rc = PGMR3Term(pVM);
1388 AssertRC(rc);
1389 rc = CPUMR3Term(pVM);
1390 AssertRC(rc);
1391 rc = STAMR3Term(pVM);
1392 AssertRC(rc);
1393 rc = PDMR3CritSectTerm(pVM);
1394 AssertRC(rc);
1395 /* MM is destroyed later in vmR3DestroyFinalBit() for heap reasons. */
1396
1397 /*
1398 * We're done in this thread.
1399 */
1400 pVM->fForcedActions = VM_FF_TERMINATE;
1401 LogFlow(("vmR3Destroy: returning %Vrc\n", VINF_EM_TERMINATE));
1402 return VINF_EM_TERMINATE;
1403}
1404
1405
1406/**
1407 * Does the final part of the VM destruction.
1408 * This is called by EMT in it's final stage or by the VMR3Destroy caller.
1409 *
1410 * @param pVM VM Handle.
1411 */
1412void vmR3DestroyFinalBit(PVM pVM)
1413{
1414 /*
1415 * Free the event semaphores associated with the request packets.s
1416 */
1417 unsigned cReqs = 0;
1418 for (unsigned i = 0; i < ELEMENTS(pVM->vm.s.apReqFree); i++)
1419 {
1420 PVMREQ pReq = pVM->vm.s.apReqFree[i];
1421 pVM->vm.s.apReqFree[i] = NULL;
1422 for (; pReq; pReq = pReq->pNext, cReqs++)
1423 {
1424 pReq->enmState = VMREQSTATE_INVALID;
1425 RTSemEventDestroy(pReq->EventSem);
1426 }
1427 }
1428 Assert(cReqs == pVM->vm.s.cReqFree); NOREF(cReqs);
1429
1430 /*
1431 * Kill all queued requests. (There really shouldn't be any!)
1432 */
1433 for (unsigned i = 0; i < 10; i++)
1434 {
1435 PVMREQ pReqHead = (PVMREQ)ASMAtomicXchgPtr((void *volatile *)&pVM->vm.s.pReqs, NULL);
1436 AssertMsg(!pReqHead, ("This isn't supposed to happen! VMR3Destroy caller has to serialize this.\n"));
1437 if (!pReqHead)
1438 break;
1439 for (PVMREQ pReq = pReqHead; pReq; pReq = pReq->pNext)
1440 {
1441 ASMAtomicXchgSize(&pReq->iStatus, VERR_INTERNAL_ERROR);
1442 ASMAtomicXchgSize(&pReq->enmState, VMREQSTATE_INVALID);
1443 RTSemEventSignal(pReq->EventSem);
1444 RTThreadSleep(2);
1445 RTSemEventDestroy(pReq->EventSem);
1446 }
1447 /* give them a chance to respond before we free the request memory. */
1448 RTThreadSleep(32);
1449 }
1450
1451 /*
1452 * Modify state and then terminate MM.
1453 * (MM must be delayed until this point so we don't destroy the callbacks and the request packet.)
1454 */
1455 vmR3SetState(pVM, VMSTATE_TERMINATED);
1456 int rc = MMR3Term(pVM);
1457 AssertRC(rc);
1458
1459 /*
1460 * Free the VM structure.
1461 */
1462 rc = SUPContFree(pVM);
1463 AssertRC(rc);
1464 rc = SUPTerm();
1465 AssertRC(rc);
1466
1467 RTLogFlush(NULL);
1468}
1469
1470
1471/**
1472 * Enumerates the VMs in this process.
1473 *
1474 * @returns Pointer to the next VM.
1475 * @returns NULL when no more VMs.
1476 * @param pVMPrev The previous VM
1477 * Use NULL to start the enumeration.
1478 */
1479VMR3DECL(PVM) VMR3EnumVMs(PVM pVMPrev)
1480{
1481 /*
1482 * This is quick and dirty. It has issues with VM being
1483 * destroyed during the enumeration.
1484 */
1485 if (pVMPrev)
1486 return pVMPrev->pNext;
1487 return g_pVMsHead;
1488}
1489
1490
1491/**
1492 * Registers an at VM destruction callback.
1493 *
1494 * @returns VBox status code.
1495 * @param pfnAtDtor Pointer to callback.
1496 * @param pvUser User argument.
1497 */
1498VMR3DECL(int) VMR3AtDtorRegister(PFNVMATDTOR pfnAtDtor, void *pvUser)
1499{
1500 /*
1501 * Check if already registered.
1502 */
1503 VM_ATDTOR_LOCK();
1504 PVMATDTOR pCur = g_pVMAtDtorHead;
1505 while (pCur)
1506 {
1507 if (pfnAtDtor == pCur->pfnAtDtor)
1508 {
1509 VM_ATDTOR_UNLOCK();
1510 AssertMsgFailed(("Already registered at destruction callback %p!\n", pfnAtDtor));
1511 return VERR_INVALID_PARAMETER;
1512 }
1513
1514 /* next */
1515 pCur = pCur->pNext;
1516 }
1517 VM_ATDTOR_UNLOCK();
1518
1519 /*
1520 * Allocate new entry.
1521 */
1522 PVMATDTOR pVMAtDtor = (PVMATDTOR)RTMemAlloc(sizeof(*pVMAtDtor));
1523 if (!pVMAtDtor)
1524 return VERR_NO_MEMORY;
1525
1526 VM_ATDTOR_LOCK();
1527 pVMAtDtor->pfnAtDtor = pfnAtDtor;
1528 pVMAtDtor->pvUser = pvUser;
1529 pVMAtDtor->pNext = g_pVMAtDtorHead;
1530 g_pVMAtDtorHead = pVMAtDtor;
1531 VM_ATDTOR_UNLOCK();
1532
1533 return VINF_SUCCESS;
1534}
1535
1536
1537/**
1538 * Deregisters an at VM destruction callback.
1539 *
1540 * @returns VBox status code.
1541 * @param pfnAtDtor Pointer to callback.
1542 */
1543VMR3DECL(int) VMR3AtDtorDeregister(PFNVMATDTOR pfnAtDtor)
1544{
1545 /*
1546 * Find it, unlink it and free it.
1547 */
1548 VM_ATDTOR_LOCK();
1549 PVMATDTOR pPrev = NULL;
1550 PVMATDTOR pCur = g_pVMAtDtorHead;
1551 while (pCur)
1552 {
1553 if (pfnAtDtor == pCur->pfnAtDtor)
1554 {
1555 if (pPrev)
1556 pPrev->pNext = pCur->pNext;
1557 else
1558 g_pVMAtDtorHead = pCur->pNext;
1559 pCur->pNext = NULL;
1560 VM_ATDTOR_UNLOCK();
1561
1562 RTMemFree(pCur);
1563 return VINF_SUCCESS;
1564 }
1565
1566 /* next */
1567 pPrev = pCur;
1568 pCur = pCur->pNext;
1569 }
1570 VM_ATDTOR_UNLOCK();
1571
1572 return VERR_INVALID_PARAMETER;
1573}
1574
1575
1576/**
1577 * Walks the list of at VM destructor callbacks.
1578 * @param pVM The VM which is about to be destroyed.
1579 */
1580static void vmR3AtDtor(PVM pVM)
1581{
1582 /*
1583 * Find it, unlink it and free it.
1584 */
1585 VM_ATDTOR_LOCK();
1586 for (PVMATDTOR pCur = g_pVMAtDtorHead; pCur; pCur = pCur->pNext)
1587 pCur->pfnAtDtor(pVM, pCur->pvUser);
1588 VM_ATDTOR_UNLOCK();
1589}
1590
1591
1592/**
1593 * Reset the current VM.
1594 *
1595 * @returns VBox status code.
1596 * @param pVM VM to reset.
1597 */
1598VMR3DECL(int) VMR3Reset(PVM pVM)
1599{
1600 int rc = VINF_SUCCESS;
1601
1602 /*
1603 * Check the state.
1604 */
1605 if (!pVM)
1606 return VERR_INVALID_PARAMETER;
1607 if ( pVM->enmVMState != VMSTATE_RUNNING
1608 && pVM->enmVMState != VMSTATE_SUSPENDED)
1609 {
1610 AssertMsgFailed(("Invalid VM state %d\n", pVM->enmVMState));
1611 return VERR_VM_INVALID_VM_STATE;
1612 }
1613
1614 /*
1615 * Queue reset request to the emulation thread
1616 * and wait for it to be processed.
1617 */
1618 PVMREQ pReq = NULL;
1619 rc = VMR3ReqCall(pVM, &pReq, 0, (PFNRT)vmR3Reset, 1, pVM);
1620 while (rc == VERR_TIMEOUT)
1621 rc = VMR3ReqWait(pReq, RT_INDEFINITE_WAIT);
1622 if (VBOX_SUCCESS(rc))
1623 rc = pReq->iStatus;
1624 VMR3ReqFree(pReq);
1625
1626 return rc;
1627}
1628
1629
1630/**
1631 * Worker which checks integrity of some internal structures.
1632 * This is yet another attempt to track down that AVL tree crash.
1633 */
1634static void vmR3CheckIntegrity(PVM pVM)
1635{
1636#ifdef VBOX_STRICT
1637 int rc = PGMR3CheckIntegrity(pVM);
1638 AssertReleaseRC(rc);
1639#endif
1640}
1641
1642
1643/**
1644 * Reset request processor.
1645 *
1646 * This is called by the emulation thread as a response to the
1647 * reset request issued by VMR3Reset().
1648 *
1649 * @returns VBox status code.
1650 * @param pVM VM to reset.
1651 */
1652static DECLCALLBACK(int) vmR3Reset(PVM pVM)
1653{
1654 /*
1655 * As a safety precaution we temporarily change the state while resetting.
1656 * (If VMR3Reset was not called from EMT we might have change state... let's ignore that fact for now.)
1657 */
1658 VMSTATE enmVMState = pVM->enmVMState;
1659 Assert(enmVMState == VMSTATE_SUSPENDED || enmVMState == VMSTATE_RUNNING);
1660 vmR3SetState(pVM, VMSTATE_RESETTING);
1661 vmR3CheckIntegrity(pVM);
1662
1663
1664 /*
1665 * Reset the VM components.
1666 */
1667 PATMR3Reset(pVM);
1668 CSAMR3Reset(pVM);
1669 PGMR3Reset(pVM); /* We clear VM RAM in PGMR3Reset. It's vital PDMR3Reset is executed
1670 * _afterwards_. E.g. ACPI sets up RAM tables during init/reset. */
1671 PDMR3Reset(pVM);
1672 SELMR3Reset(pVM);
1673 TRPMR3Reset(pVM);
1674 vmR3AtReset(pVM);
1675 REMR3Reset(pVM);
1676 IOMR3Reset(pVM);
1677 CPUMR3Reset(pVM);
1678 TMR3Reset(pVM);
1679 EMR3Reset(pVM);
1680 HWACCMR3Reset(pVM); /* This must come *after* PATM, CSAM, CPUM, SELM and TRPM. */
1681
1682#ifdef LOG_ENABLED
1683 /*
1684 * Debug logging.
1685 */
1686 RTLogPrintf("\n\nThe VM was reset:\n");
1687 DBGFR3Info(pVM, "cpum", "verbose", NULL);
1688#endif
1689
1690 /*
1691 * Restore the state.
1692 */
1693 vmR3CheckIntegrity(pVM);
1694 Assert(pVM->enmVMState == VMSTATE_RESETTING);
1695 vmR3SetState(pVM, enmVMState);
1696
1697#if defined(__AMD64__)
1698 pVM->fCSAMEnabled = false;
1699 pVM->fPATMEnabled = false;
1700 #ifndef __WIN__
1701 pVM->fRawR0Enabled = false;
1702 pVM->fRawR3Enabled = false;
1703 #endif
1704#endif
1705 return VINF_EM_RESET;
1706}
1707
1708
1709/**
1710 * Walks the list of at VM reset callbacks and calls them
1711 *
1712 * @returns VBox status code.
1713 * Any failure is fatal.
1714 * @param pVM The VM which is being reset.
1715 */
1716static int vmR3AtReset(PVM pVM)
1717{
1718 /*
1719 * Walk the list and call them all.
1720 */
1721 int rc = VINF_SUCCESS;
1722 for (PVMATRESET pCur = pVM->vm.s.pAtReset; pCur; pCur = pCur->pNext)
1723 {
1724 /* do the call */
1725 switch (pCur->enmType)
1726 {
1727 case VMATRESETTYPE_DEV:
1728 rc = pCur->u.Dev.pfnCallback(pCur->u.Dev.pDevIns, pCur->pvUser);
1729 break;
1730 case VMATRESETTYPE_INTERNAL:
1731 rc = pCur->u.Internal.pfnCallback(pVM, pCur->pvUser);
1732 break;
1733 case VMATRESETTYPE_EXTERNAL:
1734 pCur->u.External.pfnCallback(pCur->pvUser);
1735 break;
1736 default:
1737 AssertMsgFailed(("Invalid at-reset type %d!\n", pCur->enmType));
1738 return VERR_INTERNAL_ERROR;
1739 }
1740
1741 if (VBOX_FAILURE(rc))
1742 {
1743 AssertMsgFailed(("At-reset handler %s failed with rc=%d\n", pCur->pszDesc, rc));
1744 return rc;
1745 }
1746 }
1747
1748 return VINF_SUCCESS;
1749}
1750
1751
1752/**
1753 * Internal registration function
1754 */
1755static int vmr3AtResetRegister(PVM pVM, void *pvUser, const char *pszDesc, PVMATRESET *ppNew)
1756{
1757 /*
1758 * Allocate restration structure.
1759 */
1760 PVMATRESET pNew = (PVMATRESET)MMR3HeapAlloc(pVM, MM_TAG_VM, sizeof(*pNew));
1761 if (pNew)
1762 {
1763 /* fill data. */
1764 pNew->pNext = NULL;
1765 pNew->pszDesc = pszDesc;
1766 pNew->pvUser = pvUser;
1767
1768 /* insert */
1769 *pVM->vm.s.ppAtResetNext = pNew;
1770 pVM->vm.s.ppAtResetNext = &pNew->pNext;
1771
1772 return VINF_SUCCESS;
1773 }
1774 return VERR_NO_MEMORY;
1775}
1776
1777
1778/**
1779 * Registers an at VM reset callback.
1780 *
1781 * @returns VBox status code.
1782 * @param pVM The VM.
1783 * @param pDevInst Device instance.
1784 * @param pfnCallback Callback function.
1785 * @param pvUser User argument.
1786 * @param pszDesc Description (optional).
1787 */
1788VMR3DECL(int) VMR3AtResetRegister(PVM pVM, PPDMDEVINS pDevInst, PFNVMATRESET pfnCallback, void *pvUser, const char *pszDesc)
1789{
1790 /*
1791 * Validate.
1792 */
1793 if (!pDevInst)
1794 {
1795 AssertMsgFailed(("pDevIns is NULL!\n"));
1796 return VERR_INVALID_PARAMETER;
1797 }
1798
1799 /*
1800 * Create the new entry.
1801 */
1802 PVMATRESET pNew;
1803 int rc = vmr3AtResetRegister(pVM, pvUser, pszDesc, &pNew);
1804 if (VBOX_SUCCESS(rc))
1805 {
1806 /*
1807 * Fill in type data.
1808 */
1809 pNew->enmType = VMATRESETTYPE_DEV;
1810 pNew->u.Dev.pfnCallback = pfnCallback;
1811 pNew->u.Dev.pDevIns = pDevInst;
1812 }
1813
1814 return rc;
1815}
1816
1817
1818/**
1819 * Registers an at VM reset internal callback.
1820 *
1821 * @returns VBox status code.
1822 * @param pVM The VM.
1823 * @param pfnCallback Callback function.
1824 * @param pvUser User argument.
1825 * @param pszDesc Description (optional).
1826 */
1827VMR3DECL(int) VMR3AtResetRegisterInternal(PVM pVM, PFNVMATRESETINT pfnCallback, void *pvUser, const char *pszDesc)
1828{
1829 /*
1830 * Validate.
1831 */
1832 if (!pfnCallback)
1833 {
1834 AssertMsgFailed(("pfnCallback is NULL!\n"));
1835 return VERR_INVALID_PARAMETER;
1836 }
1837
1838 /*
1839 * Create the new entry.
1840 */
1841 PVMATRESET pNew;
1842 int rc = vmr3AtResetRegister(pVM, pvUser, pszDesc, &pNew);
1843 if (VBOX_SUCCESS(rc))
1844 {
1845 /*
1846 * Fill in type data.
1847 */
1848 pNew->enmType = VMATRESETTYPE_INTERNAL;
1849 pNew->u.Internal.pfnCallback = pfnCallback;
1850 }
1851
1852 return rc;
1853}
1854
1855
1856/**
1857 * Registers an at VM reset external callback.
1858 *
1859 * @returns VBox status code.
1860 * @param pVM The VM.
1861 * @param pfnCallback Callback function.
1862 * @param pvUser User argument.
1863 * @param pszDesc Description (optional).
1864 */
1865VMR3DECL(int) VMR3AtResetRegisterExternal(PVM pVM, PFNVMATRESETEXT pfnCallback, void *pvUser, const char *pszDesc)
1866{
1867 /*
1868 * Validate.
1869 */
1870 if (!pfnCallback)
1871 {
1872 AssertMsgFailed(("pfnCallback is NULL!\n"));
1873 return VERR_INVALID_PARAMETER;
1874 }
1875
1876 /*
1877 * Create the new entry.
1878 */
1879 PVMATRESET pNew;
1880 int rc = vmr3AtResetRegister(pVM, pvUser, pszDesc, &pNew);
1881 if (VBOX_SUCCESS(rc))
1882 {
1883 /*
1884 * Fill in type data.
1885 */
1886 pNew->enmType = VMATRESETTYPE_EXTERNAL;
1887 pNew->u.External.pfnCallback = pfnCallback;
1888 }
1889
1890 return rc;
1891}
1892
1893
1894/**
1895 * Unlinks and frees a callback.
1896 *
1897 * @returns Pointer to the next callback structure.
1898 * @param pVM The VM.
1899 * @param pCur The one to free.
1900 * @param pPrev The one before pCur.
1901 */
1902static PVMATRESET vmr3AtResetFree(PVM pVM, PVMATRESET pCur, PVMATRESET pPrev)
1903{
1904 /*
1905 * Unlink it.
1906 */
1907 PVMATRESET pNext = pCur->pNext;
1908 if (pPrev)
1909 {
1910 pPrev->pNext = pNext;
1911 if (!pNext)
1912 pVM->vm.s.ppAtResetNext = &pPrev->pNext;
1913 }
1914 else
1915 {
1916 pVM->vm.s.pAtReset = pNext;
1917 if (!pNext)
1918 pVM->vm.s.ppAtResetNext = &pVM->vm.s.pAtReset;
1919 }
1920
1921 /*
1922 * Free it.
1923 */
1924 MMR3HeapFree(pCur);
1925
1926 return pNext;
1927}
1928
1929
1930/**
1931 * Deregisters an at VM reset callback.
1932 *
1933 * @returns VBox status code.
1934 * @param pVM The VM.
1935 * @param pDevInst Device instance.
1936 * @param pfnCallback Callback function.
1937 */
1938VMR3DECL(int) VMR3AtResetDeregister(PVM pVM, PPDMDEVINS pDevInst, PFNVMATRESET pfnCallback)
1939{
1940 int rc = VERR_VM_ATRESET_NOT_FOUND;
1941 PVMATRESET pPrev = NULL;
1942 PVMATRESET pCur = pVM->vm.s.pAtReset;
1943 while (pCur)
1944 {
1945 if ( pCur->enmType == VMATRESETTYPE_DEV
1946 && pCur->u.Dev.pDevIns == pDevInst
1947 && (!pfnCallback || pCur->u.Dev.pfnCallback == pfnCallback))
1948 {
1949 pCur = vmr3AtResetFree(pVM, pCur, pPrev);
1950 rc = VINF_SUCCESS;
1951 }
1952 else
1953 {
1954 pPrev = pCur;
1955 pCur = pCur->pNext;
1956 }
1957 }
1958
1959 AssertRC(rc);
1960 return rc;
1961}
1962
1963
1964/**
1965 * Deregisters an at VM reset internal callback.
1966 *
1967 * @returns VBox status code.
1968 * @param pVM The VM.
1969 * @param pfnCallback Callback function.
1970 */
1971VMR3DECL(int) VMR3AtResetDeregisterInternal(PVM pVM, PFNVMATRESETINT pfnCallback)
1972{
1973 int rc = VERR_VM_ATRESET_NOT_FOUND;
1974 PVMATRESET pPrev = NULL;
1975 PVMATRESET pCur = pVM->vm.s.pAtReset;
1976 while (pCur)
1977 {
1978 if ( pCur->enmType == VMATRESETTYPE_INTERNAL
1979 && pCur->u.Internal.pfnCallback == pfnCallback)
1980 {
1981 pCur = vmr3AtResetFree(pVM, pCur, pPrev);
1982 rc = VINF_SUCCESS;
1983 }
1984 else
1985 {
1986 pPrev = pCur;
1987 pCur = pCur->pNext;
1988 }
1989 }
1990
1991 AssertRC(rc);
1992 return rc;
1993}
1994
1995
1996/**
1997 * Deregisters an at VM reset external callback.
1998 *
1999 * @returns VBox status code.
2000 * @param pVM The VM.
2001 * @param pfnCallback Callback function.
2002 */
2003VMR3DECL(int) VMR3AtResetDeregisterExternal(PVM pVM, PFNVMATRESETEXT pfnCallback)
2004{
2005 int rc = VERR_VM_ATRESET_NOT_FOUND;
2006 PVMATRESET pPrev = NULL;
2007 PVMATRESET pCur = pVM->vm.s.pAtReset;
2008 while (pCur)
2009 {
2010 if ( pCur->enmType == VMATRESETTYPE_INTERNAL
2011 && pCur->u.External.pfnCallback == pfnCallback)
2012 {
2013 pCur = vmr3AtResetFree(pVM, pCur, pPrev);
2014 rc = VINF_SUCCESS;
2015 }
2016 else
2017 {
2018 pPrev = pCur;
2019 pCur = pCur->pNext;
2020 }
2021 }
2022
2023 AssertRC(rc);
2024 return rc;
2025}
2026
2027
2028/**
2029 * Gets the current VM state.
2030 *
2031 * @returns The current VM state.
2032 * @param pVM VM handle.
2033 * @thread Any
2034 */
2035VMR3DECL(VMSTATE) VMR3GetState(PVM pVM)
2036{
2037 return pVM->enmVMState;
2038}
2039
2040
2041/**
2042 * Gets the state name string for a VM state.
2043 *
2044 * @returns Pointer to the state name. (readonly)
2045 * @param enmState The state.
2046 */
2047VMR3DECL(const char *) VMR3GetStateName(VMSTATE enmState)
2048{
2049 switch (enmState)
2050 {
2051 case VMSTATE_CREATING: return "CREATING";
2052 case VMSTATE_CREATED: return "CREATED";
2053 case VMSTATE_RUNNING: return "RUNNING";
2054 case VMSTATE_LOADING: return "LOADING";
2055 case VMSTATE_LOAD_FAILURE: return "LOAD_FAILURE";
2056 case VMSTATE_SAVING: return "SAVING";
2057 case VMSTATE_SUSPENDED: return "SUSPENDED";
2058 case VMSTATE_RESETTING: return "RESETTING";
2059 case VMSTATE_GURU_MEDITATION: return "GURU_MEDIATION";
2060 case VMSTATE_OFF: return "OFF";
2061 case VMSTATE_DESTROYING: return "DESTROYING";
2062 case VMSTATE_TERMINATED: return "TERMINATED";
2063 default:
2064 AssertMsgFailed(("Unknown state %d\n", enmState));
2065 return "Unknown!\n";
2066 }
2067}
2068
2069
2070/**
2071 * Sets the current VM state.
2072 *
2073 * @returns The current VM state.
2074 * @param pVM VM handle.
2075 * @param enmStateNew The new state.
2076 */
2077static void vmR3SetState(PVM pVM, VMSTATE enmStateNew)
2078{
2079 VMSTATE enmStateOld = pVM->enmVMState;
2080 pVM->enmVMState = enmStateNew;
2081 LogRel(("Changing the VM state from '%s' to '%s'.\n", VMR3GetStateName(enmStateOld), VMR3GetStateName(enmStateNew)));
2082
2083 /*
2084 * Call the at state change callbacks.
2085 */
2086 for (PVMATSTATE pCur = pVM->vm.s.pAtState; pCur; pCur = pCur->pNext)
2087 {
2088 pCur->pfnAtState(pVM, enmStateNew, enmStateOld, pCur->pvUser);
2089 if (pVM->enmVMState == VMSTATE_DESTROYING)
2090 break;
2091 AssertMsg(pVM->enmVMState == enmStateNew,
2092 ("You are not allowed to change the state while in the change callback, except "
2093 "from destroying the VM. There are restrictions in the way the state changes "
2094 "are propagated up to the EM execution loop and it makes the program flow very "
2095 "difficult to follow.\n"));
2096 }
2097}
2098
2099
2100/**
2101 * Registers a VM state change callback.
2102 *
2103 * You are not allowed to call any function which changes the VM state from a
2104 * state callback, except VMR3Destroy().
2105 *
2106 * @returns VBox status code.
2107 * @param pVM VM handle.
2108 * @param pfnAtState Pointer to callback.
2109 * @param pvUser User argument.
2110 * @thread Any.
2111 */
2112VMR3DECL(int) VMR3AtStateRegister(PVM pVM, PFNVMATSTATE pfnAtState, void *pvUser)
2113{
2114 LogFlow(("VMR3AtStateRegister: pfnAtState=%p pvUser=%p\n", pfnAtState, pvUser));
2115
2116 /*
2117 * Validate input.
2118 */
2119 if (!pfnAtState)
2120 {
2121 AssertMsgFailed(("callback is required\n"));
2122 return VERR_INVALID_PARAMETER;
2123 }
2124
2125 /*
2126 * Make sure we're in EMT (to avoid the logging).
2127 */
2128 PVMREQ pReq;
2129 int rc = VMR3ReqCall(pVM, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3AtStateRegister, 3, pVM, pfnAtState, pvUser);
2130 if (VBOX_FAILURE(rc))
2131 return rc;
2132 rc = pReq->iStatus;
2133 VMR3ReqFree(pReq);
2134
2135 LogFlow(("VMR3AtStateRegister: returns %Vrc\n", rc));
2136 return rc;
2137}
2138
2139
2140/**
2141 * Registers a VM state change callback.
2142 *
2143 * @returns VBox status code.
2144 * @param pVM VM handle.
2145 * @param pfnAtState Pointer to callback.
2146 * @param pvUser User argument.
2147 * @thread EMT
2148 */
2149static DECLCALLBACK(int) vmR3AtStateRegister(PVM pVM, PFNVMATSTATE pfnAtState, void *pvUser)
2150{
2151 /*
2152 * Allocate a new record.
2153 */
2154
2155 PVMATSTATE pNew = (PVMATSTATE)MMR3HeapAlloc(pVM, MM_TAG_VM, sizeof(*pNew));
2156 if (!pNew)
2157 return VERR_NO_MEMORY;
2158
2159 /* fill */
2160 pNew->pfnAtState = pfnAtState;
2161 pNew->pvUser = pvUser;
2162 pNew->pNext = NULL;
2163
2164 /* insert */
2165 *pVM->vm.s.ppAtStateNext = pNew;
2166 pVM->vm.s.ppAtStateNext = &pNew->pNext;
2167
2168 return VINF_SUCCESS;
2169}
2170
2171
2172/**
2173 * Deregisters a VM state change callback.
2174 *
2175 * @returns VBox status code.
2176 * @param pVM VM handle.
2177 * @param pfnAtState Pointer to callback.
2178 * @param pvUser User argument.
2179 * @thread Any.
2180 */
2181VMR3DECL(int) VMR3AtStateDeregister(PVM pVM, PFNVMATSTATE pfnAtState, void *pvUser)
2182{
2183 LogFlow(("VMR3AtStateDeregister: pfnAtState=%p pvUser=%p\n", pfnAtState, pvUser));
2184
2185 /*
2186 * Validate input.
2187 */
2188 if (!pfnAtState)
2189 {
2190 AssertMsgFailed(("callback is required\n"));
2191 return VERR_INVALID_PARAMETER;
2192 }
2193
2194 /*
2195 * Make sure we're in EMT (to avoid the logging).
2196 */
2197 PVMREQ pReq;
2198 int rc = VMR3ReqCall(pVM, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3AtStateDeregister, 3, pVM, pfnAtState, pvUser);
2199 if (VBOX_FAILURE(rc))
2200 return rc;
2201 rc = pReq->iStatus;
2202 VMR3ReqFree(pReq);
2203
2204 LogFlow(("VMR3AtStateDeregister: returns %Vrc\n", rc));
2205 return rc;
2206}
2207
2208
2209/**
2210 * Deregisters a VM state change callback.
2211 *
2212 * @returns VBox status code.
2213 * @param pVM VM handle.
2214 * @param pfnAtState Pointer to callback.
2215 * @param pvUser User argument.
2216 * @thread EMT
2217 */
2218static DECLCALLBACK(int) vmR3AtStateDeregister(PVM pVM, PFNVMATSTATE pfnAtState, void *pvUser)
2219{
2220 LogFlow(("vmR3AtStateDeregister: pfnAtState=%p pvUser=%p\n", pfnAtState, pvUser));
2221
2222 /*
2223 * Search the list for the entry.
2224 */
2225 PVMATSTATE pPrev = NULL;
2226 PVMATSTATE pCur = pVM->vm.s.pAtState;
2227 while ( pCur
2228 && pCur->pfnAtState == pfnAtState
2229 && pCur->pvUser == pvUser)
2230 {
2231 pPrev = pCur;
2232 pCur = pCur->pNext;
2233 }
2234 if (!pCur)
2235 {
2236 AssertMsgFailed(("pfnAtState=%p was not found\n", pfnAtState));
2237 return VERR_FILE_NOT_FOUND;
2238 }
2239
2240 /*
2241 * Unlink it.
2242 */
2243 if (pPrev)
2244 {
2245 pPrev->pNext = pCur->pNext;
2246 if (!pCur->pNext)
2247 pVM->vm.s.ppAtStateNext = &pPrev->pNext;
2248 }
2249 else
2250 {
2251 pVM->vm.s.pAtState = pCur->pNext;
2252 if (!pCur->pNext)
2253 pVM->vm.s.ppAtStateNext = &pVM->vm.s.pAtState;
2254 }
2255
2256 /*
2257 * Free it.
2258 */
2259 pCur->pfnAtState = NULL;
2260 pCur->pNext = NULL;
2261 MMR3HeapFree(pCur);
2262
2263 return VINF_SUCCESS;
2264}
2265
2266
2267/**
2268 * Registers a VM error callback.
2269 *
2270 * @returns VBox status code.
2271 * @param pVM The VM handle.
2272 * @param pfnAtError Pointer to callback.
2273 * @param pvUser User argument.
2274 * @thread Any.
2275 */
2276VMR3DECL(int) VMR3AtErrorRegister(PVM pVM, PFNVMATERROR pfnAtError, void *pvUser)
2277{
2278 LogFlow(("VMR3AtErrorRegister: pfnAtError=%p pvUser=%p\n", pfnAtError, pvUser));
2279
2280 /*
2281 * Validate input.
2282 */
2283 if (!pfnAtError)
2284 {
2285 AssertMsgFailed(("callback is required\n"));
2286 return VERR_INVALID_PARAMETER;
2287 }
2288
2289 /*
2290 * Make sure we're in EMT (to avoid the logging).
2291 */
2292 PVMREQ pReq;
2293 int rc = VMR3ReqCall(pVM, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3AtErrorRegister, 3, pVM, pfnAtError, pvUser);
2294 if (VBOX_FAILURE(rc))
2295 return rc;
2296 rc = pReq->iStatus;
2297 VMR3ReqFree(pReq);
2298
2299 LogFlow(("VMR3AtErrorRegister: returns %Vrc\n", rc));
2300 return rc;
2301}
2302
2303
2304/**
2305 * Registers a VM error callback.
2306 *
2307 * @returns VBox status code.
2308 * @param pVM The VM handle.
2309 * @param pfnAtError Pointer to callback.
2310 * @param pvUser User argument.
2311 * @thread EMT
2312 */
2313static DECLCALLBACK(int) vmR3AtErrorRegister(PVM pVM, PFNVMATERROR pfnAtError, void *pvUser)
2314{
2315 /*
2316 * Allocate a new record.
2317 */
2318
2319 PVMATERROR pNew = (PVMATERROR)MMR3HeapAlloc(pVM, MM_TAG_VM, sizeof(*pNew));
2320 if (!pNew)
2321 return VERR_NO_MEMORY;
2322
2323 /* fill */
2324 pNew->pfnAtError = pfnAtError;
2325 pNew->pvUser = pvUser;
2326 pNew->pNext = NULL;
2327
2328 /* insert */
2329 *pVM->vm.s.ppAtErrorNext = pNew;
2330 pVM->vm.s.ppAtErrorNext = &pNew->pNext;
2331
2332 return VINF_SUCCESS;
2333}
2334
2335
2336/**
2337 * Deregisters a VM error callback.
2338 *
2339 * @returns VBox status code.
2340 * @param pVM The VM handle.
2341 * @param pfnAtError Pointer to callback.
2342 * @param pvUser User argument.
2343 * @thread Any.
2344 */
2345VMR3DECL(int) VMR3AtErrorDeregister(PVM pVM, PFNVMATERROR pfnAtError, void *pvUser)
2346{
2347 LogFlow(("VMR3AtErrorDeregister: pfnAtError=%p pvUser=%p\n", pfnAtError, pvUser));
2348
2349 /*
2350 * Validate input.
2351 */
2352 if (!pfnAtError)
2353 {
2354 AssertMsgFailed(("callback is required\n"));
2355 return VERR_INVALID_PARAMETER;
2356 }
2357
2358 /*
2359 * Make sure we're in EMT (to avoid the logging).
2360 */
2361 PVMREQ pReq;
2362 int rc = VMR3ReqCall(pVM, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3AtErrorDeregister, 3, pVM, pfnAtError, pvUser);
2363 if (VBOX_FAILURE(rc))
2364 return rc;
2365 rc = pReq->iStatus;
2366 VMR3ReqFree(pReq);
2367
2368 LogFlow(("VMR3AtErrorDeregister: returns %Vrc\n", rc));
2369 return rc;
2370}
2371
2372
2373/**
2374 * Deregisters a VM error callback.
2375 *
2376 * @returns VBox status code.
2377 * @param pVM The VM handle.
2378 * @param pfnAtError Pointer to callback.
2379 * @param pvUser User argument.
2380 * @thread EMT
2381 */
2382static DECLCALLBACK(int) vmR3AtErrorDeregister(PVM pVM, PFNVMATERROR pfnAtError, void *pvUser)
2383{
2384 LogFlow(("vmR3AtErrorDeregister: pfnAtError=%p pvUser=%p\n", pfnAtError, pvUser));
2385
2386 /*
2387 * Search the list for the entry.
2388 */
2389 PVMATERROR pPrev = NULL;
2390 PVMATERROR pCur = pVM->vm.s.pAtError;
2391 while ( pCur
2392 && pCur->pfnAtError == pfnAtError
2393 && pCur->pvUser == pvUser)
2394 {
2395 pPrev = pCur;
2396 pCur = pCur->pNext;
2397 }
2398 if (!pCur)
2399 {
2400 AssertMsgFailed(("pfnAtError=%p was not found\n", pfnAtError));
2401 return VERR_FILE_NOT_FOUND;
2402 }
2403
2404 /*
2405 * Unlink it.
2406 */
2407 if (pPrev)
2408 {
2409 pPrev->pNext = pCur->pNext;
2410 if (!pCur->pNext)
2411 pVM->vm.s.ppAtErrorNext = &pPrev->pNext;
2412 }
2413 else
2414 {
2415 pVM->vm.s.pAtError = pCur->pNext;
2416 if (!pCur->pNext)
2417 pVM->vm.s.ppAtErrorNext = &pVM->vm.s.pAtError;
2418 }
2419
2420 /*
2421 * Free it.
2422 */
2423 pCur->pfnAtError = NULL;
2424 pCur->pNext = NULL;
2425 MMR3HeapFree(pCur);
2426
2427 return VINF_SUCCESS;
2428}
2429
2430
2431/**
2432 * Ellipsis to va_list wrapper for calling pfnAtError.
2433 */
2434static void vmR3SetErrorWorkerDoCall(PVM pVM, PVMATERROR pCur, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...)
2435{
2436 va_list va;
2437 va_start(va, pszFormat);
2438 pCur->pfnAtError(pVM, pCur->pvUser, rc, RT_SRC_POS_ARGS, pszFormat, va);
2439 va_end(va);
2440}
2441
2442
2443/**
2444 * This is a worker function for GC and Ring-0 calls to VMSetError and VMSetErrorV.
2445 * The message is found in VMINT.
2446 *
2447 * @param pVM The VM handle.
2448 * @thread EMT.
2449 */
2450VMR3DECL(void) VMR3SetErrorWorker(PVM pVM)
2451{
2452 VM_ASSERT_EMT(pVM);
2453 AssertReleaseMsgFailed(("And we have a winner! You get to implement Ring-0 and GC VMSetErrorV! Contrats!\n"));
2454
2455 /*
2456 * Unpack the error (if we managed to format one).
2457 */
2458 PVMERROR pErr = pVM->vm.s.pErrorR3;
2459 const char *pszFile = NULL;
2460 const char *pszFunction = NULL;
2461 uint32_t iLine = 0;
2462 const char *pszMessage;
2463 int32_t rc = VERR_MM_HYPER_NO_MEMORY;
2464 if (pErr)
2465 {
2466 AssertCompile(sizeof(const char) == sizeof(uint8_t));
2467 if (pErr->offFile)
2468 pszFile = (const char *)pErr + pErr->offFile;
2469 if (pErr->offFunction)
2470 pszFunction = (const char *)pErr + pErr->offFunction;
2471 if (pErr->offMessage)
2472 pszMessage = (const char *)pErr + pErr->offMessage;
2473 else
2474 pszMessage = "No message!";
2475 }
2476 else
2477 pszMessage = "No message! (Failed to allocate memory to put the error message in!)";
2478
2479 /*
2480 * Call the at error callbacks.
2481 */
2482 for (PVMATERROR pCur = pVM->vm.s.pAtError; pCur; pCur = pCur->pNext)
2483 vmR3SetErrorWorkerDoCall(pVM, pCur, rc, RT_SRC_POS_ARGS, "%s", pszMessage);
2484}
2485
2486
2487/**
2488 * Worker which calls everyone listening to the VM error messages.
2489 *
2490 * @param pVM The VM handle.
2491 * @param rc The VBox status code.
2492 * @param RT_SRC_POS_DECL The source position of this error.
2493 * @param pszFormat Format string.
2494 * @param pArgs Pointer to the format arguments.
2495 * @thread EMT
2496 */
2497DECLCALLBACK(void) vmR3SetErrorV(PVM pVM, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list *pArgs)
2498{
2499 /*
2500 * Make a copy of the message.
2501 */
2502 vmSetErrorCopy(pVM, rc, RT_SRC_POS_ARGS, pszFormat, *pArgs);
2503
2504 /*
2505 * Call the at error callbacks.
2506 */
2507 for (PVMATERROR pCur = pVM->vm.s.pAtError; pCur; pCur = pCur->pNext)
2508 {
2509 va_list va2;
2510 va_copy(va2, *pArgs);
2511 pCur->pfnAtError(pVM, pCur->pvUser, rc, RT_SRC_POS_ARGS, pszFormat, va2);
2512 va_end(va2);
2513 }
2514}
2515
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