Index: /trunk/src/VBox/VMM/VMMR3/NEMR3Native-win.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/NEMR3Native-win.cpp	(revision 71081)
+++ /trunk/src/VBox/VMM/VMMR3/NEMR3Native-win.cpp	(revision 71082)
@@ -1959,16 +1959,22 @@
 
     /*
+     * Consolidate current page state with actual page protection and access type.
+     * We don't really consider downgrades here, as they shouldn't happen.
+     */
+#ifndef NEM_WIN_USE_HYPERCALLS
+    /** @todo Someone at microsoft please explain:
      * I'm not sure WTF was going on, but I ended up in a loop if I remapped a
-     * readonly page as writable.  Specifically, this was an issue with the big
-     * VRAM mapping at 0xe0000000 when booing DSL 4.4.1.  So, in a hope to work
-     * around that we no longer pre-map anything, just unmap stuff and do it
-     * lazily here.  And here we will first unmap, restart, and then remap with
-     * new protection or backing.
-     */
+     * readonly page as writable (unmap, then map again).  Specifically, this was an
+     * issue with the big VRAM mapping at 0xe0000000 when booing DSL 4.4.1.  So, in
+     * a hope to work around that we no longer pre-map anything, just unmap stuff
+     * and do it lazily here.  And here we will first unmap, restart, and then remap
+     * with new protection or backing.
+     */
+#endif
+    int rc;
     switch (u2State)
     {
         case NEM_WIN_PAGE_STATE_UNMAPPED:
         case NEM_WIN_PAGE_STATE_NOT_SET:
-        {
             if (pInfo->fNemProt == NEM_PAGE_PROT_NONE)
             {
@@ -1986,19 +1992,17 @@
 
             /* Map the page. */
-            int rc = nemR3NativeSetPhysPage(pVM,
-                                            pVCpu,
-                                            GCPhysSrc & ~(RTGCPHYS)X86_PAGE_OFFSET_MASK,
-                                            GCPhys & ~(RTGCPHYS)X86_PAGE_OFFSET_MASK,
-                                            pInfo->fNemProt,
-                                            &u2State,
-                                            true /*fBackingState*/);
+            rc = nemR3NativeSetPhysPage(pVM,
+                                        pVCpu,
+                                        GCPhysSrc & ~(RTGCPHYS)X86_PAGE_OFFSET_MASK,
+                                        GCPhys & ~(RTGCPHYS)X86_PAGE_OFFSET_MASK,
+                                        pInfo->fNemProt,
+                                        &u2State,
+                                        true /*fBackingState*/);
             pInfo->u2NemState = u2State;
             Log4(("nemR3WinHandleMemoryAccessPageCheckerCallback: %RGp - synced => %s + %Rrc\n",
                   GCPhys, g_apszPageStates[u2State], rc));
-            RT_NOREF(pVCpu);
             pState->fDidSomething = true;
             pState->fCanResume    = true;
             return rc;
-        }
 
         case NEM_WIN_PAGE_STATE_READABLE:
@@ -2016,7 +2020,7 @@
                 && pState->fWriteAccess)
             {
-                int rc = nemR3WinHypercallMapPage(pVM, pVCpu, GCPhysSrc, GCPhys,
-                                                    HV_MAP_GPA_READABLE   | HV_MAP_GPA_WRITABLE
-                                                  | HV_MAP_GPA_EXECUTABLE | HV_MAP_GPA_EXECUTABLE_AGAIN);
+                rc = nemR3WinHypercallMapPage(pVM, pVCpu, GCPhysSrc, GCPhys,
+                                              HV_MAP_GPA_READABLE   | HV_MAP_GPA_WRITABLE
+                                              | HV_MAP_GPA_EXECUTABLE | HV_MAP_GPA_EXECUTABLE_AGAIN);
                 AssertRC(rc);
                 if (RT_SUCCESS(rc))
@@ -2027,9 +2031,16 @@
                     Log5(("NEM GPA write-upgrade/exit: %RGp (was %s, cMappedPages=%u)\n",
                           GCPhys, g_apszPageStates[u2State], pVM->nem.s.cMappedPages));
-                    return rc;
                 }
             }
+            else
+            {
+                /* Need to emulate the acces. */
+                AssertBreak(pInfo->fNemProt != NEM_PAGE_PROT_NONE); /* There should be no downgrades. */
+                rc = VINF_SUCCESS;
+            }
+            return rc;
+#else
+            break;
 #endif
-            break;
 
         case NEM_WIN_PAGE_STATE_WRITABLE:
@@ -2039,4 +2050,7 @@
                 return VINF_SUCCESS;
             }
+#ifdef NEM_WIN_USE_HYPERCALLS
+            AssertFailed(); /* There should be no downgrades. */
+#endif
             break;
 
@@ -2050,5 +2064,5 @@
      */
 #ifdef NEM_WIN_USE_HYPERCALLS
-    int rc = nemR3WinHypercallUnmapPage(pVM, pVCpu, GCPhys);
+    rc = nemR3WinHypercallUnmapPage(pVM, pVCpu, GCPhys);
     AssertRC(rc);
     if (RT_SUCCESS(rc))
@@ -2738,4 +2752,75 @@
                                   uint8_t *pu2State, bool fBackingChanged)
 {
+#ifdef NEM_WIN_USE_HYPERCALLS
+    /*
+     * When using the hypercalls instead of the ring-3 APIs, we don't need to
+     * unmap memory before modifying it.  We still want to track the state though,
+     * since unmap will fail when called an unmapped page and we don't want to redo
+     * upgrades/downgrades.
+     */
+    uint8_t const u2OldState = *pu2State;
+    int rc;
+    if (fPageProt == NEM_PAGE_PROT_NONE)
+    {
+        if (u2OldState > NEM_WIN_PAGE_STATE_UNMAPPED)
+        {
+            rc = nemR3WinHypercallUnmapPage(pVM, pVCpu, GCPhysDst);
+            if (RT_SUCCESS(rc))
+            {
+                *pu2State = NEM_WIN_PAGE_STATE_UNMAPPED;
+                uint32_t cMappedPages = ASMAtomicDecU32(&pVM->nem.s.cMappedPages); NOREF(cMappedPages);
+                Log5(("NEM GPA unmapped/set: %RGp (was %s, cMappedPages=%u)\n", GCPhysDst, g_apszPageStates[u2OldState], cMappedPages));
+            }
+            else
+                AssertLogRelMsgFailed(("nemR3NativeSetPhysPage/unmap: GCPhysDst=%RGp rc=%Rrc\n", GCPhysDst, rc));
+        }
+        else
+            rc = VINF_SUCCESS;
+    }
+    else if (fPageProt & NEM_PAGE_PROT_WRITE)
+    {
+        if (u2OldState != NEM_WIN_PAGE_STATE_WRITABLE || fBackingChanged)
+        {
+            rc = nemR3WinHypercallMapPage(pVM, pVCpu, GCPhysSrc, GCPhysDst,
+                                            HV_MAP_GPA_READABLE   | HV_MAP_GPA_WRITABLE
+                                          | HV_MAP_GPA_EXECUTABLE | HV_MAP_GPA_EXECUTABLE_AGAIN);
+            if (RT_SUCCESS(rc))
+            {
+                *pu2State = NEM_WIN_PAGE_STATE_WRITABLE;
+                uint32_t cMappedPages = u2OldState <= NEM_WIN_PAGE_STATE_UNMAPPED
+                                      ? ASMAtomicIncU32(&pVM->nem.s.cMappedPages) : pVM->nem.s.cMappedPages;
+                Log5(("NEM GPA writable/set: %RGp (was %s, cMappedPages=%u)\n", GCPhysDst, g_apszPageStates[u2OldState], cMappedPages));
+                NOREF(cMappedPages);
+            }
+            else
+                AssertLogRelMsgFailed(("nemR3NativeSetPhysPage/writable: GCPhysDst=%RGp rc=%Rrc\n", GCPhysDst, rc));
+        }
+        else
+            rc = VINF_SUCCESS;
+    }
+    else
+    {
+        if (u2OldState != NEM_WIN_PAGE_STATE_READABLE || fBackingChanged)
+        {
+            rc = nemR3WinHypercallMapPage(pVM, pVCpu, GCPhysSrc, GCPhysDst,
+                                          HV_MAP_GPA_READABLE | HV_MAP_GPA_EXECUTABLE | HV_MAP_GPA_EXECUTABLE_AGAIN);
+            if (RT_SUCCESS(rc))
+            {
+                *pu2State = NEM_WIN_PAGE_STATE_READABLE;
+                uint32_t cMappedPages = u2OldState <= NEM_WIN_PAGE_STATE_UNMAPPED
+                                      ? ASMAtomicIncU32(&pVM->nem.s.cMappedPages) : pVM->nem.s.cMappedPages;
+                Log5(("NEM GPA read+exec/set: %RGp (was %s, cMappedPages=%u)\n", GCPhysDst, g_apszPageStates[u2OldState], cMappedPages));
+                NOREF(cMappedPages);
+            }
+            else
+                AssertLogRelMsgFailed(("nemR3NativeSetPhysPage/writable: GCPhysDst=%RGp rc=%Rrc\n", GCPhysDst, rc));
+        }
+        else
+            rc = VINF_SUCCESS;
+    }
+
+    return VINF_SUCCESS;
+
+#else
     /*
      * Looks like we need to unmap a page before we can change the backing
@@ -2751,5 +2836,5 @@
         if (u2OldState > NEM_WIN_PAGE_STATE_UNMAPPED)
         {
-#ifdef NEM_WIN_USE_HYPERCALLS
+# ifdef NEM_WIN_USE_HYPERCALLS
             int rc = nemR3WinHypercallUnmapPage(pVM, pVCpu, GCPhysDst);
             AssertRC(rc);
@@ -2770,5 +2855,5 @@
                 return rc;
             }
-#else
+# else
             HRESULT hrc = WHvUnmapGpaRange(pVM->nem.s.hPartition, GCPhysDst, X86_PAGE_SIZE);
             if (SUCCEEDED(hrc))
@@ -2789,5 +2874,5 @@
                 return VERR_NEM_INIT_FAILED;
             }
-#endif
+# endif
         }
     }
@@ -2798,5 +2883,5 @@
     if (fPageProt & NEM_PAGE_PROT_WRITE)
     {
-#ifdef NEM_WIN_USE_HYPERCALLS
+# ifdef NEM_WIN_USE_HYPERCALLS
         int rc = nemR3WinHypercallMapPage(pVM, pVCpu, GCPhysSrc, GCPhysDst,
                                             HV_MAP_GPA_READABLE   | HV_MAP_GPA_WRITABLE
@@ -2813,5 +2898,5 @@
         LogRel(("nemR3NativeSetPhysPage/writable: GCPhysDst=%RGp rc=%Rrc\n", GCPhysDst, rc));
         return rc;
-#else
+# else
         void *pvPage;
         int rc = nemR3NativeGCPhys2R3PtrWriteable(pVM, GCPhysSrc, &pvPage);
@@ -2834,10 +2919,10 @@
         LogRel(("nemR3NativeSetPhysPage/writable: GCPhysSrc=%RGp rc=%Rrc\n", GCPhysSrc, rc));
         return rc;
-#endif
+# endif
     }
 
     if (fPageProt & NEM_PAGE_PROT_READ)
     {
-#ifdef NEM_WIN_USE_HYPERCALLS
+# ifdef NEM_WIN_USE_HYPERCALLS
         int rc = nemR3WinHypercallMapPage(pVM, pVCpu, GCPhysSrc, GCPhysDst,
                                           HV_MAP_GPA_READABLE | HV_MAP_GPA_EXECUTABLE | HV_MAP_GPA_EXECUTABLE_AGAIN);
@@ -2853,5 +2938,5 @@
         LogRel(("nemR3NativeSetPhysPage/readonly: GCPhysDst=%RGp rc=%Rrc\n", GCPhysDst, rc));
         return rc;
-#else
+# else
         const void *pvPage;
         int rc = nemR3NativeGCPhys2R3PtrReadOnly(pVM, GCPhysSrc, &pvPage);
@@ -2874,5 +2959,5 @@
         LogRel(("nemR3NativeSetPhysPage/readonly: GCPhysSrc=%RGp rc=%Rrc\n", GCPhysSrc, rc));
         return rc;
-#endif
+# endif
     }
 
@@ -2880,4 +2965,5 @@
     *pu2State = NEM_WIN_PAGE_STATE_UNMAPPED;
     return VINF_SUCCESS;
+#endif /* !NEM_WIN_USE_HYPERCALLS */
 }
 
