HMSVMR0.cpp revision 41f7107d7ff19a04c836fa8a7079edb6f6c00047
/* $Id$ */
/** @file
* HM SVM (AMD-V) - Host Context Ring-0.
*/
/*
* Copyright (C) 2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#ifdef DEBUG_ramshankar
# define HMSVM_ALWAYS_TRAP_ALL_XCPTS
# define HMSVM_ALWAYS_TRAP_PF
#endif
/*******************************************************************************
* Internal Functions *
*******************************************************************************/
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
/*******************************************************************************
* Global Variables *
*******************************************************************************/
/** Ring-0 memory object for the IO bitmap. */
/** Physical address of the IO bitmap. */
RTHCPHYS g_HCPhysIOBitmap = 0;
/** Virtual address of the IO bitmap. */
/**
* Sets up and activates AMD-V on the current CPU.
*
* @returns VBox status code.
* @param pCpu Pointer to the CPU info struct.
* @param pVM Pointer to the VM (can be NULL after a resume!).
* @param pvCpuPage Pointer to the global CPU page.
* @param HCPhysCpuPage Physical address of the global CPU page.
*/
VMMR0DECL(int) SVMR0EnableCpu(PHMGLOBLCPUINFO pCpu, PVM pVM, void *pvCpuPage, RTHCPHYS HCPhysCpuPage, bool fEnabledByHost)
{
/*
* We must turn on AMD-V and setup the host state physical address, as those MSRs are per CPU.
*/
if (u64HostEfer & MSR_K6_EFER_SVME)
{
/* If the VBOX_HWVIRTEX_IGNORE_SVM_IN_USE is active, then we blindly use AMD-V. */
if ( pVM
{
pCpu->fIgnoreAMDVInUseError = true;
}
if (!pCpu->fIgnoreAMDVInUseError)
return VERR_SVM_IN_USE;
}
/* Turn on AMD-V in the EFER MSR. */
/* Write the physical page address where the CPU will store the host state while executing the VM. */
/*
* Theoretically, other hypervisors may have used ASIDs, ideally we should flush all non-zero ASIDs
* when enabling SVM. AMD doesn't have an SVM instruction to flush all ASIDs (flushing is done
* upon VMRUN). Therefore, just set the fFlushAsidBeforeUse flag which instructs hmR0SvmSetupTLB()
* to flush the TLB with before using a new ASID.
*/
pCpu->fFlushAsidBeforeUse = true;
/*
* Ensure each VCPU scheduled on this CPU gets a new VPID on resume. See @bugref{6255}.
*/
++pCpu->cTlbFlushes;
return VINF_SUCCESS;
}
/**
* Deactivates AMD-V on the current CPU.
*
* @returns VBox status code.
* @param pCpu Pointer to the CPU info struct.
* @param pvCpuPage Pointer to the global CPU page.
* @param HCPhysCpuPage Physical address of the global CPU page.
*/
{
/* Turn off AMD-V in the EFER MSR if AMD-V is active. */
if (u64HostEfer & MSR_K6_EFER_SVME)
{
/* Invalidate host state physical address. */
}
return VINF_SUCCESS;
}
/**
* Does global AMD-V initialization (called during module initialization).
*
* @returns VBox status code.
*/
VMMR0DECL(int) SVMR0GlobalInit(void)
{
/*
* Allocate 12 KB for the IO bitmap. Since this is non-optional and we always intercept all IO accesses, it's done
* once globally here instead of per-VM.
*/
if (RT_FAILURE(rc))
return rc;
/* Set all bits to intercept all IO accesses. */
}
/**
* Does global VT-x termination (called during module termination).
*/
VMMR0DECL(void) SVMR0GlobalTerm(void)
{
if (g_hMemObjIOBitmap != NIL_RTR0MEMOBJ)
{
g_pvIOBitmap = NULL;
g_HCPhysIOBitmap = 0;
}
}
/**
* Frees any allocated per-VCPU structures for a VM.
*
* @param pVM Pointer to the VM.
*/
{
{
{
}
{
}
{
}
}
}
/**
* Does per-VM AMD-V initialization.
*
* @returns VBox status code.
* @param pVM Pointer to the VM.
*/
{
int rc = VERR_INTERNAL_ERROR_5;
/* Check for an AMD CPU erratum which requires us to flush the TLB before every world-switch. */
{
Log(("SVMR0InitVM: AMD cpu with erratum 170 family %#x model %#x stepping %#x\n", u32Family, u32Model, u32Stepping));
}
/* Initialize the memory objects up-front so we can cleanup on allocation failures properly. */
{
}
/* Allocate a VMCB for each VCPU. */
{
/* Allocate one page for the host context */
rc = RTR0MemObjAllocCont(&pVCpu->hm.s.svm.hMemObjVmcbHost, 1 << PAGE_SHIFT, false /* fExecutable */);
if (RT_FAILURE(rc))
goto failure_cleanup;
pVCpu->hm.s.svm.HCPhysVmcbHost = RTR0MemObjGetPagePhysAddr(pVCpu->hm.s.svm.hMemObjVmcbHost, 0 /* iPage */);
/* Allocate one page for the VM control block (VMCB). */
if (RT_FAILURE(rc))
goto failure_cleanup;
/* Allocate 8 KB for the MSR bitmap (doesn't seem to be a way to convince SVM not to use it) */
rc = RTR0MemObjAllocCont(&pVCpu->hm.s.svm.hMemObjMsrBitmap, 2 << PAGE_SHIFT, false /* fExecutable */);
if (RT_FAILURE(rc))
pVCpu->hm.s.svm.HCPhysMsrBitmap = RTR0MemObjGetPagePhysAddr(pVCpu->hm.s.svm.hMemObjMsrBitmap, 0 /* iPage */);
/* Set all bits to intercept all MSR accesses. */
}
return VINF_SUCCESS;
return rc;
}
/**
* Does per-VM AMD-V termination.
*
* @returns VBox status code.
* @param pVM Pointer to the VM.
*/
{
return VINF_SUCCESS;
}
/**
* Sets up AMD-V for the specified VM.
* This function is only called once per-VM during initalization.
*
* @returns VBox status code.
* @param pVM Pointer to the VM.
*/
{
int rc = VINF_SUCCESS;
{
/* Intercept traps. */
#ifdef HMSVM_ALWAYS_TRAP_PF
#endif
#ifdef HMSVM_ALWAYS_TRAP_ALL_XCPTS
| RT_BIT(X86_XCPT_PF);
#endif
/* -XXX- todo. */
}
return rc;
}