PGMAllMap.cpp revision 7517e6036eaa4efe0735dd66f1ec09dedc0664e7
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * PGM - Page Manager and Monitor - All context code.
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * Copyright (C) 2006-2007 Sun Microsystems, Inc.
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * available from http://www.virtualbox.org. This file is free software;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * you can redistribute it and/or modify it under the terms of the GNU
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * General Public License (GPL) as published by the Free Software
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * additional information or have any questions.
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync/*******************************************************************************
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync* Header Files *
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync*******************************************************************************/
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * Maps a range of physical pages at a given virtual address
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * in the guest context.
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * The GC virtual address range must be within an existing mapping.
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * @returns VBox status code.
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * @param pVM The virtual machine.
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * @param GCPtr Where to map the page(s). Must be page aligned.
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * @param HCPhys Start of the range of physical pages. Must be page aligned.
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * @param cbPages Number of bytes to map. Must be page aligned.
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * @param fFlags Page flags (X86_PTE_*).
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsyncVMMDECL(int) PGMMap(PVM pVM, RTGCUINTPTR GCPtr, RTHCPHYS HCPhys, uint32_t cbPages, unsigned fFlags)
39cac49f62afd27b0ffdbb779c7c64211939030cvboxsync * Validate input.
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync AssertMsg(RT_ALIGN_T(GCPtr, PAGE_SIZE, RTGCUINTPTR) == GCPtr, ("Invalid alignment GCPtr=%#x\n", GCPtr));
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync AssertMsg(cbPages > 0 && RT_ALIGN_32(cbPages, PAGE_SIZE) == cbPages, ("Invalid cbPages=%#x\n", cbPages));
d82d7a8b44b27420e50f410d8ee5b990bb8b8f12vboxsync AssertMsg(!(fFlags & X86_PDE_PG_MASK), ("Invalid flags %#x\n", fFlags));
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync /* hypervisor defaults */
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * Find the mapping.
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * Setup PTE.
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * Update the page tables.
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync const unsigned iPageNo = (off >> PAGE_SHIFT) & X86_PT_MASK;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync /* 32-bit */
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync 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! */
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync pCur->aPTs[iPT].CTX_SUFF(paPaePTs)[iPageNo / 512].a[iPageNo % 512].u = Pte.u;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync AssertMsgFailed(("GCPtr=%#x was not found in any mapping ranges!\n", GCPtr));
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * Sets (replaces) the page flags for a range of pages in a mapping.
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * @returns VBox status.
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * @param pVM VM handle.
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * @param GCPtr Virtual address of the first page in the range.
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * @param cb Size (in bytes) of the range to apply the modification to.
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * @param fFlags Page flags X86_PTE_*, excluding the page mask of course.
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsyncVMMDECL(int) PGMMapSetPage(PVM pVM, RTGCPTR GCPtr, uint64_t cb, uint64_t fFlags)
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync return PGMMapModifyPage(pVM, GCPtr, cb, fFlags, 0);
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * Modify page flags for a range of pages in a mapping.
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * The existing flags are ANDed with the fMask and ORed with the fFlags.
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * @returns VBox status code.
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * @param pVM VM handle.
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * @param GCPtr Virtual address of the first page in the range.
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * @param cb Size (in bytes) of the range to apply the modification to.
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * @param fFlags The OR mask - page flags X86_PTE_*, excluding the page mask of course.
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * @param fMask The AND mask - page flags X86_PTE_*, excluding the page mask of course.
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsyncVMMDECL(int) PGMMapModifyPage(PVM pVM, RTGCPTR GCPtr, size_t cb, uint64_t fFlags, uint64_t fMask)
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * Validate input.
d82d7a8b44b27420e50f410d8ee5b990bb8b8f12vboxsync AssertMsg(!(fFlags & X86_PTE_PAE_PG_MASK), ("fFlags=%#x\n", fFlags));
d82d7a8b44b27420e50f410d8ee5b990bb8b8f12vboxsync * Align the input.
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync GCPtr = (RTGCPTR)((RTGCUINTPTR)GCPtr & PAGE_BASE_GC_MASK);
d82d7a8b44b27420e50f410d8ee5b990bb8b8f12vboxsync * Find the mapping.
d82d7a8b44b27420e50f410d8ee5b990bb8b8f12vboxsync RTGCUINTPTR off = (RTGCUINTPTR)GCPtr - (RTGCUINTPTR)pCur->GCPtr;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync ("Invalid page range %#x LB%#x. mapping '%s' %#x to %#x\n",
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync GCPtr, cb, pCur->pszDesc, pCur->GCPtr, pCur->GCPtrLast),
39cac49f62afd27b0ffdbb779c7c64211939030cvboxsync * Perform the requested operation.
39cac49f62afd27b0ffdbb779c7c64211939030cvboxsync while (cb > 0)
d82d7a8b44b27420e50f410d8ee5b990bb8b8f12vboxsync while (cb > 0 && iPTE < RT_ELEMENTS(pCur->aPTs[iPT].CTX_SUFF(pPT)->a))
d82d7a8b44b27420e50f410d8ee5b990bb8b8f12vboxsync /* 32-Bit */
d82d7a8b44b27420e50f410d8ee5b990bb8b8f12vboxsync pCur->aPTs[iPT].CTX_SUFF(pPT)->a[iPTE].u &= fMask | X86_PTE_PG_MASK;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync pCur->aPTs[iPT].CTX_SUFF(pPT)->a[iPTE].u |= fFlags & ~X86_PTE_PG_MASK;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync pCur->aPTs[iPT].CTX_SUFF(paPaePTs)[iPTE / 512].a[iPTE % 512].u &= fMask | X86_PTE_PAE_PG_MASK;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync pCur->aPTs[iPT].CTX_SUFF(paPaePTs)[iPTE / 512].a[iPTE % 512].u |= fFlags & ~X86_PTE_PAE_PG_MASK;
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync /* invalidate tls */
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync AssertMsgFailed(("Page range %#x LB%#x not found\n", GCPtr, cb));
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * Sets all PDEs involved with the mapping in the shadow page table.
d82d7a8b44b27420e50f410d8ee5b990bb8b8f12vboxsync * @param pVM The VM handle.
d82d7a8b44b27420e50f410d8ee5b990bb8b8f12vboxsync * @param pMap Pointer to the mapping in question.
d82d7a8b44b27420e50f410d8ee5b990bb8b8f12vboxsync * @param iNewPDE The index of the 32-bit PDE corresponding to the base of the mapping.
d82d7a8b44b27420e50f410d8ee5b990bb8b8f12vboxsyncvoid pgmMapSetShadowPDEs(PVM pVM, PPGMMAPPING pMap, unsigned iNewPDE)
d82d7a8b44b27420e50f410d8ee5b990bb8b8f12vboxsync Log4(("pgmMapSetShadowPDEs new pde %x (mappings enabled %d)\n", iNewPDE, pgmMapAreMappingsEnabled(&pVM->pgm.s)));
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync return; /* too early */
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync * Init the page tables and insert them into the page directories.
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync while (i-- > 0)
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync PX86PD pShw32BitPd = pgmShwGet32BitPDPtr(&pVM->pgm.s);
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync Assert(!(pShw32BitPd->a[iNewPDE].u & PGM_PDFLAGS_MAPPING));
078c5b8c5c814755aab943bf62cadef7e91c419cvboxsync pgmPoolFree(pVM, pShw32BitPd->a[iNewPDE].u & X86_PDE_PG_MASK, pVM->pgm.s.CTX_SUFF(pShwPageCR3)->idx, iNewPDE);
/* Default mapping page directory flags are read/write and supervisor; individual page attributes determine the final flags */
Pde.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:
if (!pShwPaePd)
GstPdpe.u = X86_PDPE_P; /* rw/us are reserved for PAE pdpte's; accessed bit causes invalid VT-x guest state errors */
if (pGstPdpe)
GstPdpe.u = X86_PDPE_P; /* rw/us are reserved for PAE pdpte's; accessed bit causes invalid VT-x guest state errors */
PdePae0.u = PGM_PDFLAGS_MAPPING | X86_PDE_P | X86_PDE_A | X86_PDE_RW | X86_PDE_US | pMap->aPTs[i].HCPhysPaePT0;
iPDE++;
PdePae1.u = PGM_PDFLAGS_MAPPING | X86_PDE_P | X86_PDE_A | X86_PDE_RW | X86_PDE_US | pMap->aPTs[i].HCPhysPaePT1;
AssertFailed();
Log(("pgmMapClearShadowPDEs old pde %x (mappings enabled %d)\n", iOldPDE, pgmMapAreMappingsEnabled(&pVM->pgm.s)));
iOldPDE += i;
iOldPDE--;
switch(enmShadowMode)
case PGMMODE_32_BIT:
case PGMMODE_PAE:
case PGMMODE_PAE_NX:
iPDE++;
/* Clear the PGM_PDFLAGS_MAPPING flag for the page directory pointer entry. (legacy PAE guest mode) */
AssertFailed();
#ifdef VBOX_STRICT
Log(("pgmMapCheckShadowPDEs pde %x (mappings enabled %d)\n", iPDE, pgmMapAreMappingsEnabled(&pVM->pgm.s)));
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),
("Expected %x vs %x\n", 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),
("Expected %RX64 vs %RX64\n", pShwPaePd->a[iPDE].u, (PGM_PDFLAGS_MAPPING | X86_PDE_P | X86_PDE_A | X86_PDE_RW | X86_PDE_US | (uint32_t)pMap->aPTs[i].HCPhysPT)));
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),
("Expected %RX64 vs %RX64\n", pShwPaePd->a[iPDE].u, (PGM_PDFLAGS_MAPPING | X86_PDE_P | X86_PDE_A | X86_PDE_RW | X86_PDE_US | (uint32_t)pMap->aPTs[i].HCPhysPT)));
AssertFailed();
# ifdef IN_RING0
AssertFailed();
# ifdef VBOX_WITH_PGMPOOL_PAGING_ONLY
/* @note A log flush (in RC) can cause problems when called from MapCR3 (inconsistent state will trigger assertions). */
return VINF_SUCCESS;
#ifdef IN_RING0
AssertFailed();
return VERR_INTERNAL_ERROR;
# ifdef VBOX_WITH_PGMPOOL_PAGING_ONLY
return VINF_SUCCESS;
return VINF_SUCCESS;
#ifdef IN_RING0
AssertFailed();
return VERR_INTERNAL_ERROR;
# ifdef VBOX_WITH_PGMPOOL_PAGING_ONLY
return VINF_SUCCESS;
return VINF_SUCCESS;
#ifdef IN_RING0
AssertFailed();
return VERR_INTERNAL_ERROR;
# ifdef VBOX_WITH_PGMPOOL_PAGING_ONLY
return VINF_SUCCESS;
#ifndef IN_RING0
while (iPT-- > 0)
#ifdef IN_RING3
while (iPT-- > 0)
#ifdef IN_RING3
AssertFailed();
# ifdef VBOX_WITH_PGMPOOL_PAGING_ONLY
return VINF_SUCCESS;
while (iPT-- > 0)
#ifdef IN_RING3
return VINF_PGM_SYNC_CR3;
if (!pCur)
while (iPT-- > 0)
#ifdef IN_RING3
return VINF_PGM_SYNC_CR3;
if (!pCur)
AssertFailed();
return VINF_SUCCESS;