Changeset 234 in vbox for trunk/src/VBox
- Timestamp:
- Jan 23, 2007 1:04:38 PM (18 years ago)
- svn:sync-xref-src-repo-rev:
- 17760
- Location:
- trunk/src/VBox/VMM
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/EM.cpp
r23 r234 3385 3385 */ 3386 3386 case EMSTATE_REM: 3387 #if 0 3388 /* simulate a runtime error */ 3389 VMSetRuntimeError (pVM, true, "simulatedError", "pVM=%p", pVM); 3390 #endif 3387 3391 rc = emR3RemExecute(pVM, &fFFDone); 3388 3392 Log2(("EMR3ExecuteVM: emR3RemExecute -> %Vrc\n", rc)); -
trunk/src/VBox/VMM/VM.cpp
r226 r234 116 116 static DECLCALLBACK(int) vmR3AtErrorRegister(PVM pVM, PFNVMATERROR pfnAtError, void *pvUser); 117 117 static DECLCALLBACK(int) vmR3AtErrorDeregister(PVM pVM, PFNVMATERROR pfnAtError, void *pvUser); 118 static DECLCALLBACK(int) vmR3AtRuntimeErrorRegister(PVM pVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser); 119 static DECLCALLBACK(int) vmR3AtRuntimeErrorDeregister(PVM pVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser); 118 120 119 121 … … 202 204 pVM->vm.s.ppAtStateNext = &pVM->vm.s.pAtState; 203 205 pVM->vm.s.ppAtErrorNext = &pVM->vm.s.pAtError; 206 pVM->vm.s.ppAtRuntimeErrorNext = &pVM->vm.s.pAtRuntimeError; 204 207 rc = RTSemEventCreate(&pVM->vm.s.EventSemWait); 205 208 if (VBOX_FAILURE(rc)) … … 2480 2483 if (pErr->offFile) 2481 2484 pszFile = (const char *)pErr + pErr->offFile; 2485 iLine = pErr->iLine; 2482 2486 if (pErr->offFunction) 2483 2487 pszFunction = (const char *)pErr + pErr->offFunction; … … 2527 2531 } 2528 2532 2533 2534 /** 2535 * Registers a VM runtime error callback. 2536 * 2537 * @returns VBox status code. 2538 * @param pVM The VM handle. 2539 * @param pfnAtRuntimeError Pointer to callback. 2540 * @param pvUser User argument. 2541 * @thread Any. 2542 */ 2543 VMR3DECL(int) VMR3AtRuntimeErrorRegister(PVM pVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser) 2544 { 2545 LogFlow(("VMR3AtRuntimeErrorRegister: pfnAtRuntimeError=%p pvUser=%p\n", pfnAtRuntimeError, pvUser)); 2546 2547 /* 2548 * Validate input. 2549 */ 2550 if (!pfnAtRuntimeError) 2551 { 2552 AssertMsgFailed(("callback is required\n")); 2553 return VERR_INVALID_PARAMETER; 2554 } 2555 2556 /* 2557 * Make sure we're in EMT (to avoid the logging). 2558 */ 2559 PVMREQ pReq; 2560 int rc = VMR3ReqCall(pVM, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3AtRuntimeErrorRegister, 3, pVM, pfnAtRuntimeError, pvUser); 2561 if (VBOX_FAILURE(rc)) 2562 return rc; 2563 rc = pReq->iStatus; 2564 VMR3ReqFree(pReq); 2565 2566 LogFlow(("VMR3AtRuntimeErrorRegister: returns %Vrc\n", rc)); 2567 return rc; 2568 } 2569 2570 2571 /** 2572 * Registers a VM runtime error callback. 2573 * 2574 * @returns VBox status code. 2575 * @param pVM The VM handle. 2576 * @param pfnAtRuntimeError Pointer to callback. 2577 * @param pvUser User argument. 2578 * @thread EMT 2579 */ 2580 static DECLCALLBACK(int) vmR3AtRuntimeErrorRegister(PVM pVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser) 2581 { 2582 /* 2583 * Allocate a new record. 2584 */ 2585 2586 PVMATRUNTIMEERROR pNew = (PVMATRUNTIMEERROR)MMR3HeapAlloc(pVM, MM_TAG_VM, sizeof(*pNew)); 2587 if (!pNew) 2588 return VERR_NO_MEMORY; 2589 2590 /* fill */ 2591 pNew->pfnAtRuntimeError = pfnAtRuntimeError; 2592 pNew->pvUser = pvUser; 2593 pNew->pNext = NULL; 2594 2595 /* insert */ 2596 *pVM->vm.s.ppAtRuntimeErrorNext = pNew; 2597 pVM->vm.s.ppAtRuntimeErrorNext = &pNew->pNext; 2598 2599 return VINF_SUCCESS; 2600 } 2601 2602 2603 /** 2604 * Deregisters a VM runtime error callback. 2605 * 2606 * @returns VBox status code. 2607 * @param pVM The VM handle. 2608 * @param pfnAtRuntimeError Pointer to callback. 2609 * @param pvUser User argument. 2610 * @thread Any. 2611 */ 2612 VMR3DECL(int) VMR3AtRuntimeErrorDeregister(PVM pVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser) 2613 { 2614 LogFlow(("VMR3AtRuntimeErrorDeregister: pfnAtRuntimeError=%p pvUser=%p\n", pfnAtRuntimeError, pvUser)); 2615 2616 /* 2617 * Validate input. 2618 */ 2619 if (!pfnAtRuntimeError) 2620 { 2621 AssertMsgFailed(("callback is required\n")); 2622 return VERR_INVALID_PARAMETER; 2623 } 2624 2625 /* 2626 * Make sure we're in EMT (to avoid the logging). 2627 */ 2628 PVMREQ pReq; 2629 int rc = VMR3ReqCall(pVM, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3AtRuntimeErrorDeregister, 3, pVM, pfnAtRuntimeError, pvUser); 2630 if (VBOX_FAILURE(rc)) 2631 return rc; 2632 rc = pReq->iStatus; 2633 VMR3ReqFree(pReq); 2634 2635 LogFlow(("VMR3AtRuntimeErrorDeregister: returns %Vrc\n", rc)); 2636 return rc; 2637 } 2638 2639 2640 /** 2641 * Deregisters a VM runtime error callback. 2642 * 2643 * @returns VBox status code. 2644 * @param pVM The VM handle. 2645 * @param pfnAtRuntimeError Pointer to callback. 2646 * @param pvUser User argument. 2647 * @thread EMT 2648 */ 2649 static DECLCALLBACK(int) vmR3AtRuntimeErrorDeregister(PVM pVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser) 2650 { 2651 LogFlow(("vmR3AtRuntimeErrorDeregister: pfnAtRuntimeError=%p pvUser=%p\n", pfnAtRuntimeError, pvUser)); 2652 2653 /* 2654 * Search the list for the entry. 2655 */ 2656 PVMATRUNTIMEERROR pPrev = NULL; 2657 PVMATRUNTIMEERROR pCur = pVM->vm.s.pAtRuntimeError; 2658 while ( pCur 2659 && pCur->pfnAtRuntimeError == pfnAtRuntimeError 2660 && pCur->pvUser == pvUser) 2661 { 2662 pPrev = pCur; 2663 pCur = pCur->pNext; 2664 } 2665 if (!pCur) 2666 { 2667 AssertMsgFailed(("pfnAtRuntimeError=%p was not found\n", pfnAtRuntimeError)); 2668 return VERR_FILE_NOT_FOUND; 2669 } 2670 2671 /* 2672 * Unlink it. 2673 */ 2674 if (pPrev) 2675 { 2676 pPrev->pNext = pCur->pNext; 2677 if (!pCur->pNext) 2678 pVM->vm.s.ppAtRuntimeErrorNext = &pPrev->pNext; 2679 } 2680 else 2681 { 2682 pVM->vm.s.pAtRuntimeError = pCur->pNext; 2683 if (!pCur->pNext) 2684 pVM->vm.s.ppAtRuntimeErrorNext = &pVM->vm.s.pAtRuntimeError; 2685 } 2686 2687 /* 2688 * Free it. 2689 */ 2690 pCur->pfnAtRuntimeError = NULL; 2691 pCur->pNext = NULL; 2692 MMR3HeapFree(pCur); 2693 2694 return VINF_SUCCESS; 2695 } 2696 2697 2698 /** 2699 * Ellipsis to va_list wrapper for calling pfnAtRuntimeError. 2700 */ 2701 static void vmR3SetRuntimeErrorWorkerDoCall(PVM pVM, PVMATRUNTIMEERROR pCur, bool fFatal, 2702 const char *pszErrorID, 2703 const char *pszFormat, ...) 2704 { 2705 va_list va; 2706 va_start(va, pszFormat); 2707 pCur->pfnAtRuntimeError(pVM, pCur->pvUser, fFatal, pszErrorID, pszFormat, va); 2708 va_end(va); 2709 } 2710 2711 2712 /** 2713 * This is a worker function for GC and Ring-0 calls to VMSetError and VMSetErrorV. 2714 * The message is found in VMINT. 2715 * 2716 * @param pVM The VM handle. 2717 * @thread EMT. 2718 */ 2719 VMR3DECL(void) VMR3SetRuntimeErrorWorker(PVM pVM) 2720 { 2721 VM_ASSERT_EMT(pVM); 2722 AssertReleaseMsgFailed(("And we have a winner! You get to implement Ring-0 and GC VMSetRuntimeErrorV! Contrats!\n")); 2723 2724 /* 2725 * Unpack the error (if we managed to format one). 2726 */ 2727 PVMRUNTIMEERROR pErr = pVM->vm.s.pRuntimeErrorR3; 2728 const char *pszErrorID = NULL; 2729 const char *pszMessage; 2730 bool fFatal = false; 2731 if (pErr) 2732 { 2733 AssertCompile(sizeof(const char) == sizeof(uint8_t)); 2734 if (pErr->offErrorID) 2735 pszErrorID = (const char *)pErr + pErr->offErrorID; 2736 if (pErr->offMessage) 2737 pszMessage = (const char *)pErr + pErr->offMessage; 2738 else 2739 pszMessage = "No message!"; 2740 fFatal = pErr->fFatal; 2741 } 2742 else 2743 pszMessage = "No message! (Failed to allocate memory to put the error message in!)"; 2744 2745 /* 2746 * Call the at runtime error callbacks. 2747 */ 2748 for (PVMATRUNTIMEERROR pCur = pVM->vm.s.pAtRuntimeError; pCur; pCur = pCur->pNext) 2749 vmR3SetRuntimeErrorWorkerDoCall(pVM, pCur, fFatal, pszErrorID, "%s", pszMessage); 2750 } 2751 2752 2753 /** 2754 * Worker which calls everyone listening to the VM runtime error messages. 2755 * 2756 * @param pVM The VM handle. 2757 * @param fFatal Whether it is a fatal error or not. 2758 * @param pszErrorID Error ID string. 2759 * @param pszFormat Format string. 2760 * @param pArgs Pointer to the format arguments. 2761 * @thread EMT 2762 */ 2763 DECLCALLBACK(void) vmR3SetRuntimeErrorV(PVM pVM, bool fFatal, 2764 const char *pszErrorID, 2765 const char *pszFormat, va_list *pArgs) 2766 { 2767 /* 2768 * Make a copy of the message. 2769 */ 2770 vmSetRuntimeErrorCopy(pVM, fFatal, pszErrorID, pszFormat, *pArgs); 2771 2772 /* 2773 * Call the at error callbacks. 2774 */ 2775 for (PVMATRUNTIMEERROR pCur = pVM->vm.s.pAtRuntimeError; pCur; pCur = pCur->pNext) 2776 { 2777 va_list va2; 2778 va_copy(va2, *pArgs); 2779 pCur->pfnAtRuntimeError(pVM, pCur->pvUser, fFatal, pszErrorID, pszFormat, va2); 2780 va_end(va2); 2781 } 2782 } 2783 -
trunk/src/VBox/VMM/VMInternal.h
r23 r234 156 156 157 157 /** 158 * VM runtime error callback. 159 */ 160 typedef struct VMATRUNTIMEERROR 161 { 162 /** Pointer to the next one. */ 163 struct VMATRUNTIMEERROR *pNext; 164 /** Pointer to the callback. */ 165 PFNVMATRUNTIMEERROR pfnAtRuntimeError; 166 /** The user argument. */ 167 void *pvUser; 168 } VMATRUNTIMEERROR; 169 /** Pointer to a VM error callback. */ 170 typedef VMATRUNTIMEERROR *PVMATRUNTIMEERROR; 171 172 173 /** 174 * Chunk of memory allocated off the hypervisor heap in which 175 * we copy the runtime error details. 176 */ 177 typedef struct VMRUNTIMEERROR 178 { 179 /** The size of the chunk. */ 180 uint32_t cbAllocated; 181 /** The current offset into the chunk. 182 * We start by putting the error ID immediatly 183 * after the end of the buffer. */ 184 uint32_t off; 185 /** Offset from the start of this structure to the error ID. */ 186 uint32_t offErrorID; 187 /** Offset from the start of this structure to the formatted message text. */ 188 uint32_t offMessage; 189 /** Whether the error is fatal or not */ 190 bool fFatal; 191 } VMRUNTIMEERROR, *PVMRUNTIMEERROR; 192 193 194 /** 158 195 * Converts a VMM pointer into a VM pointer. 159 196 * @returns Pointer to the VM structure the VMM is part of. … … 186 223 /** List of registered error callbacks. */ 187 224 HCPTRTYPE(PVMATERROR *) ppAtErrorNext; 225 226 /** List of registered error callbacks. */ 227 HCPTRTYPE(PVMATRUNTIMEERROR) pAtRuntimeError; 228 /** List of registered error callbacks. */ 229 HCPTRTYPE(PVMATRUNTIMEERROR *) ppAtRuntimeErrorNext; 188 230 189 231 /** Head of the request queue. Atomic. */ … … 203 245 /** VM Error Message. */ 204 246 R3PTRTYPE(PVMERROR) pErrorR3; 247 248 /** VM Runtime Error Message. */ 249 R3PTRTYPE(PVMRUNTIMEERROR) pRuntimeErrorR3; 205 250 206 251 /** Pointer to the DBGC instance data. */ … … 245 290 DECLCALLBACK(void) vmR3SetErrorV(PVM pVM, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list *args); 246 291 void vmSetErrorCopy(PVM pVM, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list args); 292 DECLCALLBACK(void) vmR3SetRuntimeErrorV(PVM pVM, bool fFatal, const char *pszErrorID, const char *pszFormat, va_list *args); 293 void vmSetRuntimeErrorCopy(PVM pVM, bool fFatal, const char *pszErrorID, const char *pszFormat, va_list args); 247 294 void vmR3DestroyFinalBit(PVM pVM); 248 295 -
trunk/src/VBox/VMM/VMM.cpp
r161 r234 2121 2121 break; 2122 2122 2123 /* 2124 * Set the VM runtime error message. 2125 */ 2126 case VMMCALLHOST_VM_SET_RUNTIME_ERROR: 2127 VMR3SetRuntimeErrorWorker(pVM); 2128 break; 2129 2123 2130 default: 2124 2131 AssertMsgFailed(("enmCallHostOperation=%d\n", pVM->vmm.s.enmCallHostOperation)); -
trunk/src/VBox/VMM/VMMAll/VMAll.cpp
r23 r234 41 41 * @code 42 42 * return VM_SET_ERROR(pVM, VERR_OF_YOUR_CHOICE, "descriptive message"); 43 * @ codeend43 * @endcode 44 44 * @param pVM VM handle. Must be non-NULL. 45 45 * @param rc VBox status code. … … 65 65 * @code 66 66 * return VM_SET_ERROR(pVM, VERR_OF_YOUR_CHOICE, "descriptive message"); 67 * @ codeend67 * @endcode 68 68 * @param pVM VM handle. Must be non-NULL. 69 69 * @param rc VBox status code. … … 178 178 } 179 179 180 181 /** 182 * Sets the runtime error message. 183 * As opposed VMSetError(), this method is intended to inform the VM user about 184 * errors and error-like conditions that happen at an arbitrary point during VM 185 * execution (like "host memory low" or "out of host disk space"). 186 * 187 * The @a fFatal parameter defines whether the error is fatal or not. If it is 188 * true, then it is expected that the caller has already paused the VM execution 189 * before calling this method. The VM user is supposed to power off the VM 190 * immediately after it has received the runtime error notification via the 191 * FNVMATRUNTIMEERROR callback. 192 * 193 * If @a fFatal is false, then the paused state of the VM defines the kind of 194 * the error. If the VM is paused before calling this method, it means that 195 * the VM user may try to fix the error condition (i.e. free more host memory) 196 * and then resume the VM execution. If the VM is not paused before calling 197 * this method, it means that the given error is a warning about an error 198 * condition that may happen soon but that doesn't directly affect the 199 * VM execution by the time of the call. 200 * 201 * The @a pszErrorID parameter defines an unique error identificator. 202 * It is used by the front-ends to show a proper message to the end user 203 * containig possible actions (for example, Retry/Ignore). For this reason, 204 * an error ID assigned once to some particular error condition should not 205 * change in the future. The format of this parameter is "someErrorCondition". 206 * 207 * @param pVM VM handle. Must be non-NULL. 208 * @param fFatal Whether it is a fatal error or not. 209 * @param pszErrorID Error ID string. 210 * @param pszFormat Error message format string. 211 * @param ... Error message arguments. 212 * 213 * @return VBox status code (whether the error has been successfully set 214 * and delivered to callbacks or not). 215 * 216 * @thread Any 217 */ 218 VMDECL(int) VMSetRuntimeError(PVM pVM, bool fFatal, const char *pszErrorID, 219 const char *pszFormat, ...) 220 { 221 va_list args; 222 va_start(args, pszFormat); 223 int rc = VMSetRuntimeErrorV(pVM, fFatal, pszErrorID, pszFormat, args); 224 va_end(args); 225 return rc; 226 } 227 228 229 /** 230 * va_list version of VMSetRuntimeError. 231 * 232 * @param pVM VM handle. Must be non-NULL. 233 * @param fFatal Whether it is a fatal error or not. 234 * @param pszErrorID Error ID string. 235 * @param pszFormat Error message format string. 236 * @param args Error message arguments. 237 * 238 * @return VBox status code (whether the error has been successfully set 239 * and delivered to callbacks or not). 240 * 241 * @thread Any 242 */ 243 VMDECL(int) VMSetRuntimeErrorV(PVM pVM, bool fFatal, const char *pszErrorID, 244 const char *pszFormat, va_list args) 245 { 246 #ifdef IN_RING3 247 /* 248 * Switch to EMT. 249 */ 250 PVMREQ pReq; 251 VMR3ReqCall(pVM, &pReq, RT_INDEFINITE_WAIT, (PFNRT)vmR3SetRuntimeErrorV, 5, 252 pVM, fFatal, pszErrorID, pszFormat, &args); 253 VMR3ReqFree(pReq); 254 255 #else 256 /* 257 * We're already on the EMT thread and can safely create a VMRUNTIMEERROR chunk. 258 */ 259 vmSetRuntimeErrorCopy(pVM, fFatal, pszErrorID, pszFormat, args); 260 261 # ifdef IN_GC 262 VMMGCCallHost(pVM, VMMCALLHOST_VM_SET_RUNTIME_ERROR, 0); 263 # elif defined(IN_RING0) 264 VMMR0CallHost(pVM, VMMCALLHOST_VM_SET_RUNTIME_ERROR, 0); 265 # else 266 # endif 267 #endif 268 return VINF_SUCCESS; 269 } 270 271 272 /** 273 * Copies the error to a VMRUNTIMEERROR structure. 274 * 275 * This is mainly intended for Ring-0 and GC where the error must be copied to 276 * memory accessible from ring-3. But it's just possible that we might add 277 * APIs for retrieving the VMRUNTIMEERROR copy later. 278 * 279 * @param pVM VM handle. Must be non-NULL. 280 * @param fFatal Whether it is a fatal error or not. 281 * @param pszErrorID Error ID string. 282 * @param pszFormat Error message format string. 283 * @param args Error message arguments. 284 * @thread EMT 285 */ 286 void vmSetRuntimeErrorCopy(PVM pVM, bool fFatal, const char *pszErrorID, 287 const char *pszFormat, va_list args) 288 { 289 #if 0 /// @todo implement Ring-0 and GC VMSetError 290 /* 291 * Create the untranslated message copy. 292 */ 293 /* free any old message. */ 294 MMHyperFree(pVM, MMHyperR32Ctx(pVM, pVM->vm.s.pRuntimeErrorR3)); 295 pVM->vm.s.pRuntimeErrorR3 = NULL; 296 297 /* calc reasonable start size. */ 298 size_t cchErrorID = pszErrorID ? strlen(pszErrorID) : 0; 299 size_t cchFormat = strlen(pszFormat); 300 size_t cb = sizeof(VMRUNTIMEERROR) 301 + cchErrorID + 1 302 + cchFormat + 32; 303 304 /* allocate it */ 305 void *pv; 306 int rc2 = MMHyperAlloc(pVM, cb, 0, MM_TAG_VM, &pv); 307 if (VBOX_SUCCESS(rc2)) 308 { 309 /* initialize it. */ 310 PVMRUNTIMEERROR pErr = (PVMRUNTIMEERROR)pv; 311 pErr->cbAllocated = cb; 312 pErr->off = sizeof(PVMRUNTIMEERROR); 313 pErr->offErrorID = = 0; 314 315 if (cchErrorID) 316 { 317 pErr->offErrorID = pErr->off; 318 memcpy((uint8_t *)pErr + pErr->off, pszErrorID, cchErrorID + 1); 319 pErr->off += cchErrorID + 1; 320 } 321 322 pErr->offMessage = pErr->off; 323 324 /* format the message (pErr might be reallocated) */ 325 VMSETRUNTIMEERRORFMTARGS Args; 326 Args.pVM = pVM; 327 Args.pErr = pErr; 328 329 va_list va2; 330 va_copy(va2, args); 331 RTStrFormatV(vmSetRuntimeErrorFmtOut, &pErr, NULL, NULL, &pszFormatTmp, args); 332 va_end(va2); 333 334 /* done. */ 335 pVM->vm.s.pErrorRuntimeR3 = MMHyper2HC(pVM, (uintptr_t)pArgs.pErr); 336 } 337 #endif 338 } 339 -
trunk/src/VBox/VMM/VMMInternal.h
r161 r234 302 302 STAMCOUNTER StatGCRetRemReplay; 303 303 STAMCOUNTER StatGCRetVMSetError; 304 STAMCOUNTER StatGCRetVMSetRuntimeError; 304 305 STAMCOUNTER StatGCRetPGMLock; 305 306 -
trunk/src/VBox/VMM/VMMR0/VMMR0.cpp
r140 r234 365 365 case VMMCALLHOST_VM_SET_ERROR: 366 366 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetVMSetError); 367 break; 368 case VMMCALLHOST_VM_SET_RUNTIME_ERROR: 369 STAM_COUNTER_INC(&pVM->vmm.s.StatGCRetVMSetRuntimeError); 367 370 break; 368 371 default:
Note:
See TracChangeset
for help on using the changeset viewer.