VirtualBox

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

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

string.h & stdio.h + header cleanups.

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