HMVMXR0.cpp revision e9fe5fb557a74804047344ee43f10726bb84ce60
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * HM VMX (Intel VT-x) - Host Context Ring-0.
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * Copyright (C) 2012-2013 Oracle Corporation
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * This file is part of VirtualBox Open Source Edition (OSE), as
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * available from http://www.virtualbox.org. This file is free software;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * you can redistribute it and/or modify it under the terms of the GNU
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * General Public License (GPL) as published by the Free Software
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * Foundation, in version 2 as it comes in the "COPYING" file of the
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk/*******************************************************************************
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk* Header Files *
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk*******************************************************************************/
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk/*******************************************************************************
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk* Defined Constants And Macros *
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk*******************************************************************************/
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk# define HMVMX_IS_64BIT_HOST_MODE() (g_fVMXIs64bitHost != 0)
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk# define HMVMX_IS_64BIT_HOST_MODE() (false)
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk/** Use the function table. */
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk/** Determine which tagged-TLB flush handler to use. */
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk/** @name Updated-guest-state flags.
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk#define HMVMX_UPDATED_GUEST_SEGMENT_REGS RT_BIT(10)
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk#define HMVMX_UPDATED_GUEST_SYSENTER_CS_MSR RT_BIT(12)
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk#define HMVMX_UPDATED_GUEST_SYSENTER_EIP_MSR RT_BIT(13)
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk#define HMVMX_UPDATED_GUEST_SYSENTER_ESP_MSR RT_BIT(14)
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk#define HMVMX_UPDATED_GUEST_AUTO_LOAD_STORE_MSRS RT_BIT(15)
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk#define HMVMX_UPDATED_GUEST_ACTIVITY_STATE RT_BIT(17)
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk#define HMVMX_UPDATED_GUEST_APIC_STATE RT_BIT(18)
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk#define HMVMX_UPDATED_GUEST_ALL ( HMVMX_UPDATED_GUEST_RIP \
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * Flags to skip redundant reads of some common VMCS fields that are not part of
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * the guest-CPU state but are in the transient structure.
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk#define HMVMX_UPDATED_TRANSIENT_IDT_VECTORING_INFO RT_BIT(0)
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk#define HMVMX_UPDATED_TRANSIENT_IDT_VECTORING_ERROR_CODE RT_BIT(1)
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk#define HMVMX_UPDATED_TRANSIENT_EXIT_QUALIFICATION RT_BIT(2)
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk#define HMVMX_UPDATED_TRANSIENT_EXIT_INSTR_LEN RT_BIT(3)
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk#define HMVMX_UPDATED_TRANSIENT_EXIT_INTERRUPTION_INFO RT_BIT(4)
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk#define HMVMX_UPDATED_TRANSIENT_EXIT_INTERRUPTION_ERROR_CODE RT_BIT(5)
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk#define HMVMX_UPDATED_TRANSIENT_EXIT_INSTR_INFO RT_BIT(6)
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * States of the VMCS.
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * This does not reflect all possible VMCS states but currently only those
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * needed for maintaining the VMCS consistently even when thread-context hooks
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * are used. Maybe later this can be extended (i.e. Nested Virtualization).
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * Exception bitmap mask for real-mode guests (real-on-v86).
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * We need to intercept all exceptions manually (except #PF). #NM is also
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * handled separately, see hmR0VmxLoadSharedCR0(). #PF need not be intercepted
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * even in real-mode if we have Nested Paging support.
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk#define HMVMX_REAL_MODE_XCPT_MASK ( RT_BIT(X86_XCPT_DE) | RT_BIT(X86_XCPT_DB) | RT_BIT(X86_XCPT_NMI) \
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk | RT_BIT(X86_XCPT_BP) | RT_BIT(X86_XCPT_OF) | RT_BIT(X86_XCPT_BR) \
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk | RT_BIT(X86_XCPT_UD) /* RT_BIT(X86_XCPT_NM) */ | RT_BIT(X86_XCPT_DF) \
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk | RT_BIT(X86_XCPT_CO_SEG_OVERRUN) | RT_BIT(X86_XCPT_TS) | RT_BIT(X86_XCPT_NP) \
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk | RT_BIT(X86_XCPT_SS) | RT_BIT(X86_XCPT_GP) /* RT_BIT(X86_XCPT_PF) */ \
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk | RT_BIT(X86_XCPT_MF) | RT_BIT(X86_XCPT_AC) | RT_BIT(X86_XCPT_MC) \
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * Exception bitmap mask for all contributory exceptions.
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * Page fault is deliberately excluded here as it's conditional as to whether
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * it's contributory or benign. Page faults are handled separately.
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk#define HMVMX_CONTRIBUTORY_XCPT_MASK ( RT_BIT(X86_XCPT_GP) | RT_BIT(X86_XCPT_NP) | RT_BIT(X86_XCPT_SS) | RT_BIT(X86_XCPT_TS) \
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk/** Maximum VM-instruction error number. */
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk/** Profiling macro. */
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk# define HMVMX_START_EXIT_DISPATCH_PROF() STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitDispatch, ed)
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk# define HMVMX_STOP_EXIT_DISPATCH_PROF() STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitDispatch, ed)
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk# define HMVMX_START_EXIT_DISPATCH_PROF() do { } while (0)
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk# define HMVMX_STOP_EXIT_DISPATCH_PROF() do { } while (0)
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk/** Assert that preemption is disabled or covered by thread-context hooks. */
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk#define HMVMX_ASSERT_PREEMPT_SAFE() Assert( VMMR0ThreadCtxHooksAreRegistered(pVCpu) \
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk/** Assert that we haven't migrated CPUs when thread-context hooks are not
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk#define HMVMX_ASSERT_CPU_SAFE() AssertMsg( VMMR0ThreadCtxHooksAreRegistered(pVCpu) \
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk ("Illegal migration! Entered on CPU %u Current %u\n", \
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk/** Helper macro for VM-exit handlers called unexpectedly. */
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk pVCpu->hm.s.u32HMError = pVmxTransient->uExitReason; \
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk/*******************************************************************************
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk* Structures and Typedefs *
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk*******************************************************************************/
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * VMX transient state.
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * A state structure for holding miscellaneous information across
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * VMX non-root operation and restored after the transition.
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk /** The host's rflags/eflags. */
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk /** The guest's TPR value used for TPR shadowing. */
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk /** Alignment. */
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk /** The basic VM-exit reason. */
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk /** Alignment. */
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk /** The VM-exit interruption error code. */
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk /** The VM-exit exit qualification. */
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk /** The VM-exit interruption-information field. */
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk /** The VM-exit instruction-length field. */
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk /** The VM-exit instruction-information field. */
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk /** Plain unsigned int representation. */
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk /** INS and OUTS information. */
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk /** The address size; 0=16-bit, 1=32-bit, 2=64-bit, rest undefined. */
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk /** The segment register (X86_SREG_XXX). */
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk /** Whether the VM-entry failed or not. */
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk /** Alignment. */
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk /** The VM-entry interruption-information field. */
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk /** The VM-entry exception error code field. */
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk /** The VM-entry instruction length field. */
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk /** IDT-vectoring information field. */
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk /** IDT-vectoring error code. */
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk /** Mask of currently read VMCS fields; HMVMX_UPDATED_TRANSIENT_*. */
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk /** Whether the guest FPU was active at the time of VM-exit. */
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk /** Whether the guest debug state was active at the time of VM-exit. */
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk /** Whether the hyper debug state was active at the time of VM-exit. */
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk /** Whether TSC-offsetting should be setup before VM-entry. */
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk /** Whether the VM-exit was caused by a page-fault during delivery of a
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * contributory exception or a page-fault. */
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkAssertCompileMemberAlignment(VMXTRANSIENT, uExitReason, sizeof(uint64_t));
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkAssertCompileMemberAlignment(VMXTRANSIENT, uExitIntInfo, sizeof(uint64_t));
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkAssertCompileMemberAlignment(VMXTRANSIENT, uEntryIntInfo, sizeof(uint64_t));
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkAssertCompileMemberAlignment(VMXTRANSIENT, fWasGuestFPUStateActive, sizeof(uint64_t));
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkAssertCompileMemberSize(VMXTRANSIENT, ExitInstrInfo, sizeof(uint32_t));
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk/** Pointer to VMX transient state. */
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * MSR-bitmap read permissions.
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk /** Reading this MSR causes a VM-exit. */
typedef enum VMXMSREXITWRITE
#ifndef HMVMX_USE_FUNCTION_TABLE
typedef DECLCALLBACK(int) FNVMXEXITHANDLER(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
static int hmR0VmxInjectEventVmcs(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint64_t u64IntInfo, uint32_t cbInstr,
#ifndef HMVMX_USE_FUNCTION_TABLE
DECLINLINE(int) hmR0VmxHandleExit(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient, uint32_t rcReason);
# define HMVMX_EXIT_DECL static int
#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
#ifdef HMVMX_USE_FUNCTION_TABLE
#ifdef VBOX_STRICT
return VINF_SUCCESS;
int rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE, &pVmxTransient->uEntryXcptErrorCode);
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
int rc = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_ERROR_CODE, &pVmxTransient->uExitIntErrorCode);
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
int rc = VMXReadVmcsGstN(VMX_VMCS_RO_EXIT_QUALIFICATION, &pVmxTransient->uExitQualification); NOREF(pVCpu);
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
if (pVM)
return rc;
static int hmR0VmxLeaveRootMode(void)
int rc;
VMXDisable();
return rc;
return rc;
return VINF_SUCCESS;
*ppVirt = 0;
*pHCPhys = 0;
hmR0VmxPageFree(&pVCpu->hm.s.vmx.hMemObjHostMsr, &pVCpu->hm.s.vmx.pvHostMsr, &pVCpu->hm.s.vmx.HCPhysHostMsr);
hmR0VmxPageFree(&pVCpu->hm.s.vmx.hMemObjGuestMsr, &pVCpu->hm.s.vmx.pvGuestMsr, &pVCpu->hm.s.vmx.HCPhysGuestMsr);
hmR0VmxPageFree(&pVCpu->hm.s.vmx.hMemObjMsrBitmap, &pVCpu->hm.s.vmx.pvMsrBitmap, &pVCpu->hm.s.vmx.HCPhysMsrBitmap);
hmR0VmxPageFree(&pVCpu->hm.s.vmx.hMemObjVirtApic, (PRTR0PTR)&pVCpu->hm.s.vmx.pbVirtApic, &pVCpu->hm.s.vmx.HCPhysVirtApic);
hmR0VmxPageFree(&pVCpu->hm.s.vmx.hMemObjVmcs, &pVCpu->hm.s.vmx.pvVmcs, &pVCpu->hm.s.vmx.HCPhysVmcs);
hmR0VmxPageFree(&pVM->hm.s.vmx.hMemObjApicAccess, (PRTR0PTR)&pVM->hm.s.vmx.pbApicAccess, &pVM->hm.s.vmx.HCPhysApicAccess);
#ifdef VBOX_WITH_CRASHDUMP_MAGIC
hmR0VmxPageFree(&pVM->hm.s.vmx.hMemObjScratch, &pVM->hm.s.vmx.pbScratch, &pVM->hm.s.vmx.HCPhysScratch);
#ifdef VBOX_WITH_CRASHDUMP_MAGIC
/* The VMCS size cannot be more than 4096 bytes. See Intel spec. Appendix A.1 "Basic VMX Information". */
#ifdef VBOX_WITH_CRASHDUMP_MAGIC
rc = hmR0VmxPageAllocZ(&pVM->hm.s.vmx.hMemObjScratch, &pVM->hm.s.vmx.pbScratch, &pVM->hm.s.vmx.HCPhysScratch);
goto cleanup;
goto cleanup;
rc = hmR0VmxPageAllocZ(&pVCpu->hm.s.vmx.hMemObjVmcs, &pVCpu->hm.s.vmx.pvVmcs, &pVCpu->hm.s.vmx.HCPhysVmcs);
goto cleanup;
goto cleanup;
/* Allocate the MSR-bitmap if supported by the CPU. The MSR-bitmap is for transparent accesses of specific MSRs. */
goto cleanup;
rc = hmR0VmxPageAllocZ(&pVCpu->hm.s.vmx.hMemObjGuestMsr, &pVCpu->hm.s.vmx.pvGuestMsr, &pVCpu->hm.s.vmx.HCPhysGuestMsr);
goto cleanup;
rc = hmR0VmxPageAllocZ(&pVCpu->hm.s.vmx.hMemObjHostMsr, &pVCpu->hm.s.vmx.pvHostMsr, &pVCpu->hm.s.vmx.HCPhysHostMsr);
goto cleanup;
return VINF_SUCCESS;
return rc;
#ifdef HMVMX_USE_FUNCTION_TABLE
# ifdef VBOX_STRICT
return VINF_SUCCESS;
VMMR0DECL(int) VMXR0EnableCpu(PHMGLOBALCPUINFO pCpu, PVM pVM, void *pvCpuPage, RTHCPHYS HCPhysCpuPage, bool fEnabledByHost,
void *pvMsrs)
if (!fEnabledByHost)
return rc;
* Flush all EPT tagged-TLB entries (in case VirtualBox or any other hypervisor have been using EPTPs) so
* we don't retain any stale guest-physical mappings which won't get invalidated when flushing by VPID.
return VINF_SUCCESS;
return hmR0VmxLeaveRootMode();
static void hmR0VmxSetMsrPermission(PVMCPU pVCpu, uint32_t uMsr, VMXMSREXITREAD enmRead, VMXMSREXITWRITE enmWrite)
#ifdef VBOX_STRICT
static int hmR0VmxGetMsrPermission(PVMCPU pVCpu, uint32_t uMsr, PVMXMSREXITREAD penmRead, PVMXMSREXITWRITE penmWrite)
return VERR_NOT_SUPPORTED;
return VINF_SUCCESS;
uint32_t const cMaxSupportedMsrs = MSR_IA32_VMX_MISC_MAX_MSR(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.u64Misc);
LogRel(("CPU auto-load/store MSR count in VMCS exceeded cMsrs=%u Supported=%u.\n", cMsrs, cMaxSupportedMsrs));
/* Update number of host MSRs to load after the world-switch. Identical to guest-MSR count as it's always paired. */
return VINF_SUCCESS;
static bool hmR0VmxAddAutoLoadStoreMsr(PVMCPU pVCpu, uint32_t uMsr, uint64_t uGuestMsrValue, bool fUpdateHostMsr)
uint32_t i;
for (i = 0; i < cMsrs; i++)
pGuestMsr++;
bool fAdded = false;
if (i == cMsrs)
++cMsrs;
/* Now that we're swapping MSRs during the world-switch, allow the guest to read/write them without causing VM-exits. */
fAdded = true;
pHostMsr += i;
bool fUpdatedMsrValue = false;
if ( fAdded
&& fUpdateHostMsr)
fUpdatedMsrValue = true;
return fUpdatedMsrValue;
--cMsrs;
--cMsrs;
pGuestMsr++;
return VINF_SUCCESS;
* Note: If you're adding MSRs here, make sure to update the MSR-bitmap permissions in hmR0VmxSetupProcCtls().
switch (uMsr)
case MSR_K8_LSTAR:
case MSR_K6_STAR:
case MSR_K8_SF_MASK:
case MSR_K8_KERNEL_GS_BASE:
pVCpu->hm.s.vmx.fRestoreHostMsrs &= ~(VMX_RESTORE_HOST_MSR_LOADED_GUEST | VMX_RESTORE_HOST_MSR_SAVED_HOST);
#ifdef VBOX_STRICT
AssertMsgReturnVoid(pHostMsr->u32Msr == pGuestMsr->u32Msr, ("HostMsr=%#RX32 GuestMsr=%#RX32\n", pHostMsr->u32Msr,
AssertMsgReturnVoid(pHostMsr->u64Value == u64Msr, ("u32Msr=%#RX32 VMCS Value=%#RX64 ASMRdMsr=%#RX64\n", pHostMsr->u32Msr,
AssertMsgReturnVoid(enmRead == VMXMSREXIT_PASSTHRU_READ, ("u32Msr=%#RX32 No passthru read permission!\n",
AssertMsgReturnVoid(enmWrite == VMXMSREXIT_PASSTHRU_WRITE, ("u32Msr=%#RX32 No passthru write permission!\n",
au64Descriptor[0] = 0;
AssertMsg(rc == VINF_SUCCESS, ("VMXR0InvEPT %#x %RGv failed with %Rrc\n", enmFlush, pVCpu ? pVCpu->hm.s.vmx.HCPhysEPTP : 0,
rc));
&& pVCpu)
au64Descriptor[0] = 0;
AssertMsg(pVCpu->hm.s.uCurrentAsid != 0, ("VMXR0InvVPID: invalid ASID %lu\n", pVCpu->hm.s.uCurrentAsid));
AssertMsg(pVCpu->hm.s.uCurrentAsid <= UINT16_MAX, ("VMXR0InvVPID: invalid ASID %lu\n", pVCpu->hm.s.uCurrentAsid));
("VMXR0InvVPID %#x %u %RGv failed with %d\n", enmFlush, pVCpu ? pVCpu->hm.s.uCurrentAsid : 0, GCPtr, rc));
&& pVCpu)
if (!fFlushPending)
return VINF_SUCCESS;
* We cannot flush a page by guest-physical address. invvpid takes only a linear address while invept only flushes
* by EPT not individual addresses. We update the force flag here and flush before the next VM-entry in hmR0VmxFlushTLB*().
* This function might be called in a loop. This should cause a flush-by-EPT if EPT is in use. See @bugref{6568}.
return VINF_SUCCESS;
#ifdef VBOX_WITH_STATISTICS
bool fTlbFlushed = false;
# define HMVMX_UPDATE_FLUSH_SKIPPED_STAT() do { \
if (!fTlbFlushed) \
# define HMVMX_SET_TAGGED_TLB_FLUSHED() do { } while (0)
# define HMVMX_UPDATE_FLUSH_SKIPPED_STAT() do { } while (0)
* Force a TLB flush for the first world-switch if the current CPU differs from the one we ran on last.
* If the TLB flush count changed, another VM (VCPU rather) has hit the ASID limit while flushing the TLB
pCpu->fFlushAsidBeforeUse = true; /* All VCPUs that run on this host CPU must flush their new VPID before use. */
* Flush by EPT when we get rescheduled to a new host CPU to ensure EPT-only tagged mappings are also
* Flushing by VPID will only flush linear (only VPID-tagged) and combined (EPT+VPID tagged) mappings
("Flush count mismatch for cpu %d (%u vs %u)\n", pCpu->idCpu, pVCpu->hm.s.cTlbFlushes, pCpu->cTlbFlushes));
AssertMsg(pVM->hm.s.fNestedPaging, ("hmR0VmxFlushTaggedTlbEpt cannot be invoked with NestedPaging disabled."));
* Force a TLB flush for the first world-switch if the current CPU differs from the one we ran on last.
AssertMsg(!pVM->hm.s.fNestedPaging, ("hmR0VmxFlushTlbVpid cannot be invoked with NestedPaging enabled"));
* Force a TLB flush for the first world switch if the current CPU differs from the one we ran on last.
* If the TLB flush count changed, another VM (VCPU rather) has hit the ASID limit while flushing the TLB
* If we ever support VPID flush combinations other than ALL or SINGLE-context (see hmR0VmxSetupTaggedTlb())
pCpu->fFlushAsidBeforeUse = true; /* All VCPUs that run on this host CPU must flush their new VPID before use. */
/* Flush individual guest entries using VPID or as little as possible with EPT as supported by the CPU. */
("Flush count mismatch for cpu %d (%u vs %u)\n", pCpu->idCpu, pVCpu->hm.s.cTlbFlushes, pCpu->cTlbFlushes));
#ifdef HMVMX_ALWAYS_FLUSH_TLB
/* Don't assert that VMCPU_FF_TLB_FLUSH should no longer be pending. It can be set by other EMTs. */
* We cannot ignore EPT if no suitable flush-types is supported by the CPU as we've already setup unrestricted
LogRel(("hmR0VmxSetupTaggedTlb: Unsupported EPTP memory type %#x.\n", pVM->hm.s.vmx.Msrs.u64EptVpidCaps));
/* Neither SINGLE nor ALL-context flush types for VPID is supported by the CPU. Ignore VPID capability. */
if (pVM->hm.s.vmx.Msrs.u64EptVpidCaps & MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_SINGLE_CONTEXT_RETAIN_GLOBALS)
/* Shouldn't happen. VPID is supported but INVVPID is not supported by the CPU. Ignore VPID capability. */
return VINF_SUCCESS;
uint32_t zap = pVM->hm.s.vmx.Msrs.VmxPinCtls.n.allowed1; /* Bits cleared here must always be cleared. */
LogRel(("hmR0VmxSetupPinCtls: invalid pin-based VM-execution controls combo! cpu=%#RX64 val=%#RX64 zap=%#RX64\n",
return rc;
uint32_t val = pVM->hm.s.vmx.Msrs.VmxProcCtls.n.disallowed0; /* Bits set here must be set in the VMCS. */
uint32_t zap = pVM->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
/* We toggle VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT later, check if it's not -always- needed to be set or clear. */
/* Without Nested Paging, INVLPG (also affects INVPCID) and MOV CR3 instructions should cause VM-exits. */
* Some 32-bit CPUs do not support CR8 load/store exiting as MOV CR8 is invalid on 32-bit Intel CPUs.
* The guest can access the following MSRs (read, write) without causing VM-exits; they are loaded/stored
hmR0VmxSetMsrPermission(pVCpu, MSR_IA32_SYSENTER_CS, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
hmR0VmxSetMsrPermission(pVCpu, MSR_IA32_SYSENTER_ESP, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
hmR0VmxSetMsrPermission(pVCpu, MSR_IA32_SYSENTER_EIP, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
hmR0VmxSetMsrPermission(pVCpu, MSR_K8_GS_BASE, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
hmR0VmxSetMsrPermission(pVCpu, MSR_K8_FS_BASE, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
hmR0VmxSetMsrPermission(pVCpu, MSR_K8_SF_MASK, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
hmR0VmxSetMsrPermission(pVCpu, MSR_K8_KERNEL_GS_BASE, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
LogRel(("hmR0VmxSetupProcCtls: invalid processor-based VM-execution controls combo! cpu=%#RX64 val=%#RX64 zap=%#RX64\n",
zap = pVM->hm.s.vmx.Msrs.VmxProcCtls2.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
* Without Nested Paging, INVPCID should cause a VM-exit. Enabling this bit causes the CPU to refer to
/* Enable Virtual-APIC page accesses if supported by the CPU. This is essentially where the TPR shadow resides. */
LogRel(("hmR0VmxSetupProcCtls: Unrestricted Guest set as true when secondary processor-based VM-execution controls not "
return VINF_SUCCESS;
/* All fields are zero-initialized during allocation; but don't remove the commented block below. */
/* All CR3 accesses cause VM-exits. Later we optimize CR3 accesses (see hmR0VmxLoadGuestCR3AndCR4())*/
* Set MASK & MATCH to 0. VMX checks if GuestPFErrCode & MASK == MATCH. If equal (in our case it always is)
* and if the X86_XCPT_PF bit in the exception bitmap is set it causes a VM-exit, if clear doesn't cause an exit.
/* Set VMCS link pointer. Reserved for future use, must be -1. Intel spec. 24.4 "Guest-State Area". */
/* All fields are zero-initialized during allocation; but don't remove the commented block below. */
rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_DEBUGCTL_FULL, 0); /** @todo We don't support IA32_DEBUGCTL MSR. Should we? */
return rc;
return rc;
return VINF_SUCCESS;
return rc;
return VINF_SUCCESS;
#ifdef VBOX_WITH_CRASHDUMP_MAGIC
return VINF_SUCCESS;
* Without UnrestrictedGuest, pRealModeTSS and pNonPagingModeEPTPageTable *must* always be allocated.
* We no longer support the highly unlikely case of UnrestrictedGuest without pRealModeTSS. See hmR3InitFinalizeR0().
return VERR_INTERNAL_ERROR;
&& !HMVMX_IS_64BIT_HOST_MODE())
return rc;
*(uint32_t *)pVCpu->hm.s.vmx.pvVmcs = MSR_IA32_VMX_BASIC_INFO_VMCS_ID(pVM->hm.s.vmx.Msrs.u64BasicInfo);
AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: VMXActivateVmcs failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: hmR0VmxSetupPinCtls failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: hmR0VmxSetupProcCtls failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: hmR0VmxSetupMiscCtls failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: hmR0VmxInitXcptBitmap failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: hmR0VmxInitUpdatedGuestStateMask failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: hmR0VmxInitVmcsReadCache failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
/* Re-sync the CPU's internal data into our VMCS memory region & reset the launch state to "clear". */
AssertLogRelMsgRCReturnStmt(rc, ("VMXR0SetupVM: VMXClearVmcs(2) failed! rc=%Rrc (pVM=%p)\n", rc, pVM),
return VINF_SUCCESS;
if (HMVMX_IS_64BIT_HOST_MODE())
return rc;
bool fValidSelector = true; \
if (fValidSelector) \
(selValue) = 0; \
* should -not- save the messed up state without restoring the original host-state. See @bugref{7240}.
if (HMVMX_IS_64BIT_HOST_MODE())
* Determine if the host segment registers are suitable for VT-x. Otherwise use zero to gain VM-entry and restore them
* before we get preempted. See Intel spec. 26.2.3 "Checks on Host Segment and Descriptor-Table Registers".
/* Verification based on Intel spec. 26.2.3 "Checks on Host Segment and Descriptor-Table Registers" */
if (HMVMX_IS_64BIT_HOST_MODE())
* Determine if we need to manually need to restore the GDTR and IDTR limits as VT-x zaps them to the
* and Intel spec. 6.2 "Exception and Interrupt Vectors".) Therefore if the host has the limit as 0xfff, VT-x
* bloating the limit to 0xffff shouldn't cause any different CPU behavior. However, several hosts either insists
* on 0xfff being the limit (Windows Patch Guard) or uses the limit for other purposes (darwin puts the CPU ID in there
* but botches sidt alignment in at least one consumer). So, we're only allowing IDTR.LIMIT to be left at 0xffff on
* is effectively what the CPU does for "scaling by 8". TI is always 0 and RPL should be too in most cases.
AssertMsgFailed(("hmR0VmxSaveHostSegmentRegs: TR selector exceeds limit. TR=%RTsel cbGdt=%#x\n", uSelTR, Gdtr.cbGdt));
return VERR_VMX_INVALID_HOST_STATE;
if (HMVMX_IS_64BIT_HOST_MODE())
* VT-x unconditionally restores the TR limit to 0x67 and type to 11 (32-bit busy TSS) on all VM-exits.
* The type is the same for 64-bit busy TSS[1]. The limit needs manual restoration if the host has something else.
* Task switching is not supported in 64-bit mode[2], but the limit still matters as IOPM is supported in 64-bit mode.
* Restoring the limit lazily while returning to ring-3 is safe because IOPM is not applicable in ring-0.
if (HMVMX_IS_64BIT_HOST_MODE())
/* Store the base if we have to restore FS or GS manually as we need to restore the base as well. */
return rc;
if (HMVMX_IS_64BIT_HOST_MODE())
return rc;
uint32_t val = pVM->hm.s.vmx.Msrs.VmxEntry.n.disallowed0; /* Bits set here must be set in the VMCS. */
uint32_t zap = pVM->hm.s.vmx.Msrs.VmxEntry.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
/* Load debug controls (DR7 & IA32_DEBUGCTL_MSR). The first VT-x capable CPUs only supports the 1-setting of this bit. */
LogRel(("hmR0VmxLoadGuestEntryCtls: invalid VM-entry controls combo! cpu=%RX64 val=%RX64 zap=%RX64\n",
return rc;
uint32_t val = pVM->hm.s.vmx.Msrs.VmxExit.n.disallowed0; /* Bits set here must be set in the VMCS. */
uint32_t zap = pVM->hm.s.vmx.Msrs.VmxExit.n.allowed1; /* Bits cleared here must be cleared in the VMCS. */
/* Save debug controls (DR7 & IA32_DEBUGCTL_MSR). The first VT-x CPUs only supported the 1-setting of this bit. */
* Set the host long mode active (EFER.LMA) bit (which Intel calls "Host address-space size") if necessary.
* On VM-exit, VT-x sets both the host EFER.LMA and EFER.LME bit to this value. See assertion in hmR0VmxSaveHostMsrs().
if (HMVMX_IS_64BIT_HOST_MODE())
return rc;
bool fPendingIntr = false;
* If there are external interrupts pending but masked by the TPR value, instruct VT-x to cause a VM-exit when
* the guest lowers its TPR below the highest-priority pending interrupt and we can deliver the interrupt.
* If there are no external interrupts pending, set threshold to 0 to not cause a VM-exit. We will eventually deliver
if (fPendingIntr)
/* Bits 3:0 of the TPR threshold field correspond to bits 7:4 of the TPR (which is the Task-Priority Class). */
return rc;
* Instructions like STI and MOV SS inhibit interrupts till the next instruction completes. Check if we should
/* If inhibition is active, RIP & RFLAGS should've been accessed (i.e. read previously from the VMCS or from ring-3). */
* We can clear the inhibit force flag as even if we go back to the recompiler without executing guest code in
return uIntrState;
return rc;
Log4(("Load: VMX_VMCS_GUEST_RIP=%#RX64 fContextUseFlags=%#RX32\n", pMixedCtx->rip, HMCPU_CF_VALUE(pVCpu)));
return rc;
return rc;
/* Intel spec. 2.3.1 "System Flags and Fields in IA-32e Mode" claims the upper 32-bits of RFLAGS are reserved (MBZ).
* If we're emulating real-mode using Virtual 8086 mode, save the real-mode eflags so we can restore them on VM-exit.
* Modify the real-mode guest's eflags so that VT-x can run the real-mode guest code under Virtual 8086 mode.
pVCpu->hm.s.vmx.RealMode.Eflags.u32 = Eflags.u32; /* Save the original eflags of the real-mode guest. */
return rc;
return rc;
u32GuestCR0 |= X86_CR0_WP; /* Guest CPL 0 writes to its read-only pages should cause a #PF VM-exit. */
* Intel spec. 23.8 "Restrictions on VMX operation" mentions that CR0.NE bit must always be set on the first
bool fInterceptNM = false;
/* The guest should still get #NM exceptions when it expects it to, so we should not clear TS & MP bits here.
We're only concerned about -us- not intercepting #NMs when the guest-FPU is active. Not the guest itself! */
bool fInterceptMF = false;
fInterceptMF = true;
/* Finally, intercept all exceptions as we cannot directly inject them in real-mode, see hmR0VmxInjectEventVmcs(). */
fInterceptNM = true;
fInterceptMF = true;
if (fInterceptNM)
if (fInterceptMF)
#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
if (pVM->hm.s.vmx.fUnrestrictedGuest) /* Exceptions for unrestricted-guests for fixed CR0 bits (PE, PG). */
Log4(("Load: VMX_VMCS_GUEST_CR0=%#RX32 (uSetCR0=%#RX32 uZapCR0=%#RX32)\n", u32GuestCR0, uSetCR0, uZapCR0));
* CR0 is shared between host and guest along with a CR0 read shadow. Therefore, certain bits must not be changed
* by the guest because VT-x ignores saving/restoring them (namely CD, ET, NW) and for certain other bits
* we want to be notified immediately of guest CR0 changes (e.g. PG to update our shadow page tables).
if (fInterceptNM)
| X86_CR0_MP;
return rc;
/* Validate. See Intel spec. 28.2.2 "EPT Translation Mechanism" and 24.6.11 "Extended-Page-Table Pointer (EPTP)" */
AssertMsg( ((pVCpu->hm.s.vmx.HCPhysEPTP >> 3) & 0x07) == 3 /* Bits 3:5 (EPT page walk length - 1) must be 3. */
/* The guest's view of its CR3 is unblemished with Nested Paging when the guest is using paging or we
* The guest is not using paging, but the CPU (VT-x) has to. While the guest thinks it accesses physical memory
* If we're emulating real-mode using virtual-8086 mode, we want to redirect software interrupts to the 8086 program
* interrupt handler. Clear the VME bit (the interrupt redirection bitmap is already all 0, see hmR3InitFinalizeR0())
* The shadow paging modes and guest paging modes are different, the shadow is in accordance with the host
#ifdef VBOX_ENABLE_64_BITS_GUESTS
AssertFailed();
/* Setup CR4 mask. CR4 flags owned by the host, if the guest attempts to change them, that would cause a VM-exit. */
| X86_CR4_VMXE;
return rc;
return VINF_SUCCESS;
#ifdef VBOX_STRICT
Assert((pMixedCtx->dr[7] & (X86_DR7_MBZ_MASK | X86_DR7_RAZ_MASK)) == 0); /* Bits 63:32, 15, 14, 12, 11 are reserved. */
int rc;
bool fInterceptDB = false;
bool fInterceptMovDRx = false;
/* If the CPU supports the monitor trap flag, use it for single stepping in DBGF and avoid intercepting #DB. */
fInterceptDB = true;
if ( fInterceptDB
#if HC_ARCH_BITS == 32 && defined(VBOX_WITH_64_BITS_GUESTS) && !defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
fInterceptDB = true;
fInterceptMovDRx = true;
#if HC_ARCH_BITS == 32 && defined(VBOX_WITH_64_BITS_GUESTS) && !defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
#if HC_ARCH_BITS == 32 && defined(VBOX_WITH_64_BITS_GUESTS) && !defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
fInterceptMovDRx = true;
fInterceptDB = true;
if (fInterceptDB)
#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
if (fInterceptMovDRx)
return VINF_SUCCESS;
#ifdef VBOX_STRICT
/* NOTE: The reason we check for attribute value 0 and not just the unusable bit here is because hmR0VmxWriteSegmentReg()
* only updates the VMCS' copy of the value with the unusable bit and doesn't change the guest-context value. */
Assert(pCtx->cs.Attr.u && !(pCtx->cs.Attr.u & X86DESCATTR_UNUSABLE)); /** @todo is this really true even for 64-bit CS?!? */
if (HMVMX_IS_64BIT_HOST_MODE())
u32CSAttr = 0xf3; u32SSAttr = 0xf3; u32DSAttr = 0xf3; u32ESAttr = 0xf3; u32FSAttr = 0xf3; u32GSAttr = 0xf3;
AssertMsg((pCtx->cs.u64Base == (uint64_t)pCtx->cs.Sel << 4), ("CS base %#x %#x\n", pCtx->cs.u64Base, pCtx->cs.Sel));
if (HMVMX_IS_64BIT_HOST_MODE())
static int hmR0VmxWriteSegmentReg(PVMCPU pVCpu, uint32_t idxSel, uint32_t idxLimit, uint32_t idxBase,
* The way to differentiate between whether this is really a null selector or was just a selector loaded with 0 in
* real-mode is using the segment attributes. A selector loaded in real-mode with the value 0 is valid and usable in
* protected-mode and we should -not- mark it as an unusable segment. Both the recompiler & VT-x ensures NULL selectors
if (!u32Access)
/* Validate segment access rights. Refer to Intel spec. "26.3.1.2 Checks on Guest Segment Registers". */
("Access bit not set for usable segment. idx=%#x sel=%#x attr %#x\n", idxBase, pSelReg, pSelReg->Attr.u));
return rc;
#ifdef VBOX_WITH_REM
/* Signal that the recompiler must flush its code-cache as the guest -may- rewrite code it will later execute
rc = hmR0VmxWriteSegmentReg(pVCpu, VMX_VMCS16_GUEST_FIELD_CS, VMX_VMCS32_GUEST_CS_LIMIT, VMX_VMCS_GUEST_CS_BASE,
rc = hmR0VmxWriteSegmentReg(pVCpu, VMX_VMCS16_GUEST_FIELD_SS, VMX_VMCS32_GUEST_SS_LIMIT, VMX_VMCS_GUEST_SS_BASE,
rc = hmR0VmxWriteSegmentReg(pVCpu, VMX_VMCS16_GUEST_FIELD_DS, VMX_VMCS32_GUEST_DS_LIMIT, VMX_VMCS_GUEST_DS_BASE,
rc = hmR0VmxWriteSegmentReg(pVCpu, VMX_VMCS16_GUEST_FIELD_ES, VMX_VMCS32_GUEST_ES_LIMIT, VMX_VMCS_GUEST_ES_BASE,
rc = hmR0VmxWriteSegmentReg(pVCpu, VMX_VMCS16_GUEST_FIELD_FS, VMX_VMCS32_GUEST_FS_LIMIT, VMX_VMCS_GUEST_FS_BASE,
rc = hmR0VmxWriteSegmentReg(pVCpu, VMX_VMCS16_GUEST_FIELD_GS, VMX_VMCS32_GUEST_GS_LIMIT, VMX_VMCS_GUEST_GS_BASE,
#ifdef VBOX_STRICT
Log4(("Load: CS=%#RX16 Base=%#RX64 Limit=%#RX32 Attr=%#RX32\n", pMixedCtx->cs.Sel, pMixedCtx->cs.u64Base,
* using the interrupt redirection bitmap (all bits cleared to let the guest handle INT-n's) in the TSS.
Assert(PDMVmmDevHeapIsEnabled(pVM)); /* Guaranteed by HMR3CanExecuteGuest() -XXX- what about inner loop changes? */
/* We obtain it here every time as PCI regions could be reconfigured in the guest, changing the VMMDev base. */
DescAttr.u = 0;
u16Sel = 0;
|| (u32AccessRights & 0xf) == X86_SEL_TYPE_SYS_286_TSS_BUSY, ("TSS is not busy!? %#x\n", u32AccessRights));
AssertMsg(!(u32AccessRights & X86DESCATTR_UNUSABLE), ("TR unusable bit is not clear!? %#x\n", u32AccessRights));
return VINF_SUCCESS;
hmR0VmxAddAutoLoadStoreMsr(pVCpu, MSR_K8_SF_MASK, pMixedCtx->msrSFMASK, false /* fUpdateHostMsr */);
hmR0VmxAddAutoLoadStoreMsr(pVCpu, MSR_K8_KERNEL_GS_BASE, pMixedCtx->msrKERNELGSBASE, false /* fUpdateHostMsr */);
# ifdef DEBUG
int rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_SYSENTER_CS, pMixedCtx->SysEnter.cs); AssertRCReturn(rc, rc);
int rc = VMXWriteVmcsGstN(VMX_VMCS_GUEST_SYSENTER_EIP, pMixedCtx->SysEnter.eip); AssertRCReturn(rc, rc);
int rc = VMXWriteVmcsGstN(VMX_VMCS_GUEST_SYSENTER_ESP, pMixedCtx->SysEnter.esp); AssertRCReturn(rc, rc);
return VINF_SUCCESS;
return VINF_SUCCESS;
#ifndef VBOX_ENABLE_64_BITS_GUESTS
if (pVCpu->hm.s.vmx.pfnStartVM != NULL) /* Very first entry would have saved host-state already, ignore it. */
/* Currently, all mode changes sends us back to ring-3, so these should be set. See @bugref{6944}. */
AssertMsg(HMCPU_CF_IS_SET(pVCpu, HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_EXIT_CTLS | HM_CHANGED_VMX_ENTRY_CTLS),
if (pVCpu->hm.s.vmx.pfnStartVM != NULL) /* Very first entry would have saved host-state already, ignore it. */
/* Currently, all mode changes sends us back to ring-3, so these should be set. See @bugref{6944}. */
AssertMsg(HMCPU_CF_IS_SET(pVCpu, HM_CHANGED_HOST_CONTEXT | HM_CHANGED_VMX_EXIT_CTLS | HM_CHANGED_VMX_ENTRY_CTLS),
return VINF_SUCCESS;
* 64-bit Windows uses XMM registers in the kernel as the Microsoft compiler expresses floating-point operations
* using SSE instructions. Some XMM registers (XMM6-XMM15) are callee-saved and thus the need for this XMM wrapper.
* Refer MSDN docs. "Configuring Programs for 64-bit / x64 Software Conventions / Register Usage" for details.
#ifdef VBOX_WITH_KERNEL_USING_XMM
return HMR0VMXStartVMWrapXMM(fResumeVM, pCtx, &pVCpu->hm.s.vmx.VMCSCache, pVM, pVCpu, pVCpu->hm.s.vmx.pfnStartVM);
static void hmR0VmxReportWorldSwitchError(PVM pVM, PVMCPU pVCpu, int rcVMRun, PCPUMCTX pCtx, PVMXTRANSIENT pVmxTransient)
switch (rcVMRun)
AssertFailed();
#ifdef VBOX_STRICT
if (HMVMX_IS_64BIT_HOST_MODE())
#if HC_ARCH_BITS == 32 && defined(VBOX_ENABLE_64_BITS_GUESTS) && !defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
#ifndef VMX_USE_CACHED_VMCS_ACCESSES
#ifdef VBOX_STRICT
switch (idxField)
case VMX_VMCS_GUEST_RIP:
case VMX_VMCS_GUEST_RSP:
case VMX_VMCS_GUEST_GDTR_BASE:
case VMX_VMCS_GUEST_IDTR_BASE:
case VMX_VMCS_GUEST_CS_BASE:
case VMX_VMCS_GUEST_DS_BASE:
case VMX_VMCS_GUEST_ES_BASE:
case VMX_VMCS_GUEST_FS_BASE:
case VMX_VMCS_GUEST_GS_BASE:
case VMX_VMCS_GUEST_SS_BASE:
case VMX_VMCS_GUEST_LDTR_BASE:
case VMX_VMCS_GUEST_TR_BASE:
case VMX_VMCS_GUEST_CR3:
switch (idxField)
VMMR0DECL(int) VMXR0Execute64BitsHandler(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, HM64ON32OP enmOp, uint32_t cbParam,
Assert(pVCpu->hm.s.vmx.VMCSCache.Write.cValidEntries <= RT_ELEMENTS(pVCpu->hm.s.vmx.VMCSCache.Write.aField));
Assert(pVCpu->hm.s.vmx.VMCSCache.Read.cValidEntries <= RT_ELEMENTS(pVCpu->hm.s.vmx.VMCSCache.Read.aField));
#ifdef VBOX_STRICT
/* Clear VMCS. Marking it inactive, clearing implementation-specific data and writing VMCS data back to memory. */
VMXDisable();
rc = pVM->hm.s.pfnHost32ToGuest64R0(pVM, RT_OFFSETOF(VM, aCpus[pVCpu->idCpu].cpum) - RT_OFFSETOF(VM, cpum));
return rc2;
return rc;
DECLASM(int) VMXR0SwitcherStartVM64(RTHCUINT fResume, PCPUMCTX pCtx, PVMCSCACHE pCache, PVM pVM, PVMCPU pVCpu)
#ifdef VBOX_WITH_CRASHDUMP_MAGIC
aParam[3] = (uint32_t)(pVCpu->hm.s.vmx.HCPhysVmcs >> 32); /* Param 2: VMCS physical address - Hi. */
#ifdef VBOX_WITH_CRASHDUMP_MAGIC
#ifdef VBOX_WITH_CRASHDUMP_MAGIC
AssertMsg(pCache->TestIn.HCPhysCpuPage == HCPhysCpuPage, ("%RHp vs %RHp\n", pCache->TestIn.HCPhysCpuPage, HCPhysCpuPage));
AssertMsg(pCache->TestIn.HCPhysVmcs == pVCpu->hm.s.vmx.HCPhysVmcs, ("%RHp vs %RHp\n", pCache->TestIn.HCPhysVmcs,
AssertMsg(pCache->TestIn.HCPhysVmcs == pCache->TestOut.HCPhysVmcs, ("%RHp vs %RHp\n", pCache->TestIn.HCPhysVmcs,
AssertMsg(pCache->TestIn.pCache == pCache->TestOut.pCache, ("%RGv vs %RGv\n", pCache->TestIn.pCache,
("%RGv vs %RGv\n", pCache->TestIn.pCache, VM_RC_ADDR(pVM, &pVM->aCpus[pVCpu->idCpu].hm.s.vmx.VMCSCache)));
return rc;
++cReadFields; \
/* 64-bit guest-state fields; unused as we use two 32-bit VMREADs for these 64-bit fields (using "FULL" and "HIGH" fields). */
AssertMsg(cReadFields == VMX_VMCS_MAX_NESTED_PAGING_CACHE_IDX, ("cReadFields=%u expected %u\n", cReadFields,
AssertMsg(cReadFields == VMX_VMCS_MAX_CACHE_IDX, ("cReadFields=%u expected %u\n", cReadFields, VMX_VMCS_MAX_CACHE_IDX));
return VINF_SUCCESS;
int rc;
switch (idxField)
* These fields do not have high and low parts. Queue up the VMWRITE by using the VMCS write-cache (for 64-bit
* values). When we switch the host to 64-bit mode for running 64-bit guests, these VMWRITEs get executed then.
case VMX_VMCS_GUEST_CR3:
case VMX_VMCS_GUEST_ES_BASE:
case VMX_VMCS_GUEST_CS_BASE:
case VMX_VMCS_GUEST_SS_BASE:
case VMX_VMCS_GUEST_DS_BASE:
case VMX_VMCS_GUEST_FS_BASE:
case VMX_VMCS_GUEST_GS_BASE:
case VMX_VMCS_GUEST_LDTR_BASE:
case VMX_VMCS_GUEST_TR_BASE:
case VMX_VMCS_GUEST_GDTR_BASE:
case VMX_VMCS_GUEST_IDTR_BASE:
case VMX_VMCS_GUEST_RSP:
case VMX_VMCS_GUEST_RIP:
AssertMsgFailed(("VMXWriteVmcs64Ex: Invalid field %#RX32 (pVCpu=%p u64Val=%#RX64)\n", idxField, pVCpu, u64Val));
return rc;
return VINF_SUCCESS;
return VINF_SUCCESS;
#endif /* HC_ARCH_BITS == 32 && defined(VBOX_ENABLE_64_BITS_GUESTS) && !defined(VBOX_WITH_HYBRID_32BIT_KERNEL) */
bool fOffsettedTsc = false;
uint64_t cTicksToDeadline = TMCpuTickGetDeadlineAndTscOffset(pVCpu, &fOffsettedTsc, &pVCpu->hm.s.vmx.u64TSCOffset);
if (fOffsettedTsc)
/* Note: VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT takes precedence over TSC_OFFSET, applies to RDTSCP too. */
switch (uVector)
case X86_XCPT_GP:
case X86_XCPT_SS:
case X86_XCPT_NP:
case X86_XCPT_TS:
case X86_XCPT_DE:
DECLINLINE(void) hmR0VmxSetPendingEvent(PVMCPU pVCpu, uint32_t u32IntInfo, uint32_t cbInstr, uint32_t u32ErrCode,
hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
static int hmR0VmxCheckExitDueToEventDelivery(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
#ifdef VBOX_STRICT
* Ignore software interrupts (INT n), software exceptions (#BP, #OF) and privileged software exception
* interruption-information will not be valid and we end up here. In such cases, it is sufficient to reflect the
switch (enmReflect)
case VMXREFLECTXCPT_XCPT:
/* If uExitVector is #PF, CR2 value will be updated from the VMCS if it's a guest #PF. See hmR0VmxExitXcptPF(). */
hmR0VmxSetPendingEvent(pVCpu, VMX_ENTRY_INT_INFO_FROM_EXIT_IDT_INFO(pVmxTransient->uIdtVectoringInfo),
case VMXREFLECTXCPT_DF:
Log4(("IDT: vcpu[%RU32] Pending vectoring #DF %#RX64 uIdtVector=%#x uExitVector=%#x\n", pVCpu->idCpu,
case VMXREFLECTXCPT_TF:
Log4(("IDT: vcpu[%RU32] Pending vectoring triple-fault uIdt=%#x uExit=%#x\n", pVCpu->idCpu, uIdtVector,
uExitVector));
return rc;
* While in the middle of saving guest-CR0, we could get preempted and re-invoked from the preemption hook,
return VINF_SUCCESS;
return rc;
return rc;
return rc;
if (pVCpu->hm.s.vmx.RealMode.fRealOnV86Active) /* Undo our real-on-v86-mode changes to eflags if necessary. */
return VINF_SUCCESS;
return rc;
if (!uIntrState)
/* Nothing to do for now until we make use of different guest-CPU activity state. Just update the flag. */
return VINF_SUCCESS;
return rc;
/* Since this can be called from our preemption hook it's safer to make the guest-MSRs update non-preemptible. */
/* Doing the check here ensures we don't overwrite already-saved guest MSRs from a preemption hook. */
return VINF_SUCCESS;
return VINF_SUCCESS;
AssertFailed();
return VERR_HM_UNEXPECTED_LD_ST_MSR;
return VINF_SUCCESS;
/* Guest CR3. Only changes with Nested Paging. This must be done -after- saving CR0 and CR4 from the guest! */
if (CPUMIsGuestInPAEModeEx(pMixedCtx)) /* Reads CR0, CR4 and EFER MSR (EFER is always up-to-date). */
/* Set the force flag to inform PGM about it when necessary. It is cleared by PGMGstUpdatePaePdpes(). */
* Consider this scenario: VM-exit -> VMMRZCallRing3Enable() -> do stuff that causes a longjmp -> hmR0VmxCallRing3Callback()
* -> VMMRZCallRing3Disable() -> hmR0VmxSaveGuestState() -> Set VMCPU_FF_HM_UPDATE_CR3 pending -> return from the longjmp
* The reason for such complicated handling is because VM-exits that call into PGM expect CR3 to be up-to-date and thus
* if any CR3-saves -before- the VM-exit (longjmp) postponed the CR3 update via the force-flag, any VM-exit handler that
* calls into PGM when it re-saves CR3 will end up here and we call PGMUpdateCR3(). This is why the code below should
* The longjmp exit path can't check these CR3 force-flags and call code that takes a lock again. We cover for it here.
return rc;
DECLINLINE(int) hmR0VmxReadSegmentReg(PVMCPU pVCpu, uint32_t idxSel, uint32_t idxLimit, uint32_t idxBase, uint32_t idxAccess,
Assert(idxSel != VMX_VMCS16_GUEST_FIELD_TR); /* TR is the only selector that can never be unusable. */
/* Masking off: X86DESCATTR_P, X86DESCATTR_LIMIT_HIGH, and X86DESCATTR_AVL. The latter two are really irrelevant. */
Log4(("hmR0VmxReadSegmentReg: Unusable idxSel=%#x attr=%#x -> %#x\n", idxSel, u32Val, pSelReg->Attr.u));
#ifdef DEBUG_bird
return VINF_SUCCESS;
#ifdef VMX_USE_CACHED_VMCS_ACCESSES
return VINF_SUCCESS;
/* For real-mode emulation using virtual-8086 mode we have the fake TSS (pRealModeTSS) in TR, don't save the fake one. */
return rc;
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestRipRspRflags failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestControlRegs failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestSegmentRegs failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestTableRegs failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestSysenterMsrs failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestLazyMsrs failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestAutoLoadStoreMsrs failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestActivityState failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestApicState failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
return rc;
return rc2;
int rc2 = RT_UNLIKELY(VM_FF_IS_PENDING(pVM, VM_FF_PGM_NO_MEMORY)) ? VINF_EM_NO_MEMORY : VINF_EM_RAW_TO_R3;
return rc2;
return VINF_EM_PENDING_REQUEST;
return VINF_PGM_POOL_FLUSH_PENDING;
return VINF_EM_RAW_TO_R3;
return VINF_SUCCESS;
/* Refer Intel spec. 24.8.3 "VM-entry Controls for Event Injection" for the format of u32IntInfo. */
switch (uVector)
case X86_XCPT_BP:
case X86_XCPT_OF:
case X86_XCPT_PF:
case X86_XCPT_DF:
case X86_XCPT_TS:
case X86_XCPT_NP:
case X86_XCPT_SS:
case X86_XCPT_GP:
case X86_XCPT_AC:
Log4(("TRPM->HM event: u32IntInfo=%#RX32 enmTrpmEvent=%d cbInstr=%u uErrCode=%#RX32 GCPtrFaultAddress=%#RGv\n",
Assert(TRPMQueryTrap(pVCpu, NULL /* pu8TrapNo */, NULL /* pEnmType */) == VERR_TRPM_NO_ACTIVE_TRAP);
switch (uVectorType)
if (fErrorCodeValid)
* If you modify code here, make sure to check whether hmR0VmxCallRing3Callback() needs to be updated too.
if ( fSaveGuestState
if (!fSaveGuestState)
#ifdef VBOX_STRICT
Log4Func(("Restoring Host State: fRestoreHostFlags=%#RX32 HostCpuId=%u\n", pVCpu->hm.s.vmx.fRestoreHostFlags, idCpu));
if (!fSaveGuestState)
/* Update auto-load/store host MSRs values when we re-enter VT-x (as we could be on a different CPU). */
return VINF_SUCCESS;
/* When thread-context hooks are used, we can avoid doing the leave again if we had been preempted before
* If you modify code here, make sure to check whether hmR0VmxCallRing3Callback() needs to be updated too.
* (longjmp/exit-to-r3) in VT-x which is not efficient. */
return rc;
* executing outside HM (recompiler/IEM).
/* Please, no longjumps here (any logging shouldn't flush jump back to ring-3). NO LOGGING BEFORE THIS POINT! */
/* We need to do this only while truly exiting the "inner loop" back to ring-3 and -not- for any longjmp to ring3. */
/* On our way back from ring-3 reload the guest state if there is a possibility of it being changed. */
return rc;
* If you modify code here, make sure to check whether hmR0VmxLeave() and hmR0VmxLeaveSession() needs
* to be updated too. This is a stripped down version which gets out ASAP trying to not trigger any assertion.
return VINF_SUCCESS;
Log4(("hmR0VmxCallRing3Callback->hmR0VmxLongJmpToRing3 pVCpu=%p idCpu=%RU32\n enmOperation=%d", pVCpu, pVCpu->idCpu,
enmOperation));
return VINF_SUCCESS;
if (RT_LIKELY(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_INT_WINDOW_EXIT))
} /* else we will deliver interrupts whenever the guest exits next and is in a state to receive events. */
Assert( !(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_NMI) /* We don't support block-by-NMI and SMI yet.*/
Assert(!fBlockSti || pMixedCtx->eflags.Bits.u1IF); /* Cannot set block-by-STI when interrupts are disabled. */
if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INTERRUPT_NMI)) /* NMI. NMIs take priority over regular interrupts . */
/* On some CPUs block-by-STI also blocks NMIs. See Intel spec. 26.3.1.5 "Checks On Guest Non-Register State". */
if ( !fBlockMovSS
&& !fBlockSti)
/* On some CPUs block-by-STI also blocks NMIs. See Intel spec. 26.3.1.5 "Checks On Guest Non-Register State". */
hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddres */);
* Check if the guest can receive external interrupts (PIC/APIC). Once we do PDMGetInterrupt() we -must- deliver
* the interrupt ASAP. We must not execute any guest code until we inject the interrupt which is why it is
if ( !fBlockInt
&& !fBlockSti
&& !fBlockMovSS)
hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrfaultAddress */);
if (pMixedCtx->eflags.Bits.u1TF) /* We don't have any IA32_DEBUGCTL MSR for guests. Treat as all bits 0. */
int rc = VMXWriteVmcs32(VMX_VMCS_GUEST_PENDING_DEBUG_EXCEPTIONS, VMX_VMCS_GUEST_DEBUG_EXCEPTIONS_BS);
Assert( !(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_NMI) /* We don't support block-by-NMI and SMI yet.*/
Assert(!fBlockSti || pMixedCtx->eflags.Bits.u1IF); /* Cannot set block-by-STI when interrupts are disabled. */
* VM-exit in situations where we previously setup interrupt-window exiting but got other VM-exits and
Assert(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_INT_WINDOW_EXIT);
Log4(("Injecting pending event vcpu[%RU32] u64IntInfo=%#RX64 Type=%#x\n", pVCpu->idCpu, pVCpu->hm.s.Event.u64IntInfo,
rc = hmR0VmxInjectEventVmcs(pVCpu, pMixedCtx, pVCpu->hm.s.Event.u64IntInfo, pVCpu->hm.s.Event.cbInstr,
#ifdef VBOX_WITH_STATISTICS
if ( fBlockSti
|| fBlockMovSS)
* The pending-debug exceptions field is cleared on all VM-exits except VMX_EXIT_TPR_BELOW_THRESHOLD,
* We are single-stepping in the hypervisor debugger using EFLAGS.TF. Clear interrupt inhibition as setting the
Assert(!(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.VmxProcCtls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_MONITOR_TRAP_FLAG));
uIntrState = 0;
* There's no need to clear the VM entry-interruption information field here if we're not injecting anything.
* VT-x clears the valid bit on every VM-exit. See Intel spec. 24.8.3 "VM-Entry Controls for Event Injection".
return rc;
hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
return hmR0VmxInjectEventVmcs(pVCpu, pMixedCtx, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */,
hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
DECLINLINE(int) hmR0VmxInjectXcptGP(PVMCPU pVCpu, PCPUMCTX pMixedCtx, bool fErrorCodeValid, uint32_t u32ErrorCode,
if (fErrorCodeValid)
return hmR0VmxInjectEventVmcs(pVCpu, pMixedCtx, u32IntInfo, 0 /* cbInstr */, u32ErrorCode, 0 /* GCPtrFaultAddress */,
hmR0VmxSetPendingEvent(pVCpu, u32IntInfo, 0 /* cbInstr */, u32ErrorCode, 0 /* GCPtrFaultAddress */);
DECLINLINE(void) hmR0VmxSetPendingIntN(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint16_t uVector, uint32_t cbInstr)
* The stack limit is 0xffff in real-on-virtual 8086 mode. Real-mode with weird stack limits cannot be run in
return VINF_EM_RESET;
int rc = PGMPhysSimpleWriteGCPhys(pVM, pMixedCtx->ss.u64Base + pMixedCtx->sp, &uValue, sizeof(uint16_t));
return rc;
static int hmR0VmxInjectEventVmcs(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint64_t u64IntInfo, uint32_t cbInstr,
/* Intel spec. 24.8.3 "VM-Entry Controls for Event Injection" specifies the interruption-information field to be 32-bits. */
#ifdef VBOX_STRICT
switch (uVector)
case X86_XCPT_PF:
case X86_XCPT_DF:
case X86_XCPT_TS:
case X86_XCPT_NP:
case X86_XCPT_SS:
case X86_XCPT_GP:
case X86_XCPT_AC:
* Hardware interrupts & exceptions cannot be delivered through the software interrupt redirection bitmap to the real
* See Intel spec. 20.3 "Interrupt and Exception handling in Virtual-8086 Mode" for interrupt & exception classes.
return VINF_EM_RESET;
/* If we're injecting an interrupt/exception with no valid IDT entry, inject a general-protection fault. */
/* No error codes for exceptions in real-mode. See Intel spec. 20.1.4 "Interrupt and Exception Handling" */
return hmR0VmxInjectXcptGP(pVCpu, pMixedCtx, false /* fErrCodeValid */, 0 /* u32ErrCode */, puIntrState);
Log4(("Injecting real-mode: u32IntInfo=%#x u32ErrCode=%#x instrlen=%#x\n", u32IntInfo, u32ErrCode, cbInstr));
return rc;
* For unrestricted execution enabled CPUs running real-mode guests, we must not set the deliver-error-code bit.
Assert(VMX_EXIT_INTERRUPTION_INFO_IS_VALID(u32IntInfo)); /* Bit 31 (Valid bit) must be set by caller. */
Log4(("Injecting vcpu[%RU32] u32IntInfo=%#x u32ErrCode=%#x cbInstr=%#x pMixedCtx->uCR2=%#RX64\n", pVCpu->idCpu,
return rc;
int rc;
#ifdef VBOX_STRICT
#ifdef VBOX_STRICT
return VERR_VMX_X86_CR4_VMXE_CLEARED;
return rc;
return VINF_SUCCESS;
switch (enmEvent)
/* Do -not- save guest-state here as we might already be in the middle of saving it (esp. bad if we are
case RTTHREADCTXEVENT_RESUMED:
return VINF_SUCCESS;
AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveHostControlRegisters failed! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveHostSegmentRegisters failed! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveHostMsrs failed! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
return rc;
/* Save the host state here while entering HM context. When thread-context hooks are used, we might get preempted
and have to resave the host state but most of the time we won't be, so do it here before we disable interrupts. */
#ifdef LOG_ENABLED
AssertLogRelMsgRCReturn(rc, ("hmR0VmxSetupVMRunHandler! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
/* This needs to be done after hmR0VmxSetupVMRunHandler() as changing pfnStartVM may require VM-entry control updates. */
AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadGuestEntryCtls! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
/* This needs to be done after hmR0VmxSetupVMRunHandler() as changing pfnStartVM may require VM-exit control updates. */
AssertLogRelMsgRCReturn(rc, ("hmR0VmxSetupExitCtls failed! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadGuestActivityState! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadGuestCR3AndCR4: rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
/* Assumes pMixedCtx->cr0 is up-to-date (strict builds require CR0 for segment register validation checks). */
AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadGuestSegmentRegs: rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadSharedMsrs! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadGuestApicState! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
* Loading Rflags here is fine, even though Rflags.TF might depend on guest debug state (which is not loaded here).
AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadGuestRipRspRflags! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
#ifdef LOG_ENABLED
if (!fCallerDisabledLogFlush)
return rc;
#ifdef HMVMX_SYNC_FULL_GUEST_STATE
/* All the guest state bits should be loaded except maybe the host context and/or the shared host/guest bits. */
* and clearing the common-state (TRPM/forceflags), we must undo those changes
static int hmR0VmxPreRunGuest(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
return rc;
#ifndef IEM_VERIFICATION_MODE_FULL
/* Setup the Virtualized APIC accesses. pMixedCtx->msrApicBase is always up-to-date. It's not part of the VMCS. */
/* Map the HC APIC-access page into the GC space, this also updates the shadow page tables if necessary. */
rc = IOMMMIOMapMMIOHCPage(pVM, pVCpu, GCPhysApicBase, pVM->hm.s.vmx.HCPhysApicAccess, X86_PTE_RW | X86_PTE_P);
* Evaluate events as pending-for-injection into the guest. Toggling of force-flags here is safe as long as
* we update TRPM on premature exits to ring-3 before executing guest code. We must NOT restore the force-flags.
* Event injection may take locks (currently the PGM lock for real-on-v86 case) and thus needs to be done with
* longjmps or interrupts + preemption enabled. Event injection might also result in triple-faulting the VM.
return rc;
* Asserts() will still longjmp to ring-3 (but won't return), which is intentional, better than a kernel panic.
* We disable interrupts so that we don't miss any interrupts that would flag preemption (IPI/timers etc.)
* when thread-context hooks aren't used and we've been running with preemption disabled for a while.
* We need to check for force-flags that could've possible been altered since we last checked them (e.g.
* We also check a couple of other force-flags as a last opportunity to get the EMT back to ring-3 before
return VINF_EM_RAW_TO_R3;
return VINF_EM_RAW_INTERRUPT;
return VINF_SUCCESS;
static void hmR0VmxPreRunGuestCommitted(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
#ifdef HMVMX_ALWAYS_SWAP_FPU_STATE
#if HC_ARCH_BITS == 32 && defined(VBOX_WITH_64_BITS_GUESTS) && !defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
ASMAtomicWriteBool(&pVCpu->hm.s.fCheckedTLBFlush, true); /* Used for TLB-shootdowns, set this across the world switch. */
pVCpu->hm.s.vmx.LastError.idCurrentCpu = idCurrentCpu; /* Update the error reporting info. with the current host CPU. */
/* Finally, mark that all host MSR values are updated so we don't redo it without leaving VT-x. See @bugref{6956}. */
#ifdef VBOX_STRICT
static void hmR0VmxPostRunGuest(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient, int rcVMRun)
ASMAtomicWriteBool(&pVCpu->hm.s.fCheckedTLBFlush, false); /* See HMInvalidatePageOnAllVCpus(): used for TLB-shootdowns. */
ASMAtomicIncU32(&pVCpu->hm.s.cWorldSwitchExits); /* Initialized in vmR3CreateUVM(): used for TLB-shootdowns. */
#ifdef HMVMX_ALWAYS_SWAP_FPU_STATE
pVCpu->hm.s.vmx.fRestoreHostFlags |= VMX_RESTORE_HOST_REQUIRED; /* Host state messed up by VT-x, we must restore. */
pVCpu->hm.s.vmx.uVmcsState |= HMVMX_VMCS_STATE_LAUNCHED; /* Use VMRESUME instead of VMLAUNCH in the next run. */
Log4(("VM-entry failure: pVCpu=%p idCpu=%RU32 rcVMRun=%Rrc fVMEntryFailed=%RTbool\n", pVCpu, pVCpu->idCpu, rcVMRun,
* If the TPR was raised by the guest, it wouldn't cause a VM-exit immediately. Instead we sync the TPR lazily whenever
* we eventually get a VM-exit for any reason. This maybe expensive as PDMApicSetTPR() can longjmp to ring-3 and which is
* why it's done here as it's easier and no less efficient to deal with it here than making hmR0VmxSaveGuestState()
for (;; cLoops++)
/* The guest-CPU context is now outdated, 'pCtx' is to be treated as 'pMixedCtx' from this point on!!! */
return rc;
#ifdef HMVMX_USE_FUNCTION_TABLE
return rc;
for (;; cLoops++)
/* The guest-CPU context is now outdated, 'pCtx' is to be treated as 'pMixedCtx' from this point on!!! */
return rc;
#ifdef HMVMX_USE_FUNCTION_TABLE
return rc;
int rc;
return rc;
#ifndef HMVMX_USE_FUNCTION_TABLE
DECLINLINE(int) hmR0VmxHandleExit(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient, uint32_t rcReason)
#ifdef DEBUG_ramshankar
# define SVVMCS() do { int rc2 = hmR0VmxSaveGuestState(pVCpu, pMixedCtx); AssertRC(rc2); } while (0)
int rc;
switch (rcReason)
case VMX_EXIT_EPT_MISCONFIG: /* SVVMCS(); */ rc = hmR0VmxExitEptMisconfig(pVCpu, pMixedCtx, pVmxTransient); /* LDVMCS(); */ break;
case VMX_EXIT_EPT_VIOLATION: /* SVVMCS(); */ rc = hmR0VmxExitEptViolation(pVCpu, pMixedCtx, pVmxTransient); /* LDVMCS(); */ break;
case VMX_EXIT_IO_INSTR: /* SVVMCS(); */ rc = hmR0VmxExitIoInstr(pVCpu, pMixedCtx, pVmxTransient); /* LDVMCS(); */ break;
case VMX_EXIT_CPUID: /* SVVMCS(); */ rc = hmR0VmxExitCpuid(pVCpu, pMixedCtx, pVmxTransient); /* LDVMCS(); */ break;
case VMX_EXIT_RDTSC: /* SVVMCS(); */ rc = hmR0VmxExitRdtsc(pVCpu, pMixedCtx, pVmxTransient); /* LDVMCS(); */ break;
case VMX_EXIT_RDTSCP: /* SVVMCS(); */ rc = hmR0VmxExitRdtscp(pVCpu, pMixedCtx, pVmxTransient); /* LDVMCS(); */ break;
case VMX_EXIT_APIC_ACCESS: /* SVVMCS(); */ rc = hmR0VmxExitApicAccess(pVCpu, pMixedCtx, pVmxTransient); /* LDVMCS(); */ break;
case VMX_EXIT_XCPT_OR_NMI: /* SVVMCS(); */ rc = hmR0VmxExitXcptOrNmi(pVCpu, pMixedCtx, pVmxTransient); /* LDVMCS(); */ break;
case VMX_EXIT_MOV_CRX: /* SVVMCS(); */ rc = hmR0VmxExitMovCRx(pVCpu, pMixedCtx, pVmxTransient); /* LDVMCS(); */ break;
case VMX_EXIT_EXT_INT: /* SVVMCS(); */ rc = hmR0VmxExitExtInt(pVCpu, pMixedCtx, pVmxTransient); /* LDVMCS(); */ break;
case VMX_EXIT_INT_WINDOW: /* SVVMCS(); */ rc = hmR0VmxExitIntWindow(pVCpu, pMixedCtx, pVmxTransient); /* LDVMCS(); */ break;
case VMX_EXIT_MWAIT: /* SVVMCS(); */ rc = hmR0VmxExitMwait(pVCpu, pMixedCtx, pVmxTransient); /* LDVMCS(); */ break;
case VMX_EXIT_MONITOR: /* SVVMCS(); */ rc = hmR0VmxExitMonitor(pVCpu, pMixedCtx, pVmxTransient); /* LDVMCS(); */ break;
case VMX_EXIT_TASK_SWITCH: /* SVVMCS(); */ rc = hmR0VmxExitTaskSwitch(pVCpu, pMixedCtx, pVmxTransient); /* LDVMCS(); */ break;
case VMX_EXIT_PREEMPT_TIMER: /* SVVMCS(); */ rc = hmR0VmxExitPreemptTimer(pVCpu, pMixedCtx, pVmxTransient); /* LDVMCS(); */ break;
case VMX_EXIT_RDMSR: /* SVVMCS(); */ rc = hmR0VmxExitRdmsr(pVCpu, pMixedCtx, pVmxTransient); /* LDVMCS(); */ break;
case VMX_EXIT_WRMSR: /* SVVMCS(); */ rc = hmR0VmxExitWrmsr(pVCpu, pMixedCtx, pVmxTransient); /* LDVMCS(); */ break;
case VMX_EXIT_MOV_DRX: /* SVVMCS(); */ rc = hmR0VmxExitMovDRx(pVCpu, pMixedCtx, pVmxTransient); /* LDVMCS(); */ break;
case VMX_EXIT_TPR_BELOW_THRESHOLD: /* SVVMCS(); */ rc = hmR0VmxExitTprBelowThreshold(pVCpu, pMixedCtx, pVmxTransient); /* LDVMCS(); */ break;
case VMX_EXIT_HLT: /* SVVMCS(); */ rc = hmR0VmxExitHlt(pVCpu, pMixedCtx, pVmxTransient); /* LDVMCS(); */ break;
case VMX_EXIT_INVD: /* SVVMCS(); */ rc = hmR0VmxExitInvd(pVCpu, pMixedCtx, pVmxTransient); /* LDVMCS(); */ break;
case VMX_EXIT_INVLPG: /* SVVMCS(); */ rc = hmR0VmxExitInvlpg(pVCpu, pMixedCtx, pVmxTransient); /* LDVMCS(); */ break;
case VMX_EXIT_RSM: /* SVVMCS(); */ rc = hmR0VmxExitRsm(pVCpu, pMixedCtx, pVmxTransient); /* LDVMCS(); */ break;
case VMX_EXIT_MTF: /* SVVMCS(); */ rc = hmR0VmxExitMtf(pVCpu, pMixedCtx, pVmxTransient); /* LDVMCS(); */ break;
case VMX_EXIT_PAUSE: /* SVVMCS(); */ rc = hmR0VmxExitPause(pVCpu, pMixedCtx, pVmxTransient); /* LDVMCS(); */ break;
case VMX_EXIT_XDTR_ACCESS: /* SVVMCS(); */ rc = hmR0VmxExitXdtrAccess(pVCpu, pMixedCtx, pVmxTransient); /* LDVMCS(); */ break;
case VMX_EXIT_TR_ACCESS: /* SVVMCS(); */ rc = hmR0VmxExitXdtrAccess(pVCpu, pMixedCtx, pVmxTransient); /* LDVMCS(); */ break;
case VMX_EXIT_WBINVD: /* SVVMCS(); */ rc = hmR0VmxExitWbinvd(pVCpu, pMixedCtx, pVmxTransient); /* LDVMCS(); */ break;
case VMX_EXIT_XSETBV: /* SVVMCS(); */ rc = hmR0VmxExitXsetbv(pVCpu, pMixedCtx, pVmxTransient); /* LDVMCS(); */ break;
case VMX_EXIT_RDRAND: /* SVVMCS(); */ rc = hmR0VmxExitRdrand(pVCpu, pMixedCtx, pVmxTransient); /* LDVMCS(); */ break;
case VMX_EXIT_INVPCID: /* SVVMCS(); */ rc = hmR0VmxExitInvpcid(pVCpu, pMixedCtx, pVmxTransient); /* LDVMCS(); */ break;
case VMX_EXIT_GETSEC: /* SVVMCS(); */ rc = hmR0VmxExitGetsec(pVCpu, pMixedCtx, pVmxTransient); /* LDVMCS(); */ break;
case VMX_EXIT_RDPMC: /* SVVMCS(); */ rc = hmR0VmxExitRdpmc(pVCpu, pMixedCtx, pVmxTransient); /* LDVMCS(); */ break;
case VMX_EXIT_ERR_INVALID_GUEST_STATE: rc = hmR0VmxExitErrInvalidGuestState(pVCpu, pMixedCtx, pVmxTransient); break;
case VMX_EXIT_ERR_MACHINE_CHECK: rc = hmR0VmxExitErrMachineCheck(pVCpu, pMixedCtx, pVmxTransient); break;
case VMX_EXIT_VMCALL:
case VMX_EXIT_VMCLEAR:
case VMX_EXIT_VMLAUNCH:
case VMX_EXIT_VMPTRLD:
case VMX_EXIT_VMPTRST:
case VMX_EXIT_VMREAD:
case VMX_EXIT_VMRESUME:
case VMX_EXIT_VMWRITE:
case VMX_EXIT_VMXOFF:
case VMX_EXIT_VMXON:
case VMX_EXIT_INVEPT:
case VMX_EXIT_INVVPID:
case VMX_EXIT_VMFUNC:
return rc;
#ifdef DEBUG
# define HMVMX_ASSERT_PREEMPT_CPUID_VAR() \
# define HMVMX_ASSERT_PREEMPT_CPUID() \
RTCPUID const idAssertCpuNow = RTThreadPreemptIsEnabled(NIL_RTTHREAD) ? NIL_RTCPUID : RTMpCpuId(); \
# define HMVMX_VALIDATE_EXIT_HANDLER_PARAMS() \
Log4Func(("vcpu[%RU32] -v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v\n", pVCpu->idCpu)); \
# define HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS() \
# define HMVMX_VALIDATE_EXIT_HANDLER_PARAMS() \
# define HMVMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS() do { } while (0)
DECLINLINE(int) hmR0VmxAdvanceGuestRip(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
* Deliver a debug exception to the guest if it is single-stepping. Don't directly inject a #DB but use the
return rc;
int rc;
if (fUnrestrictedGuest)
if ( !fUnrestrictedGuest
#ifdef VBOX_STRICT
bool const fLongModeGuest = RT_BOOL(pVCpu->hm.s.vmx.u32EntryCtls & VMX_VMCS_CTRL_ENTRY_IA32E_MODE_GUEST);
if (HMVMX_IS_64BIT_HOST_MODE())
/* pCtx->rip can be different than the one in the VMCS (e.g. run guest code and VM-exits that don't update it). */
if ( !fLongModeGuest
/* Flags in pCtx can be different (real-on-v86 for instance). We are only concerned about the VMCS contents here. */
HMVMX_CHECK_BREAK(!(u32Eflags & 0xffc08028), VMX_IGS_RFLAGS_RESERVED); /* Bit 31:22, Bit 15, 5, 3 MBZ. */
if ( fLongModeGuest
|| ( fUnrestrictedGuest
if (HMVMX_IS_64BIT_HOST_MODE())
if ( fLongModeGuest
&& !fUnrestrictedGuest)
if ( !fLongModeGuest
HMVMX_CHECK_BREAK((u64Val & MSR_K6_EFER_LMA) == (pVCpu->hm.s.vmx.u32EntryCtls & VMX_VMCS_CTRL_ENTRY_IA32E_MODE_GUEST),
HMVMX_CHECK_BREAK(pCtx->cs.Attr.u && !(pCtx->cs.Attr.u & X86DESCATTR_UNUSABLE), VMX_IGS_CS_ATTR_UNUSABLE);
HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u2Dpl == (pCtx->ss.Sel & X86_SEL_RPL), VMX_IGS_SS_ATTR_DPL_RPL_UNEQUAL);
HMVMX_CHECK_BREAK(pCtx->ss.Attr.n.u4Type == 3 || pCtx->ss.Attr.n.u4Type == 7, VMX_IGS_SS_ATTR_TYPE_INVALID);
if (HMVMX_IS_64BIT_HOST_MODE())
if (HMVMX_IS_64BIT_HOST_MODE())
if (HMVMX_IS_64BIT_HOST_MODE())
if (fLongModeGuest)
if (HMVMX_IS_64BIT_HOST_MODE())
HMVMX_CHECK_BREAK(u32ActivityState == VMX_VMCS_GUEST_ACTIVITY_ACTIVE, VMX_IGS_ACTIVITY_STATE_ACTIVE_INVALID);
|| u32ActivityState != VMX_VMCS_GUEST_ACTIVITY_SIPI_WAIT, VMX_IGS_ACTIVITY_STATE_SIPI_WAIT_INVALID);
if (HMVMX_IS_64BIT_HOST_MODE())
HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0xffffffffffffaff0)), VMX_IGS_LONGMODE_PENDING_DEBUG_RESERVED);
&& !fLongModeGuest
return uError;
/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- VM-exit handlers -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
return VINF_SUCCESS;
return VINF_EM_RAW_INTERRUPT;
* This cannot be a guest NMI as the only way for the guest to receive an NMI is if we injected it ourselves and
return VINF_SUCCESS;
/* If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly. */
return VINF_SUCCESS;
return rc;
switch (uIntType)
case VMX_EXIT_INTERRUPTION_INFO_TYPE_PRIV_SW_XCPT: /* Privileged software exception. (#DB from ICEBP) */
Assert(uVector == X86_XCPT_BP || uVector == X86_XCPT_OF || uIntType == VMX_EXIT_INTERRUPTION_INFO_TYPE_PRIV_SW_XCPT);
switch (uVector)
#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
AssertMsgFailed(("Unexpected interruption info %#x\n", VMX_EXIT_INTERRUPTION_INFO_TYPE(uExitIntInfo)));
return rc;
/* Indicate that we no longer need to VM-exit when the guest is ready to receive interrupts, it is now ready. */
/* Deliver the pending interrupt via hmR0VmxPreRunGuest()->hmR0VmxInjectEvent() and resume guest execution. */
return VINF_SUCCESS;
return rc;
return VINF_EM_RAW_EMULATE_INSTR;
int rc = hmR0VmxSaveGuestCR4(pVCpu, pMixedCtx); /** @todo review if CR4 is really required by EM. */
/* If we get a spurious VM-exit when offsetting is enabled, we must reset offsetting on VM-reentry. See @bugref{6634}. */
return rc;
int rc = hmR0VmxSaveGuestCR4(pVCpu, pMixedCtx); /** @todo review if CR4 is really required by EM. */
/* If we get a spurious VM-exit when offsetting is enabled, we must reset offsetting on VM-reentry. See @bugref{6634}. */
return rc;
int rc = hmR0VmxSaveGuestCR4(pVCpu, pMixedCtx); /** @todo review if CR4 is really required by EM. */
return rc;
VBOXSTRICTRC rc2 = EMInterpretInvlpg(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx), pVmxTransient->uExitQualification);
AssertMsg(rc == VERR_EM_INTERPRETER, ("hmR0VmxExitInvlpg: EMInterpretInvlpg %#RX64 failed with %Rrc\n",
return rc;
AssertMsg(rc == VERR_EM_INTERPRETER, ("hmR0VmxExitMonitor: EMInterpretMonitor failed with %Rrc\n", rc));
return rc;
AssertMsg(rc == VERR_EM_INTERPRETER, ("hmR0VmxExitMwait: EMInterpretMWait failed with %Rrc\n", rc));
return rc;
* Execution of RSM outside of SMM mode causes #UD regardless of VMX root or VMX non-root mode. In theory, we should never
* get this VM-exit. This can happen only if dual-monitor treatment of SMI and VMX is enabled, which can (only?) be done by
* This can only happen if we support dual-monitor treatment of SMI, which can be activated by executing VMCALL in VMX
* root operation. Only an STM (SMM transfer monitor) would get this exit when we (the executive monitor) execute a VMCALL
* See Intel spec. "33.15.6 Activating the Dual-Monitor Treatment" and Intel spec. 25.3 "Other Causes of VM-Exits"
* SIPI exits can only occur in VMX non-root operation when the "wait-for-SIPI" guest activity state is used. We currently
* don't make use of it (see hmR0VmxLoadGuestActivityState()) as our guests don't have direct access to the host LAPIC.
HMVMX_EXIT_DECL hmR0VmxExitInitSignal(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
* See Intel spec. 33.14.1 Default Treatment of SMI Delivery" and Intel spec. 29.3 "VMX Instructions" for "VMXON".
return VINF_SUCCESS;
HMVMX_EXIT_DECL hmR0VmxExitTripleFault(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
return VINF_EM_RESET;
return rc;
HMVMX_EXIT_DECL hmR0VmxExitSetPendingXcptUD(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
return VINF_SUCCESS;
HMVMX_EXIT_DECL hmR0VmxExitPreemptTimer(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
return VERR_EM_INTERPRETER;
return VERR_EM_INTERPRETER;
HMVMX_EXIT_DECL hmR0VmxExitErrInvalidGuestState(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
#ifdef VBOX_STRICT
return VERR_VMX_INVALID_GUEST_STATE;
HMVMX_EXIT_DECL hmR0VmxExitErrMsrLoad(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
AssertMsgFailed(("Unexpected MSR-load exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx)); NOREF(pMixedCtx);
HMVMX_EXIT_DECL hmR0VmxExitErrMachineCheck(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
AssertMsgFailed(("Unexpected machine-check event exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx)); NOREF(pMixedCtx);
HMVMX_EXIT_DECL hmR0VmxExitErrUndefined(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
AssertMsgFailed(("Huh!? Undefined VM-exit reason %d. pVCpu=%p pMixedCtx=%p\n", pVmxTransient->uExitReason, pVCpu, pMixedCtx));
return VERR_VMX_UNDEFINED_EXIT_CODE;
HMVMX_EXIT_DECL hmR0VmxExitXdtrAccess(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
return VERR_EM_INTERPRETER;
return VERR_EM_INTERPRETER;
#ifdef VBOX_STRICT
AssertMsgFailed(("Unexpected RDMSR for an MSR in the auto-load/store area in the VMCS. ecx=%#RX32\n", pMixedCtx->ecx));
AssertMsgFailed(("Unexpected RDMSR for a passthru lazy-restore MSR. ecx=%#RX32\n", pMixedCtx->ecx));
return rc;
AssertMsg(rc == VINF_SUCCESS || rc == VERR_EM_INTERPRETER, ("hmR0VmxExitWrmsr: failed, invalid error code %Rrc\n", rc));
/* We've already saved the APIC related guest-state (TPR) in hmR0VmxPostRunGuest(). When full APIC register
else if (pMixedCtx->ecx == MSR_IA32_TSC) /* Windows 7 does this during bootup. See @bugref{6398}. */
/* Update MSRs that are part of the VMCS and auto-load/store area when MSR-bitmaps are not supported. */
#ifdef VBOX_STRICT
case MSR_IA32_SYSENTER_CS:
case MSR_IA32_SYSENTER_EIP:
case MSR_IA32_SYSENTER_ESP:
case MSR_K8_FS_BASE:
case MSR_K8_GS_BASE:
/* Writes to MSRs in auto-load/store area/swapped MSRs, shouldn't cause VM-exits with MSR-bitmaps. */
AssertMsgFailed(("Unexpected WRMSR for an MSR in the auto-load/store area in the VMCS. ecx=%#RX32\n",
return rc;
return VERR_EM_INTERPRETER;
HMVMX_EXIT_DECL hmR0VmxExitTprBelowThreshold(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
* The TPR has already been updated, see hmR0VMXPostRunGuest(). RIP is also updated as part of the VM-exit by VT-x. Update
* the threshold in the VMCS, deliver the pending interrupt via hmR0VmxPreRunGuest()->hmR0VmxInjectPendingEvent() and
return VINF_SUCCESS;
switch (uAccessType)
/* EMInterpretCRxWrite() references a lot of guest state (EFER, RFLAGS, Segment Registers, etc.) Sync entire state */
Assert(rc == VINF_SUCCESS || rc == VERR_EM_INTERPRETER || rc == VINF_PGM_CHANGE_MODE || rc == VINF_PGM_SYNC_CR3);
AssertMsgFailed(("Invalid CRx register %#x\n", VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification)));
STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCRxWrite[VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification)]);
STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCRxRead[VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification)]);
Log4(("CRX CR%d Read access rc=%d\n", VMX_EXIT_QUALIFICATION_CRX_REGISTER(uExitQualification), rc));
rc = EMInterpretLMSW(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx), VMX_EXIT_QUALIFICATION_CRX_LMSW_DATA(uExitQualification));
Assert(rc == VINF_SUCCESS || rc == VINF_PGM_CHANGE_MODE || rc == VERR_EM_INTERPRETER || rc == VINF_PGM_SYNC_CR3
return rc;
rc2 |= hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx); /* CR0 checks & PGM* in EMInterpretDisasCurrent(). */
rc2 |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx); /* SELM checks in EMInterpretDisasCurrent(). */
/* EFER also required for longmode checks in EMInterpretDisasCurrent(), but it's always up-to-date. */
static const uint32_t s_aIOOpAnd[4] = { 0xff, 0xffff, 0, 0xffffffff }; /* AND masks for saving the result (in AL/AX/EAX). */
if (fIOString)
#if 0 /* Not yet ready. IEM gurus with debian 32-bit guest without NP (on ATA reads). See @bugref{5752#c158} */
Log4(("CS:RIP=%04x:%#RX64 %#06x/%u %c str\n", pMixedCtx->cs.Sel, pMixedCtx->rip, uIOPort, cbValue, fIOWrite ? 'w' : 'r'));
if (fIOWrite)
* The segment prefix for INS cannot be overridden and is always ES. We can safely assume X86_SREG_ES.
* See Intel spec. Table 27-8 "Format of the VM-Exit Instruction-Information Field as Used for INS and OUTS".
fUpdateRipAlready = true;
if (fIOWrite)
AssertMsg(rcStrict == VERR_EM_INTERPRETER, ("rcStrict=%Rrc RIP %#RX64\n", VBOXSTRICTRC_VAL(rcStrict), pMixedCtx->rip));
Log4(("CS:RIP=%04x:%#RX64 %#06x/%u %c\n", pMixedCtx->cs.Sel, pMixedCtx->rip, uIOPort, cbValue, fIOWrite ? 'w' : 'r'));
if (fIOWrite)
HMR0SavePendingIOPortWrite(pVCpu, pMixedCtx->rip, pMixedCtx->rip + cbInstr, uIOPort, uAndVal, cbValue);
HMR0SavePendingIOPortRead(pVCpu, pMixedCtx->rip, pMixedCtx->rip + cbInstr, uIOPort, uAndVal, cbValue);
if (!fUpdateRipAlready)
* INS/OUTS with REP prefix updates RFLAGS, can be observed with triple-fault guru while booting Fedora 17 64-bit guest.
if (fIOString)
else if (fStepping)
if (fIsGuestDbgActive)
#ifdef DEBUG
HMVMX_EXIT_DECL hmR0VmxExitTaskSwitch(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
if (VMX_EXIT_QUALIFICATION_TASK_SWITCH_TYPE(pVmxTransient->uExitQualification) == VMX_EXIT_QUALIFICATION_TASK_SWITCH_TYPE_IDT)
/* Software interrupts and exceptions will be regenerated when the recompiler restarts the instruction. */
bool fErrorCodeValid = VMX_IDT_VECTORING_INFO_ERROR_CODE_IS_VALID(pVmxTransient->uIdtVectoringInfo);
if (fErrorCodeValid)
return VERR_EM_INTERPRETER;
return VINF_EM_DBG_STEPPED;
HMVMX_EXIT_DECL hmR0VmxExitApicAccess(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
/* If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly. */
return VINF_SUCCESS;
return rc;
/* See Intel spec. 27-6 "Exit Qualifications for APIC-access VM-exits from Linear Accesses & Guest-Phyiscal Addresses" */
switch (uAccessType)
RTGCPHYS GCPhys = pMixedCtx->msrApicBase; /* Always up-to-date, msrApicBase is not part of the VMCS. */
return rc;
#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
#ifdef VBOX_WITH_STATISTICS
if (VMX_EXIT_QUALIFICATION_DRX_DIRECTION(pVmxTransient->uExitQualification) == VMX_EXIT_QUALIFICATION_DRX_DIRECTION_WRITE)
return VINF_SUCCESS;
* EMInterpretDRx[Write|Read]() calls CPUMIsGuestIn64BitCode() which requires EFER, CS. EFER is always up-to-date.
if (VMX_EXIT_QUALIFICATION_DRX_DIRECTION(pVmxTransient->uExitQualification) == VMX_EXIT_QUALIFICATION_DRX_DIRECTION_WRITE)
return rc;
HMVMX_EXIT_DECL hmR0VmxExitEptMisconfig(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
/* If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly. */
return VINF_SUCCESS;
return rc;
* of the page containing the instruction via the guest's page tables (we would invalidate the guest page
* in the host TLB), resume execution which would cause a guest page fault to let the guest handle this
VBOXSTRICTRC rc2 = PGMR0Trap0eHandlerNPMisconfig(pVM, pVCpu, PGMMODE_EPT, CPUMCTX2CORE(pMixedCtx), GCPhys, UINT32_MAX);
return rc;
HMVMX_EXIT_DECL hmR0VmxExitEptViolation(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
/* If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly. */
return VINF_SUCCESS;
return rc;
AssertMsg(((pVmxTransient->uExitQualification >> 7) & 3) != 2, ("%#RX64", pVmxTransient->uExitQualification));
Log4(("EPT violation %#x at %#RX64 ErrorCode %#x CS:EIP=%04x:%#RX64\n", pVmxTransient->uExitQualification, GCPhys,
rc = PGMR0Trap0eHandlerNestedPaging(pVM, pVCpu, PGMMODE_EPT, uErrorCode, CPUMCTX2CORE(pMixedCtx), GCPhys);
return VINF_SUCCESS;
return rc;
return rc;
hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
return rc;
hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
return rc;
rc = DBGFRZTrap01Handler(pVCpu->CTX_SUFF(pVM), pVCpu, CPUMCTX2CORE(pMixedCtx), uDR6, pVCpu->hm.s.fSingleInstruction);
* It is important to reflect what the VM-exit gave us (preserving the interruption-type) rather than use
* hmR0VmxSetPendingXcptDB() as the #DB could've been raised while executing ICEBP and not the 'normal' #DB.
hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
return VINF_SUCCESS;
return rc;
#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
/* Guest FPU state was activated, we'll want to change CR0 FPU intercepts before the next VM-reentry. */
hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
return VINF_SUCCESS;
#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
/* If the guest is not in real-mode or we have unrestricted execution support, reflect #GP to the guest. */
Log4(("#GP Gst: RIP %#RX64 ErrorCode=%#x CR0=%#RX64 CPL=%u\n", pMixedCtx->rip, pVmxTransient->uExitIntErrorCode,
hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
return rc;
return VERR_VMX_UNEXPECTED_EXCEPTION;
Log4(("#GP Disas OpCode=%u CS:EIP %04x:%#RX64\n", pDis->pCurInstr->uOpcode, pMixedCtx->cs.Sel, pMixedCtx->rip));
case OP_CLI:
case OP_STI:
case OP_HLT:
case OP_POPF:
rc = SELMToFlatEx(pVCpu, DISSELREG_SS, CPUMCTX2CORE(pMixedCtx), pMixedCtx->esp & uMask, SELMTOFLAT_FLAGS_CPL0,
&GCPtrStack);
Log4(("POPF %#x -> %#RX64 mask=%#x RIP=%#RX64\n", Eflags.u, pMixedCtx->rsp, uMask, pMixedCtx->rip));
pMixedCtx->eflags.Bits.u1RF = 0; /* The RF bit is always cleared by POPF; see Intel Instruction reference. */
/* Generate a pending-debug exception when stepping over POPF regardless of how POPF modifies EFLAGS.TF. */
if (fStepping)
case OP_PUSHF:
/* The RF & VM bits are cleared on image stored on stack; see Intel Instruction reference for PUSHF. */
case OP_IRET:
rc = SELMToFlatEx(pVCpu, DISSELREG_SS, CPUMCTX2CORE(pMixedCtx), pMixedCtx->esp & uMask, SELMTOFLAT_FLAGS_CPL0,
&GCPtrStack);
/* Generate a pending-debug exception when stepping over IRET regardless of how IRET modifies EFLAGS.TF. */
if (fStepping)
case OP_INT:
case OP_INTO:
VBOXSTRICTRC rc2 = EMInterpretInstructionDisasState(pVCpu, pDis, CPUMCTX2CORE(pMixedCtx), 0 /* pvFault */,
AssertMsg(rc == VINF_SUCCESS || rc == VERR_EM_INTERPRETER || rc == VINF_PGM_CHANGE_MODE || rc == VINF_EM_HALT,
return rc;
#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
/* Re-inject the exception into the guest. This cannot be a double-fault condition which would have been handled in
hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
return VINF_SUCCESS;
pMixedCtx->cr2 = pVmxTransient->uExitQualification; /* Update here in case we go back to ring-3 before injection. */
hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
return rc;
Log4(("#PF: cr2=%#RX64 cs:rip=%#04x:%#RX64 uErrCode %#RX32 cr3=%#RX64\n", pVmxTransient->uExitQualification,
TRPMAssertXcptPF(pVCpu, pVmxTransient->uExitQualification, (RTGCUINT)pVmxTransient->uExitIntErrorCode);
return rc;
pMixedCtx->cr2 = pVmxTransient->uExitQualification; /* Update here in case we go back to ring-3 before injection. */
hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
return VINF_SUCCESS;
return rc;