MMRamGC.cpp revision d099ccfb66d26601f93e7967e8e73cee4b9c62df
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync/* $Id$ */
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync/** @file
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync * MMRamGC - Guest Context Ram access Routines, pair for MMRamGCA.asm.
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsync */
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync/*
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync * Copyright (C) 2006-2007 Sun Microsystems, Inc.
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync *
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync * available from http://www.virtualbox.org. This file is free software;
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync * you can redistribute it and/or modify it under the terms of the GNU
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync * General Public License (GPL) as published by the Free Software
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync *
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync * additional information or have any questions.
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync */
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync/*******************************************************************************
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync* Header Files *
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync*******************************************************************************/
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync#define LOG_GROUP LOG_GROUP_MM
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync#include <VBox/mm.h>
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync#include <VBox/cpum.h>
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync#include <VBox/trpm.h>
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync#include <VBox/em.h>
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync#include "MMInternal.h"
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync#include <VBox/vm.h>
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync#include <VBox/vmm.h>
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync#include <VBox/pgm.h>
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync#include <iprt/assert.h>
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync#include <VBox/param.h>
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsync#include <VBox/err.h>
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsync
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsync
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsync/*******************************************************************************
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsync* Internal Functions *
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsync*******************************************************************************/
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsyncstatic DECLCALLBACK(int) mmGCRamTrap0eHandler(PVM pVM, PCPUMCTXCORE pRegFrame);
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsync
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsyncDECLASM(void) MMGCRamReadNoTrapHandler_EndProc(void);
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsyncDECLASM(void) MMGCRamWriteNoTrapHandler_EndProc(void);
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsyncDECLASM(void) EMGCEmulateLockCmpXchg_EndProc(void);
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsyncDECLASM(void) EMGCEmulateLockCmpXchg_Error(void);
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsyncDECLASM(void) EMGCEmulateCmpXchg_EndProc(void);
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsyncDECLASM(void) EMGCEmulateCmpXchg_Error(void);
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsyncDECLASM(void) EMGCEmulateLockCmpXchg8b_EndProc(void);
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsyncDECLASM(void) EMGCEmulateLockCmpXchg8b_Error(void);
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsyncDECLASM(void) EMGCEmulateCmpXchg8b_EndProc(void);
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsyncDECLASM(void) EMGCEmulateCmpXchg8b_Error(void);
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsyncDECLASM(void) EMGCEmulateLockXAdd_EndProc(void);
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsyncDECLASM(void) EMGCEmulateLockXAdd_Error(void);
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsyncDECLASM(void) EMGCEmulateXAdd_EndProc(void);
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsyncDECLASM(void) EMGCEmulateXAdd_Error(void);
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsyncDECLASM(void) EMEmulateLockOr_EndProc(void);
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsyncDECLASM(void) EMEmulateLockOr_Error(void);
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsyncDECLASM(void) EMEmulateLockBtr_EndProc(void);
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsyncDECLASM(void) EMEmulateLockBtr_Error(void);
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsyncDECLASM(void) MMGCRamRead_Error(void);
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsyncDECLASM(void) MMGCRamWrite_Error(void);
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsync
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsync
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsync/**
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsync * Install MMGCRam Hypervisor page fault handler for normal working
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsync * of MMGCRamRead and MMGCRamWrite calls.
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsync * This handler will be automatically removed at page fault.
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsync * In other case it must be removed by MMGCRamDeregisterTrapHandler call.
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsync *
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsync * @param pVM VM handle.
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsync */
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsyncVMMRCDECL(void) MMGCRamRegisterTrapHandler(PVM pVM)
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsync{
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync TRPMGCSetTempHandler(pVM, 0xe, mmGCRamTrap0eHandler);
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync}
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsync
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsync
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsync/**
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsync * Remove MMGCRam Hypervisor page fault handler.
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsync * See description of MMGCRamRegisterTrapHandler call.
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsync *
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsync * @param pVM VM handle.
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsync */
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsyncVMMRCDECL(void) MMGCRamDeregisterTrapHandler(PVM pVM)
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsync{
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsync TRPMGCSetTempHandler(pVM, 0xe, NULL);
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsync}
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsync
8a0e16a59a2c5ffeeac323e1842e65a4ddf3c5c1vboxsync
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync/**
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync * Read data in guest context with #PF control.
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync *
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync * @returns VBox status.
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync * @param pVM The VM handle.
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync * @param pDst Where to store the readed data.
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync * @param pSrc Pointer to the data to read.
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync * @param cb Size of data to read, only 1/2/4/8 is valid.
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync */
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsyncVMMRCDECL(int) MMGCRamRead(PVM pVM, void *pDst, void *pSrc, size_t cb)
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync{
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync int rc;
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync PVMCPU pVCpu = VMMGetCpu0(pVM);
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync TRPMSaveTrap(pVCpu); /* save the current trap info, because it will get trashed if our access failed. */
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync
49ff1fd14c340480f6f52f9dec52aabc630f7fd4vboxsync MMGCRamRegisterTrapHandler(pVM);
rc = MMGCRamReadNoTrapHandler(pDst, pSrc, cb);
MMGCRamDeregisterTrapHandler(pVM);
if (RT_FAILURE(rc))
TRPMRestoreTrap(pVCpu);
return rc;
}
/**
* Write data in guest context with #PF control.
*
* @returns VBox status.
* @param pVM The VM handle.
* @param pDst Where to write the data.
* @param pSrc Pointer to the data to write.
* @param cb Size of data to write, only 1/2/4 is valid.
*/
VMMRCDECL(int) MMGCRamWrite(PVM pVM, void *pDst, void *pSrc, size_t cb)
{
PVMCPU pVCpu = VMMGetCpu0(pVM);
TRPMSaveTrap(pVCpu); /* save the current trap info, because it will get trashed if our access failed. */
MMGCRamRegisterTrapHandler(pVM);
int rc = MMGCRamWriteNoTrapHandler(pDst, pSrc, cb);
MMGCRamDeregisterTrapHandler(pVM);
if (RT_FAILURE(rc))
TRPMRestoreTrap(pVCpu);
/*
* And mark the relevant guest page as accessed and dirty.
*/
PGMGstModifyPage(VMMGetCpu0(pVM), (RTGCPTR)(RTRCUINTPTR)pDst, cb, X86_PTE_A | X86_PTE_D, ~(uint64_t)(X86_PTE_A | X86_PTE_D));
return rc;
}
/**
* \#PF Handler for servicing traps inside MMGCRamReadNoTrapHandler and MMGCRamWriteNoTrapHandler functions.
*
* @internal
*/
DECLCALLBACK(int) mmGCRamTrap0eHandler(PVM pVM, PCPUMCTXCORE pRegFrame)
{
/*
* Page fault inside MMGCRamRead()? Resume at *_Error.
*/
if ( (uintptr_t)&MMGCRamReadNoTrapHandler < (uintptr_t)pRegFrame->eip
&& (uintptr_t)pRegFrame->eip < (uintptr_t)&MMGCRamReadNoTrapHandler_EndProc)
{
/* Must be a read violation. */
AssertReturn(!(TRPMGetErrorCode(VMMGetCpu0(pVM)) & X86_TRAP_PF_RW), VERR_INTERNAL_ERROR);
pRegFrame->eip = (uintptr_t)&MMGCRamRead_Error;
return VINF_SUCCESS;
}
/*
* Page fault inside MMGCRamWrite()? Resume at _Error.
*/
if ( (uintptr_t)&MMGCRamWriteNoTrapHandler < (uintptr_t)pRegFrame->eip
&& (uintptr_t)pRegFrame->eip < (uintptr_t)&MMGCRamWriteNoTrapHandler_EndProc)
{
/* Must be a write violation. */
AssertReturn(TRPMGetErrorCode(VMMGetCpu0(pVM)) & X86_TRAP_PF_RW, VERR_INTERNAL_ERROR);
pRegFrame->eip = (uintptr_t)&MMGCRamWrite_Error;
return VINF_SUCCESS;
}
/*
* Page fault inside EMGCEmulateLockCmpXchg()? Resume at _Error.
*/
if ( (uintptr_t)&EMGCEmulateLockCmpXchg < (uintptr_t)pRegFrame->eip
&& (uintptr_t)pRegFrame->eip < (uintptr_t)&EMGCEmulateLockCmpXchg_EndProc)
{
pRegFrame->eip = (uintptr_t)&EMGCEmulateLockCmpXchg_Error;
return VINF_SUCCESS;
}
/*
* Page fault inside EMGCEmulateCmpXchg()? Resume at _Error.
*/
if ( (uintptr_t)&EMGCEmulateCmpXchg < (uintptr_t)pRegFrame->eip
&& (uintptr_t)pRegFrame->eip < (uintptr_t)&EMGCEmulateCmpXchg_EndProc)
{
pRegFrame->eip = (uintptr_t)&EMGCEmulateCmpXchg_Error;
return VINF_SUCCESS;
}
/*
* Page fault inside EMGCEmulateLockCmpXchg8b()? Resume at _Error.
*/
if ( (uintptr_t)&EMGCEmulateLockCmpXchg8b < (uintptr_t)pRegFrame->eip
&& (uintptr_t)pRegFrame->eip < (uintptr_t)&EMGCEmulateLockCmpXchg8b_EndProc)
{
pRegFrame->eip = (uintptr_t)&EMGCEmulateLockCmpXchg8b_Error;
return VINF_SUCCESS;
}
/*
* Page fault inside EMGCEmulateCmpXchg8b()? Resume at _Error.
*/
if ( (uintptr_t)&EMGCEmulateCmpXchg8b < (uintptr_t)pRegFrame->eip
&& (uintptr_t)pRegFrame->eip < (uintptr_t)&EMGCEmulateCmpXchg8b_EndProc)
{
pRegFrame->eip = (uintptr_t)&EMGCEmulateCmpXchg8b_Error;
return VINF_SUCCESS;
}
/*
* Page fault inside EMGCEmulateLockXAdd()? Resume at _Error.
*/
if ( (uintptr_t)&EMGCEmulateLockXAdd < (uintptr_t)pRegFrame->eip
&& (uintptr_t)pRegFrame->eip < (uintptr_t)&EMGCEmulateLockXAdd_EndProc)
{
pRegFrame->eip = (uintptr_t)&EMGCEmulateLockXAdd_Error;
return VINF_SUCCESS;
}
/*
* Page fault inside EMGCEmulateXAdd()? Resume at _Error.
*/
if ( (uintptr_t)&EMGCEmulateXAdd < (uintptr_t)pRegFrame->eip
&& (uintptr_t)pRegFrame->eip < (uintptr_t)&EMGCEmulateXAdd_EndProc)
{
pRegFrame->eip = (uintptr_t)&EMGCEmulateXAdd_Error;
return VINF_SUCCESS;
}
/*
* Page fault inside EMEmulateLockOr()? Resume at *_Error.
*/
if ( (uintptr_t)&EMEmulateLockOr < (uintptr_t)pRegFrame->eip
&& (uintptr_t)pRegFrame->eip < (uintptr_t)&EMEmulateLockOr_EndProc)
{
pRegFrame->eip = (uintptr_t)&EMEmulateLockOr_Error;
return VINF_SUCCESS;
}
/*
* Page fault inside EMEmulateLockBtr()? Resume at *_Error.
*/
if ( (uintptr_t)&EMEmulateLockBtr < (uintptr_t)pRegFrame->eip
&& (uintptr_t)pRegFrame->eip < (uintptr_t)&EMEmulateLockBtr_EndProc)
{
pRegFrame->eip = (uintptr_t)&EMEmulateLockBtr_Error;
return VINF_SUCCESS;
}
/*
* #PF is not handled - cause guru meditation.
*/
return VERR_INTERNAL_ERROR;
}