HWACCMAll.cpp revision 9d3a67e18530df6b3b88973dea3b32c08a07da1f
8c856c56f1af112768c672456af69561265f1fddvboxsync/* $Id$ */
8c856c56f1af112768c672456af69561265f1fddvboxsync/** @file
8c856c56f1af112768c672456af69561265f1fddvboxsync * HWACCM - All contexts.
8c856c56f1af112768c672456af69561265f1fddvboxsync */
8c856c56f1af112768c672456af69561265f1fddvboxsync
8c856c56f1af112768c672456af69561265f1fddvboxsync/*
8c856c56f1af112768c672456af69561265f1fddvboxsync * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8c856c56f1af112768c672456af69561265f1fddvboxsync *
8c856c56f1af112768c672456af69561265f1fddvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
8c856c56f1af112768c672456af69561265f1fddvboxsync * available from http://www.virtualbox.org. This file is free software;
8c856c56f1af112768c672456af69561265f1fddvboxsync * you can redistribute it and/or modify it under the terms of the GNU
8c856c56f1af112768c672456af69561265f1fddvboxsync * General Public License (GPL) as published by the Free Software
8c856c56f1af112768c672456af69561265f1fddvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
8c856c56f1af112768c672456af69561265f1fddvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
8c856c56f1af112768c672456af69561265f1fddvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
8c856c56f1af112768c672456af69561265f1fddvboxsync *
8c856c56f1af112768c672456af69561265f1fddvboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
8c856c56f1af112768c672456af69561265f1fddvboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
8c856c56f1af112768c672456af69561265f1fddvboxsync * additional information or have any questions.
8c856c56f1af112768c672456af69561265f1fddvboxsync */
8c856c56f1af112768c672456af69561265f1fddvboxsync
8c856c56f1af112768c672456af69561265f1fddvboxsync
8c856c56f1af112768c672456af69561265f1fddvboxsync/*******************************************************************************
8c856c56f1af112768c672456af69561265f1fddvboxsync* Header Files *
8c856c56f1af112768c672456af69561265f1fddvboxsync*******************************************************************************/
8c856c56f1af112768c672456af69561265f1fddvboxsync#define LOG_GROUP LOG_GROUP_HWACCM
8c856c56f1af112768c672456af69561265f1fddvboxsync#include <VBox/hwaccm.h>
8c856c56f1af112768c672456af69561265f1fddvboxsync#include "HWACCMInternal.h"
8c856c56f1af112768c672456af69561265f1fddvboxsync#include <VBox/vm.h>
8c856c56f1af112768c672456af69561265f1fddvboxsync#include <VBox/x86.h>
8c856c56f1af112768c672456af69561265f1fddvboxsync#include <VBox/hwacc_vmx.h>
8c856c56f1af112768c672456af69561265f1fddvboxsync#include <VBox/hwacc_svm.h>
8c856c56f1af112768c672456af69561265f1fddvboxsync#include <VBox/pgm.h>
8c856c56f1af112768c672456af69561265f1fddvboxsync#include <VBox/pdm.h>
8c856c56f1af112768c672456af69561265f1fddvboxsync#include <VBox/err.h>
8c856c56f1af112768c672456af69561265f1fddvboxsync#include <VBox/log.h>
8c856c56f1af112768c672456af69561265f1fddvboxsync#include <VBox/selm.h>
8c856c56f1af112768c672456af69561265f1fddvboxsync#include <VBox/iom.h>
8c856c56f1af112768c672456af69561265f1fddvboxsync#include <iprt/param.h>
8c856c56f1af112768c672456af69561265f1fddvboxsync#include <iprt/assert.h>
8c856c56f1af112768c672456af69561265f1fddvboxsync#include <iprt/asm.h>
8c856c56f1af112768c672456af69561265f1fddvboxsync#include <iprt/string.h>
8c856c56f1af112768c672456af69561265f1fddvboxsync#include <iprt/memobj.h>
8c856c56f1af112768c672456af69561265f1fddvboxsync#include <iprt/cpuset.h>
8c856c56f1af112768c672456af69561265f1fddvboxsync
8c856c56f1af112768c672456af69561265f1fddvboxsync/**
8c856c56f1af112768c672456af69561265f1fddvboxsync * Queues a page for invalidation
8c856c56f1af112768c672456af69561265f1fddvboxsync *
8c856c56f1af112768c672456af69561265f1fddvboxsync * @returns VBox status code.
8c856c56f1af112768c672456af69561265f1fddvboxsync * @param pVCpu The VMCPU to operate on.
8c856c56f1af112768c672456af69561265f1fddvboxsync * @param GCVirt Page to invalidate
8c856c56f1af112768c672456af69561265f1fddvboxsync */
8c856c56f1af112768c672456af69561265f1fddvboxsyncvoid hwaccmQueueInvlPage(PVMCPU pVCpu, RTGCPTR GCVirt)
8c856c56f1af112768c672456af69561265f1fddvboxsync{
8c856c56f1af112768c672456af69561265f1fddvboxsync /* Nothing to do if a TLB flush is already pending */
8c856c56f1af112768c672456af69561265f1fddvboxsync if (VMCPU_FF_ISSET(pVCpu, VMCPU_FF_TLB_FLUSH))
8c856c56f1af112768c672456af69561265f1fddvboxsync return;
8c856c56f1af112768c672456af69561265f1fddvboxsync#if 1
8c856c56f1af112768c672456af69561265f1fddvboxsync VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
8c856c56f1af112768c672456af69561265f1fddvboxsync#else
8c856c56f1af112768c672456af69561265f1fddvboxsync if (iPage == RT_ELEMENTS(pVCpu->hwaccm.s.TlbShootdown.aPages))
8c856c56f1af112768c672456af69561265f1fddvboxsync VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
8c856c56f1af112768c672456af69561265f1fddvboxsync else
8c856c56f1af112768c672456af69561265f1fddvboxsync VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_SHOOTDOWN);
8c856c56f1af112768c672456af69561265f1fddvboxsync#endif
8c856c56f1af112768c672456af69561265f1fddvboxsync}
8c856c56f1af112768c672456af69561265f1fddvboxsync
/**
* Invalidates a guest page
*
* @returns VBox status code.
* @param pVCpu The VMCPU to operate on.
* @param GCVirt Page to invalidate
*/
VMMDECL(int) HWACCMInvalidatePage(PVMCPU pVCpu, RTGCPTR GCVirt)
{
STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatFlushPageManual);
#ifdef IN_RING0
PVM pVM = pVCpu->CTX_SUFF(pVM);
if (pVM->hwaccm.s.vmx.fSupported)
return VMXR0InvalidatePage(pVM, pVCpu, GCVirt);
Assert(pVM->hwaccm.s.svm.fSupported);
return SVMR0InvalidatePage(pVM, pVCpu, GCVirt);
#endif
hwaccmQueueInvlPage(pVCpu, GCVirt);
return VINF_SUCCESS;
}
/**
* Flushes the guest TLB
*
* @returns VBox status code.
* @param pVCpu The VMCPU to operate on.
*/
VMMDECL(int) HWACCMFlushTLB(PVMCPU pVCpu)
{
LogFlow(("HWACCMFlushTLB\n"));
VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatFlushTLBManual);
return VINF_SUCCESS;
}
#ifndef IN_RC
/**
* Invalidates a guest page on all VCPUs.
*
* @returns VBox status code.
* @param pVM The VM to operate on.
* @param GCVirt Page to invalidate
*/
VMMDECL(int) HWACCMInvalidatePageOnAllVCpus(PVM pVM, RTGCPTR GCPtr)
{
VMCPUID idCurCpu = VMMGetCpuId(pVM);
for (unsigned idCpu = 0; idCpu < pVM->cCPUs; idCpu++)
{
PVMCPU pVCpu = &pVM->aCpus[idCpu];
if (pVCpu->idCpu == idCurCpu)
{
HWACCMInvalidatePage(pVCpu, GCPtr);
}
else
{
hwaccmQueueInvlPage(pVCpu, GCPtr);
if (VMCPU_GET_STATE(pVCpu) == VMCPUSTATE_STARTED_EXEC)
{
STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatTlbShootdown);
#ifdef IN_RING0
RTCPUID idHostCpu = pVCpu->idHostCpu;
if (idHostCpu != NIL_RTCPUID)
RTMpPokeCpu(idHostCpu);
#else
VMR3NotifyCpuFFU(pVCpu->pUVCpu, VMNOTIFYFF_FLAGS_POKE);
#endif
}
else
STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatFlushPageManual);
}
}
return VINF_SUCCESS;
}
/**
* Flush the TLBs of all VCPUs
*
* @returns VBox status code.
* @param pVM The VM to operate on.
*/
VMMDECL(int) HWACCMFlushTLBOnAllVCpus(PVM pVM)
{
if (pVM->cCPUs == 1)
return HWACCMFlushTLB(&pVM->aCpus[0]);
VMCPUID idThisCpu = VMMGetCpuId(pVM);
for (unsigned idCpu = 0; idCpu < pVM->cCPUs; idCpu++)
{
PVMCPU pVCpu = &pVM->aCpus[idCpu];
VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
if (idThisCpu == idCpu)
continue;
if (VMCPU_GET_STATE(pVCpu) == VMCPUSTATE_STARTED_EXEC)
{
STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatTlbShootdownFlush);
#ifdef IN_RING0
RTCPUID idHostCpu = pVCpu->idHostCpu;
if (idHostCpu != NIL_RTCPUID)
RTMpPokeCpu(idHostCpu);
#else
VMR3NotifyCpuFFU(pVCpu->pUVCpu, VMNOTIFYFF_FLAGS_POKE);
#endif
}
else
STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatFlushTLBManual);
}
return VINF_SUCCESS;
}
#endif
/**
* Checks if nested paging is enabled
*
* @returns boolean
* @param pVM The VM to operate on.
*/
VMMDECL(bool) HWACCMIsNestedPagingActive(PVM pVM)
{
return HWACCMIsEnabled(pVM) && pVM->hwaccm.s.fNestedPaging;
}
/**
* Return the shadow paging mode for nested paging/ept
*
* @returns shadow paging mode
* @param pVM The VM to operate on.
*/
VMMDECL(PGMMODE) HWACCMGetShwPagingMode(PVM pVM)
{
Assert(HWACCMIsNestedPagingActive(pVM));
if (pVM->hwaccm.s.svm.fSupported)
return PGMMODE_NESTED;
Assert(pVM->hwaccm.s.vmx.fSupported);
return PGMMODE_EPT;
}
/**
* Invalidates a guest page by physical address
*
* NOTE: Assumes the current instruction references this physical page though a virtual address!!
*
* @returns VBox status code.
* @param pVM The VM to operate on.
* @param GCPhys Page to invalidate
*/
VMMDECL(int) HWACCMInvalidatePhysPage(PVM pVM, RTGCPHYS GCPhys)
{
if (!HWACCMIsNestedPagingActive(pVM))
return VINF_SUCCESS;
#ifdef IN_RING0
if (pVM->hwaccm.s.vmx.fSupported)
{
VMCPUID idThisCpu = VMMGetCpuId(pVM);
for (unsigned idCpu = 0; idCpu < pVM->cCPUs; idCpu++)
{
PVMCPU pVCpu = &pVM->aCpus[idCpu];
if (idThisCpu == idCpu)
{
VMXR0InvalidatePhysPage(pVM, pVCpu, GCPhys);
continue;
}
VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
if (VMCPU_GET_STATE(pVCpu) == VMCPUSTATE_STARTED_EXEC)
{
STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatTlbShootdownFlush);
#ifdef IN_RING0
RTCPUID idHostCpu = pVCpu->idHostCpu;
if (idHostCpu != NIL_RTCPUID)
RTMpPokeCpu(idHostCpu);
#else
VMR3NotifyCpuFFU(pVCpu->pUVCpu, VMNOTIFYFF_FLAGS_POKE);
#endif
}
else
STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatFlushTLBManual);
}
return VINF_SUCCESS;
}
Assert(pVM->hwaccm.s.svm.fSupported);
/* AMD-V doesn't support invalidation with guest physical addresses; see comment in SVMR0InvalidatePhysPage. */
HWACCMFlushTLBOnAllVCpus(pVM);
#else
HWACCMFlushTLBOnAllVCpus(pVM);
#endif
return VINF_SUCCESS;
}
/**
* Checks if an interrupt event is currently pending.
*
* @returns Interrupt event pending state.
* @param pVM The VM to operate on.
*/
VMMDECL(bool) HWACCMHasPendingIrq(PVM pVM)
{
PVMCPU pVCpu = VMMGetCpu(pVM);
return !!pVCpu->hwaccm.s.Event.fPending;
}