Index: /trunk/include/VBox/vmm/cpum.h
===================================================================
--- /trunk/include/VBox/vmm/cpum.h	(revision 75492)
+++ /trunk/include/VBox/vmm/cpum.h	(revision 75493)
@@ -2085,4 +2085,6 @@
 VMM_INT_DECL(bool)      CPUMVmxGetIoBitmapPermission(void const *pvIoBitmapA, void const *pvIoBitmapB, uint16_t uPort,
                                                      uint8_t cbAccess);
+VMM_INT_DECL(VBOXSTRICTRC) CPUMVmxApicAccessPageRegister(PVMCPU pVCpu, RTGCPHYS GCPhysApicAccess);
+VMM_INT_DECL(VBOXSTRICTRC) CPUMVmxApicAccessPageDeregister(PVMCPU pVCpu, RTGCPHYS GCPhysApicAccess);
 /** @} */
 
Index: /trunk/include/VBox/vmm/hm_vmx.h
===================================================================
--- /trunk/include/VBox/vmm/hm_vmx.h	(revision 75492)
+++ /trunk/include/VBox/vmm/hm_vmx.h	(revision 75493)
@@ -3833,4 +3833,5 @@
     kVmxVDiag_Vmentry_AddrApicAccess,
     kVmxVDiag_Vmentry_AddrApicAccessEqVirtApic,
+    kVmxVDiag_Vmentry_AddrApicAccessHandlerReg,
     kVmxVDiag_Vmentry_AddrEntryMsrLoad,
     kVmxVDiag_Vmentry_AddrExitMsrLoad,
Index: /trunk/include/VBox/vmm/iem.h
===================================================================
--- /trunk/include/VBox/vmm/iem.h	(revision 75492)
+++ /trunk/include/VBox/vmm/iem.h	(revision 75493)
@@ -329,4 +329,6 @@
 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX
 VMM_INT_DECL(VBOXSTRICTRC)  IEMExecVmxVirtApicAccessMsr(PVMCPU pVCpu, uint32_t idMsr, uint64_t *pu64Val, bool fWrite);
+VMM_INT_DECL(VBOXSTRICTRC)  IEMExecVmxVirtApicAccessMem(PVMCPU pVCpu, uint16_t offAccess, size_t cbAccess, void *pvData,
+                                                        bool fWrite);
 VMM_INT_DECL(VBOXSTRICTRC)  IEMExecVmxVmexitPreemptTimer(PVMCPU pVCpu);
 VMM_INT_DECL(VBOXSTRICTRC)  IEMExecVmxVmexitExtInt(PVMCPU pVCpu, uint8_t uVector, bool fIntPending);
Index: /trunk/src/VBox/VMM/VMMAll/CPUMAllMsrs.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/CPUMAllMsrs.cpp	(revision 75492)
+++ /trunk/src/VBox/VMM/VMMAll/CPUMAllMsrs.cpp	(revision 75493)
@@ -1278,15 +1278,10 @@
         && CPUMIsGuestVmxProcCtls2Set(pVCpu, &pVCpu->cpum.s.Guest, VMX_PROC_CTLS2_VIRT_X2APIC_MODE))
     {
-        /** @todo NSTVMX: perhaps IEMExecVmxVirtApicAccessMsr should be moved to
-         *        HMVMXAll.cpp? */
         VBOXSTRICTRC rcStrict = IEMExecVmxVirtApicAccessMsr(pVCpu, idMsr, puValue, false /* fWrite */);
-        Assert(rcStrict == VINF_SUCCESS || rcStrict == VERR_OUT_OF_RANGE || rcStrict == VINF_VMX_INTERCEPT_NOT_ACTIVE);
-        if (rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE)
-        {
-            if (rcStrict == VERR_OUT_OF_RANGE)
-                return VERR_CPUM_RAISE_GP_0;
-            Assert(rcStrict == VINF_SUCCESS);
+        if (rcStrict == VINF_VMX_MODIFIES_BEHAVIOR)
             return VINF_SUCCESS;
-        }
+        if (rcStrict == VERR_OUT_OF_RANGE)
+            return VERR_CPUM_RAISE_GP_0;
+        Assert(rcStrict == VINF_VMX_INTERCEPT_NOT_ACTIVE);
     }
 #endif
@@ -1303,15 +1298,10 @@
         && CPUMIsGuestVmxProcCtls2Set(pVCpu, &pVCpu->cpum.s.Guest, VMX_PROC_CTLS2_VIRT_X2APIC_MODE))
     {
-        /** @todo NSTVMX: perhaps IEMExecVmxVirtApicAccessMsr should be moved to
-         *        HMVMXAll.cpp? */
         VBOXSTRICTRC rcStrict = IEMExecVmxVirtApicAccessMsr(pVCpu, idMsr, &uValue, true /* fWrite */);
-        Assert(rcStrict == VINF_SUCCESS || rcStrict == VERR_OUT_OF_RANGE || rcStrict == VINF_VMX_INTERCEPT_NOT_ACTIVE);
-        if (rcStrict != VINF_VMX_INTERCEPT_NOT_ACTIVE)
-        {
-            if (rcStrict == VERR_OUT_OF_RANGE)
-                return VERR_CPUM_RAISE_GP_0;
-            Assert(rcStrict == VINF_SUCCESS);
+        if (rcStrict == VINF_VMX_MODIFIES_BEHAVIOR)
             return VINF_SUCCESS;
-        }
+        if (rcStrict == VERR_OUT_OF_RANGE)
+            return VERR_CPUM_RAISE_GP_0;
+        Assert(rcStrict == VINF_VMX_INTERCEPT_NOT_ACTIVE);
     }
 #endif
Index: /trunk/src/VBox/VMM/VMMAll/CPUMAllVmx.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/CPUMAllVmx.cpp	(revision 75492)
+++ /trunk/src/VBox/VMM/VMMAll/CPUMAllVmx.cpp	(revision 75493)
@@ -21,6 +21,10 @@
 *********************************************************************************************************************************/
 #define LOG_GROUP LOG_GROUP_CPUM
+#include <VBox/log.h>
 #include <VBox/vmm/cpum.h>
-#include <VBox/log.h>
+#include "CPUMInternal.h"
+#include <VBox/vmm/iem.h>
+#include <VBox/vmm/pgm.h>
+#include <VBox/vmm/vm.h>
 
 
@@ -134,2 +138,58 @@
 }
 
+#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
+/**
+ * @callback_method_impl{FNPGMPHYSHANDLER, VMX APIC-access page accesses}
+ *
+ * @remarks The @a pvUser argument is currently unused.
+ */
+PGM_ALL_CB2_DECL(VBOXSTRICTRC) cpumVmxApicAccessPageHandler(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhysFault, void *pvPhys,
+                                                            void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType,
+                                                            PGMACCESSORIGIN enmOrigin, void *pvUser)
+{
+    RT_NOREF4(pVM, pvPhys, enmOrigin, pvUser);
+
+    uint16_t const offAccess = (GCPhysFault & PAGE_OFFSET_MASK);
+    bool const fWrite = RT_BOOL(enmAccessType == PGMACCESSTYPE_WRITE);
+    VBOXSTRICTRC rcStrict = IEMExecVmxVirtApicAccessMem(pVCpu, offAccess, cbBuf, pvBuf, fWrite);
+    if (rcStrict == VINF_VMX_MODIFIES_BEHAVIOR)
+        rcStrict = VINF_SUCCESS;
+    return rcStrict;
+}
+#endif
+
+
+/**
+ * Registers the PGM physical page handelr for teh VMX APIC-access page.
+ *
+ * @returns VBox status code.
+ * @param   pVCpu               The cross context virtual CPU structure.
+ * @param   GCPhysApicAccess    The guest-physical address of the APIC-access page.
+ */
+VMM_INT_DECL(VBOXSTRICTRC) CPUMVmxApicAccessPageRegister(PVMCPU pVCpu, RTGCPHYS GCPhysApicAccess)
+{
+    PVM pVM = pVCpu->CTX_SUFF(pVM);
+    int rc = PGMHandlerPhysicalRegister(pVM, GCPhysApicAccess, GCPhysApicAccess, pVM->cpum.s.hVmxApicAccessPage,
+                                        NIL_RTR3PTR /* pvUserR3 */, NIL_RTR0PTR /* pvUserR0 */,  NIL_RTRCPTR /* pvUserRC */,
+                                        NULL /* pszDesc */);
+    return rc;
+}
+
+
+/**
+ * Registers the PGM physical page handelr for teh VMX APIC-access page.
+ *
+ * @returns VBox status code.
+ * @param   pVCpu               The cross context virtual CPU structure.
+ * @param   GCPhysApicAccess    The guest-physical address of the APIC-access page.
+ */
+VMM_INT_DECL(VBOXSTRICTRC) CPUMVmxApicAccessPageDeregister(PVMCPU pVCpu, RTGCPHYS GCPhysApicAccess)
+{
+    /** @todo NSTVMX: If there's anything else to do while APIC-access page is
+     *        de-registered, do it here. */
+    PVM pVM = pVCpu->CTX_SUFF(pVM);
+    if (PGMHandlerPhysicalIsRegistered(pVM, GCPhysApicAccess))
+        return PGMHandlerPhysicalDeregister(pVM, GCPhysApicAccess);
+    return VINF_SUCCESS;
+}
+
Index: /trunk/src/VBox/VMM/VMMAll/HMVMXAll.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/HMVMXAll.cpp	(revision 75492)
+++ /trunk/src/VBox/VMM/VMMAll/HMVMXAll.cpp	(revision 75493)
@@ -132,4 +132,5 @@
     VMXV_DIAG_DESC(kVmxVDiag_Vmentry_AddrApicAccess           , "AddrApicAccess"            ),
     VMXV_DIAG_DESC(kVmxVDiag_Vmentry_AddrApicAccessEqVirtApic , "AddrApicAccessEqVirtApic"  ),
+    VMXV_DIAG_DESC(kVmxVDiag_Vmentry_AddrApicAccessHandlerReg , "AddrApicAccessHandlerReg"  ),
     VMXV_DIAG_DESC(kVmxVDiag_Vmentry_AddrEntryMsrLoad         , "AddrEntryMsrLoad"          ),
     VMXV_DIAG_DESC(kVmxVDiag_Vmentry_AddrExitMsrLoad          , "AddrExitMsrLoad"           ),
Index: /trunk/src/VBox/VMM/VMMAll/IEMAll.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/IEMAll.cpp	(revision 75492)
+++ /trunk/src/VBox/VMM/VMMAll/IEMAll.cpp	(revision 75493)
@@ -8910,23 +8910,4 @@
     iemMemUpdateWrittenCounter(pVCpu, fAccess, cbMem);
     *ppvMem = pvMem;
-
-#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
-    /*
-     * Check if this is an APIC-access and whether it needs to be virtualized.
-     */
-    if (   CPUMIsGuestInVmxNonRootMode(IEM_GET_CTX(pVCpu))
-        && IEM_VMX_IS_PROCCTLS2_SET(pVCpu, VMX_PROC_CTLS2_VIRT_APIC_ACCESS))
-    {
-        RTGCPHYS const GCPhysMemAccessBase  = GCPhysFirst & ~(RTGCPHYS)PAGE_OFFSET_MASK;
-        RTGCPHYS const GCPhysApicAccessBase = CPUMGetGuestVmxApicAccessPageAddr(pVCpu, IEM_GET_CTX(pVCpu))
-                                            & ~(RTGCPHYS)PAGE_OFFSET_MASK;
-        if (GCPhysMemAccessBase == GCPhysApicAccessBase)
-        {
-            Assert(pvMem);
-            uint16_t const offAccess = GCPhysFirst & (RTGCPHYS)PAGE_OFFSET_MASK;
-            return iemVmxVirtApicAccessMem(pVCpu, offAccess, cbMem, pvMem, fAccess);
-        }
-    }
-#endif
 
     return VINF_SUCCESS;
@@ -13951,6 +13932,5 @@
             int32_t const rcPassUp = pVCpu->iem.s.rcPassUp;
 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX
-            if (   (   rcStrict == VINF_VMX_VMEXIT
-                    || rcStrict == VINF_VMX_MODIFIES_BEHAVIOR)
+            if (   rcStrict == VINF_VMX_VMEXIT
                 && rcPassUp == VINF_SUCCESS)
                 rcStrict = VINF_SUCCESS;
@@ -15701,8 +15681,9 @@
  *
  * @returns Strict VBox status code.
- * @retval  VINF_SUCCESS if the MSR access was virtualized.
+ * @retval  VINF_VMX_MODIFIES_BEHAVIOR if the MSR access was virtualized.
  * @retval  VINF_VMX_INTERCEPT_NOT_ACTIVE if the MSR access must be handled by
  *          the x2APIC device.
  * @retval  VERR_OUT_RANGE if the caller must raise \#GP(0).
+ *
  * @param   pVCpu       The cross context virtual CPU structure of the calling EMT.
  * @param   idMsr       The MSR being read.
@@ -15714,5 +15695,5 @@
 VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVirtApicAccessMsr(PVMCPU pVCpu, uint32_t idMsr, uint64_t *pu64Value, bool fWrite)
 {
-    IEM_CTX_ASSERT(pVCpu, IEM_CPUMCTX_EXTRN_VMX_VMEXIT_MASK);
+    IEM_CTX_ASSERT(pVCpu, IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK);
     Assert(pu64Value);
 
@@ -15726,4 +15707,36 @@
     return iemExecStatusCodeFiddling(pVCpu, rcStrict);
 
+}
+
+
+/**
+ * Interface for HM and EM to virtualize memory-mapped APIC accesses.
+ *
+ * @returns Strict VBox status code.
+ * @retval  VINF_VMX_MODIFIES_BEHAVIOR if the memory access was virtualized.
+ *
+ * @param   pVCpu       The cross context virtual CPU structure of the calling EMT.
+ * @param   offAccess   The offset of the register being accessed (within the
+ *                      APIC-access page).
+ * @param   cbAccess    The size of the access in bytes.
+ * @param   pvData      Pointer to the data being written or where to store the data
+ *                      being read.
+ * @param   fWrite      Whether this is a write or read access.
+ * @thread  EMT(pVCpu)
+ */
+VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVirtApicAccessMem(PVMCPU pVCpu, uint16_t offAccess, size_t cbAccess, void *pvData,
+                                                       bool fWrite)
+{
+    IEM_CTX_ASSERT(pVCpu, IEM_CPUMCTX_EXTRN_VMX_VMEXIT_MASK);
+    Assert(pvData);
+
+    /** @todo NSTVMX: Unfortunately, the caller has no idea about instruction fetch
+     *        accesses, so we only use read/write here. Maybe in the future the PGM
+     *        physical handler will be extended to include this information? */
+    uint32_t const fAccess = fWrite ? IEM_ACCESS_TYPE_WRITE : IEM_ACCESS_TYPE_READ;
+    VBOXSTRICTRC rcStrict = iemVmxVirtApicAccessMem(pVCpu, offAccess, cbAccess, pvData, fAccess);
+    if (pVCpu->iem.s.cActiveMappings)
+        iemMemRollback(pVCpu);
+    return iemExecStatusCodeFiddling(pVCpu, rcStrict);
 }
 
Index: /trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp.h
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp.h	(revision 75492)
+++ /trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp.h	(revision 75493)
@@ -2681,4 +2681,5 @@
     PCVMXVVMCS pVmcs = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
     bool const fHostInLongMode = RT_BOOL(pVmcs->u32ExitCtls & VMX_EXIT_CTLS_HOST_ADDR_SPACE_SIZE);
+    bool const fVirtApicAccess = RT_BOOL(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS);
 
     /* We cannot return from a long-mode guest to a host that is not in long mode. */
@@ -2706,4 +2707,13 @@
     /* Clear address range monitoring. */
     EMMonitorWaitClear(pVCpu);
+
+    /* De-register the handler for the APIC-access page. */
+    if (fVirtApicAccess)
+    {
+        RTGCPHYS const GCPhysApicAccess = pVmcs->u64AddrApicAccess.u;
+        int rc = CPUMVmxApicAccessPageDeregister(pVCpu, GCPhysApicAccess);
+        if (RT_FAILURE(rc))
+            return rc;
+    }
 
     /* Perform the VMX transition (PGM updates). */
@@ -4236,9 +4246,13 @@
  *
  * @returns VBox strict status code.
+ * @retval VINF_VMX_MODIFIES_BEHAVIOR if the access was virtualized.
+ * @retval VINF_VMX_VMEXIT if the access causes a VM-exit.
+ *
  * @param   pVCpu       The cross context virtual CPU structure.
  * @param   offAccess   The offset of the register being accessed (within the
  *                      APIC-access page).
  * @param   cbAccess    The size of the access in bytes.
- * @param   pvData      Pointer to the data being read or written.
+ * @param   pvData      Pointer to the data being written or where to store the data
+ *                      being read.
  * @param   fAccess     The type of access (must contain IEM_ACCESS_TYPE_READ or
  *                      IEM_ACCESS_TYPE_WRITE or IEM_ACCESS_INSTRUCTION).
@@ -6006,4 +6020,9 @@
                 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_AddrApicAccessEqVirtApic);
         }
+
+        /* Register the handler for the APIC-access page. */
+        int rc = CPUMVmxApicAccessPageRegister(pVCpu, GCPhysApicAccess);
+        if (RT_FAILURE(rc))
+            IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_AddrApicAccessHandlerReg);
     }
 
Index: /trunk/src/VBox/VMM/VMMR3/CPUM.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/CPUM.cpp	(revision 75492)
+++ /trunk/src/VBox/VMM/VMMR3/CPUM.cpp	(revision 75493)
@@ -3640,5 +3640,20 @@
             }
 
+            /* Register statistic counters for MSRs. */
             cpumR3MsrRegStats(pVM);
+
+#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
+            /* Register VMX APIC-access page handler type. */
+            if (pVM->cpum.s.GuestFeatures.fVmx)
+            {
+                int rc = PGMR3HandlerPhysicalTypeRegister(pVM, PGMPHYSHANDLERKIND_ALL, cpumVmxApicAccessPageHandler,
+                                                          NULL /* pszModR0 */,
+                                                          "cpumVmxApicAccessPageHandler", NULL /* pszPfHandlerR0 */,
+                                                          NULL /* pszModRC */,
+                                                          NULL /* pszHandlerRC */, NULL /* pszPfHandlerRC */,
+                                                          "VMX APIC-access page", &pVM->cpum.s.hVmxApicAccessPage);
+                AssertRCReturn(rc, rc);
+            }
+#endif
             break;
         }
Index: /trunk/src/VBox/VMM/include/CPUMInternal.h
===================================================================
--- /trunk/src/VBox/VMM/include/CPUMInternal.h	(revision 75492)
+++ /trunk/src/VBox/VMM/include/CPUMInternal.h	(revision 75493)
@@ -24,4 +24,5 @@
 # include <VBox/vmm/stam.h>
 # include <iprt/x86.h>
+# include <VBox/vmm/pgm.h>
 #else
 # pragma D depends_on library x86.d
@@ -409,5 +410,8 @@
     /** The host MXCSR mask (determined at init). */
     uint32_t                fHostMxCsrMask;
-    uint8_t                 abPadding1[20];
+
+    /** The VMX APIC-access page handler type. */
+    PGMPHYSHANDLERTYPE      hVmxApicAccessPage;
+    uint8_t                 abPadding1[16];
 
     /** Host CPU feature information.
@@ -527,4 +531,7 @@
 PCPUMCPUIDLEAF      cpumCpuIdGetLeaf(PVM pVM, uint32_t uLeaf);
 PCPUMCPUIDLEAF      cpumCpuIdGetLeafEx(PVM pVM, uint32_t uLeaf, uint32_t uSubLeaf, bool *pfExactSubLeafHit);
+# ifdef VBOX_WITH_NESTED_HWVIRT_VMX
+PGM_ALL_CB2_PROTO(FNPGMPHYSHANDLER) cpumVmxApicAccessPageHandler;
+# endif
 
 # ifdef IN_RING3
