Index: /trunk/include/VBox/vmm/pdmapi.h
===================================================================
--- /trunk/include/VBox/vmm/pdmapi.h	(revision 60395)
+++ /trunk/include/VBox/vmm/pdmapi.h	(revision 60396)
@@ -61,4 +61,17 @@
 VMM_INT_DECL(int)       PDMVmmDevHeapR3ToGCPhys(PVM pVM, RTR3PTR pv, RTGCPHYS *pGCPhys);
 VMM_INT_DECL(bool)      PDMVmmDevHeapIsEnabled(PVM pVM);
+
+/**
+ * Mapping/unmapping callback for an VMMDev heap allocation.
+ *
+ * @param   pVM                 The cross context VM structure.
+ * @param   pvAllocation        The allocation address (ring-3).
+ * @param   GCPhysAllocation    The guest physical address of the mapping if
+ *                              it's being mapped, NIL_RTGCPHYS if it's being
+ *                              unmapped.
+ */
+typedef void FNPDMVMMDEVHEAPNOTIFY(PVM pVM, void *pvAllocation, RTGCPHYS GCPhysAllocation);
+/** Pointer (ring-3) to a FNPDMVMMDEVHEAPNOTIFY function. */
+typedef R3PTRTYPE(FNPDMVMMDEVHEAPNOTIFY *) PFNPDMVMMDEVHEAPNOTIFY;
 
 
@@ -157,7 +170,6 @@
 VMMR3DECL(void)         PDMR3DmaRun(PVM pVM);
 VMMR3_INT_DECL(int)     PDMR3LockCall(PVM pVM);
-VMMR3_INT_DECL(int)     PDMR3VmmDevHeapRegister(PVM pVM, RTGCPHYS GCPhys, RTR3PTR pvHeap, unsigned cbSize);
-VMMR3_INT_DECL(int)     PDMR3VmmDevHeapUnregister(PVM pVM, RTGCPHYS GCPhys);
-VMMR3_INT_DECL(int)     PDMR3VmmDevHeapAlloc(PVM pVM, size_t cbSize, RTR3PTR *ppv);
+
+VMMR3_INT_DECL(int)     PDMR3VmmDevHeapAlloc(PVM pVM, size_t cbSize, PFNPDMVMMDEVHEAPNOTIFY pfnNotify, RTR3PTR *ppv);
 VMMR3_INT_DECL(int)     PDMR3VmmDevHeapFree(PVM pVM, RTR3PTR pv);
 VMMR3_INT_DECL(int)     PDMR3TracingConfig(PVM pVM, const char *pszName, size_t cchName, bool fEnable, bool fApply);
Index: /trunk/include/VBox/vmm/pdmdev.h
===================================================================
--- /trunk/include/VBox/vmm/pdmdev.h	(revision 60395)
+++ /trunk/include/VBox/vmm/pdmdev.h	(revision 60396)
@@ -3552,17 +3552,31 @@
 
     /**
-     * Registers the VMM device heap
+     * Registers the VMM device heap or notifies about mapping/unmapping.
+     *
+     * This interface serves three purposes:
+     *
+     *      -# Register the VMM device heap during device construction
+     *         for the HM to use.
+     *      -# Notify PDM/HM that it's mapped into guest address
+     *         space (i.e. usable).
+     *      -# Notify PDM/HM that it is being unmapped from the guest
+     *         address space (i.e. not usable).
      *
      * @returns VBox status code.
      * @param   pDevIns             The device instance.
-     * @param   GCPhys              The physical address.
+     * @param   GCPhys              The physical address if mapped, NIL_RTGCPHYS if
+     *                              not mapped.
      * @param   pvHeap              Ring 3 heap pointer.
-     * @param   cbSize              Size of the heap.
+     * @param   cbHeap              Size of the heap.
      * @thread  EMT.
      */
-    DECLR3CALLBACKMEMBER(int, pfnRegisterVMMDevHeap,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTR3PTR pvHeap, unsigned cbSize));
-
-    /**
-     * Unregisters the VMM device heap
+    DECLR3CALLBACKMEMBER(int, pfnRegisterVMMDevHeap,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTR3PTR pvHeap, unsigned cbHeap));
+
+    /**
+     * Unregisters the VMM device heap - OBSOLETE.
+     *
+     * This entry can be reused.
+     * This entry can be reused.
+     * This entry can be reused.
      *
      * @returns VBox status code.
@@ -3570,4 +3584,5 @@
      * @param   GCPhys              The physical address.
      * @thread  EMT.
+     * @obsolete
      */
     DECLR3CALLBACKMEMBER(int, pfnUnregisterVMMDevHeap,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys));
@@ -5277,15 +5292,7 @@
  * @copydoc PDMDEVHLPR3::pfnRegisterVMMDevHeap
  */
-DECLINLINE(int) PDMDevHlpRegisterVMMDevHeap(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTR3PTR pvHeap, unsigned cbSize)
-{
-    return pDevIns->pHlpR3->pfnRegisterVMMDevHeap(pDevIns, GCPhys, pvHeap, cbSize);
-}
-
-/**
- * @copydoc PDMDEVHLPR3::pfnUnregisterVMMDevHeap
- */
-DECLINLINE(int) PDMDevHlpUnregisterVMMDevHeap(PPDMDEVINS pDevIns, RTGCPHYS GCPhys)
-{
-    return pDevIns->pHlpR3->pfnUnregisterVMMDevHeap(pDevIns, GCPhys);
+DECLINLINE(int) PDMDevHlpRegisterVMMDevHeap(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTR3PTR pvHeap, unsigned cbHeap)
+{
+    return pDevIns->pHlpR3->pfnRegisterVMMDevHeap(pDevIns, GCPhys, pvHeap, cbHeap);
 }
 
Index: /trunk/src/VBox/Devices/VMMDev/VMMDev.cpp
===================================================================
--- /trunk/src/VBox/Devices/VMMDev/VMMDev.cpp	(revision 60395)
+++ /trunk/src/VBox/Devices/VMMDev/VMMDev.cpp	(revision 60396)
@@ -2926,5 +2926,5 @@
              * It is about to be unmapped, just clean up.
              */
-            PDMDevHlpUnregisterVMMDevHeap(pPciDev->pDevIns, pThis->GCPhysVMMDevHeap);
+            PDMDevHlpRegisterVMMDevHeap(pPciDev->pDevIns, NIL_RTGCPHYS, pThis->pVMMDevHeapR3, VMMDEV_HEAP_SIZE);
             pThis->GCPhysVMMDevHeap = NIL_RTGCPHYS32;
             rc = VINF_SUCCESS;
@@ -4151,4 +4151,8 @@
             return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
                                        N_("Failed to allocate %u bytes of memory for the VMM device heap"), PAGE_SIZE);
+
+        /* Register the memory area with PDM so HM can access it before it's mapped. */
+        rc = PDMDevHlpRegisterVMMDevHeap(pDevIns, NIL_RTGCPHYS, pThis->pVMMDevHeapR3, VMMDEV_HEAP_SIZE);
+        AssertLogRelRCReturn(rc, rc);
     }
 
Index: /trunk/src/VBox/VMM/VMMAll/PDMAll.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/PDMAll.cpp	(revision 60395)
+++ /trunk/src/VBox/VMM/VMMAll/PDMAll.cpp	(revision 60396)
@@ -501,15 +501,22 @@
 VMM_INT_DECL(int) PDMVmmDevHeapR3ToGCPhys(PVM pVM, RTR3PTR pv, RTGCPHYS *pGCPhys)
 {
-    /* Don't assert here as this is called before we can catch ring-0 assertions. */
-    if (RT_UNLIKELY((RTR3UINTPTR)pv - (RTR3UINTPTR)pVM->pdm.s.pvVMMDevHeap >= pVM->pdm.s.cbVMMDevHeap))
-    {
+    if (RT_LIKELY(pVM->pdm.s.GCPhysVMMDevHeap != NIL_RTGCPHYS))
+    {
+        RTR3UINTPTR const offHeap = (RTR3UINTPTR)pv - (RTR3UINTPTR)pVM->pdm.s.pvVMMDevHeap;
+        if (RT_LIKELY(offHeap < pVM->pdm.s.cbVMMDevHeap))
+        {
+            *pGCPhys = pVM->pdm.s.GCPhysVMMDevHeap + offHeap;
+            return VINF_SUCCESS;
+        }
+
+        /* Don't assert here as this is called before we can catch ring-0 assertions. */
         Log(("PDMVmmDevHeapR3ToGCPhys: pv=%p pvVMMDevHeap=%p cbVMMDevHeap=%#x\n",
              pv, pVM->pdm.s.pvVMMDevHeap, pVM->pdm.s.cbVMMDevHeap));
-        return VERR_PDM_DEV_HEAP_R3_TO_GCPHYS;
-    }
-
-    *pGCPhys = (pVM->pdm.s.GCPhysVMMDevHeap + ((RTR3UINTPTR)pv - (RTR3UINTPTR)pVM->pdm.s.pvVMMDevHeap));
-    return VINF_SUCCESS;
-}
+    }
+    else
+        Log(("PDMVmmDevHeapR3ToGCPhys: GCPhysVMMDevHeap=%RGp (pv=%p)\n", pVM->pdm.s.GCPhysVMMDevHeap, pv));
+    return VERR_PDM_DEV_HEAP_R3_TO_GCPHYS;
+}
+
 
 /**
@@ -521,4 +528,4 @@
 VMM_INT_DECL(bool) PDMVmmDevHeapIsEnabled(PVM pVM)
 {
-    return (pVM->pdm.s.pvVMMDevHeap != NULL);
-}
+    return pVM->pdm.s.GCPhysVMMDevHeap != NIL_RTGCPHYS;
+}
Index: /trunk/src/VBox/VMM/VMMR3/HM.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/HM.cpp	(revision 60395)
+++ /trunk/src/VBox/VMM/VMMR3/HM.cpp	(revision 60396)
@@ -1105,4 +1105,15 @@
 
 /**
+ * @callback_method_impl{FNPDMVMMDEVHEAPNOTIFY}
+ */
+static DECLCALLBACK(void) hmR3VmmDevHeapNotify(PVM pVM, void *pvAllocation,  RTGCPHYS GCPhysAllocation)
+{
+    NOREF(pVM);
+    NOREF(pvAllocation);
+    NOREF(GCPhysAllocation);
+}
+
+
+/**
  * Finish VT-x initialization (after ring-0 init).
  *
@@ -1336,5 +1347,5 @@
     {
         /* Allocate three pages for the TSS we need for real mode emulation. (2 pages for the IO bitmap) */
-        rc = PDMR3VmmDevHeapAlloc(pVM, HM_VTX_TOTAL_DEVHEAP_MEM, (RTR3PTR *)&pVM->hm.s.vmx.pRealModeTSS);
+        rc = PDMR3VmmDevHeapAlloc(pVM, HM_VTX_TOTAL_DEVHEAP_MEM, hmR3VmmDevHeapNotify, (RTR3PTR *)&pVM->hm.s.vmx.pRealModeTSS);
         if (RT_SUCCESS(rc))
         {
@@ -1371,11 +1382,14 @@
 
             /* We convert it here every time as pci regions could be reconfigured. */
-            rc = PDMVmmDevHeapR3ToGCPhys(pVM, pVM->hm.s.vmx.pRealModeTSS, &GCPhys);
-            AssertRCReturn(rc, rc);
-            LogRel(("HM: Real Mode TSS guest physaddr    = %#RGp\n", GCPhys));
-
-            rc = PDMVmmDevHeapR3ToGCPhys(pVM, pVM->hm.s.vmx.pNonPagingModeEPTPageTable, &GCPhys);
-            AssertRCReturn(rc, rc);
-            LogRel(("HM: Non-Paging Mode EPT CR3         = %#RGp\n", GCPhys));
+            if (PDMVmmDevHeapIsEnabled(pVM))
+            {
+                rc = PDMVmmDevHeapR3ToGCPhys(pVM, pVM->hm.s.vmx.pRealModeTSS, &GCPhys);
+                AssertRCReturn(rc, rc);
+                LogRel(("HM: Real Mode TSS guest physaddr    = %#RGp\n", GCPhys));
+
+                rc = PDMVmmDevHeapR3ToGCPhys(pVM, pVM->hm.s.vmx.pNonPagingModeEPTPageTable, &GCPhys);
+                AssertRCReturn(rc, rc);
+                LogRel(("HM: Non-Paging Mode EPT CR3         = %#RGp\n", GCPhys));
+            }
         }
         else
Index: /trunk/src/VBox/VMM/VMMR3/PDM.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/PDM.cpp	(revision 60395)
+++ /trunk/src/VBox/VMM/VMMR3/PDM.cpp	(revision 60396)
@@ -2452,54 +2452,13 @@
 
 /**
- * Registers the VMM device heap
- *
- * @returns VBox status code.
- * @param   pVM             The cross context VM structure.
- * @param   GCPhys          The physical address.
- * @param   pvHeap          Ring-3 pointer.
- * @param   cbSize          Size of the heap.
- */
-VMMR3_INT_DECL(int) PDMR3VmmDevHeapRegister(PVM pVM, RTGCPHYS GCPhys, RTR3PTR pvHeap, unsigned cbSize)
-{
-    Assert(pVM->pdm.s.pvVMMDevHeap == NULL);
-
-    Log(("PDMR3VmmDevHeapRegister %RGp %RHv %x\n", GCPhys, pvHeap, cbSize));
-    pVM->pdm.s.pvVMMDevHeap     = pvHeap;
-    pVM->pdm.s.GCPhysVMMDevHeap = GCPhys;
-    pVM->pdm.s.cbVMMDevHeap     = cbSize;
-    pVM->pdm.s.cbVMMDevHeapLeft = cbSize;
-    return VINF_SUCCESS;
-}
-
-
-/**
- * Unregisters the VMM device heap
- *
- * @returns VBox status code.
- * @param   pVM             The cross context VM structure.
- * @param   GCPhys          The physical address.
- */
-VMMR3_INT_DECL(int) PDMR3VmmDevHeapUnregister(PVM pVM, RTGCPHYS GCPhys)
-{
-    Assert(pVM->pdm.s.GCPhysVMMDevHeap == GCPhys);
-
-    Log(("PDMR3VmmDevHeapUnregister %RGp\n", GCPhys));
-    pVM->pdm.s.pvVMMDevHeap     = NULL;
-    pVM->pdm.s.GCPhysVMMDevHeap = NIL_RTGCPHYS;
-    pVM->pdm.s.cbVMMDevHeap     = 0;
-    pVM->pdm.s.cbVMMDevHeapLeft = 0;
-    return VINF_SUCCESS;
-}
-
-
-/**
- * Allocates memory from the VMM device heap
+ * Allocates memory from the VMM device heap.
  *
  * @returns VBox status code.
  * @param   pVM             The cross context VM structure.
  * @param   cbSize          Allocation size.
+ * @param   pfnNotify       Mapping/unmapping notification callback.
  * @param   ppv             Ring-3 pointer. (out)
  */
-VMMR3_INT_DECL(int) PDMR3VmmDevHeapAlloc(PVM pVM, size_t cbSize, RTR3PTR *ppv)
+VMMR3_INT_DECL(int) PDMR3VmmDevHeapAlloc(PVM pVM, size_t cbSize, PFNPDMVMMDEVHEAPNOTIFY pfnNotify, RTR3PTR *ppv)
 {
 #ifdef DEBUG_bird
@@ -2515,4 +2474,5 @@
     *ppv = pVM->pdm.s.pvVMMDevHeap;
     pVM->pdm.s.cbVMMDevHeapLeft = 0;
+    pVM->pdm.s.pfnVMMDevHeapNotify = pfnNotify;
     return VINF_SUCCESS;
 }
@@ -2532,4 +2492,5 @@
     /** @todo not a real heap as there's currently only one user. */
     pVM->pdm.s.cbVMMDevHeapLeft = pVM->pdm.s.cbVMMDevHeap;
+    pVM->pdm.s.pfnVMMDevHeapNotify = NULL;
     return VINF_SUCCESS;
 }
Index: /trunk/src/VBox/VMM/VMMR3/PDMDevHlp.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/PDMDevHlp.cpp	(revision 60395)
+++ /trunk/src/VBox/VMM/VMMR3/PDMDevHlp.cpp	(revision 60396)
@@ -3272,11 +3272,35 @@
  * @copydoc PDMDEVHLPR3::pfnRegisterVMMDevHeap
  */
-static DECLCALLBACK(int) pdmR3DevHlp_RegisterVMMDevHeap(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTR3PTR pvHeap, unsigned cbSize)
-{
-    PDMDEV_ASSERT_DEVINS(pDevIns);
-    VM_ASSERT_EMT(pDevIns->Internal.s.pVMR3);
-
-    int rc = PDMR3VmmDevHeapRegister(pDevIns->Internal.s.pVMR3, GCPhys, pvHeap, cbSize);
-    return rc;
+static DECLCALLBACK(int) pdmR3DevHlp_RegisterVMMDevHeap(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTR3PTR pvHeap, unsigned cbHeap)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    PVM pVM = pDevIns->Internal.s.pVMR3;
+    VM_ASSERT_EMT(pVM);
+    LogFlow(("pdmR3DevHlp_RegisterVMMDevHeap: caller='%s'/%d: GCPhys=%RGp pvHeap=%p cbHeap=%#x\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, GCPhys, pvHeap, cbHeap));
+
+    if (pVM->pdm.s.pvVMMDevHeap == NULL)
+    {
+        pVM->pdm.s.pvVMMDevHeap     = pvHeap;
+        pVM->pdm.s.GCPhysVMMDevHeap = GCPhys;
+        pVM->pdm.s.cbVMMDevHeap     = cbHeap;
+        pVM->pdm.s.cbVMMDevHeapLeft = cbHeap;
+    }
+    else
+    {
+        Assert(pVM->pdm.s.pvVMMDevHeap == pvHeap);
+        Assert(pVM->pdm.s.cbVMMDevHeap == cbHeap);
+        Assert(pVM->pdm.s.GCPhysVMMDevHeap != GCPhys || GCPhys == NIL_RTGCPHYS);
+        if (pVM->pdm.s.GCPhysVMMDevHeap != GCPhys)
+        {
+            pVM->pdm.s.GCPhysVMMDevHeap = GCPhys;
+            if (pVM->pdm.s.pfnVMMDevHeapNotify)
+                pVM->pdm.s.pfnVMMDevHeapNotify(pVM, pvHeap, GCPhys);
+        }
+    }
+
+    LogFlow(("pdmR3DevHlp_RegisterVMMDevHeap: caller='%s'/%d: returns %Rrc\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, VINF_SUCCESS));
+    return VINF_SUCCESS;
 }
 
@@ -3287,9 +3311,6 @@
 static DECLCALLBACK(int) pdmR3DevHlp_UnregisterVMMDevHeap(PPDMDEVINS pDevIns, RTGCPHYS GCPhys)
 {
-    PDMDEV_ASSERT_DEVINS(pDevIns);
-    VM_ASSERT_EMT(pDevIns->Internal.s.pVMR3);
-
-    int rc = PDMR3VmmDevHeapUnregister(pDevIns->Internal.s.pVMR3, GCPhys);
-    return rc;
+    /* Free to replace this interface. */
+    AssertFailedReturn(VERR_NOT_IMPLEMENTED);
 }
 
Index: /trunk/src/VBox/VMM/include/PDMInternal.h
===================================================================
--- /trunk/src/VBox/VMM/include/PDMInternal.h	(revision 60395)
+++ /trunk/src/VBox/VMM/include/PDMInternal.h	(revision 60396)
@@ -1141,4 +1141,6 @@
     /** The current mapping. NIL_RTGCPHYS if not mapped or registered. */
     RTGCPHYS                        GCPhysVMMDevHeap;
+    /** Ring-3 mapping/unmapping notification callback for the user. */
+    PFNPDMVMMDEVHEAPNOTIFY          pfnVMMDevHeapNotify;
     /** @} */
 
