diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 16:49:04 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 16:49:04 +0000 |
commit | 16f504a9dca3fe3b70568f67b7d41241ae485288 (patch) | |
tree | c60f36ada0496ba928b7161059ba5ab1ab224f9d /include/VBox/vmm | |
parent | Initial commit. (diff) | |
download | virtualbox-upstream.tar.xz virtualbox-upstream.zip |
Adding upstream version 7.0.6-dfsg.upstream/7.0.6-dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'include/VBox/vmm')
79 files changed, 56538 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/apic.h b/include/VBox/vmm/apic.h new file mode 100644 index 00000000..6e9c3673 --- /dev/null +++ b/include/VBox/vmm/apic.h @@ -0,0 +1,107 @@ +/** @file + * APIC - Advanced Programmable Interrupt Controller. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_apic_h +#define VBOX_INCLUDED_vmm_apic_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <VBox/apic.h> +struct PDMDEVREGCB; + +/** @defgroup grp_apic The local APIC VMM API + * @ingroup grp_vmm + * @{ + */ + +RT_C_DECLS_BEGIN + +#ifdef VBOX_INCLUDED_vmm_pdmdev_h +extern const PDMDEVREG g_DeviceAPIC; +#endif + +/* These functions are exported as they are called from external modules (recompiler). */ +VMMDECL(void) APICUpdatePendingInterrupts(PVMCPUCC pVCpu); +VMMDECL(int) APICGetTpr(PCVMCPUCC pVCpu, uint8_t *pu8Tpr, bool *pfPending, uint8_t *pu8PendingIntr); +VMMDECL(int) APICSetTpr(PVMCPUCC pVCpu, uint8_t u8Tpr); + +/* These functions are VMM internal. */ +VMM_INT_DECL(bool) APICIsEnabled(PCVMCPUCC pVCpu); +VMM_INT_DECL(bool) APICGetHighestPendingInterrupt(PVMCPUCC pVCpu, uint8_t *pu8PendingIntr); +VMM_INT_DECL(bool) APICQueueInterruptToService(PVMCPUCC pVCpu, uint8_t u8PendingIntr); +VMM_INT_DECL(void) APICDequeueInterruptFromService(PVMCPUCC pVCpu, uint8_t u8PendingIntr); +VMM_INT_DECL(VBOXSTRICTRC) APICReadMsr(PVMCPUCC pVCpu, uint32_t u32Reg, uint64_t *pu64Value); +VMM_INT_DECL(VBOXSTRICTRC) APICWriteMsr(PVMCPUCC pVCpu, uint32_t u32Reg, uint64_t u64Value); +VMM_INT_DECL(int) APICGetTimerFreq(PVMCC pVM, uint64_t *pu64Value); +VMM_INT_DECL(VBOXSTRICTRC) APICLocalInterrupt(PVMCPUCC pVCpu, uint8_t u8Pin, uint8_t u8Level, int rcRZ); +VMM_INT_DECL(uint64_t) APICGetBaseMsrNoCheck(PCVMCPUCC pVCpu); +VMM_INT_DECL(VBOXSTRICTRC) APICGetBaseMsr(PVMCPUCC pVCpu, uint64_t *pu64Value); +VMM_INT_DECL(int) APICSetBaseMsr(PVMCPUCC pVCpu, uint64_t u64BaseMsr); +VMM_INT_DECL(int) APICGetInterrupt(PVMCPUCC pVCpu, uint8_t *pu8Vector, uint32_t *pu32TagSrc); +VMM_INT_DECL(int) APICBusDeliver(PVMCC pVM, uint8_t uDest, uint8_t uDestMode, uint8_t uDeliveryMode, uint8_t uVector, + uint8_t uPolarity, uint8_t uTriggerMode, uint32_t uTagSrc); +VMM_INT_DECL(int) APICGetApicPageForCpu(PCVMCPUCC pVCpu, PRTHCPHYS pHCPhys, PRTR0PTR pR0Ptr, PRTR3PTR pR3Ptr); + +/** @name Hyper-V interface (Ring-3 and all-context API). + * @{ */ +#ifdef IN_RING3 +VMMR3_INT_DECL(void) APICR3HvSetCompatMode(PVM pVM, bool fHyperVCompatMode); +#endif +VMM_INT_DECL(void) APICHvSendInterrupt(PVMCPUCC pVCpu, uint8_t uVector, bool fAutoEoi, XAPICTRIGGERMODE enmTriggerMode); +VMM_INT_DECL(VBOXSTRICTRC) APICHvSetTpr(PVMCPUCC pVCpu, uint8_t uTpr); +VMM_INT_DECL(uint8_t) APICHvGetTpr(PVMCPUCC pVCpu); +VMM_INT_DECL(VBOXSTRICTRC) APICHvSetIcr(PVMCPUCC pVCpu, uint64_t uIcr); +VMM_INT_DECL(uint64_t) APICHvGetIcr(PVMCPUCC pVCpu); +VMM_INT_DECL(VBOXSTRICTRC) APICHvSetEoi(PVMCPUCC pVCpu, uint32_t uEoi); +/** @} */ + +#ifdef IN_RING3 +/** @defgroup grp_apic_r3 The APIC Host Context Ring-3 API + * @{ + */ +VMMR3_INT_DECL(int) APICR3RegisterDevice(struct PDMDEVREGCB *pCallbacks); +VMMR3_INT_DECL(void) APICR3InitIpi(PVMCPU pVCpu); +VMMR3_INT_DECL(void) APICR3HvEnable(PVM pVM); +/** @} */ +#endif /* IN_RING3 */ + +RT_C_DECLS_END + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_apic_h */ + diff --git a/include/VBox/vmm/cfgm.h b/include/VBox/vmm/cfgm.h new file mode 100644 index 00000000..7a84dd94 --- /dev/null +++ b/include/VBox/vmm/cfgm.h @@ -0,0 +1,245 @@ +/** @file + * CFGM - Configuration Manager. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_cfgm_h +#define VBOX_INCLUDED_vmm_cfgm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <iprt/stdarg.h> + +/** @defgroup grp_cfgm The Configuration Manager API + * @ingroup grp_vmm + * @{ + */ + +/** + * Configuration manager value type. + */ +typedef enum CFGMVALUETYPE +{ + /** Integer value. */ + CFGMVALUETYPE_INTEGER = 1, + /** String value. */ + CFGMVALUETYPE_STRING, + /** Bytestring value. */ + CFGMVALUETYPE_BYTES, + /** Password value, same as String but hides the content in dump. */ + CFGMVALUETYPE_PASSWORD +} 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 + * @{ + */ + +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 pUVM The user mode VM handle. + * @param pVM The cross context VM structure. + * @param pVMM The VMM R3 vtable. + * @param pvUser The argument supplied to VMR3Create(). + */ +typedef DECLCALLBACKTYPE(int, FNCFGMCONSTRUCTOR,(PUVM pUVM, PVM pVM, PCVMMR3VTABLE pVMM, void *pvUser)); +/** Pointer to a FNCFGMCONSTRUCTOR(). */ +typedef FNCFGMCONSTRUCTOR *PFNCFGMCONSTRUCTOR; + +VMMR3DECL(int) CFGMR3Init(PVM pVM, PFNCFGMCONSTRUCTOR pfnCFGMConstructor, void *pvUser); +VMMR3DECL(int) CFGMR3Term(PVM pVM); +VMMR3DECL(int) CFGMR3ConstructDefaultTree(PVM pVM); + +VMMR3DECL(PCFGMNODE) CFGMR3CreateTree(PUVM pUVM); +VMMR3DECL(int) CFGMR3DestroyTree(PCFGMNODE pRoot); +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, ...) RT_IPRT_FORMAT_ATTR(3, 4); +VMMR3DECL(int) CFGMR3InsertNodeFV(PCFGMNODE pNode, PCFGMNODE *ppChild, + const char *pszNameFormat, va_list Args) RT_IPRT_FORMAT_ATTR(3, 0); +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, ...) RT_IPRT_FORMAT_ATTR(3, 4); +VMMR3DECL(int) CFGMR3InsertStringFV(PCFGMNODE pNode, const char *pszName, + const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(3, 0); +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) CFGMR3InsertPassword(PCFGMNODE pNode, const char *pszName, const char *pszString); +VMMR3DECL(int) CFGMR3InsertPasswordN(PCFGMNODE pNode, const char *pszName, const char *pszString, size_t cchString); +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(bool) CFGMR3Exists( PCFGMNODE pNode, const char *pszName); +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) CFGMR3QueryPassword( PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString); +VMMR3DECL(int) CFGMR3QueryPasswordDef( 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) 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) CFGMR3GetRootU(PUVM pUVM); +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, ...) RT_IPRT_FORMAT_ATTR(2, 3); +VMMR3DECL(PCFGMNODE) CFGMR3GetChildFV(PCFGMNODE pNode, const char *pszPathFormat, va_list Args) RT_IPRT_FORMAT_ATTR(3, 0); +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 /* !VBOX_INCLUDED_vmm_cfgm_h */ + diff --git a/include/VBox/vmm/cpuidcall.h b/include/VBox/vmm/cpuidcall.h new file mode 100644 index 00000000..8bcdb8da --- /dev/null +++ b/include/VBox/vmm/cpuidcall.h @@ -0,0 +1,107 @@ +/** @file + * VM - The Virtual Machine, CPU Host Call Interface (AMD64 & x86 only). + * + * @note cpuidcall.mac is generated from this file by running 'kmk incs' in the root. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_cpuidcall_h +#define VBOX_INCLUDED_vmm_cpuidcall_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> + + +/** @defgroup grp_cpuidcall VBox CPUID Host Call Interface (AMD64 & x86) + * + * This describes an interface using CPUID for calling the host from within the + * VM. This is chiefly intended for nested VM debugging at present and is + * therefore disabled by default. + * + * @{ */ + +/** Fixed EAX value for all requests (big-endian 'VBox'). */ +#define VBOX_CPUID_REQ_EAX_FIXED UINT32_C(0x56426f78) +/** Fixed portion of ECX for all requests. */ +#define VBOX_CPUID_REQ_ECX_FIXED UINT32_C(0xc0de0000) +/** Fixed portion of ECX for all requests. */ +#define VBOX_CPUID_REQ_ECX_FIXED_MASK UINT32_C(0xffff0000) +/** Function part of ECX for requests. */ +#define VBOX_CPUID_REQ_ECX_FN_MASK UINT32_C(0x0000ffff) + +/** Generic ECX return value. */ +#define VBOX_CPUID_RESP_GEN_ECX UINT32_C(0x19410612) +/** Generic EDX return value. */ +#define VBOX_CPUID_RESP_GEN_EDX UINT32_C(0x19400412) +/** Generic EBX return value. */ +#define VBOX_CPUID_RESP_GEN_EBX UINT32_C(0x19450508) + +/** @name Function \#1: Interface ID check and max function. + * + * Input: EDX & EBX content is unused and ignored. Best set to zero. + * + * Result: EAX:EDX:EBX forms the little endian string "VBox RuleZ!\0". + * ECX contains the max function number acccepted. + * @{ */ +#define VBOX_CPUID_FN_ID UINT32_C(0x0001) +#define VBOX_CPUID_RESP_ID_EAX UINT32_C(0x786f4256) +#define VBOX_CPUID_RESP_ID_EDX UINT32_C(0x6c755220) +#define VBOX_CPUID_RESP_ID_EBX UINT32_C(0x00215A65) +#define VBOX_CPUID_RESP_ID_ECX UINT32_C(0x00000002) +/** @} */ + +/** Function \#2: Write string to host Log. + * + * Input: EDX gives the number of bytes to log (max 2MB). + * EBX indicates the log to write to: 0 for debug, 1 for release. + * RSI is the FLAT pointer to the UTF-8 string to log. + * + * Output: EAX contains IPRT status code. ECX, EDX and EBX are set to the + * generic their response values (VBOX_CPUID_RESP_GEN_XXX). RSI is + * advanced EDX bytes on success. + * + * Except: May raise \#PF when reading the string. RSI and EDX is then be + * updated to the point where the page fault triggered, allowing paging + * in of logging buffer and such like. + * + * @note Buffer is not accessed if the target logger isn't enabled. + */ +#define VBOX_CPUID_FN_LOG UINT32_C(0x0002) + + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_cpuidcall_h */ + diff --git a/include/VBox/vmm/cpuidcall.mac b/include/VBox/vmm/cpuidcall.mac new file mode 100644 index 00000000..5965550c --- /dev/null +++ b/include/VBox/vmm/cpuidcall.mac @@ -0,0 +1,55 @@ +;; @file +; VM - The Virtual Machine, CPU Host Call Interface (AMD64 & x86 only). +; +; Automatically generated by various.sed. DO NOT EDIT! +; + +; +; Copyright (C) 2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox 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. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef VBOX_INCLUDED_vmm_cpuidcall_h +%define VBOX_INCLUDED_vmm_cpuidcall_h +%ifndef RT_WITHOUT_PRAGMA_ONCE +%endif +%define VBOX_CPUID_REQ_EAX_FIXED 0x56426f78 +%define VBOX_CPUID_REQ_ECX_FIXED 0xc0de0000 +%define VBOX_CPUID_REQ_ECX_FIXED_MASK 0xffff0000 +%define VBOX_CPUID_REQ_ECX_FN_MASK 0x0000ffff +%define VBOX_CPUID_RESP_GEN_ECX 0x19410612 +%define VBOX_CPUID_RESP_GEN_EDX 0x19400412 +%define VBOX_CPUID_RESP_GEN_EBX 0x19450508 +%define VBOX_CPUID_FN_ID 0x0001 +%define VBOX_CPUID_RESP_ID_EAX 0x786f4256 +%define VBOX_CPUID_RESP_ID_EDX 0x6c755220 +%define VBOX_CPUID_RESP_ID_EBX 0x00215A65 +%define VBOX_CPUID_RESP_ID_ECX 0x00000002 +%define VBOX_CPUID_FN_LOG 0x0002 +%endif diff --git a/include/VBox/vmm/cpum.h b/include/VBox/vmm/cpum.h new file mode 100644 index 00000000..1f5f28e3 --- /dev/null +++ b/include/VBox/vmm/cpum.h @@ -0,0 +1,3248 @@ +/** @file + * CPUM - CPU Monitor(/ Manager). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_cpum_h +#define VBOX_INCLUDED_vmm_cpum_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/x86.h> +#include <VBox/types.h> +#include <VBox/vmm/cpumctx.h> +#include <VBox/vmm/stam.h> +#include <VBox/vmm/vmapi.h> +#include <VBox/vmm/hm_svm.h> +#include <VBox/vmm/hm_vmx.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_cpum The CPU Monitor / Manager API + * @ingroup grp_vmm + * @{ + */ + +/** + * CPUID feature to set or clear. + */ +typedef enum CPUMCPUIDFEATURE +{ + CPUMCPUIDFEATURE_INVALID = 0, + /** The APIC feature bit. (Std+Ext) + * Note! There is a per-cpu flag for masking this CPUID feature bit when the + * APICBASE.ENABLED bit is zero. So, this feature is only set/cleared + * at VM construction time like all the others. This didn't used to be + * that way, this is new with 5.1. */ + 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 x2APIC feature bit. (Std) */ + CPUMCPUIDFEATURE_X2APIC, + /** The RDTSCP feature bit. (Ext) */ + CPUMCPUIDFEATURE_RDTSCP, + /** The Hypervisor Present bit. (Std) */ + CPUMCPUIDFEATURE_HVP, + /** The speculation control feature bits. (StExt) */ + CPUMCPUIDFEATURE_SPEC_CTRL, + /** 32bit hackishness. */ + CPUMCPUIDFEATURE_32BIT_HACK = 0x7fffffff +} CPUMCPUIDFEATURE; + +/** + * CPU Vendor. + */ +typedef enum CPUMCPUVENDOR +{ + CPUMCPUVENDOR_INVALID = 0, + CPUMCPUVENDOR_INTEL, + CPUMCPUVENDOR_AMD, + CPUMCPUVENDOR_VIA, + CPUMCPUVENDOR_CYRIX, + CPUMCPUVENDOR_SHANGHAI, + CPUMCPUVENDOR_HYGON, + CPUMCPUVENDOR_UNKNOWN, + /** 32bit hackishness. */ + CPUMCPUVENDOR_32BIT_HACK = 0x7fffffff +} CPUMCPUVENDOR; + + +/** + * X86 and AMD64 CPU microarchitectures and in processor generations. + * + * @remarks The separation here is sometimes a little bit too finely grained, + * and the differences is more like processor generation than micro + * arch. This can be useful, so we'll provide functions for getting at + * more coarse grained info. + */ +typedef enum CPUMMICROARCH +{ + kCpumMicroarch_Invalid = 0, + + kCpumMicroarch_Intel_First, + + kCpumMicroarch_Intel_8086 = kCpumMicroarch_Intel_First, + kCpumMicroarch_Intel_80186, + kCpumMicroarch_Intel_80286, + kCpumMicroarch_Intel_80386, + kCpumMicroarch_Intel_80486, + kCpumMicroarch_Intel_P5, + + kCpumMicroarch_Intel_P6_Core_Atom_First, + kCpumMicroarch_Intel_P6 = kCpumMicroarch_Intel_P6_Core_Atom_First, + kCpumMicroarch_Intel_P6_II, + kCpumMicroarch_Intel_P6_III, + + kCpumMicroarch_Intel_P6_M_Banias, + kCpumMicroarch_Intel_P6_M_Dothan, + kCpumMicroarch_Intel_Core_Yonah, /**< Core, also known as Enhanced Pentium M. */ + + kCpumMicroarch_Intel_Core2_First, + kCpumMicroarch_Intel_Core2_Merom = kCpumMicroarch_Intel_Core2_First, /**< 65nm, Merom/Conroe/Kentsfield/Tigerton */ + kCpumMicroarch_Intel_Core2_Penryn, /**< 45nm, Penryn/Wolfdale/Yorkfield/Harpertown */ + kCpumMicroarch_Intel_Core2_End, + + kCpumMicroarch_Intel_Core7_First, + kCpumMicroarch_Intel_Core7_Nehalem = kCpumMicroarch_Intel_Core7_First, + kCpumMicroarch_Intel_Core7_Westmere, + kCpumMicroarch_Intel_Core7_SandyBridge, + kCpumMicroarch_Intel_Core7_IvyBridge, + kCpumMicroarch_Intel_Core7_Haswell, + kCpumMicroarch_Intel_Core7_Broadwell, + kCpumMicroarch_Intel_Core7_Skylake, + kCpumMicroarch_Intel_Core7_KabyLake, + kCpumMicroarch_Intel_Core7_CoffeeLake, + kCpumMicroarch_Intel_Core7_WhiskeyLake, + kCpumMicroarch_Intel_Core7_CascadeLake, + kCpumMicroarch_Intel_Core7_CannonLake, /**< Limited 10nm. */ + kCpumMicroarch_Intel_Core7_CometLake, /**< 10th gen, 14nm desktop + high power mobile. */ + kCpumMicroarch_Intel_Core7_IceLake, /**< 10th gen, 10nm mobile and some Xeons. Actually 'Sunny Cove' march. */ + kCpumMicroarch_Intel_Core7_SunnyCove = kCpumMicroarch_Intel_Core7_IceLake, + kCpumMicroarch_Intel_Core7_RocketLake, /**< 11th gen, 14nm desktop + high power mobile. Aka 'Cypress Cove', backport of 'Willow Cove' to 14nm. */ + kCpumMicroarch_Intel_Core7_CypressCove = kCpumMicroarch_Intel_Core7_RocketLake, + kCpumMicroarch_Intel_Core7_TigerLake, /**< 11th gen, 10nm mobile. Actually 'Willow Cove' march. */ + kCpumMicroarch_Intel_Core7_WillowCove = kCpumMicroarch_Intel_Core7_TigerLake, + kCpumMicroarch_Intel_Core7_AlderLake, /**< 12th gen, 10nm all platforms(?). */ + kCpumMicroarch_Intel_Core7_SapphireRapids, /**< 12th? gen, 10nm server? */ + kCpumMicroarch_Intel_Core7_End, + + kCpumMicroarch_Intel_Atom_First, + kCpumMicroarch_Intel_Atom_Bonnell = kCpumMicroarch_Intel_Atom_First, + kCpumMicroarch_Intel_Atom_Lincroft, /**< Second generation bonnell (44nm). */ + kCpumMicroarch_Intel_Atom_Saltwell, /**< 32nm shrink of Bonnell. */ + kCpumMicroarch_Intel_Atom_Silvermont, /**< 22nm */ + kCpumMicroarch_Intel_Atom_Airmount, /**< 14nm */ + kCpumMicroarch_Intel_Atom_Goldmont, /**< 14nm */ + kCpumMicroarch_Intel_Atom_GoldmontPlus, /**< 14nm */ + kCpumMicroarch_Intel_Atom_Unknown, + kCpumMicroarch_Intel_Atom_End, + + + kCpumMicroarch_Intel_Phi_First, + kCpumMicroarch_Intel_Phi_KnightsFerry = kCpumMicroarch_Intel_Phi_First, + kCpumMicroarch_Intel_Phi_KnightsCorner, + kCpumMicroarch_Intel_Phi_KnightsLanding, + kCpumMicroarch_Intel_Phi_KnightsHill, + kCpumMicroarch_Intel_Phi_KnightsMill, + kCpumMicroarch_Intel_Phi_End, + + kCpumMicroarch_Intel_P6_Core_Atom_End, + + kCpumMicroarch_Intel_NB_First, + kCpumMicroarch_Intel_NB_Willamette = kCpumMicroarch_Intel_NB_First, /**< 180nm */ + kCpumMicroarch_Intel_NB_Northwood, /**< 130nm */ + kCpumMicroarch_Intel_NB_Prescott, /**< 90nm */ + kCpumMicroarch_Intel_NB_Prescott2M, /**< 90nm */ + kCpumMicroarch_Intel_NB_CedarMill, /**< 65nm */ + kCpumMicroarch_Intel_NB_Gallatin, /**< 90nm Xeon, Pentium 4 Extreme Edition ("Emergency Edition"). */ + kCpumMicroarch_Intel_NB_Unknown, + kCpumMicroarch_Intel_NB_End, + + kCpumMicroarch_Intel_Unknown, + kCpumMicroarch_Intel_End, + + kCpumMicroarch_AMD_First, + kCpumMicroarch_AMD_Am286 = kCpumMicroarch_AMD_First, + kCpumMicroarch_AMD_Am386, + kCpumMicroarch_AMD_Am486, + kCpumMicroarch_AMD_Am486Enh, /**< Covers Am5x86 as well. */ + kCpumMicroarch_AMD_K5, + kCpumMicroarch_AMD_K6, + + kCpumMicroarch_AMD_K7_First, + kCpumMicroarch_AMD_K7_Palomino = kCpumMicroarch_AMD_K7_First, + kCpumMicroarch_AMD_K7_Spitfire, + kCpumMicroarch_AMD_K7_Thunderbird, + kCpumMicroarch_AMD_K7_Morgan, + kCpumMicroarch_AMD_K7_Thoroughbred, + kCpumMicroarch_AMD_K7_Barton, + kCpumMicroarch_AMD_K7_Unknown, + kCpumMicroarch_AMD_K7_End, + + kCpumMicroarch_AMD_K8_First, + kCpumMicroarch_AMD_K8_130nm = kCpumMicroarch_AMD_K8_First, /**< 130nm Clawhammer, Sledgehammer, Newcastle, Paris, Odessa, Dublin */ + kCpumMicroarch_AMD_K8_90nm, /**< 90nm shrink */ + kCpumMicroarch_AMD_K8_90nm_DualCore, /**< 90nm with two cores. */ + kCpumMicroarch_AMD_K8_90nm_AMDV, /**< 90nm with AMD-V (usually) and two cores (usually). */ + kCpumMicroarch_AMD_K8_65nm, /**< 65nm shrink. */ + kCpumMicroarch_AMD_K8_End, + + kCpumMicroarch_AMD_K10, + kCpumMicroarch_AMD_K10_Lion, + kCpumMicroarch_AMD_K10_Llano, + kCpumMicroarch_AMD_Bobcat, + kCpumMicroarch_AMD_Jaguar, + + kCpumMicroarch_AMD_15h_First, + kCpumMicroarch_AMD_15h_Bulldozer = kCpumMicroarch_AMD_15h_First, + kCpumMicroarch_AMD_15h_Piledriver, + kCpumMicroarch_AMD_15h_Steamroller, /**< Yet to be released, might have different family. */ + kCpumMicroarch_AMD_15h_Excavator, /**< Yet to be released, might have different family. */ + kCpumMicroarch_AMD_15h_Unknown, + kCpumMicroarch_AMD_15h_End, + + kCpumMicroarch_AMD_16h_First, + kCpumMicroarch_AMD_16h_End, + + kCpumMicroarch_AMD_Zen_First, + kCpumMicroarch_AMD_Zen_Ryzen = kCpumMicroarch_AMD_Zen_First, + kCpumMicroarch_AMD_Zen_End, + + kCpumMicroarch_AMD_Unknown, + kCpumMicroarch_AMD_End, + + kCpumMicroarch_Hygon_First, + kCpumMicroarch_Hygon_Dhyana = kCpumMicroarch_Hygon_First, + kCpumMicroarch_Hygon_Unknown, + kCpumMicroarch_Hygon_End, + + kCpumMicroarch_VIA_First, + kCpumMicroarch_Centaur_C6 = kCpumMicroarch_VIA_First, + kCpumMicroarch_Centaur_C2, + kCpumMicroarch_Centaur_C3, + kCpumMicroarch_VIA_C3_M2, + kCpumMicroarch_VIA_C3_C5A, /**< 180nm Samuel - Cyrix III, C3, 1GigaPro. */ + kCpumMicroarch_VIA_C3_C5B, /**< 150nm Samuel 2 - Cyrix III, C3, 1GigaPro, Eden ESP, XP 2000+. */ + kCpumMicroarch_VIA_C3_C5C, /**< 130nm Ezra - C3, Eden ESP. */ + kCpumMicroarch_VIA_C3_C5N, /**< 130nm Ezra-T - C3. */ + kCpumMicroarch_VIA_C3_C5XL, /**< 130nm Nehemiah - C3, Eden ESP, Eden-N. */ + kCpumMicroarch_VIA_C3_C5P, /**< 130nm Nehemiah+ - C3. */ + kCpumMicroarch_VIA_C7_C5J, /**< 90nm Esther - C7, C7-D, C7-M, Eden, Eden ULV. */ + kCpumMicroarch_VIA_Isaiah, + kCpumMicroarch_VIA_Unknown, + kCpumMicroarch_VIA_End, + + kCpumMicroarch_Shanghai_First, + kCpumMicroarch_Shanghai_Wudaokou = kCpumMicroarch_Shanghai_First, + kCpumMicroarch_Shanghai_Unknown, + kCpumMicroarch_Shanghai_End, + + kCpumMicroarch_Cyrix_First, + kCpumMicroarch_Cyrix_5x86 = kCpumMicroarch_Cyrix_First, + kCpumMicroarch_Cyrix_M1, + kCpumMicroarch_Cyrix_MediaGX, + kCpumMicroarch_Cyrix_MediaGXm, + kCpumMicroarch_Cyrix_M2, + kCpumMicroarch_Cyrix_Unknown, + kCpumMicroarch_Cyrix_End, + + kCpumMicroarch_NEC_First, + kCpumMicroarch_NEC_V20 = kCpumMicroarch_NEC_First, + kCpumMicroarch_NEC_V30, + kCpumMicroarch_NEC_End, + + kCpumMicroarch_Unknown, + + kCpumMicroarch_32BitHack = 0x7fffffff +} CPUMMICROARCH; + + +/** Predicate macro for catching netburst CPUs. */ +#define CPUMMICROARCH_IS_INTEL_NETBURST(a_enmMicroarch) \ + ((a_enmMicroarch) >= kCpumMicroarch_Intel_NB_First && (a_enmMicroarch) <= kCpumMicroarch_Intel_NB_End) + +/** Predicate macro for catching Core7 CPUs. */ +#define CPUMMICROARCH_IS_INTEL_CORE7(a_enmMicroarch) \ + ((a_enmMicroarch) >= kCpumMicroarch_Intel_Core7_First && (a_enmMicroarch) <= kCpumMicroarch_Intel_Core7_End) + +/** Predicate macro for catching Core 2 CPUs. */ +#define CPUMMICROARCH_IS_INTEL_CORE2(a_enmMicroarch) \ + ((a_enmMicroarch) >= kCpumMicroarch_Intel_Core2_First && (a_enmMicroarch) <= kCpumMicroarch_Intel_Core2_End) + +/** Predicate macro for catching Atom CPUs, Silvermont and upwards. */ +#define CPUMMICROARCH_IS_INTEL_SILVERMONT_PLUS(a_enmMicroarch) \ + ((a_enmMicroarch) >= kCpumMicroarch_Intel_Atom_Silvermont && (a_enmMicroarch) <= kCpumMicroarch_Intel_Atom_End) + +/** Predicate macro for catching AMD Family OFh CPUs (aka K8). */ +#define CPUMMICROARCH_IS_AMD_FAM_0FH(a_enmMicroarch) \ + ((a_enmMicroarch) >= kCpumMicroarch_AMD_K8_First && (a_enmMicroarch) <= kCpumMicroarch_AMD_K8_End) + +/** Predicate macro for catching AMD Family 10H CPUs (aka K10). */ +#define CPUMMICROARCH_IS_AMD_FAM_10H(a_enmMicroarch) ((a_enmMicroarch) == kCpumMicroarch_AMD_K10) + +/** Predicate macro for catching AMD Family 11H CPUs (aka Lion). */ +#define CPUMMICROARCH_IS_AMD_FAM_11H(a_enmMicroarch) ((a_enmMicroarch) == kCpumMicroarch_AMD_K10_Lion) + +/** Predicate macro for catching AMD Family 12H CPUs (aka Llano). */ +#define CPUMMICROARCH_IS_AMD_FAM_12H(a_enmMicroarch) ((a_enmMicroarch) == kCpumMicroarch_AMD_K10_Llano) + +/** Predicate macro for catching AMD Family 14H CPUs (aka Bobcat). */ +#define CPUMMICROARCH_IS_AMD_FAM_14H(a_enmMicroarch) ((a_enmMicroarch) == kCpumMicroarch_AMD_Bobcat) + +/** Predicate macro for catching AMD Family 15H CPUs (bulldozer and it's + * decendants). */ +#define CPUMMICROARCH_IS_AMD_FAM_15H(a_enmMicroarch) \ + ((a_enmMicroarch) >= kCpumMicroarch_AMD_15h_First && (a_enmMicroarch) <= kCpumMicroarch_AMD_15h_End) + +/** Predicate macro for catching AMD Family 16H CPUs. */ +#define CPUMMICROARCH_IS_AMD_FAM_16H(a_enmMicroarch) \ + ((a_enmMicroarch) >= kCpumMicroarch_AMD_16h_First && (a_enmMicroarch) <= kCpumMicroarch_AMD_16h_End) + +/** Predicate macro for catching AMD Zen Family CPUs. */ +#define CPUMMICROARCH_IS_AMD_FAM_ZEN(a_enmMicroarch) \ + ((a_enmMicroarch) >= kCpumMicroarch_AMD_Zen_First && (a_enmMicroarch) <= kCpumMicroarch_AMD_Zen_End) + + +/** + * CPUID leaf. + * + * @remarks This structure is used by the patch manager and is therefore + * more or less set in stone. + */ +typedef struct CPUMCPUIDLEAF +{ + /** The leaf number. */ + uint32_t uLeaf; + /** The sub-leaf number. */ + uint32_t uSubLeaf; + /** Sub-leaf mask. This is 0 when sub-leaves aren't used. */ + uint32_t fSubLeafMask; + + /** The EAX value. */ + uint32_t uEax; + /** The EBX value. */ + uint32_t uEbx; + /** The ECX value. */ + uint32_t uEcx; + /** The EDX value. */ + uint32_t uEdx; + + /** Flags. */ + uint32_t fFlags; +} CPUMCPUIDLEAF; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(CPUMCPUIDLEAF, 32); +#endif +/** Pointer to a CPUID leaf. */ +typedef CPUMCPUIDLEAF *PCPUMCPUIDLEAF; +/** Pointer to a const CPUID leaf. */ +typedef CPUMCPUIDLEAF const *PCCPUMCPUIDLEAF; + +/** @name CPUMCPUIDLEAF::fFlags + * @{ */ +/** Indicates working intel leaf 0xb where the lower 8 ECX bits are not modified + * and EDX containing the extended APIC ID. */ +#define CPUMCPUIDLEAF_F_INTEL_TOPOLOGY_SUBLEAVES RT_BIT_32(0) +/** The leaf contains an APIC ID that needs changing to that of the current CPU. */ +#define CPUMCPUIDLEAF_F_CONTAINS_APIC_ID RT_BIT_32(1) +/** The leaf contains an OSXSAVE which needs individual handling on each CPU. */ +#define CPUMCPUIDLEAF_F_CONTAINS_OSXSAVE RT_BIT_32(2) +/** The leaf contains an APIC feature bit which is tied to APICBASE.EN. */ +#define CPUMCPUIDLEAF_F_CONTAINS_APIC RT_BIT_32(3) +/** Mask of the valid flags. */ +#define CPUMCPUIDLEAF_F_VALID_MASK UINT32_C(0xf) +/** @} */ + +/** + * Method used to deal with unknown CPUID leaves. + * @remarks Used in patch code. + */ +typedef enum CPUMUNKNOWNCPUID +{ + /** Invalid zero value. */ + CPUMUNKNOWNCPUID_INVALID = 0, + /** Use given default values (DefCpuId). */ + CPUMUNKNOWNCPUID_DEFAULTS, + /** Return the last standard leaf. + * Intel Sandy Bridge has been observed doing this. */ + CPUMUNKNOWNCPUID_LAST_STD_LEAF, + /** Return the last standard leaf, with ecx observed. + * Intel Sandy Bridge has been observed doing this. */ + CPUMUNKNOWNCPUID_LAST_STD_LEAF_WITH_ECX, + /** The register values are passed thru unmodified. */ + CPUMUNKNOWNCPUID_PASSTHRU, + /** End of valid value. */ + CPUMUNKNOWNCPUID_END, + /** Ensure 32-bit type. */ + CPUMUNKNOWNCPUID_32BIT_HACK = 0x7fffffff +} CPUMUNKNOWNCPUID; +/** Pointer to unknown CPUID leaf method. */ +typedef CPUMUNKNOWNCPUID *PCPUMUNKNOWNCPUID; + + +/** + * The register set returned by a CPUID operation. + */ +typedef struct CPUMCPUID +{ + uint32_t uEax; + uint32_t uEbx; + uint32_t uEcx; + uint32_t uEdx; +} CPUMCPUID; +/** Pointer to a CPUID leaf. */ +typedef CPUMCPUID *PCPUMCPUID; +/** Pointer to a const CPUID leaf. */ +typedef const CPUMCPUID *PCCPUMCPUID; + + +/** + * MSR read functions. + */ +typedef enum CPUMMSRRDFN +{ + /** Invalid zero value. */ + kCpumMsrRdFn_Invalid = 0, + /** Return the CPUMMSRRANGE::uValue. */ + kCpumMsrRdFn_FixedValue, + /** Alias to the MSR range starting at the MSR given by + * CPUMMSRRANGE::uValue. Must be used in pair with + * kCpumMsrWrFn_MsrAlias. */ + kCpumMsrRdFn_MsrAlias, + /** Write only register, GP all read attempts. */ + kCpumMsrRdFn_WriteOnly, + + kCpumMsrRdFn_Ia32P5McAddr, + kCpumMsrRdFn_Ia32P5McType, + kCpumMsrRdFn_Ia32TimestampCounter, + kCpumMsrRdFn_Ia32PlatformId, /**< Takes real CPU value for reference. */ + kCpumMsrRdFn_Ia32ApicBase, + kCpumMsrRdFn_Ia32FeatureControl, + kCpumMsrRdFn_Ia32BiosSignId, /**< Range value returned. */ + kCpumMsrRdFn_Ia32SmmMonitorCtl, + kCpumMsrRdFn_Ia32PmcN, + kCpumMsrRdFn_Ia32MonitorFilterLineSize, + kCpumMsrRdFn_Ia32MPerf, + kCpumMsrRdFn_Ia32APerf, + kCpumMsrRdFn_Ia32MtrrCap, /**< Takes real CPU value for reference. */ + kCpumMsrRdFn_Ia32MtrrPhysBaseN, /**< Takes register number. */ + kCpumMsrRdFn_Ia32MtrrPhysMaskN, /**< Takes register number. */ + kCpumMsrRdFn_Ia32MtrrFixed, /**< Takes CPUMCPU offset. */ + kCpumMsrRdFn_Ia32MtrrDefType, + kCpumMsrRdFn_Ia32Pat, + kCpumMsrRdFn_Ia32SysEnterCs, + kCpumMsrRdFn_Ia32SysEnterEsp, + kCpumMsrRdFn_Ia32SysEnterEip, + kCpumMsrRdFn_Ia32McgCap, + kCpumMsrRdFn_Ia32McgStatus, + kCpumMsrRdFn_Ia32McgCtl, + kCpumMsrRdFn_Ia32DebugCtl, + kCpumMsrRdFn_Ia32SmrrPhysBase, + kCpumMsrRdFn_Ia32SmrrPhysMask, + kCpumMsrRdFn_Ia32PlatformDcaCap, + kCpumMsrRdFn_Ia32CpuDcaCap, + kCpumMsrRdFn_Ia32Dca0Cap, + kCpumMsrRdFn_Ia32PerfEvtSelN, /**< Range value indicates the register number. */ + kCpumMsrRdFn_Ia32PerfStatus, /**< Range value returned. */ + kCpumMsrRdFn_Ia32PerfCtl, /**< Range value returned. */ + kCpumMsrRdFn_Ia32FixedCtrN, /**< Takes register number of start of range. */ + kCpumMsrRdFn_Ia32PerfCapabilities, /**< Takes reference value. */ + kCpumMsrRdFn_Ia32FixedCtrCtrl, + kCpumMsrRdFn_Ia32PerfGlobalStatus, /**< Takes reference value. */ + kCpumMsrRdFn_Ia32PerfGlobalCtrl, + kCpumMsrRdFn_Ia32PerfGlobalOvfCtrl, + kCpumMsrRdFn_Ia32PebsEnable, + kCpumMsrRdFn_Ia32ClockModulation, /**< Range value returned. */ + kCpumMsrRdFn_Ia32ThermInterrupt, /**< Range value returned. */ + kCpumMsrRdFn_Ia32ThermStatus, /**< Range value returned. */ + kCpumMsrRdFn_Ia32Therm2Ctl, /**< Range value returned. */ + kCpumMsrRdFn_Ia32MiscEnable, /**< Range value returned. */ + kCpumMsrRdFn_Ia32McCtlStatusAddrMiscN, /**< Takes bank number. */ + kCpumMsrRdFn_Ia32McNCtl2, /**< Takes register number of start of range. */ + kCpumMsrRdFn_Ia32DsArea, + kCpumMsrRdFn_Ia32TscDeadline, + kCpumMsrRdFn_Ia32X2ApicN, + kCpumMsrRdFn_Ia32DebugInterface, + kCpumMsrRdFn_Ia32VmxBasic, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxPinbasedCtls, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxProcbasedCtls, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxExitCtls, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxEntryCtls, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxMisc, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxCr0Fixed0, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxCr0Fixed1, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxCr4Fixed0, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxCr4Fixed1, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxVmcsEnum, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxProcBasedCtls2, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxEptVpidCap, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxTruePinbasedCtls, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxTrueProcbasedCtls, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxTrueExitCtls, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxTrueEntryCtls, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxVmFunc, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32SpecCtrl, + kCpumMsrRdFn_Ia32ArchCapabilities, + + kCpumMsrRdFn_Amd64Efer, + kCpumMsrRdFn_Amd64SyscallTarget, + kCpumMsrRdFn_Amd64LongSyscallTarget, + kCpumMsrRdFn_Amd64CompSyscallTarget, + kCpumMsrRdFn_Amd64SyscallFlagMask, + kCpumMsrRdFn_Amd64FsBase, + kCpumMsrRdFn_Amd64GsBase, + kCpumMsrRdFn_Amd64KernelGsBase, + kCpumMsrRdFn_Amd64TscAux, + + kCpumMsrRdFn_IntelEblCrPowerOn, + kCpumMsrRdFn_IntelI7CoreThreadCount, + kCpumMsrRdFn_IntelP4EbcHardPowerOn, + kCpumMsrRdFn_IntelP4EbcSoftPowerOn, + kCpumMsrRdFn_IntelP4EbcFrequencyId, + kCpumMsrRdFn_IntelP6FsbFrequency, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelPlatformInfo, + kCpumMsrRdFn_IntelFlexRatio, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelPkgCStConfigControl, + kCpumMsrRdFn_IntelPmgIoCaptureBase, + kCpumMsrRdFn_IntelLastBranchFromToN, + kCpumMsrRdFn_IntelLastBranchFromN, + kCpumMsrRdFn_IntelLastBranchToN, + kCpumMsrRdFn_IntelLastBranchTos, + kCpumMsrRdFn_IntelBblCrCtl, + kCpumMsrRdFn_IntelBblCrCtl3, + kCpumMsrRdFn_IntelI7TemperatureTarget, /**< Range value returned. */ + kCpumMsrRdFn_IntelI7MsrOffCoreResponseN,/**< Takes register number. */ + kCpumMsrRdFn_IntelI7MiscPwrMgmt, + kCpumMsrRdFn_IntelP6CrN, + kCpumMsrRdFn_IntelCpuId1FeatureMaskEcdx, + kCpumMsrRdFn_IntelCpuId1FeatureMaskEax, + kCpumMsrRdFn_IntelCpuId80000001FeatureMaskEcdx, + kCpumMsrRdFn_IntelI7SandyAesNiCtl, + kCpumMsrRdFn_IntelI7TurboRatioLimit, /**< Returns range value. */ + kCpumMsrRdFn_IntelI7LbrSelect, + kCpumMsrRdFn_IntelI7SandyErrorControl, + kCpumMsrRdFn_IntelI7VirtualLegacyWireCap,/**< Returns range value. */ + kCpumMsrRdFn_IntelI7PowerCtl, + kCpumMsrRdFn_IntelI7SandyPebsNumAlt, + kCpumMsrRdFn_IntelI7PebsLdLat, + kCpumMsrRdFn_IntelI7PkgCnResidencyN, /**< Takes C-state number. */ + kCpumMsrRdFn_IntelI7CoreCnResidencyN, /**< Takes C-state number. */ + kCpumMsrRdFn_IntelI7SandyVrCurrentConfig,/**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7SandyVrMiscConfig, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7SandyRaplPowerUnit, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7SandyPkgCnIrtlN, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7SandyPkgC2Residency, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplPkgPowerLimit, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplPkgEnergyStatus, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplPkgPerfStatus, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplPkgPowerInfo, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplDramPowerLimit, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplDramEnergyStatus,/**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplDramPerfStatus, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplDramPowerInfo, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplPp0PowerLimit, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplPp0EnergyStatus, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplPp0Policy, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplPp0PerfStatus, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplPp1PowerLimit, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplPp1EnergyStatus, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplPp1Policy, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7IvyConfigTdpNominal, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7IvyConfigTdpLevel1, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7IvyConfigTdpLevel2, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7IvyConfigTdpControl, + kCpumMsrRdFn_IntelI7IvyTurboActivationRatio, + kCpumMsrRdFn_IntelI7UncPerfGlobalCtrl, + kCpumMsrRdFn_IntelI7UncPerfGlobalStatus, + kCpumMsrRdFn_IntelI7UncPerfGlobalOvfCtrl, + kCpumMsrRdFn_IntelI7UncPerfFixedCtrCtrl, + kCpumMsrRdFn_IntelI7UncPerfFixedCtr, + kCpumMsrRdFn_IntelI7UncCBoxConfig, + kCpumMsrRdFn_IntelI7UncArbPerfCtrN, + kCpumMsrRdFn_IntelI7UncArbPerfEvtSelN, + kCpumMsrRdFn_IntelI7SmiCount, + kCpumMsrRdFn_IntelCore2EmttmCrTablesN, /**< Range value returned. */ + kCpumMsrRdFn_IntelCore2SmmCStMiscInfo, + kCpumMsrRdFn_IntelCore1ExtConfig, + kCpumMsrRdFn_IntelCore1DtsCalControl, + kCpumMsrRdFn_IntelCore2PeciControl, + kCpumMsrRdFn_IntelAtSilvCoreC1Recidency, + + kCpumMsrRdFn_P6LastBranchFromIp, + kCpumMsrRdFn_P6LastBranchToIp, + kCpumMsrRdFn_P6LastIntFromIp, + kCpumMsrRdFn_P6LastIntToIp, + + kCpumMsrRdFn_AmdFam15hTscRate, + kCpumMsrRdFn_AmdFam15hLwpCfg, + kCpumMsrRdFn_AmdFam15hLwpCbAddr, + kCpumMsrRdFn_AmdFam10hMc4MiscN, + kCpumMsrRdFn_AmdK8PerfCtlN, + kCpumMsrRdFn_AmdK8PerfCtrN, + kCpumMsrRdFn_AmdK8SysCfg, /**< Range value returned. */ + kCpumMsrRdFn_AmdK8HwCr, + kCpumMsrRdFn_AmdK8IorrBaseN, + kCpumMsrRdFn_AmdK8IorrMaskN, + kCpumMsrRdFn_AmdK8TopOfMemN, + kCpumMsrRdFn_AmdK8NbCfg1, + kCpumMsrRdFn_AmdK8McXcptRedir, + kCpumMsrRdFn_AmdK8CpuNameN, + kCpumMsrRdFn_AmdK8HwThermalCtrl, /**< Range value returned. */ + kCpumMsrRdFn_AmdK8SwThermalCtrl, + kCpumMsrRdFn_AmdK8FidVidControl, /**< Range value returned. */ + kCpumMsrRdFn_AmdK8FidVidStatus, /**< Range value returned. */ + kCpumMsrRdFn_AmdK8McCtlMaskN, + kCpumMsrRdFn_AmdK8SmiOnIoTrapN, + kCpumMsrRdFn_AmdK8SmiOnIoTrapCtlSts, + kCpumMsrRdFn_AmdK8IntPendingMessage, + kCpumMsrRdFn_AmdK8SmiTriggerIoCycle, + kCpumMsrRdFn_AmdFam10hMmioCfgBaseAddr, + kCpumMsrRdFn_AmdFam10hTrapCtlMaybe, + kCpumMsrRdFn_AmdFam10hPStateCurLimit, /**< Returns range value. */ + kCpumMsrRdFn_AmdFam10hPStateControl, /**< Returns range value. */ + kCpumMsrRdFn_AmdFam10hPStateStatus, /**< Returns range value. */ + kCpumMsrRdFn_AmdFam10hPStateN, /**< Returns range value. This isn't an register index! */ + kCpumMsrRdFn_AmdFam10hCofVidControl, /**< Returns range value. */ + kCpumMsrRdFn_AmdFam10hCofVidStatus, /**< Returns range value. */ + kCpumMsrRdFn_AmdFam10hCStateIoBaseAddr, + kCpumMsrRdFn_AmdFam10hCpuWatchdogTimer, + kCpumMsrRdFn_AmdK8SmmBase, + kCpumMsrRdFn_AmdK8SmmAddr, + kCpumMsrRdFn_AmdK8SmmMask, + kCpumMsrRdFn_AmdK8VmCr, + kCpumMsrRdFn_AmdK8IgnNe, + kCpumMsrRdFn_AmdK8SmmCtl, + kCpumMsrRdFn_AmdK8VmHSavePa, + kCpumMsrRdFn_AmdFam10hVmLockKey, + kCpumMsrRdFn_AmdFam10hSmmLockKey, + kCpumMsrRdFn_AmdFam10hLocalSmiStatus, + kCpumMsrRdFn_AmdFam10hOsVisWrkIdLength, + kCpumMsrRdFn_AmdFam10hOsVisWrkStatus, + kCpumMsrRdFn_AmdFam16hL2IPerfCtlN, + kCpumMsrRdFn_AmdFam16hL2IPerfCtrN, + kCpumMsrRdFn_AmdFam15hNorthbridgePerfCtlN, + kCpumMsrRdFn_AmdFam15hNorthbridgePerfCtrN, + kCpumMsrRdFn_AmdK7MicrocodeCtl, /**< Returns range value. */ + kCpumMsrRdFn_AmdK7ClusterIdMaybe, /**< Returns range value. */ + kCpumMsrRdFn_AmdK8CpuIdCtlStd07hEbax, + kCpumMsrRdFn_AmdK8CpuIdCtlStd06hEcx, + kCpumMsrRdFn_AmdK8CpuIdCtlStd01hEdcx, + kCpumMsrRdFn_AmdK8CpuIdCtlExt01hEdcx, + kCpumMsrRdFn_AmdK8PatchLevel, /**< Returns range value. */ + kCpumMsrRdFn_AmdK7DebugStatusMaybe, + kCpumMsrRdFn_AmdK7BHTraceBaseMaybe, + kCpumMsrRdFn_AmdK7BHTracePtrMaybe, + kCpumMsrRdFn_AmdK7BHTraceLimitMaybe, + kCpumMsrRdFn_AmdK7HardwareDebugToolCfgMaybe, + kCpumMsrRdFn_AmdK7FastFlushCountMaybe, + kCpumMsrRdFn_AmdK7NodeId, + kCpumMsrRdFn_AmdK7DrXAddrMaskN, /**< Takes register index. */ + kCpumMsrRdFn_AmdK7Dr0DataMatchMaybe, + kCpumMsrRdFn_AmdK7Dr0DataMaskMaybe, + kCpumMsrRdFn_AmdK7LoadStoreCfg, + kCpumMsrRdFn_AmdK7InstrCacheCfg, + kCpumMsrRdFn_AmdK7DataCacheCfg, + kCpumMsrRdFn_AmdK7BusUnitCfg, + kCpumMsrRdFn_AmdK7DebugCtl2Maybe, + kCpumMsrRdFn_AmdFam15hFpuCfg, + kCpumMsrRdFn_AmdFam15hDecoderCfg, + kCpumMsrRdFn_AmdFam10hBusUnitCfg2, + kCpumMsrRdFn_AmdFam15hCombUnitCfg, + kCpumMsrRdFn_AmdFam15hCombUnitCfg2, + kCpumMsrRdFn_AmdFam15hCombUnitCfg3, + kCpumMsrRdFn_AmdFam15hExecUnitCfg, + kCpumMsrRdFn_AmdFam15hLoadStoreCfg2, + kCpumMsrRdFn_AmdFam10hIbsFetchCtl, + kCpumMsrRdFn_AmdFam10hIbsFetchLinAddr, + kCpumMsrRdFn_AmdFam10hIbsFetchPhysAddr, + kCpumMsrRdFn_AmdFam10hIbsOpExecCtl, + kCpumMsrRdFn_AmdFam10hIbsOpRip, + kCpumMsrRdFn_AmdFam10hIbsOpData, + kCpumMsrRdFn_AmdFam10hIbsOpData2, + kCpumMsrRdFn_AmdFam10hIbsOpData3, + kCpumMsrRdFn_AmdFam10hIbsDcLinAddr, + kCpumMsrRdFn_AmdFam10hIbsDcPhysAddr, + kCpumMsrRdFn_AmdFam10hIbsCtl, + kCpumMsrRdFn_AmdFam14hIbsBrTarget, + + kCpumMsrRdFn_Gim, + + /** End of valid MSR read function indexes. */ + kCpumMsrRdFn_End +} CPUMMSRRDFN; + +/** + * MSR write functions. + */ +typedef enum CPUMMSRWRFN +{ + /** Invalid zero value. */ + kCpumMsrWrFn_Invalid = 0, + /** Writes are ignored, the fWrGpMask is observed though. */ + kCpumMsrWrFn_IgnoreWrite, + /** Writes cause GP(0) to be raised, the fWrGpMask should be UINT64_MAX. */ + kCpumMsrWrFn_ReadOnly, + /** Alias to the MSR range starting at the MSR given by + * CPUMMSRRANGE::uValue. Must be used in pair with + * kCpumMsrRdFn_MsrAlias. */ + kCpumMsrWrFn_MsrAlias, + + kCpumMsrWrFn_Ia32P5McAddr, + kCpumMsrWrFn_Ia32P5McType, + kCpumMsrWrFn_Ia32TimestampCounter, + kCpumMsrWrFn_Ia32ApicBase, + kCpumMsrWrFn_Ia32FeatureControl, + kCpumMsrWrFn_Ia32BiosSignId, + kCpumMsrWrFn_Ia32BiosUpdateTrigger, + kCpumMsrWrFn_Ia32SmmMonitorCtl, + kCpumMsrWrFn_Ia32PmcN, + kCpumMsrWrFn_Ia32MonitorFilterLineSize, + kCpumMsrWrFn_Ia32MPerf, + kCpumMsrWrFn_Ia32APerf, + kCpumMsrWrFn_Ia32MtrrPhysBaseN, /**< Takes register number. */ + kCpumMsrWrFn_Ia32MtrrPhysMaskN, /**< Takes register number. */ + kCpumMsrWrFn_Ia32MtrrFixed, /**< Takes CPUMCPU offset. */ + kCpumMsrWrFn_Ia32MtrrDefType, + kCpumMsrWrFn_Ia32Pat, + kCpumMsrWrFn_Ia32SysEnterCs, + kCpumMsrWrFn_Ia32SysEnterEsp, + kCpumMsrWrFn_Ia32SysEnterEip, + kCpumMsrWrFn_Ia32McgStatus, + kCpumMsrWrFn_Ia32McgCtl, + kCpumMsrWrFn_Ia32DebugCtl, + kCpumMsrWrFn_Ia32SmrrPhysBase, + kCpumMsrWrFn_Ia32SmrrPhysMask, + kCpumMsrWrFn_Ia32PlatformDcaCap, + kCpumMsrWrFn_Ia32Dca0Cap, + kCpumMsrWrFn_Ia32PerfEvtSelN, /**< Range value indicates the register number. */ + kCpumMsrWrFn_Ia32PerfStatus, + kCpumMsrWrFn_Ia32PerfCtl, + kCpumMsrWrFn_Ia32FixedCtrN, /**< Takes register number of start of range. */ + kCpumMsrWrFn_Ia32PerfCapabilities, + kCpumMsrWrFn_Ia32FixedCtrCtrl, + kCpumMsrWrFn_Ia32PerfGlobalStatus, + kCpumMsrWrFn_Ia32PerfGlobalCtrl, + kCpumMsrWrFn_Ia32PerfGlobalOvfCtrl, + kCpumMsrWrFn_Ia32PebsEnable, + kCpumMsrWrFn_Ia32ClockModulation, + kCpumMsrWrFn_Ia32ThermInterrupt, + kCpumMsrWrFn_Ia32ThermStatus, + kCpumMsrWrFn_Ia32Therm2Ctl, + kCpumMsrWrFn_Ia32MiscEnable, + kCpumMsrWrFn_Ia32McCtlStatusAddrMiscN, /**< Takes bank number. */ + kCpumMsrWrFn_Ia32McNCtl2, /**< Takes register number of start of range. */ + kCpumMsrWrFn_Ia32DsArea, + kCpumMsrWrFn_Ia32TscDeadline, + kCpumMsrWrFn_Ia32X2ApicN, + kCpumMsrWrFn_Ia32DebugInterface, + kCpumMsrWrFn_Ia32SpecCtrl, + kCpumMsrWrFn_Ia32PredCmd, + kCpumMsrWrFn_Ia32FlushCmd, + + kCpumMsrWrFn_Amd64Efer, + kCpumMsrWrFn_Amd64SyscallTarget, + kCpumMsrWrFn_Amd64LongSyscallTarget, + kCpumMsrWrFn_Amd64CompSyscallTarget, + kCpumMsrWrFn_Amd64SyscallFlagMask, + kCpumMsrWrFn_Amd64FsBase, + kCpumMsrWrFn_Amd64GsBase, + kCpumMsrWrFn_Amd64KernelGsBase, + kCpumMsrWrFn_Amd64TscAux, + kCpumMsrWrFn_IntelEblCrPowerOn, + kCpumMsrWrFn_IntelP4EbcHardPowerOn, + kCpumMsrWrFn_IntelP4EbcSoftPowerOn, + kCpumMsrWrFn_IntelP4EbcFrequencyId, + kCpumMsrWrFn_IntelFlexRatio, + kCpumMsrWrFn_IntelPkgCStConfigControl, + kCpumMsrWrFn_IntelPmgIoCaptureBase, + kCpumMsrWrFn_IntelLastBranchFromToN, + kCpumMsrWrFn_IntelLastBranchFromN, + kCpumMsrWrFn_IntelLastBranchToN, + kCpumMsrWrFn_IntelLastBranchTos, + kCpumMsrWrFn_IntelBblCrCtl, + kCpumMsrWrFn_IntelBblCrCtl3, + kCpumMsrWrFn_IntelI7TemperatureTarget, + kCpumMsrWrFn_IntelI7MsrOffCoreResponseN, /**< Takes register number. */ + kCpumMsrWrFn_IntelI7MiscPwrMgmt, + kCpumMsrWrFn_IntelP6CrN, + kCpumMsrWrFn_IntelCpuId1FeatureMaskEcdx, + kCpumMsrWrFn_IntelCpuId1FeatureMaskEax, + kCpumMsrWrFn_IntelCpuId80000001FeatureMaskEcdx, + kCpumMsrWrFn_IntelI7SandyAesNiCtl, + kCpumMsrWrFn_IntelI7TurboRatioLimit, + kCpumMsrWrFn_IntelI7LbrSelect, + kCpumMsrWrFn_IntelI7SandyErrorControl, + kCpumMsrWrFn_IntelI7PowerCtl, + kCpumMsrWrFn_IntelI7SandyPebsNumAlt, + kCpumMsrWrFn_IntelI7PebsLdLat, + kCpumMsrWrFn_IntelI7SandyVrCurrentConfig, + kCpumMsrWrFn_IntelI7SandyVrMiscConfig, + kCpumMsrWrFn_IntelI7SandyRaplPowerUnit, /**< R/O but found writable bits on a Silvermont CPU here. */ + kCpumMsrWrFn_IntelI7SandyPkgCnIrtlN, + kCpumMsrWrFn_IntelI7SandyPkgC2Residency, /**< R/O but found writable bits on a Silvermont CPU here. */ + kCpumMsrWrFn_IntelI7RaplPkgPowerLimit, + kCpumMsrWrFn_IntelI7RaplDramPowerLimit, + kCpumMsrWrFn_IntelI7RaplPp0PowerLimit, + kCpumMsrWrFn_IntelI7RaplPp0Policy, + kCpumMsrWrFn_IntelI7RaplPp1PowerLimit, + kCpumMsrWrFn_IntelI7RaplPp1Policy, + kCpumMsrWrFn_IntelI7IvyConfigTdpControl, + kCpumMsrWrFn_IntelI7IvyTurboActivationRatio, + kCpumMsrWrFn_IntelI7UncPerfGlobalCtrl, + kCpumMsrWrFn_IntelI7UncPerfGlobalStatus, + kCpumMsrWrFn_IntelI7UncPerfGlobalOvfCtrl, + kCpumMsrWrFn_IntelI7UncPerfFixedCtrCtrl, + kCpumMsrWrFn_IntelI7UncPerfFixedCtr, + kCpumMsrWrFn_IntelI7UncArbPerfCtrN, + kCpumMsrWrFn_IntelI7UncArbPerfEvtSelN, + kCpumMsrWrFn_IntelCore2EmttmCrTablesN, + kCpumMsrWrFn_IntelCore2SmmCStMiscInfo, + kCpumMsrWrFn_IntelCore1ExtConfig, + kCpumMsrWrFn_IntelCore1DtsCalControl, + kCpumMsrWrFn_IntelCore2PeciControl, + + kCpumMsrWrFn_P6LastIntFromIp, + kCpumMsrWrFn_P6LastIntToIp, + + kCpumMsrWrFn_AmdFam15hTscRate, + kCpumMsrWrFn_AmdFam15hLwpCfg, + kCpumMsrWrFn_AmdFam15hLwpCbAddr, + kCpumMsrWrFn_AmdFam10hMc4MiscN, + kCpumMsrWrFn_AmdK8PerfCtlN, + kCpumMsrWrFn_AmdK8PerfCtrN, + kCpumMsrWrFn_AmdK8SysCfg, + kCpumMsrWrFn_AmdK8HwCr, + kCpumMsrWrFn_AmdK8IorrBaseN, + kCpumMsrWrFn_AmdK8IorrMaskN, + kCpumMsrWrFn_AmdK8TopOfMemN, + kCpumMsrWrFn_AmdK8NbCfg1, + kCpumMsrWrFn_AmdK8McXcptRedir, + kCpumMsrWrFn_AmdK8CpuNameN, + kCpumMsrWrFn_AmdK8HwThermalCtrl, + kCpumMsrWrFn_AmdK8SwThermalCtrl, + kCpumMsrWrFn_AmdK8FidVidControl, + kCpumMsrWrFn_AmdK8McCtlMaskN, + kCpumMsrWrFn_AmdK8SmiOnIoTrapN, + kCpumMsrWrFn_AmdK8SmiOnIoTrapCtlSts, + kCpumMsrWrFn_AmdK8IntPendingMessage, + kCpumMsrWrFn_AmdK8SmiTriggerIoCycle, + kCpumMsrWrFn_AmdFam10hMmioCfgBaseAddr, + kCpumMsrWrFn_AmdFam10hTrapCtlMaybe, + kCpumMsrWrFn_AmdFam10hPStateControl, + kCpumMsrWrFn_AmdFam10hPStateStatus, + kCpumMsrWrFn_AmdFam10hPStateN, + kCpumMsrWrFn_AmdFam10hCofVidControl, + kCpumMsrWrFn_AmdFam10hCofVidStatus, + kCpumMsrWrFn_AmdFam10hCStateIoBaseAddr, + kCpumMsrWrFn_AmdFam10hCpuWatchdogTimer, + kCpumMsrWrFn_AmdK8SmmBase, + kCpumMsrWrFn_AmdK8SmmAddr, + kCpumMsrWrFn_AmdK8SmmMask, + kCpumMsrWrFn_AmdK8VmCr, + kCpumMsrWrFn_AmdK8IgnNe, + kCpumMsrWrFn_AmdK8SmmCtl, + kCpumMsrWrFn_AmdK8VmHSavePa, + kCpumMsrWrFn_AmdFam10hVmLockKey, + kCpumMsrWrFn_AmdFam10hSmmLockKey, + kCpumMsrWrFn_AmdFam10hLocalSmiStatus, + kCpumMsrWrFn_AmdFam10hOsVisWrkIdLength, + kCpumMsrWrFn_AmdFam10hOsVisWrkStatus, + kCpumMsrWrFn_AmdFam16hL2IPerfCtlN, + kCpumMsrWrFn_AmdFam16hL2IPerfCtrN, + kCpumMsrWrFn_AmdFam15hNorthbridgePerfCtlN, + kCpumMsrWrFn_AmdFam15hNorthbridgePerfCtrN, + kCpumMsrWrFn_AmdK7MicrocodeCtl, + kCpumMsrWrFn_AmdK7ClusterIdMaybe, + kCpumMsrWrFn_AmdK8CpuIdCtlStd07hEbax, + kCpumMsrWrFn_AmdK8CpuIdCtlStd06hEcx, + kCpumMsrWrFn_AmdK8CpuIdCtlStd01hEdcx, + kCpumMsrWrFn_AmdK8CpuIdCtlExt01hEdcx, + kCpumMsrWrFn_AmdK8PatchLoader, + kCpumMsrWrFn_AmdK7DebugStatusMaybe, + kCpumMsrWrFn_AmdK7BHTraceBaseMaybe, + kCpumMsrWrFn_AmdK7BHTracePtrMaybe, + kCpumMsrWrFn_AmdK7BHTraceLimitMaybe, + kCpumMsrWrFn_AmdK7HardwareDebugToolCfgMaybe, + kCpumMsrWrFn_AmdK7FastFlushCountMaybe, + kCpumMsrWrFn_AmdK7NodeId, + kCpumMsrWrFn_AmdK7DrXAddrMaskN, /**< Takes register index. */ + kCpumMsrWrFn_AmdK7Dr0DataMatchMaybe, + kCpumMsrWrFn_AmdK7Dr0DataMaskMaybe, + kCpumMsrWrFn_AmdK7LoadStoreCfg, + kCpumMsrWrFn_AmdK7InstrCacheCfg, + kCpumMsrWrFn_AmdK7DataCacheCfg, + kCpumMsrWrFn_AmdK7BusUnitCfg, + kCpumMsrWrFn_AmdK7DebugCtl2Maybe, + kCpumMsrWrFn_AmdFam15hFpuCfg, + kCpumMsrWrFn_AmdFam15hDecoderCfg, + kCpumMsrWrFn_AmdFam10hBusUnitCfg2, + kCpumMsrWrFn_AmdFam15hCombUnitCfg, + kCpumMsrWrFn_AmdFam15hCombUnitCfg2, + kCpumMsrWrFn_AmdFam15hCombUnitCfg3, + kCpumMsrWrFn_AmdFam15hExecUnitCfg, + kCpumMsrWrFn_AmdFam15hLoadStoreCfg2, + kCpumMsrWrFn_AmdFam10hIbsFetchCtl, + kCpumMsrWrFn_AmdFam10hIbsFetchLinAddr, + kCpumMsrWrFn_AmdFam10hIbsFetchPhysAddr, + kCpumMsrWrFn_AmdFam10hIbsOpExecCtl, + kCpumMsrWrFn_AmdFam10hIbsOpRip, + kCpumMsrWrFn_AmdFam10hIbsOpData, + kCpumMsrWrFn_AmdFam10hIbsOpData2, + kCpumMsrWrFn_AmdFam10hIbsOpData3, + kCpumMsrWrFn_AmdFam10hIbsDcLinAddr, + kCpumMsrWrFn_AmdFam10hIbsDcPhysAddr, + kCpumMsrWrFn_AmdFam10hIbsCtl, + kCpumMsrWrFn_AmdFam14hIbsBrTarget, + + kCpumMsrWrFn_Gim, + + /** End of valid MSR write function indexes. */ + kCpumMsrWrFn_End +} CPUMMSRWRFN; + +/** + * MSR range. + */ +typedef struct CPUMMSRRANGE +{ + /** The first MSR. [0] */ + uint32_t uFirst; + /** The last MSR. [4] */ + uint32_t uLast; + /** The read function (CPUMMSRRDFN). [8] */ + uint16_t enmRdFn; + /** The write function (CPUMMSRWRFN). [10] */ + uint16_t enmWrFn; + /** The offset of the 64-bit MSR value relative to the start of CPUMCPU. + * UINT16_MAX if not used by the read and write functions. [12] */ + uint32_t offCpumCpu : 24; + /** Reserved for future hacks. [15] */ + uint32_t fReserved : 8; + /** The init/read value. [16] + * When enmRdFn is kCpumMsrRdFn_INIT_VALUE, this is the value returned on RDMSR. + * offCpumCpu must be UINT16_MAX in that case, otherwise it must be a valid + * offset into CPUM. */ + uint64_t uValue; + /** The bits to ignore when writing. [24] */ + uint64_t fWrIgnMask; + /** The bits that will cause a GP(0) when writing. [32] + * This is always checked prior to calling the write function. Using + * UINT64_MAX effectively marks the MSR as read-only. */ + uint64_t fWrGpMask; + /** The register name, if applicable. [40] */ + char szName[56]; + + /** The number of reads. */ + STAMCOUNTER cReads; + /** The number of writes. */ + STAMCOUNTER cWrites; + /** The number of times ignored bits were written. */ + STAMCOUNTER cIgnoredBits; + /** The number of GPs generated. */ + STAMCOUNTER cGps; +} CPUMMSRRANGE; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(CPUMMSRRANGE, 128); +#endif +/** Pointer to an MSR range. */ +typedef CPUMMSRRANGE *PCPUMMSRRANGE; +/** Pointer to a const MSR range. */ +typedef CPUMMSRRANGE const *PCCPUMMSRRANGE; + + +/** + * MSRs which are required while exploding features. + */ +typedef struct CPUMMSRS +{ + union + { + VMXMSRS vmx; + SVMMSRS svm; + } hwvirt; +} CPUMMSRS; +/** Pointer to an CPUMMSRS struct. */ +typedef CPUMMSRS *PCPUMMSRS; +/** Pointer to a const CPUMMSRS struct. */ +typedef CPUMMSRS const *PCCPUMMSRS; + + +/** + * CPU features and quirks. + * This is mostly exploded CPUID info. + */ +typedef struct CPUMFEATURES +{ + /** The CPU vendor (CPUMCPUVENDOR). */ + uint8_t enmCpuVendor; + /** The CPU family. */ + uint8_t uFamily; + /** The CPU model. */ + uint8_t uModel; + /** The CPU stepping. */ + uint8_t uStepping; + /** The microarchitecture. */ +#ifndef VBOX_FOR_DTRACE_LIB + CPUMMICROARCH enmMicroarch; +#else + uint32_t enmMicroarch; +#endif + /** The maximum physical address width of the CPU. */ + uint8_t cMaxPhysAddrWidth; + /** The maximum linear address width of the CPU. */ + uint8_t cMaxLinearAddrWidth; + /** Max size of the extended state (or FPU state if no XSAVE). */ + uint16_t cbMaxExtendedState; + + /** Supports MSRs. */ + uint32_t fMsr : 1; + /** Supports the page size extension (4/2 MB pages). */ + uint32_t fPse : 1; + /** Supports 36-bit page size extension (4 MB pages can map memory above + * 4GB). */ + uint32_t fPse36 : 1; + /** Supports physical address extension (PAE). */ + uint32_t fPae : 1; + /** Supports page-global extension (PGE). */ + uint32_t fPge : 1; + /** Page attribute table (PAT) support (page level cache control). */ + uint32_t fPat : 1; + /** Supports the FXSAVE and FXRSTOR instructions. */ + uint32_t fFxSaveRstor : 1; + /** Supports the XSAVE and XRSTOR instructions. */ + uint32_t fXSaveRstor : 1; + /** Supports the XSAVEOPT instruction. */ + uint32_t fXSaveOpt : 1; + /** The XSAVE/XRSTOR bit in CR4 has been set (only applicable for host!). */ + uint32_t fOpSysXSaveRstor : 1; + /** Supports MMX. */ + uint32_t fMmx : 1; + /** Supports AMD extensions to MMX instructions. */ + uint32_t fAmdMmxExts : 1; + /** Supports SSE. */ + uint32_t fSse : 1; + /** Supports SSE2. */ + uint32_t fSse2 : 1; + /** Supports SSE3. */ + uint32_t fSse3 : 1; + /** Supports SSSE3. */ + uint32_t fSsse3 : 1; + /** Supports SSE4.1. */ + uint32_t fSse41 : 1; + /** Supports SSE4.2. */ + uint32_t fSse42 : 1; + /** Supports AVX. */ + uint32_t fAvx : 1; + /** Supports AVX2. */ + uint32_t fAvx2 : 1; + /** Supports AVX512 foundation. */ + uint32_t fAvx512Foundation : 1; + /** Supports RDTSC. */ + uint32_t fTsc : 1; + /** Intel SYSENTER/SYSEXIT support */ + uint32_t fSysEnter : 1; + /** First generation APIC. */ + uint32_t fApic : 1; + /** Second generation APIC. */ + uint32_t fX2Apic : 1; + /** Hypervisor present. */ + uint32_t fHypervisorPresent : 1; + /** MWAIT & MONITOR instructions supported. */ + uint32_t fMonitorMWait : 1; + /** MWAIT Extensions present. */ + uint32_t fMWaitExtensions : 1; + /** Supports CMPXCHG16B in 64-bit mode. */ + uint32_t fMovCmpXchg16b : 1; + /** Supports CLFLUSH. */ + uint32_t fClFlush : 1; + /** Supports CLFLUSHOPT. */ + uint32_t fClFlushOpt : 1; + /** Supports IA32_PRED_CMD.IBPB. */ + uint32_t fIbpb : 1; + /** Supports IA32_SPEC_CTRL.IBRS. */ + uint32_t fIbrs : 1; + /** Supports IA32_SPEC_CTRL.STIBP. */ + uint32_t fStibp : 1; + /** Supports IA32_FLUSH_CMD. */ + uint32_t fFlushCmd : 1; + /** Supports IA32_ARCH_CAP. */ + uint32_t fArchCap : 1; + /** Supports MD_CLEAR functionality (VERW, IA32_FLUSH_CMD). */ + uint32_t fMdsClear : 1; + /** Supports PCID. */ + uint32_t fPcid : 1; + /** Supports INVPCID. */ + uint32_t fInvpcid : 1; + /** Supports read/write FSGSBASE instructions. */ + uint32_t fFsGsBase : 1; + /** Supports BMI1 instructions (ANDN, BEXTR, BLSI, BLSMSK, BLSR, and TZCNT). */ + uint32_t fBmi1 : 1; + /** Supports BMI2 instructions (BZHI, MULX, PDEP, PEXT, RORX, SARX, SHRX, + * and SHLX). */ + uint32_t fBmi2 : 1; + /** Supports POPCNT instruction. */ + uint32_t fPopCnt : 1; + /** Supports RDRAND instruction. */ + uint32_t fRdRand : 1; + /** Supports RDSEED instruction. */ + uint32_t fRdSeed : 1; + /** Supports Hardware Lock Elision (HLE). */ + uint32_t fHle : 1; + /** Supports Restricted Transactional Memory (RTM - XBEGIN, XEND, XABORT). */ + uint32_t fRtm : 1; + /** Supports PCLMULQDQ instruction. */ + uint32_t fPclMul : 1; + /** Supports AES-NI (six AESxxx instructions). */ + uint32_t fAesNi : 1; + /** Support MOVBE instruction. */ + uint32_t fMovBe : 1; + + /** Supports AMD 3DNow instructions. */ + uint32_t f3DNow : 1; + /** Supports the 3DNow/AMD64 prefetch instructions (could be nops). */ + uint32_t f3DNowPrefetch : 1; + + /** AMD64: Supports long mode. */ + uint32_t fLongMode : 1; + /** AMD64: SYSCALL/SYSRET support. */ + uint32_t fSysCall : 1; + /** AMD64: No-execute page table bit. */ + uint32_t fNoExecute : 1; + /** AMD64: Supports LAHF & SAHF instructions in 64-bit mode. */ + uint32_t fLahfSahf : 1; + /** AMD64: Supports RDTSCP. */ + uint32_t fRdTscP : 1; + /** AMD64: Supports MOV CR8 in 32-bit code (lock prefix hack). */ + uint32_t fMovCr8In32Bit : 1; + /** AMD64: Supports XOP (similar to VEX3/AVX). */ + uint32_t fXop : 1; + /** AMD64: Supports ABM, i.e. the LZCNT instruction. */ + uint32_t fAbm : 1; + /** AMD64: Supports TBM (BEXTR, BLCFILL, BLCI, BLCIC, BLCMSK, BLCS, + * BLSFILL, BLSIC, T1MSKC, and TZMSK). */ + uint32_t fTbm : 1; + + /** Indicates that FPU instruction and data pointers may leak. + * This generally applies to recent AMD CPUs, where the FPU IP and DP pointer + * is only saved and restored if an exception is pending. */ + uint32_t fLeakyFxSR : 1; + + /** AMD64: Supports AMD SVM. */ + uint32_t fSvm : 1; + + /** Support for Intel VMX. */ + uint32_t fVmx : 1; + + /** Indicates that speculative execution control CPUID bits and MSRs are exposed. + * The details are different for Intel and AMD but both have similar + * functionality. */ + uint32_t fSpeculationControl : 1; + + /** MSR_IA32_ARCH_CAPABILITIES: RDCL_NO (bit 0). + * @remarks Only safe use after CPUM ring-0 init! */ + uint32_t fArchRdclNo : 1; + /** MSR_IA32_ARCH_CAPABILITIES: IBRS_ALL (bit 1). + * @remarks Only safe use after CPUM ring-0 init! */ + uint32_t fArchIbrsAll : 1; + /** MSR_IA32_ARCH_CAPABILITIES: RSB Override (bit 2). + * @remarks Only safe use after CPUM ring-0 init! */ + uint32_t fArchRsbOverride : 1; + /** MSR_IA32_ARCH_CAPABILITIES: RSB Override (bit 3). + * @remarks Only safe use after CPUM ring-0 init! */ + uint32_t fArchVmmNeedNotFlushL1d : 1; + /** MSR_IA32_ARCH_CAPABILITIES: MDS_NO (bit 4). + * @remarks Only safe use after CPUM ring-0 init! */ + uint32_t fArchMdsNo : 1; + + /** Alignment padding / reserved for future use (96 bits total, plus 12 bytes + * prior to the bit fields -> total of 24 bytes) */ + uint32_t fPadding0 : 26; + + + /** @name SVM + * @{ */ + /** SVM: Supports Nested-paging. */ + uint32_t fSvmNestedPaging : 1; + /** SVM: Support LBR (Last Branch Record) virtualization. */ + uint32_t fSvmLbrVirt : 1; + /** SVM: Supports SVM lock. */ + uint32_t fSvmSvmLock : 1; + /** SVM: Supports Next RIP save. */ + uint32_t fSvmNextRipSave : 1; + /** SVM: Supports TSC rate MSR. */ + uint32_t fSvmTscRateMsr : 1; + /** SVM: Supports VMCB clean bits. */ + uint32_t fSvmVmcbClean : 1; + /** SVM: Supports Flush-by-ASID. */ + uint32_t fSvmFlusbByAsid : 1; + /** SVM: Supports decode assist. */ + uint32_t fSvmDecodeAssists : 1; + /** SVM: Supports Pause filter. */ + uint32_t fSvmPauseFilter : 1; + /** SVM: Supports Pause filter threshold. */ + uint32_t fSvmPauseFilterThreshold : 1; + /** SVM: Supports AVIC (Advanced Virtual Interrupt Controller). */ + uint32_t fSvmAvic : 1; + /** SVM: Supports Virtualized VMSAVE/VMLOAD. */ + uint32_t fSvmVirtVmsaveVmload : 1; + /** SVM: Supports VGIF (Virtual Global Interrupt Flag). */ + uint32_t fSvmVGif : 1; + /** SVM: Supports GMET (Guest Mode Execute Trap Extension). */ + uint32_t fSvmGmet : 1; + /** SVM: Supports SSSCheck (SVM Supervisor Shadow Stack). */ + uint32_t fSvmSSSCheck : 1; + /** SVM: Supports SPEC_CTRL virtualization. */ + uint32_t fSvmSpecCtrl : 1; + /** SVM: Supports HOST_MCE_OVERRIDE. */ + uint32_t fSvmHostMceOverride : 1; + /** SVM: Supports TlbiCtl (INVLPGB/TLBSYNC in VMCB and TLBSYNC intercept). */ + uint32_t fSvmTlbiCtl : 1; + /** SVM: Padding / reserved for future features (64 bits total w/ max ASID). */ + uint32_t fSvmPadding0 : 14; + /** SVM: Maximum supported ASID. */ + uint32_t uSvmMaxAsid; + /** @} */ + + + /** VMX: Maximum physical address width. */ + uint32_t cVmxMaxPhysAddrWidth : 8; + + /** @name VMX basic controls. + * @{ */ + /** VMX: Supports INS/OUTS VM-exit instruction info. */ + uint32_t fVmxInsOutInfo : 1; + /** @} */ + + /** @name VMX Pin-based controls. + * @{ */ + /** VMX: Supports external interrupt VM-exit. */ + uint32_t fVmxExtIntExit : 1; + /** VMX: Supports NMI VM-exit. */ + uint32_t fVmxNmiExit : 1; + /** VMX: Supports Virtual NMIs. */ + uint32_t fVmxVirtNmi : 1; + /** VMX: Supports preemption timer. */ + uint32_t fVmxPreemptTimer : 1; + /** VMX: Supports posted interrupts. */ + uint32_t fVmxPostedInt : 1; + /** @} */ + + /** @name VMX Processor-based controls. + * @{ */ + /** VMX: Supports Interrupt-window exiting. */ + uint32_t fVmxIntWindowExit : 1; + /** VMX: Supports TSC offsetting. */ + uint32_t fVmxTscOffsetting : 1; + /** VMX: Supports HLT exiting. */ + uint32_t fVmxHltExit : 1; + /** VMX: Supports INVLPG exiting. */ + uint32_t fVmxInvlpgExit : 1; + /** VMX: Supports MWAIT exiting. */ + uint32_t fVmxMwaitExit : 1; + /** VMX: Supports RDPMC exiting. */ + uint32_t fVmxRdpmcExit : 1; + /** VMX: Supports RDTSC exiting. */ + uint32_t fVmxRdtscExit : 1; + /** VMX: Supports CR3-load exiting. */ + uint32_t fVmxCr3LoadExit : 1; + /** VMX: Supports CR3-store exiting. */ + uint32_t fVmxCr3StoreExit : 1; + /** VMX: Supports tertiary processor-based VM-execution controls. */ + uint32_t fVmxTertiaryExecCtls : 1; + /** VMX: Supports CR8-load exiting. */ + uint32_t fVmxCr8LoadExit : 1; + /** VMX: Supports CR8-store exiting. */ + uint32_t fVmxCr8StoreExit : 1; + /** VMX: Supports TPR shadow. */ + uint32_t fVmxUseTprShadow : 1; + /** VMX: Supports NMI-window exiting. */ + uint32_t fVmxNmiWindowExit : 1; + /** VMX: Supports Mov-DRx exiting. */ + uint32_t fVmxMovDRxExit : 1; + /** VMX: Supports Unconditional I/O exiting. */ + uint32_t fVmxUncondIoExit : 1; + /** VMX: Supportgs I/O bitmaps. */ + uint32_t fVmxUseIoBitmaps : 1; + /** VMX: Supports Monitor Trap Flag. */ + uint32_t fVmxMonitorTrapFlag : 1; + /** VMX: Supports MSR bitmap. */ + uint32_t fVmxUseMsrBitmaps : 1; + /** VMX: Supports MONITOR exiting. */ + uint32_t fVmxMonitorExit : 1; + /** VMX: Supports PAUSE exiting. */ + uint32_t fVmxPauseExit : 1; + /** VMX: Supports secondary processor-based VM-execution controls. */ + uint32_t fVmxSecondaryExecCtls : 1; + /** @} */ + + /** @name VMX Secondary processor-based controls. + * @{ */ + /** VMX: Supports virtualize-APIC access. */ + uint32_t fVmxVirtApicAccess : 1; + /** VMX: Supports EPT (Extended Page Tables). */ + uint32_t fVmxEpt : 1; + /** VMX: Supports descriptor-table exiting. */ + uint32_t fVmxDescTableExit : 1; + /** VMX: Supports RDTSCP. */ + uint32_t fVmxRdtscp : 1; + /** VMX: Supports virtualize-x2APIC mode. */ + uint32_t fVmxVirtX2ApicMode : 1; + /** VMX: Supports VPID. */ + uint32_t fVmxVpid : 1; + /** VMX: Supports WBIND exiting. */ + uint32_t fVmxWbinvdExit : 1; + /** VMX: Supports Unrestricted guest. */ + uint32_t fVmxUnrestrictedGuest : 1; + /** VMX: Supports APIC-register virtualization. */ + uint32_t fVmxApicRegVirt : 1; + /** VMX: Supports virtual-interrupt delivery. */ + uint32_t fVmxVirtIntDelivery : 1; + /** VMX: Supports Pause-loop exiting. */ + uint32_t fVmxPauseLoopExit : 1; + /** VMX: Supports RDRAND exiting. */ + uint32_t fVmxRdrandExit : 1; + /** VMX: Supports INVPCID. */ + uint32_t fVmxInvpcid : 1; + /** VMX: Supports VM functions. */ + uint32_t fVmxVmFunc : 1; + /** VMX: Supports VMCS shadowing. */ + uint32_t fVmxVmcsShadowing : 1; + /** VMX: Supports RDSEED exiting. */ + uint32_t fVmxRdseedExit : 1; + /** VMX: Supports PML. */ + uint32_t fVmxPml : 1; + /** VMX: Supports EPT-violations \#VE. */ + uint32_t fVmxEptXcptVe : 1; + /** VMX: Supports conceal VMX from PT. */ + uint32_t fVmxConcealVmxFromPt : 1; + /** VMX: Supports XSAVES/XRSTORS. */ + uint32_t fVmxXsavesXrstors : 1; + /** VMX: Supports mode-based execute control for EPT. */ + uint32_t fVmxModeBasedExecuteEpt : 1; + /** VMX: Supports sub-page write permissions for EPT. */ + uint32_t fVmxSppEpt : 1; + /** VMX: Supports Intel PT to output guest-physical addresses for EPT. */ + uint32_t fVmxPtEpt : 1; + /** VMX: Supports TSC scaling. */ + uint32_t fVmxUseTscScaling : 1; + /** VMX: Supports TPAUSE, UMONITOR, or UMWAIT. */ + uint32_t fVmxUserWaitPause : 1; + /** VMX: Supports enclave (ENCLV) exiting. */ + uint32_t fVmxEnclvExit : 1; + /** @} */ + + /** @name VMX Tertiary processor-based controls. + * @{ */ + /** VMX: Supports LOADIWKEY exiting. */ + uint32_t fVmxLoadIwKeyExit : 1; + /** @} */ + + /** @name VMX VM-entry controls. + * @{ */ + /** VMX: Supports load-debug controls on VM-entry. */ + uint32_t fVmxEntryLoadDebugCtls : 1; + /** VMX: Supports IA32e mode guest. */ + uint32_t fVmxIa32eModeGuest : 1; + /** VMX: Supports load guest EFER MSR on VM-entry. */ + uint32_t fVmxEntryLoadEferMsr : 1; + /** VMX: Supports load guest PAT MSR on VM-entry. */ + uint32_t fVmxEntryLoadPatMsr : 1; + /** @} */ + + /** @name VMX VM-exit controls. + * @{ */ + /** VMX: Supports save debug controls on VM-exit. */ + uint32_t fVmxExitSaveDebugCtls : 1; + /** VMX: Supports host-address space size. */ + uint32_t fVmxHostAddrSpaceSize : 1; + /** VMX: Supports acknowledge external interrupt on VM-exit. */ + uint32_t fVmxExitAckExtInt : 1; + /** VMX: Supports save guest PAT MSR on VM-exit. */ + uint32_t fVmxExitSavePatMsr : 1; + /** VMX: Supports load hsot PAT MSR on VM-exit. */ + uint32_t fVmxExitLoadPatMsr : 1; + /** VMX: Supports save guest EFER MSR on VM-exit. */ + uint32_t fVmxExitSaveEferMsr : 1; + /** VMX: Supports load host EFER MSR on VM-exit. */ + uint32_t fVmxExitLoadEferMsr : 1; + /** VMX: Supports save VMX preemption timer on VM-exit. */ + uint32_t fVmxSavePreemptTimer : 1; + /** VMX: Supports secondary VM-exit controls. */ + uint32_t fVmxSecondaryExitCtls : 1; + /** @} */ + + /** @name VMX Miscellaneous data. + * @{ */ + /** VMX: Supports storing EFER.LMA into IA32e-mode guest field on VM-exit. */ + uint32_t fVmxExitSaveEferLma : 1; + /** VMX: Whether Intel PT (Processor Trace) is supported in VMX mode or not. */ + uint32_t fVmxPt : 1; + /** VMX: Supports VMWRITE to any valid VMCS field incl. read-only fields, otherwise + * VMWRITE cannot modify read-only VM-exit information fields. */ + uint32_t fVmxVmwriteAll : 1; + /** VMX: Supports injection of software interrupts, ICEBP on VM-entry for zero + * length instructions. */ + uint32_t fVmxEntryInjectSoftInt : 1; + /** @} */ + + /** VMX: Padding / reserved for future features. */ + uint32_t fVmxPadding0 : 16; + /** VMX: Padding / reserved for future, making it a total of 128 bits. */ + uint32_t fVmxPadding1; +} CPUMFEATURES; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(CPUMFEATURES, 48); +#endif +/** Pointer to a CPU feature structure. */ +typedef CPUMFEATURES *PCPUMFEATURES; +/** Pointer to a const CPU feature structure. */ +typedef CPUMFEATURES const *PCCPUMFEATURES; + +/** + * Chameleon wrapper structure for the host CPU features. + * + * This is used for the globally readable g_CpumHostFeatures variable, which is + * initialized once during VMMR0 load for ring-0 and during CPUMR3Init in + * ring-3. To reflect this immutability after load/init, we use this wrapper + * structure to switch it between const and non-const depending on the context. + * Only two files sees it as non-const (CPUMR0.cpp and CPUM.cpp). + */ +typedef struct CPUHOSTFEATURES +{ + CPUMFEATURES +#ifndef CPUM_WITH_NONCONST_HOST_FEATURES + const +#endif + s; +} CPUHOSTFEATURES; +/** Pointer to a const host CPU feature structure. */ +typedef CPUHOSTFEATURES const *PCCPUHOSTFEATURES; + +/** Host CPU features. + * @note In ring-3, only valid after CPUMR3Init. In ring-0, valid after + * module init. */ +extern CPUHOSTFEATURES g_CpumHostFeatures; + + +/** + * CPU database entry. + */ +typedef struct CPUMDBENTRY +{ + /** The CPU name. */ + const char *pszName; + /** The full CPU name. */ + const char *pszFullName; + /** The CPU vendor (CPUMCPUVENDOR). */ + uint8_t enmVendor; + /** The CPU family. */ + uint8_t uFamily; + /** The CPU model. */ + uint8_t uModel; + /** The CPU stepping. */ + uint8_t uStepping; + /** The microarchitecture. */ + CPUMMICROARCH enmMicroarch; + /** Scalable bus frequency used for reporting other frequencies. */ + uint64_t uScalableBusFreq; + /** Flags - CPUMDB_F_XXX. */ + uint32_t fFlags; + /** The maximum physical address with of the CPU. This should correspond to + * the value in CPUID leaf 0x80000008 when present. */ + uint8_t cMaxPhysAddrWidth; + /** The MXCSR mask. */ + uint32_t fMxCsrMask; + /** Pointer to an array of CPUID leaves. */ + PCCPUMCPUIDLEAF paCpuIdLeaves; + /** The number of CPUID leaves in the array paCpuIdLeaves points to. */ + uint32_t cCpuIdLeaves; + /** The method used to deal with unknown CPUID leaves. */ + CPUMUNKNOWNCPUID enmUnknownCpuId; + /** The default unknown CPUID value. */ + CPUMCPUID DefUnknownCpuId; + + /** MSR mask. Several microarchitectures ignore the higher bits of ECX in + * the RDMSR and WRMSR instructions. */ + uint32_t fMsrMask; + + /** The number of ranges in the table pointed to b paMsrRanges. */ + uint32_t cMsrRanges; + /** MSR ranges for this CPU. */ + PCCPUMMSRRANGE paMsrRanges; +} CPUMDBENTRY; +/** Pointer to a const CPU database entry. */ +typedef CPUMDBENTRY const *PCCPUMDBENTRY; + +/** @name CPUMDB_F_XXX - CPUDBENTRY::fFlags + * @{ */ +/** Should execute all in IEM. + * @todo Implement this - currently done in Main... */ +#define CPUMDB_F_EXECUTE_ALL_IN_IEM RT_BIT_32(0) +/** @} */ + + + +#ifndef VBOX_FOR_DTRACE_LIB + +#if defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64) +VMMDECL(int) CPUMCpuIdCollectLeavesX86(PCPUMCPUIDLEAF *ppaLeaves, uint32_t *pcLeaves); +VMMDECL(CPUMCPUVENDOR) CPUMCpuIdDetectX86VendorEx(uint32_t uEAX, uint32_t uEBX, uint32_t uECX, uint32_t uEDX); +#endif + +VMM_INT_DECL(bool) CPUMAssertGuestRFlagsCookie(PVM pVM, PVMCPU pVCpu); + + +/** @name Guest Register Getters. + * @{ */ +VMMDECL(void) CPUMGetGuestGDTR(PCVMCPU pVCpu, PVBOXGDTR pGDTR); +VMMDECL(RTGCPTR) CPUMGetGuestIDTR(PCVMCPU pVCpu, uint16_t *pcbLimit); +VMMDECL(RTSEL) CPUMGetGuestTR(PCVMCPU pVCpu, PCPUMSELREGHID pHidden); +VMMDECL(RTSEL) CPUMGetGuestLDTR(PCVMCPU pVCpu); +VMMDECL(RTSEL) CPUMGetGuestLdtrEx(PCVMCPU pVCpu, uint64_t *pGCPtrBase, uint32_t *pcbLimit); +VMMDECL(uint64_t) CPUMGetGuestCR0(PCVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestCR2(PCVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestCR3(PCVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestCR4(PCVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestCR8(PCVMCPUCC pVCpu); +VMMDECL(int) CPUMGetGuestCRx(PCVMCPUCC pVCpu, unsigned iReg, uint64_t *pValue); +VMMDECL(uint32_t) CPUMGetGuestEFlags(PCVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestEIP(PCVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestRIP(PCVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestEAX(PCVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestEBX(PCVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestECX(PCVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestEDX(PCVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestESI(PCVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestEDI(PCVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestESP(PCVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestEBP(PCVMCPU pVCpu); +VMMDECL(RTSEL) CPUMGetGuestCS(PCVMCPU pVCpu); +VMMDECL(RTSEL) CPUMGetGuestDS(PCVMCPU pVCpu); +VMMDECL(RTSEL) CPUMGetGuestES(PCVMCPU pVCpu); +VMMDECL(RTSEL) CPUMGetGuestFS(PCVMCPU pVCpu); +VMMDECL(RTSEL) CPUMGetGuestGS(PCVMCPU pVCpu); +VMMDECL(RTSEL) CPUMGetGuestSS(PCVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestFlatPC(PVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestFlatSP(PVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestDR0(PCVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestDR1(PCVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestDR2(PCVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestDR3(PCVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestDR6(PCVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestDR7(PCVMCPU pVCpu); +VMMDECL(int) CPUMGetGuestDRx(PCVMCPU pVCpu, uint32_t iReg, uint64_t *pValue); +VMMDECL(void) CPUMGetGuestCpuId(PVMCPUCC pVCpu, uint32_t iLeaf, uint32_t iSubLeaf, int f64BitMode, + uint32_t *pEax, uint32_t *pEbx, uint32_t *pEcx, uint32_t *pEdx); +VMMDECL(uint64_t) CPUMGetGuestEFER(PCVMCPU pVCpu); +VMM_INT_DECL(uint64_t) CPUMGetGuestIa32FeatCtrl(PCVMCPUCC pVCpu); +VMM_INT_DECL(uint64_t) CPUMGetGuestIa32MtrrCap(PCVMCPU pVCpu); +VMM_INT_DECL(uint64_t) CPUMGetGuestIa32SmmMonitorCtl(PCVMCPUCC pVCpu); +VMM_INT_DECL(uint64_t) CPUMGetGuestIa32VmxEptVpidCap(PCVMCPUCC pVCpu); +VMMDECL(VBOXSTRICTRC) CPUMQueryGuestMsr(PVMCPUCC pVCpu, uint32_t idMsr, uint64_t *puValue); +VMMDECL(VBOXSTRICTRC) CPUMSetGuestMsr(PVMCPUCC pVCpu, uint32_t idMsr, uint64_t uValue); +VMMDECL(CPUMCPUVENDOR) CPUMGetGuestCpuVendor(PVM pVM); +VMMDECL(CPUMMICROARCH) CPUMGetGuestMicroarch(PCVM pVM); +VMMDECL(void) CPUMGetGuestAddrWidths(PCVM pVM, uint8_t *pcPhysAddrWidth, uint8_t *pcLinearAddrWidth); +VMMDECL(CPUMCPUVENDOR) CPUMGetHostCpuVendor(PVM pVM); +VMMDECL(CPUMMICROARCH) CPUMGetHostMicroarch(PCVM 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(PVMCPUCC 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(PVMCPUCC pVCpu, uint64_t uDr0); +VMMDECL(int) CPUMSetGuestDR1(PVMCPUCC pVCpu, uint64_t uDr1); +VMMDECL(int) CPUMSetGuestDR2(PVMCPUCC pVCpu, uint64_t uDr2); +VMMDECL(int) CPUMSetGuestDR3(PVMCPUCC pVCpu, uint64_t uDr3); +VMMDECL(int) CPUMSetGuestDR6(PVMCPU pVCpu, uint64_t uDr6); +VMMDECL(int) CPUMSetGuestDR7(PVMCPUCC pVCpu, uint64_t uDr7); +VMMDECL(int) CPUMSetGuestDRx(PVMCPUCC pVCpu, uint32_t iReg, uint64_t Value); +VMM_INT_DECL(int) CPUMSetGuestXcr0(PVMCPUCC pVCpu, uint64_t uNewValue); +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); +VMMR3_INT_DECL(void) CPUMR3SetGuestCpuIdFeature(PVM pVM, CPUMCPUIDFEATURE enmFeature); +VMMR3_INT_DECL(void) CPUMR3ClearGuestCpuIdFeature(PVM pVM, CPUMCPUIDFEATURE enmFeature); +VMMR3_INT_DECL(bool) CPUMR3GetGuestCpuIdFeature(PVM pVM, CPUMCPUIDFEATURE enmFeature); +VMMDECL(bool) CPUMSetGuestCpuIdPerCpuApicFeature(PVMCPU pVCpu, bool fVisible); +VMMDECL(void) CPUMSetGuestCtx(PVMCPU pVCpu, const PCPUMCTX pCtx); +VMM_INT_DECL(void) CPUMSetGuestTscAux(PVMCPUCC pVCpu, uint64_t uValue); +VMM_INT_DECL(uint64_t) CPUMGetGuestTscAux(PVMCPUCC pVCpu); +VMM_INT_DECL(void) CPUMSetGuestSpecCtrl(PVMCPUCC pVCpu, uint64_t uValue); +VMM_INT_DECL(uint64_t) CPUMGetGuestSpecCtrl(PVMCPUCC pVCpu); +VMM_INT_DECL(uint64_t) CPUMGetGuestCR4ValidMask(PVM pVM); +VMM_INT_DECL(void) CPUMSetGuestPaePdpes(PVMCPU pVCpu, PCX86PDPE paPaePdpes); +VMM_INT_DECL(void) CPUMGetGuestPaePdpes(PVMCPU pVCpu, PX86PDPE paPaePdpes); +/** @} */ + + +/** @name Misc Guest Predicate Functions. + * @{ */ +VMMDECL(bool) CPUMIsGuestIn64BitCode(PVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestNXEnabled(PCVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestPageSizeExtEnabled(PCVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestPagingEnabled(PCVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestR0WriteProtEnabled(PCVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestInRealMode(PCVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestInRealOrV86Mode(PCVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestInProtectedMode(PCVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestInPagedProtectedMode(PCVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestInLongMode(PCVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestInPAEMode(PCVMCPU pVCpu); +/** @} */ + +/** @name Nested Hardware-Virtualization Helpers. + * @{ */ +VMM_INT_DECL(bool) CPUMIsGuestPhysIntrEnabled(PVMCPU pVCpu); +VMM_INT_DECL(bool) CPUMIsGuestVirtIntrEnabled(PVMCPU pVCpu); +VMM_INT_DECL(uint64_t) CPUMApplyNestedGuestTscOffset(PCVMCPU pVCpu, uint64_t uTscValue); +VMM_INT_DECL(uint64_t) CPUMRemoveNestedGuestTscOffset(PCVMCPU pVCpu, uint64_t uTscValue); + +/* SVM helpers. */ +VMM_INT_DECL(bool) CPUMIsGuestSvmPhysIntrEnabled(PCVMCPU pVCpu, PCCPUMCTX pCtx); +VMM_INT_DECL(bool) CPUMIsGuestSvmVirtIntrEnabled(PCVMCPU pVCpu, PCCPUMCTX pCtx); +VMM_INT_DECL(uint8_t) CPUMGetGuestSvmVirtIntrVector(PCCPUMCTX pCtx); +VMM_INT_DECL(void) CPUMSvmVmExitRestoreHostState(PVMCPUCC pVCpu, PCPUMCTX pCtx); +VMM_INT_DECL(void) CPUMSvmVmRunSaveHostState(PCPUMCTX pCtx, uint8_t cbInstr); +VMM_INT_DECL(bool) CPUMIsSvmIoInterceptSet(void *pvIoBitmap, uint16_t u16Port, SVMIOIOTYPE enmIoType, uint8_t cbReg, + uint8_t cAddrSizeBits, uint8_t iEffSeg, bool fRep, bool fStrIo, + PSVMIOIOEXITINFO pIoExitInfo); +VMM_INT_DECL(int) CPUMGetSvmMsrpmOffsetAndBit(uint32_t idMsr, uint16_t *pbOffMsrpm, uint8_t *puMsrpmBit); + +/* VMX helpers. */ +VMM_INT_DECL(bool) CPUMIsGuestVmxVmcsFieldValid(PVMCC pVM, uint64_t u64VmcsField); +VMM_INT_DECL(bool) CPUMIsGuestVmxIoInterceptSet(PCVMCPU pVCpu, uint16_t u16Port, uint8_t cbAccess); +VMM_INT_DECL(bool) CPUMIsGuestVmxMovToCr3InterceptSet(PVMCPU pVCpu, uint64_t uNewCr3); +VMM_INT_DECL(bool) CPUMIsGuestVmxVmreadVmwriteInterceptSet(PCVMCPU pVCpu, uint32_t uExitReason, uint64_t u64FieldEnc); +VMM_INT_DECL(int) CPUMStartGuestVmxPremptTimer(PVMCPUCC pVCpu, uint32_t uTimer, uint8_t cShift, uint64_t *pu64EntryTick); +VMM_INT_DECL(int) CPUMStopGuestVmxPremptTimer(PVMCPUCC pVCpu); +VMM_INT_DECL(uint32_t) CPUMGetVmxMsrPermission(void const *pvMsrBitmap, uint32_t idMsr); +VMM_INT_DECL(bool) CPUMIsGuestVmxEptPagingEnabled(PCVMCPUCC pVCpu); +VMM_INT_DECL(bool) CPUMIsGuestVmxEptPaePagingEnabled(PCVMCPUCC pVCpu); +VMM_INT_DECL(uint64_t) CPUMGetGuestVmxApicAccessPageAddr(PCVMCPUCC pVCpu); +/** @} */ + +/** @name Externalized State Helpers. + * @{ */ +/** @def CPUM_ASSERT_NOT_EXTRN + * Macro for asserting that @a a_fNotExtrn are present. + * + * @param a_pVCpu The cross context virtual CPU structure of the calling EMT. + * @param a_fNotExtrn Mask of CPUMCTX_EXTRN_XXX bits to check. + * + * @remarks Requires VMCPU_INCL_CPUM_GST_CTX to be defined. + */ +#define CPUM_ASSERT_NOT_EXTRN(a_pVCpu, a_fNotExtrn) \ + AssertMsg(!((a_pVCpu)->cpum.GstCtx.fExtrn & (a_fNotExtrn)), \ + ("%#RX64; a_fNotExtrn=%#RX64\n", (a_pVCpu)->cpum.GstCtx.fExtrn, (a_fNotExtrn))) + +/** @def CPUMCTX_ASSERT_NOT_EXTRN + * Macro for asserting that @a a_fNotExtrn are present in @a a_pCtx. + * + * @param a_pCtx The CPU context of the calling EMT. + * @param a_fNotExtrn Mask of CPUMCTX_EXTRN_XXX bits to check. + */ +#define CPUMCTX_ASSERT_NOT_EXTRN(a_pCtx, a_fNotExtrn) \ + AssertMsg(!((a_pCtx)->fExtrn & (a_fNotExtrn)), \ + ("%#RX64; a_fNotExtrn=%#RX64\n", (a_pCtx)->fExtrn, (a_fNotExtrn))) + +/** @def CPUM_IMPORT_EXTRN_RET + * Macro for making sure the state specified by @a fExtrnImport is present, + * calling CPUMImportGuestStateOnDemand() to get it if necessary. + * + * Will return if CPUMImportGuestStateOnDemand() fails. + * + * @param a_pVCpu The cross context virtual CPU structure of the calling EMT. + * @param a_fExtrnImport Mask of CPUMCTX_EXTRN_XXX bits to get. + * @thread EMT(a_pVCpu) + * + * @remarks Requires VMCPU_INCL_CPUM_GST_CTX to be defined. + */ +#define CPUM_IMPORT_EXTRN_RET(a_pVCpu, a_fExtrnImport) \ + do { \ + if (!((a_pVCpu)->cpum.GstCtx.fExtrn & (a_fExtrnImport))) \ + { /* already present, consider this likely */ } \ + else \ + { \ + int rcCpumImport = CPUMImportGuestStateOnDemand(a_pVCpu, a_fExtrnImport); \ + AssertRCReturn(rcCpumImport, rcCpumImport); \ + } \ + } while (0) + +/** @def CPUM_IMPORT_EXTRN_RCSTRICT + * Macro for making sure the state specified by @a fExtrnImport is present, + * calling CPUMImportGuestStateOnDemand() to get it if necessary. + * + * Will update a_rcStrict if CPUMImportGuestStateOnDemand() fails. + * + * @param a_pVCpu The cross context virtual CPU structure of the calling EMT. + * @param a_fExtrnImport Mask of CPUMCTX_EXTRN_XXX bits to get. + * @param a_rcStrict Strict status code variable to update on failure. + * @thread EMT(a_pVCpu) + * + * @remarks Requires VMCPU_INCL_CPUM_GST_CTX to be defined. + */ +#define CPUM_IMPORT_EXTRN_RCSTRICT(a_pVCpu, a_fExtrnImport, a_rcStrict) \ + do { \ + if (!((a_pVCpu)->cpum.GstCtx.fExtrn & (a_fExtrnImport))) \ + { /* already present, consider this likely */ } \ + else \ + { \ + int rcCpumImport = CPUMImportGuestStateOnDemand(a_pVCpu, a_fExtrnImport); \ + AssertStmt(RT_SUCCESS(rcCpumImport) || RT_FAILURE_NP(a_rcStrict), a_rcStrict = rcCpumImport); \ + } \ + } while (0) + +VMM_INT_DECL(int) CPUMImportGuestStateOnDemand(PVMCPUCC pVCpu, uint64_t fExtrnImport); +/** @} */ + +#if !defined(IPRT_WITHOUT_NAMED_UNIONS_AND_STRUCTS) || defined(DOXYGEN_RUNNING) +/** @name Inlined Guest Getters and predicates Functions. + * @{ */ + +/** + * Gets valid CR0 bits for the guest. + * + * @returns Valid CR0 bits. + */ +DECLINLINE(uint64_t) CPUMGetGuestCR0ValidMask(void) +{ + return ( X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS + | X86_CR0_ET | X86_CR0_NE | X86_CR0_WP | X86_CR0_AM + | X86_CR0_NW | X86_CR0_CD | X86_CR0_PG); +} + +/** + * 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(PCCPUMCTX 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(PCCPUMCTX pCtx) +{ + return !(pCtx->cr0 & X86_CR0_PE) + || pCtx->eflags.Bits.u1VM; /* Cannot be set in long mode. Intel spec 2.3.1 "System Flags and Fields in IA-32e Mode". */ +} + +/** + * Tests if the guest is running in virtual 8086 mode. + * + * @returns @c true if it is, @c false if not. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestInV86ModeEx(PCCPUMCTX pCtx) +{ + return (pCtx->eflags.Bits.u1VM == 1); +} + +/** + * Tests if the guest is running in paged protected or not. + * + * @returns true if in paged protected mode, otherwise false. + * @param pCtx Current CPU context. + */ +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(PCCPUMCTX 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 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 has paging enabled or not. + * + * @returns true if paging is enabled, otherwise false. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestPagingEnabledEx(PCCPUMCTX pCtx) +{ + return !!(pCtx->cr0 & X86_CR0_PG); +} + +/** + * Tests if PAE paging is enabled given the relevant control registers. + * + * @returns @c true if in PAE mode, @c false otherwise. + * @param uCr0 The CR0 value. + * @param uCr4 The CR4 value. + * @param uEferMsr The EFER value. + */ +DECLINLINE(bool) CPUMIsPaePagingEnabled(uint64_t uCr0, uint64_t uCr4, uint64_t uEferMsr) +{ + /* Intel mentions EFER.LMA and EFER.LME in different parts of their spec. We shall use EFER.LMA rather + than EFER.LME as it reflects if the CPU has entered paging with EFER.LME set. */ + return ( (uCr4 & X86_CR4_PAE) + && (uCr0 & X86_CR0_PG) + && !(uEferMsr & MSR_K6_EFER_LMA)); +} + +/** + * Tests if the guest is running in PAE mode or not. + * + * @returns @c true if in PAE mode, @c false otherwise. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestInPAEModeEx(PCCPUMCTX pCtx) +{ + return CPUMIsPaePagingEnabled(pCtx->cr0, pCtx->cr4, pCtx->msrEFER); +} + +/** + * Tests if the guest has AMD SVM enabled or not. + * + * @returns true if SMV is enabled, otherwise false. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestSvmEnabled(PCCPUMCTX pCtx) +{ + return RT_BOOL(pCtx->msrEFER & MSR_K6_EFER_SVME); +} + +/** + * Tests if the guest has Intel VT-x enabled or not. + * + * @returns true if VMX is enabled, otherwise false. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestVmxEnabled(PCCPUMCTX pCtx) +{ + return RT_BOOL(pCtx->cr4 & X86_CR4_VMXE); +} + +/** + * Returns the guest's global-interrupt (GIF) flag. + * + * @returns true when global-interrupts are enabled, otherwise false. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMGetGuestGif(PCCPUMCTX pCtx) +{ + return pCtx->hwvirt.fGif; +} + +/** + * Sets the guest's global-interrupt flag (GIF). + * + * @param pCtx Current CPU context. + * @param fGif The value to set. + */ +DECLINLINE(void) CPUMSetGuestGif(PCPUMCTX pCtx, bool fGif) +{ + pCtx->hwvirt.fGif = fGif; +} + +/** + * Checks if we're in an "interrupt shadow", i.e. after a STI, POP SS or MOV SS. + * + * This also inhibit NMIs, except perhaps for nested guests. + * + * @returns true if interrupts are inhibited by interrupt shadow, false if not. + * @param pCtx Current guest CPU context. + * @note Requires pCtx->rip to be up to date. + * @note Does NOT clear CPUMCTX_INHIBIT_SHADOW when CPUMCTX::uRipInhibitInt + * differs from CPUMCTX::rip. + */ +DECLINLINE(bool) CPUMIsInInterruptShadow(PCCPUMCTX pCtx) +{ + if (!(pCtx->eflags.uBoth & CPUMCTX_INHIBIT_SHADOW)) + return false; + + CPUMCTX_ASSERT_NOT_EXTRN(pCtx, CPUMCTX_EXTRN_RIP); + return pCtx->uRipInhibitInt == pCtx->rip; +} + +/** + * Checks if we're in an "interrupt shadow", i.e. after a STI, POP SS or MOV SS, + * updating the state if stale. + * + * This also inhibit NMIs, except perhaps for nested guests. + * + * @retval true if interrupts are inhibited by interrupt shadow. + * @retval false if not. + * @param pCtx Current guest CPU context. + * @note Requires pCtx->rip to be up to date. + */ +DECLINLINE(bool) CPUMIsInInterruptShadowWithUpdate(PCPUMCTX pCtx) +{ + if (!(pCtx->eflags.uBoth & CPUMCTX_INHIBIT_SHADOW)) + return false; + + CPUMCTX_ASSERT_NOT_EXTRN(pCtx, CPUMCTX_EXTRN_RIP); + if (pCtx->uRipInhibitInt == pCtx->rip) + return true; + + pCtx->eflags.uBoth &= ~CPUMCTX_INHIBIT_SHADOW; + return false; +} + +/** + * Checks if we're in an "interrupt shadow" due to a POP SS or MOV SS + * instruction. + * + * This also inhibit NMIs, except perhaps for nested guests. + * + * @retval true if interrupts are inhibited due to POP/MOV SS. + * @retval false if not. + * @param pCtx Current guest CPU context. + * @note Requires pCtx->rip to be up to date. + * @note Does NOT clear CPUMCTX_INHIBIT_SHADOW when CPUMCTX::uRipInhibitInt + * differs from CPUMCTX::rip. + * @note Both CPUMIsInInterruptShadowAfterSti() and this function may return + * true depending on the execution engine being used. + */ +DECLINLINE(bool) CPUMIsInInterruptShadowAfterSs(PCCPUMCTX pCtx) +{ + if (!(pCtx->eflags.uBoth & CPUMCTX_INHIBIT_SHADOW_SS)) + return false; + + CPUMCTX_ASSERT_NOT_EXTRN(pCtx, CPUMCTX_EXTRN_RIP); + return pCtx->uRipInhibitInt == pCtx->rip; +} + +/** + * Checks if we're in an "interrupt shadow" due to an STI instruction. + * + * This also inhibit NMIs, except perhaps for nested guests. + * + * @retval true if interrupts are inhibited due to STI. + * @retval false if not. + * @param pCtx Current guest CPU context. + * @note Requires pCtx->rip to be up to date. + * @note Does NOT clear CPUMCTX_INHIBIT_SHADOW when CPUMCTX::uRipInhibitInt + * differs from CPUMCTX::rip. + * @note Both CPUMIsInInterruptShadowAfterSs() and this function may return + * true depending on the execution engine being used. + */ +DECLINLINE(bool) CPUMIsInInterruptShadowAfterSti(PCCPUMCTX pCtx) +{ + if (!(pCtx->eflags.uBoth & CPUMCTX_INHIBIT_SHADOW_STI)) + return false; + + CPUMCTX_ASSERT_NOT_EXTRN(pCtx, CPUMCTX_EXTRN_RIP); + return pCtx->uRipInhibitInt == pCtx->rip; +} + +/** + * Sets the "interrupt shadow" flag, after a STI, POP SS or MOV SS instruction. + * + * @param pCtx Current guest CPU context. + * @note Requires pCtx->rip to be up to date. + */ +DECLINLINE(void) CPUMSetInInterruptShadow(PCPUMCTX pCtx) +{ + CPUMCTX_ASSERT_NOT_EXTRN(pCtx, CPUMCTX_EXTRN_RIP); + pCtx->eflags.uBoth |= CPUMCTX_INHIBIT_SHADOW; + pCtx->uRipInhibitInt = pCtx->rip; +} + +/** + * Sets the "interrupt shadow" flag, after a STI, POP SS or MOV SS instruction, + * extended version. + * + * @param pCtx Current guest CPU context. + * @param rip The RIP for which it is inhibited. + */ +DECLINLINE(void) CPUMSetInInterruptShadowEx(PCPUMCTX pCtx, uint64_t rip) +{ + pCtx->eflags.uBoth |= CPUMCTX_INHIBIT_SHADOW; + pCtx->uRipInhibitInt = rip; +} + +/** + * Sets the "interrupt shadow" flag after a POP SS or MOV SS instruction. + * + * @param pCtx Current guest CPU context. + * @note Requires pCtx->rip to be up to date. + */ +DECLINLINE(void) CPUMSetInInterruptShadowSs(PCPUMCTX pCtx) +{ + CPUMCTX_ASSERT_NOT_EXTRN(pCtx, CPUMCTX_EXTRN_RIP); + pCtx->eflags.uBoth |= CPUMCTX_INHIBIT_SHADOW_SS; + pCtx->uRipInhibitInt = pCtx->rip; +} + +/** + * Sets the "interrupt shadow" flag after an STI instruction. + * + * @param pCtx Current guest CPU context. + * @note Requires pCtx->rip to be up to date. + */ +DECLINLINE(void) CPUMSetInInterruptShadowSti(PCPUMCTX pCtx) +{ + CPUMCTX_ASSERT_NOT_EXTRN(pCtx, CPUMCTX_EXTRN_RIP); + pCtx->eflags.uBoth |= CPUMCTX_INHIBIT_SHADOW_STI; + pCtx->uRipInhibitInt = pCtx->rip; +} + +/** + * Clears the "interrupt shadow" flag. + * + * @param pCtx Current guest CPU context. + */ +DECLINLINE(void) CPUMClearInterruptShadow(PCPUMCTX pCtx) +{ + pCtx->eflags.uBoth &= ~CPUMCTX_INHIBIT_SHADOW; +} + +/** + * Update the "interrupt shadow" flag. + * + * @param pCtx Current guest CPU context. + * @param fInhibited The new state. + * @note Requires pCtx->rip to be up to date. + */ +DECLINLINE(void) CPUMUpdateInterruptShadow(PCPUMCTX pCtx, bool fInhibited) +{ + CPUMCTX_ASSERT_NOT_EXTRN(pCtx, CPUMCTX_EXTRN_RIP); + if (!fInhibited) + pCtx->eflags.uBoth &= ~CPUMCTX_INHIBIT_SHADOW; + else + { + pCtx->eflags.uBoth |= CPUMCTX_INHIBIT_SHADOW; + pCtx->uRipInhibitInt = pCtx->rip; + } +} + +/** + * Update the "interrupt shadow" flag, extended version. + * + * @returns fInhibited. + * @param pCtx Current guest CPU context. + * @param fInhibited The new state. + * @param rip The RIP for which it is inhibited. + */ +DECLINLINE(bool) CPUMUpdateInterruptShadowEx(PCPUMCTX pCtx, bool fInhibited, uint64_t rip) +{ + if (!fInhibited) + pCtx->eflags.uBoth &= ~CPUMCTX_INHIBIT_SHADOW; + else + { + pCtx->eflags.uBoth |= CPUMCTX_INHIBIT_SHADOW; + pCtx->uRipInhibitInt = rip; + } + return fInhibited; +} + +/** + * Update the two "interrupt shadow" flags separately, extended version. + * + * @param pCtx Current guest CPU context. + * @param fInhibitedBySs The new state for the MOV SS & POP SS aspect. + * @param fInhibitedBySti The new state for the STI aspect. + * @param rip The RIP for which it is inhibited. + */ +DECLINLINE(void) CPUMUpdateInterruptShadowSsStiEx(PCPUMCTX pCtx, bool fInhibitedBySs, bool fInhibitedBySti, uint64_t rip) +{ + if (!(fInhibitedBySs | fInhibitedBySti)) + pCtx->eflags.uBoth &= ~CPUMCTX_INHIBIT_SHADOW; + else + { + pCtx->eflags.uBoth |= (fInhibitedBySs ? CPUMCTX_INHIBIT_SHADOW_SS : UINT32_C(0)) + | (fInhibitedBySti ? CPUMCTX_INHIBIT_SHADOW_STI : UINT32_C(0)); + pCtx->uRipInhibitInt = rip; + } +} + +/* VMX forward declarations used by extended function versions: */ +DECLINLINE(bool) CPUMIsGuestInVmxNonRootMode(PCCPUMCTX pCtx); +DECLINLINE(bool) CPUMIsGuestVmxPinCtlsSet(PCCPUMCTX pCtx, uint32_t uPinCtls); +DECLINLINE(bool) CPUMIsGuestVmxVirtNmiBlocking(PCCPUMCTX pCtx); +DECLINLINE(void) CPUMSetGuestVmxVirtNmiBlocking(PCPUMCTX pCtx, bool fBlocking); + +/** + * Checks whether interrupts, include NMIs, are inhibited by pending NMI + * delivery. + * + * This only checks the inhibit mask. + * + * @retval true if interrupts are inhibited by NMI handling. + * @retval false if interrupts are not inhibited by NMI handling. + * @param pCtx Current guest CPU context. + */ +DECLINLINE(bool) CPUMAreInterruptsInhibitedByNmi(PCCPUMCTX pCtx) +{ + return (pCtx->eflags.uBoth & CPUMCTX_INHIBIT_NMI) != 0; +} + +/** + * Extended version of CPUMAreInterruptsInhibitedByNmi() that takes VMX non-root + * mode into account when check whether interrupts are inhibited by NMI. + * + * @retval true if interrupts are inhibited by NMI handling. + * @retval false if interrupts are not inhibited by NMI handling. + * @param pCtx Current guest CPU context. + */ +DECLINLINE(bool) CPUMAreInterruptsInhibitedByNmiEx(PCCPUMCTX pCtx) +{ + /* See CPUMUpdateInterruptInhibitingByNmiEx for comments. */ + if ( !CPUMIsGuestInVmxNonRootMode(pCtx) + || !CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_VIRT_NMI)) + return CPUMAreInterruptsInhibitedByNmi(pCtx); + return CPUMIsGuestVmxVirtNmiBlocking(pCtx); +} + +/** + * Marks interrupts, include NMIs, as inhibited by pending NMI delivery. + * + * @param pCtx Current guest CPU context. + */ +DECLINLINE(void) CPUMSetInterruptInhibitingByNmi(PCPUMCTX pCtx) +{ + pCtx->eflags.uBoth |= CPUMCTX_INHIBIT_NMI; +} + +/** + * Extended version of CPUMSetInterruptInhibitingByNmi() that takes VMX non-root + * mode into account when marking interrupts as inhibited by NMI. + * + * @param pCtx Current guest CPU context. + */ +DECLINLINE(void) CPUMSetInterruptInhibitingByNmiEx(PCPUMCTX pCtx) +{ + /* See CPUMUpdateInterruptInhibitingByNmiEx for comments. */ + if ( !CPUMIsGuestInVmxNonRootMode(pCtx) + || !CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_VIRT_NMI)) + CPUMSetInterruptInhibitingByNmi(pCtx); + else + CPUMSetGuestVmxVirtNmiBlocking(pCtx, true); +} + +/** + * Marks interrupts, include NMIs, as no longer inhibited by pending NMI + * delivery. + * + * @param pCtx Current guest CPU context. + */ +DECLINLINE(void) CPUMClearInterruptInhibitingByNmi(PCPUMCTX pCtx) +{ + pCtx->eflags.uBoth &= ~CPUMCTX_INHIBIT_NMI; +} + +/** + * Extended version of CPUMClearInterruptInhibitingByNmi() that takes VMX + * non-root mode into account when doing the updating. + * + * @param pCtx Current guest CPU context. + */ +DECLINLINE(void) CPUMClearInterruptInhibitingByNmiEx(PCPUMCTX pCtx) +{ + /* See CPUMUpdateInterruptInhibitingByNmiEx for comments. */ + if ( !CPUMIsGuestInVmxNonRootMode(pCtx) + || !CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_VIRT_NMI)) + CPUMClearInterruptInhibitingByNmi(pCtx); + else + CPUMSetGuestVmxVirtNmiBlocking(pCtx, false); +} + +/** + * Update whether interrupts, include NMIs, are inhibited by pending NMI + * delivery. + * + * @param pCtx Current guest CPU context. + * @param fInhibited The new state. + */ +DECLINLINE(void) CPUMUpdateInterruptInhibitingByNmi(PCPUMCTX pCtx, bool fInhibited) +{ + if (!fInhibited) + pCtx->eflags.uBoth &= ~CPUMCTX_INHIBIT_NMI; + else + pCtx->eflags.uBoth |= CPUMCTX_INHIBIT_NMI; +} + +/** + * Extended version of CPUMUpdateInterruptInhibitingByNmi() that takes VMX + * non-root mode into account when doing the updating. + * + * @param pCtx Current guest CPU context. + * @param fInhibited The new state. + */ +DECLINLINE(void) CPUMUpdateInterruptInhibitingByNmiEx(PCPUMCTX pCtx, bool fInhibited) +{ + /* + * Set the state of guest-NMI blocking in any of the following cases: + * - We're not executing a nested-guest. + * - We're executing an SVM nested-guest[1]. + * - We're executing a VMX nested-guest without virtual-NMIs enabled. + * + * [1] -- SVM does not support virtual-NMIs or virtual-NMI blocking. + * SVM hypervisors must track NMI blocking themselves by intercepting + * the IRET instruction after injection of an NMI. + */ + if ( !CPUMIsGuestInVmxNonRootMode(pCtx) + || !CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_VIRT_NMI)) + CPUMUpdateInterruptInhibitingByNmi(pCtx, fInhibited); + /* + * Set the state of virtual-NMI blocking, if we are executing a + * VMX nested-guest with virtual-NMIs enabled. + */ + else + CPUMSetGuestVmxVirtNmiBlocking(pCtx, fInhibited); +} + + +/** + * Checks if we are executing inside an SVM nested hardware-virtualized guest. + * + * @returns @c true if in SVM nested-guest mode, @c false otherwise. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestInSvmNestedHwVirtMode(PCCPUMCTX pCtx) +{ + /* + * With AMD-V, the VMRUN intercept is a pre-requisite to entering SVM guest-mode. + * See AMD spec. 15.5 "VMRUN instruction" subsection "Canonicalization and Consistency Checks". + */ +#ifndef IN_RC + if ( pCtx->hwvirt.enmHwvirt != CPUMHWVIRT_SVM + || !(pCtx->hwvirt.svm.Vmcb.ctrl.u64InterceptCtrl & SVM_CTRL_INTERCEPT_VMRUN)) + return false; + return true; +#else + NOREF(pCtx); + return false; +#endif +} + +/** + * Checks if the guest is in VMX non-root operation. + * + * @returns @c true if in VMX non-root operation, @c false otherwise. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestInVmxNonRootMode(PCCPUMCTX pCtx) +{ +#ifndef IN_RC + if (pCtx->hwvirt.enmHwvirt != CPUMHWVIRT_VMX) + return false; + Assert(!pCtx->hwvirt.vmx.fInVmxNonRootMode || pCtx->hwvirt.vmx.fInVmxRootMode); + return pCtx->hwvirt.vmx.fInVmxNonRootMode; +#else + NOREF(pCtx); + return false; +#endif +} + +/** + * Checks if we are executing inside an SVM or VMX nested hardware-virtualized + * guest. + * + * @returns @c true if in nested-guest mode, @c false otherwise. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestInNestedHwvirtMode(PCCPUMCTX pCtx) +{ +#if 0 + return CPUMIsGuestInVmxNonRootMode(pCtx) || CPUMIsGuestInSvmNestedHwVirtMode(pCtx); +#else + if (pCtx->hwvirt.enmHwvirt == CPUMHWVIRT_NONE) + return false; + if (pCtx->hwvirt.enmHwvirt == CPUMHWVIRT_VMX) + { + Assert(!pCtx->hwvirt.vmx.fInVmxNonRootMode || pCtx->hwvirt.vmx.fInVmxRootMode); + return pCtx->hwvirt.vmx.fInVmxNonRootMode; + } + Assert(pCtx->hwvirt.enmHwvirt == CPUMHWVIRT_SVM); + return RT_BOOL(pCtx->hwvirt.svm.Vmcb.ctrl.u64InterceptCtrl & SVM_CTRL_INTERCEPT_VMRUN); +#endif +} + +/** + * Checks if we are executing inside an SVM or VMX nested hardware-virtualized + * guest. + * + * @retval CPUMHWVIRT_NONE if not in SVM or VMX non-root mode. + * @retval CPUMHWVIRT_VMX if in VMX non-root mode. + * @retval CPUMHWVIRT_SVM if in SVM non-root mode. + * @param pCtx Current CPU context. + */ +DECLINLINE(CPUMHWVIRT) CPUMGetGuestInNestedHwvirtMode(PCCPUMCTX pCtx) +{ + if (pCtx->hwvirt.enmHwvirt == CPUMHWVIRT_NONE) + return CPUMHWVIRT_NONE; + if (pCtx->hwvirt.enmHwvirt == CPUMHWVIRT_VMX) + { + Assert(!pCtx->hwvirt.vmx.fInVmxNonRootMode || pCtx->hwvirt.vmx.fInVmxRootMode); + return pCtx->hwvirt.vmx.fInVmxNonRootMode ? CPUMHWVIRT_VMX : CPUMHWVIRT_NONE; + } + Assert(pCtx->hwvirt.enmHwvirt == CPUMHWVIRT_SVM); + return pCtx->hwvirt.svm.Vmcb.ctrl.u64InterceptCtrl & SVM_CTRL_INTERCEPT_VMRUN ? CPUMHWVIRT_SVM : CPUMHWVIRT_NONE; +} + +/** + * Checks if the guest is in VMX root operation. + * + * @returns @c true if in VMX root operation, @c false otherwise. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestInVmxRootMode(PCCPUMCTX pCtx) +{ +#ifndef IN_RC + if (pCtx->hwvirt.enmHwvirt != CPUMHWVIRT_VMX) + return false; + return pCtx->hwvirt.vmx.fInVmxRootMode; +#else + NOREF(pCtx); + return false; +#endif +} + +# ifndef IN_RC + +/** + * Checks if the nested-guest VMCB has the specified ctrl/instruction intercept + * active. + * + * @returns @c true if in intercept is set, @c false otherwise. + * @param pVCpu The cross context virtual CPU structure of the calling EMT. + * @param pCtx Current CPU context. + * @param fIntercept The SVM control/instruction intercept, see + * SVM_CTRL_INTERCEPT_*. + */ +DECLINLINE(bool) CPUMIsGuestSvmCtrlInterceptSet(PCVMCPU pVCpu, PCCPUMCTX pCtx, uint64_t fIntercept) +{ + if (pCtx->hwvirt.enmHwvirt != CPUMHWVIRT_SVM) + return false; + uint64_t u64Intercepts; + if (!HMGetGuestSvmCtrlIntercepts(pVCpu, &u64Intercepts)) + u64Intercepts = pCtx->hwvirt.svm.Vmcb.ctrl.u64InterceptCtrl; + return RT_BOOL(u64Intercepts & fIntercept); +} + +/** + * Checks if the nested-guest VMCB has the specified CR read intercept active. + * + * @returns @c true if in intercept is set, @c false otherwise. + * @param pVCpu The cross context virtual CPU structure of the calling EMT. + * @param pCtx Current CPU context. + * @param uCr The CR register number (0 to 15). + */ +DECLINLINE(bool) CPUMIsGuestSvmReadCRxInterceptSet(PCVMCPU pVCpu, PCCPUMCTX pCtx, uint8_t uCr) +{ + Assert(uCr < 16); + if (pCtx->hwvirt.enmHwvirt != CPUMHWVIRT_SVM) + return false; + uint16_t u16Intercepts; + if (!HMGetGuestSvmReadCRxIntercepts(pVCpu, &u16Intercepts)) + u16Intercepts = pCtx->hwvirt.svm.Vmcb.ctrl.u16InterceptRdCRx; + return RT_BOOL(u16Intercepts & (UINT16_C(1) << uCr)); +} + +/** + * Checks if the nested-guest VMCB has the specified CR write intercept active. + * + * @returns @c true if in intercept is set, @c false otherwise. + * @param pVCpu The cross context virtual CPU structure of the calling EMT. + * @param pCtx Current CPU context. + * @param uCr The CR register number (0 to 15). + */ +DECLINLINE(bool) CPUMIsGuestSvmWriteCRxInterceptSet(PCVMCPU pVCpu, PCCPUMCTX pCtx, uint8_t uCr) +{ + Assert(uCr < 16); + if (pCtx->hwvirt.enmHwvirt != CPUMHWVIRT_SVM) + return false; + uint16_t u16Intercepts; + if (!HMGetGuestSvmWriteCRxIntercepts(pVCpu, &u16Intercepts)) + u16Intercepts = pCtx->hwvirt.svm.Vmcb.ctrl.u16InterceptWrCRx; + return RT_BOOL(u16Intercepts & (UINT16_C(1) << uCr)); +} + +/** + * Checks if the nested-guest VMCB has the specified DR read intercept active. + * + * @returns @c true if in intercept is set, @c false otherwise. + * @param pVCpu The cross context virtual CPU structure of the calling EMT. + * @param pCtx Current CPU context. + * @param uDr The DR register number (0 to 15). + */ +DECLINLINE(bool) CPUMIsGuestSvmReadDRxInterceptSet(PCVMCPU pVCpu, PCCPUMCTX pCtx, uint8_t uDr) +{ + Assert(uDr < 16); + if (pCtx->hwvirt.enmHwvirt != CPUMHWVIRT_SVM) + return false; + uint16_t u16Intercepts; + if (!HMGetGuestSvmReadDRxIntercepts(pVCpu, &u16Intercepts)) + u16Intercepts = pCtx->hwvirt.svm.Vmcb.ctrl.u16InterceptRdDRx; + return RT_BOOL(u16Intercepts & (UINT16_C(1) << uDr)); +} + +/** + * Checks if the nested-guest VMCB has the specified DR write intercept active. + * + * @returns @c true if in intercept is set, @c false otherwise. + * @param pVCpu The cross context virtual CPU structure of the calling EMT. + * @param pCtx Current CPU context. + * @param uDr The DR register number (0 to 15). + */ +DECLINLINE(bool) CPUMIsGuestSvmWriteDRxInterceptSet(PCVMCPU pVCpu, PCCPUMCTX pCtx, uint8_t uDr) +{ + Assert(uDr < 16); + if (pCtx->hwvirt.enmHwvirt != CPUMHWVIRT_SVM) + return false; + uint16_t u16Intercepts; + if (!HMGetGuestSvmWriteDRxIntercepts(pVCpu, &u16Intercepts)) + u16Intercepts = pCtx->hwvirt.svm.Vmcb.ctrl.u16InterceptWrDRx; + return RT_BOOL(u16Intercepts & (UINT16_C(1) << uDr)); +} + +/** + * Checks if the nested-guest VMCB has the specified exception intercept active. + * + * @returns @c true if in intercept is active, @c false otherwise. + * @param pVCpu The cross context virtual CPU structure of the calling EMT. + * @param pCtx Current CPU context. + * @param uVector The exception / interrupt vector. + */ +DECLINLINE(bool) CPUMIsGuestSvmXcptInterceptSet(PCVMCPU pVCpu, PCCPUMCTX pCtx, uint8_t uVector) +{ + Assert(uVector <= X86_XCPT_LAST); + if (pCtx->hwvirt.enmHwvirt != CPUMHWVIRT_SVM) + return false; + uint32_t u32Intercepts; + if (!HMGetGuestSvmXcptIntercepts(pVCpu, &u32Intercepts)) + u32Intercepts = pCtx->hwvirt.svm.Vmcb.ctrl.u32InterceptXcpt; + return RT_BOOL(u32Intercepts & RT_BIT(uVector)); +} + +/** + * Checks if the nested-guest VMCB has virtual-interrupt masking enabled. + * + * @returns @c true if virtual-interrupts are masked, @c false otherwise. + * @param pVCpu The cross context virtual CPU structure of the calling EMT. + * @param pCtx Current CPU context. + * + * @remarks Should only be called when SVM feature is exposed to the guest. + */ +DECLINLINE(bool) CPUMIsGuestSvmVirtIntrMasking(PCVMCPU pVCpu, PCCPUMCTX pCtx) +{ + if (pCtx->hwvirt.enmHwvirt != CPUMHWVIRT_SVM) + return false; + bool fVIntrMasking; + if (!HMGetGuestSvmVirtIntrMasking(pVCpu, &fVIntrMasking)) + fVIntrMasking = pCtx->hwvirt.svm.Vmcb.ctrl.IntCtrl.n.u1VIntrMasking; + return fVIntrMasking; +} + +/** + * Checks if the nested-guest VMCB has nested-paging enabled. + * + * @returns @c true if nested-paging is enabled, @c false otherwise. + * @param pVCpu The cross context virtual CPU structure of the calling EMT. + * @param pCtx Current CPU context. + * + * @remarks Should only be called when SVM feature is exposed to the guest. + */ +DECLINLINE(bool) CPUMIsGuestSvmNestedPagingEnabled(PCVMCPU pVCpu, PCCPUMCTX pCtx) +{ + if (pCtx->hwvirt.enmHwvirt != CPUMHWVIRT_SVM) + return false; + bool fNestedPaging; + if (!HMGetGuestSvmNestedPaging(pVCpu, &fNestedPaging)) + fNestedPaging = pCtx->hwvirt.svm.Vmcb.ctrl.NestedPagingCtrl.n.u1NestedPaging; + return fNestedPaging; +} + +/** + * Gets the nested-guest VMCB pause-filter count. + * + * @returns The pause-filter count. + * @param pVCpu The cross context virtual CPU structure of the calling EMT. + * @param pCtx Current CPU context. + * + * @remarks Should only be called when SVM feature is exposed to the guest. + */ +DECLINLINE(uint16_t) CPUMGetGuestSvmPauseFilterCount(PCVMCPU pVCpu, PCCPUMCTX pCtx) +{ + if (pCtx->hwvirt.enmHwvirt != CPUMHWVIRT_SVM) + return false; + uint16_t u16PauseFilterCount; + if (!HMGetGuestSvmPauseFilterCount(pVCpu, &u16PauseFilterCount)) + u16PauseFilterCount = pCtx->hwvirt.svm.Vmcb.ctrl.u16PauseFilterCount; + return u16PauseFilterCount; +} + +/** + * Updates the NextRIP (NRIP) field in the nested-guest VMCB. + * + * @param pVCpu The cross context virtual CPU structure of the calling EMT. + * @param pCtx Current CPU context. + * @param cbInstr The length of the current instruction in bytes. + * + * @remarks Should only be called when SVM feature is exposed to the guest. + */ +DECLINLINE(void) CPUMGuestSvmUpdateNRip(PVMCPU pVCpu, PCPUMCTX pCtx, uint8_t cbInstr) +{ + RT_NOREF(pVCpu); + Assert(pCtx->hwvirt.enmHwvirt == CPUMHWVIRT_SVM); + pCtx->hwvirt.svm.Vmcb.ctrl.u64NextRIP = pCtx->rip + cbInstr; +} + +/** + * Checks whether one of the given Pin-based VM-execution controls are set when + * executing a nested-guest. + * + * @returns @c true if set, @c false otherwise. + * @param pCtx Current CPU context. + * @param uPinCtls The Pin-based VM-execution controls to check. + * + * @remarks This does not check if all given controls are set if more than one + * control is passed in @a uPinCtl. + */ +DECLINLINE(bool) CPUMIsGuestVmxPinCtlsSet(PCCPUMCTX pCtx, uint32_t uPinCtls) +{ + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + return RT_BOOL(pCtx->hwvirt.vmx.Vmcs.u32PinCtls & uPinCtls); +} + +/** + * Checks whether one of the given Processor-based VM-execution controls are set + * when executing a nested-guest. + * + * @returns @c true if set, @c false otherwise. + * @param pCtx Current CPU context. + * @param uProcCtls The Processor-based VM-execution controls to check. + * + * @remarks This does not check if all given controls are set if more than one + * control is passed in @a uProcCtls. + */ +DECLINLINE(bool) CPUMIsGuestVmxProcCtlsSet(PCCPUMCTX pCtx, uint32_t uProcCtls) +{ + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + return RT_BOOL(pCtx->hwvirt.vmx.Vmcs.u32ProcCtls & uProcCtls); +} + +/** + * Checks whether one of the given Secondary Processor-based VM-execution controls + * are set when executing a nested-guest. + * + * @returns @c true if set, @c false otherwise. + * @param pCtx Current CPU context. + * @param uProcCtls2 The Secondary Processor-based VM-execution controls to + * check. + * + * @remarks This does not check if all given controls are set if more than one + * control is passed in @a uProcCtls2. + */ +DECLINLINE(bool) CPUMIsGuestVmxProcCtls2Set(PCCPUMCTX pCtx, uint32_t uProcCtls2) +{ + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + return RT_BOOL(pCtx->hwvirt.vmx.Vmcs.u32ProcCtls2 & uProcCtls2); +} + +/** + * Checks whether one of the given Tertiary Processor-based VM-execution controls + * are set when executing a nested-guest. + * + * @returns @c true if set, @c false otherwise. + * @param pCtx Current CPU context. + * @param uProcCtls3 The Tertiary Processor-based VM-execution controls to + * check. + * + * @remarks This does not check if all given controls are set if more than one + * control is passed in @a uProcCtls3. + */ +DECLINLINE(bool) CPUMIsGuestVmxProcCtls3Set(PCCPUMCTX pCtx, uint64_t uProcCtls3) +{ + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + return RT_BOOL(pCtx->hwvirt.vmx.Vmcs.u64ProcCtls3.u & uProcCtls3); +} + +/** + * Checks whether one of the given VM-exit controls are set when executing a + * nested-guest. + * + * @returns @c true if set, @c false otherwise. + * @param pCtx Current CPU context. + * @param uExitCtls The VM-exit controls to check. + * + * @remarks This does not check if all given controls are set if more than one + * control is passed in @a uExitCtls. + */ +DECLINLINE(bool) CPUMIsGuestVmxExitCtlsSet(PCCPUMCTX pCtx, uint32_t uExitCtls) +{ + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + return RT_BOOL(pCtx->hwvirt.vmx.Vmcs.u32ExitCtls & uExitCtls); +} + +/** + * Checks whether one of the given VM-entry controls are set when executing a + * nested-guest. + * + * @returns @c true if set, @c false otherwise. + * @param pCtx Current CPU context. + * @param uEntryCtls The VM-entry controls to check. + * + * @remarks This does not check if all given controls are set if more than one + * control is passed in @a uEntryCtls. + */ +DECLINLINE(bool) CPUMIsGuestVmxEntryCtlsSet(PCCPUMCTX pCtx, uint32_t uEntryCtls) +{ + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + return RT_BOOL(pCtx->hwvirt.vmx.Vmcs.u32EntryCtls & uEntryCtls); +} + +/** + * Checks whether events injected in the nested-guest are subject to VM-exit checks. + * + * @returns @c true if set, @c false otherwise. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestVmxInterceptEvents(PCCPUMCTX pCtx) +{ + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + return pCtx->hwvirt.vmx.fInterceptEvents; +} + +/** + * Sets whether events injected in the nested-guest are subject to VM-exit checks. + * + * @param pCtx Current CPU context. + * @param fIntercept Whether to subject injected events to VM-exits or not. + */ +DECLINLINE(void) CPUMSetGuestVmxInterceptEvents(PCPUMCTX pCtx, bool fInterceptEvents) +{ + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + pCtx->hwvirt.vmx.fInterceptEvents = fInterceptEvents; +} + +/** + * Checks whether the given exception causes a VM-exit. + * + * The exception type include hardware exceptions, software exceptions (#BP, #OF) + * and privileged software exceptions (#DB generated by INT1/ICEBP). + * + * Software interrupts do -not- cause VM-exits and hence must not be used with this + * function. + * + * @returns @c true if the exception causes a VM-exit, @c false otherwise. + * @param pCtx Current CPU context. + * @param uVector The exception vector. + * @param uErrCode The error code associated with the exception. Pass 0 if not + * applicable. + */ +DECLINLINE(bool) CPUMIsGuestVmxXcptInterceptSet(PCCPUMCTX pCtx, uint8_t uVector, uint32_t uErrCode) +{ + Assert(uVector <= X86_XCPT_LAST); + + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + + /* NMIs have a dedicated VM-execution control for causing VM-exits. */ + if (uVector == X86_XCPT_NMI) + return RT_BOOL(pCtx->hwvirt.vmx.Vmcs.u32PinCtls & VMX_PIN_CTLS_NMI_EXIT); + + /* Page-faults are subject to masking using its error code. */ + uint32_t fXcptBitmap = pCtx->hwvirt.vmx.Vmcs.u32XcptBitmap; + if (uVector == X86_XCPT_PF) + { + uint32_t const fXcptPFMask = pCtx->hwvirt.vmx.Vmcs.u32XcptPFMask; + uint32_t const fXcptPFMatch = pCtx->hwvirt.vmx.Vmcs.u32XcptPFMatch; + if ((uErrCode & fXcptPFMask) != fXcptPFMatch) + fXcptBitmap ^= RT_BIT(X86_XCPT_PF); + } + + /* Consult the exception bitmap for all other exceptions. */ + if (fXcptBitmap & RT_BIT(uVector)) + return true; + return false; +} + + +/** + * Checks whether the guest is in VMX non-root mode and using EPT paging. + * + * @returns @c true if in VMX non-root operation with EPT, @c false otherwise. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestVmxEptPagingEnabledEx(PCCPUMCTX pCtx) +{ + return CPUMIsGuestInVmxNonRootMode(pCtx) + && CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_EPT); +} + + +/** + * Implements VMSucceed for VMX instruction success. + * + * @param pCtx Current CPU context. + */ +DECLINLINE(void) CPUMSetGuestVmxVmSucceed(PCPUMCTX pCtx) +{ + pCtx->eflags.uBoth &= ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF); +} + +/** + * Implements VMFailInvalid for VMX instruction failure. + * + * @param pCtx Current CPU context. + */ +DECLINLINE(void) CPUMSetGuestVmxVmFailInvalid(PCPUMCTX pCtx) +{ + pCtx->eflags.uBoth &= ~(X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF); + pCtx->eflags.uBoth |= X86_EFL_CF; +} + +/** + * Implements VMFailValid for VMX instruction failure. + * + * @param pCtx Current CPU context. + * @param enmInsErr The VM instruction error. + */ +DECLINLINE(void) CPUMSetGuestVmxVmFailValid(PCPUMCTX pCtx, VMXINSTRERR enmInsErr) +{ + pCtx->eflags.uBoth &= ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF); + pCtx->eflags.uBoth |= X86_EFL_ZF; + pCtx->hwvirt.vmx.Vmcs.u32RoVmInstrError = enmInsErr; +} + +/** + * Implements VMFail for VMX instruction failure. + * + * @param pCtx Current CPU context. + * @param enmInsErr The VM instruction error. + */ +DECLINLINE(void) CPUMSetGuestVmxVmFail(PCPUMCTX pCtx, VMXINSTRERR enmInsErr) +{ + if (pCtx->hwvirt.vmx.GCPhysVmcs != NIL_RTGCPHYS) + CPUMSetGuestVmxVmFailValid(pCtx, enmInsErr); + else + CPUMSetGuestVmxVmFailInvalid(pCtx); +} + +/** + * Returns the guest-physical address of the APIC-access page when executing a + * nested-guest. + * + * @returns The APIC-access page guest-physical address. + * @param pCtx Current CPU context. + */ +DECLINLINE(uint64_t) CPUMGetGuestVmxApicAccessPageAddrEx(PCCPUMCTX pCtx) +{ + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + return pCtx->hwvirt.vmx.Vmcs.u64AddrApicAccess.u; +} + +/** + * Gets the nested-guest CR0 subject to the guest/host mask and the read-shadow. + * + * @returns The nested-guest CR0. + * @param pCtx Current CPU context. + * @param fGstHostMask The CR0 guest/host mask to use. + */ +DECLINLINE(uint64_t) CPUMGetGuestVmxMaskedCr0(PCCPUMCTX pCtx, uint64_t fGstHostMask) +{ + /* + * For each CR0 bit owned by the host, the corresponding bit from the + * CR0 read shadow is loaded. For each CR0 bit that is not owned by the host, + * the corresponding bit from the guest CR0 is loaded. + * + * See Intel Spec. 25.3 "Changes To Instruction Behavior In VMX Non-root Operation". + */ + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + uint64_t const uGstCr0 = pCtx->cr0; + uint64_t const fReadShadow = pCtx->hwvirt.vmx.Vmcs.u64Cr0ReadShadow.u; + return (fReadShadow & fGstHostMask) | (uGstCr0 & ~fGstHostMask); +} + +/** + * Gets the nested-guest CR4 subject to the guest/host mask and the read-shadow. + * + * @returns The nested-guest CR4. + * @param pCtx Current CPU context. + * @param fGstHostMask The CR4 guest/host mask to use. + */ +DECLINLINE(uint64_t) CPUMGetGuestVmxMaskedCr4(PCCPUMCTX pCtx, uint64_t fGstHostMask) +{ + /* + * For each CR4 bit owned by the host, the corresponding bit from the + * CR4 read shadow is loaded. For each CR4 bit that is not owned by the host, + * the corresponding bit from the guest CR4 is loaded. + * + * See Intel Spec. 25.3 "Changes To Instruction Behavior In VMX Non-root Operation". + */ + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + uint64_t const uGstCr4 = pCtx->cr4; + uint64_t const fReadShadow = pCtx->hwvirt.vmx.Vmcs.u64Cr4ReadShadow.u; + return (fReadShadow & fGstHostMask) | (uGstCr4 & ~fGstHostMask); +} + +/** + * Checks whether the LMSW access causes a VM-exit or not. + * + * @returns @c true if the LMSW access causes a VM-exit, @c false otherwise. + * @param pCtx Current CPU context. + * @param uNewMsw The LMSW source operand (the Machine Status Word). + */ +DECLINLINE(bool) CPUMIsGuestVmxLmswInterceptSet(PCCPUMCTX pCtx, uint16_t uNewMsw) +{ + /* + * LMSW VM-exits are subject to the CR0 guest/host mask and the CR0 read shadow. + * + * See Intel spec. 24.6.6 "Guest/Host Masks and Read Shadows for CR0 and CR4". + * See Intel spec. 25.1.3 "Instructions That Cause VM Exits Conditionally". + */ + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + + uint32_t const fGstHostMask = (uint32_t)pCtx->hwvirt.vmx.Vmcs.u64Cr0Mask.u; + uint32_t const fReadShadow = (uint32_t)pCtx->hwvirt.vmx.Vmcs.u64Cr0ReadShadow.u; + + /* + * LMSW can never clear CR0.PE but it may set it. Hence, we handle the + * CR0.PE case first, before the rest of the bits in the MSW. + * + * If CR0.PE is owned by the host and CR0.PE differs between the + * MSW (source operand) and the read-shadow, we must cause a VM-exit. + */ + if ( (fGstHostMask & X86_CR0_PE) + && (uNewMsw & X86_CR0_PE) + && !(fReadShadow & X86_CR0_PE)) + return true; + + /* + * If CR0.MP, CR0.EM or CR0.TS is owned by the host, and the corresponding + * bits differ between the MSW (source operand) and the read-shadow, we must + * cause a VM-exit. + */ + uint32_t const fGstHostLmswMask = fGstHostMask & (X86_CR0_MP | X86_CR0_EM | X86_CR0_TS); + if ((fReadShadow & fGstHostLmswMask) != (uNewMsw & fGstHostLmswMask)) + return true; + + return false; +} + +/** + * Checks whether the Mov-to-CR0/CR4 access causes a VM-exit or not. + * + * @returns @c true if the Mov CRX access causes a VM-exit, @c false otherwise. + * @param pCtx Current CPU context. + * @param iCrReg The control register number (must be 0 or 4). + * @param uNewCrX The CR0/CR4 value being written. + */ +DECLINLINE(bool) CPUMIsGuestVmxMovToCr0Cr4InterceptSet(PCCPUMCTX pCtx, uint8_t iCrReg, uint64_t uNewCrX) +{ + /* + * For any CR0/CR4 bit owned by the host (in the CR0/CR4 guest/host mask), if the + * corresponding bits differ between the source operand and the read-shadow, + * we must cause a VM-exit. + * + * See Intel spec. 25.1.3 "Instructions That Cause VM Exits Conditionally". + */ + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + Assert(iCrReg == 0 || iCrReg == 4); + + uint64_t fGstHostMask; + uint64_t fReadShadow; + if (iCrReg == 0) + { + fGstHostMask = pCtx->hwvirt.vmx.Vmcs.u64Cr0Mask.u; + fReadShadow = pCtx->hwvirt.vmx.Vmcs.u64Cr0ReadShadow.u; + } + else + { + fGstHostMask = pCtx->hwvirt.vmx.Vmcs.u64Cr4Mask.u; + fReadShadow = pCtx->hwvirt.vmx.Vmcs.u64Cr4ReadShadow.u; + } + + if ((fReadShadow & fGstHostMask) != (uNewCrX & fGstHostMask)) + { + Assert(fGstHostMask != 0); + return true; + } + + return false; +} + +/** + * Returns whether the guest has an active, current VMCS. + * + * @returns @c true if the guest has an active, current VMCS, @c false otherwise. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestVmxCurrentVmcsValid(PCCPUMCTX pCtx) +{ + return pCtx->hwvirt.vmx.GCPhysVmcs != NIL_RTGCPHYS; +} + +# endif /* !IN_RC */ + +/** + * Checks whether the VMX nested-guest is in a state to receive physical (APIC) + * interrupts. + * + * @returns @c true if it's ready, @c false otherwise. + * @param pCtx The guest-CPU context. + */ +DECLINLINE(bool) CPUMIsGuestVmxPhysIntrEnabled(PCCPUMCTX pCtx) +{ +#ifdef IN_RC + AssertReleaseFailedReturn(false); +#else + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + if (CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_EXT_INT_EXIT)) + return true; + return RT_BOOL(pCtx->eflags.u & X86_EFL_IF); +#endif +} + +/** + * Checks whether the VMX nested-guest is blocking virtual-NMIs. + * + * @returns @c true if it's blocked, @c false otherwise. + * @param pCtx The guest-CPU context. + */ +DECLINLINE(bool) CPUMIsGuestVmxVirtNmiBlocking(PCCPUMCTX pCtx) +{ +#ifdef IN_RC + RT_NOREF(pCtx); + AssertReleaseFailedReturn(false); +#else + /* + * Return the state of virtual-NMI blocking, if we are executing a + * VMX nested-guest with virtual-NMIs enabled. + */ + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + Assert(CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_VIRT_NMI)); + return pCtx->hwvirt.vmx.fVirtNmiBlocking; +#endif +} + +/** + * Sets or clears VMX nested-guest virtual-NMI blocking. + * + * @param pCtx The guest-CPU context. + * @param fBlocking Whether virtual-NMI blocking is in effect or not. + */ +DECLINLINE(void) CPUMSetGuestVmxVirtNmiBlocking(PCPUMCTX pCtx, bool fBlocking) +{ +#ifdef IN_RC + RT_NOREF2(pCtx, fBlocking); + AssertReleaseFailedReturnVoid(); +#else + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + Assert(CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_VIRT_NMI)); + pCtx->hwvirt.vmx.fVirtNmiBlocking = fBlocking; +#endif +} + +/** + * Checks whether the VMX nested-guest is in a state to receive virtual interrupts + * (those injected with the "virtual-interrupt delivery" feature). + * + * @returns @c true if it's ready, @c false otherwise. + * @param pCtx The guest-CPU context. + */ +DECLINLINE(bool) CPUMIsGuestVmxVirtIntrEnabled(PCCPUMCTX pCtx) +{ +#ifdef IN_RC + RT_NOREF2(pCtx); + AssertReleaseFailedReturn(false); +#else + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + return RT_BOOL(pCtx->eflags.u & X86_EFL_IF); +#endif +} + +/** @} */ +#endif /* !IPRT_WITHOUT_NAMED_UNIONS_AND_STRUCTS || DOXYGEN_RUNNING */ + + + +/** @name Hypervisor Register Getters. + * @{ */ +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(uint32_t) CPUMGetHyperCR3(PVMCPU pVCpu); +/** @} */ + +/** @name Hypervisor Register Setters. + * @{ */ +VMMDECL(void) CPUMSetHyperCR3(PVMCPU pVCpu, uint32_t cr3); +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(int) CPUMRecalcHyperDRx(PVMCPUCC pVCpu, uint8_t iGstReg); +/** @} */ + +VMMDECL(PCPUMCTX) CPUMQueryGuestCtxPtr(PVMCPU pVCpu); +#ifdef VBOX_INCLUDED_vmm_cpumctx_h +VMM_INT_DECL(PCPUMCTXMSRS) CPUMQueryGuestCtxMsrsPtr(PVMCPU pVCpu); +#endif + +/** @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! + * + * @todo This is obsolete, but remains as it will be refactored for coordinating + * IEM and NEM/HM later. Probably. + * @{ + */ +#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 fChangedAdd); +VMMDECL(bool) CPUMSupportsXSave(PVM pVM); +VMMDECL(bool) CPUMIsHostUsingSysEnter(PVM pVM); +VMMDECL(bool) CPUMIsHostUsingSysCall(PVM pVM); +VMMDECL(bool) CPUMIsGuestFPUStateActive(PVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestFPUStateLoaded(PVMCPU pVCpu); +VMMDECL(bool) CPUMIsHostFPUStateSaved(PVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestDebugStateActive(PVMCPU pVCpu); +VMMDECL(void) CPUMDeactivateGuestDebugState(PVMCPU pVCpu); +VMMDECL(bool) CPUMIsHyperDebugStateActive(PVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestCPL(PVMCPU pVCpu); +VMMDECL(CPUMMODE) CPUMGetGuestMode(PVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestCodeBits(PVMCPU pVCpu); +VMMDECL(DISCPUMODE) CPUMGetGuestDisMode(PVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestMxCsrMask(PVM pVM); +VMMDECL(uint64_t) CPUMGetGuestScalableBusFrequency(PVM pVM); +VMMDECL(uint64_t) CPUMGetGuestEferMsrValidMask(PVM pVM); +VMMDECL(int) CPUMIsGuestEferMsrWriteValid(PVM pVM, uint64_t uCr0, uint64_t uOldEfer, uint64_t uNewEfer, + uint64_t *puValidEfer); +VMMDECL(void) CPUMSetGuestEferMsrNoChecks(PVMCPUCC pVCpu, uint64_t uOldEfer, uint64_t uValidEfer); +VMMDECL(bool) CPUMIsPatMsrValid(uint64_t uValue); + + +/** Guest CPU interruptibility level, see CPUMGetGuestInterruptibility(). */ +typedef enum CPUMINTERRUPTIBILITY +{ + CPUMINTERRUPTIBILITY_INVALID = 0, + CPUMINTERRUPTIBILITY_UNRESTRAINED, + CPUMINTERRUPTIBILITY_VIRT_INT_DISABLED, + CPUMINTERRUPTIBILITY_INT_DISABLED, + CPUMINTERRUPTIBILITY_INT_INHIBITED, /**< @todo rename as it inhibits NMIs too. */ + CPUMINTERRUPTIBILITY_NMI_INHIBIT, + CPUMINTERRUPTIBILITY_GLOBAL_INHIBIT, + CPUMINTERRUPTIBILITY_END, + CPUMINTERRUPTIBILITY_32BIT_HACK = 0x7fffffff +} CPUMINTERRUPTIBILITY; + +VMM_INT_DECL(CPUMINTERRUPTIBILITY) CPUMGetGuestInterruptibility(PVMCPU pVCpu); + +/** @name Typical scalable bus frequency values. + * @{ */ +/** Special internal value indicating that we don't know the frequency. + * @internal */ +#define CPUM_SBUSFREQ_UNKNOWN UINT64_C(1) +#define CPUM_SBUSFREQ_100MHZ UINT64_C(100000000) +#define CPUM_SBUSFREQ_133MHZ UINT64_C(133333333) +#define CPUM_SBUSFREQ_167MHZ UINT64_C(166666666) +#define CPUM_SBUSFREQ_200MHZ UINT64_C(200000000) +#define CPUM_SBUSFREQ_267MHZ UINT64_C(266666666) +#define CPUM_SBUSFREQ_333MHZ UINT64_C(333333333) +#define CPUM_SBUSFREQ_400MHZ UINT64_C(400000000) +/** @} */ + + +#ifdef IN_RING3 +/** @defgroup grp_cpum_r3 The CPUM ring-3 API + * @{ + */ + +VMMR3DECL(int) CPUMR3Init(PVM pVM); +VMMR3DECL(int) CPUMR3InitCompleted(PVM pVM, VMINITCOMPLETED enmWhat); +VMMR3DECL(void) CPUMR3LogCpuIdAndMsrFeatures(PVM pVM); +VMMR3DECL(void) CPUMR3Relocate(PVM pVM); +VMMR3DECL(int) CPUMR3Term(PVM pVM); +VMMR3DECL(void) CPUMR3Reset(PVM pVM); +VMMR3DECL(void) CPUMR3ResetCpu(PVM pVM, PVMCPU pVCpu); +VMMDECL(bool) CPUMR3IsStateRestorePending(PVM pVM); +VMMR3DECL(int) CPUMR3SetCR4Feature(PVM pVM, RTHCUINTREG fOr, RTHCUINTREG fAnd); + +VMMR3DECL(int) CPUMR3CpuIdInsert(PVM pVM, PCPUMCPUIDLEAF pNewLeaf); +VMMR3DECL(int) CPUMR3CpuIdGetLeaf(PVM pVM, PCPUMCPUIDLEAF pLeaf, uint32_t uLeaf, uint32_t uSubLeaf); +VMMR3_INT_DECL(PCCPUMCPUIDLEAF) CPUMR3CpuIdGetPtr(PVM pVM, uint32_t *pcLeaves); +VMMDECL(CPUMMICROARCH) CPUMCpuIdDetermineX86MicroarchEx(CPUMCPUVENDOR enmVendor, uint8_t bFamily, + uint8_t bModel, uint8_t bStepping); +VMMDECL(const char *) CPUMMicroarchName(CPUMMICROARCH enmMicroarch); +VMMR3DECL(int) CPUMR3CpuIdDetectUnknownLeafMethod(PCPUMUNKNOWNCPUID penmUnknownMethod, PCPUMCPUID pDefUnknown); +VMMR3DECL(const char *) CPUMR3CpuIdUnknownLeafMethodName(CPUMUNKNOWNCPUID enmUnknownMethod); +VMMR3DECL(const char *) CPUMCpuVendorName(CPUMCPUVENDOR enmVendor); +#if defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64) +VMMR3DECL(uint32_t) CPUMR3DeterminHostMxCsrMask(void); +#endif + +VMMR3DECL(int) CPUMR3MsrRangesInsert(PVM pVM, PCCPUMMSRRANGE pNewRange); + +VMMR3DECL(uint32_t) CPUMR3DbGetEntries(void); +/** Pointer to CPUMR3DbGetEntries. */ +typedef DECLCALLBACKPTR(uint32_t, PFNCPUMDBGETENTRIES, (void)); +VMMR3DECL(PCCPUMDBENTRY) CPUMR3DbGetEntryByIndex(uint32_t idxCpuDb); +/** Pointer to CPUMR3DbGetEntryByIndex. */ +typedef DECLCALLBACKPTR(PCCPUMDBENTRY, PFNCPUMDBGETENTRYBYINDEX, (uint32_t idxCpuDb)); +VMMR3DECL(PCCPUMDBENTRY) CPUMR3DbGetEntryByName(const char *pszName); +/** Pointer to CPUMR3DbGetEntryByName. */ +typedef DECLCALLBACKPTR(PCCPUMDBENTRY, PFNCPUMDBGETENTRYBYNAME, (const char *pszName)); + +VMMR3_INT_DECL(void) CPUMR3NemActivateGuestDebugState(PVMCPUCC pVCpu); +VMMR3_INT_DECL(void) CPUMR3NemActivateHyperDebugState(PVMCPUCC pVCpu); +/** @} */ +#endif /* IN_RING3 */ + +#ifdef IN_RING0 +/** @defgroup grp_cpum_r0 The CPUM ring-0 API + * @{ + */ +VMMR0_INT_DECL(int) CPUMR0ModuleInit(void); +VMMR0_INT_DECL(int) CPUMR0ModuleTerm(void); +VMMR0_INT_DECL(void) CPUMR0InitPerVMData(PGVM pGVM); +VMMR0_INT_DECL(int) CPUMR0InitVM(PVMCC pVM); +DECLASM(void) CPUMR0RegisterVCpuThread(PVMCPUCC pVCpu); +DECLASM(void) CPUMR0TouchHostFpu(void); +VMMR0_INT_DECL(int) CPUMR0Trap07Handler(PVMCC pVM, PVMCPUCC pVCpu); +VMMR0_INT_DECL(int) CPUMR0LoadGuestFPU(PVMCC pVM, PVMCPUCC pVCpu); +VMMR0_INT_DECL(bool) CPUMR0FpuStateMaybeSaveGuestAndRestoreHost(PVMCPUCC pVCpu); +VMMR0_INT_DECL(int) CPUMR0SaveHostDebugState(PVMCC pVM, PVMCPUCC pVCpu); +VMMR0_INT_DECL(bool) CPUMR0DebugStateMaybeSaveGuestAndRestoreHost(PVMCPUCC pVCpu, bool fDr6); +VMMR0_INT_DECL(bool) CPUMR0DebugStateMaybeSaveGuest(PVMCPUCC pVCpu, bool fDr6); + +VMMR0_INT_DECL(void) CPUMR0LoadGuestDebugState(PVMCPUCC pVCpu, bool fDr6); +VMMR0_INT_DECL(void) CPUMR0LoadHyperDebugState(PVMCPUCC pVCpu, bool fDr6); +/** @} */ +#endif /* IN_RING0 */ + +/** @defgroup grp_cpum_rz The CPUM raw-mode and ring-0 context API + * @{ + */ +VMMRZ_INT_DECL(void) CPUMRZFpuStatePrepareHostCpuForUse(PVMCPUCC pVCpu); +VMMRZ_INT_DECL(void) CPUMRZFpuStateActualizeForRead(PVMCPUCC pVCpu); +VMMRZ_INT_DECL(void) CPUMRZFpuStateActualizeForChange(PVMCPUCC pVCpu); +VMMRZ_INT_DECL(void) CPUMRZFpuStateActualizeSseForRead(PVMCPUCC pVCpu); +VMMRZ_INT_DECL(void) CPUMRZFpuStateActualizeAvxForRead(PVMCPUCC pVCpu); +/** @} */ + + +#endif /* !VBOX_FOR_DTRACE_LIB */ +/** @} */ +RT_C_DECLS_END + + +#endif /* !VBOX_INCLUDED_vmm_cpum_h */ + diff --git a/include/VBox/vmm/cpum.mac b/include/VBox/vmm/cpum.mac new file mode 100644 index 00000000..dac92f61 --- /dev/null +++ b/include/VBox/vmm/cpum.mac @@ -0,0 +1,275 @@ +;; @file +; CPUM - CPU Monitor, Assembly header file. +; + +; +; Copyright (C) 2006-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox 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. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef ___VBox_vmm_cpum_mac__ +%define ___VBox_vmm_cpum_mac__ + +%include "iprt/asmdefs.mac" + + +;; +; The volatile XSAVE components when VBOX_WITH_KERNEL_USING_XMM is active. +; @note ASSUMED to be at the most 32-bit in width at the moment. +%ifdef VBOX_WITH_KERNEL_USING_XMM + %define CPUM_VOLATILE_XSAVE_GUEST_COMPONENTS (XSAVE_C_SSE | XSAVE_C_YMM | XSAVE_C_ZMM_HI256 | XSAVE_C_ZMM_16HI) +%endif + +;; +; CPUID leaf. +; @remarks This structure is used by the patch manager and can only be extended +; by adding to the end of it. +struc CPUMCPUIDLEAF + .uLeaf resd 1 + .uSubLeaf resd 1 + .fSubLeafMask resd 1 + .uEax resd 1 + .uEbx resd 1 + .uEcx resd 1 + .uEdx resd 1 + .fFlags resd 1 +endstruc +%define CPUMCPUIDLEAF_F_INTEL_TOPOLOGY_SUBLEAVES RT_BIT_32(0) +%define CPUMCPUIDLEAF_F_CONTAINS_APIC_ID RT_BIT_32(1) +%define CPUMCPUIDLEAF_F_CONTAINS_OSXSAVE RT_BIT_32(2) +%define CPUMCPUIDLEAF_F_CONTAINS_APIC RT_BIT_32(3) + + +;; +; For the default CPUID leaf value. +; @remarks This is used by the patch manager and cannot be modified in any way. +struc CPUMCPUID + .uEax resd 1 + .uEbx resd 1 + .uEcx resd 1 + .uEdx resd 1 +endstruc + + +;; @name Method used to deal with unknown CPUID leaves. +;; @{ +%define CPUMUNKNOWNCPUID_DEFAULTS 1 +%define CPUMUNKNOWNCPUID_LAST_STD_LEAF 2 +%define CPUMUNKNOWNCPUID_LAST_STD_LEAF_WITH_ECX 3 +%define CPUMUNKNOWNCPUID_PASSTHRU 4 +;; @} + + +%define XSTATE_SIZE 8192 + +;; Note! Updates here must be reflected in CPUMInternal.mac too! +struc CPUMCTX + .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 + .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 + alignb 8 + .eip resq 1 + .eflags resq 1 + .fExtrn resq 1 + .uRipInhibitInt 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 + .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 + + alignb 32 + .aPaePdpes resq 4 + + alignb 8 + .aXcr resq 2 + .fXStateMask resq 1 + .fUsedFpuGuest resb 1 + alignb 8 + .aoffXState resw 64 + alignb 256 + .abXState resb 0x4000-0x300 + .XState EQU .abXState + + alignb 4096 + .hwvirt resb 0 + .hwvirt.svm resb 0 + .hwvirt.vmx resb 0 + + .hwvirt.svm.Vmcb EQU .hwvirt.svm + .hwvirt.svm.abMsrBitmap EQU (.hwvirt.svm.Vmcb + 0x1000) + .hwvirt.svm.abIoBitmap EQU (.hwvirt.svm.abMsrBitmap + 0x2000) + .hwvirt.svm.uMsrHSavePa EQU (.hwvirt.svm.abIoBitmap + 0x3000) ; resq 1 + .hwvirt.svm.GCPhysVmcb EQU (.hwvirt.svm.uMsrHSavePa + 8) ; resq 1 + alignb 8 + .hwvirt.svm.HostState EQU (.hwvirt.svm.GCPhysVmcb + 8) ; resb 184 + .hwvirt.svm.uPrevPauseTick EQU (.hwvirt.svm.HostState + 184) ; resq 1 + .hwvirt.svm.cPauseFilter EQU (.hwvirt.svm.uPrevPauseTick + 8) ; resw 1 + .hwvirt.svm.cPauseFilterThreshold EQU (.hwvirt.svm.cPauseFilter + 2) ; resw 1 + .hwvirt.svm.fInterceptEvents EQU (.hwvirt.svm.cPauseFilterThreshold + 2) ; resb 1 + + .hwvirt.vmx.Vmcs resb 0x1000 + .hwvirt.vmx.ShadowVmcs resb 0x1000 + .hwvirt.vmx.abVmreadBitmap resb 0x1000 + .hwvirt.vmx.abVmwriteBitmap resb 0x1000 + .hwvirt.vmx.aEntryMsrLoadArea resb 0x2000 + .hwvirt.vmx.aExitMsrStoreArea resb 0x2000 + .hwvirt.vmx.aExitMsrLoadArea resb 0x2000 + .hwvirt.vmx.abMsrBitmap resb 0x1000 + .hwvirt.vmx.abIoBitmap resb 0x1000+0x1000 + alignb 8 + .hwvirt.vmx.GCPhysVmxon resq 1 + .hwvirt.vmx.GCPhysVmcs resq 1 + .hwvirt.vmx.GCPhysShadowVmcs resq 1 + .hwvirt.vmx.enmDiag resd 1 + .hwvirt.vmx.enmAbort resd 1 + .hwvirt.vmx.uDiagAux resq 1 + .hwvirt.vmx.uAbortAux resd 1 + .hwvirt.vmx.fInVmxRootMode resb 1 + .hwvirt.vmx.fInVmxNonRootMode resb 1 + .hwvirt.vmx.fInterceptEvents resb 1 + .hwvirt.vmx.fNmiUnblockingIret resb 1 + .hwvirt.vmx.uFirstPauseLoopTick resq 1 + .hwvirt.vmx.uPrevPauseTick resq 1 + .hwvirt.vmx.uEntryTick resq 1 + .hwvirt.vmx.offVirtApicWrite resw 1 + .hwvirt.vmx.fVirtNmiBlocking resb 1 + alignb 8 + .hwvirt.vmx.Msrs resb 224 + + alignb 8 + .hwvirt.enmHwvirt resd 1 + .hwvirt.fGif resb 1 + alignb 4 + .hwvirt.fSavedInhibit resd 1 + alignb 64 +endstruc + + +%define CPUMSELREG_FLAGS_VALID 0x0001 +%define CPUMSELREG_FLAGS_STALE 0x0002 +%define CPUMSELREG_FLAGS_VALID_MASK 0x0003 + + +;; +; 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..fe6d30db --- /dev/null +++ b/include/VBox/vmm/cpumctx-v1_6.h @@ -0,0 +1,263 @@ +/** @file + * CPUM - CPU Monitor(/ Manager), Context Structures from v1.6 (saved state). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_cpumctx_v1_6_h +#define VBOX_INCLUDED_vmm_cpumctx_v1_6_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/x86.h> +#include <VBox/vmm/cpumctx.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup 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_NM(rdi); + union + { + uint32_t esi; + uint64_t rsi; + } CPUM_UNION_NM(rsi); + union + { + uint32_t ebp; + uint64_t rbp; + } CPUM_UNION_NM(rbp); + union + { + uint32_t eax; + uint64_t rax; + } CPUM_UNION_NM(rax); + union + { + uint32_t ebx; + uint64_t rbx; + } CPUM_UNION_NM(rbx); + union + { + uint32_t edx; + uint64_t rdx; + } CPUM_UNION_NM(rdx); + union + { + uint32_t ecx; + uint64_t rcx; + } CPUM_UNION_NM(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_NM(rflags); + union + { + uint32_t eip; + uint64_t rip; + } CPUM_UNION_NM(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 /* !VBOX_INCLUDED_vmm_cpumctx_v1_6_h */ + diff --git a/include/VBox/vmm/cpumctx.h b/include/VBox/vmm/cpumctx.h new file mode 100644 index 00000000..fd8a4fec --- /dev/null +++ b/include/VBox/vmm/cpumctx.h @@ -0,0 +1,1116 @@ +/** @file + * CPUM - CPU Monitor(/ Manager), Context Structures. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_cpumctx_h +#define VBOX_INCLUDED_vmm_cpumctx_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifndef VBOX_FOR_DTRACE_LIB +# include <iprt/x86.h> +# include <VBox/types.h> +# include <VBox/vmm/hm_svm.h> +# include <VBox/vmm/hm_vmx.h> +#else +# pragma D depends_on library x86.d +#endif + + +RT_C_DECLS_BEGIN + +/** @defgroup 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; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(CPUMSELREG, 24); +#endif + +/** @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. */ +#define CPUMSELREG_ARE_HIDDEN_PARTS_VALID(a_pVCpu, a_pSelReg) \ + ( ((a_pSelReg)->fFlags & CPUMSELREG_FLAGS_VALID) \ + && (a_pSelReg)->ValidSel == (a_pSelReg)->Sel ) + +/** 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; + +/** @def CPUM_UNION_NM + * For compilers (like DTrace) that does not grok nameless unions, we have a + * little hack to make them palatable. + */ +/** @def CPUM_STRUCT_NM + * For compilers (like DTrace) that does not grok nameless structs (it is + * non-standard C++), we have a little hack to make them palatable. + */ +#ifdef VBOX_FOR_DTRACE_LIB +# define CPUM_UNION_NM(a_Nm) a_Nm +# define CPUM_STRUCT_NM(a_Nm) a_Nm +#elif defined(IPRT_WITHOUT_NAMED_UNIONS_AND_STRUCTS) +# define CPUM_UNION_NM(a_Nm) a_Nm +# define CPUM_STRUCT_NM(a_Nm) a_Nm +#else +# define CPUM_UNION_NM(a_Nm) +# define CPUM_STRUCT_NM(a_Nm) +#endif +/** @def CPUM_UNION_STRUCT_NM + * Combines CPUM_UNION_NM and CPUM_STRUCT_NM to avoid hitting the right side of + * the screen in the compile time assertions. + */ +#define CPUM_UNION_STRUCT_NM(a_UnionNm, a_StructNm) CPUM_UNION_NM(a_UnionNm .) CPUM_STRUCT_NM(a_StructNm) + +/** A general register (union). */ +typedef union CPUMCTXGREG +{ + /** Natural unsigned integer view. */ + uint64_t u; + /** 64-bit view. */ + uint64_t u64; + /** 32-bit view. */ + uint32_t u32; + /** 16-bit view. */ + uint16_t u16; + /** 8-bit view. */ + uint8_t u8; + /** 8-bit low/high view. */ + RT_GCC_EXTENSION struct + { + /** Low byte (al, cl, dl, bl, ++). */ + uint8_t bLo; + /** High byte in the first word - ah, ch, dh, bh. */ + uint8_t bHi; + } CPUM_STRUCT_NM(s); +} CPUMCTXGREG; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(CPUMCTXGREG, 8); +AssertCompileMemberOffset(CPUMCTXGREG, CPUM_STRUCT_NM(s.) bLo, 0); +AssertCompileMemberOffset(CPUMCTXGREG, CPUM_STRUCT_NM(s.) bHi, 1); +#endif + + + +/** + * SVM Host-state area (Nested Hw.virt - VirtualBox's layout). + * + * @warning Exercise caution while modifying the layout of this struct. It's + * part of VM saved states. + */ +#pragma pack(1) +typedef struct SVMHOSTSTATE +{ + uint64_t uEferMsr; + uint64_t uCr0; + uint64_t uCr4; + uint64_t uCr3; + uint64_t uRip; + uint64_t uRsp; + uint64_t uRax; + X86RFLAGS rflags; + CPUMSELREG es; + CPUMSELREG cs; + CPUMSELREG ss; + CPUMSELREG ds; + VBOXGDTR gdtr; + VBOXIDTR idtr; + uint8_t abPadding[4]; +} SVMHOSTSTATE; +#pragma pack() +/** Pointer to the SVMHOSTSTATE structure. */ +typedef SVMHOSTSTATE *PSVMHOSTSTATE; +/** Pointer to a const SVMHOSTSTATE structure. */ +typedef const SVMHOSTSTATE *PCSVMHOSTSTATE; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSizeAlignment(SVMHOSTSTATE, 8); +AssertCompileSize(SVMHOSTSTATE, 184); +#endif + + +/** + * CPU hardware virtualization types. + */ +typedef enum +{ + CPUMHWVIRT_NONE = 0, + CPUMHWVIRT_VMX, + CPUMHWVIRT_SVM, + CPUMHWVIRT_32BIT_HACK = 0x7fffffff +} CPUMHWVIRT; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(CPUMHWVIRT, 4); +#endif + +/** Number of EFLAGS bits we put aside for the hardware EFLAGS, with the bits + * above this we use for storing internal state not visible to the guest. + * + * Using a value less than 32 here means some code bloat when loading and + * fetching the hardware EFLAGS value. Comparing VMMR0.r0 text size when + * compiling release build using gcc 11.3.1 on linux: + * - 32 bits: 2475709 bytes + * - 24 bits: 2482069 bytes; +6360 bytes. + * - 22 bits: 2482261 bytes; +6552 bytes. + * Same for windows (virtual size of .text): + * - 32 bits: 1498502 bytes + * - 24 bits: 1502278 bytes; +3776 bytes. + * - 22 bits: 1502198 bytes; +3696 bytes. + * + * In addition we pass pointer the 32-bit EFLAGS to a number of IEM assembly + * functions, so it would be safer to not store anything in the lower 32 bits. + * OTOH, we'd sooner discover buggy assembly code by doing so, as we've had one + * example of accidental EFLAGS trashing by these functions already. + * + * It would be more efficient for IEM to store the interrupt shadow bit (and + * anything else that needs to be cleared at the same time) in the 30:22 bit + * range, because that would allow using a simple AND imm32 instruction on x86 + * and a MOVN imm16,16 instruction to load the constant on ARM64 (assuming the + * other flag needing clearing is RF (bit 16)). Putting it in the 63:32 range + * means we that on x86 we'll either use a memory variant of AND or require a + * separate load instruction for the immediate, whereas on ARM we'll need more + * instructions to construct the immediate value. + * + * Comparing the instruction exit thruput via the bs2-test-1 testcase, there + * seems to be little difference between 32 and 24 here (best results out of 9 + * runs on Linux/VT-x). So, unless the results are really wrong and there is + * clear drop in thruput, it would on the whole make the most sense to use 24 + * here. + * + * Update: We need more than 8 bits because of DBGF, so using 22 now. + */ +#define CPUMX86EFLAGS_HW_BITS 22 +/** Mask for the hardware EFLAGS bits, 64-bit version. */ +#define CPUMX86EFLAGS_HW_MASK_64 (RT_BIT_64(CPUMX86EFLAGS_HW_BITS) - UINT64_C(1)) +/** Mask for the hardware EFLAGS bits, 32-bit version. */ +#if CPUMX86EFLAGS_HW_BITS == 32 +# define CPUMX86EFLAGS_HW_MASK_32 UINT32_MAX +#elif CPUMX86EFLAGS_HW_BITS < 32 && CPUMX86EFLAGS_HW_BITS >= 22 +# define CPUMX86EFLAGS_HW_MASK_32 (RT_BIT_32(CPUMX86EFLAGS_HW_BITS) - UINT32_C(1)) +#else +# error "Misconfigured CPUMX86EFLAGS_HW_BITS value!" +#endif + +/** Mask of internal flags kept with EFLAGS, 64-bit version. + * Bits 22-24 are taken by CPUMCTX_INHIBIT_SHADOW_SS, CPUMCTX_INHIBIT_SHADOW_STI + * and CPUMCTX_INHIBIT_NMI, bits 25-28 are for CPUMCTX_DBG_HIT_DRX_MASK, and + * bits 29-30 are for DBGF events and breakpoints. + * + * @todo The two DBGF bits could be merged. The NMI inhibiting could move to + * bit 32 or higher as it isn't automatically cleared on instruction + * completion (except for iret). + */ +#define CPUMX86EFLAGS_INT_MASK_64 UINT64_C(0x00000000ffc00000) +/** Mask of internal flags kept with EFLAGS, 32-bit version. */ +#define CPUMX86EFLAGS_INT_MASK_32 UINT32_C(0xffc00000) + + +/** + * CPUM EFLAGS. + * + * This differs from X86EFLAGS in that we could use bits 31:22 for internal + * purposes, see CPUMX86EFLAGS_HW_BITS. + */ +typedef union CPUMX86EFLAGS +{ + /** The full unsigned view, both hardware and VBox bits. */ + uint32_t uBoth; + /** The plain unsigned view of the hardware bits. */ +#if CPUMX86EFLAGS_HW_BITS == 32 + uint32_t u; +#else + uint32_t u : CPUMX86EFLAGS_HW_BITS; +#endif +#ifndef VBOX_FOR_DTRACE_LIB + /** The bitfield view. */ + X86EFLAGSBITS Bits; +#endif +} CPUMX86EFLAGS; +/** Pointer to CPUM EFLAGS. */ +typedef CPUMX86EFLAGS *PCPUMX86EFLAGS; +/** Pointer to const CPUM EFLAGS. */ +typedef const CPUMX86EFLAGS *PCCPUMX86EFLAGS; + +/** + * CPUM RFLAGS. + * + * This differs from X86EFLAGS in that we use could be using bits 63:22 for + * internal purposes, see CPUMX86EFLAGS_HW_BITS. + */ +typedef union CPUMX86RFLAGS +{ + /** The full unsigned view, both hardware and VBox bits. */ + uint64_t uBoth; + /** The plain unsigned view of the hardware bits. */ +#if CPUMX86EFLAGS_HW_BITS == 32 + uint32_t u; +#else + uint32_t u : CPUMX86EFLAGS_HW_BITS; +#endif +#ifndef VBOX_FOR_DTRACE_LIB + /** The bitfield view. */ + X86EFLAGSBITS Bits; +#endif +} CPUMX86RFLAGS; +/** Pointer to CPUM RFLAGS. */ +typedef CPUMX86RFLAGS *PCPUMX86RFLAGS; +/** Pointer to const CPUM RFLAGS. */ +typedef const CPUMX86RFLAGS *PCCPUMX86RFLAGS; + + +/** + * CPU context. + */ +#pragma pack(1) /* for VBOXIDTR / VBOXGDTR. */ +typedef struct CPUMCTX +{ + /** General purpose registers. */ + union /* no tag! */ + { + /** The general purpose register array view, indexed by X86_GREG_XXX. */ + CPUMCTXGREG aGRegs[16]; + + /** 64-bit general purpose register view. */ + RT_GCC_EXTENSION struct /* no tag! */ + { + uint64_t rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, r15; + } CPUM_STRUCT_NM(qw); + /** 64-bit general purpose register view. */ + RT_GCC_EXTENSION struct /* no tag! */ + { + uint64_t r0, r1, r2, r3, r4, r5, r6, r7; + } CPUM_STRUCT_NM(qw2); + /** 32-bit general purpose register view. */ + RT_GCC_EXTENSION struct /* no tag! */ + { + uint32_t eax, u32Pad00, ecx, u32Pad01, edx, u32Pad02, ebx, u32Pad03, + esp, u32Pad04, ebp, u32Pad05, esi, u32Pad06, edi, u32Pad07, + r8d, u32Pad08, r9d, u32Pad09, r10d, u32Pad10, r11d, u32Pad11, + r12d, u32Pad12, r13d, u32Pad13, r14d, u32Pad14, r15d, u32Pad15; + } CPUM_STRUCT_NM(dw); + /** 16-bit general purpose register view. */ + RT_GCC_EXTENSION struct /* no tag! */ + { + uint16_t ax, au16Pad00[3], cx, au16Pad01[3], dx, au16Pad02[3], bx, au16Pad03[3], + sp, au16Pad04[3], bp, au16Pad05[3], si, au16Pad06[3], di, au16Pad07[3], + r8w, au16Pad08[3], r9w, au16Pad09[3], r10w, au16Pad10[3], r11w, au16Pad11[3], + r12w, au16Pad12[3], r13w, au16Pad13[3], r14w, au16Pad14[3], r15w, au16Pad15[3]; + } CPUM_STRUCT_NM(w); + RT_GCC_EXTENSION struct /* no tag! */ + { + uint8_t al, ah, abPad00[6], cl, ch, abPad01[6], dl, dh, abPad02[6], bl, bh, abPad03[6], + spl, abPad04[7], bpl, abPad05[7], sil, abPad06[7], dil, abPad07[7], + r8l, abPad08[7], r9l, abPad09[7], r10l, abPad10[7], r11l, abPad11[7], + r12l, abPad12[7], r13l, abPad13[7], r14l, abPad14[7], r15l, abPad15[7]; + } CPUM_STRUCT_NM(b); + } CPUM_UNION_NM(g); + + /** Segment registers. */ + union /* no tag! */ + { + /** The segment register array view, indexed by X86_SREG_XXX. */ + CPUMSELREG aSRegs[6]; + /** The named segment register view. */ + RT_GCC_EXTENSION struct /* no tag! */ + { + CPUMSELREG es, cs, ss, ds, fs, gs; + } CPUM_STRUCT_NM(n); + } CPUM_UNION_NM(s); + + /** 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 program counter. */ + union + { + uint16_t ip; + uint32_t eip; + uint64_t rip; + } CPUM_UNION_NM(rip); + + /** The flags register. */ + union + { + CPUMX86EFLAGS eflags; + CPUMX86RFLAGS rflags; + } CPUM_UNION_NM(rflags); + + /** 0x150 - Externalized state tracker, CPUMCTX_EXTRN_XXX. */ + uint64_t fExtrn; + + /** The RIP value an interrupt shadow is/was valid for. */ + uint64_t uRipInhibitInt; + + /** @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 sysenter msr registers. + * This member is not used by the hypervisor context. */ + CPUMSYSENTER SysEnter; + + /** @name System MSRs. + * @{ */ + uint64_t msrEFER; /**< @todo move EFER up to the crX registers for better cacheline mojo */ + 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. */ + /** @} */ + + uint64_t au64Unused[2]; + + /** 0x240 - PAE PDPTEs. */ + X86PDPE aPaePdpes[4]; + + /** 0x260 - The XCR0..XCR1 registers. */ + uint64_t aXcr[2]; + /** 0x270 - The mask to pass to XSAVE/XRSTOR in EDX:EAX. If zero we use + * FXSAVE/FXRSTOR (since bit 0 will always be set, we only need to test it). */ + uint64_t fXStateMask; + /** 0x278 - Mirror of CPUMCPU::fUseFlags[CPUM_USED_FPU_GUEST]. */ + bool fUsedFpuGuest; + uint8_t afUnused[7]; + + /* ---- Start of members not zeroed at reset. ---- */ + + /** 0x280 - State component offsets into pXState, UINT16_MAX if not present. + * @note Everything before this member will be memset to zero during reset. */ + uint16_t aoffXState[64]; + /** 0x300 - The extended state (FPU/SSE/AVX/AVX-2/XXXX). + * Aligned on 256 byte boundrary (min req is currently 64 bytes). */ + union /* no tag */ + { + X86XSAVEAREA XState; + /** Byte view for simple indexing and space allocation. */ + uint8_t abXState[0x4000 - 0x300]; + } CPUM_UNION_NM(u); + + /** 0x4000 - Hardware virtualization state. + * @note This is page aligned, so an full page member comes first in the + * substructures. */ + struct + { + union /* no tag! */ + { + struct + { + /** 0x4000 - Cache of the nested-guest VMCB. */ + SVMVMCB Vmcb; + /** 0x5000 - The MSRPM (MSR Permission bitmap). + * + * This need not be physically contiguous pages because we use the one from + * HMPHYSCPU while executing the nested-guest using hardware-assisted SVM. + * This one is just used for caching the bitmap from guest physical memory. + * + * @todo r=bird: This is not used directly by AMD-V hardware, so it doesn't + * really need to even be page aligned. + * + * Also, couldn't we just access the guest page directly when we need to, + * or do we have to use a cached copy of it? */ + uint8_t abMsrBitmap[SVM_MSRPM_PAGES * X86_PAGE_SIZE]; + /** 0x7000 - The IOPM (IO Permission bitmap). + * + * This need not be physically contiguous pages because we re-use the ring-0 + * allocated IOPM while executing the nested-guest using hardware-assisted SVM + * because it's identical (we trap all IO accesses). + * + * This one is just used for caching the IOPM from guest physical memory in + * case the guest hypervisor allows direct access to some IO ports. + * + * @todo r=bird: This is not used directly by AMD-V hardware, so it doesn't + * really need to even be page aligned. + * + * Also, couldn't we just access the guest page directly when we need to, + * or do we have to use a cached copy of it? */ + uint8_t abIoBitmap[SVM_IOPM_PAGES * X86_PAGE_SIZE]; + + /** 0xa000 - MSR holding physical address of the Guest's Host-state. */ + uint64_t uMsrHSavePa; + /** 0xa008 - Guest physical address of the nested-guest VMCB. */ + RTGCPHYS GCPhysVmcb; + /** 0xa010 - Guest's host-state save area. */ + SVMHOSTSTATE HostState; + /** 0xa0c8 - Guest TSC time-stamp of when the previous PAUSE instr. was + * executed. */ + uint64_t uPrevPauseTick; + /** 0xa0d0 - Pause filter count. */ + uint16_t cPauseFilter; + /** 0xa0d2 - Pause filter threshold. */ + uint16_t cPauseFilterThreshold; + /** 0xa0d4 - Whether the injected event is subject to event intercepts. */ + bool fInterceptEvents; + /** 0xa0d5 - Padding. */ + bool afPadding[3]; + } svm; + + struct + { + /** 0x4000 - The current VMCS. */ + VMXVVMCS Vmcs; + /** 0X5000 - The shadow VMCS. */ + VMXVVMCS ShadowVmcs; + /** 0x6000 - The VMREAD bitmap. + * @todo r=bird: Do we really need to keep copies for these? Couldn't we just + * access the guest memory directly as needed? */ + uint8_t abVmreadBitmap[VMX_V_VMREAD_VMWRITE_BITMAP_SIZE]; + /** 0x7000 - The VMWRITE bitmap. + * @todo r=bird: Do we really need to keep copies for these? Couldn't we just + * access the guest memory directly as needed? */ + uint8_t abVmwriteBitmap[VMX_V_VMREAD_VMWRITE_BITMAP_SIZE]; + /** 0x8000 - The VM-entry MSR-load area. */ + VMXAUTOMSR aEntryMsrLoadArea[VMX_V_AUTOMSR_AREA_SIZE / sizeof(VMXAUTOMSR)]; + /** 0xa000 - The VM-exit MSR-store area. */ + VMXAUTOMSR aExitMsrStoreArea[VMX_V_AUTOMSR_AREA_SIZE / sizeof(VMXAUTOMSR)]; + /** 0xc000 - The VM-exit MSR-load area. */ + VMXAUTOMSR aExitMsrLoadArea[VMX_V_AUTOMSR_AREA_SIZE / sizeof(VMXAUTOMSR)]; + /** 0xe000 - The MSR permission bitmap. + * @todo r=bird: Do we really need to keep copies for these? Couldn't we just + * access the guest memory directly as needed? */ + uint8_t abMsrBitmap[VMX_V_MSR_BITMAP_SIZE]; + /** 0xf000 - The I/O permission bitmap. + * @todo r=bird: Do we really need to keep copies for these? Couldn't we just + * access the guest memory directly as needed? */ + uint8_t abIoBitmap[VMX_V_IO_BITMAP_A_SIZE + VMX_V_IO_BITMAP_B_SIZE]; + + /** 0x11000 - Guest physical address of the VMXON region. */ + RTGCPHYS GCPhysVmxon; + /** 0x11008 - Guest physical address of the current VMCS pointer. */ + RTGCPHYS GCPhysVmcs; + /** 0x11010 - Guest physical address of the shadow VMCS pointer. */ + RTGCPHYS GCPhysShadowVmcs; + /** 0x11018 - Last emulated VMX instruction/VM-exit diagnostic. */ + VMXVDIAG enmDiag; + /** 0x1101c - VMX abort reason. */ + VMXABORT enmAbort; + /** 0x11020 - Last emulated VMX instruction/VM-exit diagnostic auxiliary info. + * (mainly used for info. that's not part of the VMCS). */ + uint64_t uDiagAux; + /** 0x11028 - VMX abort auxiliary info. */ + uint32_t uAbortAux; + /** 0x1102c - Whether the guest is in VMX root mode. */ + bool fInVmxRootMode; + /** 0x1102d - Whether the guest is in VMX non-root mode. */ + bool fInVmxNonRootMode; + /** 0x1102e - Whether the injected events are subjected to event intercepts. */ + bool fInterceptEvents; + /** 0x1102f - Whether blocking of NMI (or virtual-NMIs) was in effect in VMX + * non-root mode before execution of IRET. */ + bool fNmiUnblockingIret; + /** 0x11030 - Guest TSC timestamp of the first PAUSE instruction that is + * considered to be the first in a loop. */ + uint64_t uFirstPauseLoopTick; + /** 0x11038 - Guest TSC timestamp of the previous PAUSE instruction. */ + uint64_t uPrevPauseTick; + /** 0x11040 - Guest TSC timestamp of VM-entry (used for VMX-preemption + * timer). */ + uint64_t uEntryTick; + /** 0x11048 - Virtual-APIC write offset (until trap-like VM-exit). */ + uint16_t offVirtApicWrite; + /** 0x1104a - Whether virtual-NMI blocking is in effect. */ + bool fVirtNmiBlocking; + /** 0x1104b - Padding. */ + uint8_t abPadding0[5]; + /** 0x11050 - Guest VMX MSRs. */ + VMXMSRS Msrs; + } vmx; + } CPUM_UNION_NM(s); + + /** 0x11130 - Hardware virtualization type currently in use. */ + CPUMHWVIRT enmHwvirt; + /** 0x11134 - Global interrupt flag - AMD only (always true on Intel). */ + bool fGif; + /** 0x11135 - Padding. */ + bool afPadding0[3]; + /** 0x11138 - A subset of guest inhibit flags (CPUMCTX_INHIBIT_XXX) that are + * saved while running the nested-guest. */ + uint32_t fSavedInhibit; + /** 0x1113c - Pad to 64 byte boundary. */ + uint8_t abPadding1[4]; + } hwvirt; +} CPUMCTX; +#pragma pack() + +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSizeAlignment(CPUMCTX, 64); +AssertCompileSizeAlignment(CPUMCTX, 32); +AssertCompileSizeAlignment(CPUMCTX, 16); +AssertCompileSizeAlignment(CPUMCTX, 8); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) rax, 0x0000); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) rcx, 0x0008); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) rdx, 0x0010); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) rbx, 0x0018); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) rsp, 0x0020); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) rbp, 0x0028); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) rsi, 0x0030); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) rdi, 0x0038); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) r8, 0x0040); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) r9, 0x0048); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) r10, 0x0050); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) r11, 0x0058); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) r12, 0x0060); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) r13, 0x0068); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) r14, 0x0070); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) r15, 0x0078); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(s.) CPUM_STRUCT_NM(n.) es, 0x0080); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(s.) CPUM_STRUCT_NM(n.) cs, 0x0098); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(s.) CPUM_STRUCT_NM(n.) ss, 0x00b0); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(s.) CPUM_STRUCT_NM(n.) ds, 0x00c8); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(s.) CPUM_STRUCT_NM(n.) fs, 0x00e0); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(s.) CPUM_STRUCT_NM(n.) gs, 0x00f8); +AssertCompileMemberOffset(CPUMCTX, ldtr, 0x0110); +AssertCompileMemberOffset(CPUMCTX, tr, 0x0128); +AssertCompileMemberOffset(CPUMCTX, rip, 0x0140); +AssertCompileMemberOffset(CPUMCTX, rflags, 0x0148); +AssertCompileMemberOffset(CPUMCTX, fExtrn, 0x0150); +AssertCompileMemberOffset(CPUMCTX, uRipInhibitInt, 0x0158); +AssertCompileMemberOffset(CPUMCTX, cr0, 0x0160); +AssertCompileMemberOffset(CPUMCTX, cr2, 0x0168); +AssertCompileMemberOffset(CPUMCTX, cr3, 0x0170); +AssertCompileMemberOffset(CPUMCTX, cr4, 0x0178); +AssertCompileMemberOffset(CPUMCTX, dr, 0x0180); +AssertCompileMemberOffset(CPUMCTX, gdtr, 0x01c0+6); +AssertCompileMemberOffset(CPUMCTX, idtr, 0x01d0+6); +AssertCompileMemberOffset(CPUMCTX, SysEnter, 0x01e0); +AssertCompileMemberOffset(CPUMCTX, msrEFER, 0x01f8); +AssertCompileMemberOffset(CPUMCTX, msrSTAR, 0x0200); +AssertCompileMemberOffset(CPUMCTX, msrPAT, 0x0208); +AssertCompileMemberOffset(CPUMCTX, msrLSTAR, 0x0210); +AssertCompileMemberOffset(CPUMCTX, msrCSTAR, 0x0218); +AssertCompileMemberOffset(CPUMCTX, msrSFMASK, 0x0220); +AssertCompileMemberOffset(CPUMCTX, msrKERNELGSBASE, 0x0228); +AssertCompileMemberOffset(CPUMCTX, aPaePdpes, 0x0240); +AssertCompileMemberOffset(CPUMCTX, aXcr, 0x0260); +AssertCompileMemberOffset(CPUMCTX, fXStateMask, 0x0270); +AssertCompileMemberOffset(CPUMCTX, fUsedFpuGuest, 0x0278); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(u.) XState, 0x0300); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(u.) abXState, 0x0300); +AssertCompileMemberAlignment(CPUMCTX, CPUM_UNION_NM(u.) XState, 0x0100); +/* Only do spot checks for hwvirt */ +AssertCompileMemberAlignment(CPUMCTX, hwvirt, 0x1000); +AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) svm.Vmcb, X86_PAGE_SIZE); +AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) svm.abMsrBitmap, X86_PAGE_SIZE); +AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) svm.abIoBitmap, X86_PAGE_SIZE); +AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.Vmcs, X86_PAGE_SIZE); +AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.ShadowVmcs, X86_PAGE_SIZE); +AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.abVmreadBitmap, X86_PAGE_SIZE); +AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.abVmwriteBitmap, X86_PAGE_SIZE); +AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.aEntryMsrLoadArea, X86_PAGE_SIZE); +AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.aExitMsrStoreArea, X86_PAGE_SIZE); +AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.aExitMsrLoadArea, X86_PAGE_SIZE); +AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.abMsrBitmap, X86_PAGE_SIZE); +AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.abIoBitmap, X86_PAGE_SIZE); +AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.Msrs, 8); +AssertCompileMemberOffset(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) svm.abIoBitmap, 0x7000); +AssertCompileMemberOffset(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) svm.fInterceptEvents, 0xa0d4); +AssertCompileMemberOffset(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.abIoBitmap, 0xf000); +AssertCompileMemberOffset(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.fVirtNmiBlocking, 0x1104a); +AssertCompileMemberOffset(CPUMCTX, hwvirt.enmHwvirt, 0x11130); +AssertCompileMemberOffset(CPUMCTX, hwvirt.fGif, 0x11134); +AssertCompileMemberOffset(CPUMCTX, hwvirt.fSavedInhibit, 0x11138); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rax, CPUMCTX, CPUM_UNION_NM(g.) aGRegs); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rax, CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw2.) r0); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rcx, CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw2.) r1); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rdx, CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw2.) r2); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rbx, CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw2.) r3); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rsp, CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw2.) r4); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rbp, CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw2.) r5); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rsi, CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw2.) r6); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rdi, CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw2.) r7); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rax, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) eax); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rcx, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) ecx); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rdx, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) edx); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rbx, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) ebx); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rsp, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) esp); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rbp, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) ebp); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rsi, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) esi); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rdi, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) edi); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r8, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) r8d); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r9, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) r9d); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r10, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) r10d); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r11, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) r11d); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r12, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) r12d); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r13, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) r13d); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r14, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) r14d); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r15, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) r15d); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rax, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) ax); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rcx, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) cx); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rdx, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) dx); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rbx, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) bx); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rsp, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) sp); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rbp, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) bp); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rsi, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) si); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rdi, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) di); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r8, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) r8w); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r9, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) r9w); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r10, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) r10w); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r11, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) r11w); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r12, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) r12w); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r13, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) r13w); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r14, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) r14w); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r15, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) r15w); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rax, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) al); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rcx, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) cl); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rdx, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) dl); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rbx, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) bl); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rsp, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) spl); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rbp, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) bpl); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rsi, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) sil); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rdi, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) dil); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r8, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) r8l); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r9, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) r9l); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r10, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) r10l); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r11, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) r11l); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r12, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) r12l); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r13, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) r13l); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r14, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) r14l); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r15, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) r15l); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_NM(s.) CPUM_STRUCT_NM(n.) es, CPUMCTX, CPUM_UNION_NM(s.) aSRegs); +# ifndef _MSC_VER +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rax, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_xAX]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rcx, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_xCX]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rdx, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_xDX]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rbx, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_xBX]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rsp, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_xSP]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rbp, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_xBP]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rsi, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_xSI]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rdi, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_xDI]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r8, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_x8]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r9, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_x9]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r10, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_x10]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r11, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_x11]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r12, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_x12]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r13, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_x13]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r14, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_x14]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r15, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_x15]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(s,n.) es, CPUMCTX, CPUM_UNION_NM(s.) aSRegs[X86_SREG_ES]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(s,n.) cs, CPUMCTX, CPUM_UNION_NM(s.) aSRegs[X86_SREG_CS]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(s,n.) ss, CPUMCTX, CPUM_UNION_NM(s.) aSRegs[X86_SREG_SS]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(s,n.) ds, CPUMCTX, CPUM_UNION_NM(s.) aSRegs[X86_SREG_DS]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(s,n.) fs, CPUMCTX, CPUM_UNION_NM(s.) aSRegs[X86_SREG_FS]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(s,n.) gs, CPUMCTX, CPUM_UNION_NM(s.) aSRegs[X86_SREG_GS]); +# endif + + +/** + * Calculates the pointer to the given extended state component. + * + * @returns Pointer of type @a a_PtrType + * @param a_pCtx Pointer to the context. + * @param a_iCompBit The extended state component bit number. This bit + * must be set in CPUMCTX::fXStateMask. + * @param a_PtrType The pointer type of the extended state component. + * + */ +#if defined(VBOX_STRICT) && defined(RT_COMPILER_SUPPORTS_LAMBDA) +# define CPUMCTX_XSAVE_C_PTR(a_pCtx, a_iCompBit, a_PtrType) \ + ([](PCCPUMCTX a_pLambdaCtx) -> a_PtrType \ + { \ + AssertCompile((a_iCompBit) < 64U); \ + AssertMsg(a_pLambdaCtx->fXStateMask & RT_BIT_64(a_iCompBit), (#a_iCompBit "\n")); \ + AssertMsg(a_pLambdaCtx->aoffXState[(a_iCompBit)] != UINT16_MAX, (#a_iCompBit "\n")); \ + return (a_PtrType)(&a_pLambdaCtx->abXState[a_pLambdaCtx->aoffXState[(a_iCompBit)]]); \ + }(a_pCtx)) +#elif defined(VBOX_STRICT) && defined(__GNUC__) +# define CPUMCTX_XSAVE_C_PTR(a_pCtx, a_iCompBit, a_PtrType) \ + __extension__ (\ + { \ + AssertCompile((a_iCompBit) < 64U); \ + AssertMsg((a_pCtx)->fXStateMask & RT_BIT_64(a_iCompBit), (#a_iCompBit "\n")); \ + AssertMsg((a_pCtx)->aoffXState[(a_iCompBit)] != UINT16_MAX, (#a_iCompBit "\n")); \ + (a_PtrType)(&(a_pCtx)->abXState[(a_pCtx)->aoffXState[(a_iCompBit)]]); \ + }) +#else +# define CPUMCTX_XSAVE_C_PTR(a_pCtx, a_iCompBit, a_PtrType) \ + ((a_PtrType)(&(a_pCtx)->abXState[(a_pCtx)->aoffXState[(a_iCompBit)]])) +#endif + +/** + * 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 */ + + +/** @name CPUMCTX_EXTRN_XXX + * Used for parts of the CPUM state that is externalized and needs fetching + * before use. + * + * @{ */ +/** External state keeper: Invalid. */ +#define CPUMCTX_EXTRN_KEEPER_INVALID UINT64_C(0x0000000000000000) +/** External state keeper: HM. */ +#define CPUMCTX_EXTRN_KEEPER_HM UINT64_C(0x0000000000000001) +/** External state keeper: NEM. */ +#define CPUMCTX_EXTRN_KEEPER_NEM UINT64_C(0x0000000000000002) +/** External state keeper: REM. */ +#define CPUMCTX_EXTRN_KEEPER_REM UINT64_C(0x0000000000000003) +/** External state keeper mask. */ +#define CPUMCTX_EXTRN_KEEPER_MASK UINT64_C(0x0000000000000003) + +/** The RIP register value is kept externally. */ +#define CPUMCTX_EXTRN_RIP UINT64_C(0x0000000000000004) +/** The RFLAGS register values are kept externally. */ +#define CPUMCTX_EXTRN_RFLAGS UINT64_C(0x0000000000000008) + +/** The RAX register value is kept externally. */ +#define CPUMCTX_EXTRN_RAX UINT64_C(0x0000000000000010) +/** The RCX register value is kept externally. */ +#define CPUMCTX_EXTRN_RCX UINT64_C(0x0000000000000020) +/** The RDX register value is kept externally. */ +#define CPUMCTX_EXTRN_RDX UINT64_C(0x0000000000000040) +/** The RBX register value is kept externally. */ +#define CPUMCTX_EXTRN_RBX UINT64_C(0x0000000000000080) +/** The RSP register value is kept externally. */ +#define CPUMCTX_EXTRN_RSP UINT64_C(0x0000000000000100) +/** The RBP register value is kept externally. */ +#define CPUMCTX_EXTRN_RBP UINT64_C(0x0000000000000200) +/** The RSI register value is kept externally. */ +#define CPUMCTX_EXTRN_RSI UINT64_C(0x0000000000000400) +/** The RDI register value is kept externally. */ +#define CPUMCTX_EXTRN_RDI UINT64_C(0x0000000000000800) +/** The R8 thru R15 register values are kept externally. */ +#define CPUMCTX_EXTRN_R8_R15 UINT64_C(0x0000000000001000) +/** General purpose registers mask. */ +#define CPUMCTX_EXTRN_GPRS_MASK UINT64_C(0x0000000000001ff0) + +/** The ES register values are kept externally. */ +#define CPUMCTX_EXTRN_ES UINT64_C(0x0000000000002000) +/** The CS register values are kept externally. */ +#define CPUMCTX_EXTRN_CS UINT64_C(0x0000000000004000) +/** The SS register values are kept externally. */ +#define CPUMCTX_EXTRN_SS UINT64_C(0x0000000000008000) +/** The DS register values are kept externally. */ +#define CPUMCTX_EXTRN_DS UINT64_C(0x0000000000010000) +/** The FS register values are kept externally. */ +#define CPUMCTX_EXTRN_FS UINT64_C(0x0000000000020000) +/** The GS register values are kept externally. */ +#define CPUMCTX_EXTRN_GS UINT64_C(0x0000000000040000) +/** Segment registers (includes CS). */ +#define CPUMCTX_EXTRN_SREG_MASK UINT64_C(0x000000000007e000) +/** Converts a X86_XREG_XXX index to a CPUMCTX_EXTRN_xS mask. */ +#define CPUMCTX_EXTRN_SREG_FROM_IDX(a_SRegIdx) RT_BIT_64((a_SRegIdx) + 13) +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompile(CPUMCTX_EXTRN_SREG_FROM_IDX(X86_SREG_ES) == CPUMCTX_EXTRN_ES); +AssertCompile(CPUMCTX_EXTRN_SREG_FROM_IDX(X86_SREG_CS) == CPUMCTX_EXTRN_CS); +AssertCompile(CPUMCTX_EXTRN_SREG_FROM_IDX(X86_SREG_DS) == CPUMCTX_EXTRN_DS); +AssertCompile(CPUMCTX_EXTRN_SREG_FROM_IDX(X86_SREG_FS) == CPUMCTX_EXTRN_FS); +AssertCompile(CPUMCTX_EXTRN_SREG_FROM_IDX(X86_SREG_GS) == CPUMCTX_EXTRN_GS); +#endif + +/** The GDTR register values are kept externally. */ +#define CPUMCTX_EXTRN_GDTR UINT64_C(0x0000000000080000) +/** The IDTR register values are kept externally. */ +#define CPUMCTX_EXTRN_IDTR UINT64_C(0x0000000000100000) +/** The LDTR register values are kept externally. */ +#define CPUMCTX_EXTRN_LDTR UINT64_C(0x0000000000200000) +/** The TR register values are kept externally. */ +#define CPUMCTX_EXTRN_TR UINT64_C(0x0000000000400000) +/** Table register mask. */ +#define CPUMCTX_EXTRN_TABLE_MASK UINT64_C(0x0000000000780000) + +/** The CR0 register value is kept externally. */ +#define CPUMCTX_EXTRN_CR0 UINT64_C(0x0000000000800000) +/** The CR2 register value is kept externally. */ +#define CPUMCTX_EXTRN_CR2 UINT64_C(0x0000000001000000) +/** The CR3 register value is kept externally. */ +#define CPUMCTX_EXTRN_CR3 UINT64_C(0x0000000002000000) +/** The CR4 register value is kept externally. */ +#define CPUMCTX_EXTRN_CR4 UINT64_C(0x0000000004000000) +/** Control register mask. */ +#define CPUMCTX_EXTRN_CR_MASK UINT64_C(0x0000000007800000) +/** The TPR/CR8 register value is kept externally. */ +#define CPUMCTX_EXTRN_APIC_TPR UINT64_C(0x0000000008000000) +/** The EFER register value is kept externally. */ +#define CPUMCTX_EXTRN_EFER UINT64_C(0x0000000010000000) + +/** The DR0, DR1, DR2 and DR3 register values are kept externally. */ +#define CPUMCTX_EXTRN_DR0_DR3 UINT64_C(0x0000000020000000) +/** The DR6 register value is kept externally. */ +#define CPUMCTX_EXTRN_DR6 UINT64_C(0x0000000040000000) +/** The DR7 register value is kept externally. */ +#define CPUMCTX_EXTRN_DR7 UINT64_C(0x0000000080000000) +/** Debug register mask. */ +#define CPUMCTX_EXTRN_DR_MASK UINT64_C(0x00000000e0000000) + +/** The XSAVE_C_X87 state is kept externally. */ +#define CPUMCTX_EXTRN_X87 UINT64_C(0x0000000100000000) +/** The XSAVE_C_SSE, XSAVE_C_YMM, XSAVE_C_ZMM_HI256, XSAVE_C_ZMM_16HI and + * XSAVE_C_OPMASK state is kept externally. */ +#define CPUMCTX_EXTRN_SSE_AVX UINT64_C(0x0000000200000000) +/** The state of XSAVE components not covered by CPUMCTX_EXTRN_X87 and + * CPUMCTX_EXTRN_SEE_AVX is kept externally. */ +#define CPUMCTX_EXTRN_OTHER_XSAVE UINT64_C(0x0000000400000000) +/** The state of XCR0 and XCR1 register values are kept externally. */ +#define CPUMCTX_EXTRN_XCRx UINT64_C(0x0000000800000000) + + +/** The KERNEL GS BASE MSR value is kept externally. */ +#define CPUMCTX_EXTRN_KERNEL_GS_BASE UINT64_C(0x0000001000000000) +/** The STAR, LSTAR, CSTAR and SFMASK MSR values are kept externally. */ +#define CPUMCTX_EXTRN_SYSCALL_MSRS UINT64_C(0x0000002000000000) +/** The SYSENTER_CS, SYSENTER_EIP and SYSENTER_ESP MSR values are kept externally. */ +#define CPUMCTX_EXTRN_SYSENTER_MSRS UINT64_C(0x0000004000000000) +/** The TSC_AUX MSR is kept externally. */ +#define CPUMCTX_EXTRN_TSC_AUX UINT64_C(0x0000008000000000) +/** All other stateful MSRs not covered by CPUMCTX_EXTRN_EFER, + * CPUMCTX_EXTRN_KERNEL_GS_BASE, CPUMCTX_EXTRN_SYSCALL_MSRS, + * CPUMCTX_EXTRN_SYSENTER_MSRS, and CPUMCTX_EXTRN_TSC_AUX. */ +#define CPUMCTX_EXTRN_OTHER_MSRS UINT64_C(0x0000010000000000) + +/** Mask of all the MSRs. */ +#define CPUMCTX_EXTRN_ALL_MSRS ( CPUMCTX_EXTRN_EFER | CPUMCTX_EXTRN_KERNEL_GS_BASE | CPUMCTX_EXTRN_SYSCALL_MSRS \ + | CPUMCTX_EXTRN_SYSENTER_MSRS | CPUMCTX_EXTRN_TSC_AUX | CPUMCTX_EXTRN_OTHER_MSRS) + +/** Hardware-virtualization (SVM or VMX) state is kept externally. */ +#define CPUMCTX_EXTRN_HWVIRT UINT64_C(0x0000020000000000) + +/** Inhibit maskable interrupts (VMCPU_FF_INHIBIT_INTERRUPTS) */ +#define CPUMCTX_EXTRN_INHIBIT_INT UINT64_C(0x0000040000000000) +/** Inhibit non-maskable interrupts (VMCPU_FF_BLOCK_NMIS). */ +#define CPUMCTX_EXTRN_INHIBIT_NMI UINT64_C(0x0000080000000000) + +/** Mask of bits the keepers can use for state tracking. */ +#define CPUMCTX_EXTRN_KEEPER_STATE_MASK UINT64_C(0xffff000000000000) + +/** NEM/Win: Event injection (known was interruption) pending state. */ +#define CPUMCTX_EXTRN_NEM_WIN_EVENT_INJECT UINT64_C(0x0001000000000000) +/** NEM/Win: Mask. */ +#define CPUMCTX_EXTRN_NEM_WIN_MASK UINT64_C(0x0001000000000000) + +/** HM/SVM: Nested-guest interrupt pending (VMCPU_FF_INTERRUPT_NESTED_GUEST). */ +#define CPUMCTX_EXTRN_HM_SVM_HWVIRT_VIRQ UINT64_C(0x0001000000000000) +/** HM/SVM: Mask. */ +#define CPUMCTX_EXTRN_HM_SVM_MASK UINT64_C(0x0001000000000000) + +/** All CPUM state bits, not including keeper specific ones. */ +#define CPUMCTX_EXTRN_ALL UINT64_C(0x00000ffffffffffc) +/** All CPUM state bits, including keeper specific ones. */ +#define CPUMCTX_EXTRN_ABSOLUTELY_ALL UINT64_C(0xfffffffffffffffc) +/** @} */ + + +/** @name CPUMCTX_INHIBIT_XXX - Interrupt inhibiting flags. + * @{ */ +/** Interrupt shadow following MOV SS or POP SS. + * + * When this in effect, both maskable and non-maskable interrupts are blocked + * from delivery for one instruction. Same for certain debug exceptions too, + * unlike the STI variant. + * + * It is implementation specific whether a sequence of two or more of these + * instructions will have any effect on the instruction following the last one + * of them. */ +#define CPUMCTX_INHIBIT_SHADOW_SS RT_BIT_32(0 + CPUMX86EFLAGS_HW_BITS) +/** Interrupt shadow following STI. + * Same as CPUMCTX_INHIBIT_SHADOW_SS but without blocking any debug exceptions. */ +#define CPUMCTX_INHIBIT_SHADOW_STI RT_BIT_32(1 + CPUMX86EFLAGS_HW_BITS) +/** Mask combining STI and SS shadowing. */ +#define CPUMCTX_INHIBIT_SHADOW (CPUMCTX_INHIBIT_SHADOW_SS | CPUMCTX_INHIBIT_SHADOW_STI) + +/** Interrupts blocked by NMI delivery. This condition is cleared by IRET. + * + * Section "6.7 NONMASKABLE INTERRUPT (NMI)" in Intel SDM Vol 3A states that + * "The processor also invokes certain hardware conditions to ensure that no + * other interrupts, including NMI interrupts, are received until the NMI + * handler has completed executing." This flag indicates that these + * conditions are currently active. + * + * @todo this does not really need to be in the lower 32-bits of EFLAGS. + */ +#define CPUMCTX_INHIBIT_NMI RT_BIT_32(2 + CPUMX86EFLAGS_HW_BITS) + +/** Mask containing all the interrupt inhibit bits. */ +#define CPUMCTX_INHIBIT_ALL_MASK (CPUMCTX_INHIBIT_SHADOW_SS | CPUMCTX_INHIBIT_SHADOW_STI | CPUMCTX_INHIBIT_NMI) +AssertCompile(CPUMCTX_INHIBIT_ALL_MASK < UINT32_MAX); +/** @} */ + +/** @name CPUMCTX_DBG_XXX - Pending debug events. + * @{ */ +/** Hit guest DR0 breakpoint. */ +#define CPUMCTX_DBG_HIT_DR0 RT_BIT_32(CPUMCTX_DBG_HIT_DR0_BIT) +#define CPUMCTX_DBG_HIT_DR0_BIT (3 + CPUMX86EFLAGS_HW_BITS) +/** Hit guest DR1 breakpoint. */ +#define CPUMCTX_DBG_HIT_DR1 RT_BIT_32(CPUMCTX_DBG_HIT_DR1_BIT) +#define CPUMCTX_DBG_HIT_DR1_BIT (4 + CPUMX86EFLAGS_HW_BITS) +/** Hit guest DR2 breakpoint. */ +#define CPUMCTX_DBG_HIT_DR2 RT_BIT_32(CPUMCTX_DBG_HIT_DR2_BIT) +#define CPUMCTX_DBG_HIT_DR2_BIT (5 + CPUMX86EFLAGS_HW_BITS) +/** Hit guest DR3 breakpoint. */ +#define CPUMCTX_DBG_HIT_DR3 RT_BIT_32(CPUMCTX_DBG_HIT_DR3_BIT) +#define CPUMCTX_DBG_HIT_DR3_BIT (6 + CPUMX86EFLAGS_HW_BITS) +/** Shift for the CPUMCTX_DBG_HIT_DRx bits. */ +#define CPUMCTX_DBG_HIT_DRX_SHIFT CPUMCTX_DBG_HIT_DR0_BIT +/** Mask of all guest pending DR0-DR3 breakpoint indicators. */ +#define CPUMCTX_DBG_HIT_DRX_MASK (CPUMCTX_DBG_HIT_DR0 | CPUMCTX_DBG_HIT_DR1 | CPUMCTX_DBG_HIT_DR2 | CPUMCTX_DBG_HIT_DR3) +/** DBGF event/breakpoint pending. */ +#define CPUMCTX_DBG_DBGF_EVENT RT_BIT_32(CPUMCTX_DBG_DBGF_EVENT_BIT) +#define CPUMCTX_DBG_DBGF_EVENT_BIT (7 + CPUMX86EFLAGS_HW_BITS) +/** DBGF event/breakpoint pending. */ +#define CPUMCTX_DBG_DBGF_BP RT_BIT_32(CPUMCTX_DBG_DBGF_BP_BIT) +#define CPUMCTX_DBG_DBGF_BP_BIT (8 + CPUMX86EFLAGS_HW_BITS) +/** Mask of all DBGF indicators. */ +#define CPUMCTX_DBG_DBGF_MASK (CPUMCTX_DBG_DBGF_EVENT | CPUMCTX_DBG_DBGF_BP) +AssertCompile((CPUMCTX_DBG_HIT_DRX_MASK | CPUMCTX_DBG_DBGF_MASK) < UINT32_MAX); +/** @} */ + + + +/** + * 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 */ + uint64_t PkgCStateCfgCtrl; /**< MSR_PKG_CST_CONFIG_CONTROL */ + uint64_t SpecCtrl; /**< IA32_SPEC_CTRL */ + uint64_t ArchCaps; /**< IA32_ARCH_CAPABILITIES */ + } 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; + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_cpumctx_h */ + diff --git a/include/VBox/vmm/cpumdis.h b/include/VBox/vmm/cpumdis.h new file mode 100644 index 00000000..ee09e7b5 --- /dev/null +++ b/include/VBox/vmm/cpumdis.h @@ -0,0 +1,61 @@ +/** @file + * CPUM - Disassembler. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_cpumdis_h +#define VBOX_INCLUDED_vmm_cpumdis_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#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 /* !VBOX_INCLUDED_vmm_cpumdis_h */ + diff --git a/include/VBox/vmm/dbgf.h b/include/VBox/vmm/dbgf.h new file mode 100644 index 00000000..a961a3a5 --- /dev/null +++ b/include/VBox/vmm/dbgf.h @@ -0,0 +1,3192 @@ +/** @file + * DBGF - Debugger Facility. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_dbgf_h +#define VBOX_INCLUDED_vmm_dbgf_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#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 + * @ingroup grp_vmm + * @{ + */ + +/** @defgroup grp_dbgf_r0 The R0 DBGF API + * @{ + */ +VMMR0_INT_DECL(void) DBGFR0InitPerVMData(PGVM pGVM); +VMMR0_INT_DECL(void) DBGFR0CleanupVM(PGVM pGVM); + +/** + * Request buffer for DBGFR0TracerCreateReqHandler / VMMR0_DO_DBGF_TRACER_CREATE. + * @see DBGFR0TracerCreateReqHandler. + */ +typedef struct DBGFTRACERCREATEREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** Out: Where to return the address of the ring-3 tracer instance. */ + PDBGFTRACERINSR3 pTracerInsR3; + + /** Number of bytes for the shared event ring buffer. */ + uint32_t cbRingBuf; + + /** Set if the raw-mode component is desired. */ + bool fRCEnabled; + /** Explicit padding. */ + bool afReserved[3]; + +} DBGFTRACERCREATEREQ; +/** Pointer to a DBGFR0TracerCreate / VMMR0_DO_DBGF_TRACER_CREATE request buffer. */ +typedef DBGFTRACERCREATEREQ *PDBGFTRACERCREATEREQ; + +VMMR0_INT_DECL(int) DBGFR0TracerCreateReqHandler(PGVM pGVM, PDBGFTRACERCREATEREQ pReq); + +/** + * Request buffer for DBGFR0BpInitReqHandler / VMMR0_DO_DBGF_BP_INIT and + * DBGFR0BpPortIoInitReqHandler / VMMR0_DO_DBGF_BP_PORTIO_INIT. + * @see DBGFR0BpInitReqHandler, DBGFR0BpPortIoInitReqHandler. + */ +typedef struct DBGFBPINITREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** Out: Ring-3 pointer of the L1 lookup table on success. */ + R3PTRTYPE(volatile uint32_t *) paBpLocL1R3; +} DBGFBPINITREQ; +/** Pointer to a DBGFR0BpInitReqHandler / VMMR0_DO_DBGF_BP_INIT request buffer. */ +typedef DBGFBPINITREQ *PDBGFBPINITREQ; + +VMMR0_INT_DECL(int) DBGFR0BpInitReqHandler(PGVM pGVM, PDBGFBPINITREQ pReq); +VMMR0_INT_DECL(int) DBGFR0BpPortIoInitReqHandler(PGVM pGVM, PDBGFBPINITREQ pReq); + +/** + * Request buffer for DBGFR0BpOwnerInitReqHandler / VMMR0_DO_DBGF_BP_OWNER_INIT. + * @see DBGFR0BpOwnerInitReqHandler. + */ +typedef struct DBGFBPOWNERINITREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** Out: Ring-3 pointer of the breakpoint owner table on success. */ + R3PTRTYPE(void *) paBpOwnerR3; +} DBGFBPOWNERINITREQ; +/** Pointer to a DBGFR0BpOwnerInitReqHandler / VMMR0_DO_DBGF_BP_INIT request buffer. */ +typedef DBGFBPOWNERINITREQ *PDBGFBPOWNERINITREQ; + +VMMR0_INT_DECL(int) DBGFR0BpOwnerInitReqHandler(PGVM pGVM, PDBGFBPOWNERINITREQ pReq); + +/** + * Request buffer for DBGFR0BpChunkAllocReqHandler / VMMR0_DO_DBGF_CHUNK_ALLOC. + * @see DBGFR0BpChunkAllocReqHandler. + */ +typedef struct DBGFBPCHUNKALLOCREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** Out: Ring-3 pointer of the chunk base on success. */ + R3PTRTYPE(void *) pChunkBaseR3; + + /** The chunk ID to allocate. */ + uint32_t idChunk; +} DBGFBPCHUNKALLOCREQ; +/** Pointer to a DBGFR0BpChunkAllocReqHandler / VMMR0_DO_DBGF_CHUNK_ALLOC request buffer. */ +typedef DBGFBPCHUNKALLOCREQ *PDBGFBPCHUNKALLOCREQ; + +VMMR0_INT_DECL(int) DBGFR0BpChunkAllocReqHandler(PGVM pGVM, PDBGFBPCHUNKALLOCREQ pReq); + +/** + * Request buffer for DBGFR0BpL2TblChunkAllocReqHandler / VMMR0_DO_DBGF_L2_TBL_CHUNK_ALLOC. + * @see DBGFR0BpL2TblChunkAllocReqHandler. + */ +typedef struct DBGFBPL2TBLCHUNKALLOCREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** Out: Ring-3 pointer of the chunk base on success. */ + R3PTRTYPE(void *) pChunkBaseR3; + + /** The chunk ID to allocate. */ + uint32_t idChunk; +} DBGFBPL2TBLCHUNKALLOCREQ; +/** Pointer to a DBGFR0BpChunkAllocReqHandler / VMMR0_DO_DBGF_L2_TBL_CHUNK_ALLOC request buffer. */ +typedef DBGFBPL2TBLCHUNKALLOCREQ *PDBGFBPL2TBLCHUNKALLOCREQ; + +VMMR0_INT_DECL(int) DBGFR0BpL2TblChunkAllocReqHandler(PGVM pGVM, PDBGFBPL2TBLCHUNKALLOCREQ pReq); +/** @} */ + + +#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 ring-0 host address (internal use only). */ +#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) + +/** 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 any kind of far address. */ +#define DBGFADDRESS_IS_FAR(pAddress) ( ((pAddress)->fFlags & DBGFADDRESS_FLAGS_TYPE_MASK) <= DBGFADDRESS_FLAGS_FAR64 ) +/** Checks if the mixed address host context ring-0 (special). */ +#define DBGFADDRESS_IS_R0_HC(pAddress) ( ((pAddress)->fFlags & DBGFADDRESS_FLAGS_TYPE_MASK) == DBGFADDRESS_FLAGS_RING0 ) +/** Checks if the mixed address a virtual guest context address (incl HMA). */ +#define DBGFADDRESS_IS_VIRT_GC(pAddress) ( ((pAddress)->fFlags & DBGFADDRESS_FLAGS_TYPE_MASK) <= DBGFADDRESS_FLAGS_FLAT ) +/** Checks if the mixed address is valid. */ +#define DBGFADDRESS_IS_VALID(pAddress) RT_BOOL((pAddress)->fFlags & DBGFADDRESS_FLAGS_VALID) +/** @} */ + +VMMR3DECL(int) DBGFR3AddrFromSelOff(PUVM pUVM, VMCPUID idCpu, PDBGFADDRESS pAddress, RTSEL Sel, RTUINTPTR off); +VMMR3DECL(int) DBGFR3AddrFromSelInfoOff(PUVM pUVM, PDBGFADDRESS pAddress, PCDBGFSELINFO pSelInfo, RTUINTPTR off); +VMMR3DECL(PDBGFADDRESS) DBGFR3AddrFromFlat(PUVM pUVM, PDBGFADDRESS pAddress, RTGCUINTPTR FlatPtr); +VMMR3DECL(PDBGFADDRESS) DBGFR3AddrFromPhys(PUVM pUVM, PDBGFADDRESS pAddress, RTGCPHYS PhysAddr); +VMMR3_INT_DECL(PDBGFADDRESS) DBGFR3AddrFromHostR0(PDBGFADDRESS pAddress, RTR0UINTPTR R0Ptr); +VMMR3DECL(bool) DBGFR3AddrIsValid(PUVM pUVM, PCDBGFADDRESS pAddress); +VMMR3DECL(int) DBGFR3AddrToPhys(PUVM pUVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, PRTGCPHYS pGCPhys); +VMMR3DECL(int) DBGFR3AddrToHostPhys(PUVM pUVM, VMCPUID idCpu, PDBGFADDRESS pAddress, PRTHCPHYS pHCPhys); +VMMR3DECL(int) DBGFR3AddrToVolatileR3Ptr(PUVM pUVM, 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, + /** 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, + /** I/O port breakpoint. + * @todo not yet implemented. */ + DBGFEVENT_BREAKPOINT_IO, + /** MMIO breakpoint. + * @todo not yet implemented. */ + DBGFEVENT_BREAKPOINT_MMIO, + /** 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. + * @todo raw-mode: remove this + */ + 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 powering off. + * When this notification is received, the debugger thread should detach ASAP. + */ + DBGFEVENT_POWERING_OFF, + + /** Hardware Interrupt break. + * @todo not yet implemented. */ + DBGFEVENT_INTERRUPT_HARDWARE, + /** Software Interrupt break. + * @todo not yet implemented. */ + DBGFEVENT_INTERRUPT_SOFTWARE, + + /** The first selectable event. + * Whether the debugger wants or doesn't want these events can be configured + * via DBGFR3xxx and queried via DBGFR3yyy. */ + DBGFEVENT_FIRST_SELECTABLE, + /** Tripple fault. */ + DBGFEVENT_TRIPLE_FAULT = DBGFEVENT_FIRST_SELECTABLE, + + /** @name Exception events + * The exception events normally represents guest exceptions, but depending on + * the execution mode some virtualization exceptions may occure (no nested + * paging, raw-mode, ++). When necessary, we will request additional VM exits. + * @{ */ + DBGFEVENT_XCPT_FIRST, /**< The first exception event. */ + DBGFEVENT_XCPT_DE /**< 0x00 - \#DE - Fault - NoErr - Integer divide error (zero/overflow). */ + = DBGFEVENT_XCPT_FIRST, + DBGFEVENT_XCPT_DB, /**< 0x01 - \#DB - trap/fault - NoErr - debug event. */ + DBGFEVENT_XCPT_02, /**< 0x02 - Reserved for NMI, see interrupt events. */ + DBGFEVENT_XCPT_BP, /**< 0x03 - \#BP - Trap - NoErr - Breakpoint, INT 3 instruction. */ + DBGFEVENT_XCPT_OF, /**< 0x04 - \#OF - Trap - NoErr - Overflow, INTO instruction. */ + DBGFEVENT_XCPT_BR, /**< 0x05 - \#BR - Fault - NoErr - BOUND Range Exceeded, BOUND instruction. */ + DBGFEVENT_XCPT_UD, /**< 0x06 - \#UD - Fault - NoErr - Undefined(/Invalid) Opcode. */ + DBGFEVENT_XCPT_NM, /**< 0x07 - \#NM - Fault - NoErr - Device not available, FP or (F)WAIT instruction. */ + DBGFEVENT_XCPT_DF, /**< 0x08 - \#DF - Abort - Err=0 - Double fault. */ + DBGFEVENT_XCPT_09, /**< 0x09 - Int9 - Fault - NoErr - Coprocessor Segment Overrun (obsolete). */ + DBGFEVENT_XCPT_TS, /**< 0x0a - \#TS - Fault - ErrCd - Invalid TSS, Taskswitch or TSS access. */ + DBGFEVENT_XCPT_NP, /**< 0x0b - \#NP - Fault - ErrCd - Segment not present. */ + DBGFEVENT_XCPT_SS, /**< 0x0c - \#SS - Fault - ErrCd - Stack-Segment fault. */ + DBGFEVENT_XCPT_GP, /**< 0x0d - \#GP - Fault - ErrCd - General protection fault. */ + DBGFEVENT_XCPT_PF, /**< 0x0e - \#PF - Fault - ErrCd - Page fault. - interrupt gate!!! */ + DBGFEVENT_XCPT_0f, /**< 0x0f - Rsvd - Resvd - Resvd - Intel Reserved. */ + DBGFEVENT_XCPT_MF, /**< 0x10 - \#MF - Fault - NoErr - x86 FPU Floating-Point Error (Math fault), FP or (F)WAIT instruction. */ + DBGFEVENT_XCPT_AC, /**< 0x11 - \#AC - Fault - Err=0 - Alignment Check. */ + DBGFEVENT_XCPT_MC, /**< 0x12 - \#MC - Abort - NoErr - Machine Check. */ + DBGFEVENT_XCPT_XF, /**< 0x13 - \#XF - Fault - NoErr - SIMD Floating-Point Exception. */ + DBGFEVENT_XCPT_VE, /**< 0x14 - \#VE - Fault - Noerr - Virtualization exception. */ + DBGFEVENT_XCPT_15, /**< 0x15 - Intel Reserved. */ + DBGFEVENT_XCPT_16, /**< 0x16 - Intel Reserved. */ + DBGFEVENT_XCPT_17, /**< 0x17 - Intel Reserved. */ + DBGFEVENT_XCPT_18, /**< 0x18 - Intel Reserved. */ + DBGFEVENT_XCPT_19, /**< 0x19 - Intel Reserved. */ + DBGFEVENT_XCPT_1a, /**< 0x1a - Intel Reserved. */ + DBGFEVENT_XCPT_1b, /**< 0x1b - Intel Reserved. */ + DBGFEVENT_XCPT_1c, /**< 0x1c - Intel Reserved. */ + DBGFEVENT_XCPT_1d, /**< 0x1d - Intel Reserved. */ + DBGFEVENT_XCPT_SX, /**< 0x1e - \#SX - Fault - ErrCd - Security Exception. */ + DBGFEVENT_XCPT_1f, /**< 0x1f - Intel Reserved. */ + DBGFEVENT_XCPT_LAST /**< The last exception event. */ + = DBGFEVENT_XCPT_1f, + /** @} */ + + /** @name Instruction events + * The instruction events exerts all possible effort to intercept the + * relevant instructions. However, in some execution modes we won't be able + * to catch them. So it goes. + * @{ */ + DBGFEVENT_INSTR_FIRST, /**< The first VM instruction event. */ + DBGFEVENT_INSTR_HALT /**< Instruction: HALT */ + = DBGFEVENT_INSTR_FIRST, + DBGFEVENT_INSTR_MWAIT, /**< Instruction: MWAIT */ + DBGFEVENT_INSTR_MONITOR, /**< Instruction: MONITOR */ + DBGFEVENT_INSTR_CPUID, /**< Instruction: CPUID (missing stuff in raw-mode). */ + DBGFEVENT_INSTR_INVD, /**< Instruction: INVD */ + DBGFEVENT_INSTR_WBINVD, /**< Instruction: WBINVD */ + DBGFEVENT_INSTR_INVLPG, /**< Instruction: INVLPG */ + DBGFEVENT_INSTR_RDTSC, /**< Instruction: RDTSC */ + DBGFEVENT_INSTR_RDTSCP, /**< Instruction: RDTSCP */ + DBGFEVENT_INSTR_RDPMC, /**< Instruction: RDPMC */ + DBGFEVENT_INSTR_RDMSR, /**< Instruction: RDMSR */ + DBGFEVENT_INSTR_WRMSR, /**< Instruction: WRMSR */ + DBGFEVENT_INSTR_CRX_READ, /**< Instruction: CRx read instruction (missing smsw in raw-mode, and reads in general in VT-x). */ + DBGFEVENT_INSTR_CRX_WRITE, /**< Instruction: CRx write */ + DBGFEVENT_INSTR_DRX_READ, /**< Instruction: DRx read */ + DBGFEVENT_INSTR_DRX_WRITE, /**< Instruction: DRx write */ + DBGFEVENT_INSTR_PAUSE, /**< Instruction: PAUSE instruction (not in raw-mode). */ + DBGFEVENT_INSTR_XSETBV, /**< Instruction: XSETBV */ + DBGFEVENT_INSTR_SIDT, /**< Instruction: SIDT */ + DBGFEVENT_INSTR_LIDT, /**< Instruction: LIDT */ + DBGFEVENT_INSTR_SGDT, /**< Instruction: SGDT */ + DBGFEVENT_INSTR_LGDT, /**< Instruction: LGDT */ + DBGFEVENT_INSTR_SLDT, /**< Instruction: SLDT */ + DBGFEVENT_INSTR_LLDT, /**< Instruction: LLDT */ + DBGFEVENT_INSTR_STR, /**< Instruction: STR */ + DBGFEVENT_INSTR_LTR, /**< Instruction: LTR */ + DBGFEVENT_INSTR_GETSEC, /**< Instruction: GETSEC */ + DBGFEVENT_INSTR_RSM, /**< Instruction: RSM */ + DBGFEVENT_INSTR_RDRAND, /**< Instruction: RDRAND */ + DBGFEVENT_INSTR_RDSEED, /**< Instruction: RDSEED */ + DBGFEVENT_INSTR_XSAVES, /**< Instruction: XSAVES */ + DBGFEVENT_INSTR_XRSTORS, /**< Instruction: XRSTORS */ + DBGFEVENT_INSTR_VMM_CALL, /**< Instruction: VMCALL (intel) or VMMCALL (AMD) */ + DBGFEVENT_INSTR_LAST_COMMON /**< Instruction: the last common event. */ + = DBGFEVENT_INSTR_VMM_CALL, + DBGFEVENT_INSTR_VMX_FIRST, /**< Instruction: VT-x - First. */ + DBGFEVENT_INSTR_VMX_VMCLEAR /**< Instruction: VT-x VMCLEAR */ + = DBGFEVENT_INSTR_VMX_FIRST, + DBGFEVENT_INSTR_VMX_VMLAUNCH, /**< Instruction: VT-x VMLAUNCH */ + DBGFEVENT_INSTR_VMX_VMPTRLD, /**< Instruction: VT-x VMPTRLD */ + DBGFEVENT_INSTR_VMX_VMPTRST, /**< Instruction: VT-x VMPTRST */ + DBGFEVENT_INSTR_VMX_VMREAD, /**< Instruction: VT-x VMREAD */ + DBGFEVENT_INSTR_VMX_VMRESUME, /**< Instruction: VT-x VMRESUME */ + DBGFEVENT_INSTR_VMX_VMWRITE, /**< Instruction: VT-x VMWRITE */ + DBGFEVENT_INSTR_VMX_VMXOFF, /**< Instruction: VT-x VMXOFF */ + DBGFEVENT_INSTR_VMX_VMXON, /**< Instruction: VT-x VMXON */ + DBGFEVENT_INSTR_VMX_VMFUNC, /**< Instruction: VT-x VMFUNC */ + DBGFEVENT_INSTR_VMX_INVEPT, /**< Instruction: VT-x INVEPT */ + DBGFEVENT_INSTR_VMX_INVVPID, /**< Instruction: VT-x INVVPID */ + DBGFEVENT_INSTR_VMX_INVPCID, /**< Instruction: VT-x INVPCID */ + DBGFEVENT_INSTR_VMX_LAST /**< Instruction: VT-x - Last. */ + = DBGFEVENT_INSTR_VMX_INVPCID, + DBGFEVENT_INSTR_SVM_FIRST, /**< Instruction: AMD-V - first */ + DBGFEVENT_INSTR_SVM_VMRUN /**< Instruction: AMD-V VMRUN */ + = DBGFEVENT_INSTR_SVM_FIRST, + DBGFEVENT_INSTR_SVM_VMLOAD, /**< Instruction: AMD-V VMLOAD */ + DBGFEVENT_INSTR_SVM_VMSAVE, /**< Instruction: AMD-V VMSAVE */ + DBGFEVENT_INSTR_SVM_STGI, /**< Instruction: AMD-V STGI */ + DBGFEVENT_INSTR_SVM_CLGI, /**< Instruction: AMD-V CLGI */ + DBGFEVENT_INSTR_SVM_LAST /**< Instruction: The last ADM-V VM exit event. */ + = DBGFEVENT_INSTR_SVM_CLGI, + DBGFEVENT_INSTR_LAST /**< Instruction: The last instruction event. */ + = DBGFEVENT_INSTR_SVM_LAST, + /** @} */ + + + /** @name VM exit events. + * VM exits events for VT-x and AMD-V execution mode. Many of the VM exits + * behind these events are also directly translated into instruction events, but + * the difference here is that the exit events will not try provoke the exits. + * @{ */ + DBGFEVENT_EXIT_FIRST, /**< The first VM exit event. */ + DBGFEVENT_EXIT_TASK_SWITCH /**< Exit: Task switch. */ + = DBGFEVENT_EXIT_FIRST, + DBGFEVENT_EXIT_HALT, /**< Exit: HALT instruction. */ + DBGFEVENT_EXIT_MWAIT, /**< Exit: MWAIT instruction. */ + DBGFEVENT_EXIT_MONITOR, /**< Exit: MONITOR instruction. */ + DBGFEVENT_EXIT_CPUID, /**< Exit: CPUID instruction (missing stuff in raw-mode). */ + DBGFEVENT_EXIT_INVD, /**< Exit: INVD instruction. */ + DBGFEVENT_EXIT_WBINVD, /**< Exit: WBINVD instruction. */ + DBGFEVENT_EXIT_INVLPG, /**< Exit: INVLPG instruction. */ + DBGFEVENT_EXIT_RDTSC, /**< Exit: RDTSC instruction. */ + DBGFEVENT_EXIT_RDTSCP, /**< Exit: RDTSCP instruction. */ + DBGFEVENT_EXIT_RDPMC, /**< Exit: RDPMC instruction. */ + DBGFEVENT_EXIT_RDMSR, /**< Exit: RDMSR instruction. */ + DBGFEVENT_EXIT_WRMSR, /**< Exit: WRMSR instruction. */ + DBGFEVENT_EXIT_CRX_READ, /**< Exit: CRx read instruction (missing smsw in raw-mode, and reads in general in VT-x). */ + DBGFEVENT_EXIT_CRX_WRITE, /**< Exit: CRx write instruction. */ + DBGFEVENT_EXIT_DRX_READ, /**< Exit: DRx read instruction. */ + DBGFEVENT_EXIT_DRX_WRITE, /**< Exit: DRx write instruction. */ + DBGFEVENT_EXIT_PAUSE, /**< Exit: PAUSE instruction (not in raw-mode). */ + DBGFEVENT_EXIT_XSETBV, /**< Exit: XSETBV instruction. */ + DBGFEVENT_EXIT_SIDT, /**< Exit: SIDT instruction. */ + DBGFEVENT_EXIT_LIDT, /**< Exit: LIDT instruction. */ + DBGFEVENT_EXIT_SGDT, /**< Exit: SGDT instruction. */ + DBGFEVENT_EXIT_LGDT, /**< Exit: LGDT instruction. */ + DBGFEVENT_EXIT_SLDT, /**< Exit: SLDT instruction. */ + DBGFEVENT_EXIT_LLDT, /**< Exit: LLDT instruction. */ + DBGFEVENT_EXIT_STR, /**< Exit: STR instruction. */ + DBGFEVENT_EXIT_LTR, /**< Exit: LTR instruction. */ + DBGFEVENT_EXIT_GETSEC, /**< Exit: GETSEC instruction. */ + DBGFEVENT_EXIT_RSM, /**< Exit: RSM instruction. */ + DBGFEVENT_EXIT_RDRAND, /**< Exit: RDRAND instruction. */ + DBGFEVENT_EXIT_RDSEED, /**< Exit: RDSEED instruction. */ + DBGFEVENT_EXIT_XSAVES, /**< Exit: XSAVES instruction. */ + DBGFEVENT_EXIT_XRSTORS, /**< Exit: XRSTORS instruction. */ + DBGFEVENT_EXIT_VMM_CALL, /**< Exit: VMCALL (intel) or VMMCALL (AMD) instruction. */ + DBGFEVENT_EXIT_LAST_COMMON /**< Exit: the last common event. */ + = DBGFEVENT_EXIT_VMM_CALL, + DBGFEVENT_EXIT_VMX_FIRST, /**< Exit: VT-x - First. */ + DBGFEVENT_EXIT_VMX_VMCLEAR /**< Exit: VT-x VMCLEAR instruction. */ + = DBGFEVENT_EXIT_VMX_FIRST, + DBGFEVENT_EXIT_VMX_VMLAUNCH, /**< Exit: VT-x VMLAUNCH instruction. */ + DBGFEVENT_EXIT_VMX_VMPTRLD, /**< Exit: VT-x VMPTRLD instruction. */ + DBGFEVENT_EXIT_VMX_VMPTRST, /**< Exit: VT-x VMPTRST instruction. */ + DBGFEVENT_EXIT_VMX_VMREAD, /**< Exit: VT-x VMREAD instruction. */ + DBGFEVENT_EXIT_VMX_VMRESUME, /**< Exit: VT-x VMRESUME instruction. */ + DBGFEVENT_EXIT_VMX_VMWRITE, /**< Exit: VT-x VMWRITE instruction. */ + DBGFEVENT_EXIT_VMX_VMXOFF, /**< Exit: VT-x VMXOFF instruction. */ + DBGFEVENT_EXIT_VMX_VMXON, /**< Exit: VT-x VMXON instruction. */ + DBGFEVENT_EXIT_VMX_VMFUNC, /**< Exit: VT-x VMFUNC instruction. */ + DBGFEVENT_EXIT_VMX_INVEPT, /**< Exit: VT-x INVEPT instruction. */ + DBGFEVENT_EXIT_VMX_INVVPID, /**< Exit: VT-x INVVPID instruction. */ + DBGFEVENT_EXIT_VMX_INVPCID, /**< Exit: VT-x INVPCID instruction. */ + DBGFEVENT_EXIT_VMX_EPT_VIOLATION, /**< Exit: VT-x EPT violation. */ + DBGFEVENT_EXIT_VMX_EPT_MISCONFIG, /**< Exit: VT-x EPT misconfiguration. */ + DBGFEVENT_EXIT_VMX_VAPIC_ACCESS, /**< Exit: VT-x Virtual APIC page access. */ + DBGFEVENT_EXIT_VMX_VAPIC_WRITE, /**< Exit: VT-x Virtual APIC write. */ + DBGFEVENT_EXIT_VMX_LAST /**< Exit: VT-x - Last. */ + = DBGFEVENT_EXIT_VMX_VAPIC_WRITE, + DBGFEVENT_EXIT_SVM_FIRST, /**< Exit: AMD-V - first */ + DBGFEVENT_EXIT_SVM_VMRUN /**< Exit: AMD-V VMRUN instruction. */ + = DBGFEVENT_EXIT_SVM_FIRST, + DBGFEVENT_EXIT_SVM_VMLOAD, /**< Exit: AMD-V VMLOAD instruction. */ + DBGFEVENT_EXIT_SVM_VMSAVE, /**< Exit: AMD-V VMSAVE instruction. */ + DBGFEVENT_EXIT_SVM_STGI, /**< Exit: AMD-V STGI instruction. */ + DBGFEVENT_EXIT_SVM_CLGI, /**< Exit: AMD-V CLGI instruction. */ + DBGFEVENT_EXIT_SVM_LAST /**< Exit: The last ADM-V VM exit event. */ + = DBGFEVENT_EXIT_SVM_CLGI, + DBGFEVENT_EXIT_LAST /**< Exit: The last VM exit event. */ + = DBGFEVENT_EXIT_SVM_LAST, + /** @} */ + + + /** @name Misc VT-x and AMD-V execution events. + * @{ */ + DBGFEVENT_VMX_SPLIT_LOCK, /**< VT-x: Split-lock \#AC triggered by host having detection enabled. */ + /** @} */ + + + /** Access to an unassigned I/O port. + * @todo not yet implemented. */ + DBGFEVENT_IOPORT_UNASSIGNED, + /** Access to an unused I/O port on a device. + * @todo not yet implemented. */ + DBGFEVENT_IOPORT_UNUSED, + /** Unassigned memory event. + * @todo not yet implemented. */ + DBGFEVENT_MEMORY_UNASSIGNED, + /** Attempt to write to unshadowed ROM. + * @todo not yet implemented. */ + DBGFEVENT_MEMORY_ROM_WRITE, + + /** Windows guest reported BSOD via hyperv MSRs. */ + DBGFEVENT_BSOD_MSR, + /** Windows guest reported BSOD via EFI variables. */ + DBGFEVENT_BSOD_EFI, + /** Windows guest reported BSOD via VMMDev. */ + DBGFEVENT_BSOD_VMMDEV, + + /** End of valid event values. */ + DBGFEVENT_END, + /** The usual 32-bit hack. */ + DBGFEVENT_32BIT_HACK = 0x7fffffff +} DBGFEVENTTYPE; +AssertCompile(DBGFEVENT_XCPT_LAST - DBGFEVENT_XCPT_FIRST == 0x1f); + +/** + * 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_HM, + /** 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; + /** The vCPU/EMT which generated the event. */ + VMCPUID idCpu; + /** Reserved. */ + uint32_t uReserved; + /** 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 handle of the breakpoint which was hit. */ + DBGFBP hBp; + } Bp; + + /** Generic debug event. */ + struct DBGFEVENTGENERIC + { + /** Number of arguments. */ + uint8_t cArgs; + /** Alignment padding. */ + uint8_t uPadding[7]; + /** Arguments. */ + uint64_t auArgs[5]; + } Generic; + + /** Padding for ensuring that the structure is 8 byte aligned. */ + uint64_t au64Padding[6]; + } u; +} DBGFEVENT; +AssertCompileSizeAlignment(DBGFEVENT, 8); +AssertCompileSize(DBGFEVENT, 64); +/** 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 The cross context VM structure. + */ +# ifdef VBOX_STRICT +# define DBGFSTOP(pVM) DBGFR3EventSrc(pVM, DBGFEVENT_DEV_STOP, __FILE__, __LINE__, __PRETTY_FUNCTION__, NULL) +# else +# define DBGFSTOP(pVM) VINF_SUCCESS +# endif + +VMMR3_INT_DECL(int) DBGFR3Init(PVM pVM); +VMMR3_INT_DECL(int) DBGFR3Term(PVM pVM); +VMMR3DECL(void) DBGFR3TermUVM(PUVM pUVM); +VMMR3_INT_DECL(void) DBGFR3PowerOff(PVM pVM); +VMMR3_INT_DECL(void) DBGFR3Relocate(PVM pVM, RTGCINTPTR offDelta); + +VMMR3_INT_DECL(int) DBGFR3VMMForcedAction(PVM pVM, PVMCPU pVCpu); +VMMR3_INT_DECL(VBOXSTRICTRC) DBGFR3EventHandlePending(PVM pVM, PVMCPU pVCpu); +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, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(6, 7); +VMMR3DECL(int) DBGFR3EventSrcV(PVM pVM, DBGFEVENTTYPE enmEvent, const char *pszFile, unsigned uLine, + const char *pszFunction, const char *pszFormat, va_list args) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(6, 0); +VMMR3_INT_DECL(int) DBGFR3EventAssertion(PVM pVM, DBGFEVENTTYPE enmEvent, const char *pszMsg1, const char *pszMsg2); +VMMR3_INT_DECL(int) DBGFR3EventBreakpoint(PVM pVM, DBGFEVENTTYPE enmEvent); + +VMMR3_INT_DECL(int) DBGFR3PrgStep(PVMCPU pVCpu); + +VMMR3DECL(int) DBGFR3Attach(PUVM pUVM); +VMMR3DECL(int) DBGFR3Detach(PUVM pUVM); +VMMR3DECL(int) DBGFR3EventWait(PUVM pUVM, RTMSINTERVAL cMillies, PDBGFEVENT pEvent); +VMMR3DECL(int) DBGFR3Halt(PUVM pUVM, VMCPUID idCpu); +VMMR3DECL(bool) DBGFR3IsHalted(PUVM pUVM, VMCPUID idCpu); +VMMR3DECL(int) DBGFR3QueryWaitable(PUVM pUVM); +VMMR3DECL(int) DBGFR3Resume(PUVM pUVM, VMCPUID idCpu); +VMMR3DECL(int) DBGFR3InjectNMI(PUVM pUVM, VMCPUID idCpu); +VMMR3DECL(int) DBGFR3Step(PUVM pUVM, VMCPUID idCpu); +VMMR3DECL(int) DBGFR3StepEx(PUVM pUVM, VMCPUID idCpu, uint32_t fFlags, PCDBGFADDRESS pStopPcAddr, + PCDBGFADDRESS pStopPopAddr, RTGCUINTPTR cbStopPop, uint32_t cMaxSteps); + +/** @name DBGF_STEP_F_XXX - Flags for DBGFR3StepEx. + * + * @note The stop filters are not applied to the starting instruction. + * + * @{ */ +/** Step into CALL, INT, SYSCALL and SYSENTER instructions. */ +#define DBGF_STEP_F_INTO RT_BIT_32(0) +/** Step over CALL, INT, SYSCALL and SYSENTER instruction when considering + * what's "next". */ +#define DBGF_STEP_F_OVER RT_BIT_32(1) + +/** Stop on the next CALL, INT, SYSCALL, SYSENTER instruction. */ +#define DBGF_STEP_F_STOP_ON_CALL RT_BIT_32(8) +/** Stop on the next RET, IRET, SYSRET, SYSEXIT instruction. */ +#define DBGF_STEP_F_STOP_ON_RET RT_BIT_32(9) +/** Stop after the next RET, IRET, SYSRET, SYSEXIT instruction. */ +#define DBGF_STEP_F_STOP_AFTER_RET RT_BIT_32(10) +/** Stop on the given address. + * The comparison will be made using effective (flat) addresses. */ +#define DBGF_STEP_F_STOP_ON_ADDRESS RT_BIT_32(11) +/** Stop when the stack pointer pops to or past the given address. + * The comparison will be made using effective (flat) addresses. */ +#define DBGF_STEP_F_STOP_ON_STACK_POP RT_BIT_32(12) +/** Mask of stop filter flags. */ +#define DBGF_STEP_F_STOP_FILTER_MASK UINT32_C(0x00001f00) + +/** Mask of valid flags. */ +#define DBGF_STEP_F_VALID_MASK UINT32_C(0x00001f03) +/** @} */ + +/** + * Event configuration array element, see DBGFR3EventConfigEx. + */ +typedef struct DBGFEVENTCONFIG +{ + /** The event to configure */ + DBGFEVENTTYPE enmType; + /** The new state. */ + bool fEnabled; + /** Unused. */ + uint8_t abUnused[3]; +} DBGFEVENTCONFIG; +/** Pointer to an event config. */ +typedef DBGFEVENTCONFIG *PDBGFEVENTCONFIG; +/** Pointer to a const event config. */ +typedef const DBGFEVENTCONFIG *PCDBGFEVENTCONFIG; + +VMMR3DECL(int) DBGFR3EventConfigEx(PUVM pUVM, PCDBGFEVENTCONFIG paConfigs, size_t cConfigs); +VMMR3DECL(int) DBGFR3EventConfig(PUVM pUVM, DBGFEVENTTYPE enmEvent, bool fEnabled); +VMMR3DECL(bool) DBGFR3EventIsEnabled(PUVM pUVM, DBGFEVENTTYPE enmEvent); +VMMR3DECL(int) DBGFR3EventQuery(PUVM pUVM, PDBGFEVENTCONFIG paConfigs, size_t cConfigs); + +/** @name DBGFINTERRUPTSTATE_XXX - interrupt break state. + * @{ */ +#define DBGFINTERRUPTSTATE_DISABLED 0 +#define DBGFINTERRUPTSTATE_ENABLED 1 +#define DBGFINTERRUPTSTATE_DONT_TOUCH 2 +/** @} */ + +/** + * Interrupt break state configuration entry. + */ +typedef struct DBGFINTERRUPTCONFIG +{ + /** The interrupt number. */ + uint8_t iInterrupt; + /** The hardware interrupt state (DBGFINTERRUPTSTATE_XXX). */ + uint8_t enmHardState; + /** The software interrupt state (DBGFINTERRUPTSTATE_XXX). */ + uint8_t enmSoftState; +} DBGFINTERRUPTCONFIG; +/** Pointer to an interrupt break state config entyr. */ +typedef DBGFINTERRUPTCONFIG *PDBGFINTERRUPTCONFIG; +/** Pointer to a const interrupt break state config entyr. */ +typedef DBGFINTERRUPTCONFIG const *PCDBGFINTERRUPTCONFIG; + +VMMR3DECL(int) DBGFR3InterruptConfigEx(PUVM pUVM, PCDBGFINTERRUPTCONFIG paConfigs, size_t cConfigs); +VMMR3DECL(int) DBGFR3InterruptHardwareConfig(PUVM pUVM, uint8_t iInterrupt, bool fEnabled); +VMMR3DECL(int) DBGFR3InterruptSoftwareConfig(PUVM pUVM, uint8_t iInterrupt, bool fEnabled); +VMMR3DECL(int) DBGFR3InterruptHardwareIsEnabled(PUVM pUVM, uint8_t iInterrupt); +VMMR3DECL(int) DBGFR3InterruptSoftwareIsEnabled(PUVM pUVM, uint8_t iInterrupt); + +#endif /* IN_RING3 */ + +/** @def DBGF_IS_EVENT_ENABLED + * Checks if a selectable debug event is enabled or not (fast). + * + * @returns true/false. + * @param a_pVM Pointer to the cross context VM structure. + * @param a_enmEvent The selectable event to check. + * @remarks Only for use internally in the VMM. Use DBGFR3EventIsEnabled elsewhere. + */ +#if defined(VBOX_STRICT) && defined(RT_COMPILER_SUPPORTS_LAMBDA) +# define DBGF_IS_EVENT_ENABLED(a_pVM, a_enmEvent) \ + ([](PVM a_pLambdaVM, DBGFEVENTTYPE a_enmLambdaEvent) -> bool { \ + Assert( a_enmLambdaEvent >= DBGFEVENT_FIRST_SELECTABLE \ + || a_enmLambdaEvent == DBGFEVENT_INTERRUPT_HARDWARE \ + || a_enmLambdaEvent == DBGFEVENT_INTERRUPT_SOFTWARE); \ + Assert(a_enmLambdaEvent < DBGFEVENT_END); \ + return ASMBitTest(&a_pLambdaVM->dbgf.ro.bmSelectedEvents, a_enmLambdaEvent); \ + }(a_pVM, a_enmEvent)) +#elif defined(VBOX_STRICT) && defined(__GNUC__) +# define DBGF_IS_EVENT_ENABLED(a_pVM, a_enmEvent) \ + __extension__ ({ \ + Assert( (a_enmEvent) >= DBGFEVENT_FIRST_SELECTABLE \ + || (a_enmEvent) == DBGFEVENT_INTERRUPT_HARDWARE \ + || (a_enmEvent) == DBGFEVENT_INTERRUPT_SOFTWARE); \ + Assert((a_enmEvent) < DBGFEVENT_END); \ + ASMBitTest(&(a_pVM)->dbgf.ro.bmSelectedEvents, (a_enmEvent)); \ + }) +#else +# define DBGF_IS_EVENT_ENABLED(a_pVM, a_enmEvent) \ + ASMBitTest(&(a_pVM)->dbgf.ro.bmSelectedEvents, (a_enmEvent)) +#endif + + +/** @def DBGF_IS_HARDWARE_INT_ENABLED + * Checks if hardware interrupt interception is enabled or not for an interrupt. + * + * @returns true/false. + * @param a_pVM Pointer to the cross context VM structure. + * @param a_iInterrupt Interrupt to check. + * @remarks Only for use internally in the VMM. Use + * DBGFR3InterruptHardwareIsEnabled elsewhere. + */ +#define DBGF_IS_HARDWARE_INT_ENABLED(a_pVM, a_iInterrupt) \ + ASMBitTest(&(a_pVM)->dbgf.ro.bmHardIntBreakpoints, (uint8_t)(a_iInterrupt)) + +/** @def DBGF_IS_SOFTWARE_INT_ENABLED + * Checks if software interrupt interception is enabled or not for an interrupt. + * + * @returns true/false. + * @param a_pVM Pointer to the cross context VM structure. + * @param a_iInterrupt Interrupt to check. + * @remarks Only for use internally in the VMM. Use + * DBGFR3InterruptSoftwareIsEnabled elsewhere. + */ +#define DBGF_IS_SOFTWARE_INT_ENABLED(a_pVM, a_iInterrupt) \ + ASMBitTest(&(a_pVM)->dbgf.ro.bmSoftIntBreakpoints, (uint8_t)(a_iInterrupt)) + + + +/** Breakpoint type. */ +typedef enum DBGFBPTYPE +{ + /** Invalid breakpoint type. */ + DBGFBPTYPE_INVALID = 0, + /** Debug register. */ + DBGFBPTYPE_REG, + /** INT 3 instruction. */ + DBGFBPTYPE_INT3, + /** Port I/O breakpoint. */ + DBGFBPTYPE_PORT_IO, + /** Memory mapped I/O breakpoint. */ + DBGFBPTYPE_MMIO, + /** ensure 32-bit size. */ + DBGFBPTYPE_32BIT_HACK = 0x7fffffff +} DBGFBPTYPE; + + +/** @name DBGFBPIOACCESS_XXX - I/O (port + mmio) access types. + * @{ */ +/** Byte sized read accesses. */ +#define DBGFBPIOACCESS_READ_BYTE UINT32_C(0x00000001) +/** Word sized accesses. */ +#define DBGFBPIOACCESS_READ_WORD UINT32_C(0x00000002) +/** Double word sized accesses. */ +#define DBGFBPIOACCESS_READ_DWORD UINT32_C(0x00000004) +/** Quad word sized accesses - not available for I/O ports. */ +#define DBGFBPIOACCESS_READ_QWORD UINT32_C(0x00000008) +/** Other sized accesses - not available for I/O ports. */ +#define DBGFBPIOACCESS_READ_OTHER UINT32_C(0x00000010) +/** Read mask. */ +#define DBGFBPIOACCESS_READ_MASK UINT32_C(0x0000001f) + +/** Byte sized write accesses. */ +#define DBGFBPIOACCESS_WRITE_BYTE UINT32_C(0x00000100) +/** Word sized write accesses. */ +#define DBGFBPIOACCESS_WRITE_WORD UINT32_C(0x00000200) +/** Double word sized write accesses. */ +#define DBGFBPIOACCESS_WRITE_DWORD UINT32_C(0x00000400) +/** Quad word sized write accesses - not available for I/O ports. */ +#define DBGFBPIOACCESS_WRITE_QWORD UINT32_C(0x00000800) +/** Other sized write accesses - not available for I/O ports. */ +#define DBGFBPIOACCESS_WRITE_OTHER UINT32_C(0x00001000) +/** Write mask. */ +#define DBGFBPIOACCESS_WRITE_MASK UINT32_C(0x00001f00) + +/** All kind of access (read, write, all sizes). */ +#define DBGFBPIOACCESS_ALL UINT32_C(0x00001f1f) +/** All kind of access for MMIO (read, write, all sizes). */ +#define DBGFBPIOACCESS_ALL_MMIO DBGFBPIOACCESS_ALL +/** All kind of access (read, write, all sizes). */ +#define DBGFBPIOACCESS_ALL_PORT_IO UINT32_C(0x00000303) + +/** The acceptable mask for I/O ports. */ +#define DBGFBPIOACCESS_VALID_MASK_PORT_IO UINT32_C(0x00000303) +/** The acceptable mask for MMIO. */ +#define DBGFBPIOACCESS_VALID_MASK_MMIO UINT32_C(0x00001f1f) +/** @} */ + +/** + * The visible breakpoint state (read-only). + */ +typedef struct DBGFBPPUB +{ + /** 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 breakpoint owner handle (a nil owner defers the breakpoint to the + * debugger). */ + DBGFBPOWNER hOwner; + /** Breakpoint type stored as a 16bit integer to stay within size limits. */ + uint16_t u16Type; + /** Breakpoint flags. */ + uint16_t fFlags; + + /** Union of type specific data. */ + union + { + /** The flat GC address breakpoint address for REG and INT3 breakpoints. */ + RTGCUINTPTR GCPtr; + + /** Debug register data. */ + struct DBGFBPREG + { + /** The flat GC address of the breakpoint. */ + RTGCUINTPTR GCPtr; + /** 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; + + /** INT3 breakpoint data. */ + struct DBGFBPINT3 + { + /** The flat GC address of the breakpoint. */ + RTGCUINTPTR GCPtr; + /** The physical address of the breakpoint. */ + RTGCPHYS PhysAddr; + /** The byte value we replaced by the INT 3 instruction. */ + uint8_t bOrg; + } Int3; + + /** I/O port breakpoint data. */ + struct DBGFBPPORTIO + { + /** The first port. */ + RTIOPORT uPort; + /** The number of ports. */ + RTIOPORT cPorts; + /** Valid DBGFBPIOACCESS_XXX selection, max DWORD size. */ + uint32_t fAccess; + } PortIo; + + /** Memory mapped I/O breakpoint data. */ + struct DBGFBPMMIO + { + /** The first MMIO address. */ + RTGCPHYS PhysAddr; + /** The size of the MMIO range in bytes. */ + uint32_t cb; + /** Valid DBGFBPIOACCESS_XXX selection, max QWORD size. */ + uint32_t fAccess; + } Mmio; + + /** Padding to the anticipated size. */ + uint64_t u64Padding[3]; + } u; +} DBGFBPPUB; +AssertCompileSize(DBGFBPPUB, 64 - 8); +AssertCompileMembersAtSameOffset(DBGFBPPUB, u.GCPtr, DBGFBPPUB, u.Reg.GCPtr); +AssertCompileMembersAtSameOffset(DBGFBPPUB, u.GCPtr, DBGFBPPUB, u.Int3.GCPtr); + +/** Pointer to the visible breakpoint state. */ +typedef DBGFBPPUB *PDBGFBPPUB; +/** Pointer to a const visible breakpoint state. */ +typedef const DBGFBPPUB *PCDBGFBPPUB; + +/** Sets the DBGFPUB::u16Type member. */ +#define DBGF_BP_PUB_MAKE_TYPE(a_enmType) ((uint16_t)(a_enmType)) +/** Returns the type of the DBGFPUB::u16Type member. */ +#define DBGF_BP_PUB_GET_TYPE(a_pBp) ((DBGFBPTYPE)((a_pBp)->u16Type)) +/** Returns the enabled status of DBGFPUB::fFlags member. */ +#define DBGF_BP_PUB_IS_ENABLED(a_pBp) RT_BOOL((a_pBp)->fFlags & DBGF_BP_F_ENABLED) +/** Returns whether DBGF_BP_F_HIT_EXEC_BEFORE is set for DBGFPUB::fFlags. */ +#define DBGF_BP_PUB_IS_EXEC_BEFORE(a_pBp) RT_BOOL((a_pBp)->fFlags & DBGF_BP_F_HIT_EXEC_BEFORE) +/** Returns whether DBGF_BP_F_HIT_EXEC_AFTER is set for DBGFPUB::fFlags. */ +#define DBGF_BP_PUB_IS_EXEC_AFTER(a_pBp) RT_BOOL((a_pBp)->fFlags & DBGF_BP_F_HIT_EXEC_AFTER) + + +/** @name Possible DBGFBPPUB::fFlags flags. + * @{ */ +/** Default flags, breakpoint is enabled and hits before the instruction is executed. */ +#define DBGF_BP_F_DEFAULT (DBGF_BP_F_ENABLED | DBGF_BP_F_HIT_EXEC_BEFORE) +/** Flag whether the breakpoint is enabled currently. */ +#define DBGF_BP_F_ENABLED RT_BIT(0) +/** Flag indicating whether the action assoicated with the breakpoint should be carried out + * before the instruction causing the breakpoint to hit was executed. */ +#define DBGF_BP_F_HIT_EXEC_BEFORE RT_BIT(1) +/** Flag indicating whether the action assoicated with the breakpoint should be carried out + * after the instruction causing the breakpoint to hit was executed. */ +#define DBGF_BP_F_HIT_EXEC_AFTER RT_BIT(2) +/** The acceptable flags mask. */ +#define DBGF_BP_F_VALID_MASK UINT32_C(0x00000007) +/** @} */ + + +/** + * Breakpoint hit handler. + * + * @returns Strict VBox status code. + * @retval VINF_SUCCESS if the breakpoint was handled and guest execution can resume. + * @retval VINF_DBGF_BP_HALT if guest execution should be stopped and the debugger should be invoked. + * @retval VINF_DBGF_R3_BP_OWNER_DEFER return to ring-3 and invoke the owner callback there again. + * + * @param pVM The cross-context VM structure pointer. + * @param idCpu ID of the vCPU triggering the breakpoint. + * @param pvUserBp User argument of the set breakpoint. + * @param hBp The breakpoint handle. + * @param pBpPub Pointer to the readonly public state of the breakpoint. + * @param fFlags Flags indicating when the handler was called (DBGF_BP_F_HIT_EXEC_BEFORE vs DBGF_BP_F_HIT_EXEC_AFTER). + * + * @remarks The handler is called on the EMT of vCPU triggering the breakpoint and no locks are held. + * @remarks Any status code returned other than the ones mentioned will send the VM straight into a + * guru meditation. + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNDBGFBPHIT,(PVM pVM, VMCPUID idCpu, void *pvUserBp, DBGFBP hBp, PCDBGFBPPUB pBpPub, + uint16_t fFlags)); +/** Pointer to a FNDBGFBPHIT(). */ +typedef FNDBGFBPHIT *PFNDBGFBPHIT; + + +/** + * I/O breakpoint hit handler. + * + * @returns Strict VBox status code. + * @retval VINF_SUCCESS if the breakpoint was handled and guest execution can resume. + * @retval VINF_DBGF_BP_HALT if guest execution should be stopped and the debugger should be invoked. + * @retval VINF_DBGF_R3_BP_OWNER_DEFER return to ring-3 and invoke the owner callback there again. + * + * @param pVM The cross-context VM structure pointer. + * @param idCpu ID of the vCPU triggering the breakpoint. + * @param pvUserBp User argument of the set breakpoint. + * @param hBp The breakpoint handle. + * @param pBpPub Pointer to the readonly public state of the breakpoint. + * @param fFlags Flags indicating when the handler was called (DBGF_BP_F_HIT_EXEC_BEFORE vs DBGF_BP_F_HIT_EXEC_AFTER). + * @param fAccess Access flags, see DBGFBPIOACCESS_XXX. + * @param uAddr The address of the access, for port I/O this will hold the port number. + * @param uValue The value read or written (the value for reads is only valid when DBGF_BP_F_HIT_EXEC_AFTER is set). + * + * @remarks The handler is called on the EMT of vCPU triggering the breakpoint and no locks are held. + * @remarks Any status code returned other than the ones mentioned will send the VM straight into a + * guru meditation. + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNDBGFBPIOHIT,(PVM pVM, VMCPUID idCpu, void *pvUserBp, DBGFBP hBp, PCDBGFBPPUB pBpPub, + uint16_t fFlags, uint32_t fAccess, uint64_t uAddr, uint64_t uValue)); +/** Pointer to a FNDBGFBPIOHIT(). */ +typedef FNDBGFBPIOHIT *PFNDBGFBPIOHIT; + + +#ifdef IN_RING3 +/** @defgroup grp_dbgf_bp_r3 The DBGF Breakpoint Host Context Ring-3 API + * @{ */ +VMMR3DECL(int) DBGFR3BpOwnerCreate(PUVM pUVM, PFNDBGFBPHIT pfnBpHit, PFNDBGFBPIOHIT pfnBpIoHit, PDBGFBPOWNER phBpOwner); +VMMR3DECL(int) DBGFR3BpOwnerDestroy(PUVM pUVM, DBGFBPOWNER hBpOwner); + +VMMR3DECL(int) DBGFR3BpSetInt3(PUVM pUVM, VMCPUID idSrcCpu, PCDBGFADDRESS pAddress, + uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp); +VMMR3DECL(int) DBGFR3BpSetInt3Ex(PUVM pUVM, DBGFBPOWNER hOwner, void *pvUser, + VMCPUID idSrcCpu, PCDBGFADDRESS pAddress, uint16_t fFlags, + uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp); +VMMR3DECL(int) DBGFR3BpSetReg(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, + uint64_t iHitDisable, uint8_t fType, uint8_t cb, PDBGFBP phBp); +VMMR3DECL(int) DBGFR3BpSetRegEx(PUVM pUVM, DBGFBPOWNER hOwner, void *pvUser, + PCDBGFADDRESS pAddress, uint16_t fFlags, + uint64_t iHitTrigger, uint64_t iHitDisable, + uint8_t fType, uint8_t cb, PDBGFBP phBp); +VMMR3DECL(int) DBGFR3BpSetREM(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, + uint64_t iHitDisable, PDBGFBP phBp); +VMMR3DECL(int) DBGFR3BpSetPortIo(PUVM pUVM, RTIOPORT uPort, RTIOPORT cPorts, uint32_t fAccess, + uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp); +VMMR3DECL(int) DBGFR3BpSetPortIoEx(PUVM pUVM, DBGFBPOWNER hOwner, void *pvUser, + RTIOPORT uPort, RTIOPORT cPorts, uint32_t fAccess, + uint32_t fFlags, uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp); +VMMR3DECL(int) DBGFR3BpSetMmio(PUVM pUVM, RTGCPHYS GCPhys, uint32_t cb, uint32_t fAccess, + uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp); +VMMR3DECL(int) DBGFR3BpSetMmioEx(PUVM pUVM, DBGFBPOWNER hOwner, void *pvUser, + RTGCPHYS GCPhys, uint32_t cb, uint32_t fAccess, + uint32_t fFlags, uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp); +VMMR3DECL(int) DBGFR3BpClear(PUVM pUVM, DBGFBP hBp); +VMMR3DECL(int) DBGFR3BpEnable(PUVM pUVM, DBGFBP hBp); +VMMR3DECL(int) DBGFR3BpDisable(PUVM pUVM, DBGFBP hBp); + +/** + * Breakpoint enumeration callback function. + * + * @returns VBox status code. + * The enumeration stops on failure status and VINF_CALLBACK_RETURN. + * @param pUVM The user mode VM handle. + * @param pvUser The user argument. + * @param hBp The breakpoint handle. + * @param pBpPub Pointer to the public breakpoint information. (readonly) + */ +typedef DECLCALLBACKTYPE(int, FNDBGFBPENUM,(PUVM pUVM, void *pvUser, DBGFBP hBp, PCDBGFBPPUB pBpPub)); +/** Pointer to a breakpoint enumeration callback function. */ +typedef FNDBGFBPENUM *PFNDBGFBPENUM; + +VMMR3DECL(int) DBGFR3BpEnum(PUVM pUVM, PFNDBGFBPENUM pfnCallback, void *pvUser); + +VMMR3_INT_DECL(int) DBGFR3BpHit(PVM pVM, PVMCPU pVCpu); +/** @} */ +#endif /* !IN_RING3 */ + + +#if defined(IN_RING0) || defined(DOXYGEN_RUNNING) +/** @defgroup grp_dbgf_bp_r0 The DBGF Breakpoint Host Context Ring-0 API + * @{ */ +VMMR0_INT_DECL(int) DBGFR0BpOwnerSetUpContext(PGVM pGVM, DBGFBPOWNER hBpOwner, PFNDBGFBPHIT pfnBpHit, PFNDBGFBPIOHIT pfnBpIoHit); +VMMR0_INT_DECL(int) DBGFR0BpOwnerDestroyContext(PGVM pGVM, DBGFBPOWNER hBpOwner); + +VMMR0_INT_DECL(int) DBGFR0BpSetUpContext(PGVM pGVM, DBGFBP hBp, void *pvUser); +VMMR0_INT_DECL(int) DBGFR0BpDestroyContext(PGVM pGVM, DBGFBP hBp); +/** @} */ +#endif /* IN_RING0 || DOXYGEN_RUNNING */ + +VMM_INT_DECL(RTGCUINTREG) DBGFBpGetDR7(PVM pVM); +VMM_INT_DECL(RTGCUINTREG) DBGFBpGetDR0(PVM pVM); +VMM_INT_DECL(RTGCUINTREG) DBGFBpGetDR1(PVM pVM); +VMM_INT_DECL(RTGCUINTREG) DBGFBpGetDR2(PVM pVM); +VMM_INT_DECL(RTGCUINTREG) DBGFBpGetDR3(PVM pVM); +VMM_INT_DECL(bool) DBGFBpIsHwArmed(PVM pVM); +VMM_INT_DECL(bool) DBGFBpIsHwIoArmed(PVM pVM); +VMM_INT_DECL(bool) DBGFBpIsInt3Armed(PVM pVM); +VMM_INT_DECL(bool) DBGFIsStepping(PVMCPU pVCpu); +VMM_INT_DECL(VBOXSTRICTRC) DBGFBpCheckInstruction(PVMCC pVM, PVMCPUCC pVCpu, RTGCPTR GCPtrPC); +VMM_INT_DECL(VBOXSTRICTRC) DBGFBpCheckIo(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, RTIOPORT uIoPort, uint8_t cbValue); +VMM_INT_DECL(uint32_t) DBGFBpCheckIo2(PVMCC pVM, PVMCPUCC pVCpu, RTIOPORT uIoPort, uint8_t cbValue); +VMM_INT_DECL(VBOXSTRICTRC) DBGFBpCheckPortIo(PVMCC pVM, PVMCPU pVCpu, RTIOPORT uIoPort, + uint32_t fAccess, uint32_t uValue, bool fBefore); +VMM_INT_DECL(VBOXSTRICTRC) DBGFEventGenericWithArgs(PVM pVM, PVMCPU pVCpu, DBGFEVENTTYPE enmEvent, DBGFEVENTCTX enmCtx, + unsigned cArgs, ...); +VMM_INT_DECL(int) DBGFTrap01Handler(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, RTGCUINTREG uDr6, bool fAltStepping); +VMM_INT_DECL(VBOXSTRICTRC) DBGFTrap03Handler(PVMCC pVM, PVMCPUCC pVCpu, PCPUMCTX pCtx); + + +#ifdef IN_RING3 /* The CPU mode API only works in ring-3. */ +VMMR3DECL(CPUMMODE) DBGFR3CpuGetMode(PUVM pUVM, VMCPUID idCpu); +VMMR3DECL(VMCPUID) DBGFR3CpuGetCount(PUVM pUVM); +VMMR3DECL(bool) DBGFR3CpuIsIn64BitCode(PUVM pUVM, VMCPUID idCpu); +VMMR3DECL(bool) DBGFR3CpuIsInV86Code(PUVM pUVM, VMCPUID idCpu); +VMMR3DECL(const char *) DBGFR3CpuGetState(PUVM pUVM, VMCPUID idCpu); +#endif + + + +#ifdef IN_RING3 /* The info callbacks API only works in ring-3. */ + +struct RTGETOPTSTATE; +union RTGETOPTUNION; + +/** + * 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, ...)) RT_IPRT_FORMAT_ATTR(2, 3); + + /** + * 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)) RT_IPRT_FORMAT_ATTR(2, 0); + + /** + * Report getopt parsing trouble + * + * @param pHlp Pointer to this structure. + * @param rc The RTGetOpt return value. + * @param pValueUnion The value union. + * @param pState The getopt state. + */ + DECLCALLBACKMEMBER(void, pfnGetOptError,(PCDBGFINFOHLP pHlp, int rc, union RTGETOPTUNION *pValueUnion, + struct RTGETOPTSTATE *pState)); +} 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 DECLCALLBACKTYPE(void, FNDBGFHANDLERDEV,(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)); +/** Pointer to a FNDBGFHANDLERDEV function. */ +typedef FNDBGFHANDLERDEV *PFNDBGFHANDLERDEV; + +/** + * 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 DECLCALLBACKTYPE(void, FNDBGFHANDLERDRV,(PPDMDRVINS pDrvIns, PCDBGFINFOHLP pHlp, const char *pszArgs)); +/** Pointer to a FNDBGFHANDLERDRV function. */ +typedef FNDBGFHANDLERDRV *PFNDBGFHANDLERDRV; + +/** + * Info handler, internal version. + * + * @param pVM The cross context VM structure. + * @param pHlp Callback functions for doing output. + * @param pszArgs Argument string. Optional and specific to the handler. + */ +typedef DECLCALLBACKTYPE(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 DECLCALLBACKTYPE(void, FNDBGFHANDLEREXT,(void *pvUser, PCDBGFINFOHLP pHlp, const char *pszArgs)); +/** Pointer to a FNDBGFHANDLEREXT function. */ +typedef FNDBGFHANDLEREXT *PFNDBGFHANDLEREXT; + +/** + * Info handler, device version with argv. + * + * @param pDevIns The device instance which registered the info. + * @param pHlp Callback functions for doing output. + * @param cArgs Number of arguments. + * @param papszArgs Argument vector. + */ +typedef DECLCALLBACKTYPE(void, FNDBGFINFOARGVDEV,(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, int cArgs, char **papszArgs)); +/** Pointer to a FNDBGFINFOARGVDEV function. */ +typedef FNDBGFINFOARGVDEV *PFNDBGFINFOARGVDEV; + +/** + * Info handler, USB device version with argv. + * + * @param pUsbIns The USB device instance which registered the info. + * @param pHlp Callback functions for doing output. + * @param cArgs Number of arguments. + * @param papszArgs Argument vector. + */ +typedef DECLCALLBACKTYPE(void, FNDBGFINFOARGVUSB,(PPDMUSBINS pUsbIns, PCDBGFINFOHLP pHlp, int cArgs, char **papszArgs)); +/** Pointer to a FNDBGFINFOARGVUSB function. */ +typedef FNDBGFINFOARGVUSB *PFNDBGFINFOARGVUSB; + +/** + * Info handler, driver version with argv. + * + * @param pDrvIns The driver instance which registered the info. + * @param pHlp Callback functions for doing output. + * @param cArgs Number of arguments. + * @param papszArgs Argument vector. + */ +typedef DECLCALLBACKTYPE(void, FNDBGFINFOARGVDRV,(PPDMDRVINS pDrvIns, PCDBGFINFOHLP pHlp, int cArgs, char **papszArgs)); +/** Pointer to a FNDBGFINFOARGVDRV function. */ +typedef FNDBGFINFOARGVDRV *PFNDBGFINFOARGVDRV; + +/** + * Info handler, internal version with argv. + * + * @param pVM The cross context VM structure. + * @param pHlp Callback functions for doing output. + * @param cArgs Number of arguments. + * @param papszArgs Argument vector. + */ +typedef DECLCALLBACKTYPE(void, FNDBGFINFOARGVINT,(PVM pVM, PCDBGFINFOHLP pHlp, int cArgs, char **papszArgs)); +/** Pointer to a FNDBGFINFOARGVINT function. */ +typedef FNDBGFINFOARGVINT *PFNDBGFINFOARGVINT; + +/** + * Info handler, external version with argv. + * + * @param pvUser User argument. + * @param pHlp Callback functions for doing output. + * @param cArgs Number of arguments. + * @param papszArgs Argument vector. + */ +typedef DECLCALLBACKTYPE(void, FNDBGFINFOARGVEXT,(void *pvUser, PCDBGFINFOHLP pHlp, int cArgs, char **papszArgs)); +/** Pointer to a FNDBGFINFOARGVEXT function. */ +typedef FNDBGFINFOARGVEXT *PFNDBGFINFOARGVEXT; + + +/** @name Flags for the info registration functions. + * @{ */ +/** The handler must run on the EMT. */ +#define DBGFINFO_FLAGS_RUN_ON_EMT RT_BIT(0) +/** Call on all EMTs when a specific isn't specified. */ +#define DBGFINFO_FLAGS_ALL_EMTS RT_BIT(1) +/** @} */ + +VMMR3_INT_DECL(int) DBGFR3InfoRegisterDevice(PVM pVM, const char *pszName, const char *pszDesc, PFNDBGFHANDLERDEV pfnHandler, PPDMDEVINS pDevIns); +VMMR3_INT_DECL(int) DBGFR3InfoRegisterDriver(PVM pVM, const char *pszName, const char *pszDesc, PFNDBGFHANDLERDRV pfnHandler, PPDMDRVINS pDrvIns); +VMMR3_INT_DECL(int) DBGFR3InfoRegisterInternal(PVM pVM, const char *pszName, const char *pszDesc, PFNDBGFHANDLERINT pfnHandler); +VMMR3_INT_DECL(int) DBGFR3InfoRegisterInternalEx(PVM pVM, const char *pszName, const char *pszDesc, PFNDBGFHANDLERINT pfnHandler, uint32_t fFlags); +VMMR3DECL(int) DBGFR3InfoRegisterExternal(PUVM pUVM, const char *pszName, const char *pszDesc, PFNDBGFHANDLEREXT pfnHandler, void *pvUser); + +VMMR3_INT_DECL(int) DBGFR3InfoRegisterDeviceArgv(PVM pVM, const char *pszName, const char *pszDesc, PFNDBGFINFOARGVDEV pfnHandler, PPDMDEVINS pDevIns); +VMMR3_INT_DECL(int) DBGFR3InfoRegisterDriverArgv(PVM pVM, const char *pszName, const char *pszDesc, PFNDBGFINFOARGVDRV pfnHandler, PPDMDRVINS pDrvIns); +VMMR3_INT_DECL(int) DBGFR3InfoRegisterUsbArgv(PVM pVM, const char *pszName, const char *pszDesc, PFNDBGFINFOARGVUSB pfnHandler, PPDMUSBINS pUsbIns); +VMMR3_INT_DECL(int) DBGFR3InfoRegisterInternalArgv(PVM pVM, const char *pszName, const char *pszDesc, PFNDBGFINFOARGVINT pfnHandler, uint32_t fFlags); +VMMR3DECL(int) DBGFR3InfoRegisterExternalArgv(PUVM pUVM, const char *pszName, const char *pszDesc, PFNDBGFINFOARGVEXT pfnHandler, void *pvUser); + +VMMR3_INT_DECL(int) DBGFR3InfoDeregisterDevice(PVM pVM, PPDMDEVINS pDevIns, const char *pszName); +VMMR3_INT_DECL(int) DBGFR3InfoDeregisterDriver(PVM pVM, PPDMDRVINS pDrvIns, const char *pszName); +VMMR3_INT_DECL(int) DBGFR3InfoDeregisterUsb(PVM pVM, PPDMUSBINS pDrvIns, const char *pszName); +VMMR3_INT_DECL(int) DBGFR3InfoDeregisterInternal(PVM pVM, const char *pszName); +VMMR3DECL(int) DBGFR3InfoDeregisterExternal(PUVM pUVM, const char *pszName); + +VMMR3DECL(int) DBGFR3Info(PUVM pUVM, const char *pszName, const char *pszArgs, PCDBGFINFOHLP pHlp); +VMMR3DECL(int) DBGFR3InfoEx(PUVM pUVM, VMCPUID idCpu, const char *pszName, const char *pszArgs, PCDBGFINFOHLP pHlp); +VMMR3DECL(int) DBGFR3InfoLogRel(PUVM pUVM, const char *pszName, const char *pszArgs); +VMMR3DECL(int) DBGFR3InfoStdErr(PUVM pUVM, const char *pszName, const char *pszArgs); +VMMR3_INT_DECL(int) DBGFR3InfoMulti(PVM pVM, const char *pszIncludePat, const char *pszExcludePat, + const char *pszSepFmt, PCDBGFINFOHLP pHlp); + +/** @def DBGFR3_INFO_LOG + * Display a piece of info writing to the log if enabled. + * + * This is for execution on EMTs and will only show the items on the calling + * EMT. This is to avoid deadlocking against other CPUs if a rendezvous is + * initiated in parallel to this call. (Besides, nobody really wants or need + * info for the other EMTs when using this macro.) + * + * @param a_pVM The shared VM handle. + * @param a_pVCpu The cross context per CPU structure of the calling EMT. + * @param a_pszName The identifier of the info to display. + * @param a_pszArgs Arguments to the info handler. + */ +#ifdef LOG_ENABLED +# define DBGFR3_INFO_LOG(a_pVM, a_pVCpu, a_pszName, a_pszArgs) \ + do { \ + if (LogIsEnabled()) \ + DBGFR3InfoEx((a_pVM)->pUVM, (a_pVCpu)->idCpu, a_pszName, a_pszArgs, NULL); \ + } while (0) +#else +# define DBGFR3_INFO_LOG(a_pVM, a_pVCpu, a_pszName, a_pszArgs) do { } while (0) +#endif + +/** @def DBGFR3_INFO_LOG_SAFE + * Display a piece of info (rendezvous safe) writing to the log if enabled. + * + * @param a_pVM The shared VM handle. + * @param a_pszName The identifier of the info to display. + * @param a_pszArgs Arguments to the info handler. + * + * @remarks Use DBGFR3_INFO_LOG where ever possible! + */ +#ifdef LOG_ENABLED +# define DBGFR3_INFO_LOG_SAFE(a_pVM, a_pszName, a_pszArgs) \ + do { \ + if (LogIsEnabled()) \ + DBGFR3Info((a_pVM)->pUVM, a_pszName, a_pszArgs, NULL); \ + } while (0) +#else +# define DBGFR3_INFO_LOG_SAFE(a_pVM, a_pszName, a_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 pUVM The user mode VM handle. + * @param pszName Info identifier name. + * @param pszDesc The description. + * @param pvUser User parameter. + */ +typedef DECLCALLBACKTYPE(int, FNDBGFINFOENUM,(PUVM pUVM, const char *pszName, const char *pszDesc, void *pvUser)); +/** Pointer to a FNDBGFINFOENUM function. */ +typedef FNDBGFINFOENUM *PFNDBGFINFOENUM; + +VMMR3DECL(int) DBGFR3InfoEnum(PUVM pUVM, PFNDBGFINFOENUM pfnCallback, void *pvUser); +VMMR3DECL(PCDBGFINFOHLP) DBGFR3InfoLogHlp(void); +VMMR3DECL(PCDBGFINFOHLP) DBGFR3InfoLogRelHlp(void); +VMMR3DECL(void) DBGFR3InfoGenericGetOptError(PCDBGFINFOHLP pHlp, int rc, union RTGETOPTUNION *pValueUnion, + struct RTGETOPTSTATE *pState); + +#endif /* IN_RING3 */ + + +#ifdef IN_RING3 /* The log contrl API only works in ring-3. */ +VMMR3DECL(int) DBGFR3LogModifyGroups(PUVM pUVM, const char *pszGroupSettings); +VMMR3DECL(int) DBGFR3LogModifyFlags(PUVM pUVM, const char *pszFlagSettings); +VMMR3DECL(int) DBGFR3LogModifyDestinations(PUVM pUVM, 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(RTDBGCFG) DBGFR3AsGetConfig(PUVM pUVM); + +VMMR3DECL(int) DBGFR3AsAdd(PUVM pUVM, RTDBGAS hDbgAs, RTPROCESS ProcId); +VMMR3DECL(int) DBGFR3AsDelete(PUVM pUVM, RTDBGAS hDbgAs); +VMMR3DECL(int) DBGFR3AsSetAlias(PUVM pUVM, RTDBGAS hAlias, RTDBGAS hAliasFor); +VMMR3DECL(RTDBGAS) DBGFR3AsResolve(PUVM pUVM, RTDBGAS hAlias); +VMMR3DECL(RTDBGAS) DBGFR3AsResolveAndRetain(PUVM pUVM, RTDBGAS hAlias); +VMMR3DECL(RTDBGAS) DBGFR3AsQueryByName(PUVM pUVM, const char *pszName); +VMMR3DECL(RTDBGAS) DBGFR3AsQueryByPid(PUVM pUVM, RTPROCESS ProcId); + +VMMR3DECL(int) DBGFR3AsLoadImage(PUVM pUVM, RTDBGAS hDbgAs, const char *pszFilename, const char *pszModName, + RTLDRARCH enmArch, PCDBGFADDRESS pModAddress, RTDBGSEGIDX iModSeg, uint32_t fFlags); +VMMR3DECL(int) DBGFR3AsLoadMap(PUVM pUVM, RTDBGAS hDbgAs, const char *pszFilename, const char *pszModName, PCDBGFADDRESS pModAddress, RTDBGSEGIDX iModSeg, RTGCUINTPTR uSubtrahend, uint32_t fFlags); +VMMR3DECL(int) DBGFR3AsLinkModule(PUVM pUVM, RTDBGAS hDbgAs, RTDBGMOD hMod, PCDBGFADDRESS pModAddress, RTDBGSEGIDX iModSeg, uint32_t fFlags); +VMMR3DECL(int) DBGFR3AsUnlinkModuleByName(PUVM pUVM, RTDBGAS hDbgAs, const char *pszModName); + +VMMR3DECL(int) DBGFR3AsSymbolByAddr(PUVM pUVM, RTDBGAS hDbgAs, PCDBGFADDRESS pAddress, uint32_t fFlags, + PRTGCINTPTR poffDisp, PRTDBGSYMBOL pSymbol, PRTDBGMOD phMod); +VMMR3DECL(PRTDBGSYMBOL) DBGFR3AsSymbolByAddrA(PUVM pUVM, RTDBGAS hDbgAs, PCDBGFADDRESS pAddress, uint32_t Flags, + PRTGCINTPTR poffDisp, PRTDBGMOD phMod); +VMMR3DECL(int) DBGFR3AsSymbolByName(PUVM pUVM, RTDBGAS hDbgAs, const char *pszSymbol, PRTDBGSYMBOL pSymbol, PRTDBGMOD phMod); + +VMMR3DECL(int) DBGFR3AsLineByAddr(PUVM pUVM, RTDBGAS hDbgAs, PCDBGFADDRESS pAddress, + PRTGCINTPTR poffDisp, PRTDBGLINE pLine, PRTDBGMOD phMod); +VMMR3DECL(PRTDBGLINE) DBGFR3AsLineByAddrA(PUVM pUVM, RTDBGAS hDbgAs, PCDBGFADDRESS pAddress, + PRTGCINTPTR poffDisp, PRTDBGMOD phMod); + +/** @name DBGFMOD_PE_F_XXX - flags for + * @{ */ +/** NT 3.1 images were a little different, so make allowances for that. */ +#define DBGFMODINMEM_F_PE_NT31 RT_BIT_32(0) +/** No container fallback. */ +#define DBGFMODINMEM_F_NO_CONTAINER_FALLBACK RT_BIT_32(1) +/** No in-memory reader fallback. */ +#define DBGFMODINMEM_F_NO_READER_FALLBACK RT_BIT_32(2) +/** Valid flags. */ +#define DBGFMODINMEM_F_VALID_MASK UINT32_C(0x00000007) +/** @} */ +VMMR3DECL(int) DBGFR3ModInMem(PUVM pUVM, PCDBGFADDRESS pImageAddr, uint32_t fFlags, const char *pszName, + const char *pszFilename, RTLDRARCH enmArch, uint32_t cbImage, + PRTDBGMOD phDbgMod, PRTERRINFO pErrInfo); + +#endif /* IN_RING3 */ + +#ifdef IN_RING3 /* The stack API only works in ring-3. */ + +/** 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 (DBGFSTACKFRAME_FLAGS_XXX). */ + uint32_t fFlags; + /** 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 linenumber nearest the program counter (PC). NULL if not found. */ + PRTDBGLINE pLinePC; + /** The frame address. + * The off member is [e|r]bp and the Sel member is ss. */ + DBGFADDRESS AddrFrame; + /** The way this frame returns to the next one. */ + RTDBGRETURNTYPE enmReturnType; + + /** The way the next frame returns. + * Only valid when DBGFSTACKFRAME_FLAGS_UNWIND_INFO_RET is set. */ + RTDBGRETURNTYPE enmReturnFrameReturnType; + /** 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 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 linenumber nearest the return PC. NULL if not found. */ + PRTDBGLINE 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; + + /** Number of registers values we can be sure about. + * @note This is generally zero in the first frame. */ + uint32_t cSureRegs; + /** Registers we can be sure about (length given by cSureRegs). */ + struct DBGFREGVALEX *paSureRegs; + + /** 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_XXX - DBGFSTACKFRAME Flags. + * @{ */ +/** 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) +/** Real mode or V86 frame. */ +# define DBGFSTACKFRAME_FLAGS_REAL_V86 RT_BIT(7) +/** Is a trap frame (NT term). */ +# define DBGFSTACKFRAME_FLAGS_TRAP_FRAME RT_BIT(8) + +/** Used Odd/even heuristics for far/near return. */ +# define DBGFSTACKFRAME_FLAGS_USED_ODD_EVEN RT_BIT(29) +/** Set if we used unwind info to construct the frame. (Kind of internal.) */ +# define DBGFSTACKFRAME_FLAGS_USED_UNWIND_INFO RT_BIT(30) +/** Internal: Unwind info used for the return frame. */ +# define DBGFSTACKFRAME_FLAGS_UNWIND_INFO_RET RT_BIT(31) +/** @} */ + +/** @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(PUVM pUVM, VMCPUID idCpu, DBGFCODETYPE enmCodeType, + PCDBGFSTACKFRAME *ppFirstFrame); +VMMR3DECL(int) DBGFR3StackWalkBeginEx(PUVM pUVM, VMCPUID idCpu, DBGFCODETYPE enmCodeType, PCDBGFADDRESS pAddrFrame, + PCDBGFADDRESS pAddrStack,PCDBGFADDRESS pAddrPC, + RTDBGRETURNTYPE 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. */ + +/** @name Flags to pass to DBGFR3DisasInstrEx(). + * @{ */ +/** Disassemble the current guest instruction, with annotations. */ +#define DBGF_DISAS_FLAGS_CURRENT_GUEST RT_BIT(0) +/** 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 original unpatched bytes (PATM). */ +#define DBGF_DISAS_FLAGS_UNPATCHED_BYTES RT_BIT(7) +/** Annotate patched instructions. */ +#define DBGF_DISAS_FLAGS_ANNOTATE_PATCHED RT_BIT(8) +/** 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(0x700001ff) +/** @} */ + +/** Special flat selector. */ +#define DBGF_SEL_FLAT 1 + +VMMR3DECL(int) DBGFR3DisasInstrEx(PUVM pUVM, VMCPUID idCpu, RTSEL Sel, RTGCPTR GCPtr, uint32_t fFlags, + char *pszOutput, uint32_t cbOutput, uint32_t *pcbInstr); +VMMR3_INT_DECL(int) DBGFR3DisasInstrCurrent(PVMCPU pVCpu, char *pszOutput, uint32_t cbOutput); +VMMR3DECL(int) DBGFR3DisasInstrCurrentLogInternal(PVMCPU pVCpu, const char *pszPrefix); + +/** @def DBGFR3_DISAS_INSTR_CUR_LOG + * 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 DBGFR3_DISAS_INSTR_CUR_LOG(pVCpu, pszPrefix) \ + do { \ + if (LogIsEnabled()) \ + DBGFR3DisasInstrCurrentLogInternal(pVCpu, pszPrefix); \ + } while (0) +#else +# define DBGFR3_DISAS_INSTR_CUR_LOG(pVCpu, pszPrefix) do { } while (0) +#endif + +VMMR3DECL(int) DBGFR3DisasInstrLogInternal(PVMCPU pVCpu, RTSEL Sel, RTGCPTR GCPtr, const char *pszPrefix); + +/** @def DBGFR3_DISAS_INSTR_LOG + * 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 DBGFR3_DISAS_INSTR_LOG(pVCpu, Sel, GCPtr, pszPrefix) \ + do { \ + if (LogIsEnabled()) \ + DBGFR3DisasInstrLogInternal(pVCpu, Sel, GCPtr, pszPrefix); \ + } while (0) +# else +# define DBGFR3_DISAS_INSTR_LOG(pVCpu, Sel, GCPtr, pszPrefix) do { } while (0) +# endif +#endif + + +#ifdef IN_RING3 +VMMR3DECL(int) DBGFR3MemScan(PUVM pUVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, RTGCUINTPTR cbRange, RTGCUINTPTR uAlign, + const void *pvNeedle, size_t cbNeedle, PDBGFADDRESS pHitAddress); +VMMR3DECL(int) DBGFR3MemRead(PUVM pUVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, void *pvBuf, size_t cbRead); +VMMR3DECL(int) DBGFR3MemReadString(PUVM pUVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, char *pszBuf, size_t cbBuf); +VMMR3DECL(int) DBGFR3MemWrite(PUVM pUVM, 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(PUVM pUVM, 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. + * @note This is more or less a given now when raw-mode was kicked out. */ +#define DBGFSELQI_FLAGS_DT_GUEST UINT32_C(0) +/** 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(PUVM pUVM, 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. */ + + /* AVX: */ + DBGFREG_YMM0, + DBGFREG_YMM1, + DBGFREG_YMM2, + DBGFREG_YMM3, + DBGFREG_YMM4, + DBGFREG_YMM5, + DBGFREG_YMM6, + DBGFREG_YMM7, + DBGFREG_YMM8, + DBGFREG_YMM9, + DBGFREG_YMM10, + DBGFREG_YMM11, + DBGFREG_YMM12, + DBGFREG_YMM13, + DBGFREG_YMM14, + DBGFREG_YMM15, + + /* 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, + /** Unsigned 256-bit register value. */ + DBGFREGVALTYPE_U256, + /** Unsigned 512-bit register value. */ + DBGFREGVALTYPE_U512, + /** 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 +{ + uint64_t au64[8]; /**< The 64-bit array view. First because of the initializer. */ + uint32_t au32[16]; /**< The 32-bit array view. */ + uint16_t au16[32]; /**< The 16-bit array view. */ + uint8_t au8[64]; /**< The 8-bit array view. */ + + 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. */ + RTUINT256U u256; /**< The 256-bit view. */ + RTUINT512U u512; /**< The 512-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; /**< @todo Limit should be uint16_t */ + } dtr; +} DBGFREGVAL; +/** Pointer to a generic register value type. */ +typedef DBGFREGVAL *PDBGFREGVAL; +/** Pointer to a const generic register value type. */ +typedef DBGFREGVAL const *PCDBGFREGVAL; + +/** Initialize a DBGFREGVAL variable to all zeros. */ +#define DBGFREGVAL_INITIALIZE_ZERO { { 0, 0, 0, 0, 0, 0, 0, 0 } } +/** Initialize a DBGFREGVAL variable to all bits set . */ +#define DBGFREGVAL_INITIALIZE_FFFF { { UINT64_MAX, UINT64_MAX, UINT64_MAX, UINT64_MAX, UINT64_MAX, UINT64_MAX, UINT64_MAX, UINT64_MAX } } + +/** + * Extended register value, including register ID and type. + * + * This is currently only used by the stack walker. + */ +typedef struct DBGFREGVALEX +{ + /** The register value. */ + DBGFREGVAL Value; + /** The register value type. */ + DBGFREGVALTYPE enmType; + /** The register ID, DBGFREG_END if not applicable. */ + DBGFREG enmReg; + /** Pointer to read-only register name string if no register ID could be found. */ + const char *pszName; +} DBGFREGVALEX; +/** Pointer to an extended register value struct. */ +typedef DBGFREGVALEX *PDBGFREGVALEX; +/** Pointer to a const extended register value struct. */ +typedef DBGFREGVALEX const *PCDBGFREGVALEX; + + +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). + * @remarks Does not take the device lock or anything like that. + */ + DECLCALLBACKMEMBER(int, pfnGet,(void *pvUser, struct DBGFREGSUBFIELD const *pSubField, PRTUINT128U puValue)); + /** Setter (optional). + * @remarks Does not take the device lock or anything like that. + */ + 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 read-only sub-field entry without getters. */ +#define DBGFREGSUBFIELD_RO(a_szName, a_iFirstBit, a_cBits, a_cShift) \ + { a_szName, a_iFirstBit, a_cBits, a_cShift, DBGFREGSUBFIELD_FLAGS_READ_ONLY, NULL /*pfnGet*/, NULL /*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. + * @remarks Does not take the device lock or anything like that. + */ + DECLCALLBACKMEMBER(int, pfnGet,(void *pvUser, struct DBGFREGDESC const *pDesc, PDBGFREGVAL pValue)); + /** Setter. + * @remarks Does not take the device lock or anything like that. + */ + 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( PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, uint8_t *pu8); +VMMR3DECL(int) DBGFR3RegCpuQueryU16( PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, uint16_t *pu16); +VMMR3DECL(int) DBGFR3RegCpuQueryU32( PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, uint32_t *pu32); +VMMR3DECL(int) DBGFR3RegCpuQueryU64( PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, uint64_t *pu64); +VMMR3DECL(int) DBGFR3RegCpuQueryU128(PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, uint128_t *pu128); +/*VMMR3DECL(int) DBGFR3RegCpuQueryLrd( PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, long double *plrd);*/ +VMMR3DECL(int) DBGFR3RegCpuQueryXdtr(PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, uint64_t *pu64Base, uint16_t *pu16Limit); +#if 0 +VMMR3DECL(int) DBGFR3RegCpuQueryBatch(PUVM pUVM,VMCPUID idCpu, PDBGFREGENTRY paRegs, size_t cRegs); +VMMR3DECL(int) DBGFR3RegCpuQueryAll( PUVM pUVM, VMCPUID idCpu, PDBGFREGENTRY paRegs, size_t cRegs); + +VMMR3DECL(int) DBGFR3RegCpuSetU8( PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, uint8_t u8); +VMMR3DECL(int) DBGFR3RegCpuSetU16( PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, uint16_t u16); +VMMR3DECL(int) DBGFR3RegCpuSetU32( PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, uint32_t u32); +VMMR3DECL(int) DBGFR3RegCpuSetU64( PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, uint64_t u64); +VMMR3DECL(int) DBGFR3RegCpuSetU128( PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, uint128_t u128); +VMMR3DECL(int) DBGFR3RegCpuSetLrd( PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, long double lrd); +VMMR3DECL(int) DBGFR3RegCpuSetBatch( PUVM pUVM, VMCPUID idCpu, PCDBGFREGENTRY paRegs, size_t cRegs); +#endif + +VMMR3DECL(const char *) DBGFR3RegCpuName(PUVM pUVM, DBGFREG enmReg, DBGFREGVALTYPE enmType); + +VMMR3_INT_DECL(int) DBGFR3RegRegisterCpu(PVM pVM, PVMCPU pVCpu, PCDBGFREGDESC paRegisters, bool fGuestRegs); +VMMR3_INT_DECL(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( PUVM pUVM, VMCPUID idDefCpu, const char *pszReg); + +VMMR3DECL(int) DBGFR3RegNmQuery( PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, PDBGFREGVAL pValue, PDBGFREGVALTYPE penmType); +VMMR3DECL(int) DBGFR3RegNmQueryU8( PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, uint8_t *pu8); +VMMR3DECL(int) DBGFR3RegNmQueryU16( PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, uint16_t *pu16); +VMMR3DECL(int) DBGFR3RegNmQueryU32( PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, uint32_t *pu32); +VMMR3DECL(int) DBGFR3RegNmQueryU64( PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, uint64_t *pu64); +VMMR3DECL(int) DBGFR3RegNmQueryU128(PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, PRTUINT128U pu128); +/*VMMR3DECL(int) DBGFR3RegNmQueryLrd( PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, long double *plrd);*/ +VMMR3DECL(int) DBGFR3RegNmQueryXdtr(PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, uint64_t *pu64Base, uint16_t *pu16Limit); +VMMR3DECL(int) DBGFR3RegNmQueryBatch(PUVM pUVM,VMCPUID idDefCpu, PDBGFREGENTRYNM paRegs, size_t cRegs); +VMMR3DECL(int) DBGFR3RegNmQueryAllCount(PUVM pUVM, size_t *pcRegs); +VMMR3DECL(int) DBGFR3RegNmQueryAll( PUVM pUVM, PDBGFREGENTRYNM paRegs, size_t cRegs); + +VMMR3DECL(int) DBGFR3RegNmSet( PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, PCDBGFREGVAL pValue, DBGFREGVALTYPE enmType); +VMMR3DECL(int) DBGFR3RegNmSetU8( PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, uint8_t u8); +VMMR3DECL(int) DBGFR3RegNmSetU16( PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, uint16_t u16); +VMMR3DECL(int) DBGFR3RegNmSetU32( PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, uint32_t u32); +VMMR3DECL(int) DBGFR3RegNmSetU64( PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, uint64_t u64); +VMMR3DECL(int) DBGFR3RegNmSetU128( PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, RTUINT128U u128); +VMMR3DECL(int) DBGFR3RegNmSetLrd( PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, long double lrd); +VMMR3DECL(int) DBGFR3RegNmSetBatch( PUVM pUVM, VMCPUID idDefCpu, PCDBGFREGENTRYNM paRegs, size_t cRegs); + +/** @todo add enumeration methods. */ + +VMMR3DECL(int) DBGFR3RegPrintf( PUVM pUVM, VMCPUID idDefCpu, char *pszBuf, size_t cbBuf, const char *pszFormat, ...); +VMMR3DECL(int) DBGFR3RegPrintfV(PUVM pUVM, VMCPUID idDefCpu, char *pszBuf, size_t cbBuf, const char *pszFormat, va_list va); + + +#ifdef IN_RING3 + +/** + * 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, + /** Kernel message log - DBGFOSIDMESG. */ + DBGFOSINTERFACE_DMESG, + /** Windows NT specifics (for the communication with the KD debugger stub). */ + DBGFOSINTERFACE_WINNT, + /** 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 pUVM The user mode VM handle. + * @param pVMM The VMM function table. + * @param pvData Pointer to the instance data. + */ + DECLCALLBACKMEMBER(int, pfnConstruct,(PUVM pUVM, PCVMMR3VTABLE pVMM, void *pvData)); + + /** + * Destroys the instance. + * + * @param pUVM The user mode VM handle. + * @param pVMM The VMM function table. + * @param pvData Pointer to the instance data. + */ + DECLCALLBACKMEMBER(void, pfnDestruct,(PUVM pUVM, PCVMMR3VTABLE pVMM, 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 pUVM The user mode VM handle. + * @param pVMM The VMM function table. + * @param pvData Pointer to the instance data. + */ + DECLCALLBACKMEMBER(bool, pfnProbe,(PUVM pUVM, PCVMMR3VTABLE pVMM, void *pvData)); + + /** + * Initializes a fresly detected guest, loading symbols and such useful stuff. + * + * This is called after pfnProbe. + * + * @returns VBox status code. + * @param pUVM The user mode VM handle. + * @param pVMM The VMM function table. + * @param pvData Pointer to the instance data. + */ + DECLCALLBACKMEMBER(int, pfnInit,(PUVM pUVM, PCVMMR3VTABLE pVMM, void *pvData)); + + /** + * Refreshes symbols and stuff following a redetection of the same OS. + * + * This is called after pfnProbe. + * + * @returns VBox status code. + * @param pUVM The user mode VM handle. + * @param pVMM The VMM function table. + * @param pvData Pointer to the instance data. + */ + DECLCALLBACKMEMBER(int, pfnRefresh,(PUVM pUVM, PCVMMR3VTABLE pVMM, 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 pUVM The user mode VM handle. + * @param pVMM The VMM function table. + * @param pvData Pointer to the instance data. + */ + DECLCALLBACKMEMBER(void, pfnTerm,(PUVM pUVM, PCVMMR3VTABLE pVMM, void *pvData)); + + /** + * Queries the version of the running OS. + * + * This is only called after pfnInit(). + * + * @returns VBox status code. + * @param pUVM The user mode VM handle. + * @param pVMM The VMM function table. + * @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,(PUVM pUVM, PCVMMR3VTABLE pVMM, void *pvData, char *pszVersion, size_t cchVersion)); + + /** + * Queries the pointer to a interface. + * + * This is called after pfnProbe. + * + * The returned interface must be valid until pfnDestruct is called. Two calls + * to this method with the same @a enmIf value must return the same pointer. + * + * @returns Pointer to the interface if available, NULL if not available. + * @param pUVM The user mode VM handle. + * @param pVMM The VMM function table. + * @param pvData Pointer to the instance data. + * @param enmIf The interface identifier. + */ + DECLCALLBACKMEMBER(void *, pfnQueryInterface,(PUVM pUVM, PCVMMR3VTABLE pVMM, void *pvData, DBGFOSINTERFACE enmIf)); + + /** + * Stack unwind assist callback. + * + * This is only called after pfnInit(). + * + * @returns VBox status code (allocation error or something of similar fatality). + * @param pUVM The user mode VM handle. + * @param pVMM The VMM function table. + * @param pvData Pointer to the instance data. + * @param idCpu The CPU that's unwinding it's stack. + * @param pFrame The current frame. Okay to modify it a little. + * @param pState The unwind state. Okay to modify it. + * @param pInitialCtx The initial register context. + * @param hAs The address space being used for the unwind. + * @param puScratch Scratch area (initialized to zero, no dtor). + */ + DECLCALLBACKMEMBER(int, pfnStackUnwindAssist,(PUVM pUVM, PCVMMR3VTABLE pVMM, void *pvData, VMCPUID idCpu, PDBGFSTACKFRAME pFrame, + PRTDBGUNWINDSTATE pState, PCCPUMCTX pInitialCtx, RTDBGAS hAs, + uint64_t *puScratch)); + + /** 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 + + +/** + * Interface for querying kernel log messages (DBGFOSINTERFACE_DMESG). + */ +typedef struct DBGFOSIDMESG +{ + /** Trailing magic (DBGFOSIDMESG_MAGIC). */ + uint32_t u32Magic; + + /** + * Query the kernel log. + * + * @returns VBox status code. + * @retval VERR_NOT_FOUND if the messages could not be located. + * @retval VERR_INVALID_STATE if the messages was found to have unknown/invalid + * format. + * @retval VERR_BUFFER_OVERFLOW if the buffer isn't large enough, pcbActual + * will be set to the required buffer size. The buffer, however, will + * be filled with as much data as it can hold (properly zero terminated + * of course). + * + * @param pThis Pointer to the interface structure. + * @param pUVM The user mode VM handle. + * @param pVMM The VMM function table. + * @param fFlags Flags reserved for future use, MBZ. + * @param cMessages The number of messages to retrieve, counting from the + * end of the log (i.e. like tail), use UINT32_MAX for all. + * @param pszBuf The output buffer. + * @param cbBuf The buffer size. + * @param pcbActual Where to store the number of bytes actually returned, + * including zero terminator. On VERR_BUFFER_OVERFLOW this + * holds the necessary buffer size. Optional. + */ + DECLCALLBACKMEMBER(int, pfnQueryKernelLog,(struct DBGFOSIDMESG *pThis, PUVM pUVM, PCVMMR3VTABLE pVMM, uint32_t fFlags, + uint32_t cMessages, char *pszBuf, size_t cbBuf, size_t *pcbActual)); + /** Trailing magic (DBGFOSIDMESG_MAGIC). */ + uint32_t u32EndMagic; +} DBGFOSIDMESG; +/** Pointer to the interface for query kernel log messages (DBGFOSINTERFACE_DMESG). */ +typedef DBGFOSIDMESG *PDBGFOSIDMESG; +/** Magic value for DBGFOSIDMESG::32Magic and DBGFOSIDMESG::u32EndMagic. (Kenazburo Oe) */ +#define DBGFOSIDMESG_MAGIC UINT32_C(0x19350131) + + +/** + * Interface for querying Windows NT guest specifics (DBGFOSINTERFACE_WINNT). + */ +typedef struct DBGFOSIWINNT +{ + /** Trailing magic (DBGFOSIWINNT_MAGIC). */ + uint32_t u32Magic; + + /** + * Queries version information. + * + * @returns VBox status code. + * @param pThis Pointer to the interface structure. + * @param pUVM The user mode VM handle. + * @param pVMM The VMM function table. + * @param puVersMajor Where to store the major version part, optional. + * @param puVersMinor Where to store the minor version part, optional. + * @param puBuildNumber Where to store the build number, optional. + * @param pf32Bit Where to store the flag whether this is a 32bit Windows NT, optional. + */ + DECLCALLBACKMEMBER(int, pfnQueryVersion,(struct DBGFOSIWINNT *pThis, PUVM pUVM, PCVMMR3VTABLE pVMM, + uint32_t *puVersMajor, uint32_t *puVersMinor, + uint32_t *puBuildNumber, bool *pf32Bit)); + + /** + * Queries some base kernel pointers. + * + * @returns VBox status code. + * @param pThis Pointer to the interface structure. + * @param pUVM The user mode VM handle. + * @param pVMM The VMM function table. + * @param pGCPtrKernBase Where to store the kernel base on success. + * @param pGCPtrPsLoadedModuleList Where to store the pointer to the laoded module list head on success. + */ + DECLCALLBACKMEMBER(int, pfnQueryKernelPtrs,(struct DBGFOSIWINNT *pThis, PUVM pUVM, PCVMMR3VTABLE pVMM, + PRTGCUINTPTR pGCPtrKernBase, PRTGCUINTPTR pGCPtrPsLoadedModuleList)); + + /** + * Queries KPCR and KPCRB pointers for the given vCPU. + * + * @returns VBox status code. + * @param pThis Pointer to the interface structure. + * @param pUVM The user mode VM handle. + * @param pVMM The VMM function table. + * @param idCpu The vCPU to query the KPCR/KPCRB for. + * @param pKpcr Where to store the KPCR pointer on success, optional. + * @param pKpcrb Where to store the KPCR pointer on success, optional. + */ + DECLCALLBACKMEMBER(int, pfnQueryKpcrForVCpu,(struct DBGFOSIWINNT *pThis, PUVM pUVM, PCVMMR3VTABLE pVMM, VMCPUID idCpu, + PRTGCUINTPTR pKpcr, PRTGCUINTPTR pKpcrb)); + + /** + * Queries the current thread for the given vCPU. + * + * @returns VBox status code. + * @param pThis Pointer to the interface structure. + * @param pUVM The user mode VM handle. + * @param pVMM The VMM function table. + * @param idCpu The vCPU to query the KPCR/KPCRB for. + * @param pCurThrd Where to store the CurrentThread pointer on success. + */ + DECLCALLBACKMEMBER(int, pfnQueryCurThrdForVCpu,(struct DBGFOSIWINNT *pThis, PUVM pUVM, PCVMMR3VTABLE pVMM, VMCPUID idCpu, + PRTGCUINTPTR pCurThrd)); + + /** Trailing magic (DBGFOSIWINNT_MAGIC). */ + uint32_t u32EndMagic; +} DBGFOSIWINNT; +/** Pointer to the interface for query kernel log messages (DBGFOSINTERFACE_WINNT). */ +typedef DBGFOSIWINNT *PDBGFOSIWINNT; +/** Magic value for DBGFOSIWINNT::32Magic and DBGFOSIWINNT::u32EndMagic. (Dave Cutler) */ +#define DBGFOSIWINNT_MAGIC UINT32_C(0x19420313) + + +VMMR3DECL(int) DBGFR3OSRegister(PUVM pUVM, PCDBGFOSREG pReg); +VMMR3DECL(int) DBGFR3OSDeregister(PUVM pUVM, PCDBGFOSREG pReg); +VMMR3DECL(int) DBGFR3OSDetect(PUVM pUVM, char *pszName, size_t cchName); +VMMR3DECL(int) DBGFR3OSQueryNameAndVersion(PUVM pUVM, char *pszName, size_t cchName, char *pszVersion, size_t cchVersion); +VMMR3DECL(void *) DBGFR3OSQueryInterface(PUVM pUVM, DBGFOSINTERFACE enmIf); + + +VMMR3DECL(int) DBGFR3CoreWrite(PUVM pUVM, const char *pszFilename, bool fReplaceFile); + + + +/** @defgroup grp_dbgf_plug_in The DBGF Plug-in Interface + * @{ + */ + +/** The plug-in module name prefix. */ +# define DBGF_PLUG_IN_PREFIX "DbgPlugIn" + +/** The name of the plug-in entry point (FNDBGFPLUGIN) */ +# define DBGF_PLUG_IN_ENTRYPOINT "DbgPlugInEntry" + +/** + * DBGF plug-in operations. + */ +typedef enum DBGFPLUGINOP +{ + /** The usual invalid first value. */ + DBGFPLUGINOP_INVALID, + /** Initialize the plug-in for a VM, register all the stuff. + * The plug-in will be unloaded on failure. + * uArg: The full VirtualBox version, see VBox/version.h. */ + DBGFPLUGINOP_INIT, + /** Terminate the plug-ing for a VM, deregister all the stuff. + * The plug-in will be unloaded after this call regardless of the return + * code. */ + DBGFPLUGINOP_TERM, + /** The usual 32-bit hack. */ + DBGFPLUGINOP_32BIT_HACK = 0x7fffffff +} DBGFPLUGINOP; + +/** + * DBGF plug-in main entry point. + * + * @returns VBox status code. + * + * @param enmOperation The operation. + * @param pUVM The user mode VM handle. This may be NULL. + * @param pVMM The VMM function table. + * @param uArg Extra argument. + */ +typedef DECLCALLBACKTYPE(int, FNDBGFPLUGIN,(DBGFPLUGINOP enmOperation, PUVM pUVM, PCVMMR3VTABLE pVMM, uintptr_t uArg)); +/** Pointer to a FNDBGFPLUGIN. */ +typedef FNDBGFPLUGIN *PFNDBGFPLUGIN; + +/** @copydoc FNDBGFPLUGIN */ +DECLEXPORT(int) DbgPlugInEntry(DBGFPLUGINOP enmOperation, PUVM pUVM, PCVMMR3VTABLE pVMM, uintptr_t uArg); + +VMMR3DECL(int) DBGFR3PlugInLoad(PUVM pUVM, const char *pszPlugIn, char *pszActual, size_t cbActual, PRTERRINFO pErrInfo); +VMMR3DECL(int) DBGFR3PlugInUnload(PUVM pUVM, const char *pszName); +VMMR3DECL(void) DBGFR3PlugInLoadAll(PUVM pUVM); +VMMR3DECL(void) DBGFR3PlugInUnloadAll(PUVM pUVM); + +/** @} */ + + +/** @defgroup grp_dbgf_types The DBGF type system Interface. + * @{ + */ + +/** A few forward declarations. */ +/** Pointer to a type registration structure. */ +typedef struct DBGFTYPEREG *PDBGFTYPEREG; +/** Pointer to a const type registration structure. */ +typedef const struct DBGFTYPEREG *PCDBGFTYPEREG; +/** Pointer to a typed buffer. */ +typedef struct DBGFTYPEVAL *PDBGFTYPEVAL; + +/** + * DBGF built-in types. + */ +typedef enum DBGFTYPEBUILTIN +{ + /** The usual invalid first value. */ + DBGFTYPEBUILTIN_INVALID, + /** Unsigned 8bit integer. */ + DBGFTYPEBUILTIN_UINT8, + /** Signed 8bit integer. */ + DBGFTYPEBUILTIN_INT8, + /** Unsigned 16bit integer. */ + DBGFTYPEBUILTIN_UINT16, + /** Signed 16bit integer. */ + DBGFTYPEBUILTIN_INT16, + /** Unsigned 32bit integer. */ + DBGFTYPEBUILTIN_UINT32, + /** Signed 32bit integer. */ + DBGFTYPEBUILTIN_INT32, + /** Unsigned 64bit integer. */ + DBGFTYPEBUILTIN_UINT64, + /** Signed 64bit integer. */ + DBGFTYPEBUILTIN_INT64, + /** 32bit Guest pointer */ + DBGFTYPEBUILTIN_PTR32, + /** 64bit Guest pointer */ + DBGFTYPEBUILTIN_PTR64, + /** Guest pointer - size depends on the guest bitness */ + DBGFTYPEBUILTIN_PTR, + /** Type indicating a size, like size_t this can have different sizes + * on 32bit and 64bit systems */ + DBGFTYPEBUILTIN_SIZE, + /** 32bit float. */ + DBGFTYPEBUILTIN_FLOAT32, + /** 64bit float (also known as double). */ + DBGFTYPEBUILTIN_FLOAT64, + /** Compund types like structs and unions. */ + DBGFTYPEBUILTIN_COMPOUND, + /** The usual 32-bit hack. */ + DBGFTYPEBUILTIN_32BIT_HACK = 0x7fffffff +} DBGFTYPEBUILTIN; +/** Pointer to a built-in type. */ +typedef DBGFTYPEBUILTIN *PDBGFTYPEBUILTIN; +/** Pointer to a const built-in type. */ +typedef const DBGFTYPEBUILTIN *PCDBGFTYPEBUILTIN; + +/** + * DBGF type value buffer. + */ +typedef union DBGFTYPEVALBUF +{ + uint8_t u8; + int8_t i8; + uint16_t u16; + int16_t i16; + uint32_t u32; + int32_t i32; + uint64_t u64; + int64_t i64; + float f32; + double f64; + uint64_t size; /* For the built-in size_t which can be either 32-bit or 64-bit. */ + RTGCPTR GCPtr; + /** For embedded structs. */ + PDBGFTYPEVAL pVal; +} DBGFTYPEVALBUF; +/** Pointer to a value. */ +typedef DBGFTYPEVALBUF *PDBGFTYPEVALBUF; + +/** + * DBGF type value entry. + */ +typedef struct DBGFTYPEVALENTRY +{ + /** DBGF built-in type. */ + DBGFTYPEBUILTIN enmType; + /** Size of the type. */ + size_t cbType; + /** Number of entries, for arrays this can be > 1. */ + uint32_t cEntries; + /** Value buffer, depends on whether this is an array. */ + union + { + /** Single value. */ + DBGFTYPEVALBUF Val; + /** Pointer to the array of values. */ + PDBGFTYPEVALBUF pVal; + } Buf; +} DBGFTYPEVALENTRY; +/** Pointer to a type value entry. */ +typedef DBGFTYPEVALENTRY *PDBGFTYPEVALENTRY; +/** Pointer to a const type value entry. */ +typedef const DBGFTYPEVALENTRY *PCDBGFTYPEVALENTRY; + +/** + * DBGF typed value. + */ +typedef struct DBGFTYPEVAL +{ + /** Pointer to the registration structure for this type. */ + PCDBGFTYPEREG pTypeReg; + /** Number of value entries. */ + uint32_t cEntries; + /** Variable sized array of value entries. */ + DBGFTYPEVALENTRY aEntries[1]; +} DBGFTYPEVAL; + +/** + * DBGF type variant. + */ +typedef enum DBGFTYPEVARIANT +{ + /** The usual invalid first value. */ + DBGFTYPEVARIANT_INVALID, + /** A struct. */ + DBGFTYPEVARIANT_STRUCT, + /** Union. */ + DBGFTYPEVARIANT_UNION, + /** Alias for an existing type. */ + DBGFTYPEVARIANT_ALIAS, + /** The usual 32-bit hack. */ + DBGFTYPEVARIANT_32BIT_HACK = 0x7fffffff +} DBGFTYPEVARIANT; + +/** @name DBGFTYPEREGMEMBER Flags. + * @{ */ +/** The member is an array with a fixed size. */ +# define DBGFTYPEREGMEMBER_F_ARRAY RT_BIT_32(0) +/** The member denotes a pointer. */ +# define DBGFTYPEREGMEMBER_F_POINTER RT_BIT_32(1) +/** @} */ + +/** + * DBGF type member. + */ +typedef struct DBGFTYPEREGMEMBER +{ + /** Name of the member. */ + const char *pszName; + /** Flags for this member, see DBGFTYPEREGMEMBER_F_XXX. */ + uint32_t fFlags; + /** Type identifier. */ + const char *pszType; + /** The number of elements in the array, only valid for arrays. */ + uint32_t cElements; +} DBGFTYPEREGMEMBER; +/** Pointer to a member. */ +typedef DBGFTYPEREGMEMBER *PDBGFTYPEREGMEMBER; +/** Pointer to a const member. */ +typedef const DBGFTYPEREGMEMBER *PCDBGFTYPEREGMEMBER; + +/** @name DBGFTYPEREG Flags. + * @{ */ +/** The type is a packed structure. */ +# define DBGFTYPEREG_F_PACKED RT_BIT_32(0) +/** @} */ + +/** + * New type registration structure. + */ +typedef struct DBGFTYPEREG +{ + /** Name of the type. */ + const char *pszType; + /** The type variant. */ + DBGFTYPEVARIANT enmVariant; + /** Some registration flags, see DBGFTYPEREG_F_XXX. */ + uint32_t fFlags; + /** Number of members this type has, only valid for structs or unions. */ + uint32_t cMembers; + /** Pointer to the member fields, only valid for structs or unions. */ + PCDBGFTYPEREGMEMBER paMembers; + /** Name of the aliased type for aliases. */ + const char *pszAliasedType; +} DBGFTYPEREG; + +/** + * DBGF typed value dumper callback. + * + * @returns VBox status code. Any non VINF_SUCCESS status code will abort the dumping. + * + * @param off The byte offset of the entry from the start of the type. + * @param pszField The name of the field for the value. + * @param iLvl The current level. + * @param enmType The type enum. + * @param cbType Size of the type. + * @param pValBuf Pointer to the value buffer. + * @param cValBufs Number of value buffers (for arrays). + * @param pvUser Opaque user data. + */ +typedef DECLCALLBACKTYPE(int, FNDBGFR3TYPEVALDUMP,(uint32_t off, const char *pszField, uint32_t iLvl, + DBGFTYPEBUILTIN enmType, size_t cbType, + PDBGFTYPEVALBUF pValBuf, uint32_t cValBufs, void *pvUser)); +/** Pointer to a FNDBGFR3TYPEVALDUMP. */ +typedef FNDBGFR3TYPEVALDUMP *PFNDBGFR3TYPEVALDUMP; + +/** + * DBGF type information dumper callback. + * + * @returns VBox status code. Any non VINF_SUCCESS status code will abort the dumping. + * + * @param off The byte offset of the entry from the start of the type. + * @param pszField The name of the field for the value. + * @param iLvl The current level. + * @param pszType The type of the field. + * @param fTypeFlags Flags for this type, see DBGFTYPEREGMEMBER_F_XXX. + * @param cElements Number of for the field ( > 0 for arrays). + * @param pvUser Opaque user data. + */ +typedef DECLCALLBACKTYPE(int, FNDBGFR3TYPEDUMP,(uint32_t off, const char *pszField, uint32_t iLvl, + const char *pszType, uint32_t fTypeFlags, + uint32_t cElements, void *pvUser)); +/** Pointer to a FNDBGFR3TYPEDUMP. */ +typedef FNDBGFR3TYPEDUMP *PFNDBGFR3TYPEDUMP; + +VMMR3DECL(int) DBGFR3TypeRegister( PUVM pUVM, uint32_t cTypes, PCDBGFTYPEREG paTypes); +VMMR3DECL(int) DBGFR3TypeDeregister(PUVM pUVM, const char *pszType); +VMMR3DECL(int) DBGFR3TypeQueryReg( PUVM pUVM, const char *pszType, PCDBGFTYPEREG *ppTypeReg); + +VMMR3DECL(int) DBGFR3TypeQuerySize( PUVM pUVM, const char *pszType, size_t *pcbType); +VMMR3DECL(int) DBGFR3TypeSetSize( PUVM pUVM, const char *pszType, size_t cbType); +VMMR3DECL(int) DBGFR3TypeDumpEx( PUVM pUVM, const char *pszType, uint32_t fFlags, + uint32_t cLvlMax, PFNDBGFR3TYPEDUMP pfnDump, void *pvUser); +VMMR3DECL(int) DBGFR3TypeQueryValByType(PUVM pUVM, PCDBGFADDRESS pAddress, const char *pszType, + PDBGFTYPEVAL *ppVal); +VMMR3DECL(void) DBGFR3TypeValFree(PDBGFTYPEVAL pVal); +VMMR3DECL(int) DBGFR3TypeValDumpEx(PUVM pUVM, PCDBGFADDRESS pAddress, const char *pszType, uint32_t fFlags, + uint32_t cLvlMax, FNDBGFR3TYPEVALDUMP pfnDump, void *pvUser); + +/** @} */ + + +/** @defgroup grp_dbgf_flow The DBGF control flow graph Interface. + * @{ + */ + +/** A DBGF control flow graph handle. */ +typedef struct DBGFFLOWINT *DBGFFLOW; +/** Pointer to a DBGF control flow graph handle. */ +typedef DBGFFLOW *PDBGFFLOW; +/** A DBGF control flow graph basic block handle. */ +typedef struct DBGFFLOWBBINT *DBGFFLOWBB; +/** Pointer to a DBGF control flow graph basic block handle. */ +typedef DBGFFLOWBB *PDBGFFLOWBB; +/** A DBGF control flow graph branch table handle. */ +typedef struct DBGFFLOWBRANCHTBLINT *DBGFFLOWBRANCHTBL; +/** Pointer to a DBGF flow control graph branch table handle. */ +typedef DBGFFLOWBRANCHTBL *PDBGFFLOWBRANCHTBL; +/** A DBGF control flow graph iterator. */ +typedef struct DBGFFLOWITINT *DBGFFLOWIT; +/** Pointer to a control flow graph iterator. */ +typedef DBGFFLOWIT *PDBGFFLOWIT; +/** A DBGF control flow graph branch table iterator. */ +typedef struct DBGFFLOWBRANCHTBLITINT *DBGFFLOWBRANCHTBLIT; +/** Pointer to a control flow graph branch table iterator. */ +typedef DBGFFLOWBRANCHTBLIT *PDBGFFLOWBRANCHTBLIT; + +/** @name DBGFFLOWBB Flags. + * @{ */ +/** The basic block is the entry into the owning control flow graph. */ +#define DBGF_FLOW_BB_F_ENTRY RT_BIT_32(0) +/** The basic block was not populated because the limit was reached. */ +#define DBGF_FLOW_BB_F_EMPTY RT_BIT_32(1) +/** The basic block is not complete because an error happened during disassembly. */ +#define DBGF_FLOW_BB_F_INCOMPLETE_ERR RT_BIT_32(2) +/** The basic block is reached through a branch table. */ +#define DBGF_FLOW_BB_F_BRANCH_TABLE RT_BIT_32(3) +/** The basic block consists only of a single call instruction because + * DBGF_FLOW_CREATE_F_CALL_INSN_SEPARATE_BB was given. */ +#define DBGF_FLOW_BB_F_CALL_INSN RT_BIT_32(4) +/** The branch target of the call instruction could be deduced and can be queried with + * DBGFR3FlowBbGetBranchAddress(). May only be available when DBGF_FLOW_BB_F_CALL_INSN + * is set. */ +#define DBGF_FLOW_BB_F_CALL_INSN_TARGET_KNOWN RT_BIT_32(5) +/** @} */ + +/** @name Flags controlling the creating of a control flow graph. + * @{ */ +/** Default options. */ +#define DBGF_FLOW_CREATE_F_DEFAULT 0 +/** Tries to resolve indirect branches, useful for code using + * jump tables generated for large switch statements by some compilers. */ +#define DBGF_FLOW_CREATE_F_TRY_RESOLVE_INDIRECT_BRANCHES RT_BIT_32(0) +/** Call instructions are placed in a separate basic block. */ +#define DBGF_FLOW_CREATE_F_CALL_INSN_SEPARATE_BB RT_BIT_32(1) +/** @} */ + +/** + * DBGF control graph basic block end type. + */ +typedef enum DBGFFLOWBBENDTYPE +{ + /** Invalid type. */ + DBGFFLOWBBENDTYPE_INVALID = 0, + /** Basic block is the exit block and has no successor. */ + DBGFFLOWBBENDTYPE_EXIT, + /** Basic block is the last disassembled block because the + * maximum amount to disassemble was reached but is not an + * exit block - no successors. + */ + DBGFFLOWBBENDTYPE_LAST_DISASSEMBLED, + /** Unconditional control flow change because the successor is referenced by multiple + * basic blocks. - 1 successor. */ + DBGFFLOWBBENDTYPE_UNCOND, + /** Unconditional control flow change because of an direct branch - 1 successor. */ + DBGFFLOWBBENDTYPE_UNCOND_JMP, + /** Unconditional control flow change because of an indirect branch - n successors. */ + DBGFFLOWBBENDTYPE_UNCOND_INDIRECT_JMP, + /** Conditional control flow change - 2 successors. */ + DBGFFLOWBBENDTYPE_COND, + /** 32bit hack. */ + DBGFFLOWBBENDTYPE_32BIT_HACK = 0x7fffffff +} DBGFFLOWBBENDTYPE; + +/** + * DBGF control flow graph iteration order. + */ +typedef enum DBGFFLOWITORDER +{ + /** Invalid order. */ + DBGFFLOWITORDER_INVALID = 0, + /** From lowest to highest basic block start address. */ + DBGFFLOWITORDER_BY_ADDR_LOWEST_FIRST, + /** From highest to lowest basic block start address. */ + DBGFFLOWITORDER_BY_ADDR_HIGHEST_FIRST, + /** Depth first traversing starting from the entry block. */ + DBGFFLOWITORDER_DEPTH_FRIST, + /** Breadth first traversing starting from the entry block. */ + DBGFFLOWITORDER_BREADTH_FIRST, + /** Usual 32bit hack. */ + DBGFFLOWITORDER_32BIT_HACK = 0x7fffffff +} DBGFFLOWITORDER; +/** Pointer to a iteration order enum. */ +typedef DBGFFLOWITORDER *PDBGFFLOWITORDER; + + +VMMR3DECL(int) DBGFR3FlowCreate(PUVM pUVM, VMCPUID idCpu, PDBGFADDRESS pAddressStart, uint32_t cbDisasmMax, + uint32_t fFlagsFlow, uint32_t fFlagsDisasm, PDBGFFLOW phFlow); +VMMR3DECL(uint32_t) DBGFR3FlowRetain(DBGFFLOW hFlow); +VMMR3DECL(uint32_t) DBGFR3FlowRelease(DBGFFLOW hFlow); +VMMR3DECL(int) DBGFR3FlowQueryStartBb(DBGFFLOW hFlow, PDBGFFLOWBB phFlowBb); +VMMR3DECL(int) DBGFR3FlowQueryBbByAddress(DBGFFLOW hFlow, PDBGFADDRESS pAddr, PDBGFFLOWBB phFlowBb); +VMMR3DECL(int) DBGFR3FlowQueryBranchTblByAddress(DBGFFLOW hFlow, PDBGFADDRESS pAddr, PDBGFFLOWBRANCHTBL phFlowBranchTbl); +VMMR3DECL(uint32_t) DBGFR3FlowGetBbCount(DBGFFLOW hFlow); +VMMR3DECL(uint32_t) DBGFR3FlowGetBranchTblCount(DBGFFLOW hFlow); +VMMR3DECL(uint32_t) DBGFR3FlowGetCallInsnCount(DBGFFLOW hFlow); + +VMMR3DECL(uint32_t) DBGFR3FlowBbRetain(DBGFFLOWBB hFlowBb); +VMMR3DECL(uint32_t) DBGFR3FlowBbRelease(DBGFFLOWBB hFlowBb); +VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBbGetStartAddress(DBGFFLOWBB hFlowBb, PDBGFADDRESS pAddrStart); +VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBbGetEndAddress(DBGFFLOWBB hFlowBb, PDBGFADDRESS pAddrEnd); +VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBbGetBranchAddress(DBGFFLOWBB hFlowBb, PDBGFADDRESS pAddrTarget); +VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBbGetFollowingAddress(DBGFFLOWBB hFlowBb, PDBGFADDRESS pAddrFollow); +VMMR3DECL(DBGFFLOWBBENDTYPE) DBGFR3FlowBbGetType(DBGFFLOWBB hFlowBb); +VMMR3DECL(uint32_t) DBGFR3FlowBbGetInstrCount(DBGFFLOWBB hFlowBb); +VMMR3DECL(uint32_t) DBGFR3FlowBbGetFlags(DBGFFLOWBB hFlowBb); +VMMR3DECL(int) DBGFR3FlowBbQueryBranchTbl(DBGFFLOWBB hFlowBb, PDBGFFLOWBRANCHTBL phBranchTbl); +VMMR3DECL(int) DBGFR3FlowBbQueryError(DBGFFLOWBB hFlowBb, const char **ppszErr); +VMMR3DECL(int) DBGFR3FlowBbQueryInstr(DBGFFLOWBB hFlowBb, uint32_t idxInstr, PDBGFADDRESS pAddrInstr, + uint32_t *pcbInstr, const char **ppszInstr); +VMMR3DECL(int) DBGFR3FlowBbQuerySuccessors(DBGFFLOWBB hFlowBb, PDBGFFLOWBB phFlowBbFollow, + PDBGFFLOWBB phFlowBbTarget); +VMMR3DECL(uint32_t) DBGFR3FlowBbGetRefBbCount(DBGFFLOWBB hFlowBb); +VMMR3DECL(int) DBGFR3FlowBbGetRefBb(DBGFFLOWBB hFlowBb, PDBGFFLOWBB pahFlowBbRef, uint32_t cRef); + +VMMR3DECL(uint32_t) DBGFR3FlowBranchTblRetain(DBGFFLOWBRANCHTBL hFlowBranchTbl); +VMMR3DECL(uint32_t) DBGFR3FlowBranchTblRelease(DBGFFLOWBRANCHTBL hFlowBranchTbl); +VMMR3DECL(uint32_t) DBGFR3FlowBranchTblGetSlots(DBGFFLOWBRANCHTBL hFlowBranchTbl); +VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBranchTblGetStartAddress(DBGFFLOWBRANCHTBL hFlowBranchTbl, PDBGFADDRESS pAddrStart); +VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBranchTblGetAddrAtSlot(DBGFFLOWBRANCHTBL hFlowBranchTbl, uint32_t idxSlot, PDBGFADDRESS pAddrSlot); +VMMR3DECL(int) DBGFR3FlowBranchTblQueryAddresses(DBGFFLOWBRANCHTBL hFlowBranchTbl, PDBGFADDRESS paAddrs, uint32_t cAddrs); + +VMMR3DECL(int) DBGFR3FlowItCreate(DBGFFLOW hFlow, DBGFFLOWITORDER enmOrder, PDBGFFLOWIT phFlowIt); +VMMR3DECL(void) DBGFR3FlowItDestroy(DBGFFLOWIT hFlowIt); +VMMR3DECL(DBGFFLOWBB) DBGFR3FlowItNext(DBGFFLOWIT hFlowIt); +VMMR3DECL(int) DBGFR3FlowItReset(DBGFFLOWIT hFlowIt); + +VMMR3DECL(int) DBGFR3FlowBranchTblItCreate(DBGFFLOW hFlow, DBGFFLOWITORDER enmOrder, PDBGFFLOWBRANCHTBLIT phFlowBranchTblIt); +VMMR3DECL(void) DBGFR3FlowBranchTblItDestroy(DBGFFLOWBRANCHTBLIT hFlowBranchTblIt); +VMMR3DECL(DBGFFLOWBRANCHTBL) DBGFR3FlowBranchTblItNext(DBGFFLOWBRANCHTBLIT hFlowBranchTblIt); +VMMR3DECL(int) DBGFR3FlowBranchTblItReset(DBGFFLOWBRANCHTBLIT hFlowBranchTblIt); + +/** @} */ + + +/** @defgroup grp_dbgf_misc Misc DBGF interfaces. + * @{ */ +VMMR3DECL(VBOXSTRICTRC) DBGFR3ReportBugCheck(PVM pVM, PVMCPU pVCpu, DBGFEVENTTYPE enmEvent, uint64_t uBugCheck, + uint64_t uP1, uint64_t uP2, uint64_t uP3, uint64_t uP4); +VMMR3DECL(int) DBGFR3FormatBugCheck(PUVM pUVM, char *pszDetails, size_t cbDetails, + uint64_t uP0, uint64_t uP1, uint64_t uP2, uint64_t uP3, uint64_t uP4); +/** @} */ +#endif /* IN_RING3 */ + + +/** @defgroup grp_dbgf_tracer DBGF event tracing. + * @{ */ +#ifdef IN_RING3 +VMMR3_INT_DECL(int) DBGFR3TracerRegisterEvtSrc(PVM pVM, const char *pszName, PDBGFTRACEREVTSRC phEvtSrc); +VMMR3_INT_DECL(int) DBGFR3TracerDeregisterEvtSrc(PVM pVM, DBGFTRACEREVTSRC hEvtSrc); +VMMR3_INT_DECL(int) DBGFR3TracerEvtIoPortCreate(PVM pVM, DBGFTRACEREVTSRC hEvtSrc, uint64_t hRegion, RTIOPORT cPorts, uint32_t fFlags, + uint32_t iPciRegion); +VMMR3_INT_DECL(int) DBGFR3TracerEvtMmioCreate(PVM pVM, DBGFTRACEREVTSRC hEvtSrc, uint64_t hRegion, RTGCPHYS cbRegion, uint32_t fFlags, + uint32_t iPciRegion); +#endif + +VMM_INT_DECL(int) DBGFTracerEvtMmioMap(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, uint64_t hRegion, RTGCPHYS GCPhysMmio); +VMM_INT_DECL(int) DBGFTracerEvtMmioUnmap(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, uint64_t hRegion); +VMM_INT_DECL(int) DBGFTracerEvtMmioRead(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, uint64_t hRegion, RTGCPHYS offMmio, const void *pvVal, size_t cbVal); +VMM_INT_DECL(int) DBGFTracerEvtMmioWrite(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, uint64_t hRegion, RTGCPHYS offMmio, const void *pvVal, size_t cbVal); +VMM_INT_DECL(int) DBGFTracerEvtMmioFill(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, uint64_t hRegion, RTGCPHYS offMmio, uint32_t u32Item, uint32_t cbItem, uint32_t cItems); +VMM_INT_DECL(int) DBGFTracerEvtIoPortMap(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, uint64_t hIoPorts, RTIOPORT IoPortBase); +VMM_INT_DECL(int) DBGFTracerEvtIoPortUnmap(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, uint64_t hIoPorts); +VMM_INT_DECL(int) DBGFTracerEvtIoPortRead(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, uint64_t hIoPorts, RTIOPORT offPort, const void *pvVal, size_t cbVal); +VMM_INT_DECL(int) DBGFTracerEvtIoPortReadStr(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, uint64_t hIoPorts, RTIOPORT offPort, const void *pv, size_t cb, + uint32_t cTransfersReq, uint32_t cTransfersRet); +VMM_INT_DECL(int) DBGFTracerEvtIoPortWrite(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, uint64_t hIoPorts, RTIOPORT offPort, const void *pvVal, size_t cbVal); +VMM_INT_DECL(int) DBGFTracerEvtIoPortWriteStr(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, uint64_t hIoPorts, RTIOPORT offPort, const void *pv, size_t cb, + uint32_t cTransfersReq, uint32_t cTransfersRet); +VMM_INT_DECL(int) DBGFTracerEvtIrq(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, int32_t iIrq, int32_t fIrqLvl); +VMM_INT_DECL(int) DBGFTracerEvtIoApicMsi(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, RTGCPHYS GCPhys, uint32_t u32Val); +VMM_INT_DECL(int) DBGFTracerEvtGCPhysRead(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, RTGCPHYS GCPhys, const void *pvBuf, size_t cbRead); +VMM_INT_DECL(int) DBGFTracerEvtGCPhysWrite(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite); +/** @} */ + + +/** @defgroup grp_dbgf_sample_report DBGF sample report. + * @{ */ + +/** + * Callback which provides progress information about a currently running + * lengthy operation. + * + * @return VBox status code. + * @retval VERR_DBGF_CANCELLED to cancel the operation. + * @param pvUser The opaque user data associated with this interface. + * @param uPercentage Completion percentage. + */ +typedef DECLCALLBACKTYPE(int, FNDBGFPROGRESS,(void *pvUser, unsigned uPercentage)); +/** Pointer to FNDBGFPROGRESS() */ +typedef FNDBGFPROGRESS *PFNDBGFPROGRESS; + +/** @name Flags to pass to DBGFR3SampleReportCreate(). + * @{ */ +/** The report creates the call stack in reverse order (bottom to top). */ +#define DBGF_SAMPLE_REPORT_F_STACK_REVERSE RT_BIT(0) +/** Mask containing the valid flags. */ +#define DBGF_SAMPLE_REPORT_F_VALID_MASK UINT32_C(0x00000001) +/** @} */ + +VMMR3DECL(int) DBGFR3SampleReportCreate(PUVM pUVM, uint32_t cSampleIntervalMs, uint32_t fFlags, PDBGFSAMPLEREPORT phSample); +VMMR3DECL(uint32_t) DBGFR3SampleReportRetain(DBGFSAMPLEREPORT hSample); +VMMR3DECL(uint32_t) DBGFR3SampleReportRelease(DBGFSAMPLEREPORT hSample); +VMMR3DECL(int) DBGFR3SampleReportStart(DBGFSAMPLEREPORT hSample, uint64_t cSampleUs, PFNDBGFPROGRESS pfnProgress, void *pvUser); +VMMR3DECL(int) DBGFR3SampleReportStop(DBGFSAMPLEREPORT hSample); +VMMR3DECL(int) DBGFR3SampleReportDumpToFile(DBGFSAMPLEREPORT hSample, const char *pszFilename); +/** @} */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_dbgf_h */ + diff --git a/include/VBox/vmm/dbgfcorefmt.h b/include/VBox/vmm/dbgfcorefmt.h new file mode 100644 index 00000000..c2b0cd5e --- /dev/null +++ b/include/VBox/vmm/dbgfcorefmt.h @@ -0,0 +1,188 @@ +/** @file + * DBGF - Debugger Facility, VM Core File Format. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_dbgfcorefmt_h +#define VBOX_INCLUDED_vmm_dbgfcorefmt_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <VBox/vmm/cpumctx.h> +#include <iprt/assertcompile.h> + + +RT_C_DECLS_BEGIN + + +/** @defgroup 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 X86XSAVEAREA in x86.h for the CPU's + * FPU/SSE/AVX/XXX state. + * @todo Add the note names. + * + * @{ + */ + +/** DBGCORECOREDESCRIPTOR::u32Magic. */ +#define DBGFCORE_MAGIC UINT32_C(0xc01ac0de) +/** DBGCORECOREDESCRIPTOR::u32FmtVersion. */ +#define DBGFCORE_FMT_VERSION UINT32_C(0x00010006) + +/** + * An x86 segment selector. + */ +typedef struct DBGFCORESEL +{ + uint64_t uBase; + uint32_t uLimit; + uint32_t uAttr; + uint16_t uSel; + uint16_t uReserved0; + uint32_t uReserved1; +} DBGFCORESEL; +AssertCompileSizeAlignment(DBGFCORESEL, 8); + +/** + * A gdtr/ldtr descriptor. + */ +typedef struct DBGFCOREXDTR +{ + uint64_t uAddr; + uint32_t cb; + uint32_t uReserved0; +} DBGFCOREXDTR; +AssertCompileSizeAlignment(DBGFCOREXDTR, 8); + +/** + * A simpler to parse CPU dump than CPUMCTX. + * + * Please bump DBGFCORE_FMT_VERSION by 1 if you make any changes to this + * structure. + */ +typedef struct DBGFCORECPU +{ + uint64_t rax; + uint64_t rbx; + uint64_t rcx; + uint64_t rdx; + uint64_t rsi; + uint64_t 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; + uint64_t rip; + uint64_t rsp; + uint64_t rbp; + uint64_t rflags; + DBGFCORESEL cs; + DBGFCORESEL ds; + DBGFCORESEL es; + DBGFCORESEL fs; + DBGFCORESEL gs; + DBGFCORESEL ss; + uint64_t cr0; + uint64_t cr2; + uint64_t cr3; + uint64_t cr4; + uint64_t dr[8]; + DBGFCOREXDTR gdtr; + DBGFCOREXDTR idtr; + DBGFCORESEL ldtr; + DBGFCORESEL tr; + struct + { + uint64_t cs; + uint64_t eip; + uint64_t esp; + } sysenter; + uint64_t msrEFER; + uint64_t msrSTAR; + uint64_t msrPAT; + uint64_t msrLSTAR; + uint64_t msrCSTAR; + uint64_t msrSFMASK; + uint64_t msrKernelGSBase; + uint64_t msrApicBase; + uint64_t msrTscAux; + uint64_t aXcr[2]; + uint32_t cbExt; + uint32_t uPadding0; + X86XSAVEAREA ext; +} DBGFCORECPU; +/** Pointer to a DBGF-core CPU. */ +typedef DBGFCORECPU *PDBGFCORECPU; +/** Pointer to the const DBGF-core CPU. */ +typedef const DBGFCORECPU *PCDBGFCORECPU; +AssertCompileMemberAlignment(DBGFCORECPU, cr0, 8); +AssertCompileMemberAlignment(DBGFCORECPU, msrEFER, 8); +AssertCompileMemberAlignment(DBGFCORECPU, ext, 8); +AssertCompileSizeAlignment(DBGFCORECPU, 8); + +/** + * 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 /* !VBOX_INCLUDED_vmm_dbgfcorefmt_h */ + diff --git a/include/VBox/vmm/dbgfflowtrace.h b/include/VBox/vmm/dbgfflowtrace.h new file mode 100644 index 00000000..4906fe7e --- /dev/null +++ b/include/VBox/vmm/dbgfflowtrace.h @@ -0,0 +1,400 @@ +/** @file + * DBGF - Debugger Facility, Guest execution flow tracing. + */ + +/* + * Copyright (C) 2020-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_dbgfflowtrace_h +#define VBOX_INCLUDED_vmm_dbgfflowtrace_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <VBox/vmm/dbgf.h> + +RT_C_DECLS_BEGIN +/** @defgroup grp_dbgf_flowtrace Guest Execution Flow Tracing + * @ingroup grp_dbgf + * + * @{ + */ + +/** A DBGF flow trace module handle. */ +typedef struct DBGFFLOWTRACEMODINT *DBGFFLOWTRACEMOD; +/** Pointer to a DBGF flow trace module handle. */ +typedef DBGFFLOWTRACEMOD *PDBGFFLOWTRACEMOD; +/** A DBGF flow trace probe handle. */ +typedef struct DBGFFLOWTRACEPROBEINT *DBGFFLOWTRACEPROBE; +/** Pointer to a DBGF flow trace state probe handle. */ +typedef DBGFFLOWTRACEPROBE *PDBGFFLOWTRACEPROBE; +/** A DBGF flow trace report handle. */ +typedef struct DBGFFLOWTRACEREPORTINT *DBGFFLOWTRACEREPORT; +/** Pointer to a DBGF flow trace report handle. */ +typedef DBGFFLOWTRACEREPORT *PDBGFFLOWTRACEREPORT; +/** A DBGF flow trace record handle. */ +typedef struct DBGFFLOWTRACERECORDINT *DBGFFLOWTRACERECORD; +/** Pointer to a DBGF flow trace record handle. */ +typedef DBGFFLOWTRACERECORD *PDBGFFLOWTRACERECORD; + + +/** Pointer to a flow trace probe entry. */ +typedef struct DBGFFLOWTRACEPROBEENTRY *PDBGFFLOWTRACEPROBEENTRY; +/** Pointer to a const flow trace probe entry. */ +typedef const struct DBGFFLOWTRACEPROBEENTRY *PCDBGFFLOWTRACEPROBEENTRY; + +/** @name Flags controlling the type of the addition of a single probe. + * @{ */ +/** Default options. */ +#define DBGF_FLOW_TRACE_PROBE_ADD_F_DEFAULT DBGF_FLOW_TRACE_PROBE_ADD_F_BEFORE_EXEC +/** Collects the data specified by the data probe before the instruction is executed. */ +#define DBGF_FLOW_TRACE_PROBE_ADD_F_BEFORE_EXEC RT_BIT_32(0) +/** Collects the data specified by the data probe after the instruction was executed. */ +#define DBGF_FLOW_TRACE_PROBE_ADD_F_AFTER_EXEC RT_BIT_32(1) +/** Mask of all valid flags. */ +#define DBGF_FLOW_TRACE_PROBE_ADD_F_VALID_MASK ( DBGF_FLOW_TRACE_PROBE_ADD_F_BEFORE_EXEC \ + | DBGF_FLOW_TRACE_PROBE_ADD_F_AFTER_EXEC) +/** @} */ + + +/** + * Probe entry type. + */ +typedef enum DBGFFLOWTRACEPROBEENTRYTYPE +{ + /** Invalid type. */ + DBGFFLOWTRACEPROBEENTRYTYPE_INVALID = 0, + /** Register. */ + DBGFFLOWTRACEPROBEENTRYTYPE_REG, + /** Constant memory buffer pointer. */ + DBGFFLOWTRACEPROBEENTRYTYPE_CONST_MEM, + /** Indirect memory buffer pointer, obtained from the base and index register + * and a constant scale. */ + DBGFFLOWTRACEPROBEENTRYTYPE_INDIRECT_MEM, + /** Callback. */ + DBGFFLOWTRACEPROBEENTRYTYPE_CALLBACK, + /** Halt in the debugger when the entry is collected. */ + DBGFFLOWTRACEPROBEENTRYTYPE_DEBUGGER, + /** 32bit hack. */ + DBGFFLOWTRACEPROBEENTRYTYPE_32BIT_HACK = 0x7fffffff +} DBGFFLOWTRACEPROBEENTRYTYPE; + + +/** + * Register descriptor for a probe entry. + */ +typedef struct DBGFFLOWTRACEPROBEENTRYREG +{ + /** The register name - see DBGFR3RegNm*. */ + const char *pszName; + /** The size of the value in bytes. */ + DBGFREGVALTYPE enmType; +} DBGFFLOWTRACEPROBEENTRYREG; +/** Pointer to data probe register entry. */ +typedef DBGFFLOWTRACEPROBEENTRYREG *PDBGFFLOWTRACEPROBEENTRYREG; +/** Pointer to a const probe register entry. */ +typedef const DBGFFLOWTRACEPROBEENTRYREG *PCDBGFFLOWTRACEPROBEENTRYREG; + + +/** + * Flow trace probe callback. + * + * @returns VBox status code, any error aborts continuing fetching the data for the + * probe containing this callback. + * @param pUVM The usermode VM handle. + * @param idCpu The ID of the vCPU the probe as fired. + * @param hFlowTraceMod The handle to the flow trace module the probe was fired for. + * @param pAddrProbe The guest address the probe was fired at. + * @param hFlowTraceProbe The flow trace probe handle.this callback is in. + * @param pProbeEntry The probe entry this callback is part of. + * @param pvUser The opaque user data for the callback. + */ +typedef DECLCALLBACKTYPE(int, FNDBGFFLOWTRACEPROBECALLBACK, (PUVM pUVM, VMCPUID idCpu, DBGFFLOWTRACEMOD hFlowTraceMod, + PCDBGFADDRESS pAddrProbe, DBGFFLOWTRACEPROBE hFlowTraceProbe, + PCDBGFFLOWTRACEPROBEENTRY pProbeEntry, + void *pvUser)); +/** Pointer to a flow trace probe callback. */ +typedef FNDBGFFLOWTRACEPROBECALLBACK *PFNDBGFFLOWTRACEPROBECALLBACK; + + +/** + * Trace flow probe entry. + */ +typedef struct DBGFFLOWTRACEPROBEENTRY +{ + /** Entry type. */ + DBGFFLOWTRACEPROBEENTRYTYPE enmType; + /** Description for this entry, optional. */ + const char *pszDesc; + /** The data based on the entry type. */ + union + { + /** Register. */ + DBGFFLOWTRACEPROBEENTRYREG Reg; + /** Constant memory pointer. */ + struct + { + /** The address of the memory buffer. */ + DBGFADDRESS AddrMem; + /** Number of bytes to log. */ + size_t cbMem; + } ConstMem; + /** Indirect memory */ + struct + { + /** The base register. */ + DBGFFLOWTRACEPROBEENTRYREG RegBase; + /** The index register. */ + DBGFFLOWTRACEPROBEENTRYREG RegIndex; + /** The scale to apply to the index. */ + uint8_t uScale; + /** A constant offset which is applied at the end. */ + RTGCINTPTR iOffset; + /** Number of bytes to log. */ + size_t cbMem; + } IndirectMem; + /** Callback. */ + struct + { + /** The callback to call. */ + PFNDBGFFLOWTRACEPROBECALLBACK pfnCallback; + /** The opaque user data to provide. */ + void *pvUser; + } Callback; + } Type; +} DBGFFLOWTRACEPROBEENTRY; + + +/** + * Flow trace probe value. + */ +typedef struct DBGFFLOWTRACEPROBEVAL +{ + /** Pointer to the flow trace probe entry this value is for. */ + PCDBGFFLOWTRACEPROBEENTRY pProbeEntry; + /** Data based on the type in the entry. */ + union + { + /** Register value. */ + DBGFREGENTRYNM Reg; + /** Memory value (constant pointer or indirect). */ + struct + { + /** The guest address logged. */ + DBGFADDRESS Addr; + /** Pointer to the data logged. */ + const void *pvBuf; + /** Number of bytes logged. */ + size_t cbBuf; + } Mem; + } Type; +} DBGFFLOWTRACEPROBEVAL; +/** Pointer to a flow trace probe value. */ +typedef DBGFFLOWTRACEPROBEVAL *PDBGFFLOWTRACEPROBEVAL; +/** Pointer to a const flow trace probe value. */ +typedef const DBGFFLOWTRACEPROBEVAL *PCDBGFFLOWTRACEPROBEVAL; + +/** + * Flow trace report filter operation. + */ +typedef enum DBGFFLOWTRACEREPORTFILTEROP +{ + /** Invalid filter operation. */ + DBGFFLOWTRACEREPORTFILTEROP_INVALID = 0, + /** All filters must match with the record. */ + DBGFFLOWTRACEREPORTFILTEROP_AND, + /** Only one filter must match with the record. */ + DBGFFLOWTRACEREPORTFILTEROP_OR, + /** 32bit hack. */ + DBGFFLOWTRACEREPORTFILTEROP_32BIT_HACK = 0x7fffffff +} DBGFFLOWTRACEREPORTFILTEROP; + + +/** + * Flow trace report filter type. + */ +typedef enum DBGFFLOWTRACEREPORTFILTERTYPE +{ + /** Invalid filter type. */ + DBGFFLOWTRACEREPORTFILTERTYPE_INVALID = 0, + /** Filter by sequence number. */ + DBGFFLOWTRACEREPORTFILTERTYPE_SEQ_NUM, + /** Filter by timestamp. */ + DBGFFLOWTRACEREPORTFILTERTYPE_TIMESTAMP, + /** Filter by probe address. */ + DBGFFLOWTRACEREPORTFILTERTYPE_ADDR, + /** Filter by CPU ID. */ + DBGFFLOWTRACEREPORTFILTERTYPE_VMCPU_ID, + /** Filter by specific probe data. */ + DBGFFLOWTRACEREPORTFILTERTYPE_PROBE_DATA, + /** 32bit hack. */ + DBGFFLOWTRACEREPORTFILTERTYPE_32BIT_HACK = 0x7fffffff +} DBGFFLOWTRACEREPORTFILTERTYPE; + + +/** + * Flow trace report filter. + */ +typedef struct DBGFFLOWTRACEREPORTFILTER +{ + /** Filter type. */ + DBGFFLOWTRACEREPORTFILTERTYPE enmType; + /** Filter data, type dependent. */ + struct + { + /** Sequence number filtering. */ + struct + { + /** Sequence number filtering, start value. */ + uint64_t u64SeqNoFirst; + /** Sequence number filtering, last value. */ + uint64_t u64SeqNoLast; + } SeqNo; + /** Timestamp filtering. */ + struct + { + /** Start value. */ + uint64_t u64TsFirst; + /** Last value. */ + uint64_t u64TsLast; + } Timestamp; + /** Probe address filtering. */ + struct + { + /** Start address. */ + DBGFADDRESS AddrStart; + /** Last address. */ + DBGFADDRESS AddrLast; + } Addr; + /** vCPU id filtering. */ + struct + { + /** Start CPU id. */ + VMCPUID idCpuStart; + /** Last CPU id. */ + VMCPUID idCpuLast; + } VCpuId; + /** Probe data filtering. */ + struct + { + /** Pointer to the probe value array. */ + PCDBGFFLOWTRACEPROBEVAL paVal; + /** Number of entries in the array for filtering. */ + uint32_t cVals; + /** Flag whether to look into the common values or the probe specific ones. */ + bool fValCmn; + } ProbeData; + } Type; +} DBGFFLOWTRACEREPORTFILTER; +/** Pointer to a flow trace report filter. */ +typedef DBGFFLOWTRACEREPORTFILTER *PDBGFFLOWTRACEREPORTFILTER; + + +/** @name Flags controlling filtering records. + * @{ */ +/** Add records which don't match the filter. */ +#define DBGF_FLOW_TRACE_REPORT_FILTER_F_REVERSE RT_BIT_32(0) +/** Mask of all valid flags. */ +#define DBGF_FLOW_TRACE_REPORT_FILTER_F_VALID (DBGF_FLOW_TRACE_REPORT_FILTER_F_REVERSE) +/** @} */ + + +/** + * Flow trace report enumeration callback. + * + * @returns VBox status code, any non VINF_SUCCESS code aborts the enumeration and is returned + * by DBGFR3FlowTraceReportEnumRecords(). + * @param hFlowTraceReport The flow trace report handle being enumerated. + * @param hFlowTraceRecord The flow trace record handle. + * @param pvUser Opaque user data given in DBGFR3FlowTraceReportEnumRecords(). + */ +typedef DECLCALLBACKTYPE(int, FNDBGFFLOWTRACEREPORTENUMCLBK,(DBGFFLOWTRACEREPORT hFlowTraceReport, + DBGFFLOWTRACERECORD hFlowTraceRecord, + void *pvUser)); +/** Pointer to a record enumeration callback. */ +typedef FNDBGFFLOWTRACEREPORTENUMCLBK *PFNDBGFFLOWTRACEREPORTENUMCLBK; + + +VMMR3DECL(int) DBGFR3FlowTraceModCreate(PUVM pUVM, VMCPUID idCpu, + DBGFFLOWTRACEPROBE hFlowTraceProbeCommon, + PDBGFFLOWTRACEMOD phFlowTraceMod); +VMMR3DECL(int) DBGFR3FlowTraceModCreateFromFlowGraph(PUVM pUVM, VMCPUID idCpu, DBGFFLOW hFlow, + DBGFFLOWTRACEPROBE hFlowTraceProbeCommon, + DBGFFLOWTRACEPROBE hFlowTraceProbeEntry, + DBGFFLOWTRACEPROBE hFlowTraceProbeRegular, + DBGFFLOWTRACEPROBE hFlowTraceProbeExit, + PDBGFFLOWTRACEMOD phFlowTraceMod); +VMMR3DECL(uint32_t) DBGFR3FlowTraceModRetain(DBGFFLOWTRACEMOD hFlowTraceMod); +VMMR3DECL(uint32_t) DBGFR3FlowTraceModRelease(DBGFFLOWTRACEMOD hFlowTraceMod); +VMMR3DECL(int) DBGFR3FlowTraceModEnable(DBGFFLOWTRACEMOD hFlowTraceMod, uint32_t cHits, uint32_t cRecordsMax); +VMMR3DECL(int) DBGFR3FlowTraceModDisable(DBGFFLOWTRACEMOD hFlowTraceMod); +VMMR3DECL(int) DBGFR3FlowTraceModQueryReport(DBGFFLOWTRACEMOD hFlowTraceMod, + PDBGFFLOWTRACEREPORT phFlowTraceReport); +VMMR3DECL(int) DBGFR3FlowTraceModClear(DBGFFLOWTRACEMOD hFlowTraceMod); +VMMR3DECL(int) DBGFR3FlowTraceModAddProbe(DBGFFLOWTRACEMOD hFlowTraceMod, PCDBGFADDRESS pAddrProbe, + DBGFFLOWTRACEPROBE hFlowTraceProbe, uint32_t fFlags); + +VMMR3DECL(int) DBGFR3FlowTraceProbeCreate(PUVM pUVM, const char *pszDescr, PDBGFFLOWTRACEPROBE phFlowTraceProbe); +VMMR3DECL(uint32_t) DBGFR3FlowTraceProbeRetain(DBGFFLOWTRACEPROBE hFlowTraceProbe); +VMMR3DECL(uint32_t) DBGFR3FlowTraceProbeRelease(DBGFFLOWTRACEPROBE hFlowTraceProbe); +VMMR3DECL(int) DBGFR3FlowTraceProbeEntriesAdd(DBGFFLOWTRACEPROBE hFlowTraceProbe, + PCDBGFFLOWTRACEPROBEENTRY paEntries, uint32_t cEntries); + +VMMR3DECL(uint32_t) DBGFR3FlowTraceReportRetain(DBGFFLOWTRACEREPORT hFlowTraceReport); +VMMR3DECL(uint32_t) DBGFR3FlowTraceReportRelease(DBGFFLOWTRACEREPORT hFlowTraceReport); +VMMR3DECL(uint32_t) DBGFR3FlowTraceReportGetRecordCount(DBGFFLOWTRACEREPORT hFlowTraceReport); +VMMR3DECL(int) DBGFR3FlowTraceReportQueryRecord(DBGFFLOWTRACEREPORT hFlowTraceReport, uint32_t idxRec, PDBGFFLOWTRACERECORD phFlowTraceRec); +VMMR3DECL(int) DBGFR3FlowTraceReportQueryFiltered(DBGFFLOWTRACEREPORT hFlowTraceReport, uint32_t fFlags, + PDBGFFLOWTRACEREPORTFILTER paFilters, uint32_t cFilters, + DBGFFLOWTRACEREPORTFILTEROP enmOp, + PDBGFFLOWTRACEREPORT phFlowTraceReportFiltered); +VMMR3DECL(int) DBGFR3FlowTraceReportEnumRecords(DBGFFLOWTRACEREPORT hFlowTraceReport, + PFNDBGFFLOWTRACEREPORTENUMCLBK pfnEnum, + void *pvUser); + +VMMR3DECL(uint32_t) DBGFR3FlowTraceRecordRetain(DBGFFLOWTRACERECORD hFlowTraceRecord); +VMMR3DECL(uint32_t) DBGFR3FlowTraceRecordRelease(DBGFFLOWTRACERECORD hFlowTraceRecord); +VMMR3DECL(uint64_t) DBGFR3FlowTraceRecordGetSeqNo(DBGFFLOWTRACERECORD hFlowTraceRecord); +VMMR3DECL(uint64_t) DBGFR3FlowTraceRecordGetTimestamp(DBGFFLOWTRACERECORD hFlowTraceRecord); +VMMR3DECL(PDBGFADDRESS) DBGFR3FlowTraceRecordGetAddr(DBGFFLOWTRACERECORD hFlowTraceRecord, PDBGFADDRESS pAddr); +VMMR3DECL(DBGFFLOWTRACEPROBE) DBGFR3FlowTraceRecordGetProbe(DBGFFLOWTRACERECORD hFlowTraceRecord); +VMMR3DECL(uint32_t) DBGFR3FlowTraceRecordGetValCount(DBGFFLOWTRACERECORD hFlowTraceRecord); +VMMR3DECL(uint32_t) DBGFR3FlowTraceRecordGetValCommonCount(DBGFFLOWTRACERECORD hFlowTraceRecord); +VMMR3DECL(PCDBGFFLOWTRACEPROBEVAL) DBGFR3FlowTraceRecordGetVals(DBGFFLOWTRACERECORD hFlowTraceRecord); +VMMR3DECL(PCDBGFFLOWTRACEPROBEVAL) DBGFR3FlowTraceRecordGetValsCommon(DBGFFLOWTRACERECORD hFlowTraceRecord); +VMMR3DECL(VMCPUID) DBGFR3FlowTraceRecordGetCpuId(DBGFFLOWTRACERECORD hFlowTraceRecord); + +/** @} */ +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_dbgfflowtrace_h */ + diff --git a/include/VBox/vmm/dbgfsel.h b/include/VBox/vmm/dbgfsel.h new file mode 100644 index 00000000..a531ec6f --- /dev/null +++ b/include/VBox/vmm/dbgfsel.h @@ -0,0 +1,117 @@ +/** @file + * DBGF - Debugger Facility, selector interface partly shared with SELM. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_dbgfsel_h +#define VBOX_INCLUDED_vmm_dbgfsel_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#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. + * @todo remove me! */ +#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 /* !VBOX_INCLUDED_vmm_dbgfsel_h */ + diff --git a/include/VBox/vmm/dbgftrace.h b/include/VBox/vmm/dbgftrace.h new file mode 100644 index 00000000..254cc677 --- /dev/null +++ b/include/VBox/vmm/dbgftrace.h @@ -0,0 +1,168 @@ +/** @file + * DBGF - Debugger Facility. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_dbgftrace_h +#define VBOX_INCLUDED_vmm_dbgftrace_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/trace.h> +#include <VBox/types.h> + +RT_C_DECLS_BEGIN +/** @defgroup grp_dbgf_trace Tracing + * @ingroup grp_dbgf + * + * @{ + */ + +#if (defined(RTTRACE_ENABLED) || defined(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 + +#ifdef RT_COMPILER_SUPPORTS_VA_ARGS +/** + * Add a custom string (req. variadict macro support). + */ +# ifdef DBGFTRACE_ENABLED +# define DBGFTRACE_CUSTOM(a_pVM, ...) \ + do { RTTraceBufAddMsgF((a_pVM)->CTX_SUFF(hTraceBuf), __VA_ARGS__); } while (0) +# else +# define DBGFTRACE_CUSTOM(a_pVM, ...) do { } while (0) +# endif +#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 Macros 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 /* !VBOX_INCLUDED_vmm_dbgftrace_h */ diff --git a/include/VBox/vmm/em.h b/include/VBox/vmm/em.h new file mode 100644 index 00000000..6ea1b65e --- /dev/null +++ b/include/VBox/vmm/em.h @@ -0,0 +1,345 @@ +/** @file + * EM - Execution Monitor. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_em_h +#define VBOX_INCLUDED_vmm_em_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <VBox/vmm/trpm.h> +#include <VBox/vmm/vmapi.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_em The Execution Monitor / Manager API + * @ingroup grp_vmm + * @{ + */ + +/** 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_HM, + /** Executing in IEM. */ + EMSTATE_IEM, + /** 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_HM, + /** Guest debug event from interpreted execution mode is being processed. */ + EMSTATE_DEBUG_GUEST_IEM, + /** 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, + /** Executing in IEM, falling back on REM if we cannot switch back to HM or + * RAW after a short while. */ + EMSTATE_IEM_THEN_REM, + /** Executing in native (API) execution monitor. */ + EMSTATE_NEM, + /** Guest debug event from NEM mode is being processed. */ + EMSTATE_DEBUG_GUEST_NEM, + /** 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; + +VMM_INT_DECL(EMSTATE) EMGetState(PVMCPU pVCpu); +VMM_INT_DECL(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 DECLCALLBACKTYPE(uint32_t, FNEMULATEPARAM2UINT32,(void *pvParam1, uint64_t val2)); +typedef FNEMULATEPARAM2UINT32 *PFNEMULATEPARAM2UINT32; +typedef DECLCALLBACKTYPE(uint32_t, FNEMULATEPARAM2,(void *pvParam1, size_t val2)); +typedef FNEMULATEPARAM2 *PFNEMULATEPARAM2; +typedef DECLCALLBACKTYPE(uint32_t, FNEMULATEPARAM3,(void *pvParam1, uint64_t val2, size_t val3)); +typedef FNEMULATEPARAM3 *PFNEMULATEPARAM3; +typedef DECLCALLBACKTYPE(int, FNEMULATELOCKPARAM2,(void *pvParam1, uint64_t val2, RTGCUINTREG32 *pf)); +typedef FNEMULATELOCKPARAM2 *PFNEMULATELOCKPARAM2; +typedef DECLCALLBACKTYPE(int, FNEMULATELOCKPARAM3,(void *pvParam1, uint64_t val2, size_t cb, RTGCUINTREG32 *pf)); +typedef FNEMULATELOCKPARAM3 *PFNEMULATELOCKPARAM3; +/** @} */ + +VMMDECL(void) EMSetHypercallInstructionsEnabled(PVMCPU pVCpu, bool fEnabled); +VMMDECL(bool) EMAreHypercallInstructionsEnabled(PVMCPU pVCpu); +VMM_INT_DECL(bool) EMShouldContinueAfterHalt(PVMCPU pVCpu, PCPUMCTX pCtx); +VMM_INT_DECL(bool) EMMonitorWaitShouldContinue(PVMCPU pVCpu, PCPUMCTX pCtx); +VMM_INT_DECL(int) EMMonitorWaitPrepare(PVMCPU pVCpu, uint64_t rax, uint64_t rcx, uint64_t rdx, RTGCPHYS GCPhys); +VMM_INT_DECL(void) EMMonitorWaitClear(PVMCPU pVCpu); +VMM_INT_DECL(bool) EMMonitorIsArmed(PVMCPU pVCpu); +VMM_INT_DECL(unsigned) EMMonitorWaitIsActive(PVMCPU pVCpu); +VMM_INT_DECL(int) EMMonitorWaitPerform(PVMCPU pVCpu, uint64_t rax, uint64_t rcx); +VMM_INT_DECL(int) EMUnhaltAndWakeUp(PVMCC pVM, PVMCPUCC pVCpuDst); +VMMRZ_INT_DECL(VBOXSTRICTRC) EMRZSetPendingIoPortWrite(PVMCPU pVCpu, RTIOPORT uPort, uint8_t cbInstr, uint8_t cbValue, uint32_t uValue); +VMMRZ_INT_DECL(VBOXSTRICTRC) EMRZSetPendingIoPortRead(PVMCPU pVCpu, RTIOPORT uPort, uint8_t cbInstr, uint8_t cbValue); + +/** + * Common defined exit types that EM knows what to do about. + * + * These should be used instead of the VT-x, SVM or NEM specific ones for exits + * worth optimizing. + */ +typedef enum EMEXITTYPE +{ + EMEXITTYPE_INVALID = 0, + EMEXITTYPE_IO_PORT_READ, + EMEXITTYPE_IO_PORT_WRITE, + EMEXITTYPE_IO_PORT_STR_READ, + EMEXITTYPE_IO_PORT_STR_WRITE, + EMEXITTYPE_MMIO, + EMEXITTYPE_MMIO_READ, + EMEXITTYPE_MMIO_WRITE, + EMEXITTYPE_MSR_READ, + EMEXITTYPE_MSR_WRITE, + EMEXITTYPE_CPUID, + EMEXITTYPE_RDTSC, + EMEXITTYPE_MOV_CRX, + EMEXITTYPE_MOV_DRX, + EMEXITTYPE_VMREAD, + EMEXITTYPE_VMWRITE, + + /** @name Raw-mode only (for now), keep at end. + * @{ */ + EMEXITTYPE_INVLPG, + EMEXITTYPE_LLDT, + EMEXITTYPE_RDPMC, + EMEXITTYPE_CLTS, + EMEXITTYPE_STI, + EMEXITTYPE_INT, + EMEXITTYPE_SYSCALL, + EMEXITTYPE_SYSENTER, + EMEXITTYPE_HLT + /** @} */ +} EMEXITTYPE; +AssertCompileSize(EMEXITTYPE, 4); + +/** @name EMEXIT_F_XXX - EM exit flags. + * + * The flags the exit type are combined to a 32-bit number using the + * EMEXIT_MAKE_FT() macro. + * + * @{ */ +#define EMEXIT_F_TYPE_MASK UINT32_C(0x00000fff) /**< The exit type mask. */ +#define EMEXIT_F_KIND_EM UINT32_C(0x00000000) /**< EMEXITTYPE */ +#define EMEXIT_F_KIND_VMX UINT32_C(0x00001000) /**< VT-x exit codes. */ +#define EMEXIT_F_KIND_SVM UINT32_C(0x00002000) /**< SVM exit codes. */ +#define EMEXIT_F_KIND_NEM UINT32_C(0x00003000) /**< NEMEXITTYPE */ +#define EMEXIT_F_KIND_XCPT UINT32_C(0x00004000) /**< Exception numbers (raw-mode). */ +#define EMEXIT_F_KIND_MASK UINT32_C(0x00007000) +#define EMEXIT_F_CS_EIP UINT32_C(0x00010000) /**< The PC is EIP in the low dword and CS in the high. */ +#define EMEXIT_F_UNFLATTENED_PC UINT32_C(0x00020000) /**< The PC hasn't had CS.BASE added to it. */ +/** HM is calling (from ring-0). Preemption is currently disabled or we're using preemption hooks. */ +#define EMEXIT_F_HM UINT32_C(0x00040000) +/** Combines flags and exit type into EMHistoryAddExit() input. */ +#define EMEXIT_MAKE_FT(a_fFlags, a_uType) ((a_fFlags) | (uint32_t)(a_uType)) +/** @} */ + +typedef enum EMEXITACTION +{ + /** The record is free. */ + EMEXITACTION_FREE_RECORD = 0, + /** Take normal action on the exit. */ + EMEXITACTION_NORMAL, + /** Take normal action on the exit, already probed and found nothing. */ + EMEXITACTION_NORMAL_PROBED, + /** Do a probe execution. */ + EMEXITACTION_EXEC_PROBE, + /** Execute using EMEXITREC::cMaxInstructionsWithoutExit. */ + EMEXITACTION_EXEC_WITH_MAX +} EMEXITACTION; +AssertCompileSize(EMEXITACTION, 4); + +/** + * Accumulative exit record. + * + * This could perhaps be squeezed down a bit, but there isn't too much point. + * We'll probably need more data as time goes by. + */ +typedef struct EMEXITREC +{ + /** The flat PC of the exit. */ + uint64_t uFlatPC; + /** Flags and type, see EMEXIT_MAKE_FT. */ + uint32_t uFlagsAndType; + /** The action to take (EMEXITACTION). */ + uint8_t enmAction; + uint8_t bUnused; + /** Maximum number of instructions to execute without hitting an exit. */ + uint16_t cMaxInstructionsWithoutExit; + /** The exit number (EMCPU::iNextExit) at which it was last updated. */ + uint64_t uLastExitNo; + /** Number of hits. */ + uint64_t cHits; +} EMEXITREC; +AssertCompileSize(EMEXITREC, 32); +/** Pointer to an accumulative exit record. */ +typedef EMEXITREC *PEMEXITREC; +/** Pointer to a const accumulative exit record. */ +typedef EMEXITREC const *PCEMEXITREC; + +VMM_INT_DECL(PCEMEXITREC) EMHistoryAddExit(PVMCPUCC pVCpu, uint32_t uFlagsAndType, uint64_t uFlatPC, uint64_t uTimestamp); +#ifdef IN_RC +VMMRC_INT_DECL(void) EMRCHistoryAddExitCsEip(PVMCPU pVCpu, uint32_t uFlagsAndType, uint16_t uCs, uint32_t uEip, + uint64_t uTimestamp); +#endif +VMM_INT_DECL(void) EMHistoryUpdatePC(PVMCPUCC pVCpu, uint64_t uFlatPC, bool fFlattened); +VMM_INT_DECL(PCEMEXITREC) EMHistoryUpdateFlagsAndType(PVMCPUCC pVCpu, uint32_t uFlagsAndType); +VMM_INT_DECL(PCEMEXITREC) EMHistoryUpdateFlagsAndTypeAndPC(PVMCPUCC pVCpu, uint32_t uFlagsAndType, uint64_t uFlatPC); +VMM_INT_DECL(VBOXSTRICTRC) EMHistoryExec(PVMCPUCC pVCpu, PCEMEXITREC pExitRec, uint32_t fWillExit); + + +/** @name Deprecated interpretation related APIs (use IEM). + * @{ */ +VMM_INT_DECL(int) EMInterpretDisasCurrent(PVMCPUCC pVCpu, PDISCPUSTATE pCpu, unsigned *pcbInstr); +VMM_INT_DECL(int) EMInterpretDisasOneEx(PVMCPUCC pVCpu, RTGCUINTPTR GCPtrInstr, + PDISCPUSTATE pDISState, unsigned *pcbInstr); +VMM_INT_DECL(VBOXSTRICTRC) EMInterpretInstruction(PVMCPUCC pVCpu); +VMM_INT_DECL(VBOXSTRICTRC) EMInterpretInstructionDisasState(PVMCPUCC pVCpu, PDISCPUSTATE pDis, uint64_t rip); +/** @} */ + + +/** @name EM_ONE_INS_FLAGS_XXX - flags for EMR3HmSingleInstruction (et al). + * @{ */ +/** Return when CS:RIP changes or some other important event happens. + * This means running whole REP and LOOP $ sequences for instance. */ +#define EM_ONE_INS_FLAGS_RIP_CHANGE RT_BIT_32(0) +/** Mask of valid flags. */ +#define EM_ONE_INS_FLAGS_MASK UINT32_C(0x00000001) +/** @} */ + + +#ifdef IN_RING0 +/** @defgroup grp_em_r0 The EM Host Context Ring-0 API + * @{ */ +VMMR0_INT_DECL(int) EMR0InitVM(PGVM pGVM); +/** @} */ +#endif + + +#ifdef IN_RING3 +/** @defgroup grp_em_r3 The EM Host Context Ring-3 API + * @{ + */ + +/** + * 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, + /** Whether to only use IEM for execution. */ + EMEXECPOLICY_IEM_ALL, + /** End of valid value (not included). */ + EMEXECPOLICY_END, + /** The customary 32-bit type blowup. */ + EMEXECPOLICY_32BIT_HACK = 0x7fffffff +} EMEXECPOLICY; +VMMR3DECL(int) EMR3SetExecutionPolicy(PUVM pUVM, EMEXECPOLICY enmPolicy, bool fEnforce); +VMMR3DECL(int) EMR3QueryExecutionPolicy(PUVM pUVM, EMEXECPOLICY enmPolicy, bool *pfEnforced); +VMMR3DECL(int) EMR3QueryMainExecutionEngine(PUVM pUVM, uint8_t *pbMainExecutionEngine); + +VMMR3_INT_DECL(int) EMR3Init(PVM pVM); +VMMR3_INT_DECL(int) EMR3InitCompleted(PVM pVM, VMINITCOMPLETED enmWhat); +VMMR3_INT_DECL(void) EMR3Relocate(PVM pVM); +VMMR3_INT_DECL(void) EMR3ResetCpu(PVMCPU pVCpu); +VMMR3_INT_DECL(void) EMR3Reset(PVM pVM); +VMMR3_INT_DECL(int) EMR3Term(PVM pVM); +VMMR3DECL(DECL_NO_RETURN(void)) EMR3FatalError(PVMCPU pVCpu, int rc); +VMMR3_INT_DECL(int) EMR3ExecuteVM(PVM pVM, PVMCPU pVCpu); +VMMR3_INT_DECL(int) EMR3CheckRawForcedActions(PVM pVM, PVMCPU pVCpu); +VMMR3_INT_DECL(VBOXSTRICTRC) EMR3HmSingleInstruction(PVM pVM, PVMCPU pVCpu, uint32_t fFlags); + +/** @} */ +#endif /* IN_RING3 */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_em_h */ + diff --git a/include/VBox/vmm/gcm.h b/include/VBox/vmm/gcm.h new file mode 100644 index 00000000..0b3102c7 --- /dev/null +++ b/include/VBox/vmm/gcm.h @@ -0,0 +1,95 @@ +/** @file + * GCM - Guest Compatibility Manager. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_gcm_h +#define VBOX_INCLUDED_vmm_gcm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/cdefs.h> +#include <VBox/types.h> +#include <VBox/param.h> + +#include <VBox/vmm/cpum.h> +#include <VBox/vmm/pdmifs.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_gcm The Guest Compatibility Manager API + * @ingroup grp_vmm + * @{ + */ + +/** + * GCM Fixer Identifiers. + * @remarks Part of saved state! + */ +typedef enum GCMFIXERID +{ + /** None. */ + GCMFIXER_NONE = 0, + /** DOS division by zero, the worst. Includes Windows 3.x. */ + GCMFIXER_DBZ_DOS = RT_BIT(0), + /** OS/2 (any version) division by zero. */ + GCMFIXER_DBZ_OS2 = RT_BIT(1), + /** Windows 9x division by zero. */ + GCMFIXER_DBZ_WIN9X = RT_BIT(2), + /** 32-bit hack. */ + GCMFIXER_32BIT_HACK = 0x7fffffff +} GCMFIXERID; +AssertCompileSize(GCMFIXERID, sizeof(uint32_t)); + + +#ifdef IN_RING3 +/** @defgroup grp_gcm_r3 The GCM Host Context Ring-3 API + * @{ + */ +VMMR3_INT_DECL(int) GCMR3Init(PVM pVM); +VMMR3_INT_DECL(void) GCMR3Relocate(PVM pVM, RTGCINTPTR offDelta); +VMMR3_INT_DECL(int) GCMR3Term(PVM pVM); +VMMR3_INT_DECL(void) GCMR3Reset(PVM pVM); +/** @} */ +#endif /* IN_RING3 */ + +VMMDECL(bool) GCMIsEnabled(PVM pVM); +VMM_INT_DECL(bool) GCMShouldTrapXcptDE(PVMCPUCC pVCpu); +VMM_INT_DECL(VBOXSTRICTRC) GCMXcptDE(PVMCPUCC pVCpu, PCPUMCTX pCtx, PDISCPUSTATE pDis, uint8_t *pcbInstr); +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_gcm_h */ + diff --git a/include/VBox/vmm/gim.h b/include/VBox/vmm/gim.h new file mode 100644 index 00000000..b62e1a1e --- /dev/null +++ b/include/VBox/vmm/gim.h @@ -0,0 +1,218 @@ +/** @file + * GIM - Guest Interface Manager. + */ + +/* + * Copyright (C) 2014-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_gim_h +#define VBOX_INCLUDED_vmm_gim_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/cdefs.h> +#include <VBox/types.h> +#include <VBox/param.h> + +#include <VBox/vmm/cpum.h> +#include <VBox/vmm/pdmifs.h> + +/** The value used to specify that VirtualBox must use the newest + * implementation version of the GIM provider. */ +#define GIM_VERSION_LATEST UINT32_C(0) + +RT_C_DECLS_BEGIN + +/** @defgroup grp_gim The Guest Interface Manager API + * @ingroup grp_vmm + * @{ + */ + +/** + * GIM Provider Identifiers. + * @remarks Part of saved state! + */ +typedef enum GIMPROVIDERID +{ + /** None. */ + GIMPROVIDERID_NONE = 0, + /** Minimal. */ + GIMPROVIDERID_MINIMAL, + /** Microsoft Hyper-V. */ + GIMPROVIDERID_HYPERV, + /** Linux KVM Interface. */ + GIMPROVIDERID_KVM +} GIMPROVIDERID; +AssertCompileSize(GIMPROVIDERID, sizeof(uint32_t)); + + +/** + * A GIM MMIO2 region record. + */ +typedef struct GIMMMIO2REGION +{ + /** The region index. */ + uint8_t iRegion; + /** Whether an RC mapping is required. */ + bool fRCMapping; + /** Whether this region has been registered. */ + bool fRegistered; + /** Whether this region is currently mapped. */ + bool fMapped; + /** Size of the region (must be page aligned). */ + uint32_t cbRegion; + /** The host ring-0 address of the first page in the region. */ + R0PTRTYPE(void *) pvPageR0; + /** The host ring-3 address of the first page in the region. */ + R3PTRTYPE(void *) pvPageR3; +# ifdef VBOX_WITH_RAW_MODE_KEEP + /** The ring-context address of the first page in the region. */ + RCPTRTYPE(void *) pvPageRC; + RTRCPTR RCPtrAlignment0; +# endif + /** The guest-physical address of the first page in the region. */ + RTGCPHYS GCPhysPage; + /** The MMIO2 handle. */ + PGMMMIO2HANDLE hMmio2; + /** The description of the region. */ + char szDescription[32]; +} GIMMMIO2REGION; +/** Pointer to a GIM MMIO2 region. */ +typedef GIMMMIO2REGION *PGIMMMIO2REGION; +/** Pointer to a const GIM MMIO2 region. */ +typedef GIMMMIO2REGION const *PCGIMMMIO2REGION; +AssertCompileMemberAlignment(GIMMMIO2REGION, pvPageR0, 8); +AssertCompileMemberAlignment(GIMMMIO2REGION, GCPhysPage, 8); + +/** + * Debug data buffer available callback over the GIM debug connection. + * + * @param pVM The cross context VM structure. + */ +typedef DECLCALLBACKTYPE(void, FNGIMDEBUGBUFAVAIL,(PVM pVM)); +/** Pointer to GIM debug buffer available callback. */ +typedef FNGIMDEBUGBUFAVAIL *PFNGIMDEBUGBUFAVAIL; + +/** + * GIM debug setup. + * + * These are parameters/options filled in by the GIM provider and passed along + * to the GIM device. + */ +typedef struct GIMDEBUGSETUP +{ + /** The callback to invoke when the receive buffer has data. */ + PFNGIMDEBUGBUFAVAIL pfnDbgRecvBufAvail; + /** The size of the receive buffer as specified by the GIM provider. */ + uint32_t cbDbgRecvBuf; +} GIMDEBUGSETUP; +/** Pointer to a GIM debug setup struct. */ +typedef struct GIMDEBUGSETUP *PGIMDEBUGSETUP; +/** Pointer to a const GIM debug setup struct. */ +typedef struct GIMDEBUGSETUP const *PCGGIMDEBUGSETUP; + +/** + * GIM debug structure (common to the GIM device and GIM). + * + * This is used to exchanging data between the GIM provider and the GIM device. + */ +typedef struct GIMDEBUG +{ + /** The receive buffer. */ + void *pvDbgRecvBuf; + /** The debug I/O stream driver. */ + PPDMISTREAM pDbgDrvStream; + /** Number of bytes pending to be read from the receive buffer. */ + size_t cbDbgRecvBufRead; + /** The flag synchronizing reads of the receive buffer from EMT. */ + volatile bool fDbgRecvBufRead; + /** The receive thread wakeup semaphore. */ + RTSEMEVENTMULTI hDbgRecvThreadSem; +} GIMDEBUG; +/** Pointer to a GIM debug struct. */ +typedef struct GIMDEBUG *PGIMDEBUG; +/** Pointer to a const GIM debug struct. */ +typedef struct GIMDEBUG const *PCGIMDEBUG; + + +#ifdef IN_RC +/** @defgroup grp_gim_rc The GIM Raw-mode Context API + * @{ + */ +/** @} */ +#endif /* IN_RC */ + +#ifdef IN_RING0 +/** @defgroup grp_gim_r0 The GIM Host Context Ring-0 API + * @{ + */ +VMMR0_INT_DECL(int) GIMR0InitVM(PVMCC pVM); +VMMR0_INT_DECL(int) GIMR0TermVM(PVMCC pVM); +VMMR0_INT_DECL(int) GIMR0UpdateParavirtTsc(PVMCC pVM, uint64_t u64Offset); +/** @} */ +#endif /* IN_RING0 */ + + +#ifdef IN_RING3 +/** @defgroup grp_gim_r3 The GIM Host Context Ring-3 API + * @{ + */ +VMMR3_INT_DECL(int) GIMR3Init(PVM pVM); +VMMR3_INT_DECL(int) GIMR3InitCompleted(PVM pVM); +VMMR3_INT_DECL(void) GIMR3Relocate(PVM pVM, RTGCINTPTR offDelta); +VMMR3_INT_DECL(int) GIMR3Term(PVM pVM); +VMMR3_INT_DECL(void) GIMR3Reset(PVM pVM); +VMMR3DECL(void) GIMR3GimDeviceRegister(PVM pVM, PPDMDEVINS pDevInsR3, PGIMDEBUG pDbg); +VMMR3DECL(int) GIMR3GetDebugSetup(PVM pVM, PGIMDEBUGSETUP pDbgSetup); +/** @} */ +#endif /* IN_RING3 */ + +VMMDECL(bool) GIMIsEnabled(PVM pVM); +VMMDECL(GIMPROVIDERID) GIMGetProvider(PVM pVM); +VMMDECL(PGIMMMIO2REGION) GIMGetMmio2Regions(PVMCC pVM, uint32_t *pcRegions); +VMM_INT_DECL(bool) GIMIsParavirtTscEnabled(PVMCC pVM); +VMM_INT_DECL(bool) GIMAreHypercallsEnabled(PVMCPUCC pVCpu); +VMM_INT_DECL(VBOXSTRICTRC) GIMHypercall(PVMCPUCC pVCpu, PCPUMCTX pCtx); +VMM_INT_DECL(VBOXSTRICTRC) GIMHypercallEx(PVMCPUCC pVCpu, PCPUMCTX pCtx, unsigned uDisOpcode, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) GIMExecHypercallInstr(PVMCPUCC pVCpu, PCPUMCTX pCtx, uint8_t *pcbInstr); +VMM_INT_DECL(VBOXSTRICTRC) GIMXcptUD(PVMCPUCC pVCpu, PCPUMCTX pCtx, PDISCPUSTATE pDis, uint8_t *pcbInstr); +VMM_INT_DECL(bool) GIMShouldTrapXcptUD(PVMCPUCC pVCpu); +VMM_INT_DECL(VBOXSTRICTRC) GIMReadMsr(PVMCPUCC pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t *puValue); +VMM_INT_DECL(VBOXSTRICTRC) GIMWriteMsr(PVMCPUCC pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t uValue, uint64_t uRawValue); +VMM_INT_DECL(int) GIMQueryHypercallOpcodeBytes(PVM pVM, void *pvBuf, size_t cbBuf, + size_t *pcbWritten, uint16_t *puDisOpcode); +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_gim_h */ + diff --git a/include/VBox/vmm/gmm.h b/include/VBox/vmm/gmm.h new file mode 100644 index 00000000..4839b737 --- /dev/null +++ b/include/VBox/vmm/gmm.h @@ -0,0 +1,828 @@ +/** @file + * GMM - The Global Memory Manager. + */ + +/* + * Copyright (C) 2007-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_gmm_h +#define VBOX_INCLUDED_vmm_gmm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/vmm/gvmm.h> +#include <VBox/sup.h> +#include <VBox/param.h> +#include <VBox/ostypes.h> +#include <iprt/avl.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_gmm GMM - The Global Memory Manager + * @ingroup grp_vmm + * @{ + */ + +/** @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 (guest) pages. */ +#define GMM_CHUNK_NUM_PAGES (1U << (GMM_CHUNK_SHIFT - GUEST_PAGE_SHIFT)) +/** The shift factor for converting a page id into a chunk id. */ +#define GMM_CHUNKID_SHIFT (GMM_CHUNK_SHIFT - GUEST_PAGE_SHIFT) +/** The last valid Chunk ID value. */ +#define GMM_CHUNKID_LAST (GMM_PAGEID_LAST >> GMM_CHUNKID_SHIFT) +/** The last valid Page ID value. */ +#define GMM_PAGEID_LAST UINT32_C(0xfffffff0) +/** 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_GMMPAGEDESC_PHYS 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_GMMPAGEDESC_PHYS and GMM_GCPHYS_UNSHAREABLE as above. + * + * @output The host physical address of the allocated page. + * NIL_GMMPAGEDESC_PHYS on allocation failure. + * + * ASSUMES: sizeof(RTHCPHYS) >= sizeof(RTGCPHYS) and that physical addresses are + * limited to 63 or fewer bits (52 by AMD64 arch spec). + */ + RT_GCC_EXTENSION + RTHCPHYS HCPhysGCPhys : 63; + /** Set if the memory was zeroed. */ + RT_GCC_EXTENSION + RTHCPHYS fZeroed : 1; + + /** The Page ID. + * + * @input 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; + +/** Special NIL value for GMMPAGEDESC::HCPhysGCPhys. */ +#define NIL_GMMPAGEDESC_PHYS UINT64_C(0x7fffffffffffffff) + +/** 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; + /** The current chunk freeing generation use by the per-VM TLB validation (GMM::idFreeGeneration). */ + uint64_t idFreeGeneration; + /** Space reserved for later. */ + uint64_t au64Reserved[1]; + + /** 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(int) GMMR0InitPerVMData(PGVM pGVM); +GMMR0DECL(void) GMMR0CleanupVM(PGVM pGVM); +GMMR0DECL(int) GMMR0InitialReservation(PGVM pGVM, VMCPUID idCpu, uint64_t cBasePages, uint32_t cShadowPages, uint32_t cFixedPages, + GMMOCPOLICY enmPolicy, GMMPRIORITY enmPriority); +GMMR0DECL(int) GMMR0UpdateReservation(PGVM pGVM, VMCPUID idCpu, uint64_t cBasePages, uint32_t cShadowPages, uint32_t cFixedPages); +GMMR0DECL(int) GMMR0AllocateHandyPages(PGVM pGVM, VMCPUID idCpu, uint32_t cPagesToUpdate, + uint32_t cPagesToAlloc, PGMMPAGEDESC paPages); +GMMR0DECL(int) GMMR0AllocatePages(PGVM pGVM, VMCPUID idCpu, uint32_t cPages, PGMMPAGEDESC paPages, GMMACCOUNT enmAccount); +GMMR0DECL(int) GMMR0AllocateLargePage(PGVM pGVM, VMCPUID idCpu, uint32_t cbPage, uint32_t *pIdPage, RTHCPHYS *pHCPhys); +GMMR0DECL(int) GMMR0FreePages(PGVM pGVM, VMCPUID idCpu, uint32_t cPages, PGMMFREEPAGEDESC paPages, GMMACCOUNT enmAccount); +GMMR0DECL(int) GMMR0FreeLargePage(PGVM pGVM, VMCPUID idCpu, uint32_t idPage); +GMMR0DECL(int) GMMR0BalloonedPages(PGVM pGVM, VMCPUID idCpu, GMMBALLOONACTION enmAction, uint32_t cBalloonedPages); +GMMR0DECL(int) GMMR0MapUnmapChunk(PGVM pGVM, uint32_t idChunkMap, uint32_t idChunkUnmap, PRTR3PTR ppvR3); +GMMR0DECL(int) GMMR0PageIdToVirt(PGVM pGVM, uint32_t idPage, void **ppv); +GMMR0DECL(int) GMMR0RegisterSharedModule(PGVM pGVM, VMCPUID idCpu, VBOXOSFAMILY enmGuestOS, char *pszModuleName, + char *pszVersion, RTGCPTR GCBaseAddr, uint32_t cbModule, uint32_t cRegions, + struct VMMDEVSHAREDREGIONDESC const *paRegions); +GMMR0DECL(int) GMMR0UnregisterSharedModule(PGVM pGVM, VMCPUID idCpu, char *pszModuleName, char *pszVersion, + RTGCPTR GCBaseAddr, uint32_t cbModule); +GMMR0DECL(int) GMMR0UnregisterAllSharedModules(PGVM pGVM, VMCPUID idCpu); +GMMR0DECL(int) GMMR0CheckSharedModules(PGVM pGVM, VMCPUID idCpu); +GMMR0DECL(int) GMMR0ResetSharedModules(PGVM pGVM, VMCPUID idCpu); +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(PGVM pGVM, 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(PGVM pGVM, 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(PGVM pGVM, 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(PGVM pGVM, 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(PGVM pGVM, 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(PGMMMEMSTATSREQ pReq); +GMMR0DECL(int) GMMR0QueryMemoryStatsReq(PGVM pGVM, 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(PGVM pGVM, 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(PGVM pGVM, 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(PGVM pGVM, 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(PGVM pGVM, 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(PGVM pGVM, 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(PGVM pGVM, 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(PGVM pGVM, PGMMRESETSTATISTICSSREQ pReq); + + + +#ifdef IN_RING3 +/** @defgroup grp_gmm_r3 The Global Memory Manager Ring-3 API Wrappers + * @{ + */ +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) 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 /* !VBOX_INCLUDED_vmm_gmm_h */ + diff --git a/include/VBox/vmm/gvm.h b/include/VBox/vmm/gvm.h new file mode 100644 index 00000000..8efdcc24 --- /dev/null +++ b/include/VBox/vmm/gvm.h @@ -0,0 +1,351 @@ +/* $Id: gvm.h $ */ +/** @file + * GVM - The Global VM Data. + */ + +/* + * Copyright (C) 2007-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_gvm_h +#define VBOX_INCLUDED_vmm_gvm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifndef USING_VMM_COMMON_DEFS +# error "Compile job does not include VMM_COMMON_DEFS from src/VBox/Config.kmk - make sure you really need to include this file!" +#endif +#include <VBox/types.h> +#include <VBox/vmm/vm.h> +#include <VBox/param.h> +#include <iprt/thread.h> +#include <iprt/assertcompile.h> + + +/** @defgroup grp_gvmcpu GVMCPU - The Global VMCPU Data + * @ingroup grp_vmm + * @{ + */ + +#if defined(__cplusplus) && !defined(GVM_C_STYLE_STRUCTURES) +typedef struct GVMCPU : public VMCPU +#else +typedef struct GVMCPU +#endif +{ +#if !defined(__cplusplus) || defined(GVM_C_STYLE_STRUCTURES) + VMCPU s; +#endif + + /** VCPU id (0 - (pVM->cCpus - 1). */ + VMCPUID idCpu; + /** Padding. */ + uint32_t uPadding0; + + /** Handle to the EMT thread. */ + RTNATIVETHREAD hEMT; + + /** Pointer to the global (ring-0) VM structure this CPU belongs to. */ + R0PTRTYPE(PGVM) pGVM; + /** Pointer to the GVM structure, for CTX_SUFF use in VMMAll code. */ + PGVM pVMR0; + /** The ring-3 address of this structure (only VMCPU part). */ + PVMCPUR3 pVCpuR3; + + /** Padding so the noisy stuff on a 64 byte boundrary. + * @note Keeping this working for 32-bit header syntax checking. */ + uint8_t abPadding1[HC_ARCH_BITS == 32 ? 40 : 24]; + + /** Which host CPU ID is this EMT running on. + * Only valid when in RC or HMR0 with scheduling disabled. */ + RTCPUID volatile idHostCpu; + /** The CPU set index corresponding to idHostCpu, UINT32_MAX if not valid. + * @remarks Best to make sure iHostCpuSet shares cache line with idHostCpu! */ + uint32_t volatile iHostCpuSet; + + /** Padding so gvmm starts on a 64 byte boundrary. + * @note Keeping this working for 32-bit header syntax checking. */ + uint8_t abPadding2[56]; + + /** The GVMM per vcpu data. */ + union + { +#ifdef VMM_INCLUDED_SRC_VMMR0_GVMMR0Internal_h + struct GVMMPERVCPU s; +#endif + uint8_t padding[256]; + } gvmm; + + /** The HM per vcpu data. */ + union + { +#if defined(VMM_INCLUDED_SRC_include_HMInternal_h) && defined(IN_RING0) + struct HMR0PERVCPU s; +#endif + uint8_t padding[1024]; + } hmr0; + +#ifdef VBOX_WITH_NEM_R0 + /** The NEM per vcpu data. */ + union + { +# if defined(VMM_INCLUDED_SRC_include_NEMInternal_h) && defined(IN_RING0) + struct NEMR0PERVCPU s; +# endif + uint8_t padding[64]; + } nemr0; +#endif + + union + { +#if defined(VMM_INCLUDED_SRC_include_VMMInternal_h) && defined(IN_RING0) + struct VMMR0PERVCPU s; +#endif + uint8_t padding[896]; + } vmmr0; + + union + { +#if defined(VMM_INCLUDED_SRC_include_PGMInternal_h) && defined(IN_RING0) + struct PGMR0PERVCPU s; +#endif + uint8_t padding[64]; + } pgmr0; + + /** Padding the structure size to page boundrary. */ +#ifdef VBOX_WITH_NEM_R0 + uint8_t abPadding3[16384 - 64*2 - 256 - 1024 - 64 - 896 - 64]; +#else + uint8_t abPadding3[16384 - 64*2 - 256 - 1024 - 896 - 64]; +#endif +} GVMCPU; +#if RT_GNUC_PREREQ(4, 6) && defined(__cplusplus) +# pragma GCC diagnostic push +#endif +#if RT_GNUC_PREREQ(4, 3) && defined(__cplusplus) +# pragma GCC diagnostic ignored "-Winvalid-offsetof" +#endif +AssertCompileMemberAlignment(GVMCPU, idCpu, 16384); +AssertCompileMemberAlignment(GVMCPU, gvmm, 64); +#ifdef VBOX_WITH_NEM_R0 +AssertCompileMemberAlignment(GVMCPU, nemr0, 64); +#endif +AssertCompileSizeAlignment(GVMCPU, 16384); +#if RT_GNUC_PREREQ(4, 6) && defined(__cplusplus) +# pragma GCC diagnostic pop +#endif + +/** @} */ + +/** @defgroup grp_gvm GVM - The Global VM Data + * @ingroup grp_vmm + * @{ + */ + +/** + * 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. + */ +#if defined(__cplusplus) && !defined(GVM_C_STYLE_STRUCTURES) +typedef struct GVM : public VM +#else +typedef struct GVM +#endif +{ +#if !defined(__cplusplus) || defined(GVM_C_STYLE_STRUCTURES) + VM s; +#endif + /** Magic / eye-catcher (GVM_MAGIC). */ + uint32_t u32Magic; + /** The global VM handle for this VM. */ + uint32_t hSelf; + /** Pointer to this structure (for validation purposes). */ + PGVM pSelf; + /** The ring-3 mapping of the VM structure. */ + PVMR3 pVMR3; + /** The support driver session the VM is associated with. */ + PSUPDRVSESSION pSession; + /** Number of Virtual CPUs, i.e. how many entries there are in aCpus. + * Same same as VM::cCpus. */ + uint32_t cCpus; + /** Padding so gvmm starts on a 64 byte boundrary. */ + uint8_t abPadding[HC_ARCH_BITS == 32 ? 12 + 28 : 28]; + + /** The GVMM per vm data. */ + union + { +#ifdef VMM_INCLUDED_SRC_VMMR0_GVMMR0Internal_h + struct GVMMPERVM s; +#endif + uint8_t padding[4352]; + } gvmm; + + /** The GMM per vm data. */ + union + { +#ifdef VMM_INCLUDED_SRC_VMMR0_GMMR0Internal_h + struct GMMPERVM s; +#endif + uint8_t padding[1024]; + } gmm; + + /** The HM per vm data. */ + union + { +#if defined(VMM_INCLUDED_SRC_include_HMInternal_h) && defined(IN_RING0) + struct HMR0PERVM s; +#endif + uint8_t padding[256]; + } hmr0; + +#ifdef VBOX_WITH_NEM_R0 + /** The NEM per vcpu data. */ + union + { +# if defined(VMM_INCLUDED_SRC_include_NEMInternal_h) && defined(IN_RING0) + struct NEMR0PERVM s; +# endif + uint8_t padding[256]; + } nemr0; +#endif + + /** The RAWPCIVM per vm data. */ + union + { +#ifdef VBOX_INCLUDED_rawpci_h + struct RAWPCIPERVM s; +#endif + uint8_t padding[64]; + } rawpci; + + union + { +#if defined(VMM_INCLUDED_SRC_include_PDMInternal_h) && defined(IN_RING0) + struct PDMR0PERVM s; +#endif + uint8_t padding[3008]; + } pdmr0; + + union + { +#if defined(VMM_INCLUDED_SRC_include_PGMInternal_h) && defined(IN_RING0) + struct PGMR0PERVM s; +#endif + uint8_t padding[1920]; + } pgmr0; + + union + { +#if defined(VMM_INCLUDED_SRC_include_IOMInternal_h) && defined(IN_RING0) + struct IOMR0PERVM s; +#endif + uint8_t padding[512]; + } iomr0; + + union + { +#if defined(VMM_INCLUDED_SRC_include_APICInternal_h) && defined(IN_RING0) + struct APICR0PERVM s; +#endif + uint8_t padding[64]; + } apicr0; + + union + { +#if defined(VMM_INCLUDED_SRC_include_DBGFInternal_h) && defined(IN_RING0) + struct DBGFR0PERVM s; +#endif + uint8_t padding[1024]; + } dbgfr0; + + union + { +#if defined(VMM_INCLUDED_SRC_include_TMInternal_h) && defined(IN_RING0) + TMR0PERVM s; +#endif + uint8_t padding[192]; + } tmr0; + + union + { +#if defined(VMM_INCLUDED_SRC_include_VMMInternal_h) && defined(IN_RING0) + VMMR0PERVM s; +#endif + uint8_t padding[704]; + } vmmr0; + + /** Padding so aCpus starts on a page boundrary. */ +#ifdef VBOX_WITH_NEM_R0 + uint8_t abPadding2[16384 - 64 - 4352 - 1024 - 256 - 256 - 64 - 3008 - 1920 - 512 - 64 - 1024 - 192 - 704 - sizeof(PGVMCPU) * VMM_MAX_CPU_COUNT]; +#else + uint8_t abPadding2[16384 - 64 - 4352 - 1024 - 256 - 64 - 3008 - 1920 - 512 - 64 - 1024 - 192 - 704 - sizeof(PGVMCPU) * VMM_MAX_CPU_COUNT]; +#endif + + /** For simplifying CPU enumeration in VMMAll code. */ + PGVMCPU apCpusR0[VMM_MAX_CPU_COUNT]; + + /** GVMCPU array for the configured number of virtual CPUs. */ + GVMCPU aCpus[1]; +} GVM; +#if 0 +#if RT_GNUC_PREREQ(4, 6) && defined(__cplusplus) +# pragma GCC diagnostic push +#endif +#if RT_GNUC_PREREQ(4, 3) && defined(__cplusplus) +# pragma GCC diagnostic ignored "-Winvalid-offsetof" +#endif +AssertCompileMemberAlignment(GVM, u32Magic, 64); +AssertCompileMemberAlignment(GVM, gvmm, 64); +AssertCompileMemberAlignment(GVM, gmm, 64); +#ifdef VBOX_WITH_NEM_R0 +AssertCompileMemberAlignment(GVM, nemr0, 64); +#endif +AssertCompileMemberAlignment(GVM, rawpci, 64); +AssertCompileMemberAlignment(GVM, pdmr0, 64); +AssertCompileMemberAlignment(GVM, aCpus, 16384); +AssertCompileSizeAlignment(GVM, 16384); +#if RT_GNUC_PREREQ(4, 6) && defined(__cplusplus) +# pragma GCC diagnostic pop +#endif +#endif + +/** The GVM::u32Magic value (Wayne Shorter). */ +#define GVM_MAGIC 0x19330825 + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_gvm_h */ + diff --git a/include/VBox/vmm/gvm.mac b/include/VBox/vmm/gvm.mac new file mode 100644 index 00000000..af43f6ed --- /dev/null +++ b/include/VBox/vmm/gvm.mac @@ -0,0 +1,118 @@ +;; @file +; GVM - The Global VM Data. +; + +; +; Copyright (C) 2006-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox 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. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef ___VBox_vmm_gvm_mac +%define ___VBox_vmm_gvm_mac + +%include "VBox/vmm/vm.mac" + +struc GVMCPU + .s resb VMCPU_size + + .idCpu resd 1 + + alignb 8 + .hEMT RTR0PTR_RES 1 + .pGVM RTR0PTR_RES 1 + .pVMR0 RTR0PTR_RES 1 + .pVCpuR3 RTR3PTR_RES 1 + + alignb 64 + .idHostCpu resd 1 + .iHostCpuSet resd 1 + + alignb 64 + .gvmm resb 256 + alignb 64 + .hmr0 resb 1024 +%ifdef VBOX_WITH_NEM_R0 + .nemr0 resb 64 +%endif + alignb 64 + .vmmr0 resb 896 + alignb 64 + .pgmr0 resb 64 + alignb 16384 +endstruc + + +struc GVM + .s resb VM_size + + .u32Magic resd 1 + .hSelf resd 1 + alignb 8 + .pSelf RTR0PTR_RES 1 + .pVMR3 RTR3PTR_RES 1 + .pSession RTR0PTR_RES 1 + .cCpus resd 1 + + alignb 64 + .gvmm resb 4352 + alignb 64 + .gmm resb 1024 + alignb 64 + .hmr0 resb 256 +%ifdef VBOX_WITH_NEM_R0 + alignb 64 + .nemr0 resb 256 +%endif + alignb 64 + .rawpci resb 64 + alignb 64 + .pdmr0 resb 3008 + alignb 64 + .pgmr0 resb 1920 + alignb 64 + .iomr0 resb 512 + alignb 64 + .apicr0 resb 64 + alignb 64 + .dbgfr0 resb 1024 + alignb 64 + .tmr0 resb 128 + + times ((($ + VMM_MAX_CPU_COUNT * RTR0PTR_CB + 16383) & ~16383) - ($ + VMM_MAX_CPU_COUNT * RTR0PTR_CB)) resb 1 + .apCpusR0 RTR0PTR_RES VMM_MAX_CPU_COUNT + + alignb 16384 + .aCpus resb GVMCPU_size +endstruc + +%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..788c41d4 --- /dev/null +++ b/include/VBox/vmm/gvmm.h @@ -0,0 +1,364 @@ +/* $Id: gvmm.h $ */ +/** @file + * GVMM - The Global VM Manager. + */ + +/* + * Copyright (C) 2007-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_gvmm_h +#define VBOX_INCLUDED_vmm_gvmm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <VBox/vmm/stam.h> +#include <VBox/sup.h> +#include <VBox/param.h> +#include <iprt/cpuset.h> /* RTCPUSET_MAX_CPUS */ + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_gvmm GVMM - The Global VM Manager. + * @ingroup grp_vmm + * @{ + */ + +/** @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; + +/** + * Per VCpu statistics + */ +typedef struct GVMMSTATSVMCPU +{ + uint32_t cWakeUpTimerHits; + uint32_t cWakeUpTimerMisses; + uint32_t cWakeUpTimerCanceled; + uint32_t cWakeUpTimerSameCpu; + STAMPROFILE Start; + STAMPROFILE Stop; +} GVMMSTATSVMCPU; +/** Ptoiner to the GVMM per VCpu statistics. */ +typedef GVMMSTATSVMCPU *PGVMMSTATSVMCPU; + +/** + * 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 EMT statistics for the specified VM, zero if non specified. */ + GVMMSTATSVMCPU aVCpus[VMM_MAX_CPU_COUNT]; + /** 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; + +/** + * Per-VM callback for GVMMR0EnumVMs. + * + * @note This is called while holding the VM used list lock, so only suitable + * for quick and simple jobs! + * + * @returns VINF_SUCCESS to continue the enumeration, anything stops it and + * returns the status code. + * @param pGVM The VM + * @param pvUser The user parameter. + * */ +typedef DECLCALLBACKTYPE(int, FNGVMMR0ENUMCALLBACK,(PGVM pGVM, void *pvUser)); +/** Pointer to an VM enumeration callback function. */ +typedef FNGVMMR0ENUMCALLBACK *PFNGVMMR0ENUMCALLBACK; + +/** + * Worker thread IDs. + */ +typedef enum GVMMWORKERTHREAD +{ + /** The usual invalid zero value. */ + GVMMWORKERTHREAD_INVALID = 0, + /** PGM handy page allocator thread. */ + GVMMWORKERTHREAD_PGM_ALLOCATOR, + /** End of valid worker thread values. */ + GVMMWORKERTHREAD_END, + /** Make sure the type size is 32 bits. */ + GVMMWORKERTHREAD_32_BIT_HACK = 0x7fffffff +} GVMMWORKERTHREAD; + +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, PVMCC *ppVM); +GVMMR0DECL(int) GVMMR0InitVM(PGVM pGVM); +GVMMR0DECL(void) GVMMR0DoneInitVM(PGVM pGVM); +GVMMR0DECL(bool) GVMMR0DoingTermVM(PGVM pGVM); +GVMMR0DECL(int) GVMMR0DestroyVM(PGVM pGVM); +GVMMR0DECL(int) GVMMR0RegisterVCpu(PGVM pGVM, VMCPUID idCpu); +GVMMR0DECL(int) GVMMR0DeregisterVCpu(PGVM pGVM, VMCPUID idCpu); +GVMMR0DECL(int) GVMMR0RegisterWorkerThread(PGVM pGVM, GVMMWORKERTHREAD enmWorker, RTNATIVETHREAD hThreadR3); +GVMMR0DECL(int) GVMMR0DeregisterWorkerThread(PGVM pGVM, GVMMWORKERTHREAD enmWorker); +GVMMR0DECL(PGVM) GVMMR0ByHandle(uint32_t hGVM); +GVMMR0DECL(int) GVMMR0ValidateGVM(PGVM pGVM); +GVMMR0DECL(int) GVMMR0ValidateGVMandEMT(PGVM pGVM, VMCPUID idCpu); +GVMMR0DECL(int) GVMMR0ValidateGVMandEMTorWorker(PGVM pGVM, VMCPUID idCpu, GVMMWORKERTHREAD enmWorker); +GVMMR0DECL(PVMCC) GVMMR0GetVMByEMT(RTNATIVETHREAD hEMT); +GVMMR0DECL(PGVMCPU) GVMMR0GetGVCpuByEMT(RTNATIVETHREAD hEMT); +GVMMR0DECL(PGVMCPU) GVMMR0GetGVCpuByGVMandEMT(PGVM pGVM, RTNATIVETHREAD hEMT); +GVMMR0DECL(RTNATIVETHREAD) GVMMR0GetRing3ThreadForSelf(PGVM pGVM); +GVMMR0DECL(RTHCPHYS) GVMMR0ConvertGVMPtr2HCPhys(PGVM pGVM, void *pv); +GVMMR0DECL(int) GVMMR0SchedHalt(PGVM pGVM, PGVMCPU pGVCpu, uint64_t u64ExpireGipTime); +GVMMR0DECL(int) GVMMR0SchedHaltReq(PGVM pGVM, VMCPUID idCpu, uint64_t u64ExpireGipTime); +GVMMR0DECL(int) GVMMR0SchedWakeUp(PGVM pGVM, VMCPUID idCpu); +GVMMR0DECL(int) GVMMR0SchedWakeUpEx(PGVM pGVM, VMCPUID idCpu, bool fTakeUsedLock); +GVMMR0DECL(int) GVMMR0SchedWakeUpNoGVMNoLock(PGVM pGVM, VMCPUID idCpu); +GVMMR0DECL(int) GVMMR0SchedPoke(PGVM pGVM, VMCPUID idCpu); +GVMMR0DECL(int) GVMMR0SchedPokeEx(PGVM pGVM, VMCPUID idCpu, bool fTakeUsedLock); +GVMMR0DECL(int) GVMMR0SchedPokeNoGVMNoLock(PVMCC pVM, VMCPUID idCpu); +GVMMR0DECL(int) GVMMR0SchedWakeUpAndPokeCpus(PGVM pGVM, PCVMCPUSET pSleepSet, PCVMCPUSET pPokeSet); +GVMMR0DECL(int) GVMMR0SchedPoll(PGVM pGVM, VMCPUID idCpu, bool fYield); +GVMMR0DECL(void) GVMMR0SchedUpdatePeriodicPreemptionTimer(PGVM pGVM, RTCPUID idHostCpu, uint32_t uHz); +GVMMR0DECL(int) GVMMR0EnumVMs(PFNGVMMR0ENUMCALLBACK pfnCallback, void *pvUser); +GVMMR0DECL(int) GVMMR0QueryStatistics(PGVMMSTATS pStats, PSUPDRVSESSION pSession, PGVM pGVM); +GVMMR0DECL(int) GVMMR0ResetStatistics(PCGVMMSTATS pStats, PSUPDRVSESSION pSession, PGVM pGVM); + + +/** + * 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, PSUPDRVSESSION pSession); + + +/** + * Request packet for calling GVMMR0RegisterWorkerThread. + */ +typedef struct GVMMREGISTERWORKERTHREADREQ +{ + /** The request header. */ + SUPVMMR0REQHDR Hdr; + /** Ring-3 native thread handle of the caller. (IN) */ + RTNATIVETHREAD hNativeThreadR3; +} GVMMREGISTERWORKERTHREADREQ; +/** Pointer to a GVMMR0RegisterWorkerThread request packet. */ +typedef GVMMREGISTERWORKERTHREADREQ *PGVMMREGISTERWORKERTHREADREQ; + + +/** + * 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(PGVM pGVM, 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(PGVM pGVM, PGVMMQUERYSTATISTICSSREQ pReq, PSUPDRVSESSION pSession); + + +/** + * 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(PGVM pGVM, PGVMMRESETSTATISTICSSREQ pReq, PSUPDRVSESSION pSession); + + +#ifdef IN_RING3 +VMMR3_INT_DECL(int) GVMMR3CreateVM(PUVM pUVM, uint32_t cCpus, PSUPDRVSESSION pSession, PVM *ppVM, PRTR0PTR ppVMR0); +VMMR3_INT_DECL(int) GVMMR3DestroyVM(PUVM pUVM, PVM pVM); +VMMR3_INT_DECL(int) GVMMR3RegisterVCpu(PVM pVM, VMCPUID idCpu); +VMMR3_INT_DECL(int) GVMMR3DeregisterVCpu(PVM pVM, VMCPUID idCpu); +VMMR3_INT_DECL(int) GVMMR3RegisterWorkerThread(PVM pVM, GVMMWORKERTHREAD enmWorker); +VMMR3_INT_DECL(int) GVMMR3DeregisterWorkerThread(PVM pVM, GVMMWORKERTHREAD enmWorker); +#endif + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_gvmm_h */ + diff --git a/include/VBox/vmm/hm.h b/include/VBox/vmm/hm.h new file mode 100644 index 00000000..2dc1d976 --- /dev/null +++ b/include/VBox/vmm/hm.h @@ -0,0 +1,336 @@ +/** @file + * HM - Intel/AMD VM Hardware Assisted Virtualization Manager (VMM) + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_hm_h +#define VBOX_INCLUDED_vmm_hm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/vmm/pgm.h> +#include <VBox/vmm/cpum.h> +#include <VBox/vmm/vmm.h> +#include <VBox/vmm/hm_svm.h> +#include <VBox/vmm/hm_vmx.h> +#include <VBox/vmm/trpm.h> +#include <iprt/mp.h> + + +/** @defgroup grp_hm The Hardware Assisted Virtualization Manager API + * @ingroup grp_vmm + * @{ + */ + +RT_C_DECLS_BEGIN + +/** + * Checks whether HM (VT-x/AMD-V) is being used by this VM. + * + * @retval true if used. + * @retval false if software virtualization (raw-mode) or NEM is used. + * + * @param a_pVM The cross context VM structure. + * @deprecated Please use VM_IS_RAW_MODE_ENABLED, VM_IS_HM_OR_NEM_ENABLED, or + * VM_IS_HM_ENABLED instead. + * @internal + */ +#if defined(VBOX_STRICT) && defined(IN_RING3) +# define HMIsEnabled(a_pVM) HMIsEnabledNotMacro(a_pVM) +#else +# define HMIsEnabled(a_pVM) ((a_pVM)->fHMEnabled) +#endif + +/** + * Checks whether raw-mode context is required for HM purposes + * + * @retval true if required by HM for doing switching the cpu to 64-bit mode. + * @retval false if not required by HM. + * + * @param a_pVM The cross context VM structure. + * @internal + */ +#if HC_ARCH_BITS == 64 +# define HMIsRawModeCtxNeeded(a_pVM) (false) +#else +# define HMIsRawModeCtxNeeded(a_pVM) ((a_pVM)->fHMNeedRawModeCtx) +#endif + +/** + * Checks whether we're in the special hardware virtualization context. + * @returns true / false. + * @param a_pVCpu The caller's cross context virtual CPU structure. + * @thread EMT + */ +#ifdef IN_RING0 +# define HMIsInHwVirtCtx(a_pVCpu) (VMCPU_GET_STATE(a_pVCpu) == VMCPUSTATE_STARTED_HM) +#else +# define HMIsInHwVirtCtx(a_pVCpu) (false) +#endif + +/** + * Checks whether we're in the special hardware virtualization context and we + * cannot perform long jump without guru meditating and possibly messing up the + * host and/or guest state. + * + * This is after we've turned interrupts off and such. + * + * @returns true / false. + * @param a_pVCpu The caller's cross context virtual CPU structure. + * @thread EMT + */ +#ifdef IN_RING0 +# define HMIsInHwVirtNoLongJmpCtx(a_pVCpu) (VMCPU_GET_STATE(a_pVCpu) == VMCPUSTATE_STARTED_EXEC) +#else +# define HMIsInHwVirtNoLongJmpCtx(a_pVCpu) (false) +#endif + +/** @name All-context HM API. + * @{ */ +VMMDECL(bool) HMIsEnabledNotMacro(PVM pVM); +VMMDECL(bool) HMCanExecuteGuest(PVMCC pVM, PVMCPUCC pVCpu, PCCPUMCTX pCtx); +VMM_INT_DECL(int) HMInvalidatePage(PVMCPUCC pVCpu, RTGCPTR GCVirt); +VMM_INT_DECL(bool) HMHasPendingIrq(PVMCC pVM); +VMM_INT_DECL(bool) HMSetSingleInstruction(PVMCC pVM, PVMCPUCC pVCpu, bool fEnable); +VMM_INT_DECL(bool) HMIsSvmActive(PVM pVM); +VMM_INT_DECL(bool) HMIsVmxActive(PVM pVM); +VMM_INT_DECL(const char *) HMGetVmxDiagDesc(VMXVDIAG enmDiag); +VMM_INT_DECL(const char *) HMGetVmxExitName(uint32_t uExit); +VMM_INT_DECL(const char *) HMGetSvmExitName(uint32_t uExit); +VMM_INT_DECL(void) HMDumpHwvirtVmxState(PVMCPU pVCpu); +VMM_INT_DECL(void) HMHCChangedPagingMode(PVM pVM, PVMCPUCC pVCpu, PGMMODE enmShadowMode, PGMMODE enmGuestMode); +VMM_INT_DECL(void) HMGetVmxMsrsFromHwvirtMsrs(PCSUPHWVIRTMSRS pMsrs, PVMXMSRS pVmxMsrs); +VMM_INT_DECL(void) HMGetSvmMsrsFromHwvirtMsrs(PCSUPHWVIRTMSRS pMsrs, PSVMMSRS pSvmMsrs); +/** @} */ + +/** @name All-context VMX helpers. + * + * These are hardware-assisted VMX functions (used by IEM/REM/CPUM and HM). Helpers + * based purely on the Intel VT-x specification (used by IEM/REM and HM) can be + * found in CPUM. + * @{ */ +#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +VMM_INT_DECL(bool) HMIsSubjectToVmxPreemptTimerErratum(void); +#endif +VMM_INT_DECL(bool) HMCanExecuteVmxGuest(PVMCC pVM, PVMCPUCC pVCpu, PCCPUMCTX pCtx); +VMM_INT_DECL(TRPMEVENT) HMVmxEventTypeToTrpmEventType(uint32_t uIntInfo); +VMM_INT_DECL(uint32_t) HMTrpmEventTypeToVmxEventType(uint8_t uVector, TRPMEVENT enmTrpmEvent, bool fIcebp); +/** @} */ + +/** @name All-context SVM helpers. + * + * These are hardware-assisted SVM functions (used by IEM/REM/CPUM and HM). Helpers + * based purely on the AMD SVM specification (used by IEM/REM and HM) can be found + * in CPUM. + * @{ */ +VMM_INT_DECL(TRPMEVENT) HMSvmEventToTrpmEventType(PCSVMEVENT pSvmEvent, uint8_t uVector); +/** @} */ + +#ifndef IN_RC + +/** @name R0, R3 HM (VMX/SVM agnostic) handlers. + * @{ */ +VMM_INT_DECL(int) HMFlushTlb(PVMCPU pVCpu); +VMM_INT_DECL(int) HMFlushTlbOnAllVCpus(PVMCC pVM); +VMM_INT_DECL(int) HMInvalidatePageOnAllVCpus(PVMCC pVM, RTGCPTR GCVirt); +VMM_INT_DECL(int) HMInvalidatePhysPage(PVMCC pVM, RTGCPHYS GCPhys); +VMM_INT_DECL(bool) HMAreNestedPagingAndFullGuestExecEnabled(PVMCC pVM); +VMM_INT_DECL(bool) HMIsLongModeAllowed(PVMCC pVM); +VMM_INT_DECL(bool) HMIsNestedPagingActive(PVMCC pVM); +VMM_INT_DECL(bool) HMIsMsrBitmapActive(PVM pVM); +# ifdef VBOX_WITH_NESTED_HWVIRT_VMX +VMM_INT_DECL(void) HMNotifyVmxNstGstVmexit(PVMCPU pVCpu); +VMM_INT_DECL(void) HMNotifyVmxNstGstCurrentVmcsChanged(PVMCPU pVCpu); +# endif +/** @} */ + +/** @name R0, R3 SVM handlers. + * @{ */ +VMM_INT_DECL(bool) HMIsSvmVGifActive(PCVMCC pVM); +# ifdef VBOX_WITH_NESTED_HWVIRT_SVM +VMM_INT_DECL(void) HMNotifySvmNstGstVmexit(PVMCPUCC pVCpu, PCPUMCTX pCtx); +# endif +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +VMM_INT_DECL(int) HMIsSubjectToSvmErratum170(uint32_t *pu32Family, uint32_t *pu32Model, uint32_t *pu32Stepping); +# endif +VMM_INT_DECL(int) HMHCMaybeMovTprSvmHypercall(PVMCC pVM, PVMCPUCC pVCpu); +/** @} */ + +#else /* Nops in RC: */ + +/** @name RC HM (VMX/SVM agnostic) handlers. + * @{ */ +# define HMFlushTlb(pVCpu) do { } while (0) +# define HMFlushTlbOnAllVCpus(pVM) do { } while (0) +# define HMInvalidatePageOnAllVCpus(pVM, GCVirt) do { } while (0) +# define HMInvalidatePhysPage(pVM, GCVirt) do { } while (0) +# define HMAreNestedPagingAndFullGuestExecEnabled(pVM) false +# define HMIsLongModeAllowed(pVM) false +# define HMIsNestedPagingActive(pVM) false +# define HMIsMsrBitmapsActive(pVM) false +/** @} */ + +/** @name RC SVM handlers. + * @{ */ +# define HMIsSvmVGifActive(pVM) false +# define HMNotifySvmNstGstVmexit(pVCpu, pCtx) do { } while (0) +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# define HMIsSubjectToSvmErratum170(puFamily, puModel, puStepping) false +# endif +# define HMHCMaybeMovTprSvmHypercall(pVM, pVCpu) do { } while (0) +/** @} */ + +#endif + +/** @name HMVMX_READ_XXX - Flags for reading auxiliary VM-exit VMCS fields. + * + * These flags allow reading VMCS fields that are not necessarily part of the + * guest-CPU state but are needed while handling VM-exits. + * + * @note If you add any fields here, make sure to update VMXR0GetExitAuxInfo. + * + * @{ + */ +#define HMVMX_READ_IDT_VECTORING_INFO RT_BIT_32(0) +#define HMVMX_READ_IDT_VECTORING_ERROR_CODE RT_BIT_32(1) +#define HMVMX_READ_EXIT_QUALIFICATION RT_BIT_32(2) +#define HMVMX_READ_EXIT_INSTR_LEN RT_BIT_32(3) +#define HMVMX_READ_EXIT_INTERRUPTION_INFO RT_BIT_32(4) +#define HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE RT_BIT_32(5) +#define HMVMX_READ_EXIT_INSTR_INFO RT_BIT_32(6) +#define HMVMX_READ_GUEST_LINEAR_ADDR RT_BIT_32(7) +#define HMVMX_READ_GUEST_PHYSICAL_ADDR RT_BIT_32(8) +#define HMVMX_READ_GUEST_PENDING_DBG_XCPTS RT_BIT_32(9) + +/** All the VMCS fields required for processing of exception/NMI VM-exits. */ +#define HMVMX_READ_XCPT_INFO ( HMVMX_READ_EXIT_INTERRUPTION_INFO \ + | HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE \ + | HMVMX_READ_EXIT_INSTR_LEN \ + | HMVMX_READ_IDT_VECTORING_INFO \ + | HMVMX_READ_IDT_VECTORING_ERROR_CODE) + +/** Mask of all valid HMVMX_READ_XXX flags. */ +#define HMVMX_READ_VALID_MASK ( HMVMX_READ_IDT_VECTORING_INFO \ + | HMVMX_READ_IDT_VECTORING_ERROR_CODE \ + | HMVMX_READ_EXIT_QUALIFICATION \ + | HMVMX_READ_EXIT_INSTR_LEN \ + | HMVMX_READ_EXIT_INTERRUPTION_INFO \ + | HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE \ + | HMVMX_READ_EXIT_INSTR_INFO \ + | HMVMX_READ_GUEST_LINEAR_ADDR \ + | HMVMX_READ_GUEST_PHYSICAL_ADDR \ + | HMVMX_READ_GUEST_PENDING_DBG_XCPTS) +/** @} */ + +#ifdef IN_RING0 +/** @defgroup grp_hm_r0 The HM ring-0 Context API + * @{ + */ +/** + * HM VM-exit auxiliary info. + */ +typedef union +{ + /** VMX VM-exit auxiliary info. */ + VMXEXITAUX Vmx; + /** SVM \#VMEXIT auxiliary info. */ + SVMEXITAUX Svm; +} HMEXITAUX; +/** Pointer to HM-exit auxiliary info union. */ +typedef HMEXITAUX *PHMEXITAUX; +/** Pointer to a const HM-exit auxiliary info union. */ +typedef const HMEXITAUX *PCHMEXITAUX; + +VMMR0_INT_DECL(int) HMR0Init(void); +VMMR0_INT_DECL(int) HMR0Term(void); +VMMR0_INT_DECL(int) HMR0InitVM(PVMCC pVM); +VMMR0_INT_DECL(int) HMR0TermVM(PVMCC pVM); +VMMR0_INT_DECL(int) HMR0EnableAllCpus(PVMCC pVM); +# ifdef VBOX_WITH_RAW_MODE +VMMR0_INT_DECL(int) HMR0EnterSwitcher(PVMCC pVM, VMMSWITCHER enmSwitcher, bool *pfVTxDisabled); +VMMR0_INT_DECL(void) HMR0LeaveSwitcher(PVMCC pVM, bool fVTxDisabled); +# endif + +VMMR0_INT_DECL(int) HMR0SetupVM(PVMCC pVM); +VMMR0_INT_DECL(int) HMR0RunGuestCode(PVMCC pVM, PVMCPUCC pVCpu); +VMMR0_INT_DECL(int) HMR0Enter(PVMCPUCC pVCpu); +VMMR0_INT_DECL(int) HMR0LeaveCpu(PVMCPUCC pVCpu); +VMMR0_INT_DECL(void) HMR0ThreadCtxCallback(RTTHREADCTXEVENT enmEvent, void *pvUser); +VMMR0_INT_DECL(void) HMR0NotifyCpumUnloadedGuestFpuState(PVMCPUCC VCpu); +VMMR0_INT_DECL(void) HMR0NotifyCpumModifiedHostCr0(PVMCPUCC VCpu); +VMMR0_INT_DECL(bool) HMR0SuspendPending(void); +VMMR0_INT_DECL(int) HMR0InvalidatePage(PVMCPUCC pVCpu, RTGCPTR GCVirt); +VMMR0_INT_DECL(int) HMR0ImportStateOnDemand(PVMCPUCC pVCpu, uint64_t fWhat); +VMMR0_INT_DECL(int) HMR0GetExitAuxInfo(PVMCPUCC pVCpu, PHMEXITAUX pHmExitAux, uint32_t fWhat); +/** @} */ +#endif /* IN_RING0 */ + + +#ifdef IN_RING3 +/** @defgroup grp_hm_r3 The HM ring-3 Context API + * @{ + */ +VMMR3DECL(bool) HMR3IsEnabled(PUVM pUVM); +VMMR3DECL(bool) HMR3IsNestedPagingActive(PUVM pUVM); +VMMR3DECL(bool) HMR3AreVirtApicRegsEnabled(PUVM pUVM); +VMMR3DECL(bool) HMR3IsPostedIntrsEnabled(PUVM pUVM); +VMMR3DECL(bool) HMR3IsVpidActive(PUVM pUVM); +VMMR3DECL(bool) HMR3IsUXActive(PUVM pUVM); +VMMR3DECL(bool) HMR3IsSvmEnabled(PUVM pUVM); +VMMR3DECL(bool) HMR3IsVmxEnabled(PUVM pUVM); + +VMMR3_INT_DECL(int) HMR3Init(PVM pVM); +VMMR3_INT_DECL(int) HMR3InitCompleted(PVM pVM, VMINITCOMPLETED enmWhat); +VMMR3_INT_DECL(void) HMR3Relocate(PVM pVM); +VMMR3_INT_DECL(int) HMR3Term(PVM pVM); +VMMR3_INT_DECL(void) HMR3Reset(PVM pVM); +VMMR3_INT_DECL(void) HMR3ResetCpu(PVMCPU pVCpu); +VMMR3_INT_DECL(void) HMR3CheckError(PVM pVM, int iStatusCode); +VMMR3_INT_DECL(void) HMR3NotifyDebugEventChanged(PVM pVM); +VMMR3_INT_DECL(void) HMR3NotifyDebugEventChangedPerCpu(PVM pVM, PVMCPU pVCpu); +VMMR3_INT_DECL(bool) HMR3IsActive(PCVMCPU pVCpu); +VMMR3_INT_DECL(int) HMR3EnablePatching(PVM pVM, RTGCPTR pPatchMem, unsigned cbPatchMem); +VMMR3_INT_DECL(int) HMR3DisablePatching(PVM pVM, RTGCPTR pPatchMem, unsigned cbPatchMem); +VMMR3_INT_DECL(int) HMR3PatchTprInstr(PVM pVM, PVMCPU pVCpu); +VMMR3_INT_DECL(bool) HMR3IsRescheduleRequired(PVM pVM, PCCPUMCTX pCtx); +VMMR3_INT_DECL(bool) HMR3IsVmxPreemptionTimerUsed(PVM pVM); +/** @} */ +#endif /* IN_RING3 */ + +/** @} */ +RT_C_DECLS_END + + +#endif /* !VBOX_INCLUDED_vmm_hm_h */ + diff --git a/include/VBox/vmm/hm_svm.h b/include/VBox/vmm/hm_svm.h new file mode 100644 index 00000000..403480c5 --- /dev/null +++ b/include/VBox/vmm/hm_svm.h @@ -0,0 +1,1169 @@ +/** @file + * HM - SVM (AMD-V) Structures and Definitions. (VMM) + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_hm_svm_h +#define VBOX_INCLUDED_vmm_hm_svm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <iprt/assert.h> +#include <iprt/asm.h> + +#ifdef RT_OS_SOLARIS +# undef ES +# undef CS +# undef DS +# undef SS +# undef FS +# undef GS +#endif + +/** @defgroup grp_hm_svm SVM (AMD-V) Types and Definitions + * @ingroup grp_hm + * @{ + */ + +/** @name SVM generic / convenient defines. + * @{ + */ +/** Number of pages required for the VMCB. */ +#define SVM_VMCB_PAGES 1 +/** Number of pages required for the MSR permission bitmap. */ +#define SVM_MSRPM_PAGES 2 +/** Number of pages required for the IO permission bitmap. */ +#define SVM_IOPM_PAGES 3 +/** @} */ + +/* + * Ugly! + * When compiling the recompiler, its own svm.h defines clash with + * the following defines. Avoid just the duplicates here as we still + * require other definitions and structures in this header. + */ +#ifndef IN_REM_R3 +/** @name SVM_EXIT_XXX - SVM Basic Exit Reasons. + * @{ + */ +/** Invalid guest state in VMCB. */ +# define SVM_EXIT_INVALID (uint64_t)(-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_XCPT_0 0x40 +# define SVM_EXIT_XCPT_1 0x41 +# define SVM_EXIT_XCPT_2 0x42 +# define SVM_EXIT_XCPT_3 0x43 +# define SVM_EXIT_XCPT_4 0x44 +# define SVM_EXIT_XCPT_5 0x45 +# define SVM_EXIT_XCPT_6 0x46 +# define SVM_EXIT_XCPT_7 0x47 +# define SVM_EXIT_XCPT_8 0x48 +# define SVM_EXIT_XCPT_9 0x49 +# define SVM_EXIT_XCPT_10 0x4a +# define SVM_EXIT_XCPT_11 0x4b +# define SVM_EXIT_XCPT_12 0x4c +# define SVM_EXIT_XCPT_13 0x4d +# define SVM_EXIT_XCPT_14 0x4e +# define SVM_EXIT_XCPT_15 0x4f +# define SVM_EXIT_XCPT_16 0x50 +# define SVM_EXIT_XCPT_17 0x51 +# define SVM_EXIT_XCPT_18 0x52 +# define SVM_EXIT_XCPT_19 0x53 +# define SVM_EXIT_XCPT_20 0x54 +# define SVM_EXIT_XCPT_21 0x55 +# define SVM_EXIT_XCPT_22 0x56 +# define SVM_EXIT_XCPT_23 0x57 +# define SVM_EXIT_XCPT_24 0x58 +# define SVM_EXIT_XCPT_25 0x59 +# define SVM_EXIT_XCPT_26 0x5a +# define SVM_EXIT_XCPT_27 0x5b +# define SVM_EXIT_XCPT_28 0x5c +# define SVM_EXIT_XCPT_29 0x5d +# define SVM_EXIT_XCPT_30 0x5e +# define SVM_EXIT_XCPT_31 0x5f +/* Exception (more readable) */ +# define SVM_EXIT_XCPT_DE SVM_EXIT_XCPT_0 +# define SVM_EXIT_XCPT_DB SVM_EXIT_XCPT_1 +# define SVM_EXIT_XCPT_NMI SVM_EXIT_XCPT_2 +# define SVM_EXIT_XCPT_BP SVM_EXIT_XCPT_3 +# define SVM_EXIT_XCPT_OF SVM_EXIT_XCPT_4 +# define SVM_EXIT_XCPT_BR SVM_EXIT_XCPT_5 +# define SVM_EXIT_XCPT_UD SVM_EXIT_XCPT_6 +# define SVM_EXIT_XCPT_NM SVM_EXIT_XCPT_7 +# define SVM_EXIT_XCPT_DF SVM_EXIT_XCPT_8 +# define SVM_EXIT_XCPT_CO_SEG_OVERRUN SVM_EXIT_XCPT_9 +# define SVM_EXIT_XCPT_TS SVM_EXIT_XCPT_10 +# define SVM_EXIT_XCPT_NP SVM_EXIT_XCPT_11 +# define SVM_EXIT_XCPT_SS SVM_EXIT_XCPT_12 +# define SVM_EXIT_XCPT_GP SVM_EXIT_XCPT_13 +# define SVM_EXIT_XCPT_PF SVM_EXIT_XCPT_14 +# define SVM_EXIT_XCPT_MF SVM_EXIT_XCPT_16 +# define SVM_EXIT_XCPT_AC SVM_EXIT_XCPT_17 +# define SVM_EXIT_XCPT_MC SVM_EXIT_XCPT_18 +# define SVM_EXIT_XCPT_XF SVM_EXIT_XCPT_19 +# define SVM_EXIT_XCPT_VE SVM_EXIT_XCPT_20 +# define SVM_EXIT_XCPT_SX SVM_EXIT_XCPT_30 +/** 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. */ +# define SVM_EXIT_MWAIT 0x8b +/** MWAIT instruction, when armed. */ +# define SVM_EXIT_MWAIT_ARMED 0x8c +/** XSETBV instruction. */ +# define SVM_EXIT_XSETBV 0x8d +/** RDPRU instruction. */ +# define SVM_EXIT_RDPRU 0x8e +/** Write to EFER (after guest instruction completes). */ +# define SVM_EXIT_WRITE_EFER_TRAP 0x8f +/** Write to CR0-CR15 (after guest instruction completes). */ +# define SVM_EXIT_WRITE_CR0_TRAP 0x90 +# define SVM_EXIT_WRITE_CR1_TRAP 0x91 +# define SVM_EXIT_WRITE_CR2_TRAP 0x92 +# define SVM_EXIT_WRITE_CR3_TRAP 0x93 +# define SVM_EXIT_WRITE_CR4_TRAP 0x94 +# define SVM_EXIT_WRITE_CR5_TRAP 0x95 +# define SVM_EXIT_WRITE_CR6_TRAP 0x96 +# define SVM_EXIT_WRITE_CR7_TRAP 0x97 +# define SVM_EXIT_WRITE_CR8_TRAP 0x98 +# define SVM_EXIT_WRITE_CR9_TRAP 0x99 +# define SVM_EXIT_WRITE_CR10_TRAP 0x9a +# define SVM_EXIT_WRITE_CR11_TRAP 0x9b +# define SVM_EXIT_WRITE_CR12_TRAP 0x9c +# define SVM_EXIT_WRITE_CR13_TRAP 0x9d +# define SVM_EXIT_WRITE_CR14_TRAP 0x9e +# define SVM_EXIT_WRITE_CR15_TRAP 0x9f +/** MCOMMIT instruction. */ +# define SVM_EXIT_MCOMMIT 0xa3 + +/** 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 +/** AVIC: Virtual IPI delivery not completed. */ +# define SVM_EXIT_AVIC_INCOMPLETE_IPI 0x401 +/** AVIC: Attempted access by guest to a vAPIC register not handled by AVIC + * hardware. */ +# define SVM_EXIT_AVIC_NOACCEL 0x402 +/** The maximum possible exit value. */ +# define SVM_EXIT_MAX (SVM_EXIT_AVIC_NOACCEL) +/** @} */ +#endif /* !IN_REM_R3*/ + + +/** @name SVMVMCB.u64ExitInfo2 for task switches + * @{ + */ +/** 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_JUMP 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 SVMVMCB.u64ExitInfo1 for MSR accesses + * @{ + */ +/** The access was a read MSR. */ +#define SVM_EXIT1_MSR_READ 0x0 +/** The access was a write MSR. */ +#define SVM_EXIT1_MSR_WRITE 0x1 +/** @} */ + +/** @name SVMVMCB.u64ExitInfo1 for Mov CRx accesses. + * @{ + */ +/** The mask of whether the access was via a Mov CRx instruction. */ +#define SVM_EXIT1_MOV_CRX_MASK RT_BIT_64(63) +/** The mask for the GPR number of the Mov CRx instruction. */ +#define SVM_EXIT1_MOV_CRX_GPR_NUMBER 0xf +/** @} */ + +/** @name SVMVMCB.u64ExitInfo1 for Mov DRx accesses. + * @{ + */ +/** The mask for the GPR number of the Mov DRx instruction. */ +#define SVM_EXIT1_MOV_DRX_GPR_NUMBER 0xf +/** @} */ + +/** @name SVMVMCB.ctrl.u64InterceptCtrl + * @{ + */ +/** Intercept INTR (physical maskable interrupt). */ +#define SVM_CTRL_INTERCEPT_INTR RT_BIT_64(0) +/** Intercept NMI. */ +#define SVM_CTRL_INTERCEPT_NMI RT_BIT_64(1) +/** Intercept SMI. */ +#define SVM_CTRL_INTERCEPT_SMI RT_BIT_64(2) +/** Intercept INIT. */ +#define SVM_CTRL_INTERCEPT_INIT RT_BIT_64(3) +/** Intercept VINTR (virtual maskable interrupt). */ +#define SVM_CTRL_INTERCEPT_VINTR RT_BIT_64(4) +/** Intercept CR0 writes that change bits other than CR0.TS or CR0.MP */ +#define SVM_CTRL_INTERCEPT_CR0_SEL_WRITE RT_BIT_64(5) +/** Intercept reads of IDTR. */ +#define SVM_CTRL_INTERCEPT_IDTR_READS RT_BIT_64(6) +/** Intercept reads of GDTR. */ +#define SVM_CTRL_INTERCEPT_GDTR_READS RT_BIT_64(7) +/** Intercept reads of LDTR. */ +#define SVM_CTRL_INTERCEPT_LDTR_READS RT_BIT_64(8) +/** Intercept reads of TR. */ +#define SVM_CTRL_INTERCEPT_TR_READS RT_BIT_64(9) +/** Intercept writes of IDTR. */ +#define SVM_CTRL_INTERCEPT_IDTR_WRITES RT_BIT_64(10) +/** Intercept writes of GDTR. */ +#define SVM_CTRL_INTERCEPT_GDTR_WRITES RT_BIT_64(11) +/** Intercept writes of LDTR. */ +#define SVM_CTRL_INTERCEPT_LDTR_WRITES RT_BIT_64(12) +/** Intercept writes of TR. */ +#define SVM_CTRL_INTERCEPT_TR_WRITES RT_BIT_64(13) +/** Intercept RDTSC instruction. */ +#define SVM_CTRL_INTERCEPT_RDTSC RT_BIT_64(14) +/** Intercept RDPMC instruction. */ +#define SVM_CTRL_INTERCEPT_RDPMC RT_BIT_64(15) +/** Intercept PUSHF instruction. */ +#define SVM_CTRL_INTERCEPT_PUSHF RT_BIT_64(16) +/** Intercept POPF instruction. */ +#define SVM_CTRL_INTERCEPT_POPF RT_BIT_64(17) +/** Intercept CPUID instruction. */ +#define SVM_CTRL_INTERCEPT_CPUID RT_BIT_64(18) +/** Intercept RSM instruction. */ +#define SVM_CTRL_INTERCEPT_RSM RT_BIT_64(19) +/** Intercept IRET instruction. */ +#define SVM_CTRL_INTERCEPT_IRET RT_BIT_64(20) +/** Intercept INTn instruction. */ +#define SVM_CTRL_INTERCEPT_INTN RT_BIT_64(21) +/** Intercept INVD instruction. */ +#define SVM_CTRL_INTERCEPT_INVD RT_BIT_64(22) +/** Intercept PAUSE instruction. */ +#define SVM_CTRL_INTERCEPT_PAUSE RT_BIT_64(23) +/** Intercept HLT instruction. */ +#define SVM_CTRL_INTERCEPT_HLT RT_BIT_64(24) +/** Intercept INVLPG instruction. */ +#define SVM_CTRL_INTERCEPT_INVLPG RT_BIT_64(25) +/** Intercept INVLPGA instruction. */ +#define SVM_CTRL_INTERCEPT_INVLPGA RT_BIT_64(26) +/** IOIO_PROT Intercept IN/OUT accesses to selected ports. */ +#define SVM_CTRL_INTERCEPT_IOIO_PROT RT_BIT_64(27) +/** MSR_PROT Intercept RDMSR or WRMSR accesses to selected MSRs. */ +#define SVM_CTRL_INTERCEPT_MSR_PROT RT_BIT_64(28) +/** Intercept task switches. */ +#define SVM_CTRL_INTERCEPT_TASK_SWITCH RT_BIT_64(29) +/** FERR_FREEZE: intercept processor "freezing" during legacy FERR handling. */ +#define SVM_CTRL_INTERCEPT_FERR_FREEZE RT_BIT_64(30) +/** Intercept shutdown events. */ +#define SVM_CTRL_INTERCEPT_SHUTDOWN RT_BIT_64(31) +/** Intercept VMRUN instruction. */ +#define SVM_CTRL_INTERCEPT_VMRUN RT_BIT_64(32 + 0) +/** Intercept VMMCALL instruction. */ +#define SVM_CTRL_INTERCEPT_VMMCALL RT_BIT_64(32 + 1) +/** Intercept VMLOAD instruction. */ +#define SVM_CTRL_INTERCEPT_VMLOAD RT_BIT_64(32 + 2) +/** Intercept VMSAVE instruction. */ +#define SVM_CTRL_INTERCEPT_VMSAVE RT_BIT_64(32 + 3) +/** Intercept STGI instruction. */ +#define SVM_CTRL_INTERCEPT_STGI RT_BIT_64(32 + 4) +/** Intercept CLGI instruction. */ +#define SVM_CTRL_INTERCEPT_CLGI RT_BIT_64(32 + 5) +/** Intercept SKINIT instruction. */ +#define SVM_CTRL_INTERCEPT_SKINIT RT_BIT_64(32 + 6) +/** Intercept RDTSCP instruction. */ +#define SVM_CTRL_INTERCEPT_RDTSCP RT_BIT_64(32 + 7) +/** Intercept ICEBP instruction. */ +#define SVM_CTRL_INTERCEPT_ICEBP RT_BIT_64(32 + 8) +/** Intercept WBINVD instruction. */ +#define SVM_CTRL_INTERCEPT_WBINVD RT_BIT_64(32 + 9) +/** Intercept MONITOR instruction. */ +#define SVM_CTRL_INTERCEPT_MONITOR RT_BIT_64(32 + 10) +/** Intercept MWAIT instruction unconditionally. */ +#define SVM_CTRL_INTERCEPT_MWAIT RT_BIT_64(32 + 11) +/** Intercept MWAIT instruction when armed. */ +#define SVM_CTRL_INTERCEPT_MWAIT_ARMED RT_BIT_64(32 + 12) +/** Intercept XSETBV instruction. */ +#define SVM_CTRL_INTERCEPT_XSETBV RT_BIT_64(32 + 13) +/** Intercept RDPRU instruction. */ +#define SVM_CTRL_INTERCEPT_RDPRU RT_BIT_64(32 + 14) +/** Intercept EFER writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_EFER_WRITES_TRAP RT_BIT_64(32 + 15) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR0_WRITES_TRAP RT_BIT_64(32 + 16) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR1_WRITES_TRAP RT_BIT_64(32 + 17) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR2_WRITES_TRAP RT_BIT_64(32 + 18) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR3_WRITES_TRAP RT_BIT_64(32 + 19) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR4_WRITES_TRAP RT_BIT_64(32 + 20) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR5_WRITES_TRAP RT_BIT_64(32 + 21) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR6_WRITES_TRAP RT_BIT_64(32 + 22) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR7_WRITES_TRAP RT_BIT_64(32 + 23) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR8_WRITES_TRAP RT_BIT_64(32 + 24) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR9_WRITES_TRAP RT_BIT_64(32 + 25) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR10_WRITES_TRAP RT_BIT_64(32 + 26) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR11_WRITES_TRAP RT_BIT_64(32 + 27) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR12_WRITES_TRAP RT_BIT_64(32 + 28) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR13_WRITES_TRAP RT_BIT_64(32 + 29) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR14_WRITES_TRAP RT_BIT_64(32 + 30) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR15_WRITES_TRAP RT_BIT_64(32 + 31) +/** @} */ + +/** @name SVMINTCTRL.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 SVMVMCB.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/segment register type. + */ +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. */ +} SVMSELREG; +AssertCompileSize(SVMSELREG, 16); +/** Pointer to the SVMSELREG struct. */ +typedef SVMSELREG *PSVMSELREG; +/** Pointer to a const SVMSELREG struct. */ +typedef const SVMSELREG *PCSVMSELREG; + +/** + * SVM GDTR/IDTR type. + */ +typedef struct +{ + uint16_t u16Reserved0; + uint16_t u16Reserved1; + uint32_t u32Limit; /**< Only lower 16 bits are implemented. */ + uint64_t u64Base; +} SVMXDTR; +AssertCompileSize(SVMXDTR, 16); +typedef SVMXDTR SVMIDTR; +typedef SVMXDTR SVMGDTR; +/** Pointer to the SVMXDTR struct. */ +typedef SVMXDTR *PSVMXDTR; +/** Pointer to a const SVMXDTR struct. */ +typedef const SVMXDTR *PCSVMXDTR; + +/** + * SVM Event injection structure (EVENTINJ and EXITINTINFO). + */ +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 u; +} SVMEVENT; +/** Pointer to the SVMEVENT union. */ +typedef SVMEVENT *PSVMEVENT; +/** Pointer to a const SVMEVENT union. */ +typedef const SVMEVENT *PCSVMEVENT; + +/** Gets the event type given an SVMEVENT parameter. */ +#define SVM_EVENT_GET_TYPE(a_SvmEvent) (((a_SvmEvent) >> 8) & 7) + +/** + * SVM Interrupt control structure (Virtual Interrupt Control). + */ +typedef union +{ + struct + { + uint32_t u8VTPR : 8; /* V_TPR */ + uint32_t u1VIrqPending : 1; /* V_IRQ */ + uint32_t u1VGif : 1; /* VGIF */ + uint32_t u6Reserved : 6; + uint32_t u4VIntrPrio : 4; /* V_INTR_PRIO */ + uint32_t u1IgnoreTPR : 1; /* V_IGN_TPR */ + uint32_t u3Reserved : 3; + uint32_t u1VIntrMasking : 1; /* V_INTR_MASKING */ + uint32_t u1VGifEnable : 1; /* VGIF enable */ + uint32_t u5Reserved : 5; + uint32_t u1AvicEnable : 1; /* AVIC enable */ + uint32_t u8VIntrVector : 8; /* V_INTR_VECTOR */ + uint32_t u24Reserved : 24; + } n; + uint64_t u; +} SVMINTCTRL; +/** Pointer to an SVMINTCTRL structure. */ +typedef SVMINTCTRL *PSVMINTCTRL; +/** Pointer to a const SVMINTCTRL structure. */ +typedef const SVMINTCTRL *PCSVMINTCTRL; + +/** + * SVM TLB control structure. + */ +typedef union +{ + struct + { + uint32_t u32ASID : 32; + uint32_t u8TLBFlush : 8; + uint32_t u24Reserved : 24; + } n; + uint64_t u; +} SVMTLBCTRL; + +/** + * SVM IOIO exit info. structure (EXITINFO1 for IOIO intercepts). + */ +typedef union +{ + struct + { + uint32_t u1Type : 1; /**< Bit 0: 0 = out, 1 = in */ + uint32_t u1Reserved : 1; /**< Bit 1: Reserved */ + uint32_t u1Str : 1; /**< Bit 2: String I/O (1) or not (0). */ + uint32_t u1Rep : 1; /**< Bit 3: Repeat prefixed string I/O. */ + uint32_t u1Op8 : 1; /**< Bit 4: 8-bit operand. */ + uint32_t u1Op16 : 1; /**< Bit 5: 16-bit operand. */ + uint32_t u1Op32 : 1; /**< Bit 6: 32-bit operand. */ + uint32_t u1Addr16 : 1; /**< Bit 7: 16-bit address size. */ + uint32_t u1Addr32 : 1; /**< Bit 8: 32-bit address size. */ + uint32_t u1Addr64 : 1; /**< Bit 9: 64-bit address size. */ + uint32_t u3Seg : 3; /**< Bits 12:10: Effective segment number. Added w/ decode assist in APM v3.17. */ + uint32_t u3Reserved : 3; + uint32_t u16Port : 16; /**< Bits 31:16: Port number. */ + } n; + uint32_t u; +} SVMIOIOEXITINFO; +/** Pointer to an SVM IOIO exit info. structure. */ +typedef SVMIOIOEXITINFO *PSVMIOIOEXITINFO; +/** Pointer to a const SVM IOIO exit info. structure. */ +typedef const SVMIOIOEXITINFO *PCSVMIOIOEXITINFO; + +/** 8-bit IO transfer. */ +#define SVM_IOIO_8_BIT_OP RT_BIT_32(4) +/** 16-bit IO transfer. */ +#define SVM_IOIO_16_BIT_OP RT_BIT_32(5) +/** 32-bit IO transfer. */ +#define SVM_IOIO_32_BIT_OP RT_BIT_32(6) +/** Number of bits to shift right to get the operand sizes. */ +#define SVM_IOIO_OP_SIZE_SHIFT 4 +/** Mask of all possible IO transfer sizes. */ +#define SVM_IOIO_OP_SIZE_MASK (SVM_IOIO_8_BIT_OP | SVM_IOIO_16_BIT_OP | SVM_IOIO_32_BIT_OP) +/** 16-bit address for the IO buffer. */ +#define SVM_IOIO_16_BIT_ADDR RT_BIT_32(7) +/** 32-bit address for the IO buffer. */ +#define SVM_IOIO_32_BIT_ADDR RT_BIT_32(8) +/** 64-bit address for the IO buffer. */ +#define SVM_IOIO_64_BIT_ADDR RT_BIT_32(9) +/** Number of bits to shift right to get the address sizes. */ +#define SVM_IOIO_ADDR_SIZE_SHIFT 7 +/** Mask of all the IO address sizes. */ +#define SVM_IOIO_ADDR_SIZE_MASK (SVM_IOIO_16_BIT_ADDR | SVM_IOIO_32_BIT_ADDR | SVM_IOIO_64_BIT_ADDR) +/** Number of bits to shift right to get the IO port number. */ +#define SVM_IOIO_PORT_SHIFT 16 +/** IO write. */ +#define SVM_IOIO_WRITE 0 +/** IO read. */ +#define SVM_IOIO_READ 1 +/** + * SVM IOIO transfer type. + */ +typedef enum +{ + SVMIOIOTYPE_OUT = SVM_IOIO_WRITE, + SVMIOIOTYPE_IN = SVM_IOIO_READ +} SVMIOIOTYPE; + +/** + * SVM AVIC. + */ +typedef union +{ + struct + { + RT_GCC_EXTENSION uint64_t u12Reserved0 : 12; + RT_GCC_EXTENSION uint64_t u40Addr : 40; + RT_GCC_EXTENSION uint64_t u12Reserved1 : 12; + } n; + uint64_t u; +} SVMAVIC; +AssertCompileSize(SVMAVIC, 8); + +/** + * SVM AVIC PHYSICAL_TABLE pointer. + */ +typedef union +{ + struct + { + RT_GCC_EXTENSION uint64_t u8LastGuestCoreId : 8; + RT_GCC_EXTENSION uint64_t u4Reserved : 4; + RT_GCC_EXTENSION uint64_t u40Addr : 40; + RT_GCC_EXTENSION uint64_t u12Reserved : 12; + } n; + uint64_t u; +} SVMAVICPHYS; +AssertCompileSize(SVMAVICPHYS, 8); + +/** + * SVM Nested Paging struct. + */ +typedef union +{ + struct + { + uint32_t u1NestedPaging : 1; + uint32_t u1Sev : 1; + uint32_t u1SevEs : 1; + uint32_t u29Reserved : 29; + } n; + uint64_t u; +} SVMNP; +AssertCompileSize(SVMNP, 8); + +/** + * SVM Interrupt shadow struct. + */ +typedef union +{ + struct + { + uint32_t u1IntShadow : 1; + uint32_t u1GuestIntMask : 1; + uint32_t u30Reserved : 30; + } n; + uint64_t u; +} SVMINTSHADOW; +AssertCompileSize(SVMINTSHADOW, 8); + +/** + * SVM LBR virtualization struct. + */ +typedef union +{ + struct + { + uint32_t u1LbrVirt : 1; + uint32_t u1VirtVmsaveVmload : 1; + uint32_t u30Reserved : 30; + } n; + uint64_t u; +} SVMLBRVIRT; +AssertCompileSize(SVMLBRVIRT, 8); + +/** Maximum number of bytes in the Guest-instruction bytes field. */ +#define SVM_CTRL_GUEST_INSTR_BYTES_MAX 15 + +/** + * SVM VMCB control area. + */ +#pragma pack(1) +typedef struct +{ + /** Offset 0x00 - Intercept reads of CR0-CR15. */ + uint16_t u16InterceptRdCRx; + /** Offset 0x02 - Intercept writes to CR0-CR15. */ + uint16_t u16InterceptWrCRx; + /** Offset 0x04 - Intercept reads of DR0-DR15. */ + uint16_t u16InterceptRdDRx; + /** Offset 0x06 - Intercept writes to DR0-DR15. */ + uint16_t u16InterceptWrDRx; + /** Offset 0x08 - Intercept exception vectors 0-31. */ + uint32_t u32InterceptXcpt; + /** Offset 0x0c - Intercept control. */ + uint64_t u64InterceptCtrl; + /** Offset 0x14-0x3f - Reserved. */ + uint8_t u8Reserved0[0x3c - 0x14]; + /** Offset 0x3c - PAUSE filter threshold. */ + uint16_t u16PauseFilterThreshold; + /** 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. */ + SVMTLBCTRL TLBCtrl; + /** Offset 0x60 - Interrupt control field. */ + SVMINTCTRL IntCtrl; + /** Offset 0x68 - Interrupt shadow. */ + SVMINTSHADOW IntShadow; + /** 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. */ + SVMEVENT ExitIntInfo; + /** Offset 0x90 - Nested Paging control. */ + SVMNP NestedPagingCtrl; + /** Offset 0x98 - AVIC APIC BAR. */ + SVMAVIC AvicBar; + /** Offset 0xa0-0xa7 - Reserved. */ + uint8_t u8Reserved1[0xa8 - 0xa0]; + /** Offset 0xa8 - Event injection. */ + SVMEVENT EventInject; + /** Offset 0xb0 - Host CR3 for nested paging. */ + uint64_t u64NestedPagingCR3; + /** Offset 0xb8 - LBR Virtualization. */ + SVMLBRVIRT LbrVirt; + /** Offset 0xc0 - VMCB Clean Bits. */ + uint32_t u32VmcbCleanBits; + uint32_t u32Reserved0; + /** Offset 0xc8 - Next sequential instruction pointer. */ + uint64_t u64NextRIP; + /** Offset 0xd0 - Number of bytes fetched. */ + uint8_t cbInstrFetched; + /** Offset 0xd1 - Guest instruction bytes. */ + uint8_t abInstr[SVM_CTRL_GUEST_INSTR_BYTES_MAX]; + /** Offset 0xe0 - AVIC APIC_BACKING_PAGE pointer. */ + SVMAVIC AvicBackingPagePtr; + /** Offset 0xe8-0xef - Reserved. */ + uint8_t u8Reserved2[0xf0 - 0xe8]; + /** Offset 0xf0 - AVIC LOGICAL_TABLE pointer. */ + SVMAVIC AvicLogicalTablePtr; + /** Offset 0xf8 - AVIC PHYSICAL_TABLE pointer. */ + SVMAVICPHYS AvicPhysicalTablePtr; +} SVMVMCBCTRL; +#pragma pack() +/** Pointer to the SVMVMCBSTATESAVE structure. */ +typedef SVMVMCBCTRL *PSVMVMCBCTRL; +/** Pointer to a const SVMVMCBSTATESAVE structure. */ +typedef const SVMVMCBCTRL *PCSVMVMCBCTRL; +AssertCompileSize(SVMVMCBCTRL, 0x100); +AssertCompileMemberOffset(SVMVMCBCTRL, u16InterceptRdCRx, 0x00); +AssertCompileMemberOffset(SVMVMCBCTRL, u16InterceptWrCRx, 0x02); +AssertCompileMemberOffset(SVMVMCBCTRL, u16InterceptRdDRx, 0x04); +AssertCompileMemberOffset(SVMVMCBCTRL, u16InterceptWrDRx, 0x06); +AssertCompileMemberOffset(SVMVMCBCTRL, u32InterceptXcpt, 0x08); +AssertCompileMemberOffset(SVMVMCBCTRL, u64InterceptCtrl, 0x0c); +AssertCompileMemberOffset(SVMVMCBCTRL, u8Reserved0, 0x14); +AssertCompileMemberOffset(SVMVMCBCTRL, u16PauseFilterThreshold, 0x3c); +AssertCompileMemberOffset(SVMVMCBCTRL, u16PauseFilterCount, 0x3e); +AssertCompileMemberOffset(SVMVMCBCTRL, u64IOPMPhysAddr, 0x40); +AssertCompileMemberOffset(SVMVMCBCTRL, u64MSRPMPhysAddr, 0x48); +AssertCompileMemberOffset(SVMVMCBCTRL, u64TSCOffset, 0x50); +AssertCompileMemberOffset(SVMVMCBCTRL, TLBCtrl, 0x58); +AssertCompileMemberOffset(SVMVMCBCTRL, IntCtrl, 0x60); +AssertCompileMemberOffset(SVMVMCBCTRL, IntShadow, 0x68); +AssertCompileMemberOffset(SVMVMCBCTRL, u64ExitCode, 0x70); +AssertCompileMemberOffset(SVMVMCBCTRL, u64ExitInfo1, 0x78); +AssertCompileMemberOffset(SVMVMCBCTRL, u64ExitInfo2, 0x80); +AssertCompileMemberOffset(SVMVMCBCTRL, ExitIntInfo, 0x88); +AssertCompileMemberOffset(SVMVMCBCTRL, NestedPagingCtrl, 0x90); +AssertCompileMemberOffset(SVMVMCBCTRL, AvicBar, 0x98); +AssertCompileMemberOffset(SVMVMCBCTRL, u8Reserved1, 0xa0); +AssertCompileMemberOffset(SVMVMCBCTRL, EventInject, 0xa8); +AssertCompileMemberOffset(SVMVMCBCTRL, u64NestedPagingCR3, 0xb0); +AssertCompileMemberOffset(SVMVMCBCTRL, LbrVirt, 0xb8); +AssertCompileMemberOffset(SVMVMCBCTRL, u32VmcbCleanBits, 0xc0); +AssertCompileMemberOffset(SVMVMCBCTRL, u64NextRIP, 0xc8); +AssertCompileMemberOffset(SVMVMCBCTRL, cbInstrFetched, 0xd0); +AssertCompileMemberOffset(SVMVMCBCTRL, abInstr, 0xd1); +AssertCompileMemberOffset(SVMVMCBCTRL, AvicBackingPagePtr, 0xe0); +AssertCompileMemberOffset(SVMVMCBCTRL, u8Reserved2, 0xe8); +AssertCompileMemberOffset(SVMVMCBCTRL, AvicLogicalTablePtr, 0xf0); +AssertCompileMemberOffset(SVMVMCBCTRL, AvicPhysicalTablePtr, 0xf8); +AssertCompileMemberSize(SVMVMCBCTRL, abInstr, 0x0f); + +/** + * SVM VMCB state save area. + */ +#pragma pack(1) +typedef struct +{ + /** Offset 0x400 - Guest ES register + hidden parts. */ + SVMSELREG ES; + /** Offset 0x410 - Guest CS register + hidden parts. */ + SVMSELREG CS; + /** Offset 0x420 - Guest SS register + hidden parts. */ + SVMSELREG SS; + /** Offset 0x430 - Guest DS register + hidden parts. */ + SVMSELREG DS; + /** Offset 0x440 - Guest FS register + hidden parts. */ + SVMSELREG FS; + /** Offset 0x450 - Guest GS register + hidden parts. */ + SVMSELREG GS; + /** Offset 0x460 - Guest GDTR register. */ + SVMGDTR GDTR; + /** Offset 0x470 - Guest LDTR register + hidden parts. */ + SVMSELREG LDTR; + /** Offset 0x480 - Guest IDTR register. */ + SVMIDTR IDTR; + /** Offset 0x490 - Guest TR register + hidden parts. */ + SVMSELREG TR; + /** Offset 0x4A0-0x4CA - Reserved. */ + uint8_t u8Reserved0[0x4cb - 0x4a0]; + /** Offset 0x4CB - CPL. */ + uint8_t u8CPL; + /** Offset 0x4CC-0x4CF - Reserved. */ + uint8_t u8Reserved1[0x4d0 - 0x4cc]; + /** Offset 0x4D0 - EFER. */ + uint64_t u64EFER; + /** Offset 0x4D8-0x547 - Reserved. */ + uint8_t u8Reserved2[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 u8Reserved3[0x5d8 - 0x580]; + /** Offset 0x5D8 - RSP. */ + uint64_t u64RSP; + /** Offset 0x5E0-0x5F7 - Reserved. */ + uint8_t u8Reserved4[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 u8Reserved5[0x668 - 0x648]; + /** Offset 0x668 - PAT (Page Attribute Table) MSR. */ + uint64_t u64PAT; + /** 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; +} SVMVMCBSTATESAVE; +#pragma pack() +/** Pointer to the SVMVMCBSTATESAVE structure. */ +typedef SVMVMCBSTATESAVE *PSVMVMCBSTATESAVE; +/** Pointer to a const SVMVMCBSTATESAVE structure. */ +typedef const SVMVMCBSTATESAVE *PCSVMVMCBSTATESAVE; +AssertCompileSize(SVMVMCBSTATESAVE, 0x298); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, ES, 0x400 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, CS, 0x410 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, SS, 0x420 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, DS, 0x430 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, FS, 0x440 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, GS, 0x450 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, GDTR, 0x460 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, LDTR, 0x470 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, IDTR, 0x480 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, TR, 0x490 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u8Reserved0, 0x4a0 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u8CPL, 0x4cb - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u8Reserved1, 0x4cc - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64EFER, 0x4d0 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u8Reserved2, 0x4d8 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64CR4, 0x548 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64CR3, 0x550 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64CR0, 0x558 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64DR7, 0x560 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64DR6, 0x568 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64RFlags, 0x570 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64RIP, 0x578 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u8Reserved3, 0x580 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64RSP, 0x5d8 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u8Reserved4, 0x5e0 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64RAX, 0x5f8 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64STAR, 0x600 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64LSTAR, 0x608 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64CSTAR, 0x610 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64SFMASK, 0x618 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64KernelGSBase, 0x620 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64SysEnterCS, 0x628 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64SysEnterESP, 0x630 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64SysEnterEIP, 0x638 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64CR2, 0x640 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u8Reserved5, 0x648 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64PAT, 0x668 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64DBGCTL, 0x670 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64BR_FROM, 0x678 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64BR_TO, 0x680 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64LASTEXCPFROM, 0x688 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64LASTEXCPTO, 0x690 - 0x400); + +/** + * SVM VM Control Block. (VMCB) + */ +#pragma pack(1) +typedef struct SVMVMCB +{ + /** Offset 0x00 - Control area. */ + SVMVMCBCTRL ctrl; + /** Offset 0x100-0x3FF - Reserved. */ + uint8_t u8Reserved0[0x400 - 0x100]; + /** Offset 0x400 - State save area. */ + SVMVMCBSTATESAVE guest; + /** Offset 0x698-0xFFF- Reserved. */ + uint8_t u8Reserved1[0x1000 - 0x698]; +} SVMVMCB; +#pragma pack() +/** Pointer to the SVMVMCB structure. */ +typedef SVMVMCB *PSVMVMCB; +/** Pointer to a const SVMVMCB structure. */ +typedef const SVMVMCB *PCSVMVMCB; +AssertCompileMemberOffset(SVMVMCB, ctrl, 0x00); +AssertCompileMemberOffset(SVMVMCB, u8Reserved0, 0x100); +AssertCompileMemberOffset(SVMVMCB, guest, 0x400); +AssertCompileMemberOffset(SVMVMCB, u8Reserved1, 0x698); +AssertCompileSize(SVMVMCB, 0x1000); + +/** + * SVM MSRs. + */ +typedef struct SVMMSRS +{ + /** HWCR MSR. */ + uint64_t u64MsrHwcr; + /** Reserved for future. */ + uint64_t u64Padding[27]; +} SVMMSRS; +AssertCompileSizeAlignment(SVMMSRS, 8); +AssertCompileSize(SVMMSRS, 224); +/** Pointer to a SVMMSRS struct. */ +typedef SVMMSRS *PSVMMSRS; +/** Pointer to a const SVMMSRS struct. */ +typedef const SVMMSRS *PCSVMMSRS; + +/** + * SVM VM-exit auxiliary information. + * + * This includes information that isn't necessarily stored in the guest-CPU + * context but provided as part of \#VMEXITs. + */ +typedef struct +{ + uint64_t u64ExitCode; + uint64_t u64ExitInfo1; + uint64_t u64ExitInfo2; + SVMEVENT ExitIntInfo; +} SVMEXITAUX; +/** Pointer to a SVMEXITAUX struct. */ +typedef SVMEXITAUX *PSVMEXITAUX; +/** Pointer to a const SVMEXITAUX struct. */ +typedef const SVMEXITAUX *PCSVMEXITAUX; + +/** + * Segment attribute conversion between CPU and AMD-V VMCB format. + * + * The CPU format of the segment attribute is described in X86DESCATTRBITS + * which is 16-bits (i.e. includes 4 bits of the segment limit). + * + * The AMD-V VMCB format the segment attribute is compact 12-bits (strictly + * only the attribute bits and nothing else). Upper 4-bits are unused. + */ +#define HMSVM_CPU_2_VMCB_SEG_ATTR(a) ( ((a) & 0xff) | (((a) & 0xf000) >> 4) ) +#define HMSVM_VMCB_2_CPU_SEG_ATTR(a) ( ((a) & 0xff) | (((a) & 0x0f00) << 4) ) + +/** @def HMSVM_SEG_REG_COPY_TO_VMCB + * Copies the specified segment register to a VMCB from a virtual CPU context. + * + * @param a_pCtx The virtual-CPU context. + * @param a_pVmcbStateSave Pointer to the VMCB state-save area. + * @param a_REG The segment register in the VMCB state-save + * struct (ES/CS/SS/DS). + * @param a_reg The segment register in the virtual CPU struct + * (es/cs/ss/ds). + */ +#define HMSVM_SEG_REG_COPY_TO_VMCB(a_pCtx, a_pVmcbStateSave, a_REG, a_reg) \ + do \ + { \ + Assert((a_pCtx)->a_reg.fFlags & CPUMSELREG_FLAGS_VALID); \ + Assert((a_pCtx)->a_reg.ValidSel == (a_pCtx)->a_reg.Sel); \ + (a_pVmcbStateSave)->a_REG.u16Sel = (a_pCtx)->a_reg.Sel; \ + (a_pVmcbStateSave)->a_REG.u32Limit = (a_pCtx)->a_reg.u32Limit; \ + (a_pVmcbStateSave)->a_REG.u64Base = (a_pCtx)->a_reg.u64Base; \ + (a_pVmcbStateSave)->a_REG.u16Attr = HMSVM_CPU_2_VMCB_SEG_ATTR((a_pCtx)->a_reg.Attr.u); \ + } while (0) + +/** @def HMSVM_SEG_REG_COPY_FROM_VMCB + * Copies the specified segment register from the VMCB to a virtual CPU + * context. + * + * @param a_pCtx The virtual-CPU context. + * @param a_pVmcbStateSave Pointer to the VMCB state-save area. + * @param a_REG The segment register in the VMCB state-save + * struct (ES/CS/SS/DS). + * @param a_reg The segment register in the virtual CPU struct + * (es/ds/ss/ds). + */ +#define HMSVM_SEG_REG_COPY_FROM_VMCB(a_pCtx, a_pVmcbStateSave, a_REG, a_reg) \ + do \ + { \ + (a_pCtx)->a_reg.Sel = (a_pVmcbStateSave)->a_REG.u16Sel; \ + (a_pCtx)->a_reg.ValidSel = (a_pVmcbStateSave)->a_REG.u16Sel; \ + (a_pCtx)->a_reg.fFlags = CPUMSELREG_FLAGS_VALID; \ + (a_pCtx)->a_reg.u32Limit = (a_pVmcbStateSave)->a_REG.u32Limit; \ + (a_pCtx)->a_reg.u64Base = (a_pVmcbStateSave)->a_REG.u64Base; \ + (a_pCtx)->a_reg.Attr.u = HMSVM_VMCB_2_CPU_SEG_ATTR((a_pVmcbStateSave)->a_REG.u16Attr); \ + } while (0) + + +/** @defgroup grp_hm_svm_hwexec SVM Hardware-assisted execution Helpers + * + * These functions are only here because the inline functions in cpum.h calls them. + * Don't add any more functions here unless there is no other option. + * @{ + */ +VMM_INT_DECL(bool) HMGetGuestSvmCtrlIntercepts(PCVMCPU pVCpu, uint64_t *pu64Intercepts); +VMM_INT_DECL(bool) HMGetGuestSvmReadCRxIntercepts(PCVMCPU pVCpu, uint16_t *pu16Intercepts); +VMM_INT_DECL(bool) HMGetGuestSvmWriteCRxIntercepts(PCVMCPU pVCpu, uint16_t *pu16Intercepts); +VMM_INT_DECL(bool) HMGetGuestSvmReadDRxIntercepts(PCVMCPU pVCpu, uint16_t *pu16Intercepts); +VMM_INT_DECL(bool) HMGetGuestSvmWriteDRxIntercepts(PCVMCPU pVCpu, uint16_t *pu16Intercepts); +VMM_INT_DECL(bool) HMGetGuestSvmXcptIntercepts(PCVMCPU pVCpu, uint32_t *pu32Intercepts); +VMM_INT_DECL(bool) HMGetGuestSvmVirtIntrMasking(PCVMCPU pVCpu, bool *pfVIntrMasking); +VMM_INT_DECL(bool) HMGetGuestSvmNestedPaging(PCVMCPU pVCpu, bool *pfNestedPagingCtrl); +VMM_INT_DECL(bool) HMGetGuestSvmPauseFilterCount(PCVMCPU pVCpu, uint16_t *pu16PauseFilterCount); +VMM_INT_DECL(bool) HMGetGuestSvmTscOffset(PCVMCPU pVCpu, uint64_t *pu64TscOffset); +/** @} */ + + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_hm_svm_h */ + diff --git a/include/VBox/vmm/hm_vmx.h b/include/VBox/vmm/hm_vmx.h new file mode 100644 index 00000000..95794dca --- /dev/null +++ b/include/VBox/vmm/hm_vmx.h @@ -0,0 +1,4644 @@ +/** @file + * HM - VMX Structures and Definitions. (VMM) + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_hm_vmx_h +#define VBOX_INCLUDED_vmm_hm_vmx_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <iprt/x86.h> +#include <iprt/assertcompile.h> + + +/** @defgroup grp_hm_vmx VMX Types and Definitions + * @ingroup grp_hm + * @{ + */ + +/** @name Host-state MSR lazy-restoration flags. + * @{ + */ +/** The host MSRs have been saved. */ +#define VMX_LAZY_MSRS_SAVED_HOST RT_BIT(0) +/** The guest MSRs are loaded and in effect. */ +#define VMX_LAZY_MSRS_LOADED_GUEST RT_BIT(1) +/** @} */ + +/** @name VMX HM-error codes for VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO. + * UFC = Unsupported Feature Combination. + * @{ + */ +/** Unsupported pin-based VM-execution controls combo. */ +#define VMX_UFC_CTRL_PIN_EXEC 1 +/** Unsupported processor-based VM-execution controls combo. */ +#define VMX_UFC_CTRL_PROC_EXEC 2 +/** Unsupported move debug register VM-exit combo. */ +#define VMX_UFC_CTRL_PROC_MOV_DRX_EXIT 3 +/** Unsupported VM-entry controls combo. */ +#define VMX_UFC_CTRL_ENTRY 4 +/** Unsupported VM-exit controls combo. */ +#define VMX_UFC_CTRL_EXIT 5 +/** MSR storage capacity of the VMCS autoload/store area is not sufficient + * for storing host MSRs. */ +#define VMX_UFC_INSUFFICIENT_HOST_MSR_STORAGE 6 +/** MSR storage capacity of the VMCS autoload/store area is not sufficient + * for storing guest MSRs. */ +#define VMX_UFC_INSUFFICIENT_GUEST_MSR_STORAGE 7 +/** Invalid VMCS size. */ +#define VMX_UFC_INVALID_VMCS_SIZE 8 +/** Unsupported secondary processor-based VM-execution controls combo. */ +#define VMX_UFC_CTRL_PROC_EXEC2 9 +/** Invalid unrestricted-guest execution controls combo. */ +#define VMX_UFC_INVALID_UX_COMBO 10 +/** EPT flush type not supported. */ +#define VMX_UFC_EPT_FLUSH_TYPE_UNSUPPORTED 11 +/** EPT paging structure memory type is not write-back. */ +#define VMX_UFC_EPT_MEM_TYPE_NOT_WB 12 +/** EPT requires INVEPT instr. support but it's not available. */ +#define VMX_UFC_EPT_INVEPT_UNAVAILABLE 13 +/** EPT requires page-walk length of 4. */ +#define VMX_UFC_EPT_PAGE_WALK_LENGTH_UNSUPPORTED 14 +/** VMX VMWRITE all feature exposed to the guest but not supported on host. */ +#define VMX_UFC_GST_HOST_VMWRITE_ALL 15 +/** LBR stack size cannot be determined for the current CPU. */ +#define VMX_UFC_LBR_STACK_SIZE_UNKNOWN 16 +/** LBR stack size of the CPU exceeds our buffer size. */ +#define VMX_UFC_LBR_STACK_SIZE_OVERFLOW 17 +/** @} */ + +/** @name VMX HM-error codes for VERR_VMX_VMCS_FIELD_CACHE_INVALID. + * VCI = VMCS-field Cache Invalid. + * @{ + */ +/** Cache of VM-entry controls invalid. */ +#define VMX_VCI_CTRL_ENTRY 300 +/** Cache of VM-exit controls invalid. */ +#define VMX_VCI_CTRL_EXIT 301 +/** Cache of pin-based VM-execution controls invalid. */ +#define VMX_VCI_CTRL_PIN_EXEC 302 +/** Cache of processor-based VM-execution controls invalid. */ +#define VMX_VCI_CTRL_PROC_EXEC 303 +/** Cache of secondary processor-based VM-execution controls invalid. */ +#define VMX_VCI_CTRL_PROC_EXEC2 304 +/** Cache of exception bitmap invalid. */ +#define VMX_VCI_CTRL_XCPT_BITMAP 305 +/** Cache of TSC offset invalid. */ +#define VMX_VCI_CTRL_TSC_OFFSET 306 +/** Cache of tertiary processor-based VM-execution controls invalid. */ +#define VMX_VCI_CTRL_PROC_EXEC3 307 +/** @} */ + +/** @name VMX HM-error codes for VERR_VMX_INVALID_GUEST_STATE. + * IGS = Invalid Guest State. + * @{ + */ +/** An error occurred while checking invalid-guest-state. */ +#define VMX_IGS_ERROR 500 +/** The invalid guest-state checks did not find any reason why. */ +#define VMX_IGS_REASON_NOT_FOUND 501 +/** CR0 fixed1 bits invalid. */ +#define VMX_IGS_CR0_FIXED1 502 +/** CR0 fixed0 bits invalid. */ +#define VMX_IGS_CR0_FIXED0 503 +/** CR0.PE and CR0.PE invalid VT-x/host combination. */ +#define VMX_IGS_CR0_PG_PE_COMBO 504 +/** CR4 fixed1 bits invalid. */ +#define VMX_IGS_CR4_FIXED1 505 +/** CR4 fixed0 bits invalid. */ +#define VMX_IGS_CR4_FIXED0 506 +/** Reserved bits in VMCS' DEBUGCTL MSR field not set to 0 when + * VMX_VMCS_CTRL_ENTRY_LOAD_DEBUG is used. */ +#define VMX_IGS_DEBUGCTL_MSR_RESERVED 507 +/** CR0.PG not set for long-mode when not using unrestricted guest. */ +#define VMX_IGS_CR0_PG_LONGMODE 508 +/** CR4.PAE not set for long-mode guest when not using unrestricted guest. */ +#define VMX_IGS_CR4_PAE_LONGMODE 509 +/** CR4.PCIDE set for 32-bit guest. */ +#define VMX_IGS_CR4_PCIDE 510 +/** VMCS' DR7 reserved bits not set to 0. */ +#define VMX_IGS_DR7_RESERVED 511 +/** VMCS' PERF_GLOBAL MSR reserved bits not set to 0. */ +#define VMX_IGS_PERF_GLOBAL_MSR_RESERVED 512 +/** VMCS' EFER MSR reserved bits not set to 0. */ +#define VMX_IGS_EFER_MSR_RESERVED 513 +/** VMCS' EFER MSR.LMA does not match the IA32e mode guest control. */ +#define VMX_IGS_EFER_LMA_GUEST_MODE_MISMATCH 514 +/** VMCS' EFER MSR.LMA does not match EFER.LME of the guest when using paging + * without unrestricted guest. */ +#define VMX_IGS_EFER_LMA_LME_MISMATCH 515 +/** CS.Attr.P bit invalid. */ +#define VMX_IGS_CS_ATTR_P_INVALID 516 +/** CS.Attr reserved bits not set to 0. */ +#define VMX_IGS_CS_ATTR_RESERVED 517 +/** CS.Attr.G bit invalid. */ +#define VMX_IGS_CS_ATTR_G_INVALID 518 +/** CS is unusable. */ +#define VMX_IGS_CS_ATTR_UNUSABLE 519 +/** CS and SS DPL unequal. */ +#define VMX_IGS_CS_SS_ATTR_DPL_UNEQUAL 520 +/** CS and SS DPL mismatch. */ +#define VMX_IGS_CS_SS_ATTR_DPL_MISMATCH 521 +/** CS Attr.Type invalid. */ +#define VMX_IGS_CS_ATTR_TYPE_INVALID 522 +/** CS and SS RPL unequal. */ +#define VMX_IGS_SS_CS_RPL_UNEQUAL 523 +/** SS.Attr.DPL and SS RPL unequal. */ +#define VMX_IGS_SS_ATTR_DPL_RPL_UNEQUAL 524 +/** SS.Attr.DPL invalid for segment type. */ +#define VMX_IGS_SS_ATTR_DPL_INVALID 525 +/** SS.Attr.Type invalid. */ +#define VMX_IGS_SS_ATTR_TYPE_INVALID 526 +/** SS.Attr.P bit invalid. */ +#define VMX_IGS_SS_ATTR_P_INVALID 527 +/** SS.Attr reserved bits not set to 0. */ +#define VMX_IGS_SS_ATTR_RESERVED 528 +/** SS.Attr.G bit invalid. */ +#define VMX_IGS_SS_ATTR_G_INVALID 529 +/** DS.Attr.A bit invalid. */ +#define VMX_IGS_DS_ATTR_A_INVALID 530 +/** DS.Attr.P bit invalid. */ +#define VMX_IGS_DS_ATTR_P_INVALID 531 +/** DS.Attr.DPL and DS RPL unequal. */ +#define VMX_IGS_DS_ATTR_DPL_RPL_UNEQUAL 532 +/** DS.Attr reserved bits not set to 0. */ +#define VMX_IGS_DS_ATTR_RESERVED 533 +/** DS.Attr.G bit invalid. */ +#define VMX_IGS_DS_ATTR_G_INVALID 534 +/** DS.Attr.Type invalid. */ +#define VMX_IGS_DS_ATTR_TYPE_INVALID 535 +/** ES.Attr.A bit invalid. */ +#define VMX_IGS_ES_ATTR_A_INVALID 536 +/** ES.Attr.P bit invalid. */ +#define VMX_IGS_ES_ATTR_P_INVALID 537 +/** ES.Attr.DPL and DS RPL unequal. */ +#define VMX_IGS_ES_ATTR_DPL_RPL_UNEQUAL 538 +/** ES.Attr reserved bits not set to 0. */ +#define VMX_IGS_ES_ATTR_RESERVED 539 +/** ES.Attr.G bit invalid. */ +#define VMX_IGS_ES_ATTR_G_INVALID 540 +/** ES.Attr.Type invalid. */ +#define VMX_IGS_ES_ATTR_TYPE_INVALID 541 +/** FS.Attr.A bit invalid. */ +#define VMX_IGS_FS_ATTR_A_INVALID 542 +/** FS.Attr.P bit invalid. */ +#define VMX_IGS_FS_ATTR_P_INVALID 543 +/** FS.Attr.DPL and DS RPL unequal. */ +#define VMX_IGS_FS_ATTR_DPL_RPL_UNEQUAL 544 +/** FS.Attr reserved bits not set to 0. */ +#define VMX_IGS_FS_ATTR_RESERVED 545 +/** FS.Attr.G bit invalid. */ +#define VMX_IGS_FS_ATTR_G_INVALID 546 +/** FS.Attr.Type invalid. */ +#define VMX_IGS_FS_ATTR_TYPE_INVALID 547 +/** GS.Attr.A bit invalid. */ +#define VMX_IGS_GS_ATTR_A_INVALID 548 +/** GS.Attr.P bit invalid. */ +#define VMX_IGS_GS_ATTR_P_INVALID 549 +/** GS.Attr.DPL and DS RPL unequal. */ +#define VMX_IGS_GS_ATTR_DPL_RPL_UNEQUAL 550 +/** GS.Attr reserved bits not set to 0. */ +#define VMX_IGS_GS_ATTR_RESERVED 551 +/** GS.Attr.G bit invalid. */ +#define VMX_IGS_GS_ATTR_G_INVALID 552 +/** GS.Attr.Type invalid. */ +#define VMX_IGS_GS_ATTR_TYPE_INVALID 553 +/** V86 mode CS.Base invalid. */ +#define VMX_IGS_V86_CS_BASE_INVALID 554 +/** V86 mode CS.Limit invalid. */ +#define VMX_IGS_V86_CS_LIMIT_INVALID 555 +/** V86 mode CS.Attr invalid. */ +#define VMX_IGS_V86_CS_ATTR_INVALID 556 +/** V86 mode SS.Base invalid. */ +#define VMX_IGS_V86_SS_BASE_INVALID 557 +/** V86 mode SS.Limit invalid. */ +#define VMX_IGS_V86_SS_LIMIT_INVALID 558 +/** V86 mode SS.Attr invalid. */ +#define VMX_IGS_V86_SS_ATTR_INVALID 559 +/** V86 mode DS.Base invalid. */ +#define VMX_IGS_V86_DS_BASE_INVALID 560 +/** V86 mode DS.Limit invalid. */ +#define VMX_IGS_V86_DS_LIMIT_INVALID 561 +/** V86 mode DS.Attr invalid. */ +#define VMX_IGS_V86_DS_ATTR_INVALID 562 +/** V86 mode ES.Base invalid. */ +#define VMX_IGS_V86_ES_BASE_INVALID 563 +/** V86 mode ES.Limit invalid. */ +#define VMX_IGS_V86_ES_LIMIT_INVALID 564 +/** V86 mode ES.Attr invalid. */ +#define VMX_IGS_V86_ES_ATTR_INVALID 565 +/** V86 mode FS.Base invalid. */ +#define VMX_IGS_V86_FS_BASE_INVALID 566 +/** V86 mode FS.Limit invalid. */ +#define VMX_IGS_V86_FS_LIMIT_INVALID 567 +/** V86 mode FS.Attr invalid. */ +#define VMX_IGS_V86_FS_ATTR_INVALID 568 +/** V86 mode GS.Base invalid. */ +#define VMX_IGS_V86_GS_BASE_INVALID 569 +/** V86 mode GS.Limit invalid. */ +#define VMX_IGS_V86_GS_LIMIT_INVALID 570 +/** V86 mode GS.Attr invalid. */ +#define VMX_IGS_V86_GS_ATTR_INVALID 571 +/** Longmode CS.Base invalid. */ +#define VMX_IGS_LONGMODE_CS_BASE_INVALID 572 +/** Longmode SS.Base invalid. */ +#define VMX_IGS_LONGMODE_SS_BASE_INVALID 573 +/** Longmode DS.Base invalid. */ +#define VMX_IGS_LONGMODE_DS_BASE_INVALID 574 +/** Longmode ES.Base invalid. */ +#define VMX_IGS_LONGMODE_ES_BASE_INVALID 575 +/** SYSENTER ESP is not canonical. */ +#define VMX_IGS_SYSENTER_ESP_NOT_CANONICAL 576 +/** SYSENTER EIP is not canonical. */ +#define VMX_IGS_SYSENTER_EIP_NOT_CANONICAL 577 +/** PAT MSR invalid. */ +#define VMX_IGS_PAT_MSR_INVALID 578 +/** PAT MSR reserved bits not set to 0. */ +#define VMX_IGS_PAT_MSR_RESERVED 579 +/** GDTR.Base is not canonical. */ +#define VMX_IGS_GDTR_BASE_NOT_CANONICAL 580 +/** IDTR.Base is not canonical. */ +#define VMX_IGS_IDTR_BASE_NOT_CANONICAL 581 +/** GDTR.Limit invalid. */ +#define VMX_IGS_GDTR_LIMIT_INVALID 582 +/** IDTR.Limit invalid. */ +#define VMX_IGS_IDTR_LIMIT_INVALID 583 +/** Longmode RIP is invalid. */ +#define VMX_IGS_LONGMODE_RIP_INVALID 584 +/** RFLAGS reserved bits not set to 0. */ +#define VMX_IGS_RFLAGS_RESERVED 585 +/** RFLAGS RA1 reserved bits not set to 1. */ +#define VMX_IGS_RFLAGS_RESERVED1 586 +/** RFLAGS.VM (V86 mode) invalid. */ +#define VMX_IGS_RFLAGS_VM_INVALID 587 +/** RFLAGS.IF invalid. */ +#define VMX_IGS_RFLAGS_IF_INVALID 588 +/** Activity state invalid. */ +#define VMX_IGS_ACTIVITY_STATE_INVALID 589 +/** Activity state HLT invalid when SS.Attr.DPL is not zero. */ +#define VMX_IGS_ACTIVITY_STATE_HLT_INVALID 590 +/** Activity state ACTIVE invalid when block-by-STI or MOV SS. */ +#define VMX_IGS_ACTIVITY_STATE_ACTIVE_INVALID 591 +/** Activity state SIPI WAIT invalid. */ +#define VMX_IGS_ACTIVITY_STATE_SIPI_WAIT_INVALID 592 +/** Interruptibility state reserved bits not set to 0. */ +#define VMX_IGS_INTERRUPTIBILITY_STATE_RESERVED 593 +/** Interruptibility state cannot be block-by-STI -and- MOV SS. */ +#define VMX_IGS_INTERRUPTIBILITY_STATE_STI_MOVSS_INVALID 594 +/** Interruptibility state block-by-STI invalid for EFLAGS. */ +#define VMX_IGS_INTERRUPTIBILITY_STATE_STI_EFL_INVALID 595 +/** Interruptibility state invalid while trying to deliver external + * interrupt. */ +#define VMX_IGS_INTERRUPTIBILITY_STATE_EXT_INT_INVALID 596 +/** Interruptibility state block-by-MOVSS invalid while trying to deliver an + * NMI. */ +#define VMX_IGS_INTERRUPTIBILITY_STATE_MOVSS_INVALID 597 +/** Interruptibility state block-by-SMI invalid when CPU is not in SMM. */ +#define VMX_IGS_INTERRUPTIBILITY_STATE_SMI_INVALID 598 +/** Interruptibility state block-by-SMI invalid when trying to enter SMM. */ +#define VMX_IGS_INTERRUPTIBILITY_STATE_SMI_SMM_INVALID 599 +/** Interruptibility state block-by-STI (maybe) invalid when trying to + * deliver an NMI. */ +#define VMX_IGS_INTERRUPTIBILITY_STATE_STI_INVALID 600 +/** Interruptibility state block-by-NMI invalid when virtual-NMIs control is + * active. */ +#define VMX_IGS_INTERRUPTIBILITY_STATE_NMI_INVALID 601 +/** Pending debug exceptions reserved bits not set to 0. */ +#define VMX_IGS_PENDING_DEBUG_RESERVED 602 +/** Longmode pending debug exceptions reserved bits not set to 0. */ +#define VMX_IGS_LONGMODE_PENDING_DEBUG_RESERVED 603 +/** Pending debug exceptions.BS bit is not set when it should be. */ +#define VMX_IGS_PENDING_DEBUG_XCPT_BS_NOT_SET 604 +/** Pending debug exceptions.BS bit is not clear when it should be. */ +#define VMX_IGS_PENDING_DEBUG_XCPT_BS_NOT_CLEAR 605 +/** VMCS link pointer reserved bits not set to 0. */ +#define VMX_IGS_VMCS_LINK_PTR_RESERVED 606 +/** TR cannot index into LDT, TI bit MBZ. */ +#define VMX_IGS_TR_TI_INVALID 607 +/** LDTR cannot index into LDT. TI bit MBZ. */ +#define VMX_IGS_LDTR_TI_INVALID 608 +/** TR.Base is not canonical. */ +#define VMX_IGS_TR_BASE_NOT_CANONICAL 609 +/** FS.Base is not canonical. */ +#define VMX_IGS_FS_BASE_NOT_CANONICAL 610 +/** GS.Base is not canonical. */ +#define VMX_IGS_GS_BASE_NOT_CANONICAL 611 +/** LDTR.Base is not canonical. */ +#define VMX_IGS_LDTR_BASE_NOT_CANONICAL 612 +/** TR is unusable. */ +#define VMX_IGS_TR_ATTR_UNUSABLE 613 +/** TR.Attr.S bit invalid. */ +#define VMX_IGS_TR_ATTR_S_INVALID 614 +/** TR is not present. */ +#define VMX_IGS_TR_ATTR_P_INVALID 615 +/** TR.Attr reserved bits not set to 0. */ +#define VMX_IGS_TR_ATTR_RESERVED 616 +/** TR.Attr.G bit invalid. */ +#define VMX_IGS_TR_ATTR_G_INVALID 617 +/** Longmode TR.Attr.Type invalid. */ +#define VMX_IGS_LONGMODE_TR_ATTR_TYPE_INVALID 618 +/** TR.Attr.Type invalid. */ +#define VMX_IGS_TR_ATTR_TYPE_INVALID 619 +/** CS.Attr.S invalid. */ +#define VMX_IGS_CS_ATTR_S_INVALID 620 +/** CS.Attr.DPL invalid. */ +#define VMX_IGS_CS_ATTR_DPL_INVALID 621 +/** PAE PDPTE reserved bits not set to 0. */ +#define VMX_IGS_PAE_PDPTE_RESERVED 623 +/** VMCS link pointer does not point to a shadow VMCS. */ +#define VMX_IGS_VMCS_LINK_PTR_NOT_SHADOW 624 +/** VMCS link pointer to a shadow VMCS with invalid VMCS revision identifer. */ +#define VMX_IGS_VMCS_LINK_PTR_SHADOW_VMCS_ID_INVALID 625 +/** @} */ + +/** @name VMX VMCS-Read cache indices. + * @{ + */ +#define VMX_VMCS_GUEST_ES_BASE_CACHE_IDX 0 +#define VMX_VMCS_GUEST_CS_BASE_CACHE_IDX 1 +#define VMX_VMCS_GUEST_SS_BASE_CACHE_IDX 2 +#define VMX_VMCS_GUEST_DS_BASE_CACHE_IDX 3 +#define VMX_VMCS_GUEST_FS_BASE_CACHE_IDX 4 +#define VMX_VMCS_GUEST_GS_BASE_CACHE_IDX 5 +#define VMX_VMCS_GUEST_LDTR_BASE_CACHE_IDX 6 +#define VMX_VMCS_GUEST_TR_BASE_CACHE_IDX 7 +#define VMX_VMCS_GUEST_GDTR_BASE_CACHE_IDX 8 +#define VMX_VMCS_GUEST_IDTR_BASE_CACHE_IDX 9 +#define VMX_VMCS_GUEST_RSP_CACHE_IDX 10 +#define VMX_VMCS_GUEST_RIP_CACHE_IDX 11 +#define VMX_VMCS_GUEST_SYSENTER_ESP_CACHE_IDX 12 +#define VMX_VMCS_GUEST_SYSENTER_EIP_CACHE_IDX 13 +#define VMX_VMCS_RO_EXIT_QUALIFICATION_CACHE_IDX 14 +#define VMX_VMCS_RO_GUEST_LINEAR_ADDR_CACHE_IDX 15 +#define VMX_VMCS_MAX_CACHE_IDX (VMX_VMCS_RO_GUEST_LINEAR_ADDR_CACHE_IDX + 1) +#define VMX_VMCS_GUEST_CR3_CACHE_IDX 16 +#define VMX_VMCS_MAX_NESTED_PAGING_CACHE_IDX (VMX_VMCS_GUEST_CR3_CACHE_IDX + 1) +/** @} */ + + +/** @name VMX Extended Page Tables (EPT) Common Bits. + * @{ */ +/** Bit 0 - Readable (we often think of it as present). */ +#define EPT_E_BIT_READ 0 +#define EPT_E_READ RT_BIT_64(EPT_E_BIT_READ) /**< @see EPT_E_BIT_READ */ +/** Bit 1 - Writable. */ +#define EPT_E_BIT_WRITE 1 +#define EPT_E_WRITE RT_BIT_64(EPT_E_BIT_WRITE) /**< @see EPT_E_BIT_WRITE */ +/** Bit 2 - Executable. + * @note This controls supervisor instruction fetching if mode-based + * execution control is enabled. */ +#define EPT_E_BIT_EXECUTE 2 +#define EPT_E_EXECUTE RT_BIT_64(EPT_E_BIT_EXECUTE) /**< @see EPT_E_BIT_EXECUTE */ +/** Bits 3-5 - Memory type mask (leaf only, MBZ). + * The memory type is only applicable for leaf entries and MBZ for + * non-leaf (causes miconfiguration exit). */ +#define EPT_E_MEMTYPE_MASK UINT64_C(0x0038) +/** Bits 3-5 - Memory type shifted mask. */ +#define EPT_E_MEMTYPE_SMASK UINT64_C(0x0007) +/** Bits 3-5 - Memory type shift count. */ +#define EPT_E_MEMTYPE_SHIFT 3 +/** Bits 3-5 - Memory type: UC (Uncacheable). */ +#define EPT_E_MEMTYPE_UC (UINT64_C(0) << EPT_E_MEMTYPE_SHIFT) +/** Bits 3-5 - Memory type: WC (Write Combining). */ +#define EPT_E_MEMTYPE_WC (UINT64_C(1) << EPT_E_MEMTYPE_SHIFT) +/** Bits 3-5 - Memory type: Invalid (2). */ +#define EPT_E_MEMTYPE_INVALID_2 (UINT64_C(2) << EPT_E_MEMTYPE_SHIFT) +/** Bits 3-5 - Memory type: Invalid (3). */ +#define EPT_E_MEMTYPE_INVALID_3 (UINT64_C(3) << EPT_E_MEMTYPE_SHIFT) +/** Bits 3-5 - Memory type: WT (Write Through). */ +#define EPT_E_MEMTYPE_WT (UINT64_C(4) << EPT_E_MEMTYPE_SHIFT) +/** Bits 3-5 - Memory type: WP (Write Protected). */ +#define EPT_E_MEMTYPE_WP (UINT64_C(5) << EPT_E_MEMTYPE_SHIFT) +/** Bits 3-5 - Memory type: WB (Write Back). */ +#define EPT_E_MEMTYPE_WB (UINT64_C(6) << EPT_E_MEMTYPE_SHIFT) +/** Bits 3-5 - Memory type: Invalid (7). */ +#define EPT_E_MEMTYPE_INVALID_7 (UINT64_C(7) << EPT_E_MEMTYPE_SHIFT) +/** Bit 6 - Ignore page attribute table (leaf, MBZ). */ +#define EPT_E_BIT_IGNORE_PAT 6 +#define EPT_E_IGNORE_PAT RT_BIT_64(EPT_E_BIT_IGNORE_PAT) /**< @see EPT_E_BIT_IGNORE_PAT */ +/** Bit 7 - Leaf entry (MBZ in PML4, ignored in PT). */ +#define EPT_E_BIT_LEAF 7 +#define EPT_E_LEAF RT_BIT_64(EPT_E_BIT_LEAF) /**< @see EPT_E_BIT_LEAF */ +/** Bit 8 - Accessed (all levels). + * @note Ignored and not written when EPTP bit 6 is 0. */ +#define EPT_E_BIT_ACCESSED 8 +#define EPT_E_ACCESSED RT_BIT_64(EPT_E_BIT_ACCESSED) /**< @see EPT_E_BIT_ACCESSED */ +/** Bit 9 - Dirty (leaf only). + * @note Ignored and not written when EPTP bit 6 is 0. */ +#define EPT_E_BIT_DIRTY 9 +#define EPT_E_DIRTY RT_BIT_64(EPT_E_BIT_DIRTY) /**< @see EPT_E_BIT_DIRTY */ +/** Bit 10 - Executable for usermode. + * @note This ignored if mode-based execution control is disabled. */ +#define EPT_E_BIT_USER_EXECUTE 10 +#define EPT_E_USER_EXECUTE RT_BIT_64(EPT_E_BIT_USER_EXECUTE) /**< @see EPT_E_BIT_USER_EXECUTE */ +/* Bit 11 is always ignored. */ +/** Bits 12-51 - Physical Page number of the next level. */ +#define EPT_E_PG_MASK UINT64_C(0x000ffffffffff000) +/** Bit 58 - Page-write access (leaf only, ignored). + * @note Ignored if EPT page-write control is disabled. */ +#define EPT_E_BIT_PAGING_WRITE 58 +#define EPT_E_PAGING_WRITE RT_BIT_64(EPT_E_BIT_PAGING_WRITE) /**< @see EPT_E_BIT_PAGING_WRITE*/ +/* Bit 59 is always ignored. */ +/** Bit 60 - Supervisor shadow stack (leaf only, ignored). + * @note Ignored if EPT bit 7 is 0. */ +#define EPT_E_BIT_SUPER_SHW_STACK 60 +#define EPT_E_SUPER_SHW_STACK RT_BIT_64(EPT_E_BIT_SUPER_SHW_STACK) /**< @see EPT_E_BIT_SUPER_SHW_STACK */ +/** Bit 61 - Sub-page write permission (leaf only, ignored). + * @note Ignored if sub-page write permission for EPT is disabled. */ +#define EPT_E_BIT_SUBPAGE_WRITE_PERM 61 +#define EPT_E_SUBPAGE_WRITE_PERM RT_BIT_64(EPT_E_BIT_SUBPAGE_WRITE_PERM) /**< @see EPT_E_BIT_SUBPAGE_WRITE_PERM*/ +/* Bit 62 is always ignored. */ +/** Bit 63 - Suppress \#VE (leaf only, ignored). + * @note Ignored if EPT violation to \#VE conversion is disabled. */ +#define EPT_E_BIT_SUPPRESS_VE 63 +#define EPT_E_SUPPRESS_VE RT_BIT_64(EPT_E_BIT_SUPPRESS_VE) /**< @see EPT_E_BIT_SUPPRESS_VE */ +/** @} */ + + +/**@name Bit fields for common EPT attributes. + @{ */ +/** Read access. */ +#define VMX_BF_EPT_PT_READ_SHIFT 0 +#define VMX_BF_EPT_PT_READ_MASK UINT64_C(0x0000000000000001) +/** Write access. */ +#define VMX_BF_EPT_PT_WRITE_SHIFT 1 +#define VMX_BF_EPT_PT_WRITE_MASK UINT64_C(0x0000000000000002) +/** Execute access or execute access for supervisor-mode linear-addresses. */ +#define VMX_BF_EPT_PT_EXECUTE_SHIFT 2 +#define VMX_BF_EPT_PT_EXECUTE_MASK UINT64_C(0x0000000000000004) +/** EPT memory type. */ +#define VMX_BF_EPT_PT_MEMTYPE_SHIFT 3 +#define VMX_BF_EPT_PT_MEMTYPE_MASK UINT64_C(0x0000000000000038) +/** Ignore PAT. */ +#define VMX_BF_EPT_PT_IGNORE_PAT_SHIFT 6 +#define VMX_BF_EPT_PT_IGNORE_PAT_MASK UINT64_C(0x0000000000000040) +/** Ignored (bit 7). */ +#define VMX_BF_EPT_PT_IGN_7_SHIFT 7 +#define VMX_BF_EPT_PT_IGN_7_MASK UINT64_C(0x0000000000000080) +/** Accessed flag. */ +#define VMX_BF_EPT_PT_ACCESSED_SHIFT 8 +#define VMX_BF_EPT_PT_ACCESSED_MASK UINT64_C(0x0000000000000100) +/** Dirty flag. */ +#define VMX_BF_EPT_PT_DIRTY_SHIFT 9 +#define VMX_BF_EPT_PT_DIRTY_MASK UINT64_C(0x0000000000000200) +/** Execute access for user-mode linear addresses. */ +#define VMX_BF_EPT_PT_EXECUTE_USER_SHIFT 10 +#define VMX_BF_EPT_PT_EXECUTE_USER_MASK UINT64_C(0x0000000000000400) +/** Ignored (bit 59:11). */ +#define VMX_BF_EPT_PT_IGN_59_11_SHIFT 11 +#define VMX_BF_EPT_PT_IGN_59_11_MASK UINT64_C(0x0ffffffffffff800) +/** Supervisor shadow stack. */ +#define VMX_BF_EPT_PT_SUPER_SHW_STACK_SHIFT 60 +#define VMX_BF_EPT_PT_SUPER_SHW_STACK_MASK UINT64_C(0x1000000000000000) +/** Ignored (bits 62:61). */ +#define VMX_BF_EPT_PT_IGN_62_61_SHIFT 61 +#define VMX_BF_EPT_PT_IGN_62_61_MASK UINT64_C(0x6000000000000000) +/** Suppress \#VE. */ +#define VMX_BF_EPT_PT_SUPPRESS_VE_SHIFT 63 +#define VMX_BF_EPT_PT_SUPPRESS_VE_MASK UINT64_C(0x8000000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_EPT_PT_, UINT64_C(0), UINT64_MAX, + (READ, WRITE, EXECUTE, MEMTYPE, IGNORE_PAT, IGN_7, ACCESSED, DIRTY, EXECUTE_USER, IGN_59_11, + SUPER_SHW_STACK, IGN_62_61, SUPPRESS_VE)); +/** @} */ + + +/** @name VMX Extended Page Tables (EPT) Structures + * @{ + */ + +/** + * Number of page table entries in the EPT. (PDPTE/PDE/PTE) + */ +#define EPT_PG_ENTRIES X86_PG_PAE_ENTRIES + +/** + * EPT present mask. + * These are ONLY the common bits in all EPT page-table entries which does + * not rely on any CPU feature. It isn't necessarily the complete mask (e.g. when + * mode-based excute control is active). + */ +#define EPT_PRESENT_MASK (EPT_E_READ | EPT_E_WRITE | EPT_E_EXECUTE) + +/** + * EPT Page Directory Pointer Entry. Bit view. + * In accordance with the VT-x spec. + * + * @todo uint64_t isn't safe for bitfields (gcc pedantic warnings, and IIRC, + * this did cause trouble with one compiler/version). + */ +typedef struct EPTPML4EBITS +{ + /** Present bit. */ + RT_GCC_EXTENSION uint64_t u1Present : 1; + /** Writable bit. */ + RT_GCC_EXTENSION uint64_t u1Write : 1; + /** Executable bit. */ + RT_GCC_EXTENSION uint64_t u1Execute : 1; + /** Reserved (must be 0). */ + RT_GCC_EXTENSION uint64_t u5Reserved : 5; + /** Available for software. */ + RT_GCC_EXTENSION uint64_t u4Available : 4; + /** Physical address of the next level (PD). Restricted by maximum physical address width of the cpu. */ + RT_GCC_EXTENSION uint64_t u40PhysAddr : 40; + /** Available for software. */ + RT_GCC_EXTENSION uint64_t u12Available : 12; +} EPTPML4EBITS; +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 +/** Bits - - EPT - PML4 MBZ mask. */ +#define EPT_PML4E_MBZ_MASK UINT64_C(0x00000000000000f8) +/** Mask of all possible EPT PML4E attribute bits. */ +#define EPT_PML4E_ATTR_MASK (EPT_E_READ | EPT_E_WRITE | EPT_E_EXECUTE | EPT_E_ACCESSED | EPT_E_USER_EXECUTE) + +/** + * EPT PML4E. + * In accordance with the VT-x spec. + */ +typedef union EPTPML4E +{ +#ifndef VBOX_WITHOUT_PAGING_BIT_FIELDS + /** Normal view. */ + EPTPML4EBITS n; +#endif + /** Unsigned integer view. */ + X86PGPAEUINT u; + /** 64 bit unsigned integer view. */ + uint64_t au64[1]; + /** 32 bit unsigned integer view. */ + uint32_t au32[2]; +} EPTPML4E; +AssertCompileSize(EPTPML4E, 8); +/** Pointer to a PML4 table entry. */ +typedef EPTPML4E *PEPTPML4E; +/** Pointer to a const PML4 table entry. */ +typedef const EPTPML4E *PCEPTPML4E; + +/** + * EPT PML4 Table. + * In accordance with the VT-x spec. + */ +typedef struct EPTPML4 +{ + EPTPML4E a[EPT_PG_ENTRIES]; +} EPTPML4; +AssertCompileSize(EPTPML4, 0x1000); +/** 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. + * In accordance with the VT-x spec. + */ +typedef struct EPTPDPTEBITS +{ + /** Present bit. */ + RT_GCC_EXTENSION uint64_t u1Present : 1; + /** Writable bit. */ + RT_GCC_EXTENSION uint64_t u1Write : 1; + /** Executable bit. */ + RT_GCC_EXTENSION uint64_t u1Execute : 1; + /** Reserved (must be 0). */ + RT_GCC_EXTENSION uint64_t u5Reserved : 5; + /** Available for software. */ + RT_GCC_EXTENSION uint64_t u4Available : 4; + /** Physical address of the next level (PD). Restricted by maximum physical address width of the cpu. */ + RT_GCC_EXTENSION uint64_t u40PhysAddr : 40; + /** Available for software. */ + RT_GCC_EXTENSION uint64_t u12Available : 12; +} EPTPDPTEBITS; +AssertCompileSize(EPTPDPTEBITS, 8); + +/** Bit 7 - - EPT - PDPTE maps a 1GB page. */ +#define EPT_PDPTE1G_SIZE_MASK RT_BIT_64(7) +/** Bits 12-51 - - EPT - Physical Page number of the next level. */ +#define EPT_PDPTE_PG_MASK X86_PDPE_PG_MASK +/** Bits 30-51 - - EPT - Physical Page number of the 1G large page. */ +#define EPT_PDPTE1G_PG_MASK X86_PDPE1G_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 +/** Bits 3-7 - - EPT - PDPTE MBZ Mask. */ +#define EPT_PDPTE_MBZ_MASK UINT64_C(0x00000000000000f8) +/** Bits 12-29 - - EPT - 1GB PDPTE MBZ Mask. */ +#define EPT_PDPTE1G_MBZ_MASK UINT64_C(0x000000003ffff000) +/** Mask of all possible EPT PDPTE (1GB) attribute bits. */ +#define EPT_PDPTE1G_ATTR_MASK ( EPT_E_READ | EPT_E_WRITE | EPT_E_EXECUTE | EPT_E_MEMTYPE_MASK | EPT_E_IGNORE_PAT \ + | EPT_E_ACCESSED | EPT_E_DIRTY | EPT_E_USER_EXECUTE) +/** Mask of all possible EPT PDPTE attribute bits. */ +#define EPT_PDPTE_ATTR_MASK (EPT_E_READ | EPT_E_WRITE | EPT_E_EXECUTE | EPT_E_ACCESSED | EPT_E_USER_EXECUTE) +/** */ + +/** + * EPT Page Directory Pointer. + * In accordance with the VT-x spec. + */ +typedef union EPTPDPTE +{ +#ifndef VBOX_WITHOUT_PAGING_BIT_FIELDS + /** Normal view. */ + EPTPDPTEBITS n; +#endif + /** Unsigned integer view. */ + X86PGPAEUINT u; + /** 64 bit unsigned integer view. */ + uint64_t au64[1]; + /** 32 bit unsigned integer view. */ + uint32_t au32[2]; +} EPTPDPTE; +AssertCompileSize(EPTPDPTE, 8); +/** Pointer to an EPT Page Directory Pointer Entry. */ +typedef EPTPDPTE *PEPTPDPTE; +/** Pointer to a const EPT Page Directory Pointer Entry. */ +typedef const EPTPDPTE *PCEPTPDPTE; + +/** + * EPT Page Directory Pointer Table. + * In accordance with the VT-x spec. + */ +typedef struct EPTPDPT +{ + EPTPDPTE a[EPT_PG_ENTRIES]; +} EPTPDPT; +AssertCompileSize(EPTPDPT, 0x1000); +/** 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. + * In accordance with the VT-x spec. + */ +typedef struct EPTPDEBITS +{ + /** Present bit. */ + RT_GCC_EXTENSION uint64_t u1Present : 1; + /** Writable bit. */ + RT_GCC_EXTENSION uint64_t u1Write : 1; + /** Executable bit. */ + RT_GCC_EXTENSION uint64_t u1Execute : 1; + /** Reserved (must be 0). */ + RT_GCC_EXTENSION uint64_t u4Reserved : 4; + /** Big page (must be 0 here). */ + RT_GCC_EXTENSION uint64_t u1Size : 1; + /** Available for software. */ + RT_GCC_EXTENSION uint64_t u4Available : 4; + /** Physical address of page table. Restricted by maximum physical address width of the cpu. */ + RT_GCC_EXTENSION uint64_t u40PhysAddr : 40; + /** Available for software. */ + RT_GCC_EXTENSION uint64_t u12Available : 12; +} EPTPDEBITS; +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 +/** Bits 3-7 - EPT - PDE MBZ Mask. */ +#define EPT_PDE_MBZ_MASK UINT64_C(0x00000000000000f8) +/** Mask of all possible EPT PDE (2M) attribute bits. */ +#define EPT_PDE2M_ATTR_MASK ( EPT_E_READ | EPT_E_WRITE | EPT_E_EXECUTE | EPT_E_MEMTYPE_MASK | EPT_E_IGNORE_PAT \ + | EPT_E_ACCESSED | EPT_E_DIRTY | EPT_E_USER_EXECUTE) +/** Mask of all possible EPT PDE attribute bits. */ +#define EPT_PDE_ATTR_MASK (EPT_E_READ | EPT_E_WRITE | EPT_E_EXECUTE | EPT_E_ACCESSED | EPT_E_USER_EXECUTE) + + +/** + * EPT 2MB Page Directory Table Entry. Bit view. + * In accordance with the VT-x spec. + */ +typedef struct EPTPDE2MBITS +{ + /** Present bit. */ + RT_GCC_EXTENSION uint64_t u1Present : 1; + /** Writable bit. */ + RT_GCC_EXTENSION uint64_t u1Write : 1; + /** Executable bit. */ + RT_GCC_EXTENSION uint64_t u1Execute : 1; + /** EPT Table Memory Type. MBZ for non-leaf nodes. */ + RT_GCC_EXTENSION uint64_t u3EMT : 3; + /** Ignore PAT memory type */ + RT_GCC_EXTENSION uint64_t u1IgnorePAT : 1; + /** Big page (must be 1 here). */ + RT_GCC_EXTENSION uint64_t u1Size : 1; + /** Available for software. */ + RT_GCC_EXTENSION uint64_t u4Available : 4; + /** Reserved (must be 0). */ + RT_GCC_EXTENSION uint64_t u9Reserved : 9; + /** Physical address of the 2MB page. Restricted by maximum physical address width of the cpu. */ + RT_GCC_EXTENSION uint64_t u31PhysAddr : 31; + /** Available for software. */ + RT_GCC_EXTENSION uint64_t u12Available : 12; +} EPTPDE2MBITS; +AssertCompileSize(EPTPDE2MBITS, 8); + +/** Bits 21-51 - - EPT - Physical Page number of the next level. */ +#define EPT_PDE2M_PG_MASK X86_PDE2M_PAE_PG_MASK +/** Bits 20-12 - - EPT - PDE 2M MBZ Mask. */ +#define EPT_PDE2M_MBZ_MASK UINT64_C(0x00000000001ff000) + + +/** + * EPT Page Directory Table Entry. + * In accordance with the VT-x spec. + */ +typedef union EPTPDE +{ +#ifndef VBOX_WITHOUT_PAGING_BIT_FIELDS + /** Normal view. */ + EPTPDEBITS n; + /** 2MB view (big). */ + EPTPDE2MBITS b; +#endif + /** Unsigned integer view. */ + X86PGPAEUINT u; + /** 64 bit unsigned integer view. */ + uint64_t au64[1]; + /** 32 bit unsigned integer view. */ + uint32_t au32[2]; +} EPTPDE; +AssertCompileSize(EPTPDE, 8); +/** Pointer to an EPT Page Directory Table Entry. */ +typedef EPTPDE *PEPTPDE; +/** Pointer to a const EPT Page Directory Table Entry. */ +typedef const EPTPDE *PCEPTPDE; + +/** + * EPT Page Directory Table. + * In accordance with the VT-x spec. + */ +typedef struct EPTPD +{ + EPTPDE a[EPT_PG_ENTRIES]; +} EPTPD; +AssertCompileSize(EPTPD, 0x1000); +/** 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. + * In accordance with the VT-x spec. + */ +typedef struct EPTPTEBITS +{ + /** 0 - Present bit. + * @remarks 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. */ + RT_GCC_EXTENSION uint64_t u1Present : 1; + /** 1 - Writable bit. */ + RT_GCC_EXTENSION uint64_t u1Write : 1; + /** 2 - Executable bit. */ + RT_GCC_EXTENSION uint64_t u1Execute : 1; + /** 5:3 - EPT Memory Type. MBZ for non-leaf nodes. */ + RT_GCC_EXTENSION uint64_t u3EMT : 3; + /** 6 - Ignore PAT memory type */ + RT_GCC_EXTENSION uint64_t u1IgnorePAT : 1; + /** 11:7 - Available for software. */ + RT_GCC_EXTENSION uint64_t u5Available : 5; + /** 51:12 - Physical address of page. Restricted by maximum physical + * address width of the cpu. */ + RT_GCC_EXTENSION uint64_t u40PhysAddr : 40; + /** 63:52 - Available for software. */ + RT_GCC_EXTENSION uint64_t u12Available : 12; +} EPTPTEBITS; +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 +/** No bits - - EPT - PTE MBZ bits. */ +#define EPT_PTE_MBZ_MASK UINT64_C(0x0000000000000000) +/** Mask of all possible EPT PTE attribute bits. */ +#define EPT_PTE_ATTR_MASK ( EPT_E_READ | EPT_E_WRITE | EPT_E_EXECUTE | EPT_E_MEMTYPE_MASK | EPT_E_IGNORE_PAT \ + | EPT_E_ACCESSED | EPT_E_USER_EXECUTE) + + +/** + * EPT Page Table Entry. + * In accordance with the VT-x spec. + */ +typedef union EPTPTE +{ +#ifndef VBOX_WITHOUT_PAGING_BIT_FIELDS + /** Normal view. */ + EPTPTEBITS n; +#endif + /** Unsigned integer view. */ + X86PGPAEUINT u; + /** 64 bit unsigned integer view. */ + uint64_t au64[1]; + /** 32 bit unsigned integer view. */ + uint32_t au32[2]; +} EPTPTE; +AssertCompileSize(EPTPTE, 8); +/** Pointer to an EPT Page Directory Table Entry. */ +typedef EPTPTE *PEPTPTE; +/** Pointer to a const EPT Page Directory Table Entry. */ +typedef const EPTPTE *PCEPTPTE; + +/** + * EPT Page Table. + * In accordance with the VT-x spec. + */ +typedef struct EPTPT +{ + EPTPTE a[EPT_PG_ENTRIES]; +} EPTPT; +AssertCompileSize(EPTPT, 0x1000); +/** Pointer to an extended page table. */ +typedef EPTPT *PEPTPT; +/** Pointer to a const extended table. */ +typedef const EPTPT *PCEPTPT; + +/** EPTP page mask for the EPT PML4 table. */ +#define EPT_EPTP_PG_MASK X86_CR3_AMD64_PAGE_MASK +/** @} */ + +/** + * VMX VPID flush types. + * Valid enum members are in accordance with the VT-x spec. + */ +typedef enum +{ + /** Invalidate a specific page. */ + VMXTLBFLUSHVPID_INDIV_ADDR = 0, + /** Invalidate one context (specific VPID). */ + VMXTLBFLUSHVPID_SINGLE_CONTEXT = 1, + /** Invalidate all contexts (all VPIDs). */ + VMXTLBFLUSHVPID_ALL_CONTEXTS = 2, + /** Invalidate a single VPID context retaining global mappings. */ + VMXTLBFLUSHVPID_SINGLE_CONTEXT_RETAIN_GLOBALS = 3, + /** Unsupported by VirtualBox. */ + VMXTLBFLUSHVPID_NOT_SUPPORTED = 0xbad0, + /** Unsupported by CPU. */ + VMXTLBFLUSHVPID_NONE = 0xbad1 +} VMXTLBFLUSHVPID; +AssertCompileSize(VMXTLBFLUSHVPID, 4); +/** Mask of all valid INVVPID flush types. */ +#define VMX_INVVPID_VALID_MASK ( VMXTLBFLUSHVPID_INDIV_ADDR \ + | VMXTLBFLUSHVPID_SINGLE_CONTEXT \ + | VMXTLBFLUSHVPID_ALL_CONTEXTS \ + | VMXTLBFLUSHVPID_SINGLE_CONTEXT_RETAIN_GLOBALS) + +/** + * VMX EPT flush types. + * @note Valid enums values are in accordance with the VT-x spec. + */ +typedef enum +{ + /** Invalidate one context (specific EPT). */ + VMXTLBFLUSHEPT_SINGLE_CONTEXT = 1, + /* Invalidate all contexts (all EPTs) */ + VMXTLBFLUSHEPT_ALL_CONTEXTS = 2, + /** Unsupported by VirtualBox. */ + VMXTLBFLUSHEPT_NOT_SUPPORTED = 0xbad0, + /** Unsupported by CPU. */ + VMXTLBFLUSHEPT_NONE = 0xbad1 +} VMXTLBFLUSHEPT; +AssertCompileSize(VMXTLBFLUSHEPT, 4); +/** Mask of all valid INVEPT flush types. */ +#define VMX_INVEPT_VALID_MASK ( VMXTLBFLUSHEPT_SINGLE_CONTEXT \ + | VMXTLBFLUSHEPT_ALL_CONTEXTS) + +/** + * VMX Posted Interrupt Descriptor. + * In accordance with the VT-x spec. + */ +typedef struct VMXPOSTEDINTRDESC +{ + uint32_t aVectorBitmap[8]; + uint32_t fOutstandingNotification : 1; + uint32_t uReserved0 : 31; + uint8_t au8Reserved0[28]; +} VMXPOSTEDINTRDESC; +AssertCompileMemberSize(VMXPOSTEDINTRDESC, aVectorBitmap, 32); +AssertCompileSize(VMXPOSTEDINTRDESC, 64); +/** Pointer to a posted interrupt descriptor. */ +typedef VMXPOSTEDINTRDESC *PVMXPOSTEDINTRDESC; +/** Pointer to a const posted interrupt descriptor. */ +typedef const VMXPOSTEDINTRDESC *PCVMXPOSTEDINTRDESC; + +/** + * VMX VMCS revision identifier. + * In accordance with the VT-x spec. + */ +typedef union +{ + struct + { + /** Revision identifier. */ + uint32_t u31RevisionId : 31; + /** Whether this is a shadow VMCS. */ + uint32_t fIsShadowVmcs : 1; + } n; + /* The unsigned integer view. */ + uint32_t u; +} VMXVMCSREVID; +AssertCompileSize(VMXVMCSREVID, 4); +/** Pointer to the VMXVMCSREVID union. */ +typedef VMXVMCSREVID *PVMXVMCSREVID; +/** Pointer to a const VMXVMCSREVID union. */ +typedef const VMXVMCSREVID *PCVMXVMCSREVID; + +/** + * VMX VM-exit instruction information. + * In accordance with the VT-x spec. + */ +typedef union +{ + /** Plain unsigned int representation. */ + uint32_t u; + + /** INS and OUTS information. */ + struct + { + uint32_t u7Reserved0 : 7; + /** The address size; 0=16-bit, 1=32-bit, 2=64-bit, rest undefined. */ + uint32_t u3AddrSize : 3; + uint32_t u5Reserved1 : 5; + /** The segment register (X86_SREG_XXX). */ + uint32_t iSegReg : 3; + uint32_t uReserved2 : 14; + } StrIo; + + /** INVEPT, INVPCID, INVVPID information. */ + struct + { + /** Scaling; 0=no scaling, 1=scale-by-2, 2=scale-by-4, 3=scale-by-8. */ + uint32_t u2Scaling : 2; + uint32_t u5Undef0 : 5; + /** The address size; 0=16-bit, 1=32-bit, 2=64-bit, rest undefined. */ + uint32_t u3AddrSize : 3; + /** Cleared to 0. */ + uint32_t u1Cleared0 : 1; + uint32_t u4Undef0 : 4; + /** The segment register (X86_SREG_XXX). */ + uint32_t iSegReg : 3; + /** The index register (X86_GREG_XXX). */ + uint32_t iIdxReg : 4; + /** Set if index register is invalid. */ + uint32_t fIdxRegInvalid : 1; + /** The base register (X86_GREG_XXX). */ + uint32_t iBaseReg : 4; + /** Set if base register is invalid. */ + uint32_t fBaseRegInvalid : 1; + /** Register 2 (X86_GREG_XXX). */ + uint32_t iReg2 : 4; + } Inv; + + /** VMCLEAR, VMPTRLD, VMPTRST, VMXON, XRSTORS, XSAVES information. */ + struct + { + /** Scaling; 0=no scaling, 1=scale-by-2, 2=scale-by-4, 3=scale-by-8. */ + uint32_t u2Scaling : 2; + uint32_t u5Reserved0 : 5; + /** The address size; 0=16-bit, 1=32-bit, 2=64-bit, rest undefined. */ + uint32_t u3AddrSize : 3; + /** Cleared to 0. */ + uint32_t u1Cleared0 : 1; + uint32_t u4Reserved0 : 4; + /** The segment register (X86_SREG_XXX). */ + uint32_t iSegReg : 3; + /** The index register (X86_GREG_XXX). */ + uint32_t iIdxReg : 4; + /** Set if index register is invalid. */ + uint32_t fIdxRegInvalid : 1; + /** The base register (X86_GREG_XXX). */ + uint32_t iBaseReg : 4; + /** Set if base register is invalid. */ + uint32_t fBaseRegInvalid : 1; + /** Register 2 (X86_GREG_XXX). */ + uint32_t iReg2 : 4; + } VmxXsave; + + /** LIDT, LGDT, SIDT, SGDT information. */ + struct + { + /** Scaling; 0=no scaling, 1=scale-by-2, 2=scale-by-4, 3=scale-by-8. */ + uint32_t u2Scaling : 2; + uint32_t u5Undef0 : 5; + /** The address size; 0=16-bit, 1=32-bit, 2=64-bit, rest undefined. */ + uint32_t u3AddrSize : 3; + /** Always cleared to 0. */ + uint32_t u1Cleared0 : 1; + /** Operand size; 0=16-bit, 1=32-bit, undefined for 64-bit. */ + uint32_t uOperandSize : 1; + uint32_t u3Undef0 : 3; + /** The segment register (X86_SREG_XXX). */ + uint32_t iSegReg : 3; + /** The index register (X86_GREG_XXX). */ + uint32_t iIdxReg : 4; + /** Set if index register is invalid. */ + uint32_t fIdxRegInvalid : 1; + /** The base register (X86_GREG_XXX). */ + uint32_t iBaseReg : 4; + /** Set if base register is invalid. */ + uint32_t fBaseRegInvalid : 1; + /** Instruction identity (VMX_INSTR_ID_XXX). */ + uint32_t u2InstrId : 2; + uint32_t u2Undef0 : 2; + } GdtIdt; + + /** LLDT, LTR, SLDT, STR information. */ + struct + { + /** Scaling; 0=no scaling, 1=scale-by-2, 2=scale-by-4, 3=scale-by-8. */ + uint32_t u2Scaling : 2; + uint32_t u1Undef0 : 1; + /** Register 1 (X86_GREG_XXX). */ + uint32_t iReg1 : 4; + /** The address size; 0=16-bit, 1=32-bit, 2=64-bit, rest undefined. */ + uint32_t u3AddrSize : 3; + /** Memory/Register - Always cleared to 0 to indicate memory operand. */ + uint32_t fIsRegOperand : 1; + uint32_t u4Undef0 : 4; + /** The segment register (X86_SREG_XXX). */ + uint32_t iSegReg : 3; + /** The index register (X86_GREG_XXX). */ + uint32_t iIdxReg : 4; + /** Set if index register is invalid. */ + uint32_t fIdxRegInvalid : 1; + /** The base register (X86_GREG_XXX). */ + uint32_t iBaseReg : 4; + /** Set if base register is invalid. */ + uint32_t fBaseRegInvalid : 1; + /** Instruction identity (VMX_INSTR_ID_XXX). */ + uint32_t u2InstrId : 2; + uint32_t u2Undef0 : 2; + } LdtTr; + + /** RDRAND, RDSEED information. */ + struct + { + /** Scaling; 0=no scaling, 1=scale-by-2, 2=scale-by-4, 3=scale-by-8. */ + uint32_t u2Undef0 : 2; + /** Destination register (X86_GREG_XXX). */ + uint32_t iReg1 : 4; + uint32_t u4Undef0 : 4; + /** Operand size; 0=16-bit, 1=32-bit, 2=64-bit, 3=unused. */ + uint32_t u2OperandSize : 2; + uint32_t u19Def0 : 20; + } RdrandRdseed; + + /** VMREAD, VMWRITE information. */ + struct + { + /** Scaling; 0=no scaling, 1=scale-by-2, 2=scale-by-4, 3=scale-by-8. */ + uint32_t u2Scaling : 2; + uint32_t u1Undef0 : 1; + /** Register 1 (X86_GREG_XXX). */ + uint32_t iReg1 : 4; + /** The address size; 0=16-bit, 1=32-bit, 2=64-bit, rest undefined. */ + uint32_t u3AddrSize : 3; + /** Memory or register operand. */ + uint32_t fIsRegOperand : 1; + /** Operand size; 0=16-bit, 1=32-bit, 2=64-bit, 3=unused. */ + uint32_t u4Undef0 : 4; + /** The segment register (X86_SREG_XXX). */ + uint32_t iSegReg : 3; + /** The index register (X86_GREG_XXX). */ + uint32_t iIdxReg : 4; + /** Set if index register is invalid. */ + uint32_t fIdxRegInvalid : 1; + /** The base register (X86_GREG_XXX). */ + uint32_t iBaseReg : 4; + /** Set if base register is invalid. */ + uint32_t fBaseRegInvalid : 1; + /** Register 2 (X86_GREG_XXX). */ + uint32_t iReg2 : 4; + } VmreadVmwrite; + + struct + { + uint32_t u2Undef0 : 3; + /** First XMM register operand. */ + uint32_t u4XmmReg1 : 4; + uint32_t u23Undef1 : 21; + /** Second XMM register operand. */ + uint32_t u4XmmReg2 : 4; + } LoadIwkey; + + /** This is a combination field of all instruction information. Note! Not all field + * combinations are valid (e.g., iReg1 is undefined for memory operands) and + * specialized fields are overwritten by their generic counterparts (e.g. no + * instruction identity field). */ + struct + { + /** Scaling; 0=no scaling, 1=scale-by-2, 2=scale-by-4, 3=scale-by-8. */ + uint32_t u2Scaling : 2; + uint32_t u1Undef0 : 1; + /** Register 1 (X86_GREG_XXX). */ + uint32_t iReg1 : 4; + /** The address size; 0=16-bit, 1=32-bit, 2=64-bit, rest undefined. */ + uint32_t u3AddrSize : 3; + /** Memory/Register - Always cleared to 0 to indicate memory operand. */ + uint32_t fIsRegOperand : 1; + /** Operand size; 0=16-bit, 1=32-bit, 2=64-bit, 3=unused. */ + uint32_t uOperandSize : 2; + uint32_t u2Undef0 : 2; + /** The segment register (X86_SREG_XXX). */ + uint32_t iSegReg : 3; + /** The index register (X86_GREG_XXX). */ + uint32_t iIdxReg : 4; + /** Set if index register is invalid. */ + uint32_t fIdxRegInvalid : 1; + /** The base register (X86_GREG_XXX). */ + uint32_t iBaseReg : 4; + /** Set if base register is invalid. */ + uint32_t fBaseRegInvalid : 1; + /** Register 2 (X86_GREG_XXX) or instruction identity. */ + uint32_t iReg2 : 4; + } All; +} VMXEXITINSTRINFO; +AssertCompileSize(VMXEXITINSTRINFO, 4); +/** Pointer to a VMX VM-exit instruction info. struct. */ +typedef VMXEXITINSTRINFO *PVMXEXITINSTRINFO; +/** Pointer to a const VMX VM-exit instruction info. struct. */ +typedef const VMXEXITINSTRINFO *PCVMXEXITINSTRINFO; + + +/** @name VM-entry failure reported in Exit qualification. + * See Intel spec. 26.7 "VM-entry failures during or after loading guest-state". + * @{ + */ +/** No errors during VM-entry. */ +#define VMX_ENTRY_FAIL_QUAL_NO_ERROR (0) +/** Not used. */ +#define VMX_ENTRY_FAIL_QUAL_NOT_USED (1) +/** Error while loading PDPTEs. */ +#define VMX_ENTRY_FAIL_QUAL_PDPTE (2) +/** NMI injection when blocking-by-STI is set. */ +#define VMX_ENTRY_FAIL_QUAL_NMI_INJECT (3) +/** Invalid VMCS link pointer. */ +#define VMX_ENTRY_FAIL_QUAL_VMCS_LINK_PTR (4) +/** @} */ + + +/** @name VMXMSRPM_XXX - VMX MSR-bitmap permissions. + * These are -not- specified by Intel but used internally by VirtualBox. + * @{ */ +/** Guest software reads of this MSR must not cause a VM-exit. */ +#define VMXMSRPM_ALLOW_RD RT_BIT(0) +/** Guest software reads of this MSR must cause a VM-exit. */ +#define VMXMSRPM_EXIT_RD RT_BIT(1) +/** Guest software writes to this MSR must not cause a VM-exit. */ +#define VMXMSRPM_ALLOW_WR RT_BIT(2) +/** Guest software writes to this MSR must cause a VM-exit. */ +#define VMXMSRPM_EXIT_WR RT_BIT(3) +/** Guest software reads or writes of this MSR must not cause a VM-exit. */ +#define VMXMSRPM_ALLOW_RD_WR (VMXMSRPM_ALLOW_RD | VMXMSRPM_ALLOW_WR) +/** Guest software reads or writes of this MSR must cause a VM-exit. */ +#define VMXMSRPM_EXIT_RD_WR (VMXMSRPM_EXIT_RD | VMXMSRPM_EXIT_WR) +/** Mask of valid MSR read permissions. */ +#define VMXMSRPM_RD_MASK (VMXMSRPM_ALLOW_RD | VMXMSRPM_EXIT_RD) +/** Mask of valid MSR write permissions. */ +#define VMXMSRPM_WR_MASK (VMXMSRPM_ALLOW_WR | VMXMSRPM_EXIT_WR) +/** Mask of valid MSR permissions. */ +#define VMXMSRPM_MASK (VMXMSRPM_RD_MASK | VMXMSRPM_WR_MASK) +/** */ +/** Gets whether the MSR permission is valid or not. */ +#define VMXMSRPM_IS_FLAG_VALID(a_Msrpm) ( (a_Msrpm) != 0 \ + && ((a_Msrpm) & ~VMXMSRPM_MASK) == 0 \ + && ((a_Msrpm) & VMXMSRPM_RD_MASK) != VMXMSRPM_RD_MASK \ + && ((a_Msrpm) & VMXMSRPM_WR_MASK) != VMXMSRPM_WR_MASK) +/** @} */ + +/** + * VMX MSR autoload/store slot. + * In accordance with the VT-x spec. + */ +typedef struct VMXAUTOMSR +{ + /** The MSR Id. */ + uint32_t u32Msr; + /** Reserved (MBZ). */ + uint32_t u32Reserved; + /** The MSR value. */ + uint64_t u64Value; +} VMXAUTOMSR; +AssertCompileSize(VMXAUTOMSR, 16); +/** Pointer to an MSR load/store element. */ +typedef VMXAUTOMSR *PVMXAUTOMSR; +/** Pointer to a const MSR load/store element. */ +typedef const VMXAUTOMSR *PCVMXAUTOMSR; + +/** VMX auto load-store MSR (VMXAUTOMSR) offset mask. */ +#define VMX_AUTOMSR_OFFSET_MASK 0xf + +/** + * VMX tagged-TLB flush types. + */ +typedef enum +{ + VMXTLBFLUSHTYPE_EPT, + VMXTLBFLUSHTYPE_VPID, + VMXTLBFLUSHTYPE_EPT_VPID, + VMXTLBFLUSHTYPE_NONE +} VMXTLBFLUSHTYPE; +/** Pointer to a VMXTLBFLUSHTYPE enum. */ +typedef VMXTLBFLUSHTYPE *PVMXTLBFLUSHTYPE; +/** Pointer to a const VMXTLBFLUSHTYPE enum. */ +typedef const VMXTLBFLUSHTYPE *PCVMXTLBFLUSHTYPE; + +/** + * VMX controls MSR. + * In accordance with the VT-x spec. + */ +typedef union +{ + struct + { + /** Bits set here -must- be set in the corresponding VM-execution controls. */ + uint32_t allowed0; + /** Bits cleared here -must- be cleared in the corresponding VM-execution + * controls. */ + uint32_t allowed1; + } n; + uint64_t u; +} VMXCTLSMSR; +AssertCompileSize(VMXCTLSMSR, 8); +/** Pointer to a VMXCTLSMSR union. */ +typedef VMXCTLSMSR *PVMXCTLSMSR; +/** Pointer to a const VMXCTLSMSR union. */ +typedef const VMXCTLSMSR *PCVMXCTLSMSR; + +/** + * VMX MSRs. + */ +typedef struct VMXMSRS +{ + /** Basic information. */ + uint64_t u64Basic; + /** Pin-based VM-execution controls. */ + VMXCTLSMSR PinCtls; + /** Processor-based VM-execution controls. */ + VMXCTLSMSR ProcCtls; + /** Secondary processor-based VM-execution controls. */ + VMXCTLSMSR ProcCtls2; + /** VM-exit controls. */ + VMXCTLSMSR ExitCtls; + /** VM-entry controls. */ + VMXCTLSMSR EntryCtls; + /** True pin-based VM-execution controls. */ + VMXCTLSMSR TruePinCtls; + /** True processor-based VM-execution controls. */ + VMXCTLSMSR TrueProcCtls; + /** True VM-entry controls. */ + VMXCTLSMSR TrueEntryCtls; + /** True VM-exit controls. */ + VMXCTLSMSR TrueExitCtls; + /** Miscellaneous data. */ + uint64_t u64Misc; + /** CR0 fixed-0 - bits set here must be set in VMX operation. */ + uint64_t u64Cr0Fixed0; + /** CR0 fixed-1 - bits clear here must be clear in VMX operation. */ + uint64_t u64Cr0Fixed1; + /** CR4 fixed-0 - bits set here must be set in VMX operation. */ + uint64_t u64Cr4Fixed0; + /** CR4 fixed-1 - bits clear here must be clear in VMX operation. */ + uint64_t u64Cr4Fixed1; + /** VMCS enumeration. */ + uint64_t u64VmcsEnum; + /** VM Functions. */ + uint64_t u64VmFunc; + /** EPT, VPID capabilities. */ + uint64_t u64EptVpidCaps; + /** Tertiary processor-based VM-execution controls. */ + uint64_t u64ProcCtls3; + /** Secondary VM-exit controls. */ + uint64_t u64ExitCtls2; + /** Reserved for future. */ + uint64_t a_u64Reserved[8]; +} VMXMSRS; +AssertCompileSizeAlignment(VMXMSRS, 8); +AssertCompileSize(VMXMSRS, 224); +/** Pointer to a VMXMSRS struct. */ +typedef VMXMSRS *PVMXMSRS; +/** Pointer to a const VMXMSRS struct. */ +typedef const VMXMSRS *PCVMXMSRS; + + +/** + * LBR MSRs. + */ +typedef struct LBRMSRS +{ + /** List of LastBranch-From-IP MSRs. */ + uint64_t au64BranchFromIpMsr[32]; + /** List of LastBranch-To-IP MSRs. */ + uint64_t au64BranchToIpMsr[32]; + /** The MSR containing the index to the most recent branch record. */ + uint64_t uBranchTosMsr; +} LBRMSRS; +AssertCompileSizeAlignment(LBRMSRS, 8); +/** Pointer to a VMXMSRS struct. */ +typedef LBRMSRS *PLBRMSRS; +/** Pointer to a const VMXMSRS struct. */ +typedef const LBRMSRS *PCLBRMSRS; + + +/** @name VMX Basic Exit Reasons. + * In accordance with the VT-x spec. + * Update g_aVMExitHandlers if new VM-exit reasons are added. + * @{ + */ +/** Invalid exit code */ +#define VMX_EXIT_INVALID (-1) +/** Exception or non-maskable interrupt (NMI). */ +#define VMX_EXIT_XCPT_OR_NMI 0 +/** External interrupt. */ +#define VMX_EXIT_EXT_INT 1 +/** Triple fault. */ +#define VMX_EXIT_TRIPLE_FAULT 2 +/** INIT signal. */ +#define VMX_EXIT_INIT_SIGNAL 3 +/** Start-up IPI (SIPI). */ +#define VMX_EXIT_SIPI 4 +/** I/O system-management interrupt (SMI). */ +#define VMX_EXIT_IO_SMI 5 +/** Other SMI. */ +#define VMX_EXIT_SMI 6 +/** Interrupt window exiting. */ +#define VMX_EXIT_INT_WINDOW 7 +/** NMI window exiting. */ +#define VMX_EXIT_NMI_WINDOW 8 +/** Task switch. */ +#define VMX_EXIT_TASK_SWITCH 9 +/** CPUID. */ +#define VMX_EXIT_CPUID 10 +/** GETSEC. */ +#define VMX_EXIT_GETSEC 11 +/** HLT. */ +#define VMX_EXIT_HLT 12 +/** INVD. */ +#define VMX_EXIT_INVD 13 +/** INVLPG. */ +#define VMX_EXIT_INVLPG 14 +/** RDPMC. */ +#define VMX_EXIT_RDPMC 15 +/** RDTSC. */ +#define VMX_EXIT_RDTSC 16 +/** RSM in SMM. */ +#define VMX_EXIT_RSM 17 +/** VMCALL. */ +#define VMX_EXIT_VMCALL 18 +/** VMCLEAR. */ +#define VMX_EXIT_VMCLEAR 19 +/** VMLAUNCH. */ +#define VMX_EXIT_VMLAUNCH 20 +/** VMPTRLD. */ +#define VMX_EXIT_VMPTRLD 21 +/** VMPTRST. */ +#define VMX_EXIT_VMPTRST 22 +/** VMREAD. */ +#define VMX_EXIT_VMREAD 23 +/** VMRESUME. */ +#define VMX_EXIT_VMRESUME 24 +/** VMWRITE. */ +#define VMX_EXIT_VMWRITE 25 +/** VMXOFF. */ +#define VMX_EXIT_VMXOFF 26 +/** VMXON. */ +#define VMX_EXIT_VMXON 27 +/** Control-register accesses. */ +#define VMX_EXIT_MOV_CRX 28 +/** Debug-register accesses. */ +#define VMX_EXIT_MOV_DRX 29 +/** I/O instruction. */ +#define VMX_EXIT_IO_INSTR 30 +/** RDMSR. */ +#define VMX_EXIT_RDMSR 31 +/** WRMSR. */ +#define VMX_EXIT_WRMSR 32 +/** VM-entry failure due to invalid guest state. */ +#define VMX_EXIT_ERR_INVALID_GUEST_STATE 33 +/** VM-entry failure due to MSR loading. */ +#define VMX_EXIT_ERR_MSR_LOAD 34 +/** MWAIT. */ +#define VMX_EXIT_MWAIT 36 +/** VM-exit due to monitor trap flag. */ +#define VMX_EXIT_MTF 37 +/** MONITOR. */ +#define VMX_EXIT_MONITOR 39 +/** PAUSE. */ +#define VMX_EXIT_PAUSE 40 +/** VM-entry failure due to machine-check. */ +#define VMX_EXIT_ERR_MACHINE_CHECK 41 +/** TPR below threshold. Guest software executed MOV to CR8. */ +#define VMX_EXIT_TPR_BELOW_THRESHOLD 43 +/** VM-exit due to guest accessing physical address in the APIC-access page. */ +#define VMX_EXIT_APIC_ACCESS 44 +/** VM-exit due to EOI virtualization. */ +#define VMX_EXIT_VIRTUALIZED_EOI 45 +/** Access to GDTR/IDTR using LGDT, LIDT, SGDT or SIDT. */ +#define VMX_EXIT_GDTR_IDTR_ACCESS 46 +/** Access to LDTR/TR due to LLDT, LTR, SLDT, or STR. */ +#define VMX_EXIT_LDTR_TR_ACCESS 47 +/** EPT violation. */ +#define VMX_EXIT_EPT_VIOLATION 48 +/** EPT misconfiguration. */ +#define VMX_EXIT_EPT_MISCONFIG 49 +/** INVEPT. */ +#define VMX_EXIT_INVEPT 50 +/** RDTSCP. */ +#define VMX_EXIT_RDTSCP 51 +/** VMX-preemption timer expired. */ +#define VMX_EXIT_PREEMPT_TIMER 52 +/** INVVPID. */ +#define VMX_EXIT_INVVPID 53 +/** WBINVD. */ +#define VMX_EXIT_WBINVD 54 +/** XSETBV. */ +#define VMX_EXIT_XSETBV 55 +/** Guest completed write to virtual-APIC. */ +#define VMX_EXIT_APIC_WRITE 56 +/** RDRAND. */ +#define VMX_EXIT_RDRAND 57 +/** INVPCID. */ +#define VMX_EXIT_INVPCID 58 +/** VMFUNC. */ +#define VMX_EXIT_VMFUNC 59 +/** ENCLS. */ +#define VMX_EXIT_ENCLS 60 +/** RDSEED. */ +#define VMX_EXIT_RDSEED 61 +/** Page-modification log full. */ +#define VMX_EXIT_PML_FULL 62 +/** XSAVES. */ +#define VMX_EXIT_XSAVES 63 +/** XRSTORS. */ +#define VMX_EXIT_XRSTORS 64 +/** SPP-related event (SPP miss or misconfiguration). */ +#define VMX_EXIT_SPP_EVENT 66 +/* UMWAIT. */ +#define VMX_EXIT_UMWAIT 67 +/** TPAUSE. */ +#define VMX_EXIT_TPAUSE 68 +/** LOADIWKEY. */ +#define VMX_EXIT_LOADIWKEY 69 +/** The maximum VM-exit value (inclusive). */ +#define VMX_EXIT_MAX (VMX_EXIT_LOADIWKEY) +/** @} */ + + +/** @name VM Instruction Errors. + * In accordance with the VT-x spec. + * See Intel spec. "30.4 VM Instruction Error Numbers" + * @{ + */ +typedef enum +{ + /** VMCALL executed in VMX root operation. */ + VMXINSTRERR_VMCALL_VMXROOTMODE = 1, + /** VMCLEAR with invalid physical address. */ + VMXINSTRERR_VMCLEAR_INVALID_PHYSADDR = 2, + /** VMCLEAR with VMXON pointer. */ + VMXINSTRERR_VMCLEAR_VMXON_PTR = 3, + /** VMLAUNCH with non-clear VMCS. */ + VMXINSTRERR_VMLAUNCH_NON_CLEAR_VMCS = 4, + /** VMRESUME with non-launched VMCS. */ + VMXINSTRERR_VMRESUME_NON_LAUNCHED_VMCS = 5, + /** VMRESUME after VMXOFF (VMXOFF and VMXON between VMLAUNCH and VMRESUME). */ + VMXINSTRERR_VMRESUME_AFTER_VMXOFF = 6, + /** VM-entry with invalid control field(s). */ + VMXINSTRERR_VMENTRY_INVALID_CTLS = 7, + /** VM-entry with invalid host-state field(s). */ + VMXINSTRERR_VMENTRY_INVALID_HOST_STATE = 8, + /** VMPTRLD with invalid physical address. */ + VMXINSTRERR_VMPTRLD_INVALID_PHYSADDR = 9, + /** VMPTRLD with VMXON pointer. */ + VMXINSTRERR_VMPTRLD_VMXON_PTR = 10, + /** VMPTRLD with incorrect VMCS revision identifier. */ + VMXINSTRERR_VMPTRLD_INCORRECT_VMCS_REV = 11, + /** VMREAD from unsupported VMCS component. */ + VMXINSTRERR_VMREAD_INVALID_COMPONENT = 12, + /** VMWRITE to unsupported VMCS component. */ + VMXINSTRERR_VMWRITE_INVALID_COMPONENT = 12, + /** VMWRITE to read-only VMCS component. */ + VMXINSTRERR_VMWRITE_RO_COMPONENT = 13, + /** VMXON executed in VMX root operation. */ + VMXINSTRERR_VMXON_IN_VMXROOTMODE = 15, + /** VM-entry with invalid executive-VMCS pointer. */ + VMXINSTRERR_VMENTRY_EXEC_VMCS_INVALID_PTR = 16, + /** VM-entry with non-launched executive VMCS. */ + VMXINSTRERR_VMENTRY_EXEC_VMCS_NON_LAUNCHED = 17, + /** VM-entry with executive-VMCS pointer not VMXON pointer. */ + VMXINSTRERR_VMENTRY_EXEC_VMCS_PTR = 18, + /** VMCALL with non-clear VMCS. */ + VMXINSTRERR_VMCALL_NON_CLEAR_VMCS = 19, + /** VMCALL with invalid VM-exit control fields. */ + VMXINSTRERR_VMCALL_INVALID_EXITCTLS = 20, + /** VMCALL with incorrect MSEG revision identifier. */ + VMXINSTRERR_VMCALL_INVALID_MSEG_ID = 22, + /** VMXOFF under dual-monitor treatment of SMIs and SMM. */ + VMXINSTRERR_VMXOFF_DUAL_MON = 23, + /** VMCALL with invalid SMM-monitor features. */ + VMXINSTRERR_VMCALL_INVALID_SMMCTLS = 24, + /** VM-entry with invalid VM-execution control fields in executive VMCS. */ + VMXINSTRERR_VMENTRY_EXEC_VMCS_INVALID_CTLS = 25, + /** VM-entry with events blocked by MOV SS. */ + VMXINSTRERR_VMENTRY_BLOCK_MOVSS = 26, + /** Invalid operand to INVEPT/INVVPID. */ + VMXINSTRERR_INVEPT_INVVPID_INVALID_OPERAND = 28 +} VMXINSTRERR; +/** @} */ + + +/** @name VMX abort reasons. + * In accordance with the VT-x spec. + * See Intel spec. "27.7 VMX Aborts". + * Update HMGetVmxAbortDesc() if new reasons are added. + * @{ + */ +typedef enum +{ + /** None - don't use this / uninitialized value. */ + VMXABORT_NONE = 0, + /** VMX abort caused during saving of guest MSRs. */ + VMXABORT_SAVE_GUEST_MSRS = 1, + /** VMX abort caused during host PDPTE checks. */ + VMXBOART_HOST_PDPTE = 2, + /** VMX abort caused due to current VMCS being corrupted. */ + VMXABORT_CURRENT_VMCS_CORRUPT = 3, + /** VMX abort caused during loading of host MSRs. */ + VMXABORT_LOAD_HOST_MSR = 4, + /** VMX abort caused due to a machine-check exception during VM-exit. */ + VMXABORT_MACHINE_CHECK_XCPT = 5, + /** VMX abort caused due to invalid return from long mode. */ + VMXABORT_HOST_NOT_IN_LONG_MODE = 6, + /* Type size hack. */ + VMXABORT_32BIT_HACK = 0x7fffffff +} VMXABORT; +AssertCompileSize(VMXABORT, 4); +/** @} */ + + +/** @name VMX MSR - Basic VMX information. + * @{ + */ +/** VMCS (and related regions) memory type - Uncacheable. */ +#define VMX_BASIC_MEM_TYPE_UC 0 +/** VMCS (and related regions) memory type - Write back. */ +#define VMX_BASIC_MEM_TYPE_WB 6 +/** Width of physical addresses used for VMCS and associated memory regions + * (1=32-bit, 0=processor's physical address width). */ +#define VMX_BASIC_PHYSADDR_WIDTH_32BIT RT_BIT_64(48) + +/** Bit fields for MSR_IA32_VMX_BASIC. */ +/** VMCS revision identifier used by the processor. */ +#define VMX_BF_BASIC_VMCS_ID_SHIFT 0 +#define VMX_BF_BASIC_VMCS_ID_MASK UINT64_C(0x000000007fffffff) +/** Bit 31 is reserved and RAZ. */ +#define VMX_BF_BASIC_RSVD_32_SHIFT 31 +#define VMX_BF_BASIC_RSVD_32_MASK UINT64_C(0x0000000080000000) +/** VMCS size in bytes. */ +#define VMX_BF_BASIC_VMCS_SIZE_SHIFT 32 +#define VMX_BF_BASIC_VMCS_SIZE_MASK UINT64_C(0x00001fff00000000) +/** Bits 45:47 are reserved. */ +#define VMX_BF_BASIC_RSVD_45_47_SHIFT 45 +#define VMX_BF_BASIC_RSVD_45_47_MASK UINT64_C(0x0000e00000000000) +/** Width of physical addresses used for the VMCS and associated memory regions + * (always 0 on CPUs that support Intel 64 architecture). */ +#define VMX_BF_BASIC_PHYSADDR_WIDTH_SHIFT 48 +#define VMX_BF_BASIC_PHYSADDR_WIDTH_MASK UINT64_C(0x0001000000000000) +/** Dual-monitor treatment of SMI and SMM supported. */ +#define VMX_BF_BASIC_DUAL_MON_SHIFT 49 +#define VMX_BF_BASIC_DUAL_MON_MASK UINT64_C(0x0002000000000000) +/** Memory type that must be used for the VMCS and associated memory regions. */ +#define VMX_BF_BASIC_VMCS_MEM_TYPE_SHIFT 50 +#define VMX_BF_BASIC_VMCS_MEM_TYPE_MASK UINT64_C(0x003c000000000000) +/** VM-exit instruction information for INS/OUTS. */ +#define VMX_BF_BASIC_VMCS_INS_OUTS_SHIFT 54 +#define VMX_BF_BASIC_VMCS_INS_OUTS_MASK UINT64_C(0x0040000000000000) +/** Whether 'true' VMX controls MSRs are supported for handling of default1 class + * bits in VMX control MSRs. */ +#define VMX_BF_BASIC_TRUE_CTLS_SHIFT 55 +#define VMX_BF_BASIC_TRUE_CTLS_MASK UINT64_C(0x0080000000000000) +/** Whether VM-entry can delivery error code for all hardware exception vectors. */ +#define VMX_BF_BASIC_XCPT_ERRCODE_SHIFT 56 +#define VMX_BF_BASIC_XCPT_ERRCODE_MASK UINT64_C(0x0100000000000000) +/** Bits 57:63 are reserved and RAZ. */ +#define VMX_BF_BASIC_RSVD_56_63_SHIFT 57 +#define VMX_BF_BASIC_RSVD_56_63_MASK UINT64_C(0xfe00000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_BASIC_, UINT64_C(0), UINT64_MAX, + (VMCS_ID, RSVD_32, VMCS_SIZE, RSVD_45_47, PHYSADDR_WIDTH, DUAL_MON, VMCS_MEM_TYPE, + VMCS_INS_OUTS, TRUE_CTLS, XCPT_ERRCODE, RSVD_56_63)); +/** @} */ + + +/** @name VMX MSR - Miscellaneous data. + * @{ + */ +/** Whether VM-exit stores EFER.LMA into the "IA32e mode guest" field. */ +#define VMX_MISC_EXIT_SAVE_EFER_LMA RT_BIT(5) +/** Whether Intel PT is supported in VMX operation. */ +#define VMX_MISC_INTEL_PT RT_BIT(14) +/** Whether VMWRITE to any valid VMCS field incl. read-only fields, otherwise + * VMWRITE cannot modify read-only VM-exit information fields. */ +#define VMX_MISC_VMWRITE_ALL RT_BIT(29) +/** Whether VM-entry can inject software interrupts, INT1 (ICEBP) with 0-length + * instructions. */ +#define VMX_MISC_ENTRY_INJECT_SOFT_INT RT_BIT(30) +/** Maximum number of MSRs in the auto-load/store MSR areas, (n+1) * 512. */ +#define VMX_MISC_MAX_MSRS(a_MiscMsr) (512 * (RT_BF_GET((a_MiscMsr), VMX_BF_MISC_MAX_MSRS) + 1)) +/** Maximum CR3-target count supported by the CPU. */ +#define VMX_MISC_CR3_TARGET_COUNT(a_MiscMsr) (((a) >> 16) & 0xff) + +/** Bit fields for MSR_IA32_VMX_MISC. */ +/** Relationship between the preemption timer and tsc. */ +#define VMX_BF_MISC_PREEMPT_TIMER_TSC_SHIFT 0 +#define VMX_BF_MISC_PREEMPT_TIMER_TSC_MASK UINT64_C(0x000000000000001f) +/** Whether VM-exit stores EFER.LMA into the "IA32e mode guest" field. */ +#define VMX_BF_MISC_EXIT_SAVE_EFER_LMA_SHIFT 5 +#define VMX_BF_MISC_EXIT_SAVE_EFER_LMA_MASK UINT64_C(0x0000000000000020) +/** Activity states supported by the implementation. */ +#define VMX_BF_MISC_ACTIVITY_STATES_SHIFT 6 +#define VMX_BF_MISC_ACTIVITY_STATES_MASK UINT64_C(0x00000000000001c0) +/** Bits 9:13 is reserved and RAZ. */ +#define VMX_BF_MISC_RSVD_9_13_SHIFT 9 +#define VMX_BF_MISC_RSVD_9_13_MASK UINT64_C(0x0000000000003e00) +/** Whether Intel PT (Processor Trace) can be used in VMX operation. */ +#define VMX_BF_MISC_INTEL_PT_SHIFT 14 +#define VMX_BF_MISC_INTEL_PT_MASK UINT64_C(0x0000000000004000) +/** Whether RDMSR can be used to read IA32_SMBASE MSR in SMM. */ +#define VMX_BF_MISC_SMM_READ_SMBASE_MSR_SHIFT 15 +#define VMX_BF_MISC_SMM_READ_SMBASE_MSR_MASK UINT64_C(0x0000000000008000) +/** Number of CR3 target values supported by the processor. (0-256) */ +#define VMX_BF_MISC_CR3_TARGET_SHIFT 16 +#define VMX_BF_MISC_CR3_TARGET_MASK UINT64_C(0x0000000001ff0000) +/** Maximum number of MSRs in the VMCS. */ +#define VMX_BF_MISC_MAX_MSRS_SHIFT 25 +#define VMX_BF_MISC_MAX_MSRS_MASK UINT64_C(0x000000000e000000) +/** Whether IA32_SMM_MONITOR_CTL MSR can be modified to allow VMXOFF to block + * SMIs. */ +#define VMX_BF_MISC_VMXOFF_BLOCK_SMI_SHIFT 28 +#define VMX_BF_MISC_VMXOFF_BLOCK_SMI_MASK UINT64_C(0x0000000010000000) +/** Whether VMWRITE to any valid VMCS field incl. read-only fields, otherwise + * VMWRITE cannot modify read-only VM-exit information fields. */ +#define VMX_BF_MISC_VMWRITE_ALL_SHIFT 29 +#define VMX_BF_MISC_VMWRITE_ALL_MASK UINT64_C(0x0000000020000000) +/** Whether VM-entry can inject software interrupts, INT1 (ICEBP) with 0-length + * instructions. */ +#define VMX_BF_MISC_ENTRY_INJECT_SOFT_INT_SHIFT 30 +#define VMX_BF_MISC_ENTRY_INJECT_SOFT_INT_MASK UINT64_C(0x0000000040000000) +/** Bit 31 is reserved and RAZ. */ +#define VMX_BF_MISC_RSVD_31_SHIFT 31 +#define VMX_BF_MISC_RSVD_31_MASK UINT64_C(0x0000000080000000) +/** 32-bit MSEG revision ID used by the processor. */ +#define VMX_BF_MISC_MSEG_ID_SHIFT 32 +#define VMX_BF_MISC_MSEG_ID_MASK UINT64_C(0xffffffff00000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_MISC_, UINT64_C(0), UINT64_MAX, + (PREEMPT_TIMER_TSC, EXIT_SAVE_EFER_LMA, ACTIVITY_STATES, RSVD_9_13, INTEL_PT, SMM_READ_SMBASE_MSR, + CR3_TARGET, MAX_MSRS, VMXOFF_BLOCK_SMI, VMWRITE_ALL, ENTRY_INJECT_SOFT_INT, RSVD_31, MSEG_ID)); +/** @} */ + +/** @name VMX MSR - VMCS enumeration. + * Bit fields for MSR_IA32_VMX_VMCS_ENUM. + * @{ + */ +/** Bit 0 is reserved and RAZ. */ +#define VMX_BF_VMCS_ENUM_RSVD_0_SHIFT 0 +#define VMX_BF_VMCS_ENUM_RSVD_0_MASK UINT64_C(0x0000000000000001) +/** Highest index value used in VMCS field encoding. */ +#define VMX_BF_VMCS_ENUM_HIGHEST_IDX_SHIFT 1 +#define VMX_BF_VMCS_ENUM_HIGHEST_IDX_MASK UINT64_C(0x00000000000003fe) +/** Bit 10:63 is reserved and RAZ. */ +#define VMX_BF_VMCS_ENUM_RSVD_10_63_SHIFT 10 +#define VMX_BF_VMCS_ENUM_RSVD_10_63_MASK UINT64_C(0xfffffffffffffc00) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_VMCS_ENUM_, UINT64_C(0), UINT64_MAX, + (RSVD_0, HIGHEST_IDX, RSVD_10_63)); +/** @} */ + + +/** @name VMX MSR - VM Functions. + * Bit fields for MSR_IA32_VMX_VMFUNC. + * @{ + */ +/** EPTP-switching function changes the value of the EPTP to one chosen from the EPTP list. */ +#define VMX_BF_VMFUNC_EPTP_SWITCHING_SHIFT 0 +#define VMX_BF_VMFUNC_EPTP_SWITCHING_MASK UINT64_C(0x0000000000000001) +/** Bits 1:63 are reserved and RAZ. */ +#define VMX_BF_VMFUNC_RSVD_1_63_SHIFT 1 +#define VMX_BF_VMFUNC_RSVD_1_63_MASK UINT64_C(0xfffffffffffffffe) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_VMFUNC_, UINT64_C(0), UINT64_MAX, + (EPTP_SWITCHING, RSVD_1_63)); +/** @} */ + + +/** @name VMX MSR - EPT/VPID capabilities. + * @{ + */ +/** Supports execute-only translations by EPT. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_RWX_X_ONLY RT_BIT_64(0) +/** Supports page-walk length of 4. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_PAGE_WALK_LENGTH_4 RT_BIT_64(6) +/** Supports page-walk length of 5. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_PAGE_WALK_LENGTH_5 RT_BIT_64(7) +/** Supports EPT paging-structure memory type to be uncacheable. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_MEMTYPE_UC RT_BIT_64(8) +/** Supports EPT paging structure memory type to be write-back. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_MEMTYPE_WB RT_BIT_64(14) +/** Supports EPT PDE to map a 2 MB page. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_PDE_2M RT_BIT_64(16) +/** Supports EPT PDPTE to map a 1 GB page. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_PDPTE_1G RT_BIT_64(17) +/** Supports INVEPT instruction. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_INVEPT RT_BIT_64(20) +/** Supports accessed and dirty flags for EPT. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_ACCESS_DIRTY RT_BIT_64(21) +/** Supports advanced VM-exit info. for EPT violations. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_ADVEXITINFO_EPT_VIOLATION RT_BIT_64(22) +/** Supports supervisor shadow-stack control. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_SUPER_SHW_STACK RT_BIT_64(23) +/** Supports single-context INVEPT type. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_INVEPT_SINGLE_CONTEXT RT_BIT_64(25) +/** Supports all-context INVEPT type. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_INVEPT_ALL_CONTEXTS RT_BIT_64(26) +/** Supports INVVPID instruction. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_INVVPID RT_BIT_64(32) +/** Supports individual-address INVVPID type. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_INDIV_ADDR RT_BIT_64(40) +/** Supports single-context INVVPID type. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_SINGLE_CONTEXT RT_BIT_64(41) +/** Supports all-context INVVPID type. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_ALL_CONTEXTS RT_BIT_64(42) +/** Supports singe-context-retaining-globals INVVPID type. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_SINGLE_CONTEXT_RETAIN_GLOBALS RT_BIT_64(43) + +/** Bit fields for MSR_IA32_VMX_EPT_VPID_CAP. */ +#define VMX_BF_EPT_VPID_CAP_EXEC_ONLY_SHIFT 0 +#define VMX_BF_EPT_VPID_CAP_EXEC_ONLY_MASK UINT64_C(0x0000000000000001) +#define VMX_BF_EPT_VPID_CAP_RSVD_1_5_SHIFT 1 +#define VMX_BF_EPT_VPID_CAP_RSVD_1_5_MASK UINT64_C(0x000000000000003e) +#define VMX_BF_EPT_VPID_CAP_PAGE_WALK_LENGTH_4_SHIFT 6 +#define VMX_BF_EPT_VPID_CAP_PAGE_WALK_LENGTH_4_MASK UINT64_C(0x0000000000000040) +#define VMX_BF_EPT_VPID_CAP_RSVD_7_SHIFT 7 +#define VMX_BF_EPT_VPID_CAP_RSVD_7_MASK UINT64_C(0x0000000000000080) +#define VMX_BF_EPT_VPID_CAP_MEMTYPE_UC_SHIFT 8 +#define VMX_BF_EPT_VPID_CAP_MEMTYPE_UC_MASK UINT64_C(0x0000000000000100) +#define VMX_BF_EPT_VPID_CAP_RSVD_9_13_SHIFT 9 +#define VMX_BF_EPT_VPID_CAP_RSVD_9_13_MASK UINT64_C(0x0000000000003e00) +#define VMX_BF_EPT_VPID_CAP_MEMTYPE_WB_SHIFT 14 +#define VMX_BF_EPT_VPID_CAP_MEMTYPE_WB_MASK UINT64_C(0x0000000000004000) +#define VMX_BF_EPT_VPID_CAP_RSVD_15_SHIFT 15 +#define VMX_BF_EPT_VPID_CAP_RSVD_15_MASK UINT64_C(0x0000000000008000) +#define VMX_BF_EPT_VPID_CAP_PDE_2M_SHIFT 16 +#define VMX_BF_EPT_VPID_CAP_PDE_2M_MASK UINT64_C(0x0000000000010000) +#define VMX_BF_EPT_VPID_CAP_PDPTE_1G_SHIFT 17 +#define VMX_BF_EPT_VPID_CAP_PDPTE_1G_MASK UINT64_C(0x0000000000020000) +#define VMX_BF_EPT_VPID_CAP_RSVD_18_19_SHIFT 18 +#define VMX_BF_EPT_VPID_CAP_RSVD_18_19_MASK UINT64_C(0x00000000000c0000) +#define VMX_BF_EPT_VPID_CAP_INVEPT_SHIFT 20 +#define VMX_BF_EPT_VPID_CAP_INVEPT_MASK UINT64_C(0x0000000000100000) +#define VMX_BF_EPT_VPID_CAP_ACCESS_DIRTY_SHIFT 21 +#define VMX_BF_EPT_VPID_CAP_ACCESS_DIRTY_MASK UINT64_C(0x0000000000200000) +#define VMX_BF_EPT_VPID_CAP_ADVEXITINFO_EPT_VIOLATION_SHIFT 22 +#define VMX_BF_EPT_VPID_CAP_ADVEXITINFO_EPT_VIOLATION_MASK UINT64_C(0x0000000000400000) +#define VMX_BF_EPT_VPID_CAP_SUPER_SHW_STACK_SHIFT 23 +#define VMX_BF_EPT_VPID_CAP_SUPER_SHW_STACK_MASK UINT64_C(0x0000000000800000) +#define VMX_BF_EPT_VPID_CAP_RSVD_24_SHIFT 24 +#define VMX_BF_EPT_VPID_CAP_RSVD_24_MASK UINT64_C(0x0000000001000000) +#define VMX_BF_EPT_VPID_CAP_INVEPT_SINGLE_CTX_SHIFT 25 +#define VMX_BF_EPT_VPID_CAP_INVEPT_SINGLE_CTX_MASK UINT64_C(0x0000000002000000) +#define VMX_BF_EPT_VPID_CAP_INVEPT_ALL_CTX_SHIFT 26 +#define VMX_BF_EPT_VPID_CAP_INVEPT_ALL_CTX_MASK UINT64_C(0x0000000004000000) +#define VMX_BF_EPT_VPID_CAP_RSVD_27_31_SHIFT 27 +#define VMX_BF_EPT_VPID_CAP_RSVD_27_31_MASK UINT64_C(0x00000000f8000000) +#define VMX_BF_EPT_VPID_CAP_INVVPID_SHIFT 32 +#define VMX_BF_EPT_VPID_CAP_INVVPID_MASK UINT64_C(0x0000000100000000) +#define VMX_BF_EPT_VPID_CAP_RSVD_33_39_SHIFT 33 +#define VMX_BF_EPT_VPID_CAP_RSVD_33_39_MASK UINT64_C(0x000000fe00000000) +#define VMX_BF_EPT_VPID_CAP_INVVPID_INDIV_ADDR_SHIFT 40 +#define VMX_BF_EPT_VPID_CAP_INVVPID_INDIV_ADDR_MASK UINT64_C(0x0000010000000000) +#define VMX_BF_EPT_VPID_CAP_INVVPID_SINGLE_CTX_SHIFT 41 +#define VMX_BF_EPT_VPID_CAP_INVVPID_SINGLE_CTX_MASK UINT64_C(0x0000020000000000) +#define VMX_BF_EPT_VPID_CAP_INVVPID_ALL_CTX_SHIFT 42 +#define VMX_BF_EPT_VPID_CAP_INVVPID_ALL_CTX_MASK UINT64_C(0x0000040000000000) +#define VMX_BF_EPT_VPID_CAP_INVVPID_SINGLE_CTX_RETAIN_GLOBALS_SHIFT 43 +#define VMX_BF_EPT_VPID_CAP_INVVPID_SINGLE_CTX_RETAIN_GLOBALS_MASK UINT64_C(0x0000080000000000) +#define VMX_BF_EPT_VPID_CAP_RSVD_44_63_SHIFT 44 +#define VMX_BF_EPT_VPID_CAP_RSVD_44_63_MASK UINT64_C(0xfffff00000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_EPT_VPID_CAP_, UINT64_C(0), UINT64_MAX, + (EXEC_ONLY, RSVD_1_5, PAGE_WALK_LENGTH_4, RSVD_7, MEMTYPE_UC, RSVD_9_13, MEMTYPE_WB, RSVD_15, PDE_2M, + PDPTE_1G, RSVD_18_19, INVEPT, ACCESS_DIRTY, ADVEXITINFO_EPT_VIOLATION, SUPER_SHW_STACK, RSVD_24, + INVEPT_SINGLE_CTX, INVEPT_ALL_CTX, RSVD_27_31, INVVPID, RSVD_33_39, INVVPID_INDIV_ADDR, + INVVPID_SINGLE_CTX, INVVPID_ALL_CTX, INVVPID_SINGLE_CTX_RETAIN_GLOBALS, RSVD_44_63)); +/** @} */ + + +/** @name Extended Page Table Pointer (EPTP) + * In accordance with the VT-x spec. + * See Intel spec. 23.6.11 "Extended-Page-Table Pointer (EPTP)". + * @{ + */ +/** EPTP memory type: Uncachable. */ +#define VMX_EPTP_MEMTYPE_UC 0 +/** EPTP memory type: Write Back. */ +#define VMX_EPTP_MEMTYPE_WB 6 +/** Page-walk length for PML4 (4-level paging). */ +#define VMX_EPTP_PAGE_WALK_LENGTH_4 3 + +/** Bit fields for EPTP. */ +#define VMX_BF_EPTP_MEMTYPE_SHIFT 0 +#define VMX_BF_EPTP_MEMTYPE_MASK UINT64_C(0x0000000000000007) +#define VMX_BF_EPTP_PAGE_WALK_LENGTH_SHIFT 3 +#define VMX_BF_EPTP_PAGE_WALK_LENGTH_MASK UINT64_C(0x0000000000000038) +#define VMX_BF_EPTP_ACCESS_DIRTY_SHIFT 6 +#define VMX_BF_EPTP_ACCESS_DIRTY_MASK UINT64_C(0x0000000000000040) +#define VMX_BF_EPTP_SUPER_SHW_STACK_SHIFT 7 +#define VMX_BF_EPTP_SUPER_SHW_STACK_MASK UINT64_C(0x0000000000000080) +#define VMX_BF_EPTP_RSVD_8_11_SHIFT 8 +#define VMX_BF_EPTP_RSVD_8_11_MASK UINT64_C(0x0000000000000f00) +#define VMX_BF_EPTP_PML4_TABLE_ADDR_SHIFT 12 +#define VMX_BF_EPTP_PML4_TABLE_ADDR_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_EPTP_, UINT64_C(0), UINT64_MAX, + (MEMTYPE, PAGE_WALK_LENGTH, ACCESS_DIRTY, SUPER_SHW_STACK, RSVD_8_11, PML4_TABLE_ADDR)); + +/* Mask of valid EPTP bits sans physically non-addressable bits. */ +#define VMX_EPTP_VALID_MASK ( VMX_BF_EPTP_MEMTYPE_MASK \ + | VMX_BF_EPTP_PAGE_WALK_LENGTH_MASK \ + | VMX_BF_EPTP_ACCESS_DIRTY_MASK \ + | VMX_BF_EPTP_SUPER_SHW_STACK_MASK \ + | VMX_BF_EPTP_PML4_TABLE_ADDR_MASK) +/** @} */ + + +/** @name VMCS fields and encoding. + * + * When adding a new field: + * - Always add it to g_aVmcsFields. + * - Consider if it needs to be added to VMXVVMCS. + * @{ + */ +/** 16-bit control fields. */ +#define VMX_VMCS16_VPID 0x0000 +#define VMX_VMCS16_POSTED_INT_NOTIFY_VECTOR 0x0002 +#define VMX_VMCS16_EPTP_INDEX 0x0004 +#define VMX_VMCS16_HLAT_PREFIX_SIZE 0x0006 + +/** 16-bit guest-state fields. */ +#define VMX_VMCS16_GUEST_ES_SEL 0x0800 +#define VMX_VMCS16_GUEST_CS_SEL 0x0802 +#define VMX_VMCS16_GUEST_SS_SEL 0x0804 +#define VMX_VMCS16_GUEST_DS_SEL 0x0806 +#define VMX_VMCS16_GUEST_FS_SEL 0x0808 +#define VMX_VMCS16_GUEST_GS_SEL 0x080a +#define VMX_VMCS16_GUEST_LDTR_SEL 0x080c +#define VMX_VMCS16_GUEST_TR_SEL 0x080e +#define VMX_VMCS16_GUEST_INTR_STATUS 0x0810 +#define VMX_VMCS16_GUEST_PML_INDEX 0x0812 + +/** 16-bits host-state fields. */ +#define VMX_VMCS16_HOST_ES_SEL 0x0c00 +#define VMX_VMCS16_HOST_CS_SEL 0x0c02 +#define VMX_VMCS16_HOST_SS_SEL 0x0c04 +#define VMX_VMCS16_HOST_DS_SEL 0x0c06 +#define VMX_VMCS16_HOST_FS_SEL 0x0c08 +#define VMX_VMCS16_HOST_GS_SEL 0x0c0a +#define VMX_VMCS16_HOST_TR_SEL 0x0c0c + +/** 64-bit control fields. */ +#define VMX_VMCS64_CTRL_IO_BITMAP_A_FULL 0x2000 +#define VMX_VMCS64_CTRL_IO_BITMAP_A_HIGH 0x2001 +#define VMX_VMCS64_CTRL_IO_BITMAP_B_FULL 0x2002 +#define VMX_VMCS64_CTRL_IO_BITMAP_B_HIGH 0x2003 +#define VMX_VMCS64_CTRL_MSR_BITMAP_FULL 0x2004 +#define VMX_VMCS64_CTRL_MSR_BITMAP_HIGH 0x2005 +#define VMX_VMCS64_CTRL_EXIT_MSR_STORE_FULL 0x2006 +#define VMX_VMCS64_CTRL_EXIT_MSR_STORE_HIGH 0x2007 +#define VMX_VMCS64_CTRL_EXIT_MSR_LOAD_FULL 0x2008 +#define VMX_VMCS64_CTRL_EXIT_MSR_LOAD_HIGH 0x2009 +#define VMX_VMCS64_CTRL_ENTRY_MSR_LOAD_FULL 0x200a +#define VMX_VMCS64_CTRL_ENTRY_MSR_LOAD_HIGH 0x200b +#define VMX_VMCS64_CTRL_EXEC_VMCS_PTR_FULL 0x200c +#define VMX_VMCS64_CTRL_EXEC_VMCS_PTR_HIGH 0x200d +#define VMX_VMCS64_CTRL_EXEC_PML_ADDR_FULL 0x200e +#define VMX_VMCS64_CTRL_EXEC_PML_ADDR_HIGH 0x200f +#define VMX_VMCS64_CTRL_TSC_OFFSET_FULL 0x2010 +#define VMX_VMCS64_CTRL_TSC_OFFSET_HIGH 0x2011 +#define VMX_VMCS64_CTRL_VIRT_APIC_PAGEADDR_FULL 0x2012 +#define VMX_VMCS64_CTRL_VIRT_APIC_PAGEADDR_HIGH 0x2013 +#define VMX_VMCS64_CTRL_APIC_ACCESSADDR_FULL 0x2014 +#define VMX_VMCS64_CTRL_APIC_ACCESSADDR_HIGH 0x2015 +#define VMX_VMCS64_CTRL_POSTED_INTR_DESC_FULL 0x2016 +#define VMX_VMCS64_CTRL_POSTED_INTR_DESC_HIGH 0x2017 +#define VMX_VMCS64_CTRL_VMFUNC_CTRLS_FULL 0x2018 +#define VMX_VMCS64_CTRL_VMFUNC_CTRLS_HIGH 0x2019 +#define VMX_VMCS64_CTRL_EPTP_FULL 0x201a +#define VMX_VMCS64_CTRL_EPTP_HIGH 0x201b +#define VMX_VMCS64_CTRL_EOI_BITMAP_0_FULL 0x201c +#define VMX_VMCS64_CTRL_EOI_BITMAP_0_HIGH 0x201d +#define VMX_VMCS64_CTRL_EOI_BITMAP_1_FULL 0x201e +#define VMX_VMCS64_CTRL_EOI_BITMAP_1_HIGH 0x201f +#define VMX_VMCS64_CTRL_EOI_BITMAP_2_FULL 0x2020 +#define VMX_VMCS64_CTRL_EOI_BITMAP_2_HIGH 0x2021 +#define VMX_VMCS64_CTRL_EOI_BITMAP_3_FULL 0x2022 +#define VMX_VMCS64_CTRL_EOI_BITMAP_3_HIGH 0x2023 +#define VMX_VMCS64_CTRL_EPTP_LIST_FULL 0x2024 +#define VMX_VMCS64_CTRL_EPTP_LIST_HIGH 0x2025 +#define VMX_VMCS64_CTRL_VMREAD_BITMAP_FULL 0x2026 +#define VMX_VMCS64_CTRL_VMREAD_BITMAP_HIGH 0x2027 +#define VMX_VMCS64_CTRL_VMWRITE_BITMAP_FULL 0x2028 +#define VMX_VMCS64_CTRL_VMWRITE_BITMAP_HIGH 0x2029 +#define VMX_VMCS64_CTRL_VE_XCPT_INFO_ADDR_FULL 0x202a +#define VMX_VMCS64_CTRL_VE_XCPT_INFO_ADDR_HIGH 0x202b +#define VMX_VMCS64_CTRL_XSS_EXITING_BITMAP_FULL 0x202c +#define VMX_VMCS64_CTRL_XSS_EXITING_BITMAP_HIGH 0x202d +#define VMX_VMCS64_CTRL_ENCLS_EXITING_BITMAP_FULL 0x202e +#define VMX_VMCS64_CTRL_ENCLS_EXITING_BITMAP_HIGH 0x202f +#define VMX_VMCS64_CTRL_SPPTP_FULL 0x2030 +#define VMX_VMCS64_CTRL_SPPTP_HIGH 0x2031 +#define VMX_VMCS64_CTRL_TSC_MULTIPLIER_FULL 0x2032 +#define VMX_VMCS64_CTRL_TSC_MULTIPLIER_HIGH 0x2033 +#define VMX_VMCS64_CTRL_PROC_EXEC3_FULL 0x2034 +#define VMX_VMCS64_CTRL_PROC_EXEC3_HIGH 0x2035 +#define VMX_VMCS64_CTRL_ENCLV_EXITING_BITMAP_FULL 0x2036 +#define VMX_VMCS64_CTRL_ENCLV_EXITING_BITMAP_HIGH 0x2037 +#define VMX_VMCS64_CTRL_PCONFIG_EXITING_BITMAP_FULL 0x203e +#define VMX_VMCS64_CTRL_PCONFIG_EXITING_BITMAP_HIGH 0x203f +#define VMX_VMCS64_CTRL_HLAT_PTR_FULL 0x2040 +#define VMX_VMCS64_CTRL_HLAT_PTR_HIGH 0x2041 +#define VMX_VMCS64_CTRL_EXIT2_FULL 0x2044 +#define VMX_VMCS64_CTRL_EXIT2_HIGH 0x2045 + +/** 64-bit read-only data fields. */ +#define VMX_VMCS64_RO_GUEST_PHYS_ADDR_FULL 0x2400 +#define VMX_VMCS64_RO_GUEST_PHYS_ADDR_HIGH 0x2401 + +/** 64-bit guest-state fields. */ +#define VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL 0x2800 +#define VMX_VMCS64_GUEST_VMCS_LINK_PTR_HIGH 0x2801 +#define VMX_VMCS64_GUEST_DEBUGCTL_FULL 0x2802 +#define VMX_VMCS64_GUEST_DEBUGCTL_HIGH 0x2803 +#define VMX_VMCS64_GUEST_PAT_FULL 0x2804 +#define VMX_VMCS64_GUEST_PAT_HIGH 0x2805 +#define VMX_VMCS64_GUEST_EFER_FULL 0x2806 +#define VMX_VMCS64_GUEST_EFER_HIGH 0x2807 +#define VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_FULL 0x2808 +#define VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_HIGH 0x2809 +#define VMX_VMCS64_GUEST_PDPTE0_FULL 0x280a +#define VMX_VMCS64_GUEST_PDPTE0_HIGH 0x280b +#define VMX_VMCS64_GUEST_PDPTE1_FULL 0x280c +#define VMX_VMCS64_GUEST_PDPTE1_HIGH 0x280d +#define VMX_VMCS64_GUEST_PDPTE2_FULL 0x280e +#define VMX_VMCS64_GUEST_PDPTE2_HIGH 0x280f +#define VMX_VMCS64_GUEST_PDPTE3_FULL 0x2810 +#define VMX_VMCS64_GUEST_PDPTE3_HIGH 0x2811 +#define VMX_VMCS64_GUEST_BNDCFGS_FULL 0x2812 +#define VMX_VMCS64_GUEST_BNDCFGS_HIGH 0x2813 +#define VMX_VMCS64_GUEST_RTIT_CTL_FULL 0x2814 +#define VMX_VMCS64_GUEST_RTIT_CTL_HIGH 0x2815 +#define VMX_VMCS64_GUEST_PKRS_FULL 0x2818 +#define VMX_VMCS64_GUEST_PKRS_HIGH 0x2819 + +/** 64-bit host-state fields. */ +#define VMX_VMCS64_HOST_PAT_FULL 0x2c00 +#define VMX_VMCS64_HOST_PAT_HIGH 0x2c01 +#define VMX_VMCS64_HOST_EFER_FULL 0x2c02 +#define VMX_VMCS64_HOST_EFER_HIGH 0x2c03 +#define VMX_VMCS64_HOST_PERF_GLOBAL_CTRL_FULL 0x2c04 +#define VMX_VMCS64_HOST_PERF_GLOBAL_CTRL_HIGH 0x2c05 +#define VMX_VMCS64_HOST_PKRS_FULL 0x2c06 +#define VMX_VMCS64_HOST_PKRS_HIGH 0x2c07 + +/** 32-bit control fields. */ +#define VMX_VMCS32_CTRL_PIN_EXEC 0x4000 +#define VMX_VMCS32_CTRL_PROC_EXEC 0x4002 +#define VMX_VMCS32_CTRL_EXCEPTION_BITMAP 0x4004 +#define VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK 0x4006 +#define VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH 0x4008 +#define VMX_VMCS32_CTRL_CR3_TARGET_COUNT 0x400a +#define VMX_VMCS32_CTRL_EXIT 0x400c +#define VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT 0x400e +#define VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT 0x4010 +#define VMX_VMCS32_CTRL_ENTRY 0x4012 +#define VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT 0x4014 +#define VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO 0x4016 +#define VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE 0x4018 +#define VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH 0x401a +#define VMX_VMCS32_CTRL_TPR_THRESHOLD 0x401c +#define VMX_VMCS32_CTRL_PROC_EXEC2 0x401e +#define VMX_VMCS32_CTRL_PLE_GAP 0x4020 +#define VMX_VMCS32_CTRL_PLE_WINDOW 0x4022 + +/** 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_ERROR_CODE 0x4406 +#define VMX_VMCS32_RO_IDT_VECTORING_INFO 0x4408 +#define VMX_VMCS32_RO_IDT_VECTORING_ERROR_CODE 0x440a +#define VMX_VMCS32_RO_EXIT_INSTR_LENGTH 0x440c +#define VMX_VMCS32_RO_EXIT_INSTR_INFO 0x440e + +/** 32-bit 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_INT_STATE 0x4824 +#define VMX_VMCS32_GUEST_ACTIVITY_STATE 0x4826 +#define VMX_VMCS32_GUEST_SMBASE 0x4828 +#define VMX_VMCS32_GUEST_SYSENTER_CS 0x482a +#define VMX_VMCS32_PREEMPT_TIMER_VALUE 0x482e + +/** 32-bit host-state fields. */ +#define VMX_VMCS32_HOST_SYSENTER_CS 0x4C00 + +/** 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_VAL3 0x600e + +/** 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_RSI 0x6404 +#define VMX_VMCS_RO_IO_RDI 0x6406 +#define VMX_VMCS_RO_IO_RIP 0x6408 +#define VMX_VMCS_RO_GUEST_LINEAR_ADDR 0x640a + +/** Natural-width guest-state fields. */ +#define VMX_VMCS_GUEST_CR0 0x6800 +#define VMX_VMCS_GUEST_CR3 0x6802 +#define VMX_VMCS_GUEST_CR4 0x6804 +#define VMX_VMCS_GUEST_ES_BASE 0x6806 +#define VMX_VMCS_GUEST_CS_BASE 0x6808 +#define VMX_VMCS_GUEST_SS_BASE 0x680a +#define VMX_VMCS_GUEST_DS_BASE 0x680c +#define VMX_VMCS_GUEST_FS_BASE 0x680e +#define VMX_VMCS_GUEST_GS_BASE 0x6810 +#define VMX_VMCS_GUEST_LDTR_BASE 0x6812 +#define VMX_VMCS_GUEST_TR_BASE 0x6814 +#define VMX_VMCS_GUEST_GDTR_BASE 0x6816 +#define VMX_VMCS_GUEST_IDTR_BASE 0x6818 +#define VMX_VMCS_GUEST_DR7 0x681a +#define VMX_VMCS_GUEST_RSP 0x681c +#define VMX_VMCS_GUEST_RIP 0x681e +#define VMX_VMCS_GUEST_RFLAGS 0x6820 +#define VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS 0x6822 +#define VMX_VMCS_GUEST_SYSENTER_ESP 0x6824 +#define VMX_VMCS_GUEST_SYSENTER_EIP 0x6826 +#define VMX_VMCS_GUEST_S_CET 0x6828 +#define VMX_VMCS_GUEST_SSP 0x682a +#define VMX_VMCS_GUEST_INTR_SSP_TABLE_ADDR 0x682c + +/** 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 +#define VMX_VMCS_HOST_S_CET 0x6c18 +#define VMX_VMCS_HOST_SSP 0x6c1a +#define VMX_VMCS_HOST_INTR_SSP_TABLE_ADDR 0x6c1c + +#define VMX_VMCS16_GUEST_SEG_SEL(a_iSegReg) (VMX_VMCS16_GUEST_ES_SEL + (a_iSegReg) * 2) +#define VMX_VMCS_GUEST_SEG_BASE(a_iSegReg) (VMX_VMCS_GUEST_ES_BASE + (a_iSegReg) * 2) +#define VMX_VMCS32_GUEST_SEG_LIMIT(a_iSegReg) (VMX_VMCS32_GUEST_ES_LIMIT + (a_iSegReg) * 2) +#define VMX_VMCS32_GUEST_SEG_ACCESS_RIGHTS(a_iSegReg) (VMX_VMCS32_GUEST_ES_ACCESS_RIGHTS + (a_iSegReg) * 2) + +/** + * VMCS field. + * In accordance with the VT-x spec. + */ +typedef union +{ + struct + { + /** The access type; 0=full, 1=high of 64-bit fields. */ + uint32_t fAccessType : 1; + /** The index. */ + uint32_t u8Index : 8; + /** The type; 0=control, 1=VM-exit info, 2=guest-state, 3=host-state. */ + uint32_t u2Type : 2; + /** Reserved (MBZ). */ + uint32_t u1Reserved0 : 1; + /** The width; 0=16-bit, 1=64-bit, 2=32-bit, 3=natural-width. */ + uint32_t u2Width : 2; + /** Reserved (MBZ). */ + uint32_t u18Reserved0 : 18; + } n; + + /* The unsigned integer view. */ + uint32_t u; +} VMXVMCSFIELD; +AssertCompileSize(VMXVMCSFIELD, 4); +/** Pointer to a VMCS field. */ +typedef VMXVMCSFIELD *PVMXVMCSFIELD; +/** Pointer to a const VMCS field. */ +typedef const VMXVMCSFIELD *PCVMXVMCSFIELD; + +/** VMCS field: Mask of reserved bits (bits 63:15 MBZ), bit 12 is not included! */ +#define VMX_VMCSFIELD_RSVD_MASK UINT64_C(0xffffffffffff8000) + +/** Bits fields for a VMCS field. */ +#define VMX_BF_VMCSFIELD_ACCESS_TYPE_SHIFT 0 +#define VMX_BF_VMCSFIELD_ACCESS_TYPE_MASK UINT32_C(0x00000001) +#define VMX_BF_VMCSFIELD_INDEX_SHIFT 1 +#define VMX_BF_VMCSFIELD_INDEX_MASK UINT32_C(0x000003fe) +#define VMX_BF_VMCSFIELD_TYPE_SHIFT 10 +#define VMX_BF_VMCSFIELD_TYPE_MASK UINT32_C(0x00000c00) +#define VMX_BF_VMCSFIELD_RSVD_12_SHIFT 12 +#define VMX_BF_VMCSFIELD_RSVD_12_MASK UINT32_C(0x00001000) +#define VMX_BF_VMCSFIELD_WIDTH_SHIFT 13 +#define VMX_BF_VMCSFIELD_WIDTH_MASK UINT32_C(0x00006000) +#define VMX_BF_VMCSFIELD_RSVD_15_31_SHIFT 15 +#define VMX_BF_VMCSFIELD_RSVD_15_31_MASK UINT32_C(0xffff8000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_VMCSFIELD_, UINT32_C(0), UINT32_MAX, + (ACCESS_TYPE, INDEX, TYPE, RSVD_12, WIDTH, RSVD_15_31)); + +/** + * VMCS field encoding: Access type. + * In accordance with the VT-x spec. + */ +typedef enum +{ + VMXVMCSFIELDACCESS_FULL = 0, + VMXVMCSFIELDACCESS_HIGH +} VMXVMCSFIELDACCESS; +AssertCompileSize(VMXVMCSFIELDACCESS, 4); +/** VMCS field encoding type: Full. */ +#define VMX_VMCSFIELD_ACCESS_FULL 0 +/** VMCS field encoding type: High. */ +#define VMX_VMCSFIELD_ACCESS_HIGH 1 + +/** + * VMCS field encoding: Type. + * In accordance with the VT-x spec. + */ +typedef enum +{ + VMXVMCSFIELDTYPE_CONTROL = 0, + VMXVMCSFIELDTYPE_VMEXIT_INFO, + VMXVMCSFIELDTYPE_GUEST_STATE, + VMXVMCSFIELDTYPE_HOST_STATE +} VMXVMCSFIELDTYPE; +AssertCompileSize(VMXVMCSFIELDTYPE, 4); +/** VMCS field encoding type: Control. */ +#define VMX_VMCSFIELD_TYPE_CONTROL 0 +/** VMCS field encoding type: VM-exit information / read-only fields. */ +#define VMX_VMCSFIELD_TYPE_VMEXIT_INFO 1 +/** VMCS field encoding type: Guest-state. */ +#define VMX_VMCSFIELD_TYPE_GUEST_STATE 2 +/** VMCS field encoding type: Host-state. */ +#define VMX_VMCSFIELD_TYPE_HOST_STATE 3 + +/** + * VMCS field encoding: Width. + * In accordance with the VT-x spec. + */ +typedef enum +{ + VMXVMCSFIELDWIDTH_16BIT = 0, + VMXVMCSFIELDWIDTH_64BIT, + VMXVMCSFIELDWIDTH_32BIT, + VMXVMCSFIELDWIDTH_NATURAL +} VMXVMCSFIELDWIDTH; +AssertCompileSize(VMXVMCSFIELDWIDTH, 4); +/** VMCS field encoding width: 16-bit. */ +#define VMX_VMCSFIELD_WIDTH_16BIT 0 +/** VMCS field encoding width: 64-bit. */ +#define VMX_VMCSFIELD_WIDTH_64BIT 1 +/** VMCS field encoding width: 32-bit. */ +#define VMX_VMCSFIELD_WIDTH_32BIT 2 +/** VMCS field encoding width: Natural width. */ +#define VMX_VMCSFIELD_WIDTH_NATURAL 3 +/** @} */ + + +/** @name VM-entry instruction length. + * @{ */ +/** The maximum valid value for VM-entry instruction length while injecting a + * software interrupt, software exception or privileged software exception. */ +#define VMX_ENTRY_INSTR_LEN_MAX 15 +/** @} */ + + +/** @name VM-entry register masks. + * @{ */ +/** CR0 bits ignored on VM-entry while loading guest CR0 (ET, CD, NW, bits 6:15, + * bit 17 and bits 19:28). */ +#define VMX_ENTRY_GUEST_CR0_IGNORE_MASK UINT64_C(0x7ffaffd0) +/** DR7 bits set here are always cleared on VM-entry while loading guest DR7 (bit + * 12, bits 14:15). */ +#define VMX_ENTRY_GUEST_DR7_MBZ_MASK UINT64_C(0xd000) +/** DR7 bits set here are always set on VM-entry while loading guest DR7 (bit + * 10). */ +#define VMX_ENTRY_GUEST_DR7_MB1_MASK UINT64_C(0x400) +/** @} */ + + +/** @name VM-exit register masks. + * @{ */ +/** CR0 bits ignored on VM-exit while loading host CR0 (ET, CD, NW, bits 6:15, + * bit 17, bits 19:28 and bits 32:63). */ +#define VMX_EXIT_HOST_CR0_IGNORE_MASK UINT64_C(0xffffffff7ffaffd0) +/** @} */ + + +/** @name Pin-based VM-execution controls. + * @{ + */ +/** External interrupt exiting. */ +#define VMX_PIN_CTLS_EXT_INT_EXIT RT_BIT(0) +/** NMI exiting. */ +#define VMX_PIN_CTLS_NMI_EXIT RT_BIT(3) +/** Virtual NMIs. */ +#define VMX_PIN_CTLS_VIRT_NMI RT_BIT(5) +/** Activate VMX preemption timer. */ +#define VMX_PIN_CTLS_PREEMPT_TIMER RT_BIT(6) +/** Process interrupts with the posted-interrupt notification vector. */ +#define VMX_PIN_CTLS_POSTED_INT RT_BIT(7) +/** Default1 class when true capability MSRs are not supported. */ +#define VMX_PIN_CTLS_DEFAULT1 UINT32_C(0x00000016) + +/** Bit fields for MSR_IA32_VMX_PINBASED_CTLS and Pin-based VM-execution + * controls field in the VMCS. */ +#define VMX_BF_PIN_CTLS_EXT_INT_EXIT_SHIFT 0 +#define VMX_BF_PIN_CTLS_EXT_INT_EXIT_MASK UINT32_C(0x00000001) +#define VMX_BF_PIN_CTLS_RSVD_1_2_SHIFT 1 +#define VMX_BF_PIN_CTLS_RSVD_1_2_MASK UINT32_C(0x00000006) +#define VMX_BF_PIN_CTLS_NMI_EXIT_SHIFT 3 +#define VMX_BF_PIN_CTLS_NMI_EXIT_MASK UINT32_C(0x00000008) +#define VMX_BF_PIN_CTLS_RSVD_4_SHIFT 4 +#define VMX_BF_PIN_CTLS_RSVD_4_MASK UINT32_C(0x00000010) +#define VMX_BF_PIN_CTLS_VIRT_NMI_SHIFT 5 +#define VMX_BF_PIN_CTLS_VIRT_NMI_MASK UINT32_C(0x00000020) +#define VMX_BF_PIN_CTLS_PREEMPT_TIMER_SHIFT 6 +#define VMX_BF_PIN_CTLS_PREEMPT_TIMER_MASK UINT32_C(0x00000040) +#define VMX_BF_PIN_CTLS_POSTED_INT_SHIFT 7 +#define VMX_BF_PIN_CTLS_POSTED_INT_MASK UINT32_C(0x00000080) +#define VMX_BF_PIN_CTLS_RSVD_8_31_SHIFT 8 +#define VMX_BF_PIN_CTLS_RSVD_8_31_MASK UINT32_C(0xffffff00) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_PIN_CTLS_, UINT32_C(0), UINT32_MAX, + (EXT_INT_EXIT, RSVD_1_2, NMI_EXIT, RSVD_4, VIRT_NMI, PREEMPT_TIMER, POSTED_INT, RSVD_8_31)); +/** @} */ + + +/** @name Processor-based VM-execution controls. + * @{ + */ +/** VM-exit as soon as RFLAGS.IF=1 and no blocking is active. */ +#define VMX_PROC_CTLS_INT_WINDOW_EXIT RT_BIT(2) +/** Use timestamp counter offset. */ +#define VMX_PROC_CTLS_USE_TSC_OFFSETTING RT_BIT(3) +/** VM-exit when executing the HLT instruction. */ +#define VMX_PROC_CTLS_HLT_EXIT RT_BIT(7) +/** VM-exit when executing the INVLPG instruction. */ +#define VMX_PROC_CTLS_INVLPG_EXIT RT_BIT(9) +/** VM-exit when executing the MWAIT instruction. */ +#define VMX_PROC_CTLS_MWAIT_EXIT RT_BIT(10) +/** VM-exit when executing the RDPMC instruction. */ +#define VMX_PROC_CTLS_RDPMC_EXIT RT_BIT(11) +/** VM-exit when executing the RDTSC/RDTSCP instruction. */ +#define VMX_PROC_CTLS_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_PROC_CTLS_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_PROC_CTLS_CR3_STORE_EXIT RT_BIT(16) +/** Whether the secondary processor based VM-execution controls are used. */ +#define VMX_PROC_CTLS_USE_TERTIARY_CTLS RT_BIT(17) +/** VM-exit on CR8 loads. */ +#define VMX_PROC_CTLS_CR8_LOAD_EXIT RT_BIT(19) +/** VM-exit on CR8 stores. */ +#define VMX_PROC_CTLS_CR8_STORE_EXIT RT_BIT(20) +/** Use TPR shadow. */ +#define VMX_PROC_CTLS_USE_TPR_SHADOW RT_BIT(21) +/** VM-exit when virtual NMI blocking is disabled. */ +#define VMX_PROC_CTLS_NMI_WINDOW_EXIT RT_BIT(22) +/** VM-exit when executing a MOV DRx instruction. */ +#define VMX_PROC_CTLS_MOV_DR_EXIT RT_BIT(23) +/** VM-exit when executing IO instructions. */ +#define VMX_PROC_CTLS_UNCOND_IO_EXIT RT_BIT(24) +/** Use IO bitmaps. */ +#define VMX_PROC_CTLS_USE_IO_BITMAPS RT_BIT(25) +/** Monitor trap flag. */ +#define VMX_PROC_CTLS_MONITOR_TRAP_FLAG RT_BIT(27) +/** Use MSR bitmaps. */ +#define VMX_PROC_CTLS_USE_MSR_BITMAPS RT_BIT(28) +/** VM-exit when executing the MONITOR instruction. */ +#define VMX_PROC_CTLS_MONITOR_EXIT RT_BIT(29) +/** VM-exit when executing the PAUSE instruction. */ +#define VMX_PROC_CTLS_PAUSE_EXIT RT_BIT(30) +/** Whether the secondary processor based VM-execution controls are used. */ +#define VMX_PROC_CTLS_USE_SECONDARY_CTLS RT_BIT(31) +/** Default1 class when true-capability MSRs are not supported. */ +#define VMX_PROC_CTLS_DEFAULT1 UINT32_C(0x0401e172) + +/** Bit fields for MSR_IA32_VMX_PROCBASED_CTLS and Processor-based VM-execution + * controls field in the VMCS. */ +#define VMX_BF_PROC_CTLS_RSVD_0_1_SHIFT 0 +#define VMX_BF_PROC_CTLS_RSVD_0_1_MASK UINT32_C(0x00000003) +#define VMX_BF_PROC_CTLS_INT_WINDOW_EXIT_SHIFT 2 +#define VMX_BF_PROC_CTLS_INT_WINDOW_EXIT_MASK UINT32_C(0x00000004) +#define VMX_BF_PROC_CTLS_USE_TSC_OFFSETTING_SHIFT 3 +#define VMX_BF_PROC_CTLS_USE_TSC_OFFSETTING_MASK UINT32_C(0x00000008) +#define VMX_BF_PROC_CTLS_RSVD_4_6_SHIFT 4 +#define VMX_BF_PROC_CTLS_RSVD_4_6_MASK UINT32_C(0x00000070) +#define VMX_BF_PROC_CTLS_HLT_EXIT_SHIFT 7 +#define VMX_BF_PROC_CTLS_HLT_EXIT_MASK UINT32_C(0x00000080) +#define VMX_BF_PROC_CTLS_RSVD_8_SHIFT 8 +#define VMX_BF_PROC_CTLS_RSVD_8_MASK UINT32_C(0x00000100) +#define VMX_BF_PROC_CTLS_INVLPG_EXIT_SHIFT 9 +#define VMX_BF_PROC_CTLS_INVLPG_EXIT_MASK UINT32_C(0x00000200) +#define VMX_BF_PROC_CTLS_MWAIT_EXIT_SHIFT 10 +#define VMX_BF_PROC_CTLS_MWAIT_EXIT_MASK UINT32_C(0x00000400) +#define VMX_BF_PROC_CTLS_RDPMC_EXIT_SHIFT 11 +#define VMX_BF_PROC_CTLS_RDPMC_EXIT_MASK UINT32_C(0x00000800) +#define VMX_BF_PROC_CTLS_RDTSC_EXIT_SHIFT 12 +#define VMX_BF_PROC_CTLS_RDTSC_EXIT_MASK UINT32_C(0x00001000) +#define VMX_BF_PROC_CTLS_RSVD_13_14_SHIFT 13 +#define VMX_BF_PROC_CTLS_RSVD_13_14_MASK UINT32_C(0x00006000) +#define VMX_BF_PROC_CTLS_CR3_LOAD_EXIT_SHIFT 15 +#define VMX_BF_PROC_CTLS_CR3_LOAD_EXIT_MASK UINT32_C(0x00008000) +#define VMX_BF_PROC_CTLS_CR3_STORE_EXIT_SHIFT 16 +#define VMX_BF_PROC_CTLS_CR3_STORE_EXIT_MASK UINT32_C(0x00010000) +#define VMX_BF_PROC_CTLS_USE_TERTIARY_CTLS_SHIFT 17 +#define VMX_BF_PROC_CTLS_USE_TERTIARY_CTLS_MASK UINT32_C(0x00020000) +#define VMX_BF_PROC_CTLS_RSVD_18_SHIFT 18 +#define VMX_BF_PROC_CTLS_RSVD_18_MASK UINT32_C(0x00040000) +#define VMX_BF_PROC_CTLS_CR8_LOAD_EXIT_SHIFT 19 +#define VMX_BF_PROC_CTLS_CR8_LOAD_EXIT_MASK UINT32_C(0x00080000) +#define VMX_BF_PROC_CTLS_CR8_STORE_EXIT_SHIFT 20 +#define VMX_BF_PROC_CTLS_CR8_STORE_EXIT_MASK UINT32_C(0x00100000) +#define VMX_BF_PROC_CTLS_USE_TPR_SHADOW_SHIFT 21 +#define VMX_BF_PROC_CTLS_USE_TPR_SHADOW_MASK UINT32_C(0x00200000) +#define VMX_BF_PROC_CTLS_NMI_WINDOW_EXIT_SHIFT 22 +#define VMX_BF_PROC_CTLS_NMI_WINDOW_EXIT_MASK UINT32_C(0x00400000) +#define VMX_BF_PROC_CTLS_MOV_DR_EXIT_SHIFT 23 +#define VMX_BF_PROC_CTLS_MOV_DR_EXIT_MASK UINT32_C(0x00800000) +#define VMX_BF_PROC_CTLS_UNCOND_IO_EXIT_SHIFT 24 +#define VMX_BF_PROC_CTLS_UNCOND_IO_EXIT_MASK UINT32_C(0x01000000) +#define VMX_BF_PROC_CTLS_USE_IO_BITMAPS_SHIFT 25 +#define VMX_BF_PROC_CTLS_USE_IO_BITMAPS_MASK UINT32_C(0x02000000) +#define VMX_BF_PROC_CTLS_RSVD_26_SHIFT 26 +#define VMX_BF_PROC_CTLS_RSVD_26_MASK UINT32_C(0x4000000) +#define VMX_BF_PROC_CTLS_MONITOR_TRAP_FLAG_SHIFT 27 +#define VMX_BF_PROC_CTLS_MONITOR_TRAP_FLAG_MASK UINT32_C(0x08000000) +#define VMX_BF_PROC_CTLS_USE_MSR_BITMAPS_SHIFT 28 +#define VMX_BF_PROC_CTLS_USE_MSR_BITMAPS_MASK UINT32_C(0x10000000) +#define VMX_BF_PROC_CTLS_MONITOR_EXIT_SHIFT 29 +#define VMX_BF_PROC_CTLS_MONITOR_EXIT_MASK UINT32_C(0x20000000) +#define VMX_BF_PROC_CTLS_PAUSE_EXIT_SHIFT 30 +#define VMX_BF_PROC_CTLS_PAUSE_EXIT_MASK UINT32_C(0x40000000) +#define VMX_BF_PROC_CTLS_USE_SECONDARY_CTLS_SHIFT 31 +#define VMX_BF_PROC_CTLS_USE_SECONDARY_CTLS_MASK UINT32_C(0x80000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_PROC_CTLS_, UINT32_C(0), UINT32_MAX, + (RSVD_0_1, INT_WINDOW_EXIT, USE_TSC_OFFSETTING, RSVD_4_6, HLT_EXIT, RSVD_8, INVLPG_EXIT, + MWAIT_EXIT, RDPMC_EXIT, RDTSC_EXIT, RSVD_13_14, CR3_LOAD_EXIT, CR3_STORE_EXIT, USE_TERTIARY_CTLS, + RSVD_18, CR8_LOAD_EXIT, CR8_STORE_EXIT, USE_TPR_SHADOW, NMI_WINDOW_EXIT, MOV_DR_EXIT, UNCOND_IO_EXIT, + USE_IO_BITMAPS, RSVD_26, MONITOR_TRAP_FLAG, USE_MSR_BITMAPS, MONITOR_EXIT, PAUSE_EXIT, + USE_SECONDARY_CTLS)); +/** @} */ + + +/** @name Secondary Processor-based VM-execution controls. + * @{ + */ +/** Virtualize APIC accesses. */ +#define VMX_PROC_CTLS2_VIRT_APIC_ACCESS RT_BIT(0) +/** EPT supported/enabled. */ +#define VMX_PROC_CTLS2_EPT RT_BIT(1) +/** Descriptor table instructions cause VM-exits. */ +#define VMX_PROC_CTLS2_DESC_TABLE_EXIT RT_BIT(2) +/** RDTSCP supported/enabled. */ +#define VMX_PROC_CTLS2_RDTSCP RT_BIT(3) +/** Virtualize x2APIC mode. */ +#define VMX_PROC_CTLS2_VIRT_X2APIC_MODE RT_BIT(4) +/** VPID supported/enabled. */ +#define VMX_PROC_CTLS2_VPID RT_BIT(5) +/** VM-exit when executing the WBINVD instruction. */ +#define VMX_PROC_CTLS2_WBINVD_EXIT RT_BIT(6) +/** Unrestricted guest execution. */ +#define VMX_PROC_CTLS2_UNRESTRICTED_GUEST RT_BIT(7) +/** APIC register virtualization. */ +#define VMX_PROC_CTLS2_APIC_REG_VIRT RT_BIT(8) +/** Virtual-interrupt delivery. */ +#define VMX_PROC_CTLS2_VIRT_INT_DELIVERY RT_BIT(9) +/** A specified number of pause loops cause a VM-exit. */ +#define VMX_PROC_CTLS2_PAUSE_LOOP_EXIT RT_BIT(10) +/** VM-exit when executing RDRAND instructions. */ +#define VMX_PROC_CTLS2_RDRAND_EXIT RT_BIT(11) +/** Enables INVPCID instructions. */ +#define VMX_PROC_CTLS2_INVPCID RT_BIT(12) +/** Enables VMFUNC instructions. */ +#define VMX_PROC_CTLS2_VMFUNC RT_BIT(13) +/** Enables VMCS shadowing. */ +#define VMX_PROC_CTLS2_VMCS_SHADOWING RT_BIT(14) +/** Enables ENCLS VM-exits. */ +#define VMX_PROC_CTLS2_ENCLS_EXIT RT_BIT(15) +/** VM-exit when executing RDSEED. */ +#define VMX_PROC_CTLS2_RDSEED_EXIT RT_BIT(16) +/** Enables page-modification logging. */ +#define VMX_PROC_CTLS2_PML RT_BIT(17) +/** Controls whether EPT-violations may cause \#VE instead of exits. */ +#define VMX_PROC_CTLS2_EPT_XCPT_VE RT_BIT(18) +/** Conceal VMX non-root operation from Intel processor trace (PT). */ +#define VMX_PROC_CTLS2_CONCEAL_VMX_FROM_PT RT_BIT(19) +/** Enables XSAVES/XRSTORS instructions. */ +#define VMX_PROC_CTLS2_XSAVES_XRSTORS RT_BIT(20) +/** Enables supervisor/user mode based EPT execute permission for linear + * addresses. */ +#define VMX_PROC_CTLS2_MODE_BASED_EPT_PERM RT_BIT(22) +/** Enables EPT write permissions to be specified at granularity of 128 bytes. */ +#define VMX_PROC_CTLS2_SPP_EPT RT_BIT(23) +/** Intel PT output addresses are treated as guest-physical addresses and + * translated using EPT. */ +#define VMX_PROC_CTLS2_PT_EPT RT_BIT(24) +/** Use TSC scaling. */ +#define VMX_PROC_CTLS2_TSC_SCALING RT_BIT(25) +/** Enables TPAUSE, UMONITOR and UMWAIT instructions. */ +#define VMX_PROC_CTLS2_USER_WAIT_PAUSE RT_BIT(26) +/** Enables consulting ENCLV-exiting bitmap when executing ENCLV. */ +#define VMX_PROC_CTLS2_ENCLV_EXIT RT_BIT(28) + +/** Bit fields for MSR_IA32_VMX_PROCBASED_CTLS2 and Secondary processor-based + * VM-execution controls field in the VMCS. */ +#define VMX_BF_PROC_CTLS2_VIRT_APIC_ACCESS_SHIFT 0 +#define VMX_BF_PROC_CTLS2_VIRT_APIC_ACCESS_MASK UINT32_C(0x00000001) +#define VMX_BF_PROC_CTLS2_EPT_SHIFT 1 +#define VMX_BF_PROC_CTLS2_EPT_MASK UINT32_C(0x00000002) +#define VMX_BF_PROC_CTLS2_DESC_TABLE_EXIT_SHIFT 2 +#define VMX_BF_PROC_CTLS2_DESC_TABLE_EXIT_MASK UINT32_C(0x00000004) +#define VMX_BF_PROC_CTLS2_RDTSCP_SHIFT 3 +#define VMX_BF_PROC_CTLS2_RDTSCP_MASK UINT32_C(0x00000008) +#define VMX_BF_PROC_CTLS2_VIRT_X2APIC_MODE_SHIFT 4 +#define VMX_BF_PROC_CTLS2_VIRT_X2APIC_MODE_MASK UINT32_C(0x00000010) +#define VMX_BF_PROC_CTLS2_VPID_SHIFT 5 +#define VMX_BF_PROC_CTLS2_VPID_MASK UINT32_C(0x00000020) +#define VMX_BF_PROC_CTLS2_WBINVD_EXIT_SHIFT 6 +#define VMX_BF_PROC_CTLS2_WBINVD_EXIT_MASK UINT32_C(0x00000040) +#define VMX_BF_PROC_CTLS2_UNRESTRICTED_GUEST_SHIFT 7 +#define VMX_BF_PROC_CTLS2_UNRESTRICTED_GUEST_MASK UINT32_C(0x00000080) +#define VMX_BF_PROC_CTLS2_APIC_REG_VIRT_SHIFT 8 +#define VMX_BF_PROC_CTLS2_APIC_REG_VIRT_MASK UINT32_C(0x00000100) +#define VMX_BF_PROC_CTLS2_VIRT_INT_DELIVERY_SHIFT 9 +#define VMX_BF_PROC_CTLS2_VIRT_INT_DELIVERY_MASK UINT32_C(0x00000200) +#define VMX_BF_PROC_CTLS2_PAUSE_LOOP_EXIT_SHIFT 10 +#define VMX_BF_PROC_CTLS2_PAUSE_LOOP_EXIT_MASK UINT32_C(0x00000400) +#define VMX_BF_PROC_CTLS2_RDRAND_EXIT_SHIFT 11 +#define VMX_BF_PROC_CTLS2_RDRAND_EXIT_MASK UINT32_C(0x00000800) +#define VMX_BF_PROC_CTLS2_INVPCID_SHIFT 12 +#define VMX_BF_PROC_CTLS2_INVPCID_MASK UINT32_C(0x00001000) +#define VMX_BF_PROC_CTLS2_VMFUNC_SHIFT 13 +#define VMX_BF_PROC_CTLS2_VMFUNC_MASK UINT32_C(0x00002000) +#define VMX_BF_PROC_CTLS2_VMCS_SHADOWING_SHIFT 14 +#define VMX_BF_PROC_CTLS2_VMCS_SHADOWING_MASK UINT32_C(0x00004000) +#define VMX_BF_PROC_CTLS2_ENCLS_EXIT_SHIFT 15 +#define VMX_BF_PROC_CTLS2_ENCLS_EXIT_MASK UINT32_C(0x00008000) +#define VMX_BF_PROC_CTLS2_RDSEED_EXIT_SHIFT 16 +#define VMX_BF_PROC_CTLS2_RDSEED_EXIT_MASK UINT32_C(0x00010000) +#define VMX_BF_PROC_CTLS2_PML_SHIFT 17 +#define VMX_BF_PROC_CTLS2_PML_MASK UINT32_C(0x00020000) +#define VMX_BF_PROC_CTLS2_EPT_VE_SHIFT 18 +#define VMX_BF_PROC_CTLS2_EPT_VE_MASK UINT32_C(0x00040000) +#define VMX_BF_PROC_CTLS2_CONCEAL_VMX_FROM_PT_SHIFT 19 +#define VMX_BF_PROC_CTLS2_CONCEAL_VMX_FROM_PT_MASK UINT32_C(0x00080000) +#define VMX_BF_PROC_CTLS2_XSAVES_XRSTORS_SHIFT 20 +#define VMX_BF_PROC_CTLS2_XSAVES_XRSTORS_MASK UINT32_C(0x00100000) +#define VMX_BF_PROC_CTLS2_RSVD_21_SHIFT 21 +#define VMX_BF_PROC_CTLS2_RSVD_21_MASK UINT32_C(0x00200000) +#define VMX_BF_PROC_CTLS2_MODE_BASED_EPT_PERM_SHIFT 22 +#define VMX_BF_PROC_CTLS2_MODE_BASED_EPT_PERM_MASK UINT32_C(0x00400000) +#define VMX_BF_PROC_CTLS2_SPP_EPT_SHIFT 23 +#define VMX_BF_PROC_CTLS2_SPP_EPT_MASK UINT32_C(0x00800000) +#define VMX_BF_PROC_CTLS2_PT_EPT_SHIFT 24 +#define VMX_BF_PROC_CTLS2_PT_EPT_MASK UINT32_C(0x01000000) +#define VMX_BF_PROC_CTLS2_TSC_SCALING_SHIFT 25 +#define VMX_BF_PROC_CTLS2_TSC_SCALING_MASK UINT32_C(0x02000000) +#define VMX_BF_PROC_CTLS2_USER_WAIT_PAUSE_SHIFT 26 +#define VMX_BF_PROC_CTLS2_USER_WAIT_PAUSE_MASK UINT32_C(0x04000000) +#define VMX_BF_PROC_CTLS2_RSVD_27_SHIFT 27 +#define VMX_BF_PROC_CTLS2_RSVD_27_MASK UINT32_C(0x08000000) +#define VMX_BF_PROC_CTLS2_ENCLV_EXIT_SHIFT 28 +#define VMX_BF_PROC_CTLS2_ENCLV_EXIT_MASK UINT32_C(0x10000000) +#define VMX_BF_PROC_CTLS2_RSVD_29_31_SHIFT 29 +#define VMX_BF_PROC_CTLS2_RSVD_29_31_MASK UINT32_C(0xe0000000) + +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_PROC_CTLS2_, UINT32_C(0), UINT32_MAX, + (VIRT_APIC_ACCESS, EPT, DESC_TABLE_EXIT, RDTSCP, VIRT_X2APIC_MODE, VPID, WBINVD_EXIT, + UNRESTRICTED_GUEST, APIC_REG_VIRT, VIRT_INT_DELIVERY, PAUSE_LOOP_EXIT, RDRAND_EXIT, INVPCID, VMFUNC, + VMCS_SHADOWING, ENCLS_EXIT, RDSEED_EXIT, PML, EPT_VE, CONCEAL_VMX_FROM_PT, XSAVES_XRSTORS, RSVD_21, + MODE_BASED_EPT_PERM, SPP_EPT, PT_EPT, TSC_SCALING, USER_WAIT_PAUSE, RSVD_27, ENCLV_EXIT, + RSVD_29_31)); +/** @} */ + + +/** @name Tertiary Processor-based VM-execution controls. + * @{ + */ +/** VM-exit when executing LOADIWKEY. */ +#define VMX_PROC_CTLS3_LOADIWKEY_EXIT RT_BIT_64(0) + +/** Bit fields for Tertiary processor-based VM-execution controls field in the VMCS. */ +#define VMX_BF_PROC_CTLS3_LOADIWKEY_EXIT_SHIFT 0 +#define VMX_BF_PROC_CTLS3_LOADIWKEY_EXIT_MASK UINT64_C(0x0000000000000001) +#define VMX_BF_PROC_CTLS3_RSVD_1_63_SHIFT 1 +#define VMX_BF_PROC_CTLS3_RSVD_1_63_MASK UINT64_C(0xfffffffffffffffe) + +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_PROC_CTLS3_, UINT64_C(0), UINT64_MAX, + (LOADIWKEY_EXIT, RSVD_1_63)); +/** @} */ + + +/** @name VM-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_ENTRY_CTLS_LOAD_DEBUG RT_BIT(2) +/** 64-bit guest mode. Must be 0 for CPUs that don't support AMD64. */ +#define VMX_ENTRY_CTLS_IA32E_MODE_GUEST RT_BIT(9) +/** In SMM mode after VM-entry. */ +#define VMX_ENTRY_CTLS_ENTRY_TO_SMM RT_BIT(10) +/** Disable dual treatment of SMI and SMM; must be zero for VM-entry outside of SMM. */ +#define VMX_ENTRY_CTLS_DEACTIVATE_DUAL_MON RT_BIT(11) +/** Whether the guest IA32_PERF_GLOBAL_CTRL MSR is loaded on VM-entry. */ +#define VMX_ENTRY_CTLS_LOAD_PERF_MSR RT_BIT(13) +/** Whether the guest IA32_PAT MSR is loaded on VM-entry. */ +#define VMX_ENTRY_CTLS_LOAD_PAT_MSR RT_BIT(14) +/** Whether the guest IA32_EFER MSR is loaded on VM-entry. */ +#define VMX_ENTRY_CTLS_LOAD_EFER_MSR RT_BIT(15) +/** Whether the guest IA32_BNDCFGS MSR is loaded on VM-entry. */ +#define VMX_ENTRY_CTLS_LOAD_BNDCFGS_MSR RT_BIT(16) +/** Whether to conceal VMX from Intel PT (Processor Trace). */ +#define VMX_ENTRY_CTLS_CONCEAL_VMX_FROM_PT RT_BIT(17) +/** Whether the guest IA32_RTIT MSR is loaded on VM-entry. */ +#define VMX_ENTRY_CTLS_LOAD_RTIT_CTL_MSR RT_BIT(18) +/** Whether the guest CET-related MSRs and SPP are loaded on VM-entry. */ +#define VMX_ENTRY_CTLS_LOAD_CET_STATE RT_BIT(20) +/** Whether the guest IA32_PKRS MSR is loaded on VM-entry. */ +#define VMX_ENTRY_CTLS_LOAD_PKRS_MSR RT_BIT(22) +/** Default1 class when true-capability MSRs are not supported. */ +#define VMX_ENTRY_CTLS_DEFAULT1 UINT32_C(0x000011ff) + +/** Bit fields for MSR_IA32_VMX_ENTRY_CTLS and VM-entry controls field in the + * VMCS. */ +#define VMX_BF_ENTRY_CTLS_RSVD_0_1_SHIFT 0 +#define VMX_BF_ENTRY_CTLS_RSVD_0_1_MASK UINT32_C(0x00000003) +#define VMX_BF_ENTRY_CTLS_LOAD_DEBUG_SHIFT 2 +#define VMX_BF_ENTRY_CTLS_LOAD_DEBUG_MASK UINT32_C(0x00000004) +#define VMX_BF_ENTRY_CTLS_RSVD_3_8_SHIFT 3 +#define VMX_BF_ENTRY_CTLS_RSVD_3_8_MASK UINT32_C(0x000001f8) +#define VMX_BF_ENTRY_CTLS_IA32E_MODE_GUEST_SHIFT 9 +#define VMX_BF_ENTRY_CTLS_IA32E_MODE_GUEST_MASK UINT32_C(0x00000200) +#define VMX_BF_ENTRY_CTLS_ENTRY_SMM_SHIFT 10 +#define VMX_BF_ENTRY_CTLS_ENTRY_SMM_MASK UINT32_C(0x00000400) +#define VMX_BF_ENTRY_CTLS_DEACTIVATE_DUAL_MON_SHIFT 11 +#define VMX_BF_ENTRY_CTLS_DEACTIVATE_DUAL_MON_MASK UINT32_C(0x00000800) +#define VMX_BF_ENTRY_CTLS_RSVD_12_SHIFT 12 +#define VMX_BF_ENTRY_CTLS_RSVD_12_MASK UINT32_C(0x00001000) +#define VMX_BF_ENTRY_CTLS_LOAD_PERF_MSR_SHIFT 13 +#define VMX_BF_ENTRY_CTLS_LOAD_PERF_MSR_MASK UINT32_C(0x00002000) +#define VMX_BF_ENTRY_CTLS_LOAD_PAT_MSR_SHIFT 14 +#define VMX_BF_ENTRY_CTLS_LOAD_PAT_MSR_MASK UINT32_C(0x00004000) +#define VMX_BF_ENTRY_CTLS_LOAD_EFER_MSR_SHIFT 15 +#define VMX_BF_ENTRY_CTLS_LOAD_EFER_MSR_MASK UINT32_C(0x00008000) +#define VMX_BF_ENTRY_CTLS_LOAD_BNDCFGS_MSR_SHIFT 16 +#define VMX_BF_ENTRY_CTLS_LOAD_BNDCFGS_MSR_MASK UINT32_C(0x00010000) +#define VMX_BF_ENTRY_CTLS_CONCEAL_VMX_FROM_PT_SHIFT 17 +#define VMX_BF_ENTRY_CTLS_CONCEAL_VMX_FROM_PT_MASK UINT32_C(0x00020000) +#define VMX_BF_ENTRY_CTLS_LOAD_RTIT_CTL_MSR_SHIFT 18 +#define VMX_BF_ENTRY_CTLS_LOAD_RTIT_CTL_MSR_MASK UINT32_C(0x00040000) +#define VMX_BF_ENTRY_CTLS_RSVD_19_SHIFT 19 +#define VMX_BF_ENTRY_CTLS_RSVD_19_MASK UINT32_C(0x00080000) +#define VMX_BF_ENTRY_CTLS_LOAD_CET_SHIFT 20 +#define VMX_BF_ENTRY_CTLS_LOAD_CET_MASK UINT32_C(0x00100000) +#define VMX_BF_ENTRY_CTLS_RSVD_21_SHIFT 21 +#define VMX_BF_ENTRY_CTLS_RSVD_21_MASK UINT32_C(0x00200000) +#define VMX_BF_ENTRY_CTLS_LOAD_PKRS_MSR_SHIFT 22 +#define VMX_BF_ENTRY_CTLS_LOAD_PKRS_MSR_MASK UINT32_C(0x00400000) +#define VMX_BF_ENTRY_CTLS_RSVD_23_31_SHIFT 23 +#define VMX_BF_ENTRY_CTLS_RSVD_23_31_MASK UINT32_C(0xff800000) + +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_ENTRY_CTLS_, UINT32_C(0), UINT32_MAX, + (RSVD_0_1, LOAD_DEBUG, RSVD_3_8, IA32E_MODE_GUEST, ENTRY_SMM, DEACTIVATE_DUAL_MON, RSVD_12, + LOAD_PERF_MSR, LOAD_PAT_MSR, LOAD_EFER_MSR, LOAD_BNDCFGS_MSR, CONCEAL_VMX_FROM_PT, + LOAD_RTIT_CTL_MSR, RSVD_19, LOAD_CET, RSVD_21, LOAD_PKRS_MSR, RSVD_23_31)); +/** @} */ + + +/** @name VM-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_EXIT_CTLS_SAVE_DEBUG RT_BIT(2) +/** Return to long mode after a VM-exit. */ +#define VMX_EXIT_CTLS_HOST_ADDR_SPACE_SIZE RT_BIT(9) +/** Whether the host IA32_PERF_GLOBAL_CTRL MSR is loaded on VM-exit. */ +#define VMX_EXIT_CTLS_LOAD_PERF_MSR RT_BIT(12) +/** Acknowledge external interrupts with the irq controller if one caused a VM-exit. */ +#define VMX_EXIT_CTLS_ACK_EXT_INT RT_BIT(15) +/** Whether the guest IA32_PAT MSR is saved on VM-exit. */ +#define VMX_EXIT_CTLS_SAVE_PAT_MSR RT_BIT(18) +/** Whether the host IA32_PAT MSR is loaded on VM-exit. */ +#define VMX_EXIT_CTLS_LOAD_PAT_MSR RT_BIT(19) +/** Whether the guest IA32_EFER MSR is saved on VM-exit. */ +#define VMX_EXIT_CTLS_SAVE_EFER_MSR RT_BIT(20) +/** Whether the host IA32_EFER MSR is loaded on VM-exit. */ +#define VMX_EXIT_CTLS_LOAD_EFER_MSR RT_BIT(21) +/** Whether the value of the VMX preemption timer is saved on every VM-exit. */ +#define VMX_EXIT_CTLS_SAVE_PREEMPT_TIMER RT_BIT(22) +/** Whether IA32_BNDCFGS MSR is cleared on VM-exit. */ +#define VMX_EXIT_CTLS_CLEAR_BNDCFGS_MSR RT_BIT(23) +/** Whether to conceal VMX from Intel PT. */ +#define VMX_EXIT_CTLS_CONCEAL_VMX_FROM_PT RT_BIT(24) +/** Whether IA32_RTIT_CTL MSR is cleared on VM-exit. */ +#define VMX_EXIT_CTLS_CLEAR_RTIT_CTL_MSR RT_BIT(25) +/** Whether CET-related MSRs and SPP are loaded on VM-exit. */ +#define VMX_EXIT_CTLS_LOAD_CET_STATE RT_BIT(28) +/** Whether the host IA32_PKRS MSR is loaded on VM-exit. */ +#define VMX_EXIT_CTLS_LOAD_PKRS_MSR RT_BIT(29) +/** Whether the host IA32_PERF_GLOBAL_CTRL MSR is saved on VM-exit. */ +#define VMX_EXIT_CTLS_SAVE_PERF_MSR RT_BIT(30) +/** Whether secondary VM-exit controls are used. */ +#define VMX_EXIT_CTLS_USE_SECONDARY_CTLS RT_BIT(31) +/** Default1 class when true-capability MSRs are not supported. */ +#define VMX_EXIT_CTLS_DEFAULT1 UINT32_C(0x00036dff) + +/** Bit fields for MSR_IA32_VMX_EXIT_CTLS and VM-exit controls field in the + * VMCS. */ +#define VMX_BF_EXIT_CTLS_RSVD_0_1_SHIFT 0 +#define VMX_BF_EXIT_CTLS_RSVD_0_1_MASK UINT32_C(0x00000003) +#define VMX_BF_EXIT_CTLS_SAVE_DEBUG_SHIFT 2 +#define VMX_BF_EXIT_CTLS_SAVE_DEBUG_MASK UINT32_C(0x00000004) +#define VMX_BF_EXIT_CTLS_RSVD_3_8_SHIFT 3 +#define VMX_BF_EXIT_CTLS_RSVD_3_8_MASK UINT32_C(0x000001f8) +#define VMX_BF_EXIT_CTLS_HOST_ADDR_SPACE_SIZE_SHIFT 9 +#define VMX_BF_EXIT_CTLS_HOST_ADDR_SPACE_SIZE_MASK UINT32_C(0x00000200) +#define VMX_BF_EXIT_CTLS_RSVD_10_11_SHIFT 10 +#define VMX_BF_EXIT_CTLS_RSVD_10_11_MASK UINT32_C(0x00000c00) +#define VMX_BF_EXIT_CTLS_LOAD_PERF_MSR_SHIFT 12 +#define VMX_BF_EXIT_CTLS_LOAD_PERF_MSR_MASK UINT32_C(0x00001000) +#define VMX_BF_EXIT_CTLS_RSVD_13_14_SHIFT 13 +#define VMX_BF_EXIT_CTLS_RSVD_13_14_MASK UINT32_C(0x00006000) +#define VMX_BF_EXIT_CTLS_ACK_EXT_INT_SHIFT 15 +#define VMX_BF_EXIT_CTLS_ACK_EXT_INT_MASK UINT32_C(0x00008000) +#define VMX_BF_EXIT_CTLS_RSVD_16_17_SHIFT 16 +#define VMX_BF_EXIT_CTLS_RSVD_16_17_MASK UINT32_C(0x00030000) +#define VMX_BF_EXIT_CTLS_SAVE_PAT_MSR_SHIFT 18 +#define VMX_BF_EXIT_CTLS_SAVE_PAT_MSR_MASK UINT32_C(0x00040000) +#define VMX_BF_EXIT_CTLS_LOAD_PAT_MSR_SHIFT 19 +#define VMX_BF_EXIT_CTLS_LOAD_PAT_MSR_MASK UINT32_C(0x00080000) +#define VMX_BF_EXIT_CTLS_SAVE_EFER_MSR_SHIFT 20 +#define VMX_BF_EXIT_CTLS_SAVE_EFER_MSR_MASK UINT32_C(0x00100000) +#define VMX_BF_EXIT_CTLS_LOAD_EFER_MSR_SHIFT 21 +#define VMX_BF_EXIT_CTLS_LOAD_EFER_MSR_MASK UINT32_C(0x00200000) +#define VMX_BF_EXIT_CTLS_SAVE_PREEMPT_TIMER_SHIFT 22 +#define VMX_BF_EXIT_CTLS_SAVE_PREEMPT_TIMER_MASK UINT32_C(0x00400000) +#define VMX_BF_EXIT_CTLS_CLEAR_BNDCFGS_MSR_SHIFT 23 +#define VMX_BF_EXIT_CTLS_CLEAR_BNDCFGS_MSR_MASK UINT32_C(0x00800000) +#define VMX_BF_EXIT_CTLS_CONCEAL_VMX_FROM_PT_SHIFT 24 +#define VMX_BF_EXIT_CTLS_CONCEAL_VMX_FROM_PT_MASK UINT32_C(0x01000000) +#define VMX_BF_EXIT_CTLS_CLEAR_RTIT_CTL_MSR_SHIFT 25 +#define VMX_BF_EXIT_CTLS_CLEAR_RTIT_CTL_MSR_MASK UINT32_C(0x02000000) +#define VMX_BF_EXIT_CTLS_RSVD_26_27_SHIFT 26 +#define VMX_BF_EXIT_CTLS_RSVD_26_27_MASK UINT32_C(0x0c000000) +#define VMX_BF_EXIT_CTLS_LOAD_CET_SHIFT 28 +#define VMX_BF_EXIT_CTLS_LOAD_CET_MASK UINT32_C(0x10000000) +#define VMX_BF_EXIT_CTLS_LOAD_PKRS_MSR_SHIFT 29 +#define VMX_BF_EXIT_CTLS_LOAD_PKRS_MSR_MASK UINT32_C(0x20000000) +#define VMX_BF_EXIT_CTLS_SAVE_PERF_MSR_SHIFT 30 +#define VMX_BF_EXIT_CTLS_SAVE_PERF_MSR_MASK UINT32_C(0x40000000) +#define VMX_BF_EXIT_CTLS_USE_SECONDARY_CTLS_SHIFT 31 +#define VMX_BF_EXIT_CTLS_USE_SECONDARY_CTLS_MASK UINT32_C(0x80000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_EXIT_CTLS_, UINT32_C(0), UINT32_MAX, + (RSVD_0_1, SAVE_DEBUG, RSVD_3_8, HOST_ADDR_SPACE_SIZE, RSVD_10_11, LOAD_PERF_MSR, RSVD_13_14, + ACK_EXT_INT, RSVD_16_17, SAVE_PAT_MSR, LOAD_PAT_MSR, SAVE_EFER_MSR, LOAD_EFER_MSR, + SAVE_PREEMPT_TIMER, CLEAR_BNDCFGS_MSR, CONCEAL_VMX_FROM_PT, CLEAR_RTIT_CTL_MSR, RSVD_26_27, + LOAD_CET, LOAD_PKRS_MSR, SAVE_PERF_MSR, USE_SECONDARY_CTLS)); +/** @} */ + + +/** @name VM-exit reason. + * @{ + */ +#define VMX_EXIT_REASON_BASIC(a) ((a) & 0xffff) +#define VMX_EXIT_REASON_HAS_ENTRY_FAILED(a) (((a) >> 31) & 1) +#define VMX_EXIT_REASON_ENTRY_FAILED RT_BIT(31) + +/** Bit fields for VM-exit reason. */ +/** The exit reason. */ +#define VMX_BF_EXIT_REASON_BASIC_SHIFT 0 +#define VMX_BF_EXIT_REASON_BASIC_MASK UINT32_C(0x0000ffff) +/** Bits 16:26 are reseved and MBZ. */ +#define VMX_BF_EXIT_REASON_RSVD_16_26_SHIFT 16 +#define VMX_BF_EXIT_REASON_RSVD_16_26_MASK UINT32_C(0x07ff0000) +/** Whether the VM-exit was incident to enclave mode. */ +#define VMX_BF_EXIT_REASON_ENCLAVE_MODE_SHIFT 27 +#define VMX_BF_EXIT_REASON_ENCLAVE_MODE_MASK UINT32_C(0x08000000) +/** Pending MTF (Monitor Trap Flag) during VM-exit (only applicable in SMM mode). */ +#define VMX_BF_EXIT_REASON_SMM_PENDING_MTF_SHIFT 28 +#define VMX_BF_EXIT_REASON_SMM_PENDING_MTF_MASK UINT32_C(0x10000000) +/** VM-exit from VMX root operation (only possible with SMM). */ +#define VMX_BF_EXIT_REASON_VMX_ROOT_MODE_SHIFT 29 +#define VMX_BF_EXIT_REASON_VMX_ROOT_MODE_MASK UINT32_C(0x20000000) +/** Bit 30 is reserved and MBZ. */ +#define VMX_BF_EXIT_REASON_RSVD_30_SHIFT 30 +#define VMX_BF_EXIT_REASON_RSVD_30_MASK UINT32_C(0x40000000) +/** Whether VM-entry failed (currently only happens during loading guest-state + * or MSRs or machine check exceptions). */ +#define VMX_BF_EXIT_REASON_ENTRY_FAILED_SHIFT 31 +#define VMX_BF_EXIT_REASON_ENTRY_FAILED_MASK UINT32_C(0x80000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_EXIT_REASON_, UINT32_C(0), UINT32_MAX, + (BASIC, RSVD_16_26, ENCLAVE_MODE, SMM_PENDING_MTF, VMX_ROOT_MODE, RSVD_30, ENTRY_FAILED)); +/** @} */ + + +/** @name VM-entry interruption information. + * @{ + */ +#define VMX_ENTRY_INT_INFO_IS_VALID(a) (((a) >> 31) & 1) +#define VMX_ENTRY_INT_INFO_VECTOR(a) ((a) & 0xff) +#define VMX_ENTRY_INT_INFO_TYPE_SHIFT 8 +#define VMX_ENTRY_INT_INFO_TYPE(a) (((a) >> 8) & 7) +#define VMX_ENTRY_INT_INFO_ERROR_CODE_VALID RT_BIT(11) +#define VMX_ENTRY_INT_INFO_IS_ERROR_CODE_VALID(a) (((a) >> 11) & 1) +#define VMX_ENTRY_INT_INFO_NMI_UNBLOCK_IRET 12 +#define VMX_ENTRY_INT_INFO_IS_NMI_UNBLOCK_IRET(a) (((a) >> 12) & 1) +#define VMX_ENTRY_INT_INFO_VALID RT_BIT(31) +#define VMX_ENTRY_INT_INFO_IS_VALID(a) (((a) >> 31) & 1) +/** Construct an VM-entry interruption information field from a VM-exit interruption + * info value (same except that bit 12 is reserved). */ +#define VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(a) ((a) & ~RT_BIT(12)) +/** Construct a VM-entry interruption information field from an IDT-vectoring + * information field (same except that bit 12 is reserved). */ +#define VMX_ENTRY_INT_INFO_FROM_EXIT_IDT_INFO(a) ((a) & ~RT_BIT(12)) +/** If the VM-entry interruption information field indicates a page-fault. */ +#define VMX_ENTRY_INT_INFO_IS_XCPT_PF(a) (((a) & ( VMX_BF_ENTRY_INT_INFO_VALID_MASK \ + | VMX_BF_ENTRY_INT_INFO_TYPE_MASK \ + | VMX_BF_ENTRY_INT_INFO_VECTOR_MASK)) \ + == ( RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1) \ + | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_HW_XCPT) \ + | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_PF))) +/** If the VM-entry interruption information field indicates an external + * interrupt. */ +#define VMX_ENTRY_INT_INFO_IS_EXT_INT(a) (((a) & ( VMX_BF_ENTRY_INT_INFO_VALID_MASK \ + | VMX_BF_ENTRY_INT_INFO_TYPE_MASK)) \ + == ( RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1) \ + | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_EXT_INT))) +/** If the VM-entry interruption information field indicates an NMI. */ +#define VMX_ENTRY_INT_INFO_IS_XCPT_NMI(a) (((a) & ( VMX_BF_ENTRY_INT_INFO_VALID_MASK \ + | VMX_BF_ENTRY_INT_INFO_TYPE_MASK \ + | VMX_BF_ENTRY_INT_INFO_VECTOR_MASK)) \ + == ( RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1) \ + | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_NMI) \ + | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_NMI))) + +/** Bit fields for VM-entry interruption information. */ +/** The VM-entry interruption vector. */ +#define VMX_BF_ENTRY_INT_INFO_VECTOR_SHIFT 0 +#define VMX_BF_ENTRY_INT_INFO_VECTOR_MASK UINT32_C(0x000000ff) +/** The VM-entry interruption type (see VMX_ENTRY_INT_INFO_TYPE_XXX). */ +#define VMX_BF_ENTRY_INT_INFO_TYPE_SHIFT 8 +#define VMX_BF_ENTRY_INT_INFO_TYPE_MASK UINT32_C(0x00000700) +/** Whether this event has an error code. */ +#define VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID_SHIFT 11 +#define VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID_MASK UINT32_C(0x00000800) +/** Bits 12:30 are reserved and MBZ. */ +#define VMX_BF_ENTRY_INT_INFO_RSVD_12_30_SHIFT 12 +#define VMX_BF_ENTRY_INT_INFO_RSVD_12_30_MASK UINT32_C(0x7ffff000) +/** Whether this VM-entry interruption info is valid. */ +#define VMX_BF_ENTRY_INT_INFO_VALID_SHIFT 31 +#define VMX_BF_ENTRY_INT_INFO_VALID_MASK UINT32_C(0x80000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_ENTRY_INT_INFO_, UINT32_C(0), UINT32_MAX, + (VECTOR, TYPE, ERR_CODE_VALID, RSVD_12_30, VALID)); +/** @} */ + + +/** @name VM-entry exception error code. + * @{ */ +/** Error code valid mask. */ +/** @todo r=ramshankar: Intel spec. 26.2.1.3 "VM-Entry Control Fields" states that + * bits 31:15 MBZ. However, Intel spec. 6.13 "Error Code" states "To keep the + * stack aligned for doubleword pushes, the upper half of the error code is + * reserved" which implies bits 31:16 MBZ (and not 31:15) which is what we + * use below. */ +#define VMX_ENTRY_INT_XCPT_ERR_CODE_VALID_MASK UINT32_C(0xffff) +/** @} */ + +/** @name VM-entry interruption information types. + * @{ + */ +#define VMX_ENTRY_INT_INFO_TYPE_EXT_INT 0 +#define VMX_ENTRY_INT_INFO_TYPE_RSVD 1 +#define VMX_ENTRY_INT_INFO_TYPE_NMI 2 +#define VMX_ENTRY_INT_INFO_TYPE_HW_XCPT 3 +#define VMX_ENTRY_INT_INFO_TYPE_SW_INT 4 +#define VMX_ENTRY_INT_INFO_TYPE_PRIV_SW_XCPT 5 +#define VMX_ENTRY_INT_INFO_TYPE_SW_XCPT 6 +#define VMX_ENTRY_INT_INFO_TYPE_OTHER_EVENT 7 +/** @} */ + + +/** @name VM-entry interruption information vector types for + * VMX_ENTRY_INT_INFO_TYPE_OTHER_EVENT. + * @{ */ +#define VMX_ENTRY_INT_INFO_VECTOR_MTF 0 +/** @} */ + + +/** @name VM-exit interruption information. + * @{ + */ +#define VMX_EXIT_INT_INFO_VECTOR(a) ((a) & 0xff) +#define VMX_EXIT_INT_INFO_TYPE_SHIFT 8 +#define VMX_EXIT_INT_INFO_TYPE(a) (((a) >> 8) & 7) +#define VMX_EXIT_INT_INFO_ERROR_CODE_VALID RT_BIT(11) +#define VMX_EXIT_INT_INFO_IS_ERROR_CODE_VALID(a) (((a) >> 11) & 1) +#define VMX_EXIT_INT_INFO_NMI_UNBLOCK_IRET 12 +#define VMX_EXIT_INT_INFO_IS_NMI_UNBLOCK_IRET(a) (((a) >> 12) & 1) +#define VMX_EXIT_INT_INFO_VALID RT_BIT(31) +#define VMX_EXIT_INT_INFO_IS_VALID(a) (((a) >> 31) & 1) + +/** If the VM-exit interruption information field indicates an page-fault. */ +#define VMX_EXIT_INT_INFO_IS_XCPT_PF(a) (((a) & ( VMX_BF_EXIT_INT_INFO_VALID_MASK \ + | VMX_BF_EXIT_INT_INFO_TYPE_MASK \ + | VMX_BF_EXIT_INT_INFO_VECTOR_MASK)) \ + == ( RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_VALID, 1) \ + | RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT) \ + | RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_VECTOR, X86_XCPT_PF))) +/** If the VM-exit interruption information field indicates an double-fault. */ +#define VMX_EXIT_INT_INFO_IS_XCPT_DF(a) (((a) & ( VMX_BF_EXIT_INT_INFO_VALID_MASK \ + | VMX_BF_EXIT_INT_INFO_TYPE_MASK \ + | VMX_BF_EXIT_INT_INFO_VECTOR_MASK)) \ + == ( RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_VALID, 1) \ + | RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT) \ + | RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_VECTOR, X86_XCPT_DF))) +/** If the VM-exit interruption information field indicates an NMI. */ +#define VMX_EXIT_INT_INFO_IS_XCPT_NMI(a) (((a) & ( VMX_BF_EXIT_INT_INFO_VALID_MASK \ + | VMX_BF_EXIT_INT_INFO_TYPE_MASK \ + | VMX_BF_EXIT_INT_INFO_VECTOR_MASK)) \ + == ( RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_VALID, 1) \ + | RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_NMI) \ + | RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_VECTOR, X86_XCPT_NMI))) + + +/** Bit fields for VM-exit interruption infomration. */ +/** The VM-exit interruption vector. */ +#define VMX_BF_EXIT_INT_INFO_VECTOR_SHIFT 0 +#define VMX_BF_EXIT_INT_INFO_VECTOR_MASK UINT32_C(0x000000ff) +/** The VM-exit interruption type (see VMX_EXIT_INT_INFO_TYPE_XXX). */ +#define VMX_BF_EXIT_INT_INFO_TYPE_SHIFT 8 +#define VMX_BF_EXIT_INT_INFO_TYPE_MASK UINT32_C(0x00000700) +/** Whether this event has an error code. */ +#define VMX_BF_EXIT_INT_INFO_ERR_CODE_VALID_SHIFT 11 +#define VMX_BF_EXIT_INT_INFO_ERR_CODE_VALID_MASK UINT32_C(0x00000800) +/** Whether NMI-unblocking due to IRET is active. */ +#define VMX_BF_EXIT_INT_INFO_NMI_UNBLOCK_IRET_SHIFT 12 +#define VMX_BF_EXIT_INT_INFO_NMI_UNBLOCK_IRET_MASK UINT32_C(0x00001000) +/** Bits 13:30 is reserved (MBZ). */ +#define VMX_BF_EXIT_INT_INFO_RSVD_13_30_SHIFT 13 +#define VMX_BF_EXIT_INT_INFO_RSVD_13_30_MASK UINT32_C(0x7fffe000) +/** Whether this VM-exit interruption info is valid. */ +#define VMX_BF_EXIT_INT_INFO_VALID_SHIFT 31 +#define VMX_BF_EXIT_INT_INFO_VALID_MASK UINT32_C(0x80000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_EXIT_INT_INFO_, UINT32_C(0), UINT32_MAX, + (VECTOR, TYPE, ERR_CODE_VALID, NMI_UNBLOCK_IRET, RSVD_13_30, VALID)); +/** @} */ + + +/** @name VM-exit interruption information types. + * @{ + */ +#define VMX_EXIT_INT_INFO_TYPE_EXT_INT 0 +#define VMX_EXIT_INT_INFO_TYPE_NMI 2 +#define VMX_EXIT_INT_INFO_TYPE_HW_XCPT 3 +#define VMX_EXIT_INT_INFO_TYPE_SW_INT 4 +#define VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT 5 +#define VMX_EXIT_INT_INFO_TYPE_SW_XCPT 6 +#define VMX_EXIT_INT_INFO_TYPE_UNUSED 7 +/** @} */ + + +/** @name VM-exit instruction identity. + * + * These are found in VM-exit instruction information fields for certain + * instructions. + * @{ */ +typedef uint32_t VMXINSTRID; +/** Whether the instruction ID field is valid. */ +#define VMXINSTRID_VALID RT_BIT_32(31) +/** Whether the instruction's primary operand in the Mod R/M byte (bits 0:3) is a + * read or write. */ +#define VMXINSTRID_MODRM_PRIMARY_OP_W RT_BIT_32(30) +/** Gets whether the instruction ID is valid or not. */ +#define VMXINSTRID_IS_VALID(a) (((a) >> 31) & 1) +#define VMXINSTRID_IS_MODRM_PRIMARY_OP_W(a) (((a) >> 30) & 1) +/** Gets the instruction ID. */ +#define VMXINSTRID_GET_ID(a) ((a) & ~(VMXINSTRID_VALID | VMXINSTRID_MODRM_PRIMARY_OP_W)) +/** No instruction ID info. */ +#define VMXINSTRID_NONE 0 + +/** The OR'd rvalues are from the VT-x spec (valid bit is VBox specific): */ +#define VMXINSTRID_SGDT (0x0 | VMXINSTRID_VALID | VMXINSTRID_MODRM_PRIMARY_OP_W) +#define VMXINSTRID_SIDT (0x1 | VMXINSTRID_VALID | VMXINSTRID_MODRM_PRIMARY_OP_W) +#define VMXINSTRID_LGDT (0x2 | VMXINSTRID_VALID) +#define VMXINSTRID_LIDT (0x3 | VMXINSTRID_VALID) + +#define VMXINSTRID_SLDT (0x0 | VMXINSTRID_VALID | VMXINSTRID_MODRM_PRIMARY_OP_W) +#define VMXINSTRID_STR (0x1 | VMXINSTRID_VALID | VMXINSTRID_MODRM_PRIMARY_OP_W) +#define VMXINSTRID_LLDT (0x2 | VMXINSTRID_VALID) +#define VMXINSTRID_LTR (0x3 | VMXINSTRID_VALID) + +/** The following IDs are used internally (some for logging, others for conveying + * the ModR/M primary operand write bit): */ +#define VMXINSTRID_VMLAUNCH (0x10 | VMXINSTRID_VALID) +#define VMXINSTRID_VMRESUME (0x11 | VMXINSTRID_VALID) +#define VMXINSTRID_VMREAD (0x12 | VMXINSTRID_VALID) +#define VMXINSTRID_VMWRITE (0x13 | VMXINSTRID_VALID | VMXINSTRID_MODRM_PRIMARY_OP_W) +#define VMXINSTRID_IO_IN (0x14 | VMXINSTRID_VALID) +#define VMXINSTRID_IO_INS (0x15 | VMXINSTRID_VALID) +#define VMXINSTRID_IO_OUT (0x16 | VMXINSTRID_VALID) +#define VMXINSTRID_IO_OUTS (0x17 | VMXINSTRID_VALID) +#define VMXINSTRID_MOV_TO_DRX (0x18 | VMXINSTRID_VALID) +#define VMXINSTRID_MOV_FROM_DRX (0x19 | VMXINSTRID_VALID) +/** @} */ + + +/** @name IDT-vectoring information. + * @{ + */ +#define VMX_IDT_VECTORING_INFO_VECTOR(a) ((a) & 0xff) +#define VMX_IDT_VECTORING_INFO_TYPE_SHIFT 8 +#define VMX_IDT_VECTORING_INFO_TYPE(a) (((a) >> 8) & 7) +#define VMX_IDT_VECTORING_INFO_ERROR_CODE_VALID RT_BIT(11) +#define VMX_IDT_VECTORING_INFO_IS_ERROR_CODE_VALID(a) (((a) >> 11) & 1) +#define VMX_IDT_VECTORING_INFO_IS_VALID(a) (((a) >> 31) & 1) +#define VMX_IDT_VECTORING_INFO_VALID RT_BIT(31) + +/** Construct an IDT-vectoring information field from an VM-entry interruption + * information field (same except that bit 12 is reserved). */ +#define VMX_IDT_VECTORING_INFO_FROM_ENTRY_INT_INFO(a) ((a) & ~RT_BIT(12)) +/** If the IDT-vectoring information field indicates a page-fault. */ +#define VMX_IDT_VECTORING_INFO_IS_XCPT_PF(a) (((a) & ( VMX_BF_IDT_VECTORING_INFO_VALID_MASK \ + | VMX_BF_IDT_VECTORING_INFO_TYPE_MASK \ + | VMX_BF_IDT_VECTORING_INFO_VECTOR_MASK)) \ + == ( RT_BF_MAKE(VMX_BF_IDT_VECTORING_INFO_VALID, 1) \ + | RT_BF_MAKE(VMX_BF_IDT_VECTORING_INFO_TYPE, VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT) \ + | RT_BF_MAKE(VMX_BF_IDT_VECTORING_INFO_VECTOR, X86_XCPT_PF))) +/** If the IDT-vectoring information field indicates an NMI. */ +#define VMX_IDT_VECTORING_INFO_IS_XCPT_NMI(a) (((a) & ( VMX_BF_IDT_VECTORING_INFO_VALID_MASK \ + | VMX_BF_IDT_VECTORING_INFO_TYPE_MASK \ + | VMX_BF_IDT_VECTORING_INFO_VECTOR_MASK)) \ + == ( RT_BF_MAKE(VMX_BF_IDT_VECTORING_INFO_VALID, 1) \ + | RT_BF_MAKE(VMX_BF_IDT_VECTORING_INFO_TYPE, VMX_IDT_VECTORING_INFO_TYPE_NMI) \ + | RT_BF_MAKE(VMX_BF_IDT_VECTORING_INFO_VECTOR, X86_XCPT_NMI))) + + +/** Bit fields for IDT-vectoring information. */ +/** The IDT-vectoring info vector. */ +#define VMX_BF_IDT_VECTORING_INFO_VECTOR_SHIFT 0 +#define VMX_BF_IDT_VECTORING_INFO_VECTOR_MASK UINT32_C(0x000000ff) +/** The IDT-vectoring info type (see VMX_IDT_VECTORING_INFO_TYPE_XXX). */ +#define VMX_BF_IDT_VECTORING_INFO_TYPE_SHIFT 8 +#define VMX_BF_IDT_VECTORING_INFO_TYPE_MASK UINT32_C(0x00000700) +/** Whether the event has an error code. */ +#define VMX_BF_IDT_VECTORING_INFO_ERR_CODE_VALID_SHIFT 11 +#define VMX_BF_IDT_VECTORING_INFO_ERR_CODE_VALID_MASK UINT32_C(0x00000800) +/** Bit 12 is undefined. */ +#define VMX_BF_IDT_VECTORING_INFO_UNDEF_12_SHIFT 12 +#define VMX_BF_IDT_VECTORING_INFO_UNDEF_12_MASK UINT32_C(0x00001000) +/** Bits 13:30 is reserved (MBZ). */ +#define VMX_BF_IDT_VECTORING_INFO_RSVD_13_30_SHIFT 13 +#define VMX_BF_IDT_VECTORING_INFO_RSVD_13_30_MASK UINT32_C(0x7fffe000) +/** Whether this IDT-vectoring info is valid. */ +#define VMX_BF_IDT_VECTORING_INFO_VALID_SHIFT 31 +#define VMX_BF_IDT_VECTORING_INFO_VALID_MASK UINT32_C(0x80000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_IDT_VECTORING_INFO_, UINT32_C(0), UINT32_MAX, + (VECTOR, TYPE, ERR_CODE_VALID, UNDEF_12, RSVD_13_30, VALID)); +/** @} */ + + +/** @name IDT-vectoring information vector types. + * @{ + */ +#define VMX_IDT_VECTORING_INFO_TYPE_EXT_INT 0 +#define VMX_IDT_VECTORING_INFO_TYPE_NMI 2 +#define VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT 3 +#define VMX_IDT_VECTORING_INFO_TYPE_SW_INT 4 +#define VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT 5 +#define VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT 6 +#define VMX_IDT_VECTORING_INFO_TYPE_UNUSED 7 +/** @} */ + + +/** @name TPR threshold. + * @{ */ +/** Mask of the TPR threshold field (bits 31:4 MBZ). */ +#define VMX_TPR_THRESHOLD_MASK UINT32_C(0xf) + +/** Bit fields for TPR threshold. */ +#define VMX_BF_TPR_THRESHOLD_TPR_SHIFT 0 +#define VMX_BF_TPR_THRESHOLD_TPR_MASK UINT32_C(0x0000000f) +#define VMX_BF_TPR_THRESHOLD_RSVD_4_31_SHIFT 4 +#define VMX_BF_TPR_THRESHOLD_RSVD_4_31_MASK UINT32_C(0xfffffff0) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_TPR_THRESHOLD_, UINT32_C(0), UINT32_MAX, + (TPR, RSVD_4_31)); +/** @} */ + + +/** @name Guest-activity states. + * @{ + */ +/** The logical processor is active. */ +#define VMX_VMCS_GUEST_ACTIVITY_ACTIVE 0x0 +/** The logical processor is inactive, because it executed a HLT instruction. */ +#define VMX_VMCS_GUEST_ACTIVITY_HLT 0x1 +/** The logical processor is inactive, because of a triple fault or other serious error. */ +#define VMX_VMCS_GUEST_ACTIVITY_SHUTDOWN 0x2 +/** The logical processor is inactive, because it's waiting for a startup-IPI */ +#define VMX_VMCS_GUEST_ACTIVITY_SIPI_WAIT 0x3 +/** @} */ + + +/** @name Guest-interruptibility states. + * @{ + */ +#define VMX_VMCS_GUEST_INT_STATE_BLOCK_STI RT_BIT(0) +#define VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS RT_BIT(1) +#define VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI RT_BIT(2) +#define VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI RT_BIT(3) +#define VMX_VMCS_GUEST_INT_STATE_ENCLAVE RT_BIT(4) + +/** Mask of the guest-interruptibility state field (bits 31:5 MBZ). */ +#define VMX_VMCS_GUEST_INT_STATE_MASK UINT32_C(0x1f) +/** @} */ + + +/** @name Exit qualification for debug exceptions. + * @{ + */ +/** Hardware breakpoint 0 was met. */ +#define VMX_VMCS_EXIT_QUAL_DEBUG_XCPT_BP0 RT_BIT_64(0) +/** Hardware breakpoint 1 was met. */ +#define VMX_VMCS_EXIT_QUAL_DEBUG_XCPT_BP1 RT_BIT_64(1) +/** Hardware breakpoint 2 was met. */ +#define VMX_VMCS_EXIT_QUAL_DEBUG_XCPT_BP2 RT_BIT_64(2) +/** Hardware breakpoint 3 was met. */ +#define VMX_VMCS_EXIT_QUAL_DEBUG_XCPT_BP3 RT_BIT_64(3) +/** Debug register access detected. */ +#define VMX_VMCS_EXIT_QUAL_DEBUG_XCPT_BD RT_BIT_64(13) +/** A debug exception would have been triggered by single-step execution mode. */ +#define VMX_VMCS_EXIT_QUAL_DEBUG_XCPT_BS RT_BIT_64(14) +/** Mask of all valid bits. */ +#define VMX_VMCS_EXIT_QUAL_VALID_MASK ( VMX_VMCS_EXIT_QUAL_DEBUG_XCPT_BP0 \ + | VMX_VMCS_EXIT_QUAL_DEBUG_XCPT_BP1 \ + | VMX_VMCS_EXIT_QUAL_DEBUG_XCPT_BP2 \ + | VMX_VMCS_EXIT_QUAL_DEBUG_XCPT_BP3 \ + | VMX_VMCS_EXIT_QUAL_DEBUG_XCPT_BD \ + | VMX_VMCS_EXIT_QUAL_DEBUG_XCPT_BS) + +/** Bit fields for Exit qualifications due to debug exceptions. */ +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_BP0_SHIFT 0 +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_BP0_MASK UINT64_C(0x0000000000000001) +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_BP1_SHIFT 1 +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_BP1_MASK UINT64_C(0x0000000000000002) +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_BP2_SHIFT 2 +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_BP2_MASK UINT64_C(0x0000000000000004) +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_BP3_SHIFT 3 +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_BP3_MASK UINT64_C(0x0000000000000008) +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_RSVD_4_12_SHIFT 4 +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_RSVD_4_12_MASK UINT64_C(0x0000000000001ff0) +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_BD_SHIFT 13 +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_BD_MASK UINT64_C(0x0000000000002000) +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_BS_SHIFT 14 +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_BS_MASK UINT64_C(0x0000000000004000) +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_RSVD_15_63_SHIFT 15 +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_RSVD_15_63_MASK UINT64_C(0xffffffffffff8000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_EXIT_QUAL_DEBUG_XCPT_, UINT64_C(0), UINT64_MAX, + (BP0, BP1, BP2, BP3, RSVD_4_12, BD, BS, RSVD_15_63)); +/** @} */ + +/** @name Exit qualification for Mov DRx. + * @{ + */ +/** 0-2: Debug register number */ +#define VMX_EXIT_QUAL_DRX_REGISTER(a) ((a) & 7) +/** 3: Reserved; cleared to 0. */ +#define VMX_EXIT_QUAL_DRX_RES1(a) (((a) >> 3) & 1) +/** 4: Direction of move (0 = write, 1 = read) */ +#define VMX_EXIT_QUAL_DRX_DIRECTION(a) (((a) >> 4) & 1) +/** 5-7: Reserved; cleared to 0. */ +#define VMX_EXIT_QUAL_DRX_RES2(a) (((a) >> 5) & 7) +/** 8-11: General purpose register number. */ +#define VMX_EXIT_QUAL_DRX_GENREG(a) (((a) >> 8) & 0xf) + +/** Bit fields for Exit qualification due to Mov DRx. */ +#define VMX_BF_EXIT_QUAL_DRX_REGISTER_SHIFT 0 +#define VMX_BF_EXIT_QUAL_DRX_REGISTER_MASK UINT64_C(0x0000000000000007) +#define VMX_BF_EXIT_QUAL_DRX_RSVD_1_SHIFT 3 +#define VMX_BF_EXIT_QUAL_DRX_RSVD_1_MASK UINT64_C(0x0000000000000008) +#define VMX_BF_EXIT_QUAL_DRX_DIRECTION_SHIFT 4 +#define VMX_BF_EXIT_QUAL_DRX_DIRECTION_MASK UINT64_C(0x0000000000000010) +#define VMX_BF_EXIT_QUAL_DRX_RSVD_5_7_SHIFT 5 +#define VMX_BF_EXIT_QUAL_DRX_RSVD_5_7_MASK UINT64_C(0x00000000000000e0) +#define VMX_BF_EXIT_QUAL_DRX_GENREG_SHIFT 8 +#define VMX_BF_EXIT_QUAL_DRX_GENREG_MASK UINT64_C(0x0000000000000f00) +#define VMX_BF_EXIT_QUAL_DRX_RSVD_12_63_SHIFT 12 +#define VMX_BF_EXIT_QUAL_DRX_RSVD_12_63_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_EXIT_QUAL_DRX_, UINT64_C(0), UINT64_MAX, + (REGISTER, RSVD_1, DIRECTION, RSVD_5_7, GENREG, RSVD_12_63)); +/** @} */ + + +/** @name Exit qualification for debug exceptions types. + * @{ + */ +#define VMX_EXIT_QUAL_DRX_DIRECTION_WRITE 0 +#define VMX_EXIT_QUAL_DRX_DIRECTION_READ 1 +/** @} */ + + +/** @name Exit qualification for control-register accesses. + * @{ + */ +/** 0-3: Control register number (0 for CLTS & LMSW) */ +#define VMX_EXIT_QUAL_CRX_REGISTER(a) ((a) & 0xf) +/** 4-5: Access type. */ +#define VMX_EXIT_QUAL_CRX_ACCESS(a) (((a) >> 4) & 3) +/** 6: LMSW operand type memory (1 for memory, 0 for register). */ +#define VMX_EXIT_QUAL_CRX_LMSW_OP_MEM(a) (((a) >> 6) & 1) +/** 7: Reserved; cleared to 0. */ +#define VMX_EXIT_QUAL_CRX_RES1(a) (((a) >> 7) & 1) +/** 8-11: General purpose register number (0 for CLTS & LMSW). */ +#define VMX_EXIT_QUAL_CRX_GENREG(a) (((a) >> 8) & 0xf) +/** 12-15: Reserved; cleared to 0. */ +#define VMX_EXIT_QUAL_CRX_RES2(a) (((a) >> 12) & 0xf) +/** 16-31: LMSW source data (else 0). */ +#define VMX_EXIT_QUAL_CRX_LMSW_DATA(a) (((a) >> 16) & 0xffff) + +/** Bit fields for Exit qualification for control-register accesses. */ +#define VMX_BF_EXIT_QUAL_CRX_REGISTER_SHIFT 0 +#define VMX_BF_EXIT_QUAL_CRX_REGISTER_MASK UINT64_C(0x000000000000000f) +#define VMX_BF_EXIT_QUAL_CRX_ACCESS_SHIFT 4 +#define VMX_BF_EXIT_QUAL_CRX_ACCESS_MASK UINT64_C(0x0000000000000030) +#define VMX_BF_EXIT_QUAL_CRX_LMSW_OP_SHIFT 6 +#define VMX_BF_EXIT_QUAL_CRX_LMSW_OP_MASK UINT64_C(0x0000000000000040) +#define VMX_BF_EXIT_QUAL_CRX_RSVD_7_SHIFT 7 +#define VMX_BF_EXIT_QUAL_CRX_RSVD_7_MASK UINT64_C(0x0000000000000080) +#define VMX_BF_EXIT_QUAL_CRX_GENREG_SHIFT 8 +#define VMX_BF_EXIT_QUAL_CRX_GENREG_MASK UINT64_C(0x0000000000000f00) +#define VMX_BF_EXIT_QUAL_CRX_RSVD_12_15_SHIFT 12 +#define VMX_BF_EXIT_QUAL_CRX_RSVD_12_15_MASK UINT64_C(0x000000000000f000) +#define VMX_BF_EXIT_QUAL_CRX_LMSW_DATA_SHIFT 16 +#define VMX_BF_EXIT_QUAL_CRX_LMSW_DATA_MASK UINT64_C(0x00000000ffff0000) +#define VMX_BF_EXIT_QUAL_CRX_RSVD_32_63_SHIFT 32 +#define VMX_BF_EXIT_QUAL_CRX_RSVD_32_63_MASK UINT64_C(0xffffffff00000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_EXIT_QUAL_CRX_, UINT64_C(0), UINT64_MAX, + (REGISTER, ACCESS, LMSW_OP, RSVD_7, GENREG, RSVD_12_15, LMSW_DATA, RSVD_32_63)); +/** @} */ + + +/** @name Exit qualification for control-register access types. + * @{ + */ +#define VMX_EXIT_QUAL_CRX_ACCESS_WRITE 0 +#define VMX_EXIT_QUAL_CRX_ACCESS_READ 1 +#define VMX_EXIT_QUAL_CRX_ACCESS_CLTS 2 +#define VMX_EXIT_QUAL_CRX_ACCESS_LMSW 3 +/** @} */ + + +/** @name Exit qualification for task switch. + * @{ + */ +#define VMX_EXIT_QUAL_TASK_SWITCH_SELECTOR(a) ((a) & 0xffff) +#define VMX_EXIT_QUAL_TASK_SWITCH_TYPE(a) (((a) >> 30) & 0x3) +/** Task switch caused by a call instruction. */ +#define VMX_EXIT_QUAL_TASK_SWITCH_TYPE_CALL 0 +/** Task switch caused by an iret instruction. */ +#define VMX_EXIT_QUAL_TASK_SWITCH_TYPE_IRET 1 +/** Task switch caused by a jmp instruction. */ +#define VMX_EXIT_QUAL_TASK_SWITCH_TYPE_JMP 2 +/** Task switch caused by an interrupt gate. */ +#define VMX_EXIT_QUAL_TASK_SWITCH_TYPE_IDT 3 + +/** Bit fields for Exit qualification for task switches. */ +#define VMX_BF_EXIT_QUAL_TASK_SWITCH_NEW_TSS_SHIFT 0 +#define VMX_BF_EXIT_QUAL_TASK_SWITCH_NEW_TSS_MASK UINT64_C(0x000000000000ffff) +#define VMX_BF_EXIT_QUAL_TASK_SWITCH_RSVD_16_29_SHIFT 16 +#define VMX_BF_EXIT_QUAL_TASK_SWITCH_RSVD_16_29_MASK UINT64_C(0x000000003fff0000) +#define VMX_BF_EXIT_QUAL_TASK_SWITCH_SOURCE_SHIFT 30 +#define VMX_BF_EXIT_QUAL_TASK_SWITCH_SOURCE_MASK UINT64_C(0x00000000c0000000) +#define VMX_BF_EXIT_QUAL_TASK_SWITCH_RSVD_32_63_SHIFT 32 +#define VMX_BF_EXIT_QUAL_TASK_SWITCH_RSVD_32_63_MASK UINT64_C(0xffffffff00000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_EXIT_QUAL_TASK_SWITCH_, UINT64_C(0), UINT64_MAX, + (NEW_TSS, RSVD_16_29, SOURCE, RSVD_32_63)); +/** @} */ + + +/** @name Exit qualification for EPT violations. + * @{ + */ +/** Set if acess causing the violation was a data read. */ +#define VMX_EXIT_QUAL_EPT_ACCESS_READ RT_BIT_64(0) +/** Set if acess causing the violation was a data write. */ +#define VMX_EXIT_QUAL_EPT_ACCESS_WRITE RT_BIT_64(1) +/** Set if the violation was caused by an instruction fetch. */ +#define VMX_EXIT_QUAL_EPT_ACCESS_INSTR_FETCH RT_BIT_64(2) +/** AND of the read bit of all EPT structures. */ +#define VMX_EXIT_QUAL_EPT_ENTRY_READ RT_BIT_64(3) +/** AND of the write bit of all EPT structures. */ +#define VMX_EXIT_QUAL_EPT_ENTRY_WRITE RT_BIT_64(4) +/** AND of the execute bit of all EPT structures. */ +#define VMX_EXIT_QUAL_EPT_ENTRY_EXECUTE RT_BIT_64(5) +/** And of the execute bit of all EPT structures for user-mode addresses + * (requires mode-based execute control). */ +#define VMX_EXIT_QUAL_EPT_ENTRY_EXECUTE_USER RT_BIT_64(6) +/** Set if the guest linear address field is valid. */ +#define VMX_EXIT_QUAL_EPT_LINEAR_ADDR_VALID RT_BIT_64(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_QUAL_EPT_LINEAR_TO_PHYS_ADDR RT_BIT_64(8) +/** If bit 7, 8 and advanced VM-exit info. for EPT is one: (reserved otherwise) + * 1 - linear address is user-mode address. + * 0 - linear address is supervisor-mode address. + */ +#define VMX_EXIT_QUAL_EPT_LINEAR_ADDR_USER RT_BIT_64(9) +/** If bit 7, 8 and advanced VM-exit info. for EPT is one: (reserved otherwise) + * 1 - linear address translates to read-only page. + * 0 - linear address translates to read-write page. + */ +#define VMX_EXIT_QUAL_EPT_LINEAR_ADDR_RO RT_BIT_64(10) +/** If bit 7, 8 and advanced VM-exit info. for EPT is one: (reserved otherwise) + * 1 - linear address translates to executable-disabled page. + * 0 - linear address translates to executable page. + */ +#define VMX_EXIT_QUAL_EPT_LINEAR_ADDR_XD RT_BIT_64(11) +/** NMI unblocking due to IRET. */ +#define VMX_EXIT_QUAL_EPT_NMI_UNBLOCK_IRET RT_BIT_64(12) +/** Set if acess causing the violation was a shadow-stack access. */ +#define VMX_EXIT_QUAL_EPT_ACCESS_SHW_STACK RT_BIT_64(13) +/** If supervisor-shadow stack is enabled: (reserved otherwise) + * 1 - supervisor shadow-stack access allowed. + * 0 - supervisor shadow-stack access disallowed. + */ +#define VMX_EXIT_QUAL_EPT_ENTRY_SHW_STACK_SUPER RT_BIT_64(14) +/** Set if access is related to trace output by Intel PT (reserved otherwise). */ +#define VMX_EXIT_QUAL_EPT_ACCESS_PT_TRACE RT_BIT_64(16) + +/** Checks whether NMI unblocking due to IRET. */ +#define VMX_EXIT_QUAL_EPT_IS_NMI_UNBLOCK_IRET(a) (((a) >> 12) & 1) + +/** Bit fields for Exit qualification for EPT violations. */ +#define VMX_BF_EXIT_QUAL_EPT_ACCESS_READ_SHIFT 0 +#define VMX_BF_EXIT_QUAL_EPT_ACCESS_READ_MASK UINT64_C(0x0000000000000001) +#define VMX_BF_EXIT_QUAL_EPT_ACCESS_WRITE_SHIFT 1 +#define VMX_BF_EXIT_QUAL_EPT_ACCESS_WRITE_MASK UINT64_C(0x0000000000000002) +#define VMX_BF_EXIT_QUAL_EPT_ACCESS_INSTR_FETCH_SHIFT 2 +#define VMX_BF_EXIT_QUAL_EPT_ACCESS_INSTR_FETCH_MASK UINT64_C(0x0000000000000004) +#define VMX_BF_EXIT_QUAL_EPT_ENTRY_READ_SHIFT 3 +#define VMX_BF_EXIT_QUAL_EPT_ENTRY_READ_MASK UINT64_C(0x0000000000000008) +#define VMX_BF_EXIT_QUAL_EPT_ENTRY_WRITE_SHIFT 4 +#define VMX_BF_EXIT_QUAL_EPT_ENTRY_WRITE_MASK UINT64_C(0x0000000000000010) +#define VMX_BF_EXIT_QUAL_EPT_ENTRY_EXECUTE_SHIFT 5 +#define VMX_BF_EXIT_QUAL_EPT_ENTRY_EXECUTE_MASK UINT64_C(0x0000000000000020) +#define VMX_BF_EXIT_QUAL_EPT_ENTRY_EXECUTE_USER_SHIFT 6 +#define VMX_BF_EXIT_QUAL_EPT_ENTRY_EXECUTE_USER_MASK UINT64_C(0x0000000000000040) +#define VMX_BF_EXIT_QUAL_EPT_LINEAR_ADDR_VALID_SHIFT 7 +#define VMX_BF_EXIT_QUAL_EPT_LINEAR_ADDR_VALID_MASK UINT64_C(0x0000000000000080) +#define VMX_BF_EXIT_QUAL_EPT_LINEAR_TO_PHYS_ADDR_SHIFT 8 +#define VMX_BF_EXIT_QUAL_EPT_LINEAR_TO_PHYS_ADDR_MASK UINT64_C(0x0000000000000100) +#define VMX_BF_EXIT_QUAL_EPT_LINEAR_ADDR_USER_SHIFT 9 +#define VMX_BF_EXIT_QUAL_EPT_LINEAR_ADDR_USER_MASK UINT64_C(0x0000000000000200) +#define VMX_BF_EXIT_QUAL_EPT_LINEAR_ADDR_RO_SHIFT 10 +#define VMX_BF_EXIT_QUAL_EPT_LINEAR_ADDR_RO_MASK UINT64_C(0x0000000000000400) +#define VMX_BF_EXIT_QUAL_EPT_LINEAR_ADDR_XD_SHIFT 11 +#define VMX_BF_EXIT_QUAL_EPT_LINEAR_ADDR_XD_MASK UINT64_C(0x0000000000000800) +#define VMX_BF_EXIT_QUAL_EPT_NMI_UNBLOCK_IRET_SHIFT 12 +#define VMX_BF_EXIT_QUAL_EPT_NMI_UNBLOCK_IRET_MASK UINT64_C(0x0000000000001000) +#define VMX_BF_EXIT_QUAL_EPT_ACCESS_SHW_STACK_SHIFT 13 +#define VMX_BF_EXIT_QUAL_EPT_ACCESS_SHW_STACK_MASK UINT64_C(0x0000000000002000) +#define VMX_BF_EXIT_QUAL_EPT_ENTRY_SHW_STACK_SUPER_SHIFT 14 +#define VMX_BF_EXIT_QUAL_EPT_ENTRY_SHW_STACK_SUPER_MASK UINT64_C(0x0000000000004000) +#define VMX_BF_EXIT_QUAL_EPT_RSVD_15_SHIFT 15 +#define VMX_BF_EXIT_QUAL_EPT_RSVD_15_MASK UINT64_C(0x0000000000008000) +#define VMX_BF_EXIT_QUAL_EPT_ACCESS_PT_TRACE_SHIFT 16 +#define VMX_BF_EXIT_QUAL_EPT_ACCESS_PT_TRACE_MASK UINT64_C(0x0000000000010000) +#define VMX_BF_EXIT_QUAL_EPT_RSVD_17_63_SHIFT 17 +#define VMX_BF_EXIT_QUAL_EPT_RSVD_17_63_MASK UINT64_C(0xfffffffffffe0000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_EXIT_QUAL_EPT_, UINT64_C(0), UINT64_MAX, + (ACCESS_READ, ACCESS_WRITE, ACCESS_INSTR_FETCH, ENTRY_READ, ENTRY_WRITE, ENTRY_EXECUTE, + ENTRY_EXECUTE_USER, LINEAR_ADDR_VALID, LINEAR_TO_PHYS_ADDR, LINEAR_ADDR_USER, LINEAR_ADDR_RO, + LINEAR_ADDR_XD, NMI_UNBLOCK_IRET, ACCESS_SHW_STACK, ENTRY_SHW_STACK_SUPER, RSVD_15, + ACCESS_PT_TRACE, RSVD_17_63)); +/** @} */ + + +/** @name Exit qualification for I/O instructions. + * @{ + */ +/** 0-2: IO operation size 0(=1 byte), 1(=2 bytes) and 3(=4 bytes). */ +#define VMX_EXIT_QUAL_IO_SIZE(a) ((a) & 7) +/** 3: IO operation direction. */ +#define VMX_EXIT_QUAL_IO_DIRECTION(a) (((a) >> 3) & 1) +/** 4: String IO operation (INS / OUTS). */ +#define VMX_EXIT_QUAL_IO_IS_STRING(a) (((a) >> 4) & 1) +/** 5: Repeated IO operation. */ +#define VMX_EXIT_QUAL_IO_IS_REP(a) (((a) >> 5) & 1) +/** 6: Operand encoding. */ +#define VMX_EXIT_QUAL_IO_ENCODING(a) (((a) >> 6) & 1) +/** 16-31: IO Port (0-0xffff). */ +#define VMX_EXIT_QUAL_IO_PORT(a) (((a) >> 16) & 0xffff) + +/** Bit fields for Exit qualification for I/O instructions. */ +#define VMX_BF_EXIT_QUAL_IO_WIDTH_SHIFT 0 +#define VMX_BF_EXIT_QUAL_IO_WIDTH_MASK UINT64_C(0x0000000000000007) +#define VMX_BF_EXIT_QUAL_IO_DIRECTION_SHIFT 3 +#define VMX_BF_EXIT_QUAL_IO_DIRECTION_MASK UINT64_C(0x0000000000000008) +#define VMX_BF_EXIT_QUAL_IO_IS_STRING_SHIFT 4 +#define VMX_BF_EXIT_QUAL_IO_IS_STRING_MASK UINT64_C(0x0000000000000010) +#define VMX_BF_EXIT_QUAL_IO_IS_REP_SHIFT 5 +#define VMX_BF_EXIT_QUAL_IO_IS_REP_MASK UINT64_C(0x0000000000000020) +#define VMX_BF_EXIT_QUAL_IO_ENCODING_SHIFT 6 +#define VMX_BF_EXIT_QUAL_IO_ENCODING_MASK UINT64_C(0x0000000000000040) +#define VMX_BF_EXIT_QUAL_IO_RSVD_7_15_SHIFT 7 +#define VMX_BF_EXIT_QUAL_IO_RSVD_7_15_MASK UINT64_C(0x000000000000ff80) +#define VMX_BF_EXIT_QUAL_IO_PORT_SHIFT 16 +#define VMX_BF_EXIT_QUAL_IO_PORT_MASK UINT64_C(0x00000000ffff0000) +#define VMX_BF_EXIT_QUAL_IO_RSVD_32_63_SHIFT 32 +#define VMX_BF_EXIT_QUAL_IO_RSVD_32_63_MASK UINT64_C(0xffffffff00000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_EXIT_QUAL_IO_, UINT64_C(0), UINT64_MAX, + (WIDTH, DIRECTION, IS_STRING, IS_REP, ENCODING, RSVD_7_15, PORT, RSVD_32_63)); +/** @} */ + + +/** @name Exit qualification for I/O instruction types. + * @{ + */ +#define VMX_EXIT_QUAL_IO_DIRECTION_OUT 0 +#define VMX_EXIT_QUAL_IO_DIRECTION_IN 1 +/** @} */ + + +/** @name Exit qualification for I/O instruction encoding. + * @{ + */ +#define VMX_EXIT_QUAL_IO_ENCODING_DX 0 +#define VMX_EXIT_QUAL_IO_ENCODING_IMM 1 +/** @} */ + + +/** @name Exit qualification for APIC-access VM-exits from linear and + * guest-physical accesses. + * @{ + */ +/** 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_QUAL_APIC_ACCESS_OFFSET(a) ((a) & 0xfff) +/** 12-15: Access type. */ +#define VMX_EXIT_QUAL_APIC_ACCESS_TYPE(a) (((a) & 0xf000) >> 12) +/* Rest reserved. */ + +/** Bit fields for Exit qualification for APIC-access VM-exits. */ +#define VMX_BF_EXIT_QUAL_APIC_ACCESS_OFFSET_SHIFT 0 +#define VMX_BF_EXIT_QUAL_APIC_ACCESS_OFFSET_MASK UINT64_C(0x0000000000000fff) +#define VMX_BF_EXIT_QUAL_APIC_ACCESS_TYPE_SHIFT 12 +#define VMX_BF_EXIT_QUAL_APIC_ACCESS_TYPE_MASK UINT64_C(0x000000000000f000) +#define VMX_BF_EXIT_QUAL_APIC_ACCESS_RSVD_16_63_SHIFT 16 +#define VMX_BF_EXIT_QUAL_APIC_ACCESS_RSVD_16_63_MASK UINT64_C(0xffffffffffff0000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_EXIT_QUAL_APIC_ACCESS_, UINT64_C(0), UINT64_MAX, + (OFFSET, TYPE, RSVD_16_63)); +/** @} */ + + +/** @name Exit qualification for linear address APIC-access types. + * @{ + */ +/** Linear access for a data read during instruction execution. */ +#define VMX_APIC_ACCESS_TYPE_LINEAR_READ 0 +/** Linear access for a data write during instruction execution. */ +#define VMX_APIC_ACCESS_TYPE_LINEAR_WRITE 1 +/** Linear access for an instruction fetch. */ +#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 + +/** + * APIC-access type. + * In accordance with the VT-x spec. + */ +typedef enum +{ + VMXAPICACCESS_LINEAR_READ = VMX_APIC_ACCESS_TYPE_LINEAR_READ, + VMXAPICACCESS_LINEAR_WRITE = VMX_APIC_ACCESS_TYPE_LINEAR_WRITE, + VMXAPICACCESS_LINEAR_INSTR_FETCH = VMX_APIC_ACCESS_TYPE_LINEAR_INSTR_FETCH, + VMXAPICACCESS_LINEAR_EVENT_DELIVERY = VMX_APIC_ACCESS_TYPE_LINEAR_EVENT_DELIVERY, + VMXAPICACCESS_PHYSICAL_EVENT_DELIVERY = VMX_APIC_ACCESS_TYPE_PHYSICAL_EVENT_DELIVERY, + VMXAPICACCESS_PHYSICAL_INSTR = VMX_APIC_ACCESS_TYPE_PHYSICAL_INSTR +} VMXAPICACCESS; +AssertCompileSize(VMXAPICACCESS, 4); +/** @} */ + + +/** @name VMX_BF_XXTR_INSINFO_XXX - VMX_EXIT_XDTR_ACCESS instruction information. + * Found in VMX_VMCS32_RO_EXIT_INSTR_INFO. + * @{ + */ +/** Address calculation scaling field (powers of two). */ +#define VMX_BF_XDTR_INSINFO_SCALE_SHIFT 0 +#define VMX_BF_XDTR_INSINFO_SCALE_MASK UINT32_C(0x00000003) +/** Bits 2 thru 6 are undefined. */ +#define VMX_BF_XDTR_INSINFO_UNDEF_2_6_SHIFT 2 +#define VMX_BF_XDTR_INSINFO_UNDEF_2_6_MASK UINT32_C(0x0000007c) +/** Address size, only 0(=16), 1(=32) and 2(=64) are defined. + * @remarks anyone's guess why this is a 3 bit field... */ +#define VMX_BF_XDTR_INSINFO_ADDR_SIZE_SHIFT 7 +#define VMX_BF_XDTR_INSINFO_ADDR_SIZE_MASK UINT32_C(0x00000380) +/** Bit 10 is defined as zero. */ +#define VMX_BF_XDTR_INSINFO_ZERO_10_SHIFT 10 +#define VMX_BF_XDTR_INSINFO_ZERO_10_MASK UINT32_C(0x00000400) +/** Operand size, either (1=)32-bit or (0=)16-bit, but get this, it's undefined + * for exits from 64-bit code as the operand size there is fixed. */ +#define VMX_BF_XDTR_INSINFO_OP_SIZE_SHIFT 11 +#define VMX_BF_XDTR_INSINFO_OP_SIZE_MASK UINT32_C(0x00000800) +/** Bits 12 thru 14 are undefined. */ +#define VMX_BF_XDTR_INSINFO_UNDEF_12_14_SHIFT 12 +#define VMX_BF_XDTR_INSINFO_UNDEF_12_14_MASK UINT32_C(0x00007000) +/** Applicable segment register (X86_SREG_XXX values). */ +#define VMX_BF_XDTR_INSINFO_SREG_SHIFT 15 +#define VMX_BF_XDTR_INSINFO_SREG_MASK UINT32_C(0x00038000) +/** Index register (X86_GREG_XXX values). Undefined if HAS_INDEX_REG is clear. */ +#define VMX_BF_XDTR_INSINFO_INDEX_REG_SHIFT 18 +#define VMX_BF_XDTR_INSINFO_INDEX_REG_MASK UINT32_C(0x003c0000) +/** Is VMX_BF_XDTR_INSINFO_INDEX_REG_XXX valid (=1) or not (=0). */ +#define VMX_BF_XDTR_INSINFO_HAS_INDEX_REG_SHIFT 22 +#define VMX_BF_XDTR_INSINFO_HAS_INDEX_REG_MASK UINT32_C(0x00400000) +/** Base register (X86_GREG_XXX values). Undefined if HAS_BASE_REG is clear. */ +#define VMX_BF_XDTR_INSINFO_BASE_REG_SHIFT 23 +#define VMX_BF_XDTR_INSINFO_BASE_REG_MASK UINT32_C(0x07800000) +/** Is VMX_XDTR_INSINFO_BASE_REG_XXX valid (=1) or not (=0). */ +#define VMX_BF_XDTR_INSINFO_HAS_BASE_REG_SHIFT 27 +#define VMX_BF_XDTR_INSINFO_HAS_BASE_REG_MASK UINT32_C(0x08000000) +/** The instruction identity (VMX_XDTR_INSINFO_II_XXX values). */ +#define VMX_BF_XDTR_INSINFO_INSTR_ID_SHIFT 28 +#define VMX_BF_XDTR_INSINFO_INSTR_ID_MASK UINT32_C(0x30000000) +#define VMX_XDTR_INSINFO_II_SGDT 0 /**< Instruction ID: SGDT */ +#define VMX_XDTR_INSINFO_II_SIDT 1 /**< Instruction ID: SIDT */ +#define VMX_XDTR_INSINFO_II_LGDT 2 /**< Instruction ID: LGDT */ +#define VMX_XDTR_INSINFO_II_LIDT 3 /**< Instruction ID: LIDT */ +/** Bits 30 & 31 are undefined. */ +#define VMX_BF_XDTR_INSINFO_UNDEF_30_31_SHIFT 30 +#define VMX_BF_XDTR_INSINFO_UNDEF_30_31_MASK UINT32_C(0xc0000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_XDTR_INSINFO_, UINT32_C(0), UINT32_MAX, + (SCALE, UNDEF_2_6, ADDR_SIZE, ZERO_10, OP_SIZE, UNDEF_12_14, SREG, INDEX_REG, HAS_INDEX_REG, + BASE_REG, HAS_BASE_REG, INSTR_ID, UNDEF_30_31)); +/** @} */ + + +/** @name VMX_BF_YYTR_INSINFO_XXX - VMX_EXIT_TR_ACCESS instruction information. + * Found in VMX_VMCS32_RO_EXIT_INSTR_INFO. + * This is similar to VMX_BF_XDTR_INSINFO_XXX. + * @{ + */ +/** Address calculation scaling field (powers of two). */ +#define VMX_BF_YYTR_INSINFO_SCALE_SHIFT 0 +#define VMX_BF_YYTR_INSINFO_SCALE_MASK UINT32_C(0x00000003) +/** Bit 2 is undefined. */ +#define VMX_BF_YYTR_INSINFO_UNDEF_2_SHIFT 2 +#define VMX_BF_YYTR_INSINFO_UNDEF_2_MASK UINT32_C(0x00000004) +/** Register operand 1. Undefined if VMX_YYTR_INSINFO_HAS_REG1 is clear. */ +#define VMX_BF_YYTR_INSINFO_REG1_SHIFT 3 +#define VMX_BF_YYTR_INSINFO_REG1_MASK UINT32_C(0x00000078) +/** Address size, only 0(=16), 1(=32) and 2(=64) are defined. + * @remarks anyone's guess why this is a 3 bit field... */ +#define VMX_BF_YYTR_INSINFO_ADDR_SIZE_SHIFT 7 +#define VMX_BF_YYTR_INSINFO_ADDR_SIZE_MASK UINT32_C(0x00000380) +/** Is VMX_YYTR_INSINFO_REG1_XXX valid (=1) or not (=0). */ +#define VMX_BF_YYTR_INSINFO_HAS_REG1_SHIFT 10 +#define VMX_BF_YYTR_INSINFO_HAS_REG1_MASK UINT32_C(0x00000400) +/** Bits 11 thru 14 are undefined. */ +#define VMX_BF_YYTR_INSINFO_UNDEF_11_14_SHIFT 11 +#define VMX_BF_YYTR_INSINFO_UNDEF_11_14_MASK UINT32_C(0x00007800) +/** Applicable segment register (X86_SREG_XXX values). */ +#define VMX_BF_YYTR_INSINFO_SREG_SHIFT 15 +#define VMX_BF_YYTR_INSINFO_SREG_MASK UINT32_C(0x00038000) +/** Index register (X86_GREG_XXX values). Undefined if HAS_INDEX_REG is clear. */ +#define VMX_BF_YYTR_INSINFO_INDEX_REG_SHIFT 18 +#define VMX_BF_YYTR_INSINFO_INDEX_REG_MASK UINT32_C(0x003c0000) +/** Is VMX_YYTR_INSINFO_INDEX_REG_XXX valid (=1) or not (=0). */ +#define VMX_BF_YYTR_INSINFO_HAS_INDEX_REG_SHIFT 22 +#define VMX_BF_YYTR_INSINFO_HAS_INDEX_REG_MASK UINT32_C(0x00400000) +/** Base register (X86_GREG_XXX values). Undefined if HAS_BASE_REG is clear. */ +#define VMX_BF_YYTR_INSINFO_BASE_REG_SHIFT 23 +#define VMX_BF_YYTR_INSINFO_BASE_REG_MASK UINT32_C(0x07800000) +/** Is VMX_YYTR_INSINFO_BASE_REG_XXX valid (=1) or not (=0). */ +#define VMX_BF_YYTR_INSINFO_HAS_BASE_REG_SHIFT 27 +#define VMX_BF_YYTR_INSINFO_HAS_BASE_REG_MASK UINT32_C(0x08000000) +/** The instruction identity (VMX_YYTR_INSINFO_II_XXX values) */ +#define VMX_BF_YYTR_INSINFO_INSTR_ID_SHIFT 28 +#define VMX_BF_YYTR_INSINFO_INSTR_ID_MASK UINT32_C(0x30000000) +#define VMX_YYTR_INSINFO_II_SLDT 0 /**< Instruction ID: SLDT */ +#define VMX_YYTR_INSINFO_II_STR 1 /**< Instruction ID: STR */ +#define VMX_YYTR_INSINFO_II_LLDT 2 /**< Instruction ID: LLDT */ +#define VMX_YYTR_INSINFO_II_LTR 3 /**< Instruction ID: LTR */ +/** Bits 30 & 31 are undefined. */ +#define VMX_BF_YYTR_INSINFO_UNDEF_30_31_SHIFT 30 +#define VMX_BF_YYTR_INSINFO_UNDEF_30_31_MASK UINT32_C(0xc0000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_YYTR_INSINFO_, UINT32_C(0), UINT32_MAX, + (SCALE, UNDEF_2, REG1, ADDR_SIZE, HAS_REG1, UNDEF_11_14, SREG, INDEX_REG, HAS_INDEX_REG, + BASE_REG, HAS_BASE_REG, INSTR_ID, UNDEF_30_31)); +/** @} */ + + +/** @name Format of Pending-Debug-Exceptions. + * Bits 4-11, 13, 15 and 17-63 are reserved. + * Similar to DR6 except bit 12 (breakpoint enabled) and bit 16 (RTM) are both + * possibly valid here but not in DR6. + * @{ + */ +/** Hardware breakpoint 0 was met. */ +#define VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_BP0 RT_BIT_64(0) +/** Hardware breakpoint 1 was met. */ +#define VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_BP1 RT_BIT_64(1) +/** Hardware breakpoint 2 was met. */ +#define VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_BP2 RT_BIT_64(2) +/** Hardware breakpoint 3 was met. */ +#define VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_BP3 RT_BIT_64(3) +/** At least one data or IO breakpoint was hit. */ +#define VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_EN_BP RT_BIT_64(12) +/** A debug exception would have been triggered by single-step execution mode. */ +#define VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_BS RT_BIT_64(14) +/** A debug exception occurred inside an RTM region. */ +#define VMX_VMCS_GUEST_PENDING_DEBUG_RTM RT_BIT_64(16) +/** Mask of valid bits. */ +#define VMX_VMCS_GUEST_PENDING_DEBUG_VALID_MASK ( VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_BP0 \ + | VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_BP1 \ + | VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_BP2 \ + | VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_BP3 \ + | VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_EN_BP \ + | VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_BS \ + | VMX_VMCS_GUEST_PENDING_DEBUG_RTM) +#define VMX_VMCS_GUEST_PENDING_DEBUG_RTM_MASK ( VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_EN_BP \ + | VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_BS \ + | VMX_VMCS_GUEST_PENDING_DEBUG_RTM) +/** Bit fields for Pending debug exceptions. */ +#define VMX_BF_VMCS_PENDING_DBG_XCPT_BP0_SHIFT 0 +#define VMX_BF_VMCS_PENDING_DBG_XCPT_BP0_MASK UINT64_C(0x0000000000000001) +#define VMX_BF_VMCS_PENDING_DBG_XCPT_BP1_SHIFT 1 +#define VMX_BF_VMCS_PENDING_DBG_XCPT_BP1_MASK UINT64_C(0x0000000000000002) +#define VMX_BF_VMCS_PENDING_DBG_XCPT_BP2_SHIFT 2 +#define VMX_BF_VMCS_PENDING_DBG_XCPT_BP2_MASK UINT64_C(0x0000000000000004) +#define VMX_BF_VMCS_PENDING_DBG_XCPT_BP3_SHIFT 3 +#define VMX_BF_VMCS_PENDING_DBG_XCPT_BP3_MASK UINT64_C(0x0000000000000008) +#define VMX_BF_VMCS_PENDING_DBG_XCPT_RSVD_4_11_SHIFT 4 +#define VMX_BF_VMCS_PENDING_DBG_XCPT_RSVD_4_11_MASK UINT64_C(0x0000000000000ff0) +#define VMX_BF_VMCS_PENDING_DBG_XCPT_EN_BP_SHIFT 12 +#define VMX_BF_VMCS_PENDING_DBG_XCPT_EN_BP_MASK UINT64_C(0x0000000000001000) +#define VMX_BF_VMCS_PENDING_DBG_XCPT_RSVD_13_SHIFT 13 +#define VMX_BF_VMCS_PENDING_DBG_XCPT_RSVD_13_MASK UINT64_C(0x0000000000002000) +#define VMX_BF_VMCS_PENDING_DBG_XCPT_BS_SHIFT 14 +#define VMX_BF_VMCS_PENDING_DBG_XCPT_BS_MASK UINT64_C(0x0000000000004000) +#define VMX_BF_VMCS_PENDING_DBG_XCPT_RSVD_15_SHIFT 15 +#define VMX_BF_VMCS_PENDING_DBG_XCPT_RSVD_15_MASK UINT64_C(0x0000000000008000) +#define VMX_BF_VMCS_PENDING_DBG_XCPT_RTM_SHIFT 16 +#define VMX_BF_VMCS_PENDING_DBG_XCPT_RTM_MASK UINT64_C(0x0000000000010000) +#define VMX_BF_VMCS_PENDING_DBG_XCPT_RSVD_17_63_SHIFT 17 +#define VMX_BF_VMCS_PENDING_DBG_XCPT_RSVD_17_63_MASK UINT64_C(0xfffffffffffe0000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_VMCS_PENDING_DBG_XCPT_, UINT64_C(0), UINT64_MAX, + (BP0, BP1, BP2, BP3, RSVD_4_11, EN_BP, RSVD_13, BS, RSVD_15, RTM, RSVD_17_63)); +/** @} */ + + +/** + * VM-exit auxiliary information. + * + * This includes information that isn't necessarily stored in the guest-CPU + * context but provided as part of VM-exits. + */ +typedef struct +{ + /** The VM-exit reason. */ + uint32_t uReason; + /** The Exit qualification field. */ + uint64_t u64Qual; + /** The Guest-linear address field. */ + uint64_t u64GuestLinearAddr; + /** The Guest-physical address field. */ + uint64_t u64GuestPhysAddr; + /** The guest pending-debug exceptions. */ + uint64_t u64GuestPendingDbgXcpts; + /** The VM-exit instruction length. */ + uint32_t cbInstr; + /** The VM-exit instruction information. */ + VMXEXITINSTRINFO InstrInfo; + /** VM-exit interruption information. */ + uint32_t uExitIntInfo; + /** VM-exit interruption error code. */ + uint32_t uExitIntErrCode; + /** IDT-vectoring information. */ + uint32_t uIdtVectoringInfo; + /** IDT-vectoring error code. */ + uint32_t uIdtVectoringErrCode; +} VMXEXITAUX; +/** Pointer to a VMXEXITAUX struct. */ +typedef VMXEXITAUX *PVMXEXITAUX; +/** Pointer to a const VMXEXITAUX struct. */ +typedef const VMXEXITAUX *PCVMXEXITAUX; + + +/** @defgroup grp_hm_vmx_virt VMX virtualization. + * @{ + */ + +/** @name Virtual VMX MSR - Miscellaneous data. + * @{ */ +/** Number of CR3-target values supported. */ +#define VMX_V_CR3_TARGET_COUNT 4 +/** Activity states supported. */ +#define VMX_V_GUEST_ACTIVITY_STATE_MASK (VMX_VMCS_GUEST_ACTIVITY_HLT | VMX_VMCS_GUEST_ACTIVITY_SHUTDOWN) +/** VMX preemption-timer shift (Core i7-2600 taken as reference). */ +#define VMX_V_PREEMPT_TIMER_SHIFT 5 +/** Maximum number of MSRs in the auto-load/store MSR areas, (n+1) * 512. */ +#define VMX_V_AUTOMSR_COUNT_MAX 0 +/** SMM MSEG revision ID. */ +#define VMX_V_MSEG_REV_ID 0 +/** @} */ + +/** @name VMX_V_VMCS_STATE_XXX - Virtual VMCS launch state. + * @{ */ +/** VMCS launch state clear. */ +#define VMX_V_VMCS_LAUNCH_STATE_CLEAR RT_BIT(0) +/** VMCS launch state active. */ +#define VMX_V_VMCS_LAUNCH_STATE_ACTIVE RT_BIT(1) +/** VMCS launch state current. */ +#define VMX_V_VMCS_LAUNCH_STATE_CURRENT RT_BIT(2) +/** VMCS launch state launched. */ +#define VMX_V_VMCS_LAUNCH_STATE_LAUNCHED RT_BIT(3) +/** The mask of valid VMCS launch states. */ +#define VMX_V_VMCS_LAUNCH_STATE_MASK ( VMX_V_VMCS_LAUNCH_STATE_CLEAR \ + | VMX_V_VMCS_LAUNCH_STATE_ACTIVE \ + | VMX_V_VMCS_LAUNCH_STATE_CURRENT \ + | VMX_V_VMCS_LAUNCH_STATE_LAUNCHED) +/** @} */ + +/** CR0 bits set here must always be set when in VMX operation. */ +#define VMX_V_CR0_FIXED0 (X86_CR0_PE | X86_CR0_NE | X86_CR0_PG) +/** CR0 bits set here must always be set when in VMX non-root operation with + * unrestricted-guest control enabled. */ +#define VMX_V_CR0_FIXED0_UX (X86_CR0_NE) +/** CR0 bits cleared here must always be cleared when in VMX operation. */ +#define VMX_V_CR0_FIXED1 UINT32_C(0xffffffff) +/** CR4 bits set here must always be set when in VMX operation. */ +#define VMX_V_CR4_FIXED0 (X86_CR4_VMXE) + +/** Virtual VMCS revision ID. Bump this arbitarily chosen identifier if incompatible + * changes to the layout of VMXVVMCS is done. Bit 31 MBZ. */ +#define VMX_V_VMCS_REVISION_ID UINT32_C(0x40000001) +AssertCompile(!(VMX_V_VMCS_REVISION_ID & RT_BIT(31))); + +/** The size of the virtual VMCS region (we use the maximum allowed size to avoid + * complications when teleporation may be implemented). */ +#define VMX_V_VMCS_SIZE X86_PAGE_4K_SIZE +/** The size of the virtual VMCS region (in pages). */ +#define VMX_V_VMCS_PAGES 1 + +/** The size of the virtual shadow VMCS region. */ +#define VMX_V_SHADOW_VMCS_SIZE VMX_V_VMCS_SIZE +/** The size of the virtual shadow VMCS region (in pages). */ +#define VMX_V_SHADOW_VMCS_PAGES VMX_V_VMCS_PAGES + +/** The size of the Virtual-APIC page (in bytes). */ +#define VMX_V_VIRT_APIC_SIZE X86_PAGE_4K_SIZE +/** The size of the Virtual-APIC page (in pages). */ +#define VMX_V_VIRT_APIC_PAGES 1 + +/** The size of the VMREAD/VMWRITE bitmap (in bytes). */ +#define VMX_V_VMREAD_VMWRITE_BITMAP_SIZE X86_PAGE_4K_SIZE +/** The size of the VMREAD/VMWRITE-bitmap (in pages). */ +#define VMX_V_VMREAD_VMWRITE_BITMAP_PAGES 1 + +/** The size of the MSR bitmap (in bytes). */ +#define VMX_V_MSR_BITMAP_SIZE X86_PAGE_4K_SIZE +/** The size of the MSR bitmap (in pages). */ +#define VMX_V_MSR_BITMAP_PAGES 1 + +/** The size of I/O bitmap A (in bytes). */ +#define VMX_V_IO_BITMAP_A_SIZE X86_PAGE_4K_SIZE +/** The size of I/O bitmap A (in pages). */ +#define VMX_V_IO_BITMAP_A_PAGES 1 + +/** The size of I/O bitmap B (in bytes). */ +#define VMX_V_IO_BITMAP_B_SIZE X86_PAGE_4K_SIZE +/** The size of I/O bitmap B (in pages). */ +#define VMX_V_IO_BITMAP_B_PAGES 1 + +/** The size of the auto-load/store MSR area (in bytes). */ +#define VMX_V_AUTOMSR_AREA_SIZE ((512 * (VMX_V_AUTOMSR_COUNT_MAX + 1)) * sizeof(VMXAUTOMSR)) +/* Assert that the size is page aligned or adjust the VMX_V_AUTOMSR_AREA_PAGES macro below. */ +AssertCompile(RT_ALIGN_Z(VMX_V_AUTOMSR_AREA_SIZE, X86_PAGE_4K_SIZE) == VMX_V_AUTOMSR_AREA_SIZE); +/** The size of the auto-load/store MSR area (in pages). */ +#define VMX_V_AUTOMSR_AREA_PAGES ((VMX_V_AUTOMSR_AREA_SIZE) >> X86_PAGE_4K_SHIFT) + +/** The highest index value used for supported virtual VMCS field encoding. */ +#define VMX_V_VMCS_MAX_INDEX RT_BF_GET(VMX_VMCS64_CTRL_EXIT2_HIGH, VMX_BF_VMCSFIELD_INDEX) + +/** + * Virtual VM-exit information. + * + * This is a convenience structure that bundles some VM-exit information related + * fields together. + */ +typedef struct +{ + /** The VM-exit reason. */ + uint32_t uReason; + /** The VM-exit instruction length. */ + uint32_t cbInstr; + /** The VM-exit instruction information. */ + VMXEXITINSTRINFO InstrInfo; + /** The VM-exit instruction ID. */ + VMXINSTRID uInstrId; + + /** The Exit qualification field. */ + uint64_t u64Qual; + /** The Guest-linear address field. */ + uint64_t u64GuestLinearAddr; + /** The Guest-physical address field. */ + uint64_t u64GuestPhysAddr; + /** The guest pending-debug exceptions. */ + uint64_t u64GuestPendingDbgXcpts; + /** The effective guest-linear address if @a InstrInfo indicates a memory-based + * instruction VM-exit. */ + RTGCPTR GCPtrEffAddr; +} VMXVEXITINFO; +/** Pointer to the VMXVEXITINFO struct. */ +typedef VMXVEXITINFO *PVMXVEXITINFO; +/** Pointer to a const VMXVEXITINFO struct. */ +typedef const VMXVEXITINFO *PCVMXVEXITINFO; +AssertCompileMemberAlignment(VMXVEXITINFO, u64Qual, 8); + +/** Initialize a VMXVEXITINFO structure from only an exit reason. */ +#define VMXVEXITINFO_INIT_ONLY_REASON(a_uReason) \ + { (a_uReason), 0, { 0 }, VMXINSTRID_NONE, 0, 0, 0, 0, 0 } + +/** Initialize a VMXVEXITINFO structure from exit reason and instruction length (no info). */ +#define VMXVEXITINFO_INIT_WITH_INSTR_LEN(a_uReason, a_cbInstr) \ + { (a_uReason), (a_cbInstr), { 0 }, VMXINSTRID_NONE, 0, 0, 0, 0, 0 } + +/** Initialize a VMXVEXITINFO structure from exit reason and exit qualification. */ +#define VMXVEXITINFO_INIT_WITH_QUAL(a_uReason, a_uQual) \ + { (a_uReason), 0, { 0 }, VMXINSTRID_NONE, (a_uQual), 0, 0, 0, 0 } + +/** Initialize a VMXVEXITINFO structure from exit reason, exit qualification, + * instruction info and length. */ +#define VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_INFO(a_uReason, a_uQual, a_uInstrInfo, a_cbInstr) \ + { (a_uReason), (a_cbInstr), { a_uInstrInfo }, VMXINSTRID_NONE, (a_uQual), 0, 0, 0, 0 } + +/** Initialize a VMXVEXITINFO structure from exit reason, exit qualification, + * instruction info and length all copied from a VMXTRANSIENT structure. */ +#define VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_INFO_FROM_TRANSIENT(a_pVmxTransient) \ + VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_INFO((a_pVmxTransient)->uExitReason, \ + (a_pVmxTransient)->uExitQual, \ + (a_pVmxTransient)->ExitInstrInfo.u, \ + (a_pVmxTransient)->cbExitInstr) + +/** Initialize a VMXVEXITINFO structure from exit reason, exit qualification, + * instruction length (no info). */ +#define VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_LEN(a_uReason, a_uQual, a_cbInstr) \ + { (a_uReason), (a_cbInstr), { 0 }, VMXINSTRID_NONE, (a_uQual), 0, 0, 0, 0 } + +/** Initialize a VMXVEXITINFO structure from exit reason, exit qualification and + * instruction length (no info) all copied from a VMXTRANSIENT structure. */ +#define VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_LEN_FROM_TRANSIENT(a_pVmxTransient) \ + VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_LEN((a_pVmxTransient)->uExitReason, \ + (a_pVmxTransient)->uExitQual, \ + (a_pVmxTransient)->cbExitInstr) + +/** Initialize a VMXVEXITINFO structure from exit reason, exit qualification, + * instruction info, instruction length and guest linear address. */ +#define VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_INFO_AND_LIN_ADDR(a_uReason, a_uQual, a_uInstrInfo, \ + a_cbInstr, a_uGstLinAddr) \ + { (a_uReason), (a_cbInstr), { (a_uInstrInfo) }, VMXINSTRID_NONE, (a_uQual), (a_uGstLinAddr), 0, 0, 0 } + +/** Initialize a VMXVEXITINFO structure from exit reason, exit qualification, + * instruction info, instruction length and guest linear address all copied + * from a VMXTRANSIENT structure. */ +#define VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_INFO_AND_LIN_ADDR_FROM_TRANSIENT(a_pVmxTransient) \ + VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_INFO_AND_LIN_ADDR((a_pVmxTransient)->uExitReason, \ + (a_pVmxTransient)->uExitQual, \ + (a_pVmxTransient)->ExitInstrInfo.u, \ + (a_pVmxTransient)->cbExitInstr, \ + (a_pVmxTransient)->uGuestLinearAddr) + +/** Initialize a VMXVEXITINFO structure from exit reason and pending debug + * exceptions. */ +#define VMXVEXITINFO_INIT_WITH_DBG_XCPTS(a_uReason, a_uPendingDbgXcpts) \ + { (a_uReason), 0, { 0 }, VMXINSTRID_NONE, 0, 0, 0, (a_uPendingDbgXcpts), 0 } + +/** Initialize a VMXVEXITINFO structure from exit reason and pending debug + * exceptions both copied from a VMXTRANSIENT structure. */ +#define VMXVEXITINFO_INIT_WITH_DBG_XCPTS_FROM_TRANSIENT(a_pVmxTransient) \ + VMXVEXITINFO_INIT_WITH_DBG_XCPTS((a_pVmxTransient)->uExitReason, (a_pVmxTransient)->uGuestPendingDbgXcpts) + + +/** Initialize a VMXVEXITINFO structure from exit reason, exit qualification, + * instruction length, guest linear address and guest physical address. */ +#define VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_LEN_AND_GST_ADDRESSES(a_uReason, a_uQual, a_cbInstr, \ + a_uGstLinAddr, a_uGstPhysAddr) \ + { (a_uReason), (a_cbInstr), { 0 }, VMXINSTRID_NONE, (a_uQual), (a_uGstLinAddr), (a_uGstPhysAddr), 0, 0 } + + +/** + * Virtual VM-exit information for events. + * + * This is a convenience structure that bundles some event-based VM-exit information + * related fields together that are not included in VMXVEXITINFO. + * + * This is kept as a separate structure and not included in VMXVEXITINFO, to make it + * easier to distinguish that IEM VM-exit handlers will set one or more of the + * following fields in the virtual VMCS. Including it in the VMXVEXITINFO will not + * make it ovbious which fields may get set (or cleared). + */ +typedef struct +{ + /** VM-exit interruption information. */ + uint32_t uExitIntInfo; + /** VM-exit interruption error code. */ + uint32_t uExitIntErrCode; + /** IDT-vectoring information. */ + uint32_t uIdtVectoringInfo; + /** IDT-vectoring error code. */ + uint32_t uIdtVectoringErrCode; +} VMXVEXITEVENTINFO; +/** Pointer to the VMXVEXITEVENTINFO struct. */ +typedef VMXVEXITEVENTINFO *PVMXVEXITEVENTINFO; +/** Pointer to a const VMXVEXITEVENTINFO struct. */ +typedef const VMXVEXITEVENTINFO *PCVMXVEXITEVENTINFO; + +/** Initialize a VMXVEXITEVENTINFO. */ +#define VMXVEXITEVENTINFO_INIT(a_uExitIntInfo, a_uExitIntErrCode, a_uIdtVectoringInfo, a_uIdtVectoringErrCode) \ + { (a_uExitIntInfo), (a_uExitIntErrCode), (a_uIdtVectoringInfo), (a_uIdtVectoringErrCode) } + +/** Initialize a VMXVEXITEVENTINFO with VM-exit interruption info and VM-exit + * interruption error code. */ +#define VMXVEXITEVENTINFO_INIT_ONLY_INT(a_uExitIntInfo, a_uExitIntErrCode) \ + VMXVEXITEVENTINFO_INIT(a_uExitIntInfo, a_uExitIntErrCode, 0, 0) + +/** Initialize a VMXVEXITEVENTINFO with IDT vectoring info and IDT + * vectoring error code. */ +#define VMXVEXITEVENTINFO_INIT_ONLY_IDT(a_uIdtVectoringInfo, a_uIdtVectoringErrCode) \ + VMXVEXITEVENTINFO_INIT(0, 0, a_uIdtVectoringInfo, a_uIdtVectoringErrCode) + +/** + * Virtual VMCS. + * + * This is our custom format. Relevant fields from this VMCS will be merged into the + * actual/shadow VMCS when we execute nested-guest code using hardware-assisted + * VMX. + * + * The first 8 bytes must be in accordance with the Intel VT-x spec. + * See Intel spec. 24.2 "Format of the VMCS Region". + * + * The offset and size of the VMCS state field (@a fVmcsState) is also fixed (not by + * the Intel spec. but for our own requirements) as we use it to offset into guest + * memory. + * + * Although the guest is supposed to access the VMCS only through the execution of + * VMX instructions (VMREAD, VMWRITE etc.), since the VMCS may reside in guest + * memory (e.g, active but not current VMCS), for saved-states compatibility, and + * for teleportation purposes, any newly added fields should be added to the + * appropriate reserved sections or at the end of the structure. + * + * We always treat natural-width fields as 64-bit in our implementation since + * it's easier, allows for teleporation in the future and does not affect guest + * software. + * + * @note Any fields that are added or modified here, make sure to update the + * corresponding fields in IEM (g_aoffVmcsMap), the corresponding saved + * state structure in CPUM (g_aVmxHwvirtVmcs) and bump the SSM version. + * Also consider updating CPUMIsGuestVmxVmcsFieldValid and cpumR3InfoVmxVmcs. + */ +#pragma pack(1) +typedef struct +{ + /** @name Header. + * @{ + */ + VMXVMCSREVID u32VmcsRevId; /**< 0x000 - VMX VMCS revision identifier. */ + VMXABORT enmVmxAbort; /**< 0x004 - VMX-abort indicator. */ + uint8_t fVmcsState; /**< 0x008 - VMCS launch state, see VMX_V_VMCS_LAUNCH_STATE_XXX. */ + uint8_t au8Padding0[3]; /**< 0x009 - Reserved for future. */ + uint32_t au32Reserved0[12]; /**< 0x00c - Reserved for future. */ + /** @} */ + + /** @name Read-only fields. + * @{ */ + /** 16-bit fields. */ + uint16_t u16Reserved0[14]; /**< 0x03c - Reserved for future. */ + + /** 32-bit fields. */ + uint32_t u32RoVmInstrError; /**< 0x058 - VM-instruction error. */ + uint32_t u32RoExitReason; /**< 0x05c - VM-exit reason. */ + uint32_t u32RoExitIntInfo; /**< 0x060 - VM-exit interruption information. */ + uint32_t u32RoExitIntErrCode; /**< 0x064 - VM-exit interruption error code. */ + uint32_t u32RoIdtVectoringInfo; /**< 0x068 - IDT-vectoring information. */ + uint32_t u32RoIdtVectoringErrCode; /**< 0x06c - IDT-vectoring error code. */ + uint32_t u32RoExitInstrLen; /**< 0x070 - VM-exit instruction length. */ + uint32_t u32RoExitInstrInfo; /**< 0x074 - VM-exit instruction information. */ + uint32_t au32RoReserved2[16]; /**< 0x078 - Reserved for future. */ + + /** 64-bit fields. */ + RTUINT64U u64RoGuestPhysAddr; /**< 0x0b8 - Guest-physical address. */ + RTUINT64U au64Reserved1[8]; /**< 0x0c0 - Reserved for future. */ + + /** Natural-width fields. */ + RTUINT64U u64RoExitQual; /**< 0x100 - Exit qualification. */ + RTUINT64U u64RoIoRcx; /**< 0x108 - I/O RCX. */ + RTUINT64U u64RoIoRsi; /**< 0x110 - I/O RSI. */ + RTUINT64U u64RoIoRdi; /**< 0x118 - I/O RDI. */ + RTUINT64U u64RoIoRip; /**< 0x120 - I/O RIP. */ + RTUINT64U u64RoGuestLinearAddr; /**< 0x128 - Guest-linear address. */ + RTUINT64U au64Reserved5[16]; /**< 0x130 - Reserved for future. */ + /** @} */ + + /** @name Control fields. + * @{ */ + /** 16-bit fields. */ + uint16_t u16Vpid; /**< 0x1b0 - Virtual processor ID. */ + uint16_t u16PostIntNotifyVector; /**< 0x1b2 - Posted interrupt notify vector. */ + uint16_t u16EptpIndex; /**< 0x1b4 - EPTP index. */ + uint16_t u16HlatPrefixSize; /**< 0x1b6 - HLAT prefix size. */ + uint16_t au16Reserved0[12]; /**< 0x1b8 - Reserved for future. */ + + /** 32-bit fields. */ + uint32_t u32PinCtls; /**< 0x1d0 - Pin-based VM-execution controls. */ + uint32_t u32ProcCtls; /**< 0x1d4 - Processor-based VM-execution controls. */ + uint32_t u32XcptBitmap; /**< 0x1d8 - Exception bitmap. */ + uint32_t u32XcptPFMask; /**< 0x1dc - Page-fault exception error mask. */ + uint32_t u32XcptPFMatch; /**< 0x1e0 - Page-fault exception error match. */ + uint32_t u32Cr3TargetCount; /**< 0x1e4 - CR3-target count. */ + uint32_t u32ExitCtls; /**< 0x1e8 - VM-exit controls. */ + uint32_t u32ExitMsrStoreCount; /**< 0x1ec - VM-exit MSR store count. */ + uint32_t u32ExitMsrLoadCount; /**< 0x1f0 - VM-exit MSR load count. */ + uint32_t u32EntryCtls; /**< 0x1f4 - VM-entry controls. */ + uint32_t u32EntryMsrLoadCount; /**< 0x1f8 - VM-entry MSR load count. */ + uint32_t u32EntryIntInfo; /**< 0x1fc - VM-entry interruption information. */ + uint32_t u32EntryXcptErrCode; /**< 0x200 - VM-entry exception error code. */ + uint32_t u32EntryInstrLen; /**< 0x204 - VM-entry instruction length. */ + uint32_t u32TprThreshold; /**< 0x208 - TPR-threshold. */ + uint32_t u32ProcCtls2; /**< 0x20c - Secondary-processor based VM-execution controls. */ + uint32_t u32PleGap; /**< 0x210 - Pause-loop exiting Gap. */ + uint32_t u32PleWindow; /**< 0x214 - Pause-loop exiting Window. */ + uint32_t au32Reserved1[16]; /**< 0x218 - Reserved for future. */ + + /** 64-bit fields. */ + RTUINT64U u64AddrIoBitmapA; /**< 0x258 - I/O bitmap A address. */ + RTUINT64U u64AddrIoBitmapB; /**< 0x260 - I/O bitmap B address. */ + RTUINT64U u64AddrMsrBitmap; /**< 0x268 - MSR bitmap address. */ + RTUINT64U u64AddrExitMsrStore; /**< 0x270 - VM-exit MSR-store area address. */ + RTUINT64U u64AddrExitMsrLoad; /**< 0x278 - VM-exit MSR-load area address. */ + RTUINT64U u64AddrEntryMsrLoad; /**< 0x280 - VM-entry MSR-load area address. */ + RTUINT64U u64ExecVmcsPtr; /**< 0x288 - Executive-VMCS pointer. */ + RTUINT64U u64AddrPml; /**< 0x290 - Page-modification log address (PML). */ + RTUINT64U u64TscOffset; /**< 0x298 - TSC offset. */ + RTUINT64U u64AddrVirtApic; /**< 0x2a0 - Virtual-APIC address. */ + RTUINT64U u64AddrApicAccess; /**< 0x2a8 - APIC-access address. */ + RTUINT64U u64AddrPostedIntDesc; /**< 0x2b0 - Posted-interrupt descriptor address. */ + RTUINT64U u64VmFuncCtls; /**< 0x2b8 - VM-functions control. */ + RTUINT64U u64EptPtr; /**< 0x2c0 - EPT pointer. */ + RTUINT64U u64EoiExitBitmap0; /**< 0x2c8 - EOI-exit bitmap 0. */ + RTUINT64U u64EoiExitBitmap1; /**< 0x2d0 - EOI-exit bitmap 1. */ + RTUINT64U u64EoiExitBitmap2; /**< 0x2d8 - EOI-exit bitmap 2. */ + RTUINT64U u64EoiExitBitmap3; /**< 0x2e0 - EOI-exit bitmap 3. */ + RTUINT64U u64AddrEptpList; /**< 0x2e8 - EPTP-list address. */ + RTUINT64U u64AddrVmreadBitmap; /**< 0x2f0 - VMREAD-bitmap address. */ + RTUINT64U u64AddrVmwriteBitmap; /**< 0x2f8 - VMWRITE-bitmap address. */ + RTUINT64U u64AddrXcptVeInfo; /**< 0x300 - Virtualization-exception information address. */ + RTUINT64U u64XssExitBitmap; /**< 0x308 - XSS-exiting bitmap. */ + RTUINT64U u64EnclsExitBitmap; /**< 0x310 - ENCLS-exiting bitmap address. */ + RTUINT64U u64SppTablePtr; /**< 0x318 - Sub-page-permission-table pointer (SPPTP). */ + RTUINT64U u64TscMultiplier; /**< 0x320 - TSC multiplier. */ + RTUINT64U u64ProcCtls3; /**< 0x328 - Tertiary-Processor based VM-execution controls. */ + RTUINT64U u64EnclvExitBitmap; /**< 0x330 - ENCLV-exiting bitmap. */ + RTUINT64U u64PconfigExitBitmap; /**< 0x338 - PCONFIG-exiting bitmap. */ + RTUINT64U u64HlatPtr; /**< 0x340 - HLAT pointer. */ + RTUINT64U u64ExitCtls2; /**< 0x348 - Secondary VM-exit controls. */ + RTUINT64U au64Reserved0[10]; /**< 0x350 - Reserved for future. */ + + /** Natural-width fields. */ + RTUINT64U u64Cr0Mask; /**< 0x3a0 - CR0 guest/host Mask. */ + RTUINT64U u64Cr4Mask; /**< 0x3a8 - CR4 guest/host Mask. */ + RTUINT64U u64Cr0ReadShadow; /**< 0x3b0 - CR0 read shadow. */ + RTUINT64U u64Cr4ReadShadow; /**< 0x3b8 - CR4 read shadow. */ + RTUINT64U u64Cr3Target0; /**< 0x3c0 - CR3-target value 0. */ + RTUINT64U u64Cr3Target1; /**< 0x3c8 - CR3-target value 1. */ + RTUINT64U u64Cr3Target2; /**< 0x3d0 - CR3-target value 2. */ + RTUINT64U u64Cr3Target3; /**< 0x3d8 - CR3-target value 3. */ + RTUINT64U au64Reserved4[32]; /**< 0x3e0 - Reserved for future. */ + /** @} */ + + /** @name Host-state fields. + * @{ */ + /** 16-bit fields. */ + /* Order of [Es..Gs] fields below must match [X86_SREG_ES..X86_SREG_GS]. */ + RTSEL HostEs; /**< 0x4e0 - Host ES selector. */ + RTSEL HostCs; /**< 0x4e2 - Host CS selector. */ + RTSEL HostSs; /**< 0x4e4 - Host SS selector. */ + RTSEL HostDs; /**< 0x4e6 - Host DS selector. */ + RTSEL HostFs; /**< 0x4e8 - Host FS selector. */ + RTSEL HostGs; /**< 0x4ea - Host GS selector. */ + RTSEL HostTr; /**< 0x4ec - Host TR selector. */ + uint16_t au16Reserved2[13]; /**< 0x4ee - Reserved for future. */ + + /** 32-bit fields. */ + uint32_t u32HostSysenterCs; /**< 0x508 - Host SYSENTER CS. */ + uint32_t au32Reserved4[11]; /**< 0x50c - Reserved for future. */ + + /** 64-bit fields. */ + RTUINT64U u64HostPatMsr; /**< 0x538 - Host PAT MSR. */ + RTUINT64U u64HostEferMsr; /**< 0x540 - Host EFER MSR. */ + RTUINT64U u64HostPerfGlobalCtlMsr; /**< 0x548 - Host global performance-control MSR. */ + RTUINT64U u64HostPkrsMsr; /**< 0x550 - Host PKRS MSR. */ + RTUINT64U au64Reserved3[15]; /**< 0x558 - Reserved for future. */ + + /** Natural-width fields. */ + RTUINT64U u64HostCr0; /**< 0x5d0 - Host CR0. */ + RTUINT64U u64HostCr3; /**< 0x5d8 - Host CR3. */ + RTUINT64U u64HostCr4; /**< 0x5e0 - Host CR4. */ + RTUINT64U u64HostFsBase; /**< 0x5e8 - Host FS base. */ + RTUINT64U u64HostGsBase; /**< 0x5f0 - Host GS base. */ + RTUINT64U u64HostTrBase; /**< 0x5f8 - Host TR base. */ + RTUINT64U u64HostGdtrBase; /**< 0x600 - Host GDTR base. */ + RTUINT64U u64HostIdtrBase; /**< 0x608 - Host IDTR base. */ + RTUINT64U u64HostSysenterEsp; /**< 0x610 - Host SYSENTER ESP base. */ + RTUINT64U u64HostSysenterEip; /**< 0x618 - Host SYSENTER ESP base. */ + RTUINT64U u64HostRsp; /**< 0x620 - Host RSP. */ + RTUINT64U u64HostRip; /**< 0x628 - Host RIP. */ + RTUINT64U u64HostSCetMsr; /**< 0x630 - Host S_CET MSR. */ + RTUINT64U u64HostSsp; /**< 0x638 - Host SSP. */ + RTUINT64U u64HostIntrSspTableAddrMsr; /**< 0x640 - Host Interrupt SSP table address MSR. */ + RTUINT64U au64Reserved7[29]; /**< 0x648 - Reserved for future. */ + /** @} */ + + /** @name Guest-state fields. + * @{ */ + /** 16-bit fields. */ + /* Order of [Es..Gs] fields below must match [X86_SREG_ES..X86_SREG_GS]. */ + RTSEL GuestEs; /**< 0x730 - Guest ES selector. */ + RTSEL GuestCs; /**< 0x732 - Guest ES selector. */ + RTSEL GuestSs; /**< 0x734 - Guest ES selector. */ + RTSEL GuestDs; /**< 0x736 - Guest ES selector. */ + RTSEL GuestFs; /**< 0x738 - Guest ES selector. */ + RTSEL GuestGs; /**< 0x73a - Guest ES selector. */ + RTSEL GuestLdtr; /**< 0x73c - Guest LDTR selector. */ + RTSEL GuestTr; /**< 0x73e - Guest TR selector. */ + uint16_t u16GuestIntStatus; /**< 0x740 - Guest interrupt status (virtual-interrupt delivery). */ + uint16_t u16PmlIndex; /**< 0x742 - PML index. */ + uint16_t au16Reserved1[14]; /**< 0x744 - Reserved for future. */ + + /** 32-bit fields. */ + /* Order of [Es..Gs] fields below must match [X86_SREG_ES..X86_SREG_GS]. */ + uint32_t u32GuestEsLimit; /**< 0x760 - Guest ES limit. */ + uint32_t u32GuestCsLimit; /**< 0x764 - Guest CS limit. */ + uint32_t u32GuestSsLimit; /**< 0x768 - Guest SS limit. */ + uint32_t u32GuestDsLimit; /**< 0x76c - Guest DS limit. */ + uint32_t u32GuestFsLimit; /**< 0x770 - Guest FS limit. */ + uint32_t u32GuestGsLimit; /**< 0x774 - Guest GS limit. */ + uint32_t u32GuestLdtrLimit; /**< 0x778 - Guest LDTR limit. */ + uint32_t u32GuestTrLimit; /**< 0x77c - Guest TR limit. */ + uint32_t u32GuestGdtrLimit; /**< 0x780 - Guest GDTR limit. */ + uint32_t u32GuestIdtrLimit; /**< 0x784 - Guest IDTR limit. */ + uint32_t u32GuestEsAttr; /**< 0x788 - Guest ES attributes. */ + uint32_t u32GuestCsAttr; /**< 0x78c - Guest CS attributes. */ + uint32_t u32GuestSsAttr; /**< 0x790 - Guest SS attributes. */ + uint32_t u32GuestDsAttr; /**< 0x794 - Guest DS attributes. */ + uint32_t u32GuestFsAttr; /**< 0x798 - Guest FS attributes. */ + uint32_t u32GuestGsAttr; /**< 0x79c - Guest GS attributes. */ + uint32_t u32GuestLdtrAttr; /**< 0x7a0 - Guest LDTR attributes. */ + uint32_t u32GuestTrAttr; /**< 0x7a4 - Guest TR attributes. */ + uint32_t u32GuestIntrState; /**< 0x7a8 - Guest interruptibility state. */ + uint32_t u32GuestActivityState; /**< 0x7ac - Guest activity state. */ + uint32_t u32GuestSmBase; /**< 0x7b0 - Guest SMBASE. */ + uint32_t u32GuestSysenterCS; /**< 0x7b4 - Guest SYSENTER CS. */ + uint32_t u32PreemptTimer; /**< 0x7b8 - Preemption timer value. */ + uint32_t au32Reserved3[11]; /**< 0x7bc - Reserved for future. */ + + /** 64-bit fields. */ + RTUINT64U u64VmcsLinkPtr; /**< 0x7e8 - VMCS link pointer. */ + RTUINT64U u64GuestDebugCtlMsr; /**< 0x7f0 - Guest debug-control MSR. */ + RTUINT64U u64GuestPatMsr; /**< 0x7f8 - Guest PAT MSR. */ + RTUINT64U u64GuestEferMsr; /**< 0x800 - Guest EFER MSR. */ + RTUINT64U u64GuestPerfGlobalCtlMsr; /**< 0x808 - Guest global performance-control MSR. */ + RTUINT64U u64GuestPdpte0; /**< 0x810 - Guest PDPTE 0. */ + RTUINT64U u64GuestPdpte1; /**< 0x818 - Guest PDPTE 0. */ + RTUINT64U u64GuestPdpte2; /**< 0x820 - Guest PDPTE 1. */ + RTUINT64U u64GuestPdpte3; /**< 0x828 - Guest PDPTE 2. */ + RTUINT64U u64GuestBndcfgsMsr; /**< 0x830 - Guest Bounds config MPX MSR (Intel Memory Protection Extensions). */ + RTUINT64U u64GuestRtitCtlMsr; /**< 0x838 - Guest RTIT control MSR (Intel Real Time Instruction Trace). */ + RTUINT64U u64GuestPkrsMsr; /**< 0x840 - Guest PKRS MSR. */ + RTUINT64U au64Reserved2[31]; /**< 0x848 - Reserved for future. */ + + /** Natural-width fields. */ + RTUINT64U u64GuestCr0; /**< 0x940 - Guest CR0. */ + RTUINT64U u64GuestCr3; /**< 0x948 - Guest CR3. */ + RTUINT64U u64GuestCr4; /**< 0x950 - Guest CR4. */ + RTUINT64U u64GuestEsBase; /**< 0x958 - Guest ES base. */ + RTUINT64U u64GuestCsBase; /**< 0x960 - Guest CS base. */ + RTUINT64U u64GuestSsBase; /**< 0x968 - Guest SS base. */ + RTUINT64U u64GuestDsBase; /**< 0x970 - Guest DS base. */ + RTUINT64U u64GuestFsBase; /**< 0x978 - Guest FS base. */ + RTUINT64U u64GuestGsBase; /**< 0x980 - Guest GS base. */ + RTUINT64U u64GuestLdtrBase; /**< 0x988 - Guest LDTR base. */ + RTUINT64U u64GuestTrBase; /**< 0x990 - Guest TR base. */ + RTUINT64U u64GuestGdtrBase; /**< 0x998 - Guest GDTR base. */ + RTUINT64U u64GuestIdtrBase; /**< 0x9a0 - Guest IDTR base. */ + RTUINT64U u64GuestDr7; /**< 0x9a8 - Guest DR7. */ + RTUINT64U u64GuestRsp; /**< 0x9b0 - Guest RSP. */ + RTUINT64U u64GuestRip; /**< 0x9b8 - Guest RIP. */ + RTUINT64U u64GuestRFlags; /**< 0x9c0 - Guest RFLAGS. */ + RTUINT64U u64GuestPendingDbgXcpts; /**< 0x9c8 - Guest pending debug exceptions. */ + RTUINT64U u64GuestSysenterEsp; /**< 0x9d0 - Guest SYSENTER ESP. */ + RTUINT64U u64GuestSysenterEip; /**< 0x9d8 - Guest SYSENTER EIP. */ + RTUINT64U u64GuestSCetMsr; /**< 0x9e0 - Guest S_CET MSR. */ + RTUINT64U u64GuestSsp; /**< 0x9e8 - Guest SSP. */ + RTUINT64U u64GuestIntrSspTableAddrMsr; /**< 0x9f0 - Guest Interrupt SSP table address MSR. */ + RTUINT64U au64Reserved6[29]; /**< 0x9f8 - Reserved for future. */ + /** @} */ + + /** 0xae0 - Padding / reserved for future use. */ + uint8_t abPadding[X86_PAGE_4K_SIZE - 0xae0]; +} VMXVVMCS; +#pragma pack() +/** Pointer to the VMXVVMCS struct. */ +typedef VMXVVMCS *PVMXVVMCS; +/** Pointer to a const VMXVVMCS struct. */ +typedef const VMXVVMCS *PCVMXVVMCS; +AssertCompileSize(VMXVVMCS, X86_PAGE_4K_SIZE); +AssertCompileMemberSize(VMXVVMCS, fVmcsState, sizeof(uint8_t)); +AssertCompileMemberOffset(VMXVVMCS, enmVmxAbort, 0x004); +AssertCompileMemberOffset(VMXVVMCS, fVmcsState, 0x008); +AssertCompileMemberOffset(VMXVVMCS, u32RoVmInstrError, 0x058); +AssertCompileMemberOffset(VMXVVMCS, u64RoGuestPhysAddr, 0x0b8); +AssertCompileMemberOffset(VMXVVMCS, u64RoExitQual, 0x100); +AssertCompileMemberOffset(VMXVVMCS, u16Vpid, 0x1b0); +AssertCompileMemberOffset(VMXVVMCS, u32PinCtls, 0x1d0); +AssertCompileMemberOffset(VMXVVMCS, u64AddrIoBitmapA, 0x258); +AssertCompileMemberOffset(VMXVVMCS, u64Cr0Mask, 0x3a0); +AssertCompileMemberOffset(VMXVVMCS, HostEs, 0x4e0); +AssertCompileMemberOffset(VMXVVMCS, u32HostSysenterCs, 0x508); +AssertCompileMemberOffset(VMXVVMCS, u64HostPatMsr, 0x538); +AssertCompileMemberOffset(VMXVVMCS, u64HostCr0, 0x5d0); +AssertCompileMemberOffset(VMXVVMCS, GuestEs, 0x730); +AssertCompileMemberOffset(VMXVVMCS, u32GuestEsLimit, 0x760); +AssertCompileMemberOffset(VMXVVMCS, u64VmcsLinkPtr, 0x7e8); +AssertCompileMemberOffset(VMXVVMCS, u64GuestCr0, 0x940); + +/** + * Virtual VMX-instruction and VM-exit diagnostics. + * + * These are not the same as VM instruction errors that are enumerated in the Intel + * spec. These are purely internal, fine-grained definitions used for diagnostic + * purposes and are not reported to guest software under the VM-instruction error + * field in its VMCS. + * + * @note Members of this enum are used as array indices, so no gaps are allowed. + * Please update g_apszVmxVDiagDesc when you add new fields to this enum. + */ +typedef enum +{ + /* Internal processing errors. */ + kVmxVDiag_None = 0, + kVmxVDiag_Ipe_1, + kVmxVDiag_Ipe_2, + kVmxVDiag_Ipe_3, + kVmxVDiag_Ipe_4, + kVmxVDiag_Ipe_5, + kVmxVDiag_Ipe_6, + kVmxVDiag_Ipe_7, + kVmxVDiag_Ipe_8, + kVmxVDiag_Ipe_9, + kVmxVDiag_Ipe_10, + kVmxVDiag_Ipe_11, + kVmxVDiag_Ipe_12, + kVmxVDiag_Ipe_13, + kVmxVDiag_Ipe_14, + kVmxVDiag_Ipe_15, + kVmxVDiag_Ipe_16, + /* VMXON. */ + kVmxVDiag_Vmxon_A20M, + kVmxVDiag_Vmxon_Cpl, + kVmxVDiag_Vmxon_Cr0Fixed0, + kVmxVDiag_Vmxon_Cr0Fixed1, + kVmxVDiag_Vmxon_Cr4Fixed0, + kVmxVDiag_Vmxon_Cr4Fixed1, + kVmxVDiag_Vmxon_Intercept, + kVmxVDiag_Vmxon_LongModeCS, + kVmxVDiag_Vmxon_MsrFeatCtl, + kVmxVDiag_Vmxon_PtrAbnormal, + kVmxVDiag_Vmxon_PtrAlign, + kVmxVDiag_Vmxon_PtrMap, + kVmxVDiag_Vmxon_PtrReadPhys, + kVmxVDiag_Vmxon_PtrWidth, + kVmxVDiag_Vmxon_RealOrV86Mode, + kVmxVDiag_Vmxon_ShadowVmcs, + kVmxVDiag_Vmxon_VmxAlreadyRoot, + kVmxVDiag_Vmxon_Vmxe, + kVmxVDiag_Vmxon_VmcsRevId, + kVmxVDiag_Vmxon_VmxRootCpl, + /* VMXOFF. */ + kVmxVDiag_Vmxoff_Cpl, + kVmxVDiag_Vmxoff_Intercept, + kVmxVDiag_Vmxoff_LongModeCS, + kVmxVDiag_Vmxoff_RealOrV86Mode, + kVmxVDiag_Vmxoff_Vmxe, + kVmxVDiag_Vmxoff_VmxRoot, + /* VMPTRLD. */ + kVmxVDiag_Vmptrld_Cpl, + kVmxVDiag_Vmptrld_LongModeCS, + kVmxVDiag_Vmptrld_PtrAbnormal, + kVmxVDiag_Vmptrld_PtrAlign, + kVmxVDiag_Vmptrld_PtrMap, + kVmxVDiag_Vmptrld_PtrReadPhys, + kVmxVDiag_Vmptrld_PtrVmxon, + kVmxVDiag_Vmptrld_PtrWidth, + kVmxVDiag_Vmptrld_RealOrV86Mode, + kVmxVDiag_Vmptrld_RevPtrReadPhys, + kVmxVDiag_Vmptrld_ShadowVmcs, + kVmxVDiag_Vmptrld_VmcsRevId, + kVmxVDiag_Vmptrld_VmxRoot, + /* VMPTRST. */ + kVmxVDiag_Vmptrst_Cpl, + kVmxVDiag_Vmptrst_LongModeCS, + kVmxVDiag_Vmptrst_PtrMap, + kVmxVDiag_Vmptrst_RealOrV86Mode, + kVmxVDiag_Vmptrst_VmxRoot, + /* VMCLEAR. */ + kVmxVDiag_Vmclear_Cpl, + kVmxVDiag_Vmclear_LongModeCS, + kVmxVDiag_Vmclear_PtrAbnormal, + kVmxVDiag_Vmclear_PtrAlign, + kVmxVDiag_Vmclear_PtrMap, + kVmxVDiag_Vmclear_PtrReadPhys, + kVmxVDiag_Vmclear_PtrVmxon, + kVmxVDiag_Vmclear_PtrWidth, + kVmxVDiag_Vmclear_RealOrV86Mode, + kVmxVDiag_Vmclear_VmxRoot, + /* VMWRITE. */ + kVmxVDiag_Vmwrite_Cpl, + kVmxVDiag_Vmwrite_FieldInvalid, + kVmxVDiag_Vmwrite_FieldRo, + kVmxVDiag_Vmwrite_LinkPtrInvalid, + kVmxVDiag_Vmwrite_LongModeCS, + kVmxVDiag_Vmwrite_PtrInvalid, + kVmxVDiag_Vmwrite_PtrMap, + kVmxVDiag_Vmwrite_RealOrV86Mode, + kVmxVDiag_Vmwrite_VmxRoot, + /* VMREAD. */ + kVmxVDiag_Vmread_Cpl, + kVmxVDiag_Vmread_FieldInvalid, + kVmxVDiag_Vmread_LinkPtrInvalid, + kVmxVDiag_Vmread_LongModeCS, + kVmxVDiag_Vmread_PtrInvalid, + kVmxVDiag_Vmread_PtrMap, + kVmxVDiag_Vmread_RealOrV86Mode, + kVmxVDiag_Vmread_VmxRoot, + /* INVVPID. */ + kVmxVDiag_Invvpid_Cpl, + kVmxVDiag_Invvpid_DescRsvd, + kVmxVDiag_Invvpid_LongModeCS, + kVmxVDiag_Invvpid_RealOrV86Mode, + kVmxVDiag_Invvpid_TypeInvalid, + kVmxVDiag_Invvpid_Type0InvalidAddr, + kVmxVDiag_Invvpid_Type0InvalidVpid, + kVmxVDiag_Invvpid_Type1InvalidVpid, + kVmxVDiag_Invvpid_Type3InvalidVpid, + kVmxVDiag_Invvpid_VmxRoot, + /* INVEPT. */ + kVmxVDiag_Invept_Cpl, + kVmxVDiag_Invept_DescRsvd, + kVmxVDiag_Invept_EptpInvalid, + kVmxVDiag_Invept_LongModeCS, + kVmxVDiag_Invept_RealOrV86Mode, + kVmxVDiag_Invept_TypeInvalid, + kVmxVDiag_Invept_VmxRoot, + /* VMLAUNCH/VMRESUME. */ + kVmxVDiag_Vmentry_AddrApicAccess, + kVmxVDiag_Vmentry_AddrApicAccessEqVirtApic, + kVmxVDiag_Vmentry_AddrApicAccessHandlerReg, + kVmxVDiag_Vmentry_AddrEntryMsrLoad, + kVmxVDiag_Vmentry_AddrExitMsrLoad, + kVmxVDiag_Vmentry_AddrExitMsrStore, + kVmxVDiag_Vmentry_AddrIoBitmapA, + kVmxVDiag_Vmentry_AddrIoBitmapB, + kVmxVDiag_Vmentry_AddrMsrBitmap, + kVmxVDiag_Vmentry_AddrVirtApicPage, + kVmxVDiag_Vmentry_AddrVmcsLinkPtr, + kVmxVDiag_Vmentry_AddrVmreadBitmap, + kVmxVDiag_Vmentry_AddrVmwriteBitmap, + kVmxVDiag_Vmentry_ApicRegVirt, + kVmxVDiag_Vmentry_BlocKMovSS, + kVmxVDiag_Vmentry_Cpl, + kVmxVDiag_Vmentry_Cr3TargetCount, + kVmxVDiag_Vmentry_EntryCtlsAllowed1, + kVmxVDiag_Vmentry_EntryCtlsDisallowed0, + kVmxVDiag_Vmentry_EntryInstrLen, + kVmxVDiag_Vmentry_EntryInstrLenZero, + kVmxVDiag_Vmentry_EntryIntInfoErrCodePe, + kVmxVDiag_Vmentry_EntryIntInfoErrCodeVec, + kVmxVDiag_Vmentry_EntryIntInfoTypeVecRsvd, + kVmxVDiag_Vmentry_EntryXcptErrCodeRsvd, + kVmxVDiag_Vmentry_EptpAccessDirty, + kVmxVDiag_Vmentry_EptpPageWalkLength, + kVmxVDiag_Vmentry_EptpMemType, + kVmxVDiag_Vmentry_EptpRsvd, + kVmxVDiag_Vmentry_ExitCtlsAllowed1, + kVmxVDiag_Vmentry_ExitCtlsDisallowed0, + kVmxVDiag_Vmentry_GuestActStateHlt, + kVmxVDiag_Vmentry_GuestActStateRsvd, + kVmxVDiag_Vmentry_GuestActStateShutdown, + kVmxVDiag_Vmentry_GuestActStateSsDpl, + kVmxVDiag_Vmentry_GuestActStateStiMovSs, + kVmxVDiag_Vmentry_GuestCr0Fixed0, + kVmxVDiag_Vmentry_GuestCr0Fixed1, + kVmxVDiag_Vmentry_GuestCr0PgPe, + kVmxVDiag_Vmentry_GuestCr3, + kVmxVDiag_Vmentry_GuestCr4Fixed0, + kVmxVDiag_Vmentry_GuestCr4Fixed1, + kVmxVDiag_Vmentry_GuestDebugCtl, + kVmxVDiag_Vmentry_GuestDr7, + kVmxVDiag_Vmentry_GuestEferMsr, + kVmxVDiag_Vmentry_GuestEferMsrRsvd, + kVmxVDiag_Vmentry_GuestGdtrBase, + kVmxVDiag_Vmentry_GuestGdtrLimit, + kVmxVDiag_Vmentry_GuestIdtrBase, + kVmxVDiag_Vmentry_GuestIdtrLimit, + kVmxVDiag_Vmentry_GuestIntStateEnclave, + kVmxVDiag_Vmentry_GuestIntStateExtInt, + kVmxVDiag_Vmentry_GuestIntStateNmi, + kVmxVDiag_Vmentry_GuestIntStateRFlagsSti, + kVmxVDiag_Vmentry_GuestIntStateRsvd, + kVmxVDiag_Vmentry_GuestIntStateSmi, + kVmxVDiag_Vmentry_GuestIntStateStiMovSs, + kVmxVDiag_Vmentry_GuestIntStateVirtNmi, + kVmxVDiag_Vmentry_GuestPae, + kVmxVDiag_Vmentry_GuestPatMsr, + kVmxVDiag_Vmentry_GuestPcide, + kVmxVDiag_Vmentry_GuestPdpte, + kVmxVDiag_Vmentry_GuestPndDbgXcptBsNoTf, + kVmxVDiag_Vmentry_GuestPndDbgXcptBsTf, + kVmxVDiag_Vmentry_GuestPndDbgXcptRsvd, + kVmxVDiag_Vmentry_GuestPndDbgXcptRtm, + kVmxVDiag_Vmentry_GuestRip, + kVmxVDiag_Vmentry_GuestRipRsvd, + kVmxVDiag_Vmentry_GuestRFlagsIf, + kVmxVDiag_Vmentry_GuestRFlagsRsvd, + kVmxVDiag_Vmentry_GuestRFlagsVm, + kVmxVDiag_Vmentry_GuestSegAttrCsDefBig, + kVmxVDiag_Vmentry_GuestSegAttrCsDplEqSs, + kVmxVDiag_Vmentry_GuestSegAttrCsDplLtSs, + kVmxVDiag_Vmentry_GuestSegAttrCsDplZero, + kVmxVDiag_Vmentry_GuestSegAttrCsType, + kVmxVDiag_Vmentry_GuestSegAttrCsTypeRead, + kVmxVDiag_Vmentry_GuestSegAttrDescTypeCs, + kVmxVDiag_Vmentry_GuestSegAttrDescTypeDs, + kVmxVDiag_Vmentry_GuestSegAttrDescTypeEs, + kVmxVDiag_Vmentry_GuestSegAttrDescTypeFs, + kVmxVDiag_Vmentry_GuestSegAttrDescTypeGs, + kVmxVDiag_Vmentry_GuestSegAttrDescTypeSs, + kVmxVDiag_Vmentry_GuestSegAttrDplRplCs, + kVmxVDiag_Vmentry_GuestSegAttrDplRplDs, + kVmxVDiag_Vmentry_GuestSegAttrDplRplEs, + kVmxVDiag_Vmentry_GuestSegAttrDplRplFs, + kVmxVDiag_Vmentry_GuestSegAttrDplRplGs, + kVmxVDiag_Vmentry_GuestSegAttrDplRplSs, + kVmxVDiag_Vmentry_GuestSegAttrGranCs, + kVmxVDiag_Vmentry_GuestSegAttrGranDs, + kVmxVDiag_Vmentry_GuestSegAttrGranEs, + kVmxVDiag_Vmentry_GuestSegAttrGranFs, + kVmxVDiag_Vmentry_GuestSegAttrGranGs, + kVmxVDiag_Vmentry_GuestSegAttrGranSs, + kVmxVDiag_Vmentry_GuestSegAttrLdtrDescType, + kVmxVDiag_Vmentry_GuestSegAttrLdtrGran, + kVmxVDiag_Vmentry_GuestSegAttrLdtrPresent, + kVmxVDiag_Vmentry_GuestSegAttrLdtrRsvd, + kVmxVDiag_Vmentry_GuestSegAttrLdtrType, + kVmxVDiag_Vmentry_GuestSegAttrPresentCs, + kVmxVDiag_Vmentry_GuestSegAttrPresentDs, + kVmxVDiag_Vmentry_GuestSegAttrPresentEs, + kVmxVDiag_Vmentry_GuestSegAttrPresentFs, + kVmxVDiag_Vmentry_GuestSegAttrPresentGs, + kVmxVDiag_Vmentry_GuestSegAttrPresentSs, + kVmxVDiag_Vmentry_GuestSegAttrRsvdCs, + kVmxVDiag_Vmentry_GuestSegAttrRsvdDs, + kVmxVDiag_Vmentry_GuestSegAttrRsvdEs, + kVmxVDiag_Vmentry_GuestSegAttrRsvdFs, + kVmxVDiag_Vmentry_GuestSegAttrRsvdGs, + kVmxVDiag_Vmentry_GuestSegAttrRsvdSs, + kVmxVDiag_Vmentry_GuestSegAttrSsDplEqRpl, + kVmxVDiag_Vmentry_GuestSegAttrSsDplZero, + kVmxVDiag_Vmentry_GuestSegAttrSsType, + kVmxVDiag_Vmentry_GuestSegAttrTrDescType, + kVmxVDiag_Vmentry_GuestSegAttrTrGran, + kVmxVDiag_Vmentry_GuestSegAttrTrPresent, + kVmxVDiag_Vmentry_GuestSegAttrTrRsvd, + kVmxVDiag_Vmentry_GuestSegAttrTrType, + kVmxVDiag_Vmentry_GuestSegAttrTrUnusable, + kVmxVDiag_Vmentry_GuestSegAttrTypeAccCs, + kVmxVDiag_Vmentry_GuestSegAttrTypeAccDs, + kVmxVDiag_Vmentry_GuestSegAttrTypeAccEs, + kVmxVDiag_Vmentry_GuestSegAttrTypeAccFs, + kVmxVDiag_Vmentry_GuestSegAttrTypeAccGs, + kVmxVDiag_Vmentry_GuestSegAttrTypeAccSs, + kVmxVDiag_Vmentry_GuestSegAttrV86Cs, + kVmxVDiag_Vmentry_GuestSegAttrV86Ds, + kVmxVDiag_Vmentry_GuestSegAttrV86Es, + kVmxVDiag_Vmentry_GuestSegAttrV86Fs, + kVmxVDiag_Vmentry_GuestSegAttrV86Gs, + kVmxVDiag_Vmentry_GuestSegAttrV86Ss, + kVmxVDiag_Vmentry_GuestSegBaseCs, + kVmxVDiag_Vmentry_GuestSegBaseDs, + kVmxVDiag_Vmentry_GuestSegBaseEs, + kVmxVDiag_Vmentry_GuestSegBaseFs, + kVmxVDiag_Vmentry_GuestSegBaseGs, + kVmxVDiag_Vmentry_GuestSegBaseLdtr, + kVmxVDiag_Vmentry_GuestSegBaseSs, + kVmxVDiag_Vmentry_GuestSegBaseTr, + kVmxVDiag_Vmentry_GuestSegBaseV86Cs, + kVmxVDiag_Vmentry_GuestSegBaseV86Ds, + kVmxVDiag_Vmentry_GuestSegBaseV86Es, + kVmxVDiag_Vmentry_GuestSegBaseV86Fs, + kVmxVDiag_Vmentry_GuestSegBaseV86Gs, + kVmxVDiag_Vmentry_GuestSegBaseV86Ss, + kVmxVDiag_Vmentry_GuestSegLimitV86Cs, + kVmxVDiag_Vmentry_GuestSegLimitV86Ds, + kVmxVDiag_Vmentry_GuestSegLimitV86Es, + kVmxVDiag_Vmentry_GuestSegLimitV86Fs, + kVmxVDiag_Vmentry_GuestSegLimitV86Gs, + kVmxVDiag_Vmentry_GuestSegLimitV86Ss, + kVmxVDiag_Vmentry_GuestSegSelCsSsRpl, + kVmxVDiag_Vmentry_GuestSegSelLdtr, + kVmxVDiag_Vmentry_GuestSegSelTr, + kVmxVDiag_Vmentry_GuestSysenterEspEip, + kVmxVDiag_Vmentry_VmcsLinkPtrCurVmcs, + kVmxVDiag_Vmentry_VmcsLinkPtrReadPhys, + kVmxVDiag_Vmentry_VmcsLinkPtrRevId, + kVmxVDiag_Vmentry_VmcsLinkPtrShadow, + kVmxVDiag_Vmentry_HostCr0Fixed0, + kVmxVDiag_Vmentry_HostCr0Fixed1, + kVmxVDiag_Vmentry_HostCr3, + kVmxVDiag_Vmentry_HostCr4Fixed0, + kVmxVDiag_Vmentry_HostCr4Fixed1, + kVmxVDiag_Vmentry_HostCr4Pae, + kVmxVDiag_Vmentry_HostCr4Pcide, + kVmxVDiag_Vmentry_HostCsTr, + kVmxVDiag_Vmentry_HostEferMsr, + kVmxVDiag_Vmentry_HostEferMsrRsvd, + kVmxVDiag_Vmentry_HostGuestLongMode, + kVmxVDiag_Vmentry_HostGuestLongModeNoCpu, + kVmxVDiag_Vmentry_HostLongMode, + kVmxVDiag_Vmentry_HostPatMsr, + kVmxVDiag_Vmentry_HostRip, + kVmxVDiag_Vmentry_HostRipRsvd, + kVmxVDiag_Vmentry_HostSel, + kVmxVDiag_Vmentry_HostSegBase, + kVmxVDiag_Vmentry_HostSs, + kVmxVDiag_Vmentry_HostSysenterEspEip, + kVmxVDiag_Vmentry_IoBitmapAPtrReadPhys, + kVmxVDiag_Vmentry_IoBitmapBPtrReadPhys, + kVmxVDiag_Vmentry_LongModeCS, + kVmxVDiag_Vmentry_MsrBitmapPtrReadPhys, + kVmxVDiag_Vmentry_MsrLoad, + kVmxVDiag_Vmentry_MsrLoadCount, + kVmxVDiag_Vmentry_MsrLoadPtrReadPhys, + kVmxVDiag_Vmentry_MsrLoadRing3, + kVmxVDiag_Vmentry_MsrLoadRsvd, + kVmxVDiag_Vmentry_NmiWindowExit, + kVmxVDiag_Vmentry_PinCtlsAllowed1, + kVmxVDiag_Vmentry_PinCtlsDisallowed0, + kVmxVDiag_Vmentry_ProcCtlsAllowed1, + kVmxVDiag_Vmentry_ProcCtlsDisallowed0, + kVmxVDiag_Vmentry_ProcCtls2Allowed1, + kVmxVDiag_Vmentry_ProcCtls2Disallowed0, + kVmxVDiag_Vmentry_PtrInvalid, + kVmxVDiag_Vmentry_PtrShadowVmcs, + kVmxVDiag_Vmentry_RealOrV86Mode, + kVmxVDiag_Vmentry_SavePreemptTimer, + kVmxVDiag_Vmentry_TprThresholdRsvd, + kVmxVDiag_Vmentry_TprThresholdVTpr, + kVmxVDiag_Vmentry_VirtApicPagePtrReadPhys, + kVmxVDiag_Vmentry_VirtIntDelivery, + kVmxVDiag_Vmentry_VirtNmi, + kVmxVDiag_Vmentry_VirtX2ApicTprShadow, + kVmxVDiag_Vmentry_VirtX2ApicVirtApic, + kVmxVDiag_Vmentry_VmcsClear, + kVmxVDiag_Vmentry_VmcsLaunch, + kVmxVDiag_Vmentry_VmreadBitmapPtrReadPhys, + kVmxVDiag_Vmentry_VmwriteBitmapPtrReadPhys, + kVmxVDiag_Vmentry_VmxRoot, + kVmxVDiag_Vmentry_Vpid, + kVmxVDiag_Vmexit_HostPdpte, + kVmxVDiag_Vmexit_MsrLoad, + kVmxVDiag_Vmexit_MsrLoadCount, + kVmxVDiag_Vmexit_MsrLoadPtrReadPhys, + kVmxVDiag_Vmexit_MsrLoadRing3, + kVmxVDiag_Vmexit_MsrLoadRsvd, + kVmxVDiag_Vmexit_MsrStore, + kVmxVDiag_Vmexit_MsrStoreCount, + kVmxVDiag_Vmexit_MsrStorePtrReadPhys, + kVmxVDiag_Vmexit_MsrStorePtrWritePhys, + kVmxVDiag_Vmexit_MsrStoreRing3, + kVmxVDiag_Vmexit_MsrStoreRsvd, + kVmxVDiag_Vmexit_VirtApicPagePtrWritePhys, + /* Last member for determining array index limit. */ + kVmxVDiag_End +} VMXVDIAG; +AssertCompileSize(VMXVDIAG, 4); + +/** @} */ + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_hm_vmx_h */ + diff --git a/include/VBox/vmm/hm_vmx.mac b/include/VBox/vmm/hm_vmx.mac new file mode 100644 index 00000000..15373887 --- /dev/null +++ b/include/VBox/vmm/hm_vmx.mac @@ -0,0 +1,163 @@ +;; @file +; HM - VMX Structures and Definitions. +; + +; +; Copyright (C) 2006-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox 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. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%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 04000h +%define VMX_VMCS_CTRL_PROC_EXEC 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 0400Ch +%define VMX_VMCS_CTRL_EXIT_MSR_STORE_COUNT 0400Eh +%define VMX_VMCS_CTRL_EXIT_MSR_LOAD_COUNT 04010h +%define VMX_VMCS_CTRL_ENTRY 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 + diff --git a/include/VBox/vmm/hmvmxinline.h b/include/VBox/vmm/hmvmxinline.h new file mode 100644 index 00000000..a0103786 --- /dev/null +++ b/include/VBox/vmm/hmvmxinline.h @@ -0,0 +1,1172 @@ +/** @file + * HM - VMX Structures and Definitions. (VMM) + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_hmvmxinline_h +#define VBOX_INCLUDED_vmm_hmvmxinline_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/vmm/hm_vmx.h> +#include <VBox/err.h> + +/* In Visual C++ versions prior to 2012, the vmx intrinsics are only available + when targeting AMD64. */ +#if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2010 && defined(RT_ARCH_AMD64) +# include <iprt/sanitized/intrin.h> +/* We always want them as intrinsics, no functions. */ +# pragma intrinsic(__vmx_on) +# pragma intrinsic(__vmx_off) +# pragma intrinsic(__vmx_vmclear) +# pragma intrinsic(__vmx_vmptrld) +# pragma intrinsic(__vmx_vmread) +# pragma intrinsic(__vmx_vmwrite) +# define VMX_USE_MSC_INTRINSICS 1 +#else +# define VMX_USE_MSC_INTRINSICS 0 +#endif + +/** + * Whether we think the assembler supports VMX instructions. + * + * Guess that GCC 5 should have sufficient recent enough binutils. + */ +#if RT_INLINE_ASM_GNU_STYLE && RT_GNUC_PREREQ(5,0) +# define VMX_USE_GNU_STYLE_INLINE_VMX_INSTRUCTIONS 1 +#else +# define VMX_USE_GNU_STYLE_INLINE_VMX_INSTRUCTIONS 0 +#endif + +/** Whether we can use the subsection trick to put error handling code + * elsewhere. */ +#if VMX_USE_GNU_STYLE_INLINE_VMX_INSTRUCTIONS && defined(__ELF__) +# define VMX_USE_GNU_STYLE_INLINE_SECTION_TRICK 1 +#else +# define VMX_USE_GNU_STYLE_INLINE_SECTION_TRICK 0 +#endif + +/* Skip checking VMREAD/VMWRITE failures on non-strict builds. */ +#ifndef VBOX_STRICT +# define VBOX_WITH_VMREAD_VMWRITE_NOCHECK +#endif + + +/** @defgroup grp_hm_vmx_inline VMX Inline Helpers + * @ingroup grp_hm_vmx + * @{ + */ +/** + * Gets the effective width of a VMCS field given it's encoding adjusted for + * HIGH/FULL access for 64-bit fields. + * + * @returns The effective VMCS field width. + * @param uFieldEnc The VMCS field encoding. + * + * @remarks Warning! This function does not verify the encoding is for a valid and + * supported VMCS field. + */ +DECLINLINE(uint8_t) VMXGetVmcsFieldWidthEff(uint32_t uFieldEnc) +{ + /* Only the "HIGH" parts of all 64-bit fields have bit 0 set. */ + if (uFieldEnc & RT_BIT(0)) + return VMXVMCSFIELDWIDTH_32BIT; + + /* Bits 13:14 contains the width of the VMCS field, see VMXVMCSFIELDWIDTH_XXX. */ + return (uFieldEnc >> 13) & 0x3; +} + + +/** + * Returns whether the given VMCS field is a read-only VMCS field or not. + * + * @returns @c true if it's a read-only field, @c false otherwise. + * @param uFieldEnc The VMCS field encoding. + * + * @remarks Warning! This function does not verify that the encoding is for a valid + * and/or supported VMCS field. + */ +DECLINLINE(bool) VMXIsVmcsFieldReadOnly(uint32_t uFieldEnc) +{ + /* See Intel spec. B.4.2 "Natural-Width Read-Only Data Fields". */ + return (RT_BF_GET(uFieldEnc, VMX_BF_VMCSFIELD_TYPE) == VMXVMCSFIELDTYPE_VMEXIT_INFO); +} + + +/** + * Returns whether the given VM-entry interruption-information type is valid or not. + * + * @returns @c true if it's a valid type, @c false otherwise. + * @param fSupportsMTF Whether the Monitor-Trap Flag CPU feature is supported. + * @param uType The VM-entry interruption-information type. + */ +DECLINLINE(bool) VMXIsEntryIntInfoTypeValid(bool fSupportsMTF, uint8_t uType) +{ + /* See Intel spec. 26.2.1.3 "VM-Entry Control Fields". */ + switch (uType) + { + case VMX_ENTRY_INT_INFO_TYPE_EXT_INT: + case VMX_ENTRY_INT_INFO_TYPE_NMI: + case VMX_ENTRY_INT_INFO_TYPE_HW_XCPT: + case VMX_ENTRY_INT_INFO_TYPE_SW_INT: + case VMX_ENTRY_INT_INFO_TYPE_PRIV_SW_XCPT: + case VMX_ENTRY_INT_INFO_TYPE_SW_XCPT: return true; + case VMX_ENTRY_INT_INFO_TYPE_OTHER_EVENT: return fSupportsMTF; + default: + return false; + } +} + + +/** + * Returns whether the given VM-entry interruption-information vector and type + * combination is valid or not. + * + * @returns @c true if it's a valid vector/type combination, @c false otherwise. + * @param uVector The VM-entry interruption-information vector. + * @param uType The VM-entry interruption-information type. + * + * @remarks Warning! This function does not validate the type field individually. + * Use it after verifying type is valid using HMVmxIsEntryIntInfoTypeValid. + */ +DECLINLINE(bool) VMXIsEntryIntInfoVectorValid(uint8_t uVector, uint8_t uType) +{ + /* See Intel spec. 26.2.1.3 "VM-Entry Control Fields". */ + if ( uType == VMX_ENTRY_INT_INFO_TYPE_NMI + && uVector != X86_XCPT_NMI) + return false; + if ( uType == VMX_ENTRY_INT_INFO_TYPE_HW_XCPT + && uVector > X86_XCPT_LAST) + return false; + if ( uType == VMX_ENTRY_INT_INFO_TYPE_OTHER_EVENT + && uVector != VMX_ENTRY_INT_INFO_VECTOR_MTF) + return false; + return true; +} + + +/** + * Returns whether or not the VM-exit is trap-like or fault-like. + * + * @returns @c true if it's a trap-like VM-exit, @c false otherwise. + * @param uExitReason The VM-exit reason. + * + * @remarks Warning! This does not validate the VM-exit reason. + */ +DECLINLINE(bool) VMXIsVmexitTrapLike(uint32_t uExitReason) +{ + /* + * Trap-like VM-exits - The instruction causing the VM-exit completes before the + * VM-exit occurs. + * + * Fault-like VM-exits - The instruction causing the VM-exit is not completed before + * the VM-exit occurs. + * + * See Intel spec. 25.5.2 "Monitor Trap Flag". + * See Intel spec. 29.1.4 "EOI Virtualization". + * See Intel spec. 29.4.3.3 "APIC-Write VM Exits". + * See Intel spec. 29.1.2 "TPR Virtualization". + */ + /** @todo NSTVMX: r=ramshankar: What about VM-exits due to debug traps (single-step, + * I/O breakpoints, data breakpoints), debug exceptions (data breakpoint) + * delayed by MovSS blocking, machine-check exceptions. */ + switch (uExitReason) + { + case VMX_EXIT_MTF: + case VMX_EXIT_VIRTUALIZED_EOI: + case VMX_EXIT_APIC_WRITE: + case VMX_EXIT_TPR_BELOW_THRESHOLD: + return true; + } + return false; +} + + +/** + * Returns whether the VM-entry is vectoring or not given the VM-entry interruption + * information field. + * + * @returns @c true if the VM-entry is vectoring, @c false otherwise. + * @param uEntryIntInfo The VM-entry interruption information field. + * @param pEntryIntInfoType The VM-entry interruption information type field. + * Optional, can be NULL. Only updated when this + * function returns @c true. + */ +DECLINLINE(bool) VMXIsVmentryVectoring(uint32_t uEntryIntInfo, uint8_t *pEntryIntInfoType) +{ + /* + * The definition of what is a vectoring VM-entry is taken + * from Intel spec. 26.6 "Special Features of VM Entry". + */ + if (!VMX_ENTRY_INT_INFO_IS_VALID(uEntryIntInfo)) + return false; + + /* Scope and keep variable defines on top to satisy archaic c89 nonsense. */ + { + uint8_t const uType = VMX_ENTRY_INT_INFO_TYPE(uEntryIntInfo); + switch (uType) + { + case VMX_ENTRY_INT_INFO_TYPE_EXT_INT: + case VMX_ENTRY_INT_INFO_TYPE_NMI: + case VMX_ENTRY_INT_INFO_TYPE_HW_XCPT: + case VMX_ENTRY_INT_INFO_TYPE_SW_INT: + case VMX_ENTRY_INT_INFO_TYPE_PRIV_SW_XCPT: + case VMX_ENTRY_INT_INFO_TYPE_SW_XCPT: + { + if (pEntryIntInfoType) + *pEntryIntInfoType = uType; + return true; + } + } + } + return false; +} + + +/** + * Gets the description for a VMX abort reason. + * + * @returns The descriptive string. + * @param enmAbort The VMX abort reason. + */ +DECLINLINE(const char *) VMXGetAbortDesc(VMXABORT enmAbort) +{ + switch (enmAbort) + { + case VMXABORT_NONE: return "VMXABORT_NONE"; + case VMXABORT_SAVE_GUEST_MSRS: return "VMXABORT_SAVE_GUEST_MSRS"; + case VMXBOART_HOST_PDPTE: return "VMXBOART_HOST_PDPTE"; + case VMXABORT_CURRENT_VMCS_CORRUPT: return "VMXABORT_CURRENT_VMCS_CORRUPT"; + case VMXABORT_LOAD_HOST_MSR: return "VMXABORT_LOAD_HOST_MSR"; + case VMXABORT_MACHINE_CHECK_XCPT: return "VMXABORT_MACHINE_CHECK_XCPT"; + case VMXABORT_HOST_NOT_IN_LONG_MODE: return "VMXABORT_HOST_NOT_IN_LONG_MODE"; + default: + break; + } + return "Unknown/invalid"; +} + + +/** + * Gets the description for a virtual VMCS state. + * + * @returns The descriptive string. + * @param fVmcsState The virtual-VMCS state. + */ +DECLINLINE(const char *) VMXGetVmcsStateDesc(uint8_t fVmcsState) +{ + switch (fVmcsState) + { + case VMX_V_VMCS_LAUNCH_STATE_CLEAR: return "Clear"; + case VMX_V_VMCS_LAUNCH_STATE_LAUNCHED: return "Launched"; + default: return "Unknown"; + } +} + + +/** + * Gets the description for a VM-entry interruption information event type. + * + * @returns The descriptive string. + * @param uType The event type. + */ +DECLINLINE(const char *) VMXGetEntryIntInfoTypeDesc(uint8_t uType) +{ + switch (uType) + { + case VMX_ENTRY_INT_INFO_TYPE_EXT_INT: return "External Interrupt"; + case VMX_ENTRY_INT_INFO_TYPE_NMI: return "NMI"; + case VMX_ENTRY_INT_INFO_TYPE_HW_XCPT: return "Hardware Exception"; + case VMX_ENTRY_INT_INFO_TYPE_SW_INT: return "Software Interrupt"; + case VMX_ENTRY_INT_INFO_TYPE_PRIV_SW_XCPT: return "Priv. Software Exception"; + case VMX_ENTRY_INT_INFO_TYPE_SW_XCPT: return "Software Exception"; + case VMX_ENTRY_INT_INFO_TYPE_OTHER_EVENT: return "Other Event"; + default: + break; + } + return "Unknown/invalid"; +} + + +/** + * Gets the description for a VM-exit interruption information event type. + * + * @returns The descriptive string. + * @param uType The event type. + */ +DECLINLINE(const char *) VMXGetExitIntInfoTypeDesc(uint8_t uType) +{ + switch (uType) + { + case VMX_EXIT_INT_INFO_TYPE_EXT_INT: return "External Interrupt"; + case VMX_EXIT_INT_INFO_TYPE_NMI: return "NMI"; + case VMX_EXIT_INT_INFO_TYPE_HW_XCPT: return "Hardware Exception"; + case VMX_EXIT_INT_INFO_TYPE_SW_INT: return "Software Interrupt"; + case VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT: return "Priv. Software Exception"; + case VMX_EXIT_INT_INFO_TYPE_SW_XCPT: return "Software Exception"; + default: + break; + } + return "Unknown/invalid"; +} + + +/** + * Gets the description for an IDT-vectoring information event type. + * + * @returns The descriptive string. + * @param uType The event type. + */ +DECLINLINE(const char *) VMXGetIdtVectoringInfoTypeDesc(uint8_t uType) +{ + switch (uType) + { + case VMX_IDT_VECTORING_INFO_TYPE_EXT_INT: return "External Interrupt"; + case VMX_IDT_VECTORING_INFO_TYPE_NMI: return "NMI"; + case VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT: return "Hardware Exception"; + case VMX_IDT_VECTORING_INFO_TYPE_SW_INT: return "Software Interrupt"; + case VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT: return "Priv. Software Exception"; + case VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT: return "Software Exception"; + default: + break; + } + return "Unknown/invalid"; +} + + +/** @} */ + + +/** @defgroup grp_hm_vmx_asm VMX Assembly Helpers + * @{ + */ +#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) + +/** + * Dispatches an NMI to the host. + */ +DECLASM(int) VMXDispatchHostNmi(void); + + +/** + * Executes VMXON. + * + * @returns VBox status code. + * @param HCPhysVmxOn Physical address of VMXON structure. + */ +#if RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS +DECLASM(int) VMXEnable(RTHCPHYS HCPhysVmxOn); +#else +DECLINLINE(int) VMXEnable(RTHCPHYS HCPhysVmxOn) +{ +# if VMX_USE_MSC_INTRINSICS + unsigned char rcMsc = __vmx_on(&HCPhysVmxOn); + if (RT_LIKELY(rcMsc == 0)) + return VINF_SUCCESS; + return rcMsc == 2 ? VERR_VMX_INVALID_VMXON_PTR : VERR_VMX_VMXON_FAILED; + +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + int rc; + __asm__ __volatile__ ( + "pushq %2 \n\t" + ".byte 0xf3, 0x0f, 0xc7, 0x34, 0x24 # VMXON [esp] \n\t" + "ja 2f \n\t" + "je 1f \n\t" + "movl $" RT_XSTR(VERR_VMX_INVALID_VMXON_PTR)", %0 \n\t" + "jmp 2f \n\t" + "1: \n\t" + "movl $" RT_XSTR(VERR_VMX_VMXON_FAILED)", %0 \n\t" + "2: \n\t" + "add $8, %%rsp \n\t" + :"=rm"(rc) + :"0"(VINF_SUCCESS), + "ir"(HCPhysVmxOn) /* don't allow direct memory reference here, */ + /* this would not work with -fomit-frame-pointer */ + :"memory" + ); + return rc; +# else + int rc; + __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 $" RT_XSTR(VERR_VMX_INVALID_VMXON_PTR)", %0 \n\t" + "jmp 2f \n\t" + "1: \n\t" + "movl $" RT_XSTR(VERR_VMX_VMXON_FAILED)", %0 \n\t" + "2: \n\t" + "add $8, %%esp \n\t" + :"=rm"(rc) + :"0"(VINF_SUCCESS), + "ir"((uint32_t)HCPhysVmxOn), /* don't allow direct memory reference here, */ + "ir"((uint32_t)(HCPhysVmxOn >> 32)) /* this would not work with -fomit-frame-pointer */ + :"memory" + ); + return rc; +# endif + +# elif defined(RT_ARCH_X86) + int rc = VINF_SUCCESS; + __asm + { + push dword ptr [HCPhysVmxOn + 4] + push dword ptr [HCPhysVmxOn] + _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_VMXON_FAILED +the_end: + add esp, 8 + } + return rc; + +# else +# error "Shouldn't be here..." +# endif +} +#endif + + +/** + * Executes VMXOFF. + */ +#if RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS +DECLASM(void) VMXDisable(void); +#else +DECLINLINE(void) VMXDisable(void) +{ +# if VMX_USE_MSC_INTRINSICS + __vmx_off(); + +# elif RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__ ( + ".byte 0x0f, 0x01, 0xc4 # VMXOFF \n\t" + ); + +# elif defined(RT_ARCH_X86) + __asm + { + _emit 0x0f + _emit 0x01 + _emit 0xc4 /* VMXOFF */ + } + +# else +# error "Shouldn't be here..." +# endif +} +#endif + + +/** + * Executes VMCLEAR. + * + * @returns VBox status code. + * @param HCPhysVmcs Physical address of VM control structure. + */ +#if RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS +DECLASM(int) VMXClearVmcs(RTHCPHYS HCPhysVmcs); +#else +DECLINLINE(int) VMXClearVmcs(RTHCPHYS HCPhysVmcs) +{ +# if VMX_USE_MSC_INTRINSICS + unsigned char rcMsc = __vmx_vmclear(&HCPhysVmcs); + if (RT_LIKELY(rcMsc == 0)) + return VINF_SUCCESS; + return VERR_VMX_INVALID_VMCS_PTR; + +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + int rc; + __asm__ __volatile__ ( + "pushq %2 \n\t" + ".byte 0x66, 0x0f, 0xc7, 0x34, 0x24 # VMCLEAR [esp] \n\t" + "jnc 1f \n\t" + "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t" + "1: \n\t" + "add $8, %%rsp \n\t" + :"=rm"(rc) + :"0"(VINF_SUCCESS), + "ir"(HCPhysVmcs) /* don't allow direct memory reference here, */ + /* this would not work with -fomit-frame-pointer */ + :"memory" + ); + return rc; +# else + int rc; + __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 $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t" + "1: \n\t" + "add $8, %%esp \n\t" + :"=rm"(rc) + :"0"(VINF_SUCCESS), + "ir"((uint32_t)HCPhysVmcs), /* don't allow direct memory reference here, */ + "ir"((uint32_t)(HCPhysVmcs >> 32)) /* this would not work with -fomit-frame-pointer */ + :"memory" + ); + return rc; +# endif + +# elif defined(RT_ARCH_X86) + int rc = VINF_SUCCESS; + __asm + { + push dword ptr [HCPhysVmcs + 4] + push dword ptr [HCPhysVmcs] + _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 + } + return rc; + +# else +# error "Shouldn't be here..." +# endif +} +#endif + + +/** + * Executes VMPTRLD. + * + * @returns VBox status code. + * @param HCPhysVmcs Physical address of VMCS structure. + */ +#if RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS +DECLASM(int) VMXLoadVmcs(RTHCPHYS HCPhysVmcs); +#else +DECLINLINE(int) VMXLoadVmcs(RTHCPHYS HCPhysVmcs) +{ +# if VMX_USE_MSC_INTRINSICS + unsigned char rcMsc = __vmx_vmptrld(&HCPhysVmcs); + if (RT_LIKELY(rcMsc == 0)) + return VINF_SUCCESS; + return VERR_VMX_INVALID_VMCS_PTR; + +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + int rc; + __asm__ __volatile__ ( + "pushq %2 \n\t" + ".byte 0x0f, 0xc7, 0x34, 0x24 # VMPTRLD [esp] \n\t" + "jnc 1f \n\t" + "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t" + "1: \n\t" + "add $8, %%rsp \n\t" + :"=rm"(rc) + :"0"(VINF_SUCCESS), + "ir"(HCPhysVmcs) /* don't allow direct memory reference here, */ + /* this will not work with -fomit-frame-pointer */ + :"memory" + ); + return rc; +# else + int rc; + __asm__ __volatile__ ( + "push %3 \n\t" + "push %2 \n\t" + ".byte 0x0f, 0xc7, 0x34, 0x24 # VMPTRLD [esp] \n\t" + "jnc 1f \n\t" + "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t" + "1: \n\t" + "add $8, %%esp \n\t" + :"=rm"(rc) + :"0"(VINF_SUCCESS), + "ir"((uint32_t)HCPhysVmcs), /* don't allow direct memory reference here, */ + "ir"((uint32_t)(HCPhysVmcs >> 32)) /* this will not work with -fomit-frame-pointer */ + :"memory" + ); + return rc; +# endif + +# elif defined(RT_ARCH_X86) + int rc = VINF_SUCCESS; + __asm + { + push dword ptr [HCPhysVmcs + 4] + push dword ptr [HCPhysVmcs] + _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 + } + return rc; + +# else +# error "Shouldn't be here..." +# endif +} +#endif + + +/** + * Executes VMPTRST. + * + * @returns VBox status code. + * @param pHCPhysVmcs Where to store the physical address of the current + * VMCS. + */ +DECLASM(int) VMXGetCurrentVmcs(RTHCPHYS *pHCPhysVmcs); + + +/** + * Executes VMWRITE for a 32-bit field. + * + * @returns VBox status code. + * @retval VINF_SUCCESS. + * @retval VERR_VMX_INVALID_VMCS_PTR. + * @retval VERR_VMX_INVALID_VMCS_FIELD. + * + * @param uFieldEnc VMCS field encoding. + * @param u32Val The 32-bit value to set. + * + * @remarks The values of the two status codes can be OR'ed together, the result + * will be VERR_VMX_INVALID_VMCS_PTR. + */ +#if RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS +DECLASM(int) VMXWriteVmcs32(uint32_t uFieldEnc, uint32_t u32Val); +#else +DECLINLINE(int) VMXWriteVmcs32(uint32_t uFieldEnc, uint32_t u32Val) +{ +# if VMX_USE_MSC_INTRINSICS +# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK + __vmx_vmwrite(uFieldEnc, u32Val); + return VINF_SUCCESS; +# else + unsigned char rcMsc = __vmx_vmwrite(uFieldEnc, u32Val); + if (RT_LIKELY(rcMsc == 0)) + return VINF_SUCCESS; + return rcMsc == 2 ? VERR_VMX_INVALID_VMCS_PTR : VERR_VMX_INVALID_VMCS_FIELD; +# endif + +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK + __asm__ __volatile__ ( + ".byte 0x0f, 0x79, 0xc2 # VMWRITE eax, edx \n\t" + : + :"a"(uFieldEnc), + "d"(u32Val) + ); + return VINF_SUCCESS; +# else + int rc; + __asm__ __volatile__ ( + ".byte 0x0f, 0x79, 0xc2 # VMWRITE eax, edx \n\t" + "ja 2f \n\t" + "je 1f \n\t" + "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t" + "jmp 2f \n\t" + "1: \n\t" + "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_FIELD)", %0 \n\t" + "2: \n\t" + :"=rm"(rc) + :"0"(VINF_SUCCESS), + "a"(uFieldEnc), + "d"(u32Val) + ); + return rc; +# endif + +# elif defined(RT_ARCH_X86) + int rc = VINF_SUCCESS; + __asm + { + push dword ptr [u32Val] + mov eax, [uFieldEnc] + _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 + } + return rc; + +# else +# error "Shouldn't be here..." +# endif +} +#endif + + +/** + * Executes VMWRITE for a 64-bit field. + * + * @returns VBox status code. + * @retval VINF_SUCCESS. + * @retval VERR_VMX_INVALID_VMCS_PTR. + * @retval VERR_VMX_INVALID_VMCS_FIELD. + * + * @param uFieldEnc The VMCS field encoding. + * @param u64Val The 16, 32 or 64-bit value to set. + * + * @remarks The values of the two status codes can be OR'ed together, the result + * will be VERR_VMX_INVALID_VMCS_PTR. + */ +#if defined(RT_ARCH_X86) || (RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS) +DECLASM(int) VMXWriteVmcs64(uint32_t uFieldEnc, uint64_t u64Val); +#else +DECLINLINE(int) VMXWriteVmcs64(uint32_t uFieldEnc, uint64_t u64Val) +{ +# if VMX_USE_MSC_INTRINSICS +# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK + __vmx_vmwrite(uFieldEnc, u64Val); + return VINF_SUCCESS; +# else + unsigned char rcMsc = __vmx_vmwrite(uFieldEnc, u64Val); + if (RT_LIKELY(rcMsc == 0)) + return VINF_SUCCESS; + return rcMsc == 2 ? VERR_VMX_INVALID_VMCS_PTR : VERR_VMX_INVALID_VMCS_FIELD; +# endif + +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK + __asm__ __volatile__ ( + ".byte 0x0f, 0x79, 0xc2 # VMWRITE eax, edx \n\t" + : + :"a"(uFieldEnc), + "d"(u64Val) + ); + return VINF_SUCCESS; +# else + int rc; + __asm__ __volatile__ ( + ".byte 0x0f, 0x79, 0xc2 # VMWRITE eax, edx \n\t" + "ja 2f \n\t" + "je 1f \n\t" + "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t" + "jmp 2f \n\t" + "1: \n\t" + "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_FIELD)", %0 \n\t" + "2: \n\t" + :"=rm"(rc) + :"0"(VINF_SUCCESS), + "a"(uFieldEnc), + "d"(u64Val) + ); + return rc; +# endif + +# else +# error "Shouldn't be here..." +# endif +} +#endif + + +/** + * Executes VMWRITE for a 16-bit VMCS field. + * + * @returns VBox status code. + * @retval VINF_SUCCESS. + * @retval VERR_VMX_INVALID_VMCS_PTR. + * @retval VERR_VMX_INVALID_VMCS_FIELD. + * + * @param uVmcsField The VMCS field. + * @param u16Val The 16-bit value to set. + * + * @remarks The values of the two status codes can be OR'ed together, the result + * will be VERR_VMX_INVALID_VMCS_PTR. + */ +DECLINLINE(int) VMXWriteVmcs16(uint32_t uVmcsField, uint16_t u16Val) +{ + AssertMsg(RT_BF_GET(uVmcsField, VMX_BF_VMCSFIELD_WIDTH) == VMX_VMCSFIELD_WIDTH_16BIT, ("%#RX32\n", uVmcsField)); + return VMXWriteVmcs32(uVmcsField, u16Val); +} + + +/** + * Executes VMWRITE for a natural-width VMCS field. + */ +#ifdef RT_ARCH_AMD64 +# define VMXWriteVmcsNw VMXWriteVmcs64 +#else +# define VMXWriteVmcsNw VMXWriteVmcs32 +#endif + + +/** + * Invalidate a page using INVEPT. + * + * @returns VBox status code. + * @param enmFlush Type of flush. + * @param pDescriptor Pointer to the descriptor. + */ +DECLASM(int) VMXR0InvEPT(VMXTLBFLUSHEPT enmFlush, uint64_t *pDescriptor); + + +/** + * Invalidate a page using INVVPID. + * + * @returns VBox status code. + * @param enmFlush Type of flush. + * @param pDescriptor Pointer to the descriptor. + */ +DECLASM(int) VMXR0InvVPID(VMXTLBFLUSHVPID enmFlush, uint64_t *pDescriptor); + + +/** + * Executes VMREAD for a 32-bit field. + * + * @returns VBox status code. + * @retval VINF_SUCCESS. + * @retval VERR_VMX_INVALID_VMCS_PTR. + * @retval VERR_VMX_INVALID_VMCS_FIELD. + * + * @param uFieldEnc The VMCS field encoding. + * @param pData Where to store VMCS field value. + * + * @remarks The values of the two status codes can be OR'ed together, the result + * will be VERR_VMX_INVALID_VMCS_PTR. + */ +#if RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS +DECLASM(int) VMXReadVmcs32(uint32_t uFieldEnc, uint32_t *pData); +#else +DECLINLINE(int) VMXReadVmcs32(uint32_t uFieldEnc, uint32_t *pData) +{ +# if VMX_USE_MSC_INTRINSICS +# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK + uint64_t u64Tmp = 0; + __vmx_vmread(uFieldEnc, &u64Tmp); + *pData = (uint32_t)u64Tmp; + return VINF_SUCCESS; +# else + unsigned char rcMsc; + uint64_t u64Tmp; + rcMsc = __vmx_vmread(uFieldEnc, &u64Tmp); + *pData = (uint32_t)u64Tmp; + if (RT_LIKELY(rcMsc == 0)) + return VINF_SUCCESS; + return rcMsc == 2 ? VERR_VMX_INVALID_VMCS_PTR : VERR_VMX_INVALID_VMCS_FIELD; +# endif + +# elif VMX_USE_GNU_STYLE_INLINE_VMX_INSTRUCTIONS + RTCCUINTREG uTmp = 0; +# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK + __asm__ __volatile__("vmread %[uField],%[uDst]" + : [uDst] "=mr" (uTmp) + : [uField] "r" ((RTCCUINTREG)uFieldEnc)); + *pData = (uint32_t)uTmp; + return VINF_SUCCESS; +# else +#if 0 + int rc; + __asm__ __volatile__("vmread %[uField],%[uDst]\n\t" + "movl %[rcSuccess],%[rc]\n\t" +# if VMX_USE_GNU_STYLE_INLINE_SECTION_TRICK + "jna 1f\n\t" + ".section .text.vmread_failures, \"ax?\"\n\t" + "1:\n\t" + "movl %[rcInvalidVmcsPtr],%[rc]\n\t" + "jnz 2f\n\t" + "movl %[rcInvalidVmcsField],%[rc]\n\t" + "2:\n\t" + "jmp 3f\n\t" + ".previous\n\t" + "3:\n\t" +# else + "ja 1f\n\t" + "movl %[rcInvalidVmcsPtr],%[rc]\n\t" + "jnz 1f\n\t" + "movl %[rcInvalidVmcsField],%[rc]\n\t" + "1:\n\t" +# endif + : [uDst] "=mr" (uTmp) + , [rc] "=r" (rc) + : [uField] "r" ((RTCCUINTREG)uFieldEnc) + , [rcSuccess] "i" (VINF_SUCCESS) + , [rcInvalidVmcsPtr] "i" (VERR_VMX_INVALID_VMCS_PTR) + , [rcInvalidVmcsField] "i" (VERR_VMX_INVALID_VMCS_FIELD)); + *pData = uTmp; + return rc; +#else + int fSuccess, fFieldError; + __asm__ __volatile__("vmread %[uField],%[uDst]" + : [uDst] "=mr" (uTmp) + , "=@cca" (fSuccess) + , "=@ccnc" (fFieldError) + : [uField] "r" ((RTCCUINTREG)uFieldEnc)); + *pData = uTmp; + return RT_LIKELY(fSuccess) ? VINF_SUCCESS : fFieldError ? VERR_VMX_INVALID_VMCS_FIELD : VERR_VMX_INVALID_VMCS_PTR; +#endif +# endif + +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK + __asm__ __volatile__ ( + ".byte 0x0f, 0x78, 0xc2 # VMREAD eax, edx \n\t" + :"=d"(*pData) + :"a"(uFieldEnc), + "d"(0) + ); + return VINF_SUCCESS; +# else + int rc; + __asm__ __volatile__ ( + "movl $" RT_XSTR(VINF_SUCCESS)", %0 \n\t" + ".byte 0x0f, 0x78, 0xc2 # VMREAD eax, edx \n\t" + "ja 2f \n\t" + "je 1f \n\t" + "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t" + "jmp 2f \n\t" + "1: \n\t" + "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_FIELD)", %0 \n\t" + "2: \n\t" + :"=&r"(rc), + "=d"(*pData) + :"a"(uFieldEnc), + "d"(0) + ); + return rc; +# endif + +# elif defined(RT_ARCH_X86) + int rc = VINF_SUCCESS; + __asm + { + sub esp, 4 + mov dword ptr [esp], 0 + mov eax, [uFieldEnc] + _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: + } + return rc; + +# else +# error "Shouldn't be here..." +# endif +} +#endif + + +/** + * Executes VMREAD for a 64-bit field. + * + * @returns VBox status code. + * @retval VINF_SUCCESS. + * @retval VERR_VMX_INVALID_VMCS_PTR. + * @retval VERR_VMX_INVALID_VMCS_FIELD. + * + * @param uFieldEnc The VMCS field encoding. + * @param pData Where to store VMCS field value. + * + * @remarks The values of the two status codes can be OR'ed together, the result + * will be VERR_VMX_INVALID_VMCS_PTR. + */ +#if defined(RT_ARCH_X86) || (RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS) +DECLASM(int) VMXReadVmcs64(uint32_t uFieldEnc, uint64_t *pData); +#else +DECLINLINE(int) VMXReadVmcs64(uint32_t uFieldEnc, uint64_t *pData) +{ +# if VMX_USE_MSC_INTRINSICS +# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK + __vmx_vmread(uFieldEnc, pData); + return VINF_SUCCESS; +# else + unsigned char rcMsc; + rcMsc = __vmx_vmread(uFieldEnc, pData); + if (RT_LIKELY(rcMsc == 0)) + return VINF_SUCCESS; + return rcMsc == 2 ? VERR_VMX_INVALID_VMCS_PTR : VERR_VMX_INVALID_VMCS_FIELD; +# endif + +# elif VMX_USE_GNU_STYLE_INLINE_VMX_INSTRUCTIONS + uint64_t uTmp = 0; +# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK + __asm__ __volatile__("vmreadq %[uField],%[uDst]" + : [uDst] "=m" (uTmp) + : [uField] "r" ((uint64_t)uFieldEnc)); + *pData = uTmp; + return VINF_SUCCESS; +# elif 0 + int rc; + __asm__ __volatile__("vmreadq %[uField],%[uDst]\n\t" + "movl %[rcSuccess],%[rc]\n\t" +# if VMX_USE_GNU_STYLE_INLINE_SECTION_TRICK + "jna 1f\n\t" + ".section .text.vmread_failures, \"ax?\"\n\t" + "1:\n\t" + "movl %[rcInvalidVmcsPtr],%[rc]\n\t" + "jnz 2f\n\t" + "movl %[rcInvalidVmcsField],%[rc]\n\t" + "2:\n\t" + "jmp 3f\n\t" + ".previous\n\t" + "3:\n\t" +# else + "ja 1f\n\t" + "movl %[rcInvalidVmcsPtr],%[rc]\n\t" + "jnz 1f\n\t" + "movl %[rcInvalidVmcsField],%[rc]\n\t" + "1:\n\t" +# endif + : [uDst] "=mr" (uTmp) + , [rc] "=r" (rc) + : [uField] "r" ((uint64_t)uFieldEnc) + , [rcSuccess] "i" (VINF_SUCCESS) + , [rcInvalidVmcsPtr] "i" (VERR_VMX_INVALID_VMCS_PTR) + , [rcInvalidVmcsField] "i" (VERR_VMX_INVALID_VMCS_FIELD) + ); + *pData = uTmp; + return rc; +# else + int fSuccess, fFieldError; + __asm__ __volatile__("vmread %[uField],%[uDst]" + : [uDst] "=mr" (uTmp) + , "=@cca" (fSuccess) + , "=@ccnc" (fFieldError) + : [uField] "r" ((RTCCUINTREG)uFieldEnc)); + *pData = uTmp; + return RT_LIKELY(fSuccess) ? VINF_SUCCESS : fFieldError ? VERR_VMX_INVALID_VMCS_FIELD : VERR_VMX_INVALID_VMCS_PTR; +# endif + +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK + __asm__ __volatile__ ( + ".byte 0x0f, 0x78, 0xc2 # VMREAD eax, edx \n\t" + :"=d"(*pData) + :"a"(uFieldEnc), + "d"(0) + ); + return VINF_SUCCESS; +# else + int rc; + __asm__ __volatile__ ( + "movl $" RT_XSTR(VINF_SUCCESS)", %0 \n\t" + ".byte 0x0f, 0x78, 0xc2 # VMREAD eax, edx \n\t" + "ja 2f \n\t" + "je 1f \n\t" + "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t" + "jmp 2f \n\t" + "1: \n\t" + "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_FIELD)", %0 \n\t" + "2: \n\t" + :"=&r"(rc), + "=d"(*pData) + :"a"(uFieldEnc), + "d"(0) + ); + return rc; +# endif + +# else +# error "Shouldn't be here..." +# endif +} +#endif + + +/** + * Executes VMREAD for a 16-bit field. + * + * @returns VBox status code. + * @retval VINF_SUCCESS. + * @retval VERR_VMX_INVALID_VMCS_PTR. + * @retval VERR_VMX_INVALID_VMCS_FIELD. + * + * @param uVmcsField The VMCS field. + * @param pData Where to store VMCS field value. + * + * @remarks The values of the two status codes can be OR'ed together, the result + * will be VERR_VMX_INVALID_VMCS_PTR. + */ +DECLINLINE(int) VMXReadVmcs16(uint32_t uVmcsField, uint16_t *pData) +{ + uint32_t u32Tmp; + int rc; + AssertMsg(RT_BF_GET(uVmcsField, VMX_BF_VMCSFIELD_WIDTH) == VMX_VMCSFIELD_WIDTH_16BIT, ("%#RX32\n", uVmcsField)); + rc = VMXReadVmcs32(uVmcsField, &u32Tmp); + *pData = (uint16_t)u32Tmp; + return rc; +} + + +/** + * Executes VMREAD for a natural-width VMCS field. + */ +#ifdef RT_ARCH_AMD64 +# define VMXReadVmcsNw VMXReadVmcs64 +#else +# define VMXReadVmcsNw VMXReadVmcs32 +#endif + +#endif /* RT_ARCH_AMD64 || RT_ARCH_X86 */ + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_hmvmxinline_h */ + diff --git a/include/VBox/vmm/iem.h b/include/VBox/vmm/iem.h new file mode 100644 index 00000000..ef50970d --- /dev/null +++ b/include/VBox/vmm/iem.h @@ -0,0 +1,422 @@ +/** @file + * IEM - Interpreted Execution Manager. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_iem_h +#define VBOX_INCLUDED_vmm_iem_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <VBox/vmm/trpm.h> +#ifdef VBOX_WITH_NESTED_HWVIRT_VMX +# include <VBox/vmm/hm_vmx.h> +#endif +#include <iprt/assert.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_iem The Interpreted Execution Manager API. + * @ingroup grp_vmm + * @{ + */ + +/** @name IEMXCPTRAISEINFO_XXX - Extra info. on a recursive exception situation. + * + * This is primarily used by HM for working around a PGM limitation (see + * @bugref{6607}) and special NMI/IRET handling. In the future, this may be + * used for diagnostics. + * + * @{ + */ +typedef uint32_t IEMXCPTRAISEINFO; +/** Pointer to a IEMXCPTINFO type. */ +typedef IEMXCPTRAISEINFO *PIEMXCPTRAISEINFO; +/** No addition info. available. */ +#define IEMXCPTRAISEINFO_NONE RT_BIT_32(0) +/** Delivery of a \#AC caused another \#AC. */ +#define IEMXCPTRAISEINFO_AC_AC RT_BIT_32(1) +/** Delivery of a \#PF caused another \#PF. */ +#define IEMXCPTRAISEINFO_PF_PF RT_BIT_32(2) +/** Delivery of a \#PF caused some contributory exception. */ +#define IEMXCPTRAISEINFO_PF_CONTRIBUTORY_XCPT RT_BIT_32(3) +/** Delivery of an external interrupt caused an exception. */ +#define IEMXCPTRAISEINFO_EXT_INT_XCPT RT_BIT_32(4) +/** Delivery of an external interrupt caused an \#PF. */ +#define IEMXCPTRAISEINFO_EXT_INT_PF RT_BIT_32(5) +/** Delivery of a software interrupt caused an exception. */ +#define IEMXCPTRAISEINFO_SOFT_INT_XCPT RT_BIT_32(6) +/** Delivery of an NMI caused an exception. */ +#define IEMXCPTRAISEINFO_NMI_XCPT RT_BIT_32(7) +/** Delivery of an NMI caused a \#PF. */ +#define IEMXCPTRAISEINFO_NMI_PF RT_BIT_32(8) +/** Can re-execute the instruction at CS:RIP. */ +#define IEMXCPTRAISEINFO_CAN_REEXEC_INSTR RT_BIT_32(9) +/** @} */ + + +/** @name IEMXCPTRAISE_XXX - Ways to handle a recursive exception condition. + * @{ */ +typedef enum IEMXCPTRAISE +{ + /** Raise the current (second) exception. */ + IEMXCPTRAISE_CURRENT_XCPT = 0, + /** Re-raise the previous (first) event (for HM, unused by IEM). */ + IEMXCPTRAISE_PREV_EVENT, + /** Re-execute instruction at CS:RIP (for HM, unused by IEM). */ + IEMXCPTRAISE_REEXEC_INSTR, + /** Raise a \#DF exception. */ + IEMXCPTRAISE_DOUBLE_FAULT, + /** Raise a triple fault. */ + IEMXCPTRAISE_TRIPLE_FAULT, + /** Cause a CPU hang. */ + IEMXCPTRAISE_CPU_HANG, + /** Invalid sequence of events. */ + IEMXCPTRAISE_INVALID = 0x7fffffff +} IEMXCPTRAISE; +/** Pointer to a IEMXCPTRAISE type. */ +typedef IEMXCPTRAISE *PIEMXCPTRAISE; +/** @} */ + + +/** @name Operand or addressing mode. + * @{ */ +typedef uint8_t IEMMODE; +#define IEMMODE_16BIT 0 +#define IEMMODE_32BIT 1 +#define IEMMODE_64BIT 2 +/** @} */ + + +/** @name IEM_XCPT_FLAGS_XXX - flags for iemRaiseXcptOrInt. + * @{ */ +/** CPU exception. */ +#define IEM_XCPT_FLAGS_T_CPU_XCPT RT_BIT_32(0) +/** External interrupt (from PIC, APIC, whatever). */ +#define IEM_XCPT_FLAGS_T_EXT_INT RT_BIT_32(1) +/** Software interrupt (int or into, not bound). + * Returns to the following instruction */ +#define IEM_XCPT_FLAGS_T_SOFT_INT RT_BIT_32(2) +/** Takes an error code. */ +#define IEM_XCPT_FLAGS_ERR RT_BIT_32(3) +/** Takes a CR2. */ +#define IEM_XCPT_FLAGS_CR2 RT_BIT_32(4) +/** Generated by the breakpoint instruction. */ +#define IEM_XCPT_FLAGS_BP_INSTR RT_BIT_32(5) +/** Generated by a DRx instruction breakpoint and RF should be cleared. */ +#define IEM_XCPT_FLAGS_DRx_INSTR_BP RT_BIT_32(6) +/** Generated by the icebp instruction. */ +#define IEM_XCPT_FLAGS_ICEBP_INSTR RT_BIT_32(7) +/** Generated by the overflow instruction. */ +#define IEM_XCPT_FLAGS_OF_INSTR RT_BIT_32(8) +/** @} */ + + +/** @name IEMTARGETCPU_XXX - IEM target CPU specification. + * + * This is a gross simpliciation of CPUMMICROARCH for dealing with really old + * CPUs which didn't have much in the way of hinting at supported instructions + * and features. This slowly changes with the introduction of CPUID with the + * Intel Pentium. + * + * @{ + */ +/** The dynamic target CPU mode is for getting thru the BIOS and then use + * the debugger or modifying instruction behaviour (e.g. HLT) to switch to a + * different target CPU. */ +#define IEMTARGETCPU_DYNAMIC UINT32_C(0) +/** Intel 8086/8088. */ +#define IEMTARGETCPU_8086 UINT32_C(1) +/** NEC V20/V30. + * @remarks must be between 8086 and 80186. */ +#define IEMTARGETCPU_V20 UINT32_C(2) +/** Intel 80186/80188. */ +#define IEMTARGETCPU_186 UINT32_C(3) +/** Intel 80286. */ +#define IEMTARGETCPU_286 UINT32_C(4) +/** Intel 80386. */ +#define IEMTARGETCPU_386 UINT32_C(5) +/** Intel 80486. */ +#define IEMTARGETCPU_486 UINT32_C(6) +/** Intel Pentium . */ +#define IEMTARGETCPU_PENTIUM UINT32_C(7) +/** Intel PentiumPro. */ +#define IEMTARGETCPU_PPRO UINT32_C(8) +/** A reasonably current CPU, probably newer than the pentium pro when it comes + * to the feature set and behaviour. Generally the CPUID info and CPU vendor + * dicates the behaviour here. */ +#define IEMTARGETCPU_CURRENT UINT32_C(9) +/** @} */ + + +/** @name IEM status codes. + * + * Not quite sure how this will play out in the end, just aliasing safe status + * codes for now. + * + * @{ */ +#define VINF_IEM_RAISED_XCPT VINF_EM_RESCHEDULE +/** @} */ + + +/** The CPUMCTX_EXTRN_XXX mask required to be cleared when interpreting anything. + * IEM will ASSUME the caller of IEM APIs has ensured these are already present. */ +#define IEM_CPUMCTX_EXTRN_MUST_MASK ( CPUMCTX_EXTRN_GPRS_MASK \ + | CPUMCTX_EXTRN_RIP \ + | CPUMCTX_EXTRN_RFLAGS \ + | CPUMCTX_EXTRN_SS \ + | CPUMCTX_EXTRN_CS \ + | CPUMCTX_EXTRN_CR0 \ + | CPUMCTX_EXTRN_CR3 \ + | CPUMCTX_EXTRN_CR4 \ + | CPUMCTX_EXTRN_APIC_TPR \ + | CPUMCTX_EXTRN_EFER \ + | CPUMCTX_EXTRN_DR7 ) +/** The CPUMCTX_EXTRN_XXX mask needed when injecting an exception/interrupt. + * IEM will import missing bits, callers are encouraged to make these registers + * available prior to injection calls if fetching state anyway. */ +#define IEM_CPUMCTX_EXTRN_XCPT_MASK ( IEM_CPUMCTX_EXTRN_MUST_MASK \ + | CPUMCTX_EXTRN_CR2 \ + | CPUMCTX_EXTRN_SREG_MASK \ + | CPUMCTX_EXTRN_TABLE_MASK ) +/** The CPUMCTX_EXTRN_XXX mask required to be cleared when calling any + * IEMExecDecoded API not using memory. IEM will ASSUME the caller of IEM + * APIs has ensured these are already present. + * @note ASSUMES execution engine has checked for instruction breakpoints + * during decoding. */ +#define IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK ( CPUMCTX_EXTRN_RIP \ + | CPUMCTX_EXTRN_RFLAGS \ + | CPUMCTX_EXTRN_SS /* for CPL */ \ + | CPUMCTX_EXTRN_CS /* for mode */ \ + | CPUMCTX_EXTRN_CR0 /* for mode */ \ + | CPUMCTX_EXTRN_EFER /* for mode */ ) +/** The CPUMCTX_EXTRN_XXX mask required to be cleared when calling any + * IEMExecDecoded API using memory. IEM will ASSUME the caller of IEM + * APIs has ensured these are already present. + * @note ASSUMES execution engine has checked for instruction breakpoints + * during decoding. */ +#define IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK ( IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK \ + | CPUMCTX_EXTRN_CR3 /* for page tables */ \ + | CPUMCTX_EXTRN_CR4 /* for mode paging mode */ \ + | CPUMCTX_EXTRN_DR7 /* for memory breakpoints */ ) + +#ifdef VBOX_WITH_NESTED_HWVIRT_VMX +/** The CPUMCTX_EXTRN_XXX mask needed when calling IEMExecDecodedVmlaunchVmresume(). + * IEM will ASSUME the caller has ensured these are already present. */ +# define IEM_CPUMCTX_EXTRN_VMX_VMENTRY_MASK ( IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK \ + | CPUMCTX_EXTRN_CR2 \ + | CPUMCTX_EXTRN_HWVIRT ) + +/** The CPUMCTX_EXTRN_XXX mask that the IEM VM-exit code will import on-demand when + * needed, primarily because there are several IEM VM-exit interface functions and + * some of which may not cause a VM-exit at all. + * + * This is currently unused, but keeping it here in case we can get away a bit more + * fine-grained state handling. + * + * @note Update HM_CHANGED_VMX_VMEXIT_MASK if something here changes. */ +# define IEM_CPUMCTX_EXTRN_VMX_VMEXIT_MASK ( CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_CR3 | CPUMCTX_EXTRN_CR4 \ + | CPUMCTX_EXTRN_DR7 | CPUMCTX_EXTRN_DR6 \ + | CPUMCTX_EXTRN_EFER \ + | CPUMCTX_EXTRN_SYSENTER_MSRS \ + | CPUMCTX_EXTRN_OTHER_MSRS /* for PAT MSR */ \ + | CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_RFLAGS \ + | CPUMCTX_EXTRN_SREG_MASK \ + | CPUMCTX_EXTRN_TR \ + | CPUMCTX_EXTRN_LDTR | CPUMCTX_EXTRN_GDTR | CPUMCTX_EXTRN_IDTR \ + | CPUMCTX_EXTRN_HWVIRT ) +#endif + +#ifdef VBOX_WITH_NESTED_HWVIRT_SVM +/** The CPUMCTX_EXTRN_XXX mask needed when calling IEMExecSvmVmexit(). + * IEM will ASSUME the caller has ensured these are already present. */ +# define IEM_CPUMCTX_EXTRN_SVM_VMEXIT_MASK ( CPUMCTX_EXTRN_RSP \ + | CPUMCTX_EXTRN_RAX \ + | CPUMCTX_EXTRN_RIP \ + | CPUMCTX_EXTRN_RFLAGS \ + | CPUMCTX_EXTRN_CS \ + | CPUMCTX_EXTRN_SS \ + | CPUMCTX_EXTRN_DS \ + | CPUMCTX_EXTRN_ES \ + | CPUMCTX_EXTRN_GDTR \ + | CPUMCTX_EXTRN_IDTR \ + | CPUMCTX_EXTRN_CR_MASK \ + | CPUMCTX_EXTRN_EFER \ + | CPUMCTX_EXTRN_DR6 \ + | CPUMCTX_EXTRN_DR7 \ + | CPUMCTX_EXTRN_OTHER_MSRS \ + | CPUMCTX_EXTRN_HWVIRT \ + | CPUMCTX_EXTRN_APIC_TPR \ + | CPUMCTX_EXTRN_HM_SVM_HWVIRT_VIRQ) + +/** The CPUMCTX_EXTRN_XXX mask needed when calling IEMExecDecodedVmrun(). + * IEM will ASSUME the caller has ensured these are already present. */ +# define IEM_CPUMCTX_EXTRN_SVM_VMRUN_MASK IEM_CPUMCTX_EXTRN_SVM_VMEXIT_MASK +#endif + +VMMDECL(VBOXSTRICTRC) IEMExecOne(PVMCPUCC pVCpu); +VMMDECL(VBOXSTRICTRC) IEMExecOneEx(PVMCPUCC pVCpu, uint32_t *pcbWritten); +VMMDECL(VBOXSTRICTRC) IEMExecOneWithPrefetchedByPC(PVMCPUCC pVCpu, uint64_t OpcodeBytesPC, + const void *pvOpcodeBytes, size_t cbOpcodeBytes); +VMMDECL(VBOXSTRICTRC) IEMExecOneBypassEx(PVMCPUCC pVCpu, uint32_t *pcbWritten); +VMMDECL(VBOXSTRICTRC) IEMExecOneBypassWithPrefetchedByPC(PVMCPUCC pVCpu, uint64_t OpcodeBytesPC, + const void *pvOpcodeBytes, size_t cbOpcodeBytes); +VMMDECL(VBOXSTRICTRC) IEMExecOneIgnoreLock(PVMCPUCC pVCpu); +VMMDECL(VBOXSTRICTRC) IEMExecLots(PVMCPUCC pVCpu, uint32_t cMaxInstructions, uint32_t cPollRate, uint32_t *pcInstructions); +/** Statistics returned by IEMExecForExits. */ +typedef struct IEMEXECFOREXITSTATS +{ + uint32_t cInstructions; + uint32_t cExits; + uint32_t cMaxExitDistance; + uint32_t cReserved; +} IEMEXECFOREXITSTATS; +/** Pointer to statistics returned by IEMExecForExits. */ +typedef IEMEXECFOREXITSTATS *PIEMEXECFOREXITSTATS; +VMMDECL(VBOXSTRICTRC) IEMExecForExits(PVMCPUCC pVCpu, uint32_t fWillExit, uint32_t cMinInstructions, uint32_t cMaxInstructions, + uint32_t cMaxInstructionsWithoutExits, PIEMEXECFOREXITSTATS pStats); +VMMDECL(VBOXSTRICTRC) IEMInjectTrpmEvent(PVMCPUCC pVCpu); +VMM_INT_DECL(VBOXSTRICTRC) IEMInjectTrap(PVMCPUCC pVCpu, uint8_t u8TrapNo, TRPMEVENT enmType, uint16_t uErrCode, RTGCPTR uCr2, + uint8_t cbInstr); + +VMM_INT_DECL(int) IEMBreakpointSet(PVM pVM, RTGCPTR GCPtrBp); +VMM_INT_DECL(int) IEMBreakpointClear(PVM pVM, RTGCPTR GCPtrBp); + +VMM_INT_DECL(void) IEMTlbInvalidateAll(PVMCPUCC pVCpu); +VMM_INT_DECL(void) IEMTlbInvalidatePage(PVMCPUCC pVCpu, RTGCPTR GCPtr); +VMM_INT_DECL(void) IEMTlbInvalidateAllPhysical(PVMCPUCC pVCpu); +VMM_INT_DECL(void) IEMTlbInvalidateAllPhysicalAllCpus(PVMCC pVM, VMCPUID idCpuCaller); +VMM_INT_DECL(bool) IEMGetCurrentXcpt(PVMCPUCC pVCpu, uint8_t *puVector, uint32_t *pfFlags, uint32_t *puErr, + uint64_t *puCr2); +VMM_INT_DECL(IEMXCPTRAISE) IEMEvaluateRecursiveXcpt(PVMCPUCC pVCpu, uint32_t fPrevFlags, uint8_t uPrevVector, uint32_t fCurFlags, + uint8_t uCurVector, PIEMXCPTRAISEINFO pXcptRaiseInfo); + +/** @name Given Instruction Interpreters + * @{ */ +VMM_INT_DECL(VBOXSTRICTRC) IEMExecStringIoWrite(PVMCPUCC pVCpu, uint8_t cbValue, IEMMODE enmAddrMode, + bool fRepPrefix, uint8_t cbInstr, uint8_t iEffSeg, bool fIoChecked); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecStringIoRead(PVMCPUCC pVCpu, uint8_t cbValue, IEMMODE enmAddrMode, + bool fRepPrefix, uint8_t cbInstr, bool fIoChecked); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedOut(PVMCPUCC pVCpu, uint8_t cbInstr, uint16_t u16Port, bool fImm, uint8_t cbReg); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedIn(PVMCPUCC pVCpu, uint8_t cbInstr, uint16_t u16Port, bool fImm, uint8_t cbReg); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedMovCRxWrite(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iCrReg, uint8_t iGReg); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedMovCRxRead(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iGReg, uint8_t iCrReg); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedMovDRxWrite(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iDrReg, uint8_t iGReg); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedMovDRxRead(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iGReg, uint8_t iDrReg); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedClts(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedLmsw(PVMCPUCC pVCpu, uint8_t cbInstr, uint16_t uValue, RTGCPTR GCPtrEffDst); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedXsetbv(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedWbinvd(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedInvd(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedInvlpg(PVMCPUCC pVCpu, uint8_t cbInstr, RTGCPTR GCPtrPage); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedInvpcid(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iEffSeg, RTGCPTR GCPtrDesc, + uint64_t uType); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedCpuid(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedRdpmc(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedRdtsc(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedRdtscp(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedRdmsr(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedWrmsr(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedMonitor(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedMwait(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedHlt(PVMCPUCC pVCpu, uint8_t cbInstr); + +#ifdef VBOX_WITH_NESTED_HWVIRT_SVM +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedClgi(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedStgi(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedVmload(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedVmsave(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedInvlpga(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedVmrun(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecSvmVmexit(PVMCPUCC pVCpu, uint64_t uExitCode, uint64_t uExitInfo1, uint64_t uExitInfo2); +#endif + +#ifdef VBOX_WITH_NESTED_HWVIRT_VMX +VMM_INT_DECL(void) IEMReadVmxVmcsField(PCVMXVVMCS pVmcs, uint64_t u64VmcsField, uint64_t *pu64Dst); +VMM_INT_DECL(void) IEMWriteVmxVmcsField(PVMXVVMCS pVmcs, uint64_t u64VmcsField, uint64_t u64Val); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVirtApicAccessMsr(PVMCPUCC pVCpu, uint32_t idMsr, uint64_t *pu64Val, bool fWrite); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitApicWrite(PVMCPUCC pVCpu); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitPreemptTimer(PVMCPUCC pVCpu); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitExtInt(PVMCPUCC pVCpu, uint8_t uVector, bool fIntPending); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitXcpt(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo, PCVMXVEXITEVENTINFO pExitEventInfo); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitXcptNmi(PVMCPUCC pVCpu); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitTripleFault(PVMCPUCC pVCpu); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitStartupIpi(PVMCPUCC pVCpu, uint8_t uVector); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitInstrWithInfo(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitInstr(PVMCPUCC pVCpu, uint32_t uExitReason, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitTrapLike(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitTaskSwitch(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo, PCVMXVEXITEVENTINFO pExitEventInfo); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitApicAccess(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo, PCVMXVEXITEVENTINFO pExitEventInfo); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexit(PVMCPUCC pVCpu, uint32_t uExitReason, uint64_t uExitQual); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedVmread(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedVmwrite(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedVmptrld(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedVmptrst(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedVmclear(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedVmlaunchVmresume(PVMCPUCC pVCpu, uint8_t cbInstr, VMXINSTRID uInstrId); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedVmxon(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedVmxoff(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedInvvpid(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo); +# ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedInvept(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitEptViolation(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo, PCVMXVEXITEVENTINFO pExitEventInfo); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitEptMisconfig(PVMCPUCC pVCpu, RTGCPHYS GCPhysAddr, PCVMXVEXITEVENTINFO pExitEventInfo); +# endif +#endif +/** @} */ + +/** @defgroup grp_iem_r3 The IEM Host Context Ring-3 API. + * @{ + */ +VMMR0_INT_DECL(int) IEMR0InitVM(PGVM pGVM); +/** @} */ + + +/** @defgroup grp_iem_r3 The IEM Host Context Ring-3 API. + * @{ + */ +VMMR3DECL(int) IEMR3Init(PVM pVM); +VMMR3DECL(int) IEMR3Term(PVM pVM); +VMMR3DECL(void) IEMR3Relocate(PVM pVM); +VMMR3_INT_DECL(VBOXSTRICTRC) IEMR3ProcessForceFlag(PVM pVM, PVMCPUCC pVCpu, VBOXSTRICTRC rcStrict); +/** @} */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_iem_h */ + diff --git a/include/VBox/vmm/iom.h b/include/VBox/vmm/iom.h new file mode 100644 index 00000000..a2ff5891 --- /dev/null +++ b/include/VBox/vmm/iom.h @@ -0,0 +1,550 @@ +/** @file + * IOM - Input / Output Monitor. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_iom_h +#define VBOX_INCLUDED_vmm_iom_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <VBox/dis.h> +#include <VBox/vmm/dbgf.h> + +RT_C_DECLS_BEGIN + + +/** @defgroup grp_iom The Input / Ouput Monitor API + * @ingroup grp_vmm + * @{ + */ + +/** @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! + * + * @remarks To avoid making assumptions about the layout of the + * VINF_EM_FIRST...VINF_EM_LAST range we're checking explicitly for + * each exact exception. However, for efficiency 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. + */ +#ifdef IN_RING3 +# 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_HM \ + ) \ + ) +#else +# 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_HM \ + ) \ + || (rc) == VINF_IOM_R3_IOPORT_COMMIT_WRITE \ + || (rc) == VINF_IOM_R3_MMIO_COMMIT_WRITE \ + ) +#endif + +/** @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) +/** All write accesses are DWORD (32-bit) sized and aligned, attempts at other + * accesses are ignored. + * @remarks E1000, APIC */ +#define IOMMMIO_FLAGS_WRITE_ONLY_DWORD UINT32_C(0x00000050) +/** All write accesses are DWORD (32-bit) or QWORD (64-bit) sized and aligned, + * attempts at other accesses are ignored. + * @remarks Seemingly required by AHCI (although I doubt it's _really_ + * required as EM/REM doesn't do the right thing in ring-3 anyway, + * esp. not in raw-mode). */ +#define IOMMMIO_FLAGS_WRITE_ONLY_DWORD_QWORD UINT32_C(0x00000060) +/** 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) + +/** Pass the absolute physical address (GC) to the callback rather than the + * relative one. + * @note New-style only, is implicit in old-style interface. */ +#define IOMMMIO_FLAGS_ABS UINT32_C(0x00001000) + +/** Mask of valid flags. */ +#define IOMMMIO_FLAGS_VALID_MASK UINT32_C(0x00001373) +/** @} */ + +/** + * Checks whether the write mode allows aligned QWORD accesses to be passed + * thru to the device handler. + * @param a_fFlags The MMIO handler flags. + */ +#define IOMMMIO_DOES_WRITE_MODE_ALLOW_QWORD(a_fFlags) \ + ( ((a_fFlags) & IOMMMIO_FLAGS_WRITE_MODE) == IOMMMIO_FLAGS_WRITE_DWORD_QWORD_ZEROED \ + || ((a_fFlags) & IOMMMIO_FLAGS_WRITE_MODE) == IOMMMIO_FLAGS_WRITE_DWORD_QWORD_READ_MISSING \ + || ((a_fFlags) & IOMMMIO_FLAGS_WRITE_MODE) == IOMMMIO_FLAGS_WRITE_ONLY_DWORD_QWORD ) + + +/** + * 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. + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(int, FNIOMIOPORTIN,(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, 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 pbDst Pointer to the destination buffer. + * @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). + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(int, FNIOMIOPORTINSTRING,(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint8_t *pbDst, + uint32_t *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. + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(int, FNIOMIOPORTOUT,(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, 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 pbSrc Pointer to the source buffer. + * @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). + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(int, FNIOMIOPORTOUTSTRING,(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, const uint8_t *pbSrc, + uint32_t *pcTransfers, unsigned cb)); +/** Pointer to a FNIOMIOPORTOUTSTRING(). */ +typedef FNIOMIOPORTOUTSTRING *PFNIOMIOPORTOUTSTRING; + + +/** + * 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 offPort The port number if IOM_IOPORT_F_ABS is used, otherwise + * relative to the mapping base. + * @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. + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNIOMIOPORTNEWIN,(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, + uint32_t *pu32, unsigned cb)); +/** Pointer to a FNIOMIOPORTNEWIN(). */ +typedef FNIOMIOPORTNEWIN *PFNIOMIOPORTNEWIN; + +/** + * 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 offPort The port number if IOM_IOPORT_F_ABS is used, otherwise + * relative to the mapping base. + * @param pbDst Pointer to the destination buffer. + * @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). + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNIOMIOPORTNEWINSTRING,(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint8_t *pbDst, + uint32_t *pcTransfers, unsigned cb)); +/** Pointer to a FNIOMIOPORTNEWINSTRING(). */ +typedef FNIOMIOPORTNEWINSTRING *PFNIOMIOPORTNEWINSTRING; + +/** + * Port I/O Handler for OUT operations. + * + * @returns VINF_SUCCESS or VINF_EM_*. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param offPort The port number if IOM_IOPORT_F_ABS is used, otherwise + * relative to the mapping base. + * @param u32 The value to output. + * @param cb The value size in bytes. + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNIOMIOPORTNEWOUT,(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, + uint32_t u32, unsigned cb)); +/** Pointer to a FNIOMIOPORTNEWOUT(). */ +typedef FNIOMIOPORTNEWOUT *PFNIOMIOPORTNEWOUT; + +/** + * Port I/O Handler for string OUT operations. + * + * @returns VINF_SUCCESS or VINF_EM_*. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param offPort The port number if IOM_IOPORT_F_ABS is used, otherwise + * relative to the mapping base. + * @param pbSrc Pointer to the source buffer. + * @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). + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNIOMIOPORTNEWOUTSTRING,(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, + const uint8_t *pbSrc, uint32_t *pcTransfers, unsigned cb)); +/** Pointer to a FNIOMIOPORTNEWOUTSTRING(). */ +typedef FNIOMIOPORTNEWOUTSTRING *PFNIOMIOPORTNEWOUTSTRING; + +/** + * I/O port description. + * + * If both pszIn and pszOut are NULL, the entry is considered a terminator. + */ +typedef struct IOMIOPORTDESC +{ + /** Brief description / name of the IN port. */ + const char *pszIn; + /** Brief description / name of the OUT port. */ + const char *pszOut; + /** Detailed description of the IN port, optional. */ + const char *pszInDetail; + /** Detialed description of the OUT port, optional. */ + const char *pszOutDetail; +} IOMIOPORTDESC; +/** Pointer to an I/O port description. */ +typedef IOMIOPORTDESC const *PCIOMIOPORTDESC; + + +/** + * 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. + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(int, FNIOMMMIOREAD,(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)); +/** Pointer to a FNIOMMMIOREAD(). */ +typedef FNIOMMMIOREAD *PFNIOMMMIOREAD; + +/** + * Memory mapped 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. + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(int, FNIOMMMIOWRITE,(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb)); +/** Pointer to a FNIOMMMIOWRITE(). */ +typedef FNIOMMMIOWRITE *PFNIOMMMIOWRITE; + +/** + * Memory mapped 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. + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(int, FNIOMMMIOFILL,(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, + uint32_t u32Item, unsigned cbItem, unsigned cItems)); +/** Pointer to a FNIOMMMIOFILL(). */ +typedef FNIOMMMIOFILL *PFNIOMMMIOFILL; + + +/** + * Memory mapped I/O Handler for read operations. + * + * @returns Strict VBox status code. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param off Offset into the mapping of the read, + * or the physical address if IOMMMIO_FLAGS_ABS is active. + * @param pv Where to store the result. + * @param cb Number of bytes read. + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNIOMMMIONEWREAD,(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, uint32_t cb)); +/** Pointer to a FNIOMMMIONEWREAD(). */ +typedef FNIOMMMIONEWREAD *PFNIOMMMIONEWREAD; + +/** + * Memory mapped I/O Handler for write operations. + * + * @returns Strict VBox status code. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param off Offset into the mapping of the write, + * or the physical address if IOMMMIO_FLAGS_ABS is active. + * @param pv Where to fetch the result. + * @param cb Number of bytes to write. + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNIOMMMIONEWWRITE,(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, + void const *pv, uint32_t cb)); +/** Pointer to a FNIOMMMIONEWWRITE(). */ +typedef FNIOMMMIONEWWRITE *PFNIOMMMIONEWWRITE; + +/** + * Memory mapped I/O Handler for memset operations, actually for REP STOS* instructions handling. + * + * @returns Strict VBox status code. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param off Offset into the mapping of the fill, + * or the physical address if IOMMMIO_FLAGS_ABS is active. + * @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. + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNIOMMMIONEWFILL,(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, + uint32_t u32Item, uint32_t cbItem, uint32_t cItems)); +/** Pointer to a FNIOMMMIONEWFILL(). */ +typedef FNIOMMMIONEWFILL *PFNIOMMMIONEWFILL; + +VMMDECL(VBOXSTRICTRC) IOMIOPortRead(PVMCC pVM, PVMCPU pVCpu, RTIOPORT Port, uint32_t *pu32Value, size_t cbValue); +VMMDECL(VBOXSTRICTRC) IOMIOPortWrite(PVMCC pVM, PVMCPU pVCpu, RTIOPORT Port, uint32_t u32Value, size_t cbValue); +VMM_INT_DECL(VBOXSTRICTRC) IOMIOPortReadString(PVMCC pVM, PVMCPU pVCpu, RTIOPORT Port, void *pvDst, + uint32_t *pcTransfers, unsigned cb); +VMM_INT_DECL(VBOXSTRICTRC) IOMIOPortWriteString(PVMCC pVM, PVMCPU pVCpu, RTIOPORT uPort, void const *pvSrc, + uint32_t *pcTransfers, unsigned cb); +VMM_INT_DECL(VBOXSTRICTRC) IOMR0MmioPhysHandler(PVMCC pVM, PVMCPUCC pVCpu, uint32_t uErrorCode, RTGCPHYS GCPhysFault); +VMMDECL(int) IOMMmioMapMmio2Page(PVMCC pVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS offRegion, + uint64_t hMmio2, RTGCPHYS offMmio2, uint64_t fPageFlags); +VMMR0_INT_DECL(int) IOMR0MmioMapMmioHCPage(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhys, RTHCPHYS HCPhys, uint64_t fPageFlags); +VMMDECL(int) IOMMmioResetRegion(PVMCC pVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion); + + +/** @name IOM_IOPORT_F_XXX - Flags for IOMR3IoPortCreate() and PDMDevHlpIoPortCreateEx(). + * @{ */ +/** Pass the absolute I/O port to the callback rather than the relative one. */ +#define IOM_IOPORT_F_ABS RT_BIT_32(0) +/** Valid flags for IOMR3IoPortCreate(). */ +#define IOM_IOPORT_F_VALID_MASK UINT32_C(0x00000001) +/** @} */ + +#ifdef IN_RING3 +/** @defgroup grp_iom_r3 The IOM Host Context Ring-3 API + * @{ + */ +VMMR3_INT_DECL(int) IOMR3Init(PVM pVM); +VMMR3_INT_DECL(int) IOMR3InitCompleted(PVM pVM, VMINITCOMPLETED enmWhat); +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) IOMR3IoPortCreate(PVM pVM, PPDMDEVINS pDevIns, RTIOPORT cPorts, uint32_t fFlags, PPDMPCIDEV pPciDev, + uint32_t iPciRegion, PFNIOMIOPORTNEWOUT pfnOut, PFNIOMIOPORTNEWIN pfnIn, + PFNIOMIOPORTNEWOUTSTRING pfnOutStr, PFNIOMIOPORTNEWINSTRING pfnInStr, RTR3PTR pvUser, + const char *pszDesc, PCIOMIOPORTDESC paExtDescs, PIOMIOPORTHANDLE phIoPorts); +VMMR3_INT_DECL(int) IOMR3IoPortMap(PVM pVM, PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts, RTIOPORT Port); +VMMR3_INT_DECL(int) IOMR3IoPortUnmap(PVM pVM, PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts); +VMMR3_INT_DECL(int) IOMR3IoPortValidateHandle(PVM pVM, PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts); +VMMR3_INT_DECL(uint32_t) IOMR3IoPortGetMappingAddress(PVM pVM, PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts); + +VMMR3_INT_DECL(int) IOMR3MmioCreate(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS cbRegion, uint32_t fFlags, PPDMPCIDEV pPciDev, + uint32_t iPciRegion, PFNIOMMMIONEWWRITE pfnWrite, PFNIOMMMIONEWREAD pfnRead, + PFNIOMMMIONEWFILL pfnFill, void *pvUser, const char *pszDesc, PIOMMMIOHANDLE phRegion); +VMMR3_INT_DECL(int) IOMR3MmioMap(PVM pVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS GCPhys); +VMMR3_INT_DECL(int) IOMR3MmioUnmap(PVM pVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion); +VMMR3_INT_DECL(int) IOMR3MmioReduce(PVM pVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS cbRegion); +VMMR3_INT_DECL(int) IOMR3MmioValidateHandle(PVM pVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion); +VMMR3_INT_DECL(RTGCPHYS) IOMR3MmioGetMappingAddress(PVM pVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion); + +VMMR3_INT_DECL(VBOXSTRICTRC) IOMR3ProcessForceFlag(PVM pVM, PVMCPU pVCpu, VBOXSTRICTRC rcStrict); + +VMMR3_INT_DECL(void) IOMR3NotifyBreakpointCountChange(PVM pVM, bool fPortIo, bool fMmio); +VMMR3_INT_DECL(void) IOMR3NotifyDebugEventChange(PVM pVM, DBGFEVENT enmEvent, bool fEnabled); +/** @} */ +#endif /* IN_RING3 */ + + +#if defined(IN_RING0) || defined(DOXYGEN_RUNNING) +/** @defgroup grpm_iom_r0 The IOM Host Context Ring-0 API + * @{ */ +VMMR0_INT_DECL(void) IOMR0InitPerVMData(PGVM pGVM); +VMMR0_INT_DECL(int) IOMR0InitVM(PGVM pGVM); +VMMR0_INT_DECL(void) IOMR0CleanupVM(PGVM pGVM); + +VMMR0_INT_DECL(int) IOMR0IoPortSetUpContext(PGVM pGVM, PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts, + PFNIOMIOPORTNEWOUT pfnOut, PFNIOMIOPORTNEWIN pfnIn, + PFNIOMIOPORTNEWOUTSTRING pfnOutStr, PFNIOMIOPORTNEWINSTRING pfnInStr, void *pvUser); +VMMR0_INT_DECL(int) IOMR0IoPortGrowRegistrationTables(PGVM pGVM, uint64_t cMinEntries); +VMMR0_INT_DECL(int) IOMR0IoPortGrowStatisticsTable(PGVM pGVM, uint64_t cMinEntries); +VMMR0_INT_DECL(int) IOMR0IoPortSyncStatisticsIndices(PGVM pGVM); + +VMMR0_INT_DECL(int) IOMR0MmioSetUpContext(PGVM pGVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, PFNIOMMMIONEWWRITE pfnWrite, + PFNIOMMMIONEWREAD pfnRead, PFNIOMMMIONEWFILL pfnFill, void *pvUser); +VMMR0_INT_DECL(int) IOMR0MmioGrowRegistrationTables(PGVM pGVM, uint64_t cMinEntries); +VMMR0_INT_DECL(int) IOMR0MmioGrowStatisticsTable(PGVM pGVM, uint64_t cMinEntries); +VMMR0_INT_DECL(int) IOMR0MmioSyncStatisticsIndices(PGVM pGVM); + +/** @} */ +#endif /* IN_RING0 || DOXYGEN_RUNNING */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_iom_h */ + diff --git a/include/VBox/vmm/mm.h b/include/VBox/vmm/mm.h new file mode 100644 index 00000000..540ba6d2 --- /dev/null +++ b/include/VBox/vmm/mm.h @@ -0,0 +1,244 @@ +/** @file + * MM - The Memory Manager. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_mm_h +#define VBOX_INCLUDED_vmm_mm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#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 + * @ingroup grp_vmm + * @{ + */ + +/** + * 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_CPUM_CPUID, + MM_TAG_CPUM_MSRS, + + 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_DBGF_TYPE, + MM_TAG_DBGF_TRACER, + MM_TAG_DBGF_FLOWTRACE, + + MM_TAG_EM, + + MM_TAG_IEM, + + 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_HANDLER_TYPES, + 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_HM, + + MM_TAG_32BIT_HACK = 0x7fffffff +} MMTAG; + + + + +/** @defgroup grp_mm_hyper Hypervisor Memory Management + * @{ */ + +VMMDECL(RTR0PTR) MMHyperR3ToR0(PVM pVM, RTR3PTR R3Ptr); + +#ifndef IN_RING3 +VMMDECL(void *) MMHyperR3ToCC(PVM pVM, RTR3PTR R3Ptr); +#else +DECLINLINE(void *) MMHyperR3ToCC(PVM pVM, RTR3PTR R3Ptr) +{ + NOREF(pVM); + return R3Ptr; +} +#endif + + +/** @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. + */ +#define MMHYPER_RC_ASSERT_RCPTR(pVM, RCPtr) do { } while (0) + +/** @} */ + + +#if defined(IN_RING3) || defined(DOXYGEN_RUNNING) +/** @defgroup grp_mm_r3 The MM Host Context Ring-3 API + * @{ + */ + +VMMR3DECL(int) MMR3InitUVM(PUVM pUVM); +VMMR3DECL(int) MMR3Init(PVM pVM); +VMMR3DECL(int) MMR3InitPaging(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); +/** @} */ + + +/** @defgroup grp_mm_phys Guest Physical Memory Manager + * @todo retire this group, elimintating or moving MMR3PhysGetRamSize to PGMPhys. + * @{ */ +VMMR3DECL(uint64_t) MMR3PhysGetRamSize(PVM pVM); +VMMR3DECL(uint32_t) MMR3PhysGetRamSizeBelow4GB(PVM pVM); +VMMR3DECL(uint64_t) MMR3PhysGetRamSizeAbove4GB(PVM pVM); +VMMR3DECL(uint32_t) MMR3PhysGet4GBRamHoleSize(PVM pVM); +/** @} */ + + +/** @defgroup grp_mm_heap Heap Manager + * @{ */ +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, ...) RT_IPRT_FORMAT_ATTR(3, 4); +VMMR3DECL(char *) MMR3HeapAPrintfU(PUVM pUVM, MMTAG enmTag, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); +VMMR3DECL(char *) MMR3HeapAPrintfV(PVM pVM, MMTAG enmTag, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(3, 0); +VMMR3DECL(char *) MMR3HeapAPrintfVU(PUVM pUVM, MMTAG enmTag, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(3, 0); +VMMR3DECL(void) MMR3HeapFree(void *pv); +/** @} */ + +#endif /* IN_RING3 || DOXYGEN_RUNNING */ + + +/** @} */ +RT_C_DECLS_END + + +#endif /* !VBOX_INCLUDED_vmm_mm_h */ + diff --git a/include/VBox/vmm/nem.h b/include/VBox/vmm/nem.h new file mode 100644 index 00000000..3004efa5 --- /dev/null +++ b/include/VBox/vmm/nem.h @@ -0,0 +1,256 @@ +/** @file + * NEM - The Native Execution Manager. + */ + +/* + * Copyright (C) 2018-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_nem_h +#define VBOX_INCLUDED_vmm_nem_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <VBox/vmm/vmapi.h> +#include <VBox/vmm/pgm.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_nem The Native Execution Manager API + * @ingroup grp_vmm + * @{ + */ + +/** @defgroup grp_nem_r3 The NEM ring-3 Context API + * @{ + */ +VMMR3_INT_DECL(int) NEMR3InitConfig(PVM pVM); +VMMR3_INT_DECL(int) NEMR3Init(PVM pVM, bool fFallback, bool fForced); +VMMR3_INT_DECL(int) NEMR3InitAfterCPUM(PVM pVM); +#ifdef IN_RING3 +VMMR3_INT_DECL(int) NEMR3InitCompleted(PVM pVM, VMINITCOMPLETED enmWhat); +#endif +VMMR3_INT_DECL(int) NEMR3Term(PVM pVM); +VMMR3DECL(bool) NEMR3IsEnabled(PUVM pVM); +VMMR3_INT_DECL(bool) NEMR3NeedSpecialTscMode(PVM pVM); +VMMR3_INT_DECL(void) NEMR3Reset(PVM pVM); +VMMR3_INT_DECL(void) NEMR3ResetCpu(PVMCPU pVCpu, bool fInitIpi); +VMMR3DECL(const char *) NEMR3GetExitName(uint32_t uExit); +VMMR3_INT_DECL(VBOXSTRICTRC) NEMR3RunGC(PVM pVM, PVMCPU pVCpu); +VMMR3_INT_DECL(bool) NEMR3CanExecuteGuest(PVM pVM, PVMCPU pVCpu); +VMMR3_INT_DECL(bool) NEMR3SetSingleInstruction(PVM pVM, PVMCPU pVCpu, bool fEnable); +VMMR3_INT_DECL(void) NEMR3NotifyFF(PVM pVM, PVMCPU pVCpu, uint32_t fFlags); + +/** + * Checks if dirty page tracking for MMIO2 ranges is supported. + * + * If it is, PGM will not install a physical write access handler for the MMIO2 + * region and instead just forward dirty bit queries NEMR3QueryMmio2DirtyBits. + * The enable/disable control of the tracking will be ignored, and PGM will + * always set NEM_NOTIFY_PHYS_MMIO_EX_F_TRACK_DIRTY_PAGES for such ranges. + * + * @retval true if supported. + * @retval false if not. + * @param pVM The cross context VM structure. + */ +VMMR3_INT_DECL(bool) NEMR3IsMmio2DirtyPageTrackingSupported(PVM pVM); + +/** + * Worker for PGMR3PhysMmio2QueryAndResetDirtyBitmap. + * + * @returns VBox status code. + * @param pVM The cross context VM structure. + * @param GCPhys The address of the MMIO2 range. + * @param cb The size of the MMIO2 range. + * @param uNemRange The NEM internal range number. + * @param pvBitmap The output bitmap. Must be 8-byte aligned. Ignored + * when @a cbBitmap is zero. + * @param cbBitmap The size of the bitmap. Must be the size of the whole + * MMIO2 range, rounded up to the nearest 8 bytes. + * When zero only a reset is done. + */ +VMMR3_INT_DECL(int) NEMR3PhysMmio2QueryAndResetDirtyBitmap(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t uNemRange, + void *pvBitmap, size_t cbBitmap); + +VMMR3_INT_DECL(int) NEMR3NotifyPhysRamRegister(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, void *pvR3, + uint8_t *pu2State, uint32_t *puNemRange); +VMMR3_INT_DECL(int) NEMR3NotifyPhysMmioExMapEarly(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t fFlags, + void *pvRam, void *pvMmio2, uint8_t *pu2State, uint32_t *puNemRange); +VMMR3_INT_DECL(int) NEMR3NotifyPhysMmioExMapLate(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t fFlags, + void *pvRam, void *pvMmio2, uint32_t *puNemRange); +VMMR3_INT_DECL(int) NEMR3NotifyPhysMmioExUnmap(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t fFlags, + void *pvRam, void *pvMmio2, uint8_t *pu2State, uint32_t *puNemRange); +/** @name Flags for NEMR3NotifyPhysMmioExMap and NEMR3NotifyPhysMmioExUnmap. + * @{ */ +/** Set if the range is replacing RAM rather that unused space. */ +#define NEM_NOTIFY_PHYS_MMIO_EX_F_REPLACE RT_BIT(0) +/** Set if it's MMIO2 being mapped or unmapped. */ +#define NEM_NOTIFY_PHYS_MMIO_EX_F_MMIO2 RT_BIT(1) +/** Set if MMIO2 and dirty page tracking is configured. */ +#define NEM_NOTIFY_PHYS_MMIO_EX_F_TRACK_DIRTY_PAGES RT_BIT(2) +/** @} */ + +/** + * Called very early during ROM registration, basically so an existing RAM range + * can be adjusted if desired. + * + * It will be succeeded by a number of NEMHCNotifyPhysPageProtChanged() + * calls and finally a call to NEMR3NotifyPhysRomRegisterLate(). + * + * @returns VBox status code + * @param pVM The cross context VM structure. + * @param GCPhys The ROM address (page aligned). + * @param cb The size (page aligned). + * @param pvPages Pointer to the ROM (RAM) pages in simplified mode + * when NEM_NOTIFY_PHYS_ROM_F_REPLACE is set, otherwise + * NULL. + * @param fFlags NEM_NOTIFY_PHYS_ROM_F_XXX. + * @param pu2State New page state or UINT8_MAX to leave as-is. + * @param puNemRange Access to the relevant PGMRAMRANGE::uNemRange field. + */ +VMMR3_INT_DECL(int) NEMR3NotifyPhysRomRegisterEarly(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, void *pvPages, + uint32_t fFlags, uint8_t *pu2State, uint32_t *puNemRange); + +/** + * Called after the ROM range has been fully completed. + * + * This will be preceeded by a NEMR3NotifyPhysRomRegisterEarly() call as well a + * number of NEMHCNotifyPhysPageProtChanged calls. + * + * @returns VBox status code + * @param pVM The cross context VM structure. + * @param GCPhys The ROM address (page aligned). + * @param cb The size (page aligned). + * @param pvPages Pointer to the ROM pages. + * @param fFlags NEM_NOTIFY_PHYS_ROM_F_XXX. + * @param pu2State Where to return the new NEM page state, UINT8_MAX + * for unchanged. + * @param puNemRange Access to the relevant PGMRAMRANGE::uNemRange field. + */ +VMMR3_INT_DECL(int) NEMR3NotifyPhysRomRegisterLate(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, void *pvPages, + uint32_t fFlags, uint8_t *pu2State, uint32_t *puNemRange); + +/** @name Flags for NEMR3NotifyPhysRomRegisterEarly and NEMR3NotifyPhysRomRegisterLate. + * @{ */ +/** Set if the range is replacing RAM rather that unused space. */ +#define NEM_NOTIFY_PHYS_ROM_F_REPLACE RT_BIT(1) +/** Set if it's MMIO2 being mapped or unmapped. */ +#define NEM_NOTIFY_PHYS_ROM_F_SHADOW RT_BIT(2) +/** @} */ + +/** + * Called when the A20 state changes. + * + * Windows: Hyper-V doesn't seem to offer a simple way of implementing the A20 + * line features of PCs. So, we do a very minimal emulation of the HMA to make + * DOS happy. + * + * @param pVCpu The CPU the A20 state changed on. + * @param fEnabled Whether it was enabled (true) or disabled. + */ +VMMR3_INT_DECL(void) NEMR3NotifySetA20(PVMCPU pVCpu, bool fEnabled); +VMMR3_INT_DECL(void) NEMR3NotifyDebugEventChanged(PVM pVM); +VMMR3_INT_DECL(void) NEMR3NotifyDebugEventChangedPerCpu(PVM pVM, PVMCPU pVCpu); +/** @} */ + + +/** @defgroup grp_nem_r0 The NEM ring-0 Context API + * @{ */ +VMMR0_INT_DECL(int) NEMR0Init(void); +VMMR0_INT_DECL(void) NEMR0Term(void); +VMMR0_INT_DECL(int) NEMR0InitVM(PGVM pGVM); +VMMR0_INT_DECL(int) NEMR0InitVMPart2(PGVM pGVM); +VMMR0_INT_DECL(void) NEMR0CleanupVM(PGVM pGVM); +VMMR0_INT_DECL(int) NEMR0MapPages(PGVM pGVM, VMCPUID idCpu); +VMMR0_INT_DECL(int) NEMR0UnmapPages(PGVM pGVM, VMCPUID idCpu); +VMMR0_INT_DECL(int) NEMR0ExportState(PGVM pGVM, VMCPUID idCpu); +VMMR0_INT_DECL(int) NEMR0ImportState(PGVM pGVM, VMCPUID idCpu, uint64_t fWhat); +VMMR0_INT_DECL(int) NEMR0QueryCpuTick(PGVM pGVM, VMCPUID idCpu); +VMMR0_INT_DECL(int) NEMR0ResumeCpuTickOnAll(PGVM pGVM, VMCPUID idCpu, uint64_t uPausedTscValue); +VMMR0_INT_DECL(VBOXSTRICTRC) NEMR0RunGuestCode(PGVM pGVM, VMCPUID idCpu); +VMMR0_INT_DECL(int) NEMR0UpdateStatistics(PGVM pGVM, VMCPUID idCpu); +VMMR0_INT_DECL(int) NEMR0DoExperiment(PGVM pGVM, VMCPUID idCpu, uint64_t u64Arg); +#ifdef RT_OS_WINDOWS +VMMR0_INT_DECL(int) NEMR0WinGetPartitionId(PGVM pGVM, uintptr_t uHandle); +#endif +/** @} */ + + +/** @defgroup grp_nem_hc The NEM Host Context API + * @{ + */ +VMM_INT_DECL(bool) NEMHCIsLongModeAllowed(PVMCC pVM); +VMM_INT_DECL(uint32_t) NEMHCGetFeatures(PVMCC pVM); +VMM_INT_DECL(int) NEMImportStateOnDemand(PVMCPUCC pVCpu, uint64_t fWhat); + +/** @name NEM_FEAT_F_XXX - Features supported by the NEM backend + * @{ */ +/** NEM backend uses nested paging for the guest. */ +#define NEM_FEAT_F_NESTED_PAGING RT_BIT(0) +/** NEM backend uses full (unrestricted) guest execution. */ +#define NEM_FEAT_F_FULL_GST_EXEC RT_BIT(1) +/** NEM backend offers an xsave/xrstor interface. */ +#define NEM_FEAT_F_XSAVE_XRSTOR RT_BIT(2) +/** @} */ + +VMM_INT_DECL(void) NEMHCNotifyHandlerPhysicalRegister(PVMCC pVM, PGMPHYSHANDLERKIND enmKind, RTGCPHYS GCPhys, RTGCPHYS cb); +VMM_INT_DECL(void) NEMHCNotifyHandlerPhysicalDeregister(PVMCC pVM, PGMPHYSHANDLERKIND enmKind, RTGCPHYS GCPhys, RTGCPHYS cb, + RTR3PTR pvMemR3, uint8_t *pu2State); +VMM_INT_DECL(void) NEMHCNotifyHandlerPhysicalModify(PVMCC pVM, PGMPHYSHANDLERKIND enmKind, RTGCPHYS GCPhysOld, + RTGCPHYS GCPhysNew, RTGCPHYS cb, bool fRestoreAsRAM); + +VMM_INT_DECL(int) NEMHCNotifyPhysPageAllocated(PVMCC pVM, RTGCPHYS GCPhys, RTHCPHYS HCPhys, uint32_t fPageProt, + PGMPAGETYPE enmType, uint8_t *pu2State); +VMM_INT_DECL(void) NEMHCNotifyPhysPageProtChanged(PVMCC pVM, RTGCPHYS GCPhys, RTHCPHYS HCPhys, RTR3PTR pvR3, uint32_t fPageProt, + PGMPAGETYPE enmType, uint8_t *pu2State); +VMM_INT_DECL(void) NEMHCNotifyPhysPageChanged(PVMCC pVM, RTGCPHYS GCPhys, RTHCPHYS HCPhysPrev, RTHCPHYS HCPhysNew, + RTR3PTR pvNewR3, uint32_t fPageProt, PGMPAGETYPE enmType, uint8_t *pu2State); +/** @name NEM_PAGE_PROT_XXX - Page protection + * @{ */ +#define NEM_PAGE_PROT_NONE UINT32_C(0) /**< All access causes VM exits. */ +#define NEM_PAGE_PROT_READ RT_BIT(0) /**< Read access. */ +#define NEM_PAGE_PROT_EXECUTE RT_BIT(1) /**< Execute access. */ +#define NEM_PAGE_PROT_WRITE RT_BIT(2) /**< write access. */ +/** @} */ + +VMM_INT_DECL(int) NEMHCQueryCpuTick(PVMCPUCC pVCpu, uint64_t *pcTicks, uint32_t *puAux); +VMM_INT_DECL(int) NEMHCResumeCpuTickOnAll(PVMCC pVM, PVMCPUCC pVCpu, uint64_t uPausedTscValue); + +/** @} */ + +/** @} */ +RT_C_DECLS_END + + +#endif /* !VBOX_INCLUDED_vmm_nem_h */ + diff --git a/include/VBox/vmm/pdm.h b/include/VBox/vmm/pdm.h new file mode 100644 index 00000000..be46e570 --- /dev/null +++ b/include/VBox/vmm/pdm.h @@ -0,0 +1,54 @@ +/** @file + * PDM - Pluggable Device Manager. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdm_h +#define VBOX_INCLUDED_vmm_pdm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/vmm/pdmapi.h> +#include <VBox/vmm/pdmqueue.h> +#include <VBox/vmm/pdmcritsect.h> +#include <VBox/vmm/pdmcritsectrw.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 /* !VBOX_INCLUDED_vmm_pdm_h */ + diff --git a/include/VBox/vmm/pdmapi.h b/include/VBox/vmm/pdmapi.h new file mode 100644 index 00000000..bf25f043 --- /dev/null +++ b/include/VBox/vmm/pdmapi.h @@ -0,0 +1,393 @@ +/** @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-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmapi_h +#define VBOX_INCLUDED_vmm_pdmapi_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/vmm/pdmcommon.h> +#ifdef IN_RING3 +# include <VBox/vmm/vmapi.h> +#endif +#include <VBox/sup.h> + +struct PDMDEVMODREGR0; + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm The Pluggable Device Manager API + * @ingroup grp_vmm + * @{ + */ + +VMMDECL(int) PDMGetInterrupt(PVMCPUCC pVCpu, uint8_t *pu8Interrupt); +VMMDECL(int) PDMIsaSetIrq(PVMCC pVM, uint8_t u8Irq, uint8_t u8Level, uint32_t uTagSrc); +VMM_INT_DECL(bool) PDMHasIoApic(PVM pVM); +VMM_INT_DECL(bool) PDMHasApic(PVM pVM); +VMM_INT_DECL(PPDMDEVINS) PDMDeviceRing0IdxToInstance(PVMCC pVM, uint64_t idxR0Device); +VMM_INT_DECL(int) PDMIoApicSetIrq(PVM pVM, PCIBDF uBusDevFn, uint8_t u8Irq, uint8_t u8Level, uint32_t uTagSrc); +VMM_INT_DECL(void) PDMIoApicBroadcastEoi(PVMCC pVM, uint8_t uVector); +VMM_INT_DECL(void) PDMIoApicSendMsi(PVMCC pVM, PCIBDF uBusDevFn, PCMSIMSG pMsi, uint32_t uTagSrc); +VMM_INT_DECL(int) PDMVmmDevHeapR3ToGCPhys(PVM pVM, RTR3PTR pv, RTGCPHYS *pGCPhys); +VMM_INT_DECL(bool) PDMVmmDevHeapIsEnabled(PVM pVM); + +/** + * Mapping/unmapping callback for an VMMDev heap allocation. + * + * @param pVM The cross context VM structure. + * @param pvAllocation The allocation address (ring-3). + * @param GCPhysAllocation The guest physical address of the mapping if + * it's being mapped, NIL_RTGCPHYS if it's being + * unmapped. + */ +typedef DECLCALLBACKTYPE(void, FNPDMVMMDEVHEAPNOTIFY,(PVM pVM, void *pvAllocation, RTGCPHYS GCPhysAllocation)); +/** Pointer (ring-3) to a FNPDMVMMDEVHEAPNOTIFY function. */ +typedef R3PTRTYPE(FNPDMVMMDEVHEAPNOTIFY *) PFNPDMVMMDEVHEAPNOTIFY; + + +#if defined(IN_RING3) || defined(DOXYGEN_RUNNING) +/** @defgroup grp_pdm_r3 The PDM Host Context Ring-3 API + * @{ + */ +VMMR3_INT_DECL(int) PDMR3InitUVM(PUVM pUVM); +VMMR3_INT_DECL(int) PDMR3LdrLoadVMMR0U(PUVM pUVM); +VMMR3_INT_DECL(int) PDMR3Init(PVM pVM); +VMMR3_INT_DECL(int) PDMR3InitCompleted(PVM pVM, VMINITCOMPLETED enmWhat); +VMMR3DECL(void) PDMR3PowerOn(PVM pVM); +VMMR3_INT_DECL(bool) PDMR3GetResetInfo(PVM pVM, uint32_t fOverride, uint32_t *pfResetFlags); +VMMR3_INT_DECL(void) PDMR3ResetCpu(PVMCPU pVCpu); +VMMR3_INT_DECL(void) PDMR3Reset(PVM pVM); +VMMR3_INT_DECL(void) PDMR3MemSetup(PVM pVM, bool fAtReset); +VMMR3_INT_DECL(void) PDMR3SoftReset(PVM pVM, uint32_t fResetFlags); +VMMR3_INT_DECL(void) PDMR3Suspend(PVM pVM); +VMMR3_INT_DECL(void) PDMR3Resume(PVM pVM); +VMMR3DECL(void) PDMR3PowerOff(PVM pVM); +VMMR3_INT_DECL(void) PDMR3Relocate(PVM pVM, RTGCINTPTR offDelta); +VMMR3_INT_DECL(int) PDMR3Term(PVM pVM); +VMMR3_INT_DECL(void) PDMR3TermUVM(PUVM pUVM); +VMMR3_INT_DECL(bool) PDMR3HasLoadedState(PVM pVM); + +/** PDM loader context indicator. */ +typedef enum PDMLDRCTX +{ + /** Invalid zero value. */ + PDMLDRCTX_INVALID = 0, + /** Ring-0 context. */ + PDMLDRCTX_RING_0, + /** Ring-3 context. */ + PDMLDRCTX_RING_3, + /** Raw-mode context. */ + PDMLDRCTX_RAW_MODE, + /** End of valid context values. */ + PDMLDRCTX_END, + /** 32-bit type hack. */ + PDMLDRCTX_32BIT_HACK = 0x7fffffff +} PDMLDRCTX; + +/** + * 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 The cross context VM structure. + * @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 enmCtx The context the module is loaded into. + * @param pvArg User argument. + */ +typedef DECLCALLBACKTYPE(int, FNPDMR3ENUM,(PVM pVM, const char *pszFilename, const char *pszName, + RTUINTPTR ImageBase, size_t cbImage, PDMLDRCTX enmCtx, void *pvArg)); +/** Pointer to a FNPDMR3ENUM() function. */ +typedef FNPDMR3ENUM *PFNPDMR3ENUM; +VMMR3DECL(int) PDMR3LdrEnumModules(PVM pVM, PFNPDMR3ENUM pfnCallback, void *pvArg); +VMMR3_INT_DECL(void) PDMR3LdrRelocateU(PUVM pUVM, RTGCINTPTR offDelta); +VMMR3_INT_DECL(int) PDMR3LdrLoadR0(PUVM pUVM, const char *pszModule, const char *pszSearchPath); +VMMR3_INT_DECL(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); +VMMR3_INT_DECL(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); +VMMR3_INT_DECL(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); +VMMR3_INT_DECL(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(PUVM pUVM, const char *pszDevice, unsigned iInstance, PPPDMIBASE ppBase); +VMMR3DECL(int) PDMR3QueryDeviceLun(PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPPDMIBASE ppBase); +VMMR3DECL(int) PDMR3QueryLun(PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPPDMIBASE ppBase); +VMMR3DECL(int) PDMR3QueryDriverOnLun(PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, + const char *pszDriver, PPPDMIBASE ppBase); +VMMR3DECL(int) PDMR3DeviceAttach(PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, uint32_t fFlags, + PPDMIBASE *ppBase); +VMMR3DECL(int) PDMR3DeviceDetach(PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, uint32_t fFlags); +VMMR3_INT_DECL(PPDMCRITSECT) PDMR3DevGetCritSect(PVM pVM, PPDMDEVINS pDevIns); +VMMR3DECL(int) PDMR3DriverAttach(PUVM pUVM, const char *pszDevice, unsigned iDevIns, unsigned iLun, uint32_t fFlags, + PPPDMIBASE ppBase); +VMMR3DECL(int) PDMR3DriverDetach(PUVM pUVM, const char *pszDevice, unsigned iDevIns, unsigned iLun, + const char *pszDriver, unsigned iOccurrence, uint32_t fFlags); +VMMR3DECL(int) PDMR3DriverReattach(PUVM pVM, const char *pszDevice, unsigned iDevIns, unsigned iLun, + const char *pszDriver, unsigned iOccurrence, uint32_t fFlags, PCFGMNODE pCfg, + PPPDMIBASE ppBase); +VMMR3DECL(void) PDMR3DmaRun(PVM pVM); + +VMMR3_INT_DECL(int) PDMR3VmmDevHeapAlloc(PVM pVM, size_t cbSize, PFNPDMVMMDEVHEAPNOTIFY pfnNotify, RTR3PTR *ppv); +VMMR3_INT_DECL(int) PDMR3VmmDevHeapFree(PVM pVM, RTR3PTR pv); +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); +/** @} */ +#endif /* IN_RING3 */ + + + +/** @defgroup grp_pdm_rc The PDM Raw-Mode Context API + * @{ + */ +/** @} */ + + + +/** @defgroup grp_pdm_r0 The PDM Ring-0 Context API + * @{ + */ +VMMR0_INT_DECL(void) PDMR0Init(void *hMod); +VMMR0DECL(int) PDMR0DeviceRegisterModule(void *hMod, struct PDMDEVMODREGR0 *pModReg); +VMMR0DECL(int) PDMR0DeviceDeregisterModule(void *hMod, struct PDMDEVMODREGR0 *pModReg); + +VMMR0_INT_DECL(void) PDMR0InitPerVMData(PGVM pGVM); +VMMR0_INT_DECL(void) PDMR0CleanupVM(PGVM pGVM); + +/** + * 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(PGVM pGVM, PPDMDRIVERCALLREQHANDLERREQ pReq); + + +/** + * Request buffer for PDMR0DeviceCreateReqHandler / VMMR0_DO_PDM_DEVICE_CREATE. + * @see PDMR0DeviceCreateReqHandler. + */ +typedef struct PDMDEVICECREATEREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** Out: Where to return the address of the ring-3 device instance. */ + PPDMDEVINSR3 pDevInsR3; + + /** Copy of PDMDEVREGR3::fFlags for matching with PDMDEVREGR0::fFlags. */ + uint32_t fFlags; + /** Copy of PDMDEVREGR3::fClass for matching with PDMDEVREGR0::fFlags. */ + uint32_t fClass; + /** Copy of PDMDEVREGR3::cMaxInstances for matching with + * PDMDEVREGR0::cMaxInstances. */ + uint32_t cMaxInstances; + /** Copy of PDMDEVREGR3::uSharedVersion for matching with + * PDMDEVREGR0::uSharedVersion. */ + uint32_t uSharedVersion; + /** Copy of PDMDEVREGR3::cbInstanceShared for matching with + * PDMDEVREGR0::cbInstanceShared. */ + uint32_t cbInstanceShared; + /** Copy of PDMDEVREGR3::cbInstanceCC. */ + uint32_t cbInstanceR3; + /** Copy of PDMDEVREGR3::cbInstanceRC for matching with + * PDMDEVREGR0::cbInstanceRC. */ + uint32_t cbInstanceRC; + /** Copy of PDMDEVREGR3::cMaxPciDevices for matching with + * PDMDEVREGR0::cMaxPciDevices. */ + uint16_t cMaxPciDevices; + /** Copy of PDMDEVREGR3::cMaxMsixVectors for matching with + * PDMDEVREGR0::cMaxMsixVectors. */ + uint16_t cMaxMsixVectors; + + /** The device instance ordinal. */ + uint32_t iInstance; + /** Set if the raw-mode component is desired. */ + bool fRCEnabled; + /** Explicit padding. */ + bool afReserved[3]; + /** DBGF tracer event source handle if configured. */ + DBGFTRACEREVTSRC hDbgfTracerEvtSrc; + + /** In: Device name. */ + char szDevName[32]; + /** In: The module name (no path). */ + char szModName[32]; +} PDMDEVICECREATEREQ; +/** Pointer to a PDMR0DeviceCreate / VMMR0_DO_PDM_DEVICE_CREATE request buffer. */ +typedef PDMDEVICECREATEREQ *PPDMDEVICECREATEREQ; + +VMMR0_INT_DECL(int) PDMR0DeviceCreateReqHandler(PGVM pGVM, PPDMDEVICECREATEREQ pReq); + +/** + * The ring-0 device call to make. + */ +typedef enum PDMDEVICEGENCALL +{ + PDMDEVICEGENCALL_INVALID = 0, + PDMDEVICEGENCALL_CONSTRUCT, + PDMDEVICEGENCALL_DESTRUCT, + PDMDEVICEGENCALL_REQUEST, + PDMDEVICEGENCALL_END, + PDMDEVICEGENCALL_32BIT_HACK = 0x7fffffff +} PDMDEVICEGENCALL; + +/** + * Request buffer for PDMR0DeviceGenCallReqHandler / VMMR0_DO_PDM_DEVICE_GEN_CALL. + * @see PDMR0DeviceGenCallReqHandler. + */ +typedef struct PDMDEVICEGENCALLREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The ring-3 device instance. */ + PPDMDEVINSR3 pDevInsR3; + /** The ring-0 device handle. */ + uint32_t idxR0Device; + /** The call to make. */ + PDMDEVICEGENCALL enmCall; + union + { + /** PDMDEVICEGENCALL_REQUEST: */ + struct + { + /** The request argument. */ + uint64_t uArg; + /** The request number. */ + uint32_t uReq; + } Req; + /** Size padding. */ + uint64_t au64[3]; + } Params; +} PDMDEVICEGENCALLREQ; +/** Pointer to a PDMR0DeviceGenCallReqHandler / VMMR0_DO_PDM_DEVICE_GEN_CALL request buffer. */ +typedef PDMDEVICEGENCALLREQ *PPDMDEVICEGENCALLREQ; + +VMMR0_INT_DECL(int) PDMR0DeviceGenCallReqHandler(PGVM pGVM, PPDMDEVICEGENCALLREQ pReq, VMCPUID idCpu); + +/** + * Request buffer for PDMR0DeviceCompatSetCritSectReqHandler / VMMR0_DO_PDM_DEVICE_COMPAT_SET_CRITSECT + * @see PDMR0DeviceCompatSetCritSectReqHandler. + */ +typedef struct PDMDEVICECOMPATSETCRITSECTREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The ring-3 device instance. */ + PPDMDEVINSR3 pDevInsR3; + /** The ring-0 device handle. */ + uint32_t idxR0Device; + /** The critical section address (ring-3). */ + R3PTRTYPE(PPDMCRITSECT) pCritSectR3; +} PDMDEVICECOMPATSETCRITSECTREQ; +/** Pointer to a PDMR0DeviceGenCallReqHandler / VMMR0_DO_PDM_DEVICE_GEN_CALL request buffer. */ +typedef PDMDEVICECOMPATSETCRITSECTREQ *PPDMDEVICECOMPATSETCRITSECTREQ; + +VMMR0_INT_DECL(int) PDMR0DeviceCompatSetCritSectReqHandler(PGVM pGVM, PPDMDEVICECOMPATSETCRITSECTREQ pReq); + + +/** + * Request buffer for PDMR0QueueCreateReqHandler / VMMR0_DO_PDM_QUEUE_CREATE. + * @see PDMR0QueueCreateReqHandler. + */ +typedef struct PDMQUEUECREATEREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + + /** Number of queue items. */ + uint32_t cItems; + /** Queue item size. */ + uint32_t cbItem; + /** Owner type (PDMQUEUETYPE). */ + uint32_t enmType; + /** The ring-3 owner pointer. */ + RTR3PTR pvOwner; + /** The ring-3 callback function address. */ + RTR3PTR pfnCallback; + /** The queue name. */ + char szName[40]; + + /** Output: The queue handle. */ + PDMQUEUEHANDLE hQueue; +} PDMQUEUECREATEREQ; +/** Pointer to a PDMR0QueueCreateReqHandler / VMMR0_DO_PDM_QUEUE_CREATE request buffer. */ +typedef PDMQUEUECREATEREQ *PPDMQUEUECREATEREQ; + +VMMR0_INT_DECL(int) PDMR0QueueCreateReqHandler(PGVM pGVM, PPDMQUEUECREATEREQ pReq); + +/** @} */ + +RT_C_DECLS_END + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_pdmapi_h */ diff --git a/include/VBox/vmm/pdmasynccompletion.h b/include/VBox/vmm/pdmasynccompletion.h new file mode 100644 index 00000000..f46d7910 --- /dev/null +++ b/include/VBox/vmm/pdmasynccompletion.h @@ -0,0 +1,160 @@ +/** @file + * PDM - Pluggable Device Manager, Async I/O Completion. + */ + +/* + * Copyright (C) 2007-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmasynccompletion_h +#define VBOX_INCLUDED_vmm_pdmasynccompletion_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.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 DECLCALLBACKTYPE(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 DECLCALLBACKTYPE(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 DECLCALLBACKTYPE(void, FNPDMASYNCCOMPLETEUSB,(PPDMUSBINS pUsbIns, void *pvUser, int rc)); +/** Pointer to a FNPDMASYNCCOMPLETEUSB(). */ +typedef FNPDMASYNCCOMPLETEUSB *PFNPDMASYNCCOMPLETEUSB; + + +/** + * Completion callback for internal. + * + * @param pVM The cross context 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 DECLCALLBACKTYPE(void, FNPDMASYNCCOMPLETEINT,(PVM pVM, void *pvUser, void *pvUser2, int rc)); +/** Pointer to a FNPDMASYNCCOMPLETEINT(). */ +typedef FNPDMASYNCCOMPLETEINT *PFNPDMASYNCCOMPLETEINT; + +VMMR3DECL(int) PDMR3AsyncCompletionTemplateCreateInternal(PVM pVM, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate, + PFNPDMASYNCCOMPLETEINT pfnCompleted, void *pvUser2, const char *pszDesc); +VMMR3DECL(int) PDMR3AsyncCompletionTemplateDestroy(PPDMASYNCCOMPLETIONTEMPLATE pTemplate); +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) +/** @} */ + +VMMR3DECL(void) PDMR3AsyncCompletionEpClose(PPDMASYNCCOMPLETIONENDPOINT pEndpoint); +VMMR3DECL(int) PDMR3AsyncCompletionEpRead(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, RTFOFF off, + PCRTSGSEG paSegments, unsigned cSegments, + size_t cbRead, void *pvUser, + PPPDMASYNCCOMPLETIONTASK ppTask); +VMMR3DECL(int) PDMR3AsyncCompletionEpWrite(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, RTFOFF off, + PCRTSGSEG paSegments, unsigned cSegments, + size_t cbWrite, void *pvUser, + PPPDMASYNCCOMPLETIONTASK ppTask); +VMMR3DECL(int) PDMR3AsyncCompletionEpFlush(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, void *pvUser, PPPDMASYNCCOMPLETIONTASK ppTask); +VMMR3DECL(int) PDMR3AsyncCompletionEpGetSize(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, uint64_t *pcbSize); +VMMR3DECL(int) PDMR3AsyncCompletionEpSetSize(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, uint64_t cbSize); +VMMR3DECL(int) PDMR3AsyncCompletionEpSetBwMgr(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, const char *pszBwMgr); +VMMR3DECL(int) PDMR3AsyncCompletionTaskCancel(PPDMASYNCCOMPLETIONTASK pTask); +VMMR3DECL(int) PDMR3AsyncCompletionBwMgrSetMaxForFile(PUVM pUVM, const char *pszBwMgr, uint32_t cbMaxNew); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmasynccompletion_h */ + diff --git a/include/VBox/vmm/pdmasynctask.h b/include/VBox/vmm/pdmasynctask.h new file mode 100644 index 00000000..422f9727 --- /dev/null +++ b/include/VBox/vmm/pdmasynctask.h @@ -0,0 +1,74 @@ +/** @file + * PDM - Pluggable Device Manager, Async Task. + */ + +/* + * Copyright (C) 2007-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmasynctask_h +#define VBOX_INCLUDED_vmm_pdmasynctask_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#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 /* !VBOX_INCLUDED_vmm_pdmasynctask_h */ + diff --git a/include/VBox/vmm/pdmaudiohostenuminline.h b/include/VBox/vmm/pdmaudiohostenuminline.h new file mode 100644 index 00000000..538c3bd6 --- /dev/null +++ b/include/VBox/vmm/pdmaudiohostenuminline.h @@ -0,0 +1,463 @@ +/* $Id: pdmaudiohostenuminline.h $ */ +/** @file + * PDM - Audio Helpers for host audio device enumeration, Inlined Code. (DEV,++) + * + * This is all inlined because it's too tedious to create a couple libraries to + * contain it all (same bad excuse as for intnetinline.h & pdmnetinline.h). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmaudiohostenuminline_h +#define VBOX_INCLUDED_vmm_pdmaudiohostenuminline_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <VBox/err.h> +#include <VBox/log.h> +#include <VBox/vmm/pdmaudioifs.h> +#include <VBox/vmm/pdmaudioinline.h> + +#include <iprt/assert.h> +#include <iprt/mem.h> +#include <iprt/string.h> + + +/** @defgroup grp_pdm_audio_host_enum_inline The PDM Host Audio Enumeration Helper APIs + * @ingroup grp_pdm + * @{ + */ + + +/** + * Allocates a host audio device for an enumeration result. + * + * @returns Newly allocated audio device, or NULL on failure. + * @param cb The total device structure size. This must be at least the + * size of PDMAUDIOHOSTDEV. The idea is that the caller extends + * the PDMAUDIOHOSTDEV structure and appends additional data + * after it in its private structure. + * @param cbName The number of bytes to allocate for the name field + * (including the terminator). Pass zero if RTStrAlloc and + * friends will be used. + * @param cbId The number of bytes to allocate for the ID field. Pass + * zero if RTStrAlloc and friends will be used. + */ +DECLINLINE(PPDMAUDIOHOSTDEV) PDMAudioHostDevAlloc(size_t cb, size_t cbName, size_t cbId) +{ + AssertReturn(cb >= sizeof(PDMAUDIOHOSTDEV), NULL); + AssertReturn(cb < _4M, NULL); + AssertReturn(cbName < _4K, NULL); + AssertReturn(cbId < _16K, NULL); + + PPDMAUDIOHOSTDEV pDev = (PPDMAUDIOHOSTDEV)RTMemAllocZ(RT_ALIGN_Z(cb + cbName + cbId, 64)); + if (pDev) + { + pDev->uMagic = PDMAUDIOHOSTDEV_MAGIC; + pDev->cbSelf = (uint32_t)cb; + RTListInit(&pDev->ListEntry); + if (cbName) + pDev->pszName = (char *)pDev + cb; + if (cbId) + pDev->pszId = (char *)pDev + cb + cbName; + } + return pDev; +} + +/** + * Frees a host audio device allocated by PDMAudioHostDevAlloc. + * + * @param pDev The device to free. NULL is ignored. + */ +DECLINLINE(void) PDMAudioHostDevFree(PPDMAUDIOHOSTDEV pDev) +{ + if (pDev) + { + Assert(pDev->uMagic == PDMAUDIOHOSTDEV_MAGIC); + pDev->uMagic = ~PDMAUDIOHOSTDEV_MAGIC; + pDev->cbSelf = 0; + + if (pDev->fFlags & PDMAUDIOHOSTDEV_F_NAME_ALLOC) + { + RTStrFree(pDev->pszName); + pDev->pszName = NULL; + } + + if (pDev->fFlags & PDMAUDIOHOSTDEV_F_ID_ALLOC) + { + RTStrFree(pDev->pszId); + pDev->pszId = NULL; + } + + RTMemFree(pDev); + } +} + +/** + * Duplicates a host audio device enumeration entry. + * + * @returns Duplicated audio device entry on success, or NULL on failure. + * @param pDev The audio device enum entry to duplicate. + * @param fOnlyCoreData + */ +DECLINLINE(PPDMAUDIOHOSTDEV) PDMAudioHostDevDup(PCPDMAUDIOHOSTDEV pDev, bool fOnlyCoreData) +{ + AssertPtrReturn(pDev, NULL); + Assert(pDev->uMagic == PDMAUDIOHOSTDEV_MAGIC); + Assert(fOnlyCoreData || !(pDev->fFlags & PDMAUDIOHOSTDEV_F_NO_DUP)); + + uint32_t cbToDup = fOnlyCoreData ? sizeof(PDMAUDIOHOSTDEV) : pDev->cbSelf; + AssertReturn(cbToDup >= sizeof(*pDev), NULL); + + PPDMAUDIOHOSTDEV pDevDup = PDMAudioHostDevAlloc(cbToDup, 0, 0); + if (pDevDup) + { + memcpy(pDevDup, pDev, cbToDup); + RTListInit(&pDevDup->ListEntry); + pDevDup->cbSelf = cbToDup; + + if (pDev->pszName) + { + uintptr_t off; + if ( (pDevDup->fFlags & PDMAUDIOHOSTDEV_F_NAME_ALLOC) + || (off = (uintptr_t)pDev->pszName - (uintptr_t)pDev) >= pDevDup->cbSelf) + { + pDevDup->fFlags |= PDMAUDIOHOSTDEV_F_NAME_ALLOC; + pDevDup->pszName = RTStrDup(pDev->pszName); + AssertReturnStmt(pDevDup->pszName, PDMAudioHostDevFree(pDevDup), NULL); + } + else + pDevDup->pszName = (char *)pDevDup + off; + } + + if (pDev->pszId) + { + uintptr_t off; + if ( (pDevDup->fFlags & PDMAUDIOHOSTDEV_F_ID_ALLOC) + || (off = (uintptr_t)pDev->pszId - (uintptr_t)pDev) >= pDevDup->cbSelf) + { + pDevDup->fFlags |= PDMAUDIOHOSTDEV_F_ID_ALLOC; + pDevDup->pszId = RTStrDup(pDev->pszId); + AssertReturnStmt(pDevDup->pszId, PDMAudioHostDevFree(pDevDup), NULL); + } + else + pDevDup->pszId = (char *)pDevDup + off; + } + } + + return pDevDup; +} + +/** + * Initializes a host audio device enumeration. + * + * @param pDevEnm The enumeration to initialize. + */ +DECLINLINE(void) PDMAudioHostEnumInit(PPDMAUDIOHOSTENUM pDevEnm) +{ + AssertPtr(pDevEnm); + + pDevEnm->uMagic = PDMAUDIOHOSTENUM_MAGIC; + pDevEnm->cDevices = 0; + RTListInit(&pDevEnm->LstDevices); +} + +/** + * Deletes the host audio device enumeration and frees all device entries + * associated with it. + * + * The user must call PDMAudioHostEnumInit again to use it again. + * + * @param pDevEnm The host audio device enumeration to delete. + */ +DECLINLINE(void) PDMAudioHostEnumDelete(PPDMAUDIOHOSTENUM pDevEnm) +{ + if (pDevEnm) + { + AssertPtr(pDevEnm); + AssertReturnVoid(pDevEnm->uMagic == PDMAUDIOHOSTENUM_MAGIC); + + PPDMAUDIOHOSTDEV pDev, pDevNext; + RTListForEachSafe(&pDevEnm->LstDevices, pDev, pDevNext, PDMAUDIOHOSTDEV, ListEntry) + { + RTListNodeRemove(&pDev->ListEntry); + + PDMAudioHostDevFree(pDev); + + pDevEnm->cDevices--; + } + + /* Sanity. */ + Assert(RTListIsEmpty(&pDevEnm->LstDevices)); + Assert(pDevEnm->cDevices == 0); + + pDevEnm->uMagic = ~PDMAUDIOHOSTENUM_MAGIC; + } +} + +/** + * Adds an audio device to a device enumeration. + * + * @param pDevEnm Device enumeration to add device to. + * @param pDev Device to add. The pointer will be owned by the device enumeration then. + */ +DECLINLINE(void) PDMAudioHostEnumAppend(PPDMAUDIOHOSTENUM pDevEnm, PPDMAUDIOHOSTDEV pDev) +{ + AssertPtr(pDevEnm); + AssertPtr(pDev); + Assert(pDevEnm->uMagic == PDMAUDIOHOSTENUM_MAGIC); + + RTListAppend(&pDevEnm->LstDevices, &pDev->ListEntry); + pDevEnm->cDevices++; +} + +/** + * Appends copies of matching host device entries from one to another enumeration. + * + * @returns VBox status code. + * @param pDstDevEnm The target to append copies of matching device to. + * @param pSrcDevEnm The source to copy matching devices from. + * @param enmUsage The usage to match for copying. + * Use PDMAUDIODIR_INVALID to match all entries. + * @param fOnlyCoreData Set this to only copy the PDMAUDIOHOSTDEV part. + * Careful with passing @c false here as not all + * backends have data that can be copied. + */ +DECLINLINE(int) PDMAudioHostEnumCopy(PPDMAUDIOHOSTENUM pDstDevEnm, PCPDMAUDIOHOSTENUM pSrcDevEnm, + PDMAUDIODIR enmUsage, bool fOnlyCoreData) +{ + AssertPtrReturn(pDstDevEnm, VERR_INVALID_POINTER); + AssertReturn(pDstDevEnm->uMagic == PDMAUDIOHOSTENUM_MAGIC, VERR_WRONG_ORDER); + + AssertPtrReturn(pSrcDevEnm, VERR_INVALID_POINTER); + AssertReturn(pSrcDevEnm->uMagic == PDMAUDIOHOSTENUM_MAGIC, VERR_WRONG_ORDER); + + PPDMAUDIOHOSTDEV pSrcDev; + RTListForEach(&pSrcDevEnm->LstDevices, pSrcDev, PDMAUDIOHOSTDEV, ListEntry) + { + if ( enmUsage == pSrcDev->enmUsage + || enmUsage == PDMAUDIODIR_INVALID /*all*/) + { + PPDMAUDIOHOSTDEV pDstDev = PDMAudioHostDevDup(pSrcDev, fOnlyCoreData); + AssertReturn(pDstDev, VERR_NO_MEMORY); + + PDMAudioHostEnumAppend(pDstDevEnm, pDstDev); + } + } + + return VINF_SUCCESS; +} + +/** + * Moves all the device entries from one enumeration to another, destroying the + * former. + * + * @returns VBox status code. + * @param pDstDevEnm The target to put move @a pSrcDevEnm to. This + * does not need to be initialized, but if it is it + * must not have any device entries. + * @param pSrcDevEnm The source to move from. This will be empty + * upon successful return. + */ +DECLINLINE(int) PDMAudioHostEnumMove(PPDMAUDIOHOSTENUM pDstDevEnm, PPDMAUDIOHOSTENUM pSrcDevEnm) +{ + AssertPtrReturn(pDstDevEnm, VERR_INVALID_POINTER); + AssertReturn(pDstDevEnm->uMagic != PDMAUDIOHOSTENUM_MAGIC || pDstDevEnm->cDevices == 0, VERR_WRONG_ORDER); + + AssertPtrReturn(pSrcDevEnm, VERR_INVALID_POINTER); + AssertReturn(pSrcDevEnm->uMagic == PDMAUDIOHOSTENUM_MAGIC, VERR_WRONG_ORDER); + + pDstDevEnm->uMagic = PDMAUDIOHOSTENUM_MAGIC; + RTListInit(&pDstDevEnm->LstDevices); + pDstDevEnm->cDevices = pSrcDevEnm->cDevices; + if (pSrcDevEnm->cDevices) + { + PPDMAUDIOHOSTDEV pCur; + while ((pCur = RTListRemoveFirst(&pSrcDevEnm->LstDevices, PDMAUDIOHOSTDEV, ListEntry)) != NULL) + RTListAppend(&pDstDevEnm->LstDevices, &pCur->ListEntry); + } + return VINF_SUCCESS; +} + +/** + * Get the default device with the given usage. + * + * This assumes that only one default device per usage is set, if there should + * be more than one, the first one is returned. + * + * @returns Default device if found, or NULL if not. + * @param pDevEnm Device enumeration to get default device for. + * @param enmUsage Usage to get default device for. + * Pass PDMAUDIODIR_INVALID to get the first device with + * either PDMAUDIOHOSTDEV_F_DEFAULT_OUT or + * PDMAUDIOHOSTDEV_F_DEFAULT_IN set. + */ +DECLINLINE(PPDMAUDIOHOSTDEV) PDMAudioHostEnumGetDefault(PCPDMAUDIOHOSTENUM pDevEnm, PDMAUDIODIR enmUsage) +{ + AssertPtrReturn(pDevEnm, NULL); + AssertReturn(pDevEnm->uMagic == PDMAUDIOHOSTENUM_MAGIC, NULL); + + Assert(enmUsage == PDMAUDIODIR_IN || enmUsage == PDMAUDIODIR_OUT || enmUsage == PDMAUDIODIR_INVALID); + uint32_t const fFlags = enmUsage == PDMAUDIODIR_IN ? PDMAUDIOHOSTDEV_F_DEFAULT_IN + : enmUsage == PDMAUDIODIR_OUT ? PDMAUDIOHOSTDEV_F_DEFAULT_OUT + : enmUsage == PDMAUDIODIR_INVALID ? PDMAUDIOHOSTDEV_F_DEFAULT_IN | PDMAUDIOHOSTDEV_F_DEFAULT_OUT + : 0; + + PPDMAUDIOHOSTDEV pDev; + RTListForEach(&pDevEnm->LstDevices, pDev, PDMAUDIOHOSTDEV, ListEntry) + { + if (pDev->fFlags & fFlags) + { + Assert(pDev->enmUsage == enmUsage || pDev->enmUsage == PDMAUDIODIR_DUPLEX || enmUsage == PDMAUDIODIR_INVALID); + return pDev; + } + } + + return NULL; +} + +/** + * Get the number of device with the given usage. + * + * @returns Number of matching devices. + * @param pDevEnm Device enumeration to get default device for. + * @param enmUsage Usage to count devices for. + * Pass PDMAUDIODIR_INVALID to get the total number of devices. + */ +DECLINLINE(uint32_t) PDMAudioHostEnumCountMatching(PCPDMAUDIOHOSTENUM pDevEnm, PDMAUDIODIR enmUsage) +{ + AssertPtrReturn(pDevEnm, 0); + AssertReturn(pDevEnm->uMagic == PDMAUDIOHOSTENUM_MAGIC, 0); + + if (enmUsage == PDMAUDIODIR_INVALID) + return pDevEnm->cDevices; + + uint32_t cDevs = 0; + PPDMAUDIOHOSTDEV pDev; + RTListForEach(&pDevEnm->LstDevices, pDev, PDMAUDIOHOSTDEV, ListEntry) + { + if (enmUsage == pDev->enmUsage) + cDevs++; + } + + return cDevs; +} + +/** The max string length for all PDMAUDIOHOSTDEV_F_XXX. + * @sa PDMAudioHostDevFlagsToString */ +#define PDMAUDIOHOSTDEV_MAX_FLAGS_STRING_LEN sizeof("DEFAULT_OUT DEFAULT_IN HOTPLUG BUGGY IGNORE LOCKED DEAD NAME_ALLOC ID_ALLOC NO_DUP ") + +/** + * Converts an audio device flags to a string. + * + * @returns + * @param pszDst Destination buffer with a size of at least + * PDMAUDIOHOSTDEV_MAX_FLAGS_STRING_LEN bytes (including + * the string terminator). + * @param fFlags Audio flags (PDMAUDIOHOSTDEV_F_XXX) to convert. + */ +DECLINLINE(const char *) PDMAudioHostDevFlagsToString(char pszDst[PDMAUDIOHOSTDEV_MAX_FLAGS_STRING_LEN], uint32_t fFlags) +{ + static const struct { const char *pszMnemonic; uint32_t cchMnemonic; uint32_t fFlag; } s_aFlags[] = + { + { RT_STR_TUPLE("DEFAULT_OUT "), PDMAUDIOHOSTDEV_F_DEFAULT_OUT }, + { RT_STR_TUPLE("DEFAULT_IN "), PDMAUDIOHOSTDEV_F_DEFAULT_IN }, + { RT_STR_TUPLE("HOTPLUG "), PDMAUDIOHOSTDEV_F_HOTPLUG }, + { RT_STR_TUPLE("BUGGY "), PDMAUDIOHOSTDEV_F_BUGGY }, + { RT_STR_TUPLE("IGNORE "), PDMAUDIOHOSTDEV_F_IGNORE }, + { RT_STR_TUPLE("LOCKED "), PDMAUDIOHOSTDEV_F_LOCKED }, + { RT_STR_TUPLE("DEAD "), PDMAUDIOHOSTDEV_F_DEAD }, + { RT_STR_TUPLE("NAME_ALLOC "), PDMAUDIOHOSTDEV_F_NAME_ALLOC }, + { RT_STR_TUPLE("ID_ALLOC "), PDMAUDIOHOSTDEV_F_ID_ALLOC }, + { RT_STR_TUPLE("NO_DUP "), PDMAUDIOHOSTDEV_F_NO_DUP }, + }; + size_t offDst = 0; + for (uint32_t i = 0; i < RT_ELEMENTS(s_aFlags); i++) + if (fFlags & s_aFlags[i].fFlag) + { + fFlags &= ~s_aFlags[i].fFlag; + memcpy(&pszDst[offDst], s_aFlags[i].pszMnemonic, s_aFlags[i].cchMnemonic); + offDst += s_aFlags[i].cchMnemonic; + } + Assert(fFlags == 0); + Assert(offDst < PDMAUDIOHOSTDEV_MAX_FLAGS_STRING_LEN); + + if (offDst) + pszDst[offDst - 1] = '\0'; + else + memcpy(pszDst, "NONE", sizeof("NONE")); + return pszDst; +} + +/** + * Logs an audio device enumeration. + * + * @param pDevEnm Device enumeration to log. + * @param pszDesc Logging description (prefix). + */ +DECLINLINE(void) PDMAudioHostEnumLog(PCPDMAUDIOHOSTENUM pDevEnm, const char *pszDesc) +{ +#ifdef LOG_ENABLED + AssertPtrReturnVoid(pDevEnm); + AssertPtrReturnVoid(pszDesc); + AssertReturnVoid(pDevEnm->uMagic == PDMAUDIOHOSTENUM_MAGIC); + + if (LogIsEnabled()) + { + LogFunc(("%s: %RU32 devices\n", pszDesc, pDevEnm->cDevices)); + + PPDMAUDIOHOSTDEV pDev; + RTListForEach(&pDevEnm->LstDevices, pDev, PDMAUDIOHOSTDEV, ListEntry) + { + char szFlags[PDMAUDIOHOSTDEV_MAX_FLAGS_STRING_LEN]; + LogFunc(("Device '%s':\n", pDev->pszName)); + LogFunc((" ID = %s\n", pDev->pszId ? pDev->pszId : "<none>")); + LogFunc((" Usage = %s\n", PDMAudioDirGetName(pDev->enmUsage))); + LogFunc((" Flags = %s\n", PDMAudioHostDevFlagsToString(szFlags, pDev->fFlags))); + LogFunc((" Input channels = %RU8\n", pDev->cMaxInputChannels)); + LogFunc((" Output channels = %RU8\n", pDev->cMaxOutputChannels)); + LogFunc((" cbExtra = %RU32 bytes\n", pDev->cbSelf - sizeof(PDMAUDIOHOSTDEV))); + } + } +#else + RT_NOREF(pDevEnm, pszDesc); +#endif +} + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_pdmaudiohostenuminline_h */ diff --git a/include/VBox/vmm/pdmaudioifs.h b/include/VBox/vmm/pdmaudioifs.h new file mode 100644 index 00000000..11735f25 --- /dev/null +++ b/include/VBox/vmm/pdmaudioifs.h @@ -0,0 +1,1567 @@ +/** @file + * PDM - Pluggable Device Manager, Audio interfaces. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +/** @page pg_pdm_audio PDM Audio + * + * PDM provides audio device emulations and their driver chains with the + * interfaces they need to communicate with each other. + * + * + * @section sec_pdm_audio_overview Overview + * +@startuml +skinparam componentStyle rectangle + +node VM { + [Music Player App] --> [Guest Audio Driver] + [Recording App] <-- [Guest Audio Driver] +} + +component "DevAudio (DevHda / DevIchAc97 / DevSB16)" as DevAudio { + [Output DMA Engine] + [Input DMA Engine] + () LUN0 + () LUN1 + + component "AudioMixer" { + component "Output Sink" { + () "Output Stream #0" as DrvStreamOut0 + () "Output Stream #1" as DrvStreamOut1 + [Output Mixer Buffer] --> DrvStreamOut0 + [Output Mixer Buffer] --> DrvStreamOut1 + [Output DMA Engine] --> [Output Mixer Buffer] + DrvStreamOut0 --> LUN0 + DrvStreamOut1 --> LUN1 + } + component "Input Sink" { + () "Input Stream #2" as DrvStreamIn0 + () "Input Stream #3" as DrvStreamIn1 + [Input Mixer Buffer] <-- DrvStreamIn0 + [Input Mixer Buffer] <-- DrvStreamIn1 + [Input DMA Engine] --> [Input Mixer Buffer] + DrvStreamIn0 <-- LUN0 + DrvStreamIn1 <-- LUN1 + } + } +} +[Guest Audio Driver] <..> DevAudio : " MMIO or Port I/O, DMA" + +node "Driver Chain #0" { + component "DrvAudio#0" { + () PDMIHOSTAUDIOPORT0 + () PDMIAUDIOCONNECTOR0 + } + component "DrvHostAudioWasApi" { + () PDMIHOSTAUDIO0 + } +} +PDMIHOSTAUDIOPORT0 <--> PDMIHOSTAUDIO0 + +node "Driver Chain #1" { + component "DrvAudio#1" { + () PDMIAUDIOCONNECTOR1 + () PDMIHOSTAUDIOPORT1 + } + component "DrvAudioVRDE" { + () PDMIHOSTAUDIO1 + } +} +note bottom of DrvAudioVRDE + The backend driver is sometimes not configured if the component it represents + is not configured for the VM. However, Main will still set up the LUN but + with just DrvAudio attached to simplify runtime activation of the component. + In the meanwhile, the DrvAudio instance works as if DrvHostAudioNull were attached. +end note + +LUN1 <--> PDMIAUDIOCONNECTOR1 +LUN0 <--> PDMIAUDIOCONNECTOR0 + +PDMIHOSTAUDIOPORT1 <--> PDMIHOSTAUDIO1 + +@enduml + * + * Actors: + * - An audio device implementation: "DevAudio" + * - Mixer instance (AudioMixer.cpp) with one or more mixer + * sinks: "Output Sink", "Input Sink" + * - One DMA engine teamed up with each mixer sink: "Output DMA + * Engine", "Input DMA Engine" + * - The audio driver "DrvAudio" instances attached to LUN0 and LUN1 + * respectively: "DrvAudio#0", "DrvAudio#1" + * - The Windows host audio driver attached to "DrvAudio0": "DrvHostAudioWas" + * - The VRDE/VRDP host audio driver attached to "DrvAudio1": "DrvAudioVRDE" + * + * Both "Output Sink" and "Input Sink" talks to all the attached driver chains + * ("DrvAudio #0" and "DrvAudio #1"), but using different PDMAUDIOSTREAM + * instances. There can be an arbritrary number of driver chains attached to an + * audio device, the mixer sinks will multiplex output to each of them and blend + * input from all of them, taking care of format and rate conversions. The + * mixer and mixer sinks does not fit into the PDM device/driver model, because + * a driver can only have exactly one or zero other drivers attached, so it is + * implemented as a separate component that all the audio devices share (see + * AudioMixer.h, AudioMixer.cpp, AudioMixBuffer.h and AudioMixBuffer.cpp). + * + * The driver chains attached to LUN0, LUN1, ... LUNn typically have two + * drivers attached, first DrvAudio and then a backend driver like + * DrvHostAudioWasApi, DrvHostAudioPulseAudio, or DrvAudioVRDE. DrvAudio + * exposes PDMIAUDIOCONNECTOR upwards towards the device and mixer component, + * and PDMIHOSTAUDIOPORT downwards towards DrvHostAudioWasApi and the other + * backends. + * + * The backend exposes the PDMIHOSTAUDIO upwards towards DrvAudio. It is + * possible, though, to only have the DrvAudio instance and not backend, in + * which case DrvAudio works as if the NULL backend was attached. Main does + * such setups when the main component we're interfacing with isn't currently + * active, as this simplifies runtime activation. + * + * The purpose of DrvAudio is to make the work of the backend as simple as + * possible and try avoid needing to write the same code over and over again for + * each backend. It takes care of: + * - Stream creation, operation, re-initialization and destruction. + * - Pre-buffering. + * - Thread pool. + * + * The purpose of a host audio driver (aka backend) is to interface with the + * host audio system (or other audio systems like VRDP and video recording). + * The backend will optionally provide a list of host audio devices, switch + * between them, and monitor changes to them. By default our host backends use + * the default host device and will trigger stream re-initialization if this + * changes while we're using it. + * + * + * @section sec_pdm_audio_device Virtual Audio Device + * + * The virtual device translates the settings of the emulated device into mixing + * sinks with sample format, sample rate, volume control, and whatnot. + * + * It also implements a DMA engine for transfering samples to (input) or from + * (output) the guest memory. The starting and stopping of the DMA engines are + * communicated to the associated mixing sinks and by then onto the + * PDMAUDIOSTREAM instance for each driver chain. A RTCIRCBUF is used as an + * intermediary between the DMA engine and the asynchronous worker thread of the + * mixing sink. + * + * + * @section sec_pdm_audio_mixing Audio Mixing + * + * The audio mixer is a mandatory component in an audio device. It consists of + * a mixer and one or more sinks with mixer buffers. The sinks are typically + * one per virtual output/input connector, so for instance you could have a + * device with a "PCM Output" sink and a "PCM Input" sink. + * + * The audio mixer takes care of: + * - Much of the driver chain (LUN) management work. + * - Multiplexing output to each active driver chain. + * - Blending input from each active driver chain into a single audio + * stream. + * - Do format conversion (it uses signed 32-bit PCM internally) between + * the audio device and all of the LUNs (no common format needed). + * - Do sample rate conversions between the device rate and that of the + * individual driver chains. + * - Apply the volume settings of the device to the audio stream. + * - Provide the asynchronous thread that pushes data from the device's + * internal DMA buffer and all the way to the backend for output sinks, + * and vice versa for input. + * + * The term active LUNs above means that not all LUNs will actually produce + * (input) or consume (output) audio. The mixer checks the return of + * PDMIHOSTAUDIO::pfnStreamGetState each time it's processing samples to see + * which streams are currently active and which aren't. Inactive streams are + * ignored. + * + * For more info: @ref pg_audio_mixer, @ref pg_audio_mixing_buffers + * + * The AudioMixer API reference can be found here: + * - @ref grp_pdm_ifs_audio_mixing + * - @ref grp_pdm_ifs_audio_mixing_buffers + * + * + * @section sec_pdm_audio_timing Timing + * + * Handling audio data in a virtual environment is hard, as the human perception + * is very sensitive to the slightest cracks and stutters in the audible data, + * and the task of playing back and recording audio is in the real-time domain. + * + * The virtual machine is not executed with any real-time guarentees, only best + * effort, mainly because it is subject to preemptive scheduling on the host + * side. The audio processing done on the guest side is typically also subject + * to preemptive scheduling on the guest side and available CPU processing power + * there. + * + * Thus, the guest may be lagging behind because the host prioritizes other + * processes/threads over the virtual machine. This will, if it's too servere, + * cause the virtual machine to speed up it's time sense while it's trying to + * catch up. So, we can easily have a bit of a seesaw execution going on here, + * where in the playback case, the guest produces data too slowly for while and + * then switches to producing it too quickly for a while to catch up. + * + * Our working principle is that the backends and the guest are producing and + * consuming samples at the same rate, but we have to deal with the uneven + * execution. + * + * To deal with this we employ (by default) 300ms of backend buffer and + * pre-buffer 150ms of that for both input and output audio streams. This means + * we have about 150ms worth of samples to feed to the host audio device should + * the virtual machine be starving and lagging behind. Likewise, we have about + * 150ms of buffer space will can fill when the VM is in a catch-up mode. Now, + * 300ms and 150 ms isn't much for the purpose of glossing over + * scheduling/timing differences here, but we can't do too much more or the lag + * will grow rather annoying. The pre-buffering is implemented by DrvAudio. + * + * In addition to the backend buffer that defaults to 300ms, we have the + * internal DMA buffer of the device and the mixing buffer of the mixing sink. + * The latter two are typically rather small, sized to fit the anticipated DMA + * period currently in use by the guest. + */ + +#ifndef VBOX_INCLUDED_vmm_pdmaudioifs_h +#define VBOX_INCLUDED_vmm_pdmaudioifs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/assertcompile.h> +#include <iprt/critsect.h> +#include <iprt/circbuf.h> +#include <iprt/list.h> +#include <iprt/path.h> + +#include <VBox/types.h> +#include <VBox/vmm/pdmcommon.h> +#include <VBox/vmm/stam.h> + +RT_C_DECLS_BEGIN + + +/** @defgroup grp_pdm_ifs_audio PDM Audio Interfaces + * @ingroup grp_pdm_interfaces + * @{ + */ + +/** The maximum number of channels PDM supports. */ +#define PDMAUDIO_MAX_CHANNELS 12 + +/** + * Audio direction. + */ +typedef enum PDMAUDIODIR +{ + /** Invalid zero value as per usual (guards against using unintialized values). */ + PDMAUDIODIR_INVALID = 0, + /** Unknown direction. */ + PDMAUDIODIR_UNKNOWN, + /** Input. */ + PDMAUDIODIR_IN, + /** Output. */ + PDMAUDIODIR_OUT, + /** Duplex handling. */ + PDMAUDIODIR_DUPLEX, + /** End of valid values. */ + PDMAUDIODIR_END, + /** Hack to blow the type up to 32-bit. */ + PDMAUDIODIR_32BIT_HACK = 0x7fffffff +} PDMAUDIODIR; + + +/** @name PDMAUDIOHOSTDEV_F_XXX + * @{ */ +/** No flags set. */ +#define PDMAUDIOHOSTDEV_F_NONE UINT32_C(0) +/** The default input (capture/recording) device (for the user). */ +#define PDMAUDIOHOSTDEV_F_DEFAULT_IN RT_BIT_32(0) +/** The default output (playback) device (for the user). */ +#define PDMAUDIOHOSTDEV_F_DEFAULT_OUT RT_BIT_32(1) +/** The device can be removed at any time and we have to deal with it. */ +#define PDMAUDIOHOSTDEV_F_HOTPLUG RT_BIT_32(2) +/** The device is known to be buggy and needs special treatment. */ +#define PDMAUDIOHOSTDEV_F_BUGGY RT_BIT_32(3) +/** Ignore the device, no matter what. */ +#define PDMAUDIOHOSTDEV_F_IGNORE RT_BIT_32(4) +/** The device is present but marked as locked by some other application. */ +#define PDMAUDIOHOSTDEV_F_LOCKED RT_BIT_32(5) +/** The device is present but not in an alive state (dead). */ +#define PDMAUDIOHOSTDEV_F_DEAD RT_BIT_32(6) +/** Set if the PDMAUDIOHOSTDEV::pszName is allocated. */ +#define PDMAUDIOHOSTDEV_F_NAME_ALLOC RT_BIT_32(29) +/** Set if the PDMAUDIOHOSTDEV::pszId is allocated. */ +#define PDMAUDIOHOSTDEV_F_ID_ALLOC RT_BIT_32(30) +/** Set if the extra backend specific data cannot be duplicated. */ +#define PDMAUDIOHOSTDEV_F_NO_DUP RT_BIT_32(31) +/** @} */ + +/** + * Audio device type. + */ +typedef enum PDMAUDIODEVICETYPE +{ + /** Invalid zero value as per usual (guards against using unintialized values). */ + PDMAUDIODEVICETYPE_INVALID = 0, + /** Unknown device type. This is the default. */ + PDMAUDIODEVICETYPE_UNKNOWN, + /** Dummy device; for backends which are not able to report + * actual device information (yet). */ + PDMAUDIODEVICETYPE_DUMMY, + /** The device is built into the host (non-removable). */ + PDMAUDIODEVICETYPE_BUILTIN, + /** The device is an (external) USB device. */ + PDMAUDIODEVICETYPE_USB, + /** End of valid values. */ + PDMAUDIODEVICETYPE_END, + /** Hack to blow the type up to 32-bit. */ + PDMAUDIODEVICETYPE_32BIT_HACK = 0x7fffffff +} PDMAUDIODEVICETYPE; + +/** + * Host audio device info, part of enumeration result. + * + * @sa PDMAUDIOHOSTENUM, PDMIHOSTAUDIO::pfnGetDevices + */ +typedef struct PDMAUDIOHOSTDEV +{ + /** List entry (like PDMAUDIOHOSTENUM::LstDevices). */ + RTLISTNODE ListEntry; + /** Magic value (PDMAUDIOHOSTDEV_MAGIC). */ + uint32_t uMagic; + /** Size of this structure and whatever backend specific data that follows it. */ + uint32_t cbSelf; + /** The device type. */ + PDMAUDIODEVICETYPE enmType; + /** Usage of the device. */ + PDMAUDIODIR enmUsage; + /** Device flags, PDMAUDIOHOSTDEV_F_XXX. */ + uint32_t fFlags; + /** Maximum number of input audio channels the device supports. */ + uint8_t cMaxInputChannels; + /** Maximum number of output audio channels the device supports. */ + uint8_t cMaxOutputChannels; + uint8_t abAlignment[ARCH_BITS == 32 ? 2 + 8 : 2 + 8]; + /** Backend specific device identifier, can be NULL, used to select device. + * This can either point into some non-public part of this structure or to a + * RTStrAlloc allocation. PDMAUDIOHOSTDEV_F_ID_ALLOC is set in the latter + * case. + * @sa PDMIHOSTAUDIO::pfnSetDevice */ + char *pszId; + /** The friendly device name. */ + char *pszName; +} PDMAUDIOHOSTDEV; +AssertCompileSizeAlignment(PDMAUDIOHOSTDEV, 16); +/** Pointer to audio device info (enumeration result). */ +typedef PDMAUDIOHOSTDEV *PPDMAUDIOHOSTDEV; +/** Pointer to a const audio device info (enumeration result). */ +typedef PDMAUDIOHOSTDEV const *PCPDMAUDIOHOSTDEV; + +/** Magic value for PDMAUDIOHOSTDEV. */ +#define PDMAUDIOHOSTDEV_MAGIC PDM_VERSION_MAKE(0xa0d0, 3, 0) + + +/** + * A host audio device enumeration result. + * + * @sa PDMIHOSTAUDIO::pfnGetDevices + */ +typedef struct PDMAUDIOHOSTENUM +{ + /** Magic value (PDMAUDIOHOSTENUM_MAGIC). */ + uint32_t uMagic; + /** Number of audio devices in the list. */ + uint32_t cDevices; + /** List of audio devices (PDMAUDIOHOSTDEV). */ + RTLISTANCHOR LstDevices; +} PDMAUDIOHOSTENUM; +/** Pointer to an audio device enumeration result. */ +typedef PDMAUDIOHOSTENUM *PPDMAUDIOHOSTENUM; +/** Pointer to a const audio device enumeration result. */ +typedef PDMAUDIOHOSTENUM const *PCPDMAUDIOHOSTENUM; + +/** Magic for the host audio device enumeration. */ +#define PDMAUDIOHOSTENUM_MAGIC PDM_VERSION_MAKE(0xa0d1, 1, 0) + + +/** + * Audio configuration (static) of an audio host backend. + */ +typedef struct PDMAUDIOBACKENDCFG +{ + /** The backend's friendly name. */ + char szName[32]; + /** The size of the backend specific stream data (in bytes). */ + uint32_t cbStream; + /** PDMAUDIOBACKEND_F_XXX. */ + uint32_t fFlags; + /** Number of concurrent output (playback) streams supported on the host. + * UINT32_MAX for unlimited concurrent streams, 0 if no concurrent input streams are supported. */ + uint32_t cMaxStreamsOut; + /** Number of concurrent input (recording) streams supported on the host. + * UINT32_MAX for unlimited concurrent streams, 0 if no concurrent input streams are supported. */ + uint32_t cMaxStreamsIn; +} PDMAUDIOBACKENDCFG; +/** Pointer to a static host audio audio configuration. */ +typedef PDMAUDIOBACKENDCFG *PPDMAUDIOBACKENDCFG; + +/** @name PDMAUDIOBACKEND_F_XXX - PDMAUDIOBACKENDCFG::fFlags + * @{ */ +/** PDMIHOSTAUDIO::pfnStreamConfigHint should preferably be called on a + * worker thread rather than EMT as it may take a good while. */ +#define PDMAUDIOBACKEND_F_ASYNC_HINT RT_BIT_32(0) +/** PDMIHOSTAUDIO::pfnStreamDestroy and any preceeding + * PDMIHOSTAUDIO::pfnStreamControl/DISABLE should be preferably be called on a + * worker thread rather than EMT as it may take a good while. */ +#define PDMAUDIOBACKEND_F_ASYNC_STREAM_DESTROY RT_BIT_32(1) +/** @} */ + + +/** + * Audio path: input sources and playback destinations. + * + * Think of this as the name of the socket you plug the virtual audio stream + * jack into. + * + * @note Not quite sure what the purpose of this type is. It used to be two + * separate enums (PDMAUDIOPLAYBACKDST & PDMAUDIORECSRC) without overlapping + * values and most commonly used in a union (PDMAUDIODSTSRCUNION). The output + * values were designated "channel" (e.g. "Front channel"), whereas this was not + * done to the input ones. So, I'm (bird) a little confused what the actual + * meaning was. + */ +typedef enum PDMAUDIOPATH +{ + /** Customary invalid zero value. */ + PDMAUDIOPATH_INVALID = 0, + + /** Unknown path / Doesn't care. */ + PDMAUDIOPATH_UNKNOWN, + + /** First output value. */ + PDMAUDIOPATH_OUT_FIRST, + /** Output: Front. */ + PDMAUDIOPATH_OUT_FRONT = PDMAUDIOPATH_OUT_FIRST, + /** Output: Center / LFE (Subwoofer). */ + PDMAUDIOPATH_OUT_CENTER_LFE, + /** Output: Rear. */ + PDMAUDIOPATH_OUT_REAR, + /** Last output value (inclusive) */ + PDMAUDIOPATH_OUT_END = PDMAUDIOPATH_OUT_REAR, + + /** First input value. */ + PDMAUDIOPATH_IN_FIRST, + /** Input: Microphone. */ + PDMAUDIOPATH_IN_MIC = PDMAUDIOPATH_IN_FIRST, + /** Input: CD. */ + PDMAUDIOPATH_IN_CD, + /** Input: Video-In. */ + PDMAUDIOPATH_IN_VIDEO, + /** Input: AUX. */ + PDMAUDIOPATH_IN_AUX, + /** Input: Line-In. */ + PDMAUDIOPATH_IN_LINE, + /** Input: Phone-In. */ + PDMAUDIOPATH_IN_PHONE, + /** Last intput value (inclusive). */ + PDMAUDIOPATH_IN_LAST = PDMAUDIOPATH_IN_PHONE, + + /** End of valid values. */ + PDMAUDIOPATH_END, + /** Hack to blow the typ up to 32 bits. */ + PDMAUDIOPATH_32BIT_HACK = 0x7fffffff +} PDMAUDIOPATH; + + +/** + * Standard speaker channel IDs. + */ +typedef enum PDMAUDIOCHANNELID +{ + /** Invalid zero value as per usual (guards against using unintialized values). */ + PDMAUDIOCHANNELID_INVALID = 0, + + /** Unused channel - fill with zero when encoding, ignore when decoding. */ + PDMAUDIOCHANNELID_UNUSED_ZERO, + /** Unused channel - fill with silence when encoding, ignore when decoding. */ + PDMAUDIOCHANNELID_UNUSED_SILENCE, + + /** Unknown channel ID (unable to map to PDM terms). */ + PDMAUDIOCHANNELID_UNKNOWN, + + /** The first ID in the standard WAV-file assignment block. */ + PDMAUDIOCHANNELID_FIRST_STANDARD, + /** Front left channel (FR). */ + PDMAUDIOCHANNELID_FRONT_LEFT = PDMAUDIOCHANNELID_FIRST_STANDARD, + /** Front right channel (FR). */ + PDMAUDIOCHANNELID_FRONT_RIGHT, + /** Front center channel (FC). */ + PDMAUDIOCHANNELID_FRONT_CENTER, + /** Mono channel (alias for front center). */ + PDMAUDIOCHANNELID_MONO = PDMAUDIOCHANNELID_FRONT_CENTER, + /** Low frequency effects (subwoofer) channel. */ + PDMAUDIOCHANNELID_LFE, + /** Rear left channel (BL). */ + PDMAUDIOCHANNELID_REAR_LEFT, + /** Rear right channel (BR). */ + PDMAUDIOCHANNELID_REAR_RIGHT, + /** Front left of center channel (FLC). */ + PDMAUDIOCHANNELID_FRONT_LEFT_OF_CENTER, + /** Front right of center channel (FLR). */ + PDMAUDIOCHANNELID_FRONT_RIGHT_OF_CENTER, + /** Rear center channel (BC). */ + PDMAUDIOCHANNELID_REAR_CENTER, + /** Side left channel (SL). */ + PDMAUDIOCHANNELID_SIDE_LEFT, + /** Side right channel (SR). */ + PDMAUDIOCHANNELID_SIDE_RIGHT, + /** Top center (TC). */ + PDMAUDIOCHANNELID_TOP_CENTER, + /** Front left height channel (TFL). */ + PDMAUDIOCHANNELID_FRONT_LEFT_HEIGHT, + /** Front center height channel (TFC). */ + PDMAUDIOCHANNELID_FRONT_CENTER_HEIGHT, + /** Front right height channel (TFR). */ + PDMAUDIOCHANNELID_FRONT_RIGHT_HEIGHT, + /** Rear left height channel (TBL). */ + PDMAUDIOCHANNELID_REAR_LEFT_HEIGHT, + /** Rear center height channel (TBC). */ + PDMAUDIOCHANNELID_REAR_CENTER_HEIGHT, + /** Rear right height channel (TBR). */ + PDMAUDIOCHANNELID_REAR_RIGHT_HEIGHT, + /** The end of the standard WAV-file assignment block. */ + PDMAUDIOCHANNELID_END_STANDARD, + + /** End of valid values. */ + PDMAUDIOCHANNELID_END = PDMAUDIOCHANNELID_END_STANDARD, + /** Hack to blow the type up to 32-bit. */ + PDMAUDIOCHANNELID_32BIT_HACK = 0x7fffffff +} PDMAUDIOCHANNELID; +AssertCompile(PDMAUDIOCHANNELID_FRONT_LEFT - PDMAUDIOCHANNELID_FIRST_STANDARD == 0); +AssertCompile(PDMAUDIOCHANNELID_LFE - PDMAUDIOCHANNELID_FIRST_STANDARD == 3); +AssertCompile(PDMAUDIOCHANNELID_REAR_CENTER - PDMAUDIOCHANNELID_FIRST_STANDARD == 8); +AssertCompile(PDMAUDIOCHANNELID_REAR_RIGHT_HEIGHT - PDMAUDIOCHANNELID_FIRST_STANDARD == 17); + + +/** + * Properties of audio streams for host/guest for in or out directions. + */ +typedef struct PDMAUDIOPCMPROPS +{ + /** The frame size. */ + uint8_t cbFrame; + /** Shift count used with PDMAUDIOPCMPROPS_F2B and PDMAUDIOPCMPROPS_B2F. + * Depends on number of stream channels and the stream format being used, calc + * value using PDMAUDIOPCMPROPS_MAKE_SHIFT. + * @sa PDMAUDIOSTREAMCFG_B2F, PDMAUDIOSTREAMCFG_F2B */ + uint8_t cShiftX; + /** Sample width (in bytes). */ + RT_GCC_EXTENSION + uint8_t cbSampleX : 4; + /** Number of audio channels. */ + RT_GCC_EXTENSION + uint8_t cChannelsX : 4; + /** Signed or unsigned sample. */ + bool fSigned : 1; + /** Whether the endianness is swapped or not. */ + bool fSwapEndian : 1; + /** Raw mixer frames, only applicable for signed 64-bit samples. + * The raw mixer samples are really just signed 32-bit samples stored as 64-bit + * integers without any change in the value. + * + * @todo Get rid of this, only VRDE needs it an it should use the common + * mixer code rather than cooking its own stuff. */ + bool fRaw : 1; + /** Sample frequency in Hertz (Hz). */ + uint32_t uHz; + /** PDMAUDIOCHANNELID mappings for each channel. + * This ASSUMES all channels uses the same sample size. */ + uint8_t aidChannels[PDMAUDIO_MAX_CHANNELS]; + /** Padding the structure up to 32 bytes. */ + uint32_t auPadding[3]; +} PDMAUDIOPCMPROPS; +AssertCompileSize(PDMAUDIOPCMPROPS, 32); +AssertCompileSizeAlignment(PDMAUDIOPCMPROPS, 8); +/** Pointer to audio stream properties. */ +typedef PDMAUDIOPCMPROPS *PPDMAUDIOPCMPROPS; +/** Pointer to const audio stream properties. */ +typedef PDMAUDIOPCMPROPS const *PCPDMAUDIOPCMPROPS; + +/** @name Macros for use with PDMAUDIOPCMPROPS + * @{ */ +/** Initializer for PDMAUDIOPCMPROPS. + * @note The default channel mapping here is very simple and doesn't always + * match that of PDMAudioPropsInit and PDMAudioPropsInitEx. */ +#define PDMAUDIOPCMPROPS_INITIALIZER(a_cbSample, a_fSigned, a_cChannels, a_uHz, a_fSwapEndian) \ + { \ + (uint8_t)((a_cbSample) * (a_cChannels)), PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(a_cbSample, a_cChannels), \ + (uint8_t)(a_cbSample), (uint8_t)(a_cChannels), a_fSigned, a_fSwapEndian, false /*fRaw*/, a_uHz, \ + /*aidChannels =*/ { \ + (a_cChannels) > 1 ? PDMAUDIOCHANNELID_FRONT_LEFT : PDMAUDIOCHANNELID_MONO, \ + (a_cChannels) >= 2 ? PDMAUDIOCHANNELID_FRONT_RIGHT : PDMAUDIOCHANNELID_INVALID, \ + (a_cChannels) >= 3 ? PDMAUDIOCHANNELID_FRONT_CENTER : PDMAUDIOCHANNELID_INVALID, \ + (a_cChannels) >= 4 ? PDMAUDIOCHANNELID_LFE : PDMAUDIOCHANNELID_INVALID, \ + (a_cChannels) >= 5 ? PDMAUDIOCHANNELID_REAR_LEFT : PDMAUDIOCHANNELID_INVALID, \ + (a_cChannels) >= 6 ? PDMAUDIOCHANNELID_REAR_RIGHT : PDMAUDIOCHANNELID_INVALID, \ + (a_cChannels) >= 7 ? PDMAUDIOCHANNELID_FRONT_LEFT_OF_CENTER : PDMAUDIOCHANNELID_INVALID, \ + (a_cChannels) >= 8 ? PDMAUDIOCHANNELID_FRONT_RIGHT_OF_CENTER : PDMAUDIOCHANNELID_INVALID, \ + (a_cChannels) >= 9 ? PDMAUDIOCHANNELID_REAR_CENTER : PDMAUDIOCHANNELID_INVALID, \ + (a_cChannels) >= 10 ? PDMAUDIOCHANNELID_SIDE_LEFT : PDMAUDIOCHANNELID_INVALID, \ + (a_cChannels) >= 11 ? PDMAUDIOCHANNELID_SIDE_RIGHT : PDMAUDIOCHANNELID_INVALID, \ + (a_cChannels) >= 12 ? PDMAUDIOCHANNELID_UNKNOWN : PDMAUDIOCHANNELID_INVALID, \ + }, \ + /* auPadding = */ { 0, 0, 0 } \ + } + +/** Calculates the cShift value of given sample bits and audio channels. + * @note Does only support mono/stereo channels for now, for non-stereo/mono we + * returns a special value which the two conversion functions detect + * and make them fall back on cbSample * cChannels. */ +#define PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(cbSample, cChannels) \ + ( RT_IS_POWER_OF_TWO((unsigned)((cChannels) * (cbSample))) \ + ? (uint8_t)(ASMBitFirstSetU32((unsigned)((cChannels) * (cbSample))) - 1) : (uint8_t)UINT8_MAX ) +/** Calculates the cShift value of a PDMAUDIOPCMPROPS structure. */ +#define PDMAUDIOPCMPROPS_MAKE_SHIFT(pProps) \ + PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS((pProps)->cbSampleX, (pProps)->cChannelsX) +/** Converts (audio) frames to bytes. + * @note Requires properly initialized properties, i.e. cbFrames correctly calculated + * and cShift set using PDMAUDIOPCMPROPS_MAKE_SHIFT. */ +#define PDMAUDIOPCMPROPS_F2B(pProps, cFrames) \ + ( (pProps)->cShiftX != UINT8_MAX ? (cFrames) << (pProps)->cShiftX : (cFrames) * (pProps)->cbFrame ) +/** Converts bytes to (audio) frames. + * @note Requires properly initialized properties, i.e. cbFrames correctly calculated + * and cShift set using PDMAUDIOPCMPROPS_MAKE_SHIFT. */ +#define PDMAUDIOPCMPROPS_B2F(pProps, cb) \ + ( (pProps)->cShiftX != UINT8_MAX ? (cb) >> (pProps)->cShiftX : (cb) / (pProps)->cbFrame ) +/** @} */ + +/** + * An audio stream configuration. + */ +typedef struct PDMAUDIOSTREAMCFG +{ + /** The stream's PCM properties. */ + PDMAUDIOPCMPROPS Props; + /** Direction of the stream. */ + PDMAUDIODIR enmDir; + /** Destination / source path. */ + PDMAUDIOPATH enmPath; + /** Device emulation-specific data needed for the audio connector. */ + struct + { + /** Scheduling hint set by the device emulation about when this stream is being served on average (in ms). + * Can be 0 if not hint given or some other mechanism (e.g. callbacks) is being used. */ + uint32_t cMsSchedulingHint; + } Device; + /** + * Backend-specific data for the stream. + * On input (requested configuration) those values are set by the audio connector to let the backend know what we expect. + * On output (acquired configuration) those values reflect the values set and used by the backend. + * Set by the backend on return. Not all backends support all values / features. + */ + struct + { + /** Period size of the stream (in audio frames). + * This value reflects the number of audio frames in between each hardware interrupt on the + * backend (host) side. 0 if not set / available by the backend. */ + uint32_t cFramesPeriod; + /** (Ring) buffer size (in audio frames). Often is a multiple of cFramesPeriod. + * 0 if not set / available by the backend. */ + uint32_t cFramesBufferSize; + /** Pre-buffering size (in audio frames). Frames needed in buffer before the stream becomes active (pre buffering). + * The bigger this value is, the more latency for the stream will occur. + * 0 if not set / available by the backend. UINT32_MAX if not defined (yet). */ + uint32_t cFramesPreBuffering; + } Backend; + /** Friendly name of the stream. */ + char szName[64]; +} PDMAUDIOSTREAMCFG; +AssertCompileSizeAlignment(PDMAUDIOSTREAMCFG, 8); +/** Pointer to audio stream configuration keeper. */ +typedef PDMAUDIOSTREAMCFG *PPDMAUDIOSTREAMCFG; +/** Pointer to a const audio stream configuration keeper. */ +typedef PDMAUDIOSTREAMCFG const *PCPDMAUDIOSTREAMCFG; + +/** Converts (audio) frames to bytes. */ +#define PDMAUDIOSTREAMCFG_F2B(pCfg, frames) PDMAUDIOPCMPROPS_F2B(&(pCfg)->Props, (frames)) +/** Converts bytes to (audio) frames. */ +#define PDMAUDIOSTREAMCFG_B2F(pCfg, cb) PDMAUDIOPCMPROPS_B2F(&(pCfg)->Props, (cb)) + +/** + * Audio stream commands. + * + * Used in the audio connector as well as in the actual host backends. + */ +typedef enum PDMAUDIOSTREAMCMD +{ + /** Invalid zero value as per usual (guards against using unintialized values). */ + PDMAUDIOSTREAMCMD_INVALID = 0, + /** Enables the stream. */ + PDMAUDIOSTREAMCMD_ENABLE, + /** Pauses the stream. + * This is currently only issued when the VM is suspended (paused). + * @remarks This is issued by DrvAudio, never by the mixer or devices. */ + PDMAUDIOSTREAMCMD_PAUSE, + /** Resumes the stream. + * This is currently only issued when the VM is resumed. + * @remarks This is issued by DrvAudio, never by the mixer or devices. */ + PDMAUDIOSTREAMCMD_RESUME, + /** Drain the stream, that is, play what's in the buffers and then stop. + * + * There will be no more samples written after this command is issued. + * PDMIAUDIOCONNECTOR::pfnStreamIterate will drive progress for DrvAudio and + * calls to PDMIHOSTAUDIO::pfnStreamPlay with a zero sized buffer will provide + * the backend with a way to drive it forwards. These calls will come at a + * frequency set by the device and be on an asynchronous I/O thread. + * + * A DISABLE command maybe submitted if the device/mixer wants to re-enable the + * stream while it's still draining or if it gets impatient and thinks the + * draining has been going on too long, in which case the stream should stop + * immediately. + * + * @note This should not wait for the stream to finish draining, just change + * the state. (The caller could be an EMT and it must not block for + * hundreds of milliseconds of buffer to finish draining.) + * + * @note Does not apply to input streams. Backends should refuse such requests. */ + PDMAUDIOSTREAMCMD_DRAIN, + /** Stops the stream immediately w/o any draining. */ + PDMAUDIOSTREAMCMD_DISABLE, + /** End of valid values. */ + PDMAUDIOSTREAMCMD_END, + /** Hack to blow the type up to 32-bit. */ + PDMAUDIOSTREAMCMD_32BIT_HACK = 0x7fffffff +} PDMAUDIOSTREAMCMD; + +/** + * Backend status. + */ +typedef enum PDMAUDIOBACKENDSTS +{ + /** Unknown/invalid status. */ + PDMAUDIOBACKENDSTS_UNKNOWN = 0, + /** No backend attached. */ + PDMAUDIOBACKENDSTS_NOT_ATTACHED, + /** The backend is in its initialization phase. + * Not all backends support this status. */ + PDMAUDIOBACKENDSTS_INITIALIZING, + /** The backend has stopped its operation. */ + PDMAUDIOBACKENDSTS_STOPPED, + /** The backend is up and running. */ + PDMAUDIOBACKENDSTS_RUNNING, + /** The backend ran into an error and is unable to recover. + * A manual re-initialization might help. */ + PDMAUDIOBACKENDSTS_ERROR, + /** Hack to blow the type up to 32-bit. */ + PDMAUDIOBACKENDSTS_32BIT_HACK = 0x7fffffff +} PDMAUDIOBACKENDSTS; + +/** + * PDM audio stream state. + * + * This is all the mixer/device needs. The PDMAUDIOSTREAM_STS_XXX stuff will + * become DrvAudio internal state once the backend stuff is destilled out of it. + * + * @note The value order is significant, don't change it willy-nilly. + */ +typedef enum PDMAUDIOSTREAMSTATE +{ + /** Invalid state value. */ + PDMAUDIOSTREAMSTATE_INVALID = 0, + /** The stream is not operative and cannot be enabled. */ + PDMAUDIOSTREAMSTATE_NOT_WORKING, + /** The stream needs to be re-initialized by the device/mixer + * (i.e. call PDMIAUDIOCONNECTOR::pfnStreamReInit). */ + PDMAUDIOSTREAMSTATE_NEED_REINIT, + /** The stream is inactive (not enabled). */ + PDMAUDIOSTREAMSTATE_INACTIVE, + /** The stream is enabled but nothing to read/write. + * @todo not sure if we need this variant... */ + PDMAUDIOSTREAMSTATE_ENABLED, + /** The stream is enabled and captured samples can be read. */ + PDMAUDIOSTREAMSTATE_ENABLED_READABLE, + /** The stream is enabled and samples can be written for playback. */ + PDMAUDIOSTREAMSTATE_ENABLED_WRITABLE, + /** End of valid states. */ + PDMAUDIOSTREAMSTATE_END, + /** Make sure the type is 32-bit wide. */ + PDMAUDIOSTREAMSTATE_32BIT_HACK = 0x7fffffff +} PDMAUDIOSTREAMSTATE; + +/** @name PDMAUDIOSTREAM_CREATE_F_XXX + * @{ */ +/** Does not need any mixing buffers, the device takes care of all conversion. + * @note this is now default and assumed always set. */ +#define PDMAUDIOSTREAM_CREATE_F_NO_MIXBUF RT_BIT_32(0) +/** @} */ + +/** @name PDMAUDIOSTREAM_WARN_FLAGS_XXX + * @{ */ +/** No stream warning flags set. */ +#define PDMAUDIOSTREAM_WARN_FLAGS_NONE 0 +/** Warned about a disabled stream. */ +#define PDMAUDIOSTREAM_WARN_FLAGS_DISABLED RT_BIT(0) +/** @} */ + +/** + * An input or output audio stream. + */ +typedef struct PDMAUDIOSTREAM +{ + /** Critical section protecting the stream. + * + * When not otherwise stated, DrvAudio will enter this before calling the + * backend. The backend and device/mixer can normally safely enter it prior to + * a DrvAudio call, however not to pfnStreamDestroy, pfnStreamRelease or + * anything that may access the stream list. + * + * @note Lock ordering: + * - After DRVAUDIO::CritSectGlobals. + * - Before DRVAUDIO::CritSectHotPlug. */ + RTCRITSECT CritSect; + /** Stream configuration. */ + PDMAUDIOSTREAMCFG Cfg; + /** Magic value (PDMAUDIOSTREAM_MAGIC). */ + uint32_t uMagic; + /** Size (in bytes) of the backend-specific stream data. */ + uint32_t cbBackend; + /** Warnings shown already in the release log. + * See PDMAUDIOSTREAM_WARN_FLAGS_XXX. */ + uint32_t fWarningsShown; +} PDMAUDIOSTREAM; +/** Pointer to an audio stream. */ +typedef struct PDMAUDIOSTREAM *PPDMAUDIOSTREAM; +/** Pointer to a const audio stream. */ +typedef struct PDMAUDIOSTREAM const *PCPDMAUDIOSTREAM; + +/** Magic value for PDMAUDIOSTREAM. */ +#define PDMAUDIOSTREAM_MAGIC PDM_VERSION_MAKE(0xa0d3, 5, 0) + + + +/** Pointer to a audio connector interface. */ +typedef struct PDMIAUDIOCONNECTOR *PPDMIAUDIOCONNECTOR; + +/** + * Audio connector interface (up). + */ +typedef struct PDMIAUDIOCONNECTOR +{ + /** + * Enables or disables the given audio direction for this driver. + * + * When disabled, assiociated output streams consume written audio without passing them further down to the backends. + * Associated input streams then return silence when read from those. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param enmDir Audio direction to enable or disable driver for. + * @param fEnable Whether to enable or disable the specified audio direction. + * + * @note Be very careful when using this function, as this could + * violate / run against the (global) VM settings. See @bugref{9882}. + */ + DECLR3CALLBACKMEMBER(int, pfnEnable, (PPDMIAUDIOCONNECTOR pInterface, PDMAUDIODIR enmDir, bool fEnable)); + + /** + * Returns whether the given audio direction for this driver is enabled or not. + * + * @returns True if audio is enabled for the given direction, false if not. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param enmDir Audio direction to retrieve enabled status for. + */ + DECLR3CALLBACKMEMBER(bool, pfnIsEnabled, (PPDMIAUDIOCONNECTOR pInterface, PDMAUDIODIR enmDir)); + + /** + * Retrieves the current configuration of the host audio backend. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pCfg Where to store the host audio backend configuration data. + */ + DECLR3CALLBACKMEMBER(int, pfnGetConfig, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOBACKENDCFG pCfg)); + + /** + * Retrieves the current status of the host audio backend. + * + * @returns Status of the host audio backend. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param enmDir Audio direction to check host audio backend for. Specify PDMAUDIODIR_DUPLEX for the overall + * backend status. + */ + DECLR3CALLBACKMEMBER(PDMAUDIOBACKENDSTS, pfnGetStatus, (PPDMIAUDIOCONNECTOR pInterface, PDMAUDIODIR enmDir)); + + /** + * Gives the audio drivers a hint about a typical configuration. + * + * This is a little hack for windows (and maybe other hosts) where stream + * creation can take a relatively long time, making it very unsuitable for EMT. + * The audio backend can use this hint to cache pre-configured stream setups, + * so that when the guest actually wants to play something EMT won't be blocked + * configuring host audio. + * + * @param pInterface Pointer to this interface. + * @param pCfg The typical configuration. Can be modified by the + * drivers in unspecified ways. + */ + DECLR3CALLBACKMEMBER(void, pfnStreamConfigHint, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAMCFG pCfg)); + + /** + * Creates an audio stream. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param fFlags PDMAUDIOSTREAM_CREATE_F_XXX. + * @param pCfgReq The requested stream configuration. The actual stream + * configuration can be found in pStream->Cfg on success. + * @param ppStream Pointer where to return the created audio stream on + * success. + */ + DECLR3CALLBACKMEMBER(int, pfnStreamCreate, (PPDMIAUDIOCONNECTOR pInterface, uint32_t fFlags, PCPDMAUDIOSTREAMCFG pCfgReq, + PPDMAUDIOSTREAM *ppStream)); + + + /** + * Destroys an audio stream. + * + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream. + * @param fImmediate Whether to immdiately stop and destroy a draining + * stream (@c true), or to allow it to complete + * draining first (@c false) if that's feasable. + * The latter depends on the draining stage and what + * the backend is capable of. + */ + DECLR3CALLBACKMEMBER(int, pfnStreamDestroy, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream, bool fImmediate)); + + /** + * Re-initializes the stream in response to PDMAUDIOSTREAM_STS_NEED_REINIT. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pStream The audio stream needing re-initialization. + */ + DECLR3CALLBACKMEMBER(int, pfnStreamReInit, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)); + + /** + * Adds a reference to the specified audio stream. + * + * @returns New reference count. UINT32_MAX on error. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream adding the reference to. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnStreamRetain, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)); + + /** + * Releases a reference from the specified stream. + * + * @returns New reference count. UINT32_MAX on error. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream releasing a reference from. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnStreamRelease, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)); + + /** + * Controls a specific audio stream. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream. + * @param enmStreamCmd The stream command to issue. + */ + DECLR3CALLBACKMEMBER(int, pfnStreamControl, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream, + PDMAUDIOSTREAMCMD enmStreamCmd)); + + /** + * Processes stream data. + * + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream. + */ + DECLR3CALLBACKMEMBER(int, pfnStreamIterate, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)); + + /** + * Returns the state of a specific audio stream (destilled status). + * + * @returns PDMAUDIOSTREAMSTATE value. + * @retval PDMAUDIOSTREAMSTATE_INVALID if the input isn't valid (w/ assertion). + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream. + */ + DECLR3CALLBACKMEMBER(PDMAUDIOSTREAMSTATE, pfnStreamGetState, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)); + + /** + * Returns the number of bytes that can be written to an audio output stream. + * + * @returns Number of bytes writable data. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnStreamGetWritable, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)); + + /** + * Plays (writes to) an audio output stream. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream to read from. + * @param pvBuf Audio data to be written. + * @param cbBuf Number of bytes to be written. + * @param pcbWritten Bytes of audio data written. Optional. + */ + DECLR3CALLBACKMEMBER(int, pfnStreamPlay, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream, + const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)); + + /** + * Returns the number of bytes that can be read from an input stream. + * + * @returns Number of bytes of readable data. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnStreamGetReadable, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)); + + /** + * Captures (reads) samples from an audio input stream. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream to write to. + * @param pvBuf Where to store the read data. + * @param cbBuf Number of bytes to read. + * @param pcbRead Bytes of audio data read. Optional. + */ + DECLR3CALLBACKMEMBER(int, pfnStreamCapture, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream, + void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)); +} PDMIAUDIOCONNECTOR; + +/** PDMIAUDIOCONNECTOR interface ID. */ +#define PDMIAUDIOCONNECTOR_IID "2900fe2a-6aeb-4953-ac12-f8965612f446" + + +/** + * Host audio backend specific stream data. + * + * The backend will put this as the first member of it's own data structure. + */ +typedef struct PDMAUDIOBACKENDSTREAM +{ + /** Magic value (PDMAUDIOBACKENDSTREAM_MAGIC). */ + uint32_t uMagic; + /** Explicit zero padding - do not touch! */ + uint32_t uReserved; + /** Pointer to the stream this backend data is associated with. */ + PPDMAUDIOSTREAM pStream; + /** Reserved for future use (zeroed) - do not touch. */ + void *apvReserved[2]; +} PDMAUDIOBACKENDSTREAM; +/** Pointer to host audio specific stream data! */ +typedef PDMAUDIOBACKENDSTREAM *PPDMAUDIOBACKENDSTREAM; + +/** Magic value for PDMAUDIOBACKENDSTREAM. */ +#define PDMAUDIOBACKENDSTREAM_MAGIC PDM_VERSION_MAKE(0xa0d4, 1, 0) + +/** + * Host audio (backend) stream state returned by PDMIHOSTAUDIO::pfnStreamGetState. + */ +typedef enum PDMHOSTAUDIOSTREAMSTATE +{ + /** Invalid zero value, as per usual. */ + PDMHOSTAUDIOSTREAMSTATE_INVALID = 0, + /** The stream is being initialized. + * This should also be used when switching to a new device and the stream + * stops to work with the old device while the new one being configured. */ + PDMHOSTAUDIOSTREAMSTATE_INITIALIZING, + /** The stream does not work (async init failed, audio subsystem gone + * fishing, or similar). */ + PDMHOSTAUDIOSTREAMSTATE_NOT_WORKING, + /** Backend is working okay. */ + PDMHOSTAUDIOSTREAMSTATE_OKAY, + /** Backend is working okay, but currently draining the stream. */ + PDMHOSTAUDIOSTREAMSTATE_DRAINING, + /** Backend is working but doesn't want any commands or data reads/writes. */ + PDMHOSTAUDIOSTREAMSTATE_INACTIVE, + /** End of valid values. */ + PDMHOSTAUDIOSTREAMSTATE_END, + /** Blow the type up to 32 bits. */ + PDMHOSTAUDIOSTREAMSTATE_32BIT_HACK = 0x7fffffff +} PDMHOSTAUDIOSTREAMSTATE; + + +/** Pointer to a host audio interface. */ +typedef struct PDMIHOSTAUDIO *PPDMIHOSTAUDIO; + +/** + * PDM host audio interface. + */ +typedef struct PDMIHOSTAUDIO +{ + /** + * Returns the host backend's configuration (backend). + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pBackendCfg Where to store the backend audio configuration to. + */ + DECLR3CALLBACKMEMBER(int, pfnGetConfig, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg)); + + /** + * Returns (enumerates) host audio device information (optional). + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pDeviceEnum Where to return the enumerated audio devices. + */ + DECLR3CALLBACKMEMBER(int, pfnGetDevices, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOHOSTENUM pDeviceEnum)); + + /** + * Changes the output or input device. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param enmDir The direction to set the device for: PDMAUDIODIR_IN, + * PDMAUDIODIR_OUT or PDMAUDIODIR_DUPLEX (both the + * previous). + * @param pszId The PDMAUDIOHOSTDEV::pszId value of the device to + * use, or NULL / empty string for the default device. + */ + DECLR3CALLBACKMEMBER(int, pfnSetDevice, (PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir, const char *pszId)); + + /** + * Returns the current status from the audio backend (optional). + * + * @returns PDMAUDIOBACKENDSTS enum. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param enmDir Audio direction to get status for. Pass PDMAUDIODIR_DUPLEX for overall status. + */ + DECLR3CALLBACKMEMBER(PDMAUDIOBACKENDSTS, pfnGetStatus, (PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)); + + /** + * Callback for genric on-worker-thread requests initiated by the backend itself. + * + * This is the counterpart to PDMIHOSTAUDIOPORT::pfnDoOnWorkerThread that will + * be invoked on a worker thread when the backend requests it - optional. + * + * This does not return a value, so the backend must keep track of + * failure/success on its own. + * + * This method is optional. A non-NULL will, together with pfnStreamInitAsync + * and PDMAUDIOBACKEND_F_ASYNC_HINT, force DrvAudio to create the thread pool. + * + * @param pInterface Pointer to this interface. + * @param pStream Optionally a backend stream if specified in the + * PDMIHOSTAUDIOPORT::pfnDoOnWorkerThread() call. + * @param uUser User specific value as specified in the + * PDMIHOSTAUDIOPORT::pfnDoOnWorkerThread() call. + * @param pvUser User specific pointer as specified in the + * PDMIHOSTAUDIOPORT::pfnDoOnWorkerThread() call. + */ + DECLR3CALLBACKMEMBER(void, pfnDoOnWorkerThread,(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, + uintptr_t uUser, void *pvUser)); + + /** + * Gives the audio backend a hint about a typical configuration (optional). + * + * This is a little hack for windows (and maybe other hosts) where stream + * creation can take a relatively long time, making it very unsuitable for EMT. + * The audio backend can use this hint to cache pre-configured stream setups, + * so that when the guest actually wants to play something EMT won't be blocked + * configuring host audio. + * + * The backend can return PDMAUDIOBACKEND_F_ASYNC_HINT in + * PDMIHOSTAUDIO::pfnGetConfig to avoid having EMT making this call and thereby + * speeding up VM construction. + * + * @param pInterface Pointer to this interface. + * @param pCfg The typical configuration. (Feel free to change it + * to the actual stream config that would be used, + * however caller will probably ignore this.) + */ + DECLR3CALLBACKMEMBER(void, pfnStreamConfigHint, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAMCFG pCfg)); + + /** + * Creates an audio stream using the requested stream configuration. + * + * If a backend is not able to create this configuration, it will return its + * best match in the acquired configuration structure on success. + * + * @returns VBox status code. + * @retval VINF_AUDIO_STREAM_ASYNC_INIT_NEEDED if + * PDMIHOSTAUDIO::pfnStreamInitAsync should be called. + * @param pInterface Pointer to this interface. + * @param pStream Pointer to the audio stream. + * @param pCfgReq The requested stream configuration. + * @param pCfgAcq The acquired stream configuration - output. This is + * the same as @a *pCfgReq when called, the + * implementation will adjust it to make the actual + * stream configuration as needed. + */ + DECLR3CALLBACKMEMBER(int, pfnStreamCreate, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, + PCPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)); + + /** + * Asynchronous stream initialization step, optional. + * + * This is called on a worker thread iff the PDMIHOSTAUDIO::pfnStreamCreate + * method returns VINF_AUDIO_STREAM_ASYNC_INIT_NEEDED. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pStream Pointer to audio stream to continue + * initialization of. + * @param fDestroyed Set to @c true if the stream has been destroyed + * before the worker thread got to making this + * call. The backend should just ready the stream + * for destruction in that case. + */ + DECLR3CALLBACKMEMBER(int, pfnStreamInitAsync, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, bool fDestroyed)); + + /** + * Destroys an audio stream. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface containing the called function. + * @param pStream Pointer to audio stream. + * @param fImmediate Whether to immdiately stop and destroy a draining + * stream (@c true), or to allow it to complete + * draining first (@c false) if that's feasable. + */ + DECLR3CALLBACKMEMBER(int, pfnStreamDestroy, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, bool fImmediate)); + + /** + * Called from PDMIHOSTAUDIOPORT::pfnNotifyDeviceChanged so the backend can start + * the device change for a stream. + * + * This is mainly to avoid the need for a list of streams in the backend. + * + * @param pInterface Pointer to this interface. + * @param pStream Pointer to audio stream (locked). + * @param pvUser Backend specific parameter from the call to + * PDMIHOSTAUDIOPORT::pfnNotifyDeviceChanged. + */ + DECLR3CALLBACKMEMBER(void, pfnStreamNotifyDeviceChanged,(PPDMIHOSTAUDIO pInterface, + PPDMAUDIOBACKENDSTREAM pStream, void *pvUser)); + + /** + * Enables (starts) the stream. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pStream Pointer to the audio stream to enable. + * @sa PDMAUDIOSTREAMCMD_ENABLE + */ + DECLR3CALLBACKMEMBER(int, pfnStreamEnable, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)); + + /** + * Disables (stops) the stream immediately. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pStream Pointer to the audio stream to disable. + * @sa PDMAUDIOSTREAMCMD_DISABLE + */ + DECLR3CALLBACKMEMBER(int, pfnStreamDisable, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)); + + /** + * Pauses the stream - called when the VM is suspended. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pStream Pointer to the audio stream to pause. + * @sa PDMAUDIOSTREAMCMD_PAUSE + */ + DECLR3CALLBACKMEMBER(int, pfnStreamPause, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)); + + /** + * Resumes a paused stream - called when the VM is resumed. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pStream Pointer to the audio stream to resume. + * @sa PDMAUDIOSTREAMCMD_RESUME + */ + DECLR3CALLBACKMEMBER(int, pfnStreamResume, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)); + + /** + * Drain the stream, that is, play what's in the buffers and then stop. + * + * There will be no more samples written after this command is issued. + * PDMIHOSTAUDIO::pfnStreamPlay with a zero sized buffer will provide the + * backend with a way to drive it forwards. These calls will come at a + * frequency set by the device and be on an asynchronous I/O thread. + * + * The PDMIHOSTAUDIO::pfnStreamDisable method maybe called if the device/mixer + * wants to re-enable the stream while it's still draining or if it gets + * impatient and thinks the draining has been going on too long, in which case + * the stream should stop immediately. + * + * @note This should not wait for the stream to finish draining, just change + * the state. (The caller could be an EMT and it must not block for + * hundreds of milliseconds of buffer to finish draining.) + * + * @note Does not apply to input streams. Backends should refuse such + * requests. + * + * @returns VBox status code. + * @retval VERR_WRONG_ORDER if not output stream. + * @param pInterface Pointer to this interface. + * @param pStream Pointer to the audio stream to drain. + * @sa PDMAUDIOSTREAMCMD_DRAIN + */ + DECLR3CALLBACKMEMBER(int, pfnStreamDrain, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)); + + /** + * Returns the current state of the given backend stream. + * + * @returns PDMHOSTAUDIOSTREAMSTATE value. + * @retval PDMHOSTAUDIOSTREAMSTATE_INVALID if invalid stream. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream. + */ + DECLR3CALLBACKMEMBER(PDMHOSTAUDIOSTREAMSTATE, pfnStreamGetState, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)); + + /** + * Returns the number of buffered bytes that hasn't been played yet (optional). + * + * Is not valid on an input stream, implementions shall assert and return zero. + * + * @returns Number of pending bytes. + * @param pInterface Pointer to this interface. + * @param pStream Pointer to the audio stream. + * + * @todo This is no longer not used by DrvAudio and can probably be removed. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnStreamGetPending, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)); + + /** + * Returns the amount which is writable to the audio (output) stream. + * + * @returns Number of writable bytes. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnStreamGetWritable, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)); + + /** + * Plays (writes to) an audio (output) stream. + * + * This is always called with data in the buffer, except after + * PDMAUDIOSTREAMCMD_DRAIN is issued when it's called every so often to assist + * the backend with moving the draining operation forward (kind of like + * PDMIAUDIOCONNECTOR::pfnStreamIterate). + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream. + * @param pvBuf Pointer to audio data buffer to play. This will be NULL + * when called to assist draining the stream. + * @param cbBuf The number of bytes of audio data to play. This will be + * zero when called to assist draining the stream. + * @param pcbWritten Where to return the actual number of bytes played. + */ + DECLR3CALLBACKMEMBER(int, pfnStreamPlay, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, + const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)); + + /** + * Returns the amount which is readable from the audio (input) stream. + * + * @returns For non-raw layout streams: Number of readable bytes. + * for raw layout streams : Number of readable audio frames. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnStreamGetReadable, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)); + + /** + * Captures (reads from) an audio (input) stream. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream. + * @param pvBuf Buffer where to store read audio data. + * @param cbBuf Size of the audio data buffer in bytes. + * @param pcbRead Where to return the number of bytes actually captured. + */ + DECLR3CALLBACKMEMBER(int, pfnStreamCapture, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, + void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)); +} PDMIHOSTAUDIO; + +/** PDMIHOSTAUDIO interface ID. */ +#define PDMIHOSTAUDIO_IID "c0875b91-a4f9-48be-8595-31d27048432d" + + +/** Pointer to a audio notify from host interface. */ +typedef struct PDMIHOSTAUDIOPORT *PPDMIHOSTAUDIOPORT; + +/** + * PDM host audio port interface, upwards sibling of PDMIHOSTAUDIO. + */ +typedef struct PDMIHOSTAUDIOPORT +{ + /** + * Ask DrvAudio to call PDMIHOSTAUDIO::pfnDoOnWorkerThread on a worker thread. + * + * Generic method for doing asynchronous work using the DrvAudio thread pool. + * + * This function will not wait for PDMIHOSTAUDIO::pfnDoOnWorkerThread to + * complete, but returns immediately after submitting the request to the thread + * pool. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pStream Optional backend stream structure to pass along. The + * reference count will be increased till the call + * completes to make sure the stream stays valid. + * @param uUser User specific value. + * @param pvUser User specific pointer. + */ + DECLR3CALLBACKMEMBER(int, pfnDoOnWorkerThread,(PPDMIHOSTAUDIOPORT pInterface, PPDMAUDIOBACKENDSTREAM pStream, + uintptr_t uUser, void *pvUser)); + + /** + * The device for the given direction changed. + * + * The driver above backend (DrvAudio) will call the backend back + * (PDMIHOSTAUDIO::pfnStreamNotifyDeviceChanged) for all open streams in the + * given direction. (This ASSUMES the backend uses one output device and one + * input devices for all streams.) + * + * @param pInterface Pointer to this interface. + * @param enmDir The audio direction. + * @param pvUser Backend specific parameter for + * PDMIHOSTAUDIO::pfnStreamNotifyDeviceChanged. + */ + DECLR3CALLBACKMEMBER(void, pfnNotifyDeviceChanged,(PPDMIHOSTAUDIOPORT pInterface, PDMAUDIODIR enmDir, void *pvUser)); + + /** + * Notification that the stream is about to change device in a bit. + * + * This will assume PDMAUDIOSTREAM_STS_PREPARING_SWITCH will be set when + * PDMIHOSTAUDIO::pfnStreamGetStatus is next called and change the stream state + * accordingly. + * + * @param pInterface Pointer to this interface. + * @param pStream The stream that changed device (backend variant). + */ + DECLR3CALLBACKMEMBER(void, pfnStreamNotifyPreparingDeviceSwitch,(PPDMIHOSTAUDIOPORT pInterface, + PPDMAUDIOBACKENDSTREAM pStream)); + + /** + * The stream has changed its device and left the + * PDMAUDIOSTREAM_STS_PREPARING_SWITCH state (if it entered it at all). + * + * @param pInterface Pointer to this interface. + * @param pStream The stream that changed device (backend variant). + * @param fReInit Set if a re-init is required, clear if not. + */ + DECLR3CALLBACKMEMBER(void, pfnStreamNotifyDeviceChanged,(PPDMIHOSTAUDIOPORT pInterface, + PPDMAUDIOBACKENDSTREAM pStream, bool fReInit)); + + /** + * One or more audio devices have changed in some way. + * + * The upstream driver/device should re-evaluate the devices they're using. + * + * @todo r=bird: The upstream driver/device does not know which host audio + * devices they are using. This is mainly for triggering enumeration and + * logging of the audio devices. + * + * @param pInterface Pointer to this interface. + */ + DECLR3CALLBACKMEMBER(void, pfnNotifyDevicesChanged,(PPDMIHOSTAUDIOPORT pInterface)); +} PDMIHOSTAUDIOPORT; + +/** PDMIHOSTAUDIOPORT interface ID. */ +#define PDMIHOSTAUDIOPORT_IID "92ea5169-8271-402d-99a7-9de26a52acaf" + + +/** + * Audio mixer controls. + * + * @note This isn't part of any official PDM interface as such, it's more of a + * common thing that all the devices seem to need. + */ +typedef enum PDMAUDIOMIXERCTL +{ + /** Invalid zero value as per usual (guards against using unintialized values). */ + PDMAUDIOMIXERCTL_INVALID = 0, + /** Unknown mixer control. */ + PDMAUDIOMIXERCTL_UNKNOWN, + /** Master volume. */ + PDMAUDIOMIXERCTL_VOLUME_MASTER, + /** Front. */ + PDMAUDIOMIXERCTL_FRONT, + /** Center / LFE (Subwoofer). */ + PDMAUDIOMIXERCTL_CENTER_LFE, + /** Rear. */ + PDMAUDIOMIXERCTL_REAR, + /** Line-In. */ + PDMAUDIOMIXERCTL_LINE_IN, + /** Microphone-In. */ + PDMAUDIOMIXERCTL_MIC_IN, + /** End of valid values. */ + PDMAUDIOMIXERCTL_END, + /** Hack to blow the type up to 32-bit. */ + PDMAUDIOMIXERCTL_32BIT_HACK = 0x7fffffff +} PDMAUDIOMIXERCTL; + +/** + * Audio volume parameters. + * + * @note This isn't part of any official PDM interface any more (it used to be + * used to PDMIAUDIOCONNECTOR). It's currently only used by the mixer API. + */ +typedef struct PDMAUDIOVOLUME +{ + /** Set to @c true if this stream is muted, @c false if not. */ + bool fMuted; + /** The volume for each channel. + * The values zero is the most silent one (although not quite muted), and 255 + * the loudest. */ + uint8_t auChannels[PDMAUDIO_MAX_CHANNELS]; +} PDMAUDIOVOLUME; +/** Pointer to audio volume settings. */ +typedef PDMAUDIOVOLUME *PPDMAUDIOVOLUME; +/** Pointer to const audio volume settings. */ +typedef PDMAUDIOVOLUME const *PCPDMAUDIOVOLUME; + +/** Defines the minimum volume allowed. */ +#define PDMAUDIO_VOLUME_MIN (0) +/** Defines the maximum volume allowed. */ +#define PDMAUDIO_VOLUME_MAX (255) +/** Initializator for max volume on all channels. */ +#define PDMAUDIOVOLUME_INITIALIZER_MAX \ + { /* .fMuted = */ false, \ + /* .auChannels = */ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } } + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmaudioifs_h */ + diff --git a/include/VBox/vmm/pdmaudioinline.h b/include/VBox/vmm/pdmaudioinline.h new file mode 100644 index 00000000..5d3175c0 --- /dev/null +++ b/include/VBox/vmm/pdmaudioinline.h @@ -0,0 +1,1507 @@ +/* $Id: pdmaudioinline.h $ */ +/** @file + * PDM - Audio Helpers, Inlined Code. (DEV,++) + * + * This is all inlined because it's too tedious to create a couple libraries to + * contain it all (same bad excuse as for intnetinline.h & pdmnetinline.h). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmaudioinline_h +#define VBOX_INCLUDED_vmm_pdmaudioinline_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <VBox/err.h> +#include <VBox/log.h> +#include <VBox/vmm/pdmaudioifs.h> + +#include <iprt/asm.h> +#include <iprt/asm-math.h> +#include <iprt/assert.h> +#include <iprt/mem.h> +#include <iprt/string.h> + + +/** @defgroup grp_pdm_audio_inline The PDM Audio Helper APIs + * @ingroup grp_pdm + * @{ + */ + + +/** + * Gets the name of an audio direction enum value. + * + * @returns Pointer to read-only name string on success, "bad" if passed an + * invalid enum value. + * @param enmDir The audio direction value to name. + */ +DECLINLINE(const char *) PDMAudioDirGetName(PDMAUDIODIR enmDir) +{ + switch (enmDir) + { + case PDMAUDIODIR_INVALID: return "invalid"; + case PDMAUDIODIR_UNKNOWN: return "unknown"; + case PDMAUDIODIR_IN: return "input"; + case PDMAUDIODIR_OUT: return "output"; + case PDMAUDIODIR_DUPLEX: return "duplex"; + + /* no default */ + case PDMAUDIODIR_END: + case PDMAUDIODIR_32BIT_HACK: + break; + } + AssertMsgFailedReturn(("Invalid audio direction %d\n", enmDir), "bad"); +} + +/** + * Gets the name of an audio mixer control enum value. + * + * @returns Pointer to read-only name, "bad" if invalid input. + * @param enmMixerCtl The audio mixer control value. + */ +DECLINLINE(const char *) PDMAudioMixerCtlGetName(PDMAUDIOMIXERCTL enmMixerCtl) +{ + switch (enmMixerCtl) + { + case PDMAUDIOMIXERCTL_INVALID: return "Invalid"; + case PDMAUDIOMIXERCTL_UNKNOWN: return "Unknown"; + case PDMAUDIOMIXERCTL_VOLUME_MASTER: return "Master Volume"; + case PDMAUDIOMIXERCTL_FRONT: return "Front"; + case PDMAUDIOMIXERCTL_CENTER_LFE: return "Center / LFE"; + case PDMAUDIOMIXERCTL_REAR: return "Rear"; + case PDMAUDIOMIXERCTL_LINE_IN: return "Line-In"; + case PDMAUDIOMIXERCTL_MIC_IN: return "Microphone-In"; + + /* no default */ + case PDMAUDIOMIXERCTL_END: + case PDMAUDIOMIXERCTL_32BIT_HACK: + break; + } + AssertMsgFailedReturn(("Invalid mixer control %ld\n", enmMixerCtl), "bad"); +} + +/** + * Gets the name of a path enum value. + * + * @returns Pointer to read-only name, "bad" if invalid input. + * @param enmPath The path value to name. + */ +DECLINLINE(const char *) PDMAudioPathGetName(PDMAUDIOPATH enmPath) +{ + switch (enmPath) + { + case PDMAUDIOPATH_INVALID: return "invalid"; + case PDMAUDIOPATH_UNKNOWN: return "unknown"; + + case PDMAUDIOPATH_OUT_FRONT: return "front"; + case PDMAUDIOPATH_OUT_CENTER_LFE: return "center-lfe"; + case PDMAUDIOPATH_OUT_REAR: return "rear"; + + case PDMAUDIOPATH_IN_MIC: return "mic"; + case PDMAUDIOPATH_IN_CD: return "cd"; + case PDMAUDIOPATH_IN_VIDEO: return "video-in"; + case PDMAUDIOPATH_IN_AUX: return "aux-in"; + case PDMAUDIOPATH_IN_LINE: return "line-in"; + case PDMAUDIOPATH_IN_PHONE: return "phone"; + + /* no default */ + case PDMAUDIOPATH_END: + case PDMAUDIOPATH_32BIT_HACK: + break; + } + AssertMsgFailedReturn(("Unknown enmPath=%d\n", enmPath), "bad"); +} + +/** + * Gets the name of a channel. + * + * @returns Pointer to read-only name, "bad" if invalid input. + * @param enmChannelId The channel ID to name. + */ +DECLINLINE(const char *) PDMAudioChannelIdGetName(PDMAUDIOCHANNELID enmChannelId) +{ + switch (enmChannelId) + { + case PDMAUDIOCHANNELID_INVALID: return "invalid"; + case PDMAUDIOCHANNELID_UNUSED_ZERO: return "unused-zero"; + case PDMAUDIOCHANNELID_UNUSED_SILENCE: return "unused-silence"; + case PDMAUDIOCHANNELID_UNKNOWN: return "unknown"; + + case PDMAUDIOCHANNELID_FRONT_LEFT: return "FL"; + case PDMAUDIOCHANNELID_FRONT_RIGHT: return "FR"; + case PDMAUDIOCHANNELID_FRONT_CENTER: return "FC"; + case PDMAUDIOCHANNELID_LFE: return "LFE"; + case PDMAUDIOCHANNELID_REAR_LEFT: return "BL"; + case PDMAUDIOCHANNELID_REAR_RIGHT: return "BR"; + case PDMAUDIOCHANNELID_FRONT_LEFT_OF_CENTER: return "FLC"; + case PDMAUDIOCHANNELID_FRONT_RIGHT_OF_CENTER: return "FRC"; + case PDMAUDIOCHANNELID_REAR_CENTER: return "BC"; + case PDMAUDIOCHANNELID_SIDE_LEFT: return "SL"; + case PDMAUDIOCHANNELID_SIDE_RIGHT: return "SR"; + case PDMAUDIOCHANNELID_TOP_CENTER: return "TC"; + case PDMAUDIOCHANNELID_FRONT_LEFT_HEIGHT: return "TFL"; + case PDMAUDIOCHANNELID_FRONT_CENTER_HEIGHT: return "TFC"; + case PDMAUDIOCHANNELID_FRONT_RIGHT_HEIGHT: return "TFR"; + case PDMAUDIOCHANNELID_REAR_LEFT_HEIGHT: return "TBL"; + case PDMAUDIOCHANNELID_REAR_CENTER_HEIGHT: return "TBC"; + case PDMAUDIOCHANNELID_REAR_RIGHT_HEIGHT: return "TBR"; + + /* no default */ + case PDMAUDIOCHANNELID_END: + case PDMAUDIOCHANNELID_32BIT_HACK: + break; + } + AssertMsgFailedReturn(("Unknown enmChannelId=%d\n", enmChannelId), "bad"); +} + + +/********************************************************************************************************************************* +* Volume Helpers * +*********************************************************************************************************************************/ + +/** + * Initializes a PDMAUDIOVOLUME structure to max. + * + * @param pVol The structure to initialize. + */ +DECLINLINE(void) PDMAudioVolumeInitMax(PPDMAUDIOVOLUME pVol) +{ + pVol->fMuted = false; + for (uintptr_t i = 0; i < RT_ELEMENTS(pVol->auChannels); i++) + pVol->auChannels[i] = PDMAUDIO_VOLUME_MAX; +} + + +/** + * Initializes a PDMAUDIOVOLUME structure from a simple stereo setting. + * + * The additional channels will simply be assigned the higer of the two. + * + * @param pVol The structure to initialize. + * @param fMuted Muted. + * @param bLeft The left channel volume. + * @param bRight The right channel volume. + */ +DECLINLINE(void) PDMAudioVolumeInitFromStereo(PPDMAUDIOVOLUME pVol, bool fMuted, uint8_t bLeft, uint8_t bRight) +{ + pVol->fMuted = fMuted; + pVol->auChannels[0] = bLeft; + pVol->auChannels[1] = bRight; + + uint8_t const bOther = RT_MAX(bLeft, bRight); + for (uintptr_t i = 2; i < RT_ELEMENTS(pVol->auChannels); i++) + pVol->auChannels[i] = bOther; +} + + +/** + * Combines two volume settings (typically master and sink). + * + * @param pVol Where to return the combined volume + * @param pVol1 The first volume settings to combine. + * @param pVol2 The second volume settings. + */ +DECLINLINE(void) PDMAudioVolumeCombine(PPDMAUDIOVOLUME pVol, PCPDMAUDIOVOLUME pVol1, PCPDMAUDIOVOLUME pVol2) +{ + if (pVol1->fMuted || pVol2->fMuted) + { + pVol->fMuted = true; + for (uintptr_t i = 0; i < RT_ELEMENTS(pVol->auChannels); i++) + pVol->auChannels[i] = 0; + } + else + { + pVol->fMuted = false; + /** @todo Very crude implementation for now -- needs more work! (At least + * when used in audioMixerSinkUpdateVolume it was considered as such.) */ + for (uintptr_t i = 0; i < RT_ELEMENTS(pVol->auChannels); i++) + { +#if 0 /* bird: I think the shift variant should produce the exact same result, w/o two conditionals per iteration. */ + /* 255 * 255 / 255 = 0xFF (255) */ + /* 17 * 127 / 255 = 8 */ + /* 39 * 39 / 255 = 5 */ + pVol->auChannels[i] = (uint8_t)( (RT_MAX(pVol1->auChannels[i], 1U) * RT_MAX(pVol2->auChannels[i], 1U)) + / PDMAUDIO_VOLUME_MAX); +#else + /* (((255 + 1) * (255 + 1)) >> 8) - 1 = 0xFF (255) */ + /* ((( 17 + 1) * (127 + 1)) >> 8) - 1 = 0x8 (8) */ + /* ((( 39 + 1) * ( 39 + 1)) >> 8) - 1 = 0x5 (5) */ + pVol->auChannels[i] = (uint8_t)((((1U + pVol1->auChannels[i]) * (1U + pVol2->auChannels[i])) >> 8) - 1U); +#endif + } + } +} + + +/********************************************************************************************************************************* +* PCM Property Helpers * +*********************************************************************************************************************************/ + +/** + * Assigns default channel IDs according to the channel count. + * + * The assignments are taken from the standard speaker channel layouts table + * in the wikipedia article on surround sound: + * https://en.wikipedia.org/wiki/Surround_sound#Standard_speaker_channels + */ +DECLINLINE(void) PDMAudioPropsSetDefaultChannelIds(PPDMAUDIOPCMPROPS pProps) +{ + unsigned cChannels = pProps->cChannelsX; + switch (cChannels) + { + case 1: + pProps->aidChannels[0] = PDMAUDIOCHANNELID_MONO; + break; + case 2: + pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT; + pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT; + break; + case 3: /* 2.1 */ + pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT; + pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT; + pProps->aidChannels[2] = PDMAUDIOCHANNELID_LFE; + break; + case 4: /* 4.0 */ + pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT; + pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT; + pProps->aidChannels[2] = PDMAUDIOCHANNELID_REAR_LEFT; + pProps->aidChannels[3] = PDMAUDIOCHANNELID_REAR_RIGHT; + break; + case 5: /* 4.1 */ + pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT; + pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT; + pProps->aidChannels[2] = PDMAUDIOCHANNELID_FRONT_CENTER; + pProps->aidChannels[3] = PDMAUDIOCHANNELID_LFE; + pProps->aidChannels[4] = PDMAUDIOCHANNELID_REAR_CENTER; + break; + case 6: /* 5.1 */ + pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT; + pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT; + pProps->aidChannels[2] = PDMAUDIOCHANNELID_FRONT_CENTER; + pProps->aidChannels[3] = PDMAUDIOCHANNELID_LFE; + pProps->aidChannels[4] = PDMAUDIOCHANNELID_REAR_LEFT; + pProps->aidChannels[5] = PDMAUDIOCHANNELID_REAR_RIGHT; + break; + case 7: /* 6.1 */ + pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT; + pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT; + pProps->aidChannels[2] = PDMAUDIOCHANNELID_FRONT_CENTER; + pProps->aidChannels[3] = PDMAUDIOCHANNELID_LFE; + pProps->aidChannels[4] = PDMAUDIOCHANNELID_REAR_LEFT; + pProps->aidChannels[5] = PDMAUDIOCHANNELID_REAR_RIGHT; + pProps->aidChannels[6] = PDMAUDIOCHANNELID_REAR_CENTER; + break; + case 8: /* 7.1 */ + pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT; + pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT; + pProps->aidChannels[2] = PDMAUDIOCHANNELID_FRONT_CENTER; + pProps->aidChannels[3] = PDMAUDIOCHANNELID_LFE; + pProps->aidChannels[4] = PDMAUDIOCHANNELID_REAR_LEFT; + pProps->aidChannels[5] = PDMAUDIOCHANNELID_REAR_RIGHT; + pProps->aidChannels[6] = PDMAUDIOCHANNELID_FRONT_LEFT_OF_CENTER; + pProps->aidChannels[7] = PDMAUDIOCHANNELID_FRONT_RIGHT_OF_CENTER; + break; + case 9: /* 9.0 */ + pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT; + pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT; + pProps->aidChannels[2] = PDMAUDIOCHANNELID_FRONT_CENTER; + pProps->aidChannels[3] = PDMAUDIOCHANNELID_REAR_LEFT; + pProps->aidChannels[4] = PDMAUDIOCHANNELID_REAR_RIGHT; + pProps->aidChannels[5] = PDMAUDIOCHANNELID_SIDE_LEFT; + pProps->aidChannels[6] = PDMAUDIOCHANNELID_SIDE_RIGHT; + pProps->aidChannels[7] = PDMAUDIOCHANNELID_FRONT_LEFT_HEIGHT; + pProps->aidChannels[8] = PDMAUDIOCHANNELID_FRONT_RIGHT_HEIGHT; + break; + case 10: /* 9.1 */ + pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT; + pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT; + pProps->aidChannels[2] = PDMAUDIOCHANNELID_FRONT_CENTER; + pProps->aidChannels[3] = PDMAUDIOCHANNELID_LFE; + pProps->aidChannels[4] = PDMAUDIOCHANNELID_REAR_LEFT; + pProps->aidChannels[5] = PDMAUDIOCHANNELID_REAR_RIGHT; + pProps->aidChannels[6] = PDMAUDIOCHANNELID_SIDE_LEFT; + pProps->aidChannels[7] = PDMAUDIOCHANNELID_SIDE_RIGHT; + pProps->aidChannels[8] = PDMAUDIOCHANNELID_FRONT_LEFT_HEIGHT; + pProps->aidChannels[9] = PDMAUDIOCHANNELID_FRONT_RIGHT_HEIGHT; + break; + case 11: /* 11.0 */ + pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT; + pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT; + pProps->aidChannels[2] = PDMAUDIOCHANNELID_FRONT_CENTER; + pProps->aidChannels[3] = PDMAUDIOCHANNELID_REAR_LEFT; + pProps->aidChannels[4] = PDMAUDIOCHANNELID_REAR_RIGHT; + pProps->aidChannels[5] = PDMAUDIOCHANNELID_FRONT_LEFT_OF_CENTER; + pProps->aidChannels[6] = PDMAUDIOCHANNELID_FRONT_RIGHT_OF_CENTER; + pProps->aidChannels[7] = PDMAUDIOCHANNELID_SIDE_LEFT; + pProps->aidChannels[8] = PDMAUDIOCHANNELID_SIDE_RIGHT; + pProps->aidChannels[9] = PDMAUDIOCHANNELID_FRONT_LEFT_HEIGHT; + pProps->aidChannels[10]= PDMAUDIOCHANNELID_FRONT_RIGHT_HEIGHT; + break; + default: + AssertFailed(); + cChannels = 12; + RT_FALL_THROUGH(); + case 12: /* 11.1 */ + pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT; + pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT; + pProps->aidChannels[2] = PDMAUDIOCHANNELID_FRONT_CENTER; + pProps->aidChannels[3] = PDMAUDIOCHANNELID_LFE; + pProps->aidChannels[4] = PDMAUDIOCHANNELID_REAR_LEFT; + pProps->aidChannels[5] = PDMAUDIOCHANNELID_REAR_RIGHT; + pProps->aidChannels[6] = PDMAUDIOCHANNELID_FRONT_LEFT_OF_CENTER; + pProps->aidChannels[7] = PDMAUDIOCHANNELID_FRONT_RIGHT_OF_CENTER; + pProps->aidChannels[8] = PDMAUDIOCHANNELID_SIDE_LEFT; + pProps->aidChannels[9] = PDMAUDIOCHANNELID_SIDE_RIGHT; + pProps->aidChannels[10]= PDMAUDIOCHANNELID_FRONT_LEFT_HEIGHT; + pProps->aidChannels[11]= PDMAUDIOCHANNELID_FRONT_RIGHT_HEIGHT; + break; + case 0: + break; + } + AssertCompile(RT_ELEMENTS(pProps->aidChannels) >= 12); + + while (cChannels < RT_ELEMENTS(pProps->aidChannels)) + pProps->aidChannels[cChannels++] = PDMAUDIOCHANNELID_INVALID; +} + + +/** + * Initialize PCM audio properties. + */ +DECLINLINE(void) PDMAudioPropsInit(PPDMAUDIOPCMPROPS pProps, uint8_t cbSample, bool fSigned, uint8_t cChannels, uint32_t uHz) +{ + pProps->cbFrame = cbSample * cChannels; + pProps->cbSampleX = cbSample; + pProps->cChannelsX = cChannels; + pProps->cShiftX = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(cbSample, cChannels); + pProps->fSigned = fSigned; + pProps->fSwapEndian = false; + pProps->fRaw = false; + pProps->uHz = uHz; + + Assert(pProps->cbFrame == (uint32_t)cbSample * cChannels); + Assert(pProps->cbSampleX == cbSample); + Assert(pProps->cChannelsX == cChannels); + + PDMAudioPropsSetDefaultChannelIds(pProps); +} + +/** + * Initialize PCM audio properties, extended version. + */ +DECLINLINE(void) PDMAudioPropsInitEx(PPDMAUDIOPCMPROPS pProps, uint8_t cbSample, bool fSigned, uint8_t cChannels, uint32_t uHz, + bool fLittleEndian, bool fRaw) +{ + Assert(!fRaw || cbSample == sizeof(int64_t)); + pProps->cbFrame = cbSample * cChannels; + pProps->cbSampleX = cbSample; + pProps->cChannelsX = cChannels; + pProps->cShiftX = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(cbSample, cChannels); + pProps->fSigned = fSigned; +#ifdef RT_LITTLE_ENDIAN + pProps->fSwapEndian = !fLittleEndian; +#else + pProps->fSwapEndian = fLittleEndian; +#endif + pProps->fRaw = fRaw; + pProps->uHz = uHz; + + Assert(pProps->cbFrame == (uint32_t)cbSample * cChannels); + Assert(pProps->cbSampleX == cbSample); + Assert(pProps->cChannelsX == cChannels); + + PDMAudioPropsSetDefaultChannelIds(pProps); +} + +/** + * Modifies the channel count. + * + * @note This will reset the channel IDs to defaults. + * + * @param pProps The PCM properties to update. + * @param cChannels The new channel count. + */ +DECLINLINE(void) PDMAudioPropsSetChannels(PPDMAUDIOPCMPROPS pProps, uint8_t cChannels) +{ + Assert(cChannels > 0); Assert(cChannels < 16); + pProps->cChannelsX = cChannels; + pProps->cbFrame = pProps->cbSampleX * cChannels; + pProps->cShiftX = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(pProps->cbSampleX, cChannels); + + PDMAudioPropsSetDefaultChannelIds(pProps); +} + +/** + * Modifies the sample size. + * + * @param pProps The PCM properties to update. + * @param cbSample The new sample size (in bytes). + */ +DECLINLINE(void) PDMAudioPropsSetSampleSize(PPDMAUDIOPCMPROPS pProps, uint8_t cbSample) +{ + Assert(cbSample == 1 || cbSample == 2 || cbSample == 4 || cbSample == 8); + pProps->cbSampleX = cbSample; + pProps->cbFrame = cbSample * pProps->cChannelsX; + pProps->cShiftX = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(cbSample, pProps->cChannelsX); +} + +/** + * Gets the bitrate. + * + * Divide the result by 8 to get the byte rate. + * + * @returns Bit rate. + * @param pProps PCM properties to calculate bitrate for. + */ +DECLINLINE(uint32_t) PDMAudioPropsGetBitrate(PCPDMAUDIOPCMPROPS pProps) +{ + Assert(pProps->cbFrame == pProps->cbSampleX * pProps->cChannelsX); + return pProps->cbFrame * pProps->uHz * 8; +} + +/** + * Gets the number of channels. + * @returns The channel count. + * @param pProps The PCM properties. + */ +DECL_FORCE_INLINE(uint8_t) PDMAudioPropsChannels(PCPDMAUDIOPCMPROPS pProps) +{ + return pProps->cChannelsX; +} + +/** + * Gets the sample size in bytes. + * @returns Number of bytes per sample. + * @param pProps The PCM properties. + */ +DECL_FORCE_INLINE(uint8_t) PDMAudioPropsSampleSize(PCPDMAUDIOPCMPROPS pProps) +{ + return pProps->cbSampleX; +} + +/** + * Gets the sample size in bits. + * @returns Number of bits per sample. + * @param pProps The PCM properties. + */ +DECLINLINE(uint8_t) PDMAudioPropsSampleBits(PCPDMAUDIOPCMPROPS pProps) +{ + return pProps->cbSampleX * 8; +} + +/** + * Gets the frame size in bytes. + * @returns Number of bytes per frame. + * @param pProps The PCM properties. + */ +DECL_FORCE_INLINE(uint8_t) PDMAudioPropsFrameSize(PCPDMAUDIOPCMPROPS pProps) +{ + return pProps->cbFrame; +} + +/** + * Gets the frequency. + * @returns Frequency. + * @param pProps The PCM properties. + */ +DECL_FORCE_INLINE(uint32_t) PDMAudioPropsHz(PCPDMAUDIOPCMPROPS pProps) +{ + return pProps->uHz; +} + +/** + * Checks if the format is signed or unsigned. + * @returns true if signed, false if unsigned. + * @param pProps The PCM properties. + */ +DECL_FORCE_INLINE(bool) PDMAudioPropsIsSigned(PCPDMAUDIOPCMPROPS pProps) +{ + return pProps->fSigned; +} + +/** + * Checks if the format is little-endian or not. + * @returns true if little-endian (or if 8-bit), false if big-endian. + * @param pProps The PCM properties. + */ +DECL_FORCE_INLINE(bool) PDMAudioPropsIsLittleEndian(PCPDMAUDIOPCMPROPS pProps) +{ +#ifdef RT_LITTLE_ENDIAN + return !pProps->fSwapEndian || pProps->cbSampleX < 2; +#else + return pProps->fSwapEndian || pProps->cbSampleX < 2; +#endif +} + +/** + * Checks if the format is big-endian or not. + * @returns true if big-endian (or if 8-bit), false if little-endian. + * @param pProps The PCM properties. + */ +DECL_FORCE_INLINE(bool) PDMAudioPropsIsBigEndian(PCPDMAUDIOPCMPROPS pProps) +{ +#ifdef RT_LITTLE_ENDIAN + return pProps->fSwapEndian || pProps->cbSampleX < 2; +#else + return !pProps->fSwapEndian || pProps->cbSampleX < 2; +#endif +} + +/** + * Rounds down the given byte amount to the nearest frame boundrary. + * + * @returns Rounded byte amount. + * @param pProps PCM properties to use. + * @param cb The size (in bytes) to round. + */ +DECLINLINE(uint32_t) PDMAudioPropsFloorBytesToFrame(PCPDMAUDIOPCMPROPS pProps, uint32_t cb) +{ + AssertPtrReturn(pProps, 0); + return PDMAUDIOPCMPROPS_F2B(pProps, PDMAUDIOPCMPROPS_B2F(pProps, cb)); +} + +/** + * Rounds up the given byte amount to the nearest frame boundrary. + * + * @returns Rounded byte amount. + * @param pProps PCM properties to use. + * @param cb The size (in bytes) to round. + */ +DECLINLINE(uint32_t) PDMAudioPropsRoundUpBytesToFrame(PCPDMAUDIOPCMPROPS pProps, uint32_t cb) +{ + AssertPtrReturn(pProps, 0); + uint32_t const cbFrame = PDMAudioPropsFrameSize(pProps); + AssertReturn(cbFrame, 0); + return PDMAUDIOPCMPROPS_F2B(pProps, PDMAUDIOPCMPROPS_B2F(pProps, cb + cbFrame - 1)); +} + +/** + * Checks if the given size is aligned on a frame boundrary. + * + * @returns @c true if properly aligned, @c false if not. + * @param pProps PCM properties to use. + * @param cb The size (in bytes) to check. + */ +DECLINLINE(bool) PDMAudioPropsIsSizeAligned(PCPDMAUDIOPCMPROPS pProps, uint32_t cb) +{ + AssertPtrReturn(pProps, false); + uint32_t const cbFrame = PDMAudioPropsFrameSize(pProps); + AssertReturn(cbFrame, false); + return cb % cbFrame == 0; +} + +/** + * Converts bytes to frames (rounding down of course). + * + * @returns Number of frames. + * @param pProps PCM properties to use. + * @param cb The number of bytes to convert. + */ +DECLINLINE(uint32_t) PDMAudioPropsBytesToFrames(PCPDMAUDIOPCMPROPS pProps, uint32_t cb) +{ + AssertPtrReturn(pProps, 0); + return PDMAUDIOPCMPROPS_B2F(pProps, cb); +} + +/** + * Converts bytes to milliseconds. + * + * @return Number milliseconds @a cb takes to play or record. + * @param pProps PCM properties to use. + * @param cb The number of bytes to convert. + * + * @note Rounds up the result. + */ +DECLINLINE(uint64_t) PDMAudioPropsBytesToMilli(PCPDMAUDIOPCMPROPS pProps, uint32_t cb) +{ + AssertPtrReturn(pProps, 0); + + /* Check parameters to prevent division by chainsaw: */ + uint32_t const uHz = pProps->uHz; + if (uHz) + { + const unsigned cbFrame = PDMAudioPropsFrameSize(pProps); + if (cbFrame) + { + /* Round cb up to closest frame size: */ + cb = (cb + cbFrame - 1) / cbFrame; + + /* Convert to milliseconds. */ + return (cb * (uint64_t)RT_MS_1SEC + uHz - 1) / uHz; + } + } + return 0; +} + +/** + * Converts bytes to microseconds. + * + * @return Number microseconds @a cb takes to play or record. + * @param pProps PCM properties to use. + * @param cb The number of bytes to convert. + * + * @note Rounds up the result. + */ +DECLINLINE(uint64_t) PDMAudioPropsBytesToMicro(PCPDMAUDIOPCMPROPS pProps, uint32_t cb) +{ + AssertPtrReturn(pProps, 0); + + /* Check parameters to prevent division by chainsaw: */ + uint32_t const uHz = pProps->uHz; + if (uHz) + { + const unsigned cbFrame = PDMAudioPropsFrameSize(pProps); + if (cbFrame) + { + /* Round cb up to closest frame size: */ + cb = (cb + cbFrame - 1) / cbFrame; + + /* Convert to microseconds. */ + return (cb * (uint64_t)RT_US_1SEC + uHz - 1) / uHz; + } + } + return 0; +} + +/** + * Converts bytes to nanoseconds. + * + * @return Number nanoseconds @a cb takes to play or record. + * @param pProps PCM properties to use. + * @param cb The number of bytes to convert. + * + * @note Rounds up the result. + */ +DECLINLINE(uint64_t) PDMAudioPropsBytesToNano(PCPDMAUDIOPCMPROPS pProps, uint32_t cb) +{ + AssertPtrReturn(pProps, 0); + + /* Check parameters to prevent division by chainsaw: */ + uint32_t const uHz = pProps->uHz; + if (uHz) + { + const unsigned cbFrame = PDMAudioPropsFrameSize(pProps); + if (cbFrame) + { + /* Round cb up to closest frame size: */ + cb = (cb + cbFrame - 1) / cbFrame; + + /* Convert to nanoseconds. */ + return (cb * (uint64_t)RT_NS_1SEC + uHz - 1) / uHz; + } + } + return 0; +} + +/** + * Converts bytes to nanoseconds, 64-bit version. + * + * @return Number nanoseconds @a cb takes to play or record. + * @param pProps PCM properties to use. + * @param cb The number of bytes to convert (64-bit). + * + * @note Rounds up the result. + */ +DECLINLINE(uint64_t) PDMAudioPropsBytesToNano64(PCPDMAUDIOPCMPROPS pProps, uint64_t cb) +{ + AssertPtrReturn(pProps, 0); + + /* Check parameters to prevent division by chainsaw: */ + uint32_t const uHz = pProps->uHz; + if (uHz) + { + const unsigned cbFrame = PDMAudioPropsFrameSize(pProps); + if (cbFrame) + { + /* Round cb up to closest frame size: */ + cb = (cb + cbFrame - 1) / cbFrame; + + /* Convert to nanoseconds. */ + return (cb * RT_NS_1SEC + uHz - 1) / uHz; + } + } + return 0; +} + +/** + * Converts frames to bytes. + * + * @returns Number of bytes. + * @param pProps The PCM properties to use. + * @param cFrames Number of audio frames to convert. + * @sa PDMAUDIOPCMPROPS_F2B + */ +DECLINLINE(uint32_t) PDMAudioPropsFramesToBytes(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames) +{ + AssertPtrReturn(pProps, 0); + return PDMAUDIOPCMPROPS_F2B(pProps, cFrames); +} + +/** + * Converts frames to milliseconds. + * + * @returns milliseconds. + * @param pProps The PCM properties to use. + * @param cFrames Number of audio frames to convert. + * @note No rounding here, result is floored. + */ +DECLINLINE(uint64_t) PDMAudioPropsFramesToMilli(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames) +{ + AssertPtrReturn(pProps, 0); + + /* Check input to prevent division by chainsaw: */ + uint32_t const uHz = pProps->uHz; + if (uHz) + return ASMMultU32ByU32DivByU32(cFrames, RT_MS_1SEC, uHz); + return 0; +} + +/** + * Converts frames to milliseconds, but not returning more than @a cMsMax + * + * This is a convenience for logging and such. + * + * @returns milliseconds (32-bit). + * @param pProps The PCM properties to use. + * @param cFrames Number of audio frames to convert. + * @param cMsMax Max return value (32-bit). + * @note No rounding here, result is floored. + */ +DECLINLINE(uint32_t) PDMAudioPropsFramesToMilliMax(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames, uint32_t cMsMax) +{ + AssertPtrReturn(pProps, 0); + + /* Check input to prevent division by chainsaw: */ + uint32_t const uHz = pProps->uHz; + if (uHz) + { + uint32_t const cMsResult = ASMMultU32ByU32DivByU32(cFrames, RT_MS_1SEC, uHz); + return RT_MIN(cMsResult, cMsMax); + } + return 0; +} + +/** + * Converts frames to microseconds. + * + * @returns microseconds. + * @param pProps The PCM properties to use. + * @param cFrames Number of audio frames to convert. + * @note No rounding here, result is floored. + */ +DECLINLINE(uint64_t) PDMAudioPropsFramesToMicro(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames) +{ + AssertPtrReturn(pProps, 0); + + /* Check input to prevent division by chainsaw: */ + uint32_t const uHz = pProps->uHz; + if (uHz) + return ASMMultU32ByU32DivByU32(cFrames, RT_US_1SEC, uHz); + return 0; +} + +/** + * Converts frames to nanoseconds. + * + * @returns Nanoseconds. + * @param pProps The PCM properties to use. + * @param cFrames Number of audio frames to convert. + * @note No rounding here, result is floored. + */ +DECLINLINE(uint64_t) PDMAudioPropsFramesToNano(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames) +{ + AssertPtrReturn(pProps, 0); + + /* Check input to prevent division by chainsaw: */ + uint32_t const uHz = pProps->uHz; + if (uHz) + return ASMMultU32ByU32DivByU32(cFrames, RT_NS_1SEC, uHz); + return 0; +} + +/** + * Converts frames to NT ticks (100 ns units). + * + * @returns NT ticks. + * @param pProps The PCM properties to use. + * @param cFrames Number of audio frames to convert. + * @note No rounding here, result is floored. + */ +DECLINLINE(uint64_t) PDMAudioPropsFramesToNtTicks(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames) +{ + AssertPtrReturn(pProps, 0); + + /* Check input to prevent division by chainsaw: */ + uint32_t const uHz = pProps->uHz; + if (uHz) + return ASMMultU32ByU32DivByU32(cFrames, RT_NS_1SEC / 100, uHz); + return 0; +} + +/** + * Converts milliseconds to frames. + * + * @returns Number of frames + * @param pProps The PCM properties to use. + * @param cMs The number of milliseconds to convert. + * + * @note The result is rounded rather than floored (hysterical raisins). + */ +DECLINLINE(uint32_t) PDMAudioPropsMilliToFrames(PCPDMAUDIOPCMPROPS pProps, uint64_t cMs) +{ + AssertPtrReturn(pProps, 0); + + uint32_t const uHz = pProps->uHz; + uint32_t cFrames; + if (cMs < RT_MS_1SEC) + cFrames = 0; + else + { + cFrames = cMs / RT_MS_1SEC * uHz; + cMs %= RT_MS_1SEC; + } + cFrames += (ASMMult2xU32RetU64(uHz, (uint32_t)cMs) + RT_MS_1SEC - 1) / RT_MS_1SEC; + return cFrames; +} + +/** + * Converts milliseconds to bytes. + * + * @returns Number of bytes (frame aligned). + * @param pProps The PCM properties to use. + * @param cMs The number of milliseconds to convert. + * + * @note The result is rounded rather than floored (hysterical raisins). + */ +DECLINLINE(uint32_t) PDMAudioPropsMilliToBytes(PCPDMAUDIOPCMPROPS pProps, uint64_t cMs) +{ + return PDMAUDIOPCMPROPS_F2B(pProps, PDMAudioPropsMilliToFrames(pProps, cMs)); +} + +/** + * Converts nanoseconds to frames. + * + * @returns Number of frames. + * @param pProps The PCM properties to use. + * @param cNs The number of nanoseconds to convert. + * + * @note The result is rounded rather than floored (hysterical raisins). + */ +DECLINLINE(uint32_t) PDMAudioPropsNanoToFrames(PCPDMAUDIOPCMPROPS pProps, uint64_t cNs) +{ + AssertPtrReturn(pProps, 0); + + uint32_t const uHz = pProps->uHz; + uint32_t cFrames; + if (cNs < RT_NS_1SEC) + cFrames = 0; + else + { + cFrames = cNs / RT_NS_1SEC * uHz; + cNs %= RT_NS_1SEC; + } + cFrames += (ASMMult2xU32RetU64(uHz, (uint32_t)cNs) + RT_NS_1SEC - 1) / RT_NS_1SEC; + return cFrames; +} + +/** + * Converts nanoseconds to frames, 64-bit return. + * + * @returns Number of frames (64-bit). + * @param pProps The PCM properties to use. + * @param cNs The number of nanoseconds to convert. + * + * @note The result is floored! + */ +DECLINLINE(uint64_t) PDMAudioPropsNanoToFrames64(PCPDMAUDIOPCMPROPS pProps, uint64_t cNs) +{ + AssertPtrReturn(pProps, 0); + + uint32_t const uHz = pProps->uHz; + uint64_t cFrames; + if (cNs < RT_NS_1SEC) + cFrames = 0; + else + { + cFrames = cNs / RT_NS_1SEC * uHz; + cNs %= RT_NS_1SEC; + } + cFrames += ASMMult2xU32RetU64(uHz, (uint32_t)cNs) / RT_NS_1SEC; + return cFrames; +} + +/** + * Converts nanoseconds to bytes. + * + * @returns Number of bytes (frame aligned). + * @param pProps The PCM properties to use. + * @param cNs The number of nanoseconds to convert. + * + * @note The result is rounded rather than floored (hysterical raisins). + */ +DECLINLINE(uint32_t) PDMAudioPropsNanoToBytes(PCPDMAUDIOPCMPROPS pProps, uint64_t cNs) +{ + return PDMAUDIOPCMPROPS_F2B(pProps, PDMAudioPropsNanoToFrames(pProps, cNs)); +} + +/** + * Converts nanoseconds to bytes, 64-bit version. + * + * @returns Number of bytes (frame aligned), 64-bit. + * @param pProps The PCM properties to use. + * @param cNs The number of nanoseconds to convert. + * + * @note The result is floored. + */ +DECLINLINE(uint64_t) PDMAudioPropsNanoToBytes64(PCPDMAUDIOPCMPROPS pProps, uint64_t cNs) +{ + return PDMAUDIOPCMPROPS_F2B(pProps, PDMAudioPropsNanoToFrames(pProps, cNs)); +} + +/** + * Clears a sample buffer by the given amount of audio frames with silence (according to the format + * given by the PCM properties). + * + * @param pProps The PCM properties to apply. + * @param pvBuf The buffer to clear. + * @param cbBuf The buffer size in bytes. + * @param cFrames The number of audio frames to clear. Capped at @a cbBuf + * if exceeding the buffer. If the size is an unaligned + * number of frames, the extra bytes may be left + * uninitialized in some configurations. + */ +DECLINLINE(void) PDMAudioPropsClearBuffer(PCPDMAUDIOPCMPROPS pProps, void *pvBuf, size_t cbBuf, uint32_t cFrames) +{ + /* + * Validate input + */ + AssertPtrReturnVoid(pProps); + Assert(pProps->cbSampleX); + if (!cbBuf || !cFrames) + return; + AssertPtrReturnVoid(pvBuf); + + /* + * Decide how much needs clearing. + */ + size_t cbToClear = PDMAudioPropsFramesToBytes(pProps, cFrames); + AssertStmt(cbToClear <= cbBuf, cbToClear = cbBuf); + + Log2Func(("pProps=%p, pvBuf=%p, cFrames=%RU32, fSigned=%RTbool, cbSample=%RU8\n", + pProps, pvBuf, cFrames, pProps->fSigned, pProps->cbSampleX)); + + /* + * Do the job. + */ + if (pProps->fSigned) + RT_BZERO(pvBuf, cbToClear); + else /* Unsigned formats. */ + { + switch (pProps->cbSampleX) + { + case 1: /* 8 bit */ + memset(pvBuf, 0x80, cbToClear); + break; + + case 2: /* 16 bit */ + { + uint16_t *pu16Dst = (uint16_t *)pvBuf; + uint16_t const u16Offset = !pProps->fSwapEndian ? UINT16_C(0x8000) : UINT16_C(0x80); + cbBuf /= sizeof(*pu16Dst); + while (cbBuf-- > 0) + *pu16Dst++ = u16Offset; + break; + } + + case 4: /* 32 bit */ + ASMMemFill32(pvBuf, cbToClear & ~(size_t)(sizeof(uint32_t) - 1), + !pProps->fSwapEndian ? UINT32_C(0x80000000) : UINT32_C(0x80)); + break; + + default: + AssertMsgFailed(("Invalid bytes per sample: %RU8\n", pProps->cbSampleX)); + } + } +} + +/** + * Checks if the given buffer is silence. + * + * @param pProps The PCM properties to use checking the buffer. + * @param pvBuf The buffer to check. + * @param cbBuf The number of bytes to check (must be frame aligned). + */ +DECLINLINE(bool) PDMAudioPropsIsBufferSilence(PCPDMAUDIOPCMPROPS pProps, void const *pvBuf, size_t cbBuf) +{ + /* + * Validate input + */ + AssertPtrReturn(pProps, false); + if (!cbBuf) + return false; + AssertPtrReturn(pvBuf, false); + + /* + * Do the job. + */ + if (pProps->fSigned) + return ASMMemIsZero(pvBuf, cbBuf); + + switch (pProps->cbSampleX) + { + case 1: /* 8 bit */ + return ASMMemIsAllU8(pvBuf, cbBuf, 0x80); + + case 2: /* 16 bit */ + { + uint16_t const *pu16 = (uint16_t const *)pvBuf; + uint16_t const u16Offset = !pProps->fSwapEndian ? UINT16_C(0x8000) : UINT16_C(0x80); + cbBuf /= sizeof(*pu16); + while (cbBuf-- > 0) + if (*pu16 != u16Offset) + return false; + return true; + } + + case 4: /* 32 bit */ + { + uint32_t const *pu32 = (uint32_t const *)pvBuf; + uint32_t const u32Offset = !pProps->fSwapEndian ? UINT32_C(0x80000000) : UINT32_C(0x80); + cbBuf /= sizeof(*pu32); + while (cbBuf-- > 0) + if (*pu32 != u32Offset) + return false; + return true; + } + + default: + AssertMsgFailed(("Invalid bytes per sample: %RU8\n", pProps->cbSampleX)); + return false; + } +} + +/** + * Compares two sets of PCM properties. + * + * @returns @c true if the same, @c false if not. + * @param pProps1 The first set of properties to compare. + * @param pProps2 The second set of properties to compare. + */ +DECLINLINE(bool) PDMAudioPropsAreEqual(PCPDMAUDIOPCMPROPS pProps1, PCPDMAUDIOPCMPROPS pProps2) +{ + uintptr_t idxCh; + AssertPtrReturn(pProps1, false); + AssertPtrReturn(pProps2, false); + + if (pProps1 == pProps2) /* If the pointers match, take a shortcut. */ + return true; + + if (pProps1->uHz != pProps2->uHz) + return false; + if (pProps1->cChannelsX != pProps2->cChannelsX) + return false; + if (pProps1->cbSampleX != pProps2->cbSampleX) + return false; + if (pProps1->fSigned != pProps2->fSigned) + return false; + if (pProps1->fSwapEndian != pProps2->fSwapEndian) + return false; + if (pProps1->fRaw != pProps2->fRaw) + return false; + + idxCh = pProps1->cChannelsX; + while (idxCh-- > 0) + if (pProps1->aidChannels[idxCh] != pProps2->aidChannels[idxCh]) + return false; + + return true; +} + +/** + * Checks whether the given PCM properties are valid or not. + * + * @returns true/false accordingly. + * @param pProps The PCM properties to check. + * + * @remarks This just performs a generic check of value ranges. + * + * @sa PDMAudioStrmCfgIsValid + */ +DECLINLINE(bool) PDMAudioPropsAreValid(PCPDMAUDIOPCMPROPS pProps) +{ + AssertPtrReturn(pProps, false); + + /* Channels. */ + if ( pProps->cChannelsX != 0 + && pProps->cChannelsX <= PDMAUDIO_MAX_CHANNELS + /* Sample size. */ + && ( pProps->cbSampleX == 1 + || pProps->cbSampleX == 2 + || pProps->cbSampleX == 4 + || (pProps->cbSampleX == 8 && pProps->fRaw)) + /* Hertz rate. */ + && pProps->uHz >= 1000 + && pProps->uHz < 1000000 + /* Raw format: Here we only support int64_t as sample size currently, if enabled. */ + && ( !pProps->fRaw + || (pProps->fSigned && pProps->cbSampleX == sizeof(int64_t))) + ) + { + /* A few more sanity checks to see if the structure has been properly initialized (via PDMAudioPropsInit[Ex]). */ + AssertMsgReturn(pProps->cShiftX == PDMAUDIOPCMPROPS_MAKE_SHIFT(pProps), + ("cShift=%u cbSample=%u cChannels=%u\n", pProps->cShiftX, pProps->cbSampleX, pProps->cChannelsX), + false); + AssertMsgReturn(pProps->cbFrame == pProps->cbSampleX * pProps->cChannelsX, + ("cbFrame=%u cbSample=%u cChannels=%u\n", pProps->cbFrame, pProps->cbSampleX, pProps->cChannelsX), + false); + + return true; + } + + return false; +} + +/** + * Get number of bytes per frame. + * + * @returns Number of bytes per audio frame. + * @param pProps PCM properties to use. + * @sa PDMAUDIOPCMPROPS_F2B + */ +DECLINLINE(uint32_t) PDMAudioPropsBytesPerFrame(PCPDMAUDIOPCMPROPS pProps) +{ + return PDMAUDIOPCMPROPS_F2B(pProps, 1 /*cFrames*/); +} + +/** + * Prints PCM properties to the debug log. + * + * @param pProps PCM properties to use. + */ +DECLINLINE(void) PDMAudioPropsLog(PCPDMAUDIOPCMPROPS pProps) +{ + AssertPtrReturnVoid(pProps); + + Log(("uHz=%RU32, cChannels=%RU8, cBits=%RU8%s", + pProps->uHz, pProps->cChannelsX, pProps->cbSampleX * 8, pProps->fSigned ? "S" : "U")); +} + +/** Max necessary buffer space for PDMAudioPropsToString */ +#define PDMAUDIOPROPSTOSTRING_MAX sizeof("16ch S64 4294967296Hz swap raw") + +/** + * Formats the PCM audio properties into a string buffer. + * + * @returns pszDst + * @param pProps PCM properties to use. + * @param pszDst The destination buffer. + * @param cchDst The size of the destination buffer. Recommended to be at + * least PDMAUDIOPROPSTOSTRING_MAX bytes. + */ +DECLINLINE(char *) PDMAudioPropsToString(PCPDMAUDIOPCMPROPS pProps, char *pszDst, size_t cchDst) +{ + /* 2ch S64 44100Hz swap raw */ + RTStrPrintf(pszDst, cchDst, "%uch %c%u %RU32Hz%s%s", + PDMAudioPropsChannels(pProps), PDMAudioPropsIsSigned(pProps) ? 'S' : 'U', PDMAudioPropsSampleBits(pProps), + PDMAudioPropsHz(pProps), pProps->fSwapEndian ? " swap" : "", pProps->fRaw ? " raw" : ""); + return pszDst; +} + + +/********************************************************************************************************************************* +* Stream Configuration Helpers * +*********************************************************************************************************************************/ + +/** + * Initializes a stream configuration from PCM properties. + * + * @returns VBox status code. + * @param pCfg The stream configuration to initialize. + * @param pProps The PCM properties to use. + */ +DECLINLINE(int) PDMAudioStrmCfgInitWithProps(PPDMAUDIOSTREAMCFG pCfg, PCPDMAUDIOPCMPROPS pProps) +{ + AssertPtrReturn(pProps, VERR_INVALID_POINTER); + AssertPtrReturn(pCfg, VERR_INVALID_POINTER); + + RT_ZERO(*pCfg); + pCfg->Backend.cFramesPreBuffering = UINT32_MAX; /* Explicitly set to "undefined". */ + + memcpy(&pCfg->Props, pProps, sizeof(PDMAUDIOPCMPROPS)); + + return VINF_SUCCESS; +} + +/** + * Checks whether stream configuration matches the given PCM properties. + * + * @returns @c true if equal, @c false if not. + * @param pCfg The stream configuration. + * @param pProps The PCM properties to match with. + */ +DECLINLINE(bool) PDMAudioStrmCfgMatchesProps(PCPDMAUDIOSTREAMCFG pCfg, PCPDMAUDIOPCMPROPS pProps) +{ + AssertPtrReturn(pCfg, false); + return PDMAudioPropsAreEqual(pProps, &pCfg->Props); +} + +/** + * Checks whether two stream configuration matches. + * + * @returns @c true if equal, @c false if not. + * @param pCfg1 The first stream configuration. + * @param pCfg2 The second stream configuration. + */ +DECLINLINE(bool) PDMAudioStrmCfgEquals(PCPDMAUDIOSTREAMCFG pCfg1, PCPDMAUDIOSTREAMCFG pCfg2) +{ + if (!pCfg1 || !pCfg2) + return false; + if (pCfg1 == pCfg2) + return pCfg1 != NULL; + if (PDMAudioPropsAreEqual(&pCfg1->Props, &pCfg2->Props)) + return pCfg1->enmDir == pCfg2->enmDir + && pCfg1->enmPath == pCfg2->enmPath + && pCfg1->Device.cMsSchedulingHint == pCfg2->Device.cMsSchedulingHint + && pCfg1->Backend.cFramesPeriod == pCfg2->Backend.cFramesPeriod + && pCfg1->Backend.cFramesBufferSize == pCfg2->Backend.cFramesBufferSize + && pCfg1->Backend.cFramesPreBuffering == pCfg2->Backend.cFramesPreBuffering + && strcmp(pCfg1->szName, pCfg2->szName) == 0; + return false; +} + +/** + * Frees an audio stream allocated by PDMAudioStrmCfgDup(). + * + * @param pCfg The stream configuration to free. + */ +DECLINLINE(void) PDMAudioStrmCfgFree(PPDMAUDIOSTREAMCFG pCfg) +{ + if (pCfg) + RTMemFree(pCfg); +} + +/** + * Checks whether the given stream configuration is valid or not. + * + * @returns true/false accordingly. + * @param pCfg Stream configuration to check. + * + * @remarks This just performs a generic check of value ranges. Further, it + * will assert if the input is invalid. + * + * @sa PDMAudioPropsAreValid + */ +DECLINLINE(bool) PDMAudioStrmCfgIsValid(PCPDMAUDIOSTREAMCFG pCfg) +{ + AssertPtrReturn(pCfg, false); + AssertMsgReturn(pCfg->enmDir >= PDMAUDIODIR_UNKNOWN && pCfg->enmDir < PDMAUDIODIR_END, ("%d\n", pCfg->enmDir), false); + return PDMAudioPropsAreValid(&pCfg->Props); +} + +/** + * Copies one stream configuration to another. + * + * @returns VBox status code. + * @param pDstCfg The destination stream configuration. + * @param pSrcCfg The source stream configuration. + */ +DECLINLINE(int) PDMAudioStrmCfgCopy(PPDMAUDIOSTREAMCFG pDstCfg, PCPDMAUDIOSTREAMCFG pSrcCfg) +{ + AssertPtrReturn(pDstCfg, VERR_INVALID_POINTER); + AssertPtrReturn(pSrcCfg, VERR_INVALID_POINTER); + + /* This used to be VBOX_STRICT only and return VERR_INVALID_PARAMETER, but + that's making release builds work differently from debug & strict builds, + which is a terrible idea: */ + Assert(PDMAudioStrmCfgIsValid(pSrcCfg)); + + memcpy(pDstCfg, pSrcCfg, sizeof(PDMAUDIOSTREAMCFG)); + + return VINF_SUCCESS; +} + +/** + * Duplicates an audio stream configuration. + * + * @returns Pointer to duplicate on success, NULL on failure. Must be freed + * using PDMAudioStrmCfgFree(). + * + * @param pCfg The audio stream configuration to duplicate. + */ +DECLINLINE(PPDMAUDIOSTREAMCFG) PDMAudioStrmCfgDup(PCPDMAUDIOSTREAMCFG pCfg) +{ + AssertPtrReturn(pCfg, NULL); + + PPDMAUDIOSTREAMCFG pDst = (PPDMAUDIOSTREAMCFG)RTMemAllocZ(sizeof(PDMAUDIOSTREAMCFG)); + if (pDst) + { + int rc = PDMAudioStrmCfgCopy(pDst, pCfg); + if (RT_SUCCESS(rc)) + return pDst; + + PDMAudioStrmCfgFree(pDst); + } + return NULL; +} + +/** + * Logs an audio stream configuration. + * + * @param pCfg The stream configuration to log. + */ +DECLINLINE(void) PDMAudioStrmCfgLog(PCPDMAUDIOSTREAMCFG pCfg) +{ + if (pCfg) + LogFunc(("szName=%s enmDir=%RU32 uHz=%RU32 cBits=%RU8%s cChannels=%RU8\n", pCfg->szName, pCfg->enmDir, + pCfg->Props.uHz, pCfg->Props.cbSampleX * 8, pCfg->Props.fSigned ? "S" : "U", pCfg->Props.cChannelsX)); +} + +/** + * Converts a stream command enum value to a string. + * + * @returns Pointer to read-only stream command name on success, + * "bad" if invalid command value. + * @param enmCmd The stream command to name. + */ +DECLINLINE(const char *) PDMAudioStrmCmdGetName(PDMAUDIOSTREAMCMD enmCmd) +{ + switch (enmCmd) + { + case PDMAUDIOSTREAMCMD_INVALID: return "Invalid"; + case PDMAUDIOSTREAMCMD_ENABLE: return "Enable"; + case PDMAUDIOSTREAMCMD_DISABLE: return "Disable"; + case PDMAUDIOSTREAMCMD_PAUSE: return "Pause"; + case PDMAUDIOSTREAMCMD_RESUME: return "Resume"; + case PDMAUDIOSTREAMCMD_DRAIN: return "Drain"; + case PDMAUDIOSTREAMCMD_END: + case PDMAUDIOSTREAMCMD_32BIT_HACK: + break; + /* no default! */ + } + AssertMsgFailedReturn(("Invalid stream command %d\n", enmCmd), "bad"); +} + +/** Max necessary buffer space for PDMAudioStrmCfgToString */ +#define PDMAUDIOSTRMCFGTOSTRING_MAX \ + sizeof("'01234567890123456789012345678901234567890123456789012345678901234' unknown 16ch S64 4294967295Hz swap raw, 9999999ms buffer, 9999999ms period, 9999999ms pre-buffer, 4294967295ms sched, center-lfe") + +/** + * Formats an audio stream configuration. + * + * @param pCfg The stream configuration to stringify. + * @param pszDst The destination buffer. + * @param cbDst The size of the destination buffer. Recommend this be + * at least PDMAUDIOSTRMCFGTOSTRING_MAX bytes. + */ +DECLINLINE(const char *) PDMAudioStrmCfgToString(PCPDMAUDIOSTREAMCFG pCfg, char *pszDst, size_t cbDst) +{ + /* 'front' output 2ch 44100Hz raw, 300ms buffer, 75ms period, 150ms pre-buffer, 10ms sched */ + RTStrPrintf(pszDst, cbDst, + "'%s' %s %uch %c%u %RU32Hz%s%s, %RU32ms buffer, %RU32ms period, %RU32ms pre-buffer, %RU32ms sched%s%s", + pCfg->szName, PDMAudioDirGetName(pCfg->enmDir), PDMAudioPropsChannels(&pCfg->Props), + PDMAudioPropsIsSigned(&pCfg->Props) ? 'S' : 'U', PDMAudioPropsSampleBits(&pCfg->Props), + PDMAudioPropsHz(&pCfg->Props), pCfg->Props.fSwapEndian ? " swap" : "", pCfg->Props.fRaw ? " raw" : "", + PDMAudioPropsFramesToMilliMax(&pCfg->Props, pCfg->Backend.cFramesBufferSize, 9999999), + PDMAudioPropsFramesToMilliMax(&pCfg->Props, pCfg->Backend.cFramesPeriod, 9999999), + PDMAudioPropsFramesToMilliMax(&pCfg->Props, pCfg->Backend.cFramesPreBuffering, 9999999), + pCfg->Device.cMsSchedulingHint, + pCfg->enmPath == PDMAUDIOPATH_UNKNOWN ? "" : ", ", + pCfg->enmPath == PDMAUDIOPATH_UNKNOWN ? "" : PDMAudioPathGetName(pCfg->enmPath) ); + return pszDst; +} + + +/********************************************************************************************************************************* +* Stream Status Helpers * +*********************************************************************************************************************************/ + +/** + * Converts a audio stream state enum value to a string. + * + * @returns Pointer to read-only audio stream state string on success, + * "illegal" if invalid command value. + * @param enmStreamState The state to convert. + */ +DECLINLINE(const char *) PDMAudioStreamStateGetName(PDMAUDIOSTREAMSTATE enmStreamState) +{ + switch (enmStreamState) + { + case PDMAUDIOSTREAMSTATE_INVALID: return "invalid"; + case PDMAUDIOSTREAMSTATE_NOT_WORKING: return "not-working"; + case PDMAUDIOSTREAMSTATE_NEED_REINIT: return "need-reinit"; + case PDMAUDIOSTREAMSTATE_INACTIVE: return "inactive"; + case PDMAUDIOSTREAMSTATE_ENABLED: return "enabled"; + case PDMAUDIOSTREAMSTATE_ENABLED_READABLE: return "enabled-readable"; + case PDMAUDIOSTREAMSTATE_ENABLED_WRITABLE: return "enabled-writable"; + /* no default: */ + case PDMAUDIOSTREAMSTATE_END: + case PDMAUDIOSTREAMSTATE_32BIT_HACK: + break; + } + AssertMsgFailedReturn(("Invalid audio stream state: %d\n", enmStreamState), "illegal"); +} + +/** + * Converts a host audio (backend) stream state enum value to a string. + * + * @returns Pointer to read-only host audio stream state string on success, + * "illegal" if invalid command value. + * @param enmHostAudioStreamState The state to convert. + */ +DECLINLINE(const char *) PDMHostAudioStreamStateGetName(PDMHOSTAUDIOSTREAMSTATE enmHostAudioStreamState) +{ + switch (enmHostAudioStreamState) + { + case PDMHOSTAUDIOSTREAMSTATE_INVALID: return "invalid"; + case PDMHOSTAUDIOSTREAMSTATE_INITIALIZING: return "initializing"; + case PDMHOSTAUDIOSTREAMSTATE_NOT_WORKING: return "not-working"; + case PDMHOSTAUDIOSTREAMSTATE_OKAY: return "okay"; + case PDMHOSTAUDIOSTREAMSTATE_DRAINING: return "draining"; + case PDMHOSTAUDIOSTREAMSTATE_INACTIVE: return "inactive"; + /* no default: */ + case PDMHOSTAUDIOSTREAMSTATE_END: + case PDMHOSTAUDIOSTREAMSTATE_32BIT_HACK: + break; + } + AssertMsgFailedReturn(("Invalid host audio stream state: %d\n", enmHostAudioStreamState), "illegal"); +} + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_pdmaudioinline_h */ diff --git a/include/VBox/vmm/pdmblkcache.h b/include/VBox/vmm/pdmblkcache.h new file mode 100644 index 00000000..c9ff51d1 --- /dev/null +++ b/include/VBox/vmm/pdmblkcache.h @@ -0,0 +1,432 @@ +/** @file + * PDM - Pluggable Device Manager, Block cache. + */ + +/* + * Copyright (C) 2007-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmblkcache_h +#define VBOX_INCLUDED_vmm_pdmblkcache_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.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 DECLCALLBACKTYPE(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 enmXferDir Transfer direction. + * @param off Transfer offset. + * @param cbXfer Transfer size. + * @param pSgBuf Scather / gather buffer for the transfer. + * @param hIoXfer I/O transfer handle to ping on completion. + */ +typedef DECLCALLBACKTYPE(int, FNPDMBLKCACHEXFERENQUEUEDRV,(PPDMDRVINS pDrvIns, PDMBLKCACHEXFERDIR enmXferDir, uint64_t off, + size_t cbXfer, PCRTSGBUF pSgBuf, 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 DECLCALLBACKTYPE(int, FNPDMBLKCACHEXFERENQUEUEDISCARDDRV,(PPDMDRVINS pDrvIns, PCRTRANGE paRanges, unsigned cRanges, + PPDMBLKCACHEIOXFER hIoXfer)); +/** Pointer to a FNPDMBLKCACHEXFERENQUEUEDISCARDDRV(). */ +typedef FNPDMBLKCACHEXFERENQUEUEDISCARDDRV *PFNPDMBLKCACHEXFERENQUEUEDISCARDDRV; + +/** + * Completion 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 DECLCALLBACKTYPE(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 enmXferDir Transfer direction. + * @param off Transfer offset. + * @param cbXfer Transfer size. + * @param pSgBuf Scather / gather buffer for the transfer. + * @param hIoXfer I/O transfer handle to ping on completion. + */ +typedef DECLCALLBACKTYPE(int, FNPDMBLKCACHEXFERENQUEUEDEV,(PPDMDEVINS pDevIns, PDMBLKCACHEXFERDIR enmXferDir, uint64_t off, + size_t cbXfer, PCRTSGBUF pSgBuf, PPDMBLKCACHEIOXFER hIoXfer)); +/** Pointer to a FNPDMBLKCACHEXFERENQUEUEDEV(). */ +typedef FNPDMBLKCACHEXFERENQUEUEDEV *PFNPDMBLKCACHEXFERENQUEUEDEV; + +/** + * Discard enqueue callback for devices. + * + * @param pDevIns The device instance. + * @param paRanges Ranges to discard. + * @param cRanges Number of range entries. + * @param hIoXfer I/O handle to return on completion. + */ +typedef DECLCALLBACKTYPE(int, FNPDMBLKCACHEXFERENQUEUEDISCARDDEV,(PPDMDEVINS pDevIns, PCRTRANGE paRanges, unsigned cRanges, + PPDMBLKCACHEIOXFER hIoXfer)); +/** Pointer to a FNPDMBLKCACHEXFERENQUEUEDISCARDDEV(). */ +typedef FNPDMBLKCACHEXFERENQUEUEDISCARDDEV *PFNPDMBLKCACHEXFERENQUEUEDISCARDDEV; + +/** + * Completion callback for drivers. + * + * @param pvUserInt User argument given to PDMR3BlkCacheRetainInt. + * @param pvUser User argument given during request initiation. + * @param rc The status code of the completed request. + */ +typedef DECLCALLBACKTYPE(void, FNPDMBLKCACHEXFERCOMPLETEINT,(void *pvUserInt, void *pvUser, int rc)); +/** Pointer to a FNPDMBLKCACHEXFERCOMPLETEINT(). */ +typedef FNPDMBLKCACHEXFERCOMPLETEINT *PFNPDMBLKCACHEXFERCOMPLETEINT; + +/** + * I/O enqueue callback for internal users. + * + * @param pvUser User data. + * @param enmXferDir Transfer direction. + * @param off Transfer offset. + * @param cbXfer Transfer size. + * @param pSgBuf Scather / gather buffer for the transfer. + * @param hIoXfer I/O transfer handle to ping on completion. + */ +typedef DECLCALLBACKTYPE(int, FNPDMBLKCACHEXFERENQUEUEINT,(void *pvUser, PDMBLKCACHEXFERDIR enmXferDir, uint64_t off, + size_t cbXfer, PCRTSGBUF pSgBuf, PPDMBLKCACHEIOXFER hIoXfer)); +/** Pointer to a FNPDMBLKCACHEXFERENQUEUEINT(). */ +typedef FNPDMBLKCACHEXFERENQUEUEINT *PFNPDMBLKCACHEXFERENQUEUEINT; + +/** + * Discard enqueue callback for VMM internal users. + * + * @param pvUser User data. + * @param paRanges Ranges to discard. + * @param cRanges Number of range entries. + * @param hIoXfer I/O handle to return on completion. + */ +typedef DECLCALLBACKTYPE(int, FNPDMBLKCACHEXFERENQUEUEDISCARDINT,(void *pvUser, PCRTRANGE paRanges, unsigned cRanges, + PPDMBLKCACHEIOXFER hIoXfer)); +/** Pointer to a FNPDMBLKCACHEXFERENQUEUEDISCARDINT(). */ +typedef FNPDMBLKCACHEXFERENQUEUEDISCARDINT *PFNPDMBLKCACHEXFERENQUEUEDISCARDINT; + +/** + * Completion callback for USB devices. + * + * @param pUsbIns The USB device instance. + * @param pvUser User argument given during request initiation. + * @param rc The status code of the completed request. + */ +typedef DECLCALLBACKTYPE(void, FNPDMBLKCACHEXFERCOMPLETEUSB,(PPDMUSBINS pUsbIns, void *pvUser, int rc)); +/** Pointer to a FNPDMBLKCACHEXFERCOMPLETEUSB(). */ +typedef FNPDMBLKCACHEXFERCOMPLETEUSB *PFNPDMBLKCACHEXFERCOMPLETEUSB; + +/** + * I/O enqueue callback for USB devices. + * + * @param pUsbIns The USB device instance. + * @param enmXferDir Transfer direction. + * @param off Transfer offset. + * @param cbXfer Transfer size. + * @param pSgBuf Scather / gather buffer for the transfer. + * @param hIoXfer I/O transfer handle to ping on completion. + */ +typedef DECLCALLBACKTYPE(int, FNPDMBLKCACHEXFERENQUEUEUSB,(PPDMUSBINS pUsbIns, PDMBLKCACHEXFERDIR enmXferDir, uint64_t off, + size_t cbXfer, PCRTSGBUF pSgBuf, 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 DECLCALLBACKTYPE(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 The cross context 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 The cross context 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 The cross context 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 The cross context 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 The cross context 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 The cross context 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 The cross context 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 pBlkCache The cache instance. + * @param off Where to start reading from. + * @param pSgBuf Scatter gather buffer store the data in. + * @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 pSgBuf, size_t cbRead, void *pvUser); + +/** + * Creates a write task on the given endpoint. + * + * @returns VBox status code. + * @param pBlkCache The cache instance. + * @param off Where to start writing at. + * @param pSgBuf Scatter gather buffer gather the data from. + * @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 pSgBuf, size_t cbWrite, void *pvUser); + +/** + * Creates a flush task on the given endpoint. + * + * @returns VBox status code. + * @param pBlkCache The cache instance. + * @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 pBlkCache The cache instance. + * @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 /* !VBOX_INCLUDED_vmm_pdmblkcache_h */ + diff --git a/include/VBox/vmm/pdmcardreaderinfs.h b/include/VBox/vmm/pdmcardreaderinfs.h new file mode 100644 index 00000000..c0949c9d --- /dev/null +++ b/include/VBox/vmm/pdmcardreaderinfs.h @@ -0,0 +1,136 @@ +/* $Id: pdmcardreaderinfs.h $ */ +/** @file + * cardreaderinfs - interface between USB Card Reader device and its driver. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmcardreaderinfs_h +#define VBOX_INCLUDED_vmm_pdmcardreaderinfs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> + + +/** @defgroup grp_pdm_ifs_cardreader PDM USB Card Reader Interfaces + * @ingroup grp_pdm_interfaces + * @{ + */ + + +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; + + +#define PDMICARDREADERDOWN_IID "78d65378-889c-4418-8bc2-7a89a5af2817" +typedef struct PDMICARDREADERDOWN PDMICARDREADERDOWN; +typedef PDMICARDREADERDOWN *PPDMICARDREADERDOWN; +struct PDMICARDREADERDOWN +{ + DECLR3CALLBACKMEMBER(int, pfnEstablishContext,(PPDMICARDREADERDOWN pInterface)); + DECLR3CALLBACKMEMBER(int, pfnConnect,(PPDMICARDREADERDOWN pInterface, void *pvUser, const char *pszCardReaderName, + uint32_t u32ShareMode, uint32_t u32PreferredProtocols)); + DECLR3CALLBACKMEMBER(int, pfnDisconnect,(PPDMICARDREADERDOWN pInterface, void *pvUser, uint32_t u32Disposition)); + DECLR3CALLBACKMEMBER(int, pfnStatus,(PPDMICARDREADERDOWN pInterface, void *pvUser, uint32_t cchReaderName, uint32_t cbAtrLen)); + DECLR3CALLBACKMEMBER(int, pfnReleaseContext,(PPDMICARDREADERDOWN pInterface, void *pvUser)); + DECLR3CALLBACKMEMBER(int, pfnGetStatusChange,(PPDMICARDREADERDOWN pInterface, void *pvUser, uint32_t u32Timeout, + PDMICARDREADER_READERSTATE *paReaderStats, uint32_t cReaderStats)); + DECLR3CALLBACKMEMBER(int, pfnBeginTransaction,(PPDMICARDREADERDOWN pInterface, void *pvUser)); + DECLR3CALLBACKMEMBER(int, pfnEndTransaction,(PPDMICARDREADERDOWN pInterface, void *pvUser, uint32_t u32Disposition)); + DECLR3CALLBACKMEMBER(int, pfnTransmit,(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, pfnControl,(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, pfnGetAttr,(PPDMICARDREADERDOWN pInterface, void *pvUser, + uint32_t u32AttribId, uint32_t cbAttrib)); + DECLR3CALLBACKMEMBER(int, pfnSetAttr,(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, pfnEstablishContext,(PPDMICARDREADERUP pInterface, int32_t lSCardRc)); + DECLR3CALLBACKMEMBER(int, pfnStatus,(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, pfnConnect,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc, + uint32_t u32ActiveProtocol)); + DECLR3CALLBACKMEMBER(int, pfnDisconnect,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc)); + DECLR3CALLBACKMEMBER(int, pfnSetStatusChange,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc, + PDMICARDREADER_READERSTATE *paReaderStats, uint32_t cReaderStats)); + DECLR3CALLBACKMEMBER(int, pfnBeginTransaction,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc)); + DECLR3CALLBACKMEMBER(int, pfnEndTransaction,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc)); + /* Note: pioRecvPci stack variable */ + DECLR3CALLBACKMEMBER(int, pfnTransmit,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc, + const PDMICARDREADER_IO_REQUEST *pioRecvPci, + uint8_t *pu8RecvBuffer, uint32_t cbRecvBuffer)); + DECLR3CALLBACKMEMBER(int, pfnControl,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc, + uint32_t u32ControlCode, void *pvOutBuffer, uint32_t cbOutBuffer)); + DECLR3CALLBACKMEMBER(int, pfnGetAttrib,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc, + uint32_t u32AttribId, void *pvAttrib, uint32_t cbAttrib)); + DECLR3CALLBACKMEMBER(int, pfnSetAttrib,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc, uint32_t u32AttribId)); +}; + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_pdmcardreaderinfs_h */ + diff --git a/include/VBox/vmm/pdmcommon.h b/include/VBox/vmm/pdmcommon.h new file mode 100644 index 00000000..7257ff0b --- /dev/null +++ b/include/VBox/vmm/pdmcommon.h @@ -0,0 +1,192 @@ +/** @file + * PDM - Pluggable Device Manager, Common Definitions & Types. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmcommon_h +#define VBOX_INCLUDED_vmm_pdmcommon_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#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) ) + +/** + * Version of PDM_VERSION_MAKE that's compatible with the preprocessor. + * + * @returns 32-bit structure version number. + * + * @param uMagic 16-bit magic value, no suffix. This must be unique. + * @param uMajor 12-bit major version number, no suffix. Structures with + * different major numbers are not compatible. + * @param uMinor 4-bit minor version number, no suffix. When only the + * minor version differs, the structures will be 100% + * backwards compatible. + */ +#define PDM_VERSION_MAKE_PP(uMagic, uMajor, uMinor) \ + ( (UINT32_C(uMagic) << 16) | ((UINT32_C(uMajor) & UINT32_C(0xff)) << 4) | ((UINT32_C(uMinor) & UINT32_C(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)) ) \ + ) + + +/** @name 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 DECLCALLBACKTYPE(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. + * @remarks The caller will enter the device critical section. + * @thread EMT(0) + */ +typedef DECLCALLBACKTYPE(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 DECLCALLBACKTYPE(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 DECLCALLBACKTYPE(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 DECLCALLBACKTYPE(int, FNPDMDRVREQHANDLERR0,(PPDMDRVINS pDrvIns, uint32_t uOperation, uint64_t u64Arg)); +/** Ring-0 pointer to a FNPDMDRVREQHANDLERR0. */ +typedef R0PTRTYPE(FNPDMDRVREQHANDLERR0 *) PFNPDMDRVREQHANDLERR0; + + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_pdmcommon_h */ + diff --git a/include/VBox/vmm/pdmcritsect.h b/include/VBox/vmm/pdmcritsect.h new file mode 100644 index 00000000..79445ecb --- /dev/null +++ b/include/VBox/vmm/pdmcritsect.h @@ -0,0 +1,143 @@ +/** @file + * PDM - Pluggable Device Manager, Critical Sections. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmcritsect_h +#define VBOX_INCLUDED_vmm_pdmcritsect_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#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 ? 0xc0 : 0x100]; +#ifdef PDMCRITSECTINT_DECLARED + /** The internal structure (not normally visible). */ + struct PDMCRITSECTINT s; +#endif +} PDMCRITSECT; + +VMMR3_INT_DECL(int) PDMR3CritSectBothTerm(PVM pVM); +VMMR3_INT_DECL(void) PDMR3CritSectLeaveAll(PVM pVM); +VMM_INT_DECL(void) PDMCritSectBothFF(PVMCC pVM, PVMCPUCC pVCpu); + + +VMMR3DECL(uint32_t) PDMR3CritSectCountOwned(PVM pVM, char *pszNames, size_t cbNames); + +VMMR3DECL(int) PDMR3CritSectInit(PVM pVM, PPDMCRITSECT pCritSect, RT_SRC_POS_DECL, + const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR(6, 7); +VMMR3DECL(int) PDMR3CritSectEnterEx(PVM pVM, PPDMCRITSECT pCritSect, bool fCallRing3); +VMMR3DECL(bool) PDMR3CritSectYield(PVM pVM, PPDMCRITSECT pCritSect); +VMMR3DECL(const char *) PDMR3CritSectName(PCPDMCRITSECT pCritSect); +VMMR3DECL(int) PDMR3CritSectDelete(PVM pVM, PPDMCRITSECT pCritSect); +#if defined(IN_RING0) || defined(IN_RING3) +VMMDECL(int) PDMHCCritSectScheduleExitEvent(PPDMCRITSECT pCritSect, SUPSEMEVENT hEventToSignal); +#endif + +VMMDECL(DECL_CHECK_RETURN_NOT_R3(int)) + PDMCritSectEnter(PVMCC pVM, PPDMCRITSECT pCritSect, int rcBusy); +VMMDECL(DECL_CHECK_RETURN_NOT_R3(int)) + PDMCritSectEnterDebug(PVMCC pVM, PPDMCRITSECT pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL); +VMMDECL(DECL_CHECK_RETURN(int)) + PDMCritSectTryEnter(PVMCC pVM, PPDMCRITSECT pCritSect); +VMMDECL(DECL_CHECK_RETURN(int)) + PDMCritSectTryEnterDebug(PVMCC pVM, PPDMCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL); +VMMDECL(int) PDMCritSectLeave(PVMCC pVM, PPDMCRITSECT pCritSect); + +VMMDECL(bool) PDMCritSectIsOwner(PVMCC pVM, PCPDMCRITSECT pCritSect); +VMMDECL(bool) PDMCritSectIsOwnerEx(PVMCPUCC pVCpu, PCPDMCRITSECT pCritSect); +VMMDECL(bool) PDMCritSectIsInitialized(PCPDMCRITSECT pCritSect); +VMMDECL(bool) PDMCritSectHasWaiters(PVMCC pVM, PCPDMCRITSECT pCritSect); +VMMDECL(uint32_t) PDMCritSectGetRecursion(PCPDMCRITSECT pCritSect); + +VMMR3DECL(PPDMCRITSECT) PDMR3CritSectGetNop(PVM pVM); + +/* Strict build: Remap the two enter calls to the debug versions. */ +#ifdef VBOX_STRICT +# ifdef IPRT_INCLUDED_asm_h +# define PDMCritSectEnter(a_pVM, pCritSect, rcBusy) PDMCritSectEnterDebug((a_pVM), (pCritSect), (rcBusy), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define PDMCritSectTryEnter(a_pVM, pCritSect) PDMCritSectTryEnterDebug((a_pVM), (pCritSect), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# else +# define PDMCritSectEnter(a_pVM, pCritSect, rcBusy) PDMCritSectEnterDebug((a_pVM), (pCritSect), (rcBusy), 0, RT_SRC_POS) +# define PDMCritSectTryEnter(a_pVM, pCritSect) PDMCritSectTryEnterDebug((a_pVM), (pCritSect), 0, RT_SRC_POS) +# endif +#endif + +/** @def PDM_CRITSECT_RELEASE_ASSERT_RC + * Helper for PDMCritSectEnter w/ rcBusy VINF_SUCCESS when there is no way + * to forward failures to the caller. */ +#define PDM_CRITSECT_RELEASE_ASSERT_RC(a_pVM, a_pCritSect, a_rc) \ + AssertReleaseMsg(RT_SUCCESS(a_rc), ("pVM=%p pCritSect=%p: %Rrc\n", (a_pVM), (a_pCritSect), (a_rc))) + +/** @def PDM_CRITSECT_RELEASE_ASSERT_RC_DEV + * Helper for PDMCritSectEnter w/ rcBusy VINF_SUCCESS when there is no way + * to forward failures to the caller, device edition. */ +#define PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(a_pDevIns, a_pCritSect, a_rc) \ + AssertReleaseMsg(RT_SUCCESS(a_rc), ("pDevIns=%p pCritSect=%p: %Rrc\n", (a_pDevIns), (a_pCritSect), (a_rc))) + +/** @def PDM_CRITSECT_RELEASE_ASSERT_RC_DRV + * Helper for PDMCritSectEnter w/ rcBusy VINF_SUCCESS when there is no way + * to forward failures to the caller, driver edition. */ +#define PDM_CRITSECT_RELEASE_ASSERT_RC_DRV(a_pDrvIns, a_pCritSect, a_rc) \ + AssertReleaseMsg(RT_SUCCESS(a_rc), ("pDrvIns=%p pCritSect=%p: %Rrc\n", (a_pDrvIns), (a_pCritSect), (a_rc))) + +/** @def PDM_CRITSECT_RELEASE_ASSERT_RC_USB + * Helper for PDMCritSectEnter w/ rcBusy VINF_SUCCESS when there is no way + * to forward failures to the caller, USB device edition. */ +#define PDM_CRITSECT_RELEASE_ASSERT_RC_USB(a_pUsbIns, a_pCritSect, a_rc) \ + AssertReleaseMsg(RT_SUCCESS(a_rc), ("pUsbIns=%p pCritSect=%p: %Rrc\n", (a_pUsbIns), (a_pCritSect), (a_rc))) + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmcritsect_h */ + diff --git a/include/VBox/vmm/pdmcritsectrw.h b/include/VBox/vmm/pdmcritsectrw.h new file mode 100644 index 00000000..8b3eb319 --- /dev/null +++ b/include/VBox/vmm/pdmcritsectrw.h @@ -0,0 +1,111 @@ +/** @file + * PDM - Pluggable Device Manager, Read/Write Critical Section. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmcritsectrw_h +#define VBOX_INCLUDED_vmm_pdmcritsectrw_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_critsectrw The PDM Read/Write Critical Section API + * @ingroup grp_pdm + * @{ + */ + +/** + * A PDM read/write critical section. + * Initialize using PDMDRVHLP::pfnCritSectRwInit(). + */ +typedef union PDMCRITSECTRW +{ + /** Padding. */ + uint8_t padding[HC_ARCH_BITS == 32 ? 0xc0 : 0x100]; +#ifdef PDMCRITSECTRWINT_DECLARED + /** The internal structure (not normally visible). */ + struct PDMCRITSECTRWINT s; +#endif +} PDMCRITSECTRW; + +VMMR3DECL(int) PDMR3CritSectRwInit(PVM pVM, PPDMCRITSECTRW pCritSect, RT_SRC_POS_DECL, + const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR(6, 7); +VMMR3DECL(int) PDMR3CritSectRwDelete(PVM pVM, PPDMCRITSECTRW pCritSect); +VMMR3DECL(const char *) PDMR3CritSectRwName(PCPDMCRITSECTRW pCritSect); +VMMR3DECL(int) PDMR3CritSectRwEnterSharedEx(PVM pVM, PPDMCRITSECTRW pThis, bool fCallRing3); +VMMR3DECL(int) PDMR3CritSectRwEnterExclEx(PVM pVM, PPDMCRITSECTRW pThis, bool fCallRing3); + +VMMDECL(int) PDMCritSectRwEnterShared(PVMCC pVM, PPDMCRITSECTRW pCritSect, int rcBusy); +VMMDECL(int) PDMCritSectRwEnterSharedDebug(PVMCC pVM, PPDMCRITSECTRW pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL); +VMMDECL(int) PDMCritSectRwTryEnterShared(PVMCC pVM, PPDMCRITSECTRW pCritSect); +VMMDECL(int) PDMCritSectRwTryEnterSharedDebug(PVMCC pVM, PPDMCRITSECTRW pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL); +VMMDECL(int) PDMCritSectRwLeaveShared(PVMCC pVM, PPDMCRITSECTRW pCritSect); +VMMDECL(int) PDMCritSectRwEnterExcl(PVMCC pVM, PPDMCRITSECTRW pCritSect, int rcBusy); +VMMDECL(int) PDMCritSectRwEnterExclDebug(PVMCC pVM, PPDMCRITSECTRW pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL); +VMMDECL(int) PDMCritSectRwTryEnterExcl(PVMCC pVM, PPDMCRITSECTRW pCritSect); +VMMDECL(int) PDMCritSectRwTryEnterExclDebug(PVMCC pVM, PPDMCRITSECTRW pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL); +VMMDECL(int) PDMCritSectRwLeaveExcl(PVMCC pVM, PPDMCRITSECTRW pCritSect); + +VMMDECL(bool) PDMCritSectRwIsWriteOwner(PVMCC pVM, PPDMCRITSECTRW pCritSect); +VMMDECL(bool) PDMCritSectRwIsReadOwner(PVMCC pVM, PPDMCRITSECTRW pCritSect, bool fWannaHear); +VMMDECL(uint32_t) PDMCritSectRwGetWriteRecursion(PPDMCRITSECTRW pCritSect); +VMMDECL(uint32_t) PDMCritSectRwGetWriterReadRecursion(PPDMCRITSECTRW pCritSect); +VMMDECL(uint32_t) PDMCritSectRwGetReadCount(PPDMCRITSECTRW pCritSect); +VMMDECL(bool) PDMCritSectRwIsInitialized(PCPDMCRITSECTRW pCritSect); + +/* Lock strict build: Remap the three enter calls to the debug versions. */ +#ifdef VBOX_STRICT +# ifdef IPRT_INCLUDED_asm_h +# define PDMCritSectRwEnterExcl(a_pVM, pCritSect, rcBusy) PDMCritSectRwEnterExclDebug((a_pVM), pCritSect, rcBusy, (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define PDMCritSectRwTryEnterExcl(a_pVM, pCritSect) PDMCritSectRwTryEnterExclDebug((a_pVM), pCritSect, (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define PDMCritSectRwEnterShared(a_pVM, pCritSect, rcBusy) PDMCritSectRwEnterSharedDebug((a_pVM), pCritSect, rcBusy, (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define PDMCritSectRwTryEnterShared(a_pVM, pCritSect) PDMCritSectRwTryEnterSharedDebug((a_pVM), pCritSect, (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# else +# define PDMCritSectRwEnterExcl(a_pVM, pCritSect, rcBusy) PDMCritSectRwEnterExclDebug((a_pVM), pCritSect, rcBusy, 0, RT_SRC_POS) +# define PDMCritSectRwTryEnterExcl(a_pVM, pCritSect) PDMCritSectRwTryEnterExclDebug((a_pVM), pCritSect, 0, RT_SRC_POS) +# define PDMCritSectRwEnterShared(a_pVM, pCritSect, rcBusy) PDMCritSectRwEnterSharedDebug((a_pVM), pCritSect, rcBusy, 0, RT_SRC_POS) +# define PDMCritSectRwTryEnterShared(a_pVM, pCritSect) PDMCritSectRwTryEnterSharedDebug((a_pVM), pCritSect, 0, RT_SRC_POS) +# endif +#endif + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmcritsectrw_h */ + diff --git a/include/VBox/vmm/pdmdev.h b/include/VBox/vmm/pdmdev.h new file mode 100644 index 00000000..fd92fef8 --- /dev/null +++ b/include/VBox/vmm/pdmdev.h @@ -0,0 +1,9690 @@ +/** @file + * PDM - Pluggable Device Manager, Devices. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmdev_h +#define VBOX_INCLUDED_vmm_pdmdev_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/vmm/pdmcritsect.h> +#include <VBox/vmm/pdmcritsectrw.h> +#include <VBox/vmm/pdmqueue.h> +#include <VBox/vmm/pdmtask.h> +#ifdef IN_RING3 +# include <VBox/vmm/pdmthread.h> +#endif +#include <VBox/vmm/pdmifs.h> +#include <VBox/vmm/pdmins.h> +#include <VBox/vmm/pdmcommon.h> +#include <VBox/vmm/pdmpcidev.h> +#include <VBox/vmm/iom.h> +#include <VBox/vmm/mm.h> +#include <VBox/vmm/tm.h> +#include <VBox/vmm/ssm.h> +#include <VBox/vmm/cfgm.h> +#include <VBox/vmm/cpum.h> +#include <VBox/vmm/dbgf.h> +#include <VBox/vmm/pgm.h> /* PGMR3HandlerPhysicalTypeRegister() argument types. */ +#include <VBox/vmm/gim.h> +#include <VBox/err.h> /* VINF_EM_DBG_STOP, also 120+ source files expecting this. */ +#include <VBox/msi.h> +#include <iprt/stdarg.h> +#include <iprt/list.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 pDevIns->pCfg. + */ +typedef DECLCALLBACKTYPE(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 DECLCALLBACKTYPE(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 DECLCALLBACKTYPE(void, FNPDMDEVRELOCATE,(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)); +/** Pointer to a FNPDMDEVRELOCATE() function. */ +typedef FNPDMDEVRELOCATE *PFNPDMDEVRELOCATE; + +/** + * Power On notification. + * + * @returns VBox status. + * @param pDevIns The device instance data. + * + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(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 DECLCALLBACKTYPE(void, FNPDMDEVRESET,(PPDMDEVINS pDevIns)); +/** Pointer to a FNPDMDEVRESET() function. */ +typedef FNPDMDEVRESET *PFNPDMDEVRESET; + +/** + * Soft reset notification. + * + * This is mainly for emulating the 286 style protected mode exits, in which + * most devices should remain in their current state. + * + * @returns VBox status. + * @param pDevIns The device instance data. + * @param fFlags PDMVMRESET_F_XXX (only bits relevant to soft resets). + * + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(void, FNPDMDEVSOFTRESET,(PPDMDEVINS pDevIns, uint32_t fFlags)); +/** Pointer to a FNPDMDEVSOFTRESET() function. */ +typedef FNPDMDEVSOFTRESET *PFNPDMDEVSOFTRESET; + +/** @name PDMVMRESET_F_XXX - VM reset flags. + * These flags are used both for FNPDMDEVSOFTRESET and for hardware signalling + * reset via PDMDevHlpVMReset. + * @{ */ +/** Unknown reason. */ +#define PDMVMRESET_F_UNKNOWN UINT32_C(0x00000000) +/** GIM triggered reset. */ +#define PDMVMRESET_F_GIM UINT32_C(0x00000001) +/** The last source always causing hard resets. */ +#define PDMVMRESET_F_LAST_ALWAYS_HARD PDMVMRESET_F_GIM +/** ACPI triggered reset. */ +#define PDMVMRESET_F_ACPI UINT32_C(0x0000000c) +/** PS/2 system port A (92h) reset. */ +#define PDMVMRESET_F_PORT_A UINT32_C(0x0000000d) +/** Keyboard reset. */ +#define PDMVMRESET_F_KBD UINT32_C(0x0000000e) +/** Tripple fault. */ +#define PDMVMRESET_F_TRIPLE_FAULT UINT32_C(0x0000000f) +/** Reset source mask. */ +#define PDMVMRESET_F_SRC_MASK UINT32_C(0x0000000f) +/** @} */ + +/** + * Suspend notification. + * + * @returns VBox status. + * @param pDevIns The device instance data. + * @thread EMT(0) + * + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(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 DECLCALLBACKTYPE(void, FNPDMDEVRESUME,(PPDMDEVINS pDevIns)); +/** Pointer to a FNPDMDEVRESUME() function. */ +typedef FNPDMDEVRESUME *PFNPDMDEVRESUME; + +/** + * Power Off notification. + * + * This is always called when VMR3PowerOff is called. + * There will be no callback when hot plugging devices. + * + * @param pDevIns The device instance data. + * @thread EMT(0) + * + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(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 has 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 attached. + * @param fFlags Flags, combination of the PDM_TACH_FLAGS_* \#defines. + * + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(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 its 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 DECLCALLBACKTYPE(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 DECLCALLBACKTYPE(int, FNPDMDEVQUERYINTERFACE,(PPDMDEVINS pDevIns, unsigned iLUN, PPDMIBASE *ppBase)); +/** Pointer to a FNPDMDEVQUERYINTERFACE() function. */ +typedef FNPDMDEVQUERYINTERFACE *PFNPDMDEVQUERYINTERFACE; + +/** + * Init complete notification (after ring-0 & RC init since 5.1). + * + * 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 DECLCALLBACKTYPE(int, FNPDMDEVINITCOMPLETE,(PPDMDEVINS pDevIns)); +/** Pointer to a FNPDMDEVINITCOMPLETE() function. */ +typedef FNPDMDEVINITCOMPLETE *PFNPDMDEVINITCOMPLETE; + + +/** + * The context of a pfnMemSetup call. + */ +typedef enum PDMDEVMEMSETUPCTX +{ + /** Invalid zero value. */ + PDMDEVMEMSETUPCTX_INVALID = 0, + /** After construction. */ + PDMDEVMEMSETUPCTX_AFTER_CONSTRUCTION, + /** After reset. */ + PDMDEVMEMSETUPCTX_AFTER_RESET, + /** Type size hack. */ + PDMDEVMEMSETUPCTX_32BIT_HACK = 0x7fffffff +} PDMDEVMEMSETUPCTX; + + +/** + * 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. + * + * @note The first part is the same in every context. + */ +typedef struct PDMDEVREGR3 +{ + /** Structure version. PDM_DEVREGR3_VERSION defines the current version. */ + uint32_t u32Version; + /** Reserved, must be zero. */ + uint32_t uReserved0; + /** Device name, must match the ring-3 one. */ + char szName[32]; + /** 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; + /** The shared data structure version number. */ + uint32_t uSharedVersion; + /** Size of the instance data. */ + uint32_t cbInstanceShared; + /** Size of the ring-0 instance data. */ + uint32_t cbInstanceCC; + /** Size of the raw-mode instance data. */ + uint32_t cbInstanceRC; + /** Max number of PCI devices. */ + uint16_t cMaxPciDevices; + /** Max number of MSI-X vectors in any of the PCI devices. */ + uint16_t cMaxMsixVectors; + /** 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; + + /** Name of the raw-mode context module (no path). + * Only evalutated if PDM_DEVREG_FLAGS_RC is set. */ + const char *pszRCMod; + /** Name of the ring-0 module (no path). + * Only evalutated if PDM_DEVREG_FLAGS_R0 is set. */ + const char *pszR0Mod; + + /** 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; + /** + * Memory setup callback. + * + * @param pDevIns The device instance data. + * @param enmCtx Indicates the context of the call. + * @remarks The critical section is entered prior to calling this method. + */ + DECLR3CALLBACKMEMBER(void, pfnMemSetup, (PPDMDEVINS pDevIns, PDMDEVMEMSETUPCTX enmCtx)); + /** 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; + /** Software system reset notification - optional. + * Critical section is entered. */ + PFNPDMDEVSOFTRESET pfnSoftReset; + + /** @name Reserved for future extensions, must be zero. + * @{ */ + DECLR3CALLBACKMEMBER(int, pfnReserved0, (PPDMDEVINS pDevIns)); + DECLR3CALLBACKMEMBER(int, pfnReserved1, (PPDMDEVINS pDevIns)); + DECLR3CALLBACKMEMBER(int, pfnReserved2, (PPDMDEVINS pDevIns)); + DECLR3CALLBACKMEMBER(int, pfnReserved3, (PPDMDEVINS pDevIns)); + DECLR3CALLBACKMEMBER(int, pfnReserved4, (PPDMDEVINS pDevIns)); + DECLR3CALLBACKMEMBER(int, pfnReserved5, (PPDMDEVINS pDevIns)); + DECLR3CALLBACKMEMBER(int, pfnReserved6, (PPDMDEVINS pDevIns)); + DECLR3CALLBACKMEMBER(int, pfnReserved7, (PPDMDEVINS pDevIns)); + /** @} */ + + /** Initialization safty marker. */ + uint32_t u32VersionEnd; +} PDMDEVREGR3; +/** Pointer to a PDM Device Structure. */ +typedef PDMDEVREGR3 *PPDMDEVREGR3; +/** Const pointer to a PDM Device Structure. */ +typedef PDMDEVREGR3 const *PCPDMDEVREGR3; +/** Current DEVREGR3 version number. */ +#define PDM_DEVREGR3_VERSION PDM_VERSION_MAKE(0xffff, 4, 0) + + +/** PDM Device Flags. + * @{ */ +/** This flag is used to indicate that the device has a R0 component. */ +#define PDM_DEVREG_FLAGS_R0 UINT32_C(0x00000001) +/** Requires the ring-0 component, ignore configuration values. */ +#define PDM_DEVREG_FLAGS_REQUIRE_R0 UINT32_C(0x00000002) +/** Requires the ring-0 component, ignore configuration values. */ +#define PDM_DEVREG_FLAGS_OPT_IN_R0 UINT32_C(0x00000004) + +/** This flag is used to indicate that the device has a RC component. */ +#define PDM_DEVREG_FLAGS_RC UINT32_C(0x00000010) +/** Requires the raw-mode component, ignore configuration values. */ +#define PDM_DEVREG_FLAGS_REQUIRE_RC UINT32_C(0x00000020) +/** Requires the raw-mode component, ignore configuration values. */ +#define PDM_DEVREG_FLAGS_OPT_IN_RC UINT32_C(0x00000040) + +/** Convenience: PDM_DEVREG_FLAGS_R0 + PDM_DEVREG_FLAGS_RC */ +#define PDM_DEVREG_FLAGS_RZ (PDM_DEVREG_FLAGS_R0 | PDM_DEVREG_FLAGS_RC) + +/** @def PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT + * The bit count for the current host. + * @note Superfluous, but still around for hysterical raisins. */ +#if HC_ARCH_BITS == 32 +# define PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT UINT32_C(0x00000100) +#elif HC_ARCH_BITS == 64 +# define PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT UINT32_C(0x00000200) +#else +# error Unsupported HC_ARCH_BITS value. +#endif +/** The host bit count mask. */ +#define PDM_DEVREG_FLAGS_HOST_BITS_MASK UINT32_C(0x00000300) + +/** The device support only 32-bit guests. */ +#define PDM_DEVREG_FLAGS_GUEST_BITS_32 UINT32_C(0x00001000) +/** The device support only 64-bit guests. */ +#define PDM_DEVREG_FLAGS_GUEST_BITS_64 UINT32_C(0x00002000) +/** The device support both 32-bit & 64-bit guests. */ +#define PDM_DEVREG_FLAGS_GUEST_BITS_32_64 UINT32_C(0x00003000) +/** @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 UINT32_C(0x00003000) + +/** A convenience. */ +#define PDM_DEVREG_FLAGS_DEFAULT_BITS (PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT | PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT) + +/** Indicates that the device needs to be notified before the drivers when suspending. */ +#define PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION UINT32_C(0x00010000) +/** Indicates that the device needs to be notified before the drivers when powering off. */ +#define PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION UINT32_C(0x00020000) +/** Indicates that the device needs to be notified before the drivers when resetting. */ +#define PDM_DEVREG_FLAGS_FIRST_RESET_NOTIFICATION UINT32_C(0x00040000) + +/** This flag is used to indicate that the device has been converted to the + * new device style. */ +#define PDM_DEVREG_FLAGS_NEW_STYLE UINT32_C(0x80000000) + +/** @} */ + + +/** 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) +/** PCI built-in device (e.g. PCI root complex devices). */ +#define PDM_DEVREG_CLASS_PCI_BUILTIN 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) +/** @} */ + + +/** + * PDM Device Registration Structure, ring-0. + * + * This structure is used when registering a device from VBoxInitDevices() in HC + * Ring-0. PDM will continue use till the VM is terminated. + */ +typedef struct PDMDEVREGR0 +{ + /** Structure version. PDM_DEVREGR0_VERSION defines the current version. */ + uint32_t u32Version; + /** Reserved, must be zero. */ + uint32_t uReserved0; + /** Device name, must match the ring-3 one. */ + char szName[32]; + /** 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; + /** The shared data structure version number. */ + uint32_t uSharedVersion; + /** Size of the instance data. */ + uint32_t cbInstanceShared; + /** Size of the ring-0 instance data. */ + uint32_t cbInstanceCC; + /** Size of the raw-mode instance data. */ + uint32_t cbInstanceRC; + /** Max number of PCI devices. */ + uint16_t cMaxPciDevices; + /** Max number of MSI-X vectors in any of the PCI devices. */ + uint16_t cMaxMsixVectors; + /** 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; + + /** + * Early construction callback (optional). + * + * This is called right after the device instance structure has been allocated + * and before the ring-3 constructor gets called. + * + * @returns VBox status code. + * @param pDevIns The device instance data. + * @note The destructure is always called, regardless of the return status. + */ + DECLR0CALLBACKMEMBER(int, pfnEarlyConstruct, (PPDMDEVINS pDevIns)); + + /** + * Regular construction callback (optional). + * + * This is called after (or during) the ring-3 constructor. + * + * @returns VBox status code. + * @param pDevIns The device instance data. + * @note The destructure is always called, regardless of the return status. + */ + DECLR0CALLBACKMEMBER(int, pfnConstruct, (PPDMDEVINS pDevIns)); + + /** + * Destructor (optional). + * + * This is called after the ring-3 destruction. This is not called if ring-3 + * fails to trigger it (e.g. process is killed or crashes). + * + * @param pDevIns The device instance data. + */ + DECLR0CALLBACKMEMBER(void, pfnDestruct, (PPDMDEVINS pDevIns)); + + /** + * Final destructor (optional). + * + * This is called right before the memory is freed, which happens when the + * VM/GVM object is destroyed. This is always called. + * + * @param pDevIns The device instance data. + */ + DECLR0CALLBACKMEMBER(void, pfnFinalDestruct, (PPDMDEVINS pDevIns)); + + /** + * Generic request handler (optional). + * + * @param pDevIns The device instance data. + * @param uReq Device specific request. + * @param uArg Request argument. + */ + DECLR0CALLBACKMEMBER(int, pfnRequest, (PPDMDEVINS pDevIns, uint32_t uReq, uint64_t uArg)); + + /** @name Reserved for future extensions, must be zero. + * @{ */ + DECLR0CALLBACKMEMBER(int, pfnReserved0, (PPDMDEVINS pDevIns)); + DECLR0CALLBACKMEMBER(int, pfnReserved1, (PPDMDEVINS pDevIns)); + DECLR0CALLBACKMEMBER(int, pfnReserved2, (PPDMDEVINS pDevIns)); + DECLR0CALLBACKMEMBER(int, pfnReserved3, (PPDMDEVINS pDevIns)); + DECLR0CALLBACKMEMBER(int, pfnReserved4, (PPDMDEVINS pDevIns)); + DECLR0CALLBACKMEMBER(int, pfnReserved5, (PPDMDEVINS pDevIns)); + DECLR0CALLBACKMEMBER(int, pfnReserved6, (PPDMDEVINS pDevIns)); + DECLR0CALLBACKMEMBER(int, pfnReserved7, (PPDMDEVINS pDevIns)); + /** @} */ + + /** Initialization safty marker. */ + uint32_t u32VersionEnd; +} PDMDEVREGR0; +/** Pointer to a ring-0 PDM device registration structure. */ +typedef PDMDEVREGR0 *PPDMDEVREGR0; +/** Pointer to a const ring-0 PDM device registration structure. */ +typedef PDMDEVREGR0 const *PCPDMDEVREGR0; +/** Current DEVREGR0 version number. */ +#define PDM_DEVREGR0_VERSION PDM_VERSION_MAKE(0xff80, 1, 0) + + +/** + * PDM Device Registration Structure, raw-mode + * + * At the moment, this structure is mostly here to match the other two contexts. + */ +typedef struct PDMDEVREGRC +{ + /** Structure version. PDM_DEVREGRC_VERSION defines the current version. */ + uint32_t u32Version; + /** Reserved, must be zero. */ + uint32_t uReserved0; + /** Device name, must match the ring-3 one. */ + char szName[32]; + /** 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; + /** The shared data structure version number. */ + uint32_t uSharedVersion; + /** Size of the instance data. */ + uint32_t cbInstanceShared; + /** Size of the ring-0 instance data. */ + uint32_t cbInstanceCC; + /** Size of the raw-mode instance data. */ + uint32_t cbInstanceRC; + /** Max number of PCI devices. */ + uint16_t cMaxPciDevices; + /** Max number of MSI-X vectors in any of the PCI devices. */ + uint16_t cMaxMsixVectors; + /** 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; + + /** + * Constructor callback. + * + * This is called much later than both the ring-0 and ring-3 constructors, since + * raw-mode v2 require a working VMM to run actual code. + * + * @returns VBox status code. + * @param pDevIns The device instance data. + * @note The destructure is always called, regardless of the return status. + */ + DECLRGCALLBACKMEMBER(int, pfnConstruct, (PPDMDEVINS pDevIns)); + + /** @name Reserved for future extensions, must be zero. + * @{ */ + DECLRCCALLBACKMEMBER(int, pfnReserved0, (PPDMDEVINS pDevIns)); + DECLRCCALLBACKMEMBER(int, pfnReserved1, (PPDMDEVINS pDevIns)); + DECLRCCALLBACKMEMBER(int, pfnReserved2, (PPDMDEVINS pDevIns)); + DECLRCCALLBACKMEMBER(int, pfnReserved3, (PPDMDEVINS pDevIns)); + DECLRCCALLBACKMEMBER(int, pfnReserved4, (PPDMDEVINS pDevIns)); + DECLRCCALLBACKMEMBER(int, pfnReserved5, (PPDMDEVINS pDevIns)); + DECLRCCALLBACKMEMBER(int, pfnReserved6, (PPDMDEVINS pDevIns)); + DECLRCCALLBACKMEMBER(int, pfnReserved7, (PPDMDEVINS pDevIns)); + /** @} */ + + /** Initialization safty marker. */ + uint32_t u32VersionEnd; +} PDMDEVREGRC; +/** Pointer to a raw-mode PDM device registration structure. */ +typedef PDMDEVREGRC *PPDMDEVREGRC; +/** Pointer to a const raw-mode PDM device registration structure. */ +typedef PDMDEVREGRC const *PCPDMDEVREGRC; +/** Current DEVREGRC version number. */ +#define PDM_DEVREGRC_VERSION PDM_VERSION_MAKE(0xff81, 1, 0) + + + +/** @def PDM_DEVREG_VERSION + * Current DEVREG version number. */ +/** @typedef PDMDEVREGR3 + * A current context PDM device registration structure. */ +/** @typedef PPDMDEVREGR3 + * Pointer to a current context PDM device registration structure. */ +/** @typedef PCPDMDEVREGR3 + * Pointer to a const current context PDM device registration structure. */ +#if defined(IN_RING3) || defined(DOXYGEN_RUNNING) +# define PDM_DEVREG_VERSION PDM_DEVREGR3_VERSION +typedef PDMDEVREGR3 PDMDEVREG; +typedef PPDMDEVREGR3 PPDMDEVREG; +typedef PCPDMDEVREGR3 PCPDMDEVREG; +#elif defined(IN_RING0) +# define PDM_DEVREG_VERSION PDM_DEVREGR0_VERSION +typedef PDMDEVREGR0 PDMDEVREG; +typedef PPDMDEVREGR0 PPDMDEVREG; +typedef PCPDMDEVREGR0 PCPDMDEVREG; +#elif defined(IN_RC) +# define PDM_DEVREG_VERSION PDM_DEVREGRC_VERSION +typedef PDMDEVREGRC PDMDEVREG; +typedef PPDMDEVREGRC PPDMDEVREG; +typedef PCPDMDEVREGRC PCPDMDEVREG; +#else +# error "Not IN_RING3, IN_RING0 or IN_RC" +#endif + + +/** + * Device registrations for ring-0 modules. + * + * This structure is used directly and must therefore reside in persistent + * memory (i.e. the data section). + */ +typedef struct PDMDEVMODREGR0 +{ + /** The structure version (PDM_DEVMODREGR0_VERSION). */ + uint32_t u32Version; + /** Number of devices in the array papDevRegs points to. */ + uint32_t cDevRegs; + /** Pointer to device registration structures. */ + PCPDMDEVREGR0 *papDevRegs; + /** The ring-0 module handle - PDM internal, fingers off. */ + void *hMod; + /** List entry - PDM internal, fingers off. */ + RTLISTNODE ListEntry; +} PDMDEVMODREGR0; +/** Pointer to device registriations for a ring-0 module. */ +typedef PDMDEVMODREGR0 *PPDMDEVMODREGR0; +/** Current PDMDEVMODREGR0 version number. */ +#define PDM_DEVMODREGR0_VERSION PDM_VERSION_MAKE(0xff85, 1, 0) + + +/** @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 (PIC) / + * automatically deasserts it after delivery to the APIC (IOAPIC). + * @note Only suitable for edge trigger interrupts. */ +#define PDM_IRQ_LEVEL_FLIP_FLOP (RT_BIT(1) | PDM_IRQ_LEVEL_HIGH) +/** @} */ + +/** + * Registration record for MSI/MSI-X emulation. + */ +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; + /** If we do not support per-vector masking */ + bool fMsiNoMasking; + + /** 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 PDMPCIBUSREGR3 +{ + /** Structure version number. PDM_PCIBUSREGR3_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. + * @param fFlags Reserved for future use, PDMPCIDEVREG_F_MBZ. + * @param uPciDevNo PDMPCIDEVREG_DEV_NO_FIRST_UNUSED, or a specific + * device number (0-31). + * @param uPciFunNo PDMPCIDEVREG_FUN_NO_FIRST_UNUSED, or a specific + * function number (0-7). + * @param pszName Device name (static but not unique). + * + * @remarks Caller enters the PDM critical section. + */ + DECLR3CALLBACKMEMBER(int, pfnRegisterR3,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t fFlags, + uint8_t uPciDevNo, uint8_t uPciFunNo, const char *pszName)); + + /** + * Initialize MSI or MSI-X emulation support in a PCI device. + * + * This cannot handle all corner cases of the MSI/MSI-X spec, but for the + * vast majority of device emulation it covers everything necessary. It's + * fully automatic, taking care of all BAR and config space requirements, + * and interrupt delivery is done using PDMDevHlpPCISetIrq and friends. + * When MSI/MSI-X is enabled then the iIrq parameter is redefined to take + * the vector number (otherwise it has the usual INTA-D meaning for PCI). + * + * A device not using this can still offer MSI/MSI-X. In this case it's + * completely up to the device (in the MSI-X case) to create/register the + * necessary MMIO BAR, handle all config space/BAR updating and take care + * of delivering the interrupts appropriately. + * + * @returns VBox status code. + * @param pDevIns Device instance of the PCI Bus. + * @param pPciDev The PCI device structure. + * @param pMsiReg MSI emulation registration structure + * @remarks Caller enters the PDM critical section. + */ + DECLR3CALLBACKMEMBER(int, pfnRegisterMsiR3,(PPDMDEVINS pDevIns, PPDMPCIDEV 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 enmType PCI_ADDRESS_SPACE_MEM, PCI_ADDRESS_SPACE_IO or + * PCI_ADDRESS_SPACE_MEM_PREFETCH, optionally with + * PCI_ADDRESS_SPACE_BAR64 or'ed in. + * @param fFlags PDMPCIDEV_IORGN_F_XXX. + * @param hHandle An I/O port, MMIO or MMIO2 handle according to + * @a fFlags, UINT64_MAX if no handle is passed + * (old style). + * @param pfnMapUnmap Callback for doing the mapping. Optional if a handle + * is given. + * @remarks Caller enters the PDM critical section. + */ + DECLR3CALLBACKMEMBER(int, pfnIORegionRegisterR3,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, + RTGCPHYS cbRegion, PCIADDRESSSPACE enmType, uint32_t fFlags, + uint64_t hHandle, PFNPCIIOREGIONMAP pfnMapUnmap)); + + /** + * Register PCI configuration space read/write intercept 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 pfnWrite Pointer to the user defined PCI config write function. + * to call default PCI config write function. Can be NULL. + * @remarks Caller enters the PDM critical section. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(void, pfnInterceptConfigAccesses,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, + PFNPCICONFIGREAD pfnRead, PFNPCICONFIGWRITE pfnWrite)); + + /** + * Perform a PCI configuration space write, bypassing interception. + * + * This is for devices that make use of PDMDevHlpPCIInterceptConfigAccesses(). + * + * @returns Strict VBox status code (mainly DBGFSTOP). + * @param pDevIns Device instance of the PCI Bus. + * @param pPciDev The PCI device which config space is being read. + * @param uAddress The config space address. + * @param cb The size of the read: 1, 2 or 4 bytes. + * @param u32Value The value to write. + * @note The caller (PDM) does not enter the PDM critsect, but it is possible + * that the (root) bus will have done that already. + */ + DECLR3CALLBACKMEMBER(VBOXSTRICTRC, pfnConfigWrite,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, + uint32_t uAddress, unsigned cb, uint32_t u32Value)); + + /** + * Perform a PCI configuration space read, bypassing interception. + * + * This is for devices that make use of PDMDevHlpPCIInterceptConfigAccesses(). + * + * @returns Strict VBox status code (mainly DBGFSTOP). + * @param pDevIns Device instance of the PCI Bus. + * @param pPciDev The PCI device which config space is being read. + * @param uAddress The config space address. + * @param cb The size of the read: 1, 2 or 4 bytes. + * @param pu32Value Where to return the value. + * @note The caller (PDM) does not enter the PDM critsect, but it is possible + * that the (root) bus will have done that already. + */ + DECLR3CALLBACKMEMBER(VBOXSTRICTRC, pfnConfigRead,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, + uint32_t uAddress, unsigned cb, uint32_t *pu32Value)); + + /** + * 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). + * @remarks Caller enters the PDM critical section. + */ + DECLR3CALLBACKMEMBER(void, pfnSetIrqR3,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel, uint32_t uTagSrc)); + + /** Marks the end of the structure with PDM_PCIBUSREGR3_VERSION. */ + uint32_t u32EndVersion; +} PDMPCIBUSREGR3; +/** Pointer to a PCI bus registration structure. */ +typedef PDMPCIBUSREGR3 *PPDMPCIBUSREGR3; +/** Current PDMPCIBUSREGR3 version number. */ +#define PDM_PCIBUSREGR3_VERSION PDM_VERSION_MAKE(0xff86, 2, 0) + +/** + * PCI Bus registration structure for ring-0. + */ +typedef struct PDMPCIBUSREGR0 +{ + /** Structure version number. PDM_PCIBUSREGR0_VERSION defines the current version. */ + uint32_t u32Version; + /** The PCI bus number (from ring-3 registration). */ + uint32_t iBus; + /** + * 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). + * @remarks Caller enters the PDM critical section. + */ + DECLR0CALLBACKMEMBER(void, pfnSetIrq,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel, uint32_t uTagSrc)); + /** Marks the end of the structure with PDM_PCIBUSREGR0_VERSION. */ + uint32_t u32EndVersion; +} PDMPCIBUSREGR0; +/** Pointer to a PCI bus ring-0 registration structure. */ +typedef PDMPCIBUSREGR0 *PPDMPCIBUSREGR0; +/** Current PDMPCIBUSREGR0 version number. */ +#define PDM_PCIBUSREGR0_VERSION PDM_VERSION_MAKE(0xff87, 1, 0) + +/** + * PCI Bus registration structure for raw-mode. + */ +typedef struct PDMPCIBUSREGRC +{ + /** Structure version number. PDM_PCIBUSREGRC_VERSION defines the current version. */ + uint32_t u32Version; + /** The PCI bus number (from ring-3 registration). */ + uint32_t iBus; + /** + * 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). + * @remarks Caller enters the PDM critical section. + */ + DECLRCCALLBACKMEMBER(void, pfnSetIrq,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel, uint32_t uTagSrc)); + /** Marks the end of the structure with PDM_PCIBUSREGRC_VERSION. */ + uint32_t u32EndVersion; +} PDMPCIBUSREGRC; +/** Pointer to a PCI bus raw-mode registration structure. */ +typedef PDMPCIBUSREGRC *PPDMPCIBUSREGRC; +/** Current PDMPCIBUSREGRC version number. */ +#define PDM_PCIBUSREGRC_VERSION PDM_VERSION_MAKE(0xff88, 1, 0) + +/** PCI bus registration structure for the current context. */ +typedef CTX_SUFF(PDMPCIBUSREG) PDMPCIBUSREGCC; +/** Pointer to a PCI bus registration structure for the current context. */ +typedef CTX_SUFF(PPDMPCIBUSREG) PPDMPCIBUSREGCC; +/** PCI bus registration structure version for the current context. */ +#define PDM_PCIBUSREGCC_VERSION CTX_MID(PDM_PCIBUSREG,_VERSION) + + +/** + * 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 uBusDevFn The bus:device:function of the device initiating the + * IRQ. Pass NIL_PCIBDF when it's not a PCI device or + * interrupt. + * @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, PCIBDF uBusDevFn, int iIrq, int iLevel, uint32_t uTagSrc)); + + /** + * Send an MSI. + * + * @param pDevIns PCI device instance. + * @param uBusDevFn The bus:device:function of the device initiating the + * MSI. Cannot be NIL_PCIBDF. + * @param pMsi The MSI to send. + * @param uTagSrc The IRQ tag and source (for tracing). + * @thread EMT only. + */ + DECLRCCALLBACKMEMBER(void, pfnIoApicSendMsi,(PPDMDEVINS pDevIns, PCIBDF uBusDevFn, PCMSIMSG pMsi, 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. + * + * @sa PDMCritSectEnter + */ + DECLRCCALLBACKMEMBER(int, pfnLock,(PPDMDEVINS pDevIns, int rc)); + + /** + * Releases the PDM lock. + * + * @param pDevIns The PCI device instance. + */ + DECLRCCALLBACKMEMBER(void, pfnUnlock,(PPDMDEVINS pDevIns)); + + /** + * Gets a bus by it's PDM ordinal (typically the parent bus). + * + * @returns Pointer to the device instance of the bus. + * @param pDevIns The PCI bus device instance. + * @param idxPdmBus The PDM ordinal value of the bus to get. + */ + DECLRCCALLBACKMEMBER(PPDMDEVINS, pfnGetBusByNo,(PPDMDEVINS pDevIns, uint32_t idxPdmBus)); + + /** 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, 4, 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 uBusDevFn The bus:device:function of the device initiating the + * IRQ. Pass NIL_PCIBDF when it's not a PCI device or + * interrupt. + * @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, PCIBDF uBusDevFn, int iIrq, int iLevel, uint32_t uTagSrc)); + + /** + * Send an MSI. + * + * @param pDevIns PCI device instance. + * @param uBusDevFn The bus:device:function of the device initiating the + * MSI. Cannot be NIL_PCIBDF. + * @param pMsi The MSI to send. + * @param uTagSrc The IRQ tag and source (for tracing). + * @thread EMT only. + */ + DECLR0CALLBACKMEMBER(void, pfnIoApicSendMsi,(PPDMDEVINS pDevIns, PCIBDF uBusDevFn, PCMSIMSG pMsi, 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. + * + * @sa PDMCritSectEnter + */ + DECLR0CALLBACKMEMBER(int, pfnLock,(PPDMDEVINS pDevIns, int rc)); + + /** + * Releases the PDM lock. + * + * @param pDevIns The PCI device instance. + */ + DECLR0CALLBACKMEMBER(void, pfnUnlock,(PPDMDEVINS pDevIns)); + + /** + * Gets a bus by it's PDM ordinal (typically the parent bus). + * + * @returns Pointer to the device instance of the bus. + * @param pDevIns The PCI bus device instance. + * @param idxPdmBus The PDM ordinal value of the bus to get. + */ + DECLR0CALLBACKMEMBER(PPDMDEVINS, pfnGetBusByNo,(PPDMDEVINS pDevIns, uint32_t idxPdmBus)); + + /** 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, 6, 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 uBusDevFn The bus:device:function of the device initiating the + * IRQ. Pass NIL_PCIBDF when it's not a PCI device or + * interrupt. + * @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, PCIBDF uBusDevFn, int iIrq, int iLevel, uint32_t uTagSrc)); + + /** + * Send an MSI. + * + * @param pDevIns PCI device instance. + * @param uBusDevFn The bus:device:function of the device initiating the + * MSI. Cannot be NIL_PCIBDF. + * @param pMsi The MSI to send. + * @param uTagSrc The IRQ tag and source (for tracing). + */ + DECLR3CALLBACKMEMBER(void, pfnIoApicSendMsi,(PPDMDEVINS pDevIns, PCIBDF uBusDevFn, PCMSIMSG pMsi, uint32_t uTagSrc)); + + /** + * 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. + * + * @sa PDMCritSectEnter + */ + DECLR3CALLBACKMEMBER(int, pfnLock,(PPDMDEVINS pDevIns, int rc)); + + /** + * Releases the PDM lock. + * + * @param pDevIns The PCI device instance. + */ + DECLR3CALLBACKMEMBER(void, pfnUnlock,(PPDMDEVINS pDevIns)); + + /** + * Gets a bus by it's PDM ordinal (typically the parent bus). + * + * @returns Pointer to the device instance of the bus. + * @param pDevIns The PCI bus device instance. + * @param idxPdmBus The PDM ordinal value of the bus to get. + */ + DECLR3CALLBACKMEMBER(PPDMDEVINS, pfnGetBusByNo,(PPDMDEVINS pDevIns, uint32_t idxPdmBus)); + + /** 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, 5, 0) + + +/** @name PDMIOMMU_MEM_F_XXX - IOMMU memory access transaction flags. + * These flags are used for memory access transactions via the IOMMU interface. + * @{ */ +/** Memory read. */ +#define PDMIOMMU_MEM_F_READ RT_BIT_32(0) +/** Memory write. */ +#define PDMIOMMU_MEM_F_WRITE RT_BIT_32(1) +/** Valid flag mask. */ +#define PDMIOMMU_MEM_F_VALID_MASK (PDMIOMMU_MEM_F_READ | PDMIOMMU_MEM_F_WRITE) +/** @} */ + +/** + * IOMMU registration structure for ring-0. + */ +typedef struct PDMIOMMUREGR0 +{ + /** Structure version number. PDM_IOMMUREG_VERSION defines the current + * version. */ + uint32_t u32Version; + /** Index into the PDM IOMMU array (PDM::aIommus) from ring-3. */ + uint32_t idxIommu; + + /** + * Translates the physical address for a memory transaction through the IOMMU. + * + * @returns VBox status code. + * @param pDevIns The IOMMU device instance. + * @param idDevice The device identifier (bus, device, function). + * @param uIova The I/O virtual address being accessed. + * @param cbIova The size of the access. + * @param fFlags Access flags, see PDMIOMMU_MEM_F_XXX. + * @param pGCPhysSpa Where to store the translated system physical address. + * @param pcbContiguous Where to store the number of contiguous bytes translated + * and permission-checked. + * + * @thread Any. + */ + DECLR0CALLBACKMEMBER(int, pfnMemAccess,(PPDMDEVINS pDevIns, uint16_t idDevice, uint64_t uIova, size_t cbIova, + uint32_t fFlags, PRTGCPHYS pGCPhysSpa, size_t *pcbContiguous)); + + /** + * Translates in bulk physical page addresses for memory transactions through the + * IOMMU. + * + * @returns VBox status code. + * @param pDevIns The IOMMU device instance. + * @param idDevice The device identifier (bus, device, function). + * @param cIovas The number of I/O virtual addresses being accessed. + * @param pauIovas The I/O virtual addresses being accessed. + * @param fFlags Access flags, see PDMIOMMU_MEM_F_XXX. + * @param paGCPhysSpa Where to store the translated system physical page + * addresses. + * + * @thread Any. + */ + DECLR0CALLBACKMEMBER(int, pfnMemBulkAccess,(PPDMDEVINS pDevIns, uint16_t idDevice, size_t cIovas, uint64_t const *pauIovas, + uint32_t fFlags, PRTGCPHYS paGCPhysSpa)); + + /** + * Performs an interrupt remap request through the IOMMU. + * + * @returns VBox status code. + * @param pDevIns The IOMMU device instance. + * @param idDevice The device identifier (bus, device, function). + * @param pMsiIn The source MSI. + * @param pMsiOut Where to store the remapped MSI. + * + * @thread Any. + */ + DECLR0CALLBACKMEMBER(int, pfnMsiRemap,(PPDMDEVINS pDevIns, uint16_t idDevice, PCMSIMSG pMsiIn, PMSIMSG pMsiOut)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMIOMMUREGR0; +/** Pointer to a IOMMU registration structure. */ +typedef PDMIOMMUREGR0 *PPDMIOMMUREGR0; + +/** Current PDMIOMMUREG version number. */ +#define PDM_IOMMUREGR0_VERSION PDM_VERSION_MAKE(0xff10, 3, 0) + + +/** + * IOMMU registration structure for raw-mode. + */ +typedef struct PDMIOMMUREGRC +{ + /** Structure version number. PDM_IOMMUREG_VERSION defines the current + * version. */ + uint32_t u32Version; + /** Index into the PDM IOMMU array (PDM::aIommus) from ring-3. */ + uint32_t idxIommu; + + /** + * Translates the physical address for a memory transaction through the IOMMU. + * + * @returns VBox status code. + * @param pDevIns The IOMMU device instance. + * @param idDevice The device identifier (bus, device, function). + * @param uIova The I/O virtual address being accessed. + * @param cbIova The size of the access. + * @param fFlags Access flags, see PDMIOMMU_MEM_F_XXX. + * @param pGCPhysSpa Where to store the translated system physical address. + * @param pcbContiguous Where to store the number of contiguous bytes translated + * and permission-checked. + * + * @thread Any. + */ + DECLRCCALLBACKMEMBER(int, pfnMemAccess,(PPDMDEVINS pDevIns, uint16_t idDevice, uint64_t uIova, size_t cbIova, + uint32_t fFlags, PRTGCPHYS pGCPhysSpa, size_t *pcbContiguous)); + + /** + * Translates in bulk physical page addresses for memory transactions through the + * IOMMU. + * + * @returns VBox status code. + * @param pDevIns The IOMMU device instance. + * @param idDevice The device identifier (bus, device, function). + * @param cIovas The number of I/O virtual addresses being accessed. + * @param pauIovas The I/O virtual addresses being accessed. + * @param fFlags Access flags, see PDMIOMMU_MEM_F_XXX. + * @param paGCPhysSpa Where to store the translated system physical page + * addresses. + * + * @thread Any. + */ + DECLRCCALLBACKMEMBER(int, pfnMemBulkAccess,(PPDMDEVINS pDevIns, uint16_t idDevice, size_t cIovas, uint64_t const *pauIovas, + uint32_t fFlags, PRTGCPHYS paGCPhysSpa)); + + /** + * Performs an interrupt remap request through the IOMMU. + * + * @returns VBox status code. + * @param pDevIns The IOMMU device instance. + * @param idDevice The device identifier (bus, device, function). + * @param pMsiIn The source MSI. + * @param pMsiOut Where to store the remapped MSI. + * + * @thread Any. + */ + DECLRCCALLBACKMEMBER(int, pfnMsiRemap,(PPDMDEVINS pDevIns, uint16_t idDevice, PCMSIMSG pMsiIn, PMSIMSG pMsiOut)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMIOMMUREGRC; +/** Pointer to a IOMMU registration structure. */ +typedef PDMIOMMUREGRC *PPDMIOMMUREGRC; + +/** Current PDMIOMMUREG version number. */ +#define PDM_IOMMUREGRC_VERSION PDM_VERSION_MAKE(0xff11, 3, 0) + + +/** + * IOMMU registration structure for ring-3. + */ +typedef struct PDMIOMMUREGR3 +{ + /** Structure version number. PDM_IOMMUREG_VERSION defines the current + * version. */ + uint32_t u32Version; + /** Padding. */ + uint32_t uPadding0; + + /** + * Translates the physical address for a memory transaction through the IOMMU. + * + * @returns VBox status code. + * @param pDevIns The IOMMU device instance. + * @param idDevice The device identifier (bus, device, function). + * @param uIova The I/O virtual address being accessed. + * @param cbIova The size of the access. + * @param fFlags Access flags, see PDMIOMMU_MEM_F_XXX. + * @param pGCPhysSpa Where to store the translated system physical address. + * @param pcbContiguous Where to store the number of contiguous bytes translated + * and permission-checked. + * + * @thread Any. + */ + DECLR3CALLBACKMEMBER(int, pfnMemAccess,(PPDMDEVINS pDevIns, uint16_t idDevice, uint64_t uIova, size_t cbIova, + uint32_t fFlags, PRTGCPHYS pGCPhysSpa, size_t *pcbContiguous)); + + /** + * Translates in bulk physical page addresses for memory transactions through the + * IOMMU. + * + * @returns VBox status code. + * @param pDevIns The IOMMU device instance. + * @param idDevice The device identifier (bus, device, function). + * @param cIovas The number of I/O virtual addresses being accessed. + * @param pauIovas The I/O virtual addresses being accessed. + * @param fFlags Access flags, see PDMIOMMU_MEM_F_XXX. + * @param paGCPhysSpa Where to store the translated system physical page + * addresses. + * + * @thread Any. + */ + DECLR3CALLBACKMEMBER(int, pfnMemBulkAccess,(PPDMDEVINS pDevIns, uint16_t idDevice, size_t cIovas, uint64_t const *pauIovas, + uint32_t fFlags, PRTGCPHYS paGCPhysSpa)); + + /** + * Performs an interrupt remap request through the IOMMU. + * + * @returns VBox status code. + * @param pDevIns The IOMMU device instance. + * @param idDevice The device identifier (bus, device, function). + * @param pMsiIn The source MSI. + * @param pMsiOut Where to store the remapped MSI. + * + * @thread Any. + */ + DECLR3CALLBACKMEMBER(int, pfnMsiRemap,(PPDMDEVINS pDevIns, uint16_t idDevice, PCMSIMSG pMsiIn, PMSIMSG pMsiOut)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMIOMMUREGR3; +/** Pointer to a IOMMU registration structure. */ +typedef PDMIOMMUREGR3 *PPDMIOMMUREGR3; + +/** Current PDMIOMMUREG version number. */ +#define PDM_IOMMUREGR3_VERSION PDM_VERSION_MAKE(0xff12, 3, 0) + +/** IOMMU registration structure for the current context. */ +typedef CTX_SUFF(PDMIOMMUREG) PDMIOMMUREGCC; +/** Pointer to an IOMMU registration structure for the current context. */ +typedef CTX_SUFF(PPDMIOMMUREG) PPDMIOMMUREGCC; +/** IOMMU registration structure version for the current context. */ +#define PDM_IOMMUREGCC_VERSION CTX_MID(PDM_IOMMUREG,_VERSION) + + +/** + * IOMMU helpers for ring-0. + */ +typedef struct PDMIOMMUHLPR0 +{ + /** Structure version. PDM_IOMMUHLP_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * 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. + * + * @sa PDMCritSectEnter + */ + DECLR0CALLBACKMEMBER(int, pfnLock,(PPDMDEVINS pDevIns, int rc)); + + /** + * Releases the PDM lock. + * + * @param pDevIns The PCI device instance. + */ + DECLR0CALLBACKMEMBER(void, pfnUnlock,(PPDMDEVINS pDevIns)); + + /** + * Check whether the calling thread owns the PDM lock. + * + * @returns @c true if the PDM lock is owned, @c false otherwise. + * @param pDevIns The PCI device instance. + */ + DECLR0CALLBACKMEMBER(bool, pfnLockIsOwner,(PPDMDEVINS pDevIns)); + + /** + * Send an MSI (when generated by the IOMMU device itself). + * + * @param pDevIns PCI device instance. + * @param pMsi The MSI to send. + * @param uTagSrc The IRQ tag and source (for tracing). + */ + DECLR0CALLBACKMEMBER(void, pfnSendMsi,(PPDMDEVINS pDevIns, PCMSIMSG pMsi, uint32_t uTagSrc)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMIOMMUHLPR0; +/** Pointer to IOMMU helpers for ring-0. */ +typedef PDMIOMMUHLPR0 *PPDMIOMMUHLPR0; +/** Pointer to const IOMMU helpers for ring-0. */ +typedef const PDMIOMMUHLPR0 *PCPDMIOMMUHLPR0; + +/** Current PDMIOMMUHLPR0 version number. */ +#define PDM_IOMMUHLPR0_VERSION PDM_VERSION_MAKE(0xff13, 5, 0) + + +/** + * IOMMU helpers for raw-mode. + */ +typedef struct PDMIOMMUHLPRC +{ + /** Structure version. PDM_IOMMUHLP_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * 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. + * + * @sa PDMCritSectEnter + */ + DECLRCCALLBACKMEMBER(int, pfnLock,(PPDMDEVINS pDevIns, int rc)); + + /** + * Releases the PDM lock. + * + * @param pDevIns The PCI device instance. + */ + DECLRCCALLBACKMEMBER(void, pfnUnlock,(PPDMDEVINS pDevIns)); + + /** + * Check whether the threads owns the PDM lock. + * + * @returns @c true if the PDM lock is owned, @c false otherwise. + * @param pDevIns The PCI device instance. + */ + DECLRCCALLBACKMEMBER(bool, pfnLockIsOwner,(PPDMDEVINS pDevIns)); + + /** + * Send an MSI (when generated by the IOMMU device itself). + * + * @param pDevIns PCI device instance. + * @param pMsi The MSI to send. + * @param uTagSrc The IRQ tag and source (for tracing). + */ + DECLRCCALLBACKMEMBER(void, pfnSendMsi,(PPDMDEVINS pDevIns, PCMSIMSG pMsi, uint32_t uTagSrc)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMIOMMUHLPRC; +/** Pointer to IOMMU helpers for raw-mode. */ +typedef PDMIOMMUHLPRC *PPDMIOMMUHLPRC; +/** Pointer to const IOMMU helpers for raw-mode. */ +typedef const PDMIOMMUHLPRC *PCPDMIOMMUHLPRC; + +/** Current PDMIOMMUHLPRC version number. */ +#define PDM_IOMMUHLPRC_VERSION PDM_VERSION_MAKE(0xff14, 5, 0) + + +/** + * IOMMU helpers for ring-3. + */ +typedef struct PDMIOMMUHLPR3 +{ + /** Structure version. PDM_IOMMUHLP_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * 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. + * + * @sa PDMCritSectEnter + */ + DECLR3CALLBACKMEMBER(int, pfnLock,(PPDMDEVINS pDevIns, int rc)); + + /** + * Releases the PDM lock. + * + * @param pDevIns The PCI device instance. + */ + DECLR3CALLBACKMEMBER(void, pfnUnlock,(PPDMDEVINS pDevIns)); + + /** + * Check whether the threads owns the PDM lock. + * + * @returns @c true if the PDM lock is owned, @c false otherwise. + * @param pDevIns The PCI device instance. + */ + DECLR3CALLBACKMEMBER(bool, pfnLockIsOwner,(PPDMDEVINS pDevIns)); + + /** + * Send an MSI (when generated by the IOMMU device itself). + * + * @param pDevIns PCI device instance. + * @param pMsi The MSI to send. + * @param uTagSrc The IRQ tag and source (for tracing). + */ + DECLR3CALLBACKMEMBER(void, pfnSendMsi,(PPDMDEVINS pDevIns, PCMSIMSG pMsi, uint32_t uTagSrc)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMIOMMUHLPR3; +/** Pointer to IOMMU helpers for raw-mode. */ +typedef PDMIOMMUHLPR3 *PPDMIOMMUHLPR3; +/** Pointer to const IOMMU helpers for raw-mode. */ +typedef const PDMIOMMUHLPR3 *PCPDMIOMMUHLPR3; + +/** Current PDMIOMMUHLPR3 version number. */ +#define PDM_IOMMUHLPR3_VERSION PDM_VERSION_MAKE(0xff15, 5, 0) + + +/** + * Programmable Interrupt Controller registration structure (all contexts). + */ +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). + * @remarks Caller enters the PDM critical section. + */ + DECLCALLBACKMEMBER(void, pfnSetIrq,(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. + * @remarks Caller enters the PDM critical section. + */ + DECLCALLBACKMEMBER(int, pfnGetInterrupt,(PPDMDEVINS pDevIns, uint32_t *puTagSrc)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMPICREG; +/** Pointer to a PIC registration structure. */ +typedef PDMPICREG *PPDMPICREG; + +/** Current PDMPICREG version number. */ +#define PDM_PICREG_VERSION PDM_VERSION_MAKE(0xfffa, 3, 0) + +/** + * PIC helpers, same in all contexts. + */ +typedef struct PDMPICHLP +{ + /** 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. + */ + DECLCALLBACKMEMBER(void, pfnSetInterruptFF,(PPDMDEVINS pDevIns)); + + /** + * Clear the interrupt force action flag. + * + * @param pDevIns Device instance of the PIC. + */ + DECLCALLBACKMEMBER(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. + * + * @sa PDMCritSectEnter + */ + DECLCALLBACKMEMBER(int, pfnLock,(PPDMDEVINS pDevIns, int rc)); + + /** + * Releases the PDM lock. + * + * @param pDevIns The PIC device instance. + */ + DECLCALLBACKMEMBER(void, pfnUnlock,(PPDMDEVINS pDevIns)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMPICHLP; +/** Pointer to PIC helpers. */ +typedef PDMPICHLP *PPDMPICHLP; +/** Pointer to const PIC helpers. */ +typedef const PDMPICHLP *PCPDMPICHLP; + +/** Current PDMPICHLP version number. */ +#define PDM_PICHLP_VERSION PDM_VERSION_MAKE(0xfff9, 3, 0) + + +/** + * Firmware registration structure. + */ +typedef struct PDMFWREG +{ + /** Struct version+magic number (PDM_FWREG_VERSION). */ + uint32_t u32Version; + + /** + * Checks whether this is a hard or soft reset. + * + * The current definition of soft reset is what the PC BIOS does when CMOS[0xF] + * is 5, 9 or 0xA. + * + * @returns true if hard reset, false if soft. + * @param pDevIns Device instance of the firmware. + * @param fFlags PDMRESET_F_XXX passed to the PDMDevHlpVMReset API. + */ + DECLR3CALLBACKMEMBER(bool, pfnIsHardReset,(PPDMDEVINS pDevIns, uint32_t fFlags)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMFWREG; +/** Pointer to a FW registration structure. */ +typedef PDMFWREG *PPDMFWREG; +/** Pointer to a const FW registration structure. */ +typedef PDMFWREG const *PCPDMFWREG; + +/** Current PDMFWREG version number. */ +#define PDM_FWREG_VERSION PDM_VERSION_MAKE(0xffdd, 1, 0) + +/** + * Firmware R3 helpers. + */ +typedef struct PDMFWHLPR3 +{ + /** Structure version. PDM_FWHLP_VERSION defines the current version. */ + uint32_t u32Version; + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMFWHLPR3; + +/** Pointer to FW R3 helpers. */ +typedef R3PTRTYPE(PDMFWHLPR3 *) PPDMFWHLPR3; +/** Pointer to const FW R3 helpers. */ +typedef R3PTRTYPE(const PDMFWHLPR3 *) PCPDMFWHLPR3; + +/** Current PDMFWHLPR3 version number. */ +#define PDM_FWHLPR3_VERSION PDM_VERSION_MAKE(0xffdb, 1, 0) + + +/** + * APIC mode argument for apicR3SetCpuIdFeatureLevel. + * + * Also used in saved-states, CFGM don't change existing values. + */ +typedef enum PDMAPICMODE +{ + /** Invalid 0 entry. */ + PDMAPICMODE_INVALID = 0, + /** No APIC. */ + PDMAPICMODE_NONE, + /** Standard APIC (X86_CPUID_FEATURE_EDX_APIC). */ + PDMAPICMODE_APIC, + /** Intel X2APIC (X86_CPUID_FEATURE_ECX_X2APIC). */ + PDMAPICMODE_X2APIC, + /** The usual 32-bit paranoia. */ + PDMAPICMODE_32BIT_HACK = 0x7fffffff +} PDMAPICMODE; + +/** + * APIC irq argument for pfnSetInterruptFF and pfnClearInterruptFF. + */ +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, + /** Interrupt arrived, needs to be updated to the IRR. */ + PDMAPICIRQ_UPDATE_PENDING, + /** The usual 32-bit paranoia. */ + PDMAPICIRQ_32BIT_HACK = 0x7fffffff +} PDMAPICIRQ; + + +/** + * I/O APIC registration structure (all contexts). + */ +typedef struct PDMIOAPICREG +{ + /** Struct version+magic number (PDM_IOAPICREG_VERSION). */ + uint32_t u32Version; + + /** + * Set an IRQ. + * + * @param pDevIns Device instance of the I/O APIC. + * @param uBusDevFn The bus:device:function of the device initiating the + * IRQ. Can be NIL_PCIBDF. + * @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). + * + * @remarks Caller enters the PDM critical section + * Actually, as per 2018-07-21 this isn't true (bird). + */ + DECLCALLBACKMEMBER(void, pfnSetIrq,(PPDMDEVINS pDevIns, PCIBDF uBusDevFn, int iIrq, int iLevel, uint32_t uTagSrc)); + + /** + * Send a MSI. + * + * @param pDevIns Device instance of the I/O APIC. + * @param uBusDevFn The bus:device:function of the device initiating the + * MSI. Cannot be NIL_PCIBDF. + * @param pMsi The MSI to send. + * @param uTagSrc The IRQ tag and source (for tracing). + * + * @remarks Caller enters the PDM critical section + * Actually, as per 2018-07-21 this isn't true (bird). + */ + DECLCALLBACKMEMBER(void, pfnSendMsi,(PPDMDEVINS pDevIns, PCIBDF uBusDevFn, PCMSIMSG pMsi, uint32_t uTagSrc)); + + /** + * Set the EOI for an interrupt vector. + * + * @param pDevIns Device instance of the I/O APIC. + * @param u8Vector The vector. + * + * @remarks Caller enters the PDM critical section + * Actually, as per 2018-07-21 this isn't true (bird). + */ + DECLCALLBACKMEMBER(void, pfnSetEoi,(PPDMDEVINS pDevIns, uint8_t u8Vector)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMIOAPICREG; +/** Pointer to an APIC registration structure. */ +typedef PDMIOAPICREG *PPDMIOAPICREG; + +/** Current PDMAPICREG version number. */ +#define PDM_IOAPICREG_VERSION PDM_VERSION_MAKE(0xfff2, 8, 0) + + +/** + * IOAPIC helpers, same in all contexts. + */ +typedef struct PDMIOAPICHLP +{ + /** Structure version. PDM_IOAPICHLP_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Private interface between the IOAPIC and APIC. + * + * @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 uVector See APIC implementation. + * @param u8Polarity See APIC implementation. + * @param u8TriggerMode See APIC implementation. + * @param uTagSrc The IRQ tag and source (for tracing). + * + * @sa APICBusDeliver() + */ + DECLCALLBACKMEMBER(int, pfnApicBusDeliver,(PPDMDEVINS pDevIns, uint8_t u8Dest, uint8_t u8DestMode, uint8_t u8DeliveryMode, + uint8_t uVector, 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. + * + * @sa PDMCritSectEnter + */ + DECLCALLBACKMEMBER(int, pfnLock,(PPDMDEVINS pDevIns, int rc)); + + /** + * Releases the PDM lock. + * + * @param pDevIns The IOAPIC device instance. + */ + DECLCALLBACKMEMBER(void, pfnUnlock,(PPDMDEVINS pDevIns)); + + /** + * Checks if the calling thread owns the PDM lock. + * + * @param pDevIns The IOAPIC device instance. + */ + DECLCALLBACKMEMBER(bool, pfnLockIsOwner,(PPDMDEVINS pDevIns)); + + /** + * Private interface between the IOAPIC and IOMMU. + * + * @returns status code. + * @param pDevIns Device instance of the IOAPIC. + * @param idDevice The device identifier (bus, device, function). + * @param pMsiIn The source MSI. + * @param pMsiOut Where to store the remapped MSI (only updated when + * VINF_SUCCESS is returned). + */ + DECLCALLBACKMEMBER(int, pfnIommuMsiRemap,(PPDMDEVINS pDevIns, uint16_t idDevice, PCMSIMSG pMsiIn, PMSIMSG pMsiOut)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMIOAPICHLP; +/** Pointer to IOAPIC helpers. */ +typedef PDMIOAPICHLP * PPDMIOAPICHLP; +/** Pointer to const IOAPIC helpers. */ +typedef const PDMIOAPICHLP * PCPDMIOAPICHLP; + +/** Current PDMIOAPICHLP version number. */ +#define PDM_IOAPICHLP_VERSION PDM_VERSION_MAKE(0xfff0, 3, 1) + + +/** + * 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; + + /** + * 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 iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + */ + 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, 3, 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 The device instance that registered the handler. + * @param pvUser User pointer. + * @param uChannel Channel number. + * @param off DMA position. + * @param cb Block size. + * @remarks The device lock is take before the callback (in fact, the locks of + * DMA devices and the DMA controller itself are taken). + */ +typedef DECLCALLBACKTYPE(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. + * @remarks No locks held, called on EMT(0) as a form of serialization. + */ + DECLR3CALLBACKMEMBER(bool, pfnRun,(PPDMDEVINS pDevIns)); + + /** + * Register transfer function for DMA channel. + * + * @param pDevIns Device instance of the DMAC. + * @param uChannel Channel number. + * @param pDevInsHandler The device instance of the device making the + * regstration (will be passed to the callback). + * @param pfnTransferHandler Device specific transfer function. + * @param pvUser User pointer to be passed to the callback. + * @remarks No locks held, called on an EMT. + */ + DECLR3CALLBACKMEMBER(void, pfnRegister,(PPDMDEVINS pDevIns, unsigned uChannel, PPDMDEVINS pDevInsHandler, + PFNDMATRANSFERHANDLER pfnTransferHandler, void *pvUser)); + + /** + * Read memory + * + * @returns Number of bytes read. + * @param pDevIns Device instance of the DMAC. + * @param uChannel Channel number. + * @param pvBuffer Pointer to target buffer. + * @param off DMA position. + * @param cbBlock Block size. + * @remarks No locks held, called on an EMT. + */ + 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 uChannel Channel number. + * @param pvBuffer Memory to write. + * @param off DMA position. + * @param cbBlock Block size. + * @remarks No locks held, called on an EMT. + */ + 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. + * @remarks No locks held, called on an EMT. + */ + 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. + * @remarks No locks held, called on an EMT. + */ + 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, 2, 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. + * @remarks Caller enters the device critical section. + */ + 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. + * @remarks Caller enters the device critical section. + */ + 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, 2, 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) + + + +/** @name Flags for PCI I/O region registration + * @{ */ +/** No handle is passed. */ +#define PDMPCIDEV_IORGN_F_NO_HANDLE UINT32_C(0x00000000) +/** An I/O port handle is passed. */ +#define PDMPCIDEV_IORGN_F_IOPORT_HANDLE UINT32_C(0x00000001) +/** An MMIO range handle is passed. */ +#define PDMPCIDEV_IORGN_F_MMIO_HANDLE UINT32_C(0x00000002) +/** An MMIO2 handle is passed. */ +#define PDMPCIDEV_IORGN_F_MMIO2_HANDLE UINT32_C(0x00000003) +/** Handle type mask. */ +#define PDMPCIDEV_IORGN_F_HANDLE_MASK UINT32_C(0x00000003) +/** New-style (mostly wrt callbacks). */ +#define PDMPCIDEV_IORGN_F_NEW_STYLE UINT32_C(0x00000004) +/** Mask of valid flags. */ +#define PDMPCIDEV_IORGN_F_VALID_MASK UINT32_C(0x00000007) +/** @} */ + + +/** @name Flags for the guest physical read/write helpers + * @{ */ +/** Default flag with no indication whether the data is processed by the device or just passed through. */ +#define PDM_DEVHLP_PHYS_RW_F_DEFAULT UINT32_C(0x00000000) +/** The data is user data which is just passed through between the guest and the source or destination and not processed + * by the device in any way. */ +#define PDM_DEVHLP_PHYS_RW_F_DATA_USER RT_BIT_32(0) +/** The data is metadata and being processed by the device in some way. */ +#define PDM_DEVHLP_PHYS_RW_F_DATA_META RT_BIT_32(1) +/** @} */ + + +#ifdef IN_RING3 + +/** @name Special values for PDMDEVHLPR3::pfnPCIRegister parameters. + * @{ */ +/** Same device number (and bus) as the previous PCI device registered with the PDM device. + * This is handy when registering multiple PCI device functions and the device + * number is left up to the PCI bus. In order to facilitate one PDM device + * instance for each PCI function, this searches earlier PDM device + * instances as well. */ +# define PDMPCIDEVREG_DEV_NO_SAME_AS_PREV UINT8_C(0xfd) +/** Use the first unused device number (all functions must be unused). */ +# define PDMPCIDEVREG_DEV_NO_FIRST_UNUSED UINT8_C(0xfe) +/** Use the first unused device function. */ +# define PDMPCIDEVREG_FUN_NO_FIRST_UNUSED UINT8_C(0xff) + +/** The device and function numbers are not mandatory, just suggestions. */ +# define PDMPCIDEVREG_F_NOT_MANDATORY_NO RT_BIT_32(0) +/** Registering a PCI bridge device. */ +# define PDMPCIDEVREG_F_PCI_BRIDGE RT_BIT_32(1) +/** Valid flag mask. */ +# define PDMPCIDEVREG_F_VALID_MASK UINT32_C(0x00000003) +/** @} */ + +/** Current PDMDEVHLPR3 version number. */ +#define PDM_DEVHLPR3_VERSION PDM_VERSION_MAKE_PP(0xffe7, 65, 0) + +/** + * PDM Device API. + */ +typedef struct PDMDEVHLPR3 +{ + /** Structure version. PDM_DEVHLPR3_VERSION defines the current version. */ + uint32_t u32Version; + + /** @name I/O ports + * @{ */ + /** + * Creates a range of I/O ports for a device. + * + * The I/O port range must be mapped in a separately call. Any ring-0 and + * raw-mode context callback handlers needs to be set up in the respective + * contexts. + * + * @returns VBox status. + * @param pDevIns The device instance to register the ports with. + * @param cPorts Number of ports to register. + * @param fFlags IOM_IOPORT_F_XXX. + * @param pPciDev The PCI device the range is associated with, if + * applicable. + * @param iPciRegion The PCI device region in the high 16-bit word and + * sub-region in the low 16-bit word. UINT32_MAX if NA. + * @param pfnOut Pointer to function which is gonna handle OUT + * operations. Optional. + * @param pfnIn Pointer to function which is gonna handle IN operations. + * Optional. + * @param pfnOutStr Pointer to function which is gonna handle string OUT + * operations. Optional. + * @param pfnInStr Pointer to function which is gonna handle string IN + * operations. Optional. + * @param pvUser User argument to pass to the callbacks. + * @param pszDesc Pointer to description string. This must not be freed. + * @param paExtDescs Extended per-port descriptions, optional. Partial range + * coverage is allowed. This must not be freed. + * @param phIoPorts Where to return the I/O port range handle. + * + * @remarks Caller enters the device critical section prior to invoking the + * registered callback methods. + * + * @sa PDMDevHlpIoPortSetUpContext, PDMDevHlpIoPortMap, + * PDMDevHlpIoPortUnmap. + */ + DECLR3CALLBACKMEMBER(int, pfnIoPortCreateEx,(PPDMDEVINS pDevIns, RTIOPORT cPorts, uint32_t fFlags, PPDMPCIDEV pPciDev, + uint32_t iPciRegion, PFNIOMIOPORTNEWOUT pfnOut, PFNIOMIOPORTNEWIN pfnIn, + PFNIOMIOPORTNEWOUTSTRING pfnOutStr, PFNIOMIOPORTNEWINSTRING pfnInStr, RTR3PTR pvUser, + const char *pszDesc, PCIOMIOPORTDESC paExtDescs, PIOMIOPORTHANDLE phIoPorts)); + + /** + * Maps an I/O port range. + * + * @returns VBox status. + * @param pDevIns The device instance to register the ports with. + * @param hIoPorts The I/O port range handle. + * @param Port Where to map the range. + * @sa PDMDevHlpIoPortUnmap, PDMDevHlpIoPortSetUpContext, + * PDMDevHlpIoPortCreate, PDMDevHlpIoPortCreateEx. + */ + DECLR3CALLBACKMEMBER(int, pfnIoPortMap,(PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts, RTIOPORT Port)); + + /** + * Unmaps an I/O port range. + * + * @returns VBox status. + * @param pDevIns The device instance to register the ports with. + * @param hIoPorts The I/O port range handle. + * @sa PDMDevHlpIoPortMap, PDMDevHlpIoPortSetUpContext, + * PDMDevHlpIoPortCreate, PDMDevHlpIoPortCreateEx. + */ + DECLR3CALLBACKMEMBER(int, pfnIoPortUnmap,(PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts)); + + /** + * Gets the mapping address of the I/O port range @a hIoPorts. + * + * @returns Mapping address (0..65535) or UINT32_MAX if not mapped (or invalid + * parameters). + * @param pDevIns The device instance to register the ports with. + * @param hIoPorts The I/O port range handle. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnIoPortGetMappingAddress,(PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts)); + + /** + * Writes to an I/O port register. + * + * @returns Strict VBox status code. Informational status codes other than the one documented + * here are to be treated as internal failure. Use IOM_SUCCESS() to check for success. + * @retval VINF_SUCCESS Success. + * @retval VINF_EM_FIRST-VINF_EM_LAST Success with some exceptions (see IOM_SUCCESS()), the + * status code must be passed on to EM. + * + * @param pDevIns The device instance to register the ports with. + * @param Port The port to write to. + * @param u32Value The value to write. + * @param cbValue The size of the register to read in bytes. 1, 2 or 4 bytes. + * + * @thread EMT + * @todo r=aeichner This is only used by DevPCI.cpp to write the ELCR of the PIC. This shouldn't be done that way + * and removed again as soon as possible (no time right now)... + */ + DECLR3CALLBACKMEMBER(VBOXSTRICTRC, pfnIoPortWrite,(PPDMDEVINS pDevIns, RTIOPORT Port, uint32_t u32Value, size_t cbValue)); + /** @} */ + + /** @name MMIO + * @{ */ + /** + * Creates a memory mapped I/O (MMIO) region for a device. + * + * The MMIO region must be mapped in a separately call. Any ring-0 and + * raw-mode context callback handlers needs to be set up in the respective + * contexts. + * + * @returns VBox status. + * @param pDevIns The device instance to register the ports with. + * @param cbRegion The size of the region in bytes. + * @param fFlags Flags, IOMMMIO_FLAGS_XXX. + * @param pPciDev The PCI device the range is associated with, if + * applicable. + * @param iPciRegion The PCI device region in the high 16-bit word and + * sub-region in the low 16-bit word. UINT32_MAX if NA. + * @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 pvUser User argument to pass to the callbacks. + * @param pszDesc Pointer to description string. This must not be freed. + * @param phRegion Where to return the MMIO region handle. + * + * @remarks Caller enters the device critical section prior to invoking the + * registered callback methods. + * + * @sa PDMDevHlpMmioSetUpContext, PDMDevHlpMmioMap, PDMDevHlpMmioUnmap. + */ + DECLR3CALLBACKMEMBER(int, pfnMmioCreateEx,(PPDMDEVINS pDevIns, RTGCPHYS cbRegion, + uint32_t fFlags, PPDMPCIDEV pPciDev, uint32_t iPciRegion, + PFNIOMMMIONEWWRITE pfnWrite, PFNIOMMMIONEWREAD pfnRead, PFNIOMMMIONEWFILL pfnFill, + void *pvUser, const char *pszDesc, PIOMMMIOHANDLE phRegion)); + + /** + * Maps a memory mapped I/O (MMIO) region (into the guest physical address space). + * + * @returns VBox status. + * @param pDevIns The device instance the region is associated with. + * @param hRegion The MMIO region handle. + * @param GCPhys Where to map the region. + * @note An MMIO 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 + * technically incorrect but it's just not worth the effort to do + * right, at least not at this point. + * @sa PDMDevHlpMmioUnmap, PDMDevHlpMmioCreate, PDMDevHlpMmioCreateEx, + * PDMDevHlpMmioSetUpContext + */ + DECLR3CALLBACKMEMBER(int, pfnMmioMap,(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS GCPhys)); + + /** + * Unmaps a memory mapped I/O (MMIO) region. + * + * @returns VBox status. + * @param pDevIns The device instance the region is associated with. + * @param hRegion The MMIO region handle. + * @sa PDMDevHlpMmioMap, PDMDevHlpMmioCreate, PDMDevHlpMmioCreateEx, + * PDMDevHlpMmioSetUpContext + */ + DECLR3CALLBACKMEMBER(int, pfnMmioUnmap,(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion)); + + /** + * Reduces the length of a MMIO range. + * + * This is for implementations of PDMPCIDEV::pfnRegionLoadChangeHookR3 and will + * only work during saved state restore. It will not call the PCI bus code, as + * that is expected to restore the saved resource configuration. + * + * It just adjusts the mapping length of the region so that when pfnMmioMap is + * called it will only map @a cbRegion bytes and not the value set during + * registration. + * + * @return VBox status code. + * @param pDevIns The device owning the range. + * @param hRegion The MMIO region handle. + * @param cbRegion The new size, must be smaller. + */ + DECLR3CALLBACKMEMBER(int, pfnMmioReduce,(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS cbRegion)); + + /** + * Gets the mapping address of the MMIO region @a hRegion. + * + * @returns Mapping address, NIL_RTGCPHYS if not mapped (or invalid parameters). + * @param pDevIns The device instance to register the ports with. + * @param hRegion The MMIO region handle. + */ + DECLR3CALLBACKMEMBER(RTGCPHYS, pfnMmioGetMappingAddress,(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion)); + /** @} */ + + /** @name MMIO2 + * @{ */ + /** + * Creates 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 pPciDev The PCI device the region is associated with, or + * NULL if no PCI device association. + * @param iPciRegion 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 cbRegion The size (in bytes) of the region. + * @param fFlags PGMPHYS_MMIO2_FLAGS_XXX (see pgm.h). + * @param pszDesc Pointer to description string. This must not be + * freed. + * @param ppvMapping Where to store the address of the ring-3 mapping + * of the memory. + * @param phRegion Where to return the MMIO2 region handle. + * + * @thread EMT(0) + */ + DECLR3CALLBACKMEMBER(int, pfnMmio2Create,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iPciRegion, RTGCPHYS cbRegion, + uint32_t fFlags, const char *pszDesc, void **ppvMapping, PPGMMMIO2HANDLE phRegion)); + + /** + * Destroys a MMIO2 region, unmapping it and freeing the memory. + * + * Any physical access handlers registered for the region must be deregistered + * before calling this function. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param hRegion The MMIO2 region handle. + * @thread EMT. + */ + DECLR3CALLBACKMEMBER(int, pfnMmio2Destroy,(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion)); + + /** + * Maps a MMIO2 region (into the guest physical address space). + * + * @returns VBox status. + * @param pDevIns The device instance the region is associated with. + * @param hRegion The MMIO2 region handle. + * @param GCPhys Where to map the region. + * @note A MMIO2 region 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 + * technically incorrect but it's just not worth the effort to do + * right, at least not at this point. + * @sa PDMDevHlpMmio2Unmap, PDMDevHlpMmio2Create, PDMDevHlpMmio2SetUpContext + */ + DECLR3CALLBACKMEMBER(int, pfnMmio2Map,(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion, RTGCPHYS GCPhys)); + + /** + * Unmaps a MMIO2 region. + * + * @returns VBox status. + * @param pDevIns The device instance the region is associated with. + * @param hRegion The MMIO2 region handle. + * @sa PDMDevHlpMmio2Map, PDMDevHlpMmio2Create, PDMDevHlpMmio2SetUpContext + */ + DECLR3CALLBACKMEMBER(int, pfnMmio2Unmap,(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion)); + + /** + * Reduces the length of a MMIO range. + * + * This is for implementations of PDMPCIDEV::pfnRegionLoadChangeHookR3 and will + * only work during saved state restore. It will not call the PCI bus code, as + * that is expected to restore the saved resource configuration. + * + * It just adjusts the mapping length of the region so that when pfnMmioMap is + * called it will only map @a cbRegion bytes and not the value set during + * registration. + * + * @return VBox status code. + * @param pDevIns The device owning the range. + * @param hRegion The MMIO2 region handle. + * @param cbRegion The new size, must be smaller. + */ + DECLR3CALLBACKMEMBER(int, pfnMmio2Reduce,(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion, RTGCPHYS cbRegion)); + + /** + * Gets the mapping address of the MMIO region @a hRegion. + * + * @returns Mapping address, NIL_RTGCPHYS if not mapped (or invalid parameters). + * @param pDevIns The device instance to register the ports with. + * @param hRegion The MMIO2 region handle. + */ + DECLR3CALLBACKMEMBER(RTGCPHYS, pfnMmio2GetMappingAddress,(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion)); + + /** + * Queries and resets the dirty bitmap for an MMIO2 region. + * + * The MMIO2 region must have been created with the + * PGMPHYS_MMIO2_FLAGS_TRACK_DIRTY_PAGES flag for this to work. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param hRegion The MMIO2 region handle. + * @param pvBitmap Where to return the bitmap. Must be 8-byte aligned. + * Can be NULL if only resetting the tracking is desired. + * @param cbBitmap The bitmap size. One bit per page in the region, + * rounded up to 8-bytes. If pvBitmap is NULL this must + * also be zero. + */ + DECLR3CALLBACKMEMBER(int, pfnMmio2QueryAndResetDirtyBitmap, (PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion, + void *pvBitmap, size_t cbBitmap)); + + /** + * Controls the dirty page tracking for an MMIO2 region. + * + * The MMIO2 region must have been created with the + * PGMPHYS_MMIO2_FLAGS_TRACK_DIRTY_PAGES flag for this to work. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param hRegion The MMIO2 region handle. + * @param fEnabled When set to @c true the dirty page tracking will be + * enabled if currently disabled (bitmap is reset). When + * set to @c false the dirty page tracking will be + * disabled. + */ + DECLR3CALLBACKMEMBER(int, pfnMmio2ControlDirtyPageTracking, (PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion, bool fEnabled)); + + /** + * Changes the number of an MMIO2 or pre-registered MMIO region. + * + * This should only be used to deal with saved state problems, so there is no + * convenience inline wrapper for this method. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param hRegion The MMIO2 region handle. + * @param iNewRegion The new region index. + * + * @sa @bugref{9359} + */ + DECLR3CALLBACKMEMBER(int, pfnMmio2ChangeRegionNo,(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion, uint32_t iNewRegion)); + + /** + * Mapping an MMIO2 page in place of an MMIO page for direct access. + * + * This is a special optimization used by the VGA device. Call + * PDMDevHlpMmioResetRegion() to undo the mapping. + * + * @returns VBox status code. This API may return VINF_SUCCESS even if no + * remapping is made. + * @retval VERR_SEM_BUSY in ring-0 if we cannot get the IOM lock. + * + * @param pDevIns The device instance @a hRegion and @a hMmio2 are + * associated with. + * @param hRegion The handle to the MMIO region. + * @param offRegion The offset into @a hRegion of the page to be + * remapped. + * @param hMmio2 The MMIO2 handle. + * @param offMmio2 Offset into @a hMmio2 of the page to be use for the + * mapping. + * @param fPageFlags Page flags to set. Must be (X86_PTE_RW | X86_PTE_P) + * for the time being. + */ + DECLR3CALLBACKMEMBER(int, pfnMmioMapMmio2Page,(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS offRegion, + uint64_t hMmio2, RTGCPHYS offMmio2, uint64_t fPageFlags)); + + /** + * Reset a previously modified MMIO region; restore the access flags. + * + * This undoes the effects of PDMDevHlpMmioMapMmio2Page() and is currently only + * intended for some ancient VGA hack. However, it would be great to extend it + * beyond VT-x and/or nested-paging. + * + * @returns VBox status code. + * + * @param pDevIns The device instance @a hRegion is associated with. + * @param hRegion The handle to the MMIO region. + */ + DECLR3CALLBACKMEMBER(int, pfnMmioResetRegion, (PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion)); + /** @} */ + + /** + * 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 PGMPHYS_ROM_FLAGS_XXX (see 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 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. + * @remarks Caller enters the device critical section prior to invoking the + * registered callback methods. + */ + 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)); + + /** + * Register a save state data unit for backward compatibility. + * + * This is for migrating from an old device name to a new one or for merging + * devices. It will only help loading old saved states. + * + * @returns VBox status. + * @param pDevIns The device instance. + * @param pszOldName The old unit name. + * @param pfnLoadPrep Prepare load callback, optional. + * @param pfnLoadExec Execute load callback, optional. + * @param pfnLoadDone Done load callback, optional. + * @remarks Caller enters the device critical section prior to invoking the + * registered callback methods. + */ + DECLR3CALLBACKMEMBER(int, pfnSSMRegisterLegacy,(PPDMDEVINS pDevIns, const char *pszOldName, PFNSSMDEVLOADPREP pfnLoadPrep, + PFNSSMDEVLOADEXEC pfnLoadExec, PFNSSMDEVLOADDONE pfnLoadDone)); + + /** @name Exported SSM Functions + * @{ */ + DECLR3CALLBACKMEMBER(int, pfnSSMPutStruct,(PSSMHANDLE pSSM, const void *pvStruct, PCSSMFIELD paFields)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutStructEx,(PSSMHANDLE pSSM, const void *pvStruct, size_t cbStruct, uint32_t fFlags, PCSSMFIELD paFields, void *pvUser)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutBool,(PSSMHANDLE pSSM, bool fBool)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU8,(PSSMHANDLE pSSM, uint8_t u8)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS8,(PSSMHANDLE pSSM, int8_t i8)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU16,(PSSMHANDLE pSSM, uint16_t u16)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS16,(PSSMHANDLE pSSM, int16_t i16)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU32,(PSSMHANDLE pSSM, uint32_t u32)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS32,(PSSMHANDLE pSSM, int32_t i32)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU64,(PSSMHANDLE pSSM, uint64_t u64)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS64,(PSSMHANDLE pSSM, int64_t i64)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU128,(PSSMHANDLE pSSM, uint128_t u128)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS128,(PSSMHANDLE pSSM, int128_t i128)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutUInt,(PSSMHANDLE pSSM, RTUINT u)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutSInt,(PSSMHANDLE pSSM, RTINT i)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCUInt,(PSSMHANDLE pSSM, RTGCUINT u)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCUIntReg,(PSSMHANDLE pSSM, RTGCUINTREG u)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCPhys32,(PSSMHANDLE pSSM, RTGCPHYS32 GCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCPhys64,(PSSMHANDLE pSSM, RTGCPHYS64 GCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCPhys,(PSSMHANDLE pSSM, RTGCPHYS GCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCPtr,(PSSMHANDLE pSSM, RTGCPTR GCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCUIntPtr,(PSSMHANDLE pSSM, RTGCUINTPTR GCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutRCPtr,(PSSMHANDLE pSSM, RTRCPTR RCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutIOPort,(PSSMHANDLE pSSM, RTIOPORT IOPort)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutSel,(PSSMHANDLE pSSM, RTSEL Sel)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutMem,(PSSMHANDLE pSSM, const void *pv, size_t cb)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutStrZ,(PSSMHANDLE pSSM, const char *psz)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetStruct,(PSSMHANDLE pSSM, void *pvStruct, PCSSMFIELD paFields)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetStructEx,(PSSMHANDLE pSSM, void *pvStruct, size_t cbStruct, uint32_t fFlags, PCSSMFIELD paFields, void *pvUser)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetBool,(PSSMHANDLE pSSM, bool *pfBool)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetBoolV,(PSSMHANDLE pSSM, bool volatile *pfBool)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU8,(PSSMHANDLE pSSM, uint8_t *pu8)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU8V,(PSSMHANDLE pSSM, uint8_t volatile *pu8)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS8,(PSSMHANDLE pSSM, int8_t *pi8)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS8V,(PSSMHANDLE pSSM, int8_t volatile *pi8)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU16,(PSSMHANDLE pSSM, uint16_t *pu16)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU16V,(PSSMHANDLE pSSM, uint16_t volatile *pu16)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS16,(PSSMHANDLE pSSM, int16_t *pi16)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS16V,(PSSMHANDLE pSSM, int16_t volatile *pi16)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU32,(PSSMHANDLE pSSM, uint32_t *pu32)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU32V,(PSSMHANDLE pSSM, uint32_t volatile *pu32)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS32,(PSSMHANDLE pSSM, int32_t *pi32)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS32V,(PSSMHANDLE pSSM, int32_t volatile *pi32)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU64,(PSSMHANDLE pSSM, uint64_t *pu64)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU64V,(PSSMHANDLE pSSM, uint64_t volatile *pu64)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS64,(PSSMHANDLE pSSM, int64_t *pi64)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS64V,(PSSMHANDLE pSSM, int64_t volatile *pi64)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU128,(PSSMHANDLE pSSM, uint128_t *pu128)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU128V,(PSSMHANDLE pSSM, uint128_t volatile *pu128)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS128,(PSSMHANDLE pSSM, int128_t *pi128)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS128V,(PSSMHANDLE pSSM, int128_t volatile *pi128)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys32,(PSSMHANDLE pSSM, PRTGCPHYS32 pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys32V,(PSSMHANDLE pSSM, RTGCPHYS32 volatile *pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys64,(PSSMHANDLE pSSM, PRTGCPHYS64 pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys64V,(PSSMHANDLE pSSM, RTGCPHYS64 volatile *pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys,(PSSMHANDLE pSSM, PRTGCPHYS pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhysV,(PSSMHANDLE pSSM, RTGCPHYS volatile *pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetUInt,(PSSMHANDLE pSSM, PRTUINT pu)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetSInt,(PSSMHANDLE pSSM, PRTINT pi)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCUInt,(PSSMHANDLE pSSM, PRTGCUINT pu)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCUIntReg,(PSSMHANDLE pSSM, PRTGCUINTREG pu)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPtr,(PSSMHANDLE pSSM, PRTGCPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCUIntPtr,(PSSMHANDLE pSSM, PRTGCUINTPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetRCPtr,(PSSMHANDLE pSSM, PRTRCPTR pRCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetIOPort,(PSSMHANDLE pSSM, PRTIOPORT pIOPort)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetSel,(PSSMHANDLE pSSM, PRTSEL pSel)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetMem,(PSSMHANDLE pSSM, void *pv, size_t cb)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetStrZ,(PSSMHANDLE pSSM, char *psz, size_t cbMax)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetStrZEx,(PSSMHANDLE pSSM, char *psz, size_t cbMax, size_t *pcbStr)); + DECLR3CALLBACKMEMBER(int, pfnSSMSkip,(PSSMHANDLE pSSM, size_t cb)); + DECLR3CALLBACKMEMBER(int, pfnSSMSkipToEndOfUnit,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(int, pfnSSMSetLoadError,(PSSMHANDLE pSSM, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(6, 7)); + DECLR3CALLBACKMEMBER(int, pfnSSMSetLoadErrorV,(PSSMHANDLE pSSM, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(6, 0)); + DECLR3CALLBACKMEMBER(int, pfnSSMSetCfgError,(PSSMHANDLE pSSM, RT_SRC_POS_DECL, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(5, 6)); + DECLR3CALLBACKMEMBER(int, pfnSSMSetCfgErrorV,(PSSMHANDLE pSSM, RT_SRC_POS_DECL, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(5, 0)); + DECLR3CALLBACKMEMBER(int, pfnSSMHandleGetStatus,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(SSMAFTER, pfnSSMHandleGetAfter,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(bool, pfnSSMHandleIsLiveSave,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(uint32_t, pfnSSMHandleMaxDowntime,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(uint32_t, pfnSSMHandleHostBits,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(uint32_t, pfnSSMHandleRevision,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(uint32_t, pfnSSMHandleVersion,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(const char *, pfnSSMHandleHostOSAndArch,(PSSMHANDLE pSSM)); + /** @} */ + + /** + * Creates a timer w/ a cross context handle. + * + * @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 phTimer Where to store the timer handle on success. + * @remarks Caller enters the device critical section prior to invoking the + * callback. + */ + DECLR3CALLBACKMEMBER(int, pfnTimerCreate,(PPDMDEVINS pDevIns, TMCLOCK enmClock, PFNTMTIMERDEV pfnCallback, + void *pvUser, uint32_t fFlags, const char *pszDesc, PTMTIMERHANDLE phTimer)); + + /** @name Timer handle method wrappers + * @{ */ + DECLR3CALLBACKMEMBER(uint64_t, pfnTimerFromMicro,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cMicroSecs)); + DECLR3CALLBACKMEMBER(uint64_t, pfnTimerFromMilli,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cMilliSecs)); + DECLR3CALLBACKMEMBER(uint64_t, pfnTimerFromNano,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cNanoSecs)); + DECLR3CALLBACKMEMBER(uint64_t, pfnTimerGet,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + DECLR3CALLBACKMEMBER(uint64_t, pfnTimerGetFreq,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + DECLR3CALLBACKMEMBER(uint64_t, pfnTimerGetNano,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + DECLR3CALLBACKMEMBER(bool, pfnTimerIsActive,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + DECLR3CALLBACKMEMBER(bool, pfnTimerIsLockOwner,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + DECLR3CALLBACKMEMBER(VBOXSTRICTRC, pfnTimerLockClock,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, int rcBusy)); + /** Takes the clock lock then enters the specified critical section. */ + DECLR3CALLBACKMEMBER(VBOXSTRICTRC, pfnTimerLockClock2,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect, int rcBusy)); + DECLR3CALLBACKMEMBER(int, pfnTimerSet,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t uExpire)); + DECLR3CALLBACKMEMBER(int, pfnTimerSetFrequencyHint,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint32_t uHz)); + DECLR3CALLBACKMEMBER(int, pfnTimerSetMicro,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cMicrosToNext)); + DECLR3CALLBACKMEMBER(int, pfnTimerSetMillies,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cMilliesToNext)); + DECLR3CALLBACKMEMBER(int, pfnTimerSetNano,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cNanosToNext)); + DECLR3CALLBACKMEMBER(int, pfnTimerSetRelative,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cTicksToNext, uint64_t *pu64Now)); + DECLR3CALLBACKMEMBER(int, pfnTimerStop,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + DECLR3CALLBACKMEMBER(void, pfnTimerUnlockClock,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + DECLR3CALLBACKMEMBER(void, pfnTimerUnlockClock2,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(int, pfnTimerSetCritSect,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(int, pfnTimerSave,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(int, pfnTimerLoad,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(int, pfnTimerDestroy,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + /** @sa TMR3TimerSkip */ + DECLR3CALLBACKMEMBER(int, pfnTimerSkipLoad,(PSSMHANDLE pSSM, bool *pfActive)); + /** @} */ + + /** + * 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)); + + /** @name Exported CFGM Functions. + * @{ */ + DECLR3CALLBACKMEMBER(bool, pfnCFGMExists,( PCFGMNODE pNode, const char *pszName)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryType,( PCFGMNODE pNode, const char *pszName, PCFGMVALUETYPE penmType)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQuerySize,( PCFGMNODE pNode, const char *pszName, size_t *pcb)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryInteger,( PCFGMNODE pNode, const char *pszName, uint64_t *pu64)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryIntegerDef,( PCFGMNODE pNode, const char *pszName, uint64_t *pu64, uint64_t u64Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryString,( PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryStringDef,( PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString, const char *pszDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryPassword,( PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryPasswordDef,( PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString, const char *pszDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryBytes,( PCFGMNODE pNode, const char *pszName, void *pvData, size_t cbData)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU64,( PCFGMNODE pNode, const char *pszName, uint64_t *pu64)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU64Def,( PCFGMNODE pNode, const char *pszName, uint64_t *pu64, uint64_t u64Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS64,( PCFGMNODE pNode, const char *pszName, int64_t *pi64)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS64Def,( PCFGMNODE pNode, const char *pszName, int64_t *pi64, int64_t i64Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU32,( PCFGMNODE pNode, const char *pszName, uint32_t *pu32)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU32Def,( PCFGMNODE pNode, const char *pszName, uint32_t *pu32, uint32_t u32Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS32,( PCFGMNODE pNode, const char *pszName, int32_t *pi32)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS32Def,( PCFGMNODE pNode, const char *pszName, int32_t *pi32, int32_t i32Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU16,( PCFGMNODE pNode, const char *pszName, uint16_t *pu16)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU16Def,( PCFGMNODE pNode, const char *pszName, uint16_t *pu16, uint16_t u16Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS16,( PCFGMNODE pNode, const char *pszName, int16_t *pi16)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS16Def,( PCFGMNODE pNode, const char *pszName, int16_t *pi16, int16_t i16Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU8,( PCFGMNODE pNode, const char *pszName, uint8_t *pu8)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU8Def,( PCFGMNODE pNode, const char *pszName, uint8_t *pu8, uint8_t u8Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS8,( PCFGMNODE pNode, const char *pszName, int8_t *pi8)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS8Def,( PCFGMNODE pNode, const char *pszName, int8_t *pi8, int8_t i8Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryBool,( PCFGMNODE pNode, const char *pszName, bool *pf)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryBoolDef,( PCFGMNODE pNode, const char *pszName, bool *pf, bool fDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryPort,( PCFGMNODE pNode, const char *pszName, PRTIOPORT pPort)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryPortDef,( PCFGMNODE pNode, const char *pszName, PRTIOPORT pPort, RTIOPORT PortDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryUInt,( PCFGMNODE pNode, const char *pszName, unsigned int *pu)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryUIntDef,( PCFGMNODE pNode, const char *pszName, unsigned int *pu, unsigned int uDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQuerySInt,( PCFGMNODE pNode, const char *pszName, signed int *pi)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQuerySIntDef,( PCFGMNODE pNode, const char *pszName, signed int *pi, signed int iDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtr,( PCFGMNODE pNode, const char *pszName, PRTGCPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrDef,( PCFGMNODE pNode, const char *pszName, PRTGCPTR pGCPtr, RTGCPTR GCPtrDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrU,( PCFGMNODE pNode, const char *pszName, PRTGCUINTPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrUDef,( PCFGMNODE pNode, const char *pszName, PRTGCUINTPTR pGCPtr, RTGCUINTPTR GCPtrDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrS,( PCFGMNODE pNode, const char *pszName, PRTGCINTPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrSDef,( PCFGMNODE pNode, const char *pszName, PRTGCINTPTR pGCPtr, RTGCINTPTR GCPtrDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryStringAlloc,( PCFGMNODE pNode, const char *pszName, char **ppszString)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryStringAllocDef,(PCFGMNODE pNode, const char *pszName, char **ppszString, const char *pszDef)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetParent,(PCFGMNODE pNode)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetChild,(PCFGMNODE pNode, const char *pszPath)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetChildF,(PCFGMNODE pNode, const char *pszPathFormat, ...) RT_IPRT_FORMAT_ATTR(2, 3)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetChildFV,(PCFGMNODE pNode, const char *pszPathFormat, va_list Args) RT_IPRT_FORMAT_ATTR(3, 0)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetFirstChild,(PCFGMNODE pNode)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetNextChild,(PCFGMNODE pCur)); + DECLR3CALLBACKMEMBER(int, pfnCFGMGetName,(PCFGMNODE pCur, char *pszName, size_t cchName)); + DECLR3CALLBACKMEMBER(size_t, pfnCFGMGetNameLen,(PCFGMNODE pCur)); + DECLR3CALLBACKMEMBER(bool, pfnCFGMAreChildrenValid,(PCFGMNODE pNode, const char *pszzValid)); + DECLR3CALLBACKMEMBER(PCFGMLEAF, pfnCFGMGetFirstValue,(PCFGMNODE pCur)); + DECLR3CALLBACKMEMBER(PCFGMLEAF, pfnCFGMGetNextValue,(PCFGMLEAF pCur)); + DECLR3CALLBACKMEMBER(int, pfnCFGMGetValueName,(PCFGMLEAF pCur, char *pszName, size_t cchName)); + DECLR3CALLBACKMEMBER(size_t, pfnCFGMGetValueNameLen,(PCFGMLEAF pCur)); + DECLR3CALLBACKMEMBER(CFGMVALUETYPE, pfnCFGMGetValueType,(PCFGMLEAF pCur)); + DECLR3CALLBACKMEMBER(bool, pfnCFGMAreValuesValid,(PCFGMNODE pNode, const char *pszzValid)); + DECLR3CALLBACKMEMBER(int, pfnCFGMValidateConfig,(PCFGMNODE pNode, const char *pszNode, + const char *pszValidValues, const char *pszValidNodes, + const char *pszWho, uint32_t uInstance)); + /** @} */ + + /** + * 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. + * @param fFlags Combination of PDM_DEVHLP_PHYS_RW_F_XXX. + * @thread Any thread, but the call may involve the emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPhysRead,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead, uint32_t fFlags)); + + /** + * 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. + * @param fFlags Combination of PDM_DEVHLP_PHYS_RW_F_XXX. + * @thread Any thread, but the call may involve the emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPhysWrite,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite, uint32_t fFlags)); + + /** + * 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 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 (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)); + + /** + * Checks if a GC physical address is a normal page, + * i.e. not ROM, MMIO or reserved. + * + * @returns true if normal. + * @returns false if invalid, ROM, MMIO or reserved page. + * @param pDevIns The device instance. + * @param GCPhys The physical address to check. + */ + DECLR3CALLBACKMEMBER(bool, pfnPhysIsGCPhysNormal,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys)); + + /** + * Inflate or deflate a memory balloon + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param fInflate Inflate or deflate memory balloon + * @param cPages Number of pages to free + * @param paPhysPage Array of guest physical addresses + */ + DECLR3CALLBACKMEMBER(int, pfnPhysChangeMemBalloon,(PPDMDEVINS pDevIns, bool fInflate, unsigned cPages, RTGCPHYS *paPhysPage)); + + /** + * 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)); + + /** + * Allocating string printf. + * + * @returns Pointer to the string. + * @param pDevIns The device instance. + * @param enmTag The statistics tag. + * @param pszFormat The format string. + * @param va Format arguments. + */ + DECLR3CALLBACKMEMBER(char *, pfnMMHeapAPrintfV,(PPDMDEVINS pDevIns, MMTAG enmTag, const char *pszFormat, va_list va)); + + /** + * 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)); + + /** + * Returns the physical RAM size of the VM. + * + * @returns RAM size in bytes. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnMMPhysGetRamSize,(PPDMDEVINS pDevIns)); + + /** + * Returns the physical RAM size of the VM below the 4GB boundary. + * + * @returns RAM size in bytes. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnMMPhysGetRamSizeBelow4GB,(PPDMDEVINS pDevIns)); + + /** + * Returns the physical RAM size of the VM above the 4GB boundary. + * + * @returns RAM size in bytes. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnMMPhysGetRamSizeAbove4GB,(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). + */ + 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 SRC_POS 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) RT_IPRT_FORMAT_ATTR(6, 0)); + + /** + * 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) RT_IPRT_FORMAT_ATTR(4, 0)); + + /** + * Special interface for implementing a HLT-like port on a device. + * + * This can be called directly from device code, provide the device is trusted + * to access the VMM directly. Since we may not have an accurate register set + * and the caller certainly shouldn't (device code does not access CPU + * registers), this function will return when interrupts are pending regardless + * of the actual EFLAGS.IF state. + * + * @returns VBox error status (never informational statuses). + * @param pDevIns The device instance. + * @param idCpu The id of the calling EMT. + */ + DECLR3CALLBACKMEMBER(int, pfnVMWaitForDeviceReady,(PPDMDEVINS pDevIns, VMCPUID idCpu)); + + /** + * Wakes up a CPU that has called PDMDEVHLPR3::pfnVMWaitForDeviceReady. + * + * @returns VBox error status (never informational statuses). + * @param pDevIns The device instance. + * @param idCpu The id of the calling EMT. + */ + DECLR3CALLBACKMEMBER(int, pfnVMNotifyCpuDeviceReady,(PPDMDEVINS pDevIns, VMCPUID idCpu)); + + /** + * Convenience wrapper for VMR3ReqCallU. + * + * This assumes (1) you're calling a function that returns an VBox status code + * and that you do not wish to wait for it to complete. + * + * @returns VBox status code returned by VMR3ReqCallVU. + * + * @param pDevIns The device instance. + * @param idDstCpu The destination CPU(s). Either a specific CPU ID or + * one of the following special values: + * VMCPUID_ANY, VMCPUID_ANY_QUEUE, VMCPUID_ALL or VMCPUID_ALL_REVERSE. + * @param pfnFunction Pointer to the function to call. + * @param cArgs Number of arguments following in the ellipsis. + * @param Args Argument vector. + * + * @remarks See remarks on VMR3ReqCallVU. + */ + DECLR3CALLBACKMEMBER(int, pfnVMReqCallNoWaitV,(PPDMDEVINS pDevIns, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, va_list Args)); + + /** + * Convenience wrapper for VMR3ReqCallU. + * + * This assumes (1) you're calling a function that returns void, (2) that you + * wish to wait for ever for it to return, and (3) that it's priority request + * that can be safely be handled during async suspend and power off. + * + * @returns VBox status code of VMR3ReqCallVU. + * + * @param pDevIns The device instance. + * @param idDstCpu The destination CPU(s). Either a specific CPU ID or + * one of the following special values: + * VMCPUID_ANY, VMCPUID_ANY_QUEUE, VMCPUID_ALL or VMCPUID_ALL_REVERSE. + * @param pfnFunction Pointer to the function to call. + * @param cArgs Number of arguments following in the ellipsis. + * @param Args Argument vector. + * + * @remarks See remarks on VMR3ReqCallVU. + */ + DECLR3CALLBACKMEMBER(int, pfnVMReqPriorityCallWaitV,(PPDMDEVINS pDevIns, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, va_list Args)); + + /** + * 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) RT_IPRT_FORMAT_ATTR(5, 0)); + + /** + * 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)); + + /** + * Register a info handler with DBGF, argv style. + * + * @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, pfnDBGFInfoRegisterArgv,(PPDMDEVINS pDevIns, const char *pszName, const char *pszDesc, PFNDBGFINFOARGVDEV pfnHandler)); + + /** + * Registers a set of registers for a device. + * + * The @a pvUser argument of the getter and setter callbacks will be + * @a pDevIns. The register names will be prefixed by the device name followed + * immediately by the instance number. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param paRegisters The register descriptors. + * + * @remarks The device critical section is NOT entered prior to working the + * callbacks registered via this helper! + */ + DECLR3CALLBACKMEMBER(int, pfnDBGFRegRegister,(PPDMDEVINS pDevIns, PCDBGFREGDESC paRegisters)); + + /** + * 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)); + + /** + * Report a bug check. + * + * @returns + * @param pDevIns The device instance. + * @param enmEvent The kind of BSOD event this is. + * @param uBugCheck The bug check number. + * @param uP1 The bug check parameter \#1. + * @param uP2 The bug check parameter \#2. + * @param uP3 The bug check parameter \#3. + * @param uP4 The bug check parameter \#4. + * + * @thread EMT + */ + DECLR3CALLBACKMEMBER(VBOXSTRICTRC, pfnDBGFReportBugCheck,(PPDMDEVINS pDevIns, DBGFEVENTTYPE enmEvent, uint64_t uBugCheck, + uint64_t uP1, uint64_t uP2, uint64_t uP3, uint64_t uP4)); + + /** + * Write core dump of the guest. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pszFilename The name of the file to which the guest core + * dump should be written. + * @param fReplaceFile Whether to replace the file or not. + * + * @remarks The VM may need to be suspended before calling this function in + * order to truly stop all device threads and drivers. This function + * only synchronizes EMTs. + */ + DECLR3CALLBACKMEMBER(int, pfnDBGFCoreWrite,(PPDMDEVINS pDevIns, const char *pszFilename, bool fReplaceFile)); + + /** + * Gets the logger info helper. + * The returned info helper will unconditionally write all output to the log. + * + * @returns Pointer to the logger info helper. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(PCDBGFINFOHLP, pfnDBGFInfoLogHlp,(PPDMDEVINS pDevIns)); + + /** + * Queries a 64-bit register value. + * + * @retval VINF_SUCCESS + * @retval VERR_INVALID_VM_HANDLE + * @retval VERR_INVALID_CPU_ID + * @retval VERR_DBGF_REGISTER_NOT_FOUND + * @retval VERR_DBGF_UNSUPPORTED_CAST + * @retval VINF_DBGF_TRUNCATED_REGISTER + * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER + * + * @param pDevIns The device instance. + * @param idDefCpu The default target CPU ID, VMCPUID_ANY if not + * applicable. Can be OR'ed with + * DBGFREG_HYPER_VMCPUID. + * @param pszReg The register that's being queried. Except for + * CPU registers, this must be on the form + * "set.reg[.sub]". + * @param pu64 Where to store the register value. + */ + DECLR3CALLBACKMEMBER(int, pfnDBGFRegNmQueryU64,(PPDMDEVINS pDevIns, VMCPUID idDefCpu, const char *pszReg, uint64_t *pu64)); + + /** + * Format a set of registers. + * + * This is restricted to registers from one CPU, that specified by @a idCpu. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param idCpu The CPU ID of any CPU registers that may be + * printed, pass VMCPUID_ANY if not applicable. + * @param pszBuf The output buffer. + * @param cbBuf The size of the output buffer. + * @param pszFormat The format string. Register names are given by + * %VR{name}, they take no arguments. + * @param va Other format arguments. + */ + DECLR3CALLBACKMEMBER(int, pfnDBGFRegPrintfV,(PPDMDEVINS pDevIns, VMCPUID idCpu, char *pszBuf, size_t cbBuf, + const char *pszFormat, va_list va)); + + /** + * Registers a statistics sample. + * + * @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, unix path style. If this does not + * start with a '/', the default prefix will be + * prepended, otherwise it will be used as-is. + * @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 + * 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 Sample name format string, unix path style. If + * this does not start with a '/', the default + * prefix will be prepended, otherwise it will be + * used as-is. + * @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) RT_IPRT_FORMAT_ATTR(7, 0)); + + /** + * Registers a PCI device with the default PCI bus. + * + * If a PDM device has more than one PCI device, they must be registered in the + * order of PDMDEVINSR3::apPciDevs. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. + * This must be kept in the instance data. + * The PCI configuration must be initialized before registration. + * @param fFlags 0, PDMPCIDEVREG_F_PCI_BRIDGE or + * PDMPCIDEVREG_F_NOT_MANDATORY_NO. + * @param uPciDevNo PDMPCIDEVREG_DEV_NO_FIRST_UNUSED, + * PDMPCIDEVREG_DEV_NO_SAME_AS_PREV, or a specific + * device number (0-31). This will be ignored if + * the CFGM configuration contains a PCIDeviceNo + * value. + * @param uPciFunNo PDMPCIDEVREG_FUN_NO_FIRST_UNUSED, or a specific + * function number (0-7). This will be ignored if + * the CFGM configuration contains a PCIFunctionNo + * value. + * @param pszName Device name, if NULL PDMDEVREG::szName is used. + * The pointer is saved, so don't free or changed. + * @note The PCI device configuration is now implicit from the apPciDevs + * index, meaning that the zero'th entry is the primary one and + * subsequent uses CFGM subkeys "PciDev1", "PciDev2" and so on. + */ + DECLR3CALLBACKMEMBER(int, pfnPCIRegister,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t fFlags, + uint8_t uPciDevNo, uint8_t uPciFunNo, const char *pszName)); + + /** + * Initialize MSI or MSI-X emulation support for the given PCI device. + * + * @see PDMPCIBUSREG::pfnRegisterMsiR3 for details. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPciDev The PCI device. NULL is an alias for the first + * one registered. + * @param pMsiReg MSI emulation registration structure. + */ + DECLR3CALLBACKMEMBER(int, pfnPCIRegisterMsi,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, 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 pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @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 fFlags PDMPCIDEV_IORGN_F_XXX. + * @param hHandle An I/O port, MMIO or MMIO2 handle according to + * @a fFlags, UINT64_MAX if no handle is passed + * (old style). + * @param pfnMapUnmap Callback for doing the mapping, optional when a + * handle is specified. The callback will be + * invoked holding only the PDM lock. The device + * lock will _not_ be taken (due to lock order). + */ + DECLR3CALLBACKMEMBER(int, pfnPCIIORegionRegister,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, + RTGCPHYS cbRegion, PCIADDRESSSPACE enmType, uint32_t fFlags, + uint64_t hHandle, PFNPCIIOREGIONMAP pfnMapUnmap)); + + /** + * Register PCI configuration space read/write callbacks. + * + * @returns VBox status code. + * @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. + * to call default PCI config read function. Can be NULL. + * @param pfnWrite Pointer to the user defined PCI config write function. + * @remarks The callbacks will be invoked holding the PDM lock. The device lock + * is NOT take because that is very likely be a lock order violation. + * @thread EMT(0) + * @note Only callable during VM creation. + * @sa PDMDevHlpPCIConfigRead, PDMDevHlpPCIConfigWrite + */ + DECLR3CALLBACKMEMBER(int, pfnPCIInterceptConfigAccesses,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, + PFNPCICONFIGREAD pfnRead, PFNPCICONFIGWRITE pfnWrite)); + + /** + * Perform a PCI configuration space write. + * + * This is for devices that make use of PDMDevHlpPCIInterceptConfigAccesses(). + * + * @returns Strict VBox status code (mainly DBGFSTOP). + * @param pDevIns The device instance. + * @param pPciDev The PCI device which config space is being read. + * @param uAddress The config space address. + * @param cb The size of the read: 1, 2 or 4 bytes. + * @param u32Value The value to write. + */ + DECLR3CALLBACKMEMBER(VBOXSTRICTRC, pfnPCIConfigWrite,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, + uint32_t uAddress, unsigned cb, uint32_t u32Value)); + + /** + * Perform a PCI configuration space read. + * + * This is for devices that make use of PDMDevHlpPCIInterceptConfigAccesses(). + * + * @returns Strict VBox status code (mainly DBGFSTOP). + * @param pDevIns The device instance. + * @param pPciDev The PCI device which config space is being read. + * @param uAddress The config space address. + * @param cb The size of the read: 1, 2 or 4 bytes. + * @param pu32Value Where to return the value. + */ + DECLR3CALLBACKMEMBER(VBOXSTRICTRC, pfnPCIConfigRead,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, + uint32_t uAddress, unsigned cb, uint32_t *pu32Value)); + + /** + * Bus master physical memory read. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_READ_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param GCPhys Physical address start reading from. + * @param pvBuf Where to put the read bits. + * @param cbRead How many bytes to read. + * @param fFlags Combination of PDM_DEVHLP_PHYS_RW_F_XXX. + * @thread Any thread, but the call may involve the emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPCIPhysRead,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead, uint32_t fFlags)); + + /** + * Bus master physical memory write. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_WRITE_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param GCPhys Physical address to write to. + * @param pvBuf What to write. + * @param cbWrite How many bytes to write. + * @param fFlags Combination of PDM_DEVHLP_PHYS_RW_F_XXX. + * @thread Any thread, but the call may involve the emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPCIPhysWrite,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite, uint32_t fFlags)); + + /** + * Requests the mapping of a guest page into ring-3 in preparation for a bus master + * physical memory write operation. + * + * Refer pfnPhysGCPhys2CCPtr() for further details. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @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. + * + * @remarks 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, pfnPCIPhysGCPhys2CCPtr,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, uint32_t fFlags, + void **ppv, PPGMPAGEMAPLOCK pLock)); + + /** + * Requests the mapping of a guest page into ring-3, external threads, in prepartion + * for a bus master physical memory read operation. + * + * Refer pfnPhysGCPhys2CCPtrReadOnly() for further details. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @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. + * + * @remarks Avoid calling this API from within critical sections. + * @thread Any. + */ + DECLR3CALLBACKMEMBER(int, pfnPCIPhysGCPhys2CCPtrReadOnly,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, + uint32_t fFlags, void const **ppv, PPGMPAGEMAPLOCK pLock)); + + /** + * Requests the mapping of multiple guest pages into ring-3 in prepartion for a bus + * master physical memory write operation. + * + * When you're done with the pages, call pfnPhysBulkReleasePageMappingLocks() + * ASAP to release them. + * + * Refer pfnPhysBulkGCPhys2CCPtr() for further details. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param cPages Number of pages to lock. + * @param paGCPhysPages The guest physical address of the pages that + * should be mapped (@a cPages entries). + * @param fFlags Flags reserved for future use, MBZ. + * @param papvPages Where to store the ring-3 mapping addresses + * corresponding to @a paGCPhysPages. + * @param paLocks Where to store the locking information that + * pfnPhysBulkReleasePageMappingLock needs (@a cPages + * in length). + */ + DECLR3CALLBACKMEMBER(int, pfnPCIPhysBulkGCPhys2CCPtr,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t cPages, + PCRTGCPHYS paGCPhysPages, uint32_t fFlags, void **papvPages, + PPGMPAGEMAPLOCK paLocks)); + + /** + * Requests the mapping of multiple guest pages into ring-3 in preparation for a bus + * master physical memory read operation. + * + * When you're done with the pages, call pfnPhysBulkReleasePageMappingLocks() + * ASAP to release them. + * + * Refer pfnPhysBulkGCPhys2CCPtrReadOnly() for further details. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param cPages Number of pages to lock. + * @param paGCPhysPages The guest physical address of the pages that + * should be mapped (@a cPages entries). + * @param fFlags Flags reserved for future use, MBZ. + * @param papvPages Where to store the ring-3 mapping addresses + * corresponding to @a paGCPhysPages. + * @param paLocks Where to store the lock information that + * pfnPhysReleasePageMappingLock needs (@a cPages + * in length). + */ + DECLR3CALLBACKMEMBER(int, pfnPCIPhysBulkGCPhys2CCPtrReadOnly,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t cPages, + PCRTGCPHYS paGCPhysPages, uint32_t fFlags, + void const **papvPages, PPGMPAGEMAPLOCK paLocks)); + + /** + * Sets the IRQ for the given PCI device. + * + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @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, PPDMPCIDEV pPciDev, int iIrq, int iLevel)); + + /** + * Sets the IRQ for the given PCI device, but doesn't wait for EMT to process + * the request when not called from EMT. + * + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. + * @thread Any thread, but will involve the emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnPCISetIrqNoWait,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, 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 registration 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)); + + /** + * Detaches an attached driver (chain) from the device again. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pDrvIns The driver instance to detach. + * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines. + */ + DECLR3CALLBACKMEMBER(int, pfnDriverDetach,(PPDMDEVINS pDevIns, PPDMDRVINS pDrvIns, uint32_t fFlags)); + + /** + * Reconfigures the driver chain for a LUN, detaching any driver currently + * present there. + * + * Caller will have attach it, of course. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param iLun The logical unit to reconfigure. + * @param cDepth The depth of the driver chain. Determins the + * size of @a papszDrivers and @a papConfigs. + * @param papszDrivers The names of the drivers to configure in the + * chain, first entry is the one immediately + * below the device/LUN + * @param papConfigs The configurations for each of the drivers + * in @a papszDrivers array. NULL entries + * corresponds to empty 'Config' nodes. This + * function will take ownership of non-NULL + * CFGM sub-trees and set the array member to + * NULL, so the caller can do cleanups on + * failure. This parameter is optional. + * @param fFlags Reserved, MBZ. + */ + DECLR3CALLBACKMEMBER(int, pfnDriverReconfigure,(PPDMDEVINS pDevIns, uint32_t iLun, uint32_t cDepth, + const char * const *papszDrivers, PCFGMNODE *papConfigs, uint32_t fFlags)); + + /** @name Exported PDM Queue Functions + * @{ */ + /** + * 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 phQueue Where to store the queue handle on success. + * @thread EMT(0) + * @remarks The device critical section will NOT be entered before calling the + * callback. No locks will be held, but for now it's safe to assume + * that only one EMT will do queue callbacks at any one time. + */ + DECLR3CALLBACKMEMBER(int, pfnQueueCreate,(PPDMDEVINS pDevIns, size_t cbItem, uint32_t cItems, uint32_t cMilliesInterval, + PFNPDMQUEUEDEV pfnCallback, bool fRZEnabled, const char *pszName, + PDMQUEUEHANDLE *phQueue)); + + DECLR3CALLBACKMEMBER(PPDMQUEUEITEMCORE, pfnQueueAlloc,(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue)); + DECLR3CALLBACKMEMBER(int, pfnQueueInsert,(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue, PPDMQUEUEITEMCORE pItem)); + DECLR3CALLBACKMEMBER(bool, pfnQueueFlushIfNecessary,(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue)); + /** @} */ + + /** @name PDM Task + * @{ */ + /** + * Create an asynchronous ring-3 task. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param fFlags PDMTASK_F_XXX + * @param pszName The function name or similar. Used for statistics, + * so no slashes. + * @param pfnCallback The task function. + * @param pvUser User argument for the task function. + * @param phTask Where to return the task handle. + * @thread EMT(0) + */ + DECLR3CALLBACKMEMBER(int, pfnTaskCreate,(PPDMDEVINS pDevIns, uint32_t fFlags, const char *pszName, + PFNPDMTASKDEV pfnCallback, void *pvUser, PDMTASKHANDLE *phTask)); + /** + * Triggers the running the given task. + * + * @returns VBox status code. + * @retval VINF_ALREADY_POSTED is the task is already pending. + * @param pDevIns The device instance. + * @param hTask The task to trigger. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnTaskTrigger,(PPDMDEVINS pDevIns, PDMTASKHANDLE hTask)); + /** @} */ + + /** @name SUP Event Semaphore Wrappers (single release / auto reset) + * These semaphores can be signalled from ring-0. + * @{ */ + /** @sa SUPSemEventCreate */ + DECLR3CALLBACKMEMBER(int, pfnSUPSemEventCreate,(PPDMDEVINS pDevIns, PSUPSEMEVENT phEvent)); + /** @sa SUPSemEventClose */ + DECLR3CALLBACKMEMBER(int, pfnSUPSemEventClose,(PPDMDEVINS pDevIns, SUPSEMEVENT hEvent)); + /** @sa SUPSemEventSignal */ + DECLR3CALLBACKMEMBER(int, pfnSUPSemEventSignal,(PPDMDEVINS pDevIns, SUPSEMEVENT hEvent)); + /** @sa SUPSemEventWaitNoResume */ + DECLR3CALLBACKMEMBER(int, pfnSUPSemEventWaitNoResume,(PPDMDEVINS pDevIns, SUPSEMEVENT hEvent, uint32_t cMillies)); + /** @sa SUPSemEventWaitNsAbsIntr */ + DECLR3CALLBACKMEMBER(int, pfnSUPSemEventWaitNsAbsIntr,(PPDMDEVINS pDevIns, SUPSEMEVENT hEvent, uint64_t uNsTimeout)); + /** @sa SUPSemEventWaitNsRelIntr */ + DECLR3CALLBACKMEMBER(int, pfnSUPSemEventWaitNsRelIntr,(PPDMDEVINS pDevIns, SUPSEMEVENT hEvent, uint64_t cNsTimeout)); + /** @sa SUPSemEventGetResolution */ + DECLR3CALLBACKMEMBER(uint32_t, pfnSUPSemEventGetResolution,(PPDMDEVINS pDevIns)); + /** @} */ + + /** @name SUP Multi Event Semaphore Wrappers (multiple release / manual reset) + * These semaphores can be signalled from ring-0. + * @{ */ + /** @sa SUPSemEventMultiCreate */ + DECLR3CALLBACKMEMBER(int, pfnSUPSemEventMultiCreate,(PPDMDEVINS pDevIns, PSUPSEMEVENTMULTI phEventMulti)); + /** @sa SUPSemEventMultiClose */ + DECLR3CALLBACKMEMBER(int, pfnSUPSemEventMultiClose,(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti)); + /** @sa SUPSemEventMultiSignal */ + DECLR3CALLBACKMEMBER(int, pfnSUPSemEventMultiSignal,(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti)); + /** @sa SUPSemEventMultiReset */ + DECLR3CALLBACKMEMBER(int, pfnSUPSemEventMultiReset,(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti)); + /** @sa SUPSemEventMultiWaitNoResume */ + DECLR3CALLBACKMEMBER(int, pfnSUPSemEventMultiWaitNoResume,(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti, uint32_t cMillies)); + /** @sa SUPSemEventMultiWaitNsAbsIntr */ + DECLR3CALLBACKMEMBER(int, pfnSUPSemEventMultiWaitNsAbsIntr,(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti, uint64_t uNsTimeout)); + /** @sa SUPSemEventMultiWaitNsRelIntr */ + DECLR3CALLBACKMEMBER(int, pfnSUPSemEventMultiWaitNsRelIntr,(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti, uint64_t cNsTimeout)); + /** @sa SUPSemEventMultiGetResolution */ + DECLR3CALLBACKMEMBER(uint32_t, pfnSUPSemEventMultiGetResolution,(PPDMDEVINS pDevIns)); + /** @} */ + + /** + * 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 SRC_POS 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) RT_IPRT_FORMAT_ATTR(6, 0)); + + /** + * 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)); + + /** + * Changes the device level critical section from the automatically created + * default to one desired by the device constructor. + * + * For ring-0 and raw-mode capable devices, the call must be repeated in each of + * the additional contexts. + * + * @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)); + + /** @name Exported PDM Critical Section Functions + * @{ */ + DECLR3CALLBACKMEMBER(bool, pfnCritSectYield,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(int, pfnCritSectEnter,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, int rcBusy)); + DECLR3CALLBACKMEMBER(int, pfnCritSectEnterDebug,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR3CALLBACKMEMBER(int, pfnCritSectTryEnter,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(int, pfnCritSectTryEnterDebug,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR3CALLBACKMEMBER(int, pfnCritSectLeave,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(bool, pfnCritSectIsOwner,(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(bool, pfnCritSectIsInitialized,(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(bool, pfnCritSectHasWaiters,(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(uint32_t, pfnCritSectGetRecursion,(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(int, pfnCritSectScheduleExitEvent,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, SUPSEMEVENT hEventToSignal)); + DECLR3CALLBACKMEMBER(int, pfnCritSectDelete,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect)); + /** @} */ + + /** @name Exported PDM Read/Write Critical Section Functions + * @{ */ + DECLR3CALLBACKMEMBER(int, pfnCritSectRwInit,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, RT_SRC_POS_DECL, + const char *pszNameFmt, va_list va) RT_IPRT_FORMAT_ATTR(6, 0)); + DECLR3CALLBACKMEMBER(int, pfnCritSectRwDelete,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + + DECLR3CALLBACKMEMBER(int, pfnCritSectRwEnterShared,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy)); + DECLR3CALLBACKMEMBER(int, pfnCritSectRwEnterSharedDebug,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR3CALLBACKMEMBER(int, pfnCritSectRwTryEnterShared,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLR3CALLBACKMEMBER(int, pfnCritSectRwTryEnterSharedDebug,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR3CALLBACKMEMBER(int, pfnCritSectRwLeaveShared,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + + DECLR3CALLBACKMEMBER(int, pfnCritSectRwEnterExcl,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy)); + DECLR3CALLBACKMEMBER(int, pfnCritSectRwEnterExclDebug,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR3CALLBACKMEMBER(int, pfnCritSectRwTryEnterExcl,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLR3CALLBACKMEMBER(int, pfnCritSectRwTryEnterExclDebug,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR3CALLBACKMEMBER(int, pfnCritSectRwLeaveExcl,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + + DECLR3CALLBACKMEMBER(bool, pfnCritSectRwIsWriteOwner,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLR3CALLBACKMEMBER(bool, pfnCritSectRwIsReadOwner,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, bool fWannaHear)); + DECLR3CALLBACKMEMBER(uint32_t, pfnCritSectRwGetWriteRecursion,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLR3CALLBACKMEMBER(uint32_t, pfnCritSectRwGetWriterReadRecursion,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLR3CALLBACKMEMBER(uint32_t, pfnCritSectRwGetReadCount,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLR3CALLBACKMEMBER(bool, pfnCritSectRwIsInitialized,(PPDMDEVINS pDevIns, PPDMCRITSECTRW 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. + * @remarks The device critical section will NOT be entered prior to invoking + * the function pointers. + */ + DECLR3CALLBACKMEMBER(int, pfnThreadCreate,(PPDMDEVINS pDevIns, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADDEV pfnThread, + PFNPDMTHREADWAKEUPDEV pfnWakeup, size_t cbStack, RTTHREADTYPE enmType, const char *pszName)); + + /** @name Exported PDM Thread Functions + * @{ */ + DECLR3CALLBACKMEMBER(int, pfnThreadDestroy,(PPDMTHREAD pThread, int *pRcThread)); + DECLR3CALLBACKMEMBER(int, pfnThreadIAmSuspending,(PPDMTHREAD pThread)); + DECLR3CALLBACKMEMBER(int, pfnThreadIAmRunning,(PPDMTHREAD pThread)); + DECLR3CALLBACKMEMBER(int, pfnThreadSleep,(PPDMTHREAD pThread, RTMSINTERVAL cMillies)); + DECLR3CALLBACKMEMBER(int, pfnThreadSuspend,(PPDMTHREAD pThread)); + DECLR3CALLBACKMEMBER(int, pfnThreadResume,(PPDMTHREAD pThread)); + /** @} */ + + /** + * 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) + * @remarks The caller will enter the device critical section prior to invoking + * the callback. + */ + 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 a PCI Bus. + * + * @returns VBox status code, but the positive values 0..31 are used to indicate + * bus number rather than informational status codes. + * @param pDevIns The device instance. + * @param pPciBusReg Pointer to PCI bus registration structure. + * @param ppPciHlp Where to store the pointer to the PCI Bus + * helpers. + * @param piBus Where to return the PDM bus number. Optional. + */ + DECLR3CALLBACKMEMBER(int, pfnPCIBusRegister,(PPDMDEVINS pDevIns, PPDMPCIBUSREGR3 pPciBusReg, + PCPDMPCIHLPR3 *ppPciHlp, uint32_t *piBus)); + + /** + * Register the IOMMU device. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pIommuReg Pointer to a IOMMU registration structure. + * @param ppIommuHlp Where to store the pointer to the ring-3 IOMMU + * helpers. + * @param pidxIommu Where to return the IOMMU index. Optional. + */ + DECLR3CALLBACKMEMBER(int, pfnIommuRegister,(PPDMDEVINS pDevIns, PPDMIOMMUREGR3 pIommuReg, PCPDMIOMMUHLPR3 *ppIommuHlp, + uint32_t *pidxIommu)); + + /** + * Register the PIC device. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPicReg Pointer to a PIC registration structure. + * @param ppPicHlp Where to store the pointer to the ring-3 PIC + * helpers. + * @sa PDMDevHlpPICSetUpContext + */ + DECLR3CALLBACKMEMBER(int, pfnPICRegister,(PPDMDEVINS pDevIns, PPDMPICREG pPicReg, PCPDMPICHLP *ppPicHlp)); + + /** + * Register the APIC device. + * + * @returns VBox status code. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(int, pfnApicRegister,(PPDMDEVINS pDevIns)); + + /** + * 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 ppIoApicHlp Where to store the pointer to the IOAPIC + * helpers. + */ + DECLR3CALLBACKMEMBER(int, pfnIoApicRegister,(PPDMDEVINS pDevIns, PPDMIOAPICREG pIoApicReg, PCPDMIOAPICHLP *ppIoApicHlp)); + + /** + * 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 pPciRawReg 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)); + + /** + * Calls the PDMDEVREGR0::pfnRequest callback (in ring-0 context). + * + * @returns VBox status code. + * @retval VERR_INVALID_FUNCTION if the callback member is NULL. + * @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)); + + /** + * Gets the reason for the most recent VM suspend. + * + * @returns The suspend reason. VMSUSPENDREASON_INVALID is returned if no + * suspend has been made or if the pDevIns is invalid. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(VMSUSPENDREASON, pfnVMGetSuspendReason,(PPDMDEVINS pDevIns)); + + /** + * Gets the reason for the most recent VM resume. + * + * @returns The resume reason. VMRESUMEREASON_INVALID is returned if no + * resume has been made or if the pDevIns is invalid. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(VMRESUMEREASON, pfnVMGetResumeReason,(PPDMDEVINS pDevIns)); + + /** + * Requests the mapping of multiple guest page into ring-3. + * + * When you're done with the pages, call pfnPhysBulkReleasePageMappingLocks() + * ASAP to release them. + * + * This API will assume your intention is to write to the pages, and will + * therefore replace shared and zero pages. If you do not intend to modify the + * pages, use the pfnPhysBulkGCPhys2CCPtrReadOnly() API. + * + * @returns VBox status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_PGM_PHYS_PAGE_RESERVED if any of the pages has no physical + * backing or if any of the pages the page has any active access + * handlers. The caller must fall back on using PGMR3PhysWriteExternal. + * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if @a paGCPhysPages contains + * an invalid physical address. + * + * @param pDevIns The device instance. + * @param cPages Number of pages to lock. + * @param paGCPhysPages The guest physical address of the pages that + * should be mapped (@a cPages entries). + * @param fFlags Flags reserved for future use, MBZ. + * @param papvPages Where to store the ring-3 mapping addresses + * corresponding to @a paGCPhysPages. + * @param paLocks Where to store the locking information that + * pfnPhysBulkReleasePageMappingLock needs (@a cPages + * in length). + * + * @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. + * @since 6.0.6 + */ + DECLR3CALLBACKMEMBER(int, pfnPhysBulkGCPhys2CCPtr,(PPDMDEVINS pDevIns, uint32_t cPages, PCRTGCPHYS paGCPhysPages, + uint32_t fFlags, void **papvPages, PPGMPAGEMAPLOCK paLocks)); + + /** + * Requests the mapping of multiple guest page into ring-3, for reading only. + * + * When you're done with the pages, call pfnPhysBulkReleasePageMappingLocks() + * ASAP to release them. + * + * @returns VBox status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_PGM_PHYS_PAGE_RESERVED if any of the pages has no physical + * backing or if any of the pages the page has an active ALL access + * handler. The caller must fall back on using PGMR3PhysWriteExternal. + * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if @a paGCPhysPages contains + * an invalid physical address. + * + * @param pDevIns The device instance. + * @param cPages Number of pages to lock. + * @param paGCPhysPages The guest physical address of the pages that + * should be mapped (@a cPages entries). + * @param fFlags Flags reserved for future use, MBZ. + * @param papvPages Where to store the ring-3 mapping addresses + * corresponding to @a paGCPhysPages. + * @param paLocks Where to store the lock information that + * pfnPhysReleasePageMappingLock needs (@a cPages + * in length). + * + * @remark Avoid calling this API from within critical sections. + * @thread Any. + * @since 6.0.6 + */ + DECLR3CALLBACKMEMBER(int, pfnPhysBulkGCPhys2CCPtrReadOnly,(PPDMDEVINS pDevIns, uint32_t cPages, PCRTGCPHYS paGCPhysPages, + uint32_t fFlags, void const **papvPages, PPGMPAGEMAPLOCK paLocks)); + + /** + * Release the mappings of multiple guest pages. + * + * This is the counter part of pfnPhysBulkGCPhys2CCPtr and + * pfnPhysBulkGCPhys2CCPtrReadOnly. + * + * @param pDevIns The device instance. + * @param cPages Number of pages to unlock. + * @param paLocks The lock structures initialized by the mapping + * function (@a cPages in length). + * @thread Any. + * @since 6.0.6 + */ + DECLR3CALLBACKMEMBER(void, pfnPhysBulkReleasePageMappingLocks,(PPDMDEVINS pDevIns, uint32_t cPages, PPGMPAGEMAPLOCK paLocks)); + + /** + * Returns the micro architecture used for the guest. + * + * @returns CPU micro architecture enum. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(CPUMMICROARCH, pfnCpuGetGuestMicroarch,(PPDMDEVINS pDevIns)); + + /** + * Get the number of physical and linear address bits supported by the guest. + * + * @param pDevIns The device instance. + * @param pcPhysAddrWidth Where to store the number of physical address bits + * supported by the guest. + * @param pcLinearAddrWidth Where to store the number of linear address bits + * supported by the guest. + */ + DECLR3CALLBACKMEMBER(void, pfnCpuGetGuestAddrWidths,(PPDMDEVINS pDevIns, uint8_t *pcPhysAddrWidth, + uint8_t *pcLinearAddrWidth)); + + /** + * Gets the scalable bus frequency. + * + * The bus frequency is used as a base in several MSRs that gives the CPU and + * other frequency ratios. + * + * @returns Scalable bus frequency in Hz. Will not return CPUM_SBUSFREQ_UNKNOWN. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnCpuGetGuestScalableBusFrequency,(PPDMDEVINS pDevIns)); + + /** Space reserved for future members. + * @{ */ + /** + * Deregister zero or more samples given their name prefix. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pszPrefix The name prefix of the samples to remove. If this does + * not start with a '/', the default prefix will be + * prepended, otherwise it will be used as-is. + */ + DECLR3CALLBACKMEMBER(int, pfnSTAMDeregisterByPrefix,(PPDMDEVINS pDevIns, const char *pszPrefix)); + 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 user mode VM handle. Restricted API. + * + * @returns User mode VM Handle. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(PUVM, pfnGetUVM,(PPDMDEVINS pDevIns)); + + /** + * Gets the global VM handle. Restricted API. + * + * @returns VM Handle. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(PVMCC, pfnGetVM,(PPDMDEVINS pDevIns)); + + /** + * Gets the VMCPU handle. Restricted API. + * + * @returns VMCPU Handle. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(PVMCPU, pfnGetVMCPU,(PPDMDEVINS pDevIns)); + + /** + * The the VM CPU ID of the current thread (restricted API). + * + * @returns The VMCPUID of the calling thread, NIL_VMCPUID if not EMT. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(VMCPUID, pfnGetCurrentCpuId,(PPDMDEVINS pDevIns)); + + /** + * Registers the VMM device heap or notifies about mapping/unmapping. + * + * This interface serves three purposes: + * + * -# Register the VMM device heap during device construction + * for the HM to use. + * -# Notify PDM/HM that it's mapped into guest address + * space (i.e. usable). + * -# Notify PDM/HM that it is being unmapped from the guest + * address space (i.e. not usable). + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param GCPhys The physical address if mapped, NIL_RTGCPHYS if + * not mapped. + * @param pvHeap Ring 3 heap pointer. + * @param cbHeap Size of the heap. + * @thread EMT. + */ + DECLR3CALLBACKMEMBER(int, pfnRegisterVMMDevHeap,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTR3PTR pvHeap, unsigned cbHeap)); + + /** + * Registers the firmware (BIOS, EFI) device with PDM. + * + * The firmware provides a callback table and gets a special PDM helper table. + * There can only be one firmware device for a VM. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pFwReg Firmware registration structure. + * @param ppFwHlp Where to return the firmware helper structure. + * @remarks Only valid during device construction. + * @thread EMT(0) + */ + DECLR3CALLBACKMEMBER(int, pfnFirmwareRegister,(PPDMDEVINS pDevIns, PCPDMFWREG pFwReg, PCPDMFWHLPR3 *ppFwHlp)); + + /** + * Resets the VM. + * + * @returns The appropriate VBox status code to pass around on reset. + * @param pDevIns The device instance. + * @param fFlags PDMVMRESET_F_XXX flags. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnVMReset,(PPDMDEVINS pDevIns, uint32_t fFlags)); + + /** + * 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)); + + /** + * Gets the main execution engine for the VM. + * + * @returns VM_EXEC_ENGINE_XXX + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(uint8_t, pfnGetMainExecutionEngine,(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. + */ + 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)); + + /** + * Get the timestamp frequency. + * + * @returns Number of ticks per second. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnTMCpuTicksPerSecond,(PPDMDEVINS pDevIns)); + + /** + * Gets the support driver session. + * + * This is intended for working with the semaphore API. + * + * @returns Support driver session handle. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(PSUPDRVSESSION, pfnGetSupDrvSession,(PPDMDEVINS pDevIns)); + + /** + * Queries a generic object from the VMM user. + * + * @returns Pointer to the object if found, NULL if not. + * @param pDevIns The device instance. + * @param pUuid The UUID of what's being queried. The UUIDs and + * the usage conventions are defined by the user. + * + * @note It is strictly forbidden to call this internally in VBox! This + * interface is exclusively for hacks in externally developed devices. + */ + DECLR3CALLBACKMEMBER(void *, pfnQueryGenericUserObject,(PPDMDEVINS pDevIns, PCRTUUID pUuid)); + + /** + * Register a physical page access handler type. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param enmKind The kind of access handler. + * @param pfnHandler Pointer to the ring-3 handler callback. + * @param pszDesc The type description. + * @param phType Where to return the type handle (cross context safe). + * @sa PDMDevHlpPGMHandlerPhysicalTypeSetUpContext + */ + DECLR3CALLBACKMEMBER(int, pfnPGMHandlerPhysicalTypeRegister, (PPDMDEVINS pDevIns, PGMPHYSHANDLERKIND enmKind, + PFNPGMPHYSHANDLER pfnHandler, + const char *pszDesc, PPGMPHYSHANDLERTYPE phType)); + + /** + * Register a access handler for a physical range. + * + * @returns VBox status code. + * @retval VINF_SUCCESS when successfully installed. + * @retval VINF_PGM_GCPHYS_ALIASED when the shadow PTs could be updated because + * the guest page aliased or/and mapped by multiple PTs. A CR3 sync has been + * flagged together with a pool clearing. + * @retval VERR_PGM_HANDLER_PHYSICAL_CONFLICT if the range conflicts with an existing + * one. A debug assertion is raised. + * + * @param pDevIns The device instance. + * @param GCPhys Start physical address. + * @param GCPhysLast Last physical address. (inclusive) + * @param hType The handler type registration handle. + * @param pszDesc Description of this handler. If NULL, the type + * description will be used instead. + * @note There is no @a uUser argument, because it will be set to the pDevIns + * in the context the handler is called. + */ + DECLR3CALLBACKMEMBER(int, pfnPGMHandlerPhysicalRegister, (PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast, + PGMPHYSHANDLERTYPE hType, R3PTRTYPE(const char *) pszDesc)); + + /** + * Deregister a physical page access handler. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param GCPhys Start physical address. + */ + DECLR3CALLBACKMEMBER(int, pfnPGMHandlerPhysicalDeregister,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys)); + + /** + * Temporarily turns off the access monitoring of a page within a monitored + * physical write/all page access handler region. + * + * Use this when no further \#PFs are required for that page. Be aware that + * a page directory sync might reset the flags, and turn on access monitoring + * for the page. + * + * The caller must do required page table modifications. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param GCPhys The start address of the access handler. This + * must be a fully page aligned range or we risk + * messing up other handlers installed for the + * start and end pages. + * @param GCPhysPage The physical address of the page to turn off + * access monitoring for. + */ + DECLR3CALLBACKMEMBER(int, pfnPGMHandlerPhysicalPageTempOff,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTGCPHYS GCPhysPage)); + + /** + * Resets any modifications to individual pages in a physical page access + * handler region. + * + * This is used in pair with PGMHandlerPhysicalPageTempOff(), + * PGMHandlerPhysicalPageAliasMmio2() or PGMHandlerPhysicalPageAliasHC(). + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param GCPhys The start address of the handler regions, i.e. what you + * passed to PGMR3HandlerPhysicalRegister(), + * PGMHandlerPhysicalRegisterEx() or + * PGMHandlerPhysicalModify(). + */ + DECLR3CALLBACKMEMBER(int, pfnPGMHandlerPhysicalReset,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys)); + + /** + * Registers the guest memory range that can be used for patching. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param GCPtrPatchMem Patch memory range. + * @param cbPatchMem Size of the memory range. + */ + DECLR3CALLBACKMEMBER(int, pfnVMMRegisterPatchMemory, (PPDMDEVINS pDevIns, RTGCPTR GCPtrPatchMem, uint32_t cbPatchMem)); + + /** + * Deregisters the guest memory range that can be used for patching. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param GCPtrPatchMem Patch memory range. + * @param cbPatchMem Size of the memory range. + */ + DECLR3CALLBACKMEMBER(int, pfnVMMDeregisterPatchMemory, (PPDMDEVINS pDevIns, RTGCPTR GCPtrPatchMem, uint32_t cbPatchMem)); + + /** + * Registers a new shared module for the VM + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param enmGuestOS Guest OS type. + * @param pszModuleName Module name. + * @param pszVersion Module version. + * @param GCBaseAddr Module base address. + * @param cbModule Module size. + * @param cRegions Number of shared region descriptors. + * @param paRegions Shared region(s). + */ + DECLR3CALLBACKMEMBER(int, pfnSharedModuleRegister,(PPDMDEVINS pDevIns, VBOXOSFAMILY enmGuestOS, char *pszModuleName, char *pszVersion, + RTGCPTR GCBaseAddr, uint32_t cbModule, + uint32_t cRegions, VMMDEVSHAREDREGIONDESC const *paRegions)); + + /** + * Unregisters a shared module for the VM + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pszModuleName Module name. + * @param pszVersion Module version. + * @param GCBaseAddr Module base address. + * @param cbModule Module size. + */ + DECLR3CALLBACKMEMBER(int, pfnSharedModuleUnregister,(PPDMDEVINS pDevIns, char *pszModuleName, char *pszVersion, + RTGCPTR GCBaseAddr, uint32_t cbModule)); + + /** + * Query the state of a page in a shared module + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param GCPtrPage Page address. + * @param pfShared Shared status (out). + * @param pfPageFlags Page flags (out). + */ + DECLR3CALLBACKMEMBER(int, pfnSharedModuleGetPageState, (PPDMDEVINS pDevIns, RTGCPTR GCPtrPage, bool *pfShared, uint64_t *pfPageFlags)); + + /** + * Check all registered modules for changes. + * + * @returns VBox status code. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(int, pfnSharedModuleCheckAll,(PPDMDEVINS pDevIns)); + + /** + * Query the interface of the top level driver on a LUN. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pszDevice Device name. + * @param iInstance Device instance. + * @param iLun The Logical Unit to obtain the interface of. + * @param ppBase Where to store the base interface pointer. + * + * @remark We're not doing any locking ATM, so don't try call this at times when the + * device chain is known to be updated. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryLun,(PPDMDEVINS pDevIns, const char *pszDevice, unsigned iInstance, unsigned iLun, PPPDMIBASE ppBase)); + + /** + * Registers the GIM device with VMM. + * + * @param pDevIns Pointer to the GIM device instance. + * @param pDbg Pointer to the GIM device debug structure, can be + * NULL. + */ + DECLR3CALLBACKMEMBER(void, pfnGIMDeviceRegister,(PPDMDEVINS pDevIns, PGIMDEBUG pDbg)); + + /** + * Gets debug setup specified by the provider. + * + * @returns VBox status code. + * @param pDevIns Pointer to the GIM device instance. + * @param pDbgSetup Where to store the debug setup details. + */ + DECLR3CALLBACKMEMBER(int, pfnGIMGetDebugSetup,(PPDMDEVINS pDevIns, PGIMDEBUGSETUP pDbgSetup)); + + /** + * Returns the array of MMIO2 regions that are expected to be registered and + * later mapped into the guest-physical address space for the GIM provider + * configured for the VM. + * + * @returns Pointer to an array of GIM MMIO2 regions, may return NULL. + * @param pDevIns Pointer to the GIM device instance. + * @param pcRegions Where to store the number of items in the array. + * + * @remarks The caller does not own and therefore must -NOT- try to free the + * returned pointer. + */ + DECLR3CALLBACKMEMBER(PGIMMMIO2REGION, pfnGIMGetMmio2Regions,(PPDMDEVINS pDevIns, uint32_t *pcRegions)); + + /** @} */ + + /** Just a safety precaution. (PDM_DEVHLPR3_VERSION) */ + uint32_t u32TheEnd; +} PDMDEVHLPR3; +#endif /* !IN_RING3 || DOXYGEN_RUNNING */ +/** 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; + + +/** + * PDM Device API - RC Variant. + */ +typedef struct PDMDEVHLPRC +{ + /** Structure version. PDM_DEVHLPRC_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Sets up raw-mode context callback handlers for an I/O port range. + * + * The range must have been registered in ring-3 first using + * PDMDevHlpIoPortCreate() or PDMDevHlpIoPortCreateEx(). + * + * @returns VBox status. + * @param pDevIns The device instance to register the ports with. + * @param hIoPorts The I/O port range handle. + * @param pfnOut Pointer to function which is gonna handle OUT + * operations. Optional. + * @param pfnIn Pointer to function which is gonna handle IN operations. + * Optional. + * @param pfnOutStr Pointer to function which is gonna handle string OUT + * operations. Optional. + * @param pfnInStr Pointer to function which is gonna handle string IN + * operations. Optional. + * @param pvUser User argument to pass to the callbacks. + * + * @remarks Caller enters the device critical section prior to invoking the + * registered callback methods. + * + * @sa PDMDevHlpIoPortCreate, PDMDevHlpIoPortCreateEx, PDMDevHlpIoPortMap, + * PDMDevHlpIoPortUnmap. + */ + DECLRCCALLBACKMEMBER(int, pfnIoPortSetUpContextEx,(PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts, + PFNIOMIOPORTNEWOUT pfnOut, PFNIOMIOPORTNEWIN pfnIn, + PFNIOMIOPORTNEWOUTSTRING pfnOutStr, PFNIOMIOPORTNEWINSTRING pfnInStr, + void *pvUser)); + + /** + * Sets up raw-mode context callback handlers for an MMIO region. + * + * The region must have been registered in ring-3 first using + * PDMDevHlpMmioCreate() or PDMDevHlpMmioCreateEx(). + * + * @returns VBox status. + * @param pDevIns The device instance to register the ports with. + * @param hRegion The MMIO region handle. + * @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 pvUser User argument to pass to the callbacks. + * + * @remarks Caller enters the device critical section prior to invoking the + * registered callback methods. + * + * @sa PDMDevHlpMmioCreate, PDMDevHlpMmioCreateEx, PDMDevHlpMmioMap, + * PDMDevHlpMmioUnmap. + */ + DECLRCCALLBACKMEMBER(int, pfnMmioSetUpContextEx,(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, PFNIOMMMIONEWWRITE pfnWrite, + PFNIOMMMIONEWREAD pfnRead, PFNIOMMMIONEWFILL pfnFill, void *pvUser)); + + /** + * Sets up a raw-mode mapping for an MMIO2 region. + * + * The region must have been created in ring-3 first using + * PDMDevHlpMmio2Create(). + * + * @returns VBox status. + * @param pDevIns The device instance to register the ports with. + * @param hRegion The MMIO2 region handle. + * @param offSub Start of what to map into raw-mode. Must be page aligned. + * @param cbSub Number of bytes to map into raw-mode. Must be page + * aligned. Zero is an alias for everything. + * @param ppvMapping Where to return the mapping corresponding to @a offSub. + * @thread EMT(0) + * @note Only available at VM creation time. + * + * @sa PDMDevHlpMmio2Create(). + */ + DECLRCCALLBACKMEMBER(int, pfnMmio2SetUpContext,(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion, + size_t offSub, size_t cbSub, void **ppvMapping)); + + /** + * Bus master physical memory read from the given PCI device. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_READ_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param GCPhys Physical address start reading from. + * @param pvBuf Where to put the read bits. + * @param cbRead How many bytes to read. + * @param fFlags Combination of PDM_DEVHLP_PHYS_RW_F_XXX. + * @thread Any thread, but the call may involve the emulation thread. + */ + DECLRCCALLBACKMEMBER(int, pfnPCIPhysRead,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, + void *pvBuf, size_t cbRead, uint32_t fFlags)); + + /** + * Bus master physical memory write from the given PCI device. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_WRITE_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param GCPhys Physical address to write to. + * @param pvBuf What to write. + * @param cbWrite How many bytes to write. + * @param fFlags Combination of PDM_DEVHLP_PHYS_RW_F_XXX. + * @thread Any thread, but the call may involve the emulation thread. + */ + DECLRCCALLBACKMEMBER(int, pfnPCIPhysWrite,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, + const void *pvBuf, size_t cbWrite, uint32_t fFlags)); + + /** + * Set the IRQ for the given PCI device. + * + * @param pDevIns Device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @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, PPDMPCIDEV pPciDev, 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. + * @param fFlags Combination of PDM_DEVHLP_PHYS_RW_F_XXX. + */ + DECLRCCALLBACKMEMBER(int, pfnPhysRead,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead, uint32_t fFlags)); + + /** + * 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. + * @param fFlags Combination of PDM_DEVHLP_PHYS_RW_F_XXX. + */ + DECLRCCALLBACKMEMBER(int, pfnPhysWrite,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite, uint32_t fFlags)); + + /** + * 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)); + + /** + * Gets the VM handle. Restricted API. + * + * @returns VM Handle. + * @param pDevIns Device instance. + */ + DECLRCCALLBACKMEMBER(PVMCC, pfnGetVM,(PPDMDEVINS pDevIns)); + + /** + * Gets the VMCPU handle. Restricted API. + * + * @returns VMCPU Handle. + * @param pDevIns The device instance. + */ + DECLRCCALLBACKMEMBER(PVMCPUCC, pfnGetVMCPU,(PPDMDEVINS pDevIns)); + + /** + * The the VM CPU ID of the current thread (restricted API). + * + * @returns The VMCPUID of the calling thread, NIL_VMCPUID if not EMT. + * @param pDevIns The device instance. + */ + DECLRCCALLBACKMEMBER(VMCPUID, pfnGetCurrentCpuId,(PPDMDEVINS pDevIns)); + + /** + * Gets the main execution engine for the VM. + * + * @returns VM_EXEC_ENGINE_XXX + * @param pDevIns The device instance. + */ + DECLRCCALLBACKMEMBER(uint8_t, pfnGetMainExecutionEngine,(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 NOP critical section. + * + * @returns The ring-3 address of the NOP critical section. + * @param pDevIns The device instance. + */ + DECLRCCALLBACKMEMBER(PPDMCRITSECT, pfnCritSectGetNop,(PPDMDEVINS pDevIns)); + + /** + * Changes the device level critical section from the automatically created + * default to one desired by the device constructor. + * + * Must first be done in ring-3. + * + * @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. + */ + DECLRCCALLBACKMEMBER(int, pfnSetDeviceCritSect,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect)); + + /** @name Exported PDM Critical Section Functions + * @{ */ + DECLRCCALLBACKMEMBER(int, pfnCritSectEnter,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, int rcBusy)); + DECLRCCALLBACKMEMBER(int, pfnCritSectEnterDebug,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLRCCALLBACKMEMBER(int, pfnCritSectTryEnter,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect)); + DECLRCCALLBACKMEMBER(int, pfnCritSectTryEnterDebug,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLRCCALLBACKMEMBER(int, pfnCritSectLeave,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect)); + DECLRCCALLBACKMEMBER(bool, pfnCritSectIsOwner,(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect)); + DECLRCCALLBACKMEMBER(bool, pfnCritSectIsInitialized,(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect)); + DECLRCCALLBACKMEMBER(bool, pfnCritSectHasWaiters,(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect)); + DECLRCCALLBACKMEMBER(uint32_t, pfnCritSectGetRecursion,(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect)); + /** @} */ + + /** @name Exported PDM Read/Write Critical Section Functions + * @{ */ + DECLRCCALLBACKMEMBER(int, pfnCritSectRwEnterShared,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy)); + DECLRCCALLBACKMEMBER(int, pfnCritSectRwEnterSharedDebug,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLRCCALLBACKMEMBER(int, pfnCritSectRwTryEnterShared,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLRCCALLBACKMEMBER(int, pfnCritSectRwTryEnterSharedDebug,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLRCCALLBACKMEMBER(int, pfnCritSectRwLeaveShared,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + + DECLRCCALLBACKMEMBER(int, pfnCritSectRwEnterExcl,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy)); + DECLRCCALLBACKMEMBER(int, pfnCritSectRwEnterExclDebug,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLRCCALLBACKMEMBER(int, pfnCritSectRwTryEnterExcl,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLRCCALLBACKMEMBER(int, pfnCritSectRwTryEnterExclDebug,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLRCCALLBACKMEMBER(int, pfnCritSectRwLeaveExcl,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + + DECLRCCALLBACKMEMBER(bool, pfnCritSectRwIsWriteOwner,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLRCCALLBACKMEMBER(bool, pfnCritSectRwIsReadOwner,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, bool fWannaHear)); + DECLRCCALLBACKMEMBER(uint32_t, pfnCritSectRwGetWriteRecursion,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLRCCALLBACKMEMBER(uint32_t, pfnCritSectRwGetWriterReadRecursion,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLRCCALLBACKMEMBER(uint32_t, pfnCritSectRwGetReadCount,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLRCCALLBACKMEMBER(bool, pfnCritSectRwIsInitialized,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + /** @} */ + + /** + * 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)); + + /** + * Sets up the PCI bus for the raw-mode context. + * + * This must be called after ring-3 has registered the PCI bus using + * PDMDevHlpPCIBusRegister(). + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPciBusReg The PCI bus registration information for raw-mode, + * considered volatile. + * @param ppPciHlp Where to return the raw-mode PCI bus helpers. + */ + DECLRCCALLBACKMEMBER(int, pfnPCIBusSetUpContext,(PPDMDEVINS pDevIns, PPDMPCIBUSREGRC pPciBusReg, PCPDMPCIHLPRC *ppPciHlp)); + + /** + * Sets up the IOMMU for the raw-mode context. + * + * This must be called after ring-3 has registered the IOMMU using + * PDMDevHlpIommuRegister(). + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pIommuReg The IOMMU registration information for raw-mode, + * considered volatile. + * @param ppIommuHlp Where to return the raw-mode IOMMU helpers. + */ + DECLRCCALLBACKMEMBER(int, pfnIommuSetUpContext,(PPDMDEVINS pDevIns, PPDMIOMMUREGRC pIommuReg, PCPDMIOMMUHLPRC *ppIommuHlp)); + + /** + * Sets up the PIC for the ring-0 context. + * + * This must be called after ring-3 has registered the PIC using + * PDMDevHlpPICRegister(). + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPicReg The PIC registration information for ring-0, + * considered volatile and copied. + * @param ppPicHlp Where to return the ring-0 PIC helpers. + */ + DECLRCCALLBACKMEMBER(int, pfnPICSetUpContext,(PPDMDEVINS pDevIns, PPDMPICREG pPicReg, PCPDMPICHLP *ppPicHlp)); + + /** + * Sets up the APIC for the raw-mode context. + * + * This must be called after ring-3 has registered the APIC using + * PDMDevHlpApicRegister(). + * + * @returns VBox status code. + * @param pDevIns The device instance. + */ + DECLRCCALLBACKMEMBER(int, pfnApicSetUpContext,(PPDMDEVINS pDevIns)); + + /** + * Sets up the IOAPIC for the ring-0 context. + * + * This must be called after ring-3 has registered the PIC using + * PDMDevHlpIoApicRegister(). + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pIoApicReg The PIC registration information for ring-0, + * considered volatile and copied. + * @param ppIoApicHlp Where to return the ring-0 IOAPIC helpers. + */ + DECLRCCALLBACKMEMBER(int, pfnIoApicSetUpContext,(PPDMDEVINS pDevIns, PPDMIOAPICREG pIoApicReg, PCPDMIOAPICHLP *ppIoApicHlp)); + + /** + * Sets up the HPET for the raw-mode context. + * + * This must be called after ring-3 has registered the PIC using + * PDMDevHlpHpetRegister(). + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pHpetReg The PIC registration information for raw-mode, + * considered volatile and copied. + * @param ppHpetHlp Where to return the raw-mode HPET helpers. + */ + DECLRCCALLBACKMEMBER(int, pfnHpetSetUpContext,(PPDMDEVINS pDevIns, PPDMHPETREG pHpetReg, PCPDMHPETHLPRC *ppHpetHlp)); + + /** Space reserved for future members. + * @{ */ + DECLRCCALLBACKMEMBER(void, pfnReserved1,(void)); + DECLRCCALLBACKMEMBER(void, pfnReserved2,(void)); + DECLRCCALLBACKMEMBER(void, pfnReserved3,(void)); + DECLRCCALLBACKMEMBER(void, pfnReserved4,(void)); + DECLRCCALLBACKMEMBER(void, pfnReserved5,(void)); + DECLRCCALLBACKMEMBER(void, pfnReserved6,(void)); + DECLRCCALLBACKMEMBER(void, pfnReserved7,(void)); + DECLRCCALLBACKMEMBER(void, pfnReserved8,(void)); + DECLRCCALLBACKMEMBER(void, pfnReserved9,(void)); + DECLRCCALLBACKMEMBER(void, pfnReserved10,(void)); + /** @} */ + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMDEVHLPRC; +/** Pointer PDM Device RC API. */ +typedef RGPTRTYPE(struct PDMDEVHLPRC *) PPDMDEVHLPRC; +/** Pointer PDM Device RC API. */ +typedef RGPTRTYPE(const struct PDMDEVHLPRC *) PCPDMDEVHLPRC; + +/** Current PDMDEVHLP version number. */ +#define PDM_DEVHLPRC_VERSION PDM_VERSION_MAKE(0xffe6, 19, 0) + + +/** + * PDM Device API - R0 Variant. + */ +typedef struct PDMDEVHLPR0 +{ + /** Structure version. PDM_DEVHLPR0_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Sets up ring-0 callback handlers for an I/O port range. + * + * The range must have been created in ring-3 first using + * PDMDevHlpIoPortCreate() or PDMDevHlpIoPortCreateEx(). + * + * @returns VBox status. + * @param pDevIns The device instance to register the ports with. + * @param hIoPorts The I/O port range handle. + * @param pfnOut Pointer to function which is gonna handle OUT + * operations. Optional. + * @param pfnIn Pointer to function which is gonna handle IN operations. + * Optional. + * @param pfnOutStr Pointer to function which is gonna handle string OUT + * operations. Optional. + * @param pfnInStr Pointer to function which is gonna handle string IN + * operations. Optional. + * @param pvUser User argument to pass to the callbacks. + * + * @remarks Caller enters the device critical section prior to invoking the + * registered callback methods. + * + * @sa PDMDevHlpIoPortCreate(), PDMDevHlpIoPortCreateEx(), + * PDMDevHlpIoPortMap(), PDMDevHlpIoPortUnmap(). + */ + DECLR0CALLBACKMEMBER(int, pfnIoPortSetUpContextEx,(PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts, + PFNIOMIOPORTNEWOUT pfnOut, PFNIOMIOPORTNEWIN pfnIn, + PFNIOMIOPORTNEWOUTSTRING pfnOutStr, PFNIOMIOPORTNEWINSTRING pfnInStr, + void *pvUser)); + + /** + * Sets up ring-0 callback handlers for an MMIO region. + * + * The region must have been created in ring-3 first using + * PDMDevHlpMmioCreate(), PDMDevHlpMmioCreateEx(), PDMDevHlpMmioCreateAndMap(), + * PDMDevHlpMmioCreateExAndMap() or PDMDevHlpPCIIORegionCreateMmio(). + * + * @returns VBox status. + * @param pDevIns The device instance to register the ports with. + * @param hRegion The MMIO region handle. + * @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 pvUser User argument to pass to the callbacks. + * + * @remarks Caller enters the device critical section prior to invoking the + * registered callback methods. + * + * @sa PDMDevHlpMmioCreate(), PDMDevHlpMmioCreateEx(), PDMDevHlpMmioMap(), + * PDMDevHlpMmioUnmap(). + */ + DECLR0CALLBACKMEMBER(int, pfnMmioSetUpContextEx,(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, PFNIOMMMIONEWWRITE pfnWrite, + PFNIOMMMIONEWREAD pfnRead, PFNIOMMMIONEWFILL pfnFill, void *pvUser)); + + /** + * Sets up a ring-0 mapping for an MMIO2 region. + * + * The region must have been created in ring-3 first using + * PDMDevHlpMmio2Create(). + * + * @returns VBox status. + * @param pDevIns The device instance to register the ports with. + * @param hRegion The MMIO2 region handle. + * @param offSub Start of what to map into ring-0. Must be page aligned. + * @param cbSub Number of bytes to map into ring-0. Must be page + * aligned. Zero is an alias for everything. + * @param ppvMapping Where to return the mapping corresponding to @a offSub. + * + * @thread EMT(0) + * @note Only available at VM creation time. + * + * @sa PDMDevHlpMmio2Create(). + */ + DECLR0CALLBACKMEMBER(int, pfnMmio2SetUpContext,(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion, size_t offSub, size_t cbSub, + void **ppvMapping)); + + /** + * Bus master physical memory read from the given PCI device. + * + * @returns VINF_SUCCESS or VERR_PDM_NOT_PCI_BUS_MASTER, later maybe + * VERR_EM_MEMORY. + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param GCPhys Physical address start reading from. + * @param pvBuf Where to put the read bits. + * @param cbRead How many bytes to read. + * @param fFlags Combination of PDM_DEVHLP_PHYS_RW_F_XXX. + * @thread Any thread, but the call may involve the emulation thread. + */ + DECLR0CALLBACKMEMBER(int, pfnPCIPhysRead,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, + void *pvBuf, size_t cbRead, uint32_t fFlags)); + + /** + * Bus master physical memory write from the given PCI device. + * + * @returns VINF_SUCCESS or VERR_PDM_NOT_PCI_BUS_MASTER, later maybe + * VERR_EM_MEMORY. + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param GCPhys Physical address to write to. + * @param pvBuf What to write. + * @param cbWrite How many bytes to write. + * @param fFlags Combination of PDM_DEVHLP_PHYS_RW_F_XXX. + * @thread Any thread, but the call may involve the emulation thread. + */ + DECLR0CALLBACKMEMBER(int, pfnPCIPhysWrite,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, + const void *pvBuf, size_t cbWrite, uint32_t fFlags)); + + /** + * Set the IRQ for the given PCI device. + * + * @param pDevIns Device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @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, PPDMPCIDEV pPciDev, 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. + * @param fFlags Combination of PDM_DEVHLP_PHYS_RW_F_XXX. + */ + DECLR0CALLBACKMEMBER(int, pfnPhysRead,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead, uint32_t fFlags)); + + /** + * 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. + * @param fFlags Combination of PDM_DEVHLP_PHYS_RW_F_XXX. + */ + DECLR0CALLBACKMEMBER(int, pfnPhysWrite,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite, uint32_t fFlags)); + + /** + * 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)); + + /** + * Gets the VM handle. Restricted API. + * + * @returns VM Handle. + * @param pDevIns Device instance. + */ + DECLR0CALLBACKMEMBER(PVMCC, pfnGetVM,(PPDMDEVINS pDevIns)); + + /** + * Gets the VMCPU handle. Restricted API. + * + * @returns VMCPU Handle. + * @param pDevIns The device instance. + */ + DECLR0CALLBACKMEMBER(PVMCPUCC, pfnGetVMCPU,(PPDMDEVINS pDevIns)); + + /** + * The the VM CPU ID of the current thread (restricted API). + * + * @returns The VMCPUID of the calling thread, NIL_VMCPUID if not EMT. + * @param pDevIns The device instance. + */ + DECLR0CALLBACKMEMBER(VMCPUID, pfnGetCurrentCpuId,(PPDMDEVINS pDevIns)); + + /** + * Gets the main execution engine for the VM. + * + * @returns VM_EXEC_ENGINE_XXX + * @param pDevIns The device instance. + */ + DECLR0CALLBACKMEMBER(uint8_t, pfnGetMainExecutionEngine,(PPDMDEVINS pDevIns)); + + /** @name Timer handle method wrappers + * @{ */ + DECLR0CALLBACKMEMBER(uint64_t, pfnTimerFromMicro,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cMicroSecs)); + DECLR0CALLBACKMEMBER(uint64_t, pfnTimerFromMilli,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cMilliSecs)); + DECLR0CALLBACKMEMBER(uint64_t, pfnTimerFromNano,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cNanoSecs)); + DECLR0CALLBACKMEMBER(uint64_t, pfnTimerGet,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + DECLR0CALLBACKMEMBER(uint64_t, pfnTimerGetFreq,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + DECLR0CALLBACKMEMBER(uint64_t, pfnTimerGetNano,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + DECLR0CALLBACKMEMBER(bool, pfnTimerIsActive,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + DECLR0CALLBACKMEMBER(bool, pfnTimerIsLockOwner,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + DECLR0CALLBACKMEMBER(VBOXSTRICTRC, pfnTimerLockClock,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, int rcBusy)); + /** Takes the clock lock then enters the specified critical section. */ + DECLR0CALLBACKMEMBER(VBOXSTRICTRC, pfnTimerLockClock2,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect, int rcBusy)); + DECLR0CALLBACKMEMBER(int, pfnTimerSet,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t uExpire)); + DECLR0CALLBACKMEMBER(int, pfnTimerSetFrequencyHint,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint32_t uHz)); + DECLR0CALLBACKMEMBER(int, pfnTimerSetMicro,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cMicrosToNext)); + DECLR0CALLBACKMEMBER(int, pfnTimerSetMillies,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cMilliesToNext)); + DECLR0CALLBACKMEMBER(int, pfnTimerSetNano,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cNanosToNext)); + DECLR0CALLBACKMEMBER(int, pfnTimerSetRelative,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cTicksToNext, uint64_t *pu64Now)); + DECLR0CALLBACKMEMBER(int, pfnTimerStop,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + DECLR0CALLBACKMEMBER(void, pfnTimerUnlockClock,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + DECLR0CALLBACKMEMBER(void, pfnTimerUnlockClock2,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect)); + /** @} */ + + /** + * 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)); + + /** @name Exported PDM Queue Functions + * @{ */ + DECLR0CALLBACKMEMBER(PPDMQUEUEITEMCORE, pfnQueueAlloc,(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue)); + DECLR0CALLBACKMEMBER(int, pfnQueueInsert,(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue, PPDMQUEUEITEMCORE pItem)); + DECLR0CALLBACKMEMBER(bool, pfnQueueFlushIfNecessary,(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue)); + /** @} */ + + /** @name PDM Task + * @{ */ + /** + * Triggers the running the given task. + * + * @returns VBox status code. + * @retval VINF_ALREADY_POSTED is the task is already pending. + * @param pDevIns The device instance. + * @param hTask The task to trigger. + * @thread Any thread. + */ + DECLR0CALLBACKMEMBER(int, pfnTaskTrigger,(PPDMDEVINS pDevIns, PDMTASKHANDLE hTask)); + /** @} */ + + /** @name SUP Event Semaphore Wrappers (single release / auto reset) + * These semaphores can be signalled from ring-0. + * @{ */ + /** @sa SUPSemEventSignal */ + DECLR0CALLBACKMEMBER(int, pfnSUPSemEventSignal,(PPDMDEVINS pDevIns, SUPSEMEVENT hEvent)); + /** @sa SUPSemEventWaitNoResume */ + DECLR0CALLBACKMEMBER(int, pfnSUPSemEventWaitNoResume,(PPDMDEVINS pDevIns, SUPSEMEVENT hEvent, uint32_t cMillies)); + /** @sa SUPSemEventWaitNsAbsIntr */ + DECLR0CALLBACKMEMBER(int, pfnSUPSemEventWaitNsAbsIntr,(PPDMDEVINS pDevIns, SUPSEMEVENT hEvent, uint64_t uNsTimeout)); + /** @sa SUPSemEventWaitNsRelIntr */ + DECLR0CALLBACKMEMBER(int, pfnSUPSemEventWaitNsRelIntr,(PPDMDEVINS pDevIns, SUPSEMEVENT hEvent, uint64_t cNsTimeout)); + /** @sa SUPSemEventGetResolution */ + DECLR0CALLBACKMEMBER(uint32_t, pfnSUPSemEventGetResolution,(PPDMDEVINS pDevIns)); + /** @} */ + + /** @name SUP Multi Event Semaphore Wrappers (multiple release / manual reset) + * These semaphores can be signalled from ring-0. + * @{ */ + /** @sa SUPSemEventMultiSignal */ + DECLR0CALLBACKMEMBER(int, pfnSUPSemEventMultiSignal,(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti)); + /** @sa SUPSemEventMultiReset */ + DECLR0CALLBACKMEMBER(int, pfnSUPSemEventMultiReset,(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti)); + /** @sa SUPSemEventMultiWaitNoResume */ + DECLR0CALLBACKMEMBER(int, pfnSUPSemEventMultiWaitNoResume,(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti, uint32_t cMillies)); + /** @sa SUPSemEventMultiWaitNsAbsIntr */ + DECLR0CALLBACKMEMBER(int, pfnSUPSemEventMultiWaitNsAbsIntr,(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti, uint64_t uNsTimeout)); + /** @sa SUPSemEventMultiWaitNsRelIntr */ + DECLR0CALLBACKMEMBER(int, pfnSUPSemEventMultiWaitNsRelIntr,(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti, uint64_t cNsTimeout)); + /** @sa SUPSemEventMultiGetResolution */ + DECLR0CALLBACKMEMBER(uint32_t, pfnSUPSemEventMultiGetResolution,(PPDMDEVINS pDevIns)); + /** @} */ + + /** + * Gets the NOP critical section. + * + * @returns The ring-3 address of the NOP critical section. + * @param pDevIns The device instance. + */ + DECLR0CALLBACKMEMBER(PPDMCRITSECT, pfnCritSectGetNop,(PPDMDEVINS pDevIns)); + + /** + * Changes the device level critical section from the automatically created + * default to one desired by the device constructor. + * + * Must first be done in ring-3. + * + * @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. + */ + DECLR0CALLBACKMEMBER(int, pfnSetDeviceCritSect,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect)); + + /** @name Exported PDM Critical Section Functions + * @{ */ + DECLR0CALLBACKMEMBER(int, pfnCritSectEnter,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, int rcBusy)); + DECLR0CALLBACKMEMBER(int, pfnCritSectEnterDebug,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR0CALLBACKMEMBER(int, pfnCritSectTryEnter,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect)); + DECLR0CALLBACKMEMBER(int, pfnCritSectTryEnterDebug,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR0CALLBACKMEMBER(int, pfnCritSectLeave,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect)); + DECLR0CALLBACKMEMBER(bool, pfnCritSectIsOwner,(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect)); + DECLR0CALLBACKMEMBER(bool, pfnCritSectIsInitialized,(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect)); + DECLR0CALLBACKMEMBER(bool, pfnCritSectHasWaiters,(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect)); + DECLR0CALLBACKMEMBER(uint32_t, pfnCritSectGetRecursion,(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect)); + DECLR0CALLBACKMEMBER(int, pfnCritSectScheduleExitEvent,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, SUPSEMEVENT hEventToSignal)); + /** @} */ + + /** @name Exported PDM Read/Write Critical Section Functions + * @{ */ + DECLR0CALLBACKMEMBER(int, pfnCritSectRwEnterShared,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy)); + DECLR0CALLBACKMEMBER(int, pfnCritSectRwEnterSharedDebug,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR0CALLBACKMEMBER(int, pfnCritSectRwTryEnterShared,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLR0CALLBACKMEMBER(int, pfnCritSectRwTryEnterSharedDebug,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR0CALLBACKMEMBER(int, pfnCritSectRwLeaveShared,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + + DECLR0CALLBACKMEMBER(int, pfnCritSectRwEnterExcl,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy)); + DECLR0CALLBACKMEMBER(int, pfnCritSectRwEnterExclDebug,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR0CALLBACKMEMBER(int, pfnCritSectRwTryEnterExcl,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLR0CALLBACKMEMBER(int, pfnCritSectRwTryEnterExclDebug,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR0CALLBACKMEMBER(int, pfnCritSectRwLeaveExcl,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + + DECLR0CALLBACKMEMBER(bool, pfnCritSectRwIsWriteOwner,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLR0CALLBACKMEMBER(bool, pfnCritSectRwIsReadOwner,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, bool fWannaHear)); + DECLR0CALLBACKMEMBER(uint32_t, pfnCritSectRwGetWriteRecursion,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLR0CALLBACKMEMBER(uint32_t, pfnCritSectRwGetWriterReadRecursion,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLR0CALLBACKMEMBER(uint32_t, pfnCritSectRwGetReadCount,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLR0CALLBACKMEMBER(bool, pfnCritSectRwIsInitialized,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + /** @} */ + + /** + * 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)); + + /** + * Sets up the PCI bus for the ring-0 context. + * + * This must be called after ring-3 has registered the PCI bus using + * PDMDevHlpPCIBusRegister(). + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPciBusReg The PCI bus registration information for ring-0, + * considered volatile and copied. + * @param ppPciHlp Where to return the ring-0 PCI bus helpers. + */ + DECLR0CALLBACKMEMBER(int, pfnPCIBusSetUpContext,(PPDMDEVINS pDevIns, PPDMPCIBUSREGR0 pPciBusReg, PCPDMPCIHLPR0 *ppPciHlp)); + + /** + * Sets up the IOMMU for the ring-0 context. + * + * This must be called after ring-3 has registered the IOMMU using + * PDMDevHlpIommuRegister(). + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pIommuReg The IOMMU registration information for ring-0, + * considered volatile and copied. + * @param ppIommuHlp Where to return the ring-0 IOMMU helpers. + */ + DECLR0CALLBACKMEMBER(int, pfnIommuSetUpContext,(PPDMDEVINS pDevIns, PPDMIOMMUREGR0 pIommuReg, PCPDMIOMMUHLPR0 *ppIommuHlp)); + + /** + * Sets up the PIC for the ring-0 context. + * + * This must be called after ring-3 has registered the PIC using + * PDMDevHlpPICRegister(). + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPicReg The PIC registration information for ring-0, + * considered volatile and copied. + * @param ppPicHlp Where to return the ring-0 PIC helpers. + */ + DECLR0CALLBACKMEMBER(int, pfnPICSetUpContext,(PPDMDEVINS pDevIns, PPDMPICREG pPicReg, PCPDMPICHLP *ppPicHlp)); + + /** + * Sets up the APIC for the ring-0 context. + * + * This must be called after ring-3 has registered the APIC using + * PDMDevHlpApicRegister(). + * + * @returns VBox status code. + * @param pDevIns The device instance. + */ + DECLR0CALLBACKMEMBER(int, pfnApicSetUpContext,(PPDMDEVINS pDevIns)); + + /** + * Sets up the IOAPIC for the ring-0 context. + * + * This must be called after ring-3 has registered the PIC using + * PDMDevHlpIoApicRegister(). + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pIoApicReg The PIC registration information for ring-0, + * considered volatile and copied. + * @param ppIoApicHlp Where to return the ring-0 IOAPIC helpers. + */ + DECLR0CALLBACKMEMBER(int, pfnIoApicSetUpContext,(PPDMDEVINS pDevIns, PPDMIOAPICREG pIoApicReg, PCPDMIOAPICHLP *ppIoApicHlp)); + + /** + * Sets up the HPET for the ring-0 context. + * + * This must be called after ring-3 has registered the PIC using + * PDMDevHlpHpetRegister(). + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pHpetReg The PIC registration information for ring-0, + * considered volatile and copied. + * @param ppHpetHlp Where to return the ring-0 HPET helpers. + */ + DECLR0CALLBACKMEMBER(int, pfnHpetSetUpContext,(PPDMDEVINS pDevIns, PPDMHPETREG pHpetReg, PCPDMHPETHLPR0 *ppHpetHlp)); + + /** + * Sets up a physical page access handler type for ring-0 callbacks. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param enmKind The kind of access handler. + * @param pfnHandler Pointer to the ring-0 handler callback. NULL if + * the ring-3 handler should be called. + * @param pfnPfHandler The name of the ring-0 \#PF handler, NULL if the + * ring-3 handler should be called. + * @param pszDesc The type description. + * @param hType The type handle registered in ring-3 already. + * @sa PDMDevHlpPGMHandlerPhysicalTypeRegister + */ + DECLR0CALLBACKMEMBER(int, pfnPGMHandlerPhysicalTypeSetUpContext, (PPDMDEVINS pDevIns, PGMPHYSHANDLERKIND enmKind, + PFNPGMPHYSHANDLER pfnHandler, + PFNPGMRZPHYSPFHANDLER pfnPfHandler, + const char *pszDesc, PGMPHYSHANDLERTYPE hType)); + + /** + * Temporarily turns off the access monitoring of a page within a monitored + * physical write/all page access handler region. + * + * Use this when no further \#PFs are required for that page. Be aware that + * a page directory sync might reset the flags, and turn on access monitoring + * for the page. + * + * The caller must do required page table modifications. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param GCPhys The start address of the access handler. This + * must be a fully page aligned range or we risk + * messing up other handlers installed for the + * start and end pages. + * @param GCPhysPage The physical address of the page to turn off + * access monitoring for. + */ + DECLR0CALLBACKMEMBER(int, pfnPGMHandlerPhysicalPageTempOff,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTGCPHYS GCPhysPage)); + + /** + * Mapping an MMIO2 page in place of an MMIO page for direct access. + * + * This is a special optimization used by the VGA device. Call + * PDMDevHlpMmioResetRegion() to undo the mapping. + * + * @returns VBox status code. This API may return VINF_SUCCESS even if no + * remapping is made. + * @retval VERR_SEM_BUSY in ring-0 if we cannot get the IOM lock. + * + * @param pDevIns The device instance @a hRegion and @a hMmio2 are + * associated with. + * @param hRegion The handle to the MMIO region. + * @param offRegion The offset into @a hRegion of the page to be + * remapped. + * @param hMmio2 The MMIO2 handle. + * @param offMmio2 Offset into @a hMmio2 of the page to be use for the + * mapping. + * @param fPageFlags Page flags to set. Must be (X86_PTE_RW | X86_PTE_P) + * for the time being. + */ + DECLR0CALLBACKMEMBER(int, pfnMmioMapMmio2Page,(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS offRegion, + uint64_t hMmio2, RTGCPHYS offMmio2, uint64_t fPageFlags)); + + /** + * Reset a previously modified MMIO region; restore the access flags. + * + * This undoes the effects of PDMDevHlpMmioMapMmio2Page() and is currently only + * intended for some ancient VGA hack. However, it would be great to extend it + * beyond VT-x and/or nested-paging. + * + * @returns VBox status code. + * + * @param pDevIns The device instance @a hRegion is associated with. + * @param hRegion The handle to the MMIO region. + */ + DECLR0CALLBACKMEMBER(int, pfnMmioResetRegion, (PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion)); + + /** + * Returns the array of MMIO2 regions that are expected to be registered and + * later mapped into the guest-physical address space for the GIM provider + * configured for the VM. + * + * @returns Pointer to an array of GIM MMIO2 regions, may return NULL. + * @param pDevIns Pointer to the GIM device instance. + * @param pcRegions Where to store the number of items in the array. + * + * @remarks The caller does not own and therefore must -NOT- try to free the + * returned pointer. + */ + DECLR0CALLBACKMEMBER(PGIMMMIO2REGION, pfnGIMGetMmio2Regions,(PPDMDEVINS pDevIns, uint32_t *pcRegions)); + + /** Space reserved for future members. + * @{ */ + DECLR0CALLBACKMEMBER(void, pfnReserved1,(void)); + DECLR0CALLBACKMEMBER(void, pfnReserved2,(void)); + DECLR0CALLBACKMEMBER(void, pfnReserved3,(void)); + DECLR0CALLBACKMEMBER(void, pfnReserved4,(void)); + DECLR0CALLBACKMEMBER(void, pfnReserved5,(void)); + DECLR0CALLBACKMEMBER(void, pfnReserved6,(void)); + DECLR0CALLBACKMEMBER(void, pfnReserved7,(void)); + DECLR0CALLBACKMEMBER(void, pfnReserved8,(void)); + DECLR0CALLBACKMEMBER(void, pfnReserved9,(void)); + DECLR0CALLBACKMEMBER(void, pfnReserved10,(void)); + /** @} */ + + /** 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, 27, 0) + + +/** + * PDM Device Instance. + */ +typedef struct PDMDEVINSR3 +{ + /** Structure version. PDM_DEVINSR3_VERSION defines the current version. */ + uint32_t u32Version; + /** Device instance number. */ + uint32_t iInstance; + /** Size of the ring-3, raw-mode and shared bits. */ + uint32_t cbRing3; + /** Set if ring-0 context is enabled. */ + bool fR0Enabled; + /** Set if raw-mode context is enabled. */ + bool fRCEnabled; + /** Alignment padding. */ + bool afReserved[2]; + /** Pointer the HC PDM Device API. */ + PCPDMDEVHLPR3 pHlpR3; + /** Pointer to the shared device instance data. */ + RTR3PTR pvInstanceDataR3; + /** Pointer to the device instance data for ring-3. */ + RTR3PTR pvInstanceDataForR3; + /** 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; + + /** Ring-3 pointer to the raw-mode device instance. */ + R3PTRTYPE(struct PDMDEVINSRC *) pDevInsForRCR3; + /** Raw-mode address of the raw-mode device instance. */ + RTRGPTR pDevInsForRC; + /** Ring-3 pointer to the raw-mode instance data. */ + RTR3PTR pvInstanceDataForRCR3; + + /** PCI device structure size. */ + uint32_t cbPciDev; + /** Number of PCI devices in apPciDevs. */ + uint32_t cPciDevs; + /** Pointer to the PCI devices for this device. + * (Allocated after the shared instance data.) + * @note If we want to extend this beyond 8 sub-functions/devices, those 1 or + * two devices ever needing it can use cbPciDev and do the address + * calculations that for entries 8+. */ + R3PTRTYPE(struct PDMPCIDEV *) apPciDevs[8]; + + /** Temporarily. */ + R0PTRTYPE(struct PDMDEVINSR0 *) pDevInsR0RemoveMe; + /** Temporarily. */ + RTR0PTR pvInstanceDataR0; + /** Temporarily. */ + RTRCPTR pvInstanceDataRC; + /** Align the internal data more naturally. */ + uint32_t au32Padding[HC_ARCH_BITS == 32 ? 13 : 11]; + + /** Internal data. */ + union + { +#ifdef PDMDEVINSINT_DECLARED + PDMDEVINSINTR3 s; +#endif + uint8_t padding[HC_ARCH_BITS == 32 ? 0x40 : 0x90]; + } Internal; + + /** Device instance data for ring-3. The size of this area is defined + * in the PDMDEVREG::cbInstanceR3 field. */ + char achInstanceData[8]; +} PDMDEVINSR3; + +/** Current PDMDEVINSR3 version number. */ +#define PDM_DEVINSR3_VERSION PDM_VERSION_MAKE(0xff82, 4, 0) + +/** Converts a pointer to the PDMDEVINSR3::IBase to a pointer to PDMDEVINS. */ +#define PDMIBASE_2_PDMDEV(pInterface) ( (PPDMDEVINS)((char *)(pInterface) - RT_UOFFSETOF(PDMDEVINS, IBase)) ) + + +/** + * PDM ring-0 device instance. + */ +typedef struct PDMDEVINSR0 +{ + /** Structure version. PDM_DEVINSR0_VERSION defines the current version. */ + uint32_t u32Version; + /** Device instance number. */ + uint32_t iInstance; + + /** Pointer the HC PDM Device API. */ + PCPDMDEVHLPR0 pHlpR0; + /** Pointer to the shared device instance data. */ + RTR0PTR pvInstanceDataR0; + /** Pointer to the device instance data for ring-0. */ + RTR0PTR pvInstanceDataForR0; + /** 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. + */ + R0PTRTYPE(PPDMCRITSECT) pCritSectRoR0; + /** Pointer to the ring-0 device registration structure. */ + R0PTRTYPE(PCPDMDEVREGR0) pReg; + /** Ring-3 address of the ring-3 device instance. */ + R3PTRTYPE(struct PDMDEVINSR3 *) pDevInsForR3; + /** Ring-0 pointer to the ring-3 device instance. */ + R0PTRTYPE(struct PDMDEVINSR3 *) pDevInsForR3R0; + /** Ring-0 pointer to the ring-3 instance data. */ + RTR0PTR pvInstanceDataForR3R0; + /** Raw-mode address of the raw-mode device instance. */ + RGPTRTYPE(struct PDMDEVINSRC *) pDevInsForRC; + /** Ring-0 pointer to the raw-mode device instance. */ + R0PTRTYPE(struct PDMDEVINSRC *) pDevInsForRCR0; + /** Ring-0 pointer to the raw-mode instance data. */ + RTR0PTR pvInstanceDataForRCR0; + + /** PCI device structure size. */ + uint32_t cbPciDev; + /** Number of PCI devices in apPciDevs. */ + uint32_t cPciDevs; + /** Pointer to the PCI devices for this device. + * (Allocated after the shared instance data.) + * @note If we want to extend this beyond 8 sub-functions/devices, those 1 or + * two devices ever needing it can use cbPciDev and do the address + * calculations that for entries 8+. */ + R0PTRTYPE(struct PDMPCIDEV *) apPciDevs[8]; + + /** Align the internal data more naturally. */ + uint32_t au32Padding[HC_ARCH_BITS == 32 ? 3 : 2 + 4]; + + /** Internal data. */ + union + { +#ifdef PDMDEVINSINT_DECLARED + PDMDEVINSINTR0 s; +#endif + uint8_t padding[HC_ARCH_BITS == 32 ? 0x40 : 0x80]; + } Internal; + + /** Device instance data for ring-0. The size of this area is defined + * in the PDMDEVREG::cbInstanceR0 field. */ + char achInstanceData[8]; +} PDMDEVINSR0; + +/** Current PDMDEVINSR0 version number. */ +#define PDM_DEVINSR0_VERSION PDM_VERSION_MAKE(0xff83, 4, 0) + + +/** + * PDM raw-mode device instance. + */ +typedef struct PDMDEVINSRC +{ + /** Structure version. PDM_DEVINSRC_VERSION defines the current version. */ + uint32_t u32Version; + /** Device instance number. */ + uint32_t iInstance; + + /** Pointer the HC PDM Device API. */ + PCPDMDEVHLPRC pHlpRC; + /** Pointer to the shared device instance data. */ + RTRGPTR pvInstanceDataRC; + /** Pointer to the device instance data for raw-mode. */ + RTRGPTR pvInstanceDataForRC; + /** 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. + */ + RGPTRTYPE(PPDMCRITSECT) pCritSectRoRC; + /** Pointer to the raw-mode device registration structure. */ + RGPTRTYPE(PCPDMDEVREGRC) pReg; + + /** PCI device structure size. */ + uint32_t cbPciDev; + /** Number of PCI devices in apPciDevs. */ + uint32_t cPciDevs; + /** Pointer to the PCI devices for this device. + * (Allocated after the shared instance data.) */ + RGPTRTYPE(struct PDMPCIDEV *) apPciDevs[8]; + + /** Align the internal data more naturally. */ + uint32_t au32Padding[14]; + + /** Internal data. */ + union + { +#ifdef PDMDEVINSINT_DECLARED + PDMDEVINSINTRC s; +#endif + uint8_t padding[0x10]; + } Internal; + + /** Device instance data for ring-0. The size of this area is defined + * in the PDMDEVREG::cbInstanceR0 field. */ + char achInstanceData[8]; +} PDMDEVINSRC; + +/** Current PDMDEVINSR0 version number. */ +#define PDM_DEVINSRC_VERSION PDM_VERSION_MAKE(0xff84, 4, 0) + + +/** @def PDM_DEVINS_VERSION + * Current PDMDEVINS version number. */ +/** @typedef PDMDEVINS + * The device instance structure for the current context. */ +#ifdef IN_RING3 +# define PDM_DEVINS_VERSION PDM_DEVINSR3_VERSION +typedef PDMDEVINSR3 PDMDEVINS; +#elif defined(IN_RING0) +# define PDM_DEVINS_VERSION PDM_DEVINSR0_VERSION +typedef PDMDEVINSR0 PDMDEVINS; +#elif defined(IN_RC) +# define PDM_DEVINS_VERSION PDM_DEVINSRC_VERSION +typedef PDMDEVINSRC PDMDEVINS; +#else +# error "Missing context defines: IN_RING0, IN_RING3, IN_RC" +#endif + +/** + * Get the pointer to an PCI device. + * @note Returns NULL if @a a_idxPciDev is out of bounds. + */ +#define PDMDEV_GET_PPCIDEV(a_pDevIns, a_idxPciDev) \ + ( (uintptr_t)(a_idxPciDev) < RT_ELEMENTS((a_pDevIns)->apPciDevs) ? (a_pDevIns)->apPciDevs[(uintptr_t)(a_idxPciDev)] \ + : PDMDEV_CALC_PPCIDEV(a_pDevIns, a_idxPciDev) ) + +/** + * Calc the pointer to of a given PCI device. + * @note Returns NULL if @a a_idxPciDev is out of bounds. + */ +#define PDMDEV_CALC_PPCIDEV(a_pDevIns, a_idxPciDev) \ + ( (uintptr_t)(a_idxPciDev) < (a_pDevIns)->cPciDevs \ + ? (PPDMPCIDEV)((uint8_t *)((a_pDevIns)->apPciDevs[0]) + (a_pDevIns->cbPciDev) * (uintptr_t)(a_idxPciDev)) \ + : (PPDMPCIDEV)NULL ) + + +/** + * 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)->CTX_SUFF(pHlp)->u32Version, CTX_MID(PDM_DEVHLP,_VERSION)), \ + ("DevHlp=%#x mine=%#x\n", (pDevIns)->CTX_SUFF(pHlp)->u32Version, CTX_MID(PDM_DEVHLP,_VERSION)), \ + VERR_PDM_DEVHLP_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_LIKELY(PDM_VERSION_ARE_COMPATIBLE((pDevIns)->u32Version, PDM_DEVINS_VERSION) )) \ + { /* likely */ } else return VERR_PDM_DEVINS_VERSION_MISMATCH; \ + if (RT_LIKELY(PDM_VERSION_ARE_COMPATIBLE((pDevIns)->CTX_SUFF(pHlp)->u32Version, CTX_MID(PDM_DEVHLP,_VERSION)) )) \ + { /* likely */ } else return VERR_PDM_DEVHLP_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 = pDevIns->pHlpR3->pfnCFGMValidateConfig((pDevIns)->pCfg, "/", pszValidValues, pszValidNodes, \ + (pDevIns)->pReg->szName, (pDevIns)->iInstance); \ + if (RT_SUCCESS(rcValCfg)) \ + { /* likely */ } else 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 to a RC PDM Device instance pointer. + */ +#ifdef IN_RC +# define PDMDEVINS_2_RCPTR(pDevIns) (pDevIns) +#else +# define PDMDEVINS_2_RCPTR(pDevIns) ( (pDevIns)->pDevInsForRC ) +#endif + +/** @def PDMDEVINS_2_R3PTR + * Converts a PDM Device instance pointer to a R3 PDM Device instance pointer. + */ +#ifdef IN_RING3 +# define PDMDEVINS_2_R3PTR(pDevIns) (pDevIns) +#else +# define PDMDEVINS_2_R3PTR(pDevIns) ( (pDevIns)->pDevInsForR3 ) +#endif + +/** @def PDMDEVINS_2_R0PTR + * Converts a PDM Device instance pointer to a R0 PDM Device instance pointer. + */ +#ifdef IN_RING0 +# define PDMDEVINS_2_R0PTR(pDevIns) (pDevIns) +#else +# define PDMDEVINS_2_R0PTR(pDevIns) ( (pDevIns)->pDevInsR0RemoveMe ) +#endif + +/** @def PDMDEVINS_DATA_2_R0_REMOVE_ME + * Converts a PDM device instance data pointer to a ring-0 one. + * @deprecated + */ +#ifdef IN_RING0 +# define PDMDEVINS_DATA_2_R0_REMOVE_ME(pDevIns, pvCC) (pvCC) +#else +# define PDMDEVINS_DATA_2_R0_REMOVE_ME(pDevIns, pvCC) ( (pDevIns)->pvInstanceDataR0 + (uintptr_t)(pvCC) - (uintptr_t)(pDevIns)->CTX_SUFF(pvInstanceData) ) +#endif + + +/** @def PDMDEVINS_2_DATA + * This is a safer edition of PDMINS_2_DATA that checks that the size of the + * target type is same as PDMDEVREG::cbInstanceShared in strict builds. + * + * @note Do no use this macro in common code working on a core structure which + * device specific code has expanded. + */ +#if defined(VBOX_STRICT) && defined(RT_COMPILER_SUPPORTS_LAMBDA) +# define PDMDEVINS_2_DATA(a_pDevIns, a_PtrType) \ + ([](PPDMDEVINS a_pLambdaDevIns) -> a_PtrType \ + { \ + a_PtrType pLambdaRet = (a_PtrType)(a_pLambdaDevIns)->CTX_SUFF(pvInstanceData); \ + Assert(sizeof(*pLambdaRet) == a_pLambdaDevIns->pReg->cbInstanceShared); \ + return pLambdaRet; \ + }(a_pDevIns)) +#else +# define PDMDEVINS_2_DATA(a_pDevIns, a_PtrType) ( (a_PtrType)(a_pDevIns)->CTX_SUFF(pvInstanceData) ) +#endif + +/** @def PDMDEVINS_2_DATA_CC + * This is a safer edition of PDMINS_2_DATA_CC that checks that the size of the + * target type is same as PDMDEVREG::cbInstanceCC in strict builds. + * + * @note Do no use this macro in common code working on a core structure which + * device specific code has expanded. + */ +#if defined(VBOX_STRICT) && defined(RT_COMPILER_SUPPORTS_LAMBDA) +# define PDMDEVINS_2_DATA_CC(a_pDevIns, a_PtrType) \ + ([](PPDMDEVINS a_pLambdaDevIns) -> a_PtrType \ + { \ + a_PtrType pLambdaRet = (a_PtrType)&(a_pLambdaDevIns)->achInstanceData[0]; \ + Assert(sizeof(*pLambdaRet) == a_pLambdaDevIns->pReg->cbInstanceCC); \ + return pLambdaRet; \ + }(a_pDevIns)) +#else +# define PDMDEVINS_2_DATA_CC(a_pDevIns, a_PtrType) ( (a_PtrType)(void *)&(a_pDevIns)->achInstanceData[0] ) +#endif + + +#ifdef IN_RING3 + +/** + * Combines PDMDevHlpIoPortCreate() & PDMDevHlpIoPortMap(). + */ +DECLINLINE(int) PDMDevHlpIoPortCreateAndMap(PPDMDEVINS pDevIns, RTIOPORT Port, RTIOPORT cPorts, PFNIOMIOPORTNEWOUT pfnOut, + PFNIOMIOPORTNEWIN pfnIn, const char *pszDesc, PCIOMIOPORTDESC paExtDescs, + PIOMIOPORTHANDLE phIoPorts) +{ + int rc = pDevIns->pHlpR3->pfnIoPortCreateEx(pDevIns, cPorts, 0, NULL, UINT32_MAX, + pfnOut, pfnIn, NULL, NULL, NULL, pszDesc, paExtDescs, phIoPorts); + if (RT_SUCCESS(rc)) + rc = pDevIns->pHlpR3->pfnIoPortMap(pDevIns, *phIoPorts, Port); + return rc; +} + +/** + * Combines PDMDevHlpIoPortCreate() & PDMDevHlpIoPortMap(), but with pvUser. + */ +DECLINLINE(int) PDMDevHlpIoPortCreateUAndMap(PPDMDEVINS pDevIns, RTIOPORT Port, RTIOPORT cPorts, PFNIOMIOPORTNEWOUT pfnOut, + PFNIOMIOPORTNEWIN pfnIn, void *pvUser, + const char *pszDesc, PCIOMIOPORTDESC paExtDescs, PIOMIOPORTHANDLE phIoPorts) +{ + int rc = pDevIns->pHlpR3->pfnIoPortCreateEx(pDevIns, cPorts, 0, NULL, UINT32_MAX, + pfnOut, pfnIn, NULL, NULL, pvUser, pszDesc, paExtDescs, phIoPorts); + if (RT_SUCCESS(rc)) + rc = pDevIns->pHlpR3->pfnIoPortMap(pDevIns, *phIoPorts, Port); + return rc; +} + +/** + * Combines PDMDevHlpIoPortCreate() & PDMDevHlpIoPortMap(), but with flags. + */ +DECLINLINE(int) PDMDevHlpIoPortCreateFlagsAndMap(PPDMDEVINS pDevIns, RTIOPORT Port, RTIOPORT cPorts, uint32_t fFlags, + PFNIOMIOPORTNEWOUT pfnOut, PFNIOMIOPORTNEWIN pfnIn, + const char *pszDesc, PCIOMIOPORTDESC paExtDescs, PIOMIOPORTHANDLE phIoPorts) +{ + int rc = pDevIns->pHlpR3->pfnIoPortCreateEx(pDevIns, cPorts, fFlags, NULL, UINT32_MAX, + pfnOut, pfnIn, NULL, NULL, NULL, pszDesc, paExtDescs, phIoPorts); + if (RT_SUCCESS(rc)) + rc = pDevIns->pHlpR3->pfnIoPortMap(pDevIns, *phIoPorts, Port); + return rc; +} + +/** + * Combines PDMDevHlpIoPortCreateEx() & PDMDevHlpIoPortMap(). + */ +DECLINLINE(int) PDMDevHlpIoPortCreateExAndMap(PPDMDEVINS pDevIns, RTIOPORT Port, RTIOPORT cPorts, uint32_t fFlags, + PFNIOMIOPORTNEWOUT pfnOut, PFNIOMIOPORTNEWIN pfnIn, + PFNIOMIOPORTNEWOUTSTRING pfnOutStr, PFNIOMIOPORTNEWINSTRING pfnInStr, void *pvUser, + const char *pszDesc, PCIOMIOPORTDESC paExtDescs, PIOMIOPORTHANDLE phIoPorts) +{ + int rc = pDevIns->pHlpR3->pfnIoPortCreateEx(pDevIns, cPorts, fFlags, NULL, UINT32_MAX, + pfnOut, pfnIn, pfnOutStr, pfnInStr, pvUser, pszDesc, paExtDescs, phIoPorts); + if (RT_SUCCESS(rc)) + rc = pDevIns->pHlpR3->pfnIoPortMap(pDevIns, *phIoPorts, Port); + return rc; +} + +/** + * @sa PDMDevHlpIoPortCreateEx + */ +DECLINLINE(int) PDMDevHlpIoPortCreate(PPDMDEVINS pDevIns, RTIOPORT cPorts, PPDMPCIDEV pPciDev, uint32_t iPciRegion, + PFNIOMIOPORTNEWOUT pfnOut, PFNIOMIOPORTNEWIN pfnIn, void *pvUser, const char *pszDesc, + PCIOMIOPORTDESC paExtDescs, PIOMIOPORTHANDLE phIoPorts) +{ + return pDevIns->pHlpR3->pfnIoPortCreateEx(pDevIns, cPorts, 0, pPciDev, iPciRegion, + pfnOut, pfnIn, NULL, NULL, pvUser, pszDesc, paExtDescs, phIoPorts); +} + + +/** + * @sa PDMDevHlpIoPortCreateEx + */ +DECLINLINE(int) PDMDevHlpIoPortCreateIsa(PPDMDEVINS pDevIns, RTIOPORT cPorts, PFNIOMIOPORTNEWOUT pfnOut, + PFNIOMIOPORTNEWIN pfnIn, void *pvUser, const char *pszDesc, + PCIOMIOPORTDESC paExtDescs, PIOMIOPORTHANDLE phIoPorts) +{ + return pDevIns->pHlpR3->pfnIoPortCreateEx(pDevIns, cPorts, 0, NULL, UINT32_MAX, + pfnOut, pfnIn, NULL, NULL, pvUser, pszDesc, paExtDescs, phIoPorts); +} + +/** + * @copydoc PDMDEVHLPR3::pfnIoPortCreateEx + */ +DECLINLINE(int) PDMDevHlpIoPortCreateEx(PPDMDEVINS pDevIns, RTIOPORT cPorts, uint32_t fFlags, PPDMPCIDEV pPciDev, + uint32_t iPciRegion, PFNIOMIOPORTNEWOUT pfnOut, PFNIOMIOPORTNEWIN pfnIn, + PFNIOMIOPORTNEWOUTSTRING pfnOutStr, PFNIOMIOPORTNEWINSTRING pfnInStr, void *pvUser, + const char *pszDesc, PCIOMIOPORTDESC paExtDescs, PIOMIOPORTHANDLE phIoPorts) +{ + return pDevIns->pHlpR3->pfnIoPortCreateEx(pDevIns, cPorts, fFlags, pPciDev, iPciRegion, + pfnOut, pfnIn, pfnOutStr, pfnInStr, pvUser, pszDesc, paExtDescs, phIoPorts); +} + +/** + * @copydoc PDMDEVHLPR3::pfnIoPortMap + */ +DECLINLINE(int) PDMDevHlpIoPortMap(PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts, RTIOPORT Port) +{ + return pDevIns->pHlpR3->pfnIoPortMap(pDevIns, hIoPorts, Port); +} + +/** + * @copydoc PDMDEVHLPR3::pfnIoPortUnmap + */ +DECLINLINE(int) PDMDevHlpIoPortUnmap(PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts) +{ + return pDevIns->pHlpR3->pfnIoPortUnmap(pDevIns, hIoPorts); +} + +/** + * @copydoc PDMDEVHLPR3::pfnIoPortGetMappingAddress + */ +DECLINLINE(uint32_t) PDMDevHlpIoPortGetMappingAddress(PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts) +{ + return pDevIns->pHlpR3->pfnIoPortGetMappingAddress(pDevIns, hIoPorts); +} + + +#endif /* IN_RING3 */ +#if !defined(IN_RING3) || defined(DOXYGEN_RUNNING) + +/** + * @sa PDMDevHlpIoPortSetUpContextEx + */ +DECLINLINE(int) PDMDevHlpIoPortSetUpContext(PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts, + PFNIOMIOPORTNEWOUT pfnOut, PFNIOMIOPORTNEWIN pfnIn, void *pvUser) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnIoPortSetUpContextEx(pDevIns, hIoPorts, pfnOut, pfnIn, NULL, NULL, pvUser); +} + +/** + * @copydoc PDMDEVHLPR0::pfnIoPortSetUpContextEx + */ +DECLINLINE(int) PDMDevHlpIoPortSetUpContextEx(PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts, + PFNIOMIOPORTNEWOUT pfnOut, PFNIOMIOPORTNEWIN pfnIn, + PFNIOMIOPORTNEWOUTSTRING pfnOutStr, PFNIOMIOPORTNEWINSTRING pfnInStr, void *pvUser) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnIoPortSetUpContextEx(pDevIns, hIoPorts, pfnOut, pfnIn, pfnOutStr, pfnInStr, pvUser); +} + +#endif /* !IN_RING3 || DOXYGEN_RUNNING */ +#ifdef IN_RING3 + +/** + * @sa PDMDevHlpMmioCreateEx + */ +DECLINLINE(int) PDMDevHlpMmioCreate(PPDMDEVINS pDevIns, RTGCPHYS cbRegion, PPDMPCIDEV pPciDev, uint32_t iPciRegion, + PFNIOMMMIONEWWRITE pfnWrite, PFNIOMMMIONEWREAD pfnRead, void *pvUser, + uint32_t fFlags, const char *pszDesc, PIOMMMIOHANDLE phRegion) +{ + return pDevIns->pHlpR3->pfnMmioCreateEx(pDevIns, cbRegion, fFlags, pPciDev, iPciRegion, + pfnWrite, pfnRead, NULL, pvUser, pszDesc, phRegion); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMmioCreateEx + */ +DECLINLINE(int) PDMDevHlpMmioCreateEx(PPDMDEVINS pDevIns, RTGCPHYS cbRegion, + uint32_t fFlags, PPDMPCIDEV pPciDev, uint32_t iPciRegion, + PFNIOMMMIONEWWRITE pfnWrite, PFNIOMMMIONEWREAD pfnRead, PFNIOMMMIONEWFILL pfnFill, + void *pvUser, const char *pszDesc, PIOMMMIOHANDLE phRegion) +{ + return pDevIns->pHlpR3->pfnMmioCreateEx(pDevIns, cbRegion, fFlags, pPciDev, iPciRegion, + pfnWrite, pfnRead, pfnFill, pvUser, pszDesc, phRegion); +} + +/** + * @sa PDMDevHlpMmioCreate and PDMDevHlpMmioMap + */ +DECLINLINE(int) PDMDevHlpMmioCreateAndMap(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTGCPHYS cbRegion, + PFNIOMMMIONEWWRITE pfnWrite, PFNIOMMMIONEWREAD pfnRead, + uint32_t fFlags, const char *pszDesc, PIOMMMIOHANDLE phRegion) +{ + int rc = pDevIns->pHlpR3->pfnMmioCreateEx(pDevIns, cbRegion, fFlags, NULL /*pPciDev*/, UINT32_MAX /*iPciRegion*/, + pfnWrite, pfnRead, NULL /*pfnFill*/, NULL /*pvUser*/, pszDesc, phRegion); + if (RT_SUCCESS(rc)) + rc = pDevIns->pHlpR3->pfnMmioMap(pDevIns, *phRegion, GCPhys); + return rc; +} + +/** + * @sa PDMDevHlpMmioCreateEx and PDMDevHlpMmioMap + */ +DECLINLINE(int) PDMDevHlpMmioCreateExAndMap(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTGCPHYS cbRegion, uint32_t fFlags, + PPDMPCIDEV pPciDev, uint32_t iPciRegion, PFNIOMMMIONEWWRITE pfnWrite, + PFNIOMMMIONEWREAD pfnRead, PFNIOMMMIONEWFILL pfnFill, void *pvUser, + const char *pszDesc, PIOMMMIOHANDLE phRegion) +{ + int rc = pDevIns->pHlpR3->pfnMmioCreateEx(pDevIns, cbRegion, fFlags, pPciDev, iPciRegion, + pfnWrite, pfnRead, pfnFill, pvUser, pszDesc, phRegion); + if (RT_SUCCESS(rc)) + rc = pDevIns->pHlpR3->pfnMmioMap(pDevIns, *phRegion, GCPhys); + return rc; +} + +/** + * @copydoc PDMDEVHLPR3::pfnMmioMap + */ +DECLINLINE(int) PDMDevHlpMmioMap(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS GCPhys) +{ + return pDevIns->pHlpR3->pfnMmioMap(pDevIns, hRegion, GCPhys); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMmioUnmap + */ +DECLINLINE(int) PDMDevHlpMmioUnmap(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion) +{ + return pDevIns->pHlpR3->pfnMmioUnmap(pDevIns, hRegion); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMmioReduce + */ +DECLINLINE(int) PDMDevHlpMmioReduce(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS cbRegion) +{ + return pDevIns->pHlpR3->pfnMmioReduce(pDevIns, hRegion, cbRegion); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMmioGetMappingAddress + */ +DECLINLINE(RTGCPHYS) PDMDevHlpMmioGetMappingAddress(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion) +{ + return pDevIns->pHlpR3->pfnMmioGetMappingAddress(pDevIns, hRegion); +} + +#endif /* IN_RING3 */ +#if !defined(IN_RING3) || defined(DOXYGEN_RUNNING) + +/** + * @sa PDMDevHlpMmioSetUpContextEx + */ +DECLINLINE(int) PDMDevHlpMmioSetUpContext(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, + PFNIOMMMIONEWWRITE pfnWrite, PFNIOMMMIONEWREAD pfnRead, void *pvUser) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnMmioSetUpContextEx(pDevIns, hRegion, pfnWrite, pfnRead, NULL, pvUser); +} + +/** + * @copydoc PDMDEVHLPR0::pfnMmioSetUpContextEx + */ +DECLINLINE(int) PDMDevHlpMmioSetUpContextEx(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, PFNIOMMMIONEWWRITE pfnWrite, + PFNIOMMMIONEWREAD pfnRead, PFNIOMMMIONEWFILL pfnFill, void *pvUser) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnMmioSetUpContextEx(pDevIns, hRegion, pfnWrite, pfnRead, pfnFill, pvUser); +} + +#endif /* !IN_RING3 || DOXYGEN_RUNNING */ +#ifdef IN_RING3 + +/** + * @copydoc PDMDEVHLPR3::pfnMmio2Create + */ +DECLINLINE(int) PDMDevHlpMmio2Create(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iPciRegion, RTGCPHYS cbRegion, + uint32_t fFlags, const char *pszDesc, void **ppvMapping, PPGMMMIO2HANDLE phRegion) +{ + return pDevIns->pHlpR3->pfnMmio2Create(pDevIns, pPciDev, iPciRegion, cbRegion, fFlags, pszDesc, ppvMapping, phRegion); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMmio2Map + */ +DECLINLINE(int) PDMDevHlpMmio2Map(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion, RTGCPHYS GCPhys) +{ + return pDevIns->pHlpR3->pfnMmio2Map(pDevIns, hRegion, GCPhys); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMmio2Unmap + */ +DECLINLINE(int) PDMDevHlpMmio2Unmap(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion) +{ + return pDevIns->pHlpR3->pfnMmio2Unmap(pDevIns, hRegion); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMmio2Reduce + */ +DECLINLINE(int) PDMDevHlpMmio2Reduce(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion, RTGCPHYS cbRegion) +{ + return pDevIns->pHlpR3->pfnMmio2Reduce(pDevIns, hRegion, cbRegion); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMmio2GetMappingAddress + */ +DECLINLINE(RTGCPHYS) PDMDevHlpMmio2GetMappingAddress(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion) +{ + return pDevIns->pHlpR3->pfnMmio2GetMappingAddress(pDevIns, hRegion); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMmio2QueryAndResetDirtyBitmap + */ +DECLINLINE(int) PDMDevHlpMmio2QueryAndResetDirtyBitmap(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion, + void *pvBitmap, size_t cbBitmap) +{ + return pDevIns->pHlpR3->pfnMmio2QueryAndResetDirtyBitmap(pDevIns, hRegion, pvBitmap, cbBitmap); +} + +/** + * Reset the dirty bitmap tracking for an MMIO2 region. + * + * The MMIO2 region must have been created with the + * PGMPHYS_MMIO2_FLAGS_TRACK_DIRTY_PAGES flag for this to work. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param hRegion The MMIO2 region handle. + */ +DECLINLINE(int) PDMDevHlpMmio2ResetDirtyBitmap(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion) +{ + return pDevIns->pHlpR3->pfnMmio2QueryAndResetDirtyBitmap(pDevIns, hRegion, NULL, 0); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMmio2ControlDirtyPageTracking + */ +DECLINLINE(int) PDMDevHlpMmio2ControlDirtyPageTracking(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion, bool fEnabled) +{ + return pDevIns->pHlpR3->pfnMmio2ControlDirtyPageTracking(pDevIns, hRegion, fEnabled); +} + +#endif /* IN_RING3 */ + +/** + * @copydoc PDMDEVHLPR3::pfnMmioMapMmio2Page + */ +DECLINLINE(int) PDMDevHlpMmioMapMmio2Page(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS offRegion, + uint64_t hMmio2, RTGCPHYS offMmio2, uint64_t fPageFlags) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnMmioMapMmio2Page(pDevIns, hRegion, offRegion, hMmio2, offMmio2, fPageFlags); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMmioResetRegion + */ +DECLINLINE(int) PDMDevHlpMmioResetRegion(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnMmioResetRegion(pDevIns, hRegion); +} + +#if !defined(IN_RING3) || defined(DOXYGEN_RUNNING) + +/** + * @copydoc PDMDEVHLPR0::pfnMmio2SetUpContext + */ +DECLINLINE(int) PDMDevHlpMmio2SetUpContext(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion, + size_t offSub, size_t cbSub, void **ppvMapping) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnMmio2SetUpContext(pDevIns, hRegion, offSub, cbSub, ppvMapping); +} + +#endif /* !IN_RING3 || DOXYGEN_RUNNING */ +#ifdef IN_RING3 + +/** + * @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, + PFNSSMDEVLIVEEXEC 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::pfnSSMRegisterLegacy + */ +DECLINLINE(int) PDMDevHlpSSMRegisterLegacy(PPDMDEVINS pDevIns, const char *pszOldName, PFNSSMDEVLOADPREP pfnLoadPrep, + PFNSSMDEVLOADEXEC pfnLoadExec, PFNSSMDEVLOADDONE pfnLoadDone) +{ + return pDevIns->pHlpR3->pfnSSMRegisterLegacy(pDevIns, pszOldName, pfnLoadPrep, pfnLoadExec, pfnLoadDone); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerCreate + */ +DECLINLINE(int) PDMDevHlpTimerCreate(PPDMDEVINS pDevIns, TMCLOCK enmClock, PFNTMTIMERDEV pfnCallback, void *pvUser, + uint32_t fFlags, const char *pszDesc, PTMTIMERHANDLE phTimer) +{ + return pDevIns->pHlpR3->pfnTimerCreate(pDevIns, enmClock, pfnCallback, pvUser, fFlags, pszDesc, phTimer); +} + +#endif /* IN_RING3 */ + +/** + * @copydoc PDMDEVHLPR3::pfnTimerFromMicro + */ +DECLINLINE(uint64_t) PDMDevHlpTimerFromMicro(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cMicroSecs) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerFromMicro(pDevIns, hTimer, cMicroSecs); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerFromMilli + */ +DECLINLINE(uint64_t) PDMDevHlpTimerFromMilli(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cMilliSecs) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerFromMilli(pDevIns, hTimer, cMilliSecs); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerFromNano + */ +DECLINLINE(uint64_t) PDMDevHlpTimerFromNano(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cNanoSecs) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerFromNano(pDevIns, hTimer, cNanoSecs); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerGet + */ +DECLINLINE(uint64_t) PDMDevHlpTimerGet(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerGet(pDevIns, hTimer); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerGetFreq + */ +DECLINLINE(uint64_t) PDMDevHlpTimerGetFreq(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerGetFreq(pDevIns, hTimer); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerGetNano + */ +DECLINLINE(uint64_t) PDMDevHlpTimerGetNano(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerGetNano(pDevIns, hTimer); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerIsActive + */ +DECLINLINE(bool) PDMDevHlpTimerIsActive(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerIsActive(pDevIns, hTimer); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerIsLockOwner + */ +DECLINLINE(bool) PDMDevHlpTimerIsLockOwner(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerIsLockOwner(pDevIns, hTimer); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerLockClock + */ +DECLINLINE(VBOXSTRICTRC) PDMDevHlpTimerLockClock(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, int rcBusy) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerLockClock(pDevIns, hTimer, rcBusy); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerLockClock2 + */ +DECLINLINE(VBOXSTRICTRC) PDMDevHlpTimerLockClock2(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect, int rcBusy) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerLockClock2(pDevIns, hTimer, pCritSect, rcBusy); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerSet + */ +DECLINLINE(int) PDMDevHlpTimerSet(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t uExpire) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerSet(pDevIns, hTimer, uExpire); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerSetFrequencyHint + */ +DECLINLINE(int) PDMDevHlpTimerSetFrequencyHint(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint32_t uHz) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerSetFrequencyHint(pDevIns, hTimer, uHz); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerSetMicro + */ +DECLINLINE(int) PDMDevHlpTimerSetMicro(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cMicrosToNext) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerSetMicro(pDevIns, hTimer, cMicrosToNext); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerSetMillies + */ +DECLINLINE(int) PDMDevHlpTimerSetMillies(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cMilliesToNext) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerSetMillies(pDevIns, hTimer, cMilliesToNext); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerSetNano + */ +DECLINLINE(int) PDMDevHlpTimerSetNano(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cNanosToNext) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerSetNano(pDevIns, hTimer, cNanosToNext); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerSetRelative + */ +DECLINLINE(int) PDMDevHlpTimerSetRelative(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cTicksToNext, uint64_t *pu64Now) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerSetRelative(pDevIns, hTimer, cTicksToNext, pu64Now); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerStop + */ +DECLINLINE(int) PDMDevHlpTimerStop(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerStop(pDevIns, hTimer); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerUnlockClock + */ +DECLINLINE(void) PDMDevHlpTimerUnlockClock(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer) +{ + pDevIns->CTX_SUFF(pHlp)->pfnTimerUnlockClock(pDevIns, hTimer); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerUnlockClock2 + */ +DECLINLINE(void) PDMDevHlpTimerUnlockClock2(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect) +{ + pDevIns->CTX_SUFF(pHlp)->pfnTimerUnlockClock2(pDevIns, hTimer, pCritSect); +} + +#ifdef IN_RING3 + +/** + * @copydoc PDMDEVHLPR3::pfnTimerSetCritSect + */ +DECLINLINE(int) PDMDevHlpTimerSetCritSect(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect) +{ + return pDevIns->pHlpR3->pfnTimerSetCritSect(pDevIns, hTimer, pCritSect); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerSave + */ +DECLINLINE(int) PDMDevHlpTimerSave(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, PSSMHANDLE pSSM) +{ + return pDevIns->pHlpR3->pfnTimerSave(pDevIns, hTimer, pSSM); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerLoad + */ +DECLINLINE(int) PDMDevHlpTimerLoad(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, PSSMHANDLE pSSM) +{ + return pDevIns->pHlpR3->pfnTimerLoad(pDevIns, hTimer, pSSM); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerDestroy + */ +DECLINLINE(int) PDMDevHlpTimerDestroy(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer) +{ + return pDevIns->pHlpR3->pfnTimerDestroy(pDevIns, hTimer); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTMUtcNow + */ +DECLINLINE(PRTTIMESPEC) PDMDevHlpTMUtcNow(PPDMDEVINS pDevIns, PRTTIMESPEC pTime) +{ + return pDevIns->pHlpR3->pfnTMUtcNow(pDevIns, pTime); +} + +#endif + +/** + * Read physical memory - unknown data usage. + * + * @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. + */ +DECLINLINE(int) PDMDevHlpPhysRead(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPhysRead(pDevIns, GCPhys, pvBuf, cbRead, PDM_DEVHLP_PHYS_RW_F_DEFAULT); +} + +/** + * Write to physical memory - unknown data usage. + * + * @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. + */ +DECLINLINE(int) PDMDevHlpPhysWrite(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPhysWrite(pDevIns, GCPhys, pvBuf, cbWrite, PDM_DEVHLP_PHYS_RW_F_DEFAULT); +} + +/** + * Read physical memory - reads meta data processed by the device. + * + * @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. + */ +DECLINLINE(int) PDMDevHlpPhysReadMeta(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPhysRead(pDevIns, GCPhys, pvBuf, cbRead, PDM_DEVHLP_PHYS_RW_F_DATA_META); +} + +/** + * Write to physical memory - written data was created/altered by the device. + * + * @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. + */ +DECLINLINE(int) PDMDevHlpPhysWriteMeta(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPhysWrite(pDevIns, GCPhys, pvBuf, cbWrite, PDM_DEVHLP_PHYS_RW_F_DATA_META); +} + +/** + * Read physical memory - read data will not be touched by the device. + * + * @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. + */ +DECLINLINE(int) PDMDevHlpPhysReadUser(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPhysRead(pDevIns, GCPhys, pvBuf, cbRead, PDM_DEVHLP_PHYS_RW_F_DATA_USER); +} + +/** + * Write to physical memory - written data was not touched/created by the device. + * + * @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. + */ +DECLINLINE(int) PDMDevHlpPhysWriteUser(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPhysWrite(pDevIns, GCPhys, pvBuf, cbWrite, PDM_DEVHLP_PHYS_RW_F_DATA_USER); +} + +#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::pfnPhysBulkGCPhys2CCPtr + */ +DECLINLINE(int) PDMDevHlpPhysBulkGCPhys2CCPtr(PPDMDEVINS pDevIns, uint32_t cPages, PCRTGCPHYS paGCPhysPages, + uint32_t fFlags, void **papvPages, PPGMPAGEMAPLOCK paLocks) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPhysBulkGCPhys2CCPtr(pDevIns, cPages, paGCPhysPages, fFlags, papvPages, paLocks); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPhysBulkGCPhys2CCPtrReadOnly + */ +DECLINLINE(int) PDMDevHlpPhysBulkGCPhys2CCPtrReadOnly(PPDMDEVINS pDevIns, uint32_t cPages, PCRTGCPHYS paGCPhysPages, + uint32_t fFlags, void const **papvPages, PPGMPAGEMAPLOCK paLocks) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPhysBulkGCPhys2CCPtrReadOnly(pDevIns, cPages, paGCPhysPages, fFlags, papvPages, paLocks); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPhysBulkReleasePageMappingLocks + */ +DECLINLINE(void) PDMDevHlpPhysBulkReleasePageMappingLocks(PPDMDEVINS pDevIns, uint32_t cPages, PPGMPAGEMAPLOCK paLocks) +{ + pDevIns->CTX_SUFF(pHlp)->pfnPhysBulkReleasePageMappingLocks(pDevIns, cPages, paLocks); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPhysIsGCPhysNormal + */ +DECLINLINE(bool) PDMDevHlpPhysIsGCPhysNormal(PPDMDEVINS pDevIns, RTGCPHYS GCPhys) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPhysIsGCPhysNormal(pDevIns, GCPhys); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPhysChangeMemBalloon + */ +DECLINLINE(int) PDMDevHlpPhysChangeMemBalloon(PPDMDEVINS pDevIns, bool fInflate, unsigned cPages, RTGCPHYS *paPhysPage) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPhysChangeMemBalloon(pDevIns, fInflate, cPages, paPhysPage); +} + +/** + * @copydoc PDMDEVHLPR3::pfnCpuGetGuestMicroarch + */ +DECLINLINE(CPUMMICROARCH) PDMDevHlpCpuGetGuestMicroarch(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCpuGetGuestMicroarch(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnCpuGetGuestScalableBusFrequency + */ +DECLINLINE(uint64_t) PDMDevHlpCpuGetGuestScalableBusFrequency(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCpuGetGuestScalableBusFrequency(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnCpuGetGuestAddrWidths + */ +DECLINLINE(void) PDMDevHlpCpuGetGuestAddrWidths(PPDMDEVINS pDevIns, uint8_t *pcPhysAddrWidth, uint8_t *pcLinearAddrWidth) +{ + pDevIns->CTX_SUFF(pHlp)->pfnCpuGetGuestAddrWidths(pDevIns, pcPhysAddrWidth, pcLinearAddrWidth); +} + +/** + * @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); +} + +/** + * Allocating string printf. + * + * @returns Pointer to the string. + * @param pDevIns The device instance. + * @param enmTag The statistics tag. + * @param pszFormat The format string. + * @param ... Format arguments. + */ +DECLINLINE(char *) RT_IPRT_FORMAT_ATTR(2, 3) PDMDevHlpMMHeapAPrintf(PPDMDEVINS pDevIns, MMTAG enmTag, const char *pszFormat, ...) +{ + va_list va; + va_start(va, pszFormat); + char *psz = pDevIns->pHlpR3->pfnMMHeapAPrintfV(pDevIns, enmTag, pszFormat, va); + va_end(va); + + return psz; +} + +/** + * @copydoc PDMDEVHLPR3::pfnMMHeapFree + */ +DECLINLINE(void) PDMDevHlpMMHeapFree(PPDMDEVINS pDevIns, void *pv) +{ + pDevIns->pHlpR3->pfnMMHeapFree(pDevIns, pv); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMMPhysGetRamSize + */ +DECLINLINE(uint64_t) PDMDevHlpMMPhysGetRamSize(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnMMPhysGetRamSize(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMMPhysGetRamSizeBelow4GB + */ +DECLINLINE(uint32_t) PDMDevHlpMMPhysGetRamSizeBelow4GB(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnMMPhysGetRamSizeBelow4GB(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMMPhysGetRamSizeAbove4GB + */ +DECLINLINE(uint64_t) PDMDevHlpMMPhysGetRamSizeAbove4GB(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnMMPhysGetRamSizeAbove4GB(pDevIns); +} +#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); +} + +/** + * Set the VM error message + * + * @returns rc. + * @param pDevIns The device instance. + * @param rc VBox status code. + * @param SRC_POS Use RT_SRC_POS. + * @param pszFormat Error message format string. + * @param ... Error message arguments. + * @sa VMSetError + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(6, 7) 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; +} + +/** + * 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. + * @sa VMSetRuntimeError + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(4, 5) 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; +} + +/** + * @copydoc PDMDEVHLPR3::pfnVMWaitForDeviceReady + */ +DECLINLINE(int) PDMDevHlpVMWaitForDeviceReady(PPDMDEVINS pDevIns, VMCPUID idCpu) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnVMWaitForDeviceReady(pDevIns, idCpu); +} + +/** + * @copydoc PDMDEVHLPR3::pfnVMNotifyCpuDeviceReady + */ +DECLINLINE(int) PDMDevHlpVMNotifyCpuDeviceReady(PPDMDEVINS pDevIns, VMCPUID idCpu) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnVMNotifyCpuDeviceReady(pDevIns, idCpu); +} + +/** + * Convenience wrapper for VMR3ReqCallU. + * + * This assumes (1) you're calling a function that returns an VBox status code + * and that you do not wish to wait for it to complete. + * + * @returns VBox status code returned by VMR3ReqCallVU. + * + * @param pDevIns The device instance. + * @param idDstCpu The destination CPU(s). Either a specific CPU ID or + * one of the following special values: + * VMCPUID_ANY, VMCPUID_ANY_QUEUE, VMCPUID_ALL or VMCPUID_ALL_REVERSE. + * @param pfnFunction Pointer to the function to call. + * @param cArgs Number of arguments following in the ellipsis. + * @param ... Argument list. + * + * @remarks See remarks on VMR3ReqCallVU. + */ +DECLINLINE(int) PDMDevHlpVMReqCallNoWait(PPDMDEVINS pDevIns, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...) +{ + va_list Args; + va_start(Args, cArgs); + int rc = pDevIns->CTX_SUFF(pHlp)->pfnVMReqCallNoWaitV(pDevIns, idDstCpu, pfnFunction, cArgs, Args); + va_end(Args); + return rc; +} + +/** + * Convenience wrapper for VMR3ReqCallU. + * + * This assumes (1) you're calling a function that returns void, (2) that you + * wish to wait for ever for it to return, and (3) that it's priority request + * that can be safely be handled during async suspend and power off. + * + * @returns VBox status code of VMR3ReqCallVU. + * + * @param pDevIns The device instance. + * @param idDstCpu The destination CPU(s). Either a specific CPU ID or + * one of the following special values: + * VMCPUID_ANY, VMCPUID_ANY_QUEUE, VMCPUID_ALL or VMCPUID_ALL_REVERSE. + * @param pfnFunction Pointer to the function to call. + * @param cArgs Number of arguments following in the ellipsis. + * @param ... Argument list. + * + * @remarks See remarks on VMR3ReqCallVU. + */ +DECLINLINE(int) PDMDevHlpVMReqPriorityCallWait(PPDMDEVINS pDevIns, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...) +{ + va_list Args; + va_start(Args, cArgs); + int rc = pDevIns->CTX_SUFF(pHlp)->pfnVMReqPriorityCallWaitV(pDevIns, idDstCpu, pfnFunction, cArgs, Args); + va_end(Args); + return rc; +} + +#endif /* IN_RING3 */ + +/** + * 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 SRC_POS Use RT_SRC_POS. + * @param pszFormat Message. (optional) + * @param ... Message parameters. + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(5, 6) 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::pfnDBGFInfoRegisterArgv + */ +DECLINLINE(int) PDMDevHlpDBGFInfoRegisterArgv(PPDMDEVINS pDevIns, const char *pszName, const char *pszDesc, PFNDBGFINFOARGVDEV pfnHandler) +{ + return pDevIns->pHlpR3->pfnDBGFInfoRegisterArgv(pDevIns, pszName, pszDesc, pfnHandler); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDBGFRegRegister + */ +DECLINLINE(int) PDMDevHlpDBGFRegRegister(PPDMDEVINS pDevIns, PCDBGFREGDESC paRegisters) +{ + return pDevIns->pHlpR3->pfnDBGFRegRegister(pDevIns, paRegisters); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDBGFReportBugCheck + */ +DECLINLINE(VBOXSTRICTRC) PDMDevHlpDBGFReportBugCheck(PPDMDEVINS pDevIns, DBGFEVENTTYPE enmEvent, uint64_t uBugCheck, + uint64_t uP1, uint64_t uP2, uint64_t uP3, uint64_t uP4) +{ + return pDevIns->pHlpR3->pfnDBGFReportBugCheck(pDevIns, enmEvent, uBugCheck, uP1, uP2, uP3, uP4); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDBGFCoreWrite + */ +DECLINLINE(int) PDMDevHlpDBGFCoreWrite(PPDMDEVINS pDevIns, const char *pszFilename, bool fReplaceFile) +{ + return pDevIns->pHlpR3->pfnDBGFCoreWrite(pDevIns, pszFilename, fReplaceFile); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDBGFInfoLogHlp + */ +DECLINLINE(PCDBGFINFOHLP) PDMDevHlpDBGFInfoLogHlp(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnDBGFInfoLogHlp(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDBGFRegNmQueryU64 + */ +DECLINLINE(int) PDMDevHlpDBGFRegNmQueryU64(PPDMDEVINS pDevIns, VMCPUID idDefCpu, const char *pszReg, uint64_t *pu64) +{ + return pDevIns->pHlpR3->pfnDBGFRegNmQueryU64(pDevIns, idDefCpu, pszReg, pu64); +} + + /** + * Format a set of registers. + * + * This is restricted to registers from one CPU, that specified by @a idCpu. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param idCpu The CPU ID of any CPU registers that may be + * printed, pass VMCPUID_ANY if not applicable. + * @param pszBuf The output buffer. + * @param cbBuf The size of the output buffer. + * @param pszFormat The format string. Register names are given by + * %VR{name}, they take no arguments. + * @param ... Argument list. + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(4, 5) PDMDevHlpDBGFRegPrintf(PPDMDEVINS pDevIns, VMCPUID idCpu, char *pszBuf, size_t cbBuf, + const char *pszFormat, ...) +{ + va_list Args; + va_start(Args, pszFormat); + int rc = pDevIns->pHlpR3->pfnDBGFRegPrintfV(pDevIns, idCpu, pszBuf, cbBuf, pszFormat, Args); + va_end(Args); + return rc; +} + +/** + * @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); +} + +/** + * 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 Sample name format string, unix path style. If + * this does not start with a '/', the default + * prefix will be prepended, otherwise it will be + * used as-is. + * @param ... Arguments to the format string. + */ +DECLINLINE(void) RT_IPRT_FORMAT_ATTR(7, 8) 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::pfnSTAMDeregisterByPrefix + */ +DECLINLINE(int) PDMDevHlpSTAMDeregisterByPrefix(PPDMDEVINS pDevIns, const char *pszPrefix) +{ + return pDevIns->pHlpR3->pfnSTAMDeregisterByPrefix(pDevIns, pszPrefix); +} + +/** + * Registers the device with the default PCI bus. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. + * This must be kept in the instance data. + * The PCI configuration must be initialized before registration. + */ +DECLINLINE(int) PDMDevHlpPCIRegister(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev) +{ + return pDevIns->pHlpR3->pfnPCIRegister(pDevIns, pPciDev, 0 /*fFlags*/, + PDMPCIDEVREG_DEV_NO_FIRST_UNUSED, PDMPCIDEVREG_FUN_NO_FIRST_UNUSED, NULL); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPCIRegister + */ +DECLINLINE(int) PDMDevHlpPCIRegisterEx(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t fFlags, + uint8_t uPciDevNo, uint8_t uPciFunNo, const char *pszName) +{ + return pDevIns->pHlpR3->pfnPCIRegister(pDevIns, pPciDev, fFlags, uPciDevNo, uPciFunNo, pszName); +} + +/** + * Initialize MSI emulation support for the first PCI device. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pMsiReg MSI emulation registration structure. + */ +DECLINLINE(int) PDMDevHlpPCIRegisterMsi(PPDMDEVINS pDevIns, PPDMMSIREG pMsiReg) +{ + return pDevIns->pHlpR3->pfnPCIRegisterMsi(pDevIns, NULL, pMsiReg); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPCIRegisterMsi + */ +DECLINLINE(int) PDMDevHlpPCIRegisterMsiEx(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, PPDMMSIREG pMsiReg) +{ + return pDevIns->pHlpR3->pfnPCIRegisterMsi(pDevIns, pPciDev, pMsiReg); +} + +/** + * Registers a I/O port region for the default PCI device. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param iRegion The region number. + * @param cbRegion Size of the region. + * @param hIoPorts Handle to the I/O port region. + */ +DECLINLINE(int) PDMDevHlpPCIIORegionRegisterIo(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS cbRegion, IOMIOPORTHANDLE hIoPorts) +{ + return pDevIns->pHlpR3->pfnPCIIORegionRegister(pDevIns, NULL, iRegion, cbRegion, PCI_ADDRESS_SPACE_IO, + PDMPCIDEV_IORGN_F_IOPORT_HANDLE | PDMPCIDEV_IORGN_F_NEW_STYLE, hIoPorts, NULL); +} + +/** + * Registers a I/O port region for the default PCI device, custom map/unmap. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param iRegion The region number. + * @param cbRegion Size of the region. + * @param pfnMapUnmap Callback for doing the mapping, optional. The + * callback will be invoked holding only the PDM lock. + * The device lock will _not_ be taken (due to lock + * order). + */ +DECLINLINE(int) PDMDevHlpPCIIORegionRegisterIoCustom(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS cbRegion, + PFNPCIIOREGIONMAP pfnMapUnmap) +{ + return pDevIns->pHlpR3->pfnPCIIORegionRegister(pDevIns, NULL, iRegion, cbRegion, PCI_ADDRESS_SPACE_IO, + PDMPCIDEV_IORGN_F_NO_HANDLE | PDMPCIDEV_IORGN_F_NEW_STYLE, + UINT64_MAX, pfnMapUnmap); +} + +/** + * Combines PDMDevHlpIoPortCreate and PDMDevHlpPCIIORegionRegisterIo, creating + * and registering an I/O port region for the default PCI device. + * + * @returns VBox status code. + * @param pDevIns The device instance to register the ports with. + * @param cPorts The count of I/O ports in the region (the size). + * @param iPciRegion The PCI device region. + * @param pfnOut Pointer to function which is gonna handle OUT + * operations. Optional. + * @param pfnIn Pointer to function which is gonna handle IN operations. + * Optional. + * @param pvUser User argument to pass to the callbacks. + * @param pszDesc Pointer to description string. This must not be freed. + * @param paExtDescs Extended per-port descriptions, optional. Partial range + * coverage is allowed. This must not be freed. + * @param phIoPorts Where to return the I/O port range handle. + * + */ +DECLINLINE(int) PDMDevHlpPCIIORegionCreateIo(PPDMDEVINS pDevIns, uint32_t iPciRegion, RTIOPORT cPorts, + PFNIOMIOPORTNEWOUT pfnOut, PFNIOMIOPORTNEWIN pfnIn, void *pvUser, + const char *pszDesc, PCIOMIOPORTDESC paExtDescs, PIOMIOPORTHANDLE phIoPorts) + +{ + int rc = pDevIns->pHlpR3->pfnIoPortCreateEx(pDevIns, cPorts, 0 /*fFlags*/, pDevIns->apPciDevs[0], iPciRegion << 16, + pfnOut, pfnIn, NULL, NULL, pvUser, pszDesc, paExtDescs, phIoPorts); + if (RT_SUCCESS(rc)) + rc = pDevIns->pHlpR3->pfnPCIIORegionRegister(pDevIns, pDevIns->apPciDevs[0], iPciRegion, cPorts, PCI_ADDRESS_SPACE_IO, + PDMPCIDEV_IORGN_F_IOPORT_HANDLE | PDMPCIDEV_IORGN_F_NEW_STYLE, + *phIoPorts, NULL /*pfnMapUnmap*/); + return rc; +} + +/** + * Registers an MMIO region for the default 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 or + * PCI_ADDRESS_SPACE_MEM_PREFETCH, optionally or-ing in + * PCI_ADDRESS_SPACE_BAR64 or PCI_ADDRESS_SPACE_BAR32. + * @param hMmioRegion Handle to the MMIO region. + * @param pfnMapUnmap Callback for doing the mapping, optional. The + * callback will be invoked holding only the PDM lock. + * The device lock will _not_ be taken (due to lock + * order). + */ +DECLINLINE(int) PDMDevHlpPCIIORegionRegisterMmio(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS cbRegion, PCIADDRESSSPACE enmType, + IOMMMIOHANDLE hMmioRegion, PFNPCIIOREGIONMAP pfnMapUnmap) +{ + return pDevIns->pHlpR3->pfnPCIIORegionRegister(pDevIns, NULL, iRegion, cbRegion, enmType, + PDMPCIDEV_IORGN_F_MMIO_HANDLE | PDMPCIDEV_IORGN_F_NEW_STYLE, + hMmioRegion, pfnMapUnmap); +} + +/** + * Registers an MMIO region for the default PCI device, extended version. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. + * @param iRegion The region number. + * @param cbRegion Size of the region. + * @param enmType PCI_ADDRESS_SPACE_MEM or + * PCI_ADDRESS_SPACE_MEM_PREFETCH, optionally or-ing in + * PCI_ADDRESS_SPACE_BAR64 or PCI_ADDRESS_SPACE_BAR32. + * @param hMmioRegion Handle to the MMIO region. + * @param pfnMapUnmap Callback for doing the mapping, optional. The + * callback will be invoked holding only the PDM lock. + * The device lock will _not_ be taken (due to lock + * order). + */ +DECLINLINE(int) PDMDevHlpPCIIORegionRegisterMmioEx(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, + RTGCPHYS cbRegion, PCIADDRESSSPACE enmType, IOMMMIOHANDLE hMmioRegion, + PFNPCIIOREGIONMAP pfnMapUnmap) +{ + return pDevIns->pHlpR3->pfnPCIIORegionRegister(pDevIns, pPciDev, iRegion, cbRegion, enmType, + PDMPCIDEV_IORGN_F_MMIO_HANDLE | PDMPCIDEV_IORGN_F_NEW_STYLE, + hMmioRegion, pfnMapUnmap); +} + +/** + * Combines PDMDevHlpMmioCreate and PDMDevHlpPCIIORegionRegisterMmio, creating + * and registering an MMIO region for the default PCI device. + * + * @returns VBox status code. + * @param pDevIns The device instance to register the ports with. + * @param cbRegion The size of the region in bytes. + * @param iPciRegion The PCI device region. + * @param enmType PCI_ADDRESS_SPACE_MEM or + * PCI_ADDRESS_SPACE_MEM_PREFETCH, optionally or-ing in + * PCI_ADDRESS_SPACE_BAR64 or PCI_ADDRESS_SPACE_BAR32. + * @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 pvUser User argument to pass to the callbacks. + * @param pszDesc Pointer to description string. This must not be freed. + * @param phRegion Where to return the MMIO region handle. + * + */ +DECLINLINE(int) PDMDevHlpPCIIORegionCreateMmio(PPDMDEVINS pDevIns, uint32_t iPciRegion, RTGCPHYS cbRegion, PCIADDRESSSPACE enmType, + PFNIOMMMIONEWWRITE pfnWrite, PFNIOMMMIONEWREAD pfnRead, void *pvUser, + uint32_t fFlags, const char *pszDesc, PIOMMMIOHANDLE phRegion) + +{ + int rc = pDevIns->pHlpR3->pfnMmioCreateEx(pDevIns, cbRegion, fFlags, pDevIns->apPciDevs[0], iPciRegion << 16, + pfnWrite, pfnRead, NULL /*pfnFill*/, pvUser, pszDesc, phRegion); + if (RT_SUCCESS(rc)) + rc = pDevIns->pHlpR3->pfnPCIIORegionRegister(pDevIns, pDevIns->apPciDevs[0], iPciRegion, cbRegion, enmType, + PDMPCIDEV_IORGN_F_MMIO_HANDLE | PDMPCIDEV_IORGN_F_NEW_STYLE, + *phRegion, NULL /*pfnMapUnmap*/); + return rc; +} + + +/** + * Registers an MMIO2 region for the default 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 or + * PCI_ADDRESS_SPACE_MEM_PREFETCH, optionally or-ing in + * PCI_ADDRESS_SPACE_BAR64 or PCI_ADDRESS_SPACE_BAR32. + * @param hMmio2Region Handle to the MMIO2 region. + */ +DECLINLINE(int) PDMDevHlpPCIIORegionRegisterMmio2(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS cbRegion, + PCIADDRESSSPACE enmType, PGMMMIO2HANDLE hMmio2Region) +{ + return pDevIns->pHlpR3->pfnPCIIORegionRegister(pDevIns, NULL, iRegion, cbRegion, enmType, + PDMPCIDEV_IORGN_F_MMIO2_HANDLE | PDMPCIDEV_IORGN_F_NEW_STYLE, + hMmio2Region, NULL); +} + +/** + * Combines PDMDevHlpMmio2Create and PDMDevHlpPCIIORegionRegisterMmio2, creating + * and registering an MMIO2 region for the default PCI device, extended edition. + * + * @returns VBox status code. + * @param pDevIns The device instance to register the ports with. + * @param cbRegion The size of the region in bytes. + * @param iPciRegion The PCI device region. + * @param enmType PCI_ADDRESS_SPACE_MEM or + * PCI_ADDRESS_SPACE_MEM_PREFETCH, optionally or-ing in + * PCI_ADDRESS_SPACE_BAR64 or PCI_ADDRESS_SPACE_BAR32. + * @param pszDesc Pointer to description string. This must not be freed. + * @param ppvMapping Where to store the address of the ring-3 mapping of + * the memory. + * @param phRegion Where to return the MMIO2 region handle. + * + */ +DECLINLINE(int) PDMDevHlpPCIIORegionCreateMmio2(PPDMDEVINS pDevIns, uint32_t iPciRegion, RTGCPHYS cbRegion, + PCIADDRESSSPACE enmType, const char *pszDesc, + void **ppvMapping, PPGMMMIO2HANDLE phRegion) + +{ + int rc = pDevIns->pHlpR3->pfnMmio2Create(pDevIns, pDevIns->apPciDevs[0], iPciRegion << 16, cbRegion, 0 /*fFlags*/, + pszDesc, ppvMapping, phRegion); + if (RT_SUCCESS(rc)) + rc = pDevIns->pHlpR3->pfnPCIIORegionRegister(pDevIns, pDevIns->apPciDevs[0], iPciRegion, cbRegion, enmType, + PDMPCIDEV_IORGN_F_MMIO2_HANDLE | PDMPCIDEV_IORGN_F_NEW_STYLE, + *phRegion, NULL /*pfnCallback*/); + return rc; +} + +/** + * Combines PDMDevHlpMmio2Create and PDMDevHlpPCIIORegionRegisterMmio2, creating + * and registering an MMIO2 region for the default PCI device. + * + * @returns VBox status code. + * @param pDevIns The device instance to register the ports with. + * @param cbRegion The size of the region in bytes. + * @param iPciRegion The PCI device region. + * @param enmType PCI_ADDRESS_SPACE_MEM or + * PCI_ADDRESS_SPACE_MEM_PREFETCH, optionally or-ing in + * PCI_ADDRESS_SPACE_BAR64 or PCI_ADDRESS_SPACE_BAR32. + * @param fMmio2Flags PGMPHYS_MMIO2_FLAGS_XXX (see pgm.h). + * @param pfnMapUnmap Callback for doing the mapping, optional. The + * callback will be invoked holding only the PDM lock. + * The device lock will _not_ be taken (due to lock + * order). + * @param pszDesc Pointer to description string. This must not be freed. + * @param ppvMapping Where to store the address of the ring-3 mapping of + * the memory. + * @param phRegion Where to return the MMIO2 region handle. + * + */ +DECLINLINE(int) PDMDevHlpPCIIORegionCreateMmio2Ex(PPDMDEVINS pDevIns, uint32_t iPciRegion, RTGCPHYS cbRegion, + PCIADDRESSSPACE enmType, uint32_t fMmio2Flags, PFNPCIIOREGIONMAP pfnMapUnmap, + const char *pszDesc, void **ppvMapping, PPGMMMIO2HANDLE phRegion) + +{ + int rc = pDevIns->pHlpR3->pfnMmio2Create(pDevIns, pDevIns->apPciDevs[0], iPciRegion << 16, cbRegion, fMmio2Flags, + pszDesc, ppvMapping, phRegion); + if (RT_SUCCESS(rc)) + rc = pDevIns->pHlpR3->pfnPCIIORegionRegister(pDevIns, pDevIns->apPciDevs[0], iPciRegion, cbRegion, enmType, + PDMPCIDEV_IORGN_F_MMIO2_HANDLE | PDMPCIDEV_IORGN_F_NEW_STYLE, + *phRegion, pfnMapUnmap); + return rc; +} + +/** + * @copydoc PDMDEVHLPR3::pfnPCIInterceptConfigAccesses + */ +DECLINLINE(int) PDMDevHlpPCIInterceptConfigAccesses(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, + PFNPCICONFIGREAD pfnRead, PFNPCICONFIGWRITE pfnWrite) +{ + return pDevIns->pHlpR3->pfnPCIInterceptConfigAccesses(pDevIns, pPciDev, pfnRead, pfnWrite); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPCIConfigRead + */ +DECLINLINE(VBOXSTRICTRC) PDMDevHlpPCIConfigRead(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t uAddress, + unsigned cb, uint32_t *pu32Value) +{ + return pDevIns->pHlpR3->pfnPCIConfigRead(pDevIns, pPciDev, uAddress, cb, pu32Value); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPCIConfigWrite + */ +DECLINLINE(VBOXSTRICTRC) PDMDevHlpPCIConfigWrite(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t uAddress, + unsigned cb, uint32_t u32Value) +{ + return pDevIns->pHlpR3->pfnPCIConfigWrite(pDevIns, pPciDev, uAddress, cb, u32Value); +} + +#endif /* IN_RING3 */ + +/** + * Bus master physical memory read from the default PCI device. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_READ_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @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. + */ +DECLINLINE(int) PDMDevHlpPCIPhysRead(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysRead(pDevIns, NULL, GCPhys, pvBuf, cbRead, PDM_DEVHLP_PHYS_RW_F_DEFAULT); +} + +/** + * Bus master physical memory read - unknown data usage. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_READ_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @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. + */ +DECLINLINE(int) PDMDevHlpPCIPhysReadEx(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysRead(pDevIns, pPciDev, GCPhys, pvBuf, cbRead, PDM_DEVHLP_PHYS_RW_F_DEFAULT); +} + +/** + * Bus master physical memory read from the default PCI device. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_READ_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @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. + */ +DECLINLINE(int) PDMDevHlpPCIPhysReadMeta(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysRead(pDevIns, NULL, GCPhys, pvBuf, cbRead, PDM_DEVHLP_PHYS_RW_F_DATA_META); +} + +/** + * Bus master physical memory read - reads meta data processed by the device. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_READ_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @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. + */ +DECLINLINE(int) PDMDevHlpPCIPhysReadMetaEx(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysRead(pDevIns, pPciDev, GCPhys, pvBuf, cbRead, PDM_DEVHLP_PHYS_RW_F_DATA_META); +} + +/** + * Bus master physical memory read from the default PCI device - read data will not be touched by the device. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_READ_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @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. + */ +DECLINLINE(int) PDMDevHlpPCIPhysReadUser(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysRead(pDevIns, NULL, GCPhys, pvBuf, cbRead, PDM_DEVHLP_PHYS_RW_F_DATA_USER); +} + +/** + * Bus master physical memory read - read data will not be touched by the device. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_READ_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @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. + */ +DECLINLINE(int) PDMDevHlpPCIPhysReadUserEx(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysRead(pDevIns, pPciDev, GCPhys, pvBuf, cbRead, PDM_DEVHLP_PHYS_RW_F_DATA_USER); +} + +/** + * Bus master physical memory write from the default PCI device - unknown data usage. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_WRITE_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @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. + */ +DECLINLINE(int) PDMDevHlpPCIPhysWrite(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysWrite(pDevIns, NULL, GCPhys, pvBuf, cbWrite, PDM_DEVHLP_PHYS_RW_F_DEFAULT); +} + +/** + * Bus master physical memory write - unknown data usage. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_WRITE_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @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. + */ +DECLINLINE(int) PDMDevHlpPCIPhysWriteEx(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysWrite(pDevIns, pPciDev, GCPhys, pvBuf, cbWrite, PDM_DEVHLP_PHYS_RW_F_DEFAULT); +} + +/** + * Bus master physical memory write from the default PCI device. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_WRITE_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @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. + */ +DECLINLINE(int) PDMDevHlpPCIPhysWriteMeta(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysWrite(pDevIns, NULL, GCPhys, pvBuf, cbWrite, PDM_DEVHLP_PHYS_RW_F_DATA_META); +} + +/** + * Bus master physical memory write - written data was created/altered by the device. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_WRITE_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @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. + */ +DECLINLINE(int) PDMDevHlpPCIPhysWriteMetaEx(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysWrite(pDevIns, pPciDev, GCPhys, pvBuf, cbWrite, PDM_DEVHLP_PHYS_RW_F_DATA_META); +} + +/** + * Bus master physical memory write from the default PCI device. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_WRITE_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @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. + */ +DECLINLINE(int) PDMDevHlpPCIPhysWriteUser(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysWrite(pDevIns, NULL, GCPhys, pvBuf, cbWrite, PDM_DEVHLP_PHYS_RW_F_DATA_USER); +} + +/** + * Bus master physical memory write - written data was not touched/created by the device. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_WRITE_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @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. + */ +DECLINLINE(int) PDMDevHlpPCIPhysWriteUserEx(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysWrite(pDevIns, pPciDev, GCPhys, pvBuf, cbWrite, PDM_DEVHLP_PHYS_RW_F_DATA_USER); +} + +#ifdef IN_RING3 +/** + * @copydoc PDMDEVHLPR3::pfnPCIPhysGCPhys2CCPtr + */ +DECLINLINE(int) PDMDevHlpPCIPhysGCPhys2CCPtr(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, uint32_t fFlags, + void **ppv, PPGMPAGEMAPLOCK pLock) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysGCPhys2CCPtr(pDevIns, pPciDev, GCPhys, fFlags, ppv, pLock); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPCIPhysGCPhys2CCPtrReadOnly + */ +DECLINLINE(int) PDMDevHlpPCIPhysGCPhys2CCPtrReadOnly(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, uint32_t fFlags, + void const **ppv, PPGMPAGEMAPLOCK pLock) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysGCPhys2CCPtrReadOnly(pDevIns, pPciDev, GCPhys, fFlags, ppv, pLock); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPCIPhysBulkGCPhys2CCPtr + */ +DECLINLINE(int) PDMDevHlpPCIPhysBulkGCPhys2CCPtr(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t cPages, + PCRTGCPHYS paGCPhysPages, uint32_t fFlags, void **papvPages, + PPGMPAGEMAPLOCK paLocks) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysBulkGCPhys2CCPtr(pDevIns, pPciDev, cPages, paGCPhysPages, fFlags, papvPages, + paLocks); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPCIPhysBulkGCPhys2CCPtrReadOnly + */ +DECLINLINE(int) PDMDevHlpPCIPhysBulkGCPhys2CCPtrReadOnly(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t cPages, + PCRTGCPHYS paGCPhysPages, uint32_t fFlags, void const **papvPages, + PPGMPAGEMAPLOCK paLocks) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysBulkGCPhys2CCPtrReadOnly(pDevIns, pPciDev, cPages, paGCPhysPages, fFlags, + papvPages, paLocks); +} +#endif /* IN_RING3 */ + +/** + * Sets the IRQ for the default 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. + */ +DECLINLINE(void) PDMDevHlpPCISetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel) +{ + pDevIns->CTX_SUFF(pHlp)->pfnPCISetIrq(pDevIns, NULL, iIrq, iLevel); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPCISetIrq + */ +DECLINLINE(void) PDMDevHlpPCISetIrqEx(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel) +{ + pDevIns->CTX_SUFF(pHlp)->pfnPCISetIrq(pDevIns, pPciDev, iIrq, iLevel); +} + +/** + * Sets the IRQ for the given PCI device, but doesn'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. + */ +DECLINLINE(void) PDMDevHlpPCISetIrqNoWait(PPDMDEVINS pDevIns, int iIrq, int iLevel) +{ + pDevIns->CTX_SUFF(pHlp)->pfnPCISetIrq(pDevIns, NULL, iIrq, iLevel); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPCISetIrqNoWait + */ +DECLINLINE(void) PDMDevHlpPCISetIrqNoWaitEx(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel) +{ + pDevIns->CTX_SUFF(pHlp)->pfnPCISetIrq(pDevIns, pPciDev, 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::pfnDriverDetach + */ +DECLINLINE(int) PDMDevHlpDriverDetach(PPDMDEVINS pDevIns, PPDMDRVINS pDrvIns, uint32_t fFlags) +{ + return pDevIns->pHlpR3->pfnDriverDetach(pDevIns, pDrvIns, fFlags); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDriverReconfigure + */ +DECLINLINE(int) PDMDevHlpDriverReconfigure(PPDMDEVINS pDevIns, uint32_t iLun, uint32_t cDepth, + const char * const *papszDrivers, PCFGMNODE *papConfigs, uint32_t fFlags) +{ + return pDevIns->pHlpR3->pfnDriverReconfigure(pDevIns, iLun, cDepth, papszDrivers, papConfigs, fFlags); +} + +/** + * Reconfigures with a single driver reattachement, no config, noflags. + * @sa PDMDevHlpDriverReconfigure + */ +DECLINLINE(int) PDMDevHlpDriverReconfigure1(PPDMDEVINS pDevIns, uint32_t iLun, const char *pszDriver0) +{ + return pDevIns->pHlpR3->pfnDriverReconfigure(pDevIns, iLun, 1, &pszDriver0, NULL, 0); +} + +/** + * Reconfigures with a two drivers reattachement, no config, noflags. + * @sa PDMDevHlpDriverReconfigure + */ +DECLINLINE(int) PDMDevHlpDriverReconfigure2(PPDMDEVINS pDevIns, uint32_t iLun, const char *pszDriver0, const char *pszDriver1) +{ + char const * apszDrivers[2]; + apszDrivers[0] = pszDriver0; + apszDrivers[1] = pszDriver1; + return pDevIns->pHlpR3->pfnDriverReconfigure(pDevIns, iLun, 2, apszDrivers, NULL, 0); +} + +/** + * @copydoc PDMDEVHLPR3::pfnQueueCreate + */ +DECLINLINE(int) PDMDevHlpQueueCreate(PPDMDEVINS pDevIns, size_t cbItem, uint32_t cItems, uint32_t cMilliesInterval, + PFNPDMQUEUEDEV pfnCallback, bool fRZEnabled, const char *pszName, PDMQUEUEHANDLE *phQueue) +{ + return pDevIns->pHlpR3->pfnQueueCreate(pDevIns, cbItem, cItems, cMilliesInterval, pfnCallback, fRZEnabled, pszName, phQueue); +} + +#endif /* IN_RING3 */ + +/** + * @copydoc PDMDEVHLPR3::pfnQueueAlloc + */ +DECLINLINE(PPDMQUEUEITEMCORE) PDMDevHlpQueueAlloc(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnQueueAlloc(pDevIns, hQueue); +} + +/** + * @copydoc PDMDEVHLPR3::pfnQueueInsert + */ +DECLINLINE(int) PDMDevHlpQueueInsert(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue, PPDMQUEUEITEMCORE pItem) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnQueueInsert(pDevIns, hQueue, pItem); +} + +/** + * @copydoc PDMDEVHLPR3::pfnQueueFlushIfNecessary + */ +DECLINLINE(bool) PDMDevHlpQueueFlushIfNecessary(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnQueueFlushIfNecessary(pDevIns, hQueue); +} + +#ifdef IN_RING3 +/** + * @copydoc PDMDEVHLPR3::pfnTaskCreate + */ +DECLINLINE(int) PDMDevHlpTaskCreate(PPDMDEVINS pDevIns, uint32_t fFlags, const char *pszName, + PFNPDMTASKDEV pfnCallback, void *pvUser, PDMTASKHANDLE *phTask) +{ + return pDevIns->pHlpR3->pfnTaskCreate(pDevIns, fFlags, pszName, pfnCallback, pvUser, phTask); +} +#endif + +/** + * @copydoc PDMDEVHLPR3::pfnTaskTrigger + */ +DECLINLINE(int) PDMDevHlpTaskTrigger(PPDMDEVINS pDevIns, PDMTASKHANDLE hTask) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTaskTrigger(pDevIns, hTask); +} + +#ifdef IN_RING3 + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventCreate + */ +DECLINLINE(int) PDMDevHlpSUPSemEventCreate(PPDMDEVINS pDevIns, PSUPSEMEVENT phEvent) +{ + return pDevIns->pHlpR3->pfnSUPSemEventCreate(pDevIns, phEvent); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventClose + */ +DECLINLINE(int) PDMDevHlpSUPSemEventClose(PPDMDEVINS pDevIns, SUPSEMEVENT hEvent) +{ + return pDevIns->pHlpR3->pfnSUPSemEventClose(pDevIns, hEvent); +} + +#endif /* IN_RING3 */ + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventSignal + */ +DECLINLINE(int) PDMDevHlpSUPSemEventSignal(PPDMDEVINS pDevIns, SUPSEMEVENT hEvent) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnSUPSemEventSignal(pDevIns, hEvent); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventWaitNoResume + */ +DECLINLINE(int) PDMDevHlpSUPSemEventWaitNoResume(PPDMDEVINS pDevIns, SUPSEMEVENT hEvent, uint32_t cMillies) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnSUPSemEventWaitNoResume(pDevIns, hEvent, cMillies); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventWaitNsAbsIntr + */ +DECLINLINE(int) PDMDevHlpSUPSemEventWaitNsAbsIntr(PPDMDEVINS pDevIns, SUPSEMEVENT hEvent, uint64_t uNsTimeout) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnSUPSemEventWaitNsAbsIntr(pDevIns, hEvent, uNsTimeout); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventWaitNsRelIntr + */ +DECLINLINE(int) PDMDevHlpSUPSemEventWaitNsRelIntr(PPDMDEVINS pDevIns, SUPSEMEVENT hEvent, uint64_t cNsTimeout) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnSUPSemEventWaitNsRelIntr(pDevIns, hEvent, cNsTimeout); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventGetResolution + */ +DECLINLINE(uint32_t) PDMDevHlpSUPSemEventGetResolution(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnSUPSemEventGetResolution(pDevIns); +} + +#ifdef IN_RING3 + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventMultiCreate + */ +DECLINLINE(int) PDMDevHlpSUPSemEventMultiCreate(PPDMDEVINS pDevIns, PSUPSEMEVENTMULTI phEventMulti) +{ + return pDevIns->pHlpR3->pfnSUPSemEventMultiCreate(pDevIns, phEventMulti); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventMultiClose + */ +DECLINLINE(int) PDMDevHlpSUPSemEventMultiClose(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti) +{ + return pDevIns->pHlpR3->pfnSUPSemEventMultiClose(pDevIns, hEventMulti); +} + +#endif /* IN_RING3 */ + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventMultiSignal + */ +DECLINLINE(int) PDMDevHlpSUPSemEventMultiSignal(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnSUPSemEventMultiSignal(pDevIns, hEventMulti); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventMultiReset + */ +DECLINLINE(int) PDMDevHlpSUPSemEventMultiReset(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnSUPSemEventMultiReset(pDevIns, hEventMulti); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventMultiWaitNoResume + */ +DECLINLINE(int) PDMDevHlpSUPSemEventMultiWaitNoResume(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti, uint32_t cMillies) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnSUPSemEventMultiWaitNsRelIntr(pDevIns, hEventMulti, cMillies); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventMultiWaitNsAbsIntr + */ +DECLINLINE(int) PDMDevHlpSUPSemEventMultiWaitNsAbsIntr(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti, uint64_t uNsTimeout) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnSUPSemEventMultiWaitNsAbsIntr(pDevIns, hEventMulti, uNsTimeout); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventMultiWaitNsRelIntr + */ +DECLINLINE(int) PDMDevHlpSUPSemEventMultiWaitNsRelIntr(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti, uint64_t cNsTimeout) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnSUPSemEventMultiWaitNsRelIntr(pDevIns, hEventMulti, cNsTimeout); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventMultiGetResolution + */ +DECLINLINE(uint32_t) PDMDevHlpSUPSemEventMultiGetResolution(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnSUPSemEventMultiGetResolution(pDevIns); +} + +#ifdef IN_RING3 + +/** + * 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 SRC_POS 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) RT_IPRT_FORMAT_ATTR(6, 7) 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; +} + +#endif /* IN_RING3 */ + +/** + * @copydoc PDMDEVHLPR3::pfnCritSectGetNop + */ +DECLINLINE(PPDMCRITSECT) PDMDevHlpCritSectGetNop(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectGetNop(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSetDeviceCritSect + */ +DECLINLINE(int) PDMDevHlpSetDeviceCritSect(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnSetDeviceCritSect(pDevIns, pCritSect); +} + +/** + * Enters a PDM critical section. + * + * @returns VINF_SUCCESS if entered successfully. + * @returns rcBusy when encountering a busy critical section in RC/R0. + * @retval VERR_SEM_DESTROYED if the critical section is delete before or + * during the operation. + * + * @param pDevIns The device instance. + * @param pCritSect The PDM critical section to enter. + * @param rcBusy The status code to return when we're in RC or R0 + * and the section is busy. Pass VINF_SUCCESS to + * acquired the critical section thru a ring-3 + * call if necessary. + * + * @note Even callers setting @a rcBusy to VINF_SUCCESS must either handle + * possible failures in ring-0 or at least apply + * PDM_CRITSECT_RELEASE_ASSERT_RC_DEV() to the return value of this + * function. + * + * @sa PDMCritSectEnter + */ +DECLINLINE(DECL_CHECK_RETURN(int)) PDMDevHlpCritSectEnter(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, int rcBusy) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectEnter(pDevIns, pCritSect, rcBusy); +} + +/** + * Enters a PDM critical section, with location information for debugging. + * + * @returns VINF_SUCCESS if entered successfully. + * @returns rcBusy when encountering a busy critical section in RC/R0. + * @retval VERR_SEM_DESTROYED if the critical section is delete before or + * during the operation. + * + * @param pDevIns The device instance. + * @param pCritSect The PDM critical section to enter. + * @param rcBusy The status code to return when we're in RC or R0 + * and the section is busy. Pass VINF_SUCCESS to + * acquired the critical section thru a ring-3 + * call if necessary. + * @param uId Some kind of locking location ID. Typically a + * return address up the stack. Optional (0). + * @param SRC_POS The source position where to lock is being + * acquired from. Optional. + * @sa PDMCritSectEnterDebug + */ +DECLINLINE(DECL_CHECK_RETURN(int)) +PDMDevHlpCritSectEnterDebug(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectEnterDebug(pDevIns, pCritSect, rcBusy, uId, RT_SRC_POS_ARGS); +} + +/** + * Try enter a critical section. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_BUSY if the critsect was owned. + * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) + * @retval VERR_SEM_DESTROYED if the critical section is delete before or + * during the operation. + * + * @param pDevIns The device instance. + * @param pCritSect The critical section. + * @sa PDMCritSectTryEnter + */ +DECLINLINE(DECL_CHECK_RETURN(int)) +PDMDevHlpCritSectTryEnter(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectTryEnter(pDevIns, pCritSect); +} + +/** + * Try enter a critical section, with location information for debugging. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_BUSY if the critsect was owned. + * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) + * @retval VERR_SEM_DESTROYED if the critical section is delete before or + * during the operation. + * + * @param pDevIns The device instance. + * @param pCritSect The critical section. + * @param uId Some kind of locking location ID. Typically a + * return address up the stack. Optional (0). + * @param SRC_POS The source position where to lock is being + * acquired from. Optional. + * @sa PDMCritSectTryEnterDebug + */ +DECLINLINE(DECL_CHECK_RETURN(int)) +PDMDevHlpCritSectTryEnterDebug(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectTryEnterDebug(pDevIns, pCritSect, uId, RT_SRC_POS_ARGS); +} + +/** + * Leaves a critical section entered with PDMCritSectEnter(). + * + * @returns Indication whether we really exited the critical section. + * @retval VINF_SUCCESS if we really exited. + * @retval VINF_SEM_NESTED if we only reduced the nesting count. + * @retval VERR_NOT_OWNER if you somehow ignore release assertions. + * + * @param pDevIns The device instance. + * @param pCritSect The PDM critical section to leave. + * @sa PDMCritSectLeave + */ +DECLINLINE(int) PDMDevHlpCritSectLeave(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectLeave(pDevIns, pCritSect); +} + +/** + * @see PDMCritSectIsOwner + */ +DECLINLINE(bool) PDMDevHlpCritSectIsOwner(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectIsOwner(pDevIns, pCritSect); +} + +/** + * @see PDMCritSectIsInitialized + */ +DECLINLINE(bool) PDMDevHlpCritSectIsInitialized(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectIsInitialized(pDevIns, pCritSect); +} + +/** + * @see PDMCritSectHasWaiters + */ +DECLINLINE(bool) PDMDevHlpCritSectHasWaiters(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectHasWaiters(pDevIns, pCritSect); +} + +/** + * @see PDMCritSectGetRecursion + */ +DECLINLINE(uint32_t) PDMDevHlpCritSectGetRecursion(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectGetRecursion(pDevIns, pCritSect); +} + +#if defined(IN_RING3) || defined(IN_RING0) +/** + * @see PDMHCCritSectScheduleExitEvent + */ +DECLINLINE(int) PDMDevHlpCritSectScheduleExitEvent(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, SUPSEMEVENT hEventToSignal) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectScheduleExitEvent(pDevIns, pCritSect, hEventToSignal); +} +#endif + +/* Strict build: Remap the two enter calls to the debug versions. */ +#ifdef VBOX_STRICT +# ifdef IPRT_INCLUDED_asm_h +# define PDMDevHlpCritSectEnter(pDevIns, pCritSect, rcBusy) PDMDevHlpCritSectEnterDebug((pDevIns), (pCritSect), (rcBusy), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define PDMDevHlpCritSectTryEnter(pDevIns, pCritSect) PDMDevHlpCritSectTryEnterDebug((pDevIns), (pCritSect), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# else +# define PDMDevHlpCritSectEnter(pDevIns, pCritSect, rcBusy) PDMDevHlpCritSectEnterDebug((pDevIns), (pCritSect), (rcBusy), 0, RT_SRC_POS) +# define PDMDevHlpCritSectTryEnter(pDevIns, pCritSect) PDMDevHlpCritSectTryEnterDebug((pDevIns), (pCritSect), 0, RT_SRC_POS) +# endif +#endif + +#if defined(IN_RING3) || defined(DOXYGEN_RUNNING) + +/** + * Deletes the critical section. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pCritSect The PDM critical section to destroy. + * @sa PDMR3CritSectDelete + */ +DECLINLINE(int) PDMDevHlpCritSectDelete(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect) +{ + return pDevIns->pHlpR3->pfnCritSectDelete(pDevIns, pCritSect); +} + +/** + * Initializes a PDM read/write critical section. + * + * The PDM read/write 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 read/write critical section. + * @param SRC_POS 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) RT_IPRT_FORMAT_ATTR(6, 7) PDMDevHlpCritSectRwInit(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, RT_SRC_POS_DECL, + const char *pszNameFmt, ...) +{ + int rc; + va_list va; + va_start(va, pszNameFmt); + rc = pDevIns->pHlpR3->pfnCritSectRwInit(pDevIns, pCritSect, RT_SRC_POS_ARGS, pszNameFmt, va); + va_end(va); + return rc; +} + +/** + * Deletes the read/write critical section. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pCritSect The PDM read/write critical section to destroy. + * @sa PDMR3CritSectRwDelete + */ +DECLINLINE(int) PDMDevHlpCritSectRwDelete(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect) +{ + return pDevIns->pHlpR3->pfnCritSectRwDelete(pDevIns, pCritSect); +} + +#endif /* IN_RING3 */ + +/** + * @sa PDMCritSectRwEnterShared, PDM_CRITSECT_RELEASE_ASSERT_RC_DEV + */ +DECLINLINE(DECL_CHECK_RETURN(int)) PDMDevHlpCritSectRwEnterShared(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwEnterShared(pDevIns, pCritSect, rcBusy); +} + +/** + * @sa PDMCritSectRwEnterSharedDebug, PDM_CRITSECT_RELEASE_ASSERT_RC_DEV + */ +DECLINLINE(DECL_CHECK_RETURN(int)) +PDMDevHlpCritSectRwEnterSharedDebug(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwEnterSharedDebug(pDevIns, pCritSect, rcBusy, uId, RT_SRC_POS_ARGS); +} + +/** + * @sa PDMCritSectRwTryEnterShared + */ +DECLINLINE(DECL_CHECK_RETURN(int)) +PDMDevHlpCritSectRwTryEnterShared(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwTryEnterShared(pDevIns, pCritSect); +} + +/** + * @sa PDMCritSectRwTryEnterSharedDebug + */ +DECLINLINE(DECL_CHECK_RETURN(int)) +PDMDevHlpCritSectRwTryEnterSharedDebug(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwTryEnterSharedDebug(pDevIns, pCritSect, uId, RT_SRC_POS_ARGS); +} + +/** + * @sa PDMCritSectRwLeaveShared + */ +DECLINLINE(int) PDMDevHlpCritSectRwLeaveShared(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwLeaveShared(pDevIns, pCritSect); +} + +/** + * @sa PDMCritSectRwEnterExcl, PDM_CRITSECT_RELEASE_ASSERT_RC_DEV + */ +DECLINLINE(DECL_CHECK_RETURN(int)) PDMDevHlpCritSectRwEnterExcl(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwEnterExcl(pDevIns, pCritSect, rcBusy); +} + +/** + * @sa PDMCritSectRwEnterExclDebug, PDM_CRITSECT_RELEASE_ASSERT_RC_DEV + */ +DECLINLINE(DECL_CHECK_RETURN(int)) +PDMDevHlpCritSectRwEnterExclDebug(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwEnterExclDebug(pDevIns, pCritSect, rcBusy, uId, RT_SRC_POS_ARGS); +} + +/** + * @sa PDMCritSectRwTryEnterExcl + */ +DECLINLINE(DECL_CHECK_RETURN(int)) +PDMDevHlpCritSectRwTryEnterExcl(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwTryEnterExcl(pDevIns, pCritSect); +} + +/** + * @sa PDMCritSectRwTryEnterExclDebug + */ +DECLINLINE(DECL_CHECK_RETURN(int)) +PDMDevHlpCritSectRwTryEnterExclDebug(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwTryEnterExclDebug(pDevIns, pCritSect, uId, RT_SRC_POS_ARGS); +} + +/** + * @sa PDMCritSectRwLeaveExcl + */ +DECLINLINE(int) PDMDevHlpCritSectRwLeaveExcl(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwLeaveExcl(pDevIns, pCritSect); +} + +/** + * @see PDMCritSectRwIsWriteOwner + */ +DECLINLINE(bool) PDMDevHlpCritSectRwIsWriteOwner(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwIsWriteOwner(pDevIns, pCritSect); +} + +/** + * @see PDMCritSectRwIsReadOwner + */ +DECLINLINE(bool) PDMDevHlpCritSectRwIsReadOwner(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, bool fWannaHear) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwIsReadOwner(pDevIns, pCritSect, fWannaHear); +} + +/** + * @see PDMCritSectRwGetWriteRecursion + */ +DECLINLINE(uint32_t) PDMDevHlpCritSectRwGetWriteRecursion(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwGetWriteRecursion(pDevIns, pCritSect); +} + +/** + * @see PDMCritSectRwGetWriterReadRecursion + */ +DECLINLINE(uint32_t) PDMDevHlpCritSectRwGetWriterReadRecursion(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwGetWriterReadRecursion(pDevIns, pCritSect); +} + +/** + * @see PDMCritSectRwGetReadCount + */ +DECLINLINE(uint32_t) PDMDevHlpCritSectRwGetReadCount(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwGetReadCount(pDevIns, pCritSect); +} + +/** + * @see PDMCritSectRwIsInitialized + */ +DECLINLINE(bool) PDMDevHlpCritSectRwIsInitialized(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwIsInitialized(pDevIns, pCritSect); +} + +/* Strict build: Remap the two enter calls to the debug versions. */ +#ifdef VBOX_STRICT +# ifdef IPRT_INCLUDED_asm_h +# define PDMDevHlpCritSectRwEnterShared(pDevIns, pCritSect, rcBusy) PDMDevHlpCritSectRwEnterSharedDebug((pDevIns), (pCritSect), (rcBusy), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define PDMDevHlpCritSectRwTryEnterShared(pDevIns, pCritSect) PDMDevHlpCritSectRwTryEnterSharedDebug((pDevIns), (pCritSect), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define PDMDevHlpCritSectRwEnterExcl(pDevIns, pCritSect, rcBusy) PDMDevHlpCritSectRwEnterExclDebug((pDevIns), (pCritSect), (rcBusy), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define PDMDevHlpCritSectRwTryEnterExcl(pDevIns, pCritSect) PDMDevHlpCritSectRwTryEnterExclDebug((pDevIns), (pCritSect), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# else +# define PDMDevHlpCritSectRwEnterShared(pDevIns, pCritSect, rcBusy) PDMDevHlpCritSectRwEnterSharedDebug((pDevIns), (pCritSect), (rcBusy), 0, RT_SRC_POS) +# define PDMDevHlpCritSectRwTryEnterShared(pDevIns, pCritSect) PDMDevHlpCritSectRwTryEnterSharedDebug((pDevIns), (pCritSect), 0, RT_SRC_POS) +# define PDMDevHlpCritSectRwEnterExcl(pDevIns, pCritSect, rcBusy) PDMDevHlpCritSectRwEnterExclDebug((pDevIns), (pCritSect), (rcBusy), 0, RT_SRC_POS) +# define PDMDevHlpCritSectRwTryEnterExcl(pDevIns, pCritSect) PDMDevHlpCritSectRwTryEnterExclDebug((pDevIns), (pCritSect), 0, RT_SRC_POS) +# endif +#endif + +#if defined(IN_RING3) || defined(DOXYGEN_RUNNING) + +/** + * @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 PDMR3ThreadDestroy + * @param pDevIns The device instance. + */ +DECLINLINE(int) PDMDevHlpThreadDestroy(PPDMDEVINS pDevIns, PPDMTHREAD pThread, int *pRcThread) +{ + return pDevIns->pHlpR3->pfnThreadDestroy(pThread, pRcThread); +} + +/** + * @copydoc PDMR3ThreadIAmSuspending + * @param pDevIns The device instance. + */ +DECLINLINE(int) PDMDevHlpThreadIAmSuspending(PPDMDEVINS pDevIns, PPDMTHREAD pThread) +{ + return pDevIns->pHlpR3->pfnThreadIAmSuspending(pThread); +} + +/** + * @copydoc PDMR3ThreadIAmRunning + * @param pDevIns The device instance. + */ +DECLINLINE(int) PDMDevHlpThreadIAmRunning(PPDMDEVINS pDevIns, PPDMTHREAD pThread) +{ + return pDevIns->pHlpR3->pfnThreadIAmRunning(pThread); +} + +/** + * @copydoc PDMR3ThreadSleep + * @param pDevIns The device instance. + */ +DECLINLINE(int) PDMDevHlpThreadSleep(PPDMDEVINS pDevIns, PPDMTHREAD pThread, RTMSINTERVAL cMillies) +{ + return pDevIns->pHlpR3->pfnThreadSleep(pThread, cMillies); +} + +/** + * @copydoc PDMR3ThreadSuspend + * @param pDevIns The device instance. + */ +DECLINLINE(int) PDMDevHlpThreadSuspend(PPDMDEVINS pDevIns, PPDMTHREAD pThread) +{ + return pDevIns->pHlpR3->pfnThreadSuspend(pThread); +} + +/** + * @copydoc PDMR3ThreadResume + * @param pDevIns The device instance. + */ +DECLINLINE(int) PDMDevHlpThreadResume(PPDMDEVINS pDevIns, PPDMTHREAD pThread) +{ + return pDevIns->pHlpR3->pfnThreadResume(pThread); +} + +/** + * @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, PPDMPCIBUSREGR3 pPciBusReg, PCPDMPCIHLPR3 *ppPciHlp, uint32_t *piBus) +{ + return pDevIns->pHlpR3->pfnPCIBusRegister(pDevIns, pPciBusReg, ppPciHlp, piBus); +} + +/** + * @copydoc PDMDEVHLPR3::pfnIommuRegister + */ +DECLINLINE(int) PDMDevHlpIommuRegister(PPDMDEVINS pDevIns, PPDMIOMMUREGR3 pIommuReg, PCPDMIOMMUHLPR3 *ppIommuHlp, uint32_t *pidxIommu) +{ + return pDevIns->pHlpR3->pfnIommuRegister(pDevIns, pIommuReg, ppIommuHlp, pidxIommu); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPICRegister + */ +DECLINLINE(int) PDMDevHlpPICRegister(PPDMDEVINS pDevIns, PPDMPICREG pPicReg, PCPDMPICHLP *ppPicHlp) +{ + return pDevIns->pHlpR3->pfnPICRegister(pDevIns, pPicReg, ppPicHlp); +} + +/** + * @copydoc PDMDEVHLPR3::pfnApicRegister + */ +DECLINLINE(int) PDMDevHlpApicRegister(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnApicRegister(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnIoApicRegister + */ +DECLINLINE(int) PDMDevHlpIoApicRegister(PPDMDEVINS pDevIns, PPDMIOAPICREG pIoApicReg, PCPDMIOAPICHLP *ppIoApicHlp) +{ + return pDevIns->pHlpR3->pfnIoApicRegister(pDevIns, pIoApicReg, ppIoApicHlp); +} + +/** + * @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 PDMDEVHLPR3::pfnCallR0 + */ +DECLINLINE(int) PDMDevHlpCallR0(PPDMDEVINS pDevIns, uint32_t uOperation, uint64_t u64Arg) +{ + return pDevIns->pHlpR3->pfnCallR0(pDevIns, uOperation, u64Arg); +} + +/** + * @copydoc PDMDEVHLPR3::pfnVMGetSuspendReason + */ +DECLINLINE(VMSUSPENDREASON) PDMDevHlpVMGetSuspendReason(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnVMGetSuspendReason(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnVMGetResumeReason + */ +DECLINLINE(VMRESUMEREASON) PDMDevHlpVMGetResumeReason(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnVMGetResumeReason(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnGetUVM + */ +DECLINLINE(PUVM) PDMDevHlpGetUVM(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnGetUVM(pDevIns); +} + +#endif /* IN_RING3 || DOXYGEN_RUNNING */ + +#if !defined(IN_RING3) || defined(DOXYGEN_RUNNING) + +/** + * @copydoc PDMDEVHLPR0::pfnPCIBusSetUpContext + */ +DECLINLINE(int) PDMDevHlpPCIBusSetUpContext(PPDMDEVINS pDevIns, CTX_SUFF(PPDMPCIBUSREG) pPciBusReg, CTX_SUFF(PCPDMPCIHLP) *ppPciHlp) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIBusSetUpContext(pDevIns, pPciBusReg, ppPciHlp); +} + +/** + * @copydoc PDMDEVHLPR0::pfnIommuSetUpContext + */ +DECLINLINE(int) PDMDevHlpIommuSetUpContext(PPDMDEVINS pDevIns, CTX_SUFF(PPDMIOMMUREG) pIommuReg, CTX_SUFF(PCPDMIOMMUHLP) *ppIommuHlp) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnIommuSetUpContext(pDevIns, pIommuReg, ppIommuHlp); +} + +/** + * @copydoc PDMDEVHLPR0::pfnPICSetUpContext + */ +DECLINLINE(int) PDMDevHlpPICSetUpContext(PPDMDEVINS pDevIns, PPDMPICREG pPicReg, PCPDMPICHLP *ppPicHlp) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPICSetUpContext(pDevIns, pPicReg, ppPicHlp); +} + +/** + * @copydoc PDMDEVHLPR0::pfnApicSetUpContext + */ +DECLINLINE(int) PDMDevHlpApicSetUpContext(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnApicSetUpContext(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR0::pfnIoApicSetUpContext + */ +DECLINLINE(int) PDMDevHlpIoApicSetUpContext(PPDMDEVINS pDevIns, PPDMIOAPICREG pIoApicReg, PCPDMIOAPICHLP *ppIoApicHlp) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnIoApicSetUpContext(pDevIns, pIoApicReg, ppIoApicHlp); +} + +/** + * @copydoc PDMDEVHLPR0::pfnHpetSetUpContext + */ +DECLINLINE(int) PDMDevHlpHpetSetUpContext(PPDMDEVINS pDevIns, PPDMHPETREG pHpetReg, CTX_SUFF(PCPDMHPETHLP) *ppHpetHlp) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnHpetSetUpContext(pDevIns, pHpetReg, ppHpetHlp); +} + +#endif /* !IN_RING3 || DOXYGEN_RUNNING */ + +/** + * @copydoc PDMDEVHLPR3::pfnGetVM + */ +DECLINLINE(PVMCC) PDMDevHlpGetVM(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnGetVM(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnGetVMCPU + */ +DECLINLINE(PVMCPUCC) PDMDevHlpGetVMCPU(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnGetVMCPU(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnGetCurrentCpuId + */ +DECLINLINE(VMCPUID) PDMDevHlpGetCurrentCpuId(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnGetCurrentCpuId(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::pfnTMCpuTicksPerSecond + */ +DECLINLINE(uint64_t) PDMDevHlpTMCpuTicksPerSecond(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTMCpuTicksPerSecond(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnRegisterVMMDevHeap + */ +DECLINLINE(int) PDMDevHlpRegisterVMMDevHeap(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTR3PTR pvHeap, unsigned cbHeap) +{ + return pDevIns->pHlpR3->pfnRegisterVMMDevHeap(pDevIns, GCPhys, pvHeap, cbHeap); +} + +/** + * @copydoc PDMDEVHLPR3::pfnFirmwareRegister + */ +DECLINLINE(int) PDMDevHlpFirmwareRegister(PPDMDEVINS pDevIns, PCPDMFWREG pFwReg, PCPDMFWHLPR3 *ppFwHlp) +{ + return pDevIns->pHlpR3->pfnFirmwareRegister(pDevIns, pFwReg, ppFwHlp); +} + +/** + * @copydoc PDMDEVHLPR3::pfnVMReset + */ +DECLINLINE(int) PDMDevHlpVMReset(PPDMDEVINS pDevIns, uint32_t fFlags) +{ + return pDevIns->pHlpR3->pfnVMReset(pDevIns, fFlags); +} + +/** + * @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 + +/** + * @copydoc PDMDEVHLPR3::pfnGetMainExecutionEngine + */ +DECLINLINE(uint8_t) PDMDevHlpGetMainExecutionEngine(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnGetMainExecutionEngine(pDevIns); +} + +#ifdef IN_RING3 + +/** + * @copydoc PDMDEVHLPR3::pfnGetSupDrvSession + */ +DECLINLINE(PSUPDRVSESSION) PDMDevHlpGetSupDrvSession(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnGetSupDrvSession(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnQueryGenericUserObject + */ +DECLINLINE(void *) PDMDevHlpQueryGenericUserObject(PPDMDEVINS pDevIns, PCRTUUID pUuid) +{ + return pDevIns->pHlpR3->pfnQueryGenericUserObject(pDevIns, pUuid); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPGMHandlerPhysicalTypeRegister + */ +DECLINLINE(int) PDMDevHlpPGMHandlerPhysicalTypeRegister(PPDMDEVINS pDevIns, PGMPHYSHANDLERKIND enmKind, + PFNPGMPHYSHANDLER pfnHandler, const char *pszDesc, + PPGMPHYSHANDLERTYPE phType) +{ + return pDevIns->pHlpR3->pfnPGMHandlerPhysicalTypeRegister(pDevIns, enmKind, pfnHandler, pszDesc, phType); +} + +#elif defined(IN_RING0) + +/** + * @copydoc PDMDEVHLPR0::pfnPGMHandlerPhysicalTypeSetUpContext + */ +DECLINLINE(int) PDMDevHlpPGMHandlerPhysicalTypeSetUpContext(PPDMDEVINS pDevIns, PGMPHYSHANDLERKIND enmKind, + PFNPGMPHYSHANDLER pfnHandler, PFNPGMRZPHYSPFHANDLER pfnPfHandler, + const char *pszDesc, PGMPHYSHANDLERTYPE hType) +{ + return pDevIns->pHlpR0->pfnPGMHandlerPhysicalTypeSetUpContext(pDevIns, enmKind, pfnHandler, pfnPfHandler, pszDesc, hType); +} + +#endif +#ifdef IN_RING3 + +/** + * @copydoc PDMDEVHLPR3::pfnPGMHandlerPhysicalRegister + */ +DECLINLINE(int) PDMDevHlpPGMHandlerPhysicalRegister(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast, + PGMPHYSHANDLERTYPE hType, R3PTRTYPE(const char *) pszDesc) +{ + return pDevIns->pHlpR3->pfnPGMHandlerPhysicalRegister(pDevIns, GCPhys, GCPhysLast, hType, pszDesc); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPGMHandlerPhysicalDeregister + */ +DECLINLINE(int) PDMDevHlpPGMHandlerPhysicalDeregister(PPDMDEVINS pDevIns, RTGCPHYS GCPhys) +{ + return pDevIns->pHlpR3->pfnPGMHandlerPhysicalDeregister(pDevIns, GCPhys); +} + +#endif /* IN_RING3 */ + +/** + * @copydoc PDMDEVHLPR3::pfnPGMHandlerPhysicalPageTempOff + */ +DECLINLINE(int) PDMDevHlpPGMHandlerPhysicalPageTempOff(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTGCPHYS GCPhysPage) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPGMHandlerPhysicalPageTempOff(pDevIns, GCPhys, GCPhysPage); +} + +#ifdef IN_RING3 + +/** + * @copydoc PDMDEVHLPR3::pfnPGMHandlerPhysicalReset + */ +DECLINLINE(int) PDMDevHlpPGMHandlerPhysicalReset(PPDMDEVINS pDevIns, RTGCPHYS GCPhys) +{ + return pDevIns->pHlpR3->pfnPGMHandlerPhysicalReset(pDevIns, GCPhys); +} + +/** + * @copydoc PDMDEVHLPR3::pfnVMMRegisterPatchMemory + */ +DECLINLINE(int) PDMDevHlpVMMRegisterPatchMemory(PPDMDEVINS pDevIns, RTGCPTR GCPtrPatchMem, uint32_t cbPatchMem) +{ + return pDevIns->pHlpR3->pfnVMMRegisterPatchMemory(pDevIns, GCPtrPatchMem, cbPatchMem); +} + +/** + * @copydoc PDMDEVHLPR3::pfnVMMDeregisterPatchMemory + */ +DECLINLINE(int) PDMDevHlpVMMDeregisterPatchMemory(PPDMDEVINS pDevIns, RTGCPTR GCPtrPatchMem, uint32_t cbPatchMem) +{ + return pDevIns->pHlpR3->pfnVMMDeregisterPatchMemory(pDevIns, GCPtrPatchMem, cbPatchMem); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSharedModuleRegister + */ +DECLINLINE(int) PDMDevHlpSharedModuleRegister(PPDMDEVINS pDevIns, VBOXOSFAMILY enmGuestOS, char *pszModuleName, char *pszVersion, + RTGCPTR GCBaseAddr, uint32_t cbModule, + uint32_t cRegions, VMMDEVSHAREDREGIONDESC const *paRegions) +{ + return pDevIns->pHlpR3->pfnSharedModuleRegister(pDevIns, enmGuestOS, pszModuleName, pszVersion, + GCBaseAddr, cbModule, cRegions, paRegions); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSharedModuleUnregister + */ +DECLINLINE(int) PDMDevHlpSharedModuleUnregister(PPDMDEVINS pDevIns, char *pszModuleName, char *pszVersion, + RTGCPTR GCBaseAddr, uint32_t cbModule) +{ + return pDevIns->pHlpR3->pfnSharedModuleUnregister(pDevIns, pszModuleName, pszVersion, GCBaseAddr, cbModule); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSharedModuleGetPageState + */ +DECLINLINE(int) PDMDevHlpSharedModuleGetPageState(PPDMDEVINS pDevIns, RTGCPTR GCPtrPage, bool *pfShared, + uint64_t *pfPageFlags) +{ + return pDevIns->pHlpR3->pfnSharedModuleGetPageState(pDevIns, GCPtrPage, pfShared, pfPageFlags); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSharedModuleCheckAll + */ +DECLINLINE(int) PDMDevHlpSharedModuleCheckAll(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnSharedModuleCheckAll(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnQueryLun + */ +DECLINLINE(int) PDMDevHlpQueryLun(PPDMDEVINS pDevIns, const char *pszDevice, unsigned iInstance, unsigned iLun, PPDMIBASE *ppBase) +{ + return pDevIns->pHlpR3->pfnQueryLun(pDevIns, pszDevice, iInstance, iLun, ppBase); +} + +/** + * @copydoc PDMDEVHLPR3::pfnGIMDeviceRegister + */ +DECLINLINE(void) PDMDevHlpGIMDeviceRegister(PPDMDEVINS pDevIns, PGIMDEBUG pDbg) +{ + pDevIns->pHlpR3->pfnGIMDeviceRegister(pDevIns, pDbg); +} + +/** + * @copydoc PDMDEVHLPR3::pfnGIMGetDebugSetup + */ +DECLINLINE(int) PDMDevHlpGIMGetDebugSetup(PPDMDEVINS pDevIns, PGIMDEBUGSETUP pDbgSetup) +{ + return pDevIns->pHlpR3->pfnGIMGetDebugSetup(pDevIns, pDbgSetup); +} + +#endif /* IN_RING3 */ + +/** + * @copydoc PDMDEVHLPR3::pfnGIMGetMmio2Regions + */ +DECLINLINE(PGIMMMIO2REGION) PDMDevHlpGIMGetMmio2Regions(PPDMDEVINS pDevIns, uint32_t *pcRegions) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnGIMGetMmio2Regions(pDevIns, pcRegions); +} + +#ifdef IN_RING3 + +/** Wrapper around SSMR3GetU32 for simplifying getting enum values saved as uint32_t. */ +# define PDMDEVHLP_SSM_GET_ENUM32_RET(a_pHlp, a_pSSM, a_enmDst, a_EnumType) \ + do { \ + uint32_t u32GetEnumTmp = 0; \ + int rcGetEnum32Tmp = (a_pHlp)->pfnSSMGetU32((a_pSSM), &u32GetEnumTmp); \ + AssertRCReturn(rcGetEnum32Tmp, rcGetEnum32Tmp); \ + (a_enmDst) = (a_EnumType)u32GetEnumTmp; \ + AssertCompile(sizeof(a_EnumType) == sizeof(u32GetEnumTmp)); \ + } while (0) + +/** Wrapper around SSMR3GetU8 for simplifying getting enum values saved as uint8_t. */ +# define PDMDEVHLP_SSM_GET_ENUM8_RET(a_pHlp, a_pSSM, a_enmDst, a_EnumType) \ + do { \ + uint8_t bGetEnumTmp = 0; \ + int rcGetEnum32Tmp = (a_pHlp)->pfnSSMGetU8((a_pSSM), &bGetEnumTmp); \ + AssertRCReturn(rcGetEnum32Tmp, rcGetEnum32Tmp); \ + (a_enmDst) = (a_EnumType)bGetEnumTmp; \ + } while (0) + +#endif /* IN_RING3 */ + +/** 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 DECLCALLBACKTYPE(int, FNPDMVBOXDEVICESREGISTER,(PPDMDEVREGCB pCallbacks, uint32_t u32Version)); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmdev_h */ diff --git a/include/VBox/vmm/pdmdrv.h b/include/VBox/vmm/pdmdrv.h new file mode 100644 index 00000000..6c0ee40f --- /dev/null +++ b/include/VBox/vmm/pdmdrv.h @@ -0,0 +1,2497 @@ +/** @file + * PDM - Pluggable Device Manager, Drivers. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmdrv_h +#define VBOX_INCLUDED_vmm_pdmdrv_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/vmm/pdmqueue.h> +#include <VBox/vmm/pdmcritsect.h> +#include <VBox/vmm/pdmifs.h> +#include <VBox/vmm/pdmins.h> +#include <VBox/vmm/pdmcommon.h> +#ifdef IN_RING3 +# include <VBox/vmm/pdmthread.h> +# include <VBox/vmm/pdmasynccompletion.h> +# include <VBox/vmm/pdmblkcache.h> +#endif +#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 <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 DECLCALLBACKTYPE(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 DECLCALLBACKTYPE(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 DECLCALLBACKTYPE(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 DECLCALLBACKTYPE(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 DECLCALLBACKTYPE(void, FNPDMDRVPOWERON,(PPDMDRVINS pDrvIns)); +/** Pointer to a FNPDMDRVPOWERON() function. */ +typedef FNPDMDRVPOWERON *PFNPDMDRVPOWERON; + +/** + * Reset notification. + * + * @returns VBox status. + * @param pDrvIns The driver instance data. + */ +typedef DECLCALLBACKTYPE(void, FNPDMDRVRESET,(PPDMDRVINS pDrvIns)); +/** Pointer to a FNPDMDRVRESET() function. */ +typedef FNPDMDRVRESET *PFNPDMDRVRESET; + +/** + * Suspend notification. + * + * @returns VBox status. + * @param pDrvIns The driver instance data. + */ +typedef DECLCALLBACKTYPE(void, FNPDMDRVSUSPEND,(PPDMDRVINS pDrvIns)); +/** Pointer to a FNPDMDRVSUSPEND() function. */ +typedef FNPDMDRVSUSPEND *PFNPDMDRVSUSPEND; + +/** + * Resume notification. + * + * @returns VBox status. + * @param pDrvIns The driver instance data. + */ +typedef DECLCALLBACKTYPE(void, FNPDMDRVRESUME,(PPDMDRVINS pDrvIns)); +/** Pointer to a FNPDMDRVRESUME() function. */ +typedef FNPDMDRVRESUME *PFNPDMDRVRESUME; + +/** + * Power Off notification. + * + * This is always called when VMR3PowerOff is called. + * There will be no callback when hot plugging devices or when replumbing the driver + * stack. + * + * @param pDrvIns The driver instance data. + */ +typedef DECLCALLBACKTYPE(void, FNPDMDRVPOWEROFF,(PPDMDRVINS pDrvIns)); +/** Pointer to a FNPDMDRVPOWEROFF() function. */ +typedef FNPDMDRVPOWEROFF *PFNPDMDRVPOWEROFF; + +/** + * Attach command. + * + * This is called to let the driver 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 DECLCALLBACKTYPE(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 DECLCALLBACKTYPE(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_UOFFSETOF(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))((RTRCUINTPTR)(pDrvIns)->pvInstanceDataRC - (RTRCUINTPTR)RT_UOFFSETOF(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_UOFFSETOF(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_UOFFSETOF(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_LIKELY( PDM_VERSION_ARE_COMPATIBLE((pDrvIns)->u32Version, PDM_DRVINS_VERSION) \ + && PDM_VERSION_ARE_COMPATIBLE((pDrvIns)->pHlpR3->u32Version, PDM_DRVHLPR3_VERSION)) ) \ + { /* likely */ } else 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 = pDrvIns->pHlpR3->pfnCFGMValidateConfig((pDrvIns)->pCfg, "/", pszValidValues, pszValidNodes, \ + (pDrvIns)->pReg->szName, (pDrvIns)->iInstance); \ + if (RT_SUCCESS(rcValCfg)) \ + { /* likely */ } else 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 pszCaptureFilename Path to the file for USB traffic capturing, optional. + * @param piPort Where to store the port number the device was attached to. + * @thread EMT. + */ + DECLR3CALLBACKMEMBER(int, pfnAttachDevice,(PPDMDRVINS pDrvIns, PPDMUSBINS pUsbIns, const char *pszCaptureFilename, 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, 2, 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; + + /** + * 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)); + + /** @name Exported PDM Critical Section Functions + * @{ */ + DECLRCCALLBACKMEMBER(int, pfnCritSectEnter,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, int rcBusy)); + DECLRCCALLBACKMEMBER(int, pfnCritSectEnterDebug,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLRCCALLBACKMEMBER(int, pfnCritSectTryEnter,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect)); + DECLRCCALLBACKMEMBER(int, pfnCritSectTryEnterDebug,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLRCCALLBACKMEMBER(int, pfnCritSectLeave,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect)); + DECLRCCALLBACKMEMBER(bool, pfnCritSectIsOwner,(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)); + DECLRCCALLBACKMEMBER(bool, pfnCritSectIsInitialized,(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)); + DECLRCCALLBACKMEMBER(bool, pfnCritSectHasWaiters,(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)); + DECLRCCALLBACKMEMBER(uint32_t, pfnCritSectGetRecursion,(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)); + /** @} */ + + /** + * Obtains bandwidth in a bandwidth group. + * + * @returns True if bandwidth was allocated, false if not. + * @param pDrvIns The driver instance. + * @param pFilter Pointer to the filter that allocates bandwidth. + * @param cbTransfer Number of bytes to allocate. + */ + DECLRCCALLBACKMEMBER(bool, pfnNetShaperAllocateBandwidth,(PPDMDRVINS pDrvIns, PPDMNSFILTER pFilter, size_t cbTransfer)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMDRVHLPRC; +/** Current PDMDRVHLPRC version number. */ +#define PDM_DRVHLPRC_VERSION PDM_VERSION_MAKE(0xf0f9, 6, 0) + + +/** + * PDM Driver API, ring-0 context. + */ +typedef struct PDMDRVHLPR0 +{ + /** Structure version. PDM_DRVHLPR0_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 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)); + + /** @name Exported PDM Critical Section Functions + * @{ */ + DECLR0CALLBACKMEMBER(int, pfnCritSectEnter,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, int rcBusy)); + DECLR0CALLBACKMEMBER(int, pfnCritSectEnterDebug,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR0CALLBACKMEMBER(int, pfnCritSectTryEnter,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect)); + DECLR0CALLBACKMEMBER(int, pfnCritSectTryEnterDebug,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR0CALLBACKMEMBER(int, pfnCritSectLeave,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect)); + DECLR0CALLBACKMEMBER(bool, pfnCritSectIsOwner,(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)); + DECLR0CALLBACKMEMBER(bool, pfnCritSectIsInitialized,(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)); + DECLR0CALLBACKMEMBER(bool, pfnCritSectHasWaiters,(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)); + DECLR0CALLBACKMEMBER(uint32_t, pfnCritSectGetRecursion,(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)); + DECLR0CALLBACKMEMBER(int, pfnCritSectScheduleExitEvent,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, SUPSEMEVENT hEventToSignal)); + /** @} */ + + /** + * Obtains bandwidth in a bandwidth group. + * + * @returns True if bandwidth was allocated, false if not. + * @param pDrvIns The driver instance. + * @param pFilter Pointer to the filter that allocates bandwidth. + * @param cbTransfer Number of bytes to allocate. + */ + DECLR0CALLBACKMEMBER(bool, pfnNetShaperAllocateBandwidth,(PPDMDRVINS pDrvIns, PPDMNSFILTER pFilter, size_t cbTransfer)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMDRVHLPR0; +/** Current DRVHLP version number. */ +#define PDM_DRVHLPR0_VERSION PDM_VERSION_MAKE(0xf0f8, 6, 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 SRC_POS 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) RT_IPRT_FORMAT_ATTR(6, 0)); + + /** + * 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) RT_IPRT_FORMAT_ATTR(4, 0)); + + /** + * 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)); + + /** @name Exported PDM Queue Functions + * @{ */ + /** + * 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 phQueue 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, PDMQUEUEHANDLE *phQueue)); + + DECLR3CALLBACKMEMBER(PPDMQUEUEITEMCORE, pfnQueueAlloc,(PPDMDRVINS pDrvIns, PDMQUEUEHANDLE hQueue)); + DECLR3CALLBACKMEMBER(int, pfnQueueInsert,(PPDMDRVINS pDrvIns, PDMQUEUEHANDLE hQueue, PPDMQUEUEITEMCORE pItem)); + DECLR3CALLBACKMEMBER(bool, pfnQueueFlushIfNecessary,(PPDMDRVINS pDrvIns, PDMQUEUEHANDLE hQueue)); + /** @} */ + + /** + * 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 phTimer Where to store the timer handle on success. + * @thread EMT + * + * @todo Need to add a bunch of timer helpers for this to be useful again. + * Will do when required. + */ + DECLR3CALLBACKMEMBER(int, pfnTimerCreate,(PPDMDRVINS pDrvIns, TMCLOCK enmClock, PFNTMTIMERDRV pfnCallback, void *pvUser, + uint32_t fFlags, const char *pszDesc, PTMTIMERHANDLE phTimer)); + + /** + * Destroys a timer. + * + * @returns VBox status. + * @param pDrvIns Driver instance. + * @param hTimer The timer handle to destroy. + */ + DECLR3CALLBACKMEMBER(int, pfnTimerDestroy,(PPDMDRVINS pDrvIns, TMTIMERHANDLE hTimer)); + + /** + * 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)); + + /** @name Exported SSM Functions + * @{ */ + DECLR3CALLBACKMEMBER(int, pfnSSMPutStruct,(PSSMHANDLE pSSM, const void *pvStruct, PCSSMFIELD paFields)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutStructEx,(PSSMHANDLE pSSM, const void *pvStruct, size_t cbStruct, uint32_t fFlags, PCSSMFIELD paFields, void *pvUser)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutBool,(PSSMHANDLE pSSM, bool fBool)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU8,(PSSMHANDLE pSSM, uint8_t u8)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS8,(PSSMHANDLE pSSM, int8_t i8)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU16,(PSSMHANDLE pSSM, uint16_t u16)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS16,(PSSMHANDLE pSSM, int16_t i16)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU32,(PSSMHANDLE pSSM, uint32_t u32)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS32,(PSSMHANDLE pSSM, int32_t i32)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU64,(PSSMHANDLE pSSM, uint64_t u64)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS64,(PSSMHANDLE pSSM, int64_t i64)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU128,(PSSMHANDLE pSSM, uint128_t u128)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS128,(PSSMHANDLE pSSM, int128_t i128)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutUInt,(PSSMHANDLE pSSM, RTUINT u)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutSInt,(PSSMHANDLE pSSM, RTINT i)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCUInt,(PSSMHANDLE pSSM, RTGCUINT u)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCUIntReg,(PSSMHANDLE pSSM, RTGCUINTREG u)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCPhys32,(PSSMHANDLE pSSM, RTGCPHYS32 GCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCPhys64,(PSSMHANDLE pSSM, RTGCPHYS64 GCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCPhys,(PSSMHANDLE pSSM, RTGCPHYS GCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCPtr,(PSSMHANDLE pSSM, RTGCPTR GCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCUIntPtr,(PSSMHANDLE pSSM, RTGCUINTPTR GCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutRCPtr,(PSSMHANDLE pSSM, RTRCPTR RCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutIOPort,(PSSMHANDLE pSSM, RTIOPORT IOPort)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutSel,(PSSMHANDLE pSSM, RTSEL Sel)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutMem,(PSSMHANDLE pSSM, const void *pv, size_t cb)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutStrZ,(PSSMHANDLE pSSM, const char *psz)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetStruct,(PSSMHANDLE pSSM, void *pvStruct, PCSSMFIELD paFields)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetStructEx,(PSSMHANDLE pSSM, void *pvStruct, size_t cbStruct, uint32_t fFlags, PCSSMFIELD paFields, void *pvUser)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetBool,(PSSMHANDLE pSSM, bool *pfBool)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetBoolV,(PSSMHANDLE pSSM, bool volatile *pfBool)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU8,(PSSMHANDLE pSSM, uint8_t *pu8)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU8V,(PSSMHANDLE pSSM, uint8_t volatile *pu8)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS8,(PSSMHANDLE pSSM, int8_t *pi8)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS8V,(PSSMHANDLE pSSM, int8_t volatile *pi8)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU16,(PSSMHANDLE pSSM, uint16_t *pu16)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU16V,(PSSMHANDLE pSSM, uint16_t volatile *pu16)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS16,(PSSMHANDLE pSSM, int16_t *pi16)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS16V,(PSSMHANDLE pSSM, int16_t volatile *pi16)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU32,(PSSMHANDLE pSSM, uint32_t *pu32)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU32V,(PSSMHANDLE pSSM, uint32_t volatile *pu32)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS32,(PSSMHANDLE pSSM, int32_t *pi32)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS32V,(PSSMHANDLE pSSM, int32_t volatile *pi32)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU64,(PSSMHANDLE pSSM, uint64_t *pu64)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU64V,(PSSMHANDLE pSSM, uint64_t volatile *pu64)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS64,(PSSMHANDLE pSSM, int64_t *pi64)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS64V,(PSSMHANDLE pSSM, int64_t volatile *pi64)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU128,(PSSMHANDLE pSSM, uint128_t *pu128)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU128V,(PSSMHANDLE pSSM, uint128_t volatile *pu128)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS128,(PSSMHANDLE pSSM, int128_t *pi128)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS128V,(PSSMHANDLE pSSM, int128_t volatile *pi128)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys32,(PSSMHANDLE pSSM, PRTGCPHYS32 pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys32V,(PSSMHANDLE pSSM, RTGCPHYS32 volatile *pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys64,(PSSMHANDLE pSSM, PRTGCPHYS64 pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys64V,(PSSMHANDLE pSSM, RTGCPHYS64 volatile *pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys,(PSSMHANDLE pSSM, PRTGCPHYS pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhysV,(PSSMHANDLE pSSM, RTGCPHYS volatile *pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetUInt,(PSSMHANDLE pSSM, PRTUINT pu)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetSInt,(PSSMHANDLE pSSM, PRTINT pi)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCUInt,(PSSMHANDLE pSSM, PRTGCUINT pu)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCUIntReg,(PSSMHANDLE pSSM, PRTGCUINTREG pu)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPtr,(PSSMHANDLE pSSM, PRTGCPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCUIntPtr,(PSSMHANDLE pSSM, PRTGCUINTPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetRCPtr,(PSSMHANDLE pSSM, PRTRCPTR pRCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetIOPort,(PSSMHANDLE pSSM, PRTIOPORT pIOPort)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetSel,(PSSMHANDLE pSSM, PRTSEL pSel)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetMem,(PSSMHANDLE pSSM, void *pv, size_t cb)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetStrZ,(PSSMHANDLE pSSM, char *psz, size_t cbMax)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetStrZEx,(PSSMHANDLE pSSM, char *psz, size_t cbMax, size_t *pcbStr)); + DECLR3CALLBACKMEMBER(int, pfnSSMSkip,(PSSMHANDLE pSSM, size_t cb)); + DECLR3CALLBACKMEMBER(int, pfnSSMSkipToEndOfUnit,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(int, pfnSSMSetLoadError,(PSSMHANDLE pSSM, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(6, 7)); + DECLR3CALLBACKMEMBER(int, pfnSSMSetLoadErrorV,(PSSMHANDLE pSSM, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(6, 0)); + DECLR3CALLBACKMEMBER(int, pfnSSMSetCfgError,(PSSMHANDLE pSSM, RT_SRC_POS_DECL, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(5, 6)); + DECLR3CALLBACKMEMBER(int, pfnSSMSetCfgErrorV,(PSSMHANDLE pSSM, RT_SRC_POS_DECL, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(5, 0)); + DECLR3CALLBACKMEMBER(int, pfnSSMHandleGetStatus,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(SSMAFTER, pfnSSMHandleGetAfter,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(bool, pfnSSMHandleIsLiveSave,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(uint32_t, pfnSSMHandleMaxDowntime,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(uint32_t, pfnSSMHandleHostBits,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(uint32_t, pfnSSMHandleRevision,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(uint32_t, pfnSSMHandleVersion,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(const char *, pfnSSMHandleHostOSAndArch,(PSSMHANDLE pSSM)); + /** @} */ + + /** @name Exported CFGM Functions. + * @{ */ + DECLR3CALLBACKMEMBER(bool, pfnCFGMExists,( PCFGMNODE pNode, const char *pszName)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryType,( PCFGMNODE pNode, const char *pszName, PCFGMVALUETYPE penmType)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQuerySize,( PCFGMNODE pNode, const char *pszName, size_t *pcb)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryInteger,( PCFGMNODE pNode, const char *pszName, uint64_t *pu64)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryIntegerDef,( PCFGMNODE pNode, const char *pszName, uint64_t *pu64, uint64_t u64Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryString,( PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryStringDef,( PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString, const char *pszDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryPassword,( PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryPasswordDef,( PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString, const char *pszDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryBytes,( PCFGMNODE pNode, const char *pszName, void *pvData, size_t cbData)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU64,( PCFGMNODE pNode, const char *pszName, uint64_t *pu64)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU64Def,( PCFGMNODE pNode, const char *pszName, uint64_t *pu64, uint64_t u64Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS64,( PCFGMNODE pNode, const char *pszName, int64_t *pi64)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS64Def,( PCFGMNODE pNode, const char *pszName, int64_t *pi64, int64_t i64Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU32,( PCFGMNODE pNode, const char *pszName, uint32_t *pu32)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU32Def,( PCFGMNODE pNode, const char *pszName, uint32_t *pu32, uint32_t u32Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS32,( PCFGMNODE pNode, const char *pszName, int32_t *pi32)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS32Def,( PCFGMNODE pNode, const char *pszName, int32_t *pi32, int32_t i32Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU16,( PCFGMNODE pNode, const char *pszName, uint16_t *pu16)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU16Def,( PCFGMNODE pNode, const char *pszName, uint16_t *pu16, uint16_t u16Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS16,( PCFGMNODE pNode, const char *pszName, int16_t *pi16)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS16Def,( PCFGMNODE pNode, const char *pszName, int16_t *pi16, int16_t i16Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU8,( PCFGMNODE pNode, const char *pszName, uint8_t *pu8)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU8Def,( PCFGMNODE pNode, const char *pszName, uint8_t *pu8, uint8_t u8Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS8,( PCFGMNODE pNode, const char *pszName, int8_t *pi8)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS8Def,( PCFGMNODE pNode, const char *pszName, int8_t *pi8, int8_t i8Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryBool,( PCFGMNODE pNode, const char *pszName, bool *pf)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryBoolDef,( PCFGMNODE pNode, const char *pszName, bool *pf, bool fDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryPort,( PCFGMNODE pNode, const char *pszName, PRTIOPORT pPort)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryPortDef,( PCFGMNODE pNode, const char *pszName, PRTIOPORT pPort, RTIOPORT PortDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryUInt,( PCFGMNODE pNode, const char *pszName, unsigned int *pu)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryUIntDef,( PCFGMNODE pNode, const char *pszName, unsigned int *pu, unsigned int uDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQuerySInt,( PCFGMNODE pNode, const char *pszName, signed int *pi)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQuerySIntDef,( PCFGMNODE pNode, const char *pszName, signed int *pi, signed int iDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtr,( PCFGMNODE pNode, const char *pszName, PRTGCPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrDef,( PCFGMNODE pNode, const char *pszName, PRTGCPTR pGCPtr, RTGCPTR GCPtrDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrU,( PCFGMNODE pNode, const char *pszName, PRTGCUINTPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrUDef,( PCFGMNODE pNode, const char *pszName, PRTGCUINTPTR pGCPtr, RTGCUINTPTR GCPtrDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrS,( PCFGMNODE pNode, const char *pszName, PRTGCINTPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrSDef,( PCFGMNODE pNode, const char *pszName, PRTGCINTPTR pGCPtr, RTGCINTPTR GCPtrDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryStringAlloc,( PCFGMNODE pNode, const char *pszName, char **ppszString)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryStringAllocDef,(PCFGMNODE pNode, const char *pszName, char **ppszString, const char *pszDef)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetParent,(PCFGMNODE pNode)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetChild,(PCFGMNODE pNode, const char *pszPath)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetChildF,(PCFGMNODE pNode, const char *pszPathFormat, ...) RT_IPRT_FORMAT_ATTR(2, 3)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetChildFV,(PCFGMNODE pNode, const char *pszPathFormat, va_list Args) RT_IPRT_FORMAT_ATTR(3, 0)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetFirstChild,(PCFGMNODE pNode)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetNextChild,(PCFGMNODE pCur)); + DECLR3CALLBACKMEMBER(int, pfnCFGMGetName,(PCFGMNODE pCur, char *pszName, size_t cchName)); + DECLR3CALLBACKMEMBER(size_t, pfnCFGMGetNameLen,(PCFGMNODE pCur)); + DECLR3CALLBACKMEMBER(bool, pfnCFGMAreChildrenValid,(PCFGMNODE pNode, const char *pszzValid)); + DECLR3CALLBACKMEMBER(PCFGMLEAF, pfnCFGMGetFirstValue,(PCFGMNODE pCur)); + DECLR3CALLBACKMEMBER(PCFGMLEAF, pfnCFGMGetNextValue,(PCFGMLEAF pCur)); + DECLR3CALLBACKMEMBER(int, pfnCFGMGetValueName,(PCFGMLEAF pCur, char *pszName, size_t cchName)); + DECLR3CALLBACKMEMBER(size_t, pfnCFGMGetValueNameLen,(PCFGMLEAF pCur)); + DECLR3CALLBACKMEMBER(CFGMVALUETYPE, pfnCFGMGetValueType,(PCFGMLEAF pCur)); + DECLR3CALLBACKMEMBER(bool, pfnCFGMAreValuesValid,(PCFGMNODE pNode, const char *pszzValid)); + DECLR3CALLBACKMEMBER(int, pfnCFGMValidateConfig,(PCFGMNODE pNode, const char *pszNode, + const char *pszValidValues, const char *pszValidNodes, + const char *pszWho, uint32_t uInstance)); + /** @} */ + + /** + * Free memory allocated with pfnMMHeapAlloc() and pfnMMHeapAllocZ(). + * + * @param pDrvIns Driver instance. + * @param pv Pointer to the memory to free. + */ + DECLR3CALLBACKMEMBER(void, pfnMMHeapFree,(PPDMDRVINS pDrvIns, void *pv)); + + /** + * 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)); + + /** + * Register an info handler with DBGF, argv style. + * + * @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, pfnDBGFInfoRegisterArgv,(PPDMDRVINS pDrvIns, const char *pszName, const char *pszDesc, PFNDBGFINFOARGVDRV 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. If this does not start + * with a '/', the default prefix will be prepended, + * otherwise it will be used as-is. + * @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. If this does not start + * with a '/', the default prefix will be prepended, + * otherwise it will be used as-is. + * @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, ...) RT_IPRT_FORMAT_ATTR(7, 8)); + + /** + * 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. If this does not + * start with a '/', the default prefix will be prepended, + * otherwise it will be used as-is. + * @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) RT_IPRT_FORMAT_ATTR(7, 0)); + + /** + * 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)); + + /** @name Exported PDM Thread Functions + * @{ */ + DECLR3CALLBACKMEMBER(int, pfnThreadDestroy,(PPDMTHREAD pThread, int *pRcThread)); + DECLR3CALLBACKMEMBER(int, pfnThreadIAmSuspending,(PPDMTHREAD pThread)); + DECLR3CALLBACKMEMBER(int, pfnThreadIAmRunning,(PPDMTHREAD pThread)); + DECLR3CALLBACKMEMBER(int, pfnThreadSleep,(PPDMTHREAD pThread, RTMSINTERVAL cMillies)); + DECLR3CALLBACKMEMBER(int, pfnThreadSuspend,(PPDMTHREAD pThread)); + DECLR3CALLBACKMEMBER(int, pfnThreadResume,(PPDMTHREAD pThread)); + /** @} */ + + /** + * 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)); + + /** @name Exported PDM Async Completion Functions + * @{ */ + DECLR3CALLBACKMEMBER(int, pfnAsyncCompletionTemplateDestroy,(PPDMASYNCCOMPLETIONTEMPLATE pTemplate)); + DECLR3CALLBACKMEMBER(int, pfnAsyncCompletionEpCreateForFile,(PPPDMASYNCCOMPLETIONENDPOINT ppEndpoint, + const char *pszFilename, uint32_t fFlags, + PPDMASYNCCOMPLETIONTEMPLATE pTemplate)); + DECLR3CALLBACKMEMBER(void, pfnAsyncCompletionEpClose,(PPDMASYNCCOMPLETIONENDPOINT pEndpoint)); + DECLR3CALLBACKMEMBER(int, pfnAsyncCompletionEpGetSize,(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, uint64_t *pcbSize)); + DECLR3CALLBACKMEMBER(int, pfnAsyncCompletionEpSetSize,(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, uint64_t cbSize)); + DECLR3CALLBACKMEMBER(int, pfnAsyncCompletionEpSetBwMgr,(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, const char *pszBwMgr)); + DECLR3CALLBACKMEMBER(int, pfnAsyncCompletionEpFlush,(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, void *pvUser, PPPDMASYNCCOMPLETIONTASK ppTask)); + DECLR3CALLBACKMEMBER(int, pfnAsyncCompletionEpRead,(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, RTFOFF off, + PCRTSGSEG paSegments, unsigned cSegments, + size_t cbRead, void *pvUser, + PPPDMASYNCCOMPLETIONTASK ppTask)); + DECLR3CALLBACKMEMBER(int, pfnAsyncCompletionEpWrite,(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, RTFOFF off, + PCRTSGSEG paSegments, unsigned cSegments, + size_t cbWrite, void *pvUser, + PPPDMASYNCCOMPLETIONTASK ppTask)); + /** @} */ + + + /** + * Attaches a network filter driver to a named bandwidth group. + * + * @returns VBox status code. + * @retval VERR_ALREADY_INITIALIZED if already attached to a group. + * @param pDrvIns The driver instance. + * @param pszBwGroup 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 a network filter driver from its current bandwidth group (if any). + * + * @returns VBox status code. + * @param pDrvIns The driver instance. + * @param pFilter Pointer to the filter we attach. + */ + DECLR3CALLBACKMEMBER(int, pfnNetShaperDetach,(PPDMDRVINS pDrvIns, PPDMNSFILTER pFilter)); + + /** + * Obtains bandwidth in a bandwidth group. + * + * @returns True if bandwidth was allocated, false if not. + * @param pDrvIns The driver instance. + * @param pFilter Pointer to the filter that allocates bandwidth. + * @param cbTransfer Number of bytes to allocate. + */ + DECLR3CALLBACKMEMBER(bool, pfnNetShaperAllocateBandwidth,(PPDMDRVINS pDrvIns, PPDMNSFILTER pFilter, size_t cbTransfer)); + + /** + * 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 SRC_POS 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. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnCritSectInit,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, RT_SRC_POS_DECL, const char *pszName)); + + /** @name Exported PDM Critical Section Functions + * @{ */ + DECLR3CALLBACKMEMBER(bool, pfnCritSectYield,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(int, pfnCritSectEnter,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, int rcBusy)); + DECLR3CALLBACKMEMBER(int, pfnCritSectEnterDebug,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR3CALLBACKMEMBER(int, pfnCritSectTryEnter,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(int, pfnCritSectTryEnterDebug,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR3CALLBACKMEMBER(int, pfnCritSectLeave,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(bool, pfnCritSectIsOwner,(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(bool, pfnCritSectIsInitialized,(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(bool, pfnCritSectHasWaiters,(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(uint32_t, pfnCritSectGetRecursion,(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(int, pfnCritSectScheduleExitEvent,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, SUPSEMEVENT hEventToSignal)); + DECLR3CALLBACKMEMBER(int, pfnCritSectDelete,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect)); + /** @} */ + + /** + * 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)); + + /** + * 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 pfnXferEnqueueDiscard The discard 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)); + + /** @name Exported PDM Block Cache Functions + * @{ */ + DECLR3CALLBACKMEMBER(void, pfnBlkCacheRelease,(PPDMBLKCACHE pBlkCache)); + DECLR3CALLBACKMEMBER(int, pfnBlkCacheClear,(PPDMBLKCACHE pBlkCache)); + DECLR3CALLBACKMEMBER(int, pfnBlkCacheSuspend,(PPDMBLKCACHE pBlkCache)); + DECLR3CALLBACKMEMBER(int, pfnBlkCacheResume,(PPDMBLKCACHE pBlkCache)); + DECLR3CALLBACKMEMBER(void, pfnBlkCacheIoXferComplete,(PPDMBLKCACHE pBlkCache, PPDMBLKCACHEIOXFER hIoXfer, int rcIoXfer)); + DECLR3CALLBACKMEMBER(int, pfnBlkCacheRead,(PPDMBLKCACHE pBlkCache, uint64_t off, PCRTSGBUF pSgBuf, size_t cbRead, void *pvUser)); + DECLR3CALLBACKMEMBER(int, pfnBlkCacheWrite,(PPDMBLKCACHE pBlkCache, uint64_t off, PCRTSGBUF pSgBuf, size_t cbRead, void *pvUser)); + DECLR3CALLBACKMEMBER(int, pfnBlkCacheFlush,(PPDMBLKCACHE pBlkCache, void *pvUser)); + DECLR3CALLBACKMEMBER(int, pfnBlkCacheDiscard,(PPDMBLKCACHE pBlkCache, PCRTRANGE paRanges, unsigned cRanges, void *pvUser)); + /** @} */ + + /** + * Gets the reason for the most recent VM suspend. + * + * @returns The suspend reason. VMSUSPENDREASON_INVALID is returned if no + * suspend has been made or if the pDrvIns is invalid. + * @param pDrvIns The driver instance. + */ + DECLR3CALLBACKMEMBER(VMSUSPENDREASON, pfnVMGetSuspendReason,(PPDMDRVINS pDrvIns)); + + /** + * Gets the reason for the most recent VM resume. + * + * @returns The resume reason. VMRESUMEREASON_INVALID is returned if no + * resume has been made or if the pDrvIns is invalid. + * @param pDrvIns The driver instance. + */ + DECLR3CALLBACKMEMBER(VMRESUMEREASON, pfnVMGetResumeReason,(PPDMDRVINS pDrvIns)); + + /** @name Space reserved for minor interface changes. + * @{ */ + DECLR3CALLBACKMEMBER(int, pfnTimerSetMillies,(PPDMDRVINS pDrvIns, TMTIMERHANDLE hTimer, uint64_t cMilliesToNext)); + + /** + * Deregister zero or more samples given their name prefix. + * + * @returns VBox status code. + * @param pDrvIns The driver instance. + * @param pszPrefix The name prefix of the samples to remove. If this does + * not start with a '/', the default prefix will be + * prepended, otherwise it will be used as-is. + */ + DECLR3CALLBACKMEMBER(int, pfnSTAMDeregisterByPrefix,(PPDMDRVINS pDrvIns, const char *pszPrefix)); + + /** + * Queries a generic object from the VMM user. + * + * @returns Pointer to the object if found, NULL if not. + * @param pDrvIns The driver instance. + * @param pUuid The UUID of what's being queried. The UUIDs and + * the usage conventions are defined by the user. + */ + DECLR3CALLBACKMEMBER(void *, pfnQueryGenericUserObject,(PPDMDRVINS pDrvIns, PCRTUUID pUuid)); + + DECLR3CALLBACKMEMBER(void, pfnReserved0,(PPDMDRVINS pDrvIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved1,(PPDMDRVINS pDrvIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved2,(PPDMDRVINS pDrvIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved3,(PPDMDRVINS pDrvIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved4,(PPDMDRVINS pDrvIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved5,(PPDMDRVINS pDrvIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved6,(PPDMDRVINS pDrvIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved7,(PPDMDRVINS pDrvIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved8,(PPDMDRVINS pDrvIns)); + /** @} */ + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMDRVHLPR3; +/** Current DRVHLP version number. */ +#define PDM_DRVHLPR3_VERSION PDM_VERSION_MAKE(0xf0fb, 16, 0) + + +/** + * Set the VM error message + * + * @returns rc. + * @param pDrvIns Driver instance. + * @param rc VBox status code. + * @param SRC_POS Use RT_SRC_POS. + * @param pszFormat Error message format string. + * @param ... Error message arguments. + * @sa PDMDRV_SET_ERROR, PDMDrvHlpVMSetErrorV, VMSetError + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(6, 7) 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 PDMDRVHLPR3::pfnVMSetErrorV + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(6, 0) 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); +} + + +/** + * 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. + * @sa PDMDRV_SET_RUNTIME_ERROR, PDMDrvHlpVMSetRuntimeErrorV, + * VMSetRuntimeError + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(4, 5) 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 PDMDRVHLPR3::pfnVMSetRuntimeErrorV + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(4, 0) 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); +} + +#endif /* IN_RING3 */ + +/** @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 + + +#ifdef IN_RING3 + +/** + * @copydoc PDMDRVHLPR3::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 PDMDRVHLPR3::pfnDetach + */ +DECLINLINE(int) PDMDrvHlpDetach(PPDMDRVINS pDrvIns, uint32_t fFlags) +{ + return pDrvIns->pHlpR3->pfnDetach(pDrvIns, fFlags); +} + +/** + * @copydoc PDMDRVHLPR3::pfnDetachSelf + */ +DECLINLINE(int) PDMDrvHlpDetachSelf(PPDMDRVINS pDrvIns, uint32_t fFlags) +{ + return pDrvIns->pHlpR3->pfnDetachSelf(pDrvIns, fFlags); +} + +/** + * @copydoc PDMDRVHLPR3::pfnMountPrepare + */ +DECLINLINE(int) PDMDrvHlpMountPrepare(PPDMDRVINS pDrvIns, const char *pszFilename, const char *pszCoreDriver) +{ + return pDrvIns->pHlpR3->pfnMountPrepare(pDrvIns, pszFilename, pszCoreDriver); +} + +/** + * @copydoc PDMDRVHLPR3::pfnVMState + */ +DECLINLINE(VMSTATE) PDMDrvHlpVMState(PPDMDRVINS pDrvIns) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnVMState(pDrvIns); +} + +/** + * @copydoc PDMDRVHLPR3::pfnVMTeleportedAndNotFullyResumedYet + */ +DECLINLINE(bool) PDMDrvHlpVMTeleportedAndNotFullyResumedYet(PPDMDRVINS pDrvIns) +{ + return pDrvIns->pHlpR3->pfnVMTeleportedAndNotFullyResumedYet(pDrvIns); +} + +/** + * @copydoc PDMDRVHLPR3::pfnGetSupDrvSession + */ +DECLINLINE(PSUPDRVSESSION) PDMDrvHlpGetSupDrvSession(PPDMDRVINS pDrvIns) +{ + return pDrvIns->pHlpR3->pfnGetSupDrvSession(pDrvIns); +} + +/** + * @copydoc PDMDRVHLPR3::pfnQueueCreate + */ +DECLINLINE(int) PDMDrvHlpQueueCreate(PPDMDRVINS pDrvIns, uint32_t cbItem, uint32_t cItems, uint32_t cMilliesInterval, + PFNPDMQUEUEDRV pfnCallback, const char *pszName, PDMQUEUEHANDLE *phQueue) +{ + return pDrvIns->pHlpR3->pfnQueueCreate(pDrvIns, cbItem, cItems, cMilliesInterval, pfnCallback, pszName, phQueue); +} + +/** + * @copydoc PDMDRVHLPR3::pfnQueueAlloc + */ +DECLINLINE(PPDMQUEUEITEMCORE) PDMDrvHlpQueueAlloc(PPDMDRVINS pDrvIns, PDMQUEUEHANDLE hQueue) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnQueueAlloc(pDrvIns, hQueue); +} + +/** + * @copydoc PDMDRVHLPR3::pfnQueueInsert + */ +DECLINLINE(int) PDMDrvHlpQueueInsert(PPDMDRVINS pDrvIns, PDMQUEUEHANDLE hQueue, PPDMQUEUEITEMCORE pItem) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnQueueInsert(pDrvIns, hQueue, pItem); +} + +/** + * @copydoc PDMDRVHLPR3::pfnQueueFlushIfNecessary + */ +DECLINLINE(bool) PDMDrvHlpQueueFlushIfNecessary(PPDMDRVINS pDrvIns, PDMQUEUEHANDLE hQueue) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnQueueFlushIfNecessary(pDrvIns, hQueue); +} + +/** + * @copydoc PDMDRVHLPR3::pfnTMGetVirtualFreq + */ +DECLINLINE(uint64_t) PDMDrvHlpTMGetVirtualFreq(PPDMDRVINS pDrvIns) +{ + return pDrvIns->pHlpR3->pfnTMGetVirtualFreq(pDrvIns); +} + +/** + * @copydoc PDMDRVHLPR3::pfnTMGetVirtualTime + */ +DECLINLINE(uint64_t) PDMDrvHlpTMGetVirtualTime(PPDMDRVINS pDrvIns) +{ + return pDrvIns->pHlpR3->pfnTMGetVirtualTime(pDrvIns); +} + +/** + * @copydoc PDMDRVHLPR3::pfnTimerCreate + */ +DECLINLINE(int) PDMDrvHlpTMTimerCreate(PPDMDRVINS pDrvIns, TMCLOCK enmClock, PFNTMTIMERDRV pfnCallback, void *pvUser, + uint32_t fFlags, const char *pszDesc, PTMTIMERHANDLE phTimer) + +{ + return pDrvIns->pHlpR3->pfnTimerCreate(pDrvIns, enmClock, pfnCallback, pvUser, fFlags, pszDesc, phTimer); +} + +/** + * @copydoc PDMDRVHLPR3::pfnTimerDestroy + */ +DECLINLINE(int) PDMDrvHlpTimerDestroy(PPDMDRVINS pDrvIns, TMTIMERHANDLE hTimer) + +{ + return pDrvIns->pHlpR3->pfnTimerDestroy(pDrvIns, hTimer); +} + +/** + * @copydoc PDMDRVHLPR3::pfnTimerSetMillies + */ +DECLINLINE(int) PDMDrvHlpTimerSetMillies(PPDMDRVINS pDrvIns, TMTIMERHANDLE hTimer, uint64_t cMilliesToNext) + +{ + return pDrvIns->pHlpR3->pfnTimerSetMillies(pDrvIns, hTimer, cMilliesToNext); +} + +/** + * 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 PDMDRVHLPR3::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 PDMDRVHLPR3::pfnMMHeapFree + */ +DECLINLINE(void) PDMDrvHlpMMHeapFree(PPDMDRVINS pDrvIns, void *pv) +{ + pDrvIns->pHlpR3->pfnMMHeapFree(pDrvIns, pv); +} + +/** + * @copydoc PDMDRVHLPR3::pfnDBGFInfoRegister + */ +DECLINLINE(int) PDMDrvHlpDBGFInfoRegister(PPDMDRVINS pDrvIns, const char *pszName, const char *pszDesc, PFNDBGFHANDLERDRV pfnHandler) +{ + return pDrvIns->pHlpR3->pfnDBGFInfoRegister(pDrvIns, pszName, pszDesc, pfnHandler); +} + +/** + * @copydoc PDMDRVHLPR3::pfnDBGFInfoRegisterArgv + */ +DECLINLINE(int) PDMDrvHlpDBGFInfoRegisterArgv(PPDMDRVINS pDrvIns, const char *pszName, const char *pszDesc, PFNDBGFINFOARGVDRV pfnHandler) +{ + return pDrvIns->pHlpR3->pfnDBGFInfoRegisterArgv(pDrvIns, pszName, pszDesc, pfnHandler); +} + +/** + * @copydoc PDMDRVHLPR3::pfnDBGFInfoRegister + */ +DECLINLINE(int) PDMDrvHlpDBGFInfoDeregister(PPDMDRVINS pDrvIns, const char *pszName, const char *pszDesc, PFNDBGFHANDLERDRV pfnHandler) +{ + return pDrvIns->pHlpR3->pfnDBGFInfoRegister(pDrvIns, pszName, pszDesc, pfnHandler); +} + +/** + * @copydoc PDMDRVHLPR3::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 PDMDRVHLPR3::pfnSTAMRegisterF + */ +DECLINLINE(void) RT_IPRT_FORMAT_ATTR(7, 8) 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 PDMDRVHLPR3::pfnSTAMDeregister + */ +DECLINLINE(int) PDMDrvHlpSTAMDeregister(PPDMDRVINS pDrvIns, void *pvSample) +{ + return pDrvIns->pHlpR3->pfnSTAMDeregister(pDrvIns, pvSample); +} + +/** + * @copydoc PDMDRVHLPR3::pfnSTAMDeregisterByPrefix + */ +DECLINLINE(int) PDMDrvHlpSTAMDeregisterByPrefix(PPDMDRVINS pDrvIns, const char *pszPrefix) +{ + return pDrvIns->pHlpR3->pfnSTAMDeregisterByPrefix(pDrvIns, pszPrefix); +} + +/** + * @copydoc PDMDRVHLPR3::pfnSUPCallVMMR0Ex + */ +DECLINLINE(int) PDMDrvHlpSUPCallVMMR0Ex(PPDMDRVINS pDrvIns, unsigned uOperation, void *pvArg, unsigned cbArg) +{ + return pDrvIns->pHlpR3->pfnSUPCallVMMR0Ex(pDrvIns, uOperation, pvArg, cbArg); +} + +/** + * @copydoc PDMDRVHLPR3::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 PDMDRVHLPR3::pfnSetAsyncNotification + */ +DECLINLINE(int) PDMDrvHlpSetAsyncNotification(PPDMDRVINS pDrvIns, PFNPDMDRVASYNCNOTIFY pfnAsyncNotify) +{ + return pDrvIns->pHlpR3->pfnSetAsyncNotification(pDrvIns, pfnAsyncNotify); +} + +/** + * @copydoc PDMDRVHLPR3::pfnAsyncNotificationCompleted + */ +DECLINLINE(void) PDMDrvHlpAsyncNotificationCompleted(PPDMDRVINS pDrvIns) +{ + pDrvIns->pHlpR3->pfnAsyncNotificationCompleted(pDrvIns); +} + +/** + * @copydoc PDMDRVHLPR3::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); +} + +/** + * @copydoc PDMR3ThreadDestroy + * @param pDrvIns The driver instance. + */ +DECLINLINE(int) PDMDrvHlpThreadDestroy(PPDMDRVINS pDrvIns, PPDMTHREAD pThread, int *pRcThread) +{ + return pDrvIns->pHlpR3->pfnThreadDestroy(pThread, pRcThread); +} + +/** + * @copydoc PDMR3ThreadIAmSuspending + * @param pDrvIns The driver instance. + */ +DECLINLINE(int) PDMDrvHlpThreadIAmSuspending(PPDMDRVINS pDrvIns, PPDMTHREAD pThread) +{ + return pDrvIns->pHlpR3->pfnThreadIAmSuspending(pThread); +} + +/** + * @copydoc PDMR3ThreadIAmRunning + * @param pDrvIns The driver instance. + */ +DECLINLINE(int) PDMDrvHlpThreadIAmRunning(PPDMDRVINS pDrvIns, PPDMTHREAD pThread) +{ + return pDrvIns->pHlpR3->pfnThreadIAmRunning(pThread); +} + +/** + * @copydoc PDMR3ThreadSleep + * @param pDrvIns The driver instance. + */ +DECLINLINE(int) PDMDrvHlpThreadSleep(PPDMDRVINS pDrvIns, PPDMTHREAD pThread, RTMSINTERVAL cMillies) +{ + return pDrvIns->pHlpR3->pfnThreadSleep(pThread, cMillies); +} + +/** + * @copydoc PDMR3ThreadSuspend + * @param pDrvIns The driver instance. + */ +DECLINLINE(int) PDMDrvHlpThreadSuspend(PPDMDRVINS pDrvIns, PPDMTHREAD pThread) +{ + return pDrvIns->pHlpR3->pfnThreadSuspend(pThread); +} + +/** + * @copydoc PDMR3ThreadResume + * @param pDrvIns The driver instance. + */ +DECLINLINE(int) PDMDrvHlpThreadResume(PPDMDRVINS pDrvIns, PPDMTHREAD pThread) +{ + return pDrvIns->pHlpR3->pfnThreadResume(pThread); +} + +# ifdef VBOX_WITH_PDM_ASYNC_COMPLETION +/** + * @copydoc PDMDRVHLPR3::pfnAsyncCompletionTemplateCreate + */ +DECLINLINE(int) PDMDrvHlpAsyncCompletionTemplateCreate(PPDMDRVINS pDrvIns, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate, + PFNPDMASYNCCOMPLETEDRV pfnCompleted, void *pvTemplateUser, const char *pszDesc) +{ + return pDrvIns->pHlpR3->pfnAsyncCompletionTemplateCreate(pDrvIns, ppTemplate, pfnCompleted, pvTemplateUser, pszDesc); +} + +/** + * @copydoc PDMDRVHLPR3::pfnAsyncCompletionTemplateDestroy + */ +DECLINLINE(int) PDMDrvHlpAsyncCompletionTemplateDestroy(PPDMDRVINS pDrvIns, PPDMASYNCCOMPLETIONTEMPLATE pTemplate) +{ + return pDrvIns->pHlpR3->pfnAsyncCompletionTemplateDestroy(pTemplate); +} + +/** + * @copydoc PDMDRVHLPR3::pfnAsyncCompletionEpCreateForFile + */ +DECLINLINE(int) PDMDrvHlpAsyncCompletionEpCreateForFile(PPDMDRVINS pDrvIns, PPPDMASYNCCOMPLETIONENDPOINT ppEndpoint, + const char *pszFilename, uint32_t fFlags, + PPDMASYNCCOMPLETIONTEMPLATE pTemplate) +{ + return pDrvIns->pHlpR3->pfnAsyncCompletionEpCreateForFile(ppEndpoint, pszFilename, fFlags, pTemplate); +} + +/** + * @copydoc PDMDRVHLPR3::pfnAsyncCompletionEpClose + */ +DECLINLINE(void) PDMDrvHlpAsyncCompletionEpClose(PPDMDRVINS pDrvIns, PPDMASYNCCOMPLETIONENDPOINT pEndpoint) +{ + pDrvIns->pHlpR3->pfnAsyncCompletionEpClose(pEndpoint); +} + +/** + * @copydoc PDMDRVHLPR3::pfnAsyncCompletionEpGetSize + */ +DECLINLINE(int) PDMDrvHlpAsyncCompletionEpGetSize(PPDMDRVINS pDrvIns, PPDMASYNCCOMPLETIONENDPOINT pEndpoint, uint64_t *pcbSize) +{ + return pDrvIns->pHlpR3->pfnAsyncCompletionEpGetSize(pEndpoint, pcbSize); +} + +/** + * @copydoc PDMDRVHLPR3::pfnAsyncCompletionEpSetSize + */ +DECLINLINE(int) PDMDrvHlpAsyncCompletionEpSetSize(PPDMDRVINS pDrvIns, PPDMASYNCCOMPLETIONENDPOINT pEndpoint, uint64_t cbSize) +{ + return pDrvIns->pHlpR3->pfnAsyncCompletionEpSetSize(pEndpoint, cbSize); +} + +/** + * @copydoc PDMDRVHLPR3::pfnAsyncCompletionEpSetBwMgr + */ +DECLINLINE(int) PDMDrvHlpAsyncCompletionEpSetBwMgr(PPDMDRVINS pDrvIns, PPDMASYNCCOMPLETIONENDPOINT pEndpoint, const char *pszBwMgr) +{ + return pDrvIns->pHlpR3->pfnAsyncCompletionEpSetBwMgr(pEndpoint, pszBwMgr); +} + +/** + * @copydoc PDMDRVHLPR3::pfnAsyncCompletionEpFlush + */ +DECLINLINE(int) PDMDrvHlpAsyncCompletionEpFlush(PPDMDRVINS pDrvIns, PPDMASYNCCOMPLETIONENDPOINT pEndpoint, void *pvUser, + PPPDMASYNCCOMPLETIONTASK ppTask) +{ + return pDrvIns->pHlpR3->pfnAsyncCompletionEpFlush(pEndpoint, pvUser, ppTask); +} + +/** + * @copydoc PDMDRVHLPR3::pfnAsyncCompletionEpRead + */ +DECLINLINE(int) PDMDrvHlpAsyncCompletionEpRead(PPDMDRVINS pDrvIns, PPDMASYNCCOMPLETIONENDPOINT pEndpoint, RTFOFF off, + PCRTSGSEG paSegments, unsigned cSegments, + size_t cbRead, void *pvUser, + PPPDMASYNCCOMPLETIONTASK ppTask) +{ + return pDrvIns->pHlpR3->pfnAsyncCompletionEpRead(pEndpoint, off, paSegments, cSegments, cbRead, pvUser, ppTask); +} + +/** + * @copydoc PDMDRVHLPR3::pfnAsyncCompletionEpWrite + */ +DECLINLINE(int) PDMDrvHlpAsyncCompletionEpWrite(PPDMDRVINS pDrvIns, PPDMASYNCCOMPLETIONENDPOINT pEndpoint, RTFOFF off, + PCRTSGSEG paSegments, unsigned cSegments, + size_t cbWrite, void *pvUser, + PPPDMASYNCCOMPLETIONTASK ppTask) +{ + return pDrvIns->pHlpR3->pfnAsyncCompletionEpWrite(pEndpoint, off, paSegments, cSegments, cbWrite, pvUser, ppTask); +} +# endif + +#endif /* IN_RING3 */ + +#ifdef VBOX_WITH_NETSHAPER +# ifdef IN_RING3 + +/** + * @copydoc PDMDRVHLPR3::pfnNetShaperAttach + */ +DECLINLINE(int) PDMDrvHlpNetShaperAttach(PPDMDRVINS pDrvIns, const char *pcszBwGroup, PPDMNSFILTER pFilter) +{ + return pDrvIns->pHlpR3->pfnNetShaperAttach(pDrvIns, pcszBwGroup, pFilter); +} + +/** + * @copydoc PDMDRVHLPR3::pfnNetShaperDetach + */ +DECLINLINE(int) PDMDrvHlpNetShaperDetach(PPDMDRVINS pDrvIns, PPDMNSFILTER pFilter) +{ + return pDrvIns->pHlpR3->pfnNetShaperDetach(pDrvIns, pFilter); +} + +# endif /* IN_RING3 */ + +/** + * @copydoc PDMDRVHLPR3::pfnNetShaperAllocateBandwidth + */ +DECLINLINE(bool) PDMDrvHlpNetShaperAllocateBandwidth(PPDMDRVINS pDrvIns, PPDMNSFILTER pFilter, size_t cbTransfer) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnNetShaperAllocateBandwidth(pDrvIns, pFilter, cbTransfer); +} + +#endif /* VBOX_WITH_NETSHAPER*/ + +#ifdef IN_RING3 +/** + * @copydoc PDMDRVHLPR3::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); +} +#endif /* IN_RING3 */ + +/** + * @see PDMCritSectEnter + */ +DECLINLINE(int) PDMDrvHlpCritSectEnter(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, int rcBusy) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnCritSectEnter(pDrvIns, pCritSect, rcBusy); +} + +/** + * @see PDMCritSectEnterDebug + */ +DECLINLINE(int) PDMDrvHlpCritSectEnterDebug(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnCritSectEnterDebug(pDrvIns, pCritSect, rcBusy, uId, RT_SRC_POS_ARGS); +} + +/** + * @see PDMCritSectTryEnter + */ +DECLINLINE(int) PDMDrvHlpCritSectTryEnter(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnCritSectTryEnter(pDrvIns, pCritSect); +} + +/** + * @see PDMCritSectTryEnterDebug + */ +DECLINLINE(int) PDMDrvHlpCritSectTryEnterDebug(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnCritSectTryEnterDebug(pDrvIns, pCritSect, uId, RT_SRC_POS_ARGS); +} + +/** + * @see PDMCritSectLeave + */ +DECLINLINE(int) PDMDrvHlpCritSectLeave(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnCritSectLeave(pDrvIns, pCritSect); +} + +/** + * @see PDMCritSectIsOwner + */ +DECLINLINE(bool) PDMDrvHlpCritSectIsOwner(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnCritSectIsOwner(pDrvIns, pCritSect); +} + +/** + * @see PDMCritSectIsInitialized + */ +DECLINLINE(bool) PDMDrvHlpCritSectIsInitialized(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnCritSectIsInitialized(pDrvIns, pCritSect); +} + +/** + * @see PDMCritSectHasWaiters + */ +DECLINLINE(bool) PDMDrvHlpCritSectHasWaiters(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnCritSectHasWaiters(pDrvIns, pCritSect); +} + +/** + * @see PDMCritSectGetRecursion + */ +DECLINLINE(uint32_t) PDMDrvHlpCritSectGetRecursion(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnCritSectGetRecursion(pDrvIns, pCritSect); +} + +#if defined(IN_RING3) || defined(IN_RING0) +/** + * @see PDMHCCritSectScheduleExitEvent + */ +DECLINLINE(int) PDMDrvHlpCritSectScheduleExitEvent(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, SUPSEMEVENT hEventToSignal) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnCritSectScheduleExitEvent(pDrvIns, pCritSect, hEventToSignal); +} +#endif + +/* Strict build: Remap the two enter calls to the debug versions. */ +#ifdef VBOX_STRICT +# ifdef IPRT_INCLUDED_asm_h +# define PDMDrvHlpCritSectEnter(pDrvIns, pCritSect, rcBusy) PDMDrvHlpCritSectEnterDebug((pDrvIns), (pCritSect), (rcBusy), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define PDMDrvHlpCritSectTryEnter(pDrvIns, pCritSect) PDMDrvHlpCritSectTryEnterDebug((pDrvIns), (pCritSect), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# else +# define PDMDrvHlpCritSectEnter(pDrvIns, pCritSect, rcBusy) PDMDrvHlpCritSectEnterDebug((pDrvIns), (pCritSect), (rcBusy), 0, RT_SRC_POS) +# define PDMDrvHlpCritSectTryEnter(pDrvIns, pCritSect) PDMDrvHlpCritSectTryEnterDebug((pDrvIns), (pCritSect), 0, RT_SRC_POS) +# endif +#endif + +#if defined(IN_RING3) || defined(DOXYGEN_RUNNING) + +/** + * @see PDMR3CritSectDelete + */ +DECLINLINE(int) PDMDrvHlpCritSectDelete(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect) +{ + return pDrvIns->pHlpR3->pfnCritSectDelete(pDrvIns, pCritSect); +} + +/** + * @copydoc PDMDRVHLPR3::pfnCallR0 + */ +DECLINLINE(int) PDMDrvHlpCallR0(PPDMDRVINS pDrvIns, uint32_t uOperation, uint64_t u64Arg) +{ + return pDrvIns->pHlpR3->pfnCallR0(pDrvIns, uOperation, u64Arg); +} + +/** + * @copydoc PDMDRVHLPR3::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); +} + +/** + * @copydoc PDMDRVHLPR3::pfnBlkCacheRelease + */ +DECLINLINE(void) PDMDrvHlpBlkCacheRelease(PPDMDRVINS pDrvIns, PPDMBLKCACHE pBlkCache) +{ + pDrvIns->pHlpR3->pfnBlkCacheRelease(pBlkCache); +} + +/** + * @copydoc PDMDRVHLPR3::pfnBlkCacheClear + */ +DECLINLINE(int) PDMDrvHlpBlkCacheClear(PPDMDRVINS pDrvIns, PPDMBLKCACHE pBlkCache) +{ + return pDrvIns->pHlpR3->pfnBlkCacheClear(pBlkCache); +} + +/** + * @copydoc PDMDRVHLPR3::pfnBlkCacheSuspend + */ +DECLINLINE(int) PDMDrvHlpBlkCacheSuspend(PPDMDRVINS pDrvIns, PPDMBLKCACHE pBlkCache) +{ + return pDrvIns->pHlpR3->pfnBlkCacheSuspend(pBlkCache); +} + +/** + * @copydoc PDMDRVHLPR3::pfnBlkCacheResume + */ +DECLINLINE(int) PDMDrvHlpBlkCacheResume(PPDMDRVINS pDrvIns, PPDMBLKCACHE pBlkCache) +{ + return pDrvIns->pHlpR3->pfnBlkCacheResume(pBlkCache); +} + +/** + * @copydoc PDMDRVHLPR3::pfnBlkCacheIoXferComplete + */ +DECLINLINE(void) PDMDrvHlpBlkCacheIoXferComplete(PPDMDRVINS pDrvIns, PPDMBLKCACHE pBlkCache, + PPDMBLKCACHEIOXFER hIoXfer, int rcIoXfer) +{ + pDrvIns->pHlpR3->pfnBlkCacheIoXferComplete(pBlkCache, hIoXfer, rcIoXfer); +} + +/** + * @copydoc PDMDRVHLPR3::pfnBlkCacheRead + */ +DECLINLINE(int) PDMDrvHlpBlkCacheRead(PPDMDRVINS pDrvIns, PPDMBLKCACHE pBlkCache, uint64_t off, + PCRTSGBUF pSgBuf, size_t cbRead, void *pvUser) +{ + return pDrvIns->pHlpR3->pfnBlkCacheRead(pBlkCache, off, pSgBuf, cbRead, pvUser); +} + +/** + * @copydoc PDMDRVHLPR3::pfnBlkCacheWrite + */ +DECLINLINE(int) PDMDrvHlpBlkCacheWrite(PPDMDRVINS pDrvIns, PPDMBLKCACHE pBlkCache, uint64_t off, + PCRTSGBUF pSgBuf, size_t cbRead, void *pvUser) +{ + return pDrvIns->pHlpR3->pfnBlkCacheWrite(pBlkCache, off, pSgBuf, cbRead, pvUser); +} + +/** + * @copydoc PDMDRVHLPR3::pfnBlkCacheFlush + */ +DECLINLINE(int) PDMDrvHlpBlkCacheFlush(PPDMDRVINS pDrvIns, PPDMBLKCACHE pBlkCache, void *pvUser) +{ + return pDrvIns->pHlpR3->pfnBlkCacheFlush(pBlkCache, pvUser); +} + +/** + * @copydoc PDMDRVHLPR3::pfnBlkCacheDiscard + */ +DECLINLINE(int) PDMDrvHlpBlkCacheDiscard(PPDMDRVINS pDrvIns, PPDMBLKCACHE pBlkCache, PCRTRANGE paRanges, + unsigned cRanges, void *pvUser) +{ + return pDrvIns->pHlpR3->pfnBlkCacheDiscard(pBlkCache, paRanges, cRanges, pvUser); +} + +/** + * @copydoc PDMDRVHLPR3::pfnVMGetSuspendReason + */ +DECLINLINE(VMSUSPENDREASON) PDMDrvHlpVMGetSuspendReason(PPDMDRVINS pDrvIns) +{ + return pDrvIns->pHlpR3->pfnVMGetSuspendReason(pDrvIns); +} + +/** + * @copydoc PDMDRVHLPR3::pfnVMGetResumeReason + */ +DECLINLINE(VMRESUMEREASON) PDMDrvHlpVMGetResumeReason(PPDMDRVINS pDrvIns) +{ + return pDrvIns->pHlpR3->pfnVMGetResumeReason(pDrvIns); +} + +/** + * @copydoc PDMDRVHLPR3::pfnQueryGenericUserObject + */ +DECLINLINE(void *) PDMDrvHlpQueryGenericUserObject(PPDMDRVINS pDrvIns, PCRTUUID pUuid) +{ + return pDrvIns->pHlpR3->pfnQueryGenericUserObject(pDrvIns, pUuid); +} + + +/** 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 DECLCALLBACKTYPE(int, FNPDMVBOXDRIVERSREGISTER,(PCPDMDRVREGCB pCallbacks, uint32_t u32Version)); + +VMMR3DECL(int) PDMR3DrvStaticRegistration(PVM pVM, FNPDMVBOXDRIVERSREGISTER pfnCallback); + +#endif /* IN_RING3 */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmdrv_h */ diff --git a/include/VBox/vmm/pdmifs.h b/include/VBox/vmm/pdmifs.h new file mode 100644 index 00000000..57ad02f2 --- /dev/null +++ b/include/VBox/vmm/pdmifs.h @@ -0,0 +1,2366 @@ +/** @file + * PDM - Pluggable Device Manager, Interfaces. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmifs_h +#define VBOX_INCLUDED_vmm_pdmifs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/sg.h> +#include <VBox/types.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 dx The X delta. + * @param dy The Y delta. + * @param dz The Z delta. + * @param dw The W (horizontal scroll button) delta. + * @param fButtons The button states, see the PDMIMOUSEPORT_BUTTON_* \#defines. + */ + DECLR3CALLBACKMEMBER(int, pfnPutEvent,(PPDMIMOUSEPORT pInterface, + int32_t dx, int32_t dy, int32_t dz, + int32_t dw, uint32_t fButtons)); + /** + * 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 x The X value, in the range 0 to 0xffff. + * @param y The Y value, in the range 0 to 0xffff. + * @param dz The Z delta. + * @param dw The W (horizontal scroll button) delta. + * @param fButtons The button states, see the PDMIMOUSEPORT_BUTTON_* \#defines. + */ + DECLR3CALLBACKMEMBER(int, pfnPutEventAbs,(PPDMIMOUSEPORT pInterface, + uint32_t x, uint32_t y, + int32_t dz, int32_t dw, + uint32_t fButtons)); + /** + * Puts a multi-touch absolute (touchscreen) event. + * + * @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 cContacts How many touch contacts in this event. + * @param pau64Contacts Pointer to array of packed contact information. + * Each 64bit element contains: + * Bits 0..15: X coordinate in pixels (signed). + * Bits 16..31: Y coordinate in pixels (signed). + * Bits 32..39: contact identifier. + * Bit 40: "in contact" flag, which indicates that + * there is a contact with the touch surface. + * Bit 41: "in range" flag, the contact is close enough + * to the touch surface. + * All other bits are reserved for future use and must be set to 0. + * @param u32ScanTime Timestamp of this event in milliseconds. Only relative + * time between event is important. + */ + DECLR3CALLBACKMEMBER(int, pfnPutEventTouchScreen,(PPDMIMOUSEPORT pInterface, + uint8_t cContacts, + const uint64_t *pau64Contacts, + uint32_t u32ScanTime)); + + /** + * Puts a multi-touch relative (touchpad) event. + * + * @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 cContacts How many touch contacts in this event. + * @param pau64Contacts Pointer to array of packed contact information. + * Each 64bit element contains: + * Bits 0..15: Normalized X coordinate (range: 0 - 0xffff). + * Bits 16..31: Normalized Y coordinate (range: 0 - 0xffff). + * Bits 32..39: contact identifier. + * Bit 40: "in contact" flag, which indicates that + * there is a contact with the touch surface. + * All other bits are reserved for future use and must be set to 0. + * @param u32ScanTime Timestamp of this event in milliseconds. Only relative + * time between event is important. + */ + + DECLR3CALLBACKMEMBER(int, pfnPutEventTouchPad,(PPDMIMOUSEPORT pInterface, + uint8_t cContacts, + const uint64_t *pau64Contacts, + uint32_t u32ScanTime)); +} PDMIMOUSEPORT; +/** PDMIMOUSEPORT interface ID. */ +#define PDMIMOUSEPORT_IID "d2bb54b7-d877-441b-9d25-d2d3329465c2" + +/** 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 this interface structure. + * @param fRelative Whether relative mode is currently supported. + * @param fAbsolute Whether absolute mode is currently supported. + * @param fMTAbsolute Whether absolute multi-touch mode is currently supported. + * @param fMTRelative Whether relative multi-touch mode is currently supported. + */ + DECLR3CALLBACKMEMBER(void, pfnReportModes,(PPDMIMOUSECONNECTOR pInterface, bool fRelative, bool fAbsolute, bool fMTAbsolute, bool fMTRelative)); + + /** + * Flushes the mouse queue if it contains pending events. + * + * @param pInterface Pointer to this interface structure. + */ + DECLR3CALLBACKMEMBER(void, pfnFlushQueue,(PPDMIMOUSECONNECTOR pInterface)); + +} PDMIMOUSECONNECTOR; +/** PDMIMOUSECONNECTOR interface ID. */ +#define PDMIMOUSECONNECTOR_IID "ce64d7bd-fa8f-41d1-a6fb-d102a2d6bffe" + + +/** Flags for PDMIKEYBOARDPORT::pfnPutEventHid. + * @{ */ +#define PDMIKBDPORT_KEY_UP RT_BIT(31) /** Key release event if set. */ +#define PDMIKBDPORT_RELEASE_KEYS RT_BIT(30) /** Force all keys to be released. */ +/** @} */ + +/** USB HID usage pages understood by PDMIKEYBOARDPORT::pfnPutEventHid. + * @{ */ +#define USB_HID_DC_PAGE 1 /** USB HID Generic Desktop Control Usage Page. */ +#define USB_HID_KB_PAGE 7 /** USB HID Keyboard Usage Page. */ +#define USB_HID_CC_PAGE 12 /** USB HID Consumer Control Usage Page. */ +/** @} */ + + +/** Pointer to a keyboard port interface. */ +typedef struct PDMIKEYBOARDPORT *PPDMIKEYBOARDPORT; +/** + * Keyboard port interface (down). + * Pair with PDMIKEYBOARDCONNECTOR. + */ +typedef struct PDMIKEYBOARDPORT +{ + /** + * Puts a scan code based 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 u8ScanCode The scan code to queue. + */ + DECLR3CALLBACKMEMBER(int, pfnPutEventScan,(PPDMIKEYBOARDPORT pInterface, uint8_t u8KeyCode)); + + /** + * Puts a USB HID usage ID based 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 idUsage The HID usage code event to queue. + */ + DECLR3CALLBACKMEMBER(int, pfnPutEventHid,(PPDMIKEYBOARDPORT pInterface, uint32_t idUsage)); + + /** + * Forcibly releases any pressed keys. + * + * This is called by the source of keyboard events in situations when a full + * release of all currently pressed keys must be forced, e.g. when activating + * a different keyboard, or when key-up events may have been lost. + * + * @returns VBox status code. + * + * @param pInterface Pointer to this interface structure. + */ + DECLR3CALLBACKMEMBER(int, pfnReleaseKeys,(PPDMIKEYBOARDPORT pInterface)); +} 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 this interface structure. + * @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 this interface structure. + * @param fActive Whether interface wishes to get "focus". + */ + DECLR3CALLBACKMEMBER(void, pfnSetActive,(PPDMIKEYBOARDCONNECTOR pInterface, bool fActive)); + + /** + * Flushes the keyboard queue if it contains pending events. + * + * @param pInterface Pointer to this interface structure. + */ + DECLR3CALLBACKMEMBER(void, pfnFlushQueue,(PPDMIKEYBOARDCONNECTOR pInterface)); + +} 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. + * @param fFailOnResize Fail is a resize is pending. + * @thread The emulation thread - bird sees no need for EMT here! + */ + DECLR3CALLBACKMEMBER(int, pfnUpdateDisplayAll,(PPDMIDISPLAYPORT pInterface, bool fFailOnResize)); + + /** + * Return the current guest resolution and 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. + * @param pcx Where to store the horizontal resolution. + * @param pcy Where to store the vertical resolution. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryVideoMode,(PPDMIDISPLAYPORT pInterface, uint32_t *pcBits, uint32_t *pcx, uint32_t *pcy)); + + /** + * 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 ppbData 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 **ppbData, 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 pbData Pointer to the buffer returned by + * pfnTakeScreenshot. + * @thread Any. + */ + DECLR3CALLBACKMEMBER(void, pfnFreeScreenshot,(PPDMIDISPLAYPORT pInterface, uint8_t *pbData)); + + /** + * 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 - bird sees no need for EMT here! + */ + 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)); + + /** + * Inform the VGA device of viewport changes (as a result of e.g. scrolling). + * + * @param pInterface Pointer to this interface. + * @param idScreen The screen updates are for. + * @param x The upper left corner x coordinate of the new viewport rectangle + * @param y The upper left corner y coordinate of the new viewport rectangle + * @param cx The width of the new viewport rectangle + * @param cy The height of the new viewport rectangle + * @thread GUI thread? + * + * @remarks Is allowed to be NULL. + */ + DECLR3CALLBACKMEMBER(void, pfnSetViewport,(PPDMIDISPLAYPORT pInterface, + uint32_t idScreen, uint32_t x, uint32_t y, uint32_t cx, uint32_t cy)); + + /** + * Send a video mode hint to the VGA device. + * + * @param pInterface Pointer to this interface. + * @param cx The X resolution. + * @param cy The Y resolution. + * @param cBPP The bit count. + * @param iDisplay The screen number. + * @param dx X offset into the virtual framebuffer or ~0. + * @param dy Y offset into the virtual framebuffer or ~0. + * @param fEnabled Is this screen currently enabled? + * @param fNotifyGuest Should the device send the guest an IRQ? + * Set for the last hint of a series. + * @thread Schedules on the emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnSendModeHint, (PPDMIDISPLAYPORT pInterface, uint32_t cx, uint32_t cy, + uint32_t cBPP, uint32_t iDisplay, uint32_t dx, + uint32_t dy, uint32_t fEnabled, uint32_t fNotifyGuest)); + + /** + * Send the guest a notification about host cursor capabilities changes. + * + * @param pInterface Pointer to this interface. + * @param fSupportsRenderCursor Whether the host can draw the guest cursor + * using the host one provided the location matches. + * @param fSupportsMoveCursor Whether the host can draw the guest cursor + * itself at any position. Implies RenderCursor. + * @thread Any. + */ + DECLR3CALLBACKMEMBER(void, pfnReportHostCursorCapabilities, (PPDMIDISPLAYPORT pInterface, bool fSupportsRenderCursor, bool fSupportsMoveCursor)); + + /** + * Tell the graphics device about the host cursor position. + * + * @param pInterface Pointer to this interface. + * @param x X offset into the cursor range. + * @param y Y offset into the cursor range. + * @param fOutOfRange The host pointer is out of all guest windows, so + * X and Y do not currently have meaningful value. + * @thread Any. + */ + DECLR3CALLBACKMEMBER(void, pfnReportHostCursorPosition, (PPDMIDISPLAYPORT pInterface, uint32_t x, uint32_t y, bool fOutOfRange)); + + /** + * Notify the graphics device about the monitor positions since the ones we get + * from vmwgfx FIFO are not correct. + * + * In an ideal universe this method should not be here. + * + * @param pInterface Pointer to this interface. + * @param cPositions Number of monitor positions. + * @param paPositions Monitor positions (offsets/origins) array. + * @thread Any (EMT). + * @sa PDMIVMMDEVCONNECTOR::pfnUpdateMonitorPositions + */ + DECLR3CALLBACKMEMBER(void, pfnReportMonitorPositions, (PPDMIDISPLAYPORT pInterface, uint32_t cPositions, + PCRTPOINT paPositions)); + +} PDMIDISPLAYPORT; +/** PDMIDISPLAYPORT interface ID. */ +#define PDMIDISPLAYPORT_IID "471b0520-338c-11e9-bb84-6ff2c956da45" + +/** @name Flags for PDMIDISPLAYCONNECTOR::pfnVBVAReportCursorPosition. + * @{ */ +/** Is the data in the report valid? */ +#define VBVA_CURSOR_VALID_DATA RT_BIT(0) +/** Is the cursor position reported relative to a particular guest screen? */ +#define VBVA_CURSOR_SCREEN_RELATIVE RT_BIT(1) +/** @} */ + +/** Pointer to a 3D graphics notification. */ +typedef struct VBOX3DNOTIFY VBOX3DNOTIFY; +/** Pointer to a 2D graphics acceleration command. */ +typedef struct VBOXVHWACMD VBOXVHWACMD; +/** Pointer to a VBVA command header. */ +typedef struct VBVACMDHDR *PVBVACMDHDR; +/** Pointer to a const VBVA command header. */ +typedef const struct VBVACMDHDR *PCVBVACMDHDR; +/** Pointer to a VBVA screen information. */ +typedef struct VBVAINFOSCREEN *PVBVAINFOSCREEN; +/** Pointer to a const VBVA screen information. */ +typedef const struct VBVAINFOSCREEN *PCVBVAINFOSCREEN; +/** Pointer to a VBVA guest VRAM area information. */ +typedef struct VBVAINFOVIEW *PVBVAINFOVIEW; +/** Pointer to a const VBVA guest VRAM area information. */ +typedef const struct VBVAINFOVIEW *PCVBVAINFOVIEW; +typedef struct VBVAHOSTFLAGS *PVBVAHOSTFLAGS; + +/** 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 or timer queue 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 enmCmd The command type (don't re-read from pCmd). + * @param fGuestCmd Set if the command origins with the guest and + * pCmd must be considered volatile. + * @param pCmd Video HW Acceleration Command to be processed. + * @retval VINF_SUCCESS - command is completed, + * @retval VINF_CALLBACK_RETURN if command will by asynchronously completed via + * complete callback. + * @retval VERR_INVALID_STATE if the command could not be processed (most + * likely because the framebuffer was disconnected) - the post should + * be retried later. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnVHWACommandProcess,(PPDMIDISPLAYCONNECTOR pInterface, int enmCmd, bool fGuestCmd, + VBOXVHWACMD RT_UNTRUSTED_VOLATILE_GUEST *pCmd)); + + /** + * The specified screen enters VBVA mode. + * + * @param pInterface Pointer to this interface. + * @param uScreenId The screen updates are for. + * @param pHostFlags Undocumented! + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnVBVAEnable,(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId, + struct VBVAHOSTFLAGS RT_UNTRUSTED_VOLATILE_GUEST *pHostFlags)); + + /** + * The specified screen leaves VBVA mode. + * + * @param pInterface Pointer to this interface. + * @param uScreenId The screen updates are for. + * @thread if render thread mode is on (fRenderThreadMode that was passed to pfnVBVAEnable is TRUE) - the render thread pfnVBVAEnable was called in, + * otherwise - 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 if render thread mode is on (fRenderThreadMode that was passed to pfnVBVAEnable is TRUE) - the render thread pfnVBVAEnable was called in, + * otherwise - the emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnVBVAUpdateBegin,(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId)); + + /** + * Process the guest VBVA command. + * + * @param pInterface Pointer to this interface. + * @param uScreenId The screen updates are for. + * @param pCmd Video HW Acceleration Command to be processed. + * @param cbCmd Undocumented! + * @thread if render thread mode is on (fRenderThreadMode that was passed to pfnVBVAEnable is TRUE) - the render thread pfnVBVAEnable was called in, + * otherwise - the emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnVBVAUpdateProcess,(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId, + struct VBVACMDHDR const RT_UNTRUSTED_VOLATILE_GUEST *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 if render thread mode is on (fRenderThreadMode that was passed to pfnVBVAEnable is TRUE) - the render thread pfnVBVAEnable was called in, + * otherwise - 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. + * @param fResetInputMapping Whether to reset the absolute pointing device to screen position co-ordinate + * mapping. Needed for real resizes, as the caller on the guest may not know how + * to set the mapping. Not wanted when we restore a saved state and are resetting + * the mode. + * @thread if render thread mode is on (fRenderThreadMode that was passed to pfnVBVAEnable is TRUE) - the render thread pfnVBVAEnable was called in, + * otherwise - the emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnVBVAResize,(PPDMIDISPLAYCONNECTOR pInterface, PCVBVAINFOVIEW pView, PCVBVAINFOSCREEN pScreen, + void *pvVRAM, bool fResetInputMapping)); + + /** + * 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 cx Pointer width in pixels. + * @param cy Pointer height in pixels. + * @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)); + + /** + * The guest capabilities were updated. + * + * @param pInterface Pointer to this interface. + * @param fCapabilities The new capability flag state. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnVBVAGuestCapabilityUpdate,(PPDMIDISPLAYCONNECTOR pInterface, uint32_t fCapabilities)); + + /** 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 *pbData; + /** 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; + /** @} */ + + /** + * The guest display input mapping rectangle was updated. + * + * @param pInterface Pointer to this interface. + * @param xOrigin Upper left X co-ordinate relative to the first screen. + * @param yOrigin Upper left Y co-ordinate relative to the first screen. + * @param cx Rectangle width. + * @param cy Rectangle height. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnVBVAInputMappingUpdate,(PPDMIDISPLAYCONNECTOR pInterface, int32_t xOrigin, int32_t yOrigin, uint32_t cx, uint32_t cy)); + + /** + * The guest is reporting the requested location of the host pointer. + * + * @param pInterface Pointer to this interface. + * @param fFlags VBVA_CURSOR_* + * @param uScreenId The screen to which X and Y are relative if VBVA_CURSOR_SCREEN_RELATIVE is set. + * @param x Cursor X offset. + * @param y Cursor Y offset. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnVBVAReportCursorPosition,(PPDMIDISPLAYCONNECTOR pInterface, uint32_t fFlags, uint32_t uScreen, uint32_t x, uint32_t y)); + + /** + * Process the graphics device HW Acceleration command. + * + * @param pInterface Pointer to this interface. + * @param p3DNotify Acceleration Command to be processed. + * @thread The graphics device thread: FIFO for the VMSVGA device. + */ + DECLR3CALLBACKMEMBER(int, pfn3DNotifyProcess,(PPDMIDISPLAYCONNECTOR pInterface, + VBOX3DNOTIFY *p3DNotify)); +} PDMIDISPLAYCONNECTOR; +/** PDMIDISPLAYCONNECTOR interface ID. */ +#define PDMIDISPLAYCONNECTOR_IID "cdd562e4-8030-11ea-8d40-bbc8e146c565" + + +/** Pointer to a secret key interface. */ +typedef struct PDMISECKEY *PPDMISECKEY; + +/** + * Secret key interface to retrieve secret keys. + */ +typedef struct PDMISECKEY +{ + /** + * Retains a key identified by the ID. The caller will only hold a reference + * to the key and must not modify the key buffer in any way. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pszId The alias/id for the key to retrieve. + * @param ppbKey Where to store the pointer to the key buffer on success. + * @param pcbKey Where to store the size of the key in bytes on success. + */ + DECLR3CALLBACKMEMBER(int, pfnKeyRetain, (PPDMISECKEY pInterface, const char *pszId, + const uint8_t **pbKey, size_t *pcbKey)); + + /** + * Releases one reference of the key identified by the given identifier. + * The caller must not access the key buffer after calling this operation. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pszId The alias/id for the key to release. + * + * @note: It is advised to release the key whenever it is not used anymore so the entity + * storing the key can do anything to make retrieving the key from memory more + * difficult like scrambling the memory buffer for instance. + */ + DECLR3CALLBACKMEMBER(int, pfnKeyRelease, (PPDMISECKEY pInterface, const char *pszId)); + + /** + * Retains a password identified by the ID. The caller will only hold a reference + * to the password and must not modify the buffer in any way. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pszId The alias/id for the password to retrieve. + * @param ppszPassword Where to store the pointer to the password on success. + */ + DECLR3CALLBACKMEMBER(int, pfnPasswordRetain, (PPDMISECKEY pInterface, const char *pszId, + const char **ppszPassword)); + + /** + * Releases one reference of the password identified by the given identifier. + * The caller must not access the password after calling this operation. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pszId The alias/id for the password to release. + * + * @note: It is advised to release the password whenever it is not used anymore so the entity + * storing the password can do anything to make retrieving the password from memory more + * difficult like scrambling the memory buffer for instance. + */ + DECLR3CALLBACKMEMBER(int, pfnPasswordRelease, (PPDMISECKEY pInterface, const char *pszId)); +} PDMISECKEY; +/** PDMISECKEY interface ID. */ +#define PDMISECKEY_IID "3d698355-d995-453d-960f-31566a891df2" + +/** Pointer to a secret key helper interface. */ +typedef struct PDMISECKEYHLP *PPDMISECKEYHLP; + +/** + * Secret key helper interface for non critical functionality. + */ +typedef struct PDMISECKEYHLP +{ + /** + * Notifies the interface provider that a key couldn't be retrieved from the key store. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + */ + DECLR3CALLBACKMEMBER(int, pfnKeyMissingNotify, (PPDMISECKEYHLP pInterface)); + +} PDMISECKEYHLP; +/** PDMISECKEY interface ID. */ +#define PDMISECKEYHLP_IID "7be96168-4156-40ac-86d2-3073bf8b318e" + + +/** Pointer to a stream interface. */ +typedef struct PDMISTREAM *PPDMISTREAM; +/** + * Stream interface (up). + * Makes up the foundation for PDMICHARCONNECTOR. No pair interface. + */ +typedef struct PDMISTREAM +{ + /** + * Polls for the specified events. + * + * @returns VBox status code. + * @retval VERR_INTERRUPTED if the poll was interrupted. + * @retval VERR_TIMEOUT if the maximum waiting time was reached. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param fEvts The events to poll for, see RTPOLL_EVT_XXX. + * @param pfEvts Where to return details about the events that occurred. + * @param cMillies Number of milliseconds to wait. Use + * RT_INDEFINITE_WAIT to wait for ever. + */ + DECLR3CALLBACKMEMBER(int, pfnPoll,(PPDMISTREAM pInterface, uint32_t fEvts, uint32_t *pfEvts, RTMSINTERVAL cMillies)); + + /** + * Interrupts the current poll call. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + */ + DECLR3CALLBACKMEMBER(int, pfnPollInterrupt,(PPDMISTREAM pInterface)); + + /** + * 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 pcbRead Number of bytes to read/bytes actually read. + * @thread Any thread. + * + * @note: This is non blocking, use the poll callback to block when there is nothing to read. + */ + DECLR3CALLBACKMEMBER(int, pfnRead,(PPDMISTREAM pInterface, void *pvBuf, size_t *pcbRead)); + + /** + * 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 pcbWrite Number of bytes to write/bytes actually written. + * @thread Any thread. + * + * @note: This is non blocking, use the poll callback to block until there is room to write. + */ + DECLR3CALLBACKMEMBER(int, pfnWrite,(PPDMISTREAM pInterface, const void *pvBuf, size_t *pcbWrite)); +} PDMISTREAM; +/** PDMISTREAM interface ID. */ +#define PDMISTREAM_IID "f9bd1ba6-c134-44cc-8259-febe14393952" + + +/** 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 pfEntered 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)); + + /** + * Send an ACPI monitor hot-plug event. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing + * the called function pointer. + */ + DECLR3CALLBACKMEMBER(int, pfnMonitorHotPlugEvent,(PPDMIACPIPORT pInterface)); + + /** + * Send a battery status change event. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing + * the called function pointer. + */ + DECLR3CALLBACKMEMBER(int, pfnBatteryStatusChangeEvent,(PPDMIACPIPORT pInterface)); +} PDMIACPIPORT; +/** PDMIACPIPORT interface ID. */ +#define PDMIACPIPORT_IID "974cb8fb-7fda-408c-f9b4-7ff4e3b2a699" + + +/** 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" + +struct VMMDevDisplayDef; + +/** 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 + * @param dz New mouse wheel vertical movement offset + * @param dw New mouse wheel horizontal movement offset + * @param fButtons New buttons state + */ + DECLR3CALLBACKMEMBER(int, pfnSetAbsoluteMouse,(PPDMIVMMDEVPORT pInterface, int32_t xAbs, int32_t yAbs, + int32_t dz, int32_t dw, uint32_t fButtons)); + + /** + * 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 cDisplays Number of displays. Can be either 1 or the number of VM virtual monitors. + * @param paDisplays Definitions of guest screens to be applied. See VMMDev.h + * @param fForce Whether to deliver the request to the guest even if the guest has + * the requested resolution already. + * @param fMayNotify Whether to send a hotplug notification to the guest if appropriate. + */ + DECLR3CALLBACKMEMBER(int, pfnRequestDisplayChange,(PPDMIVMMDEVPORT pInterface, uint32_t cDisplays, + struct VMMDevDisplayDef const *paDisplays, bool fForce, bool fMayNotify)); + + /** + * 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 "9e004f1a-875d-11e9-a673-c77c30f53623" + + +/** 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)); + + /** + * Updates a guest user state. + * + * Called in response to VMMDevReq_ReportGuestUserState. + * + * @param pInterface Pointer to this interface. + * @param pszUser Guest user name to update status for. + * @param pszDomain Domain the guest user is bound to. Optional. + * @param uState New guest user state to notify host about. + * @param pabDetails Pointer to optional state data. + * @param cbDetails Size (in bytes) of optional state data. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnUpdateGuestUserState,(PPDMIVMMDEVCONNECTOR pInterface, const char *pszUser, + const char *pszDomain, uint32_t uState, + const uint8_t *pabDetails, uint32_t cbDetails)); + + /** + * 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)); + + /** + * Update monitor positions (offsets). + * + * Passing monitor positions from the guest to host exclusively since vmwgfx + * (linux driver) fails to do so thru the FIFO. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param cPositions Number of monitor positions + * @param paPositions Positions array + * @remarks Is allowed to be NULL. + * @thread The emulation thread. + * @sa PDMIDISPLAYPORT::pfnReportMonitorPositions + */ + DECLR3CALLBACKMEMBER(int, pfnUpdateMonitorPositions,(PPDMIVMMDEVCONNECTOR pInterface, + uint32_t cPositions, PCRTPOINT paPositions)); + + /** + * Query the visible region of the display + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pcRects Where to return the number of rectangles in + * paRects. + * @param paRects Rectangle array (set to NULL to query the number + * of rectangles) + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryVisibleRegion,(PPDMIVMMDEVCONNECTOR pInterface, uint32_t *pcRects, PRTRECT paRects)); + + /** + * 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" + + +/** + * 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. + * + * @returns VINF_SUCCESS or VERR_CANCELLED if the guest canceled the call. + * @param pInterface Pointer to this interface. + * @param rc The return code (VBox error code). + * @param pCmd A pointer that identifies the completed command. + */ + DECLR3CALLBACKMEMBER(int, pfnCompleted,(PPDMIHGCMPORT pInterface, int32_t rc, PVBOXHGCMCMD pCmd)); + + /** + * Checks if @a pCmd was restored & resubmitted from saved state. + * + * @returns true if restored, false if not. + * @param pInterface Pointer to this interface. + * @param pCmd The command we're checking on. + */ + DECLR3CALLBACKMEMBER(bool, pfnIsCmdRestored,(PPDMIHGCMPORT pInterface, PVBOXHGCMCMD pCmd)); + + /** + * Checks if @a pCmd was cancelled. + * + * @returns true if cancelled, false if not. + * @param pInterface Pointer to this interface. + * @param pCmd The command we're checking on. + */ + DECLR3CALLBACKMEMBER(bool, pfnIsCmdCancelled,(PPDMIHGCMPORT pInterface, PVBOXHGCMCMD pCmd)); + + /** + * Gets the VMMDevRequestHeader::fRequestor value for @a pCmd. + * + * @returns The fRequestor value, VMMDEV_REQUESTOR_LEGACY if guest does not + * support it, VMMDEV_REQUESTOR_LOWEST if invalid parameters. + * @param pInterface Pointer to this interface. + * @param pCmd The command we're in checking on. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnGetRequestor,(PPDMIHGCMPORT pInterface, PVBOXHGCMCMD pCmd)); + + /** + * Gets the VMMDevState::idSession value. + * + * @returns VMMDevState::idSession. + * @param pInterface Pointer to this interface. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnGetVMMDevSessionId,(PPDMIHGCMPORT pInterface)); + +} PDMIHGCMPORT; +/** PDMIHGCMPORT interface ID. */ +# define PDMIHGCMPORT_IID "28c0a201-68cd-4752-9404-bb42a0c09eb7" + +/* forward decl to hgvmsvc.h. */ +struct VBOXHGCMSVCPARM; +/** 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. + * @param tsArrival The STAM_GET_TS() value when the request arrived. + * @return VBox status code. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnCall,(PPDMIHGCMCONNECTOR pInterface, PVBOXHGCMCMD pCmd, uint32_t u32ClientID, uint32_t u32Function, + uint32_t cParms, struct VBOXHGCMSVCPARM *paParms, uint64_t tsArrival)); + + /** + * Notification about the guest cancelling a pending request. + * @param pInterface Pointer to this interface. + * @param pCmd A pointer that identifies the command. + * @param idclient The client id returned by the pfnConnect call. + */ + DECLR3CALLBACKMEMBER(void, pfnCancelled,(PPDMIHGCMCONNECTOR pInterface, PVBOXHGCMCMD pCmd, uint32_t idClient)); + +} PDMIHGCMCONNECTOR; +/** PDMIHGCMCONNECTOR interface ID. */ +# define PDMIHGCMCONNECTOR_IID "33cb5c91-6a4a-4ad9-3fec-d1f7d413c4a5" + +#endif /* VBOX_WITH_HGCM */ + + +/** 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. + */ + DECLR3CALLBACKMEMBER(int, pfnVHWACommandCompleteAsync,(PPDMIDISPLAYVBVACALLBACKS pInterface, + VBOXVHWACMD RT_UNTRUSTED_VOLATILE_GUEST *pCmd)); +} PDMIDISPLAYVBVACALLBACKS; +/** PDMIDISPLAYVBVACALLBACKS */ +#define PDMIDISPLAYVBVACALLBACKS_IID "37f34c9c-0491-47dc-a0b3-81697c44a416" + +/** 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" + + +/** Pointer to a VFS connector interface. */ +typedef struct PDMIVFSCONNECTOR *PPDMIVFSCONNECTOR; +/** + * VFS connector interface (up). + */ +typedef struct PDMIVFSCONNECTOR +{ + /** + * Queries the size of the given path. + * + * @returns VBox status code. + * @retval VERR_NOT_FOUND if the path is not available. + * @param pInterface Pointer to this interface. + * @param pszNamespace The namespace for the path (usually driver/device name) or NULL for default namespace. + * @param pszPath The path to query the size for. + * @param pcb Where to store the size of the path in bytes on success. + */ + DECLR3CALLBACKMEMBER(int, pfnQuerySize, (PPDMIVFSCONNECTOR pInterface, const char *pszNamespace, const char *pszPath, + uint64_t *pcb)); + + /** + * Reads everything from the given path and stores the data into the supplied buffer. + * + * @returns VBox status code. + * @retval VERR_NOT_FOUND if the path is not available. + * @retval VERR_BUFFER_OVERFLOW if the supplied buffer is too small to read everything. + * @retval VINF_BUFFER_UNDERFLOW if the supplied buffer is too large. + * @param pInterface Pointer to this interface. + * @param pszNamespace The namespace for the path (usually driver/device name) or NULL for default namespace. + * @param pszPath The path to read everything for. + * @param pvBuf Where to store the data. + * @param cbRead How much to read. + */ + DECLR3CALLBACKMEMBER(int, pfnReadAll, (PPDMIVFSCONNECTOR pInterface, const char *pszNamespace, const char *pszPath, + void *pvBuf, size_t cbRead)); + + /** + * Writes the supplied data to the given path, overwriting any previously existing data. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pszNamespace The namespace for the path (usually driver/device name) or NULL for default namespace. + * @param pszPath The path to write everything to. + * @param pvBuf The data to store. + * @param cbWrite How many bytes to write. + */ + DECLR3CALLBACKMEMBER(int, pfnWriteAll, (PPDMIVFSCONNECTOR pInterface, const char *pszNamespace, const char *pszPath, + const void *pvBuf, size_t cbWrite)); + + /** + * Deletes the given path. + * + * @returns VBox status code. + * @retval VERR_NOT_FOUND if the path is not available. + * @param pszNamespace The namespace for the path (usually driver/device name) or NULL for default namespace. + * @param pszPath The path to delete. + */ + DECLR3CALLBACKMEMBER(int, pfnDelete, (PPDMIVFSCONNECTOR pInterface, const char *pszNamespace, const char *pszPath)); + + /** @todo Add standard open/read/write/close callbacks when the need arises. */ + +} PDMIVFSCONNECTOR; +/** PDMIVFSCONNECTOR interface ID. */ +#define PDMIVFSCONNECTOR_IID "a1fc51e0-414a-4e78-8388-8053b9dc6521" + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmifs_h */ diff --git a/include/VBox/vmm/pdmins.h b/include/VBox/vmm/pdmins.h new file mode 100644 index 00000000..9e50b723 --- /dev/null +++ b/include/VBox/vmm/pdmins.h @@ -0,0 +1,99 @@ +/** @file + * PDM - Pluggable Device Manager, Common Instance Macros. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmins_h +#define VBOX_INCLUDED_vmm_pdmins_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +/** @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 DECLCALLBACK(type) +#endif + +/** @def PDMINS_2_DATA + * Gets the shared instance data for a PDM device, USB device, or driver instance. + * @note For devices using PDMDEVINS_2_DATA is highly recommended. + */ +#define PDMINS_2_DATA(pIns, type) ( (type)(pIns)->CTX_SUFF(pvInstanceData) ) + +/** @def PDMINS_2_DATA_CC + * Gets the current context instance data for a PDM device, USB device, or driver instance. + * @note For devices using PDMDEVINS_2_DATA_CC is highly recommended. + */ +#define PDMINS_2_DATA_CC(pIns, type) ( (type)(void *)&(pIns)->achInstanceData[0] ) + +/* @def PDMINS_2_DATA_RC + * Gets the raw-mode context instance data for a PDM device instance. + */ +#define PDMINS_2_DATA_RC(pIns, type) ( (type)(pIns)->CTX_SUFF(pvInstanceDataForRC) ) + + +/** @def PDMINS_2_DATA_RCPTR + * Converts a PDM Device, USB Device, or Driver instance pointer to a RC pointer to the instance data. + * @deprecated + */ +#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. + * @deprecated + */ +#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. + * @deprecated + */ +#define PDMINS_2_DATA_R0PTR(pIns) ( (pIns)->pvInstanceDataR0 ) + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_pdmins_h */ diff --git a/include/VBox/vmm/pdmnetifs.h b/include/VBox/vmm/pdmnetifs.h new file mode 100644 index 00000000..49e93cb5 --- /dev/null +++ b/include/VBox/vmm/pdmnetifs.h @@ -0,0 +1,456 @@ +/** @file + * PDM - Pluggable Device Manager, Network Interfaces. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmnetifs_h +#define VBOX_INCLUDED_vmm_pdmnetifs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#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::pfnEndXmit */ + 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::pfnEndXmit */ + 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)); + /** + * Inform NAT about host DNS settings change. + * + * IHostNameResolutionConfigurationChangeEvent. + */ + DECLR3CALLBACKMEMBER(void, pfnNotifyDnsChanged, (PPDMINETWORKNATCONFIG pInterface)); + +} PDMINETWORKNATCONFIG; +/** PDMINETWORKNATCONFIG interface ID. */ +#define PDMINETWORKNATCONFIG_IID "dc961028-3523-4b52-a93b-e38168a4a9fa" +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmnetifs_h */ + diff --git a/include/VBox/vmm/pdmnetinline.h b/include/VBox/vmm/pdmnetinline.h new file mode 100644 index 00000000..0acd5fb9 --- /dev/null +++ b/include/VBox/vmm/pdmnetinline.h @@ -0,0 +1,724 @@ +/** @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-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmnetinline_h +#define VBOX_INCLUDED_vmm_pdmnetinline_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +/******************************************************************************* +* 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> + + +/** @defgroup grp_pdm_net_inline The PDM Networking Helper APIs + * @ingroup grp_pdm + * @{ + */ + + +/** + * 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) +{ +#define CHECK_COND_RETURN_FALSE(expr) if (RT_LIKELY(expr)) { /* likely */ } else return false + PDMNETWORKGSOTYPE enmType; + + CHECK_COND_RETURN_FALSE(cbGsoMax >= sizeof(*pGso)); + + enmType = (PDMNETWORKGSOTYPE)pGso->u8Type; + CHECK_COND_RETURN_FALSE(enmType > PDMNETWORKGSOTYPE_INVALID && enmType < PDMNETWORKGSOTYPE_END); + + /* all types requires both headers. */ + CHECK_COND_RETURN_FALSE(pGso->offHdr1 >= sizeof(RTNETETHERHDR)); + CHECK_COND_RETURN_FALSE(pGso->offHdr2 > pGso->offHdr1); + CHECK_COND_RETURN_FALSE(pGso->cbHdrsTotal > pGso->offHdr2); + + /* min size of the 1st header(s). */ + switch (enmType) + { + case PDMNETWORKGSOTYPE_IPV4_TCP: + case PDMNETWORKGSOTYPE_IPV4_UDP: + CHECK_COND_RETURN_FALSE((unsigned)pGso->offHdr2 - pGso->offHdr1 >= RTNETIPV4_MIN_LEN); + break; + case PDMNETWORKGSOTYPE_IPV6_TCP: + case PDMNETWORKGSOTYPE_IPV6_UDP: + CHECK_COND_RETURN_FALSE((unsigned)pGso->offHdr2 - pGso->offHdr1 >= RTNETIPV6_MIN_LEN); + break; + case PDMNETWORKGSOTYPE_IPV4_IPV6_TCP: + case PDMNETWORKGSOTYPE_IPV4_IPV6_UDP: + CHECK_COND_RETURN_FALSE((unsigned)pGso->offHdr2 - pGso->offHdr1 >= RTNETIPV4_MIN_LEN + RTNETIPV6_MIN_LEN); + break; + /* These two have been rejected above already, but we need to include them to avoid gcc warnings. */ + 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: + CHECK_COND_RETURN_FALSE((unsigned)pGso->cbHdrsTotal - pGso->offHdr2 >= RTNETTCP_MIN_LEN); + break; + case PDMNETWORKGSOTYPE_IPV4_UDP: + case PDMNETWORKGSOTYPE_IPV6_UDP: + case PDMNETWORKGSOTYPE_IPV4_IPV6_UDP: + CHECK_COND_RETURN_FALSE((unsigned)pGso->cbHdrsTotal - pGso->offHdr2 >= RTNETUDP_MIN_LEN); + break; + /* These two have been rejected above already, but we need to include them to avoid gcc warnings. */ + case PDMNETWORKGSOTYPE_INVALID: + case PDMNETWORKGSOTYPE_END: + break; + /* No default case! Want gcc warnings. */ + } + + /* There must be at more than one segment. */ + CHECK_COND_RETURN_FALSE(cbFrame > pGso->cbHdrsTotal); + CHECK_COND_RETURN_FALSE(cbFrame - pGso->cbHdrsTotal >= pGso->cbMaxSeg); + + /* Make sure the segment size is enough to fit a UDP header. */ + CHECK_COND_RETURN_FALSE(enmType != PDMNETWORKGSOTYPE_IPV4_UDP || pGso->cbMaxSeg >= RTNETUDP_MIN_LEN); + + /* Make sure the segment size is not zero. */ + CHECK_COND_RETURN_FALSE(pGso->cbMaxSeg > 0); + + return true; +#undef CHECK_COND_RETURN_FALSE +} + + +/** + * 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); + 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 offIPv4Hdr 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 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. + * + * UDP GSO uses IPv4 fragmentation, meaning that UDP header is present in + * the first fragment only. When computing the total frame size of the + * first fragment we need to use PDMNETWORKGSO::cbHdrsTotal instead of + * PDMNETWORKGSO::cbHdrsSeg. In case of TCP GSO both cbHdrsTotal and + * cbHdrsSeg have the same value, so it will work as well. + */ + 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 + (iSeg ? pGso->cbHdrsSeg : pGso->cbHdrsTotal); + + /* + * 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) + { + /* uh_ulen shall not exceed cbFrame - pGso->offHdr2 (offset of UDP header) */ + PRTNETUDP pUdpHdr = (PRTNETUDP)&pbFrame[pGso->offHdr2]; + Assert(pGso->offHdr2 + RT_UOFFSET_AFTER(RTNETUDP, uh_ulen) <= cbFrame); + if ((unsigned)(pGso->offHdr2 + RT_BE2H_U16(pUdpHdr->uh_ulen)) > cbFrame) + { + size_t cbUdp = cbFrame - pGso->offHdr2; + if (cbUdp >= UINT16_MAX) + pUdpHdr->uh_ulen = UINT16_MAX; + else + pUdpHdr->uh_ulen = RT_H2BE_U16((uint16_t)cbUdp); + } + /* uh_ulen shall be at least the size of UDP header */ + if (RT_BE2H_U16(pUdpHdr->uh_ulen) < sizeof(RTNETUDP)) + pUdpHdr->uh_ulen = RT_H2BE_U16(sizeof(RTNETUDP)); + 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) + { + /* uh_ulen shall not exceed cbFrame - pGso->offHdr2 (offset of UDP header) */ + PRTNETUDP pUdpHdr = (PRTNETUDP)&pbFrame[pGso->offHdr2]; + Assert(pGso->offHdr2 + RT_UOFFSET_AFTER(RTNETUDP, uh_ulen) <= cbFrame); + if ((unsigned)(pGso->offHdr2 + RT_BE2H_U16(pUdpHdr->uh_ulen)) > cbFrame) + { + size_t cbUdp = cbFrame - pGso->offHdr2; + if (cbUdp >= UINT16_MAX) + pUdpHdr->uh_ulen = UINT16_MAX; + else + pUdpHdr->uh_ulen = RT_H2BE_U16((uint16_t)cbUdp); + } + /* uh_ulen shall be at least the size of UDP header */ + if (RT_BE2H_U16(pUdpHdr->uh_ulen) < sizeof(RTNETUDP)) + pUdpHdr->uh_ulen = RT_H2BE_U16(sizeof(RTNETUDP)); + 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"; +} + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_pdmnetinline_h */ + diff --git a/include/VBox/vmm/pdmnetshaper.h b/include/VBox/vmm/pdmnetshaper.h new file mode 100644 index 00000000..dc6932bd --- /dev/null +++ b/include/VBox/vmm/pdmnetshaper.h @@ -0,0 +1,93 @@ +/** @file + * PDM - Pluggable Device Manager, Network Shaper. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmnetshaper_h +#define VBOX_INCLUDED_vmm_pdmnetshaper_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <VBox/vmm/pdmnetifs.h> +#include <iprt/list.h> +#include <iprt/sg.h> + + +/** @defgroup grp_pdm_net_shaper The PDM Network Shaper API + * @ingroup grp_pdm + * @{ + */ + + +#define PDM_NETSHAPER_MIN_BUCKET_SIZE UINT32_C(65536) /**< bytes */ +#define PDM_NETSHAPER_MAX_LATENCY UINT32_C(100) /**< milliseconds */ + +RT_C_DECLS_BEGIN + +/** + * A network shaper filter entry. + * + * This is used by DrvNetShaper and any similar drivers. + */ +typedef struct PDMNSFILTER +{ + /** Entry in the group's filter list. + * Both members are NULL when not associated with a group. */ + RTLISTNODER3 ListEntry; + /** The group index + 1. + * @note For safety reasons the value zero is invalid and this is 1-based + * (like pascal) rather than 0-based indexing. + * @note Volatile to prevent re-reading after validation. */ + uint32_t volatile iGroup; + /** Set when the filter fails to obtain bandwidth. + * This will then cause pIDrvNetR3 to be called before long. */ + bool fChoked; + /** Aligment padding. */ + bool afPadding[3]; + /** The driver this filter is aggregated into (ring-3). */ + R3PTRTYPE(PPDMINETWORKDOWN) pIDrvNetR3; +} PDMNSFILTER; + +VMM_INT_DECL(bool) PDMNetShaperAllocateBandwidth(PVMCC pVM, PPDMNSFILTER pFilter, size_t cbTransfer); +VMMR3_INT_DECL(int) PDMR3NsAttach(PVM pVM, PPDMDRVINS pDrvIns, const char *pszName, PPDMNSFILTER pFilter); +VMMR3_INT_DECL(int) PDMR3NsDetach(PVM pVM, PPDMDRVINS pDrvIns, PPDMNSFILTER pFilter); +VMMR3DECL(int) PDMR3NsBwGroupSetLimit(PUVM pUVM, const char *pszName, uint64_t cbPerSecMax); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmnetshaper_h */ + diff --git a/include/VBox/vmm/pdmpci.h b/include/VBox/vmm/pdmpci.h new file mode 100644 index 00000000..61493eb8 --- /dev/null +++ b/include/VBox/vmm/pdmpci.h @@ -0,0 +1,408 @@ +/** @file + * PDM - Pluggable Device Manager, raw PCI Devices. (VMM) + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmpci_h +#define VBOX_INCLUDED_vmm_pdmpci_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <VBox/rawpci.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_pciraw 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 pGCPhysRegion Where to store region base address (guest). + * @param pcbRegion Where to store region size. + * + * @param pfFlags If region is MMIO or IO. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(bool, pfnGetRegionInfo, (PPDMIPCIRAWUP pInterface, + uint32_t iRegion, + RTGCPHYS *pGCPhysRegion, + uint64_t *pcbRegion, + 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 cbRegion 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, + uint32_t iRegion, + RTHCPHYS StartAddress, + uint64_t cbRegion, + uint32_t fFlags, + PRTR3PTR ppvAddressR3, + PRTR0PTR 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 cbRegion 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, + uint32_t iRegion, + RTHCPHYS StartAddress, + uint64_t cbRegion, + RTR3PTR pvAddressR3, + RTR0PTR pvAddressR0)); + + /** + * Request port IO write. + * + * @returns status code + * @param pInterface Pointer to this interface structure. + * @param uPort I/O port address. + * @param uValue Value to write. + * @param cb Access width. + * + * @thread EMT thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPioWrite, (PPDMIPCIRAWUP pInterface, + RTIOPORT uPort, + uint32_t uValue, + unsigned cb)); + + /** + * Request port IO read. + * + * @returns status code + * @param pInterface Pointer to this interface structure. + * @param uPort I/O port address. + * @param puValue Place to store read value. + * @param cb Access width. + * + * @thread EMT thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPioRead, (PPDMIPCIRAWUP pInterface, + RTIOPORT uPort, + uint32_t *puValue, + 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 pvValue Address of value to write. + * @param cb Access width. + * + * @todo Why is this @a Address documented as guest physical + * address and given a host ring-0 address type? + * + * @thread EMT thread. + */ + DECLR3CALLBACKMEMBER(int, pfnMmioWrite, (PPDMIPCIRAWUP pInterface, + RTR0PTR Address, + void const *pvValue, + unsigned cb)); + + /** + * Request MMIO read. + * + * @returns status code + * @param pInterface Pointer to this interface structure. + * @param Address Guest physical address. + * @param pvValue Place to store read value. + * @param cb Access width. + * + * @todo Why is this @a Address documented as guest physical + * address and given a host ring-0 address type? + * + * @thread EMT thread. + */ + DECLR3CALLBACKMEMBER(int, pfnMmioRead, (PPDMIPCIRAWUP pInterface, + RTR0PTR Address, + void *pvValue, + 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 offCfgSpace Offset in PCI config space. + * @param pvValue Value to write. + * @param cb Access width. + * + * @thread EMT thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPciCfgWrite, (PPDMIPCIRAWUP pInterface, + uint32_t offCfgSpace, + void *pvValue, + 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 offCfgSpace Offset in PCI config space. + * @param pvValue Where to store read value. + * @param cb Access width. + * + * @thread EMT thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPciCfgRead, (PPDMIPCIRAWUP pInterface, + uint32_t offCfgSpace, + void *pvValue, + 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 uGuestIrq Guest IRQ to be passed to pfnInterruptRequest(). + * + * @thread Any thread, pfnInterruptRequest() will be usually invoked on a dedicated thread. + */ + DECLR3CALLBACKMEMBER(int, pfnEnableInterruptNotifications, (PPDMIPCIRAWUP pInterface, uint8_t uGuestIrq)); + + /** + * Request to disable interrupt notifications. + * + * @returns status code + * @param pInterface Pointer to this interface structure. + * + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnDisableInterruptNotifications, (PPDMIPCIRAWUP pInterface)); + + /** @name 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 uHostPciAddress Host PCI address of device attached. + * @param uGuestPciAddress Guest PCI address of device attached. + * @param pszDeviceName Human readable device name. + * @param fDeviceFlags Flags for the host device. + * @param pfFlags Flags for virtual device, from the upper driver. + * + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPciDeviceConstructStart, (PPDMIPCIRAWUP pInterface, + uint32_t uHostPciAddress, + uint32_t uGuestPciAddress, + const char *pszDeviceName, + uint32_t fDeviceFlags, + uint32_t *pfFlags)); + + /** + * 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. + * @param fFlags Flags. + * + * @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 enmState 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 enmState, + uint64_t *pu64Param)); + + /** + * Notify driver about runtime error. + * + * @param pInterface Pointer to this interface structure. + * @param fFatal If error is fatal. + * @param pszErrorId Error ID. + * @param pszMessage Error message. + * + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnReportRuntimeError, (PPDMIPCIRAWUP pInterface, + bool fFatal, + const char *pszErrorId, + const char *pszMessage)); + /** @} */ +} PDMIPCIRAWUP; + +/** + * Init R0 PCI module. + */ +PCIRAWR0DECL(int) PciRawR0Init(void); +/** + * Process request (in R0). + */ +PCIRAWR0DECL(int) PciRawR0ProcessReq(PGVM pGVM, PSUPDRVSESSION pSession, PPCIRAWSENDREQ pReq); +/** + * Terminate R0 PCI module. + */ +PCIRAWR0DECL(void) PciRawR0Term(void); + +/** + * Per-VM R0 module init. + */ +PCIRAWR0DECL(int) PciRawR0InitVM(PGVM pGVM); + +/** + * Per-VM R0 module termination routine. + */ +PCIRAWR0DECL(void) PciRawR0TermVM(PGVM pGVM); + +/** + * 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 /* !VBOX_INCLUDED_vmm_pdmpci_h */ diff --git a/include/VBox/vmm/pdmpcidev.h b/include/VBox/vmm/pdmpcidev.h new file mode 100644 index 00000000..077c5525 --- /dev/null +++ b/include/VBox/vmm/pdmpcidev.h @@ -0,0 +1,803 @@ +/** @file + * PCI - The PCI Controller And Devices. (DEV) + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmpcidev_h +#define VBOX_INCLUDED_vmm_pdmpcidev_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/pci.h> +#include <iprt/assert.h> + + +/** @defgroup grp_pdm_pcidev PDM PCI Device + * @ingroup grp_pdm_device + * @{ + */ + +/** + * Callback function for intercept reading from the PCI configuration space. + * + * @returns VINF_SUCCESS or PDMDevHlpDBGFStop status (maybe others later). + * @retval VINF_PDM_PCI_DO_DEFAULT to do default read (same as calling + * PDMDevHlpPCIConfigRead()). + * + * @param pDevIns Pointer to the device instance the PCI device + * belongs to. + * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance. + * @param uAddress The configuration space register address. [0..4096] + * @param cb The register size. [1,2,4] + * @param pu32Value Where to return the register value. + * + * @remarks Called with the PDM lock held. The device lock is NOT take because + * that is very likely be a lock order violation. + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNPCICONFIGREAD,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, + uint32_t uAddress, unsigned cb, uint32_t *pu32Value)); +/** Pointer to a FNPCICONFIGREAD() function. */ +typedef FNPCICONFIGREAD *PFNPCICONFIGREAD; +#if !RT_CLANG_PREREQ(11, 0) /* Clang 11 (at least) has trouble with nothrow and pointers to function pointers. */ +/** Pointer to a PFNPCICONFIGREAD. */ +typedef PFNPCICONFIGREAD *PPFNPCICONFIGREAD; +#endif + +/** + * Callback function for writing to the PCI configuration space. + * + * @returns VINF_SUCCESS or PDMDevHlpDBGFStop status (maybe others later). + * @retval VINF_PDM_PCI_DO_DEFAULT to do default read (same as calling + * PDMDevHlpPCIConfigWrite()). + * + * @param pDevIns Pointer to the device instance the PCI device + * belongs to. + * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance. + * @param uAddress The configuration space register address. [0..4096] + * @param cb The register size. [1,2,4] + * @param u32Value The value that's being written. The number of bits actually used from + * this value is determined by the cb parameter. + * + * @remarks Called with the PDM lock held. The device lock is NOT take because + * that is very likely be a lock order violation. + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNPCICONFIGWRITE,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, + uint32_t uAddress, unsigned cb, uint32_t u32Value)); +/** Pointer to a FNPCICONFIGWRITE() function. */ +typedef FNPCICONFIGWRITE *PFNPCICONFIGWRITE; +#if !RT_CLANG_PREREQ(11, 0) /* Clang 11 (at least) has trouble with nothrow and pointers to function pointers. */ +/** Pointer to a PFNPCICONFIGWRITE. */ +typedef PFNPCICONFIGWRITE *PPFNPCICONFIGWRITE; +#endif + +/** + * Callback function for mapping an PCI I/O region. + * + * This is called when a PCI I/O region is mapped, and for new-style devices + * also when unmapped (address set to NIL_RTGCPHYS). For new-style devices, + * this callback is optional as the PCI bus calls IOM to map and unmap the + * regions. + * + * Old style devices have to call IOM to map the region themselves, while + * unmapping is done by the PCI bus like with the new style devices. + * + * @returns VBox status code. + * @retval VINF_PCI_MAPPING_DONE if the caller already did the mapping and the + * PCI bus should not use the handle it got to do the registration + * again. (Only allowed when @a GCPhysAddress is not NIL_RTGCPHYS.) + * + * @param pDevIns Pointer to the device instance the PCI device + * belongs to. + * @param pPciDev Pointer to the PCI device. + * @param iRegion The region number. + * @param GCPhysAddress Physical address of the region. If @a enmType is + * PCI_ADDRESS_SPACE_IO, this is an I/O port, otherwise + * it's a physical address. + * + * NIL_RTGCPHYS indicates that a mapping is about to be + * unmapped and that the device deregister access + * handlers for it and update its internal state to + * reflect this. + * + * @param cb Size of the region in bytes. + * @param enmType One of the PCI_ADDRESS_SPACE_* values. + * + * @remarks Called with the PDM lock held. The device lock is NOT take because + * that is very likely be a lock order violation. + */ +typedef DECLCALLBACKTYPE(int, FNPCIIOREGIONMAP,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, + RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)); +/** Pointer to a FNPCIIOREGIONMAP() function. */ +typedef FNPCIIOREGIONMAP *PFNPCIIOREGIONMAP; + + +/** + * Sets the size and type for old saved states from within a + * PDMPCIDEV::pfnRegionLoadChangeHookR3 callback. + * + * @returns VBox status code. + * @param pPciDev Pointer to the PCI device. + * @param iRegion The region number. + * @param cbRegion The region size. + * @param enmType Combination of the PCI_ADDRESS_SPACE_* values. + */ +typedef DECLCALLBACKTYPE(int, FNPCIIOREGIONOLDSETTER,(PPDMPCIDEV pPciDev, uint32_t iRegion, RTGCPHYS cbRegion, + PCIADDRESSSPACE enmType)); +/** Pointer to a FNPCIIOREGIONOLDSETTER() function. */ +typedef FNPCIIOREGIONOLDSETTER *PFNPCIIOREGIONOLDSETTER; + +/** + * Swaps two PCI I/O regions from within a PDMPCIDEV::pfnRegionLoadChangeHookR3 + * callback. + * + * @returns VBox status code. + * @param pPciDev Pointer to the PCI device. + * @param iRegion The region number. + * @param iOtherRegion The number of the region swap with. + * @sa @bugref{9359} + */ +typedef DECLCALLBACKTYPE(int, FNPCIIOREGIONSWAP,(PPDMPCIDEV pPciDev, uint32_t iRegion, uint32_t iOtherRegion)); +/** Pointer to a FNPCIIOREGIONSWAP() function. */ +typedef FNPCIIOREGIONSWAP *PFNPCIIOREGIONSWAP; + + +/* + * Hack to include the PDMPCIDEVINT structure at the right place + * to avoid duplications of FNPCIIOREGIONMAP and such. + */ +#ifdef PDMPCIDEV_INCLUDE_PRIVATE +# include "pdmpcidevint.h" +#endif + +/** + * PDM PCI Device structure. + * + * A PCI device belongs to a PDM device. A PDM device may have zero or more PCI + * devices associated with it. The first PCI device that it registers + * automatically becomes the default PCI device and can be used implicitly + * with the device helper APIs. Subsequent PCI devices must be specified + * explicitly to the device helper APIs when used. + */ +typedef struct PDMPCIDEV +{ + /** @name Read only data. + * @{ + */ + /** Magic number (PDMPCIDEV_MAGIC). */ + uint32_t u32Magic; + /** PCI device number [11:3] and function [2:0] on the pci bus. + * @sa VBOX_PCI_DEVFN_MAKE, VBOX_PCI_DEVFN_FUN_MASK, VBOX_PCI_DEVFN_DEV_SHIFT */ + uint32_t uDevFn; + /** Size of the valid config space (we always allocate 4KB). */ + uint16_t cbConfig; + /** Size of the MSI-X state data optionally following the config space. */ + uint16_t cbMsixState; + /** Index into the PDMDEVINS::apPciDev array. */ + uint16_t idxSubDev; + uint16_t u16Padding; + /** Device name. */ + R3PTRTYPE(const char *) pszNameR3; + /** @} */ + + /** + * Callback for dealing with size changes. + * + * This is set by the PCI device when needed. It is only needed if any changes + * in the PCI resources have been made that may be incompatible with saved state + * (i.e. does not reflect configuration, but configuration defaults changed). + * + * The implementation can use PDMDevHlpMMIOExReduce to adjust the resource + * allocation down in size. There is currently no way of growing resources. + * Dropping a resource is automatic. + * + * @returns VBox status code. + * @param pDevIns Pointer to the device instance the PCI device + * belongs to. + * @param pPciDev Pointer to the PCI device. + * @param iRegion The region number or UINT32_MAX if old saved state call. + * @param cbRegion The size being loaded, RTGCPHYS_MAX if old saved state + * call, or 0 for dummy 64-bit top half region. + * @param enmType The type being loaded, -1 if old saved state call, or + * 0xff if dummy 64-bit top half region. + * @param pfnOldSetter Callback for setting size and type for call + * regarding old saved states. NULL otherwise. + * @param pfnSwapRegions Used to swaps two regions. The second one must be a + * higher number than @a iRegion. NULL if old saved + * state. + */ + DECLR3CALLBACKMEMBER(int, pfnRegionLoadChangeHookR3,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, + uint64_t cbRegion, PCIADDRESSSPACE enmType, + PFNPCIIOREGIONOLDSETTER pfnOldSetter, + PFNPCIIOREGIONSWAP pfnSwapRegion)); + + /** Reserved for future stuff. */ + uint64_t au64Reserved[4 + (R3_ARCH_BITS == 32 ? 1 : 0)]; + + /** Internal data. */ + union + { +#ifdef PDMPCIDEVINT_DECLARED + PDMPCIDEVINT s; +#endif + uint8_t padding[0x180]; + } Int; + + /** PCI config space. + * This is either 256 or 4096 in size. In the latter case it may be + * followed by a MSI-X state area. */ + uint8_t abConfig[4096]; + /** The MSI-X state data. Optional. */ + RT_FLEXIBLE_ARRAY_EXTENSION + uint8_t abMsixState[RT_FLEXIBLE_ARRAY]; +} PDMPCIDEV; +#ifdef PDMPCIDEVINT_DECLARED +AssertCompile(RT_SIZEOFMEMB(PDMPCIDEV, Int.s) <= RT_SIZEOFMEMB(PDMPCIDEV, Int.padding)); +#endif +/** Magic number of PDMPCIDEV::u32Magic (Margaret Eleanor Atwood). */ +#define PDMPCIDEV_MAGIC UINT32_C(0x19391118) + +/** Checks that the PCI device structure is valid and belongs to the device + * instance, but does not return. */ +#ifdef VBOX_STRICT +# define PDMPCIDEV_ASSERT_VALID(a_pDevIns, a_pPciDev) \ + do { \ + uintptr_t const offPciDevInTable = (uintptr_t)(a_pPciDev) - (uintptr_t)pDevIns->apPciDevs[0]; \ + uint32_t const cbPciDevTmp = pDevIns->cbPciDev; \ + ASMCompilerBarrier(); \ + AssertMsg( offPciDevInTable < pDevIns->cPciDevs * cbPciDevTmp \ + && cbPciDevTmp >= RT_UOFFSETOF(PDMPCIDEV, abConfig) + 256 \ + && offPciDevInTable % cbPciDevTmp == 0, \ + ("pPciDev=%p apPciDevs[0]=%p offPciDevInTable=%p cPciDevs=%#x cbPciDev=%#x\n", \ + (a_pPciDev), pDevIns->apPciDevs[0], offPciDevInTable, pDevIns->cPciDevs, cbPciDevTmp)); \ + AssertPtr((a_pPciDev)); \ + AssertMsg((a_pPciDev)->u32Magic == PDMPCIDEV_MAGIC, ("%#x\n", (a_pPciDev)->u32Magic)); \ + } while (0) +#else +# define PDMPCIDEV_ASSERT_VALID(a_pDevIns, a_pPciDev) do { } while (0) +#endif + +/** Checks that the PCI device structure is valid, belongs to the device + * instance and that it is registered, but does not return. */ +#ifdef VBOX_STRICT +# define PDMPCIDEV_ASSERT_VALID_AND_REGISTERED(a_pDevIns, a_pPciDev) \ + do { \ + PDMPCIDEV_ASSERT_VALID(a_pDevIns, a_pPciDev); \ + Assert((a_pPciDev)->Int.s.fRegistered); \ + } while (0) +#else +# define PDMPCIDEV_ASSERT_VALID_AND_REGISTERED(a_pDevIns, a_pPciDev) do { } while (0) +#endif + +/** Checks that the PCI device structure is valid and belongs to the device + * instance, returns appropriate status code if not valid. */ +#define PDMPCIDEV_ASSERT_VALID_RET(a_pDevIns, a_pPciDev) \ + do { \ + uintptr_t const offPciDevInTable = (uintptr_t)(a_pPciDev) - (uintptr_t)pDevIns->apPciDevs[0]; \ + uint32_t const cbPciDevTmp = pDevIns->cbPciDev; \ + ASMCompilerBarrier(); \ + AssertMsgReturn( offPciDevInTable < pDevIns->cPciDevs * cbPciDevTmp \ + && cbPciDevTmp >= RT_UOFFSETOF(PDMPCIDEV, abConfig) + 256 \ + && offPciDevInTable % cbPciDevTmp == 0, \ + ("pPciDev=%p apPciDevs[0]=%p offPciDevInTable=%p cPciDevs=%#x cbPciDev=%#x\n", \ + (a_pPciDev), pDevIns->apPciDevs[0], offPciDevInTable, pDevIns->cPciDevs, cbPciDevTmp), \ + VERR_PDM_NOT_PCI_DEVICE); \ + AssertMsgReturn((a_pPciDev)->u32Magic == PDMPCIDEV_MAGIC, ("%#x\n", (a_pPciDev)->u32Magic), VERR_PDM_NOT_PCI_DEVICE); \ + AssertReturn((a_pPciDev)->Int.s.fRegistered, VERR_PDM_NOT_PCI_DEVICE); \ + } while (0) + + + +/** @name PDM PCI config space accessor function. + * @{ + */ + +/** @todo handle extended space access. */ + +DECLINLINE(void) PDMPciDevSetByte(PPDMPCIDEV pPciDev, uint32_t offReg, uint8_t u8Value) +{ + Assert(offReg < sizeof(pPciDev->abConfig)); + pPciDev->abConfig[offReg] = u8Value; +} + +DECLINLINE(uint8_t) PDMPciDevGetByte(PCPDMPCIDEV pPciDev, uint32_t offReg) +{ + Assert(offReg < sizeof(pPciDev->abConfig)); + return pPciDev->abConfig[offReg]; +} + +DECLINLINE(void) PDMPciDevSetWord(PPDMPCIDEV pPciDev, uint32_t offReg, uint16_t u16Value) +{ + Assert(offReg <= sizeof(pPciDev->abConfig) - sizeof(uint16_t)); + *(uint16_t*)&pPciDev->abConfig[offReg] = RT_H2LE_U16(u16Value); +} + +DECLINLINE(uint16_t) PDMPciDevGetWord(PCPDMPCIDEV pPciDev, uint32_t offReg) +{ + uint16_t u16Value; + Assert(offReg <= sizeof(pPciDev->abConfig) - sizeof(uint16_t)); + u16Value = *(uint16_t*)&pPciDev->abConfig[offReg]; + return RT_H2LE_U16(u16Value); +} + +DECLINLINE(void) PDMPciDevSetDWord(PPDMPCIDEV pPciDev, uint32_t offReg, uint32_t u32Value) +{ + Assert(offReg <= sizeof(pPciDev->abConfig) - sizeof(uint32_t)); + *(uint32_t*)&pPciDev->abConfig[offReg] = RT_H2LE_U32(u32Value); +} + +DECLINLINE(uint32_t) PDMPciDevGetDWord(PCPDMPCIDEV pPciDev, uint32_t offReg) +{ + uint32_t u32Value; + Assert(offReg <= sizeof(pPciDev->abConfig) - sizeof(uint32_t)); + u32Value = *(uint32_t*)&pPciDev->abConfig[offReg]; + return RT_H2LE_U32(u32Value); +} + +DECLINLINE(void) PDMPciDevSetQWord(PPDMPCIDEV pPciDev, uint32_t offReg, uint64_t u64Value) +{ + Assert(offReg <= sizeof(pPciDev->abConfig) - sizeof(uint64_t)); + *(uint64_t*)&pPciDev->abConfig[offReg] = RT_H2LE_U64(u64Value); +} + +DECLINLINE(uint64_t) PDMPciDevGetQWord(PCPDMPCIDEV pPciDev, uint32_t offReg) +{ + uint64_t u64Value; + Assert(offReg <= sizeof(pPciDev->abConfig) - sizeof(uint64_t)); + u64Value = *(uint64_t*)&pPciDev->abConfig[offReg]; + return RT_H2LE_U64(u64Value); +} + +/** + * Sets the vendor id config register. + * @param pPciDev The PCI device. + * @param u16VendorId The vendor id. + */ +DECLINLINE(void) PDMPciDevSetVendorId(PPDMPCIDEV pPciDev, uint16_t u16VendorId) +{ + PDMPciDevSetWord(pPciDev, VBOX_PCI_VENDOR_ID, u16VendorId); +} + +/** + * Gets the vendor id config register. + * @returns the vendor id. + * @param pPciDev The PCI device. + */ +DECLINLINE(uint16_t) PDMPciDevGetVendorId(PCPDMPCIDEV pPciDev) +{ + return PDMPciDevGetWord(pPciDev, VBOX_PCI_VENDOR_ID); +} + + +/** + * Sets the device id config register. + * @param pPciDev The PCI device. + * @param u16DeviceId The device id. + */ +DECLINLINE(void) PDMPciDevSetDeviceId(PPDMPCIDEV pPciDev, uint16_t u16DeviceId) +{ + PDMPciDevSetWord(pPciDev, VBOX_PCI_DEVICE_ID, u16DeviceId); +} + +/** + * Gets the device id config register. + * @returns the device id. + * @param pPciDev The PCI device. + */ +DECLINLINE(uint16_t) PDMPciDevGetDeviceId(PCPDMPCIDEV pPciDev) +{ + return PDMPciDevGetWord(pPciDev, VBOX_PCI_DEVICE_ID); +} + +/** + * Sets the command config register. + * + * @param pPciDev The PCI device. + * @param u16Command The command register value. + */ +DECLINLINE(void) PDMPciDevSetCommand(PPDMPCIDEV pPciDev, uint16_t u16Command) +{ + PDMPciDevSetWord(pPciDev, VBOX_PCI_COMMAND, u16Command); +} + + +/** + * Gets the command config register. + * @returns The command register value. + * @param pPciDev The PCI device. + */ +DECLINLINE(uint16_t) PDMPciDevGetCommand(PCPDMPCIDEV pPciDev) +{ + return PDMPciDevGetWord(pPciDev, VBOX_PCI_COMMAND); +} + +/** + * Checks if the given PCI device is a bus master. + * @returns true if the device is a bus master, false if not. + * @param pPciDev The PCI device. + */ +DECLINLINE(bool) PDMPciDevIsBusmaster(PCPDMPCIDEV pPciDev) +{ + return (PDMPciDevGetCommand(pPciDev) & VBOX_PCI_COMMAND_MASTER) != 0; +} + +/** + * Checks if INTx interrupts disabled in the command config register. + * @returns true if disabled. + * @param pPciDev The PCI device. + */ +DECLINLINE(bool) PDMPciDevIsIntxDisabled(PCPDMPCIDEV pPciDev) +{ + return (PDMPciDevGetCommand(pPciDev) & VBOX_PCI_COMMAND_INTX_DISABLE) != 0; +} + +/** + * Gets the status config register. + * + * @returns status config register. + * @param pPciDev The PCI device. + */ +DECLINLINE(uint16_t) PDMPciDevGetStatus(PCPDMPCIDEV pPciDev) +{ + return PDMPciDevGetWord(pPciDev, VBOX_PCI_STATUS); +} + +/** + * Sets the status config register. + * + * @param pPciDev The PCI device. + * @param u16Status The status register value. + */ +DECLINLINE(void) PDMPciDevSetStatus(PPDMPCIDEV pPciDev, uint16_t u16Status) +{ + PDMPciDevSetWord(pPciDev, VBOX_PCI_STATUS, u16Status); +} + + +/** + * Sets the revision id config register. + * + * @param pPciDev The PCI device. + * @param u8RevisionId The revision id. + */ +DECLINLINE(void) PDMPciDevSetRevisionId(PPDMPCIDEV pPciDev, uint8_t u8RevisionId) +{ + PDMPciDevSetByte(pPciDev, VBOX_PCI_REVISION_ID, u8RevisionId); +} + + +/** + * Sets the register level programming class config register. + * + * @param pPciDev The PCI device. + * @param u8ClassProg The new value. + */ +DECLINLINE(void) PDMPciDevSetClassProg(PPDMPCIDEV pPciDev, uint8_t u8ClassProg) +{ + PDMPciDevSetByte(pPciDev, VBOX_PCI_CLASS_PROG, u8ClassProg); +} + + +/** + * Sets the sub-class (aka device class) config register. + * + * @param pPciDev The PCI device. + * @param u8SubClass The sub-class. + */ +DECLINLINE(void) PDMPciDevSetClassSub(PPDMPCIDEV pPciDev, uint8_t u8SubClass) +{ + PDMPciDevSetByte(pPciDev, VBOX_PCI_CLASS_SUB, u8SubClass); +} + + +/** + * Sets the base class config register. + * + * @param pPciDev The PCI device. + * @param u8BaseClass The base class. + */ +DECLINLINE(void) PDMPciDevSetClassBase(PPDMPCIDEV pPciDev, uint8_t u8BaseClass) +{ + PDMPciDevSetByte(pPciDev, VBOX_PCI_CLASS_BASE, u8BaseClass); +} + +/** + * Sets the header type config register. + * + * @param pPciDev The PCI device. + * @param u8HdrType The header type. + */ +DECLINLINE(void) PDMPciDevSetHeaderType(PPDMPCIDEV pPciDev, uint8_t u8HdrType) +{ + PDMPciDevSetByte(pPciDev, VBOX_PCI_HEADER_TYPE, u8HdrType); +} + +/** + * Gets the header type config register. + * + * @param pPciDev The PCI device. + * @returns u8HdrType The header type. + */ +DECLINLINE(uint8_t) PDMPciDevGetHeaderType(PCPDMPCIDEV pPciDev) +{ + return PDMPciDevGetByte(pPciDev, VBOX_PCI_HEADER_TYPE); +} + +/** + * Sets the BIST (built-in self-test) config register. + * + * @param pPciDev The PCI device. + * @param u8Bist The BIST value. + */ +DECLINLINE(void) PDMPciDevSetBIST(PPDMPCIDEV pPciDev, uint8_t u8Bist) +{ + PDMPciDevSetByte(pPciDev, VBOX_PCI_BIST, u8Bist); +} + +/** + * Gets the BIST (built-in self-test) config register. + * + * @param pPciDev The PCI device. + * @returns u8Bist The BIST. + */ +DECLINLINE(uint8_t) PDMPciDevGetBIST(PCPDMPCIDEV pPciDev) +{ + return PDMPciDevGetByte(pPciDev, VBOX_PCI_BIST); +} + + +/** + * Sets a base address config register. + * + * @param pPciDev The PCI device. + * @param iReg Base address register number (0..5). + * @param fIOSpace Whether it's I/O (true) or memory (false) space. + * @param fPrefetchable Whether the memory is prefetachable. Must be false if fIOSpace == true. + * @param f64Bit Whether the memory can be mapped anywhere in the 64-bit address space. Otherwise restrict to 32-bit. + * @param u32Addr The address value. + */ +DECLINLINE(void) PDMPciDevSetBaseAddress(PPDMPCIDEV pPciDev, uint8_t iReg, bool fIOSpace, bool fPrefetchable, bool f64Bit, + uint32_t u32Addr) +{ + if (fIOSpace) + { + Assert(!(u32Addr & 0x3)); Assert(!fPrefetchable); Assert(!f64Bit); + u32Addr |= RT_BIT_32(0); + } + else + { + Assert(!(u32Addr & 0xf)); + if (fPrefetchable) + u32Addr |= RT_BIT_32(3); + if (f64Bit) + u32Addr |= 0x2 << 1; + } + switch (iReg) + { + case 0: iReg = VBOX_PCI_BASE_ADDRESS_0; break; + case 1: iReg = VBOX_PCI_BASE_ADDRESS_1; break; + case 2: iReg = VBOX_PCI_BASE_ADDRESS_2; break; + case 3: iReg = VBOX_PCI_BASE_ADDRESS_3; break; + case 4: iReg = VBOX_PCI_BASE_ADDRESS_4; break; + case 5: iReg = VBOX_PCI_BASE_ADDRESS_5; break; + default: AssertFailedReturnVoid(); + } + + PDMPciDevSetDWord(pPciDev, iReg, u32Addr); +} + +/** + * Please document me. I don't seem to be getting as much as calculating + * the address of some PCI region. + */ +DECLINLINE(uint32_t) PDMPciDevGetRegionReg(uint32_t iRegion) +{ + return iRegion == VBOX_PCI_ROM_SLOT + ? VBOX_PCI_ROM_ADDRESS : (VBOX_PCI_BASE_ADDRESS_0 + iRegion * 4); +} + +/** + * Sets the sub-system vendor id config register. + * + * @param pPciDev The PCI device. + * @param u16SubSysVendorId The sub-system vendor id. + */ +DECLINLINE(void) PDMPciDevSetSubSystemVendorId(PPDMPCIDEV pPciDev, uint16_t u16SubSysVendorId) +{ + PDMPciDevSetWord(pPciDev, VBOX_PCI_SUBSYSTEM_VENDOR_ID, u16SubSysVendorId); +} + +/** + * Gets the sub-system vendor id config register. + * @returns the sub-system vendor id. + * @param pPciDev The PCI device. + */ +DECLINLINE(uint16_t) PDMPciDevGetSubSystemVendorId(PCPDMPCIDEV pPciDev) +{ + return PDMPciDevGetWord(pPciDev, VBOX_PCI_SUBSYSTEM_VENDOR_ID); +} + + +/** + * Sets the sub-system id config register. + * + * @param pPciDev The PCI device. + * @param u16SubSystemId The sub-system id. + */ +DECLINLINE(void) PDMPciDevSetSubSystemId(PPDMPCIDEV pPciDev, uint16_t u16SubSystemId) +{ + PDMPciDevSetWord(pPciDev, VBOX_PCI_SUBSYSTEM_ID, u16SubSystemId); +} + +/** + * Gets the sub-system id config register. + * @returns the sub-system id. + * @param pPciDev The PCI device. + */ +DECLINLINE(uint16_t) PDMPciDevGetSubSystemId(PCPDMPCIDEV pPciDev) +{ + return PDMPciDevGetWord(pPciDev, VBOX_PCI_SUBSYSTEM_ID); +} + +/** + * Sets offset to capability list. + * + * @param pPciDev The PCI device. + * @param u8Offset The offset to capability list. + */ +DECLINLINE(void) PDMPciDevSetCapabilityList(PPDMPCIDEV pPciDev, uint8_t u8Offset) +{ + PDMPciDevSetByte(pPciDev, VBOX_PCI_CAPABILITY_LIST, u8Offset); +} + +/** + * Returns offset to capability list. + * + * @returns offset to capability list. + * @param pPciDev The PCI device. + */ +DECLINLINE(uint8_t) PDMPciDevGetCapabilityList(PCPDMPCIDEV pPciDev) +{ + return PDMPciDevGetByte(pPciDev, VBOX_PCI_CAPABILITY_LIST); +} + +/** + * Sets the interrupt line config register. + * + * @param pPciDev The PCI device. + * @param u8Line The interrupt line. + */ +DECLINLINE(void) PDMPciDevSetInterruptLine(PPDMPCIDEV pPciDev, uint8_t u8Line) +{ + PDMPciDevSetByte(pPciDev, VBOX_PCI_INTERRUPT_LINE, u8Line); +} + +/** + * Gets the interrupt line config register. + * + * @returns The interrupt line. + * @param pPciDev The PCI device. + */ +DECLINLINE(uint8_t) PDMPciDevGetInterruptLine(PCPDMPCIDEV pPciDev) +{ + return PDMPciDevGetByte(pPciDev, VBOX_PCI_INTERRUPT_LINE); +} + +/** + * Sets the interrupt pin config register. + * + * @param pPciDev The PCI device. + * @param u8Pin The interrupt pin. + */ +DECLINLINE(void) PDMPciDevSetInterruptPin(PPDMPCIDEV pPciDev, uint8_t u8Pin) +{ + PDMPciDevSetByte(pPciDev, VBOX_PCI_INTERRUPT_PIN, u8Pin); +} + +/** + * Gets the interrupt pin config register. + * + * @returns The interrupt pin. + * @param pPciDev The PCI device. + */ +DECLINLINE(uint8_t) PDMPciDevGetInterruptPin(PCPDMPCIDEV pPciDev) +{ + return PDMPciDevGetByte(pPciDev, VBOX_PCI_INTERRUPT_PIN); +} + +/** @} */ + +/** @name Aliases for old function names. + * @{ + */ +#if !defined(PDMPCIDEVICE_NO_DEPRECATED) || defined(DOXYGEN_RUNNING) +# define PCIDevSetByte PDMPciDevSetByte +# define PCIDevGetByte PDMPciDevGetByte +# define PCIDevSetWord PDMPciDevSetWord +# define PCIDevGetWord PDMPciDevGetWord +# define PCIDevSetDWord PDMPciDevSetDWord +# define PCIDevGetDWord PDMPciDevGetDWord +# define PCIDevSetQWord PDMPciDevSetQWord +# define PCIDevGetQWord PDMPciDevGetQWord +# define PCIDevSetVendorId PDMPciDevSetVendorId +# define PCIDevGetVendorId PDMPciDevGetVendorId +# define PCIDevSetDeviceId PDMPciDevSetDeviceId +# define PCIDevGetDeviceId PDMPciDevGetDeviceId +# define PCIDevSetCommand PDMPciDevSetCommand +# define PCIDevGetCommand PDMPciDevGetCommand +# define PCIDevIsBusmaster PDMPciDevIsBusmaster +# define PCIDevIsIntxDisabled PDMPciDevIsIntxDisabled +# define PCIDevGetStatus PDMPciDevGetStatus +# define PCIDevSetStatus PDMPciDevSetStatus +# define PCIDevSetRevisionId PDMPciDevSetRevisionId +# define PCIDevSetClassProg PDMPciDevSetClassProg +# define PCIDevSetClassSub PDMPciDevSetClassSub +# define PCIDevSetClassBase PDMPciDevSetClassBase +# define PCIDevSetHeaderType PDMPciDevSetHeaderType +# define PCIDevGetHeaderType PDMPciDevGetHeaderType +# define PCIDevSetBIST PDMPciDevSetBIST +# define PCIDevGetBIST PDMPciDevGetBIST +# define PCIDevSetBaseAddress PDMPciDevSetBaseAddress +# define PCIDevGetRegionReg PDMPciDevGetRegionReg +# define PCIDevSetSubSystemVendorId PDMPciDevSetSubSystemVendorId +# define PCIDevGetSubSystemVendorId PDMPciDevGetSubSystemVendorId +# define PCIDevSetSubSystemId PDMPciDevSetSubSystemId +# define PCIDevGetSubSystemId PDMPciDevGetSubSystemId +# define PCIDevSetCapabilityList PDMPciDevSetCapabilityList +# define PCIDevGetCapabilityList PDMPciDevGetCapabilityList +# define PCIDevSetInterruptLine PDMPciDevSetInterruptLine +# define PCIDevGetInterruptLine PDMPciDevGetInterruptLine +# define PCIDevSetInterruptPin PDMPciDevSetInterruptPin +# define PCIDevGetInterruptPin PDMPciDevGetInterruptPin +#endif +/** @} */ + + +/** @name PDMIICH9BRIDGEPDMPCIDEV_IID - Ugly 3rd party bridge/raw PCI hack. + * + * When querying this IID via IBase::pfnQueryInterface on a ICH9 bridge, you + * will get a pointer to a PDMPCIDEV rather pointer to an interface function + * table as is the custom. This was needed by some unusual 3rd-party raw and/or + * pass-through implementation which need to provide different PCI configuration + * space content for bridges (as long as we don't allow pass-through of bridges + * or custom bridge device implementations). So, HACK ALERT to all of this! + * @{ */ +#define PDMIICH9BRIDGEPDMPCIDEV_IID "785c74b1-8510-4458-9422-56750bf221db" +typedef PPDMPCIDEV PPDMIICH9BRIDGEPDMPCIDEV; +typedef PDMPCIDEV PDMIICH9BRIDGEPDMPCIDEV; +/** @} */ + + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_pdmpcidev_h */ diff --git a/include/VBox/vmm/pdmpcidevint.h b/include/VBox/vmm/pdmpcidevint.h new file mode 100644 index 00000000..b678bf05 --- /dev/null +++ b/include/VBox/vmm/pdmpcidevint.h @@ -0,0 +1,238 @@ +/* $Id: pdmpcidevint.h $ */ +/** @file + * DevPCI - PDM PCI Internal header - Only for hiding bits of PDMPCIDEV. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmpcidevint_h +#define VBOX_INCLUDED_vmm_pdmpcidevint_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/vmm/pdmdev.h> + +/** @defgroup grp_pdm_pcidev_int The PDM PCI Device Internals + * @ingroup grp_pdm_pcidev + * + * @remarks The PDM PCI device internals are visible to both PDM and the PCI Bus + * implementation, thus it lives among the the public headers despite + * being rather private and internal. + * + * @{ + */ + + +/** + * PCI I/O region. + */ +typedef struct PCIIOREGION +{ + /** Current PCI mapping address, INVALID_PCI_ADDRESS (0xffffffff) means not mapped. */ + uint64_t addr; + /** The region size. Power of 2. */ + uint64_t size; + /** Handle or UINT64_MAX (see PDMPCIDEV_IORGN_F_HANDLE_MASK in fFlags). */ + uint64_t hHandle; + /** PDMPCIDEV_IORGN_F_XXXX. */ + uint32_t fFlags; + /** PCIADDRESSSPACE */ + uint8_t type; + uint8_t abPadding0[3]; + /** Callback called when the region is mapped or unmapped (new style devs). */ + R3PTRTYPE(PFNPCIIOREGIONMAP) pfnMap; +#if R3_ARCH_BITS == 32 + uint32_t u32Padding2; +#endif +} PCIIOREGION; +AssertCompileSize(PCIIOREGION, 5*8); +/** Pointer to a PCI I/O region. */ +typedef PCIIOREGION *PPCIIOREGION; +/** Pointer to a const PCI I/O region. */ +typedef PCIIOREGION const *PCPCIIOREGION; + +/** + * Callback function for reading from the PCI configuration space. + * + * @returns Strict VBox status code. + * @param pDevIns Pointer to the device instance of the PCI bus. + * @param iBus The bus number this device is on. + * @param iDevice The number of the device on the bus. + * @param u32Address The configuration space register address. [0..255] + * @param cb The register size. [1,2,4] + * @param pu32Value Where to return the register value. + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNPCIBRIDGECONFIGREAD,(PPDMDEVINSR3 pDevIns, uint8_t iBus, uint8_t iDevice, + uint32_t u32Address, unsigned cb, uint32_t *pu32Value)); +/** Pointer to a FNPCICONFIGREAD() function. */ +typedef FNPCIBRIDGECONFIGREAD *PFNPCIBRIDGECONFIGREAD; +#if !RT_CLANG_PREREQ(11, 0) /* Clang 11 (at least) has trouble with nothrow and pointers to function pointers. */ +/** Pointer to a PFNPCICONFIGREAD. */ +typedef PFNPCIBRIDGECONFIGREAD *PPFNPCIBRIDGECONFIGREAD; +#endif + +/** + * Callback function for writing to the PCI configuration space. + * + * @returns Strict VBox status code. + * @param pDevIns Pointer to the device instance of the PCI bus. + * @param iBus The bus number this device is on. + * @param iDevice The number of the device on the bus. + * @param u32Address The configuration space register address. [0..255] + * @param cb The register size. [1,2,4] + * @param u32Value The value that's being written. The number of bits actually used from + * this value is determined by the cb parameter. + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNPCIBRIDGECONFIGWRITE,(PPDMDEVINSR3 pDevIns, uint8_t iBus, uint8_t iDevice, + uint32_t u32Address, unsigned cb, uint32_t u32Value)); +/** Pointer to a FNPCICONFIGWRITE() function. */ +typedef FNPCIBRIDGECONFIGWRITE *PFNPCIBRIDGECONFIGWRITE; +#if !RT_CLANG_PREREQ(11, 0) /* Clang 11 (at least) has trouble with nothrow and pointers to function pointers. */ +/** Pointer to a PFNPCICONFIGWRITE. */ +typedef PFNPCIBRIDGECONFIGWRITE *PPFNPCIBRIDGECONFIGWRITE; +#endif + +/* Forward declaration */ +struct DEVPCIBUS; + +enum { + /** Flag whether the device is a pci-to-pci bridge. + * This is set prior to device registration. */ + PCIDEV_FLAG_PCI_TO_PCI_BRIDGE = RT_BIT_32(1), + /** Flag whether the device is a PCI Express device. + * This is set prior to device registration. */ + PCIDEV_FLAG_PCI_EXPRESS_DEVICE = RT_BIT_32(2), + /** Flag whether the device is capable of MSI. + * This one is set by MsiInit(). */ + PCIDEV_FLAG_MSI_CAPABLE = RT_BIT_32(3), + /** Flag whether the device is capable of MSI-X. + * This one is set by MsixInit(). */ + PCIDEV_FLAG_MSIX_CAPABLE = RT_BIT_32(4), + /** Flag if device represents real physical device in passthrough mode. */ + PCIDEV_FLAG_PASSTHROUGH = RT_BIT_32(5), + /** Flag whether the device is capable of MSI using 64-bit address. */ + PCIDEV_FLAG_MSI64_CAPABLE = RT_BIT_32(6) + +}; + + +/** + * PDM PCI Device - Internal data. + * + * @sa PDMPCIDEV + */ +typedef struct PDMPCIDEVINT +{ + /** @name Owned by PDM. + * @remarks The bus may use the device instance pointers. + * @{ + */ + /** Pointer to the PDM device the PCI device belongs to. (R3 ptr) */ + PPDMDEVINSR3 pDevInsR3; + /** The CFGM device configuration index (default, PciDev1..255). + * This also works as the internal sub-device ordinal with MMIOEx. + * @note Same value as idxSubDev, can therefore be removed later. */ + uint8_t idxDevCfg; + /** Set if the it can be reassigned to a different PCI device number. */ + bool fReassignableDevNo; + /** Set if the it can be reassigned to a different PCI function number. */ + bool fReassignableFunNo; + /** Alignment padding - used by ICH9 for region swapping (DevVGA hack). */ + uint8_t bPadding0; + /** Index into the PDM internal bus array (PDM::aPciBuses). */ + uint8_t idxPdmBus; + /** Set if this device has been registered. */ + bool fRegistered; + /** Index into PDMDEVINSR3::apPciDevs (same as PDMPCIDEV::idxSubDev). */ + uint16_t idxSubDev; + /** @} */ + + /** @name Owned by the PCI Bus + * @remarks PDM will not touch anything here (includes not relocating anything). + * @{ + */ + /** Pointer to the PCI bus of the device. (R3 ptr) */ + R3PTRTYPE(struct DEVPCIBUS *) pBusR3; + /** Read config callback. */ + R3PTRTYPE(PFNPCICONFIGREAD) pfnConfigRead; + /** Write config callback. */ + R3PTRTYPE(PFNPCICONFIGWRITE) pfnConfigWrite; + /** Read config callback for PCI bridges to pass requests + * to devices on another bus. */ + R3PTRTYPE(PFNPCIBRIDGECONFIGREAD) pfnBridgeConfigRead; + /** Write config callback for PCI bridges to pass requests + * to devices on another bus. */ + R3PTRTYPE(PFNPCIBRIDGECONFIGWRITE) pfnBridgeConfigWrite; + + /** Flags of this PCI device, see PCIDEV_FLAG_XXX constants. */ + uint32_t fFlags; + /** Current state of the IRQ pin of the device. */ + int32_t uIrqPinState; + + /** Offset of MSI PCI capability in config space, or 0. + * @todo fix non-standard naming. */ + uint8_t u8MsiCapOffset; + /** Size of MSI PCI capability in config space, or 0. + * @todo fix non-standard naming. */ + uint8_t u8MsiCapSize; + /** Offset of MSI-X PCI capability in config space, or 0. + * @todo fix non-standard naming. */ + uint8_t u8MsixCapOffset; + /** Size of MSI-X PCI capability in config space, or 0. + * @todo fix non-standard naming. */ + uint8_t u8MsixCapSize; + /** Size of the MSI-X region. */ + uint16_t cbMsixRegion; + /** Offset to the PBA for MSI-X. */ + uint16_t offMsixPba; + /** Add padding to align aIORegions to an 16 byte boundary. */ + uint8_t abPadding2[HC_ARCH_BITS == 32 ? 12 : 8]; + /** The MMIO handle for the MSI-X MMIO bar. */ + IOMMMIOHANDLE hMmioMsix; + + /** Pointer to bus specific data. (R3 ptr) */ + R3PTRTYPE(const void *) pvPciBusPtrR3; + /** I/O regions. */ + PCIIOREGION aIORegions[VBOX_PCI_NUM_REGIONS]; + /** @} */ +} PDMPCIDEVINT; +AssertCompileMemberAlignment(PDMPCIDEVINT, aIORegions, 8); +AssertCompileSize(PDMPCIDEVINT, HC_ARCH_BITS == 32 ? 0x98 : 0x178); + +/** Indicate that PDMPCIDEV::Int.s can be declared. */ +#define PDMPCIDEVINT_DECLARED + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_pdmpcidevint_h */ + diff --git a/include/VBox/vmm/pdmqueue.h b/include/VBox/vmm/pdmqueue.h new file mode 100644 index 00000000..a932ec28 --- /dev/null +++ b/include/VBox/vmm/pdmqueue.h @@ -0,0 +1,169 @@ +/** @file + * PDM - Pluggable Device Manager, Queues. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmqueue_h +#define VBOX_INCLUDED_vmm_pdmqueue_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_queue The PDM Queues API + * @ingroup grp_pdm + * @{ + */ + +/** Pointer to a PDM queue. */ +typedef struct PDMQUEUE *PPDMQUEUE; + +/** Pointer to a PDM queue item core. */ +typedef union PDMQUEUEITEMCORE *PPDMQUEUEITEMCORE; + +/** + * PDM queue item core. + */ +typedef union PDMQUEUEITEMCORE +{ + /** The next queue item on the pending list (UINT32_MAX for NIL). */ + uint32_t volatile iNext; + /** The next item about to be flushed. */ + R3PTRTYPE(PPDMQUEUEITEMCORE) pNext; + /** Make sure the core is 64-bit wide. */ + uint64_t u64View; +} 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. + * @remarks The device critical section will NOT be entered before calling the + * callback. No locks will be held, but for now it's safe to assume + * that only one EMT will do queue callbacks at any one time. + */ +typedef DECLCALLBACKTYPE(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 pUsbIns The USB device instance. + * @param pItem The item to consume. Upon return this item will be freed. + * @remarks No locks will be held, but for now it's safe to assume that only one + * EMT will do queue callbacks at any one time. + */ +typedef DECLCALLBACKTYPE(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. + * @remarks No locks will be held, but for now it's safe to assume that only one + * EMT will do queue callbacks at any one time. + */ +typedef DECLCALLBACKTYPE(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 cross context VM structure. + * @param pItem The item to consume. Upon return this item will be freed. + * @remarks No locks will be held, but for now it's safe to assume that only one + * EMT will do queue callbacks at any one time. + */ +typedef DECLCALLBACKTYPE(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. + * @remarks No locks will be held, but for now it's safe to assume that only one + * EMT will do queue callbacks at any one time. + */ +typedef DECLCALLBACKTYPE(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, PDMQUEUEHANDLE *phQueue); +VMMR3_INT_DECL(int) PDMR3QueueCreateDriver(PVM pVM, PPDMDRVINS pDrvIns, size_t cbItem, uint32_t cItems, + uint32_t cMilliesInterval, PFNPDMQUEUEDRV pfnCallback, + const char *pszName, PDMQUEUEHANDLE *phQueue); +VMMR3_INT_DECL(int) PDMR3QueueCreateInternal(PVM pVM, size_t cbItem, uint32_t cItems, + uint32_t cMilliesInterval, PFNPDMQUEUEINT pfnCallback, + bool fRZEnabled, const char *pszName, PDMQUEUEHANDLE *phQueue); +VMMR3DECL(int) PDMR3QueueCreateExternal(PVM pVM, size_t cbItem, uint32_t cItems, uint32_t cMilliesInterval, + PFNPDMQUEUEEXT pfnCallback, void *pvUser, const char *pszName, PDMQUEUEHANDLE *phQueue); +VMMR3DECL(int) PDMR3QueueDestroy(PVM pVM, PDMQUEUEHANDLE hQueue, void *pvOwner); +VMMR3_INT_DECL(int) PDMR3QueueDestroyDevice(PVM pVM, PPDMDEVINS pDevIns); +VMMR3_INT_DECL(int) PDMR3QueueDestroyDriver(PVM pVM, PPDMDRVINS pDrvIns); +VMMR3DECL(void) PDMR3QueueFlushAll(PVM pVM); +#endif /* VBOX_IN_VMM */ + +VMMDECL(PPDMQUEUEITEMCORE) PDMQueueAlloc(PVMCC pVM, PDMQUEUEHANDLE hQueue, void *pvOwner); +VMMDECL(int) PDMQueueInsert(PVMCC pVM, PDMQUEUEHANDLE hQueue, void *pvOwner, PPDMQUEUEITEMCORE pInsert); +VMMDECL(int) PDMQueueFlushIfNecessary(PVMCC pVM, PDMQUEUEHANDLE hQueue, void *pvOwner); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmqueue_h */ + diff --git a/include/VBox/vmm/pdmserialifs.h b/include/VBox/vmm/pdmserialifs.h new file mode 100644 index 00000000..3917e0e5 --- /dev/null +++ b/include/VBox/vmm/pdmserialifs.h @@ -0,0 +1,249 @@ +/** @file + * PDM - Pluggable Device Manager, Serial port related interfaces. + */ + +/* + * Copyright (C) 2018-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmserialifs_h +#define VBOX_INCLUDED_vmm_pdmserialifs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_ifs_serial PDM Serial Port Interfaces + * @ingroup grp_pdm_interfaces + * @{ + */ + + +/** @name Bit mask definitions for status line type. + * @{ */ +#define PDMISERIALPORT_STS_LINE_DCD RT_BIT(0) +#define PDMISERIALPORT_STS_LINE_RI RT_BIT(1) +#define PDMISERIALPORT_STS_LINE_DSR RT_BIT(2) +#define PDMISERIALPORT_STS_LINE_CTS RT_BIT(3) +/** @} */ + +/** Pointer to a serial port interface. */ +typedef struct PDMISERIALPORT *PPDMISERIALPORT; +/** + * Serial port interface (down). + */ +typedef struct PDMISERIALPORT +{ + /** + * Notifies the upper device/driver that data is available for reading. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param cbAvail The amount of data available to be written. + */ + DECLR3CALLBACKMEMBER(int, pfnDataAvailRdrNotify, (PPDMISERIALPORT pInterface, size_t cbAvail)); + + /** + * Notifies the upper device/driver that all data was sent. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + */ + DECLR3CALLBACKMEMBER(int, pfnDataSentNotify, (PPDMISERIALPORT pInterface)); + + /** + * Try to read data from the device/driver above for writing. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pvBuf Where to store the read data. + * @param cbRead How much to read. + * @param pcbRead Where to store the amount of data actually read on success. + */ + DECLR3CALLBACKMEMBER(int, pfnReadWr, (PPDMISERIALPORT pInterface, void *pvBuf, size_t cbRead, 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 fNewStatusLines New state of the status line pins. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnNotifyStsLinesChanged, (PPDMISERIALPORT pInterface, uint32_t fNewStatusLines)); + + /** + * Notify the device/driver that a break condition occurred. + * + * @returns VBox statsus code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnNotifyBrk, (PPDMISERIALPORT pInterface)); + +} PDMISERIALPORT; +/** PDMISERIALPORT interface ID. */ +#define PDMISERIALPORT_IID "44540323-06ca-44c1-8eb2-f5a387704dbd" + + +/** + * Supported parity modes. + */ +typedef enum PDMSERIALPARITY +{ + /** Invalid parity setting. */ + PDMSERIALPARITY_INVALID = 0, + /** No parity. */ + PDMSERIALPARITY_NONE, + /** Even parity. */ + PDMSERIALPARITY_EVEN, + /** Odd parity. */ + PDMSERIALPARITY_ODD, + /** Mark parity. */ + PDMSERIALPARITY_MARK, + /** Space parity. */ + PDMSERIALPARITY_SPACE, + /** 32bit hack. */ + PDMSERIALPARITY_32BIT_HACK = 0x7fffffff +} PDMSERIALPARITY; + + +/** + * Supported number of stop bits. + */ +typedef enum PDMSERIALSTOPBITS +{ + /** Invalid stop bits setting. */ + PDMSERIALSTOPBITS_INVALID = 0, + /** One stop bit is used. */ + PDMSERIALSTOPBITS_ONE, + /** 1.5 stop bits are used. */ + PDMSERIALSTOPBITS_ONEPOINTFIVE, + /** 2 stop bits are used. */ + PDMSERIALSTOPBITS_TWO, + /** 32bit hack. */ + PDMSERIALSTOPBITS_32BIT_HACK = 0x7fffffff +} PDMSERIALSTOPBITS; + + +/** Pointer to a serial interface. */ +typedef struct PDMISERIALCONNECTOR *PPDMISERIALCONNECTOR; +/** + * Serial interface (up). + * Pairs with PDMISERIALPORT. + */ +typedef struct PDMISERIALCONNECTOR +{ + /** + * Notifies the lower layer that data is available for writing. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + */ + DECLR3CALLBACKMEMBER(int, pfnDataAvailWrNotify, (PPDMISERIALCONNECTOR pInterface)); + + /** + * Try to read data from the underyling driver. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pvBuf Where to store the read data. + * @param cbRead How much to read. + * @param pcbRead Where to store the amount of data actually read on success. + */ + DECLR3CALLBACKMEMBER(int, pfnReadRdr, (PPDMISERIALCONNECTOR pInterface, void *pvBuf, size_t cbRead, size_t *pcbRead)); + + /** + * Change device parameters. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param uBps Speed of the serial connection. (bits per second) + * @param enmParity Parity method. + * @param cDataBits Number of data bits. + * @param enmStopBits Number of stop bits. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnChgParams, (PPDMISERIALCONNECTOR pInterface, uint32_t uBps, + PDMSERIALPARITY enmParity, unsigned cDataBits, + PDMSERIALSTOPBITS enmStopBits)); + + /** + * Set the state of the modem lines. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param fRts Set to true to make the Request to Send line active otherwise to 0. + * @param fDtr Set to true to make the Data Terminal Ready line active otherwise 0. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnChgModemLines, (PPDMISERIALCONNECTOR pInterface, bool fRts, bool fDtr)); + + /** + * Changes the TD line into the requested break condition. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param fBrk Set to true to let the device send a break false to put into normal operation. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnChgBrk, (PPDMISERIALCONNECTOR pInterface, bool fBrk)); + + /** + * Queries the current state of the status lines. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pfStsLines Where to store the status line states on success. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryStsLines, (PPDMISERIALCONNECTOR pInterface, uint32_t *pfStsLines)); + + /** + * Flushes the indicated queues. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param fQueueRecv Flag whether to flush the receive queue. + * @param fQueueXmit Flag whether to flush the transmit queue. + */ + DECLR3CALLBACKMEMBER(int, pfnQueuesFlush, (PPDMISERIALCONNECTOR pInterface, bool fQueueRecv, bool fQueueXmit)); + +} PDMISERIALCONNECTOR; +/** PDMIMEDIA interface ID. */ +#define PDMISERIALCONNECTOR_IID "d024f170-c00d-11e8-b568-0800200c9a66" + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmserialifs_h */ diff --git a/include/VBox/vmm/pdmsrv.h b/include/VBox/vmm/pdmsrv.h new file mode 100644 index 00000000..e0b3f7ce --- /dev/null +++ b/include/VBox/vmm/pdmsrv.h @@ -0,0 +1,350 @@ +/** @file + * PDM - Pluggable Device Manager, VM Services. + * + * @todo This has not been implemented, consider dropping the concept. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmsrv_h +#define VBOX_INCLUDED_vmm_pdmsrv_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#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 DECLCALLBACKTYPE(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 DECLCALLBACKTYPE(void, FNPDMSRVDESTRUCT,(PPDMSRVINS pSrvIns)); +/** Pointer to a FNPDMSRVDESTRUCT() function. */ +typedef FNPDMSRVDESTRUCT *PFNPDMSRVDESTRUCT; + +/** + * Power On notification. + * + * @param pSrvIns The service instance data. + */ +typedef DECLCALLBACKTYPE(void, FNPDMSRVPOWERON,(PPDMSRVINS pSrvIns)); +/** Pointer to a FNPDMSRVPOWERON() function. */ +typedef FNPDMSRVPOWERON *PFNPDMSRVPOWERON; + +/** + * Reset notification. + * + * @returns VBox status. + * @param pSrvIns The service instance data. + */ +typedef DECLCALLBACKTYPE(void, FNPDMSRVRESET,(PPDMSRVINS pSrvIns)); +/** Pointer to a FNPDMSRVRESET() function. */ +typedef FNPDMSRVRESET *PFNPDMSRVRESET; + +/** + * Suspend notification. + * + * @returns VBox status. + * @param pSrvIns The service instance data. + */ +typedef DECLCALLBACKTYPE(void, FNPDMSRVSUSPEND,(PPDMSRVINS pSrvIns)); +/** Pointer to a FNPDMSRVSUSPEND() function. */ +typedef FNPDMSRVSUSPEND *PFNPDMSRVSUSPEND; + +/** + * Resume notification. + * + * @returns VBox status. + * @param pSrvIns The service instance data. + */ +typedef DECLCALLBACKTYPE(void, FNPDMSRVRESUME,(PPDMSRVINS pSrvIns)); +/** Pointer to a FNPDMSRVRESUME() function. */ +typedef FNPDMSRVRESUME *PFNPDMSRVRESUME; + +/** + * Power Off notification. + * + * @param pSrvIns The service instance data. + */ +typedef DECLCALLBACKTYPE(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. + * @param pDevIns The device instance to detach. + * @param pDrvIns The driver instance to detach. + */ +typedef DECLCALLBACKTYPE(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 cross context VM structure. + * @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_UOFFSETOF(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 DECLCALLBACKTYPE(int, FNPDMVBOXSERVICESREGISTER,(PPDMSRVREGCB pCallbacks, uint32_t u32Version)); + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmsrv_h */ diff --git a/include/VBox/vmm/pdmstorageifs.h b/include/VBox/vmm/pdmstorageifs.h new file mode 100644 index 00000000..2aeeed99 --- /dev/null +++ b/include/VBox/vmm/pdmstorageifs.h @@ -0,0 +1,1059 @@ +/** @file + * PDM - Pluggable Device Manager, Storage related interfaces. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmstorageifs_h +#define VBOX_INCLUDED_vmm_pdmstorageifs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/sg.h> +#include <VBox/types.h> +#include <VBox/vdmedia.h> + +RT_C_DECLS_BEGIN + +struct PDMISECKEY; +struct PDMISECKEYHLP; + + +/** @defgroup grp_pdm_ifs_storage PDM Storage Interfaces + * @ingroup grp_pdm_interfaces + * @{ + */ + + +/** 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 +{ + /** + * 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" + + +/** + * Callback which provides progress information. + * + * @return VBox status code. + * @param pvUser Opaque user data. + * @param uPercentage Completion percentage. + */ +typedef DECLCALLBACKTYPE(int, FNSIMPLEPROGRESS,(void *pvUser, unsigned uPercentage)); +/** Pointer to FNSIMPLEPROGRESS() */ +typedef FNSIMPLEPROGRESS *PFNSIMPLEPROGRESS; + + +/** + * Media type. + */ +typedef enum PDMMEDIATYPE +{ + /** Error (for the query function). */ + PDMMEDIATYPE_ERROR = 1, + /** 360KB 5 1/4" floppy drive. */ + PDMMEDIATYPE_FLOPPY_360, + /** 720KB 3 1/2" floppy drive. */ + PDMMEDIATYPE_FLOPPY_720, + /** 1.2MB 5 1/4" floppy drive. */ + PDMMEDIATYPE_FLOPPY_1_20, + /** 1.44MB 3 1/2" floppy drive. */ + PDMMEDIATYPE_FLOPPY_1_44, + /** 2.88MB 3 1/2" floppy drive. */ + PDMMEDIATYPE_FLOPPY_2_88, + /** Fake drive that can take up to 15.6 MB images. + * C=255, H=2, S=63. */ + PDMMEDIATYPE_FLOPPY_FAKE_15_6, + /** Fake drive that can take up to 63.5 MB images. + * C=255, H=2, S=255. */ + PDMMEDIATYPE_FLOPPY_FAKE_63_5, + /** CDROM drive. */ + PDMMEDIATYPE_CDROM, + /** DVD drive. */ + PDMMEDIATYPE_DVD, + /** Hard disk drive. */ + PDMMEDIATYPE_HARD_DISK +} PDMMEDIATYPE; + +/** Check if the given block type is a floppy. */ +#define PDMMEDIATYPE_IS_FLOPPY(a_enmType) ( (a_enmType) >= PDMMEDIATYPE_FLOPPY_360 && (a_enmType) <= PDMMEDIATYPE_FLOPPY_2_88 ) + +/** + * Raw command data transfer direction. + */ +typedef enum PDMMEDIATXDIR +{ + PDMMEDIATXDIR_NONE = 0, + PDMMEDIATXDIR_FROM_DEVICE, + PDMMEDIATXDIR_TO_DEVICE +} PDMMEDIATXDIR; + +/** + * 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)); + + + /** + * Queries the vendor and product ID and revision to report for INQUIRY commands in underlying devices, optional. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param ppszVendorId Where to store the pointer to the vendor ID string to report. + * @param ppszProductId Where to store the pointer to the product ID string to report. + * @param ppszRevision Where to store the pointer to the revision string to report. + * + * @note The strings for the inquiry data are stored in the storage controller rather than in the device + * because if device attachments change (virtual CD/DVD drive versus host drive) there is currently no + * way to keep the INQUIRY data in extradata keys without causing trouble when the attachment is changed. + * Also Main currently doesn't has any settings for the attachment to store such information in the settings + * properly. Last reason (but not the most important one) is to stay compatible with older versions + * where the drive emulation was in AHCI but it now uses VSCSI and the settings overwrite should still work. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryScsiInqStrings, (PPDMIMEDIAPORT pInterface, const char **ppszVendorId, + const char **ppszProductId, const char **ppszRevision)); + +} PDMIMEDIAPORT; +/** PDMIMEDIAPORT interface ID. */ +#define PDMIMEDIAPORT_IID "77180ab8-6485-454f-b440-efca322b7bd7" + +/** Pointer to a media interface. */ +typedef struct PDMIMEDIA *PPDMIMEDIA; +/** + * Media interface (up). + * 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)); + + /** + * Read bits - version for DevPcBios. + * + * @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. + * + * @note: Special version of pfnRead which doesn't try to suspend the VM when the DEKs for encrypted disks + * are missing but just returns an error. + */ + DECLR3CALLBACKMEMBER(int, pfnReadPcBios,(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)); + + /** + * 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 pbCdb The command to process. + * @param cbCdb The length of the command in bytes. + * @param enmTxDir Direction of transfer. + * @param pvBuf Pointer tp the transfer buffer. + * @param pcbBuf Size of the transfer buffer. + * @param pabSense Status of the command (when return value is VERR_DEV_IO_ERROR). + * @param cbSense Size of the sense buffer in bytes. + * @param cTimeoutMillies Command timeout in milliseconds. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnSendCmd,(PPDMIMEDIA pInterface, const uint8_t *pbCdb, size_t cbCdb, + PDMMEDIATXDIR enmTxDir, void *pvBuf, uint32_t *pcbBuf, + uint8_t *pabSense, size_t cbSense, uint32_t cTimeoutMillies)); + + /** + * 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)); + + /** + * Sets the secret key retrieval interface to use to get secret keys. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pIfSecKey The secret key interface to use. + * Use NULL to clear the currently set interface and clear all secret + * keys from the user. + * @param pIfSecKeyHlp The secret key helper interface to use. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnSetSecKeyIf,(PPDMIMEDIA pInterface, struct PDMISECKEY *pIfSecKey, + struct PDMISECKEYHLP *pIfSecKeyHlp)); + + /** + * 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)); + + /** + * Gets the media sector size in bytes. + * + * @returns Media sector size in bytes. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnGetSectorSize,(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)); + + /** + * Returns whether the medium should be marked as rotational or not. + * + * @returns true if non rotating medium. + * @returns false if rotating medium. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(bool, pfnIsNonRotational,(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)); + + /** + * 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, pfnBiosIsVisible,(PPDMIMEDIA pInterface)); + + /** + * Gets the media type. + * + * @returns media type. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(PDMMEDIATYPE, pfnGetType,(PPDMIMEDIA pInterface)); + + /** + * 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)); + + /** + * Returns the number of regions for the medium. + * + * @returns Number of regions. + * @param pInterface Pointer to the interface structure containing the called function pointer. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnGetRegionCount,(PPDMIMEDIA pInterface)); + + /** + * Queries the properties for the given region. + * + * @returns VBox status code. + * @retval VERR_NOT_FOUND if the region index is not known. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param uRegion The region index to query the properties of. + * @param pu64LbaStart Where to store the starting LBA for the region on success. + * @param pcBlocks Where to store the number of blocks for the region on success. + * @param pcbBlock Where to store the size of one block in bytes on success. + * @param penmDataForm WHere to store the data form for the region on success. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryRegionProperties,(PPDMIMEDIA pInterface, uint32_t uRegion, uint64_t *pu64LbaStart, + uint64_t *pcBlocks, uint64_t *pcbBlock, + PVDREGIONDATAFORM penmDataForm)); + + /** + * Queries the properties for the region covering the given LBA. + * + * @returns VBox status code. + * @retval VERR_NOT_FOUND if the region index is not known. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param u64LbaStart Where to store the starting LBA for the region on success. + * @param puRegion Where to store the region number on success. + * @param pcBlocks Where to store the number of blocks left in this region starting from the given LBA. + * @param pcbBlock Where to store the size of one block in bytes on success. + * @param penmDataForm WHere to store the data form for the region on success. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryRegionPropertiesForLba,(PPDMIMEDIA pInterface, uint64_t u64LbaStart, + uint32_t *puRegion, uint64_t *pcBlocks, + uint64_t *pcbBlock, PVDREGIONDATAFORM penmDataForm)); + +} PDMIMEDIA; +/** PDMIMEDIA interface ID. */ +#define PDMIMEDIA_IID "8ec68c48-dd20-4430-8386-f0d628a5aca6" + + +/** + * Opaque I/O request handle. + * + * The specific content depends on the driver implementing this interface. + */ +typedef struct PDMMEDIAEXIOREQINT *PDMMEDIAEXIOREQ; +/** Pointer to an I/O request handle. */ +typedef PDMMEDIAEXIOREQ *PPDMMEDIAEXIOREQ; +/** NIL I/O request handle. */ +#define NIL_PDMMEDIAEXIOREQ ((PDMMEDIAEXIOREQ)0) + +/** A I/O request ID. */ +typedef uint64_t PDMMEDIAEXIOREQID; + +/** + * I/O Request Type. + */ +typedef enum PDMMEDIAEXIOREQTYPE +{ + /** Invalid tpe. */ + PDMMEDIAEXIOREQTYPE_INVALID = 0, + /** Flush request. */ + PDMMEDIAEXIOREQTYPE_FLUSH, + /** Write request. */ + PDMMEDIAEXIOREQTYPE_WRITE, + /** Read request. */ + PDMMEDIAEXIOREQTYPE_READ, + /** Discard request. */ + PDMMEDIAEXIOREQTYPE_DISCARD, + /** SCSI command. */ + PDMMEDIAEXIOREQTYPE_SCSI +} PDMMEDIAEXIOREQTYPE; +/** Pointer to a I/O request type. */ +typedef PDMMEDIAEXIOREQTYPE *PPDMMEDIAEXIOREQTYPE; + +/** + * Data direction for raw SCSI commands. + */ +typedef enum PDMMEDIAEXIOREQSCSITXDIR +{ + /** Invalid data direction. */ + PDMMEDIAEXIOREQSCSITXDIR_INVALID = 0, + /** Direction is unknown. */ + PDMMEDIAEXIOREQSCSITXDIR_UNKNOWN, + /** Direction is from device to host. */ + PDMMEDIAEXIOREQSCSITXDIR_FROM_DEVICE, + /** Direction is from host to device. */ + PDMMEDIAEXIOREQSCSITXDIR_TO_DEVICE, + /** No data transfer associated with this request. */ + PDMMEDIAEXIOREQSCSITXDIR_NONE, + /** 32bit hack. */ + PDMMEDIAEXIOREQSCSITXDIR_32BIT_HACK = 0x7fffffff +} PDMMEDIAEXIOREQSCSITXDIR; + +/** + * I/O request state. + */ +typedef enum PDMMEDIAEXIOREQSTATE +{ + /** Invalid state. */ + PDMMEDIAEXIOREQSTATE_INVALID = 0, + /** The request is active and being processed. */ + PDMMEDIAEXIOREQSTATE_ACTIVE, + /** The request is suspended due to an error and no processing will take place. */ + PDMMEDIAEXIOREQSTATE_SUSPENDED, + /** 32bit hack. */ + PDMMEDIAEXIOREQSTATE_32BIT_HACK = 0x7fffffff +} PDMMEDIAEXIOREQSTATE; +/** Pointer to a I/O request state. */ +typedef PDMMEDIAEXIOREQSTATE *PPDMMEDIAEXIOREQSTATE; + +/** @name Supported feature flags + * @{ */ +/** I/O requests will execute asynchronously by default. */ +#define PDMIMEDIAEX_FEATURE_F_ASYNC RT_BIT_32(0) +/** The discard request is supported. */ +#define PDMIMEDIAEX_FEATURE_F_DISCARD RT_BIT_32(1) +/** The send raw SCSI command request is supported. */ +#define PDMIMEDIAEX_FEATURE_F_RAWSCSICMD RT_BIT_32(2) +/** Mask of valid flags. */ +#define PDMIMEDIAEX_FEATURE_F_VALID (PDMIMEDIAEX_FEATURE_F_ASYNC | PDMIMEDIAEX_FEATURE_F_DISCARD | PDMIMEDIAEX_FEATURE_F_RAWSCSICMD) +/** @} */ + +/** @name I/O request specific flags + * @{ */ +/** Default behavior (async I/O).*/ +#define PDMIMEDIAEX_F_DEFAULT (0) +/** The I/O request will be executed synchronously. */ +#define PDMIMEDIAEX_F_SYNC RT_BIT_32(0) +/** Whether to suspend the VM on a recoverable error with + * an appropriate error message (disk full, etc.). + * The request will be retried by the driver implementing the interface + * when the VM resumes the next time. However before suspending the request + * the owner of the request will be notified using the PDMMEDIAEXPORT::pfnIoReqStateChanged. + * The same goes for resuming the request after the VM was resumed. + */ +#define PDMIMEDIAEX_F_SUSPEND_ON_RECOVERABLE_ERR RT_BIT_32(1) + /** Mask of valid flags. */ +#define PDMIMEDIAEX_F_VALID (PDMIMEDIAEX_F_SYNC | PDMIMEDIAEX_F_SUSPEND_ON_RECOVERABLE_ERR) +/** @} */ + +/** Pointer to an extended media notification interface. */ +typedef struct PDMIMEDIAEXPORT *PPDMIMEDIAEXPORT; + +/** + * Asynchronous version of the media interface (up). + * Pair with PDMIMEDIAEXPORT. + */ +typedef struct PDMIMEDIAEXPORT +{ + /** + * Notify completion of a I/O request. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The I/O request handle. + * @param pvIoReqAlloc The allocator specific memory for this request. + * @param rcReq IPRT Status code of the completed request. + * VERR_PDM_MEDIAEX_IOREQ_CANCELED if the request was canceled by a call to + * PDMIMEDIAEX::pfnIoReqCancel. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqCompleteNotify, (PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq, + void *pvIoReqAlloc, int rcReq)); + + /** + * Copy data from the memory buffer of the caller to the callees memory buffer for the given request. + * + * @returns VBox status code. + * @retval VERR_PDM_MEDIAEX_IOBUF_OVERFLOW if there is not enough room to store the data. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The I/O request handle. + * @param pvIoReqAlloc The allocator specific memory for this request. + * @param offDst The destination offset from the start to write the data to. + * @param pSgBuf The S/G buffer to read the data from. + * @param cbCopy How many bytes to copy. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqCopyFromBuf, (PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq, + void *pvIoReqAlloc, uint32_t offDst, PRTSGBUF pSgBuf, + size_t cbCopy)); + + /** + * Copy data to the memory buffer of the caller from the callees memory buffer for the given request. + * + * @returns VBox status code. + * @retval VERR_PDM_MEDIAEX_IOBUF_UNDERRUN if there is not enough data to copy from the buffer. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The I/O request handle. + * @param pvIoReqAlloc The allocator specific memory for this request. + * @param offSrc The offset from the start of the buffer to read the data from. + * @param pSgBuf The S/G buffer to write the data to. + * @param cbCopy How many bytes to copy. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqCopyToBuf, (PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq, + void *pvIoReqAlloc, uint32_t offSrc, PRTSGBUF pSgBuf, + size_t cbCopy)); + + /** + * Queries a pointer to the memory buffer for the request from the drive/device above. + * + * @returns VBox status code. + * @retval VERR_NOT_SUPPORTED if this is not supported for this request. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The I/O request handle. + * @param pvIoReqAlloc The allocator specific memory for this request. + * @param ppvBuf Where to store the pointer to the guest buffer on success. + * @param pcbBuf Where to store the size of the buffer on success. + * + * @note This is an optional feature of the entity implementing this interface to avoid overhead + * by copying the data between buffers. If NULL it is not supported at all and the caller + * has to resort to PDMIMEDIAEXPORT::pfnIoReqCopyToBuf and PDMIMEDIAEXPORT::pfnIoReqCopyFromBuf. + * The same holds when VERR_NOT_SUPPORTED is returned. + * + * On the upside the caller of this interface might not call this method at all and just + * use the before mentioned methods to copy the data between the buffers. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqQueryBuf, (PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq, + void *pvIoReqAlloc, void **ppvBuf, size_t *pcbBuf)); + + /** + * Queries the specified amount of ranges to discard from the callee for the given I/O request. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The I/O request handle. + * @param pvIoReqAlloc The allocator specific memory for this request. + * @param idxRangeStart The range index to start with. + * @param cRanges How man ranges can be stored in the provided array. + * @param paRanges Where to store the ranges on success. + * @param *pcRanges Where to store the number of ranges copied over on success. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqQueryDiscardRanges, (PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq, + void *pvIoReqAlloc, uint32_t idxRangeStart, + uint32_t cRanges, PRTRANGE paRanges, + uint32_t *pcRanges)); + + /** + * Notify the request owner about a state change for the request. + * + * @returns nothing. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The I/O request handle. + * @param pvIoReqAlloc The allocator specific memory for this request. + * @param enmState The new state of the request. + */ + DECLR3CALLBACKMEMBER(void, pfnIoReqStateChanged, (PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq, + void *pvIoReqAlloc, PDMMEDIAEXIOREQSTATE enmState)); + + /** + * Informs the device that the underlying medium was ejected. + * + * @returns nothing. + * @param pInterface Pointer to the interface structure containing the called function pointer. + */ + DECLR3CALLBACKMEMBER(void, pfnMediumEjected, (PPDMIMEDIAEXPORT pInterface)); + +} PDMIMEDIAEXPORT; + +/** PDMIMEDIAAEXPORT interface ID. */ +#define PDMIMEDIAEXPORT_IID "0ae2e534-6c28-41d6-9a88-7f88f2cb2ff8" + + +/** Pointer to an extended media interface. */ +typedef struct PDMIMEDIAEX *PPDMIMEDIAEX; + +/** + * Extended version of PDMIMEDIA (down). + * Pair with PDMIMEDIAEXPORT. + */ +typedef struct PDMIMEDIAEX +{ + /** + * Queries the features supported by the entity implementing this interface. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pfFeatures Where to store the supported feature flags on success. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryFeatures, (PPDMIMEDIAEX pInterface, uint32_t *pfFeatures)); + + /** + * Notifies the driver below that the device received a suspend notification. + * + * @returns nothing. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * + * @note this is required because the PDM drivers in the storage area usually get their suspend notification + * only after the device finished suspending. For some cases it is useful for the driver to know + * as early as possible that a suspend is in progress to stop issuing deferred requests or other things. + */ + DECLR3CALLBACKMEMBER(void, pfnNotifySuspend, (PPDMIMEDIAEX pInterface)); + + /** + * Sets the size of the allocator specific memory for a I/O request. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param cbIoReqAlloc The size of the allocator specific memory in bytes. + * @thread EMT. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqAllocSizeSet, (PPDMIMEDIAEX pInterface, size_t cbIoReqAlloc)); + + /** + * Allocates a new I/O request. + * + * @returns VBox status code. + * @retval VERR_PDM_MEDIAEX_IOREQID_CONFLICT if the ID belongs to a still active request. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param phIoReq Where to store the handle to the new I/O request on success. + * @param ppvIoReqAlloc Where to store the pointer to the allocator specific memory on success. + * NULL if the memory size was not set or set to 0. + * @param uIoReqId A custom request ID which can be used to cancel the request. + * @param fFlags A combination of PDMIMEDIAEX_F_* flags. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqAlloc, (PPDMIMEDIAEX pInterface, PPDMMEDIAEXIOREQ phIoReq, void **ppvIoReqAlloc, + PDMMEDIAEXIOREQID uIoReqId, uint32_t fFlags)); + + /** + * Frees a given I/O request. + * + * @returns VBox status code. + * @retval VERR_PDM_MEDIAEX_IOREQ_INVALID_STATE if the given request is still active. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The I/O request to free. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqFree, (PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq)); + + /** + * Queries the residual amount of data not transfered when the request completed. + * + * @returns VBox status code. + * @retval VERR_PDM_MEDIAEX_IOREQ_INVALID_STATE has not completed yet. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The I/O request. + * @param pcbResidual Where to store the amount of resdiual data in bytes. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqQueryResidual, (PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, size_t *pcbResidual)); + + /** + * Queries the residual amount of data not transfered when the request completed. + * + * @returns VBox status code. + * @retval VERR_PDM_MEDIAEX_IOREQ_INVALID_STATE has not completed yet. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The I/O request. + * @param pcbXfer Where to store the amount of resdiual data in bytes. + * @thread Any thread. + * + * @note For simple read/write requests this returns the amount to read/write as given to the + * PDMIMEDIAEX::pfnIoReqRead or PDMIMEDIAEX::pfnIoReqWrite call. + * For SCSI commands this returns the transfer size as given in the provided CDB. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqQueryXferSize, (PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, size_t *pcbXfer)); + + /** + * Cancels all I/O active requests. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqCancelAll, (PPDMIMEDIAEX pInterface)); + + /** + * Cancels a I/O request identified by the ID. + * + * @returns VBox status code. + * @retval VERR_PDM_MEDIAEX_IOREQID_NOT_FOUND if the given ID could not be found in the active request list. + * (The request has either completed already or an invalid ID was given). + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param uIoReqId The I/O request ID + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqCancel, (PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQID uIoReqId)); + + /** + * Start a reading request. + * + * @returns VBox status code. + * @retval VERR_PDM_MEDIAEX_IOREQ_CANCELED if the request was canceled by a call to + * PDMIMEDIAEX::pfnIoReqCancel. + * @retval VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS if the request was successfully submitted but is still in progress. + * Completion will be notified through PDMIMEDIAEXPORT::pfnIoReqCompleteNotify with the appropriate status code. + * @retval VINF_SUCCESS if the request completed successfully. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The I/O request to associate the read with. + * @param off Offset to start reading from. Must be aligned to a sector boundary. + * @param cbRead Number of bytes to read. Must be aligned to a sector boundary. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqRead, (PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, uint64_t off, size_t cbRead)); + + /** + * Start a writing request. + * + * @returns VBox status code. + * @retval VERR_PDM_MEDIAEX_IOREQ_CANCELED if the request was canceled by a call to + * PDMIMEDIAEX::pfnIoReqCancel. + * @retval VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS if the request was successfully submitted but is still in progress. + * Completion will be notified through PDMIMEDIAEXPORT::pfnIoReqCompleteNotify with the appropriate status code. + * @retval VINF_SUCCESS if the request completed successfully. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The I/O request to associate the write with. + * @param off Offset to start reading from. Must be aligned to a sector boundary. + * @param cbWrite Number of bytes to write. Must be aligned to a sector boundary. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqWrite, (PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, uint64_t off, size_t cbWrite)); + + /** + * Flush everything to disk. + * + * @returns VBox status code. + * @retval VERR_PDM_MEDIAEX_IOREQ_CANCELED if the request was canceled by a call to + * PDMIMEDIAEX::pfnIoReqCancel. + * @retval VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS if the request was successfully submitted but is still in progress. + * Completion will be notified through PDMIMEDIAEXPORT::pfnIoReqCompleteNotify with the appropriate status code. + * @retval VINF_SUCCESS if the request completed successfully. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The I/O request to associate the flush with. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqFlush, (PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq)); + + /** + * Discards the given range. + * + * @returns VBox status code. + * @retval VERR_PDM_MEDIAEX_IOREQ_CANCELED if the request was canceled by a call to + * PDMIMEDIAEX::pfnIoReqCancel. + * @retval VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS if the request was successfully submitted but is still in progress. + * Completion will be notified through PDMIMEDIAEXPORT::pfnIoReqCompleteNotify with the appropriate status code. + * @retval VINF_SUCCESS if the request completed successfully. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The I/O request to associate the discard with. + * @param cRangesMax The maximum number of ranges this request has associated, this must not be accurate + * but can actually be bigger than the amount of ranges actually available. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqDiscard, (PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, unsigned cRangesMax)); + + /** + * Send a raw command to the underlying device (CDROM). + * + * @returns VBox status code. + * @retval VERR_PDM_MEDIAEX_IOREQ_CANCELED if the request was canceled by a call to + * PDMIMEDIAEX::pfnIoReqCancel. + * @retval VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS if the request was successfully submitted but is still in progress. + * Completion will be notified through PDMIMEDIAEXPORT::pfnIoReqCompleteNotify with the appropriate status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The I/O request to associate the command with. + * @param uLun The LUN the command is for. + * @param pbCdb The SCSI CDB containing the command. + * @param cbCdb Size of the CDB in bytes. + * @param enmTxDir Direction of transfer. + * @param penmTxDirRet Where to store the transfer direction as parsed from the CDB, optional. + * @param cbBuf Size of the transfer buffer. + * @param pabSense Where to store the optional sense key. + * @param cbSense Size of the sense key buffer. + * @param pcbSenseRet Where to store the amount of sense data written, optional. + * @param pu8ScsiSts Where to store the SCSI status on success. + * @param cTimeoutMillies Command timeout in milliseconds. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqSendScsiCmd,(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, + uint32_t uLun, const uint8_t *pbCdb, size_t cbCdb, + PDMMEDIAEXIOREQSCSITXDIR enmTxDir, PDMMEDIAEXIOREQSCSITXDIR *penmTxDirRet, + size_t cbBuf, uint8_t *pabSense, size_t cbSense, size_t *pcbSenseRet, + uint8_t *pu8ScsiSts, uint32_t cTimeoutMillies)); + + /** + * Returns the number of active I/O requests. + * + * @returns Number of active I/O requests. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnIoReqGetActiveCount, (PPDMIMEDIAEX pInterface)); + + /** + * Returns the number of suspended requests. + * + * @returns Number of suspended I/O requests. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnIoReqGetSuspendedCount, (PPDMIMEDIAEX pInterface)); + + /** + * Gets the first suspended request handle. + * + * @returns VBox status code. + * @retval VERR_NOT_FOUND if there is no suspended request waiting. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param phIoReq Where to store the request handle on success. + * @param ppvIoReqAlloc Where to store the pointer to the allocator specific memory on success. + * @thread Any thread. + * + * @note This should only be called when the VM is suspended to make sure the request doesn't suddenly + * changes into the active state again. The only purpose for this method for now is to make saving the state + * possible without breaking saved state versions. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqQuerySuspendedStart, (PPDMIMEDIAEX pInterface, PPDMMEDIAEXIOREQ phIoReq, void **ppvIoReqAlloc)); + + /** + * Gets the next suspended request handle. + * + * @returns VBox status code. + * @retval VERR_NOT_FOUND if there is no suspended request waiting. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The current request handle. + * @param phIoReqNext Where to store the request handle on success. + * @param ppvIoReqAllocNext Where to store the pointer to the allocator specific memory on success. + * @thread Any thread. + * + * @note This should only be called when the VM is suspended to make sure the request doesn't suddenly + * changes into the active state again. The only purpose for this method for now is to make saving the state + * possible without breaking saved state versions. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqQuerySuspendedNext, (PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, + PPDMMEDIAEXIOREQ phIoReqNext, void **ppvIoReqAllocNext)); + + /** + * Saves the given I/O request state in the provided saved state unit. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pSSM The SSM handle. + * @param hIoReq The request handle to save. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqSuspendedSave, (PPDMIMEDIAEX pInterface, PSSMHANDLE pSSM, PDMMEDIAEXIOREQ hIoReq)); + + /** + * Load a suspended request state from the given saved state unit and link it into the suspended list. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pSSM The SSM handle to read the state from. + * @param hIoReq The request handle to load the state into. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqSuspendedLoad, (PPDMIMEDIAEX pInterface, PSSMHANDLE pSSM, PDMMEDIAEXIOREQ hIoReq)); + +} PDMIMEDIAEX; +/** PDMIMEDIAEX interface ID. */ +#define PDMIMEDIAEX_IID "29c9e82b-934e-45c5-bb84-0d871c3cc9dd" + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmstorageifs_h */ diff --git a/include/VBox/vmm/pdmtask.h b/include/VBox/vmm/pdmtask.h new file mode 100644 index 00000000..d3b48e99 --- /dev/null +++ b/include/VBox/vmm/pdmtask.h @@ -0,0 +1,162 @@ +/** @file + * PDM - Pluggable Device Manager, Tasks. + */ + +/* + * Copyright (C) 2019-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmtask_h +#define VBOX_INCLUDED_vmm_pdmtask_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_task The PDM Tasks API + * @ingroup grp_pdm + * + * A task is a predefined asynchronous procedure call that can be triggered from + * any context. + * + * @{ + */ + +/** PDM task handle. */ +typedef uint64_t PDMTASKHANDLE; +/** NIL PDM task handle. */ +#define NIL_PDMTASKHANDLE UINT64_MAX + + +/** + * Task worker callback for devices. + * + * @param pDevIns The device instance. + * @param pvUser The user parameter. + * @thread Task worker thread. + * @remarks The device critical section will NOT be entered before calling the + * callback. No other locks will be held either. + */ +typedef DECLCALLBACKTYPE(void, FNPDMTASKDEV,(PPDMDEVINS pDevIns, void *pvUser)); +/** Pointer to a FNPDMTASKDEV(). */ +typedef FNPDMTASKDEV *PFNPDMTASKDEV; + +/** + * Task worker callback for drivers. + * + * @param pDrvIns The driver instance. + * @param pvUser The user parameter. + * @thread Task worker thread. + * @remarks No other locks will be held. + */ +typedef DECLCALLBACKTYPE(void, FNPDMTASKDRV,(PPDMDRVINS pDrvIns, void *pvUser)); +/** Pointer to a FNPDMTASKDRV(). */ +typedef FNPDMTASKDRV *PFNPDMTASKDRV; + +/** + * Task worker callback for USB devices. + * + * @param pUsbIns The USB device instance. + * @param pvUser The user parameter. + * @thread Task worker thread. + * @remarks No other locks will be held. + */ +typedef DECLCALLBACKTYPE(void, FNPDMTASKUSB,(PPDMUSBINS pUsbIns, void *pvUser)); +/** Pointer to a FNPDMTASKUSB(). */ +typedef FNPDMTASKUSB *PFNPDMTASKUSB; + +/** + * Task worker callback for internal components. + * + * @param pVM The cross context VM structure. + * @param pvUser The user parameter. + * @thread Task worker thread. + * @remarks No other locks will be held. + */ +typedef DECLCALLBACKTYPE(void, FNPDMTASKINT,(PVM pVM, void *pvUser)); +/** Pointer to a FNPDMTASKINT(). */ +typedef FNPDMTASKINT *PFNPDMTASKINT; + + +/** @name PDMTASK_F_XXX - Task creation flags. + * @{ */ +/** Create a ring-0 triggerable task. */ +#define PDMTASK_F_R0 RT_BIT_32(0) +/** Create a raw-mode triggerable task. */ +#define PDMTASK_F_RC RT_BIT_32(1) +/** Create a ring-0 and raw-mode triggerable task. */ +#define PDMTASK_F_RZ (PDMTASK_F_R0 | PDMTASK_F_RC) +/** Valid flags. */ +#define PDMTASK_F_VALID_MASK UINT32_C(0x00000003) +/** @} */ + +#ifdef VBOX_IN_VMM +/** + * Task owner type. + */ +typedef enum PDMTASKTYPE +{ + /** Invalid zero value. */ + PDMTASKTYPE_INVALID = 0, + /** Device consumer. */ + PDMTASKTYPE_DEV, + /** Driver consumer. */ + PDMTASKTYPE_DRV, + /** USB device consumer. */ + PDMTASKTYPE_USB, + /** Internal consumer. */ + PDMTASKTYPE_INTERNAL, + /** End of valid values. */ + PDMTASKTYPE_END, + /** Typical 32-bit type blowup. */ + PDMTASKTYPE_32BIT_HACK = 0x7fffffff +} PDMTASKTYPE; + +VMMR3_INT_DECL(int) PDMR3TaskCreate(PVM pVM, uint32_t fFlags, const char *pszName, PDMTASKTYPE enmType, void *pvOwner, + PFNRT pfnCallback, void *pvUser, PDMTASKHANDLE *phTask); +VMMR3_INT_DECL(int) PDMR3TaskCreateInternal(PVM pVM, uint32_t fFlags, const char *pszName, + PFNPDMTASKINT pfnCallback, void *pvUser, PDMTASKHANDLE *phTask); +VMMR3_INT_DECL(int) PDMR3TaskDestroyAllByOwner(PVM pVM, PDMTASKTYPE enmType, void *pvOwner); +VMMR3_INT_DECL(int) PDMR3TaskDestroySpecific(PVM pVM, PDMTASKTYPE enmType, void *pvOwner, PDMTASKHANDLE hTask); +VMMR3_INT_DECL(int) PDMR3TaskDestroyInternal(PVM pVM, PDMTASKHANDLE hTask); + +VMM_INT_DECL(int) PDMTaskTrigger(PVMCC pVM, PDMTASKTYPE enmType, RTR3PTR pvOwner, PDMTASKHANDLE hTask); +VMM_INT_DECL(int) PDMTaskTriggerInternal(PVMCC pVM, PDMTASKHANDLE hTask); +#endif /* VBOX_IN_VMM */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmtask_h */ + diff --git a/include/VBox/vmm/pdmthread.h b/include/VBox/vmm/pdmthread.h new file mode 100644 index 00000000..1163f163 --- /dev/null +++ b/include/VBox/vmm/pdmthread.h @@ -0,0 +1,311 @@ +/** @file + * PDM - Pluggable Device Manager, Threads. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmthread_h +#define VBOX_INCLUDED_vmm_pdmthread_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#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 DECLCALLBACKTYPE(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 DECLCALLBACKTYPE(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 DECLCALLBACKTYPE(int, FNPDMTHREADDRV,(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)); +/** Pointer to a FNPDMTHREADDRV(). */ +typedef FNPDMTHREADDRV *PFNPDMTHREADDRV; + +/** + * PDM thread, driver variation. + * + * @returns VBox status code. + * @param pVM The cross context VM structure. + * @param pThread The PDM thread data. + */ +typedef DECLCALLBACKTYPE(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 DECLCALLBACKTYPE(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 DECLCALLBACKTYPE(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 DECLCALLBACKTYPE(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 cross context VM structure. + * @param pThread The PDM thread data. + */ +typedef DECLCALLBACKTYPE(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 /* !VBOX_INCLUDED_vmm_pdmthread_h */ diff --git a/include/VBox/vmm/pdmtpmifs.h b/include/VBox/vmm/pdmtpmifs.h new file mode 100644 index 00000000..22a15839 --- /dev/null +++ b/include/VBox/vmm/pdmtpmifs.h @@ -0,0 +1,163 @@ +/** @file + * PDM - Pluggable Device Manager, TPM related interfaces. + */ + +/* + * Copyright (C) 2021-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmtpmifs_h +#define VBOX_INCLUDED_vmm_pdmtpmifs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_ifs_tpm PDM TPM Interfaces + * @ingroup grp_pdm_interfaces + * @{ + */ + + +/** Pointer to a TPM port interface. */ +typedef struct PDMITPMPORT *PPDMITPMPORT; +/** + * TPM port interface (down). + */ +typedef struct PDMITPMPORT +{ + /** + * @todo + */ + DECLR3CALLBACKMEMBER(int, pfnDummy, (PPDMITPMPORT pInterface)); + +} PDMITPMPORT; +/** PDMITPMPORT interface ID. */ +#define PDMITPMPORT_IID "1e57710f-f820-47ec-afa6-2713195f8f94" + + +/** + * TPM version enumeration. + */ +typedef enum TPMVERSION +{ + /** Invalid TPM version, don't use. */ + TPMVERSION_INVALID = 0, + /** TPM works according to version 1.2 of the specification. */ + TPMVERSION_1_2, + /** TPM works according to version 2.0 of the specification. */ + TPMVERSION_2_0, + /** TPM version is unknown. */ + TPMVERSION_UNKNOWN +} TPMVERSION; + + +/** Pointer to a TPM interface. */ +typedef struct PDMITPMCONNECTOR *PPDMITPMCONNECTOR; +/** + * TPM interface (up). + * Pairs with PDMITPMPORT. + */ +typedef struct PDMITPMCONNECTOR +{ + /** + * Returns the version of the TPM implemented by the driver below. + * + * @returns The TPM version. + * @param pInterface Pointer to the interface structure containing the called function pointer. + */ + DECLR3CALLBACKMEMBER(TPMVERSION, pfnGetVersion, (PPDMITPMCONNECTOR pInterface)); + + /** + * Returns the maximum supported locality of the driver below. + * + * @returns The maximum supported locality (0-4). + * @param pInterface Pointer to the interface structure containing the called function pointer. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnGetLocalityMax, (PPDMITPMCONNECTOR pInterface)); + + /** + * Returns the command/response buffer size of the driver below. + * + * @returns Buffer size in bytes. + * @param pInterface Pointer to the interface structure containing the called function pointer. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnGetBufferSize, (PPDMITPMCONNECTOR pInterface)); + + /** + * Returns the status of the established flag. + * + * @returns Status of the established flag. + * @param pInterface Pointer to the interface structure containing the called function pointer. + */ + DECLR3CALLBACKMEMBER(bool, pfnGetEstablishedFlag, (PPDMITPMCONNECTOR pInterface)); + + /** + * Resets the TPM established flag. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param bLoc The locality issuing this request. + */ + DECLR3CALLBACKMEMBER(int, pfnResetEstablishedFlag, (PPDMITPMCONNECTOR pInterface, uint8_t bLoc)); + + /** + * Executes the given command. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param bLoc The locality the command is issued from. + * @param pvCmd Pointer to the command data. + * @param cbCmd Size of the command in bytes. + * @param pvResp Where to store the response data. + * @param cbResp Size of the response buffer in bytes. + */ + DECLR3CALLBACKMEMBER(int, pfnCmdExec, (PPDMITPMCONNECTOR pInterface, uint8_t bLoc, const void *pvCmd, size_t cbCmd, void *pvResp, size_t cbResp)); + + /** + * Cancels the currently executed command. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + */ + DECLR3CALLBACKMEMBER(int, pfnCmdCancel, (PPDMITPMCONNECTOR pInterface)); + +} PDMITPMCONNECTOR; +/** PDMITPMCONNECTOR interface ID. */ +#define PDMITPMCONNECTOR_IID "30afefd8-c11f-4e2a-a746-424e3d99fa86" + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmtpmifs_h */ diff --git a/include/VBox/vmm/pdmusb.h b/include/VBox/vmm/pdmusb.h new file mode 100644 index 00000000..c27c33a7 --- /dev/null +++ b/include/VBox/vmm/pdmusb.h @@ -0,0 +1,1502 @@ +/** @file + * PDM - Pluggable Device Manager, USB Devices. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmusb_h +#define VBOX_INCLUDED_vmm_pdmusb_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#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/tm.h> +#include <VBox/vmm/ssm.h> +#include <VBox/vmm/cfgm.h> +#include <VBox/vmm/dbgf.h> +#include <VBox/vmm/mm.h> +#include <VBox/vusb.h> +#include <iprt/errcore.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 Device Flags. + * @{ */ +/** A high-speed capable USB 2.0 device (also required to support full-speed). */ +#define PDM_USBREG_HIGHSPEED_CAPABLE RT_BIT(0) +/** Indicates that the device implements the saved state handlers. */ +#define PDM_USBREG_SAVED_STATE_SUPPORTED RT_BIT(1) +/** A SuperSpeed USB 3.0 device. */ +#define PDM_USBREG_SUPERSPEED_CAPABLE RT_BIT(2) +/** @} */ + +/** 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 pfnConstruct 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. + * @param fFlags Flags, combination of the PDM_TACH_FLAGS_* \#defines. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(int, pfnDriverAttach,(PPDMUSBINS pUsbIns, unsigned iLUN, uint32_t fFlags)); + + /** + * 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. + * @param fFlags Flags, combination of the PDM_TACH_FLAGS_* \#defines. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(void, pfnDriverDetach,(PPDMUSBINS pUsbIns, unsigned iLUN, uint32_t fFlags)); + + /** + * 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)); + + /** + * Wakes a thread waiting in pfnUrbReap. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + */ + DECLR3CALLBACKMEMBER(int, pfnWakeup,(PPDMUSBINS pUsbIns)); + + /** 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, 2, 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 registration 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) RT_IPRT_FORMAT_ATTR(5, 0)); + + /** + * Register a info handler with DBGF, argv style. + * + * @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, pfnDBGFInfoRegisterArgv,(PPDMUSBINS pUsbIns, const char *pszName, const char *pszDesc, PFNDBGFINFOARGVUSB 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)); + + /** + * Free memory allocated with pfnMMHeapAlloc() and pfnMMHeapAllocZ(). + * + * @param pUsbIns The USB device instance. + * @param pv Pointer to the memory to free. + */ + DECLR3CALLBACKMEMBER(void, pfnMMHeapFree,(PPDMUSBINS pUsbIns, void *pv)); + + /** + * 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)); + + /** @name Exported SSM Functions + * @{ */ + DECLR3CALLBACKMEMBER(int, pfnSSMPutStruct,(PSSMHANDLE pSSM, const void *pvStruct, PCSSMFIELD paFields)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutStructEx,(PSSMHANDLE pSSM, const void *pvStruct, size_t cbStruct, uint32_t fFlags, PCSSMFIELD paFields, void *pvUser)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutBool,(PSSMHANDLE pSSM, bool fBool)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU8,(PSSMHANDLE pSSM, uint8_t u8)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS8,(PSSMHANDLE pSSM, int8_t i8)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU16,(PSSMHANDLE pSSM, uint16_t u16)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS16,(PSSMHANDLE pSSM, int16_t i16)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU32,(PSSMHANDLE pSSM, uint32_t u32)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS32,(PSSMHANDLE pSSM, int32_t i32)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU64,(PSSMHANDLE pSSM, uint64_t u64)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS64,(PSSMHANDLE pSSM, int64_t i64)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU128,(PSSMHANDLE pSSM, uint128_t u128)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS128,(PSSMHANDLE pSSM, int128_t i128)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutUInt,(PSSMHANDLE pSSM, RTUINT u)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutSInt,(PSSMHANDLE pSSM, RTINT i)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCUInt,(PSSMHANDLE pSSM, RTGCUINT u)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCUIntReg,(PSSMHANDLE pSSM, RTGCUINTREG u)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCPhys32,(PSSMHANDLE pSSM, RTGCPHYS32 GCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCPhys64,(PSSMHANDLE pSSM, RTGCPHYS64 GCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCPhys,(PSSMHANDLE pSSM, RTGCPHYS GCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCPtr,(PSSMHANDLE pSSM, RTGCPTR GCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCUIntPtr,(PSSMHANDLE pSSM, RTGCUINTPTR GCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutRCPtr,(PSSMHANDLE pSSM, RTRCPTR RCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutIOPort,(PSSMHANDLE pSSM, RTIOPORT IOPort)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutSel,(PSSMHANDLE pSSM, RTSEL Sel)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutMem,(PSSMHANDLE pSSM, const void *pv, size_t cb)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutStrZ,(PSSMHANDLE pSSM, const char *psz)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetStruct,(PSSMHANDLE pSSM, void *pvStruct, PCSSMFIELD paFields)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetStructEx,(PSSMHANDLE pSSM, void *pvStruct, size_t cbStruct, uint32_t fFlags, PCSSMFIELD paFields, void *pvUser)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetBool,(PSSMHANDLE pSSM, bool *pfBool)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetBoolV,(PSSMHANDLE pSSM, bool volatile *pfBool)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU8,(PSSMHANDLE pSSM, uint8_t *pu8)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU8V,(PSSMHANDLE pSSM, uint8_t volatile *pu8)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS8,(PSSMHANDLE pSSM, int8_t *pi8)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS8V,(PSSMHANDLE pSSM, int8_t volatile *pi8)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU16,(PSSMHANDLE pSSM, uint16_t *pu16)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU16V,(PSSMHANDLE pSSM, uint16_t volatile *pu16)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS16,(PSSMHANDLE pSSM, int16_t *pi16)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS16V,(PSSMHANDLE pSSM, int16_t volatile *pi16)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU32,(PSSMHANDLE pSSM, uint32_t *pu32)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU32V,(PSSMHANDLE pSSM, uint32_t volatile *pu32)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS32,(PSSMHANDLE pSSM, int32_t *pi32)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS32V,(PSSMHANDLE pSSM, int32_t volatile *pi32)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU64,(PSSMHANDLE pSSM, uint64_t *pu64)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU64V,(PSSMHANDLE pSSM, uint64_t volatile *pu64)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS64,(PSSMHANDLE pSSM, int64_t *pi64)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS64V,(PSSMHANDLE pSSM, int64_t volatile *pi64)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU128,(PSSMHANDLE pSSM, uint128_t *pu128)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU128V,(PSSMHANDLE pSSM, uint128_t volatile *pu128)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS128,(PSSMHANDLE pSSM, int128_t *pi128)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS128V,(PSSMHANDLE pSSM, int128_t volatile *pi128)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys32,(PSSMHANDLE pSSM, PRTGCPHYS32 pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys32V,(PSSMHANDLE pSSM, RTGCPHYS32 volatile *pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys64,(PSSMHANDLE pSSM, PRTGCPHYS64 pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys64V,(PSSMHANDLE pSSM, RTGCPHYS64 volatile *pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys,(PSSMHANDLE pSSM, PRTGCPHYS pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhysV,(PSSMHANDLE pSSM, RTGCPHYS volatile *pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetUInt,(PSSMHANDLE pSSM, PRTUINT pu)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetSInt,(PSSMHANDLE pSSM, PRTINT pi)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCUInt,(PSSMHANDLE pSSM, PRTGCUINT pu)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCUIntReg,(PSSMHANDLE pSSM, PRTGCUINTREG pu)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPtr,(PSSMHANDLE pSSM, PRTGCPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCUIntPtr,(PSSMHANDLE pSSM, PRTGCUINTPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetRCPtr,(PSSMHANDLE pSSM, PRTRCPTR pRCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetIOPort,(PSSMHANDLE pSSM, PRTIOPORT pIOPort)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetSel,(PSSMHANDLE pSSM, PRTSEL pSel)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetMem,(PSSMHANDLE pSSM, void *pv, size_t cb)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetStrZ,(PSSMHANDLE pSSM, char *psz, size_t cbMax)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetStrZEx,(PSSMHANDLE pSSM, char *psz, size_t cbMax, size_t *pcbStr)); + DECLR3CALLBACKMEMBER(int, pfnSSMSkip,(PSSMHANDLE pSSM, size_t cb)); + DECLR3CALLBACKMEMBER(int, pfnSSMSkipToEndOfUnit,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(int, pfnSSMSetLoadError,(PSSMHANDLE pSSM, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(6, 7)); + DECLR3CALLBACKMEMBER(int, pfnSSMSetLoadErrorV,(PSSMHANDLE pSSM, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(6, 0)); + DECLR3CALLBACKMEMBER(int, pfnSSMSetCfgError,(PSSMHANDLE pSSM, RT_SRC_POS_DECL, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(5, 6)); + DECLR3CALLBACKMEMBER(int, pfnSSMSetCfgErrorV,(PSSMHANDLE pSSM, RT_SRC_POS_DECL, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(5, 0)); + DECLR3CALLBACKMEMBER(int, pfnSSMHandleGetStatus,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(SSMAFTER, pfnSSMHandleGetAfter,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(bool, pfnSSMHandleIsLiveSave,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(uint32_t, pfnSSMHandleMaxDowntime,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(uint32_t, pfnSSMHandleHostBits,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(uint32_t, pfnSSMHandleRevision,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(uint32_t, pfnSSMHandleVersion,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(const char *, pfnSSMHandleHostOSAndArch,(PSSMHANDLE pSSM)); + /** @} */ + + /** @name Exported CFGM Functions. + * @{ */ + DECLR3CALLBACKMEMBER(bool, pfnCFGMExists,( PCFGMNODE pNode, const char *pszName)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryType,( PCFGMNODE pNode, const char *pszName, PCFGMVALUETYPE penmType)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQuerySize,( PCFGMNODE pNode, const char *pszName, size_t *pcb)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryInteger,( PCFGMNODE pNode, const char *pszName, uint64_t *pu64)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryIntegerDef,( PCFGMNODE pNode, const char *pszName, uint64_t *pu64, uint64_t u64Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryString,( PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryStringDef,( PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString, const char *pszDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryBytes,( PCFGMNODE pNode, const char *pszName, void *pvData, size_t cbData)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU64,( PCFGMNODE pNode, const char *pszName, uint64_t *pu64)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU64Def,( PCFGMNODE pNode, const char *pszName, uint64_t *pu64, uint64_t u64Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS64,( PCFGMNODE pNode, const char *pszName, int64_t *pi64)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS64Def,( PCFGMNODE pNode, const char *pszName, int64_t *pi64, int64_t i64Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU32,( PCFGMNODE pNode, const char *pszName, uint32_t *pu32)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU32Def,( PCFGMNODE pNode, const char *pszName, uint32_t *pu32, uint32_t u32Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS32,( PCFGMNODE pNode, const char *pszName, int32_t *pi32)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS32Def,( PCFGMNODE pNode, const char *pszName, int32_t *pi32, int32_t i32Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU16,( PCFGMNODE pNode, const char *pszName, uint16_t *pu16)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU16Def,( PCFGMNODE pNode, const char *pszName, uint16_t *pu16, uint16_t u16Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS16,( PCFGMNODE pNode, const char *pszName, int16_t *pi16)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS16Def,( PCFGMNODE pNode, const char *pszName, int16_t *pi16, int16_t i16Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU8,( PCFGMNODE pNode, const char *pszName, uint8_t *pu8)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU8Def,( PCFGMNODE pNode, const char *pszName, uint8_t *pu8, uint8_t u8Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS8,( PCFGMNODE pNode, const char *pszName, int8_t *pi8)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS8Def,( PCFGMNODE pNode, const char *pszName, int8_t *pi8, int8_t i8Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryBool,( PCFGMNODE pNode, const char *pszName, bool *pf)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryBoolDef,( PCFGMNODE pNode, const char *pszName, bool *pf, bool fDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryPort,( PCFGMNODE pNode, const char *pszName, PRTIOPORT pPort)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryPortDef,( PCFGMNODE pNode, const char *pszName, PRTIOPORT pPort, RTIOPORT PortDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryUInt,( PCFGMNODE pNode, const char *pszName, unsigned int *pu)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryUIntDef,( PCFGMNODE pNode, const char *pszName, unsigned int *pu, unsigned int uDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQuerySInt,( PCFGMNODE pNode, const char *pszName, signed int *pi)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQuerySIntDef,( PCFGMNODE pNode, const char *pszName, signed int *pi, signed int iDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtr,( PCFGMNODE pNode, const char *pszName, PRTGCPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrDef,( PCFGMNODE pNode, const char *pszName, PRTGCPTR pGCPtr, RTGCPTR GCPtrDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrU,( PCFGMNODE pNode, const char *pszName, PRTGCUINTPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrUDef,( PCFGMNODE pNode, const char *pszName, PRTGCUINTPTR pGCPtr, RTGCUINTPTR GCPtrDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrS,( PCFGMNODE pNode, const char *pszName, PRTGCINTPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrSDef,( PCFGMNODE pNode, const char *pszName, PRTGCINTPTR pGCPtr, RTGCINTPTR GCPtrDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryStringAlloc,( PCFGMNODE pNode, const char *pszName, char **ppszString)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryStringAllocDef,(PCFGMNODE pNode, const char *pszName, char **ppszString, const char *pszDef)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetParent,(PCFGMNODE pNode)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetChild,(PCFGMNODE pNode, const char *pszPath)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetChildF,(PCFGMNODE pNode, const char *pszPathFormat, ...) RT_IPRT_FORMAT_ATTR(2, 3)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetChildFV,(PCFGMNODE pNode, const char *pszPathFormat, va_list Args) RT_IPRT_FORMAT_ATTR(3, 0)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetFirstChild,(PCFGMNODE pNode)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetNextChild,(PCFGMNODE pCur)); + DECLR3CALLBACKMEMBER(int, pfnCFGMGetName,(PCFGMNODE pCur, char *pszName, size_t cchName)); + DECLR3CALLBACKMEMBER(size_t, pfnCFGMGetNameLen,(PCFGMNODE pCur)); + DECLR3CALLBACKMEMBER(bool, pfnCFGMAreChildrenValid,(PCFGMNODE pNode, const char *pszzValid)); + DECLR3CALLBACKMEMBER(PCFGMLEAF, pfnCFGMGetFirstValue,(PCFGMNODE pCur)); + DECLR3CALLBACKMEMBER(PCFGMLEAF, pfnCFGMGetNextValue,(PCFGMLEAF pCur)); + DECLR3CALLBACKMEMBER(int, pfnCFGMGetValueName,(PCFGMLEAF pCur, char *pszName, size_t cchName)); + DECLR3CALLBACKMEMBER(size_t, pfnCFGMGetValueNameLen,(PCFGMLEAF pCur)); + DECLR3CALLBACKMEMBER(CFGMVALUETYPE, pfnCFGMGetValueType,(PCFGMLEAF pCur)); + DECLR3CALLBACKMEMBER(bool, pfnCFGMAreValuesValid,(PCFGMNODE pNode, const char *pszzValid)); + DECLR3CALLBACKMEMBER(int, pfnCFGMValidateConfig,(PCFGMNODE pNode, const char *pszNode, + const char *pszValidValues, const char *pszValidNodes, + const char *pszWho, uint32_t uInstance)); + /** @} */ + + /** + * 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) RT_IPRT_FORMAT_ATTR(7, 0)); + + /** + * 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 phTimer Where to store the timer handle on success. + */ + DECLR3CALLBACKMEMBER(int, pfnTimerCreate,(PPDMUSBINS pUsbIns, TMCLOCK enmClock, PFNTMTIMERUSB pfnCallback, void *pvUser, + uint32_t fFlags, const char *pszDesc, PTMTIMERHANDLE phTimer)); + + /** @name Timer handle method wrappers + * @{ */ + DECLR3CALLBACKMEMBER(uint64_t, pfnTimerFromMicro,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cMicroSecs)); + DECLR3CALLBACKMEMBER(uint64_t, pfnTimerFromMilli,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cMilliSecs)); + DECLR3CALLBACKMEMBER(uint64_t, pfnTimerFromNano,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cNanoSecs)); + DECLR3CALLBACKMEMBER(uint64_t, pfnTimerGet,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)); + DECLR3CALLBACKMEMBER(uint64_t, pfnTimerGetFreq,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)); + DECLR3CALLBACKMEMBER(uint64_t, pfnTimerGetNano,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)); + DECLR3CALLBACKMEMBER(bool, pfnTimerIsActive,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)); + DECLR3CALLBACKMEMBER(bool, pfnTimerIsLockOwner,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)); + DECLR3CALLBACKMEMBER(int, pfnTimerLockClock,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)); + /** Takes the clock lock then enters the specified critical section. */ + DECLR3CALLBACKMEMBER(int, pfnTimerLockClock2,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(int, pfnTimerSet,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t uExpire)); + DECLR3CALLBACKMEMBER(int, pfnTimerSetFrequencyHint,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint32_t uHz)); + DECLR3CALLBACKMEMBER(int, pfnTimerSetMicro,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cMicrosToNext)); + DECLR3CALLBACKMEMBER(int, pfnTimerSetMillies,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cMilliesToNext)); + DECLR3CALLBACKMEMBER(int, pfnTimerSetNano,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cNanosToNext)); + DECLR3CALLBACKMEMBER(int, pfnTimerSetRelative,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cTicksToNext, uint64_t *pu64Now)); + DECLR3CALLBACKMEMBER(int, pfnTimerStop,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)); + DECLR3CALLBACKMEMBER(void, pfnTimerUnlockClock,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)); + DECLR3CALLBACKMEMBER(void, pfnTimerUnlockClock2,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(int, pfnTimerSetCritSect,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(int, pfnTimerSave,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(int, pfnTimerLoad,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(int, pfnTimerDestroy,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)); + /** @sa TMR3TimerSkip */ + DECLR3CALLBACKMEMBER(int, pfnTimerSkipLoad,(PSSMHANDLE pSSM, bool *pfActive)); + /** @} */ + + /** + * Set the VM error message + * + * @returns rc. + * @param pUsbIns The USB device instance. + * @param rc VBox status code. + * @param SRC_POS 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) RT_IPRT_FORMAT_ATTR(6, 0)); + + /** + * 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) RT_IPRT_FORMAT_ATTR(4, 0)); + + /** + * 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 pUsbIns The USB 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)); + + /** @name Exported PDM Thread Functions + * @{ */ + DECLR3CALLBACKMEMBER(int, pfnThreadDestroy,(PPDMTHREAD pThread, int *pRcThread)); + DECLR3CALLBACKMEMBER(int, pfnThreadIAmSuspending,(PPDMTHREAD pThread)); + DECLR3CALLBACKMEMBER(int, pfnThreadIAmRunning,(PPDMTHREAD pThread)); + DECLR3CALLBACKMEMBER(int, pfnThreadSleep,(PPDMTHREAD pThread, RTMSINTERVAL cMillies)); + DECLR3CALLBACKMEMBER(int, pfnThreadSuspend,(PPDMTHREAD pThread)); + DECLR3CALLBACKMEMBER(int, pfnThreadResume,(PPDMTHREAD pThread)); + /** @} */ + + /** + * 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)); + + /** + * Gets the reason for the most recent VM suspend. + * + * @returns The suspend reason. VMSUSPENDREASON_INVALID is returned if no + * suspend has been made or if the pUsbIns is invalid. + * @param pUsbIns The driver instance. + */ + DECLR3CALLBACKMEMBER(VMSUSPENDREASON, pfnVMGetSuspendReason,(PPDMUSBINS pUsbIns)); + + /** + * Gets the reason for the most recent VM resume. + * + * @returns The resume reason. VMRESUMEREASON_INVALID is returned if no + * resume has been made or if the pUsbIns is invalid. + * @param pUsbIns The driver instance. + */ + DECLR3CALLBACKMEMBER(VMRESUMEREASON, pfnVMGetResumeReason,(PPDMUSBINS pUsbIns)); + + /** + * Queries a generic object from the VMM user. + * + * @returns Pointer to the object if found, NULL if not. + * @param pUsbIns The USB device instance. + * @param pUuid The UUID of what's being queried. The UUIDs and + * the usage conventions are defined by the user. + */ + DECLR3CALLBACKMEMBER(void *, pfnQueryGenericUserObject,(PPDMUSBINS pUsbIns, PCRTUUID pUuid)); + + /** @name Space reserved for minor interface changes. + * @{ */ + DECLR3CALLBACKMEMBER(void, pfnReserved0,(PPDMUSBINS pUsbIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved1,(PPDMUSBINS pUsbIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved2,(PPDMUSBINS pUsbIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved3,(PPDMUSBINS pUsbIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved4,(PPDMUSBINS pUsbIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved5,(PPDMUSBINS pUsbIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved6,(PPDMUSBINS pUsbIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved7,(PPDMUSBINS pUsbIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved8,(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, 7, 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; + /** The port/device speed. HCs and emulated devices need to know. */ + VUSBSPEED enmSpeed; + + /** Padding to make achInstanceData aligned at 32 byte boundary. */ + uint32_t au32Padding[HC_ARCH_BITS == 32 ? 2 : 3]; + + /** 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, 3, 0) + +/** + * Checks the structure versions of the USB device instance and USB device + * helpers, returning if they are incompatible. + * + * This shall be the first statement of 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 shall be invoked as the first statement in the destructor! + * + * @param pUsbIns The USB device instance pointer. + */ +#define PDMUSB_CHECK_VERSIONS_RETURN_VOID(pUsbIns) \ + do \ + { \ + PPDMUSBINS pUsbInsTypeCheck = (pUsbIns); NOREF(pUsbInsTypeCheck); \ + if (RT_LIKELY(PDM_VERSION_ARE_COMPATIBLE((pUsbIns)->u32Version, PDM_USBINS_VERSION) )) \ + { /* likely */ } else return; \ + if (RT_LIKELY(PDM_VERSION_ARE_COMPATIBLE((pUsbIns)->pHlpR3->u32Version, PDM_USBHLP_VERSION) )) \ + { /* likely */ } else return; \ + } while (0) + + +/** Converts a pointer to the PDMUSBINS::IBase to a pointer to PDMUSBINS. */ +#define PDMIBASE_2_PDMUSB(pInterface) ( (PPDMUSBINS)((char *)(pInterface) - RT_UOFFSETOF(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 SRC_POS Use RT_SRC_POS. + * @param pszFormat Message. (optional) + * @param ... Message parameters. + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(5, 6) 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 SRC_POS Use RT_SRC_POS. + * @param pszFormat Error message format string. + * @param ... Error message arguments. + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(6, 7) 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) +{ + pUsbIns->pHlpR3->pfnMMHeapFree(pUsbIns, pv); +} + +/** + * @copydoc PDMUSBHLP::pfnDBGFInfoRegisterArgv + */ +DECLINLINE(int) PDMUsbHlpDBGFInfoRegisterArgv(PPDMUSBINS pUsbIns, const char *pszName, const char *pszDesc, PFNDBGFINFOARGVUSB pfnHandler) +{ + return pUsbIns->pHlpR3->pfnDBGFInfoRegisterArgv(pUsbIns, pszName, pszDesc, pfnHandler); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerCreate + */ +DECLINLINE(int) PDMUsbHlpTimerCreate(PPDMUSBINS pUsbIns, TMCLOCK enmClock, PFNTMTIMERUSB pfnCallback, void *pvUser, + uint32_t fFlags, const char *pszDesc, PTMTIMERHANDLE phTimer) +{ + return pUsbIns->pHlpR3->pfnTimerCreate(pUsbIns, enmClock, pfnCallback, pvUser, fFlags, pszDesc, phTimer); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerFromMicro + */ +DECLINLINE(uint64_t) PDMUsbHlpTimerFromMicro(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cMicroSecs) +{ + return pUsbIns->pHlpR3->pfnTimerFromMicro(pUsbIns, hTimer, cMicroSecs); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerFromMilli + */ +DECLINLINE(uint64_t) PDMUsbHlpTimerFromMilli(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cMilliSecs) +{ + return pUsbIns->pHlpR3->pfnTimerFromMilli(pUsbIns, hTimer, cMilliSecs); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerFromNano + */ +DECLINLINE(uint64_t) PDMUsbHlpTimerFromNano(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cNanoSecs) +{ + return pUsbIns->pHlpR3->pfnTimerFromNano(pUsbIns, hTimer, cNanoSecs); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerGet + */ +DECLINLINE(uint64_t) PDMUsbHlpTimerGet(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer) +{ + return pUsbIns->pHlpR3->pfnTimerGet(pUsbIns, hTimer); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerGetFreq + */ +DECLINLINE(uint64_t) PDMUsbHlpTimerGetFreq(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer) +{ + return pUsbIns->pHlpR3->pfnTimerGetFreq(pUsbIns, hTimer); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerGetNano + */ +DECLINLINE(uint64_t) PDMUsbHlpTimerGetNano(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer) +{ + return pUsbIns->pHlpR3->pfnTimerGetNano(pUsbIns, hTimer); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerIsActive + */ +DECLINLINE(bool) PDMUsbHlpTimerIsActive(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer) +{ + return pUsbIns->pHlpR3->pfnTimerIsActive(pUsbIns, hTimer); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerIsLockOwner + */ +DECLINLINE(bool) PDMUsbHlpTimerIsLockOwner(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer) +{ + return pUsbIns->pHlpR3->pfnTimerIsLockOwner(pUsbIns, hTimer); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerLockClock + */ +DECLINLINE(int) PDMUsbHlpTimerLockClock(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer) +{ + return pUsbIns->pHlpR3->pfnTimerLockClock(pUsbIns, hTimer); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerLockClock2 + */ +DECLINLINE(int) PDMUsbHlpTimerLockClock2(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect) +{ + return pUsbIns->pHlpR3->pfnTimerLockClock2(pUsbIns, hTimer, pCritSect); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerSet + */ +DECLINLINE(int) PDMUsbHlpTimerSet(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t uExpire) +{ + return pUsbIns->pHlpR3->pfnTimerSet(pUsbIns, hTimer, uExpire); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerSetFrequencyHint + */ +DECLINLINE(int) PDMUsbHlpTimerSetFrequencyHint(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint32_t uHz) +{ + return pUsbIns->pHlpR3->pfnTimerSetFrequencyHint(pUsbIns, hTimer, uHz); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerSetMicro + */ +DECLINLINE(int) PDMUsbHlpTimerSetMicro(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cMicrosToNext) +{ + return pUsbIns->pHlpR3->pfnTimerSetMicro(pUsbIns, hTimer, cMicrosToNext); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerSetMillies + */ +DECLINLINE(int) PDMUsbHlpTimerSetMillies(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cMilliesToNext) +{ + return pUsbIns->pHlpR3->pfnTimerSetMillies(pUsbIns, hTimer, cMilliesToNext); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerSetNano + */ +DECLINLINE(int) PDMUsbHlpTimerSetNano(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cNanosToNext) +{ + return pUsbIns->pHlpR3->pfnTimerSetNano(pUsbIns, hTimer, cNanosToNext); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerSetRelative + */ +DECLINLINE(int) PDMUsbHlpTimerSetRelative(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cTicksToNext, uint64_t *pu64Now) +{ + return pUsbIns->pHlpR3->pfnTimerSetRelative(pUsbIns, hTimer, cTicksToNext, pu64Now); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerStop + */ +DECLINLINE(int) PDMUsbHlpTimerStop(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer) +{ + return pUsbIns->pHlpR3->pfnTimerStop(pUsbIns, hTimer); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerUnlockClock + */ +DECLINLINE(void) PDMUsbHlpTimerUnlockClock(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer) +{ + pUsbIns->pHlpR3->pfnTimerUnlockClock(pUsbIns, hTimer); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerUnlockClock2 + */ +DECLINLINE(void) PDMUsbHlpTimerUnlockClock2(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect) +{ + pUsbIns->pHlpR3->pfnTimerUnlockClock2(pUsbIns, hTimer, pCritSect); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerSetCritSect + */ +DECLINLINE(int) PDMUsbHlpTimerSetCritSect(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect) +{ + return pUsbIns->pHlpR3->pfnTimerSetCritSect(pUsbIns, hTimer, pCritSect); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerSave + */ +DECLINLINE(int) PDMUsbHlpTimerSave(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PSSMHANDLE pSSM) +{ + return pUsbIns->pHlpR3->pfnTimerSave(pUsbIns, hTimer, pSSM); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerLoad + */ +DECLINLINE(int) PDMUsbHlpTimerLoad(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PSSMHANDLE pSSM) +{ + return pUsbIns->pHlpR3->pfnTimerLoad(pUsbIns, hTimer, pSSM); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerDestroy + */ +DECLINLINE(int) PDMUsbHlpTimerDestroy(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer) +{ + return pUsbIns->pHlpR3->pfnTimerDestroy(pUsbIns, hTimer); +} + +/** + * @copydoc PDMUSBHLP::pfnSSMRegister + */ +DECLINLINE(int) PDMUsbHlpSSMRegister(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) +{ + return pUsbIns->pHlpR3->pfnSSMRegister(pUsbIns, uVersion, cbGuess, + pfnLivePrep, pfnLiveExec, pfnLiveVote, + pfnSavePrep, pfnSaveExec, pfnSaveDone, + pfnLoadPrep, pfnLoadExec, pfnLoadDone); +} + +/** + * @copydoc PDMUSBHLP::pfnQueryGenericUserObject + */ +DECLINLINE(void *) PDMUsbHlpQueryGenericUserObject(PPDMUSBINS pUsbIns, PCRTUUID pUuid) +{ + return pUsbIns->pHlpR3->pfnQueryGenericUserObject(pUsbIns, pUuid); +} + +#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 DECLCALLBACKTYPE(int, FNPDMVBOXUSBREGISTER,(PCPDMUSBREGCB pCallbacks, uint32_t u32Version)); + +VMMR3DECL(int) PDMR3UsbCreateEmulatedDevice(PUVM pUVM, const char *pszDeviceName, PCFGMNODE pDeviceNode, PCRTUUID pUuid, + const char *pszCaptureFilename); +VMMR3DECL(int) PDMR3UsbCreateProxyDevice(PUVM pUVM, PCRTUUID pUuid, const char *pszBackend, const char *pszAddress, PCFGMNODE pSubTree, + VUSBSPEED enmSpeed, uint32_t fMaskedIfs, const char *pszCaptureFilename); +VMMR3DECL(int) PDMR3UsbDetachDevice(PUVM pUVM, PCRTUUID pUuid); +VMMR3DECL(bool) PDMR3UsbHasHub(PUVM pUVM); +VMMR3DECL(int) PDMR3UsbDriverAttach(PUVM pUVM, const char *pszDevice, unsigned iDevIns, unsigned iLun, uint32_t fFlags, + PPPDMIBASE ppBase); +VMMR3DECL(int) PDMR3UsbDriverDetach(PUVM pUVM, const char *pszDevice, unsigned iDevIns, unsigned iLun, + const char *pszDriver, unsigned iOccurrence, uint32_t fFlags); +VMMR3DECL(int) PDMR3UsbQueryLun(PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPDMIBASE *ppBase); +VMMR3DECL(int) PDMR3UsbQueryDriverOnLun(PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, + const char *pszDriver, PPPDMIBASE ppBase); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmusb_h */ diff --git a/include/VBox/vmm/pdmwebcaminfs.h b/include/VBox/vmm/pdmwebcaminfs.h new file mode 100644 index 00000000..3c1fe35f --- /dev/null +++ b/include/VBox/vmm/pdmwebcaminfs.h @@ -0,0 +1,156 @@ +/* $Id: pdmwebcaminfs.h $ */ +/** @file + * webcaminfs - interfaces between dev and driver. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmwebcaminfs_h +#define VBOX_INCLUDED_vmm_pdmwebcaminfs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> + +struct VRDEVIDEOINDEVICEDESC; +struct VRDEVIDEOINPAYLOADHDR; +struct VRDEVIDEOINCTRLHDR; + + +/** @defgroup grp_pdm_ifs_webcam PDM Web Camera Interfaces + * @ingroup grp_pdm_interfaces + * @{ + */ + +/** Pointer to the web camera driver (up) interface. */ +typedef struct PDMIWEBCAMDRV *PPDMIWEBCAMDRV; +/** + * Web camera interface driver provided by the driver to the device, + * i.e. facing upwards. + */ +typedef struct PDMIWEBCAMDRV +{ + /** + * The PDM device is ready to get webcam notifications. + * + * @param pInterface Pointer to the interface. + * @param fReady Whether the device is ready. + */ + DECLR3CALLBACKMEMBER(void, pfnReady,(PPDMIWEBCAMDRV pInterface, bool fReady)); + + /** + * Send a control request to the webcam. + * + * Async response will be returned by pfnWebcamUpControl callback. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface. + * @param pvUser The callers context. + * @param idDevice Unique id for the reported webcam assigned by the driver. + * @param pCtrl The control data. + * @param cbCtrl The size of the control data. + */ + DECLR3CALLBACKMEMBER(int, pfnControl,(PPDMIWEBCAMDRV pInterface, void *pvUser, uint64_t idDevice, + struct VRDEVIDEOINCTRLHDR const *pCtrl, uint32_t cbCtrl)); +} PDMIWEBCAMDRV; +/** Interface ID for PDMIWEBCAMDRV. */ +#define PDMIWEBCAMDRV_IID "0d29b9a1-f4cd-4719-a564-38d5634ba9f8" + + +/** Pointer to the web camera driver/device (down) interface. */ +typedef struct PDMIWEBCAMDEV *PPDMIWEBCAMDEV; +/** + * Web camera interface provided by the device(/driver) interface, + * i.e. facing downwards. + */ +typedef struct PDMIWEBCAMDEV +{ + /** + * A webcam is available. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface. + * @param idDevice Unique id for the reported webcam assigned by the driver. + * @param pDeviceDesc The device description. + * @param cbDeviceDesc The size of the device description. + * @param uVersion The remote video input protocol version. + * @param fCapabilities The remote video input protocol capabilities. + */ + DECLR3CALLBACKMEMBER(int, pfnAttached,(PPDMIWEBCAMDEV pInterface, uint64_t idDevice, + struct VRDEVIDEOINDEVICEDESC const *pDeviceDesc, uint32_t cbDeviceDesc, + uint32_t uVersion, uint32_t fCapabilities)); + + /** + * The webcam is not available anymore. + * + * @param pInterface Pointer to the interface. + * @param idDevice Unique id for the reported webcam assigned by the + * driver. + */ + DECLR3CALLBACKMEMBER(void, pfnDetached,(PPDMIWEBCAMDEV pInterface, uint64_t idDevice)); + + /** + * There is a control response or a control change for the webcam. + * + * @param pInterface Pointer to the interface. + * @param fResponse True if this is a response for a previous pfnWebcamDownControl call. + * @param pvUser The pvUser parameter of the pfnWebcamDownControl call. Undefined if fResponse == false. + * @param idDevice Unique id for the reported webcam assigned by the + * driver. + * @param pCtrl The control data (defined in VRDE). + * @param cbCtrl The size of the control data. + */ + DECLR3CALLBACKMEMBER(void, pfnControl,(PPDMIWEBCAMDEV pInterface, bool fResponse, void *pvUser, + uint64_t idDevice, struct VRDEVIDEOINCTRLHDR const *pCtrl, uint32_t cbCtrl)); + + /** + * A new frame. + * + * @param pInterface Pointer to the interface. + * @param idDevice Unique id for the reported webcam assigned by the driver. + * @param pHeader Payload header (defined in VRDE). + * @param cbHeader Size of the payload header. + * @param pvFrame Frame (image) data. + * @param cbFrame Size of the image data. + */ + DECLR3CALLBACKMEMBER(void, pfnFrame,(PPDMIWEBCAMDEV pInterface, uint64_t idDevice, + struct VRDEVIDEOINPAYLOADHDR const *pHeader, uint32_t cbHeader, + const void *pvFrame, uint32_t cbFrame)); +} PDMIWEBCAMDEV; +/** Interface ID for PDMIWEBCAMDEV. */ +#define PDMIWEBCAMDEV_IID "6ac03e3c-f56c-4a35-80af-c13ce47a9dd7" + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_pdmwebcaminfs_h */ + diff --git a/include/VBox/vmm/pgm.h b/include/VBox/vmm/pgm.h new file mode 100644 index 00000000..133ad827 --- /dev/null +++ b/include/VBox/vmm/pgm.h @@ -0,0 +1,1129 @@ +/** @file + * PGM - Page Monitor / Monitor. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pgm_h +#define VBOX_INCLUDED_vmm_pgm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <VBox/sup.h> +#include <VBox/vmm/vmapi.h> +#include <VBox/vmm/gmm.h> /* for PGMMREGISTERSHAREDMODULEREQ */ +#include <VBox/vmm/hm_vmx.h> +#include <iprt/x86.h> +#include <VBox/param.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pgm The Page Monitor / Manager API + * @ingroup grp_vmm + * @{ + */ + +/** + * 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 pVM The cross context VM structure. + * @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 DECLCALLBACKTYPE(bool, FNPGMRELOCATE,(PVM pVM, RTGCPTR GCPtrOld, RTGCPTR GCPtrNew, PGMRELOCATECALL enmMode, void *pvUser)); +/** Pointer to a relocation callback function. */ +typedef FNPGMRELOCATE *PFNPGMRELOCATE; + + +/** + * Memory access origin. + */ +typedef enum PGMACCESSORIGIN +{ + /** Invalid zero value. */ + PGMACCESSORIGIN_INVALID = 0, + /** IEM is access memory. */ + PGMACCESSORIGIN_IEM, + /** HM is access memory. */ + PGMACCESSORIGIN_HM, + /** Some device is access memory. */ + PGMACCESSORIGIN_DEVICE, + /** Someone debugging is access memory. */ + PGMACCESSORIGIN_DEBUGGER, + /** SELM is access memory. */ + PGMACCESSORIGIN_SELM, + /** FTM is access memory. */ + PGMACCESSORIGIN_FTM, + /** REM is access memory. */ + PGMACCESSORIGIN_REM, + /** IOM is access memory. */ + PGMACCESSORIGIN_IOM, + /** End of valid values. */ + PGMACCESSORIGIN_END, + /** Type size hack. */ + PGMACCESSORIGIN_32BIT_HACK = 0x7fffffff +} PGMACCESSORIGIN; + + +/** + * Physical page access handler kind. + */ +typedef enum PGMPHYSHANDLERKIND +{ + /** Invalid zero value. */ + PGMPHYSHANDLERKIND_INVALID = 0, + /** MMIO range. Pages are not present, all access is done in interpreter or recompiler. */ + PGMPHYSHANDLERKIND_MMIO, + /** Handler all write access to a physical page range. */ + PGMPHYSHANDLERKIND_WRITE, + /** Handler all access to a physical page range. */ + PGMPHYSHANDLERKIND_ALL, + /** End of the valid values. */ + PGMPHYSHANDLERKIND_END, + /** Type size hack. */ + PGMPHYSHANDLERKIND_32BIT_HACK = 0x7fffffff +} PGMPHYSHANDLERKIND; + +/** + * Guest Access type + */ +typedef enum PGMACCESSTYPE +{ + /** Read access. */ + PGMACCESSTYPE_READ = 1, + /** Write access. */ + PGMACCESSTYPE_WRITE +} PGMACCESSTYPE; + + +/** @def PGM_ALL_CB_DECL + * Macro for declaring a handler callback for all contexts. The handler + * callback is static in ring-3, and exported in RC and R0. + * @sa PGM_ALL_CB2_DECL. + */ +#if defined(IN_RC) || defined(IN_RING0) +# ifdef __cplusplus +# define PGM_ALL_CB_DECL(type) extern "C" DECLCALLBACK(DECLEXPORT(type)) +# else +# define PGM_ALL_CB_DECL(type) DECLCALLBACK(DECLEXPORT(type)) +# endif +#else +# define PGM_ALL_CB_DECL(type) static DECLCALLBACK(type) +#endif + +/** @def PGM_ALL_CB2_DECL + * Macro for declaring a handler callback for all contexts. The handler + * callback is hidden in ring-3, and exported in RC and R0. + * @sa PGM_ALL_CB2_DECL. + */ +#if defined(IN_RC) || defined(IN_RING0) +# ifdef __cplusplus +# define PGM_ALL_CB2_DECL(type) extern "C" DECLCALLBACK(DECLEXPORT(type)) +# else +# define PGM_ALL_CB2_DECL(type) DECLCALLBACK(DECLEXPORT(type)) +# endif +#else +# define PGM_ALL_CB2_DECL(type) DECL_HIDDEN_CALLBACK(type) +#endif + +/** @def PGM_ALL_CB2_PROTO + * Macro for declaring a handler callback for all contexts. The handler + * callback is hidden in ring-3, and exported in RC and R0. + * @param fnType The callback function type. + * @sa PGM_ALL_CB2_DECL. + */ +#if defined(IN_RC) || defined(IN_RING0) +# ifdef __cplusplus +# define PGM_ALL_CB2_PROTO(fnType) extern "C" DECLEXPORT(fnType) +# else +# define PGM_ALL_CB2_PROTO(fnType) DECLEXPORT(fnType) +# endif +#else +# define PGM_ALL_CB2_PROTO(fnType) DECLHIDDEN(fnType) +#endif + + +/** + * \#PF Handler callback for physical access handler ranges in RC and R0. + * + * @returns Strict VBox status code (appropriate for ring-0 and raw-mode). + * @param pVM The cross context VM structure. + * @param pVCpu The cross context virtual CPU structure of the calling EMT. + * @param uErrorCode CPU Error code. + * @param pCtx Pointer to the register context for the CPU. + * @param pvFault The fault address (cr2). + * @param GCPhysFault The GC physical address corresponding to pvFault. + * @param uUser User argument (not a pointer). + * @thread EMT(pVCpu) + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNPGMRZPHYSPFHANDLER,(PVMCC pVM, PVMCPUCC pVCpu, RTGCUINT uErrorCode, PCPUMCTX pCtx, + RTGCPTR pvFault, RTGCPHYS GCPhysFault, uint64_t uUser)); +/** Pointer to PGM access callback. */ +typedef FNPGMRZPHYSPFHANDLER *PFNPGMRZPHYSPFHANDLER; + + +/** + * Access handler callback for physical access handler ranges. + * + * The handler can not raise any faults, it's mainly for monitoring write access + * to certain pages (like MMIO). + * + * @returns Strict VBox status code in ring-0 and raw-mode context, in ring-3 + * the only supported informational status code is + * VINF_PGM_HANDLER_DO_DEFAULT. + * @retval VINF_SUCCESS if the handler have carried out the operation. + * @retval VINF_PGM_HANDLER_DO_DEFAULT if the caller should carry out the + * access operation. + * @retval VINF_EM_XXX in ring-0 and raw-mode context. + * + * @param pVM The cross context VM structure. + * @param pVCpu The cross context virtual CPU structure of the calling EMT. + * @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 enmOrigin The origin of this call. + * @param uUser User argument (not a pointer). + * @thread EMT(pVCpu) + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNPGMPHYSHANDLER,(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhys, void *pvPhys, + void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType, + PGMACCESSORIGIN enmOrigin, uint64_t uUser)); +/** Pointer to PGM access callback. */ +typedef FNPGMPHYSHANDLER *PFNPGMPHYSHANDLER; + + +/** + * Paging mode. + * + * @note Part of saved state. Change with extreme care. + */ +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, + /** 32-bit nested paging mode (shadow only; guest physical to host physical). */ + PGMMODE_NESTED_32BIT, + /** PAE nested paging mode (shadow only; guest physical to host physical). */ + PGMMODE_NESTED_PAE, + /** AMD64 nested paging mode (shadow only; guest physical to host physical). */ + PGMMODE_NESTED_AMD64, + /** Extended paging (Intel) mode. */ + PGMMODE_EPT, + /** Special mode used by NEM to indicate no shadow paging necessary. */ + PGMMODE_NONE, + /** The max number of modes */ + PGMMODE_MAX, + /** 32bit hackishness. */ + PGMMODE_32BIT_HACK = 0x7fffffff +} PGMMODE; + +/** + * Second level address translation (SLAT) mode. + */ +typedef enum PGMSLAT +{ + /** The usual invalid value. */ + PGMSLAT_INVALID = 0, + /** No second level translation. */ + PGMSLAT_DIRECT, + /** Intel Extended Page Tables (EPT). */ + PGMSLAT_EPT, + /** AMD-V Nested Paging 32-bit. */ + PGMSLAT_32BIT, + /** AMD-V Nested Paging PAE. */ + PGMSLAT_PAE, + /** AMD-V Nested Paging 64-bit. */ + PGMSLAT_AMD64, + /** 32bit hackishness. */ + PGMSLAT_32BIT_HACK = 0x7fffffff +} PGMSLAT; + + +/** @name PGMPTWALK::fFailed flags. + * These flags indicate the type of a page-walk failure. + * @{ + */ +typedef uint32_t PGMWALKFAIL; +/** Regular page fault (MBZ since guest Walk code don't set these explicitly). */ +#define PGM_WALKFAIL_PAGE_FAULT UINT32_C(0) +/** EPT violation - Intel. */ +#define PGM_WALKFAIL_EPT_VIOLATION RT_BIT_32(0) +/** EPT violation, convertible to \#VE exception - Intel. */ +#define PGM_WALKFAIL_EPT_VIOLATION_CONVERTIBLE RT_BIT_32(1) +/** EPT misconfiguration - Intel. */ +#define PGM_WALKFAIL_EPT_MISCONFIG RT_BIT_32(2) + +/** Mask of all EPT induced page-walk failures - Intel. */ +#define PGM_WALKFAIL_EPT ( PGM_WALKFAIL_EPT_VIOLATION \ + | PGM_WALKFAIL_EPT_VIOLATION_CONVERTIBLE \ + | PGM_WALKFAIL_EPT_MISCONFIG) +/** @} */ + + +/** @name PGMPTATTRS - PGM page-table attributes. + * + * This is VirtualBox's combined page table attributes. It combines regular page + * table and Intel EPT attributes. It's 64-bit in size so there's ample room for + * bits added in the future to EPT or regular page tables (for e.g. Protection Key). + * + * The following bits map 1:1 (shifted by PGM_PTATTRS_EPT_SHIFT) to the Intel EPT + * attributes as these are unique to EPT and fit within 64-bits despite the shift: + * - EPT_R : Read access. + * - EPT_W : Write access. + * - EPT_X_SUPER : Execute or execute for supervisor-mode linear addr access. + * - EPT_MEMTYPE : EPT memory type. + * - EPT_IGNORE_PAT: Ignore PAT memory type. + * - EPT_X_USER : Execute access for user-mode linear addresses. + * + * For regular page tables, the R bit is always 1 (same as P bit). + * For Intel EPT, the EPT_R and EPT_W bits are copied to R and W bits respectively. + * + * The following EPT attributes are mapped to the following positions because they + * exist in the regular page tables at these positions OR are exclusive to EPT and + * have been mapped to arbitrarily chosen positions: + * - EPT_A : Accessed (EPT bit 8 maps to bit 5). + * - EPT_D : Dirty (EPT bit 9 maps to bit 6). + * - EPT_SUPER_SHW_STACK : Supervisor Shadow Stack (EPT bit 60 maps to bit 24). + * - EPT_SUPPRESS_VE_XCPT: Suppress \#VE exception (EPT bit 63 maps to bit 25). + * + * Bits 12, 11:9 and 43 are deliberately kept unused (correspond to bit PS and bits + * 11:9 in the regular page-table structures and to bit 11 in the EPT structures + * respectively) as bit 12 is the page-size bit and bits 11:9 are reserved for + * use by software and we may want to use/preserve them in the future. + * + * @{ */ +typedef uint64_t PGMPTATTRS; +/** Pointer to a PGMPTATTRS type. */ +typedef PGMPTATTRS *PPGMPTATTRS; + +/** Read bit (always 1 for regular PT, copy of EPT_R for EPT). */ +#define PGM_PTATTRS_R_SHIFT 0 +#define PGM_PTATTRS_R_MASK RT_BIT_64(PGM_PTATTRS_R_SHIFT) +/** Write access bit (aka read/write bit for regular PT). */ +#define PGM_PTATTRS_W_SHIFT 1 +#define PGM_PTATTRS_W_MASK RT_BIT_64(PGM_PTATTRS_W_SHIFT) +/** User-mode access bit. */ +#define PGM_PTATTRS_US_SHIFT 2 +#define PGM_PTATTRS_US_MASK RT_BIT_64(PGM_PTATTRS_US_SHIFT) +/** Write through cache bit. */ +#define PGM_PTATTRS_PWT_SHIFT 3 +#define PGM_PTATTRS_PWT_MASK RT_BIT_64(PGM_PTATTRS_PWT_SHIFT) +/** Cache disabled bit. */ +#define PGM_PTATTRS_PCD_SHIFT 4 +#define PGM_PTATTRS_PCD_MASK RT_BIT_64(PGM_PTATTRS_PCD_SHIFT) +/** Accessed bit. */ +#define PGM_PTATTRS_A_SHIFT 5 +#define PGM_PTATTRS_A_MASK RT_BIT_64(PGM_PTATTRS_A_SHIFT) +/** Dirty bit. */ +#define PGM_PTATTRS_D_SHIFT 6 +#define PGM_PTATTRS_D_MASK RT_BIT_64(PGM_PTATTRS_D_SHIFT) +/** The PAT bit. */ +#define PGM_PTATTRS_PAT_SHIFT 7 +#define PGM_PTATTRS_PAT_MASK RT_BIT_64(PGM_PTATTRS_PAT_SHIFT) +/** The global bit. */ +#define PGM_PTATTRS_G_SHIFT 8 +#define PGM_PTATTRS_G_MASK RT_BIT_64(PGM_PTATTRS_G_SHIFT) +/** Reserved (bits 12:9) unused. */ +#define PGM_PTATTRS_RSVD_12_9_SHIFT 9 +#define PGM_PTATTRS_RSVD_12_9_MASK UINT64_C(0x0000000000001e00) +/** Read access bit - EPT only. */ +#define PGM_PTATTRS_EPT_R_SHIFT 13 +#define PGM_PTATTRS_EPT_R_MASK RT_BIT_64(PGM_PTATTRS_EPT_R_SHIFT) +/** Write access bit - EPT only. */ +#define PGM_PTATTRS_EPT_W_SHIFT 14 +#define PGM_PTATTRS_EPT_W_MASK RT_BIT_64(PGM_PTATTRS_EPT_W_SHIFT) +/** Execute or execute access for supervisor-mode linear addresses - EPT only. */ +#define PGM_PTATTRS_EPT_X_SUPER_SHIFT 15 +#define PGM_PTATTRS_EPT_X_SUPER_MASK RT_BIT_64(PGM_PTATTRS_EPT_X_SUPER_SHIFT) +/** EPT memory type - EPT only. */ +#define PGM_PTATTRS_EPT_MEMTYPE_SHIFT 16 +#define PGM_PTATTRS_EPT_MEMTYPE_MASK UINT64_C(0x0000000000070000) +/** Ignore PAT memory type - EPT only. */ +#define PGM_PTATTRS_EPT_IGNORE_PAT_SHIFT 19 +#define PGM_PTATTRS_EPT_IGNORE_PAT_MASK RT_BIT_64(PGM_PTATTRS_EPT_IGNORE_PAT_SHIFT) +/** Leaf paging entry (big or regular) - EPT only. */ +#define PGM_PTATTRS_EPT_LEAF_SHIFT 20 +#define PGM_PTATTRS_EPT_LEAF_MASK RT_BIT_64(PGM_PTATTRS_EPT_LEAF_SHIFT) +/** Accessed bit - EPT only. */ +#define PGM_PTATTRS_EPT_A_SHIFT 21 +#define PGM_PTATTRS_EPT_A_MASK RT_BIT_64(PGM_PTATTRS_EPT_A_SHIFT) +/** Dirty bit - EPT only. */ +#define PGM_PTATTRS_EPT_D_SHIFT 22 +#define PGM_PTATTRS_EPT_D_MASK RT_BIT_64(PGM_PTATTRS_EPT_D_SHIFT) +/** Execute access for user-mode linear addresses - EPT only. */ +#define PGM_PTATTRS_EPT_X_USER_SHIFT 23 +#define PGM_PTATTRS_EPT_X_USER_MASK RT_BIT_64(PGM_PTATTRS_EPT_X_USER_SHIFT) +/** Reserved (bits 29:24) - unused. */ +#define PGM_PTATTRS_RSVD_29_24_SHIFT 24 +#define PGM_PTATTRS_RSVD_29_24_MASK UINT64_C(0x000000003f000000) +/** Verify Guest Paging - EPT only. */ +#define PGM_PTATTRS_EPT_VGP_SHIFT 30 +#define PGM_PTATTRS_EPT_VGP_MASK RT_BIT_64(PGM_PTATTRS_EPT_VGP_SHIFT) +/** Paging-write - EPT only. */ +#define PGM_PTATTRS_EPT_PW_SHIFT 31 +#define PGM_PTATTRS_EPT_PW_MASK RT_BIT_64(PGM_PTATTRS_EPT_PW_SHIFT) +/** Reserved (bit 32) - unused. */ +#define PGM_PTATTRS_RSVD_32_SHIFT 32 +#define PGM_PTATTRS_RSVD_32_MASK UINT64_C(0x0000000100000000) +/** Supervisor shadow stack - EPT only. */ +#define PGM_PTATTRS_EPT_SSS_SHIFT 33 +#define PGM_PTATTRS_EPT_SSS_MASK RT_BIT_64(PGM_PTATTRS_EPT_SSS_SHIFT) +/** Sub-page write permission - EPT only. */ +#define PGM_PTATTRS_EPT_SPP_SHIFT 34 +#define PGM_PTATTRS_EPT_SPP_MASK RT_BIT_64(PGM_PTATTRS_EPT_SPP_SHIFT) +/** Reserved (bit 35) - unused. */ +#define PGM_PTATTRS_RSVD_35_SHIFT 35 +#define PGM_PTATTRS_RSVD_35_MASK UINT64_C(0x0000000800000000) +/** Suppress \#VE exception - EPT only. */ +#define PGM_PTATTRS_EPT_SVE_SHIFT 36 +#define PGM_PTATTRS_EPT_SVE_MASK RT_BIT_64(PGM_PTATTRS_EPT_SVE_SHIFT) +/** Reserved (bits 62:37) - unused. */ +#define PGM_PTATTRS_RSVD_62_37_SHIFT 37 +#define PGM_PTATTRS_RSVD_62_37_MASK UINT64_C(0x7fffffe000000000) +/** No-execute bit. */ +#define PGM_PTATTRS_NX_SHIFT 63 +#define PGM_PTATTRS_NX_MASK RT_BIT_64(PGM_PTATTRS_NX_SHIFT) + +RT_BF_ASSERT_COMPILE_CHECKS(PGM_PTATTRS_, UINT64_C(0), UINT64_MAX, + (R, W, US, PWT, PCD, A, D, PAT, G, RSVD_12_9, EPT_R, EPT_W, EPT_X_SUPER, EPT_MEMTYPE, EPT_IGNORE_PAT, + EPT_LEAF, EPT_A, EPT_D, EPT_X_USER, RSVD_29_24, EPT_VGP, EPT_PW, RSVD_32, EPT_SSS, EPT_SPP, + RSVD_35, EPT_SVE, RSVD_62_37, NX)); + +/** The bit position where the EPT specific attributes begin. */ +#define PGM_PTATTRS_EPT_SHIFT PGM_PTATTRS_EPT_R_SHIFT +/** The mask of EPT bits (bits 36:ATTR_SHIFT). In the future we might choose to + * use higher unused bits for something else, in that case adjust this mask. */ +#define PGM_PTATTRS_EPT_MASK UINT64_C(0x0000001fffffe000) + +/** The mask of all PGM page attribute bits for regular page-tables. */ +#define PGM_PTATTRS_PT_VALID_MASK ( PGM_PTATTRS_R_MASK \ + | PGM_PTATTRS_W_MASK \ + | PGM_PTATTRS_US_MASK \ + | PGM_PTATTRS_PWT_MASK \ + | PGM_PTATTRS_PCD_MASK \ + | PGM_PTATTRS_A_MASK \ + | PGM_PTATTRS_D_MASK \ + | PGM_PTATTRS_PAT_MASK \ + | PGM_PTATTRS_G_MASK \ + | PGM_PTATTRS_NX_MASK) + +/** The mask of all PGM page attribute bits for EPT. */ +#define PGM_PTATTRS_EPT_VALID_MASK ( PGM_PTATTRS_EPT_R_MASK \ + | PGM_PTATTRS_EPT_W_MASK \ + | PGM_PTATTRS_EPT_X_SUPER_MASK \ + | PGM_PTATTRS_EPT_MEMTYPE_MASK \ + | PGM_PTATTRS_EPT_IGNORE_PAT_MASK \ + | PGM_PTATTRS_EPT_LEAF_MASK \ + | PGM_PTATTRS_EPT_A_MASK \ + | PGM_PTATTRS_EPT_D_MASK \ + | PGM_PTATTRS_EPT_X_USER_MASK \ + | PGM_PTATTRS_EPT_VGP_MASK \ + | PGM_PTATTRS_EPT_PW_MASK \ + | PGM_PTATTRS_EPT_SSS_MASK \ + | PGM_PTATTRS_EPT_SPP_MASK \ + | PGM_PTATTRS_EPT_SVE_MASK) + +/* The mask of all PGM page attribute bits (combined). */ +#define PGM_PTATTRS_VALID_MASK (PGM_PTATTRS_PT_VALID_MASK | PGM_PTATTRS_EPT_VALID_MASK) + +/* Verify bits match the regular PT bits. */ +AssertCompile(PGM_PTATTRS_W_SHIFT == X86_PTE_BIT_RW); +AssertCompile(PGM_PTATTRS_US_SHIFT == X86_PTE_BIT_US); +AssertCompile(PGM_PTATTRS_PWT_SHIFT == X86_PTE_BIT_PWT); +AssertCompile(PGM_PTATTRS_PCD_SHIFT == X86_PTE_BIT_PCD); +AssertCompile(PGM_PTATTRS_A_SHIFT == X86_PTE_BIT_A); +AssertCompile(PGM_PTATTRS_D_SHIFT == X86_PTE_BIT_D); +AssertCompile(PGM_PTATTRS_PAT_SHIFT == X86_PTE_BIT_PAT); +AssertCompile(PGM_PTATTRS_G_SHIFT == X86_PTE_BIT_G); +AssertCompile(PGM_PTATTRS_W_MASK == X86_PTE_RW); +AssertCompile(PGM_PTATTRS_US_MASK == X86_PTE_US); +AssertCompile(PGM_PTATTRS_PWT_MASK == X86_PTE_PWT); +AssertCompile(PGM_PTATTRS_PCD_MASK == X86_PTE_PCD); +AssertCompile(PGM_PTATTRS_A_MASK == X86_PTE_A); +AssertCompile(PGM_PTATTRS_D_MASK == X86_PTE_D); +AssertCompile(PGM_PTATTRS_PAT_MASK == X86_PTE_PAT); +AssertCompile(PGM_PTATTRS_G_MASK == X86_PTE_G); +AssertCompile(PGM_PTATTRS_NX_MASK == X86_PTE_PAE_NX); + +/* Verify those EPT bits that must map 1:1 (after shifting). */ +AssertCompile(PGM_PTATTRS_EPT_R_SHIFT - PGM_PTATTRS_EPT_SHIFT == EPT_E_BIT_READ); +AssertCompile(PGM_PTATTRS_EPT_W_SHIFT - PGM_PTATTRS_EPT_SHIFT == EPT_E_BIT_WRITE); +AssertCompile(PGM_PTATTRS_EPT_X_SUPER_SHIFT - PGM_PTATTRS_EPT_SHIFT == EPT_E_BIT_EXECUTE); +AssertCompile(PGM_PTATTRS_EPT_IGNORE_PAT_SHIFT - PGM_PTATTRS_EPT_SHIFT == EPT_E_BIT_IGNORE_PAT); +AssertCompile(PGM_PTATTRS_EPT_X_USER_SHIFT - PGM_PTATTRS_EPT_SHIFT == EPT_E_BIT_USER_EXECUTE); +/** @} */ + + +/** + * Page table walk information. + * + * This provides extensive information regarding page faults (or EPT + * violations/misconfigurations) while traversing page tables. + */ +typedef struct PGMPTWALK +{ + /** The linear address that is being resolved (input). */ + RTGCPTR GCPtr; + + /** The second-level physical address (input/output). + * @remarks only valid if fIsSlat is set. */ + RTGCPHYS GCPhysNested; + + /** The physical address that is the result of the walk (output). */ + RTGCPHYS GCPhys; + + /** Set if the walk succeeded. */ + bool fSucceeded; + /** Whether this is a second-level address translation. */ + bool fIsSlat; + /** Whether the linear address (GCPtr) caused the second-level + * address translation. */ + bool fIsLinearAddrValid; + /** The level problem arrised at. + * PTE is level 1, PDE is level 2, PDPE is level 3, PML4 is level 4, CR3 is + * level 8. This is 0 on success. */ + uint8_t uLevel; + /** Set if the page isn't present. */ + bool fNotPresent; + /** Encountered a bad physical address. */ + bool fBadPhysAddr; + /** Set if there was reserved bit violations. */ + bool fRsvdError; + /** Set if it involves a big page (2/4 MB). */ + bool fBigPage; + /** Set if it involves a gigantic page (1 GB). */ + bool fGigantPage; + bool afPadding[3]; + /** Page-walk failure type, PGM_WALKFAIL_XXX. */ + PGMWALKFAIL fFailed; + + /** The effective page-table attributes, PGM_PTATTRS_XXX. */ + PGMPTATTRS fEffective; +} PGMPTWALK; +/** Pointer to page walk information. */ +typedef PGMPTWALK *PPGMPTWALK; +/** Pointer to const page walk information. */ +typedef PGMPTWALK const *PCPGMPTWALK; + + +/** 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) + +/** Macro for checking if it's one of the AMD64 nested modes. + * @param enmMode PGMMODE_*. + */ +#define PGMMODE_IS_NESTED(enmMode) ( (enmMode) == PGMMODE_NESTED_32BIT \ + || (enmMode) == PGMMODE_NESTED_PAE \ + || (enmMode) == PGMMODE_NESTED_AMD64) + +/** Macro for checking if it's one of the PAE modes. + * @param enmMode PGMMODE_*. + */ +#define PGMMODE_IS_PAE(enmMode) ( (enmMode) == PGMMODE_PAE \ + || (enmMode) == PGMMODE_PAE_NX) + +/** + * 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(PVMCC pVM); + +VMMDECL(int) PGMRegisterStringFormatTypes(void); +VMMDECL(void) PGMDeregisterStringFormatTypes(void); +VMMDECL(RTHCPHYS) PGMGetHyperCR3(PVMCPU pVCpu); +VMMDECL(int) PGMTrap0eHandler(PVMCPUCC pVCpu, RTGCUINT uErr, PCPUMCTX pCtx, RTGCPTR pvFault); +VMMDECL(int) PGMPrefetchPage(PVMCPUCC pVCpu, RTGCPTR GCPtrPage); +VMMDECL(VBOXSTRICTRC) PGMInterpretInstruction(PVMCPUCC pVCpu, RTGCPTR pvFault); +VMMDECL(int) PGMShwGetPage(PVMCPUCC pVCpu, RTGCPTR GCPtr, uint64_t *pfFlags, PRTHCPHYS pHCPhys); +VMMDECL(int) PGMShwMakePageReadonly(PVMCPUCC pVCpu, RTGCPTR GCPtr, uint32_t fFlags); +VMMDECL(int) PGMShwMakePageWritable(PVMCPUCC pVCpu, RTGCPTR GCPtr, uint32_t fFlags); +VMMDECL(int) PGMShwMakePageNotPresent(PVMCPUCC 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(PVMCPUCC pVCpu, RTGCPTR GCPtr, PPGMPTWALK pWalk); +VMMDECL(int) PGMGstModifyPage(PVMCPUCC pVCpu, RTGCPTR GCPtr, size_t cb, uint64_t fFlags, uint64_t fMask); +VMM_INT_DECL(bool) PGMGstArePaePdpesValid(PVMCPUCC pVCpu, PCX86PDPE paPaePdpes); +VMM_INT_DECL(int) PGMGstMapPaePdpes(PVMCPUCC pVCpu, PCX86PDPE paPaePdpes); +VMM_INT_DECL(int) PGMGstMapPaePdpesAtCr3(PVMCPUCC pVCpu, uint64_t cr3); + +VMMDECL(int) PGMInvalidatePage(PVMCPUCC pVCpu, RTGCPTR GCPtrPage); +VMMDECL(int) PGMFlushTLB(PVMCPUCC pVCpu, uint64_t cr3, bool fGlobal); +VMMDECL(int) PGMSyncCR3(PVMCPUCC pVCpu, uint64_t cr0, uint64_t cr3, uint64_t cr4, bool fGlobal); +VMMDECL(int) PGMUpdateCR3(PVMCPUCC pVCpu, uint64_t cr3); +VMMDECL(int) PGMChangeMode(PVMCPUCC pVCpu, uint64_t cr0, uint64_t cr4, uint64_t efer, bool fForce); +VMM_INT_DECL(int) PGMHCChangeMode(PVMCC pVM, PVMCPUCC pVCpu, PGMMODE enmGuestMode, bool fForce); +VMMDECL(void) PGMCr0WpEnabled(PVMCPUCC pVCpu); +VMMDECL(PGMMODE) PGMGetGuestMode(PVMCPU pVCpu); +VMMDECL(PGMMODE) PGMGetShadowMode(PVMCPU pVCpu); +VMMDECL(PGMMODE) PGMGetHostMode(PVM pVM); +VMMDECL(const char *) PGMGetModeName(PGMMODE enmMode); +#ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT +VMM_INT_DECL(const char *) PGMGetSlatModeName(PGMSLAT enmSlatMode); +#endif +VMM_INT_DECL(RTGCPHYS) PGMGetGuestCR3Phys(PVMCPU pVCpu); +VMM_INT_DECL(void) PGMNotifyNxeChanged(PVMCPU pVCpu, bool fNxe); +VMMDECL(bool) PGMHasDirtyPages(PVM pVM); +VMM_INT_DECL(void) PGMSetGuestEptPtr(PVMCPUCC pVCpu, uint64_t uEptPtr); + +/** PGM physical access handler type registration handle (heap offset, valid + * cross contexts without needing fixing up). Callbacks and handler type is + * associated with this and it is shared by all handler registrations. */ +typedef uint64_t PGMPHYSHANDLERTYPE; +/** Pointer to a PGM physical handler type registration handle. */ +typedef PGMPHYSHANDLERTYPE *PPGMPHYSHANDLERTYPE; +/** NIL value for PGM physical access handler type handle. */ +#define NIL_PGMPHYSHANDLERTYPE UINT64_MAX +VMMDECL(int) PGMHandlerPhysicalRegister(PVMCC pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast, PGMPHYSHANDLERTYPE hType, + uint64_t uUser, R3PTRTYPE(const char *) pszDesc); +VMMDECL(int) PGMHandlerPhysicalModify(PVMCC pVM, RTGCPHYS GCPhysCurrent, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast); +VMMDECL(int) PGMHandlerPhysicalDeregister(PVMCC pVM, RTGCPHYS GCPhys); +VMMDECL(int) PGMHandlerPhysicalChangeUserArg(PVMCC pVM, RTGCPHYS GCPhys, uint64_t uUser); +VMMDECL(int) PGMHandlerPhysicalSplit(PVMCC pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysSplit); +VMMDECL(int) PGMHandlerPhysicalJoin(PVMCC pVM, RTGCPHYS GCPhys1, RTGCPHYS GCPhys2); +VMMDECL(int) PGMHandlerPhysicalPageTempOff(PVMCC pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysPage); +VMMDECL(int) PGMHandlerPhysicalPageAliasMmio2(PVMCC pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysPage, + PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2, RTGCPHYS offMMio2PageRemap); +VMMDECL(int) PGMHandlerPhysicalPageAliasHC(PVMCC pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysPage, RTHCPHYS HCPhysPageRemap); +VMMDECL(int) PGMHandlerPhysicalReset(PVMCC pVM, RTGCPHYS GCPhys); +VMMDECL(bool) PGMHandlerPhysicalIsRegistered(PVMCC pVM, RTGCPHYS GCPhys); + +/** @name PGMPHYSHANDLER_F_XXX - flags for PGMR3HandlerPhysicalTypeRegister and PGMR0HandlerPhysicalTypeRegister + * @{ */ +/** Whether to hold the PGM lock while calling the handler or not. + * Mainly an optimization for PGM callers. */ +#define PGMPHYSHANDLER_F_KEEP_PGM_LOCK RT_BIT_32(0) +/** The uUser value is a ring-0 device instance index that needs translating + * into a PDMDEVINS pointer before calling the handler. This is a hack to make + * it possible to use access handlers in devices. */ +#define PGMPHYSHANDLER_F_R0_DEVINS_IDX RT_BIT_32(1) +/** Don't apply the access handler to VT-x and AMD-V. Only works with full pages. + * This is a trick for the VT-x APIC access page in nested VT-x setups. */ +#define PGMPHYSHANDLER_F_NOT_IN_HM RT_BIT_32(2) +/** Mask of valid bits. */ +#define PGMPHYSHANDLER_F_VALID_MASK UINT32_C(7) +/** @} */ + + +/** + * Page type. + * + * @remarks This enum has to fit in a 3-bit field (see PGMPAGE::u3Type). + * @remarks This is used in the saved state, so changes to it requires bumping + * the saved state version. + * @todo So, convert to \#defines! + */ +typedef enum PGMPAGETYPE +{ + /** The usual invalid zero entry. */ + PGMPAGETYPE_INVALID = 0, + /** RAM page. (RWX) */ + PGMPAGETYPE_RAM, + /** MMIO2 page. (RWX) */ + PGMPAGETYPE_MMIO2, + /** MMIO2 page aliased over an MMIO page. (RWX) + * See PGMHandlerPhysicalPageAlias(). */ + PGMPAGETYPE_MMIO2_ALIAS_MMIO, + /** Special page aliased over an MMIO page. (RWX) + * See PGMHandlerPhysicalPageAliasHC(), but this is generally only used for + * VT-x's APIC access page at the moment. Treated as MMIO by everyone except + * the shadow paging code. */ + PGMPAGETYPE_SPECIAL_ALIAS_MMIO, + /** Shadowed ROM. (RWX) */ + PGMPAGETYPE_ROM_SHADOW, + /** ROM page. (R-X) */ + PGMPAGETYPE_ROM, + /** MMIO page. (---) */ + PGMPAGETYPE_MMIO, + /** End of valid entries. */ + PGMPAGETYPE_END +} PGMPAGETYPE; +AssertCompile(PGMPAGETYPE_END == 8); + +/** @name PGM page type predicates. + * @{ */ +#define PGMPAGETYPE_IS_READABLE(a_enmType) ( (a_enmType) <= PGMPAGETYPE_ROM ) +#define PGMPAGETYPE_IS_WRITEABLE(a_enmType) ( (a_enmType) <= PGMPAGETYPE_ROM_SHADOW ) +#define PGMPAGETYPE_IS_RWX(a_enmType) ( (a_enmType) <= PGMPAGETYPE_ROM_SHADOW ) +#define PGMPAGETYPE_IS_ROX(a_enmType) ( (a_enmType) == PGMPAGETYPE_ROM ) +#define PGMPAGETYPE_IS_NP(a_enmType) ( (a_enmType) == PGMPAGETYPE_MMIO ) +/** @} */ + + +VMM_INT_DECL(PGMPAGETYPE) PGMPhysGetPageType(PVMCC pVM, RTGCPHYS GCPhys); + +VMM_INT_DECL(int) PGMPhysGCPhys2HCPhys(PVMCC pVM, RTGCPHYS GCPhys, PRTHCPHYS pHCPhys); +VMM_INT_DECL(int) PGMPhysGCPtr2HCPhys(PVMCPUCC pVCpu, RTGCPTR GCPtr, PRTHCPHYS pHCPhys); +VMM_INT_DECL(int) PGMPhysGCPhys2CCPtr(PVMCC pVM, RTGCPHYS GCPhys, void **ppv, PPGMPAGEMAPLOCK pLock); +VMM_INT_DECL(int) PGMPhysGCPhys2CCPtrReadOnly(PVMCC pVM, RTGCPHYS GCPhys, void const **ppv, PPGMPAGEMAPLOCK pLock); +VMM_INT_DECL(int) PGMPhysGCPtr2CCPtr(PVMCPU pVCpu, RTGCPTR GCPtr, void **ppv, PPGMPAGEMAPLOCK pLock); +VMM_INT_DECL(int) PGMPhysGCPtr2CCPtrReadOnly(PVMCPUCC pVCpu, RTGCPTR GCPtr, void const **ppv, PPGMPAGEMAPLOCK pLock); + +VMMDECL(bool) PGMPhysIsA20Enabled(PVMCPU pVCpu); +VMMDECL(bool) PGMPhysIsGCPhysValid(PVMCC pVM, RTGCPHYS GCPhys); +VMMDECL(bool) PGMPhysIsGCPhysNormal(PVMCC pVM, RTGCPHYS GCPhys); +VMMDECL(int) PGMPhysGCPtr2GCPhys(PVMCPUCC pVCpu, RTGCPTR GCPtr, PRTGCPHYS pGCPhys); +VMMDECL(void) PGMPhysReleasePageMappingLock(PVMCC pVM, PPGMPAGEMAPLOCK pLock); +VMMDECL(void) PGMPhysBulkReleasePageMappingLocks(PVMCC pVM, uint32_t cPages, PPGMPAGEMAPLOCK paLock); + +/** @def PGM_PHYS_RW_IS_SUCCESS + * Check whether a PGMPhysRead, PGMPhysWrite, PGMPhysReadGCPtr or + * PGMPhysWriteGCPtr call completed the given task. + * + * @returns true if completed, false if not. + * @param a_rcStrict The status code. + * @sa IOM_SUCCESS + */ +#ifdef IN_RING3 +# define PGM_PHYS_RW_IS_SUCCESS(a_rcStrict) \ + ( (a_rcStrict) == VINF_SUCCESS \ + || (a_rcStrict) == VINF_EM_DBG_STOP \ + || (a_rcStrict) == VINF_EM_DBG_EVENT \ + || (a_rcStrict) == VINF_EM_DBG_BREAKPOINT \ + ) +#elif defined(IN_RING0) +# define PGM_PHYS_RW_IS_SUCCESS(a_rcStrict) \ + ( (a_rcStrict) == VINF_SUCCESS \ + || (a_rcStrict) == VINF_IOM_R3_MMIO_COMMIT_WRITE \ + || (a_rcStrict) == VINF_EM_OFF \ + || (a_rcStrict) == VINF_EM_SUSPEND \ + || (a_rcStrict) == VINF_EM_RESET \ + || (a_rcStrict) == VINF_EM_HALT \ + || (a_rcStrict) == VINF_EM_DBG_STOP \ + || (a_rcStrict) == VINF_EM_DBG_EVENT \ + || (a_rcStrict) == VINF_EM_DBG_BREAKPOINT \ + ) +#elif defined(IN_RC) +# define PGM_PHYS_RW_IS_SUCCESS(a_rcStrict) \ + ( (a_rcStrict) == VINF_SUCCESS \ + || (a_rcStrict) == VINF_IOM_R3_MMIO_COMMIT_WRITE \ + || (a_rcStrict) == VINF_EM_OFF \ + || (a_rcStrict) == VINF_EM_SUSPEND \ + || (a_rcStrict) == VINF_EM_RESET \ + || (a_rcStrict) == VINF_EM_HALT \ + || (a_rcStrict) == VINF_SELM_SYNC_GDT \ + || (a_rcStrict) == VINF_EM_RAW_EMULATE_INSTR_GDT_FAULT \ + || (a_rcStrict) == VINF_EM_DBG_STOP \ + || (a_rcStrict) == VINF_EM_DBG_EVENT \ + || (a_rcStrict) == VINF_EM_DBG_BREAKPOINT \ + ) +#endif +/** @def PGM_PHYS_RW_DO_UPDATE_STRICT_RC + * Updates the return code with a new result. + * + * Both status codes must be successes according to PGM_PHYS_RW_IS_SUCCESS. + * + * @param a_rcStrict The current return code, to be updated. + * @param a_rcStrict2 The new return code to merge in. + */ +#ifdef IN_RING3 +# define PGM_PHYS_RW_DO_UPDATE_STRICT_RC(a_rcStrict, a_rcStrict2) \ + do { \ + Assert(rcStrict == VINF_SUCCESS); \ + Assert(rcStrict2 == VINF_SUCCESS); \ + } while (0) +#elif defined(IN_RING0) +# define PGM_PHYS_RW_DO_UPDATE_STRICT_RC(a_rcStrict, a_rcStrict2) \ + do { \ + Assert(PGM_PHYS_RW_IS_SUCCESS(rcStrict)); \ + Assert(PGM_PHYS_RW_IS_SUCCESS(rcStrict2)); \ + AssertCompile(VINF_IOM_R3_MMIO_COMMIT_WRITE > VINF_EM_LAST); \ + if ((a_rcStrict2) == VINF_SUCCESS || (a_rcStrict) == (a_rcStrict2)) \ + { /* likely */ } \ + else if ( (a_rcStrict) == VINF_SUCCESS \ + || (a_rcStrict) > (a_rcStrict2)) \ + (a_rcStrict) = (a_rcStrict2); \ + } while (0) +#elif defined(IN_RC) +# define PGM_PHYS_RW_DO_UPDATE_STRICT_RC(a_rcStrict, a_rcStrict2) \ + do { \ + Assert(PGM_PHYS_RW_IS_SUCCESS(rcStrict)); \ + Assert(PGM_PHYS_RW_IS_SUCCESS(rcStrict2)); \ + AssertCompile(VINF_SELM_SYNC_GDT > VINF_EM_LAST); \ + AssertCompile(VINF_EM_RAW_EMULATE_INSTR_GDT_FAULT > VINF_EM_LAST); \ + AssertCompile(VINF_EM_RAW_EMULATE_INSTR_GDT_FAULT < VINF_SELM_SYNC_GDT); \ + AssertCompile(VINF_IOM_R3_MMIO_COMMIT_WRITE > VINF_EM_LAST); \ + AssertCompile(VINF_IOM_R3_MMIO_COMMIT_WRITE > VINF_SELM_SYNC_GDT); \ + AssertCompile(VINF_IOM_R3_MMIO_COMMIT_WRITE > VINF_EM_RAW_EMULATE_INSTR_GDT_FAULT); \ + if ((a_rcStrict2) == VINF_SUCCESS || (a_rcStrict) == (a_rcStrict2)) \ + { /* likely */ } \ + else if ((a_rcStrict) == VINF_SUCCESS) \ + (a_rcStrict) = (a_rcStrict2); \ + else if ( ( (a_rcStrict) > (a_rcStrict2) \ + && ( (a_rcStrict2) <= VINF_EM_RESET \ + || (a_rcStrict) != VINF_EM_RAW_EMULATE_INSTR_GDT_FAULT) ) \ + || ( (a_rcStrict2) == VINF_EM_RAW_EMULATE_INSTR_GDT_FAULT \ + && (a_rcStrict) > VINF_EM_RESET) ) \ + (a_rcStrict) = (a_rcStrict2); \ + } while (0) +#endif + +VMMDECL(VBOXSTRICTRC) PGMPhysRead(PVMCC pVM, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead, PGMACCESSORIGIN enmOrigin); +VMMDECL(VBOXSTRICTRC) PGMPhysWrite(PVMCC pVM, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite, PGMACCESSORIGIN enmOrigin); +VMMDECL(VBOXSTRICTRC) PGMPhysReadGCPtr(PVMCPUCC pVCpu, void *pvDst, RTGCPTR GCPtrSrc, size_t cb, PGMACCESSORIGIN enmOrigin); +VMMDECL(VBOXSTRICTRC) PGMPhysWriteGCPtr(PVMCPUCC pVCpu, RTGCPTR GCPtrDst, const void *pvSrc, size_t cb, PGMACCESSORIGIN enmOrigin); + +VMMDECL(int) PGMPhysSimpleReadGCPhys(PVMCC pVM, void *pvDst, RTGCPHYS GCPhysSrc, size_t cb); +VMMDECL(int) PGMPhysSimpleWriteGCPhys(PVMCC pVM, RTGCPHYS GCPhysDst, const void *pvSrc, size_t cb); +VMMDECL(int) PGMPhysSimpleReadGCPtr(PVMCPUCC pVCpu, void *pvDst, RTGCPTR GCPtrSrc, size_t cb); +VMMDECL(int) PGMPhysSimpleWriteGCPtr(PVMCPUCC pVCpu, RTGCPTR GCPtrDst, const void *pvSrc, size_t cb); +VMMDECL(int) PGMPhysSimpleDirtyWriteGCPtr(PVMCPUCC pVCpu, RTGCPTR GCPtrDst, const void *pvSrc, size_t cb); + +VMM_INT_DECL(int) PGMPhysIemGCPhys2Ptr(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhys, bool fWritable, bool fByPassHandlers, void **ppv, PPGMPAGEMAPLOCK pLock); +VMM_INT_DECL(int) PGMPhysIemQueryAccess(PVMCC pVM, RTGCPHYS GCPhys, bool fWritable, bool fByPassHandlers); +VMM_INT_DECL(int) PGMPhysIemGCPhys2PtrNoLock(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhys, uint64_t const volatile *puTlbPhysRev, +#if defined(IN_RC) + R3PTRTYPE(uint8_t *) *ppb, +#else + R3R0PTRTYPE(uint8_t *) *ppb, +#endif + uint64_t *pfTlb); +/** @name Flags returned by PGMPhysIemGCPhys2PtrNoLock + * @{ */ +#define PGMIEMGCPHYS2PTR_F_NO_WRITE RT_BIT_32(3) /**< Not writable (IEMTLBE_F_PG_NO_WRITE). */ +#define PGMIEMGCPHYS2PTR_F_NO_READ RT_BIT_32(4) /**< Not readable (IEMTLBE_F_PG_NO_READ). */ +#define PGMIEMGCPHYS2PTR_F_NO_MAPPINGR3 RT_BIT_32(7) /**< No ring-3 mapping (IEMTLBE_F_NO_MAPPINGR3). */ +#define PGMIEMGCPHYS2PTR_F_UNASSIGNED RT_BIT_32(8) /**< Unassgined memory (IEMTLBE_F_PG_UNASSIGNED). */ +/** @} */ + +/** Information returned by PGMPhysNemQueryPageInfo. */ +typedef struct PGMPHYSNEMPAGEINFO +{ + /** The host physical address of the page, NIL_HCPHYS if invalid page. */ + RTHCPHYS HCPhys; + /** The NEM access mode for the page, NEM_PAGE_PROT_XXX */ + uint32_t fNemProt : 8; + /** The NEM state associated with the PAGE. */ + uint32_t u2NemState : 2; + /** The NEM state associated with the PAGE before pgmPhysPageMakeWritable was called. */ + uint32_t u2OldNemState : 2; + /** Set if the page has handler. */ + uint32_t fHasHandlers : 1; + /** Set if is the zero page backing it. */ + uint32_t fZeroPage : 1; + /** Set if the page has handler. */ + PGMPAGETYPE enmType; +} PGMPHYSNEMPAGEINFO; +/** Pointer to page information for NEM. */ +typedef PGMPHYSNEMPAGEINFO *PPGMPHYSNEMPAGEINFO; +/** + * Callback for checking that the page is in sync while under the PGM lock. + * + * NEM passes this callback to PGMPhysNemQueryPageInfo to check that the page is + * in-sync between PGM and the native hypervisor API in an atomic fashion. + * + * @returns VBox status code. + * @param pVM The cross context VM structure. + * @param pVCpu The cross context per virtual CPU structure. Optional, + * see PGMPhysNemQueryPageInfo. + * @param GCPhys The guest physical address (not A20 masked). + * @param pInfo The page info structure. This function updates the + * u2NemState memory and the caller will update the PGMPAGE + * copy accordingly. + * @param pvUser Callback user argument. + */ +typedef DECLCALLBACKTYPE(int, FNPGMPHYSNEMCHECKPAGE,(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhys, PPGMPHYSNEMPAGEINFO pInfo, void *pvUser)); +/** Pointer to a FNPGMPHYSNEMCHECKPAGE function. */ +typedef FNPGMPHYSNEMCHECKPAGE *PFNPGMPHYSNEMCHECKPAGE; + +VMM_INT_DECL(int) PGMPhysNemPageInfoChecker(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhys, bool fMakeWritable, + PPGMPHYSNEMPAGEINFO pInfo, PFNPGMPHYSNEMCHECKPAGE pfnChecker, void *pvUser); + +/** + * Callback for use with PGMPhysNemEnumPagesByState. + * @returns VBox status code. + * Failure status will stop enumeration immediately and return. + * @param pVM The cross context VM structure. + * @param pVCpu The cross context per virtual CPU structure. Optional, + * see PGMPhysNemEnumPagesByState. + * @param GCPhys The guest physical address (not A20 masked). + * @param pu2NemState Pointer to variable with the NEM state. This can be + * update. + * @param pvUser The user argument. + */ +typedef DECLCALLBACKTYPE(int, FNPGMPHYSNEMENUMCALLBACK,(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhys, + uint8_t *pu2NemState, void *pvUser)); +/** Pointer to a FNPGMPHYSNEMENUMCALLBACK function. */ +typedef FNPGMPHYSNEMENUMCALLBACK *PFNPGMPHYSNEMENUMCALLBACK; +VMM_INT_DECL(int) PGMPhysNemEnumPagesByState(PVMCC pVM, PVMCPUCC VCpu, uint8_t uMinState, + PFNPGMPHYSNEMENUMCALLBACK pfnCallback, void *pvUser); + + +#ifdef VBOX_STRICT +VMMDECL(unsigned) PGMAssertHandlerAndFlagsInSync(PVMCC pVM); +VMMDECL(unsigned) PGMAssertNoMappingConflicts(PVM pVM); +VMMDECL(unsigned) PGMAssertCR3(PVMCC pVM, PVMCPUCC pVCpu, uint64_t cr3, uint64_t cr4); +#endif /* VBOX_STRICT */ + +VMMDECL(int) PGMSetLargePageUsage(PVMCC pVM, bool fUseLargePages); + +/** + * Query large page usage state + * + * @returns 0 - disabled, 1 - enabled + * @param pVM The cross context VM structure. + */ +#define PGMIsUsingLargePages(pVM) ((pVM)->pgm.s.fUseLargePages) + + +#ifdef IN_RING0 +/** @defgroup grp_pgm_r0 The PGM Host Context Ring-0 API + * @{ + */ +VMMR0_INT_DECL(int) PGMR0InitPerVMData(PGVM pGVM, RTR0MEMOBJ hMemObj); +VMMR0_INT_DECL(int) PGMR0InitVM(PGVM pGVM); +VMMR0_INT_DECL(void) PGMR0DoneInitVM(PGVM pGVM); +VMMR0_INT_DECL(void) PGMR0CleanupVM(PGVM pGVM); +VMMR0_INT_DECL(int) PGMR0PhysAllocateHandyPages(PGVM pGVM, VMCPUID idCpu); +VMMR0_INT_DECL(int) PGMR0PhysFlushHandyPages(PGVM pGVM, VMCPUID idCpu); +VMMR0_INT_DECL(int) PGMR0PhysAllocateLargePage(PGVM pGVM, VMCPUID idCpu, RTGCPHYS GCPhys); +VMMR0_INT_DECL(int) PGMR0PhysMMIO2MapKernel(PGVM pGVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2, + size_t offSub, size_t cbSub, void **ppvMapping); +VMMR0_INT_DECL(int) PGMR0PhysSetupIoMmu(PGVM pGVM); +VMMR0_INT_DECL(int) PGMR0PhysHandlerInitReqHandler(PGVM pGVM, uint32_t cEntries); +VMMR0_INT_DECL(int) PGMR0HandlerPhysicalTypeSetUpContext(PGVM pGVM, PGMPHYSHANDLERKIND enmKind, uint32_t fFlags, + PFNPGMPHYSHANDLER pfnHandler, PFNPGMRZPHYSPFHANDLER pfnPfHandler, + const char *pszDesc, PGMPHYSHANDLERTYPE hType); + +VMMR0DECL(int) PGMR0SharedModuleCheck(PVMCC pVM, PGVM pGVM, VMCPUID idCpu, PGMMSHAREDMODULE pModule, + PCRTGCPTR64 paRegionsGCPtrs); +VMMR0DECL(int) PGMR0Trap0eHandlerNestedPaging(PGVM pGVM, PGVMCPU pGVCpu, PGMMODE enmShwPagingMode, RTGCUINT uErr, + PCPUMCTX pCtx, RTGCPHYS pvFault); +VMMR0DECL(VBOXSTRICTRC) PGMR0Trap0eHandlerNPMisconfig(PGVM pGVM, PGVMCPU pGVCpu, PGMMODE enmShwPagingMode, + PCPUMCTX pCtx, RTGCPHYS GCPhysFault, uint32_t uErr); +VMMR0_INT_DECL(int) PGMR0PoolGrow(PGVM pGVM, VMCPUID idCpu); + +# ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT +VMMR0DECL(VBOXSTRICTRC) PGMR0NestedTrap0eHandlerNestedPaging(PGVMCPU pGVCpu, PGMMODE enmShwPagingMode, RTGCUINT uErr, + PCPUMCTX pCtx, RTGCPHYS GCPhysNestedFault, + bool fIsLinearAddrValid, RTGCPTR GCPtrNestedFault, PPGMPTWALK pWalk); +# endif +/** @} */ +#endif /* IN_RING0 */ + + + +#ifdef IN_RING3 +/** @defgroup grp_pgm_r3 The PGM Host Context Ring-3 API + * @{ + */ +VMMR3_INT_DECL(void) PGMR3EnableNemMode(PVM pVM); +VMMR3_INT_DECL(bool) PGMR3IsNemModeEnabled(PVM pVM); +VMMR3DECL(int) PGMR3Init(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) PGMR3ResetCpu(PVM pVM, PVMCPU pVCpu); +VMMR3_INT_DECL(void) PGMR3Reset(PVM pVM); +VMMR3_INT_DECL(void) PGMR3ResetNoMorePhysWritesFlag(PVM pVM); +VMMR3_INT_DECL(void) PGMR3MemSetup(PVM pVM, bool fReset); +VMMR3DECL(int) PGMR3Term(PVM pVM); + +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(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(PUVM pUVM, uint64_t *pcbTotalMem, uint64_t *pcbPrivateMem, uint64_t *pcbSharedMem, uint64_t *pcbZeroMem); +VMMR3DECL(int) PGMR3QueryGlobalMemoryStats(PUVM pUVM, uint64_t *pcbAllocMem, uint64_t *pcbFreeMem, uint64_t *pcbBallonedMem, uint64_t *pcbSharedMem); + +VMMR3DECL(int) PGMR3PhysMMIORegister(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, PGMPHYSHANDLERTYPE hType, + uint64_t uUser, const char *pszDesc); +VMMR3DECL(int) PGMR3PhysMMIODeregister(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb); + +/** @name PGMPHYS_MMIO2_FLAGS_XXX - MMIO2 registration flags. + * @see PGMR3PhysMmio2Register, PDMDevHlpMmio2Create + * @{ */ +/** Track dirty pages. + * @see PGMR3PhysMmio2QueryAndResetDirtyBitmap(), PGMR3PhysMmio2ControlDirtyPageTracking(). */ +#define PGMPHYS_MMIO2_FLAGS_TRACK_DIRTY_PAGES RT_BIT_32(0) +/** Valid flags. */ +#define PGMPHYS_MMIO2_FLAGS_VALID_MASK UINT32_C(0x00000001) +/** @} */ + +VMMR3_INT_DECL(int) PGMR3PhysMmio2Register(PVM pVM, PPDMDEVINS pDevIns, uint32_t iSubDev, uint32_t iRegion, RTGCPHYS cb, + uint32_t fFlags, const char *pszDesc, void **ppv, PGMMMIO2HANDLE *phRegion); +VMMR3_INT_DECL(int) PGMR3PhysMmio2Deregister(PVM pVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2); +VMMR3_INT_DECL(int) PGMR3PhysMmio2Map(PVM pVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2, RTGCPHYS GCPhys); +VMMR3_INT_DECL(int) PGMR3PhysMmio2Unmap(PVM pVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2, RTGCPHYS GCPhys); +VMMR3_INT_DECL(int) PGMR3PhysMmio2Reduce(PVM pVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2, RTGCPHYS cbRegion); +VMMR3_INT_DECL(int) PGMR3PhysMmio2ValidateHandle(PVM pVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2); +VMMR3_INT_DECL(RTGCPHYS) PGMR3PhysMmio2GetMappingAddress(PVM pVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2); +VMMR3_INT_DECL(int) PGMR3PhysMmio2ChangeRegionNo(PVM pVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2, uint32_t iNewRegion); +VMMR3_INT_DECL(int) PGMR3PhysMmio2QueryAndResetDirtyBitmap(PVM pVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2, + void *pvBitmap, size_t cbBitmap); +VMMR3_INT_DECL(int) PGMR3PhysMmio2ControlDirtyPageTracking(PVM pVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2, bool fEnabled); + +/** @name PGMPHYS_ROM_FLAGS_XXX - ROM registration flags. + * @see PGMR3PhysRegisterRom, PDMDevHlpROMRegister + * @{ */ +/** Inidicates that ROM shadowing should be enabled. */ +#define PGMPHYS_ROM_FLAGS_SHADOWED UINT8_C(0x01) +/** Indicates that what pvBinary points to won't go away + * and can be used for strictness checks. */ +#define PGMPHYS_ROM_FLAGS_PERMANENT_BINARY UINT8_C(0x02) +/** Indicates that the ROM is allowed to be missing from saved state. + * @note This is a hack for EFI, see @bugref{6940} */ +#define PGMPHYS_ROM_FLAGS_MAYBE_MISSING_FROM_STATE UINT8_C(0x04) +/** Valid flags. */ +#define PGMPHYS_ROM_FLAGS_VALID_MASK UINT8_C(0x07) +/** @} */ + +VMMR3DECL(int) PGMR3PhysRomRegister(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTGCPHYS cb, + const void *pvBinary, uint32_t cbBinary, uint8_t fFlags, const char *pszDesc); +VMMR3DECL(int) PGMR3PhysRomProtect(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, PGMROMPROT enmProt); +VMMDECL(void) PGMR3PhysSetA20(PVMCPU pVCpu, bool fEnable); + +VMMR3_INT_DECL(int) PGMR3HandlerPhysicalTypeRegister(PVM pVM, PGMPHYSHANDLERKIND enmKind, uint32_t fFlags, + PFNPGMPHYSHANDLER pfnHandlerR3, const char *pszDesc, + PPGMPHYSHANDLERTYPE phType); + +VMMR3_INT_DECL(int) PGMR3PoolGrow(PVM pVM, PVMCPU pVCpu); + +VMMR3DECL(int) PGMR3PhysTlbGCPhys2Ptr(PVM pVM, RTGCPHYS GCPhys, bool fWritable, void **ppv); +VMMR3DECL(uint8_t) PGMR3PhysReadU8(PVM pVM, RTGCPHYS GCPhys, PGMACCESSORIGIN enmOrigin); +VMMR3DECL(uint16_t) PGMR3PhysReadU16(PVM pVM, RTGCPHYS GCPhys, PGMACCESSORIGIN enmOrigin); +VMMR3DECL(uint32_t) PGMR3PhysReadU32(PVM pVM, RTGCPHYS GCPhys, PGMACCESSORIGIN enmOrigin); +VMMR3DECL(uint64_t) PGMR3PhysReadU64(PVM pVM, RTGCPHYS GCPhys, PGMACCESSORIGIN enmOrigin); +VMMR3DECL(void) PGMR3PhysWriteU8(PVM pVM, RTGCPHYS GCPhys, uint8_t Value, PGMACCESSORIGIN enmOrigin); +VMMR3DECL(void) PGMR3PhysWriteU16(PVM pVM, RTGCPHYS GCPhys, uint16_t Value, PGMACCESSORIGIN enmOrigin); +VMMR3DECL(void) PGMR3PhysWriteU32(PVM pVM, RTGCPHYS GCPhys, uint32_t Value, PGMACCESSORIGIN enmOrigin); +VMMR3DECL(void) PGMR3PhysWriteU64(PVM pVM, RTGCPHYS GCPhys, uint64_t Value, PGMACCESSORIGIN enmOrigin); +VMMR3DECL(int) PGMR3PhysReadExternal(PVM pVM, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead, PGMACCESSORIGIN enmOrigin); +VMMR3DECL(int) PGMR3PhysWriteExternal(PVM pVM, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite, PGMACCESSORIGIN enmOrigin); +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) PGMR3PhysBulkGCPhys2CCPtrExternal(PVM pVM, uint32_t cPages, PCRTGCPHYS paGCPhysPages, + void **papvPages, PPGMPAGEMAPLOCK paLocks); +VMMR3DECL(int) PGMR3PhysBulkGCPhys2CCPtrReadOnlyExternal(PVM pVM, uint32_t cPages, PCRTGCPHYS paGCPhysPages, + void const **papvPages, PPGMPAGEMAPLOCK paLocks); +VMMR3DECL(void) PGMR3PhysChunkInvalidateTLB(PVM pVM); +VMMR3DECL(int) PGMR3PhysAllocateHandyPages(PVM pVM); + +VMMR3DECL(int) PGMR3CheckIntegrity(PVM pVM); + +VMMR3DECL(int) PGMR3DbgR3Ptr2GCPhys(PUVM pUVM, RTR3PTR R3Ptr, PRTGCPHYS pGCPhys); +VMMR3DECL(int) PGMR3DbgR3Ptr2HCPhys(PUVM pUVM, RTR3PTR R3Ptr, PRTHCPHYS pHCPhys); +VMMR3DECL(int) PGMR3DbgHCPhys2GCPhys(PUVM pUVM, RTHCPHYS HCPhys, PRTGCPHYS pGCPhys); +VMMR3_INT_DECL(int) PGMR3DbgReadGCPhys(PVM pVM, void *pvDst, RTGCPHYS GCPhysSrc, size_t cb, uint32_t fFlags, size_t *pcbRead); +VMMR3_INT_DECL(int) PGMR3DbgWriteGCPhys(PVM pVM, RTGCPHYS GCPhysDst, const void *pvSrc, size_t cb, uint32_t fFlags, size_t *pcbWritten); +VMMR3_INT_DECL(int) PGMR3DbgReadGCPtr(PVM pVM, void *pvDst, RTGCPTR GCPtrSrc, size_t cb, uint32_t fFlags, size_t *pcbRead); +VMMR3_INT_DECL(int) PGMR3DbgWriteGCPtr(PVM pVM, RTGCPTR GCPtrDst, void const *pvSrc, size_t cb, uint32_t fFlags, size_t *pcbWritten); +VMMR3_INT_DECL(int) PGMR3DbgScanPhysical(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cbRange, RTGCPHYS GCPhysAlign, const uint8_t *pabNeedle, size_t cbNeedle, PRTGCPHYS pGCPhysHit); +VMMR3_INT_DECL(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 /* !VBOX_INCLUDED_vmm_pgm_h */ + diff --git a/include/VBox/vmm/selm.h b/include/VBox/vmm/selm.h new file mode 100644 index 00000000..1b68e3f5 --- /dev/null +++ b/include/VBox/vmm/selm.h @@ -0,0 +1,114 @@ +/** @file + * SELM - The Selector Manager. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_selm_h +#define VBOX_INCLUDED_vmm_selm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#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 + * @ingroup grp_vmm + * @{ + */ + +VMMDECL(int) SELMGetTSSInfo(PVM pVM, PVMCPU pVCpu, PRTGCUINTPTR pGCPtrTss, PRTGCUINTPTR pcbTss, bool *pfCanHaveIOBitmap); +VMMDECL(RTGCPTR) SELMToFlat(PVMCPUCC pVCpu, unsigned idxSeg, PCPUMCTX pCtx, RTGCPTR Addr); +VMMDECL(RTGCPTR) SELMToFlatBySel(PVM pVM, RTSEL Sel, RTGCPTR Addr); + +/** 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) +#define SELMTOFLAT_FLAGS_HYPER RT_BIT(10) +/** @} */ + +VMMDECL(int) SELMToFlatEx(PVMCPU pVCpu, unsigned idxSeg, PCPUMCTX pCtx, RTGCPTR Addr, uint32_t fFlags, PRTGCPTR ppvGC); +VMMDECL(int) SELMValidateAndConvertCSAddr(PVMCPU pVCpu, uint32_t fEFlags, 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 SELM ring-3 Context API + * @{ + */ +VMMR3DECL(int) SELMR3Init(PVM pVM); +VMMR3DECL(void) SELMR3Relocate(PVM pVM); +VMMR3DECL(int) SELMR3Term(PVM pVM); +VMMR3DECL(void) SELMR3Reset(PVM pVM); +VMMR3DECL(int) SELMR3GetSelectorInfo(PVMCPU pVCpu, RTSEL Sel, PDBGFSELINFO pSelInfo); +VMMR3DECL(void) SELMR3DumpDescriptor(X86DESC Desc, RTSEL Sel, const char *pszMsg); +VMMR3DECL(void) SELMR3DumpGuestGDT(PVM pVM); +VMMR3DECL(void) SELMR3DumpGuestLDT(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 /* !VBOX_INCLUDED_vmm_selm_h */ + diff --git a/include/VBox/vmm/ssm.h b/include/VBox/vmm/ssm.h new file mode 100644 index 00000000..591b5d7e --- /dev/null +++ b/include/VBox/vmm/ssm.h @@ -0,0 +1,1354 @@ +/** @file + * SSM - The Save State Manager. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_ssm_h +#define VBOX_INCLUDED_vmm_ssm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#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 + * @ingroup grp_vmm + * @{ + */ + +/** + * 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 DECLCALLBACKTYPE(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; + /** This field was first saved by this unit version number. */ + uint32_t uFirstVer; + /** Field name. */ + const char *pszName; +} SSMFIELD; + +/** Emit a SSMFIELD array entry. + * @internal */ +#define SSMFIELD_ENTRY_INT(Name, off, cb, enmTransformer, uFirstVer) \ + { (PFNSSMFIELDGETPUT)(uintptr_t)(enmTransformer), (uint32_t)(off), (uint32_t)(cb), (uFirstVer), Name } +/** Emit a SSMFIELD array entry. + * @internal */ +#define SSMFIELD_ENTRY_TF_INT(Type, Field, enmTransformer, uFirstVer) \ + SSMFIELD_ENTRY_INT(#Type "::" #Field, RT_UOFFSETOF(Type, Field), RT_SIZEOFMEMB(Type, Field), enmTransformer, uFirstVer) +/** 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, 0) +/** 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_UOFFSETOF(Type, Field), \ + (RT_SIZEOFMEMB(Type, Field) << 16) | (cb32) | ((cb64) << 8), enmTransformer, 0) +/** 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, 0) + +/** Emit a SSMFIELD array entry. */ +#define SSMFIELD_ENTRY(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_NO_TRANSFORMATION, 0) +/** Emit a SSMFIELD array entry with first version. */ +#define SSMFIELD_ENTRY_VER(Type, Field, uFirstVer) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_NO_TRANSFORMATION, uFirstVer) +/** 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, 0) +/** Emit a SSMFIELD array entry for a RTGCPHYS type. */ +#define SSMFIELD_ENTRY_GCPHYS(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_GCPHYS, 0) +/** Emit a SSMFIELD array entry for a RTGCPTR type. */ +#define SSMFIELD_ENTRY_GCPTR(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_GCPTR, 0) +/** 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, 0) +/** 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, 0) +/** 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, 0) +/** 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, 0) +/** 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, 0) +/** 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, 0) + +/** 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, 0) +/** 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, 0) +/** 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, 0) +/** 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, 0) +/** 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, 0) + +/** 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), 0, "<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), 0, "<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), 0, "<msc32-padding>" \ + } +#else +# define SSMFIELD_ENTRY_PAD_MSC32_AUTO(cb) \ + { \ + (PFNSSMFIELDGETPUT)(uintptr_t)(SSMFIELDTRANS_PAD_MSC32_AUTO), \ + UINT32_MAX / 2, (cb), 0, "<msc32-padding>" \ + } +#endif + +/** Emit a SSMFIELD array entry for a field with a custom callback. */ +#define SSMFIELD_ENTRY_CALLBACK(Type, Field, pfnGetPut) \ + { (pfnGetPut), RT_UOFFSETOF(Type, Field), RT_SIZEOFMEMB(Type, Field), 0, #Type "::" #Field } +/** Emit the terminating entry of a SSMFIELD array. */ +#define SSMFIELD_ENTRY_TERM() \ + { (PFNSSMFIELDGETPUT)(uintptr_t)SSMFIELDTRANS_INVALID, UINT32_MAX, 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) +/** No introductory structure marker. Use when splitting up structures. */ +#define SSMSTRUCT_FLAGS_NO_LEAD_MARKER RT_BIT_32(4) +/** No trailing structure marker. Use when splitting up structures. */ +#define SSMSTRUCT_FLAGS_NO_TAIL_MARKER RT_BIT_32(5) + +/** Band-aid for old SSMR3PutMem/SSMR3GetMem of structurs with host pointers. + * @remarks This type is normally only used up to the first changes to the + * structures take place in order to make sure the conversion from + * SSMR3PutMem to field descriptors went smoothly. Replace with + * SSMSTRUCT_FLAGS_MEM_BAND_AID_RELAXED when changing the structure. */ +#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(0x0000003f) +/** @} */ + + +/** 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. + * @remarks The caller enters the device critical section prior to the call. + * @thread Any. + */ +typedef DECLCALLBACKTYPE(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. + * @remarks The caller enters the device critical section prior to the call. + * @thread Any. + */ +typedef DECLCALLBACKTYPE(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. + * @remarks The caller enters the device critical section prior to the call. + * @thread Any. + */ +typedef DECLCALLBACKTYPE(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. + * @remarks The caller enters the device critical section prior to the call. + */ +typedef DECLCALLBACKTYPE(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. + * @remarks The caller enters the device critical section prior to the call. + */ +typedef DECLCALLBACKTYPE(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. + * @remarks The caller enters the device critical section prior to the call. + */ +typedef DECLCALLBACKTYPE(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. + * @remarks The caller enters the device critical section prior to the call. + */ +typedef DECLCALLBACKTYPE(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. + * @remarks The caller enters the device critical section prior to the call. + */ +typedef DECLCALLBACKTYPE(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. + * @remarks The caller enters the device critical section prior to the call. + */ +typedef DECLCALLBACKTYPE(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 DECLCALLBACKTYPE(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 DECLCALLBACKTYPE(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 DECLCALLBACKTYPE(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 DECLCALLBACKTYPE(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 DECLCALLBACKTYPE(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 DECLCALLBACKTYPE(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 DECLCALLBACKTYPE(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 DECLCALLBACKTYPE(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 DECLCALLBACKTYPE(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 DECLCALLBACKTYPE(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 DECLCALLBACKTYPE(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 DECLCALLBACKTYPE(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 DECLCALLBACKTYPE(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 DECLCALLBACKTYPE(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 DECLCALLBACKTYPE(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 DECLCALLBACKTYPE(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 DECLCALLBACKTYPE(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 DECLCALLBACKTYPE(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 The cross context VM structure. + * @param pSSM SSM operation handle. + * @thread Any. + */ +typedef DECLCALLBACKTYPE(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 The cross context VM structure. + * @param pSSM SSM operation handle. + * @param uPass The data pass. + * @thread Any. + */ +typedef DECLCALLBACKTYPE(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 The cross context VM structure. + * @param pSSM SSM operation handle. + * @param uPass The data pass. + * @thread Any. + */ +typedef DECLCALLBACKTYPE(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 The cross context VM structure. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACKTYPE(int, FNSSMINTSAVEPREP,(PVM pVM, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMINTSAVEPREP() function. */ +typedef FNSSMINTSAVEPREP *PFNSSMINTSAVEPREP; + +/** + * Execute state save operation. + * + * @returns VBox status code. + * @param pVM The cross context VM structure. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACKTYPE(int, FNSSMINTSAVEEXEC,(PVM pVM, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMINTSAVEEXEC() function. */ +typedef FNSSMINTSAVEEXEC *PFNSSMINTSAVEEXEC; + +/** + * Done state save operation. + * + * @returns VBox status code. + * @param pVM The cross context VM structure. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACKTYPE(int, FNSSMINTSAVEDONE,(PVM pVM, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMINTSAVEDONE() function. */ +typedef FNSSMINTSAVEDONE *PFNSSMINTSAVEDONE; + +/** + * Prepare state load operation. + * + * @returns VBox status code. + * @param pVM The cross context VM structure. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACKTYPE(int, FNSSMINTLOADPREP,(PVM pVM, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMINTLOADPREP() function. */ +typedef FNSSMINTLOADPREP *PFNSSMINTLOADPREP; + +/** + * Execute state load operation. + * + * @returns VBox status code. + * @param pVM The cross context VM structure. + * @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 DECLCALLBACKTYPE(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 The cross context VM structure. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACKTYPE(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 pVMM The VMM ring-3 vtable. + * @param pvUser User argument. + * @thread Any. + */ +typedef DECLCALLBACKTYPE(int, FNSSMEXTLIVEPREP,(PSSMHANDLE pSSM, PCVMMR3VTABLE pVMM, 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 pVMM The VMM ring-3 vtable. + * @param pvUser User argument. + * @param uPass The data pass. + * @thread Any. + */ +typedef DECLCALLBACKTYPE(int, FNSSMEXTLIVEEXEC,(PSSMHANDLE pSSM, PCVMMR3VTABLE pVMM, 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 pVMM The VMM ring-3 vtable. + * @param pvUser User argument. + * @param uPass The data pass. + * @thread Any. + */ +typedef DECLCALLBACKTYPE(int, FNSSMEXTLIVEVOTE,(PSSMHANDLE pSSM, PCVMMR3VTABLE pVMM, 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 pVMM The VMM ring-3 vtable. + * @param pvUser User argument. + */ +typedef DECLCALLBACKTYPE(int, FNSSMEXTSAVEPREP,(PSSMHANDLE pSSM, PCVMMR3VTABLE pVMM, void *pvUser)); +/** Pointer to a FNSSMEXTSAVEPREP() function. */ +typedef FNSSMEXTSAVEPREP *PFNSSMEXTSAVEPREP; + +/** + * Execute state save operation. + * + * @returns VBox status code. + * @param pSSM SSM operation handle. + * @param pVMM The VMM ring-3 vtable. + * @param pvUser User argument. + */ +typedef DECLCALLBACKTYPE(int, FNSSMEXTSAVEEXEC,(PSSMHANDLE pSSM, PCVMMR3VTABLE pVMM, void *pvUser)); +/** Pointer to a FNSSMEXTSAVEEXEC() function. */ +typedef FNSSMEXTSAVEEXEC *PFNSSMEXTSAVEEXEC; + +/** + * Done state save operation. + * + * @returns VBox status code. + * @param pSSM SSM operation handle. + * @param pVMM The VMM ring-3 vtable. + * @param pvUser User argument. + */ +typedef DECLCALLBACKTYPE(int, FNSSMEXTSAVEDONE,(PSSMHANDLE pSSM, PCVMMR3VTABLE pVMM, void *pvUser)); +/** Pointer to a FNSSMEXTSAVEDONE() function. */ +typedef FNSSMEXTSAVEDONE *PFNSSMEXTSAVEDONE; + +/** + * Prepare state load operation. + * + * @returns VBox status code. + * @param pSSM SSM operation handle. + * @param pVMM The VMM ring-3 vtable. + * @param pvUser User argument. + */ +typedef DECLCALLBACKTYPE(int, FNSSMEXTLOADPREP,(PSSMHANDLE pSSM, PCVMMR3VTABLE pVMM, void *pvUser)); +/** Pointer to a FNSSMEXTLOADPREP() function. */ +typedef FNSSMEXTLOADPREP *PFNSSMEXTLOADPREP; + +/** + * Execute state load operation. + * + * @returns VBox status code. + * @param pSSM SSM operation handle. + * @param pVMM The VMM ring-3 vtable. + * @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 DECLCALLBACKTYPE(int, FNSSMEXTLOADEXEC,(PSSMHANDLE pSSM, PCVMMR3VTABLE pVMM, 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 pVMM The VMM ring-3 vtable. + * @param pvUser User argument. + */ +typedef DECLCALLBACKTYPE(int, FNSSMEXTLOADDONE,(PSSMHANDLE pSSM, PCVMMR3VTABLE pVMM, 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) + + +VMMR3DECL(void) SSMR3Term(PVM pVM); +VMMR3_INT_DECL(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); +VMMR3_INT_DECL(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); +VMMR3_INT_DECL(int) +SSMR3RegisterUsb(PVM pVM, PPDMUSBINS pUsbIns, const char *pszName, uint32_t uInstance, uint32_t uVersion, size_t cbGuess, + PFNSSMUSBLIVEPREP pfnLivePrep, PFNSSMUSBLIVEEXEC pfnLiveExec, PFNSSMUSBLIVEVOTE pfnLiveVote, + PFNSSMUSBSAVEPREP pfnSavePrep, PFNSSMUSBSAVEEXEC pfnSaveExec, PFNSSMUSBSAVEDONE pfnSaveDone, + PFNSSMUSBLOADPREP pfnLoadPrep, PFNSSMUSBLOADEXEC pfnLoadExec, PFNSSMUSBLOADDONE 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(PUVM pUVM, 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); +VMMR3DECL(int) SSMR3RegisterStub(PVM pVM, const char *pszName, uint32_t uInstance); +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); +VMMR3_INT_DECL(int) SSMR3DeregisterUsb(PVM pVM, PPDMUSBINS pUsbIns, const char *pszName, uint32_t uInstance); +VMMR3DECL(int) SSMR3DeregisterInternal(PVM pVM, const char *pszName); +VMMR3DECL(int) SSMR3DeregisterExternal(PUVM pUVM, 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, PCSSMSTRMOPS pStreamOps, void *pvStreamOps, + bool fChecksumIt); +VMMR3DECL(int) SSMR3Open(const char *pszFilename, PCSSMSTRMOPS pStreamOps, void *pvStreamOps, + 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); +#ifdef DEBUG +VMMR3DECL(uint64_t) SSMR3HandleTellInUnit(PSSMHANDLE pSSM); +#endif +VMMR3DECL(int) SSMR3Cancel(PUVM pUVM); + + +/** 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) SSMR3GetBoolV(PSSMHANDLE pSSM, bool volatile *pfBool); +VMMR3DECL(int) SSMR3GetU8(PSSMHANDLE pSSM, uint8_t *pu8); +VMMR3DECL(int) SSMR3GetU8V(PSSMHANDLE pSSM, uint8_t volatile *pu8); +VMMR3DECL(int) SSMR3GetS8(PSSMHANDLE pSSM, int8_t *pi8); +VMMR3DECL(int) SSMR3GetS8V(PSSMHANDLE pSSM, int8_t volatile *pi8); +VMMR3DECL(int) SSMR3GetU16(PSSMHANDLE pSSM, uint16_t *pu16); +VMMR3DECL(int) SSMR3GetU16V(PSSMHANDLE pSSM, uint16_t volatile *pu16); +VMMR3DECL(int) SSMR3GetS16(PSSMHANDLE pSSM, int16_t *pi16); +VMMR3DECL(int) SSMR3GetS16V(PSSMHANDLE pSSM, int16_t volatile *pi16); +VMMR3DECL(int) SSMR3GetU32(PSSMHANDLE pSSM, uint32_t *pu32); +VMMR3DECL(int) SSMR3GetU32V(PSSMHANDLE pSSM, uint32_t volatile *pu32); +VMMR3DECL(int) SSMR3GetS32(PSSMHANDLE pSSM, int32_t *pi32); +VMMR3DECL(int) SSMR3GetS32V(PSSMHANDLE pSSM, int32_t volatile *pi32); +VMMR3DECL(int) SSMR3GetU64(PSSMHANDLE pSSM, uint64_t *pu64); +VMMR3DECL(int) SSMR3GetU64V(PSSMHANDLE pSSM, uint64_t volatile *pu64); +VMMR3DECL(int) SSMR3GetS64(PSSMHANDLE pSSM, int64_t *pi64); +VMMR3DECL(int) SSMR3GetS64V(PSSMHANDLE pSSM, int64_t volatile *pi64); +VMMR3DECL(int) SSMR3GetU128(PSSMHANDLE pSSM, uint128_t *pu128); +VMMR3DECL(int) SSMR3GetU128V(PSSMHANDLE pSSM, uint128_t volatile *pu128); +VMMR3DECL(int) SSMR3GetS128(PSSMHANDLE pSSM, int128_t *pi128); +VMMR3DECL(int) SSMR3GetS128V(PSSMHANDLE pSSM, int128_t volatile *pi128); +VMMR3DECL(int) SSMR3GetGCPhys32(PSSMHANDLE pSSM, PRTGCPHYS32 pGCPhys); +VMMR3DECL(int) SSMR3GetGCPhys32V(PSSMHANDLE pSSM, RTGCPHYS32 volatile *pGCPhys); +VMMR3DECL(int) SSMR3GetGCPhys64(PSSMHANDLE pSSM, PRTGCPHYS64 pGCPhys); +VMMR3DECL(int) SSMR3GetGCPhys64V(PSSMHANDLE pSSM, RTGCPHYS64 volatile *pGCPhys); +VMMR3DECL(int) SSMR3GetGCPhys(PSSMHANDLE pSSM, PRTGCPHYS pGCPhys); +VMMR3DECL(int) SSMR3GetGCPhysV(PSSMHANDLE pSSM, RTGCPHYS volatile *pGCPhys); +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) 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) 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, ...) RT_IPRT_FORMAT_ATTR(6, 7); +VMMR3DECL(int) SSMR3SetLoadErrorV(PSSMHANDLE pSSM, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(6, 0); +VMMR3DECL(int) SSMR3SetCfgError(PSSMHANDLE pSSM, RT_SRC_POS_DECL, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(5, 6); +VMMR3DECL(int) SSMR3SetCfgErrorV(PSSMHANDLE pSSM, RT_SRC_POS_DECL, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(5, 0); + +/** Wrapper around SSMR3GetU32 for simplifying getting enum values saved as uint32_t. */ +# define SSM_GET_ENUM32_RET(a_pSSM, a_enmDst, a_EnumType) \ + do { \ + uint32_t u32GetEnumTmp = 0; \ + int rcGetEnum32Tmp = SSMR3GetU32((a_pSSM), &u32GetEnumTmp); \ + AssertRCReturn(rcGetEnum32Tmp, rcGetEnum32Tmp); \ + (a_enmDst) = (a_EnumType)u32GetEnumTmp; \ + AssertCompile(sizeof(a_EnumType) == sizeof(u32GetEnumTmp)); \ + } while (0) + +/** @} */ + +/** @} */ +#endif /* IN_RING3 */ + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_ssm_h */ + diff --git a/include/VBox/vmm/stam.h b/include/VBox/vmm/stam.h new file mode 100644 index 00000000..4c5764b4 --- /dev/null +++ b/include/VBox/vmm/stam.h @@ -0,0 +1,1376 @@ +/** @file + * STAM - Statistics Manager. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_stam_h +#define VBOX_INCLUDED_vmm_stam_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <iprt/stdarg.h> +#ifdef _MSC_VER +# if RT_MSC_PREREQ(RT_MSC_VER_VS2005) +# include <iprt/sanitized/intrin.h> +# endif +#endif +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) +# include <iprt/asm-arm.h> +#endif + +RT_C_DECLS_BEGIN + +/** @defgroup grp_stam The Statistics Manager API + * @ingroup grp_vmm + * @{ + */ + +#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. + */ +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) +# define STAM_GET_TS(u64) do { (u64) = ASMReadTSC(); } while (0) +#elif defined(__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 RT_MSC_PREREQ(RT_MSC_VER_VS2005) +# 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 per call. */ + STAMUNIT_BYTES_PER_CALL, + /** 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; + +/** @name STAM_REFRESH_GRP_XXX - STAM refresh groups + * @{ */ +#define STAM_REFRESH_GRP_NONE UINT8_MAX +#define STAM_REFRESH_GRP_GVMM 0 +#define STAM_REFRESH_GRP_GMM 1 +#define STAM_REFRESH_GRP_NEM 2 +/** @} */ + + +/** @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_ADD + * 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_ADD + * 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 pProfile Pointer to the STAMPROFILE 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 pProfile Pointer to the STAMPROFILE 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 + + +/** @def STAM_REL_PROFILE_STOP_START + * Stops one profile counter (if running) and starts another one. + * + * @param pProfile1 Pointer to the STAMPROFILE structure to stop. + * @param pProfile2 Pointer to the STAMPROFILE structure to start. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_STOP_START(pProfile1, pProfile2, Prefix) \ + do { \ + uint64_t Prefix##_tsStop; \ + STAM_GET_TS(Prefix##_tsStop); \ + STAM_REL_PROFILE_ADD_PERIOD(pProfile1, Prefix##_tsStop - Prefix##_tsStart); \ + Prefix##_tsStart = Prefix##_tsStop; \ + } while (0) +#else +# define STAM_REL_PROFILE_STOP_START(pProfile1, pProfile2, Prefix) \ + do { } while (0) +#endif +/** @def STAM_PROFILE_STOP_START + * Samples the stop time of a profiling period (if running) and updates the + * sample. + * + * @param pProfile1 Pointer to the STAMPROFILE structure to stop. + * @param pProfile2 Pointer to the STAMPROFILE structure to start. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_STOP_START(pProfile1, pProfile2, Prefix) \ + STAM_REL_PROFILE_STOP_START(pProfile1, pProfile2, Prefix) +#else +# define STAM_PROFILE_STOP_START(pProfile1, pProfile2, Prefix) \ + do { } while (0) +#endif + + +/** @def STAM_REL_PROFILE_START_NS + * Samples the start time of a profiling period, using RTTimeNanoTS(). + * + * @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_NS(pProfile, Prefix) \ + uint64_t const Prefix##_tsStart = RTTimeNanoTS() +#else +# define STAM_REL_PROFILE_START_NS(pProfile, Prefix) do { } while (0) +#endif +/** @def STAM_PROFILE_START_NS + * Samples the start time of a profiling period, using RTTimeNanoTS(). + * + * @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_NS(pProfile, Prefix) STAM_REL_PROFILE_START_NS(pProfile, Prefix) +#else +# define STAM_PROFILE_START_NS(pProfile, Prefix) do { } while (0) +#endif + +/** @def STAM_REL_PROFILE_STOP_NS + * Samples the stop time of a profiling period and updates the sample, using + * RTTimeNanoTS(). + * + * @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_NS(pProfile, Prefix) \ + STAM_REL_PROFILE_ADD_PERIOD(pProfile, RTTimeNanoTS() - Prefix##_tsStart) +#else +# define STAM_REL_PROFILE_STOP_NS(pProfile, Prefix) do { } while (0) +#endif +/** @def STAM_PROFILE_STOP_NS + * Samples the stop time of a profiling period and updates the sample, using + * RTTimeNanoTS(). + * + * @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_NS(pProfile, Prefix) STAM_REL_PROFILE_STOP_NS(pProfile, Prefix) +#else +# define STAM_PROFILE_STOP_NS(pProfile, 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 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. + */ +#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 + * @{ + */ + +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 The cross context VM structure. + * @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 The cross context VM structure. + * @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 The cross context VM structure. + * @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 The cross context VM structure. + * @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, ...) RT_IPRT_FORMAT_ATTR(7, 8); +VMMR3DECL(int) STAMR3RegisterF(PVM pVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, + const char *pszDesc, const char *pszName, ...) RT_IPRT_FORMAT_ATTR(7, 8); +VMMR3DECL(int) STAMR3RegisterVU(PUVM pUVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, + const char *pszDesc, const char *pszName, va_list args) RT_IPRT_FORMAT_ATTR(7, 0); +VMMR3DECL(int) STAMR3RegisterV(PVM pVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, + const char *pszDesc, const char *pszName, va_list args) RT_IPRT_FORMAT_ATTR(7, 0); + +/** + * Resets the sample. + * @param pVM The cross context VM structure. + * @param pvSample The sample registered using STAMR3RegisterCallback. + */ +typedef DECLCALLBACKTYPE(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 cross context VM structure. + * @param pvSample The sample registered using STAMR3RegisterCallback. + * @param pszBuf The buffer to print into. + * @param cchBuf The size of the buffer. + */ +typedef DECLCALLBACKTYPE(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, ...) RT_IPRT_FORMAT_ATTR(8, 9); +VMMR3DECL(int) STAMR3RegisterCallbackV(PVM pVM, void *pvSample, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, + PFNSTAMR3CALLBACKRESET pfnReset, PFNSTAMR3CALLBACKPRINT pfnPrint, + const char *pszDesc, const char *pszName, va_list args) RT_IPRT_FORMAT_ATTR(8, 0); + +VMMR3DECL(int) STAMR3RegisterRefresh(PUVM pUVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, + STAMUNIT enmUnit, uint8_t iRefreshGrp, const char *pszDesc, + const char *pszName, ...) RT_IPRT_FORMAT_ATTR(8, 9); +VMMR3DECL(int) STAMR3RegisterRefreshV(PUVM pUVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, + STAMUNIT enmUnit, uint8_t iRefreshGrp, const char *pszDesc, + const char *pszName, va_list va) RT_IPRT_FORMAT_ATTR(8, 0); + +VMMR3DECL(int) STAMR3Deregister(PUVM pUVM, const char *pszPat); +VMMR3DECL(int) STAMR3DeregisterF(PUVM pUVM, const char *pszPatFmt, ...) RT_IPRT_FORMAT_ATTR(2, 3); +VMMR3DECL(int) STAMR3DeregisterV(PUVM pUVM, const char *pszPatFmt, va_list va) RT_IPRT_FORMAT_ATTR(2, 0); +VMMR3DECL(int) STAMR3DeregisterByPrefix(PUVM pUVM, const char *pszPrefix); +VMMR3DECL(int) STAMR3DeregisterByAddr(PUVM pUVM, void *pvSample); + +VMMR3DECL(int) STAMR3Reset(PUVM pUVM, const char *pszPat); +VMMR3DECL(int) STAMR3Snapshot(PUVM pUVM, const char *pszPat, char **ppszSnapshot, size_t *pcchSnapshot, bool fWithDesc); +VMMR3DECL(int) STAMR3SnapshotFree(PUVM pUVM, char *pszSnapshot); +VMMR3DECL(int) STAMR3Dump(PUVM pUVM, const char *pszPat); +VMMR3DECL(int) STAMR3DumpToReleaseLog(PUVM pUVM, const char *pszPat); +VMMR3DECL(int) STAMR3Print(PUVM pUVM, 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 pszUnit The unit as string. This is a permanent string, + * same as returned by STAMR3GetUnit(). + * @param enmVisibility The visibility. + * @param pszDesc The description. + * @param pvUser The pvUser argument given to STAMR3Enum(). + */ +typedef DECLCALLBACKTYPE(int, FNSTAMR3ENUM,(const char *pszName, STAMTYPE enmType, void *pvSample, STAMUNIT enmUnit, + const char *pszUnit, STAMVISIBILITY enmVisibility, const char *pszDesc, void *pvUser)); +/** Pointer to a FNSTAMR3ENUM(). */ +typedef FNSTAMR3ENUM *PFNSTAMR3ENUM; + +VMMR3DECL(int) STAMR3Enum(PUVM pUVM, const char *pszPat, PFNSTAMR3ENUM pfnEnum, void *pvUser); +VMMR3DECL(const char *) STAMR3GetUnit(STAMUNIT enmUnit); +VMMR3DECL(const char *) STAMR3GetUnit1(STAMUNIT enmUnit); +VMMR3DECL(const char *) STAMR3GetUnit2(STAMUNIT enmUnit); + +/** @} */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_stam_h */ + diff --git a/include/VBox/vmm/stam.mac b/include/VBox/vmm/stam.mac new file mode 100644 index 00000000..b70a881a --- /dev/null +++ b/include/VBox/vmm/stam.mac @@ -0,0 +1,392 @@ +;; @file +; STAM - Statistics Manager. +; + +; +; Copyright (C) 2006-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox 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. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%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..2bd62d3a --- /dev/null +++ b/include/VBox/vmm/tm.h @@ -0,0 +1,322 @@ +/** @file + * TM - Time Manager. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_tm_h +#define VBOX_INCLUDED_vmm_tm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#ifdef IN_RING3 +# include <iprt/time.h> +#endif + +RT_C_DECLS_BEGIN + +/** @defgroup grp_tm The Time Manager API + * @ingroup grp_vmm + * @{ + */ + +/** 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) +/** Used in ring-0. Must set this or TMTIMER_FLAGS_NO_RING0. */ +#define TMTIMER_FLAGS_RING0 RT_BIT_32(1) +/** Not used in ring-0 (for refactoring and doc purposes). */ +#define TMTIMER_FLAGS_NO_RING0 RT_BIT_32(31) +/** @} */ + + +VMMDECL(void) TMNotifyStartOfExecution(PVMCC pVM, PVMCPUCC pVCpu); +VMMDECL(void) TMNotifyEndOfExecution(PVMCC pVM, PVMCPUCC pVCpu, uint64_t uTsc); +VMM_INT_DECL(void) TMNotifyStartOfHalt(PVMCPUCC pVCpu); +VMM_INT_DECL(void) TMNotifyEndOfHalt(PVMCPUCC pVCpu); +#ifdef IN_RING3 +VMMR3DECL(int) TMR3NotifySuspend(PVM pVM, PVMCPU pVCpu); +VMMR3DECL(int) TMR3NotifyResume(PVM pVM, PVMCPU pVCpu); +VMMR3DECL(int) TMR3SetWarpDrive(PUVM pUVM, uint32_t u32Percent); +VMMR3DECL(uint32_t) TMR3GetWarpDrive(PUVM pUVM); +#endif +VMM_INT_DECL(uint32_t) TMCalcHostTimerFrequency(PVMCC pVM, PVMCPUCC pVCpu); +#ifdef IN_RING3 +VMMR3DECL(int) TMR3GetCpuLoadTimes(PVM pVM, VMCPUID idCpu, uint64_t *pcNsTotal, uint64_t *pcNsExecuting, + uint64_t *pcNsHalted, uint64_t *pcNsOther); +VMMR3DECL(int) TMR3GetCpuLoadPercents(PUVM pVUM, VMCPUID idCpu, uint64_t *pcMsInterval, uint8_t *pcPctExecuting, + uint8_t *pcPctHalted, uint8_t *pcPctOther); +#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(PVMCC pVM); +VMM_INT_DECL(uint64_t) TMVirtualGetNoCheck(PVMCC pVM); +VMM_INT_DECL(uint64_t) TMVirtualSyncGetLag(PVMCC pVM); +VMM_INT_DECL(uint32_t) TMVirtualSyncGetCatchUpPct(PVMCC pVM); +VMM_INT_DECL(uint64_t) TMVirtualGetFreq(PVM pVM); +VMM_INT_DECL(uint64_t) TMVirtualSyncGet(PVMCC pVM); +VMM_INT_DECL(uint64_t) TMVirtualSyncGetNoCheck(PVMCC pVM); +VMM_INT_DECL(uint64_t) TMVirtualSyncGetNoCheckWithTsc(PVMCC pVM, uint64_t *puTscNow); +VMM_INT_DECL(uint64_t) TMVirtualSyncGetEx(PVMCC pVM, bool fCheckTimers); +VMM_INT_DECL(uint64_t) TMVirtualSyncGetWithDeadlineNoCheck(PVMCC pVM, uint64_t *pcNsToDeadline, + uint64_t *puDeadlineVersion, uint64_t *puTscNow); +VMMDECL(uint64_t) TMVirtualSyncGetNsToDeadline(PVMCC pVM, uint64_t *puDeadlineVersion, uint64_t *puTscNow); +VMM_INT_DECL(bool) TMVirtualSyncIsCurrentDeadlineVersion(PVMCC pVM, uint64_t uDeadlineVersion); +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); +VMM_INT_DECL(bool) TMVirtualIsTicking(PVM pVM); + +VMMR3DECL(uint64_t) TMR3TimeVirtGet(PUVM pUVM); +VMMR3DECL(uint64_t) TMR3TimeVirtGetMilli(PUVM pUVM); +VMMR3DECL(uint64_t) TMR3TimeVirtGetMicro(PUVM pUVM); +VMMR3DECL(uint64_t) TMR3TimeVirtGetNano(PUVM pUVM); +/** @} */ + + +/** @name CPU Clock Methods + * @{ + */ +VMMDECL(uint64_t) TMCpuTickGet(PVMCPUCC pVCpu); +VMM_INT_DECL(uint64_t) TMCpuTickGetNoCheck(PVMCPUCC pVCpu); +VMM_INT_DECL(bool) TMCpuTickCanUseRealTSC(PVMCC pVM, PVMCPUCC pVCpu, uint64_t *poffRealTSC, bool *pfParavirtTsc); +VMM_INT_DECL(uint64_t) TMCpuTickGetDeadlineAndTscOffset(PVMCC pVM, PVMCPUCC pVCpu, uint64_t *poffRealTsc, + bool *pfOffsettedTsc, bool *pfParavirtTsc, + uint64_t *puTscNow, uint64_t *puDeadlineVersion); +VMM_INT_DECL(int) TMCpuTickSet(PVMCC pVM, PVMCPUCC pVCpu, uint64_t u64Tick); +VMM_INT_DECL(int) TMCpuTickSetLastSeen(PVMCPUCC pVCpu, uint64_t u64LastSeenTick); +VMM_INT_DECL(uint64_t) TMCpuTickGetLastSeen(PVMCPUCC pVCpu); +VMMDECL(uint64_t) TMCpuTicksPerSecond(PVMCC pVM); +VMM_INT_DECL(bool) TMCpuTickIsTicking(PVMCPUCC pVCpu); +/** @} */ + + +/** @name Timer Methods + * @{ + */ +/** + * Device timer callback function. + * + * @param pDevIns Device instance of the device which registered the timer. + * @param hTimer The timer handle. + * @param pvUser User argument specified upon timer creation. + */ +typedef DECLCALLBACKTYPE(void, FNTMTIMERDEV,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, 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 hTimer The timer handle. + * @param pvUser User argument specified upon timer creation. + */ +typedef DECLCALLBACKTYPE(void, FNTMTIMERUSB,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, 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 hTimer The timer handle. + * @param pvUser User argument specified upon timer creation. + */ +typedef DECLCALLBACKTYPE(void, FNTMTIMERDRV,(PPDMDRVINS pDrvIns, TMTIMERHANDLE hTimer, 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 hTimer The timer handle. + */ +typedef DECLCALLBACKTYPE(void, FNTMTIMERSRV,(PPDMSRVINS pSrvIns, TMTIMERHANDLE hTimer)); +/** Pointer to a service timer callback function. */ +typedef FNTMTIMERSRV *PFNTMTIMERSRV; + +/** + * Internal timer callback function. + * + * @param pVM The cross context VM structure. + * @param hTimer The timer handle. + * @param pvUser User argument specified upon timer creation. + */ +typedef DECLCALLBACKTYPE(void, FNTMTIMERINT,(PVM pVM, TMTIMERHANDLE hTimer, 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 DECLCALLBACKTYPE(void, FNTMTIMEREXT,(void *pvUser)); +/** Pointer to an external timer callback function. */ +typedef FNTMTIMEREXT *PFNTMTIMEREXT; + +VMMDECL(int) TMTimerLock(PVMCC pVM, TMTIMERHANDLE hTimer, int rcBusy); +VMMDECL(void) TMTimerUnlock(PVMCC pVM, TMTIMERHANDLE hTimer); +VMMDECL(bool) TMTimerIsLockOwner(PVMCC pVM, TMTIMERHANDLE hTimer); +VMMDECL(int) TMTimerSet(PVMCC pVM, TMTIMERHANDLE hTimer, uint64_t u64Expire); +VMMDECL(int) TMTimerSetRelative(PVMCC pVM, TMTIMERHANDLE hTimer, uint64_t cTicksToNext, uint64_t *pu64Now); +VMMDECL(int) TMTimerSetFrequencyHint(PVMCC pVM, TMTIMERHANDLE hTimer, uint32_t uHz); +VMMDECL(uint64_t) TMTimerGet(PVMCC pVM, TMTIMERHANDLE hTimer); +VMMDECL(int) TMTimerStop(PVMCC pVM, TMTIMERHANDLE hTimer); +VMMDECL(bool) TMTimerIsActive(PVMCC pVM, TMTIMERHANDLE hTimer); + +VMMDECL(int) TMTimerSetMillies(PVMCC pVM, TMTIMERHANDLE hTimer, uint32_t cMilliesToNext); +VMMDECL(int) TMTimerSetMicro(PVMCC pVM, TMTIMERHANDLE hTimer, uint64_t cMicrosToNext); +VMMDECL(int) TMTimerSetNano(PVMCC pVM, TMTIMERHANDLE hTimer, uint64_t cNanosToNext); +VMMDECL(uint64_t) TMTimerGetNano(PVMCC pVM, TMTIMERHANDLE hTimer); +VMMDECL(uint64_t) TMTimerGetMicro(PVMCC pVM, TMTIMERHANDLE hTimer); +VMMDECL(uint64_t) TMTimerGetMilli(PVMCC pVM, TMTIMERHANDLE hTimer); +VMMDECL(uint64_t) TMTimerGetFreq(PVMCC pVM, TMTIMERHANDLE hTimer); +VMMDECL(uint64_t) TMTimerGetExpire(PVMCC pVM, TMTIMERHANDLE hTimer); +VMMDECL(uint64_t) TMTimerToNano(PVMCC pVM, TMTIMERHANDLE hTimer, uint64_t cTicks); +VMMDECL(uint64_t) TMTimerToMicro(PVMCC pVM, TMTIMERHANDLE hTimer, uint64_t cTicks); +VMMDECL(uint64_t) TMTimerToMilli(PVMCC pVM, TMTIMERHANDLE hTimer, uint64_t cTicks); +VMMDECL(uint64_t) TMTimerFromNano(PVMCC pVM, TMTIMERHANDLE hTimer, uint64_t cNanoSecs); +VMMDECL(uint64_t) TMTimerFromMicro(PVMCC pVM, TMTIMERHANDLE hTimer, uint64_t cMicroSecs); +VMMDECL(uint64_t) TMTimerFromMilli(PVMCC pVM, TMTIMERHANDLE hTimer, uint64_t cMilliSecs); + +VMMDECL(bool) TMTimerPollBool(PVMCC pVM, PVMCPUCC pVCpu); +VMM_INT_DECL(void) TMTimerPollVoid(PVMCC pVM, PVMCPUCC pVCpu); +VMM_INT_DECL(uint64_t) TMTimerPollGIP(PVMCC pVM, PVMCPUCC pVCpu, uint64_t *pu64Delta); +/** @} */ + + +/** @defgroup grp_tm_r3 The TM Host Context Ring-3 API + * @{ + */ +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) TMR3TimerCreateDevice(PVM pVM, PPDMDEVINS pDevIns, TMCLOCK enmClock, PFNTMTIMERDEV pfnCallback, + void *pvUser, uint32_t fFlags, const char *pszName, PTMTIMERHANDLE phTimer); +VMM_INT_DECL(int) TMR3TimerCreateUsb(PVM pVM, PPDMUSBINS pUsbIns, TMCLOCK enmClock, PFNTMTIMERUSB pfnCallback, + void *pvUser, uint32_t fFlags, const char *pszName, PTMTIMERHANDLE phTimer); +VMM_INT_DECL(int) TMR3TimerCreateDriver(PVM pVM, PPDMDRVINS pDrvIns, TMCLOCK enmClock, PFNTMTIMERDRV pfnCallback, + void *pvUser, uint32_t fFlags, const char *pszName, PTMTIMERHANDLE phTimer); +VMMR3DECL(int) TMR3TimerCreate(PVM pVM, TMCLOCK enmClock, PFNTMTIMERINT pfnCallback, void *pvUser, uint32_t fFlags, + const char *pszName, PTMTIMERHANDLE phTimer); +VMMR3DECL(int) TMR3TimerDestroy(PVM pVM, TMTIMERHANDLE hTimer); +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(PVMCC pVM, TMTIMERHANDLE hTimer, PSSMHANDLE pSSM); +VMMR3DECL(int) TMR3TimerLoad(PVMCC pVM, TMTIMERHANDLE hTimer, PSSMHANDLE pSSM); +VMMR3DECL(int) TMR3TimerSkip(PSSMHANDLE pSSM, bool *pfActive); +VMMR3DECL(int) TMR3TimerSetCritSect(PVMCC pVM, TMTIMERHANDLE hTimer, 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); + +VMMR3_INT_DECL(int) TMR3CpuTickParavirtEnable(PVM pVM); +VMMR3_INT_DECL(int) TMR3CpuTickParavirtDisable(PVM pVM); +VMMR3_INT_DECL(bool) TMR3CpuTickIsFixedRateMonotonic(PVM pVM, bool fWithParavirtEnabled); +/** @} */ + + +/** @defgroup grp_tm_r0 The TM Host Context Ring-0 API + * @{ + */ +VMMR0_INT_DECL(void) TMR0InitPerVMData(PGVM pGVM); +VMMR0_INT_DECL(void) TMR0CleanupVM(PGVM pGVM); +VMMR0_INT_DECL(int) TMR0TimerQueueGrow(PGVM pGVM, uint32_t idxQueue, uint32_t cMinTimers); +/** @} */ + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_tm_h */ + diff --git a/include/VBox/vmm/trpm.h b/include/VBox/vmm/trpm.h new file mode 100644 index 00000000..0e23dd5b --- /dev/null +++ b/include/VBox/vmm/trpm.h @@ -0,0 +1,102 @@ +/** @file + * TRPM - The Trap Monitor. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_trpm_h +#define VBOX_INCLUDED_vmm_trpm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <iprt/x86.h> + + +RT_C_DECLS_BEGIN +/** @defgroup grp_trpm The Trap Monitor API + * @ingroup grp_vmm + * @{ + */ + +/** + * TRPM event type. + */ +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; + +VMMDECL(int) TRPMQueryTrap(PVMCPU pVCpu, uint8_t *pu8TrapNo, PTRPMEVENT penmType); +VMMDECL(uint8_t) TRPMGetTrapNo(PVMCPU pVCpu); +VMMDECL(uint32_t) TRPMGetErrorCode(PVMCPU pVCpu); +VMMDECL(RTGCUINTPTR) TRPMGetFaultAddress(PVMCPU pVCpu); +VMMDECL(uint8_t) TRPMGetInstrLength(PVMCPU pVCpu); +VMMDECL(bool) TRPMIsTrapDueToIcebp(PVMCPU pVCpu); +VMMDECL(int) TRPMResetTrap(PVMCPU pVCpu); +VMMDECL(int) TRPMAssertTrap(PVMCPUCC pVCpu, uint8_t u8TrapNo, TRPMEVENT enmType); +VMMDECL(int) TRPMAssertXcptPF(PVMCPUCC pVCpu, RTGCUINTPTR uCR2, uint32_t uErrorCode); +VMMDECL(void) TRPMSetErrorCode(PVMCPU pVCpu, uint32_t uErrorCode); +VMMDECL(void) TRPMSetFaultAddress(PVMCPU pVCpu, RTGCUINTPTR uCR2); +VMMDECL(void) TRPMSetInstrLength(PVMCPU pVCpu, uint8_t cbInstr); +VMMDECL(void) TRPMSetTrapDueToIcebp(PVMCPU pVCpu); +VMMDECL(bool) TRPMIsSoftwareInterrupt(PVMCPU pVCpu); +VMMDECL(bool) TRPMHasTrap(PVMCPU pVCpu); +VMMDECL(int) TRPMQueryTrapAll(PVMCPU pVCpu, uint8_t *pu8TrapNo, PTRPMEVENT pEnmType, uint32_t *puErrorCode, + PRTGCUINTPTR puCR2, uint8_t *pcbInstr, bool *pfIcebp); + +#ifdef IN_RING3 +/** @defgroup grp_trpm_r3 TRPM Host Context Ring 3 API + * @{ + */ +VMMR3DECL(int) TRPMR3Init(PVM pVM); +VMMR3DECL(void) TRPMR3Relocate(PVM pVM, RTGCINTPTR offDelta); +VMMR3DECL(void) TRPMR3ResetCpu(PVMCPU pVCpu); +VMMR3DECL(void) TRPMR3Reset(PVM pVM); +VMMR3DECL(int) TRPMR3Term(PVM pVM); +VMMR3DECL(int) TRPMR3InjectEvent(PVM pVM, PVMCPU pVCpu, TRPMEVENT enmEvent, bool *pfInjected); +/** @} */ +#endif + +/** @} */ +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_trpm_h */ diff --git a/include/VBox/vmm/trpm.mac b/include/VBox/vmm/trpm.mac new file mode 100644 index 00000000..6e1c1cd6 --- /dev/null +++ b/include/VBox/vmm/trpm.mac @@ -0,0 +1,57 @@ +;; @file +; TRPM - The Trap Monitor. +; + +; +; Copyright (C) 2006-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox 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. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%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..2edc65db --- /dev/null +++ b/include/VBox/vmm/uvm.h @@ -0,0 +1,195 @@ +/** @file + * GVM - The Global VM Data. + */ + +/* + * Copyright (C) 2007-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_uvm_h +#define VBOX_INCLUDED_vmm_uvm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <iprt/assert.h> + +/** @addtogroup grp_vm + * @{ */ + + +/** + * 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 VMM_INCLUDED_SRC_include_VMInternal_h + struct VMINTUSERPERVMCPU s; +#endif + uint8_t padding[512]; + } vm; + + /** The DBGF data. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_DBGFInternal_h + struct DBGFUSERPERVMCPU s; +#endif + uint8_t padding[64]; + } dbgf; + +} 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 VMM_INCLUDED_SRC_include_VMInternal_h + struct VMINTUSERPERVM s; +#endif + uint8_t padding[512]; + } vm; + + /** The MM data. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_MMInternal_h + struct MMUSERPERVM s; +#endif + uint8_t padding[32]; + } mm; + + /** The PDM data. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_PDMInternal_h + struct PDMUSERPERVM s; +#endif + uint8_t padding[256]; + } pdm; + + /** The STAM data. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_STAMInternal_h + struct STAMUSERPERVM s; +#endif + uint8_t padding[30208]; + } stam; + + /** The DBGF data. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_DBGFInternal_h + struct DBGFUSERPERVM s; +#endif + uint8_t padding[1024]; + } dbgf; + + /** 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)) +/** @def UVM_ASSERT_VALID_EXT_RETURN + * Asserts a user mode VM handle is valid for external access. + */ +#define UVM_ASSERT_VALID_EXT_RETURN_VOID(a_pUVM) \ + AssertMsgReturnVoid( 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)) + +/** @} */ +#endif /* !VBOX_INCLUDED_vmm_uvm_h */ + diff --git a/include/VBox/vmm/vm.h b/include/VBox/vmm/vm.h new file mode 100644 index 00000000..2ebdda94 --- /dev/null +++ b/include/VBox/vmm/vm.h @@ -0,0 +1,1519 @@ +/** @file + * VM - The Virtual Machine, data. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_vm_h +#define VBOX_INCLUDED_vmm_vm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifndef VBOX_FOR_DTRACE_LIB +# ifndef USING_VMM_COMMON_DEFS +# error "Compile job does not include VMM_COMMON_DEFS from src/VBox/VMM/Config.kmk - make sure you really need to include this file!" +# endif +# include <iprt/param.h> +# include <VBox/param.h> +# 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 VMM_INCLUDED_SRC_include_CPUMInternal_h +#endif + + + +/** @defgroup grp_vm The Virtual Machine + * @ingroup grp_vmm + * @{ + */ + +/** + * 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, + /** CPU started in HM context. */ + VMCPUSTATE_STARTED_HM, + /** Executing guest code and can be poked (RC or STI bits of HM). */ + VMCPUSTATE_STARTED_EXEC, + /** Executing guest code using NEM. */ + VMCPUSTATE_STARTED_EXEC_NEM, + VMCPUSTATE_STARTED_EXEC_NEM_WAIT, + VMCPUSTATE_STARTED_EXEC_NEM_CANCELED, + /** Halted. */ + VMCPUSTATE_STARTED_HALTED, + + /** The end of valid virtual CPU states. */ + VMCPUSTATE_END, + + /** Ensure 32-bit type. */ + VMCPUSTATE_32BIT_HACK = 0x7fffffff +} VMCPUSTATE; + +/** Enables 64-bit FFs. */ +#define VMCPU_WITH_64_BIT_FFS + + +/** + * The cross context virtual CPU structure. + * + * Run 'kmk run-struct-tests' (from src/VBox/VMM if you like) after updating! + */ +typedef struct VMCPU +{ + /** @name Volatile per-cpu data. + * @{ */ + /** Per CPU forced action. + * See the VMCPU_FF_* \#defines. Updated atomically. */ +#ifdef VMCPU_WITH_64_BIT_FFS + uint64_t volatile fLocalForcedActions; +#else + uint32_t volatile fLocalForcedActions; + uint32_t fForLocalForcedActionsExpansion; +#endif + /** The CPU state. */ + VMCPUSTATE volatile enmState; + + /** Padding up to 64 bytes. */ + uint8_t abAlignment0[64 - 12]; + /** @} */ + + /** IEM part. + * @remarks This comes first as it allows the use of 8-bit immediates for the + * first 64 bytes of the structure, reducing code size a wee bit. */ +#ifdef VMM_INCLUDED_SRC_include_IEMInternal_h /* For PDB hacking. */ + union VMCPUUNIONIEMFULL +#else + union VMCPUUNIONIEMSTUB +#endif + { +#ifdef VMM_INCLUDED_SRC_include_IEMInternal_h + struct IEMCPU s; +#endif + uint8_t padding[32832]; /* multiple of 64 */ + } iem; + + /** @name Static per-cpu data. + * (Putting this after IEM, hoping that it's less frequently used than it.) + * @{ */ + /** Ring-3 Host Context VM Pointer. */ + PVMR3 pVMR3; + /** Ring-0 Host Context VM Pointer, currently used by VTG/dtrace. */ + RTR0PTR pVCpuR0ForVtg; + /** Raw-mode Context VM Pointer. */ + uint32_t pVMRC; + /** Padding for new raw-mode (long mode). */ + uint32_t pVMRCPadding; + /** Pointer to the ring-3 UVMCPU structure. */ + PUVMCPU pUVCpu; + /** The native thread handle. */ + RTNATIVETHREAD hNativeThread; + /** The native R0 thread handle. (different from the R3 handle!) */ + RTNATIVETHREAD hNativeThreadR0; + /** The IPRT thread handle (for VMMDevTesting). */ + RTTHREAD hThread; + /** The CPU ID. + * This is the index into the VM::aCpu array. */ +#ifdef IN_RING0 + VMCPUID idCpuUnsafe; +#else + VMCPUID idCpu; +#endif + + /** 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[64 - 6 * (HC_ARCH_BITS == 32 ? 4 : 8) - 8 - 4]; + /** @} */ + + /** HM part. */ + union VMCPUUNIONHM + { +#ifdef VMM_INCLUDED_SRC_include_HMInternal_h + struct HMCPU s; +#endif + uint8_t padding[9984]; /* multiple of 64 */ + } hm; + + /** NEM part. */ + union VMCPUUNIONNEM + { +#ifdef VMM_INCLUDED_SRC_include_NEMInternal_h + struct NEMCPU s; +#endif + uint8_t padding[4608]; /* multiple of 64 */ + } nem; + + /** TRPM part. */ + union VMCPUUNIONTRPM + { +#ifdef VMM_INCLUDED_SRC_include_TRPMInternal_h + struct TRPMCPU s; +#endif + uint8_t padding[128]; /* multiple of 64 */ + } trpm; + + /** TM part. */ + union VMCPUUNIONTM + { +#ifdef VMM_INCLUDED_SRC_include_TMInternal_h + struct TMCPU s; +#endif + uint8_t padding[5760]; /* multiple of 64 */ + } tm; + + /** VMM part. */ + union VMCPUUNIONVMM + { +#ifdef VMM_INCLUDED_SRC_include_VMMInternal_h + struct VMMCPU s; +#endif + uint8_t padding[9536]; /* multiple of 64 */ + } vmm; + + /** PDM part. */ + union VMCPUUNIONPDM + { +#ifdef VMM_INCLUDED_SRC_include_PDMInternal_h + struct PDMCPU s; +#endif + uint8_t padding[256]; /* multiple of 64 */ + } pdm; + + /** IOM part. */ + union VMCPUUNIONIOM + { +#ifdef VMM_INCLUDED_SRC_include_IOMInternal_h + struct IOMCPU s; +#endif + uint8_t padding[512]; /* multiple of 64 */ + } iom; + + /** DBGF part. + * @todo Combine this with other tiny structures. */ + union VMCPUUNIONDBGF + { +#ifdef VMM_INCLUDED_SRC_include_DBGFInternal_h + struct DBGFCPU s; +#endif + uint8_t padding[512]; /* multiple of 64 */ + } dbgf; + + /** GIM part. */ + union VMCPUUNIONGIM + { +#ifdef VMM_INCLUDED_SRC_include_GIMInternal_h + struct GIMCPU s; +#endif + uint8_t padding[512]; /* multiple of 64 */ + } gim; + + /** APIC part. */ + union VMCPUUNIONAPIC + { +#ifdef VMM_INCLUDED_SRC_include_APICInternal_h + struct APICCPU s; +#endif + uint8_t padding[3840]; /* multiple of 64 */ + } apic; + + /* + * Some less frequently used global members that doesn't need to take up + * precious space at the head of the structure. + */ + + /** Trace groups enable flags. */ + uint32_t fTraceGroups; /* 64 / 44 */ + /** Number of collisions hashing the ring-0 EMT handle. */ + uint8_t cEmtHashCollisions; + uint8_t abAdHoc[3]; + /** Profiling samples for use by ad hoc profiling. */ + STAMPROFILEADV aStatAdHoc[8]; /* size: 40*8 = 320 */ + + /** Align the following members on page boundary. */ + uint8_t abAlignment2[696]; + + /** PGM part. */ + union VMCPUUNIONPGM + { +#ifdef VMM_INCLUDED_SRC_include_PGMInternal_h + struct PGMCPU s; +#endif + uint8_t padding[4096 + 28672]; /* multiple of 4096 */ + } pgm; + + /** CPUM part. */ + union VMCPUUNIONCPUM + { +#ifdef VMM_INCLUDED_SRC_include_CPUMInternal_h + struct CPUMCPU s; +#endif +#ifdef VMCPU_INCL_CPUM_GST_CTX + /** The guest CPUM context for direct use by execution engines. + * This is not for general consumption, but for HM, REM, IEM, and maybe a few + * others. The rest will use the function based CPUM API. */ + CPUMCTX GstCtx; +#endif + uint8_t padding[102400]; /* multiple of 4096 */ + } cpum; + + /** EM part. */ + union VMCPUUNIONEM + { +#ifdef VMM_INCLUDED_SRC_include_EMInternal_h + struct EMCPU s; +#endif + uint8_t padding[40960]; /* multiple of 4096 */ + } em; + +} VMCPU; + + +#ifndef VBOX_FOR_DTRACE_LIB +/* Make sure the structure size is aligned on a 16384 boundary for arm64 purposes. */ +AssertCompileSizeAlignment(VMCPU, 16384); + +/** @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) + +# define VMCPU_ASSERT_STATE_2(pVCpu, enmExpectedState, a_enmExpectedState2) \ + do { \ + VMCPUSTATE enmState = VMCPU_GET_STATE(pVCpu); \ + AssertMsg( enmState == (enmExpectedState) \ + || enmState == (a_enmExpectedState2), \ + ("enmState=%d enmExpectedState=%d enmExpectedState2=%d idCpu=%u\n", \ + enmState, enmExpectedState, a_enmExpectedState2, (pVCpu)->idCpu)); \ + } while (0) +#else +# define VMCPU_ASSERT_STATE(pVCpu, enmExpectedState) do { } while (0) +# define VMCPU_ASSERT_STATE_2(pVCpu, enmExpectedState, a_enmExpectedState2) 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 raw-mode context VMM Core module. */ +#define VMMRC_MAIN_MODULE_NAME "VMMRC.rc" +/** 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. + * + * Available VM bits: + * 0, 1, 5, 6, 7, 13, 14, 15, 16, 17, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 + * + * + * Available VMCPU bits: + * 14, 15, 36 to 63 + * + * @todo If we run low on VMCPU, we may consider merging the SELM bits + * + * @{ + */ +/** The virtual sync clock has been stopped, go to TM until it has been + * restarted... */ +#define VM_FF_TM_VIRTUAL_SYNC RT_BIT_32(VM_FF_TM_VIRTUAL_SYNC_BIT) +#define VM_FF_TM_VIRTUAL_SYNC_BIT 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(VM_FF_REQUEST_BIT) +#define VM_FF_REQUEST_BIT 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(VM_FF_PGM_NEED_HANDY_PAGES_BIT) +#define VM_FF_PGM_NEED_HANDY_PAGES_BIT 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(VM_FF_PGM_NO_MEMORY_BIT) +#define VM_FF_PGM_NO_MEMORY_BIT 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(VM_FF_PGM_POOL_FLUSH_PENDING_BIT) +#define VM_FF_PGM_POOL_FLUSH_PENDING_BIT 20 +/** Suspend the VM - debug only. */ +#define VM_FF_DEBUG_SUSPEND RT_BIT_32(VM_FF_DEBUG_SUSPEND_BIT) +#define VM_FF_DEBUG_SUSPEND_BIT 31 + + +/** This action forces the VM to check any pending interrupts on the APIC. */ +#define VMCPU_FF_INTERRUPT_APIC RT_BIT_64(VMCPU_FF_INTERRUPT_APIC_BIT) +#define VMCPU_FF_INTERRUPT_APIC_BIT 0 +/** This action forces the VM to check any pending interrups on the PIC. */ +#define VMCPU_FF_INTERRUPT_PIC RT_BIT_64(VMCPU_FF_INTERRUPT_PIC_BIT) +#define VMCPU_FF_INTERRUPT_PIC_BIT 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_64(VMCPU_FF_TIMER_BIT) +#define VMCPU_FF_TIMER_BIT 2 +/** This action forces the VM to check any pending NMIs. */ +#define VMCPU_FF_INTERRUPT_NMI RT_BIT_64(VMCPU_FF_INTERRUPT_NMI_BIT) +#define VMCPU_FF_INTERRUPT_NMI_BIT 3 +/** This action forces the VM to check any pending SMIs. */ +#define VMCPU_FF_INTERRUPT_SMI RT_BIT_64(VMCPU_FF_INTERRUPT_SMI_BIT) +#define VMCPU_FF_INTERRUPT_SMI_BIT 4 +/** PDM critical section unlocking is pending, process promptly upon return to R3. */ +#define VMCPU_FF_PDM_CRITSECT RT_BIT_64(VMCPU_FF_PDM_CRITSECT_BIT) +#define VMCPU_FF_PDM_CRITSECT_BIT 5 +/** Special EM internal force flag that is used by EMUnhaltAndWakeUp() to force + * the virtual CPU out of the next (/current) halted state. It is not processed + * nor cleared by emR3ForcedActions (similar to VMCPU_FF_BLOCK_NMIS), instead it + * is cleared the next time EM leaves the HALTED state. */ +#define VMCPU_FF_UNHALT RT_BIT_64(VMCPU_FF_UNHALT_BIT) +#define VMCPU_FF_UNHALT_BIT 6 +/** Pending IEM action (mask). */ +#define VMCPU_FF_IEM RT_BIT_64(VMCPU_FF_IEM_BIT) +/** Pending IEM action (bit number). */ +#define VMCPU_FF_IEM_BIT 7 +/** Pending APIC action (bit number). */ +#define VMCPU_FF_UPDATE_APIC_BIT 8 +/** This action forces the VM to update APIC's asynchronously arrived + * interrupts as pending interrupts. */ +#define VMCPU_FF_UPDATE_APIC RT_BIT_64(VMCPU_FF_UPDATE_APIC_BIT) +/** 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_64(VMCPU_FF_REQUEST_BIT) +#define VMCPU_FF_REQUEST_BIT 9 +/** Pending DBGF event (alternative to passing VINF_EM_DBG_EVENT around). */ +#define VMCPU_FF_DBGF RT_BIT_64(VMCPU_FF_DBGF_BIT) +/** The bit number for VMCPU_FF_DBGF. */ +#define VMCPU_FF_DBGF_BIT 10 +/** Hardware virtualized nested-guest interrupt pending. */ +#define VMCPU_FF_INTERRUPT_NESTED_GUEST RT_BIT_64(VMCPU_FF_INTERRUPT_NESTED_GUEST_BIT) +#define VMCPU_FF_INTERRUPT_NESTED_GUEST_BIT 11 +/** This action forces PGM to update changes to CR3 when the guest was in HM mode + * (when using nested paging). */ +#define VMCPU_FF_HM_UPDATE_CR3 RT_BIT_64(VMCPU_FF_HM_UPDATE_CR3_BIT) +#define VMCPU_FF_HM_UPDATE_CR3_BIT 12 +/* Bit 13 used to be VMCPU_FF_HM_UPDATE_PAE_PDPES. */ +/** 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_64(VMCPU_FF_PGM_SYNC_CR3_BIT) +#define VMCPU_FF_PGM_SYNC_CR3_BIT 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_64(VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL_BIT) +#define VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL_BIT 17 +/** Check for pending TLB shootdown actions (deprecated) + * Reserved for future HM re-use if necessary / safe. + * Consumer: HM */ +#define VMCPU_FF_TLB_SHOOTDOWN_UNUSED RT_BIT_64(VMCPU_FF_TLB_SHOOTDOWN_UNUSED_BIT) +#define VMCPU_FF_TLB_SHOOTDOWN_UNUSED_BIT 18 +/** Check for pending TLB flush action. + * Consumer: HM + * @todo rename to VMCPU_FF_HM_TLB_FLUSH */ +#define VMCPU_FF_TLB_FLUSH RT_BIT_64(VMCPU_FF_TLB_FLUSH_BIT) +/** The bit number for VMCPU_FF_TLB_FLUSH. */ +#define VMCPU_FF_TLB_FLUSH_BIT 19 +/* 20 used to be VMCPU_FF_TRPM_SYNC_IDT (raw-mode only). */ +/* 21 used to be VMCPU_FF_SELM_SYNC_TSS (raw-mode only). */ +/* 22 used to be VMCPU_FF_SELM_SYNC_GDT (raw-mode only). */ +/* 23 used to be VMCPU_FF_SELM_SYNC_LDT (raw-mode only). */ +/* 24 used to be VMCPU_FF_INHIBIT_INTERRUPTS, which moved to CPUMCTX::eflags.uBoth in v7.0.4. */ +/* 25 used to be VMCPU_FF_BLOCK_NMIS, which moved to CPUMCTX::eflags.uBoth in v7.0.4. */ +/** Force return to Ring-3. */ +#define VMCPU_FF_TO_R3 RT_BIT_64(VMCPU_FF_TO_R3_BIT) +#define VMCPU_FF_TO_R3_BIT 28 +/** Force return to ring-3 to service pending I/O or MMIO write. + * This is a backup for mechanism VINF_IOM_R3_IOPORT_COMMIT_WRITE and + * VINF_IOM_R3_MMIO_COMMIT_WRITE, allowing VINF_EM_DBG_BREAKPOINT and similar + * status codes to be propagated at the same time without loss. */ +#define VMCPU_FF_IOM RT_BIT_64(VMCPU_FF_IOM_BIT) +#define VMCPU_FF_IOM_BIT 29 +/* 30 used to be VMCPU_FF_CPUM */ +/** VMX-preemption timer expired. */ +#define VMCPU_FF_VMX_PREEMPT_TIMER RT_BIT_64(VMCPU_FF_VMX_PREEMPT_TIMER_BIT) +#define VMCPU_FF_VMX_PREEMPT_TIMER_BIT 31 +/** Pending MTF (Monitor Trap Flag) event. */ +#define VMCPU_FF_VMX_MTF RT_BIT_64(VMCPU_FF_VMX_MTF_BIT) +#define VMCPU_FF_VMX_MTF_BIT 32 +/** VMX APIC-write emulation pending. + * @todo possible candidate for internal EFLAGS, or maybe just a summary bit + * (see also VMCPU_FF_VMX_INT_WINDOW). */ +#define VMCPU_FF_VMX_APIC_WRITE RT_BIT_64(VMCPU_FF_VMX_APIC_WRITE_BIT) +#define VMCPU_FF_VMX_APIC_WRITE_BIT 33 +/** VMX interrupt-window event pending. + * + * "Pending" is misleading here, it would be better to say that the event need + * to be generated at the next opportunity and that this flag causes it to be + * polled for on every instruction boundrary and such. + * + * @todo Change the IEM side of this to not poll but to track down the places + * where it can be generated and set an internal EFLAGS bit that causes it + * to be checked out when finishing the current instruction. */ +#define VMCPU_FF_VMX_INT_WINDOW RT_BIT_64(VMCPU_FF_VMX_INT_WINDOW_BIT) +#define VMCPU_FF_VMX_INT_WINDOW_BIT 34 +/** VMX NMI-window event pending. + * Same "pending" comment and todo in VMCPU_FF_VMX_INT_WINDOW. */ +#define VMCPU_FF_VMX_NMI_WINDOW RT_BIT_64(VMCPU_FF_VMX_NMI_WINDOW_BIT) +#define VMCPU_FF_VMX_NMI_WINDOW_BIT 35 + + +/** 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 | VMCPU_FF_DBGF ) + +/** 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_UPDATE_APIC | VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC \ + | VMCPU_FF_REQUEST | VMCPU_FF_INTERRUPT_NMI | VMCPU_FF_INTERRUPT_SMI \ + | VMCPU_FF_UNHALT | VMCPU_FF_TIMER | VMCPU_FF_DBGF \ + | VMCPU_FF_INTERRUPT_NESTED_GUEST) + +/** 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_UPDATE_APIC | VMCPU_FF_DBGF \ + | VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL \ + | VMCPU_FF_INTERRUPT_NESTED_GUEST | VMCPU_FF_VMX_MTF | VMCPU_FF_VMX_APIC_WRITE \ + | VMCPU_FF_VMX_PREEMPT_TIMER | VMCPU_FF_VMX_NMI_WINDOW | VMCPU_FF_VMX_INT_WINDOW ) + +/** 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 ) + +/** 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_HM_UPDATE_CR3 | VMCPU_FF_IEM | VMCPU_FF_IOM ) + +/** 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_DBGF ) + +/** Normal priority VM actions. */ +#define VM_FF_NORMAL_PRIORITY_MASK ( VM_FF_REQUEST | VM_FF_PDM_QUEUES | VM_FF_PDM_DMA | 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 REP[|NE|E] STRINS loops to yield immediately. */ +#define VM_FF_HIGH_PRIORITY_POST_REPSTR_MASK ( VM_FF_TM_VIRTUAL_SYNC | VM_FF_PGM_NEED_HANDY_PAGES | VM_FF_PGM_NO_MEMORY \ + | VM_FF_EMT_RENDEZVOUS | VM_FF_PGM_POOL_FLUSH_PENDING | VM_FF_RESET) +/** VM flags that cause the REP[|NE|E] STRINS loops to yield. */ +#define VM_FF_YIELD_REPSTR_MASK ( VM_FF_HIGH_PRIORITY_POST_REPSTR_MASK \ + | VM_FF_PDM_QUEUES | VM_FF_PDM_DMA | VM_FF_DBGF | VM_FF_DEBUG_SUSPEND ) +/** VMCPU flags that cause the REP[|NE|E] STRINS loops to yield immediately. */ +#ifdef IN_RING3 +# define VMCPU_FF_HIGH_PRIORITY_POST_REPSTR_MASK ( VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL | VMCPU_FF_DBGF \ + | VMCPU_FF_VMX_MTF ) +#else +# define VMCPU_FF_HIGH_PRIORITY_POST_REPSTR_MASK ( VMCPU_FF_TO_R3 | VMCPU_FF_IEM | VMCPU_FF_IOM | VMCPU_FF_PGM_SYNC_CR3 \ + | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL | VMCPU_FF_DBGF | VMCPU_FF_VMX_MTF ) +#endif +/** VMCPU flags that cause the REP[|NE|E] STRINS loops to yield, interrupts + * enabled. */ +#define VMCPU_FF_YIELD_REPSTR_MASK ( VMCPU_FF_HIGH_PRIORITY_POST_REPSTR_MASK \ + | VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_UPDATE_APIC | VMCPU_FF_INTERRUPT_PIC \ + | VMCPU_FF_INTERRUPT_NMI | VMCPU_FF_INTERRUPT_SMI | VMCPU_FF_PDM_CRITSECT \ + | VMCPU_FF_TIMER | VMCPU_FF_REQUEST \ + | VMCPU_FF_INTERRUPT_NESTED_GUEST ) +/** VMCPU flags that cause the REP[|NE|E] STRINS loops to yield, interrupts + * disabled. */ +#define VMCPU_FF_YIELD_REPSTR_NOINT_MASK ( VMCPU_FF_YIELD_REPSTR_MASK \ + & ~( VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_UPDATE_APIC | VMCPU_FF_INTERRUPT_PIC \ + | VMCPU_FF_INTERRUPT_NESTED_GUEST) ) + +/** VM Flags that cause the HM loops to go back to ring-3. */ +#define VM_FF_HM_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 HM loops to go back to ring-3. */ +#define VMCPU_FF_HM_TO_R3_MASK ( VMCPU_FF_TO_R3 | VMCPU_FF_TIMER | VMCPU_FF_PDM_CRITSECT \ + | VMCPU_FF_IEM | VMCPU_FF_IOM) + +/** High priority ring-0 VM pre HM-mode execution mask. */ +#define VM_FF_HP_R0_PRE_HM_MASK (VM_FF_HM_TO_R3_MASK | VM_FF_REQUEST | VM_FF_PGM_POOL_FLUSH_PENDING | VM_FF_PDM_DMA) +/** High priority ring-0 VMCPU pre HM-mode execution mask. */ +#define VMCPU_FF_HP_R0_PRE_HM_MASK ( VMCPU_FF_HM_TO_R3_MASK | VMCPU_FF_PGM_SYNC_CR3 \ + | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL | VMCPU_FF_REQUEST \ + | VMCPU_FF_VMX_APIC_WRITE | VMCPU_FF_VMX_MTF | VMCPU_FF_VMX_PREEMPT_TIMER) +/** High priority ring-0 VM pre HM-mode execution mask, single stepping. */ +#define VM_FF_HP_R0_PRE_HM_STEP_MASK (VM_FF_HP_R0_PRE_HM_MASK & ~( VM_FF_TM_VIRTUAL_SYNC | VM_FF_PDM_QUEUES \ + | VM_FF_EMT_RENDEZVOUS | VM_FF_REQUEST \ + | VM_FF_PDM_DMA) ) +/** High priority ring-0 VMCPU pre HM-mode execution mask, single stepping. */ +#define VMCPU_FF_HP_R0_PRE_HM_STEP_MASK (VMCPU_FF_HP_R0_PRE_HM_MASK & ~( VMCPU_FF_TO_R3 | VMCPU_FF_TIMER \ + | VMCPU_FF_PDM_CRITSECT | VMCPU_FF_REQUEST) ) + +/** All the VMX nested-guest flags. */ +#define VMCPU_FF_VMX_ALL_MASK ( VMCPU_FF_VMX_PREEMPT_TIMER | VMCPU_FF_VMX_MTF | VMCPU_FF_VMX_APIC_WRITE \ + | VMCPU_FF_VMX_INT_WINDOW | VMCPU_FF_VMX_NMI_WINDOW ) + +/** All the forced VM flags. */ +#define VM_FF_ALL_MASK (UINT32_MAX) +/** All the forced VMCPU flags. */ +#define VMCPU_FF_ALL_MASK (UINT32_MAX) + +/** 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_NEED_HANDY_PAGES | 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_PDM_CRITSECT | VMCPU_FF_TLB_FLUSH)) +/** @} */ + +/** @def VM_FF_SET + * Sets a single force action flag. + * + * @param pVM The cross context VM structure. + * @param fFlag The flag to set. + */ +#define VM_FF_SET(pVM, fFlag) do { \ + AssertCompile(RT_IS_POWER_OF_TWO(fFlag)); \ + AssertCompile((fFlag) == RT_BIT_32(fFlag##_BIT)); \ + ASMAtomicOrU32(&(pVM)->fGlobalForcedActions, (fFlag)); \ + } while (0) + +/** @def VMCPU_FF_SET + * Sets a single force action flag for the given VCPU. + * + * @param pVCpu The cross context virtual CPU structure. + * @param fFlag The flag to set. + * @sa VMCPU_FF_SET_MASK + */ +#ifdef VMCPU_WITH_64_BIT_FFS +# define VMCPU_FF_SET(pVCpu, fFlag) do { \ + AssertCompile(RT_IS_POWER_OF_TWO(fFlag)); \ + AssertCompile((fFlag) == RT_BIT_64(fFlag##_BIT)); \ + ASMAtomicBitSet(&(pVCpu)->fLocalForcedActions, fFlag##_BIT); \ + } while (0) +#else +# define VMCPU_FF_SET(pVCpu, fFlag) do { \ + AssertCompile(RT_IS_POWER_OF_TWO(fFlag)); \ + AssertCompile((fFlag) == RT_BIT_32(fFlag##_BIT)); \ + ASMAtomicOrU32(&(pVCpu)->fLocalForcedActions, (fFlag)); \ + } while (0) +#endif + +/** @def VMCPU_FF_SET_MASK + * Sets a two or more force action flag for the given VCPU. + * + * @param pVCpu The cross context virtual CPU structure. + * @param fFlags The flags to set. + * @sa VMCPU_FF_SET + */ +#ifdef VMCPU_WITH_64_BIT_FFS +# if ARCH_BITS > 32 +# define VMCPU_FF_SET_MASK(pVCpu, fFlags) \ + do { ASMAtomicOrU64(&pVCpu->fLocalForcedActions, (fFlags)); } while (0) +# else +# define VMCPU_FF_SET_MASK(pVCpu, fFlags) do { \ + if (!((fFlags) >> 32)) ASMAtomicOrU32((uint32_t volatile *)&pVCpu->fLocalForcedActions, (uint32_t)(fFlags)); \ + else ASMAtomicOrU64(&pVCpu->fLocalForcedActions, (fFlags)); \ + } while (0) +# endif +#else +# define VMCPU_FF_SET_MASK(pVCpu, fFlags) \ + do { ASMAtomicOrU32(&pVCpu->fLocalForcedActions, (fFlags)); } while (0) +#endif + +/** @def VM_FF_CLEAR + * Clears a single force action flag. + * + * @param pVM The cross context VM structure. + * @param fFlag The flag to clear. + */ +#define VM_FF_CLEAR(pVM, fFlag) do { \ + AssertCompile(RT_IS_POWER_OF_TWO(fFlag)); \ + AssertCompile((fFlag) == RT_BIT_32(fFlag##_BIT)); \ + ASMAtomicAndU32(&(pVM)->fGlobalForcedActions, ~(fFlag)); \ + } while (0) + +/** @def VMCPU_FF_CLEAR + * Clears a single force action flag for the given VCPU. + * + * @param pVCpu The cross context virtual CPU structure. + * @param fFlag The flag to clear. + */ +#ifdef VMCPU_WITH_64_BIT_FFS +# define VMCPU_FF_CLEAR(pVCpu, fFlag) do { \ + AssertCompile(RT_IS_POWER_OF_TWO(fFlag)); \ + AssertCompile((fFlag) == RT_BIT_64(fFlag##_BIT)); \ + ASMAtomicBitClear(&(pVCpu)->fLocalForcedActions, fFlag##_BIT); \ + } while (0) +#else +# define VMCPU_FF_CLEAR(pVCpu, fFlag) do { \ + AssertCompile(RT_IS_POWER_OF_TWO(fFlag)); \ + AssertCompile((fFlag) == RT_BIT_32(fFlag##_BIT)); \ + ASMAtomicAndU32(&(pVCpu)->fLocalForcedActions, ~(fFlag)); \ + } while (0) +#endif + +/** @def VMCPU_FF_CLEAR_MASK + * Clears two or more force action flags for the given VCPU. + * + * @param pVCpu The cross context virtual CPU structure. + * @param fFlags The flags to clear. + */ +#ifdef VMCPU_WITH_64_BIT_FFS +# if ARCH_BITS > 32 +# define VMCPU_FF_CLEAR_MASK(pVCpu, fFlags) \ + do { ASMAtomicAndU64(&(pVCpu)->fLocalForcedActions, ~(fFlags)); } while (0) +# else +# define VMCPU_FF_CLEAR_MASK(pVCpu, fFlags) do { \ + if (!((fFlags) >> 32)) ASMAtomicAndU32((uint32_t volatile *)&(pVCpu)->fLocalForcedActions, ~(uint32_t)(fFlags)); \ + else ASMAtomicAndU64(&(pVCpu)->fLocalForcedActions, ~(fFlags)); \ + } while (0) +# endif +#else +# define VMCPU_FF_CLEAR_MASK(pVCpu, fFlags) \ + do { ASMAtomicAndU32(&(pVCpu)->fLocalForcedActions, ~(fFlags)); } while (0) +#endif + +/** @def VM_FF_IS_SET + * Checks if single a force action flag is set. + * + * @param pVM The cross context VM structure. + * @param fFlag The flag to check. + * @sa VM_FF_IS_ANY_SET + */ +#if !defined(VBOX_STRICT) || !defined(RT_COMPILER_SUPPORTS_LAMBDA) +# define VM_FF_IS_SET(pVM, fFlag) RT_BOOL((pVM)->fGlobalForcedActions & (fFlag)) +#else +# define VM_FF_IS_SET(pVM, fFlag) \ + ([](PVM a_pVM) -> bool \ + { \ + AssertCompile(RT_IS_POWER_OF_TWO(fFlag)); \ + AssertCompile((fFlag) == RT_BIT_32(fFlag##_BIT)); \ + return RT_BOOL(a_pVM->fGlobalForcedActions & (fFlag)); \ + }(pVM)) +#endif + +/** @def VMCPU_FF_IS_SET + * Checks if a single force action flag is set for the given VCPU. + * + * @param pVCpu The cross context virtual CPU structure. + * @param fFlag The flag to check. + * @sa VMCPU_FF_IS_ANY_SET + */ +#if !defined(VBOX_STRICT) || !defined(RT_COMPILER_SUPPORTS_LAMBDA) +# define VMCPU_FF_IS_SET(pVCpu, fFlag) RT_BOOL((pVCpu)->fLocalForcedActions & (fFlag)) +#else +# define VMCPU_FF_IS_SET(pVCpu, fFlag) \ + ([](PCVMCPU a_pVCpu) -> bool \ + { \ + AssertCompile(RT_IS_POWER_OF_TWO(fFlag)); \ + AssertCompile((fFlag) == RT_BIT_64(fFlag##_BIT)); \ + return RT_BOOL(a_pVCpu->fLocalForcedActions & (fFlag)); \ + }(pVCpu)) +#endif + +/** @def VM_FF_IS_ANY_SET + * Checks if one or more force action in the specified set is pending. + * + * @param pVM The cross context VM structure. + * @param fFlags The flags to check for. + * @sa VM_FF_IS_SET + */ +#define VM_FF_IS_ANY_SET(pVM, fFlags) RT_BOOL((pVM)->fGlobalForcedActions & (fFlags)) + +/** @def VMCPU_FF_IS_ANY_SET + * Checks if two or more force action flags in the specified set is set for the given VCPU. + * + * @param pVCpu The cross context virtual CPU structure. + * @param fFlags The flags to check for. + * @sa VMCPU_FF_IS_SET + */ +#define VMCPU_FF_IS_ANY_SET(pVCpu, fFlags) RT_BOOL((pVCpu)->fLocalForcedActions & (fFlags)) + +/** @def VM_FF_TEST_AND_CLEAR + * 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 The cross context VM structure. + * @param fFlag Flag constant to check and clear (_BIT is appended). + */ +#define VM_FF_TEST_AND_CLEAR(pVM, fFlag) (ASMAtomicBitTestAndClear(&(pVM)->fGlobalForcedActions, fFlag##_BIT)) + +/** @def VMCPU_FF_TEST_AND_CLEAR + * 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 The cross context virtual CPU structure. + * @param fFlag Flag constant to check and clear (_BIT is appended). + */ +#define VMCPU_FF_TEST_AND_CLEAR(pVCpu, fFlag) (ASMAtomicBitTestAndClear(&(pVCpu)->fLocalForcedActions, fFlag##_BIT)) + +/** @def VM_FF_IS_PENDING_EXCEPT + * Checks if one or more force action in the specified set is pending while one + * or more other ones are not. + * + * @param pVM The cross context VM structure. + * @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 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) AssertMsg(VMCPU_IS_EMT(pVCpu), \ + ("Not emulation thread! Thread=%RTnthrd ThreadEMT=%RTnthrd idCpu=%u\n", \ + RTThreadNativeSelf(), (pVCpu) ? (pVCpu)->hNativeThreadR0 : 0, \ + (pVCpu) ? (pVCpu)->idCpu : 0)) +#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) \ + AssertMsgReturn(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 or the VM is not running. + */ +#if defined(IN_RC) || defined(IN_RING0) +# define VMCPU_ASSERT_EMT_OR_NOT_RUNNING(pVCpu) \ + Assert( VMCPU_IS_EMT(pVCpu) \ + || !VM_IS_RUNNING_FOR_ASSERTIONS_ONLY((pVCpu)->CTX_SUFF(pVM)) ) +#else +# define VMCPU_ASSERT_EMT_OR_NOT_RUNNING(pVCpu) \ + AssertMsg( VMCPU_IS_EMT(pVCpu) \ + || !VM_IS_RUNNING_FOR_ASSERTIONS_ONLY((pVCpu)->CTX_SUFF(pVM)), \ + ("Not emulation thread! Thread=%RTnthrd ThreadEMT=%RTnthrd idCpu=%#x\n", \ + RTThreadNativeSelf(), (pVCpu)->hNativeThread, (pVCpu)->idCpu)) +#endif + +/** @def VMSTATE_IS_RUNNING + * Checks if the given state indicates a running VM. + */ +#define VMSTATE_IS_RUNNING(a_enmVMState) \ + ( (enmVMState) == VMSTATE_RUNNING \ + || (enmVMState) == VMSTATE_RUNNING_LS ) + +/** @def VM_IS_RUNNING_FOR_ASSERTIONS_ONLY + * Checks if the VM is running. + * @note This is only for pure debug assertions. No AssertReturn or similar! + * @sa VMSTATE_IS_RUNNING + */ +#define VM_IS_RUNNING_FOR_ASSERTIONS_ONLY(pVM) \ + ( (pVM)->enmVMState == VMSTATE_RUNNING \ + || (pVM)->enmVMState == VMSTATE_RUNNING_LS ) + +/** @def VM_ASSERT_IS_NOT_RUNNING + * Asserts that the VM is not running. + */ +#if defined(IN_RC) || defined(IN_RING0) +#define VM_ASSERT_IS_NOT_RUNNING(pVM) Assert(!VM_IS_RUNNING_FOR_ASSERTIONS_ONLY(pVM)) +#else +#define VM_ASSERT_IS_NOT_RUNNING(pVM) AssertMsg(!VM_IS_RUNNING_FOR_ASSERTIONS_ONLY(pVM), \ + ("VM is running. enmVMState=%d\n", (pVM)->enmVMState)) +#endif + +/** @def VM_ASSERT_EMT0 + * Asserts that the current thread IS emulation thread \#0 (EMT0). + */ +#ifdef IN_RING3 +# define VM_ASSERT_EMT0(a_pVM) VMCPU_ASSERT_EMT((a_pVM)->apCpusR3[0]) +#else +# define VM_ASSERT_EMT0(a_pVM) VMCPU_ASSERT_EMT(&(a_pVM)->aCpus[0]) +#endif + +/** @def VM_ASSERT_EMT0_RETURN + * Asserts that the current thread IS emulation thread \#0 (EMT0) and returns if + * it isn't. + */ +#ifdef IN_RING3 +# define VM_ASSERT_EMT0_RETURN(pVM, rc) VMCPU_ASSERT_EMT_RETURN((pVM)->apCpusR3[0], (rc)) +#else +# define VM_ASSERT_EMT0_RETURN(pVM, rc) VMCPU_ASSERT_EMT_RETURN(&(pVM)->aCpus[0], (rc)) +#endif + + +/** + * 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 + * 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_IS_VALID_EXT + * Asserts a the VM handle is valid for external access, i.e. not being destroy + * or terminated. */ +#define VM_IS_VALID_EXT(pVM) \ + ( RT_VALID_ALIGNED_PTR(pVM, PAGE_SIZE) \ + && ( (unsigned)(pVM)->enmVMState < (unsigned)VMSTATE_DESTROYING \ + || ( (unsigned)(pVM)->enmVMState == (unsigned)VMSTATE_DESTROYING \ + && VM_IS_EMT(pVM))) ) + +/** @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(VM_IS_VALID_EXT(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 */ + + +/** + * Helper that HM and NEM uses for safely modifying VM::bMainExecutionEngine. + * + * ONLY HM and NEM MAY USE THIS! + * + * @param a_pVM The cross context VM structure. + * @param a_bValue The new value. + * @internal + */ +#define VM_SET_MAIN_EXECUTION_ENGINE(a_pVM, a_bValue) \ + do { \ + *const_cast<uint8_t *>(&(a_pVM)->bMainExecutionEngine) = (a_bValue); \ + ASMCompilerBarrier(); /* just to be on the safe side */ \ + } while (0) + +/** + * Checks whether iem-executes-all-mode is used. + * + * @retval true if IEM is used. + * @retval false if not. + * + * @param a_pVM The cross context VM structure. + * @sa VM_IS_HM_OR_NEM_ENABLED, VM_IS_HM_ENABLED, VM_IS_NEM_ENABLED. + * @internal + */ +#define VM_IS_EXEC_ENGINE_IEM(a_pVM) ((a_pVM)->bMainExecutionEngine == VM_EXEC_ENGINE_IEM) + +/** + * Checks whether HM (VT-x/AMD-V) or NEM is being used by this VM. + * + * @retval true if either is used. + * @retval false if software virtualization (raw-mode) is used. + * + * @param a_pVM The cross context VM structure. + * @sa VM_IS_EXEC_ENGINE_IEM, VM_IS_HM_ENABLED, VM_IS_NEM_ENABLED. + * @internal + */ +#define VM_IS_HM_OR_NEM_ENABLED(a_pVM) ((a_pVM)->bMainExecutionEngine != VM_EXEC_ENGINE_IEM) + +/** + * Checks whether HM is being used by this VM. + * + * @retval true if HM (VT-x/AMD-v) is used. + * @retval false if not. + * + * @param a_pVM The cross context VM structure. + * @sa VM_IS_NEM_ENABLED, VM_IS_EXEC_ENGINE_IEM, VM_IS_HM_OR_NEM_ENABLED. + * @internal + */ +#define VM_IS_HM_ENABLED(a_pVM) ((a_pVM)->bMainExecutionEngine == VM_EXEC_ENGINE_HW_VIRT) + +/** + * Checks whether NEM is being used by this VM. + * + * @retval true if a native hypervisor API is used. + * @retval false if not. + * + * @param a_pVM The cross context VM structure. + * @sa VM_IS_HM_ENABLED, VM_IS_EXEC_ENGINE_IEM, VM_IS_HM_OR_NEM_ENABLED. + * @internal + */ +#define VM_IS_NEM_ENABLED(a_pVM) ((a_pVM)->bMainExecutionEngine == VM_EXEC_ENGINE_NATIVE_API) + + +/** + * The cross context VM structure. + * + * It contains 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 'kmk run-struct-tests' (from src/VBox/VMM if you like) after updating! + */ +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. */ +#ifdef IN_RING0 + PSUPDRVSESSION pSessionUnsafe; +#else + PSUPDRVSESSION pSession; +#endif + /** Pointer to the ring-3 VM structure. */ + PUVM pUVM; + /** Ring-3 Host Context VM Pointer. */ +#ifdef IN_RING0 + R3PTRTYPE(struct VM *) pVMR3Unsafe; +#else + R3PTRTYPE(struct VM *) pVMR3; +#endif + /** Ring-0 Host Context VM pointer for making ring-0 calls. */ + R0PTRTYPE(struct VM *) pVMR0ForCall; + /** Raw-mode Context VM Pointer. */ + uint32_t pVMRC; + /** Padding for new raw-mode (long mode). */ + uint32_t pVMRCPadding; + + /** The GVM VM handle. Only the GVM should modify this field. */ +#ifdef IN_RING0 + uint32_t hSelfUnsafe; +#else + uint32_t hSelf; +#endif + /** Number of virtual CPUs. */ +#ifdef IN_RING0 + uint32_t cCpusUnsafe; +#else + uint32_t cCpus; +#endif + /** CPU excution cap (1-100) */ + uint32_t uCpuExecutionCap; + + /** Size of the VM structure. */ + uint32_t cbSelf; + /** Size of the VMCPU structure. */ + uint32_t cbVCpu; + /** Structure version number (TBD). */ + uint32_t uStructVersion; + + /** @name Various items that are frequently accessed. + * @{ */ + /** The main execution engine, VM_EXEC_ENGINE_XXX. + * This is set early during vmR3InitRing3 by HM or NEM. */ + uint8_t const bMainExecutionEngine; + + /** Hardware VM support is available and enabled. + * Determined very early during init. + * This is placed here for performance reasons. + * @todo obsoleted by bMainExecutionEngine, eliminate. */ + bool fHMEnabled; + /** @} */ + + /** Alignment padding. */ + uint8_t uPadding1[6]; + + /** @name Debugging + * @{ */ + /** Ring-3 Host Context VM Pointer. */ + R3PTRTYPE(RTTRACEBUF) hTraceBufR3; + /** Ring-0 Host Context VM Pointer. */ + R0PTRTYPE(RTTRACEBUF) hTraceBufR0; + /** @} */ + + /** Max EMT hash lookup collisions (in GVMM). */ + uint8_t cMaxEmtHashCollisions; + + /** Padding - the unions must be aligned on a 64 bytes boundary. */ + uint8_t abAlignment3[HC_ARCH_BITS == 64 ? 23 : 51]; + + /** CPUM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_CPUMInternal_h + struct CPUM s; +#endif +#ifdef VBOX_INCLUDED_vmm_cpum_h + /** Read only info exposed about the host and guest CPUs. */ + struct + { + /** Padding for hidden fields. */ + uint8_t abHidden0[64 + 48]; + /** Guest CPU feature information. */ + CPUMFEATURES GuestFeatures; + } const ro; +#endif + /** @todo this is rather bloated because of static MSR range allocation. + * Probably a good idea to move it to a separate R0 allocation... */ + uint8_t padding[8832 + 128*8192 + 0x1d00]; /* multiple of 64 */ + } cpum; + + /** PGM part. + * @note 16384 aligned for zero and mmio page storage. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_PGMInternal_h + struct PGM s; +#endif + uint8_t padding[53888]; /* multiple of 64 */ + } pgm; + + /** VMM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_VMMInternal_h + struct VMM s; +#endif + uint8_t padding[1600]; /* multiple of 64 */ + } vmm; + + /** HM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_HMInternal_h + struct HM s; +#endif + uint8_t padding[5504]; /* multiple of 64 */ + } hm; + + /** TRPM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_TRPMInternal_h + struct TRPM s; +#endif + uint8_t padding[2048]; /* multiple of 64 */ + } trpm; + + /** SELM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_SELMInternal_h + struct SELM s; +#endif + uint8_t padding[768]; /* multiple of 64 */ + } selm; + + /** MM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_MMInternal_h + struct MM s; +#endif + uint8_t padding[192]; /* multiple of 64 */ + } mm; + + /** PDM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_PDMInternal_h + struct PDM s; +#endif + uint8_t padding[22400]; /* multiple of 64 */ + } pdm; + + /** IOM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_IOMInternal_h + struct IOM s; +#endif + uint8_t padding[1152]; /* multiple of 64 */ + } iom; + + /** EM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_EMInternal_h + struct EM s; +#endif + uint8_t padding[256]; /* multiple of 64 */ + } em; + + /** NEM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_NEMInternal_h + struct NEM s; +#endif + uint8_t padding[4608]; /* multiple of 64 */ + } nem; + + /** TM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_TMInternal_h + struct TM s; +#endif + uint8_t padding[10112]; /* multiple of 64 */ + } tm; + + /** DBGF part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_DBGFInternal_h + struct DBGF s; +#endif +#ifdef VBOX_INCLUDED_vmm_dbgf_h + /** Read only info exposed about interrupt breakpoints and selected events. */ + struct + { + /** Bitmap of enabled hardware interrupt breakpoints. */ + uint32_t bmHardIntBreakpoints[256 / 32]; + /** Bitmap of enabled software interrupt breakpoints. */ + uint32_t bmSoftIntBreakpoints[256 / 32]; + /** Bitmap of selected events. + * This includes non-selectable events too for simplicity, we maintain the + * state for some of these, as it may come in handy. */ + uint64_t bmSelectedEvents[(DBGFEVENT_END + 63) / 64]; + /** Enabled hardware interrupt breakpoints. */ + uint32_t cHardIntBreakpoints; + /** Enabled software interrupt breakpoints. */ + uint32_t cSoftIntBreakpoints; + /** The number of selected events. */ + uint32_t cSelectedEvents; + /** The number of enabled hardware breakpoints. */ + uint8_t cEnabledHwBreakpoints; + /** The number of enabled hardware I/O breakpoints. */ + uint8_t cEnabledHwIoBreakpoints; + uint8_t au8Alignment1[2]; /**< Alignment padding. */ + /** The number of enabled INT3 breakpoints. */ + uint32_t volatile cEnabledInt3Breakpoints; + } const ro; +#endif + uint8_t padding[2432]; /* multiple of 64 */ + } dbgf; + + /** SSM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_SSMInternal_h + struct SSM s; +#endif + uint8_t padding[128]; /* multiple of 64 */ + } ssm; + + union + { +#ifdef VMM_INCLUDED_SRC_include_GIMInternal_h + struct GIM s; +#endif + uint8_t padding[448]; /* multiple of 64 */ + } gim; + + union + { +#ifdef VMM_INCLUDED_SRC_include_APICInternal_h + struct APIC s; +#endif + uint8_t padding[128]; /* multiple of 8 */ + } apic; + + /* ---- begin small stuff ---- */ + + /** VM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_VMInternal_h + struct VMINT s; +#endif + uint8_t padding[32]; /* multiple of 8 */ + } vm; + + /** CFGM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_CFGMInternal_h + struct CFGM s; +#endif + uint8_t padding[8]; /* multiple of 8 */ + } cfgm; + + /** IEM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_IEMInternal_h + struct IEM s; +#endif + uint8_t padding[16]; /* multiple of 8 */ + } iem; + + /** Statistics for ring-0 only components. */ + struct + { + /** GMMR0 stats. */ + struct + { + /** Chunk TLB hits. */ + uint64_t cChunkTlbHits; + /** Chunk TLB misses. */ + uint64_t cChunkTlbMisses; + } gmm; + uint64_t au64Padding[6]; /* probably more comming here... */ + } R0Stats; + + union + { +#ifdef VMM_INCLUDED_SRC_include_GCMInternal_h + struct GCM s; +#endif + uint8_t padding[32]; /* multiple of 8 */ + } gcm; + + /** Padding for aligning the structure size on a page boundrary. */ + uint8_t abAlignment2[8872 - sizeof(PVMCPUR3) * VMM_MAX_CPU_COUNT]; + + /* ---- end small stuff ---- */ + + /** Array of VMCPU ring-3 pointers. */ + PVMCPUR3 apCpusR3[VMM_MAX_CPU_COUNT]; + + /* This point is aligned on a 16384 boundrary (for arm64 purposes). */ +} VM; +#ifndef VBOX_FOR_DTRACE_LIB +//AssertCompileSizeAlignment(VM, 16384); +#endif + + +#ifdef IN_RC +RT_C_DECLS_BEGIN + +/** The VM structure. + * This is imported from the VMMRCBuiltin module, i.e. it's a one of those magic + * globals which we should avoid using. + */ +extern DECLIMPORT(VM) g_VM; + +/** The VMCPU structure for virtual CPU \#0. + * This is imported from the VMMRCBuiltin module, i.e. it's a one of those magic + * globals which we should avoid using. + */ +extern DECLIMPORT(VMCPU) g_VCpu0; + +RT_C_DECLS_END +#endif + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_vm_h */ + diff --git a/include/VBox/vmm/vm.mac b/include/VBox/vmm/vm.mac new file mode 100644 index 00000000..2aa4b515 --- /dev/null +++ b/include/VBox/vmm/vm.mac @@ -0,0 +1,187 @@ +;; @file +; VM - The Virtual Machine. +; + +; +; Copyright (C) 2006-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox 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. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef ___VBox_vmm_vm_mac +%define ___VBox_vmm_vm_mac + +%include "VBox/vmm/stam.mac" +%include "VBox/param.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 VMCPU structure. +struc VMCPU + .fLocalForcedActions resd 1 + alignb 8 + .enmState resd 1 + + alignb 64 + .iem resb 32832 + + alignb 64 + .pVMR3 RTR3PTR_RES 1 + .pVCpuR0ForVtg RTR0PTR_RES 1 + .pVMRC resq 1 + .pUVCpu RTR3PTR_RES 1 + .hNativeThread RTR3PTR_RES 1 + .hNativeThreadR0 RTR0PTR_RES 1 + .hThread RTR3PTR_RES 1 + .idCpu resd 1 + + alignb 64 + .hm resb 9984 + alignb 64 + .nem resb 4608 + alignb 64 + .trpm resb 128 + alignb 64 + .tm resb 5760 + alignb 64 + .vmm resb 9536 + alignb 64 + .pdm resb 256 + alignb 64 + .iom resb 512 + alignb 64 + .dbgf resb 512 + alignb 64 + .gim resb 512 + alignb 64 + .apic resb 3840 + + alignb 64 + .fTraceGroups resd 1 + .cEmtHashCollisions resb 1 + .abAdHoc resb 3 + alignb 8 + .aStatAdHoc resb STAMPROFILEADV_size * 8 + + alignb 4096 + .pgm resb 4096+28672 + alignb 4096 + .cpum resb 102400 +%define VMCPU.cpum.GstCtx VMCPU.cpum + alignb 4096 + .em resb 40960 + alignb 16384 +endstruc + +;; +; 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 + .pVMR0ForCall RTR0PTR_RES 1 + .pVMRC resq 1 +%ifdef IN_RING0 + .hSelfUnsafe resd 1 + .cCpusUnsafe resd 1 +%else + .hSelf resd 1 + .cCpus resd 1 +%endif + .uCpuExecutionCap resd 1 + .cbSelf resd 1 + .cbVCpu resd 1 + .uStructVersion resd 1 + .bMainExecutionEngine resb 1 + .fHMEnabled resb 1 + + .uPadding1 resb 6 + + .hTraceBufR3 RTR3PTR_RES 1 + .hTraceBufR0 RTR0PTR_RES 1 + + alignb 64 + .cpum resb 8832 + 128*8192 + alignb 16384 + .pgm resb 53888 + alignb 64 + .vmm resb 1600 + alignb 64 + .hm resb 5504 + alignb 64 + .trpm resb 2048 + alignb 64 + .selm resb 768 + alignb 64 + .mm resb 192 + alignb 64 + .pdm resb 22400 + alignb 64 + .iom resb 1152 + alignb 64 + .em resb 256 + alignb 64 + .nem resb 4608 + alignb 64 + .tm resb 10112 + alignb 64 + .dbgf resb 2432 + alignb 64 + .ssm resb 128 + alignb 64 + .gim resb 448 + alignb 64 + .apic resb 128 + alignb 64 + .vm resb 32 + .cfgm resb 8 + .iem resb 16 + .R0Stats resb 64 + .gcm resb 32 + + times ((($ + VMM_MAX_CPU_COUNT * RTR0PTR_CB + 16383) & ~16383) - ($ + VMM_MAX_CPU_COUNT * RTR0PTR_CB)) resb 1 + .apCpusR3 RTR3PTR_RES VMM_MAX_CPU_COUNT + alignb 16384 + +endstruc + + +%endif + diff --git a/include/VBox/vmm/vmapi.h b/include/VBox/vmm/vmapi.h new file mode 100644 index 00000000..0a1cc09b --- /dev/null +++ b/include/VBox/vmm/vmapi.h @@ -0,0 +1,485 @@ +/** @file + * VM - The Virtual Machine, API. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_vmapi_h +#define VBOX_INCLUDED_vmm_vmapi_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <VBox/vmm/stam.h> +#include <VBox/vmm/cfgm.h> + +#include <iprt/stdarg.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_vm_apis VM All Contexts API + * @ingroup grp_vm + * @{ */ + +/** @name VM_EXEC_ENGINE_XXX - VM::bMainExecutionEngine values. + * @sa EMR3QueryMainExecutionEngine, VM_IS_RAW_MODE_ENABLED, VM_IS_HM_ENABLED, + * VM_IS_HM_OR_NEM_ENABLED, VM_IS_NEM_ENABLED, VM_SET_MAIN_EXECUTION_ENGINE + * @{ */ +/** Has not yet been set. */ +#define VM_EXEC_ENGINE_NOT_SET UINT8_C(0) +/** The interpreter (IEM). */ +#define VM_EXEC_ENGINE_IEM UINT8_C(1) +/** Hardware assisted virtualization thru HM. */ +#define VM_EXEC_ENGINE_HW_VIRT UINT8_C(2) +/** Hardware assisted virtualization thru native API (NEM). */ +#define VM_EXEC_ENGINE_NATIVE_API UINT8_C(3) +/** @} */ + + +/** + * VM error callback function. + * + * @param pUVM The user mode 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 SRC_POS 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 DECLCALLBACKTYPE(void, FNVMATERROR,(PUVM pUVM, void *pvUser, int rc, RT_SRC_POS_DECL, + const char *pszFormat, va_list args)); +/** Pointer to a VM error callback. */ +typedef FNVMATERROR *PFNVMATERROR; + +#ifdef IN_RING3 +VMMDECL(int) VMSetError(PVMCC pVM, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(6, 7); +VMMDECL(int) VMSetErrorV(PVMCC pVM, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list args) RT_IPRT_FORMAT_ATTR(6, 7); +#endif + +/** @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 The cross context VM structure. + * @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)) + +/** @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 The cross context VM structure. + * @param rc VBox status code. + * @param pszMessage Error message string. + * @thread Any + */ +#define VM_SET_ERROR_U(a_pUVM, a_rc, a_pszMessage) (VMR3SetError(a_pUVM, a_rc, RT_SRC_POS, a_pszMessage)) + + +/** + * VM runtime error callback function. + * + * See VMSetRuntimeError for the detailed description of parameters. + * + * @param pUVM The user mode 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 DECLCALLBACKTYPE(void, FNVMATRUNTIMEERROR,(PUVM pUVM, void *pvUser, uint32_t fFlags, const char *pszErrorId, + const char *pszFormat, va_list va)) RT_IPRT_FORMAT_ATTR(5, 0); +/** Pointer to a VM runtime error callback. */ +typedef FNVMATRUNTIMEERROR *PFNVMATRUNTIMEERROR; + +#ifdef IN_RING3 +VMMDECL(int) VMSetRuntimeError(PVMCC pVM, uint32_t fFlags, const char *pszErrorId, + const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(4, 5); +VMMDECL(int) VMSetRuntimeErrorV(PVMCC pVM, uint32_t fFlags, const char *pszErrorId, + const char *pszFormat, va_list args) RT_IPRT_FORMAT_ATTR(4, 0); +#endif + +/** @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 change callback function. + * + * You are not allowed to call any function which changes the VM state from a + * state callback, except VMR3Destroy(). + * + * @param pUVM The user mode VM handle. + * @param pVMM The VMM ring-3 vtable. + * @param enmState The new state. + * @param enmOldState The old state. + * @param pvUser The user argument. + */ +typedef DECLCALLBACKTYPE(void, FNVMATSTATE,(PUVM pUVM, PCVMMR3VTABLE pVMM, VMSTATE enmState, VMSTATE enmOldState, void *pvUser)); +/** Pointer to a VM state callback. */ +typedef FNVMATSTATE *PFNVMATSTATE; + +VMMDECL(const char *) VMGetStateName(VMSTATE enmState); + +VMMDECL(uint32_t) VMGetResetCount(PVMCC pVM); +VMMDECL(uint32_t) VMGetSoftResetCount(PVMCC pVM); +VMMDECL(uint32_t) VMGetHardResetCount(PVMCC pVM); + + +/** + * 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 + * @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 HM* bits being completely + * initialized. */ + VMINITCOMPLETED_HM +} VMINITCOMPLETED; + + +/** Reason for VM resume. */ +typedef enum VMRESUMEREASON +{ + VMRESUMEREASON_INVALID = 0, + /** User decided to do so. */ + VMRESUMEREASON_USER, + /** VM reconfiguration (like changing DVD). */ + VMRESUMEREASON_RECONFIG, + /** The host resumed. */ + VMRESUMEREASON_HOST_RESUME, + /** Restored state. */ + VMRESUMEREASON_STATE_RESTORED, + /** Snapshot / saved state. */ + VMRESUMEREASON_STATE_SAVED, + /** Teleported to a new box / instance. */ + VMRESUMEREASON_TELEPORTED, + /** Teleportation failed. */ + VMRESUMEREASON_TELEPORT_FAILED, + /** FTM temporarily suspended the VM. */ + VMRESUMEREASON_FTM_SYNC, + /** End of valid reasons. */ + VMRESUMEREASON_END, + /** Blow the type up to 32-bits. */ + VMRESUMEREASON_32BIT_HACK = 0x7fffffff +} VMRESUMEREASON; + +/** Reason for VM suspend. */ +typedef enum VMSUSPENDREASON +{ + VMSUSPENDREASON_INVALID = 0, + /** User decided to do so. */ + VMSUSPENDREASON_USER, + /** VM reconfiguration (like changing DVD). */ + VMSUSPENDREASON_RECONFIG, + /** The VM is suspending itself. */ + VMSUSPENDREASON_VM, + /** The Vm is suspending because of a runtime error. */ + VMSUSPENDREASON_RUNTIME_ERROR, + /** The host was suspended. */ + VMSUSPENDREASON_HOST_SUSPEND, + /** The host is running low on battery power. */ + VMSUSPENDREASON_HOST_BATTERY_LOW, + /** FTM is temporarily suspending the VM. */ + VMSUSPENDREASON_FTM_SYNC, + /** End of valid reasons. */ + VMSUSPENDREASON_END, + /** Blow the type up to 32-bits. */ + VMSUSPENDREASON_32BIT_HACK = 0x7fffffff +} VMSUSPENDREASON; + + +/** + * Progress callback. + * + * This will report the completion percentage of an operation. + * + * @returns VINF_SUCCESS. + * @returns Error code to cancel the operation with. + * @param pUVM The user mode VM handle. + * @param uPercent Completion percentage (0-100). + * @param pvUser User specified argument. + */ +typedef DECLCALLBACKTYPE(int, FNVMPROGRESS,(PUVM pUVM, unsigned uPercent, void *pvUser)); +/** Pointer to a FNVMPROGRESS function. */ +typedef FNVMPROGRESS *PFNVMPROGRESS; + + +VMMR3DECL(int) VMR3Create(uint32_t cCpus, PCVMM2USERMETHODS pVm2UserCbs, + PFNVMATERROR pfnVMAtError, void *pvUserVM, + PFNCFGMCONSTRUCTOR pfnCFGMConstructor, void *pvUserCFGM, + PVM *ppVM, PUVM *ppUVM); +VMMR3DECL(int) VMR3PowerOn(PUVM pUVM); +VMMR3DECL(int) VMR3Suspend(PUVM pUVM, VMSUSPENDREASON enmReason); +VMMR3DECL(VMSUSPENDREASON) VMR3GetSuspendReason(PUVM); +VMMR3DECL(int) VMR3Resume(PUVM pUVM, VMRESUMEREASON enmReason); +VMMR3DECL(VMRESUMEREASON) VMR3GetResumeReason(PUVM); +VMMR3DECL(int) VMR3Reset(PUVM pUVM); +VMMR3_INT_DECL(VBOXSTRICTRC) VMR3ResetFF(PVM pVM); +VMMR3_INT_DECL(VBOXSTRICTRC) VMR3ResetTripleFault(PVM pVM); +VMMR3DECL(int) VMR3Save(PUVM pUVM, const char *pszFilename, PCSSMSTRMOPS pStreamOps, void *pvStreamOpsUser, bool fContinueAfterwards, PFNVMPROGRESS pfnProgress, void *pvUser, bool *pfSuspended); +VMMR3DECL(int) VMR3Teleport(PUVM pUVM, uint32_t cMsDowntime, PCSSMSTRMOPS pStreamOps, void *pvStreamOpsUser, PFNVMPROGRESS pfnProgress, void *pvProgressUser, bool *pfSuspended); +VMMR3DECL(int) VMR3LoadFromFile(PUVM pUVM, const char *pszFilename, PFNVMPROGRESS pfnProgress, void *pvUser); +VMMR3DECL(int) VMR3LoadFromStream(PUVM pUVM, PCSSMSTRMOPS pStreamOps, void *pvStreamOpsUser, + PFNVMPROGRESS pfnProgress, void *pvProgressUser, bool fTeleporting); + +VMMR3DECL(int) VMR3PowerOff(PUVM pUVM); +VMMR3DECL(int) VMR3Destroy(PUVM pUVM); +VMMR3_INT_DECL(void) VMR3Relocate(PVM pVM, RTGCINTPTR offDelta); + +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); +VMMR3DECL(int) VMR3AtStateRegister(PUVM pUVM, PFNVMATSTATE pfnAtState, void *pvUser); +VMMR3DECL(int) VMR3AtStateDeregister(PUVM pUVM, PFNVMATSTATE pfnAtState, void *pvUser); +VMMR3_INT_DECL(bool) VMR3SetGuruMeditation(PVM pVM); +VMMR3_INT_DECL(bool) VMR3TeleportedAndNotFullyResumedYet(PVM pVM); +VMMR3DECL(int) VMR3AtErrorRegister(PUVM pUVM, PFNVMATERROR pfnAtError, void *pvUser); +VMMR3DECL(int) VMR3AtErrorDeregister(PUVM pUVM, PFNVMATERROR pfnAtError, void *pvUser); +VMMR3DECL(int) VMR3SetError(PUVM pUVM, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(6, 7); +VMMR3DECL(int) VMR3SetErrorV(PUVM pUVM, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(6, 0); +VMMR3_INT_DECL(void) VMR3SetErrorWorker(PVM pVM); +VMMR3_INT_DECL(uint32_t) VMR3GetErrorCount(PUVM pUVM); +VMMR3DECL(int) VMR3AtRuntimeErrorRegister(PUVM pUVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser); +VMMR3DECL(int) VMR3AtRuntimeErrorDeregister(PUVM pUVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser); +VMMR3_INT_DECL(int) VMR3SetRuntimeErrorWorker(PVM pVM); +VMMR3_INT_DECL(uint32_t) VMR3GetRuntimeErrorCount(PUVM pUVM); + +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); +VMMR3_INT_DECL(int) VMR3ReqCallWait(PVM pVM, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...); +VMMR3DECL(int) VMR3ReqCallWaitU(PUVM pUVM, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...); +VMMR3DECL(int) VMR3ReqCallNoWait(PVM pVM, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...); +VMMR3DECL(int) VMR3ReqCallNoWaitU(PUVM pUVM, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...); +VMMR3_INT_DECL(int) VMR3ReqCallVoidWait(PVM pVM, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...); +VMMR3DECL(int) VMR3ReqCallVoidWaitU(PUVM pUVM, 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) VMR3ReqPriorityCallWaitU(PUVM pUVM, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...); +VMMR3DECL(int) VMR3ReqPriorityCallVoidWaitU(PUVM pUVM, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...); +VMMR3DECL(int) VMR3ReqAlloc(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); +VMMR3_INT_DECL(int) VMR3ReqProcessU(PUVM pUVM, VMCPUID idDstCpu, bool fPriorityOnly); + +/** @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) +/** @} */ +VMMR3_INT_DECL(void) VMR3NotifyGlobalFFU(PUVM pUVM, uint32_t fFlags); +VMMR3_INT_DECL(void) VMR3NotifyCpuFFU(PUVMCPU pUVMCpu, uint32_t fFlags); +VMMR3DECL(int) VMR3NotifyCpuDeviceReady(PVM pVM, VMCPUID idCpu); +VMMR3_INT_DECL(int) VMR3WaitHalted(PVM pVM, PVMCPU pVCpu, bool fIgnoreInterrupts); +VMMR3_INT_DECL(int) VMR3WaitU(PUVMCPU pUVMCpu); +VMMR3DECL(int) VMR3WaitForDeviceReady(PVM pVM, VMCPUID idCpu); +VMMR3_INT_DECL(int) VMR3AsyncPdmNotificationWaitU(PUVMCPU pUVCpu); +VMMR3_INT_DECL(void) VMR3AsyncPdmNotificationWakeupU(PUVM pUVM); +VMMR3_INT_DECL(RTCPUID) VMR3GetVMCPUId(PVM pVM); +VMMR3_INT_DECL(bool) VMR3IsLongModeAllowed(PVM pVM); +VMMR3_INT_DECL(RTTHREAD) VMR3GetThreadHandle(PUVMCPU pUVCpu); +VMMR3DECL(RTTHREAD) VMR3GetVMCPUThread(PUVM pUVM); +VMMR3DECL(RTNATIVETHREAD) VMR3GetVMCPUNativeThread(PVM pVM); +VMMR3DECL(RTNATIVETHREAD) VMR3GetVMCPUNativeThreadU(PUVM pUVM); +VMMR3DECL(int) VMR3GetCpuCoreAndPackageIdFromCpuId(PUVM pUVM, VMCPUID idCpu, uint32_t *pidCpuCore, uint32_t *pidCpuPackage); +VMMR3_INT_DECL(uint32_t) VMR3GetActiveEmts(PUVM pUVM); +VMMR3DECL(int) VMR3HotUnplugCpu(PUVM pUVM, VMCPUID idCpu); +VMMR3DECL(int) VMR3HotPlugCpu(PUVM pUVM, VMCPUID idCpu); +VMMR3DECL(int) VMR3SetCpuExecutionCap(PUVM pUVM, uint32_t uCpuExecutionCap); +VMMR3DECL(int) VMR3SetPowerOffInsteadOfReset(PUVM pUVM, bool fPowerOffInsteadOfReset); +/** @} */ +#endif /* IN_RING3 */ + +RT_C_DECLS_END + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_vmapi_h */ + diff --git a/include/VBox/vmm/vmcc.h b/include/VBox/vmm/vmcc.h new file mode 100644 index 00000000..3a143fae --- /dev/null +++ b/include/VBox/vmm/vmcc.h @@ -0,0 +1,148 @@ +/** @file + * VM - The Virtual Machine, GVM/GVMCPU or VM/VMCPU depending on context. + */ + +/* + * Copyright (C) 2019-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_vmcc_h +#define VBOX_INCLUDED_vmm_vmcc_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +#include <VBox/vmm/vm.h> +#ifdef IN_RING0 +# include <VBox/vmm/gvm.h> +#else +# include <VBox/vmm/uvm.h> +#endif + +/** @typedef VMCC + * Context specific VM derived structure. + * This is plain VM in ring-3 and GVM (inherits from VM) in ring-0. */ +/** @typedef VMCPUCC + * Context specific VMCPU derived structure. + * This is plain VM in ring-3 and GVMCPU (inherits from VMCPU) in ring-0. */ +#ifdef IN_RING0 +typedef GVM VMCC; +typedef GVMCPU VMCPUCC; +#else +typedef VM VMCC; +typedef VMCPU VMCPUCC; +#endif + +/** @def VMCC_GET_CPU_0 + * Gets the context specfic pointer to virtual CPU \#0. + * @param a_pVM The context specfic VM structure. + */ +#ifdef IN_RING0 +# define VMCC_GET_CPU_0(a_pVM) (&(a_pVM)->aCpus[0]) +#else +# define VMCC_GET_CPU_0(a_pVM) ((a_pVM)->CTX_SUFF(apCpus)[0]) +#endif + +/** @def VMCC_GET_CPU + * Gets the context specfic pointer to a virtual CPU by index (ID). + * @param a_pVM The context specfic VM structure. + * @param a_idCpu The CPU number to get (caller ensures validity). + */ +#ifdef IN_RING0 +# define VMCC_GET_CPU(a_pVM, a_idCpu) (&(a_pVM)->aCpus[(a_idCpu)]) +#else +# define VMCC_GET_CPU(a_pVM, a_idCpu) ((a_pVM)->CTX_SUFF(apCpus)[(a_idCpu)]) +#endif + +/** @def VMCC_FOR_EACH_VMCPU + * For enumerating VCpus in ascending order, avoiding unnecessary apCpusR0 + * access in ring-0, caching the CPU count and not checking for CPU \#0. + * + * Defines local variables @c idCpu, @c pVCpu and @c cCpus. + * + * @param a_pVM The VM handle. + * + * @note Close loop with VMCC_FOR_EACH_VMCPU_END. + */ +#define VMCC_FOR_EACH_VMCPU(a_pVM) \ + do { \ + VMCPUID idCpu = 0; \ + VMCPUID const cCpus = (a_pVM)->cCpus; \ + PVMCPUCC pVCpu = VMCC_GET_CPU_0(a_pVM); \ + for (;;) \ + { + +/** @def VMCC_FOR_EACH_VMCPU_END + * Ends a VMCC_FOR_EACH_VMCPU loop. + * @param a_pVM The VM handle. + */ +#define VMCC_FOR_EACH_VMCPU_END(a_pVM) \ + /* advance */ \ + if (++idCpu >= cCpus) \ + break; \ + pVCpu = VMCC_GET_CPU(pVM, idCpu); \ + } \ + } while (0) + +/** + * Execute the given statement for each virtual CPU in an environment with + * @c pVCpu and @c idCpu variables. + * + * @param a_pVM The VM handle. + * @param a_Stmt The statement to execute. + */ +#define VMCC_FOR_EACH_VMCPU_STMT(a_pVM, a_Stmt) VMCC_FOR_EACH_VMCPU(pVM) { a_Stmt; } VMCC_FOR_EACH_VMCPU_END(pVM) + +/** @def VMCC_GET_VMR0_FOR_CALL(pVM) */ +#if defined(IN_RING3) +# define VMCC_GET_VMR0_FOR_CALL(a_pVM) ((a_pVM)->pVMR0ForCall) +#elif defined(IN_RING3) +# define VMCC_GET_VMR0_FOR_CALL(a_pVM) ((a_pVM)->pVMR0) +#else +# define VMCC_GET_VMR0_FOR_CALL(a_pVM) ((a_pVM)->ring3_only_macro) +#endif + + +/** + * Used to pick ring-0 or ring-3 VM component data. + * + * @code{.cpp} + * pVM->VMCC_CTX(pdm).s.pfnWorker + * @endcode + */ +#ifdef IN_RING0 +# define VMCC_CTX(a_Name) a_Name ## r0 +#else +# define VMCC_CTX(a_Name) a_Name +#endif + +#endif /* !VBOX_INCLUDED_vmm_vmcc_h */ + diff --git a/include/VBox/vmm/vmcpuset.h b/include/VBox/vmm/vmcpuset.h new file mode 100644 index 00000000..496721de --- /dev/null +++ b/include/VBox/vmm/vmcpuset.h @@ -0,0 +1,124 @@ +/** @file + * VirtualBox - VMCPUSET Operation. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_vmcpuset_h +#define VBOX_INCLUDED_vmm_vmcpuset_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#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)) +/** Adds a CPU to the set, atomically. */ +#define VMCPUSET_ATOMIC_ADD(pSet, idCpu) ASMAtomicBitSet( &(pSet)->au32Bitmap[0], (idCpu)) +/** Deletes a CPU from the set, atomically. */ +#define VMCPUSET_ATOMIC_DEL(pSet, idCpu) ASMAtomicBitClear(&(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 /* !VBOX_INCLUDED_vmm_vmcpuset_h */ + diff --git a/include/VBox/vmm/vmm.h b/include/VBox/vmm/vmm.h new file mode 100644 index 00000000..85df7e4c --- /dev/null +++ b/include/VBox/vmm/vmm.h @@ -0,0 +1,639 @@ +/** @file + * VMM - The Virtual Machine Monitor. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_vmm_h +#define VBOX_INCLUDED_vmm_vmm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <VBox/vmm/vmapi.h> +#include <VBox/sup.h> +#include <VBox/log.h> +#include <iprt/stdarg.h> +#include <iprt/thread.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_vmm The Virtual Machine Monitor + * @{ + */ + +/** @defgroup grp_vmm_api The Virtual Machine Monitor API + * @{ + */ + + +/** + * Ring-0 assertion notification callback. + * + * @returns VBox status code. + * @param pVCpu The cross context virtual CPU structure. + * @param pvUser The user argument. + */ +typedef DECLCALLBACKTYPE(int, FNVMMR0ASSERTIONNOTIFICATION,(PVMCPUCC pVCpu, void *pvUser)); +/** Pointer to a FNVMMR0ASSERTIONNOTIFICATION(). */ +typedef FNVMMR0ASSERTIONNOTIFICATION *PFNVMMR0ASSERTIONNOTIFICATION; + +/** + * 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 cross context VM structure. + * @param pVCpu The cross context virtual CPU structure of the calling EMT. + * @param pvUser The user argument. + */ +typedef DECLCALLBACKTYPE(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)); + + /** + * Notification callback that that a VM reset will be turned into a power off. + * + * @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, pfnNotifyResetTurnedIntoPowerOff,(PCVMM2USERMETHODS pThis, PUVM pUVM)); + + /** + * Generic object query by UUID. + * + * @returns pointer to queried the object on success, NULL if not found. + * + * @param pThis Pointer to the callback method table. + * @param pUVM The user mode VM handle. + * @param pUuid The UUID of what's being queried. The UUIDs and the + * usage conventions are defined by the user. + * + * @remarks This is optional and shall be set to NULL if not wanted. + */ + DECLR3CALLBACKMEMBER(void *, pfnQueryGenericObject,(PCVMM2USERMETHODS pThis, PUVM pUVM, PCRTUUID pUuid)); + + /** 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(0x00030000) + + +/** + * Checks whether we've armed the ring-0 long jump machinery. + * + * @returns @c true / @c false + * @param a_pVCpu The caller's cross context virtual CPU structure. + * @thread EMT + * @sa VMMR0IsLongJumpArmed + */ +#ifdef IN_RING0 +# define VMMIsLongJumpArmed(a_pVCpu) VMMR0IsLongJumpArmed(a_pVCpu) +#else +# define VMMIsLongJumpArmed(a_pVCpu) (false) +#endif + + +VMMDECL(VMCPUID) VMMGetCpuId(PVMCC pVM); +VMMDECL(PVMCPUCC) VMMGetCpu(PVMCC pVM); +VMMDECL(PVMCPUCC) VMMGetCpu0(PVMCC pVM); +VMMDECL(PVMCPUCC) VMMGetCpuById(PVMCC pVM, VMCPUID idCpu); +VMMR3DECL(PVMCPUCC) VMMR3GetCpuByIdU(PUVM pVM, VMCPUID idCpu); +VMM_INT_DECL(uint32_t) VMMGetSvnRev(void); +VMM_INT_DECL(void) VMMTrashVolatileXMMRegs(void); + + +/** @defgroup grp_vmm_api_r0 The VMM Host Context Ring 0 API + * @{ + */ + +/** + * The VMMR0Entry() codes. + */ +typedef enum VMMR0OPERATION +{ + /** Run guest code using the available hardware acceleration technology. */ + VMMR0_DO_HM_RUN = SUP_VMMR0_DO_HM_RUN, + /** Official NOP that we use for profiling. */ + VMMR0_DO_NEM_RUN = SUP_VMMR0_DO_NEM_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 = 32, + /** Ask the GVMM to destroy the VM. */ + VMMR0_DO_GVMM_DESTROY_VM, + /** Call GVMMR0RegisterVCpu(). */ + VMMR0_DO_GVMM_REGISTER_VMCPU, + /** Call GVMMR0DeregisterVCpu(). */ + VMMR0_DO_GVMM_DEREGISTER_VMCPU, + /** Call GVMMR0RegisterWorkerThread(). */ + VMMR0_DO_GVMM_REGISTER_WORKER_THREAD, + /** Call GVMMR0DeregisterWorkerThread(). */ + VMMR0_DO_GVMM_DEREGISTER_WORKER_THREAD, + /** 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 VMMR0 Per VM Init. */ + VMMR0_DO_VMMR0_INIT = 64, + /** Call VMMR0 Per VM EMT Init */ + VMMR0_DO_VMMR0_INIT_EMT, + /** Call VMMR0 Per VM Termination. */ + VMMR0_DO_VMMR0_TERM, + /** Copy logger settings from userland, VMMR0UpdateLoggersReq(). */ + VMMR0_DO_VMMR0_UPDATE_LOGGERS, + /** Used by the log flusher, VMMR0LogFlusher. */ + VMMR0_DO_VMMR0_LOG_FLUSHER, + /** Used by EMTs to wait for the log flusher to finish, VMMR0LogWaitFlushed. */ + VMMR0_DO_VMMR0_LOG_WAIT_FLUSHED, + + /** Setup hardware-assisted VM session. */ + VMMR0_DO_HM_SETUP_VM = 128, + /** Attempt to enable or disable hardware-assisted mode. */ + VMMR0_DO_HM_ENABLE, + + /** Call PGMR0PhysAllocateHandyPages(). */ + VMMR0_DO_PGM_ALLOCATE_HANDY_PAGES = 192, + /** Call PGMR0PhysFlushHandyPages(). */ + VMMR0_DO_PGM_FLUSH_HANDY_PAGES, + /** Call PGMR0AllocateLargePage(). */ + VMMR0_DO_PGM_ALLOCATE_LARGE_PAGE, + /** Call PGMR0PhysSetupIommu(). */ + VMMR0_DO_PGM_PHYS_SETUP_IOMMU, + /** Call PGMR0PoolGrow(). */ + VMMR0_DO_PGM_POOL_GROW, + /** Call PGMR0PhysHandlerInitReqHandler(). */ + VMMR0_DO_PGM_PHYS_HANDLER_INIT, + + /** Call GMMR0InitialReservation(). */ + VMMR0_DO_GMM_INITIAL_RESERVATION = 256, + /** 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 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, + + /** Call PDMR0DriverCallReqHandler. */ + VMMR0_DO_PDM_DRIVER_CALL_REQ_HANDLER = 320, + /** Call PDMR0DeviceCreateReqHandler. */ + VMMR0_DO_PDM_DEVICE_CREATE, + /** Call PDMR0DeviceGenCallReqHandler. */ + VMMR0_DO_PDM_DEVICE_GEN_CALL, + /** Old style device compat: Set ring-0 critical section. */ + VMMR0_DO_PDM_DEVICE_COMPAT_SET_CRITSECT, + /** Call PDMR0QueueCreateReqHandler. */ + VMMR0_DO_PDM_QUEUE_CREATE, + + /** Set a GVMM or GMM configuration value. */ + VMMR0_DO_GCFGM_SET_VALUE = 400, + /** Query a GVMM or GMM configuration value. */ + VMMR0_DO_GCFGM_QUERY_VALUE, + + /** The start of the R0 service operations. */ + VMMR0_DO_SRV_START = 448, + /** 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, + +#if 0 + /** Forward call to the PCI driver */ + VMMR0_DO_PCIRAW_REQ = 512, +#endif + + /** The end of the R0 service operations. */ + VMMR0_DO_SRV_END, + + /** Call NEMR0InitVM() (host specific). */ + VMMR0_DO_NEM_INIT_VM = 576, + /** Call NEMR0InitVMPart2() (host specific). */ + VMMR0_DO_NEM_INIT_VM_PART_2, + /** Call NEMR0MapPages() (host specific). */ + VMMR0_DO_NEM_MAP_PAGES, + /** Call NEMR0UnmapPages() (host specific). */ + VMMR0_DO_NEM_UNMAP_PAGES, + /** Call NEMR0ExportState() (host specific). */ + VMMR0_DO_NEM_EXPORT_STATE, + /** Call NEMR0ImportState() (host specific). */ + VMMR0_DO_NEM_IMPORT_STATE, + /** Call NEMR0QueryCpuTick() (host specific). */ + VMMR0_DO_NEM_QUERY_CPU_TICK, + /** Call NEMR0ResumeCpuTickOnAll() (host specific). */ + VMMR0_DO_NEM_RESUME_CPU_TICK_ON_ALL, + /** Call NEMR0UpdateStatistics() (host specific). */ + VMMR0_DO_NEM_UPDATE_STATISTICS, + /** Call NEMR0DoExperiment() (host specific, experimental, debug only). */ + VMMR0_DO_NEM_EXPERIMENT, + + /** Grow the I/O port registration tables. */ + VMMR0_DO_IOM_GROW_IO_PORTS = 640, + /** Grow the I/O port statistics tables. */ + VMMR0_DO_IOM_GROW_IO_PORT_STATS, + /** Grow the MMIO registration tables. */ + VMMR0_DO_IOM_GROW_MMIO_REGS, + /** Grow the MMIO statistics tables. */ + VMMR0_DO_IOM_GROW_MMIO_STATS, + /** Synchronize statistics indices for I/O ports and MMIO regions. */ + VMMR0_DO_IOM_SYNC_STATS_INDICES, + + /** Call DBGFR0TraceCreateReqHandler. */ + VMMR0_DO_DBGF_TRACER_CREATE = 704, + /** Call DBGFR0TraceCallReqHandler. */ + VMMR0_DO_DBGF_TRACER_CALL_REQ_HANDLER, + /** Call DBGFR0BpInitReqHandler(). */ + VMMR0_DO_DBGF_BP_INIT, + /** Call DBGFR0BpChunkAllocReqHandler(). */ + VMMR0_DO_DBGF_BP_CHUNK_ALLOC, + /** Call DBGFR0BpL2TblChunkAllocReqHandler(). */ + VMMR0_DO_DBGF_BP_L2_TBL_CHUNK_ALLOC, + /** Call DBGFR0BpOwnerInitReqHandler(). */ + VMMR0_DO_DBGF_BP_OWNER_INIT, + /** Call DBGFR0BpPortIoInitReqHandler(). */ + VMMR0_DO_DBGF_BP_PORTIO_INIT, + + /** Grow a timer queue. */ + VMMR0_DO_TM_GROW_TIMER_QUEUE = 768, + + /** Official call we use for testing Ring-0 APIs. */ + VMMR0_DO_TESTS = 2048, + + /** 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; + + +/** + * Request package for VMMR0_DO_VMMR0_UPDATE_LOGGERS. + * + * In addition the u64Arg is selects the logger and indicates whether we're only + * outputting to the parent VMM. See VMMR0UPDATELOGGER_F_XXX. + */ +typedef struct VMMR0UPDATELOGGERSREQ +{ + /** The request header. */ + SUPVMMR0REQHDR Hdr; + /** The current logger flags (RTLOGFLAGS). */ + uint64_t fFlags; + /** Groups, assuming same group layout as ring-3. */ + uint32_t cGroups; + /** CRC32 of the group names. */ + uint32_t uGroupCrc32; + /** Per-group settings, variable size. */ + RT_FLEXIBLE_ARRAY_EXTENSION + uint32_t afGroups[RT_FLEXIBLE_ARRAY]; +} VMMR0UPDATELOGGERSREQ; +/** Pointer to a VMMR0_DO_VMMR0_UPDATE_LOGGERS request. */ +typedef VMMR0UPDATELOGGERSREQ *PVMMR0UPDATELOGGERSREQ; + +/** @name VMMR0UPDATELOGGER_F_XXX - u64Arg definitions for VMMR0_DO_VMMR0_UPDATE_LOGGERS. + * @{ */ +/** Logger index mask. */ +#define VMMR0UPDATELOGGER_F_LOGGER_MASK UINT64_C(0x0001) +/** Only flush to the parent VMM's debug log, don't return to ring-3. */ +#define VMMR0UPDATELOGGER_F_TO_PARENT_VMM_DBG UINT64_C(0x0002) +/** Only flush to the parent VMM's debug log, don't return to ring-3. */ +#define VMMR0UPDATELOGGER_F_TO_PARENT_VMM_REL UINT64_C(0x0004) +/** Valid flag mask. */ +#define VMMR0UPDATELOGGER_F_VALID_MASK UINT64_C(0x0007) +/** @} */ + +#if defined(IN_RING0) || defined(DOXYGEN_RUNNING) + +/** + * Structure VMMR0EmtPrepareToBlock uses to pass info to + * VMMR0EmtResumeAfterBlocking. + */ +typedef struct VMMR0EMTBLOCKCTX +{ + /** Magic value (VMMR0EMTBLOCKCTX_MAGIC). */ + uint32_t uMagic; + /** Set if we were in HM context, clear if not. */ + bool fWasInHmContext; +} VMMR0EMTBLOCKCTX; +/** Pointer to a VMMR0EmtPrepareToBlock context structure. */ +typedef VMMR0EMTBLOCKCTX *PVMMR0EMTBLOCKCTX; +/** Magic value for VMMR0EMTBLOCKCTX::uMagic (Paul Desmond). */ +#define VMMR0EMTBLOCKCTX_MAGIC UINT32_C(0x19261125) +/** Magic value for VMMR0EMTBLOCKCTX::uMagic when its out of context. */ +#define VMMR0EMTBLOCKCTX_MAGIC_DEAD UINT32_C(0x19770530) + +VMMR0DECL(void) VMMR0EntryFast(PGVM pGVM, PVMCC pVM, VMCPUID idCpu, VMMR0OPERATION enmOperation); +VMMR0DECL(int) VMMR0EntryEx(PGVM pGVM, PVMCC pVM, VMCPUID idCpu, VMMR0OPERATION enmOperation, + PSUPVMMR0REQHDR pReq, uint64_t u64Arg, PSUPDRVSESSION); +VMMR0_INT_DECL(int) VMMR0InitPerVMData(PGVM pGVM); +VMMR0_INT_DECL(int) VMMR0TermVM(PGVM pGVM, VMCPUID idCpu); +VMMR0_INT_DECL(void) VMMR0CleanupVM(PGVM pGVM); +VMMR0_INT_DECL(bool) VMMR0IsLongJumpArmed(PVMCPUCC pVCpu); +VMMR0_INT_DECL(int) VMMR0ThreadCtxHookCreateForEmt(PVMCPUCC pVCpu); +VMMR0_INT_DECL(void) VMMR0ThreadCtxHookDestroyForEmt(PVMCPUCC pVCpu); +VMMR0_INT_DECL(void) VMMR0ThreadCtxHookDisable(PVMCPUCC pVCpu); +VMMR0_INT_DECL(bool) VMMR0ThreadCtxHookIsEnabled(PVMCPUCC pVCpu); +VMMR0_INT_DECL(int) VMMR0EmtPrepareToBlock(PVMCPUCC pVCpu, int rcBusy, const char *pszCaller, void *pvLock, + PVMMR0EMTBLOCKCTX pCtx); +VMMR0_INT_DECL(void) VMMR0EmtResumeAfterBlocking(PVMCPUCC pVCpu, PVMMR0EMTBLOCKCTX pCtx); +VMMR0_INT_DECL(int) VMMR0EmtWaitEventInner(PGVMCPU pGVCpu, uint32_t fFlags, RTSEMEVENT hEvent, RTMSINTERVAL cMsTimeout); +VMMR0_INT_DECL(int) VMMR0EmtSignalSupEvent(PGVM pGVM, PGVMCPU pGVCpu, SUPSEMEVENT hEvent); +VMMR0_INT_DECL(int) VMMR0EmtSignalSupEventByGVM(PGVM pGVM, SUPSEMEVENT hEvent); +VMMR0_INT_DECL(int) VMMR0AssertionSetNotification(PVMCPUCC pVCpu, PFNVMMR0ASSERTIONNOTIFICATION pfnCallback, RTR0PTR pvUser); +VMMR0_INT_DECL(void) VMMR0AssertionRemoveNotification(PVMCPUCC pVCpu); +VMMR0_INT_DECL(bool) VMMR0AssertionIsNotificationSet(PVMCPUCC pVCpu); + +/** @name VMMR0EMTWAIT_F_XXX - flags for VMMR0EmtWaitEventInner and friends. + * @{ */ +/** Try suppress VERR_INTERRUPTED for a little while (~10 sec). */ +#define VMMR0EMTWAIT_F_TRY_SUPPRESS_INTERRUPTED RT_BIT_32(0) +/** @} */ +#endif /* IN_RING0 */ + +VMMR0_INT_DECL(PRTLOGGER) VMMR0GetReleaseLogger(PVMCPUCC pVCpu); +/** @} */ + + +#if defined(IN_RING3) || defined(DOXYGEN_RUNNING) +/** @defgroup grp_vmm_api_r3 The VMM Host Context Ring 3 API + * @{ + */ +VMMR3DECL(PCVMMR3VTABLE) VMMR3GetVTable(void); +VMMR3_INT_DECL(int) VMMR3Init(PVM pVM); +VMMR3_INT_DECL(int) VMMR3InitR0(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) VMMR3HmRunGC(PVM pVM, PVMCPU pVCpu); +VMMR3DECL(int) VMMR3CallR0(PVM pVM, uint32_t uOperation, uint64_t u64Arg, PSUPVMMR0REQHDR pReqHdr); +VMMR3_INT_DECL(int) VMMR3CallR0Emt(PVM pVM, PVMCPU pVCpu, VMMR0OPERATION enmOperation, uint64_t u64Arg, PSUPVMMR0REQHDR pReqHdr); +VMMR3_INT_DECL(VBOXSTRICTRC) VMMR3CallR0EmtFast(PVM pVM, PVMCPU pVCpu, VMMR0OPERATION enmOperation); +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) VMMR3SendStartupIpi(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); +/** @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). + * Recursion from within the callback possible. */ +#define VMMEMTRENDEZVOUS_FLAGS_TYPE_ONE_BY_ONE UINT32_C(1) +/** Let all the EMTs execute the callback at the same time. + * Cannot recurse from the callback. */ +#define VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE UINT32_C(2) +/** Only execute the callback on one EMT (no particular one). + * Recursion from within the callback possible. */ +#define VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE UINT32_C(3) +/** Let the EMTs execute the callback one by one in ascending order. + * Recursion from within the callback possible. */ +#define VMMEMTRENDEZVOUS_FLAGS_TYPE_ASCENDING UINT32_C(4) +/** Let the EMTs execute the callback one by one in descending order. + * Recursion from within the callback possible. */ +#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) +/** Use VMREQFLAGS_PRIORITY when contacting the EMTs. */ +#define VMMEMTRENDEZVOUS_FLAGS_PRIORITY UINT32_C(0x00000010) +/** The valid flags. */ +#define VMMEMTRENDEZVOUS_FLAGS_VALID_MASK UINT32_C(0x0000001f) +/** @} */ +VMMR3_INT_DECL(int) VMMR3EmtRendezvousFF(PVM pVM, PVMCPU pVCpu); +VMMR3_INT_DECL(void) VMMR3SetMayHaltInRing0(PVMCPU pVCpu, bool fMayHaltInRing0, uint32_t cNsSpinBlockThreshold); +VMMR3_INT_DECL(int) VMMR3ReadR0Stack(PVM pVM, VMCPUID idCpu, RTHCUINTPTR R0Addr, void *pvBuf, size_t cbRead); +VMMR3_INT_DECL(void) VMMR3InitR0StackUnwindState(PUVM pUVM, VMCPUID idCpu, PRTDBGUNWINDSTATE pState); +/** @} */ +#endif /* IN_RING3 */ + + +#if defined(IN_RC) || defined(IN_RING0) || defined(DOXYGEN_RUNNING) +/** @defgroup grp_vmm_api_rz The VMM Raw-Mode and Ring-0 Context API + * @{ + */ +VMMRZDECL(void) VMMRZCallRing3Disable(PVMCPUCC pVCpu); +VMMRZDECL(void) VMMRZCallRing3Enable(PVMCPUCC pVCpu); +VMMRZDECL(bool) VMMRZCallRing3IsEnabled(PVMCPUCC pVCpu); +/** @} */ +#endif + + +/** Wrapper around AssertReleaseMsgReturn that avoid tripping up in the + * kernel when we don't have a setjmp in place. */ +#ifdef IN_RING0 +# define VMM_ASSERT_RELEASE_MSG_RETURN(a_pVM, a_Expr, a_Msg, a_rc) do { \ + if (RT_LIKELY(a_Expr)) { /* likely */ } \ + else \ + { \ + PVMCPUCC pVCpuAssert = VMMGetCpu(a_pVM); \ + if (pVCpuAssert && VMMR0IsLongJumpArmed(pVCpuAssert)) \ + AssertReleaseMsg(a_Expr, a_Msg); \ + else \ + AssertLogRelMsg(a_Expr, a_Msg); \ + return (a_rc); \ + } \ + } while (0) +#else +# define VMM_ASSERT_RELEASE_MSG_RETURN(a_pVM, a_Expr, a_Msg, a_rc) AssertReleaseMsgReturn(a_Expr, a_Msg, a_rc) +#endif + +/** @} */ + +/** @} */ +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_vmm_h */ diff --git a/include/VBox/vmm/vmmr3vtable-def.h b/include/VBox/vmm/vmmr3vtable-def.h new file mode 100644 index 00000000..b95fdb47 --- /dev/null +++ b/include/VBox/vmm/vmmr3vtable-def.h @@ -0,0 +1,711 @@ +/** @file + * VM - The Virtual Machine Monitor, VTable ring-3 API, Definition Template. + * + * This is used by the vmmr3vtable.h header and the VMMR3VTable.cpp source file + * that implements it. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + + +/** @name VMM + * @{ */ +VTABLE_ENTRY(VMMGetSvnRev) +VTABLE_ENTRY(VMMGetCpu) + +VTABLE_RESERVED(pfnVMMR3Reserved1) +VTABLE_RESERVED(pfnVMMR3Reserved2) +VTABLE_RESERVED(pfnVMMR3Reserved3) +VTABLE_RESERVED(pfnVMMR3Reserved4) +VTABLE_RESERVED(pfnVMMR3Reserved5) +/** @} */ + +/** @name VM + * @{ + */ +VTABLE_ENTRY(VMR3Create) +VTABLE_ENTRY(VMR3PowerOn) +VTABLE_ENTRY(VMR3Suspend) +VTABLE_ENTRY(VMR3GetSuspendReason) +VTABLE_ENTRY(VMR3Resume) +VTABLE_ENTRY(VMR3GetResumeReason) +VTABLE_ENTRY(VMR3Reset) +VTABLE_ENTRY(VMR3Save) +VTABLE_ENTRY(VMR3Teleport) +VTABLE_ENTRY(VMR3LoadFromFile) +VTABLE_ENTRY(VMR3LoadFromStream) +VTABLE_ENTRY(VMR3PowerOff) +VTABLE_ENTRY(VMR3Destroy) + +VTABLE_ENTRY(VMR3GetVM) +VTABLE_ENTRY(VMR3GetUVM) +VTABLE_ENTRY(VMR3RetainUVM) +VTABLE_ENTRY(VMR3ReleaseUVM) +VTABLE_ENTRY(VMR3GetName) +VTABLE_ENTRY(VMR3GetUuid) +VTABLE_ENTRY(VMR3GetState) +VTABLE_ENTRY(VMR3GetStateU) +VTABLE_ENTRY(VMR3GetStateName) +VTABLE_ENTRY(VMR3AtStateRegister) +VTABLE_ENTRY(VMR3AtStateDeregister) +VTABLE_ENTRY(VMR3AtErrorRegister) +VTABLE_ENTRY(VMR3AtErrorDeregister) +VTABLE_ENTRY(VMR3SetError) +VTABLE_ENTRY(VMR3SetErrorV) +VTABLE_ENTRY(VMR3AtRuntimeErrorRegister) +VTABLE_ENTRY(VMR3AtRuntimeErrorDeregister) + +VTABLE_ENTRY(VMR3ReqCallU) +VTABLE_ENTRY(VMR3ReqCallVU) +VTABLE_ENTRY(VMR3ReqCallWaitU) +VTABLE_ENTRY(VMR3ReqCallNoWait) +VTABLE_ENTRY(VMR3ReqCallNoWaitU) +VTABLE_ENTRY(VMR3ReqCallVoidWaitU) +VTABLE_ENTRY(VMR3ReqCallVoidNoWait) +VTABLE_ENTRY(VMR3ReqPriorityCallWait) +VTABLE_ENTRY(VMR3ReqPriorityCallWaitU) +VTABLE_ENTRY(VMR3ReqPriorityCallVoidWaitU) +VTABLE_ENTRY(VMR3ReqAlloc) +VTABLE_ENTRY(VMR3ReqFree) +VTABLE_ENTRY(VMR3ReqQueue) +VTABLE_ENTRY(VMR3ReqWait) + +VTABLE_ENTRY(VMR3NotifyCpuDeviceReady) +VTABLE_ENTRY(VMR3WaitForDeviceReady) +VTABLE_ENTRY(VMR3GetVMCPUThread) +VTABLE_ENTRY(VMR3GetVMCPUNativeThread) +VTABLE_ENTRY(VMR3GetVMCPUNativeThreadU) +VTABLE_ENTRY(VMR3GetCpuCoreAndPackageIdFromCpuId) +VTABLE_ENTRY(VMR3HotUnplugCpu) +VTABLE_ENTRY(VMR3HotPlugCpu) +VTABLE_ENTRY(VMR3SetCpuExecutionCap) +VTABLE_ENTRY(VMR3SetPowerOffInsteadOfReset) + +VTABLE_RESERVED(pfnVMR3Reserved1) +VTABLE_RESERVED(pfnVMR3Reserved2) +VTABLE_RESERVED(pfnVMR3Reserved3) +VTABLE_RESERVED(pfnVMR3Reserved4) +VTABLE_RESERVED(pfnVMR3Reserved5) +/** @} */ + +/** @name CFGM + * @{ */ +VTABLE_ENTRY(CFGMR3Init) +VTABLE_ENTRY(CFGMR3Term) +VTABLE_ENTRY(CFGMR3ConstructDefaultTree) + +VTABLE_ENTRY(CFGMR3CreateTree) +VTABLE_ENTRY(CFGMR3DestroyTree) +VTABLE_ENTRY(CFGMR3Dump) +VTABLE_ENTRY(CFGMR3DuplicateSubTree) +VTABLE_ENTRY(CFGMR3ReplaceSubTree) +VTABLE_ENTRY(CFGMR3InsertSubTree) +VTABLE_ENTRY(CFGMR3InsertNode) +VTABLE_ENTRY(CFGMR3InsertNodeF) +VTABLE_ENTRY(CFGMR3InsertNodeFV) +VTABLE_ENTRY(CFGMR3SetRestrictedRoot) +VTABLE_ENTRY(CFGMR3RemoveNode) +VTABLE_ENTRY(CFGMR3InsertInteger) +VTABLE_ENTRY(CFGMR3InsertString) +VTABLE_ENTRY(CFGMR3InsertStringN) +VTABLE_ENTRY(CFGMR3InsertStringF) +VTABLE_ENTRY(CFGMR3InsertStringFV) +VTABLE_ENTRY(CFGMR3InsertStringW) +VTABLE_ENTRY(CFGMR3InsertBytes) +VTABLE_ENTRY(CFGMR3InsertPassword) +VTABLE_ENTRY(CFGMR3InsertPasswordN) +VTABLE_ENTRY(CFGMR3InsertValue) +VTABLE_ENTRY(CFGMR3RemoveValue) +VTABLE_ENTRY(CFGMR3CopyTree) + +VTABLE_ENTRY(CFGMR3Exists) +VTABLE_ENTRY(CFGMR3QueryType) +VTABLE_ENTRY(CFGMR3QuerySize) +VTABLE_ENTRY(CFGMR3QueryInteger) +VTABLE_ENTRY(CFGMR3QueryIntegerDef) +VTABLE_ENTRY(CFGMR3QueryString) +VTABLE_ENTRY(CFGMR3QueryStringDef) +VTABLE_ENTRY(CFGMR3QueryPassword) +VTABLE_ENTRY(CFGMR3QueryPasswordDef) +VTABLE_ENTRY(CFGMR3QueryBytes) + +VTABLE_ENTRY(CFGMR3QueryU64) +VTABLE_ENTRY(CFGMR3QueryU64Def) +VTABLE_ENTRY(CFGMR3QueryS64) +VTABLE_ENTRY(CFGMR3QueryS64Def) +VTABLE_ENTRY(CFGMR3QueryU32) +VTABLE_ENTRY(CFGMR3QueryU32Def) +VTABLE_ENTRY(CFGMR3QueryS32) +VTABLE_ENTRY(CFGMR3QueryS32Def) +VTABLE_ENTRY(CFGMR3QueryU16) +VTABLE_ENTRY(CFGMR3QueryU16Def) +VTABLE_ENTRY(CFGMR3QueryS16) +VTABLE_ENTRY(CFGMR3QueryS16Def) +VTABLE_ENTRY(CFGMR3QueryU8) +VTABLE_ENTRY(CFGMR3QueryU8Def) +VTABLE_ENTRY(CFGMR3QueryS8) +VTABLE_ENTRY(CFGMR3QueryS8Def) +VTABLE_ENTRY(CFGMR3QueryBool) +VTABLE_ENTRY(CFGMR3QueryBoolDef) +VTABLE_ENTRY(CFGMR3QueryPort) +VTABLE_ENTRY(CFGMR3QueryPortDef) +VTABLE_ENTRY(CFGMR3QueryUInt) +VTABLE_ENTRY(CFGMR3QueryUIntDef) +VTABLE_ENTRY(CFGMR3QuerySInt) +VTABLE_ENTRY(CFGMR3QuerySIntDef) +VTABLE_ENTRY(CFGMR3QueryGCPtr) +VTABLE_ENTRY(CFGMR3QueryGCPtrDef) +VTABLE_ENTRY(CFGMR3QueryGCPtrU) +VTABLE_ENTRY(CFGMR3QueryGCPtrUDef) +VTABLE_ENTRY(CFGMR3QueryGCPtrS) +VTABLE_ENTRY(CFGMR3QueryGCPtrSDef) +VTABLE_ENTRY(CFGMR3QueryStringAlloc) +VTABLE_ENTRY(CFGMR3QueryStringAllocDef) + +VTABLE_ENTRY(CFGMR3GetRoot) +VTABLE_ENTRY(CFGMR3GetRootU) +VTABLE_ENTRY(CFGMR3GetParent) +VTABLE_ENTRY(CFGMR3GetParentEx) +VTABLE_ENTRY(CFGMR3GetChild) +VTABLE_ENTRY(CFGMR3GetChildF) +VTABLE_ENTRY(CFGMR3GetChildFV) +VTABLE_ENTRY(CFGMR3GetFirstChild) +VTABLE_ENTRY(CFGMR3GetNextChild) +VTABLE_ENTRY(CFGMR3GetName) +VTABLE_ENTRY(CFGMR3GetNameLen) +VTABLE_ENTRY(CFGMR3AreChildrenValid) +VTABLE_ENTRY(CFGMR3GetFirstValue) +VTABLE_ENTRY(CFGMR3GetNextValue) +VTABLE_ENTRY(CFGMR3GetValueName) +VTABLE_ENTRY(CFGMR3GetValueNameLen) +VTABLE_ENTRY(CFGMR3GetValueType) +VTABLE_ENTRY(CFGMR3AreValuesValid) +VTABLE_ENTRY(CFGMR3ValidateConfig) + +VTABLE_RESERVED(pfnCFMGR3Reserved1) +VTABLE_RESERVED(pfnCFMGR3Reserved2) +VTABLE_RESERVED(pfnCFMGR3Reserved3) +VTABLE_RESERVED(pfnCFMGR3Reserved4) +VTABLE_RESERVED(pfnCFMGR3Reserved5) +/** @} */ + +/** @name SSM + * @{ */ +VTABLE_ENTRY(SSMR3Term) +VTABLE_ENTRY(SSMR3RegisterInternal) +VTABLE_ENTRY(SSMR3RegisterExternal) +VTABLE_ENTRY(SSMR3RegisterStub) +VTABLE_ENTRY(SSMR3DeregisterInternal) +VTABLE_ENTRY(SSMR3DeregisterExternal) +VTABLE_ENTRY(SSMR3Save) +VTABLE_ENTRY(SSMR3Load) +VTABLE_ENTRY(SSMR3ValidateFile) +VTABLE_ENTRY(SSMR3Open) +VTABLE_ENTRY(SSMR3Close) +VTABLE_ENTRY(SSMR3Seek) +VTABLE_ENTRY(SSMR3HandleGetStatus) +VTABLE_ENTRY(SSMR3HandleSetStatus) +VTABLE_ENTRY(SSMR3HandleGetAfter) +VTABLE_ENTRY(SSMR3HandleIsLiveSave) +VTABLE_ENTRY(SSMR3HandleMaxDowntime) +VTABLE_ENTRY(SSMR3HandleHostBits) +VTABLE_ENTRY(SSMR3HandleRevision) +VTABLE_ENTRY(SSMR3HandleVersion) +VTABLE_ENTRY(SSMR3HandleHostOSAndArch) +VTABLE_ENTRY(SSMR3HandleReportLivePercent) +VTABLE_ENTRY(SSMR3Cancel) + +VTABLE_ENTRY(SSMR3PutStruct) +VTABLE_ENTRY(SSMR3PutStructEx) +VTABLE_ENTRY(SSMR3PutBool) +VTABLE_ENTRY(SSMR3PutU8) +VTABLE_ENTRY(SSMR3PutS8) +VTABLE_ENTRY(SSMR3PutU16) +VTABLE_ENTRY(SSMR3PutS16) +VTABLE_ENTRY(SSMR3PutU32) +VTABLE_ENTRY(SSMR3PutS32) +VTABLE_ENTRY(SSMR3PutU64) +VTABLE_ENTRY(SSMR3PutS64) +VTABLE_ENTRY(SSMR3PutU128) +VTABLE_ENTRY(SSMR3PutS128) +VTABLE_ENTRY(SSMR3PutUInt) +VTABLE_ENTRY(SSMR3PutSInt) +VTABLE_ENTRY(SSMR3PutGCUInt) +VTABLE_ENTRY(SSMR3PutGCUIntReg) +VTABLE_ENTRY(SSMR3PutGCPhys32) +VTABLE_ENTRY(SSMR3PutGCPhys64) +VTABLE_ENTRY(SSMR3PutGCPhys) +VTABLE_ENTRY(SSMR3PutGCPtr) +VTABLE_ENTRY(SSMR3PutGCUIntPtr) +VTABLE_ENTRY(SSMR3PutRCPtr) +VTABLE_ENTRY(SSMR3PutIOPort) +VTABLE_ENTRY(SSMR3PutSel) +VTABLE_ENTRY(SSMR3PutMem) +VTABLE_ENTRY(SSMR3PutStrZ) + +VTABLE_ENTRY(SSMR3GetStruct) +VTABLE_ENTRY(SSMR3GetStructEx) +VTABLE_ENTRY(SSMR3GetBool) +VTABLE_ENTRY(SSMR3GetBoolV) +VTABLE_ENTRY(SSMR3GetU8) +VTABLE_ENTRY(SSMR3GetU8V) +VTABLE_ENTRY(SSMR3GetS8) +VTABLE_ENTRY(SSMR3GetS8V) +VTABLE_ENTRY(SSMR3GetU16) +VTABLE_ENTRY(SSMR3GetU16V) +VTABLE_ENTRY(SSMR3GetS16) +VTABLE_ENTRY(SSMR3GetS16V) +VTABLE_ENTRY(SSMR3GetU32) +VTABLE_ENTRY(SSMR3GetU32V) +VTABLE_ENTRY(SSMR3GetS32) +VTABLE_ENTRY(SSMR3GetS32V) +VTABLE_ENTRY(SSMR3GetU64) +VTABLE_ENTRY(SSMR3GetU64V) +VTABLE_ENTRY(SSMR3GetS64) +VTABLE_ENTRY(SSMR3GetS64V) +VTABLE_ENTRY(SSMR3GetU128) +VTABLE_ENTRY(SSMR3GetU128V) +VTABLE_ENTRY(SSMR3GetS128) +VTABLE_ENTRY(SSMR3GetS128V) +VTABLE_ENTRY(SSMR3GetGCPhys32) +VTABLE_ENTRY(SSMR3GetGCPhys32V) +VTABLE_ENTRY(SSMR3GetGCPhys64) +VTABLE_ENTRY(SSMR3GetGCPhys64V) +VTABLE_ENTRY(SSMR3GetGCPhys) +VTABLE_ENTRY(SSMR3GetGCPhysV) +VTABLE_ENTRY(SSMR3GetUInt) +VTABLE_ENTRY(SSMR3GetSInt) +VTABLE_ENTRY(SSMR3GetGCUInt) +VTABLE_ENTRY(SSMR3GetGCUIntReg) +VTABLE_ENTRY(SSMR3GetGCPtr) +VTABLE_ENTRY(SSMR3GetGCUIntPtr) +VTABLE_ENTRY(SSMR3GetRCPtr) +VTABLE_ENTRY(SSMR3GetIOPort) +VTABLE_ENTRY(SSMR3GetSel) +VTABLE_ENTRY(SSMR3GetMem) +VTABLE_ENTRY(SSMR3GetStrZ) +VTABLE_ENTRY(SSMR3GetStrZEx) +VTABLE_ENTRY(SSMR3Skip) +VTABLE_ENTRY(SSMR3SkipToEndOfUnit) +VTABLE_ENTRY(SSMR3SetLoadError) +VTABLE_ENTRY(SSMR3SetLoadErrorV) +VTABLE_ENTRY(SSMR3SetCfgError) +VTABLE_ENTRY(SSMR3SetCfgErrorV) + +VTABLE_RESERVED(pfnSSMR3Reserved1) +VTABLE_RESERVED(pfnSSMR3Reserved2) +VTABLE_RESERVED(pfnSSMR3Reserved3) +VTABLE_RESERVED(pfnSSMR3Reserved4) +VTABLE_RESERVED(pfnSSMR3Reserved5) +/** @} */ + +/** @name STAM + * @{ */ +VTABLE_ENTRY(STAMR3InitUVM) +VTABLE_ENTRY(STAMR3TermUVM) +VTABLE_ENTRY(STAMR3RegisterU) +VTABLE_ENTRY(STAMR3Register) +VTABLE_ENTRY(STAMR3RegisterFU) +VTABLE_ENTRY(STAMR3RegisterF) +VTABLE_ENTRY(STAMR3RegisterVU) +VTABLE_ENTRY(STAMR3RegisterV) +VTABLE_ENTRY(STAMR3RegisterCallback) +VTABLE_ENTRY(STAMR3RegisterCallbackV) +VTABLE_ENTRY(STAMR3RegisterRefresh) +VTABLE_ENTRY(STAMR3RegisterRefreshV) +VTABLE_ENTRY(STAMR3Deregister) +VTABLE_ENTRY(STAMR3DeregisterF) +VTABLE_ENTRY(STAMR3DeregisterV) +VTABLE_ENTRY(STAMR3DeregisterByPrefix) +VTABLE_ENTRY(STAMR3DeregisterByAddr) +VTABLE_ENTRY(STAMR3Reset) +VTABLE_ENTRY(STAMR3Snapshot) +VTABLE_ENTRY(STAMR3SnapshotFree) +VTABLE_ENTRY(STAMR3Dump) +VTABLE_ENTRY(STAMR3DumpToReleaseLog) +VTABLE_ENTRY(STAMR3Print) +VTABLE_ENTRY(STAMR3Enum) +VTABLE_ENTRY(STAMR3GetUnit) +VTABLE_ENTRY(STAMR3GetUnit1) +VTABLE_ENTRY(STAMR3GetUnit2) + +VTABLE_RESERVED(pfnSTAMR3Reserved1) +VTABLE_RESERVED(pfnSTAMR3Reserved2) +VTABLE_RESERVED(pfnSTAMR3Reserved3) +VTABLE_RESERVED(pfnSTAMR3Reserved4) +VTABLE_RESERVED(pfnSTAMR3Reserved5) +/** @} */ + +/** @name CPUM + * @{ */ +VTABLE_ENTRY(CPUMGetHostCpuVendor) +VTABLE_ENTRY(CPUMGetHostMicroarch) + +VTABLE_RESERVED(pfnCPUMR3Reserved1) +VTABLE_RESERVED(pfnCPUMR3Reserved2) +VTABLE_RESERVED(pfnCPUMR3Reserved3) +VTABLE_RESERVED(pfnCPUMR3Reserved4) +VTABLE_RESERVED(pfnCPUMR3Reserved5) +/** @} */ + +/** @name DBGC + * @{ */ +VTABLE_ENTRY(DBGCCreate) + +VTABLE_RESERVED(pfnDBGCR3Reserved1) +VTABLE_RESERVED(pfnDBGCR3Reserved2) +VTABLE_RESERVED(pfnDBGCR3Reserved3) +VTABLE_RESERVED(pfnDBGCR3Reserved4) +VTABLE_RESERVED(pfnDBGCR3Reserved5) +/** @} */ + +/** @name DBGF + * @{ */ +VTABLE_ENTRY(DBGFR3BpClear) +VTABLE_ENTRY(DBGFR3BpDisable) +VTABLE_ENTRY(DBGFR3BpEnable) +VTABLE_ENTRY(DBGFR3BpOwnerCreate) +VTABLE_ENTRY(DBGFR3BpOwnerDestroy) +VTABLE_ENTRY(DBGFR3BpSetInt3) +VTABLE_ENTRY(DBGFR3BpSetInt3Ex) +VTABLE_ENTRY(DBGFR3BpSetMmio) +VTABLE_ENTRY(DBGFR3BpSetMmioEx) +VTABLE_ENTRY(DBGFR3BpSetPortIo) +VTABLE_ENTRY(DBGFR3BpSetPortIoEx) +VTABLE_ENTRY(DBGFR3BpSetReg) +VTABLE_ENTRY(DBGFR3BpSetRegEx) +VTABLE_ENTRY(DBGFR3BpSetREM) +VTABLE_ENTRY(DBGFR3CoreWrite) +VTABLE_ENTRY(DBGFR3Info) +VTABLE_ENTRY(DBGFR3InfoRegisterExternal) +VTABLE_ENTRY(DBGFR3InfoDeregisterExternal) +VTABLE_ENTRY(DBGFR3InfoGenericGetOptError) +VTABLE_ENTRY(DBGFR3InjectNMI) +VTABLE_ENTRY(DBGFR3LogModifyDestinations) +VTABLE_ENTRY(DBGFR3LogModifyFlags) +VTABLE_ENTRY(DBGFR3LogModifyGroups) +VTABLE_ENTRY(DBGFR3OSDetect) +VTABLE_ENTRY(DBGFR3OSQueryNameAndVersion) +VTABLE_ENTRY(DBGFR3RegCpuQueryU8) +VTABLE_ENTRY(DBGFR3RegCpuQueryU16) +VTABLE_ENTRY(DBGFR3RegCpuQueryU32) +VTABLE_ENTRY(DBGFR3RegCpuQueryU64) +VTABLE_ENTRY(DBGFR3RegCpuQueryXdtr) +VTABLE_ENTRY(DBGFR3RegFormatValue) +VTABLE_ENTRY(DBGFR3RegNmQuery) +VTABLE_ENTRY(DBGFR3RegNmQueryAll) +VTABLE_ENTRY(DBGFR3RegNmQueryAllCount) +VTABLE_ENTRY(DBGFR3RegNmSetBatch) +VTABLE_ENTRY(DBGFR3OSDeregister) +VTABLE_ENTRY(DBGFR3OSRegister) +VTABLE_ENTRY(DBGFR3OSQueryInterface) +VTABLE_ENTRY(DBGFR3MemReadString) +VTABLE_ENTRY(DBGFR3MemRead) +VTABLE_ENTRY(DBGFR3MemScan) +VTABLE_ENTRY(DBGFR3ModInMem) +VTABLE_ENTRY(DBGFR3AddrFromFlat) +VTABLE_ENTRY(DBGFR3AsSymbolByName) +VTABLE_ENTRY(DBGFR3AsResolveAndRetain) +VTABLE_ENTRY(DBGFR3AsSetAlias) +VTABLE_ENTRY(DBGFR3AddrAdd) +VTABLE_ENTRY(DBGFR3AddrSub) +VTABLE_ENTRY(DBGFR3AsGetConfig) +VTABLE_ENTRY(DBGFR3CpuGetCount) +VTABLE_ENTRY(DBGFR3CpuGetMode) +VTABLE_ENTRY(DBGFR3CpuGetState) +VTABLE_ENTRY(DBGFR3AddrFromSelOff) +VTABLE_ENTRY(DBGFR3FlowCreate) +VTABLE_ENTRY(DBGFR3FlowRetain) +VTABLE_ENTRY(DBGFR3FlowRelease) +VTABLE_ENTRY(DBGFR3FlowQueryStartBb) +VTABLE_ENTRY(DBGFR3FlowQueryBbByAddress) +VTABLE_ENTRY(DBGFR3FlowQueryBranchTblByAddress) +VTABLE_ENTRY(DBGFR3FlowGetBbCount) +VTABLE_ENTRY(DBGFR3FlowGetBranchTblCount) +VTABLE_ENTRY(DBGFR3FlowGetCallInsnCount) +VTABLE_ENTRY(DBGFR3FlowBbRetain) +VTABLE_ENTRY(DBGFR3FlowBbRelease) +VTABLE_ENTRY(DBGFR3FlowBbGetStartAddress) +VTABLE_ENTRY(DBGFR3FlowBbGetEndAddress) +VTABLE_ENTRY(DBGFR3FlowBbGetBranchAddress) +VTABLE_ENTRY(DBGFR3FlowBbGetFollowingAddress) +VTABLE_ENTRY(DBGFR3FlowBbGetType) +VTABLE_ENTRY(DBGFR3FlowBbGetInstrCount) +VTABLE_ENTRY(DBGFR3FlowBbGetFlags) +VTABLE_ENTRY(DBGFR3FlowBbQueryBranchTbl) +VTABLE_ENTRY(DBGFR3FlowBbQueryError) +VTABLE_ENTRY(DBGFR3FlowBbQueryInstr) +VTABLE_ENTRY(DBGFR3FlowBbQuerySuccessors) +VTABLE_ENTRY(DBGFR3FlowBbGetRefBbCount) +VTABLE_ENTRY(DBGFR3FlowBbGetRefBb) +VTABLE_ENTRY(DBGFR3FlowBranchTblRetain) +VTABLE_ENTRY(DBGFR3FlowBranchTblRelease) +VTABLE_ENTRY(DBGFR3FlowBranchTblGetSlots) +VTABLE_ENTRY(DBGFR3FlowBranchTblGetStartAddress) +VTABLE_ENTRY(DBGFR3FlowBranchTblGetAddrAtSlot) +VTABLE_ENTRY(DBGFR3FlowBranchTblQueryAddresses) +VTABLE_ENTRY(DBGFR3FlowItCreate) +VTABLE_ENTRY(DBGFR3FlowItDestroy) +VTABLE_ENTRY(DBGFR3FlowItNext) +VTABLE_ENTRY(DBGFR3FlowItReset) +VTABLE_ENTRY(DBGFR3FlowBranchTblItCreate) +VTABLE_ENTRY(DBGFR3FlowBranchTblItDestroy) +VTABLE_ENTRY(DBGFR3FlowBranchTblItNext) +VTABLE_ENTRY(DBGFR3FlowBranchTblItReset) +VTABLE_ENTRY(DBGFR3FlowTraceModCreate) +VTABLE_ENTRY(DBGFR3FlowTraceModCreateFromFlowGraph) +VTABLE_ENTRY(DBGFR3FlowTraceModRetain) +VTABLE_ENTRY(DBGFR3FlowTraceModRelease) +VTABLE_ENTRY(DBGFR3FlowTraceModEnable) +VTABLE_ENTRY(DBGFR3FlowTraceModDisable) +VTABLE_ENTRY(DBGFR3FlowTraceModQueryReport) +VTABLE_ENTRY(DBGFR3FlowTraceModClear) +VTABLE_ENTRY(DBGFR3FlowTraceModAddProbe) +VTABLE_ENTRY(DBGFR3FlowTraceProbeCreate) +VTABLE_ENTRY(DBGFR3FlowTraceProbeRetain) +VTABLE_ENTRY(DBGFR3FlowTraceProbeRelease) +VTABLE_ENTRY(DBGFR3FlowTraceProbeEntriesAdd) +VTABLE_ENTRY(DBGFR3FlowTraceReportRetain) +VTABLE_ENTRY(DBGFR3FlowTraceReportRelease) +VTABLE_ENTRY(DBGFR3FlowTraceReportGetRecordCount) +VTABLE_ENTRY(DBGFR3FlowTraceReportQueryRecord) +VTABLE_ENTRY(DBGFR3FlowTraceReportQueryFiltered) +VTABLE_ENTRY(DBGFR3FlowTraceReportEnumRecords) +VTABLE_ENTRY(DBGFR3FlowTraceRecordRetain) +VTABLE_ENTRY(DBGFR3FlowTraceRecordRelease) +VTABLE_ENTRY(DBGFR3FlowTraceRecordGetSeqNo) +VTABLE_ENTRY(DBGFR3FlowTraceRecordGetTimestamp) +VTABLE_ENTRY(DBGFR3FlowTraceRecordGetAddr) +VTABLE_ENTRY(DBGFR3FlowTraceRecordGetProbe) +VTABLE_ENTRY(DBGFR3FlowTraceRecordGetValCount) +VTABLE_ENTRY(DBGFR3FlowTraceRecordGetVals) +VTABLE_ENTRY(DBGFR3FlowTraceRecordGetValsCommon) +VTABLE_ENTRY(DBGFR3FlowTraceRecordGetCpuId) +VTABLE_ENTRY(DBGFR3PlugInLoad) +VTABLE_ENTRY(DBGFR3PlugInUnload) +VTABLE_ENTRY(DBGFR3PlugInLoadAll) +VTABLE_ENTRY(DBGFR3PlugInUnloadAll) +VTABLE_ENTRY(DBGFR3SampleReportCreate) +VTABLE_ENTRY(DBGFR3SampleReportRetain) +VTABLE_ENTRY(DBGFR3SampleReportRelease) +VTABLE_ENTRY(DBGFR3SampleReportStart) +VTABLE_ENTRY(DBGFR3SampleReportStop) +VTABLE_ENTRY(DBGFR3SampleReportDumpToFile) +VTABLE_ENTRY(DBGFR3SelQueryInfo) +VTABLE_ENTRY(DBGFR3StackWalkBegin) +VTABLE_ENTRY(DBGFR3StackWalkNext) +VTABLE_ENTRY(DBGFR3StackWalkEnd) +VTABLE_ENTRY(DBGFR3TypeDeregister) +VTABLE_ENTRY(DBGFR3TypeDumpEx) +VTABLE_ENTRY(DBGFR3TypeQueryReg) +VTABLE_ENTRY(DBGFR3TypeQuerySize) +VTABLE_ENTRY(DBGFR3TypeQueryValByType) +VTABLE_ENTRY(DBGFR3TypeRegister) +VTABLE_ENTRY(DBGFR3TypeSetSize) +VTABLE_ENTRY(DBGFR3TypeValFree) +VTABLE_ENTRY(DBGFR3TypeValDumpEx) + +VTABLE_RESERVED(pfnDBGFR3Reserved1) +VTABLE_RESERVED(pfnDBGFR3Reserved2) +VTABLE_RESERVED(pfnDBGFR3Reserved3) +VTABLE_RESERVED(pfnDBGFR3Reserved4) +VTABLE_RESERVED(pfnDBGFR3Reserved5) +/** @} */ + +/** @name EM + * @{ */ +VTABLE_ENTRY(EMR3QueryExecutionPolicy) +VTABLE_ENTRY(EMR3QueryMainExecutionEngine) +VTABLE_ENTRY(EMR3SetExecutionPolicy) + +VTABLE_RESERVED(pfnEMR3Reserved1) +VTABLE_RESERVED(pfnEMR3Reserved2) +VTABLE_RESERVED(pfnEMR3Reserved3) +VTABLE_RESERVED(pfnEMR3Reserved4) +VTABLE_RESERVED(pfnEMR3Reserved5) +/** @} */ + +/** @name HM + * @{ */ +VTABLE_ENTRY(HMR3IsEnabled) +VTABLE_ENTRY(HMR3IsNestedPagingActive) +VTABLE_ENTRY(HMR3IsUXActive) +VTABLE_ENTRY(HMR3IsVpidActive) + +VTABLE_RESERVED(pfnHMR3Reserved1) +VTABLE_RESERVED(pfnHMR3Reserved2) +VTABLE_RESERVED(pfnHMR3Reserved3) +VTABLE_RESERVED(pfnHMR3Reserved4) +VTABLE_RESERVED(pfnHMR3Reserved5) +/** @} */ + +/** @name MM + * @{ */ +VTABLE_ENTRY(MMR3HeapAllocU) +VTABLE_ENTRY(MMR3HeapAllocExU) +VTABLE_ENTRY(MMR3HeapAllocZU) +VTABLE_ENTRY(MMR3HeapAllocZExU) +VTABLE_ENTRY(MMR3HeapRealloc) +VTABLE_ENTRY(MMR3HeapStrDupU) +VTABLE_ENTRY(MMR3HeapAPrintfU) +VTABLE_ENTRY(MMR3HeapAPrintfVU) +VTABLE_ENTRY(MMR3HeapFree) + +VTABLE_RESERVED(pfnMMR3Reserved1) +VTABLE_RESERVED(pfnMMR3Reserved2) +VTABLE_RESERVED(pfnMMR3Reserved3) +VTABLE_RESERVED(pfnMMR3Reserved4) +VTABLE_RESERVED(pfnMMR3Reserved5) +/** @} */ + +/** @name PDM + * @{ */ +VTABLE_ENTRY(PDMR3AsyncCompletionBwMgrSetMaxForFile) +VTABLE_ENTRY(PDMR3DeviceAttach) +VTABLE_ENTRY(PDMR3DeviceDetach) +VTABLE_ENTRY(PDMR3DriverAttach) +VTABLE_ENTRY(PDMR3DriverDetach) +VTABLE_ENTRY(PDMR3NsBwGroupSetLimit) +VTABLE_ENTRY(PDMR3QueryDeviceLun) +VTABLE_ENTRY(PDMR3QueryDriverOnLun) +VTABLE_ENTRY(PDMR3QueryLun) + +VTABLE_ENTRY(PDMCritSectEnter) +VTABLE_ENTRY(PDMCritSectEnterDebug) +VTABLE_ENTRY(PDMCritSectTryEnter) +VTABLE_ENTRY(PDMCritSectTryEnterDebug) +VTABLE_ENTRY(PDMR3CritSectEnterEx) +VTABLE_ENTRY(PDMCritSectLeave) +VTABLE_ENTRY(PDMCritSectIsOwner) +VTABLE_ENTRY(PDMCritSectIsOwnerEx) +VTABLE_ENTRY(PDMCritSectIsInitialized) +VTABLE_ENTRY(PDMCritSectHasWaiters) +VTABLE_ENTRY(PDMCritSectGetRecursion) +VTABLE_ENTRY(PDMR3CritSectYield) +VTABLE_ENTRY(PDMR3CritSectName) +VTABLE_ENTRY(PDMR3CritSectDelete) + +VTABLE_ENTRY(PDMQueueAlloc) +VTABLE_ENTRY(PDMQueueInsert) +VTABLE_RESERVED(pfnPDMR3Reserved11) + +VTABLE_ENTRY(PDMR3ThreadDestroy) +VTABLE_ENTRY(PDMR3ThreadIAmRunning) +VTABLE_ENTRY(PDMR3ThreadIAmSuspending) +VTABLE_ENTRY(PDMR3ThreadResume) +VTABLE_ENTRY(PDMR3ThreadSleep) +VTABLE_ENTRY(PDMR3ThreadSuspend) + +VTABLE_ENTRY(PDMR3UsbCreateEmulatedDevice) +VTABLE_ENTRY(PDMR3UsbCreateProxyDevice) +VTABLE_ENTRY(PDMR3UsbDetachDevice) +VTABLE_ENTRY(PDMR3UsbHasHub) +VTABLE_ENTRY(PDMR3UsbDriverAttach) +VTABLE_ENTRY(PDMR3UsbDriverDetach) +VTABLE_ENTRY(PDMR3UsbQueryLun) +VTABLE_ENTRY(PDMR3UsbQueryDriverOnLun) + +VTABLE_RESERVED(pfnPDMR3Reserved1) +VTABLE_RESERVED(pfnPDMR3Reserved2) +VTABLE_RESERVED(pfnPDMR3Reserved3) +VTABLE_RESERVED(pfnPDMR3Reserved4) +VTABLE_RESERVED(pfnPDMR3Reserved5) +VTABLE_RESERVED(pfnPDMR3Reserved6) +VTABLE_RESERVED(pfnPDMR3Reserved7) +VTABLE_RESERVED(pfnPDMR3Reserved8) +VTABLE_RESERVED(pfnPDMR3Reserved9) +VTABLE_RESERVED(pfnPDMR3Reserved10) +/** @} */ + +/** @name PGM + * @{ */ +VTABLE_ENTRY(PGMHandlerPhysicalPageTempOff) +VTABLE_ENTRY(PGMPhysReadGCPtr) +VTABLE_ENTRY(PGMPhysSimpleDirtyWriteGCPtr) +VTABLE_ENTRY(PGMPhysSimpleReadGCPtr) +VTABLE_ENTRY(PGMPhysSimpleWriteGCPhys) +VTABLE_ENTRY(PGMPhysSimpleWriteGCPtr) +VTABLE_ENTRY(PGMPhysWriteGCPtr) +VTABLE_ENTRY(PGMShwMakePageWritable) +VTABLE_ENTRY(PGMR3QueryGlobalMemoryStats) +VTABLE_ENTRY(PGMR3QueryMemoryStats) + +VTABLE_RESERVED(pfnPGMR3Reserved1) +VTABLE_RESERVED(pfnPGMR3Reserved2) +VTABLE_RESERVED(pfnPGMR3Reserved3) +VTABLE_RESERVED(pfnPGMR3Reserved4) +VTABLE_RESERVED(pfnPGMR3Reserved5) +/** @} */ + +/** @name TM + * @{ */ +VTABLE_ENTRY(TMR3GetCpuLoadPercents) +VTABLE_ENTRY(TMR3TimerSetCritSect) +VTABLE_ENTRY(TMR3TimerLoad) +VTABLE_ENTRY(TMR3TimerSave) +VTABLE_ENTRY(TMR3TimerSkip) +VTABLE_ENTRY(TMR3TimerDestroy) +VTABLE_ENTRY(TMTimerFromMicro) +VTABLE_ENTRY(TMTimerFromMilli) +VTABLE_ENTRY(TMTimerFromNano) +VTABLE_ENTRY(TMTimerGet) +VTABLE_ENTRY(TMTimerGetFreq) +VTABLE_ENTRY(TMTimerGetMicro) +VTABLE_ENTRY(TMTimerGetMilli) +VTABLE_ENTRY(TMTimerGetNano) +VTABLE_ENTRY(TMTimerIsActive) +VTABLE_ENTRY(TMTimerIsLockOwner) +VTABLE_ENTRY(TMTimerLock) +VTABLE_ENTRY(TMTimerSet) +VTABLE_ENTRY(TMTimerSetFrequencyHint) +VTABLE_ENTRY(TMTimerSetMicro) +VTABLE_ENTRY(TMTimerSetMillies) +VTABLE_ENTRY(TMTimerSetNano) +VTABLE_ENTRY(TMTimerSetRelative) +VTABLE_ENTRY(TMTimerStop) +VTABLE_ENTRY(TMTimerToMicro) +VTABLE_ENTRY(TMTimerToMilli) +VTABLE_ENTRY(TMTimerToNano) +VTABLE_ENTRY(TMTimerUnlock) +VTABLE_ENTRY(TMR3GetWarpDrive) +VTABLE_ENTRY(TMR3SetWarpDrive) +VTABLE_ENTRY(TMR3TimeVirtGet) +VTABLE_ENTRY(TMR3TimeVirtGetMicro) +VTABLE_ENTRY(TMR3TimeVirtGetMilli) +VTABLE_ENTRY(TMR3TimeVirtGetNano) + +VTABLE_RESERVED(pfnTMR3Reserved1) +VTABLE_RESERVED(pfnTMR3Reserved2) +VTABLE_RESERVED(pfnTMR3Reserved3) +VTABLE_RESERVED(pfnTMR3Reserved4) +VTABLE_RESERVED(pfnTMR3Reserved5) +/** @} */ diff --git a/include/VBox/vmm/vmmr3vtable.h b/include/VBox/vmm/vmmr3vtable.h new file mode 100644 index 00000000..96d88636 --- /dev/null +++ b/include/VBox/vmm/vmmr3vtable.h @@ -0,0 +1,140 @@ +/** @file + * VM - The Virtual Machine Monitor, VTable ring-3 API. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_vmmr3vtable_h +#define VBOX_INCLUDED_vmm_vmmr3vtable_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <VBox/vmm/cfgm.h> +#include <VBox/vmm/cpum.h> +#include <VBox/vmm/dbgf.h> +#include <VBox/vmm/dbgfflowtrace.h> +#include <VBox/vmm/em.h> +#include <VBox/vmm/hm.h> +#include <VBox/vmm/pdmapi.h> +#include <VBox/vmm/pdmasynccompletion.h> +#include <VBox/vmm/pdmcritsect.h> +#include <VBox/vmm/pdmnetshaper.h> +#include <VBox/vmm/pdmqueue.h> +#include <VBox/vmm/pdmusb.h> +#include <VBox/vmm/pdmthread.h> +#include <VBox/vmm/pgm.h> +#include <VBox/vmm/ssm.h> +#include <VBox/vmm/stam.h> +#include <VBox/vmm/tm.h> +#include <VBox/vmm/vmm.h> +#include <VBox/dbg.h> + +#include <iprt/stdarg.h> + +RT_C_DECLS_BEGIN + +/** @defgroup grp_vmm_vtable VMM Function Table + * @ingroup grp_vmm + * @{ */ + + +/** Magic and version for the VMM vtable. (Magic: Emmet Cohen) */ +#define VMMR3VTABLE_MAGIC_VERSION RT_MAKE_U64(0x19900525, 0x00030000) +/** Compatibility mask: These bits must match - magic and major version. */ +#define VMMR3VTABLE_MAGIC_VERSION_MASK RT_MAKE_U64(0xffffffff, 0xffff0000) + +/** Checks if @a a_uTableMagicVersion can be used by code compiled + * against @a a_CompiledMagicVersion */ +#define VMMR3VTABLE_IS_COMPATIBLE_EX(a_uTableMagicVersion, a_CompiledMagicVersion) \ + ( (a_uTableMagicVersion) >= (a_CompiledMagicVersion) /* table must be same or later version */ \ + && ((a_uTableMagicVersion) & VMMR3VTABLE_MAGIC_VERSION_MASK) == ((a_CompiledMagicVersion) & VMMR3VTABLE_MAGIC_VERSION_MASK) ) + +/** Checks if @a a_uTableMagicVersion can be used by this us. */ +#define VMMR3VTABLE_IS_COMPATIBLE(a_uTableMagicVersion) \ + VMMR3VTABLE_IS_COMPATIBLE_EX(a_uTableMagicVersion, VMMR3VTABLE_MAGIC_VERSION) + + +/** + * Function for getting the vtable of a VMM DLL/SO/DyLib. + * + * @returns the pointer to the vtable. + */ +typedef DECLCALLBACKTYPE(PCVMMR3VTABLE, FNVMMGETVTABLE,(void)); +/** Pointer to VMM vtable getter. */ +typedef FNVMMGETVTABLE *PFNVMMGETVTABLE; +/** The name of the FNVMMGETVTABLE function. */ +#define VMMR3VTABLE_GETTER_NAME "VMMR3GetVTable" + + +/** + * VTable for the ring-3 VMM API. + */ +typedef struct VMMR3VTABLE +{ + /** VMMR3VTABLE_MAGIC_VERSION. */ + uint64_t uMagicVersion; + /** Flags (TBD). */ + uint64_t fFlags; + /** The description of this VMM. */ + const char *pszDescription; + +/** @def VTABLE_ENTRY + * Define a VTable entry for the given function. */ +#if defined(DOXYGEN_RUNNING) \ + || (defined(__cplusplus) && (defined(__clang_major__) || RT_GNUC_PREREQ_EX(4, 8, /*non-gcc: */1) /* For 4.8+ we enable c++11 */)) +# define VTABLE_ENTRY(a_Api) /** @copydoc a_Api */ decltype(a_Api) *pfn ## a_Api; +#elif defined(__GNUC__) +# define VTABLE_ENTRY(a_Api) /** @copydoc a_Api */ typeof(a_Api) *pfn ## a_Api; +#else +# error "Unsupported compiler" +#endif +/** @def VTABLE_RESERVED + * Define a reserved VTable entry with the given name. */ +#define VTABLE_RESERVED(a_Name) DECLCALLBACKMEMBER(int, a_Name,(void)); + +#include "vmmr3vtable-def.h" + +#undef VTABLE_ENTRY +#undef VTABLE_RESERVED + + /** VMMR3VTABLE_MAGIC_VERSION. */ + uint64_t uMagicVersionEnd; +} VMMR3VTABLE; + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_vmmr3vtable_h */ + |