diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2012-10-26 16:25:44 +0000 |
---|---|---|
committer | <> | 2012-11-12 12:15:52 +0000 |
commit | 58ed4748338f9466599adfc8a9171280ed99e23f (patch) | |
tree | 02027d99ded4fb56a64aa9489ac2eb487e7858ab /include/VBox/vmm | |
download | VirtualBox-58ed4748338f9466599adfc8a9171280ed99e23f.tar.gz |
Imported from /home/lorry/working-area/delta_VirtualBox/VirtualBox-4.2.4.tar.bz2.VirtualBox-4.2.4
Diffstat (limited to 'include/VBox/vmm')
62 files changed, 31534 insertions, 0 deletions
diff --git a/include/VBox/vmm/Makefile.kup b/include/VBox/vmm/Makefile.kup new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/include/VBox/vmm/Makefile.kup diff --git a/include/VBox/vmm/cfgm.h b/include/VBox/vmm/cfgm.h new file mode 100644 index 00000000..9b4e47ab --- /dev/null +++ b/include/VBox/vmm/cfgm.h @@ -0,0 +1,220 @@ +/** @file + * CFGM - Configuration Manager. + */ + +/* + * Copyright (C) 2006-2010 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_cfgm_h +#define ___VBox_vmm_cfgm_h + +#include <VBox/types.h> +#include <iprt/stdarg.h> + +/** @defgroup grp_cfgm The Configuration Manager API + * @{ + */ + +/** + * Configuration manager value type. + */ +typedef enum CFGMVALUETYPE +{ + /** Integer value. */ + CFGMVALUETYPE_INTEGER = 1, + /** String value. */ + CFGMVALUETYPE_STRING, + /** Bytestring value. */ + CFGMVALUETYPE_BYTES +} CFGMVALUETYPE; +/** Pointer to configuration manager property type. */ +typedef CFGMVALUETYPE *PCFGMVALUETYPE; + + + +RT_C_DECLS_BEGIN + +#ifdef IN_RING3 +/** @defgroup grp_cfgm_r3 The CFGM Host Context Ring-3 API + * @ingroup grp_cfgm + * @{ + */ + +typedef enum CFGMCONFIGTYPE +{ + /** pvConfig points to nothing, use defaults. */ + CFGMCONFIGTYPE_NONE = 0, + /** pvConfig points to a IMachine interface. */ + CFGMCONFIGTYPE_IMACHINE +} CFGMCONFIGTYPE; + + +/** + * CFGM init callback for constructing the configuration tree. + * + * This is called from the emulation thread, and the one interfacing the VM + * can make any necessary per-thread initializations at this point. + * + * @returns VBox status code. + * @param pVM VM handle. + * @param pvUser The argument supplied to VMR3Create(). + */ +typedef DECLCALLBACK(int) FNCFGMCONSTRUCTOR(PVM pVM, void *pvUser); +/** Pointer to a FNCFGMCONSTRUCTOR(). */ +typedef FNCFGMCONSTRUCTOR *PFNCFGMCONSTRUCTOR; + +VMMR3DECL(int) CFGMR3Init(PVM pVM, PFNCFGMCONSTRUCTOR pfnCFGMConstructor, void *pvUser); +VMMR3DECL(int) CFGMR3Term(PVM pVM); + + +VMMR3DECL(PCFGMNODE) CFGMR3CreateTree(PVM pVM); +VMMR3DECL(int) CFGMR3ConstructDefaultTree(PVM pVM); +VMMR3DECL(void) CFGMR3Dump(PCFGMNODE pRoot); +VMMR3DECL(int) CFGMR3DuplicateSubTree(PCFGMNODE pRoot, PCFGMNODE *ppCopy); +VMMR3DECL(int) CFGMR3ReplaceSubTree(PCFGMNODE pRoot, PCFGMNODE pNewRoot); +VMMR3DECL(int) CFGMR3InsertSubTree(PCFGMNODE pNode, const char *pszName, PCFGMNODE pSubTree, PCFGMNODE *ppChild); +VMMR3DECL(int) CFGMR3InsertNode(PCFGMNODE pNode, const char *pszName, PCFGMNODE *ppChild); +VMMR3DECL(int) CFGMR3InsertNodeF(PCFGMNODE pNode, PCFGMNODE *ppChild, const char *pszNameFormat, ...); +VMMR3DECL(int) CFGMR3InsertNodeFV(PCFGMNODE pNode, PCFGMNODE *ppChild, const char *pszNameFormat, va_list Args); +VMMR3DECL(void) CFGMR3SetRestrictedRoot(PCFGMNODE pNode); +VMMR3DECL(void) CFGMR3RemoveNode(PCFGMNODE pNode); +VMMR3DECL(int) CFGMR3InsertInteger(PCFGMNODE pNode, const char *pszName, uint64_t u64Integer); +VMMR3DECL(int) CFGMR3InsertString(PCFGMNODE pNode, const char *pszName, const char *pszString); +VMMR3DECL(int) CFGMR3InsertStringN(PCFGMNODE pNode, const char *pszName, const char *pszString, size_t cchString); +VMMR3DECL(int) CFGMR3InsertStringF(PCFGMNODE pNode, const char *pszName, const char *pszFormat, ...); +VMMR3DECL(int) CFGMR3InsertStringFV(PCFGMNODE pNode, const char *pszName, const char *pszFormat, va_list va); +VMMR3DECL(int) CFGMR3InsertStringW(PCFGMNODE pNode, const char *pszName, PCRTUTF16 pwszValue); +VMMR3DECL(int) CFGMR3InsertBytes(PCFGMNODE pNode, const char *pszName, const void *pvBytes, size_t cbBytes); +VMMR3DECL(int) CFGMR3InsertValue(PCFGMNODE pNode, PCFGMLEAF pValue); +VMMR3DECL(int) CFGMR3RemoveValue(PCFGMNODE pNode, const char *pszName); + +/** @name CFGMR3CopyTree flags. + * @{ */ +/** Reserved value disposition \#0. */ +#define CFGM_COPY_FLAGS_RESERVED_VALUE_DISP_0 UINT32_C(0x00000000) +/** Reserved value disposition \#1. */ +#define CFGM_COPY_FLAGS_RESERVED_VALUE_DISP_1 UINT32_C(0x00000001) +/** Replace exiting values. */ +#define CFGM_COPY_FLAGS_REPLACE_VALUES UINT32_C(0x00000002) +/** Ignore exiting values. */ +#define CFGM_COPY_FLAGS_IGNORE_EXISTING_VALUES UINT32_C(0x00000003) +/** Value disposition mask. */ +#define CFGM_COPY_FLAGS_VALUE_DISP_MASK UINT32_C(0x00000003) + +/** Replace exiting keys. */ +#define CFGM_COPY_FLAGS_RESERVED_KEY_DISP UINT32_C(0x00000000) +/** Replace exiting keys. */ +#define CFGM_COPY_FLAGS_MERGE_KEYS UINT32_C(0x00000010) +/** Replace exiting keys. */ +#define CFGM_COPY_FLAGS_REPLACE_KEYS UINT32_C(0x00000020) +/** Ignore existing keys. */ +#define CFGM_COPY_FLAGS_IGNORE_EXISTING_KEYS UINT32_C(0x00000030) +/** Key disposition. */ +#define CFGM_COPY_FLAGS_KEY_DISP_MASK UINT32_C(0x00000030) +/** @} */ +VMMR3DECL(int) CFGMR3CopyTree(PCFGMNODE pDstTree, PCFGMNODE pSrcTree, uint32_t fFlags); + +VMMR3DECL(int) CFGMR3QueryType( PCFGMNODE pNode, const char *pszName, PCFGMVALUETYPE penmType); +VMMR3DECL(int) CFGMR3QuerySize( PCFGMNODE pNode, const char *pszName, size_t *pcb); +VMMR3DECL(int) CFGMR3QueryInteger( PCFGMNODE pNode, const char *pszName, uint64_t *pu64); +VMMR3DECL(int) CFGMR3QueryIntegerDef( PCFGMNODE pNode, const char *pszName, uint64_t *pu64, uint64_t u64Def); +VMMR3DECL(int) CFGMR3QueryString( PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString); +VMMR3DECL(int) CFGMR3QueryStringDef( PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString, const char *pszDef); +VMMR3DECL(int) CFGMR3QueryBytes( PCFGMNODE pNode, const char *pszName, void *pvData, size_t cbData); + + +/** @name Helpers + * @{ + */ +VMMR3DECL(int) CFGMR3QueryU64( PCFGMNODE pNode, const char *pszName, uint64_t *pu64); +VMMR3DECL(int) CFGMR3QueryU64Def( PCFGMNODE pNode, const char *pszName, uint64_t *pu64, uint64_t u64Def); +VMMR3DECL(int) CFGMR3QueryS64( PCFGMNODE pNode, const char *pszName, int64_t *pi64); +VMMR3DECL(int) CFGMR3QueryS64Def( PCFGMNODE pNode, const char *pszName, int64_t *pi64, int64_t i64Def); +VMMR3DECL(int) CFGMR3QueryU32( PCFGMNODE pNode, const char *pszName, uint32_t *pu32); +VMMR3DECL(int) CFGMR3QueryU32Def( PCFGMNODE pNode, const char *pszName, uint32_t *pu32, uint32_t u32Def); +VMMR3DECL(int) CFGMR3QueryS32( PCFGMNODE pNode, const char *pszName, int32_t *pi32); +VMMR3DECL(int) CFGMR3QueryS32Def( PCFGMNODE pNode, const char *pszName, int32_t *pi32, int32_t i32Def); +VMMR3DECL(int) CFGMR3QueryU16( PCFGMNODE pNode, const char *pszName, uint16_t *pu16); +VMMR3DECL(int) CFGMR3QueryU16Def( PCFGMNODE pNode, const char *pszName, uint16_t *pu16, uint16_t u16Def); +VMMR3DECL(int) CFGMR3QueryS16( PCFGMNODE pNode, const char *pszName, int16_t *pi16); +VMMR3DECL(int) CFGMR3QueryS16Def( PCFGMNODE pNode, const char *pszName, int16_t *pi16, int16_t i16Def); +VMMR3DECL(int) CFGMR3QueryU8( PCFGMNODE pNode, const char *pszName, uint8_t *pu8); +VMMR3DECL(int) CFGMR3QueryU8Def( PCFGMNODE pNode, const char *pszName, uint8_t *pu8, uint8_t u8Def); +VMMR3DECL(int) CFGMR3QueryS8( PCFGMNODE pNode, const char *pszName, int8_t *pi8); +VMMR3DECL(int) CFGMR3QueryS8Def( PCFGMNODE pNode, const char *pszName, int8_t *pi8, int8_t i8Def); +VMMR3DECL(int) CFGMR3QueryBool( PCFGMNODE pNode, const char *pszName, bool *pf); +VMMR3DECL(int) CFGMR3QueryBoolDef( PCFGMNODE pNode, const char *pszName, bool *pf, bool fDef); +VMMR3DECL(int) CFGMR3QueryPort( PCFGMNODE pNode, const char *pszName, PRTIOPORT pPort); +VMMR3DECL(int) CFGMR3QueryPortDef( PCFGMNODE pNode, const char *pszName, PRTIOPORT pPort, RTIOPORT PortDef); +VMMR3DECL(int) CFGMR3QueryUInt( PCFGMNODE pNode, const char *pszName, unsigned int *pu); +VMMR3DECL(int) CFGMR3QueryUIntDef( PCFGMNODE pNode, const char *pszName, unsigned int *pu, unsigned int uDef); +VMMR3DECL(int) CFGMR3QuerySInt( PCFGMNODE pNode, const char *pszName, signed int *pi); +VMMR3DECL(int) CFGMR3QuerySIntDef( PCFGMNODE pNode, const char *pszName, signed int *pi, signed int iDef); +VMMR3DECL(int) CFGMR3QueryPtr( PCFGMNODE pNode, const char *pszName, void **ppv); +VMMR3DECL(int) CFGMR3QueryPtrDef( PCFGMNODE pNode, const char *pszName, void **ppv, void *pvDef); +VMMR3DECL(int) CFGMR3QueryGCPtr( PCFGMNODE pNode, const char *pszName, PRTGCPTR pGCPtr); +VMMR3DECL(int) CFGMR3QueryGCPtrDef( PCFGMNODE pNode, const char *pszName, PRTGCPTR pGCPtr, RTGCPTR GCPtrDef); +VMMR3DECL(int) CFGMR3QueryGCPtrU( PCFGMNODE pNode, const char *pszName, PRTGCUINTPTR pGCPtr); +VMMR3DECL(int) CFGMR3QueryGCPtrUDef( PCFGMNODE pNode, const char *pszName, PRTGCUINTPTR pGCPtr, RTGCUINTPTR GCPtrDef); +VMMR3DECL(int) CFGMR3QueryGCPtrS( PCFGMNODE pNode, const char *pszName, PRTGCINTPTR pGCPtr); +VMMR3DECL(int) CFGMR3QueryGCPtrSDef( PCFGMNODE pNode, const char *pszName, PRTGCINTPTR pGCPtr, RTGCINTPTR GCPtrDef); +VMMR3DECL(int) CFGMR3QueryStringAlloc( PCFGMNODE pNode, const char *pszName, char **ppszString); +VMMR3DECL(int) CFGMR3QueryStringAllocDef(PCFGMNODE pNode, const char *pszName, char **ppszString, const char *pszDef); + +/** @} */ + +/** @name Tree Navigation and Enumeration. + * @{ + */ +VMMR3DECL(PCFGMNODE) CFGMR3GetRoot(PVM pVM); +VMMR3DECL(PCFGMNODE) CFGMR3GetParent(PCFGMNODE pNode); +VMMR3DECL(PCFGMNODE) CFGMR3GetParentEx(PVM pVM, PCFGMNODE pNode); +VMMR3DECL(PCFGMNODE) CFGMR3GetChild(PCFGMNODE pNode, const char *pszPath); +VMMR3DECL(PCFGMNODE) CFGMR3GetChildF(PCFGMNODE pNode, const char *pszPathFormat, ...); +VMMR3DECL(PCFGMNODE) CFGMR3GetChildFV(PCFGMNODE pNode, const char *pszPathFormat, va_list Args); +VMMR3DECL(PCFGMNODE) CFGMR3GetFirstChild(PCFGMNODE pNode); +VMMR3DECL(PCFGMNODE) CFGMR3GetNextChild(PCFGMNODE pCur); +VMMR3DECL(int) CFGMR3GetName(PCFGMNODE pCur, char *pszName, size_t cchName); +VMMR3DECL(size_t) CFGMR3GetNameLen(PCFGMNODE pCur); +VMMR3DECL(bool) CFGMR3AreChildrenValid(PCFGMNODE pNode, const char *pszzValid); +VMMR3DECL(PCFGMLEAF) CFGMR3GetFirstValue(PCFGMNODE pCur); +VMMR3DECL(PCFGMLEAF) CFGMR3GetNextValue(PCFGMLEAF pCur); +VMMR3DECL(int) CFGMR3GetValueName(PCFGMLEAF pCur, char *pszName, size_t cchName); +VMMR3DECL(size_t) CFGMR3GetValueNameLen(PCFGMLEAF pCur); +VMMR3DECL(CFGMVALUETYPE) CFGMR3GetValueType(PCFGMLEAF pCur); +VMMR3DECL(bool) CFGMR3AreValuesValid(PCFGMNODE pNode, const char *pszzValid); +VMMR3DECL(int) CFGMR3ValidateConfig(PCFGMNODE pNode, const char *pszNode, + const char *pszValidValues, const char *pszValidNodes, + const char *pszWho, uint32_t uInstance); + +/** @} */ + + +/** @} */ +#endif /* IN_RING3 */ + + +RT_C_DECLS_END + +/** @} */ + +#endif + diff --git a/include/VBox/vmm/cpum.h b/include/VBox/vmm/cpum.h new file mode 100644 index 00000000..0b4abf33 --- /dev/null +++ b/include/VBox/vmm/cpum.h @@ -0,0 +1,492 @@ +/** @file + * CPUM - CPU Monitor(/ Manager). + */ + +/* + * Copyright (C) 2006-2012 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_cpum_h +#define ___VBox_vmm_cpum_h + +#include <iprt/x86.h> +#include <VBox/types.h> +#include <VBox/vmm/cpumctx.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_cpum The CPU Monitor / Manager API + * @{ + */ + +/** + * CPUID feature to set or clear. + */ +typedef enum CPUMCPUIDFEATURE +{ + CPUMCPUIDFEATURE_INVALID = 0, + /** The APIC feature bit. (Std+Ext) */ + CPUMCPUIDFEATURE_APIC, + /** The sysenter/sysexit feature bit. (Std) */ + CPUMCPUIDFEATURE_SEP, + /** The SYSCALL/SYSEXIT feature bit (64 bits mode only for Intel CPUs). (Ext) */ + CPUMCPUIDFEATURE_SYSCALL, + /** The PAE feature bit. (Std+Ext) */ + CPUMCPUIDFEATURE_PAE, + /** The NX feature bit. (Ext) */ + CPUMCPUIDFEATURE_NX, + /** The LAHF/SAHF feature bit (64 bits mode only). (Ext) */ + CPUMCPUIDFEATURE_LAHF, + /** The LONG MODE feature bit. (Ext) */ + CPUMCPUIDFEATURE_LONG_MODE, + /** The PAT feature bit. (Std+Ext) */ + CPUMCPUIDFEATURE_PAT, + /** The x2APIC feature bit. (Std) */ + CPUMCPUIDFEATURE_X2APIC, + /** The RDTSCP feature bit. (Ext) */ + CPUMCPUIDFEATURE_RDTSCP, + /** The Hypervisor Present bit. (Std) */ + CPUMCPUIDFEATURE_HVP, + /** 32bit hackishness. */ + CPUMCPUIDFEATURE_32BIT_HACK = 0x7fffffff +} CPUMCPUIDFEATURE; + +/** + * CPU Vendor. + */ +typedef enum CPUMCPUVENDOR +{ + CPUMCPUVENDOR_INVALID = 0, + CPUMCPUVENDOR_INTEL, + CPUMCPUVENDOR_AMD, + CPUMCPUVENDOR_VIA, + CPUMCPUVENDOR_UNKNOWN, + CPUMCPUVENDOR_SYNTHETIC, + /** 32bit hackishness. */ + CPUMCPUVENDOR_32BIT_HACK = 0x7fffffff +} CPUMCPUVENDOR; + + +/** @name Guest Register Getters. + * @{ */ +VMMDECL(void) CPUMGetGuestGDTR(PVMCPU pVCpu, PVBOXGDTR pGDTR); +VMMDECL(RTGCPTR) CPUMGetGuestIDTR(PVMCPU pVCpu, uint16_t *pcbLimit); +VMMDECL(RTSEL) CPUMGetGuestTR(PVMCPU pVCpu, PCPUMSELREGHID pHidden); +VMMDECL(RTSEL) CPUMGetGuestLDTR(PVMCPU pVCpu); +VMMDECL(RTSEL) CPUMGetGuestLdtrEx(PVMCPU pVCpu, uint64_t *pGCPtrBase, uint32_t *pcbLimit); +VMMDECL(uint64_t) CPUMGetGuestCR0(PVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestCR2(PVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestCR3(PVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestCR4(PVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestCR8(PVMCPU pVCpu); +VMMDECL(int) CPUMGetGuestCRx(PVMCPU pVCpu, unsigned iReg, uint64_t *pValue); +VMMDECL(uint32_t) CPUMGetGuestEFlags(PVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestEIP(PVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestRIP(PVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestEAX(PVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestEBX(PVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestECX(PVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestEDX(PVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestESI(PVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestEDI(PVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestESP(PVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestEBP(PVMCPU pVCpu); +VMMDECL(RTSEL) CPUMGetGuestCS(PVMCPU pVCpu); +VMMDECL(RTSEL) CPUMGetGuestDS(PVMCPU pVCpu); +VMMDECL(RTSEL) CPUMGetGuestES(PVMCPU pVCpu); +VMMDECL(RTSEL) CPUMGetGuestFS(PVMCPU pVCpu); +VMMDECL(RTSEL) CPUMGetGuestGS(PVMCPU pVCpu); +VMMDECL(RTSEL) CPUMGetGuestSS(PVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestDR0(PVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestDR1(PVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestDR2(PVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestDR3(PVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestDR6(PVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestDR7(PVMCPU pVCpu); +VMMDECL(int) CPUMGetGuestDRx(PVMCPU pVCpu, uint32_t iReg, uint64_t *pValue); +VMMDECL(void) CPUMGetGuestCpuId(PVMCPU pVCpu, uint32_t iLeaf, uint32_t *pEax, uint32_t *pEbx, uint32_t *pEcx, uint32_t *pEdx); +VMMDECL(uint32_t) CPUMGetGuestCpuIdStdMax(PVM pVM); +VMMDECL(uint32_t) CPUMGetGuestCpuIdExtMax(PVM pVM); +VMMDECL(uint32_t) CPUMGetGuestCpuIdCentaurMax(PVM pVM); +VMMDECL(uint64_t) CPUMGetGuestEFER(PVMCPU pVCpu); +VMMDECL(int) CPUMQueryGuestMsr(PVMCPU pVCpu, uint32_t idMsr, uint64_t *puValue); +VMMDECL(int) CPUMSetGuestMsr(PVMCPU pVCpu, uint32_t idMsr, uint64_t uValue); +VMMDECL(CPUMCPUVENDOR) CPUMGetGuestCpuVendor(PVM pVM); +VMMDECL(CPUMCPUVENDOR) CPUMGetHostCpuVendor(PVM pVM); +/** @} */ + +/** @name Guest Register Setters. + * @{ */ +VMMDECL(int) CPUMSetGuestGDTR(PVMCPU pVCpu, uint64_t GCPtrBase, uint16_t cbLimit); +VMMDECL(int) CPUMSetGuestIDTR(PVMCPU pVCpu, uint64_t GCPtrBase, uint16_t cbLimit); +VMMDECL(int) CPUMSetGuestTR(PVMCPU pVCpu, uint16_t tr); +VMMDECL(int) CPUMSetGuestLDTR(PVMCPU pVCpu, uint16_t ldtr); +VMMDECL(int) CPUMSetGuestCR0(PVMCPU pVCpu, uint64_t cr0); +VMMDECL(int) CPUMSetGuestCR2(PVMCPU pVCpu, uint64_t cr2); +VMMDECL(int) CPUMSetGuestCR3(PVMCPU pVCpu, uint64_t cr3); +VMMDECL(int) CPUMSetGuestCR4(PVMCPU pVCpu, uint64_t cr4); +VMMDECL(int) CPUMSetGuestDR0(PVMCPU pVCpu, uint64_t uDr0); +VMMDECL(int) CPUMSetGuestDR1(PVMCPU pVCpu, uint64_t uDr1); +VMMDECL(int) CPUMSetGuestDR2(PVMCPU pVCpu, uint64_t uDr2); +VMMDECL(int) CPUMSetGuestDR3(PVMCPU pVCpu, uint64_t uDr3); +VMMDECL(int) CPUMSetGuestDR6(PVMCPU pVCpu, uint64_t uDr6); +VMMDECL(int) CPUMSetGuestDR7(PVMCPU pVCpu, uint64_t uDr7); +VMMDECL(int) CPUMSetGuestDRx(PVMCPU pVCpu, uint32_t iReg, uint64_t Value); +VMMDECL(int) CPUMSetGuestEFlags(PVMCPU pVCpu, uint32_t eflags); +VMMDECL(int) CPUMSetGuestEIP(PVMCPU pVCpu, uint32_t eip); +VMMDECL(int) CPUMSetGuestEAX(PVMCPU pVCpu, uint32_t eax); +VMMDECL(int) CPUMSetGuestEBX(PVMCPU pVCpu, uint32_t ebx); +VMMDECL(int) CPUMSetGuestECX(PVMCPU pVCpu, uint32_t ecx); +VMMDECL(int) CPUMSetGuestEDX(PVMCPU pVCpu, uint32_t edx); +VMMDECL(int) CPUMSetGuestESI(PVMCPU pVCpu, uint32_t esi); +VMMDECL(int) CPUMSetGuestEDI(PVMCPU pVCpu, uint32_t edi); +VMMDECL(int) CPUMSetGuestESP(PVMCPU pVCpu, uint32_t esp); +VMMDECL(int) CPUMSetGuestEBP(PVMCPU pVCpu, uint32_t ebp); +VMMDECL(int) CPUMSetGuestCS(PVMCPU pVCpu, uint16_t cs); +VMMDECL(int) CPUMSetGuestDS(PVMCPU pVCpu, uint16_t ds); +VMMDECL(int) CPUMSetGuestES(PVMCPU pVCpu, uint16_t es); +VMMDECL(int) CPUMSetGuestFS(PVMCPU pVCpu, uint16_t fs); +VMMDECL(int) CPUMSetGuestGS(PVMCPU pVCpu, uint16_t gs); +VMMDECL(int) CPUMSetGuestSS(PVMCPU pVCpu, uint16_t ss); +VMMDECL(void) CPUMSetGuestEFER(PVMCPU pVCpu, uint64_t val); +VMMDECL(void) CPUMSetGuestCpuIdFeature(PVM pVM, CPUMCPUIDFEATURE enmFeature); +VMMDECL(void) CPUMClearGuestCpuIdFeature(PVM pVM, CPUMCPUIDFEATURE enmFeature); +VMMDECL(bool) CPUMGetGuestCpuIdFeature(PVM pVM, CPUMCPUIDFEATURE enmFeature); +VMMDECL(void) CPUMSetGuestCtx(PVMCPU pVCpu, const PCPUMCTX pCtx); +VMM_INT_DECL(void) CPUMGuestLazyLoadHiddenCsAndSs(PVMCPU pVCpu); +VMM_INT_DECL(void) CPUMGuestLazyLoadHiddenSelectorReg(PVMCPU pVCpu, PCPUMSELREG pSReg); +/** @} */ + + +/** @name Misc Guest Predicate Functions. + * @{ */ + +VMMDECL(bool) CPUMIsGuestIn16BitCode(PVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestIn32BitCode(PVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestIn64BitCode(PVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestNXEnabled(PVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestPageSizeExtEnabled(PVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestPagingEnabled(PVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestR0WriteProtEnabled(PVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestInRealMode(PVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestInRealOrV86Mode(PVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestInProtectedMode(PVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestInPagedProtectedMode(PVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestInLongMode(PVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestInPAEMode(PVMCPU pVCpu); +VMM_INT_DECL(bool) CPUMIsGuestInRawMode(PVMCPU pVCpu); + +#ifndef VBOX_WITHOUT_UNNAMED_UNIONS + +/** + * Tests if the guest is running in real mode or not. + * + * @returns true if in real mode, otherwise false. + * @param pCtx Current CPU context + */ +DECLINLINE(bool) CPUMIsGuestInRealModeEx(PCPUMCTX pCtx) +{ + return !(pCtx->cr0 & X86_CR0_PE); +} + +/** + * Tests if the guest is running in real or virtual 8086 mode. + * + * @returns @c true if it is, @c false if not. + * @param pCtx Current CPU context + */ +DECLINLINE(bool) CPUMIsGuestInRealOrV86ModeEx(PCPUMCTX pCtx) +{ + return !(pCtx->cr0 & X86_CR0_PE) + || pCtx->eflags.Bits.u1VM; /** @todo verify that this cannot be set in long mode. */ +} + +/** + * Tests if the guest is running in paged protected or not. + * + * @returns true if in paged protected mode, otherwise false. + * @param pVM The VM handle. + */ +DECLINLINE(bool) CPUMIsGuestInPagedProtectedModeEx(PCPUMCTX pCtx) +{ + return (pCtx->cr0 & (X86_CR0_PE | X86_CR0_PG)) == (X86_CR0_PE | X86_CR0_PG); +} + +/** + * Tests if the guest is running in long mode or not. + * + * @returns true if in long mode, otherwise false. + * @param pCtx Current CPU context + */ +DECLINLINE(bool) CPUMIsGuestInLongModeEx(PCPUMCTX pCtx) +{ + return (pCtx->msrEFER & MSR_K6_EFER_LMA) == MSR_K6_EFER_LMA; +} + +VMM_INT_DECL(bool) CPUMIsGuestIn64BitCodeSlow(PCPUMCTX pCtx); + +/** + * Tests if the guest is running in 64 bits mode or not. + * + * @returns true if in 64 bits protected mode, otherwise false. + * @param pVCpu The current virtual CPU. + * @param pCtx Current CPU context + */ +DECLINLINE(bool) CPUMIsGuestIn64BitCodeEx(PCPUMCTX pCtx) +{ + if (!(pCtx->msrEFER & MSR_K6_EFER_LMA)) + return false; + if (!CPUMSELREG_ARE_HIDDEN_PARTS_VALID(NULL, &pCtx->cs)) + return CPUMIsGuestIn64BitCodeSlow(pCtx); + return pCtx->cs.Attr.n.u1Long; +} + +/** + * Tests if the guest is running in PAE mode or not. + * + * @returns true if in PAE mode, otherwise false. + * @param pCtx Current CPU context + */ +DECLINLINE(bool) CPUMIsGuestInPAEModeEx(PCPUMCTX pCtx) +{ + return ( (pCtx->cr4 & X86_CR4_PAE) + && CPUMIsGuestInPagedProtectedModeEx(pCtx) + && !CPUMIsGuestInLongModeEx(pCtx)); +} + +#endif /* VBOX_WITHOUT_UNNAMED_UNIONS */ + +/** @} */ + + +/** @name Hypervisor Register Getters. + * @{ */ +VMMDECL(RTSEL) CPUMGetHyperCS(PVMCPU pVCpu); +VMMDECL(RTSEL) CPUMGetHyperDS(PVMCPU pVCpu); +VMMDECL(RTSEL) CPUMGetHyperES(PVMCPU pVCpu); +VMMDECL(RTSEL) CPUMGetHyperFS(PVMCPU pVCpu); +VMMDECL(RTSEL) CPUMGetHyperGS(PVMCPU pVCpu); +VMMDECL(RTSEL) CPUMGetHyperSS(PVMCPU pVCpu); +#if 0 /* these are not correct. */ +VMMDECL(uint32_t) CPUMGetHyperCR0(PVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetHyperCR2(PVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetHyperCR3(PVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetHyperCR4(PVMCPU pVCpu); +#endif +/** This register is only saved on fatal traps. */ +VMMDECL(uint32_t) CPUMGetHyperEAX(PVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetHyperEBX(PVMCPU pVCpu); +/** This register is only saved on fatal traps. */ +VMMDECL(uint32_t) CPUMGetHyperECX(PVMCPU pVCpu); +/** This register is only saved on fatal traps. */ +VMMDECL(uint32_t) CPUMGetHyperEDX(PVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetHyperESI(PVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetHyperEDI(PVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetHyperEBP(PVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetHyperESP(PVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetHyperEFlags(PVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetHyperEIP(PVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetHyperRIP(PVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetHyperIDTR(PVMCPU pVCpu, uint16_t *pcbLimit); +VMMDECL(uint32_t) CPUMGetHyperGDTR(PVMCPU pVCpu, uint16_t *pcbLimit); +VMMDECL(RTSEL) CPUMGetHyperLDTR(PVMCPU pVCpu); +VMMDECL(RTGCUINTREG) CPUMGetHyperDR0(PVMCPU pVCpu); +VMMDECL(RTGCUINTREG) CPUMGetHyperDR1(PVMCPU pVCpu); +VMMDECL(RTGCUINTREG) CPUMGetHyperDR2(PVMCPU pVCpu); +VMMDECL(RTGCUINTREG) CPUMGetHyperDR3(PVMCPU pVCpu); +VMMDECL(RTGCUINTREG) CPUMGetHyperDR6(PVMCPU pVCpu); +VMMDECL(RTGCUINTREG) CPUMGetHyperDR7(PVMCPU pVCpu); +VMMDECL(void) CPUMGetHyperCtx(PVMCPU pVCpu, PCPUMCTX pCtx); +VMMDECL(uint32_t) CPUMGetHyperCR3(PVMCPU pVCpu); +/** @} */ + +/** @name Hypervisor Register Setters. + * @{ */ +VMMDECL(void) CPUMSetHyperGDTR(PVMCPU pVCpu, uint32_t addr, uint16_t limit); +VMMDECL(void) CPUMSetHyperLDTR(PVMCPU pVCpu, RTSEL SelLDTR); +VMMDECL(void) CPUMSetHyperIDTR(PVMCPU pVCpu, uint32_t addr, uint16_t limit); +VMMDECL(void) CPUMSetHyperCR3(PVMCPU pVCpu, uint32_t cr3); +VMMDECL(void) CPUMSetHyperTR(PVMCPU pVCpu, RTSEL SelTR); +VMMDECL(void) CPUMSetHyperCS(PVMCPU pVCpu, RTSEL SelCS); +VMMDECL(void) CPUMSetHyperDS(PVMCPU pVCpu, RTSEL SelDS); +VMMDECL(void) CPUMSetHyperES(PVMCPU pVCpu, RTSEL SelDS); +VMMDECL(void) CPUMSetHyperFS(PVMCPU pVCpu, RTSEL SelDS); +VMMDECL(void) CPUMSetHyperGS(PVMCPU pVCpu, RTSEL SelDS); +VMMDECL(void) CPUMSetHyperSS(PVMCPU pVCpu, RTSEL SelSS); +VMMDECL(void) CPUMSetHyperESP(PVMCPU pVCpu, uint32_t u32ESP); +VMMDECL(int) CPUMSetHyperEFlags(PVMCPU pVCpu, uint32_t Efl); +VMMDECL(void) CPUMSetHyperEIP(PVMCPU pVCpu, uint32_t u32EIP); +VMM_INT_DECL(void) CPUMSetHyperState(PVMCPU pVCpu, uint32_t u32EIP, uint32_t u32ESP, uint32_t u32EAX, uint32_t u32EDX); +VMMDECL(void) CPUMSetHyperDR0(PVMCPU pVCpu, RTGCUINTREG uDr0); +VMMDECL(void) CPUMSetHyperDR1(PVMCPU pVCpu, RTGCUINTREG uDr1); +VMMDECL(void) CPUMSetHyperDR2(PVMCPU pVCpu, RTGCUINTREG uDr2); +VMMDECL(void) CPUMSetHyperDR3(PVMCPU pVCpu, RTGCUINTREG uDr3); +VMMDECL(void) CPUMSetHyperDR6(PVMCPU pVCpu, RTGCUINTREG uDr6); +VMMDECL(void) CPUMSetHyperDR7(PVMCPU pVCpu, RTGCUINTREG uDr7); +VMMDECL(void) CPUMSetHyperCtx(PVMCPU pVCpu, const PCPUMCTX pCtx); +VMMDECL(int) CPUMRecalcHyperDRx(PVMCPU pVCpu); +/** @} */ + +VMMDECL(void) CPUMPushHyper(PVMCPU pVCpu, uint32_t u32); +VMMDECL(int) CPUMQueryHyperCtxPtr(PVMCPU pVCpu, PCPUMCTX *ppCtx); +VMMDECL(PCPUMCTX) CPUMGetHyperCtxPtr(PVMCPU pVCpu); +VMMDECL(PCCPUMCTXCORE) CPUMGetHyperCtxCore(PVMCPU pVCpu); +VMMDECL(PCPUMCTX) CPUMQueryGuestCtxPtr(PVMCPU pVCpu); +VMMDECL(PCCPUMCTXCORE) CPUMGetGuestCtxCore(PVMCPU pVCpu); +VMMR3DECL(int) CPUMR3RawEnter(PVMCPU pVCpu, PCPUMCTXCORE pCtxCore); +VMMR3DECL(int) CPUMR3RawLeave(PVMCPU pVCpu, PCPUMCTXCORE pCtxCore, int rc); +VMMDECL(uint32_t) CPUMRawGetEFlags(PVMCPU pVCpu); +VMMDECL(void) CPUMRawSetEFlags(PVMCPU pVCpu, uint32_t fEfl); +VMMDECL(int) CPUMHandleLazyFPU(PVMCPU pVCpu); + +/** @name Changed flags. + * These flags are used to keep track of which important register that + * have been changed since last they were reset. The only one allowed + * to clear them is REM! + * @{ + */ +#define CPUM_CHANGED_FPU_REM RT_BIT(0) +#define CPUM_CHANGED_CR0 RT_BIT(1) +#define CPUM_CHANGED_CR4 RT_BIT(2) +#define CPUM_CHANGED_GLOBAL_TLB_FLUSH RT_BIT(3) +#define CPUM_CHANGED_CR3 RT_BIT(4) +#define CPUM_CHANGED_GDTR RT_BIT(5) +#define CPUM_CHANGED_IDTR RT_BIT(6) +#define CPUM_CHANGED_LDTR RT_BIT(7) +#define CPUM_CHANGED_TR RT_BIT(8) /**@< Currently unused. */ +#define CPUM_CHANGED_SYSENTER_MSR RT_BIT(9) +#define CPUM_CHANGED_HIDDEN_SEL_REGS RT_BIT(10) /**@< Currently unused. */ +#define CPUM_CHANGED_CPUID RT_BIT(11) +#define CPUM_CHANGED_ALL ( CPUM_CHANGED_FPU_REM \ + | CPUM_CHANGED_CR0 \ + | CPUM_CHANGED_CR4 \ + | CPUM_CHANGED_GLOBAL_TLB_FLUSH \ + | CPUM_CHANGED_CR3 \ + | CPUM_CHANGED_GDTR \ + | CPUM_CHANGED_IDTR \ + | CPUM_CHANGED_LDTR \ + | CPUM_CHANGED_TR \ + | CPUM_CHANGED_SYSENTER_MSR \ + | CPUM_CHANGED_HIDDEN_SEL_REGS \ + | CPUM_CHANGED_CPUID ) +/** @} */ + +VMMDECL(void) CPUMSetChangedFlags(PVMCPU pVCpu, uint32_t fChangedFlags); +VMMR3DECL(uint32_t) CPUMR3RemEnter(PVMCPU pVCpu, uint32_t *puCpl); +VMMR3DECL(void) CPUMR3RemLeave(PVMCPU pVCpu, bool fNoOutOfSyncSels); +VMMDECL(bool) CPUMSupportsFXSR(PVM pVM); +VMMDECL(bool) CPUMIsHostUsingSysEnter(PVM pVM); +VMMDECL(bool) CPUMIsHostUsingSysCall(PVM pVM); +VMMDECL(bool) CPUMIsGuestFPUStateActive(PVMCPU pVCPU); +VMMDECL(void) CPUMDeactivateGuestFPUState(PVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestDebugStateActive(PVMCPU pVCpu); +VMMDECL(void) CPUMDeactivateGuestDebugState(PVMCPU pVCpu); +VMMDECL(bool) CPUMIsHyperDebugStateActive(PVMCPU pVCpu); +VMMDECL(void) CPUMDeactivateHyperDebugState(PVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestCPL(PVMCPU pVCpu); +VMMDECL(CPUMMODE) CPUMGetGuestMode(PVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestCodeBits(PVMCPU pVCpu); +VMMDECL(DISCPUMODE) CPUMGetGuestDisMode(PVMCPU pVCpu); + + +#ifdef IN_RING3 +/** @defgroup grp_cpum_r3 The CPU Monitor(/Manager) API + * @ingroup grp_cpum + * @{ + */ + +VMMR3DECL(int) CPUMR3Init(PVM pVM); +VMMR3DECL(void) CPUMR3Relocate(PVM pVM); +VMMR3DECL(int) CPUMR3Term(PVM pVM); +VMMR3DECL(void) CPUMR3Reset(PVM pVM); +VMMR3DECL(void) CPUMR3ResetCpu(PVMCPU pVCpu); +VMMDECL(bool) CPUMR3IsStateRestorePending(PVM pVM); +VMMR3DECL(void) CPUMR3SetHWVirtEx(PVM pVM, bool fHWVirtExEnabled); +VMMR3DECL(int) CPUMR3SetCR4Feature(PVM pVM, RTHCUINTREG fOr, RTHCUINTREG fAnd); +VMMR3DECL(RCPTRTYPE(PCCPUMCPUID)) CPUMR3GetGuestCpuIdStdRCPtr(PVM pVM); +VMMR3DECL(RCPTRTYPE(PCCPUMCPUID)) CPUMR3GetGuestCpuIdExtRCPtr(PVM pVM); +VMMR3DECL(RCPTRTYPE(PCCPUMCPUID)) CPUMR3GetGuestCpuIdCentaurRCPtr(PVM pVM); +VMMR3DECL(RCPTRTYPE(PCCPUMCPUID)) CPUMR3GetGuestCpuIdDefRCPtr(PVM pVM); + +/** @} */ +#endif /* IN_RING3 */ + +#ifdef IN_RC +/** @defgroup grp_cpum_gc The CPU Monitor(/Manager) API + * @ingroup grp_cpum + * @{ + */ + +/** + * Calls a guest trap/interrupt handler directly + * + * Assumes a trap stack frame has already been setup on the guest's stack! + * This function does not return! + * + * @param pRegFrame Original trap/interrupt context + * @param selCS Code selector of handler + * @param pHandler GC virtual address of handler + * @param eflags Callee's EFLAGS + * @param selSS Stack selector for handler + * @param pEsp Stack address for handler + */ +DECLASM(void) CPUMGCCallGuestTrapHandler(PCPUMCTXCORE pRegFrame, uint32_t selCS, RTRCPTR pHandler, + uint32_t eflags, uint32_t selSS, RTRCPTR pEsp); + +/** + * Call guest V86 code directly. + * + * This function does not return! + * + * @param pRegFrame Original trap/interrupt context + */ +DECLASM(void) CPUMGCCallV86Code(PCPUMCTXCORE pRegFrame); + +/** @} */ +#endif /* IN_RC */ + +#ifdef IN_RING0 +/** @defgroup grp_cpum_r0 The CPU Monitor(/Manager) API + * @ingroup grp_cpum + * @{ + */ +VMMR0DECL(int) CPUMR0ModuleInit(void); +VMMR0DECL(int) CPUMR0ModuleTerm(void); +VMMR0DECL(int) CPUMR0Init(PVM pVM); +VMMR0DECL(int) CPUMR0LoadGuestFPU(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx); +VMMR0DECL(int) CPUMR0SaveGuestFPU(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx); +VMMR0DECL(int) CPUMR0SaveGuestDebugState(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, bool fDR6); +VMMR0DECL(int) CPUMR0LoadGuestDebugState(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, bool fDR6); +VMMR0DECL(int) CPUMR0LoadHostDebugState(PVM pVM, PVMCPU pVCpu); +VMMR0DECL(int) CPUMR0SaveHostDebugState(PVM pVM, PVMCPU pVCpu); +VMMR0DECL(int) CPUMR0LoadHyperDebugState(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, bool fDR6); +#ifdef VBOX_WITH_VMMR0_DISABLE_LAPIC_NMI +VMMR0DECL(void) CPUMR0SetLApic(PVM pVM, RTCPUID idHostCpu); +#endif + +/** @} */ +#endif /* IN_RING0 */ + +/** @} */ +RT_C_DECLS_END + + +#endif + diff --git a/include/VBox/vmm/cpum.mac b/include/VBox/vmm/cpum.mac new file mode 100644 index 00000000..8f906d06 --- /dev/null +++ b/include/VBox/vmm/cpum.mac @@ -0,0 +1,207 @@ +;; @file +; CPUM - CPU Monitor, Assembly header file. +; + +; +; Copyright (C) 2006-2010 Oracle Corporation +; +; 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 (GPL) 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. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%ifndef ___VBox_vmm_cpum_mac__ +%define ___VBox_vmm_cpum_mac__ + +;; +; Registers frame. +; This is used internally in TRPM, VMMSwitcher_GuestToHost_GuestCtx +; and other places. +struc CPUMCTXCORE + .eax resq 1 + .ecx resq 1 + .edx resq 1 + .ebx resq 1 + .esp resq 1 + .ebp resq 1 + .esi resq 1 + .edi resq 1 + .r8 resq 1 + .r9 resq 1 + .r10 resq 1 + .r11 resq 1 + .r12 resq 1 + .r13 resq 1 + .r14 resq 1 + .r15 resq 1 + .es.Sel resw 1 + .es.PaddingSel resw 1 + .es.ValidSel resw 1 + .es.fFlags resw 1 + .es.u64Base resq 1 + .es.u32Limit resd 1 + .es.Attr resd 1 + .cs.Sel resw 1 + .cs.PaddingSel resw 1 + .cs.ValidSel resw 1 + .cs.fFlags resw 1 + .cs.u64Base resq 1 + .cs.u32Limit resd 1 + .cs.Attr resd 1 + .ss.Sel resw 1 + .ss.PaddingSel resw 1 + .ss.ValidSel resw 1 + .ss.fFlags resw 1 + .ss.u64Base resq 1 + .ss.u32Limit resd 1 + .ss.Attr resd 1 + .ds.Sel resw 1 + .ds.PaddingSel resw 1 + .ds.ValidSel resw 1 + .ds.fFlags resw 1 + .ds.u64Base resq 1 + .ds.u32Limit resd 1 + .ds.Attr resd 1 + .fs.Sel resw 1 + .fs.PaddingSel resw 1 + .fs.ValidSel resw 1 + .fs.fFlags resw 1 + .fs.u64Base resq 1 + .fs.u32Limit resd 1 + .fs.Attr resd 1 + .gs.Sel resw 1 + .gs.PaddingSel resw 1 + .gs.ValidSel resw 1 + .gs.fFlags resw 1 + .gs.u64Base resq 1 + .gs.u32Limit resd 1 + .gs.Attr resd 1 + .eip resq 1 + .eflags resq 1 +endstruc + + +struc CPUMCTX + .fpu resb 512 + .eax resq 1 + .ecx resq 1 + .edx resq 1 + .ebx resq 1 + .esp resq 1 + .ebp resq 1 + .esi resq 1 + .edi resq 1 + .r8 resq 1 + .r9 resq 1 + .r10 resq 1 + .r11 resq 1 + .r12 resq 1 + .r13 resq 1 + .r14 resq 1 + .r15 resq 1 + .es.Sel resw 1 + .es.PaddingSel resw 1 + .es.ValidSel resw 1 + .es.fFlags resw 1 + .es.u64Base resq 1 + .es.u32Limit resd 1 + .es.Attr resd 1 + .cs.Sel resw 1 + .cs.PaddingSel resw 1 + .cs.ValidSel resw 1 + .cs.fFlags resw 1 + .cs.u64Base resq 1 + .cs.u32Limit resd 1 + .cs.Attr resd 1 + .ss.Sel resw 1 + .ss.PaddingSel resw 1 + .ss.ValidSel resw 1 + .ss.fFlags resw 1 + .ss.u64Base resq 1 + .ss.u32Limit resd 1 + .ss.Attr resd 1 + .ds.Sel resw 1 + .ds.PaddingSel resw 1 + .ds.ValidSel resw 1 + .ds.fFlags resw 1 + .ds.u64Base resq 1 + .ds.u32Limit resd 1 + .ds.Attr resd 1 + .fs.Sel resw 1 + .fs.PaddingSel resw 1 + .fs.ValidSel resw 1 + .fs.fFlags resw 1 + .fs.u64Base resq 1 + .fs.u32Limit resd 1 + .fs.Attr resd 1 + .gs.Sel resw 1 + .gs.PaddingSel resw 1 + .gs.ValidSel resw 1 + .gs.fFlags resw 1 + .gs.u64Base resq 1 + .gs.u32Limit resd 1 + .gs.Attr resd 1 + .eip resq 1 + .eflags resq 1 + .cr0 resq 1 + .cr2 resq 1 + .cr3 resq 1 + .cr4 resq 1 + .dr resq 8 + .gdtrPadding resw 3 + .gdtr resw 0 + .gdtr.cbGdt resw 1 + .gdtr.pGdt resq 1 + .idtrPadding resw 3 + .idtr resw 0 + .idtr.cbIdt resw 1 + .idtr.pIdt resq 1 + .ldtr.Sel resw 1 + .ldtr.PaddingSel resw 1 + .ldtr.ValidSel resw 1 + .ldtr.fFlags resw 1 + .ldtr.u64Base resq 1 + .ldtr.u32Limit resd 1 + .ldtr.Attr resd 1 + .tr.Sel resw 1 + .tr.PaddingSel resw 1 + .tr.ValidSel resw 1 + .tr.fFlags resw 1 + .tr.u64Base resq 1 + .tr.u32Limit resd 1 + .tr.Attr resd 1 + .SysEnter.cs resb 8 + .SysEnter.eip resb 8 + .SysEnter.esp resb 8 + .msrEFER resb 8 + .msrSTAR resb 8 + .msrPAT resb 8 + .msrLSTAR resb 8 + .msrCSTAR resb 8 + .msrSFMASK resb 8 + .msrKERNELGSBASE resb 8 + .au32SizePadding resb 32 +endstruc + + +;; +; Guest MSR state. +struc CPUMCTXMSRS + .au64 resq 64 +endstruc + + +%endif diff --git a/include/VBox/vmm/cpumctx-v1_6.h b/include/VBox/vmm/cpumctx-v1_6.h new file mode 100644 index 00000000..dbc5935d --- /dev/null +++ b/include/VBox/vmm/cpumctx-v1_6.h @@ -0,0 +1,249 @@ +/** @file + * CPUM - CPU Monitor(/ Manager), Context Structures from v1.6 (saved state). + */ + +/* + * Copyright (C) 2006-2012 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_cpumctx_v1_6_h +#define ___VBox_vmm_cpumctx_v1_6_h + +#include <iprt/x86.h> + + +RT_C_DECLS_BEGIN + +/** @addgroup grp_cpum_ctx_v1_6 The CPUM Context Structures from v1.6 + * @ingroup grp_cpum + * @{ + */ + +#pragma pack(1) +/** IDTR from version 1.6 */ +typedef struct VBOXIDTR_VER1_6 +{ + /** Size of the IDT. */ + uint16_t cbIdt; + /** Address of the IDT. */ + uint32_t pIdt; +} VBOXIDTR_VER1_6; +#pragma pack() + +#pragma pack(1) +/** GDTR from version 1.6 */ +typedef struct VBOXGDTR_VER1_6 +{ + /** Size of the GDT. */ + uint16_t cbGdt; + /** Address of the GDT. */ + uint32_t pGdt; +} VBOXGDTR_VER1_6; +#pragma pack() + + +/** + * Selector hidden registers, for version 1.6 saved state. + */ +typedef struct CPUMSELREGHID_VER1_6 +{ + /** Base register. */ + uint32_t u32Base; + /** Limit (expanded). */ + uint32_t u32Limit; + /** Flags. + * This is the high 32-bit word of the descriptor entry. + * Only the flags, dpl and type are used. */ + X86DESCATTR Attr; +} CPUMSELREGHID_VER1_6; + +/** + * CPU context, for version 1.6 saved state. + * @remarks PATM uses this, which is why it has to be here. + */ +# pragma pack(1) +typedef struct CPUMCTX_VER1_6 +{ + /** FPU state. (16-byte alignment) + * @todo This doesn't have to be in X86FXSTATE on CPUs without fxsr - we need a type for the + * actual format or convert it (waste of time). */ + X86FXSTATE fpu; + + /** CPUMCTXCORE Part. + * @{ */ + union + { + uint32_t edi; + uint64_t rdi; + } CPUM_UNION_NAME(rdi); + union + { + uint32_t esi; + uint64_t rsi; + } CPUM_UNION_NAME(rsi); + union + { + uint32_t ebp; + uint64_t rbp; + } CPUM_UNION_NAME(rbp); + union + { + uint32_t eax; + uint64_t rax; + } CPUM_UNION_NAME(rax); + union + { + uint32_t ebx; + uint64_t rbx; + } CPUM_UNION_NAME(rbx); + union + { + uint32_t edx; + uint64_t rdx; + } CPUM_UNION_NAME(rdx); + union + { + uint32_t ecx; + uint64_t rcx; + } CPUM_UNION_NAME(rcx); + /** @note We rely on the exact layout, because we use lss esp, [] in the + * switcher. */ + uint32_t esp; + RTSEL ss; + RTSEL ssPadding; + /* Note: no overlap with esp here. */ + uint64_t rsp_notused; + + RTSEL gs; + RTSEL gsPadding; + RTSEL fs; + RTSEL fsPadding; + RTSEL es; + RTSEL esPadding; + RTSEL ds; + RTSEL dsPadding; + RTSEL cs; + RTSEL csPadding[3]; /**< 3 words to force 8 byte alignment for the remainder. */ + + union + { + X86EFLAGS eflags; + X86RFLAGS rflags; + } CPUM_UNION_NAME(rflags); + union + { + uint32_t eip; + uint64_t rip; + } CPUM_UNION_NAME(rip); + + uint64_t r8; + uint64_t r9; + uint64_t r10; + uint64_t r11; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; + + /** Hidden selector registers. + * @{ */ + CPUMSELREGHID_VER1_6 esHid; + CPUMSELREGHID_VER1_6 csHid; + CPUMSELREGHID_VER1_6 ssHid; + CPUMSELREGHID_VER1_6 dsHid; + CPUMSELREGHID_VER1_6 fsHid; + CPUMSELREGHID_VER1_6 gsHid; + /** @} */ + + /** @} */ + + /** Control registers. + * @{ */ + uint64_t cr0; + uint64_t cr2; + uint64_t cr3; + uint64_t cr4; + uint64_t cr8; + /** @} */ + + /** Debug registers. + * @{ */ + uint64_t dr0; + uint64_t dr1; + uint64_t dr2; + uint64_t dr3; + uint64_t dr4; /**< @todo remove dr4 and dr5. */ + uint64_t dr5; + uint64_t dr6; + uint64_t dr7; + /* DR8-15 are currently not supported */ + /** @} */ + + /** Global Descriptor Table register. */ + VBOXGDTR_VER1_6 gdtr; + uint16_t gdtrPadding; + uint32_t gdtrPadding64;/** @todo fix this hack */ + /** Interrupt Descriptor Table register. */ + VBOXIDTR_VER1_6 idtr; + uint16_t idtrPadding; + uint32_t idtrPadding64;/** @todo fix this hack */ + /** The task register. + * Only the guest context uses all the members. */ + RTSEL ldtr; + RTSEL ldtrPadding; + /** The task register. + * Only the guest context uses all the members. */ + RTSEL tr; + RTSEL trPadding; + + /** The sysenter msr registers. + * This member is not used by the hypervisor context. */ + CPUMSYSENTER SysEnter; + + /** System MSRs. + * @{ */ + uint64_t msrEFER; + uint64_t msrSTAR; + uint64_t msrPAT; + uint64_t msrLSTAR; + uint64_t msrCSTAR; + uint64_t msrSFMASK; + uint64_t msrFSBASE; + uint64_t msrGSBASE; + uint64_t msrKERNELGSBASE; + /** @} */ + + /** Hidden selector registers. + * @{ */ + CPUMSELREGHID_VER1_6 ldtrHid; + CPUMSELREGHID_VER1_6 trHid; + /** @} */ + + /** padding to get 32byte aligned size. */ + uint32_t padding[2]; +} CPUMCTX_VER1_6; +# pragma pack() + +/** @} */ + +RT_C_DECLS_END + +#endif + diff --git a/include/VBox/vmm/cpumctx.h b/include/VBox/vmm/cpumctx.h new file mode 100644 index 00000000..35861823 --- /dev/null +++ b/include/VBox/vmm/cpumctx.h @@ -0,0 +1,477 @@ +/** @file + * CPUM - CPU Monitor(/ Manager), Context Structures. + */ + +/* + * Copyright (C) 2006-2012 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_cpumctx_h +#define ___VBox_vmm_cpumctx_h + +#ifndef VBOX_FOR_DTRACE_LIB +# include <iprt/x86.h> +# include <VBox/types.h> +#else +# pragma D depends_on library x86.d +#endif + + +RT_C_DECLS_BEGIN + +/** @addgroup grp_cpum_ctx The CPUM Context Structures + * @ingroup grp_cpum + * @{ + */ + +/** + * Selector hidden registers. + */ +typedef struct CPUMSELREG +{ + /** The selector register. */ + RTSEL Sel; + /** Padding, don't use. */ + RTSEL PaddingSel; + /** The selector which info resides in u64Base, u32Limit and Attr, provided + * that CPUMSELREG_FLAGS_VALID is set. */ + RTSEL ValidSel; + /** Flags, see CPUMSELREG_FLAGS_XXX. */ + uint16_t fFlags; + + /** Base register. + * + * Long mode remarks: + * - Unused in long mode for CS, DS, ES, SS + * - 32 bits for FS & GS; FS(GS)_BASE msr used for the base address + * - 64 bits for TR & LDTR + */ + uint64_t u64Base; + /** Limit (expanded). */ + uint32_t u32Limit; + /** Flags. + * This is the high 32-bit word of the descriptor entry. + * Only the flags, dpl and type are used. */ + X86DESCATTR Attr; +} CPUMSELREG; + +/** @name CPUMSELREG_FLAGS_XXX - CPUMSELREG::fFlags values. + * @{ */ +#define CPUMSELREG_FLAGS_VALID UINT16_C(0x0001) +#define CPUMSELREG_FLAGS_STALE UINT16_C(0x0002) +#define CPUMSELREG_FLAGS_VALID_MASK UINT16_C(0x0003) +/** @} */ + +/** Checks if the hidden parts of the selector register are valid. */ +#ifdef VBOX_WITH_RAW_MODE_NOT_R0 +# define CPUMSELREG_ARE_HIDDEN_PARTS_VALID(a_pVCpu, a_pSelReg) \ + ( ((a_pSelReg)->fFlags & CPUMSELREG_FLAGS_VALID) \ + && ( (a_pSelReg)->ValidSel == (a_pSelReg)->Sel \ + || ( (a_pVCpu) /*!= NULL*/ \ + && (a_pSelReg)->ValidSel == ((a_pSelReg)->Sel & X86_SEL_MASK_OFF_RPL) \ + && ((a_pSelReg)->Sel & X86_SEL_RPL) == 1 \ + && ((a_pSelReg)->ValidSel & X86_SEL_RPL) == 0 \ + && CPUMIsGuestInRawMode(a_pVCpu) \ + ) \ + ) \ + ) +#else +# define CPUMSELREG_ARE_HIDDEN_PARTS_VALID(a_pVCpu, a_pSelReg) \ + ( ((a_pSelReg)->fFlags & CPUMSELREG_FLAGS_VALID) \ + && (a_pSelReg)->ValidSel == (a_pSelReg)->Sel ) +#endif + +/** Old type used for the hidden register part. + * @deprecated */ +typedef CPUMSELREG CPUMSELREGHID; + +/** + * The sysenter register set. + */ +typedef struct CPUMSYSENTER +{ + /** Ring 0 cs. + * This value + 8 is the Ring 0 ss. + * This value + 16 is the Ring 3 cs. + * This value + 24 is the Ring 3 ss. + */ + uint64_t cs; + /** Ring 0 eip. */ + uint64_t eip; + /** Ring 0 esp. */ + uint64_t esp; +} CPUMSYSENTER; + +/** + * For compilers (like DTrace) that does not grok nameless unions, we have a + * little hack to make them palatable. + */ +#ifdef VBOX_FOR_DTRACE_LIB +# define CPUM_UNION_NAME(a_Nm) a_Nm +#elif defined(VBOX_WITHOUT_UNNAMED_UNIONS) +# define CPUM_UNION_NAME(a_Nm) a_Nm +#else +# define CPUM_UNION_NAME(a_Nm) +#endif + + +/** + * CPU context core. + * + * @todo eliminate this structure! + */ +#pragma pack(1) +typedef struct CPUMCTXCORE +{ + /** @name General Register. + * @note These follow the encoding order (X86_GREG_XXX) and can be accessed as + * an array starting a rax. + * @{ */ + union + { + uint8_t al; + uint16_t ax; + uint32_t eax; + uint64_t rax; + } CPUM_UNION_NAME(rax); + union + { + uint8_t cl; + uint16_t cx; + uint32_t ecx; + uint64_t rcx; + } CPUM_UNION_NAME(rcx); + union + { + uint8_t dl; + uint16_t dx; + uint32_t edx; + uint64_t rdx; + } CPUM_UNION_NAME(rdx); + union + { + uint8_t bl; + uint16_t bx; + uint32_t ebx; + uint64_t rbx; + } CPUM_UNION_NAME(rbx); + union + { + uint16_t sp; + uint32_t esp; + uint64_t rsp; + } CPUM_UNION_NAME(rsp); + union + { + uint16_t bp; + uint32_t ebp; + uint64_t rbp; + } CPUM_UNION_NAME(rbp); + union + { + uint8_t sil; + uint16_t si; + uint32_t esi; + uint64_t rsi; + } CPUM_UNION_NAME(rsi); + union + { + uint8_t dil; + uint16_t di; + uint32_t edi; + uint64_t rdi; + } CPUM_UNION_NAME(rdi); + uint64_t r8; + uint64_t r9; + uint64_t r10; + uint64_t r11; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; + /** @} */ + + /** @name Segment registers. + * @note These follow the encoding order (X86_SREG_XXX) and can be accessed as + * an array starting a es. + * @{ */ + CPUMSELREG es; + CPUMSELREG cs; + CPUMSELREG ss; + CPUMSELREG ds; + CPUMSELREG fs; + CPUMSELREG gs; + /** @} */ + + /** The program counter. */ + union + { + uint16_t ip; + uint32_t eip; + uint64_t rip; + } CPUM_UNION_NAME(rip); + + /** The flags register. */ + union + { + X86EFLAGS eflags; + X86RFLAGS rflags; + } CPUM_UNION_NAME(rflags); + +} CPUMCTXCORE; +#pragma pack() + + +/** + * CPU context. + */ +#pragma pack(1) /* for VBOXIDTR / VBOXGDTR. */ +typedef struct CPUMCTX +{ + /** FPU state. (16-byte alignment) + * @todo This doesn't have to be in X86FXSTATE on CPUs without fxsr - we need a type for the + * actual format or convert it (waste of time). */ + X86FXSTATE fpu; + + /** CPUMCTXCORE Part. + * @{ */ + + /** @name General Register. + * @note These follow the encoding order (X86_GREG_XXX) and can be accessed as + * an array starting at rax. + * @{ */ + union + { + uint8_t al; + uint16_t ax; + uint32_t eax; + uint64_t rax; + } CPUM_UNION_NAME(rax); + union + { + uint8_t cl; + uint16_t cx; + uint32_t ecx; + uint64_t rcx; + } CPUM_UNION_NAME(rcx); + union + { + uint8_t dl; + uint16_t dx; + uint32_t edx; + uint64_t rdx; + } CPUM_UNION_NAME(rdx); + union + { + uint8_t bl; + uint16_t bx; + uint32_t ebx; + uint64_t rbx; + } CPUM_UNION_NAME(rbx); + union + { + uint16_t sp; + uint32_t esp; + uint64_t rsp; + } CPUM_UNION_NAME(rsp); + union + { + uint16_t bp; + uint32_t ebp; + uint64_t rbp; + } CPUM_UNION_NAME(rbp); + union + { + uint8_t sil; + uint16_t si; + uint32_t esi; + uint64_t rsi; + } CPUM_UNION_NAME(rsi); + union + { + uint8_t dil; + uint16_t di; + uint32_t edi; + uint64_t rdi; + } CPUM_UNION_NAME(rdi); + uint64_t r8; + uint64_t r9; + uint64_t r10; + uint64_t r11; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; + /** @} */ + + /** @name Segment registers. + * @note These follow the encoding order (X86_SREG_XXX) and can be accessed as + * an array starting at es. + * @{ */ + CPUMSELREG es; + CPUMSELREG cs; + CPUMSELREG ss; + CPUMSELREG ds; + CPUMSELREG fs; + CPUMSELREG gs; + /** @} */ + + /** The program counter. */ + union + { + uint16_t ip; + uint32_t eip; + uint64_t rip; + } CPUM_UNION_NAME(rip); + + /** The flags register. */ + union + { + X86EFLAGS eflags; + X86RFLAGS rflags; + } CPUM_UNION_NAME(rflags); + + /** @} */ /*(CPUMCTXCORE)*/ + + + /** @name Control registers. + * @{ */ + uint64_t cr0; + uint64_t cr2; + uint64_t cr3; + uint64_t cr4; + /** @} */ + + /** Debug registers. + * @remarks DR4 and DR5 should not be used since they are aliases for + * DR6 and DR7 respectively on both AMD and Intel CPUs. + * @remarks DR8-15 are currently not supported by AMD or Intel, so + * neither do we. + */ + uint64_t dr[8]; + + /** Padding before the structure so the 64-bit member is correctly aligned. + * @todo fix this structure! */ + uint16_t gdtrPadding[3]; + /** Global Descriptor Table register. */ + VBOXGDTR gdtr; + + /** Padding before the structure so the 64-bit member is correctly aligned. + * @todo fix this structure! */ + uint16_t idtrPadding[3]; + /** Interrupt Descriptor Table register. */ + VBOXIDTR idtr; + + /** The task register. + * Only the guest context uses all the members. */ + CPUMSELREG ldtr; + /** The task register. + * Only the guest context uses all the members. */ + CPUMSELREG tr; + + /** The sysenter msr registers. + * This member is not used by the hypervisor context. */ + CPUMSYSENTER SysEnter; + + /** @name System MSRs. + * @{ */ + uint64_t msrEFER; + uint64_t msrSTAR; /**< Legacy syscall eip, cs & ss. */ + uint64_t msrPAT; /**< Page attribute table. */ + uint64_t msrLSTAR; /**< 64 bits mode syscall rip. */ + uint64_t msrCSTAR; /**< Compatibility mode syscall rip. */ + uint64_t msrSFMASK; /**< syscall flag mask. */ + uint64_t msrKERNELGSBASE; /**< swapgs exchange value. */ + /** @} */ + + /** Size padding. */ + uint32_t au32SizePadding[8]; +} CPUMCTX; +#pragma pack() + +#ifndef VBOX_FOR_DTRACE_LIB + +/** + * Gets the CPUMCTXCORE part of a CPUMCTX. + */ +# define CPUMCTX2CORE(pCtx) ((PCPUMCTXCORE)(void *)&(pCtx)->rax) + +/** + * Gets the first selector register of a CPUMCTX. + * + * Use this with X86_SREG_COUNT to loop thru the selector registers. + */ +# define CPUMCTX_FIRST_SREG(a_pCtx) (&(a_pCtx)->es) + +#endif /* !VBOX_FOR_DTRACE_LIB */ + +/** + * Additional guest MSRs (i.e. not part of the CPU context structure). + * + * @remarks Never change the order here because of the saved stated! The size + * can in theory be changed, but keep older VBox versions in mind. + */ +typedef union CPUMCTXMSRS +{ + struct + { + uint64_t TscAux; /**< MSR_K8_TSC_AUX */ + uint64_t MiscEnable; /**< MSR_IA32_MISC_ENABLE */ + uint64_t MtrrDefType; /**< IA32_MTRR_DEF_TYPE */ + uint64_t MtrrFix64K_00000; /**< IA32_MTRR_FIX16K_80000 */ + uint64_t MtrrFix16K_80000; /**< IA32_MTRR_FIX16K_80000 */ + uint64_t MtrrFix16K_A0000; /**< IA32_MTRR_FIX16K_A0000 */ + uint64_t MtrrFix4K_C0000; /**< IA32_MTRR_FIX4K_C0000 */ + uint64_t MtrrFix4K_C8000; /**< IA32_MTRR_FIX4K_C8000 */ + uint64_t MtrrFix4K_D0000; /**< IA32_MTRR_FIX4K_D0000 */ + uint64_t MtrrFix4K_D8000; /**< IA32_MTRR_FIX4K_D8000 */ + uint64_t MtrrFix4K_E0000; /**< IA32_MTRR_FIX4K_E0000 */ + uint64_t MtrrFix4K_E8000; /**< IA32_MTRR_FIX4K_E8000 */ + uint64_t MtrrFix4K_F0000; /**< IA32_MTRR_FIX4K_F0000 */ + uint64_t MtrrFix4K_F8000; /**< IA32_MTRR_FIX4K_F8000 */ + } msr; + uint64_t au64[64]; +} CPUMCTXMSRS; +/** Pointer to the guest MSR state. */ +typedef CPUMCTXMSRS *PCPUMCTXMSRS; +/** Pointer to the const guest MSR state. */ +typedef const CPUMCTXMSRS *PCCPUMCTXMSRS; + +/** + * The register set returned by a CPUID operation. + */ +typedef struct CPUMCPUID +{ + uint32_t eax; + uint32_t ebx; + uint32_t ecx; + uint32_t edx; +} CPUMCPUID; +/** Pointer to a CPUID leaf. */ +typedef CPUMCPUID *PCPUMCPUID; +/** Pointer to a const CPUID leaf. */ +typedef const CPUMCPUID *PCCPUMCPUID; + +/** @} */ + +RT_C_DECLS_END + +#endif + diff --git a/include/VBox/vmm/cpumdis.h b/include/VBox/vmm/cpumdis.h new file mode 100644 index 00000000..9aa509a3 --- /dev/null +++ b/include/VBox/vmm/cpumdis.h @@ -0,0 +1,48 @@ +/** @file + * CPUM - Disassembler. + */ + +/* + * Copyright (C) 2006-2010 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_cpumdis_h +#define ___VBox_vmm_cpumdis_h + +#include <VBox/vmm/cpum.h> +#include <iprt/x86.h> +#include <VBox/dis.h> + + +RT_C_DECLS_BEGIN +/** @addtogroup grp_cpum + * @{ + */ + +#ifdef IN_RING3 +VMMR3DECL(int) CPUMR3DisasmInstrCPU(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, RTGCPTR GCPtrPC, PDISCPUSTATE pCpu, const char *pszPrefix); +#endif + +/** @} */ +RT_C_DECLS_END + + +#endif + diff --git a/include/VBox/vmm/csam.h b/include/VBox/vmm/csam.h new file mode 100644 index 00000000..675cac7f --- /dev/null +++ b/include/VBox/vmm/csam.h @@ -0,0 +1,305 @@ +/** @file + * CSAM - Guest OS Code Scanning and Analyis Manager. + */ + +/* + * Copyright (C) 2006-2010 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_csam_h +#define ___VBox_vmm_csam_h + +#include <VBox/types.h> + + +/** @defgroup grp_csam The Code Scanning and Analysis API + * @{ + */ + +/** + * CSAM monitoring tag + * For use with CSAMR3MonitorPage + */ +typedef enum CSAMTAG +{ + CSAM_TAG_INVALID = 0, + CSAM_TAG_REM, + CSAM_TAG_PATM, + CSAM_TAG_CSAM, + CSAM_TAG_32BIT_HACK = 0x7fffffff +} CSAMTAG; + + +RT_C_DECLS_BEGIN + + +/** + * Check if this page needs to be analysed by CSAM. + * + * This function should only be called for supervisor pages and + * only when CSAM is enabled. Leaving these selection criteria + * to the caller simplifies the interface (PTE passing). + * + * Note the the page has not yet been synced, so the TLB trick + * (which wasn't ever active anyway) cannot be applied. + * + * @returns true if the page should be marked not present because + * CSAM want need to scan it. + * @returns false if the page was already scanned. + * @param pVM The VM to operate on. + * @param GCPtr GC pointer of page table entry + */ +VMMDECL(bool) CSAMDoesPageNeedScanning(PVM pVM, RTRCUINTPTR GCPtr); + +/** + * Check if this page was previously scanned by CSAM + * + * @returns true -> scanned, false -> not scanned + * @param pVM The VM to operate on. + * @param pPage GC page address + */ +VMMDECL(bool) CSAMIsPageScanned(PVM pVM, RTRCPTR pPage); + +/** + * Mark a page as scanned/not scanned + * + * @note: we always mark it as scanned, even if we haven't completely done so + * + * @returns VBox status code. + * @param pVM The VM to operate on. + * @param pPage GC page address (not necessarily aligned) + * @param fScanned Mark as scanned or not scanned + * + */ +VMMDECL(int) CSAMMarkPage(PVM pVM, RTRCUINTPTR pPage, bool fScanned); + + +/** + * Remember a possible code page for later inspection + * + * @returns VBox status code. + * @param pVM The VM to operate on. + * @param GCPtr GC pointer of page + */ +VMMDECL(void) CSAMMarkPossibleCodePage(PVM pVM, RTRCPTR GCPtr); + +/** + * Query CSAM state (enabled/disabled) + * + * @returns 0 - disabled, 1 - enabled + * @param pVM The VM to operate on. + */ +#define CSAMIsEnabled(pVM) (pVM->fCSAMEnabled && EMIsRawRing0Enabled(pVM)) + +/** + * Turn on code scanning + * + * @returns VBox status code. (trap handled or not) + * @param pVM The VM to operate on. + */ +VMMDECL(int) CSAMEnableScanning(PVM pVM); + +/** + * Turn off code scanning + * + * @returns VBox status code. (trap handled or not) + * @param pVM The VM to operate on. + */ +VMMDECL(int) CSAMDisableScanning(PVM pVM); + + +/** + * Check if this page needs to be analysed by CSAM + * + * @returns 0 - disabled, 1 - enabled + * @param pVM The VM to operate on. + * @param pvFault Fault address + */ +VMMDECL(int) CSAMExecFault(PVM pVM, RTRCPTR pvFault); + +/** + * Check if we've scanned this instruction before. If true, then we can emulate + * it instead of returning to ring 3. + * + * @returns boolean + * @param pVM The VM to operate on. + * @param GCPtr GC pointer of page table entry + */ +VMMDECL(bool) CSAMIsKnownDangerousInstr(PVM pVM, RTRCUINTPTR GCPtr); + + +#ifdef IN_RING3 +/** @defgroup grp_csam_r3 The Code Scanning and Analysis API + * @ingroup grp_csam + * @{ + */ + +/** + * Query CSAM state (enabled/disabled) + * + * @returns 0 - disabled, 1 - enabled + * @param pVM The VM to operate on. + */ +VMMR3DECL(int) CSAMR3IsEnabled(PVM pVM); + +/** + * Initializes the csam. + * + * @returns VBox status code. + * @param pVM The VM to operate on. + */ +VMMR3DECL(int) CSAMR3Init(PVM pVM); + +/** + * Applies relocations to data and code managed by this + * component. This function will be called at init and + * whenever the VMM need to relocate it self inside the GC. + * + * The csam will update the addresses used by the switcher. + * + * @param pVM The VM. + * @param offDelta Relocation delta. + */ +VMMR3DECL(void) CSAMR3Relocate(PVM pVM, RTGCINTPTR offDelta); + +/** + * Terminates the csam. + * + * Termination means cleaning up and freeing all resources, + * the VM it self is at this point powered off or suspended. + * + * @returns VBox status code. + * @param pVM The VM to operate on. + */ +VMMR3DECL(int) CSAMR3Term(PVM pVM); + +/** + * CSAM reset callback. + * + * @returns VBox status code. + * @param pVM The VM which is reset. + */ +VMMR3DECL(int) CSAMR3Reset(PVM pVM); + + +/** + * Notify CSAM of a page flush + * + * @returns VBox status code + * @param pVM The VM to operate on. + * @param addr GC address of the page to flush + */ +VMMR3DECL(int) CSAMR3FlushPage(PVM pVM, RTRCPTR addr); + +/** + * Remove a CSAM monitored page. Use with care! + * + * @returns VBox status code + * @param pVM The VM to operate on. + * @param addr GC address of the page to flush + */ +VMMR3DECL(int) CSAMR3RemovePage(PVM pVM, RTRCPTR addr); + +/** + * Scan and analyse code + * + * @returns VBox status code. + * @param pVM The VM to operate on. + * @param pCtxCore CPU context + * @param pInstrGC Instruction pointer + */ +VMMR3DECL(int) CSAMR3CheckCodeEx(PVM pVM, PCPUMCTXCORE pCtxCore, RTRCPTR pInstrGC); + +/** + * Scan and analyse code + * + * @returns VBox status code. + * @param pVM The VM to operate on. + * @param pInstrGC Instruction pointer (0:32 virtual address) + */ +VMMR3DECL(int) CSAMR3CheckCode(PVM pVM, RTRCPTR pInstrGC); + +/** + * Mark an instruction in a page as scanned/not scanned + * + * @returns VBox status code. + * @param pVM The VM to operate on. + * @param pInstr Instruction pointer + * @param cbInstr Instruction size + * @param fScanned Mark as scanned or not + */ +VMMR3DECL(int) CSAMR3MarkCode(PVM pVM, RTRCPTR pInstr, uint32_t cbInstr, bool fScanned); + +/** + * Perform any pending actions + * + * @returns VBox status code. + * @param pVM The VM to operate on. + * @param pVCpu The VMCPU to operate on. + */ +VMMR3DECL(int) CSAMR3DoPendingAction(PVM pVM, PVMCPU pVCpu); + +/** + * Monitors a code page (if not already monitored) + * + * @returns VBox status code + * @param pVM The VM to operate on. + * @param pPageAddrGC The page to monitor + * @param enmTag Monitor tag + */ +VMMR3DECL(int) CSAMR3MonitorPage(PVM pVM, RTRCPTR pPageAddrGC, CSAMTAG enmTag); + +/** + * Unmonitors a code page + * + * @returns VBox status code + * @param pVM The VM to operate on. + * @param pPageAddrGC The page to monitor + * @param enmTag Monitor tag + */ +VMMR3DECL(int) CSAMR3UnmonitorPage(PVM pVM, RTRCPTR pPageAddrGC, CSAMTAG enmTag); + +/** + * Analyse interrupt and trap gates + * + * @returns VBox status code. + * @param pVM The VM to operate on. + * @param iGate Start gate + * @param cGates Number of gates to check + */ +VMMR3DECL(int) CSAMR3CheckGates(PVM pVM, uint32_t iGate, uint32_t cGates); + +/** + * Record previous call instruction addresses + * + * @returns VBox status code. + * @param pVM The VM to operate on. + * @param GCPtrCall Call address + */ +VMMR3DECL(int) CSAMR3RecordCallAddress(PVM pVM, RTRCPTR GCPtrCall); + +/** @} */ +#endif + + +/** @} */ +RT_C_DECLS_END + +#endif diff --git a/include/VBox/vmm/dbgf.h b/include/VBox/vmm/dbgf.h new file mode 100644 index 00000000..65bb94c7 --- /dev/null +++ b/include/VBox/vmm/dbgf.h @@ -0,0 +1,1658 @@ +/** @file + * DBGF - Debugger Facility. + */ + +/* + * Copyright (C) 2006-2010 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_dbgf_h +#define ___VBox_vmm_dbgf_h + +#include <VBox/types.h> +#include <VBox/log.h> /* LOG_ENABLED */ +#include <VBox/vmm/vmm.h> +#include <VBox/vmm/dbgfsel.h> + +#include <iprt/stdarg.h> +#include <iprt/dbg.h> + +RT_C_DECLS_BEGIN + + +/** @defgroup grp_dbgf The Debugger Facility API + * @{ + */ + +#if defined(IN_RC) || defined(IN_RING0) +/** @addgroup grp_dbgf_rz The RZ DBGF API + * @ingroup grp_dbgf + * @{ + */ +VMMRZDECL(int) DBGFRZTrap01Handler(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, RTGCUINTREG uDr6); +VMMRZDECL(int) DBGFRZTrap03Handler(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame); +/** @} */ +#endif + + + +#ifdef IN_RING3 + +/** + * Mixed address. + */ +typedef struct DBGFADDRESS +{ + /** The flat address. */ + RTGCUINTPTR FlatPtr; + /** The selector offset address. */ + RTGCUINTPTR off; + /** The selector. DBGF_SEL_FLAT is a legal value. */ + RTSEL Sel; + /** Flags describing further details about the address. */ + uint16_t fFlags; +} DBGFADDRESS; +/** Pointer to a mixed address. */ +typedef DBGFADDRESS *PDBGFADDRESS; +/** Pointer to a const mixed address. */ +typedef const DBGFADDRESS *PCDBGFADDRESS; + +/** @name DBGFADDRESS Flags. + * @{ */ +/** A 16:16 far address. */ +#define DBGFADDRESS_FLAGS_FAR16 0 +/** A 16:32 far address. */ +#define DBGFADDRESS_FLAGS_FAR32 1 +/** A 16:64 far address. */ +#define DBGFADDRESS_FLAGS_FAR64 2 +/** A flat address. */ +#define DBGFADDRESS_FLAGS_FLAT 3 +/** A physical address. */ +#define DBGFADDRESS_FLAGS_PHYS 4 +/** A physical address. */ +#define DBGFADDRESS_FLAGS_RING0 5 +/** The address type mask. */ +#define DBGFADDRESS_FLAGS_TYPE_MASK 7 + +/** Set if the address is valid. */ +#define DBGFADDRESS_FLAGS_VALID RT_BIT(3) + +/** The address is within the hypervisor memoary area (HMA). + * If not set, the address can be assumed to be a guest address. */ +#define DBGFADDRESS_FLAGS_HMA RT_BIT(4) + +/** Checks if the mixed address is flat or not. */ +#define DBGFADDRESS_IS_FLAT(pAddress) ( ((pAddress)->fFlags & DBGFADDRESS_FLAGS_TYPE_MASK) == DBGFADDRESS_FLAGS_FLAT ) +/** Checks if the mixed address is flat or not. */ +#define DBGFADDRESS_IS_PHYS(pAddress) ( ((pAddress)->fFlags & DBGFADDRESS_FLAGS_TYPE_MASK) == DBGFADDRESS_FLAGS_PHYS ) +/** Checks if the mixed address is far 16:16 or not. */ +#define DBGFADDRESS_IS_FAR16(pAddress) ( ((pAddress)->fFlags & DBGFADDRESS_FLAGS_TYPE_MASK) == DBGFADDRESS_FLAGS_FAR16 ) +/** Checks if the mixed address is far 16:32 or not. */ +#define DBGFADDRESS_IS_FAR32(pAddress) ( ((pAddress)->fFlags & DBGFADDRESS_FLAGS_TYPE_MASK) == DBGFADDRESS_FLAGS_FAR32 ) +/** Checks if the mixed address is far 16:64 or not. */ +#define DBGFADDRESS_IS_FAR64(pAddress) ( ((pAddress)->fFlags & DBGFADDRESS_FLAGS_TYPE_MASK) == DBGFADDRESS_FLAGS_FAR64 ) +/** Checks if the mixed address is valid. */ +#define DBGFADDRESS_IS_VALID(pAddress) ( !!((pAddress)->fFlags & DBGFADDRESS_FLAGS_VALID) ) +/** Checks if the address is flagged as within the HMA. */ +#define DBGFADDRESS_IS_HMA(pAddress) ( !!((pAddress)->fFlags & DBGFADDRESS_FLAGS_HMA) ) +/** @} */ + +VMMR3DECL(int) DBGFR3AddrFromSelOff(PVM pVM, VMCPUID idCpu, PDBGFADDRESS pAddress, RTSEL Sel, RTUINTPTR off); +VMMR3DECL(int) DBGFR3AddrFromSelInfoOff(PVM pVM, PDBGFADDRESS pAddress, PCDBGFSELINFO pSelInfo, RTUINTPTR off); +VMMR3DECL(PDBGFADDRESS) DBGFR3AddrFromFlat(PVM pVM, PDBGFADDRESS pAddress, RTGCUINTPTR FlatPtr); +VMMR3DECL(PDBGFADDRESS) DBGFR3AddrFromPhys(PVM pVM, PDBGFADDRESS pAddress, RTGCPHYS PhysAddr); +VMMR3DECL(bool) DBGFR3AddrIsValid(PVM pVM, PCDBGFADDRESS pAddress); +VMMR3DECL(int) DBGFR3AddrToPhys(PVM pVM, VMCPUID idCpu, PDBGFADDRESS pAddress, PRTGCPHYS pGCPhys); +VMMR3DECL(int) DBGFR3AddrToHostPhys(PVM pVM, VMCPUID idCpu, PDBGFADDRESS pAddress, PRTHCPHYS pHCPhys); +VMMR3DECL(int) DBGFR3AddrToVolatileR3Ptr(PVM pVM, VMCPUID idCpu, PDBGFADDRESS pAddress, bool fReadOnly, void **ppvR3Ptr); +VMMR3DECL(PDBGFADDRESS) DBGFR3AddrAdd(PDBGFADDRESS pAddress, RTGCUINTPTR uAddend); +VMMR3DECL(PDBGFADDRESS) DBGFR3AddrSub(PDBGFADDRESS pAddress, RTGCUINTPTR uSubtrahend); + +#endif /* IN_RING3 */ + + + +/** + * VMM Debug Event Type. + */ +typedef enum DBGFEVENTTYPE +{ + /** Halt completed. + * This notifies that a halt command have been successfully completed. + */ + DBGFEVENT_HALT_DONE = 0, + /** Detach completed. + * This notifies that the detach command have been successfully completed. + */ + DBGFEVENT_DETACH_DONE, + /** The command from the debugger is not recognized. + * This means internal error or half implemented features. + */ + DBGFEVENT_INVALID_COMMAND, + + + /** Fatal error. + * This notifies a fatal error in the VMM and that the debugger get's a + * chance to first hand information about the the problem. + */ + DBGFEVENT_FATAL_ERROR = 100, + /** Breakpoint Hit. + * This notifies that a breakpoint installed by the debugger was hit. The + * identifier of the breakpoint can be found in the DBGFEVENT::u::Bp::iBp member. + */ + DBGFEVENT_BREAKPOINT, + /** Breakpoint Hit in the Hypervisor. + * This notifies that a breakpoint installed by the debugger was hit. The + * identifier of the breakpoint can be found in the DBGFEVENT::u::Bp::iBp member. + */ + DBGFEVENT_BREAKPOINT_HYPER, + /** Assertion in the Hypervisor (breakpoint instruction). + * This notifies that a breakpoint instruction was hit in the hypervisor context. + */ + DBGFEVENT_ASSERTION_HYPER, + /** Single Stepped. + * This notifies that a single step operation was completed. + */ + DBGFEVENT_STEPPED, + /** Single Stepped. + * This notifies that a hypervisor single step operation was completed. + */ + DBGFEVENT_STEPPED_HYPER, + /** The developer have used the DBGFSTOP macro or the PDMDeviceDBGFSTOP function + * to bring up the debugger at a specific place. + */ + DBGFEVENT_DEV_STOP, + /** The VM is terminating. + * When this notification is received, the debugger thread should detach ASAP. + */ + DBGFEVENT_TERMINATING, + + /** The usual 32-bit hack. */ + DBGFEVENT_32BIT_HACK = 0x7fffffff +} DBGFEVENTTYPE; + + +/** + * The context of an event. + */ +typedef enum DBGFEVENTCTX +{ + /** The usual invalid entry. */ + DBGFEVENTCTX_INVALID = 0, + /** Raw mode. */ + DBGFEVENTCTX_RAW, + /** Recompiled mode. */ + DBGFEVENTCTX_REM, + /** VMX / AVT mode. */ + DBGFEVENTCTX_HWACCL, + /** Hypervisor context. */ + DBGFEVENTCTX_HYPER, + /** Other mode */ + DBGFEVENTCTX_OTHER, + + /** The usual 32-bit hack */ + DBGFEVENTCTX_32BIT_HACK = 0x7fffffff +} DBGFEVENTCTX; + +/** + * VMM Debug Event. + */ +typedef struct DBGFEVENT +{ + /** Type. */ + DBGFEVENTTYPE enmType; + /** Context */ + DBGFEVENTCTX enmCtx; + /** Type specific data. */ + union + { + /** Fatal error details. */ + struct + { + /** The GC return code. */ + int rc; + } FatalError; + + /** Source location. */ + struct + { + /** File name. */ + R3PTRTYPE(const char *) pszFile; + /** Function name. */ + R3PTRTYPE(const char *) pszFunction; + /** Message. */ + R3PTRTYPE(const char *) pszMessage; + /** Line number. */ + unsigned uLine; + } Src; + + /** Assertion messages. */ + struct + { + /** The first message. */ + R3PTRTYPE(const char *) pszMsg1; + /** The second message. */ + R3PTRTYPE(const char *) pszMsg2; + } Assert; + + /** Breakpoint. */ + struct DBGFEVENTBP + { + /** The identifier of the breakpoint which was hit. */ + RTUINT iBp; + } Bp; + /** Padding for ensuring that the structure is 8 byte aligned. */ + uint64_t au64Padding[4]; + } u; +} DBGFEVENT; +/** Pointer to VMM Debug Event. */ +typedef DBGFEVENT *PDBGFEVENT; +/** Pointer to const VMM Debug Event. */ +typedef const DBGFEVENT *PCDBGFEVENT; + +#ifdef IN_RING3 /* The event API only works in ring-3. */ + +/** @def DBGFSTOP + * Stops the debugger raising a DBGFEVENT_DEVELOPER_STOP event. + * + * @returns VBox status code which must be propagated up to EM if not VINF_SUCCESS. + * @param pVM VM Handle. + */ +# ifdef VBOX_STRICT +# define DBGFSTOP(pVM) DBGFR3EventSrc(pVM, DBGFEVENT_DEV_STOP, __FILE__, __LINE__, __PRETTY_FUNCTION__, NULL) +# else +# define DBGFSTOP(pVM) VINF_SUCCESS +# endif + +VMMR3DECL(int) DBGFR3Init(PVM pVM); +VMMR3DECL(int) DBGFR3Term(PVM pVM); +VMMR3DECL(void) DBGFR3Relocate(PVM pVM, RTGCINTPTR offDelta); +VMMR3DECL(int) DBGFR3VMMForcedAction(PVM pVM); +VMMR3DECL(int) DBGFR3Event(PVM pVM, DBGFEVENTTYPE enmEvent); +VMMR3DECL(int) DBGFR3EventSrc(PVM pVM, DBGFEVENTTYPE enmEvent, const char *pszFile, unsigned uLine, const char *pszFunction, const char *pszFormat, ...); +VMMR3DECL(int) DBGFR3EventSrcV(PVM pVM, DBGFEVENTTYPE enmEvent, const char *pszFile, unsigned uLine, const char *pszFunction, const char *pszFormat, va_list args); +VMMR3DECL(int) DBGFR3EventAssertion(PVM pVM, DBGFEVENTTYPE enmEvent, const char *pszMsg1, const char *pszMsg2); +VMMR3DECL(int) DBGFR3EventBreakpoint(PVM pVM, DBGFEVENTTYPE enmEvent); +VMMR3DECL(int) DBGFR3Attach(PVM pVM); +VMMR3DECL(int) DBGFR3Detach(PVM pVM); +VMMR3DECL(int) DBGFR3EventWait(PVM pVM, RTMSINTERVAL cMillies, PCDBGFEVENT *ppEvent); +VMMR3DECL(int) DBGFR3Halt(PVM pVM); +VMMR3DECL(bool) DBGFR3IsHalted(PVM pVM); +VMMR3DECL(bool) DBGFR3CanWait(PVM pVM); +VMMR3DECL(int) DBGFR3Resume(PVM pVM); +VMMR3DECL(int) DBGFR3Step(PVM pVM, VMCPUID idCpu); +VMMR3DECL(int) DBGFR3PrgStep(PVMCPU pVCpu); + +#endif /* IN_RING3 */ + + + +/** Breakpoint type. */ +typedef enum DBGFBPTYPE +{ + /** Free breakpoint entry. */ + DBGFBPTYPE_FREE = 0, + /** Debug register. */ + DBGFBPTYPE_REG, + /** INT 3 instruction. */ + DBGFBPTYPE_INT3, + /** Recompiler. */ + DBGFBPTYPE_REM, + /** ensure 32-bit size. */ + DBGFBPTYPE_32BIT_HACK = 0x7fffffff +} DBGFBPTYPE; + + +/** + * A Breakpoint. + */ +typedef struct DBGFBP +{ + /** The number of breakpoint hits. */ + uint64_t cHits; + /** The hit number which starts to trigger the breakpoint. */ + uint64_t iHitTrigger; + /** The hit number which stops triggering the breakpoint (disables it). + * Use ~(uint64_t)0 if it should never stop. */ + uint64_t iHitDisable; + /** The Flat GC address of the breakpoint. + * (PC register value if REM type?) */ + RTGCUINTPTR GCPtr; + /** The breakpoint id. */ + uint32_t iBp; + /** The breakpoint status - enabled or disabled. */ + bool fEnabled; + + /** The breakpoint type. */ + DBGFBPTYPE enmType; + +#if GC_ARCH_BITS == 64 + uint32_t u32Padding; +#endif + + /** Union of type specific data. */ + union + { + /** Debug register data. */ + struct DBGFBPREG + { + /** The debug register number. */ + uint8_t iReg; + /** The access type (one of the X86_DR7_RW_* value). */ + uint8_t fType; + /** The access size. */ + uint8_t cb; + } Reg; + /** Recompiler breakpoint data. */ + struct DBGFBPINT3 + { + /** The byte value we replaced by the INT 3 instruction. */ + uint8_t bOrg; + } Int3; + + /** Recompiler breakpoint data. */ + struct DBGFBPREM + { + /** nothing yet */ + uint8_t fDummy; + } Rem; + /** Paddind to ensure that the size is identical on win32 and linux. */ + uint64_t u64Padding; + } u; +} DBGFBP; + +/** Pointer to a breakpoint. */ +typedef DBGFBP *PDBGFBP; +/** Pointer to a const breakpoint. */ +typedef const DBGFBP *PCDBGFBP; + +#ifdef IN_RING3 /* The breakpoint management API is only available in ring-3. */ +VMMR3DECL(int) DBGFR3BpSet(PVM pVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable, uint32_t *piBp); +VMMR3DECL(int) DBGFR3BpSetReg(PVM pVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable, + uint8_t fType, uint8_t cb, uint32_t *piBp); +VMMR3DECL(int) DBGFR3BpSetREM(PVM pVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, uint64_t iHitDisable, uint32_t *piBp); +VMMR3DECL(int) DBGFR3BpClear(PVM pVM, uint32_t iBp); +VMMR3DECL(int) DBGFR3BpEnable(PVM pVM, uint32_t iBp); +VMMR3DECL(int) DBGFR3BpDisable(PVM pVM, uint32_t iBp); + +/** + * Breakpoint enumeration callback function. + * + * @returns VBox status code. Any failure will stop the enumeration. + * @param pVM The VM handle. + * @param pvUser The user argument. + * @param pBp Pointer to the breakpoint information. (readonly) + */ +typedef DECLCALLBACK(int) FNDBGFBPENUM(PVM pVM, void *pvUser, PCDBGFBP pBp); +/** Pointer to a breakpoint enumeration callback function. */ +typedef FNDBGFBPENUM *PFNDBGFBPENUM; + +VMMR3DECL(int) DBGFR3BpEnum(PVM pVM, PFNDBGFBPENUM pfnCallback, void *pvUser); +#endif /* IN_RING3 */ + +VMMDECL(RTGCUINTREG) DBGFBpGetDR7(PVM pVM); +VMMDECL(RTGCUINTREG) DBGFBpGetDR0(PVM pVM); +VMMDECL(RTGCUINTREG) DBGFBpGetDR1(PVM pVM); +VMMDECL(RTGCUINTREG) DBGFBpGetDR2(PVM pVM); +VMMDECL(RTGCUINTREG) DBGFBpGetDR3(PVM pVM); +VMMDECL(bool) DBGFIsStepping(PVMCPU pVCpu); + + +#ifdef IN_RING3 /* The CPU mode API only works in ring-3. */ +VMMR3DECL(CPUMMODE) DBGFR3CpuGetMode(PVM pVM, VMCPUID idCpu); +#endif + + + +#ifdef IN_RING3 /* The info callbacks API only works in ring-3. */ + +/** + * Info helper callback structure. + */ +typedef struct DBGFINFOHLP +{ + /** + * Print formatted string. + * + * @param pHlp Pointer to this structure. + * @param pszFormat The format string. + * @param ... Arguments. + */ + DECLCALLBACKMEMBER(void, pfnPrintf)(PCDBGFINFOHLP pHlp, const char *pszFormat, ...); + + /** + * Print formatted string. + * + * @param pHlp Pointer to this structure. + * @param pszFormat The format string. + * @param args Argument list. + */ + DECLCALLBACKMEMBER(void, pfnPrintfV)(PCDBGFINFOHLP pHlp, const char *pszFormat, va_list args); +} DBGFINFOHLP; + + +/** + * Info handler, device version. + * + * @param pDevIns The device instance which registered the info. + * @param pHlp Callback functions for doing output. + * @param pszArgs Argument string. Optional and specific to the handler. + */ +typedef DECLCALLBACK(void) FNDBGFHANDLERDEV(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs); +/** Pointer to a FNDBGFHANDLERDEV function. */ +typedef FNDBGFHANDLERDEV *PFNDBGFHANDLERDEV; + +/** + * Info handler, USB device version. + * + * @param pUsbIns The USB device instance which registered the info. + * @param pHlp Callback functions for doing output. + * @param pszArgs Argument string. Optional and specific to the handler. + */ +typedef DECLCALLBACK(void) FNDBGFHANDLERUSB(PPDMUSBINS pUsbIns, PCDBGFINFOHLP pHlp, const char *pszArgs); +/** Pointer to a FNDBGFHANDLERUSB function. */ +typedef FNDBGFHANDLERUSB *PFNDBGFHANDLERUSB; + +/** + * Info handler, driver version. + * + * @param pDrvIns The driver instance which registered the info. + * @param pHlp Callback functions for doing output. + * @param pszArgs Argument string. Optional and specific to the handler. + */ +typedef DECLCALLBACK(void) FNDBGFHANDLERDRV(PPDMDRVINS pDrvIns, PCDBGFINFOHLP pHlp, const char *pszArgs); +/** Pointer to a FNDBGFHANDLERDRV function. */ +typedef FNDBGFHANDLERDRV *PFNDBGFHANDLERDRV; + +/** + * Info handler, internal version. + * + * @param pVM The VM handle. + * @param pHlp Callback functions for doing output. + * @param pszArgs Argument string. Optional and specific to the handler. + */ +typedef DECLCALLBACK(void) FNDBGFHANDLERINT(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs); +/** Pointer to a FNDBGFHANDLERINT function. */ +typedef FNDBGFHANDLERINT *PFNDBGFHANDLERINT; + +/** + * Info handler, external version. + * + * @param pvUser User argument. + * @param pHlp Callback functions for doing output. + * @param pszArgs Argument string. Optional and specific to the handler. + */ +typedef DECLCALLBACK(void) FNDBGFHANDLEREXT(void *pvUser, PCDBGFINFOHLP pHlp, const char *pszArgs); +/** Pointer to a FNDBGFHANDLEREXT function. */ +typedef FNDBGFHANDLEREXT *PFNDBGFHANDLEREXT; + + +/** @name Flags for the info registration functions. + * @{ */ +/** The handler must run on the EMT. */ +#define DBGFINFO_FLAGS_RUN_ON_EMT RT_BIT(0) +/** @} */ + +VMMR3DECL(int) DBGFR3InfoRegisterDevice(PVM pVM, const char *pszName, const char *pszDesc, PFNDBGFHANDLERDEV pfnHandler, PPDMDEVINS pDevIns); +VMMR3DECL(int) DBGFR3InfoRegisterDriver(PVM pVM, const char *pszName, const char *pszDesc, PFNDBGFHANDLERDRV pfnHandler, PPDMDRVINS pDrvIns); +VMMR3DECL(int) DBGFR3InfoRegisterInternal(PVM pVM, const char *pszName, const char *pszDesc, PFNDBGFHANDLERINT pfnHandler); +VMMR3DECL(int) DBGFR3InfoRegisterInternalEx(PVM pVM, const char *pszName, const char *pszDesc, PFNDBGFHANDLERINT pfnHandler, uint32_t fFlags); +VMMR3DECL(int) DBGFR3InfoRegisterExternal(PVM pVM, const char *pszName, const char *pszDesc, PFNDBGFHANDLEREXT pfnHandler, void *pvUser); +VMMR3DECL(int) DBGFR3InfoDeregisterDevice(PVM pVM, PPDMDEVINS pDevIns, const char *pszName); +VMMR3DECL(int) DBGFR3InfoDeregisterDriver(PVM pVM, PPDMDRVINS pDrvIns, const char *pszName); +VMMR3DECL(int) DBGFR3InfoDeregisterInternal(PVM pVM, const char *pszName); +VMMR3DECL(int) DBGFR3InfoDeregisterExternal(PVM pVM, const char *pszName); +VMMR3DECL(int) DBGFR3Info(PVM pVM, const char *pszName, const char *pszArgs, PCDBGFINFOHLP pHlp); +VMMR3DECL(int) DBGFR3InfoEx(PVM pVM, VMCPUID idCpu, const char *pszName, const char *pszArgs, PCDBGFINFOHLP pHlp); +VMMR3DECL(int) DBGFR3InfoLogRel(PVM pVM, const char *pszName, const char *pszArgs); +VMMR3DECL(int) DBGFR3InfoStdErr(PVM pVM, const char *pszName, const char *pszArgs); +VMMR3DECL(int) DBGFR3InfoMulti(PVM pVM, const char *pszIncludePat, const char *pszExcludePat, + const char *pszSepFmt, PCDBGFINFOHLP pHlp); + +/** @def DBGFR3InfoLog + * Display a piece of info writing to the log if enabled. + * + * @param pVM VM handle. + * @param pszName The identifier of the info to display. + * @param pszArgs Arguments to the info handler. + */ +#ifdef LOG_ENABLED +#define DBGFR3InfoLog(pVM, pszName, pszArgs) \ + do { \ + if (LogIsEnabled()) \ + DBGFR3Info(pVM, pszName, pszArgs, NULL); \ + } while (0) +#else +#define DBGFR3InfoLog(pVM, pszName, pszArgs) do { } while (0) +#endif + +/** + * Enumeration callback for use with DBGFR3InfoEnum. + * + * @returns VBox status code. + * A status code indicating failure will end the enumeration + * and DBGFR3InfoEnum will return with that status code. + * @param pVM VM handle. + * @param pszName Info identifier name. + * @param pszDesc The description. + */ +typedef DECLCALLBACK(int) FNDBGFINFOENUM(PVM pVM, const char *pszName, const char *pszDesc, void *pvUser); +/** Pointer to a FNDBGFINFOENUM function. */ +typedef FNDBGFINFOENUM *PFNDBGFINFOENUM; + +VMMR3DECL(int) DBGFR3InfoEnum(PVM pVM, PFNDBGFINFOENUM pfnCallback, void *pvUser); +VMMR3DECL(PCDBGFINFOHLP) DBGFR3InfoLogHlp(void); +VMMR3DECL(PCDBGFINFOHLP) DBGFR3InfoLogRelHlp(void); + +#endif /* IN_RING3 */ + + +#ifdef IN_RING3 /* The log contrl API only works in ring-3. */ +VMMR3DECL(int) DBGFR3LogModifyGroups(PVM pVM, const char *pszGroupSettings); +VMMR3DECL(int) DBGFR3LogModifyFlags(PVM pVM, const char *pszFlagSettings); +VMMR3DECL(int) DBGFR3LogModifyDestinations(PVM pVM, const char *pszDestSettings); +#endif /* IN_RING3 */ + +#ifdef IN_RING3 /* The debug information management APIs only works in ring-3. */ + +/** Max length (including '\\0') of a symbol name. */ +#define DBGF_SYMBOL_NAME_LENGTH 512 + +/** + * Debug symbol. + */ +typedef struct DBGFSYMBOL +{ + /** Symbol value (address). */ + RTGCUINTPTR Value; + /** Symbol size. */ + uint32_t cb; + /** Symbol Flags. (reserved). */ + uint32_t fFlags; + /** Symbol name. */ + char szName[DBGF_SYMBOL_NAME_LENGTH]; +} DBGFSYMBOL; +/** Pointer to debug symbol. */ +typedef DBGFSYMBOL *PDBGFSYMBOL; +/** Pointer to const debug symbol. */ +typedef const DBGFSYMBOL *PCDBGFSYMBOL; + +/** + * Debug line number information. + */ +typedef struct DBGFLINE +{ + /** Address. */ + RTGCUINTPTR Address; + /** Line number. */ + uint32_t uLineNo; + /** Filename. */ + char szFilename[260]; +} DBGFLINE; +/** Pointer to debug line number. */ +typedef DBGFLINE *PDBGFLINE; +/** Pointer to const debug line number. */ +typedef const DBGFLINE *PCDBGFLINE; + +/** @name Address spaces aliases. + * @{ */ +/** The guest global address space. */ +#define DBGF_AS_GLOBAL ((RTDBGAS)-1) +/** The guest kernel address space. + * This is usually resolves to the same as DBGF_AS_GLOBAL. */ +#define DBGF_AS_KERNEL ((RTDBGAS)-2) +/** The physical address space. */ +#define DBGF_AS_PHYS ((RTDBGAS)-3) +/** Raw-mode context. */ +#define DBGF_AS_RC ((RTDBGAS)-4) +/** Ring-0 context. */ +#define DBGF_AS_R0 ((RTDBGAS)-5) +/** Raw-mode context and then global guest context. + * When used for looking up information, it works as if the call was first made + * with DBGF_AS_RC and then on failure with DBGF_AS_GLOBAL. When called for + * making address space changes, it works as if DBGF_AS_RC was used. */ +#define DBGF_AS_RC_AND_GC_GLOBAL ((RTDBGAS)-6) + +/** The first special one. */ +#define DBGF_AS_FIRST DBGF_AS_RC_AND_GC_GLOBAL +/** The last special one. */ +#define DBGF_AS_LAST DBGF_AS_GLOBAL +#endif +/** The number of special address space handles. */ +#define DBGF_AS_COUNT (6U) +#ifdef IN_RING3 +/** Converts an alias handle to an array index. */ +#define DBGF_AS_ALIAS_2_INDEX(hAlias) \ + ( (uintptr_t)(hAlias) - (uintptr_t)DBGF_AS_FIRST ) +/** Predicat macro that check if the specified handle is an alias. */ +#define DBGF_AS_IS_ALIAS(hAlias) \ + ( DBGF_AS_ALIAS_2_INDEX(hAlias) < DBGF_AS_COUNT ) +/** Predicat macro that check if the specified alias is a fixed one or not. */ +#define DBGF_AS_IS_FIXED_ALIAS(hAlias) \ + ( DBGF_AS_ALIAS_2_INDEX(hAlias) < (uintptr_t)DBGF_AS_PHYS - (uintptr_t)DBGF_AS_FIRST + 1U ) + +/** @} */ + +VMMR3DECL(int) DBGFR3AsAdd(PVM pVM, RTDBGAS hDbgAs, RTPROCESS ProcId); +VMMR3DECL(int) DBGFR3AsDelete(PVM pVM, RTDBGAS hDbgAs); +VMMR3DECL(int) DBGFR3AsSetAlias(PVM pVM, RTDBGAS hAlias, RTDBGAS hAliasFor); +VMMR3DECL(RTDBGAS) DBGFR3AsResolve(PVM pVM, RTDBGAS hAlias); +VMMR3DECL(RTDBGAS) DBGFR3AsResolveAndRetain(PVM pVM, RTDBGAS hAlias); +VMMR3DECL(RTDBGAS) DBGFR3AsQueryByName(PVM pVM, const char *pszName); +VMMR3DECL(RTDBGAS) DBGFR3AsQueryByPid(PVM pVM, RTPROCESS ProcId); + +VMMR3DECL(int) DBGFR3AsLoadImage(PVM pVM, RTDBGAS hDbgAs, const char *pszFilename, const char *pszModName, PCDBGFADDRESS pModAddress, RTDBGSEGIDX iModSeg, uint32_t fFlags); +VMMR3DECL(int) DBGFR3AsLoadMap(PVM pVM, RTDBGAS hDbgAs, const char *pszFilename, const char *pszModName, PCDBGFADDRESS pModAddress, RTDBGSEGIDX iModSeg, RTGCUINTPTR uSubtrahend, uint32_t fFlags); +VMMR3DECL(int) DBGFR3AsLinkModule(PVM pVM, RTDBGAS hDbgAs, RTDBGMOD hMod, PCDBGFADDRESS pModAddress, RTDBGSEGIDX iModSeg, uint32_t fFlags); + +VMMR3DECL(int) DBGFR3AsSymbolByAddr(PVM pVM, RTDBGAS hDbgAs, PCDBGFADDRESS pAddress, PRTGCINTPTR poffDisp, PRTDBGSYMBOL pSymbol, PRTDBGMOD phMod); +VMMR3DECL(PRTDBGSYMBOL) DBGFR3AsSymbolByAddrA(PVM pVM, RTDBGAS hDbgAs, PCDBGFADDRESS pAddress, PRTGCINTPTR poffDisp, PRTDBGMOD phMod); +VMMR3DECL(int) DBGFR3AsSymbolByName(PVM pVM, RTDBGAS hDbgAs, const char *pszSymbol, PRTDBGSYMBOL pSymbol, PRTDBGMOD phMod); + +/* The following are soon to be obsoleted: */ +VMMR3DECL(int) DBGFR3ModuleLoad(PVM pVM, const char *pszFilename, RTGCUINTPTR AddressDelta, const char *pszName, RTGCUINTPTR ModuleAddress, unsigned cbImage); +VMMR3DECL(void) DBGFR3ModuleRelocate(PVM pVM, RTGCUINTPTR OldImageBase, RTGCUINTPTR NewImageBase, RTGCUINTPTR cbImage, + const char *pszFilename, const char *pszName); +VMMR3DECL(int) DBGFR3SymbolAdd(PVM pVM, RTGCUINTPTR ModuleAddress, RTGCUINTPTR SymbolAddress, RTUINT cbSymbol, const char *pszSymbol); +VMMR3DECL(int) DBGFR3SymbolByAddr(PVM pVM, RTGCUINTPTR Address, PRTGCINTPTR poffDisplacement, PDBGFSYMBOL pSymbol); +VMMR3DECL(int) DBGFR3SymbolByName(PVM pVM, const char *pszSymbol, PDBGFSYMBOL pSymbol); + +VMMR3DECL(int) DBGFR3LineByAddr(PVM pVM, RTGCUINTPTR Address, PRTGCINTPTR poffDisplacement, PDBGFLINE pLine); +VMMR3DECL(PDBGFLINE) DBGFR3LineByAddrAlloc(PVM pVM, RTGCUINTPTR Address, PRTGCINTPTR poffDisplacement); +VMMR3DECL(void) DBGFR3LineFree(PDBGFLINE pLine); + +#endif /* IN_RING3 */ + +#ifdef IN_RING3 /* The stack API only works in ring-3. */ + +/** + * Return type. + */ +typedef enum DBGFRETRUNTYPE +{ + /** The usual invalid 0 value. */ + DBGFRETURNTYPE_INVALID = 0, + /** Near 16-bit return. */ + DBGFRETURNTYPE_NEAR16, + /** Near 32-bit return. */ + DBGFRETURNTYPE_NEAR32, + /** Near 64-bit return. */ + DBGFRETURNTYPE_NEAR64, + /** Far 16:16 return. */ + DBGFRETURNTYPE_FAR16, + /** Far 16:32 return. */ + DBGFRETURNTYPE_FAR32, + /** Far 16:64 return. */ + DBGFRETURNTYPE_FAR64, + /** 16-bit iret return (e.g. real or 286 protect mode). */ + DBGFRETURNTYPE_IRET16, + /** 32-bit iret return. */ + DBGFRETURNTYPE_IRET32, + /** 32-bit iret return. */ + DBGFRETURNTYPE_IRET32_PRIV, + /** 32-bit iret return to V86 mode. */ + DBGFRETURNTYPE_IRET32_V86, + /** @todo 64-bit iret return. */ + DBGFRETURNTYPE_IRET64, + /** The end of the valid return types. */ + DBGFRETURNTYPE_END, + /** The usual 32-bit blowup. */ + DBGFRETURNTYPE_32BIT_HACK = 0x7fffffff +} DBGFRETURNTYPE; + +/** + * Figures the size of the return state on the stack. + * + * @returns number of bytes. 0 if invalid parameter. + * @param enmRetType The type of return. + */ +DECLINLINE(unsigned) DBGFReturnTypeSize(DBGFRETURNTYPE enmRetType) +{ + switch (enmRetType) + { + case DBGFRETURNTYPE_NEAR16: return 2; + case DBGFRETURNTYPE_NEAR32: return 4; + case DBGFRETURNTYPE_NEAR64: return 8; + case DBGFRETURNTYPE_FAR16: return 4; + case DBGFRETURNTYPE_FAR32: return 4; + case DBGFRETURNTYPE_FAR64: return 8; + case DBGFRETURNTYPE_IRET16: return 6; + case DBGFRETURNTYPE_IRET32: return 4*3; + case DBGFRETURNTYPE_IRET32_PRIV: return 4*5; + case DBGFRETURNTYPE_IRET32_V86: return 4*9; + case DBGFRETURNTYPE_IRET64: + default: + return 0; + } +} + + +/** Pointer to stack frame info. */ +typedef struct DBGFSTACKFRAME *PDBGFSTACKFRAME; +/** Pointer to const stack frame info. */ +typedef struct DBGFSTACKFRAME const *PCDBGFSTACKFRAME; +/** + * Info about a stack frame. + */ +typedef struct DBGFSTACKFRAME +{ + /** Frame number. */ + uint32_t iFrame; + /** Frame flags. */ + uint32_t fFlags; + /** The frame address. + * The off member is [e|r]bp and the Sel member is ss. */ + DBGFADDRESS AddrFrame; + /** The stack address of the frame. + * The off member is [e|r]sp and the Sel member is ss. */ + DBGFADDRESS AddrStack; + /** The program counter (PC) address of the frame. + * The off member is [e|r]ip and the Sel member is cs. */ + DBGFADDRESS AddrPC; + /** Pointer to the symbol nearest the program counter (PC). NULL if not found. */ + PRTDBGSYMBOL pSymPC; + /** Pointer to the linnumber nearest the program counter (PC). NULL if not found. */ + PDBGFLINE pLinePC; + + /** The return frame address. + * The off member is [e|r]bp and the Sel member is ss. */ + DBGFADDRESS AddrReturnFrame; + /** The return stack address. + * The off member is [e|r]sp and the Sel member is ss. */ + DBGFADDRESS AddrReturnStack; + /** The way this frame returns to the next one. */ + DBGFRETURNTYPE enmReturnType; + + /** The program counter (PC) address which the frame returns to. + * The off member is [e|r]ip and the Sel member is cs. */ + DBGFADDRESS AddrReturnPC; + /** Pointer to the symbol nearest the return PC. NULL if not found. */ + PRTDBGSYMBOL pSymReturnPC; + /** Pointer to the linnumber nearest the return PC. NULL if not found. */ + PDBGFLINE pLineReturnPC; + + /** 32-bytes of stack arguments. */ + union + { + /** 64-bit view */ + uint64_t au64[4]; + /** 32-bit view */ + uint32_t au32[8]; + /** 16-bit view */ + uint16_t au16[16]; + /** 8-bit view */ + uint8_t au8[32]; + } Args; + + /** Pointer to the next frame. + * Might not be used in some cases, so consider it internal. */ + PCDBGFSTACKFRAME pNextInternal; + /** Pointer to the first frame. + * Might not be used in some cases, so consider it internal. */ + PCDBGFSTACKFRAME pFirstInternal; +} DBGFSTACKFRAME; + +/** @name DBGFSTACKFRAME Flags. + * @{ */ +/** Set if the content of the frame is filled in by DBGFR3StackWalk() and can be used + * to construct the next frame. */ +# define DBGFSTACKFRAME_FLAGS_ALL_VALID RT_BIT(0) +/** This is the last stack frame we can read. + * This flag is not set if the walk stop because of max dept or recursion. */ +# define DBGFSTACKFRAME_FLAGS_LAST RT_BIT(1) +/** This is the last record because we detected a loop. */ +# define DBGFSTACKFRAME_FLAGS_LOOP RT_BIT(2) +/** This is the last record because we reached the maximum depth. */ +# define DBGFSTACKFRAME_FLAGS_MAX_DEPTH RT_BIT(3) +/** 16-bit frame. */ +# define DBGFSTACKFRAME_FLAGS_16BIT RT_BIT(4) +/** 32-bit frame. */ +# define DBGFSTACKFRAME_FLAGS_32BIT RT_BIT(5) +/** 64-bit frame. */ +# define DBGFSTACKFRAME_FLAGS_64BIT RT_BIT(6) +/** @} */ + +/** @name DBGFCODETYPE + * @{ */ +typedef enum DBGFCODETYPE +{ + /** The usual invalid 0 value. */ + DBGFCODETYPE_INVALID = 0, + /** Stack walk for guest code. */ + DBGFCODETYPE_GUEST, + /** Stack walk for hypervisor code. */ + DBGFCODETYPE_HYPER, + /** Stack walk for ring 0 code. */ + DBGFCODETYPE_RING0, + /** The usual 32-bit blowup. */ + DBGFCODETYPE_32BIT_HACK = 0x7fffffff +} DBGFCODETYPE; +/** @} */ + +VMMR3DECL(int) DBGFR3StackWalkBegin(PVM pVM, VMCPUID idCpu, DBGFCODETYPE enmCodeType, PCDBGFSTACKFRAME *ppFirstFrame); +VMMR3DECL(int) DBGFR3StackWalkBeginEx(PVM pVM, VMCPUID idCpu, DBGFCODETYPE enmCodeType, PCDBGFADDRESS pAddrFrame, + PCDBGFADDRESS pAddrStack,PCDBGFADDRESS pAddrPC, + DBGFRETURNTYPE enmReturnType, PCDBGFSTACKFRAME *ppFirstFrame); +VMMR3DECL(PCDBGFSTACKFRAME) DBGFR3StackWalkNext(PCDBGFSTACKFRAME pCurrent); +VMMR3DECL(void) DBGFR3StackWalkEnd(PCDBGFSTACKFRAME pFirstFrame); + +#endif /* IN_RING3 */ + + +#ifdef IN_RING3 /* The disassembly API only works in ring-3. */ + +/** Flags to pass to DBGFR3DisasInstrEx(). + * @{ */ +/** Disassemble the current guest instruction, with annotations. */ +#define DBGF_DISAS_FLAGS_CURRENT_GUEST RT_BIT(0) +/** Disassemble the current hypervisor instruction, with annotations. */ +#define DBGF_DISAS_FLAGS_CURRENT_HYPER RT_BIT(1) +/** No annotations for current context. */ +#define DBGF_DISAS_FLAGS_NO_ANNOTATION RT_BIT(2) +/** No symbol lookup. */ +#define DBGF_DISAS_FLAGS_NO_SYMBOLS RT_BIT(3) +/** No instruction bytes. */ +#define DBGF_DISAS_FLAGS_NO_BYTES RT_BIT(4) +/** No address in the output. */ +#define DBGF_DISAS_FLAGS_NO_ADDRESS RT_BIT(5) +/** Disassemble in the default mode of the specific context. */ +#define DBGF_DISAS_FLAGS_DEFAULT_MODE UINT32_C(0x00000000) +/** Disassemble in 16-bit mode. */ +#define DBGF_DISAS_FLAGS_16BIT_MODE UINT32_C(0x10000000) +/** Disassemble in 16-bit mode with real mode address translation. */ +#define DBGF_DISAS_FLAGS_16BIT_REAL_MODE UINT32_C(0x20000000) +/** Disassemble in 32-bit mode. */ +#define DBGF_DISAS_FLAGS_32BIT_MODE UINT32_C(0x30000000) +/** Disassemble in 64-bit mode. */ +#define DBGF_DISAS_FLAGS_64BIT_MODE UINT32_C(0x40000000) +/** The disassembly mode mask. */ +#define DBGF_DISAS_FLAGS_MODE_MASK UINT32_C(0x70000000) +/** Mask containing the valid flags. */ +#define DBGF_DISAS_FLAGS_VALID_MASK UINT32_C(0x7000007f) +/** @} */ + +/** Special flat selector. */ +#define DBGF_SEL_FLAT 1 + +VMMR3DECL(int) DBGFR3DisasInstrEx(PVM pVM, VMCPUID idCpu, RTSEL Sel, RTGCPTR GCPtr, uint32_t fFlags, + char *pszOutput, uint32_t cbOutput, uint32_t *pcbInstr); +VMMR3DECL(int) DBGFR3DisasInstrCurrent(PVMCPU pVCpu, char *pszOutput, uint32_t cbOutput); +VMMR3DECL(int) DBGFR3DisasInstrCurrentLogInternal(PVMCPU pVCpu, const char *pszPrefix); + +/** @def DBGFR3DisasInstrCurrentLog + * Disassembles the current guest context instruction and writes it to the log. + * All registers and data will be displayed. Addresses will be attempted resolved to symbols. + */ +#ifdef LOG_ENABLED +# define DBGFR3DisasInstrCurrentLog(pVCpu, pszPrefix) \ + do { \ + if (LogIsEnabled()) \ + DBGFR3DisasInstrCurrentLogInternal(pVCpu, pszPrefix); \ + } while (0) +#else +# define DBGFR3DisasInstrCurrentLog(pVCpu, pszPrefix) do { } while (0) +#endif + +VMMR3DECL(int) DBGFR3DisasInstrLogInternal(PVMCPU pVCpu, RTSEL Sel, RTGCPTR GCPtr, const char *pszPrefix); + +/** @def DBGFR3DisasInstrLog + * Disassembles the specified guest context instruction and writes it to the log. + * Addresses will be attempted resolved to symbols. + * @thread Any EMT. + */ +# ifdef LOG_ENABLED +# define DBGFR3DisasInstrLog(pVCpu, Sel, GCPtr, pszPrefix) \ + do { \ + if (LogIsEnabled()) \ + DBGFR3DisasInstrLogInternal(pVCpu, Sel, GCPtr, pszPrefix); \ + } while (0) +# else +# define DBGFR3DisasInstrLog(pVCpu, Sel, GCPtr, pszPrefix) do { } while (0) +# endif +#endif + + +#ifdef IN_RING3 +VMMR3DECL(int) DBGFR3MemScan(PVM pVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, RTGCUINTPTR cbRange, RTGCUINTPTR uAlign, + const void *pvNeedle, size_t cbNeedle, PDBGFADDRESS pHitAddress); +VMMR3DECL(int) DBGFR3MemRead(PVM pVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, void *pvBuf, size_t cbRead); +VMMR3DECL(int) DBGFR3MemReadString(PVM pVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, char *pszBuf, size_t cbBuf); +VMMR3DECL(int) DBGFR3MemWrite(PVM pVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, void const *pvBuf, size_t cbRead); +#endif + + +/** @name Flags for DBGFR3PagingDumpEx, PGMR3DumpHierarchyHCEx and + * PGMR3DumpHierarchyGCEx + * @{ */ +/** The CR3 from the current CPU state. */ +#define DBGFPGDMP_FLAGS_CURRENT_CR3 RT_BIT_32(0) +/** The current CPU paging mode (PSE, PAE, LM, EPT, NX). */ +#define DBGFPGDMP_FLAGS_CURRENT_MODE RT_BIT_32(1) +/** Whether PSE is enabled (!DBGFPGDMP_FLAGS_CURRENT_STATE). + * Same value as X86_CR4_PSE. */ +#define DBGFPGDMP_FLAGS_PSE RT_BIT_32(4) /* */ +/** Whether PAE is enabled (!DBGFPGDMP_FLAGS_CURRENT_STATE). + * Same value as X86_CR4_PAE. */ +#define DBGFPGDMP_FLAGS_PAE RT_BIT_32(5) /* */ +/** Whether LME is enabled (!DBGFPGDMP_FLAGS_CURRENT_STATE). + * Same value as MSR_K6_EFER_LME. */ +#define DBGFPGDMP_FLAGS_LME RT_BIT_32(8) +/** Whether nested paging is enabled (!DBGFPGDMP_FLAGS_CURRENT_STATE). */ +#define DBGFPGDMP_FLAGS_NP RT_BIT_32(9) +/** Whether extended nested page tables are enabled + * (!DBGFPGDMP_FLAGS_CURRENT_STATE). */ +#define DBGFPGDMP_FLAGS_EPT RT_BIT_32(10) +/** Whether no-execution is enabled (!DBGFPGDMP_FLAGS_CURRENT_STATE). + * Same value as MSR_K6_EFER_NXE. */ +#define DBGFPGDMP_FLAGS_NXE RT_BIT_32(11) +/** Whether to print the CR3. */ +#define DBGFPGDMP_FLAGS_PRINT_CR3 RT_BIT_32(27) +/** Whether to print the header. */ +#define DBGFPGDMP_FLAGS_HEADER RT_BIT_32(28) +/** Whether to dump additional page information. */ +#define DBGFPGDMP_FLAGS_PAGE_INFO RT_BIT_32(29) +/** Dump the shadow tables if set. + * Cannot be used together with DBGFPGDMP_FLAGS_GUEST. */ +#define DBGFPGDMP_FLAGS_SHADOW RT_BIT_32(30) +/** Dump the guest tables if set. + * Cannot be used together with DBGFPGDMP_FLAGS_SHADOW. */ +#define DBGFPGDMP_FLAGS_GUEST RT_BIT_32(31) +/** Mask of valid bits. */ +#define DBGFPGDMP_FLAGS_VALID_MASK UINT32_C(0xf8000f33) +/** The mask of bits controlling the paging mode. */ +#define DBGFPGDMP_FLAGS_MODE_MASK UINT32_C(0x00000f32) +/** @} */ +VMMDECL(int) DBGFR3PagingDumpEx(PVM pVM, VMCPUID idCpu, uint32_t fFlags, uint64_t cr3, uint64_t u64FirstAddr, + uint64_t u64LastAddr, uint32_t cMaxDepth, PCDBGFINFOHLP pHlp); + + +/** @name DBGFR3SelQueryInfo flags. + * @{ */ +/** Get the info from the guest descriptor table. */ +#define DBGFSELQI_FLAGS_DT_GUEST UINT32_C(0) +/** Get the info from the shadow descriptor table. + * Only works in raw-mode. */ +#define DBGFSELQI_FLAGS_DT_SHADOW UINT32_C(1) +/** If currently executing in in 64-bit mode, blow up data selectors. */ +#define DBGFSELQI_FLAGS_DT_ADJ_64BIT_MODE UINT32_C(2) +/** @} */ +VMMR3DECL(int) DBGFR3SelQueryInfo(PVM pVM, VMCPUID idCpu, RTSEL Sel, uint32_t fFlags, PDBGFSELINFO pSelInfo); + + +/** + * Register identifiers. + */ +typedef enum DBGFREG +{ + /* General purpose registers: */ + DBGFREG_AL = 0, + DBGFREG_AX = DBGFREG_AL, + DBGFREG_EAX = DBGFREG_AL, + DBGFREG_RAX = DBGFREG_AL, + + DBGFREG_CL, + DBGFREG_CX = DBGFREG_CL, + DBGFREG_ECX = DBGFREG_CL, + DBGFREG_RCX = DBGFREG_CL, + + DBGFREG_DL, + DBGFREG_DX = DBGFREG_DL, + DBGFREG_EDX = DBGFREG_DL, + DBGFREG_RDX = DBGFREG_DL, + + DBGFREG_BL, + DBGFREG_BX = DBGFREG_BL, + DBGFREG_EBX = DBGFREG_BL, + DBGFREG_RBX = DBGFREG_BL, + + DBGFREG_SPL, + DBGFREG_SP = DBGFREG_SPL, + DBGFREG_ESP = DBGFREG_SPL, + DBGFREG_RSP = DBGFREG_SPL, + + DBGFREG_BPL, + DBGFREG_BP = DBGFREG_BPL, + DBGFREG_EBP = DBGFREG_BPL, + DBGFREG_RBP = DBGFREG_BPL, + + DBGFREG_SIL, + DBGFREG_SI = DBGFREG_SIL, + DBGFREG_ESI = DBGFREG_SIL, + DBGFREG_RSI = DBGFREG_SIL, + + DBGFREG_DIL, + DBGFREG_DI = DBGFREG_DIL, + DBGFREG_EDI = DBGFREG_DIL, + DBGFREG_RDI = DBGFREG_DIL, + + DBGFREG_R8, + DBGFREG_R8B = DBGFREG_R8, + DBGFREG_R8W = DBGFREG_R8, + DBGFREG_R8D = DBGFREG_R8, + + DBGFREG_R9, + DBGFREG_R9B = DBGFREG_R9, + DBGFREG_R9W = DBGFREG_R9, + DBGFREG_R9D = DBGFREG_R9, + + DBGFREG_R10, + DBGFREG_R10B = DBGFREG_R10, + DBGFREG_R10W = DBGFREG_R10, + DBGFREG_R10D = DBGFREG_R10, + + DBGFREG_R11, + DBGFREG_R11B = DBGFREG_R11, + DBGFREG_R11W = DBGFREG_R11, + DBGFREG_R11D = DBGFREG_R11, + + DBGFREG_R12, + DBGFREG_R12B = DBGFREG_R12, + DBGFREG_R12W = DBGFREG_R12, + DBGFREG_R12D = DBGFREG_R12, + + DBGFREG_R13, + DBGFREG_R13B = DBGFREG_R13, + DBGFREG_R13W = DBGFREG_R13, + DBGFREG_R13D = DBGFREG_R13, + + DBGFREG_R14, + DBGFREG_R14B = DBGFREG_R14, + DBGFREG_R14W = DBGFREG_R14, + DBGFREG_R14D = DBGFREG_R14, + + DBGFREG_R15, + DBGFREG_R15B = DBGFREG_R15, + DBGFREG_R15W = DBGFREG_R15, + DBGFREG_R15D = DBGFREG_R15, + + /* Segments and other special registers: */ + DBGFREG_CS, + DBGFREG_CS_ATTR, + DBGFREG_CS_BASE, + DBGFREG_CS_LIMIT, + + DBGFREG_DS, + DBGFREG_DS_ATTR, + DBGFREG_DS_BASE, + DBGFREG_DS_LIMIT, + + DBGFREG_ES, + DBGFREG_ES_ATTR, + DBGFREG_ES_BASE, + DBGFREG_ES_LIMIT, + + DBGFREG_FS, + DBGFREG_FS_ATTR, + DBGFREG_FS_BASE, + DBGFREG_FS_LIMIT, + + DBGFREG_GS, + DBGFREG_GS_ATTR, + DBGFREG_GS_BASE, + DBGFREG_GS_LIMIT, + + DBGFREG_SS, + DBGFREG_SS_ATTR, + DBGFREG_SS_BASE, + DBGFREG_SS_LIMIT, + + DBGFREG_IP, + DBGFREG_EIP = DBGFREG_IP, + DBGFREG_RIP = DBGFREG_IP, + + DBGFREG_FLAGS, + DBGFREG_EFLAGS = DBGFREG_FLAGS, + DBGFREG_RFLAGS = DBGFREG_FLAGS, + + /* FPU: */ + DBGFREG_FCW, + DBGFREG_FSW, + DBGFREG_FTW, + DBGFREG_FOP, + DBGFREG_FPUIP, + DBGFREG_FPUCS, + DBGFREG_FPUDP, + DBGFREG_FPUDS, + DBGFREG_MXCSR, + DBGFREG_MXCSR_MASK, + + DBGFREG_ST0, + DBGFREG_ST1, + DBGFREG_ST2, + DBGFREG_ST3, + DBGFREG_ST4, + DBGFREG_ST5, + DBGFREG_ST6, + DBGFREG_ST7, + + DBGFREG_MM0, + DBGFREG_MM1, + DBGFREG_MM2, + DBGFREG_MM3, + DBGFREG_MM4, + DBGFREG_MM5, + DBGFREG_MM6, + DBGFREG_MM7, + + /* SSE: */ + DBGFREG_XMM0, + DBGFREG_XMM1, + DBGFREG_XMM2, + DBGFREG_XMM3, + DBGFREG_XMM4, + DBGFREG_XMM5, + DBGFREG_XMM6, + DBGFREG_XMM7, + DBGFREG_XMM8, + DBGFREG_XMM9, + DBGFREG_XMM10, + DBGFREG_XMM11, + DBGFREG_XMM12, + DBGFREG_XMM13, + DBGFREG_XMM14, + DBGFREG_XMM15, + /** @todo add XMM aliases. */ + + /* System registers: */ + DBGFREG_GDTR_BASE, + DBGFREG_GDTR_LIMIT, + DBGFREG_IDTR_BASE, + DBGFREG_IDTR_LIMIT, + DBGFREG_LDTR, + DBGFREG_LDTR_ATTR, + DBGFREG_LDTR_BASE, + DBGFREG_LDTR_LIMIT, + DBGFREG_TR, + DBGFREG_TR_ATTR, + DBGFREG_TR_BASE, + DBGFREG_TR_LIMIT, + + DBGFREG_CR0, + DBGFREG_CR2, + DBGFREG_CR3, + DBGFREG_CR4, + DBGFREG_CR8, + + DBGFREG_DR0, + DBGFREG_DR1, + DBGFREG_DR2, + DBGFREG_DR3, + DBGFREG_DR6, + DBGFREG_DR7, + + /* MSRs: */ + DBGFREG_MSR_IA32_APICBASE, + DBGFREG_MSR_IA32_CR_PAT, + DBGFREG_MSR_IA32_PERF_STATUS, + DBGFREG_MSR_IA32_SYSENTER_CS, + DBGFREG_MSR_IA32_SYSENTER_EIP, + DBGFREG_MSR_IA32_SYSENTER_ESP, + DBGFREG_MSR_IA32_TSC, + DBGFREG_MSR_K6_EFER, + DBGFREG_MSR_K6_STAR, + DBGFREG_MSR_K8_CSTAR, + DBGFREG_MSR_K8_FS_BASE, + DBGFREG_MSR_K8_GS_BASE, + DBGFREG_MSR_K8_KERNEL_GS_BASE, + DBGFREG_MSR_K8_LSTAR, + DBGFREG_MSR_K8_SF_MASK, + DBGFREG_MSR_K8_TSC_AUX, + + /** The number of registers to pass to DBGFR3RegQueryAll. */ + DBGFREG_ALL_COUNT, + + /* Misc aliases that doesn't need be part of the 'all' query: */ + DBGFREG_AH = DBGFREG_ALL_COUNT, + DBGFREG_CH, + DBGFREG_DH, + DBGFREG_BH, + DBGFREG_GDTR, + DBGFREG_IDTR, + + /** The end of the registers. */ + DBGFREG_END, + /** The usual 32-bit type hack. */ + DBGFREG_32BIT_HACK = 0x7fffffff +} DBGFREG; +/** Pointer to a register identifier. */ +typedef DBGFREG *PDBGFREG; +/** Pointer to a const register identifier. */ +typedef DBGFREG const *PCDBGFREG; + +/** + * Register value type. + */ +typedef enum DBGFREGVALTYPE +{ + DBGFREGVALTYPE_INVALID = 0, + /** Unsigned 8-bit register value. */ + DBGFREGVALTYPE_U8, + /** Unsigned 16-bit register value. */ + DBGFREGVALTYPE_U16, + /** Unsigned 32-bit register value. */ + DBGFREGVALTYPE_U32, + /** Unsigned 64-bit register value. */ + DBGFREGVALTYPE_U64, + /** Unsigned 128-bit register value. */ + DBGFREGVALTYPE_U128, + /** Long double register value. */ + DBGFREGVALTYPE_R80, + /** Descriptor table register value. */ + DBGFREGVALTYPE_DTR, + /** End of the valid register value types. */ + DBGFREGVALTYPE_END, + /** The usual 32-bit type hack. */ + DBGFREGVALTYPE_32BIT_HACK = 0x7fffffff +} DBGFREGVALTYPE; +/** Pointer to a register value type. */ +typedef DBGFREGVALTYPE *PDBGFREGVALTYPE; + +/** + * A generic register value type. + */ +typedef union DBGFREGVAL +{ + uint8_t u8; /**< The 8-bit view. */ + uint16_t u16; /**< The 16-bit view. */ + uint32_t u32; /**< The 32-bit view. */ + uint64_t u64; /**< The 64-bit view. */ + RTUINT128U u128; /**< The 128-bit view. */ + RTFLOAT80U r80; /**< The 80-bit floating point view. */ + RTFLOAT80U2 r80Ex; /**< The 80-bit floating point view v2. */ + /** GDTR or LDTR (DBGFREGVALTYPE_DTR). */ + struct + { + /** The table address. */ + uint64_t u64Base; + /** The table limit (length minus 1). */ + uint32_t u32Limit; + } dtr; + + uint8_t au8[16]; /**< The 8-bit array view. */ + uint16_t au16[8]; /**< The 16-bit array view. */ + uint32_t au32[4]; /**< The 32-bit array view. */ + uint64_t au64[2]; /**< The 64-bit array view. */ + RTUINT128U u; +} DBGFREGVAL; +/** Pointer to a generic register value type. */ +typedef DBGFREGVAL *PDBGFREGVAL; +/** Pointer to a const generic register value type. */ +typedef DBGFREGVAL const *PCDBGFREGVAL; + +VMMDECL(ssize_t) DBGFR3RegFormatValue(char *pszBuf, size_t cbBuf, PCDBGFREGVAL pValue, DBGFREGVALTYPE enmType, bool fSpecial); +VMMDECL(ssize_t) DBGFR3RegFormatValueEx(char *pszBuf, size_t cbBuf, PCDBGFREGVAL pValue, DBGFREGVALTYPE enmType, + unsigned uBase, signed int cchWidth, signed int cchPrecision, uint32_t fFlags); + +/** + * Register sub-field descriptor. + */ +typedef struct DBGFREGSUBFIELD +{ + /** The name of the sub-field. NULL is used to terminate the array. */ + const char *pszName; + /** The index of the first bit. Ignored if pfnGet is set. */ + uint8_t iFirstBit; + /** The number of bits. Mandatory. */ + uint8_t cBits; + /** The shift count. Not applied when pfnGet is set, but used to + * calculate the minimum type. */ + int8_t cShift; + /** Sub-field flags, DBGFREGSUBFIELD_FLAGS_XXX. */ + uint8_t fFlags; + /** Getter (optional). */ + DECLCALLBACKMEMBER(int, pfnGet)(void *pvUser, struct DBGFREGSUBFIELD const *pSubField, PRTUINT128U puValue); + /** Setter (optional). */ + DECLCALLBACKMEMBER(int, pfnSet)(void *pvUser, struct DBGFREGSUBFIELD const *pSubField, RTUINT128U uValue, RTUINT128U fMask); +} DBGFREGSUBFIELD; +/** Pointer to a const register sub-field descriptor. */ +typedef DBGFREGSUBFIELD const *PCDBGFREGSUBFIELD; + +/** @name DBGFREGSUBFIELD_FLAGS_XXX + * @{ */ +/** The sub-field is read-only. */ +#define DBGFREGSUBFIELD_FLAGS_READ_ONLY UINT8_C(0x01) +/** @} */ + +/** Macro for creating a read-write sub-field entry without getters. */ +#define DBGFREGSUBFIELD_RW(a_szName, a_iFirstBit, a_cBits, a_cShift) \ + { a_szName, a_iFirstBit, a_cBits, a_cShift, 0 /*fFlags*/, NULL /*pfnGet*/, NULL /*pfnSet*/ } +/** Macro for creating a read-write sub-field entry with getters. */ +#define DBGFREGSUBFIELD_RW_SG(a_szName, a_cBits, a_cShift, a_pfnGet, a_pfnSet) \ + { a_szName, 0 /*iFirstBit*/, a_cBits, a_cShift, 0 /*fFlags*/, a_pfnGet, a_pfnSet } +/** Macro for creating a terminator sub-field entry. */ +#define DBGFREGSUBFIELD_TERMINATOR() \ + { NULL, 0, 0, 0, 0, NULL, NULL } + +/** + * Register alias descriptor. + */ +typedef struct DBGFREGALIAS +{ + /** The alias name. NULL is used to terminate the array. */ + const char *pszName; + /** Set to a valid type if the alias has a different type. */ + DBGFREGVALTYPE enmType; +} DBGFREGALIAS; +/** Pointer to a const register alias descriptor. */ +typedef DBGFREGALIAS const *PCDBGFREGALIAS; + +/** + * Register descriptor. + */ +typedef struct DBGFREGDESC +{ + /** The normal register name. */ + const char *pszName; + /** The register identifier if this is a CPU register. */ + DBGFREG enmReg; + /** The default register type. */ + DBGFREGVALTYPE enmType; + /** Flags, see DBGFREG_FLAGS_XXX. */ + uint32_t fFlags; + /** The internal register indicator. + * For CPU registers this is the offset into the CPUMCTX structure, + * thuse the 'off' prefix. */ + uint32_t offRegister; + /** Getter. */ + DECLCALLBACKMEMBER(int, pfnGet)(void *pvUser, struct DBGFREGDESC const *pDesc, PDBGFREGVAL pValue); + /** Setter. */ + DECLCALLBACKMEMBER(int, pfnSet)(void *pvUser, struct DBGFREGDESC const *pDesc, PCDBGFREGVAL pValue, PCDBGFREGVAL pfMask); + /** Aliases (optional). */ + PCDBGFREGALIAS paAliases; + /** Sub fields (optional). */ + PCDBGFREGSUBFIELD paSubFields; +} DBGFREGDESC; + +/** @name Macros for constructing DBGFREGDESC arrays. + * @{ */ +#define DBGFREGDESC_RW(a_szName, a_TypeSuff, a_offRegister, a_pfnGet, a_pfnSet) \ + { a_szName, DBGFREG_END, DBGFREGVALTYPE_##a_TypeSuff, 0 /*fFlags*/, a_offRegister, a_pfnGet, a_pfnSet, NULL /*paAlises*/, NULL /*paSubFields*/ } +#define DBGFREGDESC_RO(a_szName, a_TypeSuff, a_offRegister, a_pfnGet, a_pfnSet) \ + { a_szName, DBGFREG_END, DBGFREGVALTYPE_##a_TypeSuff, DBGFREG_FLAGS_READ_ONLY, a_offRegister, a_pfnGet, a_pfnSet, NULL /*paAlises*/, NULL /*paSubFields*/ } +#define DBGFREGDESC_RW_A(a_szName, a_TypeSuff, a_offRegister, a_pfnGet, a_pfnSet, a_paAliases) \ + { a_szName, DBGFREG_END, DBGFREGVALTYPE_##a_TypeSuff, 0 /*fFlags*/, a_offRegister, a_pfnGet, a_pfnSet, a_paAliases, NULL /*paSubFields*/ } +#define DBGFREGDESC_RO_A(a_szName, a_TypeSuff, a_offRegister, a_pfnGet, a_pfnSet, a_paAliases) \ + { a_szName, DBGFREG_END, DBGFREGVALTYPE_##a_TypeSuff, DBGFREG_FLAGS_READ_ONLY, a_offRegister, a_pfnGet, a_pfnSet, a_paAliases, NULL /*paSubFields*/ } +#define DBGFREGDESC_RW_S(a_szName, a_TypeSuff, a_offRegister, a_pfnGet, a_pfnSet, a_paSubFields) \ + { a_szName, DBGFREG_END, DBGFREGVALTYPE_##a_TypeSuff, 0 /*fFlags*/, a_offRegister, a_pfnGet, a_pfnSet, /*paAliases*/, a_paSubFields } +#define DBGFREGDESC_RO_S(a_szName, a_TypeSuff, a_offRegister, a_pfnGet, a_pfnSet, a_paSubFields) \ + { a_szName, DBGFREG_END, DBGFREGVALTYPE_##a_TypeSuff, DBGFREG_FLAGS_READ_ONLY, a_offRegister, a_pfnGet, a_pfnSet, /*paAliases*/, a_paSubFields } +#define DBGFREGDESC_RW_AS(a_szName, a_TypeSuff, a_offRegister, a_pfnGet, a_pfnSet, a_paAliases, a_paSubFields) \ + { a_szName, DBGFREG_END, DBGFREGVALTYPE_##a_TypeSuff, 0 /*fFlags*/, a_offRegister, a_pfnGet, a_pfnSet, a_paAliases, a_paSubFields } +#define DBGFREGDESC_RO_AS(a_szName, a_TypeSuff, a_offRegister, a_pfnGet, a_pfnSet, a_paAliases, a_paSubFields) \ + { a_szName, DBGFREG_END, DBGFREGVALTYPE_##a_TypeSuff, DBGFREG_FLAGS_READ_ONLY, a_offRegister, a_pfnGet, a_pfnSet, a_paAliases, a_paSubFields } +#define DBGFREGDESC_TERMINATOR() \ + { NULL, DBGFREG_END, DBGFREGVALTYPE_INVALID, 0, 0, NULL, NULL, NULL, NULL } +/** @} */ + + +/** @name DBGFREG_FLAGS_XXX + * @{ */ +/** The register is read-only. */ +#define DBGFREG_FLAGS_READ_ONLY RT_BIT_32(0) +/** @} */ + +/** + * Entry in a batch query or set operation. + */ +typedef struct DBGFREGENTRY +{ + /** The register identifier. */ + DBGFREG enmReg; + /** The size of the value in bytes. */ + DBGFREGVALTYPE enmType; + /** The register value. The valid view is indicated by enmType. */ + DBGFREGVAL Val; +} DBGFREGENTRY; +/** Pointer to a register entry in a batch operation. */ +typedef DBGFREGENTRY *PDBGFREGENTRY; +/** Pointer to a const register entry in a batch operation. */ +typedef DBGFREGENTRY const *PCDBGFREGENTRY; + +/** Used with DBGFR3Reg* to indicate the hypervisor register set instead of the + * guest. */ +#define DBGFREG_HYPER_VMCPUID UINT32_C(0x01000000) + +VMMR3DECL(int) DBGFR3RegCpuQueryU8( PVM pVM, VMCPUID idCpu, DBGFREG enmReg, uint8_t *pu8); +VMMR3DECL(int) DBGFR3RegCpuQueryU16( PVM pVM, VMCPUID idCpu, DBGFREG enmReg, uint16_t *pu16); +VMMR3DECL(int) DBGFR3RegCpuQueryU32( PVM pVM, VMCPUID idCpu, DBGFREG enmReg, uint32_t *pu32); +VMMR3DECL(int) DBGFR3RegCpuQueryU64( PVM pVM, VMCPUID idCpu, DBGFREG enmReg, uint64_t *pu64); +VMMR3DECL(int) DBGFR3RegCpuQueryU128(PVM pVM, VMCPUID idCpu, DBGFREG enmReg, uint128_t *pu128); +VMMR3DECL(int) DBGFR3RegCpuQueryLrd( PVM pVM, VMCPUID idCpu, DBGFREG enmReg, long double *plrd); +VMMR3DECL(int) DBGFR3RegCpuQueryXdtr(PVM pVM, VMCPUID idCpu, DBGFREG enmReg, uint64_t *pu64Base, uint16_t *pu16Limit); +#if 0 +VMMR3DECL(int) DBGFR3RegCpuQueryBatch(PVM pVM,VMCPUID idCpu, PDBGFREGENTRY paRegs, size_t cRegs); +VMMR3DECL(int) DBGFR3RegCpuQueryAll( PVM pVM, VMCPUID idCpu, PDBGFREGENTRY paRegs, size_t cRegs); + +VMMR3DECL(int) DBGFR3RegCpuSetU8( PVM pVM, VMCPUID idCpu, DBGFREG enmReg, uint8_t u8); +VMMR3DECL(int) DBGFR3RegCpuSetU16( PVM pVM, VMCPUID idCpu, DBGFREG enmReg, uint16_t u16); +VMMR3DECL(int) DBGFR3RegCpuSetU32( PVM pVM, VMCPUID idCpu, DBGFREG enmReg, uint32_t u32); +VMMR3DECL(int) DBGFR3RegCpuSetU64( PVM pVM, VMCPUID idCpu, DBGFREG enmReg, uint64_t u64); +VMMR3DECL(int) DBGFR3RegCpuSetU128( PVM pVM, VMCPUID idCpu, DBGFREG enmReg, uint128_t u128); +VMMR3DECL(int) DBGFR3RegCpuSetLrd( PVM pVM, VMCPUID idCpu, DBGFREG enmReg, long double lrd); +VMMR3DECL(int) DBGFR3RegCpuSetBatch( PVM pVM, VMCPUID idCpu, PCDBGFREGENTRY paRegs, size_t cRegs); +#endif + +VMMR3DECL(const char *) DBGFR3RegCpuName(PVM pVM, DBGFREG enmReg, DBGFREGVALTYPE enmType); + +VMMR3_INT_DECL(int) DBGFR3RegRegisterCpu(PVM pVM, PVMCPU pVCpu, PCDBGFREGDESC paRegisters, bool fGuestRegs); +VMMR3DECL(int) DBGFR3RegRegisterDevice(PVM pVM, PCDBGFREGDESC paRegisters, PPDMDEVINS pDevIns, const char *pszPrefix, uint32_t iInstance); + +/** + * Entry in a named batch query or set operation. + */ +typedef struct DBGFREGENTRYNM +{ + /** The register name. */ + const char *pszName; + /** The size of the value in bytes. */ + DBGFREGVALTYPE enmType; + /** The register value. The valid view is indicated by enmType. */ + DBGFREGVAL Val; +} DBGFREGENTRYNM; +/** Pointer to a named register entry in a batch operation. */ +typedef DBGFREGENTRYNM *PDBGFREGENTRYNM; +/** Pointer to a const named register entry in a batch operation. */ +typedef DBGFREGENTRYNM const *PCDBGFREGENTRYNM; + +VMMR3DECL(int) DBGFR3RegNmValidate( PVM pVM, VMCPUID idDefCpu, const char *pszReg); + +VMMR3DECL(int) DBGFR3RegNmQuery( PVM pVM, VMCPUID idDefCpu, const char *pszReg, PDBGFREGVAL pValue, PDBGFREGVALTYPE penmType); +VMMR3DECL(int) DBGFR3RegNmQueryU8( PVM pVM, VMCPUID idDefCpu, const char *pszReg, uint8_t *pu8); +VMMR3DECL(int) DBGFR3RegNmQueryU16( PVM pVM, VMCPUID idDefCpu, const char *pszReg, uint16_t *pu16); +VMMR3DECL(int) DBGFR3RegNmQueryU32( PVM pVM, VMCPUID idDefCpu, const char *pszReg, uint32_t *pu32); +VMMR3DECL(int) DBGFR3RegNmQueryU64( PVM pVM, VMCPUID idDefCpu, const char *pszReg, uint64_t *pu64); +VMMR3DECL(int) DBGFR3RegNmQueryU128(PVM pVM, VMCPUID idDefCpu, const char *pszReg, PRTUINT128U pu128); +/*VMMR3DECL(int) DBGFR3RegNmQueryLrd( PVM pVM, VMCPUID idDefCpu, const char *pszReg, long double *plrd);*/ +VMMR3DECL(int) DBGFR3RegNmQueryXdtr(PVM pVM, VMCPUID idDefCpu, const char *pszReg, uint64_t *pu64Base, uint16_t *pu16Limit); +VMMR3DECL(int) DBGFR3RegNmQueryBatch(PVM pVM,VMCPUID idDefCpu, PDBGFREGENTRYNM paRegs, size_t cRegs); +VMMR3DECL(int) DBGFR3RegNmQueryAllCount(PVM pVM, size_t *pcRegs); +VMMR3DECL(int) DBGFR3RegNmQueryAll( PVM pVM, PDBGFREGENTRYNM paRegs, size_t cRegs); + +VMMR3DECL(int) DBGFR3RegNmSet( PVM pVM, VMCPUID idDefCpu, const char *pszReg, PCDBGFREGVAL pValue, DBGFREGVALTYPE enmType); +VMMR3DECL(int) DBGFR3RegNmSetU8( PVM pVM, VMCPUID idDefCpu, const char *pszReg, uint8_t u8); +VMMR3DECL(int) DBGFR3RegNmSetU16( PVM pVM, VMCPUID idDefCpu, const char *pszReg, uint16_t u16); +VMMR3DECL(int) DBGFR3RegNmSetU32( PVM pVM, VMCPUID idDefCpu, const char *pszReg, uint32_t u32); +VMMR3DECL(int) DBGFR3RegNmSetU64( PVM pVM, VMCPUID idDefCpu, const char *pszReg, uint64_t u64); +VMMR3DECL(int) DBGFR3RegNmSetU128( PVM pVM, VMCPUID idDefCpu, const char *pszReg, RTUINT128U u128); +VMMR3DECL(int) DBGFR3RegNmSetLrd( PVM pVM, VMCPUID idDefCpu, const char *pszReg, long double lrd); +VMMR3DECL(int) DBGFR3RegNmSetBatch( PVM pVM, VMCPUID idDefCpu, PCDBGFREGENTRYNM paRegs, size_t cRegs); + +/** @todo add enumeration methods. */ + +VMMR3DECL(int) DBGFR3RegPrintf( PVM pVM, VMCPUID idDefCpu, char *pszBuf, size_t cbBuf, const char *pszFormat, ...); +VMMR3DECL(int) DBGFR3RegPrintfV(PVM pVM, VMCPUID idDefCpu, char *pszBuf, size_t cbBuf, const char *pszFormat, va_list va); + + +/** + * Guest OS digger interface identifier. + * + * This is for use together with PDBGFR3QueryInterface and is used to + * obtain access to optional interfaces. + */ +typedef enum DBGFOSINTERFACE +{ + /** The usual invalid entry. */ + DBGFOSINTERFACE_INVALID = 0, + /** Process info. */ + DBGFOSINTERFACE_PROCESS, + /** Thread info. */ + DBGFOSINTERFACE_THREAD, + /** The end of the valid entries. */ + DBGFOSINTERFACE_END, + /** The usual 32-bit type blowup. */ + DBGFOSINTERFACE_32BIT_HACK = 0x7fffffff +} DBGFOSINTERFACE; +/** Pointer to a Guest OS digger interface identifier. */ +typedef DBGFOSINTERFACE *PDBGFOSINTERFACE; +/** Pointer to a const Guest OS digger interface identifier. */ +typedef DBGFOSINTERFACE const *PCDBGFOSINTERFACE; + + +/** + * Guest OS Digger Registration Record. + * + * This is used with the DBGFR3OSRegister() API. + */ +typedef struct DBGFOSREG +{ + /** Magic value (DBGFOSREG_MAGIC). */ + uint32_t u32Magic; + /** Flags. Reserved. */ + uint32_t fFlags; + /** The size of the instance data. */ + uint32_t cbData; + /** Operative System name. */ + char szName[24]; + + /** + * Constructs the instance. + * + * @returns VBox status code. + * @param pVM Pointer to the shared VM structure. + * @param pvData Pointer to the instance data. + */ + DECLCALLBACKMEMBER(int, pfnConstruct)(PVM pVM, void *pvData); + + /** + * Destroys the instance. + * + * @param pVM Pointer to the shared VM structure. + * @param pvData Pointer to the instance data. + */ + DECLCALLBACKMEMBER(void, pfnDestruct)(PVM pVM, void *pvData); + + /** + * Probes the guest memory for OS finger prints. + * + * No setup or so is performed, it will be followed by a call to pfnInit + * or pfnRefresh that should take care of that. + * + * @returns true if is an OS handled by this module, otherwise false. + * @param pVM Pointer to the shared VM structure. + * @param pvData Pointer to the instance data. + */ + DECLCALLBACKMEMBER(bool, pfnProbe)(PVM pVM, void *pvData); + + /** + * Initializes a fresly detected guest, loading symbols and such useful stuff. + * + * This is called after pfnProbe. + * + * @returns VBox status code. + * @param pVM Pointer to the shared VM structure. + * @param pvData Pointer to the instance data. + */ + DECLCALLBACKMEMBER(int, pfnInit)(PVM pVM, void *pvData); + + /** + * Refreshes symbols and stuff following a redetection of the same OS. + * + * This is called after pfnProbe. + * + * @returns VBox status code. + * @param pVM Pointer to the shared VM structure. + * @param pvData Pointer to the instance data. + */ + DECLCALLBACKMEMBER(int, pfnRefresh)(PVM pVM, void *pvData); + + /** + * Terminates an OS when a new (or none) OS has been detected, + * and before destruction. + * + * This is called after pfnProbe and if needed before pfnDestruct. + * + * @param pVM Pointer to the shared VM structure. + * @param pvData Pointer to the instance data. + */ + DECLCALLBACKMEMBER(void, pfnTerm)(PVM pVM, void *pvData); + + /** + * Queries the version of the running OS. + * + * This is only called after pfnInit(). + * + * @returns VBox status code. + * @param pVM Pointer to the shared VM structure. + * @param pvData Pointer to the instance data. + * @param pszVersion Where to store the version string. + * @param cchVersion The size of the version string buffer. + */ + DECLCALLBACKMEMBER(int, pfnQueryVersion)(PVM pVM, void *pvData, char *pszVersion, size_t cchVersion); + + /** + * Queries the pointer to a interface. + * + * This is called after pfnProbe. + * + * @returns Pointer to the interface if available, NULL if not available. + * @param pVM Pointer to the shared VM structure. + * @param pvData Pointer to the instance data. + * @param enmIf The interface identifier. + */ + DECLCALLBACKMEMBER(void *, pfnQueryInterface)(PVM pVM, void *pvData, DBGFOSINTERFACE enmIf); + + /** Trailing magic (DBGFOSREG_MAGIC). */ + uint32_t u32EndMagic; +} DBGFOSREG; +/** Pointer to a Guest OS digger registration record. */ +typedef DBGFOSREG *PDBGFOSREG; +/** Pointer to a const Guest OS digger registration record. */ +typedef DBGFOSREG const *PCDBGFOSREG; + +/** Magic value for DBGFOSREG::u32Magic and DBGFOSREG::u32EndMagic. (Hitomi Kanehara) */ +#define DBGFOSREG_MAGIC 0x19830808 + +VMMR3DECL(int) DBGFR3OSRegister(PVM pVM, PCDBGFOSREG pReg); +VMMR3DECL(int) DBGFR3OSDeregister(PVM pVM, PCDBGFOSREG pReg); +VMMR3DECL(int) DBGFR3OSDetect(PVM pVM, char *pszName, size_t cchName); +VMMR3DECL(int) DBGFR3OSQueryNameAndVersion(PVM pVM, char *pszName, size_t cchName, char *pszVersion, size_t cchVersion); +VMMR3DECL(void *) DBGFR3OSQueryInterface(PVM pVM, DBGFOSINTERFACE enmIf); + + +VMMR3DECL(int) DBGFR3CoreWrite(PVM pVM, const char *pszFilename, bool fReplaceFile); + +/** @} */ + + +RT_C_DECLS_END + +#endif + diff --git a/include/VBox/vmm/dbgfcorefmt.h b/include/VBox/vmm/dbgfcorefmt.h new file mode 100644 index 00000000..28f6aec2 --- /dev/null +++ b/include/VBox/vmm/dbgfcorefmt.h @@ -0,0 +1,79 @@ +/** @file + * DBGF - Debugger Facility, VM Core File Format. + */ + +/* + * Copyright (C) 2010 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_dbgfcore_h +#define ___VBox_vmm_dbgfcore_h + +#include <VBox/types.h> +#include <VBox/vmm/cpumctx.h> +#include <iprt/assert.h> + + +RT_C_DECLS_BEGIN + + +/** @addgroup grp_dbgf_corefmt VM Core File Format + * @ingroup grp_dbgf + * + * @todo Add description of the core file format and how the structures in this + * file relate to it. Point to CPUMCTX in cpum.h for the CPU state. + * @todo Add the note names. + * + * @{ + */ + +/** DBGCORECOREDESCRIPTOR::u32Magic. */ +#define DBGFCORE_MAGIC UINT32_C(0xc01ac0de) +/** DBGCORECOREDESCRIPTOR::u32FmtVersion. */ +#define DBGFCORE_FMT_VERSION UINT32_C(0x00010000) + +/** + * The DBGF Core descriptor. + */ +typedef struct DBGFCOREDESCRIPTOR +{ + /** The core file magic (DBGFCORE_MAGIC) */ + uint32_t u32Magic; + /** The core file format version (DBGFCORE_FMT_VERSION). */ + uint32_t u32FmtVersion; + /** Size of this structure (sizeof(DBGFCOREDESCRIPTOR)). */ + uint32_t cbSelf; + /** VirtualBox version. */ + uint32_t u32VBoxVersion; + /** VirtualBox revision. */ + uint32_t u32VBoxRevision; + /** Number of CPUs. */ + uint32_t cCpus; +} DBGFCOREDESCRIPTOR; +AssertCompileSizeAlignment(DBGFCOREDESCRIPTOR, 8); +/** Pointer to DBGFCOREDESCRIPTOR data. */ +typedef DBGFCOREDESCRIPTOR *PDBGFCOREDESCRIPTOR; + +/** @} */ + +RT_C_DECLS_END + +#endif + diff --git a/include/VBox/vmm/dbgfsel.h b/include/VBox/vmm/dbgfsel.h new file mode 100644 index 00000000..708666bf --- /dev/null +++ b/include/VBox/vmm/dbgfsel.h @@ -0,0 +1,104 @@ +/** @file + * DBGF - Debugger Facility, selector interface partly shared with SELM. + */ + +/* + * Copyright (C) 2006-2010 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +#ifndef ___VBox_vmm_dbgfsel_h +#define ___VBox_vmm_dbgfsel_h + +#include <VBox/types.h> +#include <iprt/x86.h> + + +/** @addtogroup grp_dbgf + * @{ */ + +/** + * Selector information structure. + */ +typedef struct DBGFSELINFO +{ + /** The base address. + * For gate descriptors, this is the target address. */ + RTGCPTR GCPtrBase; + /** The limit (-1). + * For gate descriptors, this is set to zero. */ + RTGCUINTPTR cbLimit; + /** The raw descriptor. */ + union + { + X86DESC Raw; + X86DESC64 Raw64; + } u; + /** The selector. */ + RTSEL Sel; + /** The target selector for a gate. + * This is 0 if non-gate descriptor. */ + RTSEL SelGate; + /** Flags. */ + uint32_t fFlags; +} DBGFSELINFO; +/** Pointer to a SELM selector information struct. */ +typedef DBGFSELINFO *PDBGFSELINFO; +/** Pointer to a const SELM selector information struct. */ +typedef const DBGFSELINFO *PCDBGFSELINFO; + +/** @name DBGFSELINFO::fFlags + * @{ */ +/** The CPU is in real mode. */ +#define DBGFSELINFO_FLAGS_REAL_MODE RT_BIT_32(0) +/** The CPU is in protected mode. */ +#define DBGFSELINFO_FLAGS_PROT_MODE RT_BIT_32(1) +/** The CPU is in long mode. */ +#define DBGFSELINFO_FLAGS_LONG_MODE RT_BIT_32(2) +/** The selector is a hyper selector. */ +#define DBGFSELINFO_FLAGS_HYPER RT_BIT_32(3) +/** The selector is a gate selector. */ +#define DBGFSELINFO_FLAGS_GATE RT_BIT_32(4) +/** The selector is invalid. */ +#define DBGFSELINFO_FLAGS_INVALID RT_BIT_32(5) +/** The selector not present. */ +#define DBGFSELINFO_FLAGS_NOT_PRESENT RT_BIT_32(6) +/** @} */ + + +/** + * Tests whether the selector info describes an expand-down selector or now. + * + * @returns true / false. + * @param pSelInfo The selector info. + */ +DECLINLINE(bool) DBGFSelInfoIsExpandDown(PCDBGFSELINFO pSelInfo) +{ + return (pSelInfo)->u.Raw.Gen.u1DescType + && ((pSelInfo)->u.Raw.Gen.u4Type & (X86_SEL_TYPE_DOWN | X86_SEL_TYPE_CODE)) == X86_SEL_TYPE_DOWN; +} + + +VMMR3DECL(int) DBGFR3SelInfoValidateCS(PCDBGFSELINFO pSelInfo, RTSEL SelCPL); + +/** @} */ + +#endif + diff --git a/include/VBox/vmm/dbgftrace.h b/include/VBox/vmm/dbgftrace.h new file mode 100644 index 00000000..df9b15de --- /dev/null +++ b/include/VBox/vmm/dbgftrace.h @@ -0,0 +1,143 @@ +/** @file + * DBGF - Debugger Facility. + */ + +/* + * Copyright (C) 2006-2012 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_dbgftrace_h +#define ___VBox_vmm_dbgftrace_h + +#include <iprt/trace.h> +#include <VBox/types.h> + +RT_C_DECLS_BEGIN +/** @addgroup grp_dbgf_trace Tracing + * @ingroup grp_dbgf + * + * @{ + */ + +#if (defined(RTTRACE_ENABLED) || DBGFTRACE_ENABLED) && !defined(DBGFTRACE_DISABLED) +# undef DBGFTRACE_ENABLED +# undef DBGFTRACE_DISABLED +# define DBGFTRACE_ENABLED +#else +# undef DBGFTRACE_ENABLED +# undef DBGFTRACE_DISABLED +# define DBGFTRACE_DISABLED +#endif + +VMMDECL(int) DBGFR3TraceConfig(PVM pVM, const char *pszConfig); + + +/** @name VMM Internal Trace Macros + * @remarks The user of these macros is responsible of including VBox/vmm/vm.h. + * @{ + */ +/** + * Records a 64-bit unsigned integer together with a tag string. + */ +#ifdef DBGFTRACE_ENABLED +# define DBGFTRACE_U64_TAG(a_pVM, a_u64, a_pszTag) \ + do { RTTraceBufAddMsgF((a_pVM)->CTX_SUFF(hTraceBuf), "%'llu %s", (a_u64), (a_pszTag)); } while (0) +#else +# define DBGFTRACE_U64_TAG(a_pVM, a_u64, a_pszTag) do { } while (0) +#endif + +/** + * Records a 64-bit unsigned integer together with two tag strings. + */ +#ifdef DBGFTRACE_ENABLED +# define DBGFTRACE_U64_TAG2(a_pVM, a_u64, a_pszTag1, a_pszTag2) \ + do { RTTraceBufAddMsgF((a_pVM)->CTX_SUFF(hTraceBuf), "%'llu %s %s", (a_u64), (a_pszTag1), (a_pszTag2)); } while (0) +#else +# define DBGFTRACE_U64_TAG2(a_pVM, a_u64, a_pszTag1, a_pszTag2) do { } while (0) +#endif + +/** + * Records the current source position. + */ +#ifdef DBGFTRACE_ENABLED +# define DBGFTRACE_POS(a_pVM) \ + do { RTTraceBufAddPos((a_pVM)->CTX_SUFF(hTraceBuf), RT_SRC_POS); } while (0) +#else +# define DBGFTRACE_POS(a_pVM) do { } while (0) +#endif + +/** + * Records the current source position along with a 64-bit unsigned integer. + */ +#ifdef DBGFTRACE_ENABLED +# define DBGFTRACE_POS_U64(a_pVM, a_u64) \ + do { RTTraceBufAddPosMsgF((a_pVM)->CTX_SUFF(hTraceBuf), RT_SRC_POS, "%'llu", (a_u64)); } while (0) +#else +# define DBGFTRACE_POS_U64(a_pVM, a_u64) do { } while (0) +#endif +/** @} */ + + +/** @name Tracing Macors for PDM Devices, Drivers and USB Devices. + * @{ + */ + +/** + * Get the trace buffer handle. + * @param a_pIns The instance (pDevIns, pDrvIns or pUsbIns). + */ +#define DBGFTRACE_PDM_TRACEBUF(a_pIns) ( (a_pIns)->CTX_SUFF(pHlp)->pfnDBGFTraceBuf((a_pIns)) ) + +/** + * Records a tagged 64-bit unsigned integer. + */ +#ifdef DBGFTRACE_ENABLED +# define DBGFTRACE_PDM_U64_TAG(a_pIns, a_u64, a_pszTag) \ + do { RTTraceBufAddMsgF(DBGFTRACE_PDM_TRACEBUF(a_pIns), "%'llu %s", (a_u64), (a_pszTag)); } while (0) +#else +# define DBGFTRACE_PDM_U64_TAG(a_pIns, a_u64, a_pszTag) do { } while (0) +#endif + +/** + * Records the current source position. + */ +#ifdef DBGFTRACE_ENABLED +# define DBGFTRACE_PDM_POS(a_pIns) \ + do { RTTraceBufAddPos(DBGFTRACE_PDM_TRACEBUF(a_pIns), RT_SRC_POS); } while (0) +#else +# define DBGFTRACE_PDM_POS(a_pIns) do { } while (0) +#endif + +/** + * Records the current source position along with a 64-bit unsigned integer. + */ +#ifdef DBGFTRACE_ENABLED +# define DBGFTRACE_PDM_POS_U64(a_pIns, a_u64) \ + do { RTTraceBufAddPosMsgF(DBGFTRACE_PDM_TRACEBUF(a_pIns), RT_SRC_POS, "%'llu", (a_u64)); } while (0) +#else +# define DBGFTRACE_PDM_POS_U64(a_pIns, a_u64) do { } while (0) +#endif +/** @} */ + + +/** @} */ +RT_C_DECLS_END + +#endif diff --git a/include/VBox/vmm/em.h b/include/VBox/vmm/em.h new file mode 100644 index 00000000..a0efe5fc --- /dev/null +++ b/include/VBox/vmm/em.h @@ -0,0 +1,276 @@ +/** @file + * EM - Execution Monitor. + */ + +/* + * Copyright (C) 2006-2010 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_em_h +#define ___VBox_vmm_em_h + +#include <VBox/types.h> +#include <VBox/vmm/trpm.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_em The Execution Monitor / Manager API + * @{ + */ + +/** Enable to allow V86 code to run in raw mode. */ +#define VBOX_RAW_V86 + +/** + * The Execution Manager State. + * + * @remarks This is used in the saved state! + */ +typedef enum EMSTATE +{ + /** Not yet started. */ + EMSTATE_NONE = 1, + /** Raw-mode execution. */ + EMSTATE_RAW, + /** Hardware accelerated raw-mode execution. */ + EMSTATE_HWACC, + /** Value reserved for future use (used to be PARAV). */ + EMSTATE_RESERVED, + /** Recompiled mode execution. */ + EMSTATE_REM, + /** Execution is halted. (waiting for interrupt) */ + EMSTATE_HALTED, + /** Application processor execution is halted. (waiting for startup IPI (SIPI)) */ + EMSTATE_WAIT_SIPI, + /** Execution is suspended. */ + EMSTATE_SUSPENDED, + /** The VM is terminating. */ + EMSTATE_TERMINATING, + /** Guest debug event from raw-mode is being processed. */ + EMSTATE_DEBUG_GUEST_RAW, + /** Guest debug event from hardware accelerated mode is being processed. */ + EMSTATE_DEBUG_GUEST_HWACC, + /** Guest debug event from recompiled-mode is being processed. */ + EMSTATE_DEBUG_GUEST_REM, + /** Hypervisor debug event being processed. */ + EMSTATE_DEBUG_HYPER, + /** The VM has encountered a fatal error. (And everyone is panicing....) */ + EMSTATE_GURU_MEDITATION, + /** Just a hack to ensure that we get a 32-bit integer. */ + EMSTATE_MAKE_32BIT_HACK = 0x7fffffff +} EMSTATE; + + +/** + * EMInterpretInstructionCPU execution modes. + */ +typedef enum +{ + /** Only supervisor code (CPL=0). */ + EMCODETYPE_SUPERVISOR, + /** User-level code only. */ + EMCODETYPE_USER, + /** Supervisor and user-level code (use with great care!). */ + EMCODETYPE_ALL, + /** Just a hack to ensure that we get a 32-bit integer. */ + EMCODETYPE_32BIT_HACK = 0x7fffffff +} EMCODETYPE; + +VMMDECL(EMSTATE) EMGetState(PVMCPU pVCpu); +VMMDECL(void) EMSetState(PVMCPU pVCpu, EMSTATE enmNewState); + +/** @name Callback handlers for instruction emulation functions. + * These are placed here because IOM wants to use them as well. + * @{ + */ +typedef DECLCALLBACK(uint32_t) FNEMULATEPARAM2UINT32(void *pvParam1, uint64_t val2); +typedef FNEMULATEPARAM2UINT32 *PFNEMULATEPARAM2UINT32; +typedef DECLCALLBACK(uint32_t) FNEMULATEPARAM2(void *pvParam1, size_t val2); +typedef FNEMULATEPARAM2 *PFNEMULATEPARAM2; +typedef DECLCALLBACK(uint32_t) FNEMULATEPARAM3(void *pvParam1, uint64_t val2, size_t val3); +typedef FNEMULATEPARAM3 *PFNEMULATEPARAM3; +typedef DECLCALLBACK(int) FNEMULATELOCKPARAM2(void *pvParam1, uint64_t val2, RTGCUINTREG32 *pf); +typedef FNEMULATELOCKPARAM2 *PFNEMULATELOCKPARAM2; +typedef DECLCALLBACK(int) FNEMULATELOCKPARAM3(void *pvParam1, uint64_t val2, size_t cb, RTGCUINTREG32 *pf); +typedef FNEMULATELOCKPARAM3 *PFNEMULATELOCKPARAM3; +/** @} */ + + +/** + * Checks if raw ring-3 execute mode is enabled. + * + * @returns true if enabled. + * @returns false if disabled. + * @param pVM The VM to operate on. + */ +#define EMIsRawRing3Enabled(pVM) (!(pVM)->fRecompileUser) + +/** + * Checks if raw ring-0 execute mode is enabled. + * + * @returns true if enabled. + * @returns false if disabled. + * @param pVM The VM to operate on. + */ +#define EMIsRawRing0Enabled(pVM) (!(pVM)->fRecompileSupervisor) + +/** + * Checks if execution with hardware assisted virtualization is enabled. + * + * @returns true if enabled. + * @returns false if disabled. + * @param pVM The VM to operate on. + */ +#define EMIsHwVirtExecutionEnabled(pVM) (!(pVM)->fRecompileSupervisor && !(pVM)->fRecompileUser) + +/** + * Checks if execution of supervisor code should be done in the + * recompiler or not. + * + * @returns true if enabled. + * @returns false if disabled. + * @param pVM The VM to operate on. + */ +#define EMIsSupervisorCodeRecompiled(pVM) ((pVM)->fRecompileSupervisor) + +VMMDECL(void) EMSetInhibitInterruptsPC(PVMCPU pVCpu, RTGCUINTPTR PC); +VMMDECL(RTGCUINTPTR) EMGetInhibitInterruptsPC(PVMCPU pVCpu); +VMMDECL(int) EMInterpretDisasCurrent(PVM pVM, PVMCPU pVCpu, PDISCPUSTATE pCpu, unsigned *pcbInstr); +VMMDECL(int) EMInterpretDisasOneEx(PVM pVM, PVMCPU pVCpu, RTGCUINTPTR GCPtrInstr, PCCPUMCTXCORE pCtxCore, + PDISCPUSTATE pDISState, unsigned *pcbInstr); +VMMDECL(VBOXSTRICTRC) EMInterpretInstruction(PVMCPU pVCpu, PCPUMCTXCORE pCoreCtx, RTGCPTR pvFault); +VMMDECL(VBOXSTRICTRC) EMInterpretInstructionEx(PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbWritten); +VMMDECL(VBOXSTRICTRC) EMInterpretInstructionDisasState(PVMCPU pVCpu, PDISCPUSTATE pDis, PCPUMCTXCORE pCoreCtx, RTGCPTR pvFault, EMCODETYPE enmCodeType); + +#ifdef IN_RC +VMMDECL(int) EMInterpretIretV86ForPatm(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame); +#endif + +VMMDECL(int) EMInterpretCpuId(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame); +VMMDECL(int) EMInterpretRdtsc(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame); +VMMDECL(int) EMInterpretRdpmc(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame); +VMMDECL(int) EMInterpretRdtscp(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx); +VMMDECL(VBOXSTRICTRC) EMInterpretInvlpg(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pAddrGC); +VMMDECL(VBOXSTRICTRC) EMInterpretMWait(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame); +VMMDECL(int) EMInterpretMonitor(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame); +VMMDECL(int) EMInterpretDRxWrite(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t DestRegDrx, uint32_t SrcRegGen); +VMMDECL(int) EMInterpretDRxRead(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t DestRegGen, uint32_t SrcRegDrx); +VMMDECL(int) EMInterpretCRxWrite(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t DestRegCrx, uint32_t SrcRegGen); +VMMDECL(int) EMInterpretCRxRead(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t DestRegGen, uint32_t SrcRegCrx); +VMMDECL(int) EMInterpretLMSW(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint16_t u16Data); +VMMDECL(int) EMInterpretCLTS(PVM pVM, PVMCPU pVCpu); +#ifndef VBOX_WITH_IEM +VMMDECL(int) EMInterpretRdmsr(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame); +VMMDECL(int) EMInterpretWrmsr(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame); +#endif /* !VBOX_WITH_IEM */ +VMM_INT_DECL(bool) EMShouldContinueAfterHalt(PVMCPU pVCpu, PCPUMCTX pCtx); +VMM_INT_DECL(int) EMMonitorWaitPrepare(PVMCPU pVCpu, uint64_t rax, uint64_t rcx, uint64_t rdx); +VMM_INT_DECL(int) EMMonitorWaitPerform(PVMCPU pVCpu, uint64_t rax, uint64_t rcx); + +/** @name Assembly routines + * @{ */ +VMMDECL(uint32_t) EMEmulateCmp(uint32_t u32Param1, uint64_t u64Param2, size_t cb); +VMMDECL(uint32_t) EMEmulateAnd(void *pvParam1, uint64_t u64Param2, size_t cb); +VMMDECL(uint32_t) EMEmulateInc(void *pvParam1, size_t cb); +VMMDECL(uint32_t) EMEmulateDec(void *pvParam1, size_t cb); +VMMDECL(uint32_t) EMEmulateOr(void *pvParam1, uint64_t u64Param2, size_t cb); +VMMDECL(int) EMEmulateLockOr(void *pvParam1, uint64_t u64Param2, size_t cbSize, RTGCUINTREG32 *pf); +VMMDECL(uint32_t) EMEmulateXor(void *pvParam1, uint64_t u64Param2, size_t cb); +VMMDECL(int) EMEmulateLockXor(void *pvParam1, uint64_t u64Param2, size_t cbSize, RTGCUINTREG32 *pf); +VMMDECL(uint32_t) EMEmulateAdd(void *pvParam1, uint64_t u64Param2, size_t cb); +VMMDECL(int) EMEmulateLockAnd(void *pvParam1, uint64_t u64Param2, size_t cbSize, RTGCUINTREG32 *pf); +VMMDECL(uint32_t) EMEmulateSub(void *pvParam1, uint64_t u64Param2, size_t cb); +VMMDECL(uint32_t) EMEmulateAdcWithCarrySet(void *pvParam1, uint64_t u64Param2, size_t cb); +VMMDECL(uint32_t) EMEmulateBtr(void *pvParam1, uint64_t u64Param2); +VMMDECL(int) EMEmulateLockBtr(void *pvParam1, uint64_t u64Param2, RTGCUINTREG32 *pf); +VMMDECL(uint32_t) EMEmulateBts(void *pvParam1, uint64_t u64Param2); +VMMDECL(uint32_t) EMEmulateBtc(void *pvParam1, uint64_t u64Param2); +VMMDECL(uint32_t) EMEmulateCmpXchg(void *pvParam1, uint64_t *pu32Param2, uint64_t u32Param3, size_t cbSize); +VMMDECL(uint32_t) EMEmulateLockCmpXchg(void *pvParam1, uint64_t *pu64Param2, uint64_t u64Param3, size_t cbSize); +VMMDECL(uint32_t) EMEmulateCmpXchg8b(void *pu32Param1, uint32_t *pEAX, uint32_t *pEDX, uint32_t uEBX, uint32_t uECX); +VMMDECL(uint32_t) EMEmulateLockCmpXchg8b(void *pu32Param1, uint32_t *pEAX, uint32_t *pEDX, uint32_t uEBX, uint32_t uECX); +VMMDECL(uint32_t) EMEmulateXAdd(void *pvParam1, void *pvParam2, size_t cbOp); +VMMDECL(uint32_t) EMEmulateLockXAdd(void *pvParam1, void *pvParam2, size_t cbOp); +/** @} */ + +/** @name REM locking routines + * @{ */ +VMMDECL(void) EMRemUnlock(PVM pVM); +VMMDECL(void) EMRemLock(PVM pVM); +VMMDECL(bool) EMRemIsLockOwner(PVM pVM); +VMMDECL(int) EMRemTryLock(PVM pVM); +/** @} */ + +#ifdef IN_RING3 +/** @defgroup grp_em_r3 The EM Host Context Ring-3 API + * @ingroup grp_em + * @{ + */ +VMMR3DECL(int) EMR3Init(PVM pVM); +VMMR3DECL(void) EMR3Relocate(PVM pVM); +VMMR3DECL(void) EMR3ResetCpu(PVMCPU pVCpu); +VMMR3DECL(void) EMR3Reset(PVM pVM); +VMMR3DECL(int) EMR3Term(PVM pVM); +VMMR3DECL(DECLNORETURN(void)) EMR3FatalError(PVMCPU pVCpu, int rc); +VMMR3DECL(int) EMR3ExecuteVM(PVM pVM, PVMCPU pVCpu); +VMMR3DECL(int) EMR3CheckRawForcedActions(PVM pVM, PVMCPU pVCpu); +VMMR3DECL(int) EMR3Interpret(PVM pVM); + +/** + * Command argument for EMR3RawSetMode(). + * + * It's possible to extend this interface to change several + * execution modes at once should the need arise. + */ +typedef enum EMEXECPOLICY +{ + /** The customary invalid zero entry. */ + EMEXECPOLICY_INVALID = 0, + /** Whether to recompile ring-0 code or execute it in raw/hm. */ + EMEXECPOLICY_RECOMPILE_RING0, + /** Whether to recompile ring-3 code or execute it in raw/hm. */ + EMEXECPOLICY_RECOMPILE_RING3, + /** End of valid value (not included). */ + EMEXECPOLICY_END, + /** The customary 32-bit type blowup. */ + EMEXECPOLICY_32BIT_HACK = 0x7fffffff +} EMEXECPOLICY; + +VMMR3DECL(int) EMR3SetExecutionPolicy(PVM pVM, EMEXECPOLICY enmPolicy, bool fEnforce); +/** @} */ +#endif /* IN_RING3 */ + + +#ifdef IN_RC +/** @defgroup grp_em_gc The EM Guest Context API + * @ingroup grp_em + * @{ + */ +VMMRCDECL(int) EMGCTrap(PVM pVM, unsigned uTrap, PCPUMCTXCORE pRegFrame); +/** @} */ +#endif /* IN_RC */ + +/** @} */ + +RT_C_DECLS_END + +#endif + diff --git a/include/VBox/vmm/ftm.h b/include/VBox/vmm/ftm.h new file mode 100644 index 00000000..2fc1ccfe --- /dev/null +++ b/include/VBox/vmm/ftm.h @@ -0,0 +1,71 @@ +/** @file + * FTM - Fault Tolerance Manager. + */ + +/* + * Copyright (C) 2010 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_ftm_h +#define ___VBox_vmm_ftm_h + +#include <VBox/types.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_ftm The Fault Tolerance Monitor / Manager API + * @{ + */ + +/** + * Fault tolerance checkpoint type. + */ +typedef enum FTMCHECKPOINTTYPE +{ + FTMCHECKPOINTTYPE_NETWORK, + FTMCHECKPOINTTYPE_STORAGE, + FTMCHECKPOINTTYPE_32BIT_HACK = 0x7fffffff +} FTMCHECKPOINTTYPE; + +VMMDECL(bool) FTMIsDeltaLoadSaveActive(PVM pVM); +VMMDECL(int) FTMSetCheckpoint(PVM pVM, FTMCHECKPOINTTYPE enmType); + +#ifdef IN_RING3 +/** @defgroup grp_ftm_r3 The FTM Host Context Ring-3 API + * @ingroup grp_ftm + * @{ + */ +VMMR3DECL(int) FTMR3PowerOn(PVM pVM, bool fMaster, unsigned uInterval, const char *pszAddress, unsigned uPort, const char *pszPassword); +VMMR3DECL(int) FTMR3Init(PVM pVM); +VMMR3DECL(int) FTMR3Term(PVM pVM); +VMMR3DECL(int) FTMR3CancelStandby(PVM pVM); +VMMR3DECL(int) FTMR3SetCheckpoint(PVM pVM, FTMCHECKPOINTTYPE enmType); + +#endif /* IN_RING3 */ + +/** @} */ + +/** @} */ + +RT_C_DECLS_END + +#endif + diff --git a/include/VBox/vmm/gmm.h b/include/VBox/vmm/gmm.h new file mode 100644 index 00000000..0f93c94a --- /dev/null +++ b/include/VBox/vmm/gmm.h @@ -0,0 +1,809 @@ +/** @file + * GMM - The Global Memory Manager. + */ + +/* + * Copyright (C) 2007-2010 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_gmm_h +#define ___VBox_vmm_gmm_h + +#include <VBox/vmm/gvmm.h> +#include <VBox/sup.h> +#include <VBox/param.h> +#include <VBox/ostypes.h> +#include <VBox/VMMDev.h> +#include <iprt/avl.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_gmm GMM - The Global Memory Manager + * @{ + */ + +/** @def IN_GMM_R0 + * Used to indicate whether we're inside the same link module as the ring 0 + * part of the Global Memory Manager or not. + */ +#ifdef DOXYGEN_RUNNING +# define IN_GMM_R0 +#endif +/** @def GMMR0DECL + * Ring 0 GMM export or import declaration. + * @param type The return type of the function declaration. + */ +#ifdef IN_GMM_R0 +# define GMMR0DECL(type) DECLEXPORT(type) VBOXCALL +#else +# define GMMR0DECL(type) DECLIMPORT(type) VBOXCALL +#endif + +/** @def IN_GMM_R3 + * Used to indicate whether we're inside the same link module as the ring 3 + * part of the Global Memory Manager or not. + */ +#ifdef DOXYGEN_RUNNING +# define IN_GMM_R3 +#endif +/** @def GMMR3DECL + * Ring 3 GMM export or import declaration. + * @param type The return type of the function declaration. + */ +#ifdef IN_GMM_R3 +# define GMMR3DECL(type) DECLEXPORT(type) VBOXCALL +#else +# define GMMR3DECL(type) DECLIMPORT(type) VBOXCALL +#endif + + +/** The chunk shift. (2^21 = 2 MB) */ +#define GMM_CHUNK_SHIFT 21 +/** The allocation chunk size. */ +#define GMM_CHUNK_SIZE (1U << GMM_CHUNK_SHIFT) +/** The allocation chunk size in pages. */ +#define GMM_CHUNK_NUM_PAGES (1U << (GMM_CHUNK_SHIFT - PAGE_SHIFT)) +/** The shift factor for converting a page id into a chunk id. */ +#define GMM_CHUNKID_SHIFT (GMM_CHUNK_SHIFT - PAGE_SHIFT) +/** The last valid Chunk ID value. */ +#define GMM_CHUNKID_LAST (GMM_PAGEID_LAST >> GMM_CHUNKID_SHIFT) +/** The last valid Page ID value. + * The current limit is 2^28 - 1, or almost 1TB if you like. + * The constraints are currently dictated by PGMPAGE. */ +#define GMM_PAGEID_LAST (RT_BIT_32(28) - 1) +/** Mask out the page index from the Page ID. */ +#define GMM_PAGEID_IDX_MASK ((1U << GMM_CHUNKID_SHIFT) - 1) +/** The NIL Chunk ID value. */ +#define NIL_GMM_CHUNKID 0 +/** The NIL Page ID value. */ +#define NIL_GMM_PAGEID 0 + +#if 0 /* wrong - these are guest page pfns and not page ids! */ +/** Special Page ID used by unassigned pages. */ +#define GMM_PAGEID_UNASSIGNED 0x0fffffffU +/** Special Page ID used by unsharable pages. + * Like MMIO2, shadow and heap. This is for later, obviously. */ +#define GMM_PAGEID_UNSHARABLE 0x0ffffffeU +/** The end of the valid Page IDs. This is the first special one. */ +#define GMM_PAGEID_END 0x0ffffff0U +#endif + + +/** @def GMM_GCPHYS_LAST + * The last of the valid guest physical address as it applies to GMM pages. + * + * This must reflect the constraints imposed by the RTGCPHYS type and + * the guest page frame number used internally in GMMPAGE. + * + * @note Note this corresponds to GMM_PAGE_PFN_LAST. */ +#if HC_ARCH_BITS == 64 +# define GMM_GCPHYS_LAST UINT64_C(0x00000fffffff0000) /* 2^44 (16TB) - 0x10000 */ +#else +# define GMM_GCPHYS_LAST UINT64_C(0x0000000fffff0000) /* 2^36 (64GB) - 0x10000 */ +#endif + +/** + * Over-commitment policy. + */ +typedef enum GMMOCPOLICY +{ + /** The usual invalid 0 value. */ + GMMOCPOLICY_INVALID = 0, + /** No over-commitment, fully backed. + * The GMM guarantees that it will be able to allocate all of the + * guest RAM for a VM with OC policy. */ + GMMOCPOLICY_NO_OC, + /** to-be-determined. */ + GMMOCPOLICY_TBD, + /** The end of the valid policy range. */ + GMMOCPOLICY_END, + /** The usual 32-bit hack. */ + GMMOCPOLICY_32BIT_HACK = 0x7fffffff +} GMMOCPOLICY; + +/** + * VM / Memory priority. + */ +typedef enum GMMPRIORITY +{ + /** The usual invalid 0 value. */ + GMMPRIORITY_INVALID = 0, + /** High. + * When ballooning, ask these VMs last. + * When running out of memory, try not to interrupt these VMs. */ + GMMPRIORITY_HIGH, + /** Normal. + * When ballooning, don't wait to ask these. + * When running out of memory, pause, save and/or kill these VMs. */ + GMMPRIORITY_NORMAL, + /** Low. + * When ballooning, maximize these first. + * When running out of memory, save or kill these VMs. */ + GMMPRIORITY_LOW, + /** The end of the valid priority range. */ + GMMPRIORITY_END, + /** The custom 32-bit type blowup. */ + GMMPRIORITY_32BIT_HACK = 0x7fffffff +} GMMPRIORITY; + + +/** + * GMM Memory Accounts. + */ +typedef enum GMMACCOUNT +{ + /** The customary invalid zero entry. */ + GMMACCOUNT_INVALID = 0, + /** Account with the base allocations. */ + GMMACCOUNT_BASE, + /** Account with the shadow allocations. */ + GMMACCOUNT_SHADOW, + /** Account with the fixed allocations. */ + GMMACCOUNT_FIXED, + /** The end of the valid values. */ + GMMACCOUNT_END, + /** The usual 32-bit value to finish it off. */ + GMMACCOUNT_32BIT_HACK = 0x7fffffff +} GMMACCOUNT; + + +/** + * Balloon actions. + */ +typedef enum +{ + /** Invalid zero entry. */ + GMMBALLOONACTION_INVALID = 0, + /** Inflate the balloon. */ + GMMBALLOONACTION_INFLATE, + /** Deflate the balloon. */ + GMMBALLOONACTION_DEFLATE, + /** Puncture the balloon because of VM reset. */ + GMMBALLOONACTION_RESET, + /** End of the valid actions. */ + GMMBALLOONACTION_END, + /** hack forcing the size of the enum to 32-bits. */ + GMMBALLOONACTION_MAKE_32BIT_HACK = 0x7fffffff +} GMMBALLOONACTION; + + +/** + * A page descriptor for use when freeing pages. + * See GMMR0FreePages, GMMR0BalloonedPages. + */ +typedef struct GMMFREEPAGEDESC +{ + /** The Page ID of the page to be freed. */ + uint32_t idPage; +} GMMFREEPAGEDESC; +/** Pointer to a page descriptor for freeing pages. */ +typedef GMMFREEPAGEDESC *PGMMFREEPAGEDESC; + + +/** + * A page descriptor for use when updating and allocating pages. + * + * This is a bit complicated because we want to do as much as possible + * with the same structure. + */ +typedef struct GMMPAGEDESC +{ + /** The physical address of the page. + * + * @input GMMR0AllocateHandyPages expects the guest physical address + * to update the GMMPAGE structure with. Pass GMM_GCPHYS_UNSHAREABLE + * when appropriate and NIL_RTHCPHYS when the page wasn't used + * for any specific guest address. + * + * GMMR0AllocatePage expects the guest physical address to put in + * the GMMPAGE structure for the page it allocates for this entry. + * Pass NIL_RTHCPHYS and GMM_GCPHYS_UNSHAREABLE as above. + * + * @output The host physical address of the allocated page. + * NIL_RTHCPHYS on allocation failure. + * + * ASSUMES: sizeof(RTHCPHYS) >= sizeof(RTGCPHYS). + */ + RTHCPHYS HCPhysGCPhys; + + /** The Page ID. + * + * @intput GMMR0AllocateHandyPages expects the Page ID of the page to + * update here. NIL_GMM_PAGEID means no page should be updated. + * + * GMMR0AllocatePages requires this to be initialized to + * NIL_GMM_PAGEID currently. + * + * @output The ID of the page, NIL_GMM_PAGEID if the allocation failed. + */ + uint32_t idPage; + + /** The Page ID of the shared page was replaced by this page. + * + * @input GMMR0AllocateHandyPages expects this to indicate a shared + * page that has been replaced by this page and should have its + * reference counter decremented and perhaps be freed up. Use + * NIL_GMM_PAGEID if no shared page was involved. + * + * All other APIs expects NIL_GMM_PAGEID here. + * + * @output All APIs sets this to NIL_GMM_PAGEID. + */ + uint32_t idSharedPage; +} GMMPAGEDESC; +AssertCompileSize(GMMPAGEDESC, 16); +/** Pointer to a page allocation. */ +typedef GMMPAGEDESC *PGMMPAGEDESC; + +/** GMMPAGEDESC::HCPhysGCPhys value that indicates that the page is unsharable. + * @note This corresponds to GMM_PAGE_PFN_UNSHAREABLE. */ +#if HC_ARCH_BITS == 64 +# define GMM_GCPHYS_UNSHAREABLE UINT64_C(0x00000fffffff1000) +#else +# define GMM_GCPHYS_UNSHAREABLE UINT64_C(0x0000000fffff1000) +#endif + + +/** + * The allocation sizes. + */ +typedef struct GMMVMSIZES +{ + /** The number of pages of base memory. + * This is the sum of RAM, ROMs and handy pages. */ + uint64_t cBasePages; + /** The number of pages for the shadow pool. (Can be squeezed for memory.) */ + uint32_t cShadowPages; + /** The number of pages for fixed allocations like MMIO2 and the hyper heap. */ + uint32_t cFixedPages; +} GMMVMSIZES; +/** Pointer to a GMMVMSIZES. */ +typedef GMMVMSIZES *PGMMVMSIZES; + + +/** + * GMM VM statistics. + */ +typedef struct GMMVMSTATS +{ + /** The reservations. */ + GMMVMSIZES Reserved; + /** The actual allocations. + * This includes both private and shared page allocations. */ + GMMVMSIZES Allocated; + + /** The current number of private pages. */ + uint64_t cPrivatePages; + /** The current number of shared pages. */ + uint64_t cSharedPages; + /** The current number of ballooned pages. */ + uint64_t cBalloonedPages; + /** The max number of pages that can be ballooned. */ + uint64_t cMaxBalloonedPages; + /** The number of pages we've currently requested the guest to give us. + * This is 0 if no pages currently requested. */ + uint64_t cReqBalloonedPages; + /** The number of pages the guest has given us in response to the request. + * This is not reset on request completed and may be used in later decisions. */ + uint64_t cReqActuallyBalloonedPages; + /** The number of pages we've currently requested the guest to take back. */ + uint64_t cReqDeflatePages; + /** The number of shareable module tracked by this VM. */ + uint32_t cShareableModules; + + /** The current over-commitment policy. */ + GMMOCPOLICY enmPolicy; + /** The VM priority for arbitrating VMs in low and out of memory situation. + * Like which VMs to start squeezing first. */ + GMMPRIORITY enmPriority; + /** Whether ballooning is enabled or not. */ + bool fBallooningEnabled; + /** Whether shared paging is enabled or not. */ + bool fSharedPagingEnabled; + /** Whether the VM is allowed to allocate memory or not. + * This is used when the reservation update request fails or when the VM has + * been told to suspend/save/die in an out-of-memory case. */ + bool fMayAllocate; + /** Explicit alignment. */ + bool afReserved[1]; + + +} GMMVMSTATS; + + +/** + * The GMM statistics. + */ +typedef struct GMMSTATS +{ + /** The maximum number of pages we're allowed to allocate + * (GMM::cMaxPages). */ + uint64_t cMaxPages; + /** The number of pages that has been reserved (GMM::cReservedPages). */ + uint64_t cReservedPages; + /** The number of pages that we have over-committed in reservations + * (GMM::cOverCommittedPages). */ + uint64_t cOverCommittedPages; + /** The number of actually allocated (committed if you like) pages + * (GMM::cAllocatedPages). */ + uint64_t cAllocatedPages; + /** The number of pages that are shared. A subset of cAllocatedPages. + * (GMM::cSharedPages) */ + uint64_t cSharedPages; + /** The number of pages that are actually shared between VMs. + * (GMM:cDuplicatePages) */ + uint64_t cDuplicatePages; + /** The number of pages that are shared that has been left behind by + * VMs not doing proper cleanups (GMM::cLeftBehindSharedPages). */ + uint64_t cLeftBehindSharedPages; + /** The number of current ballooned pages (GMM::cBalloonedPages). */ + uint64_t cBalloonedPages; + /** The number of allocation chunks (GMM::cChunks). */ + uint32_t cChunks; + /** The number of freed chunks ever (GMM::cFreedChunks). */ + uint32_t cFreedChunks; + /** The number of shareable modules (GMM:cShareableModules). */ + uint64_t cShareableModules; + /** Space reserved for later. */ + uint64_t au64Reserved[2]; + + /** Statistics for the specified VM. (Zero filled if not requested.) */ + GMMVMSTATS VMStats; +} GMMSTATS; +/** Pointer to the GMM statistics. */ +typedef GMMSTATS *PGMMSTATS; +/** Const pointer to the GMM statistics. */ +typedef const GMMSTATS *PCGMMSTATS; + + +GMMR0DECL(int) GMMR0Init(void); +GMMR0DECL(void) GMMR0Term(void); +GMMR0DECL(void) GMMR0InitPerVMData(PGVM pGVM); +GMMR0DECL(void) GMMR0CleanupVM(PGVM pGVM); +GMMR0DECL(int) GMMR0InitialReservation(PVM pVM, VMCPUID idCpu, uint64_t cBasePages, uint32_t cShadowPages, uint32_t cFixedPages, + GMMOCPOLICY enmPolicy, GMMPRIORITY enmPriority); +GMMR0DECL(int) GMMR0UpdateReservation(PVM pVM, VMCPUID idCpu, uint64_t cBasePages, uint32_t cShadowPages, uint32_t cFixedPages); +GMMR0DECL(int) GMMR0AllocateHandyPages(PVM pVM, VMCPUID idCpu, uint32_t cPagesToUpdate, uint32_t cPagesToAlloc, PGMMPAGEDESC paPages); +GMMR0DECL(int) GMMR0AllocatePages(PVM pVM, VMCPUID idCpu, uint32_t cPages, PGMMPAGEDESC paPages, GMMACCOUNT enmAccount); +GMMR0DECL(int) GMMR0AllocateLargePage(PVM pVM, VMCPUID idCpu, uint32_t cbPage, uint32_t *pIdPage, RTHCPHYS *pHCPhys); +GMMR0DECL(int) GMMR0FreePages(PVM pVM, VMCPUID idCpu, uint32_t cPages, PGMMFREEPAGEDESC paPages, GMMACCOUNT enmAccount); +GMMR0DECL(int) GMMR0FreeLargePage(PVM pVM, VMCPUID idCpu, uint32_t idPage); +GMMR0DECL(int) GMMR0BalloonedPages(PVM pVM, VMCPUID idCpu, GMMBALLOONACTION enmAction, uint32_t cBalloonedPages); +GMMR0DECL(int) GMMR0MapUnmapChunk(PVM pVM, uint32_t idChunkMap, uint32_t idChunkUnmap, PRTR3PTR ppvR3); +GMMR0DECL(int) GMMR0SeedChunk(PVM pVM, VMCPUID idCpu, RTR3PTR pvR3); +GMMR0DECL(int) GMMR0RegisterSharedModule(PVM pVM, VMCPUID idCpu, VBOXOSFAMILY enmGuestOS, char *pszModuleName, char *pszVersion, + RTGCPTR GCBaseAddr, uint32_t cbModule, uint32_t cRegions, + struct VMMDEVSHAREDREGIONDESC const *paRegions); +GMMR0DECL(int) GMMR0UnregisterSharedModule(PVM pVM, VMCPUID idCpu, char *pszModuleName, char *pszVersion, RTGCPTR GCBaseAddr, uint32_t cbModule); +GMMR0DECL(int) GMMR0UnregisterAllSharedModules(PVM pVM, VMCPUID idCpu); +GMMR0DECL(int) GMMR0CheckSharedModules(PVM pVM, PVMCPU pVCpu); +GMMR0DECL(int) GMMR0ResetSharedModules(PVM pVM, VMCPUID idCpu); +GMMR0DECL(int) GMMR0CheckSharedModulesStart(PVM pVM); +GMMR0DECL(int) GMMR0CheckSharedModulesEnd(PVM pVM); +GMMR0DECL(int) GMMR0QueryStatistics(PGMMSTATS pStats, PSUPDRVSESSION pSession); +GMMR0DECL(int) GMMR0ResetStatistics(PCGMMSTATS pStats, PSUPDRVSESSION pSession); + +/** + * Request buffer for GMMR0InitialReservationReq / VMMR0_DO_GMM_INITIAL_RESERVATION. + * @see GMMR0InitialReservation + */ +typedef struct GMMINITIALRESERVATIONREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + uint64_t cBasePages; /**< @see GMMR0InitialReservation */ + uint32_t cShadowPages; /**< @see GMMR0InitialReservation */ + uint32_t cFixedPages; /**< @see GMMR0InitialReservation */ + GMMOCPOLICY enmPolicy; /**< @see GMMR0InitialReservation */ + GMMPRIORITY enmPriority; /**< @see GMMR0InitialReservation */ +} GMMINITIALRESERVATIONREQ; +/** Pointer to a GMMR0InitialReservationReq / VMMR0_DO_GMM_INITIAL_RESERVATION request buffer. */ +typedef GMMINITIALRESERVATIONREQ *PGMMINITIALRESERVATIONREQ; + +GMMR0DECL(int) GMMR0InitialReservationReq(PVM pVM, VMCPUID idCpu, PGMMINITIALRESERVATIONREQ pReq); + + +/** + * Request buffer for GMMR0UpdateReservationReq / VMMR0_DO_GMM_UPDATE_RESERVATION. + * @see GMMR0UpdateReservation + */ +typedef struct GMMUPDATERESERVATIONREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + uint64_t cBasePages; /**< @see GMMR0UpdateReservation */ + uint32_t cShadowPages; /**< @see GMMR0UpdateReservation */ + uint32_t cFixedPages; /**< @see GMMR0UpdateReservation */ +} GMMUPDATERESERVATIONREQ; +/** Pointer to a GMMR0InitialReservationReq / VMMR0_DO_GMM_INITIAL_RESERVATION request buffer. */ +typedef GMMUPDATERESERVATIONREQ *PGMMUPDATERESERVATIONREQ; + +GMMR0DECL(int) GMMR0UpdateReservationReq(PVM pVM, VMCPUID idCpu, PGMMUPDATERESERVATIONREQ pReq); + + +/** + * Request buffer for GMMR0AllocatePagesReq / VMMR0_DO_GMM_ALLOCATE_PAGES. + * @see GMMR0AllocatePages. + */ +typedef struct GMMALLOCATEPAGESREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The account to charge the allocation to. */ + GMMACCOUNT enmAccount; + /** The number of pages to allocate. */ + uint32_t cPages; + /** Array of page descriptors. */ + GMMPAGEDESC aPages[1]; +} GMMALLOCATEPAGESREQ; +/** Pointer to a GMMR0AllocatePagesReq / VMMR0_DO_GMM_ALLOCATE_PAGES request buffer. */ +typedef GMMALLOCATEPAGESREQ *PGMMALLOCATEPAGESREQ; + +GMMR0DECL(int) GMMR0AllocatePagesReq(PVM pVM, VMCPUID idCpu, PGMMALLOCATEPAGESREQ pReq); + + +/** + * Request buffer for GMMR0FreePagesReq / VMMR0_DO_GMM_FREE_PAGES. + * @see GMMR0FreePages. + */ +typedef struct GMMFREEPAGESREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The account this relates to. */ + GMMACCOUNT enmAccount; + /** The number of pages to free. */ + uint32_t cPages; + /** Array of free page descriptors. */ + GMMFREEPAGEDESC aPages[1]; +} GMMFREEPAGESREQ; +/** Pointer to a GMMR0FreePagesReq / VMMR0_DO_GMM_FREE_PAGES request buffer. */ +typedef GMMFREEPAGESREQ *PGMMFREEPAGESREQ; + +GMMR0DECL(int) GMMR0FreePagesReq(PVM pVM, VMCPUID idCpu, PGMMFREEPAGESREQ pReq); + +/** + * Request buffer for GMMR0BalloonedPagesReq / VMMR0_DO_GMM_BALLOONED_PAGES. + * @see GMMR0BalloonedPages. + */ +typedef struct GMMBALLOONEDPAGESREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The number of ballooned pages. */ + uint32_t cBalloonedPages; + /** Inflate or deflate the balloon. */ + GMMBALLOONACTION enmAction; +} GMMBALLOONEDPAGESREQ; +/** Pointer to a GMMR0BalloonedPagesReq / VMMR0_DO_GMM_BALLOONED_PAGES request buffer. */ +typedef GMMBALLOONEDPAGESREQ *PGMMBALLOONEDPAGESREQ; + +GMMR0DECL(int) GMMR0BalloonedPagesReq(PVM pVM, VMCPUID idCpu, PGMMBALLOONEDPAGESREQ pReq); + + +/** + * Request buffer for GMMR0QueryHypervisorMemoryStatsReq / VMMR0_DO_GMM_QUERY_VMM_MEM_STATS. + * @see GMMR0QueryHypervisorMemoryStatsReq. + */ +typedef struct GMMMEMSTATSREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The number of allocated pages (out). */ + uint64_t cAllocPages; + /** The number of free pages (out). */ + uint64_t cFreePages; + /** The number of ballooned pages (out). */ + uint64_t cBalloonedPages; + /** The number of shared pages (out). */ + uint64_t cSharedPages; + /** Maximum nr of pages (out). */ + uint64_t cMaxPages; +} GMMMEMSTATSREQ; +/** Pointer to a GMMR0QueryHypervisorMemoryStatsReq / VMMR0_DO_GMM_QUERY_HYPERVISOR_MEM_STATS request buffer. */ +typedef GMMMEMSTATSREQ *PGMMMEMSTATSREQ; + +GMMR0DECL(int) GMMR0QueryHypervisorMemoryStatsReq(PVM pVM, PGMMMEMSTATSREQ pReq); +GMMR0DECL(int) GMMR0QueryMemoryStatsReq(PVM pVM, VMCPUID idCpu, PGMMMEMSTATSREQ pReq); + +/** + * Request buffer for GMMR0MapUnmapChunkReq / VMMR0_DO_GMM_MAP_UNMAP_CHUNK. + * @see GMMR0MapUnmapChunk + */ +typedef struct GMMMAPUNMAPCHUNKREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The chunk to map, NIL_GMM_CHUNKID if unmap only. (IN) */ + uint32_t idChunkMap; + /** The chunk to unmap, NIL_GMM_CHUNKID if map only. (IN) */ + uint32_t idChunkUnmap; + /** Where the mapping address is returned. (OUT) */ + RTR3PTR pvR3; +} GMMMAPUNMAPCHUNKREQ; +/** Pointer to a GMMR0MapUnmapChunkReq / VMMR0_DO_GMM_MAP_UNMAP_CHUNK request buffer. */ +typedef GMMMAPUNMAPCHUNKREQ *PGMMMAPUNMAPCHUNKREQ; + +GMMR0DECL(int) GMMR0MapUnmapChunkReq(PVM pVM, PGMMMAPUNMAPCHUNKREQ pReq); + + +/** + * Request buffer for GMMR0FreeLargePageReq / VMMR0_DO_GMM_FREE_LARGE_PAGE. + * @see GMMR0FreeLargePage. + */ +typedef struct GMMFREELARGEPAGEREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The Page ID. */ + uint32_t idPage; +} GMMFREELARGEPAGEREQ; +/** Pointer to a GMMR0FreePagesReq / VMMR0_DO_GMM_FREE_PAGES request buffer. */ +typedef GMMFREELARGEPAGEREQ *PGMMFREELARGEPAGEREQ; + +GMMR0DECL(int) GMMR0FreeLargePageReq(PVM pVM, VMCPUID idCpu, PGMMFREELARGEPAGEREQ pReq); + +/** Maximum length of the shared module name string, terminator included. */ +#define GMM_SHARED_MODULE_MAX_NAME_STRING 128 +/** Maximum length of the shared module version string, terminator included. */ +#define GMM_SHARED_MODULE_MAX_VERSION_STRING 16 + +/** + * Request buffer for GMMR0RegisterSharedModuleReq / VMMR0_DO_GMM_REGISTER_SHARED_MODULE. + * @see GMMR0RegisterSharedModule. + */ +typedef struct GMMREGISTERSHAREDMODULEREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** Shared module size. */ + uint32_t cbModule; + /** Number of included region descriptors */ + uint32_t cRegions; + /** Base address of the shared module. */ + RTGCPTR64 GCBaseAddr; + /** Guest OS type. */ + VBOXOSFAMILY enmGuestOS; + /** return code. */ + uint32_t rc; + /** Module name */ + char szName[GMM_SHARED_MODULE_MAX_NAME_STRING]; + /** Module version */ + char szVersion[GMM_SHARED_MODULE_MAX_VERSION_STRING]; + /** Shared region descriptor(s). */ + VMMDEVSHAREDREGIONDESC aRegions[1]; +} GMMREGISTERSHAREDMODULEREQ; +/** Pointer to a GMMR0RegisterSharedModuleReq / VMMR0_DO_GMM_REGISTER_SHARED_MODULE request buffer. */ +typedef GMMREGISTERSHAREDMODULEREQ *PGMMREGISTERSHAREDMODULEREQ; + +GMMR0DECL(int) GMMR0RegisterSharedModuleReq(PVM pVM, VMCPUID idCpu, PGMMREGISTERSHAREDMODULEREQ pReq); + +/** + * Shared region descriptor + */ +typedef struct GMMSHAREDREGIONDESC +{ + /** The page offset where the region starts. */ + uint32_t off; + /** Region size - adjusted by the region offset and rounded up to a + * page. */ + uint32_t cb; + /** Pointer to physical GMM page ID array. */ + uint32_t *paidPages; +} GMMSHAREDREGIONDESC; +/** Pointer to a GMMSHAREDREGIONDESC. */ +typedef GMMSHAREDREGIONDESC *PGMMSHAREDREGIONDESC; + + +/** + * Shared module registration info (global) + */ +typedef struct GMMSHAREDMODULE +{ + /** Tree node (keyed by a hash of name & version). */ + AVLLU32NODECORE Core; + /** Shared module size. */ + uint32_t cbModule; + /** Number of included region descriptors */ + uint32_t cRegions; + /** Number of users (VMs). */ + uint32_t cUsers; + /** Guest OS family type. */ + VBOXOSFAMILY enmGuestOS; + /** Module name */ + char szName[GMM_SHARED_MODULE_MAX_NAME_STRING]; + /** Module version */ + char szVersion[GMM_SHARED_MODULE_MAX_VERSION_STRING]; + /** Shared region descriptor(s). */ + GMMSHAREDREGIONDESC aRegions[1]; +} GMMSHAREDMODULE; +/** Pointer to a GMMSHAREDMODULE. */ +typedef GMMSHAREDMODULE *PGMMSHAREDMODULE; + +/** + * Page descriptor for GMMR0SharedModuleCheckRange + */ +typedef struct GMMSHAREDPAGEDESC +{ + /** HC Physical address (in/out) */ + RTHCPHYS HCPhys; + /** GC Physical address (in) */ + RTGCPHYS GCPhys; + /** GMM page id. (in/out) */ + uint32_t idPage; + /** CRC32 of the page in strict builds (0 if page not available). + * In non-strict build this serves as structure alignment. */ + uint32_t u32StrictChecksum; +} GMMSHAREDPAGEDESC; +/** Pointer to a GMMSHAREDPAGEDESC. */ +typedef GMMSHAREDPAGEDESC *PGMMSHAREDPAGEDESC; + +GMMR0DECL(int) GMMR0SharedModuleCheckPage(PGVM pGVM, PGMMSHAREDMODULE pModule, uint32_t idxRegion, uint32_t idxPage, + PGMMSHAREDPAGEDESC pPageDesc); + +/** + * Request buffer for GMMR0UnregisterSharedModuleReq / VMMR0_DO_GMM_UNREGISTER_SHARED_MODULE. + * @see GMMR0UnregisterSharedModule. + */ +typedef struct GMMUNREGISTERSHAREDMODULEREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** Shared module size. */ + uint32_t cbModule; + /** Align at 8 byte boundary. */ + uint32_t u32Alignment; + /** Base address of the shared module. */ + RTGCPTR64 GCBaseAddr; + /** Module name */ + char szName[GMM_SHARED_MODULE_MAX_NAME_STRING]; + /** Module version */ + char szVersion[GMM_SHARED_MODULE_MAX_VERSION_STRING]; +} GMMUNREGISTERSHAREDMODULEREQ; +/** Pointer to a GMMR0UnregisterSharedModuleReq / VMMR0_DO_GMM_UNREGISTER_SHARED_MODULE request buffer. */ +typedef GMMUNREGISTERSHAREDMODULEREQ *PGMMUNREGISTERSHAREDMODULEREQ; + +GMMR0DECL(int) GMMR0UnregisterSharedModuleReq(PVM pVM, VMCPUID idCpu, PGMMUNREGISTERSHAREDMODULEREQ pReq); + +#if defined(VBOX_STRICT) && HC_ARCH_BITS == 64 +/** + * Request buffer for GMMR0FindDuplicatePageReq / VMMR0_DO_GMM_FIND_DUPLICATE_PAGE. + * @see GMMR0FindDuplicatePage. + */ +typedef struct GMMFINDDUPLICATEPAGEREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** Page id. */ + uint32_t idPage; + /** Duplicate flag (out) */ + bool fDuplicate; +} GMMFINDDUPLICATEPAGEREQ; +/** Pointer to a GMMR0FindDuplicatePageReq / VMMR0_DO_GMM_FIND_DUPLICATE_PAGE request buffer. */ +typedef GMMFINDDUPLICATEPAGEREQ *PGMMFINDDUPLICATEPAGEREQ; + +GMMR0DECL(int) GMMR0FindDuplicatePageReq(PVM pVM, PGMMFINDDUPLICATEPAGEREQ pReq); +#endif /* VBOX_STRICT && HC_ARCH_BITS == 64 */ + + +/** + * Request buffer for GMMR0QueryStatisticsReq / VMMR0_DO_GMM_QUERY_STATISTICS. + * @see GMMR0QueryStatistics. + */ +typedef struct GMMQUERYSTATISTICSSREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The support driver session. */ + PSUPDRVSESSION pSession; + /** The statistics. */ + GMMSTATS Stats; +} GMMQUERYSTATISTICSSREQ; +/** Pointer to a GMMR0QueryStatisticsReq / VMMR0_DO_GMM_QUERY_STATISTICS + * request buffer. */ +typedef GMMQUERYSTATISTICSSREQ *PGMMQUERYSTATISTICSSREQ; + +GMMR0DECL(int) GMMR0QueryStatisticsReq(PVM pVM, PGMMQUERYSTATISTICSSREQ pReq); + + +/** + * Request buffer for GMMR0ResetStatisticsReq / VMMR0_DO_GMM_RESET_STATISTICS. + * @see GMMR0ResetStatistics. + */ +typedef struct GMMRESETSTATISTICSSREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The support driver session. */ + PSUPDRVSESSION pSession; + /** The statistics to reset. + * Any non-zero entry will be reset (if permitted). */ + GMMSTATS Stats; +} GMMRESETSTATISTICSSREQ; +/** Pointer to a GMMR0ResetStatisticsReq / VMMR0_DO_GMM_RESET_STATISTICS + * request buffer. */ +typedef GMMRESETSTATISTICSSREQ *PGMMRESETSTATISTICSSREQ; + +GMMR0DECL(int) GMMR0ResetStatisticsReq(PVM pVM, PGMMRESETSTATISTICSSREQ pReq); + + + +#ifdef IN_RING3 +/** @defgroup grp_gmm_r3 The Global Memory Manager Ring-3 API Wrappers + * @ingroup grp_gmm + * @{ + */ +GMMR3DECL(int) GMMR3InitialReservation(PVM pVM, uint64_t cBasePages, uint32_t cShadowPages, uint32_t cFixedPages, + GMMOCPOLICY enmPolicy, GMMPRIORITY enmPriority); +GMMR3DECL(int) GMMR3UpdateReservation(PVM pVM, uint64_t cBasePages, uint32_t cShadowPages, uint32_t cFixedPages); +GMMR3DECL(int) GMMR3AllocatePagesPrepare(PVM pVM, PGMMALLOCATEPAGESREQ *ppReq, uint32_t cPages, GMMACCOUNT enmAccount); +GMMR3DECL(int) GMMR3AllocatePagesPerform(PVM pVM, PGMMALLOCATEPAGESREQ pReq); +GMMR3DECL(void) GMMR3AllocatePagesCleanup(PGMMALLOCATEPAGESREQ pReq); +GMMR3DECL(int) GMMR3FreePagesPrepare(PVM pVM, PGMMFREEPAGESREQ *ppReq, uint32_t cPages, GMMACCOUNT enmAccount); +GMMR3DECL(void) GMMR3FreePagesRePrep(PVM pVM, PGMMFREEPAGESREQ pReq, uint32_t cPages, GMMACCOUNT enmAccount); +GMMR3DECL(int) GMMR3FreePagesPerform(PVM pVM, PGMMFREEPAGESREQ pReq, uint32_t cActualPages); +GMMR3DECL(void) GMMR3FreePagesCleanup(PGMMFREEPAGESREQ pReq); +GMMR3DECL(void) GMMR3FreeAllocatedPages(PVM pVM, GMMALLOCATEPAGESREQ const *pAllocReq); +GMMR3DECL(int) GMMR3AllocateLargePage(PVM pVM, uint32_t cbPage); +GMMR3DECL(int) GMMR3FreeLargePage(PVM pVM, uint32_t idPage); +GMMR3DECL(int) GMMR3MapUnmapChunk(PVM pVM, uint32_t idChunkMap, uint32_t idChunkUnmap, PRTR3PTR ppvR3); +GMMR3DECL(int) GMMR3SeedChunk(PVM pVM, RTR3PTR pvR3); +GMMR3DECL(int) GMMR3QueryHypervisorMemoryStats(PVM pVM, uint64_t *pcTotalAllocPages, uint64_t *pcTotalFreePages, uint64_t *pcTotalBalloonPages, uint64_t *puTotalBalloonSize); +GMMR3DECL(int) GMMR3QueryMemoryStats(PVM pVM, uint64_t *pcAllocPages, uint64_t *pcMaxPages, uint64_t *pcBalloonPages); +GMMR3DECL(int) GMMR3BalloonedPages(PVM pVM, GMMBALLOONACTION enmAction, uint32_t cBalloonedPages); +GMMR3DECL(int) GMMR3RegisterSharedModule(PVM pVM, PGMMREGISTERSHAREDMODULEREQ pReq); +GMMR3DECL(int) GMMR3UnregisterSharedModule(PVM pVM, PGMMUNREGISTERSHAREDMODULEREQ pReq); +GMMR3DECL(int) GMMR3CheckSharedModules(PVM pVM); +GMMR3DECL(int) GMMR3ResetSharedModules(PVM pVM); + +# if defined(VBOX_STRICT) && HC_ARCH_BITS == 64 +GMMR3DECL(bool) GMMR3IsDuplicatePage(PVM pVM, uint32_t idPage); +# endif + +/** @} */ +#endif /* IN_RING3 */ + +/** @} */ + +RT_C_DECLS_END + +#endif + diff --git a/include/VBox/vmm/gvm.h b/include/VBox/vmm/gvm.h new file mode 100644 index 00000000..b0d607de --- /dev/null +++ b/include/VBox/vmm/gvm.h @@ -0,0 +1,124 @@ +/* $Id: gvm.h $ */ +/** @file + * GVM - The Global VM Data. + */ + +/* + * Copyright (C) 2007-2010 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +#ifndef ___VBox_vmm_gvm_h +#define ___VBox_vmm_gvm_h + +#include <VBox/types.h> +#include <iprt/thread.h> + + +/** @defgroup grp_gvm GVMCPU - The Global VMCPU Data + * @{ + */ + +typedef struct GVMCPU +{ + /** VCPU id (0 - (pVM->cCpus - 1). */ + VMCPUID idCpu; + + /** Handle to the EMT thread. */ + RTNATIVETHREAD hEMT; + + /** The GVMM per vcpu data. */ + union + { +#ifdef ___GVMMR0Internal_h + struct GVMMPERVCPU s; +#endif + uint8_t padding[64]; + } gvmm; +} GVMCPU; +/** Pointer to the GVMCPU data. */ +typedef GVMCPU *PGVMCPU; + +/** @} */ + +/** @defgroup grp_gvm GVM - The Global VM Data + * @{ + */ + +/** + * The Global VM Data. + * + * This is a ring-0 only structure where we put items we don't need to + * share with ring-3 or GC, like for instance various RTR0MEMOBJ handles. + * + * Unlike VM, there are no special alignment restrictions here. The + * paddings are checked by compile time assertions. + */ +typedef struct GVM +{ + /** Magic / eye-catcher (GVM_MAGIC). */ + uint32_t u32Magic; + /** The global VM handle for this VM. */ + uint32_t hSelf; + /** The ring-0 mapping of the VM structure. */ + PVM pVM; + /** Number of Virtual CPUs, i.e. how many entries there are in aCpus. + * Same same as VM::cCpus. */ + uint32_t cCpus; + uint32_t padding; + + /** The GVMM per vm data. */ + union + { +#ifdef ___GVMMR0Internal_h + struct GVMMPERVM s; +#endif + uint8_t padding[256]; + } gvmm; + + /** The GMM per vm data. */ + union + { +#ifdef ___GMMR0Internal_h + struct GMMPERVM s; +#endif + uint8_t padding[512]; + } gmm; + + /** The RAWPCIVM per vm data. */ + union + { +#ifdef ___VBox_rawpci_h + struct RAWPCIPERVM s; +#endif + uint8_t padding[64]; + } rawpci; + + + /** GVMCPU array for the configured number of virtual CPUs. */ + GVMCPU aCpus[1]; +} GVM; + +/** The GVM::u32Magic value (Wayne Shorter). */ +#define GVM_MAGIC 0x19330825 + +/** @} */ + +#endif diff --git a/include/VBox/vmm/gvmm.h b/include/VBox/vmm/gvmm.h new file mode 100644 index 00000000..e78d181b --- /dev/null +++ b/include/VBox/vmm/gvmm.h @@ -0,0 +1,268 @@ +/* $Id: gvmm.h $ */ +/** @file + * GVMM - The Global VM Manager. + */ + +/* + * Copyright (C) 2007-2010 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_gvmm_h +#define ___VBox_vmm_gvmm_h + +#include <VBox/types.h> +#include <VBox/sup.h> +#include <iprt/cpuset.h> /* RTCPUSET_MAX_CPUS */ + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_GVMM GVMM - The Global VM Manager. + * @{ + */ + +/** @def IN_GVMM_R0 + * Used to indicate whether we're inside the same link module as the ring 0 + * part of the Global VM Manager or not. + */ +#ifdef DOXYGEN_RUNNING +# define IN_GVMM_R0 +#endif +/** @def GVMMR0DECL + * Ring 0 VM export or import declaration. + * @param type The return type of the function declaration. + */ +#ifdef IN_GVMM_R0 +# define GVMMR0DECL(type) DECLEXPORT(type) VBOXCALL +#else +# define GVMMR0DECL(type) DECLIMPORT(type) VBOXCALL +#endif + +/** @def NIL_GVM_HANDLE + * The nil GVM VM handle value (VM::hSelf). + */ +#define NIL_GVM_HANDLE 0 + + +/** + * The scheduler statistics + */ +typedef struct GVMMSTATSSCHED +{ + /** The number of calls to GVMMR0SchedHalt. */ + uint64_t cHaltCalls; + /** The number of times we did go to sleep in GVMMR0SchedHalt. */ + uint64_t cHaltBlocking; + /** The number of times we timed out in GVMMR0SchedHalt. */ + uint64_t cHaltTimeouts; + /** The number of times we didn't go to sleep in GVMMR0SchedHalt. */ + uint64_t cHaltNotBlocking; + /** The number of wake ups done during GVMMR0SchedHalt. */ + uint64_t cHaltWakeUps; + + /** The number of calls to GVMMR0WakeUp. */ + uint64_t cWakeUpCalls; + /** The number of times the EMT thread wasn't actually halted when GVMMR0WakeUp + * was called. */ + uint64_t cWakeUpNotHalted; + /** The number of wake ups done during GVMMR0WakeUp (not counting the explicit + * one). */ + uint64_t cWakeUpWakeUps; + + /** The number of calls to GVMMR0Poke. */ + uint64_t cPokeCalls; + /** The number of times the EMT thread wasn't actually busy when + * GVMMR0Poke was called. */ + uint64_t cPokeNotBusy; + + /** The number of calls to GVMMR0SchedPoll. */ + uint64_t cPollCalls; + /** The number of times the EMT has halted in a GVMMR0SchedPoll call. */ + uint64_t cPollHalts; + /** The number of wake ups done during GVMMR0SchedPoll. */ + uint64_t cPollWakeUps; + + uint64_t u64Alignment; /**< padding */ +} GVMMSTATSSCHED; +/** Pointer to the GVMM scheduler statistics. */ +typedef GVMMSTATSSCHED *PGVMMSTATSSCHED; + +/** + * Per host cpu statistics. + */ +typedef struct GVMMSTATSHOSTCPU +{ + /** The CPU ID. */ + RTCPUID idCpu; + /** The CPU's set index. */ + uint32_t idxCpuSet; + /** The desired PPT frequency. */ + uint32_t uDesiredHz; + /** The current PPT timer frequency. */ + uint32_t uTimerHz; + /** The number of times the PPT was changed. */ + uint32_t cChanges; + /** The number of times the PPT was started. */ + uint32_t cStarts; +} GVMMSTATSHOSTCPU; +/** Pointer to the GVMM per host CPU statistics. */ +typedef GVMMSTATSHOSTCPU *PGVMMSTATSHOSTCPU; + +/** + * The GVMM statistics. + */ +typedef struct GVMMSTATS +{ + /** The VM statistics if a VM was specified. */ + GVMMSTATSSCHED SchedVM; + /** The sum statistics of all VMs accessible to the caller. */ + GVMMSTATSSCHED SchedSum; + /** The number of VMs accessible to the caller. */ + uint32_t cVMs; + /** The number of emulation threads in those VMs. */ + uint32_t cEMTs; + /** Padding. */ + uint32_t u32Padding; + /** The number of valid entries in aHostCpus. */ + uint32_t cHostCpus; + /** Per host CPU statistics. */ + GVMMSTATSHOSTCPU aHostCpus[RTCPUSET_MAX_CPUS]; +} GVMMSTATS; +/** Pointer to the GVMM statistics. */ +typedef GVMMSTATS *PGVMMSTATS; +/** Const pointer to the GVMM statistics. */ +typedef const GVMMSTATS *PCGVMMSTATS; + + + +GVMMR0DECL(int) GVMMR0Init(void); +GVMMR0DECL(void) GVMMR0Term(void); +GVMMR0DECL(int) GVMMR0SetConfig(PSUPDRVSESSION pSession, const char *pszName, uint64_t u64Value); +GVMMR0DECL(int) GVMMR0QueryConfig(PSUPDRVSESSION pSession, const char *pszName, uint64_t *pu64Value); + +GVMMR0DECL(int) GVMMR0CreateVM(PSUPDRVSESSION pSession, uint32_t cCpus, PVM *ppVM); +GVMMR0DECL(int) GVMMR0InitVM(PVM pVM); +GVMMR0DECL(void) GVMMR0DoneInitVM(PVM pVM); +GVMMR0DECL(bool) GVMMR0DoingTermVM(PVM pVM, PGVM pGVM); +GVMMR0DECL(int) GVMMR0DestroyVM(PVM pVM); +GVMMR0DECL(int) GVMMR0RegisterVCpu(PVM pVM, VMCPUID idCpu); +GVMMR0DECL(PGVM) GVMMR0ByHandle(uint32_t hGVM); +GVMMR0DECL(int) GVMMR0ByVM(PVM pVM, PGVM *ppGVM); +GVMMR0DECL(int) GVMMR0ByVMAndEMT(PVM pVM, VMCPUID idCpu, PGVM *ppGVM); +GVMMR0DECL(PVM) GVMMR0GetVMByHandle(uint32_t hGVM); +GVMMR0DECL(PVM) GVMMR0GetVMByEMT(RTNATIVETHREAD hEMT); +GVMMR0DECL(int) GVMMR0SchedHalt(PVM pVM, VMCPUID idCpu, uint64_t u64ExpireGipTime); +GVMMR0DECL(int) GVMMR0SchedWakeUp(PVM pVM, VMCPUID idCpu); +GVMMR0DECL(int) GVMMR0SchedWakeUpEx(PVM pVM, VMCPUID idCpu, bool fTakeUsedLock); +GVMMR0DECL(int) GVMMR0SchedPoke(PVM pVM, VMCPUID idCpu); +GVMMR0DECL(int) GVMMR0SchedPokeEx(PVM pVM, VMCPUID idCpu, bool fTakeUsedLock); +GVMMR0DECL(int) GVMMR0SchedWakeUpAndPokeCpus(PVM pVM, PCVMCPUSET pSleepSet, PCVMCPUSET pPokeSet); +GVMMR0DECL(int) GVMMR0SchedPoll(PVM pVM, VMCPUID idCpu, bool fYield); +GVMMR0DECL(void) GVMMR0SchedUpdatePeriodicPreemptionTimer(PVM pVM, RTCPUID idHostCpu, uint32_t uHz); +GVMMR0DECL(int) GVMMR0QueryStatistics(PGVMMSTATS pStats, PSUPDRVSESSION pSession, PVM pVM); +GVMMR0DECL(int) GVMMR0ResetStatistics(PCGVMMSTATS pStats, PSUPDRVSESSION pSession, PVM pVM); + + +/** + * Request packet for calling GVMMR0CreateVM. + */ +typedef struct GVMMCREATEVMREQ +{ + /** The request header. */ + SUPVMMR0REQHDR Hdr; + /** The support driver session. (IN) */ + PSUPDRVSESSION pSession; + /** Number of virtual CPUs for the new VM. (IN) */ + uint32_t cCpus; + /** Pointer to the ring-3 mapping of the shared VM structure on return. (OUT) */ + PVMR3 pVMR3; + /** Pointer to the ring-0 mapping of the shared VM structure on return. (OUT) */ + PVMR0 pVMR0; +} GVMMCREATEVMREQ; +/** Pointer to a GVMMR0CreateVM request packet. */ +typedef GVMMCREATEVMREQ *PGVMMCREATEVMREQ; + +GVMMR0DECL(int) GVMMR0CreateVMReq(PGVMMCREATEVMREQ pReq); + + +/** + * Request buffer for GVMMR0SchedWakeUpAndPokeCpusReq / VMMR0_DO_GVMM_SCHED_WAKE_UP_AND_POKE_CPUS. + * @see GVMMR0SchedWakeUpAndPokeCpus. + */ +typedef struct GVMMSCHEDWAKEUPANDPOKECPUSREQ /* nice and unreadable... */ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The sleeper set. */ + VMCPUSET SleepSet; + /** The set of virtual CPUs to poke. */ + VMCPUSET PokeSet; +} GVMMSCHEDWAKEUPANDPOKECPUSREQ; +/** Pointer to a GVMMR0QueryStatisticsReq / VMMR0_DO_GVMM_QUERY_STATISTICS request buffer. */ +typedef GVMMSCHEDWAKEUPANDPOKECPUSREQ *PGVMMSCHEDWAKEUPANDPOKECPUSREQ; + +GVMMR0DECL(int) GVMMR0SchedWakeUpAndPokeCpusReq(PVM pVM, PGVMMSCHEDWAKEUPANDPOKECPUSREQ pReq); + + +/** + * Request buffer for GVMMR0QueryStatisticsReq / VMMR0_DO_GVMM_QUERY_STATISTICS. + * @see GVMMR0QueryStatistics. + */ +typedef struct GVMMQUERYSTATISTICSSREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The support driver session. */ + PSUPDRVSESSION pSession; + /** The statistics. */ + GVMMSTATS Stats; +} GVMMQUERYSTATISTICSSREQ; +/** Pointer to a GVMMR0QueryStatisticsReq / VMMR0_DO_GVMM_QUERY_STATISTICS request buffer. */ +typedef GVMMQUERYSTATISTICSSREQ *PGVMMQUERYSTATISTICSSREQ; + +GVMMR0DECL(int) GVMMR0QueryStatisticsReq(PVM pVM, PGVMMQUERYSTATISTICSSREQ pReq); + + +/** + * Request buffer for GVMMR0ResetStatisticsReq / VMMR0_DO_GVMM_RESET_STATISTICS. + * @see GVMMR0ResetStatistics. + */ +typedef struct GVMMRESETSTATISTICSSREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The support driver session. */ + PSUPDRVSESSION pSession; + /** The statistics to reset. + * Any non-zero entry will be reset (if permitted). */ + GVMMSTATS Stats; +} GVMMRESETSTATISTICSSREQ; +/** Pointer to a GVMMR0ResetStatisticsReq / VMMR0_DO_GVMM_RESET_STATISTICS request buffer. */ +typedef GVMMRESETSTATISTICSSREQ *PGVMMRESETSTATISTICSSREQ; + +GVMMR0DECL(int) GVMMR0ResetStatisticsReq(PVM pVM, PGVMMRESETSTATISTICSSREQ pReq); + + +/** @} */ + +RT_C_DECLS_END + +#endif + diff --git a/include/VBox/vmm/hwacc_svm.h b/include/VBox/vmm/hwacc_svm.h new file mode 100644 index 00000000..8912e378 --- /dev/null +++ b/include/VBox/vmm/hwacc_svm.h @@ -0,0 +1,744 @@ +/** @file + * HWACCM - SVM Structures and Definitions. (VMM) + */ + +/* + * Copyright (C) 2006-2007 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_svm_h +#define ___VBox_vmm_svm_h + +#include <VBox/types.h> +#include <VBox/err.h> +#include <iprt/assert.h> +#include <iprt/asm.h> + +/** @defgroup grp_svm svm Types and Definitions + * @ingroup grp_hwaccm + * @{ + */ + +/** @name SVM features for cpuid 0x8000000a + * @{ + */ +/** Bit 0 - NP - Nested Paging supported. */ +#define AMD_CPUID_SVM_FEATURE_EDX_NESTED_PAGING RT_BIT(0) +/** Bit 1 - LbrVirt - Support for saving five debug MSRs. */ +#define AMD_CPUID_SVM_FEATURE_EDX_LBR_VIRT RT_BIT(1) +/** Bit 2 - SVML - SVM locking bit supported. */ +#define AMD_CPUID_SVM_FEATURE_EDX_SVM_LOCK RT_BIT(2) +/** Bit 3 - NRIPS - Saving the next instruction pointer is supported. */ +#define AMD_CPUID_SVM_FEATURE_EDX_NRIP_SAVE RT_BIT(3) +/** Bit 4 - TscRateMsr - Support for MSR TSC ratio. */ +#define AMD_CPUID_SVM_FEATURE_EDX_TSC_RATE_MSR RT_BIT(4) +/** Bit 5 - VmcbClean - Support VMCB clean bits. */ +#define AMD_CPUID_SVM_FEATURE_EDX_VMCB_CLEAN RT_BIT(5) +/** Bit 6 - FlushByAsid - Indicate TLB flushing for current ASID only, and that + * VMCB.TLB_Control is supported. */ +#define AMD_CPUID_SVM_FEATURE_EDX_FLUSH_BY_ASID RT_BIT(6) +/** Bit 7 - DecodeAssist - Indicate decode assist is supported. */ +#define AMD_CPUID_SVM_FEATURE_EDX_DECODE_ASSIST RT_BIT(7) +/** Where did we get this from? */ +#define AMD_CPUID_SVM_FEATURE_EDX_SSE_3_5_DISABLE RT_BIT(9) +/** Bit 10 - PauseFilter - Indicates support for the PAUSE intercept filter. */ +#define AMD_CPUID_SVM_FEATURE_EDX_PAUSE_FILTER RT_BIT(10) +/** Bit 12 - PauseFilterThreshold - Indicates support for the PAUSE + * intercept filter cycle count threshold. */ +#define AMD_CPUID_SVM_FEATURE_EDX_PAUSE_FILTER_THRESHOLD RT_BIT(12) +/** @} */ + + +/** @name SVM Basic Exit Reasons. + * @{ + */ +/** Invalid guest state in VMCB. */ +#define SVM_EXIT_INVALID -1 +/** Read from CR0-CR15. */ +#define SVM_EXIT_READ_CR0 0x0 +#define SVM_EXIT_READ_CR1 0x1 +#define SVM_EXIT_READ_CR2 0x2 +#define SVM_EXIT_READ_CR3 0x3 +#define SVM_EXIT_READ_CR4 0x4 +#define SVM_EXIT_READ_CR5 0x5 +#define SVM_EXIT_READ_CR6 0x6 +#define SVM_EXIT_READ_CR7 0x7 +#define SVM_EXIT_READ_CR8 0x8 +#define SVM_EXIT_READ_CR9 0x9 +#define SVM_EXIT_READ_CR10 0xA +#define SVM_EXIT_READ_CR11 0xB +#define SVM_EXIT_READ_CR12 0xC +#define SVM_EXIT_READ_CR13 0xD +#define SVM_EXIT_READ_CR14 0xE +#define SVM_EXIT_READ_CR15 0xF +/** Writes to CR0-CR15. */ +#define SVM_EXIT_WRITE_CR0 0x10 +#define SVM_EXIT_WRITE_CR1 0x11 +#define SVM_EXIT_WRITE_CR2 0x12 +#define SVM_EXIT_WRITE_CR3 0x13 +#define SVM_EXIT_WRITE_CR4 0x14 +#define SVM_EXIT_WRITE_CR5 0x15 +#define SVM_EXIT_WRITE_CR6 0x16 +#define SVM_EXIT_WRITE_CR7 0x17 +#define SVM_EXIT_WRITE_CR8 0x18 +#define SVM_EXIT_WRITE_CR9 0x19 +#define SVM_EXIT_WRITE_CR10 0x1A +#define SVM_EXIT_WRITE_CR11 0x1B +#define SVM_EXIT_WRITE_CR12 0x1C +#define SVM_EXIT_WRITE_CR13 0x1D +#define SVM_EXIT_WRITE_CR14 0x1E +#define SVM_EXIT_WRITE_CR15 0x1F +/** Read from DR0-DR15. */ +#define SVM_EXIT_READ_DR0 0x20 +#define SVM_EXIT_READ_DR1 0x21 +#define SVM_EXIT_READ_DR2 0x22 +#define SVM_EXIT_READ_DR3 0x23 +#define SVM_EXIT_READ_DR4 0x24 +#define SVM_EXIT_READ_DR5 0x25 +#define SVM_EXIT_READ_DR6 0x26 +#define SVM_EXIT_READ_DR7 0x27 +#define SVM_EXIT_READ_DR8 0x28 +#define SVM_EXIT_READ_DR9 0x29 +#define SVM_EXIT_READ_DR10 0x2A +#define SVM_EXIT_READ_DR11 0x2B +#define SVM_EXIT_READ_DR12 0x2C +#define SVM_EXIT_READ_DR13 0x2D +#define SVM_EXIT_READ_DR14 0x2E +#define SVM_EXIT_READ_DR15 0x2F +/** Writes to DR0-DR15. */ +#define SVM_EXIT_WRITE_DR0 0x30 +#define SVM_EXIT_WRITE_DR1 0x31 +#define SVM_EXIT_WRITE_DR2 0x32 +#define SVM_EXIT_WRITE_DR3 0x33 +#define SVM_EXIT_WRITE_DR4 0x34 +#define SVM_EXIT_WRITE_DR5 0x35 +#define SVM_EXIT_WRITE_DR6 0x36 +#define SVM_EXIT_WRITE_DR7 0x37 +#define SVM_EXIT_WRITE_DR8 0x38 +#define SVM_EXIT_WRITE_DR9 0x39 +#define SVM_EXIT_WRITE_DR10 0x3A +#define SVM_EXIT_WRITE_DR11 0x3B +#define SVM_EXIT_WRITE_DR12 0x3C +#define SVM_EXIT_WRITE_DR13 0x3D +#define SVM_EXIT_WRITE_DR14 0x3E +#define SVM_EXIT_WRITE_DR15 0x3F +/* Exception 0-31. */ +#define SVM_EXIT_EXCEPTION_0 0x40 +#define SVM_EXIT_EXCEPTION_1 0x41 +#define SVM_EXIT_EXCEPTION_2 0x42 +#define SVM_EXIT_EXCEPTION_3 0x43 +#define SVM_EXIT_EXCEPTION_4 0x44 +#define SVM_EXIT_EXCEPTION_5 0x45 +#define SVM_EXIT_EXCEPTION_6 0x46 +#define SVM_EXIT_EXCEPTION_7 0x47 +#define SVM_EXIT_EXCEPTION_8 0x48 +#define SVM_EXIT_EXCEPTION_9 0x49 +#define SVM_EXIT_EXCEPTION_A 0x4A +#define SVM_EXIT_EXCEPTION_B 0x4B +#define SVM_EXIT_EXCEPTION_C 0x4C +#define SVM_EXIT_EXCEPTION_D 0x4D +#define SVM_EXIT_EXCEPTION_E 0x4E +#define SVM_EXIT_EXCEPTION_F 0x4F +#define SVM_EXIT_EXCEPTION_10 0x50 +#define SVM_EXIT_EXCEPTION_11 0x51 +#define SVM_EXIT_EXCEPTION_12 0x52 +#define SVM_EXIT_EXCEPTION_13 0x53 +#define SVM_EXIT_EXCEPTION_14 0x54 +#define SVM_EXIT_EXCEPTION_15 0x55 +#define SVM_EXIT_EXCEPTION_16 0x56 +#define SVM_EXIT_EXCEPTION_17 0x57 +#define SVM_EXIT_EXCEPTION_18 0x58 +#define SVM_EXIT_EXCEPTION_19 0x59 +#define SVM_EXIT_EXCEPTION_1A 0x5A +#define SVM_EXIT_EXCEPTION_1B 0x5B +#define SVM_EXIT_EXCEPTION_1C 0x5C +#define SVM_EXIT_EXCEPTION_1D 0x5D +#define SVM_EXIT_EXCEPTION_1E 0x5E +#define SVM_EXIT_EXCEPTION_1F 0x5F +/** Physical maskable interrupt. */ +#define SVM_EXIT_INTR 0x60 +/** Non-maskable interrupt. */ +#define SVM_EXIT_NMI 0x61 +/** System Management interrupt. */ +#define SVM_EXIT_SMI 0x62 +/** Physical INIT signal. */ +#define SVM_EXIT_INIT 0x63 +/** Virtual interrupt. */ +#define SVM_EXIT_VINTR 0x64 +/** Write to CR0 that changed any bits other than CR0.TS or CR0.MP. */ +#define SVM_EXIT_CR0_SEL_WRITE 0x65 +/** IDTR read. */ +#define SVM_EXIT_IDTR_READ 0x66 +/** GDTR read. */ +#define SVM_EXIT_GDTR_READ 0x67 +/** LDTR read. */ +#define SVM_EXIT_LDTR_READ 0x68 +/** TR read. */ +#define SVM_EXIT_TR_READ 0x69 +/** IDTR write. */ +#define SVM_EXIT_IDTR_WRITE 0x6A +/** GDTR write. */ +#define SVM_EXIT_GDTR_WRITE 0x6B +/** LDTR write. */ +#define SVM_EXIT_LDTR_WRITE 0x6C +/** TR write. */ +#define SVM_EXIT_TR_WRITE 0x6D +/** RDTSC instruction. */ +#define SVM_EXIT_RDTSC 0x6E +/** RDPMC instruction. */ +#define SVM_EXIT_RDPMC 0x6F +/** PUSHF instruction. */ +#define SVM_EXIT_PUSHF 0x70 +/** POPF instruction. */ +#define SVM_EXIT_POPF 0x71 +/** CPUID instruction. */ +#define SVM_EXIT_CPUID 0x72 +/** RSM instruction. */ +#define SVM_EXIT_RSM 0x73 +/** IRET instruction. */ +#define SVM_EXIT_IRET 0x74 +/** software interrupt (INTn instructions). */ +#define SVM_EXIT_SWINT 0x75 +/** INVD instruction. */ +#define SVM_EXIT_INVD 0x76 +/** PAUSE instruction. */ +#define SVM_EXIT_PAUSE 0x77 +/** HLT instruction. */ +#define SVM_EXIT_HLT 0x78 +/** INVLPG instructions. */ +#define SVM_EXIT_INVLPG 0x79 +/** INVLPGA instruction. */ +#define SVM_EXIT_INVLPGA 0x7A +/** IN or OUT accessing protected port (the EXITINFO1 field provides more information). */ +#define SVM_EXIT_IOIO 0x7B +/** RDMSR or WRMSR access to protected MSR. */ +#define SVM_EXIT_MSR 0x7C +/** task switch. */ +#define SVM_EXIT_TASK_SWITCH 0x7D +/** FP legacy handling enabled, and processor is frozen in an x87/mmx instruction waiting for an interrupt. */ +#define SVM_EXIT_FERR_FREEZE 0x7E +/** Shutdown. */ +#define SVM_EXIT_SHUTDOWN 0x7F +/** VMRUN instruction. */ +#define SVM_EXIT_VMRUN 0x80 +/** VMMCALL instruction. */ +#define SVM_EXIT_VMMCALL 0x81 +/** VMLOAD instruction. */ +#define SVM_EXIT_VMLOAD 0x82 +/** VMSAVE instruction. */ +#define SVM_EXIT_VMSAVE 0x83 +/** STGI instruction. */ +#define SVM_EXIT_STGI 0x84 +/** CLGI instruction. */ +#define SVM_EXIT_CLGI 0x85 +/** SKINIT instruction. */ +#define SVM_EXIT_SKINIT 0x86 +/** RDTSCP instruction. */ +#define SVM_EXIT_RDTSCP 0x87 +/** ICEBP instruction. */ +#define SVM_EXIT_ICEBP 0x88 +/** WBINVD instruction. */ +#define SVM_EXIT_WBINVD 0x89 +/** MONITOR instruction. */ +#define SVM_EXIT_MONITOR 0x8A +/** MWAIT instruction uncond. */ +#define SVM_EXIT_MWAIT_UNCOND 0x8B +/** MWAIT instruction when armed. */ +#define SVM_EXIT_MWAIT_ARMED 0x8C +/** Nested paging: host-level page fault occurred (EXITINFO1 contains fault errorcode; EXITINFO2 contains the guest physical address causing the fault). */ +#define SVM_EXIT_NPF 0x400 + +/** @} */ + + +/** @name SVM_VMCB.u64ExitInfo2 + * @{ + */ +/** Set to 1 if the task switch was caused by an IRET; else cleared to 0. */ +#define SVM_EXIT2_TASK_SWITCH_IRET RT_BIT_64(36) +/** Set to 1 if the task switch was caused by a far jump; else cleared to 0. */ +#define SVM_EXIT2_TASK_SWITCH_JMP RT_BIT_64(38) +/** Set to 1 if the task switch has an error code; else cleared to 0. */ +#define SVM_EXIT2_TASK_SWITCH_HAS_ERROR_CODE RT_BIT_64(44) +/** The value of EFLAGS.RF that would be saved in the outgoing TSS if the task switch were not intercepted. */ +#define SVM_EXIT2_TASK_SWITCH_EFLAGS_RF RT_BIT_64(48) +/** @} */ + +/** @name SVM_VMCB.ctrl.u32InterceptCtrl1 + * @{ + */ +/** 0 Intercept INTR (physical maskable interrupt). */ +#define SVM_CTRL1_INTERCEPT_INTR RT_BIT(0) +/** 1 Intercept NMI. */ +#define SVM_CTRL1_INTERCEPT_NMI RT_BIT(1) +/** 2 Intercept SMI. */ +#define SVM_CTRL1_INTERCEPT_SMI RT_BIT(2) +/** 3 Intercept INIT. */ +#define SVM_CTRL1_INTERCEPT_INIT RT_BIT(3) +/** 4 Intercept VINTR (virtual maskable interrupt). */ +#define SVM_CTRL1_INTERCEPT_VINTR RT_BIT(4) +/** 5 Intercept CR0 writes that change bits other than CR0.TS or CR0.MP */ +#define SVM_CTRL1_INTERCEPT_CR0 RT_BIT(5) +/** 6 Intercept reads of IDTR. */ +#define SVM_CTRL1_INTERCEPT_IDTR_READS RT_BIT(6) +/** 7 Intercept reads of GDTR. */ +#define SVM_CTRL1_INTERCEPT_GDTR_READS RT_BIT(7) +/** 8 Intercept reads of LDTR. */ +#define SVM_CTRL1_INTERCEPT_LDTR_READS RT_BIT(8) +/** 9 Intercept reads of TR. */ +#define SVM_CTRL1_INTERCEPT_TR_READS RT_BIT(9) +/** 10 Intercept writes of IDTR. */ +#define SVM_CTRL1_INTERCEPT_IDTR_WRITES RT_BIT(10) +/** 11 Intercept writes of GDTR. */ +#define SVM_CTRL1_INTERCEPT_GDTR_WRITES RT_BIT(11) +/** 12 Intercept writes of LDTR. */ +#define SVM_CTRL1_INTERCEPT_LDTR_WRITES RT_BIT(12) +/** 13 Intercept writes of TR. */ +#define SVM_CTRL1_INTERCEPT_TR_WRITES RT_BIT(13) +/** 14 Intercept RDTSC instruction. */ +#define SVM_CTRL1_INTERCEPT_RDTSC RT_BIT(14) +/** 15 Intercept RDPMC instruction. */ +#define SVM_CTRL1_INTERCEPT_RDPMC RT_BIT(15) +/** 16 Intercept PUSHF instruction. */ +#define SVM_CTRL1_INTERCEPT_PUSHF RT_BIT(16) +/** 17 Intercept POPF instruction. */ +#define SVM_CTRL1_INTERCEPT_POPF RT_BIT(17) +/** 18 Intercept CPUID instruction. */ +#define SVM_CTRL1_INTERCEPT_CPUID RT_BIT(18) +/** 19 Intercept RSM instruction. */ +#define SVM_CTRL1_INTERCEPT_RSM RT_BIT(19) +/** 20 Intercept IRET instruction. */ +#define SVM_CTRL1_INTERCEPT_IRET RT_BIT(20) +/** 21 Intercept INTn instruction. */ +#define SVM_CTRL1_INTERCEPT_INTN RT_BIT(21) +/** 22 Intercept INVD instruction. */ +#define SVM_CTRL1_INTERCEPT_INVD RT_BIT(22) +/** 23 Intercept PAUSE instruction. */ +#define SVM_CTRL1_INTERCEPT_PAUSE RT_BIT(23) +/** 24 Intercept HLT instruction. */ +#define SVM_CTRL1_INTERCEPT_HLT RT_BIT(24) +/** 25 Intercept INVLPG instruction. */ +#define SVM_CTRL1_INTERCEPT_INVLPG RT_BIT(25) +/** 26 Intercept INVLPGA instruction. */ +#define SVM_CTRL1_INTERCEPT_INVLPGA RT_BIT(26) +/** 27 IOIO_PROT Intercept IN/OUT accesses to selected ports. */ +#define SVM_CTRL1_INTERCEPT_INOUT_BITMAP RT_BIT(27) +/** 28 MSR_PROT Intercept RDMSR or WRMSR accesses to selected MSRs. */ +#define SVM_CTRL1_INTERCEPT_MSR_SHADOW RT_BIT(28) +/** 29 Intercept task switches. */ +#define SVM_CTRL1_INTERCEPT_TASK_SWITCH RT_BIT(29) +/** 30 FERR_FREEZE: intercept processor "freezing" during legacy FERR handling. */ +#define SVM_CTRL1_INTERCEPT_FERR_FREEZE RT_BIT(30) +/** 31 Intercept shutdown events. */ +#define SVM_CTRL1_INTERCEPT_SHUTDOWN RT_BIT(31) +/** @} */ + + +/** @name SVM_VMCB.ctrl.u32InterceptCtrl2 + * @{ + */ +/** 0 Intercept VMRUN instruction. */ +#define SVM_CTRL2_INTERCEPT_VMRUN RT_BIT(0) +/** 1 Intercept VMMCALL instruction. */ +#define SVM_CTRL2_INTERCEPT_VMMCALL RT_BIT(1) +/** 2 Intercept VMLOAD instruction. */ +#define SVM_CTRL2_INTERCEPT_VMLOAD RT_BIT(2) +/** 3 Intercept VMSAVE instruction. */ +#define SVM_CTRL2_INTERCEPT_VMSAVE RT_BIT(3) +/** 4 Intercept STGI instruction. */ +#define SVM_CTRL2_INTERCEPT_STGI RT_BIT(4) +/** 5 Intercept CLGI instruction. */ +#define SVM_CTRL2_INTERCEPT_CLGI RT_BIT(5) +/** 6 Intercept SKINIT instruction. */ +#define SVM_CTRL2_INTERCEPT_SKINIT RT_BIT(6) +/** 7 Intercept RDTSCP instruction. */ +#define SVM_CTRL2_INTERCEPT_RDTSCP RT_BIT(7) +/** 8 Intercept ICEBP instruction. */ +#define SVM_CTRL2_INTERCEPT_ICEBP RT_BIT(8) +/** 9 Intercept WBINVD instruction. */ +#define SVM_CTRL2_INTERCEPT_WBINVD RT_BIT(9) +/** 10 Intercept MONITOR instruction. */ +#define SVM_CTRL2_INTERCEPT_MONITOR RT_BIT(10) +/** 11 Intercept MWAIT instruction unconditionally. */ +#define SVM_CTRL2_INTERCEPT_MWAIT_UNCOND RT_BIT(11) +/** 12 Intercept MWAIT instruction when armed. */ +#define SVM_CTRL2_INTERCEPT_MWAIT_ARMED RT_BIT(12) +/** 13 Intercept XSETBV instruction. */ +#define SVM_CTRL2_INTERCEPT_XSETBV RT_BIT(13) +/** @} */ + +/** @name SVM_VMCB.ctrl.u64NestedPaging + * @{ + */ +#define SVM_NESTED_PAGING_ENABLE RT_BIT(0) +/** @} */ + +/** @name SVM_VMCB.ctrl.u64IntShadow + * @{ + */ +#define SVM_INTERRUPT_SHADOW_ACTIVE RT_BIT(0) +/** @} */ + + +/** @name SVM_INTCTRL.u3Type + * @{ + */ +/** External or virtual interrupt. */ +#define SVM_EVENT_EXTERNAL_IRQ 0 +/** Non-maskable interrupt. */ +#define SVM_EVENT_NMI 2 +/** Exception; fault or trap. */ +#define SVM_EVENT_EXCEPTION 3 +/** Software interrupt. */ +#define SVM_EVENT_SOFTWARE_INT 4 +/** @} */ + + +/** @name SVM_VMCB.ctrl.TLBCtrl.n.u8TLBFlush + * @{ + */ +/** Flush nothing. */ +#define SVM_TLB_FLUSH_NOTHING 0 +/** Flush entire TLB (host+guest entries) */ +#define SVM_TLB_FLUSH_ENTIRE 1 +/** Flush this guest's TLB entries (by ASID) */ +#define SVM_TLB_FLUSH_SINGLE_CONTEXT 3 +/** Flush this guest's non-global TLB entries (by ASID) */ +#define SVM_TLB_FLUSH_SINGLE_CONTEXT_RETAIN_GLOBALS 7 +/** @} */ + + +/** + * SVM Selector type; includes hidden parts. + */ +#pragma pack(1) +typedef struct +{ + uint16_t u16Sel; + uint16_t u16Attr; + uint32_t u32Limit; + uint64_t u64Base; /**< Only lower 32 bits are implemented for CS, DS, ES & SS. */ +} SVMSEL; +#pragma pack() + +/** + * SVM GDTR/IDTR type. + */ +#pragma pack(1) +typedef struct +{ + uint16_t u16Reserved1; + uint16_t u16Reserved2; + uint32_t u32Limit; /**< Only lower 16 bits are implemented. */ + uint64_t u64Base; +} SVMGDTR; +#pragma pack() + +typedef SVMGDTR SVMIDTR; + +/** + * SVM Event injection structure. + */ +#pragma pack(1) +typedef union +{ + struct + { + uint32_t u8Vector : 8; + uint32_t u3Type : 3; + uint32_t u1ErrorCodeValid : 1; + uint32_t u19Reserved : 19; + uint32_t u1Valid : 1; + uint32_t u32ErrorCode : 32; + } n; + uint64_t au64[1]; +} SVM_EVENT; +#pragma pack() + + +/** + * SVM Interrupt control structure. + */ +#pragma pack(1) +typedef union +{ + struct + { + uint32_t u8VTPR : 8; + uint32_t u1VIrqValid : 1; + uint32_t u7Reserved : 7; + uint32_t u4VIrqPriority : 4; + uint32_t u1IgnoreTPR : 1; + uint32_t u3Reserved : 3; + uint32_t u1VIrqMasking : 1; + uint32_t u7Reserved2 : 7; + uint32_t u8VIrqVector : 8; + uint32_t u24Reserved : 24; + } n; + uint64_t au64[1]; +} SVM_INTCTRL; +#pragma pack() + + +/** + * SVM TLB control structure. + */ +#pragma pack(1) +typedef union +{ + struct + { + uint32_t u32ASID : 32; + uint32_t u8TLBFlush : 8; + uint32_t u24Reserved : 24; + } n; + uint64_t au64[1]; +} SVM_TLBCTRL; +#pragma pack() + + +/** + * SVM IOIO exit structure. + */ +#pragma pack(1) +typedef union +{ + struct + { + uint32_t u1Type : 1; /**< 0 = out, 1 = in */ + uint32_t u1Reserved : 1; + uint32_t u1STR : 1; + uint32_t u1REP : 1; + uint32_t u1OP8 : 1; + uint32_t u1OP16 : 1; + uint32_t u1OP32 : 1; + uint32_t u1ADDR16 : 1; + uint32_t u1ADDR32 : 1; + uint32_t u1ADDR64 : 1; + uint32_t u6Reserved : 6; + uint32_t u16Port : 16; + } n; + uint32_t au32[1]; +} SVM_IOIO_EXIT; +#pragma pack() + +/** + * SVM nested paging structure. + */ +#pragma pack(1) +typedef union +{ + struct + { + uint32_t u1NestedPaging : 1; /**< enabled/disabled */ + } n; + uint64_t au64[1]; +} SVM_NPCTRL; +#pragma pack() + +/** + * SVM VM Control Block. (VMCB) + */ +#pragma pack(1) +typedef struct _SVM_VMCB +{ + /** Control Area. */ + struct + { + /** Offset 0x00 - Intercept reads of CR0-15. */ + uint16_t u16InterceptRdCRx; + /** Offset 0x02 - Intercept writes to CR0-15. */ + uint16_t u16InterceptWrCRx; + /** Offset 0x04 - Intercept reads of DR0-15. */ + uint16_t u16InterceptRdDRx; + /** Offset 0x06 - Intercept writes to DR0-15. */ + uint16_t u16InterceptWrDRx; + /** Offset 0x08 - Intercept exception vectors 0-31. */ + uint32_t u32InterceptException; + /** Offset 0x0C - Intercept control field 1. */ + uint32_t u32InterceptCtrl1; + /** Offset 0x0C - Intercept control field 2. */ + uint32_t u32InterceptCtrl2; + /** Offset 0x14-0x3F - Reserved. */ + uint8_t u8Reserved[0x3e - 0x14]; + /** Offset 0x3e - PAUSE intercept filter count. */ + uint16_t u16PauseFilterCount; + /** Offset 0x40 - Physical address of IOPM. */ + uint64_t u64IOPMPhysAddr; + /** Offset 0x48 - Physical address of MSRPM. */ + uint64_t u64MSRPMPhysAddr; + /** Offset 0x50 - TSC Offset. */ + uint64_t u64TSCOffset; + /** Offset 0x58 - TLB control field. */ + SVM_TLBCTRL TLBCtrl; + /** Offset 0x60 - Interrupt control field. */ + SVM_INTCTRL IntCtrl; + /** Offset 0x68 - Interrupt shadow. */ + uint64_t u64IntShadow; + /** Offset 0x70 - Exit code. */ + uint64_t u64ExitCode; + /** Offset 0x78 - Exit info 1. */ + uint64_t u64ExitInfo1; + /** Offset 0x80 - Exit info 2. */ + uint64_t u64ExitInfo2; + /** Offset 0x88 - Exit Interrupt info. */ + SVM_EVENT ExitIntInfo; + /** Offset 0x90 - Nested Paging. */ + SVM_NPCTRL NestedPaging; + /** Offset 0x98-0xA7 - Reserved. */ + uint8_t u8Reserved2[0xA8-0x98]; + /** Offset 0xA8 - Event injection. */ + SVM_EVENT EventInject; + /** Offset 0xB0 - Host CR3 for nested paging. */ + uint64_t u64NestedPagingCR3; + /** Offset 0xB8 - LBR Virtualization. */ + uint64_t u64LBRVirt; + /** Offset 0xC0 - VMCB Clean Bits. */ + uint64_t u64VMCBCleanBits; + /** Offset 0xC8 - Next sequential instruction pointer. */ + uint64_t u64NextRIP; + /** Offset 0xD0 - Number of bytes fetched. */ + uint8_t cbInstrFetched; + /** Offset 0xD1 - Number of bytes fetched. */ + uint8_t abInstr[15]; + } ctrl; + + /** Offset 0xC0-0x3FF - Reserved. */ + uint8_t u8Reserved3[0x400-0xE0]; + + /** State Save Area. Starts at offset 0x400. */ + struct + { + /** Offset 0x400 - Guest ES register + hidden parts. */ + SVMSEL ES; + /** Offset 0x410 - Guest CS register + hidden parts. */ + SVMSEL CS; + /** Offset 0x420 - Guest SS register + hidden parts. */ + SVMSEL SS; + /** Offset 0x430 - Guest DS register + hidden parts. */ + SVMSEL DS; + /** Offset 0x440 - Guest FS register + hidden parts. */ + SVMSEL FS; + /** Offset 0x450 - Guest GS register + hidden parts. */ + SVMSEL GS; + /** Offset 0x460 - Guest GDTR register. */ + SVMGDTR GDTR; + /** Offset 0x470 - Guest LDTR register + hidden parts. */ + SVMSEL LDTR; + /** Offset 0x480 - Guest IDTR register. */ + SVMIDTR IDTR; + /** Offset 0x490 - Guest TR register + hidden parts. */ + SVMSEL TR; + /** Offset 0x4A0-0x4CA - Reserved. */ + uint8_t u8Reserved4[0x4CB-0x4A0]; + /** Offset 0x4CB - CPL. */ + uint8_t u8CPL; + /** Offset 0x4CC-0x4CF - Reserved. */ + uint8_t u8Reserved5[0x4D0-0x4CC]; + /** Offset 0x4D0 - EFER. */ + uint64_t u64EFER; + /** Offset 0x4D8-0x547 - Reserved. */ + uint8_t u8Reserved6[0x548-0x4D8]; + /** Offset 0x548 - CR4. */ + uint64_t u64CR4; + /** Offset 0x550 - CR3. */ + uint64_t u64CR3; + /** Offset 0x558 - CR0. */ + uint64_t u64CR0; + /** Offset 0x560 - DR7. */ + uint64_t u64DR7; + /** Offset 0x568 - DR6. */ + uint64_t u64DR6; + /** Offset 0x570 - RFLAGS. */ + uint64_t u64RFlags; + /** Offset 0x578 - RIP. */ + uint64_t u64RIP; + /** Offset 0x580-0x5D7 - Reserved. */ + uint8_t u8Reserved7[0x5D8-0x580]; + /** Offset 0x5D8 - RSP. */ + uint64_t u64RSP; + /** Offset 0x5E0-0x5F7 - Reserved. */ + uint8_t u8Reserved8[0x5F8-0x5E0]; + /** Offset 0x5F8 - RAX. */ + uint64_t u64RAX; + /** Offset 0x600 - STAR. */ + uint64_t u64STAR; + /** Offset 0x608 - LSTAR. */ + uint64_t u64LSTAR; + /** Offset 0x610 - CSTAR. */ + uint64_t u64CSTAR; + /** Offset 0x618 - SFMASK. */ + uint64_t u64SFMASK; + /** Offset 0x620 - KernelGSBase. */ + uint64_t u64KernelGSBase; + /** Offset 0x628 - SYSENTER_CS. */ + uint64_t u64SysEnterCS; + /** Offset 0x630 - SYSENTER_ESP. */ + uint64_t u64SysEnterESP; + /** Offset 0x638 - SYSENTER_EIP. */ + uint64_t u64SysEnterEIP; + /** Offset 0x640 - CR2. */ + uint64_t u64CR2; + /** Offset 0x648-0x667 - Reserved. */ + uint8_t u8Reserved9[0x668-0x648]; + /** Offset 0x668 - G_PAT. */ + uint64_t u64GPAT; + /** Offset 0x670 - DBGCTL. */ + uint64_t u64DBGCTL; + /** Offset 0x678 - BR_FROM. */ + uint64_t u64BR_FROM; + /** Offset 0x680 - BR_TO. */ + uint64_t u64BR_TO; + /** Offset 0x688 - LASTEXCPFROM. */ + uint64_t u64LASTEXCPFROM; + /** Offset 0x690 - LASTEXCPTO. */ + uint64_t u64LASTEXCPTO; + } guest; + + /** Offset 0x698-0xFFF- Reserved. */ + uint8_t u8Reserved10[0x1000-0x698]; +} SVM_VMCB; +#pragma pack() +AssertCompileSize(SVM_VMCB, 0x1000); +AssertCompileMemberOffset(SVM_VMCB, ctrl.u16InterceptRdCRx, 0x000); +AssertCompileMemberOffset(SVM_VMCB, ctrl.u16PauseFilterCount,0x03e); +AssertCompileMemberOffset(SVM_VMCB, ctrl.TLBCtrl, 0x058); +AssertCompileMemberOffset(SVM_VMCB, ctrl.ExitIntInfo, 0x088); +AssertCompileMemberOffset(SVM_VMCB, ctrl.EventInject, 0x0A8); +AssertCompileMemberOffset(SVM_VMCB, ctrl.abInstr, 0x0D1); +AssertCompileMemberOffset(SVM_VMCB, guest, 0x400); +AssertCompileMemberOffset(SVM_VMCB, guest.ES, 0x400); +AssertCompileMemberOffset(SVM_VMCB, guest.u8Reserved4, 0x4A0); +AssertCompileMemberOffset(SVM_VMCB, guest.u8CPL, 0x4CB); +AssertCompileMemberOffset(SVM_VMCB, guest.u8Reserved6, 0x4D8); +AssertCompileMemberOffset(SVM_VMCB, guest.u8Reserved7, 0x580); +AssertCompileMemberOffset(SVM_VMCB, guest.u8Reserved9, 0x648); +AssertCompileMemberOffset(SVM_VMCB, guest.u64GPAT, 0x668); +AssertCompileMemberOffset(SVM_VMCB, guest.u64LASTEXCPTO, 0x690); +AssertCompileMemberOffset(SVM_VMCB, u8Reserved10, 0x698); + +#ifdef IN_RING0 +VMMR0DECL(int) SVMR0InvalidatePage(PVM pVM, PVMCPU pVCpu, RTGCPTR GCVirt); +#endif /* IN_RING0 */ + +/** @} */ + +#endif + diff --git a/include/VBox/vmm/hwacc_vmx.h b/include/VBox/vmm/hwacc_vmx.h new file mode 100644 index 00000000..a96f587e --- /dev/null +++ b/include/VBox/vmm/hwacc_vmx.h @@ -0,0 +1,1708 @@ +/** @file + * HWACCM - VMX Structures and Definitions. (VMM) + */ + +/* + * Copyright (C) 2006-2010 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_vmx_h +#define ___VBox_vmm_vmx_h + +#include <VBox/types.h> +#include <VBox/err.h> +#include <iprt/x86.h> +#include <iprt/assert.h> + +/** @defgroup grp_vmx vmx Types and Definitions + * @ingroup grp_hwaccm + * @{ + */ + +/** @name VMX EPT paging structures + * @{ + */ + +/** + * Number of page table entries in the EPT. (PDPTE/PDE/PTE) + */ +#define EPT_PG_ENTRIES X86_PG_PAE_ENTRIES + +/** + * EPT Page Directory Pointer Entry. Bit view. + * @todo uint64_t isn't safe for bitfields (gcc pedantic warnings, and IIRC, + * this did cause trouble with one compiler/version). + */ +#pragma pack(1) +typedef struct EPTPML4EBITS +{ + /** Present bit. */ + uint64_t u1Present : 1; + /** Writable bit. */ + uint64_t u1Write : 1; + /** Executable bit. */ + uint64_t u1Execute : 1; + /** Reserved (must be 0). */ + uint64_t u5Reserved : 5; + /** Available for software. */ + uint64_t u4Available : 4; + /** Physical address of the next level (PD). Restricted by maximum physical address width of the cpu. */ + uint64_t u40PhysAddr : 40; + /** Availabe for software. */ + uint64_t u12Available : 12; +} EPTPML4EBITS; +#pragma pack() +AssertCompileSize(EPTPML4EBITS, 8); + +/** Bits 12-51 - - EPT - Physical Page number of the next level. */ +#define EPT_PML4E_PG_MASK X86_PML4E_PG_MASK +/** The page shift to get the PML4 index. */ +#define EPT_PML4_SHIFT X86_PML4_SHIFT +/** The PML4 index mask (apply to a shifted page address). */ +#define EPT_PML4_MASK X86_PML4_MASK + +/** + * EPT PML4E. + */ +#pragma pack(1) +typedef union EPTPML4E +{ + /** Normal view. */ + EPTPML4EBITS n; + /** Unsigned integer view. */ + X86PGPAEUINT u; + /** 64 bit unsigned integer view. */ + uint64_t au64[1]; + /** 32 bit unsigned integer view. */ + uint32_t au32[2]; +} EPTPML4E; +#pragma pack() +/** Pointer to a PML4 table entry. */ +typedef EPTPML4E *PEPTPML4E; +/** Pointer to a const PML4 table entry. */ +typedef const EPTPML4E *PCEPTPML4E; +AssertCompileSize(EPTPML4E, 8); + +/** + * EPT PML4 Table. + */ +#pragma pack(1) +typedef struct EPTPML4 +{ + EPTPML4E a[EPT_PG_ENTRIES]; +} EPTPML4; +#pragma pack() +/** Pointer to an EPT PML4 Table. */ +typedef EPTPML4 *PEPTPML4; +/** Pointer to a const EPT PML4 Table. */ +typedef const EPTPML4 *PCEPTPML4; + +/** + * EPT Page Directory Pointer Entry. Bit view. + */ +#pragma pack(1) +typedef struct EPTPDPTEBITS +{ + /** Present bit. */ + uint64_t u1Present : 1; + /** Writable bit. */ + uint64_t u1Write : 1; + /** Executable bit. */ + uint64_t u1Execute : 1; + /** Reserved (must be 0). */ + uint64_t u5Reserved : 5; + /** Available for software. */ + uint64_t u4Available : 4; + /** Physical address of the next level (PD). Restricted by maximum physical address width of the cpu. */ + uint64_t u40PhysAddr : 40; + /** Availabe for software. */ + uint64_t u12Available : 12; +} EPTPDPTEBITS; +#pragma pack() +AssertCompileSize(EPTPDPTEBITS, 8); + +/** Bits 12-51 - - EPT - Physical Page number of the next level. */ +#define EPT_PDPTE_PG_MASK X86_PDPE_PG_MASK +/** The page shift to get the PDPT index. */ +#define EPT_PDPT_SHIFT X86_PDPT_SHIFT +/** The PDPT index mask (apply to a shifted page address). */ +#define EPT_PDPT_MASK X86_PDPT_MASK_AMD64 + +/** + * EPT Page Directory Pointer. + */ +#pragma pack(1) +typedef union EPTPDPTE +{ + /** Normal view. */ + EPTPDPTEBITS n; + /** Unsigned integer view. */ + X86PGPAEUINT u; + /** 64 bit unsigned integer view. */ + uint64_t au64[1]; + /** 32 bit unsigned integer view. */ + uint32_t au32[2]; +} EPTPDPTE; +#pragma pack() +/** Pointer to an EPT Page Directory Pointer Entry. */ +typedef EPTPDPTE *PEPTPDPTE; +/** Pointer to a const EPT Page Directory Pointer Entry. */ +typedef const EPTPDPTE *PCEPTPDPTE; +AssertCompileSize(EPTPDPTE, 8); + +/** + * EPT Page Directory Pointer Table. + */ +#pragma pack(1) +typedef struct EPTPDPT +{ + EPTPDPTE a[EPT_PG_ENTRIES]; +} EPTPDPT; +#pragma pack() +/** Pointer to an EPT Page Directory Pointer Table. */ +typedef EPTPDPT *PEPTPDPT; +/** Pointer to a const EPT Page Directory Pointer Table. */ +typedef const EPTPDPT *PCEPTPDPT; + + +/** + * EPT Page Directory Table Entry. Bit view. + */ +#pragma pack(1) +typedef struct EPTPDEBITS +{ + /** Present bit. */ + uint64_t u1Present : 1; + /** Writable bit. */ + uint64_t u1Write : 1; + /** Executable bit. */ + uint64_t u1Execute : 1; + /** Reserved (must be 0). */ + uint64_t u4Reserved : 4; + /** Big page (must be 0 here). */ + uint64_t u1Size : 1; + /** Available for software. */ + uint64_t u4Available : 4; + /** Physical address of page table. Restricted by maximum physical address width of the cpu. */ + uint64_t u40PhysAddr : 40; + /** Availabe for software. */ + uint64_t u12Available : 12; +} EPTPDEBITS; +#pragma pack() +AssertCompileSize(EPTPDEBITS, 8); + +/** Bits 12-51 - - EPT - Physical Page number of the next level. */ +#define EPT_PDE_PG_MASK X86_PDE_PAE_PG_MASK +/** The page shift to get the PD index. */ +#define EPT_PD_SHIFT X86_PD_PAE_SHIFT +/** The PD index mask (apply to a shifted page address). */ +#define EPT_PD_MASK X86_PD_PAE_MASK + +/** + * EPT 2MB Page Directory Table Entry. Bit view. + */ +#pragma pack(1) +typedef struct EPTPDE2MBITS +{ + /** Present bit. */ + uint64_t u1Present : 1; + /** Writable bit. */ + uint64_t u1Write : 1; + /** Executable bit. */ + uint64_t u1Execute : 1; + /** EPT Table Memory Type. MBZ for non-leaf nodes. */ + uint64_t u3EMT : 3; + /** Ignore PAT memory type */ + uint64_t u1IgnorePAT : 1; + /** Big page (must be 1 here). */ + uint64_t u1Size : 1; + /** Available for software. */ + uint64_t u4Available : 4; + /** Reserved (must be 0). */ + uint64_t u9Reserved : 9; + /** Physical address of the 2MB page. Restricted by maximum physical address width of the cpu. */ + uint64_t u31PhysAddr : 31; + /** Availabe for software. */ + uint64_t u12Available : 12; +} EPTPDE2MBITS; +#pragma pack() +AssertCompileSize(EPTPDE2MBITS, 8); + +/** Bits 21-51 - - EPT - Physical Page number of the next level. */ +#define EPT_PDE2M_PG_MASK X86_PDE2M_PAE_PG_MASK + +/** + * EPT Page Directory Table Entry. + */ +#pragma pack(1) +typedef union EPTPDE +{ + /** Normal view. */ + EPTPDEBITS n; + /** 2MB view (big). */ + EPTPDE2MBITS b; + /** Unsigned integer view. */ + X86PGPAEUINT u; + /** 64 bit unsigned integer view. */ + uint64_t au64[1]; + /** 32 bit unsigned integer view. */ + uint32_t au32[2]; +} EPTPDE; +#pragma pack() +/** Pointer to an EPT Page Directory Table Entry. */ +typedef EPTPDE *PEPTPDE; +/** Pointer to a const EPT Page Directory Table Entry. */ +typedef const EPTPDE *PCEPTPDE; +AssertCompileSize(EPTPDE, 8); + +/** + * EPT Page Directory Table. + */ +#pragma pack(1) +typedef struct EPTPD +{ + EPTPDE a[EPT_PG_ENTRIES]; +} EPTPD; +#pragma pack() +/** Pointer to an EPT Page Directory Table. */ +typedef EPTPD *PEPTPD; +/** Pointer to a const EPT Page Directory Table. */ +typedef const EPTPD *PCEPTPD; + + +/** + * EPT Page Table Entry. Bit view. + */ +#pragma pack(1) +typedef struct EPTPTEBITS +{ + /** 0 - Present bit. + * @remark This is a convenience "misnomer". The bit actually indicates + * read access and the CPU will consider an entry with any of the + * first three bits set as present. Since all our valid entries + * will have this bit set, it can be used as a present indicator + * and allow some code sharing. */ + uint64_t u1Present : 1; + /** 1 - Writable bit. */ + uint64_t u1Write : 1; + /** 2 - Executable bit. */ + uint64_t u1Execute : 1; + /** 5:3 - EPT Memory Type. MBZ for non-leaf nodes. */ + uint64_t u3EMT : 3; + /** 6 - Ignore PAT memory type */ + uint64_t u1IgnorePAT : 1; + /** 11:7 - Available for software. */ + uint64_t u5Available : 5; + /** 51:12 - Physical address of page. Restricted by maximum physical + * address width of the cpu. */ + uint64_t u40PhysAddr : 40; + /** 63:52 - Available for software. */ + uint64_t u12Available : 12; +} EPTPTEBITS; +#pragma pack() +AssertCompileSize(EPTPTEBITS, 8); + +/** Bits 12-51 - - EPT - Physical Page number of the next level. */ +#define EPT_PTE_PG_MASK X86_PTE_PAE_PG_MASK +/** The page shift to get the EPT PTE index. */ +#define EPT_PT_SHIFT X86_PT_PAE_SHIFT +/** The EPT PT index mask (apply to a shifted page address). */ +#define EPT_PT_MASK X86_PT_PAE_MASK + +/** + * EPT Page Table Entry. + */ +#pragma pack(1) +typedef union EPTPTE +{ + /** Normal view. */ + EPTPTEBITS n; + /** Unsigned integer view. */ + X86PGPAEUINT u; + /** 64 bit unsigned integer view. */ + uint64_t au64[1]; + /** 32 bit unsigned integer view. */ + uint32_t au32[2]; +} EPTPTE; +#pragma pack() +/** Pointer to an EPT Page Directory Table Entry. */ +typedef EPTPTE *PEPTPTE; +/** Pointer to a const EPT Page Directory Table Entry. */ +typedef const EPTPTE *PCEPTPTE; +AssertCompileSize(EPTPTE, 8); + +/** + * EPT Page Table. + */ +#pragma pack(1) +typedef struct EPTPT +{ + EPTPTE a[EPT_PG_ENTRIES]; +} EPTPT; +#pragma pack() +/** Pointer to an extended page table. */ +typedef EPTPT *PEPTPT; +/** Pointer to a const extended table. */ +typedef const EPTPT *PCEPTPT; + +/** + * VPID flush types. + */ +typedef enum +{ + /** Invalidate a specific page. */ + VMX_FLUSH_VPID_INDIV_ADDR = 0, + /** Invalidate one context (specific VPID). */ + VMX_FLUSH_VPID_SINGLE_CONTEXT = 1, + /** Invalidate all contexts (all VPIDs). */ + VMX_FLUSH_VPID_ALL_CONTEXTS = 2, + /** Invalidate a single VPID context retaining global mappings. */ + VMX_FLUSH_VPID_SINGLE_CONTEXT_RETAIN_GLOBALS = 3, + /** Unsupported by VirtualBox. */ + VMX_FLUSH_VPID_NOT_SUPPORTED = 0xbad, + /** Unsupported by CPU. */ + VMX_FLUSH_VPID_NONE = 0xb00, + /** 32bit hackishness. */ + VMX_FLUSH_VPID_32BIT_HACK = 0x7fffffff +} VMX_FLUSH_VPID; + +/** + * EPT flush types. + */ +typedef enum +{ + /** Invalidate one context (specific EPT). */ + VMX_FLUSH_EPT_SINGLE_CONTEXT = 1, + /* Invalidate all contexts (all EPTs) */ + VMX_FLUSH_EPT_ALL_CONTEXTS = 2, + /** Unsupported by VirtualBox. */ + VMX_FLUSH_EPT_NOT_SUPPORTED = 0xbad, + /** Unsupported by CPU. */ + VMX_FLUSH_EPT_NONE = 0xb00, + /** 32bit hackishness. */ + VMX_FLUSH_EPT_32BIT_HACK = 0x7fffffff +} VMX_FLUSH_EPT; +/** @} */ + +/** @name MSR load/store elements + * @{ + */ +#pragma pack(1) +typedef struct +{ + uint32_t u32IndexMSR; + uint32_t u32Reserved; + uint64_t u64Value; +} VMXMSR; +#pragma pack() +/** Pointer to an MSR load/store element. */ +typedef VMXMSR *PVMXMSR; +/** Pointer to a const MSR load/store element. */ +typedef const VMXMSR *PCVMXMSR; + +/** @} */ + + +/** @name VT-x capability qword + * @{ + */ +#pragma pack(1) +typedef union +{ + struct + { + uint32_t disallowed0; + uint32_t allowed1; + } n; + uint64_t u; +} VMX_CAPABILITY; +#pragma pack() +/** @} */ + +/** @name VMX Basic Exit Reasons. + * @{ + */ +/** And-mask for setting reserved bits to zero */ +#define VMX_EFLAGS_RESERVED_0 (~0xffc08028) +/** Or-mask for setting reserved bits to 1 */ +#define VMX_EFLAGS_RESERVED_1 0x00000002 +/** @} */ + +/** @name VMX Basic Exit Reasons. + * @{ + */ +/** -1 Invalid exit code */ +#define VMX_EXIT_INVALID -1 +/** 0 Exception or non-maskable interrupt (NMI). */ +#define VMX_EXIT_EXCEPTION 0 +/** 1 External interrupt. */ +#define VMX_EXIT_EXTERNAL_IRQ 1 +/** 2 Triple fault. */ +#define VMX_EXIT_TRIPLE_FAULT 2 +/** 3 INIT signal. */ +#define VMX_EXIT_INIT_SIGNAL 3 +/** 4 Start-up IPI (SIPI). */ +#define VMX_EXIT_SIPI 4 +/** 5 I/O system-management interrupt (SMI). */ +#define VMX_EXIT_IO_SMI_IRQ 5 +/** 6 Other SMI. */ +#define VMX_EXIT_SMI_IRQ 6 +/** 7 Interrupt window. */ +#define VMX_EXIT_IRQ_WINDOW 7 +/** 9 Task switch. */ +#define VMX_EXIT_TASK_SWITCH 9 +/** 10 Guest software attempted to execute CPUID. */ +#define VMX_EXIT_CPUID 10 +/** 12 Guest software attempted to execute HLT. */ +#define VMX_EXIT_HLT 12 +/** 13 Guest software attempted to execute INVD. */ +#define VMX_EXIT_INVD 13 +/** 14 Guest software attempted to execute INVLPG. */ +#define VMX_EXIT_INVLPG 14 +/** 15 Guest software attempted to execute RDPMC. */ +#define VMX_EXIT_RDPMC 15 +/** 16 Guest software attempted to execute RDTSC. */ +#define VMX_EXIT_RDTSC 16 +/** 17 Guest software attempted to execute RSM in SMM. */ +#define VMX_EXIT_RSM 17 +/** 18 Guest software executed VMCALL. */ +#define VMX_EXIT_VMCALL 18 +/** 19 Guest software executed VMCLEAR. */ +#define VMX_EXIT_VMCLEAR 19 +/** 20 Guest software executed VMLAUNCH. */ +#define VMX_EXIT_VMLAUNCH 20 +/** 21 Guest software executed VMPTRLD. */ +#define VMX_EXIT_VMPTRLD 21 +/** 22 Guest software executed VMPTRST. */ +#define VMX_EXIT_VMPTRST 22 +/** 23 Guest software executed VMREAD. */ +#define VMX_EXIT_VMREAD 23 +/** 24 Guest software executed VMRESUME. */ +#define VMX_EXIT_VMRESUME 24 +/** 25 Guest software executed VMWRITE. */ +#define VMX_EXIT_VMWRITE 25 +/** 26 Guest software executed VMXOFF. */ +#define VMX_EXIT_VMXOFF 26 +/** 27 Guest software executed VMXON. */ +#define VMX_EXIT_VMXON 27 +/** 28 Control-register accesses. */ +#define VMX_EXIT_CRX_MOVE 28 +/** 29 Debug-register accesses. */ +#define VMX_EXIT_DRX_MOVE 29 +/** 30 I/O instruction. */ +#define VMX_EXIT_PORT_IO 30 +/** 31 RDMSR. Guest software attempted to execute RDMSR. */ +#define VMX_EXIT_RDMSR 31 +/** 32 WRMSR. Guest software attempted to execute WRMSR. */ +#define VMX_EXIT_WRMSR 32 +/** 33 VM-entry failure due to invalid guest state. */ +#define VMX_EXIT_ERR_INVALID_GUEST_STATE 33 +/** 34 VM-entry failure due to MSR loading. */ +#define VMX_EXIT_ERR_MSR_LOAD 34 +/** 36 Guest software executed MWAIT. */ +#define VMX_EXIT_MWAIT 36 +/** 37 VM exit due to monitor trap flag. */ +#define VMX_EXIT_MTF 37 +/** 39 Guest software attempted to execute MONITOR. */ +#define VMX_EXIT_MONITOR 39 +/** 40 Guest software attempted to execute PAUSE. */ +#define VMX_EXIT_PAUSE 40 +/** 41 VM-entry failure due to machine-check. */ +#define VMX_EXIT_ERR_MACHINE_CHECK 41 +/** 43 TPR below threshold. Guest software executed MOV to CR8. */ +#define VMX_EXIT_TPR 43 +/** 44 APIC access. Guest software attempted to access memory at a physical address on the APIC-access page. */ +#define VMX_EXIT_APIC_ACCESS 44 +/** 46 Access to GDTR or IDTR. Guest software attempted to execute LGDT, LIDT, SGDT, or SIDT. */ +#define VMX_EXIT_XDTR_ACCESS 46 +/** 47 Access to LDTR or TR. Guest software attempted to execute LLDT, LTR, SLDT, or STR. */ +#define VMX_EXIT_TR_ACCESS 47 +/** 48 EPT violation. An attempt to access memory with a guest-physical address was disallowed by the configuration of the EPT paging structures. */ +#define VMX_EXIT_EPT_VIOLATION 48 +/** 49 EPT misconfiguration. An attempt to access memory with a guest-physical address encountered a misconfigured EPT paging-structure entry. */ +#define VMX_EXIT_EPT_MISCONFIG 49 +/** 50 INVEPT. Guest software attempted to execute INVEPT. */ +#define VMX_EXIT_INVEPT 50 +/** 51 RDTSCP. Guest software attempted to execute RDTSCP. */ +#define VMX_EXIT_RDTSCP 51 +/** 52 VMX-preemption timer expired. The preemption timer counted down to zero. */ +#define VMX_EXIT_PREEMPTION_TIMER 52 +/** 53 INVVPID. Guest software attempted to execute INVVPID. */ +#define VMX_EXIT_INVVPID 53 +/** 54 WBINVD. Guest software attempted to execute WBINVD. */ +#define VMX_EXIT_WBINVD 54 +/** 55 XSETBV. Guest software attempted to execute XSETBV. */ +#define VMX_EXIT_XSETBV 55 +/** @} */ + + +/** @name VM Instruction Errors + * @{ + */ +/** 1 VMCALL executed in VMX root operation. */ +#define VMX_ERROR_VMCALL 1 +/** 2 VMCLEAR with invalid physical address. */ +#define VMX_ERROR_VMCLEAR_INVALID_PHYS_ADDR 2 +/** 3 VMCLEAR with VMXON pointer. */ +#define VMX_ERROR_VMCLEAR_INVALID_VMXON_PTR 3 +/** 4 VMLAUNCH with non-clear VMCS. */ +#define VMX_ERROR_VMLAUCH_NON_CLEAR_VMCS 4 +/** 5 VMRESUME with non-launched VMCS. */ +#define VMX_ERROR_VMRESUME_NON_LAUNCHED_VMCS 5 +/** 6 VMRESUME with a corrupted VMCS (indicates corruption of the current VMCS). */ +#define VMX_ERROR_VMRESUME_CORRUPTED_VMCS 6 +/** 7 VM entry with invalid control field(s). */ +#define VMX_ERROR_VMENTRY_INVALID_CONTROL_FIELDS 7 +/** 8 VM entry with invalid host-state field(s). */ +#define VMX_ERROR_VMENTRY_INVALID_HOST_STATE 8 +/** 9 VMPTRLD with invalid physical address. */ +#define VMX_ERROR_VMPTRLD_INVALID_PHYS_ADDR 9 +/** 10 VMPTRLD with VMXON pointer. */ +#define VMX_ERROR_VMPTRLD_VMXON_PTR 10 +/** 11 VMPTRLD with incorrect VMCS revision identifier. */ +#define VMX_ERROR_VMPTRLD_WRONG_VMCS_REVISION 11 +/** 12 VMREAD/VMWRITE from/to unsupported VMCS component. */ +#define VMX_ERROR_VMREAD_INVALID_COMPONENT 12 +#define VMX_ERROR_VMWRITE_INVALID_COMPONENT VMX_ERROR_VMREAD_INVALID_COMPONENT +/** 13 VMWRITE to read-only VMCS component. */ +#define VMX_ERROR_VMWRITE_READONLY_COMPONENT 13 +/** 15 VMXON executed in VMX root operation. */ +#define VMX_ERROR_VMXON_IN_VMX_ROOT_OP 15 +/** 16 VM entry with invalid executive-VMCS pointer. */ +#define VMX_ERROR_VMENTRY_INVALID_VMCS_EXEC_PTR 16 +/** 17 VM entry with non-launched executive VMCS. */ +#define VMX_ERROR_VMENTRY_NON_LAUNCHED_EXEC_VMCS 17 +/** 18 VM entry with executive-VMCS pointer not VMXON pointer. */ +#define VMX_ERROR_VMENTRY_EXEC_VMCS_PTR 18 +/** 19 VMCALL with non-clear VMCS. */ +#define VMX_ERROR_VMCALL_NON_CLEAR_VMCS 19 +/** 20 VMCALL with invalid VM-exit control fields. */ +#define VMX_ERROR_VMCALL_INVALID_VMEXIT_FIELDS 20 +/** 22 VMCALL with incorrect MSEG revision identifier. */ +#define VMX_ERROR_VMCALL_INVALID_MSEG_REVISION 22 +/** 23 VMXOFF under dual-monitor treatment of SMIs and SMM. */ +#define VMX_ERROR_VMXOFF_DUAL_MONITOR 23 +/** 24 VMCALL with invalid SMM-monitor features. */ +#define VMX_ERROR_VMCALL_INVALID_SMM_MONITOR 24 +/** 25 VM entry with invalid VM-execution control fields in executive VMCS. */ +#define VMX_ERROR_VMENTRY_INVALID_VM_EXEC_CTRL 25 +/** 26 VM entry with events blocked by MOV SS. */ +#define VMX_ERROR_VMENTRY_MOV_SS 26 +/** 26 Invalid operand to INVEPT/INVVPID. */ +#define VMX_ERROR_INVEPTVPID_INVALID_OPERAND 28 + +/** @} */ + + +/** @name VMX MSRs - Basic VMX information. + * @{ + */ +/** VMCS revision identifier used by the processor. */ +#define MSR_IA32_VMX_BASIC_INFO_VMCS_ID(a) (a & 0x7FFFFFFF) +/** Size of the VMCS. */ +#define MSR_IA32_VMX_BASIC_INFO_VMCS_SIZE(a) (((a) >> 32) & 0xFFF) +/** Width of physical address used for the VMCS. + * 0 -> limited to the available amount of physical ram + * 1 -> within the first 4 GB + */ +#define MSR_IA32_VMX_BASIC_INFO_VMCS_PHYS_WIDTH(a) (((a) >> 48) & 1) +/** Whether the processor supports the dual-monitor treatment of system-management interrupts and system-management code. (always 1) */ +#define MSR_IA32_VMX_BASIC_INFO_VMCS_DUAL_MON(a) (((a) >> 49) & 1) +/** Memory type that must be used for the VMCS. */ +#define MSR_IA32_VMX_BASIC_INFO_VMCS_MEM_TYPE(a) (((a) >> 50) & 0xF) +/** @} */ + + +/** @name VMX MSRs - Misc VMX info. + * @{ + */ +/** Relationship between the preemption timer and tsc; count down every time bit x of the tsc changes. */ +#define MSR_IA32_VMX_MISC_PREEMPT_TSC_BIT(a) ((a) & 0x1f) +/** Activity states supported by the implementation. */ +#define MSR_IA32_VMX_MISC_ACTIVITY_STATES(a) (((a) >> 6) & 0x7) +/** Number of CR3 target values supported by the processor. (0-256) */ +#define MSR_IA32_VMX_MISC_CR3_TARGET(a) (((a) >> 16) & 0x1FF) +/** Maximum nr of MSRs in the VMCS. (N+1)*512. */ +#define MSR_IA32_VMX_MISC_MAX_MSR(a) (((((a) >> 25) & 0x7) + 1) * 512) +/** MSEG revision identifier used by the processor. */ +#define MSR_IA32_VMX_MISC_MSEG_ID(a) ((a) >> 32) +/** @} */ + + +/** @name VMX MSRs - VMCS enumeration field info + * @{ + */ +/** Highest field index. */ +#define MSR_IA32_VMX_VMCS_ENUM_HIGHEST_INDEX(a) (((a) >> 1) & 0x1FF) + +/** @} */ + + +/** @name MSR_IA32_VMX_EPT_CAPS; EPT capabilities MSR + * @{ + */ +#define MSR_IA32_VMX_EPT_CAPS_RWX_X_ONLY RT_BIT_64(0) +#define MSR_IA32_VMX_EPT_CAPS_RWX_W_ONLY RT_BIT_64(1) +#define MSR_IA32_VMX_EPT_CAPS_RWX_WX_ONLY RT_BIT_64(2) +#define MSR_IA32_VMX_EPT_CAPS_GAW_21_BITS RT_BIT_64(3) +#define MSR_IA32_VMX_EPT_CAPS_GAW_30_BITS RT_BIT_64(4) +#define MSR_IA32_VMX_EPT_CAPS_GAW_39_BITS RT_BIT_64(5) +#define MSR_IA32_VMX_EPT_CAPS_GAW_48_BITS RT_BIT_64(6) +#define MSR_IA32_VMX_EPT_CAPS_GAW_57_BITS RT_BIT_64(7) +#define MSR_IA32_VMX_EPT_CAPS_EMT_UC RT_BIT_64(8) +#define MSR_IA32_VMX_EPT_CAPS_EMT_WC RT_BIT_64(9) +#define MSR_IA32_VMX_EPT_CAPS_EMT_WT RT_BIT_64(12) +#define MSR_IA32_VMX_EPT_CAPS_EMT_WP RT_BIT_64(13) +#define MSR_IA32_VMX_EPT_CAPS_EMT_WB RT_BIT_64(14) +#define MSR_IA32_VMX_EPT_CAPS_SP_21_BITS RT_BIT_64(16) +#define MSR_IA32_VMX_EPT_CAPS_SP_30_BITS RT_BIT_64(17) +#define MSR_IA32_VMX_EPT_CAPS_SP_39_BITS RT_BIT_64(18) +#define MSR_IA32_VMX_EPT_CAPS_SP_48_BITS RT_BIT_64(19) +#define MSR_IA32_VMX_EPT_CAPS_INVEPT RT_BIT_64(20) +#define MSR_IA32_VMX_EPT_CAPS_INVEPT_CAPS_SINGLE_CONTEXT RT_BIT_64(25) +#define MSR_IA32_VMX_EPT_CAPS_INVEPT_CAPS_ALL_CONTEXTS RT_BIT_64(26) +#define MSR_IA32_VMX_EPT_CAPS_INVVPID RT_BIT_64(32) +#define MSR_IA32_VMX_EPT_CAPS_INVVPID_CAPS_INDIV_ADDR RT_BIT_64(40) +#define MSR_IA32_VMX_EPT_CAPS_INVVPID_CAPS_SINGLE_CONTEXT RT_BIT_64(41) +#define MSR_IA32_VMX_EPT_CAPS_INVVPID_CAPS_ALL_CONTEXTS RT_BIT_64(42) +#define MSR_IA32_VMX_EPT_CAPS_INVVPID_CAPS_SINGLE_CONTEXT_RETAIN_GLOBALS RT_BIT_64(43) + +/** @} */ + +/** @name Extended Page Table Pointer (EPTP) + * @{ + */ +/** Uncachable EPT paging structure memory type. */ +#define VMX_EPT_MEMTYPE_UC 0 +/** Write-back EPT paging structure memory type. */ +#define VMX_EPT_MEMTYPE_WB 6 +/** Shift value to get the EPT page walk length (bits 5-3) */ +#define VMX_EPT_PAGE_WALK_LENGTH_SHIFT 3 +/** Mask value to get the EPT page walk length (bits 5-3) */ +#define VMX_EPT_PAGE_WALK_LENGTH_MASK 7 +/** Default EPT page walk length */ +#define VMX_EPT_PAGE_WALK_LENGTH_DEFAULT 3 +/** @} */ + + +/** @name VMCS field encoding - 16 bits guest fields + * @{ + */ +#define VMX_VMCS16_GUEST_FIELD_VPID 0x0 +#define VMX_VMCS16_GUEST_FIELD_ES 0x800 +#define VMX_VMCS16_GUEST_FIELD_CS 0x802 +#define VMX_VMCS16_GUEST_FIELD_SS 0x804 +#define VMX_VMCS16_GUEST_FIELD_DS 0x806 +#define VMX_VMCS16_GUEST_FIELD_FS 0x808 +#define VMX_VMCS16_GUEST_FIELD_GS 0x80A +#define VMX_VMCS16_GUEST_FIELD_LDTR 0x80C +#define VMX_VMCS16_GUEST_FIELD_TR 0x80E +/** @} */ + +/** @name VMCS field encoding - 16 bits host fields + * @{ + */ +#define VMX_VMCS16_HOST_FIELD_ES 0xC00 +#define VMX_VMCS16_HOST_FIELD_CS 0xC02 +#define VMX_VMCS16_HOST_FIELD_SS 0xC04 +#define VMX_VMCS16_HOST_FIELD_DS 0xC06 +#define VMX_VMCS16_HOST_FIELD_FS 0xC08 +#define VMX_VMCS16_HOST_FIELD_GS 0xC0A +#define VMX_VMCS16_HOST_FIELD_TR 0xC0C +/** @} */ + +/** @name VMCS field encoding - 64 bits host fields + * @{ + */ +#define VMX_VMCS_HOST_FIELD_PAT_FULL 0x2C00 +#define VMX_VMCS_HOST_FIELD_PAT_HIGH 0x2C01 +#define VMX_VMCS_HOST_FIELD_EFER_FULL 0x2C02 +#define VMX_VMCS_HOST_FIELD_EFER_HIGH 0x2C03 +#define VMX_VMCS_HOST_PERF_GLOBAL_CTRL_FULL 0x2C04 /**< MSR IA32_PERF_GLOBAL_CTRL */ +#define VMX_VMCS_HOST_PERF_GLOBAL_CTRL_HIGH 0x2C05 /**< MSR IA32_PERF_GLOBAL_CTRL */ +/** @} */ + + +/** @name VMCS field encoding - 64 Bits control fields + * @{ + */ +#define VMX_VMCS_CTRL_IO_BITMAP_A_FULL 0x2000 +#define VMX_VMCS_CTRL_IO_BITMAP_A_HIGH 0x2001 +#define VMX_VMCS_CTRL_IO_BITMAP_B_FULL 0x2002 +#define VMX_VMCS_CTRL_IO_BITMAP_B_HIGH 0x2003 + +/* Optional */ +#define VMX_VMCS_CTRL_MSR_BITMAP_FULL 0x2004 +#define VMX_VMCS_CTRL_MSR_BITMAP_HIGH 0x2005 + +#define VMX_VMCS_CTRL_VMEXIT_MSR_STORE_FULL 0x2006 +#define VMX_VMCS_CTRL_VMEXIT_MSR_STORE_HIGH 0x2007 +#define VMX_VMCS_CTRL_VMEXIT_MSR_LOAD_FULL 0x2008 +#define VMX_VMCS_CTRL_VMEXIT_MSR_LOAD_HIGH 0x2009 + +#define VMX_VMCS_CTRL_VMENTRY_MSR_LOAD_FULL 0x200A +#define VMX_VMCS_CTRL_VMENTRY_MSR_LOAD_HIGH 0x200B + +#define VMX_VMCS_CTRL_EXEC_VMCS_PTR_FULL 0x200C +#define VMX_VMCS_CTRL_EXEC_VMCS_PTR_HIGH 0x200D + +#define VMX_VMCS_CTRL_TSC_OFFSET_FULL 0x2010 +#define VMX_VMCS_CTRL_TSC_OFFSET_HIGH 0x2011 + +/** Optional (VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_USE_TPR_SHADOW) */ +#define VMX_VMCS_CTRL_VAPIC_PAGEADDR_FULL 0x2012 +#define VMX_VMCS_CTRL_VAPIC_PAGEADDR_HIGH 0x2013 + +/** Optional (VMX_VMCS_CTRL_PROC_EXEC2_VIRT_APIC) */ +#define VMX_VMCS_CTRL_APIC_ACCESSADDR_FULL 0x2014 +#define VMX_VMCS_CTRL_APIC_ACCESSADDR_HIGH 0x2015 + +/** Extended page table pointer. */ +#define VMX_VMCS_CTRL_EPTP_FULL 0x201a +#define VMX_VMCS_CTRL_EPTP_HIGH 0x201b + +/** VM-exit phyiscal address. */ +#define VMX_VMCS_EXIT_PHYS_ADDR_FULL 0x2400 +#define VMX_VMCS_EXIT_PHYS_ADDR_HIGH 0x2401 +/** @} */ + + +/** @name VMCS field encoding - 64 Bits guest fields + * @{ + */ +#define VMX_VMCS_GUEST_LINK_PTR_FULL 0x2800 +#define VMX_VMCS_GUEST_LINK_PTR_HIGH 0x2801 +#define VMX_VMCS_GUEST_DEBUGCTL_FULL 0x2802 /**< MSR IA32_DEBUGCTL */ +#define VMX_VMCS_GUEST_DEBUGCTL_HIGH 0x2803 /**< MSR IA32_DEBUGCTL */ +#define VMX_VMCS_GUEST_PAT_FULL 0x2804 +#define VMX_VMCS_GUEST_PAT_HIGH 0x2805 +#define VMX_VMCS_GUEST_EFER_FULL 0x2806 +#define VMX_VMCS_GUEST_EFER_HIGH 0x2807 +#define VMX_VMCS_GUEST_PERF_GLOBAL_CTRL_FULL 0x2808 /**< MSR IA32_PERF_GLOBAL_CTRL */ +#define VMX_VMCS_GUEST_PERF_GLOBAL_CTRL_HIGH 0x2809 /**< MSR IA32_PERF_GLOBAL_CTRL */ +#define VMX_VMCS_GUEST_PDPTR0_FULL 0x280A +#define VMX_VMCS_GUEST_PDPTR0_HIGH 0x280B +#define VMX_VMCS_GUEST_PDPTR1_FULL 0x280C +#define VMX_VMCS_GUEST_PDPTR1_HIGH 0x280D +#define VMX_VMCS_GUEST_PDPTR2_FULL 0x280E +#define VMX_VMCS_GUEST_PDPTR2_HIGH 0x280F +#define VMX_VMCS_GUEST_PDPTR3_FULL 0x2810 +#define VMX_VMCS_GUEST_PDPTR3_HIGH 0x2811 +/** @} */ + + +/** @name VMCS field encoding - 32 Bits control fields + * @{ + */ +#define VMX_VMCS_CTRL_PIN_EXEC_CONTROLS 0x4000 +#define VMX_VMCS_CTRL_PROC_EXEC_CONTROLS 0x4002 +#define VMX_VMCS_CTRL_EXCEPTION_BITMAP 0x4004 +#define VMX_VMCS_CTRL_PAGEFAULT_ERROR_MASK 0x4006 +#define VMX_VMCS_CTRL_PAGEFAULT_ERROR_MATCH 0x4008 +#define VMX_VMCS_CTRL_CR3_TARGET_COUNT 0x400A +#define VMX_VMCS_CTRL_EXIT_CONTROLS 0x400C +#define VMX_VMCS_CTRL_EXIT_MSR_STORE_COUNT 0x400E +#define VMX_VMCS_CTRL_EXIT_MSR_LOAD_COUNT 0x4010 +#define VMX_VMCS_CTRL_ENTRY_CONTROLS 0x4012 +#define VMX_VMCS_CTRL_ENTRY_MSR_LOAD_COUNT 0x4014 +#define VMX_VMCS_CTRL_ENTRY_IRQ_INFO 0x4016 +#define VMX_VMCS_CTRL_ENTRY_EXCEPTION_ERRCODE 0x4018 +#define VMX_VMCS_CTRL_ENTRY_INSTR_LENGTH 0x401A +/** This field exists only on processors that support the 1-setting of the “use TPR shadow” VM-execution control. */ +#define VMX_VMCS_CTRL_TPR_THRESHOLD 0x401C +/** This field exists only on processors that support the 1-setting of the “activate secondary controls” VM-execution control. */ +#define VMX_VMCS_CTRL_PROC_EXEC_CONTROLS2 0x401E +/** @} */ + + +/** @name VMX_VMCS_CTRL_PIN_EXEC_CONTROLS + * @{ + */ +/** External interrupts cause VM exits if set; otherwise dispatched through the guest's IDT. */ +#define VMX_VMCS_CTRL_PIN_EXEC_CONTROLS_EXT_INT_EXIT RT_BIT(0) +/** Non-maskable interrupts cause VM exits if set; otherwise dispatched through the guest's IDT. */ +#define VMX_VMCS_CTRL_PIN_EXEC_CONTROLS_NMI_EXIT RT_BIT(3) +/** Virtual NMIs. */ +#define VMX_VMCS_CTRL_PIN_EXEC_CONTROLS_VIRTUAL_NMI RT_BIT(5) +/** Activate VMX preemption timer. */ +#define VMX_VMCS_CTRL_PIN_EXEC_CONTROLS_PREEMPT_TIMER RT_BIT(6) +/* All other bits are reserved and must be set according to MSR IA32_VMX_PROCBASED_CTLS. */ +/** @} */ + +/** @name VMX_VMCS_CTRL_PROC_EXEC_CONTROLS + * @{ + */ +/** VM Exit as soon as RFLAGS.IF=1 and no blocking is active. */ +#define VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_IRQ_WINDOW_EXIT RT_BIT(2) +/** Use timestamp counter offset. */ +#define VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_TSC_OFFSET RT_BIT(3) +/** VM Exit when executing the HLT instruction. */ +#define VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_HLT_EXIT RT_BIT(7) +/** VM Exit when executing the INVLPG instruction. */ +#define VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_INVLPG_EXIT RT_BIT(9) +/** VM Exit when executing the MWAIT instruction. */ +#define VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_MWAIT_EXIT RT_BIT(10) +/** VM Exit when executing the RDPMC instruction. */ +#define VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_RDPMC_EXIT RT_BIT(11) +/** VM Exit when executing the RDTSC/RDTSCP instruction. */ +#define VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_RDTSC_EXIT RT_BIT(12) +/** VM Exit when executing the MOV to CR3 instruction. (forced to 1 on the 'first' VT-x capable CPUs; this actually includes the newest Nehalem CPUs) */ +#define VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_CR3_LOAD_EXIT RT_BIT(15) +/** VM Exit when executing the MOV from CR3 instruction. (forced to 1 on the 'first' VT-x capable CPUs; this actually includes the newest Nehalem CPUs) */ +#define VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_CR3_STORE_EXIT RT_BIT(16) +/** VM Exit on CR8 loads. */ +#define VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_CR8_LOAD_EXIT RT_BIT(19) +/** VM Exit on CR8 stores. */ +#define VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_CR8_STORE_EXIT RT_BIT(20) +/** Use TPR shadow. */ +#define VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_USE_TPR_SHADOW RT_BIT(21) +/** VM Exit when virtual nmi blocking is disabled. */ +#define VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_NMI_WINDOW_EXIT RT_BIT(22) +/** VM Exit when executing a MOV DRx instruction. */ +#define VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_MOV_DR_EXIT RT_BIT(23) +/** VM Exit when executing IO instructions. */ +#define VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_UNCOND_IO_EXIT RT_BIT(24) +/** Use IO bitmaps. */ +#define VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_USE_IO_BITMAPS RT_BIT(25) +/** Monitor trap flag. */ +#define VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_MONITOR_TRAP_FLAG RT_BIT(27) +/** Use MSR bitmaps. */ +#define VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_USE_MSR_BITMAPS RT_BIT(28) +/** VM Exit when executing the MONITOR instruction. */ +#define VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_MONITOR_EXIT RT_BIT(29) +/** VM Exit when executing the PAUSE instruction. */ +#define VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_PAUSE_EXIT RT_BIT(30) +/** Determines whether the secondary processor based VM-execution controls are used. */ +#define VMX_VMCS_CTRL_PROC_EXEC_USE_SECONDARY_EXEC_CTRL RT_BIT(31) +/** @} */ + +/** @name VMX_VMCS_CTRL_PROC_EXEC_CONTROLS2 + * @{ + */ +/** Virtualize APIC access. */ +#define VMX_VMCS_CTRL_PROC_EXEC2_VIRT_APIC RT_BIT(0) +/** EPT supported/enabled. */ +#define VMX_VMCS_CTRL_PROC_EXEC2_EPT RT_BIT(1) +/** Descriptor table instructions cause VM-exits. */ +#define VMX_VMCS_CTRL_PROC_EXEC2_DESCRIPTOR_INSTR_EXIT RT_BIT(2) +/** RDTSCP supported/enabled. */ +#define VMX_VMCS_CTRL_PROC_EXEC2_RDTSCP RT_BIT(3) +/** Virtualize x2APIC mode. */ +#define VMX_VMCS_CTRL_PROC_EXEC2_X2APIC RT_BIT(4) +/** VPID supported/enabled. */ +#define VMX_VMCS_CTRL_PROC_EXEC2_VPID RT_BIT(5) +/** VM Exit when executing the WBINVD instruction. */ +#define VMX_VMCS_CTRL_PROC_EXEC2_WBINVD_EXIT RT_BIT(6) +/** Unrestricted guest execution. */ +#define VMX_VMCS_CTRL_PROC_EXEC2_REAL_MODE RT_BIT(7) +/** A specified nr of pause loops cause a VM-exit. */ +#define VMX_VMCS_CTRL_PROC_EXEC2_PAUSE_LOOP_EXIT RT_BIT(10) +/** @} */ + + +/** @name VMX_VMCS_CTRL_ENTRY_CONTROLS + * @{ + */ +/** Load guest debug controls (dr7 & IA32_DEBUGCTL_MSR) (forced to 1 on the 'first' VT-x capable CPUs; this actually includes the newest Nehalem CPUs) */ +#define VMX_VMCS_CTRL_ENTRY_CONTROLS_LOAD_DEBUG RT_BIT(2) +/** 64 bits guest mode. Must be 0 for CPUs that don't support AMD64. */ +#define VMX_VMCS_CTRL_ENTRY_CONTROLS_IA64_MODE RT_BIT(9) +/** In SMM mode after VM-entry. */ +#define VMX_VMCS_CTRL_ENTRY_CONTROLS_ENTRY_SMM RT_BIT(10) +/** Disable dual treatment of SMI and SMM; must be zero for VM-entry outside of SMM. */ +#define VMX_VMCS_CTRL_ENTRY_CONTROLS_DEACTIVATE_DUALMON RT_BIT(11) +/** This control determines whether the guest IA32_PERF_GLOBAL_CTRL MSR is loaded on VM entry. */ +#define VMX_VMCS_CTRL_ENTRY_CONTROLS_LOAD_GUEST_PERF_MSR RT_BIT(13) +/** This control determines whether the guest IA32_PAT MSR is loaded on VM entry. */ +#define VMX_VMCS_CTRL_ENTRY_CONTROLS_LOAD_GUEST_PAT_MSR RT_BIT(14) +/** This control determines whether the guest IA32_EFER MSR is loaded on VM entry. */ +#define VMX_VMCS_CTRL_ENTRY_CONTROLS_LOAD_GUEST_EFER_MSR RT_BIT(15) +/** @} */ + + +/** @name VMX_VMCS_CTRL_EXIT_CONTROLS + * @{ + */ +/** Save guest debug controls (dr7 & IA32_DEBUGCTL_MSR) (forced to 1 on the 'first' VT-x capable CPUs; this actually includes the newest Nehalem CPUs) */ +#define VMX_VMCS_CTRL_EXIT_CONTROLS_SAVE_DEBUG RT_BIT(2) +/** Return to long mode after a VM-exit. */ +#define VMX_VMCS_CTRL_EXIT_CONTROLS_HOST_AMD64 RT_BIT(9) +/** This control determines whether the IA32_PERF_GLOBAL_CTRL MSR is loaded on VM exit. */ +#define VMX_VMCS_CTRL_EXIT_CONTROLS_LOAD_PERF_MSR RT_BIT(12) +/** Acknowledge external interrupts with the irq controller if one caused a VM-exit. */ +#define VMX_VMCS_CTRL_EXIT_CONTROLS_ACK_EXTERNAL_IRQ RT_BIT(15) +/** This control determines whether the guest IA32_PAT MSR is saved on VM exit. */ +#define VMX_VMCS_CTRL_EXIT_CONTROLS_SAVE_GUEST_PAT_MSR RT_BIT(18) +/** This control determines whether the host IA32_PAT MSR is loaded on VM exit. */ +#define VMX_VMCS_CTRL_EXIT_CONTROLS_LOAD_HOST_PAT_MSR RT_BIT(19) +/** This control determines whether the guest IA32_EFER MSR is saved on VM exit. */ +#define VMX_VMCS_CTRL_EXIT_CONTROLS_SAVE_GUEST_EFER_MSR RT_BIT(20) +/** This control determines whether the host IA32_EFER MSR is loaded on VM exit. */ +#define VMX_VMCS_CTRL_EXIT_CONTROLS_LOAD_HOST_EFER_MSR RT_BIT(21) +/** This control determines whether the value of the VMX preemption timer is saved on VM exit. */ +#define VMX_VMCS_CTRL_EXIT_CONTROLS_SAVE_VMX_PREEMPT_TIMER RT_BIT(22) +/** @} */ + +/** @name VMCS field encoding - 32 Bits read-only fields + * @{ + */ +#define VMX_VMCS32_RO_VM_INSTR_ERROR 0x4400 +#define VMX_VMCS32_RO_EXIT_REASON 0x4402 +#define VMX_VMCS32_RO_EXIT_INTERRUPTION_INFO 0x4404 +#define VMX_VMCS32_RO_EXIT_INTERRUPTION_ERRCODE 0x4406 +#define VMX_VMCS32_RO_IDT_INFO 0x4408 +#define VMX_VMCS32_RO_IDT_ERRCODE 0x440A +#define VMX_VMCS32_RO_EXIT_INSTR_LENGTH 0x440C +#define VMX_VMCS32_RO_EXIT_INSTR_INFO 0x440E +/** @} */ + +/** @name VMX_VMCS_RO_EXIT_INTERRUPTION_INFO + * @{ + */ +#define VMX_EXIT_INTERRUPTION_INFO_VECTOR(a) (a & 0xff) +#define VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT 8 +#define VMX_EXIT_INTERRUPTION_INFO_TYPE(a) ((a >> VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT) & 7) +#define VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID RT_BIT(11) +#define VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_IS_VALID(a) (a & VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID) +#define VMX_EXIT_INTERRUPTION_INFO_NMI_UNBLOCK(a) (a & RT_BIT(12)) +#define VMX_EXIT_INTERRUPTION_INFO_VALID_SHIFT 31 +#define VMX_EXIT_INTERRUPTION_INFO_VALID(a) (a & RT_BIT(31)) +/** Construct an irq event injection value from the exit interruption info value (same except that bit 12 is reserved). */ +#define VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(a) (a & ~RT_BIT(12)) +/** @} */ + +/** @name VMX_VMCS_RO_EXIT_INTERRUPTION_INFO_TYPE + * @{ + */ +#define VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT 0 +#define VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI 2 +#define VMX_EXIT_INTERRUPTION_INFO_TYPE_HWEXCPT 3 +#define VMX_EXIT_INTERRUPTION_INFO_TYPE_SW 4 /**< int xx */ +#define VMX_EXIT_INTERRUPTION_INFO_TYPE_DBEXCPT 5 /**< Why are we getting this one?? */ +#define VMX_EXIT_INTERRUPTION_INFO_TYPE_SWEXCPT 6 +/** @} */ + + +/** @name VMCS field encoding - 32 Bits guest state fields + * @{ + */ +#define VMX_VMCS32_GUEST_ES_LIMIT 0x4800 +#define VMX_VMCS32_GUEST_CS_LIMIT 0x4802 +#define VMX_VMCS32_GUEST_SS_LIMIT 0x4804 +#define VMX_VMCS32_GUEST_DS_LIMIT 0x4806 +#define VMX_VMCS32_GUEST_FS_LIMIT 0x4808 +#define VMX_VMCS32_GUEST_GS_LIMIT 0x480A +#define VMX_VMCS32_GUEST_LDTR_LIMIT 0x480C +#define VMX_VMCS32_GUEST_TR_LIMIT 0x480E +#define VMX_VMCS32_GUEST_GDTR_LIMIT 0x4810 +#define VMX_VMCS32_GUEST_IDTR_LIMIT 0x4812 +#define VMX_VMCS32_GUEST_ES_ACCESS_RIGHTS 0x4814 +#define VMX_VMCS32_GUEST_CS_ACCESS_RIGHTS 0x4816 +#define VMX_VMCS32_GUEST_SS_ACCESS_RIGHTS 0x4818 +#define VMX_VMCS32_GUEST_DS_ACCESS_RIGHTS 0x481A +#define VMX_VMCS32_GUEST_FS_ACCESS_RIGHTS 0x481C +#define VMX_VMCS32_GUEST_GS_ACCESS_RIGHTS 0x481E +#define VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS 0x4820 +#define VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS 0x4822 +#define VMX_VMCS32_GUEST_INTERRUPTIBILITY_STATE 0x4824 +#define VMX_VMCS32_GUEST_ACTIVITY_STATE 0x4826 +#define VMX_VMCS32_GUEST_SYSENTER_CS 0x482A /**< MSR IA32_SYSENTER_CS */ +#define VMX_VMCS32_GUEST_PREEMPTION_TIMER_VALUE 0x482E +/** @} */ + + +/** @name VMX_VMCS_GUEST_ACTIVITY_STATE + * @{ + */ +/** The logical processor is active. */ +#define VMX_CMS_GUEST_ACTIVITY_ACTIVE 0x0 +/** The logical processor is inactive, because executed a HLT instruction. */ +#define VMX_CMS_GUEST_ACTIVITY_HLT 0x1 +/** The logical processor is inactive, because of a triple fault or other serious error. */ +#define VMX_CMS_GUEST_ACTIVITY_SHUTDOWN 0x2 +/** The logical processor is inactive, because it's waiting for a startup-IPI */ +#define VMX_CMS_GUEST_ACTIVITY_SIPI_WAIT 0x3 +/** @} */ + + +/** @name VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE + * @{ + */ +#define VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI RT_BIT(0) +#define VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS RT_BIT(1) +#define VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_SMI RT_BIT(2) +#define VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_NMI RT_BIT(3) +/** @} */ + + +/** @name VMCS field encoding - 32 Bits host state fields + * @{ + */ +#define VMX_VMCS32_HOST_SYSENTER_CS 0x4C00 +/** @} */ + +/** @name Natural width control fields + * @{ + */ +#define VMX_VMCS_CTRL_CR0_MASK 0x6000 +#define VMX_VMCS_CTRL_CR4_MASK 0x6002 +#define VMX_VMCS_CTRL_CR0_READ_SHADOW 0x6004 +#define VMX_VMCS_CTRL_CR4_READ_SHADOW 0x6006 +#define VMX_VMCS_CTRL_CR3_TARGET_VAL0 0x6008 +#define VMX_VMCS_CTRL_CR3_TARGET_VAL1 0x600A +#define VMX_VMCS_CTRL_CR3_TARGET_VAL2 0x600C +#define VMX_VMCS_CTRL_CR3_TARGET_VAL31 0x600E +/** @} */ + + +/** @name Natural width read-only data fields + * @{ + */ +#define VMX_VMCS_RO_EXIT_QUALIFICATION 0x6400 +#define VMX_VMCS_RO_IO_RCX 0x6402 +#define VMX_VMCS_RO_IO_RSX 0x6404 +#define VMX_VMCS_RO_IO_RDI 0x6406 +#define VMX_VMCS_RO_IO_RIP 0x6408 +#define VMX_VMCS_EXIT_GUEST_LINEAR_ADDR 0x640A +/** @} */ + + +/** @name VMX_VMCS_RO_EXIT_QUALIFICATION + * @{ + */ +/** 0-2: Debug register number */ +#define VMX_EXIT_QUALIFICATION_DRX_REGISTER(a) (a & 7) +/** 3: Reserved; cleared to 0. */ +#define VMX_EXIT_QUALIFICATION_DRX_RES1(a) ((a >> 3) & 1) +/** 4: Direction of move (0 = write, 1 = read) */ +#define VMX_EXIT_QUALIFICATION_DRX_DIRECTION(a) ((a >> 4) & 1) +/** 5-7: Reserved; cleared to 0. */ +#define VMX_EXIT_QUALIFICATION_DRX_RES2(a) ((a >> 5) & 7) +/** 8-11: General purpose register number. */ +#define VMX_EXIT_QUALIFICATION_DRX_GENREG(a) ((a >> 8) & 0xF) +/** Rest: reserved. */ +/** @} */ + +/** @name VMX_EXIT_QUALIFICATION_DRX_DIRECTION values + * @{ + */ +#define VMX_EXIT_QUALIFICATION_DRX_DIRECTION_WRITE 0 +#define VMX_EXIT_QUALIFICATION_DRX_DIRECTION_READ 1 +/** @} */ + + + +/** @name CRx accesses + * @{ + */ +/** 0-3: Control register number (0 for CLTS & LMSW) */ +#define VMX_EXIT_QUALIFICATION_CRX_REGISTER(a) (a & 0xF) +/** 4-5: Access type. */ +#define VMX_EXIT_QUALIFICATION_CRX_ACCESS(a) ((a >> 4) & 3) +/** 6: LMSW operand type */ +#define VMX_EXIT_QUALIFICATION_CRX_LMSW_OP(a) ((a >> 6) & 1) +/** 7: Reserved; cleared to 0. */ +#define VMX_EXIT_QUALIFICATION_CRX_RES1(a) ((a >> 7) & 1) +/** 8-11: General purpose register number (0 for CLTS & LMSW). */ +#define VMX_EXIT_QUALIFICATION_CRX_GENREG(a) ((a >> 8) & 0xF) +/** 12-15: Reserved; cleared to 0. */ +#define VMX_EXIT_QUALIFICATION_CRX_RES2(a) ((a >> 12) & 0xF) +/** 16-31: LMSW source data (else 0). */ +#define VMX_EXIT_QUALIFICATION_CRX_LMSW_DATA(a) ((a >> 16) & 0xFFFF) +/** Rest: reserved. */ +/** @} */ + +/** @name VMX_EXIT_QUALIFICATION_CRX_ACCESS + * @{ + */ +#define VMX_EXIT_QUALIFICATION_CRX_ACCESS_WRITE 0 +#define VMX_EXIT_QUALIFICATION_CRX_ACCESS_READ 1 +#define VMX_EXIT_QUALIFICATION_CRX_ACCESS_CLTS 2 +#define VMX_EXIT_QUALIFICATION_CRX_ACCESS_LMSW 3 +/** @} */ + +/** @name VMX_EXIT_QUALIFICATION_TASK_SWITCH + * @{ + */ +#define VMX_EXIT_QUALIFICATION_TASK_SWITCH_SELECTOR(a) (a & 0xffff) +#define VMX_EXIT_QUALIFICATION_TASK_SWITCH_TYPE(a) ((a >> 30)& 0x3) +/** Task switch caused by a call instruction. */ +#define VMX_EXIT_QUALIFICATION_TASK_SWITCH_TYPE_CALL 0 +/** Task switch caused by an iret instruction. */ +#define VMX_EXIT_QUALIFICATION_TASK_SWITCH_TYPE_IRET 1 +/** Task switch caused by a jmp instruction. */ +#define VMX_EXIT_QUALIFICATION_TASK_SWITCH_TYPE_JMP 2 +/** Task switch caused by an interrupt gate. */ +#define VMX_EXIT_QUALIFICATION_TASK_SWITCH_TYPE_IDT 3 + +/** @} */ + + +/** @name VMX_EXIT_EPT_VIOLATION + * @{ + */ +/** Set if the violation was caused by a data read. */ +#define VMX_EXIT_QUALIFICATION_EPT_DATA_READ RT_BIT(0) +/** Set if the violation was caused by a data write. */ +#define VMX_EXIT_QUALIFICATION_EPT_DATA_WRITE RT_BIT(1) +/** Set if the violation was caused by an insruction fetch. */ +#define VMX_EXIT_QUALIFICATION_EPT_INSTR_FETCH RT_BIT(2) +/** AND of the present bit of all EPT structures. */ +#define VMX_EXIT_QUALIFICATION_EPT_ENTRY_PRESENT RT_BIT(3) +/** AND of the write bit of all EPT structures. */ +#define VMX_EXIT_QUALIFICATION_EPT_ENTRY_WRITE RT_BIT(4) +/** AND of the execute bit of all EPT structures. */ +#define VMX_EXIT_QUALIFICATION_EPT_ENTRY_EXECUTE RT_BIT(5) +/** Set if the guest linear address field contains the faulting address. */ +#define VMX_EXIT_QUALIFICATION_EPT_GUEST_ADDR_VALID RT_BIT(7) +/** If bit 7 is one: (reserved otherwise) + * 1 - violation due to physical address access. + * 0 - violation caused by page walk or access/dirty bit updates + */ +#define VMX_EXIT_QUALIFICATION_EPT_TRANSLATED_ACCESS RT_BIT(8) +/** @} */ + + +/** @name VMX_EXIT_PORT_IO + * @{ + */ +/** 0-2: IO operation width. */ +#define VMX_EXIT_QUALIFICATION_IO_WIDTH(a) (a & 7) +/** 3: IO operation direction. */ +#define VMX_EXIT_QUALIFICATION_IO_DIRECTION(a) ((a >> 3) & 1) +/** 4: String IO operation. */ +#define VMX_EXIT_QUALIFICATION_IO_STRING(a) ((a >> 4) & 1) +/** 5: Repeated IO operation. */ +#define VMX_EXIT_QUALIFICATION_IO_REP(a) ((a >> 5) & 1) +/** 6: Operand encoding. */ +#define VMX_EXIT_QUALIFICATION_IO_ENCODING(a) ((a >> 6) & 1) +/** 16-31: IO Port (0-0xffff). */ +#define VMX_EXIT_QUALIFICATION_IO_PORT(a) ((a >> 16) & 0xffff) +/* Rest reserved. */ +/** @} */ + +/** @name VMX_EXIT_QUALIFICATION_IO_DIRECTION + * @{ + */ +#define VMX_EXIT_QUALIFICATION_IO_DIRECTION_OUT 0 +#define VMX_EXIT_QUALIFICATION_IO_DIRECTION_IN 1 +/** @} */ + + +/** @name VMX_EXIT_QUALIFICATION_IO_ENCODING + * @{ + */ +#define VMX_EXIT_QUALIFICATION_IO_ENCODING_DX 0 +#define VMX_EXIT_QUALIFICATION_IO_ENCODING_IMM 1 +/** @} */ + +/** @name VMX_EXIT_APIC_ACCESS + * @{ + */ +/** 0-11: If the APIC-access VM exit is due to a linear access, the offset of access within the APIC page. */ +#define VMX_EXIT_QUALIFICATION_APIC_ACCESS_OFFSET(a) (a & 0xfff) +/** 12-15: Access type. */ +#define VMX_EXIT_QUALIFICATION_APIC_ACCESS_TYPE(a) ((a >> 12) & 0xf) +/* Rest reserved. */ +/** @} */ + + +/** @name VMX_EXIT_QUALIFICATION_APIC_ACCESS_TYPE; access types + * @{ + */ +/** Linear read access. */ +#define VMX_APIC_ACCESS_TYPE_LINEAR_READ 0 +/** Linear write access. */ +#define VMX_APIC_ACCESS_TYPE_LINEAR_WRITE 1 +/** Linear instruction fetch access. */ +#define VMX_APIC_ACCESS_TYPE_LINEAR_INSTR_FETCH 2 +/** Linear read/write access during event delivery. */ +#define VMX_APIC_ACCESS_TYPE_LINEAR_EVENT_DELIVERY 3 +/** Physical read/write access during event delivery. */ +#define VMX_APIC_ACCESS_TYPE_PHYSICAL_EVENT_DELIVERY 10 +/** Physical access for an instruction fetch or during instruction execution. */ +#define VMX_APIC_ACCESS_TYPE_PHYSICAL_INSTR 15 +/** @} */ + +/** @} */ + +/** @name VMCS field encoding - Natural width guest state fields + * @{ + */ +#define VMX_VMCS64_GUEST_CR0 0x6800 +#define VMX_VMCS64_GUEST_CR3 0x6802 +#define VMX_VMCS64_GUEST_CR4 0x6804 +#define VMX_VMCS64_GUEST_ES_BASE 0x6806 +#define VMX_VMCS64_GUEST_CS_BASE 0x6808 +#define VMX_VMCS64_GUEST_SS_BASE 0x680A +#define VMX_VMCS64_GUEST_DS_BASE 0x680C +#define VMX_VMCS64_GUEST_FS_BASE 0x680E +#define VMX_VMCS64_GUEST_GS_BASE 0x6810 +#define VMX_VMCS64_GUEST_LDTR_BASE 0x6812 +#define VMX_VMCS64_GUEST_TR_BASE 0x6814 +#define VMX_VMCS64_GUEST_GDTR_BASE 0x6816 +#define VMX_VMCS64_GUEST_IDTR_BASE 0x6818 +#define VMX_VMCS64_GUEST_DR7 0x681A +#define VMX_VMCS64_GUEST_RSP 0x681C +#define VMX_VMCS64_GUEST_RIP 0x681E +#define VMX_VMCS_GUEST_RFLAGS 0x6820 +#define VMX_VMCS_GUEST_DEBUG_EXCEPTIONS 0x6822 +#define VMX_VMCS64_GUEST_SYSENTER_ESP 0x6824 /**< MSR IA32_SYSENTER_ESP */ +#define VMX_VMCS64_GUEST_SYSENTER_EIP 0x6826 /**< MSR IA32_SYSENTER_EIP */ +/** @} */ + + +/** @name VMX_VMCS_GUEST_DEBUG_EXCEPTIONS + * @{ + */ +/** Hardware breakpoint 0 was met. */ +#define VMX_VMCS_GUEST_DEBUG_EXCEPTIONS_B0 RT_BIT(0) +/** Hardware breakpoint 1 was met. */ +#define VMX_VMCS_GUEST_DEBUG_EXCEPTIONS_B1 RT_BIT(1) +/** Hardware breakpoint 2 was met. */ +#define VMX_VMCS_GUEST_DEBUG_EXCEPTIONS_B2 RT_BIT(2) +/** Hardware breakpoint 3 was met. */ +#define VMX_VMCS_GUEST_DEBUG_EXCEPTIONS_B3 RT_BIT(3) +/** At least one data or IO breakpoint was hit. */ +#define VMX_VMCS_GUEST_DEBUG_EXCEPTIONS_BREAKPOINT_ENABLED RT_BIT(12) +/** A debug exception would have been triggered by single-step execution mode. */ +#define VMX_VMCS_GUEST_DEBUG_EXCEPTIONS_BS RT_BIT(14) +/** Bits 4-11, 13 and 15-63 are reserved. */ + +/** @} */ + +/** @name VMCS field encoding - Natural width host state fields + * @{ + */ +#define VMX_VMCS_HOST_CR0 0x6C00 +#define VMX_VMCS_HOST_CR3 0x6C02 +#define VMX_VMCS_HOST_CR4 0x6C04 +#define VMX_VMCS_HOST_FS_BASE 0x6C06 +#define VMX_VMCS_HOST_GS_BASE 0x6C08 +#define VMX_VMCS_HOST_TR_BASE 0x6C0A +#define VMX_VMCS_HOST_GDTR_BASE 0x6C0C +#define VMX_VMCS_HOST_IDTR_BASE 0x6C0E +#define VMX_VMCS_HOST_SYSENTER_ESP 0x6C10 +#define VMX_VMCS_HOST_SYSENTER_EIP 0x6C12 +#define VMX_VMCS_HOST_RSP 0x6C14 +#define VMX_VMCS_HOST_RIP 0x6C16 +/** @} */ + +/** @} */ + + +#if RT_INLINE_ASM_GNU_STYLE +# define __STR(x) #x +# define STR(x) __STR(x) +#endif + + +/** @defgroup grp_vmx_asm vmx assembly helpers + * @ingroup grp_vmx + * @{ + */ + +/** + * Executes VMXON + * + * @returns VBox status code + * @param pVMXOn Physical address of VMXON structure + */ +#if RT_INLINE_ASM_EXTERNAL || HC_ARCH_BITS == 64 || defined(VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0) +DECLASM(int) VMXEnable(RTHCPHYS pVMXOn); +#else +DECLINLINE(int) VMXEnable(RTHCPHYS pVMXOn) +{ + int rc = VINF_SUCCESS; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__ ( + "push %3 \n\t" + "push %2 \n\t" + ".byte 0xF3, 0x0F, 0xC7, 0x34, 0x24 # VMXON [esp] \n\t" + "ja 2f \n\t" + "je 1f \n\t" + "movl $"STR(VERR_VMX_INVALID_VMXON_PTR)", %0 \n\t" + "jmp 2f \n\t" + "1: \n\t" + "movl $"STR(VERR_VMX_GENERIC)", %0 \n\t" + "2: \n\t" + "add $8, %%esp \n\t" + :"=rm"(rc) + :"0"(VINF_SUCCESS), + "ir"((uint32_t)pVMXOn), /* don't allow direct memory reference here, */ + "ir"((uint32_t)(pVMXOn >> 32)) /* this would not work with -fomit-frame-pointer */ + :"memory" + ); +# else + __asm + { + push dword ptr [pVMXOn+4] + push dword ptr [pVMXOn] + _emit 0xF3 + _emit 0x0F + _emit 0xC7 + _emit 0x34 + _emit 0x24 /* VMXON [esp] */ + jnc vmxon_good + mov dword ptr [rc], VERR_VMX_INVALID_VMXON_PTR + jmp the_end + +vmxon_good: + jnz the_end + mov dword ptr [rc], VERR_VMX_GENERIC +the_end: + add esp, 8 + } +# endif + return rc; +} +#endif + + +/** + * Executes VMXOFF + */ +#if RT_INLINE_ASM_EXTERNAL || HC_ARCH_BITS == 64 || defined(VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0) +DECLASM(void) VMXDisable(void); +#else +DECLINLINE(void) VMXDisable(void) +{ +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__ ( + ".byte 0x0F, 0x01, 0xC4 # VMXOFF \n\t" + ); +# else + __asm + { + _emit 0x0F + _emit 0x01 + _emit 0xC4 /* VMXOFF */ + } +# endif +} +#endif + + +/** + * Executes VMCLEAR + * + * @returns VBox status code + * @param pVMCS Physical address of VM control structure + */ +#if RT_INLINE_ASM_EXTERNAL || HC_ARCH_BITS == 64 || defined(VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0) +DECLASM(int) VMXClearVMCS(RTHCPHYS pVMCS); +#else +DECLINLINE(int) VMXClearVMCS(RTHCPHYS pVMCS) +{ + int rc = VINF_SUCCESS; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__ ( + "push %3 \n\t" + "push %2 \n\t" + ".byte 0x66, 0x0F, 0xC7, 0x34, 0x24 # VMCLEAR [esp] \n\t" + "jnc 1f \n\t" + "movl $"STR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t" + "1: \n\t" + "add $8, %%esp \n\t" + :"=rm"(rc) + :"0"(VINF_SUCCESS), + "ir"((uint32_t)pVMCS), /* don't allow direct memory reference here, */ + "ir"((uint32_t)(pVMCS >> 32)) /* this would not work with -fomit-frame-pointer */ + :"memory" + ); +# else + __asm + { + push dword ptr [pVMCS+4] + push dword ptr [pVMCS] + _emit 0x66 + _emit 0x0F + _emit 0xC7 + _emit 0x34 + _emit 0x24 /* VMCLEAR [esp] */ + jnc success + mov dword ptr [rc], VERR_VMX_INVALID_VMCS_PTR +success: + add esp, 8 + } +# endif + return rc; +} +#endif + + +/** + * Executes VMPTRLD + * + * @returns VBox status code + * @param pVMCS Physical address of VMCS structure + */ +#if RT_INLINE_ASM_EXTERNAL || HC_ARCH_BITS == 64 || defined(VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0) +DECLASM(int) VMXActivateVMCS(RTHCPHYS pVMCS); +#else +DECLINLINE(int) VMXActivateVMCS(RTHCPHYS pVMCS) +{ + int rc = VINF_SUCCESS; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__ ( + "push %3 \n\t" + "push %2 \n\t" + ".byte 0x0F, 0xC7, 0x34, 0x24 # VMPTRLD [esp] \n\t" + "jnc 1f \n\t" + "movl $"STR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t" + "1: \n\t" + "add $8, %%esp \n\t" + :"=rm"(rc) + :"0"(VINF_SUCCESS), + "ir"((uint32_t)pVMCS), /* don't allow direct memory reference here, */ + "ir"((uint32_t)(pVMCS >> 32)) /* this will not work with -fomit-frame-pointer */ + ); +# else + __asm + { + push dword ptr [pVMCS+4] + push dword ptr [pVMCS] + _emit 0x0F + _emit 0xC7 + _emit 0x34 + _emit 0x24 /* VMPTRLD [esp] */ + jnc success + mov dword ptr [rc], VERR_VMX_INVALID_VMCS_PTR + +success: + add esp, 8 + } +# endif + return rc; +} +#endif + +/** + * Executes VMPTRST + * + * @returns VBox status code + * @param pVMCS Address that will receive the current pointer + */ +DECLASM(int) VMXGetActivateVMCS(RTHCPHYS *pVMCS); + +/** + * Executes VMWRITE + * + * @returns VBox status code + * @param idxField VMCS index + * @param u32Val 32 bits value + */ +#if RT_INLINE_ASM_EXTERNAL || HC_ARCH_BITS == 64 || defined(VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0) +DECLASM(int) VMXWriteVMCS32(uint32_t idxField, uint32_t u32Val); +#else +DECLINLINE(int) VMXWriteVMCS32(uint32_t idxField, uint32_t u32Val) +{ + int rc = VINF_SUCCESS; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__ ( + ".byte 0x0F, 0x79, 0xC2 # VMWRITE eax, edx \n\t" + "ja 2f \n\t" + "je 1f \n\t" + "movl $"STR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t" + "jmp 2f \n\t" + "1: \n\t" + "movl $"STR(VERR_VMX_INVALID_VMCS_FIELD)", %0 \n\t" + "2: \n\t" + :"=rm"(rc) + :"0"(VINF_SUCCESS), + "a"(idxField), + "d"(u32Val) + ); +# else + __asm + { + push dword ptr [u32Val] + mov eax, [idxField] + _emit 0x0F + _emit 0x79 + _emit 0x04 + _emit 0x24 /* VMWRITE eax, [esp] */ + jnc valid_vmcs + mov dword ptr [rc], VERR_VMX_INVALID_VMCS_PTR + jmp the_end + +valid_vmcs: + jnz the_end + mov dword ptr [rc], VERR_VMX_INVALID_VMCS_FIELD +the_end: + add esp, 4 + } +# endif + return rc; +} +#endif + +/** + * Executes VMWRITE + * + * @returns VBox status code + * @param idxField VMCS index + * @param u64Val 16, 32 or 64 bits value + */ +#if HC_ARCH_BITS == 64 || defined(VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0) +DECLASM(int) VMXWriteVMCS64(uint32_t idxField, uint64_t u64Val); +#else +VMMR0DECL(int) VMXWriteVMCS64Ex(PVMCPU pVCpu, uint32_t idxField, uint64_t u64Val); + +#define VMXWriteVMCS64(idxField, u64Val) VMXWriteVMCS64Ex(pVCpu, idxField, u64Val) +#endif + +#if HC_ARCH_BITS == 64 +#define VMXWriteVMCS VMXWriteVMCS64 +#else +#define VMXWriteVMCS VMXWriteVMCS32 +#endif /* HC_ARCH_BITS == 64 */ + + +/** + * Invalidate a page using invept + * @returns VBox status code + * @param enmFlush Type of flush + * @param pDescriptor Descriptor + */ +DECLASM(int) VMXR0InvEPT(VMX_FLUSH_EPT enmFlush, uint64_t *pDescriptor); + +/** + * Invalidate a page using invvpid + * @returns VBox status code + * @param enmFlush Type of flush + * @param pDescriptor Descriptor + */ +DECLASM(int) VMXR0InvVPID(VMX_FLUSH_VPID enmFlush, uint64_t *pDescriptor); + +/** + * Executes VMREAD + * + * @returns VBox status code + * @param idxField VMCS index + * @param pData Ptr to store VM field value + */ +#if RT_INLINE_ASM_EXTERNAL || HC_ARCH_BITS == 64 || defined(VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0) +DECLASM(int) VMXReadVMCS32(uint32_t idxField, uint32_t *pData); +#else +DECLINLINE(int) VMXReadVMCS32(uint32_t idxField, uint32_t *pData) +{ + int rc = VINF_SUCCESS; +# if RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__ ( + "movl $"STR(VINF_SUCCESS)", %0 \n\t" + ".byte 0x0F, 0x78, 0xc2 # VMREAD eax, edx \n\t" + "ja 2f \n\t" + "je 1f \n\t" + "movl $"STR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t" + "jmp 2f \n\t" + "1: \n\t" + "movl $"STR(VERR_VMX_INVALID_VMCS_FIELD)", %0 \n\t" + "2: \n\t" + :"=&r"(rc), + "=d"(*pData) + :"a"(idxField), + "d"(0) + ); +# else + __asm + { + sub esp, 4 + mov dword ptr [esp], 0 + mov eax, [idxField] + _emit 0x0F + _emit 0x78 + _emit 0x04 + _emit 0x24 /* VMREAD eax, [esp] */ + mov edx, pData + pop dword ptr [edx] + jnc valid_vmcs + mov dword ptr [rc], VERR_VMX_INVALID_VMCS_PTR + jmp the_end + +valid_vmcs: + jnz the_end + mov dword ptr [rc], VERR_VMX_INVALID_VMCS_FIELD +the_end: + } +# endif + return rc; +} +#endif + +/** + * Executes VMREAD + * + * @returns VBox status code + * @param idxField VMCS index + * @param pData Ptr to store VM field value + */ +#if HC_ARCH_BITS == 64 || defined(VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0) +DECLASM(int) VMXReadVMCS64(uint32_t idxField, uint64_t *pData); +#else +DECLINLINE(int) VMXReadVMCS64(uint32_t idxField, uint64_t *pData) +{ + int rc; + + uint32_t val_hi, val; + rc = VMXReadVMCS32(idxField, &val); + rc |= VMXReadVMCS32(idxField + 1, &val_hi); + AssertRC(rc); + *pData = RT_MAKE_U64(val, val_hi); + return rc; +} +#endif + +#if HC_ARCH_BITS == 64 +# define VMXReadVMCS VMXReadVMCS64 +#else +# define VMXReadVMCS VMXReadVMCS32 +#endif /* HC_ARCH_BITS == 64 */ + +/** + * Gets the last instruction error value from the current VMCS + * + * @returns error value + */ +DECLINLINE(uint32_t) VMXGetLastError(void) +{ +#if HC_ARCH_BITS == 64 + uint64_t uLastError = 0; + int rc = VMXReadVMCS(VMX_VMCS32_RO_VM_INSTR_ERROR, &uLastError); + AssertRC(rc); + return (uint32_t)uLastError; + +#else /* 32-bit host: */ + uint32_t uLastError = 0; + int rc = VMXReadVMCS32(VMX_VMCS32_RO_VM_INSTR_ERROR, &uLastError); + AssertRC(rc); + return uLastError; +#endif +} + +#ifdef IN_RING0 +VMMR0DECL(int) VMXR0InvalidatePage(PVM pVM, PVMCPU pVCpu, RTGCPTR GCVirt); +VMMR0DECL(int) VMXR0InvalidatePhysPage(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys); +#endif /* IN_RING0 */ + +/** @} */ + +#endif + diff --git a/include/VBox/vmm/hwacc_vmx.mac b/include/VBox/vmm/hwacc_vmx.mac new file mode 100644 index 00000000..3fc11b43 --- /dev/null +++ b/include/VBox/vmm/hwacc_vmx.mac @@ -0,0 +1,154 @@ +;; @file +; HWACCM - VMX Structures and Definitions. +; + +; +; Copyright (C) 2006-2010 Oracle Corporation +; +; 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 (GPL) 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. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%define VMX_VMCS_GUEST_FIELD_ES 0800h +%define VMX_VMCS_GUEST_FIELD_CS 0802h +%define VMX_VMCS_GUEST_FIELD_SS 0804h +%define VMX_VMCS_GUEST_FIELD_DS 0806h +%define VMX_VMCS_GUEST_FIELD_FS 0808h +%define VMX_VMCS_GUEST_FIELD_GS 080Ah +%define VMX_VMCS_GUEST_FIELD_LDTR 080Ch +%define VMX_VMCS_GUEST_FIELD_TR 080Eh +%define VMX_VMCS_HOST_FIELD_ES 0C00h +%define VMX_VMCS_HOST_FIELD_CS 0C02h +%define VMX_VMCS_HOST_FIELD_SS 0C04h +%define VMX_VMCS_HOST_FIELD_DS 0C06h +%define VMX_VMCS_HOST_FIELD_FS 0C08h +%define VMX_VMCS_HOST_FIELD_GS 0C0Ah +%define VMX_VMCS_HOST_FIELD_TR 0C0Ch +%define VMX_VMCS_CTRL_IO_BITMAP_A_FULL 02000h +%define VMX_VMCS_CTRL_IO_BITMAP_A_HIGH 02001h +%define VMX_VMCS_CTRL_IO_BITMAP_B_FULL 02002h +%define VMX_VMCS_CTRL_IO_BITMAP_B_HIGH 02003h +%define VMX_VMCS_CTRL_MSR_BITMAP_FULL 02004h +%define VMX_VMCS_CTRL_MSR_BITMAP_HIGH 02005h +%define VMX_VMCS_CTRL_VMEXIT_MSR_STORE_FULL 02006h +%define VMX_VMCS_CTRL_VMEXIT_MSR_STORE_HIGH 02007h +%define VMX_VMCS_CTRL_VMEXIT_MSR_LOAD_FULL 02008h +%define VMX_VMCS_CTRL_VMEXIT_MSR_LOAD_HIGH 02009h +%define VMX_VMCS_CTRL_VMENTRY_MSR_LOAD_FULL 0200Ah +%define VMX_VMCS_CTRL_VMENTRY_MSR_LOAD_HIGH 0200Bh +%define VMX_VMCS_CTRL_EXEC_VMCS_PTR_FULL 0200Ch +%define VMX_VMCS_CTRL_EXEC_VMCS_PTR_HIGH 0200Dh +%define VMX_VMCS_CTRL_TSC_OFFSET_FULL 02010h +%define VMX_VMCS_CTRL_TSC_OFFSET_HIGH 02011h +%define VMX_VMCS_CTRL_VAPIC_PAGEADDR_FULL 02012h +%define VMX_VMCS_CTRL_VAPIC_PAGEADDR_HIGH 02013h +%define VMX_VMCS_GUEST_LINK_PTR_FULL 02800h +%define VMX_VMCS_GUEST_LINK_PTR_HIGH 02801h +%define VMX_VMCS_GUEST_DEBUGCTL_FULL 02802h +%define VMX_VMCS_GUEST_DEBUGCTL_HIGH 02803h +%define VMX_VMCS_CTRL_PIN_EXEC_CONTROLS 04000h +%define VMX_VMCS_CTRL_PROC_EXEC_CONTROLS 04002h +%define VMX_VMCS_CTRL_EXCEPTION_BITMAP 04004h +%define VMX_VMCS_CTRL_PAGEFAULT_ERROR_MASK 04006h +%define VMX_VMCS_CTRL_PAGEFAULT_ERROR_MATCH 04008h +%define VMX_VMCS_CTRL_CR3_TARGET_COUNT 0400Ah +%define VMX_VMCS_CTRL_EXIT_CONTROLS 0400Ch +%define VMX_VMCS_CTRL_EXIT_MSR_STORE_COUNT 0400Eh +%define VMX_VMCS_CTRL_EXIT_MSR_LOAD_COUNT 04010h +%define VMX_VMCS_CTRL_ENTRY_CONTROLS 04012h +%define VMX_VMCS_CTRL_ENTRY_MSR_LOAD_COUNT 04014h +%define VMX_VMCS_CTRL_ENTRY_IRQ_INFO 04016h +%define VMX_VMCS_CTRL_ENTRY_EXCEPTION_ERRCODE 04018h +%define VMX_VMCS_CTRL_ENTRY_INSTR_LENGTH 0401Ah +%define VMX_VMCS_CTRL_TRP_TRESHOLD 0401Ch +%define VMX_VMCS_RO_VM_INSTR_ERROR 04400h +%define VMX_VMCS_RO_EXIT_REASON 04402h +%define VMX_VMCS_RO_EXIT_INTERRUPTION_INFO 04404h +%define VMX_VMCS_RO_EXIT_INTERRUPTION_ERRCODE 04406h +%define VMX_VMCS_RO_IDT_INFO 04408h +%define VMX_VMCS_RO_IDT_ERRCODE 0440Ah +%define VMX_VMCS_RO_EXIT_INSTR_LENGTH 0440Ch +%define VMX_VMCS_RO_EXIT_INSTR_INFO 0440Eh +%define VMX_VMCS_GUEST_ES_LIMIT 04800h +%define VMX_VMCS_GUEST_CS_LIMIT 04802h +%define VMX_VMCS_GUEST_SS_LIMIT 04804h +%define VMX_VMCS_GUEST_DS_LIMIT 04806h +%define VMX_VMCS_GUEST_FS_LIMIT 04808h +%define VMX_VMCS_GUEST_GS_LIMIT 0480Ah +%define VMX_VMCS_GUEST_LDTR_LIMIT 0480Ch +%define VMX_VMCS_GUEST_TR_LIMIT 0480Eh +%define VMX_VMCS_GUEST_GDTR_LIMIT 04810h +%define VMX_VMCS_GUEST_IDTR_LIMIT 04812h +%define VMX_VMCS_GUEST_ES_ACCESS_RIGHTS 04814h +%define VMX_VMCS_GUEST_CS_ACCESS_RIGHTS 04816h +%define VMX_VMCS_GUEST_SS_ACCESS_RIGHTS 04818h +%define VMX_VMCS_GUEST_DS_ACCESS_RIGHTS 0481Ah +%define VMX_VMCS_GUEST_FS_ACCESS_RIGHTS 0481Ch +%define VMX_VMCS_GUEST_GS_ACCESS_RIGHTS 0481Eh +%define VMX_VMCS_GUEST_LDTR_ACCESS_RIGHTS 04820h +%define VMX_VMCS_GUEST_TR_ACCESS_RIGHTS 04822h +%define VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE 04824h +%define VMX_VMCS_GUEST_ACTIVITY_STATE 04826h +%define VMX_VMCS_GUEST_SYSENTER_CS 0482Ah +%define VMX_VMCS_CTRL_CR0_MASK 06000h +%define VMX_VMCS_CTRL_CR4_MASK 06002h +%define VMX_VMCS_CTRL_CR0_READ_SHADOW 06004h +%define VMX_VMCS_CTRL_CR4_READ_SHADOW 06006h +%define VMX_VMCS_CTRL_CR3_TARGET_VAL0 06008h +%define VMX_VMCS_CTRL_CR3_TARGET_VAL1 0600Ah +%define VMX_VMCS_CTRL_CR3_TARGET_VAL2 0600Ch +%define VMX_VMCS_CTRL_CR3_TARGET_VAL31 0600Eh +%define VMX_VMCS_RO_EXIT_QUALIFICATION 06400h +%define VMX_VMCS_RO_IO_RCX 06402h +%define VMX_VMCS_RO_IO_RSX 06404h +%define VMX_VMCS_RO_IO_RDI 06406h +%define VMX_VMCS_RO_IO_RIP 06408h +%define VMX_VMCS_GUEST_LINEAR_ADDR 0640Ah +%define VMX_VMCS64_GUEST_CR0 06800h +%define VMX_VMCS64_GUEST_CR3 06802h +%define VMX_VMCS64_GUEST_CR4 06804h +%define VMX_VMCS64_GUEST_ES_BASE 06806h +%define VMX_VMCS64_GUEST_CS_BASE 06808h +%define VMX_VMCS64_GUEST_SS_BASE 0680Ah +%define VMX_VMCS64_GUEST_DS_BASE 0680Ch +%define VMX_VMCS64_GUEST_FS_BASE 0680Eh +%define VMX_VMCS64_GUEST_GS_BASE 06810h +%define VMX_VMCS64_GUEST_LDTR_BASE 06812h +%define VMX_VMCS64_GUEST_TR_BASE 06814h +%define VMX_VMCS64_GUEST_GDTR_BASE 06816h +%define VMX_VMCS64_GUEST_IDTR_BASE 06818h +%define VMX_VMCS64_GUEST_DR7 0681Ah +%define VMX_VMCS64_GUEST_RSP 0681Ch +%define VMX_VMCS64_GUEST_RIP 0681Eh +%define VMX_VMCS64_GUEST_RFLAGS 06820h +%define VMX_VMCS_GUEST_DEBUG_EXCEPTIONS 06822h +%define VMX_VMCS64_GUEST_SYSENTER_ESP 06824h +%define VMX_VMCS64_GUEST_SYSENTER_EIP 06826h +%define VMX_VMCS_HOST_CR0 06C00h +%define VMX_VMCS_HOST_CR3 06C02h +%define VMX_VMCS_HOST_CR4 06C04h +%define VMX_VMCS_HOST_FS_BASE 06C06h +%define VMX_VMCS_HOST_GS_BASE 06C08h +%define VMX_VMCS_HOST_TR_BASE 06C0Ah +%define VMX_VMCS_HOST_GDTR_BASE 06C0Ch +%define VMX_VMCS_HOST_IDTR_BASE 06C0Eh +%define VMX_VMCS_HOST_SYSENTER_ESP 06C10h +%define VMX_VMCS_HOST_SYSENTER_EIP 06C12h +%define VMX_VMCS_HOST_RSP 06C14h +%define VMX_VMCS_HOST_RIP 06C16h + +%define VMX_VMCS_CTRL_EXIT_CONTROLS_HOST_AMD64 RT_BIT(9) diff --git a/include/VBox/vmm/hwaccm.h b/include/VBox/vmm/hwaccm.h new file mode 100644 index 00000000..98a7d02e --- /dev/null +++ b/include/VBox/vmm/hwaccm.h @@ -0,0 +1,154 @@ +/** @file + * HWACCM - Intel/AMD VM Hardware Support Manager (VMM) + */ + +/* + * Copyright (C) 2006-2010 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_hwaccm_h +#define ___VBox_vmm_hwaccm_h + +#include <VBox/vmm/pgm.h> +#include <VBox/vmm/cpum.h> +#include <iprt/mp.h> + + +/** @defgroup grp_hwaccm The VM Hardware Manager API + * @{ + */ + +RT_C_DECLS_BEGIN + +/** + * Query HWACCM state (enabled/disabled) + * + * @returns 0 - disabled, 1 - enabled + * @param pVM The VM to operate on. + */ +#define HWACCMIsEnabled(pVM) ((pVM)->fHWACCMEnabled) + + /** + * Check if the current CPU state is valid for emulating IO blocks in the recompiler + * + * @returns boolean + * @param pCtx CPU context + */ +#define HWACCMCanEmulateIoBlock(pVCpu) (!CPUMIsGuestInPagedProtectedMode(pVCpu)) +#define HWACCMCanEmulateIoBlockEx(pCtx) (!CPUMIsGuestInPagedProtectedModeEx(pCtx)) + +VMMDECL(int) HWACCMInvalidatePage(PVMCPU pVCpu, RTGCPTR GCVirt); +VMMDECL(bool) HWACCMHasPendingIrq(PVM pVM); + +#ifndef IN_RC +VMMDECL(int) HWACCMFlushTLB(PVMCPU pVCpu); +VMMDECL(int) HWACCMFlushTLBOnAllVCpus(PVM pVM); +VMMDECL(int) HWACCMInvalidatePageOnAllVCpus(PVM pVM, RTGCPTR GCVirt); +VMMDECL(int) HWACCMInvalidatePhysPage(PVM pVM, RTGCPHYS GCPhys); +VMMDECL(bool) HWACCMIsNestedPagingActive(PVM pVM); +VMMDECL(PGMMODE) HWACCMGetShwPagingMode(PVM pVM); +#else +/* Nop in GC */ +# define HWACCMFlushTLB(pVCpu) do { } while (0) +# define HWACCMIsNestedPagingActive(pVM) false +# define HWACCMFlushTLBOnAllVCpus(pVM) do { } while (0) +#endif + +#ifdef IN_RING0 +/** @defgroup grp_hwaccm_r0 The VM Hardware Manager API + * @ingroup grp_hwaccm + * @{ + */ +VMMR0DECL(int) HWACCMR0Init(void); +VMMR0DECL(int) HWACCMR0Term(void); +VMMR0DECL(int) HWACCMR0InitVM(PVM pVM); +VMMR0DECL(int) HWACCMR0TermVM(PVM pVM); +VMMR0DECL(int) HWACCMR0EnableAllCpus(PVM pVM); +VMMR0DECL(int) HWACCMR0EnterSwitcher(PVM pVM, bool *pfVTxDisabled); +VMMR0DECL(int) HWACCMR0LeaveSwitcher(PVM pVM, bool fVTxDisabled); + +VMMR0DECL(void) HWACCMR0SavePendingIOPortWrite(PVMCPU pVCpu, RTGCPTR GCPtrRip, RTGCPTR GCPtrRipNext, unsigned uPort, unsigned uAndVal, unsigned cbSize); +VMMR0DECL(void) HWACCMR0SavePendingIOPortRead(PVMCPU pVCpu, RTGCPTR GCPtrRip, RTGCPTR GCPtrRipNext, unsigned uPort, unsigned uAndVal, unsigned cbSize); + +/** @} */ +#endif /* IN_RING0 */ + + +#ifdef IN_RING3 +/** @defgroup grp_hwaccm_r3 The VM Hardware Manager API + * @ingroup grp_hwaccm + * @{ + */ +VMMR3DECL(bool) HWACCMR3IsEventPending(PVMCPU pVCpu); +VMMR3DECL(int) HWACCMR3Init(PVM pVM); +VMMR3_INT_DECL(int) HWACCMR3InitCompleted(PVM pVM, VMINITCOMPLETED enmWhat); +VMMR3DECL(void) HWACCMR3Relocate(PVM pVM); +VMMR3DECL(int) HWACCMR3Term(PVM pVM); +VMMR3DECL(void) HWACCMR3Reset(PVM pVM); +VMMR3DECL(void) HWACCMR3ResetCpu(PVMCPU pVCpu); +VMMR3DECL(void) HWACCMR3CheckError(PVM pVM, int iStatusCode); +VMMR3DECL(bool) HWACCMR3CanExecuteGuest(PVM pVM, PCPUMCTX pCtx); +VMMR3DECL(void) HWACCMR3NotifyScheduled(PVMCPU pVCpu); +VMMR3DECL(void) HWACCMR3NotifyEmulated(PVMCPU pVCpu); +VMMR3DECL(bool) HWACCMR3IsActive(PVMCPU pVCpu); +VMMR3DECL(bool) HWACCMR3IsNestedPagingActive(PVM pVM); +VMMR3DECL(bool) HWACCMR3IsAllowed(PVM pVM); +VMMR3DECL(void) HWACCMR3PagingModeChanged(PVM pVM, PVMCPU pVCpu, PGMMODE enmShadowMode, PGMMODE enmGuestMode); +VMMR3DECL(bool) HWACCMR3IsVPIDActive(PVM pVM); +VMMR3DECL(int) HWACCMR3InjectNMI(PVM pVM); +VMMR3DECL(int) HWACCMR3EmulateIoBlock(PVM pVM, PCPUMCTX pCtx); +VMMR3DECL(VBOXSTRICTRC) HWACCMR3RestartPendingIOInstr(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx); +VMMR3DECL(int) HWACMMR3EnablePatching(PVM pVM, RTGCPTR pPatchMem, unsigned cbPatchMem); +VMMR3DECL(int) HWACMMR3DisablePatching(PVM pVM, RTGCPTR pPatchMem, unsigned cbPatchMem); +VMMR3DECL(int) HWACCMR3PatchTprInstr(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx); +VMMR3DECL(bool) HWACCMR3IsRescheduleRequired(PVM pVM, PCPUMCTX pCtx); +VMMR3DECL(bool) HWACCMR3IsVmxPreemptionTimerUsed(PVM pVM); + +/** @} */ +#endif /* IN_RING3 */ + +#ifdef IN_RING0 +/** @addtogroup grp_hwaccm_r0 + * @{ + */ +VMMR0DECL(int) HWACCMR0SetupVM(PVM pVM); +VMMR0DECL(int) HWACCMR0RunGuestCode(PVM pVM, PVMCPU pVCpu); +VMMR0DECL(int) HWACCMR0Enter(PVM pVM, PVMCPU pVCpu); +VMMR0DECL(int) HWACCMR0Leave(PVM pVM, PVMCPU pVCpu); +VMMR0DECL(int) HWACCMR0InvalidatePage(PVM pVM, PVMCPU pVCpu); +VMMR0DECL(int) HWACCMR0FlushTLB(PVM pVM); +VMMR0DECL(bool) HWACCMR0SuspendPending(void); + +# if HC_ARCH_BITS == 32 && defined(VBOX_WITH_64_BITS_GUESTS) +VMMR0DECL(int) HWACCMR0SaveFPUState(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx); +VMMR0DECL(int) HWACCMR0SaveDebugState(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx); +VMMR0DECL(int) HWACCMR0TestSwitcher3264(PVM pVM); +# endif + +/** @} */ +#endif /* IN_RING0 */ + + +/** @} */ +RT_C_DECLS_END + + +#endif + diff --git a/include/VBox/vmm/iem.h b/include/VBox/vmm/iem.h new file mode 100644 index 00000000..617a05a6 --- /dev/null +++ b/include/VBox/vmm/iem.h @@ -0,0 +1,83 @@ +/** @file + * IEM - Interpreted Execution Manager. + */ + +/* + * Copyright (C) 2011 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_iem_h +#define ___VBox_vmm_iem_h + +#include <VBox/types.h> +#include <VBox/vmm/trpm.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_iem The Interpreted Execution Manager API. + * @{ + */ + + + +VMMDECL(VBOXSTRICTRC) IEMExecOne(PVMCPU pVCpu); +VMMDECL(VBOXSTRICTRC) IEMExecOneEx(PVMCPU pVCpu, PCPUMCTXCORE pCtxCore, uint32_t *pcbWritten); +VMMDECL(VBOXSTRICTRC) IEMExecOneWithPrefetchedByPC(PVMCPU pVCpu, PCPUMCTXCORE pCtxCore, uint64_t OpcodeBytesPC, + const void *pvOpcodeBytes, size_t cbOpcodeBytes); +VMMDECL(VBOXSTRICTRC) IEMExecOneBypassEx(PVMCPU pVCpu, PCPUMCTXCORE pCtxCore, uint32_t *pcbWritten); +VMMDECL(VBOXSTRICTRC) IEMExecOneBypassWithPrefetchedByPC(PVMCPU pVCpu, PCPUMCTXCORE pCtxCore, uint64_t OpcodeBytesPC, + const void *pvOpcodeBytes, size_t cbOpcodeBytes); +VMMDECL(VBOXSTRICTRC) IEMExecLots(PVMCPU pVCpu); +VMM_INT_DECL(VBOXSTRICTRC) IEMInjectTrap(PVMCPU pVCpu, uint8_t u8TrapNo, TRPMEVENT enmType, uint16_t uErrCode, RTGCPTR uCr2); + +VMM_INT_DECL(int) IEMBreakpointSet(PVM pVM, RTGCPTR GCPtrBp); +VMM_INT_DECL(int) IEMBreakpointClear(PVM pVM, RTGCPTR GCPtrBp); + +/** @name Given Instruction Interpreters + * @{ */ + +/** @} */ + +#if defined(IEM_VERIFICATION_MODE) && defined(IN_RING3) +VMM_INT_DECL(void) IEMNotifyMMIORead(PVM pVM, RTGCPHYS GCPhys, size_t cbValue); +VMM_INT_DECL(void) IEMNotifyMMIOWrite(PVM pVM, RTGCPHYS GCPhys, uint32_t u32Value, size_t cbValue); +VMM_INT_DECL(void) IEMNotifyIOPortRead(PVM pVM, RTIOPORT Port, size_t cbValue); +VMM_INT_DECL(void) IEMNotifyIOPortWrite(PVM pVM, RTIOPORT Port, uint32_t u32Value, size_t cbValue); +VMM_INT_DECL(void) IEMNotifyIOPortReadString(PVM pVM, RTIOPORT Port, RTGCPTR GCPtrDst, RTGCUINTREG cTransfers, size_t cbValue); +VMM_INT_DECL(void) IEMNotifyIOPortWriteString(PVM pVM, RTIOPORT Port, RTGCPTR GCPtrSrc, RTGCUINTREG cTransfers, size_t cbValue); +#endif + + +/** @defgroup grp_em_r3 The IEM Host Context Ring-3 API. + * @ingroup grp_em + * @{ + */ +VMMR3DECL(int) IEMR3Init(PVM pVM); +VMMR3DECL(int) IEMR3Term(PVM pVM); +VMMR3DECL(void) IEMR3Relocate(PVM pVM); +/** @} */ + +/** @} */ + +RT_C_DECLS_END + +#endif + diff --git a/include/VBox/vmm/iom.h b/include/VBox/vmm/iom.h new file mode 100644 index 00000000..a7e552c9 --- /dev/null +++ b/include/VBox/vmm/iom.h @@ -0,0 +1,325 @@ +/** @file + * IOM - Input / Output Monitor. + */ + +/* + * Copyright (C) 2006-2010 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_iom_h +#define ___VBox_vmm_iom_h + +#include <VBox/types.h> +#include <VBox/dis.h> + +RT_C_DECLS_BEGIN + + +/** @defgroup grp_iom The Input / Ouput Monitor API + * @{ + */ + +/** @def IOM_NO_PDMINS_CHECKS + * Until all devices have been fully adjusted to PDM style, the pPdmIns + * parameter is not checked by IOM. + * @todo Check this again, now. + */ +#define IOM_NO_PDMINS_CHECKS + +/** + * Macro for checking if an I/O or MMIO emulation call succeeded. + * + * This macro shall only be used with the IOM APIs where it's mentioned + * in the return value description. And there it must be used to correctly + * determine if the call succeeded and things like the RIP needs updating. + * + * + * @returns Success indicator (true/false). + * + * @param rc The status code. This may be evaluated + * more than once! + * + * @remark To avoid making assumptions about the layout of the + * VINF_EM_FIRST...VINF_EM_LAST range we're checking + * explicitly for each for exach the exceptions. + * However, for efficieny we ASSUME that the + * VINF_EM_LAST is smaller than most of the relevant + * status codes. We also ASSUME that the + * VINF_EM_RESCHEDULE_REM status code is the most + * frequent status code we'll enounter in this range. + * + * @todo Will have to add VINF_EM_DBG_HYPER_BREAKPOINT if the + * I/O port and MMIO breakpoints should trigger before + * the I/O is done. Currently, we don't implement these + * kind of breakpoints. + */ +#define IOM_SUCCESS(rc) ( (rc) == VINF_SUCCESS \ + || ( (rc) <= VINF_EM_LAST \ + && (rc) != VINF_EM_RESCHEDULE_REM \ + && (rc) >= VINF_EM_FIRST \ + && (rc) != VINF_EM_RESCHEDULE_RAW \ + && (rc) != VINF_EM_RESCHEDULE_HWACC \ + ) \ + ) + +/** @name IOMMMIO_FLAGS_XXX + * @{ */ +/** Pass all reads thru unmodified. */ +#define IOMMMIO_FLAGS_READ_PASSTHRU UINT32_C(0x00000000) +/** All read accesses are DWORD sized (32-bit). */ +#define IOMMMIO_FLAGS_READ_DWORD UINT32_C(0x00000001) +/** All read accesses are DWORD (32-bit) or QWORD (64-bit) sized. + * Only accesses that are both QWORD sized and aligned are performed as QWORD. + * All other access will be done DWORD fashion (because it is way simpler). */ +#define IOMMMIO_FLAGS_READ_DWORD_QWORD UINT32_C(0x00000002) +/** The read access mode mask. */ +#define IOMMMIO_FLAGS_READ_MODE UINT32_C(0x00000003) + +/** Pass all writes thru unmodified. */ +#define IOMMMIO_FLAGS_WRITE_PASSTHRU UINT32_C(0x00000000) +/** All write accesses are DWORD (32-bit) sized and unspecified bytes are + * written as zero. */ +#define IOMMMIO_FLAGS_WRITE_DWORD_ZEROED UINT32_C(0x00000010) +/** All write accesses are either DWORD (32-bit) or QWORD (64-bit) sized, + * missing bytes will be written as zero. Only accesses that are both QWORD + * sized and aligned are performed as QWORD, all other accesses will be done + * DWORD fashion (because it's way simpler). */ +#define IOMMMIO_FLAGS_WRITE_DWORD_QWORD_ZEROED UINT32_C(0x00000020) +/** All write accesses are DWORD (32-bit) sized and unspecified bytes are + * read from the device first as DWORDs. + * @remarks This isn't how it happens on real hardware, but it allows + * simplifications of devices where reads doesn't change the device + * state in any way. */ +#define IOMMMIO_FLAGS_WRITE_DWORD_READ_MISSING UINT32_C(0x00000030) +/** All write accesses are DWORD (32-bit) or QWORD (64-bit) sized and + * unspecified bytes are read from the device first as DWORDs. Only accesses + * that are both QWORD sized and aligned are performed as QWORD, all other + * accesses will be done DWORD fashion (because it's way simpler). + * @remarks This isn't how it happens on real hardware, but it allows + * simplifications of devices where reads doesn't change the device + * state in any way. */ +#define IOMMMIO_FLAGS_WRITE_DWORD_QWORD_READ_MISSING UINT32_C(0x00000040) +/** The read access mode mask. */ +#define IOMMMIO_FLAGS_WRITE_MODE UINT32_C(0x00000070) + +/** Whether to do a DBGSTOP on complicated reads. + * What this includes depends on the read mode, but generally all misaligned + * reads as well as word and byte reads and maybe qword reads. */ +#define IOMMMIO_FLAGS_DBGSTOP_ON_COMPLICATED_READ UINT32_C(0x00000100) +/** Whether to do a DBGSTOP on complicated writes. + * This depends on the write mode, but generally all writes where we have to + * supply bytes (zero them or read them). */ +#define IOMMMIO_FLAGS_DBGSTOP_ON_COMPLICATED_WRITE UINT32_C(0x00000200) + +/** Mask of valid flags. */ +#define IOMMMIO_FLAGS_VALID_MASK UINT32_C(0x00000373) +/** @} */ + + +/** + * Port I/O Handler for IN operations. + * + * @returns VINF_SUCCESS or VINF_EM_*. + * @returns VERR_IOM_IOPORT_UNUSED if the port is really unused and a ~0 value should be returned. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param uPort Port number used for the IN operation. + * @param pu32 Where to store the result. This is always a 32-bit + * variable regardless of what @a cb might say. + * @param cb Number of bytes read. + */ +typedef DECLCALLBACK(int) FNIOMIOPORTIN(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb); +/** Pointer to a FNIOMIOPORTIN(). */ +typedef FNIOMIOPORTIN *PFNIOMIOPORTIN; + +/** + * Port I/O Handler for string IN operations. + * + * @returns VINF_SUCCESS or VINF_EM_*. + * @returns VERR_IOM_IOPORT_UNUSED if the port is really unused and a ~0 value should be returned. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param uPort Port number used for the IN operation. + * @param pGCPtrDst Pointer to the destination buffer (GC, incremented appropriately). + * @param pcTransfers Pointer to the number of transfer units to read, on return remaining transfer units. + * @param cb Size of the transfer unit (1, 2 or 4 bytes). + */ +typedef DECLCALLBACK(int) FNIOMIOPORTINSTRING(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrDst, PRTGCUINTREG pcTransfers, unsigned cb); +/** Pointer to a FNIOMIOPORTINSTRING(). */ +typedef FNIOMIOPORTINSTRING *PFNIOMIOPORTINSTRING; + +/** + * Port I/O Handler for OUT operations. + * + * @returns VINF_SUCCESS or VINF_EM_*. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param uPort Port number used for the OUT operation. + * @param u32 The value to output. + * @param cb The value size in bytes. + */ +typedef DECLCALLBACK(int) FNIOMIOPORTOUT(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb); +/** Pointer to a FNIOMIOPORTOUT(). */ +typedef FNIOMIOPORTOUT *PFNIOMIOPORTOUT; + +/** + * Port I/O Handler for string OUT operations. + * + * @returns VINF_SUCCESS or VINF_EM_*. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param uPort Port number used for the OUT operation. + * @param pGCPtrSrc Pointer to the source buffer (GC, incremented appropriately). + * @param pcTransfers Pointer to the number of transfer units to write, on return remaining transfer units. + * @param cb Size of the transfer unit (1, 2 or 4 bytes). + */ +typedef DECLCALLBACK(int) FNIOMIOPORTOUTSTRING(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrSrc, PRTGCUINTREG pcTransfers, unsigned cb); +/** Pointer to a FNIOMIOPORTOUTSTRING(). */ +typedef FNIOMIOPORTOUTSTRING *PFNIOMIOPORTOUTSTRING; + + +/** + * Memory mapped I/O Handler for read operations. + * + * @returns VBox status code. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param GCPhysAddr Physical address (in GC) where the read starts. + * @param pv Where to store the result. + * @param cb Number of bytes read. + */ +typedef DECLCALLBACK(int) FNIOMMMIOREAD(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb); +/** Pointer to a FNIOMMMIOREAD(). */ +typedef FNIOMMMIOREAD *PFNIOMMMIOREAD; + +/** + * Port I/O Handler for write operations. + * + * @returns VBox status code. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param GCPhysAddr Physical address (in GC) where the read starts. + * @param pv Where to fetch the result. + * @param cb Number of bytes to write. + */ +typedef DECLCALLBACK(int) FNIOMMMIOWRITE(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb); +/** Pointer to a FNIOMMMIOWRITE(). */ +typedef FNIOMMMIOWRITE *PFNIOMMMIOWRITE; + +/** + * Port I/O Handler for memset operations, actually for REP STOS* instructions handling. + * + * @returns VBox status code. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param GCPhysAddr Physical address (in GC) where the write starts. + * @param u32Item Byte/Word/Dword data to fill. + * @param cbItem Size of data in u32Item parameter, restricted to 1/2/4 bytes. + * @param cItems Number of iterations. + */ +typedef DECLCALLBACK(int) FNIOMMMIOFILL(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, uint32_t u32Item, unsigned cbItem, unsigned cItems); +/** Pointer to a FNIOMMMIOFILL(). */ +typedef FNIOMMMIOFILL *PFNIOMMMIOFILL; + +VMMDECL(VBOXSTRICTRC) IOMIOPortRead(PVM pVM, RTIOPORT Port, uint32_t *pu32Value, size_t cbValue); +VMMDECL(VBOXSTRICTRC) IOMIOPortWrite(PVM pVM, RTIOPORT Port, uint32_t u32Value, size_t cbValue); +VMMDECL(VBOXSTRICTRC) IOMInterpretOUT(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu); +VMMDECL(VBOXSTRICTRC) IOMInterpretIN(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu); +VMMDECL(VBOXSTRICTRC) IOMIOPortReadString(PVM pVM, RTIOPORT Port, PRTGCPTR pGCPtrDst, PRTGCUINTREG pcTransfers, unsigned cb); +VMMDECL(VBOXSTRICTRC) IOMIOPortWriteString(PVM pVM, RTIOPORT Port, PRTGCPTR pGCPtrSrc, PRTGCUINTREG pcTransfers, unsigned cb); +VMMDECL(VBOXSTRICTRC) IOMInterpretINS(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu); +VMMDECL(VBOXSTRICTRC) IOMInterpretINSEx(PVM pVM, PCPUMCTXCORE pRegFrame, uint32_t uPort, uint32_t uPrefix, DISCPUMODE enmAddrMode, uint32_t cbTransfer); +VMMDECL(VBOXSTRICTRC) IOMInterpretOUTS(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu); +VMMDECL(VBOXSTRICTRC) IOMInterpretOUTSEx(PVM pVM, PCPUMCTXCORE pRegFrame, uint32_t uPort, uint32_t uPrefix, DISCPUMODE enmAddrMode, uint32_t cbTransfer); +VMMDECL(VBOXSTRICTRC) IOMMMIORead(PVM pVM, RTGCPHYS GCPhys, uint32_t *pu32Value, size_t cbValue); +VMMDECL(VBOXSTRICTRC) IOMMMIOWrite(PVM pVM, RTGCPHYS GCPhys, uint32_t u32Value, size_t cbValue); +VMMDECL(VBOXSTRICTRC) IOMMMIOPhysHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pCtxCore, RTGCPHYS GCPhysFault); +VMMDECL(VBOXSTRICTRC) IOMInterpretCheckPortIOAccess(PVM pVM, PCPUMCTXCORE pCtxCore, RTIOPORT Port, unsigned cb); +VMMDECL(int) IOMMMIOMapMMIO2Page(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysRemapped, uint64_t fPageFlags); +VMMDECL(int) IOMMMIOMapMMIOHCPage(PVM pVM, RTGCPHYS GCPhys, RTHCPHYS HCPhys, uint64_t fPageFlags); +VMMDECL(int) IOMMMIOResetRegion(PVM pVM, RTGCPHYS GCPhys); +VMMDECL(bool) IOMIsLockOwner(PVM pVM); + +#ifdef IN_RC +/** @defgroup grp_iom_rc The IOM Raw-Mode Context API + * @ingroup grp_iom + * @{ + */ +VMMRCDECL(VBOXSTRICTRC) IOMRCIOPortHandler(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu); +/** @} */ +#endif /* IN_RC */ + + + +#ifdef IN_RING3 +/** @defgroup grp_iom_r3 The IOM Host Context Ring-3 API + * @ingroup grp_iom + * @{ + */ +VMMR3_INT_DECL(int) IOMR3Init(PVM pVM); +VMMR3_INT_DECL(void) IOMR3Reset(PVM pVM); +VMMR3_INT_DECL(void) IOMR3Relocate(PVM pVM, RTGCINTPTR offDelta); +VMMR3_INT_DECL(int) IOMR3Term(PVM pVM); +VMMR3_INT_DECL(int) IOMR3IOPortRegisterR3(PVM pVM, PPDMDEVINS pDevIns, RTIOPORT PortStart, RTUINT cPorts, RTHCPTR pvUser, + R3PTRTYPE(PFNIOMIOPORTOUT) pfnOutCallback, R3PTRTYPE(PFNIOMIOPORTIN) pfnInCallback, + R3PTRTYPE(PFNIOMIOPORTOUTSTRING) pfnOutStringCallback, R3PTRTYPE(PFNIOMIOPORTINSTRING) pfnInStringCallback, + const char *pszDesc); +VMMR3_INT_DECL(int) IOMR3IOPortRegisterRC(PVM pVM, PPDMDEVINS pDevIns, RTIOPORT PortStart, RTUINT cPorts, RTRCPTR pvUser, + RCPTRTYPE(PFNIOMIOPORTOUT) pfnOutCallback, RCPTRTYPE(PFNIOMIOPORTIN) pfnInCallback, + RCPTRTYPE(PFNIOMIOPORTOUTSTRING) pfnOutStrCallback, RCPTRTYPE(PFNIOMIOPORTINSTRING) pfnInStrCallback, + const char *pszDesc); +VMMR3_INT_DECL(int) IOMR3IOPortRegisterR0(PVM pVM, PPDMDEVINS pDevIns, RTIOPORT PortStart, RTUINT cPorts, RTR0PTR pvUser, + R0PTRTYPE(PFNIOMIOPORTOUT) pfnOutCallback, R0PTRTYPE(PFNIOMIOPORTIN) pfnInCallback, + R0PTRTYPE(PFNIOMIOPORTOUTSTRING) pfnOutStrCallback, R0PTRTYPE(PFNIOMIOPORTINSTRING) pfnInStrCallback, + const char *pszDesc); +VMMR3_INT_DECL(int) IOMR3IOPortDeregister(PVM pVM, PPDMDEVINS pDevIns, RTIOPORT PortStart, RTUINT cPorts); + +VMMR3_INT_DECL(int) IOMR3MmioRegisterR3(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, uint32_t cbRange, RTHCPTR pvUser, + R3PTRTYPE(PFNIOMMMIOWRITE) pfnWriteCallback, + R3PTRTYPE(PFNIOMMMIOREAD) pfnReadCallback, + R3PTRTYPE(PFNIOMMMIOFILL) pfnFillCallback, + uint32_t fFlags, const char *pszDesc); +VMMR3_INT_DECL(int) IOMR3MmioRegisterR0(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, uint32_t cbRange, RTR0PTR pvUser, + R0PTRTYPE(PFNIOMMMIOWRITE) pfnWriteCallback, + R0PTRTYPE(PFNIOMMMIOREAD) pfnReadCallback, + R0PTRTYPE(PFNIOMMMIOFILL) pfnFillCallback); +VMMR3_INT_DECL(int) IOMR3MmioRegisterRC(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, uint32_t cbRange, RTGCPTR pvUser, + RCPTRTYPE(PFNIOMMMIOWRITE) pfnWriteCallback, + RCPTRTYPE(PFNIOMMMIOREAD) pfnReadCallback, + RCPTRTYPE(PFNIOMMMIOFILL) pfnFillCallback); +VMMR3_INT_DECL(int) IOMR3MmioDeregister(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, uint32_t cbRange); + +/** @} */ +#endif /* IN_RING3 */ + + +/** @} */ + +RT_C_DECLS_END + +#endif + diff --git a/include/VBox/vmm/mm.h b/include/VBox/vmm/mm.h new file mode 100644 index 00000000..66490fce --- /dev/null +++ b/include/VBox/vmm/mm.h @@ -0,0 +1,370 @@ +/** @file + * MM - The Memory Manager. + */ + +/* + * Copyright (C) 2006-2010 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_mm_h +#define ___VBox_vmm_mm_h + +#include <VBox/types.h> +#include <iprt/x86.h> +#include <VBox/sup.h> +#include <iprt/stdarg.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_mm The Memory Manager API + * @{ + */ + +/** + * Memory Allocation Tags. + * For use with MMHyperAlloc(), MMR3HeapAlloc(), MMR3HeapAllocEx(), + * MMR3HeapAllocZ() and MMR3HeapAllocZEx(). + * + * @remark Don't forget to update the dump command in MMHeap.cpp! + */ +typedef enum MMTAG +{ + MM_TAG_INVALID = 0, + + MM_TAG_CFGM, + MM_TAG_CFGM_BYTES, + MM_TAG_CFGM_STRING, + MM_TAG_CFGM_USER, + + MM_TAG_CSAM, + MM_TAG_CSAM_PATCH, + + MM_TAG_CPUM_CTX, + + MM_TAG_DBGF, + MM_TAG_DBGF_AS, + MM_TAG_DBGF_CORE_WRITE, + MM_TAG_DBGF_INFO, + MM_TAG_DBGF_LINE, + MM_TAG_DBGF_LINE_DUP, + MM_TAG_DBGF_MODULE, + MM_TAG_DBGF_OS, + MM_TAG_DBGF_REG, + MM_TAG_DBGF_STACK, + MM_TAG_DBGF_SYMBOL, + MM_TAG_DBGF_SYMBOL_DUP, + + MM_TAG_EM, + + MM_TAG_IOM, + MM_TAG_IOM_STATS, + + MM_TAG_MM, + MM_TAG_MM_LOOKUP_GUEST, + MM_TAG_MM_LOOKUP_PHYS, + MM_TAG_MM_LOOKUP_VIRT, + MM_TAG_MM_PAGE, + + MM_TAG_PARAV, + + MM_TAG_PATM, + MM_TAG_PATM_PATCH, + + MM_TAG_PDM, + MM_TAG_PDM_ASYNC_COMPLETION, + MM_TAG_PDM_DEVICE, + MM_TAG_PDM_DEVICE_DESC, + MM_TAG_PDM_DEVICE_USER, + MM_TAG_PDM_DRIVER, + MM_TAG_PDM_DRIVER_DESC, + MM_TAG_PDM_DRIVER_USER, + MM_TAG_PDM_USB, + MM_TAG_PDM_USB_DESC, + MM_TAG_PDM_USB_USER, + MM_TAG_PDM_LUN, +#ifdef VBOX_WITH_NETSHAPER + MM_TAG_PDM_NET_SHAPER, +#endif /* VBOX_WITH_NETSHAPER */ + MM_TAG_PDM_QUEUE, + MM_TAG_PDM_THREAD, + + MM_TAG_PGM, + MM_TAG_PGM_CHUNK_MAPPING, + MM_TAG_PGM_HANDLERS, + MM_TAG_PGM_MAPPINGS, + MM_TAG_PGM_PHYS, + MM_TAG_PGM_POOL, + + MM_TAG_REM, + + MM_TAG_SELM, + + MM_TAG_SSM, + + MM_TAG_STAM, + + MM_TAG_TM, + + MM_TAG_TRPM, + + MM_TAG_VM, + MM_TAG_VM_REQ, + + MM_TAG_VMM, + + MM_TAG_HWACCM, + + MM_TAG_32BIT_HACK = 0x7fffffff +} MMTAG; + + + + +/** @defgroup grp_mm_hyper Hypervisor Memory Management + * @ingroup grp_mm + * @{ */ + +VMMDECL(RTR3PTR) MMHyperR0ToR3(PVM pVM, RTR0PTR R0Ptr); +VMMDECL(RTRCPTR) MMHyperR0ToRC(PVM pVM, RTR0PTR R0Ptr); +#ifndef IN_RING0 +VMMDECL(void *) MMHyperR0ToCC(PVM pVM, RTR0PTR R0Ptr); +#endif +VMMDECL(RTR0PTR) MMHyperR3ToR0(PVM pVM, RTR3PTR R3Ptr); +VMMDECL(RTRCPTR) MMHyperR3ToRC(PVM pVM, RTR3PTR R3Ptr); +VMMDECL(RTR3PTR) MMHyperRCToR3(PVM pVM, RTRCPTR RCPtr); +VMMDECL(RTR0PTR) MMHyperRCToR0(PVM pVM, RTRCPTR RCPtr); + +#ifndef IN_RING3 +VMMDECL(void *) MMHyperR3ToCC(PVM pVM, RTR3PTR R3Ptr); +#else +DECLINLINE(void *) MMHyperR3ToCC(PVM pVM, RTR3PTR R3Ptr) +{ + NOREF(pVM); + return R3Ptr; +} +#endif + + +#ifndef IN_RC +VMMDECL(void *) MMHyperRCToCC(PVM pVM, RTRCPTR RCPtr); +#else +DECLINLINE(void *) MMHyperRCToCC(PVM pVM, RTRCPTR RCPtr) +{ + NOREF(pVM); + return (void *)RCPtr; +} +#endif + +#ifndef IN_RING3 +VMMDECL(RTR3PTR) MMHyperCCToR3(PVM pVM, void *pv); +#else +DECLINLINE(RTR3PTR) MMHyperCCToR3(PVM pVM, void *pv) +{ + NOREF(pVM); + return pv; +} +#endif + +#ifndef IN_RING0 +VMMDECL(RTR0PTR) MMHyperCCToR0(PVM pVM, void *pv); +#else +DECLINLINE(RTR0PTR) MMHyperCCToR0(PVM pVM, void *pv) +{ + NOREF(pVM); + return pv; +} +#endif + +#ifndef IN_RC +VMMDECL(RTRCPTR) MMHyperCCToRC(PVM pVM, void *pv); +#else +DECLINLINE(RTRCPTR) MMHyperCCToRC(PVM pVM, void *pv) +{ + NOREF(pVM); + return (RTRCPTR)pv; +} +#endif + + +VMMDECL(int) MMHyperAlloc(PVM pVM, size_t cb, uint32_t uAlignment, MMTAG enmTag, void **ppv); +VMMDECL(int) MMHyperFree(PVM pVM, void *pv); +VMMDECL(void) MMHyperHeapCheck(PVM pVM); +VMMDECL(int) MMR3LockCall(PVM pVM); +#ifdef DEBUG +VMMDECL(void) MMHyperHeapDump(PVM pVM); +#endif +VMMDECL(size_t) MMHyperHeapGetFreeSize(PVM pVM); +VMMDECL(size_t) MMHyperHeapGetSize(PVM pVM); +VMMDECL(RTGCPTR) MMHyperGetArea(PVM pVM, size_t *pcb); +VMMDECL(bool) MMHyperIsInsideArea(PVM pVM, RTGCPTR GCPtr); + + +VMMDECL(RTHCPHYS) MMPage2Phys(PVM pVM, void *pvPage); +VMMDECL(void *) MMPagePhys2Page(PVM pVM, RTHCPHYS HCPhysPage); +VMMDECL(int) MMPagePhys2PageEx(PVM pVM, RTHCPHYS HCPhysPage, void **ppvPage); +VMMDECL(int) MMPagePhys2PageTry(PVM pVM, RTHCPHYS HCPhysPage, void **ppvPage); + + +/** @def MMHYPER_RC_ASSERT_RCPTR + * Asserts that an address is either NULL or inside the hypervisor memory area. + * This assertion only works while IN_RC, it's a NOP everywhere else. + * @thread The Emulation Thread. + */ +#ifdef IN_RC +# define MMHYPER_RC_ASSERT_RCPTR(pVM, RCPtr) Assert(MMHyperIsInsideArea((pVM), (RTRCUINTPTR)(RCPtr)) || !(RCPtr)) +#else +# define MMHYPER_RC_ASSERT_RCPTR(pVM, RCPtr) do { } while (0) +#endif + +/** @} */ + + +#ifdef IN_RING3 +/** @defgroup grp_mm_r3 The MM Host Context Ring-3 API + * @ingroup grp_mm + * @{ + */ + +VMMR3DECL(int) MMR3InitUVM(PUVM pUVM); +VMMR3DECL(int) MMR3Init(PVM pVM); +VMMR3DECL(int) MMR3InitPaging(PVM pVM); +VMMR3DECL(int) MMR3HyperInitFinalize(PVM pVM); +VMMR3DECL(int) MMR3Term(PVM pVM); +VMMR3DECL(void) MMR3TermUVM(PUVM pUVM); +VMMR3DECL(int) MMR3ReserveHandyPages(PVM pVM, uint32_t cHandyPages); +VMMR3DECL(int) MMR3IncreaseBaseReservation(PVM pVM, uint64_t cAddBasePages); +VMMR3DECL(int) MMR3AdjustFixedReservation(PVM pVM, int32_t cDeltaFixedPages, const char *pszDesc); +VMMR3DECL(int) MMR3UpdateShadowReservation(PVM pVM, uint32_t cShadowPages); + +VMMR3DECL(int) MMR3HCPhys2HCVirt(PVM pVM, RTHCPHYS HCPhys, void **ppv); + +/** @defgroup grp_mm_r3_hyper Hypervisor Memory Manager (HC R3 Portion) + * @ingroup grp_mm_r3 + * @{ */ +VMMR3DECL(int) MMR3HyperAllocOnceNoRel(PVM pVM, size_t cb, uint32_t uAlignment, MMTAG enmTag, void **ppv); +VMMR3DECL(int) MMR3HyperAllocOnceNoRelEx(PVM pVM, size_t cb, uint32_t uAlignment, MMTAG enmTag, uint32_t fFlags, void **ppv); +/** @name MMR3HyperAllocOnceNoRelEx flags + * @{ */ +/** Must have kernel mapping. + * If not specified, the R0 pointer may point to the user process mapping. */ +#define MMHYPER_AONR_FLAGS_KERNEL_MAPPING RT_BIT(0) +/** @} */ +VMMR3DECL(int) MMR3HyperSetGuard(PVM pVM, void *pvStart, size_t cb, bool fSet); +VMMR3DECL(int) MMR3HyperMapHCPhys(PVM pVM, void *pvR3, RTR0PTR pvR0, RTHCPHYS HCPhys, size_t cb, const char *pszDesc, PRTGCPTR pGCPtr); +VMMR3DECL(int) MMR3HyperMapGCPhys(PVM pVM, RTGCPHYS GCPhys, size_t cb, const char *pszDesc, PRTGCPTR pGCPtr); +VMMR3DECL(int) MMR3HyperMapMMIO2(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS off, RTGCPHYS cb, const char *pszDesc, PRTRCPTR pRCPtr); +VMMR3DECL(int) MMR3HyperMapPages(PVM pVM, void *pvR3, RTR0PTR pvR0, size_t cPages, PCSUPPAGE paPages, const char *pszDesc, PRTGCPTR pGCPtr); +VMMR3DECL(int) MMR3HyperReserve(PVM pVM, unsigned cb, const char *pszDesc, PRTGCPTR pGCPtr); +VMMR3DECL(RTHCPHYS) MMR3HyperHCVirt2HCPhys(PVM pVM, void *pvHC); +VMMR3DECL(int) MMR3HyperHCVirt2HCPhysEx(PVM pVM, void *pvHC, PRTHCPHYS pHCPhys); +VMMR3DECL(void *) MMR3HyperHCPhys2HCVirt(PVM pVM, RTHCPHYS HCPhys); +VMMR3DECL(int) MMR3HyperHCPhys2HCVirtEx(PVM pVM, RTHCPHYS HCPhys, void **ppv); +VMMR3_INT_DECL(int) MMR3HyperQueryInfoFromHCPhys(PVM pVM, RTHCPHYS HCPhys, char *pszWhat, size_t cbWhat, uint32_t *pcbAlloc); +VMMR3DECL(int) MMR3HyperReadGCVirt(PVM pVM, void *pvDst, RTGCPTR GCPtr, size_t cb); +/** @} */ + + +/** @defgroup grp_mm_phys Guest Physical Memory Manager + * @todo retire this group, elimintating or moving MMR3PhysGetRamSize to PGMPhys. + * @ingroup grp_mm_r3 + * @{ */ +VMMR3DECL(uint64_t) MMR3PhysGetRamSize(PVM pVM); +/** @} */ + + +/** @defgroup grp_mm_page Physical Page Pool + * @ingroup grp_mm_r3 + * @{ */ +VMMR3DECL(void *) MMR3PageAlloc(PVM pVM); +VMMR3DECL(RTHCPHYS) MMR3PageAllocPhys(PVM pVM); +VMMR3DECL(void) MMR3PageFree(PVM pVM, void *pvPage); +VMMR3DECL(void *) MMR3PageAllocLow(PVM pVM); +VMMR3DECL(void) MMR3PageFreeLow(PVM pVM, void *pvPage); +VMMR3DECL(void) MMR3PageFreeByPhys(PVM pVM, RTHCPHYS HCPhysPage); +VMMR3DECL(void *) MMR3PageDummyHCPtr(PVM pVM); +VMMR3DECL(RTHCPHYS) MMR3PageDummyHCPhys(PVM pVM); +/** @} */ + + +/** @defgroup grp_mm_heap Heap Manager + * @ingroup grp_mm_r3 + * @{ */ +VMMR3DECL(void *) MMR3HeapAlloc(PVM pVM, MMTAG enmTag, size_t cbSize); +VMMR3DECL(void *) MMR3HeapAllocU(PUVM pUVM, MMTAG enmTag, size_t cbSize); +VMMR3DECL(int) MMR3HeapAllocEx(PVM pVM, MMTAG enmTag, size_t cbSize, void **ppv); +VMMR3DECL(int) MMR3HeapAllocExU(PUVM pUVM, MMTAG enmTag, size_t cbSize, void **ppv); +VMMR3DECL(void *) MMR3HeapAllocZ(PVM pVM, MMTAG enmTag, size_t cbSize); +VMMR3DECL(void *) MMR3HeapAllocZU(PUVM pUVM, MMTAG enmTag, size_t cbSize); +VMMR3DECL(int) MMR3HeapAllocZEx(PVM pVM, MMTAG enmTag, size_t cbSize, void **ppv); +VMMR3DECL(int) MMR3HeapAllocZExU(PUVM pUVM, MMTAG enmTag, size_t cbSize, void **ppv); +VMMR3DECL(void *) MMR3HeapRealloc(void *pv, size_t cbNewSize); +VMMR3DECL(char *) MMR3HeapStrDup(PVM pVM, MMTAG enmTag, const char *psz); +VMMR3DECL(char *) MMR3HeapStrDupU(PUVM pUVM, MMTAG enmTag, const char *psz); +VMMR3DECL(char *) MMR3HeapAPrintf(PVM pVM, MMTAG enmTag, const char *pszFormat, ...); +VMMR3DECL(char *) MMR3HeapAPrintfU(PUVM pUVM, MMTAG enmTag, const char *pszFormat, ...); +VMMR3DECL(char *) MMR3HeapAPrintfV(PVM pVM, MMTAG enmTag, const char *pszFormat, va_list va); +VMMR3DECL(char *) MMR3HeapAPrintfVU(PUVM pUVM, MMTAG enmTag, const char *pszFormat, va_list va); +VMMR3DECL(void) MMR3HeapFree(void *pv); +/** @} */ + +/** @defgroup grp_mm_heap User-kernel Heap Manager. + * @ingroup grp_mm_r3 + * + * The memory is safely accessible from kernel context as well as user land. + * + * @{ */ +VMMR3DECL(void *) MMR3UkHeapAlloc(PVM pVM, MMTAG enmTag, size_t cbSize, PRTR0PTR pR0Ptr); +VMMR3DECL(int) MMR3UkHeapAllocEx(PVM pVM, MMTAG enmTag, size_t cbSize, void **ppv, PRTR0PTR pR0Ptr); +VMMR3DECL(void *) MMR3UkHeapAllocZ(PVM pVM, MMTAG enmTag, size_t cbSize, PRTR0PTR pR0Ptr); +VMMR3DECL(int) MMR3UkHeapAllocZEx(PVM pVM, MMTAG enmTag, size_t cbSize, void **ppv, PRTR0PTR pR0Ptr); +VMMR3DECL(void) MMR3UkHeapFree(PVM pVM, void *pv, MMTAG enmTag); +/** @} */ + +/** @} */ +#endif /* IN_RING3 */ + + + +#ifdef IN_RC +/** @defgroup grp_mm_gc The MM Guest Context API + * @ingroup grp_mm + * @{ + */ + +VMMRCDECL(void) MMGCRamRegisterTrapHandler(PVM pVM); +VMMRCDECL(void) MMGCRamDeregisterTrapHandler(PVM pVM); +VMMRCDECL(int) MMGCRamReadNoTrapHandler(void *pDst, void *pSrc, size_t cb); +/** + * @deprecated Don't use this as it doesn't check the page state. + */ +VMMRCDECL(int) MMGCRamWriteNoTrapHandler(void *pDst, void *pSrc, size_t cb); +VMMRCDECL(int) MMGCRamRead(PVM pVM, void *pDst, void *pSrc, size_t cb); +VMMRCDECL(int) MMGCRamWrite(PVM pVM, void *pDst, void *pSrc, size_t cb); + +/** @} */ +#endif /* IN_RC */ + +/** @} */ +RT_C_DECLS_END + + +#endif + diff --git a/include/VBox/vmm/patm.h b/include/VBox/vmm/patm.h new file mode 100644 index 00000000..70b7fa55 --- /dev/null +++ b/include/VBox/vmm/patm.h @@ -0,0 +1,672 @@ +/** @file + * PATM - Dynamic Guest OS Patching Manager. + */ + +/* + * Copyright (C) 2006-2010 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_patm_h +#define ___VBox_vmm_patm_h + +#include <VBox/types.h> +#include <VBox/dis.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_patm The Patch Manager API + * @{ + */ +#define MAX_PATCHES 512 + +/** + * Flags for specifying the type of patch to install with PATMR3InstallPatch + * @{ + */ +#define PATMFL_CODE32 RT_BIT_64(0) +#define PATMFL_INTHANDLER RT_BIT_64(1) +#define PATMFL_SYSENTER RT_BIT_64(2) +#define PATMFL_GUEST_SPECIFIC RT_BIT_64(3) +#define PATMFL_USER_MODE RT_BIT_64(4) +#define PATMFL_IDTHANDLER RT_BIT_64(5) +#define PATMFL_TRAPHANDLER RT_BIT_64(6) +#define PATMFL_DUPLICATE_FUNCTION RT_BIT_64(7) +#define PATMFL_REPLACE_FUNCTION_CALL RT_BIT_64(8) +#define PATMFL_TRAPHANDLER_WITH_ERRORCODE RT_BIT_64(9) +#define PATMFL_INTHANDLER_WITH_ERRORCODE (PATMFL_TRAPHANDLER_WITH_ERRORCODE) +#define PATMFL_MMIO_ACCESS RT_BIT_64(10) +/* no more room -> change PATMInternal.h if more is needed!! */ + +/* + * Flags above 1024 are reserved for internal use! + */ +/** @} */ + +/** Enable to activate sysenter emulation in GC. */ +/* #define PATM_EMULATE_SYSENTER */ + +/** + * Maximum number of cached VGA writes + */ +#define MAX_VGA_WRITE_CACHE 64 + +typedef struct PATMGCSTATE +{ + /* Virtual Flags register (IF + more later on) */ + uint32_t uVMFlags; + + /* Pending PATM actions (internal use only) */ + uint32_t uPendingAction; + + /* Records the number of times all patches are called (indicating how many exceptions we managed to avoid) */ + uint32_t uPatchCalls; + /* Scratchpad dword */ + uint32_t uScratch; + /* Debugging info */ + uint32_t uIretEFlags, uIretCS, uIretEIP; + + /* PATM stack pointer */ + uint32_t Psp; + + /* PATM interrupt flag */ + uint32_t fPIF; + /* PATM inhibit irq address (used by sti) */ + RTRCPTR GCPtrInhibitInterrupts; + + /* Scratch room for call patch */ + RTRCPTR GCCallPatchTargetAddr; + RTRCPTR GCCallReturnAddr; + + /* Temporary storage for guest registers. */ + struct + { + uint32_t uEAX; + uint32_t uECX; + uint32_t uEDI; + uint32_t eFlags; + uint32_t uFlags; + } Restore; +} PATMGCSTATE, *PPATMGCSTATE; + +typedef struct PATMTRAPREC +{ + /* pointer to original guest code instruction (for emulation) */ + RTRCPTR pNewEIP; + /* pointer to the next guest code instruction */ + RTRCPTR pNextInstr; + /* pointer to the corresponding next instruction in the patch block */ + RTRCPTR pNextPatchInstr; +} PATMTRAPREC, *PPATMTRAPREC; + + +/** + * Translation state (currently patch to GC ptr) + */ +typedef enum +{ + PATMTRANS_FAILED, + PATMTRANS_SAFE, /* Safe translation */ + PATMTRANS_PATCHSTART, /* Instruction starts a patch block */ + PATMTRANS_OVERWRITTEN, /* Instruction overwritten by patchjump */ + PATMTRANS_INHIBITIRQ /* Instruction must be executed due to instruction fusing */ +} PATMTRANSSTATE; + +/** + * Load virtualized flags. + * + * This function is called from CPUMRawEnter(). It doesn't have to update the + * IF and IOPL eflags bits, the caller will enforce those to set and 0 respectively. + * + * @param pVM VM handle. + * @param pCtxCore The cpu context core. + * @see pg_raw + */ +VMMDECL(void) PATMRawEnter(PVM pVM, PCPUMCTXCORE pCtxCore); + +/** + * Restores virtualized flags. + * + * This function is called from CPUMRawLeave(). It will update the eflags register. + * + * @param pVM VM handle. + * @param pCtxCore The cpu context core. + * @param rawRC Raw mode return code + * @see @ref pg_raw + */ +VMMDECL(void) PATMRawLeave(PVM pVM, PCPUMCTXCORE pCtxCore, int rawRC); + +/** + * Get the EFLAGS. + * This is a worker for CPUMRawGetEFlags(). + * + * @returns The eflags. + * @param pVM The VM handle. + * @param pCtxCore The context core. + */ +VMMDECL(uint32_t) PATMRawGetEFlags(PVM pVM, PCCPUMCTXCORE pCtxCore); + +/** + * Updates the EFLAGS. + * This is a worker for CPUMRawSetEFlags(). + * + * @param pVM The VM handle. + * @param pCtxCore The context core. + * @param efl The new EFLAGS value. + */ +VMMDECL(void) PATMRawSetEFlags(PVM pVM, PCPUMCTXCORE pCtxCore, uint32_t efl); + +/** + * Returns the guest context pointer of the GC context structure + * + * @returns VBox status code. + * @param pVM The VM to operate on. + */ +VMMDECL(RCPTRTYPE(PPATMGCSTATE)) PATMQueryGCState(PVM pVM); + +/** + * Checks whether the GC address is part of our patch region + * + * @returns true -> yes, false -> no + * @param pVM The VM to operate on. + * @param pAddr Guest context address + */ +VMMDECL(bool) PATMIsPatchGCAddr(PVM pVM, RTRCUINTPTR pAddr); + +/** + * Check if we must use raw mode (patch code being executed or marked safe for IF=0) + * + * @param pVM VM handle. + * @param pAddrGC Guest context address + */ +VMMDECL(bool) PATMShouldUseRawMode(PVM pVM, RTRCPTR pAddrGC); + +/** + * Query PATM state (enabled/disabled) + * + * @returns 0 - disabled, 1 - enabled + * @param pVM The VM to operate on. + */ +#define PATMIsEnabled(pVM) (pVM->fPATMEnabled) + +/** + * Set parameters for pending MMIO patch operation + * + * @returns VBox status code. + * @param pDevIns Device instance. + * @param GCPhys MMIO physical address + * @param pCachedData GC pointer to cached data + */ +VMMDECL(int) PATMSetMMIOPatchInfo(PVM pVM, RTGCPHYS GCPhys, RTRCPTR pCachedData); + + +/** + * Adds branch pair to the lookup cache of the particular branch instruction + * + * @returns VBox status + * @param pVM The VM to operate on. + * @param pJumpTableGC Pointer to branch instruction lookup cache + * @param pBranchTarget Original branch target + * @param pRelBranchPatch Relative duplicated function address + */ +VMMDECL(int) PATMAddBranchToLookupCache(PVM pVM, RTRCPTR pJumpTableGC, RTRCPTR pBranchTarget, RTRCUINTPTR pRelBranchPatch); + + +/** + * Checks if the int 3 was caused by a patched instruction + * + * @returns VBox status + * + * @param pVM The VM handle. + * @param pCtxCore The relevant core context. + */ +VMMRCDECL(int) PATMRCHandleInt3PatchTrap(PVM pVM, PCPUMCTXCORE pRegFrame); + +/** + * Checks if the int 3 was caused by a patched instruction + * + * @returns VBox status + * + * @param pVM The VM handle. + * @param pInstrGC Instruction pointer + * @param pOpcode Original instruction opcode (out, optional) + * @param pSize Original instruction size (out, optional) + */ +VMMDECL(bool) PATMIsInt3Patch(PVM pVM, RTRCPTR pInstrGC, uint32_t *pOpcode, uint32_t *pSize); + + +/** + * Checks if the interrupt flag is enabled or not. + * + * @returns true if it's enabled. + * @returns false if it's disabled. + * + * @param pVM The VM handle. + */ +VMMDECL(bool) PATMAreInterruptsEnabled(PVM pVM); + +/** + * Checks if the interrupt flag is enabled or not. + * + * @returns true if it's enabled. + * @returns false if it's disabled. + * + * @param pVM The VM handle. + * @param pCtxCore CPU context + */ +VMMDECL(bool) PATMAreInterruptsEnabledByCtxCore(PVM pVM, PCPUMCTXCORE pCtxCore); + +#ifdef PATM_EMULATE_SYSENTER +/** + * Emulate sysenter, sysexit and syscall instructions + * + * @returns VBox status + * + * @param pVM The VM handle. + * @param pCtxCore The relevant core context. + * @param pCpu Disassembly context + */ +VMMDECL(int) PATMSysCall(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu); +#endif + +#ifdef IN_RC +/** @defgroup grp_patm_gc The Patch Manager API + * @ingroup grp_patm + * @{ + */ + +/** + * Checks if the write is located on a page with was patched before. + * (if so, then we are not allowed to turn on r/w) + * + * @returns VBox status + * @param pVM The VM to operate on. + * @param pRegFrame CPU context + * @param GCPtr GC pointer to write address + * @param cbWrite Nr of bytes to write + * + */ +VMMRCDECL(int) PATMGCHandleWriteToPatchPage(PVM pVM, PCPUMCTXCORE pRegFrame, RTRCPTR GCPtr, uint32_t cbWrite); + +/** + * Checks if the illegal instruction was caused by a patched instruction + * + * @returns VBox status + * + * @param pVM The VM handle. + * @param pCtxCore The relevant core context. + */ +VMMDECL(int) PATMRCHandleIllegalInstrTrap(PVM pVM, PCPUMCTXCORE pRegFrame); + +/** @} */ + +#endif + +#ifdef IN_RING3 +/** @defgroup grp_patm_r3 The Patch Manager API + * @ingroup grp_patm + * @{ + */ + +/** + * Query PATM state (enabled/disabled) + * + * @returns 0 - disabled, 1 - enabled + * @param pVM The VM to operate on. + */ +VMMR3DECL(int) PATMR3IsEnabled(PVM pVM); + +/** + * Initializes the PATM. + * + * @returns VBox status code. + * @param pVM The VM to operate on. + */ +VMMR3DECL(int) PATMR3Init(PVM pVM); + +/** + * Finalizes HMA page attributes. + * + * @returns VBox status code. + * @param pVM The VM handle. + */ +VMMR3DECL(int) PATMR3InitFinalize(PVM pVM); + +/** + * Applies relocations to data and code managed by this + * component. This function will be called at init and + * whenever the VMM need to relocate it self inside the GC. + * + * The PATM will update the addresses used by the switcher. + * + * @param pVM The VM. + */ +VMMR3DECL(void) PATMR3Relocate(PVM pVM); + +/** + * Terminates the PATM. + * + * Termination means cleaning up and freeing all resources, + * the VM it self is at this point powered off or suspended. + * + * @returns VBox status code. + * @param pVM The VM to operate on. + */ +VMMR3DECL(int) PATMR3Term(PVM pVM); + +/** + * PATM reset callback. + * + * @returns VBox status code. + * @param pVM The VM which is reset. + */ +VMMR3DECL(int) PATMR3Reset(PVM pVM); + +/** + * Returns the host context pointer and size of the patch memory block + * + * @returns VBox status code. + * @param pVM The VM to operate on. + * @param pcb Size of the patch memory block + */ +VMMR3DECL(void *) PATMR3QueryPatchMemHC(PVM pVM, uint32_t *pcb); + +/** + * Returns the guest context pointer and size of the patch memory block + * + * @returns VBox status code. + * @param pVM The VM to operate on. + * @param pcb Size of the patch memory block + */ +VMMR3DECL(RTRCPTR) PATMR3QueryPatchMemGC(PVM pVM, uint32_t *pcb); + +/** + * Checks whether the GC address is inside a generated patch jump + * + * @returns true -> yes, false -> no + * @param pVM The VM to operate on. + * @param pAddr Guest context address + * @param pPatchAddr Guest context patch address (if true) + */ +VMMR3DECL(bool) PATMR3IsInsidePatchJump(PVM pVM, RTRCPTR pAddr, PRTGCPTR32 pPatchAddr); + + +/** + * Returns the GC pointer of the patch for the specified GC address + * + * @returns VBox status code. + * @param pVM The VM to operate on. + * @param pAddrGC Guest context address + */ +VMMR3DECL(RTRCPTR) PATMR3QueryPatchGCPtr(PVM pVM, RTRCPTR pAddrGC); + +/** + * Checks whether the HC address is part of our patch region + * + * @returns VBox status code. + * @param pVM The VM to operate on. + * @param pAddrGC Guest context address + */ +VMMR3DECL(bool) PATMR3IsPatchHCAddr(PVM pVM, R3PTRTYPE(uint8_t *) pAddrHC); + +/** + * Convert a GC patch block pointer to a HC patch pointer + * + * @returns HC pointer or NULL if it's not a GC patch pointer + * @param pVM The VM to operate on. + * @param pAddrGC GC pointer + */ +VMMR3DECL(R3PTRTYPE(void *)) PATMR3GCPtrToHCPtr(PVM pVM, RTRCPTR pAddrGC); + + +/** + * Returns the host context pointer and size of the GC context structure + * + * @returns VBox status code. + * @param pVM The VM to operate on. + */ +VMMR3DECL(PPATMGCSTATE) PATMR3QueryGCStateHC(PVM pVM); + +/** + * Handle trap inside patch code + * + * @returns VBox status code. + * @param pVM The VM to operate on. + * @param pCtx CPU context + * @param pEip GC pointer of trapping instruction + * @param pNewEip GC pointer to new instruction + */ +VMMR3DECL(int) PATMR3HandleTrap(PVM pVM, PCPUMCTX pCtx, RTRCPTR pEip, RTGCPTR *ppNewEip); + +/** + * Handle page-fault in monitored page + * + * @returns VBox status code. + * @param pVM The VM to operate on. + */ +VMMR3DECL(int) PATMR3HandleMonitoredPage(PVM pVM); + +/** + * Notifies PATM about a (potential) write to code that has been patched. + * + * @returns VBox status code. + * @param pVM The VM to operate on. + * @param GCPtr GC pointer to write address + * @param cbWrite Nr of bytes to write + * + */ +VMMR3DECL(int) PATMR3PatchWrite(PVM pVM, RTRCPTR GCPtr, uint32_t cbWrite); + +/** + * Notify PATM of a page flush + * + * @returns VBox status code + * @param pVM The VM to operate on. + * @param addr GC address of the page to flush + */ +VMMR3DECL(int) PATMR3FlushPage(PVM pVM, RTRCPTR addr); + +/** + * Allows or disallow patching of privileged instructions executed by the guest OS + * + * @returns VBox status code. + * @param pVM The VM to operate on. + * @param fAllowPatching Allow/disallow patching + */ +VMMR3DECL(int) PATMR3AllowPatching(PVM pVM, uint32_t fAllowPatching); + +/** + * Patch privileged instruction at specified location + * + * @returns VBox status code. + * @param pVM The VM to operate on. + * @param pInstr Guest context point to privileged instruction (0:32 flat address) + * @param flags Patch flags + * + * @note returns failure if patching is not allowed or possible + */ +VMMR3DECL(int) PATMR3InstallPatch(PVM pVM, RTRCPTR pInstrGC, uint64_t flags); + +/** + * Gives hint to PATM about supervisor guest instructions + * + * @returns VBox status code. + * @param pVM The VM to operate on. + * @param pInstr Guest context point to privileged instruction + * @param flags Patch flags + */ +VMMR3DECL(int) PATMR3AddHint(PVM pVM, RTRCPTR pInstrGC, uint32_t flags); + +/** + * Patch branch target function for call/jump at specified location. + * (in responds to a VINF_PATM_DUPLICATE_FUNCTION GC exit reason) + * + * @returns VBox status code. + * @param pVM The VM to operate on. + * @param pCtx Guest context + * + */ +VMMR3DECL(int) PATMR3DuplicateFunctionRequest(PVM pVM, PCPUMCTX pCtx); + +/** + * Query the corresponding GC instruction pointer from a pointer inside the patch block itself + * + * @returns original GC instruction pointer or 0 if not found + * @param pVM The VM to operate on. + * @param pPatchGC GC address in patch block + * @param pEnmState State of the translated address (out) + * + */ +VMMR3DECL(RTRCPTR) PATMR3PatchToGCPtr(PVM pVM, RTRCPTR pPatchGC, PATMTRANSSTATE *pEnmState); + +/** + * Converts Guest code GC ptr to Patch code GC ptr (if found) + * + * @returns corresponding GC pointer in patch block + * @param pVM The VM to operate on. + * @param pInstrGC Guest context pointer to privileged instruction + * + */ +VMMR3DECL(RTRCPTR) PATMR3GuestGCPtrToPatchGCPtr(PVM pVM, RCPTRTYPE(uint8_t*) pInstrGC); + +/** + * Query the opcode of the original code that was overwritten by the 5 bytes patch jump + * + * @returns VBox status code. + * @param pVM The VM to operate on. + * @param pInstrGC GC address of instr + * @param pByte opcode byte pointer (OUT) + * @returns VBOX error code + * + */ +VMMR3DECL(int) PATMR3QueryOpcode(PVM pVM, RTRCPTR pInstrGC, uint8_t *pByte); +VMMR3DECL(int) PATMR3ReadOrgInstr(PVM pVM, RTGCPTR32 GCPtrInstr, uint8_t *pbDst, size_t cbToRead, size_t *pcbRead); + +/** + * Disable patch for privileged instruction at specified location + * + * @returns VBox status code. + * @param pVM The VM to operate on. + * @param pInstr Guest context point to privileged instruction + * + * @note returns failure if patching is not allowed or possible + * + */ +VMMR3DECL(int) PATMR3DisablePatch(PVM pVM, RTRCPTR pInstrGC); + + +/** + * Enable patch for privileged instruction at specified location + * + * @returns VBox status code. + * @param pVM The VM to operate on. + * @param pInstr Guest context point to privileged instruction + * + * @note returns failure if patching is not allowed or possible + * + */ +VMMR3DECL(int) PATMR3EnablePatch(PVM pVM, RTRCPTR pInstrGC); + + +/** + * Remove patch for privileged instruction at specified location + * + * @returns VBox status code. + * @param pVM The VM to operate on. + * @param pInstr Guest context point to privileged instruction + * + * @note returns failure if patching is not allowed or possible + * + */ +VMMR3DECL(int) PATMR3RemovePatch(PVM pVM, RTRCPTR pInstrGC); + + +/** + * Detects it the specified address falls within a 5 byte jump generated for an active patch. + * If so, this patch is permanently disabled. + * + * @param pVM The VM to operate on. + * @param pInstrGC Guest context pointer to instruction + * @param pConflictGC Guest context pointer to check + */ +VMMR3DECL(int) PATMR3DetectConflict(PVM pVM, RTRCPTR pInstrGC, RTRCPTR pConflictGC); + + +/** + * Checks if the instructions at the specified address has been patched already. + * + * @returns boolean, patched or not + * @param pVM The VM to operate on. + * @param pInstrGC Guest context pointer to instruction + */ +VMMR3DECL(bool) PATMR3HasBeenPatched(PVM pVM, RTRCPTR pInstrGC); + + +/** + * Install Linux 2.6 spinlock patch + * + * @returns VBox status code. + * @param pVM The VM to operate on + * @param pCallAcquireSpinlockGC GC pointer of call instruction + * @param cbAcquireSpinlockCall Instruction size + * + */ +VMMR3DECL(int) PATMInstallSpinlockPatch(PVM pVM, RTRCPTR pCallAcquireSpinlockGC, uint32_t cbAcquireSpinlockCall); + + +/** + * Check if supplied call target is the Linux 2.6 spinlock acquire function + * + * @returns boolean + * @param pVM The VM to operate on + * @param pCallAcquireSpinlockGC Call target GC address + * + */ +VMMR3DECL(bool) PATMIsSpinlockAcquire(PVM pVM, RTRCPTR pCallTargetGC); + +/** + * Check if supplied call target is the Linux 2.6 spinlock release function + * + * @returns boolean + * @param pVM The VM to operate on + * @param pCallTargetGC Call target GC address + * + */ +VMMR3DECL(bool) PATMIsSpinlockRelease(PVM pVM, RTRCPTR pCallTargetGC); + +/** + * Check if supplied call target is the Linux 2.6 spinlock release function (patched equivalent) + * + * @returns boolean + * @param pVM The VM to operate on + * @param pCallTargetGC Call target GC address + * + */ +VMMR3DECL(bool) PATMIsSpinlockReleasePatch(PVM pVM, RTRCPTR pCallTargetGC); + +/** @} */ +#endif + + +/** @} */ +RT_C_DECLS_END + + +#endif diff --git a/include/VBox/vmm/pdm.h b/include/VBox/vmm/pdm.h new file mode 100644 index 00000000..ff95ea82 --- /dev/null +++ b/include/VBox/vmm/pdm.h @@ -0,0 +1,40 @@ +/** @file + * PDM - Pluggable Device Manager. + */ + +/* + * Copyright (C) 2006-2010 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_pdm_h +#define ___VBox_vmm_pdm_h + +#include <VBox/vmm/pdmapi.h> +#include <VBox/vmm/pdmqueue.h> +#include <VBox/vmm/pdmcritsect.h> +#include <VBox/vmm/pdmthread.h> +#include <VBox/vmm/pdmifs.h> +#include <VBox/vmm/pdmdrv.h> +#include <VBox/vmm/pdmdev.h> +#include <VBox/vmm/pdmusb.h> +#include <VBox/vmm/pdmsrv.h> + +#endif + diff --git a/include/VBox/vmm/pdmapi.h b/include/VBox/vmm/pdmapi.h new file mode 100644 index 00000000..1fb8aef6 --- /dev/null +++ b/include/VBox/vmm/pdmapi.h @@ -0,0 +1,210 @@ +/** @file + * PDM - Pluggable Device Manager, Core API. + * + * The 'Core API' has been put in a different header because everyone + * is currently including pdm.h. So, pdm.h is for including all of the + * PDM stuff, while pdmapi.h is for the core stuff. + */ + +/* + * Copyright (C) 2006-2010 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_pdmapi_h +#define ___VBox_vmm_pdmapi_h + +#include <VBox/vmm/pdmcommon.h> +#include <VBox/sup.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm The Pluggable Device Manager API + * @{ + */ + +VMMDECL(int) PDMGetInterrupt(PVMCPU pVCpu, uint8_t *pu8Interrupt); +VMMDECL(int) PDMIsaSetIrq(PVM pVM, uint8_t u8Irq, uint8_t u8Level, uint32_t uTagSrc); +VMM_INT_DECL(int) PDMIoApicSetIrq(PVM pVM, uint8_t u8Irq, uint8_t u8Level, uint32_t uTagSrc); +VMM_INT_DECL(int) PDMIoApicSendMsi(PVM pVM, RTGCPHYS GCAddr, uint32_t uValue, uint32_t uTagSrc); +VMMDECL(bool) PDMHasIoApic(PVM pVM); +VMMDECL(int) PDMApicHasPendingIrq(PVM pVM, bool *pfPending); +VMMDECL(int) PDMApicSetBase(PVM pVM, uint64_t u64Base); +VMMDECL(int) PDMApicGetBase(PVM pVM, uint64_t *pu64Base); +VMMDECL(int) PDMApicSetTPR(PVMCPU pVCpu, uint8_t u8TPR); +VMMDECL(int) PDMApicGetTPR(PVMCPU pVCpu, uint8_t *pu8TPR, bool *pfPending); +VMMDECL(int) PDMApicWriteMSR(PVM pVM, VMCPUID iCpu, uint32_t u32Reg, uint64_t u64Value); +VMMDECL(int) PDMApicReadMSR(PVM pVM, VMCPUID iCpu, uint32_t u32Reg, uint64_t *pu64Value); +VMMDECL(int) PDMVMMDevHeapR3ToGCPhys(PVM pVM, RTR3PTR pv, RTGCPHYS *pGCPhys); +VMMDECL(bool) PDMVMMDevHeapIsEnabled(PVM pVM); + + +/** @defgroup grp_pdm_r3 The PDM Host Context Ring-3 API + * @ingroup grp_pdm + * @{ + */ + +VMMR3DECL(int) PDMR3InitUVM(PUVM pUVM); +VMMR3DECL(int) PDMR3LdrLoadVMMR0U(PUVM pUVM); +VMMR3DECL(int) PDMR3Init(PVM pVM); +VMMR3DECL(void) PDMR3PowerOn(PVM pVM); +VMMR3DECL(void) PDMR3ResetCpu(PVMCPU pVCpu); +VMMR3DECL(void) PDMR3Reset(PVM pVM); +VMMR3DECL(void) PDMR3Suspend(PVM pVM); +VMMR3DECL(void) PDMR3Resume(PVM pVM); +VMMR3DECL(void) PDMR3PowerOff(PVM pVM); +VMMR3DECL(void) PDMR3Relocate(PVM pVM, RTGCINTPTR offDelta); +VMMR3DECL(int) PDMR3Term(PVM pVM); +VMMR3DECL(void) PDMR3TermUVM(PUVM pUVM); + +/** + * Module enumeration callback function. + * + * @returns VBox status. + * Failure will stop the search and return the return code. + * Warnings will be ignored and not returned. + * @param pVM VM Handle. + * @param pszFilename Module filename. + * @param pszName Module name. (short and unique) + * @param ImageBase Address where to executable image is loaded. + * @param cbImage Size of the executable image. + * @param fRC Set if raw-mode context, clear if host context. + * @param pvArg User argument. + */ +typedef DECLCALLBACK(int) FNPDMR3ENUM(PVM pVM, const char *pszFilename, const char *pszName, + RTUINTPTR ImageBase, size_t cbImage, bool fRC, void *pvArg); +/** Pointer to a FNPDMR3ENUM() function. */ +typedef FNPDMR3ENUM *PFNPDMR3ENUM; +VMMR3DECL(int) PDMR3LdrEnumModules(PVM pVM, PFNPDMR3ENUM pfnCallback, void *pvArg); +VMMR3DECL(void) PDMR3LdrRelocateU(PUVM pUVM, RTGCINTPTR offDelta); +VMMR3DECL(int) PDMR3LdrGetSymbolR3(PVM pVM, const char *pszModule, const char *pszSymbol, void **ppvValue); +VMMR3DECL(int) PDMR3LdrGetSymbolR0(PVM pVM, const char *pszModule, const char *pszSymbol, PRTR0PTR ppvValue); +VMMR3DECL(int) PDMR3LdrGetSymbolR0Lazy(PVM pVM, const char *pszModule, const char *pszSearchPath, const char *pszSymbol, PRTR0PTR ppvValue); +VMMR3DECL(int) PDMR3LdrLoadRC(PVM pVM, const char *pszFilename, const char *pszName); +VMMR3DECL(int) PDMR3LdrGetSymbolRC(PVM pVM, const char *pszModule, const char *pszSymbol, PRTRCPTR pRCPtrValue); +VMMR3DECL(int) PDMR3LdrGetSymbolRCLazy(PVM pVM, const char *pszModule, const char *pszSearchPath, const char *pszSymbol, PRTRCPTR pRCPtrValue); +VMMR3DECL(int) PDMR3LdrQueryRCModFromPC(PVM pVM, RTRCPTR uPC, + char *pszModName, size_t cchModName, PRTRCPTR pMod, + char *pszNearSym1, size_t cchNearSym1, PRTRCPTR pNearSym1, + char *pszNearSym2, size_t cchNearSym2, PRTRCPTR pNearSym2); +VMMR3DECL(int) PDMR3LdrQueryR0ModFromPC(PVM pVM, RTR0PTR uPC, + char *pszModName, size_t cchModName, PRTR0PTR pMod, + char *pszNearSym1, size_t cchNearSym1, PRTR0PTR pNearSym1, + char *pszNearSym2, size_t cchNearSym2, PRTR0PTR pNearSym2); +VMMR3DECL(int) PDMR3LdrGetInterfaceSymbols(PVM pVM, + void *pvInterface, size_t cbInterface, + const char *pszModule, const char *pszSearchPath, + const char *pszSymPrefix, const char *pszSymList, + bool fRing0OrRC); + +VMMR3DECL(int) PDMR3QueryDevice(PVM pVM, const char *pszDevice, unsigned iInstance, PPPDMIBASE ppBase); +VMMR3DECL(int) PDMR3QueryDeviceLun(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPPDMIBASE ppBase); +VMMR3DECL(int) PDMR3QueryLun(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPPDMIBASE ppBase); +VMMR3DECL(int) PDMR3QueryDriverOnLun(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, const char *pszDriver, + PPPDMIBASE ppBase); +VMMR3DECL(int) PDMR3DeviceAttach(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, uint32_t fFlags, PPDMIBASE *ppBase); +VMMR3DECL(int) PDMR3DeviceDetach(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, uint32_t fFlags); +VMMR3_INT_DECL(PPDMCRITSECT) PDMR3DevGetCritSect(PVM pVM, PPDMDEVINS pDevIns); +VMMR3DECL(int) PDMR3DriverAttach(PVM pVM, const char *pszDevice, unsigned iDevIns, unsigned iLun, uint32_t fFlags, PPPDMIBASE ppBase); +VMMR3DECL(int) PDMR3DriverDetach(PVM pVM, const char *pszDevice, unsigned iDevIns, unsigned iLun, + const char *pszDriver, unsigned iOccurance, uint32_t fFlags); +VMMR3DECL(int) PDMR3DriverReattach(PVM pVM, const char *pszDevice, unsigned iDevIns, unsigned iLun, + const char *pszDriver, unsigned iOccurance, uint32_t fFlags, PCFGMNODE pCfg, PPPDMIBASE ppBase); +VMMR3DECL(void) PDMR3DmaRun(PVM pVM); +VMMR3DECL(int) PDMR3LockCall(PVM pVM); +VMMR3DECL(int) PDMR3RegisterVMMDevHeap(PVM pVM, RTGCPHYS GCPhys, RTR3PTR pvHeap, unsigned cbSize); +VMMR3DECL(int) PDMR3VMMDevHeapAlloc(PVM pVM, unsigned cbSize, RTR3PTR *ppv); +VMMR3DECL(int) PDMR3VMMDevHeapFree(PVM pVM, RTR3PTR pv); +VMMR3DECL(int) PDMR3UnregisterVMMDevHeap(PVM pVM, RTGCPHYS GCPhys); +VMMR3_INT_DECL(int) PDMR3TracingConfig(PVM pVM, const char *pszName, size_t cchName, bool fEnable, bool fApply); +VMMR3_INT_DECL(bool) PDMR3TracingAreAll(PVM pVM, bool fEnabled); +VMMR3_INT_DECL(int) PDMR3TracingQueryConfig(PVM pVM, char *pszConfig, size_t cbConfig); +/** @} */ + + + +/** @defgroup grp_pdm_rc The PDM Raw-Mode Context API + * @ingroup grp_pdm + * @{ + */ +/** @} */ + + + +/** @defgroup grp_pdm_r0 The PDM Ring-0 Context API + * @ingroup grp_pdm + * @{ + */ + +/** + * Request buffer for PDMR0DriverCallReqHandler / VMMR0_DO_PDM_DRIVER_CALL_REQ_HANDLER. + * @see PDMR0DriverCallReqHandler. + */ +typedef struct PDMDRIVERCALLREQHANDLERREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The driver instance. */ + PPDMDRVINSR0 pDrvInsR0; + /** The operation. */ + uint32_t uOperation; + /** Explicit alignment padding. */ + uint32_t u32Alignment; + /** Optional 64-bit integer argument. */ + uint64_t u64Arg; +} PDMDRIVERCALLREQHANDLERREQ; +/** Pointer to a PDMR0DriverCallReqHandler / VMMR0_DO_PDM_DRIVER_CALL_REQ_HANDLER + * request buffer. */ +typedef PDMDRIVERCALLREQHANDLERREQ *PPDMDRIVERCALLREQHANDLERREQ; + +VMMR0_INT_DECL(int) PDMR0DriverCallReqHandler(PVM pVM, PPDMDRIVERCALLREQHANDLERREQ pReq); + +/** + * Request buffer for PDMR0DeviceCallReqHandler / VMMR0_DO_PDM_DEVICE_CALL_REQ_HANDLER. + * @see PDMR0DeviceCallReqHandler. + */ +typedef struct PDMDEVICECALLREQHANDLERREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The device instance. */ + PPDMDEVINSR0 pDevInsR0; + /** The request handler for the device. */ + PFNPDMDEVREQHANDLERR0 pfnReqHandlerR0; + /** The operation. */ + uint32_t uOperation; + /** Explicit alignment padding. */ + uint32_t u32Alignment; + /** Optional 64-bit integer argument. */ + uint64_t u64Arg; +} PDMDEVICECALLREQHANDLERREQ; +/** Pointer to a PDMR0DeviceCallReqHandler / + * VMMR0_DO_PDM_DEVICE_CALL_REQ_HANDLER request buffer. */ +typedef PDMDEVICECALLREQHANDLERREQ *PPDMDEVICECALLREQHANDLERREQ; + +VMMR0_INT_DECL(int) PDMR0DeviceCallReqHandler(PVM pVM, PPDMDEVICECALLREQHANDLERREQ pReq); + +/** @} */ + +RT_C_DECLS_END + +/** @} */ + +#endif diff --git a/include/VBox/vmm/pdmasynccompletion.h b/include/VBox/vmm/pdmasynccompletion.h new file mode 100644 index 00000000..1d1af265 --- /dev/null +++ b/include/VBox/vmm/pdmasynccompletion.h @@ -0,0 +1,368 @@ +/** @file + * PDM - Pluggable Device Manager, Async I/O Completion. + */ + +/* + * Copyright (C) 2007-2010 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_pdmasynccompletion_h +#define ___VBox_vmm_pdmasynccompletion_h + +#include <VBox/types.h> +#include <VBox/err.h> +#include <iprt/assert.h> +#include <iprt/sg.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_async_completion The PDM Async I/O Completion API + * @ingroup grp_pdm + * @{ + */ + +/** Pointer to a PDM async completion template handle. */ +typedef struct PDMASYNCCOMPLETIONTEMPLATE *PPDMASYNCCOMPLETIONTEMPLATE; +/** Pointer to a PDM async completion template handle pointer. */ +typedef PPDMASYNCCOMPLETIONTEMPLATE *PPPDMASYNCCOMPLETIONTEMPLATE; + +/** Pointer to a PDM async completion task handle. */ +typedef struct PDMASYNCCOMPLETIONTASK *PPDMASYNCCOMPLETIONTASK; +/** Pointer to a PDM async completion task handle pointer. */ +typedef PPDMASYNCCOMPLETIONTASK *PPPDMASYNCCOMPLETIONTASK; + +/** Pointer to a PDM async completion endpoint handle. */ +typedef struct PDMASYNCCOMPLETIONENDPOINT *PPDMASYNCCOMPLETIONENDPOINT; +/** Pointer to a PDM async completion endpoint handle pointer. */ +typedef PPDMASYNCCOMPLETIONENDPOINT *PPPDMASYNCCOMPLETIONENDPOINT; + + +/** + * Completion callback for devices. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param rc The status code of the completed request. + */ +typedef DECLCALLBACK(void) FNPDMASYNCCOMPLETEDEV(PPDMDEVINS pDevIns, void *pvUser, int rc); +/** Pointer to a FNPDMASYNCCOMPLETEDEV(). */ +typedef FNPDMASYNCCOMPLETEDEV *PFNPDMASYNCCOMPLETEDEV; + + +/** + * Completion callback for drivers. + * + * @param pDrvIns The driver instance. + * @param pvTemplateUser User argument given when creating the template. + * @param pvUser User argument given during request initiation. + * @param rc The status code of the completed request. + */ +typedef DECLCALLBACK(void) FNPDMASYNCCOMPLETEDRV(PPDMDRVINS pDrvIns, void *pvTemplateUser, void *pvUser, int rc); +/** Pointer to a FNPDMASYNCCOMPLETEDRV(). */ +typedef FNPDMASYNCCOMPLETEDRV *PFNPDMASYNCCOMPLETEDRV; + + +/** + * Completion callback for USB devices. + * + * @param pUsbIns The USB device instance. + * @param pvUser User argument. + * @param rc The status code of the completed request. + */ +typedef DECLCALLBACK(void) FNPDMASYNCCOMPLETEUSB(PPDMUSBINS pUsbIns, void *pvUser, int rc); +/** Pointer to a FNPDMASYNCCOMPLETEUSB(). */ +typedef FNPDMASYNCCOMPLETEUSB *PFNPDMASYNCCOMPLETEUSB; + + +/** + * Completion callback for internal. + * + * @param pVM Pointer to the shared VM structure. + * @param pvUser User argument for the task. + * @param pvUser2 User argument for the template. + * @param rc The status code of the completed request. + */ +typedef DECLCALLBACK(void) FNPDMASYNCCOMPLETEINT(PVM pVM, void *pvUser, void *pvUser2, int rc); +/** Pointer to a FNPDMASYNCCOMPLETEINT(). */ +typedef FNPDMASYNCCOMPLETEINT *PFNPDMASYNCCOMPLETEINT; + + +/** + * Creates an async completion template for a device instance. + * + * The template is used when creating new completion tasks. + * + * @returns VBox status code. + * @param pVM Pointer to the shared VM structure. + * @param pDevIns The device instance. + * @param ppTemplate Where to store the template pointer on success. + * @param pfnCompleted The completion callback routine. + * @param pszDesc Description. + */ +VMMR3DECL(int) PDMR3AsyncCompletionTemplateCreateDevice(PVM pVM, PPDMDEVINS pDevIns, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate, PFNPDMASYNCCOMPLETEDEV pfnCompleted, const char *pszDesc); + +/** + * Creates an async completion template for a driver instance. + * + * The template is used when creating new completion tasks. + * + * @returns VBox status code. + * @param pVM Pointer to the shared VM structure. + * @param pDrvIns The driver instance. + * @param ppTemplate Where to store the template pointer on success. + * @param pfnCompleted The completion callback routine. + * @param pvTemplateUser Template user argument. + * @param pszDesc Description. + */ +VMMR3DECL(int) PDMR3AsyncCompletionTemplateCreateDriver(PVM pVM, PPDMDRVINS pDrvIns, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate, PFNPDMASYNCCOMPLETEDRV pfnCompleted, void *pvTemplateUser, const char *pszDesc); + +/** + * Creates an async completion template for a USB device instance. + * + * The template is used when creating new completion tasks. + * + * @returns VBox status code. + * @param pVM Pointer to the shared VM structure. + * @param pUsbIns The USB device instance. + * @param ppTemplate Where to store the template pointer on success. + * @param pfnCompleted The completion callback routine. + * @param pszDesc Description. + */ +VMMR3DECL(int) PDMR3AsyncCompletionTemplateCreateUsb(PVM pVM, PPDMUSBINS pUsbIns, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate, PFNPDMASYNCCOMPLETEUSB pfnCompleted, const char *pszDesc); + +/** + * Creates an async completion template for internally by the VMM. + * + * The template is used when creating new completion tasks. + * + * @returns VBox status code. + * @param pVM Pointer to the shared VM structure. + * @param ppTemplate Where to store the template pointer on success. + * @param pfnCompleted The completion callback routine. + * @param pvUser2 The 2nd user argument for the callback. + * @param pszDesc Description. + */ +VMMR3DECL(int) PDMR3AsyncCompletionTemplateCreateInternal(PVM pVM, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate, PFNPDMASYNCCOMPLETEINT pfnCompleted, void *pvUser2, const char *pszDesc); + +/** + * Destroys the specified async completion template. + * + * @returns VBox status codes: + * @retval VINF_SUCCESS on success. + * @retval VERR_PDM_ASYNC_TEMPLATE_BUSY if the template is still in use. + * + * @param pTemplate The template in question. + */ +VMMR3DECL(int) PDMR3AsyncCompletionTemplateDestroy(PPDMASYNCCOMPLETIONTEMPLATE pTemplate); + +/** + * Destroys all the specified async completion templates for the given device instance. + * + * @returns VBox status codes: + * @retval VINF_SUCCESS on success. + * @retval VERR_PDM_ASYNC_TEMPLATE_BUSY if one or more of the templates are still in use. + * + * @param pVM Pointer to the shared VM structure. + * @param pDevIns The device instance. + */ +VMMR3DECL(int) PDMR3AsyncCompletionTemplateDestroyDevice(PVM pVM, PPDMDEVINS pDevIns); + +/** + * Destroys all the specified async completion templates for the given driver instance. + * + * @returns VBox status codes: + * @retval VINF_SUCCESS on success. + * @retval VERR_PDM_ASYNC_TEMPLATE_BUSY if one or more of the templates are still in use. + * + * @param pVM Pointer to the shared VM structure. + * @param pDrvIns The driver instance. + */ +VMMR3DECL(int) PDMR3AsyncCompletionTemplateDestroyDriver(PVM pVM, PPDMDRVINS pDrvIns); + +/** + * Destroys all the specified async completion templates for the given USB device instance. + * + * @returns VBox status codes: + * @retval VINF_SUCCESS on success. + * @retval VERR_PDM_ASYNC_TEMPLATE_BUSY if one or more of the templates are still in use. + * + * @param pVM Pointer to the shared VM structure. + * @param pUsbIns The USB device instance. + */ +VMMR3DECL(int) PDMR3AsyncCompletionTemplateDestroyUsb(PVM pVM, PPDMUSBINS pUsbIns); + + +/** + * Opens a file as an async completion endpoint. + * + * @returns VBox status code. + * @param ppEndpoint Where to store the opaque endpoint handle on success. + * @param pszFilename Path to the file which is to be opened. (UTF-8) + * @param fFlags Open flags, see grp_pdmacep_file_flags. + * @param pTemplate Handle to the completion callback template to use + * for this end point. + */ +VMMR3DECL(int) PDMR3AsyncCompletionEpCreateForFile(PPPDMASYNCCOMPLETIONENDPOINT ppEndpoint, + const char *pszFilename, uint32_t fFlags, + PPDMASYNCCOMPLETIONTEMPLATE pTemplate); + +/** @defgroup grp_pdmacep_file_flags Flags for PDMR3AsyncCompletionEpCreateForFile + * @{ */ +/** Open the file in read-only mode. */ +#define PDMACEP_FILE_FLAGS_READ_ONLY RT_BIT_32(0) +/** Whether the file should not be write protected. + * The default is to protect the file against writes by other processes + * when opened in read/write mode to prevent data corruption by + * concurrent access which can occur if the local writeback cache is enabled. + */ +#define PDMACEP_FILE_FLAGS_DONT_LOCK RT_BIT_32(2) +/** Open the endpoint with the host cache enabled. */ +#define PDMACEP_FILE_FLAGS_HOST_CACHE_ENABLED RT_BIT_32(3) +/** @} */ + +/** + * Closes a endpoint waiting for any pending tasks to finish. + * + * @returns nothing. + * @param pEndpoint Handle of the endpoint. + */ +VMMR3DECL(void) PDMR3AsyncCompletionEpClose(PPDMASYNCCOMPLETIONENDPOINT pEndpoint); + +/** + * Creates a read task on the given endpoint. + * + * @returns VBox status code. + * @param pEndpoint The file endpoint to read from. + * @param off Where to start reading from. + * @param paSegments Scatter gather list to store the data in. + * @param cSegments Number of segments in the list. + * @param cbRead The overall number of bytes to read. + * @param pvUser Opaque user data returned in the completion callback + * upon completion of the task. + * @param ppTask Where to store the task handle on success. + */ +VMMR3DECL(int) PDMR3AsyncCompletionEpRead(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, RTFOFF off, + PCRTSGSEG paSegments, unsigned cSegments, + size_t cbRead, void *pvUser, + PPPDMASYNCCOMPLETIONTASK ppTask); + +/** + * Creates a write task on the given endpoint. + * + * @returns VBox status code. + * @param pEndpoint The file endpoint to write to. + * @param off Where to start writing at. + * @param paSegments Scatter gather list of the data to write. + * @param cSegments Number of segments in the list. + * @param cbWrite The overall number of bytes to write. + * @param pvUser Opaque user data returned in the completion callback + * upon completion of the task. + * @param ppTask Where to store the task handle on success. + */ +VMMR3DECL(int) PDMR3AsyncCompletionEpWrite(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, RTFOFF off, + PCRTSGSEG paSegments, unsigned cSegments, + size_t cbWrite, void *pvUser, + PPPDMASYNCCOMPLETIONTASK ppTask); + +/** + * Creates a flush task on the given endpoint. + * + * Every read and write task initiated before the flush task is + * finished upon completion of this task. + * + * @returns VBox status code. + * @param pEndpoint The file endpoint to flush. + * @param pvUser Opaque user data returned in the completion callback + * upon completion of the task. + * @param ppTask Where to store the task handle on success. + */ +VMMR3DECL(int) PDMR3AsyncCompletionEpFlush(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, + void *pvUser, + PPPDMASYNCCOMPLETIONTASK ppTask); + +/** + * Queries the size of an endpoint. + * Not that some endpoints may not support this and will return an error + * (sockets for example). + * + * @returns VBox status code. + * @retval VERR_NOT_SUPPORTED if the endpoint does not support this operation. + * @param pEndpoint The file endpoint. + * @param pcbSize Where to store the size of the endpoint. + */ +VMMR3DECL(int) PDMR3AsyncCompletionEpGetSize(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, + uint64_t *pcbSize); + +/** + * Sets the size of an endpoint. + * Not that some endpoints may not support this and will return an error + * (sockets for example). + * + * @returns VBox status code. + * @retval VERR_NOT_SUPPORTED if the endpoint does not support this operation. + * @param pEndpoint The file endpoint. + * @param cbSize The size to set. + * + * @note PDMR3AsyncCompletionEpFlush should be called before this operation is executed. + */ +VMMR3DECL(int) PDMR3AsyncCompletionEpSetSize(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, + uint64_t cbSize); + +/** + * Assigns or removes a bandwidth control manager to/from the endpoint. + * + * @returns VBox status code. + * @param pEndpoint The endpoint. + * @param pcszBwMgr The identifer of the new bandwidth manager to assign + * or NULL to remove the current one. + */ +VMMR3DECL(int) PDMR3AsyncCompletionEpSetBwMgr(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, + const char *pcszBwMgr); + +/** + * Cancels an async completion task. + * + * If you want to use this method, you have to take great create to make sure + * you will never attempt cancel a task which has been completed. Since there is + * no reference counting or anything on the task it self, you have to serialize + * the cancelation and completion paths such that the aren't racing one another. + * + * @returns VBox status code + * @param pTask The Task to cancel. + */ +VMMR3DECL(int) PDMR3AsyncCompletionTaskCancel(PPDMASYNCCOMPLETIONTASK pTask); + +/** + * Changes the limit of a bandwidth manager for file endpoints to the given value. + * + * @returns VBox status code. + * @param pVM Pointer to the shared VM structure. + * @param pcszBwMgr The identifer of the bandwidth manager to change. + * @param cbMaxNew The new maximum for the bandwidth manager in bytes/sec. + */ +VMMR3DECL(int) PDMR3AsyncCompletionBwMgrSetMaxForFile(PVM pVM, const char *pcszBwMgr, uint32_t cbMaxNew); + +/** @} */ + +RT_C_DECLS_END + +#endif + diff --git a/include/VBox/vmm/pdmasynctask.h b/include/VBox/vmm/pdmasynctask.h new file mode 100644 index 00000000..65fdd245 --- /dev/null +++ b/include/VBox/vmm/pdmasynctask.h @@ -0,0 +1,61 @@ +/** @file + * PDM - Pluggable Device Manager, Async Task. + */ + +/* + * Copyright (C) 2007-2010 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_pdmasynctask_h +#define ___VBox_vmm_pdmasynctask_h + +#include <VBox/types.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_async_task The PDM Async Task API + * @ingroup grp_pdm + * @{ + */ + +/** Pointer to a PDM async task template handle. */ +typedef struct PDMASYNCTASKTEMPLATE *PPDMASYNCTASKTEMPLATE; +/** Pointer to a PDM async task template handle pointer. */ +typedef PPDMASYNCTASKTEMPLATE *PPPDMASYNCTASKTEMPLATE; + +/** Pointer to a PDM async task handle. */ +typedef struct PDMASYNCTASK *PPDMASYNCTASK; +/** Pointer to a PDM async task handle pointer. */ +typedef PPDMASYNCTASK *PPPDMASYNCTASK; + +/* This should be similar to VMReq, only difference there will be a pool + of worker threads instead of EMT. The actual implementation should be + made in IPRT so we can reuse it for other stuff later. The reason why + it should be put in PDM is because we need to manage it wrt to VM + state changes (need exception - add a flag for this). */ + +/** @} */ + + +RT_C_DECLS_END + +#endif + diff --git a/include/VBox/vmm/pdmblkcache.h b/include/VBox/vmm/pdmblkcache.h new file mode 100644 index 00000000..fc92bc4f --- /dev/null +++ b/include/VBox/vmm/pdmblkcache.h @@ -0,0 +1,422 @@ +/** @file + * PDM - Pluggable Device Manager, Block cache. + */ + +/* + * Copyright (C) 2007-2010 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_pdmblkcache_h +#define ___VBox_vmm_pdmblkcache_h + +#include <VBox/types.h> +#include <VBox/err.h> +#include <iprt/assert.h> +#include <iprt/sg.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_blk_cache The PDM Block Cache API + * @ingroup grp_pdm + * @{ + */ + +/** Pointer to a PDM block cache. */ +typedef struct PDMBLKCACHE *PPDMBLKCACHE; +/** Pointer to a PDM block cache pointer. */ +typedef PPDMBLKCACHE *PPPDMBLKCACHE; + +/** I/O transfer handle. */ +typedef struct PDMBLKCACHEIOXFER *PPDMBLKCACHEIOXFER; + +/** + * Block cache I/O request transfer direction. + */ +typedef enum PDMBLKCACHEXFERDIR +{ + /** Read */ + PDMBLKCACHEXFERDIR_READ = 0, + /** Write */ + PDMBLKCACHEXFERDIR_WRITE, + /** Flush */ + PDMBLKCACHEXFERDIR_FLUSH, + /** Discard */ + PDMBLKCACHEXFERDIR_DISCARD +} PDMBLKCACHEXFERDIR; + +/** + * Completion callback for drivers. + * + * @param pDrvIns The driver instance. + * @param pvUser User argument given during request initiation. + * @param rc The status code of the completed request. + */ +typedef DECLCALLBACK(void) FNPDMBLKCACHEXFERCOMPLETEDRV(PPDMDRVINS pDrvIns, void *pvUser, int rc); +/** Pointer to a FNPDMBLKCACHEXFERCOMPLETEDRV(). */ +typedef FNPDMBLKCACHEXFERCOMPLETEDRV *PFNPDMBLKCACHEXFERCOMPLETEDRV; + +/** + * I/O enqueue callback for drivers. + * + * @param pDrvIns The driver instance. + * @param pvUser User argument given during request initiation. + * @param rc The status code of the completed request. + */ +typedef DECLCALLBACK(int) FNPDMBLKCACHEXFERENQUEUEDRV(PPDMDRVINS pDrvIns, + PDMBLKCACHEXFERDIR enmXferDir, + uint64_t off, size_t cbXfer, + PCRTSGBUF pcSgBuf, PPDMBLKCACHEIOXFER hIoXfer); +/** Pointer to a FNPDMBLKCACHEXFERENQUEUEDRV(). */ +typedef FNPDMBLKCACHEXFERENQUEUEDRV *PFNPDMBLKCACHEXFERENQUEUEDRV; + +/** + * Discard enqueue callback for drivers. + * + * @param pDrvIns The driver instance. + * @param paRanges Ranges to discard. + * @param cRanges Number of range entries. + * @param hIoXfer I/O handle to return on completion. + */ +typedef DECLCALLBACK(int) FNPDMBLKCACHEXFERENQUEUEDISCARDDRV(PPDMDRVINS pDrvIns, + PCRTRANGE paRanges, unsigned cRanges, + PPDMBLKCACHEIOXFER hIoXfer); +/** Pointer to a FNPDMBLKCACHEXFERENQUEUEDISCARDDRV(). */ +typedef FNPDMBLKCACHEXFERENQUEUEDISCARDDRV *PFNPDMBLKCACHEXFERENQUEUEDISCARDDRV; + +/** + * Completion callback for devices. + * + * @param pDrvIns The device instance. + * @param pvUser User argument given during request initiation. + * @param rc The status code of the completed request. + */ +typedef DECLCALLBACK(void) FNPDMBLKCACHEXFERCOMPLETEDEV(PPDMDEVINS pDevIns, void *pvUser, int rc); +/** Pointer to a FNPDMBLKCACHEXFERCOMPLETEDEV(). */ +typedef FNPDMBLKCACHEXFERCOMPLETEDEV *PFNPDMBLKCACHEXFERCOMPLETEDEV; + +/** + * I/O enqueue callback for devices. + * + * @param pDevIns The device instance. + * @param pvUser User argument given during request initiation. + * @param rc The status code of the completed request. + */ +typedef DECLCALLBACK(int) FNPDMBLKCACHEXFERENQUEUEDEV(PPDMDEVINS pDevIns, + PDMBLKCACHEXFERDIR enmXferDir, + uint64_t off, size_t cbXfer, + PCRTSGBUF pcSgBuf, PPDMBLKCACHEIOXFER hIoXfer); +/** Pointer to a FNPDMBLKCACHEXFERENQUEUEDEV(). */ +typedef FNPDMBLKCACHEXFERENQUEUEDEV *PFNPDMBLKCACHEXFERENQUEUEDEV; + +/** + * Discard enqueue callback for devices. + * + * @param pDrvIns The driver instance. + * @param paRanges Ranges to discard. + * @param cRanges Number of range entries. + * @param hIoXfer I/O handle to return on completion. + */ +typedef DECLCALLBACK(int) FNPDMBLKCACHEXFERENQUEUEDISCARDDEV(PPDMDEVINS pDevIns, + PCRTRANGE paRanges, unsigned cRanges, + PPDMBLKCACHEIOXFER hIoXfer); +/** Pointer to a FNPDMBLKCACHEXFERENQUEUEDISCARDDEV(). */ +typedef FNPDMBLKCACHEXFERENQUEUEDISCARDDEV *PFNPDMBLKCACHEXFERENQUEUEDISCARDDEV; + +/** + * Completion callback for drivers. + * + * @param pDrvIns The driver instance. + * @param pvUser User argument given during request initiation. + * @param rc The status code of the completed request. + */ +typedef DECLCALLBACK(void) FNPDMBLKCACHEXFERCOMPLETEINT(void *pvUserInt, void *pvUser, int rc); +/** Pointer to a FNPDMBLKCACHEXFERCOMPLETEINT(). */ +typedef FNPDMBLKCACHEXFERCOMPLETEINT *PFNPDMBLKCACHEXFERCOMPLETEINT; + +/** + * I/O enqueue callback for drivers. + * + * @param pDrvIns The driver instance. + * @param pvUser User argument given during request initiation. + * @param rc The status code of the completed request. + */ +typedef DECLCALLBACK(int) FNPDMBLKCACHEXFERENQUEUEINT(void *pvUser, + PDMBLKCACHEXFERDIR enmXferDir, + uint64_t off, size_t cbXfer, + PCRTSGBUF pcSgBuf, PPDMBLKCACHEIOXFER hIoXfer); +/** Pointer to a FNPDMBLKCACHEXFERENQUEUEINT(). */ +typedef FNPDMBLKCACHEXFERENQUEUEINT *PFNPDMBLKCACHEXFERENQUEUEINT; + +/** + * Discard enqueue callback for VMM internal users. + * + * @param pDrvIns The driver instance. + * @param paRanges Ranges to discard. + * @param cRanges Number of range entries. + * @param hIoXfer I/O handle to return on completion. + */ +typedef DECLCALLBACK(int) FNPDMBLKCACHEXFERENQUEUEDISCARDINT(void *pvUser, + PCRTRANGE paRanges, unsigned cRanges, + PPDMBLKCACHEIOXFER hIoXfer); +/** Pointer to a FNPDMBLKCACHEXFERENQUEUEDISCARDINT(). */ +typedef FNPDMBLKCACHEXFERENQUEUEDISCARDINT *PFNPDMBLKCACHEXFERENQUEUEDISCARDINT; + +/** + * Completion callback for USB. + * + * @param pDrvIns The driver instance. + * @param pvUser User argument given during request initiation. + * @param rc The status code of the completed request. + */ +typedef DECLCALLBACK(void) FNPDMBLKCACHEXFERCOMPLETEUSB(PPDMUSBINS pUsbIns, void *pvUser, int rc); +/** Pointer to a FNPDMBLKCACHEXFERCOMPLETEUSB(). */ +typedef FNPDMBLKCACHEXFERCOMPLETEUSB *PFNPDMBLKCACHEXFERCOMPLETEUSB; + +/** + * I/O enqueue callback for drivers. + * + * @param pDrvIns The driver instance. + * @param pvUser User argument given during request initiation. + * @param rc The status code of the completed request. + */ +typedef DECLCALLBACK(int) FNPDMBLKCACHEXFERENQUEUEUSB(PPDMUSBINS pUsbIns, + PDMBLKCACHEXFERDIR enmXferDir, + uint64_t off, size_t cbXfer, + PCRTSGBUF pcSgBuf, PPDMBLKCACHEIOXFER hIoXfer); +/** Pointer to a FNPDMBLKCACHEXFERENQUEUEUSB(). */ +typedef FNPDMBLKCACHEXFERENQUEUEUSB *PFNPDMBLKCACHEXFERENQUEUEUSB; + +/** + * Discard enqueue callback for USB devices. + * + * @param pUsbIns The USB device instance. + * @param paRanges Ranges to discard. + * @param cRanges Number of range entries. + * @param hIoXfer I/O handle to return on completion. + */ +typedef DECLCALLBACK(int) FNPDMBLKCACHEXFERENQUEUEDISCARDUSB(PPDMUSBINS pUsbIns, + PCRTRANGE paRanges, unsigned cRanges, + PPDMBLKCACHEIOXFER hIoXfer); +/** Pointer to a FNPDMBLKCACHEXFERENQUEUEDISCARDUSB(). */ +typedef FNPDMBLKCACHEXFERENQUEUEDISCARDUSB *PFNPDMBLKCACHEXFERENQUEUEDISCARDUSB; + +/** + * Create a block cache user for a driver instance. + * + * @returns VBox status code. + * @param pVM Pointer to the shared VM structure. + * @param pDrvIns The driver instance. + * @param ppBlkCache Where to store the handle to the block cache. + * @param pfnXferComplete The I/O transfer complete callback. + * @param pfnXferEnqueue The I/O request enqueue callback. + * @param pfnXferEnqueueDiscard The discard request enqueue callback. + * @param pcszId Unique ID used to identify the user. + */ +VMMR3DECL(int) PDMR3BlkCacheRetainDriver(PVM pVM, PPDMDRVINS pDrvIns, PPPDMBLKCACHE ppBlkCache, + PFNPDMBLKCACHEXFERCOMPLETEDRV pfnXferComplete, + PFNPDMBLKCACHEXFERENQUEUEDRV pfnXferEnqueue, + PFNPDMBLKCACHEXFERENQUEUEDISCARDDRV pfnXferEnqueueDiscard, + const char *pcszId); + +/** + * Create a block cache user for a device instance. + * + * @returns VBox status code. + * @param pVM Pointer to the shared VM structure. + * @param pDevIns The device instance. + * @param ppBlkCache Where to store the handle to the block cache. + * @param pfnXferComplete The I/O transfer complete callback. + * @param pfnXferEnqueue The I/O request enqueue callback. + * @param pfnXferEnqueueDiscard The discard request enqueue callback. + * @param pcszId Unique ID used to identify the user. + */ +VMMR3DECL(int) PDMR3BlkCacheRetainDevice(PVM pVM, PPDMDEVINS pDevIns, PPPDMBLKCACHE ppBlkCache, + PFNPDMBLKCACHEXFERCOMPLETEDEV pfnXferComplete, + PFNPDMBLKCACHEXFERENQUEUEDEV pfnXferEnqueue, + PFNPDMBLKCACHEXFERENQUEUEDISCARDDEV pfnXferEnqueueDiscard, + const char *pcszId); + +/** + * Create a block cache user for a USB instance. + * + * @returns VBox status code. + * @param pVM Pointer to the shared VM structure. + * @param pUsbIns The USB device instance. + * @param ppBlkCache Where to store the handle to the block cache. + * @param pfnXferComplete The I/O transfer complete callback. + * @param pfnXferEnqueue The I/O request enqueue callback. + * @param pfnXferEnqueueDiscard The discard request enqueue callback. + * @param pcszId Unique ID used to identify the user. + */ +VMMR3DECL(int) PDMR3BlkCacheRetainUsb(PVM pVM, PPDMUSBINS pUsbIns, PPPDMBLKCACHE ppBlkCache, + PFNPDMBLKCACHEXFERCOMPLETEUSB pfnXferComplete, + PFNPDMBLKCACHEXFERENQUEUEUSB pfnXferEnqueue, + PFNPDMBLKCACHEXFERENQUEUEDISCARDUSB pfnXferEnqueueDiscard, + const char *pcszId); + +/** + * Create a block cache user for internal use by VMM. + * + * @returns VBox status code. + * @param pVM Pointer to the shared VM structure. + * @param pvUser Opaque user data. + * @param ppBlkCache Where to store the handle to the block cache. + * @param pfnXferComplete The I/O transfer complete callback. + * @param pfnXferEnqueue The I/O request enqueue callback. + * @param pfnXferEnqueueDiscard The discard request enqueue callback. + * @param pcszId Unique ID used to identify the user. + */ +VMMR3DECL(int) PDMR3BlkCacheRetainInt(PVM pVM, void *pvUser, PPPDMBLKCACHE ppBlkCache, + PFNPDMBLKCACHEXFERCOMPLETEINT pfnXferComplete, + PFNPDMBLKCACHEXFERENQUEUEINT pfnXferEnqueue, + PFNPDMBLKCACHEXFERENQUEUEDISCARDINT pfnXferEnqueueDiscard, + const char *pcszId); + +/** + * Releases a block cache handle. + * + * @returns nothing. + * @param pBlkCache Block cache handle. + */ +VMMR3DECL(void) PDMR3BlkCacheRelease(PPDMBLKCACHE pBlkCache); + +/** + * Releases all block cache handles for a device instance. + * + * @returns nothing. + * @param pVM Pointer to the shared VM structure. + * @param pDevIns The device instance. + */ +VMMR3DECL(void) PDMR3BlkCacheReleaseDevice(PVM pVM, PPDMDEVINS pDevIns); + +/** + * Releases all block cache handles for a driver instance. + * + * @returns nothing. + * @param pVM Pointer to the shared VM structure. + * @param pDrvIns The driver instance. + */ +VMMR3DECL(void) PDMR3BlkCacheReleaseDriver(PVM pVM, PPDMDRVINS pDrvIns); + +/** + * Releases all block cache handles for a USB device instance. + * + * @returns nothing. + * @param pVM Pointer to the shared VM structure. + * @param pUsbIns The USB device instance. + */ +VMMR3DECL(void) PDMR3BlkCacheReleaseUsb(PVM pVM, PPDMUSBINS pUsbIns); + +/** + * Creates a read task on the given endpoint. + * + * @returns VBox status code. + * @param pEndpoint The file endpoint to read from. + * @param off Where to start reading from. + * @param paSegments Scatter gather list to store the data in. + * @param cSegments Number of segments in the list. + * @param cbRead The overall number of bytes to read. + * @param pvUser Opaque user data returned in the completion callback + * upon completion of the read. + */ +VMMR3DECL(int) PDMR3BlkCacheRead(PPDMBLKCACHE pBlkCache, uint64_t off, + PCRTSGBUF pcSgBuf, size_t cbRead, void *pvUser); + +/** + * Creates a write task on the given endpoint. + * + * @returns VBox status code. + * @param pEndpoint The file endpoint to write to. + * @param off Where to start writing at. + * @param paSegments Scatter gather list of the data to write. + * @param cSegments Number of segments in the list. + * @param cbWrite The overall number of bytes to write. + * @param pvUser Opaque user data returned in the completion callback + * upon completion of the task. + */ +VMMR3DECL(int) PDMR3BlkCacheWrite(PPDMBLKCACHE pBlkCache, uint64_t off, + PCRTSGBUF pcSgBuf, size_t cbWrite, void *pvUser); + +/** + * Creates a flush task on the given endpoint. + * + * @returns VBox status code. + * @param pEndpoint The file endpoint to flush. + * @param pvUser Opaque user data returned in the completion callback + * upon completion of the task. + */ +VMMR3DECL(int) PDMR3BlkCacheFlush(PPDMBLKCACHE pBlkCache, void *pvUser); + +/** + * Discards the given ranges from the cache. + * + * @returns VBox status code. + * @param pEndpoint The file endpoint to flush. + * @param paRanges Array of ranges to discard. + * @param cRanges Number of ranges in the array. + * @param pvUser Opaque user data returned in the completion callback + * upon completion of the task. + */ +VMMR3DECL(int) PDMR3BlkCacheDiscard(PPDMBLKCACHE pBlkCache, PCRTRANGE paRanges, unsigned cRanges, void *pvUser); + +/** + * Notify the cache of a complete I/O transfer. + * + * @returns nothing. + * @param pBlkCache The cache instance. + * @param hIoXfer The I/O transfer handle which completed. + * @param rcIoXfer The status code of the completed request. + */ +VMMR3DECL(void) PDMR3BlkCacheIoXferComplete(PPDMBLKCACHE pBlkCache, PPDMBLKCACHEIOXFER hIoXfer, int rcIoXfer); + +/** + * Suspends the block cache. The cache waits until all I/O transfers completed + * and stops to enqueue new requests after the call returned but will not accept + * reads, write or flushes either. + * + * @returns VBox status code. + * @param pBlkCache The cache instance. + */ +VMMR3DECL(int) PDMR3BlkCacheSuspend(PPDMBLKCACHE pBlkCache); + +/** + * Resumes operation of the block cache. + * + * @returns VBox status code. + * @param pBlkCache The cache instance. + */ +VMMR3DECL(int) PDMR3BlkCacheResume(PPDMBLKCACHE pBlkCache); + +/** + * Clears the block cache and removes all entries. The cache waits until all + * I/O transfers completed. + * + * @returns VBox status code. + * @param pBlkCache The cache instance. + */ +VMMR3DECL(int) PDMR3BlkCacheClear(PPDMBLKCACHE pBlkCache); + +/** @} */ + +RT_C_DECLS_END + +#endif + diff --git a/include/VBox/vmm/pdmcardreaderinfs.h b/include/VBox/vmm/pdmcardreaderinfs.h new file mode 100644 index 00000000..e1ad5a2d --- /dev/null +++ b/include/VBox/vmm/pdmcardreaderinfs.h @@ -0,0 +1,116 @@ +/* $Id: pdmcardreaderinfs.h $ */ + +/** @file + * cardreaderinfs - interface between Usb Card Reader device and its driver. + */ + +/* + * Copyright (C) 2011-2012 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_pdmcardreaderinfs_h +# define ___VBox_vmm_pdmcardreaderinfs_h + +#include <VBox/types.h> + +#define PDMICARDREADERDOWN_IID "78d65378-889c-4418-8bc2-7a89a5af2817" + +typedef struct PDMICARDREADER_IO_REQUEST +{ + uint32_t u32Protocol; /* Protocol identifier */ + uint32_t cbPciLength; /* Protocol Control Information Length */ + /* 'cbPciLength - 8' bytes of control info may follow. */ +} PDMICARDREADER_IO_REQUEST; + +typedef struct PDMICARDREADER_READERSTATE +{ + char *pszReaderName; + uint32_t u32CurrentState; /* Current state of reader at time of call. */ + uint32_t u32EventState; /* State of reader after state change */ + uint32_t cbAtr; /* Number of bytes in the returned ATR. */ + uint8_t au8Atr[36]; /* Atr of inserted card, (extra alignment bytes) */ +} PDMICARDREADER_READERSTATE; + + +typedef struct PDMICARDREADERDOWN PDMICARDREADERDOWN; +typedef PDMICARDREADERDOWN *PPDMICARDREADERDOWN; +struct PDMICARDREADERDOWN +{ + DECLR3CALLBACKMEMBER(int, pfnCardReaderDownEstablishContext,(PPDMICARDREADERDOWN pInterface)); + DECLR3CALLBACKMEMBER(int, pfnCardReaderDownConnect,(PPDMICARDREADERDOWN pInterface, void *pvUser, const char *pszCardReaderName, + uint32_t u32ShareMode, uint32_t u32PreferredProtocols)); + DECLR3CALLBACKMEMBER(int, pfnCardReaderDownDisconnect,(PPDMICARDREADERDOWN pInterface, void *pvUser, + uint32_t u32Disposition)); + DECLR3CALLBACKMEMBER(int, pfnCardReaderDownStatus,(PPDMICARDREADERDOWN pInterface, void *pvUser, + uint32_t cchReaderName, uint32_t cbAtrLen)); + DECLR3CALLBACKMEMBER(int, pfnCardReaderDownReleaseContext,(PPDMICARDREADERDOWN pInterface, void *pvUser)); + DECLR3CALLBACKMEMBER(int, pfnCardReaderDownGetStatusChange,(PPDMICARDREADERDOWN pInterface, void *pvUser, + uint32_t u32Timeout, PDMICARDREADER_READERSTATE *paReaderStats, uint32_t cReaderStats)); + DECLR3CALLBACKMEMBER(int, pfnCardReaderDownBeginTransaction,(PPDMICARDREADERDOWN pInterface, void *pvUser)); + DECLR3CALLBACKMEMBER(int, pfnCardReaderDownEndTransaction,(PPDMICARDREADERDOWN pInterface, void *pvUser, + uint32_t u32Disposition)); + DECLR3CALLBACKMEMBER(int, pfnCardReaderDownTransmit,(PPDMICARDREADERDOWN pInterface, void *pvUser, + const PDMICARDREADER_IO_REQUEST *pioSendRequest, + const uint8_t *pu8SendBuffer, uint32_t cbSendBuffer, uint32_t cbRecvBuffer)); + /** + * Up level provides pvInBuffer of cbInBuffer bytes to call SCardControl, also it specify bytes it expects to receive + * @note: device/driver implementation should copy buffers before execution in async mode, and both layers shouldn't + * expect permanent storage for the buffer. + */ + DECLR3CALLBACKMEMBER(int, pfnCardReaderDownControl,(PPDMICARDREADERDOWN pInterface, void *pvUser, + uint32_t u32ControlCode, const void *pvInBuffer, uint32_t cbInBuffer, uint32_t cbOutBuffer)); + /** + * This function ask driver to provide attribute (dwAttribId) and provide limit (cbAttrib) of buffer size for attribute value, + * Callback UpGetAttrib returns buffer containing the value and altered size of the buffer. + */ + DECLR3CALLBACKMEMBER(int, pfnCardReaderDownGetAttr,(PPDMICARDREADERDOWN pInterface, void *pvUser, + uint32_t u32AttribId, uint32_t cbAttrib)); + DECLR3CALLBACKMEMBER(int, pfnCardReaderDownSetAttr,(PPDMICARDREADERDOWN pInterface, void *pvUser, + uint32_t u32AttribId, const void *pvAttrib, uint32_t cbAttrib)); +}; + +#define PDMICARDREADERUP_IID "c0d7498e-0635-48ca-aab1-b11b6a55cf7d" +typedef struct PDMICARDREADERUP PDMICARDREADERUP; +typedef PDMICARDREADERUP *PPDMICARDREADERUP; +struct PDMICARDREADERUP +{ + DECLR3CALLBACKMEMBER(int, pfnCardReaderUpEstablishContext,(PPDMICARDREADERUP pInterface, int32_t lSCardRc)); + DECLR3CALLBACKMEMBER(int, pfnCardReaderUpStatus,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc, + char *pszReaderName, uint32_t cchReaderName, uint32_t u32CardState, + uint32_t u32Protocol, uint8_t *pu8Atr, uint32_t cbAtr)); + DECLR3CALLBACKMEMBER(int, pfnCardReaderUpConnect,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc, + uint32_t u32ActiveProtocol)); + DECLR3CALLBACKMEMBER(int, pfnCardReaderUpDisconnect,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc)); + DECLR3CALLBACKMEMBER(int, pfnCardReaderUpSetStatusChange,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc, + PDMICARDREADER_READERSTATE *paReaderStats, uint32_t cReaderStats)); + DECLR3CALLBACKMEMBER(int, pfnCardReaderUpBeginTransaction,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc)); + DECLR3CALLBACKMEMBER(int, pfnCardReaderUpEndTransaction,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc)); + /* Note: pioRecvPci stack variable */ + DECLR3CALLBACKMEMBER(int, pfnCardReaderUpTransmit,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc, + const PDMICARDREADER_IO_REQUEST *pioRecvPci, uint8_t *pu8RecvBuffer, uint32_t cbRecvBuffer)); + DECLR3CALLBACKMEMBER(int, pfnCardReaderUpControl,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc, + uint32_t u32ControlCode, void *pvOutBuffer, uint32_t cbOutBuffer)); + DECLR3CALLBACKMEMBER(int, pfnCardReaderUpGetAttrib,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc, + uint32_t u32AttribId, void *pvAttrib, uint32_t cbAttrib)); + DECLR3CALLBACKMEMBER(int, pfnCardReaderUpSetAttrib,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc, + uint32_t u32AttribId)); +}; + +#endif diff --git a/include/VBox/vmm/pdmcommon.h b/include/VBox/vmm/pdmcommon.h new file mode 100644 index 00000000..c4e1be26 --- /dev/null +++ b/include/VBox/vmm/pdmcommon.h @@ -0,0 +1,164 @@ +/** @file + * PDM - Pluggable Device Manager, Common Definitions & Types. + */ + +/* + * Copyright (C) 2006-2010 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_pdmcommon_h +#define ___VBox_vmm_pdmcommon_h + +#include <VBox/types.h> + + +/** @defgroup grp_pdm_common Common Definitions & Types + * @ingroup grp_pdm + * + * Not all the types here are "common", they are here to work around header + * ordering issues. + * + * @{ + */ + +/** Makes a PDM structure version out of an unique magic value and major & + * minor version numbers. + * + * @returns 32-bit structure version number. + * + * @param uMagic 16-bit magic value. This must be unique. + * @param uMajor 12-bit major version number. Structures with different + * major numbers are not compatible. + * @param uMinor 4-bit minor version number. When only the minor version + * differs, the structures will be 100% backwards + * compatible. + */ +#define PDM_VERSION_MAKE(uMagic, uMajor, uMinor) \ + ( ((uint32_t)(uMagic) << 16) | ((uint32_t)((uMajor) & 0xff) << 4) | ((uint32_t)((uMinor) & 0xf) << 0) ) + +/** Checks if @a uVerMagic1 is compatible with @a uVerMagic2. + * + * @returns true / false. + * @param uVerMagic1 Typically the runtime version of the struct. This must + * have the same magic and major version as @a uVerMagic2 + * and the minor version must be greater or equal to that + * of @a uVerMagic2. + * @param uVerMagic2 Typically the version the code was compiled against. + * + * @remarks The parameters will be referenced more than once. + */ +#define PDM_VERSION_ARE_COMPATIBLE(uVerMagic1, uVerMagic2) \ + ( (uVerMagic1) == (uVerMagic2) \ + || ( (uVerMagic1) >= (uVerMagic2) \ + && ((uVerMagic1) & UINT32_C(0xfffffff0)) == ((uVerMagic2) & UINT32_C(0xfffffff0)) ) \ + ) + + +/** PDM Attach/Detach Callback Flags. + * Used by PDMDeviceAttach, PDMDeviceDetach, PDMDriverAttach, PDMDriverDetach, + * FNPDMDEVATTACH, FNPDMDEVDETACH, FNPDMDRVATTACH, FNPDMDRVDETACH and + * FNPDMDRVCONSTRUCT. + @{ */ +/** The attach/detach command is not a hotplug event. */ +#define PDM_TACH_FLAGS_NOT_HOT_PLUG RT_BIT_32(0) +/** Indicates that no attach or detach callbacks should be made. + * This is mostly for internal use. */ +#define PDM_TACH_FLAGS_NO_CALLBACKS RT_BIT_32(1) +/* @} */ + + +/** + * Is asynchronous handling of suspend or power off notification completed? + * + * This is called to check whether the USB device has quiesced. Don't deadlock. + * Avoid blocking. Do NOT wait for anything. + * + * @returns true if done, false if more work to be done. + * + * @param pUsbIns The USB device instance. + * + * @thread EMT(0) + */ +typedef DECLCALLBACK(bool) FNPDMUSBASYNCNOTIFY(PPDMUSBINS pUsbIns); +/** Pointer to a FNPDMUSBASYNCNOTIFY. */ +typedef FNPDMUSBASYNCNOTIFY *PFNPDMUSBASYNCNOTIFY; + +/** + * Is asynchronous handling of suspend or power off notification completed? + * + * This is called to check whether the device has quiesced. Don't deadlock. + * Avoid blocking. Do NOT wait for anything. + * + * @returns true if done, false if more work to be done. + * + * @param pDevIns The device instance. + * + * @thread EMT(0) + */ +typedef DECLCALLBACK(bool) FNPDMDEVASYNCNOTIFY(PPDMDEVINS pDevIns); +/** Pointer to a FNPDMDEVASYNCNOTIFY. */ +typedef FNPDMDEVASYNCNOTIFY *PFNPDMDEVASYNCNOTIFY; + +/** + * Is asynchronous handling of suspend or power off notification completed? + * + * This is called to check whether the driver has quiesced. Don't deadlock. + * Avoid blocking. Do NOT wait for anything. + * + * @returns true if done, false if more work to be done. + * + * @param pDrvIns The driver instance. + * + * @thread EMT(0) + */ +typedef DECLCALLBACK(bool) FNPDMDRVASYNCNOTIFY(PPDMDRVINS pDrvIns); +/** Pointer to a FNPDMDRVASYNCNOTIFY. */ +typedef FNPDMDRVASYNCNOTIFY *PFNPDMDRVASYNCNOTIFY; + + +/** + * The ring-0 driver request handler. + * + * @returns VBox status code. PDMDevHlpCallR0 will return this. + * @param pDevIns The device instance (the ring-0 mapping). + * @param uOperation The operation. + * @param u64Arg Optional integer argument for the operation. + */ +typedef DECLCALLBACK(int) FNPDMDEVREQHANDLERR0(PPDMDEVINS pDevIns, uint32_t uOperation, uint64_t u64Arg); +/** Ring-0 pointer to a FNPDMDEVREQHANDLERR0. */ +typedef R0PTRTYPE(FNPDMDEVREQHANDLERR0 *) PFNPDMDEVREQHANDLERR0; + +/** + * The ring-0 driver request handler. + * + * @returns VBox status code. PDMDrvHlpCallR0 will return this. + * @param pDrvIns The driver instance (the ring-0 mapping). + * @param uOperation The operation. + * @param u64Arg Optional integer argument for the operation. + */ +typedef DECLCALLBACK(int) FNPDMDRVREQHANDLERR0(PPDMDRVINS pDrvIns, uint32_t uOperation, uint64_t u64Arg); +/** Ring-0 pointer to a FNPDMDRVREQHANDLERR0. */ +typedef R0PTRTYPE(FNPDMDRVREQHANDLERR0 *) PFNPDMDRVREQHANDLERR0; + + +/** @} */ + +#endif + diff --git a/include/VBox/vmm/pdmcritsect.h b/include/VBox/vmm/pdmcritsect.h new file mode 100644 index 00000000..02d7924d --- /dev/null +++ b/include/VBox/vmm/pdmcritsect.h @@ -0,0 +1,95 @@ +/** @file + * PDM - Pluggable Device Manager, Critical Sections. + */ + +/* + * Copyright (C) 2006-2010 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_pdmcritsect_h +#define ___VBox_vmm_pdmcritsect_h + +#include <VBox/types.h> +#include <iprt/critsect.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_critsect The PDM Critical Section API + * @ingroup grp_pdm + * @{ + */ + +/** + * A PDM critical section. + * Initialize using PDMDRVHLP::pfnCritSectInit(). + */ +typedef union PDMCRITSECT +{ + /** Padding. */ + uint8_t padding[HC_ARCH_BITS == 32 ? 0x80 : 0xc0]; +#ifdef PDMCRITSECTINT_DECLARED + /** The internal structure (not normally visible). */ + struct PDMCRITSECTINT s; +#endif +} PDMCRITSECT; + +VMMR3DECL(int) PDMR3CritSectInit(PVM pVM, PPDMCRITSECT pCritSect, RT_SRC_POS_DECL, const char *pszNameFmt, ...); +VMMDECL(int) PDMCritSectEnter(PPDMCRITSECT pCritSect, int rcBusy); +VMMDECL(int) PDMCritSectEnterDebug(PPDMCRITSECT pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL); +VMMDECL(int) PDMCritSectTryEnter(PPDMCRITSECT pCritSect); +VMMDECL(int) PDMCritSectTryEnterDebug(PPDMCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL); +VMMR3DECL(int) PDMR3CritSectEnterEx(PPDMCRITSECT pCritSect, bool fCallRing3); +VMMDECL(int) PDMCritSectLeave(PPDMCRITSECT pCritSect); +VMMDECL(bool) PDMCritSectIsOwner(PCPDMCRITSECT pCritSect); +VMMDECL(bool) PDMCritSectIsOwnerEx(PCPDMCRITSECT pCritSect, PVMCPU pVCpu); +VMMDECL(bool) PDMCritSectIsInitialized(PCPDMCRITSECT pCritSect); +VMMDECL(bool) PDMCritSectHasWaiters(PCPDMCRITSECT pCritSect); +VMMDECL(uint32_t) PDMCritSectGetRecursion(PCPDMCRITSECT pCritSect); +VMMR3DECL(bool) PDMR3CritSectYield(PPDMCRITSECT pCritSect); +VMMR3DECL(const char *) PDMR3CritSectName(PCPDMCRITSECT pCritSect); +VMMR3DECL(int) PDMR3CritSectScheduleExitEvent(PPDMCRITSECT pCritSect, RTSEMEVENT EventToSignal); +VMMR3DECL(int) PDMR3CritSectDelete(PPDMCRITSECT pCritSect); +VMMDECL(int) PDMR3CritSectTerm(PVM pVM); +VMMDECL(void) PDMCritSectFF(PVMCPU pVCpu); +VMMR3DECL(uint32_t) PDMR3CritSectCountOwned(PVM pVM, char *pszNames, size_t cbNames); +VMMR3DECL(void) PDMR3CritSectLeaveAll(PVM pVM); + +VMMR3DECL(PPDMCRITSECT) PDMR3CritSectGetNop(PVM pVM); +VMMR3DECL(R0PTRTYPE(PPDMCRITSECT)) PDMR3CritSectGetNopR0(PVM pVM); +VMMR3DECL(RCPTRTYPE(PPDMCRITSECT)) PDMR3CritSectGetNopRC(PVM pVM); + +/* Strict build: Remap the two enter calls to the debug versions. */ +#ifdef VBOX_STRICT +# ifdef ___iprt_asm_h +# define PDMCritSectEnter(pCritSect, rcBusy) PDMCritSectEnterDebug((pCritSect), (rcBusy), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define PDMCritSectTryEnter(pCritSect) PDMCritSectTryEnterDebug((pCritSect), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# else +# define PDMCritSectEnter(pCritSect, rcBusy) PDMCritSectEnterDebug((pCritSect), (rcBusy), 0, RT_SRC_POS) +# define PDMCritSectTryEnter(pCritSect) PDMCritSectTryEnterDebug((pCritSect), 0, RT_SRC_POS) +# endif +#endif + +/** @} */ + +RT_C_DECLS_END + +#endif + diff --git a/include/VBox/vmm/pdmdev.h b/include/VBox/vmm/pdmdev.h new file mode 100644 index 00000000..892ed590 --- /dev/null +++ b/include/VBox/vmm/pdmdev.h @@ -0,0 +1,5173 @@ +/** @file + * PDM - Pluggable Device Manager, Devices. + */ + +/* + * Copyright (C) 2006-2011 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_pdmdev_h +#define ___VBox_vmm_pdmdev_h + +#include <VBox/vmm/pdmqueue.h> +#include <VBox/vmm/pdmcritsect.h> +#include <VBox/vmm/pdmthread.h> +#include <VBox/vmm/pdmifs.h> +#include <VBox/vmm/pdmins.h> +#include <VBox/vmm/pdmcommon.h> +#include <VBox/vmm/iom.h> +#include <VBox/vmm/tm.h> +#include <VBox/vmm/ssm.h> +#include <VBox/vmm/cfgm.h> +#include <VBox/vmm/dbgf.h> +#include <VBox/err.h> +#include <VBox/pci.h> +#include <iprt/stdarg.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_device The PDM Devices API + * @ingroup grp_pdm + * @{ + */ + +/** + * Construct a device instance for a VM. + * + * @returns VBox status. + * @param pDevIns The device instance data. If the registration structure + * is needed, it can be accessed thru pDevIns->pReg. + * @param iInstance Instance number. Use this to figure out which registers + * and such to use. The instance number is also found in + * pDevIns->iInstance, but since it's likely to be + * frequently used PDM passes it as parameter. + * @param pCfg Configuration node handle for the driver. This is + * expected to be in high demand in the constructor and is + * therefore passed as an argument. When using it at other + * times, it can be found in pDrvIns->pCfg. + */ +typedef DECLCALLBACK(int) FNPDMDEVCONSTRUCT(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg); +/** Pointer to a FNPDMDEVCONSTRUCT() function. */ +typedef FNPDMDEVCONSTRUCT *PFNPDMDEVCONSTRUCT; + +/** + * Destruct a device instance. + * + * Most VM resources are freed by the VM. This callback is provided so that any non-VM + * resources can be freed correctly. + * + * @returns VBox status. + * @param pDevIns The device instance data. + * + * @remarks The device critical section is not entered. The routine may delete + * the critical section, so the caller cannot exit it. + */ +typedef DECLCALLBACK(int) FNPDMDEVDESTRUCT(PPDMDEVINS pDevIns); +/** Pointer to a FNPDMDEVDESTRUCT() function. */ +typedef FNPDMDEVDESTRUCT *PFNPDMDEVDESTRUCT; + +/** + * Device relocation callback. + * + * This is called when the instance data has been relocated in raw-mode context + * (RC). It is also called when the RC hypervisor selects changes. The device + * must fixup all necessary pointers and re-query all interfaces to other RC + * devices and drivers. + * + * Before the RC code is executed the first time, this function will be called + * with a 0 delta so RC pointer calculations can be one in one place. + * + * @param pDevIns Pointer to the device instance. + * @param offDelta The relocation delta relative to the old location. + * + * @remarks A relocation CANNOT fail. + * + * @remarks The device critical section is not entered. The relocations should + * not normally require any locking. + */ +typedef DECLCALLBACK(void) FNPDMDEVRELOCATE(PPDMDEVINS pDevIns, RTGCINTPTR offDelta); +/** Pointer to a FNPDMDEVRELOCATE() function. */ +typedef FNPDMDEVRELOCATE *PFNPDMDEVRELOCATE; + +/** + * Device I/O Control interface. + * + * This is used by external components, such as the COM interface, to + * communicate with devices using a class wide interface or a device + * specific interface. + * + * @returns VBox status code. + * @param pDevIns Pointer to the device instance. + * @param uFunction Function to perform. + * @param pvIn Pointer to input data. + * @param cbIn Size of input data. + * @param pvOut Pointer to output data. + * @param cbOut Size of output data. + * @param pcbOut Where to store the actual size of the output data. + * + * @remarks Not used. + */ +typedef DECLCALLBACK(int) FNPDMDEVIOCTL(PPDMDEVINS pDevIns, uint32_t uFunction, + void *pvIn, uint32_t cbIn, + void *pvOut, uint32_t cbOut, PRTUINT pcbOut); +/** Pointer to a FNPDMDEVIOCTL() function. */ +typedef FNPDMDEVIOCTL *PFNPDMDEVIOCTL; + +/** + * Power On notification. + * + * @returns VBox status. + * @param pDevIns The device instance data. + * + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACK(void) FNPDMDEVPOWERON(PPDMDEVINS pDevIns); +/** Pointer to a FNPDMDEVPOWERON() function. */ +typedef FNPDMDEVPOWERON *PFNPDMDEVPOWERON; + +/** + * Reset notification. + * + * @returns VBox status. + * @param pDevIns The device instance data. + * + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACK(void) FNPDMDEVRESET(PPDMDEVINS pDevIns); +/** Pointer to a FNPDMDEVRESET() function. */ +typedef FNPDMDEVRESET *PFNPDMDEVRESET; + +/** + * Suspend notification. + * + * @returns VBox status. + * @param pDevIns The device instance data. + * @thread EMT(0) + * + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACK(void) FNPDMDEVSUSPEND(PPDMDEVINS pDevIns); +/** Pointer to a FNPDMDEVSUSPEND() function. */ +typedef FNPDMDEVSUSPEND *PFNPDMDEVSUSPEND; + +/** + * Resume notification. + * + * @returns VBox status. + * @param pDevIns The device instance data. + * + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACK(void) FNPDMDEVRESUME(PPDMDEVINS pDevIns); +/** Pointer to a FNPDMDEVRESUME() function. */ +typedef FNPDMDEVRESUME *PFNPDMDEVRESUME; + +/** + * Power Off notification. + * + * This is only called when the VMR3PowerOff call is made on a running VM. This + * means that there is no notification if the VM was suspended before being + * powered of. There will also be no callback when hot plugging devices. + * + * @param pDevIns The device instance data. + * @thread EMT(0) + * + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACK(void) FNPDMDEVPOWEROFF(PPDMDEVINS pDevIns); +/** Pointer to a FNPDMDEVPOWEROFF() function. */ +typedef FNPDMDEVPOWEROFF *PFNPDMDEVPOWEROFF; + +/** + * Attach command. + * + * This is called to let the device attach to a driver for a specified LUN + * at runtime. This is not called during VM construction, the device + * constructor have to attach to all the available drivers. + * + * This is like plugging in the keyboard or mouse after turning on the PC. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param iLUN The logical unit which is being detached. + * @param fFlags Flags, combination of the PDM_TACH_FLAGS_* \#defines. + * + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACK(int) FNPDMDEVATTACH(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags); +/** Pointer to a FNPDMDEVATTACH() function. */ +typedef FNPDMDEVATTACH *PFNPDMDEVATTACH; + +/** + * Detach notification. + * + * This is called when a driver is detaching itself from a LUN of the device. + * The device should adjust it's state to reflect this. + * + * This is like unplugging the network cable to use it for the laptop or + * something while the PC is still running. + * + * @param pDevIns The device instance. + * @param iLUN The logical unit which is being detached. + * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines. + * + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACK(void) FNPDMDEVDETACH(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags); +/** Pointer to a FNPDMDEVDETACH() function. */ +typedef FNPDMDEVDETACH *PFNPDMDEVDETACH; + +/** + * Query the base interface of a logical unit. + * + * @returns VBOX status code. + * @param pDevIns The device instance. + * @param iLUN The logicial unit to query. + * @param ppBase Where to store the pointer to the base interface of the LUN. + * + * @remarks The device critical section is not entered. + */ +typedef DECLCALLBACK(int) FNPDMDEVQUERYINTERFACE(PPDMDEVINS pDevIns, unsigned iLUN, PPDMIBASE *ppBase); +/** Pointer to a FNPDMDEVQUERYINTERFACE() function. */ +typedef FNPDMDEVQUERYINTERFACE *PFNPDMDEVQUERYINTERFACE; + +/** + * Init complete notification. + * This can be done to do communication with other devices and other + * initialization which requires everything to be in place. + * + * @returns VBOX status code. + * @param pDevIns The device instance. + * + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACK(int) FNPDMDEVINITCOMPLETE(PPDMDEVINS pDevIns); +/** Pointer to a FNPDMDEVINITCOMPLETE() function. */ +typedef FNPDMDEVINITCOMPLETE *PFNPDMDEVINITCOMPLETE; + + + +/** + * PDM Device Registration Structure. + * + * This structure is used when registering a device from VBoxInitDevices() in HC + * Ring-3. PDM will continue use till the VM is terminated. + */ +typedef struct PDMDEVREG +{ + /** Structure version. PDM_DEVREG_VERSION defines the current version. */ + uint32_t u32Version; + /** Device name. */ + char szName[32]; + /** Name of the raw-mode context module (no path). + * Only evalutated if PDM_DEVREG_FLAGS_RC is set. */ + char szRCMod[32]; + /** Name of the ring-0 module (no path). + * Only evalutated if PDM_DEVREG_FLAGS_R0 is set. */ + char szR0Mod[32]; + /** The description of the device. The UTF-8 string pointed to shall, like this structure, + * remain unchanged from registration till VM destruction. */ + const char *pszDescription; + + /** Flags, combination of the PDM_DEVREG_FLAGS_* \#defines. */ + uint32_t fFlags; + /** Device class(es), combination of the PDM_DEVREG_CLASS_* \#defines. */ + uint32_t fClass; + /** Maximum number of instances (per VM). */ + uint32_t cMaxInstances; + /** Size of the instance data. */ + uint32_t cbInstance; + + /** Construct instance - required. */ + PFNPDMDEVCONSTRUCT pfnConstruct; + /** Destruct instance - optional. + * Critical section NOT entered (will be destroyed). */ + PFNPDMDEVDESTRUCT pfnDestruct; + /** Relocation command - optional. + * Critical section NOT entered. */ + PFNPDMDEVRELOCATE pfnRelocate; + /** I/O Control interface - optional. + * Not used. */ + PFNPDMDEVIOCTL pfnIOCtl; + /** Power on notification - optional. + * Critical section is entered. */ + PFNPDMDEVPOWERON pfnPowerOn; + /** Reset notification - optional. + * Critical section is entered. */ + PFNPDMDEVRESET pfnReset; + /** Suspend notification - optional. + * Critical section is entered. */ + PFNPDMDEVSUSPEND pfnSuspend; + /** Resume notification - optional. + * Critical section is entered. */ + PFNPDMDEVRESUME pfnResume; + /** Attach command - optional. + * Critical section is entered. */ + PFNPDMDEVATTACH pfnAttach; + /** Detach notification - optional. + * Critical section is entered. */ + PFNPDMDEVDETACH pfnDetach; + /** Query a LUN base interface - optional. + * Critical section is NOT entered. */ + PFNPDMDEVQUERYINTERFACE pfnQueryInterface; + /** Init complete notification - optional. + * Critical section is entered. */ + PFNPDMDEVINITCOMPLETE pfnInitComplete; + /** Power off notification - optional. + * Critical section is entered. */ + PFNPDMDEVPOWEROFF pfnPowerOff; + /** @todo */ + PFNRT pfnSoftReset; + /** Initialization safty marker. */ + uint32_t u32VersionEnd; +} PDMDEVREG; +/** Pointer to a PDM Device Structure. */ +typedef PDMDEVREG *PPDMDEVREG; +/** Const pointer to a PDM Device Structure. */ +typedef PDMDEVREG const *PCPDMDEVREG; + +/** Current DEVREG version number. */ +#define PDM_DEVREG_VERSION PDM_VERSION_MAKE(0xffff, 1, 0) + +/** PDM Device Flags. + * @{ */ +/** This flag is used to indicate that the device has a RC component. */ +#define PDM_DEVREG_FLAGS_RC 0x00000001 +/** This flag is used to indicate that the device has a R0 component. */ +#define PDM_DEVREG_FLAGS_R0 0x00000002 + +/** @def PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT + * The bit count for the current host. */ +#if HC_ARCH_BITS == 32 +# define PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT 0x00000010 +#elif HC_ARCH_BITS == 64 +# define PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT 0x00000020 +#else +# error Unsupported HC_ARCH_BITS value. +#endif +/** The host bit count mask. */ +#define PDM_DEVREG_FLAGS_HOST_BITS_MASK 0x00000030 + +/** The device support only 32-bit guests. */ +#define PDM_DEVREG_FLAGS_GUEST_BITS_32 0x00000100 +/** The device support only 64-bit guests. */ +#define PDM_DEVREG_FLAGS_GUEST_BITS_64 0x00000200 +/** The device support both 32-bit & 64-bit guests. */ +#define PDM_DEVREG_FLAGS_GUEST_BITS_32_64 0x00000300 +/** @def PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT + * The guest bit count for the current compilation. */ +#if GC_ARCH_BITS == 32 +# define PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT PDM_DEVREG_FLAGS_GUEST_BITS_32 +#elif GC_ARCH_BITS == 64 +# define PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT PDM_DEVREG_FLAGS_GUEST_BITS_32_64 +#else +# error Unsupported GC_ARCH_BITS value. +#endif +/** The guest bit count mask. */ +#define PDM_DEVREG_FLAGS_GUEST_BITS_MASK 0x00000300 + +/** A convenience. */ +#define PDM_DEVREG_FLAGS_DEFAULT_BITS (PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT | PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT) + +/** Indicates that the devices support PAE36 on a 32-bit guest. */ +#define PDM_DEVREG_FLAGS_PAE36 0x00001000 + +/** Indicates that the device needs to be notified before the drivers when suspending. */ +#define PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION 0x00002000 + +/** Indicates that the device needs to be notified before the drivers when powering off. */ +#define PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION 0x00004000 + +/** Indicates that the device needs to be notified before the drivers when resetting. */ +#define PDM_DEVREG_FLAGS_FIRST_RESET_NOTIFICATION 0x00008000 +/** @} */ + + +/** PDM Device Classes. + * The order is important, lower bit earlier instantiation. + * @{ */ +/** Architecture device. */ +#define PDM_DEVREG_CLASS_ARCH RT_BIT(0) +/** Architecture BIOS device. */ +#define PDM_DEVREG_CLASS_ARCH_BIOS RT_BIT(1) +/** PCI bus brigde. */ +#define PDM_DEVREG_CLASS_BUS_PCI RT_BIT(2) +/** ISA bus brigde. */ +#define PDM_DEVREG_CLASS_BUS_ISA RT_BIT(3) +/** Input device (mouse, keyboard, joystick, HID, ...). */ +#define PDM_DEVREG_CLASS_INPUT RT_BIT(4) +/** Interrupt controller (PIC). */ +#define PDM_DEVREG_CLASS_PIC RT_BIT(5) +/** Interval controoler (PIT). */ +#define PDM_DEVREG_CLASS_PIT RT_BIT(6) +/** RTC/CMOS. */ +#define PDM_DEVREG_CLASS_RTC RT_BIT(7) +/** DMA controller. */ +#define PDM_DEVREG_CLASS_DMA RT_BIT(8) +/** VMM Device. */ +#define PDM_DEVREG_CLASS_VMM_DEV RT_BIT(9) +/** Graphics device, like VGA. */ +#define PDM_DEVREG_CLASS_GRAPHICS RT_BIT(10) +/** Storage controller device. */ +#define PDM_DEVREG_CLASS_STORAGE RT_BIT(11) +/** Network interface controller. */ +#define PDM_DEVREG_CLASS_NETWORK RT_BIT(12) +/** Audio. */ +#define PDM_DEVREG_CLASS_AUDIO RT_BIT(13) +/** USB HIC. */ +#define PDM_DEVREG_CLASS_BUS_USB RT_BIT(14) +/** ACPI. */ +#define PDM_DEVREG_CLASS_ACPI RT_BIT(15) +/** Serial controller device. */ +#define PDM_DEVREG_CLASS_SERIAL RT_BIT(16) +/** Parallel controller device */ +#define PDM_DEVREG_CLASS_PARALLEL RT_BIT(17) +/** Host PCI pass-through device */ +#define PDM_DEVREG_CLASS_HOST_DEV RT_BIT(18) +/** Misc devices (always last). */ +#define PDM_DEVREG_CLASS_MISC RT_BIT(31) +/** @} */ + + +/** @name IRQ Level for use with the *SetIrq APIs. + * @{ + */ +/** Assert the IRQ (can assume value 1). */ +#define PDM_IRQ_LEVEL_HIGH RT_BIT(0) +/** Deassert the IRQ (can assume value 0). */ +#define PDM_IRQ_LEVEL_LOW 0 +/** flip-flop - deassert and then assert the IRQ again immediately. */ +#define PDM_IRQ_LEVEL_FLIP_FLOP (RT_BIT(1) | PDM_IRQ_LEVEL_HIGH) +/** @} */ + +/** + * Registration record for MSI. + */ +typedef struct PDMMSIREG +{ + /** Number of MSI interrupt vectors, 0 if MSI not supported */ + uint16_t cMsiVectors; + /** Offset of MSI capability */ + uint8_t iMsiCapOffset; + /** Offset of next capability to MSI */ + uint8_t iMsiNextOffset; + /** If we support 64-bit MSI addressing */ + bool fMsi64bit; + + /** Number of MSI-X interrupt vectors, 0 if MSI-X not supported */ + uint16_t cMsixVectors; + /** Offset of MSI-X capability */ + uint8_t iMsixCapOffset; + /** Offset of next capability to MSI-X */ + uint8_t iMsixNextOffset; + /** Value of PCI BAR (base addresss register) assigned by device for MSI-X page access */ + uint8_t iMsixBar; +} PDMMSIREG; +typedef PDMMSIREG *PPDMMSIREG; + +/** + * PCI Bus registration structure. + * All the callbacks, except the PCIBIOS hack, are working on PCI devices. + */ +typedef struct PDMPCIBUSREG +{ + /** Structure version number. PDM_PCIBUSREG_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Registers the device with the default PCI bus. + * + * @returns VBox status code. + * @param pDevIns Device instance of the PCI Bus. + * @param pPciDev The PCI device structure. + * Any PCI enabled device must keep this in it's instance data! + * Fill in the PCI data config before registration, please. + * @param pszName Pointer to device name (permanent, readonly). For debugging, not unique. + * @param iDev The device number ((dev << 3) | function) the device should have on the bus. + * If negative, the pci bus device will assign one. + */ + DECLR3CALLBACKMEMBER(int, pfnRegisterR3,(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, const char *pszName, int iDev)); + + /** + * Initialize MSI support in a PCI device. + * + * @returns VBox status code. + * @param pDevIns Device instance of the PCI Bus. + * @param pPciDev The PCI device structure. + * @param pMsiReg MSI registration structure + */ + DECLR3CALLBACKMEMBER(int, pfnRegisterMsiR3,(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, PPDMMSIREG pMsiReg)); + + /** + * Registers a I/O region (memory mapped or I/O ports) for a PCI device. + * + * @returns VBox status code. + * @param pDevIns Device instance of the PCI Bus. + * @param pPciDev The PCI device structure. + * @param iRegion The region number. + * @param cbRegion Size of the region. + * @param iType PCI_ADDRESS_SPACE_MEM, PCI_ADDRESS_SPACE_IO or PCI_ADDRESS_SPACE_MEM_PREFETCH. + * @param pfnCallback Callback for doing the mapping. + */ + DECLR3CALLBACKMEMBER(int, pfnIORegionRegisterR3,(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iRegion, uint32_t cbRegion, PCIADDRESSSPACE enmType, PFNPCIIOREGIONMAP pfnCallback)); + + /** + * Register PCI configuration space read/write callbacks. + * + * @param pDevIns Device instance of the PCI Bus. + * @param pPciDev The PCI device structure. + * @param pfnRead Pointer to the user defined PCI config read function. + * @param ppfnReadOld Pointer to function pointer which will receive the old (default) + * PCI config read function. This way, user can decide when (and if) + * to call default PCI config read function. Can be NULL. + * @param pfnWrite Pointer to the user defined PCI config write function. + * @param pfnWriteOld Pointer to function pointer which will receive the old (default) + * PCI config write function. This way, user can decide when (and if) + * to call default PCI config write function. Can be NULL. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(void, pfnSetConfigCallbacksR3,(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, PFNPCICONFIGREAD pfnRead, PPFNPCICONFIGREAD ppfnReadOld, + PFNPCICONFIGWRITE pfnWrite, PPFNPCICONFIGWRITE ppfnWriteOld)); + + /** + * Set the IRQ for a PCI device. + * + * @param pDevIns Device instance of the PCI Bus. + * @param pPciDev The PCI device structure. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @param uTagSrc The IRQ tag and source (for tracing). + */ + DECLR3CALLBACKMEMBER(void, pfnSetIrqR3,(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iIrq, int iLevel, uint32_t uTagSrc)); + + /** + * Saves a state of the PCI device. + * + * @returns VBox status code. + * @param pDevIns Device instance of the PCI Bus. + * @param pPciDev Pointer to PCI device. + * @param pSSMHandle The handle to save the state to. + */ + DECLR3CALLBACKMEMBER(int, pfnSaveExecR3,(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, PSSMHANDLE pSSMHandle)); + + /** + * Loads a saved PCI device state. + * + * @returns VBox status code. + * @param pDevIns Device instance of the PCI Bus. + * @param pPciDev Pointer to PCI device. + * @param pSSMHandle The handle to the saved state. + */ + DECLR3CALLBACKMEMBER(int, pfnLoadExecR3,(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, PSSMHANDLE pSSMHandle)); + + /** + * Called to perform the job of the bios. + * This is only called for the first PCI Bus - it is expected to + * service all the PCI buses. + * + * @returns VBox status. + * @param pDevIns Device instance of the first bus. + */ + DECLR3CALLBACKMEMBER(int, pfnFakePCIBIOSR3,(PPDMDEVINS pDevIns)); + + /** The name of the SetIrq RC entry point. */ + const char *pszSetIrqRC; + + /** The name of the SetIrq R0 entry point. */ + const char *pszSetIrqR0; + +} PDMPCIBUSREG; +/** Pointer to a PCI bus registration structure. */ +typedef PDMPCIBUSREG *PPDMPCIBUSREG; + +/** Current PDMPCIBUSREG version number. */ +#define PDM_PCIBUSREG_VERSION PDM_VERSION_MAKE(0xfffe, 3, 0) + +/** + * PCI Bus RC helpers. + */ +typedef struct PDMPCIHLPRC +{ + /** Structure version. PDM_PCIHLPRC_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Set an ISA IRQ. + * + * @param pDevIns PCI device instance. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @param uTagSrc The IRQ tag and source (for tracing). + * @thread EMT only. + */ + DECLRCCALLBACKMEMBER(void, pfnIsaSetIrq,(PPDMDEVINS pDevIns, int iIrq, int iLevel, uint32_t uTagSrc)); + + /** + * Set an I/O-APIC IRQ. + * + * @param pDevIns PCI device instance. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @param uTagSrc The IRQ tag and source (for tracing). + * @thread EMT only. + */ + DECLRCCALLBACKMEMBER(void, pfnIoApicSetIrq,(PPDMDEVINS pDevIns, int iIrq, int iLevel, uint32_t uTagSrc)); + + /** + * Send an MSI. + * + * @param pDevIns PCI device instance. + * @param GCPhys Physical address MSI request was written. + * @param uValue Value written. + * @param uTagSrc The IRQ tag and source (for tracing). + * @thread EMT only. + */ + DECLRCCALLBACKMEMBER(void, pfnIoApicSendMsi,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, uint32_t uValue, uint32_t uTagSrc)); + + + /** + * Acquires the PDM lock. + * + * @returns VINF_SUCCESS on success. + * @returns rc if we failed to acquire the lock. + * @param pDevIns The PCI device instance. + * @param rc What to return if we fail to acquire the lock. + */ + DECLRCCALLBACKMEMBER(int, pfnLock,(PPDMDEVINS pDevIns, int rc)); + + /** + * Releases the PDM lock. + * + * @param pDevIns The PCI device instance. + */ + DECLRCCALLBACKMEMBER(void, pfnUnlock,(PPDMDEVINS pDevIns)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMPCIHLPRC; +/** Pointer to PCI helpers. */ +typedef RCPTRTYPE(PDMPCIHLPRC *) PPDMPCIHLPRC; +/** Pointer to const PCI helpers. */ +typedef RCPTRTYPE(const PDMPCIHLPRC *) PCPDMPCIHLPRC; + +/** Current PDMPCIHLPRC version number. */ +#define PDM_PCIHLPRC_VERSION PDM_VERSION_MAKE(0xfffd, 3, 0) + + +/** + * PCI Bus R0 helpers. + */ +typedef struct PDMPCIHLPR0 +{ + /** Structure version. PDM_PCIHLPR0_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Set an ISA IRQ. + * + * @param pDevIns PCI device instance. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @param uTagSrc The IRQ tag and source (for tracing). + * @thread EMT only. + */ + DECLR0CALLBACKMEMBER(void, pfnIsaSetIrq,(PPDMDEVINS pDevIns, int iIrq, int iLevel, uint32_t uTagSrc)); + + /** + * Set an I/O-APIC IRQ. + * + * @param pDevIns PCI device instance. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @param uTagSrc The IRQ tag and source (for tracing). + * @thread EMT only. + */ + DECLR0CALLBACKMEMBER(void, pfnIoApicSetIrq,(PPDMDEVINS pDevIns, int iIrq, int iLevel, uint32_t uTagSrc)); + + /** + * Send an MSI. + * + * @param pDevIns PCI device instance. + * @param GCPhys Physical address MSI request was written. + * @param uValue Value written. + * @param uTagSrc The IRQ tag and source (for tracing). + * @thread EMT only. + */ + DECLR0CALLBACKMEMBER(void, pfnIoApicSendMsi,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, uint32_t uValue, uint32_t uTagSrc)); + + + /** + * Acquires the PDM lock. + * + * @returns VINF_SUCCESS on success. + * @returns rc if we failed to acquire the lock. + * @param pDevIns The PCI device instance. + * @param rc What to return if we fail to acquire the lock. + */ + DECLR0CALLBACKMEMBER(int, pfnLock,(PPDMDEVINS pDevIns, int rc)); + + /** + * Releases the PDM lock. + * + * @param pDevIns The PCI device instance. + */ + DECLR0CALLBACKMEMBER(void, pfnUnlock,(PPDMDEVINS pDevIns)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMPCIHLPR0; +/** Pointer to PCI helpers. */ +typedef R0PTRTYPE(PDMPCIHLPR0 *) PPDMPCIHLPR0; +/** Pointer to const PCI helpers. */ +typedef R0PTRTYPE(const PDMPCIHLPR0 *) PCPDMPCIHLPR0; + +/** Current PDMPCIHLPR0 version number. */ +#define PDM_PCIHLPR0_VERSION PDM_VERSION_MAKE(0xfffc, 3, 0) + +/** + * PCI device helpers. + */ +typedef struct PDMPCIHLPR3 +{ + /** Structure version. PDM_PCIHLPR3_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Set an ISA IRQ. + * + * @param pDevIns The PCI device instance. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @param uTagSrc The IRQ tag and source (for tracing). + */ + DECLR3CALLBACKMEMBER(void, pfnIsaSetIrq,(PPDMDEVINS pDevIns, int iIrq, int iLevel, uint32_t uTagSrc)); + + /** + * Set an I/O-APIC IRQ. + * + * @param pDevIns The PCI device instance. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @param uTagSrc The IRQ tag and source (for tracing). + */ + DECLR3CALLBACKMEMBER(void, pfnIoApicSetIrq,(PPDMDEVINS pDevIns, int iIrq, int iLevel, uint32_t uTagSrc)); + + /** + * Send an MSI. + * + * @param pDevIns PCI device instance. + * @param GCPhys Physical address MSI request was written. + * @param uValue Value written. + * @param uTagSrc The IRQ tag and source (for tracing). + */ + DECLR3CALLBACKMEMBER(void, pfnIoApicSendMsi,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, uint32_t uValue, uint32_t uTagSrc)); + + /** + * Checks if the given address is an MMIO2 base address or not. + * + * @returns true/false accordingly. + * @param pDevIns The PCI device instance. + * @param pOwner The owner of the memory, optional. + * @param GCPhys The address to check. + */ + DECLR3CALLBACKMEMBER(bool, pfnIsMMIO2Base,(PPDMDEVINS pDevIns, PPDMDEVINS pOwner, RTGCPHYS GCPhys)); + + /** + * Gets the address of the RC PCI Bus helpers. + * + * This should be called at both construction and relocation time + * to obtain the correct address of the RC helpers. + * + * @returns RC pointer to the PCI Bus helpers. + * @param pDevIns Device instance of the PCI Bus. + * @thread EMT only. + */ + DECLR3CALLBACKMEMBER(PCPDMPCIHLPRC, pfnGetRCHelpers,(PPDMDEVINS pDevIns)); + + /** + * Gets the address of the R0 PCI Bus helpers. + * + * This should be called at both construction and relocation time + * to obtain the correct address of the R0 helpers. + * + * @returns R0 pointer to the PCI Bus helpers. + * @param pDevIns Device instance of the PCI Bus. + * @thread EMT only. + */ + DECLR3CALLBACKMEMBER(PCPDMPCIHLPR0, pfnGetR0Helpers,(PPDMDEVINS pDevIns)); + + /** + * Acquires the PDM lock. + * + * @returns VINF_SUCCESS on success. + * @returns Fatal error on failure. + * @param pDevIns The PCI device instance. + * @param rc Dummy for making the interface identical to the RC and R0 versions. + */ + DECLR3CALLBACKMEMBER(int, pfnLock,(PPDMDEVINS pDevIns, int rc)); + + /** + * Releases the PDM lock. + * + * @param pDevIns The PCI device instance. + */ + DECLR3CALLBACKMEMBER(void, pfnUnlock,(PPDMDEVINS pDevIns)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMPCIHLPR3; +/** Pointer to PCI helpers. */ +typedef R3PTRTYPE(PDMPCIHLPR3 *) PPDMPCIHLPR3; +/** Pointer to const PCI helpers. */ +typedef R3PTRTYPE(const PDMPCIHLPR3 *) PCPDMPCIHLPR3; + +/** Current PDMPCIHLPR3 version number. */ +#define PDM_PCIHLPR3_VERSION PDM_VERSION_MAKE(0xfffb, 3, 0) + + +/** + * Programmable Interrupt Controller registration structure. + */ +typedef struct PDMPICREG +{ + /** Structure version number. PDM_PICREG_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Set the an IRQ. + * + * @param pDevIns Device instance of the PIC. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @param uTagSrc The IRQ tag and source (for tracing). + */ + DECLR3CALLBACKMEMBER(void, pfnSetIrqR3,(PPDMDEVINS pDevIns, int iIrq, int iLevel, uint32_t uTagSrc)); + + /** + * Get a pending interrupt. + * + * @returns Pending interrupt number. + * @param pDevIns Device instance of the PIC. + * @param puTagSrc Where to return the IRQ tag and source. + */ + DECLR3CALLBACKMEMBER(int, pfnGetInterruptR3,(PPDMDEVINS pDevIns, uint32_t *puTagSrc)); + + /** The name of the RC SetIrq entry point. */ + const char *pszSetIrqRC; + /** The name of the RC GetInterrupt entry point. */ + const char *pszGetInterruptRC; + + /** The name of the R0 SetIrq entry point. */ + const char *pszSetIrqR0; + /** The name of the R0 GetInterrupt entry point. */ + const char *pszGetInterruptR0; +} PDMPICREG; +/** Pointer to a PIC registration structure. */ +typedef PDMPICREG *PPDMPICREG; + +/** Current PDMPICREG version number. */ +#define PDM_PICREG_VERSION PDM_VERSION_MAKE(0xfffa, 2, 0) + +/** + * PIC RC helpers. + */ +typedef struct PDMPICHLPRC +{ + /** Structure version. PDM_PICHLPRC_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Set the interrupt force action flag. + * + * @param pDevIns Device instance of the PIC. + */ + DECLRCCALLBACKMEMBER(void, pfnSetInterruptFF,(PPDMDEVINS pDevIns)); + + /** + * Clear the interrupt force action flag. + * + * @param pDevIns Device instance of the PIC. + */ + DECLRCCALLBACKMEMBER(void, pfnClearInterruptFF,(PPDMDEVINS pDevIns)); + + /** + * Acquires the PDM lock. + * + * @returns VINF_SUCCESS on success. + * @returns rc if we failed to acquire the lock. + * @param pDevIns The PIC device instance. + * @param rc What to return if we fail to acquire the lock. + */ + DECLRCCALLBACKMEMBER(int, pfnLock,(PPDMDEVINS pDevIns, int rc)); + + /** + * Releases the PDM lock. + * + * @param pDevIns The PIC device instance. + */ + DECLRCCALLBACKMEMBER(void, pfnUnlock,(PPDMDEVINS pDevIns)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMPICHLPRC; + +/** Pointer to PIC RC helpers. */ +typedef RCPTRTYPE(PDMPICHLPRC *) PPDMPICHLPRC; +/** Pointer to const PIC RC helpers. */ +typedef RCPTRTYPE(const PDMPICHLPRC *) PCPDMPICHLPRC; + +/** Current PDMPICHLPRC version number. */ +#define PDM_PICHLPRC_VERSION PDM_VERSION_MAKE(0xfff9, 2, 0) + + +/** + * PIC R0 helpers. + */ +typedef struct PDMPICHLPR0 +{ + /** Structure version. PDM_PICHLPR0_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Set the interrupt force action flag. + * + * @param pDevIns Device instance of the PIC. + */ + DECLR0CALLBACKMEMBER(void, pfnSetInterruptFF,(PPDMDEVINS pDevIns)); + + /** + * Clear the interrupt force action flag. + * + * @param pDevIns Device instance of the PIC. + */ + DECLR0CALLBACKMEMBER(void, pfnClearInterruptFF,(PPDMDEVINS pDevIns)); + + /** + * Acquires the PDM lock. + * + * @returns VINF_SUCCESS on success. + * @returns rc if we failed to acquire the lock. + * @param pDevIns The PIC device instance. + * @param rc What to return if we fail to acquire the lock. + */ + DECLR0CALLBACKMEMBER(int, pfnLock,(PPDMDEVINS pDevIns, int rc)); + + /** + * Releases the PDM lock. + * + * @param pDevIns The PCI device instance. + */ + DECLR0CALLBACKMEMBER(void, pfnUnlock,(PPDMDEVINS pDevIns)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMPICHLPR0; + +/** Pointer to PIC R0 helpers. */ +typedef R0PTRTYPE(PDMPICHLPR0 *) PPDMPICHLPR0; +/** Pointer to const PIC R0 helpers. */ +typedef R0PTRTYPE(const PDMPICHLPR0 *) PCPDMPICHLPR0; + +/** Current PDMPICHLPR0 version number. */ +#define PDM_PICHLPR0_VERSION PDM_VERSION_MAKE(0xfff8, 1, 0) + +/** + * PIC R3 helpers. + */ +typedef struct PDMPICHLPR3 +{ + /** Structure version. PDM_PICHLP_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Set the interrupt force action flag. + * + * @param pDevIns Device instance of the PIC. + */ + DECLR3CALLBACKMEMBER(void, pfnSetInterruptFF,(PPDMDEVINS pDevIns)); + + /** + * Clear the interrupt force action flag. + * + * @param pDevIns Device instance of the PIC. + */ + DECLR3CALLBACKMEMBER(void, pfnClearInterruptFF,(PPDMDEVINS pDevIns)); + + /** + * Acquires the PDM lock. + * + * @returns VINF_SUCCESS on success. + * @returns Fatal error on failure. + * @param pDevIns The PIC device instance. + * @param rc Dummy for making the interface identical to the RC and R0 versions. + */ + DECLR3CALLBACKMEMBER(int, pfnLock,(PPDMDEVINS pDevIns, int rc)); + + /** + * Releases the PDM lock. + * + * @param pDevIns The PIC device instance. + */ + DECLR3CALLBACKMEMBER(void, pfnUnlock,(PPDMDEVINS pDevIns)); + + /** + * Gets the address of the RC PIC helpers. + * + * This should be called at both construction and relocation time + * to obtain the correct address of the RC helpers. + * + * @returns RC pointer to the PIC helpers. + * @param pDevIns Device instance of the PIC. + */ + DECLR3CALLBACKMEMBER(PCPDMPICHLPRC, pfnGetRCHelpers,(PPDMDEVINS pDevIns)); + + /** + * Gets the address of the R0 PIC helpers. + * + * This should be called at both construction and relocation time + * to obtain the correct address of the R0 helpers. + * + * @returns R0 pointer to the PIC helpers. + * @param pDevIns Device instance of the PIC. + */ + DECLR3CALLBACKMEMBER(PCPDMPICHLPR0, pfnGetR0Helpers,(PPDMDEVINS pDevIns)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMPICHLPR3; + +/** Pointer to PIC R3 helpers. */ +typedef R3PTRTYPE(PDMPICHLPR3 *) PPDMPICHLPR3; +/** Pointer to const PIC R3 helpers. */ +typedef R3PTRTYPE(const PDMPICHLPR3 *) PCPDMPICHLPR3; + +/** Current PDMPICHLPR3 version number. */ +#define PDM_PICHLPR3_VERSION PDM_VERSION_MAKE(0xfff7, 1, 0) + + + +/** + * Advanced Programmable Interrupt Controller registration structure. + */ +typedef struct PDMAPICREG +{ + /** Structure version number. PDM_APICREG_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Get a pending interrupt. + * + * @returns Pending interrupt number. + * @param pDevIns Device instance of the APIC. + * @param puTagSrc Where to return the tag source. + */ + DECLR3CALLBACKMEMBER(int, pfnGetInterruptR3,(PPDMDEVINS pDevIns, uint32_t *puTagSrc)); + + /** + * Check if the APIC has a pending interrupt/if a TPR change would active one + * + * @returns Pending interrupt yes/no + * @param pDevIns Device instance of the APIC. + */ + DECLR3CALLBACKMEMBER(bool, pfnHasPendingIrqR3,(PPDMDEVINS pDevIns)); + + /** + * Set the APIC base. + * + * @param pDevIns Device instance of the APIC. + * @param u64Base The new base. + */ + DECLR3CALLBACKMEMBER(void, pfnSetBaseR3,(PPDMDEVINS pDevIns, uint64_t u64Base)); + + /** + * Get the APIC base. + * + * @returns Current base. + * @param pDevIns Device instance of the APIC. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnGetBaseR3,(PPDMDEVINS pDevIns)); + + /** + * Set the TPR (task priority register). + * + * @param pDevIns Device instance of the APIC. + * @param idCpu VCPU id + * @param u8TPR The new TPR. + */ + DECLR3CALLBACKMEMBER(void, pfnSetTPRR3,(PPDMDEVINS pDevIns, VMCPUID idCpu, uint8_t u8TPR)); + + /** + * Get the TPR (task priority register). + * + * @returns The current TPR. + * @param pDevIns Device instance of the APIC. + * @param idCpu VCPU id + */ + DECLR3CALLBACKMEMBER(uint8_t, pfnGetTPRR3,(PPDMDEVINS pDevIns, VMCPUID idCpu)); + + /** + * Write to a MSR in APIC range. + * + * @returns VBox status code. + * @param pDevIns Device instance of the APIC. + * @param idCpu Target CPU. + * @param u32Reg The MSR begin written to. + * @param u64Value The value to write. + * + * @remarks Unlike the other callbacks, the PDM lock is not taken before + * calling this method. + */ + DECLR3CALLBACKMEMBER(int, pfnWriteMSRR3, (PPDMDEVINS pDevIns, VMCPUID idCpu, uint32_t u32Reg, uint64_t u64Value)); + + /** + * Read from a MSR in APIC range. + * + * @returns VBox status code. + * @param pDevIns Device instance of the APIC. + * @param idCpu Target CPU. + * @param u32Reg MSR to read. + * @param pu64Value Where to return the read value. + * + * @remarks Unlike the other callbacks, the PDM lock is not taken before + * calling this method. + */ + DECLR3CALLBACKMEMBER(int, pfnReadMSRR3, (PPDMDEVINS pDevIns, VMCPUID idCpu, uint32_t u32Reg, uint64_t *pu64Value)); + + /** + * Private interface between the IOAPIC and APIC. + * + * This is a low-level, APIC/IOAPIC implementation specific interface which + * is registered with PDM only because it makes life so much simpler right + * now (GC bits). This is a bad bad hack! The correct way of doing this + * would involve some way of querying GC interfaces and relocating them. + * Perhaps doing some kind of device init in GC... + * + * @returns status code. + * @param pDevIns Device instance of the APIC. + * @param u8Dest See APIC implementation. + * @param u8DestMode See APIC implementation. + * @param u8DeliveryMode See APIC implementation. + * @param iVector See APIC implementation. + * @param u8Polarity See APIC implementation. + * @param u8TriggerMode See APIC implementation. + * @param uTagSrc The IRQ tag and source (for tracing). + */ + DECLR3CALLBACKMEMBER(int, pfnBusDeliverR3,(PPDMDEVINS pDevIns, uint8_t u8Dest, uint8_t u8DestMode, uint8_t u8DeliveryMode, + uint8_t iVector, uint8_t u8Polarity, uint8_t u8TriggerMode, uint32_t uTagSrc)); + + /** + * Deliver a signal to CPU's local interrupt pins (LINT0/LINT1). + * + * Used for virtual wire mode when interrupts from the PIC are passed through + * LAPIC. + * + * @returns status code. + * @param pDevIns Device instance of the APIC. + * @param u8Pin Local pin number (0 or 1 for current CPUs). + * @param u8Level The level. + * @param uTagSrc The IRQ tag and source (for tracing). + */ + DECLR3CALLBACKMEMBER(int, pfnLocalInterruptR3,(PPDMDEVINS pDevIns, uint8_t u8Pin, uint8_t u8Level)); + + /** The name of the RC GetInterrupt entry point. */ + const char *pszGetInterruptRC; + /** The name of the RC HasPendingIrq entry point. */ + const char *pszHasPendingIrqRC; + /** The name of the RC SetBase entry point. */ + const char *pszSetBaseRC; + /** The name of the RC GetBase entry point. */ + const char *pszGetBaseRC; + /** The name of the RC SetTPR entry point. */ + const char *pszSetTPRRC; + /** The name of the RC GetTPR entry point. */ + const char *pszGetTPRRC; + /** The name of the RC WriteMSR entry point. */ + const char *pszWriteMSRRC; + /** The name of the RC ReadMSR entry point. */ + const char *pszReadMSRRC; + /** The name of the RC BusDeliver entry point. */ + const char *pszBusDeliverRC; + /** The name of the RC LocalInterrupt entry point. */ + const char *pszLocalInterruptRC; + + /** The name of the R0 GetInterrupt entry point. */ + const char *pszGetInterruptR0; + /** The name of the R0 HasPendingIrq entry point. */ + const char *pszHasPendingIrqR0; + /** The name of the R0 SetBase entry point. */ + const char *pszSetBaseR0; + /** The name of the R0 GetBase entry point. */ + const char *pszGetBaseR0; + /** The name of the R0 SetTPR entry point. */ + const char *pszSetTPRR0; + /** The name of the R0 GetTPR entry point. */ + const char *pszGetTPRR0; + /** The name of the R0 WriteMSR entry point. */ + const char *pszWriteMSRR0; + /** The name of the R0 ReadMSR entry point. */ + const char *pszReadMSRR0; + /** The name of the R0 BusDeliver entry point. */ + const char *pszBusDeliverR0; + /** The name of the R0 LocalInterrupt entry point. */ + const char *pszLocalInterruptR0; + +} PDMAPICREG; +/** Pointer to an APIC registration structure. */ +typedef PDMAPICREG *PPDMAPICREG; + +/** Current PDMAPICREG version number. */ +#define PDM_APICREG_VERSION PDM_VERSION_MAKE(0xfff6, 2, 0) + + +/** + * APIC version argument for pfnChangeFeature. + */ +typedef enum PDMAPICVERSION +{ + /** Invalid 0 entry. */ + PDMAPICVERSION_INVALID = 0, + /** No APIC. */ + PDMAPICVERSION_NONE, + /** Standard APIC (X86_CPUID_FEATURE_EDX_APIC). */ + PDMAPICVERSION_APIC, + /** Intel X2APIC (X86_CPUID_FEATURE_ECX_X2APIC). */ + PDMAPICVERSION_X2APIC, + /** The usual 32-bit paranoia. */ + PDMAPICVERSION_32BIT_HACK = 0x7fffffff +} PDMAPICVERSION; + +/** + * APIC irq argument for SetInterruptFF. + */ +typedef enum PDMAPICIRQ +{ + /** Invalid 0 entry. */ + PDMAPICIRQ_INVALID = 0, + /** Normal hardware interrupt. */ + PDMAPICIRQ_HARDWARE, + /** NMI. */ + PDMAPICIRQ_NMI, + /** SMI. */ + PDMAPICIRQ_SMI, + /** ExtINT (HW interrupt via PIC). */ + PDMAPICIRQ_EXTINT, + /** The usual 32-bit paranoia. */ + PDMAPICIRQ_32BIT_HACK = 0x7fffffff +} PDMAPICIRQ; + + +/** + * APIC RC helpers. + */ +typedef struct PDMAPICHLPRC +{ + /** Structure version. PDM_APICHLPRC_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Set the interrupt force action flag. + * + * @param pDevIns Device instance of the APIC. + * @param enmType IRQ type. + * @param idCpu Virtual CPU to set flag upon. + */ + DECLRCCALLBACKMEMBER(void, pfnSetInterruptFF,(PPDMDEVINS pDevIns, PDMAPICIRQ enmType, VMCPUID idCpu)); + + /** + * Clear the interrupt force action flag. + * + * @param pDevIns Device instance of the APIC. + * @param enmType IRQ type. + * @param idCpu Virtual CPU to clear flag upon. + */ + DECLRCCALLBACKMEMBER(void, pfnClearInterruptFF,(PPDMDEVINS pDevIns, PDMAPICIRQ enmType, VMCPUID idCpu)); + + /** + * Calculates an IRQ tag for a timer, IPI or similar event. + * + * @returns The IRQ tag. + * @param pDevIns Device instance of the APIC. + * @param u8Level PDM_IRQ_LEVEL_HIGH or PDM_IRQ_LEVEL_FLIP_FLOP. + */ + DECLRCCALLBACKMEMBER(uint32_t, pfnCalcIrqTag,(PPDMDEVINS pDevIns, uint8_t u8Level)); + + /** + * Modifies APIC-related bits in the CPUID feature mask. + * + * @param pDevIns Device instance of the APIC. + * @param enmVersion Supported APIC version. + */ + DECLRCCALLBACKMEMBER(void, pfnChangeFeature,(PPDMDEVINS pDevIns, PDMAPICVERSION enmVersion)); + + /** + * Acquires the PDM lock. + * + * @returns VINF_SUCCESS on success. + * @returns rc if we failed to acquire the lock. + * @param pDevIns The APIC device instance. + * @param rc What to return if we fail to acquire the lock. + */ + DECLRCCALLBACKMEMBER(int, pfnLock,(PPDMDEVINS pDevIns, int rc)); + + /** + * Releases the PDM lock. + * + * @param pDevIns The APIC device instance. + */ + DECLRCCALLBACKMEMBER(void, pfnUnlock,(PPDMDEVINS pDevIns)); + + /** + * Get the virtual CPU id corresponding to the current EMT. + * + * @param pDevIns The APIC device instance. + */ + DECLRCCALLBACKMEMBER(VMCPUID, pfnGetCpuId,(PPDMDEVINS pDevIns)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMAPICHLPRC; +/** Pointer to APIC GC helpers. */ +typedef RCPTRTYPE(PDMAPICHLPRC *) PPDMAPICHLPRC; +/** Pointer to const APIC helpers. */ +typedef RCPTRTYPE(const PDMAPICHLPRC *) PCPDMAPICHLPRC; + +/** Current PDMAPICHLPRC version number. */ +#define PDM_APICHLPRC_VERSION PDM_VERSION_MAKE(0xfff5, 2, 0) + + +/** + * APIC R0 helpers. + */ +typedef struct PDMAPICHLPR0 +{ + /** Structure version. PDM_APICHLPR0_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Set the interrupt force action flag. + * + * @param pDevIns Device instance of the APIC. + * @param enmType IRQ type. + * @param idCpu Virtual CPU to set flag upon. + */ + DECLR0CALLBACKMEMBER(void, pfnSetInterruptFF,(PPDMDEVINS pDevIns, PDMAPICIRQ enmType, VMCPUID idCpu)); + + /** + * Clear the interrupt force action flag. + * + * @param pDevIns Device instance of the APIC. + * @param enmType IRQ type. + * @param idCpu Virtual CPU to clear flag upon. + */ + DECLR0CALLBACKMEMBER(void, pfnClearInterruptFF,(PPDMDEVINS pDevIns, PDMAPICIRQ enmType, VMCPUID idCpu)); + + /** + * Calculates an IRQ tag for a timer, IPI or similar event. + * + * @returns The IRQ tag. + * @param pDevIns Device instance of the APIC. + * @param u8Level PDM_IRQ_LEVEL_HIGH or PDM_IRQ_LEVEL_FLIP_FLOP. + */ + DECLR0CALLBACKMEMBER(uint32_t, pfnCalcIrqTag,(PPDMDEVINS pDevIns, uint8_t u8Level)); + + /** + * Modifies APIC-related bits in the CPUID feature mask. + * + * @param pDevIns Device instance of the APIC. + * @param enmVersion Supported APIC version. + */ + DECLR0CALLBACKMEMBER(void, pfnChangeFeature,(PPDMDEVINS pDevIns, PDMAPICVERSION enmVersion)); + + /** + * Acquires the PDM lock. + * + * @returns VINF_SUCCESS on success. + * @returns rc if we failed to acquire the lock. + * @param pDevIns The APIC device instance. + * @param rc What to return if we fail to acquire the lock. + */ + DECLR0CALLBACKMEMBER(int, pfnLock,(PPDMDEVINS pDevIns, int rc)); + + /** + * Releases the PDM lock. + * + * @param pDevIns The APIC device instance. + */ + DECLR0CALLBACKMEMBER(void, pfnUnlock,(PPDMDEVINS pDevIns)); + + /** + * Get the virtual CPU id corresponding to the current EMT. + * + * @param pDevIns The APIC device instance. + */ + DECLR0CALLBACKMEMBER(VMCPUID, pfnGetCpuId,(PPDMDEVINS pDevIns)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMAPICHLPR0; +/** Pointer to APIC GC helpers. */ +typedef RCPTRTYPE(PDMAPICHLPR0 *) PPDMAPICHLPR0; +/** Pointer to const APIC helpers. */ +typedef R0PTRTYPE(const PDMAPICHLPR0 *) PCPDMAPICHLPR0; + +/** Current PDMAPICHLPR0 version number. */ +#define PDM_APICHLPR0_VERSION PDM_VERSION_MAKE(0xfff4, 2, 0) + +/** + * APIC R3 helpers. + */ +typedef struct PDMAPICHLPR3 +{ + /** Structure version. PDM_APICHLPR3_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Set the interrupt force action flag. + * + * @param pDevIns Device instance of the APIC. + * @param enmType IRQ type. + * @param idCpu Virtual CPU to set flag upon. + */ + DECLR3CALLBACKMEMBER(void, pfnSetInterruptFF,(PPDMDEVINS pDevIns, PDMAPICIRQ enmType, VMCPUID idCpu)); + + /** + * Clear the interrupt force action flag. + * + * @param pDevIns Device instance of the APIC. + * @param enmType IRQ type. + * @param idCpu Virtual CPU to clear flag upon. + */ + DECLR3CALLBACKMEMBER(void, pfnClearInterruptFF,(PPDMDEVINS pDevIns, PDMAPICIRQ enmType, VMCPUID idCpu)); + + /** + * Calculates an IRQ tag for a timer, IPI or similar event. + * + * @returns The IRQ tag. + * @param pDevIns Device instance of the APIC. + * @param u8Level PDM_IRQ_LEVEL_HIGH or PDM_IRQ_LEVEL_FLIP_FLOP. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnCalcIrqTag,(PPDMDEVINS pDevIns, uint8_t u8Level)); + + /** + * Modifies APIC-related bits in the CPUID feature mask. + * + * @param pDevIns Device instance of the APIC. + * @param enmVersion Supported APIC version. + */ + DECLR3CALLBACKMEMBER(void, pfnChangeFeature,(PPDMDEVINS pDevIns, PDMAPICVERSION enmVersion)); + + /** + * Get the virtual CPU id corresponding to the current EMT. + * + * @param pDevIns The APIC device instance. + */ + DECLR3CALLBACKMEMBER(VMCPUID, pfnGetCpuId,(PPDMDEVINS pDevIns)); + + /** + * Sends SIPI to given virtual CPU. + * + * @param pDevIns The APIC device instance. + * @param idCpu Virtual CPU to perform SIPI on + * @param iVector SIPI vector + */ + DECLR3CALLBACKMEMBER(void, pfnSendSipi,(PPDMDEVINS pDevIns, VMCPUID idCpu, uint32_t uVector)); + + /** + * Sends init IPI to given virtual CPU, should result in reset and + * halting till SIPI. + * + * @param pDevIns The APIC device instance. + * @param idCpu Virtual CPU to perform SIPI on + */ + DECLR3CALLBACKMEMBER(void, pfnSendInitIpi,(PPDMDEVINS pDevIns, VMCPUID idCpu)); + + /** + * Gets the address of the RC APIC helpers. + * + * This should be called at both construction and relocation time + * to obtain the correct address of the RC helpers. + * + * @returns GC pointer to the APIC helpers. + * @param pDevIns Device instance of the APIC. + */ + DECLR3CALLBACKMEMBER(PCPDMAPICHLPRC, pfnGetRCHelpers,(PPDMDEVINS pDevIns)); + + /** + * Gets the address of the R0 APIC helpers. + * + * This should be called at both construction and relocation time + * to obtain the correct address of the R0 helpers. + * + * @returns R0 pointer to the APIC helpers. + * @param pDevIns Device instance of the APIC. + */ + DECLR3CALLBACKMEMBER(PCPDMAPICHLPR0, pfnGetR0Helpers,(PPDMDEVINS pDevIns)); + + /** + * Get the critical section used to synchronize the PICs, PCI and stuff. + * + * @returns Ring-3 pointer to the critical section. + * @param pDevIns The APIC device instance. + */ + DECLR3CALLBACKMEMBER(R3PTRTYPE(PPDMCRITSECT), pfnGetR3CritSect,(PPDMDEVINS pDevIns)); + + /** + * Get the critical section used to synchronize the PICs, PCI and stuff. + * + * @returns Raw-mode context pointer to the critical section. + * @param pDevIns The APIC device instance. + */ + DECLR3CALLBACKMEMBER(RCPTRTYPE(PPDMCRITSECT), pfnGetRCCritSect,(PPDMDEVINS pDevIns)); + + /** + * Get the critical section used to synchronize the PICs, PCI and stuff. + * + * @returns Ring-0 pointer to the critical section. + * @param pDevIns The APIC device instance. + */ + DECLR3CALLBACKMEMBER(R0PTRTYPE(PPDMCRITSECT), pfnGetR0CritSect,(PPDMDEVINS pDevIns)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMAPICHLPR3; +/** Pointer to APIC helpers. */ +typedef R3PTRTYPE(PDMAPICHLPR3 *) PPDMAPICHLPR3; +/** Pointer to const APIC helpers. */ +typedef R3PTRTYPE(const PDMAPICHLPR3 *) PCPDMAPICHLPR3; + +/** Current PDMAPICHLP version number. */ +#define PDM_APICHLPR3_VERSION PDM_VERSION_MAKE(0xfff3, 2, 0) + + +/** + * I/O APIC registration structure. + */ +typedef struct PDMIOAPICREG +{ + /** Struct version+magic number (PDM_IOAPICREG_VERSION). */ + uint32_t u32Version; + + /** + * Set the an IRQ. + * + * @param pDevIns Device instance of the I/O APIC. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @param uTagSrc The IRQ tag and source (for tracing). + */ + DECLR3CALLBACKMEMBER(void, pfnSetIrqR3,(PPDMDEVINS pDevIns, int iIrq, int iLevel, uint32_t uTagSrc)); + + /** The name of the RC SetIrq entry point. */ + const char *pszSetIrqRC; + + /** The name of the R0 SetIrq entry point. */ + const char *pszSetIrqR0; + + /** + * Send a MSI. + * + * @param pDevIns Device instance of the I/O APIC. + * @param GCPhys Request address. + * @param uValue Request value. + * @param uTagSrc The IRQ tag and source (for tracing). + */ + DECLR3CALLBACKMEMBER(void, pfnSendMsiR3,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, uint32_t uValue, uint32_t uTagSrc)); + + /** The name of the RC SendMsi entry point. */ + const char *pszSendMsiRC; + + /** The name of the R0 SendMsi entry point. */ + const char *pszSendMsiR0; +} PDMIOAPICREG; +/** Pointer to an APIC registration structure. */ +typedef PDMIOAPICREG *PPDMIOAPICREG; + +/** Current PDMAPICREG version number. */ +#define PDM_IOAPICREG_VERSION PDM_VERSION_MAKE(0xfff2, 3, 0) + + +/** + * IOAPIC RC helpers. + */ +typedef struct PDMIOAPICHLPRC +{ + /** Structure version. PDM_IOAPICHLPRC_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Private interface between the IOAPIC and APIC. + * + * See comments about this hack on PDMAPICREG::pfnBusDeliverR3. + * + * @returns status code. + * @param pDevIns Device instance of the IOAPIC. + * @param u8Dest See APIC implementation. + * @param u8DestMode See APIC implementation. + * @param u8DeliveryMode See APIC implementation. + * @param iVector See APIC implementation. + * @param u8Polarity See APIC implementation. + * @param u8TriggerMode See APIC implementation. + * @param uTagSrc The IRQ tag and source (for tracing). + */ + DECLRCCALLBACKMEMBER(int, pfnApicBusDeliver,(PPDMDEVINS pDevIns, uint8_t u8Dest, uint8_t u8DestMode, uint8_t u8DeliveryMode, + uint8_t iVector, uint8_t u8Polarity, uint8_t u8TriggerMode, uint32_t uTagSrc)); + + /** + * Acquires the PDM lock. + * + * @returns VINF_SUCCESS on success. + * @returns rc if we failed to acquire the lock. + * @param pDevIns The IOAPIC device instance. + * @param rc What to return if we fail to acquire the lock. + */ + DECLRCCALLBACKMEMBER(int, pfnLock,(PPDMDEVINS pDevIns, int rc)); + + /** + * Releases the PDM lock. + * + * @param pDevIns The IOAPIC device instance. + */ + DECLRCCALLBACKMEMBER(void, pfnUnlock,(PPDMDEVINS pDevIns)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMIOAPICHLPRC; +/** Pointer to IOAPIC RC helpers. */ +typedef RCPTRTYPE(PDMIOAPICHLPRC *) PPDMIOAPICHLPRC; +/** Pointer to const IOAPIC helpers. */ +typedef RCPTRTYPE(const PDMIOAPICHLPRC *) PCPDMIOAPICHLPRC; + +/** Current PDMIOAPICHLPRC version number. */ +#define PDM_IOAPICHLPRC_VERSION PDM_VERSION_MAKE(0xfff1, 2, 0) + + +/** + * IOAPIC R0 helpers. + */ +typedef struct PDMIOAPICHLPR0 +{ + /** Structure version. PDM_IOAPICHLPR0_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Private interface between the IOAPIC and APIC. + * + * See comments about this hack on PDMAPICREG::pfnBusDeliverR3. + * + * @returns status code. + * @param pDevIns Device instance of the IOAPIC. + * @param u8Dest See APIC implementation. + * @param u8DestMode See APIC implementation. + * @param u8DeliveryMode See APIC implementation. + * @param iVector See APIC implementation. + * @param u8Polarity See APIC implementation. + * @param u8TriggerMode See APIC implementation. + * @param uTagSrc The IRQ tag and source (for tracing). + */ + DECLR0CALLBACKMEMBER(int, pfnApicBusDeliver,(PPDMDEVINS pDevIns, uint8_t u8Dest, uint8_t u8DestMode, uint8_t u8DeliveryMode, + uint8_t iVector, uint8_t u8Polarity, uint8_t u8TriggerMode, uint32_t uTagSrc)); + + /** + * Acquires the PDM lock. + * + * @returns VINF_SUCCESS on success. + * @returns rc if we failed to acquire the lock. + * @param pDevIns The IOAPIC device instance. + * @param rc What to return if we fail to acquire the lock. + */ + DECLR0CALLBACKMEMBER(int, pfnLock,(PPDMDEVINS pDevIns, int rc)); + + /** + * Releases the PDM lock. + * + * @param pDevIns The IOAPIC device instance. + */ + DECLR0CALLBACKMEMBER(void, pfnUnlock,(PPDMDEVINS pDevIns)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMIOAPICHLPR0; +/** Pointer to IOAPIC R0 helpers. */ +typedef R0PTRTYPE(PDMIOAPICHLPR0 *) PPDMIOAPICHLPR0; +/** Pointer to const IOAPIC helpers. */ +typedef R0PTRTYPE(const PDMIOAPICHLPR0 *) PCPDMIOAPICHLPR0; + +/** Current PDMIOAPICHLPR0 version number. */ +#define PDM_IOAPICHLPR0_VERSION PDM_VERSION_MAKE(0xfff0, 2, 0) + +/** + * IOAPIC R3 helpers. + */ +typedef struct PDMIOAPICHLPR3 +{ + /** Structure version. PDM_IOAPICHLPR3_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Private interface between the IOAPIC and APIC. + * + * See comments about this hack on PDMAPICREG::pfnBusDeliverR3. + * + * @returns status code + * @param pDevIns Device instance of the IOAPIC. + * @param u8Dest See APIC implementation. + * @param u8DestMode See APIC implementation. + * @param u8DeliveryMode See APIC implementation. + * @param iVector See APIC implementation. + * @param u8Polarity See APIC implementation. + * @param u8TriggerMode See APIC implementation. + * @param uTagSrc The IRQ tag and source (for tracing). + */ + DECLR3CALLBACKMEMBER(int, pfnApicBusDeliver,(PPDMDEVINS pDevIns, uint8_t u8Dest, uint8_t u8DestMode, uint8_t u8DeliveryMode, + uint8_t iVector, uint8_t u8Polarity, uint8_t u8TriggerMode, uint32_t uTagSrc)); + + /** + * Acquires the PDM lock. + * + * @returns VINF_SUCCESS on success. + * @returns Fatal error on failure. + * @param pDevIns The IOAPIC device instance. + * @param rc Dummy for making the interface identical to the GC and R0 versions. + */ + DECLR3CALLBACKMEMBER(int, pfnLock,(PPDMDEVINS pDevIns, int rc)); + + /** + * Releases the PDM lock. + * + * @param pDevIns The IOAPIC device instance. + */ + DECLR3CALLBACKMEMBER(void, pfnUnlock,(PPDMDEVINS pDevIns)); + + /** + * Gets the address of the RC IOAPIC helpers. + * + * This should be called at both construction and relocation time + * to obtain the correct address of the RC helpers. + * + * @returns RC pointer to the IOAPIC helpers. + * @param pDevIns Device instance of the IOAPIC. + */ + DECLR3CALLBACKMEMBER(PCPDMIOAPICHLPRC, pfnGetRCHelpers,(PPDMDEVINS pDevIns)); + + /** + * Gets the address of the R0 IOAPIC helpers. + * + * This should be called at both construction and relocation time + * to obtain the correct address of the R0 helpers. + * + * @returns R0 pointer to the IOAPIC helpers. + * @param pDevIns Device instance of the IOAPIC. + */ + DECLR3CALLBACKMEMBER(PCPDMIOAPICHLPR0, pfnGetR0Helpers,(PPDMDEVINS pDevIns)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMIOAPICHLPR3; +/** Pointer to IOAPIC R3 helpers. */ +typedef R3PTRTYPE(PDMIOAPICHLPR3 *) PPDMIOAPICHLPR3; +/** Pointer to const IOAPIC helpers. */ +typedef R3PTRTYPE(const PDMIOAPICHLPR3 *) PCPDMIOAPICHLPR3; + +/** Current PDMIOAPICHLPR3 version number. */ +#define PDM_IOAPICHLPR3_VERSION PDM_VERSION_MAKE(0xffef, 2, 0) + + +/** + * HPET registration structure. + */ +typedef struct PDMHPETREG +{ + /** Struct version+magic number (PDM_HPETREG_VERSION). */ + uint32_t u32Version; + +} PDMHPETREG; +/** Pointer to an HPET registration structure. */ +typedef PDMHPETREG *PPDMHPETREG; + +/** Current PDMHPETREG version number. */ +#define PDM_HPETREG_VERSION PDM_VERSION_MAKE(0xffe2, 1, 0) + +/** + * HPET RC helpers. + * + * @remarks Keep this around in case HPET will need PDM interaction in again RC + * at some later point. + */ +typedef struct PDMHPETHLPRC +{ + /** Structure version. PDM_HPETHLPRC_VERSION defines the current version. */ + uint32_t u32Version; + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMHPETHLPRC; + +/** Pointer to HPET RC helpers. */ +typedef RCPTRTYPE(PDMHPETHLPRC *) PPDMHPETHLPRC; +/** Pointer to const HPET RC helpers. */ +typedef RCPTRTYPE(const PDMHPETHLPRC *) PCPDMHPETHLPRC; + +/** Current PDMHPETHLPRC version number. */ +#define PDM_HPETHLPRC_VERSION PDM_VERSION_MAKE(0xffee, 2, 0) + + +/** + * HPET R0 helpers. + * + * @remarks Keep this around in case HPET will need PDM interaction in again R0 + * at some later point. + */ +typedef struct PDMHPETHLPR0 +{ + /** Structure version. PDM_HPETHLPR0_VERSION defines the current version. */ + uint32_t u32Version; + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMHPETHLPR0; + +/** Pointer to HPET R0 helpers. */ +typedef R0PTRTYPE(PDMHPETHLPR0 *) PPDMHPETHLPR0; +/** Pointer to const HPET R0 helpers. */ +typedef R0PTRTYPE(const PDMHPETHLPR0 *) PCPDMHPETHLPR0; + +/** Current PDMHPETHLPR0 version number. */ +#define PDM_HPETHLPR0_VERSION PDM_VERSION_MAKE(0xffed, 2, 0) + +/** + * HPET R3 helpers. + */ +typedef struct PDMHPETHLPR3 +{ + /** Structure version. PDM_HPETHLP_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Gets the address of the RC HPET helpers. + * + * This should be called at both construction and relocation time + * to obtain the correct address of the RC helpers. + * + * @returns RC pointer to the HPET helpers. + * @param pDevIns Device instance of the HPET. + */ + DECLR3CALLBACKMEMBER(PCPDMHPETHLPRC, pfnGetRCHelpers,(PPDMDEVINS pDevIns)); + + /** + * Gets the address of the R0 HPET helpers. + * + * This should be called at both construction and relocation time + * to obtain the correct address of the R0 helpers. + * + * @returns R0 pointer to the HPET helpers. + * @param pDevIns Device instance of the HPET. + */ + DECLR3CALLBACKMEMBER(PCPDMHPETHLPR0, pfnGetR0Helpers,(PPDMDEVINS pDevIns)); + + /** + * Set legacy mode on PIT and RTC. + * + * @returns VINF_SUCCESS on success. + * @returns rc if we failed to set legacy mode. + * @param pDevIns Device instance of the HPET. + * @param fActivated Whether legacy mode is activated or deactivated. + */ + DECLR3CALLBACKMEMBER(int, pfnSetLegacyMode,(PPDMDEVINS pDevIns, bool fActivated)); + + + /** + * Set IRQ, bypassing ISA bus override rules. + * + * @returns VINF_SUCCESS on success. + * @returns rc if we failed to set legacy mode. + * @param pDevIns Device instance of the HPET. + * @param fActivate Activate or deactivate legacy mode. + */ + DECLR3CALLBACKMEMBER(int, pfnSetIrq,(PPDMDEVINS pDevIns, int iIrq, int iLevel)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMHPETHLPR3; + +/** Pointer to HPET R3 helpers. */ +typedef R3PTRTYPE(PDMHPETHLPR3 *) PPDMHPETHLPR3; +/** Pointer to const HPET R3 helpers. */ +typedef R3PTRTYPE(const PDMHPETHLPR3 *) PCPDMHPETHLPR3; + +/** Current PDMHPETHLPR3 version number. */ +#define PDM_HPETHLPR3_VERSION PDM_VERSION_MAKE(0xffec, 2, 0) + + +/** + * Raw PCI device registration structure. + */ +typedef struct PDMPCIRAWREG +{ + /** Struct version+magic number (PDM_PCIRAWREG_VERSION). */ + uint32_t u32Version; + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMPCIRAWREG; +/** Pointer to a raw PCI registration structure. */ +typedef PDMPCIRAWREG *PPDMPCIRAWREG; + +/** Current PDMPCIRAWREG version number. */ +#define PDM_PCIRAWREG_VERSION PDM_VERSION_MAKE(0xffe1, 1, 0) + +/** + * Raw PCI device raw-mode context helpers. + */ +typedef struct PDMPCIRAWHLPRC +{ + /** Structure version and magic number (PDM_PCIRAWHLPRC_VERSION). */ + uint32_t u32Version; + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMPCIRAWHLPRC; +/** Pointer to a raw PCI deviec raw-mode context helper structure. */ +typedef RCPTRTYPE(PDMPCIRAWHLPRC *) PPDMPCIRAWHLPRC; +/** Pointer to a const raw PCI deviec raw-mode context helper structure. */ +typedef RCPTRTYPE(const PDMPCIRAWHLPRC *) PCPDMPCIRAWHLPRC; + +/** Current PDMPCIRAWHLPRC version number. */ +#define PDM_PCIRAWHLPRC_VERSION PDM_VERSION_MAKE(0xffe0, 1, 0) + +/** + * Raw PCI device ring-0 context helpers. + */ +typedef struct PDMPCIRAWHLPR0 +{ + /** Structure version and magic number (PDM_PCIRAWHLPR0_VERSION). */ + uint32_t u32Version; + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMPCIRAWHLPR0; +/** Pointer to a raw PCI deviec ring-0 context helper structure. */ +typedef R0PTRTYPE(PDMPCIRAWHLPR0 *) PPDMPCIRAWHLPR0; +/** Pointer to a const raw PCI deviec ring-0 context helper structure. */ +typedef R0PTRTYPE(const PDMPCIRAWHLPR0 *) PCPDMPCIRAWHLPR0; + +/** Current PDMPCIRAWHLPR0 version number. */ +#define PDM_PCIRAWHLPR0_VERSION PDM_VERSION_MAKE(0xffdf, 1, 0) + + +/** + * Raw PCI device ring-3 context helpers. + */ +typedef struct PDMPCIRAWHLPR3 +{ + /** Undefined structure version and magic number. */ + uint32_t u32Version; + + /** + * Gets the address of the RC raw PCI device helpers. + * + * This should be called at both construction and relocation time to obtain + * the correct address of the RC helpers. + * + * @returns RC pointer to the raw PCI device helpers. + * @param pDevIns Device instance of the raw PCI device. + */ + DECLR3CALLBACKMEMBER(PCPDMPCIRAWHLPRC, pfnGetRCHelpers,(PPDMDEVINS pDevIns)); + + /** + * Gets the address of the R0 raw PCI device helpers. + * + * This should be called at both construction and relocation time to obtain + * the correct address of the R0 helpers. + * + * @returns R0 pointer to the raw PCI device helpers. + * @param pDevIns Device instance of the raw PCI device. + */ + DECLR3CALLBACKMEMBER(PCPDMPCIRAWHLPR0, pfnGetR0Helpers,(PPDMDEVINS pDevIns)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMPCIRAWHLPR3; +/** Pointer to raw PCI R3 helpers. */ +typedef R3PTRTYPE(PDMPCIRAWHLPR3 *) PPDMPCIRAWHLPR3; +/** Pointer to const raw PCI R3 helpers. */ +typedef R3PTRTYPE(const PDMPCIRAWHLPR3 *) PCPDMPCIRAWHLPR3; + +/** Current PDMPCIRAWHLPR3 version number. */ +#define PDM_PCIRAWHLPR3_VERSION PDM_VERSION_MAKE(0xffde, 1, 0) + + +#ifdef IN_RING3 + +/** + * DMA Transfer Handler. + * + * @returns Number of bytes transferred. + * @param pDevIns Device instance of the DMA. + * @param pvUser User pointer. + * @param uChannel Channel number. + * @param off DMA position. + * @param cb Block size. + */ +typedef DECLCALLBACK(uint32_t) FNDMATRANSFERHANDLER(PPDMDEVINS pDevIns, void *pvUser, unsigned uChannel, uint32_t off, uint32_t cb); +/** Pointer to a FNDMATRANSFERHANDLER(). */ +typedef FNDMATRANSFERHANDLER *PFNDMATRANSFERHANDLER; + +/** + * DMA Controller registration structure. + */ +typedef struct PDMDMAREG +{ + /** Structure version number. PDM_DMACREG_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Execute pending transfers. + * + * @returns A more work indiciator. I.e. 'true' if there is more to be done, and 'false' if all is done. + * @param pDevIns Device instance of the DMAC. + */ + DECLR3CALLBACKMEMBER(bool, pfnRun,(PPDMDEVINS pDevIns)); + + /** + * Register transfer function for DMA channel. + * + * @param pDevIns Device instance of the DMAC. + * @param uChannel Channel number. + * @param pfnTransferHandler Device specific transfer function. + * @param pvUSer User pointer to be passed to the callback. + */ + DECLR3CALLBACKMEMBER(void, pfnRegister,(PPDMDEVINS pDevIns, unsigned uChannel, PFNDMATRANSFERHANDLER pfnTransferHandler, void *pvUser)); + + /** + * Read memory + * + * @returns Number of bytes read. + * @param pDevIns Device instance of the DMAC. + * @param pvBuffer Pointer to target buffer. + * @param off DMA position. + * @param cbBlock Block size. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnReadMemory,(PPDMDEVINS pDevIns, unsigned uChannel, void *pvBuffer, uint32_t off, uint32_t cbBlock)); + + /** + * Write memory + * + * @returns Number of bytes written. + * @param pDevIns Device instance of the DMAC. + * @param pvBuffer Memory to write. + * @param off DMA position. + * @param cbBlock Block size. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnWriteMemory,(PPDMDEVINS pDevIns, unsigned uChannel, const void *pvBuffer, uint32_t off, uint32_t cbBlock)); + + /** + * Set the DREQ line. + * + * @param pDevIns Device instance of the DMAC. + * @param uChannel Channel number. + * @param uLevel Level of the line. + */ + DECLR3CALLBACKMEMBER(void, pfnSetDREQ,(PPDMDEVINS pDevIns, unsigned uChannel, unsigned uLevel)); + + /** + * Get channel mode + * + * @returns Channel mode. + * @param pDevIns Device instance of the DMAC. + * @param uChannel Channel number. + */ + DECLR3CALLBACKMEMBER(uint8_t, pfnGetChannelMode,(PPDMDEVINS pDevIns, unsigned uChannel)); + +} PDMDMACREG; +/** Pointer to a DMAC registration structure. */ +typedef PDMDMACREG *PPDMDMACREG; + +/** Current PDMDMACREG version number. */ +#define PDM_DMACREG_VERSION PDM_VERSION_MAKE(0xffeb, 1, 0) + + +/** + * DMA Controller device helpers. + */ +typedef struct PDMDMACHLP +{ + /** Structure version. PDM_DMACHLP_VERSION defines the current version. */ + uint32_t u32Version; + + /* to-be-defined */ + +} PDMDMACHLP; +/** Pointer to DMAC helpers. */ +typedef PDMDMACHLP *PPDMDMACHLP; +/** Pointer to const DMAC helpers. */ +typedef const PDMDMACHLP *PCPDMDMACHLP; + +/** Current PDMDMACHLP version number. */ +#define PDM_DMACHLP_VERSION PDM_VERSION_MAKE(0xffea, 1, 0) + +#endif /* IN_RING3 */ + + + +/** + * RTC registration structure. + */ +typedef struct PDMRTCREG +{ + /** Structure version number. PDM_RTCREG_VERSION defines the current version. */ + uint32_t u32Version; + uint32_t u32Alignment; /**< structure size alignment. */ + + /** + * Write to a CMOS register and update the checksum if necessary. + * + * @returns VBox status code. + * @param pDevIns Device instance of the RTC. + * @param iReg The CMOS register index. + * @param u8Value The CMOS register value. + */ + DECLR3CALLBACKMEMBER(int, pfnWrite,(PPDMDEVINS pDevIns, unsigned iReg, uint8_t u8Value)); + + /** + * Read a CMOS register. + * + * @returns VBox status code. + * @param pDevIns Device instance of the RTC. + * @param iReg The CMOS register index. + * @param pu8Value Where to store the CMOS register value. + */ + DECLR3CALLBACKMEMBER(int, pfnRead,(PPDMDEVINS pDevIns, unsigned iReg, uint8_t *pu8Value)); + +} PDMRTCREG; +/** Pointer to a RTC registration structure. */ +typedef PDMRTCREG *PPDMRTCREG; +/** Pointer to a const RTC registration structure. */ +typedef const PDMRTCREG *PCPDMRTCREG; + +/** Current PDMRTCREG version number. */ +#define PDM_RTCREG_VERSION PDM_VERSION_MAKE(0xffe9, 1, 0) + + +/** + * RTC device helpers. + */ +typedef struct PDMRTCHLP +{ + /** Structure version. PDM_RTCHLP_VERSION defines the current version. */ + uint32_t u32Version; + + /* to-be-defined */ + +} PDMRTCHLP; +/** Pointer to RTC helpers. */ +typedef PDMRTCHLP *PPDMRTCHLP; +/** Pointer to const RTC helpers. */ +typedef const PDMRTCHLP *PCPDMRTCHLP; + +/** Current PDMRTCHLP version number. */ +#define PDM_RTCHLP_VERSION PDM_VERSION_MAKE(0xffe8, 1, 0) + + + +#ifdef IN_RING3 + +/** + * PDM Device API. + */ +typedef struct PDMDEVHLPR3 +{ + /** Structure version. PDM_DEVHLPR3_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Register a number of I/O ports with a device. + * + * These callbacks are of course for the host context (HC). + * Register HC handlers before guest context (GC) handlers! There must be a + * HC handler for every GC handler! + * + * @returns VBox status. + * @param pDevIns The device instance to register the ports with. + * @param Port First port number in the range. + * @param cPorts Number of ports to register. + * @param pvUser User argument. + * @param pfnOut Pointer to function which is gonna handle OUT operations. + * @param pfnIn Pointer to function which is gonna handle IN operations. + * @param pfnOutStr Pointer to function which is gonna handle string OUT operations. + * @param pfnInStr Pointer to function which is gonna handle string IN operations. + * @param pszDesc Pointer to description string. This must not be freed. + */ + DECLR3CALLBACKMEMBER(int, pfnIOPortRegister,(PPDMDEVINS pDevIns, RTIOPORT Port, RTIOPORT cPorts, RTHCPTR pvUser, + PFNIOMIOPORTOUT pfnOut, PFNIOMIOPORTIN pfnIn, + PFNIOMIOPORTOUTSTRING pfnOutStr, PFNIOMIOPORTINSTRING pfnInStr, const char *pszDesc)); + + /** + * Register a number of I/O ports with a device for RC. + * + * These callbacks are for the raw-mode context (RC). Register ring-3 context + * (R3) handlers before raw-mode context handlers! There must be a R3 handler + * for every RC handler! + * + * @returns VBox status. + * @param pDevIns The device instance to register the ports with + * and which RC module to resolve the names + * against. + * @param Port First port number in the range. + * @param cPorts Number of ports to register. + * @param pvUser User argument. + * @param pszOut Name of the RC function which is gonna handle OUT operations. + * @param pszIn Name of the RC function which is gonna handle IN operations. + * @param pszOutStr Name of the RC function which is gonna handle string OUT operations. + * @param pszInStr Name of the RC function which is gonna handle string IN operations. + * @param pszDesc Pointer to description string. This must not be freed. + */ + DECLR3CALLBACKMEMBER(int, pfnIOPortRegisterRC,(PPDMDEVINS pDevIns, RTIOPORT Port, RTIOPORT cPorts, RTRCPTR pvUser, + const char *pszOut, const char *pszIn, + const char *pszOutStr, const char *pszInStr, const char *pszDesc)); + + /** + * Register a number of I/O ports with a device. + * + * These callbacks are of course for the ring-0 host context (R0). + * Register R3 (HC) handlers before R0 (R0) handlers! There must be a R3 (HC) handler for every R0 handler! + * + * @returns VBox status. + * @param pDevIns The device instance to register the ports with. + * @param Port First port number in the range. + * @param cPorts Number of ports to register. + * @param pvUser User argument. (if pointer, then it must be in locked memory!) + * @param pszOut Name of the R0 function which is gonna handle OUT operations. + * @param pszIn Name of the R0 function which is gonna handle IN operations. + * @param pszOutStr Name of the R0 function which is gonna handle string OUT operations. + * @param pszInStr Name of the R0 function which is gonna handle string IN operations. + * @param pszDesc Pointer to description string. This must not be freed. + */ + DECLR3CALLBACKMEMBER(int, pfnIOPortRegisterR0,(PPDMDEVINS pDevIns, RTIOPORT Port, RTIOPORT cPorts, RTR0PTR pvUser, + const char *pszOut, const char *pszIn, + const char *pszOutStr, const char *pszInStr, const char *pszDesc)); + + /** + * Deregister I/O ports. + * + * This naturally affects both guest context (GC), ring-0 (R0) and ring-3 (R3/HC) handlers. + * + * @returns VBox status. + * @param pDevIns The device instance owning the ports. + * @param Port First port number in the range. + * @param cPorts Number of ports to deregister. + */ + DECLR3CALLBACKMEMBER(int, pfnIOPortDeregister,(PPDMDEVINS pDevIns, RTIOPORT Port, RTIOPORT cPorts)); + + /** + * Register a Memory Mapped I/O (MMIO) region. + * + * These callbacks are of course for the ring-3 context (R3). Register HC + * handlers before raw-mode context (RC) and ring-0 context (R0) handlers! There + * must be a R3 handler for every RC and R0 handler! + * + * @returns VBox status. + * @param pDevIns The device instance to register the MMIO with. + * @param GCPhysStart First physical address in the range. + * @param cbRange The size of the range (in bytes). + * @param pvUser User argument. + * @param pfnWrite Pointer to function which is gonna handle Write operations. + * @param pfnRead Pointer to function which is gonna handle Read operations. + * @param pfnFill Pointer to function which is gonna handle Fill/memset operations. (optional) + * @param fFlags Flags, IOMMMIO_FLAGS_XXX. + * @param pszDesc Pointer to description string. This must not be freed. + */ + DECLR3CALLBACKMEMBER(int, pfnMMIORegister,(PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, uint32_t cbRange, RTHCPTR pvUser, + PFNIOMMMIOWRITE pfnWrite, PFNIOMMMIOREAD pfnRead, PFNIOMMMIOFILL pfnFill, + uint32_t fFlags, const char *pszDesc)); + + /** + * Register a Memory Mapped I/O (MMIO) region for GC. + * + * These callbacks are for the raw-mode context (RC). Register ring-3 context + * (R3) handlers before guest context handlers! There must be a R3 handler for + * every RC handler! + * + * @returns VBox status. + * @param pDevIns The device instance to register the MMIO with. + * @param GCPhysStart First physical address in the range. + * @param cbRange The size of the range (in bytes). + * @param pvUser User argument. + * @param pszWrite Name of the RC function which is gonna handle Write operations. + * @param pszRead Name of the RC function which is gonna handle Read operations. + * @param pszFill Name of the RC function which is gonna handle Fill/memset operations. (optional) + */ + DECLR3CALLBACKMEMBER(int, pfnMMIORegisterRC,(PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, uint32_t cbRange, RTRCPTR pvUser, + const char *pszWrite, const char *pszRead, const char *pszFill)); + + /** + * Register a Memory Mapped I/O (MMIO) region for R0. + * + * These callbacks are for the ring-0 host context (R0). Register ring-3 + * constext (R3) handlers before R0 handlers! There must be a R3 handler for + * every R0 handler! + * + * @returns VBox status. + * @param pDevIns The device instance to register the MMIO with. + * @param GCPhysStart First physical address in the range. + * @param cbRange The size of the range (in bytes). + * @param pvUser User argument. (if pointer, then it must be in locked memory!) + * @param pszWrite Name of the RC function which is gonna handle Write operations. + * @param pszRead Name of the RC function which is gonna handle Read operations. + * @param pszFill Name of the RC function which is gonna handle Fill/memset operations. (optional) + * @param pszDesc Obsolete. NULL is fine. + */ + DECLR3CALLBACKMEMBER(int, pfnMMIORegisterR0,(PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, uint32_t cbRange, RTR0PTR pvUser, + const char *pszWrite, const char *pszRead, const char *pszFill)); + + /** + * Deregister a Memory Mapped I/O (MMIO) region. + * + * This naturally affects both guest context (GC), ring-0 (R0) and ring-3 (R3/HC) handlers. + * + * @returns VBox status. + * @param pDevIns The device instance owning the MMIO region(s). + * @param GCPhysStart First physical address in the range. + * @param cbRange The size of the range (in bytes). + */ + DECLR3CALLBACKMEMBER(int, pfnMMIODeregister,(PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, uint32_t cbRange)); + + /** + * Allocate and register a MMIO2 region. + * + * As mentioned elsewhere, MMIO2 is just RAM spelled differently. It's + * RAM associated with a device. It is also non-shared memory with a + * permanent ring-3 mapping and page backing (presently). + * + * @returns VBox status. + * @param pDevIns The device instance. + * @param iRegion The region number. Use the PCI region number as + * this must be known to the PCI bus device too. If + * it's not associated with the PCI device, then + * any number up to UINT8_MAX is fine. + * @param cb The size (in bytes) of the region. + * @param fFlags Reserved for future use, must be zero. + * @param ppv Where to store the address of the ring-3 mapping + * of the memory. + * @param pszDesc Pointer to description string. This must not be + * freed. + * @thread EMT. + */ + DECLR3CALLBACKMEMBER(int, pfnMMIO2Register,(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS cb, uint32_t fFlags, void **ppv, const char *pszDesc)); + + /** + * Deregisters and frees a MMIO2 region. + * + * Any physical (and virtual) access handlers registered for the region must + * be deregistered before calling this function. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param iRegion The region number used during registration. + * @thread EMT. + */ + DECLR3CALLBACKMEMBER(int, pfnMMIO2Deregister,(PPDMDEVINS pDevIns, uint32_t iRegion)); + + /** + * Maps a MMIO2 region into the physical memory space. + * + * A MMIO2 range may overlap with base memory if a lot of RAM + * is configured for the VM, in which case we'll drop the base + * memory pages. Presently we will make no attempt to preserve + * anything that happens to be present in the base memory that + * is replaced, this is of course incorrectly but it's too much + * effort. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param iRegion The region number used during registration. + * @param GCPhys The physical address to map it at. + * @thread EMT. + */ + DECLR3CALLBACKMEMBER(int, pfnMMIO2Map,(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS GCPhys)); + + /** + * Unmaps a MMIO2 region previously mapped using pfnMMIO2Map. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param iRegion The region number used during registration. + * @param GCPhys The physical address it's currently mapped at. + * @thread EMT. + */ + DECLR3CALLBACKMEMBER(int, pfnMMIO2Unmap,(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS GCPhys)); + + /** + * Maps a portion of an MMIO2 region into the hypervisor region. + * + * Callers of this API must never deregister the MMIO2 region before the + * VM is powered off. + * + * @return VBox status code. + * @param pDevIns The device owning the MMIO2 memory. + * @param iRegion The region. + * @param off The offset into the region. Will be rounded down + * to closest page boundary. + * @param cb The number of bytes to map. Will be rounded up + * to the closest page boundary. + * @param pszDesc Mapping description. + * @param pRCPtr Where to store the RC address. + */ + DECLR3CALLBACKMEMBER(int, pfnMMHyperMapMMIO2,(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS off, RTGCPHYS cb, + const char *pszDesc, PRTRCPTR pRCPtr)); + + /** + * Maps a portion of an MMIO2 region into kernel space (host). + * + * The kernel mapping will become invalid when the MMIO2 memory is deregistered + * or the VM is terminated. + * + * @return VBox status code. + * @param pDevIns The device owning the MMIO2 memory. + * @param iRegion The region. + * @param off The offset into the region. Must be page + * aligned. + * @param cb The number of bytes to map. Must be page + * aligned. + * @param pszDesc Mapping description. + * @param pR0Ptr Where to store the R0 address. + */ + DECLR3CALLBACKMEMBER(int, pfnMMIO2MapKernel,(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS off, RTGCPHYS cb, + const char *pszDesc, PRTR0PTR pR0Ptr)); + + /** + * Register a ROM (BIOS) region. + * + * It goes without saying that this is read-only memory. The memory region must be + * in unassigned memory. I.e. from the top of the address space or on the PC in + * the 0xa0000-0xfffff range. + * + * @returns VBox status. + * @param pDevIns The device instance owning the ROM region. + * @param GCPhysStart First physical address in the range. + * Must be page aligned! + * @param cbRange The size of the range (in bytes). + * Must be page aligned! + * @param pvBinary Pointer to the binary data backing the ROM image. + * @param cbBinary The size of the binary pointer. This must + * be equal or smaller than @a cbRange. + * @param fFlags Shadow ROM flags, PGMPHYS_ROM_FLAGS_* in pgm.h. + * @param pszDesc Pointer to description string. This must not be freed. + * + * @remark There is no way to remove the rom, automatically on device cleanup or + * manually from the device yet. At present I doubt we need such features... + */ + DECLR3CALLBACKMEMBER(int, pfnROMRegister,(PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, uint32_t cbRange, + const void *pvBinary, uint32_t cbBinary, uint32_t fFlags, const char *pszDesc)); + + /** + * Changes the protection of shadowed ROM mapping. + * + * This is intented for use by the system BIOS, chipset or device in question to + * change the protection of shadowed ROM code after init and on reset. + * + * @param pDevIns The device instance. + * @param GCPhysStart Where the mapping starts. + * @param cbRange The size of the mapping. + * @param enmProt The new protection type. + */ + DECLR3CALLBACKMEMBER(int, pfnROMProtectShadow,(PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, uint32_t cbRange, PGMROMPROT enmProt)); + + /** + * Register a save state data unit. + * + * @returns VBox status. + * @param pDevIns The device instance. + * @param pszName Data unit name. + * @param uInstance The instance identifier of the data unit. + * This must together with the name be unique. + * @param uVersion Data layout version number. + * @param cbGuess The approximate amount of data in the unit. + * Only for progress indicators. + * @param pszBefore Name of data unit which we should be put in + * front of. Optional (NULL). + * + * @param pfnLivePrep Prepare live save callback, optional. + * @param pfnLiveExec Execute live save callback, optional. + * @param pfnLiveVote Vote live save callback, optional. + * + * @param pfnSavePrep Prepare save callback, optional. + * @param pfnSaveExec Execute save callback, optional. + * @param pfnSaveDone Done save callback, optional. + * + * @param pfnLoadPrep Prepare load callback, optional. + * @param pfnLoadExec Execute load callback, optional. + * @param pfnLoadDone Done load callback, optional. + */ + DECLR3CALLBACKMEMBER(int, pfnSSMRegister,(PPDMDEVINS pDevIns, uint32_t uVersion, size_t cbGuess, const char *pszBefore, + PFNSSMDEVLIVEPREP pfnLivePrep, PFNSSMDEVLIVEEXEC pfnLiveExec, PFNSSMDEVLIVEVOTE pfnLiveVote, + PFNSSMDEVSAVEPREP pfnSavePrep, PFNSSMDEVSAVEEXEC pfnSaveExec, PFNSSMDEVSAVEDONE pfnSaveDone, + PFNSSMDEVLOADPREP pfnLoadPrep, PFNSSMDEVLOADEXEC pfnLoadExec, PFNSSMDEVLOADDONE pfnLoadDone)); + + /** + * Creates a timer. + * + * @returns VBox status. + * @param pDevIns The device instance. + * @param enmClock The clock to use on this timer. + * @param pfnCallback Callback function. + * @param pvUser User argument for the callback. + * @param fFlags Flags, see TMTIMER_FLAGS_*. + * @param pszDesc Pointer to description string which must stay around + * until the timer is fully destroyed (i.e. a bit after TMTimerDestroy()). + * @param ppTimer Where to store the timer on success. + */ + DECLR3CALLBACKMEMBER(int, pfnTMTimerCreate,(PPDMDEVINS pDevIns, TMCLOCK enmClock, PFNTMTIMERDEV pfnCallback, void *pvUser, uint32_t fFlags, const char *pszDesc, PPTMTIMERR3 ppTimer)); + + /** + * Get the real world UTC time adjusted for VM lag, user offset and warpdrive. + * + * @returns pTime. + * @param pDevIns The device instance. + * @param pTime Where to store the time. + */ + DECLR3CALLBACKMEMBER(PRTTIMESPEC, pfnTMUtcNow,(PPDMDEVINS pDevIns, PRTTIMESPEC pTime)); + + /** + * Read physical memory. + * + * @returns VINF_SUCCESS (for now). + * @param pDevIns The device instance. + * @param GCPhys Physical address start reading from. + * @param pvBuf Where to put the read bits. + * @param cbRead How many bytes to read. + * @thread Any thread, but the call may involve the emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPhysRead,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead)); + + /** + * Write to physical memory. + * + * @returns VINF_SUCCESS for now, and later maybe VERR_EM_MEMORY. + * @param pDevIns The device instance. + * @param GCPhys Physical address to write to. + * @param pvBuf What to write. + * @param cbWrite How many bytes to write. + * @thread Any thread, but the call may involve the emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPhysWrite,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite)); + + /** + * Requests the mapping of a guest page into ring-3. + * + * When you're done with the page, call pfnPhysReleasePageMappingLock() ASAP to + * release it. + * + * This API will assume your intention is to write to the page, and will + * therefore replace shared and zero pages. If you do not intend to modify the + * page, use the pfnPhysGCPhys2CCPtrReadOnly() API. + * + * @returns VBox status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid page but has no physical + * backing or if the page has any active access handlers. The caller + * must fall back on using PGMR3PhysWriteExternal. + * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid physical address. + * + * @param pVM The VM handle. + * @param GCPhys The guest physical address of the page that + * should be mapped. + * @param fFlags Flags reserved for future use, MBZ. + * @param ppv Where to store the address corresponding to + * GCPhys. + * @param pLock Where to store the lock information that + * pfnPhysReleasePageMappingLock needs. + * + * @remark Avoid calling this API from within critical sections (other than the + * PGM one) because of the deadlock risk when we have to delegating the + * task to an EMT. + * @thread Any. + */ + DECLR3CALLBACKMEMBER(int, pfnPhysGCPhys2CCPtr,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, uint32_t fFlags, void **ppv, PPGMPAGEMAPLOCK pLock)); + + /** + * Requests the mapping of a guest page into ring-3, external threads. + * + * When you're done with the page, call pfnPhysReleasePageMappingLock() ASAP to + * release it. + * + * @returns VBox status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid page but has no physical + * backing or if the page as an active ALL access handler. The caller + * must fall back on using PGMPhysRead. + * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid physical address. + * + * @param pDevIns The device instance. + * @param GCPhys The guest physical address of the page that + * should be mapped. + * @param fFlags Flags reserved for future use, MBZ. + * @param ppv Where to store the address corresponding to + * GCPhys. + * @param pLock Where to store the lock information that + * pfnPhysReleasePageMappingLock needs. + * + * @remark Avoid calling this API from within critical sections. + * @thread Any. + */ + DECLR3CALLBACKMEMBER(int, pfnPhysGCPhys2CCPtrReadOnly,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, uint32_t fFlags, void const **ppv, PPGMPAGEMAPLOCK pLock)); + + /** + * Release the mapping of a guest page. + * + * This is the counter part of pfnPhysGCPhys2CCPtr and + * pfnPhysGCPhys2CCPtrReadOnly. + * + * @param pDevIns The device instance. + * @param pLock The lock structure initialized by the mapping + * function. + */ + DECLR3CALLBACKMEMBER(void, pfnPhysReleasePageMappingLock,(PPDMDEVINS pDevIns, PPGMPAGEMAPLOCK pLock)); + + /** + * Read guest physical memory by virtual address. + * + * @param pDevIns The device instance. + * @param pvDst Where to put the read bits. + * @param GCVirtSrc Guest virtual address to start reading from. + * @param cb How many bytes to read. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPhysReadGCVirt,(PPDMDEVINS pDevIns, void *pvDst, RTGCPTR GCVirtSrc, size_t cb)); + + /** + * Write to guest physical memory by virtual address. + * + * @param pDevIns The device instance. + * @param GCVirtDst Guest virtual address to write to. + * @param pvSrc What to write. + * @param cb How many bytes to write. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPhysWriteGCVirt,(PPDMDEVINS pDevIns, RTGCPTR GCVirtDst, const void *pvSrc, size_t cb)); + + /** + * Convert a guest virtual address to a guest physical address. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param GCPtr Guest virtual address. + * @param pGCPhys Where to store the GC physical address + * corresponding to GCPtr. + * @thread The emulation thread. + * @remark Careful with page boundaries. + */ + DECLR3CALLBACKMEMBER(int, pfnPhysGCPtr2GCPhys, (PPDMDEVINS pDevIns, RTGCPTR GCPtr, PRTGCPHYS pGCPhys)); + + /** + * Allocate memory which is associated with current VM instance + * and automatically freed on it's destruction. + * + * @returns Pointer to allocated memory. The memory is *NOT* zero-ed. + * @param pDevIns The device instance. + * @param cb Number of bytes to allocate. + */ + DECLR3CALLBACKMEMBER(void *, pfnMMHeapAlloc,(PPDMDEVINS pDevIns, size_t cb)); + + /** + * Allocate memory which is associated with current VM instance + * and automatically freed on it's destruction. The memory is ZEROed. + * + * @returns Pointer to allocated memory. The memory is *NOT* zero-ed. + * @param pDevIns The device instance. + * @param cb Number of bytes to allocate. + */ + DECLR3CALLBACKMEMBER(void *, pfnMMHeapAllocZ,(PPDMDEVINS pDevIns, size_t cb)); + + /** + * Free memory allocated with pfnMMHeapAlloc() and pfnMMHeapAllocZ(). + * + * @param pDevIns The device instance. + * @param pv Pointer to the memory to free. + */ + DECLR3CALLBACKMEMBER(void, pfnMMHeapFree,(PPDMDEVINS pDevIns, void *pv)); + + /** + * Gets the VM state. + * + * @returns VM state. + * @param pDevIns The device instance. + * @thread Any thread (just keep in mind that it's volatile info). + */ + DECLR3CALLBACKMEMBER(VMSTATE, pfnVMState, (PPDMDEVINS pDevIns)); + + /** + * Checks if the VM was teleported and hasn't been fully resumed yet. + * + * @returns true / false. + * @param pDevIns The device instance. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(bool, pfnVMTeleportedAndNotFullyResumedYet,(PPDMDEVINS pDevIns)); + + /** + * Set the VM error message + * + * @returns rc. + * @param pDevIns The device instance. + * @param rc VBox status code. + * @param RT_SRC_POS_DECL Use RT_SRC_POS. + * @param pszFormat Error message format string. + * @param ... Error message arguments. + */ + DECLR3CALLBACKMEMBER(int, pfnVMSetError,(PPDMDEVINS pDevIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...)); + + /** + * Set the VM error message + * + * @returns rc. + * @param pDevIns The device instance. + * @param rc VBox status code. + * @param RT_SRC_POS_DECL Use RT_SRC_POS. + * @param pszFormat Error message format string. + * @param va Error message arguments. + */ + DECLR3CALLBACKMEMBER(int, pfnVMSetErrorV,(PPDMDEVINS pDevIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va)); + + /** + * Set the VM runtime error message + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param fFlags The action flags. See VMSETRTERR_FLAGS_*. + * @param pszErrorId Error ID string. + * @param pszFormat Error message format string. + * @param ... Error message arguments. + */ + DECLR3CALLBACKMEMBER(int, pfnVMSetRuntimeError,(PPDMDEVINS pDevIns, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...)); + + /** + * Set the VM runtime error message + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param fFlags The action flags. See VMSETRTERR_FLAGS_*. + * @param pszErrorId Error ID string. + * @param pszFormat Error message format string. + * @param va Error message arguments. + */ + DECLR3CALLBACKMEMBER(int, pfnVMSetRuntimeErrorV,(PPDMDEVINS pDevIns, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, va_list va)); + + /** + * Stops the VM and enters the debugger to look at the guest state. + * + * Use the PDMDeviceDBGFStop() inline function with the RT_SRC_POS macro instead of + * invoking this function directly. + * + * @returns VBox status code which must be passed up to the VMM. + * @param pDevIns The device instance. + * @param pszFile Filename of the assertion location. + * @param iLine The linenumber of the assertion location. + * @param pszFunction Function of the assertion location. + * @param pszFormat Message. (optional) + * @param args Message parameters. + */ + DECLR3CALLBACKMEMBER(int, pfnDBGFStopV,(PPDMDEVINS pDevIns, const char *pszFile, unsigned iLine, const char *pszFunction, const char *pszFormat, va_list args)); + + /** + * Register a info handler with DBGF, + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pszName The identifier of the info. + * @param pszDesc The description of the info and any arguments + * the handler may take. + * @param pfnHandler The handler function to be called to display the + * info. + */ + DECLR3CALLBACKMEMBER(int, pfnDBGFInfoRegister,(PPDMDEVINS pDevIns, const char *pszName, const char *pszDesc, PFNDBGFHANDLERDEV pfnHandler)); + + /** + * Gets the trace buffer handle. + * + * This is used by the macros found in VBox/vmm/dbgftrace.h and is not + * really inteded for direct usage, thus no inline wrapper function. + * + * @returns Trace buffer handle or NIL_RTTRACEBUF. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(RTTRACEBUF, pfnDBGFTraceBuf,(PPDMDEVINS pDevIns)); + + /** + * Registers a statistics sample if statistics are enabled. + * + * @param pDevIns Device instance of the DMA. + * @param pvSample Pointer to the sample. + * @param enmType Sample type. This indicates what pvSample is + * pointing at. + * @param pszName Sample name. The name is on this form + * "/<component>/<sample>". Further nesting is + * possible. + * @param enmUnit Sample unit. + * @param pszDesc Sample description. + */ + DECLR3CALLBACKMEMBER(void, pfnSTAMRegister,(PPDMDEVINS pDevIns, void *pvSample, STAMTYPE enmType, const char *pszName, STAMUNIT enmUnit, const char *pszDesc)); + + /** + * Same as pfnSTAMRegister except that the name is specified in a + * RTStrPrintf like fashion. + * + * @returns VBox status. + * @param pDevIns Device instance of the DMA. + * @param pvSample Pointer to the sample. + * @param enmType Sample type. This indicates what pvSample is + * pointing at. + * @param enmVisibility Visibility type specifying whether unused + * statistics should be visible or not. + * @param enmUnit Sample unit. + * @param pszDesc Sample description. + * @param pszName The sample name format string. + * @param ... Arguments to the format string. + */ + DECLR3CALLBACKMEMBER(void, pfnSTAMRegisterF,(PPDMDEVINS pDevIns, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, + STAMUNIT enmUnit, const char *pszDesc, const char *pszName, ...)); + + /** + * Same as pfnSTAMRegister except that the name is specified in a + * RTStrPrintfV like fashion. + * + * @returns VBox status. + * @param pDevIns Device instance of the DMA. + * @param pvSample Pointer to the sample. + * @param enmType Sample type. This indicates what pvSample is + * pointing at. + * @param enmVisibility Visibility type specifying whether unused + * statistics should be visible or not. + * @param enmUnit Sample unit. + * @param pszDesc Sample description. + * @param pszName The sample name format string. + * @param args Arguments to the format string. + */ + DECLR3CALLBACKMEMBER(void, pfnSTAMRegisterV,(PPDMDEVINS pDevIns, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, + STAMUNIT enmUnit, const char *pszDesc, const char *pszName, va_list args)); + + /** + * Reads data via bus mastering, if enabled. If no bus mastering is available, + * this function does nothing and returns VINF_PGM_PCI_PHYS_READ_BM_DISABLED. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, pfnPCIPhysRead,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead)); + + /** + * Writes data via bus mastering, if enabled. If no bus mastering is available, + * this function does nothing and returns VINF_PGM_PCI_PHYS_WRITE_BM_DISABLED. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, pfnPCIPhysWrite,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite)); + + /** + * Registers the device with the default PCI bus. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. + * Any PCI enabled device must keep this in it's instance data! + * Fill in the PCI data config before registration, please. + * @remark This is the simple interface, a Ex interface will be created if + * more features are needed later. + */ + DECLR3CALLBACKMEMBER(int, pfnPCIRegister,(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev)); + + /** + * Initialize MSI support in a PCI device. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pMsiReg MSI registartion structure. + */ + DECLR3CALLBACKMEMBER(int, pfnPCIRegisterMsi,(PPDMDEVINS pDevIns, PPDMMSIREG pMsiReg)); + + /** + * Registers a I/O region (memory mapped or I/O ports) for a PCI device. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param iRegion The region number. + * @param cbRegion Size of the region. + * @param enmType PCI_ADDRESS_SPACE_MEM, PCI_ADDRESS_SPACE_IO or PCI_ADDRESS_SPACE_MEM_PREFETCH. + * @param pfnCallback Callback for doing the mapping. + */ + DECLR3CALLBACKMEMBER(int, pfnPCIIORegionRegister,(PPDMDEVINS pDevIns, int iRegion, uint32_t cbRegion, PCIADDRESSSPACE enmType, PFNPCIIOREGIONMAP pfnCallback)); + + /** + * Register PCI configuration space read/write callbacks. + * + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. + * If NULL the default PCI device for this device instance is used. + * @param pfnRead Pointer to the user defined PCI config read function. + * @param ppfnReadOld Pointer to function pointer which will receive the old (default) + * PCI config read function. This way, user can decide when (and if) + * to call default PCI config read function. Can be NULL. + * @param pfnWrite Pointer to the user defined PCI config write function. + * @param pfnWriteOld Pointer to function pointer which will receive the old (default) + * PCI config write function. This way, user can decide when (and if) + * to call default PCI config write function. Can be NULL. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(void, pfnPCISetConfigCallbacks,(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, PFNPCICONFIGREAD pfnRead, PPFNPCICONFIGREAD ppfnReadOld, + PFNPCICONFIGWRITE pfnWrite, PPFNPCICONFIGWRITE ppfnWriteOld)); + + /** + * Set the IRQ for a PCI device. + * + * @param pDevIns The device instance. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @thread Any thread, but will involve the emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnPCISetIrq,(PPDMDEVINS pDevIns, int iIrq, int iLevel)); + + /** + * Set the IRQ for a PCI device, but don't wait for EMT to process + * the request when not called from EMT. + * + * @param pDevIns The device instance. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. + * @thread Any thread, but will involve the emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnPCISetIrqNoWait,(PPDMDEVINS pDevIns, int iIrq, int iLevel)); + + /** + * Set ISA IRQ for a device. + * + * @param pDevIns The device instance. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @thread Any thread, but will involve the emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnISASetIrq,(PPDMDEVINS pDevIns, int iIrq, int iLevel)); + + /** + * Set the ISA IRQ for a device, but don't wait for EMT to process + * the request when not called from EMT. + * + * @param pDevIns The device instance. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @thread Any thread, but will involve the emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnISASetIrqNoWait,(PPDMDEVINS pDevIns, int iIrq, int iLevel)); + + /** + * Attaches a driver (chain) to the device. + * + * The first call for a LUN this will serve as a registartion of the LUN. The pBaseInterface and + * the pszDesc string will be registered with that LUN and kept around for PDMR3QueryDeviceLun(). + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param iLun The logical unit to attach. + * @param pBaseInterface Pointer to the base interface for that LUN. (device side / down) + * @param ppBaseInterface Where to store the pointer to the base interface. (driver side / up) + * @param pszDesc Pointer to a string describing the LUN. This string must remain valid + * for the live of the device instance. + */ + DECLR3CALLBACKMEMBER(int, pfnDriverAttach,(PPDMDEVINS pDevIns, uint32_t iLun, PPDMIBASE pBaseInterface, PPDMIBASE *ppBaseInterface, const char *pszDesc)); + + /** + * Create a queue. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param cbItem The size of a queue item. + * @param cItems The number of items in the queue. + * @param cMilliesInterval The number of milliseconds between polling the queue. + * If 0 then the emulation thread will be notified whenever an item arrives. + * @param pfnCallback The consumer function. + * @param fRZEnabled Set if the queue should work in RC and R0. + * @param pszName The queue base name. The instance number will be + * appended automatically. + * @param ppQueue Where to store the queue handle on success. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnQueueCreate,(PPDMDEVINS pDevIns, size_t cbItem, uint32_t cItems, uint32_t cMilliesInterval, + PFNPDMQUEUEDEV pfnCallback, bool fRZEnabled, const char *pszName, PPDMQUEUE *ppQueue)); + + /** + * Initializes a PDM critical section. + * + * The PDM critical sections are derived from the IPRT critical sections, but + * works in RC and R0 as well. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pCritSect Pointer to the critical section. + * @param RT_SRC_POS_DECL Use RT_SRC_POS. + * @param pszNameFmt Format string for naming the critical section. + * For statistics and lock validation. + * @param va Arguments for the format string. + */ + DECLR3CALLBACKMEMBER(int, pfnCritSectInit,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, RT_SRC_POS_DECL, + const char *pszNameFmt, va_list va)); + + /** + * Gets the NOP critical section. + * + * @returns The ring-3 address of the NOP critical section. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(PPDMCRITSECT, pfnCritSectGetNop,(PPDMDEVINS pDevIns)); + + /** + * Gets the NOP critical section. + * + * @returns The ring-0 address of the NOP critical section. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(R0PTRTYPE(PPDMCRITSECT), pfnCritSectGetNopR0,(PPDMDEVINS pDevIns)); + + /** + * Gets the NOP critical section. + * + * @returns The raw-mode context address of the NOP critical section. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(RCPTRTYPE(PPDMCRITSECT), pfnCritSectGetNopRC,(PPDMDEVINS pDevIns)); + + /** + * Changes the device level critical section from the automatically created + * default to one desired by the device constructor. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pCritSect The critical section to use. NULL is not + * valid, instead use the NOP critical + * section. + */ + DECLR3CALLBACKMEMBER(int, pfnSetDeviceCritSect,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect)); + + /** + * Creates a PDM thread. + * + * This differs from the RTThreadCreate() API in that PDM takes care of suspending, + * resuming, and destroying the thread as the VM state changes. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param ppThread Where to store the thread 'handle'. + * @param pvUser The user argument to the thread function. + * @param pfnThread The thread function. + * @param pfnWakeup The wakup callback. This is called on the EMT + * thread when a state change is pending. + * @param cbStack See RTThreadCreate. + * @param enmType See RTThreadCreate. + * @param pszName See RTThreadCreate. + */ + DECLR3CALLBACKMEMBER(int, pfnThreadCreate,(PPDMDEVINS pDevIns, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADDEV pfnThread, + PFNPDMTHREADWAKEUPDEV pfnWakeup, size_t cbStack, RTTHREADTYPE enmType, const char *pszName)); + + /** + * Set up asynchronous handling of a suspend, reset or power off notification. + * + * This shall only be called when getting the notification. It must be called + * for each one. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pfnAsyncNotify The callback. + * @thread EMT(0) + */ + DECLR3CALLBACKMEMBER(int, pfnSetAsyncNotification, (PPDMDEVINS pDevIns, PFNPDMDEVASYNCNOTIFY pfnAsyncNotify)); + + /** + * Notify EMT(0) that the device has completed the asynchronous notification + * handling. + * + * This can be called at any time, spurious calls will simply be ignored. + * + * @param pDevIns The device instance. + * @thread Any + */ + DECLR3CALLBACKMEMBER(void, pfnAsyncNotificationCompleted, (PPDMDEVINS pDevIns)); + + /** + * Register the RTC device. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pRtcReg Pointer to a RTC registration structure. + * @param ppRtcHlp Where to store the pointer to the helper + * functions. + */ + DECLR3CALLBACKMEMBER(int, pfnRTCRegister,(PPDMDEVINS pDevIns, PCPDMRTCREG pRtcReg, PCPDMRTCHLP *ppRtcHlp)); + + /** + * Register the PCI Bus. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPciBusReg Pointer to PCI bus registration structure. + * @param ppPciHlpR3 Where to store the pointer to the PCI Bus + * helpers. + */ + DECLR3CALLBACKMEMBER(int, pfnPCIBusRegister,(PPDMDEVINS pDevIns, PPDMPCIBUSREG pPciBusReg, PCPDMPCIHLPR3 *ppPciHlpR3)); + + /** + * Register the PIC device. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPicReg Pointer to a PIC registration structure. + * @param ppPicHlpR3 Where to store the pointer to the PIC HC + * helpers. + */ + DECLR3CALLBACKMEMBER(int, pfnPICRegister,(PPDMDEVINS pDevIns, PPDMPICREG pPicReg, PCPDMPICHLPR3 *ppPicHlpR3)); + + /** + * Register the APIC device. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pApicReg Pointer to a APIC registration structure. + * @param ppApicHlpR3 Where to store the pointer to the APIC helpers. + */ + DECLR3CALLBACKMEMBER(int, pfnAPICRegister,(PPDMDEVINS pDevIns, PPDMAPICREG pApicReg, PCPDMAPICHLPR3 *ppApicHlpR3)); + + /** + * Register the I/O APIC device. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pIoApicReg Pointer to a I/O APIC registration structure. + * @param ppIoApicHlpR3 Where to store the pointer to the IOAPIC + * helpers. + */ + DECLR3CALLBACKMEMBER(int, pfnIOAPICRegister,(PPDMDEVINS pDevIns, PPDMIOAPICREG pIoApicReg, PCPDMIOAPICHLPR3 *ppIoApicHlpR3)); + + /** + * Register the HPET device. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pHpetReg Pointer to a HPET registration structure. + * @param ppHpetHlpR3 Where to store the pointer to the HPET + * helpers. + */ + DECLR3CALLBACKMEMBER(int, pfnHPETRegister,(PPDMDEVINS pDevIns, PPDMHPETREG pHpetReg, PCPDMHPETHLPR3 *ppHpetHlpR3)); + + /** + * Register a raw PCI device. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pHpetReg Pointer to a raw PCI registration structure. + * @param ppPciRawHlpR3 Where to store the pointer to the raw PCI + * device helpers. + */ + DECLR3CALLBACKMEMBER(int, pfnPciRawRegister,(PPDMDEVINS pDevIns, PPDMPCIRAWREG pPciRawReg, PCPDMPCIRAWHLPR3 *ppPciRawHlpR3)); + + /** + * Register the DMA device. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pDmacReg Pointer to a DMAC registration structure. + * @param ppDmacHlp Where to store the pointer to the DMA helpers. + */ + DECLR3CALLBACKMEMBER(int, pfnDMACRegister,(PPDMDEVINS pDevIns, PPDMDMACREG pDmacReg, PCPDMDMACHLP *ppDmacHlp)); + + /** + * Register transfer function for DMA channel. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param uChannel Channel number. + * @param pfnTransferHandler Device specific transfer callback function. + * @param pvUser User pointer to pass to the callback. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnDMARegister,(PPDMDEVINS pDevIns, unsigned uChannel, PFNDMATRANSFERHANDLER pfnTransferHandler, void *pvUser)); + + /** + * Read memory. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param uChannel Channel number. + * @param pvBuffer Pointer to target buffer. + * @param off DMA position. + * @param cbBlock Block size. + * @param pcbRead Where to store the number of bytes which was + * read. optional. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnDMAReadMemory,(PPDMDEVINS pDevIns, unsigned uChannel, void *pvBuffer, uint32_t off, uint32_t cbBlock, uint32_t *pcbRead)); + + /** + * Write memory. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param uChannel Channel number. + * @param pvBuffer Memory to write. + * @param off DMA position. + * @param cbBlock Block size. + * @param pcbWritten Where to store the number of bytes which was + * written. optional. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnDMAWriteMemory,(PPDMDEVINS pDevIns, unsigned uChannel, const void *pvBuffer, uint32_t off, uint32_t cbBlock, uint32_t *pcbWritten)); + + /** + * Set the DREQ line. + * + * @returns VBox status code. + * @param pDevIns Device instance. + * @param uChannel Channel number. + * @param uLevel Level of the line. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnDMASetDREQ,(PPDMDEVINS pDevIns, unsigned uChannel, unsigned uLevel)); + + /** + * Get channel mode. + * + * @returns Channel mode. See specs. + * @param pDevIns The device instance. + * @param uChannel Channel number. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(uint8_t, pfnDMAGetChannelMode,(PPDMDEVINS pDevIns, unsigned uChannel)); + + /** + * Schedule DMA execution. + * + * @param pDevIns The device instance. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(void, pfnDMASchedule,(PPDMDEVINS pDevIns)); + + /** + * Write CMOS value and update the checksum(s). + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param iReg The CMOS register index. + * @param u8Value The CMOS register value. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnCMOSWrite,(PPDMDEVINS pDevIns, unsigned iReg, uint8_t u8Value)); + + /** + * Read CMOS value. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param iReg The CMOS register index. + * @param pu8Value Where to store the CMOS register value. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnCMOSRead,(PPDMDEVINS pDevIns, unsigned iReg, uint8_t *pu8Value)); + + /** + * Assert that the current thread is the emulation thread. + * + * @returns True if correct. + * @returns False if wrong. + * @param pDevIns The device instance. + * @param pszFile Filename of the assertion location. + * @param iLine The linenumber of the assertion location. + * @param pszFunction Function of the assertion location. + */ + DECLR3CALLBACKMEMBER(bool, pfnAssertEMT,(PPDMDEVINS pDevIns, const char *pszFile, unsigned iLine, const char *pszFunction)); + + /** + * Assert that the current thread is NOT the emulation thread. + * + * @returns True if correct. + * @returns False if wrong. + * @param pDevIns The device instance. + * @param pszFile Filename of the assertion location. + * @param iLine The linenumber of the assertion location. + * @param pszFunction Function of the assertion location. + */ + DECLR3CALLBACKMEMBER(bool, pfnAssertOther,(PPDMDEVINS pDevIns, const char *pszFile, unsigned iLine, const char *pszFunction)); + + /** + * Resolves the symbol for a raw-mode context interface. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pvInterface The interface structure. + * @param cbInterface The size of the interface structure. + * @param pszSymPrefix What to prefix the symbols in the list with + * before resolving them. This must start with + * 'dev' and contain the driver name. + * @param pszSymList List of symbols corresponding to the interface. + * There is generally a there is generally a define + * holding this list associated with the interface + * definition (INTERFACE_SYM_LIST). For more + * details see PDMR3LdrGetInterfaceSymbols. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnLdrGetRCInterfaceSymbols,(PPDMDEVINS pDevIns, void *pvInterface, size_t cbInterface, + const char *pszSymPrefix, const char *pszSymList)); + + /** + * Resolves the symbol for a ring-0 context interface. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pvInterface The interface structure. + * @param cbInterface The size of the interface structure. + * @param pszSymPrefix What to prefix the symbols in the list with + * before resolving them. This must start with + * 'dev' and contain the driver name. + * @param pszSymList List of symbols corresponding to the interface. + * There is generally a there is generally a define + * holding this list associated with the interface + * definition (INTERFACE_SYM_LIST). For more + * details see PDMR3LdrGetInterfaceSymbols. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnLdrGetR0InterfaceSymbols,(PPDMDEVINS pDevIns, void *pvInterface, size_t cbInterface, + const char *pszSymPrefix, const char *pszSymList)); + + /** + * Call the ring-0 request handler routine of the device. + * + * For this to work, the device must be ring-0 enabled and export a request + * handler function. The name of the function must be the device name in + * the PDMDRVREG struct prefixed with 'drvR0' and suffixed with + * 'ReqHandler'. The device name will be captialized. It shall take the + * exact same arguments as this function and be declared using + * PDMBOTHCBDECL. See FNPDMDEVREQHANDLERR0. + * + * Unlike PDMDrvHlpCallR0, this is current unsuitable for more than a call + * or two as the handler address will be resolved on each invocation. This + * is the reason for the EMT only restriction as well. + * + * @returns VBox status code. + * @retval VERR_SYMBOL_NOT_FOUND if the device doesn't export the required + * handler function. + * @retval VERR_ACCESS_DENIED if the device isn't ring-0 capable. + * + * @param pDevIns The device instance. + * @param uOperation The operation to perform. + * @param u64Arg 64-bit integer argument. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnCallR0,(PPDMDEVINS pDevIns, uint32_t uOperation, uint64_t u64Arg)); + + /** Space reserved for future members. + * @{ */ + DECLR3CALLBACKMEMBER(void, pfnReserved1,(void)); + DECLR3CALLBACKMEMBER(void, pfnReserved2,(void)); + DECLR3CALLBACKMEMBER(void, pfnReserved3,(void)); + DECLR3CALLBACKMEMBER(void, pfnReserved4,(void)); + DECLR3CALLBACKMEMBER(void, pfnReserved5,(void)); + DECLR3CALLBACKMEMBER(void, pfnReserved6,(void)); + DECLR3CALLBACKMEMBER(void, pfnReserved7,(void)); + DECLR3CALLBACKMEMBER(void, pfnReserved8,(void)); + DECLR3CALLBACKMEMBER(void, pfnReserved9,(void)); + DECLR3CALLBACKMEMBER(void, pfnReserved10,(void)); + /** @} */ + + + /** API available to trusted devices only. + * + * These APIs are providing unrestricted access to the guest and the VM, + * or they are interacting intimately with PDM. + * + * @{ + */ + /** + * Gets the VM handle. Restricted API. + * + * @returns VM Handle. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(PVM, pfnGetVM,(PPDMDEVINS pDevIns)); + + /** + * Gets the VMCPU handle. Restricted API. + * + * @returns VMCPU Handle. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(PVMCPU, pfnGetVMCPU,(PPDMDEVINS pDevIns)); + + /** + * Registers the VMM device heap + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param GCPhys The physical address. + * @param pvHeap Ring 3 heap pointer. + * @param cbSize Size of the heap. + * @thread EMT. + */ + DECLR3CALLBACKMEMBER(int, pfnRegisterVMMDevHeap,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTR3PTR pvHeap, unsigned cbSize)); + + /** + * Unregisters the VMM device heap + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param GCPhys The physical address. + * @thread EMT. + */ + DECLR3CALLBACKMEMBER(int, pfnUnregisterVMMDevHeap,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys)); + + /** + * Resets the VM. + * + * @returns The appropriate VBox status code to pass around on reset. + * @param pDevIns The device instance. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnVMReset,(PPDMDEVINS pDevIns)); + + /** + * Suspends the VM. + * + * @returns The appropriate VBox status code to pass around on suspend. + * @param pDevIns The device instance. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnVMSuspend,(PPDMDEVINS pDevIns)); + + /** + * Suspends, saves and powers off the VM. + * + * @returns The appropriate VBox status code to pass around. + * @param pDevIns The device instance. + * @thread An emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnVMSuspendSaveAndPowerOff,(PPDMDEVINS pDevIns)); + + /** + * Power off the VM. + * + * @returns The appropriate VBox status code to pass around on power off. + * @param pDevIns The device instance. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnVMPowerOff,(PPDMDEVINS pDevIns)); + + /** + * Checks if the Gate A20 is enabled or not. + * + * @returns true if A20 is enabled. + * @returns false if A20 is disabled. + * @param pDevIns The device instance. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(bool, pfnA20IsEnabled,(PPDMDEVINS pDevIns)); + + /** + * Enables or disables the Gate A20. + * + * @param pDevIns The device instance. + * @param fEnable Set this flag to enable the Gate A20; clear it + * to disable. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnA20Set,(PPDMDEVINS pDevIns, bool fEnable)); + + /** + * Get the specified CPUID leaf for the virtual CPU associated with the calling + * thread. + * + * @param pDevIns The device instance. + * @param iLeaf The CPUID leaf to get. + * @param pEax Where to store the EAX value. + * @param pEbx Where to store the EBX value. + * @param pEcx Where to store the ECX value. + * @param pEdx Where to store the EDX value. + * @thread EMT. + */ + DECLR3CALLBACKMEMBER(void, pfnGetCpuId,(PPDMDEVINS pDevIns, uint32_t iLeaf, uint32_t *pEax, uint32_t *pEbx, uint32_t *pEcx, uint32_t *pEdx)); + + /** + * Get the current virtual clock time in a VM. The clock frequency must be + * queried separately. + * + * @returns Current clock time. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnTMTimeVirtGet,(PPDMDEVINS pDevIns)); + + /** + * Get the frequency of the virtual clock. + * + * @returns The clock frequency (not variable at run-time). + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnTMTimeVirtGetFreq,(PPDMDEVINS pDevIns)); + + /** + * Get the current virtual clock time in a VM, in nanoseconds. + * + * @returns Current clock time (in ns). + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnTMTimeVirtGetNano,(PPDMDEVINS pDevIns)); + + /** @} */ + + /** Just a safety precaution. (PDM_DEVHLPR3_VERSION) */ + uint32_t u32TheEnd; +} PDMDEVHLPR3; +#endif /* !IN_RING3 */ +/** Pointer to the R3 PDM Device API. */ +typedef R3PTRTYPE(struct PDMDEVHLPR3 *) PPDMDEVHLPR3; +/** Pointer to the R3 PDM Device API, const variant. */ +typedef R3PTRTYPE(const struct PDMDEVHLPR3 *) PCPDMDEVHLPR3; + +/** Current PDMDEVHLPR3 version number. */ +#define PDM_DEVHLPR3_VERSION PDM_VERSION_MAKE(0xffe7, 9, 0) + + +/** + * PDM Device API - RC Variant. + */ +typedef struct PDMDEVHLPRC +{ + /** Structure version. PDM_DEVHLPRC_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Reads data via bus mastering, if enabled. If no bus mastering is available, + * this function does nothing and returns VINF_PGM_PCI_PHYS_READ_BM_DISABLED. + * + * @return IPRT status code. + */ + DECLRCCALLBACKMEMBER(int, pfnPCIDevPhysRead,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead)); + + /** + * Writes data via bus mastering, if enabled. If no bus mastering is available, + * this function does nothing and returns VINF_PGM_PCI_PHYS_WRITE_BM_DISABLED. + * + * @return IPRT status code. + */ + DECLRCCALLBACKMEMBER(int, pfnPCIDevPhysWrite,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite)); + + /** + * Set the IRQ for a PCI device. + * + * @param pDevIns Device instance. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @thread Any thread, but will involve the emulation thread. + */ + DECLRCCALLBACKMEMBER(void, pfnPCISetIrq,(PPDMDEVINS pDevIns, int iIrq, int iLevel)); + + /** + * Set ISA IRQ for a device. + * + * @param pDevIns Device instance. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @thread Any thread, but will involve the emulation thread. + */ + DECLRCCALLBACKMEMBER(void, pfnISASetIrq,(PPDMDEVINS pDevIns, int iIrq, int iLevel)); + + /** + * Read physical memory. + * + * @returns VINF_SUCCESS (for now). + * @param pDevIns Device instance. + * @param GCPhys Physical address start reading from. + * @param pvBuf Where to put the read bits. + * @param cbRead How many bytes to read. + */ + DECLRCCALLBACKMEMBER(int, pfnPhysRead,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead)); + + /** + * Write to physical memory. + * + * @returns VINF_SUCCESS for now, and later maybe VERR_EM_MEMORY. + * @param pDevIns Device instance. + * @param GCPhys Physical address to write to. + * @param pvBuf What to write. + * @param cbWrite How many bytes to write. + */ + DECLRCCALLBACKMEMBER(int, pfnPhysWrite,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite)); + + /** + * Checks if the Gate A20 is enabled or not. + * + * @returns true if A20 is enabled. + * @returns false if A20 is disabled. + * @param pDevIns Device instance. + * @thread The emulation thread. + */ + DECLRCCALLBACKMEMBER(bool, pfnA20IsEnabled,(PPDMDEVINS pDevIns)); + + /** + * Gets the VM state. + * + * @returns VM state. + * @param pDevIns The device instance. + * @thread Any thread (just keep in mind that it's volatile info). + */ + DECLRCCALLBACKMEMBER(VMSTATE, pfnVMState, (PPDMDEVINS pDevIns)); + + /** + * Set the VM error message + * + * @returns rc. + * @param pDrvIns Driver instance. + * @param rc VBox status code. + * @param RT_SRC_POS_DECL Use RT_SRC_POS. + * @param pszFormat Error message format string. + * @param ... Error message arguments. + */ + DECLRCCALLBACKMEMBER(int, pfnVMSetError,(PPDMDEVINS pDevIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...)); + + /** + * Set the VM error message + * + * @returns rc. + * @param pDrvIns Driver instance. + * @param rc VBox status code. + * @param RT_SRC_POS_DECL Use RT_SRC_POS. + * @param pszFormat Error message format string. + * @param va Error message arguments. + */ + DECLRCCALLBACKMEMBER(int, pfnVMSetErrorV,(PPDMDEVINS pDevIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va)); + + /** + * Set the VM runtime error message + * + * @returns VBox status code. + * @param pDevIns Device instance. + * @param fFlags The action flags. See VMSETRTERR_FLAGS_*. + * @param pszErrorId Error ID string. + * @param pszFormat Error message format string. + * @param ... Error message arguments. + */ + DECLRCCALLBACKMEMBER(int, pfnVMSetRuntimeError,(PPDMDEVINS pDevIns, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...)); + + /** + * Set the VM runtime error message + * + * @returns VBox status code. + * @param pDevIns Device instance. + * @param fFlags The action flags. See VMSETRTERR_FLAGS_*. + * @param pszErrorId Error ID string. + * @param pszFormat Error message format string. + * @param va Error message arguments. + */ + DECLRCCALLBACKMEMBER(int, pfnVMSetRuntimeErrorV,(PPDMDEVINS pDevIns, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, va_list va)); + + /** + * Set parameters for pending MMIO patch operation + * + * @returns VBox status code. + * @param pDevIns Device instance. + * @param GCPhys MMIO physical address + * @param pCachedData GC pointer to cached data + */ + DECLRCCALLBACKMEMBER(int, pfnPATMSetMMIOPatchInfo,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTGCPTR pCachedData)); + + /** + * Gets the VM handle. Restricted API. + * + * @returns VM Handle. + * @param pDevIns Device instance. + */ + DECLRCCALLBACKMEMBER(PVM, pfnGetVM,(PPDMDEVINS pDevIns)); + + /** + * Gets the VMCPU handle. Restricted API. + * + * @returns VMCPU Handle. + * @param pDevIns The device instance. + */ + DECLRCCALLBACKMEMBER(PVMCPU, pfnGetVMCPU,(PPDMDEVINS pDevIns)); + + /** + * Get the current virtual clock time in a VM. The clock frequency must be + * queried separately. + * + * @returns Current clock time. + * @param pDevIns The device instance. + */ + DECLRCCALLBACKMEMBER(uint64_t, pfnTMTimeVirtGet,(PPDMDEVINS pDevIns)); + + /** + * Get the frequency of the virtual clock. + * + * @returns The clock frequency (not variable at run-time). + * @param pDevIns The device instance. + */ + DECLRCCALLBACKMEMBER(uint64_t, pfnTMTimeVirtGetFreq,(PPDMDEVINS pDevIns)); + + /** + * Get the current virtual clock time in a VM, in nanoseconds. + * + * @returns Current clock time (in ns). + * @param pDevIns The device instance. + */ + DECLRCCALLBACKMEMBER(uint64_t, pfnTMTimeVirtGetNano,(PPDMDEVINS pDevIns)); + + /** + * Gets the trace buffer handle. + * + * This is used by the macros found in VBox/vmm/dbgftrace.h and is not + * really inteded for direct usage, thus no inline wrapper function. + * + * @returns Trace buffer handle or NIL_RTTRACEBUF. + * @param pDevIns The device instance. + */ + DECLRCCALLBACKMEMBER(RTTRACEBUF, pfnDBGFTraceBuf,(PPDMDEVINS pDevIns)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMDEVHLPRC; +/** Pointer PDM Device RC API. */ +typedef RCPTRTYPE(struct PDMDEVHLPRC *) PPDMDEVHLPRC; +/** Pointer PDM Device RC API. */ +typedef RCPTRTYPE(const struct PDMDEVHLPRC *) PCPDMDEVHLPRC; + +/** Current PDMDEVHLP version number. */ +#define PDM_DEVHLPRC_VERSION PDM_VERSION_MAKE(0xffe6, 3, 0) + + +/** + * PDM Device API - R0 Variant. + */ +typedef struct PDMDEVHLPR0 +{ + /** Structure version. PDM_DEVHLPR0_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Reads data via bus mastering, if enabled. If no bus mastering is available, + * this function does nothing and returns VINF_PGM_PCI_PHYS_READ_BM_DISABLED. + * + * @return IPRT status code. + */ + DECLR0CALLBACKMEMBER(int, pfnPCIPhysRead,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead)); + + /** + * Writes data via bus mastering, if enabled. If no bus mastering is available, + * this function does nothing and returns VINF_PGM_PCI_PHYS_WRITE_BM_DISABLED. + * + * @return IPRT status code. + */ + DECLR0CALLBACKMEMBER(int, pfnPCIPhysWrite,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite)); + + /** + * Set the IRQ for a PCI device. + * + * @param pDevIns Device instance. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @thread Any thread, but will involve the emulation thread. + */ + DECLR0CALLBACKMEMBER(void, pfnPCISetIrq,(PPDMDEVINS pDevIns, int iIrq, int iLevel)); + + /** + * Set ISA IRQ for a device. + * + * @param pDevIns Device instance. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @thread Any thread, but will involve the emulation thread. + */ + DECLR0CALLBACKMEMBER(void, pfnISASetIrq,(PPDMDEVINS pDevIns, int iIrq, int iLevel)); + + /** + * Read physical memory. + * + * @returns VINF_SUCCESS (for now). + * @param pDevIns Device instance. + * @param GCPhys Physical address start reading from. + * @param pvBuf Where to put the read bits. + * @param cbRead How many bytes to read. + */ + DECLR0CALLBACKMEMBER(int, pfnPhysRead,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead)); + + /** + * Write to physical memory. + * + * @returns VINF_SUCCESS for now, and later maybe VERR_EM_MEMORY. + * @param pDevIns Device instance. + * @param GCPhys Physical address to write to. + * @param pvBuf What to write. + * @param cbWrite How many bytes to write. + */ + DECLR0CALLBACKMEMBER(int, pfnPhysWrite,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite)); + + /** + * Checks if the Gate A20 is enabled or not. + * + * @returns true if A20 is enabled. + * @returns false if A20 is disabled. + * @param pDevIns Device instance. + * @thread The emulation thread. + */ + DECLR0CALLBACKMEMBER(bool, pfnA20IsEnabled,(PPDMDEVINS pDevIns)); + + /** + * Gets the VM state. + * + * @returns VM state. + * @param pDevIns The device instance. + * @thread Any thread (just keep in mind that it's volatile info). + */ + DECLR0CALLBACKMEMBER(VMSTATE, pfnVMState, (PPDMDEVINS pDevIns)); + + /** + * Set the VM error message + * + * @returns rc. + * @param pDrvIns Driver instance. + * @param rc VBox status code. + * @param RT_SRC_POS_DECL Use RT_SRC_POS. + * @param pszFormat Error message format string. + * @param ... Error message arguments. + */ + DECLR0CALLBACKMEMBER(int, pfnVMSetError,(PPDMDEVINS pDevIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...)); + + /** + * Set the VM error message + * + * @returns rc. + * @param pDrvIns Driver instance. + * @param rc VBox status code. + * @param RT_SRC_POS_DECL Use RT_SRC_POS. + * @param pszFormat Error message format string. + * @param va Error message arguments. + */ + DECLR0CALLBACKMEMBER(int, pfnVMSetErrorV,(PPDMDEVINS pDevIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va)); + + /** + * Set the VM runtime error message + * + * @returns VBox status code. + * @param pDevIns Device instance. + * @param fFlags The action flags. See VMSETRTERR_FLAGS_*. + * @param pszErrorId Error ID string. + * @param pszFormat Error message format string. + * @param ... Error message arguments. + */ + DECLR0CALLBACKMEMBER(int, pfnVMSetRuntimeError,(PPDMDEVINS pDevIns, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...)); + + /** + * Set the VM runtime error message + * + * @returns VBox status code. + * @param pDevIns Device instance. + * @param fFlags The action flags. See VMSETRTERR_FLAGS_*. + * @param pszErrorId Error ID string. + * @param pszFormat Error message format string. + * @param va Error message arguments. + */ + DECLR0CALLBACKMEMBER(int, pfnVMSetRuntimeErrorV,(PPDMDEVINS pDevIns, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, va_list va)); + + /** + * Set parameters for pending MMIO patch operation + * + * @returns rc. + * @param pDevIns Device instance. + * @param GCPhys MMIO physical address + * @param pCachedData GC pointer to cached data + */ + DECLR0CALLBACKMEMBER(int, pfnPATMSetMMIOPatchInfo,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTGCPTR pCachedData)); + + /** + * Gets the VM handle. Restricted API. + * + * @returns VM Handle. + * @param pDevIns Device instance. + */ + DECLR0CALLBACKMEMBER(PVM, pfnGetVM,(PPDMDEVINS pDevIns)); + + /** + * Checks if our current CPU state allows for IO block emulation fallback to the recompiler + * + * @returns true = yes, false = no + * @param pDevIns Device instance. + */ + DECLR0CALLBACKMEMBER(bool, pfnCanEmulateIoBlock,(PPDMDEVINS pDevIns)); + + /** + * Gets the VMCPU handle. Restricted API. + * + * @returns VMCPU Handle. + * @param pDevIns The device instance. + */ + DECLR0CALLBACKMEMBER(PVMCPU, pfnGetVMCPU,(PPDMDEVINS pDevIns)); + + /** + * Get the current virtual clock time in a VM. The clock frequency must be + * queried separately. + * + * @returns Current clock time. + * @param pDevIns The device instance. + */ + DECLR0CALLBACKMEMBER(uint64_t, pfnTMTimeVirtGet,(PPDMDEVINS pDevIns)); + + /** + * Get the frequency of the virtual clock. + * + * @returns The clock frequency (not variable at run-time). + * @param pDevIns The device instance. + */ + DECLR0CALLBACKMEMBER(uint64_t, pfnTMTimeVirtGetFreq,(PPDMDEVINS pDevIns)); + + /** + * Get the current virtual clock time in a VM, in nanoseconds. + * + * @returns Current clock time (in ns). + * @param pDevIns The device instance. + */ + DECLR0CALLBACKMEMBER(uint64_t, pfnTMTimeVirtGetNano,(PPDMDEVINS pDevIns)); + + /** + * Gets the trace buffer handle. + * + * This is used by the macros found in VBox/vmm/dbgftrace.h and is not + * really inteded for direct usage, thus no inline wrapper function. + * + * @returns Trace buffer handle or NIL_RTTRACEBUF. + * @param pDevIns The device instance. + */ + DECLR0CALLBACKMEMBER(RTTRACEBUF, pfnDBGFTraceBuf,(PPDMDEVINS pDevIns)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMDEVHLPR0; +/** Pointer PDM Device R0 API. */ +typedef R0PTRTYPE(struct PDMDEVHLPR0 *) PPDMDEVHLPR0; +/** Pointer PDM Device GC API. */ +typedef R0PTRTYPE(const struct PDMDEVHLPR0 *) PCPDMDEVHLPR0; + +/** Current PDMDEVHLP version number. */ +#define PDM_DEVHLPR0_VERSION PDM_VERSION_MAKE(0xffe5, 3, 0) + + + +/** + * PDM Device Instance. + */ +typedef struct PDMDEVINS +{ + /** Structure version. PDM_DEVINS_VERSION defines the current version. */ + uint32_t u32Version; + /** Device instance number. */ + uint32_t iInstance; + + /** Pointer the GC PDM Device API. */ + PCPDMDEVHLPRC pHlpRC; + /** Pointer to device instance data. */ + RTRCPTR pvInstanceDataRC; + /** The critical section for the device, see pCritSectXR3. */ + RCPTRTYPE(PPDMCRITSECT) pCritSectRoRC; + /** Alignment padding. */ + RTRCPTR pAlignmentRC; + + /** Pointer the R0 PDM Device API. */ + PCPDMDEVHLPR0 pHlpR0; + /** Pointer to device instance data (R0). */ + RTR0PTR pvInstanceDataR0; + /** The critical section for the device, see pCritSectXR3. */ + R0PTRTYPE(PPDMCRITSECT) pCritSectRoR0; + + /** Pointer the HC PDM Device API. */ + PCPDMDEVHLPR3 pHlpR3; + /** Pointer to device instance data. */ + RTR3PTR pvInstanceDataR3; + /** The critical section for the device. + * + * TM and IOM will enter this critical section before calling into the device + * code. PDM will when doing power on, power off, reset, suspend and resume + * notifications. SSM will currently not, but this will be changed later on. + * + * The device gets a critical section automatically assigned to it before + * the constructor is called. If the constructor wishes to use a different + * critical section, it calls PDMDevHlpSetDeviceCritSect() to change it + * very early on. + */ + R3PTRTYPE(PPDMCRITSECT) pCritSectRoR3; + + /** Pointer to device registration structure. */ + R3PTRTYPE(PCPDMDEVREG) pReg; + /** Configuration handle. */ + R3PTRTYPE(PCFGMNODE) pCfg; + + /** The base interface of the device. + * + * The device constructor initializes this if it has any + * device level interfaces to export. To obtain this interface + * call PDMR3QueryDevice(). */ + PDMIBASE IBase; + + /** Tracing indicator. */ + uint32_t fTracing; + /** The tracing ID of this device. */ + uint32_t idTracing; +#if HC_ARCH_BITS == 32 + /** Align the internal data more naturally. */ + uint32_t au32Padding[HC_ARCH_BITS == 32 ? 13 : 0]; +#endif + + /** Internal data. */ + union + { +#ifdef PDMDEVINSINT_DECLARED + PDMDEVINSINT s; +#endif + uint8_t padding[HC_ARCH_BITS == 32 ? 72 : 112 + 0x28]; + } Internal; + + /** Device instance data. The size of this area is defined + * in the PDMDEVREG::cbInstanceData field. */ + char achInstanceData[8]; +} PDMDEVINS; + +/** Current PDMDEVINS version number. */ +#define PDM_DEVINS_VERSION PDM_VERSION_MAKE(0xffe4, 3, 0) + +/** Converts a pointer to the PDMDEVINS::IBase to a pointer to PDMDEVINS. */ +#define PDMIBASE_2_PDMDEV(pInterface) ( (PPDMDEVINS)((char *)(pInterface) - RT_OFFSETOF(PDMDEVINS, IBase)) ) + +/** + * Checks the structure versions of the device instance and device helpers, + * returning if they are incompatible. + * + * This is for use in the constructor. + * + * @param pDevIns The device instance pointer. + */ +#define PDMDEV_CHECK_VERSIONS_RETURN(pDevIns) \ + do \ + { \ + PPDMDEVINS pDevInsTypeCheck = (pDevIns); NOREF(pDevInsTypeCheck); \ + AssertLogRelMsgReturn(PDM_VERSION_ARE_COMPATIBLE((pDevIns)->u32Version, PDM_DEVINS_VERSION), \ + ("DevIns=%#x mine=%#x\n", (pDevIns)->u32Version, PDM_DEVINS_VERSION), \ + VERR_PDM_DEVINS_VERSION_MISMATCH); \ + AssertLogRelMsgReturn(PDM_VERSION_ARE_COMPATIBLE((pDevIns)->pHlpR3->u32Version, PDM_DEVHLPR3_VERSION), \ + ("DevHlp=%#x mine=%#x\n", (pDevIns)->pHlpR3->u32Version, PDM_DEVHLPR3_VERSION), \ + VERR_PDM_DEVHLPR3_VERSION_MISMATCH); \ + } while (0) + +/** + * Quietly checks the structure versions of the device instance and device + * helpers, returning if they are incompatible. + * + * This is for use in the destructor. + * + * @param pDevIns The device instance pointer. + */ +#define PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns) \ + do \ + { \ + PPDMDEVINS pDevInsTypeCheck = (pDevIns); NOREF(pDevInsTypeCheck); \ + if (RT_UNLIKELY(!PDM_VERSION_ARE_COMPATIBLE((pDevIns)->u32Version, PDM_DEVINS_VERSION) )) \ + return VERR_PDM_DEVINS_VERSION_MISMATCH; \ + if (RT_UNLIKELY(!PDM_VERSION_ARE_COMPATIBLE((pDevIns)->pHlpR3->u32Version, PDM_DEVHLPR3_VERSION) )) \ + return VERR_PDM_DEVHLPR3_VERSION_MISMATCH; \ + } while (0) + +/** + * Wrapper around CFGMR3ValidateConfig for the root config for use in the + * constructor - returns on failure. + * + * This should be invoked after having initialized the instance data + * sufficiently for the correct operation of the destructor. The destructor is + * always called! + * + * @param pDevIns Pointer to the PDM device instance. + * @param pszValidValues Patterns describing the valid value names. See + * RTStrSimplePatternMultiMatch for details on the + * pattern syntax. + * @param pszValidNodes Patterns describing the valid node (key) names. + * Pass empty string if no valid nodes. + */ +#define PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, pszValidValues, pszValidNodes) \ + do \ + { \ + int rcValCfg = CFGMR3ValidateConfig((pDevIns)->pCfg, "/", pszValidValues, pszValidNodes, \ + (pDevIns)->pReg->szName, (pDevIns)->iInstance); \ + if (RT_FAILURE(rcValCfg)) \ + return rcValCfg; \ + } while (0) + +/** @def PDMDEV_ASSERT_EMT + * Assert that the current thread is the emulation thread. + */ +#ifdef VBOX_STRICT +# define PDMDEV_ASSERT_EMT(pDevIns) pDevIns->pHlpR3->pfnAssertEMT(pDevIns, __FILE__, __LINE__, __FUNCTION__) +#else +# define PDMDEV_ASSERT_EMT(pDevIns) do { } while (0) +#endif + +/** @def PDMDEV_ASSERT_OTHER + * Assert that the current thread is NOT the emulation thread. + */ +#ifdef VBOX_STRICT +# define PDMDEV_ASSERT_OTHER(pDevIns) pDevIns->pHlpR3->pfnAssertOther(pDevIns, __FILE__, __LINE__, __FUNCTION__) +#else +# define PDMDEV_ASSERT_OTHER(pDevIns) do { } while (0) +#endif + +/** @def PDMDEV_ASSERT_VMLOCK_OWNER + * Assert that the current thread is owner of the VM lock. + */ +#ifdef VBOX_STRICT +# define PDMDEV_ASSERT_VMLOCK_OWNER(pDevIns) pDevIns->pHlpR3->pfnAssertVMLock(pDevIns, __FILE__, __LINE__, __FUNCTION__) +#else +# define PDMDEV_ASSERT_VMLOCK_OWNER(pDevIns) do { } while (0) +#endif + +/** @def PDMDEV_SET_ERROR + * Set the VM error. See PDMDevHlpVMSetError() for printf like message formatting. + */ +#define PDMDEV_SET_ERROR(pDevIns, rc, pszError) \ + PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, "%s", pszError) + +/** @def PDMDEV_SET_RUNTIME_ERROR + * Set the VM runtime error. See PDMDevHlpVMSetRuntimeError() for printf like message formatting. + */ +#define PDMDEV_SET_RUNTIME_ERROR(pDevIns, fFlags, pszErrorId, pszError) \ + PDMDevHlpVMSetRuntimeError(pDevIns, fFlags, pszErrorId, "%s", pszError) + +/** @def PDMDEVINS_2_RCPTR + * Converts a PDM Device instance pointer a RC PDM Device instance pointer. + */ +#define PDMDEVINS_2_RCPTR(pDevIns) ( (RCPTRTYPE(PPDMDEVINS))((RTGCUINTPTR)(pDevIns)->pvInstanceDataRC - RT_OFFSETOF(PDMDEVINS, achInstanceData)) ) + +/** @def PDMDEVINS_2_R3PTR + * Converts a PDM Device instance pointer a R3 PDM Device instance pointer. + */ +#define PDMDEVINS_2_R3PTR(pDevIns) ( (R3PTRTYPE(PPDMDEVINS))((RTHCUINTPTR)(pDevIns)->pvInstanceDataR3 - RT_OFFSETOF(PDMDEVINS, achInstanceData)) ) + +/** @def PDMDEVINS_2_R0PTR + * Converts a PDM Device instance pointer a R0 PDM Device instance pointer. + */ +#define PDMDEVINS_2_R0PTR(pDevIns) ( (R0PTRTYPE(PPDMDEVINS))((RTR0UINTPTR)(pDevIns)->pvInstanceDataR0 - RT_OFFSETOF(PDMDEVINS, achInstanceData)) ) + + +#ifdef IN_RING3 + +/** + * @copydoc PDMDEVHLPR3::pfnIOPortRegister + */ +DECLINLINE(int) PDMDevHlpIOPortRegister(PPDMDEVINS pDevIns, RTIOPORT Port, RTIOPORT cPorts, RTHCPTR pvUser, + PFNIOMIOPORTOUT pfnOut, PFNIOMIOPORTIN pfnIn, + PFNIOMIOPORTOUTSTRING pfnOutStr, PFNIOMIOPORTINSTRING pfnInStr, const char *pszDesc) +{ + return pDevIns->pHlpR3->pfnIOPortRegister(pDevIns, Port, cPorts, pvUser, pfnOut, pfnIn, pfnOutStr, pfnInStr, pszDesc); +} + +/** + * @copydoc PDMDEVHLPR3::pfnIOPortRegisterRC + */ +DECLINLINE(int) PDMDevHlpIOPortRegisterRC(PPDMDEVINS pDevIns, RTIOPORT Port, RTIOPORT cPorts, RTRCPTR pvUser, + const char *pszOut, const char *pszIn, const char *pszOutStr, + const char *pszInStr, const char *pszDesc) +{ + return pDevIns->pHlpR3->pfnIOPortRegisterRC(pDevIns, Port, cPorts, pvUser, pszOut, pszIn, pszOutStr, pszInStr, pszDesc); +} + +/** + * @copydoc PDMDEVHLPR3::pfnIOPortRegisterR0 + */ +DECLINLINE(int) PDMDevHlpIOPortRegisterR0(PPDMDEVINS pDevIns, RTIOPORT Port, RTIOPORT cPorts, RTR0PTR pvUser, + const char *pszOut, const char *pszIn, const char *pszOutStr, + const char *pszInStr, const char *pszDesc) +{ + return pDevIns->pHlpR3->pfnIOPortRegisterR0(pDevIns, Port, cPorts, pvUser, pszOut, pszIn, pszOutStr, pszInStr, pszDesc); +} + +/** + * @copydoc PDMDEVHLPR3::pfnIOPortDeregister + */ +DECLINLINE(int) PDMDevHlpIOPortDeregister(PPDMDEVINS pDevIns, RTIOPORT Port, RTIOPORT cPorts) +{ + return pDevIns->pHlpR3->pfnIOPortDeregister(pDevIns, Port, cPorts); +} + +/** + * Register a Memory Mapped I/O (MMIO) region. + * + * These callbacks are of course for the ring-3 context (R3). Register HC + * handlers before raw-mode context (RC) and ring-0 context (R0) handlers! There + * must be a R3 handler for every RC and R0 handler! + * + * @returns VBox status. + * @param pDevIns The device instance to register the MMIO with. + * @param GCPhysStart First physical address in the range. + * @param cbRange The size of the range (in bytes). + * @param pvUser User argument. + * @param fFlags Flags, IOMMMIO_FLAGS_XXX. + * @param pfnWrite Pointer to function which is gonna handle Write operations. + * @param pfnRead Pointer to function which is gonna handle Read operations. + * @param pszDesc Pointer to description string. This must not be freed. + */ +DECLINLINE(int) PDMDevHlpMMIORegister(PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, uint32_t cbRange, RTHCPTR pvUser, + uint32_t fFlags, PFNIOMMMIOWRITE pfnWrite, PFNIOMMMIOREAD pfnRead, const char *pszDesc) +{ + return pDevIns->pHlpR3->pfnMMIORegister(pDevIns, GCPhysStart, cbRange, pvUser, pfnWrite, pfnRead, NULL /*pfnFill*/, + fFlags, pszDesc); +} + +/** + * Register a Memory Mapped I/O (MMIO) region for GC. + * + * These callbacks are for the raw-mode context (RC). Register ring-3 context + * (R3) handlers before guest context handlers! There must be a R3 handler for + * every RC handler! + * + * @returns VBox status. + * @param pDevIns The device instance to register the MMIO with. + * @param GCPhysStart First physical address in the range. + * @param cbRange The size of the range (in bytes). + * @param pvUser User argument. + * @param pszWrite Name of the RC function which is gonna handle Write operations. + * @param pszRead Name of the RC function which is gonna handle Read operations. + */ +DECLINLINE(int) PDMDevHlpMMIORegisterRC(PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, uint32_t cbRange, RTRCPTR pvUser, + const char *pszWrite, const char *pszRead) +{ + return pDevIns->pHlpR3->pfnMMIORegisterRC(pDevIns, GCPhysStart, cbRange, pvUser, pszWrite, pszRead, NULL /*pszFill*/); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMMIORegisterR0 + */ +DECLINLINE(int) PDMDevHlpMMIORegisterR0(PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, uint32_t cbRange, RTR0PTR pvUser, + const char *pszWrite, const char *pszRead) +{ + return pDevIns->pHlpR3->pfnMMIORegisterR0(pDevIns, GCPhysStart, cbRange, pvUser, pszWrite, pszRead, NULL /*pszFill*/); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMMIORegister + */ +DECLINLINE(int) PDMDevHlpMMIORegisterEx(PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, uint32_t cbRange, RTHCPTR pvUser, + uint32_t fFlags, PFNIOMMMIOWRITE pfnWrite, PFNIOMMMIOREAD pfnRead, + PFNIOMMMIOFILL pfnFill, const char *pszDesc) +{ + return pDevIns->pHlpR3->pfnMMIORegister(pDevIns, GCPhysStart, cbRange, pvUser, pfnWrite, pfnRead, pfnFill, + fFlags, pszDesc); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMMIORegisterRC + */ +DECLINLINE(int) PDMDevHlpMMIORegisterRCEx(PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, uint32_t cbRange, RTRCPTR pvUser, + const char *pszWrite, const char *pszRead, const char *pszFill) +{ + return pDevIns->pHlpR3->pfnMMIORegisterRC(pDevIns, GCPhysStart, cbRange, pvUser, pszWrite, pszRead, pszFill); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMMIORegisterR0 + */ +DECLINLINE(int) PDMDevHlpMMIORegisterR0Ex(PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, uint32_t cbRange, RTR0PTR pvUser, + const char *pszWrite, const char *pszRead, const char *pszFill) +{ + return pDevIns->pHlpR3->pfnMMIORegisterR0(pDevIns, GCPhysStart, cbRange, pvUser, pszWrite, pszRead, pszFill); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMMIODeregister + */ +DECLINLINE(int) PDMDevHlpMMIODeregister(PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, uint32_t cbRange) +{ + return pDevIns->pHlpR3->pfnMMIODeregister(pDevIns, GCPhysStart, cbRange); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMMIO2Register + */ +DECLINLINE(int) PDMDevHlpMMIO2Register(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS cb, uint32_t fFlags, void **ppv, const char *pszDesc) +{ + return pDevIns->pHlpR3->pfnMMIO2Register(pDevIns, iRegion, cb, fFlags, ppv, pszDesc); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMMIO2Deregister + */ +DECLINLINE(int) PDMDevHlpMMIO2Deregister(PPDMDEVINS pDevIns, uint32_t iRegion) +{ + return pDevIns->pHlpR3->pfnMMIO2Deregister(pDevIns, iRegion); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMMIO2Map + */ +DECLINLINE(int) PDMDevHlpMMIO2Map(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS GCPhys) +{ + return pDevIns->pHlpR3->pfnMMIO2Map(pDevIns, iRegion, GCPhys); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMMIO2Unmap + */ +DECLINLINE(int) PDMDevHlpMMIO2Unmap(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS GCPhys) +{ + return pDevIns->pHlpR3->pfnMMIO2Unmap(pDevIns, iRegion, GCPhys); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMMHyperMapMMIO2 + */ +DECLINLINE(int) PDMDevHlpMMHyperMapMMIO2(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS off, RTGCPHYS cb, + const char *pszDesc, PRTRCPTR pRCPtr) +{ + return pDevIns->pHlpR3->pfnMMHyperMapMMIO2(pDevIns, iRegion, off, cb, pszDesc, pRCPtr); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMMIO2MapKernel + */ +DECLINLINE(int) PDMDevHlpMMIO2MapKernel(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS off, RTGCPHYS cb, + const char *pszDesc, PRTR0PTR pR0Ptr) +{ + return pDevIns->pHlpR3->pfnMMIO2MapKernel(pDevIns, iRegion, off, cb, pszDesc, pR0Ptr); +} + +/** + * @copydoc PDMDEVHLPR3::pfnROMRegister + */ +DECLINLINE(int) PDMDevHlpROMRegister(PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, uint32_t cbRange, + const void *pvBinary, uint32_t cbBinary, uint32_t fFlags, const char *pszDesc) +{ + return pDevIns->pHlpR3->pfnROMRegister(pDevIns, GCPhysStart, cbRange, pvBinary, cbBinary, fFlags, pszDesc); +} + +/** + * @copydoc PDMDEVHLPR3::pfnROMProtectShadow + */ +DECLINLINE(int) PDMDevHlpROMProtectShadow(PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, uint32_t cbRange, PGMROMPROT enmProt) +{ + return pDevIns->pHlpR3->pfnROMProtectShadow(pDevIns, GCPhysStart, cbRange, enmProt); +} + +/** + * Register a save state data unit. + * + * @returns VBox status. + * @param pDevIns The device instance. + * @param uVersion Data layout version number. + * @param cbGuess The approximate amount of data in the unit. + * Only for progress indicators. + * @param pfnSaveExec Execute save callback, optional. + * @param pfnLoadExec Execute load callback, optional. + */ +DECLINLINE(int) PDMDevHlpSSMRegister(PPDMDEVINS pDevIns, uint32_t uVersion, size_t cbGuess, + PFNSSMDEVSAVEEXEC pfnSaveExec, PFNSSMDEVLOADEXEC pfnLoadExec) +{ + return pDevIns->pHlpR3->pfnSSMRegister(pDevIns, uVersion, cbGuess, NULL /*pszBefore*/, + NULL /*pfnLivePrep*/, NULL /*pfnLiveExec*/, NULL /*pfnLiveDone*/, + NULL /*pfnSavePrep*/, pfnSaveExec, NULL /*pfnSaveDone*/, + NULL /*pfnLoadPrep*/, pfnLoadExec, NULL /*pfnLoadDone*/); +} + +/** + * Register a save state data unit with a live save callback as well. + * + * @returns VBox status. + * @param pDevIns The device instance. + * @param uVersion Data layout version number. + * @param cbGuess The approximate amount of data in the unit. + * Only for progress indicators. + * @param pfnLiveExec Execute live callback, optional. + * @param pfnSaveExec Execute save callback, optional. + * @param pfnLoadExec Execute load callback, optional. + */ +DECLINLINE(int) PDMDevHlpSSMRegister3(PPDMDEVINS pDevIns, uint32_t uVersion, size_t cbGuess, + FNSSMDEVLIVEEXEC pfnLiveExec, PFNSSMDEVSAVEEXEC pfnSaveExec, PFNSSMDEVLOADEXEC pfnLoadExec) +{ + return pDevIns->pHlpR3->pfnSSMRegister(pDevIns, uVersion, cbGuess, NULL /*pszBefore*/, + NULL /*pfnLivePrep*/, pfnLiveExec, NULL /*pfnLiveDone*/, + NULL /*pfnSavePrep*/, pfnSaveExec, NULL /*pfnSaveDone*/, + NULL /*pfnLoadPrep*/, pfnLoadExec, NULL /*pfnLoadDone*/); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSSMRegister + */ +DECLINLINE(int) PDMDevHlpSSMRegisterEx(PPDMDEVINS pDevIns, uint32_t uVersion, size_t cbGuess, const char *pszBefore, + PFNSSMDEVLIVEPREP pfnLivePrep, PFNSSMDEVLIVEEXEC pfnLiveExec, PFNSSMDEVLIVEVOTE pfnLiveVote, + PFNSSMDEVSAVEPREP pfnSavePrep, PFNSSMDEVSAVEEXEC pfnSaveExec, PFNSSMDEVSAVEDONE pfnSaveDone, + PFNSSMDEVLOADPREP pfnLoadPrep, PFNSSMDEVLOADEXEC pfnLoadExec, PFNSSMDEVLOADDONE pfnLoadDone) +{ + return pDevIns->pHlpR3->pfnSSMRegister(pDevIns, uVersion, cbGuess, pszBefore, + pfnLivePrep, pfnLiveExec, pfnLiveVote, + pfnSavePrep, pfnSaveExec, pfnSaveDone, + pfnLoadPrep, pfnLoadExec, pfnLoadDone); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTMTimerCreate + */ +DECLINLINE(int) PDMDevHlpTMTimerCreate(PPDMDEVINS pDevIns, TMCLOCK enmClock, PFNTMTIMERDEV pfnCallback, void *pvUser, uint32_t fFlags, + const char *pszDesc, PPTMTIMERR3 ppTimer) +{ + return pDevIns->pHlpR3->pfnTMTimerCreate(pDevIns, enmClock, pfnCallback, pvUser, fFlags, pszDesc, ppTimer); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTMUtcNow + */ +DECLINLINE(PRTTIMESPEC) PDMDevHlpTMUtcNow(PPDMDEVINS pDevIns, PRTTIMESPEC pTime) +{ + return pDevIns->pHlpR3->pfnTMUtcNow(pDevIns, pTime); +} + +#endif /* IN_RING3 */ + +/** + * @copydoc PDMDEVHLPR3::pfnPhysRead + */ +DECLINLINE(int) PDMDevHlpPhysRead(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPhysRead(pDevIns, GCPhys, pvBuf, cbRead); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPhysWrite + */ +DECLINLINE(int) PDMDevHlpPhysWrite(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPhysWrite(pDevIns, GCPhys, pvBuf, cbWrite); +} + +#ifdef IN_RING3 + +/** + * @copydoc PDMDEVHLPR3::pfnPhysGCPhys2CCPtr + */ +DECLINLINE(int) PDMDevHlpPhysGCPhys2CCPtr(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, uint32_t fFlags, void **ppv, PPGMPAGEMAPLOCK pLock) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPhysGCPhys2CCPtr(pDevIns, GCPhys, fFlags, ppv, pLock); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPhysGCPhys2CCPtrReadOnly + */ +DECLINLINE(int) PDMDevHlpPhysGCPhys2CCPtrReadOnly(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, uint32_t fFlags, void const **ppv, PPGMPAGEMAPLOCK pLock) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPhysGCPhys2CCPtrReadOnly(pDevIns, GCPhys, fFlags, ppv, pLock); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPhysReleasePageMappingLock + */ +DECLINLINE(void) PDMDevHlpPhysReleasePageMappingLock(PPDMDEVINS pDevIns, PPGMPAGEMAPLOCK pLock) +{ + pDevIns->CTX_SUFF(pHlp)->pfnPhysReleasePageMappingLock(pDevIns, pLock); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPhysReadGCVirt + */ +DECLINLINE(int) PDMDevHlpPhysReadGCVirt(PPDMDEVINS pDevIns, void *pvDst, RTGCPTR GCVirtSrc, size_t cb) +{ + return pDevIns->pHlpR3->pfnPhysReadGCVirt(pDevIns, pvDst, GCVirtSrc, cb); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPhysWriteGCVirt + */ +DECLINLINE(int) PDMDevHlpPhysWriteGCVirt(PPDMDEVINS pDevIns, RTGCPTR GCVirtDst, const void *pvSrc, size_t cb) +{ + return pDevIns->pHlpR3->pfnPhysWriteGCVirt(pDevIns, GCVirtDst, pvSrc, cb); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPhysGCPtr2GCPhys + */ +DECLINLINE(int) PDMDevHlpPhysGCPtr2GCPhys(PPDMDEVINS pDevIns, RTGCPTR GCPtr, PRTGCPHYS pGCPhys) +{ + return pDevIns->pHlpR3->pfnPhysGCPtr2GCPhys(pDevIns, GCPtr, pGCPhys); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMMHeapAlloc + */ +DECLINLINE(void *) PDMDevHlpMMHeapAlloc(PPDMDEVINS pDevIns, size_t cb) +{ + return pDevIns->pHlpR3->pfnMMHeapAlloc(pDevIns, cb); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMMHeapAllocZ + */ +DECLINLINE(void *) PDMDevHlpMMHeapAllocZ(PPDMDEVINS pDevIns, size_t cb) +{ + return pDevIns->pHlpR3->pfnMMHeapAllocZ(pDevIns, cb); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMMHeapFree + */ +DECLINLINE(void) PDMDevHlpMMHeapFree(PPDMDEVINS pDevIns, void *pv) +{ + pDevIns->pHlpR3->pfnMMHeapFree(pDevIns, pv); +} +#endif /* IN_RING3 */ + +/** + * @copydoc PDMDEVHLPR3::pfnVMState + */ +DECLINLINE(VMSTATE) PDMDevHlpVMState(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnVMState(pDevIns); +} + +#ifdef IN_RING3 +/** + * @copydoc PDMDEVHLPR3::pfnVMTeleportedAndNotFullyResumedYet + */ +DECLINLINE(bool) PDMDevHlpVMTeleportedAndNotFullyResumedYet(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnVMTeleportedAndNotFullyResumedYet(pDevIns); +} +#endif /* IN_RING3 */ + +/** + * @copydoc PDMDEVHLPR3::pfnVMSetError + */ +DECLINLINE(int) PDMDevHlpVMSetError(PPDMDEVINS pDevIns, const int rc, RT_SRC_POS_DECL, const char *pszFormat, ...) +{ + va_list va; + va_start(va, pszFormat); + pDevIns->CTX_SUFF(pHlp)->pfnVMSetErrorV(pDevIns, rc, RT_SRC_POS_ARGS, pszFormat, va); + va_end(va); + return rc; +} + +/** + * @copydoc PDMDEVHLPR3::pfnVMSetRuntimeError + */ +DECLINLINE(int) PDMDevHlpVMSetRuntimeError(PPDMDEVINS pDevIns, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...) +{ + va_list va; + int rc; + va_start(va, pszFormat); + rc = pDevIns->CTX_SUFF(pHlp)->pfnVMSetRuntimeErrorV(pDevIns, fFlags, pszErrorId, pszFormat, va); + va_end(va); + return rc; +} + +/** + * VBOX_STRICT wrapper for pHlp->pfnDBGFStopV. + * + * @returns VBox status code which must be passed up to the VMM. This will be + * VINF_SUCCESS in non-strict builds. + * @param pDevIns The device instance. + * @param RT_SRC_POS_DECL Use RT_SRC_POS. + * @param pszFormat Message. (optional) + * @param ... Message parameters. + */ +DECLINLINE(int) PDMDevHlpDBGFStop(PPDMDEVINS pDevIns, RT_SRC_POS_DECL, const char *pszFormat, ...) +{ +#ifdef VBOX_STRICT +# ifdef IN_RING3 + int rc; + va_list args; + va_start(args, pszFormat); + rc = pDevIns->pHlpR3->pfnDBGFStopV(pDevIns, RT_SRC_POS_ARGS, pszFormat, args); + va_end(args); + return rc; +# else + NOREF(pDevIns); + NOREF(pszFile); + NOREF(iLine); + NOREF(pszFunction); + NOREF(pszFormat); + return VINF_EM_DBG_STOP; +# endif +#else + NOREF(pDevIns); + NOREF(pszFile); + NOREF(iLine); + NOREF(pszFunction); + NOREF(pszFormat); + return VINF_SUCCESS; +#endif +} + +#ifdef IN_RING3 + +/** + * @copydoc PDMDEVHLPR3::pfnDBGFInfoRegister + */ +DECLINLINE(int) PDMDevHlpDBGFInfoRegister(PPDMDEVINS pDevIns, const char *pszName, const char *pszDesc, PFNDBGFHANDLERDEV pfnHandler) +{ + return pDevIns->pHlpR3->pfnDBGFInfoRegister(pDevIns, pszName, pszDesc, pfnHandler); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSTAMRegister + */ +DECLINLINE(void) PDMDevHlpSTAMRegister(PPDMDEVINS pDevIns, void *pvSample, STAMTYPE enmType, const char *pszName, STAMUNIT enmUnit, const char *pszDesc) +{ + pDevIns->pHlpR3->pfnSTAMRegister(pDevIns, pvSample, enmType, pszName, enmUnit, pszDesc); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSTAMRegisterF + */ +DECLINLINE(void) PDMDevHlpSTAMRegisterF(PPDMDEVINS pDevIns, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, + const char *pszDesc, const char *pszName, ...) +{ + va_list va; + va_start(va, pszName); + pDevIns->pHlpR3->pfnSTAMRegisterV(pDevIns, pvSample, enmType, enmVisibility, enmUnit, pszDesc, pszName, va); + va_end(va); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPCIRegister + */ +DECLINLINE(int) PDMDevHlpPCIRegister(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev) +{ + return pDevIns->pHlpR3->pfnPCIRegister(pDevIns, pPciDev); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPCIIORegionRegister + */ +DECLINLINE(int) PDMDevHlpPCIIORegionRegister(PPDMDEVINS pDevIns, int iRegion, uint32_t cbRegion, PCIADDRESSSPACE enmType, PFNPCIIOREGIONMAP pfnCallback) +{ + return pDevIns->pHlpR3->pfnPCIIORegionRegister(pDevIns, iRegion, cbRegion, enmType, pfnCallback); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPCIRegisterMsi + */ +DECLINLINE(int) PDMDevHlpPCIRegisterMsi(PPDMDEVINS pDevIns, PPDMMSIREG pMsiReg) +{ + return pDevIns->pHlpR3->pfnPCIRegisterMsi(pDevIns, pMsiReg); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPCISetConfigCallbacks + */ +DECLINLINE(void) PDMDevHlpPCISetConfigCallbacks(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, PFNPCICONFIGREAD pfnRead, PPFNPCICONFIGREAD ppfnReadOld, + PFNPCICONFIGWRITE pfnWrite, PPFNPCICONFIGWRITE ppfnWriteOld) +{ + pDevIns->pHlpR3->pfnPCISetConfigCallbacks(pDevIns, pPciDev, pfnRead, ppfnReadOld, pfnWrite, ppfnWriteOld); +} + +/** + * Reads data via bus mastering, if enabled. If no bus mastering is available, + * this function does nothing and returns VINF_PGM_PCI_PHYS_READ_BM_DISABLED. + * + * @return IPRT status code. + */ +DECLINLINE(int) PDMDevHlpPCIDevPhysRead(PPCIDEVICE pPciDev, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead) +{ + AssertPtrReturn(pPciDev, VERR_INVALID_POINTER); + AssertPtrReturn(pvBuf, VERR_INVALID_POINTER); + AssertReturn(cbRead, VERR_INVALID_PARAMETER); + + if (!PCIDevIsBusmaster(pPciDev)) + { +#ifdef DEBUG + Log2(("%s: %RU16:%RU16: No bus master (anymore), skipping read %p (%z)\n", __FUNCTION__, + PCIDevGetVendorId(pPciDev), PCIDevGetDeviceId(pPciDev), pvBuf, cbRead)); +#endif + return VINF_PDM_PCI_PHYS_READ_BM_DISABLED; + } + + return PDMDevHlpPhysRead(pPciDev->pDevIns, GCPhys, pvBuf, cbRead); +} + +/** + * Writes data via bus mastering, if enabled. If no bus mastering is available, + * this function does nothing and returns VINF_PGM_PCI_PHYS_WRITE_BM_DISABLED. + * + * @return IPRT status code. + */ +DECLINLINE(int) PDMDevHlpPCIDevPhysWrite(PPCIDEVICE pPciDev, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite) +{ + AssertPtrReturn(pPciDev, VERR_INVALID_POINTER); + AssertPtrReturn(pvBuf, VERR_INVALID_POINTER); + AssertReturn(cbWrite, VERR_INVALID_PARAMETER); + + if (!PCIDevIsBusmaster(pPciDev)) + { +#ifdef DEBUG + Log2(("%s: %RU16:%RU16: No bus master (anymore), skipping write %p (%z)\n", __FUNCTION__, + PCIDevGetVendorId(pPciDev), PCIDevGetDeviceId(pPciDev), pvBuf, cbWrite)); +#endif + return VINF_PDM_PCI_PHYS_WRITE_BM_DISABLED; + } + + return PDMDevHlpPhysWrite(pPciDev->pDevIns, GCPhys, pvBuf, cbWrite); +} + +#endif /* IN_RING3 */ + +/** + * @copydoc PDMDEVHLPR3::pfnPCISetIrq + */ +DECLINLINE(void) PDMDevHlpPCISetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel) +{ + pDevIns->CTX_SUFF(pHlp)->pfnPCISetIrq(pDevIns, iIrq, iLevel); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPCISetIrqNoWait + */ +DECLINLINE(void) PDMDevHlpPCISetIrqNoWait(PPDMDEVINS pDevIns, int iIrq, int iLevel) +{ + pDevIns->CTX_SUFF(pHlp)->pfnPCISetIrq(pDevIns, iIrq, iLevel); +} + +/** + * @copydoc PDMDEVHLPR3::pfnISASetIrq + */ +DECLINLINE(void) PDMDevHlpISASetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel) +{ + pDevIns->CTX_SUFF(pHlp)->pfnISASetIrq(pDevIns, iIrq, iLevel); +} + +/** + * @copydoc PDMDEVHLPR3::pfnISASetIrqNoWait + */ +DECLINLINE(void) PDMDevHlpISASetIrqNoWait(PPDMDEVINS pDevIns, int iIrq, int iLevel) +{ + pDevIns->CTX_SUFF(pHlp)->pfnISASetIrq(pDevIns, iIrq, iLevel); +} + +#ifdef IN_RING3 + +/** + * @copydoc PDMDEVHLPR3::pfnDriverAttach + */ +DECLINLINE(int) PDMDevHlpDriverAttach(PPDMDEVINS pDevIns, uint32_t iLun, PPDMIBASE pBaseInterface, PPDMIBASE *ppBaseInterface, const char *pszDesc) +{ + return pDevIns->pHlpR3->pfnDriverAttach(pDevIns, iLun, pBaseInterface, ppBaseInterface, pszDesc); +} + +/** + * @copydoc PDMDEVHLPR3::pfnQueueCreate + */ +DECLINLINE(int) PDMDevHlpQueueCreate(PPDMDEVINS pDevIns, size_t cbItem, uint32_t cItems, uint32_t cMilliesInterval, + PFNPDMQUEUEDEV pfnCallback, bool fRZEnabled, const char *pszName, PPDMQUEUE *ppQueue) +{ + return pDevIns->pHlpR3->pfnQueueCreate(pDevIns, cbItem, cItems, cMilliesInterval, pfnCallback, fRZEnabled, pszName, ppQueue); +} + +/** + * Initializes a PDM critical section. + * + * The PDM critical sections are derived from the IPRT critical sections, but + * works in RC and R0 as well. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pCritSect Pointer to the critical section. + * @param RT_SRC_POS_DECL Use RT_SRC_POS. + * @param pszNameFmt Format string for naming the critical section. + * For statistics and lock validation. + * @param ... Arguments for the format string. + */ +DECLINLINE(int) PDMDevHlpCritSectInit(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, RT_SRC_POS_DECL, const char *pszNameFmt, ...) +{ + int rc; + va_list va; + va_start(va, pszNameFmt); + rc = pDevIns->pHlpR3->pfnCritSectInit(pDevIns, pCritSect, RT_SRC_POS_ARGS, pszNameFmt, va); + va_end(va); + return rc; +} + +/** + * @copydoc PDMDEVHLPR3::pfnCritSectGetNop + */ +DECLINLINE(PPDMCRITSECT) PDMDevHlpCritSectGetNop(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnCritSectGetNop(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnCritSectGetNopR0 + */ +DECLINLINE(R0PTRTYPE(PPDMCRITSECT)) PDMDevHlpCritSectGetNopR0(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnCritSectGetNopR0(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnCritSectGetNopRC + */ +DECLINLINE(RCPTRTYPE(PPDMCRITSECT)) PDMDevHlpCritSectGetNopRC(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnCritSectGetNopRC(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSetDeviceCritSect + */ +DECLINLINE(int) PDMDevHlpSetDeviceCritSect(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect) +{ + return pDevIns->pHlpR3->pfnSetDeviceCritSect(pDevIns, pCritSect); +} + +/** + * @copydoc PDMDEVHLPR3::pfnThreadCreate + */ +DECLINLINE(int) PDMDevHlpThreadCreate(PPDMDEVINS pDevIns, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADDEV pfnThread, + PFNPDMTHREADWAKEUPDEV pfnWakeup, size_t cbStack, RTTHREADTYPE enmType, const char *pszName) +{ + return pDevIns->pHlpR3->pfnThreadCreate(pDevIns, ppThread, pvUser, pfnThread, pfnWakeup, cbStack, enmType, pszName); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSetAsyncNotification + */ +DECLINLINE(int) PDMDevHlpSetAsyncNotification(PPDMDEVINS pDevIns, PFNPDMDEVASYNCNOTIFY pfnAsyncNotify) +{ + return pDevIns->pHlpR3->pfnSetAsyncNotification(pDevIns, pfnAsyncNotify); +} + +/** + * @copydoc PDMDEVHLPR3::pfnAsyncNotificationCompleted + */ +DECLINLINE(void) PDMDevHlpAsyncNotificationCompleted(PPDMDEVINS pDevIns) +{ + pDevIns->pHlpR3->pfnAsyncNotificationCompleted(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnA20Set + */ +DECLINLINE(void) PDMDevHlpA20Set(PPDMDEVINS pDevIns, bool fEnable) +{ + pDevIns->pHlpR3->pfnA20Set(pDevIns, fEnable); +} + +/** + * @copydoc PDMDEVHLPR3::pfnRTCRegister + */ +DECLINLINE(int) PDMDevHlpRTCRegister(PPDMDEVINS pDevIns, PCPDMRTCREG pRtcReg, PCPDMRTCHLP *ppRtcHlp) +{ + return pDevIns->pHlpR3->pfnRTCRegister(pDevIns, pRtcReg, ppRtcHlp); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPCIBusRegister + */ +DECLINLINE(int) PDMDevHlpPCIBusRegister(PPDMDEVINS pDevIns, PPDMPCIBUSREG pPciBusReg, PCPDMPCIHLPR3 *ppPciHlpR3) +{ + return pDevIns->pHlpR3->pfnPCIBusRegister(pDevIns, pPciBusReg, ppPciHlpR3); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPICRegister + */ +DECLINLINE(int) PDMDevHlpPICRegister(PPDMDEVINS pDevIns, PPDMPICREG pPicReg, PCPDMPICHLPR3 *ppPicHlpR3) +{ + return pDevIns->pHlpR3->pfnPICRegister(pDevIns, pPicReg, ppPicHlpR3); +} + +/** + * @copydoc PDMDEVHLPR3::pfnAPICRegister + */ +DECLINLINE(int) PDMDevHlpAPICRegister(PPDMDEVINS pDevIns, PPDMAPICREG pApicReg, PCPDMAPICHLPR3 *ppApicHlpR3) +{ + return pDevIns->pHlpR3->pfnAPICRegister(pDevIns, pApicReg, ppApicHlpR3); +} + +/** + * @copydoc PDMDEVHLPR3::pfn + */ +DECLINLINE(int) PDMDevHlpIOAPICRegister(PPDMDEVINS pDevIns, PPDMIOAPICREG pIoApicReg, PCPDMIOAPICHLPR3 *ppIoApicHlpR3) +{ + return pDevIns->pHlpR3->pfnIOAPICRegister(pDevIns, pIoApicReg, ppIoApicHlpR3); +} + +/** + * @copydoc PDMDEVHLPR3::pfnHPETRegister + */ +DECLINLINE(int) PDMDevHlpHPETRegister(PPDMDEVINS pDevIns, PPDMHPETREG pHpetReg, PCPDMHPETHLPR3 *ppHpetHlpR3) +{ + return pDevIns->pHlpR3->pfnHPETRegister(pDevIns, pHpetReg, ppHpetHlpR3); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPciRawRegister + */ +DECLINLINE(int) PDMDevHlpPciRawRegister(PPDMDEVINS pDevIns, PPDMPCIRAWREG pPciRawReg, PCPDMPCIRAWHLPR3 *ppPciRawHlpR3) +{ + return pDevIns->pHlpR3->pfnPciRawRegister(pDevIns, pPciRawReg, ppPciRawHlpR3); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDMACRegister + */ +DECLINLINE(int) PDMDevHlpDMACRegister(PPDMDEVINS pDevIns, PPDMDMACREG pDmacReg, PCPDMDMACHLP *ppDmacHlp) +{ + return pDevIns->pHlpR3->pfnDMACRegister(pDevIns, pDmacReg, ppDmacHlp); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDMARegister + */ +DECLINLINE(int) PDMDevHlpDMARegister(PPDMDEVINS pDevIns, unsigned uChannel, PFNDMATRANSFERHANDLER pfnTransferHandler, void *pvUser) +{ + return pDevIns->pHlpR3->pfnDMARegister(pDevIns, uChannel, pfnTransferHandler, pvUser); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDMAReadMemory + */ +DECLINLINE(int) PDMDevHlpDMAReadMemory(PPDMDEVINS pDevIns, unsigned uChannel, void *pvBuffer, uint32_t off, uint32_t cbBlock, uint32_t *pcbRead) +{ + return pDevIns->pHlpR3->pfnDMAReadMemory(pDevIns, uChannel, pvBuffer, off, cbBlock, pcbRead); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDMAWriteMemory + */ +DECLINLINE(int) PDMDevHlpDMAWriteMemory(PPDMDEVINS pDevIns, unsigned uChannel, const void *pvBuffer, uint32_t off, uint32_t cbBlock, uint32_t *pcbWritten) +{ + return pDevIns->pHlpR3->pfnDMAWriteMemory(pDevIns, uChannel, pvBuffer, off, cbBlock, pcbWritten); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDMASetDREQ + */ +DECLINLINE(int) PDMDevHlpDMASetDREQ(PPDMDEVINS pDevIns, unsigned uChannel, unsigned uLevel) +{ + return pDevIns->pHlpR3->pfnDMASetDREQ(pDevIns, uChannel, uLevel); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDMAGetChannelMode + */ +DECLINLINE(uint8_t) PDMDevHlpDMAGetChannelMode(PPDMDEVINS pDevIns, unsigned uChannel) +{ + return pDevIns->pHlpR3->pfnDMAGetChannelMode(pDevIns, uChannel); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDMASchedule + */ +DECLINLINE(void) PDMDevHlpDMASchedule(PPDMDEVINS pDevIns) +{ + pDevIns->pHlpR3->pfnDMASchedule(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnCMOSWrite + */ +DECLINLINE(int) PDMDevHlpCMOSWrite(PPDMDEVINS pDevIns, unsigned iReg, uint8_t u8Value) +{ + return pDevIns->pHlpR3->pfnCMOSWrite(pDevIns, iReg, u8Value); +} + +/** + * @copydoc PDMDEVHLPR3::pfnCMOSRead + */ +DECLINLINE(int) PDMDevHlpCMOSRead(PPDMDEVINS pDevIns, unsigned iReg, uint8_t *pu8Value) +{ + return pDevIns->pHlpR3->pfnCMOSRead(pDevIns, iReg, pu8Value); +} + +/** + * @copydoc PDMDEVHLP::pfnCallR0 + */ +DECLINLINE(int) PDMDevHlpCallR0(PPDMDEVINS pDevIns, uint32_t uOperation, uint64_t u64Arg) +{ + return pDevIns->pHlpR3->pfnCallR0(pDevIns, uOperation, u64Arg); +} + +#endif /* IN_RING3 */ + +/** + * @copydoc PDMDEVHLPR3::pfnGetVM + */ +DECLINLINE(PVM) PDMDevHlpGetVM(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnGetVM(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnGetVMCPU + */ +DECLINLINE(PVMCPU) PDMDevHlpGetVMCPU(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnGetVMCPU(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTMTimeVirtGet + */ +DECLINLINE(uint64_t) PDMDevHlpTMTimeVirtGet(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTMTimeVirtGet(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTMTimeVirtGetFreq + */ +DECLINLINE(uint64_t) PDMDevHlpTMTimeVirtGetFreq(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTMTimeVirtGetFreq(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTMTimeVirtGetFreq + */ +DECLINLINE(uint64_t) PDMDevHlpTMTimeVirtGetNano(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTMTimeVirtGetNano(pDevIns); +} + +#ifdef IN_RING3 + +/** + * @copydoc PDMDEVHLPR3::pfnRegisterVMMDevHeap + */ +DECLINLINE(int) PDMDevHlpRegisterVMMDevHeap(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTR3PTR pvHeap, unsigned cbSize) +{ + return pDevIns->pHlpR3->pfnRegisterVMMDevHeap(pDevIns, GCPhys, pvHeap, cbSize); +} + +/** + * @copydoc PDMDEVHLPR3::pfnUnregisterVMMDevHeap + */ +DECLINLINE(int) PDMDevHlpUnregisterVMMDevHeap(PPDMDEVINS pDevIns, RTGCPHYS GCPhys) +{ + return pDevIns->pHlpR3->pfnUnregisterVMMDevHeap(pDevIns, GCPhys); +} + +/** + * @copydoc PDMDEVHLPR3::pfnVMReset + */ +DECLINLINE(int) PDMDevHlpVMReset(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnVMReset(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnVMSuspend + */ +DECLINLINE(int) PDMDevHlpVMSuspend(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnVMSuspend(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnVMSuspendSaveAndPowerOff + */ +DECLINLINE(int) PDMDevHlpVMSuspendSaveAndPowerOff(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnVMSuspendSaveAndPowerOff(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnVMPowerOff + */ +DECLINLINE(int) PDMDevHlpVMPowerOff(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnVMPowerOff(pDevIns); +} + +#endif /* IN_RING3 */ + +/** + * @copydoc PDMDEVHLPR3::pfnA20IsEnabled + */ +DECLINLINE(bool) PDMDevHlpA20IsEnabled(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnA20IsEnabled(pDevIns); +} + +#ifdef IN_RING3 + +/** + * @copydoc PDMDEVHLPR3::pfnGetCpuId + */ +DECLINLINE(void) PDMDevHlpGetCpuId(PPDMDEVINS pDevIns, uint32_t iLeaf, uint32_t *pEax, uint32_t *pEbx, uint32_t *pEcx, uint32_t *pEdx) +{ + pDevIns->pHlpR3->pfnGetCpuId(pDevIns, iLeaf, pEax, pEbx, pEcx, pEdx); +} + +#endif /* IN_RING3 */ +#ifdef IN_RING0 + +/** + * @copydoc PDMDEVHLPR0::pfnCanEmulateIoBlock + */ +DECLINLINE(bool) PDMDevHlpCanEmulateIoBlock(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCanEmulateIoBlock(pDevIns); +} + +#endif /* IN_RING0 */ + + + + +/** Pointer to callbacks provided to the VBoxDeviceRegister() call. */ +typedef struct PDMDEVREGCB *PPDMDEVREGCB; + +/** + * Callbacks for VBoxDeviceRegister(). + */ +typedef struct PDMDEVREGCB +{ + /** Interface version. + * This is set to PDM_DEVREG_CB_VERSION. */ + uint32_t u32Version; + + /** + * Registers a device with the current VM instance. + * + * @returns VBox status code. + * @param pCallbacks Pointer to the callback table. + * @param pReg Pointer to the device registration record. + * This data must be permanent and readonly. + */ + DECLR3CALLBACKMEMBER(int, pfnRegister,(PPDMDEVREGCB pCallbacks, PCPDMDEVREG pReg)); +} PDMDEVREGCB; + +/** Current version of the PDMDEVREGCB structure. */ +#define PDM_DEVREG_CB_VERSION PDM_VERSION_MAKE(0xffe3, 1, 0) + + +/** + * The VBoxDevicesRegister callback function. + * + * PDM will invoke this function after loading a device module and letting + * the module decide which devices to register and how to handle conflicts. + * + * @returns VBox status code. + * @param pCallbacks Pointer to the callback table. + * @param u32Version VBox version number. + */ +typedef DECLCALLBACK(int) FNPDMVBOXDEVICESREGISTER(PPDMDEVREGCB pCallbacks, uint32_t u32Version); + +/** @} */ + +RT_C_DECLS_END + +#endif diff --git a/include/VBox/vmm/pdmdrv.h b/include/VBox/vmm/pdmdrv.h new file mode 100644 index 00000000..d830ea69 --- /dev/null +++ b/include/VBox/vmm/pdmdrv.h @@ -0,0 +1,1829 @@ +/** @file + * PDM - Pluggable Device Manager, Drivers. + */ + +/* + * Copyright (C) 2006-2010 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_pdmdrv_h +#define ___VBox_vmm_pdmdrv_h + +#include <VBox/vmm/pdmqueue.h> +#include <VBox/vmm/pdmcritsect.h> +#include <VBox/vmm/pdmthread.h> +#include <VBox/vmm/pdmifs.h> +#include <VBox/vmm/pdmins.h> +#include <VBox/vmm/pdmcommon.h> +#include <VBox/vmm/pdmasynccompletion.h> +#ifdef VBOX_WITH_NETSHAPER +#include <VBox/vmm/pdmnetshaper.h> +#endif /* VBOX_WITH_NETSHAPER */ +#include <VBox/vmm/pdmblkcache.h> +#include <VBox/vmm/tm.h> +#include <VBox/vmm/ssm.h> +#include <VBox/vmm/cfgm.h> +#include <VBox/vmm/dbgf.h> +#include <VBox/vmm/mm.h> +#include <VBox/vmm/ftm.h> +#include <VBox/err.h> +#include <iprt/stdarg.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_driver The PDM Drivers API + * @ingroup grp_pdm + * @{ + */ + +/** Pointer const PDM Driver API, ring-3. */ +typedef R3PTRTYPE(struct PDMDRVHLPR3 const *) PCPDMDRVHLPR3; +/** Pointer const PDM Driver API, ring-0. */ +typedef R0PTRTYPE(struct PDMDRVHLPR0 const *) PCPDMDRVHLPR0; +/** Pointer const PDM Driver API, raw-mode context. */ +typedef RCPTRTYPE(struct PDMDRVHLPRC const *) PCPDMDRVHLPRC; + + +/** + * Construct a driver instance for a VM. + * + * @returns VBox status. + * @param pDrvIns The driver instance data. If the registration structure + * is needed, it can be accessed thru pDrvIns->pReg. + * @param pCfg Configuration node handle for the driver. This is + * expected to be in high demand in the constructor and is + * therefore passed as an argument. When using it at other + * times, it can be accessed via pDrvIns->pCfg. + * @param fFlags Flags, combination of the PDM_TACH_FLAGS_* \#defines. + */ +typedef DECLCALLBACK(int) FNPDMDRVCONSTRUCT(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags); +/** Pointer to a FNPDMDRVCONSTRUCT() function. */ +typedef FNPDMDRVCONSTRUCT *PFNPDMDRVCONSTRUCT; + +/** + * Destruct a driver instance. + * + * Most VM resources are freed by the VM. This callback is provided so that + * any non-VM resources can be freed correctly. + * + * @param pDrvIns The driver instance data. + */ +typedef DECLCALLBACK(void) FNPDMDRVDESTRUCT(PPDMDRVINS pDrvIns); +/** Pointer to a FNPDMDRVDESTRUCT() function. */ +typedef FNPDMDRVDESTRUCT *PFNPDMDRVDESTRUCT; + +/** + * Driver relocation callback. + * + * This is called when the instance data has been relocated in raw-mode context + * (RC). It is also called when the RC hypervisor selects changes. The driver + * must fixup all necessary pointers and re-query all interfaces to other RC + * devices and drivers. + * + * Before the RC code is executed the first time, this function will be called + * with a 0 delta so RC pointer calculations can be one in one place. + * + * @param pDrvIns Pointer to the driver instance. + * @param offDelta The relocation delta relative to the old location. + * + * @remark A relocation CANNOT fail. + */ +typedef DECLCALLBACK(void) FNPDMDRVRELOCATE(PPDMDRVINS pDrvIns, RTGCINTPTR offDelta); +/** Pointer to a FNPDMDRVRELOCATE() function. */ +typedef FNPDMDRVRELOCATE *PFNPDMDRVRELOCATE; + +/** + * Driver I/O Control interface. + * + * This is used by external components, such as the COM interface, to + * communicate with a driver using a driver specific interface. Generally, + * the driver interfaces are used for this task. + * + * @returns VBox status code. + * @param pDrvIns Pointer to the driver instance. + * @param uFunction Function to perform. + * @param pvIn Pointer to input data. + * @param cbIn Size of input data. + * @param pvOut Pointer to output data. + * @param cbOut Size of output data. + * @param pcbOut Where to store the actual size of the output data. + */ +typedef DECLCALLBACK(int) FNPDMDRVIOCTL(PPDMDRVINS pDrvIns, uint32_t uFunction, + void *pvIn, uint32_t cbIn, + void *pvOut, uint32_t cbOut, uint32_t *pcbOut); +/** Pointer to a FNPDMDRVIOCTL() function. */ +typedef FNPDMDRVIOCTL *PFNPDMDRVIOCTL; + +/** + * Power On notification. + * + * @param pDrvIns The driver instance data. + */ +typedef DECLCALLBACK(void) FNPDMDRVPOWERON(PPDMDRVINS pDrvIns); +/** Pointer to a FNPDMDRVPOWERON() function. */ +typedef FNPDMDRVPOWERON *PFNPDMDRVPOWERON; + +/** + * Reset notification. + * + * @returns VBox status. + * @param pDrvIns The driver instance data. + */ +typedef DECLCALLBACK(void) FNPDMDRVRESET(PPDMDRVINS pDrvIns); +/** Pointer to a FNPDMDRVRESET() function. */ +typedef FNPDMDRVRESET *PFNPDMDRVRESET; + +/** + * Suspend notification. + * + * @returns VBox status. + * @param pDrvIns The driver instance data. + */ +typedef DECLCALLBACK(void) FNPDMDRVSUSPEND(PPDMDRVINS pDrvIns); +/** Pointer to a FNPDMDRVSUSPEND() function. */ +typedef FNPDMDRVSUSPEND *PFNPDMDRVSUSPEND; + +/** + * Resume notification. + * + * @returns VBox status. + * @param pDrvIns The driver instance data. + */ +typedef DECLCALLBACK(void) FNPDMDRVRESUME(PPDMDRVINS pDrvIns); +/** Pointer to a FNPDMDRVRESUME() function. */ +typedef FNPDMDRVRESUME *PFNPDMDRVRESUME; + +/** + * Power Off notification. + * + * This is only called when the VMR3PowerOff call is made on a running VM. This + * means that there is no notification if the VM was suspended before being + * powered of. There will also be no callback when hot plugging devices or when + * replumbing the driver stack. + * + * @param pDrvIns The driver instance data. + */ +typedef DECLCALLBACK(void) FNPDMDRVPOWEROFF(PPDMDRVINS pDrvIns); +/** Pointer to a FNPDMDRVPOWEROFF() function. */ +typedef FNPDMDRVPOWEROFF *PFNPDMDRVPOWEROFF; + +/** + * Attach command. + * + * This is called to let the drive attach to a driver at runtime. This is not + * called during VM construction, the driver constructor have to do this by + * calling PDMDrvHlpAttach. + * + * This is like plugging in the keyboard or mouse after turning on the PC. + * + * @returns VBox status code. + * @param pDrvIns The driver instance. + * @param fFlags Flags, combination of the PDM_TACH_FLAGS_* \#defines. + */ +typedef DECLCALLBACK(int) FNPDMDRVATTACH(PPDMDRVINS pDrvIns, uint32_t fFlags); +/** Pointer to a FNPDMDRVATTACH() function. */ +typedef FNPDMDRVATTACH *PFNPDMDRVATTACH; + +/** + * Detach notification. + * + * This is called when a driver below it in the chain is detaching itself + * from it. The driver should adjust it's state to reflect this. + * + * This is like ejecting a cdrom or floppy. + * + * @param pDrvIns The driver instance. + * @param fFlags PDM_TACH_FLAGS_NOT_HOT_PLUG or 0. + */ +typedef DECLCALLBACK(void) FNPDMDRVDETACH(PPDMDRVINS pDrvIns, uint32_t fFlags); +/** Pointer to a FNPDMDRVDETACH() function. */ +typedef FNPDMDRVDETACH *PFNPDMDRVDETACH; + + + +/** + * PDM Driver Registration Structure. + * + * This structure is used when registering a driver from VBoxInitDrivers() (in + * host ring-3 context). PDM will continue use till the VM is terminated. + */ +typedef struct PDMDRVREG +{ + /** Structure version. PDM_DRVREG_VERSION defines the current version. */ + uint32_t u32Version; + /** Driver name. */ + char szName[32]; + /** Name of the raw-mode context module (no path). + * Only evalutated if PDM_DRVREG_FLAGS_RC is set. */ + char szRCMod[32]; + /** Name of the ring-0 module (no path). + * Only evalutated if PDM_DRVREG_FLAGS_R0 is set. */ + char szR0Mod[32]; + /** The description of the driver. The UTF-8 string pointed to shall, like this structure, + * remain unchanged from registration till VM destruction. */ + const char *pszDescription; + + /** Flags, combination of the PDM_DRVREG_FLAGS_* \#defines. */ + uint32_t fFlags; + /** Driver class(es), combination of the PDM_DRVREG_CLASS_* \#defines. */ + uint32_t fClass; + /** Maximum number of instances (per VM). */ + uint32_t cMaxInstances; + /** Size of the instance data. */ + uint32_t cbInstance; + + /** Construct instance - required. */ + PFNPDMDRVCONSTRUCT pfnConstruct; + /** Destruct instance - optional. */ + PFNPDMDRVDESTRUCT pfnDestruct; + /** Relocation command - optional. */ + PFNPDMDRVRELOCATE pfnRelocate; + /** I/O control - optional. */ + PFNPDMDRVIOCTL pfnIOCtl; + /** Power on notification - optional. */ + PFNPDMDRVPOWERON pfnPowerOn; + /** Reset notification - optional. */ + PFNPDMDRVRESET pfnReset; + /** Suspend notification - optional. */ + PFNPDMDRVSUSPEND pfnSuspend; + /** Resume notification - optional. */ + PFNPDMDRVRESUME pfnResume; + /** Attach command - optional. */ + PFNPDMDRVATTACH pfnAttach; + /** Detach notification - optional. */ + PFNPDMDRVDETACH pfnDetach; + /** Power off notification - optional. */ + PFNPDMDRVPOWEROFF pfnPowerOff; + /** @todo */ + PFNRT pfnSoftReset; + /** Initialization safty marker. */ + uint32_t u32VersionEnd; +} PDMDRVREG; +/** Pointer to a PDM Driver Structure. */ +typedef PDMDRVREG *PPDMDRVREG; +/** Const pointer to a PDM Driver Structure. */ +typedef PDMDRVREG const *PCPDMDRVREG; + +/** Current DRVREG version number. */ +#define PDM_DRVREG_VERSION PDM_VERSION_MAKE(0xf0ff, 1, 0) + +/** PDM Driver Flags. + * @{ */ +/** @def PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT + * The bit count for the current host. */ +#if HC_ARCH_BITS == 32 +# define PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT UINT32_C(0x00000001) +#elif HC_ARCH_BITS == 64 +# define PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT UINT32_C(0x00000002) +#else +# error Unsupported HC_ARCH_BITS value. +#endif +/** The host bit count mask. */ +#define PDM_DRVREG_FLAGS_HOST_BITS_MASK UINT32_C(0x00000003) +/** This flag is used to indicate that the driver has a RC component. */ +#define PDM_DRVREG_FLAGS_RC UINT32_C(0x00000010) +/** This flag is used to indicate that the driver has a R0 component. */ +#define PDM_DRVREG_FLAGS_R0 UINT32_C(0x00000020) + +/** @} */ + + +/** PDM Driver Classes. + * @{ */ +/** Mouse input driver. */ +#define PDM_DRVREG_CLASS_MOUSE RT_BIT(0) +/** Keyboard input driver. */ +#define PDM_DRVREG_CLASS_KEYBOARD RT_BIT(1) +/** Display driver. */ +#define PDM_DRVREG_CLASS_DISPLAY RT_BIT(2) +/** Network transport driver. */ +#define PDM_DRVREG_CLASS_NETWORK RT_BIT(3) +/** Block driver. */ +#define PDM_DRVREG_CLASS_BLOCK RT_BIT(4) +/** Media driver. */ +#define PDM_DRVREG_CLASS_MEDIA RT_BIT(5) +/** Mountable driver. */ +#define PDM_DRVREG_CLASS_MOUNTABLE RT_BIT(6) +/** Audio driver. */ +#define PDM_DRVREG_CLASS_AUDIO RT_BIT(7) +/** VMMDev driver. */ +#define PDM_DRVREG_CLASS_VMMDEV RT_BIT(8) +/** Status driver. */ +#define PDM_DRVREG_CLASS_STATUS RT_BIT(9) +/** ACPI driver. */ +#define PDM_DRVREG_CLASS_ACPI RT_BIT(10) +/** USB related driver. */ +#define PDM_DRVREG_CLASS_USB RT_BIT(11) +/** ISCSI Transport related driver. */ +#define PDM_DRVREG_CLASS_ISCSITRANSPORT RT_BIT(12) +/** Char driver. */ +#define PDM_DRVREG_CLASS_CHAR RT_BIT(13) +/** Stream driver. */ +#define PDM_DRVREG_CLASS_STREAM RT_BIT(14) +/** SCSI driver. */ +#define PDM_DRVREG_CLASS_SCSI RT_BIT(15) +/** Generic raw PCI device driver. */ +#define PDM_DRVREG_CLASS_PCIRAW RT_BIT(16) +/** @} */ + + +/** + * PDM Driver Instance. + * + * @implements PDMIBASE + */ +typedef struct PDMDRVINS +{ + /** Structure version. PDM_DRVINS_VERSION defines the current version. */ + uint32_t u32Version; + /** Driver instance number. */ + uint32_t iInstance; + + /** Pointer the PDM Driver API. */ + RCPTRTYPE(PCPDMDRVHLPRC) pHlpRC; + /** Pointer to driver instance data. */ + RCPTRTYPE(void *) pvInstanceDataRC; + + /** Pointer the PDM Driver API. */ + R0PTRTYPE(PCPDMDRVHLPR0) pHlpR0; + /** Pointer to driver instance data. */ + R0PTRTYPE(void *) pvInstanceDataR0; + + /** Pointer the PDM Driver API. */ + R3PTRTYPE(PCPDMDRVHLPR3) pHlpR3; + /** Pointer to driver instance data. */ + R3PTRTYPE(void *) pvInstanceDataR3; + + /** Pointer to driver registration structure. */ + R3PTRTYPE(PCPDMDRVREG) pReg; + /** Configuration handle. */ + R3PTRTYPE(PCFGMNODE) pCfg; + + /** Pointer to the base interface of the device/driver instance above. */ + R3PTRTYPE(PPDMIBASE) pUpBase; + /** Pointer to the base interface of the driver instance below. */ + R3PTRTYPE(PPDMIBASE) pDownBase; + + /** The base interface of the driver. + * The driver constructor initializes this. */ + PDMIBASE IBase; + + /** Tracing indicator. */ + uint32_t fTracing; + /** The tracing ID of this device. */ + uint32_t idTracing; +#if HC_ARCH_BITS == 32 + /** Align the internal data more naturally. */ + uint32_t au32Padding[HC_ARCH_BITS == 32 ? 7 : 0]; +#endif + + /** Internal data. */ + union + { +#ifdef PDMDRVINSINT_DECLARED + PDMDRVINSINT s; +#endif + uint8_t padding[HC_ARCH_BITS == 32 ? 40 + 32 : 72 + 24]; + } Internal; + + /** Driver instance data. The size of this area is defined + * in the PDMDRVREG::cbInstanceData field. */ + char achInstanceData[4]; +} PDMDRVINS; + +/** Current DRVREG version number. */ +#define PDM_DRVINS_VERSION PDM_VERSION_MAKE(0xf0fe, 2, 0) + +/** Converts a pointer to the PDMDRVINS::IBase to a pointer to PDMDRVINS. */ +#define PDMIBASE_2_PDMDRV(pInterface) ( (PPDMDRVINS)((char *)(pInterface) - RT_OFFSETOF(PDMDRVINS, IBase)) ) + +/** @def PDMDRVINS_2_RCPTR + * Converts a PDM Driver instance pointer a RC PDM Driver instance pointer. + */ +#define PDMDRVINS_2_RCPTR(pDrvIns) ( (RCPTRTYPE(PPDMDRVINS))((RTGCUINTPTR)(pDrvIns)->pvInstanceDataRC - RT_OFFSETOF(PDMDRVINS, achInstanceData)) ) + +/** @def PDMDRVINS_2_R3PTR + * Converts a PDM Driver instance pointer a R3 PDM Driver instance pointer. + */ +#define PDMDRVINS_2_R3PTR(pDrvIns) ( (R3PTRTYPE(PPDMDRVINS))((RTHCUINTPTR)(pDrvIns)->pvInstanceDataR3 - RT_OFFSETOF(PDMDRVINS, achInstanceData)) ) + +/** @def PDMDRVINS_2_R0PTR + * Converts a PDM Driver instance pointer a R0 PDM Driver instance pointer. + */ +#define PDMDRVINS_2_R0PTR(pDrvIns) ( (R0PTRTYPE(PPDMDRVINS))((RTR0UINTPTR)(pDrvIns)->pvInstanceDataR0 - RT_OFFSETOF(PDMDRVINS, achInstanceData)) ) + + + +/** + * Checks the structure versions of the drive instance and driver helpers, + * returning if they are incompatible. + * + * Intended for the constructor. + * + * @param pDrvIns Pointer to the PDM driver instance. + */ +#define PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns) \ + do \ + { \ + PPDMDRVINS pDrvInsTypeCheck = (pDrvIns); NOREF(pDrvInsTypeCheck); \ + AssertLogRelMsgReturn(PDM_VERSION_ARE_COMPATIBLE((pDrvIns)->u32Version, PDM_DRVINS_VERSION), \ + ("DrvIns=%#x mine=%#x\n", (pDrvIns)->u32Version, PDM_DRVINS_VERSION), \ + VERR_PDM_DRVINS_VERSION_MISMATCH); \ + AssertLogRelMsgReturn(PDM_VERSION_ARE_COMPATIBLE((pDrvIns)->pHlpR3->u32Version, PDM_DRVHLPR3_VERSION), \ + ("DrvHlp=%#x mine=%#x\n", (pDrvIns)->pHlpR3->u32Version, PDM_DRVHLPR3_VERSION), \ + VERR_PDM_DRVHLPR3_VERSION_MISMATCH); \ + } while (0) + +/** + * Quietly checks the structure versions of the drive instance and driver + * helpers, returning if they are incompatible. + * + * Intended for the destructor. + * + * @param pDrvIns Pointer to the PDM driver instance. + */ +#define PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns) \ + do \ + { \ + PPDMDRVINS pDrvInsTypeCheck = (pDrvIns); NOREF(pDrvInsTypeCheck); \ + if (RT_UNLIKELY( !PDM_VERSION_ARE_COMPATIBLE((pDrvIns)->u32Version, PDM_DRVINS_VERSION) \ + || !PDM_VERSION_ARE_COMPATIBLE((pDrvIns)->pHlpR3->u32Version, PDM_DRVHLPR3_VERSION)) ) \ + return; \ + } while (0) + +/** + * Wrapper around CFGMR3ValidateConfig for the root config for use in the + * constructor - returns on failure. + * + * This should be invoked after having initialized the instance data + * sufficiently for the correct operation of the destructor. The destructor is + * always called! + * + * @param pDrvIns Pointer to the PDM driver instance. + * @param pszValidValues Patterns describing the valid value names. See + * RTStrSimplePatternMultiMatch for details on the + * pattern syntax. + * @param pszValidNodes Patterns describing the valid node (key) names. + * Pass empty string if no valid nodess. + */ +#define PDMDRV_VALIDATE_CONFIG_RETURN(pDrvIns, pszValidValues, pszValidNodes) \ + do \ + { \ + int rcValCfg = CFGMR3ValidateConfig((pDrvIns)->pCfg, "/", pszValidValues, pszValidNodes, \ + (pDrvIns)->pReg->szName, (pDrvIns)->iInstance); \ + if (RT_FAILURE(rcValCfg)) \ + return rcValCfg; \ + } while (0) + + + +/** + * USB hub registration structure. + */ +typedef struct PDMUSBHUBREG +{ + /** Structure version number. PDM_USBHUBREG_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Request the hub to attach of the specified device. + * + * @returns VBox status code. + * @param pDrvIns The hub instance. + * @param pUsbIns The device to attach. + * @param piPort Where to store the port number the device was attached to. + * @thread EMT. + */ + DECLR3CALLBACKMEMBER(int, pfnAttachDevice,(PPDMDRVINS pDrvIns, PPDMUSBINS pUsbIns, uint32_t *piPort)); + + /** + * Request the hub to detach of the specified device. + * + * The device has previously been attached to the hub with the + * pfnAttachDevice call. This call is not currently expected to + * fail. + * + * @returns VBox status code. + * @param pDrvIns The hub instance. + * @param pUsbIns The device to detach. + * @param iPort The port number returned by the attach call. + * @thread EMT. + */ + DECLR3CALLBACKMEMBER(int, pfnDetachDevice,(PPDMDRVINS pDrvIns, PPDMUSBINS pUsbIns, uint32_t iPort)); + + /** Counterpart to u32Version, same value. */ + uint32_t u32TheEnd; +} PDMUSBHUBREG; +/** Pointer to a const USB hub registration structure. */ +typedef const PDMUSBHUBREG *PCPDMUSBHUBREG; + +/** Current PDMUSBHUBREG version number. */ +#define PDM_USBHUBREG_VERSION PDM_VERSION_MAKE(0xf0fd, 1, 0) + + +/** + * USB hub helpers. + * This is currently just a place holder. + */ +typedef struct PDMUSBHUBHLP +{ + /** Structure version. PDM_USBHUBHLP_VERSION defines the current version. */ + uint32_t u32Version; + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMUSBHUBHLP; +/** Pointer to PCI helpers. */ +typedef PDMUSBHUBHLP *PPDMUSBHUBHLP; +/** Pointer to const PCI helpers. */ +typedef const PDMUSBHUBHLP *PCPDMUSBHUBHLP; +/** Pointer to const PCI helpers pointer. */ +typedef PCPDMUSBHUBHLP *PPCPDMUSBHUBHLP; + +/** Current PDMUSBHUBHLP version number. */ +#define PDM_USBHUBHLP_VERSION PDM_VERSION_MAKE(0xf0fc, 1, 0) + + +/** + * PDM Driver API - raw-mode context variant. + */ +typedef struct PDMDRVHLPRC +{ + /** Structure version. PDM_DRVHLPRC_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Set the VM error message + * + * @returns rc. + * @param pDrvIns Driver instance. + * @param rc VBox status code. + * @param RT_SRC_POS_DECL Use RT_SRC_POS. + * @param pszFormat Error message format string. + * @param ... Error message arguments. + */ + DECLRCCALLBACKMEMBER(int, pfnVMSetError,(PPDMDRVINS pDrvIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...)); + + /** + * Set the VM error message + * + * @returns rc. + * @param pDrvIns Driver instance. + * @param rc VBox status code. + * @param RT_SRC_POS_DECL Use RT_SRC_POS. + * @param pszFormat Error message format string. + * @param va Error message arguments. + */ + DECLRCCALLBACKMEMBER(int, pfnVMSetErrorV,(PPDMDRVINS pDrvIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va)); + + /** + * Set the VM runtime error message + * + * @returns VBox status code. + * @param pDrvIns Driver instance. + * @param fFlags The action flags. See VMSETRTERR_FLAGS_*. + * @param pszErrorId Error ID string. + * @param pszFormat Error message format string. + * @param ... Error message arguments. + */ + DECLRCCALLBACKMEMBER(int, pfnVMSetRuntimeError,(PPDMDRVINS pDrvIns, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...)); + + /** + * Set the VM runtime error message + * + * @returns VBox status code. + * @param pDrvIns Driver instance. + * @param fFlags The action flags. See VMSETRTERR_FLAGS_*. + * @param pszErrorId Error ID string. + * @param pszFormat Error message format string. + * @param va Error message arguments. + */ + DECLRCCALLBACKMEMBER(int, pfnVMSetRuntimeErrorV,(PPDMDRVINS pDrvIns, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, va_list va)); + + /** + * Assert that the current thread is the emulation thread. + * + * @returns True if correct. + * @returns False if wrong. + * @param pDrvIns Driver instance. + * @param pszFile Filename of the assertion location. + * @param iLine Linenumber of the assertion location. + * @param pszFunction Function of the assertion location. + */ + DECLRCCALLBACKMEMBER(bool, pfnAssertEMT,(PPDMDRVINS pDrvIns, const char *pszFile, unsigned iLine, const char *pszFunction)); + + /** + * Assert that the current thread is NOT the emulation thread. + * + * @returns True if correct. + * @returns False if wrong. + * @param pDrvIns Driver instance. + * @param pszFile Filename of the assertion location. + * @param iLine Linenumber of the assertion location. + * @param pszFunction Function of the assertion location. + */ + DECLRCCALLBACKMEMBER(bool, pfnAssertOther,(PPDMDRVINS pDrvIns, const char *pszFile, unsigned iLine, const char *pszFunction)); + + /** + * Notify FTM about a checkpoint occurrence + * + * @param pDrvIns The driver instance. + * @param enmType Checkpoint type + * @thread Any + */ + DECLRCCALLBACKMEMBER(int, pfnFTSetCheckpoint,(PPDMDRVINS pDrvIns, FTMCHECKPOINTTYPE enmType)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMDRVHLPRC; +/** Current PDMDRVHLPRC version number. */ +#define PDM_DRVHLPRC_VERSION PDM_VERSION_MAKE(0xf0f9, 2, 0) + + +/** + * PDM Driver API, ring-0 context. + */ +typedef struct PDMDRVHLPR0 +{ + /** Structure version. PDM_DRVHLPR0_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Set the VM error message + * + * @returns rc. + * @param pDrvIns Driver instance. + * @param rc VBox status code. + * @param RT_SRC_POS_DECL Use RT_SRC_POS. + * @param pszFormat Error message format string. + * @param ... Error message arguments. + */ + DECLR0CALLBACKMEMBER(int, pfnVMSetError,(PPDMDRVINS pDrvIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...)); + + /** + * Set the VM error message + * + * @returns rc. + * @param pDrvIns Driver instance. + * @param rc VBox status code. + * @param RT_SRC_POS_DECL Use RT_SRC_POS. + * @param pszFormat Error message format string. + * @param va Error message arguments. + */ + DECLR0CALLBACKMEMBER(int, pfnVMSetErrorV,(PPDMDRVINS pDrvIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va)); + + /** + * Set the VM runtime error message + * + * @returns VBox status code. + * @param pDrvIns Driver instance. + * @param fFlags The action flags. See VMSETRTERR_FLAGS_*. + * @param pszErrorId Error ID string. + * @param pszFormat Error message format string. + * @param ... Error message arguments. + */ + DECLR0CALLBACKMEMBER(int, pfnVMSetRuntimeError,(PPDMDRVINS pDrvIns, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...)); + + /** + * Set the VM runtime error message + * + * @returns VBox status code. + * @param pDrvIns Driver instance. + * @param fFlags The action flags. See VMSETRTERR_FLAGS_*. + * @param pszErrorId Error ID string. + * @param pszFormat Error message format string. + * @param va Error message arguments. + */ + DECLR0CALLBACKMEMBER(int, pfnVMSetRuntimeErrorV,(PPDMDRVINS pDrvIns, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, va_list va)); + + /** + * Assert that the current thread is the emulation thread. + * + * @returns True if correct. + * @returns False if wrong. + * @param pDrvIns Driver instance. + * @param pszFile Filename of the assertion location. + * @param iLine Linenumber of the assertion location. + * @param pszFunction Function of the assertion location. + */ + DECLR0CALLBACKMEMBER(bool, pfnAssertEMT,(PPDMDRVINS pDrvIns, const char *pszFile, unsigned iLine, const char *pszFunction)); + + /** + * Assert that the current thread is NOT the emulation thread. + * + * @returns True if correct. + * @returns False if wrong. + * @param pDrvIns Driver instance. + * @param pszFile Filename of the assertion location. + * @param iLine Linenumber of the assertion location. + * @param pszFunction Function of the assertion location. + */ + DECLR0CALLBACKMEMBER(bool, pfnAssertOther,(PPDMDRVINS pDrvIns, const char *pszFile, unsigned iLine, const char *pszFunction)); + + /** + * Notify FTM about a checkpoint occurrence + * + * @param pDrvIns The driver instance. + * @param enmType Checkpoint type + * @thread Any + */ + DECLR0CALLBACKMEMBER(int, pfnFTSetCheckpoint,(PPDMDRVINS pDrvIns, FTMCHECKPOINTTYPE enmType)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMDRVHLPR0; +/** Current DRVHLP version number. */ +#define PDM_DRVHLPR0_VERSION PDM_VERSION_MAKE(0xf0f8, 2, 0) + + +#ifdef IN_RING3 + +/** + * PDM Driver API. + */ +typedef struct PDMDRVHLPR3 +{ + /** Structure version. PDM_DRVHLPR3_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Attaches a driver (chain) to the driver. + * + * @returns VBox status code. + * @param pDrvIns Driver instance. + * @param fFlags PDM_TACH_FLAGS_NOT_HOT_PLUG or 0. + * @param ppBaseInterface Where to store the pointer to the base interface. + */ + DECLR3CALLBACKMEMBER(int, pfnAttach,(PPDMDRVINS pDrvIns, uint32_t fFlags, PPDMIBASE *ppBaseInterface)); + + /** + * Detach the driver the drivers below us. + * + * @returns VBox status code. + * @param pDrvIns Driver instance. + * @param fFlags PDM_TACH_FLAGS_NOT_HOT_PLUG or 0. + */ + DECLR3CALLBACKMEMBER(int, pfnDetach,(PPDMDRVINS pDrvIns, uint32_t fFlags)); + + /** + * Detach the driver from the driver above it and destroy this + * driver and all drivers below it. + * + * @returns VBox status code. + * @param pDrvIns Driver instance. + * @param fFlags PDM_TACH_FLAGS_NOT_HOT_PLUG or 0. + */ + DECLR3CALLBACKMEMBER(int, pfnDetachSelf,(PPDMDRVINS pDrvIns, uint32_t fFlags)); + + /** + * Prepare a media mount. + * + * The driver must not have anything attached to itself + * when calling this function as the purpose is to set up the configuration + * of an future attachment. + * + * @returns VBox status code + * @param pDrvIns Driver instance. + * @param pszFilename Pointer to filename. If this is NULL it assumed that the caller have + * constructed a configuration which can be attached to the bottom driver. + * @param pszCoreDriver Core driver name. NULL will cause autodetection. Ignored if pszFilanem is NULL. + */ + DECLR3CALLBACKMEMBER(int, pfnMountPrepare,(PPDMDRVINS pDrvIns, const char *pszFilename, const char *pszCoreDriver)); + + /** + * Assert that the current thread is the emulation thread. + * + * @returns True if correct. + * @returns False if wrong. + * @param pDrvIns Driver instance. + * @param pszFile Filename of the assertion location. + * @param iLine Linenumber of the assertion location. + * @param pszFunction Function of the assertion location. + */ + DECLR3CALLBACKMEMBER(bool, pfnAssertEMT,(PPDMDRVINS pDrvIns, const char *pszFile, unsigned iLine, const char *pszFunction)); + + /** + * Assert that the current thread is NOT the emulation thread. + * + * @returns True if correct. + * @returns False if wrong. + * @param pDrvIns Driver instance. + * @param pszFile Filename of the assertion location. + * @param iLine Linenumber of the assertion location. + * @param pszFunction Function of the assertion location. + */ + DECLR3CALLBACKMEMBER(bool, pfnAssertOther,(PPDMDRVINS pDrvIns, const char *pszFile, unsigned iLine, const char *pszFunction)); + + /** + * Set the VM error message + * + * @returns rc. + * @param pDrvIns Driver instance. + * @param rc VBox status code. + * @param RT_SRC_POS_DECL Use RT_SRC_POS. + * @param pszFormat Error message format string. + * @param ... Error message arguments. + */ + DECLR3CALLBACKMEMBER(int, pfnVMSetError,(PPDMDRVINS pDrvIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...)); + + /** + * Set the VM error message + * + * @returns rc. + * @param pDrvIns Driver instance. + * @param rc VBox status code. + * @param RT_SRC_POS_DECL Use RT_SRC_POS. + * @param pszFormat Error message format string. + * @param va Error message arguments. + */ + DECLR3CALLBACKMEMBER(int, pfnVMSetErrorV,(PPDMDRVINS pDrvIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va)); + + /** + * Set the VM runtime error message + * + * @returns VBox status code. + * @param pDrvIns Driver instance. + * @param fFlags The action flags. See VMSETRTERR_FLAGS_*. + * @param pszErrorId Error ID string. + * @param pszFormat Error message format string. + * @param ... Error message arguments. + */ + DECLR3CALLBACKMEMBER(int, pfnVMSetRuntimeError,(PPDMDRVINS pDrvIns, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...)); + + /** + * Set the VM runtime error message + * + * @returns VBox status code. + * @param pDrvIns Driver instance. + * @param fFlags The action flags. See VMSETRTERR_FLAGS_*. + * @param pszErrorId Error ID string. + * @param pszFormat Error message format string. + * @param va Error message arguments. + */ + DECLR3CALLBACKMEMBER(int, pfnVMSetRuntimeErrorV,(PPDMDRVINS pDrvIns, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, va_list va)); + + /** + * Gets the VM state. + * + * @returns VM state. + * @param pDrvIns The driver instance. + * @thread Any thread (just keep in mind that it's volatile info). + */ + DECLR3CALLBACKMEMBER(VMSTATE, pfnVMState, (PPDMDRVINS pDrvIns)); + + /** + * Checks if the VM was teleported and hasn't been fully resumed yet. + * + * @returns true / false. + * @param pDrvIns The driver instance. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(bool, pfnVMTeleportedAndNotFullyResumedYet,(PPDMDRVINS pDrvIns)); + + /** + * Gets the support driver session. + * + * This is intended for working using the semaphore API. + * + * @returns Support driver session handle. + * @param pDrvIns The driver instance. + */ + DECLR3CALLBACKMEMBER(PSUPDRVSESSION, pfnGetSupDrvSession,(PPDMDRVINS pDrvIns)); + + /** + * Create a queue. + * + * @returns VBox status code. + * @param pDrvIns Driver instance. + * @param cbItem Size a queue item. + * @param cItems Number of items in the queue. + * @param cMilliesInterval Number of milliseconds between polling the queue. + * If 0 then the emulation thread will be notified whenever an item arrives. + * @param pfnCallback The consumer function. + * @param pszName The queue base name. The instance number will be + * appended automatically. + * @param ppQueue Where to store the queue handle on success. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnQueueCreate,(PPDMDRVINS pDrvIns, uint32_t cbItem, uint32_t cItems, uint32_t cMilliesInterval, + PFNPDMQUEUEDRV pfnCallback, const char *pszName, PPDMQUEUE *ppQueue)); + + /** + * Query the virtual timer frequency. + * + * @returns Frequency in Hz. + * @param pDrvIns Driver instance. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnTMGetVirtualFreq,(PPDMDRVINS pDrvIns)); + + /** + * Query the virtual time. + * + * @returns The current virtual time. + * @param pDrvIns Driver instance. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnTMGetVirtualTime,(PPDMDRVINS pDrvIns)); + + /** + * Creates a timer. + * + * @returns VBox status. + * @param pDrvIns Driver instance. + * @param enmClock The clock to use on this timer. + * @param pfnCallback Callback function. + * @param pvUser The user argument to the callback. + * @param fFlags Timer creation flags, see grp_tm_timer_flags. + * @param pszDesc Pointer to description string which must stay around + * until the timer is fully destroyed (i.e. a bit after TMTimerDestroy()). + * @param ppTimer Where to store the timer on success. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnTMTimerCreate,(PPDMDRVINS pDrvIns, TMCLOCK enmClock, PFNTMTIMERDRV pfnCallback, void *pvUser, uint32_t fFlags, const char *pszDesc, PPTMTIMERR3 ppTimer)); + + /** + * Register a save state data unit. + * + * @returns VBox status. + * @param pDrvIns Driver instance. + * @param uVersion Data layout version number. + * @param cbGuess The approximate amount of data in the unit. + * Only for progress indicators. + * + * @param pfnLivePrep Prepare live save callback, optional. + * @param pfnLiveExec Execute live save callback, optional. + * @param pfnLiveVote Vote live save callback, optional. + * + * @param pfnSavePrep Prepare save callback, optional. + * @param pfnSaveExec Execute save callback, optional. + * @param pfnSaveDone Done save callback, optional. + * + * @param pfnLoadPrep Prepare load callback, optional. + * @param pfnLoadExec Execute load callback, optional. + * @param pfnLoadDone Done load callback, optional. + */ + DECLR3CALLBACKMEMBER(int, pfnSSMRegister,(PPDMDRVINS pDrvIns, uint32_t uVersion, size_t cbGuess, + PFNSSMDRVLIVEPREP pfnLivePrep, PFNSSMDRVLIVEEXEC pfnLiveExec, PFNSSMDRVLIVEVOTE pfnLiveVote, + PFNSSMDRVSAVEPREP pfnSavePrep, PFNSSMDRVSAVEEXEC pfnSaveExec, PFNSSMDRVSAVEDONE pfnSaveDone, + PFNSSMDRVLOADPREP pfnLoadPrep, PFNSSMDRVLOADEXEC pfnLoadExec, PFNSSMDRVLOADDONE pfnLoadDone)); + + /** + * Deregister a save state data unit. + * + * @returns VBox status. + * @param pDrvIns Driver instance. + * @param pszName Data unit name. + * @param uInstance The instance identifier of the data unit. + * This must together with the name be unique. + */ + DECLR3CALLBACKMEMBER(int, pfnSSMDeregister,(PPDMDRVINS pDrvIns, const char *pszName, uint32_t uInstance)); + + /** + * Register an info handler with DBGF. + * + * @returns VBox status code. + * @param pDrvIns Driver instance. + * @param pszName Data unit name. + * @param pszDesc The description of the info and any arguments + * the handler may take. + * @param pfnHandler The handler function to be called to display the + * info. + */ + DECLR3CALLBACKMEMBER(int, pfnDBGFInfoRegister,(PPDMDRVINS pDrvIns, const char *pszName, const char *pszDesc, PFNDBGFHANDLERDRV pfnHandler)); + + /** + * Deregister an info handler from DBGF. + * + * @returns VBox status code. + * @param pDrvIns Driver instance. + * @param pszName Data unit name. + */ + DECLR3CALLBACKMEMBER(int, pfnDBGFInfoDeregister,(PPDMDRVINS pDrvIns, const char *pszName)); + + /** + * Registers a statistics sample if statistics are enabled. + * + * @param pDrvIns Driver instance. + * @param pvSample Pointer to the sample. + * @param enmType Sample type. This indicates what pvSample is pointing at. + * @param pszName Sample name. The name is on this form "/<component>/<sample>". + * Further nesting is possible. + * @param enmUnit Sample unit. + * @param pszDesc Sample description. + */ + DECLR3CALLBACKMEMBER(void, pfnSTAMRegister,(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType, const char *pszName, + STAMUNIT enmUnit, const char *pszDesc)); + + /** + * Same as pfnSTAMRegister except that the name is specified in a + * RTStrPrintf like fashion. + * + * @param pDrvIns Driver instance. + * @param pvSample Pointer to the sample. + * @param enmType Sample type. This indicates what pvSample is pointing at. + * @param enmVisibility Visibility type specifying whether unused statistics should be visible or not. + * @param enmUnit Sample unit. + * @param pszDesc Sample description. + * @param pszName The sample name format string. + * @param ... Arguments to the format string. + */ + DECLR3CALLBACKMEMBER(void, pfnSTAMRegisterF,(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, + STAMUNIT enmUnit, const char *pszDesc, const char *pszName, ...)); + + /** + * Same as pfnSTAMRegister except that the name is specified in a + * RTStrPrintfV like fashion. + * + * @param pDrvIns Driver instance. + * @param pvSample Pointer to the sample. + * @param enmType Sample type. This indicates what pvSample is pointing at. + * @param enmVisibility Visibility type specifying whether unused statistics should be visible or not. + * @param enmUnit Sample unit. + * @param pszDesc Sample description. + * @param pszName The sample name format string. + * @param args Arguments to the format string. + */ + DECLR3CALLBACKMEMBER(void, pfnSTAMRegisterV,(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, + STAMUNIT enmUnit, const char *pszDesc, const char *pszName, va_list args)); + + /** + * Deregister a statistic item previously registered with pfnSTAMRegister, + * pfnSTAMRegisterF or pfnSTAMRegisterV + * + * @returns VBox status. + * @param pDrvIns Driver instance. + * @param pvSample Pointer to the sample. + */ + DECLR3CALLBACKMEMBER(int, pfnSTAMDeregister,(PPDMDRVINS pDrvIns, void *pvSample)); + + /** + * Calls the HC R0 VMM entry point, in a safer but slower manner than + * SUPR3CallVMMR0. + * + * When entering using this call the R0 components can call into the host kernel + * (i.e. use the SUPR0 and RT APIs). + * + * See VMMR0Entry() for more details. + * + * @returns error code specific to uFunction. + * @param pDrvIns The driver instance. + * @param uOperation Operation to execute. + * This is limited to services. + * @param pvArg Pointer to argument structure or if cbArg is 0 just an value. + * @param cbArg The size of the argument. This is used to copy whatever the argument + * points at into a kernel buffer to avoid problems like the user page + * being invalidated while we're executing the call. + */ + DECLR3CALLBACKMEMBER(int, pfnSUPCallVMMR0Ex,(PPDMDRVINS pDrvIns, unsigned uOperation, void *pvArg, unsigned cbArg)); + + /** + * Registers a USB HUB. + * + * @returns VBox status code. + * @param pDrvIns The driver instance. + * @param fVersions Indicates the kinds of USB devices that can be attached to this HUB. + * @param cPorts The number of ports. + * @param pUsbHubReg The hub callback structure that PDMUsb uses to interact with it. + * @param ppUsbHubHlp The helper callback structure that the hub uses to talk to PDMUsb. + * + * @thread EMT. + */ + DECLR3CALLBACKMEMBER(int, pfnUSBRegisterHub,(PPDMDRVINS pDrvIns, uint32_t fVersions, uint32_t cPorts, PCPDMUSBHUBREG pUsbHubReg, PPCPDMUSBHUBHLP ppUsbHubHlp)); + + /** + * Set up asynchronous handling of a suspend, reset or power off notification. + * + * This shall only be called when getting the notification. It must be called + * for each one. + * + * @returns VBox status code. + * @param pDrvIns The driver instance. + * @param pfnAsyncNotify The callback. + * @thread EMT(0) + */ + DECLR3CALLBACKMEMBER(int, pfnSetAsyncNotification, (PPDMDRVINS pDrvIns, PFNPDMDRVASYNCNOTIFY pfnAsyncNotify)); + + /** + * Notify EMT(0) that the driver has completed the asynchronous notification + * handling. + * + * This can be called at any time, spurious calls will simply be ignored. + * + * @param pDrvIns The driver instance. + * @thread Any + */ + DECLR3CALLBACKMEMBER(void, pfnAsyncNotificationCompleted, (PPDMDRVINS pDrvIns)); + + /** + * Creates a PDM thread. + * + * This differs from the RTThreadCreate() API in that PDM takes care of suspending, + * resuming, and destroying the thread as the VM state changes. + * + * @returns VBox status code. + * @param pDrvIns The driver instance. + * @param ppThread Where to store the thread 'handle'. + * @param pvUser The user argument to the thread function. + * @param pfnThread The thread function. + * @param pfnWakeup The wakup callback. This is called on the EMT thread when + * a state change is pending. + * @param cbStack See RTThreadCreate. + * @param enmType See RTThreadCreate. + * @param pszName See RTThreadCreate. + */ + DECLR3CALLBACKMEMBER(int, pfnThreadCreate,(PPDMDRVINS pDrvIns, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADDRV pfnThread, + PFNPDMTHREADWAKEUPDRV pfnWakeup, size_t cbStack, RTTHREADTYPE enmType, const char *pszName)); + + /** + * Creates an async completion template for a driver instance. + * + * The template is used when creating new completion tasks. + * + * @returns VBox status code. + * @param pDrvIns The driver instance. + * @param ppTemplate Where to store the template pointer on success. + * @param pfnCompleted The completion callback routine. + * @param pvTemplateUser Template user argument. + * @param pszDesc Description. + */ + DECLR3CALLBACKMEMBER(int, pfnAsyncCompletionTemplateCreate,(PPDMDRVINS pDrvIns, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate, + PFNPDMASYNCCOMPLETEDRV pfnCompleted, void *pvTemplateUser, + const char *pszDesc)); + +#ifdef VBOX_WITH_NETSHAPER + /** + * Attaches network filter driver to a bandwidth group. + * + * @returns VBox status code. + * @param pDrvIns The driver instance. + * @param pcszBwGroup Name of the bandwidth group to attach to. + * @param pFilter Pointer to the filter we attach. + */ + DECLR3CALLBACKMEMBER(int, pfnNetShaperAttach,(PPDMDRVINS pDrvIns, const char *pszBwGroup, + PPDMNSFILTER pFilter)); + + + /** + * Detaches network filter driver to a bandwidth group. + * + * @returns VBox status code. + * @param pDrvIns The driver instance. + * @param pFilter Pointer to the filter we attach. + */ + DECLR3CALLBACKMEMBER(int, pfnNetShaperDetach,(PPDMDRVINS pDrvIns, PPDMNSFILTER pFilter)); +#endif /* VBOX_WITH_NETSHAPER */ + + + /** + * Resolves the symbol for a raw-mode context interface. + * + * @returns VBox status code. + * @param pDrvIns The driver instance. + * @param pvInterface The interface structure. + * @param cbInterface The size of the interface structure. + * @param pszSymPrefix What to prefix the symbols in the list with before + * resolving them. This must start with 'drv' and + * contain the driver name. + * @param pszSymList List of symbols corresponding to the interface. + * There is generally a there is generally a define + * holding this list associated with the interface + * definition (INTERFACE_SYM_LIST). For more details + * see PDMR3LdrGetInterfaceSymbols. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnLdrGetRCInterfaceSymbols,(PPDMDRVINS pDrvIns, void *pvInterface, size_t cbInterface, + const char *pszSymPrefix, const char *pszSymList)); + + /** + * Resolves the symbol for a ring-0 context interface. + * + * @returns VBox status code. + * @param pDrvIns The driver instance. + * @param pvInterface The interface structure. + * @param cbInterface The size of the interface structure. + * @param pszSymPrefix What to prefix the symbols in the list with before + * resolving them. This must start with 'drv' and + * contain the driver name. + * @param pszSymList List of symbols corresponding to the interface. + * There is generally a there is generally a define + * holding this list associated with the interface + * definition (INTERFACE_SYM_LIST). For more details + * see PDMR3LdrGetInterfaceSymbols. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnLdrGetR0InterfaceSymbols,(PPDMDRVINS pDrvIns, void *pvInterface, size_t cbInterface, + const char *pszSymPrefix, const char *pszSymList)); + /** + * Initializes a PDM critical section. + * + * The PDM critical sections are derived from the IPRT critical sections, but + * works in both RC and R0 as well as R3. + * + * @returns VBox status code. + * @param pDrvIns The driver instance. + * @param pCritSect Pointer to the critical section. + * @param RT_SRC_POS_DECL Use RT_SRC_POS. + * @param pszName The base name of the critical section. Will be + * mangeled with the instance number. For + * statistics and lock validation. + * @param va Arguments for the format string. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnCritSectInit,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, + RT_SRC_POS_DECL, const char *pszName)); + + /** + * Call the ring-0 request handler routine of the driver. + * + * For this to work, the driver must be ring-0 enabled and export a request + * handler function. The name of the function must be the driver name in the + * PDMDRVREG struct prefixed with 'drvR0' and suffixed with 'ReqHandler'. + * The driver name will be capitalized. It shall take the exact same + * arguments as this function and be declared using PDMBOTHCBDECL. See + * FNPDMDRVREQHANDLERR0. + * + * @returns VBox status code. + * @retval VERR_SYMBOL_NOT_FOUND if the driver doesn't export the required + * handler function. + * @retval VERR_ACCESS_DENIED if the driver isn't ring-0 capable. + * + * @param pDrvIns The driver instance. + * @param uOperation The operation to perform. + * @param u64Arg 64-bit integer argument. + * @thread Any + */ + DECLR3CALLBACKMEMBER(int, pfnCallR0,(PPDMDRVINS pDrvIns, uint32_t uOperation, uint64_t u64Arg)); + + /** + * Notify FTM about a checkpoint occurrence + * + * @param pDrvIns The driver instance. + * @param enmType Checkpoint type + * @thread Any + */ + DECLR3CALLBACKMEMBER(int, pfnFTSetCheckpoint,(PPDMDRVINS pDrvIns, FTMCHECKPOINTTYPE enmType)); + + /** + * Creates a block cache for a driver driver instance. + * + * @returns VBox status code. + * @param pDrvIns The driver instance. + * @param ppBlkCache Where to store the handle to the block cache. + * @param pfnXferComplete The I/O transfer complete callback. + * @param pfnXferEnqueue The I/O request enqueue callback. + * @param pcszId Unique ID used to identify the user. + */ + DECLR3CALLBACKMEMBER(int, pfnBlkCacheRetain, (PPDMDRVINS pDrvIns, PPPDMBLKCACHE ppBlkCache, + PFNPDMBLKCACHEXFERCOMPLETEDRV pfnXferComplete, + PFNPDMBLKCACHEXFERENQUEUEDRV pfnXferEnqueue, + PFNPDMBLKCACHEXFERENQUEUEDISCARDDRV pfnXferEnqueueDiscard, + const char *pcszId)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMDRVHLPR3; +/** Current DRVHLP version number. */ +#define PDM_DRVHLPR3_VERSION PDM_VERSION_MAKE(0xf0fb, 2, 0) + +#endif /* IN_RING3 */ + + +/** + * @copydoc PDMDRVHLP::pfnVMSetError + */ +DECLINLINE(int) PDMDrvHlpVMSetError(PPDMDRVINS pDrvIns, const int rc, RT_SRC_POS_DECL, const char *pszFormat, ...) +{ + va_list va; + va_start(va, pszFormat); + pDrvIns->CTX_SUFF(pHlp)->pfnVMSetErrorV(pDrvIns, rc, RT_SRC_POS_ARGS, pszFormat, va); + va_end(va); + return rc; +} + +/** @def PDMDRV_SET_ERROR + * Set the VM error. See PDMDrvHlpVMSetError() for printf like message formatting. + */ +#define PDMDRV_SET_ERROR(pDrvIns, rc, pszError) \ + PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, "%s", pszError) + +/** + * @copydoc PDMDRVHLP::pfnVMSetErrorV + */ +DECLINLINE(int) PDMDrvHlpVMSetErrorV(PPDMDRVINS pDrvIns, const int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnVMSetErrorV(pDrvIns, rc, RT_SRC_POS_ARGS, pszFormat, va); +} + + +/** + * @copydoc PDMDRVHLP::pfnVMSetRuntimeError + */ +DECLINLINE(int) PDMDrvHlpVMSetRuntimeError(PPDMDRVINS pDrvIns, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...) +{ + va_list va; + int rc; + va_start(va, pszFormat); + rc = pDrvIns->CTX_SUFF(pHlp)->pfnVMSetRuntimeErrorV(pDrvIns, fFlags, pszErrorId, pszFormat, va); + va_end(va); + return rc; +} + +/** @def PDMDRV_SET_RUNTIME_ERROR + * Set the VM runtime error. See PDMDrvHlpVMSetRuntimeError() for printf like message formatting. + */ +#define PDMDRV_SET_RUNTIME_ERROR(pDrvIns, fFlags, pszErrorId, pszError) \ + PDMDrvHlpVMSetRuntimeError(pDrvIns, fFlags, pszErrorId, "%s", pszError) + +/** + * @copydoc PDMDRVHLP::pfnVMSetRuntimeErrorV + */ +DECLINLINE(int) PDMDrvHlpVMSetRuntimeErrorV(PPDMDRVINS pDrvIns, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, va_list va) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnVMSetRuntimeErrorV(pDrvIns, fFlags, pszErrorId, pszFormat, va); +} + + + +/** @def PDMDRV_ASSERT_EMT + * Assert that the current thread is the emulation thread. + */ +#ifdef VBOX_STRICT +# define PDMDRV_ASSERT_EMT(pDrvIns) pDrvIns->CTX_SUFF(pHlp)->pfnAssertEMT(pDrvIns, __FILE__, __LINE__, __FUNCTION__) +#else +# define PDMDRV_ASSERT_EMT(pDrvIns) do { } while (0) +#endif + +/** @def PDMDRV_ASSERT_OTHER + * Assert that the current thread is NOT the emulation thread. + */ +#ifdef VBOX_STRICT +# define PDMDRV_ASSERT_OTHER(pDrvIns) pDrvIns->CTX_SUFF(pHlp)->pfnAssertOther(pDrvIns, __FILE__, __LINE__, __FUNCTION__) +#else +# define PDMDRV_ASSERT_OTHER(pDrvIns) do { } while (0) +#endif + +/** + * @copydoc PDMDRVHLP::pfnFTSetCheckpoint + */ +DECLINLINE(int) PDMDrvHlpFTSetCheckpoint(PPDMDRVINS pDrvIns, FTMCHECKPOINTTYPE enmType) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnFTSetCheckpoint(pDrvIns, enmType); +} + + +#ifdef IN_RING3 + +/** + * @copydoc PDMDRVHLP::pfnAttach + */ +DECLINLINE(int) PDMDrvHlpAttach(PPDMDRVINS pDrvIns, uint32_t fFlags, PPDMIBASE *ppBaseInterface) +{ + return pDrvIns->pHlpR3->pfnAttach(pDrvIns, fFlags, ppBaseInterface); +} + +/** + * Check that there is no driver below the us that we should attach to. + * + * @returns VERR_PDM_NO_ATTACHED_DRIVER if there is no driver. + * @param pDrvIns The driver instance. + */ +DECLINLINE(int) PDMDrvHlpNoAttach(PPDMDRVINS pDrvIns) +{ + return pDrvIns->pHlpR3->pfnAttach(pDrvIns, 0, NULL); +} + +/** + * @copydoc PDMDRVHLP::pfnDetach + */ +DECLINLINE(int) PDMDrvHlpDetach(PPDMDRVINS pDrvIns, uint32_t fFlags) +{ + return pDrvIns->pHlpR3->pfnDetach(pDrvIns, fFlags); +} + +/** + * @copydoc PDMDRVHLP::pfnDetachSelf + */ +DECLINLINE(int) PDMDrvHlpDetachSelf(PPDMDRVINS pDrvIns, uint32_t fFlags) +{ + return pDrvIns->pHlpR3->pfnDetachSelf(pDrvIns, fFlags); +} + +/** + * @copydoc PDMDRVHLP::pfnMountPrepare + */ +DECLINLINE(int) PDMDrvHlpMountPrepare(PPDMDRVINS pDrvIns, const char *pszFilename, const char *pszCoreDriver) +{ + return pDrvIns->pHlpR3->pfnMountPrepare(pDrvIns, pszFilename, pszCoreDriver); +} + +/** + * @copydoc PDMDRVHLP::pfnVMState + */ +DECLINLINE(VMSTATE) PDMDrvHlpVMState(PPDMDRVINS pDrvIns) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnVMState(pDrvIns); +} + +/** + * @copydoc PDMDRVHLP::pfnVMTeleportedAndNotFullyResumedYet + */ +DECLINLINE(bool) PDMDrvHlpVMTeleportedAndNotFullyResumedYet(PPDMDRVINS pDrvIns) +{ + return pDrvIns->pHlpR3->pfnVMTeleportedAndNotFullyResumedYet(pDrvIns); +} + +/** + * @copydoc PDMDRVHLP::pfnGetSupDrvSession + */ +DECLINLINE(PSUPDRVSESSION) PDMDrvHlpGetSupDrvSession(PPDMDRVINS pDrvIns) +{ + return pDrvIns->pHlpR3->pfnGetSupDrvSession(pDrvIns); +} + +/** + * @copydoc PDMDRVHLP::pfnQueueCreate + */ +DECLINLINE(int) PDMDrvHlpQueueCreate(PPDMDRVINS pDrvIns, uint32_t cbItem, uint32_t cItems, uint32_t cMilliesInterval, + PFNPDMQUEUEDRV pfnCallback, const char *pszName, PPDMQUEUE *ppQueue) +{ + return pDrvIns->pHlpR3->pfnQueueCreate(pDrvIns, cbItem, cItems, cMilliesInterval, pfnCallback, pszName, ppQueue); +} + +/** + * @copydoc PDMDRVHLP::pfnTMGetVirtualFreq + */ +DECLINLINE(uint64_t) PDMDrvHlpTMGetVirtualFreq(PPDMDRVINS pDrvIns) +{ + return pDrvIns->pHlpR3->pfnTMGetVirtualFreq(pDrvIns); +} + +/** + * @copydoc PDMDRVHLP::pfnTMGetVirtualTime + */ +DECLINLINE(uint64_t) PDMDrvHlpTMGetVirtualTime(PPDMDRVINS pDrvIns) +{ + return pDrvIns->pHlpR3->pfnTMGetVirtualTime(pDrvIns); +} + +/** + * @copydoc PDMDRVHLP::pfnTMTimerCreate + */ +DECLINLINE(int) PDMDrvHlpTMTimerCreate(PPDMDRVINS pDrvIns, TMCLOCK enmClock, PFNTMTIMERDRV pfnCallback, void *pvUser, uint32_t fFlags, const char *pszDesc, PPTMTIMERR3 ppTimer) +{ + return pDrvIns->pHlpR3->pfnTMTimerCreate(pDrvIns, enmClock, pfnCallback, pvUser, fFlags, pszDesc, ppTimer); +} + +/** + * Register a save state data unit. + * + * @returns VBox status. + * @param pDrvIns Driver instance. + * @param uVersion Data layout version number. + * @param cbGuess The approximate amount of data in the unit. + * Only for progress indicators. + * @param pfnSaveExec Execute save callback, optional. + * @param pfnLoadExec Execute load callback, optional. + */ +DECLINLINE(int) PDMDrvHlpSSMRegister(PPDMDRVINS pDrvIns, uint32_t uVersion, size_t cbGuess, + PFNSSMDRVSAVEEXEC pfnSaveExec, PFNSSMDRVLOADEXEC pfnLoadExec) +{ + return pDrvIns->pHlpR3->pfnSSMRegister(pDrvIns, uVersion, cbGuess, + NULL /*pfnLivePrep*/, NULL /*pfnLiveExec*/, NULL /*pfnLiveVote*/, + NULL /*pfnSavePrep*/, pfnSaveExec, NULL /*pfnSaveDone*/, + NULL /*pfnLoadPrep*/, pfnLoadExec, NULL /*pfnLoadDone*/); +} + +/** + * @copydoc PDMDRVHLP::pfnSSMRegister + */ +DECLINLINE(int) PDMDrvHlpSSMRegisterEx(PPDMDRVINS pDrvIns, uint32_t uVersion, size_t cbGuess, + PFNSSMDRVLIVEPREP pfnLivePrep, PFNSSMDRVLIVEEXEC pfnLiveExec, PFNSSMDRVLIVEVOTE pfnLiveVote, + PFNSSMDRVSAVEPREP pfnSavePrep, PFNSSMDRVSAVEEXEC pfnSaveExec, PFNSSMDRVSAVEDONE pfnSaveDone, + PFNSSMDRVLOADPREP pfnLoadPrep, PFNSSMDRVLOADEXEC pfnLoadExec, PFNSSMDRVLOADDONE pfnLoadDone) +{ + return pDrvIns->pHlpR3->pfnSSMRegister(pDrvIns, uVersion, cbGuess, + pfnLivePrep, pfnLiveExec, pfnLiveVote, + pfnSavePrep, pfnSaveExec, pfnSaveDone, + pfnLoadPrep, pfnLoadExec, pfnLoadDone); +} + +/** + * Register a load done callback. + * + * @returns VBox status. + * @param pDrvIns Driver instance. + * @param pfnLoadDone Done load callback, optional. + */ +DECLINLINE(int) PDMDrvHlpSSMRegisterLoadDone(PPDMDRVINS pDrvIns, PFNSSMDRVLOADDONE pfnLoadDone) +{ + return pDrvIns->pHlpR3->pfnSSMRegister(pDrvIns, 0 /*uVersion*/, 0 /*cbGuess*/, + NULL /*pfnLivePrep*/, NULL /*pfnLiveExec*/, NULL /*pfnLiveVote*/, + NULL /*pfnSavePrep*/, NULL /*pfnSaveExec*/, NULL /*pfnSaveDone*/, + NULL /*pfnLoadPrep*/, NULL /*pfnLoadExec*/, pfnLoadDone); +} + +/** + * @copydoc PDMDRVHLP::pfnDBGFInfoRegister + */ +DECLINLINE(int) PDMDrvHlpDBGFInfoRegister(PPDMDRVINS pDrvIns, const char *pszName, const char *pszDesc, PFNDBGFHANDLERDRV pfnHandler) +{ + return pDrvIns->pHlpR3->pfnDBGFInfoRegister(pDrvIns, pszName, pszDesc, pfnHandler); +} + +/** + * @copydoc PDMDRVHLP::pfnDBGFInfoDeregister + */ +DECLINLINE(int) PDMDrvHlpDBGFInfoDeregister(PPDMDRVINS pDrvIns, const char *pszName, const char *pszDesc, PFNDBGFHANDLERDRV pfnHandler) +{ + return pDrvIns->pHlpR3->pfnDBGFInfoRegister(pDrvIns, pszName, pszDesc, pfnHandler); +} + +/** + * @copydoc PDMDRVHLP::pfnSTAMRegister + */ +DECLINLINE(void) PDMDrvHlpSTAMRegister(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType, const char *pszName, STAMUNIT enmUnit, const char *pszDesc) +{ + pDrvIns->pHlpR3->pfnSTAMRegister(pDrvIns, pvSample, enmType, pszName, enmUnit, pszDesc); +} + +/** + * @copydoc PDMDRVHLP::pfnSTAMRegisterF + */ +DECLINLINE(void) PDMDrvHlpSTAMRegisterF(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, + const char *pszDesc, const char *pszName, ...) +{ + va_list va; + va_start(va, pszName); + pDrvIns->pHlpR3->pfnSTAMRegisterV(pDrvIns, pvSample, enmType, enmVisibility, enmUnit, pszDesc, pszName, va); + va_end(va); +} + +/** + * Convenience wrapper that registers counter which is always visible. + * + * @param pDrvIns The driver instance. + * @param pCounter Pointer to the counter variable. + * @param pszName The name of the sample. This is prefixed with + * "/Drivers/<drivername>-<instance no>/". + * @param enmUnit The unit. + * @param pszDesc The description. + */ +DECLINLINE(void) PDMDrvHlpSTAMRegCounterEx(PPDMDRVINS pDrvIns, PSTAMCOUNTER pCounter, const char *pszName, STAMUNIT enmUnit, const char *pszDesc) +{ + pDrvIns->pHlpR3->pfnSTAMRegisterF(pDrvIns, pCounter, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, enmUnit, pszDesc, + "/Drivers/%s-%u/%s", pDrvIns->pReg->szName, pDrvIns->iInstance, pszName); +} + +/** + * Convenience wrapper that registers counter which is always visible and has + * the STAMUNIT_COUNT unit. + * + * @param pDrvIns The driver instance. + * @param pCounter Pointer to the counter variable. + * @param pszName The name of the sample. This is prefixed with + * "/Drivers/<drivername>-<instance no>/". + * @param pszDesc The description. + */ +DECLINLINE(void) PDMDrvHlpSTAMRegCounter(PPDMDRVINS pDrvIns, PSTAMCOUNTER pCounter, const char *pszName, const char *pszDesc) +{ + PDMDrvHlpSTAMRegCounterEx(pDrvIns, pCounter, pszName, STAMUNIT_COUNT, pszDesc); +} + +/** + * Convenience wrapper that registers profiling sample which is always visible. + * + * @param pDrvIns The driver instance. + * @param pProfile Pointer to the profiling variable. + * @param pszName The name of the sample. This is prefixed with + * "/Drivers/<drivername>-<instance no>/". + * @param enmUnit The unit. + * @param pszDesc The description. + */ +DECLINLINE(void) PDMDrvHlpSTAMRegProfileEx(PPDMDRVINS pDrvIns, PSTAMPROFILE pProfile, const char *pszName, STAMUNIT enmUnit, const char *pszDesc) +{ + pDrvIns->pHlpR3->pfnSTAMRegisterF(pDrvIns, pProfile, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, enmUnit, pszDesc, + "/Drivers/%s-%u/%s", pDrvIns->pReg->szName, pDrvIns->iInstance, pszName); +} + +/** + * Convenience wrapper that registers profiling sample which is always visible + * hand counts ticks per call (STAMUNIT_TICKS_PER_CALL). + * + * @param pDrvIns The driver instance. + * @param pProfile Pointer to the profiling variable. + * @param pszName The name of the sample. This is prefixed with + * "/Drivers/<drivername>-<instance no>/". + * @param pszDesc The description. + */ +DECLINLINE(void) PDMDrvHlpSTAMRegProfile(PPDMDRVINS pDrvIns, PSTAMPROFILE pProfile, const char *pszName, const char *pszDesc) +{ + PDMDrvHlpSTAMRegProfileEx(pDrvIns, pProfile, pszName, STAMUNIT_TICKS_PER_CALL, pszDesc); +} + +/** + * Convenience wrapper that registers an advanced profiling sample which is + * always visible. + * + * @param pDrvIns The driver instance. + * @param pProfile Pointer to the profiling variable. + * @param enmUnit The unit. + * @param pszName The name of the sample. This is prefixed with + * "/Drivers/<drivername>-<instance no>/". + * @param pszDesc The description. + */ +DECLINLINE(void) PDMDrvHlpSTAMRegProfileAdvEx(PPDMDRVINS pDrvIns, PSTAMPROFILEADV pProfile, const char *pszName, STAMUNIT enmUnit, const char *pszDesc) +{ + pDrvIns->pHlpR3->pfnSTAMRegisterF(pDrvIns, pProfile, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, enmUnit, pszDesc, + "/Drivers/%s-%u/%s", pDrvIns->pReg->szName, pDrvIns->iInstance, pszName); +} + +/** + * Convenience wrapper that registers an advanced profiling sample which is + * always visible. + * + * @param pDrvIns The driver instance. + * @param pProfile Pointer to the profiling variable. + * @param pszName The name of the sample. This is prefixed with + * "/Drivers/<drivername>-<instance no>/". + * @param pszDesc The description. + */ +DECLINLINE(void) PDMDrvHlpSTAMRegProfileAdv(PPDMDRVINS pDrvIns, PSTAMPROFILEADV pProfile, const char *pszName, const char *pszDesc) +{ + PDMDrvHlpSTAMRegProfileAdvEx(pDrvIns, pProfile, pszName, STAMUNIT_TICKS_PER_CALL, pszDesc); +} + +/** + * @copydoc PDMDRVHLP::pfnSTAMDeregister + */ +DECLINLINE(int) PDMDrvHlpSTAMDeregister(PPDMDRVINS pDrvIns, void *pvSample) +{ + return pDrvIns->pHlpR3->pfnSTAMDeregister(pDrvIns, pvSample); +} + +/** + * @copydoc PDMDRVHLP::pfnSUPCallVMMR0Ex + */ +DECLINLINE(int) PDMDrvHlpSUPCallVMMR0Ex(PPDMDRVINS pDrvIns, unsigned uOperation, void *pvArg, unsigned cbArg) +{ + return pDrvIns->pHlpR3->pfnSUPCallVMMR0Ex(pDrvIns, uOperation, pvArg, cbArg); +} + +/** + * @copydoc PDMDRVHLP::pfnUSBRegisterHub + */ +DECLINLINE(int) PDMDrvHlpUSBRegisterHub(PPDMDRVINS pDrvIns, uint32_t fVersions, uint32_t cPorts, PCPDMUSBHUBREG pUsbHubReg, PPCPDMUSBHUBHLP ppUsbHubHlp) +{ + return pDrvIns->pHlpR3->pfnUSBRegisterHub(pDrvIns, fVersions, cPorts, pUsbHubReg, ppUsbHubHlp); +} + +/** + * @copydoc PDMDRVHLP::pfnSetAsyncNotification + */ +DECLINLINE(int) PDMDrvHlpSetAsyncNotification(PPDMDRVINS pDrvIns, PFNPDMDRVASYNCNOTIFY pfnAsyncNotify) +{ + return pDrvIns->pHlpR3->pfnSetAsyncNotification(pDrvIns, pfnAsyncNotify); +} + +/** + * @copydoc PDMDRVHLP::pfnAsyncNotificationCompleted + */ +DECLINLINE(void) PDMDrvHlpAsyncNotificationCompleted(PPDMDRVINS pDrvIns) +{ + pDrvIns->pHlpR3->pfnAsyncNotificationCompleted(pDrvIns); +} + +/** + * @copydoc PDMDRVHLP::pfnThreadCreate + */ +DECLINLINE(int) PDMDrvHlpThreadCreate(PPDMDRVINS pDrvIns, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADDRV pfnThread, + PFNPDMTHREADWAKEUPDRV pfnWakeup, size_t cbStack, RTTHREADTYPE enmType, const char *pszName) +{ + return pDrvIns->pHlpR3->pfnThreadCreate(pDrvIns, ppThread, pvUser, pfnThread, pfnWakeup, cbStack, enmType, pszName); +} + +# ifdef VBOX_WITH_PDM_ASYNC_COMPLETION +/** + * @copydoc PDMDRVHLP::pfnAsyncCompletionTemplateCreate + */ +DECLINLINE(int) PDMDrvHlpAsyncCompletionTemplateCreate(PPDMDRVINS pDrvIns, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate, + PFNPDMASYNCCOMPLETEDRV pfnCompleted, void *pvTemplateUser, const char *pszDesc) +{ + return pDrvIns->pHlpR3->pfnAsyncCompletionTemplateCreate(pDrvIns, ppTemplate, pfnCompleted, pvTemplateUser, pszDesc); +} +# endif + +# ifdef VBOX_WITH_NETSHAPER +/** + * @copydoc PDMDRVHLP::pfnNetShaperAttach + */ +DECLINLINE(int) PDMDrvHlpNetShaperAttach(PPDMDRVINS pDrvIns, const char *pcszBwGroup, PPDMNSFILTER pFilter) +{ + return pDrvIns->pHlpR3->pfnNetShaperAttach(pDrvIns, pcszBwGroup, pFilter); +} + +/** + * @copydoc PDMDRVHLP::pfnNetShaperDetach + */ +DECLINLINE(int) PDMDrvHlpNetShaperDetach(PPDMDRVINS pDrvIns, PPDMNSFILTER pFilter) +{ + return pDrvIns->pHlpR3->pfnNetShaperDetach(pDrvIns, pFilter); +} +# endif + +/** + * @copydoc PDMDRVHLP::pfnCritSectInit + */ +DECLINLINE(int) PDMDrvHlpCritSectInit(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, RT_SRC_POS_DECL, const char *pszName) +{ + return pDrvIns->pHlpR3->pfnCritSectInit(pDrvIns, pCritSect, RT_SRC_POS_ARGS, pszName); +} + +/** + * @copydoc PDMDRVHLP::pfnCallR0 + */ +DECLINLINE(int) PDMDrvHlpCallR0(PPDMDRVINS pDrvIns, uint32_t uOperation, uint64_t u64Arg) +{ + return pDrvIns->pHlpR3->pfnCallR0(pDrvIns, uOperation, u64Arg); +} + +/** + * @copydoc PDMDRVHLP::pfnBlkCacheRetain + */ +DECLINLINE(int) PDMDrvHlpBlkCacheRetain(PPDMDRVINS pDrvIns, PPPDMBLKCACHE ppBlkCache, + PFNPDMBLKCACHEXFERCOMPLETEDRV pfnXferComplete, + PFNPDMBLKCACHEXFERENQUEUEDRV pfnXferEnqueue, + PFNPDMBLKCACHEXFERENQUEUEDISCARDDRV pfnXferEnqueueDiscard, + const char *pcszId) +{ + return pDrvIns->pHlpR3->pfnBlkCacheRetain(pDrvIns, ppBlkCache, pfnXferComplete, pfnXferEnqueue, pfnXferEnqueueDiscard, pcszId); +} + +/** Pointer to callbacks provided to the VBoxDriverRegister() call. */ +typedef struct PDMDRVREGCB *PPDMDRVREGCB; +/** Pointer to const callbacks provided to the VBoxDriverRegister() call. */ +typedef const struct PDMDRVREGCB *PCPDMDRVREGCB; + +/** + * Callbacks for VBoxDriverRegister(). + */ +typedef struct PDMDRVREGCB +{ + /** Interface version. + * This is set to PDM_DRVREG_CB_VERSION. */ + uint32_t u32Version; + + /** + * Registers a driver with the current VM instance. + * + * @returns VBox status code. + * @param pCallbacks Pointer to the callback table. + * @param pReg Pointer to the driver registration record. + * This data must be permanent and readonly. + */ + DECLR3CALLBACKMEMBER(int, pfnRegister,(PCPDMDRVREGCB pCallbacks, PCPDMDRVREG pReg)); +} PDMDRVREGCB; + +/** Current version of the PDMDRVREGCB structure. */ +#define PDM_DRVREG_CB_VERSION PDM_VERSION_MAKE(0xf0fa, 1, 0) + + +/** + * The VBoxDriverRegister callback function. + * + * PDM will invoke this function after loading a driver module and letting + * the module decide which drivers to register and how to handle conflicts. + * + * @returns VBox status code. + * @param pCallbacks Pointer to the callback table. + * @param u32Version VBox version number. + */ +typedef DECLCALLBACK(int) FNPDMVBOXDRIVERSREGISTER(PCPDMDRVREGCB pCallbacks, uint32_t u32Version); + +VMMR3DECL(int) PDMR3DrvStaticRegistration(PVM pVM, FNPDMVBOXDRIVERSREGISTER pfnCallback); + +#endif /* IN_RING3 */ + +/** @} */ + +RT_C_DECLS_END + +#endif diff --git a/include/VBox/vmm/pdmifs.h b/include/VBox/vmm/pdmifs.h new file mode 100644 index 00000000..17dba105 --- /dev/null +++ b/include/VBox/vmm/pdmifs.h @@ -0,0 +1,2996 @@ +/** @file + * PDM - Pluggable Device Manager, Interfaces. + */ + +/* + * Copyright (C) 2006-2012 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_pdmifs_h +#define ___VBox_vmm_pdmifs_h + +#include <iprt/sg.h> +#include <VBox/types.h> +#include <VBox/hgcmsvc.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_interfaces The PDM Interface Definitions + * @ingroup grp_pdm + * + * For historical reasons (the PDMINTERFACE enum) a lot of interface was stuffed + * together in this group instead, dragging stuff into global space that didn't + * need to be there and making this file huge (>2500 lines). Since we're using + * UUIDs as interface identifiers (IIDs) now, no only generic PDM interface will + * be added to this file. Component specific interface should be defined in the + * header file of that component. + * + * Interfaces consists of a method table (typedef'ed struct) and an interface + * ID. The typename of the method table should have an 'I' in it, be all + * capitals and according to the rules, no underscores. The interface ID is a + * \#define constructed by appending '_IID' to the typename. The IID value is a + * UUID string on the form "a2299c0d-b709-4551-aa5a-73f59ffbed74". If you stick + * to these rules, you can make use of the PDMIBASE_QUERY_INTERFACE and + * PDMIBASE_RETURN_INTERFACE when querying interface and implementing + * PDMIBASE::pfnQueryInterface respectively. + * + * In most interface descriptions the orientation of the interface is given as + * 'down' or 'up'. This refers to a model with the device on the top and the + * drivers stacked below it. Sometimes there is mention of 'main' or 'external' + * which normally means the same, i.e. the Main or VBoxBFE API. Picture the + * orientation of 'main' as horizontal. + * + * @{ + */ + + +/** @name PDMIBASE + * @{ + */ + +/** + * PDM Base Interface. + * + * Everyone implements this. + */ +typedef struct PDMIBASE +{ + /** + * Queries an interface to the driver. + * + * @returns Pointer to interface. + * @returns NULL if the interface was not supported by the driver. + * @param pInterface Pointer to this interface structure. + * @param pszIID The interface ID, a UUID string. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(void *, pfnQueryInterface,(struct PDMIBASE *pInterface, const char *pszIID)); +} PDMIBASE; +/** PDMIBASE interface ID. */ +#define PDMIBASE_IID "a2299c0d-b709-4551-aa5a-73f59ffbed74" + +/** + * Helper macro for querying an interface from PDMIBASE. + * + * @returns Correctly typed PDMIBASE::pfnQueryInterface return value. + * + * @param pIBase Pointer to the base interface. + * @param InterfaceType The interface type name. The interface ID is + * derived from this by appending _IID. + */ +#define PDMIBASE_QUERY_INTERFACE(pIBase, InterfaceType) \ + ( (InterfaceType *)(pIBase)->pfnQueryInterface(pIBase, InterfaceType##_IID ) ) + +/** + * Helper macro for implementing PDMIBASE::pfnQueryInterface. + * + * Return @a pInterface if @a pszIID matches the @a InterfaceType. This will + * perform basic type checking. + * + * @param pszIID The ID of the interface that is being queried. + * @param InterfaceType The interface type name. The interface ID is + * derived from this by appending _IID. + * @param pInterface The interface address expression. + */ +#define PDMIBASE_RETURN_INTERFACE(pszIID, InterfaceType, pInterface) \ + do { \ + if (RTUuidCompare2Strs((pszIID), InterfaceType##_IID) == 0) \ + { \ + P##InterfaceType pReturnInterfaceTypeCheck = (pInterface); \ + return pReturnInterfaceTypeCheck; \ + } \ + } while (0) + +/** @} */ + + +/** @name PDMIBASERC + * @{ + */ + +/** + * PDM Base Interface for querying ring-mode context interfaces in + * ring-3. + * + * This is mandatory for drivers present in raw-mode context. + */ +typedef struct PDMIBASERC +{ + /** + * Queries an ring-mode context interface to the driver. + * + * @returns Pointer to interface. + * @returns NULL if the interface was not supported by the driver. + * @param pInterface Pointer to this interface structure. + * @param pszIID The interface ID, a UUID string. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(RTRCPTR, pfnQueryInterface,(struct PDMIBASERC *pInterface, const char *pszIID)); +} PDMIBASERC; +/** Pointer to a PDM Base Interface for query ring-mode context interfaces. */ +typedef PDMIBASERC *PPDMIBASERC; +/** PDMIBASERC interface ID. */ +#define PDMIBASERC_IID "f6a6c649-6cb3-493f-9737-4653f221aeca" + +/** + * Helper macro for querying an interface from PDMIBASERC. + * + * @returns PDMIBASERC::pfnQueryInterface return value. + * + * @param pIBaseRC Pointer to the base raw-mode context interface. Can + * be NULL. + * @param InterfaceType The interface type base name, no trailing RC. The + * interface ID is derived from this by appending _IID. + * + * @remarks Unlike PDMIBASE_QUERY_INTERFACE, this macro is not able to do any + * implicit type checking for you. + */ +#define PDMIBASERC_QUERY_INTERFACE(pIBaseRC, InterfaceType) \ + ( (P##InterfaceType##RC)((pIBaseRC) ? (pIBaseRC)->pfnQueryInterface(pIBaseRC, InterfaceType##_IID) : NIL_RTRCPTR) ) + +/** + * Helper macro for implementing PDMIBASERC::pfnQueryInterface. + * + * Return @a pInterface if @a pszIID matches the @a InterfaceType. This will + * perform basic type checking. + * + * @param pIns Pointer to the instance data. + * @param pszIID The ID of the interface that is being queried. + * @param InterfaceType The interface type base name, no trailing RC. The + * interface ID is derived from this by appending _IID. + * @param pInterface The interface address expression. This must resolve + * to some address within the instance data. + * @remarks Don't use with PDMIBASE. + */ +#define PDMIBASERC_RETURN_INTERFACE(pIns, pszIID, InterfaceType, pInterface) \ + do { \ + Assert((uintptr_t)pInterface - PDMINS_2_DATA(pIns, uintptr_t) < _4M); \ + if (RTUuidCompare2Strs((pszIID), InterfaceType##_IID) == 0) \ + { \ + InterfaceType##RC *pReturnInterfaceTypeCheck = (pInterface); \ + return (uintptr_t)pReturnInterfaceTypeCheck \ + - PDMINS_2_DATA(pIns, uintptr_t) \ + + PDMINS_2_DATA_RCPTR(pIns); \ + } \ + } while (0) + +/** @} */ + + +/** @name PDMIBASER0 + * @{ + */ + +/** + * PDM Base Interface for querying ring-0 interfaces in ring-3. + * + * This is mandatory for drivers present in ring-0 context. + */ +typedef struct PDMIBASER0 +{ + /** + * Queries an ring-0 interface to the driver. + * + * @returns Pointer to interface. + * @returns NULL if the interface was not supported by the driver. + * @param pInterface Pointer to this interface structure. + * @param pszIID The interface ID, a UUID string. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(RTR0PTR, pfnQueryInterface,(struct PDMIBASER0 *pInterface, const char *pszIID)); +} PDMIBASER0; +/** Pointer to a PDM Base Interface for query ring-0 context interfaces. */ +typedef PDMIBASER0 *PPDMIBASER0; +/** PDMIBASER0 interface ID. */ +#define PDMIBASER0_IID "9c9b99b8-7f53-4f59-a3c2-5bc9659c7944" + +/** + * Helper macro for querying an interface from PDMIBASER0. + * + * @returns PDMIBASER0::pfnQueryInterface return value. + * + * @param pIBaseR0 Pointer to the base ring-0 interface. Can be NULL. + * @param InterfaceType The interface type base name, no trailing R0. The + * interface ID is derived from this by appending _IID. + * + * @remarks Unlike PDMIBASE_QUERY_INTERFACE, this macro is not able to do any + * implicit type checking for you. + */ +#define PDMIBASER0_QUERY_INTERFACE(pIBaseR0, InterfaceType) \ + ( (P##InterfaceType##R0)((pIBaseR0) ? (pIBaseR0)->pfnQueryInterface(pIBaseR0, InterfaceType##_IID) : NIL_RTR0PTR) ) + +/** + * Helper macro for implementing PDMIBASER0::pfnQueryInterface. + * + * Return @a pInterface if @a pszIID matches the @a InterfaceType. This will + * perform basic type checking. + * + * @param pIns Pointer to the instance data. + * @param pszIID The ID of the interface that is being queried. + * @param InterfaceType The interface type base name, no trailing R0. The + * interface ID is derived from this by appending _IID. + * @param pInterface The interface address expression. This must resolve + * to some address within the instance data. + * @remarks Don't use with PDMIBASE. + */ +#define PDMIBASER0_RETURN_INTERFACE(pIns, pszIID, InterfaceType, pInterface) \ + do { \ + Assert((uintptr_t)pInterface - PDMINS_2_DATA(pIns, uintptr_t) < _4M); \ + if (RTUuidCompare2Strs((pszIID), InterfaceType##_IID) == 0) \ + { \ + InterfaceType##R0 *pReturnInterfaceTypeCheck = (pInterface); \ + return (uintptr_t)pReturnInterfaceTypeCheck \ + - PDMINS_2_DATA(pIns, uintptr_t) \ + + PDMINS_2_DATA_R0PTR(pIns); \ + } \ + } while (0) + +/** @} */ + + +/** + * Dummy interface. + * + * This is used to typedef other dummy interfaces. The purpose of a dummy + * interface is to validate the logical function of a driver/device and + * full a natural interface pair. + */ +typedef struct PDMIDUMMY +{ + RTHCPTR pvDummy; +} PDMIDUMMY; + + +/** Pointer to a mouse port interface. */ +typedef struct PDMIMOUSEPORT *PPDMIMOUSEPORT; +/** + * Mouse port interface (down). + * Pair with PDMIMOUSECONNECTOR. + */ +typedef struct PDMIMOUSEPORT +{ + /** + * Puts a mouse event. + * + * This is called by the source of mouse events. The event will be passed up + * until the topmost driver, which then calls the registered event handler. + * + * @returns VBox status code. Return VERR_TRY_AGAIN if you cannot process the + * event now and want it to be repeated at a later point. + * + * @param pInterface Pointer to this interface structure. + * @param iDeltaX The X delta. + * @param iDeltaY The Y delta. + * @param iDeltaZ The Z delta. + * @param iDeltaW The W (horizontal scroll button) delta. + * @param fButtonStates The button states, see the PDMIMOUSEPORT_BUTTON_* \#defines. + */ + DECLR3CALLBACKMEMBER(int, pfnPutEvent,(PPDMIMOUSEPORT pInterface, int32_t iDeltaX, int32_t iDeltaY, int32_t iDeltaZ, int32_t iDeltaW, uint32_t fButtonStates)); + /** + * Puts an absolute mouse event. + * + * This is called by the source of mouse events. The event will be passed up + * until the topmost driver, which then calls the registered event handler. + * + * @returns VBox status code. Return VERR_TRY_AGAIN if you cannot process the + * event now and want it to be repeated at a later point. + * + * @param pInterface Pointer to this interface structure. + * @param uX The X value, in the range 0 to 0xffff. + * @param uY The Y value, in the range 0 to 0xffff. + * @param iDeltaZ The Z delta. + * @param iDeltaW The W (horizontal scroll button) delta. + * @param fButtonStates The button states, see the PDMIMOUSEPORT_BUTTON_* \#defines. + */ + DECLR3CALLBACKMEMBER(int, pfnPutEventAbs,(PPDMIMOUSEPORT pInterface, uint32_t uX, uint32_t uY, int32_t iDeltaZ, int32_t iDeltaW, uint32_t fButtonStates)); +} PDMIMOUSEPORT; +/** PDMIMOUSEPORT interface ID. */ +#define PDMIMOUSEPORT_IID "442136fe-6f3c-49ec-9964-259b378ffa64" + +/** Mouse button defines for PDMIMOUSEPORT::pfnPutEvent. + * @{ */ +#define PDMIMOUSEPORT_BUTTON_LEFT RT_BIT(0) +#define PDMIMOUSEPORT_BUTTON_RIGHT RT_BIT(1) +#define PDMIMOUSEPORT_BUTTON_MIDDLE RT_BIT(2) +#define PDMIMOUSEPORT_BUTTON_X1 RT_BIT(3) +#define PDMIMOUSEPORT_BUTTON_X2 RT_BIT(4) +/** @} */ + + +/** Pointer to a mouse connector interface. */ +typedef struct PDMIMOUSECONNECTOR *PPDMIMOUSECONNECTOR; +/** + * Mouse connector interface (up). + * Pair with PDMIMOUSEPORT. + */ +typedef struct PDMIMOUSECONNECTOR +{ + /** + * Notifies the the downstream driver of changes to the reporting modes + * supported by the driver + * + * @param pInterface Pointer to the this interface. + * @param fRelative Whether relative mode is currently supported. + * @param fAbsolute Whether absolute mode is currently supported. + */ + DECLR3CALLBACKMEMBER(void, pfnReportModes,(PPDMIMOUSECONNECTOR pInterface, bool fRelative, bool fAbsolute)); + +} PDMIMOUSECONNECTOR; +/** PDMIMOUSECONNECTOR interface ID. */ +#define PDMIMOUSECONNECTOR_IID "ce64d7bd-fa8f-41d1-a6fb-d102a2d6bffe" + + +/** Pointer to a keyboard port interface. */ +typedef struct PDMIKEYBOARDPORT *PPDMIKEYBOARDPORT; +/** + * Keyboard port interface (down). + * Pair with PDMIKEYBOARDCONNECTOR. + */ +typedef struct PDMIKEYBOARDPORT +{ + /** + * Puts a keyboard event. + * + * This is called by the source of keyboard events. The event will be passed up + * until the topmost driver, which then calls the registered event handler. + * + * @returns VBox status code. Return VERR_TRY_AGAIN if you cannot process the + * event now and want it to be repeated at a later point. + * + * @param pInterface Pointer to this interface structure. + * @param u8KeyCode The keycode to queue. + */ + DECLR3CALLBACKMEMBER(int, pfnPutEvent,(PPDMIKEYBOARDPORT pInterface, uint8_t u8KeyCode)); +} PDMIKEYBOARDPORT; +/** PDMIKEYBOARDPORT interface ID. */ +#define PDMIKEYBOARDPORT_IID "2a0844f0-410b-40ab-a6ed-6575f3aa3e29" + + +/** + * Keyboard LEDs. + */ +typedef enum PDMKEYBLEDS +{ + /** No leds. */ + PDMKEYBLEDS_NONE = 0x0000, + /** Num Lock */ + PDMKEYBLEDS_NUMLOCK = 0x0001, + /** Caps Lock */ + PDMKEYBLEDS_CAPSLOCK = 0x0002, + /** Scroll Lock */ + PDMKEYBLEDS_SCROLLLOCK = 0x0004 +} PDMKEYBLEDS; + +/** Pointer to keyboard connector interface. */ +typedef struct PDMIKEYBOARDCONNECTOR *PPDMIKEYBOARDCONNECTOR; +/** + * Keyboard connector interface (up). + * Pair with PDMIKEYBOARDPORT + */ +typedef struct PDMIKEYBOARDCONNECTOR +{ + /** + * Notifies the the downstream driver about an LED change initiated by the guest. + * + * @param pInterface Pointer to the this interface. + * @param enmLeds The new led mask. + */ + DECLR3CALLBACKMEMBER(void, pfnLedStatusChange,(PPDMIKEYBOARDCONNECTOR pInterface, PDMKEYBLEDS enmLeds)); + + /** + * Notifies the the downstream driver of changes in driver state. + * + * @param pInterface Pointer to the this interface. + * @param fActive Whether interface wishes to get "focus". + */ + DECLR3CALLBACKMEMBER(void, pfnSetActive,(PPDMIKEYBOARDCONNECTOR pInterface, bool fActive)); + +} PDMIKEYBOARDCONNECTOR; +/** PDMIKEYBOARDCONNECTOR interface ID. */ +#define PDMIKEYBOARDCONNECTOR_IID "db3f7bd5-953e-436f-9f8e-077905a92d82" + + + +/** Pointer to a display port interface. */ +typedef struct PDMIDISPLAYPORT *PPDMIDISPLAYPORT; +/** + * Display port interface (down). + * Pair with PDMIDISPLAYCONNECTOR. + */ +typedef struct PDMIDISPLAYPORT +{ + /** + * Update the display with any changed regions. + * + * Flushes any display changes to the memory pointed to by the + * PDMIDISPLAYCONNECTOR interface and calles PDMIDISPLAYCONNECTOR::pfnUpdateRect() + * while doing so. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnUpdateDisplay,(PPDMIDISPLAYPORT pInterface)); + + /** + * Update the entire display. + * + * Flushes the entire display content to the memory pointed to by the + * PDMIDISPLAYCONNECTOR interface and calles PDMIDISPLAYCONNECTOR::pfnUpdateRect(). + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnUpdateDisplayAll,(PPDMIDISPLAYPORT pInterface)); + + /** + * Return the current guest color depth in bits per pixel (bpp). + * + * As the graphics card is able to provide display updates with the bpp + * requested by the host, this method can be used to query the actual + * guest color depth. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pcBits Where to store the current guest color depth. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryColorDepth,(PPDMIDISPLAYPORT pInterface, uint32_t *pcBits)); + + /** + * Sets the refresh rate and restart the timer. + * The rate is defined as the minimum interval between the return of + * one PDMIDISPLAYPORT::pfnRefresh() call to the next one. + * + * The interval timer will be restarted by this call. So at VM startup + * this function must be called to start the refresh cycle. The refresh + * rate is not saved, but have to be when resuming a loaded VM state. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param cMilliesInterval Number of millis between two refreshes. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnSetRefreshRate,(PPDMIDISPLAYPORT pInterface, uint32_t cMilliesInterval)); + + /** + * Create a 32-bbp screenshot of the display. + * + * This will allocate and return a 32-bbp bitmap. Size of the bitmap scanline in bytes is 4*width. + * + * The allocated bitmap buffer must be freed with pfnFreeScreenshot. + * + * @param pInterface Pointer to this interface. + * @param ppu8Data Where to store the pointer to the allocated buffer. + * @param pcbData Where to store the actual size of the bitmap. + * @param pcx Where to store the width of the bitmap. + * @param pcy Where to store the height of the bitmap. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnTakeScreenshot,(PPDMIDISPLAYPORT pInterface, uint8_t **ppu8Data, size_t *pcbData, uint32_t *pcx, uint32_t *pcy)); + + /** + * Free screenshot buffer. + * + * This will free the memory buffer allocated by pfnTakeScreenshot. + * + * @param pInterface Pointer to this interface. + * @param ppu8Data Pointer to the buffer returned by pfnTakeScreenshot. + * @thread Any. + */ + DECLR3CALLBACKMEMBER(void, pfnFreeScreenshot,(PPDMIDISPLAYPORT pInterface, uint8_t *pu8Data)); + + /** + * Copy bitmap to the display. + * + * This will convert and copy a 32-bbp bitmap (with dword aligned scanline length) to + * the memory pointed to by the PDMIDISPLAYCONNECTOR interface. + * + * @param pInterface Pointer to this interface. + * @param pvData Pointer to the bitmap bits. + * @param x The upper left corner x coordinate of the destination rectangle. + * @param y The upper left corner y coordinate of the destination rectangle. + * @param cx The width of the source and destination rectangles. + * @param cy The height of the source and destination rectangles. + * @thread The emulation thread. + * @remark This is just a convenience for using the bitmap conversions of the + * graphics device. + */ + DECLR3CALLBACKMEMBER(int, pfnDisplayBlt,(PPDMIDISPLAYPORT pInterface, const void *pvData, uint32_t x, uint32_t y, uint32_t cx, uint32_t cy)); + + /** + * Render a rectangle from guest VRAM to Framebuffer. + * + * @param pInterface Pointer to this interface. + * @param x The upper left corner x coordinate of the rectangle to be updated. + * @param y The upper left corner y coordinate of the rectangle to be updated. + * @param cx The width of the rectangle to be updated. + * @param cy The height of the rectangle to be updated. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnUpdateDisplayRect,(PPDMIDISPLAYPORT pInterface, int32_t x, int32_t y, uint32_t cx, uint32_t cy)); + + /** + * Inform the VGA device whether the Display is directly using the guest VRAM and there is no need + * to render the VRAM to the framebuffer memory. + * + * @param pInterface Pointer to this interface. + * @param fRender Whether the VRAM content must be rendered to the framebuffer. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnSetRenderVRAM,(PPDMIDISPLAYPORT pInterface, bool fRender)); + + /** + * Render a bitmap rectangle from source to target buffer. + * + * @param pInterface Pointer to this interface. + * @param cx The width of the rectangle to be copied. + * @param cy The height of the rectangle to be copied. + * @param pbSrc Source frame buffer 0,0. + * @param xSrc The upper left corner x coordinate of the source rectangle. + * @param ySrc The upper left corner y coordinate of the source rectangle. + * @param cxSrc The width of the source frame buffer. + * @param cySrc The height of the source frame buffer. + * @param cbSrcLine The line length of the source frame buffer. + * @param cSrcBitsPerPixel The pixel depth of the source. + * @param pbDst Destination frame buffer 0,0. + * @param xDst The upper left corner x coordinate of the destination rectangle. + * @param yDst The upper left corner y coordinate of the destination rectangle. + * @param cxDst The width of the destination frame buffer. + * @param cyDst The height of the destination frame buffer. + * @param cbDstLine The line length of the destination frame buffer. + * @param cDstBitsPerPixel The pixel depth of the destination. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnCopyRect,(PPDMIDISPLAYPORT pInterface, uint32_t cx, uint32_t cy, + const uint8_t *pbSrc, int32_t xSrc, int32_t ySrc, uint32_t cxSrc, uint32_t cySrc, uint32_t cbSrcLine, uint32_t cSrcBitsPerPixel, + uint8_t *pbDst, int32_t xDst, int32_t yDst, uint32_t cxDst, uint32_t cyDst, uint32_t cbDstLine, uint32_t cDstBitsPerPixel)); + +} PDMIDISPLAYPORT; +/** PDMIDISPLAYPORT interface ID. */ +#define PDMIDISPLAYPORT_IID "22d3d93d-3407-487a-8308-85367eae00bb" + + +typedef struct VBOXVHWACMD *PVBOXVHWACMD; /**< @todo r=bird: A line what it is to make doxygen happy. */ +typedef struct VBVACMDHDR *PVBVACMDHDR; +typedef struct VBVAINFOSCREEN *PVBVAINFOSCREEN; +typedef struct VBVAINFOVIEW *PVBVAINFOVIEW; +typedef struct VBVAHOSTFLAGS *PVBVAHOSTFLAGS; +typedef struct VBOXVDMACMD_CHROMIUM_CMD *PVBOXVDMACMD_CHROMIUM_CMD; /* <- chromium [hgsmi] command */ +typedef struct VBOXVDMACMD_CHROMIUM_CTL *PVBOXVDMACMD_CHROMIUM_CTL; /* <- chromium [hgsmi] command */ + +/** Pointer to a display connector interface. */ +typedef struct PDMIDISPLAYCONNECTOR *PPDMIDISPLAYCONNECTOR; +/** + * Display connector interface (up). + * Pair with PDMIDISPLAYPORT. + */ +typedef struct PDMIDISPLAYCONNECTOR +{ + /** + * Resize the display. + * This is called when the resolution changes. This usually happens on + * request from the guest os, but may also happen as the result of a reset. + * If the callback returns VINF_VGA_RESIZE_IN_PROGRESS, the caller (VGA device) + * must not access the connector and return. + * + * @returns VINF_SUCCESS if the framebuffer resize was completed, + * VINF_VGA_RESIZE_IN_PROGRESS if resize takes time and not yet finished. + * @param pInterface Pointer to this interface. + * @param cBits Color depth (bits per pixel) of the new video mode. + * @param pvVRAM Address of the guest VRAM. + * @param cbLine Size in bytes of a single scan line. + * @param cx New display width. + * @param cy New display height. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnResize,(PPDMIDISPLAYCONNECTOR pInterface, uint32_t cBits, void *pvVRAM, uint32_t cbLine, uint32_t cx, uint32_t cy)); + + /** + * Update a rectangle of the display. + * PDMIDISPLAYPORT::pfnUpdateDisplay is the caller. + * + * @param pInterface Pointer to this interface. + * @param x The upper left corner x coordinate of the rectangle. + * @param y The upper left corner y coordinate of the rectangle. + * @param cx The width of the rectangle. + * @param cy The height of the rectangle. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnUpdateRect,(PPDMIDISPLAYCONNECTOR pInterface, uint32_t x, uint32_t y, uint32_t cx, uint32_t cy)); + + /** + * Refresh the display. + * + * The interval between these calls is set by + * PDMIDISPLAYPORT::pfnSetRefreshRate(). The driver should call + * PDMIDISPLAYPORT::pfnUpdateDisplay() if it wishes to refresh the + * display. PDMIDISPLAYPORT::pfnUpdateDisplay calls pfnUpdateRect with + * the changed rectangles. + * + * @param pInterface Pointer to this interface. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnRefresh,(PPDMIDISPLAYCONNECTOR pInterface)); + + /** + * Reset the display. + * + * Notification message when the graphics card has been reset. + * + * @param pInterface Pointer to this interface. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnReset,(PPDMIDISPLAYCONNECTOR pInterface)); + + /** + * LFB video mode enter/exit. + * + * Notification message when LinearFrameBuffer video mode is enabled/disabled. + * + * @param pInterface Pointer to this interface. + * @param fEnabled false - LFB mode was disabled, + * true - an LFB mode was disabled + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnLFBModeChange, (PPDMIDISPLAYCONNECTOR pInterface, bool fEnabled)); + + /** + * Process the guest graphics adapter information. + * + * Direct notification from guest to the display connector. + * + * @param pInterface Pointer to this interface. + * @param pvVRAM Address of the guest VRAM. + * @param u32VRAMSize Size of the guest VRAM. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnProcessAdapterData, (PPDMIDISPLAYCONNECTOR pInterface, void *pvVRAM, uint32_t u32VRAMSize)); + + /** + * Process the guest display information. + * + * Direct notification from guest to the display connector. + * + * @param pInterface Pointer to this interface. + * @param pvVRAM Address of the guest VRAM. + * @param uScreenId The index of the guest display to be processed. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnProcessDisplayData, (PPDMIDISPLAYCONNECTOR pInterface, void *pvVRAM, unsigned uScreenId)); + + /** + * Process the guest Video HW Acceleration command. + * + * @param pInterface Pointer to this interface. + * @param pCmd Video HW Acceleration Command to be processed. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnVHWACommandProcess, (PPDMIDISPLAYCONNECTOR pInterface, PVBOXVHWACMD pCmd)); + + /** + * Process the guest chromium command. + * + * @param pInterface Pointer to this interface. + * @param pCmd Video HW Acceleration Command to be processed. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnCrHgsmiCommandProcess, (PPDMIDISPLAYCONNECTOR pInterface, PVBOXVDMACMD_CHROMIUM_CMD pCmd, uint32_t cbCmd)); + + /** + * Process the guest chromium control command. + * + * @param pInterface Pointer to this interface. + * @param pCmd Video HW Acceleration Command to be processed. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnCrHgsmiControlProcess, (PPDMIDISPLAYCONNECTOR pInterface, PVBOXVDMACMD_CHROMIUM_CTL pCtl, uint32_t cbCtl)); + + + /** + * The specified screen enters VBVA mode. + * + * @param pInterface Pointer to this interface. + * @param uScreenId The screen updates are for. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnVBVAEnable,(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId, PVBVAHOSTFLAGS pHostFlags)); + + /** + * The specified screen leaves VBVA mode. + * + * @param pInterface Pointer to this interface. + * @param uScreenId The screen updates are for. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnVBVADisable,(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId)); + + /** + * A sequence of pfnVBVAUpdateProcess calls begins. + * + * @param pInterface Pointer to this interface. + * @param uScreenId The screen updates are for. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnVBVAUpdateBegin,(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId)); + + /** + * Process the guest VBVA command. + * + * @param pInterface Pointer to this interface. + * @param pCmd Video HW Acceleration Command to be processed. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnVBVAUpdateProcess,(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId, const PVBVACMDHDR pCmd, size_t cbCmd)); + + /** + * A sequence of pfnVBVAUpdateProcess calls ends. + * + * @param pInterface Pointer to this interface. + * @param uScreenId The screen updates are for. + * @param x The upper left corner x coordinate of the combined rectangle of all VBVA updates. + * @param y The upper left corner y coordinate of the rectangle. + * @param cx The width of the rectangle. + * @param cy The height of the rectangle. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnVBVAUpdateEnd,(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId, int32_t x, int32_t y, uint32_t cx, uint32_t cy)); + + /** + * Resize the display. + * This is called when the resolution changes. This usually happens on + * request from the guest os, but may also happen as the result of a reset. + * If the callback returns VINF_VGA_RESIZE_IN_PROGRESS, the caller (VGA device) + * must not access the connector and return. + * + * @todo Merge with pfnResize. + * + * @returns VINF_SUCCESS if the framebuffer resize was completed, + * VINF_VGA_RESIZE_IN_PROGRESS if resize takes time and not yet finished. + * @param pInterface Pointer to this interface. + * @param pView The description of VRAM block for this screen. + * @param pScreen The data of screen being resized. + * @param pvVRAM Address of the guest VRAM. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnVBVAResize,(PPDMIDISPLAYCONNECTOR pInterface, const PVBVAINFOVIEW pView, const PVBVAINFOSCREEN pScreen, void *pvVRAM)); + + /** + * Update the pointer shape. + * This is called when the mouse pointer shape changes. The new shape + * is passed as a caller allocated buffer that will be freed after returning + * + * @param pInterface Pointer to this interface. + * @param fVisible Visibility indicator (if false, the other parameters are undefined). + * @param fAlpha Flag whether alpha channel is being passed. + * @param xHot Pointer hot spot x coordinate. + * @param yHot Pointer hot spot y coordinate. + * @param x Pointer new x coordinate on screen. + * @param y Pointer new y coordinate on screen. + * @param cx Pointer width in pixels. + * @param cy Pointer height in pixels. + * @param cbScanline Size of one scanline in bytes. + * @param pvShape New shape buffer. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnVBVAMousePointerShape,(PPDMIDISPLAYCONNECTOR pInterface, bool fVisible, bool fAlpha, + uint32_t xHot, uint32_t yHot, + uint32_t cx, uint32_t cy, + const void *pvShape)); + + /** Read-only attributes. + * For preformance reasons some readonly attributes are kept in the interface. + * We trust the interface users to respect the readonlyness of these. + * @{ + */ + /** Pointer to the display data buffer. */ + uint8_t *pu8Data; + /** Size of a scanline in the data buffer. */ + uint32_t cbScanline; + /** The color depth (in bits) the graphics card is supposed to provide. */ + uint32_t cBits; + /** The display width. */ + uint32_t cx; + /** The display height. */ + uint32_t cy; + /** @} */ +} PDMIDISPLAYCONNECTOR; +/** PDMIDISPLAYCONNECTOR interface ID. */ +#define PDMIDISPLAYCONNECTOR_IID "c7a1b36d-8dfc-421d-b71f-3a0eeaf733e6" + + +/** Pointer to a block port interface. */ +typedef struct PDMIBLOCKPORT *PPDMIBLOCKPORT; +/** + * Block notify interface (down). + * Pair with PDMIBLOCK. + */ +typedef struct PDMIBLOCKPORT +{ + /** + * Returns the storage controller name, instance and LUN of the attached medium. + * + * @returns VBox status. + * @param pInterface Pointer to this interface. + * @param ppcszController Where to store the name of the storage controller. + * @param piInstance Where to store the instance number of the controller. + * @param piLUN Where to store the LUN of the attached device. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryDeviceLocation, (PPDMIBLOCKPORT pInterface, const char **ppcszController, + uint32_t *piInstance, uint32_t *piLUN)); + +} PDMIBLOCKPORT; +/** PDMIBLOCKPORT interface ID. */ +#define PDMIBLOCKPORT_IID "bbbed4cf-0862-4ffd-b60c-f7a65ef8e8ff" + + +/** + * Callback which provides progress information. + * + * @return VBox status code. + * @param pvUser Opaque user data. + * @param uPercent Completion percentage. + */ +typedef DECLCALLBACK(int) FNSIMPLEPROGRESS(void *pvUser, unsigned uPercentage); +/** Pointer to FNSIMPLEPROGRESS() */ +typedef FNSIMPLEPROGRESS *PFNSIMPLEPROGRESS; + + +/** + * Block drive type. + */ +typedef enum PDMBLOCKTYPE +{ + /** Error (for the query function). */ + PDMBLOCKTYPE_ERROR = 1, + /** 360KB 5 1/4" floppy drive. */ + PDMBLOCKTYPE_FLOPPY_360, + /** 720KB 3 1/2" floppy drive. */ + PDMBLOCKTYPE_FLOPPY_720, + /** 1.2MB 5 1/4" floppy drive. */ + PDMBLOCKTYPE_FLOPPY_1_20, + /** 1.44MB 3 1/2" floppy drive. */ + PDMBLOCKTYPE_FLOPPY_1_44, + /** 2.88MB 3 1/2" floppy drive. */ + PDMBLOCKTYPE_FLOPPY_2_88, + /** CDROM drive. */ + PDMBLOCKTYPE_CDROM, + /** DVD drive. */ + PDMBLOCKTYPE_DVD, + /** Hard disk drive. */ + PDMBLOCKTYPE_HARD_DISK +} PDMBLOCKTYPE; + + +/** + * Block raw command data transfer direction. + */ +typedef enum PDMBLOCKTXDIR +{ + PDMBLOCKTXDIR_NONE = 0, + PDMBLOCKTXDIR_FROM_DEVICE, + PDMBLOCKTXDIR_TO_DEVICE +} PDMBLOCKTXDIR; + + +/** Pointer to a block interface. */ +typedef struct PDMIBLOCK *PPDMIBLOCK; +/** + * Block interface (up). + * Pair with PDMIBLOCKPORT. + */ +typedef struct PDMIBLOCK +{ + /** + * Read bits. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param off Offset to start reading from. The offset must be aligned to a sector boundary. + * @param pvBuf Where to store the read bits. + * @param cbRead Number of bytes to read. Must be aligned to a sector boundary. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnRead,(PPDMIBLOCK pInterface, uint64_t off, void *pvBuf, size_t cbRead)); + + /** + * Write bits. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param off Offset to start writing at. The offset must be aligned to a sector boundary. + * @param pvBuf Where to store the write bits. + * @param cbWrite Number of bytes to write. Must be aligned to a sector boundary. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnWrite,(PPDMIBLOCK pInterface, uint64_t off, const void *pvBuf, size_t cbWrite)); + + /** + * Make sure that the bits written are actually on the storage medium. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnFlush,(PPDMIBLOCK pInterface)); + + /** + * Send a raw command to the underlying device (CDROM). + * This method is optional (i.e. the function pointer may be NULL). + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pbCmd Offset to start reading from. + * @param enmTxDir Direction of transfer. + * @param pvBuf Pointer tp the transfer buffer. + * @param cbBuf Size of the transfer buffer. + * @param pbSenseKey Status of the command (when return value is VERR_DEV_IO_ERROR). + * @param cTimeoutMillies Command timeout in milliseconds. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnSendCmd,(PPDMIBLOCK pInterface, const uint8_t *pbCmd, PDMBLOCKTXDIR enmTxDir, void *pvBuf, uint32_t *pcbBuf, uint8_t *pabSense, size_t cbSense, uint32_t cTimeoutMillies)); + + /** + * Merge medium contents during a live snapshot deletion. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pfnProgress Function pointer for progress notification. + * @param pvUser Opaque user data for progress notification. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnMerge,(PPDMIBLOCK pInterface, PFNSIMPLEPROGRESS pfnProgress, void *pvUser)); + + /** + * Check if the media is readonly or not. + * + * @returns true if readonly. + * @returns false if read/write. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(bool, pfnIsReadOnly,(PPDMIBLOCK pInterface)); + + /** + * Gets the media size in bytes. + * + * @returns Media size in bytes. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnGetSize,(PPDMIBLOCK pInterface)); + + /** + * Gets the block drive type. + * + * @returns block drive type. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(PDMBLOCKTYPE, pfnGetType,(PPDMIBLOCK pInterface)); + + /** + * Gets the UUID of the block drive. + * Don't return the media UUID if it's removable. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pUuid Where to store the UUID on success. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnGetUuid,(PPDMIBLOCK pInterface, PRTUUID pUuid)); + + /** + * Discards the given range. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param paRanges Array of ranges to discard. + * @param cRanges Number of entries in the array. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnDiscard,(PPDMIBLOCK pInterface, PCRTRANGE paRanges, unsigned cRanges)); +} PDMIBLOCK; +/** PDMIBLOCK interface ID. */ +#define PDMIBLOCK_IID "5e7123dd-8cdf-4a6e-97a5-ab0c68d7e850" + + +/** Pointer to a mount interface. */ +typedef struct PDMIMOUNTNOTIFY *PPDMIMOUNTNOTIFY; +/** + * Block interface (up). + * Pair with PDMIMOUNT. + */ +typedef struct PDMIMOUNTNOTIFY +{ + /** + * Called when a media is mounted. + * + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnMountNotify,(PPDMIMOUNTNOTIFY pInterface)); + + /** + * Called when a media is unmounted + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnUnmountNotify,(PPDMIMOUNTNOTIFY pInterface)); +} PDMIMOUNTNOTIFY; +/** PDMIMOUNTNOTIFY interface ID. */ +#define PDMIMOUNTNOTIFY_IID "fa143ac9-9fc6-498e-997f-945380a558f9" + + +/** Pointer to mount interface. */ +typedef struct PDMIMOUNT *PPDMIMOUNT; +/** + * Mount interface (down). + * Pair with PDMIMOUNTNOTIFY. + */ +typedef struct PDMIMOUNT +{ + /** + * Mount a media. + * + * This will not unmount any currently mounted media! + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pszFilename Pointer to filename. If this is NULL it assumed that the caller have + * constructed a configuration which can be attached to the bottom driver. + * @param pszCoreDriver Core driver name. NULL will cause autodetection. Ignored if pszFilanem is NULL. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnMount,(PPDMIMOUNT pInterface, const char *pszFilename, const char *pszCoreDriver)); + + /** + * Unmount the media. + * + * The driver will validate and pass it on. On the rebounce it will decide whether or not to detach it self. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread The emulation thread. + * @param fForce Force the unmount, even for locked media. + * @param fEject Eject the medium. Only relevant for host drives. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnUnmount,(PPDMIMOUNT pInterface, bool fForce, bool fEject)); + + /** + * Checks if a media is mounted. + * + * @returns true if mounted. + * @returns false if not mounted. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(bool, pfnIsMounted,(PPDMIMOUNT pInterface)); + + /** + * Locks the media, preventing any unmounting of it. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnLock,(PPDMIMOUNT pInterface)); + + /** + * Unlocks the media, canceling previous calls to pfnLock(). + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnUnlock,(PPDMIMOUNT pInterface)); + + /** + * Checks if a media is locked. + * + * @returns true if locked. + * @returns false if not locked. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(bool, pfnIsLocked,(PPDMIMOUNT pInterface)); +} PDMIMOUNT; +/** PDMIMOUNT interface ID. */ +#define PDMIMOUNT_IID "34fc7a4c-623a-4806-a6bf-5be1be33c99f" + + +/** + * Media geometry structure. + */ +typedef struct PDMMEDIAGEOMETRY +{ + /** Number of cylinders. */ + uint32_t cCylinders; + /** Number of heads. */ + uint32_t cHeads; + /** Number of sectors. */ + uint32_t cSectors; +} PDMMEDIAGEOMETRY; + +/** Pointer to media geometry structure. */ +typedef PDMMEDIAGEOMETRY *PPDMMEDIAGEOMETRY; +/** Pointer to constant media geometry structure. */ +typedef const PDMMEDIAGEOMETRY *PCPDMMEDIAGEOMETRY; + +/** Pointer to a media port interface. */ +typedef struct PDMIMEDIAPORT *PPDMIMEDIAPORT; +/** + * Media port interface (down). + */ +typedef struct PDMIMEDIAPORT +{ + /** + * Returns the storage controller name, instance and LUN of the attached medium. + * + * @returns VBox status. + * @param pInterface Pointer to this interface. + * @param ppcszController Where to store the name of the storage controller. + * @param piInstance Where to store the instance number of the controller. + * @param piLUN Where to store the LUN of the attached device. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryDeviceLocation, (PPDMIMEDIAPORT pInterface, const char **ppcszController, + uint32_t *piInstance, uint32_t *piLUN)); + +} PDMIMEDIAPORT; +/** PDMIMEDIAPORT interface ID. */ +#define PDMIMEDIAPORT_IID "9f7e8c9e-6d35-4453-bbef-1f78033174d6" + +/** Pointer to a media interface. */ +typedef struct PDMIMEDIA *PPDMIMEDIA; +/** + * Media interface (up). + * Makes up the foundation for PDMIBLOCK and PDMIBLOCKBIOS. + * Pairs with PDMIMEDIAPORT. + */ +typedef struct PDMIMEDIA +{ + /** + * Read bits. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param off Offset to start reading from. The offset must be aligned to a sector boundary. + * @param pvBuf Where to store the read bits. + * @param cbRead Number of bytes to read. Must be aligned to a sector boundary. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnRead,(PPDMIMEDIA pInterface, uint64_t off, void *pvBuf, size_t cbRead)); + + /** + * Write bits. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param off Offset to start writing at. The offset must be aligned to a sector boundary. + * @param pvBuf Where to store the write bits. + * @param cbWrite Number of bytes to write. Must be aligned to a sector boundary. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnWrite,(PPDMIMEDIA pInterface, uint64_t off, const void *pvBuf, size_t cbWrite)); + + /** + * Make sure that the bits written are actually on the storage medium. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnFlush,(PPDMIMEDIA pInterface)); + + /** + * Merge medium contents during a live snapshot deletion. All details + * must have been configured through CFGM or this will fail. + * This method is optional (i.e. the function pointer may be NULL). + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pfnProgress Function pointer for progress notification. + * @param pvUser Opaque user data for progress notification. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnMerge,(PPDMIMEDIA pInterface, PFNSIMPLEPROGRESS pfnProgress, void *pvUser)); + + /** + * Get the media size in bytes. + * + * @returns Media size in bytes. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnGetSize,(PPDMIMEDIA pInterface)); + + /** + * Check if the media is readonly or not. + * + * @returns true if readonly. + * @returns false if read/write. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(bool, pfnIsReadOnly,(PPDMIMEDIA pInterface)); + + /** + * Get stored media geometry (physical CHS, PCHS) - BIOS property. + * This is an optional feature of a media. + * + * @returns VBox status code. + * @returns VERR_NOT_IMPLEMENTED if the media doesn't support storing the geometry. + * @returns VERR_PDM_GEOMETRY_NOT_SET if the geometry hasn't been set using pfnBiosSetPCHSGeometry() yet. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pPCHSGeometry Pointer to PCHS geometry (cylinders/heads/sectors). + * @remark This has no influence on the read/write operations. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnBiosGetPCHSGeometry,(PPDMIMEDIA pInterface, PPDMMEDIAGEOMETRY pPCHSGeometry)); + + /** + * Store the media geometry (physical CHS, PCHS) - BIOS property. + * This is an optional feature of a media. + * + * @returns VBox status code. + * @returns VERR_NOT_IMPLEMENTED if the media doesn't support storing the geometry. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pPCHSGeometry Pointer to PCHS geometry (cylinders/heads/sectors). + * @remark This has no influence on the read/write operations. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnBiosSetPCHSGeometry,(PPDMIMEDIA pInterface, PCPDMMEDIAGEOMETRY pPCHSGeometry)); + + /** + * Get stored media geometry (logical CHS, LCHS) - BIOS property. + * This is an optional feature of a media. + * + * @returns VBox status code. + * @returns VERR_NOT_IMPLEMENTED if the media doesn't support storing the geometry. + * @returns VERR_PDM_GEOMETRY_NOT_SET if the geometry hasn't been set using pfnBiosSetLCHSGeometry() yet. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pLCHSGeometry Pointer to LCHS geometry (cylinders/heads/sectors). + * @remark This has no influence on the read/write operations. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnBiosGetLCHSGeometry,(PPDMIMEDIA pInterface, PPDMMEDIAGEOMETRY pLCHSGeometry)); + + /** + * Store the media geometry (logical CHS, LCHS) - BIOS property. + * This is an optional feature of a media. + * + * @returns VBox status code. + * @returns VERR_NOT_IMPLEMENTED if the media doesn't support storing the geometry. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pLCHSGeometry Pointer to LCHS geometry (cylinders/heads/sectors). + * @remark This has no influence on the read/write operations. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnBiosSetLCHSGeometry,(PPDMIMEDIA pInterface, PCPDMMEDIAGEOMETRY pLCHSGeometry)); + + /** + * Gets the UUID of the media drive. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pUuid Where to store the UUID on success. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnGetUuid,(PPDMIMEDIA pInterface, PRTUUID pUuid)); + + /** + * Discards the given range. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param paRanges Array of ranges to discard. + * @param cRanges Number of entries in the array. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnDiscard,(PPDMIMEDIA pInterface, PCRTRANGE paRanges, unsigned cRanges)); + +} PDMIMEDIA; +/** PDMIMEDIA interface ID. */ +#define PDMIMEDIA_IID "ec385d21-7aa9-42ca-8cfb-e1388297fa52" + + +/** Pointer to a block BIOS interface. */ +typedef struct PDMIBLOCKBIOS *PPDMIBLOCKBIOS; +/** + * Media BIOS interface (Up / External). + * The interface the getting and setting properties which the BIOS/CMOS care about. + */ +typedef struct PDMIBLOCKBIOS +{ + /** + * Get stored media geometry (physical CHS, PCHS) - BIOS property. + * This is an optional feature of a media. + * + * @returns VBox status code. + * @returns VERR_NOT_IMPLEMENTED if the media doesn't support storing the geometry. + * @returns VERR_PDM_GEOMETRY_NOT_SET if the geometry hasn't been set using pfnSetPCHSGeometry() yet. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pPCHSGeometry Pointer to PCHS geometry (cylinders/heads/sectors). + * @remark This has no influence on the read/write operations. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnGetPCHSGeometry,(PPDMIBLOCKBIOS pInterface, PPDMMEDIAGEOMETRY pPCHSGeometry)); + + /** + * Store the media geometry (physical CHS, PCHS) - BIOS property. + * This is an optional feature of a media. + * + * @returns VBox status code. + * @returns VERR_NOT_IMPLEMENTED if the media doesn't support storing the geometry. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pPCHSGeometry Pointer to PCHS geometry (cylinders/heads/sectors). + * @remark This has no influence on the read/write operations. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnSetPCHSGeometry,(PPDMIBLOCKBIOS pInterface, PCPDMMEDIAGEOMETRY pPCHSGeometry)); + + /** + * Get stored media geometry (logical CHS, LCHS) - BIOS property. + * This is an optional feature of a media. + * + * @returns VBox status code. + * @returns VERR_NOT_IMPLEMENTED if the media doesn't support storing the geometry. + * @returns VERR_PDM_GEOMETRY_NOT_SET if the geometry hasn't been set using pfnSetLCHSGeometry() yet. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pLCHSGeometry Pointer to LCHS geometry (cylinders/heads/sectors). + * @remark This has no influence on the read/write operations. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnGetLCHSGeometry,(PPDMIBLOCKBIOS pInterface, PPDMMEDIAGEOMETRY pLCHSGeometry)); + + /** + * Store the media geometry (logical CHS, LCHS) - BIOS property. + * This is an optional feature of a media. + * + * @returns VBox status code. + * @returns VERR_NOT_IMPLEMENTED if the media doesn't support storing the geometry. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pLCHSGeometry Pointer to LCHS geometry (cylinders/heads/sectors). + * @remark This has no influence on the read/write operations. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnSetLCHSGeometry,(PPDMIBLOCKBIOS pInterface, PCPDMMEDIAGEOMETRY pLCHSGeometry)); + + /** + * Checks if the device should be visible to the BIOS or not. + * + * @returns true if the device is visible to the BIOS. + * @returns false if the device is not visible to the BIOS. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(bool, pfnIsVisible,(PPDMIBLOCKBIOS pInterface)); + + /** + * Gets the block drive type. + * + * @returns block drive type. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(PDMBLOCKTYPE, pfnGetType,(PPDMIBLOCKBIOS pInterface)); + +} PDMIBLOCKBIOS; +/** PDMIBLOCKBIOS interface ID. */ +#define PDMIBLOCKBIOS_IID "477c3eee-a48d-48a9-82fd-2a54de16b2e9" + + +/** Pointer to a static block core driver interface. */ +typedef struct PDMIMEDIASTATIC *PPDMIMEDIASTATIC; +/** + * Static block core driver interface. + */ +typedef struct PDMIMEDIASTATIC +{ + /** + * Check if the specified file is a format which the core driver can handle. + * + * @returns true / false accordingly. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pszFilename Name of the file to probe. + */ + DECLR3CALLBACKMEMBER(bool, pfnCanHandle,(PPDMIMEDIASTATIC pInterface, const char *pszFilename)); +} PDMIMEDIASTATIC; + + + + + +/** Pointer to an asynchronous block notify interface. */ +typedef struct PDMIBLOCKASYNCPORT *PPDMIBLOCKASYNCPORT; +/** + * Asynchronous block notify interface (up). + * Pair with PDMIBLOCKASYNC. + */ +typedef struct PDMIBLOCKASYNCPORT +{ + /** + * Notify completion of an asynchronous transfer. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pvUser The user argument given in pfnStartWrite/Read. + * @param rcReq IPRT Status code of the completed request. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnTransferCompleteNotify, (PPDMIBLOCKASYNCPORT pInterface, void *pvUser, int rcReq)); +} PDMIBLOCKASYNCPORT; +/** PDMIBLOCKASYNCPORT interface ID. */ +#define PDMIBLOCKASYNCPORT_IID "e3bdc0cb-9d99-41dd-8eec-0dc8cf5b2a92" + + + +/** Pointer to an asynchronous block interface. */ +typedef struct PDMIBLOCKASYNC *PPDMIBLOCKASYNC; +/** + * Asynchronous block interface (down). + * Pair with PDMIBLOCKASYNCPORT. + */ +typedef struct PDMIBLOCKASYNC +{ + /** + * Start reading task. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param off Offset to start reading from.c + * @param paSegs Pointer to the S/G segment array. + * @param cSegs Number of entries in the array. + * @param cbRead Number of bytes to read. Must be aligned to a sector boundary. + * @param pvUser User argument which is returned in completion callback. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnStartRead,(PPDMIBLOCKASYNC pInterface, uint64_t off, PCRTSGSEG paSegs, unsigned cSegs, size_t cbRead, void *pvUser)); + + /** + * Write bits. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param off Offset to start writing at. The offset must be aligned to a sector boundary. + * @param paSegs Pointer to the S/G segment array. + * @param cSegs Number of entries in the array. + * @param cbWrite Number of bytes to write. Must be aligned to a sector boundary. + * @param pvUser User argument which is returned in completion callback. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnStartWrite,(PPDMIBLOCKASYNC pInterface, uint64_t off, PCRTSGSEG paSegs, unsigned cSegs, size_t cbWrite, void *pvUser)); + + /** + * Flush everything to disk. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pvUser User argument which is returned in completion callback. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnStartFlush,(PPDMIBLOCKASYNC pInterface, void *pvUser)); + + /** + * Discards the given range. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param paRanges Array of ranges to discard. + * @param cRanges Number of entries in the array. + * @param pvUser User argument which is returned in completion callback. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnStartDiscard,(PPDMIBLOCKASYNC pInterface, PCRTRANGE paRanges, unsigned cRanges, void *pvUser)); + +} PDMIBLOCKASYNC; +/** PDMIBLOCKASYNC interface ID. */ +#define PDMIBLOCKASYNC_IID "a921dd96-1748-4ecd-941e-d5f3cd4c8fe4" + + +/** Pointer to an asynchronous notification interface. */ +typedef struct PDMIMEDIAASYNCPORT *PPDMIMEDIAASYNCPORT; +/** + * Asynchronous version of the media interface (up). + * Pair with PDMIMEDIAASYNC. + */ +typedef struct PDMIMEDIAASYNCPORT +{ + /** + * Notify completion of a task. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pvUser The user argument given in pfnStartWrite. + * @param rcReq IPRT Status code of the completed request. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnTransferCompleteNotify, (PPDMIMEDIAASYNCPORT pInterface, void *pvUser, int rcReq)); +} PDMIMEDIAASYNCPORT; +/** PDMIMEDIAASYNCPORT interface ID. */ +#define PDMIMEDIAASYNCPORT_IID "22d38853-901f-4a71-9670-4d9da6e82317" + + +/** Pointer to an asynchronous media interface. */ +typedef struct PDMIMEDIAASYNC *PPDMIMEDIAASYNC; +/** + * Asynchronous version of PDMIMEDIA (down). + * Pair with PDMIMEDIAASYNCPORT. + */ +typedef struct PDMIMEDIAASYNC +{ + /** + * Start reading task. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param off Offset to start reading from. Must be aligned to a sector boundary. + * @param paSegs Pointer to the S/G segment array. + * @param cSegs Number of entries in the array. + * @param cbRead Number of bytes to read. Must be aligned to a sector boundary. + * @param pvUser User data. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnStartRead,(PPDMIMEDIAASYNC pInterface, uint64_t off, PCRTSGSEG paSegs, unsigned cSegs, size_t cbRead, void *pvUser)); + + /** + * Start writing task. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param off Offset to start writing at. Must be aligned to a sector boundary. + * @param paSegs Pointer to the S/G segment array. + * @param cSegs Number of entries in the array. + * @param cbWrite Number of bytes to write. Must be aligned to a sector boundary. + * @param pvUser User data. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnStartWrite,(PPDMIMEDIAASYNC pInterface, uint64_t off, PCRTSGSEG paSegs, unsigned cSegs, size_t cbWrite, void *pvUser)); + + /** + * Flush everything to disk. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pvUser User argument which is returned in completion callback. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnStartFlush,(PPDMIMEDIAASYNC pInterface, void *pvUser)); + + /** + * Discards the given range. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param paRanges Array of ranges to discard. + * @param cRanges Number of entries in the array. + * @param pvUser User argument which is returned in completion callback. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnStartDiscard,(PPDMIMEDIAASYNC pInterface, PCRTRANGE paRanges, unsigned cRanges, void *pvUser)); + +} PDMIMEDIAASYNC; +/** PDMIMEDIAASYNC interface ID. */ +#define PDMIMEDIAASYNC_IID "4be209d3-ccb5-4297-82fe-7d8018bc6ab4" + + +/** Pointer to a char port interface. */ +typedef struct PDMICHARPORT *PPDMICHARPORT; +/** + * Char port interface (down). + * Pair with PDMICHARCONNECTOR. + */ +typedef struct PDMICHARPORT +{ + /** + * Deliver data read to the device/driver. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pvBuf Where the read bits are stored. + * @param pcbRead Number of bytes available for reading/having been read. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnNotifyRead,(PPDMICHARPORT pInterface, const void *pvBuf, size_t *pcbRead)); + + /** + * Notify the device/driver when the status lines changed. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param fNewStatusLine New state of the status line pins. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnNotifyStatusLinesChanged,(PPDMICHARPORT pInterface, uint32_t fNewStatusLines)); + + /** + * Notify the device when the driver buffer is full. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param fFull Buffer full. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnNotifyBufferFull,(PPDMICHARPORT pInterface, bool fFull)); + + /** + * Notify the device/driver that a break occurred. + * + * @returns VBox statsus code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnNotifyBreak,(PPDMICHARPORT pInterface)); +} PDMICHARPORT; +/** PDMICHARPORT interface ID. */ +#define PDMICHARPORT_IID "22769834-ea8b-4a6d-ade1-213dcdbd1228" + +/** @name Bit mask definitions for status line type. + * @{ */ +#define PDMICHARPORT_STATUS_LINES_DCD RT_BIT(0) +#define PDMICHARPORT_STATUS_LINES_RI RT_BIT(1) +#define PDMICHARPORT_STATUS_LINES_DSR RT_BIT(2) +#define PDMICHARPORT_STATUS_LINES_CTS RT_BIT(3) +/** @} */ + + +/** Pointer to a char interface. */ +typedef struct PDMICHARCONNECTOR *PPDMICHARCONNECTOR; +/** + * Char connector interface (up). + * Pair with PDMICHARPORT. + */ +typedef struct PDMICHARCONNECTOR +{ + /** + * Write bits. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pvBuf Where to store the write bits. + * @param cbWrite Number of bytes to write. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnWrite,(PPDMICHARCONNECTOR pInterface, const void *pvBuf, size_t cbWrite)); + + /** + * Set device parameters. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param Bps Speed of the serial connection. (bits per second) + * @param chParity Parity method: 'E' - even, 'O' - odd, 'N' - none. + * @param cDataBits Number of data bits. + * @param cStopBits Number of stop bits. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnSetParameters,(PPDMICHARCONNECTOR pInterface, unsigned Bps, char chParity, unsigned cDataBits, unsigned cStopBits)); + + /** + * Set the state of the modem lines. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param fRequestToSend Set to true to make the Request to Send line active otherwise to 0. + * @param fDataTerminalReady Set to true to make the Data Terminal Ready line active otherwise 0. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnSetModemLines,(PPDMICHARCONNECTOR pInterface, bool fRequestToSend, bool fDataTerminalReady)); + + /** + * Sets the TD line into break condition. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param fBreak Set to true to let the device send a break false to put into normal operation. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnSetBreak,(PPDMICHARCONNECTOR pInterface, bool fBreak)); +} PDMICHARCONNECTOR; +/** PDMICHARCONNECTOR interface ID. */ +#define PDMICHARCONNECTOR_IID "4ad5c190-b408-4cef-926f-fbffce0dc5cc" + + +/** Pointer to a stream interface. */ +typedef struct PDMISTREAM *PPDMISTREAM; +/** + * Stream interface (up). + * Makes up the foundation for PDMICHARCONNECTOR. No pair interface. + */ +typedef struct PDMISTREAM +{ + /** + * Read bits. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pvBuf Where to store the read bits. + * @param cbRead Number of bytes to read/bytes actually read. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnRead,(PPDMISTREAM pInterface, void *pvBuf, size_t *cbRead)); + + /** + * Write bits. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pvBuf Where to store the write bits. + * @param cbWrite Number of bytes to write/bytes actually written. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnWrite,(PPDMISTREAM pInterface, const void *pvBuf, size_t *cbWrite)); +} PDMISTREAM; +/** PDMISTREAM interface ID. */ +#define PDMISTREAM_IID "d1a5bf5e-3d2c-449a-bde9-addd7920b71f" + + +/** Mode of the parallel port */ +typedef enum PDMPARALLELPORTMODE +{ + /** First invalid mode. */ + PDM_PARALLEL_PORT_MODE_INVALID = 0, + /** SPP (Compatibility mode). */ + PDM_PARALLEL_PORT_MODE_SPP, + /** EPP Data mode. */ + PDM_PARALLEL_PORT_MODE_EPP_DATA, + /** EPP Address mode. */ + PDM_PARALLEL_PORT_MODE_EPP_ADDR, + /** ECP mode (not implemented yet). */ + PDM_PARALLEL_PORT_MODE_ECP, + /** 32bit hack. */ + PDM_PARALLEL_PORT_MODE_32BIT_HACK = 0x7fffffff +} PDMPARALLELPORTMODE; + +/** Pointer to a host parallel port interface. */ +typedef struct PDMIHOSTPARALLELPORT *PPDMIHOSTPARALLELPORT; +/** + * Host parallel port interface (down). + * Pair with PDMIHOSTPARALLELCONNECTOR. + */ +typedef struct PDMIHOSTPARALLELPORT +{ + /** + * Notify device/driver that an interrupt has occurred. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnNotifyInterrupt,(PPDMIHOSTPARALLELPORT pInterface)); +} PDMIHOSTPARALLELPORT; +/** PDMIHOSTPARALLELPORT interface ID. */ +#define PDMIHOSTPARALLELPORT_IID "f24b8668-e7f6-4eaa-a14c-4aa2a5f7048e" + + + +/** Pointer to a Host Parallel connector interface. */ +typedef struct PDMIHOSTPARALLELCONNECTOR *PPDMIHOSTPARALLELCONNECTOR; +/** + * Host parallel connector interface (up). + * Pair with PDMIHOSTPARALLELPORT. + */ +typedef struct PDMIHOSTPARALLELCONNECTOR +{ + /** + * Write bits. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pvBuf Where to store the write bits. + * @param cbWrite Number of bytes to write. + * @param enmMode Mode to write the data. + * @thread Any thread. + * @todo r=klaus cbWrite only defines buffer length, method needs a way top return actually written amount of data. + */ + DECLR3CALLBACKMEMBER(int, pfnWrite,(PPDMIHOSTPARALLELCONNECTOR pInterface, const void *pvBuf, + size_t cbWrite, PDMPARALLELPORTMODE enmMode)); + + /** + * Read bits. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pvBuf Where to store the read bits. + * @param cbRead Number of bytes to read. + * @param enmMode Mode to read the data. + * @thread Any thread. + * @todo r=klaus cbRead only defines buffer length, method needs a way top return actually read amount of data. + */ + DECLR3CALLBACKMEMBER(int, pfnRead,(PPDMIHOSTPARALLELCONNECTOR pInterface, void *pvBuf, + size_t cbRead, PDMPARALLELPORTMODE enmMode)); + + /** + * Set data direction of the port (forward/reverse). + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param fForward Flag whether to indicate whether the port is operated in forward or reverse mode. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnSetPortDirection,(PPDMIHOSTPARALLELCONNECTOR pInterface, bool fForward)); + + /** + * Write control register bits. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param fReg The new control register value. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnWriteControl,(PPDMIHOSTPARALLELCONNECTOR pInterface, uint8_t fReg)); + + /** + * Read control register bits. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pfReg Where to store the control register bits. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnReadControl,(PPDMIHOSTPARALLELCONNECTOR pInterface, uint8_t *pfReg)); + + /** + * Read status register bits. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pfReg Where to store the status register bits. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnReadStatus,(PPDMIHOSTPARALLELCONNECTOR pInterface, uint8_t *pfReg)); + +} PDMIHOSTPARALLELCONNECTOR; +/** PDMIHOSTPARALLELCONNECTOR interface ID. */ +#define PDMIHOSTPARALLELCONNECTOR_IID "7c532602-7438-4fbc-9265-349d9f0415f9" + + +/** ACPI power source identifier */ +typedef enum PDMACPIPOWERSOURCE +{ + PDM_ACPI_POWER_SOURCE_UNKNOWN = 0, + PDM_ACPI_POWER_SOURCE_OUTLET, + PDM_ACPI_POWER_SOURCE_BATTERY +} PDMACPIPOWERSOURCE; +/** Pointer to ACPI battery state. */ +typedef PDMACPIPOWERSOURCE *PPDMACPIPOWERSOURCE; + +/** ACPI battey capacity */ +typedef enum PDMACPIBATCAPACITY +{ + PDM_ACPI_BAT_CAPACITY_MIN = 0, + PDM_ACPI_BAT_CAPACITY_MAX = 100, + PDM_ACPI_BAT_CAPACITY_UNKNOWN = 255 +} PDMACPIBATCAPACITY; +/** Pointer to ACPI battery capacity. */ +typedef PDMACPIBATCAPACITY *PPDMACPIBATCAPACITY; + +/** ACPI battery state. See ACPI 3.0 spec '_BST (Battery Status)' */ +typedef enum PDMACPIBATSTATE +{ + PDM_ACPI_BAT_STATE_CHARGED = 0x00, + PDM_ACPI_BAT_STATE_DISCHARGING = 0x01, + PDM_ACPI_BAT_STATE_CHARGING = 0x02, + PDM_ACPI_BAT_STATE_CRITICAL = 0x04 +} PDMACPIBATSTATE; +/** Pointer to ACPI battery state. */ +typedef PDMACPIBATSTATE *PPDMACPIBATSTATE; + +/** Pointer to an ACPI port interface. */ +typedef struct PDMIACPIPORT *PPDMIACPIPORT; +/** + * ACPI port interface (down). Used by both the ACPI driver and (grumble) main. + * Pair with PDMIACPICONNECTOR. + */ +typedef struct PDMIACPIPORT +{ + /** + * Send an ACPI power off event. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + */ + DECLR3CALLBACKMEMBER(int, pfnPowerButtonPress,(PPDMIACPIPORT pInterface)); + + /** + * Send an ACPI sleep button event. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + */ + DECLR3CALLBACKMEMBER(int, pfnSleepButtonPress,(PPDMIACPIPORT pInterface)); + + /** + * Check if the last power button event was handled by the guest. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pfHandled Is set to true if the last power button event was handled, false otherwise. + */ + DECLR3CALLBACKMEMBER(int, pfnGetPowerButtonHandled,(PPDMIACPIPORT pInterface, bool *pfHandled)); + + /** + * Check if the guest entered the ACPI mode. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pfEnabled Is set to true if the guest entered the ACPI mode, false otherwise. + */ + DECLR3CALLBACKMEMBER(int, pfnGetGuestEnteredACPIMode,(PPDMIACPIPORT pInterface, bool *pfEntered)); + + /** + * Check if the given CPU is still locked by the guest. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param uCpu The CPU to check for. + * @param pfLocked Is set to true if the CPU is still locked by the guest, false otherwise. + */ + DECLR3CALLBACKMEMBER(int, pfnGetCpuStatus,(PPDMIACPIPORT pInterface, unsigned uCpu, bool *pfLocked)); +} PDMIACPIPORT; +/** PDMIACPIPORT interface ID. */ +#define PDMIACPIPORT_IID "30d3dc4c-6a73-40c8-80e9-34309deacbb3" + + +/** Pointer to an ACPI connector interface. */ +typedef struct PDMIACPICONNECTOR *PPDMIACPICONNECTOR; +/** + * ACPI connector interface (up). + * Pair with PDMIACPIPORT. + */ +typedef struct PDMIACPICONNECTOR +{ + /** + * Get the current power source of the host system. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param penmPowerSource Pointer to the power source result variable. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryPowerSource,(PPDMIACPICONNECTOR, PPDMACPIPOWERSOURCE penmPowerSource)); + + /** + * Query the current battery status of the host system. + * + * @returns VBox status code? + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pfPresent Is set to true if battery is present, false otherwise. + * @param penmRemainingCapacity Pointer to the battery remaining capacity (0 - 100 or 255 for unknown). + * @param penmBatteryState Pointer to the battery status. + * @param pu32PresentRate Pointer to the present rate (0..1000 of the total capacity). + */ + DECLR3CALLBACKMEMBER(int, pfnQueryBatteryStatus,(PPDMIACPICONNECTOR, bool *pfPresent, PPDMACPIBATCAPACITY penmRemainingCapacity, + PPDMACPIBATSTATE penmBatteryState, uint32_t *pu32PresentRate)); +} PDMIACPICONNECTOR; +/** PDMIACPICONNECTOR interface ID. */ +#define PDMIACPICONNECTOR_IID "5f14bf8d-1edf-4e3a-a1e1-cca9fd08e359" + + +/** Pointer to a VMMDevice port interface. */ +typedef struct PDMIVMMDEVPORT *PPDMIVMMDEVPORT; +/** + * VMMDevice port interface (down). + * Pair with PDMIVMMDEVCONNECTOR. + */ +typedef struct PDMIVMMDEVPORT +{ + /** + * Return the current absolute mouse position in pixels + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pxAbs Pointer of result value, can be NULL + * @param pyAbs Pointer of result value, can be NULL + */ + DECLR3CALLBACKMEMBER(int, pfnQueryAbsoluteMouse,(PPDMIVMMDEVPORT pInterface, int32_t *pxAbs, int32_t *pyAbs)); + + /** + * Set the new absolute mouse position in pixels + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param xabs New absolute X position + * @param yAbs New absolute Y position + */ + DECLR3CALLBACKMEMBER(int, pfnSetAbsoluteMouse,(PPDMIVMMDEVPORT pInterface, int32_t xAbs, int32_t yAbs)); + + /** + * Return the current mouse capability flags + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pfCapabilities Pointer of result value + */ + DECLR3CALLBACKMEMBER(int, pfnQueryMouseCapabilities,(PPDMIVMMDEVPORT pInterface, uint32_t *pfCapabilities)); + + /** + * Set the current mouse capability flag (host side) + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param fCapsAdded Mask of capabilities to add to the flag + * @param fCapsRemoved Mask of capabilities to remove from the flag + */ + DECLR3CALLBACKMEMBER(int, pfnUpdateMouseCapabilities,(PPDMIVMMDEVPORT pInterface, uint32_t fCapsAdded, uint32_t fCapsRemoved)); + + /** + * Issue a display resolution change request. + * + * Note that there can only one request in the queue and that in case the guest does + * not process it, issuing another request will overwrite the previous. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param cx Horizontal pixel resolution (0 = do not change). + * @param cy Vertical pixel resolution (0 = do not change). + * @param cBits Bits per pixel (0 = do not change). + * @param idxDisplay The display index. + */ + DECLR3CALLBACKMEMBER(int, pfnRequestDisplayChange,(PPDMIVMMDEVPORT pInterface, uint32_t cx, uint32_t cy, uint32_t cBits, uint32_t idxDisplay)); + + /** + * Pass credentials to guest. + * + * Note that there can only be one set of credentials and the guest may or may not + * query them and may do whatever it wants with them. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pszUsername User name, may be empty (UTF-8). + * @param pszPassword Password, may be empty (UTF-8). + * @param pszDomain Domain name, may be empty (UTF-8). + * @param fFlags VMMDEV_SETCREDENTIALS_*. + */ + DECLR3CALLBACKMEMBER(int, pfnSetCredentials,(PPDMIVMMDEVPORT pInterface, const char *pszUsername, + const char *pszPassword, const char *pszDomain, + uint32_t fFlags)); + + /** + * Notify the driver about a VBVA status change. + * + * @returns Nothing. Because it is informational callback. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param fEnabled Current VBVA status. + */ + DECLR3CALLBACKMEMBER(void, pfnVBVAChange, (PPDMIVMMDEVPORT pInterface, bool fEnabled)); + + /** + * Issue a seamless mode change request. + * + * Note that there can only one request in the queue and that in case the guest does + * not process it, issuing another request will overwrite the previous. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param fEnabled Seamless mode enabled or not + */ + DECLR3CALLBACKMEMBER(int, pfnRequestSeamlessChange,(PPDMIVMMDEVPORT pInterface, bool fEnabled)); + + /** + * Issue a memory balloon change request. + * + * Note that there can only one request in the queue and that in case the guest does + * not process it, issuing another request will overwrite the previous. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param cMbBalloon Balloon size in megabytes + */ + DECLR3CALLBACKMEMBER(int, pfnSetMemoryBalloon,(PPDMIVMMDEVPORT pInterface, uint32_t cMbBalloon)); + + /** + * Issue a statistcs interval change request. + * + * Note that there can only one request in the queue and that in case the guest does + * not process it, issuing another request will overwrite the previous. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param cSecsStatInterval Statistics query interval in seconds + * (0=disable). + */ + DECLR3CALLBACKMEMBER(int, pfnSetStatisticsInterval,(PPDMIVMMDEVPORT pInterface, uint32_t cSecsStatInterval)); + + /** + * Notify the guest about a VRDP status change. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param fVRDPEnabled Current VRDP status. + * @param uVRDPExperienceLevel Which visual effects to be disabled in + * the guest. + */ + DECLR3CALLBACKMEMBER(int, pfnVRDPChange, (PPDMIVMMDEVPORT pInterface, bool fVRDPEnabled, uint32_t uVRDPExperienceLevel)); + + /** + * Notify the guest of CPU hot-unplug event. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param idCpuCore The core id of the CPU to remove. + * @param idCpuPackage The package id of the CPU to remove. + */ + DECLR3CALLBACKMEMBER(int, pfnCpuHotUnplug, (PPDMIVMMDEVPORT pInterface, uint32_t idCpuCore, uint32_t idCpuPackage)); + + /** + * Notify the guest of CPU hot-plug event. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param idCpuCore The core id of the CPU to add. + * @param idCpuPackage The package id of the CPU to add. + */ + DECLR3CALLBACKMEMBER(int, pfnCpuHotPlug, (PPDMIVMMDEVPORT pInterface, uint32_t idCpuCore, uint32_t idCpuPackage)); + +} PDMIVMMDEVPORT; +/** PDMIVMMDEVPORT interface ID. */ +#define PDMIVMMDEVPORT_IID "d7e52035-3b6c-422e-9215-2a75646a945d" + + +/** Pointer to a HPET legacy notification interface. */ +typedef struct PDMIHPETLEGACYNOTIFY *PPDMIHPETLEGACYNOTIFY; +/** + * HPET legacy notification interface. + */ +typedef struct PDMIHPETLEGACYNOTIFY +{ + /** + * Notify about change of HPET legacy mode. + * + * @param pInterface Pointer to the interface structure containing the + * called function pointer. + * @param fActivated If HPET legacy mode is activated (@c true) or + * deactivated (@c false). + */ + DECLR3CALLBACKMEMBER(void, pfnModeChanged,(PPDMIHPETLEGACYNOTIFY pInterface, bool fActivated)); +} PDMIHPETLEGACYNOTIFY; +/** PDMIHPETLEGACYNOTIFY interface ID. */ +#define PDMIHPETLEGACYNOTIFY_IID "c9ada595-4b65-4311-8b21-b10498997774" + + +/** @name Flags for PDMIVMMDEVPORT::pfnSetCredentials. + * @{ */ +/** The guest should perform a logon with the credentials. */ +#define VMMDEV_SETCREDENTIALS_GUESTLOGON RT_BIT(0) +/** The guest should prevent local logons. */ +#define VMMDEV_SETCREDENTIALS_NOLOCALLOGON RT_BIT(1) +/** The guest should verify the credentials. */ +#define VMMDEV_SETCREDENTIALS_JUDGE RT_BIT(15) +/** @} */ + +/** Forward declaration of the guest information structure. */ +struct VBoxGuestInfo; +/** Forward declaration of the guest information-2 structure. */ +struct VBoxGuestInfo2; +/** Forward declaration of the guest statistics structure */ +struct VBoxGuestStatistics; +/** Forward declaration of the guest status structure */ +struct VBoxGuestStatus; + +/** Forward declaration of the video accelerator command memory. */ +struct VBVAMEMORY; +/** Pointer to video accelerator command memory. */ +typedef struct VBVAMEMORY *PVBVAMEMORY; + +/** Pointer to a VMMDev connector interface. */ +typedef struct PDMIVMMDEVCONNECTOR *PPDMIVMMDEVCONNECTOR; +/** + * VMMDev connector interface (up). + * Pair with PDMIVMMDEVPORT. + */ +typedef struct PDMIVMMDEVCONNECTOR +{ + /** + * Update guest facility status. + * + * Called in response to VMMDevReq_ReportGuestStatus, reset or state restore. + * + * @param pInterface Pointer to this interface. + * @param uFacility The facility. + * @param uStatus The status. + * @param fFlags Flags assoicated with the update. Currently + * reserved and should be ignored. + * @param pTimeSpecTS Pointer to the timestamp of this report. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnUpdateGuestStatus,(PPDMIVMMDEVCONNECTOR pInterface, uint32_t uFacility, uint16_t uStatus, + uint32_t fFlags, PCRTTIMESPEC pTimeSpecTS)); + + /** + * Reports the guest API and OS version. + * Called whenever the Additions issue a guest info report request. + * + * @param pInterface Pointer to this interface. + * @param pGuestInfo Pointer to guest information structure + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnUpdateGuestInfo,(PPDMIVMMDEVCONNECTOR pInterface, const struct VBoxGuestInfo *pGuestInfo)); + + /** + * Reports the detailed Guest Additions version. + * + * @param pInterface Pointer to this interface. + * @param uFullVersion The guest additions version as a full version. + * Use VBOX_FULL_VERSION_GET_MAJOR, + * VBOX_FULL_VERSION_GET_MINOR and + * VBOX_FULL_VERSION_GET_BUILD to access it. + * (This will not be zero, so turn down the + * paranoia level a notch.) + * @param pszName Pointer to the sanitized version name. This can + * be empty, but will not be NULL. If not empty, + * it will contain a build type tag and/or a + * publisher tag. If both, then they are separated + * by an underscore (VBOX_VERSION_STRING fashion). + * @param uRevision The SVN revision. Can be 0. + * @param fFeatures Feature mask, currently none are defined. + * + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnUpdateGuestInfo2,(PPDMIVMMDEVCONNECTOR pInterface, uint32_t uFullVersion, + const char *pszName, uint32_t uRevision, uint32_t fFeatures)); + + /** + * Update the guest additions capabilities. + * This is called when the guest additions capabilities change. The new capabilities + * are given and the connector should update its internal state. + * + * @param pInterface Pointer to this interface. + * @param newCapabilities New capabilities. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnUpdateGuestCapabilities,(PPDMIVMMDEVCONNECTOR pInterface, uint32_t newCapabilities)); + + /** + * Update the mouse capabilities. + * This is called when the mouse capabilities change. The new capabilities + * are given and the connector should update its internal state. + * + * @param pInterface Pointer to this interface. + * @param newCapabilities New capabilities. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnUpdateMouseCapabilities,(PPDMIVMMDEVCONNECTOR pInterface, uint32_t newCapabilities)); + + /** + * Update the pointer shape. + * This is called when the mouse pointer shape changes. The new shape + * is passed as a caller allocated buffer that will be freed after returning + * + * @param pInterface Pointer to this interface. + * @param fVisible Visibility indicator (if false, the other parameters are undefined). + * @param fAlpha Flag whether alpha channel is being passed. + * @param xHot Pointer hot spot x coordinate. + * @param yHot Pointer hot spot y coordinate. + * @param x Pointer new x coordinate on screen. + * @param y Pointer new y coordinate on screen. + * @param cx Pointer width in pixels. + * @param cy Pointer height in pixels. + * @param cbScanline Size of one scanline in bytes. + * @param pvShape New shape buffer. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnUpdatePointerShape,(PPDMIVMMDEVCONNECTOR pInterface, bool fVisible, bool fAlpha, + uint32_t xHot, uint32_t yHot, + uint32_t cx, uint32_t cy, + void *pvShape)); + + /** + * Enable or disable video acceleration on behalf of guest. + * + * @param pInterface Pointer to this interface. + * @param fEnable Whether to enable acceleration. + * @param pVbvaMemory Video accelerator memory. + + * @return VBox rc. VINF_SUCCESS if VBVA was enabled. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnVideoAccelEnable,(PPDMIVMMDEVCONNECTOR pInterface, bool fEnable, PVBVAMEMORY pVbvaMemory)); + + /** + * Force video queue processing. + * + * @param pInterface Pointer to this interface. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnVideoAccelFlush,(PPDMIVMMDEVCONNECTOR pInterface)); + + /** + * Return whether the given video mode is supported/wanted by the host. + * + * @returns VBox status code + * @param pInterface Pointer to this interface. + * @param display The guest monitor, 0 for primary. + * @param cy Video mode horizontal resolution in pixels. + * @param cx Video mode vertical resolution in pixels. + * @param cBits Video mode bits per pixel. + * @param pfSupported Where to put the indicator for whether this mode is supported. (output) + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnVideoModeSupported,(PPDMIVMMDEVCONNECTOR pInterface, uint32_t display, uint32_t cx, uint32_t cy, uint32_t cBits, bool *pfSupported)); + + /** + * Queries by how many pixels the height should be reduced when calculating video modes + * + * @returns VBox status code + * @param pInterface Pointer to this interface. + * @param pcyReduction Pointer to the result value. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnGetHeightReduction,(PPDMIVMMDEVCONNECTOR pInterface, uint32_t *pcyReduction)); + + /** + * Informs about a credentials judgement result from the guest. + * + * @returns VBox status code + * @param pInterface Pointer to this interface. + * @param fFlags Judgement result flags. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnSetCredentialsJudgementResult,(PPDMIVMMDEVCONNECTOR pInterface, uint32_t fFlags)); + + /** + * Set the visible region of the display + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param cRect Number of rectangles in pRect + * @param pRect Rectangle array + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnSetVisibleRegion,(PPDMIVMMDEVCONNECTOR pInterface, uint32_t cRect, PRTRECT pRect)); + + /** + * Query the visible region of the display + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pcRect Number of rectangles in pRect + * @param pRect Rectangle array (set to NULL to query the number of rectangles) + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryVisibleRegion,(PPDMIVMMDEVCONNECTOR pInterface, uint32_t *pcRect, PRTRECT pRect)); + + /** + * Request the statistics interval + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pulInterval Pointer to interval in seconds + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryStatisticsInterval,(PPDMIVMMDEVCONNECTOR pInterface, uint32_t *pulInterval)); + + /** + * Report new guest statistics + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pGuestStats Guest statistics + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnReportStatistics,(PPDMIVMMDEVCONNECTOR pInterface, struct VBoxGuestStatistics *pGuestStats)); + + /** + * Query the current balloon size + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pcbBalloon Balloon size + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryBalloonSize,(PPDMIVMMDEVCONNECTOR pInterface, uint32_t *pcbBalloon)); + + /** + * Query the current page fusion setting + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pfPageFusionEnabled Pointer to boolean + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnIsPageFusionEnabled,(PPDMIVMMDEVCONNECTOR pInterface, bool *pfPageFusionEnabled)); + +} PDMIVMMDEVCONNECTOR; +/** PDMIVMMDEVCONNECTOR interface ID. */ +#define PDMIVMMDEVCONNECTOR_IID "aff90240-a443-434e-9132-80c186ab97d4" + + +/** Pointer to a network connector interface */ +typedef struct PDMIAUDIOCONNECTOR *PPDMIAUDIOCONNECTOR; +/** + * Audio connector interface (up). + * No interface pair yet. + */ +typedef struct PDMIAUDIOCONNECTOR +{ + DECLR3CALLBACKMEMBER(void, pfnRun,(PPDMIAUDIOCONNECTOR pInterface)); + +/* DECLR3CALLBACKMEMBER(int, pfnSetRecordSource,(PPDMIAUDIOINCONNECTOR pInterface, AUDIORECSOURCE)); */ + +} PDMIAUDIOCONNECTOR; +/** PDMIAUDIOCONNECTOR interface ID. */ +#define PDMIAUDIOCONNECTOR_IID "85d52af5-b3aa-4b3e-b176-4b5ebfc52f47" + + +/** @todo r=bird: the two following interfaces are hacks to work around the missing audio driver + * interface. This should be addressed rather than making more temporary hacks. */ + +/** Pointer to a Audio Sniffer Device port interface. */ +typedef struct PDMIAUDIOSNIFFERPORT *PPDMIAUDIOSNIFFERPORT; +/** + * Audio Sniffer port interface (down). + * Pair with PDMIAUDIOSNIFFERCONNECTOR. + */ +typedef struct PDMIAUDIOSNIFFERPORT +{ + /** + * Enables or disables sniffing. + * + * If sniffing is being enabled also sets a flag whether the audio must be also + * left on the host. + * + * @returns VBox status code + * @param pInterface Pointer to this interface. + * @param fEnable 'true' for enable sniffing, 'false' to disable. + * @param fKeepHostAudio Indicates whether host audio should also present + * 'true' means that sound should not be played + * by the audio device. + */ + DECLR3CALLBACKMEMBER(int, pfnSetup,(PPDMIAUDIOSNIFFERPORT pInterface, bool fEnable, bool fKeepHostAudio)); + + /** + * Enables or disables audio input. + * + * @returns VBox status code + * @param pInterface Pointer to this interface. + * @param fIntercept 'true' for interception of audio input, + * 'false' to let the host audio backend do audio input. + */ + DECLR3CALLBACKMEMBER(int, pfnAudioInputIntercept,(PPDMIAUDIOSNIFFERPORT pInterface, bool fIntercept)); + + /** + * Audio input is about to start. + * + * @returns VBox status code. + * @param pvContext The callback context, supplied in the + * PDMIAUDIOSNIFFERCONNECTOR::pfnAudioInputBegin as pvContext. + * @param iSampleHz The sample frequency in Hz. + * @param cChannels Number of channels. 1 for mono, 2 for stereo. + * @param cBits How many bits a sample for a single channel has. Normally 8 or 16. + * @param fUnsigned Whether samples are unsigned values. + */ + DECLR3CALLBACKMEMBER(int, pfnAudioInputEventBegin,(PPDMIAUDIOSNIFFERPORT pInterface, + void *pvContext, + int iSampleHz, + int cChannels, + int cBits, + bool fUnsigned)); + + /** + * Callback which delivers audio data to the audio device. + * + * @returns VBox status code. + * @param pvContext The callback context, supplied in the + * PDMIAUDIOSNIFFERCONNECTOR::pfnAudioInputBegin as pvContext. + * @param pvData Event specific data. + * @param cbData Size of the buffer pointed by pvData. + */ + DECLR3CALLBACKMEMBER(int, pfnAudioInputEventData,(PPDMIAUDIOSNIFFERPORT pInterface, + void *pvContext, + const void *pvData, + uint32_t cbData)); + + /** + * Audio input ends. + * + * @param pvContext The callback context, supplied in the + * PDMIAUDIOSNIFFERCONNECTOR::pfnAudioInputBegin as pvContext. + */ + DECLR3CALLBACKMEMBER(void, pfnAudioInputEventEnd,(PPDMIAUDIOSNIFFERPORT pInterface, + void *pvContext)); +} PDMIAUDIOSNIFFERPORT; +/** PDMIAUDIOSNIFFERPORT interface ID. */ +#define PDMIAUDIOSNIFFERPORT_IID "8ad25d78-46e9-479b-a363-bb0bc0fe022f" + + +/** Pointer to a Audio Sniffer connector interface. */ +typedef struct PDMIAUDIOSNIFFERCONNECTOR *PPDMIAUDIOSNIFFERCONNECTOR; + +/** + * Audio Sniffer connector interface (up). + * Pair with PDMIAUDIOSNIFFERPORT. + */ +typedef struct PDMIAUDIOSNIFFERCONNECTOR +{ + /** + * AudioSniffer device calls this method when audio samples + * are about to be played and sniffing is enabled. + * + * @param pInterface Pointer to this interface. + * @param pvSamples Audio samples buffer. + * @param cSamples How many complete samples are in the buffer. + * @param iSampleHz The sample frequency in Hz. + * @param cChannels Number of channels. 1 for mono, 2 for stereo. + * @param cBits How many bits a sample for a single channel has. Normally 8 or 16. + * @param fUnsigned Whether samples are unsigned values. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnAudioSamplesOut,(PPDMIAUDIOSNIFFERCONNECTOR pInterface, void *pvSamples, uint32_t cSamples, + int iSampleHz, int cChannels, int cBits, bool fUnsigned)); + + /** + * AudioSniffer device calls this method when output volume is changed. + * + * @param pInterface Pointer to this interface. + * @param u16LeftVolume 0..0xFFFF volume level for left channel. + * @param u16RightVolume 0..0xFFFF volume level for right channel. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnAudioVolumeOut,(PPDMIAUDIOSNIFFERCONNECTOR pInterface, uint16_t u16LeftVolume, uint16_t u16RightVolume)); + + /** + * Audio input has been requested by the virtual audio device. + * + * @param pInterface Pointer to this interface. + * @param ppvUserCtx The interface context for this audio input stream, + * it will be used in the pfnAudioInputEnd call. + * @param pvContext The context pointer to be used in PDMIAUDIOSNIFFERPORT::pfnAudioInputEvent. + * @param cSamples How many samples in a block is preferred in + * PDMIAUDIOSNIFFERPORT::pfnAudioInputEvent. + * @param iSampleHz The sample frequency in Hz. + * @param cChannels Number of channels. 1 for mono, 2 for stereo. + * @param cBits How many bits a sample for a single channel has. Normally 8 or 16. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnAudioInputBegin,(PPDMIAUDIOSNIFFERCONNECTOR pInterface, + void **ppvUserCtx, + void *pvContext, + uint32_t cSamples, + uint32_t iSampleHz, + uint32_t cChannels, + uint32_t cBits)); + + /** + * Audio input has been requested by the virtual audio device. + * + * @param pInterface Pointer to this interface. + * @param pvUserCtx The interface context for this audio input stream, + * which was returned by pfnAudioInputBegin call. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnAudioInputEnd,(PPDMIAUDIOSNIFFERCONNECTOR pInterface, + void *pvUserCtx)); +} PDMIAUDIOSNIFFERCONNECTOR; +/** PDMIAUDIOSNIFFERCONNECTOR - The Audio Sniffer Driver connector interface. */ +#define PDMIAUDIOSNIFFERCONNECTOR_IID "9d37f543-27af-45f8-8002-8ef7abac71e4" + + +/** + * Generic status LED core. + * Note that a unit doesn't have to support all the indicators. + */ +typedef union PDMLEDCORE +{ + /** 32-bit view. */ + uint32_t volatile u32; + /** Bit view. */ + struct + { + /** Reading/Receiving indicator. */ + uint32_t fReading : 1; + /** Writing/Sending indicator. */ + uint32_t fWriting : 1; + /** Busy indicator. */ + uint32_t fBusy : 1; + /** Error indicator. */ + uint32_t fError : 1; + } s; +} PDMLEDCORE; + +/** LED bit masks for the u32 view. + * @{ */ +/** Reading/Receiving indicator. */ +#define PDMLED_READING RT_BIT(0) +/** Writing/Sending indicator. */ +#define PDMLED_WRITING RT_BIT(1) +/** Busy indicator. */ +#define PDMLED_BUSY RT_BIT(2) +/** Error indicator. */ +#define PDMLED_ERROR RT_BIT(3) +/** @} */ + + +/** + * Generic status LED. + * Note that a unit doesn't have to support all the indicators. + */ +typedef struct PDMLED +{ + /** Just a magic for sanity checking. */ + uint32_t u32Magic; + uint32_t u32Alignment; /**< structure size alignment. */ + /** The actual LED status. + * Only the device is allowed to change this. */ + PDMLEDCORE Actual; + /** The asserted LED status which is cleared by the reader. + * The device will assert the bits but never clear them. + * The driver clears them as it sees fit. */ + PDMLEDCORE Asserted; +} PDMLED; + +/** Pointer to an LED. */ +typedef PDMLED *PPDMLED; +/** Pointer to a const LED. */ +typedef const PDMLED *PCPDMLED; + +/** Magic value for PDMLED::u32Magic. */ +#define PDMLED_MAGIC UINT32_C(0x11335577) + +/** Pointer to an LED ports interface. */ +typedef struct PDMILEDPORTS *PPDMILEDPORTS; +/** + * Interface for exporting LEDs (down). + * Pair with PDMILEDCONNECTORS. + */ +typedef struct PDMILEDPORTS +{ + /** + * Gets the pointer to the status LED of a unit. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param iLUN The unit which status LED we desire. + * @param ppLed Where to store the LED pointer. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryStatusLed,(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)); + +} PDMILEDPORTS; +/** PDMILEDPORTS interface ID. */ +#define PDMILEDPORTS_IID "435e0cec-8549-4ca0-8c0d-98e52f1dc038" + + +/** Pointer to an LED connectors interface. */ +typedef struct PDMILEDCONNECTORS *PPDMILEDCONNECTORS; +/** + * Interface for reading LEDs (up). + * Pair with PDMILEDPORTS. + */ +typedef struct PDMILEDCONNECTORS +{ + /** + * Notification about a unit which have been changed. + * + * The driver must discard any pointers to data owned by + * the unit and requery it. + * + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param iLUN The unit number. + */ + DECLR3CALLBACKMEMBER(void, pfnUnitChanged,(PPDMILEDCONNECTORS pInterface, unsigned iLUN)); +} PDMILEDCONNECTORS; +/** PDMILEDCONNECTORS interface ID. */ +#define PDMILEDCONNECTORS_IID "8ed63568-82a7-4193-b57b-db8085ac4495" + + +/** Pointer to a Media Notification interface. */ +typedef struct PDMIMEDIANOTIFY *PPDMIMEDIANOTIFY; +/** + * Interface for exporting Medium eject information (up). No interface pair. + */ +typedef struct PDMIMEDIANOTIFY +{ + /** + * Signals that the medium was ejected. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param iLUN The unit which had the medium ejected. + */ + DECLR3CALLBACKMEMBER(int, pfnEjected,(PPDMIMEDIANOTIFY pInterface, unsigned iLUN)); + +} PDMIMEDIANOTIFY; +/** PDMIMEDIANOTIFY interface ID. */ +#define PDMIMEDIANOTIFY_IID "fc22d53e-feb1-4a9c-b9fb-0a990a6ab288" + + +/** The special status unit number */ +#define PDM_STATUS_LUN 999 + + +#ifdef VBOX_WITH_HGCM + +/** Abstract HGCM command structure. Used only to define a typed pointer. */ +struct VBOXHGCMCMD; + +/** Pointer to HGCM command structure. This pointer is unique and identifies + * the command being processed. The pointer is passed to HGCM connector methods, + * and must be passed back to HGCM port when command is completed. + */ +typedef struct VBOXHGCMCMD *PVBOXHGCMCMD; + +/** Pointer to a HGCM port interface. */ +typedef struct PDMIHGCMPORT *PPDMIHGCMPORT; +/** + * Host-Guest communication manager port interface (down). Normally implemented + * by VMMDev. + * Pair with PDMIHGCMCONNECTOR. + */ +typedef struct PDMIHGCMPORT +{ + /** + * Notify the guest on a command completion. + * + * @param pInterface Pointer to this interface. + * @param rc The return code (VBox error code). + * @param pCmd A pointer that identifies the completed command. + * + * @returns VBox status code + */ + DECLR3CALLBACKMEMBER(void, pfnCompleted,(PPDMIHGCMPORT pInterface, int32_t rc, PVBOXHGCMCMD pCmd)); + +} PDMIHGCMPORT; +/** PDMIHGCMPORT interface ID. */ +# define PDMIHGCMPORT_IID "e00a0cbf-b75a-45c3-87f4-41cddbc5ae0b" + + +/** Pointer to a HGCM service location structure. */ +typedef struct HGCMSERVICELOCATION *PHGCMSERVICELOCATION; + +/** Pointer to a HGCM connector interface. */ +typedef struct PDMIHGCMCONNECTOR *PPDMIHGCMCONNECTOR; +/** + * The Host-Guest communication manager connector interface (up). Normally + * implemented by Main::VMMDevInterface. + * Pair with PDMIHGCMPORT. + */ +typedef struct PDMIHGCMCONNECTOR +{ + /** + * Locate a service and inform it about a client connection. + * + * @param pInterface Pointer to this interface. + * @param pCmd A pointer that identifies the command. + * @param pServiceLocation Pointer to the service location structure. + * @param pu32ClientID Where to store the client id for the connection. + * @return VBox status code. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnConnect,(PPDMIHGCMCONNECTOR pInterface, PVBOXHGCMCMD pCmd, PHGCMSERVICELOCATION pServiceLocation, uint32_t *pu32ClientID)); + + /** + * Disconnect from service. + * + * @param pInterface Pointer to this interface. + * @param pCmd A pointer that identifies the command. + * @param u32ClientID The client id returned by the pfnConnect call. + * @return VBox status code. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnDisconnect,(PPDMIHGCMCONNECTOR pInterface, PVBOXHGCMCMD pCmd, uint32_t u32ClientID)); + + /** + * Process a guest issued command. + * + * @param pInterface Pointer to this interface. + * @param pCmd A pointer that identifies the command. + * @param u32ClientID The client id returned by the pfnConnect call. + * @param u32Function Function to be performed by the service. + * @param cParms Number of parameters in the array pointed to by paParams. + * @param paParms Pointer to an array of parameters. + * @return VBox status code. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnCall,(PPDMIHGCMCONNECTOR pInterface, PVBOXHGCMCMD pCmd, uint32_t u32ClientID, uint32_t u32Function, + uint32_t cParms, PVBOXHGCMSVCPARM paParms)); + +} PDMIHGCMCONNECTOR; +/** PDMIHGCMCONNECTOR interface ID. */ +# define PDMIHGCMCONNECTOR_IID "a1104758-c888-4437-8f2a-7bac17865b5c" + +#endif /* VBOX_WITH_HGCM */ + +/** + * Data direction. + */ +typedef enum PDMSCSIREQUESTTXDIR +{ + PDMSCSIREQUESTTXDIR_UNKNOWN = 0x00, + PDMSCSIREQUESTTXDIR_FROM_DEVICE = 0x01, + PDMSCSIREQUESTTXDIR_TO_DEVICE = 0x02, + PDMSCSIREQUESTTXDIR_NONE = 0x03, + PDMSCSIREQUESTTXDIR_32BIT_HACK = 0x7fffffff +} PDMSCSIREQUESTTXDIR; + +/** + * SCSI request structure. + */ +typedef struct PDMSCSIREQUEST +{ + /** The logical unit. */ + uint32_t uLogicalUnit; + /** Direction of the data flow. */ + PDMSCSIREQUESTTXDIR uDataDirection; + /** Size of the SCSI CDB. */ + uint32_t cbCDB; + /** Pointer to the SCSI CDB. */ + uint8_t *pbCDB; + /** Overall size of all scatter gather list elements + * for data transfer if any. */ + uint32_t cbScatterGather; + /** Number of elements in the scatter gather list. */ + uint32_t cScatterGatherEntries; + /** Pointer to the head of the scatter gather list. */ + PRTSGSEG paScatterGatherHead; + /** Size of the sense buffer. */ + uint32_t cbSenseBuffer; + /** Pointer to the sense buffer. * + * Current assumption that the sense buffer is not scattered. */ + uint8_t *pbSenseBuffer; + /** Opaque user data for use by the device. Left untouched by everything else! */ + void *pvUser; +} PDMSCSIREQUEST, *PPDMSCSIREQUEST; +/** Pointer to a const SCSI request structure. */ +typedef const PDMSCSIREQUEST *PCSCSIREQUEST; + +/** Pointer to a SCSI port interface. */ +typedef struct PDMISCSIPORT *PPDMISCSIPORT; +/** + * SCSI command execution port interface (down). + * Pair with PDMISCSICONNECTOR. + */ +typedef struct PDMISCSIPORT +{ + + /** + * Notify the device on request completion. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pSCSIRequest Pointer to the finished SCSI request. + * @param rcCompletion SCSI_STATUS_* code for the completed request. + * @param fRedo Flag whether the request can to be redone + * when it failed. + * @param rcReq The status code the request completed with (VERR_*) + * Should be only used to choose the correct error message + * displayed to the user if the error can be fixed by him + * (fRedo is true). + */ + DECLR3CALLBACKMEMBER(int, pfnSCSIRequestCompleted, (PPDMISCSIPORT pInterface, PPDMSCSIREQUEST pSCSIRequest, + int rcCompletion, bool fRedo, int rcReq)); + + /** + * Returns the storage controller name, instance and LUN of the attached medium. + * + * @returns VBox status. + * @param pInterface Pointer to this interface. + * @param ppcszController Where to store the name of the storage controller. + * @param piInstance Where to store the instance number of the controller. + * @param piLUN Where to store the LUN of the attached device. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryDeviceLocation, (PPDMISCSIPORT pInterface, const char **ppcszController, + uint32_t *piInstance, uint32_t *piLUN)); + +} PDMISCSIPORT; +/** PDMISCSIPORT interface ID. */ +#define PDMISCSIPORT_IID "05d9fc3b-e38c-4b30-8344-a323feebcfe5" + + +/** Pointer to a SCSI connector interface. */ +typedef struct PDMISCSICONNECTOR *PPDMISCSICONNECTOR; +/** + * SCSI command execution connector interface (up). + * Pair with PDMISCSIPORT. + */ +typedef struct PDMISCSICONNECTOR +{ + + /** + * Submits a SCSI request for execution. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pSCSIRequest Pointer to the SCSI request to execute. + */ + DECLR3CALLBACKMEMBER(int, pfnSCSIRequestSend, (PPDMISCSICONNECTOR pInterface, PPDMSCSIREQUEST pSCSIRequest)); + +} PDMISCSICONNECTOR; +/** PDMISCSICONNECTOR interface ID. */ +#define PDMISCSICONNECTOR_IID "94465fbd-a2f2-447e-88c9-7366421bfbfe" + + +/** Pointer to a display VBVA callbacks interface. */ +typedef struct PDMIDISPLAYVBVACALLBACKS *PPDMIDISPLAYVBVACALLBACKS; +/** + * Display VBVA callbacks interface (up). + */ +typedef struct PDMIDISPLAYVBVACALLBACKS +{ + + /** + * Informs guest about completion of processing the given Video HW Acceleration + * command, does not wait for the guest to process the command. + * + * @returns ??? + * @param pInterface Pointer to this interface. + * @param pCmd The Video HW Acceleration Command that was + * completed. + * @todo r=bird: if async means asynchronous; then + * s/pfnVHWACommandCompleteAsynch/pfnVHWACommandCompleteAsync/; + * fi + */ + DECLR3CALLBACKMEMBER(int, pfnVHWACommandCompleteAsynch, (PPDMIDISPLAYVBVACALLBACKS pInterface, + PVBOXVHWACMD pCmd)); + + DECLR3CALLBACKMEMBER(int, pfnCrHgsmiCommandCompleteAsync, (PPDMIDISPLAYVBVACALLBACKS pInterface, + PVBOXVDMACMD_CHROMIUM_CMD pCmd, int rc)); + + DECLR3CALLBACKMEMBER(int, pfnCrHgsmiControlCompleteAsync, (PPDMIDISPLAYVBVACALLBACKS pInterface, + PVBOXVDMACMD_CHROMIUM_CTL pCmd, int rc)); +} PDMIDISPLAYVBVACALLBACKS; +/** PDMIDISPLAYVBVACALLBACKS */ +#define PDMIDISPLAYVBVACALLBACKS_IID "b78b81d2-c821-4e66-96ff-dbafa76343a5" + +/** Pointer to a PCI raw connector interface. */ +typedef struct PDMIPCIRAWCONNECTOR *PPDMIPCIRAWCONNECTOR; +/** + * PCI raw connector interface (up). + */ +typedef struct PDMIPCIRAWCONNECTOR +{ + + /** + * + */ + DECLR3CALLBACKMEMBER(int, pfnDeviceConstructComplete, (PPDMIPCIRAWCONNECTOR pInterface, const char *pcszName, + uint32_t uHostPciAddress, uint32_t uGuestPciAddress, + int rc)); + +} PDMIPCIRAWCONNECTOR; +/** PDMIPCIRAWCONNECTOR interface ID. */ +#define PDMIPCIRAWCONNECTOR_IID "14aa9c6c-8869-4782-9dfc-910071a6aebf" + +/** @} */ + +RT_C_DECLS_END + +#endif diff --git a/include/VBox/vmm/pdmins.h b/include/VBox/vmm/pdmins.h new file mode 100644 index 00000000..2375f3c4 --- /dev/null +++ b/include/VBox/vmm/pdmins.h @@ -0,0 +1,70 @@ +/** @file + * PDM - Pluggable Device Manager, Common Instance Macros. + */ + +/* + * Copyright (C) 2006-2010 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_pdmins_h +#define ___VBox_vmm_pdmins_h + + +/** @defgroup grp_pdm_ins Common PDM Instance Macros + * @ingroup grp_pdm + * @{ + */ + +/** @def PDMBOTHCBDECL + * Macro for declaring a callback which is static in HC and exported in GC. + */ +#if defined(IN_RC) || defined(IN_RING0) +# ifdef __cplusplus +# define PDMBOTHCBDECL(type) extern "C" DECLEXPORT(type) +# else +# define PDMBOTHCBDECL(type) DECLEXPORT(type) +# endif +#else +# define PDMBOTHCBDECL(type) static type +#endif + +/** @def PDMINS_2_DATA + * Converts a PDM Device, USB Device, or Driver instance pointer to a pointer to the instance data. + */ +#define PDMINS_2_DATA(pIns, type) ( (type)(void *)&(pIns)->achInstanceData[0] ) + +/** @def PDMINS_2_DATA_RCPTR + * Converts a PDM Device, USB Device, or Driver instance pointer to a RC pointer to the instance data. + */ +#define PDMINS_2_DATA_RCPTR(pIns) ( (pIns)->pvInstanceDataRC ) + +/** @def PDMINS_2_DATA_R3PTR + * Converts a PDM Device, USB Device, or Driver instance pointer to a HC pointer to the instance data. + */ +#define PDMINS_2_DATA_R3PTR(pIns) ( (pIns)->pvInstanceDataR3 ) + +/** @def PDMINS_2_DATA_R0PTR + * Converts a PDM Device, USB Device, or Driver instance pointer to a R0 pointer to the instance data. + */ +#define PDMINS_2_DATA_R0PTR(pIns) ( (pIns)->pvInstanceDataR0 ) + +/** @} */ + +#endif diff --git a/include/VBox/vmm/pdmnetifs.h b/include/VBox/vmm/pdmnetifs.h new file mode 100644 index 00000000..e9280440 --- /dev/null +++ b/include/VBox/vmm/pdmnetifs.h @@ -0,0 +1,437 @@ +/** @file + * PDM - Pluggable Device Manager, Network Interfaces. + */ + +/* + * Copyright (C) 2006-2010 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_pdmnetifs_h +#define ___VBox_vmm_pdmnetifs_h + +#include <VBox/types.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_ifs_net PDM Network Interfaces + * @ingroup grp_pdm_interfaces + * @{ + */ + + +/** + * PDM scatter/gather buffer. + * + * @todo Promote this to VBox/types.h, VBox/vmm/pdmcommon.h or some such place. + */ +typedef struct PDMSCATTERGATHER +{ + /** Flags. */ + size_t fFlags; + /** The number of bytes used. + * This is cleared on alloc and set by the user. */ + size_t cbUsed; + /** The number of bytes available. + * This is set on alloc and not changed by the user. */ + size_t cbAvailable; + /** Private data member for the allocator side. */ + void *pvAllocator; + /** Private data member for the user side. */ + void *pvUser; + /** The number of segments + * This is set on alloc and not changed by the user. */ + size_t cSegs; + /** Variable sized array of segments. */ + PDMDATASEG aSegs[1]; +} PDMSCATTERGATHER; +/** Pointer to a PDM scatter/gather buffer. */ +typedef PDMSCATTERGATHER *PPDMSCATTERGATHER; +/** Pointer to a PDM scatter/gather buffer pointer. */ +typedef PPDMSCATTERGATHER *PPPDMSCATTERGATHER; + + +/** @name PDMSCATTERGATHER::fFlags + * @{ */ +/** Magic value. */ +#define PDMSCATTERGATHER_FLAGS_MAGIC UINT32_C(0xb1b10000) +/** Magic mask. */ +#define PDMSCATTERGATHER_FLAGS_MAGIC_MASK UINT32_C(0xffff0000) +/** Owned by owner number 1. */ +#define PDMSCATTERGATHER_FLAGS_OWNER_1 UINT32_C(0x00000001) +/** Owned by owner number 2. */ +#define PDMSCATTERGATHER_FLAGS_OWNER_2 UINT32_C(0x00000002) +/** Owned by owner number 3. */ +#define PDMSCATTERGATHER_FLAGS_OWNER_3 UINT32_C(0x00000002) +/** Owner mask. */ +#define PDMSCATTERGATHER_FLAGS_OWNER_MASK UINT32_C(0x00000003) +/** Mask of flags available to general use. + * The parties using the SG must all agree upon how to use these of course. */ +#define PDMSCATTERGATHER_FLAGS_AVL_MASK UINT32_C(0x0000f000) +/** Flags reserved for future use, MBZ. */ +#define PDMSCATTERGATHER_FLAGS_RVD_MASK UINT32_C(0x00000ff8) +/** @} */ + + +/** + * Sets the owner of a scatter/gather buffer. + * + * @param pSgBuf . + * @param uNewOwner The new owner. + */ +DECLINLINE(void) PDMScatterGatherSetOwner(PPDMSCATTERGATHER pSgBuf, uint32_t uNewOwner) +{ + pSgBuf->fFlags = (pSgBuf->fFlags & ~PDMSCATTERGATHER_FLAGS_OWNER_MASK) | uNewOwner; +} + + + +/** Pointer to a network port interface */ +typedef struct PDMINETWORKDOWN *PPDMINETWORKDOWN; +/** + * Network port interface (down). + * Pair with PDMINETWORKUP. + */ +typedef struct PDMINETWORKDOWN +{ + /** + * Wait until there is space for receiving data. We do not care how much space is available + * because pfnReceive() will re-check and notify the guest if necessary. + * + * This function must be called before the pfnRecieve() method is called. + * + * @returns VBox status code. VINF_SUCCESS means there is at least one receive descriptor available. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param cMillies Number of milliseconds to wait. 0 means return immediately. + * + * @thread Non-EMT. + */ + DECLR3CALLBACKMEMBER(int, pfnWaitReceiveAvail,(PPDMINETWORKDOWN pInterface, RTMSINTERVAL cMillies)); + + /** + * Receive data from the network. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pvBuf The available data. + * @param cb Number of bytes available in the buffer. + * + * @thread Non-EMT. + */ + DECLR3CALLBACKMEMBER(int, pfnReceive,(PPDMINETWORKDOWN pInterface, const void *pvBuf, size_t cb)); + + /** + * Receive data with segmentation context from the network. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pvBuf The available data. + * @param cb Number of bytes available in the buffer. + * @param pGso Segmentation context. + * + * @thread Non-EMT. + */ + DECLR3CALLBACKMEMBER(int, pfnReceiveGso,(PPDMINETWORKDOWN pInterface, const void *pvBuf, size_t cb, PCPDMNETWORKGSO pGso)); + + /** + * Do pending transmit work on the leaf driver's XMIT thread. + * + * When a PDMINETWORKUP::pfnBeginTransmit or PDMINETWORKUP::pfnAllocBuf call + * fails with VERR_TRY_AGAIN, the leaf drivers XMIT thread will offer to process + * the upstream device/driver when the the VERR_TRY_AGAIN condition has been + * removed. In some cases the VERR_TRY_AGAIN condition is simply being in an + * inconvenient context and the XMIT thread will start working ASAP. + * + * @param pInterface Pointer to this interface. + * @thread Non-EMT. + */ + DECLR3CALLBACKMEMBER(void, pfnXmitPending,(PPDMINETWORKDOWN pInterface)); + +} PDMINETWORKDOWN; +/** PDMINETWORKDOWN interface ID. */ +#define PDMINETWORKDOWN_IID "52b8cdbb-a087-493b-baa7-81ec3b803e06" + + +/** + * Network link state. + */ +typedef enum PDMNETWORKLINKSTATE +{ + /** Invalid state. */ + PDMNETWORKLINKSTATE_INVALID = 0, + /** The link is up. */ + PDMNETWORKLINKSTATE_UP, + /** The link is down. */ + PDMNETWORKLINKSTATE_DOWN, + /** The link is temporarily down while resuming. */ + PDMNETWORKLINKSTATE_DOWN_RESUME +} PDMNETWORKLINKSTATE; + + +/** Pointer to a network connector interface */ +typedef R3PTRTYPE(struct PDMINETWORKUP *) PPDMINETWORKUPR3; +/** Pointer to a network connector interface, ring-0 context. */ +typedef R0PTRTYPE(struct PDMINETWORKUPR0 *) PPDMINETWORKUPR0; +/** Pointer to a network connector interface, raw-mode context. */ +typedef RCPTRTYPE(struct PDMINETWORKUPRC *) PPDMINETWORKUPRC; +/** Pointer to a current context network connector interface. */ +typedef CTX_SUFF(PPDMINETWORKUP) PPDMINETWORKUP; + +/** + * Network connector interface (up). + * Pair with PDMINETWORKDOWN. + */ +typedef struct PDMINETWORKUP +{ + /** + * Begins a transmit session. + * + * The leaf driver guarantees that there are no concurrent sessions. + * + * @retval VINF_SUCCESS on success. Must always call + * PDMINETWORKUP::pfnEndXmit. + * @retval VERR_TRY_AGAIN if there is already an open transmit session or some + * important resource was unavailable (like buffer space). If it's a + * resources issue, the driver will signal its XMIT thread and have it + * work the device thru the PDMINETWORKDOWN::pfnNotifyBufAvailable + * callback method. + * + * @param pInterface Pointer to the interface structure containing the + * called function pointer. + * @param fOnWorkerThread Set if we're being called on a work thread. Clear + * if an EMT. + * + * @thread Any, but normally EMT or the XMIT thread. + */ + DECLR3CALLBACKMEMBER(int, pfnBeginXmit,(PPDMINETWORKUP pInterface, bool fOnWorkerThread)); + + /** + * Get a send buffer for passing to pfnSendBuf. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_TRY_AGAIN if temporarily out of buffer space. After this + * happens, the driver will call PDMINETWORKDOWN::pfnNotifyBufAvailable + * when this is a buffer of the required size available. + * @retval VERR_NO_MEMORY if really out of buffer space. + * @retval VERR_NET_DOWN if we cannot send anything to the network at this + * point in time. Drop the frame with a xmit error. This is typically + * only seen when pausing the VM since the device keeps the link state, + * but there could of course be races. + * + * @param pInterface Pointer to the interface structure containing the + * called function pointer. + * @param cbMin The minimum buffer size. + * @param pGso Pointer to a GSO context (only reference while in + * this call). NULL indicates no segmentation + * offloading. PDMSCATTERGATHER::pvUser is used to + * indicate that a network SG uses GSO, usually by + * pointing to a copy of @a pGso. + * @param ppSgBuf Where to return the buffer. The buffer will be + * owned by the caller, designation owner number 1. + * + * @thread Any, but normally EMT or the XMIT thread. + */ + DECLR3CALLBACKMEMBER(int, pfnAllocBuf,(PPDMINETWORKUP pInterface, size_t cbMin, PCPDMNETWORKGSO pGso, + PPPDMSCATTERGATHER ppSgBuf)); + + /** + * Frees an unused buffer. + * + * @retval VINF_SUCCESS on success. + * + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pSgBuf A buffer from PDMINETWORKUP::pfnAllocBuf or + * PDMINETWORKDOWN::pfnNotifyBufAvailable. The buffer + * ownership shall be 1. + * + * @thread Any, but normally EMT or the XMIT thread. + */ + DECLR3CALLBACKMEMBER(int, pfnFreeBuf,(PPDMINETWORKUP pInterface, PPDMSCATTERGATHER pSgBuf)); + + /** + * Send data to the network. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_NET_DOWN if the NIC is not connected to a network. pSgBuf will + * be freed. + * @retval VERR_NET_NO_BUFFER_SPACE if we're out of resources. pSgBuf will be + * freed. + * + * @param pInterface Pointer to the interface structure containing the + * called function pointer. + * @param pSgBuf The buffer containing the data to send. The buffer + * ownership shall be 1. The buffer will always be + * consumed, regardless of the status code. + * + * @param fOnWorkerThread Set if we're being called on a work thread. Clear + * if an EMT. + * + * @thread Any, but normally EMT or the XMIT thread. + */ + DECLR3CALLBACKMEMBER(int, pfnSendBuf,(PPDMINETWORKUP pInterface, PPDMSCATTERGATHER pSgBuf, bool fOnWorkerThread)); + + /** + * Ends a transmit session. + * + * Pairs with successful PDMINETWORKUP::pfnBeginXmit calls. + * + * @param pInterface Pointer to the interface structure containing the + * called function pointer. + * + * @thread Any, but normally EMT or the XMIT thread. + */ + DECLR3CALLBACKMEMBER(void, pfnEndXmit,(PPDMINETWORKUP pInterface)); + + /** + * Set promiscuous mode. + * + * This is called when the promiscuous mode is set. This means that there doesn't have + * to be a mode change when it's called. + * + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param fPromiscuous Set if the adaptor is now in promiscuous mode. Clear if it is not. + * @thread EMT ?? + */ + DECLR3CALLBACKMEMBER(void, pfnSetPromiscuousMode,(PPDMINETWORKUP pInterface, bool fPromiscuous)); + + /** + * Notification on link status changes. + * + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param enmLinkState The new link state. + * @thread EMT ?? + */ + DECLR3CALLBACKMEMBER(void, pfnNotifyLinkChanged,(PPDMINETWORKUP pInterface, PDMNETWORKLINKSTATE enmLinkState)); + + /** @todo Add a callback that informs the driver chain about MAC address changes if we ever implement that. */ + +} PDMINETWORKUP; + +/** Ring-0 edition of PDMINETWORKUP. */ +typedef struct PDMINETWORKUPR0 +{ + /** @copydoc PDMINETWORKUP::pfnBeginXmit */ + DECLR0CALLBACKMEMBER(int, pfnBeginXmit,(PPDMINETWORKUPR0 pInterface, bool fOnWorkerThread)); + /** @copydoc PDMINETWORKUP::pfnAllocBuf */ + DECLR0CALLBACKMEMBER(int, pfnAllocBuf,(PPDMINETWORKUPR0 pInterface, size_t cbMin, PCPDMNETWORKGSO pGso, + PPPDMSCATTERGATHER ppSgBuf)); + /** @copydoc PDMINETWORKUP::pfnFreeBuf */ + DECLR0CALLBACKMEMBER(int, pfnFreeBuf,(PPDMINETWORKUPR0 pInterface, PPDMSCATTERGATHER pSgBuf)); + /** @copydoc PDMINETWORKUP::pfnSendBuf */ + DECLR0CALLBACKMEMBER(int, pfnSendBuf,(PPDMINETWORKUPR0 pInterface, PPDMSCATTERGATHER pSgBuf, bool fOnWorkerThread)); + /** @copydoc PDMINETWORKUP::pfnEndBuf */ + DECLR0CALLBACKMEMBER(void, pfnEndXmit,(PPDMINETWORKUPR0 pInterface)); + /** @copydoc PDMINETWORKUP::pfnSetPromiscuousMode */ + DECLR0CALLBACKMEMBER(void, pfnSetPromiscuousMode,(PPDMINETWORKUPR0 pInterface, bool fPromiscuous)); +} PDMINETWORKUPR0; + +/** Raw-mode context edition of PDMINETWORKUP. */ +typedef struct PDMINETWORKUPRC +{ + /** @copydoc PDMINETWORKUP::pfnBeginXmit */ + DECLRCCALLBACKMEMBER(int, pfnBeginXmit,(PPDMINETWORKUPRC pInterface, bool fOnWorkerThread)); + /** @copydoc PDMINETWORKUP::pfnAllocBuf */ + DECLRCCALLBACKMEMBER(int, pfnAllocBuf,(PPDMINETWORKUPRC pInterface, size_t cbMin, PCPDMNETWORKGSO pGso, + PPPDMSCATTERGATHER ppSgBuf)); + /** @copydoc PDMINETWORKUP::pfnFreeBuf */ + DECLRCCALLBACKMEMBER(int, pfnFreeBuf,(PPDMINETWORKUPRC pInterface, PPDMSCATTERGATHER pSgBuf)); + /** @copydoc PDMINETWORKUP::pfnSendBuf */ + DECLRCCALLBACKMEMBER(int, pfnSendBuf,(PPDMINETWORKUPRC pInterface, PPDMSCATTERGATHER pSgBuf, bool fOnWorkerThread)); + /** @copydoc PDMINETWORKUP::pfnEndBuf */ + DECLRCCALLBACKMEMBER(void, pfnEndXmit,(PPDMINETWORKUPRC pInterface)); + /** @copydoc PDMINETWORKUP::pfnSetPromiscuousMode */ + DECLRCCALLBACKMEMBER(void, pfnSetPromiscuousMode,(PPDMINETWORKUPRC pInterface, bool fPromiscuous)); +} PDMINETWORKUPRC; + +/** PDMINETWORKUP interface ID. */ +#define PDMINETWORKUP_IID "67e7e7a8-2594-4649-a1e3-7cee680c6083" +/** PDMINETWORKUP interface method names. */ +#define PDMINETWORKUP_SYM_LIST "BeginXmit;AllocBuf;FreeBuf;SendBuf;EndXmit;SetPromiscuousMode" + + +/** Pointer to a network config port interface */ +typedef struct PDMINETWORKCONFIG *PPDMINETWORKCONFIG; +/** + * Network config port interface (main). + * No interface pair. + */ +typedef struct PDMINETWORKCONFIG +{ + /** + * Gets the current Media Access Control (MAC) address. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pMac Where to store the MAC address. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnGetMac,(PPDMINETWORKCONFIG pInterface, PRTMAC pMac)); + + /** + * Gets the new link state. + * + * @returns The current link state. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(PDMNETWORKLINKSTATE, pfnGetLinkState,(PPDMINETWORKCONFIG pInterface)); + + /** + * Sets the new link state. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param enmState The new link state + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnSetLinkState,(PPDMINETWORKCONFIG pInterface, PDMNETWORKLINKSTATE enmState)); + +} PDMINETWORKCONFIG; +/** PDMINETWORKCONFIG interface ID. */ +#define PDMINETWORKCONFIG_IID "d6d909e8-716d-415d-b109-534e4478ff4e" + + +/** Pointer to a NAT configuration port. */ +typedef struct PDMINETWORKNATCONFIG *PPDMINETWORKNATCONFIG; +/** + * Network config port interface (main). + * No interface pair. + */ +typedef struct PDMINETWORKNATCONFIG +{ + /** + * Inform NAT about the adding/removing redirection rule + * + * @todo D O C U M E N T M E ! + * @todo s/u16/u/g + */ + DECLR3CALLBACKMEMBER(int, pfnRedirectRuleCommand ,(PPDMINETWORKNATCONFIG pInterface, bool fRemove, + bool fUdp, const char *pHostIp, uint16_t u16HostPort, + const char *pGuestIp, uint16_t u16GuestPort)); + +} PDMINETWORKNATCONFIG; +/** PDMINETWORKNATCONFIG interface ID. */ +#define PDMINETWORKNATCONFIG_IID "0f001d62-4d2f-11df-93b3-2fd0b3a36a6b" +/** @} */ + +RT_C_DECLS_END + +#endif + diff --git a/include/VBox/vmm/pdmnetinline.h b/include/VBox/vmm/pdmnetinline.h new file mode 100644 index 00000000..66c3078f --- /dev/null +++ b/include/VBox/vmm/pdmnetinline.h @@ -0,0 +1,664 @@ +/** @file + * PDM - Networking Helpers, Inlined Code. (DEV,++) + * + * This is all inlined because it's too tedious to create 2-3 libraries to + * contain it all (same bad excuse as for intnetinline.h). + */ + +/* + * Copyright (C) 2010 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include <VBox/log.h> +#include <VBox/types.h> +#include <iprt/asm.h> +#include <iprt/assert.h> +#include <iprt/net.h> +#include <iprt/string.h> + + +/** + * Checksum type. + */ +typedef enum PDMNETCSUMTYPE +{ + /** No checksum. */ + PDMNETCSUMTYPE_NONE = 0, + /** Normal TCP checksum. */ + PDMNETCSUMTYPE_COMPLETE, + /** Checksum on pseudo header (used with GSO). */ + PDMNETCSUMTYPE_PSEUDO, + /** The usual 32-bit hack. */ + PDMNETCSUMTYPE_32_BIT_HACK = 0x7fffffff +} PDMNETCSUMTYPE; + + +/** + * Validates the GSO context. + * + * @returns true if valid, false if not (not asserted or logged). + * @param pGso The GSO context. + * @param cbGsoMax The max size of the GSO context. + * @param cbFrame The max size of the GSO frame (use to validate + * the MSS). + */ +DECLINLINE(bool) PDMNetGsoIsValid(PCPDMNETWORKGSO pGso, size_t cbGsoMax, size_t cbFrame) +{ + PDMNETWORKGSOTYPE enmType; + + if (RT_UNLIKELY(cbGsoMax < sizeof(*pGso))) + return false; + + enmType = (PDMNETWORKGSOTYPE)pGso->u8Type; + if (RT_UNLIKELY( enmType <= PDMNETWORKGSOTYPE_INVALID || enmType >= PDMNETWORKGSOTYPE_END )) + return false; + + /* all types requires both headers. */ + if (RT_UNLIKELY( pGso->offHdr1 < sizeof(RTNETETHERHDR) )) + return false; + if (RT_UNLIKELY( pGso->offHdr2 <= pGso->offHdr1 )) + return false; + if (RT_UNLIKELY( pGso->cbHdrsTotal <= pGso->offHdr2 )) + return false; + + /* min size of the 1st header(s). */ + switch (enmType) + { + case PDMNETWORKGSOTYPE_IPV4_TCP: + case PDMNETWORKGSOTYPE_IPV4_UDP: + if (RT_UNLIKELY( (unsigned)pGso->offHdr2 - pGso->offHdr1 < RTNETIPV4_MIN_LEN )) + return false; + break; + case PDMNETWORKGSOTYPE_IPV6_TCP: + case PDMNETWORKGSOTYPE_IPV6_UDP: + if (RT_UNLIKELY( (unsigned)pGso->offHdr2 - pGso->offHdr1 < RTNETIPV6_MIN_LEN )) + return false; + break; + case PDMNETWORKGSOTYPE_IPV4_IPV6_TCP: + case PDMNETWORKGSOTYPE_IPV4_IPV6_UDP: + if (RT_UNLIKELY( (unsigned)pGso->offHdr2 - pGso->offHdr1 < RTNETIPV4_MIN_LEN + RTNETIPV6_MIN_LEN )) + return false; + break; + case PDMNETWORKGSOTYPE_INVALID: + case PDMNETWORKGSOTYPE_END: + break; + /* no default case! want gcc warnings. */ + } + + /* min size of the 2nd header. */ + switch (enmType) + { + case PDMNETWORKGSOTYPE_IPV4_TCP: + case PDMNETWORKGSOTYPE_IPV6_TCP: + case PDMNETWORKGSOTYPE_IPV4_IPV6_TCP: + if (RT_UNLIKELY( (unsigned)pGso->cbHdrsTotal - pGso->offHdr2 < RTNETTCP_MIN_LEN )) + return false; + break; + case PDMNETWORKGSOTYPE_IPV4_UDP: + case PDMNETWORKGSOTYPE_IPV6_UDP: + case PDMNETWORKGSOTYPE_IPV4_IPV6_UDP: + if (RT_UNLIKELY( (unsigned)pGso->cbHdrsTotal - pGso->offHdr2 < RTNETUDP_MIN_LEN )) + return false; + break; + case PDMNETWORKGSOTYPE_INVALID: + case PDMNETWORKGSOTYPE_END: + break; + /* no default case! want gcc warnings. */ + } + + /* There must be at more than one segment. */ + if (RT_UNLIKELY( cbFrame <= pGso->cbHdrsTotal )) + return false; + if (RT_UNLIKELY( cbFrame - pGso->cbHdrsTotal < pGso->cbMaxSeg )) + return false; + + return true; +} + + +/** + * Returns the length of header for a particular segment/fragment. + * + * We cannot simply treat UDP header as a part of payload because we do not + * want to modify the payload but still need to modify the checksum field in + * UDP header. So we want to include UDP header when calculating the length + * of headers in the first segment getting it copied to a temporary buffer + * along with other headers. + * + * @returns Length of headers (including UDP header for the first fragment). + * @param pGso The GSO context. + * @param iSeg The segment index. + */ +DECLINLINE(uint8_t) pdmNetSegHdrLen(PCPDMNETWORKGSO pGso, uint32_t iSeg) +{ + return iSeg ? pGso->cbHdrsSeg : pGso->cbHdrsTotal; +} + +/** + * Returns the length of payload for a particular segment/fragment. + * + * The first segment does not contain UDP header. The size of UDP header is + * determined as the difference between the total headers size and the size + * used during segmentation. + * + * @returns Length of payload (including UDP header for the first fragment). + * @param pGso The GSO context. + * @param iSeg The segment that we're carving out (0-based). + * @param cSegs The number of segments in the GSO frame. + * @param cbFrame The size of the GSO frame. + */ +DECLINLINE(uint32_t) pdmNetSegPayloadLen(PCPDMNETWORKGSO pGso, uint32_t iSeg, uint32_t cSegs, uint32_t cbFrame) +{ + if (iSeg + 1 == cSegs) + return cbFrame - iSeg * pGso->cbMaxSeg - pdmNetSegHdrLen(pGso, iSeg); + else + return pGso->cbMaxSeg - (iSeg ? 0 : pGso->cbHdrsTotal - pGso->cbHdrsSeg); +} + +/** + * Calculates the number of segments a GSO frame will be segmented into. + * + * @returns Segment count. + * @param pGso The GSO context. + * @param cbFrame The GSO frame size (header proto + payload). + */ +DECLINLINE(uint32_t) PDMNetGsoCalcSegmentCount(PCPDMNETWORKGSO pGso, size_t cbFrame) +{ + size_t cbPayload; + Assert(PDMNetGsoIsValid(pGso, sizeof(*pGso), cbFrame)); + cbPayload = cbFrame - pGso->cbHdrsSeg; + return (uint32_t)((cbPayload + pGso->cbMaxSeg - 1) / pGso->cbMaxSeg); +} + + +/** + * Used to find the IPv6 header when handling 4to6 tunneling. + * + * @returns Offset of the IPv6 header. + * @param pbSegHdrs The headers / frame start. + * @param offIpHdr The offset of the IPv4 header. + */ +DECLINLINE(uint8_t) pgmNetGsoCalcIpv6Offset(uint8_t *pbSegHdrs, uint8_t offIPv4Hdr) +{ + PCRTNETIPV4 pIPv4Hdr = (PCRTNETIPV4)&pbSegHdrs[offIPv4Hdr]; + return offIPv4Hdr + pIPv4Hdr->ip_hl * 4; +} + + +/** + * Update an UDP header after carving out a segment + * + * @param u32PseudoSum The pseudo checksum. + * @param pbSegHdrs Pointer to the header bytes / frame start. + * @param offUdpHdr The offset into @a pbSegHdrs of the UDP header. + * @param pbPayload Pointer to the payload bytes. + * @param cbPayload The amount of payload. + * @param cbHdrs The size of all the headers. + * @param enmCsumType Whether to checksum the payload, the pseudo + * header or nothing. + * @internal + */ +DECLINLINE(void) pdmNetGsoUpdateUdpHdr(uint32_t u32PseudoSum, uint8_t *pbSegHdrs, uint8_t offUdpHdr, + uint8_t const *pbPayload, uint32_t cbPayload, uint8_t cbHdrs, + PDMNETCSUMTYPE enmCsumType) +{ + PRTNETUDP pUdpHdr = (PRTNETUDP)&pbSegHdrs[offUdpHdr]; + pUdpHdr->uh_ulen = RT_H2N_U16(cbPayload + cbHdrs - offUdpHdr); + switch (enmCsumType) + { + case PDMNETCSUMTYPE_NONE: + pUdpHdr->uh_sum = 0; + break; + case PDMNETCSUMTYPE_COMPLETE: + pUdpHdr->uh_sum = RTNetUDPChecksum(u32PseudoSum, pUdpHdr); + break; + case PDMNETCSUMTYPE_PSEUDO: + pUdpHdr->uh_sum = ~RTNetIPv4FinalizeChecksum(u32PseudoSum); + break; + default: + NOREF(pbPayload); + AssertFailed(); + break; + } +} + + +/** + * Update an UDP header after carving out an IP fragment + * + * @param u32PseudoSum The pseudo checksum. + * @param pbSegHdrs Pointer to the header bytes copy + * @param pbFrame Pointer to the frame start. + * @param offUdpHdr The offset into @a pbSegHdrs of the UDP header. + * + * @internal + */ +DECLINLINE(void) pdmNetGsoUpdateUdpHdrUfo(uint32_t u32PseudoSum, uint8_t *pbSegHdrs, const uint8_t *pbFrame, uint8_t offUdpHdr) +{ + PCRTNETUDP pcUdpHdrOrig = (PCRTNETUDP)&pbFrame[offUdpHdr]; + PRTNETUDP pUdpHdr = (PRTNETUDP)&pbSegHdrs[offUdpHdr]; + pUdpHdr->uh_sum = RTNetUDPChecksum(u32PseudoSum, pcUdpHdrOrig); +} + + +/** + * Update a TCP header after carving out a segment. + * + * @param u32PseudoSum The pseudo checksum. + * @param pbSegHdrs Pointer to the header bytes / frame start. + * @param offTcpHdr The offset into @a pbSegHdrs of the TCP header. + * @param pbPayload Pointer to the payload bytes. + * @param cbPayload The amount of payload. + * @param offPayload The offset into the payload that we're splitting + * up. We're ASSUMING that the payload follows + * immediately after the TCP header w/ options. + * @param cbHdrs The size of all the headers. + * @param fLastSeg Set if this is the last segment. + * @param enmCsumType Whether to checksum the payload, the pseudo + * header or nothing. + * @internal + */ +DECLINLINE(void) pdmNetGsoUpdateTcpHdr(uint32_t u32PseudoSum, uint8_t *pbSegHdrs, uint8_t offTcpHdr, + uint8_t const *pbPayload, uint32_t cbPayload, uint32_t offPayload, uint8_t cbHdrs, + bool fLastSeg, PDMNETCSUMTYPE enmCsumType) +{ + PRTNETTCP pTcpHdr = (PRTNETTCP)&pbSegHdrs[offTcpHdr]; + pTcpHdr->th_seq = RT_H2N_U32(RT_N2H_U32(pTcpHdr->th_seq) + offPayload); + if (!fLastSeg) + pTcpHdr->th_flags &= ~(RTNETTCP_F_FIN | RTNETTCP_F_PSH); + switch (enmCsumType) + { + case PDMNETCSUMTYPE_NONE: + pTcpHdr->th_sum = 0; + break; + case PDMNETCSUMTYPE_COMPLETE: + pTcpHdr->th_sum = RTNetTCPChecksum(u32PseudoSum, pTcpHdr, pbPayload, cbPayload); + break; + case PDMNETCSUMTYPE_PSEUDO: + pTcpHdr->th_sum = ~RTNetIPv4FinalizeChecksum(u32PseudoSum); + break; + default: + NOREF(cbHdrs); + AssertFailed(); + break; + } +} + + +/** + * Updates a IPv6 header after carving out a segment. + * + * @returns 32-bit intermediary checksum value for the pseudo header. + * @param pbSegHdrs Pointer to the header bytes. + * @param offIpHdr The offset into @a pbSegHdrs of the IP header. + * @param cbSegPayload The amount of segmented payload. Not to be + * confused with the IP payload. + * @param cbHdrs The size of all the headers. + * @param offPktHdr Offset of the protocol packet header. For the + * pseudo header checksum calulation. + * @param bProtocol The protocol type. For the pseudo header. + * @internal + */ +DECLINLINE(uint32_t) pdmNetGsoUpdateIPv6Hdr(uint8_t *pbSegHdrs, uint8_t offIpHdr, uint32_t cbSegPayload, uint8_t cbHdrs, + uint8_t offPktHdr, uint8_t bProtocol) +{ + PRTNETIPV6 pIpHdr = (PRTNETIPV6)&pbSegHdrs[offIpHdr]; + uint16_t cbPayload = (uint16_t)(cbHdrs - (offIpHdr + sizeof(RTNETIPV6)) + cbSegPayload); + pIpHdr->ip6_plen = RT_H2N_U16(cbPayload); + return RTNetIPv6PseudoChecksumEx(pIpHdr, bProtocol, (uint16_t)(cbHdrs - offPktHdr + cbSegPayload)); +} + + +/** + * Updates a IPv4 header after carving out a segment. + * + * @returns 32-bit intermediary checksum value for the pseudo header. + * @param pbSegHdrs Pointer to the header bytes. + * @param offIpHdr The offset into @a pbSegHdrs of the IP header. + * @param cbSegPayload The amount of segmented payload. + * @param iSeg The segment index. + * @param cbHdrs The size of all the headers. + * @internal + */ +DECLINLINE(uint32_t) pdmNetGsoUpdateIPv4Hdr(uint8_t *pbSegHdrs, uint8_t offIpHdr, uint32_t cbSegPayload, + uint32_t iSeg, uint8_t cbHdrs) +{ + PRTNETIPV4 pIpHdr = (PRTNETIPV4)&pbSegHdrs[offIpHdr]; + pIpHdr->ip_len = RT_H2N_U16(cbHdrs - offIpHdr + cbSegPayload); + pIpHdr->ip_id = RT_H2N_U16(RT_N2H_U16(pIpHdr->ip_id) + iSeg); + pIpHdr->ip_sum = RTNetIPv4HdrChecksum(pIpHdr); + return RTNetIPv4PseudoChecksum(pIpHdr); +} + + +/** + * Updates a IPv4 header after carving out an IP fragment. + * + * @param pbSegHdrs Pointer to the header bytes. + * @param offIpHdr The offset into @a pbSegHdrs of the IP header. + * @param cbSegPayload The amount of segmented payload. + * @param offFragment The offset of this fragment for reassembly. + * @param iSeg The segment index. + * @param cbHdrs The size of all the headers. + * @param fLastFragment True if this is the last fragment of datagram. + * @internal + */ +DECLINLINE(void) pdmNetGsoUpdateIPv4HdrUfo(uint8_t *pbSegHdrs, uint8_t offIpHdr, uint32_t cbSegPayload, + uint32_t offFragment, uint8_t cbHdrs, bool fLastFragment) +{ + PRTNETIPV4 pIpHdr = (PRTNETIPV4)&pbSegHdrs[offIpHdr]; + pIpHdr->ip_len = RT_H2N_U16(cbHdrs - offIpHdr + cbSegPayload); + pIpHdr->ip_off = RT_H2N_U16((offFragment / 8) | (fLastFragment ? 0 : RTNETIPV4_FLAGS_MF)); + pIpHdr->ip_sum = RTNetIPv4HdrChecksum(pIpHdr); +} + + +/** + * Carves out the specified segment in a destructive manner. + * + * This is for sequentially carving out segments and pushing them along for + * processing or sending. To avoid allocating a temporary buffer for + * constructing the segment in, we trash the previous frame by putting the + * header at the end of it. + * + * @returns Pointer to the segment frame that we've carved out. + * @param pGso The GSO context data. + * @param pbFrame Pointer to the GSO frame. + * @param cbFrame The size of the GSO frame. + * @param pbHdrScatch Pointer to a pGso->cbHdrs sized area where we + * can save the original header prototypes on the + * first call (@a iSeg is 0) and retrieve it on + * susequent calls. (Just use a 256 bytes + * buffer to make life easy.) + * @param iSeg The segment that we're carving out (0-based). + * @param cSegs The number of segments in the GSO frame. Use + * PDMNetGsoCalcSegmentCount to find this. + * @param pcbSegFrame Where to return the size of the returned segment + * frame. + */ +DECLINLINE(void *) PDMNetGsoCarveSegmentQD(PCPDMNETWORKGSO pGso, uint8_t *pbFrame, size_t cbFrame, uint8_t *pbHdrScatch, + uint32_t iSeg, uint32_t cSegs, uint32_t *pcbSegFrame) +{ + /* + * Figure out where the payload is and where the header starts before we + * do the protocol specific carving. + */ + uint8_t * const pbSegHdrs = pbFrame + pGso->cbMaxSeg * iSeg; + uint8_t * const pbSegPayload = pbSegHdrs + pGso->cbHdrsSeg; + uint32_t const cbSegPayload = pdmNetSegPayloadLen(pGso, iSeg, cSegs, (uint32_t)cbFrame); + uint32_t const cbSegFrame = cbSegPayload + pGso->cbHdrsSeg; + + /* + * Check assumptions (doing it after declaring the variables because of C). + */ + Assert(iSeg < cSegs); + Assert(cSegs == PDMNetGsoCalcSegmentCount(pGso, cbFrame)); + Assert(PDMNetGsoIsValid(pGso, sizeof(*pGso), cbFrame)); + + /* + * Copy the header and do the protocol specific massaging of it. + */ + if (iSeg != 0) + memcpy(pbSegHdrs, pbHdrScatch, pGso->cbHdrsSeg); + else + memcpy(pbHdrScatch, pbSegHdrs, pGso->cbHdrsSeg); /* There is no need to save UDP header */ + + switch ((PDMNETWORKGSOTYPE)pGso->u8Type) + { + case PDMNETWORKGSOTYPE_IPV4_TCP: + pdmNetGsoUpdateTcpHdr(pdmNetGsoUpdateIPv4Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, iSeg, pGso->cbHdrsSeg), + pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, iSeg * pGso->cbMaxSeg, + pGso->cbHdrsSeg, iSeg + 1 == cSegs, PDMNETCSUMTYPE_COMPLETE); + break; + case PDMNETWORKGSOTYPE_IPV4_UDP: + if (iSeg == 0) + pdmNetGsoUpdateUdpHdrUfo(RTNetIPv4PseudoChecksum((PRTNETIPV4)&pbFrame[pGso->offHdr1]), + pbSegHdrs, pbFrame, pGso->offHdr2); + pdmNetGsoUpdateIPv4HdrUfo(pbSegHdrs, pGso->offHdr1, cbSegPayload, iSeg * pGso->cbMaxSeg, + pdmNetSegHdrLen(pGso, iSeg), iSeg + 1 == cSegs); + break; + case PDMNETWORKGSOTYPE_IPV6_TCP: + pdmNetGsoUpdateTcpHdr(pdmNetGsoUpdateIPv6Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, pGso->cbHdrsSeg, + pGso->offHdr2, RTNETIPV4_PROT_TCP), + pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, iSeg * pGso->cbMaxSeg, + pGso->cbHdrsSeg, iSeg + 1 == cSegs, PDMNETCSUMTYPE_COMPLETE); + break; + case PDMNETWORKGSOTYPE_IPV6_UDP: + pdmNetGsoUpdateUdpHdr(pdmNetGsoUpdateIPv6Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, pGso->cbHdrsSeg, + pGso->offHdr2, RTNETIPV4_PROT_UDP), + pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, pGso->cbHdrsSeg, PDMNETCSUMTYPE_COMPLETE); + break; + case PDMNETWORKGSOTYPE_IPV4_IPV6_TCP: + pdmNetGsoUpdateIPv4Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, iSeg, pGso->cbHdrsSeg); + pdmNetGsoUpdateTcpHdr(pdmNetGsoUpdateIPv6Hdr(pbSegHdrs, pgmNetGsoCalcIpv6Offset(pbSegHdrs, pGso->offHdr1), + cbSegPayload, pGso->cbHdrsSeg, pGso->offHdr2, RTNETIPV4_PROT_TCP), + pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, iSeg * pGso->cbMaxSeg, + pGso->cbHdrsSeg, iSeg + 1 == cSegs, PDMNETCSUMTYPE_COMPLETE); + break; + case PDMNETWORKGSOTYPE_IPV4_IPV6_UDP: + pdmNetGsoUpdateIPv4Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, iSeg, pGso->cbHdrsSeg); + pdmNetGsoUpdateUdpHdr(pdmNetGsoUpdateIPv6Hdr(pbSegHdrs, pgmNetGsoCalcIpv6Offset(pbSegHdrs, pGso->offHdr1), + cbSegPayload, pGso->cbHdrsSeg, pGso->offHdr2, RTNETIPV4_PROT_UDP), + pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, pGso->cbHdrsSeg, PDMNETCSUMTYPE_COMPLETE); + break; + case PDMNETWORKGSOTYPE_INVALID: + case PDMNETWORKGSOTYPE_END: + /* no default! wnat gcc warnings. */ + break; + } + + *pcbSegFrame = cbSegFrame; + return pbSegHdrs; +} + + +/** + * Carves out the specified segment in a non-destructive manner. + * + * The segment headers and segment payload is kept separate here. The GSO frame + * is still expected to be one linear chunk of data, but we don't modify any of + * it. + * + * @returns The offset into the GSO frame of the payload. + * @param pGso The GSO context data. + * @param pbFrame Pointer to the GSO frame. Used for retrieving + * the header prototype and for checksumming the + * payload. The buffer is not modified. + * @param cbFrame The size of the GSO frame. + * @param iSeg The segment that we're carving out (0-based). + * @param cSegs The number of segments in the GSO frame. Use + * PDMNetGsoCalcSegmentCount to find this. + * @param pbSegHdrs Where to return the headers for the segment + * that's been carved out. The buffer must be at + * least pGso->cbHdrs in size, using a 256 byte + * buffer is a recommended simplification. + * @param pcbSegHdrs Where to return the size of the returned + * segment headers. + * @param pcbSegPayload Where to return the size of the returned + * segment payload. + */ +DECLINLINE(uint32_t) PDMNetGsoCarveSegment(PCPDMNETWORKGSO pGso, const uint8_t *pbFrame, size_t cbFrame, + uint32_t iSeg, uint32_t cSegs, uint8_t *pbSegHdrs, + uint32_t *pcbSegHdrs, uint32_t *pcbSegPayload) +{ + /* + * Figure out where the payload is and where the header starts before we + * do the protocol specific carving. + */ + uint32_t const cbSegHdrs = pdmNetSegHdrLen(pGso, iSeg); + uint8_t const * const pbSegPayload = pbFrame + cbSegHdrs + iSeg * pGso->cbMaxSeg; + uint32_t const cbSegPayload = pdmNetSegPayloadLen(pGso, iSeg, cSegs, (uint32_t)cbFrame); + + /* + * Check assumptions (doing it after declaring the variables because of C). + */ + Assert(iSeg < cSegs); + Assert(cSegs == PDMNetGsoCalcSegmentCount(pGso, cbFrame)); + Assert(PDMNetGsoIsValid(pGso, sizeof(*pGso), cbFrame)); + + /* + * Copy the header and do the protocol specific massaging of it. + */ + memcpy(pbSegHdrs, pbFrame, pGso->cbHdrsTotal); /* include UDP header */ + + switch ((PDMNETWORKGSOTYPE)pGso->u8Type) + { + case PDMNETWORKGSOTYPE_IPV4_TCP: + pdmNetGsoUpdateTcpHdr(pdmNetGsoUpdateIPv4Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, iSeg, cbSegHdrs), + pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, iSeg * pGso->cbMaxSeg, + cbSegHdrs, iSeg + 1 == cSegs, PDMNETCSUMTYPE_COMPLETE); + break; + case PDMNETWORKGSOTYPE_IPV4_UDP: + if (iSeg == 0) + pdmNetGsoUpdateUdpHdrUfo(RTNetIPv4PseudoChecksum((PRTNETIPV4)&pbFrame[pGso->offHdr1]), + pbSegHdrs, pbFrame, pGso->offHdr2); + pdmNetGsoUpdateIPv4HdrUfo(pbSegHdrs, pGso->offHdr1, cbSegPayload, iSeg * pGso->cbMaxSeg, + cbSegHdrs, iSeg + 1 == cSegs); + break; + case PDMNETWORKGSOTYPE_IPV6_TCP: + pdmNetGsoUpdateTcpHdr(pdmNetGsoUpdateIPv6Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, cbSegHdrs, + pGso->offHdr2, RTNETIPV4_PROT_TCP), + pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, iSeg * pGso->cbMaxSeg, + cbSegHdrs, iSeg + 1 == cSegs, PDMNETCSUMTYPE_COMPLETE); + break; + case PDMNETWORKGSOTYPE_IPV6_UDP: + pdmNetGsoUpdateUdpHdr(pdmNetGsoUpdateIPv6Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, cbSegHdrs, + pGso->offHdr2, RTNETIPV4_PROT_UDP), + pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, cbSegHdrs, PDMNETCSUMTYPE_COMPLETE); + break; + case PDMNETWORKGSOTYPE_IPV4_IPV6_TCP: + pdmNetGsoUpdateIPv4Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, iSeg, cbSegHdrs); + pdmNetGsoUpdateTcpHdr(pdmNetGsoUpdateIPv6Hdr(pbSegHdrs, pgmNetGsoCalcIpv6Offset(pbSegHdrs, pGso->offHdr1), + cbSegPayload, cbSegHdrs, pGso->offHdr2, RTNETIPV4_PROT_TCP), + pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, iSeg * pGso->cbMaxSeg, + cbSegHdrs, iSeg + 1 == cSegs, PDMNETCSUMTYPE_COMPLETE); + break; + case PDMNETWORKGSOTYPE_IPV4_IPV6_UDP: + pdmNetGsoUpdateIPv4Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, iSeg, cbSegHdrs); + pdmNetGsoUpdateUdpHdr(pdmNetGsoUpdateIPv6Hdr(pbSegHdrs, pgmNetGsoCalcIpv6Offset(pbSegHdrs, pGso->offHdr1), + cbSegPayload, cbSegHdrs, pGso->offHdr2, RTNETIPV4_PROT_UDP), + pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, cbSegHdrs, PDMNETCSUMTYPE_COMPLETE); + break; + case PDMNETWORKGSOTYPE_INVALID: + case PDMNETWORKGSOTYPE_END: + /* no default! wnat gcc warnings. */ + break; + } + + *pcbSegHdrs = cbSegHdrs; + *pcbSegPayload = cbSegPayload; + return cbSegHdrs + iSeg * pGso->cbMaxSeg; +} + + +/** + * Prepares the GSO frame for direct use without any segmenting. + * + * @param pGso The GSO context. + * @param pvFrame The frame to prepare. + * @param cbFrame The frame size. + * @param enmCsumType Whether to checksum the payload, the pseudo + * header or nothing. + */ +DECLINLINE(void) PDMNetGsoPrepForDirectUse(PCPDMNETWORKGSO pGso, void *pvFrame, size_t cbFrame, PDMNETCSUMTYPE enmCsumType) +{ + /* + * Figure out where the payload is and where the header starts before we + * do the protocol bits. + */ + uint8_t * const pbHdrs = (uint8_t *)pvFrame; + uint8_t * const pbPayload = pbHdrs + pGso->cbHdrsTotal; + uint32_t const cbFrame32 = (uint32_t)cbFrame; + uint32_t const cbPayload = cbFrame32 - pGso->cbHdrsTotal; + + /* + * Check assumptions (doing it after declaring the variables because of C). + */ + Assert(PDMNetGsoIsValid(pGso, sizeof(*pGso), cbFrame)); + + /* + * Get down to busienss. + */ + switch ((PDMNETWORKGSOTYPE)pGso->u8Type) + { + case PDMNETWORKGSOTYPE_IPV4_TCP: + pdmNetGsoUpdateTcpHdr(pdmNetGsoUpdateIPv4Hdr(pbHdrs, pGso->offHdr1, cbFrame32 - pGso->cbHdrsTotal, 0, pGso->cbHdrsTotal), + pbHdrs, pGso->offHdr2, pbPayload, cbPayload, 0, pGso->cbHdrsTotal, true, enmCsumType); + break; + case PDMNETWORKGSOTYPE_IPV4_UDP: + pdmNetGsoUpdateUdpHdr(pdmNetGsoUpdateIPv4Hdr(pbHdrs, pGso->offHdr1, cbFrame32 - pGso->cbHdrsTotal, 0, pGso->cbHdrsTotal), + pbHdrs, pGso->offHdr2, pbPayload, cbPayload, pGso->cbHdrsTotal, enmCsumType); + break; + case PDMNETWORKGSOTYPE_IPV6_TCP: + pdmNetGsoUpdateTcpHdr(pdmNetGsoUpdateIPv6Hdr(pbHdrs, pGso->offHdr1, cbPayload, pGso->cbHdrsTotal, + pGso->offHdr2, RTNETIPV4_PROT_TCP), + pbHdrs, pGso->offHdr2, pbPayload, cbPayload, 0, pGso->cbHdrsTotal, true, enmCsumType); + break; + case PDMNETWORKGSOTYPE_IPV6_UDP: + pdmNetGsoUpdateUdpHdr(pdmNetGsoUpdateIPv6Hdr(pbHdrs, pGso->offHdr1, cbPayload, pGso->cbHdrsTotal, + pGso->offHdr2, RTNETIPV4_PROT_UDP), + pbHdrs, pGso->offHdr2, pbPayload, cbPayload, pGso->cbHdrsTotal, enmCsumType); + break; + case PDMNETWORKGSOTYPE_IPV4_IPV6_TCP: + pdmNetGsoUpdateIPv4Hdr(pbHdrs, pGso->offHdr1, cbPayload, 0, pGso->cbHdrsTotal); + pdmNetGsoUpdateTcpHdr(pdmNetGsoUpdateIPv6Hdr(pbHdrs, pgmNetGsoCalcIpv6Offset(pbHdrs, pGso->offHdr1), + cbPayload, pGso->cbHdrsTotal, pGso->offHdr2, RTNETIPV4_PROT_TCP), + pbHdrs, pGso->offHdr2, pbPayload, cbPayload, 0, pGso->cbHdrsTotal, true, enmCsumType); + break; + case PDMNETWORKGSOTYPE_IPV4_IPV6_UDP: + pdmNetGsoUpdateIPv4Hdr(pbHdrs, pGso->offHdr1, cbPayload, 0, pGso->cbHdrsTotal); + pdmNetGsoUpdateUdpHdr(pdmNetGsoUpdateIPv6Hdr(pbHdrs, pgmNetGsoCalcIpv6Offset(pbHdrs, pGso->offHdr1), + cbPayload, pGso->cbHdrsTotal, pGso->offHdr2, RTNETIPV4_PROT_UDP), + pbHdrs, pGso->offHdr2, pbPayload, cbPayload, pGso->cbHdrsTotal, enmCsumType); + break; + case PDMNETWORKGSOTYPE_INVALID: + case PDMNETWORKGSOTYPE_END: + /* no default! wnat gcc warnings. */ + break; + } +} + + +/** + * Gets the GSO type name string. + * + * @returns Pointer to read only name string. + * @param enmType The type. + */ +DECLINLINE(const char *) PDMNetGsoTypeName(PDMNETWORKGSOTYPE enmType) +{ + switch (enmType) + { + case PDMNETWORKGSOTYPE_IPV4_TCP: return "TCPv4"; + case PDMNETWORKGSOTYPE_IPV6_TCP: return "TCPv6"; + case PDMNETWORKGSOTYPE_IPV4_UDP: return "UDPv4"; + case PDMNETWORKGSOTYPE_IPV6_UDP: return "UDPv6"; + case PDMNETWORKGSOTYPE_IPV4_IPV6_TCP: return "4to6TCP"; + case PDMNETWORKGSOTYPE_IPV4_IPV6_UDP: return "4to6UDP"; + case PDMNETWORKGSOTYPE_INVALID: return "invalid"; + case PDMNETWORKGSOTYPE_END: return "end"; + } + return "bad-gso-type"; +} + diff --git a/include/VBox/vmm/pdmnetshaper.h b/include/VBox/vmm/pdmnetshaper.h new file mode 100644 index 00000000..b2aa5bab --- /dev/null +++ b/include/VBox/vmm/pdmnetshaper.h @@ -0,0 +1,120 @@ +/** @file + * PDM - Pluggable Device Manager, Network Shaper. + */ + +/* + * Copyright (C) 2011-2012 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_pdmnetshaper_h +#define ___VBox_vmm_pdmnetshaper_h + +#include <VBox/types.h> +#include <VBox/err.h> +#include <VBox/vmm/pdmnetifs.h> +#include <iprt/assert.h> +#include <iprt/sg.h> + + +#define PDM_NETSHAPER_MIN_BUCKET_SIZE 65536 /* bytes */ +#define PDM_NETSHAPER_MAX_LATENCY 100 /* milliseconds */ + +RT_C_DECLS_BEGIN + +typedef struct PDMNSFILTER +{ + /** [R3] Pointer to the next group in the list. */ + struct PDMNSFILTER *pNext; + /** [R3] Pointer to the bandwidth group. */ + struct PDMNSBWGROUP *pBwGroupR3; + /** [R0] Pointer to the bandwidth group. */ + R0PTRTYPE(struct PDMNSBWGROUP *) pBwGroupR0; + /** Becomes true when filter fails to obtain bandwidth. */ + bool fChoked; + /** [R3] The driver this filter is aggregated into. */ + PPDMINETWORKDOWN pIDrvNet; +} PDMNSFILTER; + +/** @defgroup grp_pdm_net_shaper The PDM Network Shaper API + * @ingroup grp_pdm + * @{ + */ + +/** Pointer to a PDM filter handle. */ +typedef struct PDMNSFILTER *PPDMNSFILTER; +/** Pointer to a network shaper. */ +typedef struct PDMNETSHAPER *PPDMNETSHAPER; + + +/** + * Obtain bandwidth in a bandwidth group (R0 version). + * + * @returns VBox status code. + * @param pFilter Pointer to the filter that allocates bandwidth. + * @param cbTransfer Number of bytes to allocate. + */ +VMMR0DECL(bool) PDMR0NsAllocateBandwidth(PPDMNSFILTER pFilter, size_t cbTransfer); + +/** + * Obtain bandwidth in a bandwidth group. + * + * @returns VBox status code. + * @param pFilter Pointer to the filter that allocates bandwidth. + * @param cbTransfer Number of bytes to allocate. + */ +VMMR3DECL(bool) PDMR3NsAllocateBandwidth(PPDMNSFILTER pFilter, size_t cbTransfer); + +/** + * Attach network filter driver from bandwidth group. + * + * @returns VBox status code. + * @param pVM Handle of VM. + * @param pDrvIns The driver instance. + * @param pcszBwGroup Name of the bandwidth group to attach to. + * @param pFilter Pointer to the filter we attach. + */ +VMMR3DECL(int) PDMR3NsAttach(PVM pVM, PPDMDRVINS pDrvIns, const char *pcszBwGroup, PPDMNSFILTER pFilter); + +/** + * Detach network filter driver from bandwidth group. + * + * @returns VBox status code. + * @param pVM Handle of VM. + * @param pDrvIns The driver instance. + * @param pFilter Pointer to the filter we detach. + */ +VMMR3DECL(int) PDMR3NsDetach(PVM pVM, PPDMDRVINS pDrvIns, PPDMNSFILTER pFilter); + +/** + * Adjusts the maximum rate for the bandwidth group. + * + * @returns VBox status code. + * @param pVM Handle of VM. + * @param pcszBwGroup Name of the bandwidth group to attach to. + * @param cbTransferPerSecMax Maximum number of bytes per second to be transmitted. + */ +VMMR3DECL(int) PDMR3NsBwGroupSetLimit(PVM pVM, const char *pcszBwGroup, uint64_t cbTransferPerSecMax); + +/** @} */ + +RT_C_DECLS_END + +#endif + diff --git a/include/VBox/vmm/pdmnetshaperint.h b/include/VBox/vmm/pdmnetshaperint.h new file mode 100644 index 00000000..3bbfcda7 --- /dev/null +++ b/include/VBox/vmm/pdmnetshaperint.h @@ -0,0 +1,94 @@ +/* $Id: pdmnetshaperint.h $ */ +/** @file + * PDM Network Shaper - Internal data structures and functions common for both + * R0 and R3 parts. + */ + +/* + * Copyright (C) 2011-2012 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +/** + * Bandwidth group instance data + */ +typedef struct PDMNSBWGROUP +{ + /** Pointer to the next group in the list. */ + struct PDMNSBWGROUP *pNext; + /** Pointer to the shared UVM structure. */ + struct PDMNETSHAPER *pShaper; + /** Critical section protecting all members below. */ + PDMCRITSECT cs; + /** Pointer to the first filter attached to this group. */ + struct PDMNSFILTER *pFiltersHead; + /** Bandwidth group name. */ + char *pszName; + /** Maximum number of bytes filters are allowed to transfer. */ + volatile uint64_t cbTransferPerSecMax; + /** Number of bytes we are allowed to transfer in one burst. */ + volatile uint32_t cbBucketSize; + /** Number of bytes we were allowed to transfer at the last update. */ + volatile uint32_t cbTokensLast; + /** Timestamp of the last update */ + volatile uint64_t tsUpdatedLast; + /** Reference counter - How many filters are associated with this group. */ + volatile uint32_t cRefs; +} PDMNSBWGROUP; +/** Pointer to a bandwidth group. */ +typedef PDMNSBWGROUP *PPDMNSBWGROUP; + +DECLINLINE(bool) pdmNsAllocateBandwidth(PPDMNSFILTER pFilter, size_t cbTransfer) +{ + AssertPtrReturn(pFilter, true); + if (!VALID_PTR(pFilter->CTX_SUFF(pBwGroup))) + return true; + + PPDMNSBWGROUP pBwGroup = ASMAtomicReadPtrT(&pFilter->CTX_SUFF(pBwGroup), PPDMNSBWGROUP); + int rc = PDMCritSectEnter(&pBwGroup->cs, VERR_SEM_BUSY); AssertRC(rc); + if (RT_UNLIKELY(rc == VERR_SEM_BUSY)) + return true; + bool fAllowed = true; + if (pBwGroup->cbTransferPerSecMax) + { + /* Re-fill the bucket first */ + uint64_t tsNow = RTTimeSystemNanoTS(); + uint32_t uTokensAdded = (tsNow - pBwGroup->tsUpdatedLast)*pBwGroup->cbTransferPerSecMax/(1000*1000*1000); + uint32_t uTokens = RT_MIN(pBwGroup->cbBucketSize, uTokensAdded + pBwGroup->cbTokensLast); + + if (cbTransfer > uTokens) + { + fAllowed = false; + ASMAtomicWriteBool(&pFilter->fChoked, true); + } + else + { + pBwGroup->tsUpdatedLast = tsNow; + pBwGroup->cbTokensLast = uTokens - (uint32_t)cbTransfer; + } + Log2((LOG_FN_FMT "BwGroup=%#p{%s} cbTransfer=%u uTokens=%u uTokensAdded=%u fAllowed=%RTbool\n", + __PRETTY_FUNCTION__, pBwGroup, pBwGroup->pszName, cbTransfer, uTokens, uTokensAdded, fAllowed)); + } + else + Log2((LOG_FN_FMT "BwGroup=%#p{%s} disabled fAllowed=%RTbool\n", + __PRETTY_FUNCTION__, pBwGroup, pBwGroup->pszName, fAllowed)); + + rc = PDMCritSectLeave(&pBwGroup->cs); AssertRC(rc); + return fAllowed; +} diff --git a/include/VBox/vmm/pdmnvram.h b/include/VBox/vmm/pdmnvram.h new file mode 100644 index 00000000..10c1abc4 --- /dev/null +++ b/include/VBox/vmm/pdmnvram.h @@ -0,0 +1,70 @@ +/** @file + * PDM - Pluggable Device Manager, EFI NVRAM storage back-end. + */ + +/* + * Copyright (C) 2012 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_pdmnvram_h_ +#define ___VBox_vmm_pdmnvram_h_ + +#include <VBox/types.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_ifs_nvram NVRAM Interface + * @ingroup grp_pdm_interfaces + * @{ + */ + +typedef struct PDMINVRAM *PPDMINVRAM; + +typedef struct PDMINVRAM +{ + /** + * This method flushes all values in the storage. + */ + DECLR3CALLBACKMEMBER(int, pfnFlushNvramStorage, (PPDMINVRAM pInterface)); + + /** + * This method store NVRAM variable to storage + */ + DECLR3CALLBACKMEMBER(int, pfnStoreNvramValue, (PPDMINVRAM pInterface, int idxVariable, RTUUID *pVendorUuid, const char *pcszVariableName, size_t cbVariableName, uint8_t *pu8Value, size_t cbValue)); + + /** + * This method load NVRAM variable to storage + */ + DECLR3CALLBACKMEMBER(int, pfnLoadNvramValue, (PPDMINVRAM pInterface, int idxVariable, RTUUID *pVendorUuid, char *pcszVariableName, size_t *pcbVariableName, uint8_t *pu8Value, size_t *pcbValue)); + +} PDMINVRAM; + + +#define PDMINVRAM_IID "11226408-CB4C-4369-9218-1EE0092FB9F8" + +/** @} */ + +RT_C_DECLS_END + + +#endif + + diff --git a/include/VBox/vmm/pdmpci.h b/include/VBox/vmm/pdmpci.h new file mode 100644 index 00000000..16d925f1 --- /dev/null +++ b/include/VBox/vmm/pdmpci.h @@ -0,0 +1,398 @@ +/** @file + * PDM - Pluggable Device Manager, raw PCI Devices. (VMM) + */ + +/* + * Copyright (C) 2010-2011 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_pdmpci_h +#define ___VBox_vmm_pdmpci_h + +#include <VBox/types.h> +#include <VBox/rawpci.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_pcidev The raw PCI Devices API + * @ingroup grp_pdm + * @{ + */ + +typedef struct PDMIPCIRAW *PPDMIPCIRAW; +typedef struct PDMIPCIRAW +{ + /** + * Notify virtual device that interrupt has arrived. + * For this callback to be called, interface have to be + * registered with PDMIPCIRAWUP::pfnRegisterInterruptListener. + * + * @note no level parameter, as we can only support flip-flop. + * + * @param pInterface Pointer to this interface structure. + * @param iGuestIrq Guest interrupt number, passed earlier when registering listener. + * + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnInterruptRequest ,(PPDMIPCIRAW pInterface, int32_t iGuestIrq)); +} PDMIPCIRAW; + +typedef struct PDMIPCIRAWUP *PPDMIPCIRAWUP; +typedef struct PDMIPCIRAWUP +{ + /** + * Host PCI MMIO access function. + */ + + /** + * Request driver info about PCI region on host PCI device. + * + * @returns true, if region is present, and out parameters are correct + * @param pInterface Pointer to this interface structure. + * @param iRegion Region number. + * @param pRegStart Where to store region base address (guest). + * @param piRegSize Where to store region size. + * + * @param fMmio If region is MMIO or IO. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(bool, pfnGetRegionInfo, (PPDMIPCIRAWUP pInterface, + int32_t iRegion, + RTGCPHYS *pRegStart, + uint64_t *piRegSize, + uint32_t *pfFlags + )); + + /** + * Request driver to map part of host device's MMIO region to the VM process and maybe kernel. + * Shall only be issued within earlier obtained with pfnGetRegionInfo() + * host physical address ranges for the device BARs. Even if failed, device still may function + * using pfnMmio* and pfnPio* operations, just much slower. + * + * @returns status code + * @param pInterface Pointer to this interface structure. + * @param iRegion Number of the region. + * @param StartAddress Host physical address of start. + * @param iRegionSize Size of the region. + * @param fFlags Flags, currently lowest significant bit set if R0 mapping requested too + * @param ppvAddressR3 Where to store mapped region address for R3 (can be 0, if cannot map into userland) + * @param ppvAddressR0 Where to store mapped region address for R0 (can be 0, if cannot map into kernel) + * + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnMapRegion, (PPDMIPCIRAWUP pInterface, + int32_t iRegion, + RTHCPHYS StartAddress, + uint64_t iRegionSize, + uint32_t fFlags, + RTR3PTR *ppvAddressR3, + RTR0PTR *ppvAddressR0 + )); + + /** + * Request driver to unmap part of host device's MMIO region to the VM process. + * Shall only be issued with pointer earlier obtained with pfnMapRegion(). + * + * @returns status code + * @param pInterface Pointer to this interface structure + * @param iRegion Number of the region. + * @param StartAddress Host physical address of start. + * @param iRegionSize Size of the region. + * @param pvAddressR3 R3 address of mapped region. + * @param pvAddressR0 R0 address of mapped region. + * + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnUnmapRegion, (PPDMIPCIRAWUP pInterface, + int iRegion, + RTHCPHYS StartAddress, + uint64_t iRegionSize, + RTR3PTR pvAddressR3, + RTR0PTR pvAddressR0 + )); + + /** + * Request port IO write. + * + * @returns status code + * @param pInterface Pointer to this interface structure. + * @param iPort IO port. + * @param iValue Value to write. + * @param cb Access width. + * + * @thread EMT thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPioWrite, (PPDMIPCIRAWUP pInterface, + uint16_t iPort, + uint32_t iValue, + unsigned cb + )); + + /** + * Request port IO read. + * + * @returns status code + * @param pInterface Pointer to this interface structure. + * @param iPort IO port. + * @param piValue Place to store read value. + * @param cb Access width. + * + * @thread EMT thread. + */ + + DECLR3CALLBACKMEMBER(int, pfnPioRead, (PPDMIPCIRAWUP pInterface, + uint16_t iPort, + uint32_t *piValue, + unsigned cb + )); + + + /** + * Request MMIO write. This callback is only called if driver wants to receive MMIO via + * pu32Flags argument of pfnPciDeviceConstructStart(). + * + * @returns status code + * @param pInterface Pointer to this interface structure. + * @param Address Guest physical address. + * @param pValue Address of value to write. + * @param cb Access width. + * + * @thread EMT thread. + */ + DECLR3CALLBACKMEMBER(int, pfnMmioWrite, (PPDMIPCIRAWUP pInterface, + RTR0PTR Address, + void const *pValue, + unsigned cb + )); + + /** + * Request MMIO read. + * + * @returns status code + * @param pInterface Pointer to this interface structure. + * @param Address Guest physical address. + * @param pValue Place to store read value. + * @param cb Access width. + * + * @thread EMT thread. + */ + + DECLR3CALLBACKMEMBER(int, pfnMmioRead, (PPDMIPCIRAWUP pInterface, + RTR0PTR Address, + void *pValue, + unsigned cb + )); + + /** + * Host PCI config space accessors. + */ + /** + * Request driver to write value to host device's PCI config space. + * Host specific way (PIO or MCFG) is used to perform actual operation. + * + * @returns status code + * @param pInterface Pointer to this interface structure. + * @param iOffset Offset in PCI config space. + * @param iValue Value to write. + * @param cb Access width. + * + * @thread EMT thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPciCfgWrite, (PPDMIPCIRAWUP pInterface, + uint32_t iOffset, + void* pValue, + unsigned cb + )); + /** + * Request driver to read value from host device's PCI config space. + * Host specific way (PIO or MCFG) is used to perform actual operation. + * + * @returns status code + * @param pInterface Pointer to this interface structure. + * @param iOffset Offset in PCI config space. + * @param pValue Where to store read value. + * @param cb Access width. + * + * @thread EMT thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPciCfgRead, (PPDMIPCIRAWUP pInterface, + uint32_t iOffset, + void *pValue, + unsigned cb )); + + /** + * Request to enable interrupt notifications. Please note that this is purely + * R3 interface, so it's up to implementor to perform necessary machinery + * for communications with host OS kernel driver. Typical implementation will start + * userland thread waiting on shared semaphore (such as using SUPSEMEVENT), + * notified by the kernel interrupt handler, and then will call + * upper port pfnInterruptRequest() based on data provided by the driver. + * This apporach is taken, as calling VBox code from an asyncronous R0 + * interrupt handler when VMM may not be even running doesn't look + * like a good idea. + * + * @returns status code + * @param pInterface Pointer to this interface structure. + * @param pListener Pointer to the listener object. + * @param iGuestIrq Guest IRQ to be passed to pfnInterruptRequest(). + * + * @thread Any thread, pfnInterruptRequest() will be usually invoked on a dedicated thread. + */ + DECLR3CALLBACKMEMBER(int, pfnEnableInterruptNotifications, (PPDMIPCIRAWUP pInterface, int32_t iGuestIrq + )); + + /** + * Request to disable interrupt notifications. + * + * @returns status code + * @param pInterface Pointer to this interface structure. + * + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnDisableInterruptNotifications, (PPDMIPCIRAWUP pInterface + )); + + /** + * Notification APIs. + */ + + /** + * Notify driver when raw PCI device construction starts. Have to be the first operation + * as initializes internal state and opens host device driver. + * + * @returns status code + * @param pInterface Pointer to this interface structure. + * @param iHostAddress Host PCI address of device attached. + * @param iGuestAddress Guest PCI address of device attached. + * @param szDeviceName Human readable device name. + * @param fDeviceFlags Flags for the host device. + * @param pu32Flags Flags for virtual device, from the upper driver. + * + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPciDeviceConstructStart, (PPDMIPCIRAWUP pInterface, + uint32_t iHostAddress, + uint32_t iGuestAddress, + const char* szDeviceName, + uint32_t fDeviceFlags, + uint32_t *pu32Flags)); + + /** + * Notify driver when raw PCI device construction completes, so that it may + * perform further actions depending on success or failure of this operation. + * Standard action is to raise global IHostPciDevicePlugEvent. + * + * @param pInterface Pointer to this interface structure. + * @param rc Result code of the operation. + * + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(void, pfnPciDeviceConstructComplete, (PPDMIPCIRAWUP pInterface, + int rc)); + + /** + * Notify driver on finalization of raw PCI device. + * + * @param pInterface Pointer to this interface structure. + * + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPciDeviceDestruct, (PPDMIPCIRAWUP pInterface, + uint32_t fFlags)); + + /** + * Notify driver on guest power state change. + * + * @param pInterface Pointer to this interface structure. + * @param aState New power state. + * @param pu64Param State-specific in/out parameter. For now only used during power-on to provide VM caps. + * + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPciDevicePowerStateChange, (PPDMIPCIRAWUP pInterface, + PCIRAWPOWERSTATE aState, + uint64_t *pu64Param)); + + /** + * Notify driver about runtime error. + * + * @param pInterface Pointer to this interface structure. + * @param fFatal If error is fatal. + * @param szErrorId Error ID. + * @param szMessage Error message. + * + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnReportRuntimeError, (PPDMIPCIRAWUP pInterface, + uint8_t fFatal, + const char* szErrorId, + const char* szMessage)); +} PDMIPCIRAWUP; + +/** + * Init R0 PCI module. + */ +PCIRAWR0DECL(int) PciRawR0Init(void); +/** + * Process request (in R0). + */ +PCIRAWR0DECL(int) PciRawR0ProcessReq(PSUPDRVSESSION pSession, PVM pVM, PPCIRAWSENDREQ pReq); +/** + * Terminate R0 PCI module. + */ +PCIRAWR0DECL(void) PciRawR0Term(void); + +/** + * Per-VM R0 module init. + */ +PCIRAWR0DECL(int) PciRawR0InitVM(PVM pVM); + +/** + * Per-VM R0 module termination routine. + */ +PCIRAWR0DECL(void) PciRawR0TermVM(PVM pVM); + +/** + * Flags returned by pfnPciDeviceConstructStart(), to notify device + * how it shall handle device IO traffic. + */ +typedef enum PCIRAWDEVICEFLAGS +{ + /** Intercept port IO (R3 PIO always go to the driver). */ + PCIRAWRFLAG_CAPTURE_PIO = (1 << 0), + /** Intercept MMIO. */ + PCIRAWRFLAG_CAPTURE_MMIO = (1 << 1), + /** Allow bus mastering by physical device (requires IOMMU). */ + PCIRAWRFLAG_ALLOW_BM = (1 << 2), + /** Allow R3 MMIO mapping. */ + PCIRAWRFLAG_ALLOW_R3MAP = (1 << 3), + + /** The usual 32-bit type blow up. */ + PCIRAWRFLAG_32BIT_HACK = 0x7fffffff +} PCIRAWDEVICEFLAGS; + +#define PDMIPCIRAWUP_IID "06daa17f-097b-4ebe-a626-15f467b1de12" +#define PDMIPCIRAW_IID "68c6e4c4-4223-47e0-9134-e3c297992543" + +/** @} */ + +RT_C_DECLS_END + +#endif diff --git a/include/VBox/vmm/pdmqueue.h b/include/VBox/vmm/pdmqueue.h new file mode 100644 index 00000000..3445c85a --- /dev/null +++ b/include/VBox/vmm/pdmqueue.h @@ -0,0 +1,147 @@ +/** @file + * PDM - Pluggable Device Manager, Queues. + */ + +/* + * Copyright (C) 2006-2011 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_pdmqueue_h +#define ___VBox_vmm_pdmqueue_h + +#include <VBox/types.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_queue The PDM Queues API + * @ingroup grp_pdm + * @{ + */ + +/** Pointer to a PDM queue. Also called PDM queue handle. */ +typedef struct PDMQUEUE *PPDMQUEUE; + +/** Pointer to a PDM queue item core. */ +typedef struct PDMQUEUEITEMCORE *PPDMQUEUEITEMCORE; + +/** + * PDM queue item core. + */ +typedef struct PDMQUEUEITEMCORE +{ + /** Pointer to the next item in the pending list - R3 Pointer. */ + R3PTRTYPE(PPDMQUEUEITEMCORE) pNextR3; + /** Pointer to the next item in the pending list - R0 Pointer. */ + R0PTRTYPE(PPDMQUEUEITEMCORE) pNextR0; + /** Pointer to the next item in the pending list - RC Pointer. */ + RCPTRTYPE(PPDMQUEUEITEMCORE) pNextRC; +#if HC_ARCH_BITS == 64 + RTRCPTR Alignment0; +#endif +} PDMQUEUEITEMCORE; + + +/** + * Queue consumer callback for devices. + * + * @returns Success indicator. + * If false the item will not be removed and the flushing will stop. + * @param pDevIns The device instance. + * @param pItem The item to consume. Upon return this item will be freed. + */ +typedef DECLCALLBACK(bool) FNPDMQUEUEDEV(PPDMDEVINS pDevIns, PPDMQUEUEITEMCORE pItem); +/** Pointer to a FNPDMQUEUEDEV(). */ +typedef FNPDMQUEUEDEV *PFNPDMQUEUEDEV; + +/** + * Queue consumer callback for USB devices. + * + * @returns Success indicator. + * If false the item will not be removed and the flushing will stop. + * @param pDevIns The USB device instance. + * @param pItem The item to consume. Upon return this item will be freed. + */ +typedef DECLCALLBACK(bool) FNPDMQUEUEUSB(PPDMUSBINS pUsbIns, PPDMQUEUEITEMCORE pItem); +/** Pointer to a FNPDMQUEUEUSB(). */ +typedef FNPDMQUEUEUSB *PFNPDMQUEUEUSB; + +/** + * Queue consumer callback for drivers. + * + * @returns Success indicator. + * If false the item will not be removed and the flushing will stop. + * @param pDrvIns The driver instance. + * @param pItem The item to consume. Upon return this item will be freed. + */ +typedef DECLCALLBACK(bool) FNPDMQUEUEDRV(PPDMDRVINS pDrvIns, PPDMQUEUEITEMCORE pItem); +/** Pointer to a FNPDMQUEUEDRV(). */ +typedef FNPDMQUEUEDRV *PFNPDMQUEUEDRV; + +/** + * Queue consumer callback for internal component. + * + * @returns Success indicator. + * If false the item will not be removed and the flushing will stop. + * @param pVM The VM handle. + * @param pItem The item to consume. Upon return this item will be freed. + */ +typedef DECLCALLBACK(bool) FNPDMQUEUEINT(PVM pVM, PPDMQUEUEITEMCORE pItem); +/** Pointer to a FNPDMQUEUEINT(). */ +typedef FNPDMQUEUEINT *PFNPDMQUEUEINT; + +/** + * Queue consumer callback for external component. + * + * @returns Success indicator. + * If false the item will not be removed and the flushing will stop. + * @param pvUser User argument. + * @param pItem The item to consume. Upon return this item will be freed. + */ +typedef DECLCALLBACK(bool) FNPDMQUEUEEXT(void *pvUser, PPDMQUEUEITEMCORE pItem); +/** Pointer to a FNPDMQUEUEEXT(). */ +typedef FNPDMQUEUEEXT *PFNPDMQUEUEEXT; + +#ifdef VBOX_IN_VMM +VMMR3_INT_DECL(int) PDMR3QueueCreateDevice(PVM pVM, PPDMDEVINS pDevIns, size_t cbItem, uint32_t cItems, uint32_t cMilliesInterval, + PFNPDMQUEUEDEV pfnCallback, bool fRZEnabled, const char *pszName, PPDMQUEUE *ppQueue); +VMMR3_INT_DECL(int) PDMR3QueueCreateDriver(PVM pVM, PPDMDRVINS pDrvIns, size_t cbItem, uint32_t cItems, uint32_t cMilliesInterval, + PFNPDMQUEUEDRV pfnCallback, const char *pszName, PPDMQUEUE *ppQueue); +VMMR3_INT_DECL(int) PDMR3QueueCreateInternal(PVM pVM, size_t cbItem, uint32_t cItems, uint32_t cMilliesInterval, + PFNPDMQUEUEINT pfnCallback, bool fGCEnabled, const char *pszName, PPDMQUEUE *ppQueue); +VMMR3_INT_DECL(int) PDMR3QueueCreateExternal(PVM pVM, size_t cbItem, uint32_t cItems, uint32_t cMilliesInterval, + PFNPDMQUEUEEXT pfnCallback, void *pvUser, const char *pszName, PPDMQUEUE *ppQueue); +VMMR3_INT_DECL(int) PDMR3QueueDestroy(PPDMQUEUE pQueue); +VMMR3_INT_DECL(int) PDMR3QueueDestroyDevice(PVM pVM, PPDMDEVINS pDevIns); +VMMR3_INT_DECL(int) PDMR3QueueDestroyDriver(PVM pVM, PPDMDRVINS pDrvIns); +VMMR3_INT_DECL(void) PDMR3QueueFlushAll(PVM pVM); +#endif /* VBOX_IN_VMM */ + +VMMDECL(PPDMQUEUEITEMCORE) PDMQueueAlloc(PPDMQUEUE pQueue); +VMMDECL(void) PDMQueueInsert(PPDMQUEUE pQueue, PPDMQUEUEITEMCORE pItem); +VMMDECL(void) PDMQueueInsertEx(PPDMQUEUE pQueue, PPDMQUEUEITEMCORE pItem, uint64_t NanoMaxDelay); +VMMDECL(RCPTRTYPE(PPDMQUEUE)) PDMQueueRCPtr(PPDMQUEUE pQueue); +VMMDECL(R0PTRTYPE(PPDMQUEUE)) PDMQueueR0Ptr(PPDMQUEUE pQueue); + +/** @} */ + +RT_C_DECLS_END + +#endif + diff --git a/include/VBox/vmm/pdmsrv.h b/include/VBox/vmm/pdmsrv.h new file mode 100644 index 00000000..98766223 --- /dev/null +++ b/include/VBox/vmm/pdmsrv.h @@ -0,0 +1,335 @@ +/** @file + * PDM - Pluggable Device Manager, VM Services. + * + * @todo This has not been implemented, consider dropping the concept. + */ + +/* + * Copyright (C) 2006-2010 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_pdmsrv_h +#define ___VBox_vmm_pdmsrv_h + +#include <VBox/vmm/pdmifs.h> +#include <VBox/vmm/ssm.h> +#include <VBox/vmm/cfgm.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_services The PDM Services API + * @ingroup grp_pdm + * @{ + */ + +/** + * Construct a service instance for a VM. + * + * @returns VBox status. + * @param pSrvIns The service instance data. + * If the registration structure is needed, pSrvIns->pReg points to it. + * @param pCfg Configuration node handle for the service. Use this to obtain the configuration + * of the driver instance. It's also found in pSrvIns->pCfg, but since it's primary + * usage is expected in this function it is passed as a parameter. + */ +typedef DECLCALLBACK(int) FNPDMSRVCONSTRUCT(PPDMSRVINS pSrvIns, PCFGMNODE pCfg); +/** Pointer to a FNPDMSRVCONSTRUCT() function. */ +typedef FNPDMSRVCONSTRUCT *PFNPDMSRVCONSTRUCT; + +/** + * Destruct a driver instance. + * + * Most VM resources are freed by the VM. This callback is provided so that any non-VM + * resources can be freed correctly. + * + * @param pSrvIns The service instance data. + */ +typedef DECLCALLBACK(void) FNPDMSRVDESTRUCT(PPDMSRVINS pSrvIns); +/** Pointer to a FNPDMSRVDESTRUCT() function. */ +typedef FNPDMSRVDESTRUCT *PFNPDMSRVDESTRUCT; + +/** + * Power On notification. + * + * @param pSrvIns The service instance data. + */ +typedef DECLCALLBACK(void) FNPDMSRVPOWERON(PPDMSRVINS pSrvIns); +/** Pointer to a FNPDMSRVPOWERON() function. */ +typedef FNPDMSRVPOWERON *PFNPDMSRVPOWERON; + +/** + * Reset notification. + * + * @returns VBox status. + * @param pSrvIns The service instance data. + */ +typedef DECLCALLBACK(void) FNPDMSRVRESET(PPDMSRVINS pSrvIns); +/** Pointer to a FNPDMSRVRESET() function. */ +typedef FNPDMSRVRESET *PFNPDMSRVRESET; + +/** + * Suspend notification. + * + * @returns VBox status. + * @param pSrvIns The service instance data. + */ +typedef DECLCALLBACK(void) FNPDMSRVSUSPEND(PPDMSRVINS pSrvIns); +/** Pointer to a FNPDMSRVSUSPEND() function. */ +typedef FNPDMSRVSUSPEND *PFNPDMSRVSUSPEND; + +/** + * Resume notification. + * + * @returns VBox status. + * @param pSrvIns The service instance data. + */ +typedef DECLCALLBACK(void) FNPDMSRVRESUME(PPDMSRVINS pSrvIns); +/** Pointer to a FNPDMSRVRESUME() function. */ +typedef FNPDMSRVRESUME *PFNPDMSRVRESUME; + +/** + * Power Off notification. + * + * @param pSrvIns The service instance data. + */ +typedef DECLCALLBACK(void) FNPDMSRVPOWEROFF(PPDMSRVINS pSrvIns); +/** Pointer to a FNPDMSRVPOWEROFF() function. */ +typedef FNPDMSRVPOWEROFF *PFNPDMSRVPOWEROFF; + +/** + * Detach notification. + * + * This is called when a driver or device is detached from the service + * + * @param pSrvIns The service instance data. + */ +typedef DECLCALLBACK(void) FNPDMSRVDETACH(PPDMSRVINS pSrvIns, PPDMDEVINS pDevIns, PPDMDRVINS pDrvIns); +/** Pointer to a FNPDMSRVDETACH() function. */ +typedef FNPDMSRVDETACH *PFNPDMSRVDETACH; + + + +/** PDM Service Registration Structure, + * This structure is used when registering a driver from + * VBoxServicesRegister() (HC Ring-3). PDM will continue use till + * the VM is terminated. + */ +typedef struct PDMSRVREG +{ + /** Structure version. PDM_SRVREG_VERSION defines the current version. */ + uint32_t u32Version; + /** Driver name. */ + char szServiceName[32]; + /** The description of the driver. The UTF-8 string pointed to shall, like this structure, + * remain unchanged from registration till VM destruction. */ + const char *pszDescription; + + /** Flags, combination of the PDM_SRVREG_FLAGS_* \#defines. */ + RTUINT fFlags; + /** Size of the instance data. */ + RTUINT cbInstance; + + /** Construct instance - required. */ + PFNPDMSRVCONSTRUCT pfnConstruct; + /** Destruct instance - optional. */ + PFNPDMSRVDESTRUCT pfnDestruct; + /** Power on notification - optional. */ + PFNPDMSRVPOWERON pfnPowerOn; + /** Reset notification - optional. */ + PFNPDMSRVRESET pfnReset; + /** Suspend notification - optional. */ + PFNPDMSRVSUSPEND pfnSuspend; + /** Resume notification - optional. */ + PFNPDMSRVRESUME pfnResume; + /** Detach notification - optional. */ + PFNPDMSRVDETACH pfnDetach; + /** Power off notification - optional. */ + PFNPDMSRVPOWEROFF pfnPowerOff; + +} PDMSRVREG; +/** Pointer to a PDM Driver Structure. */ +typedef PDMSRVREG *PPDMSRVREG; +/** Const pointer to a PDM Driver Structure. */ +typedef PDMSRVREG const *PCPDMSRVREG; + + + +/** + * PDM Service API. + */ +typedef struct PDMSRVHLP +{ + /** Structure version. PDM_SRVHLP_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Assert that the current thread is the emulation thread. + * + * @returns True if correct. + * @returns False if wrong. + * @param pSrvIns Service instance. + * @param pszFile Filename of the assertion location. + * @param iLine Linenumber of the assertion location. + * @param pszFunction Function of the assertion location. + */ + DECLR3CALLBACKMEMBER(bool, pfnAssertEMT,(PPDMSRVINS pSrvIns, const char *pszFile, unsigned iLine, const char *pszFunction)); + + /** + * Assert that the current thread is NOT the emulation thread. + * + * @returns True if correct. + * @returns False if wrong. + * @param pSrvIns Service instance. + * @param pszFile Filename of the assertion location. + * @param iLine Linenumber of the assertion location. + * @param pszFunction Function of the assertion location. + */ + DECLR3CALLBACKMEMBER(bool, pfnAssertOther,(PPDMSRVINS pSrvIns, const char *pszFile, unsigned iLine, const char *pszFunction)); + + /** + * Creates a timer. + * + * @returns VBox status. + * @param pVM The VM to create the timer in. + * @param pSrvIns Service instance. + * @param enmClock The clock to use on this timer. + * @param pfnCallback Callback function. + * @param pszDesc Pointer to description string which must stay around + * until the timer is fully destroyed (i.e. a bit after TMTimerDestroy()). + * @param ppTimer Where to store the timer on success. + */ + DECLR3CALLBACKMEMBER(int, pfnTMTimerCreate,(PPDMSRVINS pSrvIns, TMCLOCK enmClock, PFNTMTIMERDEV pfnCallback, const char *pszDesc, PPTMTIMERR3 ppTimer)); + + /** + * Query the virtual timer frequency. + * + * @returns Frequency in Hz. + * @param pSrvIns Service instance. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnTMGetVirtualFreq,(PPDMSRVINS pSrvIns)); + + /** + * Query the virtual time. + * + * @returns The current virtual time. + * @param pSrvIns Service instance. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnTMGetVirtualTime,(PPDMSRVINS pSrvIns)); + +} PDMSRVHLP; +/** Pointer PDM Service API. */ +typedef PDMSRVHLP *PPDMSRVHLP; +/** Pointer const PDM Service API. */ +typedef const PDMSRVHLP *PCPDMSRVHLP; + +/** Current SRVHLP version number. */ +#define PDM_SRVHLP_VERSION PDM_VERSION_MAKE(0xdfff, 1, 0) + + +/** + * PDM Service Instance. + */ +typedef struct PDMSRVINS +{ + /** Structure version. PDM_SRVINS_VERSION defines the current version. */ + uint32_t u32Version; + + /** Internal data. */ + union + { +#ifdef PDMSRVINSINT_DECLARED + PDMSRVINSINT s; +#endif + uint8_t padding[HC_ARCH_BITS == 32 ? 32 : 32]; + } Internal; + + /** Pointer the PDM Service API. */ + R3PTRTYPE(PCPDMSRVHLP) pHlp; + /** Pointer to driver registration structure. */ + R3PTRTYPE(PCPDMSRVREG) pReg; + /** Configuration handle. */ + R3PTRTYPE(PCFGMNODE) pCfg; + /** The base interface of the service. + * The service constructor initializes this. */ + PDMIBASE IBase; + /* padding to make achInstanceData aligned at 16 byte boundary. */ + uint32_t au32Padding[2]; + /** Pointer to driver instance data. */ + R3PTRTYPE(void *) pvInstanceData; + /** Driver instance data. The size of this area is defined + * in the PDMSRVREG::cbInstanceData field. */ + char achInstanceData[4]; +} PDMSRVINS; + +/** Current PDMSRVREG version number. */ +#define PDM_SRVINS_VERSION PDM_VERSION_MAKE(0xdffe, 1, 0) + +/** Converts a pointer to the PDMSRVINS::IBase to a pointer to PDMSRVINS. */ +#define PDMIBASE_2_PDMSRV(pInterface) ( (PPDMSRVINS)((char *)(pInterface) - RT_OFFSETOF(PDMSRVINS, IBase)) ) + + + +/** Pointer to callbacks provided to the VBoxServiceRegister() call. */ +typedef struct PDMSRVREGCB *PPDMSRVREGCB; + +/** + * Callbacks for VBoxServiceRegister(). + */ +typedef struct PDMSRVREGCB +{ + /** Interface version. + * This is set to PDM_SRVREG_CB_VERSION. */ + uint32_t u32Version; + + /** + * Registers a service with the current VM instance. + * + * @returns VBox status code. + * @param pCallbacks Pointer to the callback table. + * @param pSrvReg Pointer to the device registration record. + * This data must be permanent and readonly. + */ + DECLR3CALLBACKMEMBER(int, pfnRegister,(PPDMSRVREGCB pCallbacks, PCPDMSRVREG pSrvReg)); +} PDMSRVREGCB; + +/** Current version of the PDMSRVREGCB structure. */ +#define PDM_SRVREG_CB_VERSION PDM_VERSION_MAKE(0xdffd, 1, 0) + + +/** + * The VBoxServicesRegister callback function. + * + * PDM will invoke this function after loading a device module and letting + * the module decide which devices to register and how to handle conflicts. + * + * @returns VBox status code. + * @param pCallbacks Pointer to the callback table. + * @param u32Version VBox version number. + */ +typedef DECLCALLBACK(int) FNPDMVBOXSERVICESREGISTER(PPDMSRVREGCB pCallbacks, uint32_t u32Version); + + +/** @} */ + +RT_C_DECLS_END + +#endif diff --git a/include/VBox/vmm/pdmthread.h b/include/VBox/vmm/pdmthread.h new file mode 100644 index 00000000..044620cd --- /dev/null +++ b/include/VBox/vmm/pdmthread.h @@ -0,0 +1,298 @@ +/** @file + * PDM - Pluggable Device Manager, Threads. + */ + +/* + * Copyright (C) 2006-2010 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_pdmthread_h +#define ___VBox_vmm_pdmthread_h + +#include <VBox/cdefs.h> +#include <VBox/types.h> +#ifdef IN_RING3 +# include <iprt/thread.h> +#endif + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_thread The PDM Threads API + * @ingroup grp_pdm + * @{ + */ + +/** + * The thread state + */ +typedef enum PDMTHREADSTATE +{ + /** The usual invalid 0 entry. */ + PDMTHREADSTATE_INVALID = 0, + /** The thread is initializing. + * Prev state: none + * Next state: suspended, terminating (error) */ + PDMTHREADSTATE_INITIALIZING, + /** The thread has been asked to suspend. + * Prev state: running + * Next state: suspended */ + PDMTHREADSTATE_SUSPENDING, + /** The thread is supended. + * Prev state: suspending, initializing + * Next state: resuming, terminated. */ + PDMTHREADSTATE_SUSPENDED, + /** The thread is active. + * Prev state: suspended + * Next state: running, terminating. */ + PDMTHREADSTATE_RESUMING, + /** The thread is active. + * Prev state: resuming + * Next state: suspending, terminating. */ + PDMTHREADSTATE_RUNNING, + /** The thread has been asked to terminate. + * Prev state: initializing, suspended, resuming, running + * Next state: terminated. */ + PDMTHREADSTATE_TERMINATING, + /** The thread is terminating / has terminated. + * Prev state: terminating + * Next state: none */ + PDMTHREADSTATE_TERMINATED, + /** The usual 32-bit hack. */ + PDMTHREADSTATE_32BIT_HACK = 0x7fffffff +} PDMTHREADSTATE; + +/** A pointer to a PDM thread. */ +typedef R3PTRTYPE(struct PDMTHREAD *) PPDMTHREAD; +/** A pointer to a pointer to a PDM thread. */ +typedef PPDMTHREAD *PPPDMTHREAD; + +/** + * PDM thread, device variation. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pThread The PDM thread data. + */ +typedef int FNPDMTHREADDEV(PPDMDEVINS pDevIns, PPDMTHREAD pThread); +/** Pointer to a FNPDMTHREADDEV(). */ +typedef FNPDMTHREADDEV *PFNPDMTHREADDEV; + +/** + * PDM thread, USB device variation. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + * @param pThread The PDM thread data. + */ +typedef int FNPDMTHREADUSB(PPDMUSBINS pUsbIns, PPDMTHREAD pThread); +/** Pointer to a FNPDMTHREADUSB(). */ +typedef FNPDMTHREADUSB *PFNPDMTHREADUSB; + +/** + * PDM thread, driver variation. + * + * @returns VBox status code. + * @param pDrvIns The driver instance. + * @param pThread The PDM thread data. + */ +typedef int FNPDMTHREADDRV(PPDMDRVINS pDrvIns, PPDMTHREAD pThread); +/** Pointer to a FNPDMTHREADDRV(). */ +typedef FNPDMTHREADDRV *PFNPDMTHREADDRV; + +/** + * PDM thread, driver variation. + * + * @returns VBox status code. + * @param pVM The VM handle. + * @param pThread The PDM thread data. + */ +typedef int FNPDMTHREADINT(PVM pVM, PPDMTHREAD pThread); +/** Pointer to a FNPDMTHREADINT(). */ +typedef FNPDMTHREADINT *PFNPDMTHREADINT; + +/** + * PDM thread, driver variation. + * + * @returns VBox status code. + * @param pThread The PDM thread data. + */ +typedef int FNPDMTHREADEXT(PPDMTHREAD pThread); +/** Pointer to a FNPDMTHREADEXT(). */ +typedef FNPDMTHREADEXT *PFNPDMTHREADEXT; + + + +/** + * PDM thread wakeup call, device variation. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pThread The PDM thread data. + */ +typedef int FNPDMTHREADWAKEUPDEV(PPDMDEVINS pDevIns, PPDMTHREAD pThread); +/** Pointer to a FNPDMTHREADDEV(). */ +typedef FNPDMTHREADWAKEUPDEV *PFNPDMTHREADWAKEUPDEV; + +/** + * PDM thread wakeup call, device variation. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + * @param pThread The PDM thread data. + */ +typedef int FNPDMTHREADWAKEUPUSB(PPDMUSBINS pUsbIns, PPDMTHREAD pThread); +/** Pointer to a FNPDMTHREADUSB(). */ +typedef FNPDMTHREADWAKEUPUSB *PFNPDMTHREADWAKEUPUSB; + +/** + * PDM thread wakeup call, driver variation. + * + * @returns VBox status code. + * @param pDrvIns The driver instance. + * @param pThread The PDM thread data. + */ +typedef int FNPDMTHREADWAKEUPDRV(PPDMDRVINS pDrvIns, PPDMTHREAD pThread); +/** Pointer to a FNPDMTHREADDRV(). */ +typedef FNPDMTHREADWAKEUPDRV *PFNPDMTHREADWAKEUPDRV; + +/** + * PDM thread wakeup call, internal variation. + * + * @returns VBox status code. + * @param pVM The VM handle. + * @param pThread The PDM thread data. + */ +typedef int FNPDMTHREADWAKEUPINT(PVM pVM, PPDMTHREAD pThread); +/** Pointer to a FNPDMTHREADWAKEUPINT(). */ +typedef FNPDMTHREADWAKEUPINT *PFNPDMTHREADWAKEUPINT; + +/** + * PDM thread wakeup call, external variation. + * + * @returns VBox status code. + * @param pThread The PDM thread data. + */ +typedef int FNPDMTHREADWAKEUPEXT(PPDMTHREAD pThread); +/** Pointer to a FNPDMTHREADEXT(). */ +typedef FNPDMTHREADWAKEUPEXT *PFNPDMTHREADWAKEUPEXT; + + +/** + * PDM Thread instance data. + */ +typedef struct PDMTHREAD +{ + /** PDMTHREAD_VERSION. */ + uint32_t u32Version; + /** The thread state. */ + PDMTHREADSTATE volatile enmState; + /** The thread handle. */ + RTTHREAD Thread; + /** The user parameter. */ + R3PTRTYPE(void *) pvUser; + /** Data specific to the kind of thread. + * This should really be in PDMTHREADINT, but is placed here because of the + * function pointer typedefs. So, don't touch these, please. + */ + union + { + /** PDMTHREADTYPE_DEVICE data. */ + struct + { + /** The device instance. */ + PPDMDEVINSR3 pDevIns; + /** The thread function. */ + R3PTRTYPE(PFNPDMTHREADDEV) pfnThread; + /** Thread. */ + R3PTRTYPE(PFNPDMTHREADWAKEUPDEV) pfnWakeUp; + } Dev; + + /** PDMTHREADTYPE_USB data. */ + struct + { + /** The device instance. */ + PPDMUSBINS pUsbIns; + /** The thread function. */ + R3PTRTYPE(PFNPDMTHREADUSB) pfnThread; + /** Thread. */ + R3PTRTYPE(PFNPDMTHREADWAKEUPUSB) pfnWakeUp; + } Usb; + + /** PDMTHREADTYPE_DRIVER data. */ + struct + { + /** The driver instance. */ + R3PTRTYPE(PPDMDRVINS) pDrvIns; + /** The thread function. */ + R3PTRTYPE(PFNPDMTHREADDRV) pfnThread; + /** Thread. */ + R3PTRTYPE(PFNPDMTHREADWAKEUPDRV) pfnWakeUp; + } Drv; + + /** PDMTHREADTYPE_INTERNAL data. */ + struct + { + /** The thread function. */ + R3PTRTYPE(PFNPDMTHREADINT) pfnThread; + /** Thread. */ + R3PTRTYPE(PFNPDMTHREADWAKEUPINT) pfnWakeUp; + } Int; + + /** PDMTHREADTYPE_EXTERNAL data. */ + struct + { + /** The thread function. */ + R3PTRTYPE(PFNPDMTHREADEXT) pfnThread; + /** Thread. */ + R3PTRTYPE(PFNPDMTHREADWAKEUPEXT) pfnWakeUp; + } Ext; + } u; + + /** Internal data. */ + union + { +#ifdef PDMTHREADINT_DECLARED + PDMTHREADINT s; +#endif + uint8_t padding[64]; + } Internal; +} PDMTHREAD; + +/** PDMTHREAD::u32Version value. */ +#define PDMTHREAD_VERSION PDM_VERSION_MAKE(0xefff, 1, 0) + +#ifdef IN_RING3 +VMMR3DECL(int) PDMR3ThreadCreate(PVM pVM, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADINT pfnThread, + PFNPDMTHREADWAKEUPINT pfnWakeUp, size_t cbStack, RTTHREADTYPE enmType, const char *pszName); +VMMR3DECL(int) PDMR3ThreadCreateExternal(PVM pVM, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADEXT pfnThread, + PFNPDMTHREADWAKEUPEXT pfnWakeUp, size_t cbStack, RTTHREADTYPE enmType, const char *pszName); +VMMR3DECL(int) PDMR3ThreadDestroy(PPDMTHREAD pThread, int *pRcThread); +VMMR3DECL(int) PDMR3ThreadIAmSuspending(PPDMTHREAD pThread); +VMMR3DECL(int) PDMR3ThreadIAmRunning(PPDMTHREAD pThread); +VMMR3DECL(int) PDMR3ThreadSleep(PPDMTHREAD pThread, RTMSINTERVAL cMillies); +VMMR3DECL(int) PDMR3ThreadSuspend(PPDMTHREAD pThread); +VMMR3DECL(int) PDMR3ThreadResume(PPDMTHREAD pThread); +#endif /* IN_RING3 */ + +/** @} */ + +RT_C_DECLS_END + +#endif diff --git a/include/VBox/vmm/pdmusb.h b/include/VBox/vmm/pdmusb.h new file mode 100644 index 00000000..ae3f5cfb --- /dev/null +++ b/include/VBox/vmm/pdmusb.h @@ -0,0 +1,1004 @@ +/** @file + * PDM - Pluggable Device Manager, USB Devices. + */ + +/* + * Copyright (C) 2006-2010 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_pdmusb_h +#define ___VBox_vmm_pdmusb_h + +#include <VBox/vmm/pdmqueue.h> +#include <VBox/vmm/pdmcritsect.h> +#include <VBox/vmm/pdmthread.h> +#include <VBox/vmm/pdmifs.h> +#include <VBox/vmm/pdmcommon.h> +#include <VBox/vmm/tm.h> +#include <VBox/vmm/ssm.h> +#include <VBox/vmm/cfgm.h> +#include <VBox/vmm/dbgf.h> +#include <VBox/vmm/mm.h> +#include <VBox/err.h> +#include <VBox/vusb.h> +#include <iprt/stdarg.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_usbdev The USB Devices API + * @ingroup grp_pdm + * @{ + */ + + +/** + * A string entry for the USB descriptor cache. + */ +typedef struct PDMUSBDESCCACHESTRING +{ + /** The string index. */ + uint8_t idx; + /** The UTF-8 representation of the string. */ + const char *psz; +} PDMUSBDESCCACHESTRING; +/** Pointer to a const string entry. */ +typedef PDMUSBDESCCACHESTRING const *PCPDMUSBDESCCACHESTRING; + + +/** + * A language entry for the USB descriptor cache. + */ +typedef struct PDMUSBDESCCACHELANG +{ + /** The language ID for the strings in this block. */ + uint16_t idLang; + /** The number of strings in the array. */ + uint16_t cStrings; + /** Pointer to an array of associated strings. + * This must be sorted in ascending order by string index as a binary lookup + * will be performed. */ + PCPDMUSBDESCCACHESTRING paStrings; +} PDMUSBDESCCACHELANG; +/** Pointer to a const language entry. */ +typedef PDMUSBDESCCACHELANG const *PCPDMUSBDESCCACHELANG; + + +/** + * USB descriptor cache. + * + * This structure is owned by the USB device but provided to the PDM/VUSB layer + * thru the PDMUSBREG::pfnGetDescriptorCache method. PDM/VUSB will use the + * information here to map addresses to endpoints, perform SET_CONFIGURATION + * requests, and optionally perform GET_DESCRIPTOR requests (see flag). + * + * Currently, only device and configuration descriptors are cached. + */ +typedef struct PDMUSBDESCCACHE +{ + /** USB device descriptor */ + PCVUSBDESCDEVICE pDevice; + /** USB Descriptor arrays (pDev->bNumConfigurations) */ + PCVUSBDESCCONFIGEX paConfigs; + /** Language IDs and their associated strings. + * This must be sorted in ascending order by language ID as a binary lookup + * will be used. */ + PCPDMUSBDESCCACHELANG paLanguages; + /** The number of entries in the array pointed to by paLanguages. */ + uint16_t cLanguages; + /** Use the cached descriptors for GET_DESCRIPTOR requests. */ + bool fUseCachedDescriptors; + /** Use the cached string descriptors. */ + bool fUseCachedStringsDescriptors; +} PDMUSBDESCCACHE; +/** Pointer to an USB descriptor cache. */ +typedef PDMUSBDESCCACHE *PPDMUSBDESCCACHE; +/** Pointer to a const USB descriptor cache. */ +typedef const PDMUSBDESCCACHE *PCPDMUSBDESCCACHE; + + + +/** PDM USB Device Registration Structure, + * + * This structure is used when registering a device from VBoxUsbRegister() in HC Ring-3. + * The PDM will make use of this structure until the VM is destroyed. + */ +typedef struct PDMUSBREG +{ + /** Structure version. PDM_DEVREG_VERSION defines the current version. */ + uint32_t u32Version; + /** Device name. */ + char szName[32]; + /** The description of the device. The UTF-8 string pointed to shall, like this structure, + * remain unchanged from registration till VM destruction. */ + const char *pszDescription; + + /** Flags, combination of the PDM_USBREG_FLAGS_* \#defines. */ + RTUINT fFlags; + /** Maximum number of instances (per VM). */ + RTUINT cMaxInstances; + /** Size of the instance data. */ + RTUINT cbInstance; + + + /** + * Construct an USB device instance for a VM. + * + * @returns VBox status. + * @param pUsbIns The USB device instance data. + * If the registration structure is needed, it will be + * accessible thru pUsbDev->pReg. + * @param iInstance Instance number. Use this to figure out which registers + * and such to use. The instance number is also found in + * pUsbDev->iInstance, but since it's likely to be + * frequently used PDM passes it as parameter. + * @param pCfg Configuration node handle for the device. Use this to + * obtain the configuration of the device instance. It is + * also found in pUsbDev->pCfg, but since it is primary + * usage will in this function it is passed as a parameter. + * @param pCfgGlobal Handle to the global device configuration. Also found + * in pUsbDev->pCfgGlobal. + * @remarks This callback is required. + */ + DECLR3CALLBACKMEMBER(int, pfnConstruct,(PPDMUSBINS pUsbIns, int iInstance, PCFGMNODE pCfg, PCFGMNODE pCfgGlobal)); + + /** + * Destruct an USB device instance. + * + * Most VM resources are freed by the VM. This callback is provided so that any non-VM + * resources can be freed correctly. + * + * This method will be called regardless of the pfnConstruc result to avoid + * complicated failure paths. + * + * @param pUsbIns The USB device instance data. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(void, pfnDestruct,(PPDMUSBINS pUsbIns)); + + + /** + * Init complete notification. + * + * This can be done to do communication with other devices and other + * initialization which requires everything to be in place. + * + * @returns VBOX status code. + * @param pUsbIns The USB device instance data. + * @remarks Optional. + * @remarks Not called when hotplugged. + */ + DECLR3CALLBACKMEMBER(int, pfnVMInitComplete,(PPDMUSBINS pUsbIns)); + + /** + * VM Power On notification. + * + * @returns VBox status. + * @param pUsbIns The USB device instance data. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(void, pfnVMPowerOn,(PPDMUSBINS pUsbIns)); + + /** + * VM Reset notification. + * + * @returns VBox status. + * @param pUsbIns The USB device instance data. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(void, pfnVMReset,(PPDMUSBINS pUsbIns)); + + /** + * VM Suspend notification. + * + * @returns VBox status. + * @param pUsbIns The USB device instance data. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(void, pfnVMSuspend,(PPDMUSBINS pUsbIns)); + + /** + * VM Resume notification. + * + * @returns VBox status. + * @param pUsbIns The USB device instance data. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(void, pfnVMResume,(PPDMUSBINS pUsbIns)); + + /** + * VM Power Off notification. + * + * This is only called when the VMR3PowerOff call is made on a running VM. This + * means that there is no notification if the VM was suspended before being + * powered of. There will also be no callback when hot plugging devices. + * + * @param pUsbIns The USB device instance data. + */ + DECLR3CALLBACKMEMBER(void, pfnVMPowerOff,(PPDMUSBINS pUsbIns)); + + /** + * Called after the constructor when attaching a device at run time. + * + * This can be used to do tasks normally assigned to pfnInitComplete and/or pfnVMPowerOn. + * + * @returns VBox status. + * @param pUsbIns The USB device instance data. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(void, pfnHotPlugged,(PPDMUSBINS pUsbIns)); + + /** + * Called before the destructor when a device is unplugged at run time. + * + * This can be used to do tasks normally assigned to pfnVMSuspend and/or pfnVMPowerOff. + * + * @returns VBox status. + * @param pUsbIns The USB device instance data. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(void, pfnHotUnplugged,(PPDMUSBINS pUsbIns)); + /** + * Driver Attach command. + * + * This is called to let the USB device attach to a driver for a specified LUN + * at runtime. This is not called during VM construction, the device constructor + * have to attach to all the available drivers. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance data. + * @param iLUN The logical unit which is being detached. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(int, pfnDriverAttach,(PPDMUSBINS pUsbIns, unsigned iLUN)); + + /** + * Driver Detach notification. + * + * This is called when a driver is detaching itself from a LUN of the device. + * The device should adjust it's state to reflect this. + * + * @param pUsbIns The USB device instance data. + * @param iLUN The logical unit which is being detached. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(void, pfnDriverDetach,(PPDMUSBINS pUsbIns, unsigned iLUN)); + + /** + * Query the base interface of a logical unit. + * + * @returns VBOX status code. + * @param pUsbIns The USB device instance data. + * @param iLUN The logicial unit to query. + * @param ppBase Where to store the pointer to the base interface of the LUN. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryInterface,(PPDMUSBINS pUsbIns, unsigned iLUN, PPDMIBASE *ppBase)); + + /** + * Requests the USB device to reset. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + * @param fResetOnLinux A hint to the usb proxy. + * Don't use this unless you're the linux proxy device. + * @thread Any thread. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(int, pfnUsbReset,(PPDMUSBINS pUsbIns, bool fResetOnLinux)); + + /** + * Query device and configuration descriptors for the caching and servicing + * relevant GET_DESCRIPTOR requests. + * + * @returns Pointer to the descriptor cache (read-only). + * @param pUsbIns The USB device instance. + * @remarks Mandatory. + */ + DECLR3CALLBACKMEMBER(PCPDMUSBDESCCACHE, pfnUsbGetDescriptorCache,(PPDMUSBINS pUsbIns)); + + /** + * SET_CONFIGURATION request. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + * @param bConfigurationValue The bConfigurationValue of the new configuration. + * @param pvOldCfgDesc Internal - for the device proxy. + * @param pvOldIfState Internal - for the device proxy. + * @param pvNewCfgDesc Internal - for the device proxy. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(int, pfnUsbSetConfiguration,(PPDMUSBINS pUsbIns, uint8_t bConfigurationValue, + const void *pvOldCfgDesc, const void *pvOldIfState, const void *pvNewCfgDesc)); + + /** + * SET_INTERFACE request. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + * @param bInterfaceNumber The interface number. + * @param bAlternateSetting The alternate setting. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(int, pfnUsbSetInterface,(PPDMUSBINS pUsbIns, uint8_t bInterfaceNumber, uint8_t bAlternateSetting)); + + /** + * Clears the halted state of an endpoint. (Optional) + * + * This called when VUSB sees a CLEAR_FEATURE(ENDPOINT_HALT) on request + * on the zero pipe. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + * @param uEndpoint The endpoint to clear. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(int, pfnUsbClearHaltedEndpoint,(PPDMUSBINS pUsbIns, unsigned uEndpoint)); + + /** + * Allocates an URB. + * + * This can be used to make use of shared user/kernel mode buffers. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + * @param cbData The size of the data buffer. + * @param cTds The number of TDs. + * @param enmType The type of URB. + * @param ppUrb Where to store the allocated URB. + * @remarks Optional. + * @remarks Not implemented yet. + */ + DECLR3CALLBACKMEMBER(int, pfnUrbNew,(PPDMUSBINS pUsbIns, size_t cbData, size_t cTds, VUSBXFERTYPE enmType, PVUSBURB *ppUrb)); + + /** + * Queues an URB for processing. + * + * @returns VBox status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_VUSB_DEVICE_NOT_ATTACHED if the device has been disconnected. + * @retval VERR_VUSB_FAILED_TO_QUEUE_URB as a general failure kind of thing. + * @retval TBD - document new stuff! + * + * @param pUsbIns The USB device instance. + * @param pUrb The URB to process. + * @remarks Mandatory. + */ + DECLR3CALLBACKMEMBER(int, pfnUrbQueue,(PPDMUSBINS pUsbIns, PVUSBURB pUrb)); + + /** + * Cancels an URB. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + * @param pUrb The URB to cancel. + * @remarks Mandatory. + */ + DECLR3CALLBACKMEMBER(int, pfnUrbCancel,(PPDMUSBINS pUsbIns, PVUSBURB pUrb)); + + /** + * Reaps an URB. + * + * @returns A ripe URB, NULL if none. + * @param pUsbIns The USB device instance. + * @param cMillies How log to wait for an URB to become ripe. + * @remarks Mandatory. + */ + DECLR3CALLBACKMEMBER(PVUSBURB, pfnUrbReap,(PPDMUSBINS pUsbIns, RTMSINTERVAL cMillies)); + + + /** Just some init precaution. Must be set to PDM_USBREG_VERSION. */ + uint32_t u32TheEnd; +} PDMUSBREG; +/** Pointer to a PDM USB Device Structure. */ +typedef PDMUSBREG *PPDMUSBREG; +/** Const pointer to a PDM USB Device Structure. */ +typedef PDMUSBREG const *PCPDMUSBREG; + +/** Current USBREG version number. */ +#define PDM_USBREG_VERSION PDM_VERSION_MAKE(0xeeff, 1, 0) + +/** PDM USB Device Flags. + * @{ */ +/* none yet */ +/** @} */ + + +#ifdef IN_RING3 + +/** + * PDM USB Device API. + */ +typedef struct PDMUSBHLP +{ + /** Structure version. PDM_USBHLP_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Attaches a driver (chain) to the USB device. + * + * The first call for a LUN this will serve as a registartion of the LUN. The pBaseInterface and + * the pszDesc string will be registered with that LUN and kept around for PDMR3QueryUSBDeviceLun(). + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + * @param iLun The logical unit to attach. + * @param pBaseInterface Pointer to the base interface for that LUN. (device side / down) + * @param ppBaseInterface Where to store the pointer to the base interface. (driver side / up) + * @param pszDesc Pointer to a string describing the LUN. This string must remain valid + * for the live of the device instance. + */ + DECLR3CALLBACKMEMBER(int, pfnDriverAttach,(PPDMUSBINS pUsbIns, RTUINT iLun, PPDMIBASE pBaseInterface, PPDMIBASE *ppBaseInterface, const char *pszDesc)); + + /** + * Assert that the current thread is the emulation thread. + * + * @returns True if correct. + * @returns False if wrong. + * @param pUsbIns The USB device instance. + * @param pszFile Filename of the assertion location. + * @param iLine Linenumber of the assertion location. + * @param pszFunction Function of the assertion location. + */ + DECLR3CALLBACKMEMBER(bool, pfnAssertEMT,(PPDMUSBINS pUsbIns, const char *pszFile, unsigned iLine, const char *pszFunction)); + + /** + * Assert that the current thread is NOT the emulation thread. + * + * @returns True if correct. + * @returns False if wrong. + * @param pUsbIns The USB device instance. + * @param pszFile Filename of the assertion location. + * @param iLine Linenumber of the assertion location. + * @param pszFunction Function of the assertion location. + */ + DECLR3CALLBACKMEMBER(bool, pfnAssertOther,(PPDMUSBINS pUsbIns, const char *pszFile, unsigned iLine, const char *pszFunction)); + + /** + * Stops the VM and enters the debugger to look at the guest state. + * + * Use the PDMUsbDBGFStop() inline function with the RT_SRC_POS macro instead of + * invoking this function directly. + * + * @returns VBox status code which must be passed up to the VMM. + * @param pUsbIns The USB device instance. + * @param pszFile Filename of the assertion location. + * @param iLine The linenumber of the assertion location. + * @param pszFunction Function of the assertion location. + * @param pszFormat Message. (optional) + * @param va Message parameters. + */ + DECLR3CALLBACKMEMBER(int, pfnDBGFStopV,(PPDMUSBINS pUsbIns, const char *pszFile, unsigned iLine, const char *pszFunction, const char *pszFormat, va_list va)); + + /** + * Register a info handler with DBGF, + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + * @param pszName The identifier of the info. + * @param pszDesc The description of the info and any arguments the handler may take. + * @param pfnHandler The handler function to be called to display the info. + */ + DECLR3CALLBACKMEMBER(int, pfnDBGFInfoRegister,(PPDMUSBINS pUsbIns, const char *pszName, const char *pszDesc, PFNDBGFHANDLERUSB pfnHandler)); + + /** + * Allocate memory which is associated with current VM instance + * and automatically freed on it's destruction. + * + * @returns Pointer to allocated memory. The memory is *NOT* zero-ed. + * @param pUsbIns The USB device instance. + * @param cb Number of bytes to allocate. + */ + DECLR3CALLBACKMEMBER(void *, pfnMMHeapAlloc,(PPDMUSBINS pUsbIns, size_t cb)); + + /** + * Allocate memory which is associated with current VM instance + * and automatically freed on it's destruction. The memory is ZEROed. + * + * @returns Pointer to allocated memory. The memory is *NOT* zero-ed. + * @param pUsbIns The USB device instance. + * @param cb Number of bytes to allocate. + */ + DECLR3CALLBACKMEMBER(void *, pfnMMHeapAllocZ,(PPDMUSBINS pUsbIns, size_t cb)); + + /** + * Create a queue. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + * @param cbItem Size a queue item. + * @param cItems Number of items in the queue. + * @param cMilliesInterval Number of milliseconds between polling the queue. + * If 0 then the emulation thread will be notified whenever an item arrives. + * @param pfnCallback The consumer function. + * @param pszName The queue base name. The instance number will be + * appended automatically. + * @param ppQueue Where to store the queue handle on success. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPDMQueueCreate,(PPDMUSBINS pUsbIns, RTUINT cbItem, RTUINT cItems, uint32_t cMilliesInterval, + PFNPDMQUEUEUSB pfnCallback, const char *pszName, PPDMQUEUE *ppQueue)); + + /** + * Register a save state data unit. + * + * @returns VBox status. + * @param pUsbIns The USB device instance. + * @param uVersion Data layout version number. + * @param cbGuess The approximate amount of data in the unit. + * Only for progress indicators. + * + * @param pfnLivePrep Prepare live save callback, optional. + * @param pfnLiveExec Execute live save callback, optional. + * @param pfnLiveVote Vote live save callback, optional. + * + * @param pfnSavePrep Prepare save callback, optional. + * @param pfnSaveExec Execute save callback, optional. + * @param pfnSaveDone Done save callback, optional. + * + * @param pfnLoadPrep Prepare load callback, optional. + * @param pfnLoadExec Execute load callback, optional. + * @param pfnLoadDone Done load callback, optional. + */ + DECLR3CALLBACKMEMBER(int, pfnSSMRegister,(PPDMUSBINS pUsbIns, uint32_t uVersion, size_t cbGuess, + PFNSSMUSBLIVEPREP pfnLivePrep, PFNSSMUSBLIVEEXEC pfnLiveExec, PFNSSMUSBLIVEVOTE pfnLiveVote, + PFNSSMUSBSAVEPREP pfnSavePrep, PFNSSMUSBSAVEEXEC pfnSaveExec, PFNSSMUSBSAVEDONE pfnSaveDone, + PFNSSMUSBLOADPREP pfnLoadPrep, PFNSSMUSBLOADEXEC pfnLoadExec, PFNSSMUSBLOADDONE pfnLoadDone)); + + /** + * Register a STAM sample. + * + * Use the PDMUsbHlpSTAMRegister wrapper. + * + * @returns VBox status. + * @param pUsbIns The USB device instance. + * @param pvSample Pointer to the sample. + * @param enmType Sample type. This indicates what pvSample is pointing at. + * @param enmVisibility Visibility type specifying whether unused statistics should be visible or not. + * @param enmUnit Sample unit. + * @param pszDesc Sample description. + * @param pszName The sample name format string. + * @param va Arguments to the format string. + */ + DECLR3CALLBACKMEMBER(void, pfnSTAMRegisterV,(PPDMUSBINS pUsbIns, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, + STAMUNIT enmUnit, const char *pszDesc, const char *pszName, va_list va)); + + /** + * Creates a timer. + * + * @returns VBox status. + * @param pUsbIns The USB device instance. + * @param enmClock The clock to use on this timer. + * @param pfnCallback Callback function. + * @param pvUser User argument for the callback. + * @param fFlags Flags, see TMTIMER_FLAGS_*. + * @param pszDesc Pointer to description string which must stay around + * until the timer is fully destroyed (i.e. a bit after TMTimerDestroy()). + * @param ppTimer Where to store the timer on success. + */ + DECLR3CALLBACKMEMBER(int, pfnTMTimerCreate,(PPDMUSBINS pUsbIns, TMCLOCK enmClock, PFNTMTIMERUSB pfnCallback, void *pvUser, + uint32_t fFlags, const char *pszDesc, PPTMTIMERR3 ppTimer)); + + /** + * Set the VM error message + * + * @returns rc. + * @param pUsbIns The USB device instance. + * @param rc VBox status code. + * @param RT_SRC_POS_DECL Use RT_SRC_POS. + * @param pszFormat Error message format string. + * @param va Error message arguments. + */ + DECLR3CALLBACKMEMBER(int, pfnVMSetErrorV,(PPDMUSBINS pUsbIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va)); + + /** + * Set the VM runtime error message + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + * @param fFlags The action flags. See VMSETRTERR_FLAGS_*. + * @param pszErrorId Error ID string. + * @param pszFormat Error message format string. + * @param va Error message arguments. + */ + DECLR3CALLBACKMEMBER(int, pfnVMSetRuntimeErrorV,(PPDMUSBINS pUsbIns, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, va_list va)); + + /** + * Gets the VM state. + * + * @returns VM state. + * @param pUsbIns The USB device instance. + * @thread Any thread (just keep in mind that it's volatile info). + */ + DECLR3CALLBACKMEMBER(VMSTATE, pfnVMState, (PPDMUSBINS pUsbIns)); + + /** + * Creates a PDM thread. + * + * This differs from the RTThreadCreate() API in that PDM takes care of suspending, + * resuming, and destroying the thread as the VM state changes. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param ppThread Where to store the thread 'handle'. + * @param pvUser The user argument to the thread function. + * @param pfnThread The thread function. + * @param pfnWakeup The wakup callback. This is called on the EMT + * thread when a state change is pending. + * @param cbStack See RTThreadCreate. + * @param enmType See RTThreadCreate. + * @param pszName See RTThreadCreate. + */ + DECLR3CALLBACKMEMBER(int, pfnThreadCreate,(PPDMUSBINS pUsbIns, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADUSB pfnThread, + PFNPDMTHREADWAKEUPUSB pfnWakeup, size_t cbStack, RTTHREADTYPE enmType, const char *pszName)); + + /** + * Set up asynchronous handling of a suspend, reset or power off notification. + * + * This shall only be called when getting the notification. It must be called + * for each one. + * + * @returns VBox status code. + * @param pUSBIns The USB device instance. + * @param pfnAsyncNotify The callback. + * @thread EMT(0) + */ + DECLR3CALLBACKMEMBER(int, pfnSetAsyncNotification, (PPDMUSBINS pUSbIns, PFNPDMUSBASYNCNOTIFY pfnAsyncNotify)); + + /** + * Notify EMT(0) that the device has completed the asynchronous notification + * handling. + * + * This can be called at any time, spurious calls will simply be ignored. + * + * @param pUSBIns The USB device instance. + * @thread Any + */ + DECLR3CALLBACKMEMBER(void, pfnAsyncNotificationCompleted, (PPDMUSBINS pUsbIns)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMUSBHLP; +/** Pointer PDM USB Device API. */ +typedef PDMUSBHLP *PPDMUSBHLP; +/** Pointer const PDM USB Device API. */ +typedef const PDMUSBHLP *PCPDMUSBHLP; + +/** Current USBHLP version number. */ +#define PDM_USBHLP_VERSION PDM_VERSION_MAKE(0xeefe, 2, 0) + +#endif /* IN_RING3 */ + +/** + * PDM USB Device Instance. + */ +typedef struct PDMUSBINS +{ + /** Structure version. PDM_USBINS_VERSION defines the current version. */ + uint32_t u32Version; + /** USB device instance number. */ + uint32_t iInstance; + /** The base interface of the device. + * The device constructor initializes this if it has any device level + * interfaces to export. To obtain this interface call PDMR3QueryUSBDevice(). */ + PDMIBASE IBase; +#if HC_ARCH_BITS == 32 + uint32_t u32Alignment; /**< Alignment padding. */ +#endif + + /** Internal data. */ + union + { +#ifdef PDMUSBINSINT_DECLARED + PDMUSBINSINT s; +#endif + uint8_t padding[HC_ARCH_BITS == 32 ? 96 : 128]; + } Internal; + + /** Pointer the PDM USB Device API. */ + R3PTRTYPE(PCPDMUSBHLP) pHlpR3; + /** Pointer to the USB device registration structure. */ + R3PTRTYPE(PCPDMUSBREG) pReg; + /** Configuration handle. */ + R3PTRTYPE(PCFGMNODE) pCfg; + /** The (device) global configuration handle. */ + R3PTRTYPE(PCFGMNODE) pCfgGlobal; + /** Pointer to device instance data. */ + R3PTRTYPE(void *) pvInstanceDataR3; + /** Pointer to the VUSB Device structure. + * Internal to VUSB, don't touch. + * @todo Moved this to PDMUSBINSINT. */ + R3PTRTYPE(void *) pvVUsbDev2; + /** Device name for using when logging. + * The constructor sets this and the destructor frees it. */ + R3PTRTYPE(char *) pszName; + /** Tracing indicator. */ + uint32_t fTracing; + /** The tracing ID of this device. */ + uint32_t idTracing; + + /** Padding to make achInstanceData aligned at 32 byte boundary. */ + uint32_t au32Padding[HC_ARCH_BITS == 32 ? 3 : 4]; + + /** Device instance data. The size of this area is defined + * in the PDMUSBREG::cbInstanceData field. */ + char achInstanceData[8]; +} PDMUSBINS; + +/** Current USBINS version number. */ +#define PDM_USBINS_VERSION PDM_VERSION_MAKE(0xeefd, 2, 0) + +/** + * Checks the structure versions of the USB device instance and USB device + * helpers, returning if they are incompatible. + * + * This is for use in the constructor. + * + * @param pUsbIns The USB device instance pointer. + */ +#define PDMUSB_CHECK_VERSIONS_RETURN(pUsbIns) \ + do \ + { \ + PPDMUSBINS pUsbInsTypeCheck = (pUsbIns); NOREF(pUsbInsTypeCheck); \ + AssertLogRelMsgReturn(PDM_VERSION_ARE_COMPATIBLE((pUsbIns)->u32Version, PDM_USBINS_VERSION), \ + ("DevIns=%#x mine=%#x\n", (pUsbIns)->u32Version, PDM_USBINS_VERSION), \ + VERR_PDM_USBINS_VERSION_MISMATCH); \ + AssertLogRelMsgReturn(PDM_VERSION_ARE_COMPATIBLE((pUsbIns)->pHlpR3->u32Version, PDM_USBHLP_VERSION), \ + ("DevHlp=%#x mine=%#x\n", (pUsbIns)->pHlpR3->u32Version, PDM_USBHLP_VERSION), \ + VERR_PDM_USBHLPR3_VERSION_MISMATCH); \ + } while (0) + +/** + * Quietly checks the structure versions of the USB device instance and + * USB device helpers, returning if they are incompatible. + * + * This is for use in the destructor. + * + * @param pUsbIns The USB device instance pointer. + */ +#define PDMUSB_CHECK_VERSIONS_RETURN_QUIET(pUsbIns) \ + do \ + { \ + PPDMUSBINS pUsbInsTypeCheck = (pUsbIns); NOREF(pUsbInsTypeCheck); \ + if (RT_UNLIKELY(!PDM_VERSION_ARE_COMPATIBLE((pUsbIns)->u32Version, PDM_USBINS_VERSION) )) \ + return VERR_PDM_USBINS_VERSION_MISMATCH; \ + if (RT_UNLIKELY(!PDM_VERSION_ARE_COMPATIBLE((pUsbIns)->pHlpR3->u32Version, PDM_USBHLPR3_VERSION) )) \ + return VERR_PDM_USBHLPR3_VERSION_MISMATCH; \ + } while (0) + + +/** Converts a pointer to the PDMUSBINS::IBase to a pointer to PDMUSBINS. */ +#define PDMIBASE_2_PDMUSB(pInterface) ( (PPDMUSBINS)((char *)(pInterface) - RT_OFFSETOF(PDMUSBINS, IBase)) ) + + +/** @def PDMUSB_ASSERT_EMT + * Assert that the current thread is the emulation thread. + */ +#ifdef VBOX_STRICT +# define PDMUSB_ASSERT_EMT(pUsbIns) pUsbIns->pHlpR3->pfnAssertEMT(pUsbIns, __FILE__, __LINE__, __FUNCTION__) +#else +# define PDMUSB_ASSERT_EMT(pUsbIns) do { } while (0) +#endif + +/** @def PDMUSB_ASSERT_OTHER + * Assert that the current thread is NOT the emulation thread. + */ +#ifdef VBOX_STRICT +# define PDMUSB_ASSERT_OTHER(pUsbIns) pUsbIns->pHlpR3->pfnAssertOther(pUsbIns, __FILE__, __LINE__, __FUNCTION__) +#else +# define PDMUSB_ASSERT_OTHER(pUsbIns) do { } while (0) +#endif + +/** @def PDMUSB_SET_ERROR + * Set the VM error. See PDMUsbHlpVMSetError() for printf like message + * formatting. + */ +#define PDMUSB_SET_ERROR(pUsbIns, rc, pszError) \ + PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS, "%s", pszError) + +/** @def PDMUSB_SET_RUNTIME_ERROR + * Set the VM runtime error. See PDMUsbHlpVMSetRuntimeError() for printf like + * message formatting. + */ +#define PDMUSB_SET_RUNTIME_ERROR(pUsbIns, fFlags, pszErrorId, pszError) \ + PDMUsbHlpVMSetRuntimeError(pUsbIns, fFlags, pszErrorId, "%s", pszError) + + +#ifdef IN_RING3 + +/** + * @copydoc PDMUSBHLP::pfnDriverAttach + */ +DECLINLINE(int) PDMUsbHlpDriverAttach(PPDMUSBINS pUsbIns, RTUINT iLun, PPDMIBASE pBaseInterface, PPDMIBASE *ppBaseInterface, const char *pszDesc) +{ + return pUsbIns->pHlpR3->pfnDriverAttach(pUsbIns, iLun, pBaseInterface, ppBaseInterface, pszDesc); +} + +/** + * VBOX_STRICT wrapper for pHlpR3->pfnDBGFStopV. + * + * @returns VBox status code which must be passed up to the VMM. + * @param pUsbIns Device instance. + * @param RT_SRC_POS_DECL Use RT_SRC_POS. + * @param pszFormat Message. (optional) + * @param ... Message parameters. + */ +DECLINLINE(int) PDMUsbDBGFStop(PPDMUSBINS pUsbIns, RT_SRC_POS_DECL, const char *pszFormat, ...) +{ +#ifdef VBOX_STRICT + int rc; + va_list va; + va_start(va, pszFormat); + rc = pUsbIns->pHlpR3->pfnDBGFStopV(pUsbIns, RT_SRC_POS_ARGS, pszFormat, va); + va_end(va); + return rc; +#else + NOREF(pUsbIns); + NOREF(pszFile); + NOREF(iLine); + NOREF(pszFunction); + NOREF(pszFormat); + return VINF_SUCCESS; +#endif +} + +/** + * @copydoc PDMUSBHLP::pfnVMState + */ +DECLINLINE(VMSTATE) PDMUsbHlpVMState(PPDMUSBINS pUsbIns) +{ + return pUsbIns->pHlpR3->pfnVMState(pUsbIns); +} + +/** + * @copydoc PDMUSBHLP::pfnThreadCreate + */ +DECLINLINE(int) PDMUsbHlpThreadCreate(PPDMUSBINS pUsbIns, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADUSB pfnThread, + PFNPDMTHREADWAKEUPUSB pfnWakeup, size_t cbStack, RTTHREADTYPE enmType, const char *pszName) +{ + return pUsbIns->pHlpR3->pfnThreadCreate(pUsbIns, ppThread, pvUser, pfnThread, pfnWakeup, cbStack, enmType, pszName); +} + + +/** + * @copydoc PDMUSBHLP::pfnSetAsyncNotification + */ +DECLINLINE(int) PDMUsbHlpSetAsyncNotification(PPDMUSBINS pUsbIns, PFNPDMUSBASYNCNOTIFY pfnAsyncNotify) +{ + return pUsbIns->pHlpR3->pfnSetAsyncNotification(pUsbIns, pfnAsyncNotify); +} + +/** + * @copydoc PDMUSBHLP::pfnAsyncNotificationCompleted + */ +DECLINLINE(void) PDMUsbHlpAsyncNotificationCompleted(PPDMUSBINS pUsbIns) +{ + pUsbIns->pHlpR3->pfnAsyncNotificationCompleted(pUsbIns); +} + +/** + * Set the VM error message + * + * @returns rc. + * @param pUsbIns The USB device instance. + * @param rc VBox status code. + * @param RT_SRC_POS_DECL Use RT_SRC_POS. + * @param pszFormat Error message format string. + * @param ... Error message arguments. + */ +DECLINLINE(int) PDMUsbHlpVMSetError(PPDMUSBINS pUsbIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...) +{ + va_list va; + va_start(va, pszFormat); + rc = pUsbIns->pHlpR3->pfnVMSetErrorV(pUsbIns, rc, RT_SRC_POS_ARGS, pszFormat, va); + va_end(va); + return rc; +} + +/** + * @copydoc PDMUSBHLP::pfnMMHeapAlloc + */ +DECLINLINE(void *) PDMUsbHlpMMHeapAlloc(PPDMUSBINS pUsbIns, size_t cb) +{ + return pUsbIns->pHlpR3->pfnMMHeapAlloc(pUsbIns, cb); +} + +/** + * @copydoc PDMUSBHLP::pfnMMHeapAllocZ + */ +DECLINLINE(void *) PDMUsbHlpMMHeapAllocZ(PPDMUSBINS pUsbIns, size_t cb) +{ + return pUsbIns->pHlpR3->pfnMMHeapAllocZ(pUsbIns, cb); +} + +/** + * Frees memory allocated by PDMUsbHlpMMHeapAlloc or PDMUsbHlpMMHeapAllocZ. + * + * @param pUsbIns The USB device instance. + * @param pv The memory to free. NULL is fine. + */ +DECLINLINE(void) PDMUsbHlpMMHeapFree(PPDMUSBINS pUsbIns, void *pv) +{ + NOREF(pUsbIns); + MMR3HeapFree(pv); +} + +/** + * @copydoc PDMUSBHLP::pfnTMTimerCreate + */ +DECLINLINE(int) PDMUsbHlpTMTimerCreate(PPDMUSBINS pUsbIns, TMCLOCK enmClock, PFNTMTIMERUSB pfnCallback, void *pvUser, + uint32_t fFlags, const char *pszDesc, PPTMTIMERR3 ppTimer) +{ + return pUsbIns->pHlpR3->pfnTMTimerCreate(pUsbIns, enmClock, pfnCallback, pvUser, fFlags, pszDesc, ppTimer); +} + +#endif /* IN_RING3 */ + + + +/** Pointer to callbacks provided to the VBoxUsbRegister() call. */ +typedef const struct PDMUSBREGCB *PCPDMUSBREGCB; + +/** + * Callbacks for VBoxUSBDeviceRegister(). + */ +typedef struct PDMUSBREGCB +{ + /** Interface version. + * This is set to PDM_USBREG_CB_VERSION. */ + uint32_t u32Version; + + /** + * Registers a device with the current VM instance. + * + * @returns VBox status code. + * @param pCallbacks Pointer to the callback table. + * @param pReg Pointer to the USB device registration record. + * This data must be permanent and readonly. + */ + DECLR3CALLBACKMEMBER(int, pfnRegister,(PCPDMUSBREGCB pCallbacks, PCPDMUSBREG pReg)); +} PDMUSBREGCB; + +/** Current version of the PDMUSBREGCB structure. */ +#define PDM_USBREG_CB_VERSION PDM_VERSION_MAKE(0xeefc, 1, 0) + + +/** + * The VBoxUsbRegister callback function. + * + * PDM will invoke this function after loading a USB device module and letting + * the module decide which devices to register and how to handle conflicts. + * + * @returns VBox status code. + * @param pCallbacks Pointer to the callback table. + * @param u32Version VBox version number. + */ +typedef DECLCALLBACK(int) FNPDMVBOXUSBREGISTER(PCPDMUSBREGCB pCallbacks, uint32_t u32Version); + +VMMR3DECL(int) PDMR3USBCreateProxyDevice(PVM pVM, PCRTUUID pUuid, bool fRemote, const char *pszAddress, void *pvBackend, + uint32_t iUsbVersion, uint32_t fMaskedIfs); +VMMR3DECL(int) PDMR3USBDetachDevice(PVM pVM, PCRTUUID pUuid); +VMMR3DECL(bool) PDMR3USBHasHub(PVM pVM); + + +/** @} */ + +RT_C_DECLS_END + +#endif diff --git a/include/VBox/vmm/pgm.h b/include/VBox/vmm/pgm.h new file mode 100644 index 00000000..5d8b5f0d --- /dev/null +++ b/include/VBox/vmm/pgm.h @@ -0,0 +1,586 @@ +/** @file + * PGM - Page Monitor / Monitor. + */ + +/* + * Copyright (C) 2006-2010 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_pgm_h +#define ___VBox_vmm_pgm_h + +#include <VBox/types.h> +#include <VBox/sup.h> +#include <VBox/vmm/vmapi.h> +#include <VBox/vmm/gmm.h> /* for PGMMREGISTERSHAREDMODULEREQ */ +#include <iprt/x86.h> +#include <VBox/VMMDev.h> /* for VMMDEVSHAREDREGIONDESC */ +#include <VBox/param.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pgm The Page Monitor / Manager API + * @{ + */ + +/** + * FNPGMRELOCATE callback mode. + */ +typedef enum PGMRELOCATECALL +{ + /** The callback is for checking if the suggested address is suitable. */ + PGMRELOCATECALL_SUGGEST = 1, + /** The callback is for executing the relocation. */ + PGMRELOCATECALL_RELOCATE +} PGMRELOCATECALL; + + +/** + * Callback function which will be called when PGM is trying to find + * a new location for the mapping. + * + * The callback is called in two modes, 1) the check mode and 2) the relocate mode. + * In 1) the callback should say if it objects to a suggested new location. If it + * accepts the new location, it is called again for doing it's relocation. + * + * + * @returns true if the location is ok. + * @returns false if another location should be found. + * @param GCPtrOld The old virtual address. + * @param GCPtrNew The new virtual address. + * @param enmMode Used to indicate the callback mode. + * @param pvUser User argument. + * @remark The return value is no a failure indicator, it's an acceptance + * indicator. Relocation can not fail! + */ +typedef DECLCALLBACK(bool) FNPGMRELOCATE(PVM pVM, RTGCPTR GCPtrOld, RTGCPTR GCPtrNew, PGMRELOCATECALL enmMode, void *pvUser); +/** Pointer to a relocation callback function. */ +typedef FNPGMRELOCATE *PFNPGMRELOCATE; + + +/** + * Physical page access handler type. + */ +typedef enum PGMPHYSHANDLERTYPE +{ + /** MMIO range. Pages are not present, all access is done in interpreter or recompiler. */ + PGMPHYSHANDLERTYPE_MMIO = 1, + /** Handler all write access to a physical page range. */ + PGMPHYSHANDLERTYPE_PHYSICAL_WRITE, + /** Handler all access to a physical page range. */ + PGMPHYSHANDLERTYPE_PHYSICAL_ALL + +} PGMPHYSHANDLERTYPE; + +/** + * \#PF Handler callback for physical access handler ranges in RC. + * + * @returns VBox status code (appropriate for RC return). + * @param pVM VM Handle. + * @param uErrorCode CPU Error code. + * @param pRegFrame Trap register frame. + * NULL on DMA and other non CPU access. + * @param pvFault The fault address (cr2). + * @param GCPhysFault The GC physical address corresponding to pvFault. + * @param pvUser User argument. + */ +typedef DECLCALLBACK(int) FNPGMRCPHYSHANDLER(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPHYS GCPhysFault, void *pvUser); +/** Pointer to PGM access callback. */ +typedef FNPGMRCPHYSHANDLER *PFNPGMRCPHYSHANDLER; + +/** + * \#PF Handler callback for physical access handler ranges in R0. + * + * @returns VBox status code (appropriate for R0 return). + * @param pVM VM Handle. + * @param uErrorCode CPU Error code. + * @param pRegFrame Trap register frame. + * NULL on DMA and other non CPU access. + * @param pvFault The fault address (cr2). + * @param GCPhysFault The GC physical address corresponding to pvFault. + * @param pvUser User argument. + */ +typedef DECLCALLBACK(int) FNPGMR0PHYSHANDLER(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPHYS GCPhysFault, void *pvUser); +/** Pointer to PGM access callback. */ +typedef FNPGMR0PHYSHANDLER *PFNPGMR0PHYSHANDLER; + +/** + * Guest Access type + */ +typedef enum PGMACCESSTYPE +{ + /** Read access. */ + PGMACCESSTYPE_READ = 1, + /** Write access. */ + PGMACCESSTYPE_WRITE +} PGMACCESSTYPE; + +/** + * \#PF Handler callback for physical access handler ranges (MMIO among others) in HC. + * + * The handler can not raise any faults, it's mainly for monitoring write access + * to certain pages. + * + * @returns VINF_SUCCESS if the handler have carried out the operation. + * @returns VINF_PGM_HANDLER_DO_DEFAULT if the caller should carry out the access operation. + * @param pVM VM Handle. + * @param GCPhys The physical address the guest is writing to. + * @param pvPhys The HC mapping of that address. + * @param pvBuf What the guest is reading/writing. + * @param cbBuf How much it's reading/writing. + * @param enmAccessType The access type. + * @param pvUser User argument. + * + * @todo Add pVCpu, possibly replacing pVM. + */ +typedef DECLCALLBACK(int) FNPGMR3PHYSHANDLER(PVM pVM, RTGCPHYS GCPhys, void *pvPhys, void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType, void *pvUser); +/** Pointer to PGM access callback. */ +typedef FNPGMR3PHYSHANDLER *PFNPGMR3PHYSHANDLER; + + +/** + * Virtual access handler type. + */ +typedef enum PGMVIRTHANDLERTYPE +{ + /** Write access handled. */ + PGMVIRTHANDLERTYPE_WRITE = 1, + /** All access handled. */ + PGMVIRTHANDLERTYPE_ALL, + /** Hypervisor write access handled. + * This is used to catch the guest trying to write to LDT, TSS and any other + * system structure which the brain dead intel guys let unprivilegde code find. */ + PGMVIRTHANDLERTYPE_HYPERVISOR +} PGMVIRTHANDLERTYPE; + +/** + * \#PF Handler callback for virtual access handler ranges, RC. + * + * Important to realize that a physical page in a range can have aliases, and + * for ALL and WRITE handlers these will also trigger. + * + * @returns VBox status code (appropriate for GC return). + * @param pVM VM Handle. + * @param uErrorCode CPU Error code. + * @param pRegFrame Trap register frame. + * @param pvFault The fault address (cr2). + * @param pvRange The base address of the handled virtual range. + * @param offRange The offset of the access into this range. + * (If it's a EIP range this is the EIP, if not it's pvFault.) + * @todo Add pVCpu, possibly replacing pVM. + */ +typedef DECLCALLBACK(int) FNPGMRCVIRTHANDLER(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPTR pvRange, uintptr_t offRange); +/** Pointer to PGM access callback. */ +typedef FNPGMRCVIRTHANDLER *PFNPGMRCVIRTHANDLER; + +/** + * \#PF Handler callback for virtual access handler ranges, R3. + * + * Important to realize that a physical page in a range can have aliases, and + * for ALL and WRITE handlers these will also trigger. + * + * @returns VINF_SUCCESS if the handler have carried out the operation. + * @returns VINF_PGM_HANDLER_DO_DEFAULT if the caller should carry out the access operation. + * @param pVM VM Handle. + * @param GCPtr The virtual address the guest is writing to. (not correct if it's an alias!) + * @param pvPtr The HC mapping of that address. + * @param pvBuf What the guest is reading/writing. + * @param cbBuf How much it's reading/writing. + * @param enmAccessType The access type. + * @param pvUser User argument. + * @todo Add pVCpu, possibly replacing pVM. + */ +typedef DECLCALLBACK(int) FNPGMR3VIRTHANDLER(PVM pVM, RTGCPTR GCPtr, void *pvPtr, void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType, void *pvUser); +/** Pointer to PGM access callback. */ +typedef FNPGMR3VIRTHANDLER *PFNPGMR3VIRTHANDLER; + + +/** + * \#PF Handler callback for invalidation of virtual access handler ranges. + * + * @param pVM VM Handle. + * @param GCPtr The virtual address the guest has changed. + */ +typedef DECLCALLBACK(int) FNPGMR3VIRTINVALIDATE(PVM pVM, RTGCPTR GCPtr); +/** Pointer to PGM invalidation callback. */ +typedef FNPGMR3VIRTINVALIDATE *PFNPGMR3VIRTINVALIDATE; + +/** + * PGMR3PhysEnumDirtyFTPages callback for syncing dirty physical pages + * + * @param pVM VM Handle. + * @param GCPhys GC physical address + * @param pRange HC virtual address of the page(s) + * @param cbRange Size of the dirty range in bytes. + * @param pvUser User argument. + */ +typedef DECLCALLBACK(int) FNPGMENUMDIRTYFTPAGES(PVM pVM, RTGCPHYS GCPhys, uint8_t *pRange, unsigned cbRange, void *pvUser); +/** Pointer to PGMR3PhysEnumDirtyFTPages callback. */ +typedef FNPGMENUMDIRTYFTPAGES *PFNPGMENUMDIRTYFTPAGES; + +/** + * Paging mode. + */ +typedef enum PGMMODE +{ + /** The usual invalid value. */ + PGMMODE_INVALID = 0, + /** Real mode. */ + PGMMODE_REAL, + /** Protected mode, no paging. */ + PGMMODE_PROTECTED, + /** 32-bit paging. */ + PGMMODE_32_BIT, + /** PAE paging. */ + PGMMODE_PAE, + /** PAE paging with NX enabled. */ + PGMMODE_PAE_NX, + /** 64-bit AMD paging (long mode). */ + PGMMODE_AMD64, + /** 64-bit AMD paging (long mode) with NX enabled. */ + PGMMODE_AMD64_NX, + /** Nested paging mode (shadow only; guest physical to host physical). */ + PGMMODE_NESTED, + /** Extended paging (Intel) mode. */ + PGMMODE_EPT, + /** The max number of modes */ + PGMMODE_MAX, + /** 32bit hackishness. */ + PGMMODE_32BIT_HACK = 0x7fffffff +} PGMMODE; + +/** Macro for checking if the guest is using paging. + * @param enmMode PGMMODE_*. + * @remark ASSUMES certain order of the PGMMODE_* values. + */ +#define PGMMODE_WITH_PAGING(enmMode) ((enmMode) >= PGMMODE_32_BIT) + +/** Macro for checking if it's one of the long mode modes. + * @param enmMode PGMMODE_*. + */ +#define PGMMODE_IS_LONG_MODE(enmMode) ((enmMode) == PGMMODE_AMD64_NX || (enmMode) == PGMMODE_AMD64) + +/** + * Is the ROM mapped (true) or is the shadow RAM mapped (false). + * + * @returns boolean. + * @param enmProt The PGMROMPROT value, must be valid. + */ +#define PGMROMPROT_IS_ROM(enmProt) \ + ( (enmProt) == PGMROMPROT_READ_ROM_WRITE_IGNORE \ + || (enmProt) == PGMROMPROT_READ_ROM_WRITE_RAM ) + + + +VMMDECL(bool) PGMIsLockOwner(PVM pVM); + +VMMDECL(int) PGMRegisterStringFormatTypes(void); +VMMDECL(void) PGMDeregisterStringFormatTypes(void); +VMMDECL(RTHCPHYS) PGMGetHyperCR3(PVMCPU pVCpu); +VMMDECL(RTHCPHYS) PGMGetNestedCR3(PVMCPU pVCpu, PGMMODE enmShadowMode); +VMMDECL(RTHCPHYS) PGMGetInterHCCR3(PVM pVM); +VMMDECL(RTHCPHYS) PGMGetInterRCCR3(PVM pVM, PVMCPU pVCpu); +VMMDECL(RTHCPHYS) PGMGetInter32BitCR3(PVM pVM); +VMMDECL(RTHCPHYS) PGMGetInterPaeCR3(PVM pVM); +VMMDECL(RTHCPHYS) PGMGetInterAmd64CR3(PVM pVM); +VMMDECL(int) PGMTrap0eHandler(PVMCPU pVCpu, RTGCUINT uErr, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault); +VMMDECL(int) PGMPrefetchPage(PVMCPU pVCpu, RTGCPTR GCPtrPage); +VMMDECL(int) PGMVerifyAccess(PVMCPU pVCpu, RTGCPTR Addr, uint32_t cbSize, uint32_t fAccess); +VMMDECL(int) PGMIsValidAccess(PVMCPU pVCpu, RTGCPTR Addr, uint32_t cbSize, uint32_t fAccess); +VMMDECL(VBOXSTRICTRC) PGMInterpretInstruction(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault); +VMMDECL(int) PGMMap(PVM pVM, RTGCPTR GCPtr, RTHCPHYS HCPhys, uint32_t cbPages, unsigned fFlags); +VMMDECL(int) PGMMapGetPage(PVM pVM, RTGCPTR GCPtr, uint64_t *pfFlags, PRTHCPHYS pHCPhys); +VMMDECL(int) PGMMapSetPage(PVM pVM, RTGCPTR GCPtr, uint64_t cb, uint64_t fFlags); +VMMDECL(int) PGMMapModifyPage(PVM pVM, RTGCPTR GCPtr, size_t cb, uint64_t fFlags, uint64_t fMask); +#ifndef IN_RING0 +VMMDECL(bool) PGMMapHasConflicts(PVM pVM); +#endif +#ifdef VBOX_STRICT +VMMDECL(void) PGMMapCheck(PVM pVM); +#endif +VMMDECL(int) PGMShwGetPage(PVMCPU pVCpu, RTGCPTR GCPtr, uint64_t *pfFlags, PRTHCPHYS pHCPhys); +VMMDECL(int) PGMShwMakePageReadonly(PVMCPU pVCpu, RTGCPTR GCPtr, uint32_t fFlags); +VMMDECL(int) PGMShwMakePageWritable(PVMCPU pVCpu, RTGCPTR GCPtr, uint32_t fFlags); +VMMDECL(int) PGMShwMakePageNotPresent(PVMCPU pVCpu, RTGCPTR GCPtr, uint32_t fFlags); +/** @name Flags for PGMShwMakePageReadonly, PGMShwMakePageWritable and + * PGMShwMakePageNotPresent + * @{ */ +/** The call is from an access handler for dealing with the a faulting write + * operation. The virtual address is within the same page. */ +#define PGM_MK_PG_IS_WRITE_FAULT RT_BIT(0) +/** The page is an MMIO2. */ +#define PGM_MK_PG_IS_MMIO2 RT_BIT(1) +/** @}*/ +VMMDECL(int) PGMGstGetPage(PVMCPU pVCpu, RTGCPTR GCPtr, uint64_t *pfFlags, PRTGCPHYS pGCPhys); +VMMDECL(bool) PGMGstIsPagePresent(PVMCPU pVCpu, RTGCPTR GCPtr); +VMMDECL(int) PGMGstSetPage(PVMCPU pVCpu, RTGCPTR GCPtr, size_t cb, uint64_t fFlags); +VMMDECL(int) PGMGstModifyPage(PVMCPU pVCpu, RTGCPTR GCPtr, size_t cb, uint64_t fFlags, uint64_t fMask); +VMM_INT_DECL(int) PGMGstGetPaePdpes(PVMCPU pVCpu, PX86PDPE paPdpes); +VMM_INT_DECL(int) PGMGstUpdatePaePdpes(PVMCPU pVCpu, PCX86PDPE paPdpes); + +VMMDECL(int) PGMInvalidatePage(PVMCPU pVCpu, RTGCPTR GCPtrPage); +VMMDECL(int) PGMFlushTLB(PVMCPU pVCpu, uint64_t cr3, bool fGlobal); +VMMDECL(int) PGMSyncCR3(PVMCPU pVCpu, uint64_t cr0, uint64_t cr3, uint64_t cr4, bool fGlobal); +VMMDECL(int) PGMUpdateCR3(PVMCPU pVCpu, uint64_t cr3); +VMMDECL(int) PGMChangeMode(PVMCPU pVCpu, uint64_t cr0, uint64_t cr4, uint64_t efer); +VMMDECL(PGMMODE) PGMGetGuestMode(PVMCPU pVCpu); +VMMDECL(PGMMODE) PGMGetShadowMode(PVMCPU pVCpu); +VMMDECL(PGMMODE) PGMGetHostMode(PVM pVM); +VMMDECL(const char *) PGMGetModeName(PGMMODE enmMode); +VMM_INT_DECL(void) PGMNotifyNxeChanged(PVMCPU pVCpu, bool fNxe); +VMMDECL(bool) PGMHasDirtyPages(PVM pVM); +VMMDECL(int) PGMHandlerPhysicalRegisterEx(PVM pVM, PGMPHYSHANDLERTYPE enmType, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast, + R3PTRTYPE(PFNPGMR3PHYSHANDLER) pfnHandlerR3, RTR3PTR pvUserR3, + R0PTRTYPE(PFNPGMR0PHYSHANDLER) pfnHandlerR0, RTR0PTR pvUserR0, + RCPTRTYPE(PFNPGMRCPHYSHANDLER) pfnHandlerRC, RTRCPTR pvUserRC, + R3PTRTYPE(const char *) pszDesc); +VMMDECL(int) PGMHandlerPhysicalModify(PVM pVM, RTGCPHYS GCPhysCurrent, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast); +VMMDECL(int) PGMHandlerPhysicalDeregister(PVM pVM, RTGCPHYS GCPhys); +VMMDECL(int) PGMHandlerPhysicalChangeCallbacks(PVM pVM, RTGCPHYS GCPhys, + R3PTRTYPE(PFNPGMR3PHYSHANDLER) pfnHandlerR3, RTR3PTR pvUserR3, + R0PTRTYPE(PFNPGMR0PHYSHANDLER) pfnHandlerR0, RTR0PTR pvUserR0, + RCPTRTYPE(PFNPGMRCPHYSHANDLER) pfnHandlerRC, RTRCPTR pvUserRC, + R3PTRTYPE(const char *) pszDesc); +VMMDECL(int) PGMHandlerPhysicalSplit(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysSplit); +VMMDECL(int) PGMHandlerPhysicalJoin(PVM pVM, RTGCPHYS GCPhys1, RTGCPHYS GCPhys2); +VMMDECL(int) PGMHandlerPhysicalPageTempOff(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysPage); +VMMDECL(int) PGMHandlerPhysicalPageAlias(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysPage, RTGCPHYS GCPhysPageRemap); +VMMDECL(int) PGMHandlerPhysicalPageAliasHC(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysPage, RTHCPHYS HCPhysPageRemap); +VMMDECL(int) PGMHandlerPhysicalReset(PVM pVM, RTGCPHYS GCPhys); +VMMDECL(bool) PGMHandlerPhysicalIsRegistered(PVM pVM, RTGCPHYS GCPhys); +VMMDECL(bool) PGMHandlerVirtualIsRegistered(PVM pVM, RTGCPTR GCPtr); +VMMDECL(bool) PGMPhysIsA20Enabled(PVMCPU pVCpu); +VMMDECL(bool) PGMPhysIsGCPhysValid(PVM pVM, RTGCPHYS GCPhys); +VMMDECL(bool) PGMPhysIsGCPhysNormal(PVM pVM, RTGCPHYS GCPhys); +VMMDECL(int) PGMPhysGCPtr2GCPhys(PVMCPU pVCpu, RTGCPTR GCPtr, PRTGCPHYS pGCPhys); +VMMDECL(void) PGMPhysReleasePageMappingLock(PVM pVM, PPGMPAGEMAPLOCK pLock); +VMMDECL(int) PGMPhysRead(PVM pVM, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead); +VMMDECL(int) PGMPhysWrite(PVM pVM, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite); +VMMDECL(int) PGMPhysSimpleReadGCPhys(PVM pVM, void *pvDst, RTGCPHYS GCPhysSrc, size_t cb); +VMMDECL(int) PGMPhysSimpleWriteGCPhys(PVM pVM, RTGCPHYS GCPhysDst, const void *pvSrc, size_t cb); +VMMDECL(int) PGMPhysSimpleReadGCPtr(PVMCPU pVCpu, void *pvDst, RTGCPTR GCPtrSrc, size_t cb); +VMMDECL(int) PGMPhysSimpleWriteGCPtr(PVMCPU pVCpu, RTGCPTR GCPtrDst, const void *pvSrc, size_t cb); +VMMDECL(int) PGMPhysReadGCPtr(PVMCPU pVCpu, void *pvDst, RTGCPTR GCPtrSrc, size_t cb); +VMMDECL(int) PGMPhysWriteGCPtr(PVMCPU pVCpu, RTGCPTR GCPtrDst, const void *pvSrc, size_t cb); +VMMDECL(int) PGMPhysSimpleDirtyWriteGCPtr(PVMCPU pVCpu, RTGCPTR GCPtrDst, const void *pvSrc, size_t cb); +VMMDECL(int) PGMPhysInterpretedRead(PVMCPU pVCpu, PCPUMCTXCORE pCtxCore, void *pvDst, RTGCPTR GCPtrSrc, size_t cb); +VMMDECL(int) PGMPhysInterpretedReadNoHandlers(PVMCPU pVCpu, PCPUMCTXCORE pCtxCore, void *pvDst, RTGCUINTPTR GCPtrSrc, size_t cb, bool fRaiseTrap); +VMMDECL(int) PGMPhysInterpretedWriteNoHandlers(PVMCPU pVCpu, PCPUMCTXCORE pCtxCore, RTGCPTR GCPtrDst, void const *pvSrc, size_t cb, bool fRaiseTrap); +VMM_INT_DECL(int) PGMPhysIemGCPhys2Ptr(PVM pVM, RTGCPHYS GCPhys, bool fWritable, bool fByPassHandlers, void **ppv, PPGMPAGEMAPLOCK pLock); +#ifdef VBOX_STRICT +VMMDECL(unsigned) PGMAssertHandlerAndFlagsInSync(PVM pVM); +VMMDECL(unsigned) PGMAssertNoMappingConflicts(PVM pVM); +VMMDECL(unsigned) PGMAssertCR3(PVM pVM, PVMCPU pVCpu, uint64_t cr3, uint64_t cr4); +#endif /* VBOX_STRICT */ + +#if defined(IN_RC) || defined(VBOX_WITH_2X_4GB_ADDR_SPACE) +VMMDECL(void) PGMRZDynMapStartAutoSet(PVMCPU pVCpu); +VMMDECL(void) PGMRZDynMapReleaseAutoSet(PVMCPU pVCpu); +VMMDECL(void) PGMRZDynMapFlushAutoSet(PVMCPU pVCpu); +VMMDECL(uint32_t) PGMRZDynMapPushAutoSubset(PVMCPU pVCpu); +VMMDECL(void) PGMRZDynMapPopAutoSubset(PVMCPU pVCpu, uint32_t iPrevSubset); +#endif + +VMMDECL(int) PGMSetLargePageUsage(PVM pVM, bool fUseLargePages); + +/** + * Query large page usage state + * + * @returns 0 - disabled, 1 - enabled + * @param pVM The VM to operate on. + */ +#define PGMIsUsingLargePages(pVM) ((pVM)->fUseLargePages) + + +#ifdef IN_RC +/** @defgroup grp_pgm_gc The PGM Guest Context API + * @ingroup grp_pgm + * @{ + */ +VMMRCDECL(int) PGMRCDynMapInit(PVM pVM); +/** @} */ +#endif /* IN_RC */ + + +#ifdef IN_RING0 +/** @defgroup grp_pgm_r0 The PGM Host Context Ring-0 API + * @ingroup grp_pgm + * @{ + */ +VMMR0_INT_DECL(int) PGMR0PhysAllocateHandyPages(PVM pVM, PVMCPU pVCpu); +VMMR0_INT_DECL(int) PGMR0PhysFlushHandyPages(PVM pVM, PVMCPU pVCpu); +VMMR0_INT_DECL(int) PGMR0PhysAllocateLargeHandyPage(PVM pVM, PVMCPU pVCpu); +VMMR0_INT_DECL(int) PGMR0PhysSetupIommu(PVM pVM); +VMMR0DECL(int) PGMR0SharedModuleCheck(PVM pVM, PGVM pGVM, VMCPUID idCpu, PGMMSHAREDMODULE pModule, PCRTGCPTR64 paRegionsGCPtrs); +VMMR0DECL(int) PGMR0Trap0eHandlerNestedPaging(PVM pVM, PVMCPU pVCpu, PGMMODE enmShwPagingMode, RTGCUINT uErr, PCPUMCTXCORE pRegFrame, RTGCPHYS pvFault); +VMMR0DECL(VBOXSTRICTRC) PGMR0Trap0eHandlerNPMisconfig(PVM pVM, PVMCPU pVCpu, PGMMODE enmShwPagingMode, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, uint32_t uErr); +# ifdef VBOX_WITH_2X_4GB_ADDR_SPACE +VMMR0DECL(int) PGMR0DynMapInit(void); +VMMR0DECL(void) PGMR0DynMapTerm(void); +VMMR0DECL(int) PGMR0DynMapInitVM(PVM pVM); +VMMR0DECL(void) PGMR0DynMapTermVM(PVM pVM); +VMMR0DECL(int) PGMR0DynMapAssertIntegrity(void); +VMMR0DECL(bool) PGMR0DynMapStartOrMigrateAutoSet(PVMCPU pVCpu); +VMMR0DECL(void) PGMR0DynMapMigrateAutoSet(PVMCPU pVCpu); +# endif +/** @} */ +#endif /* IN_RING0 */ + + + +#ifdef IN_RING3 +/** @defgroup grp_pgm_r3 The PGM Host Context Ring-3 API + * @ingroup grp_pgm + * @{ + */ +VMMR3DECL(int) PGMR3Init(PVM pVM); +VMMR3DECL(int) PGMR3InitDynMap(PVM pVM); +VMMR3DECL(int) PGMR3InitFinalize(PVM pVM); +VMMR3_INT_DECL(int) PGMR3InitCompleted(PVM pVM, VMINITCOMPLETED enmWhat); +VMMR3DECL(void) PGMR3Relocate(PVM pVM, RTGCINTPTR offDelta); +VMMR3DECL(void) PGMR3ResetUnpluggedCpu(PVM pVM, PVMCPU pVCpu); +VMMR3DECL(void) PGMR3Reset(PVM pVM); +VMMR3DECL(int) PGMR3Term(PVM pVM); +VMMR3DECL(int) PGMR3LockCall(PVM pVM); +VMMR3DECL(int) PGMR3ChangeMode(PVM pVM, PVMCPU pVCpu, PGMMODE enmGuestMode); + +VMMR3DECL(int) PGMR3PhysRegisterRam(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, const char *pszDesc); +VMMR3DECL(int) PGMR3PhysChangeMemBalloon(PVM pVM, bool fInflate, unsigned cPages, RTGCPHYS *paPhysPage); +VMMR3DECL(int) PGMR3PhysWriteProtectRAM(PVM pVM); +VMMR3DECL(int) PGMR3PhysEnumDirtyFTPages(PVM pVM, PFNPGMENUMDIRTYFTPAGES pfnEnum, void *pvUser); +VMMR3DECL(uint32_t) PGMR3PhysGetRamRangeCount(PVM pVM); +VMMR3DECL(int) PGMR3PhysGetRange(PVM pVM, uint32_t iRange, PRTGCPHYS pGCPhysStart, PRTGCPHYS pGCPhysLast, + const char **ppszDesc, bool *pfIsMmio); +VMMR3DECL(int) PGMR3QueryMemoryStats(PVM pVM, uint64_t *pcbTotalMem, uint64_t *pcbPrivateMem, uint64_t *pcbSharedMem, uint64_t *pcbZeroMem); +VMMR3DECL(int) PGMR3QueryGlobalMemoryStats(PVM pVM, uint64_t *pcbAllocMem, uint64_t *pcbFreeMem, uint64_t *pcbBallonedMem, uint64_t *pcbSharedMem); + +VMMR3DECL(int) PGMR3PhysMMIORegister(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, + R3PTRTYPE(PFNPGMR3PHYSHANDLER) pfnHandlerR3, RTR3PTR pvUserR3, + R0PTRTYPE(PFNPGMR0PHYSHANDLER) pfnHandlerR0, RTR0PTR pvUserR0, + RCPTRTYPE(PFNPGMRCPHYSHANDLER) pfnHandlerRC, RTRCPTR pvUserRC, + R3PTRTYPE(const char *) pszDesc); +VMMR3DECL(int) PGMR3PhysMMIODeregister(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb); +VMMR3DECL(int) PGMR3PhysMMIO2Register(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS cb, uint32_t fFlags, void **ppv, const char *pszDesc); +VMMR3DECL(int) PGMR3PhysMMIO2Deregister(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion); +VMMR3DECL(int) PGMR3PhysMMIO2Map(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS GCPhys); +VMMR3DECL(int) PGMR3PhysMMIO2Unmap(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS GCPhys); +VMMR3DECL(bool) PGMR3PhysMMIO2IsBase(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhys); +VMMR3DECL(int) PGMR3PhysMMIO2GetHCPhys(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS off, PRTHCPHYS pHCPhys); +VMMR3DECL(int) PGMR3PhysMMIO2MapKernel(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS off, RTGCPHYS cb, const char *pszDesc, PRTR0PTR pR0Ptr); + +/** @name PGMR3PhysRegisterRom flags. + * @{ */ +/** Inidicates that ROM shadowing should be enabled. */ +#define PGMPHYS_ROM_FLAGS_SHADOWED RT_BIT_32(0) +/** Indicates that what pvBinary points to won't go away + * and can be used for strictness checks. */ +#define PGMPHYS_ROM_FLAGS_PERMANENT_BINARY RT_BIT_32(1) +/** @} */ + +VMMR3DECL(int) PGMR3PhysRomRegister(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTGCPHYS cb, + const void *pvBinary, uint32_t cbBinary, uint32_t fFlags, const char *pszDesc); +VMMR3DECL(int) PGMR3PhysRomProtect(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, PGMROMPROT enmProt); +VMMR3DECL(int) PGMR3PhysRegister(PVM pVM, void *pvRam, RTGCPHYS GCPhys, size_t cb, unsigned fFlags, const SUPPAGE *paPages, const char *pszDesc); +VMMDECL(void) PGMR3PhysSetA20(PVMCPU pVCpu, bool fEnable); +/** @name PGMR3MapPT flags. + * @{ */ +/** The mapping may be unmapped later. The default is permanent mappings. */ +#define PGMR3MAPPT_FLAGS_UNMAPPABLE RT_BIT(0) +/** @} */ +VMMR3DECL(int) PGMR3MapPT(PVM pVM, RTGCPTR GCPtr, uint32_t cb, uint32_t fFlags, PFNPGMRELOCATE pfnRelocate, void *pvUser, const char *pszDesc); +VMMR3DECL(int) PGMR3UnmapPT(PVM pVM, RTGCPTR GCPtr); +VMMR3DECL(int) PGMR3FinalizeMappings(PVM pVM); +VMMR3DECL(int) PGMR3MappingsDisable(PVM pVM); +VMMR3DECL(int) PGMR3MappingsSize(PVM pVM, uint32_t *pcb); +VMMR3DECL(int) PGMR3MappingsFix(PVM pVM, RTGCPTR GCPtrBase, uint32_t cb); +VMMR3DECL(int) PGMR3MappingsUnfix(PVM pVM); +VMMR3DECL(bool) PGMR3MappingsNeedReFixing(PVM pVM); +VMMR3DECL(int) PGMR3MapIntermediate(PVM pVM, RTUINTPTR Addr, RTHCPHYS HCPhys, unsigned cbPages); +VMMR3DECL(int) PGMR3MapRead(PVM pVM, void *pvDst, RTGCPTR GCPtrSrc, size_t cb); + +VMMR3DECL(int) PGMR3HandlerPhysicalRegister(PVM pVM, PGMPHYSHANDLERTYPE enmType, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast, + PFNPGMR3PHYSHANDLER pfnHandlerR3, void *pvUserR3, + const char *pszModR0, const char *pszHandlerR0, RTR0PTR pvUserR0, + const char *pszModRC, const char *pszHandlerRC, RTRCPTR pvUserRC, const char *pszDesc); +VMMDECL(int) PGMR3HandlerVirtualRegisterEx(PVM pVM, PGMVIRTHANDLERTYPE enmType, RTGCPTR GCPtr, RTGCPTR GCPtrLast, + R3PTRTYPE(PFNPGMR3VIRTINVALIDATE) pfnInvalidateR3, + R3PTRTYPE(PFNPGMR3VIRTHANDLER) pfnHandlerR3, + RCPTRTYPE(PFNPGMRCVIRTHANDLER) pfnHandlerRC, + R3PTRTYPE(const char *) pszDesc); +VMMR3DECL(int) PGMR3HandlerVirtualRegister(PVM pVM, PGMVIRTHANDLERTYPE enmType, RTGCPTR GCPtr, RTGCPTR GCPtrLast, + PFNPGMR3VIRTINVALIDATE pfnInvalidateR3, + PFNPGMR3VIRTHANDLER pfnHandlerR3, + const char *pszHandlerRC, const char *pszModRC, const char *pszDesc); +VMMDECL(int) PGMHandlerVirtualChangeInvalidateCallback(PVM pVM, RTGCPTR GCPtr, R3PTRTYPE(PFNPGMR3VIRTINVALIDATE) pfnInvalidateR3); +VMMDECL(int) PGMHandlerVirtualDeregister(PVM pVM, RTGCPTR GCPtr); +VMMR3DECL(int) PGMR3PoolGrow(PVM pVM); + +VMMR3DECL(int) PGMR3PhysTlbGCPhys2Ptr(PVM pVM, RTGCPHYS GCPhys, bool fWritable, void **ppv); +VMMR3DECL(uint8_t) PGMR3PhysReadU8(PVM pVM, RTGCPHYS GCPhys); +VMMR3DECL(uint16_t) PGMR3PhysReadU16(PVM pVM, RTGCPHYS GCPhys); +VMMR3DECL(uint32_t) PGMR3PhysReadU32(PVM pVM, RTGCPHYS GCPhys); +VMMR3DECL(uint64_t) PGMR3PhysReadU64(PVM pVM, RTGCPHYS GCPhys); +VMMR3DECL(void) PGMR3PhysWriteU8(PVM pVM, RTGCPHYS GCPhys, uint8_t Value); +VMMR3DECL(void) PGMR3PhysWriteU16(PVM pVM, RTGCPHYS GCPhys, uint16_t Value); +VMMR3DECL(void) PGMR3PhysWriteU32(PVM pVM, RTGCPHYS GCPhys, uint32_t Value); +VMMR3DECL(void) PGMR3PhysWriteU64(PVM pVM, RTGCPHYS GCPhys, uint64_t Value); +VMMR3DECL(int) PGMR3PhysReadExternal(PVM pVM, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead); +VMMR3DECL(int) PGMR3PhysWriteExternal(PVM pVM, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite, const char *pszWho); +VMMR3DECL(int) PGMR3PhysGCPhys2CCPtrExternal(PVM pVM, RTGCPHYS GCPhys, void **ppv, PPGMPAGEMAPLOCK pLock); +VMMR3DECL(int) PGMR3PhysGCPhys2CCPtrReadOnlyExternal(PVM pVM, RTGCPHYS GCPhys, void const **ppv, PPGMPAGEMAPLOCK pLock); +VMMR3DECL(int) PGMR3PhysChunkMap(PVM pVM, uint32_t idChunk); +VMMR3DECL(void) PGMR3PhysChunkInvalidateTLB(PVM pVM); +VMMR3DECL(int) PGMR3PhysAllocateHandyPages(PVM pVM); +VMMR3DECL(int) PGMR3PhysAllocateLargeHandyPage(PVM pVM, RTGCPHYS GCPhys); + +VMMR3DECL(int) PGMR3CheckIntegrity(PVM pVM); + +VMMR3DECL(int) PGMR3DbgR3Ptr2GCPhys(PVM pVM, RTR3PTR R3Ptr, PRTGCPHYS pGCPhys); +VMMR3DECL(int) PGMR3DbgR3Ptr2HCPhys(PVM pVM, RTR3PTR R3Ptr, PRTHCPHYS pHCPhys); +VMMR3DECL(int) PGMR3DbgHCPhys2GCPhys(PVM pVM, RTHCPHYS HCPhys, PRTGCPHYS pGCPhys); +VMMR3DECL(int) PGMR3DbgReadGCPhys(PVM pVM, void *pvDst, RTGCPHYS GCPhysSrc, size_t cb, uint32_t fFlags, size_t *pcbRead); +VMMR3DECL(int) PGMR3DbgWriteGCPhys(PVM pVM, RTGCPHYS GCPhysDst, const void *pvSrc, size_t cb, uint32_t fFlags, size_t *pcbWritten); +VMMR3DECL(int) PGMR3DbgReadGCPtr(PVM pVM, void *pvDst, RTGCPTR GCPtrSrc, size_t cb, uint32_t fFlags, size_t *pcbRead); +VMMR3DECL(int) PGMR3DbgWriteGCPtr(PVM pVM, RTGCPTR GCPtrDst, void const *pvSrc, size_t cb, uint32_t fFlags, size_t *pcbWritten); +VMMR3DECL(int) PGMR3DbgScanPhysical(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cbRange, RTGCPHYS GCPhysAlign, const uint8_t *pabNeedle, size_t cbNeedle, PRTGCPHYS pGCPhysHit); +VMMR3DECL(int) PGMR3DbgScanVirtual(PVM pVM, PVMCPU pVCpu, RTGCPTR GCPtr, RTGCPTR cbRange, RTGCPTR GCPtrAlign, const uint8_t *pabNeedle, size_t cbNeedle, PRTGCUINTPTR pGCPhysHit); +VMMR3_INT_DECL(int) PGMR3DumpHierarchyShw(PVM pVM, uint64_t cr3, uint32_t fFlags, uint64_t u64FirstAddr, uint64_t u64LastAddr, uint32_t cMaxDepth, PCDBGFINFOHLP pHlp); +VMMR3_INT_DECL(int) PGMR3DumpHierarchyGst(PVM pVM, uint64_t cr3, uint32_t fFlags, RTGCPTR FirstAddr, RTGCPTR LastAddr, uint32_t cMaxDepth, PCDBGFINFOHLP pHlp); + + +/** @name Page sharing + * @{ */ +VMMR3DECL(int) PGMR3SharedModuleRegister(PVM pVM, VBOXOSFAMILY enmGuestOS, char *pszModuleName, char *pszVersion, + RTGCPTR GCBaseAddr, uint32_t cbModule, + uint32_t cRegions, VMMDEVSHAREDREGIONDESC const *paRegions); +VMMR3DECL(int) PGMR3SharedModuleUnregister(PVM pVM, char *pszModuleName, char *pszVersion, + RTGCPTR GCBaseAddr, uint32_t cbModule); +VMMR3DECL(int) PGMR3SharedModuleCheckAll(PVM pVM); +VMMR3DECL(int) PGMR3SharedModuleGetPageState(PVM pVM, RTGCPTR GCPtrPage, bool *pfShared, uint64_t *pfPageFlags); +/** @} */ + +/** @} */ +#endif /* IN_RING3 */ + +RT_C_DECLS_END + +/** @} */ +#endif + diff --git a/include/VBox/vmm/rem.h b/include/VBox/vmm/rem.h new file mode 100644 index 00000000..79a18810 --- /dev/null +++ b/include/VBox/vmm/rem.h @@ -0,0 +1,106 @@ +/** @file + * REM - The Recompiled Execution Manager. + */ + +/* + * Copyright (C) 2006-2010 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_rem_h +#define ___VBox_vmm_rem_h + +#include <VBox/types.h> +#include <VBox/vmm/pgm.h> +#include <VBox/vmm/vmapi.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_rem The Recompiled Execution Manager API + * @{ + */ + +/** No pending interrupt. */ +#define REM_NO_PENDING_IRQ (~(uint32_t)0) + + +#if defined(IN_RING0) || defined(IN_RC) +VMMDECL(void) REMNotifyInvalidatePage(PVM pVM, RTGCPTR GCPtrPage); +VMMDECL(void) REMNotifyHandlerPhysicalRegister(PVM pVM, PGMPHYSHANDLERTYPE enmType, RTGCPHYS GCPhys, RTGCPHYS cb, bool fHasHCHandler); +VMMDECL(void) REMNotifyHandlerPhysicalDeregister(PVM pVM, PGMPHYSHANDLERTYPE enmType, RTGCPHYS GCPhys, RTGCPHYS cb, bool fHasHCHandler, bool fRestoreAsRAM); +VMMDECL(void) REMNotifyHandlerPhysicalModify(PVM pVM, PGMPHYSHANDLERTYPE enmType, RTGCPHYS GCPhysOld, RTGCPHYS GCPhysNew, RTGCPHYS cb, bool fHasHCHandler, bool fRestoreAsRAM); +#endif /* IN_RING0 || IN_RC */ +#ifdef IN_RC +VMMDECL(void) REMNotifyHandlerPhysicalFlushIfAlmostFull(PVM pVM, PVMCPU pVCpu); +#endif +VMMDECL(void) REMFlushTBs(PVM pVM); + + +#ifdef IN_RING3 +/** @defgroup grp_rem_r3 REM Host Context Ring 3 API + * @ingroup grp_rem + * @{ + */ +REMR3DECL(int) REMR3Init(PVM pVM); +REMR3DECL(int) REMR3InitFinalize(PVM pVM); +REMR3DECL(int) REMR3Term(PVM pVM); +REMR3DECL(void) REMR3Reset(PVM pVM); +REMR3DECL(int) REMR3Run(PVM pVM, PVMCPU pVCpu); +REMR3DECL(int) REMR3EmulateInstruction(PVM pVM, PVMCPU pVCpu); +REMR3DECL(int) REMR3Step(PVM pVM, PVMCPU pVCpu); +REMR3DECL(int) REMR3BreakpointSet(PVM pVM, RTGCUINTPTR Address); +REMR3DECL(int) REMR3BreakpointClear(PVM pVM, RTGCUINTPTR Address); +REMR3DECL(int) REMR3State(PVM pVM, PVMCPU pVCpu); +REMR3DECL(int) REMR3StateBack(PVM pVM, PVMCPU pVCpu); +REMR3DECL(void) REMR3StateUpdate(PVM pVM, PVMCPU pVCpu); +REMR3DECL(void) REMR3A20Set(PVM pVM, PVMCPU pVCpu, bool fEnable); +REMR3DECL(int) REMR3DisasEnableStepping(PVM pVM, bool fEnable); +REMR3DECL(void) REMR3ReplayHandlerNotifications(PVM pVM); +REMR3DECL(int) REMR3NotifyCodePageChanged(PVM pVM, PVMCPU pVCpu, RTGCPTR pvCodePage); +REMR3DECL(void) REMR3NotifyPhysRamRegister(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, unsigned fFlags); +/** @name Flags for REMR3NotifyPhysRamRegister. + * @{ */ +#define REM_NOTIFY_PHYS_RAM_FLAGS_RAM RT_BIT(16) +#define REM_NOTIFY_PHYS_RAM_FLAGS_MMIO2 RT_BIT(17) +/** @} */ +REMR3DECL(void) REMR3NotifyPhysRomRegister(PVM pVM, RTGCPHYS GCPhys, RTUINT cb, void *pvCopy, bool fShadow); +REMR3DECL(void) REMR3NotifyPhysRamDeregister(PVM pVM, RTGCPHYS GCPhys, RTUINT cb); +REMR3DECL(void) REMR3NotifyHandlerPhysicalRegister(PVM pVM, PGMPHYSHANDLERTYPE enmType, RTGCPHYS GCPhys, RTGCPHYS cb, bool fHasHCHandler); +REMR3DECL(void) REMR3NotifyHandlerPhysicalDeregister(PVM pVM, PGMPHYSHANDLERTYPE enmType, RTGCPHYS GCPhys, RTGCPHYS cb, bool fHasHCHandler, bool fRestoreAsRAM); +REMR3DECL(void) REMR3NotifyHandlerPhysicalModify(PVM pVM, PGMPHYSHANDLERTYPE enmType, RTGCPHYS GCPhysOld, RTGCPHYS GCPhysNew, RTGCPHYS cb, bool fHasHCHandler, bool fRestoreAsRAM); +REMR3DECL(void) REMR3NotifyPendingInterrupt(PVM pVM, PVMCPU pVCpu, uint8_t u8Interrupt); +REMR3DECL(uint32_t) REMR3QueryPendingInterrupt(PVM pVM, PVMCPU pVCpu); +REMR3DECL(void) REMR3NotifyInterruptSet(PVM pVM, PVMCPU pVCpu); +REMR3DECL(void) REMR3NotifyInterruptClear(PVM pVM, PVMCPU pVCpu); +REMR3DECL(void) REMR3NotifyTimerPending(PVM pVM, PVMCPU pVCpuDst); +REMR3DECL(void) REMR3NotifyDmaPending(PVM pVM); +REMR3DECL(void) REMR3NotifyQueuePending(PVM pVM); +REMR3DECL(void) REMR3NotifyFF(PVM pVM); +REMR3DECL(bool) REMR3IsPageAccessHandled(PVM pVM, RTGCPHYS GCPhys); +/** @} */ +#endif /* IN_RING3 */ + + +/** @} */ +RT_C_DECLS_END + + +#endif + diff --git a/include/VBox/vmm/selm.h b/include/VBox/vmm/selm.h new file mode 100644 index 00000000..763d0acf --- /dev/null +++ b/include/VBox/vmm/selm.h @@ -0,0 +1,123 @@ +/** @file + * SELM - The Selector Manager. + */ + +/* + * Copyright (C) 2006-2012 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_selm_h +#define ___VBox_vmm_selm_h + +#include <VBox/types.h> +#include <iprt/x86.h> +#include <VBox/dis.h> +#include <VBox/vmm/dbgfsel.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_selm The Selector Monitor(/Manager) API + * @{ + */ + +VMMDECL(RTSEL) SELMGetTrap8Selector(PVM pVM); +VMMDECL(void) SELMSetTrap8EIP(PVM pVM, uint32_t u32EIP); +VMMDECL(int) SELMGetRing1Stack(PVM pVM, uint32_t *pSS, PRTGCPTR32 pEsp); +VMMDECL(RTGCPTR) SELMGetGuestTSS(PVM pVM); +VMMDECL(RTSEL) SELMGetHyperCS(PVM pVM); +VMMDECL(RTSEL) SELMGetHyperCS64(PVM pVM); +VMMDECL(RTSEL) SELMGetHyperDS(PVM pVM); +VMMDECL(RTSEL) SELMGetHyperTSS(PVM pVM); +VMMDECL(RTSEL) SELMGetHyperTSSTrap08(PVM pVM); +VMMDECL(RTRCPTR) SELMGetHyperGDT(PVM pVM); +VMMDECL(int) SELMGetTSSInfo(PVM pVM, PVMCPU pVCpu, PRTGCUINTPTR pGCPtrTss, PRTGCUINTPTR pcbTss, bool *pfCanHaveIOBitmap); +VMMDECL(RTGCPTR) SELMToFlat(PVM pVM, DISSELREG SelReg, PCPUMCTXCORE pCtxCore, RTGCPTR Addr); +VMMDECL(RTGCPTR) SELMToFlatBySel(PVM pVM, RTSEL Sel, RTGCPTR Addr); +VMMDECL(void) SELMShadowCR3Changed(PVM pVM, PVMCPU pVCpu); + +/** Flags for SELMToFlatEx(). + * @{ */ +/** Don't check the RPL,DPL or CPL. */ +#define SELMTOFLAT_FLAGS_NO_PL RT_BIT(8) +/** Flags contains CPL information. */ +#define SELMTOFLAT_FLAGS_HAVE_CPL RT_BIT(9) +/** CPL is 3. */ +#define SELMTOFLAT_FLAGS_CPL3 3 +/** CPL is 2. */ +#define SELMTOFLAT_FLAGS_CPL2 2 +/** CPL is 1. */ +#define SELMTOFLAT_FLAGS_CPL1 1 +/** CPL is 0. */ +#define SELMTOFLAT_FLAGS_CPL0 0 +/** Get the CPL from the flags. */ +#define SELMTOFLAT_FLAGS_CPL(fFlags) ((fFlags) & X86_SEL_RPL) +/** Allow converting using Hypervisor GDT entries. */ +#define SELMTOFLAT_FLAGS_HYPER RT_BIT(10) +/** @} */ + +VMMDECL(int) SELMToFlatEx(PVMCPU pVCpu, DISSELREG SelReg, PCPUMCTXCORE pCtxCore, RTGCPTR Addr, uint32_t fFlags, + PRTGCPTR ppvGC); +VMMDECL(int) SELMToFlatBySelEx(PVMCPU pVCpu, X86EFLAGS eflags, RTSEL Sel, RTGCPTR Addr, uint32_t fFlags, + PRTGCPTR ppvGC, uint32_t *pcb); +VMMDECL(int) SELMValidateAndConvertCSAddr(PVMCPU pVCpu, X86EFLAGS eflags, RTSEL SelCPL, RTSEL SelCS, + PCPUMSELREG pSRegCS, RTGCPTR Addr, PRTGCPTR ppvFlat); +#ifdef VBOX_WITH_RAW_MODE +VMM_INT_DECL(void) SELMLoadHiddenSelectorReg(PVMCPU pVCpu, PCCPUMCTX pCtx, PCPUMSELREG pSReg); +#endif + + +#ifdef IN_RING3 +/** @defgroup grp_selm_r3 The Selector Monitor(/Manager) API + * @ingroup grp_selm + * @{ + */ +VMMR3DECL(int) SELMR3Init(PVM pVM); +VMMR3DECL(int) SELMR3InitFinalize(PVM pVM); +VMMR3DECL(void) SELMR3Relocate(PVM pVM); +VMMR3DECL(int) SELMR3Term(PVM pVM); +VMMR3DECL(void) SELMR3Reset(PVM pVM); +VMMR3DECL(VBOXSTRICTRC) SELMR3UpdateFromCPUM(PVM pVM, PVMCPU pVCpu); +VMMR3DECL(int) SELMR3SyncTSS(PVM pVM, PVMCPU pVCpu); +VMMR3DECL(int) SELMR3GetSelectorInfo(PVM pVM, PVMCPU pVCpu, RTSEL Sel, PDBGFSELINFO pSelInfo); +VMMR3DECL(int) SELMR3GetShadowSelectorInfo(PVM pVM, RTSEL Sel, PDBGFSELINFO pSelInfo); +VMMR3DECL(void) SELMR3DisableMonitoring(PVM pVM); +VMMR3DECL(void) SELMR3DumpDescriptor(X86DESC Desc, RTSEL Sel, const char *pszMsg); +VMMR3DECL(void) SELMR3DumpHyperGDT(PVM pVM); +VMMR3DECL(void) SELMR3DumpHyperLDT(PVM pVM); +VMMR3DECL(void) SELMR3DumpGuestGDT(PVM pVM); +VMMR3DECL(void) SELMR3DumpGuestLDT(PVM pVM); +VMMR3DECL(bool) SELMR3CheckTSS(PVM pVM); +VMMR3DECL(int) SELMR3DebugCheck(PVM pVM); +/** @def SELMR3_DEBUG_CHECK + * Invokes SELMR3DebugCheck in stricts builds. */ +# ifdef VBOX_STRICT +# define SELMR3_DEBUG_CHECK(pVM) SELMR3DebugCheck(pVM) +# else +# define SELMR3_DEBUG_CHECK(pVM) do { } while (0) +# endif +/** @} */ +#endif /* IN_RING3 */ + +/** @} */ +RT_C_DECLS_END + +#endif + diff --git a/include/VBox/vmm/ssm.h b/include/VBox/vmm/ssm.h new file mode 100644 index 00000000..427e0796 --- /dev/null +++ b/include/VBox/vmm/ssm.h @@ -0,0 +1,1265 @@ +/** @file + * SSM - The Save State Manager. + */ + +/* + * Copyright (C) 2006-2010 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_ssm_h +#define ___VBox_vmm_ssm_h + +#include <VBox/types.h> +#include <VBox/vmm/tm.h> +#include <VBox/vmm/vmapi.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_ssm The Saved State Manager API + * @{ + */ + +/** + * Determine the major version of the SSM version. If the major SSM version of two snapshots is + * different, the snapshots are incompatible. + */ +#define SSM_VERSION_MAJOR(ver) ((ver) & 0xffff0000) + +/** + * Determine the minor version of the SSM version. If the major SSM version of two snapshots is + * the same, the code must handle incompatibilies between minor version changes (e.g. use dummy + * values for non-existent fields). + */ +#define SSM_VERSION_MINOR(ver) ((ver) & 0x0000ffff) + +/** + * Determine if the major version changed between two SSM versions. + */ +#define SSM_VERSION_MAJOR_CHANGED(ver1,ver2) (SSM_VERSION_MAJOR(ver1) != SSM_VERSION_MAJOR(ver2)) + +/** The special value for the final pass. */ +#define SSM_PASS_FINAL UINT32_MAX + + +#ifdef IN_RING3 +/** @defgroup grp_ssm_r3 The SSM Host Context Ring-3 API + * @{ + */ + + +/** + * What to do after the save/load operation. + */ +typedef enum SSMAFTER +{ + /** Invalid. */ + SSMAFTER_INVALID = 0, + /** Will resume the loaded state. */ + SSMAFTER_RESUME, + /** Will destroy the VM after saving. */ + SSMAFTER_DESTROY, + /** Will continue execution after saving the VM. */ + SSMAFTER_CONTINUE, + /** Will teleport the VM. + * The source VM will be destroyed (then one saving), the destination VM + * will continue execution. */ + SSMAFTER_TELEPORT, + /** Will debug the saved state. + * This is used to drop some of the stricter consitentcy checks so it'll + * load fine in the debugger or animator. */ + SSMAFTER_DEBUG_IT, + /** The file was opened using SSMR3Open() and we have no idea what the plan is. */ + SSMAFTER_OPENED +} SSMAFTER; + + +/** Pointer to a structure field description. */ +typedef struct SSMFIELD *PSSMFIELD; +/** Pointer to a const structure field description. */ +typedef const struct SSMFIELD *PCSSMFIELD; + +/** + * SSMFIELD Get/Put callback function. + * + * This is call for getting and putting the field it is associated with. It's + * up to the callback to work the saved state correctly. + * + * @returns VBox status code. + * + * @param pSSM The saved state handle. + * @param pField The field that is being processed. + * @param pvStruct Pointer to the structure. + * @param fFlags SSMSTRUCT_FLAGS_XXX. + * @param fGetOrPut True if getting, false if putting. + * @param pvUser The user argument specified to SSMR3GetStructEx or + * SSMR3PutStructEx. + */ +typedef DECLCALLBACK(int) FNSSMFIELDGETPUT(PSSMHANDLE pSSM, const struct SSMFIELD *pField, void *pvStruct, + uint32_t fFlags, bool fGetOrPut, void *pvUser); +/** Pointer to a SSMFIELD Get/Put callback. */ +typedef FNSSMFIELDGETPUT *PFNSSMFIELDGETPUT; + +/** + * SSM field transformers. + * + * These are stored in the SSMFIELD::pfnGetPutOrTransformer and must therefore + * have values outside the valid pointer range. + */ +typedef enum SSMFIELDTRANS +{ + /** Invalid. */ + SSMFIELDTRANS_INVALID = 0, + /** No transformation. */ + SSMFIELDTRANS_NO_TRANSFORMATION, + /** Guest context (GC) physical address. */ + SSMFIELDTRANS_GCPHYS, + /** Guest context (GC) virtual address. */ + SSMFIELDTRANS_GCPTR, + /** Raw-mode context (RC) virtual address. */ + SSMFIELDTRANS_RCPTR, + /** Array of raw-mode context (RC) virtual addresses. */ + SSMFIELDTRANS_RCPTR_ARRAY, + /** Host context (HC) virtual address used as a NULL indicator. See + * SSMFIELD_ENTRY_HCPTR_NI. */ + SSMFIELDTRANS_HCPTR_NI, + /** Array of SSMFIELDTRANS_HCPTR_NI. */ + SSMFIELDTRANS_HCPTR_NI_ARRAY, + /** Host context (HC) virtual address used to hold a unsigned 32-bit value. */ + SSMFIELDTRANS_HCPTR_HACK_U32, + /** Load a 32-bit unsigned filed from the state and zero extend it into a 64-bit + * structure member. */ + SSMFIELDTRANS_U32_ZX_U64, + + /** Ignorable field. See SSMFIELD_ENTRY_IGNORE. */ + SSMFIELDTRANS_IGNORE, + /** Ignorable guest context (GC) physical address. */ + SSMFIELDTRANS_IGN_GCPHYS, + /** Ignorable guest context (GC) virtual address. */ + SSMFIELDTRANS_IGN_GCPTR, + /** Ignorable raw-mode context (RC) virtual address. */ + SSMFIELDTRANS_IGN_RCPTR, + /** Ignorable host context (HC) virtual address. */ + SSMFIELDTRANS_IGN_HCPTR, + + /** Old field. + * Save as zeros and skip on restore (nowhere to restore it any longer). */ + SSMFIELDTRANS_OLD, + /** Old guest context (GC) physical address. */ + SSMFIELDTRANS_OLD_GCPHYS, + /** Old guest context (GC) virtual address. */ + SSMFIELDTRANS_OLD_GCPTR, + /** Old raw-mode context (RC) virtual address. */ + SSMFIELDTRANS_OLD_RCPTR, + /** Old host context (HC) virtual address. */ + SSMFIELDTRANS_OLD_HCPTR, + /** Old host context specific padding. + * The lower word is the size of 32-bit hosts, the upper for 64-bit hosts. */ + SSMFIELDTRANS_OLD_PAD_HC, + /** Old padding specific to the 32-bit Microsoft C Compiler. */ + SSMFIELDTRANS_OLD_PAD_MSC32, + + /** Padding that differs between 32-bit and 64-bit hosts. + * The first byte of SSMFIELD::cb contains the size for 32-bit hosts. + * The second byte of SSMFIELD::cb contains the size for 64-bit hosts. + * The upper word of SSMFIELD::cb contains the actual field size. + */ + SSMFIELDTRANS_PAD_HC, + /** Padding for 32-bit hosts only. + * SSMFIELD::cb has the same format as for SSMFIELDTRANS_PAD_HC. */ + SSMFIELDTRANS_PAD_HC32, + /** Padding for 64-bit hosts only. + * SSMFIELD::cb has the same format as for SSMFIELDTRANS_PAD_HC. */ + SSMFIELDTRANS_PAD_HC64, + /** Automatic compiler padding that may differ between 32-bit and + * 64-bit hosts. SSMFIELD::cb has the same format as for + * SSMFIELDTRANS_PAD_HC. */ + SSMFIELDTRANS_PAD_HC_AUTO, + /** Automatic compiler padding specific to the 32-bit Microsoft C + * compiler. + * SSMFIELD::cb has the same format as for SSMFIELDTRANS_PAD_HC. */ + SSMFIELDTRANS_PAD_MSC32_AUTO +} SSMFIELDTRANS; + +/** Tests if it's a padding field with the special SSMFIELD::cb format. + * @returns true / false. + * @param pfn The SSMFIELD::pfnGetPutOrTransformer value. + */ +#define SSMFIELDTRANS_IS_PADDING(pfn) \ + ( (uintptr_t)(pfn) >= SSMFIELDTRANS_PAD_HC && (uintptr_t)(pfn) <= SSMFIELDTRANS_PAD_MSC32_AUTO ) + +/** Tests if it's an entry for an old field. + * + * @returns true / false. + * @param pfn The SSMFIELD::pfnGetPutOrTransformer value. + */ +#define SSMFIELDTRANS_IS_OLD(pfn) \ + ( (uintptr_t)(pfn) >= SSMFIELDTRANS_OLD && (uintptr_t)(pfn) <= SSMFIELDTRANS_OLD_PAD_MSC32 ) + +/** + * A structure field description. + */ +typedef struct SSMFIELD +{ + /** Getter and putter callback or transformer index. */ + PFNSSMFIELDGETPUT pfnGetPutOrTransformer; + /** Field offset into the structure. */ + uint32_t off; + /** The size of the field. */ + uint32_t cb; + /** Field name. */ + const char *pszName; +} SSMFIELD; + +/** Emit a SSMFIELD array entry. + * @internal */ +#define SSMFIELD_ENTRY_INT(Name, off, cb, enmTransformer) \ + { (PFNSSMFIELDGETPUT)(uintptr_t)(enmTransformer), (off), (cb), Name } +/** Emit a SSMFIELD array entry. + * @internal */ +#define SSMFIELD_ENTRY_TF_INT(Type, Field, enmTransformer) \ + SSMFIELD_ENTRY_INT(#Type "::" #Field, RT_OFFSETOF(Type, Field), RT_SIZEOFMEMB(Type, Field), enmTransformer) +/** Emit a SSMFIELD array entry for an old field. + * @internal */ +#define SSMFIELD_ENTRY_OLD_INT(Field, cb, enmTransformer) \ + SSMFIELD_ENTRY_INT("old::" #Field, UINT32_MAX / 2, (cb), enmTransformer) +/** Emit a SSMFIELD array entry for an alignment padding. + * @internal */ +#define SSMFIELD_ENTRY_PAD_INT(Type, Field, cb32, cb64, enmTransformer) \ + SSMFIELD_ENTRY_INT(#Type "::" #Field, RT_OFFSETOF(Type, Field), \ + (RT_SIZEOFMEMB(Type, Field) << 16) | (cb32) | ((cb64) << 8), enmTransformer) +/** Emit a SSMFIELD array entry for an alignment padding. + * @internal */ +#define SSMFIELD_ENTRY_PAD_OTHER_INT(Type, Field, cb32, cb64, enmTransformer) \ + SSMFIELD_ENTRY_INT(#Type "::" #Field, UINT32_MAX / 2, 0 | (cb32) | ((cb64) << 8), enmTransformer) + +/** Emit a SSMFIELD array entry. */ +#define SSMFIELD_ENTRY(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_NO_TRANSFORMATION) +/** Emit a SSMFIELD array entry for a custom made field. This is intended + * for working around bitfields in old structures. */ +#define SSMFIELD_ENTRY_CUSTOM(Field, off, cb) SSMFIELD_ENTRY_INT("custom::" #Field, off, cb, SSMFIELDTRANS_NO_TRANSFORMATION) +/** Emit a SSMFIELD array entry for a RTGCPHYS type. */ +#define SSMFIELD_ENTRY_GCPHYS(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_GCPHYS) +/** Emit a SSMFIELD array entry for a RTGCPTR type. */ +#define SSMFIELD_ENTRY_GCPTR(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_GCPTR) +/** Emit a SSMFIELD array entry for a raw-mode context pointer. */ +#define SSMFIELD_ENTRY_RCPTR(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_RCPTR) +/** Emit a SSMFIELD array entry for a raw-mode context pointer. */ +#define SSMFIELD_ENTRY_RCPTR_ARRAY(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_RCPTR_ARRAY) +/** Emit a SSMFIELD array entry for a ring-0 or ring-3 pointer type that is only + * of interest as a NULL indicator. + * + * This is always restored as a 0 (NULL) or 1 value. When + * SSMSTRUCT_FLAGS_DONT_IGNORE is set, the pointer will be saved in its + * entirety, when clear it will be saved as a boolean. */ +#define SSMFIELD_ENTRY_HCPTR_NI(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_HCPTR_NI) +/** Same as SSMFIELD_ENTRY_HCPTR_NI, except it's an array of the buggers. */ +#define SSMFIELD_ENTRY_HCPTR_NI_ARRAY(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_HCPTR_NI_ARRAY) +/** Emit a SSMFIELD array entry for a ring-0 or ring-3 pointer type that has + * been hacked such that it will never exceed 32-bit. No sign extending. */ +#define SSMFIELD_ENTRY_HCPTR_HACK_U32(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_HCPTR_HACK_U32) +/** Emit a SSMFIELD array entry for loading a 32-bit field into a 64-bit + * structure member, zero extending the value. */ +#define SSMFIELD_ENTRY_U32_ZX_U64(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_U32_ZX_U64) + +/** Emit a SSMFIELD array entry for a field that can be ignored. + * It is stored as zeros if SSMSTRUCT_FLAGS_DONT_IGNORE is specified to + * SSMR3PutStructEx. The member is never touched upon restore. */ +#define SSMFIELD_ENTRY_IGNORE(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_IGNORE) +/** Emit a SSMFIELD array entry for an ignorable RTGCPHYS type. */ +#define SSMFIELD_ENTRY_IGN_GCPHYS(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_IGN_GCPHYS) +/** Emit a SSMFIELD array entry for an ignorable RTGCPHYS type. */ +#define SSMFIELD_ENTRY_IGN_GCPTR(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_IGN_GCPTR) +/** Emit a SSMFIELD array entry for an ignorable raw-mode context pointer. */ +#define SSMFIELD_ENTRY_IGN_RCPTR(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_IGN_RCPTR) +/** Emit a SSMFIELD array entry for an ignorable ring-3 or/and ring-0 pointer. */ +#define SSMFIELD_ENTRY_IGN_HCPTR(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_IGN_HCPTR) + +/** Emit a SSMFIELD array entry for an old field that should be ignored now. + * It is stored as zeros and skipped on load. */ +#define SSMFIELD_ENTRY_OLD(Field, cb) SSMFIELD_ENTRY_OLD_INT(Field, cb, SSMFIELDTRANS_OLD) +/** Same as SSMFIELD_ENTRY_IGN_GCPHYS, except there is no structure field. */ +#define SSMFIELD_ENTRY_OLD_GCPHYS(Field) SSMFIELD_ENTRY_OLD_INT(Field, sizeof(RTGCPHYS), SSMFIELDTRANS_OLD_GCPHYS) +/** Same as SSMFIELD_ENTRY_IGN_GCPTR, except there is no structure field. */ +#define SSMFIELD_ENTRY_OLD_GCPTR(Field) SSMFIELD_ENTRY_OLD_INT(Field, sizeof(RTGCPTR), SSMFIELDTRANS_OLD_GCPTR) +/** Same as SSMFIELD_ENTRY_IGN_RCPTR, except there is no structure field. */ +#define SSMFIELD_ENTRY_OLD_RCPTR(Field) SSMFIELD_ENTRY_OLD_INT(Field, sizeof(RTRCPTR), SSMFIELDTRANS_OLD_RCPTR) +/** Same as SSMFIELD_ENTRY_IGN_HCPTR, except there is no structure field. */ +#define SSMFIELD_ENTRY_OLD_HCPTR(Field) SSMFIELD_ENTRY_OLD_INT(Field, sizeof(RTHCPTR), SSMFIELDTRANS_OLD_HCPTR) +/** Same as SSMFIELD_ENTRY_PAD_HC, except there is no structure field. */ +#define SSMFIELD_ENTRY_OLD_PAD_HC(Field, cb32, cb64) \ + SSMFIELD_ENTRY_OLD_INT(Field, RT_MAKE_U32((cb32), (cb64)), SSMFIELDTRANS_OLD_PAD_HC) +/** Same as SSMFIELD_ENTRY_PAD_HC64, except there is no structure field. */ +#define SSMFIELD_ENTRY_OLD_PAD_HC64(Field, cb) SSMFIELD_ENTRY_OLD_PAD_HC(Field, 0, cb) +/** Same as SSMFIELD_ENTRY_PAD_HC32, except there is no structure field. */ +#define SSMFIELD_ENTRY_OLD_PAD_HC32(Field, cb) SSMFIELD_ENTRY_OLD_PAD_HC(Field, cb, 0) +/** Same as SSMFIELD_ENTRY_PAD_HC, except there is no structure field. */ +#define SSMFIELD_ENTRY_OLD_PAD_MSC32(Field, cb) SSMFIELD_ENTRY_OLD_INT(Field, cb, SSMFIELDTRANS_OLD_PAD_MSC32) + +/** Emit a SSMFIELD array entry for a padding that differs in size between + * 64-bit and 32-bit hosts. */ +#define SSMFIELD_ENTRY_PAD_HC(Type, Field, cb32, cb64) SSMFIELD_ENTRY_PAD_INT( Type, Field, cb32, cb64, SSMFIELDTRANS_PAD_HC) +/** Emit a SSMFIELD array entry for a padding that is exclusive to 64-bit hosts. */ +#if HC_ARCH_BITS == 64 +# define SSMFIELD_ENTRY_PAD_HC64(Type, Field, cb) SSMFIELD_ENTRY_PAD_INT( Type, Field, 0, cb, SSMFIELDTRANS_PAD_HC64) +#else +# define SSMFIELD_ENTRY_PAD_HC64(Type, Field, cb) SSMFIELD_ENTRY_PAD_OTHER_INT(Type, Field, 0, cb, SSMFIELDTRANS_PAD_HC64) +#endif +/** Emit a SSMFIELD array entry for a 32-bit padding for on 64-bits hosts. */ +#if HC_ARCH_BITS == 32 +# define SSMFIELD_ENTRY_PAD_HC32(Type, Field, cb) SSMFIELD_ENTRY_PAD_INT( Type, Field, cb, 0, SSMFIELDTRANS_PAD_HC32) +#else +# define SSMFIELD_ENTRY_PAD_HC32(Type, Field, cb) SSMFIELD_ENTRY_PAD_OTHER_INT(Type, Field, cb, 0, SSMFIELDTRANS_PAD_HC32) +#endif +/** Emit a SSMFIELD array entry for an automatic compiler padding that may + * differ in size between 64-bit and 32-bit hosts. */ +#if HC_ARCH_BITS == 64 +# define SSMFIELD_ENTRY_PAD_HC_AUTO(cb32, cb64) \ + { \ + (PFNSSMFIELDGETPUT)(uintptr_t)(SSMFIELDTRANS_PAD_HC_AUTO), \ + UINT32_MAX / 2, (cb64 << 16) | (cb32) | ((cb64) << 8), "<compiler-padding>" \ + } +#else +# define SSMFIELD_ENTRY_PAD_HC_AUTO(cb32, cb64) \ + { \ + (PFNSSMFIELDGETPUT)(uintptr_t)(SSMFIELDTRANS_PAD_HC_AUTO), \ + UINT32_MAX / 2, (cb32 << 16) | (cb32) | ((cb64) << 8), "<compiler-padding>" \ + } +#endif +/** Emit a SSMFIELD array entry for an automatic compiler padding that is unique + * to the 32-bit microsoft compiler. This is usually used together with + * SSMFIELD_ENTRY_PAD_HC*. */ +#if HC_ARCH_BITS == 32 && defined(_MSC_VER) +# define SSMFIELD_ENTRY_PAD_MSC32_AUTO(cb) \ + { \ + (PFNSSMFIELDGETPUT)(uintptr_t)(SSMFIELDTRANS_PAD_MSC32_AUTO), \ + UINT32_MAX / 2, ((cb) << 16) | (cb), "<msc32-padding>" \ + } +#else +# define SSMFIELD_ENTRY_PAD_MSC32_AUTO(cb) \ + { \ + (PFNSSMFIELDGETPUT)(uintptr_t)(SSMFIELDTRANS_PAD_MSC32_AUTO), \ + UINT32_MAX / 2, (cb), "<msc32-padding>" \ + } +#endif + +/** Emit a SSMFIELD array entry for a field with a custom callback. */ +#define SSMFIELD_ENTRY_CALLBACK(Type, Field, pfnGetPut) \ + { (pfnGetPut), RT_OFFSETOF(Type, Field), RT_SIZEOFMEMB(Type, Field), #Type "::" #Field } +/** Emit the terminating entry of a SSMFIELD array. */ +#define SSMFIELD_ENTRY_TERM() { (PFNSSMFIELDGETPUT)(uintptr_t)SSMFIELDTRANS_INVALID, UINT32_MAX, UINT32_MAX, NULL } + + +/** @name SSMR3GetStructEx and SSMR3PutStructEx flags. + * @{ */ +/** The field descriptors must exactly cover the entire struct, A to Z. */ +#define SSMSTRUCT_FLAGS_FULL_STRUCT RT_BIT_32(0) +/** No start and end markers, just the raw bits. */ +#define SSMSTRUCT_FLAGS_NO_MARKERS RT_BIT_32(1) +/** Do not ignore any ignorable fields. */ +#define SSMSTRUCT_FLAGS_DONT_IGNORE RT_BIT_32(2) +/** Saved using SSMR3PutMem, don't be too strict. */ +#define SSMSTRUCT_FLAGS_SAVED_AS_MEM RT_BIT_32(3) +/** Band-aid for old SSMR3PutMem/SSMR3GetMem of structurs with host pointers. */ +#define SSMSTRUCT_FLAGS_MEM_BAND_AID ( SSMSTRUCT_FLAGS_DONT_IGNORE | SSMSTRUCT_FLAGS_FULL_STRUCT \ + | SSMSTRUCT_FLAGS_NO_MARKERS | SSMSTRUCT_FLAGS_SAVED_AS_MEM) +/** Band-aid for old SSMR3PutMem/SSMR3GetMem of structurs with host + * pointers, with relaxed checks. */ +#define SSMSTRUCT_FLAGS_MEM_BAND_AID_RELAXED ( SSMSTRUCT_FLAGS_DONT_IGNORE \ + | SSMSTRUCT_FLAGS_NO_MARKERS | SSMSTRUCT_FLAGS_SAVED_AS_MEM) +/** Mask of the valid bits. */ +#define SSMSTRUCT_FLAGS_VALID_MASK UINT32_C(0x0000000f) +/** @} */ + + +/** The PDM Device callback variants. + * @{ + */ + +/** + * Prepare state live save operation. + * + * @returns VBox status code. + * @param pDevIns Device instance of the device which registered the data unit. + * @param pSSM SSM operation handle. + * @thread Any. + */ +typedef DECLCALLBACK(int) FNSSMDEVLIVEPREP(PPDMDEVINS pDevIns, PSSMHANDLE pSSM); +/** Pointer to a FNSSMDEVLIVEPREP() function. */ +typedef FNSSMDEVLIVEPREP *PFNSSMDEVLIVEPREP; + +/** + * Execute state live save operation. + * + * This will be called repeatedly until all units vote that the live phase has + * been concluded. + * + * @returns VBox status code. + * @param pDevIns Device instance of the device which registered the data unit. + * @param pSSM SSM operation handle. + * @param uPass The pass. + * @thread Any. + */ +typedef DECLCALLBACK(int) FNSSMDEVLIVEEXEC(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass); +/** Pointer to a FNSSMDEVLIVEEXEC() function. */ +typedef FNSSMDEVLIVEEXEC *PFNSSMDEVLIVEEXEC; + +/** + * Vote on whether the live part of the saving has been concluded. + * + * The vote stops once a unit has vetoed the decision, so don't rely upon this + * being called every time. + * + * @returns VBox status code. + * @retval VINF_SUCCESS if done. + * @retval VINF_SSM_VOTE_FOR_ANOTHER_PASS if another pass is needed. + * @retval VINF_SSM_VOTE_DONE_DONT_CALL_AGAIN if the live saving of the unit is + * done and there is not need calling it again before the final pass. + * @retval VERR_SSM_VOTE_FOR_GIVING_UP if its time to give up. + * + * @param pDevIns Device instance of the device which registered the data unit. + * @param pSSM SSM operation handle. + * @param uPass The data pass. + * @thread Any. + */ +typedef DECLCALLBACK(int) FNSSMDEVLIVEVOTE(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass); +/** Pointer to a FNSSMDEVLIVEVOTE() function. */ +typedef FNSSMDEVLIVEVOTE *PFNSSMDEVLIVEVOTE; + +/** + * Prepare state save operation. + * + * @returns VBox status code. + * @param pDevIns Device instance of the device which registered the data unit. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACK(int) FNSSMDEVSAVEPREP(PPDMDEVINS pDevIns, PSSMHANDLE pSSM); +/** Pointer to a FNSSMDEVSAVEPREP() function. */ +typedef FNSSMDEVSAVEPREP *PFNSSMDEVSAVEPREP; + +/** + * Execute state save operation. + * + * @returns VBox status code. + * @param pDevIns Device instance of the device which registered the data unit. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACK(int) FNSSMDEVSAVEEXEC(PPDMDEVINS pDevIns, PSSMHANDLE pSSM); +/** Pointer to a FNSSMDEVSAVEEXEC() function. */ +typedef FNSSMDEVSAVEEXEC *PFNSSMDEVSAVEEXEC; + +/** + * Done state save operation. + * + * @returns VBox status code. + * @param pDevIns Device instance of the device which registered the data unit. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACK(int) FNSSMDEVSAVEDONE(PPDMDEVINS pDevIns, PSSMHANDLE pSSM); +/** Pointer to a FNSSMDEVSAVEDONE() function. */ +typedef FNSSMDEVSAVEDONE *PFNSSMDEVSAVEDONE; + +/** + * Prepare state load operation. + * + * @returns VBox status code. + * @param pDevIns Device instance of the device which registered the data unit. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACK(int) FNSSMDEVLOADPREP(PPDMDEVINS pDevIns, PSSMHANDLE pSSM); +/** Pointer to a FNSSMDEVLOADPREP() function. */ +typedef FNSSMDEVLOADPREP *PFNSSMDEVLOADPREP; + +/** + * Execute state load operation. + * + * @returns VBox status code. + * @param pDevIns Device instance of the device which registered the data unit. + * @param pSSM SSM operation handle. + * @param uVersion Data layout version. + * @param uPass The pass. This is always SSM_PASS_FINAL for units + * that doesn't specify a pfnSaveLive callback. + */ +typedef DECLCALLBACK(int) FNSSMDEVLOADEXEC(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass); +/** Pointer to a FNSSMDEVLOADEXEC() function. */ +typedef FNSSMDEVLOADEXEC *PFNSSMDEVLOADEXEC; + +/** + * Done state load operation. + * + * @returns VBox load code. + * @param pDevIns Device instance of the device which registered the data unit. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACK(int) FNSSMDEVLOADDONE(PPDMDEVINS pDevIns, PSSMHANDLE pSSM); +/** Pointer to a FNSSMDEVLOADDONE() function. */ +typedef FNSSMDEVLOADDONE *PFNSSMDEVLOADDONE; + +/** @} */ + + +/** The PDM USB device callback variants. + * @{ + */ + +/** + * Prepare state live save operation. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance of the USB device which + * registered the data unit. + * @param pSSM SSM operation handle. + * @thread Any. + */ +typedef DECLCALLBACK(int) FNSSMUSBLIVEPREP(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM); +/** Pointer to a FNSSMUSBLIVEPREP() function. */ +typedef FNSSMUSBLIVEPREP *PFNSSMUSBLIVEPREP; + +/** + * Execute state live save operation. + * + * This will be called repeatedly until all units vote that the live phase has + * been concluded. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance of the USB device which + * registered the data unit. + * @param pSSM SSM operation handle. + * @param uPass The pass. + * @thread Any. + */ +typedef DECLCALLBACK(int) FNSSMUSBLIVEEXEC(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM, uint32_t uPass); +/** Pointer to a FNSSMUSBLIVEEXEC() function. */ +typedef FNSSMUSBLIVEEXEC *PFNSSMUSBLIVEEXEC; + +/** + * Vote on whether the live part of the saving has been concluded. + * + * The vote stops once a unit has vetoed the decision, so don't rely upon this + * being called every time. + * + * @returns VBox status code. + * @retval VINF_SUCCESS if done. + * @retval VINF_SSM_VOTE_FOR_ANOTHER_PASS if another pass is needed. + * @retval VINF_SSM_VOTE_DONE_DONT_CALL_AGAIN if the live saving of the unit is + * done and there is not need calling it again before the final pass. + * @retval VERR_SSM_VOTE_FOR_GIVING_UP if its time to give up. + * + * @param pUsbIns The USB device instance of the USB device which + * registered the data unit. + * @param pSSM SSM operation handle. + * @param uPass The data pass. + * @thread Any. + */ +typedef DECLCALLBACK(int) FNSSMUSBLIVEVOTE(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM, uint32_t uPass); +/** Pointer to a FNSSMUSBLIVEVOTE() function. */ +typedef FNSSMUSBLIVEVOTE *PFNSSMUSBLIVEVOTE; + +/** + * Prepare state save operation. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance of the USB device which + * registered the data unit. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACK(int) FNSSMUSBSAVEPREP(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM); +/** Pointer to a FNSSMUSBSAVEPREP() function. */ +typedef FNSSMUSBSAVEPREP *PFNSSMUSBSAVEPREP; + +/** + * Execute state save operation. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance of the USB device which + * registered the data unit. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACK(int) FNSSMUSBSAVEEXEC(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM); +/** Pointer to a FNSSMUSBSAVEEXEC() function. */ +typedef FNSSMUSBSAVEEXEC *PFNSSMUSBSAVEEXEC; + +/** + * Done state save operation. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance of the USB device which + * registered the data unit. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACK(int) FNSSMUSBSAVEDONE(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM); +/** Pointer to a FNSSMUSBSAVEDONE() function. */ +typedef FNSSMUSBSAVEDONE *PFNSSMUSBSAVEDONE; + +/** + * Prepare state load operation. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance of the USB device which + * registered the data unit. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACK(int) FNSSMUSBLOADPREP(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM); +/** Pointer to a FNSSMUSBLOADPREP() function. */ +typedef FNSSMUSBLOADPREP *PFNSSMUSBLOADPREP; + +/** + * Execute state load operation. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance of the USB device which + * registered the data unit. + * @param pSSM SSM operation handle. + * @param uVersion Data layout version. + * @param uPass The pass. This is always SSM_PASS_FINAL for units + * that doesn't specify a pfnSaveLive callback. + */ +typedef DECLCALLBACK(int) FNSSMUSBLOADEXEC(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass); +/** Pointer to a FNSSMUSBLOADEXEC() function. */ +typedef FNSSMUSBLOADEXEC *PFNSSMUSBLOADEXEC; + +/** + * Done state load operation. + * + * @returns VBox load code. + * @param pUsbIns The USB device instance of the USB device which + * registered the data unit. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACK(int) FNSSMUSBLOADDONE(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM); +/** Pointer to a FNSSMUSBLOADDONE() function. */ +typedef FNSSMUSBLOADDONE *PFNSSMUSBLOADDONE; + +/** @} */ + + +/** The PDM Driver callback variants. + * @{ + */ + +/** + * Prepare state live save operation. + * + * @returns VBox status code. + * @param pDrvIns Driver instance of the driver which registered the + * data unit. + * @param pSSM SSM operation handle. + * @thread Any. + */ +typedef DECLCALLBACK(int) FNSSMDRVLIVEPREP(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM); +/** Pointer to a FNSSMDRVLIVEPREP() function. */ +typedef FNSSMDRVLIVEPREP *PFNSSMDRVLIVEPREP; + +/** + * Execute state live save operation. + * + * This will be called repeatedly until all units vote that the live phase has + * been concluded. + * + * @returns VBox status code. + * @param pDrvIns Driver instance of the driver which registered the + * data unit. + * @param pSSM SSM operation handle. + * @param uPass The data pass. + * @thread Any. + */ +typedef DECLCALLBACK(int) FNSSMDRVLIVEEXEC(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM, uint32_t uPass); +/** Pointer to a FNSSMDRVLIVEEXEC() function. */ +typedef FNSSMDRVLIVEEXEC *PFNSSMDRVLIVEEXEC; + +/** + * Vote on whether the live part of the saving has been concluded. + * + * The vote stops once a unit has vetoed the decision, so don't rely upon this + * being called every time. + * + * @returns VBox status code. + * @retval VINF_SUCCESS if done. + * @retval VINF_SSM_VOTE_FOR_ANOTHER_PASS if another pass is needed. + * @retval VINF_SSM_VOTE_DONE_DONT_CALL_AGAIN if the live saving of the unit is + * done and there is not need calling it again before the final pass. + * @retval VERR_SSM_VOTE_FOR_GIVING_UP if its time to give up. + * + * @param pDrvIns Driver instance of the driver which registered the + * data unit. + * @param pSSM SSM operation handle. + * @param uPass The data pass. + * @thread Any. + */ +typedef DECLCALLBACK(int) FNSSMDRVLIVEVOTE(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM, uint32_t uPass); +/** Pointer to a FNSSMDRVLIVEVOTE() function. */ +typedef FNSSMDRVLIVEVOTE *PFNSSMDRVLIVEVOTE; + + +/** + * Prepare state save operation. + * + * @returns VBox status code. + * @param pDrvIns Driver instance of the driver which registered the data unit. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACK(int) FNSSMDRVSAVEPREP(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM); +/** Pointer to a FNSSMDRVSAVEPREP() function. */ +typedef FNSSMDRVSAVEPREP *PFNSSMDRVSAVEPREP; + +/** + * Execute state save operation. + * + * @returns VBox status code. + * @param pDrvIns Driver instance of the driver which registered the data unit. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACK(int) FNSSMDRVSAVEEXEC(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM); +/** Pointer to a FNSSMDRVSAVEEXEC() function. */ +typedef FNSSMDRVSAVEEXEC *PFNSSMDRVSAVEEXEC; + +/** + * Done state save operation. + * + * @returns VBox status code. + * @param pDrvIns Driver instance of the driver which registered the data unit. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACK(int) FNSSMDRVSAVEDONE(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM); +/** Pointer to a FNSSMDRVSAVEDONE() function. */ +typedef FNSSMDRVSAVEDONE *PFNSSMDRVSAVEDONE; + +/** + * Prepare state load operation. + * + * @returns VBox status code. + * @param pDrvIns Driver instance of the driver which registered the data unit. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACK(int) FNSSMDRVLOADPREP(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM); +/** Pointer to a FNSSMDRVLOADPREP() function. */ +typedef FNSSMDRVLOADPREP *PFNSSMDRVLOADPREP; + +/** + * Execute state load operation. + * + * @returns VBox status code. + * @param pDrvIns Driver instance of the driver which registered the data unit. + * @param pSSM SSM operation handle. + * @param uVersion Data layout version. + * @param uPass The pass. This is always SSM_PASS_FINAL for units + * that doesn't specify a pfnSaveLive callback. + */ +typedef DECLCALLBACK(int) FNSSMDRVLOADEXEC(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass); +/** Pointer to a FNSSMDRVLOADEXEC() function. */ +typedef FNSSMDRVLOADEXEC *PFNSSMDRVLOADEXEC; + +/** + * Done state load operation. + * + * @returns VBox load code. + * @param pDrvIns Driver instance of the driver which registered the data unit. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACK(int) FNSSMDRVLOADDONE(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM); +/** Pointer to a FNSSMDRVLOADDONE() function. */ +typedef FNSSMDRVLOADDONE *PFNSSMDRVLOADDONE; + +/** @} */ + + +/** The internal callback variants. + * @{ + */ + + +/** + * Prepare state live save operation. + * + * @returns VBox status code. + * @param pVM VM Handle. + * @param pSSM SSM operation handle. + * @thread Any. + */ +typedef DECLCALLBACK(int) FNSSMINTLIVEPREP(PVM pVM, PSSMHANDLE pSSM); +/** Pointer to a FNSSMINTLIVEPREP() function. */ +typedef FNSSMINTLIVEPREP *PFNSSMINTLIVEPREP; + +/** + * Execute state live save operation. + * + * This will be called repeatedly until all units vote that the live phase has + * been concluded. + * + * @returns VBox status code. + * @param pVM VM Handle. + * @param pSSM SSM operation handle. + * @param uPass The data pass. + * @thread Any. + */ +typedef DECLCALLBACK(int) FNSSMINTLIVEEXEC(PVM pVM, PSSMHANDLE pSSM, uint32_t uPass); +/** Pointer to a FNSSMINTLIVEEXEC() function. */ +typedef FNSSMINTLIVEEXEC *PFNSSMINTLIVEEXEC; + +/** + * Vote on whether the live part of the saving has been concluded. + * + * The vote stops once a unit has vetoed the decision, so don't rely upon this + * being called every time. + * + * @returns VBox status code. + * @retval VINF_SUCCESS if done. + * @retval VINF_SSM_VOTE_FOR_ANOTHER_PASS if another pass is needed. + * @retval VINF_SSM_VOTE_DONE_DONT_CALL_AGAIN if the live saving of the unit is + * done and there is not need calling it again before the final pass. + * @retval VERR_SSM_VOTE_FOR_GIVING_UP if its time to give up. + * + * @param pVM VM Handle. + * @param pSSM SSM operation handle. + * @param uPass The data pass. + * @thread Any. + */ +typedef DECLCALLBACK(int) FNSSMINTLIVEVOTE(PVM pVM, PSSMHANDLE pSSM, uint32_t uPass); +/** Pointer to a FNSSMINTLIVEVOTE() function. */ +typedef FNSSMINTLIVEVOTE *PFNSSMINTLIVEVOTE; + +/** + * Prepare state save operation. + * + * @returns VBox status code. + * @param pVM VM Handle. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACK(int) FNSSMINTSAVEPREP(PVM pVM, PSSMHANDLE pSSM); +/** Pointer to a FNSSMINTSAVEPREP() function. */ +typedef FNSSMINTSAVEPREP *PFNSSMINTSAVEPREP; + +/** + * Execute state save operation. + * + * @returns VBox status code. + * @param pVM VM Handle. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACK(int) FNSSMINTSAVEEXEC(PVM pVM, PSSMHANDLE pSSM); +/** Pointer to a FNSSMINTSAVEEXEC() function. */ +typedef FNSSMINTSAVEEXEC *PFNSSMINTSAVEEXEC; + +/** + * Done state save operation. + * + * @returns VBox status code. + * @param pVM VM Handle. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACK(int) FNSSMINTSAVEDONE(PVM pVM, PSSMHANDLE pSSM); +/** Pointer to a FNSSMINTSAVEDONE() function. */ +typedef FNSSMINTSAVEDONE *PFNSSMINTSAVEDONE; + +/** + * Prepare state load operation. + * + * @returns VBox status code. + * @param pVM VM Handle. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACK(int) FNSSMINTLOADPREP(PVM pVM, PSSMHANDLE pSSM); +/** Pointer to a FNSSMINTLOADPREP() function. */ +typedef FNSSMINTLOADPREP *PFNSSMINTLOADPREP; + +/** + * Execute state load operation. + * + * @returns VBox status code. + * @param pVM VM Handle. + * @param pSSM SSM operation handle. + * @param uVersion Data layout version. + * @param uPass The pass. This is always SSM_PASS_FINAL for units + * that doesn't specify a pfnSaveLive callback. + */ +typedef DECLCALLBACK(int) FNSSMINTLOADEXEC(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass); +/** Pointer to a FNSSMINTLOADEXEC() function. */ +typedef FNSSMINTLOADEXEC *PFNSSMINTLOADEXEC; + +/** + * Done state load operation. + * + * @returns VBox load code. + * @param pVM VM Handle. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACK(int) FNSSMINTLOADDONE(PVM pVM, PSSMHANDLE pSSM); +/** Pointer to a FNSSMINTLOADDONE() function. */ +typedef FNSSMINTLOADDONE *PFNSSMINTLOADDONE; + +/** @} */ + + +/** The External callback variants. + * @{ + */ + +/** + * Prepare state live save operation. + * + * @returns VBox status code. + * @param pSSM SSM operation handle. + * @param pvUser User argument. + * @thread Any. + */ +typedef DECLCALLBACK(int) FNSSMEXTLIVEPREP(PSSMHANDLE pSSM, void *pvUser); +/** Pointer to a FNSSMEXTLIVEPREP() function. */ +typedef FNSSMEXTLIVEPREP *PFNSSMEXTLIVEPREP; + +/** + * Execute state live save operation. + * + * This will be called repeatedly until all units vote that the live phase has + * been concluded. + * + * @returns VBox status code. + * @param pSSM SSM operation handle. + * @param pvUser User argument. + * @param uPass The data pass. + * @thread Any. + */ +typedef DECLCALLBACK(int) FNSSMEXTLIVEEXEC(PSSMHANDLE pSSM, void *pvUser, uint32_t uPass); +/** Pointer to a FNSSMEXTLIVEEXEC() function. */ +typedef FNSSMEXTLIVEEXEC *PFNSSMEXTLIVEEXEC; + +/** + * Vote on whether the live part of the saving has been concluded. + * + * The vote stops once a unit has vetoed the decision, so don't rely upon this + * being called every time. + * + * @returns VBox status code. + * @retval VINF_SUCCESS if done. + * @retval VINF_SSM_VOTE_FOR_ANOTHER_PASS if another pass is needed. + * @retval VINF_SSM_VOTE_DONE_DONT_CALL_AGAIN if the live saving of the unit is + * done and there is not need calling it again before the final pass. + * @retval VERR_SSM_VOTE_FOR_GIVING_UP if its time to give up. + * + * @param pSSM SSM operation handle. + * @param pvUser User argument. + * @param uPass The data pass. + * @thread Any. + */ +typedef DECLCALLBACK(int) FNSSMEXTLIVEVOTE(PSSMHANDLE pSSM, void *pvUser, uint32_t uPass); +/** Pointer to a FNSSMEXTLIVEVOTE() function. */ +typedef FNSSMEXTLIVEVOTE *PFNSSMEXTLIVEVOTE; + +/** + * Prepare state save operation. + * + * @returns VBox status code. + * @param pSSM SSM operation handle. + * @param pvUser User argument. + */ +typedef DECLCALLBACK(int) FNSSMEXTSAVEPREP(PSSMHANDLE pSSM, void *pvUser); +/** Pointer to a FNSSMEXTSAVEPREP() function. */ +typedef FNSSMEXTSAVEPREP *PFNSSMEXTSAVEPREP; + +/** + * Execute state save operation. + * + * @param pSSM SSM operation handle. + * @param pvUser User argument. + * @author The lack of return code is for legacy reasons. + */ +typedef DECLCALLBACK(void) FNSSMEXTSAVEEXEC(PSSMHANDLE pSSM, void *pvUser); +/** Pointer to a FNSSMEXTSAVEEXEC() function. */ +typedef FNSSMEXTSAVEEXEC *PFNSSMEXTSAVEEXEC; + +/** + * Done state save operation. + * + * @returns VBox status code. + * @param pSSM SSM operation handle. + * @param pvUser User argument. + */ +typedef DECLCALLBACK(int) FNSSMEXTSAVEDONE(PSSMHANDLE pSSM, void *pvUser); +/** Pointer to a FNSSMEXTSAVEDONE() function. */ +typedef FNSSMEXTSAVEDONE *PFNSSMEXTSAVEDONE; + +/** + * Prepare state load operation. + * + * @returns VBox status code. + * @param pSSM SSM operation handle. + * @param pvUser User argument. + */ +typedef DECLCALLBACK(int) FNSSMEXTLOADPREP(PSSMHANDLE pSSM, void *pvUser); +/** Pointer to a FNSSMEXTLOADPREP() function. */ +typedef FNSSMEXTLOADPREP *PFNSSMEXTLOADPREP; + +/** + * Execute state load operation. + * + * @returns VBox status code. + * @param pSSM SSM operation handle. + * @param pvUser User argument. + * @param uVersion Data layout version. + * @param uPass The pass. This is always SSM_PASS_FINAL for units + * that doesn't specify a pfnSaveLive callback. + * @remark The odd return value is for legacy reasons. + */ +typedef DECLCALLBACK(int) FNSSMEXTLOADEXEC(PSSMHANDLE pSSM, void *pvUser, uint32_t uVersion, uint32_t uPass); +/** Pointer to a FNSSMEXTLOADEXEC() function. */ +typedef FNSSMEXTLOADEXEC *PFNSSMEXTLOADEXEC; + +/** + * Done state load operation. + * + * @returns VBox load code. + * @param pSSM SSM operation handle. + * @param pvUser User argument. + */ +typedef DECLCALLBACK(int) FNSSMEXTLOADDONE(PSSMHANDLE pSSM, void *pvUser); +/** Pointer to a FNSSMEXTLOADDONE() function. */ +typedef FNSSMEXTLOADDONE *PFNSSMEXTLOADDONE; + +/** @} */ + + +/** + * SSM stream method table. + * + * This is used by external parties for teleporting over TCP or any other media. + * SSM also uses this internally for file access, thus the 2-3 file centric + * methods. + */ +typedef struct SSMSTRMOPS +{ + /** Struct magic + version (SSMSTRMOPS_VERSION). */ + uint32_t u32Version; + + /** + * Write bytes to the stream. + * + * @returns VBox status code. + * @param pvUser The user argument. + * @param offStream The stream offset we're (supposed to be) at. + * @param pvBuf Pointer to the data. + * @param cbToWrite The number of bytes to write. + */ + DECLCALLBACKMEMBER(int, pfnWrite)(void *pvUser, uint64_t offStream, const void *pvBuf, size_t cbToWrite); + + /** + * Read bytes to the stream. + * + * @returns VBox status code. + * @param pvUser The user argument. + * @param offStream The stream offset we're (supposed to be) at. + * @param pvBuf Where to return the bytes. + * @param cbToRead The number of bytes to read. + * @param pcbRead Where to return the number of bytes actually + * read. This may differ from cbToRead when the + * end of the stream is encountered. + */ + DECLCALLBACKMEMBER(int, pfnRead)(void *pvUser, uint64_t offStream, void *pvBuf, size_t cbToRead, size_t *pcbRead); + + /** + * Seeks in the stream. + * + * @returns VBox status code. + * @retval VERR_NOT_SUPPORTED if the stream doesn't support this action. + * + * @param pvUser The user argument. + * @param offSeek The seek offset. + * @param uMethod RTFILE_SEEK_BEGIN, RTFILE_SEEK_END or + * RTFILE_SEEK_CURRENT. + * @param poffActual Where to store the new file position. Optional. + */ + DECLCALLBACKMEMBER(int, pfnSeek)(void *pvUser, int64_t offSeek, unsigned uMethod, uint64_t *poffActual); + + /** + * Get the current stream position. + * + * @returns The correct stream position. + * @param pvUser The user argument. + */ + DECLCALLBACKMEMBER(uint64_t, pfnTell)(void *pvUser); + + /** + * Get the size/length of the stream. + * + * @returns VBox status code. + * @retval VERR_NOT_SUPPORTED if the stream doesn't support this action. + * + * @param pvUser The user argument. + * @param pcb Where to return the size/length. + */ + DECLCALLBACKMEMBER(int, pfnSize)(void *pvUser, uint64_t *pcb); + + /** + * Check if the stream is OK or not (cancelled). + * + * @returns VBox status code. + * @param pvUser The user argument. + * + * @remarks The method is expected to do a LogRel on failure. + */ + DECLCALLBACKMEMBER(int, pfnIsOk)(void *pvUser); + + /** + * Close the stream. + * + * @returns VBox status code. + * @param pvUser The user argument. + * @param fCancelled True if the operation was cancelled. + */ + DECLCALLBACKMEMBER(int, pfnClose)(void *pvUser, bool fCancelled); + + /** Struct magic + version (SSMSTRMOPS_VERSION). */ + uint32_t u32EndVersion; +} SSMSTRMOPS; +/** Struct magic + version (SSMSTRMOPS_VERSION). */ +#define SSMSTRMOPS_VERSION UINT32_C(0x55aa0001) + + +VMMR3_INT_DECL(void) SSMR3Term(PVM pVM); +VMMR3DECL(int) SSMR3RegisterDevice(PVM pVM, PPDMDEVINS pDevIns, const char *pszName, uint32_t uInstance, uint32_t uVersion, size_t cbGuess, const char *pszBefore, + PFNSSMDEVLIVEPREP pfnLivePrep, PFNSSMDEVLIVEEXEC pfnLiveExec, PFNSSMDEVLIVEVOTE pfnLiveVote, + PFNSSMDEVSAVEPREP pfnSavePrep, PFNSSMDEVSAVEEXEC pfnSaveExec, PFNSSMDEVSAVEDONE pfnSaveDone, + PFNSSMDEVLOADPREP pfnLoadPrep, PFNSSMDEVLOADEXEC pfnLoadExec, PFNSSMDEVLOADDONE pfnLoadDone); +VMMR3DECL(int) SSMR3RegisterDriver(PVM pVM, PPDMDRVINS pDrvIns, const char *pszName, uint32_t uInstance, uint32_t uVersion, size_t cbGuess, + PFNSSMDRVLIVEPREP pfnLivePrep, PFNSSMDRVLIVEEXEC pfnLiveExec, PFNSSMDRVLIVEVOTE pfnLiveVote, + PFNSSMDRVSAVEPREP pfnSavePrep, PFNSSMDRVSAVEEXEC pfnSaveExec, PFNSSMDRVSAVEDONE pfnSaveDone, + PFNSSMDRVLOADPREP pfnLoadPrep, PFNSSMDRVLOADEXEC pfnLoadExec, PFNSSMDRVLOADDONE pfnLoadDone); +VMMR3DECL(int) SSMR3RegisterInternal(PVM pVM, const char *pszName, uint32_t uInstance, uint32_t uVersion, size_t cbGuess, + PFNSSMINTLIVEPREP pfnLivePrep, PFNSSMINTLIVEEXEC pfnLiveExec, PFNSSMINTLIVEVOTE pfnLiveVote, + PFNSSMINTSAVEPREP pfnSavePrep, PFNSSMINTSAVEEXEC pfnSaveExec, PFNSSMINTSAVEDONE pfnSaveDone, + PFNSSMINTLOADPREP pfnLoadPrep, PFNSSMINTLOADEXEC pfnLoadExec, PFNSSMINTLOADDONE pfnLoadDone); +VMMR3DECL(int) SSMR3RegisterExternal(PVM pVM, const char *pszName, uint32_t uInstance, uint32_t uVersion, size_t cbGuess, + PFNSSMEXTLIVEPREP pfnLivePrep, PFNSSMEXTLIVEEXEC pfnLiveExec, PFNSSMEXTLIVEVOTE pfnLiveVote, + PFNSSMEXTSAVEPREP pfnSavePrep, PFNSSMEXTSAVEEXEC pfnSaveExec, PFNSSMEXTSAVEDONE pfnSaveDone, + PFNSSMEXTLOADPREP pfnLoadPrep, PFNSSMEXTLOADEXEC pfnLoadExec, PFNSSMEXTLOADDONE pfnLoadDone, void *pvUser); +VMMR3_INT_DECL(int) SSMR3DeregisterDevice(PVM pVM, PPDMDEVINS pDevIns, const char *pszName, uint32_t uInstance); +VMMR3_INT_DECL(int) SSMR3DeregisterDriver(PVM pVM, PPDMDRVINS pDrvIns, const char *pszName, uint32_t uInstance); +VMMR3DECL(int) SSMR3DeregisterInternal(PVM pVM, const char *pszName); +VMMR3DECL(int) SSMR3DeregisterExternal(PVM pVM, const char *pszName); +VMMR3DECL(int) SSMR3Save(PVM pVM, const char *pszFilename, PCSSMSTRMOPS pStreamOps, void *pvStreamOpsUser, SSMAFTER enmAfter, PFNVMPROGRESS pfnProgress, void *pvUser); +VMMR3_INT_DECL(int) SSMR3LiveSave(PVM pVM, uint32_t cMsMaxDowntime, + const char *pszFilename, PCSSMSTRMOPS pStreamOps, void *pvStreamOps, + SSMAFTER enmAfter, PFNVMPROGRESS pfnProgress, void *pvProgressUser, + PSSMHANDLE *ppSSM); +VMMR3_INT_DECL(int) SSMR3LiveDoStep1(PSSMHANDLE pSSM); +VMMR3_INT_DECL(int) SSMR3LiveDoStep2(PSSMHANDLE pSSM); +VMMR3_INT_DECL(int) SSMR3LiveDone(PSSMHANDLE pSSM); +VMMR3DECL(int) SSMR3Load(PVM pVM, const char *pszFilename, PCSSMSTRMOPS pStreamOps, void *pvStreamOpsUser, + SSMAFTER enmAfter, PFNVMPROGRESS pfnProgress, void *pvProgressUser); +VMMR3DECL(int) SSMR3ValidateFile(const char *pszFilename, bool fChecksumIt); +VMMR3DECL(int) SSMR3Open(const char *pszFilename, unsigned fFlags, PSSMHANDLE *ppSSM); +VMMR3DECL(int) SSMR3Close(PSSMHANDLE pSSM); +VMMR3DECL(int) SSMR3Seek(PSSMHANDLE pSSM, const char *pszUnit, uint32_t iInstance, uint32_t *piVersion); +VMMR3DECL(int) SSMR3HandleGetStatus(PSSMHANDLE pSSM); +VMMR3DECL(int) SSMR3HandleSetStatus(PSSMHANDLE pSSM, int iStatus); +VMMR3DECL(SSMAFTER) SSMR3HandleGetAfter(PSSMHANDLE pSSM); +VMMR3DECL(bool) SSMR3HandleIsLiveSave(PSSMHANDLE pSSM); +VMMR3DECL(uint32_t) SSMR3HandleMaxDowntime(PSSMHANDLE pSSM); +VMMR3DECL(uint32_t) SSMR3HandleHostBits(PSSMHANDLE pSSM); +VMMR3DECL(uint32_t) SSMR3HandleRevision(PSSMHANDLE pSSM); +VMMR3DECL(uint32_t) SSMR3HandleVersion(PSSMHANDLE pSSM); +VMMR3DECL(const char *) SSMR3HandleHostOSAndArch(PSSMHANDLE pSSM); +VMMR3_INT_DECL(int) SSMR3HandleSetGCPtrSize(PSSMHANDLE pSSM, unsigned cbGCPtr); +VMMR3DECL(void) SSMR3HandleReportLivePercent(PSSMHANDLE pSSM, unsigned uPercent); +VMMR3DECL(int) SSMR3Cancel(PVM pVM); + + +/** Save operations. + * @{ + */ +VMMR3DECL(int) SSMR3PutStruct(PSSMHANDLE pSSM, const void *pvStruct, PCSSMFIELD paFields); +VMMR3DECL(int) SSMR3PutStructEx(PSSMHANDLE pSSM, const void *pvStruct, size_t cbStruct, uint32_t fFlags, PCSSMFIELD paFields, void *pvUser); +VMMR3DECL(int) SSMR3PutBool(PSSMHANDLE pSSM, bool fBool); +VMMR3DECL(int) SSMR3PutU8(PSSMHANDLE pSSM, uint8_t u8); +VMMR3DECL(int) SSMR3PutS8(PSSMHANDLE pSSM, int8_t i8); +VMMR3DECL(int) SSMR3PutU16(PSSMHANDLE pSSM, uint16_t u16); +VMMR3DECL(int) SSMR3PutS16(PSSMHANDLE pSSM, int16_t i16); +VMMR3DECL(int) SSMR3PutU32(PSSMHANDLE pSSM, uint32_t u32); +VMMR3DECL(int) SSMR3PutS32(PSSMHANDLE pSSM, int32_t i32); +VMMR3DECL(int) SSMR3PutU64(PSSMHANDLE pSSM, uint64_t u64); +VMMR3DECL(int) SSMR3PutS64(PSSMHANDLE pSSM, int64_t i64); +VMMR3DECL(int) SSMR3PutU128(PSSMHANDLE pSSM, uint128_t u128); +VMMR3DECL(int) SSMR3PutS128(PSSMHANDLE pSSM, int128_t i128); +VMMR3DECL(int) SSMR3PutUInt(PSSMHANDLE pSSM, RTUINT u); +VMMR3DECL(int) SSMR3PutSInt(PSSMHANDLE pSSM, RTINT i); +VMMR3DECL(int) SSMR3PutGCUInt(PSSMHANDLE pSSM, RTGCUINT u); +VMMR3DECL(int) SSMR3PutGCUIntReg(PSSMHANDLE pSSM, RTGCUINTREG u); +VMMR3DECL(int) SSMR3PutGCPhys32(PSSMHANDLE pSSM, RTGCPHYS32 GCPhys); +VMMR3DECL(int) SSMR3PutGCPhys64(PSSMHANDLE pSSM, RTGCPHYS64 GCPhys); +VMMR3DECL(int) SSMR3PutGCPhys(PSSMHANDLE pSSM, RTGCPHYS GCPhys); +VMMR3DECL(int) SSMR3PutGCPtr(PSSMHANDLE pSSM, RTGCPTR GCPtr); +VMMR3DECL(int) SSMR3PutGCUIntPtr(PSSMHANDLE pSSM, RTGCUINTPTR GCPtr); +VMMR3DECL(int) SSMR3PutRCPtr(PSSMHANDLE pSSM, RTRCPTR RCPtr); +VMMR3DECL(int) SSMR3PutIOPort(PSSMHANDLE pSSM, RTIOPORT IOPort); +VMMR3DECL(int) SSMR3PutSel(PSSMHANDLE pSSM, RTSEL Sel); +VMMR3DECL(int) SSMR3PutMem(PSSMHANDLE pSSM, const void *pv, size_t cb); +VMMR3DECL(int) SSMR3PutStrZ(PSSMHANDLE pSSM, const char *psz); +/** @} */ + + + +/** Load operations. + * @{ + */ +VMMR3DECL(int) SSMR3GetStruct(PSSMHANDLE pSSM, void *pvStruct, PCSSMFIELD paFields); +VMMR3DECL(int) SSMR3GetStructEx(PSSMHANDLE pSSM, void *pvStruct, size_t cbStruct, uint32_t fFlags, PCSSMFIELD paFields, void *pvUser); +VMMR3DECL(int) SSMR3GetBool(PSSMHANDLE pSSM, bool *pfBool); +VMMR3DECL(int) SSMR3GetU8(PSSMHANDLE pSSM, uint8_t *pu8); +VMMR3DECL(int) SSMR3GetS8(PSSMHANDLE pSSM, int8_t *pi8); +VMMR3DECL(int) SSMR3GetU16(PSSMHANDLE pSSM, uint16_t *pu16); +VMMR3DECL(int) SSMR3GetS16(PSSMHANDLE pSSM, int16_t *pi16); +VMMR3DECL(int) SSMR3GetU32(PSSMHANDLE pSSM, uint32_t *pu32); +VMMR3DECL(int) SSMR3GetS32(PSSMHANDLE pSSM, int32_t *pi32); +VMMR3DECL(int) SSMR3GetU64(PSSMHANDLE pSSM, uint64_t *pu64); +VMMR3DECL(int) SSMR3GetS64(PSSMHANDLE pSSM, int64_t *pi64); +VMMR3DECL(int) SSMR3GetU128(PSSMHANDLE pSSM, uint128_t *pu128); +VMMR3DECL(int) SSMR3GetS128(PSSMHANDLE pSSM, int128_t *pi128); +VMMR3DECL(int) SSMR3GetUInt(PSSMHANDLE pSSM, PRTUINT pu); +VMMR3DECL(int) SSMR3GetSInt(PSSMHANDLE pSSM, PRTINT pi); +VMMR3DECL(int) SSMR3GetGCUInt(PSSMHANDLE pSSM, PRTGCUINT pu); +VMMR3DECL(int) SSMR3GetGCUIntReg(PSSMHANDLE pSSM, PRTGCUINTREG pu); +VMMR3DECL(int) SSMR3GetGCPhys32(PSSMHANDLE pSSM, PRTGCPHYS32 pGCPhys); +VMMR3DECL(int) SSMR3GetGCPhys64(PSSMHANDLE pSSM, PRTGCPHYS64 pGCPhys); +VMMR3DECL(int) SSMR3GetGCPhys(PSSMHANDLE pSSM, PRTGCPHYS pGCPhys); +VMMR3DECL(int) SSMR3GetGCPtr(PSSMHANDLE pSSM, PRTGCPTR pGCPtr); +VMMR3DECL(int) SSMR3GetGCUIntPtr(PSSMHANDLE pSSM, PRTGCUINTPTR pGCPtr); +VMMR3DECL(int) SSMR3GetRCPtr(PSSMHANDLE pSSM, PRTRCPTR pRCPtr); +VMMR3DECL(int) SSMR3GetIOPort(PSSMHANDLE pSSM, PRTIOPORT pIOPort); +VMMR3DECL(int) SSMR3GetSel(PSSMHANDLE pSSM, PRTSEL pSel); +VMMR3DECL(int) SSMR3GetMem(PSSMHANDLE pSSM, void *pv, size_t cb); +VMMR3DECL(int) SSMR3GetStrZ(PSSMHANDLE pSSM, char *psz, size_t cbMax); +VMMR3DECL(int) SSMR3GetStrZEx(PSSMHANDLE pSSM, char *psz, size_t cbMax, size_t *pcbStr); +VMMR3DECL(int) SSMR3GetTimer(PSSMHANDLE pSSM, PTMTIMER pTimer); +VMMR3DECL(int) SSMR3Skip(PSSMHANDLE pSSM, size_t cb); +VMMR3DECL(int) SSMR3SkipToEndOfUnit(PSSMHANDLE pSSM); +VMMR3DECL(int) SSMR3SetLoadError(PSSMHANDLE pSSM, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...); +VMMR3DECL(int) SSMR3SetLoadErrorV(PSSMHANDLE pSSM, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va); +VMMR3DECL(int) SSMR3SetCfgError(PSSMHANDLE pSSM, RT_SRC_POS_DECL, const char *pszFormat, ...); + +/** @} */ + +/** @} */ +#endif /* IN_RING3 */ + + +/** @} */ + +RT_C_DECLS_END + +#endif + diff --git a/include/VBox/vmm/stam.h b/include/VBox/vmm/stam.h new file mode 100644 index 00000000..c25c606f --- /dev/null +++ b/include/VBox/vmm/stam.h @@ -0,0 +1,1265 @@ +/** @file + * STAM - Statistics Manager. + */ + +/* + * Copyright (C) 2006-2010 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_stam_h +#define ___VBox_vmm_stam_h + +#include <VBox/types.h> +#include <iprt/stdarg.h> +#ifdef _MSC_VER +# if _MSC_VER >= 1400 +# include <intrin.h> +# endif +#endif + +RT_C_DECLS_BEGIN + +/** @defgroup grp_stam The Statistics Manager API + * @{ + */ + +#if defined(VBOX_WITHOUT_RELEASE_STATISTICS) && defined(VBOX_WITH_STATISTICS) +# error "Both VBOX_WITHOUT_RELEASE_STATISTICS and VBOX_WITH_STATISTICS are defined! Make up your mind!" +#endif + + +/** @def STAM_GET_TS + * Gets the CPU timestamp counter. + * + * @param u64 The 64-bit variable which the timestamp shall be saved in. + */ +#ifdef __GNUC__ +# if defined(RT_ARCH_X86) + /* This produces optimal assembler code for x86 but does not work for AMD64 ('A' means 'either rax or rdx') */ +# define STAM_GET_TS(u64) __asm__ __volatile__ ("rdtsc\n\t" : "=A" (u64)) +# elif defined(RT_ARCH_AMD64) +# define STAM_GET_TS(u64) \ + do { uint64_t low; uint64_t high; \ + __asm__ __volatile__ ("rdtsc\n\t" : "=a"(low), "=d"(high)); \ + (u64) = ((high << 32) | low); \ + } while (0) +# endif +#else +# if _MSC_VER >= 1400 +# pragma intrinsic(__rdtsc) +# define STAM_GET_TS(u64) \ + do { (u64) = __rdtsc(); } while (0) +# else +# define STAM_GET_TS(u64) \ + do { \ + uint64_t u64Tmp; \ + __asm { \ + __asm rdtsc \ + __asm mov dword ptr [u64Tmp], eax \ + __asm mov dword ptr [u64Tmp + 4], edx \ + } \ + (u64) = u64Tmp; \ + } while (0) +# endif +#endif + + +/** @def STAM_REL_STATS + * Code for inclusion only when VBOX_WITH_STATISTICS is defined. + * @param code A code block enclosed in {}. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_STATS(code) do code while(0) +#else +# define STAM_REL_STATS(code) do {} while(0) +#endif +/** @def STAM_STATS + * Code for inclusion only when VBOX_WITH_STATISTICS is defined. + * @param code A code block enclosed in {}. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_STATS(code) STAM_REL_STATS(code) +#else +# define STAM_STATS(code) do {} while(0) +#endif + + +/** + * Sample type. + */ +typedef enum STAMTYPE +{ + /** Invalid entry. */ + STAMTYPE_INVALID = 0, + /** Generic counter. */ + STAMTYPE_COUNTER, + /** Profiling of an function. */ + STAMTYPE_PROFILE, + /** Profiling of an operation. */ + STAMTYPE_PROFILE_ADV, + /** Ratio of A to B, uint32_t types. Not reset. */ + STAMTYPE_RATIO_U32, + /** Ratio of A to B, uint32_t types. Reset both to 0. */ + STAMTYPE_RATIO_U32_RESET, + /** Callback. */ + STAMTYPE_CALLBACK, + /** Generic unsigned 8-bit value. Not reset. */ + STAMTYPE_U8, + /** Generic unsigned 8-bit value. Reset to 0. */ + STAMTYPE_U8_RESET, + /** Generic hexadecimal unsigned 8-bit value. Not reset. */ + STAMTYPE_X8, + /** Generic hexadecimal unsigned 8-bit value. Reset to 0. */ + STAMTYPE_X8_RESET, + /** Generic unsigned 16-bit value. Not reset. */ + STAMTYPE_U16, + /** Generic unsigned 16-bit value. Reset to 0. */ + STAMTYPE_U16_RESET, + /** Generic hexadecimal unsigned 16-bit value. Not reset. */ + STAMTYPE_X16, + /** Generic hexadecimal unsigned 16-bit value. Reset to 0. */ + STAMTYPE_X16_RESET, + /** Generic unsigned 32-bit value. Not reset. */ + STAMTYPE_U32, + /** Generic unsigned 32-bit value. Reset to 0. */ + STAMTYPE_U32_RESET, + /** Generic hexadecimal unsigned 32-bit value. Not reset. */ + STAMTYPE_X32, + /** Generic hexadecimal unsigned 32-bit value. Reset to 0. */ + STAMTYPE_X32_RESET, + /** Generic unsigned 64-bit value. Not reset. */ + STAMTYPE_U64, + /** Generic unsigned 64-bit value. Reset to 0. */ + STAMTYPE_U64_RESET, + /** Generic hexadecimal unsigned 64-bit value. Not reset. */ + STAMTYPE_X64, + /** Generic hexadecimal unsigned 64-bit value. Reset to 0. */ + STAMTYPE_X64_RESET, + /** Generic boolean value. Not reset. */ + STAMTYPE_BOOL, + /** Generic boolean value. Reset to false. */ + STAMTYPE_BOOL_RESET, + /** The end (exclusive). */ + STAMTYPE_END +} STAMTYPE; + +/** + * Sample visibility type. + */ +typedef enum STAMVISIBILITY +{ + /** Invalid entry. */ + STAMVISIBILITY_INVALID = 0, + /** Always visible. */ + STAMVISIBILITY_ALWAYS, + /** Only visible when used (/hit). */ + STAMVISIBILITY_USED, + /** Not visible in the GUI. */ + STAMVISIBILITY_NOT_GUI, + /** The end (exclusive). */ + STAMVISIBILITY_END +} STAMVISIBILITY; + +/** + * Sample unit. + */ +typedef enum STAMUNIT +{ + /** Invalid entry .*/ + STAMUNIT_INVALID = 0, + /** No unit. */ + STAMUNIT_NONE, + /** Number of calls. */ + STAMUNIT_CALLS, + /** Count of whatever. */ + STAMUNIT_COUNT, + /** Count of bytes. */ + STAMUNIT_BYTES, + /** Count of bytes. */ + STAMUNIT_PAGES, + /** Error count. */ + STAMUNIT_ERRORS, + /** Number of occurences. */ + STAMUNIT_OCCURENCES, + /** Ticks. */ + STAMUNIT_TICKS, + /** Ticks per call. */ + STAMUNIT_TICKS_PER_CALL, + /** Ticks per occurence. */ + STAMUNIT_TICKS_PER_OCCURENCE, + /** Ratio of good vs. bad. */ + STAMUNIT_GOOD_BAD, + /** Megabytes. */ + STAMUNIT_MEGABYTES, + /** Kilobytes. */ + STAMUNIT_KILOBYTES, + /** Nano seconds. */ + STAMUNIT_NS, + /** Nanoseconds per call. */ + STAMUNIT_NS_PER_CALL, + /** Nanoseconds per call. */ + STAMUNIT_NS_PER_OCCURENCE, + /** Percentage. */ + STAMUNIT_PCT, + /** Hertz. */ + STAMUNIT_HZ, + /** The end (exclusive). */ + STAMUNIT_END +} STAMUNIT; + + +/** @def STAM_REL_U8_INC + * Increments a uint8_t sample by one. + * + * @param pCounter Pointer to the uint8_t variable to operate on. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_U8_INC(pCounter) \ + do { ++*(pCounter); } while (0) +#else +# define STAM_REL_U8_INC(pCounter) do { } while (0) +#endif +/** @def STAM_U8_INC + * Increments a uint8_t sample by one. + * + * @param pCounter Pointer to the uint8_t variable to operate on. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_U8_INC(pCounter) STAM_REL_U8_INC(pCounter) +#else +# define STAM_U8_INC(pCounter) do { } while (0) +#endif + + +/** @def STAM_REL_U8_DEC + * Decrements a uint8_t sample by one. + * + * @param pCounter Pointer to the uint8_t variable to operate on. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_U8_DEC(pCounter) \ + do { --*(pCounter); } while (0) +#else +# define STAM_REL_U8_DEC(pCounter) do { } while (0) +#endif +/** @def STAM_U8_DEC + * Decrements a uint8_t sample by one. + * + * @param pCounter Pointer to the uint8_t variable to operate on. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_U8_DEC(pCounter) STAM_REL_U8_DEC(pCounter) +#else +# define STAM_U8_DEC(pCounter) do { } while (0) +#endif + + +/** @def STAM_REL_U8_ADD + * Increments a uint8_t sample by a value. + * + * @param pCounter Pointer to the uint8_t variable to operate on. + * @param Addend The value to add. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_U8_ADD(pCounter, Addend) \ + do { *(pCounter) += (Addend); } while (0) +#else +# define STAM_REL_U8_ADD(pCounter, Addend) do { } while (0) +#endif +/** @def STAM_U8_ADD + * Increments a uint8_t sample by a value. + * + * @param pCounter Pointer to the uint8_t variable to operate on. + * @param Addend The value to add. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_U8_ADD(pCounter, Addend) STAM_REL_U8_ADD(pCounter, Addend +#else +# define STAM_U8_ADD(pCounter, Addend) do { } while (0) +#endif + + +/** @def STAM_REL_U16_INC + * Increments a uint16_t sample by one. + * + * @param pCounter Pointer to the uint16_t variable to operate on. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_U16_INC(pCounter) \ + do { ++*(pCounter); } while (0) +#else +# define STAM_REL_U16_INC(pCounter) do { } while (0) +#endif +/** @def STAM_U16_INC + * Increments a uint16_t sample by one. + * + * @param pCounter Pointer to the uint16_t variable to operate on. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_U16_INC(pCounter) STAM_REL_U16_INC(pCounter) +#else +# define STAM_U16_INC(pCounter) do { } while (0) +#endif + + +/** @def STAM_REL_U16_DEC + * Decrements a uint16_t sample by one. + * + * @param pCounter Pointer to the uint16_t variable to operate on. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_U16_DEC(pCounter) \ + do { --*(pCounter); } while (0) +#else +# define STAM_REL_U16_DEC(pCounter) do { } while (0) +#endif +/** @def STAM_U16_DEC + * Decrements a uint16_t sample by one. + * + * @param pCounter Pointer to the uint16_t variable to operate on. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_U16_DEC(pCounter) STAM_REL_U16_DEC(pCounter) +#else +# define STAM_U16_DEC(pCounter) do { } while (0) +#endif + + +/** @def STAM_REL_U16_INC + * Increments a uint16_t sample by a value. + * + * @param pCounter Pointer to the uint16_t variable to operate on. + * @param Addend The value to add. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_U16_ADD(pCounter, Addend) \ + do { *(pCounter) += (Addend); } while (0) +#else +# define STAM_REL_U16_ADD(pCounter, Addend) do { } while (0) +#endif +/** @def STAM_U16_INC + * Increments a uint16_t sample by a value. + * + * @param pCounter Pointer to the uint16_t variable to operate on. + * @param Addend The value to add. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_U16_ADD(pCounter, Addend) STAM_REL_U16_ADD(pCounter, Addend) +#else +# define STAM_U16_ADD(pCounter, Addend) do { } while (0) +#endif + + +/** @def STAM_REL_U32_INC + * Increments a uint32_t sample by one. + * + * @param pCounter Pointer to the uint32_t variable to operate on. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_U32_INC(pCounter) \ + do { ++*(pCounter); } while (0) +#else +# define STAM_REL_U32_INC(pCounter) do { } while (0) +#endif +/** @def STAM_U32_INC + * Increments a uint32_t sample by one. + * + * @param pCounter Pointer to the uint32_t variable to operate on. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_U32_INC(pCounter) STAM_REL_U32_INC(pCounter) +#else +# define STAM_U32_INC(pCounter) do { } while (0) +#endif + + +/** @def STAM_REL_U32_DEC + * Decrements a uint32_t sample by one. + * + * @param pCounter Pointer to the uint32_t variable to operate on. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_U32_DEC(pCounter) \ + do { --*(pCounter); } while (0) +#else +# define STAM_REL_U32_DEC(pCounter) do { } while (0) +#endif +/** @def STAM_U32_DEC + * Decrements a uint32_t sample by one. + * + * @param pCounter Pointer to the uint32_t variable to operate on. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_U32_DEC(pCounter) STAM_REL_U32_DEC(pCounter) +#else +# define STAM_U32_DEC(pCounter) do { } while (0) +#endif + + +/** @def STAM_REL_U32_ADD + * Increments a uint32_t sample by value. + * + * @param pCounter Pointer to the uint32_t variable to operate on. + * @param Addend The value to add. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_U32_ADD(pCounter, Addend) \ + do { *(pCounter) += (Addend); } while (0) +#else +# define STAM_REL_U32_ADD(pCounter, Addend) do { } while (0) +#endif +/** @def STAM_U32_ADD + * Increments a uint32_t sample by value. + * + * @param pCounter Pointer to the uint32_t variable to operate on. + * @param Addend The value to add. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_U32_ADD(pCounter, Addend) STAM_REL_U32_ADD(pCounter, Addend) +#else +# define STAM_U32_ADD(pCounter, Addend) do { } while (0) +#endif + + +/** @def STAM_REL_U64_INC + * Increments a uint64_t sample by one. + * + * @param pCounter Pointer to the uint64_t variable to operate on. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_U64_INC(pCounter) \ + do { ++*(pCounter); } while (0) +#else +# define STAM_REL_U64_INC(pCounter) do { } while (0) +#endif +/** @def STAM_U64_INC + * Increments a uint64_t sample by one. + * + * @param pCounter Pointer to the uint64_t variable to operate on. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_U64_INC(pCounter) STAM_REL_U64_INC(pCounter) +#else +# define STAM_U64_INC(pCounter) do { } while (0) +#endif + + +/** @def STAM_REL_U64_DEC + * Decrements a uint64_t sample by one. + * + * @param pCounter Pointer to the uint64_t variable to operate on. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_U64_DEC(pCounter) \ + do { --*(pCounter); } while (0) +#else +# define STAM_REL_U64_DEC(pCounter) do { } while (0) +#endif +/** @def STAM_U64_DEC + * Decrements a uint64_t sample by one. + * + * @param pCounter Pointer to the uint64_t variable to operate on. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_U64_DEC(pCounter) STAM_REL_U64_DEC(pCounter) +#else +# define STAM_U64_DEC(pCounter) do { } while (0) +#endif + + +/** @def STAM_REL_U64_ADD + * Increments a uint64_t sample by a value. + * + * @param pCounter Pointer to the uint64_t variable to operate on. + * @param Addend The value to add. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_U64_ADD(pCounter, Addend) \ + do { *(pCounter) += (Addend); } while (0) +#else +# define STAM_REL_U64_ADD(pCounter, Addend) do { } while (0) +#endif +/** @def STAM_U64_ADD + * Increments a uint64_t sample by a value. + * + * @param pCounter Pointer to the uint64_t variable to operate on. + * @param Addend The value to add. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_U64_ADD(pCounter, Addend) STAM_REL_U64_ADD(pCounter, Addend) +#else +# define STAM_U64_ADD(pCounter, Addend) do { } while (0) +#endif + + +/** + * Counter sample - STAMTYPE_COUNTER. + */ +typedef struct STAMCOUNTER +{ + /** The current count. */ + volatile uint64_t c; +} STAMCOUNTER; +/** Pointer to a counter. */ +typedef STAMCOUNTER *PSTAMCOUNTER; +/** Pointer to a const counter. */ +typedef const STAMCOUNTER *PCSTAMCOUNTER; + + +/** @def STAM_REL_COUNTER_INC + * Increments a counter sample by one. + * + * @param pCounter Pointer to the STAMCOUNTER structure to operate on. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_COUNTER_INC(pCounter) \ + do { (pCounter)->c++; } while (0) +#else +# define STAM_REL_COUNTER_INC(pCounter) do { } while (0) +#endif +/** @def STAM_COUNTER_INC + * Increments a counter sample by one. + * + * @param pCounter Pointer to the STAMCOUNTER structure to operate on. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_COUNTER_INC(pCounter) STAM_REL_COUNTER_INC(pCounter) +#else +# define STAM_COUNTER_INC(pCounter) do { } while (0) +#endif + + +/** @def STAM_REL_COUNTER_DEC + * Decrements a counter sample by one. + * + * @param pCounter Pointer to the STAMCOUNTER structure to operate on. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_COUNTER_DEC(pCounter) \ + do { (pCounter)->c--; } while (0) +#else +# define STAM_REL_COUNTER_DEC(pCounter) do { } while (0) +#endif +/** @def STAM_COUNTER_DEC + * Decrements a counter sample by one. + * + * @param pCounter Pointer to the STAMCOUNTER structure to operate on. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_COUNTER_DEC(pCounter) STAM_REL_COUNTER_DEC(pCounter) +#else +# define STAM_COUNTER_DEC(pCounter) do { } while (0) +#endif + + +/** @def STAM_REL_COUNTER_ADD + * Increments a counter sample by a value. + * + * @param pCounter Pointer to the STAMCOUNTER structure to operate on. + * @param Addend The value to add to the counter. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_COUNTER_ADD(pCounter, Addend) \ + do { (pCounter)->c += (Addend); } while (0) +#else +# define STAM_REL_COUNTER_ADD(pCounter, Addend) do { } while (0) +#endif +/** @def STAM_COUNTER_ADD + * Increments a counter sample by a value. + * + * @param pCounter Pointer to the STAMCOUNTER structure to operate on. + * @param Addend The value to add to the counter. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_COUNTER_ADD(pCounter, Addend) STAM_REL_COUNTER_ADD(pCounter, Addend) +#else +# define STAM_COUNTER_ADD(pCounter, Addend) do { } while (0) +#endif + + +/** @def STAM_REL_COUNTER_RESET + * Resets the statistics sample. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_COUNTER_RESET(pCounter) do { (pCounter)->c = 0; } while (0) +#else +# define STAM_REL_COUNTER_RESET(pCounter) do { } while (0) +#endif +/** @def STAM_COUNTER_RESET + * Resets the statistics sample. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_COUNTER_RESET(pCounter) STAM_REL_COUNTER_RESET(pCounter) +#else +# define STAM_COUNTER_RESET(pCounter) do { } while (0) +#endif + + + +/** + * Profiling sample - STAMTYPE_PROFILE. + */ +typedef struct STAMPROFILE +{ + /** Number of periods. */ + volatile uint64_t cPeriods; + /** Total count of ticks. */ + volatile uint64_t cTicks; + /** Maximum tick count during a sampling. */ + volatile uint64_t cTicksMax; + /** Minimum tick count during a sampling. */ + volatile uint64_t cTicksMin; +} STAMPROFILE; +/** Pointer to a profile sample. */ +typedef STAMPROFILE *PSTAMPROFILE; +/** Pointer to a const profile sample. */ +typedef const STAMPROFILE *PCSTAMPROFILE; + + +/** @def STAM_REL_PROFILE_ADD_PERIOD + * Adds a period. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + * @param cTicksInPeriod The number of tick (or whatever) of the preiod + * being added. This is only referenced once. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_ADD_PERIOD(pProfile, cTicksInPeriod) \ + do { \ + uint64_t const StamPrefix_cTicks = (cTicksInPeriod); \ + (pProfile)->cTicks += StamPrefix_cTicks; \ + (pProfile)->cPeriods++; \ + if ((pProfile)->cTicksMax < StamPrefix_cTicks) \ + (pProfile)->cTicksMax = StamPrefix_cTicks; \ + if ((pProfile)->cTicksMin > StamPrefix_cTicks) \ + (pProfile)->cTicksMin = StamPrefix_cTicks; \ + } while (0) +#else +# define STAM_REL_PROFILE_ADD_PERIOD(pProfile, cTicksInPeriod) do { } while (0) +#endif +/** @def STAM_PROFILE_ADD_PERIOD + * Adds a period. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + * @param cTicksInPeriod The number of tick (or whatever) of the preiod + * being added. This is only referenced once. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_ADD_PERIOD(pProfile, cTicksInPeriod) STAM_REL_PROFILE_ADD_PERIOD(pProfile, cTicksInPeriod) +#else +# define STAM_PROFILE_ADD_PERIOD(pProfile, cTicksInPeriod) do { } while (0) +#endif + + +/** @def STAM_REL_PROFILE_START + * Samples the start time of a profiling period. + * + * @param pProfile Pointer to the STAMPROFILE structure to operate on. + * @param Prefix Identifier prefix used to internal variables. + * + * @remarks Declears a stack variable that will be used by related macros. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_START(pProfile, Prefix) \ + uint64_t Prefix##_tsStart; \ + STAM_GET_TS(Prefix##_tsStart) +#else +# define STAM_REL_PROFILE_START(pProfile, Prefix) do { } while (0) +#endif +/** @def STAM_PROFILE_START + * Samples the start time of a profiling period. + * + * @param pProfile Pointer to the STAMPROFILE structure to operate on. + * @param Prefix Identifier prefix used to internal variables. + * + * @remarks Declears a stack variable that will be used by related macros. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_START(pProfile, Prefix) STAM_REL_PROFILE_START(pProfile, Prefix) +#else +# define STAM_PROFILE_START(pProfile, Prefix) do { } while (0) +#endif + +/** @def STAM_REL_PROFILE_STOP + * Samples the stop time of a profiling period and updates the sample. + * + * @param pProfile Pointer to the STAMPROFILE structure to operate on. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_STOP(pProfile, Prefix) \ + do { \ + uint64_t Prefix##_cTicks; \ + STAM_GET_TS(Prefix##_cTicks); \ + Prefix##_cTicks -= Prefix##_tsStart; \ + (pProfile)->cTicks += Prefix##_cTicks; \ + (pProfile)->cPeriods++; \ + if ((pProfile)->cTicksMax < Prefix##_cTicks) \ + (pProfile)->cTicksMax = Prefix##_cTicks; \ + if ((pProfile)->cTicksMin > Prefix##_cTicks) \ + (pProfile)->cTicksMin = Prefix##_cTicks; \ + } while (0) +#else +# define STAM_REL_PROFILE_STOP(pProfile, Prefix) do { } while (0) +#endif +/** @def STAM_PROFILE_STOP + * Samples the stop time of a profiling period and updates the sample. + * + * @param pProfile Pointer to the STAMPROFILE structure to operate on. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_STOP(pProfile, Prefix) STAM_REL_PROFILE_STOP(pProfile, Prefix) +#else +# define STAM_PROFILE_STOP(pProfile, Prefix) do { } while (0) +#endif + + +/** @def STAM_REL_PROFILE_STOP_EX + * Samples the stop time of a profiling period and updates both the sample + * and an attribution sample. + * + * @param pProfile Pointer to the STAMPROFILE structure to operate on. + * @param pProfile2 Pointer to the STAMPROFILE structure which this + * interval should be attributed to as well. This may be NULL. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_STOP_EX(pProfile, pProfile2, Prefix) \ + do { \ + uint64_t Prefix##_cTicks; \ + STAM_GET_TS(Prefix##_cTicks); \ + Prefix##_cTicks -= Prefix##_tsStart; \ + (pProfile)->cTicks += Prefix##_cTicks; \ + (pProfile)->cPeriods++; \ + if ((pProfile)->cTicksMax < Prefix##_cTicks) \ + (pProfile)->cTicksMax = Prefix##_cTicks; \ + if ((pProfile)->cTicksMin > Prefix##_cTicks) \ + (pProfile)->cTicksMin = Prefix##_cTicks; \ + \ + if ((pProfile2)) \ + { \ + (pProfile2)->cTicks += Prefix##_cTicks; \ + (pProfile2)->cPeriods++; \ + if ((pProfile2)->cTicksMax < Prefix##_cTicks) \ + (pProfile2)->cTicksMax = Prefix##_cTicks; \ + if ((pProfile2)->cTicksMin > Prefix##_cTicks) \ + (pProfile2)->cTicksMin = Prefix##_cTicks; \ + } \ + } while (0) +#else +# define STAM_REL_PROFILE_STOP_EX(pProfile, pProfile2, Prefix) do { } while (0) +#endif +/** @def STAM_PROFILE_STOP_EX + * Samples the stop time of a profiling period and updates both the sample + * and an attribution sample. + * + * @param pProfile Pointer to the STAMPROFILE structure to operate on. + * @param pProfile2 Pointer to the STAMPROFILE structure which this + * interval should be attributed to as well. This may be NULL. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_STOP_EX(pProfile, pProfile2, Prefix) STAM_REL_PROFILE_STOP_EX(pProfile, pProfile2, Prefix) +#else +# define STAM_PROFILE_STOP_EX(pProfile, pProfile2, Prefix) do { } while (0) +#endif + + +/** + * Advanced profiling sample - STAMTYPE_PROFILE_ADV. + * + * Identical to a STAMPROFILE sample, but the start timestamp + * is stored after the STAMPROFILE structure so the sampling + * can start and stop in different functions. + */ +typedef struct STAMPROFILEADV +{ + /** The STAMPROFILE core. */ + STAMPROFILE Core; + /** The start timestamp. */ + volatile uint64_t tsStart; +} STAMPROFILEADV; +/** Pointer to a advanced profile sample. */ +typedef STAMPROFILEADV *PSTAMPROFILEADV; +/** Pointer to a const advanced profile sample. */ +typedef const STAMPROFILEADV *PCSTAMPROFILEADV; + + +/** @def STAM_REL_PROFILE_ADV_START + * Samples the start time of a profiling period. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_ADV_START(pProfileAdv, Prefix) \ + STAM_GET_TS((pProfileAdv)->tsStart) +#else +# define STAM_REL_PROFILE_ADV_START(pProfileAdv, Prefix) do { } while (0) +#endif +/** @def STAM_PROFILE_ADV_START + * Samples the start time of a profiling period. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_ADV_START(pProfileAdv, Prefix) STAM_REL_PROFILE_ADV_START(pProfileAdv, Prefix) +#else +# define STAM_PROFILE_ADV_START(pProfileAdv, Prefix) do { } while (0) +#endif + + +/** @def STAM_REL_PROFILE_ADV_STOP + * Samples the stop time of a profiling period (if running) and updates the + * sample. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_ADV_STOP(pProfileAdv, Prefix) \ + do { \ + if ((pProfileAdv)->tsStart) \ + { \ + uint64_t Prefix##_cTicks; \ + STAM_GET_TS(Prefix##_cTicks); \ + Prefix##_cTicks -= (pProfileAdv)->tsStart; \ + (pProfileAdv)->tsStart = 0; \ + (pProfileAdv)->Core.cTicks += Prefix##_cTicks; \ + (pProfileAdv)->Core.cPeriods++; \ + if ((pProfileAdv)->Core.cTicksMax < Prefix##_cTicks) \ + (pProfileAdv)->Core.cTicksMax = Prefix##_cTicks; \ + if ((pProfileAdv)->Core.cTicksMin > Prefix##_cTicks) \ + (pProfileAdv)->Core.cTicksMin = Prefix##_cTicks; \ + } \ + } while (0) +#else +# define STAM_REL_PROFILE_ADV_STOP(pProfileAdv, Prefix) do { } while (0) +#endif +/** @def STAM_PROFILE_ADV_STOP + * Samples the stop time of a profiling period (if running) and updates the + * sample. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_ADV_STOP(pProfileAdv, Prefix) STAM_REL_PROFILE_ADV_STOP(pProfileAdv, Prefix) +#else +# define STAM_PROFILE_ADV_STOP(pProfileAdv, Prefix) do { } while (0) +#endif + + +/** @def STAM_REL_PROFILE_ADV_STOP_START + * Stops one profile counter (if running) and starts another one. + * + * @param pProfileAdv1 Pointer to the STAMPROFILEADV structure to stop. + * @param pProfileAdv2 Pointer to the STAMPROFILEADV structure to start. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_ADV_STOP_START(pProfileAdv1, pProfileAdv2, Prefix) \ + do { \ + uint64_t Prefix##_cTicks; \ + STAM_GET_TS(Prefix##_cTicks); \ + (pProfileAdv2)->tsStart = Prefix##_cTicks; \ + if ((pProfileAdv1)->tsStart) \ + { \ + Prefix##_cTicks -= (pProfileAdv1)->tsStart; \ + (pProfileAdv1)->tsStart = 0; \ + (pProfileAdv1)->Core.cTicks += Prefix##_cTicks; \ + (pProfileAdv1)->Core.cPeriods++; \ + if ((pProfileAdv1)->Core.cTicksMax < Prefix##_cTicks) \ + (pProfileAdv1)->Core.cTicksMax = Prefix##_cTicks; \ + if ((pProfileAdv1)->Core.cTicksMin > Prefix##_cTicks) \ + (pProfileAdv1)->Core.cTicksMin = Prefix##_cTicks; \ + } \ + } while (0) +#else +# define STAM_REL_PROFILE_ADV_STOP_START(pProfileAdv1, pProfileAdv2, Prefix) \ + do { } while (0) +#endif +/** @def STAM_PROFILE_ADV_STOP_START + * Samples the stop time of a profiling period (if running) and updates the + * sample. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_ADV_STOP_START(pProfileAdv1, pProfileAdv2, Prefix) \ + STAM_REL_PROFILE_ADV_STOP_START(pProfileAdv1, pProfileAdv2, Prefix) +#else +# define STAM_PROFILE_ADV_STOP_START(pProfileAdv1, pProfileAdv2, Prefix) \ + do { } while (0) +#endif + + +/** @def STAM_REL_PROFILE_ADV_SUSPEND + * Suspends the sampling for a while. This can be useful to exclude parts + * covered by other samples without screwing up the count, and average+min times. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + * @param Prefix Identifier prefix used to internal variables. The prefix + * must match that of the resume one since it stores the + * suspend time in a stack variable. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_ADV_SUSPEND(pProfileAdv, Prefix) \ + uint64_t Prefix##_tsSuspend; \ + STAM_GET_TS(Prefix##_tsSuspend) +#else +# define STAM_REL_PROFILE_ADV_SUSPEND(pProfileAdv, Prefix) do { } while (0) +#endif +/** @def STAM_PROFILE_ADV_SUSPEND + * Suspends the sampling for a while. This can be useful to exclude parts + * covered by other samples without screwing up the count, and average+min times. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + * @param Prefix Identifier prefix used to internal variables. The prefix + * must match that of the resume one since it stores the + * suspend time in a stack variable. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_ADV_SUSPEND(pProfileAdv, Prefix) STAM_REL_PROFILE_ADV_SUSPEND(pProfileAdv, Prefix) +#else +# define STAM_PROFILE_ADV_SUSPEND(pProfileAdv, Prefix) do { } while (0) +#endif + + +/** @def STAM_REL_PROFILE_ADV_RESUME + * Counter to STAM_REL_PROFILE_ADV_SUSPEND. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + * @param Prefix Identifier prefix used to internal variables. This must + * match the one used with the SUSPEND! + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_ADV_RESUME(pProfileAdv, Prefix) \ + do { \ + uint64_t Prefix##_tsNow; \ + STAM_GET_TS(Prefix##_tsNow); \ + (pProfileAdv)->tsStart += Prefix##_tsNow - Prefix##_tsSuspend; \ + } while (0) +#else +# define STAM_REL_PROFILE_ADV_RESUME(pProfileAdv, Prefix) do { } while (0) +#endif +/** @def STAM_PROFILE_ADV_RESUME + * Counter to STAM_PROFILE_ADV_SUSPEND. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + * @param Prefix Identifier prefix used to internal variables. This must + * match the one used with the SUSPEND! + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_ADV_RESUME(pProfileAdv, Prefix) STAM_REL_PROFILE_ADV_RESUME(pProfileAdv, Prefix) +#else +# define STAM_PROFILE_ADV_RESUME(pProfileAdv, Prefix) do { } while (0) +#endif + + +/** @def STAM_REL_PROFILE_ADV_STOP_EX + * Samples the stop time of a profiling period (if running) and updates both + * the sample and an attribution sample. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + * @param pProfile2 Pointer to the STAMPROFILE structure which this + * interval should be attributed to as well. This may be NULL. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_ADV_STOP_EX(pProfileAdv, pProfile2, Prefix) \ + do { \ + if ((pProfileAdv)->tsStart) \ + { \ + uint64_t Prefix##_cTicks; \ + STAM_GET_TS(Prefix##_cTicks); \ + Prefix##_cTicks -= (pProfileAdv)->tsStart; \ + (pProfileAdv)->tsStart = 0; \ + (pProfileAdv)->Core.cTicks += Prefix##_cTicks; \ + (pProfileAdv)->Core.cPeriods++; \ + if ((pProfileAdv)->Core.cTicksMax < Prefix##_cTicks) \ + (pProfileAdv)->Core.cTicksMax = Prefix##_cTicks; \ + if ((pProfileAdv)->Core.cTicksMin > Prefix##_cTicks) \ + (pProfileAdv)->Core.cTicksMin = Prefix##_cTicks; \ + if ((pProfile2)) \ + { \ + (pProfile2)->cTicks += Prefix##_cTicks; \ + (pProfile2)->cPeriods++; \ + if ((pProfile2)->cTicksMax < Prefix##_cTicks) \ + (pProfile2)->cTicksMax = Prefix##_cTicks; \ + if ((pProfile2)->cTicksMin > Prefix##_cTicks) \ + (pProfile2)->cTicksMin = Prefix##_cTicks; \ + } \ + } \ + } while (0) +#else +# define STAM_REL_PROFILE_ADV_STOP_EX(pProfileAdv, pProfile2, Prefix) do { } while (0) +#endif +/** @def STAM_PROFILE_ADV_STOP_EX + * Samples the stop time of a profiling period (if running) and updates both + * the sample and an attribution sample. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + * @param pProfile2 Pointer to the STAMPROFILE structure which this + * interval should be attributed to as well. This may be NULL. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_ADV_STOP_EX(pProfileAdv, pProfile2, Prefix) STAM_REL_PROFILE_ADV_STOP_EX(pProfileAdv, pProfile2, Prefix) +#else +# define STAM_PROFILE_ADV_STOP_EX(pProfileAdv, pProfile2, Prefix) do { } while (0) +#endif + +/** @def STAM_REL_PROFILE_ADV_IS_RUNNING + * Checks if it is running. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_ADV_IS_RUNNING(pProfileAdv) (pProfileAdv)->tsStart +#else +# define STAM_REL_PROFILE_ADV_IS_RUNNING(pProfileAdv) (false) +#endif +/** @def STAM_PROFILE_ADV_IS_RUNNING + * Checks if it is running. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_ADV_IS_RUNNING(pProfileAdv) STAM_REL_PROFILE_ADV_IS_RUNNING(pProfileAdv) +#else +# define STAM_PROFILE_ADV_IS_RUNNING(pProfileAdv) (false) +#endif + +/** @def STAM_REL_PROFILE_ADV_SET_STOPPED + * Marks the profile counter as stopped. + * + * This is for avoiding screwups in twisty code. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_ADV_SET_STOPPED(pProfileAdv) do { (pProfileAdv)->tsStart = 0; } while (0) +#else +# define STAM_REL_PROFILE_ADV_SET_STOPPED(pProfileAdv) do { } while (0) +#endif +/** @def STAM_PROFILE_ADV_SET_STOPPED + * Marks the profile counter as stopped. + * + * This is for avoiding screwups in twisty code. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_ADV_SET_STOPPED(pProfileAdv) STAM_REL_PROFILE_ADV_SET_STOPPED(pProfileAdv) +#else +# define STAM_PROFILE_ADV_SET_STOPPED(pProfileAdv) do { } while (0) +#endif + + +/** + * Ratio of A to B, uint32_t types. + * @remark Use STAM_STATS or STAM_REL_STATS for modifying A & B values. + */ +typedef struct STAMRATIOU32 +{ + /** Sample A. */ + uint32_t volatile u32A; + /** Sample B. */ + uint32_t volatile u32B; +} STAMRATIOU32; +/** Pointer to a uint32_t ratio. */ +typedef STAMRATIOU32 *PSTAMRATIOU32; +/** Pointer to const a uint32_t ratio. */ +typedef const STAMRATIOU32 *PCSTAMRATIOU32; + + + + +/** @defgroup grp_stam_r3 The STAM Host Context Ring 3 API + * @ingroup grp_stam + * @{ + */ + +VMMR3DECL(int) STAMR3InitUVM(PUVM pUVM); +VMMR3DECL(void) STAMR3TermUVM(PUVM pUVM); +VMMR3DECL(int) STAMR3RegisterU(PUVM pUVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, + const char *pszName, STAMUNIT enmUnit, const char *pszDesc); +VMMR3DECL(int) STAMR3Register(PVM pVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, + const char *pszName, STAMUNIT enmUnit, const char *pszDesc); + +/** @def STAM_REL_REG + * Registers a statistics sample. + * + * @param pVM VM Handle. + * @param pvSample Pointer to the sample. + * @param enmType Sample type. This indicates what pvSample is pointing at. + * @param pszName Sample name. The name is on this form "/<component>/<sample>". + * Further nesting is possible. + * @param enmUnit Sample unit. + * @param pszDesc Sample description. + */ +#define STAM_REL_REG(pVM, pvSample, enmType, pszName, enmUnit, pszDesc) \ + STAM_REL_STATS({ int rcStam = STAMR3Register(pVM, pvSample, enmType, STAMVISIBILITY_ALWAYS, pszName, enmUnit, pszDesc); \ + AssertRC(rcStam); }) +/** @def STAM_REG + * Registers a statistics sample if statistics are enabled. + * + * @param pVM VM Handle. + * @param pvSample Pointer to the sample. + * @param enmType Sample type. This indicates what pvSample is pointing at. + * @param pszName Sample name. The name is on this form "/<component>/<sample>". + * Further nesting is possible. + * @param enmUnit Sample unit. + * @param pszDesc Sample description. + */ +#define STAM_REG(pVM, pvSample, enmType, pszName, enmUnit, pszDesc) \ + STAM_STATS({STAM_REL_REG(pVM, pvSample, enmType, pszName, enmUnit, pszDesc);}) + +/** @def STAM_REL_REG_USED + * Registers a statistics sample which only shows when used. + * + * @param pVM VM Handle. + * @param pvSample Pointer to the sample. + * @param enmType Sample type. This indicates what pvSample is pointing at. + * @param pszName Sample name. The name is on this form "/<component>/<sample>". + * Further nesting is possible. + * @param enmUnit Sample unit. + * @param pszDesc Sample description. + */ +#define STAM_REL_REG_USED(pVM, pvSample, enmType, pszName, enmUnit, pszDesc) \ + STAM_REL_STATS({ int rcStam = STAMR3Register(pVM, pvSample, enmType, STAMVISIBILITY_USED, pszName, enmUnit, pszDesc); \ + AssertRC(rcStam);}) +/** @def STAM_REG_USED + * Registers a statistics sample which only shows when used, if statistics are enabled. + * + * @param pVM VM Handle. + * @param pvSample Pointer to the sample. + * @param enmType Sample type. This indicates what pvSample is pointing at. + * @param pszName Sample name. The name is on this form "/<component>/<sample>". + * Further nesting is possible. + * @param enmUnit Sample unit. + * @param pszDesc Sample description. + */ +#define STAM_REG_USED(pVM, pvSample, enmType, pszName, enmUnit, pszDesc) \ + STAM_STATS({ STAM_REL_REG_USED(pVM, pvSample, enmType, pszName, enmUnit, pszDesc); }) + +VMMR3DECL(int) STAMR3RegisterFU(PUVM pUVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, + const char *pszDesc, const char *pszName, ...); +VMMR3DECL(int) STAMR3RegisterF(PVM pVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, + const char *pszDesc, const char *pszName, ...); +VMMR3DECL(int) STAMR3RegisterVU(PUVM pUVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, + const char *pszDesc, const char *pszName, va_list args); +VMMR3DECL(int) STAMR3RegisterV(PVM pVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, + const char *pszDesc, const char *pszName, va_list args); + +/** + * Resets the sample. + * @param pVM The VM handle. + * @param pvSample The sample registered using STAMR3RegisterCallback. + */ +typedef void FNSTAMR3CALLBACKRESET(PVM pVM, void *pvSample); +/** Pointer to a STAM sample reset callback. */ +typedef FNSTAMR3CALLBACKRESET *PFNSTAMR3CALLBACKRESET; + +/** + * Prints the sample into the buffer. + * + * @param pVM The VM handle. + * @param pvSample The sample registered using STAMR3RegisterCallback. + * @param pszBuf The buffer to print into. + * @param cchBuf The size of the buffer. + */ +typedef void FNSTAMR3CALLBACKPRINT(PVM pVM, void *pvSample, char *pszBuf, size_t cchBuf); +/** Pointer to a STAM sample print callback. */ +typedef FNSTAMR3CALLBACKPRINT *PFNSTAMR3CALLBACKPRINT; + +VMMR3DECL(int) STAMR3RegisterCallback(PVM pVM, void *pvSample, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, + PFNSTAMR3CALLBACKRESET pfnReset, PFNSTAMR3CALLBACKPRINT pfnPrint, + const char *pszDesc, const char *pszName, ...); +VMMR3DECL(int) STAMR3RegisterCallbackV(PVM pVM, void *pvSample, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, + PFNSTAMR3CALLBACKRESET pfnReset, PFNSTAMR3CALLBACKPRINT pfnPrint, + const char *pszDesc, const char *pszName, va_list args); +VMMR3DECL(int) STAMR3DeregisterU(PUVM pUVM, void *pvSample); +VMMR3DECL(int) STAMR3Deregister(PVM pVM, void *pvSample); + +/** @def STAM_REL_DEREG + * Deregisters a statistics sample if statistics are enabled. + * + * @param pVM VM Handle. + * @param pvSample Pointer to the sample. + */ +#define STAM_REL_DEREG(pVM, pvSample) \ + STAM_REL_STATS({ int rcStam = STAMR3Deregister(pVM, pvSample); AssertRC(rcStam); }) +/** @def STAM_DEREG + * Deregisters a statistics sample if statistics are enabled. + * + * @param pVM VM Handle. + * @param pvSample Pointer to the sample. + */ +#define STAM_DEREG(pVM, pvSample) \ + STAM_STATS({ STAM_REL_DEREG(pVM, pvSample); }) + +VMMR3DECL(int) STAMR3ResetU(PUVM pUVM, const char *pszPat); +VMMR3DECL(int) STAMR3Reset(PVM pVM, const char *pszPat); +VMMR3DECL(int) STAMR3SnapshotU(PUVM pUVM, const char *pszPat, char **ppszSnapshot, size_t *pcchSnapshot, bool fWithDesc); +VMMR3DECL(int) STAMR3Snapshot(PVM pVM, const char *pszPat, char **ppszSnapshot, size_t *pcchSnapshot, bool fWithDesc); +VMMR3DECL(int) STAMR3SnapshotFreeU(PUVM pUVM, char *pszSnapshot); +VMMR3DECL(int) STAMR3SnapshotFree(PVM pVM, char *pszSnapshot); +VMMR3DECL(int) STAMR3DumpU(PUVM pUVM, const char *pszPat); +VMMR3DECL(int) STAMR3Dump(PVM pVM, const char *pszPat); +VMMR3DECL(int) STAMR3DumpToReleaseLogU(PUVM pUVM, const char *pszPat); +VMMR3DECL(int) STAMR3DumpToReleaseLog(PVM pVM, const char *pszPat); +VMMR3DECL(int) STAMR3PrintU(PUVM pUVM, const char *pszPat); +VMMR3DECL(int) STAMR3Print(PVM pVM, const char *pszPat); + +/** + * Callback function for STAMR3Enum(). + * + * @returns non-zero to halt the enumeration. + * + * @param pszName The name of the sample. + * @param enmType The type. + * @param pvSample Pointer to the data. enmType indicates the format of this data. + * @param enmUnit The unit. + * @param enmVisibility The visibility. + * @param pszDesc The description. + * @param pvUser The pvUser argument given to STAMR3Enum(). + */ +typedef DECLCALLBACK(int) FNSTAMR3ENUM(const char *pszName, STAMTYPE enmType, void *pvSample, STAMUNIT enmUnit, + STAMVISIBILITY enmVisiblity, const char *pszDesc, void *pvUser); +/** Pointer to a FNSTAMR3ENUM(). */ +typedef FNSTAMR3ENUM *PFNSTAMR3ENUM; + +VMMR3DECL(int) STAMR3EnumU(PUVM pUVM, const char *pszPat, PFNSTAMR3ENUM pfnEnum, void *pvUser); +VMMR3DECL(int) STAMR3Enum(PVM pVM, const char *pszPat, PFNSTAMR3ENUM pfnEnum, void *pvUser); +VMMR3DECL(const char *) STAMR3GetUnit(STAMUNIT enmUnit); + +/** @} */ + +/** @} */ + +RT_C_DECLS_END + +#endif + diff --git a/include/VBox/vmm/stam.mac b/include/VBox/vmm/stam.mac new file mode 100644 index 00000000..5e0fd65b --- /dev/null +++ b/include/VBox/vmm/stam.mac @@ -0,0 +1,382 @@ +;; @file +; STAM - Statistics Manager. +; + +; +; Copyright (C) 2006-2010 Oracle Corporation +; +; 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 (GPL) 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. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%ifndef ___VBox_vmm_stam_mac__ +%define ___VBox_vmm_stam_mac__ + + +%ifndef VBOX_WITH_STATISTICS + %ifdef DEBUG + %define VBOX_WITH_STATISTICS + %endif +%endif + + + +;; +; Counter sample - STAMTYPE_COUNTER. +struc STAMCOUNTER + .c resd 2 +endstruc + +;; +; Increments a counter sample by one. +; @param %1 Pointer to the STAMCOUNTER structure to operate on. +%macro STAM32_COUNTER_INC 1 +%ifdef VBOX_WITH_STATISTICS + push ebx + mov ebx, %1 + inc dword [ebx + STAMCOUNTER.c] + adc dword [ebx + STAMCOUNTER.c + 1], byte 0 + pop ebx +%endif +%endmacro + +%macro STAM64_COUNTER_INC 1 +%ifdef VBOX_WITH_STATISTICS + push rbx + mov rbx, %1 + inc qword [rbx + STAMCOUNTER.c] + pop rbx +%endif +%endmacro + +%macro STAM_COUNTER_INC 1 +%ifdef VBOX_WITH_STATISTICS + %ifdef RT_ARCH_AMD64 + STAM64_COUNTER_INC %1 + %else + STAM32_COUNTER_INC %1 + %endif +%endif +%endmacro + + +;; +; Increments a counter sample by a value. +; +; @param %1 Pointer to the STAMCOUNTER structure to operate on. +; @param %2 The value to add to the counter. +%macro STAM32_COUNTER_ADD 2 +%ifdef VBOX_WITH_STATISTICS + push ebx + mov ebx, %1 + push eax + mov eax, %2 + + add [ebx + STAMCOUNTER.c], eax + adc dword [ebx + STAMCOUNTER.c], byte 0 + + pop eax + pop ebx +%endif +%endmacro + +%macro STAM64_COUNTER_ADD 2 +%ifdef VBOX_WITH_STATISTICS + push rbx + mov rbx, %1 + push rax + mov rax, %2 + + add [rbx + STAMCOUNTER.c], rax + + pop rax + pop rbx +%endif +%endmacro + +%macro STAM_COUNTER_ADD 2 +%ifdef VBOX_WITH_STATISTICS + %ifdef RT_ARCH_AMD64 + STAM64_COUNTER_ADD %1, %2 + %else + STAM32_COUNTER_ADD %1, %2 + %endif +%endif +%endmacro + + +;; +; Profiling sample - STAMTYPE_PROFILE. +struc STAMPROFILE + .cPeriods resd 2 + .cTicks resd 2 + .cTicksMax resd 2 + .cTicksMin resd 2 +endstruc + + +;; +; Samples the start time of a profiling period. +; +; @param %1 Pointer to somewhere one can store a 64-bit timestamp until STAM_PROFILE_STOPP +%macro STAM32_PROFILE_START 1 +%ifdef VBOX_WITH_STATISTICS + push ebx + mov ebx, %1 + push eax + push edx + + rdtsc + mov [ebx], eax + mov [ebx + 4], edx + + pop edx + pop eax + pop ebx +%endif +%endmacro + +%macro STAM64_PROFILE_START 1 +%ifdef VBOX_WITH_STATISTICS + push rbx + mov rbx, %1 + push rax + push rdx + + rdtsc + mov [rbx], eax + mov [rbx + 4], edx + + pop rdx + pop rax + pop rbx +%endif +%endmacro + +%macro STAM_PROFILE_START 1 +%ifdef VBOX_WITH_STATISTICS + %ifdef RT_ARCH_AMD64 + STAM64_PROFILE_START %1 + %else + STAM32_PROFILE_START %1 + %endif +%endif +%endmacro + + +;; +; Samples the stop time of a profiling period and updates the sample. +; +; @param %1 Pointer to the STAMPROFILE structure to operate on. +; @param %2 Pointer to where the 64-bit timestamp from STAM_PROFILE_START was stored. +%macro STAM32_PROFILE_STOP 2 +%ifdef VBOX_WITH_STATISTICS + push ebx + mov ebx, %1 + push eax + push edx + + ; calc cTicks + push ecx + mov ecx, %2 + rdtsc + sub eax, [ecx] + sbb edx, [ecx + 4] + pop ecx + + ; update STAMPROFILE.cTicks + add [ebx + STAMPROFILE.cTicks], eax + adc [ebx + STAMPROFILE.cTicks + 4], edx + ; update STAMPROFILE.cPeriods + inc dword [ebx + STAMPROFILE.cPeriods] + adc dword [ebx + STAMPROFILE.cPeriods + 4], byte 0 + + ; update max? + cmp edx, [ebx + STAMPROFILE.cTicksMax + 4] + jb short %%not_update_max + ja short %%update_max + cmp eax, [ebx + STAMPROFILE.cTicksMax] + jbe short %%not_update_max +%%update_max: + mov [ebx + STAMPROFILE.cTicksMax], eax + mov [ebx + STAMPROFILE.cTicksMax + 4], edx +%%not_update_max: + + ; update min? + cmp edx, [ebx + STAMPROFILE.cTicksMin + 4] + ja short %%not_update_min + jb short %%update_min + cmp eax, [ebx + STAMPROFILE.cTicksMin] + jae short %%not_update_min +%%update_min: + mov [ebx + STAMPROFILE.cTicksMin], eax + mov [ebx + STAMPROFILE.cTicksMin + 4], edx +%%not_update_min: + + pop edx + pop eax + pop ebx +%endif +%endmacro + +%macro STAM64_PROFILE_STOP 2 +%ifdef VBOX_WITH_STATISTICS + push rbx + mov rbx, %1 + push rax + push rdx + + ; calc cTicks + push rcx + mov rcx, %2 + rdtsc + sub rax, [ecx] + sbb rdx, [ecx + 4] + pop rcx + + ; update STAMPROFILE.cTicks + shl rdx, 32 + or rdx, rax + add [rbx + STAMPROFILE.cTicks], rdx + ; update STAMPROFILE.cPeriods + inc qword [rbx + STAMPROFILE.cPeriods] + + ; update max? + cmp rdx, [rbx + STAMPROFILE.cTicksMax] + jbe short %%not_update_max + mov [rbx + STAMPROFILE.cTicksMax], rdx +%%not_update_max: + + ; update min? + cmp rdx, [rbx + STAMPROFILE.cTicksMin] + jae short %%not_update_min + mov [rbx + STAMPROFILE.cTicksMin], rax +%%not_update_min: + + pop rdx + pop rax + pop rbx +%endif +%endmacro + +%macro STAM_PROFILE_STOP 2 +%ifdef VBOX_WITH_STATISTICS + %ifdef RT_ARCH_AMD64 + STAM64_PROFILE_STOP %1, %2 + %else + STAM32_PROFILE_STOP %1, %2 + %endif +%endif +%endmacro + + + +struc STAMPROFILEADV + .cPeriods resd 2 + .cTicks resd 2 + .cTicksMax resd 2 + .cTicksMin resd 2 + .tsStart resd 2 +endstruc + + +;; +; Samples the start time of a profiling period. +; +; @param %1 Pointer to the STAMPROFILEADV structure to operate on. +%macro STAM32_PROFILE_ADV_START 1 +%ifdef VBOX_WITH_STATISTICS + push ecx + mov ecx, %1 + lea ecx, [ecx + STAMPROFILEADV.tsStart] + STAM32_PROFILE_START ecx + pop ecx +%endif +%endmacro + +%macro STAM64_PROFILE_ADV_START 1 +%ifdef VBOX_WITH_STATISTICS + push rcx + mov rcx, %1 + lea rcx, [rcx + STAMPROFILEADV.tsStart] + STAM64_PROFILE_START rcx + pop rcx +%endif +%endmacro + +%macro STAM_PROFILE_ADV_START 1 +%ifdef VBOX_WITH_STATISTICS + %ifdef RT_ARCH_AMD64 + STAM64_PROFILE_ADV_START %1 + %else + STAM32_PROFILE_ADV_START %1 + %endif +%endif +%endmacro + + +;; +; Samples the stop time of a profiling period and updates the sample. +; +; @param %1 Pointer to the STAMPROFILEADV structure to operate on. + +%macro STAM32_PROFILE_ADV_STOP 1 +%ifdef VBOX_WITH_STATISTICS + push ecx + mov ecx, %1 + lea ecx, [ecx + STAMPROFILEADV.tsStart] + cmp dword [ecx], byte 0 + jnz short %%doit + cmp dword [ecx + 4], byte 0 + jz short %%dont +%%doit: + STAM32_PROFILE_STOP %1, ecx +%%dont: + mov dword [ecx], 0 + mov dword [ecx + 4], 0 + pop ecx +%endif +%endmacro + +%macro STAM64_PROFILE_ADV_STOP 1 +%ifdef VBOX_WITH_STATISTICS + push rcx + mov rcx, %1 + lea rcx, [rcx + STAMPROFILEADV.tsStart] + cmp qword [rcx], byte 0 + jz short %%dont +%%doit: + STAM64_PROFILE_STOP %1, rcx +%%dont: + mov qword [rcx], 0 + pop rcx +%endif +%endmacro + +%macro STAM_PROFILE_ADV_STOP 1 +%ifdef VBOX_WITH_STATISTICS + %ifdef RT_ARCH_AMD64 + STAM64_PROFILE_ADV_STOP %1 + %else + STAM32_PROFILE_ADV_STOP %1 + %endif +%endif +%endmacro + + + +%endif diff --git a/include/VBox/vmm/tm.h b/include/VBox/vmm/tm.h new file mode 100644 index 00000000..be328b1c --- /dev/null +++ b/include/VBox/vmm/tm.h @@ -0,0 +1,281 @@ +/** @file + * TM - Time Manager. + */ + +/* + * Copyright (C) 2006-2010 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_tm_h +#define ___VBox_vmm_tm_h + +#include <VBox/types.h> +#ifdef IN_RING3 +# include <iprt/time.h> +#endif + +RT_C_DECLS_BEGIN + +/** @defgroup grp_tm The Time Manager API + * @{ + */ + +/** Enable a timer hack which improves the timer response/resolution a bit. */ +#define VBOX_HIGH_RES_TIMERS_HACK + + +/** + * Clock type. + */ +typedef enum TMCLOCK +{ + /** Real host time. + * This clock ticks all the time, so use with care. */ + TMCLOCK_REAL = 0, + /** Virtual guest time. + * This clock only ticks when the guest is running. It's implemented + * as an offset to monotonic real time (GIP). */ + TMCLOCK_VIRTUAL, + /** Virtual guest synchronized timer time. + * This is a special clock and timer queue for synchronizing virtual timers + * and virtual time sources. This clock is trying to keep up with + * TMCLOCK_VIRTUAL, but will wait for timers to be executed. If it lags + * too far behind TMCLOCK_VIRTUAL, it will try speed up to close the + * distance. + * @remarks Do not use this unless you really *must*. */ + TMCLOCK_VIRTUAL_SYNC, + /** Virtual CPU timestamp. + * By default this is a function of TMCLOCK_VIRTUAL_SYNC and the virtual + * CPU frequency. */ + TMCLOCK_TSC, + /** Number of clocks. */ + TMCLOCK_MAX +} TMCLOCK; + + +/** @defgroup grp_tm_timer_flags Timer flags. + * @{ */ +/** Use the default critical section for the class of timers. */ +#define TMTIMER_FLAGS_DEFAULT_CRIT_SECT 0 +/** No critical section needed or a custom one is set using + * TMR3TimerSetCritSect(). */ +#define TMTIMER_FLAGS_NO_CRIT_SECT RT_BIT_32(0) +/** @} */ + + +VMMDECL(void) TMNotifyStartOfExecution(PVMCPU pVCpu); +VMMDECL(void) TMNotifyEndOfExecution(PVMCPU pVCpu); +VMM_INT_DECL(void) TMNotifyStartOfHalt(PVMCPU pVCpu); +VMM_INT_DECL(void) TMNotifyEndOfHalt(PVMCPU pVCpu); +#ifdef IN_RING3 +VMMR3DECL(int) TMR3NotifySuspend(PVM pVM, PVMCPU pVCpu); +VMMR3DECL(int) TMR3NotifyResume(PVM pVM, PVMCPU pVCpu); +VMMR3DECL(int) TMR3SetWarpDrive(PVM pVM, uint32_t u32Percent); +#endif +VMMDECL(uint32_t) TMGetWarpDrive(PVM pVM); +VMM_INT_DECL(uint32_t) TMCalcHostTimerFrequency(PVM pVM, PVMCPU pVCpu); +#ifdef IN_RING3 +VMMR3DECL(int) TMR3GetCpuLoadTimes(PVM pVM, VMCPUID idCpu, uint64_t *pcNsTotal, uint64_t *pcNsExecuting, + uint64_t *pcNsHalted, uint64_t *pcNsOther); +#endif + + +/** @name Real Clock Methods + * @{ + */ +VMM_INT_DECL(uint64_t) TMRealGet(PVM pVM); +VMM_INT_DECL(uint64_t) TMRealGetFreq(PVM pVM); +/** @} */ + + +/** @name Virtual Clock Methods + * @{ + */ +VMM_INT_DECL(uint64_t) TMVirtualGet(PVM pVM); +VMM_INT_DECL(uint64_t) TMVirtualGetNoCheck(PVM pVM); +VMM_INT_DECL(uint64_t) TMVirtualSyncGetLag(PVM pVM); +VMM_INT_DECL(uint32_t) TMVirtualSyncGetCatchUpPct(PVM pVM); +VMM_INT_DECL(uint64_t) TMVirtualGetFreq(PVM pVM); +VMM_INT_DECL(uint64_t) TMVirtualSyncGet(PVM pVM); +VMM_INT_DECL(uint64_t) TMVirtualSyncGetNoCheck(PVM pVM); +VMM_INT_DECL(uint64_t) TMVirtualSyncGetEx(PVM pVM, bool fCheckTimers); +VMM_INT_DECL(uint64_t) TMVirtualSyncGetWithDeadlineNoCheck(PVM pVM, uint64_t *pcNsToDeadline); +VMM_INT_DECL(uint64_t) TMVirtualSyncGetNsToDeadline(PVM pVM); +VMM_INT_DECL(uint64_t) TMVirtualToNano(PVM pVM, uint64_t u64VirtualTicks); +VMM_INT_DECL(uint64_t) TMVirtualToMicro(PVM pVM, uint64_t u64VirtualTicks); +VMM_INT_DECL(uint64_t) TMVirtualToMilli(PVM pVM, uint64_t u64VirtualTicks); +VMM_INT_DECL(uint64_t) TMVirtualFromNano(PVM pVM, uint64_t u64NanoTS); +VMM_INT_DECL(uint64_t) TMVirtualFromMicro(PVM pVM, uint64_t u64MicroTS); +VMM_INT_DECL(uint64_t) TMVirtualFromMilli(PVM pVM, uint64_t u64MilliTS); +/** @} */ + + +/** @name CPU Clock Methods + * @{ + */ +VMMDECL(uint64_t) TMCpuTickGet(PVMCPU pVCpu); +VMM_INT_DECL(uint64_t) TMCpuTickGetNoCheck(PVMCPU pVCpu); +VMM_INT_DECL(bool) TMCpuTickCanUseRealTSC(PVMCPU pVCpu, uint64_t *poffRealTSC); +VMM_INT_DECL(uint64_t) TMCpuTickGetDeadlineAndTscOffset(PVMCPU pVCpu, bool *pfOffsettedTsc, uint64_t *poffRealTSC); +VMM_INT_DECL(int) TMCpuTickSet(PVM pVM, PVMCPU pVCpu, uint64_t u64Tick); +VMM_INT_DECL(int) TMCpuTickSetLastSeen(PVMCPU pVCpu, uint64_t u64LastSeenTick); +VMM_INT_DECL(uint64_t) TMCpuTickGetLastSeen(PVMCPU pVCpu); +VMMDECL(uint64_t) TMCpuTicksPerSecond(PVM pVM); +/** @} */ + + +/** @name Timer Methods + * @{ + */ +/** + * Device timer callback function. + * + * @param pDevIns Device instance of the device which registered the timer. + * @param pTimer The timer handle. + * @param pvUser User argument specified upon timer creation. + */ +typedef DECLCALLBACK(void) FNTMTIMERDEV(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser); +/** Pointer to a device timer callback function. */ +typedef FNTMTIMERDEV *PFNTMTIMERDEV; + +/** + * USB device timer callback function. + * + * @param pUsbIns The USB device instance the timer is associated + * with. + * @param pTimer The timer handle. + * @param pvUser User argument specified upon timer creation. + */ +typedef DECLCALLBACK(void) FNTMTIMERUSB(PPDMUSBINS pUsbIns, PTMTIMER pTimer, void *pvUser); +/** Pointer to a timer callback for a USB device. */ +typedef FNTMTIMERUSB *PFNTMTIMERUSB; + +/** + * Driver timer callback function. + * + * @param pDrvIns Device instance of the device which registered the timer. + * @param pTimer The timer handle. + * @param pvUser User argument specified upon timer creation. + */ +typedef DECLCALLBACK(void) FNTMTIMERDRV(PPDMDRVINS pDrvIns, PTMTIMER pTimer, void *pvUser); +/** Pointer to a driver timer callback function. */ +typedef FNTMTIMERDRV *PFNTMTIMERDRV; + +/** + * Service timer callback function. + * + * @param pSrvIns Service instance of the device which registered the timer. + * @param pTimer The timer handle. + */ +typedef DECLCALLBACK(void) FNTMTIMERSRV(PPDMSRVINS pSrvIns, PTMTIMER pTimer); +/** Pointer to a service timer callback function. */ +typedef FNTMTIMERSRV *PFNTMTIMERSRV; + +/** + * Internal timer callback function. + * + * @param pVM The VM. + * @param pTimer The timer handle. + * @param pvUser User argument specified upon timer creation. + */ +typedef DECLCALLBACK(void) FNTMTIMERINT(PVM pVM, PTMTIMER pTimer, void *pvUser); +/** Pointer to internal timer callback function. */ +typedef FNTMTIMERINT *PFNTMTIMERINT; + +/** + * External timer callback function. + * + * @param pvUser User argument as specified when the timer was created. + */ +typedef DECLCALLBACK(void) FNTMTIMEREXT(void *pvUser); +/** Pointer to an external timer callback function. */ +typedef FNTMTIMEREXT *PFNTMTIMEREXT; + +VMMDECL(PTMTIMERR3) TMTimerR3Ptr(PTMTIMER pTimer); +VMMDECL(PTMTIMERR0) TMTimerR0Ptr(PTMTIMER pTimer); +VMMDECL(PTMTIMERRC) TMTimerRCPtr(PTMTIMER pTimer); +VMMDECL(int) TMTimerLock(PTMTIMER pTimer, int rcBusy); +VMMDECL(void) TMTimerUnlock(PTMTIMER pTimer); +VMMDECL(bool) TMTimerIsLockOwner(PTMTIMER pTimer); +VMMDECL(int) TMTimerSet(PTMTIMER pTimer, uint64_t u64Expire); +VMMDECL(int) TMTimerSetRelative(PTMTIMER pTimer, uint64_t cTicksToNext, uint64_t *pu64Now); +VMMDECL(int) TMTimerSetFrequencyHint(PTMTIMER pTimer, uint32_t uHz); +VMMDECL(uint64_t) TMTimerGet(PTMTIMER pTimer); +VMMDECL(int) TMTimerStop(PTMTIMER pTimer); +VMMDECL(bool) TMTimerIsActive(PTMTIMER pTimer); + +VMMDECL(int) TMTimerSetMillies(PTMTIMER pTimer, uint32_t cMilliesToNext); +VMMDECL(int) TMTimerSetMicro(PTMTIMER pTimer, uint64_t cMicrosToNext); +VMMDECL(int) TMTimerSetNano(PTMTIMER pTimer, uint64_t cNanosToNext); +VMMDECL(uint64_t) TMTimerGetNano(PTMTIMER pTimer); +VMMDECL(uint64_t) TMTimerGetMicro(PTMTIMER pTimer); +VMMDECL(uint64_t) TMTimerGetMilli(PTMTIMER pTimer); +VMMDECL(uint64_t) TMTimerGetFreq(PTMTIMER pTimer); +VMMDECL(uint64_t) TMTimerGetExpire(PTMTIMER pTimer); +VMMDECL(uint64_t) TMTimerToNano(PTMTIMER pTimer, uint64_t cTicks); +VMMDECL(uint64_t) TMTimerToMicro(PTMTIMER pTimer, uint64_t cTicks); +VMMDECL(uint64_t) TMTimerToMilli(PTMTIMER pTimer, uint64_t cTicks); +VMMDECL(uint64_t) TMTimerFromNano(PTMTIMER pTimer, uint64_t cNanoSecs); +VMMDECL(uint64_t) TMTimerFromMicro(PTMTIMER pTimer, uint64_t cMicroSecs); +VMMDECL(uint64_t) TMTimerFromMilli(PTMTIMER pTimer, uint64_t cMilliSecs); + +VMMDECL(bool) TMTimerPollBool(PVM pVM, PVMCPU pVCpu); +VMM_INT_DECL(void) TMTimerPollVoid(PVM pVM, PVMCPU pVCpu); +VMM_INT_DECL(uint64_t) TMTimerPollGIP(PVM pVM, PVMCPU pVCpu, uint64_t *pu64Delta); + +/** @} */ + + +#ifdef IN_RING3 +/** @defgroup grp_tm_r3 The TM Host Context Ring-3 API + * @ingroup grp_tm + * @{ + */ +VMM_INT_DECL(int) TMR3Init(PVM pVM); +VMM_INT_DECL(int) TMR3InitFinalize(PVM pVM); +VMM_INT_DECL(void) TMR3Relocate(PVM pVM, RTGCINTPTR offDelta); +VMM_INT_DECL(int) TMR3Term(PVM pVM); +VMM_INT_DECL(void) TMR3Reset(PVM pVM); +VMM_INT_DECL(int) TMR3GetImportRC(PVM pVM, const char *pszSymbol, PRTRCPTR pRCPtrValue); +VMM_INT_DECL(int) TMR3TimerCreateDevice(PVM pVM, PPDMDEVINS pDevIns, TMCLOCK enmClock, PFNTMTIMERDEV pfnCallback, void *pvUser, uint32_t fFlags, const char *pszDesc, PPTMTIMERR3 ppTimer); +VMM_INT_DECL(int) TMR3TimerCreateUsb(PVM pVM, PPDMUSBINS pUsbIns, TMCLOCK enmClock, PFNTMTIMERUSB pfnCallback, void *pvUser, uint32_t fFlags, const char *pszDesc, PPTMTIMERR3 ppTimer); +VMM_INT_DECL(int) TMR3TimerCreateDriver(PVM pVM, PPDMDRVINS pDrvIns, TMCLOCK enmClock, PFNTMTIMERDRV pfnCallback, void *pvUser, uint32_t fFlags, const char *pszDesc, PPTMTIMERR3 ppTimer); +VMMR3DECL(int) TMR3TimerCreateInternal(PVM pVM, TMCLOCK enmClock, PFNTMTIMERINT pfnCallback, void *pvUser, const char *pszDesc, PPTMTIMERR3 ppTimer); +VMMR3DECL(PTMTIMERR3) TMR3TimerCreateExternal(PVM pVM, TMCLOCK enmClock, PFNTMTIMEREXT pfnCallback, void *pvUser, const char *pszDesc); +VMMR3DECL(int) TMR3TimerDestroy(PTMTIMER pTimer); +VMM_INT_DECL(int) TMR3TimerDestroyDevice(PVM pVM, PPDMDEVINS pDevIns); +VMM_INT_DECL(int) TMR3TimerDestroyUsb(PVM pVM, PPDMUSBINS pUsbIns); +VMM_INT_DECL(int) TMR3TimerDestroyDriver(PVM pVM, PPDMDRVINS pDrvIns); +VMMR3DECL(int) TMR3TimerSave(PTMTIMERR3 pTimer, PSSMHANDLE pSSM); +VMMR3DECL(int) TMR3TimerLoad(PTMTIMERR3 pTimer, PSSMHANDLE pSSM); +VMMR3DECL(int) TMR3TimerSetCritSect(PTMTIMERR3 pTimer, PPDMCRITSECT pCritSect); +VMMR3DECL(void) TMR3TimerQueuesDo(PVM pVM); +VMMR3_INT_DECL(void) TMR3VirtualSyncFF(PVM pVM, PVMCPU pVCpu); +VMMR3_INT_DECL(PRTTIMESPEC) TMR3UtcNow(PVM pVM, PRTTIMESPEC pTime); +/** @} */ +#endif /* IN_RING3 */ + + +/** @} */ + +RT_C_DECLS_END + +#endif + diff --git a/include/VBox/vmm/trpm.h b/include/VBox/vmm/trpm.h new file mode 100644 index 00000000..0cdfc153 --- /dev/null +++ b/include/VBox/vmm/trpm.h @@ -0,0 +1,150 @@ +/** @file + * TRPM - The Trap Monitor. + */ + +/* + * Copyright (C) 2006-2010 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_trpm_h +#define ___VBox_vmm_trpm_h + +#include <VBox/types.h> +#include <iprt/x86.h> + + +RT_C_DECLS_BEGIN +/** @defgroup grp_trpm The Trap Monitor API + * @{ + */ + +/** + * Trap: error code present or not + */ +typedef enum +{ + TRPM_TRAP_HAS_ERRORCODE = 0, + TRPM_TRAP_NO_ERRORCODE, + /** The usual 32-bit paranoia. */ + TRPM_TRAP_32BIT_HACK = 0x7fffffff +} TRPMERRORCODE; + +/** + * TRPM event type + */ +/** Note: must match trpm.mac! */ +typedef enum +{ + TRPM_TRAP = 0, + TRPM_HARDWARE_INT = 1, + TRPM_SOFTWARE_INT = 2, + /** The usual 32-bit paranoia. */ + TRPM_32BIT_HACK = 0x7fffffff +} TRPMEVENT; +/** Pointer to a TRPM event type. */ +typedef TRPMEVENT *PTRPMEVENT; +/** Pointer to a const TRPM event type. */ +typedef TRPMEVENT const *PCTRPMEVENT; + +/** + * Invalid trap handler for trampoline calls + */ +#define TRPM_INVALID_HANDLER 0 + +VMMDECL(int) TRPMQueryTrap(PVMCPU pVCpu, uint8_t *pu8TrapNo, PTRPMEVENT pEnmType); +VMMDECL(uint8_t) TRPMGetTrapNo(PVMCPU pVCpu); +VMMDECL(RTGCUINT) TRPMGetErrorCode(PVMCPU pVCpu); +VMMDECL(RTGCUINTPTR) TRPMGetFaultAddress(PVMCPU pVCpu); +VMMDECL(int) TRPMResetTrap(PVMCPU pVCpu); +VMMDECL(int) TRPMAssertTrap(PVMCPU pVCpu, uint8_t u8TrapNo, TRPMEVENT enmType); +VMMDECL(void) TRPMSetErrorCode(PVMCPU pVCpu, RTGCUINT uErrorCode); +VMMDECL(void) TRPMSetFaultAddress(PVMCPU pVCpu, RTGCUINTPTR uCR2); +VMMDECL(bool) TRPMIsSoftwareInterrupt(PVMCPU pVCpu); +VMMDECL(bool) TRPMHasTrap(PVMCPU pVCpu); +VMMDECL(int) TRPMQueryTrapAll(PVMCPU pVCpu, uint8_t *pu8TrapNo, PTRPMEVENT pEnmType, PRTGCUINT puErrorCode, PRTGCUINTPTR puCR2); +VMMDECL(void) TRPMSaveTrap(PVMCPU pVCpu); +VMMDECL(void) TRPMRestoreTrap(PVMCPU pVCpu); +VMMDECL(int) TRPMForwardTrap(PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t iGate, uint32_t cbInstr, TRPMERRORCODE enmError, TRPMEVENT enmType, int32_t iOrgTrap); +VMMDECL(int) TRPMRaiseXcpt(PVMCPU pVCpu, PCPUMCTXCORE pCtxCore, X86XCPT enmXcpt); +VMMDECL(int) TRPMRaiseXcptErr(PVMCPU pVCpu, PCPUMCTXCORE pCtxCore, X86XCPT enmXcpt, uint32_t uErr); +VMMDECL(int) TRPMRaiseXcptErrCR2(PVMCPU pVCpu, PCPUMCTXCORE pCtxCore, X86XCPT enmXcpt, uint32_t uErr, RTGCUINTPTR uCR2); + + +#ifdef IN_RING3 +/** @defgroup grp_trpm_r3 TRPM Host Context Ring 3 API + * @ingroup grp_trpm + * @{ + */ +VMMR3DECL(int) TRPMR3Init(PVM pVM); +VMMR3DECL(void) TRPMR3Relocate(PVM pVM, RTGCINTPTR offDelta); +VMMR3DECL(void) TRPMR3ResetCpu(PVMCPU pVCpu); +VMMR3DECL(void) TRPMR3Reset(PVM pVM); +VMMR3_INT_DECL(int) TRPMR3GetImportRC(PVM pVM, const char *pszSymbol, PRTRCPTR pRCPtrValue); +VMMR3DECL(int) TRPMR3Term(PVM pVM); +VMMR3DECL(int) TRPMR3EnableGuestTrapHandler(PVM pVM, unsigned iTrap); +VMMR3DECL(int) TRPMR3SetGuestTrapHandler(PVM pVM, unsigned iTrap, RTRCPTR pHandler); +VMMR3DECL(RTRCPTR) TRPMR3GetGuestTrapHandler(PVM pVM, unsigned iTrap); +VMMR3DECL(void) TRPMR3DisableMonitoring(PVM pVM); +VMMR3DECL(int) TRPMR3SyncIDT(PVM pVM, PVMCPU pVCpu); +VMMR3DECL(bool) TRPMR3IsGateHandler(PVM pVM, RTRCPTR GCPtr); +VMMR3DECL(uint32_t) TRPMR3QueryGateByHandler(PVM pVM, RTRCPTR GCPtr); +VMMR3DECL(int) TRPMR3InjectEvent(PVM pVM, PVMCPU pVCpu, TRPMEVENT enmEvent); +/** @} */ +#endif + + +#ifdef IN_RC +/** @defgroup grp_trpm_gc The TRPM Guest Context API + * @ingroup grp_trpm + * @{ + */ + +/** + * Guest Context temporary trap handler + * + * @returns VBox status code (appropriate for GC return). + * In this context VINF_SUCCESS means to restart the instruction. + * @param pVM VM handle. + * @param pRegFrame Trap register frame. + */ +typedef DECLCALLBACK(int) FNTRPMGCTRAPHANDLER(PVM pVM, PCPUMCTXCORE pRegFrame); +/** Pointer to a TRPMGCTRAPHANDLER() function. */ +typedef FNTRPMGCTRAPHANDLER *PFNTRPMGCTRAPHANDLER; + +VMMRCDECL(int) TRPMGCSetTempHandler(PVM pVM, unsigned iTrap, PFNTRPMGCTRAPHANDLER pfnHandler); +VMMRCDECL(void) TRPMGCHyperReturnToHost(PVM pVM, int rc); +/** @} */ +#endif + + +#ifdef IN_RING0 +/** @defgroup grp_trpm_r0 TRPM Host Context Ring 0 API + * @ingroup grp_trpm + * @{ + */ +VMMR0DECL(void) TRPMR0DispatchHostInterrupt(PVM pVM); +VMMR0DECL(void) TRPMR0SetupInterruptDispatcherFrame(PVM pVM, void *pvRet); +/** @} */ +#endif + +/** @} */ +RT_C_DECLS_END + +#endif diff --git a/include/VBox/vmm/trpm.mac b/include/VBox/vmm/trpm.mac new file mode 100644 index 00000000..534039e2 --- /dev/null +++ b/include/VBox/vmm/trpm.mac @@ -0,0 +1,47 @@ +;; @file +; TRPM - The Trap Monitor. +; + +; +; Copyright (C) 2006-2010 Oracle Corporation +; +; 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 (GPL) 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. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%ifndef ___VBox_vmm_trpm_mac__ +%define ___VBox_vmm_trpm_mac__ + + +;/** +; * TRPM event type +; */ +;/** Note: must match trpm.mac! */ +;typedef enum +;{ +; TRPM_TRAP = 0, +; TRPM_HARDWARE_INT = 1, +; TRPM_SOFTWARE_INT = 2, +; /** The usual 32-bit paranoia. */ +; TRPM_32BIT_HACK = 0x7fffffff +;} TRPMEVENT; + +%define TRPM_TRAP 0 +%define TRPM_HARDWARE_INT 1 +%define TRPM_SOFTWARE_INT 2 +%endif + diff --git a/include/VBox/vmm/uvm.h b/include/VBox/vmm/uvm.h new file mode 100644 index 00000000..10b8e49b --- /dev/null +++ b/include/VBox/vmm/uvm.h @@ -0,0 +1,152 @@ +/** @file + * GVM - The Global VM Data. + */ + +/* + * Copyright (C) 2007-2010 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +#ifndef ___VBox_vmm_uvm_h +#define ___VBox_vmm_uvm_h + +#include <VBox/types.h> +#include <iprt/assert.h> + + +/** + * Per virtual CPU ring-3 (user mode) data. + */ +typedef struct UVMCPU +{ + /** Pointer to the UVM structure. */ + PUVM pUVM; + /** Pointer to the VM structure. */ + PVM pVM; + /** Pointer to the VMCPU structure. */ + PVMCPU pVCpu; + /** The virtual CPU ID. */ + RTCPUID idCpu; + /** Alignment padding. */ + uint8_t abAlignment0[HC_ARCH_BITS == 32 ? 16 : 4]; + + /** The VM internal data. */ + union + { +#ifdef ___VMInternal_h + struct VMINTUSERPERVMCPU s; +#endif + uint8_t padding[512]; + } vm; +} UVMCPU; +AssertCompileMemberAlignment(UVMCPU, vm, 32); + + +/** + * The ring-3 (user mode) VM structure. + * + * This structure is similar to VM and GVM except that it resides in swappable + * user memory. The main purpose is to assist bootstrapping, where it allows us + * to start EMT much earlier and gives PDMLdr somewhere to put it's VMMR0 data. + * It is also a nice place to put big things that are user mode only. + */ +typedef struct UVM +{ + /** Magic / eye-catcher (UVM_MAGIC). */ + uint32_t u32Magic; + /** The number of virtual CPUs. */ + uint32_t cCpus; + /** The ring-3 mapping of the shared VM structure. */ + PVM pVM; + /** Pointer to the next VM. + * We keep a per process list of VM for the event that a process could + * contain more than one VM. + * @todo move this into vm.s! + */ + struct UVM *pNext; + + /** Pointer to the optional method table provided by the VMM user. */ + PCVMM2USERMETHODS pVmm2UserMethods; + +#if HC_ARCH_BITS == 32 + /** Align the next member on a 32 byte boundary. */ + uint8_t abAlignment0[HC_ARCH_BITS == 32 ? 12 : 0]; +#endif + + /** The VM internal data. */ + union + { +#ifdef ___VMInternal_h + struct VMINTUSERPERVM s; +#endif + uint8_t padding[512]; + } vm; + + /** The MM data. */ + union + { +#ifdef ___MMInternal_h + struct MMUSERPERVM s; +#endif + uint8_t padding[32]; + } mm; + + /** The PDM data. */ + union + { +#ifdef ___PDMInternal_h + struct PDMUSERPERVM s; +#endif + uint8_t padding[128]; + } pdm; + + /** The STAM data. */ + union + { +#ifdef ___STAMInternal_h + struct STAMUSERPERVM s; +#endif + uint8_t padding[6624]; + } stam; + + /** Per virtual CPU data. */ + UVMCPU aCpus[1]; +} UVM; +AssertCompileMemberAlignment(UVM, vm, 32); +AssertCompileMemberAlignment(UVM, mm, 32); +AssertCompileMemberAlignment(UVM, pdm, 32); +AssertCompileMemberAlignment(UVM, stam, 32); +AssertCompileMemberAlignment(UVM, aCpus, 32); + +/** The UVM::u32Magic value (Brad Mehldau). */ +#define UVM_MAGIC 0x19700823 + +/** @def UVM_ASSERT_VALID_EXT_RETURN + * Asserts a user mode VM handle is valid for external access. + */ +#define UVM_ASSERT_VALID_EXT_RETURN(a_pUVM, a_rc) \ + AssertMsgReturn( RT_VALID_ALIGNED_PTR(a_pUVM, PAGE_SIZE) \ + && (a_pUVM)->u32Magic == UVM_MAGIC, \ + ("a_pUVM=%p u32Magic=%#x\n", (a_pUVM), \ + RT_VALID_ALIGNED_PTR(a_pUVM, PAGE_SIZE) ? (a_pUVM)->u32Magic : 0), \ + (a_rc)) + +#endif + diff --git a/include/VBox/vmm/vm.h b/include/VBox/vmm/vm.h new file mode 100644 index 00000000..ef713127 --- /dev/null +++ b/include/VBox/vmm/vm.h @@ -0,0 +1,1106 @@ +/** @file + * VM - The Virtual Machine, data. + */ + +/* + * Copyright (C) 2006-2012 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_vm_h +#define ___VBox_vmm_vm_h + +#ifndef VBOX_FOR_DTRACE_LIB +# include <VBox/types.h> +# include <VBox/vmm/cpum.h> +# include <VBox/vmm/stam.h> +# include <VBox/vmm/vmapi.h> +# include <VBox/vmm/vmm.h> +# include <VBox/sup.h> +#else +# pragma D depends_on library vbox-types.d +# pragma D depends_on library CPUMInternal.d +# define ___CPUMInternal_h +#endif + + + +/** @defgroup grp_vm The Virtual Machine + * @{ + */ + +/** + * The state of a Virtual CPU. + * + * The basic state indicated here is whether the CPU has been started or not. In + * addition, there are sub-states when started for assisting scheduling (GVMM + * mostly). + * + * The transition out of the STOPPED state is done by a vmR3PowerOn. + * The transition back to the STOPPED state is done by vmR3PowerOff. + * + * (Alternatively we could let vmR3PowerOn start CPU 0 only and let the SPIP + * handling switch on the other CPUs. Then vmR3Reset would stop all but CPU 0.) + */ +typedef enum VMCPUSTATE +{ + /** The customary invalid zero. */ + VMCPUSTATE_INVALID = 0, + + /** Virtual CPU has not yet been started. */ + VMCPUSTATE_STOPPED, + + /** CPU started. */ + VMCPUSTATE_STARTED, + /** Executing guest code and can be poked. */ + VMCPUSTATE_STARTED_EXEC, + /** Executing guest code in the recompiler. */ + VMCPUSTATE_STARTED_EXEC_REM, + /** Halted. */ + VMCPUSTATE_STARTED_HALTED, + + /** The end of valid virtual CPU states. */ + VMCPUSTATE_END, + + /** Ensure 32-bit type. */ + VMCPUSTATE_32BIT_HACK = 0x7fffffff +} VMCPUSTATE; + + +/** + * Per virtual CPU data. + */ +typedef struct VMCPU +{ + /** Per CPU forced action. + * See the VMCPU_FF_* \#defines. Updated atomically. */ + uint32_t volatile fLocalForcedActions; /* 0 */ + /** The CPU state. */ + VMCPUSTATE volatile enmState; /* 4 */ + + /** Pointer to the ring-3 UVMCPU structure. */ + PUVMCPU pUVCpu; /* 8 */ + /** Ring-3 Host Context VM Pointer. */ + PVMR3 pVMR3; /* 16 / 12 */ + /** Ring-0 Host Context VM Pointer. */ + PVMR0 pVMR0; /* 24 / 16 */ + /** Raw-mode Context VM Pointer. */ + PVMRC pVMRC; /* 32 / 20 */ + /** The CPU ID. + * This is the index into the VM::aCpu array. */ + VMCPUID idCpu; /* 36 / 24 */ + /** The native thread handle. */ + RTNATIVETHREAD hNativeThread; /* 40 / 28 */ + /** The native R0 thread handle. (different from the R3 handle!) */ + RTNATIVETHREAD hNativeThreadR0; /* 48 / 32 */ + /** Which host CPU ID is this EMT running on. + * Only valid when in RC or HWACCMR0 with scheduling disabled. */ + RTCPUID volatile idHostCpu; /* 56 / 36 */ + + /** Trace groups enable flags. */ + uint32_t fTraceGroups; /* 60 / 40 */ + /** Align the structures below bit on a 64-byte boundary and make sure it starts + * at the same offset in both 64-bit and 32-bit builds. + * + * @remarks The alignments of the members that are larger than 48 bytes should be + * 64-byte for cache line reasons. structs containing small amounts of + * data could be lumped together at the end with a < 64 byte padding + * following it (to grow into and align the struct size). + * */ + uint8_t abAlignment1[HC_ARCH_BITS == 64 ? 60 : 16+64]; + /** State data for use by ad hoc profiling. */ + uint32_t uAdHoc; + /** Profiling samples for use by ad hoc profiling. */ + STAMPROFILEADV aStatAdHoc[8]; /* size: 40*8 = 320 */ + + /** CPUM part. */ + union + { +#ifdef ___CPUMInternal_h + struct CPUMCPU s; +#endif + uint8_t padding[3584]; /* multiple of 64 */ + } cpum; + + /** HWACCM part. */ + union + { +#ifdef ___HWACCMInternal_h + struct HWACCMCPU s; +#endif + uint8_t padding[5376]; /* multiple of 64 */ + } hwaccm; + + /** EM part. */ + union + { +#ifdef ___EMInternal_h + struct EMCPU s; +#endif + uint8_t padding[1472]; /* multiple of 64 */ + } em; + + /** IEM part. */ + union + { +#ifdef ___IEMInternal_h + struct IEMCPU s; +#endif + uint8_t padding[3072]; /* multiple of 64 */ + } iem; + + /** TRPM part. */ + union + { +#ifdef ___TRPMInternal_h + struct TRPMCPU s; +#endif + uint8_t padding[128]; /* multiple of 64 */ + } trpm; + + /** TM part. */ + union + { +#ifdef ___TMInternal_h + struct TMCPU s; +#endif + uint8_t padding[384]; /* multiple of 64 */ + } tm; + + /** VMM part. */ + union + { +#ifdef ___VMMInternal_h + struct VMMCPU s; +#endif + uint8_t padding[640]; /* multiple of 64 */ + } vmm; + + /** PDM part. */ + union + { +#ifdef ___PDMInternal_h + struct PDMCPU s; +#endif + uint8_t padding[128]; /* multiple of 64 */ + } pdm; + + /** IOM part. */ + union + { +#ifdef ___IOMInternal_h + struct IOMCPU s; +#endif + uint8_t padding[512]; /* multiple of 64 */ + } iom; + + /** DBGF part. + * @todo Combine this with other tiny structures. */ + union + { +#ifdef ___DBGFInternal_h + struct DBGFCPU s; +#endif + uint8_t padding[64]; /* multiple of 64 */ + } dbgf; + + /** Align the following members on page boundary. */ + uint8_t abAlignment2[1024 - 320 - 128]; + + /** PGM part. */ + union + { +#ifdef ___PGMInternal_h + struct PGMCPU s; +#endif + uint8_t padding[4096]; /* multiple of 4096 */ + } pgm; + +} VMCPU; + + +#ifndef VBOX_FOR_DTRACE_LIB + +/** @name Operations on VMCPU::enmState + * @{ */ +/** Gets the VMCPU state. */ +#define VMCPU_GET_STATE(pVCpu) ( (pVCpu)->enmState ) +/** Sets the VMCPU state. */ +#define VMCPU_SET_STATE(pVCpu, enmNewState) \ + ASMAtomicWriteU32((uint32_t volatile *)&(pVCpu)->enmState, (enmNewState)) +/** Cmpares and sets the VMCPU state. */ +#define VMCPU_CMPXCHG_STATE(pVCpu, enmNewState, enmOldState) \ + ASMAtomicCmpXchgU32((uint32_t volatile *)&(pVCpu)->enmState, (enmNewState), (enmOldState)) +/** Checks the VMCPU state. */ +#ifdef VBOX_STRICT +# define VMCPU_ASSERT_STATE(pVCpu, enmExpectedState) \ + do { \ + VMCPUSTATE enmState = VMCPU_GET_STATE(pVCpu); \ + AssertMsg(enmState == (enmExpectedState), \ + ("enmState=%d enmExpectedState=%d idCpu=%u\n", \ + enmState, enmExpectedState, (pVCpu)->idCpu)); \ + } while (0) +#else +# define VMCPU_ASSERT_STATE(pVCpu, enmExpectedState) do { } while (0) +#endif +/** Tests if the state means that the CPU is started. */ +#define VMCPUSTATE_IS_STARTED(enmState) ( (enmState) > VMCPUSTATE_STOPPED ) +/** Tests if the state means that the CPU is stopped. */ +#define VMCPUSTATE_IS_STOPPED(enmState) ( (enmState) == VMCPUSTATE_STOPPED ) +/** @} */ + + +/** The name of the Guest Context VMM Core module. */ +#define VMMGC_MAIN_MODULE_NAME "VMMGC.gc" +/** The name of the Ring 0 Context VMM Core module. */ +#define VMMR0_MAIN_MODULE_NAME "VMMR0.r0" + +/** VM Forced Action Flags. + * + * Use the VM_FF_SET() and VM_FF_CLEAR() macros to change the force + * action mask of a VM. + * + * @{ + */ +/** The virtual sync clock has been stopped, go to TM until it has been + * restarted... */ +#define VM_FF_TM_VIRTUAL_SYNC RT_BIT_32(2) +/** PDM Queues are pending. */ +#define VM_FF_PDM_QUEUES RT_BIT_32(VM_FF_PDM_QUEUES_BIT) +/** The bit number for VM_FF_PDM_QUEUES. */ +#define VM_FF_PDM_QUEUES_BIT 3 +/** PDM DMA transfers are pending. */ +#define VM_FF_PDM_DMA RT_BIT_32(VM_FF_PDM_DMA_BIT) +/** The bit number for VM_FF_PDM_DMA. */ +#define VM_FF_PDM_DMA_BIT 4 +/** This action forces the VM to call DBGF so DBGF can service debugger + * requests in the emulation thread. + * This action flag stays asserted till DBGF clears it.*/ +#define VM_FF_DBGF RT_BIT_32(VM_FF_DBGF_BIT) +/** The bit number for VM_FF_DBGF. */ +#define VM_FF_DBGF_BIT 8 +/** This action forces the VM to service pending requests from other + * thread or requests which must be executed in another context. */ +#define VM_FF_REQUEST RT_BIT_32(9) +/** Check for VM state changes and take appropriate action. */ +#define VM_FF_CHECK_VM_STATE RT_BIT_32(VM_FF_CHECK_VM_STATE_BIT) +/** The bit number for VM_FF_CHECK_VM_STATE. */ +#define VM_FF_CHECK_VM_STATE_BIT 10 +/** Reset the VM. (postponed) */ +#define VM_FF_RESET RT_BIT_32(VM_FF_RESET_BIT) +/** The bit number for VM_FF_RESET. */ +#define VM_FF_RESET_BIT 11 +/** EMT rendezvous in VMM. */ +#define VM_FF_EMT_RENDEZVOUS RT_BIT_32(VM_FF_EMT_RENDEZVOUS_BIT) +/** The bit number for VM_FF_EMT_RENDEZVOUS. */ +#define VM_FF_EMT_RENDEZVOUS_BIT 12 + +/** PGM needs to allocate handy pages. */ +#define VM_FF_PGM_NEED_HANDY_PAGES RT_BIT_32(18) +/** PGM is out of memory. + * Abandon all loops and code paths which can be resumed and get up to the EM + * loops. */ +#define VM_FF_PGM_NO_MEMORY RT_BIT_32(19) + /** PGM is about to perform a lightweight pool flush + * Guest SMP: all EMT threads should return to ring 3 + */ +#define VM_FF_PGM_POOL_FLUSH_PENDING RT_BIT_32(20) +/** REM needs to be informed about handler changes. */ +#define VM_FF_REM_HANDLER_NOTIFY RT_BIT_32(VM_FF_REM_HANDLER_NOTIFY_BIT) +/** The bit number for VM_FF_REM_HANDLER_NOTIFY. */ +#define VM_FF_REM_HANDLER_NOTIFY_BIT 29 +/** Suspend the VM - debug only. */ +#define VM_FF_DEBUG_SUSPEND RT_BIT_32(31) + + +/** This action forces the VM to check any pending interrups on the APIC. */ +#define VMCPU_FF_INTERRUPT_APIC RT_BIT_32(0) +/** This action forces the VM to check any pending interrups on the PIC. */ +#define VMCPU_FF_INTERRUPT_PIC RT_BIT_32(1) +/** This action forces the VM to schedule and run pending timer (TM). + * @remarks Don't move - PATM compatibility. */ +#define VMCPU_FF_TIMER RT_BIT_32(2) +/** This action forces the VM to check any pending NMIs. */ +#define VMCPU_FF_INTERRUPT_NMI_BIT 3 +#define VMCPU_FF_INTERRUPT_NMI RT_BIT_32(VMCPU_FF_INTERRUPT_NMI_BIT) +/** This action forces the VM to check any pending SMIs. */ +#define VMCPU_FF_INTERRUPT_SMI_BIT 4 +#define VMCPU_FF_INTERRUPT_SMI RT_BIT_32(VMCPU_FF_INTERRUPT_SMI_BIT) +/** PDM critical section unlocking is pending, process promptly upon return to R3. */ +#define VMCPU_FF_PDM_CRITSECT RT_BIT_32(5) +/** This action forces the VM to service pending requests from other + * thread or requests which must be executed in another context. */ +#define VMCPU_FF_REQUEST RT_BIT_32(9) +/** This action forces the VM to resync the page tables before going + * back to execute guest code. (GLOBAL FLUSH) */ +#define VMCPU_FF_PGM_SYNC_CR3 RT_BIT_32(16) +/** Same as VM_FF_PGM_SYNC_CR3 except that global pages can be skipped. + * (NON-GLOBAL FLUSH) */ +#define VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL RT_BIT_32(17) +/** Check for pending TLB shootdown actions. + * Consumer: HWACCM + * @todo rename to VMCPU_FF_HWACCM_TLB_SHOOTDOWN */ +#define VMCPU_FF_TLB_SHOOTDOWN RT_BIT_32(18) +/** Check for pending TLB flush action. + * Consumer: HWACCM + * @todo rename to VMCPU_FF_HWACCM_TLB_FLUSH */ +#define VMCPU_FF_TLB_FLUSH RT_BIT_32(VMCPU_FF_TLB_FLUSH_BIT) +/** The bit number for VMCPU_FF_TLB_FLUSH. */ +#define VMCPU_FF_TLB_FLUSH_BIT 19 +/** Check the interrupt and trap gates */ +#define VMCPU_FF_TRPM_SYNC_IDT RT_BIT_32(20) +/** Check Guest's TSS ring 0 stack */ +#define VMCPU_FF_SELM_SYNC_TSS RT_BIT_32(21) +/** Check Guest's GDT table */ +#define VMCPU_FF_SELM_SYNC_GDT RT_BIT_32(22) +/** Check Guest's LDT table */ +#define VMCPU_FF_SELM_SYNC_LDT RT_BIT_32(23) +/** Inhibit interrupts pending. See EMGetInhibitInterruptsPC(). */ +#define VMCPU_FF_INHIBIT_INTERRUPTS RT_BIT_32(24) +/** CSAM needs to scan the page that's being executed */ +#define VMCPU_FF_CSAM_SCAN_PAGE RT_BIT_32(26) +/** CSAM needs to do some homework. */ +#define VMCPU_FF_CSAM_PENDING_ACTION RT_BIT_32(27) +/** Force return to Ring-3. */ +#define VMCPU_FF_TO_R3 RT_BIT_32(28) + +/** Externally VM forced actions. Used to quit the idle/wait loop. */ +#define VM_FF_EXTERNAL_SUSPENDED_MASK (VM_FF_CHECK_VM_STATE | VM_FF_DBGF | VM_FF_REQUEST | VM_FF_EMT_RENDEZVOUS) +/** Externally VMCPU forced actions. Used to quit the idle/wait loop. */ +#define VMCPU_FF_EXTERNAL_SUSPENDED_MASK (VMCPU_FF_REQUEST) + +/** Externally forced VM actions. Used to quit the idle/wait loop. */ +#define VM_FF_EXTERNAL_HALTED_MASK ( VM_FF_CHECK_VM_STATE | VM_FF_DBGF | VM_FF_REQUEST \ + | VM_FF_PDM_QUEUES | VM_FF_PDM_DMA | VM_FF_EMT_RENDEZVOUS) +/** Externally forced VMCPU actions. Used to quit the idle/wait loop. */ +#define VMCPU_FF_EXTERNAL_HALTED_MASK (VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC | VMCPU_FF_REQUEST | VMCPU_FF_TIMER) + +/** High priority VM pre-execution actions. */ +#define VM_FF_HIGH_PRIORITY_PRE_MASK ( VM_FF_CHECK_VM_STATE | VM_FF_DBGF | VM_FF_TM_VIRTUAL_SYNC \ + | VM_FF_DEBUG_SUSPEND | VM_FF_PGM_NEED_HANDY_PAGES | VM_FF_PGM_NO_MEMORY | VM_FF_EMT_RENDEZVOUS) +/** High priority VMCPU pre-execution actions. */ +#define VMCPU_FF_HIGH_PRIORITY_PRE_MASK ( VMCPU_FF_TIMER | VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC | VMCPU_FF_PGM_SYNC_CR3 \ + | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL | VMCPU_FF_SELM_SYNC_TSS | VMCPU_FF_TRPM_SYNC_IDT \ + | VMCPU_FF_SELM_SYNC_GDT | VMCPU_FF_SELM_SYNC_LDT | VMCPU_FF_INHIBIT_INTERRUPTS) + +/** High priority VM pre raw-mode execution mask. */ +#define VM_FF_HIGH_PRIORITY_PRE_RAW_MASK (VM_FF_PGM_NEED_HANDY_PAGES | VM_FF_PGM_NO_MEMORY) +/** High priority VMCPU pre raw-mode execution mask. */ +#define VMCPU_FF_HIGH_PRIORITY_PRE_RAW_MASK ( VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL | VMCPU_FF_SELM_SYNC_TSS | VMCPU_FF_TRPM_SYNC_IDT \ + | VMCPU_FF_SELM_SYNC_GDT | VMCPU_FF_SELM_SYNC_LDT | VMCPU_FF_INHIBIT_INTERRUPTS) + +/** High priority post-execution actions. */ +#define VM_FF_HIGH_PRIORITY_POST_MASK (VM_FF_PGM_NO_MEMORY) +/** High priority post-execution actions. */ +#define VMCPU_FF_HIGH_PRIORITY_POST_MASK (VMCPU_FF_PDM_CRITSECT|VMCPU_FF_CSAM_PENDING_ACTION) + +/** Normal priority VM post-execution actions. */ +#define VM_FF_NORMAL_PRIORITY_POST_MASK ( VM_FF_CHECK_VM_STATE | VM_FF_DBGF | VM_FF_RESET \ + | VM_FF_PGM_NO_MEMORY | VM_FF_EMT_RENDEZVOUS) +/** Normal priority VMCPU post-execution actions. */ +#define VMCPU_FF_NORMAL_PRIORITY_POST_MASK (VMCPU_FF_CSAM_SCAN_PAGE) + +/** Normal priority VM actions. */ +#define VM_FF_NORMAL_PRIORITY_MASK (VM_FF_REQUEST | VM_FF_PDM_QUEUES | VM_FF_PDM_DMA | VM_FF_REM_HANDLER_NOTIFY | VM_FF_EMT_RENDEZVOUS) +/** Normal priority VMCPU actions. */ +#define VMCPU_FF_NORMAL_PRIORITY_MASK (VMCPU_FF_REQUEST) + +/** Flags to clear before resuming guest execution. */ +#define VMCPU_FF_RESUME_GUEST_MASK (VMCPU_FF_TO_R3) + +/** VM Flags that cause the HWACCM loops to go back to ring-3. */ +#define VM_FF_HWACCM_TO_R3_MASK (VM_FF_TM_VIRTUAL_SYNC | VM_FF_PGM_NEED_HANDY_PAGES | VM_FF_PGM_NO_MEMORY | VM_FF_PDM_QUEUES | VM_FF_EMT_RENDEZVOUS) +/** VMCPU Flags that cause the HWACCM loops to go back to ring-3. */ +#define VMCPU_FF_HWACCM_TO_R3_MASK (VMCPU_FF_TO_R3 | VMCPU_FF_TIMER | VMCPU_FF_PDM_CRITSECT) + +/** All the forced VM flags. */ +#define VM_FF_ALL_MASK (~0U) +/** All the forced VMCPU flags. */ +#define VMCPU_FF_ALL_MASK (~0U) + +/** All the forced VM flags except those related to raw-mode and hardware + * assisted execution. */ +#define VM_FF_ALL_REM_MASK (~(VM_FF_HIGH_PRIORITY_PRE_RAW_MASK) | VM_FF_PGM_NO_MEMORY) +/** All the forced VMCPU flags except those related to raw-mode and hardware + * assisted execution. */ +#define VMCPU_FF_ALL_REM_MASK (~(VMCPU_FF_HIGH_PRIORITY_PRE_RAW_MASK | VMCPU_FF_CSAM_PENDING_ACTION | VMCPU_FF_PDM_CRITSECT | VMCPU_FF_TLB_FLUSH | VMCPU_FF_TLB_SHOOTDOWN)) + +/** @} */ + +/** @def VM_FF_SET + * Sets a force action flag. + * + * @param pVM VM Handle. + * @param fFlag The flag to set. + */ +#if 1 +# define VM_FF_SET(pVM, fFlag) ASMAtomicOrU32(&(pVM)->fGlobalForcedActions, (fFlag)) +#else +# define VM_FF_SET(pVM, fFlag) \ + do { ASMAtomicOrU32(&(pVM)->fGlobalForcedActions, (fFlag)); \ + RTLogPrintf("VM_FF_SET : %08x %s - %s(%d) %s\n", (pVM)->fGlobalForcedActions, #fFlag, __FILE__, __LINE__, __FUNCTION__); \ + } while (0) +#endif + +/** @def VMCPU_FF_SET + * Sets a force action flag for the given VCPU. + * + * @param pVCpu VMCPU Handle. + * @param fFlag The flag to set. + */ +#define VMCPU_FF_SET(pVCpu, fFlag) ASMAtomicOrU32(&(pVCpu)->fLocalForcedActions, (fFlag)) + +/** @def VM_FF_CLEAR + * Clears a force action flag. + * + * @param pVM VM Handle. + * @param fFlag The flag to clear. + */ +#if 1 +# define VM_FF_CLEAR(pVM, fFlag) ASMAtomicAndU32(&(pVM)->fGlobalForcedActions, ~(fFlag)) +#else +# define VM_FF_CLEAR(pVM, fFlag) \ + do { ASMAtomicAndU32(&(pVM)->fGlobalForcedActions, ~(fFlag)); \ + RTLogPrintf("VM_FF_CLEAR: %08x %s - %s(%d) %s\n", (pVM)->fGlobalForcedActions, #fFlag, __FILE__, __LINE__, __FUNCTION__); \ + } while (0) +#endif + +/** @def VMCPU_FF_CLEAR + * Clears a force action flag for the given VCPU. + * + * @param pVCpu VMCPU Handle. + * @param fFlag The flag to clear. + */ +#define VMCPU_FF_CLEAR(pVCpu, fFlag) ASMAtomicAndU32(&(pVCpu)->fLocalForcedActions, ~(fFlag)) + +/** @def VM_FF_ISSET + * Checks if a force action flag is set. + * + * @param pVM VM Handle. + * @param fFlag The flag to check. + */ +#define VM_FF_IS_SET(pVM, fFlag) (((pVM)->fGlobalForcedActions & (fFlag)) == (fFlag)) +/** @deprecated */ +#define VM_FF_ISSET(pVM, fFlag) VM_FF_IS_SET(pVM, fFlag) + +/** @def VMCPU_FF_ISSET + * Checks if a force action flag is set for the given VCPU. + * + * @param pVCpu VMCPU Handle. + * @param fFlag The flag to check. + */ +#define VMCPU_FF_IS_SET(pVCpu, fFlag) (((pVCpu)->fLocalForcedActions & (fFlag)) == (fFlag)) +/** @deprecated */ +#define VMCPU_FF_ISSET(pVCpu, fFlag) VMCPU_FF_IS_SET(pVCpu, fFlag) + +/** @def VM_FF_ISPENDING + * Checks if one or more force action in the specified set is pending. + * + * @param pVM VM Handle. + * @param fFlags The flags to check for. + */ +#define VM_FF_IS_PENDING(pVM, fFlags) ((pVM)->fGlobalForcedActions & (fFlags)) +/** @deprecated */ +#define VM_FF_ISPENDING(pVM, fFlags) VM_FF_IS_PENDING(pVM, fFlags) + +/** @def VM_FF_TESTANDCLEAR + * Checks if one (!) force action in the specified set is pending and clears it atomically + * + * @returns true if the bit was set. + * @returns false if the bit was clear. + * @param pVM VM Handle. + * @param iBit Bit position to check and clear + */ +#define VM_FF_TEST_AND_CLEAR(pVM, iBit) (ASMAtomicBitTestAndClear(&(pVM)->fGlobalForcedActions, iBit##_BIT)) +/** @deprecated */ +#define VM_FF_TESTANDCLEAR(pVM, iBit) (ASMAtomicBitTestAndClear(&(pVM)->fGlobalForcedActions, iBit##_BIT)) + +/** @def VMCPU_FF_TESTANDCLEAR + * Checks if one (!) force action in the specified set is pending and clears it atomically + * + * @returns true if the bit was set. + * @returns false if the bit was clear. + * @param pVCpu VMCPU Handle. + * @param iBit Bit position to check and clear + */ +#define VMCPU_FF_TEST_AND_CLEAR(pVCpu, iBit) (ASMAtomicBitTestAndClear(&(pVCpu)->fLocalForcedActions, iBit##_BIT)) +/** @deprecated */ +#define VMCPU_FF_TESTANDCLEAR(pVCpu, iBit) (ASMAtomicBitTestAndClear(&(pVCpu)->fLocalForcedActions, iBit##_BIT)) + +/** @def VMCPU_FF_ISPENDING + * Checks if one or more force action in the specified set is pending for the given VCPU. + * + * @param pVCpu VMCPU Handle. + * @param fFlags The flags to check for. + */ +#define VMCPU_FF_IS_PENDING(pVCpu, fFlags) ((pVCpu)->fLocalForcedActions & (fFlags)) +/** @deprecated */ +#define VMCPU_FF_ISPENDING(pVCpu, fFlags) VMCPU_FF_IS_PENDING(pVCpu, fFlags) + +/** @def VM_FF_ISPENDING + * Checks if one or more force action in the specified set is pending while one + * or more other ones are not. + * + * @param pVM VM Handle. + * @param fFlags The flags to check for. + * @param fExcpt The flags that should not be set. + */ +#define VM_FF_IS_PENDING_EXCEPT(pVM, fFlags, fExcpt) ( ((pVM)->fGlobalForcedActions & (fFlags)) && !((pVM)->fGlobalForcedActions & (fExcpt)) ) + +/** @def VMCPU_FF_IS_PENDING_EXCEPT + * Checks if one or more force action in the specified set is pending for the given + * VCPU while one or more other ones are not. + * + * @param pVCpu VMCPU Handle. + * @param fFlags The flags to check for. + * @param fExcpt The flags that should not be set. + */ +#define VMCPU_FF_IS_PENDING_EXCEPT(pVCpu, fFlags, fExcpt) ( ((pVCpu)->fLocalForcedActions & (fFlags)) && !((pVCpu)->fLocalForcedActions & (fExcpt)) ) + +/** @def VM_IS_EMT + * Checks if the current thread is the emulation thread (EMT). + * + * @remark The ring-0 variation will need attention if we expand the ring-0 + * code to let threads other than EMT mess around with the VM. + */ +#ifdef IN_RC +# define VM_IS_EMT(pVM) true +#else +# define VM_IS_EMT(pVM) (VMMGetCpu(pVM) != NULL) +#endif + +/** @def VMCPU_IS_EMT + * Checks if the current thread is the emulation thread (EMT) for the specified + * virtual CPU. + */ +#ifdef IN_RC +# define VMCPU_IS_EMT(pVCpu) true +#else +# define VMCPU_IS_EMT(pVCpu) ((pVCpu) && ((pVCpu) == VMMGetCpu((pVCpu)->CTX_SUFF(pVM)))) +#endif + +/** @def VM_ASSERT_EMT + * Asserts that the current thread IS the emulation thread (EMT). + */ +#ifdef IN_RC +# define VM_ASSERT_EMT(pVM) Assert(VM_IS_EMT(pVM)) +#elif defined(IN_RING0) +# define VM_ASSERT_EMT(pVM) Assert(VM_IS_EMT(pVM)) +#else +# define VM_ASSERT_EMT(pVM) \ + AssertMsg(VM_IS_EMT(pVM), \ + ("Not emulation thread! Thread=%RTnthrd ThreadEMT=%RTnthrd\n", RTThreadNativeSelf(), VMR3GetVMCPUNativeThread(pVM))) +#endif + +/** @def VMCPU_ASSERT_EMT + * Asserts that the current thread IS the emulation thread (EMT) of the + * specified virtual CPU. + */ +#ifdef IN_RC +# define VMCPU_ASSERT_EMT(pVCpu) Assert(VMCPU_IS_EMT(pVCpu)) +#elif defined(IN_RING0) +# define VMCPU_ASSERT_EMT(pVCpu) Assert(VMCPU_IS_EMT(pVCpu)) +#else +# define VMCPU_ASSERT_EMT(pVCpu) \ + AssertMsg(VMCPU_IS_EMT(pVCpu), \ + ("Not emulation thread! Thread=%RTnthrd ThreadEMT=%RTnthrd idCpu=%#x\n", \ + RTThreadNativeSelf(), (pVCpu)->hNativeThread, (pVCpu)->idCpu)) +#endif + +/** @def VM_ASSERT_EMT_RETURN + * Asserts that the current thread IS the emulation thread (EMT) and returns if it isn't. + */ +#ifdef IN_RC +# define VM_ASSERT_EMT_RETURN(pVM, rc) AssertReturn(VM_IS_EMT(pVM), (rc)) +#elif defined(IN_RING0) +# define VM_ASSERT_EMT_RETURN(pVM, rc) AssertReturn(VM_IS_EMT(pVM), (rc)) +#else +# define VM_ASSERT_EMT_RETURN(pVM, rc) \ + AssertMsgReturn(VM_IS_EMT(pVM), \ + ("Not emulation thread! Thread=%RTnthrd ThreadEMT=%RTnthrd\n", RTThreadNativeSelf(), VMR3GetVMCPUNativeThread(pVM)), \ + (rc)) +#endif + +/** @def VMCPU_ASSERT_EMT_RETURN + * Asserts that the current thread IS the emulation thread (EMT) and returns if it isn't. + */ +#ifdef IN_RC +# define VMCPU_ASSERT_EMT_RETURN(pVCpu, rc) AssertReturn(VMCPU_IS_EMT(pVCpu), (rc)) +#elif defined(IN_RING0) +# define VMCPU_ASSERT_EMT_RETURN(pVCpu, rc) AssertReturn(VMCPU_IS_EMT(pVCpu), (rc)) +#else +# define VMCPU_ASSERT_EMT_RETURN(pVCpu, rc) \ + AssertMsg(VMCPU_IS_EMT(pVCpu), \ + ("Not emulation thread! Thread=%RTnthrd ThreadEMT=%RTnthrd idCpu=%#x\n", \ + RTThreadNativeSelf(), (pVCpu)->hNativeThread, (pVCpu)->idCpu), \ + (rc)) +#endif + +/** @def VMCPU_ASSERT_EMT_OR_GURU + * Asserts that the current thread IS the emulation thread (EMT) of the + * specified virtual CPU. + */ +#if defined(IN_RC) || defined(IN_RING0) +# define VMCPU_ASSERT_EMT_OR_GURU(pVCpu) Assert( VMCPU_IS_EMT(pVCpu) \ + || pVCpu->CTX_SUFF(pVM)->enmVMState == VMSTATE_GURU_MEDITATION \ + || pVCpu->CTX_SUFF(pVM)->enmVMState == VMSTATE_GURU_MEDITATION_LS ) +#else +# define VMCPU_ASSERT_EMT_OR_GURU(pVCpu) \ + AssertMsg( VMCPU_IS_EMT(pVCpu) \ + || pVCpu->CTX_SUFF(pVM)->enmVMState == VMSTATE_GURU_MEDITATION \ + || pVCpu->CTX_SUFF(pVM)->enmVMState == VMSTATE_GURU_MEDITATION_LS, \ + ("Not emulation thread! Thread=%RTnthrd ThreadEMT=%RTnthrd idCpu=%#x\n", \ + RTThreadNativeSelf(), (pVCpu)->hNativeThread, (pVCpu)->idCpu)) +#endif + +/** @def VMCPU_ASSERT_EMT_OR_NOT_RUNNING + * Asserts that the current thread IS the emulation thread (EMT) of the + * specified virtual CPU when the VM is running. + */ +#if defined(IN_RC) || defined(IN_RING0) +# define VMCPU_ASSERT_EMT_OR_NOT_RUNNING(pVCpu) \ + Assert( VMCPU_IS_EMT(pVCpu) \ + || pVCpu->CTX_SUFF(pVM)->enmVMState == VMSTATE_RUNNING \ + || pVCpu->CTX_SUFF(pVM)->enmVMState == VMSTATE_RUNNING_LS \ + || pVCpu->CTX_SUFF(pVM)->enmVMState == VMSTATE_RUNNING_FT ) +#else +# define VMCPU_ASSERT_EMT_OR_NOT_RUNNING(pVCpu) \ + AssertMsg( VMCPU_IS_EMT(pVCpu) \ + || pVCpu->CTX_SUFF(pVM)->enmVMState == VMSTATE_RUNNING \ + || pVCpu->CTX_SUFF(pVM)->enmVMState == VMSTATE_RUNNING_LS \ + || pVCpu->CTX_SUFF(pVM)->enmVMState == VMSTATE_RUNNING_FT, \ + ("Not emulation thread! Thread=%RTnthrd ThreadEMT=%RTnthrd idCpu=%#x\n", \ + RTThreadNativeSelf(), (pVCpu)->hNativeThread, (pVCpu)->idCpu)) +#endif + +/** @def VM_ASSERT_EMT0 + * Asserts that the current thread IS emulation thread \#0 (EMT0). + */ +#define VM_ASSERT_EMT0(pVM) VMCPU_ASSERT_EMT(&(pVM)->aCpus[0]) + +/** @def VM_ASSERT_EMT0_RETURN + * Asserts that the current thread IS emulation thread \#0 (EMT0) and returns if + * it isn't. + */ +#define VM_ASSERT_EMT0_RETURN(pVM, rc) VMCPU_ASSERT_EMT_RETURN(&(pVM)->aCpus[0], (rc)) + + +/** + * Asserts that the current thread is NOT the emulation thread. + */ +#define VM_ASSERT_OTHER_THREAD(pVM) \ + AssertMsg(!VM_IS_EMT(pVM), ("Not other thread!!\n")) + + +/** @def VM_ASSERT_STATE_RETURN + * Asserts a certain VM state. + */ +#define VM_ASSERT_STATE(pVM, _enmState) \ + AssertMsg((pVM)->enmVMState == (_enmState), \ + ("state %s, expected %s\n", VMGetStateName((pVM)->enmVMState), VMGetStateName(_enmState))) + +/** @def VM_ASSERT_STATE_RETURN + * Asserts a certain VM state and returns if it doesn't match. + */ +#define VM_ASSERT_STATE_RETURN(pVM, _enmState, rc) \ + AssertMsgReturn((pVM)->enmVMState == (_enmState), \ + ("state %s, expected %s\n", VMGetStateName((pVM)->enmVMState), VMGetStateName(_enmState)), \ + (rc)) + +/** @def VM_ASSERT_VALID_EXT_RETURN + * Asserts a the VM handle is valid for external access, i.e. not being + * destroy or terminated. + */ +#define VM_ASSERT_VALID_EXT_RETURN(pVM, rc) \ + AssertMsgReturn( RT_VALID_ALIGNED_PTR(pVM, PAGE_SIZE) \ + && ( (unsigned)(pVM)->enmVMState < (unsigned)VMSTATE_DESTROYING \ + || ( (unsigned)(pVM)->enmVMState == (unsigned)VMSTATE_DESTROYING \ + && VM_IS_EMT(pVM))), \ + ("pVM=%p state %s\n", (pVM), RT_VALID_ALIGNED_PTR(pVM, PAGE_SIZE) \ + ? VMGetStateName(pVM->enmVMState) : ""), \ + (rc)) + +/** @def VMCPU_ASSERT_VALID_EXT_RETURN + * Asserts a the VMCPU handle is valid for external access, i.e. not being + * destroy or terminated. + */ +#define VMCPU_ASSERT_VALID_EXT_RETURN(pVCpu, rc) \ + AssertMsgReturn( RT_VALID_ALIGNED_PTR(pVCpu, 64) \ + && RT_VALID_ALIGNED_PTR((pVCpu)->CTX_SUFF(pVM), PAGE_SIZE) \ + && (unsigned)(pVCpu)->CTX_SUFF(pVM)->enmVMState < (unsigned)VMSTATE_DESTROYING, \ + ("pVCpu=%p pVM=%p state %s\n", (pVCpu), RT_VALID_ALIGNED_PTR(pVCpu, 64) ? (pVCpu)->CTX_SUFF(pVM) : NULL, \ + RT_VALID_ALIGNED_PTR(pVCpu, 64) && RT_VALID_ALIGNED_PTR((pVCpu)->CTX_SUFF(pVM), PAGE_SIZE) \ + ? VMGetStateName((pVCpu)->pVMR3->enmVMState) : ""), \ + (rc)) + +#endif /* !VBOX_FOR_DTRACE_LIB */ + + + +/** This is the VM structure. + * + * It contains (nearly?) all the VM data which have to be available in all + * contexts. Even if it contains all the data the idea is to use APIs not + * to modify all the members all around the place. Therefore we make use of + * unions to hide everything which isn't local to the current source module. + * This means we'll have to pay a little bit of attention when adding new + * members to structures in the unions and make sure to keep the padding sizes + * up to date. + * + * Run tstVMStructSize after update! + */ +typedef struct VM +{ + /** The state of the VM. + * This field is read only to everyone except the VM and EM. */ + VMSTATE volatile enmVMState; + /** Forced action flags. + * See the VM_FF_* \#defines. Updated atomically. + */ + volatile uint32_t fGlobalForcedActions; + /** Pointer to the array of page descriptors for the VM structure allocation. */ + R3PTRTYPE(PSUPPAGE) paVMPagesR3; + /** Session handle. For use when calling SUPR0 APIs. */ + PSUPDRVSESSION pSession; + /** Pointer to the ring-3 VM structure. */ + PUVM pUVM; + /** Ring-3 Host Context VM Pointer. */ + R3PTRTYPE(struct VM *) pVMR3; + /** Ring-0 Host Context VM Pointer. */ + R0PTRTYPE(struct VM *) pVMR0; + /** Raw-mode Context VM Pointer. */ + RCPTRTYPE(struct VM *) pVMRC; + + /** The GVM VM handle. Only the GVM should modify this field. */ + uint32_t hSelf; + /** Number of virtual CPUs. */ + uint32_t cCpus; + /** CPU excution cap (1-100) */ + uint32_t uCpuExecutionCap; + + /** Size of the VM structure including the VMCPU array. */ + uint32_t cbSelf; + + /** Offset to the VMCPU array starting from beginning of this structure. */ + uint32_t offVMCPU; + + /** + * VMMSwitcher assembly entry point returning to host context. + * + * Depending on how the host handles the rc status given in @a eax, this may + * return and let the caller resume whatever it was doing prior to the call. + * + * + * @param eax The return code, register. + * @remark Assume interrupts disabled. + * @remark This method pointer lives here because TRPM needs it. + */ + RTRCPTR pfnVMMRCToHostAsm/*(int32_t eax)*/; + + /** + * VMMSwitcher assembly entry point returning to host context without saving the + * raw-mode context (hyper) registers. + * + * Unlike pfnVMMRC2HCAsm, this will not return to the caller. Instead it + * expects the caller to save a RC context in CPUM where one might return if the + * return code indicate that this is possible. + * + * This method pointer lives here because TRPM needs it. + * + * @param eax The return code, register. + * @remark Assume interrupts disabled. + * @remark This method pointer lives here because TRPM needs it. + */ + RTRCPTR pfnVMMRCToHostAsmNoReturn/*(int32_t eax)*/; + + /** @name Various items that are frequently accessed. + * @{ */ + /** Whether to recompile user mode code or run it raw/hm. */ + bool fRecompileUser; + /** Whether to recompile supervisor mode code or run it raw/hm. */ + bool fRecompileSupervisor; + /** PATM enabled flag. + * This is placed here for performance reasons. */ + bool fPATMEnabled; + /** CSAM enabled flag. + * This is placed here for performance reasons. */ + bool fCSAMEnabled; + /** Hardware VM support is available and enabled. + * This is placed here for performance reasons. */ + bool fHWACCMEnabled; + /** Hardware VM support is required and non-optional. + * This is initialized together with the rest of the VM structure. */ + bool fHwVirtExtForced; + /** Set when this VM is the master FT node. */ + bool fFaultTolerantMaster; + /** Large page enabled flag. */ + bool fUseLargePages; + /** @} */ + + /** Alignment padding.. */ + uint32_t uPadding1; + + /** @name Debugging + * @{ */ + /** Raw-mode Context VM Pointer. */ + RCPTRTYPE(RTTRACEBUF) hTraceBufRC; + /** Ring-3 Host Context VM Pointer. */ + R3PTRTYPE(RTTRACEBUF) hTraceBufR3; + /** Ring-0 Host Context VM Pointer. */ + R0PTRTYPE(RTTRACEBUF) hTraceBufR0; + /** @} */ + +#if HC_ARCH_BITS == 32 + /** Alignment padding.. */ + uint32_t uPadding2; +#endif + + /** @name Switcher statistics (remove) + * @{ */ + /** Profiling the total time from Qemu to GC. */ + STAMPROFILEADV StatTotalQemuToGC; + /** Profiling the total time from GC to Qemu. */ + STAMPROFILEADV StatTotalGCToQemu; + /** Profiling the total time spent in GC. */ + STAMPROFILEADV StatTotalInGC; + /** Profiling the total time spent not in Qemu. */ + STAMPROFILEADV StatTotalInQemu; + /** Profiling the VMMSwitcher code for going to GC. */ + STAMPROFILEADV StatSwitcherToGC; + /** Profiling the VMMSwitcher code for going to HC. */ + STAMPROFILEADV StatSwitcherToHC; + STAMPROFILEADV StatSwitcherSaveRegs; + STAMPROFILEADV StatSwitcherSysEnter; + STAMPROFILEADV StatSwitcherDebug; + STAMPROFILEADV StatSwitcherCR0; + STAMPROFILEADV StatSwitcherCR4; + STAMPROFILEADV StatSwitcherJmpCR3; + STAMPROFILEADV StatSwitcherRstrRegs; + STAMPROFILEADV StatSwitcherLgdt; + STAMPROFILEADV StatSwitcherLidt; + STAMPROFILEADV StatSwitcherLldt; + STAMPROFILEADV StatSwitcherTSS; + /** @} */ + + /** Padding - the unions must be aligned on a 64 bytes boundary and the unions + * must start at the same offset on both 64-bit and 32-bit hosts. */ + uint8_t abAlignment3[(HC_ARCH_BITS == 32 ? 24 : 0) + 40]; + + /** CPUM part. */ + union + { +#ifdef ___CPUMInternal_h + struct CPUM s; +#endif + uint8_t padding[1536]; /* multiple of 64 */ + } cpum; + + /** VMM part. */ + union + { +#ifdef ___VMMInternal_h + struct VMM s; +#endif + uint8_t padding[1600]; /* multiple of 64 */ + } vmm; + + /** PGM part. */ + union + { +#ifdef ___PGMInternal_h + struct PGM s; +#endif + uint8_t padding[4096*2+6080]; /* multiple of 64 */ + } pgm; + + /** HWACCM part. */ + union + { +#ifdef ___HWACCMInternal_h + struct HWACCM s; +#endif + uint8_t padding[5376]; /* multiple of 64 */ + } hwaccm; + + /** TRPM part. */ + union + { +#ifdef ___TRPMInternal_h + struct TRPM s; +#endif + uint8_t padding[5248]; /* multiple of 64 */ + } trpm; + + /** SELM part. */ + union + { +#ifdef ___SELMInternal_h + struct SELM s; +#endif + uint8_t padding[768]; /* multiple of 64 */ + } selm; + + /** MM part. */ + union + { +#ifdef ___MMInternal_h + struct MM s; +#endif + uint8_t padding[192]; /* multiple of 64 */ + } mm; + + /** PDM part. */ + union + { +#ifdef ___PDMInternal_h + struct PDM s; +#endif + uint8_t padding[1920]; /* multiple of 64 */ + } pdm; + + /** IOM part. */ + union + { +#ifdef ___IOMInternal_h + struct IOM s; +#endif + uint8_t padding[832]; /* multiple of 64 */ + } iom; + + /** PATM part. */ + union + { +#ifdef ___PATMInternal_h + struct PATM s; +#endif + uint8_t padding[768]; /* multiple of 64 */ + } patm; + + /** CSAM part. */ + union + { +#ifdef ___CSAMInternal_h + struct CSAM s; +#endif + uint8_t padding[1088]; /* multiple of 64 */ + } csam; + + /** EM part. */ + union + { +#ifdef ___EMInternal_h + struct EM s; +#endif + uint8_t padding[256]; /* multiple of 64 */ + } em; + + /** TM part. */ + union + { +#ifdef ___TMInternal_h + struct TM s; +#endif + uint8_t padding[2432]; /* multiple of 64 */ + } tm; + + /** DBGF part. */ + union + { +#ifdef ___DBGFInternal_h + struct DBGF s; +#endif + uint8_t padding[2368]; /* multiple of 64 */ + } dbgf; + + /** SSM part. */ + union + { +#ifdef ___SSMInternal_h + struct SSM s; +#endif + uint8_t padding[128]; /* multiple of 64 */ + } ssm; + + /** FTM part. */ + union + { +#ifdef ___FTMInternal_h + struct FTM s; +#endif + uint8_t padding[512]; /* multiple of 64 */ + } ftm; + + /** REM part. */ + union + { +#ifdef ___REMInternal_h + struct REM s; +#endif + uint8_t padding[0x11100]; /* multiple of 64 */ + } rem; + + /* ---- begin small stuff ---- */ + + /** VM part. */ + union + { +#ifdef ___VMInternal_h + struct VMINT s; +#endif + uint8_t padding[24]; /* multiple of 8 */ + } vm; + + /** CFGM part. */ + union + { +#ifdef ___CFGMInternal_h + struct CFGM s; +#endif + uint8_t padding[8]; /* multiple of 8 */ + } cfgm; + + + /** Padding for aligning the cpu array on a page boundary. */ + uint8_t abAlignment2[542]; + + /* ---- end small stuff ---- */ + + /** VMCPU array for the configured number of virtual CPUs. + * Must be aligned on a page boundary for TLB hit reasons as well as + * alignment of VMCPU members. */ + VMCPU aCpus[1]; +} VM; + + +#ifdef IN_RC +RT_C_DECLS_BEGIN + +/** The VM structure. + * This is imported from the VMMGCBuiltin module, i.e. it's a one + * of those magic globals which we should avoid using. + */ +extern DECLIMPORT(VM) g_VM; + +RT_C_DECLS_END +#endif + +/** @} */ + +#endif + diff --git a/include/VBox/vmm/vm.mac b/include/VBox/vmm/vm.mac new file mode 100644 index 00000000..6d65b0c9 --- /dev/null +++ b/include/VBox/vmm/vm.mac @@ -0,0 +1,150 @@ +;; @file +; VM - The Virtual Machine. +; + +; +; Copyright (C) 2006-2012 Oracle Corporation +; +; 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 (GPL) 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. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%ifndef ___VBox_vmm_vm_mac +%define ___VBox_vmm_vm_mac + +%include "VBox/vmm/stam.mac" + +;/** This action forces the VM to service check and pending interrups on the APIC. */ +%define VMCPU_FF_INTERRUPT_APIC (1 << 0) +;/** This action forces the VM to service check and pending interrups on the PIC. */ +%define VMCPU_FF_INTERRUPT_PIC (1 << 1) +;/** This action forces the VM to schedule and run pending timer (TM). */ +%define VMCPU_FF_TIMER (1 << 2) +;/** This action forces the VM to service pending requests from other +; * thread or requests which must be executed in another context. */ +%define VMCPU_FF_REQUEST (1 << 9) + +;; +; This is part of the VM structure. +struc VM + .enmVMState resd 1 + .fGlobalForcedActions resd 1 + .paVMPagesR3 RTR3PTR_RES 1 + .pSession RTR0PTR_RES 1 + .pUVM RTR3PTR_RES 1 + .pVMR3 RTR3PTR_RES 1 + .pVMR0 RTR0PTR_RES 1 + .pVMRC RTRCPTR_RES 1 + .hSelf resd 1 + .cCpus resd 1 + .uCpuExecutionCap resd 1 + .cbSelf resd 1 + .offVMCPU resd 1 + .pfnVMMRCToHostAsm resd 1 + .pfnVMMRCToHostAsmNoReturn resd 1 + .fRecompileUser resb 1 + .fRecompileSupervisor resb 1 + .fPATMEnabled resb 1 + .fCSAMEnabled resb 1 + .fHWACCMEnabled resb 1 + .fHwVirtExtForced resb 1 + .fFaultTolerantMaster resb 1 + .fUseLargePages resb 1 + + .uPadding1 resd 1 + + .hTraceBufRC RTRCPTR_RES 1 + .hTraceBufR3 RTR3PTR_RES 1 + .hTraceBufR0 RTR0PTR_RES 1 + + alignb 8 + + .StatTotalQemuToGC resb STAMPROFILEADV_size + .StatTotalGCToQemu resb STAMPROFILEADV_size + .StatTotalInGC resb STAMPROFILEADV_size + .StatTotalInQemu resb STAMPROFILEADV_size + .StatSwitcherToGC resb STAMPROFILEADV_size + .StatSwitcherToHC resb STAMPROFILEADV_size + .StatSwitcherSaveRegs resb STAMPROFILEADV_size + .StatSwitcherSysEnter resb STAMPROFILEADV_size + .StatSwitcherDebug resb STAMPROFILEADV_size + .StatSwitcherCR0 resb STAMPROFILEADV_size + .StatSwitcherCR4 resb STAMPROFILEADV_size + .StatSwitcherJmpCR3 resb STAMPROFILEADV_size + .StatSwitcherRstrRegs resb STAMPROFILEADV_size + .StatSwitcherLgdt resb STAMPROFILEADV_size + .StatSwitcherLidt resb STAMPROFILEADV_size + .StatSwitcherLldt resb STAMPROFILEADV_size + .StatSwitcherTSS resb STAMPROFILEADV_size + +%ifndef HC_ARCH_BITS + %error "Missing HC_ARCH_BITS" +%endif +%if HC_ARCH_BITS == 32 + .abAlignment3 resb 16 +%else +; .abAlignment3 resb 16 +%endif + + alignb 64 + .cpum resb 1536 + .vmm resb 1536 + +endstruc + +;; +; This is part of the VMCPU structure. +struc VMCPU + .fLocalForcedActions resd 1 + .enmState resd 1 + .pUVCpu RTR3PTR_RES 1 + .pVMR3 RTR3PTR_RES 1 + .pVMR0 RTR0PTR_RES 1 + .pVMRC RTRCPTR_RES 1 + .idCpu resd 1 + + .hNativeThread RTR0PTR_RES 1 + .hNativeThreadR0 RTR0PTR_RES 1 + .idHostCpu resd 1 + .fTraceGroups resd 1 +%if HC_ARCH_BITS == 32 + .abAlignment1 resb 16+64 +%else + .abAlignment1 resb 60 +%endif + .uAdHoc resd 1 + .aStatAdHoc resb STAMPROFILEADV_size * 8 + + alignb 64 + + .cpum resb 3584 + .hwaccm resb 5376 + .em resb 1472 + .iem resb 3072 + .trpm resb 128 + .tm resb 384 + .vmm resb 640 + .pdm resb 128 + .iom resb 512 + .dbgf resb 64 + alignb 4096 + .pgm resb 4096 +endstruc + + +%endif + diff --git a/include/VBox/vmm/vmapi.h b/include/VBox/vmm/vmapi.h new file mode 100644 index 00000000..b15fc7f6 --- /dev/null +++ b/include/VBox/vmm/vmapi.h @@ -0,0 +1,441 @@ +/** @file + * VM - The Virtual Machine, API. + */ + +/* + * Copyright (C) 2006-2010 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_vmapi_h +#define ___VBox_vmm_vmapi_h + +#include <VBox/types.h> +#include <VBox/vmm/stam.h> +#include <VBox/vmm/cfgm.h> + +#include <iprt/stdarg.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_vmm_apis VM All Contexts API + * @ingroup grp_vm + * @{ */ + +/** @def VM_RC_ADDR + * Converts a current context address of data within the VM structure to the equivalent + * raw-mode address. + * + * @returns raw-mode virtual address. + * @param pVM Pointer to the VM. + * @param pvInVM CC Pointer within the VM. + */ +#ifdef IN_RING3 +# define VM_RC_ADDR(pVM, pvInVM) ( (RTRCPTR)((RTRCUINTPTR)pVM->pVMRC + (uint32_t)((uintptr_t)(pvInVM) - (uintptr_t)pVM->pVMR3)) ) +#elif defined(IN_RING0) +# define VM_RC_ADDR(pVM, pvInVM) ( (RTRCPTR)((RTRCUINTPTR)pVM->pVMRC + (uint32_t)((uintptr_t)(pvInVM) - (uintptr_t)pVM->pVMR0)) ) +#else +# define VM_RC_ADDR(pVM, pvInVM) ( (RTRCPTR)(pvInVM) ) +#endif + +/** @def VM_R3_ADDR + * Converts a current context address of data within the VM structure to the equivalent + * ring-3 host address. + * + * @returns host virtual address. + * @param pVM Pointer to the VM. + * @param pvInVM CC pointer within the VM. + */ +#ifdef IN_RC +# define VM_R3_ADDR(pVM, pvInVM) ( (RTR3PTR)((RTR3UINTPTR)pVM->pVMR3 + (uint32_t)((uintptr_t)(pvInVM) - (uintptr_t)pVM->pVMRC)) ) +#elif defined(IN_RING0) +# define VM_R3_ADDR(pVM, pvInVM) ( (RTR3PTR)((RTR3UINTPTR)pVM->pVMR3 + (uint32_t)((uintptr_t)(pvInVM) - (uintptr_t)pVM->pVMR0)) ) +#else +# define VM_R3_ADDR(pVM, pvInVM) ( (RTR3PTR)(pvInVM) ) +#endif + + +/** @def VM_R0_ADDR + * Converts a current context address of data within the VM structure to the equivalent + * ring-0 host address. + * + * @returns host virtual address. + * @param pVM Pointer to the VM. + * @param pvInVM CC pointer within the VM. + */ +#ifdef IN_RC +# define VM_R0_ADDR(pVM, pvInVM) ( (RTR0PTR)((RTR0UINTPTR)pVM->pVMR0 + (uint32_t)((uintptr_t)(pvInVM) - (uintptr_t)pVM->pVMRC)) ) +#elif defined(IN_RING3) +# define VM_R0_ADDR(pVM, pvInVM) ( (RTR0PTR)((RTR0UINTPTR)pVM->pVMR0 + (uint32_t)((uintptr_t)(pvInVM) - (uintptr_t)pVM->pVMR3)) ) +#else +# define VM_R0_ADDR(pVM, pvInVM) ( (RTR0PTR)(pvInVM) ) +#endif + + + +/** + * VM error callback function. + * + * @param pVM The VM handle. Can be NULL if an error occurred before + * successfully creating a VM. + * @param pvUser The user argument. + * @param rc VBox status code. + * @param RT_SRC_POS_DECL The source position arguments. See RT_SRC_POS and RT_SRC_POS_ARGS. + * @param pszFormat Error message format string. + * @param args Error message arguments. + */ +typedef DECLCALLBACK(void) FNVMATERROR(PVM pVM, void *pvUser, int rc, RT_SRC_POS_DECL, const char *pszError, va_list args); +/** Pointer to a VM error callback. */ +typedef FNVMATERROR *PFNVMATERROR; + +VMMDECL(int) VMSetError(PVM pVM, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...); +VMMDECL(int) VMSetErrorV(PVM pVM, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list args); + +/** @def VM_SET_ERROR + * Macro for setting a simple VM error message. + * Don't use '%' in the message! + * + * @returns rc. Meaning you can do: + * @code + * return VM_SET_ERROR(pVM, VERR_OF_YOUR_CHOICE, "descriptive message"); + * @endcode + * @param pVM VM handle. + * @param rc VBox status code. + * @param pszMessage Error message string. + * @thread Any + */ +#define VM_SET_ERROR(pVM, rc, pszMessage) (VMSetError(pVM, rc, RT_SRC_POS, pszMessage)) + + +/** + * VM runtime error callback function. + * + * See VMSetRuntimeError for the detailed description of parameters. + * + * @param pVM The VM handle. + * @param pvUser The user argument. + * @param fFlags The error flags. + * @param pszErrorId Error ID string. + * @param pszFormat Error message format string. + * @param va Error message arguments. + */ +typedef DECLCALLBACK(void) FNVMATRUNTIMEERROR(PVM pVM, void *pvUser, uint32_t fFlags, const char *pszErrorId, + const char *pszFormat, va_list va); +/** Pointer to a VM runtime error callback. */ +typedef FNVMATRUNTIMEERROR *PFNVMATRUNTIMEERROR; + +VMMDECL(int) VMSetRuntimeError(PVM pVM, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...); +VMMDECL(int) VMSetRuntimeErrorV(PVM pVM, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, va_list args); + +/** @name VMSetRuntimeError fFlags + * When no flags are given the VM will continue running and it's up to the front + * end to take action on the error condition. + * + * @{ */ +/** The error is fatal. + * The VM is not in a state where it can be saved and will enter a state + * where it can no longer execute code. The caller <b>must</b> propagate status + * codes. */ +#define VMSETRTERR_FLAGS_FATAL RT_BIT_32(0) +/** Suspend the VM after, or if possible before, raising the error on EMT. The + * caller <b>must</b> propagate status codes. */ +#define VMSETRTERR_FLAGS_SUSPEND RT_BIT_32(1) +/** Don't wait for the EMT to handle the request. + * Only valid when on a worker thread and there is a high risk of a dead + * lock. Be careful not to flood the user with errors. */ +#define VMSETRTERR_FLAGS_NO_WAIT RT_BIT_32(2) +/** @} */ + +/** + * VM state callback function. + * + * You are not allowed to call any function which changes the VM state from a + * state callback, except VMR3Destroy(). + * + * @param pVM The VM handle. + * @param enmState The new state. + * @param enmOldState The old state. + * @param pvUser The user argument. + */ +typedef DECLCALLBACK(void) FNVMATSTATE(PVM pVM, VMSTATE enmState, VMSTATE enmOldState, void *pvUser); +/** Pointer to a VM state callback. */ +typedef FNVMATSTATE *PFNVMATSTATE; + +VMMDECL(const char *) VMGetStateName(VMSTATE enmState); + + +/** + * Request type. + */ +typedef enum VMREQTYPE +{ + /** Invalid request. */ + VMREQTYPE_INVALID = 0, + /** VM: Internal. */ + VMREQTYPE_INTERNAL, + /** Maximum request type (exclusive). Used for validation. */ + VMREQTYPE_MAX +} VMREQTYPE; + +/** + * Request state. + */ +typedef enum VMREQSTATE +{ + /** The state is invalid. */ + VMREQSTATE_INVALID = 0, + /** The request have been allocated and is in the process of being filed. */ + VMREQSTATE_ALLOCATED, + /** The request is queued by the requester. */ + VMREQSTATE_QUEUED, + /** The request is begin processed. */ + VMREQSTATE_PROCESSING, + /** The request is completed, the requester is begin notified. */ + VMREQSTATE_COMPLETED, + /** The request packet is in the free chain. (The requester */ + VMREQSTATE_FREE +} VMREQSTATE; + +/** + * Request flags. + */ +typedef enum VMREQFLAGS +{ + /** The request returns a VBox status code. */ + VMREQFLAGS_VBOX_STATUS = 0, + /** The request is a void request and have no status code. */ + VMREQFLAGS_VOID = 1, + /** Return type mask. */ + VMREQFLAGS_RETURN_MASK = 1, + /** Caller does not wait on the packet, EMT will free it. */ + VMREQFLAGS_NO_WAIT = 2, + /** Poke the destination EMT(s) if executing guest code. Use with care. */ + VMREQFLAGS_POKE = 4, + /** Priority request that can safely be processed while doing async + * suspend and power off. */ + VMREQFLAGS_PRIORITY = 8 +} VMREQFLAGS; + + +/** + * VM Request packet. + * + * This is used to request an action in the EMT. Usually the requester is + * another thread, but EMT can also end up being the requester in which case + * it's carried out synchronously. + */ +typedef struct VMREQ +{ + /** Pointer to the next request in the chain. */ + struct VMREQ * volatile pNext; + /** Pointer to ring-3 VM structure which this request belongs to. */ + PUVM pUVM; + /** Request state. */ + volatile VMREQSTATE enmState; + /** VBox status code for the completed request. */ + volatile int32_t iStatus; + /** Requester event sem. + * The request can use this event semaphore to wait/poll for completion + * of the request. + */ + RTSEMEVENT EventSem; + /** Set if the event semaphore is clear. */ + volatile bool fEventSemClear; + /** Flags, VMR3REQ_FLAGS_*. */ + unsigned fFlags; + /** Request type. */ + VMREQTYPE enmType; + /** Request destination. */ + VMCPUID idDstCpu; + /** Request specific data. */ + union VMREQ_U + { + /** VMREQTYPE_INTERNAL. */ + struct + { + /** Pointer to the function to be called. */ + PFNRT pfn; + /** Number of arguments. */ + unsigned cArgs; + /** Array of arguments. */ + uintptr_t aArgs[64]; + } Internal; + } u; +} VMREQ; +/** Pointer to a VM request packet. */ +typedef VMREQ *PVMREQ; + +/** @} */ + + +#ifndef IN_RC +/** @defgroup grp_vmm_apis_hc VM Host Context API + * @ingroup grp_vm + * @{ */ + +/** @} */ +#endif + + +#ifdef IN_RING3 +/** @defgroup grp_vmm_apis_r3 VM Host Context Ring 3 API + * This interface is a _draft_! + * @ingroup grp_vm + * @{ */ + +/** + * Completion notification codes. + */ +typedef enum VMINITCOMPLETED +{ + /** The ring-3 init is completed. */ + VMINITCOMPLETED_RING3 = 1, + /** The ring-0 init is completed. */ + VMINITCOMPLETED_RING0, + /** The hardware accelerated virtualization init is completed. + * Used to make decisision depending on whether HWACCMIsEnabled(). */ + VMINITCOMPLETED_HWACCM, + /** The GC init is completed. */ + VMINITCOMPLETED_GC +} VMINITCOMPLETED; + + +VMMR3DECL(int) VMR3Create(uint32_t cCpus, PCVMM2USERMETHODS pVm2UserCbs, + PFNVMATERROR pfnVMAtError, void *pvUserVM, + PFNCFGMCONSTRUCTOR pfnCFGMConstructor, void *pvUserCFGM, + PVM *ppVM); +VMMR3DECL(int) VMR3PowerOn(PVM pVM); +VMMR3DECL(int) VMR3Suspend(PVM pVM); +VMMR3DECL(int) VMR3Resume(PVM pVM); +VMMR3DECL(int) VMR3Reset(PVM pVM); + +/** + * Progress callback. + * This will report the completion percentage of an operation. + * + * @returns VINF_SUCCESS. + * @returns Error code to cancel the operation with. + * @param pVM The VM handle. + * @param uPercent Completion percentage (0-100). + * @param pvUser User specified argument. + */ +typedef DECLCALLBACK(int) FNVMPROGRESS(PVM pVM, unsigned uPercent, void *pvUser); +/** Pointer to a FNVMPROGRESS function. */ +typedef FNVMPROGRESS *PFNVMPROGRESS; + +VMMR3DECL(int) VMR3Save(PVM pVM, const char *pszFilename, bool fContinueAfterwards, PFNVMPROGRESS pfnProgress, void *pvUser, bool *pfSuspended); +VMMR3DECL(int) VMR3Teleport(PVM pVM, uint32_t cMsDowntime, PCSSMSTRMOPS pStreamOps, void *pvStreamOpsUser, PFNVMPROGRESS pfnProgress, void *pvProgressUser, bool *pfSuspended); +VMMR3DECL(int) VMR3LoadFromFile(PVM pVM, const char *pszFilename, PFNVMPROGRESS pfnProgress, void *pvUser); +VMMR3DECL(int) VMR3LoadFromStream(PVM pVM, PCSSMSTRMOPS pStreamOps, void *pvStreamOpsUser, + PFNVMPROGRESS pfnProgress, void *pvProgressUser); +VMMR3DECL(int) VMR3PowerOff(PVM pVM); +VMMR3DECL(int) VMR3Destroy(PVM pVM); +VMMR3DECL(void) VMR3Relocate(PVM pVM, RTGCINTPTR offDelta); +VMMR3DECL(PVM) VMR3EnumVMs(PVM pVMPrev); + +VMMR3DECL(PVM) VMR3GetVM(PUVM pUVM); +VMMR3DECL(PUVM) VMR3GetUVM(PVM pVM); +VMMR3DECL(uint32_t) VMR3RetainUVM(PUVM pUVM); +VMMR3DECL(uint32_t) VMR3ReleaseUVM(PUVM pUVM); +VMMR3DECL(const char *) VMR3GetName(PUVM pUVM); +VMMR3DECL(PRTUUID) VMR3GetUuid(PUVM pUVM, PRTUUID pUuid); +VMMR3DECL(VMSTATE) VMR3GetState(PVM pVM); +VMMR3DECL(VMSTATE) VMR3GetStateU(PUVM pUVM); +VMMR3DECL(const char *) VMR3GetStateName(VMSTATE enmState); + +/** + * VM destruction callback. + * @param pVM The VM which is about to be destroyed. + * @param pvUser The user parameter specified at registration. + */ +typedef DECLCALLBACK(void) FNVMATDTOR(PVM pVM, void *pvUser); +/** Pointer to a VM destruction callback. */ +typedef FNVMATDTOR *PFNVMATDTOR; + +VMMR3DECL(int) VMR3AtDtorRegister(PFNVMATDTOR pfnAtDtor, void *pvUser); +VMMR3DECL(int) VMR3AtDtorDeregister(PFNVMATDTOR pfnAtDtor); +VMMR3DECL(int) VMR3AtStateRegister(PVM pVM, PFNVMATSTATE pfnAtState, void *pvUser); +VMMR3DECL(int) VMR3AtStateDeregister(PVM pVM, PFNVMATSTATE pfnAtState, void *pvUser); +VMMR3DECL(bool) VMR3TeleportedAndNotFullyResumedYet(PVM pVM); +VMMR3DECL(int) VMR3AtErrorRegister(PVM pVM, PFNVMATERROR pfnAtError, void *pvUser); +VMMR3DECL(int) VMR3AtErrorRegisterU(PUVM pVM, PFNVMATERROR pfnAtError, void *pvUser); +VMMR3DECL(int) VMR3AtErrorDeregister(PVM pVM, PFNVMATERROR pfnAtError, void *pvUser); +VMMR3DECL(void) VMR3SetErrorWorker(PVM pVM); +VMMR3DECL(uint32_t) VMR3GetErrorCount(PVM pVM); +VMMR3DECL(uint32_t) VMR3GetErrorCountU(PUVM pUVM); +VMMR3DECL(int) VMR3AtRuntimeErrorRegister(PVM pVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser); +VMMR3DECL(int) VMR3AtRuntimeErrorDeregister(PVM pVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser); +VMMR3DECL(int) VMR3SetRuntimeErrorWorker(PVM pVM); +VMMR3DECL(uint32_t) VMR3GetRuntimeErrorCount(PVM pVM); +VMMR3DECL(int) VMR3ReqCall(PVM pVM, VMCPUID idDstCpu, PVMREQ *ppReq, RTMSINTERVAL cMillies, uint32_t fFlags, PFNRT pfnFunction, unsigned cArgs, ...); +VMMR3DECL(int) VMR3ReqCallU(PUVM pUVM, VMCPUID idDstCpu, PVMREQ *ppReq, RTMSINTERVAL cMillies, uint32_t fFlags, PFNRT pfnFunction, unsigned cArgs, ...); +VMMR3DECL(int) VMR3ReqCallVU(PUVM pUVM, VMCPUID idDstCpu, PVMREQ *ppReq, RTMSINTERVAL cMillies, uint32_t fFlags, PFNRT pfnFunction, unsigned cArgs, va_list Args); +VMMR3DECL(int) VMR3ReqCallWait(PVM pVM, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...); +VMMR3DECL(int) VMR3ReqCallNoWait(PVM pVM, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...); +VMMR3DECL(int) VMR3ReqCallVoidWait(PVM pVM, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...); +VMMR3DECL(int) VMR3ReqCallVoidNoWait(PVM pVM, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...); +VMMR3DECL(int) VMR3ReqPriorityCallWait(PVM pVM, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...); +VMMR3DECL(int) VMR3ReqPriorityCallVoidWait(PVM pVM, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...); +VMMR3DECL(int) VMR3ReqAlloc(PVM pVM, PVMREQ *ppReq, VMREQTYPE enmType, VMCPUID idDstCpu); +VMMR3DECL(int) VMR3ReqAllocU(PUVM pUVM, PVMREQ *ppReq, VMREQTYPE enmType, VMCPUID idDstCpu); +VMMR3DECL(int) VMR3ReqFree(PVMREQ pReq); +VMMR3DECL(int) VMR3ReqQueue(PVMREQ pReq, RTMSINTERVAL cMillies); +VMMR3DECL(int) VMR3ReqWait(PVMREQ pReq, RTMSINTERVAL cMillies); +VMMR3DECL(int) VMR3ReqProcessU(PUVM pUVM, VMCPUID idDstCpu, bool fPriorityOnly); +VMMR3DECL(void) VMR3NotifyGlobalFFU(PUVM pUVM, uint32_t fFlags); +VMMR3DECL(void) VMR3NotifyCpuFFU(PUVMCPU pUVMCpu, uint32_t fFlags); +/** @name Flags for VMR3NotifyCpuFFU and VMR3NotifyGlobalFFU. + * @{ */ +/** Whether we've done REM or not. */ +#define VMNOTIFYFF_FLAGS_DONE_REM RT_BIT_32(0) +/** Whether we should poke the CPU if it's executing guest code. */ +#define VMNOTIFYFF_FLAGS_POKE RT_BIT_32(1) +/** @} */ + +VMMR3DECL(int) VMR3WaitHalted(PVM pVM, PVMCPU pVCpu, bool fIgnoreInterrupts); +VMMR3DECL(int) VMR3WaitU(PUVMCPU pUVMCpu); +VMMR3_INT_DECL(int) VMR3AsyncPdmNotificationWaitU(PUVMCPU pUVCpu); +VMMR3_INT_DECL(void) VMR3AsyncPdmNotificationWakeupU(PUVM pUVM); +VMMR3DECL(RTCPUID) VMR3GetVMCPUId(PVM pVM); +VMMR3DECL(RTTHREAD) VMR3GetVMCPUThread(PVM pVM); +VMMR3DECL(RTTHREAD) VMR3GetVMCPUThreadU(PUVM pUVM); +VMMR3DECL(RTNATIVETHREAD) VMR3GetVMCPUNativeThread(PVM pVM); +VMMR3DECL(RTNATIVETHREAD) VMR3GetVMCPUNativeThreadU(PUVM pUVM); +VMMR3DECL(int) VMR3GetCpuCoreAndPackageIdFromCpuId(PVM pVM, VMCPUID idCpu, uint32_t *pidCpuCore, uint32_t *pidCpuPackage); +VMMR3DECL(int) VMR3HotUnplugCpu(PVM pVM, VMCPUID idCpu); +VMMR3DECL(int) VMR3HotPlugCpu(PVM pVM, VMCPUID idCpu); +VMMR3DECL(int) VMR3SetCpuExecutionCap(PVM pVM, uint32_t uCpuExecutionCap); +/** @} */ +#endif /* IN_RING3 */ + + +#ifdef IN_RC +/** @defgroup grp_vmm_apis_gc VM Guest Context APIs + * @ingroup grp_vm + * @{ */ + +/** @} */ +#endif + +RT_C_DECLS_END + +/** @} */ + +#endif + diff --git a/include/VBox/vmm/vmcpuset.h b/include/VBox/vmm/vmcpuset.h new file mode 100644 index 00000000..8d92dbb5 --- /dev/null +++ b/include/VBox/vmm/vmcpuset.h @@ -0,0 +1,107 @@ +/** @file + * VirtualBox - VMCPUSET Operation. + */ + +/* + * Copyright (C) 2006-2011 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_vmcpuset_h +#define ___VBox_vmm_vmcpuset_h + +#include <VBox/types.h> +#include <iprt/asm.h> +#include <iprt/string.h> + +/** @defgroup grp_vmcpuset VMCPUSET Operations + * @ingroup grp_types_both + * @sa VMCPUSET + * @{ + */ + +/** Tests if a valid CPU ID is present in the set.. */ +#define VMCPUSET_IS_PRESENT(pSet, idCpu) ASMBitTest( &(pSet)->au32Bitmap[0], (idCpu)) +/** Adds a CPU to the set. */ +#define VMCPUSET_ADD(pSet, idCpu) ASMBitSet( &(pSet)->au32Bitmap[0], (idCpu)) +/** Deletes a CPU from the set. */ +#define VMCPUSET_DEL(pSet, idCpu) ASMBitClear(&(pSet)->au32Bitmap[0], (idCpu)) +/** Empties the set. */ +#define VMCPUSET_EMPTY(pSet) memset(&(pSet)->au32Bitmap[0], '\0', sizeof((pSet)->au32Bitmap)) +/** Fills the set. */ +#define VMCPUSET_FILL(pSet) memset(&(pSet)->au32Bitmap[0], 0xff, sizeof((pSet)->au32Bitmap)) +/** Checks if two sets are equal to one another. */ +#define VMCPUSET_IS_EQUAL(pSet1, pSet2) (memcmp(&(pSet1)->au32Bitmap[0], &(pSet2)->au32Bitmap[0], sizeof((pSet1)->au32Bitmap)) == 0) +/** Checks if the set is empty. */ +#define VMCPUSET_IS_EMPTY(a_pSet) ( (a_pSet)->au32Bitmap[0] == 0 \ + && (a_pSet)->au32Bitmap[1] == 0 \ + && (a_pSet)->au32Bitmap[2] == 0 \ + && (a_pSet)->au32Bitmap[3] == 0 \ + && (a_pSet)->au32Bitmap[4] == 0 \ + && (a_pSet)->au32Bitmap[5] == 0 \ + && (a_pSet)->au32Bitmap[6] == 0 \ + && (a_pSet)->au32Bitmap[7] == 0 \ + ) +/** Finds the first CPU present in the SET. + * @returns CPU index if found, NIL_VMCPUID if not. */ +#define VMCPUSET_FIND_FIRST_PRESENT(a_pSet) VMCpuSetFindFirstPresentInternal(a_pSet) + +/** Implements VMCPUSET_FIND_FIRST_PRESENT. + * + * @returns CPU index of the first CPU present in the set, NIL_VMCPUID if none + * are present. + * @param pSet The set to scan. + */ +DECLINLINE(int32_t) VMCpuSetFindFirstPresentInternal(PCVMCPUSET pSet) +{ + int i = ASMBitFirstSet(&pSet->au32Bitmap[0], RT_ELEMENTS(pSet->au32Bitmap) * 32); + return i >= 0 ? (VMCPUID)i : NIL_VMCPUID; +} + +/** Finds the first CPU present in the SET. + * @returns CPU index if found, NIL_VMCPUID if not. */ +#define VMCPUSET_FIND_LAST_PRESENT(a_pSet) VMCpuSetFindLastPresentInternal(a_pSet) + +/** Implements VMCPUSET_FIND_LAST_PRESENT. + * + * @returns CPU index of the last CPU present in the set, NIL_VMCPUID if none + * are present. + * @param pSet The set to scan. + */ +DECLINLINE(int32_t) VMCpuSetFindLastPresentInternal(PCVMCPUSET pSet) +{ + uint32_t i = RT_ELEMENTS(pSet->au32Bitmap); + while (i-- > 0) + { + uint32_t u = pSet->au32Bitmap[i]; + if (u) + { + u = ASMBitLastSetU32(u); + u--; + u |= i << 5; + return u; + } + } + return NIL_VMCPUID; +} + +/** @ */ + +#endif + diff --git a/include/VBox/vmm/vmm.h b/include/VBox/vmm/vmm.h new file mode 100644 index 00000000..e3af0c29 --- /dev/null +++ b/include/VBox/vmm/vmm.h @@ -0,0 +1,522 @@ +/** @file + * VMM - The Virtual Machine Monitor. + */ + +/* + * Copyright (C) 2006-2010 Oracle Corporation + * + * 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 (GPL) 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. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_vmm_vmm_h +#define ___VBox_vmm_vmm_h + +#include <VBox/types.h> +#include <VBox/vmm/vmapi.h> +#include <VBox/sup.h> +#include <VBox/log.h> +#include <iprt/stdarg.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_vmm The Virtual Machine Monitor API + * @{ + */ + +/** + * World switcher identifiers. + */ +typedef enum VMMSWITCHER +{ + /** The usual invalid 0. */ + VMMSWITCHER_INVALID = 0, + /** Switcher for 32-bit host to 32-bit shadow paging. */ + VMMSWITCHER_32_TO_32, + /** Switcher for 32-bit host paging to PAE shadow paging. */ + VMMSWITCHER_32_TO_PAE, + /** Switcher for 32-bit host paging to AMD64 shadow paging. */ + VMMSWITCHER_32_TO_AMD64, + /** Switcher for PAE host to 32-bit shadow paging. */ + VMMSWITCHER_PAE_TO_32, + /** Switcher for PAE host to PAE shadow paging. */ + VMMSWITCHER_PAE_TO_PAE, + /** Switcher for PAE host paging to AMD64 shadow paging. */ + VMMSWITCHER_PAE_TO_AMD64, + /** Switcher for AMD64 host paging to 32-bit shadow paging. */ + VMMSWITCHER_AMD64_TO_32, + /** Switcher for AMD64 host paging to PAE shadow paging. */ + VMMSWITCHER_AMD64_TO_PAE, + /** Switcher for AMD64 host paging to AMD64 shadow paging. */ + VMMSWITCHER_AMD64_TO_AMD64, + /** Used to make a count for array declarations and suchlike. */ + VMMSWITCHER_MAX, + /** The usual 32-bit paranoia. */ + VMMSWITCHER_32BIT_HACK = 0x7fffffff +} VMMSWITCHER; + + +/** + * VMMRZCallRing3 operations. + */ +typedef enum VMMCALLRING3 +{ + /** Invalid operation. */ + VMMCALLRING3_INVALID = 0, + /** Acquire the PDM lock. */ + VMMCALLRING3_PDM_LOCK, + /** Acquire the critical section specified as argument. */ + VMMCALLRING3_PDM_CRIT_SECT_ENTER, + /** Acquire the PGM lock. */ + VMMCALLRING3_PGM_LOCK, + /** Grow the PGM shadow page pool. */ + VMMCALLRING3_PGM_POOL_GROW, + /** Maps a chunk into ring-3. */ + VMMCALLRING3_PGM_MAP_CHUNK, + /** Allocates more handy pages. */ + VMMCALLRING3_PGM_ALLOCATE_HANDY_PAGES, + /** Allocates a large (2MB) page. */ + VMMCALLRING3_PGM_ALLOCATE_LARGE_HANDY_PAGE, + /** Acquire the MM hypervisor heap lock. */ + VMMCALLRING3_MMHYPER_LOCK, + /** Replay the REM handler notifications. */ + VMMCALLRING3_REM_REPLAY_HANDLER_NOTIFICATIONS, + /** Flush the GC/R0 logger. */ + VMMCALLRING3_VMM_LOGGER_FLUSH, + /** Set the VM error message. */ + VMMCALLRING3_VM_SET_ERROR, + /** Set the VM runtime error message. */ + VMMCALLRING3_VM_SET_RUNTIME_ERROR, + /** Signal a ring 0 assertion. */ + VMMCALLRING3_VM_R0_ASSERTION, + /** Ring switch to force preemption. */ + VMMCALLRING3_VM_R0_PREEMPT, + /** Sync the FTM state with the standby node. */ + VMMCALLRING3_FTM_SET_CHECKPOINT, + /** The usual 32-bit hack. */ + VMMCALLRING3_32BIT_HACK = 0x7fffffff +} VMMCALLRING3; + +/** + * VMMR3AtomicExecuteHandler callback function. + * + * @returns VBox status code. + * @param pVM Pointer to the shared VM structure. + * @param pvUser User specified argument + * + * @todo missing prefix. + */ +typedef DECLCALLBACK(int) FNATOMICHANDLER(PVM pVM, void *pvUser); +/** Pointer to a FNMMATOMICHANDLER(). */ +typedef FNATOMICHANDLER *PFNATOMICHANDLER; + +/** + * Rendezvous callback. + * + * @returns VBox strict status code - EM scheduling. Do not return + * informational status code other than the ones used by EM for + * scheduling. + * + * @param pVM The VM handle. + * @param pVCpu The handle of the calling virtual CPU. + * @param pvUser The user argument. + */ +typedef DECLCALLBACK(VBOXSTRICTRC) FNVMMEMTRENDEZVOUS(PVM pVM, PVMCPU pVCpu, void *pvUser); +/** Pointer to a rendezvous callback function. */ +typedef FNVMMEMTRENDEZVOUS *PFNVMMEMTRENDEZVOUS; + +/** + * Method table that the VMM uses to call back the user of the VMM. + */ +typedef struct VMM2USERMETHODS +{ + /** Magic value (VMM2USERMETHODS_MAGIC). */ + uint32_t u32Magic; + /** Structure version (VMM2USERMETHODS_VERSION). */ + uint32_t u32Version; + + /** + * Save the VM state. + * + * @returns VBox status code. + * @param pThis Pointer to the callback method table. + * @param pUVM The user mode VM handle. + * + * @remarks This member shall be set to NULL if the operation is not + * supported. + */ + DECLR3CALLBACKMEMBER(int, pfnSaveState,(PCVMM2USERMETHODS pThis, PUVM pUVM)); + /** @todo Move pfnVMAtError and pfnCFGMConstructor here? */ + + /** + * EMT initialization notification callback. + * + * This is intended for doing per-thread initialization for EMTs (like COM + * init). + * + * @param pThis Pointer to the callback method table. + * @param pUVM The user mode VM handle. + * @param pUVCpu The user mode virtual CPU handle. + * + * @remarks This is optional and shall be set to NULL if not wanted. + */ + DECLR3CALLBACKMEMBER(void, pfnNotifyEmtInit,(PCVMM2USERMETHODS pThis, PUVM pUVM, PUVMCPU pUVCpu)); + + /** + * EMT termination notification callback. + * + * This is intended for doing per-thread cleanups for EMTs (like COM). + * + * @param pThis Pointer to the callback method table. + * @param pUVM The user mode VM handle. + * @param pUVCpu The user mode virtual CPU handle. + * + * @remarks This is optional and shall be set to NULL if not wanted. + */ + DECLR3CALLBACKMEMBER(void, pfnNotifyEmtTerm,(PCVMM2USERMETHODS pThis, PUVM pUVM, PUVMCPU pUVCpu)); + + /** + * PDM thread initialization notification callback. + * + * This is intended for doing per-thread initialization (like COM init). + * + * @param pThis Pointer to the callback method table. + * @param pUVM The user mode VM handle. + * + * @remarks This is optional and shall be set to NULL if not wanted. + */ + DECLR3CALLBACKMEMBER(void, pfnNotifyPdmtInit,(PCVMM2USERMETHODS pThis, PUVM pUVM)); + + /** + * EMT termination notification callback. + * + * This is intended for doing per-thread cleanups for EMTs (like COM). + * + * @param pThis Pointer to the callback method table. + * @param pUVM The user mode VM handle. + * + * @remarks This is optional and shall be set to NULL if not wanted. + */ + DECLR3CALLBACKMEMBER(void, pfnNotifyPdmtTerm,(PCVMM2USERMETHODS pThis, PUVM pUVM)); + + /** Magic value (VMM2USERMETHODS_MAGIC) marking the end of the structure. */ + uint32_t u32EndMagic; +} VMM2USERMETHODS; + +/** Magic value of the VMM2USERMETHODS (Franz Kafka). */ +#define VMM2USERMETHODS_MAGIC UINT32_C(0x18830703) +/** The VMM2USERMETHODS structure version. */ +#define VMM2USERMETHODS_VERSION UINT32_C(0x00020000) + + +VMMDECL(RTRCPTR) VMMGetStackRC(PVMCPU pVCpu); +VMMDECL(VMCPUID) VMMGetCpuId(PVM pVM); +VMMDECL(PVMCPU) VMMGetCpu(PVM pVM); +VMMDECL(PVMCPU) VMMGetCpu0(PVM pVM); +VMMDECL(PVMCPU) VMMGetCpuById(PVM pVM, VMCPUID idCpu); +VMMDECL(uint32_t) VMMGetSvnRev(void); +VMMDECL(VMMSWITCHER) VMMGetSwitcher(PVM pVM); +VMMDECL(void) VMMTrashVolatileXMMRegs(void); + +/** @def VMMIsHwVirtExtForced + * Checks if forced to use the hardware assisted virtualization extensions. + * + * This is intended for making setup decisions where we can save resources when + * using hardware assisted virtualization. + * + * @returns true / false. + * @param pVM Pointer to the shared VM structure. + */ +#define VMMIsHwVirtExtForced(pVM) ((pVM)->fHwVirtExtForced) + + +#ifdef IN_RING3 +/** @defgroup grp_vmm_r3 The VMM Host Context Ring 3 API + * @ingroup grp_vmm + * @{ + */ +VMMR3_INT_DECL(int) VMMR3Init(PVM pVM); +VMMR3_INT_DECL(int) VMMR3InitR0(PVM pVM); +VMMR3_INT_DECL(int) VMMR3InitRC(PVM pVM); +VMMR3_INT_DECL(int) VMMR3InitCompleted(PVM pVM, VMINITCOMPLETED enmWhat); +VMMR3_INT_DECL(int) VMMR3Term(PVM pVM); +VMMR3_INT_DECL(void) VMMR3Relocate(PVM pVM, RTGCINTPTR offDelta); +VMMR3_INT_DECL(int) VMMR3UpdateLoggers(PVM pVM); +VMMR3DECL(const char *) VMMR3GetRZAssertMsg1(PVM pVM); +VMMR3DECL(const char *) VMMR3GetRZAssertMsg2(PVM pVM); +VMMR3_INT_DECL(int) VMMR3GetImportRC(PVM pVM, const char *pszSymbol, PRTRCPTR pRCPtrValue); +VMMR3_INT_DECL(int) VMMR3SelectSwitcher(PVM pVM, VMMSWITCHER enmSwitcher); +VMMR3_INT_DECL(int) VMMR3DisableSwitcher(PVM pVM); +VMMR3_INT_DECL(RTR0PTR) VMMR3GetHostToGuestSwitcher(PVM pVM, VMMSWITCHER enmSwitcher); +VMMR3_INT_DECL(int) VMMR3RawRunGC(PVM pVM, PVMCPU pVCpu); +VMMR3_INT_DECL(int) VMMR3HwAccRunGC(PVM pVM, PVMCPU pVCpu); +VMMR3DECL(int) VMMR3CallRC(PVM pVM, RTRCPTR RCPtrEntry, unsigned cArgs, ...); +VMMR3DECL(int) VMMR3CallRCV(PVM pVM, RTRCPTR RCPtrEntry, unsigned cArgs, va_list args); +VMMR3DECL(int) VMMR3CallR0(PVM pVM, uint32_t uOperation, uint64_t u64Arg, PSUPVMMR0REQHDR pReqHdr); +VMMR3DECL(int) VMMR3ResumeHyper(PVM pVM, PVMCPU pVCpu); +VMMR3DECL(void) VMMR3FatalDump(PVM pVM, PVMCPU pVCpu, int rcErr); +VMMR3_INT_DECL(void) VMMR3YieldSuspend(PVM pVM); +VMMR3_INT_DECL(void) VMMR3YieldStop(PVM pVM); +VMMR3_INT_DECL(void) VMMR3YieldResume(PVM pVM); +VMMR3_INT_DECL(void) VMMR3SendSipi(PVM pVM, VMCPUID idCpu, uint32_t uVector); +VMMR3_INT_DECL(void) VMMR3SendInitIpi(PVM pVM, VMCPUID idCpu); +VMMR3DECL(int) VMMR3RegisterPatchMemory(PVM pVM, RTGCPTR pPatchMem, unsigned cbPatchMem); +VMMR3DECL(int) VMMR3DeregisterPatchMemory(PVM pVM, RTGCPTR pPatchMem, unsigned cbPatchMem); +VMMR3DECL(int) VMMR3EmtRendezvous(PVM pVM, uint32_t fFlags, PFNVMMEMTRENDEZVOUS pfnRendezvous, void *pvUser); +VMMR3_INT_DECL(bool) VMMR3EmtRendezvousSetDisabled(PVMCPU pVCpu, bool fDisabled); +/** @defgroup grp_VMMR3EmtRendezvous_fFlags VMMR3EmtRendezvous flags + * @{ */ +/** Execution type mask. */ +#define VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK UINT32_C(0x00000007) +/** Invalid execution type. */ +#define VMMEMTRENDEZVOUS_FLAGS_TYPE_INVALID UINT32_C(0) +/** Let the EMTs execute the callback one by one (in no particular order). */ +#define VMMEMTRENDEZVOUS_FLAGS_TYPE_ONE_BY_ONE UINT32_C(1) +/** Let all the EMTs execute the callback at the same time. */ +#define VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE UINT32_C(2) +/** Only execute the callback on one EMT (no particular one). */ +#define VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE UINT32_C(3) +/** Let the EMTs execute the callback one by one in ascending order. */ +#define VMMEMTRENDEZVOUS_FLAGS_TYPE_ASCENDING UINT32_C(4) +/** Let the EMTs execute the callback one by one in descending order. */ +#define VMMEMTRENDEZVOUS_FLAGS_TYPE_DESCENDING UINT32_C(5) +/** Stop after the first error. + * This is not valid for any execution type where more than one EMT is active + * at a time. */ +#define VMMEMTRENDEZVOUS_FLAGS_STOP_ON_ERROR UINT32_C(0x00000008) +/** The valid flags. */ +#define VMMEMTRENDEZVOUS_FLAGS_VALID_MASK UINT32_C(0x0000000f) +/** @} */ +VMMR3_INT_DECL(int) VMMR3EmtRendezvousFF(PVM pVM, PVMCPU pVCpu); +VMMR3_INT_DECL(int) VMMR3ReadR0Stack(PVM pVM, VMCPUID idCpu, RTHCUINTPTR R0Addr, void *pvBuf, size_t cbRead); +/** @} */ +#endif /* IN_RING3 */ + + +/** @defgroup grp_vmm_r0 The VMM Host Context Ring 0 API + * @ingroup grp_vmm + * @{ + */ + +/** + * The VMMR0Entry() codes. + */ +typedef enum VMMR0OPERATION +{ + /** Run guest context. */ + VMMR0_DO_RAW_RUN = SUP_VMMR0_DO_RAW_RUN, + /** Run guest code using the available hardware acceleration technology. */ + VMMR0_DO_HWACC_RUN = SUP_VMMR0_DO_HWACC_RUN, + /** Official NOP that we use for profiling. */ + VMMR0_DO_NOP = SUP_VMMR0_DO_NOP, + /** Official slow iocl NOP that we use for profiling. */ + VMMR0_DO_SLOW_NOP, + + /** Ask the GVMM to create a new VM. */ + VMMR0_DO_GVMM_CREATE_VM, + /** Ask the GVMM to destroy the VM. */ + VMMR0_DO_GVMM_DESTROY_VM, + /** Call GVMMR0SchedHalt(). */ + VMMR0_DO_GVMM_SCHED_HALT, + /** Call GVMMR0SchedWakeUp(). */ + VMMR0_DO_GVMM_SCHED_WAKE_UP, + /** Call GVMMR0SchedPoke(). */ + VMMR0_DO_GVMM_SCHED_POKE, + /** Call GVMMR0SchedWakeUpAndPokeCpus(). */ + VMMR0_DO_GVMM_SCHED_WAKE_UP_AND_POKE_CPUS, + /** Call GVMMR0SchedPoll(). */ + VMMR0_DO_GVMM_SCHED_POLL, + /** Call GVMMR0QueryStatistics(). */ + VMMR0_DO_GVMM_QUERY_STATISTICS, + /** Call GVMMR0ResetStatistics(). */ + VMMR0_DO_GVMM_RESET_STATISTICS, + /** Call GVMMR0RegisterVCpu(). */ + VMMR0_DO_GVMM_REGISTER_VMCPU, + + /** Call VMMR0 Per VM Init. */ + VMMR0_DO_VMMR0_INIT, + /** Call VMMR0 Per VM Termination. */ + VMMR0_DO_VMMR0_TERM, + /** Setup the hardware accelerated raw-mode session. */ + VMMR0_DO_HWACC_SETUP_VM, + /** Attempt to enable or disable hardware accelerated raw-mode. */ + VMMR0_DO_HWACC_ENABLE, + /** Calls function in the hypervisor. + * The caller must setup the hypervisor context so the call will be performed. + * The difference between VMMR0_DO_RUN_GC and this one is the handling of + * the return GC code. The return code will not be interpreted by this operation. + */ + VMMR0_DO_CALL_HYPERVISOR, + + /** Call PGMR0PhysAllocateHandyPages(). */ + VMMR0_DO_PGM_ALLOCATE_HANDY_PAGES, + /** Call PGMR0PhysFlushHandyPages(). */ + VMMR0_DO_PGM_FLUSH_HANDY_PAGES, + /** Call PGMR0AllocateLargePage(). */ + VMMR0_DO_PGM_ALLOCATE_LARGE_HANDY_PAGE, + /** Call PGMR0PhysSetupIommu(). */ + VMMR0_DO_PGM_PHYS_SETUP_IOMMU, + + /** Call GMMR0InitialReservation(). */ + VMMR0_DO_GMM_INITIAL_RESERVATION, + /** Call GMMR0UpdateReservation(). */ + VMMR0_DO_GMM_UPDATE_RESERVATION, + /** Call GMMR0AllocatePages(). */ + VMMR0_DO_GMM_ALLOCATE_PAGES, + /** Call GMMR0FreePages(). */ + VMMR0_DO_GMM_FREE_PAGES, + /** Call GMMR0FreeLargePage(). */ + VMMR0_DO_GMM_FREE_LARGE_PAGE, + /** Call GMMR0QueryHypervisorMemoryStatsReq(). */ + VMMR0_DO_GMM_QUERY_HYPERVISOR_MEM_STATS, + /** Call GMMR0QueryMemoryStatsReq(). */ + VMMR0_DO_GMM_QUERY_MEM_STATS, + /** Call GMMR0BalloonedPages(). */ + VMMR0_DO_GMM_BALLOONED_PAGES, + /** Call GMMR0MapUnmapChunk(). */ + VMMR0_DO_GMM_MAP_UNMAP_CHUNK, + /** Call GMMR0SeedChunk(). */ + VMMR0_DO_GMM_SEED_CHUNK, + /** Call GMMR0RegisterSharedModule. */ + VMMR0_DO_GMM_REGISTER_SHARED_MODULE, + /** Call GMMR0UnregisterSharedModule. */ + VMMR0_DO_GMM_UNREGISTER_SHARED_MODULE, + /** Call GMMR0ResetSharedModules. */ + VMMR0_DO_GMM_RESET_SHARED_MODULES, + /** Call GMMR0CheckSharedModules. */ + VMMR0_DO_GMM_CHECK_SHARED_MODULES, + /** Call GMMR0FindDuplicatePage. */ + VMMR0_DO_GMM_FIND_DUPLICATE_PAGE, + /** Call GMMR0QueryStatistics(). */ + VMMR0_DO_GMM_QUERY_STATISTICS, + /** Call GMMR0ResetStatistics(). */ + VMMR0_DO_GMM_RESET_STATISTICS, + + /** Set a GVMM or GMM configuration value. */ + VMMR0_DO_GCFGM_SET_VALUE, + /** Query a GVMM or GMM configuration value. */ + VMMR0_DO_GCFGM_QUERY_VALUE, + + /** Call PDMR0DriverCallReqHandler. */ + VMMR0_DO_PDM_DRIVER_CALL_REQ_HANDLER, + /** Call PDMR0DeviceCallReqHandler. */ + VMMR0_DO_PDM_DEVICE_CALL_REQ_HANDLER, + + /** The start of the R0 service operations. */ + VMMR0_DO_SRV_START, + /** Call IntNetR0Open(). */ + VMMR0_DO_INTNET_OPEN, + /** Call IntNetR0IfClose(). */ + VMMR0_DO_INTNET_IF_CLOSE, + /** Call IntNetR0IfGetBufferPtrs(). */ + VMMR0_DO_INTNET_IF_GET_BUFFER_PTRS, + /** Call IntNetR0IfSetPromiscuousMode(). */ + VMMR0_DO_INTNET_IF_SET_PROMISCUOUS_MODE, + /** Call IntNetR0IfSetMacAddress(). */ + VMMR0_DO_INTNET_IF_SET_MAC_ADDRESS, + /** Call IntNetR0IfSetActive(). */ + VMMR0_DO_INTNET_IF_SET_ACTIVE, + /** Call IntNetR0IfSend(). */ + VMMR0_DO_INTNET_IF_SEND, + /** Call IntNetR0IfWait(). */ + VMMR0_DO_INTNET_IF_WAIT, + /** Call IntNetR0IfAbortWait(). */ + VMMR0_DO_INTNET_IF_ABORT_WAIT, + + /** Forward call to the PCI driver */ + VMMR0_DO_PCIRAW_REQ, + + /** The end of the R0 service operations. */ + VMMR0_DO_SRV_END, + + /** Official call we use for testing Ring-0 APIs. */ + VMMR0_DO_TESTS, + /** Test the 32->64 bits switcher. */ + VMMR0_DO_TEST_SWITCHER3264, + + /** The usual 32-bit type blow up. */ + VMMR0_DO_32BIT_HACK = 0x7fffffff +} VMMR0OPERATION; + + +/** + * Request buffer for VMMR0_DO_GCFGM_SET_VALUE and VMMR0_DO_GCFGM_QUERY_VALUE. + * @todo Move got GCFGM.h when it's implemented. + */ +typedef struct GCFGMVALUEREQ +{ + /** The request header.*/ + SUPVMMR0REQHDR Hdr; + /** The support driver session handle. */ + PSUPDRVSESSION pSession; + /** The value. + * This is input for the set request and output for the query. */ + uint64_t u64Value; + /** The variable name. + * This is fixed sized just to make things simple for the mock-up. */ + char szName[48]; +} GCFGMVALUEREQ; +/** Pointer to a VMMR0_DO_GCFGM_SET_VALUE and VMMR0_DO_GCFGM_QUERY_VALUE request buffer. + * @todo Move got GCFGM.h when it's implemented. + */ +typedef GCFGMVALUEREQ *PGCFGMVALUEREQ; + +VMMR0DECL(int) VMMR0EntryInt(PVM pVM, VMMR0OPERATION enmOperation, void *pvArg); +VMMR0DECL(void) VMMR0EntryFast(PVM pVM, VMCPUID idCpu, VMMR0OPERATION enmOperation); +VMMR0DECL(int) VMMR0EntryEx(PVM pVM, VMCPUID idCpu, VMMR0OPERATION enmOperation, PSUPVMMR0REQHDR pReq, uint64_t u64Arg, PSUPDRVSESSION); +VMMR0DECL(int) VMMR0TermVM(PVM pVM, PGVM pGVM); + +#ifdef LOG_ENABLED +VMMR0DECL(void) VMMR0LogFlushDisable(PVMCPU pVCpu); +VMMR0DECL(void) VMMR0LogFlushEnable(PVMCPU pVCpu); +#else +#define VMMR0LogFlushDisable(pVCpu) do { } while(0) +#define VMMR0LogFlushEnable(pVCpu) do { } while(0) +#endif + +/** @} */ + + +#ifdef IN_RC +/** @defgroup grp_vmm_rc The VMM Raw-Mode Context API + * @ingroup grp_vmm + * @{ + */ +VMMRCDECL(int) VMMGCEntry(PVM pVM, unsigned uOperation, unsigned uArg, ...); +VMMRCDECL(void) VMMGCGuestToHost(PVM pVM, int rc); +VMMRCDECL(void) VMMGCLogFlushIfFull(PVM pVM); +/** @} */ +#endif /* IN_RC */ + +#if defined(IN_RC) || defined(IN_RING0) +/** @defgroup grp_vmm_rz The VMM Raw-Mode and Ring-0 Context API + * @ingroup grp_vmm + * @{ + */ +VMMRZDECL(int) VMMRZCallRing3(PVM pVM, PVMCPU pVCpu, VMMCALLRING3 enmOperation, uint64_t uArg); +VMMRZDECL(int) VMMRZCallRing3NoCpu(PVM pVM, VMMCALLRING3 enmOperation, uint64_t uArg); +VMMRZDECL(void) VMMRZCallRing3Disable(PVMCPU pVCpu); +VMMRZDECL(void) VMMRZCallRing3Enable(PVMCPU pVCpu); +VMMRZDECL(bool) VMMRZCallRing3IsEnabled(PVMCPU pVCpu); +/** @} */ +#endif + + +/** @} */ +RT_C_DECLS_END + +#endif |