PGMR0.cpp revision e4d7b580d72e968d3753363ab36e196a968c1947
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * PGM - Page Manager and Monitor, Ring-0.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * Copyright (C) 2007 Oracle Corporation
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * available from http://www.virtualbox.org. This file is free software;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * you can redistribute it and/or modify it under the terms of the GNU
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * General Public License (GPL) as published by the Free Software
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync/*******************************************************************************
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync* Header Files *
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync*******************************************************************************/
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync#define PGM_BTH_NAME(name) PGM_BTH_NAME_32BIT_PROT(name)
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync#define PGM_BTH_NAME(name) PGM_BTH_NAME_PAE_PROT(name)
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync#define PGM_BTH_NAME(name) PGM_BTH_NAME_AMD64_PROT(name)
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync#define PGM_BTH_NAME(name) PGM_BTH_NAME_EPT_PROT(name)
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * Worker function for PGMR3PhysAllocateHandyPages and pgmPhysEnsureHandyPage.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * @returns The following VBox status codes.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * @retval VINF_SUCCESS on success. FF cleared.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * @retval VINF_EM_NO_MEMORY if we're out of memory. The FF is set in this case.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * @param pVM The VM handle.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * @param pVCpu The VMCPU handle.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * @remarks Must be called from within the PGM critical section. The caller
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * must clear the new pages.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsyncVMMR0DECL(int) PGMR0PhysAllocateHandyPages(PVM pVM, PVMCPU pVCpu)
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync Assert(PDMCritSectIsOwnerEx(&pVM->pgm.s.CritSect, pVCpu->idCpu));
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * Check for error injection.
633bed59cef34fca736f18bf63e608e02a7bbfdcvboxsync * Try allocate a full set of handy pages.
633bed59cef34fca736f18bf63e608e02a7bbfdcvboxsync AssertReturn(iFirst <= RT_ELEMENTS(pVM->pgm.s.aHandyPages), VERR_INTERNAL_ERROR);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync uint32_t cPages = RT_ELEMENTS(pVM->pgm.s.aHandyPages) - iFirst;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync int rc = GMMR0AllocateHandyPages(pVM, pVCpu->idCpu, cPages, cPages, &pVM->pgm.s.aHandyPages[iFirst]);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pVM->pgm.s.aHandyPages); i++)
faa7602db7e32056326da7e169b5f505c607138fvboxsync Assert(pVM->pgm.s.aHandyPages[i].idPage != NIL_GMM_PAGEID);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync Assert(pVM->pgm.s.aHandyPages[i].idPage <= GMM_PAGEID_LAST);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync Assert(pVM->pgm.s.aHandyPages[i].idSharedPage == NIL_GMM_PAGEID);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync Assert(pVM->pgm.s.aHandyPages[i].HCPhysGCPhys != NIL_RTHCPHYS);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync Assert(!(pVM->pgm.s.aHandyPages[i].HCPhysGCPhys & ~X86_PTE_PAE_PG_MASK));
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync pVM->pgm.s.cHandyPages = RT_ELEMENTS(pVM->pgm.s.aHandyPages);
7220367ea1944fa8a7694534401321ad86eb70c6vboxsync /* We're ASSUMING that GMM has updated all the entires before failing us. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync for (i = iFirst; i < RT_ELEMENTS(pVM->pgm.s.aHandyPages); i++)
7220367ea1944fa8a7694534401321ad86eb70c6vboxsync Assert(pVM->pgm.s.aHandyPages[i].idPage == NIL_GMM_PAGEID);
7220367ea1944fa8a7694534401321ad86eb70c6vboxsync Assert(pVM->pgm.s.aHandyPages[i].idSharedPage == NIL_GMM_PAGEID);
7220367ea1944fa8a7694534401321ad86eb70c6vboxsync Assert(pVM->pgm.s.aHandyPages[i].HCPhysGCPhys == NIL_RTHCPHYS);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * Reduce the number of pages until we hit the minimum limit.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync rc = GMMR0AllocateHandyPages(pVM, pVCpu->idCpu, cPages, cPages, &pVM->pgm.s.aHandyPages[iFirst]);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync while (i-- > 0)
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync Assert(pVM->pgm.s.aHandyPages[i].idPage != NIL_GMM_PAGEID);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync Assert(pVM->pgm.s.aHandyPages[i].idPage <= GMM_PAGEID_LAST);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync Assert(pVM->pgm.s.aHandyPages[i].idSharedPage == NIL_GMM_PAGEID);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync Assert(pVM->pgm.s.aHandyPages[i].HCPhysGCPhys != NIL_RTHCPHYS);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync Assert(!(pVM->pgm.s.aHandyPages[i].HCPhysGCPhys & ~X86_PTE_PAE_PG_MASK));
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync for (i = cPages + iFirst; i < RT_ELEMENTS(pVM->pgm.s.aHandyPages); i++)
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync Assert(pVM->pgm.s.aHandyPages[i].idPage == NIL_GMM_PAGEID);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync Assert(pVM->pgm.s.aHandyPages[i].idSharedPage == NIL_GMM_PAGEID);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync Assert(pVM->pgm.s.aHandyPages[i].HCPhysGCPhys == NIL_RTHCPHYS);
return rc;
int rc = GMMR0AllocateLargePage(pVM, pVCpu->idCpu, _2M, &pVM->pgm.s.aLargeHandyPage[0].idPage, &pVM->pgm.s.aLargeHandyPage[0].HCPhysGCPhys);
return rc;
VMMR0DECL(int) PGMR0Trap0eHandlerNestedPaging(PVM pVM, PVMCPU pVCpu, PGMMODE enmShwPagingMode, RTGCUINT uErr, PCPUMCTXCORE pRegFrame, RTGCPHYS pvFault)
int rc;
LogFlow(("PGMTrap0eHandler: uErr=%RGx pvFault=%RGp eip=%RGv\n", uErr, pvFault, (RTGCPTR)pRegFrame->rip));
AssertMsg(enmShwPagingMode == PGMMODE_32_BIT || enmShwPagingMode == PGMMODE_PAE || enmShwPagingMode == PGMMODE_PAE_NX || enmShwPagingMode == PGMMODE_AMD64 || enmShwPagingMode == PGMMODE_AMD64_NX || enmShwPagingMode == PGMMODE_EPT, ("enmShwPagingMode=%d\n", enmShwPagingMode));
#ifdef VBOX_WITH_STATISTICS
* We pretend the guest is in protected mode without paging, so we can use existing code to build the
bool fLockTaken = false;
switch(enmShwPagingMode)
case PGMMODE_32_BIT:
case PGMMODE_PAE:
case PGMMODE_PAE_NX:
case PGMMODE_AMD64:
case PGMMODE_AMD64_NX:
case PGMMODE_EPT:
AssertFailed();
if (fLockTaken)
Log(("WARNING: Unexpected VERR_PAGE_TABLE_NOT_PRESENT (%d) for page fault at %RGp 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. */
return rc;
#ifdef VBOX_WITH_PAGE_SHARING
bool fFlushTLBs = false;
AssertMsgReturn(pReq->Hdr.cbReq >= sizeof(*pReq) && pReq->Hdr.cbReq == RT_UOFFSETOF(GMMREGISTERSHAREDMODULEREQ, aRegions[pReq->cRegions]), ("%#x != %#x\n", pReq->Hdr.cbReq, sizeof(*pReq)), VERR_INVALID_PARAMETER);
unsigned idxPage = 0;
bool fValidChanges = false;
if (paPageDesc)
if (!paPageDesc)
AssertFailed();
goto end;
while (cbRegion)
if ( pPage
fValidChanges = true;
idxPage++;
if (fValidChanges)
for (unsigned i = 0; i < idxPage; i++)
if (!pPage)
AssertFailed();
goto end;
bool fFlush = false;
rc = pgmPoolTrackUpdateGCPhys(pVM, paPageDesc[idxPage].GCPhys, pPage, true /* clear the entries */, &fFlush);
goto end;
Assert(rc == VINF_SUCCESS || (VMCPU_FF_ISSET(pVCpu, VMCPU_FF_PGM_SYNC_CR3) && (pVCpu->pgm.s.fSyncFlags & PGM_SYNC_CLEAR_PGM_POOL)));
end:
if (fFlushTLBs)
if (paPageDesc)
return rc;