PGMAllMap.cpp revision a4eb337e9a5a6a72bcfe50134dc42732f5ee65c0
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
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * General Public License (GPL) as published by the Free Software
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * additional information or have any questions.
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync/*******************************************************************************
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync* Header Files *
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync*******************************************************************************/
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * Maps a range of physical pages at a given virtual address
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * in the guest context.
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * The GC virtual address range must be within an existing mapping.
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * @returns VBox status code.
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * @param pVM The virtual machine.
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * @param GCPtr Where to map the page(s). Must be page aligned.
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * @param HCPhys Start of the range of physical pages. Must be page aligned.
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * @param cbPages Number of bytes to map. Must be page aligned.
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * @param fFlags Page flags (X86_PTE_*).
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsyncVMMDECL(int) PGMMap(PVM pVM, RTGCUINTPTR GCPtr, RTHCPHYS HCPhys, uint32_t cbPages, unsigned fFlags)
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * Validate input.
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync AssertMsg(RT_ALIGN_T(GCPtr, PAGE_SIZE, RTGCUINTPTR) == GCPtr, ("Invalid alignment GCPtr=%#x\n", GCPtr));
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync AssertMsg(cbPages > 0 && RT_ALIGN_32(cbPages, PAGE_SIZE) == cbPages, ("Invalid cbPages=%#x\n", cbPages));
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync AssertMsg(!(fFlags & X86_PDE_PG_MASK), ("Invalid flags %#x\n", fFlags));
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync /* hypervisor defaults */
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * Find the mapping.
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * Setup PTE.
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * Update the page tables.
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync const unsigned iPageNo = (off >> PAGE_SHIFT) & X86_PT_MASK;
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync /* 32-bit */
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync pCur->aPTs[iPT].CTX_SUFF(pPT)->a[iPageNo].u = (uint32_t)Pte.u; /* ASSUMES HCPhys < 4GB and/or that we're never gonna do 32-bit on a PAE host! */
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync pCur->aPTs[iPT].CTX_SUFF(paPaePTs)[iPageNo / 512].a[iPageNo % 512].u = Pte.u;
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync AssertMsgFailed(("GCPtr=%#x was not found in any mapping ranges!\n", GCPtr));
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * Sets (replaces) the page flags for a range of pages in a mapping.
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * @returns VBox status.
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * @param pVM VM handle.
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * @param GCPtr Virtual address of the first page in the range.
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * @param cb Size (in bytes) of the range to apply the modification to.
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * @param fFlags Page flags X86_PTE_*, excluding the page mask of course.
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsyncVMMDECL(int) PGMMapSetPage(PVM pVM, RTGCPTR GCPtr, uint64_t cb, uint64_t fFlags)
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync return PGMMapModifyPage(pVM, GCPtr, cb, fFlags, 0);
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * Modify page flags for a range of pages in a mapping.
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * The existing flags are ANDed with the fMask and ORed with the fFlags.
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * @returns VBox status code.
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * @param pVM VM handle.
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * @param GCPtr Virtual address of the first page in the range.
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * @param cb Size (in bytes) of the range to apply the modification to.
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * @param fFlags The OR mask - page flags X86_PTE_*, excluding the page mask of course.
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * @param fMask The AND mask - page flags X86_PTE_*, excluding the page mask of course.
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsyncVMMDECL(int) PGMMapModifyPage(PVM pVM, RTGCPTR GCPtr, size_t cb, uint64_t fFlags, uint64_t fMask)
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * Validate input.
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync AssertMsg(!(fFlags & X86_PTE_PAE_PG_MASK), ("fFlags=%#x\n", fFlags));
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * Align the input.
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync GCPtr = (RTGCPTR)((RTGCUINTPTR)GCPtr & PAGE_BASE_GC_MASK);
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * Find the mapping.
56665b35e85d3cd7d4232957d09b488ab44d81cfvboxsync RTGCUINTPTR off = (RTGCUINTPTR)GCPtr - (RTGCUINTPTR)pCur->GCPtr;
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync ("Invalid page range %#x LB%#x. mapping '%s' %#x to %#x\n",
56665b35e85d3cd7d4232957d09b488ab44d81cfvboxsync GCPtr, cb, pCur->pszDesc, pCur->GCPtr, pCur->GCPtrLast),
56665b35e85d3cd7d4232957d09b488ab44d81cfvboxsync * Perform the requested operation.
56665b35e85d3cd7d4232957d09b488ab44d81cfvboxsync while (cb > 0)
56665b35e85d3cd7d4232957d09b488ab44d81cfvboxsync while (cb > 0 && iPTE < RT_ELEMENTS(pCur->aPTs[iPT].CTX_SUFF(pPT)->a))
56665b35e85d3cd7d4232957d09b488ab44d81cfvboxsync /* 32-Bit */
56665b35e85d3cd7d4232957d09b488ab44d81cfvboxsync pCur->aPTs[iPT].CTX_SUFF(pPT)->a[iPTE].u &= fMask | X86_PTE_PG_MASK;
56665b35e85d3cd7d4232957d09b488ab44d81cfvboxsync pCur->aPTs[iPT].CTX_SUFF(pPT)->a[iPTE].u |= fFlags & ~X86_PTE_PG_MASK;
56665b35e85d3cd7d4232957d09b488ab44d81cfvboxsync pCur->aPTs[iPT].CTX_SUFF(paPaePTs)[iPTE / 512].a[iPTE % 512].u &= fMask | X86_PTE_PAE_PG_MASK;
56665b35e85d3cd7d4232957d09b488ab44d81cfvboxsync pCur->aPTs[iPT].CTX_SUFF(paPaePTs)[iPTE / 512].a[iPTE % 512].u |= fFlags & ~X86_PTE_PAE_PG_MASK;
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync /* invalidate tls */
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync AssertMsgFailed(("Page range %#x LB%#x not found\n", GCPtr, cb));
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * Sets all PDEs involved with the mapping in the shadow page table.
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * @param pVM The VM handle.
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * @param pMap Pointer to the mapping in question.
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * @param iNewPDE The index of the 32-bit PDE corresponding to the base of the mapping.
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsyncvoid pgmMapSetShadowPDEs(PVM pVM, PPGMMAPPING pMap, unsigned iNewPDE)
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync Log4(("pgmMapSetShadowPDEs new pde %x (mappings enabled %d)\n", iNewPDE, pgmMapAreMappingsEnabled(&pVM->pgm.s)));
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync /* This only applies to raw mode where we only support 1 VCPU. */
727cf0d6c794dffee1023d2bbb6e94eda7f35ca9vboxsync return; /* too early */
727cf0d6c794dffee1023d2bbb6e94eda7f35ca9vboxsync * Insert the page tables into the shadow page directories.
iNewPDE += i;
iNewPDE--;
switch (enmShadowMode)
case PGMMODE_32_BIT:
Assert( (pShw32BitPd->a[iNewPDE].u & (X86_PDE_P | PGM_PDFLAGS_MAPPING)) != (X86_PDE_P | PGM_PDFLAGS_MAPPING)
pgmPoolFree(pVM, pShw32BitPd->a[iNewPDE].u & X86_PDE_PG_MASK, pVCpu->pgm.s.CTX_SUFF(pShwPageCR3)->idx, iNewPDE);
/* Default mapping page directory flags are read/write and supervisor; individual page attributes determine the final flags. */
#ifdef IN_RC
case PGMMODE_PAE:
case PGMMODE_PAE_NX:
if (!pShwPaePd)
if (pGstPdpe)
#ifdef VBOX_STRICT
Assert(PGMGetGuestMode(pVCpu) >= PGMMODE_PAE); /** @todo We may hit this during reset, will fix later. */
Assert( (pShwPaePd->a[iPaePde].u & (X86_PDE_P | PGM_PDFLAGS_MAPPING)) != (X86_PDE_P | PGM_PDFLAGS_MAPPING)
iPaePde++;
Assert( (pShwPaePd->a[iPaePde].u & (X86_PDE_P | PGM_PDFLAGS_MAPPING)) != (X86_PDE_P | PGM_PDFLAGS_MAPPING)
#ifdef IN_RC
AssertFailed();
void pgmMapClearShadowPDEs(PVM pVM, PPGMPOOLPAGE pShwPageCR3, PPGMMAPPING pMap, unsigned iOldPDE, bool fDeactivateCR3)
Log(("pgmMapClearShadowPDEs: old pde %x (cPTs=%x) (mappings enabled %d) fDeactivateCR3=%RTbool\n", iOldPDE, pMap->cPTs, pgmMapAreMappingsEnabled(&pVM->pgm.s), fDeactivateCR3));
# ifdef IN_RC
if (pCurrentShwPdpt)
iOldPDE += i;
iOldPDE--;
switch(enmShadowMode)
case PGMMODE_32_BIT:
case PGMMODE_PAE:
case PGMMODE_PAE_NX:
if (fDeactivateCR3)
if ( pCurrentShwPdpt
iPaePde++;
if ( fDeactivateCR3
AssertFailed();
#ifdef IN_RC
if (pCurrentShwPdpt)
static void pgmMapCheckShadowPDEs(PVM pVM, PVMCPU pVCpu, PPGMPOOLPAGE pShwPageCR3, PPGMMAPPING pMap, unsigned iPDE)
iPDE += i;
iPDE--;
switch (enmShadowMode)
case PGMMODE_32_BIT:
AssertMsg(pShw32BitPd->a[iPDE].u == (PGM_PDFLAGS_MAPPING | X86_PDE_P | X86_PDE_A | X86_PDE_RW | X86_PDE_US | (uint32_t)pMap->aPTs[i].HCPhysPT),
pShw32BitPd->a[iPDE].u, (PGM_PDFLAGS_MAPPING | X86_PDE_P | X86_PDE_A | X86_PDE_RW | X86_PDE_US | (uint32_t)pMap->aPTs[i].HCPhysPT),
case PGMMODE_PAE:
case PGMMODE_PAE_NX:
AssertMsg(pShwPaePd->a[iPaePDE].u == (PGM_PDFLAGS_MAPPING | X86_PDE_P | X86_PDE_A | X86_PDE_RW | X86_PDE_US | pMap->aPTs[i].HCPhysPaePT0),
pShwPaePd->a[iPaePDE].u, (PGM_PDFLAGS_MAPPING | X86_PDE_P | X86_PDE_A | X86_PDE_RW | X86_PDE_US | pMap->aPTs[i].HCPhysPaePT0),
iPaePDE++;
AssertMsg(pShwPaePd->a[iPaePDE].u == (PGM_PDFLAGS_MAPPING | X86_PDE_P | X86_PDE_A | X86_PDE_RW | X86_PDE_US | pMap->aPTs[i].HCPhysPaePT1),
pShwPaePd->a[iPaePDE].u, (PGM_PDFLAGS_MAPPING | X86_PDE_P | X86_PDE_A | X86_PDE_RW | X86_PDE_US | pMap->aPTs[i].HCPhysPaePT1),
AssertFailed();
#ifndef IN_RING0
return VINF_SUCCESS;
/* Note. A log flush (in RC) can cause problems when called from MapCR3 (inconsistent state will trigger assertions). */
Log4(("pgmMapActivateCR3: fixed mappings=%d idxShwPageCR3=%#x\n", pVM->pgm.s.fMappingsFixed, pShwPageCR3 ? pShwPageCR3->idx : NIL_PGMPOOL_IDX));
#ifdef VBOX_STRICT
return VINF_SUCCESS;
return VINF_SUCCESS;
Log4(("pgmMapDeactivateCR3: fixed mappings=%d idxShwPageCR3=%#x\n", pVM->pgm.s.fMappingsFixed, pShwPageCR3 ? pShwPageCR3->idx : NIL_PGMPOOL_IDX));
return VINF_SUCCESS;
while (iPT-- > 0)
#ifdef IN_RING3
while (iPT-- > 0)
#ifdef IN_RING3
AssertFailed();
return VINF_SUCCESS;
while (iPT-- > 0)
#ifdef IN_RING3
return VINF_PGM_SYNC_CR3;
while (iPT-- > 0)
#ifdef IN_RING3
return VINF_PGM_SYNC_CR3;
AssertFailed();
return VINF_SUCCESS;