Index: trunk/src/VBox/VMM/MMHyper.cpp
===================================================================
--- trunk/src/VBox/VMM/MMHyper.cpp	(revision 20530)
+++ trunk/src/VBox/VMM/MMHyper.cpp	(revision 20531)
@@ -74,5 +74,5 @@
     /** @todo @bugref{1865}, @bugref{3202}: Change the cbHyperHeap default
      *        depending on whether VT-x/AMD-V is enabled or not! Don't waste
-     *        precious kernel space on heap for the PATM. 
+     *        precious kernel space on heap for the PATM.
      */
     uint32_t cbHyperHeap;
@@ -868,5 +868,5 @@
  * @remark  This is assumed not to be used at times when serialization is required.
  */
-VMMDECL(int) MMR3HyperAllocOnceNoRel(PVM pVM, size_t cb, unsigned uAlignment, MMTAG enmTag, void **ppv)
+VMMR3DECL(int) MMR3HyperAllocOnceNoRel(PVM pVM, size_t cb, unsigned uAlignment, MMTAG enmTag, void **ppv)
 {
     AssertMsg(cb >= 8, ("Hey! Do you really mean to allocate less than 8 bytes?! cb=%d\n", cb));
@@ -983,4 +983,101 @@
 
 /**
+ * Lookus up a ring-3 pointer to HMA.
+ *
+ * @returns The lookup record on success, NULL on failure.
+ * @param   pVM                 The VM handle.
+ * @param   pvR3                The ring-3 address to look up.
+ */
+DECLINLINE(PMMLOOKUPHYPER) mmR3HyperLookupR3(PVM pVM, void *pvR3)
+{
+    PMMLOOKUPHYPER  pLookup = (PMMLOOKUPHYPER)((uint8_t *)pVM->mm.s.pHyperHeapR3 + pVM->mm.s.offLookupHyper);
+    for (;;)
+    {
+        switch (pLookup->enmType)
+        {
+            case MMLOOKUPHYPERTYPE_LOCKED:
+            {
+                unsigned off = (uint8_t *)pvR3 - (uint8_t *)pLookup->u.Locked.pvR3;
+                if (off < pLookup->cb)
+                    return pLookup;
+                break;
+            }
+
+            case MMLOOKUPHYPERTYPE_HCPHYS:
+            {
+                unsigned off = (uint8_t *)pvR3 - (uint8_t *)pLookup->u.HCPhys.pvR3;
+                if (off < pLookup->cb)
+                    return pLookup;
+                break;
+            }
+
+            case MMLOOKUPHYPERTYPE_GCPHYS:
+            case MMLOOKUPHYPERTYPE_MMIO2:
+            case MMLOOKUPHYPERTYPE_DYNAMIC:
+                /** @todo ?    */
+                break;
+
+            default:
+                AssertMsgFailed(("enmType=%d\n", pLookup->enmType));
+                return NULL;
+        }
+
+        /* next */
+        if ((unsigned)pLookup->offNext == NIL_OFFSET)
+            return NULL;
+        pLookup = (PMMLOOKUPHYPER)((uint8_t *)pLookup + pLookup->offNext);
+    }
+}
+
+
+/**
+ * Set / unset guard status on one or more hyper heap pages.
+ *
+ * @returns VBox status code (first failure).
+ * @param   pVM                 The VM handle.
+ * @param   pvStart             The hyper heap page address. Must be page
+ *                              aligned.
+ * @param   cb                  The number of bytes. Must be page aligned.
+ * @param   fSet                Wheter to set or unset guard page status.
+ */
+VMMR3DECL(int) MMR3HyperSetGuard(PVM pVM, void *pvStart, size_t cb, bool fSet)
+{
+    /*
+     * Validate input.
+     */
+    AssertReturn(!((uintptr_t)pvStart & PAGE_OFFSET_MASK), VERR_INVALID_POINTER);
+    AssertReturn(!(cb & PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
+    PMMLOOKUPHYPER pLookup = mmR3HyperLookupR3(pVM, pvStart);
+    AssertReturn(pLookup, VERR_INVALID_PARAMETER);
+    AssertReturn(pLookup->enmType == MMLOOKUPHYPERTYPE_LOCKED, VERR_INVALID_PARAMETER);
+
+    /*
+     * Get down to business.
+     * Note! We quietly ignore errors from the support library since the
+     *       protection stuff isn't possible to implement on all platforms.
+     */
+    uint8_t    *pbR3  = (uint8_t *)pLookup->u.Locked.pvR3;
+#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
+    RTR0PTR     R0Ptr = VMMIsHwVirtExtForced(pVM) ? pLookup->u.Locked.pvR0 : NIL_RTR0PTR;
+#else
+    RTR0PTR     R0Ptr = NIL_RTR0PTR; /* ring-0 and ring-3 uses the same mapping. */
+#endif
+    uint32_t    off   = (uint32_t)((uint8_t *)pvStart - pbR3);
+    int         rc;
+    if (fSet)
+    {
+        rc = PGMMapSetPage(pVM, MMHyperR3ToRC(pVM, pvStart), cb, 0);
+        SUPR3PageProtect(pbR3, R0Ptr, off, cb, RTMEM_PROT_NONE);
+    }
+    else
+    {
+        rc = PGMMapSetPage(pVM, MMHyperR3ToRC(pVM, pvStart), cb, X86_PTE_P | X86_PTE_A | X86_PTE_D | X86_PTE_RW);
+        SUPR3PageProtect(pbR3, R0Ptr, off, cb, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
+    }
+    return rc;
+}
+
+
+/**
  * Convert hypervisor HC virtual address to HC physical address.
  *
