HMVMXR0.cpp revision 380b8540bceb13a79763971ed08a3235b01da963
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/** This bit indicates the segment selector is unusable in VT-x. */
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_FS_BASE_MSR RT_BIT(12)
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk#define HMVMX_UPDATED_GUEST_GS_BASE_MSR RT_BIT(13)
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk#define HMVMX_UPDATED_GUEST_SYSENTER_CS_MSR RT_BIT(14)
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk#define HMVMX_UPDATED_GUEST_SYSENTER_EIP_MSR RT_BIT(15)
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk#define HMVMX_UPDATED_GUEST_SYSENTER_ESP_MSR RT_BIT(16)
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk#define HMVMX_UPDATED_GUEST_AUTO_LOAD_STORE_MSRS RT_BIT(17)
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk#define HMVMX_UPDATED_GUEST_ACTIVITY_STATE RT_BIT(18)
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk#define HMVMX_UPDATED_GUEST_APIC_STATE RT_BIT(19)
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 * Exception bitmap mask for real-mode guests (real-on-v86). We need to intercept all exceptions manually (except #PF).
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * #NM is also handled spearetely, see hmR0VmxLoadGuestControlRegs(). #PF need not be intercepted even in real-mode if
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * 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#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/*******************************************************************************
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk* Structures and Typedefs *
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk*******************************************************************************/
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 LSTAR MSR value used for TPR patching for 32-bit guests. */
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 /** 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 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 * contributary exception or a page-fault. */
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkAssertCompileMemberAlignment(VMXTRANSIENT, uExitReason, sizeof(uint64_t));
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkAssertCompileMemberAlignment(VMXTRANSIENT, uExitIntrInfo, sizeof(uint64_t));
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkAssertCompileMemberAlignment(VMXTRANSIENT, uEntryIntrInfo, sizeof(uint64_t));
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * MSR-bitmap read permissions.
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk /** Reading this MSR causes a VM-exit. */
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk /** Reading this MSR does not cause a VM-exit. */
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * MSR-bitmap write permissions.
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk /** Writing to this MSR causes a VM-exit. */
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk /** Writing to this MSR does not cause a VM-exit. */
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk/*******************************************************************************
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk* Internal Functions *
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk*******************************************************************************/
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkstatic void hmR0VmxFlushVpid(PVM pVM, PVMCPU pVCpu, VMX_FLUSH_VPID enmFlush, RTGCPTR GCPtr);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkstatic int hmR0VmxInjectEventVmcs(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint64_t u64IntrInfo, uint32_t cbInstr,
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk uint32_t u32ErrCode, RTGCUINTREG GCPtrFaultAddress, uint32_t *puIntrState);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk#if HC_ARCH_BITS == 32 && !defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkstatic int hmR0VmxInitVmcsReadCache(PVM pVM, PVMCPU pVCpu);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkDECLINLINE(int) hmR0VmxHandleExit(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient, uint32_t rcReason);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk#define HMVMX_EXIT_DECL static int
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkHMVMX_EXIT_DECL hmR0VmxExitXcptNmi(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkHMVMX_EXIT_DECL hmR0VmxExitExtInt(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkHMVMX_EXIT_DECL hmR0VmxExitTripleFault(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkHMVMX_EXIT_DECL hmR0VmxExitInitSignal(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkHMVMX_EXIT_DECL hmR0VmxExitSipi(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkHMVMX_EXIT_DECL hmR0VmxExitIoSmi(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkHMVMX_EXIT_DECL hmR0VmxExitSmi(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkHMVMX_EXIT_DECL hmR0VmxExitIntWindow(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkHMVMX_EXIT_DECL hmR0VmxExitNmiWindow(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkHMVMX_EXIT_DECL hmR0VmxExitTaskSwitch(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkHMVMX_EXIT_DECL hmR0VmxExitCpuid(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkHMVMX_EXIT_DECL hmR0VmxExitGetsec(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkHMVMX_EXIT_DECL hmR0VmxExitHlt(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkHMVMX_EXIT_DECL hmR0VmxExitInvd(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkHMVMX_EXIT_DECL hmR0VmxExitInvlpg(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkHMVMX_EXIT_DECL hmR0VmxExitRdpmc(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkHMVMX_EXIT_DECL hmR0VmxExitRdtsc(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkHMVMX_EXIT_DECL hmR0VmxExitRsm(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkHMVMX_EXIT_DECL hmR0VmxExitSetPendingXcptUD(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkHMVMX_EXIT_DECL hmR0VmxExitMovCRx(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkHMVMX_EXIT_DECL hmR0VmxExitMovDRx(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkHMVMX_EXIT_DECL hmR0VmxExitIoInstr(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkHMVMX_EXIT_DECL hmR0VmxExitRdmsr(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkHMVMX_EXIT_DECL hmR0VmxExitWrmsr(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkHMVMX_EXIT_DECL hmR0VmxExitErrInvalidGuestState(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkHMVMX_EXIT_DECL hmR0VmxExitErrMsrLoad(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkHMVMX_EXIT_DECL hmR0VmxExitErrUndefined(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkHMVMX_EXIT_DECL hmR0VmxExitMwait(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkHMVMX_EXIT_DECL hmR0VmxExitMtf(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkHMVMX_EXIT_DECL hmR0VmxExitMonitor(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkHMVMX_EXIT_DECL hmR0VmxExitPause(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkHMVMX_EXIT_DECL hmR0VmxExitErrMachineCheck(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkHMVMX_EXIT_DECL hmR0VmxExitTprBelowThreshold(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
HMVMX_EXIT_DECL hmR0VmxExitApicAccess(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
HMVMX_EXIT_DECL hmR0VmxExitXdtrAccess(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
HMVMX_EXIT_DECL hmR0VmxExitXdtrAccess(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
HMVMX_EXIT_DECL hmR0VmxExitEptViolation(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
HMVMX_EXIT_DECL hmR0VmxExitEptMisconfig(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
HMVMX_EXIT_DECL hmR0VmxExitPreemptTimer(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
#ifdef HMVMX_USE_FUNCTION_TABLE
typedef DECLCALLBACK(int) FNVMEXITHANDLER(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient);
#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->uExitIntrErrorCode);
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
if (pVM)
return rc;
static int hmR0VmxLeaveRootMode(void)
VMXDisable();
return VINF_SUCCESS;
return VERR_VMX_NOT_IN_VMX_ROOT_MODE;
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
#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;
AssertReturn(MSR_IA32_VMX_BASIC_INFO_VMCS_SIZE(pVM->hm.s.vmx.msr.vmx_basic_info) <= PAGE_SIZE, VERR_INTERNAL_ERROR);
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(PHMGLOBLCPUINFO pCpu, PVM pVM, void *pvCpuPage, RTHCPHYS HCPhysCpuPage, bool fEnabledByHost)
if (!fEnabledByHost)
return rc;
if ( pVM
return VINF_SUCCESS;
return hmR0VmxLeaveRootMode();
static void hmR0VmxSetMsrPermission(PVMCPU pVCpu, uint32_t uMsr, VMXMSREXITREAD enmRead, VMXMSREXITWRITE enmWrite)
AssertMsg(rc == VINF_SUCCESS, ("VMXR0InvEPT %#x %RGv failed with %Rrc\n", enmFlush, pVCpu->hm.s.vmx.HCPhysEPTP, rc));
descriptor[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*().
return VINF_SUCCESS;
* 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
bool fNewASID = false;
fNewASID = true;
if (fNewASID)
("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())
/* 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));
* 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.msr.vmx_ept_vpid_caps));
/* Neither SINGLE nor ALL-context flush types for VPID is supported by the CPU. Ignore VPID capability. */
if (pVM->hm.s.vmx.msr.vmx_ept_vpid_caps & 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 val = pVM->hm.s.vmx.msr.vmx_pin_ctls.n.disallowed0; /* Bits set here must always be set. */
uint32_t zap = pVM->hm.s.vmx.msr.vmx_pin_ctls.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.msr.vmx_proc_ctls.n.disallowed0; /* Bits set here must be set in the VMCS. */
uint32_t zap = pVM->hm.s.vmx.msr.vmx_proc_ctls.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. */
* 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_SF_MASK, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
hmR0VmxSetMsrPermission(pVCpu, MSR_K8_KERNEL_GS_BASE, 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);
LogRel(("hmR0VmxSetupProcCtls: invalid processor-based VM-execution controls combo! cpu=%#RX64 val=%#RX64 zap=%#RX64\n",
zap = pVM->hm.s.vmx.msr.vmx_proc_ctls2.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. */
hmR0VmxSetMsrPermission(pVCpu, MSR_K8_TSC_AUX, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
return VINF_SUCCESS;
/* All CR3 accesses cause VM-exits. Later we optimize CR3 accesses (see hmR0VmxLoadGuestControlRegs())*/
* 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.
/* Setup MSR autoloading/storing. */
/* Set VMCS link pointer. Reserved for future use, must be -1. Intel spec. 24.4 "Guest-State Area". */
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;
return rc;
*(uint32_t *)pVCpu->hm.s.vmx.pvVmcs = MSR_IA32_VMX_BASIC_INFO_VMCS_ID(pVM->hm.s.vmx.msr.vmx_basic_info);
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;
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".
uSelDS = 0;
uSelES = 0;
uSelFS = 0;
uSelGS = 0;
/* 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
* IDT limit is practically 0xfff. Therefore if the host has the limit as 0xfff, VT-x bloating the limit to 0xffff
* is not a problem as it's not possible to get at them anyway. See Intel spec. 6.14.1 "64-Bit Mode IDT" and
* 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())
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;
/* All our supported 64-bit host platforms must have NXE bit set. Otherwise we can change the below code to save EFER. */
# if HC_ARCH_BITS == 32 && defined(VBOX_ENABLE_64_BITS_GUESTS) && !defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
if (HMVMX_IS_64BIT_HOST_MODE())
LogRel(("cHostMsrs=%u Cpu=%u\n", cHostMsrs, (unsigned)MSR_IA32_VMX_MISC_MAX_MSR(pVM->hm.s.vmx.msr.vmx_misc)));
# ifdef VBOX_WITH_HYBRID_32BIT_KERNEL
if (HMVMX_IS_64BIT_HOST_MODE())
return rc;
uint32_t val = pVM->hm.s.vmx.msr.vmx_entry.n.disallowed0; /* Bits set here must be set in the VMCS. */
uint32_t zap = pVM->hm.s.vmx.msr.vmx_entry.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.msr.vmx_exit.n.disallowed0; /* Bits set here must be set in the VMCS. */
uint32_t zap = pVM->hm.s.vmx.msr.vmx_exit.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). */
/* If there are interrupts pending, intercept CR8 writes, otherwise don't intercept CR8 reads or writes. */
if (fPendingIntr)
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). */
AssertMsg((pVCpu->hm.s.vmx.fUpdatedGuestState & (HMVMX_UPDATED_GUEST_RIP | HMVMX_UPDATED_GUEST_RFLAGS))
== (HMVMX_UPDATED_GUEST_RIP | HMVMX_UPDATED_GUEST_RFLAGS), ("%#x\n", pVCpu->hm.s.vmx.fUpdatedGuestState));
* 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;
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 = uEFlags.u32; /* Save the original eflags of the real-mode guest. */
return rc;
return rc;
/* The guest doesn't have paging enabled, make CR3 access to cause VM exits to update our shadow. */
* 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). */
Log(("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)
/* 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
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;
fInterceptMovDRx = true;
/* For the first time we would need to intercept MOV DRx accesses even when the guest debug registers aren't loaded. */
fInterceptMovDRx = true;
if (fInterceptDB)
#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
if (fInterceptMovDRx)
/* The guest's view of its DR7 is unblemished. Use 32-bit write as upper 32-bits MBZ as asserted above. */
return rc;
#ifdef VBOX_STRICT
/* NOTE: The reason we check for attribute value 0 and not just the unusable bit here is because hmR0VmxWriteSegmentReg()
Assert(pCtx->cs.Attr.u && !(pCtx->cs.Attr.u & HMVMX_SEL_UNUSABLE)); /** @todo is this really true even for 64-bit CS?!? */
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));
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,
Log(("Load: CS=%#RX16 Base=%#RX64 Limit=%#RX32 Attr=%#RX32\n", pMixedCtx->cs.Sel, pMixedCtx->cs.u64Base,
#ifdef VBOX_STRICT
* 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 & HMVMX_SEL_UNUSABLE), ("TR unusable bit is not clear!? %#x\n", u32AccessRights));
rc |= VMXWriteVmcs32(VMX_VMCS32_GUEST_LDTR_LIMIT, pMixedCtx->ldtr.u32Limit); AssertRCReturn(rc, rc);
return VINF_SUCCESS;
/* Do -not- load guest EFER as we don't save/restore the host EFER always. See hmr0VmxSaveHostMsrs() */
/* VT-x will complain if only MSR_K6_EFER_LME is set. See Intel spec. 26.4 "Loading MSRs" for details. */
if (fSupportsLongMode)
rc = VMXWriteVmcsGstN(VMX_VMCS_GUEST_SYSENTER_EIP, pMixedCtx->SysEnter.eip); AssertRCReturn(rc, rc);
rc = VMXWriteVmcsGstN(VMX_VMCS_GUEST_SYSENTER_ESP, pMixedCtx->SysEnter.esp); AssertRCReturn(rc, rc);
return rc;
return rc;
#ifndef VBOX_ENABLE_64_BITS_GUESTS
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(pVCpu->hm.s.fResumeVM, pCtx, &pVCpu->hm.s.vmx.VMCSCache, pVM, pVCpu, pVCpu->hm.s.vmx.pfnStartVM);
return pVCpu->hm.s.vmx.pfnStartVM(pVCpu->hm.s.fResumeVM, pCtx, &pVCpu->hm.s.vmx.VMCSCache, pVM, pVCpu);
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
#ifdef VBOX_STRICT
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
#ifdef VBOX_STRICT
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 u32IntrInfo, uint32_t cbInstr, uint32_t u32ErrCode,
hmR0VmxSetPendingEvent(pVCpu, u32IntrInfo, 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
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_INTR_INFO_FROM_EXIT_IDT_INFO(pVmxTransient->uIdtVectoringInfo),
case VMXREFLECTXCPT_DF:
Log(("IDT: Pending vectoring #DF %#RX64 uIdtVector=%#x uExitVector=%#x\n", pVCpu->hm.s.Event.u64IntrInfo,
case VMXREFLECTXCPT_TF:
return rc;
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;
return rc;
return rc;
return VINF_SUCCESS;
pMsr += i;
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 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,
* If VT-x marks the segment as unusable, the rest of the attributes are undefined with certain exceptions (some bits in
* CS, SS). Regardless, we have to clear the bits here and only retain the unusable bit because the unusable bit is specific
* to VT-x, everyone else relies on the attribute being zero and have no clue what the unusable bit is.
Assert(idxSel != VMX_VMCS16_GUEST_FIELD_TR); /* TR is the only selector that can never be unusable. */
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 rc;
return VINF_SUCCESS;
return VINF_SUCCESS;
/* Though we can longjmp to ring-3 due to log-flushes here and get recalled again on the ring-3 callback path,
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, ("hmR0VmxSaveGuestDebugRegs failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestSysenterMsrs failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestFSBaseMsr failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
AssertLogRelMsgRCReturn(rc, ("hmR0VmxSaveGuestGSBaseMsr 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, ("hmR0VmxSaveGuestDebugRegs failed! rc=%Rrc (pVCpu=%p)\n", rc, pVCpu), rc);
("Missed guest state bits while saving state; residue %RX32\n", pVCpu->hm.s.vmx.fUpdatedGuestState));
return rc;
if ( VM_FF_IS_PENDING(pVM, VM_FF_HM_TO_R3_MASK | VM_FF_REQUEST | VM_FF_PGM_POOL_FLUSH_PENDING | VM_FF_PDM_DMA)
|| VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_TO_R3_MASK | VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL
rc = PGMSyncCR3(pVCpu, pMixedCtx->cr0, pMixedCtx->cr3, pMixedCtx->cr4, VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3));
return rc;
rc = RT_UNLIKELY(VM_FF_IS_PENDING(pVM, VM_FF_PGM_NO_MEMORY)) ? VINF_EM_NO_MEMORY : VINF_EM_RAW_TO_R3;
return rc;
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 u32IntrInfo. */
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:
Log(("TRPM->HM event: u32IntrInfo=%#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)
/* We want to see what the guest-state was before VM-entry, don't resync here, as we won't continue guest execution. */
/* 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. */
/* VMMRZCallRing3() already makes sure we never get called as a result of an longjmp due to an assertion, */
if (RT_LIKELY(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.msr.vmx_proc_ctls.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. */
bool fInject = true;
if ( fBlockInt
|| fBlockSti
|| fBlockMovSS)
fInject = false;
&& ( fBlockMovSS
|| fBlockSti))
/* On some CPUs block-by-STI also blocks NMIs. See Intel spec. 26.3.1.5 "Checks On Guest Non-Register State". */
fInject = false;
if (fInject)
rc = hmR0VmxInjectEventVmcs(pVCpu, pMixedCtx, pVCpu->hm.s.Event.u64IntrInfo, pVCpu->hm.s.Event.cbInstr,
else if (VMCPU_FF_IS_SET(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)
/* Check if there are guest external interrupts (PIC/APIC) pending and inject them if the guest can receive them. */
if ( !fBlockInt
&& !fBlockSti
&& !fBlockMovSS)
* Delivery pending debug exception if the guest is single-stepping. The interruptibility-state could have been changed by
* hmR0VmxInjectEventVmcs() (e.g. real-on-v86 injecting software interrupts), re-evaluate it and set the BS bit.
if ( fBlockSti
|| fBlockMovSS)
if (pMixedCtx->eflags.Bits.u1TF) /* We don't have any IA32_DEBUGCTL MSR for guests. Treat as all bits 0. */
* The pending-debug exceptions field is cleared on all VM-exits except VMX_EXIT_TPR_BELOW_THRESHOLD, VMX_EXIT_MTF
* VMX_EXIT_APIC_WRITE, VMX_EXIT_VIRTUALIZED_EOI. See Intel spec. 27.3.4 "Saving Non-Register State".
/* We are single-stepping in the hypervisor debugger, clear interrupt inhibition as setting the BS bit would mean
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, u32IntrInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
return hmR0VmxInjectEventVmcs(pVCpu, pMixedCtx, u32IntrInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */,
hmR0VmxSetPendingEvent(pVCpu, u32IntrInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);
DECLINLINE(int) hmR0VmxInjectXcptGP(PVMCPU pVCpu, PCPUMCTX pMixedCtx, bool fErrorCodeValid, uint32_t u32ErrorCode,
if (fErrorCodeValid)
return hmR0VmxInjectEventVmcs(pVCpu, pMixedCtx, u32IntrInfo, 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 u64IntrInfo, uint32_t cbInstr,
/* Intel spec. 24.8.3 "VM-Entry Controls for Event Injection" specifies the interruption-information field to be 32-bits. */
* 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);
Log(("Injecting real-mode: u32IntrInfo=%#x u32ErrCode=%#x instrlen=%#x\n", u32IntrInfo, 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(u32IntrInfo)); /* Bit 31 (Valid bit) must be set by caller. */
Log(("Injecting u32IntrInfo=%#x u32ErrCode=%#x cbInstr=%#x uCR2=%#RX64\n", u32IntrInfo, u32ErrCode, cbInstr, pMixedCtx->cr2));
return rc;
return VERR_VMX_X86_CR4_VMXE_CLEARED;
return rc;
return VINF_SUCCESS;
return rc;
/* Nothing to do if the host-state-changed flag isn't set. This will later be optimized when preemption hooks are in place. */
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;
AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadGuestEntryCtls! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
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, ("hmR0VmxLoadGuestControlRegs: rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
/* Must be done after CR0 is loaded (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, ("hmR0VmxLoadGuestDebugRegs: rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadGuestMsrs! 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);
/* Must be done after hmR0VmxLoadGuestDebugRegs() as it may update eflags.TF for debugging purposes. */
AssertLogRelMsgRCReturn(rc, ("hmR0VmxLoadGuestGprs! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
AssertLogRelMsgRCReturn(rc, ("hmR0VmxSetupVMRunHandler! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
return rc;
* clearing the common-state (TRPM/forceflags), we must undo those changes so
DECLINLINE(int) hmR0VmxPreRunGuest(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
return rc;
/* 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);
/* We disable interrupts so that we don't miss any interrupts that would flag preemption (IPI/timers etc.) */
/* Don't use VINF_EM_RAW_INTERRUPT_HYPER as we can't assume the host does kernel preemption. Maybe some day? */
return VINF_EM_RAW_INTERRUPT;
* Evaluates and injects any pending events, toggling force-flags and updating the guest-interruptibility
* state (interrupt shadow) in the VMCS. This -can- potentially be reworked to be done before disabling
* interrupts and handle returning to ring-3 afterwards, but requires very careful state restoration.
return rc;
DECLINLINE(void) hmR0VmxPreRunGuestCommitted(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
/** @todo I don't see the point of this, VMMR0EntryFast() already disables interrupts for the entire period. */
#ifdef HMVMX_SYNC_FULL_GUEST_STATE
AssertMsg(!pVCpu->hm.s.fContextUseFlags, ("fContextUseFlags =%#x\n", pVCpu->hm.s.fContextUseFlags));
ASMAtomicWriteBool(&pVCpu->hm.s.fCheckedTLBFlush, true); /* Used for TLB-shootdowns, set this across the world switch. */
* TPR patching (only active for 32-bit guests on 64-bit capable CPUs) when the CPU does not supported virtualizing
/* Need guest's LSTAR MSR (which is part of the auto load/store MSRs in the VMCS), ensure we have the updated one. */
/* The patch code uses the LSTAR as it's not used by a guest in 32-bit mode implicitly (i.e. SYSCALL is 64-bit only). */
#ifndef VBOX_WITH_AUTO_MSR_LOAD_RESTORE
DECLINLINE(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. */
pVCpu->hm.s.vmx.fUpdatedGuestState = 0; /* Exits/longjmps to ring-3 requires saving the guest state. */
#ifndef VBOX_WITH_AUTO_MSR_LOAD_RESTORE
Log(("VM-entry failure: rcVMRun=%Rrc fVMEntryFailed=%RTbool\n", rcVMRun, pVmxTransient->fVMEntryFailed));
* 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++)
/* Preparatory work for running guest code, this may return to ring-3 for some last minute updates. */
* Asserts() will still longjmp to ring-3 (but won't return), which is intentional, better than a kernel panic.
/* The guest-CPU context is now outdated, 'pCtx' is to be treated as 'pMixedCtx' from this point on!!! */
* Restore any residual host-state and save any bits shared between host and guest into the guest-CPU state.
if (RT_UNLIKELY(rc != VINF_SUCCESS)) /* Check for errors with running the VM (VMLAUNCH/VMRESUME). */
return rc;
#ifdef HMVMX_USE_FUNCTION_TABLE
return rc;
#ifndef HMVMX_USE_FUNCTION_TABLE
DECLINLINE(int) hmR0VmxHandleExit(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient, uint32_t rcReason)
int rc;
switch (rcReason)
case VMX_EXIT_TPR_BELOW_THRESHOLD: rc = hmR0VmxExitTprBelowThreshold(pVCpu, pMixedCtx, pVmxTransient); 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 VMX_ASSERT_PREEMPT_CPUID_VAR() \
# define VMX_ASSERT_PREEMPT_CPUID() \
RTCPUID const idAssertCpuNow = RTThreadPreemptIsEnabled(NIL_RTTHREAD) ? NIL_RTCPUID : RTMpCpuId(); \
# define VMX_VALIDATE_EXIT_HANDLER_PARAMS() \
# define VMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS() \
# define VMX_VALIDATE_EXIT_XCPT_HANDLER_PARAMS() do { } while(0)
DECLINLINE(int) hmR0VmxAdvanceGuestRip(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
return rc;
/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- VM-exit handlers -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
return VINF_SUCCESS;
return VINF_EM_RAW_INTERRUPT;
return VINF_EM_RAW_INTERRUPT;
/* If this VM-exit occurred while delivering an event through the guest IDT, handle it accordingly. */
return VINF_SUCCESS;
return rc;
switch (uIntrType)
switch (uVector)
#ifdef HMVMX_ALWAYS_TRAP_ALL_XCPTS
AssertMsgFailed(("Unexpected interruption code %#x\n", VMX_EXIT_INTERRUPTION_INFO_TYPE(uExitIntrInfo)));
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 VERR_VMX_UNEXPECTED_EXIT_CODE;
return rc;
return VINF_EM_RAW_EMULATE_INSTR;
return VERR_VMX_UNEXPECTED_EXIT_CODE;
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
return VERR_VMX_UNEXPECTED_EXIT_CODE;
* This can only happen if we support dual-monitor treatment of SMI, which can be activated by executing VMCALL in VMX
* See Intel spec. "33.15.6 Activating the Dual-Monitor Treatment" and Intel spec. 25.3 "Other Causes of VM-Exits"
return VERR_VMX_UNEXPECTED_EXIT_CODE;
return VERR_VMX_UNEXPECTED_EXIT_CODE;
* 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.
return VERR_VMX_UNEXPECTED_EXIT_CODE;
HMVMX_EXIT_DECL hmR0VmxExitInitSignal(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
* INIT signals are blocked in VMX root operation by VMXON and by SMI in SMM. See Intel spec. "33.14.1 Default Treatment of
* SMI Delivery" and "29.3 VMX Instructions" for "VMXON". It is -NOT- blocked in VMX non-root operation so we can potentially
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)
return VERR_VMX_INVALID_GUEST_STATE;
HMVMX_EXIT_DECL hmR0VmxExitErrMsrLoad(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
return VERR_VMX_UNEXPECTED_EXIT_CODE;
HMVMX_EXIT_DECL hmR0VmxExitErrMachineCheck(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
AssertMsgFailed(("Unexpected machine-check event exit. pVCpu=%p pMixedCtx=%p\n", pVCpu, pMixedCtx));
return VERR_VMX_UNEXPECTED_EXIT_CODE;
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_VMX_UNEXPECTED_EXIT_CODE;
return VERR_EM_INTERPRETER;
return VERR_VMX_UNEXPECTED_EXIT_CODE;
return rc;
/* If TPR patching is active, LSTAR holds the guest TPR, writes to it must be propagated to the APIC. */
return VINF_SUCCESS;
AssertMsg(rc == VINF_SUCCESS || rc == VERR_EM_INTERPRETER, ("hmR0VmxExitWrmsr: failed, invalid error code %Rrc\n", rc));
else if (pMixedCtx->ecx == MSR_K6_EFER) /* EFER is the only MSR we auto-load but don't allow write-passthrough. */
else if (pMixedCtx->ecx == MSR_IA32_TSC) /* Windows 7 does this during bootup. See @bugref{6398}. */
case MSR_IA32_SYSENTER_EIP: pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_GUEST_SYSENTER_EIP_MSR; break;
case MSR_IA32_SYSENTER_ESP: pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_GUEST_SYSENTER_ESP_MSR; break;
#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:
return VERR_VMX_UNEXPECTED_EXIT_CODE;
case MSR_K8_LSTAR:
case MSR_K6_STAR:
case MSR_K8_SF_MASK:
case MSR_K8_TSC_AUX:
case MSR_K8_KERNEL_GS_BASE:
AssertMsgFailed(("Unexpected WRMSR for an MSR in the auto-load/store area in the VMCS. ecx=%#RX32\n",
return VERR_VMX_UNEXPECTED_EXIT_CODE;
return rc;
return VERR_EM_INTERPRETER;
return VERR_VMX_UNEXPECTED_EXIT_CODE;
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()->hmR0VmxInjectEvent() 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)]);
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;
rc |= hmR0VmxSaveGuestControlRegs(pVCpu, pMixedCtx); /* CR0 checks & PGM* in EMInterpretDisasCurrent(). */
rc |= 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 (fIOWrite)
if (fIOWrite)
HMR0SavePendingIOPortWrite(pVCpu, pMixedCtx->rip, pMixedCtx->rip + cbInstr, uIOPort, uAndVal, cbSize);
HMR0SavePendingIOPortRead(pVCpu, pMixedCtx->rip, pMixedCtx->rip + cbInstr, uIOPort, uAndVal, cbSize);
#ifdef DEBUG
return rc;
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_STOP;
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. */
pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS
return rc;
return VERR_VMX_UNEXPECTED_EXIT_CODE;
#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, see
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);
pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS
return VINF_SUCCESS;
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));
Log(("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);
pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS
return VINF_SUCCESS;
return rc;
return VERR_EM_INTERPRETER;
hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntrInfo),
return rc;
hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntrInfo),
return rc;
/* DR6, DR7.GD and IA32_DEBUGCTL.LBR are not updated yet. See Intel spec. 27.1 "Architectural State before a VM-Exit". */
hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntrInfo),
return rc;
#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
return VINF_SUCCESS;
hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntrInfo),
return rc;
#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. */
Log(("#GP Gst: RIP %#RX64 ErrorCode=%#x CR0=%#RX64 CPL=%u\n", pMixedCtx->rip, pVmxTransient->uExitIntrErrorCode,
hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntrInfo),
return rc;
return VERR_VMX_UNEXPECTED_EXCEPTION;
Log(("#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);
pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS;
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);
pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_SEGMENT_REGS | HM_CHANGED_GUEST_RSP
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;
/* 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->uExitIntrInfo),
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->uExitIntrInfo),
return rc;
#ifdef VBOX_HM_WITH_GUEST_PATCHING
if (!pPatch)
return VINF_EM_HM_PATCH_TPR_INSTR;
Log(("#PF: cr2=%#RX64 cs:rip=%#04x:%#RX64 uErrCode %#RX32 cr3=%#RX64\n", pVmxTransient->uExitQualification, pMixedCtx->cs.Sel,
TRPMAssertXcptPF(pVCpu, pVmxTransient->uExitQualification, (RTGCUINT)pVmxTransient->uExitIntrErrorCode);
pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP | HM_CHANGED_GUEST_RFLAGS
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->uExitIntrInfo),
return VINF_SUCCESS;
return rc;