/* $Id: VMInternal.h 2830 2007-05-23 19:53:38Z vboxsync $ */ /** @file * VM - Internal header file. */ /* * Copyright (C) 2006 InnoTek Systemberatung GmbH * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; * you can redistribute it and/or modify it under the terms of the GNU * General Public License as published by the Free Software Foundation, * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE * distribution. VirtualBox OSE is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY of any kind. * * If you received this file as part of a commercial VirtualBox * distribution, then only the terms of your commercial VirtualBox * license agreement apply instead of the previous paragraph. */ #ifndef __VMInternal_h__ #define __VMInternal_h__ #include #include #include #if !defined(IN_VM_R3) && !defined(IN_VM_R0) && !defined(IN_VM_GC) # error "Not in VM! This is an internal header!" #endif /** @defgroup grp_vm_int Internals * @ingroup grp_vm * @internal * @{ */ /** * At-reset callback type. */ typedef enum VMATRESETTYPE { /** Device callback. */ VMATRESETTYPE_DEV = 1, /** Internal callback . */ VMATRESETTYPE_INTERNAL, /** External callback. */ VMATRESETTYPE_EXTERNAL } VMATRESETTYPE; /** Pointer to at-reset callback. */ typedef struct VMATRESET *PVMATRESET; /** * At reset callback. */ typedef struct VMATRESET { /** Pointer to the next one in the list. */ PVMATRESET pNext; /** Callback type. */ VMATRESETTYPE enmType; /** User argument for the callback. */ void *pvUser; /** Description. */ const char *pszDesc; /** Type specific data. */ union { /** VMATRESETTYPE_DEV. */ struct { /** Callback. */ PFNVMATRESET pfnCallback; /** Device instance. */ PPDMDEVINS pDevIns; } Dev; /** VMATRESETTYPE_INTERNAL. */ struct { /** Callback. */ PFNVMATRESETINT pfnCallback; } Internal; /** VMATRESETTYPE_EXTERNAL. */ struct { /** Callback. */ PFNVMATRESETEXT pfnCallback; } External; } u; } VMATRESET; /** * VM state change callback. */ typedef struct VMATSTATE { /** Pointer to the next one. */ struct VMATSTATE *pNext; /** Pointer to the callback. */ PFNVMATSTATE pfnAtState; /** The user argument. */ void *pvUser; } VMATSTATE; /** Pointer to a VM state change callback. */ typedef VMATSTATE *PVMATSTATE; /** * VM error callback. */ typedef struct VMATERROR { /** Pointer to the next one. */ struct VMATERROR *pNext; /** Pointer to the callback. */ PFNVMATERROR pfnAtError; /** The user argument. */ void *pvUser; } VMATERROR; /** Pointer to a VM error callback. */ typedef VMATERROR *PVMATERROR; /** * Chunk of memory allocated off the hypervisor heap in which * we copy the error details. */ typedef struct VMERROR { /** The size of the chunk. */ uint32_t cbAllocated; /** The current offset into the chunk. * We start by putting the filename and function immediatly * after the end of the buffer. */ uint32_t off; /** Offset from the start of this structure to the file name. */ uint32_t offFile; /** The line number. */ uint32_t iLine; /** Offset from the start of this structure to the function name. */ uint32_t offFunction; /** Offset from the start of this structure to the formatted message text. */ uint32_t offMessage; /** The VBox status code. */ int32_t rc; } VMERROR, *PVMERROR; /** * VM runtime error callback. */ typedef struct VMATRUNTIMEERROR { /** Pointer to the next one. */ struct VMATRUNTIMEERROR *pNext; /** Pointer to the callback. */ PFNVMATRUNTIMEERROR pfnAtRuntimeError; /** The user argument. */ void *pvUser; } VMATRUNTIMEERROR; /** Pointer to a VM error callback. */ typedef VMATRUNTIMEERROR *PVMATRUNTIMEERROR; /** * Chunk of memory allocated off the hypervisor heap in which * we copy the runtime error details. */ typedef struct VMRUNTIMEERROR { /** The size of the chunk. */ uint32_t cbAllocated; /** The current offset into the chunk. * We start by putting the error ID immediatly * after the end of the buffer. */ uint32_t off; /** Offset from the start of this structure to the error ID. */ uint32_t offErrorID; /** Offset from the start of this structure to the formatted message text. */ uint32_t offMessage; /** Whether the error is fatal or not */ bool fFatal; } VMRUNTIMEERROR, *PVMRUNTIMEERROR; /** * Converts a VMM pointer into a VM pointer. * @returns Pointer to the VM structure the VMM is part of. * @param pVMM Pointer to VMM instance data. */ #define VMINT2VM(pVMM) ( (PVM)((char*)pVMM - pVMM->offVM) ) /** * VM Internal Data (part of VM) */ typedef struct VMINT { /** Offset to the VM structure. * See VMINT2VM(). */ RTINT offVM; /** List of registered reset callbacks. */ HCPTRTYPE(PVMATRESET) pAtReset; /** List of registered reset callbacks. */ HCPTRTYPE(PVMATRESET *) ppAtResetNext; /** List of registered state change callbacks. */ HCPTRTYPE(PVMATSTATE) pAtState; /** List of registered state change callbacks. */ HCPTRTYPE(PVMATSTATE *) ppAtStateNext; /** List of registered error callbacks. */ HCPTRTYPE(PVMATERROR) pAtError; /** List of registered error callbacks. */ HCPTRTYPE(PVMATERROR *) ppAtErrorNext; /** List of registered error callbacks. */ HCPTRTYPE(PVMATRUNTIMEERROR) pAtRuntimeError; /** List of registered error callbacks. */ HCPTRTYPE(PVMATRUNTIMEERROR *) ppAtRuntimeErrorNext; /** Head of the request queue. Atomic. */ volatile HCPTRTYPE(PVMREQ) pReqs; /** The last index used during alloc/free. */ volatile uint32_t iReqFree; /** Array of pointers to lists of free request packets. Atomic. */ volatile HCPTRTYPE(PVMREQ) apReqFree[9]; /** Number of free request packets. */ volatile uint32_t cReqFree; /** Wait/Idle indicator. */ volatile uint32_t fWait; /** Wait event semaphore. */ HCPTRTYPE(RTSEMEVENT) EventSemWait; /** VM Error Message. */ R3PTRTYPE(PVMERROR) pErrorR3; /** VM Runtime Error Message. */ R3PTRTYPE(PVMRUNTIMEERROR) pRuntimeErrorR3; /** Pointer to the DBGC instance data. */ HCPTRTYPE(void *) pvDBGC; /** If set the EMT does the final VM cleanup when it exits. * If clear the VMR3Destroy() caller does so. */ bool fEMTDoesTheCleanup; /** Set by VMR3SuspendNoSave; cleared by VMR3Resume; signals the VM is in an inconsistent state and saving is not allowed. */ bool fPreventSaveState; /** vmR3EmulationThread longjmp buffer * @todo r=bird: requires union with padding. See EMInternal.h. */ jmp_buf emtJumpEnv; /** @name Yield * @{ */ /** The average time (ns) between two halts in the last second. (updated once per second) */ uint32_t HaltInterval; /** The average halt frequency for the last second. (updated once per second) */ uint32_t HaltFrequency; /** The number of halts in the current period. */ uint32_t cHalts; uint32_t padding0; /**< alignment padding. */ /** When we started counting halts in cHalts (RTTimeNanoTS). */ uint64_t u64HaltsStartTS; /** Union containing data and config for the different halt algorithms. */ union { /** * Method 1 & 2 - Block whenever possible, and when lagging behind * switch to spinning for 10-30ms with occational blocking until * the lag has been eliminated. * * The difference between 1 and 2 is that we use native absolute * time APIs for the blocking instead of the millisecond based IPRT * interface. */ struct { /** How many times we've blocked while cBlockedNS and cBlockedTooLongNS has been accumulating. */ uint32_t cBlocks; /** Avg. time spend oversleeping when blocking. (Re-calculated every so often.) */ uint64_t cNSBlockedTooLongAvg; /** Total time spend oversleeping when blocking. */ uint64_t cNSBlockedTooLong; /** Total time spent blocking. */ uint64_t cNSBlocked; /** The timestamp (RTTimeNanoTS) of the last block. */ uint64_t u64LastBlockTS; /** When we started spinning relentlessly in order to catch up some of the oversleeping. * This is 0 when we're not spinning. */ uint64_t u64StartSpinTS; } Method12; #if 0 /** * Method 3 & 4 - Same as method 1 & 2 respectivly, except that we * sprinkle it with yields. */ struct { /** How many times we've blocked while cBlockedNS and cBlockedTooLongNS has been accumulating. */ uint32_t cBlocks; /** Avg. time spend oversleeping when blocking. (Re-calculated every so often.) */ uint64_t cBlockedTooLongNSAvg; /** Total time spend oversleeping when blocking. */ uint64_t cBlockedTooLongNS; /** Total time spent blocking. */ uint64_t cBlockedNS; /** The timestamp (RTTimeNanoTS) of the last block. */ uint64_t u64LastBlockTS; /** How many times we've yielded while cBlockedNS and cBlockedTooLongNS has been accumulating. */ uint32_t cYields; /** Avg. time spend oversleeping when yielding. */ uint32_t cYieldTooLongNSAvg; /** Total time spend oversleeping when yielding. */ uint64_t cYieldTooLongNS; /** Total time spent yielding. */ uint64_t cYieldedNS; /** The timestamp (RTTimeNanoTS) of the last block. */ uint64_t u64LastYieldTS; /** When we started spinning relentlessly in order to catch up some of the oversleeping. */ uint64_t u64StartSpinTS; } Method34; #endif } Halt; /** @} */ /** Number of VMR3ReqAlloc returning a new packet. */ STAMCOUNTER StatReqAllocNew; /** Number of VMR3ReqAlloc causing races. */ STAMCOUNTER StatReqAllocRaces; /** Number of VMR3ReqAlloc returning a recycled packet. */ STAMCOUNTER StatReqAllocRecycled; /** Number of VMR3ReqFree calls. */ STAMCOUNTER StatReqFree; /** Number of times the request was actually freed. */ STAMCOUNTER StatReqFreeOverflow; /** Profiling the halted state; yielding vs blocking. */ STAMPROFILE StatHaltYield; STAMPROFILE StatHaltBlock; STAMPROFILE StatHaltTimers; STAMPROFILE StatHaltPoll; } VMINT, *PVMINT; /** * Emulation thread arguments. */ typedef struct VMEMULATIONTHREADARGS { /** Pointer to the VM structure. */ PVM pVM; } VMEMULATIONTHREADARGS; /** Pointer to the emulation thread arguments. */ typedef VMEMULATIONTHREADARGS *PVMEMULATIONTHREADARGS; DECLCALLBACK(int) vmR3EmulationThread(RTTHREAD ThreadSelf, void *pvArg); DECLCALLBACK(int) vmR3Destroy(PVM pVM); DECLCALLBACK(void) vmR3SetErrorV(PVM pVM, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list *args); void vmSetErrorCopy(PVM pVM, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list args); DECLCALLBACK(void) vmR3SetRuntimeErrorV(PVM pVM, bool fFatal, const char *pszErrorID, const char *pszFormat, va_list *args); void vmSetRuntimeErrorCopy(PVM pVM, bool fFatal, const char *pszErrorID, const char *pszFormat, va_list args); void vmR3DestroyFinalBit(PVM pVM); /** @} */ #endif