summaryrefslogtreecommitdiffstats
path: root/include/VBox/vmm/hmvmxinline.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/VBox/vmm/hmvmxinline.h')
-rw-r--r--include/VBox/vmm/hmvmxinline.h743
1 files changed, 743 insertions, 0 deletions
diff --git a/include/VBox/vmm/hmvmxinline.h b/include/VBox/vmm/hmvmxinline.h
new file mode 100644
index 00000000..52c0126d
--- /dev/null
+++ b/include/VBox/vmm/hmvmxinline.h
@@ -0,0 +1,743 @@
+/** @file
+ * HM - VMX Structures and Definitions. (VMM)
+ */
+
+/*
+ * Copyright (C) 2006-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef VBOX_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 >= 16 && defined(RT_ARCH_AMD64)
+# pragma warning(push)
+# pragma warning(disable:4668) /* Several incorrect __cplusplus uses. */
+# pragma warning(disable:4255) /* Incorrect __slwpcb prototype. */
+# include <intrin.h>
+# pragma warning(pop)
+/* 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
+
+
+/** @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) HMVmxGetVmcsFieldWidthEff(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 the encoding is for a valid and
+ * supported VMCS field.
+ */
+DECLINLINE(bool) HMVmxIsVmcsFieldReadOnly(uint32_t uFieldEnc)
+{
+ /* See Intel spec. B.4.2 "Natural-Width Read-Only Data Fields". */
+ return (RT_BF_GET(uFieldEnc, VMX_BF_VMCS_ENC_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) HMVmxIsEntryIntInfoTypeValid(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) HMVmxIsEntryIntInfoVectorValid(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) HMVmxIsVmexitTrapLike(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) HMVmxIsVmentryVectoring(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;
+}
+/** @} */
+
+
+/** @defgroup grp_hm_vmx_asm VMX Assembly Helpers
+ * @{
+ */
+
+/**
+ * Restores some host-state fields that need not be done on every VM-exit.
+ *
+ * @returns VBox status code.
+ * @param fRestoreHostFlags Flags of which host registers needs to be
+ * restored.
+ * @param pRestoreHost Pointer to the host-restore structure.
+ */
+DECLASM(int) VMXRestoreHostState(uint32_t fRestoreHostFlags, PVMXRESTOREHOST pRestoreHost);
+
+
+/**
+ * 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 || !defined(RT_ARCH_X86)) && !VMX_USE_MSC_INTRINSICS)
+DECLASM(int) VMXEnable(RTHCPHYS HCPhysVmxOn);
+#else
+DECLINLINE(int) VMXEnable(RTHCPHYS HCPhysVmxOn)
+{
+# if RT_INLINE_ASM_GNU_STYLE
+ int rc = VINF_SUCCESS;
+ __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;
+
+# elif 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;
+
+# else
+ 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;
+# endif
+}
+#endif
+
+
+/**
+ * Executes VMXOFF.
+ */
+#if ((RT_INLINE_ASM_EXTERNAL || !defined(RT_ARCH_X86)) && !VMX_USE_MSC_INTRINSICS)
+DECLASM(void) VMXDisable(void);
+#else
+DECLINLINE(void) VMXDisable(void)
+{
+# if RT_INLINE_ASM_GNU_STYLE
+ __asm__ __volatile__ (
+ ".byte 0x0f, 0x01, 0xc4 # VMXOFF \n\t"
+ );
+
+# elif VMX_USE_MSC_INTRINSICS
+ __vmx_off();
+
+# else
+ __asm
+ {
+ _emit 0x0f
+ _emit 0x01
+ _emit 0xc4 /* VMXOFF */
+ }
+# endif
+}
+#endif
+
+
+/**
+ * Executes VMCLEAR.
+ *
+ * @returns VBox status code.
+ * @param HCPhysVmcs Physical address of VM control structure.
+ */
+#if ((RT_INLINE_ASM_EXTERNAL || !defined(RT_ARCH_X86)) && !VMX_USE_MSC_INTRINSICS)
+DECLASM(int) VMXClearVmcs(RTHCPHYS HCPhysVmcs);
+#else
+DECLINLINE(int) VMXClearVmcs(RTHCPHYS HCPhysVmcs)
+{
+# if RT_INLINE_ASM_GNU_STYLE
+ int rc = VINF_SUCCESS;
+ __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;
+
+# elif VMX_USE_MSC_INTRINSICS
+ unsigned char rcMsc = __vmx_vmclear(&HCPhysVmcs);
+ if (RT_LIKELY(rcMsc == 0))
+ return VINF_SUCCESS;
+ return VERR_VMX_INVALID_VMCS_PTR;
+
+# else
+ 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;
+# endif
+}
+#endif
+
+
+/**
+ * Executes VMPTRLD.
+ *
+ * @returns VBox status code.
+ * @param HCPhysVmcs Physical address of VMCS structure.
+ */
+#if ((RT_INLINE_ASM_EXTERNAL || !defined(RT_ARCH_X86)) && !VMX_USE_MSC_INTRINSICS)
+DECLASM(int) VMXActivateVmcs(RTHCPHYS HCPhysVmcs);
+#else
+DECLINLINE(int) VMXActivateVmcs(RTHCPHYS HCPhysVmcs)
+{
+# if RT_INLINE_ASM_GNU_STYLE
+ int rc = VINF_SUCCESS;
+ __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 */
+ );
+ return rc;
+
+# elif VMX_USE_MSC_INTRINSICS
+ unsigned char rcMsc = __vmx_vmptrld(&HCPhysVmcs);
+ if (RT_LIKELY(rcMsc == 0))
+ return VINF_SUCCESS;
+ return VERR_VMX_INVALID_VMCS_PTR;
+
+# else
+ 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;
+# endif
+}
+#endif
+
+
+/**
+ * Executes VMPTRST.
+ *
+ * @returns VBox status code.
+ * @param pHCPhysVmcs Where to store the physical address of the current
+ * VMCS.
+ */
+DECLASM(int) VMXGetActivatedVmcs(RTHCPHYS *pHCPhysVmcs);
+
+
+/**
+ * Executes VMWRITE.
+ *
+ * @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 || !defined(RT_ARCH_X86)) && !VMX_USE_MSC_INTRINSICS)
+DECLASM(int) VMXWriteVmcs32(uint32_t uFieldEnc, uint32_t u32Val);
+#else
+DECLINLINE(int) VMXWriteVmcs32(uint32_t uFieldEnc, uint32_t u32Val)
+{
+# if RT_INLINE_ASM_GNU_STYLE
+ int rc = VINF_SUCCESS;
+ __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;
+
+# elif VMX_USE_MSC_INTRINSICS
+ 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;
+
+#else
+ 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;
+# endif
+}
+#endif
+
+/**
+ * Executes VMWRITE.
+ *
+ * @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)
+# if !VMX_USE_MSC_INTRINSICS || ARCH_BITS != 64
+DECLASM(int) VMXWriteVmcs64(uint32_t uFieldEnc, uint64_t u64Val);
+# else /* VMX_USE_MSC_INTRINSICS */
+DECLINLINE(int) VMXWriteVmcs64(uint32_t uFieldEnc, uint64_t u64Val)
+{
+ 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 /* VMX_USE_MSC_INTRINSICS */
+#else
+# define VMXWriteVmcs64(uFieldEnc, u64Val) VMXWriteVmcs64Ex(pVCpu, uFieldEnc, u64Val) /** @todo dead ugly, picking up pVCpu like this */
+VMMR0DECL(int) VMXWriteVmcs64Ex(PVMCPU pVCpu, uint32_t uFieldEnc, uint64_t u64Val);
+#endif
+
+#if ARCH_BITS == 32
+# define VMXWriteVmcsHstN VMXWriteVmcs32
+# define VMXWriteVmcsGstN(uFieldEnc, u64Val) VMXWriteVmcs64Ex(pVCpu, uFieldEnc, u64Val)
+#else /* ARCH_BITS == 64 */
+# define VMXWriteVmcsHstN VMXWriteVmcs64
+# define VMXWriteVmcsGstN VMXWriteVmcs64
+#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 || !defined(RT_ARCH_X86)) && !VMX_USE_MSC_INTRINSICS)
+DECLASM(int) VMXReadVmcs32(uint32_t uFieldEnc, uint32_t *pData);
+#else
+DECLINLINE(int) VMXReadVmcs32(uint32_t uFieldEnc, uint32_t *pData)
+{
+# if RT_INLINE_ASM_GNU_STYLE
+ int rc = VINF_SUCCESS;
+ __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;
+
+# elif VMX_USE_MSC_INTRINSICS
+ unsigned char rcMsc;
+# if ARCH_BITS == 32
+ rcMsc = __vmx_vmread(uFieldEnc, pData);
+# else
+ uint64_t u64Tmp;
+ rcMsc = __vmx_vmread(uFieldEnc, &u64Tmp);
+ *pData = (uint32_t)u64Tmp;
+# endif
+ if (RT_LIKELY(rcMsc == 0))
+ return VINF_SUCCESS;
+ return rcMsc == 2 ? VERR_VMX_INVALID_VMCS_PTR : VERR_VMX_INVALID_VMCS_FIELD;
+
+#else
+ 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;
+# 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) && !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
+ unsigned char rcMsc;
+# if ARCH_BITS == 32
+ size_t uLow;
+ size_t uHigh;
+ rcMsc = __vmx_vmread(uFieldEnc, &uLow);
+ rcMsc |= __vmx_vmread(uFieldEnc + 1, &uHigh);
+ *pData = RT_MAKE_U64(uLow, uHigh);
+# else
+ rcMsc = __vmx_vmread(uFieldEnc, pData);
+# endif
+ if (RT_LIKELY(rcMsc == 0))
+ return VINF_SUCCESS;
+ return rcMsc == 2 ? VERR_VMX_INVALID_VMCS_PTR : VERR_VMX_INVALID_VMCS_FIELD;
+
+# elif ARCH_BITS == 32
+ int rc;
+ uint32_t val_hi, val;
+ rc = VMXReadVmcs32(uFieldEnc, &val);
+ rc |= VMXReadVmcs32(uFieldEnc + 1, &val_hi);
+ AssertRC(rc);
+ *pData = RT_MAKE_U64(val, val_hi);
+ return rc;
+
+# else
+# error "Shouldn't be here..."
+# endif
+}
+#endif
+
+
+/**
+ * Gets the last instruction error value from the current VMCS.
+ *
+ * @returns VBox status code.
+ */
+DECLINLINE(uint32_t) VMXGetLastError(void)
+{
+#if ARCH_BITS == 64
+ uint64_t uLastError = 0;
+ int rc = VMXReadVmcs64(VMX_VMCS32_RO_VM_INSTR_ERROR, &uLastError);
+ AssertRC(rc);
+ return (uint32_t)uLastError;
+
+#else /* 32-bit host: */
+ uint32_t uLastError = 0;
+ int rc = VMXReadVmcs32(VMX_VMCS32_RO_VM_INSTR_ERROR, &uLastError);
+ AssertRC(rc);
+ return uLastError;
+#endif
+}
+
+/** @} */
+
+#endif /* !VBOX_INCLUDED_vmm_hmvmxinline_h */
+