PGMR0.cpp revision 43dff6077acb4176145b18bdb862eb73620182d2
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * PGM - Page Manager and Monitor, Ring-0.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * Copyright (C) 2007-2011 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 * Instantiate the ring-0 header/code templates.
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));
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * Check for error injection.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * Try allocate a full set of handy pages.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync 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++)
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 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++)
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);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * Reduce the number of pages until we hit the minimum limit.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync rc = GMMR0AllocateHandyPages(pVM, pVCpu->idCpu, 0, 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;
#ifdef VBOX_WITH_PCI_PASSTHROUGH
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
return rc;
#ifdef VBOX_WITH_PCI_PASSTHROUGH
while (cLeft-- > 0)
pPage++;
return rc;
VMMR0DECL(int) PGMR0Trap0eHandlerNestedPaging(PVM pVM, PVMCPU pVCpu, PGMMODE enmShwPagingMode, RTGCUINT uErr,
int rc;
LogFlow(("PGMTrap0eHandler: uErr=%RGx GCPhysFault=%RGp eip=%RGv\n", uErr, GCPhysFault, (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,
#ifdef VBOX_WITH_STATISTICS
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, GCPhysFault, uErr, pRegFrame->rip));
/* Some kind of inconsistency in the SMP case; it's safe to just execute the instruction again; not sure about
pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eTime2Misc; });
STAM_PROFILE_STOP_EX(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0e, pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution), a);
return rc;
VMMR0DECL(VBOXSTRICTRC) PGMR0Trap0eHandlerNPMisconfig(PVM pVM, PVMCPU pVCpu, PGMMODE enmShwPagingMode,
#ifdef PGM_WITH_MMIO_OPTIMIZATIONS
Log(("PGMR0Trap0eHandlerNPMisconfig: Resyncing aliases / tmp-off page at %RGp (uErr=%#x) %R[pgmpage]\n", GCPhysFault, uErr, pPage));
Log6(("PGMR0Trap0eHandlerNPMisconfig: calling %p(,%#x,,%RGp,%p)\n", pfnHandler, uErr, GCPhysFault, pvUser));
rc = pfnHandler(pVM, uErr == UINT32_MAX ? RTGCPTR_MAX : uErr, pRegFrame, GCPhysFault, GCPhysFault, pvUser);
#ifdef VBOX_WITH_STATISTICS
if (pHandler)
return rc;
return VERR_INTERNAL_ERROR_4;