PGMR0.cpp revision 19d274949f66f4797eb8850fe9c8de3e6ec931e8
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * PGM - Page Manager and Monitor, Ring-0.
506df97a8c78dacfe69bc4d3ee5d3de832d0f19avboxsync * Copyright (C) 2007-2011 Oracle Corporation
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync * available from http://www.virtualbox.org. This file is free software;
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync * you can redistribute it and/or modify it under the terms of the GNU
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync * General Public License (GPL) as published by the Free Software
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/*******************************************************************************
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync* Header Files *
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync*******************************************************************************/
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Instantiate the ring-0 header/code templates.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#define PGM_BTH_NAME(name) PGM_BTH_NAME_32BIT_PROT(name)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#define PGM_BTH_NAME(name) PGM_BTH_NAME_PAE_PROT(name)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#define PGM_BTH_NAME(name) PGM_BTH_NAME_AMD64_PROT(name)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#define PGM_BTH_NAME(name) PGM_BTH_NAME_EPT_PROT(name)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Worker function for PGMR3PhysAllocateHandyPages and pgmPhysEnsureHandyPage.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @returns The following VBox status codes.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @retval VINF_SUCCESS on success. FF cleared.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @retval VINF_EM_NO_MEMORY if we're out of memory. The FF is set in this case.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pVM Pointer to the VM.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pVCpu Pointer to the VMCPU.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @remarks Must be called from within the PGM critical section. The caller
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * must clear the new pages.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsyncVMMR0DECL(int) PGMR0PhysAllocateHandyPages(PVM pVM, PVMCPU pVCpu)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Check for error injection.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Try allocate a full set of handy pages.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync AssertReturn(iFirst <= RT_ELEMENTS(pVM->pgm.s.aHandyPages), VERR_PGM_HANDY_PAGE_IPE);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync uint32_t cPages = RT_ELEMENTS(pVM->pgm.s.aHandyPages) - iFirst;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync int rc = GMMR0AllocateHandyPages(pVM, pVCpu->idCpu, cPages, cPages, &pVM->pgm.s.aHandyPages[iFirst]);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pVM->pgm.s.aHandyPages); i++)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(pVM->pgm.s.aHandyPages[i].idPage != NIL_GMM_PAGEID);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(pVM->pgm.s.aHandyPages[i].idPage <= GMM_PAGEID_LAST);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(pVM->pgm.s.aHandyPages[i].idSharedPage == NIL_GMM_PAGEID);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(pVM->pgm.s.aHandyPages[i].HCPhysGCPhys != NIL_RTHCPHYS);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(!(pVM->pgm.s.aHandyPages[i].HCPhysGCPhys & ~X86_PTE_PAE_PG_MASK));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pVM->pgm.s.cHandyPages = RT_ELEMENTS(pVM->pgm.s.aHandyPages);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* We're ASSUMING that GMM has updated all the entires before failing us. */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync for (i = iFirst; i < RT_ELEMENTS(pVM->pgm.s.aHandyPages); i++)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(pVM->pgm.s.aHandyPages[i].idPage == NIL_GMM_PAGEID);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(pVM->pgm.s.aHandyPages[i].idSharedPage == NIL_GMM_PAGEID);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(pVM->pgm.s.aHandyPages[i].HCPhysGCPhys == NIL_RTHCPHYS);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Reduce the number of pages until we hit the minimum limit.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync rc = GMMR0AllocateHandyPages(pVM, pVCpu->idCpu, 0, cPages, &pVM->pgm.s.aHandyPages[iFirst]);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync while (i-- > 0)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(pVM->pgm.s.aHandyPages[i].idPage != NIL_GMM_PAGEID);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(pVM->pgm.s.aHandyPages[i].idPage <= GMM_PAGEID_LAST);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(pVM->pgm.s.aHandyPages[i].idSharedPage == NIL_GMM_PAGEID);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(pVM->pgm.s.aHandyPages[i].HCPhysGCPhys != NIL_RTHCPHYS);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(!(pVM->pgm.s.aHandyPages[i].HCPhysGCPhys & ~X86_PTE_PAE_PG_MASK));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync for (i = cPages + iFirst; i < RT_ELEMENTS(pVM->pgm.s.aHandyPages); i++)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(pVM->pgm.s.aHandyPages[i].idPage == NIL_GMM_PAGEID);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(pVM->pgm.s.aHandyPages[i].idSharedPage == NIL_GMM_PAGEID);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(pVM->pgm.s.aHandyPages[i].HCPhysGCPhys == NIL_RTHCPHYS);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync LogRel(("PGMR0PhysAllocateHandyPages: rc=%Rrc iFirst=%d cPages=%d\n", rc, iFirst, cPages));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync LogFlow(("PGMR0PhysAllocateHandyPages: cPages=%d rc=%Rrc\n", cPages, rc));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Worker function for PGMR3PhysAllocateLargeHandyPage
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @returns The following VBox status codes.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @retval VINF_SUCCESS on success.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @retval VINF_EM_NO_MEMORY if we're out of memory.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pVM Pointer to the VM.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pVCpu Pointer to the VMCPU.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @remarks Must be called from within the PGM critical section. The caller
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * must clear the new pages.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsyncVMMR0DECL(int) PGMR0PhysAllocateLargeHandyPage(PVM pVM, PVMCPU pVCpu)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync int rc = GMMR0AllocateLargePage(pVM, pVCpu->idCpu, _2M,
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/* Interface sketch. The interface belongs to a global PCI pass-through
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync manager. It shall use the global VM handle, not the user VM handle to
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync store the per-VM info (domain) since that is all ring-0 stuff, thus
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync passing pGVM here. I've tentitively prefixed the functions 'GPciRawR0',
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync we can discuss the PciRaw code re-organtization when I'm back from
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync I've implemented the initial IOMMU set up below. For things to work
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync reliably, we will probably need add a whole bunch of checks and
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync GPciRawR0GuestPageUpdate call to the PGM code. For the present,
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync assuming nested paging (enforced) and prealloc (enforced), no
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync ballooning (check missing), page sharing (check missing) or live
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync migration (check missing), it might work fine. At least if some
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync VM power-off hook is present and can tear down the IOMMU page tables. */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Tells the global PCI pass-through manager that we are about to set up the
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * guest page to host page mappings for the specfied VM.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @returns VBox status code.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pGVM The ring-0 VM structure.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsyncVMMR0_INT_DECL(int) GPciRawR0GuestPageBeginAssignments(PGVM pGVM)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Assigns a host page mapping for a guest page.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * This is only used when setting up the mappings, i.e. between
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * GPciRawR0GuestPageBeginAssignments and GPciRawR0GuestPageEndAssignments.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @returns VBox status code.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pGVM The ring-0 VM structure.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param GCPhys The address of the guest page (page aligned).
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param HCPhys The address of the host page (page aligned).
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsyncVMMR0_INT_DECL(int) GPciRawR0GuestPageAssign(PGVM pGVM, RTGCPHYS GCPhys, RTHCPHYS HCPhys)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync AssertReturn(!(GCPhys & PAGE_OFFSET_MASK), VERR_INTERNAL_ERROR_3);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync AssertReturn(!(HCPhys & PAGE_OFFSET_MASK), VERR_INTERNAL_ERROR_3);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /** @todo: what do we do on failure? */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pGVM->rawpci.s.pfnContigMemInfo(&pGVM->rawpci.s, HCPhys, GCPhys, PAGE_SIZE, PCIRAW_MEMINFO_MAP);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Indicates that the specified guest page doesn't exists but doesn't have host
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * page mapping we trust PCI pass-through with.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * This is only used when setting up the mappings, i.e. between
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * GPciRawR0GuestPageBeginAssignments and GPciRawR0GuestPageEndAssignments.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @returns VBox status code.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pGVM The ring-0 VM structure.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param GCPhys The address of the guest page (page aligned).
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param HCPhys The address of the host page (page aligned).
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsyncVMMR0_INT_DECL(int) GPciRawR0GuestPageUnassign(PGVM pGVM, RTGCPHYS GCPhys)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync AssertReturn(!(GCPhys & PAGE_OFFSET_MASK), VERR_INTERNAL_ERROR_3);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /** @todo: what do we do on failure? */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pGVM->rawpci.s.pfnContigMemInfo(&pGVM->rawpci.s, 0, GCPhys, PAGE_SIZE, PCIRAW_MEMINFO_UNMAP);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Tells the global PCI pass-through manager that we have completed setting up
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * the guest page to host page mappings for the specfied VM.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * This complements GPciRawR0GuestPageBeginAssignments and will be called even
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * if some page assignment failed.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @returns VBox status code.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pGVM The ring-0 VM structure.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsyncVMMR0_INT_DECL(int) GPciRawR0GuestPageEndAssignments(PGVM pGVM)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Tells the global PCI pass-through manager that a guest page mapping has
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * changed after the initial setup.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @returns VBox status code.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pGVM The ring-0 VM structure.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param GCPhys The address of the guest page (page aligned).
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param HCPhys The new host page address or NIL_RTHCPHYS if
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * now unassigned.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsyncVMMR0_INT_DECL(int) GPciRawR0GuestPageUpdate(PGVM pGVM, RTGCPHYS GCPhys, RTHCPHYS HCPhys)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync AssertReturn(!(GCPhys & PAGE_OFFSET_MASK), VERR_INTERNAL_ERROR_4);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync AssertReturn(!(HCPhys & PAGE_OFFSET_MASK) || HCPhys == NIL_RTHCPHYS, VERR_INTERNAL_ERROR_4);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#endif /* VBOX_WITH_PCI_PASSTHROUGH */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Sets up the IOMMU when raw PCI device is enabled.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @note This is a hack that will probably be remodelled and refined later!
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @returns VBox status code.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pVM Pointer to the VM.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * The Simplistic Approach - Enumerate all the pages and call tell the
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * IOMMU about each of them.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync for (PPGMRAMRANGE pRam = pVM->pgm.s.pRamRangesXR0; RT_SUCCESS(rc) && pRam; pRam = pRam->pNextR0)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync while (cLeft-- > 0)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* Only expose pages that are 100% safe for now. */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync && PGM_PAGE_GET_STATE(pPage) == PGM_PAGE_STATE_ALLOCATED
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync rc = GPciRawR0GuestPageAssign(pGVM, GCPhys, PGM_PAGE_GET_HCPHYS(pPage));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * #PF Handler for nested paging.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @returns VBox status code (appropriate for trap handling and GC return).
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pVM Pointer to the VM.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pVCpu Pointer to the VMCPU.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param enmShwPagingMode Paging mode for the nested page tables.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param uErr The trap error code.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pRegFrame Trap register frame.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param GCPhysFault The fault address.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsyncVMMR0DECL(int) PGMR0Trap0eHandlerNestedPaging(PVM pVM, PVMCPU pVCpu, PGMMODE enmShwPagingMode, RTGCUINT uErr,
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync LogFlow(("PGMTrap0eHandler: uErr=%RGx GCPhysFault=%RGp eip=%RGv\n", uErr, GCPhysFault, (RTGCPTR)pRegFrame->rip));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = NULL; } );
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* AMD uses the host's paging mode; Intel has a single mode (EPT). */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync AssertMsg( enmShwPagingMode == PGMMODE_32_BIT || enmShwPagingMode == PGMMODE_PAE || enmShwPagingMode == PGMMODE_PAE_NX
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync || enmShwPagingMode == PGMMODE_AMD64 || enmShwPagingMode == PGMMODE_AMD64_NX || enmShwPagingMode == PGMMODE_EPT,
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* Reserved shouldn't end up here. */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Error code stats.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eUSNotPresentWrite);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eUSNotPresentRead);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eUSWrite);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eUSReserved);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eUSNXE);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eUSRead);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync { /* Supervisor */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eSVNotPresentWrite);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eSVNotPresentRead);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eSVWrite);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eSNXE);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eSVReserved);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Call the worker.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Note! We pretend the guest is in protected mode without paging, so we
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * can use existing code to build the nested page tables.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync bool fLockTaken = false;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync rc = PGM_BTH_NAME_32BIT_PROT(Trap0eHandler)(pVCpu, uErr, pRegFrame, GCPhysFault, &fLockTaken);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync rc = PGM_BTH_NAME_PAE_PROT(Trap0eHandler)(pVCpu, uErr, pRegFrame, GCPhysFault, &fLockTaken);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync rc = PGM_BTH_NAME_AMD64_PROT(Trap0eHandler)(pVCpu, uErr, pRegFrame, GCPhysFault, &fLockTaken);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync rc = PGM_BTH_NAME_EPT_PROT(Trap0eHandler)(pVCpu, uErr, pRegFrame, GCPhysFault, &fLockTaken);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* Note: hack alert for difficult to reproduce problem. */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync else if ( rc == VERR_PAGE_NOT_PRESENT /* SMP only ; disassembly might fail. */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync || rc == VERR_PAGE_TABLE_NOT_PRESENT /* seen with UNI & SMP */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync || rc == VERR_PAGE_DIRECTORY_PTR_NOT_PRESENT /* seen with SMP */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync || rc == VERR_PAGE_MAP_LEVEL4_NOT_PRESENT) /* precaution */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync 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));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* Some kind of inconsistency in the SMP case; it's safe to just execute the instruction again; not sure about
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync single VCPU VMs though. */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync STAM_STATS({ if (!pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution))
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eTime2Misc; });
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync STAM_PROFILE_STOP_EX(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0e, pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution), a);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * #PF Handler for deliberate nested paging misconfiguration (/reserved bit)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * employed for MMIO pages.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @returns VBox status code (appropriate for trap handling and GC return).
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pVM Pointer to the VM.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pVCpu Pointer to the VMCPU.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param enmShwPagingMode Paging mode for the nested page tables.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pRegFrame Trap register frame.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param GCPhysFault The fault address.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param uErr The error code, UINT32_MAX if not available
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsyncVMMR0DECL(VBOXSTRICTRC) PGMR0Trap0eHandlerNPMisconfig(PVM pVM, PVMCPU pVCpu, PGMMODE enmShwPagingMode,
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, uint32_t uErr)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync STAM_PROFILE_START(&pVCpu->CTX_SUFF(pStats)->StatR0NpMiscfg, a);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Try lookup the all access physical handler for the address.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync PPGMPHYSHANDLER pHandler = pgmHandlerPhysicalLookup(pVM, GCPhysFault);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if (RT_LIKELY(pHandler && pHandler->enmType != PGMPHYSHANDLERTYPE_PHYSICAL_WRITE))
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * If the handle has aliases page or pages that have been temporarily
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * disabled, we'll have to take a detour to make sure we resync them
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * to avoid lots of unnecessary exits.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync && ( (pPage = pgmPhysGetPage(pVM, GCPhysFault)) == NULL
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync || PGM_PAGE_GET_HNDL_PHYS_STATE(pPage) == PGM_PAGE_HNDL_PHYS_STATE_DISABLED)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Log(("PGMR0Trap0eHandlerNPMisconfig: Resyncing aliases / tmp-off page at %RGp (uErr=%#x) %R[pgmpage]\n", GCPhysFault, uErr, pPage));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatR0NpMiscfgSyncPage);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync rc = pgmShwSyncNestedPageLocked(pVCpu, GCPhysFault, 1 /*cPages*/, enmShwPagingMode);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync CTX_MID(PFNPGM,PHYSHANDLER) pfnHandler = pHandler->CTX_SUFF(pfnHandler);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Log6(("PGMR0Trap0eHandlerNPMisconfig: calling %p(,%#x,,%RGp,%p)\n", pfnHandler, uErr, GCPhysFault, pvUser));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync rc = pfnHandler(pVM, uErr == UINT32_MAX ? RTGCPTR_MAX : uErr, pRegFrame, GCPhysFault, GCPhysFault, pvUser);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pHandler = pgmHandlerPhysicalLookup(pVM, GCPhysFault);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Log(("PGMR0Trap0eHandlerNPMisconfig: %RGp (uErr=%#x) -> R3\n", GCPhysFault, uErr));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Must be out of sync, so do a SyncPage and restart the instruction.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * ASSUMES that ALL handlers are page aligned and covers whole pages
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * (assumption asserted in PGMHandlerPhysicalRegisterEx).
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Log(("PGMR0Trap0eHandlerNPMisconfig: Out of sync page at %RGp (uErr=%#x)\n", GCPhysFault, uErr));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatR0NpMiscfgSyncPage);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync rc = pgmShwSyncNestedPageLocked(pVCpu, GCPhysFault, 1 /*cPages*/, enmShwPagingMode);