Index: trunk/include/VBox/vmm/pgm.h
===================================================================
--- trunk/include/VBox/vmm/pgm.h	(revision 99315)
+++ trunk/include/VBox/vmm/pgm.h	(revision 99316)
@@ -669,4 +669,5 @@
 VMMDECL(int)        PGMHandlerPhysicalRegister(PVMCC pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast, PGMPHYSHANDLERTYPE hType,
                                                uint64_t uUser, R3PTRTYPE(const char *) pszDesc);
+VMMDECL(int)        PGMHandlerPhysicalRegisterVmxApicAccessPage(PVMCC pVM, RTGCPHYS GCPhys, PGMPHYSHANDLERTYPE hType);
 VMMDECL(int)        PGMHandlerPhysicalModify(PVMCC pVM, RTGCPHYS GCPhysCurrent, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast);
 VMMDECL(int)        PGMHandlerPhysicalDeregister(PVMCC pVM, RTGCPHYS GCPhys);
Index: trunk/src/VBox/VMM/VMMAll/PGMAllHandler.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMAll/PGMAllHandler.cpp	(revision 99315)
+++ trunk/src/VBox/VMM/VMMAll/PGMAllHandler.cpp	(revision 99316)
@@ -125,37 +125,19 @@
 
 /**
- * Creates a physical access handler, allocation part.
- *
- * @returns VBox status code.
- * @retval  VERR_OUT_OF_RESOURCES if no more handlers available.
- *
- * @param   pVM             The cross context VM structure.
- * @param   hType           The handler type registration handle.
- * @param   uUser           User argument to the handlers (not pointer).
- * @param   pszDesc         Description of this handler.  If NULL, the type
- *                          description will be used instead.
- * @param   ppPhysHandler   Where to return the access handler structure on
- *                          success.
- */
-int pgmHandlerPhysicalExCreate(PVMCC pVM, PGMPHYSHANDLERTYPE hType, uint64_t uUser,
-                               R3PTRTYPE(const char *) pszDesc, PPGMPHYSHANDLER *ppPhysHandler)
-{
-    /*
-     * Validate input.
-     */
-    PCPGMPHYSHANDLERTYPEINT const pType = pgmHandlerPhysicalTypeHandleToPtr(pVM, hType);
-    AssertReturn(pType, VERR_INVALID_HANDLE);
-    AssertReturn(pType->enmKind > PGMPHYSHANDLERKIND_INVALID && pType->enmKind < PGMPHYSHANDLERKIND_END, VERR_INVALID_HANDLE);
-    AssertPtr(ppPhysHandler);
-
-    Log(("pgmHandlerPhysicalExCreate: uUser=%#RX64 hType=%#x (%d, %s) pszDesc=%RHv:%s\n",
-         uUser, hType, pType->enmKind, pType->pszDesc, pszDesc, R3STRING(pszDesc)));
-
-    /*
-     * Allocate and initialize the new entry.
-     */
-    int rc = PGM_LOCK(pVM);
-    AssertRCReturn(rc, rc);
-
+ * Worker for pgmHandlerPhysicalExCreate.
+ *
+ * @returns A new physical handler on success or NULL on failure.
+ * @param   pVM         The cross context VM structure.
+ * @param   pType       The physical handler type.
+ * @param   hType       The physical handler type registeration handle.
+ * @param   uUser       User argument to the handlers (not pointer).
+ * @param   pszDesc     Description of this handler.  If NULL, the type description
+ *                      will be used instead.
+ */
+DECL_FORCE_INLINE(PPGMPHYSHANDLER) pgmHandlerPhysicalExCreateWorker(PVMCC pVM, PCPGMPHYSHANDLERTYPEINT pType,
+                                                                    PGMPHYSHANDLERTYPE hType, uint64_t uUser,
+                                                                    R3PTRTYPE(const char *) pszDesc)
+{
+    PGM_LOCK_ASSERT_OWNER(pVM);
     PPGMPHYSHANDLER pNew = pVM->VMCC_CTX(pgm).s.PhysHandlerAllocator.allocateNode();
     if (pNew)
@@ -174,11 +156,46 @@
                             : pVM->pgm.s.aPhysHandlerTypes[hType & PGMPHYSHANDLERTYPE_IDX_MASK].pszDesc;
 #endif
-
-        PGM_UNLOCK(pVM);
-        *ppPhysHandler = pNew;
+    }
+    return pNew;
+}
+
+
+/**
+ * Creates a physical access handler, allocation part.
+ *
+ * @returns VBox status code.
+ * @retval  VERR_OUT_OF_RESOURCES if no more handlers available.
+ *
+ * @param   pVM             The cross context VM structure.
+ * @param   hType           The handler type registration handle.
+ * @param   uUser           User argument to the handlers (not pointer).
+ * @param   pszDesc         Description of this handler.  If NULL, the type
+ *                          description will be used instead.
+ * @param   ppPhysHandler   Where to return the access handler structure on
+ *                          success.
+ */
+int pgmHandlerPhysicalExCreate(PVMCC pVM, PGMPHYSHANDLERTYPE hType, uint64_t uUser,
+                               R3PTRTYPE(const char *) pszDesc, PPGMPHYSHANDLER *ppPhysHandler)
+{
+    /*
+     * Validate input.
+     */
+    PCPGMPHYSHANDLERTYPEINT const pType = pgmHandlerPhysicalTypeHandleToPtr(pVM, hType);
+    AssertReturn(pType, VERR_INVALID_HANDLE);
+    AssertReturn(pType->enmKind > PGMPHYSHANDLERKIND_INVALID && pType->enmKind < PGMPHYSHANDLERKIND_END, VERR_INVALID_HANDLE);
+    AssertPtr(ppPhysHandler);
+
+    Log(("pgmHandlerPhysicalExCreate: uUser=%#RX64 hType=%#x (%d, %s) pszDesc=%RHv:%s\n",
+         uUser, hType, pType->enmKind, pType->pszDesc, pszDesc, R3STRING(pszDesc)));
+
+    /*
+     * Allocate and initialize the new entry.
+     */
+    int rc = PGM_LOCK(pVM);
+    AssertRCReturn(rc, rc);
+    *ppPhysHandler = pgmHandlerPhysicalExCreateWorker(pVM, pType, hType, uUser, pszDesc);
+    PGM_UNLOCK(pVM);
+    if (*ppPhysHandler)
         return VINF_SUCCESS;
-    }
-
-    PGM_UNLOCK(pVM);
     return VERR_OUT_OF_RESOURCES;
 }
@@ -313,4 +330,70 @@
 
 /**
+ * Worker for pgmHandlerPhysicalRegisterVmxApicAccessPage.
+ *
+ * @returns VBox status code.
+ * @retval  VINF_SUCCESS when successfully installed.
+ * @retval  VINF_PGM_GCPHYS_ALIASED could be returned.
+ *
+ * @param   pVM             The cross context VM structure.
+ * @param   pPhysHandler    The physical handler.
+ * @param   GCPhys          The address of the virtual VMX APIC-access page.
+ */
+static int pgmHandlerPhysicalRegisterVmxApicAccessPage(PVMCC pVM, PPGMPHYSHANDLER pPhysHandler, RTGCPHYS GCPhys)
+{
+    PGM_LOCK_ASSERT_OWNER(pVM);
+    LogFunc(("GCPhys=%RGp\n", GCPhys));
+
+    /*
+     * We require the range to be within registered ram.
+     * There is no apparent need to support ranges which cover more than one ram range.
+     */
+    PPGMRAMRANGE pRam = pgmPhysGetRange(pVM, GCPhys);
+    RTGCPHYS const GCPhysLast = GCPhys | X86_PAGE_4K_OFFSET_MASK;
+    if (   !pRam
+        || GCPhysLast > pRam->GCPhysLast)
+    {
+#ifdef IN_RING3
+        DBGFR3Info(pVM->pUVM, "phys", NULL, NULL);
+#endif
+        AssertMsgFailed(("No RAM range for %RGp-%RGp\n", GCPhys, GCPhysLast));
+        return VERR_PGM_HANDLER_PHYSICAL_NO_RAM_RANGE;
+    }
+    Assert(GCPhys >= pRam->GCPhys && GCPhys < pRam->GCPhysLast);
+    Assert(GCPhysLast <= pRam->GCPhysLast && GCPhysLast >= pRam->GCPhys);
+
+    /*
+     * Try insert into list.
+     */
+    pPhysHandler->Key     = GCPhys;
+    pPhysHandler->KeyLast = GCPhysLast;
+    pPhysHandler->cPages  = (GCPhysLast - (GCPhys & X86_PTE_PAE_PG_MASK) + GUEST_PAGE_SIZE) >> GUEST_PAGE_SHIFT;
+
+    int rc = pVM->VMCC_CTX(pgm).s.pPhysHandlerTree->insert(&pVM->VMCC_CTX(pgm).s.PhysHandlerAllocator, pPhysHandler);
+    if (RT_SUCCESS(rc))
+    {
+        rc = pgmHandlerPhysicalSetRamFlagsAndFlushShadowPTs(pVM, pPhysHandler, pRam, NULL /*pvBitmap*/, 0 /*offBitmap*/);
+        if (rc == VINF_PGM_SYNC_CR3)
+            rc = VINF_PGM_GCPHYS_ALIASED;
+
+#if defined(IN_RING3) || defined(IN_RING0)
+        NEMHCNotifyHandlerPhysicalRegister(pVM, PGMPHYSHANDLERKIND_ALL, GCPhys, GCPhysLast - GCPhys + 1);
+#endif
+        return rc;
+    }
+
+    pPhysHandler->Key     = NIL_RTGCPHYS;
+    pPhysHandler->KeyLast = NIL_RTGCPHYS;
+
+    AssertMsgReturn(rc == VERR_ALREADY_EXISTS, ("%Rrc GCPhys=%RGp GCPhysLast=%RGp\n", rc, GCPhys, GCPhysLast), rc);
+#if defined(IN_RING3) && defined(VBOX_STRICT)
+    DBGFR3Info(pVM->pUVM, "handlers", "phys nostats", NULL);
+#endif
+    AssertMsgFailed(("Conflict! GCPhys=%RGp GCPhysLast=%RGp\n", GCPhys, GCPhysLast));
+    return VERR_PGM_HANDLER_PHYSICAL_CONFLICT;
+}
+
+
+/**
  * Register a access handler for a physical range.
  *
@@ -349,4 +432,82 @@
         pgmHandlerPhysicalExDestroy(pVM, pNew);
     }
+    return rc;
+}
+
+
+/**
+ * Register an access handler for a virtual VMX APIC-access page.
+ *
+ * This holds the PGM lock across the whole operation to resolve races between
+ * VCPUs registering the same page simultaneously. It's also a slightly slimmer
+ * version of the regular registeration function as it's specific to the VMX
+ * APIC-access page.
+ *
+ * @returns VBox status code.
+ * @retval  VINF_SUCCESS when successfully installed.
+ * @retval  VINF_PGM_GCPHYS_ALIASED when the shadow PTs could be updated because
+ *          the guest page aliased or/and mapped by multiple PTs. A CR3 sync has been
+ *          flagged together with a pool clearing.
+ * @retval  VERR_PGM_HANDLER_PHYSICAL_CONFLICT if the range conflicts with an existing
+ *          one. A debug assertion is raised.
+ *
+ * @param   pVM             The cross context VM structure.
+ * @param   GCPhys          Start physical address.
+ * @param   hType           The handler type registration handle.
+ */
+VMMDECL(int) PGMHandlerPhysicalRegisterVmxApicAccessPage(PVMCC pVM, RTGCPHYS GCPhys, PGMPHYSHANDLERTYPE hType)
+{
+    PCPGMPHYSHANDLERTYPEINT const pType = pgmHandlerPhysicalTypeHandleToPtr(pVM, hType);
+    AssertReturn(pType, VERR_INVALID_HANDLE);
+    AssertReturn(pType->enmKind == PGMPHYSHANDLERKIND_ALL, VERR_INVALID_HANDLE);
+    AssertMsgReturn(!(GCPhys & GUEST_PAGE_OFFSET_MASK), ("%RGp\n", GCPhys), VERR_INVALID_PARAMETER);
+
+    /*
+     * Find if the VMX APIC access page has already been registered at this address.
+     */
+    int rc = PGM_LOCK_VOID(pVM);
+    AssertRCReturn(rc, rc);
+
+    PPGMPHYSHANDLER pHandler;
+    rc = pgmHandlerPhysicalLookup(pVM, GCPhys, &pHandler);
+    if (RT_SUCCESS(rc))
+    {
+        PCPGMPHYSHANDLERTYPEINT const pHandlerType = PGMPHYSHANDLER_GET_TYPE_NO_NULL(pVM, pHandler);
+        Assert(GCPhys >= pHandler->Key && GCPhys <= pHandler->KeyLast);
+        Assert(   pHandlerType->enmKind == PGMPHYSHANDLERKIND_WRITE
+               || pHandlerType->enmKind == PGMPHYSHANDLERKIND_ALL
+               || pHandlerType->enmKind == PGMPHYSHANDLERKIND_MMIO);
+
+        /* Check it's the virtual VMX APIC-access page. */
+        if (   pHandlerType->fNotInHm
+            && pHandlerType->enmKind == PGMPHYSHANDLERKIND_ALL)
+            rc = VINF_SUCCESS;
+        else
+        {
+            rc = VERR_PGM_HANDLER_PHYSICAL_CONFLICT;
+            AssertMsgFailed(("Conflict! GCPhys=%RGp enmKind=%#x fNotInHm=%RTbool\n", GCPhys, pHandlerType->enmKind,
+                             pHandlerType->fNotInHm));
+        }
+
+        PGM_UNLOCK(pVM);
+        return rc;
+    }
+
+    /*
+     * Create and register a physical handler for the virtual VMX APIC-access page.
+     */
+    pHandler = pgmHandlerPhysicalExCreateWorker(pVM, pType, hType, 0 /*uUser*/, NULL /*pszDesc*/);
+    if (pHandler)
+    {
+        rc = pgmHandlerPhysicalRegisterVmxApicAccessPage(pVM, pHandler, GCPhys);
+        if (RT_SUCCESS(rc))
+        { /* likely */ }
+        else
+            pgmHandlerPhysicalExDestroy(pVM, pHandler);
+    }
+    else
+        rc = VERR_OUT_OF_RESOURCES;
+
+    PGM_UNLOCK(pVM);
     return rc;
 }
