PGMAll.cpp revision 016950bb1b289514e67d9e473538d22a50c0e408
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * PGM - Page Manager and Monitor - All context code.
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * Copyright (C) 2006-2007 Sun Microsystems, Inc.
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * available from http://www.virtualbox.org. This file is free software;
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * you can redistribute it and/or modify it under the terms of the GNU
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * General Public License (GPL) as published by the Free Software
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * additional information or have any questions.
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync/*******************************************************************************
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync* Header Files *
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync*******************************************************************************/
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync/*******************************************************************************
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync* Structures and Typedefs *
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync*******************************************************************************/
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * Stated structure for PGM_GST_NAME(HandlerVirtualUpdate) that's
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * passed to PGM_GST_NAME(VirtHandlerUpdateOne) during enumeration.
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsynctypedef struct PGMHVUSTATE
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync /** The VM handle. */
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync /** The VMCPU handle. */
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync /** The todo flags. */
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync /** The CR4 register value. */
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync/*******************************************************************************
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync* Internal Functions *
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync*******************************************************************************/
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsyncDECLINLINE(int) pgmShwGetLongModePDPtr(PVMCPU pVCpu, RTGCPTR64 GCPtr, PX86PML4E *ppPml4e, PX86PDPT *ppPdpt, PX86PDPAE *ppPD);
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsyncDECLINLINE(int) pgmShwGetPaePoolPagePD(PPGMCPU pPGM, RTGCPTR GCPtr, PPGMPOOLPAGE *ppShwPde);
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * Shadow - 32-bit mode
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync/* Guest - real mode */
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync#define PGM_BTH_NAME(name) PGM_BTH_NAME_32BIT_REAL(name)
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync#define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_32BIT_PT_FOR_PHYS
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync#define BTH_PGMPOOLKIND_ROOT PGMPOOLKIND_32BIT_PD_PHYS
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync/* Guest - protected mode */
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync#define PGM_BTH_NAME(name) PGM_BTH_NAME_32BIT_PROT(name)
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync#define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_32BIT_PT_FOR_PHYS
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync#define BTH_PGMPOOLKIND_ROOT PGMPOOLKIND_32BIT_PD_PHYS
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync/* Guest - 32-bit mode */
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync#define PGM_BTH_NAME(name) PGM_BTH_NAME_32BIT_32BIT(name)
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync#define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync#define BTH_PGMPOOLKIND_PT_FOR_BIG PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * Shadow - PAE mode
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync#define PGM_BTH_NAME(name) PGM_BTH_NAME_PAE_REAL(name)
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync/* Guest - real mode */
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync#define PGM_BTH_NAME(name) PGM_BTH_NAME_PAE_REAL(name)
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync#define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_PAE_PT_FOR_PHYS
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync#define BTH_PGMPOOLKIND_ROOT PGMPOOLKIND_PAE_PDPT_PHYS
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync/* Guest - protected mode */
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync#define PGM_BTH_NAME(name) PGM_BTH_NAME_PAE_PROT(name)
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync#define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_PAE_PT_FOR_PHYS
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync#define BTH_PGMPOOLKIND_ROOT PGMPOOLKIND_PAE_PDPT_PHYS
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync/* Guest - 32-bit mode */
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync#define PGM_BTH_NAME(name) PGM_BTH_NAME_PAE_32BIT(name)
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync#define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_PAE_PT_FOR_32BIT_PT
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync#define BTH_PGMPOOLKIND_PT_FOR_BIG PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync#define BTH_PGMPOOLKIND_ROOT PGMPOOLKIND_PAE_PDPT_FOR_32BIT
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync/* Guest - PAE mode */
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync#define PGM_BTH_NAME(name) PGM_BTH_NAME_PAE_PAE(name)
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync#define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_PAE_PT_FOR_PAE_PT
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync#define BTH_PGMPOOLKIND_PT_FOR_BIG PGMPOOLKIND_PAE_PT_FOR_PAE_2MB
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * Shadow - AMD64 mode
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync# define PGM_SHW_NAME(name) PGM_SHW_NAME_AMD64(name)
# include "PGMGstDefs.h"
# include "PGMAllBth.h"
# ifdef VBOX_WITH_64_BITS_GUESTS
# include "PGMGstDefs.h"
# include "PGMAllGst.h"
# include "PGMAllBth.h"
# include "PGMAllShw.h"
# include "PGMGstDefs.h"
# include "PGMAllBth.h"
# include "PGMGstDefs.h"
# include "PGMAllBth.h"
# include "PGMGstDefs.h"
# include "PGMAllBth.h"
# include "PGMGstDefs.h"
# include "PGMAllBth.h"
# ifdef VBOX_WITH_64_BITS_GUESTS
# include "PGMGstDefs.h"
# include "PGMAllBth.h"
# include "PGMAllShw.h"
# include "PGMGstDefs.h"
# include "PGMAllBth.h"
# include "PGMGstDefs.h"
# include "PGMAllBth.h"
# include "PGMGstDefs.h"
# include "PGMAllBth.h"
# include "PGMGstDefs.h"
# include "PGMAllBth.h"
# ifdef VBOX_WITH_64_BITS_GUESTS
# include "PGMGstDefs.h"
# include "PGMAllBth.h"
#ifndef IN_RING3
Log(("PGMTrap0eHandler: uErr=%RGu pvFault=%RGv eip=%04x:%RGv\n", uErr, pvFault, pRegFrame->cs, (RTGCPTR)pRegFrame->rip));
#ifdef VBOX_WITH_STATISTICS
bool fLockTaken = false;
if (fLockTaken)
# ifdef IN_RING0
Log(("WARNING: Unexpected VERR_PAGE_TABLE_NOT_PRESENT (%d) for page fault at %RGv error code %x (rip=%RGv)\n", rc, pvFault, uErr, pRegFrame->rip));
/* Some kind of inconsistency in the SMP case; it's safe to just execute the instruction again; not sure about single VCPU VMs though. */
STAM_STATS({ if (rc == VINF_EM_RAW_GUEST_TRAP) STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZTrap0eGuestPF); });
return rc;
return rc;
while (pMapping)
return pMapping;
return NULL;
* @param fAccess Access type (r/w, user/supervisor (X86_PTE_*))
return VERR_INVALID_PARAMETER;
return VINF_EM_RAW_GUEST_TRAP;
Log(("PGMIsValidAccess: access violation for %RGv attr %#llx vs %d:%d\n", Addr, fPage, fWrite, fUser));
return VINF_EM_RAW_GUEST_TRAP;
return PGMIsValidAccess(pVCpu, Addr + PAGE_SIZE, (cbSize > PAGE_SIZE) ? cbSize - PAGE_SIZE : 1, fAccess);
return rc;
* @param fAccess Access type (r/w, user/supervisor (X86_PTE_*))
AssertMsg(!(fAccess & ~(X86_PTE_US | X86_PTE_RW)), ("PGMVerifyAccess: invalid access type %08x\n", fAccess));
return VINF_EM_RAW_GUEST_TRAP;
Log(("PGMVerifyAccess: access violation for %RGv attr %#llx vs %d:%d\n", Addr, fPageGst, fWrite, fUser));
return VINF_EM_RAW_GUEST_TRAP;
return rc;
return VINF_EM_RAW_GUEST_TRAP;
return rc;
int rc;
#ifndef IN_RING3
#ifdef IN_RC
return VINF_PGM_SYNC_CR3;
return VINF_EM_RAW_EMULATE_INSTR;
#ifdef IN_RING3
return rc;
VMMDECL(int) PGMInterpretInstruction(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault)
return rc;
return rc;
VMMDECL(int) PGMShwModifyPage(PVMCPU pVCpu, RTGCPTR GCPtr, size_t cb, uint64_t fFlags, uint64_t fMask)
return rc;
int rc;
# if defined(IN_RC)
# if defined(IN_RC)
/* In 32 bits PAE mode we *must* invalidate the TLB when changing a PDPT entry; the CPU fetches them only during cr3 load, so any
ASMReloadCR3();
return VINF_SUCCESS;
PPGMPOOLPAGE pShwPde = pgmPoolGetPage(PGMCPU2PGM(pPGM)->CTX_SUFF(pPool), pPdpt->a[iPdPt].u & X86_PDPE_PG_MASK);
return VINF_SUCCESS;
#ifndef IN_RC
int pgmShwSyncLongModePDPtr(PVMCPU pVCpu, RTGCPTR64 GCPtr, PX86PML4E pGstPml4e, PX86PDPE pGstPdpe, PX86PDPAE *ppPD)
bool fNestedPagingOrNoGstPaging = HWACCMIsNestedPagingActive(pVM) || !CPUMIsGuestPagingEnabled(pVCpu);
int rc;
return VINF_SUCCESS;
DECLINLINE(int) pgmShwGetLongModePDPtr(PVMCPU pVCpu, RTGCPTR64 GCPtr, PX86PML4E *ppPml4e, PX86PDPT *ppPdpt, PX86PDPAE *ppPD)
if (ppPml4e)
return VERR_PAGE_MAP_LEVEL4_NOT_PRESENT;
return VINF_SUCCESS;
int rc;
rc = pgmPoolAlloc(pVM, GCPml4, PGMPOOLKIND_EPT_PDPT_FOR_PHYS, PGMPOOL_IDX_NESTED_ROOT, iPml4, &pShwPage);
if (ppPdpt)
return VINF_SUCCESS;
VMMDECL(int) PGMGstModifyPage(PVMCPU pVCpu, RTGCPTR GCPtr, size_t cb, uint64_t fFlags, uint64_t fMask)
return rc;
#ifdef IN_RING3
int rc = pgmPhysGCPhys2CCPtrInternal(pVM, pPage, pPGM->GCPhysCR3 & X86_CR3_PAGE_MASK, (void **)&HCPtrGuestCR3);
# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
int rc = pgmPhysGCPhys2CCPtrInternal(pVM, pPage, pPGM->GCPhysCR3 & X86_CR3_PAE_PAGE_MASK, (void **)&HCPtrGuestCR3); /** @todo r=bird: This GCPhysR3 masking isn't necessary. */
# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
if (fChanged)
# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
return NULL;
int rc = pgmPhysGCPhys2CCPtrInternal(pVM, pPage, pPGM->GCPhysCR3 & X86_CR3_AMD64_PAGE_MASK, (void **)&HCPtrGuestCR3); /** @todo r=bird: This GCPhysCR3 masking isn't necessary. */
# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
case SUPPAGINGMODE_32_BIT:
case SUPPAGINGMODE_PAE:
case SUPPAGINGMODE_PAE_GLOBAL:
case SUPPAGINGMODE_PAE_NX:
case SUPPAGINGMODE_AMD64:
case SUPPAGINGMODE_AMD64_NX:
case PGMMODE_32_BIT:
case PGMMODE_PAE:
case PGMMODE_PAE_NX:
case PGMMODE_AMD64:
case PGMMODE_AMD64_NX:
case PGMMODE_EPT:
case PGMMODE_NESTED:
if (fGlobal)
LogFlow(("PGMFlushTLB: cr3=%RX64 OldCr3=%RX64 fGlobal=%d\n", cr3, pVCpu->pgm.s.GCPhysCR3, fGlobal));
case PGMMODE_PAE:
case PGMMODE_PAE_NX:
case PGMMODE_AMD64:
case PGMMODE_AMD64_NX:
if (fGlobal)
# ifdef PGMPOOL_WITH_OPTIMIZED_DIRTY_PT
if (fGlobal)
return rc;
case PGMMODE_PAE:
case PGMMODE_PAE_NX:
case PGMMODE_AMD64:
case PGMMODE_AMD64_NX:
AssertRCSuccess(rc); /* Assumes VINF_PGM_SYNC_CR3 doesn't apply to nested paging. */ /** @todo this isn't true for the mac, but we need hw to test/fix this. */
return rc;
int rc;
return rc;
return VINF_SUCCESS;
fGlobal = true;
VMCPU_FF_ISSET(pVCpu, VMCPU_FF_PGM_SYNC_CR3), VMCPU_FF_ISSET(pVCpu, VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL)));
case PGMMODE_PAE:
case PGMMODE_PAE_NX:
case PGMMODE_AMD64:
case PGMMODE_AMD64_NX:
#ifdef IN_RING3
return VINF_PGM_SYNC_CR3;
return rc;
return VINF_SUCCESS;
#ifdef IN_RING3
return VINF_PGM_CHANGE_MODE;
case SUPPAGINGMODE_32_BIT:
return PGMMODE_32_BIT;
case SUPPAGINGMODE_PAE:
case SUPPAGINGMODE_PAE_GLOBAL:
return PGMMODE_PAE;
case SUPPAGINGMODE_PAE_NX:
return PGMMODE_PAE_NX;
case SUPPAGINGMODE_AMD64:
return PGMMODE_AMD64;
case SUPPAGINGMODE_AMD64_NX:
return PGMMODE_AMD64_NX;
return PGMMODE_INVALID;
switch (enmMode)
return rc;
if (!pRam)
return VINF_SUCCESS;
if (!pRam)
return VINF_SUCCESS;
# ifdef IN_RC
register unsigned iCache;
static const uint8_t au8Trans[MM_HYPER_DYNAMIC_SIZE >> PAGE_SHIFT][RT_ELEMENTS(pVM->pgm.s.aHCPhysDynPageMapCache)] =
/* The cache can get out of sync with locked entries. (10 locked, 2 overwrites its cache position, last = 11, lookup 2 -> page 10 instead of 2) */
return VINF_SUCCESS;
iPage++;
pVM->pgm.s.aHCPhysDynPageMapCache[iPage & (RT_ELEMENTS(pVM->pgm.s.aHCPhysDynPageMapCache) - 1)] = HCPhys;
return VINF_SUCCESS;
unsigned iPage;
Assert(GCPage >= pVM->pgm.s.pbDynPageMapBaseGC && GCPage < (pVM->pgm.s.pbDynPageMapBaseGC + MM_HYPER_DYNAMIC_SIZE));
unsigned iPage;
AssertCompile(RT_ELEMENTS(pVM->pgm.s.aLockedDynPageMapCache) == 2* RT_ELEMENTS(pVM->pgm.s.aHCPhysDynPageMapCache));
AssertCompileMemberSize(VM, pgm.s.aLockedDynPageMapCache, sizeof(uint32_t) * (MM_HYPER_DYNAMIC_SIZE >> (PAGE_SHIFT)));
Assert(GCPage >= pVM->pgm.s.pbDynPageMapBaseGC && GCPage < (pVM->pgm.s.pbDynPageMapBaseGC + MM_HYPER_DYNAMIC_SIZE));
# ifdef VBOX_STRICT
void *pvUser)
cch = 0;
#define IS_PART_INCLUDED(lvl) ( !(fFlags & RTSTR_F_PRECISION) || cchPrecision == (lvl) || cchPrecision >= (lvl)+10 )
static const char s_achPageTypes[8][4] = { "INV", "RAM", "MI2", "M2A", "SHA", "ROM", "MIO", "BAD" };
cch += RTStrFormatNumber(&szTmp[cch], PGM_PAGE_GET_HCPHYS(pPage), 16, 12, 0, RTSTR_F_ZEROPAD | RTSTR_F_64BIT);
cch += RTStrFormatNumber(&szTmp[cch], PGM_PAGE_GET_PAGEID(pPage), 16, 7, 0, RTSTR_F_ZEROPAD | RTSTR_F_32BIT);
cch += RTStrFormatNumber(&szTmp[cch], PGM_PAGE_GET_TD_IDX(pPage), 16, 4, 0, RTSTR_F_ZEROPAD | RTSTR_F_16BIT);
return cch;
static DECLCALLBACK(size_t) pgmFormatTypeHandlerRamRange(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
void *pvUser)
return cch;
/** Format type andlers to be registered/deregistered. */
} g_aPgmFormatTypes[] =
# ifdef IN_RING0
return rc;
return VINF_SUCCESS;
#ifdef VBOX_STRICT
unsigned cErrors = 0;
cErrors++;
return cErrors;
return cErrors;