PGMMap.cpp revision f827fea1108b8f8a1a5f63318f6ec3cf4a9e7010
f7b81dcd1a01325f5ca2806c2694b8f1d3b9eb4cvboxsync * PGM - Page Manager, Guest Context Mappings.
f74e35c55b43bdbc2d2ac21d61ac77ab764deadcvboxsync * Copyright (C) 2006-2007 innotek GmbH
f74e35c55b43bdbc2d2ac21d61ac77ab764deadcvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
e64031e20c39650a7bc902a3e1aba613b9415deevboxsync * available from http://www.virtualbox.org. This file is free software;
f74e35c55b43bdbc2d2ac21d61ac77ab764deadcvboxsync * you can redistribute it and/or modify it under the terms of the GNU
f74e35c55b43bdbc2d2ac21d61ac77ab764deadcvboxsync * General Public License (GPL) as published by the Free Software
f74e35c55b43bdbc2d2ac21d61ac77ab764deadcvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
f74e35c55b43bdbc2d2ac21d61ac77ab764deadcvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
f74e35c55b43bdbc2d2ac21d61ac77ab764deadcvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
f74e35c55b43bdbc2d2ac21d61ac77ab764deadcvboxsync/*******************************************************************************
f74e35c55b43bdbc2d2ac21d61ac77ab764deadcvboxsync* Header Files *
ebb998c68d059fb28283dd5631df33cbca044519vboxsync*******************************************************************************/
f74e35c55b43bdbc2d2ac21d61ac77ab764deadcvboxsync/*******************************************************************************
f74e35c55b43bdbc2d2ac21d61ac77ab764deadcvboxsync* Internal Functions *
f74e35c55b43bdbc2d2ac21d61ac77ab764deadcvboxsync*******************************************************************************/
f74e35c55b43bdbc2d2ac21d61ac77ab764deadcvboxsyncstatic void pgmR3MapClearPDEs(PPGM pPGM, PPGMMAPPING pMap, unsigned iOldPDE);
f74e35c55b43bdbc2d2ac21d61ac77ab764deadcvboxsyncstatic void pgmR3MapSetPDEs(PVM pVM, PPGMMAPPING pMap, unsigned iNewPDE);
f74e35c55b43bdbc2d2ac21d61ac77ab764deadcvboxsyncstatic int pgmR3MapIntermediateCheckOne(PVM pVM, uintptr_t uAddress, unsigned cPages, PX86PT pPTDefault, PX86PTPAE pPTPaeDefault);
f74e35c55b43bdbc2d2ac21d61ac77ab764deadcvboxsyncstatic void pgmR3MapIntermediateDoOne(PVM pVM, uintptr_t uAddress, RTHCPHYS HCPhys, unsigned cPages, PX86PT pPTDefault, PX86PTPAE pPTPaeDefault);
2599750883f13b2a38c421dc073df83e2f9cdae6vboxsync * Creates a page table based mapping in GC.
2599750883f13b2a38c421dc073df83e2f9cdae6vboxsync * @returns VBox status code.
f74e35c55b43bdbc2d2ac21d61ac77ab764deadcvboxsync * @param pVM VM Handle.
f74e35c55b43bdbc2d2ac21d61ac77ab764deadcvboxsync * @param GCPtr Virtual Address. (Page table aligned!)
2599750883f13b2a38c421dc073df83e2f9cdae6vboxsync * @param cb Size of the range. Must be a 4MB aligned!
2599750883f13b2a38c421dc073df83e2f9cdae6vboxsync * @param pfnRelocate Relocation callback function.
2599750883f13b2a38c421dc073df83e2f9cdae6vboxsync * @param pvUser User argument to the callback.
2599750883f13b2a38c421dc073df83e2f9cdae6vboxsync * @param pszDesc Pointer to description string. This must not be freed.
2599750883f13b2a38c421dc073df83e2f9cdae6vboxsyncPGMR3DECL(int) PGMR3MapPT(PVM pVM, RTGCPTR GCPtr, uint32_t cb, PFNPGMRELOCATE pfnRelocate, void *pvUser, const char *pszDesc)
f74e35c55b43bdbc2d2ac21d61ac77ab764deadcvboxsync LogFlow(("PGMR3MapPT: GCPtr=%#x cb=%d pfnRelocate=%p pvUser=%p pszDesc=%s\n", GCPtr, cb, pfnRelocate, pvUser, pszDesc));
2599750883f13b2a38c421dc073df83e2f9cdae6vboxsync AssertMsg(pVM->pgm.s.pInterPD && pVM->pgm.s.pHC32BitPD, ("Paging isn't initialized, init order problems!\n"));
f74e35c55b43bdbc2d2ac21d61ac77ab764deadcvboxsync * Validate input.
f74e35c55b43bdbc2d2ac21d61ac77ab764deadcvboxsync AssertMsgFailed(("Range wraps! GCPtr=%x GCPtrLast=%x\n", GCPtr, GCPtrLast));
f74e35c55b43bdbc2d2ac21d61ac77ab764deadcvboxsync AssertMsgFailed(("Mappings are fixed! It's not possible to add new mappings at this time!\n"));
f74e35c55b43bdbc2d2ac21d61ac77ab764deadcvboxsync * Find list location.
f74e35c55b43bdbc2d2ac21d61ac77ab764deadcvboxsync if (pCur->GCPtrLast >= GCPtr && pCur->GCPtr <= GCPtrLast)
f74e35c55b43bdbc2d2ac21d61ac77ab764deadcvboxsync AssertMsgFailed(("Address is already in use by %s. req %#x-%#x take %#x-%#x\n",
f74e35c55b43bdbc2d2ac21d61ac77ab764deadcvboxsync pCur->pszDesc, GCPtr, GCPtrLast, pCur->GCPtr, pCur->GCPtrLast));
f74e35c55b43bdbc2d2ac21d61ac77ab764deadcvboxsync LogRel(("VERR_PGM_MAPPING_CONFLICT: Address is already in use by %s. req %#x-%#x take %#x-%#x\n",
f74e35c55b43bdbc2d2ac21d61ac77ab764deadcvboxsync pCur->pszDesc, GCPtr, GCPtrLast, pCur->GCPtr, pCur->GCPtrLast));
b4b896baff58dad1f81179386beed73197bf59bevboxsync * Check for conflicts with intermediate mappings.
531c00db9f8998c8b606845f72098698c48e6290vboxsync unsigned i;
531c00db9f8998c8b606845f72098698c48e6290vboxsync for (i = 0; i < cPTs; i++)
531c00db9f8998c8b606845f72098698c48e6290vboxsync if (pVM->pgm.s.pInterPD->a[iPageDir + i].n.u1Present)
531c00db9f8998c8b606845f72098698c48e6290vboxsync AssertMsgFailed(("Address %#x is already in use by an intermediate mapping.\n", GCPtr + (i << PAGE_SHIFT)));
531c00db9f8998c8b606845f72098698c48e6290vboxsync LogRel(("VERR_PGM_MAPPING_CONFLICT: Address %#x is already in use by an intermediate mapping.\n", GCPtr + (i << PAGE_SHIFT)));
531c00db9f8998c8b606845f72098698c48e6290vboxsync /** @todo AMD64: add check in PAE structures too, so we can remove all the 32-Bit paging stuff there. */
a0c1e203edd9781c6d0f7560e37dbc729fef5991vboxsync * Allocate and initialize the new list node.
a0c1e203edd9781c6d0f7560e37dbc729fef5991vboxsync int rc = MMHyperAlloc(pVM, RT_OFFSETOF(PGMMAPPING, aPTs[cPTs]), 0, MM_TAG_PGM, (void **)&pNew);
531c00db9f8998c8b606845f72098698c48e6290vboxsync * Allocate page tables and insert them into the page directories.
2599750883f13b2a38c421dc073df83e2f9cdae6vboxsync * (One 32-bit PT and two PAE PTs.)
531c00db9f8998c8b606845f72098698c48e6290vboxsync rc = MMHyperAlloc(pVM, PAGE_SIZE * 3 * cPTs, PAGE_SIZE, MM_TAG_PGM, (void **)&pbPTs);
531c00db9f8998c8b606845f72098698c48e6290vboxsync * Init the page tables and insert them into the page directories.
531c00db9f8998c8b606845f72098698c48e6290vboxsync Log4(("PGMR3MapPT: GCPtr=%VGv cPTs=%u pbPTs=%p\n", GCPtr, cPTs, pbPTs));
531c00db9f8998c8b606845f72098698c48e6290vboxsync for (i = 0; i < cPTs; i++)
ebb998c68d059fb28283dd5631df33cbca044519vboxsync pNew->aPTs[i].pPTGC = MMHyperR3ToGC(pVM, pNew->aPTs[i].pPTR3);
c0704390ccf86cde88ad1e69dedf77d3e57aa15avboxsync pNew->aPTs[i].pPTR0 = MMHyperR3ToR0(pVM, pNew->aPTs[i].pPTR3);
c0704390ccf86cde88ad1e69dedf77d3e57aa15avboxsync pNew->aPTs[i].HCPhysPT = MMR3HyperHCVirt2HCPhys(pVM, pNew->aPTs[i].pPTR3);
c0704390ccf86cde88ad1e69dedf77d3e57aa15avboxsync Log4(("PGMR3MapPT: i=%d: pPTHC=%p pPTGC=%p HCPhysPT=%RHp\n",
978580e1feeb8eb42df0b6366b9c8bebbb9fb02cvboxsync i, pNew->aPTs[i].pPTR3, pNew->aPTs[i].pPTGC, pNew->aPTs[i].HCPhysPT));
978580e1feeb8eb42df0b6366b9c8bebbb9fb02cvboxsync pNew->aPTs[i].HCPhysPaePT0 = MMR3HyperHCVirt2HCPhys(pVM, pbPTs);
978580e1feeb8eb42df0b6366b9c8bebbb9fb02cvboxsync pNew->aPTs[i].HCPhysPaePT1 = MMR3HyperHCVirt2HCPhys(pVM, pbPTs + PAGE_SIZE);
c0704390ccf86cde88ad1e69dedf77d3e57aa15avboxsync pNew->aPTs[i].paPaePTsGC = MMHyperR3ToGC(pVM, pbPTs);
c0704390ccf86cde88ad1e69dedf77d3e57aa15avboxsync pNew->aPTs[i].paPaePTsR0 = MMHyperR3ToR0(pVM, pbPTs);
b4b896baff58dad1f81179386beed73197bf59bevboxsync Log4(("PGMR3MapPT: i=%d: paPaePTsHC=%p paPaePTsGC=%p HCPhysPaePT0=%RHp HCPhysPaePT1=%RHp\n",
b4b896baff58dad1f81179386beed73197bf59bevboxsync i, pNew->aPTs[i].paPaePTsR3, pNew->aPTs[i].paPaePTsGC, pNew->aPTs[i].HCPhysPaePT0, pNew->aPTs[i].HCPhysPaePT1));
ebb998c68d059fb28283dd5631df33cbca044519vboxsync * Insert the new mapping.
ebb998c68d059fb28283dd5631df33cbca044519vboxsync pNew->pNextGC = pCur ? MMHyperR3ToGC(pVM, pCur) : 0;
c0704390ccf86cde88ad1e69dedf77d3e57aa15avboxsync pNew->pNextR0 = pCur ? MMHyperR3ToR0(pVM, pCur) : 0;
c0704390ccf86cde88ad1e69dedf77d3e57aa15avboxsync * Removes a page table based mapping.
b4b896baff58dad1f81179386beed73197bf59bevboxsync * @returns VBox status code.
b4b896baff58dad1f81179386beed73197bf59bevboxsync * @param pVM VM Handle.
b4b896baff58dad1f81179386beed73197bf59bevboxsync * @param GCPtr Virtual Address. (Page table aligned!)
if (pPrev)
return VINF_SUCCESS;
return VERR_INVALID_PARAMETER;
return VINF_SUCCESS;
return VERR_INVALID_PARAMETER;
return VERR_INVALID_PARAMETER;
while (pCur)
if (!pCur)
LogRel(("PGMR3MappingsFix: Conflicts with intermediate PDE %#x (GCPtrBase=%VGv 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;
#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=%VHp 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)
AssertMsgFailed(("Conflict iPTE=%#x iPDE=%#x uAddress=%VHv pPT->a[iPTE].u=%RX32\n", iPTE, iPDE, uAddress, pPT->a[iPTE].u));
AssertMsgFailed(("Conflict iPTE=%#x iPDE=%#x uAddress=%VHv 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;
Log(("PGM: Relocating %s from %#x to %#x\n", pMapping->pszDesc, iPDOld << X86_PD_SHIFT, iPDNew << X86_PD_SHIFT));
if (pPrevMap)
if (pPrev)
pMapping->pfnRelocate(pVM, iPDOld << X86_PD_SHIFT, iPDNew << X86_PD_SHIFT, PGMRELOCATECALL_RELOCATE, pMapping->pvUser);
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, iPDOld << X86_PD_SHIFT, iPDNew << X86_PD_SHIFT, PGMRELOCATECALL_SUGGEST, pMapping->pvUser))
return VINF_SUCCESS;
AssertMsgFailed(("Failed to relocate page table mapping '%s' from %#x! (cPTs=%d)\n", pMapping->pszDesc, iPDOld << X86_PD_SHIFT, cPTs));
return VERR_PGM_NO_HYPERVISOR_ADDRESS;
PGMR3DECL(bool) PGMR3MapHasConflicts(PVM pVM, uint64_t cr3, bool fRawR0) /** @todo how many HasConflict constructs do we really need? */
while (iPT-- > 0)
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;