SELMGC.cpp revision 949e540380e375caee37199f0a6f5ff1eb97636b
/* $Id$ */
/** @file
* SELM - The Selector Manager, Guest Context.
*/
/*
* Copyright (C) 2006-2007 Sun Microsystems, Inc.
*
* 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.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 USA or visit http://www.sun.com if you need
* additional information or have any questions.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#define LOG_GROUP LOG_GROUP_SELM
#include "SELMInternal.h"
/**
* Synchronizes one GDT entry (guest -> shadow).
*
* @returns VBox status code (appropriate for trap handling and GC return).
* @param pVM VM Handle.
* @param pRegFrame Trap register frame.
* @param iGDTEntry The GDT entry to sync.
*/
{
/*
* Validate the offset.
*/
if ( iGDTEntry >= SELM_GDT_ELEMENTS
/*
* Read the guest descriptor.
*/
if (RT_FAILURE(rc))
/*
* Check for conflicts.
*/
{
{
return VINF_SELM_SYNC_GDT;
}
Log(("selmGCSyncGDTEntry: Sel=%d Desc=%.8Rhxs: potential conflict (still not present)!\n", Sel, &Desc));
/* Note: we can't continue below or else we'll change the shadow descriptor!! */
/* When the guest makes the selector present, then we'll do a GDT sync. */
return VINF_SUCCESS;
}
/*
* Code and data selectors are generally 1:1, with the
* 'little' adjustment we do for DPL 0 selectors.
*/
{
/*
* Hack for A-bit against Trap E on read-only GDT.
*/
/** @todo Fix this by loading ds and cs before turning off WP. */
/*
* All DPL 0 code and data segments are squeezed into DPL 1.
*
* We're skipping conforming segments here because those
* cannot give us any trouble.
*/
!= (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF) )
}
else
{
/*
* System type selectors are marked not present.
* Recompiler or special handling is required for these.
*/
/** @todo what about interrupt gates and rawr0? */
}
//Log(("O: base=%08X limit=%08X attr=%04X\n", X86DESC_BASE(*pShadowDescr)), X86DESC_LIMIT(*pShadowDescr), (pShadowDescr->au32[1] >> 8) & 0xFFFF ));
//Log(("N: base=%08X limit=%08X attr=%04X\n", X86DESC_BASE(Desc)), X86DESC_LIMIT(Desc), (Desc.au32[1] >> 8) & 0xFFFF ));
*pShadowDescr = Desc;
/* Check if we change the LDT selector */
if (Sel == CPUMGetGuestLDTR(pVM)) /** @todo this isn't correct in two(+) ways! 1. It shouldn't be done until the LDTR is reloaded. 2. It caused the next instruction to be emulated. */
{
}
#ifdef LOG_ENABLED
#endif
return VINF_SUCCESS;
}
/**
* \#PF Virtual Handler callback for Guest write access to the Guest's own GDT.
*
* @returns VBox status code (appropriate for trap handling and GC return).
* @param pVM VM Handle.
* @param uErrorCode CPU Error code.
* @param pRegFrame Trap register frame.
* @param pvFault The fault address (cr2).
* @param pvRange The base address of the handled virtual range.
* @param offRange The offset of the access into this range.
* (If it's a EIP range this's the EIP, if not it's pvFault.)
*/
VMMRCDECL(int) selmRCGuestGDTWriteHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPTR pvRange, uintptr_t offRange)
{
LogFlow(("selmRCGuestGDTWriteHandler errcode=%x fault=%RGv offRange=%08x\n", (uint32_t)uErrorCode, pvFault, offRange));
/*
* First check if this is the LDT entry.
* LDT updates are problemous since an invalid LDT entry will cause trouble during worldswitch.
*/
int rc;
{
Log(("LDTR selector change -> fall back to HC!!\n"));
/** @todo We're not handling changed to the selectors in LDTR and TR correctly at all.
* We should ignore any changes to those and sync them only when they are loaded by the guest! */
}
else
{
/*
* Attempt to emulate the instruction and sync the affected entries.
*/
/** @todo should check if any affected selectors are loaded. */
{
if (rc2 == VINF_SUCCESS)
{
if (rc2 == VINF_SUCCESS)
{
return rc;
}
}
}
else
{
if (rc == VERR_EM_INTERPRETER)
}
}
{
/* Not necessary when we need to go back to the host context to sync the LDT or TSS. */
}
return rc;
}
/**
* \#PF Virtual Handler callback for Guest write access to the Guest's own LDT.
*
* @returns VBox status code (appropriate for trap handling and GC return).
* @param pVM VM Handle.
* @param uErrorCode CPU Error code.
* @param pRegFrame Trap register frame.
* @param pvFault The fault address (cr2).
* @param pvRange The base address of the handled virtual range.
* @param offRange The offset of the access into this range.
* (If it's a EIP range this's the EIP, if not it's pvFault.)
*/
VMMRCDECL(int) selmRCGuestLDTWriteHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPTR pvRange, uintptr_t offRange)
{
/** @todo To be implemented. */
////LogCom(("selmRCGuestLDTWriteHandler: eip=%08X pvFault=%RGv pvRange=%RGv\r\n", pRegFrame->eip, pvFault, pvRange));
}
/**
* Read wrapper used by selmRCGuestTSSWriteHandler.
* @returns VBox status code (appropriate for trap handling and GC return).
* @param pVM The VM handle
* @param pvDst Where to put the bits we read.
* @param pvSrc Guest address to read from.
* @param cb The number of bytes to read.
*/
{
if (RT_SUCCESS(rc))
return VINF_SUCCESS;
/** @todo use different fallback? */
if (rc == VINF_SUCCESS)
{
}
return rc;
}
/**
* \#PF Virtual Handler callback for Guest write access to the Guest's own current TSS.
*
* @returns VBox status code (appropriate for trap handling and GC return).
* @param pVM VM Handle.
* @param uErrorCode CPU Error code.
* @param pRegFrame Trap register frame.
* @param pvFault The fault address (cr2).
* @param pvRange The base address of the handled virtual range.
* @param offRange The offset of the access into this range.
* (If it's a EIP range this's the EIP, if not it's pvFault.)
*/
VMMRCDECL(int) selmRCGuestTSSWriteHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPTR pvRange, uintptr_t offRange)
{
LogFlow(("selmRCGuestTSSWriteHandler errcode=%x fault=%RGv offRange=%08x\n", (uint32_t)uErrorCode, pvFault, offRange));
/*
* Try emulate the access.
*/
{
rc = VINF_SUCCESS;
/*
* If it's on the same page as the esp0 and ss0 fields or actually one of them,
* then check if any of these has changed.
*/
)
{
Log(("selmRCGuestTSSWriteHandler: R0 stack: %RTsel:%RGv -> %RTsel:%RGv\n",
(RTSEL)(pVM->selm.s.Tss.ss1 & ~1), (RTGCPTR)pVM->selm.s.Tss.esp1, (RTSEL)pGuestTss->ss0, (RTGCPTR)pGuestTss->esp0));
}
/* Handle misaligned TSS in a safe manner (just in case). */
{
struct
{
} s;
AssertCompileSize(s, 8);
if ( rc == VINF_SUCCESS
)
{
Log(("selmRCGuestTSSWriteHandler: R0 stack: %RTsel:%RGv -> %RTsel:%RGv\n",
}
}
/*
* If VME is enabled we need to check if the interrupt redirection bitmap
* needs updating.
*/
{
{
{
Log(("TSS offIoBitmap changed: old=%#x new=%#x -> resync in ring-3\n", pVM->selm.s.offGuestIoBitmap, offIoBitmap));
}
else
}
else
{
/** @todo not sure how the partial case is handled; probably not allowed */
if ( offIntRedirBitmap <= offRange
{
Log(("TSS IntRedirBitmap Changed: offIoBitmap=%x offIntRedirBitmap=%x cbTSS=%x offRange=%x cb=%x\n",
/** @todo only update the changed part. */
{
if (rc != VINF_SUCCESS)
break;
}
}
}
}
/* Return to ring-3 for a full resync if any of the above fails... (?) */
if (rc != VINF_SUCCESS)
{
if (RT_SUCCESS(rc))
rc = VINF_SUCCESS;
}
}
else
{
if (rc == VERR_EM_INTERPRETER)
}
return rc;
}
/**
* \#PF Virtual Handler callback for Guest write access to the VBox shadow GDT.
*
* @returns VBox status code (appropriate for trap handling and GC return).
* @param pVM VM Handle.
* @param uErrorCode CPU Error code.
* @param pRegFrame Trap register frame.
* @param pvFault The fault address (cr2).
* @param pvRange The base address of the handled virtual range.
* @param offRange The offset of the access into this range.
* (If it's a EIP range this's the EIP, if not it's pvFault.)
*/
VMMRCDECL(int) selmRCShadowGDTWriteHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPTR pvRange, uintptr_t offRange)
{
LogRel(("FATAL ERROR: selmRCShadowGDTWriteHandler: eip=%08X pvFault=%RGv pvRange=%RGv\r\n", pRegFrame->eip, pvFault, pvRange));
return VERR_SELM_SHADOW_GDT_WRITE;
}
/**
* \#PF Virtual Handler callback for Guest write access to the VBox shadow LDT.
*
* @returns VBox status code (appropriate for trap handling and GC return).
* @param pVM VM Handle.
* @param uErrorCode CPU Error code.
* @param pRegFrame Trap register frame.
* @param pvFault The fault address (cr2).
* @param pvRange The base address of the handled virtual range.
* @param offRange The offset of the access into this range.
* (If it's a EIP range this's the EIP, if not it's pvFault.)
*/
VMMRCDECL(int) selmRCShadowLDTWriteHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPTR pvRange, uintptr_t offRange)
{
LogRel(("FATAL ERROR: selmRCShadowLDTWriteHandler: eip=%08X pvFault=%RGv pvRange=%RGv\r\n", pRegFrame->eip, pvFault, pvRange));
Assert((RTRCPTR)pvFault >= pVM->selm.s.pvLdtRC && (RTRCUINTPTR)pvFault < (RTRCUINTPTR)pVM->selm.s.pvLdtRC + 65536 + PAGE_SIZE);
return VERR_SELM_SHADOW_LDT_WRITE;
}
/**
* \#PF Virtual Handler callback for Guest write access to the VBox shadow TSS.
*
* @returns VBox status code (appropriate for trap handling and GC return).
* @param pVM VM Handle.
* @param uErrorCode CPU Error code.
* @param pRegFrame Trap register frame.
* @param pvFault The fault address (cr2).
* @param pvRange The base address of the handled virtual range.
* @param offRange The offset of the access into this range.
* (If it's a EIP range this's the EIP, if not it's pvFault.)
*/
VMMRCDECL(int) selmRCShadowTSSWriteHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPTR pvRange, uintptr_t offRange)
{
LogRel(("FATAL ERROR: selmRCShadowTSSWriteHandler: eip=%08X pvFault=%RGv pvRange=%RGv\r\n", pRegFrame->eip, pvFault, pvRange));
return VERR_SELM_SHADOW_TSS_WRITE;
}