Index: /trunk/include/VBox/err.h
===================================================================
--- /trunk/include/VBox/err.h	(revision 104931)
+++ /trunk/include/VBox/err.h	(revision 104932)
@@ -110,4 +110,6 @@
 /** The requested feature is not supported by NEM. */
 #define VERR_NOT_SUP_BY_NEM                 (-1026)
+/** Reserved page table bits set. */
+#define VERR_RESERVED_PAGE_TABLE_BITS       (-1027)
 /** @} */
 
Index: /trunk/include/VBox/vmm/pgm.h
===================================================================
--- /trunk/include/VBox/vmm/pgm.h	(revision 104931)
+++ /trunk/include/VBox/vmm/pgm.h	(revision 104932)
@@ -316,21 +316,43 @@
  */
 typedef uint32_t PGMWALKFAIL;
-/** Regular page fault (MBZ since guest Walk code don't set these explicitly). */
-#define PGM_WALKFAIL_PAGE_FAULT                     UINT32_C(0)
+/** No fault. */
+#define PGM_WALKFAIL_SUCCESS                        UINT32_C(0)
+
+/** Not present (X86_TRAP_PF_P). */
+#define PGM_WALKFAIL_NOT_PRESENT                    RT_BIT_32(0)
+/** Reserved bit set in table entry (X86_TRAP_PF_RSVD). */
+#define PGM_WALKFAIL_RESERVED_BITS                  RT_BIT_32(1)
+/** Bad physical address (VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS). */
+#define PGM_WALKFAIL_BAD_PHYSICAL_ADDRESS           RT_BIT_32(2)
+
 /** EPT violation - Intel. */
-#define PGM_WALKFAIL_EPT_VIOLATION                  RT_BIT_32(0)
+#define PGM_WALKFAIL_EPT_VIOLATION                  RT_BIT_32(3)
 /** EPT violation, convertible to \#VE exception - Intel. */
-#define PGM_WALKFAIL_EPT_VIOLATION_CONVERTIBLE      RT_BIT_32(1)
+#define PGM_WALKFAIL_EPT_VIOLATION_CONVERTIBLE      RT_BIT_32(4)
 /** EPT misconfiguration - Intel. */
-#define PGM_WALKFAIL_EPT_MISCONFIG                  RT_BIT_32(2)
-
+#define PGM_WALKFAIL_EPT_MISCONFIG                  RT_BIT_32(5)
 /** Mask of all EPT induced page-walk failures - Intel. */
 #define PGM_WALKFAIL_EPT                            (  PGM_WALKFAIL_EPT_VIOLATION \
                                                      | PGM_WALKFAIL_EPT_VIOLATION_CONVERTIBLE \
                                                      | PGM_WALKFAIL_EPT_MISCONFIG)
+
+/** Access denied: Not writable (VERR_ACCESS_DENIED). */
+#define PGM_WALKFAIL_NOT_WRITABLE                   RT_BIT_32(6)
+/** Access denied: Not executable (VERR_ACCESS_DENIED). */
+#define PGM_WALKFAIL_NOT_EXECUTABLE                 RT_BIT_32(7)
+/** Access denied: Not user/supervisor mode accessible (VERR_ACCESS_DENIED). */
+#define PGM_WALKFAIL_NOT_ACCESSIBLE_BY_MODE         RT_BIT_32(8)
+
+/** The level the problem arrised at.
+ * PTE is level 1, PDE is level 2, PDPE is level 3, PML4 is level 4, CR3 is
+ * level 8.  This is 0 on success. */
+#define PGM_WALKFAIL_LEVEL_MASK                     UINT32_C(0x0000f100)
+/** Level shift (see PGM_WALKINFO_LEVEL_MASK).   */
+#define PGM_WALKFAIL_LEVEL_SHIFT                    11
+
 /** @} */
 
 
-/** @name PGMPTATTRS - PGM page-table attributes.
+/** @name PGM_PTATTRS_XXX - PGM page-table attributes.
  *
  * This is VirtualBox's combined page table attributes. It combines regular page
@@ -578,4 +600,62 @@
 
 
+/** @name PGM_WALKINFO_XXX - flag based PGM page table walk info.
+ * @{ */
+/** Set if the walk succeeded. */
+#define PGM_WALKINFO_SUCCEEDED                  RT_BIT_32(0)
+/** Whether this is a second-level address translation. */
+#define PGM_WALKINFO_IS_SLAT                    RT_BIT_32(1)
+/** Set if it involves a big page (2/4 MB). */
+#define PGM_WALKINFO_BIG_PAGE                   RT_BIT_32(2)
+/** Set if it involves a gigantic page (1 GB). */
+#define PGM_WALKINFO_GIGANTIC_PAGE              RT_BIT_32(3)
+
+/** Whether the linear address (GCPtr) caused the second-level
+ * address translation - read the code to figure this one.
+ * @todo for PGMPTWALKFAST::fFailed?  */
+#define PGM_WALKINFO_IS_LINEAR_ADDR_VALID       RT_BIT_32(7)
+/** @} */
+
+/**
+ * Fast page table walk information.
+ *
+ * This is a slimmed down version of PGMPTWALK for use by IEM.
+ */
+typedef struct PGMPTWALKFAST
+{
+    /** The linear address that is being resolved (input). */
+    RTGCPTR         GCPtr;
+
+    /** The physical address that is the result of the walk (output).
+     * This includes the offset mask from the GCPtr input value.  */
+    RTGCPHYS        GCPhys;
+
+    /** The second-level physical address (input/output).
+     *  @remarks only valid if fIsSlat is set. */
+    RTGCPHYS        GCPhysNested;
+
+    /** Walk information PGM_WALKINFO_XXX (output). */
+    uint32_t        fInfo;
+    /** Page-walk failure type, PGM_WALKFAIL_XXX (output). */
+    PGMWALKFAIL     fFailed;
+
+    /** The effective page-table attributes, PGM_PTATTRS_XXX (output). */
+    PGMPTATTRS      fEffective;
+} PGMPTWALKFAST;
+/** Pointer to fast page walk information. */
+typedef PGMPTWALKFAST *PPGMPTWALKFAST;
+/** Pointer to const fast page walk information. */
+typedef PGMPTWALKFAST const *PCPGMPTWALKFAST;
+
+#define PGMPTWALKFAST_ZERO(a_pWalkFast) do { \
+        (a_pWalkFast)->GCPtr        = 0; \
+        (a_pWalkFast)->GCPhys       = 0; \
+        (a_pWalkFast)->GCPhysNested = 0; \
+        (a_pWalkFast)->fInfo        = 0; \
+        (a_pWalkFast)->fFailed      = 0; \
+        (a_pWalkFast)->fEffective   = 0; \
+    } while (0)
+
+
 /** Macro for checking if the guest is using paging.
  * @param enmMode   PGMMODE_*.
@@ -635,4 +715,24 @@
 /** @}*/
 VMMDECL(int)        PGMGstGetPage(PVMCPUCC pVCpu, RTGCPTR GCPtr, PPGMPTWALK pWalk);
+/** @name PGMQPAGE_F_XXX - Flags for PGMGstQueryPageFast
+ * @{ */
+/** Querying for read access, set A bits accordingly. */
+#define PGMQPAGE_F_READ         RT_BIT_32(0)
+/** Querying for write access, set A bits and D bit accordingly.
+ * Don't set leaf entry bits if is read-only.  */
+#define PGMQPAGE_F_WRITE        RT_BIT_32(1)
+/** Querying for execute access, set A bits accordingly. */
+#define PGMQPAGE_F_EXECUTE      RT_BIT_32(2)
+/** The query is for a user mode access, so don't set leaf A or D bits
+ * unless the effective access allows usermode access.
+ * Assume supervisor access when not set. */
+#define PGMQPAGE_F_USER_MODE    RT_BIT_32(3)
+/** Treat CR0.WP as zero when evalutating the access.
+ * @note Same value as X86_CR0_WP.  */
+#define PGMQPAGE_F_CR0_WP0      RT_BIT_32(16)
+/** The valid flag mask.   */
+#define PGMQPAGE_F_VALID_MASK   UINT32_C(0x0001000f)
+/** @} */
+VMM_INT_DECL(int)   PGMGstQueryPageFast(PVMCPUCC pVCpu, RTGCPTR GCPtr, uint32_t fFlags, PPGMPTWALKFAST pWalkFast);
 VMMDECL(int)        PGMGstModifyPage(PVMCPUCC pVCpu, RTGCPTR GCPtr, size_t cb, uint64_t fFlags, uint64_t fMask);
 VMM_INT_DECL(bool)  PGMGstArePaePdpesValid(PVMCPUCC pVCpu, PCX86PDPE paPaePdpes);
Index: /trunk/src/VBox/VMM/VMMAll/IEMAll.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/IEMAll.cpp	(revision 104931)
+++ /trunk/src/VBox/VMM/VMMAll/IEMAll.cpp	(revision 104932)
@@ -511,38 +511,51 @@
     }
 
-    PGMPTWALK Walk;
-    int rc = PGMGstGetPage(pVCpu, GCPtrPC, &Walk);
+    PGMPTWALKFAST WalkFast;
+    int rc = PGMGstQueryPageFast(pVCpu, GCPtrPC,
+                                 IEM_GET_CPL(pVCpu) == 3 ? PGMQPAGE_F_EXECUTE | PGMQPAGE_F_USER_MODE : PGMQPAGE_F_EXECUTE,
+                                 &WalkFast);
     if (RT_SUCCESS(rc))
-        Assert(Walk.fSucceeded); /* probable. */
+        Assert(WalkFast.fInfo & PGM_WALKINFO_SUCCEEDED);
     else
     {
         Log(("iemInitDecoderAndPrefetchOpcodes: %RGv - rc=%Rrc\n", GCPtrPC, rc));
 # ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
-        if (Walk.fFailed & PGM_WALKFAIL_EPT)
-            IEM_VMX_VMEXIT_EPT_RET(pVCpu, &Walk, IEM_ACCESS_INSTRUCTION, IEM_SLAT_FAIL_LINEAR_TO_PHYS_ADDR, 0 /* cbInstr */);
+/** @todo This isn't quite right yet, as PGM_GST_SLAT_NAME_EPT(Walk) doesn't
+ * know about what kind of access we're making! See PGM_GST_NAME(WalkFast). */
+        if (WalkFast.fFailed & PGM_WALKFAIL_EPT)
+            IEM_VMX_VMEXIT_EPT_RET(pVCpu, &WalkFast, IEM_ACCESS_INSTRUCTION, IEM_SLAT_FAIL_LINEAR_TO_PHYS_ADDR, 0 /* cbInstr */);
 # endif
         return iemRaisePageFault(pVCpu, GCPtrPC, 1, IEM_ACCESS_INSTRUCTION, rc);
     }
-    if ((Walk.fEffective & X86_PTE_US) || IEM_GET_CPL(pVCpu) != 3) { /* likely */ }
+#if 0
+    if ((WalkFast.fEffective & X86_PTE_US) || IEM_GET_CPL(pVCpu) != 3) { /* likely */ }
     else
     {
         Log(("iemInitDecoderAndPrefetchOpcodes: %RGv - supervisor page\n", GCPtrPC));
 # ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
-        if (Walk.fFailed & PGM_WALKFAIL_EPT)
-            IEM_VMX_VMEXIT_EPT_RET(pVCpu, &Walk, IEM_ACCESS_INSTRUCTION, IEM_SLAT_FAIL_LINEAR_TO_PAGE_TABLE, 0 /* cbInstr */);
+/** @todo this is completely wrong for EPT. WalkFast.fFailed is always zero here!*/
+#  error completely wrong
+        if (WalkFast.fFailed & PGM_WALKFAIL_EPT)
+            IEM_VMX_VMEXIT_EPT_RET(pVCpu, &WalkFast, IEM_ACCESS_INSTRUCTION, IEM_SLAT_FAIL_LINEAR_TO_PAGE_TABLE, 0 /* cbInstr */);
 # endif
         return iemRaisePageFault(pVCpu, GCPtrPC, 1, IEM_ACCESS_INSTRUCTION, VERR_ACCESS_DENIED);
     }
-    if (!(Walk.fEffective & X86_PTE_PAE_NX) || !(pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_NXE)) { /* likely */ }
+    if (!(WalkFast.fEffective & X86_PTE_PAE_NX) || !(pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_NXE)) { /* likely */ }
     else
     {
         Log(("iemInitDecoderAndPrefetchOpcodes: %RGv - NX\n", GCPtrPC));
 # ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
-        if (Walk.fFailed & PGM_WALKFAIL_EPT)
-            IEM_VMX_VMEXIT_EPT_RET(pVCpu, &Walk, IEM_ACCESS_INSTRUCTION, IEM_SLAT_FAIL_LINEAR_TO_PAGE_TABLE, 0 /* cbInstr */);
+/** @todo this is completely wrong for EPT. WalkFast.fFailed is always zero here!*/
+#  error completely wrong.
+        if (WalkFast.fFailed & PGM_WALKFAIL_EPT)
+            IEM_VMX_VMEXIT_EPT_RET(pVCpu, &WalkFast, IEM_ACCESS_INSTRUCTION, IEM_SLAT_FAIL_LINEAR_TO_PAGE_TABLE, 0 /* cbInstr */);
 # endif
         return iemRaisePageFault(pVCpu, GCPtrPC, 1, IEM_ACCESS_INSTRUCTION, VERR_ACCESS_DENIED);
     }
-    RTGCPHYS const GCPhys = Walk.GCPhys | (GCPtrPC & GUEST_PAGE_OFFSET_MASK);
+#else
+    Assert((WalkFast.fEffective & X86_PTE_US) || IEM_GET_CPL(pVCpu) != 3));
+    Assert(!(WalkFast.fEffective & X86_PTE_PAE_NX) || !(pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_NXE));
+#endif
+    RTGCPHYS const GCPhys = Walk.GCPhys;
     /** @todo Check reserved bits and such stuff. PGM is better at doing
      *        that, so do it when implementing the guest virtual address
@@ -929,14 +942,53 @@
             pVCpu->iem.s.CodeTlb.cTlbHits++;
 # endif
+            Assert(!(pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_ACCESSED));
+
+            /* Check TLB page table level access flags. */
+            if (pTlbe->fFlagsAndPhysRev & (IEMTLBE_F_PT_NO_USER | IEMTLBE_F_PT_NO_EXEC))
+            {
+                if ((pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_USER) && IEM_GET_CPL(pVCpu) == 3)
+                {
+                    Log(("iemOpcodeFetchBytesJmp: %RGv - supervisor page\n", GCPtrFirst));
+                    iemRaisePageFaultJmp(pVCpu, GCPtrFirst, 1, IEM_ACCESS_INSTRUCTION, VERR_ACCESS_DENIED);
+                }
+                if ((pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_EXEC) && (pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_NXE))
+                {
+                    Log(("iemOpcodeFetchMoreBytes: %RGv - NX\n", GCPtrFirst));
+                    iemRaisePageFaultJmp(pVCpu, GCPtrFirst, 1, IEM_ACCESS_INSTRUCTION, VERR_ACCESS_DENIED);
+                }
+            }
+
+            /* Look up the physical page info if necessary. */
+            if ((pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PHYS_REV) == pVCpu->iem.s.CodeTlb.uTlbPhysRev)
+            { /* not necessary */ }
+            else
+            {
+                if (RT_LIKELY(pVCpu->iem.s.CodeTlb.uTlbPhysRev > IEMTLB_PHYS_REV_INCR))
+                { /* likely */ }
+                else
+                    IEMTlbInvalidateAllPhysicalSlow(pVCpu);
+                pTlbe->fFlagsAndPhysRev &= ~IEMTLBE_GCPHYS2PTR_MASK;
+                int rc = PGMPhysIemGCPhys2PtrNoLock(pVCpu->CTX_SUFF(pVM), pVCpu, pTlbe->GCPhys, &pVCpu->iem.s.CodeTlb.uTlbPhysRev,
+                                                    &pTlbe->pbMappingR3, &pTlbe->fFlagsAndPhysRev);
+                AssertRCStmt(rc, IEM_DO_LONGJMP(pVCpu, rc));
+            }
         }
         else
         {
             pVCpu->iem.s.CodeTlb.cTlbMisses++;
-            PGMPTWALK Walk;
-            int rc = PGMGstGetPage(pVCpu, GCPtrFirst, &Walk);
-            if (RT_FAILURE(rc))
+
+            /* This page table walking will set A bits as required by the access while performing the walk.
+               ASSUMES these are set when the address is translated rather than on commit... */
+            /** @todo testcase: check when A bits are actually set by the CPU for code.  */
+            PGMPTWALKFAST WalkFast;
+            int rc = PGMGstQueryPageFast(pVCpu, GCPtrFirst,
+                                         IEM_GET_CPL(pVCpu) == 3 ? PGMQPAGE_F_EXECUTE | PGMQPAGE_F_USER_MODE : PGMQPAGE_F_EXECUTE,
+                                         &WalkFast);
+            if (RT_SUCCESS(rc))
+                Assert((WalkFast.fInfo & PGM_WALKINFO_SUCCEEDED) && WalkFast.fFailed == PGM_WALKFAIL_SUCCESS);
+            else
             {
 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
-                /** @todo Nested VMX: Need to handle EPT violation/misconfig here?  */
+                /** @todo Nested VMX: Need to handle EPT violation/misconfig here?  OF COURSE! */
                 Assert(!(Walk.fFailed & PGM_WALKFAIL_EPT));
 #endif
@@ -946,67 +998,22 @@
 
             AssertCompile(IEMTLBE_F_PT_NO_EXEC == 1);
-            Assert(Walk.fSucceeded);
             pTlbe->uTag             = uTag;
-            pTlbe->fFlagsAndPhysRev = (~Walk.fEffective & (X86_PTE_US | X86_PTE_RW | X86_PTE_D | X86_PTE_A))
-                                    | (Walk.fEffective >> X86_PTE_PAE_BIT_NX);
-            pTlbe->GCPhys           = Walk.GCPhys;
+            pTlbe->fFlagsAndPhysRev = (~WalkFast.fEffective & (X86_PTE_US | X86_PTE_RW | X86_PTE_D | X86_PTE_A))
+                                    | (WalkFast.fEffective >> X86_PTE_PAE_BIT_NX) /*IEMTLBE_F_PT_NO_EXEC*/;
+            RTGCPHYS const GCPhysPg = WalkFast.GCPhys & ~(RTGCPHYS)GUEST_PAGE_OFFSET_MASK;
+            pTlbe->GCPhys           = GCPhysPg;
             pTlbe->pbMappingR3      = NULL;
-        }
-
-        /*
-         * Check TLB page table level access flags.
-         */
-        if (pTlbe->fFlagsAndPhysRev & (IEMTLBE_F_PT_NO_USER | IEMTLBE_F_PT_NO_EXEC))
-        {
-            if ((pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_USER) && IEM_GET_CPL(pVCpu) == 3)
-            {
-                Log(("iemOpcodeFetchBytesJmp: %RGv - supervisor page\n", GCPtrFirst));
-                iemRaisePageFaultJmp(pVCpu, GCPtrFirst, 1, IEM_ACCESS_INSTRUCTION, VERR_ACCESS_DENIED);
-            }
-            if ((pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_EXEC) && (pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_NXE))
-            {
-                Log(("iemOpcodeFetchMoreBytes: %RGv - NX\n", GCPtrFirst));
-                iemRaisePageFaultJmp(pVCpu, GCPtrFirst, 1, IEM_ACCESS_INSTRUCTION, VERR_ACCESS_DENIED);
-            }
-        }
-
-        /*
-         * Set the accessed flags.
-         * ASSUMES this is set when the address is translated rather than on commit...
-         */
-        /** @todo testcase: check when the A bit are actually set by the CPU for code. */
-        if (pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_ACCESSED)
-        {
-            int rc2 = PGMGstModifyPage(pVCpu, GCPtrFirst, 1, X86_PTE_A, ~(uint64_t)X86_PTE_A);
-            AssertRC(rc2);
-            /** @todo Nested VMX: Accessed/dirty bit currently not supported, asserted below. */
-            Assert(!(CPUMGetGuestIa32VmxEptVpidCap(pVCpu) & VMX_BF_EPT_VPID_CAP_ACCESS_DIRTY_MASK));
-            pTlbe->fFlagsAndPhysRev &= ~IEMTLBE_F_PT_NO_ACCESSED;
-        }
-
-        /*
-         * Look up the physical page info if necessary.
-         */
-        if ((pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PHYS_REV) == pVCpu->iem.s.CodeTlb.uTlbPhysRev)
-        { /* not necessary */ }
-        else
-        {
-            AssertCompile(PGMIEMGCPHYS2PTR_F_NO_WRITE     == IEMTLBE_F_PG_NO_WRITE);
-            AssertCompile(PGMIEMGCPHYS2PTR_F_NO_READ      == IEMTLBE_F_PG_NO_READ);
-            AssertCompile(PGMIEMGCPHYS2PTR_F_NO_MAPPINGR3 == IEMTLBE_F_NO_MAPPINGR3);
-            AssertCompile(PGMIEMGCPHYS2PTR_F_UNASSIGNED   == IEMTLBE_F_PG_UNASSIGNED);
-            AssertCompile(PGMIEMGCPHYS2PTR_F_CODE_PAGE    == IEMTLBE_F_PG_CODE_PAGE);
+            Assert(!(pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_EXEC) || !(pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_NXE));
+            Assert(!(pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_USER) || IEM_GET_CPL(pVCpu) != 3);
+            Assert(!(pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_ACCESSED));
+
+            /* Resolve the physical address. */
             if (RT_LIKELY(pVCpu->iem.s.CodeTlb.uTlbPhysRev > IEMTLB_PHYS_REV_INCR))
             { /* likely */ }
             else
                 IEMTlbInvalidateAllPhysicalSlow(pVCpu);
-            pTlbe->fFlagsAndPhysRev &= ~(  IEMTLBE_F_PHYS_REV
-                                         | IEMTLBE_F_NO_MAPPINGR3
-                                         | IEMTLBE_F_PG_NO_READ
-                                         | IEMTLBE_F_PG_NO_WRITE
-                                         | IEMTLBE_F_PG_UNASSIGNED
-                                         | IEMTLBE_F_PG_CODE_PAGE);
-            int rc = PGMPhysIemGCPhys2PtrNoLock(pVCpu->CTX_SUFF(pVM), pVCpu, pTlbe->GCPhys, &pVCpu->iem.s.CodeTlb.uTlbPhysRev,
-                                                &pTlbe->pbMappingR3, &pTlbe->fFlagsAndPhysRev);
+            Assert(!(pTlbe->fFlagsAndPhysRev & IEMTLBE_GCPHYS2PTR_MASK));
+            rc = PGMPhysIemGCPhys2PtrNoLock(pVCpu->CTX_SUFF(pVM), pVCpu, GCPhysPg, &pVCpu->iem.s.CodeTlb.uTlbPhysRev,
+                                            &pTlbe->pbMappingR3, &pTlbe->fFlagsAndPhysRev);
             AssertRCStmt(rc, IEM_DO_LONGJMP(pVCpu, rc));
         }
@@ -4458,4 +4465,8 @@
             break;
 
+        case VERR_RESERVED_PAGE_TABLE_BITS:
+            uErr = X86_TRAP_PF_P | X86_TRAP_PF_RSVD;
+            break;
+
         default:
             AssertMsgFailed(("%Rrc\n", rc));
@@ -4464,6 +4475,4 @@
             uErr = X86_TRAP_PF_P;
             break;
-
-        /** @todo reserved  */
     }
 
@@ -5657,86 +5666,52 @@
      *        iemSvmWorldSwitch/iemVmxWorldSwitch to work around raising a page-fault
      *        here. */
-    PGMPTWALK Walk;
-    int rc = PGMGstGetPage(pVCpu, GCPtrMem, &Walk);
-    if (RT_FAILURE(rc))
-    {
-        LogEx(LOG_GROUP_IEM,("iemMemPageTranslateAndCheckAccess: GCPtrMem=%RGv - failed to fetch page -> #PF\n", GCPtrMem));
-        /** @todo Check unassigned memory in unpaged mode. */
-        /** @todo Reserved bits in page tables. Requires new PGM interface. */
+    Assert(!(fAccess & IEM_ACCESS_TYPE_EXEC));
+    PGMPTWALKFAST WalkFast;
+    AssertCompile(IEM_ACCESS_TYPE_READ  == PGMQPAGE_F_READ);
+    AssertCompile(IEM_ACCESS_TYPE_WRITE == PGMQPAGE_F_WRITE);
+    AssertCompile(IEM_ACCESS_TYPE_EXEC  == PGMQPAGE_F_EXECUTE);
+    AssertCompile(X86_CR0_WP            == PGMQPAGE_F_CR0_WP0);
+    uint32_t fQPage = (fAccess & (PGMQPAGE_F_READ | IEM_ACCESS_TYPE_WRITE | PGMQPAGE_F_EXECUTE))
+                    | (((uint32_t)pVCpu->cpum.GstCtx.cr0 & X86_CR0_WP) ^ X86_CR0_WP);
+    if (IEM_GET_CPL(pVCpu) == 3 && !(fAccess & IEM_ACCESS_WHAT_SYS))
+        fQPage |= PGMQPAGE_F_USER_MODE;
+    int rc = PGMGstQueryPageFast(pVCpu, GCPtrMem, fQPage, &WalkFast);
+    if (RT_SUCCESS(rc))
+    {
+        Assert((WalkFast.fInfo & PGM_WALKINFO_SUCCEEDED) && WalkFast.fFailed == PGM_WALKFAIL_SUCCESS);
+
+        /* If the page is writable and does not have the no-exec bit set, all
+           access is allowed.  Otherwise we'll have to check more carefully... */
+        Assert(   (WalkFast.fEffective & (X86_PTE_RW | X86_PTE_US | X86_PTE_PAE_NX)) == (X86_PTE_RW | X86_PTE_US)
+               || (   (   !(fAccess & IEM_ACCESS_TYPE_WRITE)
+                       || (WalkFast.fEffective & X86_PTE_RW)
+                       || (   (    IEM_GET_CPL(pVCpu) != 3
+                               || (fAccess & IEM_ACCESS_WHAT_SYS))
+                           && (pVCpu->cpum.GstCtx.cr0 & X86_CR0_WP)) )
+                    && (   (WalkFast.fEffective & X86_PTE_US)
+                        || IEM_GET_CPL(pVCpu) != 3
+                        || (fAccess & IEM_ACCESS_WHAT_SYS) )
+                    && (   !(fAccess & IEM_ACCESS_TYPE_EXEC)
+                        || !(WalkFast.fEffective & X86_PTE_PAE_NX)
+                        || !(pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_NXE) )
+                  )
+              );
+
+        /* PGMGstQueryPageFast sets the A & D bits. */
+        /** @todo testcase: check when A and D bits are actually set by the CPU.  */
+        Assert(!(~WalkFast.fEffective & (fAccess & IEM_ACCESS_TYPE_WRITE ? X86_PTE_D | X86_PTE_A : X86_PTE_A)));
+
+        *pGCPhysMem = WalkFast.GCPhys;
+        return VINF_SUCCESS;
+    }
+
+    LogEx(LOG_GROUP_IEM,("iemMemPageTranslateAndCheckAccess: GCPtrMem=%RGv - failed to fetch page -> #PF\n", GCPtrMem));
+    /** @todo Check unassigned memory in unpaged mode. */
 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
-        if (Walk.fFailed & PGM_WALKFAIL_EPT)
-            IEM_VMX_VMEXIT_EPT_RET(pVCpu, &Walk, fAccess, IEM_SLAT_FAIL_LINEAR_TO_PHYS_ADDR, 0 /* cbInstr */);
+    if (WalkFast.fFailed & PGM_WALKFAIL_EPT)
+        IEM_VMX_VMEXIT_EPT_RET(pVCpu, &Walk, fAccess, IEM_SLAT_FAIL_LINEAR_TO_PHYS_ADDR, 0 /* cbInstr */);
 #endif
-        *pGCPhysMem = NIL_RTGCPHYS;
-        return iemRaisePageFault(pVCpu, GCPtrMem, cbAccess, fAccess, rc);
-    }
-
-    /* If the page is writable and does not have the no-exec bit set, all
-       access is allowed.  Otherwise we'll have to check more carefully... */
-    if ((Walk.fEffective & (X86_PTE_RW | X86_PTE_US | X86_PTE_PAE_NX)) != (X86_PTE_RW | X86_PTE_US))
-    {
-        /* Write to read only memory? */
-        if (   (fAccess & IEM_ACCESS_TYPE_WRITE)
-            && !(Walk.fEffective & X86_PTE_RW)
-            && (   (    IEM_GET_CPL(pVCpu) == 3
-                    && !(fAccess & IEM_ACCESS_WHAT_SYS))
-                || (pVCpu->cpum.GstCtx.cr0 & X86_CR0_WP)))
-        {
-            LogEx(LOG_GROUP_IEM,("iemMemPageTranslateAndCheckAccess: GCPtrMem=%RGv - read-only page -> #PF\n", GCPtrMem));
-            *pGCPhysMem = NIL_RTGCPHYS;
-#ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
-            if (Walk.fFailed & PGM_WALKFAIL_EPT)
-                IEM_VMX_VMEXIT_EPT_RET(pVCpu, &Walk, fAccess, IEM_SLAT_FAIL_LINEAR_TO_PAGE_TABLE, 0 /* cbInstr */);
-#endif
-            return iemRaisePageFault(pVCpu, GCPtrMem, cbAccess, fAccess & ~IEM_ACCESS_TYPE_READ, VERR_ACCESS_DENIED);
-        }
-
-        /* Kernel memory accessed by userland? */
-        if (   !(Walk.fEffective & X86_PTE_US)
-            && IEM_GET_CPL(pVCpu) == 3
-            && !(fAccess & IEM_ACCESS_WHAT_SYS))
-        {
-            LogEx(LOG_GROUP_IEM,("iemMemPageTranslateAndCheckAccess: GCPtrMem=%RGv - user access to kernel page -> #PF\n", GCPtrMem));
-            *pGCPhysMem = NIL_RTGCPHYS;
-#ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
-            if (Walk.fFailed & PGM_WALKFAIL_EPT)
-                IEM_VMX_VMEXIT_EPT_RET(pVCpu, &Walk, fAccess, IEM_SLAT_FAIL_LINEAR_TO_PAGE_TABLE, 0 /* cbInstr */);
-#endif
-            return iemRaisePageFault(pVCpu, GCPtrMem, cbAccess, fAccess, VERR_ACCESS_DENIED);
-        }
-
-        /* Executing non-executable memory? */
-        if (   (fAccess & IEM_ACCESS_TYPE_EXEC)
-            && (Walk.fEffective & X86_PTE_PAE_NX)
-            && (pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_NXE) )
-        {
-            LogEx(LOG_GROUP_IEM,("iemMemPageTranslateAndCheckAccess: GCPtrMem=%RGv - NX -> #PF\n", GCPtrMem));
-            *pGCPhysMem = NIL_RTGCPHYS;
-#ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
-            if (Walk.fFailed & PGM_WALKFAIL_EPT)
-                IEM_VMX_VMEXIT_EPT_RET(pVCpu, &Walk, fAccess, IEM_SLAT_FAIL_LINEAR_TO_PAGE_TABLE, 0 /* cbInstr */);
-#endif
-            return iemRaisePageFault(pVCpu, GCPtrMem, cbAccess, fAccess & ~(IEM_ACCESS_TYPE_READ | IEM_ACCESS_TYPE_WRITE),
-                                     VERR_ACCESS_DENIED);
-        }
-    }
-
-    /*
-     * Set the dirty / access flags.
-     * ASSUMES this is set when the address is translated rather than on committ...
-     */
-    /** @todo testcase: check when A and D bits are actually set by the CPU.  */
-    uint32_t fAccessedDirty = fAccess & IEM_ACCESS_TYPE_WRITE ? X86_PTE_D | X86_PTE_A : X86_PTE_A;
-    if ((Walk.fEffective & fAccessedDirty) != fAccessedDirty)
-    {
-        int rc2 = PGMGstModifyPage(pVCpu, GCPtrMem, 1, fAccessedDirty, ~(uint64_t)fAccessedDirty);
-        AssertRC(rc2);
-        /** @todo Nested VMX: Accessed/dirty bit currently not supported, asserted below. */
-        Assert(!(CPUMGetGuestIa32VmxEptVpidCap(pVCpu) & VMX_BF_EPT_VPID_CAP_ACCESS_DIRTY_MASK));
-    }
-
-    RTGCPHYS const GCPhys = Walk.GCPhys | (GCPtrMem & GUEST_PAGE_OFFSET_MASK);
-    *pGCPhysMem = GCPhys;
-    return VINF_SUCCESS;
+    *pGCPhysMem = NIL_RTGCPHYS;
+    return iemRaisePageFault(pVCpu, GCPtrMem, cbAccess, fAccess, rc);
 }
 
@@ -6368,118 +6343,110 @@
 
     /*
-     * Get the TLB entry for this page.
+     * Get the TLB entry for this page and check PT flags.
+     *
+     * We reload the TLB entry if we need to set the dirty bit (accessed
+     * should in theory always be set).
      */
+    uint8_t           *pbMem = NULL;
     uint64_t const     uTag  = IEMTLB_CALC_TAG(    &pVCpu->iem.s.DataTlb, GCPtrMem);
     PIEMTLBENTRY const pTlbe = IEMTLB_TAG_TO_ENTRY(&pVCpu->iem.s.DataTlb, uTag);
-    if (pTlbe->uTag == uTag)
-    {
-# ifdef VBOX_WITH_STATISTICS
-        pVCpu->iem.s.DataTlb.cTlbHits++;
+    if (   pTlbe->uTag == uTag
+        && !(pTlbe->fFlagsAndPhysRev & (IEMTLBE_F_PT_NO_ACCESSED | (fAccess & IEM_ACCESS_TYPE_WRITE ? IEMTLBE_F_PT_NO_DIRTY : 0))) )
+    {
+        STAM_STATS({pVCpu->iem.s.DataTlb.cTlbHits++;});
+
+        /* If the page is either supervisor only or non-writable, we need to do
+           more careful access checks. */
+        if (pTlbe->fFlagsAndPhysRev & (IEMTLBE_F_PT_NO_USER | IEMTLBE_F_PT_NO_WRITE))
+        {
+            /* Write to read only memory? */
+            if (   (pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_WRITE)
+                && (fAccess & IEM_ACCESS_TYPE_WRITE)
+                && (   (    IEM_GET_CPL(pVCpu) == 3
+                        && !(fAccess & IEM_ACCESS_WHAT_SYS))
+                    || (pVCpu->cpum.GstCtx.cr0 & X86_CR0_WP)))
+            {
+                LogEx(LOG_GROUP_IEM, ("iemMemMap: GCPtrMem=%RGv - read-only page -> #PF\n", GCPtrMem));
+                return iemRaisePageFault(pVCpu, GCPtrMem, (uint32_t)cbMem, fAccess & ~IEM_ACCESS_TYPE_READ, VERR_ACCESS_DENIED);
+            }
+
+            /* Kernel memory accessed by userland? */
+            if (   (pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_USER)
+                && IEM_GET_CPL(pVCpu) == 3
+                && !(fAccess & IEM_ACCESS_WHAT_SYS))
+            {
+                LogEx(LOG_GROUP_IEM, ("iemMemMap: GCPtrMem=%RGv - user access to kernel page -> #PF\n", GCPtrMem));
+                return iemRaisePageFault(pVCpu, GCPtrMem, (uint32_t)cbMem, fAccess, VERR_ACCESS_DENIED);
+            }
+        }
+
+        /* Look up the physical page info if necessary. */
+        if ((pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PHYS_REV) == pVCpu->iem.s.DataTlb.uTlbPhysRev)
+# ifdef IN_RING3
+            pbMem = pTlbe->pbMappingR3;
+# else
+            pbMem = NULL;
 # endif
+        else
+        {
+            if (RT_LIKELY(pVCpu->iem.s.CodeTlb.uTlbPhysRev > IEMTLB_PHYS_REV_INCR))
+            { /* likely */ }
+            else
+                IEMTlbInvalidateAllPhysicalSlow(pVCpu);
+            pTlbe->pbMappingR3       = NULL;
+            pTlbe->fFlagsAndPhysRev &= ~IEMTLBE_GCPHYS2PTR_MASK;
+            int rc = PGMPhysIemGCPhys2PtrNoLock(pVCpu->CTX_SUFF(pVM), pVCpu, pTlbe->GCPhys, &pVCpu->iem.s.DataTlb.uTlbPhysRev,
+                                                &pbMem, &pTlbe->fFlagsAndPhysRev);
+            AssertRCReturn(rc, rc);
+# ifdef IN_RING3
+            pTlbe->pbMappingR3 = pbMem;
+# endif
+        }
     }
     else
     {
         pVCpu->iem.s.DataTlb.cTlbMisses++;
-        PGMPTWALK Walk;
-        int rc = PGMGstGetPage(pVCpu, GCPtrMem, &Walk);
-        if (RT_FAILURE(rc))
+
+        /* This page table walking will set A bits as required by the access while performing the walk.
+           ASSUMES these are set when the address is translated rather than on commit... */
+        /** @todo testcase: check when A bits are actually set by the CPU for code.  */
+        PGMPTWALKFAST WalkFast;
+        AssertCompile(IEM_ACCESS_TYPE_READ  == PGMQPAGE_F_READ);
+        AssertCompile(IEM_ACCESS_TYPE_WRITE == PGMQPAGE_F_WRITE);
+        AssertCompile(IEM_ACCESS_TYPE_EXEC  == PGMQPAGE_F_EXECUTE);
+        AssertCompile(X86_CR0_WP            == PGMQPAGE_F_CR0_WP0);
+        uint32_t fQPage = (fAccess & (PGMQPAGE_F_READ | IEM_ACCESS_TYPE_WRITE | PGMQPAGE_F_EXECUTE))
+                        | (((uint32_t)pVCpu->cpum.GstCtx.cr0 & X86_CR0_WP) ^ X86_CR0_WP);
+        if (IEM_GET_CPL(pVCpu) == 3 && !(fAccess & IEM_ACCESS_WHAT_SYS))
+            fQPage |= PGMQPAGE_F_USER_MODE;
+        int rc = PGMGstQueryPageFast(pVCpu, GCPtrMem, fQPage, &WalkFast);
+        if (RT_SUCCESS(rc))
+            Assert((WalkFast.fInfo & PGM_WALKINFO_SUCCEEDED) && WalkFast.fFailed == PGM_WALKFAIL_SUCCESS);
+        else
         {
             LogEx(LOG_GROUP_IEM, ("iemMemMap: GCPtrMem=%RGv - failed to fetch page -> #PF\n", GCPtrMem));
 # ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
-            if (Walk.fFailed & PGM_WALKFAIL_EPT)
-                IEM_VMX_VMEXIT_EPT_RET(pVCpu, &Walk, fAccess, IEM_SLAT_FAIL_LINEAR_TO_PHYS_ADDR, 0 /* cbInstr */);
+            if (WalkFast.fFailed & PGM_WALKFAIL_EPT)
+                IEM_VMX_VMEXIT_EPT_RET(pVCpu, &WalkFast, fAccess, IEM_SLAT_FAIL_LINEAR_TO_PHYS_ADDR, 0 /* cbInstr */);
 # endif
             return iemRaisePageFault(pVCpu, GCPtrMem, (uint32_t)cbMem, fAccess, rc);
         }
 
-        Assert(Walk.fSucceeded);
         pTlbe->uTag             = uTag;
-        pTlbe->fFlagsAndPhysRev = ~Walk.fEffective & (X86_PTE_US | X86_PTE_RW | X86_PTE_D | X86_PTE_A); /* skipping NX */
-        pTlbe->GCPhys           = Walk.GCPhys;
+        pTlbe->fFlagsAndPhysRev = ~WalkFast.fEffective & (X86_PTE_US | X86_PTE_RW | X86_PTE_D | X86_PTE_A); /* skipping NX */
+        RTGCPHYS const GCPhysPg = WalkFast.GCPhys & ~(RTGCPHYS)GUEST_PAGE_OFFSET_MASK;
+        pTlbe->GCPhys           = GCPhysPg;
         pTlbe->pbMappingR3      = NULL;
-    }
-
-    /*
-     * Check TLB page table level access flags.
-     */
-    /* If the page is either supervisor only or non-writable, we need to do
-       more careful access checks. */
-    if (pTlbe->fFlagsAndPhysRev & (IEMTLBE_F_PT_NO_USER | IEMTLBE_F_PT_NO_WRITE))
-    {
-        /* Write to read only memory? */
-        if (   (pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_WRITE)
-            && (fAccess & IEM_ACCESS_TYPE_WRITE)
-            && (   (    IEM_GET_CPL(pVCpu) == 3
-                    && !(fAccess & IEM_ACCESS_WHAT_SYS))
-                || (pVCpu->cpum.GstCtx.cr0 & X86_CR0_WP)))
-        {
-            LogEx(LOG_GROUP_IEM, ("iemMemMap: GCPtrMem=%RGv - read-only page -> #PF\n", GCPtrMem));
-# ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
-            if (Walk.fFailed & PGM_WALKFAIL_EPT)
-                IEM_VMX_VMEXIT_EPT_RET(pVCpu, &Walk, fAccess, IEM_SLAT_FAIL_LINEAR_TO_PAGE_TABLE, 0 /* cbInstr */);
-# endif
-            return iemRaisePageFault(pVCpu, GCPtrMem, (uint32_t)cbMem, fAccess & ~IEM_ACCESS_TYPE_READ, VERR_ACCESS_DENIED);
-        }
-
-        /* Kernel memory accessed by userland? */
-        if (   (pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_USER)
-            && IEM_GET_CPL(pVCpu) == 3
-            && !(fAccess & IEM_ACCESS_WHAT_SYS))
-        {
-            LogEx(LOG_GROUP_IEM, ("iemMemMap: GCPtrMem=%RGv - user access to kernel page -> #PF\n", GCPtrMem));
-# ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
-            if (Walk.fFailed & PGM_WALKFAIL_EPT)
-                IEM_VMX_VMEXIT_EPT_RET(pVCpu, &Walk, fAccess, IEM_SLAT_FAIL_LINEAR_TO_PAGE_TABLE, 0 /* cbInstr */);
-# endif
-            return iemRaisePageFault(pVCpu, GCPtrMem, (uint32_t)cbMem, fAccess, VERR_ACCESS_DENIED);
-        }
-    }
-
-    /*
-     * Set the dirty / access flags.
-     * ASSUMES this is set when the address is translated rather than on commit...
-     */
-    /** @todo testcase: check when A and D bits are actually set by the CPU.  */
-    uint64_t const fTlbAccessedDirty = (fAccess & IEM_ACCESS_TYPE_WRITE ? IEMTLBE_F_PT_NO_DIRTY : 0) | IEMTLBE_F_PT_NO_ACCESSED;
-    if (pTlbe->fFlagsAndPhysRev & fTlbAccessedDirty)
-    {
-        uint32_t const fAccessedDirty = fAccess & IEM_ACCESS_TYPE_WRITE ? X86_PTE_D | X86_PTE_A : X86_PTE_A;
-        int rc2 = PGMGstModifyPage(pVCpu, GCPtrMem, 1, fAccessedDirty, ~(uint64_t)fAccessedDirty);
-        AssertRC(rc2);
-        /** @todo Nested VMX: Accessed/dirty bit currently not supported, asserted below. */
-        Assert(!(CPUMGetGuestIa32VmxEptVpidCap(pVCpu) & VMX_BF_EPT_VPID_CAP_ACCESS_DIRTY_MASK));
-        pTlbe->fFlagsAndPhysRev &= ~fTlbAccessedDirty;
-    }
-
-    /*
-     * Look up the physical page info if necessary.
-     */
-    uint8_t *pbMem = NULL;
-    if ((pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PHYS_REV) == pVCpu->iem.s.DataTlb.uTlbPhysRev)
-# ifdef IN_RING3
-        pbMem = pTlbe->pbMappingR3;
-# else
-        pbMem = NULL;
-# endif
-    else
-    {
-        AssertCompile(PGMIEMGCPHYS2PTR_F_NO_WRITE     == IEMTLBE_F_PG_NO_WRITE);
-        AssertCompile(PGMIEMGCPHYS2PTR_F_NO_READ      == IEMTLBE_F_PG_NO_READ);
-        AssertCompile(PGMIEMGCPHYS2PTR_F_NO_MAPPINGR3 == IEMTLBE_F_NO_MAPPINGR3);
-        AssertCompile(PGMIEMGCPHYS2PTR_F_UNASSIGNED   == IEMTLBE_F_PG_UNASSIGNED);
-        AssertCompile(PGMIEMGCPHYS2PTR_F_CODE_PAGE    == IEMTLBE_F_PG_CODE_PAGE);
-        if (RT_LIKELY(pVCpu->iem.s.CodeTlb.uTlbPhysRev > IEMTLB_PHYS_REV_INCR))
-        { /* likely */ }
-        else
-            IEMTlbInvalidateAllPhysicalSlow(pVCpu);
-        pTlbe->pbMappingR3       = NULL;
-        pTlbe->fFlagsAndPhysRev &= ~(  IEMTLBE_F_PHYS_REV
-                                     | IEMTLBE_F_NO_MAPPINGR3
-                                     | IEMTLBE_F_PG_NO_READ
-                                     | IEMTLBE_F_PG_NO_WRITE
-                                     | IEMTLBE_F_PG_UNASSIGNED
-                                     | IEMTLBE_F_PG_CODE_PAGE);
-        int rc = PGMPhysIemGCPhys2PtrNoLock(pVCpu->CTX_SUFF(pVM), pVCpu, pTlbe->GCPhys, &pVCpu->iem.s.DataTlb.uTlbPhysRev,
-                                            &pbMem, &pTlbe->fFlagsAndPhysRev);
+        Assert(!(pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_ACCESSED));
+        Assert(!(pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_DIRTY) || !(fAccess & IEM_ACCESS_TYPE_WRITE));
+        Assert(!(pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_WRITE) || !(fAccess & IEM_ACCESS_TYPE_WRITE));
+        Assert(   !(pTlbe->fFlagsAndPhysRev & IEMTLBE_F_PT_NO_USER)
+               || IEM_GET_CPL(pVCpu) != 3
+               || (fAccess & IEM_ACCESS_WHAT_SYS));
+
+        /* Resolve the physical address. */
+        Assert(!(pTlbe->fFlagsAndPhysRev & IEMTLBE_GCPHYS2PTR_MASK));
+        rc = PGMPhysIemGCPhys2PtrNoLock(pVCpu->CTX_SUFF(pVM), pVCpu, GCPhysPg, &pVCpu->iem.s.DataTlb.uTlbPhysRev,
+                                        &pbMem, &pTlbe->fFlagsAndPhysRev);
         AssertRCReturn(rc, rc);
 # ifdef IN_RING3
@@ -6764,20 +6731,48 @@
 
     /*
-     * Get the TLB entry for this page.
+     * Get the TLB entry for this page checking that it has the A & D bits
+     * set as per fAccess flags.
      */
+    /** @todo make the caller pass these in with fAccess. */
+    uint64_t const     fNoUser          = (fAccess & IEM_ACCESS_WHAT_MASK) != IEM_ACCESS_WHAT_SYS && IEM_GET_CPL(pVCpu) == 3
+                                        ? IEMTLBE_F_PT_NO_USER : 0;
+    uint64_t const     fNoWriteNoDirty  = fAccess & IEM_ACCESS_TYPE_WRITE
+                                        ? IEMTLBE_F_PG_NO_WRITE | IEMTLBE_F_PT_NO_DIRTY
+                                          | (   (pVCpu->cpum.GstCtx.cr0 & X86_CR0_WP)
+                                             || (IEM_GET_CPL(pVCpu) == 3 && (fAccess & IEM_ACCESS_WHAT_MASK) != IEM_ACCESS_WHAT_SYS)
+                                             ? IEMTLBE_F_PT_NO_WRITE : 0)
+                                        : 0;
+    uint64_t const     fNoRead          = fAccess & IEM_ACCESS_TYPE_READ ? IEMTLBE_F_PG_NO_READ : 0;
+
     uint64_t const     uTag  = IEMTLB_CALC_TAG(    &pVCpu->iem.s.DataTlb, GCPtrMem);
     PIEMTLBENTRY const pTlbe = IEMTLB_TAG_TO_ENTRY(&pVCpu->iem.s.DataTlb, uTag);
-    if (pTlbe->uTag == uTag)
+    if (   pTlbe->uTag == uTag
+        && !(pTlbe->fFlagsAndPhysRev & (IEMTLBE_F_PT_NO_ACCESSED | (fNoWriteNoDirty & IEMTLBE_F_PT_NO_DIRTY))) )
         STAM_STATS({pVCpu->iem.s.DataTlb.cTlbHits++;});
     else
     {
         pVCpu->iem.s.DataTlb.cTlbMisses++;
-        PGMPTWALK Walk;
-        int rc = PGMGstGetPage(pVCpu, GCPtrMem, &Walk);
-        if (RT_FAILURE(rc))
+
+        /* This page table walking will set A and D bits as required by the
+           access while performing the walk.
+           ASSUMES these are set when the address is translated rather than on commit... */
+        /** @todo testcase: check when A and D bits are actually set by the CPU.  */
+        PGMPTWALKFAST WalkFast;
+        AssertCompile(IEM_ACCESS_TYPE_READ  == PGMQPAGE_F_READ);
+        AssertCompile(IEM_ACCESS_TYPE_WRITE == PGMQPAGE_F_WRITE);
+        AssertCompile(IEM_ACCESS_TYPE_EXEC  == PGMQPAGE_F_EXECUTE);
+        AssertCompile(X86_CR0_WP            == PGMQPAGE_F_CR0_WP0);
+        uint32_t fQPage = (fAccess & (PGMQPAGE_F_READ | IEM_ACCESS_TYPE_WRITE | PGMQPAGE_F_EXECUTE))
+                        | (((uint32_t)pVCpu->cpum.GstCtx.cr0 & X86_CR0_WP) ^ X86_CR0_WP);
+        if (IEM_GET_CPL(pVCpu) == 3 && !(fAccess & IEM_ACCESS_WHAT_SYS))
+            fQPage |= PGMQPAGE_F_USER_MODE;
+        int rc = PGMGstQueryPageFast(pVCpu, GCPtrMem, fQPage, &WalkFast);
+        if (RT_SUCCESS(rc))
+            Assert((WalkFast.fInfo & PGM_WALKINFO_SUCCEEDED) && WalkFast.fFailed == PGM_WALKFAIL_SUCCESS);
+        else
         {
             LogEx(LOG_GROUP_IEM, ("iemMemMap: GCPtrMem=%RGv - failed to fetch page -> #PF\n", GCPtrMem));
 # ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
-            if (Walk.fFailed & PGM_WALKFAIL_EPT)
+            if (WalkFast.fFailed & PGM_WALKFAIL_EPT)
                 IEM_VMX_VMEXIT_EPT_RET(pVCpu, &Walk, fAccess, IEM_SLAT_FAIL_LINEAR_TO_PHYS_ADDR, 0 /* cbInstr */);
 # endif
@@ -6785,25 +6780,30 @@
         }
 
-        Assert(Walk.fSucceeded);
         pTlbe->uTag             = uTag;
-        pTlbe->fFlagsAndPhysRev = ~Walk.fEffective & (X86_PTE_US | X86_PTE_RW | X86_PTE_D | X86_PTE_A); /* skipping NX */
-        pTlbe->GCPhys           = Walk.GCPhys;
+        pTlbe->fFlagsAndPhysRev = ~WalkFast.fEffective & (X86_PTE_US | X86_PTE_RW | X86_PTE_D | X86_PTE_A); /* skipping NX */
+        RTGCPHYS const GCPhysPg = WalkFast.GCPhys & ~(RTGCPHYS)GUEST_PAGE_OFFSET_MASK;
+        pTlbe->GCPhys           = GCPhysPg;
         pTlbe->pbMappingR3      = NULL;
+        Assert(!(pTlbe->fFlagsAndPhysRev & ((fNoWriteNoDirty & IEMTLBE_F_PT_NO_DIRTY) | IEMTLBE_F_PT_NO_ACCESSED)));
+        Assert(!(pTlbe->fFlagsAndPhysRev & fNoWriteNoDirty & IEMTLBE_F_PT_NO_WRITE));
+        Assert(!(pTlbe->fFlagsAndPhysRev & fNoUser & IEMTLBE_F_PT_NO_USER));
+
+        /* Resolve the physical address. */
+        Assert(!(pTlbe->fFlagsAndPhysRev & IEMTLBE_GCPHYS2PTR_MASK));
+        uint8_t *pbMemFullLoad = NULL;
+        rc = PGMPhysIemGCPhys2PtrNoLock(pVCpu->CTX_SUFF(pVM), pVCpu, GCPhysPg, &pVCpu->iem.s.DataTlb.uTlbPhysRev,
+                                        &pbMemFullLoad, &pTlbe->fFlagsAndPhysRev);
+        AssertRCStmt(rc, IEM_DO_LONGJMP(pVCpu, rc));
+# ifdef IN_RING3
+        pTlbe->pbMappingR3 = pbMemFullLoad;
+# endif
     }
 
     /*
      * Check the flags and physical revision.
+     * Note! This will revalidate the uTlbPhysRev after a full load.  This is
+     *       just to keep the code structure simple (i.e. avoid gotos or similar).
      */
-    /** @todo make the caller pass these in with fAccess. */
-    uint64_t const fNoUser          = (fAccess & IEM_ACCESS_WHAT_MASK) != IEM_ACCESS_WHAT_SYS && IEM_GET_CPL(pVCpu) == 3
-                                    ? IEMTLBE_F_PT_NO_USER : 0;
-    uint64_t const fNoWriteNoDirty  = fAccess & IEM_ACCESS_TYPE_WRITE
-                                    ? IEMTLBE_F_PG_NO_WRITE | IEMTLBE_F_PT_NO_DIRTY
-                                      | (   (pVCpu->cpum.GstCtx.cr0 & X86_CR0_WP)
-                                         || (IEM_GET_CPL(pVCpu) == 3 && (fAccess & IEM_ACCESS_WHAT_MASK) != IEM_ACCESS_WHAT_SYS)
-                                         ? IEMTLBE_F_PT_NO_WRITE : 0)
-                                    : 0;
-    uint64_t const fNoRead          = fAccess & IEM_ACCESS_TYPE_READ ? IEMTLBE_F_PG_NO_READ : 0;
-    uint8_t       *pbMem            = NULL;
+    uint8_t *pbMem;
     if (   (pTlbe->fFlagsAndPhysRev & (IEMTLBE_F_PHYS_REV | IEMTLBE_F_PT_NO_ACCESSED | fNoRead | fNoWriteNoDirty | fNoUser))
         == pVCpu->iem.s.DataTlb.uTlbPhysRev)
@@ -6815,4 +6815,6 @@
     else
     {
+        Assert(!(pTlbe->fFlagsAndPhysRev & ((fNoWriteNoDirty & IEMTLBE_F_PT_NO_DIRTY) | IEMTLBE_F_PT_NO_ACCESSED)));
+
         /*
          * Okay, something isn't quite right or needs refreshing.
@@ -6823,4 +6825,6 @@
             LogEx(LOG_GROUP_IEM, ("iemMemMapJmp: GCPtrMem=%RGv - read-only page -> #PF\n", GCPtrMem));
 # ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
+/** @todo TLB: EPT isn't integrated into the TLB stuff, so we don't know whether
+ *        to trigger an \#PG or a VM nested paging exit here yet! */
             if (Walk.fFailed & PGM_WALKFAIL_EPT)
                 IEM_VMX_VMEXIT_EPT_RET(pVCpu, &Walk, fAccess, IEM_SLAT_FAIL_LINEAR_TO_PAGE_TABLE, 0 /* cbInstr */);
@@ -6834,21 +6838,9 @@
             LogEx(LOG_GROUP_IEM, ("iemMemMapJmp: GCPtrMem=%RGv - user access to kernel page -> #PF\n", GCPtrMem));
 # ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
+/** @todo TLB: See above. */
             if (Walk.fFailed & PGM_WALKFAIL_EPT)
                 IEM_VMX_VMEXIT_EPT_RET(pVCpu, &Walk, fAccess, IEM_SLAT_FAIL_LINEAR_TO_PAGE_TABLE, 0 /* cbInstr */);
 # endif
             iemRaisePageFaultJmp(pVCpu, GCPtrMem, (uint32_t)cbMem, fAccess, VERR_ACCESS_DENIED);
-        }
-
-        /* Set the dirty / access flags.
-           ASSUMES this is set when the address is translated rather than on commit... */
-        /** @todo testcase: check when A and D bits are actually set by the CPU.  */
-        if (pTlbe->fFlagsAndPhysRev & ((fNoWriteNoDirty & IEMTLBE_F_PT_NO_DIRTY) | IEMTLBE_F_PT_NO_ACCESSED))
-        {
-            uint32_t const fAccessedDirty = fAccess & IEM_ACCESS_TYPE_WRITE ? X86_PTE_D | X86_PTE_A : X86_PTE_A;
-            int rc2 = PGMGstModifyPage(pVCpu, GCPtrMem, 1, fAccessedDirty, ~(uint64_t)fAccessedDirty);
-            AssertRC(rc2);
-            /** @todo Nested VMX: Accessed/dirty bit currently not supported, asserted below. */
-            Assert(!(CPUMGetGuestIa32VmxEptVpidCap(pVCpu) & VMX_BF_EPT_VPID_CAP_ACCESS_DIRTY_MASK));
-            pTlbe->fFlagsAndPhysRev &= ~((fNoWriteNoDirty & IEMTLBE_F_PT_NO_DIRTY) | IEMTLBE_F_PT_NO_ACCESSED);
         }
 
@@ -6864,16 +6856,7 @@
         else
         {
-            AssertCompile(PGMIEMGCPHYS2PTR_F_NO_WRITE     == IEMTLBE_F_PG_NO_WRITE);
-            AssertCompile(PGMIEMGCPHYS2PTR_F_NO_READ      == IEMTLBE_F_PG_NO_READ);
-            AssertCompile(PGMIEMGCPHYS2PTR_F_NO_MAPPINGR3 == IEMTLBE_F_NO_MAPPINGR3);
-            AssertCompile(PGMIEMGCPHYS2PTR_F_UNASSIGNED   == IEMTLBE_F_PG_UNASSIGNED);
-            AssertCompile(PGMIEMGCPHYS2PTR_F_CODE_PAGE    == IEMTLBE_F_PG_CODE_PAGE);
             pTlbe->pbMappingR3       = NULL;
-            pTlbe->fFlagsAndPhysRev &= ~(  IEMTLBE_F_PHYS_REV
-                                         | IEMTLBE_F_NO_MAPPINGR3
-                                         | IEMTLBE_F_PG_NO_READ
-                                         | IEMTLBE_F_PG_NO_WRITE
-                                         | IEMTLBE_F_PG_UNASSIGNED
-                                         | IEMTLBE_F_PG_CODE_PAGE);
+            pTlbe->fFlagsAndPhysRev &= ~IEMTLBE_GCPHYS2PTR_MASK;
+            pbMem = NULL;
             int rc = PGMPhysIemGCPhys2PtrNoLock(pVCpu->CTX_SUFF(pVM), pVCpu, pTlbe->GCPhys, &pVCpu->iem.s.DataTlb.uTlbPhysRev,
                                                 &pbMem, &pTlbe->fFlagsAndPhysRev);
Index: /trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp	(revision 104931)
+++ /trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp	(revision 104932)
@@ -4136,7 +4136,7 @@
  *                      applicable.
  */
-VBOXSTRICTRC iemVmxVmexitEpt(PVMCPUCC pVCpu, PPGMPTWALK pWalk, uint32_t fAccess, uint32_t fSlatFail, uint8_t cbInstr) RT_NOEXCEPT
-{
-    Assert(pWalk->fIsSlat);
+VBOXSTRICTRC iemVmxVmexitEpt(PVMCPUCC pVCpu, PPGMPTWALKFAST pWalk, uint32_t fAccess, uint32_t fSlatFail, uint8_t cbInstr) RT_NOEXCEPT
+{
+    Assert(pWalk->fInfo & PGM_WALKINFO_IS_SLAT);
     Assert(pWalk->fFailed & PGM_WALKFAIL_EPT);
     Assert(!IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fVmxEptXcptVe);          /* #VE exceptions not supported. */
@@ -4147,5 +4147,6 @@
         LogFlow(("EptViolation: cs:rip=%04x:%08RX64 fAccess=%#RX32\n", pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, fAccess));
         uint64_t const fEptAccess = (pWalk->fEffective & PGM_PTATTRS_EPT_MASK) >> PGM_PTATTRS_EPT_SHIFT;
-        return iemVmxVmexitEptViolation(pVCpu, fAccess, fSlatFail, fEptAccess, pWalk->GCPhysNested, pWalk->fIsLinearAddrValid,
+        return iemVmxVmexitEptViolation(pVCpu, fAccess, fSlatFail, fEptAccess, pWalk->GCPhysNested,
+                                        RT_BOOL(pWalk->fInfo & PGM_WALKINFO_IS_LINEAR_ADDR_VALID),
                                         pWalk->GCPtr, cbInstr);
     }
Index: /trunk/src/VBox/VMM/VMMAll/PGMAll.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/PGMAll.cpp	(revision 104931)
+++ /trunk/src/VBox/VMM/VMMAll/PGMAll.cpp	(revision 104932)
@@ -600,4 +600,5 @@
         PGM_TYPE_REAL,
         PGM_GST_NAME_REAL(GetPage),
+        PGM_GST_NAME_REAL(QueryPageFast),
         PGM_GST_NAME_REAL(ModifyPage),
         PGM_GST_NAME_REAL(Enter),
@@ -610,4 +611,5 @@
         PGM_TYPE_PROT,
         PGM_GST_NAME_PROT(GetPage),
+        PGM_GST_NAME_PROT(QueryPageFast),
         PGM_GST_NAME_PROT(ModifyPage),
         PGM_GST_NAME_PROT(Enter),
@@ -620,4 +622,5 @@
         PGM_TYPE_32BIT,
         PGM_GST_NAME_32BIT(GetPage),
+        PGM_GST_NAME_32BIT(QueryPageFast),
         PGM_GST_NAME_32BIT(ModifyPage),
         PGM_GST_NAME_32BIT(Enter),
@@ -630,4 +633,5 @@
         PGM_TYPE_PAE,
         PGM_GST_NAME_PAE(GetPage),
+        PGM_GST_NAME_PAE(QueryPageFast),
         PGM_GST_NAME_PAE(ModifyPage),
         PGM_GST_NAME_PAE(Enter),
@@ -641,4 +645,5 @@
         PGM_TYPE_AMD64,
         PGM_GST_NAME_AMD64(GetPage),
+        PGM_GST_NAME_AMD64(QueryPageFast),
         PGM_GST_NAME_AMD64(ModifyPage),
         PGM_GST_NAME_AMD64(Enter),
@@ -1921,4 +1926,28 @@
     AssertReturn(g_aPgmGuestModeData[idx].pfnGetPage, VERR_PGM_MODE_IPE);
     return g_aPgmGuestModeData[idx].pfnGetPage(pVCpu, GCPtr, pWalk);
+}
+
+
+/**
+ * Gets effective Guest OS page information.
+ *
+ * @returns VBox status code.
+ * @param   pVCpu       The cross context virtual CPU structure of the calling EMT.
+ * @param   GCPtr       Guest Context virtual address of the page.
+ * @param   fFlags      PGMQPAGE_F_XXX. If zero, no accessed or dirty bits will
+ *                      be set.
+ * @param   pWalk       Where to store the page walk information.
+ * @thread  EMT(pVCpu)
+ */
+VMM_INT_DECL(int) PGMGstQueryPageFast(PVMCPUCC pVCpu, RTGCPTR GCPtr, uint32_t fFlags, PPGMPTWALKFAST pWalk)
+{
+    VMCPU_ASSERT_EMT(pVCpu);
+    Assert(pWalk);
+    Assert(!(fFlags & ~(PGMQPAGE_F_VALID_MASK)));
+    Assert(!(fFlags & PGMQPAGE_F_EXECUTE) || !(fFlags & PGMQPAGE_F_WRITE));
+    uintptr_t idx = pVCpu->pgm.s.idxGuestModeData;
+    AssertReturn(idx < RT_ELEMENTS(g_aPgmGuestModeData), VERR_PGM_MODE_IPE);
+    AssertReturn(g_aPgmGuestModeData[idx].pfnGetPage, VERR_PGM_MODE_IPE);
+    return g_aPgmGuestModeData[idx].pfnQueryPageFast(pVCpu, GCPtr, fFlags, pWalk);
 }
 
Index: /trunk/src/VBox/VMM/VMMAll/PGMAllGst.h
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/PGMAllGst.h	(revision 104931)
+++ /trunk/src/VBox/VMM/VMMAll/PGMAllGst.h	(revision 104932)
@@ -87,25 +87,31 @@
 
 
-DECLINLINE(int) PGM_GST_NAME(WalkReturnNotPresent)(PVMCPUCC pVCpu, PPGMPTWALK pWalk, int iLevel)
-{
-    NOREF(iLevel); NOREF(pVCpu);
+DECLINLINE(int) PGM_GST_NAME(WalkReturnNotPresent)(PVMCPUCC pVCpu, PPGMPTWALK pWalk, uint8_t uLevel)
+{
+    NOREF(pVCpu);
     pWalk->fNotPresent     = true;
-    pWalk->uLevel          = (uint8_t)iLevel;
+    pWalk->uLevel          = uLevel;
+    pWalk->fFailed         = PGM_WALKFAIL_NOT_PRESENT
+                           | ((uint32_t)uLevel << PGM_WALKFAIL_LEVEL_SHIFT);
     return VERR_PAGE_TABLE_NOT_PRESENT;
 }
 
-DECLINLINE(int) PGM_GST_NAME(WalkReturnBadPhysAddr)(PVMCPUCC pVCpu, PPGMPTWALK pWalk, int iLevel, int rc)
+DECLINLINE(int) PGM_GST_NAME(WalkReturnBadPhysAddr)(PVMCPUCC pVCpu, PPGMPTWALK pWalk, uint8_t uLevel, int rc)
 {
     AssertMsg(rc == VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS, ("%Rrc\n", rc)); NOREF(rc); NOREF(pVCpu);
     pWalk->fBadPhysAddr    = true;
-    pWalk->uLevel          = (uint8_t)iLevel;
+    pWalk->uLevel          = uLevel;
+    pWalk->fFailed         = PGM_WALKFAIL_BAD_PHYSICAL_ADDRESS
+                           | ((uint32_t)uLevel << PGM_WALKFAIL_LEVEL_SHIFT);
     return VERR_PAGE_TABLE_NOT_PRESENT;
 }
 
-DECLINLINE(int) PGM_GST_NAME(WalkReturnRsvdError)(PVMCPUCC pVCpu, PPGMPTWALK pWalk, int iLevel)
+DECLINLINE(int) PGM_GST_NAME(WalkReturnRsvdError)(PVMCPUCC pVCpu, PPGMPTWALK pWalk, uint8_t uLevel)
 {
     NOREF(pVCpu);
     pWalk->fRsvdError      = true;
-    pWalk->uLevel          = (uint8_t)iLevel;
+    pWalk->uLevel          = uLevel;
+    pWalk->fFailed         = PGM_WALKFAIL_RESERVED_BITS
+                           | ((uint32_t)uLevel << PGM_WALKFAIL_LEVEL_SHIFT);
     return VERR_PAGE_TABLE_NOT_PRESENT;
 }
@@ -297,5 +303,5 @@
 # endif
             pWalk->GCPhys     = GCPhysPde;
-            PGM_A20_APPLY_TO_VAR(pVCpu, pWalk->GCPhys);
+            PGM_A20_APPLY_TO_VAR(pVCpu, pWalk->GCPhys); /** @todo why do we apply it here and not below?!? */
             return VINF_SUCCESS;
         }
@@ -443,4 +449,551 @@
 }
 
+
+/* x x x x x x x x */
+/* x x x x x x x x */
+
+#if defined(VBOX_WITH_NESTED_HWVIRT_VMX_EPT) || defined(VBOX_WITH_NESTED_HWVIRT_SVM_XXX) || defined(DOXYGEN_RUNNING)
+/** Converts regular style walk info to fast style. */
+DECL_FORCE_INLINE(void) PGM_GST_NAME(ConvertPtWalkToFast)(PGMPTWALK const *pSrc, PPGMPTWALKFAST *pDst)
+{
+    pDst->GCPtr              = pSrc->GCPtr;
+    pDst->GCPhys             = pSrc->GCPhys;
+    pDst->GCPhysNested       = pSrc->GCPhysNested;
+    pDst->fInfo              = (pSrc->fSucceeded         ? PGM_WALKINFO_SUCCEEDED            : 0)
+                             | (pSrc->fIsSlat            ? PGM_WALKINFO_IS_SLAT              : 0)
+                             | (pSrc->fIsLinearAddrValid ? PGM_WALKINFO_IS_LINEAR_ADDR_VALID : 0)
+                             | ((uint32_t)pSrc->uLevel << PGM_WALKINFO_LEVEL_SHIFT);
+    pDst->fFailed            = pSrc->fFailed;
+    pDst->fEffective         = pSrc->fEffective;
+}
+#endif
+
+
+#if PGM_GST_TYPE == PGM_TYPE_32BIT \
+ || PGM_GST_TYPE == PGM_TYPE_PAE \
+ || PGM_GST_TYPE == PGM_TYPE_AMD64
+
+DECLINLINE(int) PGM_GST_NAME(WalkFastReturnNotPresent)(PVMCPUCC pVCpu, PPGMPTWALKFAST pWalk, uint8_t uLevel)
+{
+    RT_NOREF(pVCpu);
+    pWalk->fFailed = PGM_WALKFAIL_NOT_PRESENT           | ((uint32_t)uLevel << PGM_WALKFAIL_LEVEL_SHIFT);
+    return VERR_PAGE_TABLE_NOT_PRESENT;
+}
+
+DECLINLINE(int) PGM_GST_NAME(WalkFastReturnBadPhysAddr)(PVMCPUCC pVCpu, PPGMPTWALKFAST pWalk, uint8_t uLevel, int rc)
+{
+    AssertMsg(rc == VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS, ("%Rrc\n", rc)); RT_NOREF(pVCpu, rc);
+    pWalk->fFailed = PGM_WALKFAIL_BAD_PHYSICAL_ADDRESS  | ((uint32_t)uLevel << PGM_WALKFAIL_LEVEL_SHIFT);
+    return VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS;
+}
+
+DECLINLINE(int) PGM_GST_NAME(WalkFastReturnRsvdError)(PVMCPUCC pVCpu, PPGMPTWALKFAST pWalk, uint8_t uLevel)
+{
+    RT_NOREF(pVCpu);
+    pWalk->fFailed = PGM_WALKFAIL_RESERVED_BITS         | ((uint32_t)uLevel << PGM_WALKFAIL_LEVEL_SHIFT);
+    return VERR_RESERVED_PAGE_TABLE_BITS;
+}
+
+/**
+ * Performs a guest page table walk.
+ *
+ * @returns VBox status code.
+ * @retval  VINF_SUCCESS on success.
+ * @retval  VERR_PAGE_TABLE_NOT_PRESENT, VERR_RESERVED_PAGE_TABLE_BITS or
+ *          VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS on normal failure.
+ *          The failure reason is also recorded in PGMPTWALKFAST::fFailed.
+ *
+ * @param   pVCpu               The cross context virtual CPU structure of the calling EMT.
+ * @param   GCPtr               The guest virtual address to walk by.
+ * @param   fFlags              PGMQPAGE_F_XXX.
+ *                              This is ignored when @a a_fSetFlags is @c false.
+ * @param   pWalk               The page walk info.
+ * @param   pGstWalk            The guest mode specific page walk info.
+ * @tparam  a_enmGuestSlatMode  The SLAT mode of the function.
+ * @tparam  a_fSetFlags         Whether to process @a fFlags and set accessed
+ *                              and dirty flags accordingly.
+ * @thread  EMT(pVCpu)
+ */
+template<PGMSLAT const a_enmGuestSlatMode = PGMSLAT_DIRECT, bool const a_fSetFlags = false>
+DECLINLINE(int) PGM_GST_NAME(WalkFast)(PVMCPUCC pVCpu, RTGCPTR GCPtr, uint32_t fFlags, PPGMPTWALKFAST pWalk, PGSTPTWALK pGstWalk)
+{
+    int rc;
+
+# if defined(VBOX_WITH_NESTED_HWVIRT_VMX_EPT) || defined(VBOX_WITH_NESTED_HWVIRT_SVM_XXX) || defined(DOXYGEN_RUNNING)
+/** @def PGM_GST_SLAT_WALK
+ * Macro to perform guest second-level address translation (EPT or Nested).
+ *
+ * @param   a_pVCpu         The cross context virtual CPU structure of the calling
+ *                          EMT.
+ * @param   a_GCPtrNested   The nested-guest linear address that caused the
+ *                          second-level translation.
+ * @param   a_GCPhysNested  The nested-guest physical address to translate.
+ * @param   a_fFinal        Set to @a true if this is the final page table entry
+ *                          and effective nested page table flags should be
+ *                          merged into PGMPTWALKFAST::fEffective.  Otherwise
+ *                          set to @a false and nothing done.
+ * @param   a_GCPhysOut     Where to store the guest-physical address (result).
+ * @param   a_pWalk         The @a pWalk argument to the function.
+ */
+#  define PGM_GST_SLAT_WALK_FAST(a_pVCpu, a_GCPtrNested, a_GCPhysNested, a_fFinal, a_GCPhysOut, a_pWalk) \
+    do { \
+        /** @todo Optimize this. Among other things, WalkSlat can be eliminated. WalkGstSlat is completely pointless. */ \
+        /** @todo pass fFlags along as appropriate... */ \
+        if (a_enmGuestSlatMode != PGMSLAT_DIRECT) \
+        { \
+            PGMPTWALK    WalkSlat; \
+            PGMPTWALKGST WalkGstSlat; \
+            int rcX; \
+            if (a_enmGuestSlatMode == PGMSLAT_EPT) \
+                rcX = PGM_GST_SLAT_NAME_EPT(Walk)(a_pVCpu, a_GCPhysNested, true /* fIsLinearAddrValid */, a_GCPtrNested, \
+                                                  &WalkSlat, &WalkGstSlat.u.Ept); \
+            else AssertFailedReturn(VERR_NOT_IMPLEMENTED); \
+            if (RT_SUCCESS(rcX)) \
+                (a_GCPhysOut) = WalkSlat.GCPhys; \
+            else \
+            { \
+                PGM_NAME(ConvertPtWalkToFast)(&WalkSlat, pWalk); \
+                return rcX; \
+            } \
+            if (a_fFinal) \
+            {   /* Merge in the nested paging flags for the final GCPhys. */ \
+                if (a_enmGuestSlatMode == PGMSLAT_EPT) \
+                    (a_pWalk)->fEffective = ((a_pWalk)->fEffective & ~PGM_PTATTRS_EPT_MASK) \
+                                          | WalkSlat.fEffective & PGM_PTATTRS_EPT_MASK; \
+                else AssertFailedReturn(VERR_NOT_IMPLEMENTED); \
+            } \
+        } \
+    } while (0)
+# else
+#  define PGM_GST_SLAT_WALK_FAST(a_pVCpu, a_GCPtrNested, a_GCPhysNested, a_fFinal, a_GCPhysOut, a_pWalk) do { } while (0)
+# endif
+# if PGM_GST_TYPE == PGM_TYPE_32BIT
+#  define PGM_GST_ENSURE_ENTRY_FLAGS_SET(a_pVCpu, a_fEffective, a_pEntryU, a_OrgEntryU, a_fFlags) do { \
+       if (!a_fSetFlags || ((a_OrgEntryU) & (a_fFlags)) == (a_fFlags)) \
+       { /* likely */ } \
+       else \
+       { \
+           ASMAtomicOrU32((a_pEntryU), (a_fFlags)); \
+           (a_fEffective) |= (a_fFlags); \
+       } \
+    } while (0)
+# else
+#  define PGM_GST_ENSURE_ENTRY_FLAGS_SET(a_pVCpu, a_fEffective, a_pEntryU, a_OrgEntryU, a_fFlags) do { \
+       if (!a_fSetFlags || ((a_OrgEntryU) & (a_fFlags)) == (a_fFlags)) \
+       { /* likely */ } \
+       else \
+       { \
+           ASMAtomicOrU64((a_pEntryU), (a_fFlags)); \
+           (a_fEffective) |= (a_fFlags); \
+       } \
+    } while (0)
+# endif
+
+
+    /*
+     * Init the walking structures.
+     */
+    RT_ZERO(*pGstWalk);
+    pWalk->GCPtr        = GCPtr;
+    pWalk->GCPhys       = 0;
+    pWalk->GCPhysNested = 0;
+    pWalk->fInfo        = 0;
+    pWalk->fFailed      = 0;
+    pWalk->fEffective   = 0;
+
+# if PGM_GST_TYPE == PGM_TYPE_32BIT \
+  || PGM_GST_TYPE == PGM_TYPE_PAE
+    /*
+     * Boundary check for PAE and 32-bit (prevents trouble further down).
+     */
+    if (RT_LIKELY(GCPtr < _4G))
+    { /* extremely likely */ }
+    else
+        return PGM_GST_NAME(WalkFastReturnNotPresent)(pVCpu, pWalk, 8);
+# endif
+
+    uint64_t fEffective;
+    {
+# if PGM_GST_TYPE == PGM_TYPE_AMD64
+        /*
+         * The PML4 table.
+         */
+        rc = pgmGstGetLongModePML4PtrEx(pVCpu, &pGstWalk->pPml4);
+        if (RT_SUCCESS(rc)) { /* probable */ }
+        else return PGM_GST_NAME(WalkFastReturnBadPhysAddr)(pVCpu, pWalk, 4, rc);
+
+        PX86PML4E pPml4e;
+        pGstWalk->pPml4e  = pPml4e  = &pGstWalk->pPml4->a[(GCPtr >> X86_PML4_SHIFT) & X86_PML4_MASK];
+        X86PML4E  Pml4e;
+        pGstWalk->Pml4e.u = Pml4e.u = ASMAtomicUoReadU64(&pPml4e->u);
+
+        if (GST_IS_PGENTRY_PRESENT(pVCpu, Pml4e)) { /* probable */ }
+        else return PGM_GST_NAME(WalkFastReturnNotPresent)(pVCpu, pWalk, 4);
+
+        if (RT_LIKELY(GST_IS_PML4E_VALID(pVCpu, Pml4e))) { /* likely */ }
+        else return PGM_GST_NAME(WalkFastReturnRsvdError)(pVCpu, pWalk, 4);
+
+        fEffective = Pml4e.u & (  X86_PML4E_P | X86_PML4E_RW | X86_PML4E_US | X86_PML4E_PWT | X86_PML4E_PCD | X86_PML4E_A
+                                | X86_PML4E_NX);
+        PGM_GST_ENSURE_ENTRY_FLAGS_SET(a_pVCpu, fEffective, &pPml4e->u, Pml4e.u, X86_PML4E_A);
+        pWalk->fEffective = fEffective;
+
+        /*
+         * The PDPT.
+         */
+        RTGCPHYS GCPhysPdpt = Pml4e.u & X86_PML4E_PG_MASK;
+        PGM_GST_SLAT_WALK_FAST(pVCpu, GCPtr, GCPhysPdpt, false /*a_fFinal*/, GCPhysPdpt, pWalk);
+        rc = PGM_GCPHYS_2_PTR_BY_VMCPU(pVCpu, GCPhysPdpt, &pGstWalk->pPdpt);
+        if (RT_SUCCESS(rc)) { /* probable */ }
+        else return PGM_GST_NAME(WalkFastReturnBadPhysAddr)(pVCpu, pWalk, 3, rc);
+
+# elif PGM_GST_TYPE == PGM_TYPE_PAE
+        rc = pgmGstGetPaePDPTPtrEx(pVCpu, &pGstWalk->pPdpt);
+        if (RT_SUCCESS(rc)) { /* probable */ }
+        else return PGM_GST_NAME(WalkFastReturnBadPhysAddr)(pVCpu, pWalk, 8, rc);
+# endif
+    }
+    {
+# if PGM_GST_TYPE == PGM_TYPE_AMD64 || PGM_GST_TYPE == PGM_TYPE_PAE
+        PX86PDPE pPdpe;
+        pGstWalk->pPdpe  = pPdpe  = &pGstWalk->pPdpt->a[(GCPtr >> GST_PDPT_SHIFT) & GST_PDPT_MASK];
+        X86PDPE  Pdpe;
+        pGstWalk->Pdpe.u = Pdpe.u = ASMAtomicUoReadU64(&pPdpe->u);
+
+        if (GST_IS_PGENTRY_PRESENT(pVCpu, Pdpe)) { /* probable */ }
+        else return PGM_GST_NAME(WalkFastReturnNotPresent)(pVCpu, pWalk, 3);
+
+        if (RT_LIKELY(GST_IS_PDPE_VALID(pVCpu, Pdpe))) { /* likely */ }
+        else return PGM_GST_NAME(WalkFastReturnRsvdError)(pVCpu, pWalk, 3);
+
+#  if PGM_GST_TYPE == PGM_TYPE_AMD64
+        fEffective &= (Pdpe.u & (  X86_PDPE_P   | X86_PDPE_RW  | X86_PDPE_US
+                                 | X86_PDPE_PWT | X86_PDPE_PCD | X86_PDPE_A));
+        fEffective |= Pdpe.u & X86_PDPE_LM_NX;
+        PGM_GST_ENSURE_ENTRY_FLAGS_SET(a_pVCpu, fEffective, &pPdpe->u, Pdpe.u, X86_PDE_A);
+#  else
+        /*
+         * NX in the legacy-mode PAE PDPE is reserved. The valid check above ensures the NX bit is not set.
+         * The RW, US, A bits MBZ in PAE PDPTE entries but must be 1 the way we compute cumulative (effective) access rights.
+         */
+        Assert(!(Pdpe.u & X86_PDPE_LM_NX));
+        fEffective = X86_PDPE_P | X86_PDPE_RW  | X86_PDPE_US | X86_PDPE_A
+                   | (Pdpe.u & (X86_PDPE_PWT | X86_PDPE_PCD));
+#  endif
+        pWalk->fEffective = fEffective;
+
+        /*
+         * The PD.
+         */
+        RTGCPHYS GCPhysPd = Pdpe.u & X86_PDPE_PG_MASK;
+        PGM_GST_SLAT_WALK_FAST(pVCpu, GCPtr, GCPhysPd, false /*a_fFinal*/, GCPhysPd, pWalk);
+        rc = PGM_GCPHYS_2_PTR_BY_VMCPU(pVCpu, GCPhysPd, &pGstWalk->pPd);
+        if (RT_SUCCESS(rc)) { /* probable */ }
+        else return PGM_GST_NAME(WalkFastReturnBadPhysAddr)(pVCpu, pWalk, 2, rc);
+
+# elif PGM_GST_TYPE == PGM_TYPE_32BIT
+        rc = pgmGstGet32bitPDPtrEx(pVCpu, &pGstWalk->pPd);
+        if (RT_SUCCESS(rc)) { /* probable */ }
+        else return PGM_GST_NAME(WalkFastReturnBadPhysAddr)(pVCpu, pWalk, 8, rc);
+# endif
+    }
+    {
+        PGSTPDE pPde;
+        pGstWalk->pPde  = pPde  = &pGstWalk->pPd->a[(GCPtr >> GST_PD_SHIFT) & GST_PD_MASK];
+        GSTPDE  Pde;
+# if PGM_GST_TYPE != PGM_TYPE_32BIT
+        pGstWalk->Pde.u = Pde.u = ASMAtomicUoReadU64(&pPde->u);
+# else
+        pGstWalk->Pde.u = Pde.u = ASMAtomicUoReadU32(&pPde->u);
+# endif
+        if (GST_IS_PGENTRY_PRESENT(pVCpu, Pde)) { /* probable */ }
+        else return PGM_GST_NAME(WalkFastReturnNotPresent)(pVCpu, pWalk, 2);
+        if ((Pde.u & X86_PDE_PS) && GST_IS_PSE_ACTIVE(pVCpu))
+        {
+            if (RT_LIKELY(GST_IS_BIG_PDE_VALID(pVCpu, Pde))) { /* likely */ }
+            else return PGM_GST_NAME(WalkFastReturnRsvdError)(pVCpu, pWalk, 2);
+
+            /*
+             * We're done.
+             */
+            pWalk->fInfo = PGM_WALKINFO_SUCCEEDED | PGM_WALKINFO_BIG_PAGE;
+
+# if PGM_GST_TYPE == PGM_TYPE_32BIT
+            fEffective  = Pde.u & (X86_PDE4M_P | X86_PDE4M_RW | X86_PDE4M_US | X86_PDE4M_PWT | X86_PDE4M_PCD | X86_PDE4M_A);
+# else
+            fEffective &= Pde.u & (X86_PDE4M_P | X86_PDE4M_RW | X86_PDE4M_US | X86_PDE4M_PWT | X86_PDE4M_PCD | X86_PDE4M_A);
+            fEffective |= Pde.u & X86_PDE2M_PAE_NX;
+# endif
+            fEffective |= Pde.u & (X86_PDE4M_D | X86_PDE4M_G);
+            fEffective |= (Pde.u & X86_PDE4M_PAT) >> X86_PDE4M_PAT_SHIFT;
+
+            rc = VINF_SUCCESS;
+            if (a_fSetFlags)
+            {
+                /* We have to validate the access before setting any flags. */
+                uint32_t fFailed = 0;
+                if ((fFlags & PGMQPAGE_F_USER_MODE) && !(fEffective & X86_PDE4M_US))
+                    fFailed |= PGM_WALKFAIL_NOT_ACCESSIBLE_BY_MODE;
+                if (fFlags & PGMQPAGE_F_WRITE)
+                {
+                    if (   (fEffective & X86_PDE4M_RW)
+                        || (fFlags & (PGMQPAGE_F_USER_MODE | PGMQPAGE_F_CR0_WP0)) == PGMQPAGE_F_CR0_WP0)
+                    { /* likely*/ }
+                    else fFailed |= PGM_WALKFAIL_NOT_WRITABLE;
+                }
+# if PGM_GST_TYPE != PGM_TYPE_32BIT
+                else if (fFlags & PGMQPAGE_F_EXECUTE)
+                {
+                    if (!(fEffective & X86_PDE2M_PAE_NX) || !pVCpu->pgm.s.fNoExecuteEnabled) { /* likely */ }
+                    else fFailed |= PGM_WALKFAIL_NOT_EXECUTABLE;
+                }
+# endif
+                if (fFailed == 0)
+                {
+                    if (!(fFlags & PGMQPAGE_F_WRITE))
+                        PGM_GST_ENSURE_ENTRY_FLAGS_SET(a_pVCpu, fEffective, &pPde->u, Pde.u, X86_PDE4M_A);
+                    else
+                        PGM_GST_ENSURE_ENTRY_FLAGS_SET(a_pVCpu, fEffective, &pPde->u, Pde.u, X86_PDE4M_A | X86_PDE4M_D);
+                }
+                else
+                {
+                    pWalk->fFailed = fFailed | (2U << PGM_WALKFAIL_LEVEL_SHIFT);
+                    pWalk->fInfo   = PGM_WALKINFO_BIG_PAGE;
+                    rc = VERR_ACCESS_DENIED;
+                }
+            }
+
+            pWalk->fEffective = fEffective;
+            Assert(GST_IS_NX_ACTIVE(pVCpu) || !(fEffective & PGM_PTATTRS_NX_MASK));
+            Assert(fEffective & PGM_PTATTRS_R_MASK);
+
+            RTGCPHYS GCPhysPde = GST_GET_BIG_PDE_GCPHYS(pVCpu->CTX_SUFF(pVM), Pde)
+                               | (GCPtr & GST_BIG_PAGE_OFFSET_MASK);
+            PGM_GST_SLAT_WALK_FAST(pVCpu, GCPtr, GCPhysPde, true /*a_fFinal*/, GCPhysPde, pWalk);
+            pWalk->GCPhys     = GCPhysPde;
+            PGM_A20_APPLY_TO_VAR(pVCpu, pWalk->GCPhys); /** @todo why do we apply it here and not below?!? */
+            return rc;
+        }
+
+        if (RT_UNLIKELY(!GST_IS_PDE_VALID(pVCpu, Pde)))
+            return PGM_GST_NAME(WalkFastReturnRsvdError)(pVCpu, pWalk, 2);
+# if PGM_GST_TYPE == PGM_TYPE_32BIT
+        fEffective  = Pde.u & (X86_PDE_P | X86_PDE_RW | X86_PDE_US | X86_PDE_PWT | X86_PDE_PCD | X86_PDE_A);
+# else
+        fEffective &= Pde.u & (X86_PDE_P | X86_PDE_RW | X86_PDE_US | X86_PDE_PWT | X86_PDE_PCD | X86_PDE_A);
+        fEffective |= Pde.u & X86_PDE_PAE_NX;
+# endif
+        PGM_GST_ENSURE_ENTRY_FLAGS_SET(a_pVCpu, fEffective, &pPde->u, Pde.u, X86_PDE_A);
+        pWalk->fEffective = fEffective;
+
+        /*
+         * The PT.
+         */
+        RTGCPHYS GCPhysPt = GST_GET_PDE_GCPHYS(Pde);
+        PGM_GST_SLAT_WALK_FAST(pVCpu, GCPtr, GCPhysPt, false /*a_fFinal*/, GCPhysPt, pWalk);
+        rc = PGM_GCPHYS_2_PTR_BY_VMCPU(pVCpu, GCPhysPt, &pGstWalk->pPt);
+        if (RT_SUCCESS(rc)) { /* probable */ }
+        else return PGM_GST_NAME(WalkFastReturnBadPhysAddr)(pVCpu, pWalk, 1, rc);
+    }
+    {
+        PGSTPTE pPte;
+        pGstWalk->pPte  = pPte  = &pGstWalk->pPt->a[(GCPtr >> GST_PT_SHIFT) & GST_PT_MASK];
+        GSTPTE  Pte;
+# if PGM_GST_TYPE != PGM_TYPE_32BIT
+        pGstWalk->Pte.u = Pte.u = ASMAtomicUoReadU64(&pPte->u);
+# else
+        pGstWalk->Pte.u = Pte.u = ASMAtomicUoReadU32(&pPte->u);
+# endif
+
+        if (GST_IS_PGENTRY_PRESENT(pVCpu, Pte)) { /* probable */ }
+        else return PGM_GST_NAME(WalkFastReturnNotPresent)(pVCpu, pWalk, 1);
+
+        if (RT_LIKELY(GST_IS_PTE_VALID(pVCpu, Pte))) { /* likely */ }
+        else return PGM_GST_NAME(WalkFastReturnRsvdError)(pVCpu, pWalk, 1);
+
+        /*
+         * We're done.
+         */
+        pWalk->fInfo = PGM_WALKINFO_SUCCEEDED;
+
+        fEffective &= Pte.u & (X86_PTE_P | X86_PTE_RW | X86_PTE_US | X86_PTE_PWT | X86_PTE_PCD | X86_PTE_A);
+# if PGM_GST_TYPE != PGM_TYPE_32BIT
+        fEffective |= Pte.u & (X86_PTE_D | X86_PTE_PAT | X86_PTE_G | X86_PTE_PAE_NX);
+# else
+        fEffective |= Pte.u & (X86_PTE_D | X86_PTE_PAT | X86_PTE_G);
+# endif
+
+        rc = VINF_SUCCESS;
+        if (a_fSetFlags)
+        {
+            /* We have to validate the access before setting any flags. */
+            uint32_t fFailed = 0;
+            if ((fFlags & PGMQPAGE_F_USER_MODE) && !(fEffective & X86_PTE_US))
+                fFailed |= PGM_WALKFAIL_NOT_ACCESSIBLE_BY_MODE;
+            if (fFlags & PGMQPAGE_F_WRITE)
+            {
+                if ((fEffective & X86_PTE_RW) || (fFlags & (PGMQPAGE_F_USER_MODE | PGMQPAGE_F_CR0_WP0)) == PGMQPAGE_F_CR0_WP0)
+                { /* likely*/ }
+                else fFailed |= PGM_WALKFAIL_NOT_WRITABLE;
+            }
+# if PGM_GST_TYPE != PGM_TYPE_32BIT
+            else if (fFlags & PGMQPAGE_F_EXECUTE)
+            {
+                if (!(fEffective & X86_PTE_PAE_NX) || !pVCpu->pgm.s.fNoExecuteEnabled) { /* likely */ }
+                else fFailed |= PGM_WALKFAIL_NOT_EXECUTABLE;
+            }
+# endif
+            if (fFailed == 0)
+            {
+                if (!(fFlags & PGMQPAGE_F_WRITE))
+                    PGM_GST_ENSURE_ENTRY_FLAGS_SET(a_pVCpu, fEffective, &pPte->u, Pte.u, X86_PTE_A);
+                else
+                    PGM_GST_ENSURE_ENTRY_FLAGS_SET(a_pVCpu, fEffective, &pPte->u, Pte.u, X86_PTE_A | X86_PTE_D);
+            }
+            else
+            {
+                pWalk->fFailed = fFailed | (1U << PGM_WALKFAIL_LEVEL_SHIFT);
+                pWalk->fInfo   = 0;
+                rc = VERR_ACCESS_DENIED;
+            }
+        }
+
+        pWalk->fEffective = fEffective;
+        Assert(GST_IS_NX_ACTIVE(pVCpu) || !(fEffective & PGM_PTATTRS_NX_MASK));
+        Assert(fEffective & PGM_PTATTRS_R_MASK);
+
+        RTGCPHYS GCPhysPte = GST_GET_PTE_GCPHYS(Pte)
+                           | (GCPtr & GUEST_PAGE_OFFSET_MASK);
+        PGM_GST_SLAT_WALK_FAST(pVCpu, GCPtr, GCPhysPte, true /*a_fFinal*/, GCPhysPte, pWalk);
+        pWalk->GCPhys     = GCPhysPte;
+        return rc;
+    }
+# undef PGM_GST_SLAT_WALK_FAST
+# undef PGM_GST_ENSURE_ENTRY_FLAGS_SET
+}
+
+#endif /* 32BIT, PAE, AMD64 */
+
+/**
+ * Guest virtual to guest physical + info translation, the faster and better
+ * version.
+ *
+ * @returns VBox status code.
+ * @param   pVCpu       The cross context virtual CPU structure.
+ * @param   GCPtr       Guest Context virtual address of the page.
+ * @param   fFlags      PGMQPAGE_F_XXX
+ * @param   pWalk       Where to store the page walk info.
+ * @thread  EMT(pVCpu)
+ */
+#define PGM_GET_PAGE_F_WRITE
+#define PGM_GET_PAGE_F_READ
+PGM_GST_DECL(int, QueryPageFast)(PVMCPUCC pVCpu, RTGCPTR GCPtr, uint32_t fFlags, PPGMPTWALKFAST pWalk)
+{
+#if PGM_GST_TYPE == PGM_TYPE_REAL \
+ || PGM_GST_TYPE == PGM_TYPE_PROT
+
+# ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
+    if (pVCpu->pgm.s.enmGuestSlatMode == PGMSLAT_EPT)
+    {
+        /** @todo optimize this case as well.   */
+        /** @todo pass fFlags along. */
+        PGMPTWALK    WalkSlat;
+        PGMPTWALKGST WalkGstSlat;
+        int const rc = pgmGstSlatWalk(pVCpu, GCPtr, true /* fIsLinearAddrValid */, GCPtr, &WalkSlat, &WalkGstSlat);
+        if (RT_SUCCESS(rc))
+        {
+            PGMPTWALKFAST_ZERO(pWalk);
+            pWalk->GCPtr        = GCPtr;
+            pWalk->GCPhys       = WalkSlat.GCPhys;
+            pWalk->GCPhysNested = 0;
+            pWalk->u64Union     = 0;
+            pWalk->fSucceeded   = true;
+            pWalk->fEffective   = X86_PTE_P | X86_PTE_RW | X86_PTE_US | X86_PTE_A | X86_PTE_D;
+        }
+        else
+            PGM_NAME(ConvertPtWalkToFast)(&WalkSlat, pWalk);
+        return rc;
+    }
+# endif
+
+    /*
+     * Fake it.
+     */
+    pWalk->GCPtr        = GCPtr;
+    pWalk->GCPhys       = GCPtr;
+    pWalk->GCPhysNested = 0;
+    pWalk->fInfo        = PGM_WALKINFO_SUCCEEDED;
+    pWalk->fFailed      = PGM_WALKFAIL_SUCCESS;
+    pWalk->fEffective   = X86_PTE_P | X86_PTE_RW | X86_PTE_US | X86_PTE_A | X86_PTE_D;
+    RT_NOREF(pVCpu, fFlags);
+    return VINF_SUCCESS;
+
+#elif PGM_GST_TYPE == PGM_TYPE_32BIT \
+   || PGM_GST_TYPE == PGM_TYPE_PAE \
+   || PGM_GST_TYPE == PGM_TYPE_AMD64
+
+    GSTPTWALK GstWalk;
+    int rc;
+# if defined(VBOX_WITH_NESTED_HWVIRT_VMX_EPT) || defined(VBOX_WITH_NESTED_HWVIRT_SVM_XXX)
+    switch (pVCpu->pgm.s.enmGuestSlatMode)
+    {
+        case PGMSLAT_DIRECT:
+# endif
+            if (fFlags)
+                rc = PGM_GST_NAME(WalkFast)<PGMSLAT_DIRECT, true>(pVCpu, GCPtr, fFlags, pWalk, &GstWalk);
+            else
+                rc = PGM_GST_NAME(WalkFast)<PGMSLAT_DIRECT, false>(pVCpu, GCPtr, 0, pWalk, &GstWalk);
+# if defined(VBOX_WITH_NESTED_HWVIRT_VMX_EPT) || defined(VBOX_WITH_NESTED_HWVIRT_SVM_XXX)
+            break;
+#  ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
+        case PGMSLAT_EPT:
+            if (fFlags)
+                rc = PGM_GST_NAME(WalkFast)<PGMSLAT_EPT, true>(pVCpu, GCPtr, fFlags, pWalk, &GstWalk);
+            else
+                rc = PGM_GST_NAME(WalkFast)<PGMSLAT_EPT, false>(pVCpu, GCPtr, 0, pWalk, &GstWalk);
+            break;
+#  endif
+#  ifdef VBOX_WITH_NESTED_HWVIRT_SVM_XXX
+        case PGMSLAT_32BIT:
+            if (fFlags)
+                rc = PGM_GST_NAME(WalkFast)<PGMSLAT_32BIT, true>(pVCpu, GCPtr, fFlags, pWalk, &GstWalk);
+            else
+                rc = PGM_GST_NAME(WalkFast)<PGMSLAT_32BIT, false>(pVCpu, GCPtr, 0, pWalk, &GstWalk);
+            break;
+        case PGMSLAT_PAE:
+            if (fFlags)
+                rc = PGM_GST_NAME(WalkFast)<PGMSLAT_PAE, true>(pVCpu, GCPtr, fFlags, pWalk, &GstWalk);
+            else
+                rc = PGM_GST_NAME(WalkFast)<PGMSLAT_PAE, false>(pVCpu, GCPtr, 0, pWalk, &GstWalk);
+            break;
+        case PGMSLAT_AMD64:
+            if (fFlags)
+                rc = PGM_GST_NAME(WalkFast)<PGMSLAT_AMD64, true>(pVCpu, GCPtr, fFlags, pWalk, &GstWalk);
+            else
+                rc = PGM_GST_NAME(WalkFast)<PGMSLAT_AMD64, false>(pVCpu, GCPtr, 0, pWalk, &GstWalk);
+            break;
+#  endif
+        default:
+            AssertFailedReturn(VERR_INTERNAL_ERROR_4);
+    }
+# endif
+    if (RT_SUCCESS(rc))
+    {
+        Assert(pWalk->fInfo & PGM_WALKINFO_SUCCEEDED);
+        Assert(pWalk->GCPtr == GCPtr);
+        Assert((pWalk->GCPhys & GUEST_PAGE_OFFSET_MASK) == (GCPtr & GUEST_PAGE_OFFSET_MASK));
+        return VINF_SUCCESS;
+    }
+    return rc;
+
+#else
+# error "shouldn't be here!"
+    /* something else... */
+    return VERR_NOT_SUPPORTED;
+#endif
+}
+
+/* x x x x x x x x */
+/* x x x x x x x x */
 
 /**
Index: /trunk/src/VBox/VMM/VMMAll/PGMAllGstSlatEpt.cpp.h
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/PGMAllGstSlatEpt.cpp.h	(revision 104931)
+++ /trunk/src/VBox/VMM/VMMAll/PGMAllGstSlatEpt.cpp.h	(revision 104932)
@@ -102,5 +102,5 @@
     pWalk->fNotPresent = true;
     pWalk->uLevel      = uLevel;
-    pWalk->fFailed     = s_afEptViolations[idxViolationType];
+    pWalk->fFailed     = s_afEptViolations[idxViolationType] | ((uint32_t)uLevel << PGM_WALKFAIL_LEVEL_SHIFT);
     return VERR_PAGE_TABLE_NOT_PRESENT;
 }
@@ -121,5 +121,5 @@
     pWalk->fBadPhysAddr = true;
     pWalk->uLevel       = uLevel;
-    pWalk->fFailed      = PGM_WALKFAIL_EPT_VIOLATION;
+    pWalk->fFailed      = PGM_WALKFAIL_EPT_VIOLATION         | ((uint32_t)uLevel << PGM_WALKFAIL_LEVEL_SHIFT);
     return VERR_PAGE_TABLE_NOT_PRESENT;
 }
@@ -139,5 +139,5 @@
     pWalk->fRsvdError = true;
     pWalk->uLevel     = uLevel;
-    pWalk->fFailed    = PGM_WALKFAIL_EPT_MISCONFIG;
+    pWalk->fFailed    = PGM_WALKFAIL_EPT_MISCONFIG           | ((uint32_t)uLevel << PGM_WALKFAIL_LEVEL_SHIFT);
     return VERR_PAGE_TABLE_NOT_PRESENT;
 }
Index: /trunk/src/VBox/VMM/include/IEMInternal.h
===================================================================
--- /trunk/src/VBox/VMM/include/IEMInternal.h	(revision 104931)
+++ /trunk/src/VBox/VMM/include/IEMInternal.h	(revision 104932)
@@ -504,4 +504,16 @@
 #define IEMTLBE_F_PHYS_REV          UINT64_C(0xfffffffffffffc00) /**< Physical revision mask. @sa IEMTLB_PHYS_REV_INCR */
 /** @} */
+AssertCompile(PGMIEMGCPHYS2PTR_F_NO_WRITE     == IEMTLBE_F_PG_NO_WRITE);
+AssertCompile(PGMIEMGCPHYS2PTR_F_NO_READ      == IEMTLBE_F_PG_NO_READ);
+AssertCompile(PGMIEMGCPHYS2PTR_F_NO_MAPPINGR3 == IEMTLBE_F_NO_MAPPINGR3);
+AssertCompile(PGMIEMGCPHYS2PTR_F_UNASSIGNED   == IEMTLBE_F_PG_UNASSIGNED);
+AssertCompile(PGMIEMGCPHYS2PTR_F_CODE_PAGE    == IEMTLBE_F_PG_CODE_PAGE);
+/** The bits set by PGMPhysIemGCPhys2PtrNoLock. */
+#define IEMTLBE_GCPHYS2PTR_MASK     (  PGMIEMGCPHYS2PTR_F_NO_WRITE \
+                                     | PGMIEMGCPHYS2PTR_F_NO_READ \
+                                     | PGMIEMGCPHYS2PTR_F_NO_MAPPINGR3 \
+                                     | PGMIEMGCPHYS2PTR_F_UNASSIGNED \
+                                     | PGMIEMGCPHYS2PTR_F_CODE_PAGE \
+                                     | IEMTLBE_F_PHYS_REV )
 
 
@@ -6100,5 +6112,5 @@
 VBOXSTRICTRC    iemVmxVmexitEvent(PVMCPUCC pVCpu, uint8_t uVector, uint32_t fFlags, uint32_t uErrCode, uint64_t uCr2, uint8_t cbInstr)  RT_NOEXCEPT;
 VBOXSTRICTRC    iemVmxVmexitEventDoubleFault(PVMCPUCC pVCpu) RT_NOEXCEPT;
-VBOXSTRICTRC    iemVmxVmexitEpt(PVMCPUCC pVCpu, PPGMPTWALK pWalk, uint32_t fAccess, uint32_t fSlatFail, uint8_t cbInstr) RT_NOEXCEPT;
+VBOXSTRICTRC    iemVmxVmexitEpt(PVMCPUCC pVCpu, PPGMPTWALKFAST pWalk, uint32_t fAccess, uint32_t fSlatFail, uint8_t cbInstr) RT_NOEXCEPT;
 VBOXSTRICTRC    iemVmxVmexitPreemptTimer(PVMCPUCC pVCpu) RT_NOEXCEPT;
 VBOXSTRICTRC    iemVmxVmexitInstrMwait(PVMCPUCC pVCpu, bool fMonitorHwArmed, uint8_t cbInstr) RT_NOEXCEPT;
Index: /trunk/src/VBox/VMM/include/PGMInternal.h
===================================================================
--- /trunk/src/VBox/VMM/include/PGMInternal.h	(revision 104931)
+++ /trunk/src/VBox/VMM/include/PGMInternal.h	(revision 104932)
@@ -2810,4 +2810,5 @@
     uint32_t                        uType;
     DECLCALLBACKMEMBER(int, pfnGetPage,(PVMCPUCC pVCpu, RTGCPTR GCPtr, PPGMPTWALK pWalk));
+    DECLCALLBACKMEMBER(int, pfnQueryPageFast,(PVMCPUCC pVCpu, RTGCPTR GCPtr, uint32_t fFlags, PPGMPTWALKFAST pWalk));
     DECLCALLBACKMEMBER(int, pfnModifyPage,(PVMCPUCC pVCpu, RTGCPTR GCPtr, size_t cbPages, uint64_t fFlags, uint64_t fMask));
     DECLCALLBACKMEMBER(int, pfnEnter,(PVMCPUCC pVCpu, RTGCPHYS GCPhysCR3));
