HWVMXR0.cpp revision 96be842aaed828957a6671643c1558f2f2c07df7
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * HWACCM VMX - Host Context Ring 0.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * Copyright (C) 2006 InnoTek Systemberatung GmbH
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * available from http://www.virtualbox.org. This file is free software;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * you can redistribute it and/or modify it under the terms of the GNU
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * General Public License as published by the Free Software Foundation,
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * distribution. VirtualBox OSE is distributed in the hope that it will
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * be useful, but WITHOUT ANY WARRANTY of any kind.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * If you received this file as part of a commercial VirtualBox
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * distribution, then only the terms of your commercial VirtualBox
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * license agreement apply instead of the previous paragraph.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync/*******************************************************************************
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync* Header Files *
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync*******************************************************************************/
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync/* IO operation lookup arrays. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsyncstatic uint32_t aIOOpAnd[4] = {0xff, 0xffff, 0, 0xffffffff};
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * Sets up and activates VMX
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * @returns VBox status code.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * @param pVM The VM to operate on.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /* Setup Intel VMX. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /* Set revision dword at the beginning of both structures. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync *(uint32_t *)pVM->hwaccm.s.vmx.pVMCS = MSR_IA32_VMX_BASIC_INFO_VMCS_ID(pVM->hwaccm.s.vmx.msr.vmx_basic_info);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync *(uint32_t *)pVM->hwaccm.s.vmx.pVMXON = MSR_IA32_VMX_BASIC_INFO_VMCS_ID(pVM->hwaccm.s.vmx.msr.vmx_basic_info);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /* @todo we should unmap the two pages from the virtual address space in order to prevent accidental corruption.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * (which can have very bad consequences!!!)
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /* Make sure the VMX instructions don't cause #UD faults. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /* Enter VMX Root Mode */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /* Clear VM Control Structure. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /* Activate the VM Control Structure. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /* VMX_VMCS_CTRL_PIN_EXEC_CONTROLS
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * Set required bits to one and zero according to the MSR capabilities.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync val = (pVM->hwaccm.s.vmx.msr.vmx_pin_ctls & 0xFFFFFFFF);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /* External and non-maskable interrupts cause VM-exits. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync val = val | VMX_VMCS_CTRL_PIN_EXEC_CONTROLS_EXT_INT_EXIT | VMX_VMCS_CTRL_PIN_EXEC_CONTROLS_NMI_EXIT;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync val &= (pVM->hwaccm.s.vmx.msr.vmx_pin_ctls >> 32ULL);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync rc = VMXWriteVMCS(VMX_VMCS_CTRL_PIN_EXEC_CONTROLS, val);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /* VMX_VMCS_CTRL_PROC_EXEC_CONTROLS
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * Set required bits to one and zero according to the MSR capabilities.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync val = (pVM->hwaccm.s.vmx.msr.vmx_proc_ctls & 0xFFFFFFFF);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /* Program which event cause VM-exits and which features we want to use. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync val = val | VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_HLT_EXIT
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync | VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_MWAIT_EXIT; /* don't execute mwait or else we'll idle inside the guest (host thinks the cpu load is high) */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /** @note VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_MWAIT_EXIT might cause a vmlaunch failure with an invalid control fields error. (combined with some other exit reasons) */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync if AMD64 guest mode
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync val |= VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_CR8_LOAD_EXIT
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync | VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_CR8_STORE_EXIT;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /* Mask away the bits that the CPU doesn't support */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /** @todo make sure they don't conflict with the above requirements. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync val &= (pVM->hwaccm.s.vmx.msr.vmx_proc_ctls >> 32ULL);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync rc = VMXWriteVMCS(VMX_VMCS_CTRL_PROC_EXEC_CONTROLS, val);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /* VMX_VMCS_CTRL_CR3_TARGET_COUNT
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * Set required bits to one and zero according to the MSR capabilities.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync rc = VMXWriteVMCS(VMX_VMCS_CTRL_CR3_TARGET_COUNT, 0);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /* VMX_VMCS_CTRL_ENTRY_CONTROLS
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * Set required bits to one and zero according to the MSR capabilities.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync val = (pVM->hwaccm.s.vmx.msr.vmx_entry & 0xFFFFFFFF);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync if (pVM->hwaccm.s.cpuid.u32AMDFeatureEDX & X86_CPUID_AMD_FEATURE_EDX_LONG_MODE)
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /** @todo 32 bits guest mode only for now. */
d1d4bf58f99da14d0aaa7bcc728a359c8a7eb7bdvboxsync /* val |= VMX_VMCS_CTRL_ENTRY_CONTROLS_IA64_MODE; */
d1d4bf58f99da14d0aaa7bcc728a359c8a7eb7bdvboxsync /* Mask away the bits that the CPU doesn't support */
d1d4bf58f99da14d0aaa7bcc728a359c8a7eb7bdvboxsync /** @todo make sure they don't conflict with the above requirements. */
d1d4bf58f99da14d0aaa7bcc728a359c8a7eb7bdvboxsync /* else Must be zero when AMD64 is not available. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync rc = VMXWriteVMCS(VMX_VMCS_CTRL_ENTRY_CONTROLS, val);
/* Clear VM Control Structure. Marking it inactive, clearing implementation specific data and writing back VMCS data to memory. */
VMXDisable();
return rc;
static int VMXR0InjectEvent(PVM pVM, CPUMCTX *pCtx, uint32_t intInfo, uint32_t cbInstr, uint32_t errCode)
int rc;
#ifdef VBOX_STRICT
Log2(("VMXR0InjectEvent: Injecting interrupt %d at %VGv error code=%08x CR2=%08x intInfo=%08x\n", iGate, pCtx->eip, errCode, pCtx->cr2, intInfo));
Log2(("VMXR0InjectEvent: Injecting interrupt %d at %VGv error code=%08x\n", iGate, pCtx->eip, errCode));
return rc;
int rc;
Log(("Reinjecting event %VX64 %08x at %VGv\n", pVM->hwaccm.s.Event.intInfo, pVM->hwaccm.s.Event.errCode, pCtx->eip));
return VINF_SUCCESS;
rc = VMXWriteVMCS(VMX_VMCS_CTRL_PROC_EXEC_CONTROLS, pVM->hwaccm.s.vmx.proc_ctls | VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_IRQ_WINDOW_EXIT);
AssertFailed();
return VINF_EM_RAW_INTERRUPT_PENDING;
#ifdef VBOX_STRICT
int rc;
bool fSoftwareInt;
switch (u8Vector) {
return VINF_SUCCESS;
/** @note VMX is (again) very picky about the RPL of the selectors here; we'll restore them manually. */
return VERR_VMX_INVALID_HOST_STATE;
return rc;
/* Also catch floating point exceptions as we need to report them to the guest in a different way. */
val |= X86_CR0_NE; /* always turn on the native mechanism to report FPU errors (old style uses interrupts) */
| X86_CR0_MP;
case PGMMODE_REAL:
AssertFailed();
AssertFailed();
AssertFailed();
| X86_CR4_VMXE;
#ifdef VBOX_STRICT
return rc;
* @note NEVER EVER turn on interrupts here. Due to our illegal entry into the kernel, it might mess things up. (XP kernel traps have been frequently observed)
#ifdef VBOX_STRICT
if ((val & (pVM->hwaccm.s.vmx.msr.vmx_pin_ctls & 0xFFFFFFFF)) != (pVM->hwaccm.s.vmx.msr.vmx_pin_ctls & 0xFFFFFFFF))
if ((val & (pVM->hwaccm.s.vmx.msr.vmx_proc_ctls & 0xFFFFFFFF)) != (pVM->hwaccm.s.vmx.msr.vmx_proc_ctls & 0xFFFFFFFF))
if ((val & (pVM->hwaccm.s.vmx.msr.vmx_entry & 0xFFFFFFFF)) != (pVM->hwaccm.s.vmx.msr.vmx_entry & 0xFFFFFFFF))
if ((val & (pVM->hwaccm.s.vmx.msr.vmx_exit & 0xFFFFFFFF)) != (pVM->hwaccm.s.vmx.msr.vmx_exit & 0xFFFFFFFF))
Log(("VM_FF_INHIBIT_INTERRUPTS at %VGv successor %VGv\n", pCtx->eip, EMGetInhibitInterruptsPC(pVM)));
* Before we are able to execute this instruction in raw mode (iret to guest code) an external interrupt might
* force a world switch again. Possibly allowing a guest interrupt to be dispatched in the process. This could
* break the guest. Sounds very unlikely, but such timing sensitive problem are not as rare as you might think.
goto end;
/* Pending request packets might contain actions that need immediate attention, such as pending hardware interrupts. */
goto end;
goto end;
goto end;
goto end;
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
* IMPORTANT: WE CAN'T DO ANY LOGGING OR OPERATIONS THAT CAN DO A LONGJMP BACK TO RING 3 *BEFORE* WE'VE SYNCED BACK (MOST OF) THE GUEST STATE
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
switch (rc)
case VINF_SUCCESS:
AssertFailed();
goto end;
#ifdef VBOX_STRICT
int rc1;
Log(("Unable to start/resume VM for reason: %x. Instruction error %x\n", (uint32_t)exitReason, (uint32_t)instrError));
goto end;
AssertFailed();
goto end;
if (uInterruptState != 0)
&& VMX_EXIT_INTERRUPTION_INFO_TYPE(pVM->hwaccm.s.Event.intInfo) != VMX_EXIT_INTERRUPTION_INFO_TYPE_SW)
Log(("Pending inject %VX64 at %08x exit=%08x intInfo=%08x exitQualification=%08x\n", pVM->hwaccm.s.Event.intInfo, pCtx->eip, exitReason, intInfo, exitQualification));
#ifdef VBOX_STRICT
switch (exitReason)
switch (vector)
case X86_XCPT_NM:
/* If we sync the FPU/XMM state on-demand, then we can continue execution as if nothing has happened. */
goto ResumeExecution;
rc = VMXR0InjectEvent(pVM, pCtx, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(intInfo), cbInstr, 0);
goto ResumeExecution;
Log2(("Shadow page fault at %VGv cr2=%VGv error code %x\n", pCtx->eip, exitQualification ,errCode));
goto ResumeExecution;
rc = VMXR0InjectEvent(pVM, pCtx, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(intInfo), cbInstr, errCode);
goto ResumeExecution;
#ifdef VBOX_STRICT
rc = VMXR0InjectEvent(pVM, pCtx, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(intInfo), cbInstr, errCode);
goto ResumeExecution;
#ifdef VBOX_STRICT
switch(vector)
case X86_XCPT_DE:
case X86_XCPT_UD:
case X86_XCPT_SS:
case X86_XCPT_NP:
case X86_XCPT_GP:
rc = VMXR0InjectEvent(pVM, pCtx, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(intInfo), cbInstr, errCode);
goto ResumeExecution;
AssertFailed();
goto ResumeExecution;
goto ResumeExecution;
goto ResumeExecution;
Log2(("VMX: %VGv mov cr%d, x\n", pCtx->eip, VMX_EXIT_QUALIFICATION_CRX_REGISTER(exitQualification)));
AssertFailed();
rc = PGMSyncCR3(pVM, CPUMGetGuestCR0(pVM), CPUMGetGuestCR3(pVM), CPUMGetGuestCR4(pVM), VM_FF_ISSET(pVM, VM_FF_PGM_SYNC_CR3));
goto ResumeExecution;
/** @todo clear VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_MOV_DR_EXIT after the first time and restore drx registers afterwards */
if (VMX_EXIT_QUALIFICATION_DRX_DIRECTION(exitQualification) == VMX_EXIT_QUALIFICATION_DRX_DIRECTION_WRITE)
Log2(("VMX: mov drx%d, genreg%d\n", VMX_EXIT_QUALIFICATION_DRX_REGISTER(exitQualification), VMX_EXIT_QUALIFICATION_DRX_GENREG(exitQualification)));
goto ResumeExecution;
/** @note We'll get a #GP if the IO instruction isn't allowed (IOPL or TSS bitmap); no need to double check. */
if (VMX_EXIT_QUALIFICATION_IO_DIRECTION(exitQualification) == VMX_EXIT_QUALIFICATION_IO_DIRECTION_OUT)
goto ResumeExecution;
rc = (VMX_EXIT_QUALIFICATION_IO_DIRECTION(exitQualification) == VMX_EXIT_QUALIFICATION_IO_DIRECTION_OUT)
CPUMSetChangedFlags(pVM, CPUM_CHANGED_SYSENTER_MSR | CPUM_CHANGED_LDTR | CPUM_CHANGED_GDTR | CPUM_CHANGED_IDTR | CPUM_CHANGED_TR | CPUM_CHANGED_HIDDEN_SEL_REGS);
switch (exitReason)
goto ResumeExecution;
AssertMsg(rc == VINF_PGM_CHANGE_MODE || rc == VINF_EM_RAW_INTERRUPT || rc == VINF_EM_RAW_EMULATE_INSTR || rc == VINF_PGM_SYNC_CR3 || rc == VINF_IOM_HC_IOPORT_READ || rc == VINF_IOM_HC_IOPORT_WRITE || rc == VINF_IOM_HC_IOPORT_READWRITE, ("rc = %d\n", rc));
end:
/* If we executed vmlaunch/vmresume and an external irq was pending, then we don't have to do a full sync the next time. */
return rc;
return rc;
VMXDisable();
return rc;
return VINF_SUCCESS;
/* Clear VM Control Structure. Marking it inactive, clearing implementation specific data and writing back VMCS data to memory. */
VMXDisable();
return VINF_SUCCESS;