PGMAllBth.h revision dc280865bd72003e72d83a80fa88275dbb27585f
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * VBox - Page Manager, Shadow+Guest Paging Template - All context code.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @remarks The nested page tables on AMD makes use of PGM_SHW_TYPE in
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * {PGM_TYPE_AMD64, PGM_TYPE_PAE and PGM_TYPE_32BIT} and PGM_GST_TYPE
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * set to PGM_TYPE_PROT. Half of the code in this file is not
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * exercised with PGM_SHW_TYPE set to PGM_TYPE_NESTED.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @remarks Extended page tables (intel) are built with PGM_GST_TYPE set to
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * PGM_TYPE_PROT (and PGM_SHW_TYPE set to PGM_TYPE_EPT).
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @remarks This file is one big \#ifdef-orgy!
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Copyright (C) 2006-2010 Oracle Corporation
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * available from http://www.virtualbox.org. This file is free software;
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * you can redistribute it and/or modify it under the terms of the GNU
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * General Public License (GPL) as published by the Free Software
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync/*******************************************************************************
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync* Internal Functions *
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync*******************************************************************************/
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsyncPGM_BTH_DECL(int, Trap0eHandler)(PVMCPU pVCpu, RTGCUINT uErr, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, bool *pfLockTaken);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsyncPGM_BTH_DECL(int, InvalidatePage)(PVMCPU pVCpu, RTGCPTR GCPtrPage);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsyncstatic int PGM_BTH_NAME(SyncPage)(PVMCPU pVCpu, GSTPDE PdeSrc, RTGCPTR GCPtrPage, unsigned cPages, unsigned uErr);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsyncstatic int PGM_BTH_NAME(CheckDirtyPageFault)(PVMCPU pVCpu, uint32_t uErr, PSHWPDE pPdeDst, GSTPDE const *pPdeSrc, RTGCPTR GCPtrPage);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsyncstatic int PGM_BTH_NAME(SyncPT)(PVMCPU pVCpu, unsigned iPD, PGSTPD pPDSrc, RTGCPTR GCPtrPage);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsyncstatic void PGM_BTH_NAME(SyncPageWorker)(PVMCPU pVCpu, PSHWPTE pPteDst, GSTPDE PdeSrc, GSTPTE PteSrc, PPGMPOOLPAGE pShwPage, unsigned iPTDst);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsyncPGM_BTH_DECL(int, VerifyAccessSyncPage)(PVMCPU pVCpu, RTGCPTR Addr, unsigned fPage, unsigned uErr);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsyncPGM_BTH_DECL(int, PrefetchPage)(PVMCPU pVCpu, RTGCPTR GCPtrPage);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsyncPGM_BTH_DECL(int, SyncCR3)(PVMCPU pVCpu, uint64_t cr0, uint64_t cr3, uint64_t cr4, bool fGlobal);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsyncPGM_BTH_DECL(unsigned, AssertCR3)(PVMCPU pVCpu, uint64_t cr3, uint64_t cr4, RTGCPTR GCPtr = 0, RTGCPTR cb = ~(RTGCPTR)0);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsyncPGM_BTH_DECL(int, MapCR3)(PVMCPU pVCpu, RTGCPHYS GCPhysCR3);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Filter out some illegal combinations of guest and shadow paging, so we can
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * remove redundant checks inside functions.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync#if PGM_GST_TYPE == PGM_TYPE_PAE && PGM_SHW_TYPE != PGM_TYPE_PAE && PGM_SHW_TYPE != PGM_TYPE_NESTED && PGM_SHW_TYPE != PGM_TYPE_EPT
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# error "Invalid combination; PAE guest implies PAE shadow"
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync#if (PGM_GST_TYPE == PGM_TYPE_REAL || PGM_GST_TYPE == PGM_TYPE_PROT) \
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync && !(PGM_SHW_TYPE == PGM_TYPE_32BIT || PGM_SHW_TYPE == PGM_TYPE_PAE || PGM_SHW_TYPE == PGM_TYPE_AMD64 || PGM_SHW_TYPE == PGM_TYPE_NESTED || PGM_SHW_TYPE == PGM_TYPE_EPT)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# error "Invalid combination; real or protected mode without paging implies 32 bits or PAE shadow paging."
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync#if (PGM_GST_TYPE == PGM_TYPE_32BIT || PGM_GST_TYPE == PGM_TYPE_PAE) \
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync && !(PGM_SHW_TYPE == PGM_TYPE_32BIT || PGM_SHW_TYPE == PGM_TYPE_PAE || PGM_SHW_TYPE == PGM_TYPE_NESTED || PGM_SHW_TYPE == PGM_TYPE_EPT)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# error "Invalid combination; 32 bits guest paging or PAE implies 32 bits or PAE shadow paging."
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync#if (PGM_GST_TYPE == PGM_TYPE_AMD64 && PGM_SHW_TYPE != PGM_TYPE_AMD64 && PGM_SHW_TYPE != PGM_TYPE_NESTED && PGM_SHW_TYPE != PGM_TYPE_EPT) \
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync || (PGM_SHW_TYPE == PGM_TYPE_AMD64 && PGM_GST_TYPE != PGM_TYPE_AMD64 && PGM_GST_TYPE != PGM_TYPE_PROT)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# error "Invalid combination; AMD64 guest implies AMD64 shadow and vice versa"
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Deal with a guest page fault.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @returns Strict VBox status code.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @retval VINF_EM_RAW_GUEST_TRAP
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @retval VINF_EM_RAW_EMULATE_INSTR
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param pVCpu The current CPU.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param pGstWalk The guest page table walk result.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param uErr The error code.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsyncPGM_BTH_DECL(VBOXSTRICTRC, Trap0eHandlerGuestFault)(PVMCPU pVCpu, PGSTPTWALK pGstWalk, RTGCUINT uErr)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# if !defined(PGM_WITHOUT_MAPPINGS) && (PGM_GST_TYPE == PGM_TYPE_32BIT || PGM_GST_TYPE == PGM_TYPE_PAE)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Check for write conflicts with our hypervisor mapping.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * If the guest happens to access a non-present page, where our hypervisor
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * is currently mapped, then we'll create a #PF storm in the guest.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync if ( (uErr & (X86_TRAP_PF_P | X86_TRAP_PF_RW)) == (X86_TRAP_PF_P | X86_TRAP_PF_RW)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync && MMHyperIsInsideArea(pVCpu->CTX_SUFF(pVM), pGstWalk->Core.GCPtr))
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* Force a CR3 sync to check for conflicts and emulate the instruction. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eTime2GuestTrap; });
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Calc the error code for the guest trap.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync ? uErr & (X86_TRAP_PF_RW | X86_TRAP_PF_US | X86_TRAP_PF_ID)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync LogFlow(("Guest trap; cr2=%RGv uErr=%RGv lvl=%d\n", pGstWalk->Core.GCPtr, uErr, pGstWalk->Core.uLevel));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eTime2GuestTrap; });
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# endif /* PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE) */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Deal with a guest page fault.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * The caller has taken the PGM lock.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @returns Strict VBox status code.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param pVCpu The current CPU.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param uErr The error code.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param pRegFrame The register frame.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param pvFault The fault address.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param pPage The guest page at @a pvFault.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param pGstWalk The guest page table walk result.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param pfLockTaken PGM lock taken here or not (out). This is true
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * when we're called.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsyncstatic VBOXSTRICTRC PGM_BTH_NAME(Trap0eHandlerDoAccessHandlers)(PVMCPU pVCpu, RTGCUINT uErr, PCPUMCTXCORE pRegFrame,
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync GSTPDE const PdeSrcDummy = { X86_PDE_P | X86_PDE_US | X86_PDE_RW | X86_PDE_A };
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Physical page access handler.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync const RTGCPHYS GCPhysFault = pGstWalk->Core.GCPhys;
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PPGMPHYSHANDLER pCur = pgmHandlerPhysicalLookup(pVM, GCPhysFault);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * If the region is write protected and we got a page not present fault, then sync
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * the pages. If the fault was caused by a read, then restart the instruction.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * In case of write access continue to the GC write handler.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * ASSUMES that there is only one handler per page or that they have similar write properties.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync && pCur->enmType == PGMPHYSHANDLERTYPE_PHYSICAL_WRITE)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = PGM_BTH_NAME(SyncPage)(pVCpu, pGstWalk->Pde, pvFault, PGM_SYNC_NR_PAGES, uErr);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = PGM_BTH_NAME(SyncPage)(pVCpu, PdeSrcDummy, pvFault, PGM_SYNC_NR_PAGES, uErr);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eHandlersOutOfSync);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eTime2OutOfSyncHndPhys; });
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * If the access was not thru a #PF(RSVD|...) resync the page.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync && pCur->enmType != PGMPHYSHANDLERTYPE_PHYSICAL_WRITE
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync && !pGstWalk->Core.fEffectiveUS /** @todo Remove pGstWalk->Core.fEffectiveUS and X86_PTE_US further down in the sync code. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = PGM_BTH_NAME(SyncPage)(pVCpu, pGstWalk->Pde, pvFault, PGM_SYNC_NR_PAGES, uErr);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = PGM_BTH_NAME(SyncPage)(pVCpu, PdeSrcDummy, pvFault, PGM_SYNC_NR_PAGES, uErr);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eHandlersOutOfSync);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eTime2OutOfSyncHndPhys; });
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync AssertMsg( pCur->enmType != PGMPHYSHANDLERTYPE_PHYSICAL_WRITE
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync || (pCur->enmType == PGMPHYSHANDLERTYPE_PHYSICAL_WRITE && (uErr & X86_TRAP_PF_RW)),
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync ("Unexpected trap for physical handler: %08X (phys=%08x) pPage=%R[pgmpage] uErr=%X, enum=%d\n",
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync pvFault, GCPhysFault, pPage, uErr, pCur->enmType));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync if (pCur->enmType == PGMPHYSHANDLERTYPE_PHYSICAL_WRITE)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eHandlersPhysWrite);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eHandlersPhysAll);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync if (uErr & X86_TRAP_PF_RSVD) STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eHandlersPhysAllOpt);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PFNPGMR0PHYSHANDLER pfnHandler = pCur->CTX_SUFF(pfnHandler);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PFNPGMRCPHYSHANDLER pfnHandler = pCur->CTX_SUFF(pfnHandler);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync if (pfnHandler != pPool->CTX_SUFF(pfnAccessHandler))
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = pfnHandler(pVM, uErr, pRegFrame, pvFault, GCPhysFault, pvUser);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eTime2HndPhys; });
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# if PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE) && !defined(IN_RING0)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * If the region is write protected and we got a page not present fault, then sync
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * the pages. If the fault was caused by a read, then restart the instruction.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * In case of write access continue to the GC write handler.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync if ( PGM_PAGE_GET_HNDL_VIRT_STATE(pPage) < PGM_PAGE_HNDL_PHYS_STATE_ALL
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = PGM_BTH_NAME(SyncPage)(pVCpu, pGstWalk->Pde, pvFault, PGM_SYNC_NR_PAGES, uErr);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eHandlersOutOfSync);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eTime2OutOfSyncHndVirt; });
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Ok, it's an virtual page access handler.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Since it's faster to search by address, we'll do that first
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * and then retry by GCPhys if that fails.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /** @todo r=bird: perhaps we should consider looking up by physical address directly now?
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * r=svl: true, but lookup on virtual address should remain as a fallback as phys & virt trees might be
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * out of sync, because the page was changed without us noticing it (not-present -> present
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * without invlpg or mov cr3, xxx).
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PPGMVIRTHANDLER pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrRangeGet(&pVM->pgm.s.CTX_SUFF(pTrees)->VirtHandlers, pvFault);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync || (pCur->enmType == PGMVIRTHANDLERTYPE_WRITE && (uErr & X86_TRAP_PF_RW))),
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync ("Unexpected trap for virtual handler: %RGv (phys=%RGp) pPage=%R[pgmpage] uErr=%X, enum=%d\n",
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync pvFault, pGstWalk->Core.GCPhys, pPage, uErr, pCur->enmType));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync CTX_MID(PFNPGM,VIRTHANDLER) pfnHandler = pCur->CTX_SUFF(pfnHandler);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = pfnHandler(pVM, uErr, pRegFrame, pvFault, GCPtrStart, pvFault - GCPtrStart);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrRangeGet(&pVM->pgm.s.CTX_SUFF(pTrees)->VirtHandlers, pvFault);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = VINF_EM_RAW_EMULATE_INSTR; /** @todo for VMX */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eHandlersVirtual);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eTime2HndVirt; });
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* Unhandled part of a monitored page */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* Check by physical address. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = pgmHandlerVirtualFindByPhysAddr(pVM, pGstWalk->Core.GCPhys, &pCur, &iPage);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync Assert((pCur->aPhysToVirt[iPage].Core.Key & X86_PTE_PAE_PG_MASK) == (pGstWalk->Core.GCPhys & X86_PTE_PAE_PG_MASK));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync CTX_MID(PFNPGM,VIRTHANDLER) pfnHandler = pCur->CTX_SUFF(pfnHandler);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = pfnHandler(pVM, uErr, pRegFrame, pvFault, GCPtrStart, off);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrRangeGet(&pVM->pgm.s.CTX_SUFF(pTrees)->VirtHandlers, GCPtrStart);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = VINF_EM_RAW_EMULATE_INSTR; /** @todo for VMX */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eHandlersVirtualByPhys);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eTime2HndVirt; });
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# endif /* PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE) */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * There is a handled area of the page, but this fault doesn't belong to it.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * We must emulate the instruction.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * To avoid crashing (non-fatal) in the interpreter and go back to the recompiler
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * we first check if this was a page-not-present fault for a page with only
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * write access handlers. Restart the instruction if it wasn't a write access.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eHandlersUnhandled);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = PGM_BTH_NAME(SyncPage)(pVCpu, pGstWalk->Pde, pvFault, PGM_SYNC_NR_PAGES, uErr);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = PGM_BTH_NAME(SyncPage)(pVCpu, PdeSrcDummy, pvFault, PGM_SYNC_NR_PAGES, uErr);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eHandlersOutOfSync);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eTime2OutOfSyncHndPhys; });
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /** @todo This particular case can cause quite a lot of overhead. E.g. early stage of kernel booting in Ubuntu 6.06
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * It's writing to an unhandled part of the LDT page several million times.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = VBOXSTRICTRC_TODO(PGMInterpretInstruction(pVM, pVCpu, pRegFrame, pvFault));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync LogFlow(("PGM: PGMInterpretInstruction -> rc=%d pPage=%R[pgmpage]\n", rc, pPage));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eTime2HndUnhandled; });
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync} /* if any kind of handler */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * #PF Handler for raw-mode guest execution.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @returns VBox status code (appropriate for trap handling and GC return).
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param pVCpu VMCPU Handle.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param uErr The trap error code.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param pRegFrame Trap register frame.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param pvFault The fault address.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param pfLockTaken PGM lock taken here or not (out)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsyncPGM_BTH_DECL(int, Trap0eHandler)(PVMCPU pVCpu, RTGCUINT uErr, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, bool *pfLockTaken)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# if ( PGM_GST_TYPE == PGM_TYPE_32BIT || PGM_GST_TYPE == PGM_TYPE_REAL || PGM_GST_TYPE == PGM_TYPE_PROT \
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync || PGM_GST_TYPE == PGM_TYPE_PAE || PGM_GST_TYPE == PGM_TYPE_AMD64) \
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync && (PGM_SHW_TYPE != PGM_TYPE_EPT || PGM_GST_TYPE == PGM_TYPE_PROT)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Walk the guest page translation tables and check if it's a guest fault.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync return VBOXSTRICTRC_TODO(PGM_BTH_NAME(Trap0eHandlerGuestFault)(pVCpu, &GstWalk, uErr));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* assert some GstWalk sanity. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync AssertMsg(GstWalk.Pml4e.u == GstWalk.pPml4e->u, ("%RX64 %RX64\n", (uint64_t)GstWalk.Pml4e.u, (uint64_t)GstWalk.pPml4e->u));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# if PGM_GST_TYPE == PGM_TYPE_AMD64 || PGM_GST_TYPE == PGM_TYPE_PAE
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync AssertMsg(GstWalk.Pdpe.u == GstWalk.pPdpe->u, ("%RX64 %RX64\n", (uint64_t)GstWalk.Pdpe.u, (uint64_t)GstWalk.pPdpe->u));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync AssertMsg(GstWalk.Pde.u == GstWalk.pPde->u, ("%RX64 %RX64\n", (uint64_t)GstWalk.Pde.u, (uint64_t)GstWalk.pPde->u));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync AssertMsg(GstWalk.Core.fBigPage || GstWalk.Pte.u == GstWalk.pPte->u, ("%RX64 %RX64\n", (uint64_t)GstWalk.Pte.u, (uint64_t)GstWalk.pPte->u));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync if (uErr & (X86_TRAP_PF_RW | X86_TRAP_PF_US | X86_TRAP_PF_ID))
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync || ((uErr & X86_TRAP_PF_US) && !GstWalk.Core.fEffectiveUS)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync || ((uErr & X86_TRAP_PF_ID) && GstWalk.Core.fEffectiveNX)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync return VBOXSTRICTRC_TODO(PGM_BTH_NAME(Trap0eHandlerGuestFault)(pVCpu, &GstWalk, uErr));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Set the accessed and dirty flags.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,DirtiedPage));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,PageAlreadyDirty));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync AssertMsg(GstWalk.Pde.u == GstWalk.pPde->u || GstWalk.pPte->u == GstWalk.pPde->u,
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync ("%RX64 %RX64 pPte=%p pPde=%p Pte=%RX64\n", (uint64_t)GstWalk.Pde.u, (uint64_t)GstWalk.pPde->u, GstWalk.pPte, GstWalk.pPde, (uint64_t)GstWalk.pPte->u));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# else /* !PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE) */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync GSTPDE const PdeSrcDummy = { X86_PDE_P | X86_PDE_US | X86_PDE_RW | X86_PDE_A}; /** @todo eliminate this */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# endif /* !PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE) */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* Take the big lock now. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * If it is a reserved bit fault we know that it is an MMIO (access
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * handler) related fault and can skip some 200 lines of code.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = pgmPhysGetPageEx(&pVM->pgm.s, GstWalk.Core.GCPhys, &pPage);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync if (RT_SUCCESS(rc) && PGM_PAGE_HAS_ACTIVE_ALL_HANDLERS(pPage))
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync return VBOXSTRICTRC_TODO(PGM_BTH_NAME(Trap0eHandlerDoAccessHandlers)(pVCpu, uErr, pRegFrame, pvFault, pPage,
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = PGM_BTH_NAME(SyncPage)(pVCpu, GstWalk.Pde, pvFault, 1, uErr);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = pgmPhysGetPageEx(&pVM->pgm.s, (RTGCPHYS)pvFault, &pPage);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync if (RT_SUCCESS(rc) && PGM_PAGE_HAS_ACTIVE_ALL_HANDLERS(pPage))
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync return VBOXSTRICTRC_TODO(PGM_BTH_NAME(Trap0eHandlerDoAccessHandlers)(pVCpu, uErr, pRegFrame, pvFault, pPage,
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = PGM_BTH_NAME(SyncPage)(pVCpu, PdeSrcDummy, pvFault, 1, uErr);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# endif /* PGM_WITH_MMIO_OPTIMIZATIONS */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Fetch the guest PDE, PDPE and PML4E.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync const unsigned iPDDst = (pvFault >> SHW_PD_SHIFT) & SHW_PD_MASK; /* pPDDst index, not used with the pool. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = pgmShwSyncPaePDPtr(pVCpu, pvFault, GstWalk.Pdpe.u, &pPDDst);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = pgmShwSyncPaePDPtr(pVCpu, pvFault, X86_PDPE_P, &pPDDst); /* RW, US and A are reserved in PAE mode. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync AssertMsgReturn(rc == VINF_SUCCESS, ("rc=%Rrc\n", rc), RT_FAILURE_NP(rc) ? rc : VERR_INTERNAL_ERROR_4);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync const unsigned iPDDst = ((pvFault >> SHW_PD_SHIFT) & SHW_PD_MASK);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# if PGM_GST_TYPE == PGM_TYPE_PROT /* (AMD-V nested paging) */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = pgmShwSyncLongModePDPtr(pVCpu, pvFault, X86_PML4E_P | X86_PML4E_RW | X86_PML4E_US | X86_PML4E_A,
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync X86_PDPE_P | X86_PDPE_RW | X86_PDPE_US | X86_PDPE_A, &pPDDst);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = pgmShwSyncLongModePDPtr(pVCpu, pvFault, GstWalk.Pml4e.u, GstWalk.Pdpe.u, &pPDDst);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync AssertMsgReturn(rc == VINF_SUCCESS, ("rc=%Rrc\n", rc), RT_FAILURE_NP(rc) ? rc : VERR_INTERNAL_ERROR_4);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync const unsigned iPDDst = ((pvFault >> SHW_PD_SHIFT) & SHW_PD_MASK);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = pgmShwGetEPTPDPtr(pVCpu, pvFault, NULL, &pPDDst);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync AssertMsgReturn(rc == VINF_SUCCESS, ("rc=%Rrc\n", rc), RT_FAILURE_NP(rc) ? rc : VERR_INTERNAL_ERROR_4);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Dirty page handling.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * If we successfully correct the write protection fault due to dirty bit
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * tracking, then return immediately.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_PROFILE_START(&pVCpu->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,DirtyBitTracking), a);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = PGM_BTH_NAME(CheckDirtyPageFault)(pVCpu, uErr, &pPDDst->a[iPDDst], GstWalk.pPde, pvFault);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_PROFILE_STOP(&pVCpu->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,DirtyBitTracking), a);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync ? &pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eTime2DirtyAndAccessed
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync : &pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eTime2GuestTrap; });
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync LogBird(("Trap0eHandler: returns VINF_SUCCESS\n"));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync AssertMsg(GstWalk.Pde.u == GstWalk.pPde->u || GstWalk.pPte->u == GstWalk.pPde->u, ("%RX64 %RX64\n", (uint64_t)GstWalk.Pde.u, (uint64_t)GstWalk.pPde->u));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync AssertMsg(GstWalk.Core.fBigPage || GstWalk.Pte.u == GstWalk.pPte->u, ("%RX64 %RX64\n", (uint64_t)GstWalk.Pte.u, (uint64_t)GstWalk.pPte->u));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# if 0 /* rarely useful; leave for debugging. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZTrap0ePD[iPDSrc]);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# endif /* PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE) */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * A common case is the not-present error caused by lazy page table syncing.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * It is IMPORTANT that we weed out any access to non-present shadow PDEs
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * here so we can safely assume that the shadow PT is present when calling
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * SyncPage later.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * On failure, we ASSUME that SyncPT is out of memory or detected some kind
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * of mapping conflict and defer to SyncCR3 in R3.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * (Again, we do NOT support access handlers for non-present guest pages.)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync if ( !(uErr & X86_TRAP_PF_P) /* not set means page not present instead of page protection violation */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eTime2SyncPT; });
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync LogFlow(("=>SyncPT %04x = %08RX64\n", (pvFault >> GST_PD_SHIFT) & GST_PD_MASK, (uint64_t)GstWalk.Pde.u));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = PGM_BTH_NAME(SyncPT)(pVCpu, (pvFault >> GST_PD_SHIFT) & GST_PD_MASK, GstWalk.pPd, pvFault);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = PGM_BTH_NAME(SyncPT)(pVCpu, 0, NULL, pvFault);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync Log(("SyncPT: %RGv failed!! rc=%Rrc\n", pvFault, rc));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3); /** @todo no need to do global sync, right? */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# if PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE) && !defined(PGM_WITHOUT_MAPPINGS)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Check if this address is within any of our mappings.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * This is *very* fast and it's gonna save us a bit of effort below and prevent
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * us from screwing ourself with MMIO2 pages which have a GC Mapping (VRam).
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * (BTW, it's impossible to have physical access handlers in a mapping.)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PPGMMAPPING pMapping = pVM->pgm.s.CTX_SUFF(pMappings);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync for ( ; pMapping; pMapping = pMapping->CTX_SUFF(pNext))
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * The first thing we check is if we've got an undetected conflict.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync while (iPT-- > 0)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eConflicts);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync Log(("Trap0e: Detected Conflict %RGv-%RGv\n", pMapping->GCPtr, pMapping->GCPtrLast));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3); /** @todo no need to do global sync,right? */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eTime2Mapping; });
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Check if the fault address is in a virtual page access handler range.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PPGMVIRTHANDLER pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrRangeGet(&pVM->pgm.s.CTX_SUFF(pTrees)->HyperVirtHandlers, pvFault);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = pCur->CTX_SUFF(pfnHandler)(pVM, uErr, pRegFrame, pvFault, pCur->Core.Key, pvFault - pCur->Core.Key);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = VINF_EM_RAW_EMULATE_INSTR; /* can't happen with VMX */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eHandlersMapping);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eTime2Mapping; });
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Pretend we're not here and let the guest handle the trap.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eGuestPFMapping);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync LogFlow(("PGM: Mapping access -> route trap to recompiler!\n"));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eTime2Mapping; });
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync } /* pgmAreMappingsEnabled(&pVM->pgm.s) */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# endif /* PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE) */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Check if this fault address is flagged for special treatment,
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * which means we'll have to figure out the physical address and
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * check flags associated with it.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * ASSUME that we can limit any special access handling to pages
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * in page tables which the guest believes to be present.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync RTGCPHYS GCPhys = GstWalk.Core.GCPhys & ~(RTGCPHYS)PAGE_OFFSET_MASK;
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync RTGCPHYS GCPhys = (RTGCPHYS)pvFault & ~(RTGCPHYS)PAGE_OFFSET_MASK;
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# endif /* PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE) */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = pgmPhysGetPageEx(&pVM->pgm.s, GCPhys, &pPage);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * When the guest accesses invalid physical memory (e.g. probing
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * of RAM or accessing a remapped MMIO range), then we'll fall
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * back to the recompiler to emulate the instruction.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync LogFlow(("PGM #PF: pgmPhysGetPageEx(%RGp) failed with %Rrc\n", GCPhys, rc));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eHandlersInvalid);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eTime2InvalidPhys; });
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Any handlers for this page?
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync return VBOXSTRICTRC_TODO(PGM_BTH_NAME(Trap0eHandlerDoAccessHandlers)(pVCpu, uErr, pRegFrame, pvFault, pPage, pfLockTaken,
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync return VBOXSTRICTRC_TODO(PGM_BTH_NAME(Trap0eHandlerDoAccessHandlers)(pVCpu, uErr, pRegFrame, pvFault, pPage, pfLockTaken));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_PROFILE_START(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eTimeOutOfSync, c);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# if PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE) && !defined(IN_RING0)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * The page isn't marked, but it might still be monitored by a virtual page access handler.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * (ASSUMES no temporary disabling of virtual handlers.)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /** @todo r=bird: Since the purpose is to catch out of sync pages with virtual handler(s) here,
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * we should correct both the shadow page table and physical memory flags, and not only check for
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * accesses within the handler region but for access to pages with virtual handlers. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PPGMVIRTHANDLER pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrRangeGet(&pVM->pgm.s.CTX_SUFF(pTrees)->VirtHandlers, pvFault);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync || (pCur->enmType == PGMVIRTHANDLERTYPE_WRITE && (uErr & X86_TRAP_PF_RW))),
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync ("Unexpected trap for virtual handler: %08X (phys=%08x) %R[pgmpage] uErr=%X, enum=%d\n", pvFault, GCPhys, pPage, uErr, pCur->enmType));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = pCur->CTX_SUFF(pfnHandler)(pVM, uErr, pRegFrame, pvFault, pCur->Core.Key, pvFault - pCur->Core.Key);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = VINF_EM_RAW_EMULATE_INSTR; /** @todo for VMX */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eTime2HndVirt; });
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# endif /* PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE) */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * We are here only if page is present in Guest page tables and
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * trap is not handled by our handlers.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Check it for page out-of-sync situation.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Page is not present in our page tables. Try to sync it!
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,PageOutOfSyncUser));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync else /* supervisor */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,PageOutOfSyncSupervisor));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* Emulate reads from ballooned pages as they are not present in
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync our shadow page tables. (Required for e.g. Solaris guests; soft
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync ecc, random nr generator.) */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = VBOXSTRICTRC_TODO(PGMInterpretInstruction(pVM, pVCpu, pRegFrame, pvFault));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync LogFlow(("PGM: PGMInterpretInstruction balloon -> rc=%d pPage=%R[pgmpage]\n", rc, pPage));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,PageOutOfSyncBallloon));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eTime2Ballooned; });
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PGMGstGetPage(pVCpu, pvFault, &fPageGst2, &GCPhys2);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync Log(("Page out of sync: %RGv eip=%08x PdeSrc.US=%d fPageGst2=%08llx GCPhys2=%RGp scan=%d\n",
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync pvFault, pRegFrame->eip, GstWalk.Pde.n.u1User, fPageGst2, GCPhys2, CSAMDoesPageNeedScanning(pVM, pRegFrame->eip)));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync Log(("Page out of sync: %RGv eip=%08x fPageGst2=%08llx GCPhys2=%RGp scan=%d\n",
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync pvFault, pRegFrame->eip, fPageGst2, GCPhys2, CSAMDoesPageNeedScanning(pVM, pRegFrame->eip)));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# endif /* LOG_ENABLED */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# if PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE) && !defined(IN_RING0)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* Note: Can't check for X86_TRAP_ID bit, because that requires execute disable support on the CPU. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync || pvFault - pRegFrame->eip < 8 /* instruction crossing a page boundary */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync && CSAMDoesPageNeedScanning(pVM, pRegFrame->eip)) /* any new code we encounter here */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# endif /* CSAM_DETECT_NEW_CODE_PAGES */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync LogFlow(("CSAMExecFault %RX32\n", pRegFrame->eip));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * CSAM needs to perform a job in ring 3.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Sync the page before going to the host context; otherwise we'll end up in a loop if
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * CSAM fails (e.g. instruction crosses a page boundary and the next page is not present)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync int rc2 = PGM_BTH_NAME(SyncPage)(pVCpu, GstWalk.Pde, pvFault, 1, uErr);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eTime2CSAM; });
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync && pRegFrame->ecx >= 0x100 /* early check for movswd count */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* In case of a write to a non-present supervisor shadow page, we'll take special precautions
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * to detect loading of new code pages.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Decode the instruction.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = SELMValidateAndConvertCSAddr(pVM, pRegFrame->eflags, pRegFrame->ss, pRegFrame->cs,
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = EMInterpretDisasOneEx(pVM, pVCpu, PC, pRegFrame, pDis, &cbOp);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* For now we'll restrict this to rep movsw/d instructions */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# endif /* CSAM_DETECT_NEW_CODE_PAGES */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Mark this page as safe.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /** @todo not correct for pages that contain both code and data!! */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync Log2(("CSAMMarkPage %RGv; scanned=%d\n", pvFault, true));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# endif /* PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE) && !defined(IN_RING0) */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = PGM_BTH_NAME(SyncPage)(pVCpu, GstWalk.Pde, pvFault, PGM_SYNC_NR_PAGES, uErr);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = PGM_BTH_NAME(SyncPage)(pVCpu, PdeSrcDummy, pvFault, PGM_SYNC_NR_PAGES, uErr);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* The page was successfully synced, return to the guest. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eTime2OutOfSync; });
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync else /* uErr & X86_TRAP_PF_P: */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Write protected pages are made writable when the guest makes the
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * first write to it. This happens for pages that are shared, write
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * monitored or not yet allocated.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * We may also end up here when CR0.WP=0 in the guest.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Also, a side effect of not flushing global PDEs are out of sync
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * pages due to physical monitored regions, that are no longer valid.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Assume for now it only applies to the read/write flag.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Check if it is a read-only page.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync if (PGM_PAGE_GET_STATE(pPage) != PGM_PAGE_STATE_ALLOCATED)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync Log(("PGM #PF: Make writable: %RGp %R[pgmpage] pvFault=%RGp uErr=%#x\n", GCPhys, pPage, pvFault, uErr));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync AssertFatalMsg(!PGM_PAGE_IS_BALLOONED(pPage), ("Unexpected ballooned page at %RGp\n", GCPhys));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eTime2MakeWritable; });
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync AssertMsg(rc == VINF_PGM_SYNC_CR3 || RT_FAILURE(rc), ("%Rrc\n", rc));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync if (RT_UNLIKELY(VM_FF_ISPENDING(pVM, VM_FF_PGM_NO_MEMORY)))
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Check to see if we need to emulate the instruction if CR0.WP=0.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync && (CPUMGetGuestCR0(pVCpu) & (X86_CR0_WP | X86_CR0_PG)) == X86_CR0_PG
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync Assert((uErr & (X86_TRAP_PF_RW | X86_TRAP_PF_P)) == (X86_TRAP_PF_RW | X86_TRAP_PF_P));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = VBOXSTRICTRC_TODO(PGMInterpretInstruction(pVM, pVCpu, pRegFrame, pvFault));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eWPEmulInRZ);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eWPEmulToR3);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eTime2WPEmulation; });
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /// @todo count the above case; else
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,PageOutOfSyncUserWrite));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync else /* supervisor */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,PageOutOfSyncSupervisorWrite));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Sync the page.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Note: Do NOT use PGM_SYNC_NR_PAGES here. That only works if the
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * page is not present, which is not true in this case.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = PGM_BTH_NAME(SyncPage)(pVCpu, GstWalk.Pde, pvFault, 1, uErr);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = PGM_BTH_NAME(SyncPage)(pVCpu, PdeSrcDummy, pvFault, 1, uErr);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Page was successfully synced, return to guest but invalidate
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * the TLB first as the page is very likely to be in it.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = PGMGstGetPage(pVCpu, pvFault, &fPageGst, &GCPhys2);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync AssertMsg(RT_SUCCESS(rc) && (fPageGst & X86_PTE_RW), ("rc=%Rrc fPageGst=%RX64\n", rc, fPageGst));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync LogFlow(("Obsolete physical monitor page out of sync %RGv - phys %RGp flags=%08llx\n", pvFault, GCPhys2, (uint64_t)fPageGst));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = PGMShwGetPage(pVCpu, pvFault, &fPageShw, NULL);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync AssertMsg((RT_SUCCESS(rc) && (fPageShw & X86_PTE_RW)) || pVM->cCpus > 1 /* new monitor can be installed/page table flushed between the trap exit and PGMTrap0eHandler */,
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# endif /* VBOX_STRICT */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eTime2OutOfSyncHndObs; });
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /** @todo else: why are we here? */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# if PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE) && defined(VBOX_STRICT)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Check for VMM page flags vs. Guest page flags consistency.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Currently only for debug purposes.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* Get guest page flags. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = PGMGstGetPage(pVCpu, pvFault, &fPageGst, NULL);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = PGMShwGetPage(pVCpu, pvFault, &fPageShw, NULL);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Compare page flags.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Note: we have AVL, A, D bits desynched.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync AssertMsg( (fPageShw & ~(X86_PTE_A | X86_PTE_D | X86_PTE_AVL_MASK))
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync == (fPageGst & ~(X86_PTE_A | X86_PTE_D | X86_PTE_AVL_MASK)),
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync ("Page flags mismatch! pvFault=%RGv uErr=%x GCPhys=%RGp fPageShw=%RX64 fPageGst=%RX64\n",
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync pvFault, (uint32_t)uErr, GCPhys, fPageShw, fPageGst));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# endif /* PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE) && VBOX_STRICT */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * If we get here it is because something failed above, i.e. most like guru
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * meditiation time.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync LogRel(("%s: returns rc=%Rrc pvFault=%RGv uErr=%RX64 cs:rip=%04x:%08RX64\n",
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync __PRETTY_FUNCTION__, rc, pvFault, (uint64_t)uErr, pRegFrame->cs, pRegFrame->rip));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# else /* Nested paging, EPT except PGM_GST_TYPE = PROT */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync AssertReleaseMsgFailed(("Shw=%d Gst=%d is not implemented!\n", PGM_GST_TYPE, PGM_SHW_TYPE));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync#endif /* !IN_RING3 */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Emulation of the invlpg instruction.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @returns VBox status code.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param pVCpu The VMCPU handle.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param GCPtrPage Page to invalidate.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @remark ASSUMES that the guest is updating before invalidating. This order
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * isn't required by the CPU, so this is speculative and could cause
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @remark No TLB shootdown is done on any other VCPU as we assume that
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * invlpg emulation is the *only* reason for calling this function.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * (The guest has to shoot down TLB entries on other CPUs itself)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Currently true, but keep in mind!
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @todo Clean this up! Most of it is (or should be) no longer necessary as we catch all page table accesses.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Should only be required when PGMPOOL_WITH_OPTIMIZED_DIRTY_PT is active (PAE or AMD64 (for now))
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsyncPGM_BTH_DECL(int, InvalidatePage)(PVMCPU pVCpu, RTGCPTR GCPtrPage)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Get the shadow PD entry and skip out if this PD isn't present.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * (Guessing that it is frequent for a shadow PDE to not be present, do this first.)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync const unsigned iPDDst = (GCPtrPage >> SHW_PD_SHIFT) & SHW_PD_MASK;
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PX86PDE pPdeDst = pgmShwGet32BitPDEPtr(pVCpu, GCPtrPage);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* Fetch the pgm pool shadow descriptor. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PPGMPOOLPAGE pShwPde = pVCpu->pgm.s.CTX_SUFF(pShwPageCR3);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync const unsigned iPdpt = (GCPtrPage >> X86_PDPT_SHIFT);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* If the shadow PDPE isn't present, then skip the invalidate. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync Assert(!(pPdptDst->a[iPdpt].u & PGM_PLXFLAGS_MAPPING));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,InvalidatePageSkipped));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync const unsigned iPDDst = (GCPtrPage >> SHW_PD_SHIFT) & SHW_PD_MASK;
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* Fetch the pgm pool shadow descriptor. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = pgmShwGetPaePoolPagePD(pVCpu, GCPtrPage, &pShwPde);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync pPDDst = (PX86PDPAE)PGMPOOL_PAGE_2_PTR_V2(pVM, pVCpu, pShwPde);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# else /* PGM_SHW_TYPE == PGM_TYPE_AMD64 */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync const unsigned iPml4 = (GCPtrPage >> X86_PML4_SHIFT) & X86_PML4_MASK;
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync const unsigned iPdpt = (GCPtrPage >> X86_PDPT_SHIFT) & X86_PDPT_MASK_AMD64;
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync const unsigned iPDDst = (GCPtrPage >> SHW_PD_SHIFT) & SHW_PD_MASK;
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = pgmShwGetLongModePDPtr(pVCpu, GCPtrPage, &pPml4eDst, &pPdptDst, &pPDDst);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync AssertMsg(rc == VERR_PAGE_DIRECTORY_PTR_NOT_PRESENT || rc == VERR_PAGE_MAP_LEVEL4_NOT_PRESENT, ("Unexpected rc=%Rrc\n", rc));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,InvalidatePageSkipped));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,InvalidatePageSkipped));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* Fetch the pgm pool shadow descriptor. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PPGMPOOLPAGE pShwPde = pgmPoolGetPage(pPool, pPdptDst->a[iPdpt].u & SHW_PDPE_PG_MASK);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# endif /* PGM_SHW_TYPE == PGM_TYPE_AMD64 */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,InvalidatePageSkipped));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Get the guest PD entry and calc big page.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# else /* PGM_GST_TYPE != PGM_TYPE_32BIT */
6716c5c35f6e4987aecd2ad2f65f3ecebf235f6bvboxsync unsigned iPDSrc = 0;
ac2f474cb351240b8a8e5e2049b0b7badb99fffavboxsync PX86PDPAE pPDSrc = pgmGstGetPaePDPtr(pVCpu, GCPtrPage, &iPDSrc, &PdpeSrcIgn);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# else /* AMD64 */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PX86PDPAE pPDSrc = pgmGstGetLongModePDPtr(pVCpu, GCPtrPage, &pPml4eSrcIgn, &PdpeSrcIgn, &iPDSrc);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# endif /* PGM_GST_TYPE != PGM_TYPE_32BIT */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync const bool fIsBigPage = PdeSrc.b.u1Size && GST_IS_PSE_ACTIVE(pVCpu);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * If a CR3 Sync is pending we may ignore the invalidate page operation
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * depending on the kind of sync and if it's a global page or not.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * This doesn't make sense in GC/R0 so we'll skip it entirely there.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync || ( VMCPU_FF_ISSET(pVCpu, VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync if (VM_FF_ISPENDING(pVM, VM_FF_PGM_SYNC_CR3 | VM_FF_PGM_SYNC_CR3_NON_GLOBAL) )
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,InvalidatePageSkipped));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# endif /* IN_RING3 */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Deal with the Guest PDE.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Conflict - Let SyncPT deal with it to avoid duplicate code.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = PGM_BTH_NAME(SyncPT)(pVCpu, iPDSrc, pPDSrc, GCPtrPage);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# endif /* !PGM_WITHOUT_MAPPING */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * 4KB - page.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PPGMPOOLPAGE pShwPage = pgmPoolGetPage(pPool, PdeDst.u & SHW_PDE_PG_MASK);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# if PGM_SHW_TYPE == PGM_TYPE_PAE && PGM_GST_TYPE == PGM_TYPE_32BIT
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* Select the right PDE as we're emulating a 4kb page table with 2 shadow page tables. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* Syncing it here isn't 100% safe and it's probably not worth spending time syncing it. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PSHWPT pPTDst = (PSHWPT)PGMPOOL_PAGE_2_PTR_V2(pVM, pVCpu, pShwPage);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = PGM_GCPHYS_2_PTR_V2(pVM, pVCpu, GST_GET_PDE_GCPHYS(PdeSrc), &pPTSrc);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync const unsigned iPTSrc = (GCPtrPage >> GST_PT_SHIFT) & GST_PT_MASK;
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync const unsigned iPTDst = (GCPtrPage >> SHW_PT_SHIFT) & SHW_PT_MASK;
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PGM_BTH_NAME(SyncPageWorker)(pVCpu, &pPTDst->a[iPTDst], PdeSrc, PteSrc, pShwPage, iPTDst);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync Log2(("SyncPage: 4K %RGv PteSrc:{P=%d RW=%d U=%d raw=%08llx} PteDst=%08llx %s\n",
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync SHW_PTE_IS_TRACK_DIRTY(pPTDst->a[iPTDst]) ? " Track-Dirty" : ""));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,InvalidatePage4KBPages));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * The page table address changed.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync LogFlow(("InvalidatePage: Out-of-sync at %RGp PdeSrc=%RX64 PdeDst=%RX64 ShwGCPhys=%RGp iPDDst=%#x\n",
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync GCPtrPage, (uint64_t)PdeSrc.u, (uint64_t)PdeDst.u, pShwPage->GCPhys, iPDDst));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync pgmPoolFree(pVM, PdeDst.u & SHW_PDE_PG_MASK, pShwPde->idx, iPDDst);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,InvalidatePagePDOutOfSync));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * 2/4MB - page.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* Before freeing the page, check if anything really changed. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PPGMPOOLPAGE pShwPage = pgmPoolGetPage(pPool, PdeDst.u & SHW_PDE_PG_MASK);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync RTGCPHYS GCPhys = GST_GET_BIG_PDE_GCPHYS(pVM, PdeSrc);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# if PGM_SHW_TYPE == PGM_TYPE_PAE && PGM_GST_TYPE == PGM_TYPE_32BIT
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* Select the right PDE as we're emulating a 4MB page directory with two 2 MB shadow PDEs.*/
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync && pShwPage->enmKind == BTH_PGMPOOLKIND_PT_FOR_BIG)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* ASSUMES a the given bits are identical for 4M and normal PDEs */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /** @todo This test is wrong as it cannot check the G bit!
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync if ( (PdeSrc.u & (X86_PDE_P | X86_PDE_RW | X86_PDE_US))
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync == (PdeDst.u & (X86_PDE_P | X86_PDE_RW | X86_PDE_US))
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync && ( PdeSrc.b.u1Dirty /** @todo rainy day: What about read-only 4M pages? not very common, but still... */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync LogFlow(("Skipping flush for big page containing %RGv (PD=%X .u=%RX64)-> nothing has changed!\n", GCPtrPage, iPDSrc, PdeSrc.u));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,InvalidatePage4MBPagesSkip));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Ok, the page table is present and it's been changed in the guest.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * If we're in host context, we'll just mark it as not present taking the lazy approach.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * We could do this for some flushes in GC too, but we need an algorithm for
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * deciding which 4MB pages containing code likely to be executed very soon.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync LogFlow(("InvalidatePage: Out-of-sync PD at %RGp PdeSrc=%RX64 PdeDst=%RX64\n",
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync GCPtrPage, (uint64_t)PdeSrc.u, (uint64_t)PdeDst.u));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync pgmPoolFree(pVM, PdeDst.u & SHW_PDE_PG_MASK, pShwPde->idx, iPDDst);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,InvalidatePage4MBPages));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Page directory is not present, mark shadow PDE not present.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync pgmPoolFree(pVM, PdeDst.u & SHW_PDE_PG_MASK, pShwPde->idx, iPDDst);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,InvalidatePagePDNPs));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,InvalidatePagePDMappings));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync#else /* guest real and protected mode */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* There's no such thing as InvalidatePage when paging is disabled, so just ignore. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Update the tracking of shadowed pages.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param pVCpu The VMCPU handle.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param pShwPage The shadow page.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param HCPhys The physical page we is being dereferenced.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param iPte Shadow PTE index
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param GCPhysPage Guest physical address (only valid if pShwPage->fDirty is set)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsyncDECLINLINE(void) PGM_BTH_NAME(SyncPageWorkerTrackDeref)(PVMCPU pVCpu, PPGMPOOLPAGE pShwPage, RTHCPHYS HCPhys, uint16_t iPte, RTGCPHYS GCPhysPage)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync && (PGM_GST_TYPE == PGM_TYPE_PAE || PGM_GST_TYPE == PGM_TYPE_AMD64 || PGM_SHW_TYPE == PGM_TYPE_PAE /* pae/32bit combo */)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* Use the hint we retrieved from the cached guest PT. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PPGMPAGE pPhysPage = pgmPhysGetPage(&pVM->pgm.s, GCPhysPage);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync pgmTrackDerefGCPhys(pPool, pShwPage, pPhysPage, iPte);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_PROFILE_START(&pVM->pgm.s.CTX_SUFF(pStats)->StatTrackDeref, a);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync LogFlow(("SyncPageWorkerTrackDeref: Damn HCPhys=%RHp pShwPage->idx=%#x!!!\n", HCPhys, pShwPage->idx));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /** @todo If this turns out to be a bottle neck (*very* likely) two things can be done:
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * 1. have a medium sized HCPhys -> GCPhys TLB (hash?)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * 2. write protect all shadowed pages. I.e. implement caching.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /** @todo duplicated in the 2nd half of pgmPoolTracDerefGCPhysHint */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Find the guest address.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync for (PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(pRamRanges);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync while (iPage-- > 0)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync if (PGM_PAGE_GET_HCPHYS(&pRam->aPages[iPage]) == HCPhys)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync pgmTrackDerefGCPhys(pPool, pShwPage, &pRam->aPages[iPage], iPte);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_PROFILE_STOP(&pVM->pgm.s.CTX_SUFF(pStats)->StatTrackDeref, a);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync AssertReleaseMsgFailed(("HCPhys=%RHp wasn't found!\n", HCPhys));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Update the tracking of shadowed pages.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param pVCpu The VMCPU handle.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param pShwPage The shadow page.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param u16 The top 16-bit of the pPage->HCPhys.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param pPage Pointer to the guest page. this will be modified.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param iPTDst The index into the shadow table.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsyncDECLINLINE(void) PGM_BTH_NAME(SyncPageWorkerTrackAddref)(PVMCPU pVCpu, PPGMPOOLPAGE pShwPage, uint16_t u16, PPGMPAGE pPage, const unsigned iPTDst)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Just deal with the simple first time here.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVM->pgm.s.CTX_SUFF(pStats)->StatTrackVirgin);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* Save the page table index. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync u16 = pgmPoolTrackPhysExtAddref(pVM, pPage, u16, pShwPage->idx, iPTDst);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* write back */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync Log2(("SyncPageWorkerTrackAddRef: u16=%#x->%#x iPTDst=%#x\n", u16, PGM_PAGE_GET_TRACKING(pPage), iPTDst));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* update statistics. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Modifies a shadow PTE to account for access handlers.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param pVM The VM handle.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param pPage The page in question.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param fPteSrc The shadowed flags of the source PTE. Must include the
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * A (accessed) bit so it can be emulated correctly.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param pPteDst The shadow PTE (output). This is temporary storage and
ac2f474cb351240b8a8e5e2049b0b7badb99fffavboxsync * does not need to be set atomically.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsyncDECLINLINE(void) PGM_BTH_NAME(SyncHandlerPte)(PVM pVM, PCPGMPAGE pPage, uint64_t fPteSrc, PSHWPTE pPteDst)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /** @todo r=bird: Are we actually handling dirty and access bits for pages with access handlers correctly? No.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Update: \#PF should deal with this before or after calling the handlers. It has all the info to do the job efficiently. */
#ifdef PGM_WITH_MMIO_OPTIMIZATIONS
|| (fPteSrc & (X86_PTE_RW | X86_PTE_US)) == X86_PTE_RW) /** @todo Remove X86_PTE_US here and pGstWalk->Core.fEffectiveUS before the sync page test. */
static void PGM_BTH_NAME(SyncPageWorker)(PVMCPU pVCpu, PSHWPTE pPteDst, GSTPDE PdeSrc, GSTPTE PteSrc,
#if defined(PGMPOOL_WITH_OPTIMIZED_DIRTY_PT) \
&& (PGM_GST_TYPE == PGM_TYPE_PAE || PGM_GST_TYPE == PGM_TYPE_AMD64 || PGM_SHW_TYPE == PGM_TYPE_PAE /* pae/32bit combo */)
#ifndef VBOX_WITH_NEW_LAZY_PAGE_ALLOC
# ifdef VBOX_WITH_PAGE_SHARING
* If the page is not flagged as dirty and is writable, then make it read-only, so we can set the dirty bit
Log3(("SyncPageWorker: write-protecting %RGp pPage=%R[pgmpage]at iPTDst=%d\n", (RTGCPHYS)GST_GET_PTE_GCPHYS(PteSrc), pPage, iPTDst));
PGM_BTH_NAME(SyncPageWorkerTrackAddref)(pVCpu, pShwPage, PGM_PAGE_GET_TRACKING(pPage), pPage, iPTDst);
Log2(("SyncPageWorker: deref! *pPteDst=%RX64 PteDst=%RX64\n", SHW_PTE_LOG64(*pPteDst), SHW_PTE_LOG64(PteDst)));
PGM_BTH_NAME(SyncPageWorkerTrackDeref)(pVCpu, pShwPage, SHW_PTE_GET_HCPHYS(*pPteDst), iPTDst, GCPhysOldPage);
PGM_BTH_NAME(SyncPageWorkerTrackAddref)(pVCpu, pShwPage, PGM_PAGE_GET_TRACKING(pPage), pPage, iPTDst);
PGM_BTH_NAME(SyncPageWorkerTrackDeref)(pVCpu, pShwPage, SHW_PTE_GET_HCPHYS(*pPteDst), iPTDst, GCPhysOldPage);
PGM_BTH_NAME(SyncPageWorkerTrackDeref)(pVCpu, pShwPage, SHW_PTE_GET_HCPHYS(*pPteDst), iPTDst, GCPhysOldPage);
static int PGM_BTH_NAME(SyncPage)(PVMCPU pVCpu, GSTPDE PdeSrc, RTGCPTR GCPtrPage, unsigned cPages, unsigned uErr)
Log(("CPU%u: SyncPage: Pde at %RGv changed behind our back? (pPdeDst=%p/%RX64) uErr=%#x\n", pVCpu->idCpu, GCPtrPage, pPdeDst, (uint64_t)PdeDst.u, (uint32_t)uErr));
AssertMsg(pVM->cCpus > 1 || (uErr & (X86_TRAP_PF_P | X86_TRAP_PF_RW)) == (X86_TRAP_PF_P | X86_TRAP_PF_RW),
const bool fPdeValid = !fBigPage ? GST_IS_PDE_VALID(pVCpu, PdeSrc) : GST_IS_BIG_PDE_VALID(pVCpu, PdeSrc);
if (!fBigPage)
if ( fPdeValid
if (!fBigPage)
# ifdef PGM_SYNC_N_PAGES
const unsigned offPTSrc = 0;
iPTDst = 0;
RTGCPTR GCPtrCurPage = (GCPtrPage & ~(RTGCPTR)(GST_PT_MASK << GST_PT_SHIFT)) | ((offPTSrc + iPTDst) << PAGE_SHIFT);
#ifndef IN_RING0
# ifndef VBOX_WITH_NEW_LAZY_PAGE_ALLOC
# ifdef VBOX_WITH_PAGE_SHARING
PGM_BTH_NAME(SyncPageWorkerTrackAddref)(pVCpu, pShwPage, PGM_PAGE_GET_TRACKING(pPage), pPage, iPTDst);
return VINF_SUCCESS;
else if (fPdeValid)
/// @todo STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_MID_Z(Stat,SyncPagePDOutOfSyncAndInvalid));
return VINF_PGM_SYNCPAGE_MODIFIED_PDE;
&& !defined(IN_RC)
# ifdef PGM_SYNC_N_PAGES
return rc;
/* Can happen in the guest SMP case; other VCPU activated this PDE while we were blocking to handle the page fault. */
Log(("CPU%d: SyncPage: Pde (big:%RX64) at %RGv changed behind our back!\n", pVCpu->idCpu, PdeDst.u, GCPtrPage));
return VINF_SUCCESS;
iPTDst = 0;
RTGCPTR GCPtrCurPage = (GCPtrPage & ~(RTGCPTR)(SHW_PT_MASK << SHW_PT_SHIFT)) | (iPTDst << PAGE_SHIFT);
Log4(("%RGv iPTDst=%x pPTDst->a[iPTDst] %RX64\n", (GCPtrPage & ~(RTGCPTR)(SHW_PT_MASK << SHW_PT_SHIFT)) | (iPTDst << PAGE_SHIFT), iPTDst, SHW_PTE_LOG64(pPTDst->a[iPTDst]) ));
RTGCPTR GCPtrCurPage = (GCPtrPage & ~(RTGCPTR)(SHW_PT_MASK << SHW_PT_SHIFT)) | (iPTDst << PAGE_SHIFT);
return VINF_SUCCESS;
return VERR_INTERNAL_ERROR;
DECLINLINE(int) PGM_BTH_NAME(CheckPageFaultReturnNP)(PVMCPU pVCpu, uint32_t uErr, RTGCPTR GCPtrPage, unsigned uPageFaultLevel)
return VINF_EM_RAW_GUEST_TRAP;
DECLINLINE(int) PGM_BTH_NAME(CheckPageFaultReturnRSVD)(PVMCPU pVCpu, uint32_t uErr, RTGCPTR GCPtrPage, unsigned uPageFaultLevel)
return VINF_EM_RAW_GUEST_TRAP;
DECLINLINE(int) PGM_BTH_NAME(CheckPageFaultReturnProt)(PVMCPU pVCpu, uint32_t uErr, RTGCPTR GCPtrPage, unsigned uPageFaultLevel)
return VINF_EM_RAW_GUEST_TRAP;
static int PGM_BTH_NAME(CheckDirtyPageFault)(PVMCPU pVCpu, uint32_t uErr, PSHWPDE pPdeDst, GSTPDE const *pPdeSrc, RTGCPTR GCPtrPage)
/* Note: No need to invalidate this entry on other VCPUs as a stale TLB entry will not harm; write access will simply
# ifdef IN_RING0
if (pShwPage)
return VINF_PGM_NO_DIRTY_BIT_TRACKING;
return rc;
#ifndef IN_RING0
return VINF_PGM_NO_DIRTY_BIT_TRACKING;
if (pShwPage)
SHW_PTE_SET(PteDst, (SHW_PTE_GET_U(PteDst) | X86_PTE_D | X86_PTE_A) & ~(uint64_t)PGM_PTFLAGS_TRACK_DIRTY);
# ifdef IN_RING0
return VINF_PGM_NO_DIRTY_BIT_TRACKING;
AssertMsg(iPDSrc == ((GCPtrPage >> GST_PD_SHIFT) & GST_PD_MASK), ("iPDSrc=%x GCPtrPage=%RGv\n", iPDSrc, GCPtrPage));
# ifndef PGM_WITHOUT_MAPPINGS
# ifndef IN_RING3
return VERR_ADDRESS_CONFLICT;
return rc;
if (fPageTable)
const bool fNoExecute = false;
rc = pgmPoolAllocEx(pVM, GCPhys, BTH_PGMPOOLKIND_PT_FOR_BIG, enmAccess, pShwPde->idx, iPDDst, false /*fLockPage*/,
&pShwPage);
if (fPageTable)
return VINF_SUCCESS;
return VINF_PGM_SYNC_CR3;
if (fPageTable)
# ifdef PGM_SYNC_N_PAGES
iPTDst = 0;
unsigned iPTDst = 0;
const unsigned offPTSrc = 0;
# ifndef IN_RING0
Log2(("SyncPT: 4K+ %RGv PteSrc:{P=%d RW=%d U=%d raw=%08llx}%s dst.raw=%08llx iPTSrc=%x PdeSrc.u=%x physpte=%RGp\n",
SHW_PTE_IS_TRACK_DIRTY(pPTDst->a[iPTDst]) ? " Track-Dirty" : "", SHW_PTE_LOG64(pPTDst->a[iPTDst]), iPTSrc, PdeSrc.au32[0],
unsigned iPTDst = 0;
# ifndef VBOX_WITH_NEW_LAZY_PAGE_ALLOC
# ifdef VBOX_WITH_PAGE_SHARING
# ifndef IN_RING0
Log3(("SyncPT: write-protecting %RGp pPage=%R[pgmpage] at %RGv\n", GCPhys, pPage, (RTGCPTR)(GCPtr | (iPTDst << SHW_PT_SHIFT))));
PGM_BTH_NAME(SyncPageWorkerTrackAddref)(pVCpu, pShwPage, PGM_PAGE_GET_TRACKING(pPage), pPage, iPTDst);
(RTGCPTR)(GCPtr | (iPTDst << SHW_PT_SHIFT)), SHW_PTE_IS_P(PteDst), SHW_PTE_IS_RW(PteDst), SHW_PTE_IS_US(PteDst), SHW_PTE_LOG64(PteDst),
iHCPage++;
iPTDst++;
else if (pRam)
iPTDst++;
return rc;
&& !defined(IN_RC)
return rc;
# if defined(PGM_WITH_LARGE_PAGES) && PGM_SHW_TYPE != PGM_TYPE_32BIT && PGM_SHW_TYPE != PGM_TYPE_PAE
PGM_BTH_NAME(SyncPageWorkerTrackAddref)(pVCpu, pShwPde, PGM_PAGE_GET_TRACKING(pPage), pPage, iPDDst);
return VINF_SUCCESS;
rc = pgmPoolAlloc(pVM, GCPhys & ~(RT_BIT_64(SHW_PD_SHIFT) - 1), BTH_PGMPOOLKIND_PT_FOR_PT, pShwPde->idx, iPDDst, &pShwPage);
return rc;
return VERR_INTERNAL_ERROR;
unsigned iPDSrc;
if (!pPDSrc)
unsigned iPDSrc;
if (!pPDSrc)
const unsigned iPDSrc = 0;
PdpeSrc.u = X86_PDPE_P; /* rw/us are reserved for PAE pdpte's; accessed bit causes invalid VT-x guest state errors */
return rc;
return rc;
return rc;
AssertCompile(0);
PGM_BTH_DECL(int, VerifyAccessSyncPage)(PVMCPU pVCpu, RTGCPTR GCPtrPage, unsigned fPage, unsigned uErr)
# ifndef IN_RING0
unsigned iPDSrc = 0;
return VINF_EM_RAW_GUEST_TRAP;
return VINF_EM_RAW_GUEST_TRAP;
const unsigned iPDSrc = 0;
PdpeSrc.u = X86_PDPE_P; /* rw/us are reserved for PAE pdpte's; accessed bit causes invalid VT-x guest state errors */
return rc;
/* AMD-V nested paging: Fake PML4 & PDPT entry; access control handled on the page table level, so allow everything. */
return rc;
return rc;
return rc;
return VERR_INTERNAL_ERROR;
# ifdef PGMPOOL_WITH_OPTIMIZED_DIRTY_PT
return VINF_SUCCESS;
return VINF_SUCCESS;
#else /* PGM_SHW_TYPE != PGM_TYPE_NESTED && PGM_SHW_TYPE != PGM_TYPE_EPT && PGM_SHW_TYPE != PGM_TYPE_AMD64 */
# ifndef PGM_WITHOUT_MAPPINGS
return VINF_PGM_SYNC_CR3;
return VINF_SUCCESS;
#endif /* PGM_SHW_TYPE != PGM_TYPE_NESTED && PGM_SHW_TYPE != PGM_TYPE_EPT && PGM_SHW_TYPE != PGM_TYPE_AMD64 */
#ifdef VBOX_STRICT
# ifdef IN_RC
PGM_BTH_DECL(unsigned, AssertCR3)(PVMCPU pVCpu, uint64_t cr3, uint64_t cr4, RTGCPTR GCPtr, RTGCPTR cb)
unsigned cErrors = 0;
AssertFailed();
# ifndef IN_RING0
int rc;
AssertMsgReturn(HCPhys == HCPhysShw, ("HCPhys=%RHp HCPhyswShw=%RHp (cr3)\n", HCPhys, HCPhysShw), false);
AssertMsgReturn((cr3 & GST_CR3_PAGE_MASK) == GCPhys, ("GCPhys=%RGp cr3=%RGp\n", GCPhys, (RTGCPHYS)cr3), false);
AssertMsgFailed(("Present bit doesn't match! pPml4eDst.u=%#RX64 pPml4eSrc.u=%RX64\n", pPml4eDst->u, pPml4eSrc->u));
cErrors++;
AssertMsgFailed(("Physical address doesn't match! iPml4 %d pPml4eDst.u=%#RX64 pPml4eSrc.u=%RX64 Phys %RX64 vs %RX64\n", iPml4, pPml4eDst->u, pPml4eSrc->u, pShwPdpt->GCPhys, GCPhysPdptSrc));
cErrors++;
AssertMsgFailed(("User/Write/NoExec bits don't match! pPml4eDst.u=%#RX64 pPml4eSrc.u=%RX64\n", pPml4eDst->u, pPml4eSrc->u));
cErrors++;
AssertMsgFailed(("Present bit doesn't match! pPdpeDst.u=%#RX64 pPdpeSrc.u=%RX64\n", pPdpeDst->u, PdpeSrc.u));
cErrors++;
AssertMsgFailed(("Physical address doesn't match! iPml4 %d iPdpt %d pPdpeDst.u=%#RX64 pPdpeSrc.u=%RX64 Phys %RX64 vs %RX64\n", iPml4, iPdpt, pPdpeDst->u, PdpeSrc.u, pShwPde->GCPhys, GCPhysPdeSrc));
AssertMsgFailed(("Physical address doesn't match! iPdpt %d pPdpeDst.u=%#RX64 pPdpeSrc.u=%RX64 Phys %RX64 vs %RX64\n", iPdpt, pPdpeDst->u, PdpeSrc.u, pShwPde->GCPhys, GCPhysPdeSrc));
cErrors++;
AssertMsgFailed(("User/Write/NoExec bits don't match! pPdpeDst.u=%#RX64 pPdpeSrc.u=%RX64\n", pPdpeDst->u, PdpeSrc.u));
cErrors++;
AssertMsgFailed(("Mapping shall only have PGM_PDFLAGS_MAPPING set! PdeDst.u=%#RX64\n", (uint64_t)PdeDst.u));
cErrors++;
if (!pPoolPage)
cErrors++;
AssertMsgFailed(("PDE flags PWT and/or PCD is set at %RGv! These flags are not virtualized! PdeDst=%#RX64\n",
cErrors++;
cErrors++;
cErrors++;
|| !fBigPagesSupported)
cErrors++;
!= (!PdeSrc.b.u1Size || !fBigPagesSupported ? BTH_PGMPOOLKIND_PT_FOR_PT : BTH_PGMPOOLKIND_PT_FOR_BIG))
cErrors++;
if (!pPhysPage)
cErrors++;
cErrors++;
|| !fBigPagesSupported)
AssertMsgFailed(("Cannot map/convert guest physical address %RGp in the PDE at %RGv! PdeSrc=%#RX64\n",
cErrors++;
/// @todo We get here a lot on out-of-sync CR3 entries. The access handler should zap them to avoid false alarms here!
cErrors++;
cErrors++;
const unsigned offPTSrc = 0;
if (!(SHW_PTE_GET_U(PteDst) & (X86_PTE_P | PGM_PTFLAGS_TRACK_DIRTY))) /** @todo deal with ALL handlers and CSAM !P pages! */
# ifdef IN_RING3
AssertMsgFailed(("Out of sync (!P) PTE at %RGv! PteSrc=%#RX64 PteDst=%#RX64 pPTSrc=%RGv iPTSrc=%x PdeSrc=%x physpte=%RGp\n",
cErrors++;
uint64_t fIgnoreFlags = GST_PTE_PG_MASK | X86_PTE_AVL_MASK | X86_PTE_G | X86_PTE_D | X86_PTE_PWT | X86_PTE_PCD | X86_PTE_PAT;
# ifdef IN_RING3
cErrors++;
AssertMsgFailed(("Out of sync (phys) at %RGv! HCPhysShw=%RHp HCPhys=%RHp GCPhysGst=%RGp PteSrc=%#RX64 PteDst=%#RX64\n",
cErrors++;
if (!pPhysPage)
cErrors++;
AssertMsgFailed(("Invalid guest page at %RGv is writable! GCPhysGst=%RGp PteSrc=%#RX64 PteDst=%#RX64\n",
cErrors++;
AssertMsgFailed(("Out of sync (phys) at %RGv! HCPhysShw=%RHp pPhysPage:%R[pgmpage] GCPhysGst=%RGp PteSrc=%#RX64 PteDst=%#RX64\n",
cErrors++;
AssertMsgFailed(("WRITE access flagged at %RGv but the page is writable! pPhysPage=%R[pgmpage] PteSrc=%#RX64 PteDst=%#RX64\n",
cErrors++;
AssertMsgFailed(("ALL access flagged at %RGv but the page is present! pPhysPage=%R[pgmpage] PteSrc=%#RX64 PteDst=%#RX64\n",
cErrors++;
cErrors++;
cErrors++;
cErrors++;
AssertMsgFailed(("!DIRTY page at %RGv is has mismatching accessed bit! PteSrc=%#RX64 PteDst=%#RX64\n",
cErrors++;
AssertMsgFailed(("PGM_PTFLAGS_TRACK_DIRTY set at %RGv but no accessed bit emulation! PteSrc=%#RX64 PteDst=%#RX64\n",
cErrors++;
AssertMsgFailed(("!ACCESSED page at %RGv is has the accessed bit set! PteSrc=%#RX64 PteDst=%#RX64\n",
cErrors++;
# ifdef DEBUG_sandervl
AssertMsgFailed(("Flags mismatch at %RGv! %#RX64 != %#RX64 fIgnoreFlags=%#RX64 PteSrc=%#RX64 PteDst=%#RX64\n",
cErrors++;
uint64_t fIgnoreFlags = X86_PDE_AVL_MASK | GST_PDE_PG_MASK | X86_PDE4M_G | X86_PDE4M_D | X86_PDE4M_PS | X86_PDE4M_PWT | X86_PDE4M_PCD;
cErrors++;
cErrors++;
AssertMsgFailed(("!DIRTY page at %RGv is has mismatching accessed bit! PteSrc=%#RX64 PteDst=%#RX64\n",
cErrors++;
AssertMsgFailed(("PGM_PDFLAGS_TRACK_DIRTY set at %RGv but no accessed bit emulation! PdeSrc=%#RX64 PdeDst=%#RX64\n",
cErrors++;
AssertMsgFailed(("!ACCESSED page at %RGv is has the accessed bit set! PdeSrc=%#RX64 PdeDst=%#RX64\n",
cErrors++;
AssertMsgFailed(("Flags mismatch (B) at %RGv! %#RX64 != %#RX64 fIgnoreFlags=%#RX64 PdeSrc=%#RX64 PdeDst=%#RX64\n",
cErrors++;
AssertMsgFailed(("The PTE at %RGv emulating a 2/4M page is marked TRACK_DIRTY! PdeSrc=%#RX64 PteDst=%#RX64\n",
cErrors++;
fIgnoreFlags = X86_PTE_PAE_PG_MASK | X86_PTE_AVL_MASK | X86_PTE_PWT | X86_PTE_PCD | X86_PTE_PAT | X86_PTE_D | X86_PTE_A | X86_PTE_G | X86_PTE_PAE_NX;
# ifdef IN_RING3
cErrors++;
AssertMsgFailed(("Out of sync (phys) at %RGv! HCPhysShw=%RHp HCPhys=%RHp GCPhysGst=%RGp PdeSrc=%#RX64 PteDst=%#RX64\n",
cErrors++;
if (!pPhysPage)
cErrors++;
AssertMsgFailed(("Invalid guest page at %RGv is writable! GCPhysGst=%RGp PdeSrc=%#RX64 PteDst=%#RX64\n",
cErrors++;
AssertMsgFailed(("Out of sync (phys) at %RGv! HCPhysShw=%RHp pPhysPage=%R[pgmpage] GCPhysGst=%RGp PdeSrc=%#RX64 PteDst=%#RX64\n",
cErrors++;
AssertMsgFailed(("WRITE access flagged at %RGv but the page is writable! pPhysPage=%R[pgmpage] PdeSrc=%#RX64 PteDst=%#RX64\n",
cErrors++;
AssertMsgFailed(("ALL access flagged at %RGv but the page is present! pPhysPage=%R[pgmpage] PdeSrc=%#RX64 PteDst=%#RX64\n",
cErrors++;
&& (PdeSrc.u & ~(fIgnoreFlags | X86_PTE_RW)) != (SHW_PTE_GET_U(PteDst) & ~fIgnoreFlags) /* lazy phys handler dereg. */
AssertMsgFailed(("Flags mismatch (BT) at %RGv! %#RX64 != %#RX64 fIgnoreFlags=%#RX64 PdeSrc=%#RX64 PteDst=%#RX64\n",
cErrors++;
# ifdef DEBUG
if (cErrors)
return cErrors;
int rc = pgmPhysGCPhys2CCPtrInternal(pVM, pPageCR3, GCPhysCR3 & GST_CR3_PAGE_MASK, (void **)&HCPtrGuestCR3); /** @todo r=bird: This GCPhysCR3 masking isn't necessary. */
# ifdef IN_RC
# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
# ifdef IN_RC
# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
# ifdef IN_RC
# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
# ifdef PGMPOOL_WITH_OPTIMIZED_DIRTY_PT
rc = pgmPoolAllocEx(pVM, GCPhysCR3 & GST_CR3_PAGE_MASK, BTH_PGMPOOLKIND_ROOT, PGMPOOLACCESS_DONTCARE, SHW_POOL_ROOT_IDX,
# ifdef IN_RC
# ifdef IN_RING0
# ifndef PGM_WITHOUT_MAPPINGS
Assert(VMCPU_FF_ISSET(pVCpu, VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL) || VMCPU_FF_ISSET(pVCpu, VMCPU_FF_PGM_SYNC_CR3));
# ifdef IN_RC
if ( pOldShwPageCR3
&& pOldShwPageCR3 != pNewShwPageCR3 /* @todo can happen due to incorrect syncing between REM & PGM; find the real cause */)
# ifndef PGM_WITHOUT_MAPPINGS
return rc;
# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
for (unsigned i = 0; i < X86_PG_PAE_PDPE_ENTRIES; i++)
# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
# ifndef PGM_WITHOUT_MAPPINGS
# ifdef PGMPOOL_WITH_OPTIMIZED_DIRTY_PT
pgmPoolFreeByPage(pPool, pVCpu->pgm.s.CTX_SUFF(pShwPageCR3), pVCpu->pgm.s.iShwUser, pVCpu->pgm.s.iShwUserTable);
return rc;