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