VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/VMAll.cpp@ 38838

Last change on this file since 38838 was 38838, checked in by vboxsync, 13 years ago

VMM,++: Try fix the async reset, suspend and power-off problems in PDM wrt conflicting VMM requests. Split them into priority requests and normal requests. The priority requests can safely be processed when PDM is doing async state change waits, the normal ones cannot. (The problem I bumped into was a unmap-chunk request from PGM being processed during PDMR3Reset, causing a recursive VMMR3EmtRendezvous deadlock.)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 12.2 KB
Line 
1/* $Id: VMAll.cpp 38838 2011-09-23 11:21:55Z vboxsync $ */
2/** @file
3 * VM - Virtual Machine All Contexts.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Oracle Corporation
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 (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#define LOG_GROUP LOG_GROUP_VM
23#include "VMInternal.h"
24#include <VBox/vmm/vmm.h>
25#include <VBox/vmm/mm.h>
26#include <VBox/vmm/vm.h>
27#include <VBox/err.h>
28#include <VBox/log.h>
29
30#include <iprt/assert.h>
31#include <iprt/string.h>
32#ifndef IN_RC
33# include <iprt/thread.h>
34#endif
35
36
37/**
38 * Sets the error message.
39 *
40 * @returns rc. Meaning you can do:
41 * @code
42 * return VM_SET_ERROR(pVM, VERR_OF_YOUR_CHOICE, "descriptive message");
43 * @endcode
44 * @param pVM VM handle. Must be non-NULL.
45 * @param rc VBox status code.
46 * @param RT_SRC_POS_DECL Use RT_SRC_POS.
47 * @param pszFormat Error message format string.
48 * @param ... Error message arguments.
49 * @thread Any
50 */
51VMMDECL(int) VMSetError(PVM pVM, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...)
52{
53 va_list args;
54 va_start(args, pszFormat);
55 int rc2 = VMSetErrorV(pVM, rc, RT_SRC_POS_ARGS, pszFormat, args); Assert(rc == rc2); NOREF(rc2);
56 va_end(args);
57 return rc;
58}
59
60
61/**
62 * Sets the error message.
63 *
64 * @returns rc. Meaning you can do:
65 * @code
66 * return VM_SET_ERROR(pVM, VERR_OF_YOUR_CHOICE, "descriptive message");
67 * @endcode
68 * @param pVM VM handle. Must be non-NULL.
69 * @param rc VBox status code.
70 * @param RT_SRC_POS_DECL Use RT_SRC_POS.
71 * @param pszFormat Error message format string.
72 * @param args Error message arguments.
73 * @thread Any
74 */
75VMMDECL(int) VMSetErrorV(PVM pVM, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list args)
76{
77#ifdef IN_RING3
78 /*
79 * Switch to EMT.
80 */
81 va_list va2;
82 va_copy(va2, args); /* Have to make a copy here or GCC will break. */
83 VMR3ReqPriorityCallWait(pVM, VMCPUID_ANY, (PFNRT)vmR3SetErrorUV, 7, /* ASSUMES 3 source pos args! */
84 pVM->pUVM, rc, RT_SRC_POS_ARGS, pszFormat, &va2);
85 va_end(va2);
86
87#else
88 /*
89 * We're already on the EMT thread and can safely create a VMERROR chunk.
90 */
91 vmSetErrorCopy(pVM, rc, RT_SRC_POS_ARGS, pszFormat, args);
92 VMMRZCallRing3NoCpu(pVM, VMMCALLRING3_VM_SET_ERROR, 0);
93#endif
94 return rc;
95}
96
97
98/**
99 * Copies the error to a VMERROR structure.
100 *
101 * This is mainly intended for Ring-0 and GC where the error must be copied to
102 * memory accessible from ring-3. But it's just possible that we might add
103 * APIs for retrieving the VMERROR copy later.
104 *
105 * @param pVM VM handle. Must be non-NULL.
106 * @param rc VBox status code.
107 * @param RT_SRC_POS_DECL Use RT_SRC_POS.
108 * @param pszFormat Error message format string.
109 * @param args Error message arguments.
110 * @thread EMT
111 */
112void vmSetErrorCopy(PVM pVM, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list args)
113{
114#if 0 /// @todo implement Ring-0 and GC VMSetError
115 /*
116 * Create the untranslated message copy.
117 */
118 /* free any old message. */
119 MMHyperFree(pVM, MMHyperR32Ctx(pVM, pVM->vm.s.pError));
120 pVM->vm.s.pError = NULL;
121
122 /* calc reasonable start size. */
123 size_t cchFile = pszFile ? strlen(pszFile) : 0;
124 size_t cchFunction = pszFunction ? strlen(pszFunction) : 0;
125 size_t cchFormat = strlen(pszFormat);
126 size_t cb = sizeof(VMERROR)
127 + cchFile + 1
128 + cchFunction + 1
129 + cchFormat + 32;
130
131 /* allocate it */
132 void *pv;
133 int rc2 = MMHyperAlloc(pVM, cb, 0, MM_TAG_VM, &pv);
134 if (RT_SUCCESS(rc2))
135 {
136 /* initialize it. */
137 PVMERROR pErr = (PVMERROR)pv;
138 pErr->cbAllocated = cb;
139 pErr->iLine = iLine;
140 pErr->off = sizeof(VMERROR);
141 pErr->offFile = pErr->offFunction = 0;
142
143 if (cchFile)
144 {
145 pErr->offFile = pErr->off;
146 memcpy((uint8_t *)pErr + pErr->off, pszFile, cchFile + 1);
147 pErr->off += cchFile + 1;
148 }
149
150 if (cchFunction)
151 {
152 pErr->offFunction = pErr->off;
153 memcpy((uint8_t *)pErr + pErr->off, pszFunction, cchFunction + 1);
154 pErr->off += cchFunction + 1;
155 }
156
157 pErr->offMessage = pErr->off;
158
159 /* format the message (pErr might be reallocated) */
160 VMSETERRORFMTARGS Args;
161 Args.pVM = pVM;
162 Args.pErr = pErr;
163
164 va_list va2;
165 va_copy(va2, args);
166 RTStrFormatV(vmSetErrorFmtOut, &pErr, NULL, NULL, &pszFormatTmp, args);
167 va_end(va2);
168
169 /* done. */
170 pVM->vm.s.pErrorR3 = MMHyper2HC(pVM, (uintptr_t)pArgs.pErr);
171 }
172#endif
173}
174
175
176/**
177 * Sets the runtime error message.
178 *
179 * As opposed VMSetError(), this method is intended to inform the VM user about
180 * errors and error-like conditions that happen at an arbitrary point during VM
181 * execution (like "host memory low" or "out of host disk space").
182 *
183 * @returns VBox status code. For some flags the status code <b>must</b> be
184 * propagated up the stack.
185 *
186 * @param pVM The VM handle.
187 *
188 * @param fFlags Flags indicating which actions to take.
189 * See VMSETRTERR_FLAGS_* for details on each flag.
190 *
191 * @param pszErrorId Unique error identification string. This is used by
192 * the frontends and maybe other devices or drivers, so
193 * once an ID has been selected it's essentially
194 * unchangable. Employ camelcase when constructing the
195 * string, leave out spaces.
196 *
197 * The registered runtime error callbacks should string
198 * switch on this and handle the ones it knows
199 * specifically and the unknown ones generically.
200 *
201 * @param pszFormat Error message format string.
202 * @param ... Error message arguments.
203 *
204 * @thread Any
205 */
206VMMDECL(int) VMSetRuntimeError(PVM pVM, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...)
207{
208 va_list va;
209 va_start(va, pszFormat);
210 int rc = VMSetRuntimeErrorV(pVM, fFlags, pszErrorId, pszFormat, va);
211 va_end(va);
212 return rc;
213}
214
215
216/**
217 * va_list version of VMSetRuntimeError.
218 *
219 * @returns VBox status code. For some flags the status code <b>must</b> be
220 * propagated up the stack.
221 *
222 * @param pVM The VM handle.
223 * @param fFlags Flags indicating which actions to take. See
224 * VMSETRTERR_FLAGS_*.
225 * @param pszErrorId Error ID string.
226 * @param pszFormat Error message format string.
227 * @param va Error message arguments.
228 *
229 * @thread Any
230 */
231VMMDECL(int) VMSetRuntimeErrorV(PVM pVM, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, va_list va)
232{
233 Log(("VMSetRuntimeErrorV: fFlags=%#x pszErrorId=%s\n", fFlags, pszErrorId));
234
235 /*
236 * Relaxed parameter validation.
237 */
238 AssertPtr(pVM);
239 AssertMsg(!(fFlags & ~(VMSETRTERR_FLAGS_NO_WAIT | VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_FATAL)), ("%#x\n", fFlags));
240 Assert(!(fFlags & VMSETRTERR_FLAGS_NO_WAIT) || !VM_IS_EMT(pVM));
241 Assert(!(fFlags & VMSETRTERR_FLAGS_SUSPEND) || !(fFlags & VMSETRTERR_FLAGS_FATAL));
242 AssertPtr(pszErrorId);
243 Assert(*pszErrorId);
244 Assert(RTStrEnd(pszErrorId, 128) != NULL);
245 AssertPtr(pszFormat);
246 Assert(RTStrEnd(pszFormat, 512) != NULL);
247
248#ifdef IN_RING3
249 /*
250 * Switch to EMT.
251 *
252 * If it's a no-wait request, we have to format the message into a buffer
253 * here since the variable arguments list will become invalid once we call
254 * va_end and return.
255 */
256 int rc;
257 if ( !(fFlags & VMSETRTERR_FLAGS_NO_WAIT)
258 || VM_IS_EMT(pVM))
259 {
260 fFlags &= ~VMSETRTERR_FLAGS_NO_WAIT;
261
262 va_list va2;
263 va_copy(va2, va); /* Have to make a copy here or GCC will break. */
264 rc = VMR3ReqPriorityCallWait(pVM, VMCPUID_ANY,
265 (PFNRT)vmR3SetRuntimeErrorV, 5, pVM, fFlags, pszErrorId, pszFormat, &va2);
266 va_end(va2);
267 }
268 else
269 {
270 char *pszMessage = MMR3HeapAPrintfV(pVM, MM_TAG_VM, pszFormat, va);
271 rc = VMR3ReqCallNoWait(pVM, VMCPUID_ANY,
272 (PFNRT)vmR3SetRuntimeError, 4, pVM, fFlags, pszErrorId, pszMessage);
273 if (RT_FAILURE(rc))
274 MMR3HeapFree(pszMessage);
275 }
276
277#else
278 /*
279 * We're already on the EMT and can safely create a VMRUNTIMEERROR chunk.
280 */
281 AssertReleaseMsgFailed(("Congratulations! You will have the pleasure of debugging the RC/R0 path.\n"));
282 vmSetRuntimeErrorCopy(pVM, fFlags, pszErrorId, pszFormat, va);
283
284 int rc = VMMRZCallRing3NoCpu(pVM, VMMCALLRING3_VM_SET_RUNTIME_ERROR, 0);
285#endif
286
287 Log(("VMSetRuntimeErrorV: returns %Rrc (pszErrorId=%s)\n", rc, pszErrorId));
288 return rc;
289}
290
291
292/**
293 * Copies the error to a VMRUNTIMEERROR structure.
294 *
295 * This is mainly intended for Ring-0 and RC where the error must be copied to
296 * memory accessible from ring-3. But it's just possible that we might add
297 * APIs for retrieving the VMRUNTIMEERROR copy later.
298 *
299 * @param pVM VM handle. Must be non-NULL.
300 * @param fFlags The error flags.
301 * @param pszErrorId Error ID string.
302 * @param pszFormat Error message format string.
303 * @param va Error message arguments. This is of course spoiled
304 * by this call.
305 * @thread EMT
306 */
307void vmSetRuntimeErrorCopy(PVM pVM, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, va_list va)
308{
309#if 0 /// @todo implement Ring-0 and GC VMSetError
310 /*
311 * Create the untranslated message copy.
312 */
313 /* free any old message. */
314 MMHyperFree(pVM, MMHyperR32Ctx(pVM, pVM->vm.s.pRuntimeErrorR3));
315 pVM->vm.s.pRuntimeErrorR3 = NULL;
316
317 /* calc reasonable start size. */
318 size_t cchErrorID = pszErrorId ? strlen(pszErrorId) : 0;
319 size_t cchFormat = strlen(pszFormat);
320 size_t cb = sizeof(VMRUNTIMEERROR)
321 + cchErrorID + 1
322 + cchFormat + 32;
323
324 /* allocate it */
325 void *pv;
326 int rc2 = MMHyperAlloc(pVM, cb, 0, MM_TAG_VM, &pv);
327 if (RT_SUCCESS(rc2))
328 {
329 /* initialize it. */
330 PVMRUNTIMEERROR pErr = (PVMRUNTIMEERROR)pv;
331 pErr->cbAllocated = cb;
332 pErr->fFlags = fFlags;
333 pErr->off = sizeof(PVMRUNTIMEERROR);
334 pErr->offErrorID = 0;
335
336 if (cchErrorID)
337 {
338 pErr->offErrorID = pErr->off;
339 memcpy((uint8_t *)pErr + pErr->off, pszErrorId, cchErrorID + 1);
340 pErr->off += cchErrorID + 1;
341 }
342
343 pErr->offMessage = pErr->off;
344
345 /* format the message (pErr might be reallocated) */
346 VMSETRUNTIMEERRORFMTARGS Args;
347 Args.pVM = pVM;
348 Args.pErr = pErr;
349
350 va_list va2;
351 va_copy(va2, args);
352 RTStrFormatV(vmSetRuntimeErrorFmtOut, &pErr, NULL, NULL, &pszFormatTmp, args);
353 va_end(va2);
354
355 /* done. */
356 pVM->vm.s.pErrorRuntimeR3 = MMHyper2HC(pVM, (uintptr_t)pArgs.pErr);
357 }
358#endif
359}
360
361
362/**
363 * Gets the name of VM state.
364 *
365 * @returns Pointer to a read-only string with the state name.
366 * @param enmState The state.
367 */
368VMMDECL(const char *) VMGetStateName(VMSTATE enmState)
369{
370 switch (enmState)
371 {
372#define MY_CASE(enm) case VMSTATE_##enm: return #enm;
373 MY_CASE(CREATING);
374 MY_CASE(CREATED);
375 MY_CASE(RUNNING);
376 MY_CASE(LOADING);
377 MY_CASE(LOAD_FAILURE);
378 MY_CASE(SAVING);
379 MY_CASE(SUSPENDED);
380 MY_CASE(RESETTING);
381 MY_CASE(GURU_MEDITATION);
382 MY_CASE(OFF);
383 MY_CASE(DESTROYING);
384 MY_CASE(TERMINATED);
385#undef MY_CASE
386 default:
387 return "Unknown";
388 }
389}
390
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