summaryrefslogtreecommitdiffstats
path: root/include/VBox/vmm
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 16:49:04 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 16:49:04 +0000
commit16f504a9dca3fe3b70568f67b7d41241ae485288 (patch)
treec60f36ada0496ba928b7161059ba5ab1ab224f9d /include/VBox/vmm
parentInitial commit. (diff)
downloadvirtualbox-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 '')
-rw-r--r--include/VBox/vmm/Makefile.kup0
-rw-r--r--include/VBox/vmm/apic.h107
-rw-r--r--include/VBox/vmm/cfgm.h245
-rw-r--r--include/VBox/vmm/cpuidcall.h107
-rw-r--r--include/VBox/vmm/cpuidcall.mac55
-rw-r--r--include/VBox/vmm/cpum.h3248
-rw-r--r--include/VBox/vmm/cpum.mac275
-rw-r--r--include/VBox/vmm/cpumctx-v1_6.h263
-rw-r--r--include/VBox/vmm/cpumctx.h1116
-rw-r--r--include/VBox/vmm/cpumdis.h61
-rw-r--r--include/VBox/vmm/dbgf.h3192
-rw-r--r--include/VBox/vmm/dbgfcorefmt.h188
-rw-r--r--include/VBox/vmm/dbgfflowtrace.h400
-rw-r--r--include/VBox/vmm/dbgfsel.h117
-rw-r--r--include/VBox/vmm/dbgftrace.h168
-rw-r--r--include/VBox/vmm/em.h345
-rw-r--r--include/VBox/vmm/gcm.h95
-rw-r--r--include/VBox/vmm/gim.h218
-rw-r--r--include/VBox/vmm/gmm.h828
-rw-r--r--include/VBox/vmm/gvm.h351
-rw-r--r--include/VBox/vmm/gvm.mac118
-rw-r--r--include/VBox/vmm/gvmm.h364
-rw-r--r--include/VBox/vmm/hm.h336
-rw-r--r--include/VBox/vmm/hm_svm.h1169
-rw-r--r--include/VBox/vmm/hm_vmx.h4644
-rw-r--r--include/VBox/vmm/hm_vmx.mac163
-rw-r--r--include/VBox/vmm/hmvmxinline.h1172
-rw-r--r--include/VBox/vmm/iem.h422
-rw-r--r--include/VBox/vmm/iom.h550
-rw-r--r--include/VBox/vmm/mm.h244
-rw-r--r--include/VBox/vmm/nem.h256
-rw-r--r--include/VBox/vmm/pdm.h54
-rw-r--r--include/VBox/vmm/pdmapi.h393
-rw-r--r--include/VBox/vmm/pdmasynccompletion.h160
-rw-r--r--include/VBox/vmm/pdmasynctask.h74
-rw-r--r--include/VBox/vmm/pdmaudiohostenuminline.h463
-rw-r--r--include/VBox/vmm/pdmaudioifs.h1567
-rw-r--r--include/VBox/vmm/pdmaudioinline.h1507
-rw-r--r--include/VBox/vmm/pdmblkcache.h432
-rw-r--r--include/VBox/vmm/pdmcardreaderinfs.h136
-rw-r--r--include/VBox/vmm/pdmcommon.h192
-rw-r--r--include/VBox/vmm/pdmcritsect.h143
-rw-r--r--include/VBox/vmm/pdmcritsectrw.h111
-rw-r--r--include/VBox/vmm/pdmdev.h9690
-rw-r--r--include/VBox/vmm/pdmdrv.h2497
-rw-r--r--include/VBox/vmm/pdmifs.h2366
-rw-r--r--include/VBox/vmm/pdmins.h99
-rw-r--r--include/VBox/vmm/pdmnetifs.h456
-rw-r--r--include/VBox/vmm/pdmnetinline.h724
-rw-r--r--include/VBox/vmm/pdmnetshaper.h93
-rw-r--r--include/VBox/vmm/pdmpci.h408
-rw-r--r--include/VBox/vmm/pdmpcidev.h803
-rw-r--r--include/VBox/vmm/pdmpcidevint.h238
-rw-r--r--include/VBox/vmm/pdmqueue.h169
-rw-r--r--include/VBox/vmm/pdmserialifs.h249
-rw-r--r--include/VBox/vmm/pdmsrv.h350
-rw-r--r--include/VBox/vmm/pdmstorageifs.h1059
-rw-r--r--include/VBox/vmm/pdmtask.h162
-rw-r--r--include/VBox/vmm/pdmthread.h311
-rw-r--r--include/VBox/vmm/pdmtpmifs.h163
-rw-r--r--include/VBox/vmm/pdmusb.h1502
-rw-r--r--include/VBox/vmm/pdmwebcaminfs.h156
-rw-r--r--include/VBox/vmm/pgm.h1129
-rw-r--r--include/VBox/vmm/selm.h114
-rw-r--r--include/VBox/vmm/ssm.h1354
-rw-r--r--include/VBox/vmm/stam.h1376
-rw-r--r--include/VBox/vmm/stam.mac392
-rw-r--r--include/VBox/vmm/tm.h322
-rw-r--r--include/VBox/vmm/trpm.h102
-rw-r--r--include/VBox/vmm/trpm.mac57
-rw-r--r--include/VBox/vmm/uvm.h195
-rw-r--r--include/VBox/vmm/vm.h1519
-rw-r--r--include/VBox/vmm/vm.mac187
-rw-r--r--include/VBox/vmm/vmapi.h485
-rw-r--r--include/VBox/vmm/vmcc.h148
-rw-r--r--include/VBox/vmm/vmcpuset.h124
-rw-r--r--include/VBox/vmm/vmm.h639
-rw-r--r--include/VBox/vmm/vmmr3vtable-def.h711
-rw-r--r--include/VBox/vmm/vmmr3vtable.h140
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 */
+