PGMAllBth.h revision dfa8248be9f58d614e4c52559c0e6bd29e27f9d5
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * VBox - Page Manager, Shadow+Guest Paging Template - All context code.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * This file is a big challenge!
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Copyright (C) 2006-2007 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * additional information or have any questions.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync/*******************************************************************************
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync* Internal Functions *
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync*******************************************************************************/
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsyncPGM_BTH_DECL(int, Trap0eHandler)(PVM pVM, RTGCUINT uErr, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsyncPGM_BTH_DECL(int, InvalidatePage)(PVM pVM, RTGCUINTPTR GCPtrPage);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsyncPGM_BTH_DECL(int, SyncPage)(PVM pVM, GSTPDE PdeSrc, RTGCUINTPTR GCPtrPage, unsigned cPages, unsigned uErr);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsyncPGM_BTH_DECL(int, CheckPageFault)(PVM pVM, uint32_t uErr, PSHWPDE pPdeDst, PGSTPDE pPdeSrc, RTGCUINTPTR GCPtrPage);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsyncPGM_BTH_DECL(int, SyncPT)(PVM pVM, unsigned iPD, PGSTPD pPDSrc, RTGCUINTPTR GCPtrPage);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsyncPGM_BTH_DECL(int, VerifyAccessSyncPage)(PVM pVM, RTGCUINTPTR Addr, unsigned fPage, unsigned uErr);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsyncPGM_BTH_DECL(int, PrefetchPage)(PVM pVM, RTGCUINTPTR GCPtrPage);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsyncPGM_BTH_DECL(int, SyncCR3)(PVM pVM, uint64_t cr0, uint64_t cr3, uint64_t cr4, bool fGlobal);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsyncPGM_BTH_DECL(unsigned, AssertCR3)(PVM pVM, uint64_t cr3, uint64_t cr4, RTGCUINTPTR GCPtr = 0, RTGCUINTPTR cb = ~(RTGCUINTPTR)0);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsyncDECLINLINE(void) PGM_BTH_NAME(SyncPageWorkerTrackDeref)(PVM pVM, PPGMPOOLPAGE pShwPage, RTHCPHYS HCPhys);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync/* Filter out some illegal combinations of guest and shadow paging, so we can 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
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)
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)
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) \
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#ifdef IN_RING0 /* no mappings in VT-x and AMD-V mode */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * #PF Handler for raw-mode guest execution.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @returns VBox status code (appropriate for trap handling and GC return).
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param pVM VM Handle.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param uErr The trap error code.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param pRegFrame Trap register frame.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param pvFault The fault address.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsyncPGM_BTH_DECL(int, Trap0eHandler)(PVM pVM, RTGCUINT uErr, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync#if (PGM_GST_TYPE == PGM_TYPE_32BIT || PGM_GST_TYPE == PGM_TYPE_REAL || PGM_GST_TYPE == PGM_TYPE_PROT || PGM_GST_TYPE == PGM_TYPE_PAE || PGM_GST_TYPE == PGM_TYPE_AMD64) \
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# if PGM_SHW_TYPE == PGM_TYPE_PAE && PGM_GST_TYPE != PGM_TYPE_PAE
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Hide the instruction fetch trap indicator for now.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /** @todo NXE will change this and we must fix NXE in the switcher too! */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync const unsigned iPDSrc = (RTGCUINTPTR)pvFault >> GST_PD_SHIFT;
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# elif PGM_GST_TYPE == PGM_TYPE_PAE || PGM_GST_TYPE == PGM_TYPE_AMD64
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PGSTPD pPDSrc = pgmGstGetPaePDPtr(&pVM->pgm.s, (RTGCUINTPTR)pvFault, &iPDSrc);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync pPDSrc = pgmGstGetLongModePDPtr(&pVM->pgm.s, pvFault, &pPml4eSrc, &PdpeSrc, &iPDSrc);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* Quick check for a valid guest trap. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync LogFlow(("Trap0eHandler: guest PDPTR %d not present CR3=%VGp\n", (pvFault >> X86_PML4_SHIFT) & X86_PML4_MASK, (CPUMGetGuestCR3(pVM) & X86_CR3_PAGE_MASK)));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_STATS({ pVM->pgm.s.CTXSUFF(pStatTrap0eAttribution) = &pVM->pgm.s.StatTrap0eGuestTrap; });
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync const unsigned iPDSrc = 0;
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync const unsigned iPDDst = (RTGCUINTPTR)pvFault >> SHW_PD_SHIFT;
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync const unsigned iPDDst = (RTGCUINTPTR)pvFault >> SHW_PD_SHIFT;
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PX86PDPAE pPDDst = pVM->pgm.s.CTXMID(ap,PaePDs)[0]; /* We treat this as a PD with 2048 entries, so no need to and with SHW_PD_MASK to get iPDDst */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* Did we mark the PDPT as not present in SyncCR3? */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync unsigned iPdpte = ((RTGCUINTPTR)pvFault >> SHW_PDPT_SHIFT) & SHW_PDPT_MASK;
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync if (!pVM->pgm.s.CTXMID(p,PaePDPT)->a[iPdpte].n.u1Present)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync pVM->pgm.s.CTXMID(p,PaePDPT)->a[iPdpte].n.u1Present = 1;
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync const unsigned iPDDst = (((RTGCUINTPTR)pvFault >> SHW_PD_SHIFT) & SHW_PD_MASK);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* AMD-V nested paging */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* Fake PML4 & PDPT entry; access control handled on the page table level, so allow everything. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync Pml4eSrc.u = X86_PML4E_P | X86_PML4E_RW | X86_PML4E_US | X86_PML4E_A;
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PdpeSrc.u = X86_PDPE_P | X86_PDPE_RW | X86_PDPE_US | X86_PDPE_A;
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = PGMShwSyncLongModePDPtr(pVM, (RTGCUINTPTR)pvFault, pPml4eSrc, &PdpeSrc, &pPDDst);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * If we successfully correct the write protection fault due to dirty bit
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * tracking, or this page fault is a genuine one, then return immediately.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_PROFILE_START(&pVM->pgm.s.StatCheckPageFault, e);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = PGM_BTH_NAME(CheckPageFault)(pVM, uErr, &pPDDst->a[iPDDst], &pPDSrc->a[iPDSrc], (RTGCUINTPTR)pvFault);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_PROFILE_STOP(&pVM->pgm.s.StatCheckPageFault, e);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_STATS({ pVM->pgm.s.CTXSUFF(pStatTrap0eAttribution)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync = rc == VINF_PGM_HANDLED_DIRTY_BIT_FAULT ? &pVM->pgm.s.StatTrap0eDirtyAndAccessedBits : &pVM->pgm.s.StatTrap0eGuestTrap; });
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync LogBird(("Trap0eHandler: returns %s\n", rc == VINF_PGM_HANDLED_DIRTY_BIT_FAULT ? "VINF_SUCCESS" : "VINF_EM_RAW_GUEST_TRAP"));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync return rc == VINF_PGM_HANDLED_DIRTY_BIT_FAULT ? VINF_SUCCESS : rc;
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVM->pgm.s.StatGCTrap0ePD[iPDSrc]);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# endif /* PGM_WITH_PAGING(PGM_GST_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 here
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * so we can safely assume that the shadow PT is present when calling 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 PdeSrc.au32[0] = 0; /* faked so we don't have to #ifdef everything */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync if ( !(uErr & X86_TRAP_PF_P) /* not set means page not present instead of page protection violation */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_STATS({ pVM->pgm.s.CTXSUFF(pStatTrap0eAttribution) = &pVM->pgm.s.StatTrap0eSyncPT; });
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync LogFlow(("=>SyncPT %04x = %08x\n", iPDSrc, PdeSrc.au32[0]));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = PGM_BTH_NAME(SyncPT)(pVM, iPDSrc, pPDSrc, (RTGCUINTPTR)pvFault);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync VM_FF_SET(pVM, VM_FF_PGM_SYNC_CR3); /** @todo no need to do global sync, right? */
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 = CTXALLSUFF(pVM->pgm.s.pMappings);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync for ( ; pMapping; pMapping = CTXALLSUFF(pMapping->pNext))
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync if ((RTGCUINTPTR)pvFault < (RTGCUINTPTR)pMapping->GCPtr)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync if ((RTGCUINTPTR)pvFault - (RTGCUINTPTR)pMapping->GCPtr < pMapping->cb)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * The first thing we check is if we've got an undetected conflict.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync while (iPT-- > 0)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVM->pgm.s.StatGCTrap0eConflicts);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync Log(("Trap0e: Detected Conflict %VGv-%VGv\n", pMapping->GCPtr, pMapping->GCPtrLast));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync VM_FF_SET(pVM, VM_FF_PGM_SYNC_CR3); /** @todo no need to do global sync,right? */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Check if the fault address is in a virtual page access handler range.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PPGMVIRTHANDLER pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrRangeGet(&CTXSUFF(pVM->pgm.s.pTrees)->HyperVirtHandlers, pvFault);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync && (RTGCUINTPTR)pvFault - (RTGCUINTPTR)pCur->GCPtr < pCur->cb
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = CTXSUFF(pCur->pfnHandler)(pVM, uErr, pRegFrame, pvFault, pCur->GCPtr, (RTGCUINTPTR)pvFault - (RTGCUINTPTR)pCur->GCPtr);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = VINF_EM_RAW_EMULATE_INSTR; /* can't happen with VMX */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVM->pgm.s.StatTrap0eMapHandler);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Pretend we're not here and let the guest handle the trap.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync LogFlow(("PGM: Mapping access -> route trap to recompiler!\n"));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync } /* pgmAreMappingsEnabled(&pVM->pgm.s) */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# endif /* PGM_WITH_PAGING(PGM_GST_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 bool fBigPagesSupported = !!(CPUMGetGuestCR4(pVM) & X86_CR4_PSE);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync | ((RTGCPHYS)pvFault & (GST_BIG_PAGE_OFFSET_MASK ^ PAGE_OFFSET_MASK));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = PGM_GCPHYS_2_PTR(pVM, PdeSrc.u & GST_PDE_PG_MASK, &pPTSrc);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync unsigned iPTESrc = ((RTGCUINTPTR)pvFault >> GST_PT_SHIFT) & GST_PT_MASK;
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* No paging so the fault address is the physical address */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync GCPhys = (RTGCPHYS)((RTGCUINTPTR)pvFault & ~PAGE_OFFSET_MASK);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# endif /* PGM_WITH_PAGING(PGM_GST_TYPE) */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * If we have a GC address we'll check if it has any flags set.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = pgmPhysGetPageEx(&pVM->pgm.s, GCPhys, &pPage);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Physical page access handler.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync const RTGCPHYS GCPhysFault = GCPhys | ((RTGCUINTPTR)pvFault & PAGE_OFFSET_MASK);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)RTAvlroGCPhysRangeGet(&CTXSUFF(pVM->pgm.s.pTrees)->PhysHandlers, 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 if ( pCur->enmType == PGMPHYSHANDLERTYPE_PHYSICAL_WRITE
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = PGM_BTH_NAME(SyncPage)(pVM, PdeSrc, (RTGCUINTPTR)pvFault, PGM_SYNC_NR_PAGES, uErr);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVM->pgm.s.StatHandlersOutOfSync);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_STATS({ pVM->pgm.s.CTXSUFF(pStatTrap0eAttribution) = &pVM->pgm.s.StatTrap0eOutOfSyncHndPhys; });
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) HCPhys=%X uErr=%X, enum=%d\n", pvFault, GCPhys, pPage->HCPhys, uErr, pCur->enmType));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = pCur->CTXALLSUFF(pfnHandler)(pVM, uErr, pRegFrame, pvFault, GCPhysFault, CTXALLSUFF(pCur->pvUser));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVM->pgm.s.StatHandlersPhysical);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_STATS({ pVM->pgm.s.CTXSUFF(pStatTrap0eAttribution) = &pVM->pgm.s.StatTrap0eHndPhys; });
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)(pVM, PdeSrc, (RTGCUINTPTR)pvFault, PGM_SYNC_NR_PAGES, uErr);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVM->pgm.s.StatHandlersOutOfSync);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_STATS({ pVM->pgm.s.CTXSUFF(pStatTrap0eAttribution) = &pVM->pgm.s.StatTrap0eOutOfSyncHndVirt; });
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 /** @note r=svl: true, but lookup on virtual address should remain as a fallback as phys & virt trees might be out of sync, because the
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * page was changed without us noticing it (not-present -> present without invlpg or mov cr3, xxx)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PPGMVIRTHANDLER pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrRangeGet(&CTXSUFF(pVM->pgm.s.pTrees)->VirtHandlers, pvFault);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync AssertMsg(!((RTGCUINTPTR)pvFault - (RTGCUINTPTR)pCur->GCPtr < pCur->cb)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync || (pCur->enmType == PGMVIRTHANDLERTYPE_WRITE && (uErr & X86_TRAP_PF_RW))),
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync ("Unexpected trap for virtual handler: %VGv (phys=%VGp) HCPhys=%HGp uErr=%X, enum=%d\n", pvFault, GCPhys, pPage->HCPhys, uErr, pCur->enmType));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync if ( (RTGCUINTPTR)pvFault - (RTGCUINTPTR)pCur->GCPtr < pCur->cb
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = CTXSUFF(pCur->pfnHandler)(pVM, uErr, pRegFrame, pvFault, pCur->GCPtr, (RTGCUINTPTR)pvFault - (RTGCUINTPTR)pCur->GCPtr);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = VINF_EM_RAW_EMULATE_INSTR; /** @todo for VMX */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_STATS({ pVM->pgm.s.CTXSUFF(pStatTrap0eAttribution) = &pVM->pgm.s.StatTrap0eHndVirt; });
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* Unhandled part of a monitored page */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* Check by physical address. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = pgmHandlerVirtualFindByPhysAddr(pVM, GCPhys + ((RTGCUINTPTR)pvFault & PAGE_OFFSET_MASK),
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync Assert((pCur->aPhysToVirt[iPage].Core.Key & X86_PTE_PAE_PG_MASK) == GCPhys);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync RTGCUINTPTR off = (iPage << PAGE_SHIFT) + ((RTGCUINTPTR)pvFault & PAGE_OFFSET_MASK) - ((RTGCUINTPTR)pCur->GCPtr & PAGE_OFFSET_MASK);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = CTXSUFF(pCur->pfnHandler)(pVM, uErr, pRegFrame, pvFault, pCur->GCPtr, off);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = VINF_EM_RAW_EMULATE_INSTR; /** @todo for VMX */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVM->pgm.s.StatHandlersVirtualByPhys);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_STATS({ pVM->pgm.s.CTXSUFF(pStatTrap0eAttribution) = &pVM->pgm.s.StatTrap0eHndVirt; });
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# endif /* PGM_WITH_PAGING(PGM_GST_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(&pVM->pgm.s.StatHandlersUnhandled);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = PGM_BTH_NAME(SyncPage)(pVM, PdeSrc, (RTGCUINTPTR)pvFault, PGM_SYNC_NR_PAGES, uErr);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVM->pgm.s.StatHandlersOutOfSync);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_STATS({ pVM->pgm.s.CTXSUFF(pStatTrap0eAttribution) = &pVM->pgm.s.StatTrap0eOutOfSyncHndPhys; });
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 = PGMInterpretInstruction(pVM, pRegFrame, pvFault);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync LogFlow(("PGM: PGMInterpretInstruction -> rc=%d HCPhys=%RHp%s%s\n",
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PGM_PAGE_HAS_ANY_PHYSICAL_HANDLERS(pPage) ? " phys" : "",
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PGM_PAGE_HAS_ANY_VIRTUAL_HANDLERS(pPage) ? " virt" : ""));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_STATS({ pVM->pgm.s.CTXSUFF(pStatTrap0eAttribution) = &pVM->pgm.s.StatTrap0eHndUnhandled; });
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync } /* if any kind of handler */
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(&CTXSUFF(pVM->pgm.s.pTrees)->VirtHandlers, pvFault);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync AssertMsg( !((RTGCUINTPTR)pvFault - (RTGCUINTPTR)pCur->GCPtr < pCur->cb)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync || (pCur->enmType == PGMVIRTHANDLERTYPE_WRITE && (uErr & X86_TRAP_PF_RW))),
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync ("Unexpected trap for virtual handler: %08X (phys=%08x) HCPhys=%X uErr=%X, enum=%d\n", pvFault, GCPhys, pPage->HCPhys, uErr, pCur->enmType));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync if ( (RTGCUINTPTR)pvFault - (RTGCUINTPTR)pCur->GCPtr < pCur->cb
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = CTXSUFF(pCur->pfnHandler)(pVM, uErr, pRegFrame, pvFault, pCur->GCPtr, (RTGCUINTPTR)pvFault - (RTGCUINTPTR)pCur->GCPtr);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = VINF_EM_RAW_EMULATE_INSTR; /** @todo for VMX */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVM->pgm.s.StatHandlersVirtualUnmarked);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_STATS({ pVM->pgm.s.CTXSUFF(pStatTrap0eAttribution) = &pVM->pgm.s.StatTrap0eHndVirt; });
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# endif /* PGM_WITH_PAGING(PGM_GST_TYPE) */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* When the guest accesses invalid physical memory (e.g. probing of RAM or accessing a remapped MMIO range), then we'll fall
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * back to the recompiler to emulate the instruction.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync LogFlow(("pgmPhysGetPageEx %VGp failed with %Vrc\n", GCPhys, rc));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * We are here only if page is present in Guest page tables and trap is not handled
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * by our handlers.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Check it for page out-of-sync situation.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Page is not present in our page tables.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Try to sync it!
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * BTW, fPageShw is invalid in this branch!
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVM->pgm.s.StatGCPageOutOfSyncUser);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync else /* supervisor */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVM->pgm.s.StatGCPageOutOfSyncSupervisor);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync Log(("Page out of sync: %VGv eip=%08x PdeSrc.n.u1User=%d fPageGst=%08llx GCPhys=%VGp scan=%d\n",
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync pvFault, pRegFrame->eip, PdeSrc.n.u1User, fPageGst, GCPhys, CSAMDoesPageNeedScanning(pVM, (RTRCPTR)pRegFrame->eip)));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# endif /* LOG_ENABLED */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# if PGM_WITH_PAGING(PGM_GST_TYPE) && !defined(IN_RING0)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* Note: can't check for X86_TRAP_ID bit, because that requires execute disable support on the CPU */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync || (RTGCUINTPTR)pvFault - pRegFrame->eip < 8 /* instruction crossing a page boundary */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync || ( !PATMIsPatchGCAddr(pVM, (RTGCPTR)pRegFrame->eip)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync && CSAMDoesPageNeedScanning(pVM, (RTRCPTR)pRegFrame->eip)) /* any new code we encounter here */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# endif /* CSAM_DETECT_NEW_CODE_PAGES */
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)(pVM, PdeSrc, (RTGCUINTPTR)pvFault, 1, uErr);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_STATS({ pVM->pgm.s.CTXSUFF(pStatTrap0eAttribution) = &pVM->pgm.s.StatTrap0eCSAM; });
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, &pRegFrame->csHid, (RTGCPTR)pRegFrame->eip, &PC);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = EMInterpretDisasOneEx(pVM, (RTGCUINTPTR)PC, pRegFrame, &Cpu, &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 %VGv; scanned=%d\n", pvFault, true));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# endif /* PGM_WITH_PAGING(PGM_GST_TYPE) && !defined(IN_RING0) */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = PGM_BTH_NAME(SyncPage)(pVM, PdeSrc, (RTGCUINTPTR)pvFault, PGM_SYNC_NR_PAGES, uErr);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* The page was successfully synced, return to the guest. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_STATS({ pVM->pgm.s.CTXSUFF(pStatTrap0eAttribution) = &pVM->pgm.s.StatTrap0eOutOfSync; });
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * A side effect of not flushing global PDEs are out of sync pages due
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * to physical monitored regions, that are no longer valid.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Assume for now it only applies to the read/write flag
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVM->pgm.s.StatGCPageOutOfSyncUser);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync else /* supervisor */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVM->pgm.s.StatGCPageOutOfSyncSupervisor);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Note: Do NOT use PGM_SYNC_NR_PAGES here. That only works if the page is not present, which is not true in this case.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = PGM_BTH_NAME(SyncPage)(pVM, PdeSrc, (RTGCUINTPTR)pvFault, 1, uErr);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Page was successfully synced, return to guest.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = PGMGstGetPage(pVM, pvFault, &fPageGst, &GCPhys);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync LogFlow(("Obsolete physical monitor page out of sync %VGv - phys %VGp flags=%08llx\n", pvFault, GCPhys, (uint64_t)fPageGst));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync AssertMsg(VBOX_SUCCESS(rc) && fPageShw & X86_PTE_RW, ("rc=%Vrc fPageShw=%VX64\n", rc, fPageShw));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# endif /* VBOX_STRICT */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_STATS({ pVM->pgm.s.CTXSUFF(pStatTrap0eAttribution) = &pVM->pgm.s.StatTrap0eOutOfSyncObsHnd; });
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* Check to see if we need to emulate the instruction as X86_CR0_WP has been cleared. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync && ((CPUMGetGuestCR0(pVM) & (X86_CR0_WP|X86_CR0_PG)) == X86_CR0_PG)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync && (uErr & (X86_TRAP_PF_RW | X86_TRAP_PF_P)) == (X86_TRAP_PF_RW | X86_TRAP_PF_P))
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = PGMInterpretInstruction(pVM, pRegFrame, pvFault);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync AssertMsgFailed(("Unexpected r/w page %x flag=%x\n", pvFault, (uint32_t)fPageGst));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Check for VMM page flags vs. Guest page flags consistency.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Currently only for debug purposes.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* Get guest page flags. */
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)) == (fPageGst & ~(X86_PTE_A | X86_PTE_D | X86_PTE_AVL_MASK)),
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync ("Page flags mismatch! pvFault=%VGv GCPhys=%VGp fPageShw=%08llx fPageGst=%08llx\n", pvFault, GCPhys, fPageShw, fPageGst));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# endif /* VBOX_STRICT */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# endif /* PGM_WITH_PAGING(PGM_GST_TYPE) */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# endif /* PGM_OUT_OF_SYNC_IN_GC */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Page not present in Guest OS or invalid page table address.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * This is potential virtual page access handler food.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * For the present we'll say that our access handlers don't
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * work for this case - we've already discarded the page table
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * not present case which is identical to this.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * When we perchance find we need this, we will probably have AVL
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * trees (offset based) to operate on and we can measure their speed
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * agains mapping a page table and probably rearrange this handling
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * a bit. (Like, searching virtual ranges before checking the
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * physical address.)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Conclusion, this is a guest trap.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync LogFlow(("PGM: Unhandled #PF -> route trap to recompiler!\n"));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVM->pgm.s.StatGCTrap0eUnhandled);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* present, but not a monitored page; perhaps the guest is probing physical memory */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# endif /* PGM_WITH_PAGING(PGM_GST_TYPE) */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync#else /* PGM_GST_TYPE != PGM_TYPE_32BIT */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync AssertReleaseMsgFailed(("Shw=%d Gst=%d is not implemented!\n", PGM_GST_TYPE, PGM_SHW_TYPE));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync#endif /* PGM_GST_TYPE != PGM_TYPE_32BIT */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Emulation of the invlpg instruction.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @returns VBox status code.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param pVM VM 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 * @todo Flush page or page directory only if necessary!
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @todo Add a #define for simply invalidating the page.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsyncPGM_BTH_DECL(int, InvalidatePage)(PVM pVM, RTGCUINTPTR 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 PX86PDE pPdeDst = &pVM->pgm.s.CTXMID(p,32BitPD)->a[iPDDst];
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync const unsigned iPDDst = GCPtrPage >> SHW_PD_SHIFT; /* no mask; flat index into the 2048 entry array. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync const unsigned iPdpte = (GCPtrPage >> X86_PDPT_SHIFT);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PX86PDEPAE pPdeDst = &pVM->pgm.s.CTXMID(ap,PaePDs[0])->a[iPDDst];
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# else /* AMD64 */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync AssertReturn(pVM->pgm.s.pHCPaePML4, VERR_INTERNAL_ERROR);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync const unsigned iPml4e = (GCPtrPage >> X86_PML4_SHIFT) & X86_PML4_MASK;
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync const unsigned iPdpte = (GCPtrPage >> X86_PDPT_SHIFT) & X86_PDPT_MASK_AMD64;
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync const unsigned iPDDst = (GCPtrPage >> SHW_PD_SHIFT) & SHW_PD_MASK;
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PX86PML4E pPml4eDst = &pVM->pgm.s.pHCPaePML4->a[iPml4e];
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = PGMShwGetLongModePDPtr(pVM, GCPtrPage, &pPdptDst, &pPDDst);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync AssertMsg(rc == VERR_PAGE_DIRECTORY_PTR_NOT_PRESENT || rc == VERR_PAGE_MAP_LEVEL4_NOT_PRESENT, ("Unexpected rc=%Vrc\n", rc));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,InvalidatePageSkipped));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,InvalidatePageSkipped));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,InvalidatePageSkipped));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Get the guest PD entry and calc big page.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PX86PDPAE pPDSrc = pgmGstGetPaePDPtr(&pVM->pgm.s, GCPtrPage, &iPDSrc);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# else /* AMD64 */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PX86PDPAE pPDSrc = pgmGstGetLongModePDPtr(&pVM->pgm.s, GCPtrPage, &pPml4eSrc, &PdpeSrc, &iPDSrc);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync const bool fIsBigPage = PdeSrc.b.u1Size && (CPUMGetGuestCR4(pVM) & X86_CR4_PSE);
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 || ( VM_FF_ISSET(pVM, VM_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(&pVM->pgm.s.StatHCInvalidatePageSkipped);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# endif /* IN_RING3 */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* Fetch the pgm pool shadow descriptor. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PPGMPOOLPAGE pShwPdpt = pgmPoolGetPageByHCPhys(pVM, pPml4eDst->u & X86_PML4E_PG_MASK);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* Fetch the pgm pool shadow descriptor. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PPGMPOOLPAGE pShwPde = pgmPoolGetPageByHCPhys(pVM, pPdptDst->a[iPdpte].u & SHW_PDPE_PG_MASK);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync Assert(pPml4eDst->n.u1Present && (pPml4eDst->u & SHW_PDPT_MASK));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync RTGCPHYS GCPhysPdpt = pPml4eSrc->u & X86_PML4E_PG_MASK;
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync LogFlow(("InvalidatePage: Out-of-sync PML4E (P/GCPhys) at %VGv GCPhys=%VGp vs %VGp Pml4eSrc=%RX64 Pml4eDst=%RX64\n",
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync GCPtrPage, pShwPdpt->GCPhys, GCPhysPdpt, (uint64_t)pPml4eSrc->u, (uint64_t)pPml4eDst->u));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync pgmPoolFreeByPage(pPool, pShwPdpt, pVM->pgm.s.pHCShwAmd64CR3->idx, iPml4e);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,InvalidatePagePDNPs));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync || (!pPml4eSrc->n.u1Write && pPml4eDst->n.u1Write))
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Mark not present so we can resync the PML4E when it's used.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync LogFlow(("InvalidatePage: Out-of-sync PML4E at %VGv Pml4eSrc=%RX64 Pml4eDst=%RX64\n",
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync GCPtrPage, (uint64_t)pPml4eSrc->u, (uint64_t)pPml4eDst->u));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync pgmPoolFreeByPage(pPool, pShwPdpt, pVM->pgm.s.pHCShwAmd64CR3->idx, iPml4e);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,InvalidatePagePDOutOfSync));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Mark not present so we can set the accessed bit.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync LogFlow(("InvalidatePage: Out-of-sync PML4E (A) at %VGv Pml4eSrc=%RX64 Pml4eDst=%RX64\n",
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync GCPtrPage, (uint64_t)pPml4eSrc->u, (uint64_t)pPml4eDst->u));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync pgmPoolFreeByPage(pPool, pShwPdpt, pVM->pgm.s.pHCShwAmd64CR3->idx, iPml4e);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,InvalidatePagePDNAs));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* Check if the PDPT entry has changed. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync Assert(pPdpeDst->n.u1Present && pPdpeDst->u & SHW_PDPT_MASK);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync LogFlow(("InvalidatePage: Out-of-sync PDPE (P/GCPhys) at %VGv GCPhys=%VGp vs %VGp PdpeSrc=%RX64 PdpeDst=%RX64\n",
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync GCPtrPage, pShwPde->GCPhys, GCPhysPd, (uint64_t)PdpeSrc.u, (uint64_t)pPdpeDst->u));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync pgmPoolFreeByPage(pPool, pShwPde, pShwPdpt->idx, iPdpte);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,InvalidatePagePDNPs));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Mark not present so we can resync the PDPTE when it's used.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync LogFlow(("InvalidatePage: Out-of-sync PDPE at %VGv PdpeSrc=%RX64 PdpeDst=%RX64\n",
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync GCPtrPage, (uint64_t)PdpeSrc.u, (uint64_t)pPdpeDst->u));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync pgmPoolFreeByPage(pPool, pShwPde, pShwPdpt->idx, iPdpte);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,InvalidatePagePDOutOfSync));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Mark not present so we can set the accessed bit.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync LogFlow(("InvalidatePage: Out-of-sync PDPE (A) at %VGv PdpeSrc=%RX64 PdpeDst=%RX64\n",
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync GCPtrPage, (uint64_t)PdpeSrc.u, (uint64_t)pPdpeDst->u));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync pgmPoolFreeByPage(pPool, pShwPde, pShwPdpt->idx, iPdpte);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,InvalidatePagePDNAs));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# endif /* PGM_GST_TYPE != PGM_TYPE_AMD64 */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Deal with the Guest PDE.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Conflict - Let SyncPT deal with it to avoid duplicate code.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = PGM_BTH_NAME(SyncPT)(pVM, iPDSrc, pPDSrc, GCPtrPage);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Mark not present so we can resync the PDE when it's used.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync LogFlow(("InvalidatePage: Out-of-sync at %VGp 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 pgmPoolFree(pVM, PdeDst.u & SHW_PDE_PG_MASK, SHW_POOL_ROOT_IDX, iPDDst);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,InvalidatePagePDOutOfSync));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Mark not present so we can set the accessed bit.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync LogFlow(("InvalidatePage: Out-of-sync (A) at %VGp 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 pgmPoolFree(pVM, PdeDst.u & SHW_PDE_PG_MASK, SHW_POOL_ROOT_IDX, iPDDst);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,InvalidatePagePDNAs));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * 4KB - page.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PPGMPOOLPAGE pShwPage = pgmPoolGetPageByHCPhys(pVM, 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# if 0 /* likely cause of a major performance regression; must be SyncPageWorkerTrackDeref then */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync const unsigned iPTEDst = (GCPtrPage >> SHW_PT_SHIFT) & SHW_PT_MASK;
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PSHWPT pPT = (PSHWPT)PGMPOOL_PAGE_2_PTR(pVM, pShwPage);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* This is very unlikely with caching/monitoring enabled. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PGM_BTH_NAME(SyncPageWorkerTrackDeref)(pVM, pShwPage, pPT->a[iPTEDst].u & SHW_PTE_PG_MASK);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# else /* Syncing it here isn't 100% safe and it's probably not worth spending time syncing it. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync rc = PGM_BTH_NAME(SyncPage)(pVM, PdeSrc, GCPtrPage, 1, 0);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,InvalidatePage4KBPages));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * The page table address changed.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync LogFlow(("InvalidatePage: Out-of-sync at %VGp PdeSrc=%RX64 PdeDst=%RX64 ShwGCPhys=%VGp 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 pgmPoolFree(pVM, PdeDst.u & SHW_PDE_PG_MASK, SHW_POOL_ROOT_IDX, iPDDst);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,InvalidatePagePDOutOfSync));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * 2/4MB - page.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* Before freeing the page, check if anything really changed. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PPGMPOOLPAGE pShwPage = pgmPoolGetPageByHCPhys(pVM, 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 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 PAT */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync if ( (PdeSrc.u & (X86_PDE_P | X86_PDE_RW | X86_PDE_US | X86_PDE_PWT | X86_PDE_PCD))
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync == (PdeDst.u & (X86_PDE_P | X86_PDE_RW | X86_PDE_US | X86_PDE_PWT | X86_PDE_PCD))
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 %VGv (PD=%X .u=%VX64)-> nothing has changed!\n", GCPtrPage, iPDSrc, PdeSrc.u));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(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 %VGp 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);
ac2f474cb351240b8a8e5e2049b0b7badb99fffavboxsync pgmPoolFree(pVM, PdeDst.u & SHW_PDE_PG_MASK, SHW_POOL_ROOT_IDX, iPDDst);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(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 pgmPoolFree(pVM, PdeDst.u & SHW_PDE_PG_MASK, SHW_POOL_ROOT_IDX, iPDDst);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,InvalidatePagePDNPs));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(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 pVM The VM handle.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param pShwPage The shadow page.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param HCPhys The physical page we is being dereferenced.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsyncDECLINLINE(void) PGM_BTH_NAME(SyncPageWorkerTrackDeref)(PVM pVM, PPGMPOOLPAGE pShwPage, RTHCPHYS HCPhys)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync LogFlow(("SyncPageWorkerTrackDeref: Damn HCPhys=%VHp 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 * Find the guest address.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync for (PPGMRAMRANGE pRam = CTXALLSUFF(pVM->pgm.s.pRamRanges);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync while (iPage-- > 0)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync if (PGM_PAGE_GET_HCPHYS(&pRam->aPages[iPage]) == HCPhys)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync pgmTrackDerefGCPhys(pPool, pShwPage, &pRam->aPages[iPage]);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync AssertReleaseMsgFailed(("HCPhys=%VHp wasn't found!\n", HCPhys));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# else /* !PGMPOOL_WITH_GCPHYS_TRACKING */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# endif /* !PGMPOOL_WITH_GCPHYS_TRACKING */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Update the tracking of shadowed pages.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param pVM The VM 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)(PVM pVM, PPGMPOOLPAGE pShwPage, uint16_t u16, PPGMPAGE pPage, const unsigned iPTDst)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * We're making certain assumptions about the placement of cRef and idx.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync Assert(MM_RAM_FLAGS_CREFS_SHIFT > MM_RAM_FLAGS_IDX_SHIFT);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Just deal with the simple first time here.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync u16 = (1 << (MM_RAM_FLAGS_CREFS_SHIFT - MM_RAM_FLAGS_IDX_SHIFT)) | pShwPage->idx;
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync u16 = pgmPoolTrackPhysExtAddref(pVM, u16, pShwPage->idx);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* write back, trying to be clever... */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync Log2(("SyncPageWorkerTrackAddRef: u16=%#x pPage->HCPhys=%VHp->%VHp iPTDst=%#x\n",
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync u16, pPage->HCPhys, (pPage->HCPhys & MM_RAM_FLAGS_NO_REFS_MASK) | ((uint64_t)u16 << MM_RAM_FLAGS_CREFS_SHIFT), iPTDst));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync *((uint16_t *)&pPage->HCPhys + 3) = u16; /** @todo PAGE FLAGS */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync# endif /* PGMPOOL_WITH_GCPHYS_TRACKING */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* update statistics. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync#endif /* PGMPOOL_WITH_USER_TRACKING */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Creates a 4K shadow page for a guest page.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * For 4M pages the caller must convert the PDE4M to a PTE, this includes adjusting the
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * physical address. The PdeSrc argument only the flags are used. No page structured
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * will be mapped in this function.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param pVM VM handle.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param pPteDst Destination page table entry.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param PdeSrc Source page directory entry (i.e. Guest OS page directory entry).
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Can safely assume that only the flags are being used.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param PteSrc Source page table entry (i.e. Guest OS page table entry).
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param pShwPage Pointer to the shadow page.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param iPTDst The index into the shadow table.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @remark Not used for 2/4MB pages!
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsyncDECLINLINE(void) PGM_BTH_NAME(SyncPageWorker)(PVM pVM, PSHWPTE pPteDst, GSTPDE PdeSrc, GSTPTE PteSrc, PPGMPOOLPAGE pShwPage, unsigned iPTDst)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Find the ram range.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync int rc = pgmPhysGetPageEx(&pVM->pgm.s, PteSrc.u & GST_PTE_PG_MASK, &pPage);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /** @todo investiage PWT, PCD and PAT. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Make page table entry.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync const RTHCPHYS HCPhys = pPage->HCPhys; /** @todo FLAGS */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /** @todo r=bird: Are we actually handling dirty and access bits for pages with access handlers correctly? No. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PteDst.u = (PteSrc.u & ~(X86_PTE_PAE_PG_MASK | X86_PTE_AVL_MASK | X86_PTE_PAT | X86_PTE_PCD | X86_PTE_PWT | X86_PTE_RW))
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync LogFlow(("SyncPageWorker: monitored page (%VGp) -> mark not present\n", HCPhys));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /** @todo count these two kinds. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * If the page or page directory entry is not marked accessed,
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * we mark the page not present.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync LogFlow(("SyncPageWorker: page and or page directory not accessed -> mark not present\n"));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,AccessedPage));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * If the page is not flagged as dirty and is writable, then make it read-only, so we can set the dirty bit
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * when the page is modified.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync if (!PteSrc.n.u1Dirty && (PdeSrc.n.u1Write & PteSrc.n.u1Write))
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,DirtyPage));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PteDst.u = (PteSrc.u & ~(X86_PTE_PAE_PG_MASK | X86_PTE_AVL_MASK | X86_PTE_PAT | X86_PTE_PCD | X86_PTE_PWT | X86_PTE_RW))
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,DirtyPageSkipped));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PteDst.u = (PteSrc.u & ~(X86_PTE_PAE_PG_MASK | X86_PTE_AVL_MASK | X86_PTE_PAT | X86_PTE_PCD | X86_PTE_PWT))
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Keep user track up to date.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PGM_BTH_NAME(SyncPageWorkerTrackAddref)(pVM, pShwPage, HCPhys >> MM_RAM_FLAGS_IDX_SHIFT, pPage, iPTDst);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync else if ((pPteDst->u & SHW_PTE_PG_MASK) != (PteDst.u & SHW_PTE_PG_MASK))
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync Log2(("SyncPageWorker: deref! *pPteDst=%RX64 PteDst=%RX64\n", (uint64_t)pPteDst->u, (uint64_t)PteDst.u));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PGM_BTH_NAME(SyncPageWorkerTrackDeref)(pVM, pShwPage, pPteDst->u & SHW_PTE_PG_MASK);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PGM_BTH_NAME(SyncPageWorkerTrackAddref)(pVM, pShwPage, HCPhys >> MM_RAM_FLAGS_IDX_SHIFT, pPage, iPTDst);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync Log2(("SyncPageWorker: deref! *pPteDst=%RX64\n", (uint64_t)pPteDst->u));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PGM_BTH_NAME(SyncPageWorkerTrackDeref)(pVM, pShwPage, pPteDst->u & SHW_PTE_PG_MASK);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync#endif /* PGMPOOL_WITH_USER_TRACKING */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Update statistics and commit the entry.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* else MMIO or invalid page, we must handle them manually in the #PF handler. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /** @todo count these. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Page not-present.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync LogFlow(("SyncPageWorker: page not present in Pte\n"));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /* Keep user track up to date. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync Log2(("SyncPageWorker: deref! *pPteDst=%RX64\n", (uint64_t)pPteDst->u));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync PGM_BTH_NAME(SyncPageWorkerTrackDeref)(pVM, pShwPage, pPteDst->u & SHW_PTE_PG_MASK);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync#endif /* PGMPOOL_WITH_USER_TRACKING */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync /** @todo count these. */
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Syncs a guest OS page.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * There are no conflicts at this point, neither is there any need for
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * page table allocations.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @returns VBox status code.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @returns VINF_PGM_SYNCPAGE_MODIFIED_PDE if it modifies the PDE in any way.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param pVM VM handle.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param PdeSrc Page directory entry of the guest.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param GCPtrPage Guest context page address.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param cPages Number of pages to sync (PGM_SYNC_N_PAGES) (default=1).
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * @param uErr Fault error (X86_TRAP_PF_*).
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsyncPGM_BTH_DECL(int, SyncPage)(PVM pVM, GSTPDE PdeSrc, RTGCUINTPTR GCPtrPage, unsigned cPages, unsigned uErr)
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync LogFlow(("SyncPage: GCPtrPage=%VGv cPages=%d uErr=%#x\n", GCPtrPage, cPages, uErr));
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync bool fNoExecuteBitValid = !!(CPUMGetGuestEFER(pVM) & MSR_K6_EFER_NXE);
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync * Assert preconditions.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync STAM_COUNTER_INC(&pVM->pgm.s.StatGCSyncPagePD[(GCPtrPage >> GST_PD_SHIFT) & GST_PD_MASK]);
ac2f474cb351240b8a8e5e2049b0b7badb99fffavboxsync * Get the shadow PDE, find the shadow page table in the pool.
4d70901ea82628b9ad4f093d47bb048b8bbd207evboxsync X86PDE PdeDst = pVM->pgm.s.CTXMID(p,32BitPD)->a[iPDDst];
const unsigned iPdpte = (GCPtrPage >> X86_PDPT_SHIFT); /* no mask; flat index into the 2048 entry array. */
if (!fBigPage)
if (!fBigPage)
# ifdef PGM_SYNC_N_PAGES
const unsigned offPTSrc = 0;
iPTDst = 0;
RTGCUINTPTR GCPtrCurPage = ((RTGCUINTPTR)GCPtrPage & ~(RTGCUINTPTR)(GST_PT_MASK << GST_PT_SHIFT)) | ((offPTSrc + iPTDst) << PAGE_SHIFT);
#ifndef IN_RING0
RTGCPHYS GCPhys = (PdeSrc.u & GST_PDE_BIG_PG_MASK) | ((RTGCUINTPTR)GCPtrPage & GST_BIG_PAGE_OFFSET_MASK);
PteDst.u = (PdeSrc.u & ~(X86_PTE_PAE_PG_MASK | X86_PTE_AVL_MASK | X86_PTE_PAT | X86_PTE_PCD | X86_PTE_PWT))
PteDst.u = 0;
# ifdef PGMPOOL_WITH_USER_TRACKING
PGM_BTH_NAME(SyncPageWorkerTrackAddref)(pVM, pShwPage, HCPhys >> MM_RAM_FLAGS_IDX_SHIFT, pPage, iPTDst);
return VINF_SUCCESS;
return VINF_PGM_SYNCPAGE_MODIFIED_PDE;
# ifdef PGM_SYNC_N_PAGES
const unsigned iPDDst = GCPtrPage >> SHW_PD_SHIFT; /* no mask; flat index into the 2048 entry array. */
iPTDst = 0;
RTGCUINTPTR GCPtrCurPage = ((RTGCUINTPTR)GCPtrPage & ~(RTGCUINTPTR)(SHW_PT_MASK << SHW_PT_SHIFT)) | (iPTDst << PAGE_SHIFT);
Log4(("%VGv iPTDst=%x pPTDst->a[iPTDst] %RX64\n", ((RTGCUINTPTR)GCPtrPage & ~(RTGCUINTPTR)(SHW_PT_MASK << SHW_PT_SHIFT)) | (iPTDst << PAGE_SHIFT), iPTDst, pPTDst->a[iPTDst].u));
RTGCUINTPTR GCPtrCurPage = ((RTGCUINTPTR)GCPtrPage & ~(RTGCUINTPTR)(SHW_PT_MASK << SHW_PT_SHIFT)) | (iPTDst << PAGE_SHIFT);
return VINF_SUCCESS;
return VERR_INTERNAL_ERROR;
PGM_BTH_DECL(int, CheckPageFault)(PVM pVM, uint32_t uErr, PSHWPDE pPdeDst, PGSTPDE pPdeSrc, RTGCUINTPTR GCPtrPage)
bool fBigPagesSupported = true;
unsigned uPageFaultLevel;
int rc;
uPageFaultLevel = 0;
goto UpperLevelPageFault;
PX86PDPE pPdpeSrc = &pVM->pgm.s.CTXSUFF(pGstPaePDPT)->a[(GCPtrPage >> GST_PDPT_SHIFT) & GST_PDPT_MASK];
goto UpperLevelPageFault;
goto UpperLevelPageFault;
if (fWriteFault)
return VINF_PGM_HANDLED_DIRTY_BIT_FAULT;
return VINF_PGM_NO_DIRTY_BIT_TRACKING;
# ifdef IN_GC
return VINF_EM_RAW_GUEST_TRAP;
if (fWriteFault)
return VINF_SUCCESS;
if (pShwPage)
# ifdef VBOX_STRICT
if (pPage)
("Unexpected dirty bit tracking on monitored page %VGv (phys %VGp)!!!!!!\n", GCPtrPage, pPteSrc->u & X86_PTE_PAE_PG_MASK));
return VINF_PGM_HANDLED_DIRTY_BIT_FAULT;
# ifdef VBOX_STRICT
return VINF_PGM_NO_DIRTY_BIT_TRACKING;
return rc;
# ifdef IN_GC
/* Check the present bit as the shadow tables can cause different error codes by being out of sync. */
return VINF_EM_RAW_GUEST_TRAP;
AssertMsg(iPDSrc == ((GCPtrPage >> GST_PD_SHIFT) & GST_PD_MASK), ("iPDSrc=%x GCPtrPage=%VGv\n", iPDSrc, GCPtrPage));
const unsigned iPDDst = GCPtrPage >> SHW_PD_SHIFT; /* no mask; flat index into the 2048 entry array. */
return rc;
# ifndef PGM_WITHOUT_MAPPINGS
# ifndef IN_RING3
return VERR_ADDRESS_CONFLICT;
int rc = pgmR3SyncPTResolveConflict(pVM, pMapping, pPDSrc, GCPtrPage & (GST_PD_MASK << GST_PD_SHIFT));
return rc;
if (fPageTable)
if (fPageTable)
| (PdeSrc.u & ~(GST_PDE_PG_MASK | X86_PDE_AVL_MASK | X86_PDE_PCD | X86_PDE_PWT | X86_PDE_PS | X86_PDE4M_G | X86_PDE4M_D));
| (PdeSrc.u & ~(GST_PDE_PG_MASK | X86_PDE_AVL_MASK | X86_PDE_PCD | X86_PDE_PWT | X86_PDE_PS | X86_PDE4M_G | X86_PDE4M_D));
return VINF_SUCCESS;
return VINF_PGM_SYNC_CR3;
if (fPageTable)
| (PdeSrc.u & ~(GST_PDE_PG_MASK | X86_PDE_AVL_MASK | X86_PDE_PCD | X86_PDE_PWT | X86_PDE_PS | X86_PDE4M_G | X86_PDE4M_D));
# ifdef PGM_SYNC_N_PAGES
iPTDst = 0;
unsigned iPTDst = 0;
const unsigned offPTSrc = 0;
# ifndef IN_RING0
Log2(("SyncPT: 4K+ %VGv PteSrc:{P=%d RW=%d U=%d raw=%08llx}%s dst.raw=%08llx iPTSrc=%x PdeSrc.u=%x physpte=%VGp\n",
pPTDst->a[iPTDst].u & PGM_PTFLAGS_TRACK_DIRTY ? " Track-Dirty" : "", pPTDst->a[iPTDst].u, iPTSrc, PdeSrc.au32[0],
* @todo It might be more efficient to sync only a part of the 4MB page (similar to what we do for 4kb PDs).
| (PdeSrc.u & ~(GST_PDE_PG_MASK | X86_PDE_AVL_MASK | X86_PDE_PCD | X86_PDE_PWT | X86_PDE_PS | X86_PDE4M_G | X86_PDE4M_D));
PteDstBase.u = PdeSrc.u & ~(GST_PDE_PG_MASK | X86_PTE_AVL_MASK | X86_PTE_PAT | X86_PTE_PCD | X86_PTE_PWT);
unsigned iPTDst = 0;
# ifdef IN_RING3
return rc;
PteDst.u = 0;
# ifndef IN_RING0
PteDst.u = 0;
# ifdef PGMPOOL_WITH_USER_TRACKING
PGM_BTH_NAME(SyncPageWorkerTrackAddref)(pVM, pShwPage, pPage->HCPhys >> MM_RAM_FLAGS_IDX_SHIFT, pPage, iPTDst); /** @todo PAGE FLAGS */
(RTGCPTR)(GCPtr | (iPTDst << SHW_PT_SHIFT)), PteDst.n.u1Present, PteDst.n.u1Write, PteDst.n.u1User, (uint64_t)PteDst.u,
iHCPage++;
iPTDst++;
else if (pRam)
iPTDst++;
# ifdef IN_GC
return rc;
const unsigned iPDDst = GCPtrPage >> SHW_PD_SHIFT; /* no mask; flat index into the 2048 entry array. */
return rc;
rc = pgmPoolAlloc(pVM, GCPhys & ~(RT_BIT_64(SHW_PD_SHIFT) - 1), BTH_PGMPOOLKIND_PT_FOR_PT, pShwPde->idx, iPDDst, &pShwPage);
rc = pgmPoolAlloc(pVM, GCPhys & ~(RT_BIT_64(SHW_PD_SHIFT) - 1), BTH_PGMPOOLKIND_PT_FOR_PT, SHW_POOL_ROOT_IDX, iPDDst, &pShwPage);
rc = PGM_BTH_NAME(SyncPage)(pVM, PdeSrc, (RTGCUINTPTR)GCPtrPage, PGM_SYNC_NR_PAGES, 0 /* page not present */);
return rc;
return VERR_INTERNAL_ERROR;
#if (PGM_GST_TYPE == PGM_TYPE_32BIT || PGM_GST_TYPE == PGM_TYPE_REAL || PGM_GST_TYPE == PGM_TYPE_PROT || PGM_GST_TYPE == PGM_TYPE_PAE || PGM_GST_TYPE == PGM_TYPE_AMD64) \
unsigned iPDSrc;
if (!pPDSrc)
unsigned iPDSrc;
if (!pPDSrc)
const unsigned iPDSrc = 0;
return rc;
return rc;
PGM_BTH_DECL(int, VerifyAccessSyncPage)(PVM pVM, RTGCUINTPTR GCPtrPage, unsigned fPage, unsigned uErr)
#if (PGM_GST_TYPE == PGM_TYPE_32BIT || PGM_GST_TYPE == PGM_TYPE_REAL || PGM_GST_TYPE == PGM_TYPE_PROT || PGM_GST_TYPE == PGM_TYPE_PAE || PGM_TYPE_AMD64) \
# ifndef IN_RING0
unsigned iPDSrc;
if (pPDSrc)
return VINF_EM_RAW_GUEST_TRAP;
unsigned iPDSrc;
if (!pPDSrc)
return VINF_EM_RAW_GUEST_TRAP;
const unsigned iPDSrc = 0;
return rc;
return rc;
return VINF_EM_RAW_GUEST_TRAP;
return rc;
return VERR_INTERNAL_ERROR;
#if PGM_GST_TYPE == PGM_TYPE_32BIT || PGM_GST_TYPE == PGM_TYPE_PAE || PGM_GST_TYPE == PGM_TYPE_AMD64
# if PGM_SHW_TYPE == PGM_TYPE_32BIT || PGM_SHW_TYPE == PGM_TYPE_PAE || PGM_SHW_TYPE == PGM_TYPE_AMD64
return BTH_PGMPOOLKIND_PT_FOR_PT;
return BTH_PGMPOOLKIND_PT_FOR_BIG;
#define MY_STAM_COUNTER_INC(a) do { } while (0)
#ifdef PGMPOOL_WITH_MONITORING
return rc;
return VINF_SUCCESS;
/* No need to check all paging levels; we zero out the shadow parts when the guest modifies its tables. */
return VINF_SUCCESS;
MY_STAM_COUNTER_INC(fGlobal ? &pVM->pgm.s.CTXMID(Stat,SyncCR3Global) : &pVM->pgm.s.CTXMID(Stat,SyncCR3NotGlobal));
# if PGM_GST_TYPE == PGM_TYPE_32BIT || PGM_GST_TYPE == PGM_TYPE_PAE || PGM_GST_TYPE == PGM_TYPE_AMD64
bool fBigPagesSupported = true;
# ifndef IN_GC
unsigned iPdNoMapping;
pMapping = 0;
iPdNoMapping = ~0U;
LogFlow(("SyncCR3: Out-of-sync PML4E (GCPhys) GCPtr=%VGv %VGp vs %VGp PdpeSrc=%RX64 PdpeDst=%RX64\n",
(uint64_t)iPml4e << X86_PML4_SHIFT, pShwPdpt->GCPhys, GCPhysPdptSrc, (uint64_t)pPml4eSrc->u, (uint64_t)pPml4eDst->u));
pPml4eDst->u = 0;
unsigned iPDSrc;
pgmPoolFreeByPage(pPool, pgmPoolGetPage(pPool, pPDEDst[iPD].u & SHW_PDE_PG_MASK), SHW_POOL_ROOT_IDX, iPdpte * X86_PG_PAE_ENTRIES + iPD);
LogFlow(("SyncCR3: Out-of-sync PDPE (GCPhys) GCPtr=%VGv %VGp vs %VGp PdpeSrc=%RX64 PdpeDst=%RX64\n",
((uint64_t)iPml4e << X86_PML4_SHIFT) + ((uint64_t)iPdpte << X86_PDPT_SHIFT), pShwPde->GCPhys, GCPhysPdeSrc, (uint64_t)PdpeSrc.u, (uint64_t)pPdpeDst->u));
/* Mark it as not present if there's no hypervisor mapping present. (bit flipped at the top of Trap0eHandler) */
pPdpeDst->u = 0;
AssertMsg(&pVM->pgm.s.CTXMID(ap,PaePDs)[iPD * 2 / 512]->a[iPD * 2 % 512] == pPDEDst, ("%p vs %p\n", &pVM->pgm.s.CTXMID(ap,PaePDs)[iPD * 2 / 512]->a[iPD * 2 % 512], pPDEDst));
&& !defined(PGM_WITHOUT_MAPPINGS)
pPDEDst += cPTs + (PGM_GST_TYPE != PGM_SHW_TYPE) * cPTs; /* Only applies to the pae shadow and 32 bits guest case */
# ifdef IN_RING3
int rc = pgmR3SyncPTResolveConflictPAE(pVM, pMapping, (iPdpte << GST_PDPT_SHIFT) + (iPD << GST_PD_SHIFT));
return rc;
return VINF_PGM_SYNC_CR3;
# else /* (PGM_GST_TYPE != PGM_TYPE_32BIT && PGM_GST_TYPE != PGM_TYPE_PAE) || PGM_WITHOUT_MAPPINGS */
# endif /* (PGM_GST_TYPE != PGM_TYPE_32BIT && PGM_GST_TYPE != PGM_TYPE_PAE) || PGM_WITHOUT_MAPPINGS */
for (unsigned i = 0, iPdShw = iPD * 2; i < 2; i++, iPdShw++) /* pray that the compiler unrolls this */
|| !fBigPagesSupported)
|| ( !fGlobal
|| ( fBigPagesSupported
# ifdef VBOX_WITH_STATISTICS
if ( !fGlobal
/** @todo a replacement strategy isn't really needed unless we're using a very small pool < 512 pages.
* The whole ageing stuff should be put in yet another set of #ifdefs. For now, let's just skip it. */
pPDEDst->u = 0;
pPDEDst++;
for (unsigned i = 0, iPdShw = iPD * 2; i < 2; i++, iPdShw++) /* pray that the compiler unrolls this */
pgmPoolFreeByPage(pPool, pgmPoolGetPage(pPool, pPDEDst->u & SHW_PDE_PG_MASK), pShwPde->idx, iPdShw);
pgmPoolFreeByPage(pPool, pgmPoolGetPage(pPool, pPDEDst->u & SHW_PDE_PG_MASK), SHW_POOL_ROOT_IDX, iPdShw);
pPDEDst->u = 0;
pPDEDst++;
&& !defined(PGM_WITHOUT_MAPPINGS)
iPdNoMapping = ~0U;
# ifdef IN_RING3
int rc = pgmR3SyncPTResolveConflictPAE(pVM, pMapping, (iPdpte << GST_PDPT_SHIFT) + (iPD << GST_PD_SHIFT));
return rc;
return VINF_PGM_SYNC_CR3;
if (pMapping)
pPDEDst += cPTs + (PGM_GST_TYPE != PGM_SHW_TYPE) * cPTs; /* Only applies to the pae shadow and 32 bits guest case */
# else /* (PGM_GST_TYPE != PGM_TYPE_32BIT && PGM_GST_TYPE != PGM_TYPE_PAE) || PGM_WITHOUT_MAPPINGS */
# endif /* (PGM_GST_TYPE != PGM_TYPE_32BIT && PGM_GST_TYPE != PGM_TYPE_PAE) || PGM_WITHOUT_MAPPINGS */
return VINF_SUCCESS;
return VINF_SUCCESS;
#ifdef VBOX_STRICT
#ifdef IN_GC
#ifdef IN_RING3
PGMR3DECL(int) PGMR3DumpHierarchyHC(PVM pVM, uint32_t cr3, uint32_t cr4, bool fLongMode, unsigned cMaxDepth, PCDBGFINFOHLP pHlp);
PGM_BTH_DECL(unsigned, AssertCR3)(PVM pVM, uint64_t cr3, uint64_t cr4, RTGCUINTPTR GCPtr, RTGCUINTPTR cb)
unsigned cErrors = 0;
AssertFailed();
bool fBigPagesSupported = true;
# ifndef IN_RING0
int rc;
# ifndef IN_RING0
AssertMsgReturn(HCPhys == HCPhysShw, ("HCPhys=%VHp HCPhyswShw=%VHp (cr3)\n", HCPhys, HCPhysShw), false);
AssertMsgReturn((cr3 & GST_CR3_PAGE_MASK) == GCPhys, ("GCPhys=%VGp cr3=%VGp\n", GCPhys, (RTGCPHYS)cr3), false);
AssertFailed();
AssertMsgFailed(("Present bit doesn't match! pPml4eDst.u=%#RX64 pPml4eSrc.u=%RX64\n", pPml4eDst->u, pPml4eSrc->u));
cErrors++;
AssertMsgFailed(("Physical address doesn't match! iPml4e %d pPml4eDst.u=%#RX64 pPml4eSrc.u=%RX64 Phys %RX64 vs %RX64\n", iPml4e, 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++;
unsigned iPDSrc;
AssertMsgFailed(("Present bit doesn't match! pPdpeDst.u=%#RX64 pPdpeSrc.u=%RX64\n", pPdpeDst->u, PdpeSrc.u));
cErrors++;
AssertMsgFailed(("Physical address doesn't match! iPml4e %d iPdpte %d pPdpeDst.u=%#RX64 pPdpeSrc.u=%RX64 Phys %RX64 vs %RX64\n", iPml4e, iPdpte, pPdpeDst->u, PdpeSrc.u, pShwPde->GCPhys, GCPhysPdeSrc));
AssertMsgFailed(("Physical address doesn't match! iPdpte %d pPdpeDst.u=%#RX64 pPdpeSrc.u=%RX64 Phys %RX64 vs %RX64\n", iPdpte, 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++;
const PX86PDPAE pPDDst = pVM->pgm.s.CTXMID(ap,PaePDs)[0]; /* We treat this as a PD with 2048 entries, so no need to and with SHW_PD_MASK to get iPDDst */
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 %VGv! 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 %VGp in the PDE at %VGv! 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 (!(PteDst.u & (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 %VGv! PteSrc=%#RX64 PteDst=%#RX64 pPTSrc=%VGv iPTSrc=%x PdeSrc=%x physpte=%VGp\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 %VGv! HCPhysShw=%VHp HCPhys=%VHp GCPhysGst=%VGp PteSrc=%#RX64 PteDst=%#RX64\n",
cErrors++;
if (!pPhysPage)
cErrors++;
AssertMsgFailed(("Invalid guest page at %VGv is writable! GCPhysGst=%VGp PteSrc=%#RX64 PteDst=%#RX64\n",
cErrors++;
AssertMsgFailed(("Out of sync (phys) at %VGv! HCPhysShw=%VHp HCPhys=%VHp GCPhysGst=%VGp PteSrc=%#RX64 PteDst=%#RX64\n",
cErrors++;
AssertMsgFailed(("WRITE access flagged at %VGv but the page is writable! HCPhys=%VGv PteSrc=%#RX64 PteDst=%#RX64\n",
cErrors++;
AssertMsgFailed(("ALL access flagged at %VGv but the page is present! HCPhys=%VHp PteSrc=%#RX64 PteDst=%#RX64\n",
cErrors++;
cErrors++;
cErrors++;
cErrors++;
AssertMsgFailed(("!DIRTY page at %VGv is has mismatching accessed bit! PteSrc=%#RX64 PteDst=%#RX64\n",
cErrors++;
AssertMsgFailed(("PGM_PTFLAGS_TRACK_DIRTY set at %VGv but no accessed bit emulation! PteSrc=%#RX64 PteDst=%#RX64\n",
cErrors++;
AssertMsgFailed(("!ACCESSED page at %VGv is has the accessed bit set! PteSrc=%#RX64 PteDst=%#RX64\n",
cErrors++;
# ifdef DEBUG_sandervl
AssertMsgFailed(("Flags mismatch at %VGv! %#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 %VGv is has mismatching accessed bit! PteSrc=%#RX64 PteDst=%#RX64\n",
cErrors++;
AssertMsgFailed(("PGM_PDFLAGS_TRACK_DIRTY set at %VGv but no accessed bit emulation! PdeSrc=%#RX64 PdeDst=%#RX64\n",
cErrors++;
AssertMsgFailed(("!ACCESSED page at %VGv is has the accessed bit set! PdeSrc=%#RX64 PdeDst=%#RX64\n",
cErrors++;
AssertMsgFailed(("Flags mismatch (B) at %VGv! %#RX64 != %#RX64 fIgnoreFlags=%#RX64 PdeSrc=%#RX64 PdeDst=%#RX64\n",
cErrors++;
AssertMsgFailed(("The PTE at %VGv 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 %VGv! HCPhysShw=%VHp HCPhys=%VHp GCPhysGst=%VGp PdeSrc=%#RX64 PteDst=%#RX64\n",
cErrors++;
if (!pPhysPage)
cErrors++;
AssertMsgFailed(("Invalid guest page at %VGv is writable! GCPhysGst=%VGp PdeSrc=%#RX64 PteDst=%#RX64\n",
cErrors++;
AssertMsgFailed(("Out of sync (phys) at %VGv! HCPhysShw=%VHp HCPhys=%VHp GCPhysGst=%VGp PdeSrc=%#RX64 PteDst=%#RX64\n",
cErrors++;
AssertMsgFailed(("WRITE access flagged at %VGv but the page is writable! HCPhys=%VGv PdeSrc=%#RX64 PteDst=%#RX64\n",
cErrors++;
AssertMsgFailed(("ALL access flagged at %VGv but the page is present! HCPhys=%VGv PdeSrc=%#RX64 PteDst=%#RX64\n",
cErrors++;
&& (PdeSrc.u & ~(fIgnoreFlags | X86_PTE_RW)) != (PteDst.u & ~fIgnoreFlags) /* lazy phys handler dereg. */
AssertMsgFailed(("Flags mismatch (BT) at %VGv! %#RX64 != %#RX64 fIgnoreFlags=%#RX64 PdeSrc=%#RX64 PteDst=%#RX64\n",
cErrors++;
# ifdef DEBUG
if (cErrors)
return cErrors;