PGMMap.cpp revision 08bc90fc2848c80bf8270bedc883745b8398e186
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * PGM - Page Manager, Guest Context Mappings.
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * Copyright (C) 2006-2007 Sun Microsystems, Inc.
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * available from http://www.virtualbox.org. This file is free software;
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * you can redistribute it and/or modify it under the terms of the GNU
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * General Public License (GPL) as published by the Free Software
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * additional information or have any questions.
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync/*******************************************************************************
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync* Header Files *
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync*******************************************************************************/
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync/*******************************************************************************
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync* Internal Functions *
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync*******************************************************************************/
deb4998ba50060c48cce222fd18a8eed053918d7vboxsyncstatic void pgmR3MapClearPDEs(PPGM pPGM, PPGMMAPPING pMap, unsigned iOldPDE);
deb4998ba50060c48cce222fd18a8eed053918d7vboxsyncstatic void pgmR3MapSetPDEs(PVM pVM, PPGMMAPPING pMap, unsigned iNewPDE);
deb4998ba50060c48cce222fd18a8eed053918d7vboxsyncstatic int pgmR3MapIntermediateCheckOne(PVM pVM, uintptr_t uAddress, unsigned cPages, PX86PT pPTDefault, PX86PTPAE pPTPaeDefault);
deb4998ba50060c48cce222fd18a8eed053918d7vboxsyncstatic void pgmR3MapIntermediateDoOne(PVM pVM, uintptr_t uAddress, RTHCPHYS HCPhys, unsigned cPages, PX86PT pPTDefault, PX86PTPAE pPTPaeDefault);
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * Creates a page table based mapping in GC.
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * @returns VBox status code.
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * @param pVM VM Handle.
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * @param GCPtr Virtual Address. (Page table aligned!)
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * @param cb Size of the range. Must be a 4MB aligned!
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * @param pfnRelocate Relocation callback function.
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * @param pvUser User argument to the callback.
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * @param pszDesc Pointer to description string. This must not be freed.
deb4998ba50060c48cce222fd18a8eed053918d7vboxsyncVMMR3DECL(int) PGMR3MapPT(PVM pVM, RTGCPTR GCPtr, uint32_t cb, PFNPGMRELOCATE pfnRelocate, void *pvUser, const char *pszDesc)
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync LogFlow(("PGMR3MapPT: GCPtr=%#x cb=%d pfnRelocate=%p pvUser=%p pszDesc=%s\n", GCPtr, cb, pfnRelocate, pvUser, pszDesc));
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync AssertMsg(pVM->pgm.s.pInterPD && pVM->pgm.s.pHC32BitPD, ("Paging isn't initialized, init order problems!\n"));
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * Validate input.
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync AssertMsgFailed(("Range wraps! GCPtr=%x GCPtrLast=%x\n", GCPtr, GCPtrLast));
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync AssertMsgFailed(("Mappings are fixed! It's not possible to add new mappings at this time!\n"));
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * Find list location.
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync if (pCur->GCPtrLast >= GCPtr && pCur->GCPtr <= GCPtrLast)
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync AssertMsgFailed(("Address is already in use by %s. req %#x-%#x take %#x-%#x\n",
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync pCur->pszDesc, GCPtr, GCPtrLast, pCur->GCPtr, pCur->GCPtrLast));
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync LogRel(("VERR_PGM_MAPPING_CONFLICT: Address is already in use by %s. req %#x-%#x take %#x-%#x\n",
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync pCur->pszDesc, GCPtr, GCPtrLast, pCur->GCPtr, pCur->GCPtrLast));
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * Check for conflicts with intermediate mappings.
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync unsigned i;
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync for (i = 0; i < cPTs; i++)
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync if (pVM->pgm.s.pInterPD->a[iPageDir + i].n.u1Present)
AssertMsgFailed(("Address %#x is already in use by an intermediate mapping.\n", GCPtr + (i << PAGE_SHIFT)));
LogRel(("VERR_PGM_MAPPING_CONFLICT: Address %#x is already in use by an intermediate mapping.\n", GCPtr + (i << PAGE_SHIFT)));
return VERR_PGM_MAPPING_CONFLICT;
/** @todo AMD64: add check in PAE structures too, so we can remove all the 32-Bit paging stuff there. */
return rc;
return VERR_NO_MEMORY;
for (i = 0; i < cPTs; i++)
Log4(("PGMR3MapPT: i=%d: paPaePTsR#=%RHv paPaePTsRC=%RRv paPaePTsR#=%RHv HCPhysPaePT0=%RHp HCPhysPaePT1=%RHp\n",
i, pNew->aPTs[i].paPaePTsR3, pNew->aPTs[i].paPaePTsRC, pNew->aPTs[i].paPaePTsR0, pNew->aPTs[i].HCPhysPaePT0, pNew->aPTs[i].HCPhysPaePT1));
if (pPrev)
return VINF_SUCCESS;
while (pCur)
if (pPrev)
return VINF_SUCCESS;
return VERR_INVALID_PARAMETER;
return VINF_SUCCESS;
return VINF_SUCCESS;
return VERR_INVALID_PARAMETER;
return VERR_INVALID_PARAMETER;
while (pCur)
if (!pCur)
LogRel(("PGMR3MappingsFix: Conflicts with intermediate PDE %#x (GCPtrBase=%RGv cb=%#zx). The guest should retry.\n",
return VERR_PGM_MAPPINGS_FIX_CONFLICT;
while (pCur)
AssertMsgFailed(("The suggested fixed address %#x was rejected by '%s'!\n", GCPtrCur, pCur->pszDesc));
return VERR_PGM_MAPPINGS_FIX_REJECTED;
return VERR_PGM_MAPPINGS_FIX_TOO_SMALL;
while (pCur)
pCur->pfnRelocate(pVM, iPDOld << X86_PD_SHIFT, iPDNew << X86_PD_SHIFT, PGMRELOCATECALL_RELOCATE, pCur->pvUser);
return VINF_SUCCESS;
return VINF_SUCCESS;
#ifdef PGMPOOL_WITH_MONITORING
return VINF_SUCCESS;
/* We only care about the first 4GB, because on AMD64 we'll be repeating them all over the address space. */
AssertMsg(HCPhys < _4G && HCPhys + cbPages < _4G, ("Addr=%RTptr HCPhys=%RHp cbPages=%d\n", Addr, HCPhys, cbPages));
int rc = pgmR3MapIntermediateCheckOne(pVM, uAddress, cPages, pVM->pgm.s.apInterPTs[0], pVM->pgm.s.apInterPaePTs[0]);
return rc;
rc = pgmR3MapIntermediateCheckOne(pVM, (uintptr_t)HCPhys, cPages, pVM->pgm.s.apInterPTs[1], pVM->pgm.s.apInterPaePTs[1]);
return rc;
pgmR3MapIntermediateDoOne(pVM, uAddress, HCPhys, cPages, pVM->pgm.s.apInterPTs[0], pVM->pgm.s.apInterPaePTs[0]);
pgmR3MapIntermediateDoOne(pVM, (uintptr_t)HCPhys, HCPhys, cPages, pVM->pgm.s.apInterPTs[1], pVM->pgm.s.apInterPaePTs[1]);
return VINF_SUCCESS;
static int pgmR3MapIntermediateCheckOne(PVM pVM, uintptr_t uAddress, unsigned cPages, PX86PT pPTDefault, PX86PTPAE pPTPaeDefault)
while (cPages > 0)
AssertLogRelMsgFailedReturn(("Conflict between core code and PGMR3Mapping(). uAddress=%RHv\n", uAddress),
AssertLogRelMsgFailedReturn(("Conflict iPTE=%#x iPDE=%#x uAddress=%RHv pPT->a[iPTE].u=%RX32\n", iPTE, iPDE, uAddress, pPT->a[iPTE].u),
AssertLogRelMsgFailedReturn(("Conflict between core code and PGMR3Mapping(). uAddress=%RHv\n", uAddress),
AssertLogRelMsgFailedReturn(("Conflict iPTE=%#x iPDE=%#x uAddress=%RHv pPTPae->a[iPTE].u=%#RX64\n", iPTE, iPDE, uAddress, pPTPae->a[iPTE].u),
cPages--;
return VINF_SUCCESS;
static void pgmR3MapIntermediateDoOne(PVM pVM, uintptr_t uAddress, RTHCPHYS HCPhys, unsigned cPages, PX86PT pPTDefault, PX86PTPAE pPTPaeDefault)
while (cPages > 0)
pPTPae = (PX86PTPAE)MMPagePhys2Page(pVM, pVM->pgm.s.apInterPaePDs[iPDPE]->a[iPDE].u & X86_PDE_PAE_PG_MASK);
cPages--;
iOldPDE += i;
iOldPDE--;
iPDE++;
/* Clear the PGM_PDFLAGS_MAPPING flag for the page directory pointer entry. (legacy PAE guest mode) */
iNewPDE += i;
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;
pgmPoolFree(pVM, pPGM->apHCPaePDs[iPD]->a[iPDE].u & X86_PDE_PAE_PG_MASK, PGMPOOL_IDX_PAE_PD, iNewPDE * 2);
PdePae0.u = PGM_PDFLAGS_MAPPING | X86_PDE_P | X86_PDE_A | X86_PDE_RW | X86_PDE_US | pMap->aPTs[i].HCPhysPaePT0;
iPDE++;
pgmPoolFree(pVM, pPGM->apHCPaePDs[iPD]->a[iPDE].u & X86_PDE_PAE_PG_MASK, PGMPOOL_IDX_PAE_PD, iNewPDE * 2 + 1);
PdePae1.u = PGM_PDFLAGS_MAPPING | X86_PDE_P | X86_PDE_A | X86_PDE_RW | X86_PDE_US | pMap->aPTs[i].HCPhysPaePT1;
void pgmR3MapRelocate(PVM pVM, PPGMMAPPING pMapping, RTGCPTR GCPtrOldMapping, RTGCPTR GCPtrNewMapping)
Log(("PGM: Relocating %s from %RGv to %RGv\n", pMapping->pszDesc, GCPtrOldMapping, GCPtrNewMapping));
if (pPrevMap)
if (pPrev)
pMapping->pfnRelocate(pVM, iPDOld << X86_PD_SHIFT, iPDNew << X86_PD_SHIFT, PGMRELOCATECALL_RELOCATE, pMapping->pvUser);
int pgmR3SyncPTResolveConflict(PVM pVM, PPGMMAPPING pMapping, PX86PD pPDSrc, RTGCPTR GCPtrOldMapping)
while (iPDNew-- > 0)
bool fOk = true;
fOk = false;
if (!fOk)
bool fOk = true;
unsigned i = cPTs;
while (fOk && i-- > 0)
if (!fOk)
if (pMapping->pfnRelocate(pVM, GCPtrOldMapping, GCPtrNewMapping, PGMRELOCATECALL_SUGGEST, pMapping->pvUser))
return VINF_SUCCESS;
AssertMsgFailed(("Failed to relocate page table mapping '%s' from %#x! (cPTs=%d)\n", pMapping->pszDesc, GCPtrOldMapping, cPTs));
return VERR_PGM_NO_HYPERVISOR_ADDRESS;
unsigned iPDSrc;
while (iPDNew-- > 0)
if (pPDSrc)
bool fOk = true;
fOk = false;
if (!fOk)
bool fOk = true;
unsigned i = cPTs;
while (fOk && i-- > 0)
if (!fOk)
if (pMapping->pfnRelocate(pVM, GCPtrOldMapping, GCPtrNewMapping, PGMRELOCATECALL_SUGGEST, pMapping->pvUser))
return VINF_SUCCESS;
AssertMsgFailed(("Failed to relocate page table mapping '%s' from %#x! (cPTs=%d)\n", pMapping->pszDesc, GCPtrOldMapping, pMapping->cb >> X86_PD_PAE_SHIFT));
return VERR_PGM_NO_HYPERVISOR_ADDRESS;
VMMR3DECL(bool) PGMR3MapHasConflicts(PVM pVM, uint64_t cr3, bool fRawR0) /** @todo how many HasConflict constructs do we really need? */
while (iPT-- > 0)
while (iPT-- > 0)
AssertFailed();
return rc;
if (!cb)
return VINF_SUCCESS;
while (pCur)
return VERR_INVALID_PARAMETER;
return VERR_PAGE_NOT_PRESENT;
RTHCPHYS HCPhys = CTXALLSUFF(pCur->aPTs[iPT].paPaePTs)[iPTE / 512].a[iPTE % 512].u & X86_PTE_PAE_PG_MASK;
void *pvPage;
return rc;
return VINF_SUCCESS;
return VERR_INVALID_POINTER;