Index: trunk/src/VBox/VMM/Makefile.kmk
===================================================================
--- trunk/src/VBox/VMM/Makefile.kmk	(revision 70953)
+++ trunk/src/VBox/VMM/Makefile.kmk	(revision 70954)
@@ -243,4 +243,5 @@
 	VMMAll/MMAllHyper.cpp \
 	VMMAll/MMAllPagePool.cpp \
+	VMMAll/NEMAll.cpp \
 	VMMAll/PDMAll.cpp \
 	VMMAll/PDMAllCritSect.cpp \
@@ -786,4 +787,5 @@
  	VMMAll/MMAllHyper.cpp \
  	VMMAll/MMAllPagePool.cpp \
+	VMMAll/NEMAll.cpp \
  	VMMAll/PDMAll.cpp \
  	VMMAll/PDMAllCritSect.cpp \
Index: trunk/src/VBox/VMM/VMMAll/PGMAllHandler.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMAll/PGMAllHandler.cpp	(revision 70953)
+++ trunk/src/VBox/VMM/VMMAll/PGMAllHandler.cpp	(revision 70954)
@@ -26,4 +26,5 @@
 #include <VBox/vmm/mm.h>
 #include <VBox/vmm/em.h>
+#include <VBox/vmm/nem.h>
 #include <VBox/vmm/stam.h>
 #ifdef VBOX_WITH_REM
@@ -31,7 +32,4 @@
 #endif
 #include <VBox/vmm/dbgf.h>
-#ifdef VBOX_WITH_REM
-# include <VBox/vmm/rem.h>
-#endif
 #include "PGMInternal.h"
 #include <VBox/vmm/vm.h>
@@ -51,5 +49,5 @@
 *********************************************************************************************************************************/
 static int  pgmHandlerPhysicalSetRamFlagsAndFlushShadowPTs(PVM pVM, PPGMPHYSHANDLER pCur, PPGMRAMRANGE pRam);
-static void pgmHandlerPhysicalDeregisterNotifyREM(PVM pVM, PPGMPHYSHANDLER pCur);
+static void pgmHandlerPhysicalDeregisterNotifyREMAndNEM(PVM pVM, PPGMPHYSHANDLER pCur, int fRestoreRAM);
 static void pgmHandlerPhysicalResetRamFlags(PVM pVM, PPGMPHYSHANDLER pCur);
 
@@ -285,4 +283,8 @@
         if (rc == VINF_PGM_SYNC_CR3)
             rc = VINF_PGM_GCPHYS_ALIASED;
+
+#if defined(IN_RING3) || defined(IN_RING0)
+        NEMHCNotifyHandlerPhysicalRegister(pVM, pType->enmKind, GCPhys, GCPhysLast - GCPhys + 1);
+#endif
         pgmUnlock(pVM);
 
@@ -421,9 +423,11 @@
  * @param   pVM             The cross context VM structure.
  * @param   pPhysHandler    The handler to deregister (but not free).
- */
-int pgmHandlerPhysicalExDeregister(PVM pVM, PPGMPHYSHANDLER pPhysHandler)
-{
-    LogFlow(("pgmHandlerPhysicalExDeregister: Removing Range %RGp-%RGp %s\n",
-             pPhysHandler->Core.Key, pPhysHandler->Core.KeyLast, R3STRING(pPhysHandler->pszDesc)));
+ * @param   fRestoreAsRAM   How this will likely be restored, if we know (true,
+ *                          false, or if we don't know -1).
+ */
+int pgmHandlerPhysicalExDeregister(PVM pVM, PPGMPHYSHANDLER pPhysHandler, int fRestoreAsRAM)
+{
+    LogFlow(("pgmHandlerPhysicalExDeregister: Removing Range %RGp-%RGp %s fRestoreAsRAM=%d\n",
+             pPhysHandler->Core.Key, pPhysHandler->Core.KeyLast, R3STRING(pPhysHandler->pszDesc), fRestoreAsRAM));
     AssertReturn(pPhysHandler->Core.Key != NIL_RTGCPHYS, VERR_PGM_HANDLER_NOT_FOUND);
 
@@ -441,5 +445,5 @@
          */
         pgmHandlerPhysicalResetRamFlags(pVM, pPhysHandler);
-        pgmHandlerPhysicalDeregisterNotifyREM(pVM, pPhysHandler);
+        pgmHandlerPhysicalDeregisterNotifyREMAndNEM(pVM, pPhysHandler, fRestoreAsRAM);
         pVM->pgm.s.pLastPhysHandlerR0 = 0;
         pVM->pgm.s.pLastPhysHandlerR3 = 0;
@@ -520,5 +524,5 @@
          */
         pgmHandlerPhysicalResetRamFlags(pVM, pRemoved);
-        pgmHandlerPhysicalDeregisterNotifyREM(pVM, pRemoved);
+        pgmHandlerPhysicalDeregisterNotifyREMAndNEM(pVM, pRemoved, -1);
         pVM->pgm.s.pLastPhysHandlerR0 = 0;
         pVM->pgm.s.pLastPhysHandlerR3 = 0;
@@ -542,5 +546,5 @@
  * Shared code with modify.
  */
-static void pgmHandlerPhysicalDeregisterNotifyREM(PVM pVM, PPGMPHYSHANDLER pCur)
+static void pgmHandlerPhysicalDeregisterNotifyREMAndNEM(PVM pVM, PPGMPHYSHANDLER pCur, int fRestoreAsRAM)
 {
     PPGMPHYSHANDLERTYPEINT  pCurType    = PGMPHYSHANDLER_GET_TYPE(pVM, pCur);
@@ -555,6 +559,6 @@
      * included in the REM notification or not.
      */
-    if (    (pCur->Core.Key & PAGE_OFFSET_MASK)
-        ||  ((pCur->Core.KeyLast + 1) & PAGE_OFFSET_MASK))
+    if (   (pCur->Core.Key           & PAGE_OFFSET_MASK)
+        || ((pCur->Core.KeyLast + 1) & PAGE_OFFSET_MASK))
     {
         Assert(pCurType->enmKind != PGMPHYSHANDLERKIND_MMIO);
@@ -595,19 +599,23 @@
     }
 
+    /*
+     * Tell REM and NEM.
+     */
 #ifdef VBOX_WITH_REM
-    /*
-     * Tell REM.
-     */
-    const bool fRestoreAsRAM = pCurType->pfnHandlerR3
-                            && pCurType->enmKind != PGMPHYSHANDLERKIND_MMIO; /** @todo this isn't entirely correct. */
+    const bool fRestoreAsRAM2 = pCurType->pfnHandlerR3
+                             && pCurType->enmKind != PGMPHYSHANDLERKIND_MMIO; /** @todo this isn't entirely correct. */
 # ifndef IN_RING3
     REMNotifyHandlerPhysicalDeregister(pVM, pCurType->enmKind, GCPhysStart, GCPhysLast - GCPhysStart + 1,
-                                       !!pCurType->pfnHandlerR3, fRestoreAsRAM);
+                                       !!pCurType->pfnHandlerR3, fRestoreAsRAM2);
 # else
     REMR3NotifyHandlerPhysicalDeregister(pVM, pCurType->enmKind, GCPhysStart, GCPhysLast - GCPhysStart + 1,
-                                         !!pCurType->pfnHandlerR3, fRestoreAsRAM);
+                                         !!pCurType->pfnHandlerR3, fRestoreAsRAM2);
 # endif
+#endif
+#if defined(IN_RING3) || defined(IN_RING0)
+    NEMHCNotifyHandlerPhysicalDeregister(pVM, pCurType->enmKind, GCPhysStart, GCPhysLast - GCPhysStart + 1,
+                                         fRestoreAsRAM, fRestoreAsRAM2);
 #else
-    RT_NOREF_PV(pCurType);
+    RT_NOREF_PV(fRestoreAsRAM); /** @todo this needs more work for REM! */
 #endif
 }
@@ -816,8 +824,8 @@
          */
         pgmHandlerPhysicalResetRamFlags(pVM, pCur);
-#ifdef VBOX_WITH_REM
-        PPGMPHYSHANDLERTYPEINT pCurType = PGMPHYSHANDLER_GET_TYPE(pVM, pCur);
-        const bool fRestoreAsRAM = pCurType->pfnHandlerR3
-                                && pCurType->enmKind != PGMPHYSHANDLERKIND_MMIO; /** @todo this isn't entirely correct. */
+#if defined(VBOX_WITH_REM) || defined(IN_RING3) || defined(IN_RING0)
+        PPGMPHYSHANDLERTYPEINT const pCurType      = PGMPHYSHANDLER_GET_TYPE(pVM, pCur);
+        bool const                   fRestoreAsRAM = pCurType->pfnHandlerR3 /** @todo this isn't entirely correct. */
+                                                  && pCurType->enmKind != PGMPHYSHANDLERKIND_MMIO;
 #endif
 
@@ -842,8 +850,10 @@
                 if (RTAvlroGCPhysInsert(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, &pCur->Core))
                 {
+#if defined(VBOX_WITH_REM) || defined(IN_RING3) || defined(IN_RING0)
+                    RTGCPHYS            const cb            = GCPhysLast - GCPhys + 1;
+                    PGMPHYSHANDLERKIND  const enmKind       = pCurType->enmKind;
+#endif
 #ifdef VBOX_WITH_REM
-                    RTGCPHYS            cb            = GCPhysLast - GCPhys + 1;
-                    PGMPHYSHANDLERKIND  enmKind       = pCurType->enmKind;
-                    bool                fHasHCHandler = !!pCurType->pfnHandlerR3;
+                    bool                const fHasHCHandler = !!pCurType->pfnHandlerR3;
 #endif
 
@@ -852,4 +862,9 @@
                      */
                     rc = pgmHandlerPhysicalSetRamFlagsAndFlushShadowPTs(pVM, pCur, pRam);
+
+#if defined(IN_RING3) || defined(IN_RING0)
+                    NEMHCNotifyHandlerPhysicalModify(pVM, enmKind, GCPhysCurrent, GCPhys, cb, fRestoreAsRAM);
+#endif
+
                     pgmUnlock(pVM);
 
@@ -888,5 +903,5 @@
          * We've only gotta notify REM and free the memory.
          */
-        pgmHandlerPhysicalDeregisterNotifyREM(pVM, pCur);
+        pgmHandlerPhysicalDeregisterNotifyREMAndNEM(pVM, pCur, -1);
         pVM->pgm.s.pLastPhysHandlerR0 = 0;
         pVM->pgm.s.pLastPhysHandlerR3 = 0;
Index: trunk/src/VBox/VMM/VMMR3/NEMR3.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMR3/NEMR3.cpp	(revision 70953)
+++ trunk/src/VBox/VMM/VMMR3/NEMR3.cpp	(revision 70954)
@@ -235,2 +235,78 @@
 }
 
+
+VMMR3_INT_DECL(int)  NEMR3NotifyPhysRamRegister(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb)
+{
+    int rc = VINF_SUCCESS;
+#ifdef VBOX_WITH_NATIVE_NEM
+    if (pVM->bMainExecutionEngine == VM_EXEC_ENGINE_NATIVE_API)
+        rc = nemR3NativeNotifyPhysRamRegister(pVM, GCPhys, cb);
+#else
+    NOREF(pVM); NOREF(GCPhys); NOREF(cb);
+#endif
+    return rc;
+}
+
+
+VMMR3_INT_DECL(int)  NEMR3NotifyPhysMmioExMap(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t fFlags)
+{
+    int rc = VINF_SUCCESS;
+#ifdef VBOX_WITH_NATIVE_NEM
+    if (pVM->bMainExecutionEngine == VM_EXEC_ENGINE_NATIVE_API)
+        rc = nemR3NativeNotifyPhysMmioExMap(pVM, GCPhys, cb, fFlags);
+#else
+    NOREF(pVM); NOREF(GCPhys); NOREF(cb); NOREF(fFlags);
+#endif
+    return rc;
+}
+
+
+VMMR3_INT_DECL(int)  NEMR3NotifyPhysMmioExUnmap(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t fFlags)
+{
+    int rc = VINF_SUCCESS;
+#ifdef VBOX_WITH_NATIVE_NEM
+    if (pVM->bMainExecutionEngine == VM_EXEC_ENGINE_NATIVE_API)
+        rc = nemR3NativeNotifyPhysMmioExUnmap(pVM, GCPhys, cb, fFlags);
+#else
+    NOREF(pVM); NOREF(GCPhys); NOREF(cb); NOREF(fFlags);
+#endif
+    return rc;
+}
+
+
+VMMR3_INT_DECL(int)  NEMR3NotifyPhysRomRegisterEarly(PVM pVM, RTGCPHYS GCPhys, RTUINT cb, uint32_t fFlags)
+{
+    int rc = VINF_SUCCESS;
+#ifdef VBOX_WITH_NATIVE_NEM
+    if (pVM->bMainExecutionEngine == VM_EXEC_ENGINE_NATIVE_API)
+        rc = nemR3NativeNotifyPhysRomRegisterEarly(pVM, GCPhys, cb, fFlags);
+#else
+    NOREF(pVM); NOREF(GCPhys); NOREF(cb); NOREF(fFlags);
+#endif
+    return rc;
+}
+
+
+VMMR3_INT_DECL(int)  NEMR3NotifyPhysRomRegisterLate(PVM pVM, RTGCPHYS GCPhys, RTUINT cb, uint32_t fFlags)
+{
+    int rc = VINF_SUCCESS;
+#ifdef VBOX_WITH_NATIVE_NEM
+    if (pVM->bMainExecutionEngine == VM_EXEC_ENGINE_NATIVE_API)
+        rc = nemR3NativeNotifyPhysRomRegisterLate(pVM, GCPhys, cb, fFlags);
+#else
+    NOREF(pVM); NOREF(GCPhys); NOREF(cb); NOREF(fFlags);
+#endif
+    return rc;
+}
+
+
+VMMR3_INT_DECL(void) NEMR3NotifySetA20(PVMCPU pVCpu, bool fEnabled)
+{
+#ifdef VBOX_WITH_NATIVE_NEM
+    if (pVCpu->pVMR3->bMainExecutionEngine == VM_EXEC_ENGINE_NATIVE_API)
+        nemR3NativeNotifySetA20(pVCpu, fEnabled);
+#else
+    NOREF(pVCpu); NOREF(fEnabled);
+#endif
+}
+
Index: trunk/src/VBox/VMM/VMMR3/NEMR3Native-win.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMR3/NEMR3Native-win.cpp	(revision 70953)
+++ trunk/src/VBox/VMM/VMMR3/NEMR3Native-win.cpp	(revision 70954)
@@ -122,4 +122,112 @@
 #endif
 
+
+
+/**
+ * Worker for nemR3NativeInit that probes and load the native API.
+ *
+ * @returns VBox status code.
+ * @param   fForced             Whether the HMForced flag is set and we should
+ *                              fail if we cannot initialize.
+ * @param   pErrInfo            Where to always return error info.
+ */
+static int nemR3WinInitProbeAndLoad(bool fForced, PRTERRINFO pErrInfo)
+{
+    /*
+     * Check that the DLL files we need are present, but without loading them.
+     * We'd like to avoid loading them unnecessarily.
+     */
+    WCHAR wszPath[MAX_PATH + 64];
+    UINT  cwcPath = GetSystemDirectoryW(wszPath, MAX_PATH);
+    if (cwcPath >= MAX_PATH || cwcPath < 2)
+        return RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED, "GetSystemDirectoryW failed (%#x / %u)", cwcPath, GetLastError());
+
+    if (wszPath[cwcPath - 1] != '\\' || wszPath[cwcPath - 1] != '/')
+        wszPath[cwcPath++] = '\\';
+    RTUtf16CopyAscii(&wszPath[cwcPath], RT_ELEMENTS(wszPath) - cwcPath, "WinHvPlatform.dll");
+    if (GetFileAttributesW(wszPath) == INVALID_FILE_ATTRIBUTES)
+        return RTErrInfoSetF(pErrInfo, VERR_NEM_NOT_AVAILABLE, "The native API dll was not found (%ls)", wszPath);
+
+    /*
+     * Check that we're in a VM and that the hypervisor identifies itself as Hyper-V.
+     */
+    if (!ASMHasCpuId())
+        return RTErrInfoSet(pErrInfo, VERR_NEM_NOT_AVAILABLE, "No CPUID support");
+    if (!ASMIsValidStdRange(ASMCpuId_EAX(0)))
+        return RTErrInfoSet(pErrInfo, VERR_NEM_NOT_AVAILABLE, "No CPUID leaf #1");
+    if (!(ASMCpuId_ECX(1) & X86_CPUID_FEATURE_ECX_HVP))
+        return RTErrInfoSet(pErrInfo, VERR_NEM_NOT_AVAILABLE, "Not in a hypervisor partition (HVP=0)");
+
+    uint32_t cMaxHyperLeaf = 0;
+    uint32_t uEbx = 0;
+    uint32_t uEcx = 0;
+    uint32_t uEdx = 0;
+    ASMCpuIdExSlow(0x40000000, 0, 0, 0, &cMaxHyperLeaf, &uEbx, &uEcx, &uEdx);
+    if (!ASMIsValidHypervisorRange(cMaxHyperLeaf))
+        return RTErrInfoSetF(pErrInfo, VERR_NEM_NOT_AVAILABLE, "Invalid hypervisor CPUID range (%#x %#x %#x %#x)",
+                             cMaxHyperLeaf, uEbx, uEcx, uEdx);
+    if (   uEbx != UINT32_C(0x7263694d) /* Micr */
+        || uEcx != UINT32_C(0x666f736f) /* osof */
+        || uEdx != UINT32_C(0x76482074) /* t Hv */)
+        return RTErrInfoSetF(pErrInfo, VERR_NEM_NOT_AVAILABLE,
+                             "Not Hyper-V CPUID signature: %#x %#x %#x (expected %#x %#x %#x)",
+                             uEbx, uEcx, uEdx, UINT32_C(0x7263694d), UINT32_C(0x666f736f), UINT32_C(0x76482074));
+    if (cMaxHyperLeaf < UINT32_C(0x40000005))
+        return RTErrInfoSetF(pErrInfo, VERR_NEM_NOT_AVAILABLE, "Too narrow hypervisor CPUID range (%#x)", cMaxHyperLeaf);
+
+    /** @todo would be great if we could recognize a root partition from the
+     *        CPUID info, but I currently don't dare do that. */
+
+    /*
+     * Now try load the DLLs and resolve the APIs.
+     */
+    static const char * const s_apszDllNames[2] = { "WinHvPlatform.dll",  "vid.dll" };
+    RTLDRMOD                  ahMods[2]         = { NIL_RTLDRMOD,          NIL_RTLDRMOD };
+    int                       rc = VINF_SUCCESS;
+    for (unsigned i = 0; i < RT_ELEMENTS(s_apszDllNames); i++)
+    {
+        int rc2 = RTLdrLoadSystem(s_apszDllNames[i], true /*fNoUnload*/, &ahMods[i]);
+        if (RT_FAILURE(rc2))
+        {
+            if (!RTErrInfoIsSet(pErrInfo))
+                RTErrInfoSetF(pErrInfo, rc2, "Failed to load API DLL: %s: %Rrc", s_apszDllNames[i], rc2);
+            else
+                RTErrInfoAddF(pErrInfo, rc2, "; %s: %Rrc", s_apszDllNames[i], rc2);
+            ahMods[i] = NIL_RTLDRMOD;
+            rc = VERR_NEM_INIT_FAILED;
+        }
+    }
+    if (RT_SUCCESS(rc))
+    {
+        for (unsigned i = 0; i < RT_ELEMENTS(g_aImports); i++)
+        {
+            int rc2 = RTLdrGetSymbol(ahMods[g_aImports[i].idxDll], g_aImports[i].pszName, (void **)g_aImports[i].ppfn);
+            if (RT_FAILURE(rc2))
+            {
+                *g_aImports[i].ppfn = NULL;
+
+                LogRel(("NEM:  %s: Failed to import %s!%s: %Rrc",
+                        g_aImports[i].fOptional ? "info" : fForced ? "fatal" : "error",
+                        s_apszDllNames[g_aImports[i].idxDll], g_aImports[i].pszName, rc2));
+                if (!g_aImports[i].fOptional)
+                {
+                    if (RTErrInfoIsSet(pErrInfo))
+                        RTErrInfoAddF(pErrInfo, rc2, ", %s!%s",
+                                      s_apszDllNames[g_aImports[i].idxDll], g_aImports[i].pszName);
+                    else
+                        rc = RTErrInfoSetF(pErrInfo, rc2, "Failed to import: %s!%s",
+                                           s_apszDllNames[g_aImports[i].idxDll], g_aImports[i].pszName);
+                    Assert(RT_FAILURE(rc));
+                }
+            }
+        }
+        if (RT_SUCCESS(rc))
+            Assert(!RTErrInfoIsSet(pErrInfo));
+    }
+
+    for (unsigned i = 0; i < RT_ELEMENTS(ahMods); i++)
+        RTLdrClose(ahMods[i]);
+    return rc;
+}
 
 
@@ -413,127 +521,25 @@
     /*
      * Error state.
-     *
-     * The error message will be non-empty on failure, 'rc' may or  may not
-     * be set.  Early API detection failures will not set 'rc', so we'll sort
-     * that out at the other end of the function.
+     * The error message will be non-empty on failure and 'rc' will be set too.
      */
     RTERRINFOSTATIC ErrInfo;
-    int             rc = VINF_SUCCESS;
     PRTERRINFO pErrInfo = RTErrInfoInitStatic(&ErrInfo);
-
-    /*
-     * Check that the DLL files we need are present, but without loading them.
-     * We'd like to avoid loading them unnecessarily.
-     */
-    WCHAR wszPath[MAX_PATH + 64];
-    UINT  cwcPath = GetSystemDirectoryW(wszPath, MAX_PATH);
-    if (cwcPath >= MAX_PATH || cwcPath < 2)
-        rc = RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED, "GetSystemDirectoryW failed (%#x / %u)", cwcPath, GetLastError());
-    else
-    {
-        if (wszPath[cwcPath - 1] != '\\' || wszPath[cwcPath - 1] != '/')
-            wszPath[cwcPath++] = '\\';
-        RTUtf16CopyAscii(&wszPath[cwcPath], RT_ELEMENTS(wszPath) - cwcPath, "WinHvPlatform.dll");
-        if (GetFileAttributesW(wszPath) == INVALID_FILE_ATTRIBUTES)
-            rc = RTErrInfoSetF(pErrInfo, VERR_NEM_NOT_AVAILABLE, "The native API dll was not found (%ls)", wszPath);
-        else
+    int rc = nemR3WinInitProbeAndLoad(fForced, pErrInfo);
+    if (RT_SUCCESS(rc))
+    {
+        /*
+         * Check the capabilties of the hypervisor, starting with whether it's present.
+         */
+        rc = nemR3WinInitCheckCapabilities(pVM, pErrInfo);
+        if (RT_SUCCESS(rc))
         {
             /*
-             * Check that we're in a VM and that the hypervisor identifies itself as Hyper-V.
+             * Create and initialize a partition.
              */
-            if (!ASMHasCpuId())
-                rc = RTErrInfoSet(pErrInfo, VERR_NEM_NOT_AVAILABLE, "No CPUID support");
-            else if (!ASMIsValidStdRange(ASMCpuId_EAX(0)))
-                rc = RTErrInfoSet(pErrInfo, VERR_NEM_NOT_AVAILABLE, "No CPUID leaf #1");
-            else if (!(ASMCpuId_ECX(1) & X86_CPUID_FEATURE_ECX_HVP))
-                rc = RTErrInfoSet(pErrInfo, VERR_NEM_NOT_AVAILABLE, "Not in a hypervisor partition (HVP=0)");
-            else
+            rc = nemR3WinInitCreatePartition(pVM, pErrInfo);
+            if (RT_SUCCESS(rc))
             {
-                uint32_t cMaxHyperLeaf = 0;
-                uint32_t uEbx = 0;
-                uint32_t uEcx = 0;
-                uint32_t uEdx = 0;
-                ASMCpuIdExSlow(0x40000000, 0, 0, 0, &cMaxHyperLeaf, &uEbx, &uEcx, &uEdx);
-                if (!ASMIsValidHypervisorRange(cMaxHyperLeaf))
-                    rc = RTErrInfoSetF(pErrInfo, VERR_NEM_NOT_AVAILABLE, "Invalid hypervisor CPUID range (%#x %#x %#x %#x)",
-                                       cMaxHyperLeaf, uEbx, uEcx, uEdx);
-                else if (   uEbx != UINT32_C(0x7263694d) /* Micr */
-                         || uEcx != UINT32_C(0x666f736f) /* osof */
-                         || uEdx != UINT32_C(0x76482074) /* t Hv */)
-                    rc = RTErrInfoSetF(pErrInfo, VERR_NEM_NOT_AVAILABLE,
-                                       "Not Hyper-V CPUID signature: %#x %#x %#x (expected %#x %#x %#x)",
-                                       uEbx, uEcx, uEdx, UINT32_C(0x7263694d), UINT32_C(0x666f736f), UINT32_C(0x76482074));
-                else if (cMaxHyperLeaf < UINT32_C(0x40000005))
-                    rc = RTErrInfoSetF(pErrInfo, VERR_NEM_NOT_AVAILABLE, "Too narrow hypervisor CPUID range (%#x)", cMaxHyperLeaf);
-                else
-                {
-                    /** @todo would be great if we could recognize a root partition from the
-                     *        CPUID info, but I currently don't dare do that. */
-
-                    /*
-                     * Now try load the DLLs and resolve the APIs.
-                     */
-                    static const char * const s_pszDllPrefixes[] = { "WinHvPlatform.dll!",  "vid.dll!" };
-                    RTLDRMOD                  ahMods[2]          = { NIL_RTLDRMOD,          NIL_RTLDRMOD };
-                    rc = RTLdrLoadSystem("vid.dll", true /*fNoUnload*/, &ahMods[1]);
-                    if (RT_SUCCESS(rc))
-                    {
-                        rc = RTLdrLoadSystem("WinHvPlatform.dll", true /*fNoUnload*/, &ahMods[0]);
-                        if (RT_SUCCESS(rc))
-                        {
-                            for (unsigned i = 0; i < RT_ELEMENTS(g_aImports); i++)
-                            {
-                                int rc2 = RTLdrGetSymbol(ahMods[g_aImports[i].idxDll], g_aImports[i].pszName,
-                                                         (void **)g_aImports[i].ppfn);
-                                if (RT_FAILURE(rc2))
-                                {
-                                    *g_aImports[i].ppfn = NULL;
-
-                                    LogRel(("NEM:  %s: Failed to import %s%s: %Rrc",
-                                            g_aImports[i].fOptional ? "info" : fForced ? "fatal" : "error",
-                                            s_pszDllPrefixes[g_aImports[i].idxDll], g_aImports[i].pszName, rc2));
-                                    if (!g_aImports[i].fOptional)
-                                    {
-                                        if (RTErrInfoIsSet(pErrInfo))
-                                            RTErrInfoAddF(pErrInfo, rc2, ", %s%s",
-                                                          s_pszDllPrefixes[g_aImports[i].idxDll], g_aImports[i].pszName);
-                                        else
-                                            rc = RTErrInfoSetF(pErrInfo, rc2, "Failed to import: %s%s",
-                                                               s_pszDllPrefixes[g_aImports[i].idxDll], g_aImports[i].pszName);
-                                        Assert(RT_FAILURE(rc));
-                                    }
-                                }
-                            }
-                            if (RT_SUCCESS(rc))
-                            {
-                                Assert(!RTErrInfoIsSet(pErrInfo));
-
-                                /*
-                                 * Check the capabilties of the hypervisor, starting with whether it's present.
-                                 */
-                                rc = nemR3WinInitCheckCapabilities(pVM, pErrInfo);
-                                if (RT_SUCCESS(rc))
-                                {
-                                    /*
-                                     * Create and initialize a partition.
-                                     */
-                                    rc = nemR3WinInitCreatePartition(pVM, pErrInfo);
-                                    if (RT_SUCCESS(rc))
-                                    {
-                                        VM_SET_MAIN_EXECUTION_ENGINE(pVM, VM_EXEC_ENGINE_NATIVE_API);
-                                        Log(("NEM: Marked active!\n"));
-                                    }
-                                }
-                            }
-                            RTLdrClose(ahMods[0]);
-                        }
-                        else
-                            rc = RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED,
-                                               "Failed to load API DLL 'WinHvPlatform.dll': %Rrc", rc);
-                        RTLdrClose(ahMods[1]);
-                    }
-                    else
-                        rc = RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED, "Failed to load API DLL 'vid.dll': %Rrc", rc);
-                }
+                VM_SET_MAIN_EXECUTION_ENGINE(pVM, VM_EXEC_ENGINE_NATIVE_API);
+                Log(("NEM: Marked active!\n"));
             }
         }
@@ -706,2 +712,43 @@
 }
 
+
+int nemR3NativeNotifyPhysRamRegister(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb)
+{
+    NOREF(pVM); NOREF(GCPhys); NOREF(cb);
+    return VINF_SUCCESS;
+}
+
+
+int nemR3NativeNotifyPhysMmioExMap(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t fFlags)
+{
+    NOREF(pVM); NOREF(GCPhys); NOREF(cb); NOREF(fFlags);
+    return VINF_SUCCESS;
+}
+
+
+int nemR3NativeNotifyPhysMmioExUnmap(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t fFlags)
+{
+    NOREF(pVM); NOREF(GCPhys); NOREF(cb); NOREF(fFlags);
+    return VINF_SUCCESS;
+}
+
+
+int nemR3NativeNotifyPhysRomRegisterEarly(PVM pVM, RTGCPHYS GCPhys, RTUINT cb, uint32_t fFlags)
+{
+    NOREF(pVM); NOREF(GCPhys); NOREF(cb); NOREF(fFlags);
+    return VINF_SUCCESS;
+}
+
+
+int nemR3NativeNotifyPhysRomRegisterLate(PVM pVM, RTGCPHYS GCPhys, RTUINT cb, uint32_t fFlags)
+{
+    NOREF(pVM); NOREF(GCPhys); NOREF(cb); NOREF(fFlags);
+    return VINF_SUCCESS;
+}
+
+
+void nemR3NativeNotifySetA20(PVMCPU pVCpu, bool fEnabled)
+{
+    NOREF(pVCpu); NOREF(fEnabled);
+}
+
Index: trunk/src/VBox/VMM/VMMR3/PGMPhys.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMR3/PGMPhys.cpp	(revision 70953)
+++ trunk/src/VBox/VMM/VMMR3/PGMPhys.cpp	(revision 70954)
@@ -25,4 +25,5 @@
 #include <VBox/vmm/iom.h>
 #include <VBox/vmm/mm.h>
+#include <VBox/vmm/nem.h>
 #include <VBox/vmm/stam.h>
 #ifdef VBOX_WITH_REM
@@ -1746,14 +1747,14 @@
     }
     pgmPhysInvalidatePageMapTLB(pVM);
+
+    /*
+     * Notify NEM while holding the lock (experimental) and REM without (like always).
+     */
+    rc = NEMR3NotifyPhysRamRegister(pVM, GCPhys, cb);
     pgmUnlock(pVM);
-
 #ifdef VBOX_WITH_REM
-    /*
-     * Notify REM.
-     */
     REMR3NotifyPhysRamRegister(pVM, GCPhys, cb, REM_NOTIFY_PHYS_RAM_FLAGS_RAM);
 #endif
-
-    return VINF_SUCCESS;
+    return rc;
 }
 
@@ -3466,5 +3467,5 @@
                 {
                     pCurMmio->fFlags &= ~PGMREGMMIORANGE_F_MAPPED;
-                    pgmHandlerPhysicalExDeregister(pVM, pCurMmio->pPhysHandlerR3);
+                    pgmHandlerPhysicalExDeregister(pVM, pCurMmio->pPhysHandlerR3, fRamExists);
                 }
 
@@ -3510,14 +3511,16 @@
     pgmPhysInvalidatePageMapTLB(pVM);
 
+    /*
+     * Notify NEM while holding the lock (experimental) and REM without (like always).
+     */
+    uint32_t const fNemNotify = (pFirstMmio->fFlags & PGMREGMMIORANGE_F_MMIO2       ? NEM_NOTIFY_PHYS_MMIO_EX_F_MMIO2   : 0)
+                              | (pFirstMmio->fFlags & PGMREGMMIORANGE_F_OVERLAPPING ? NEM_NOTIFY_PHYS_MMIO_EX_F_REPLACE : 0);
+    int rc = NEMR3NotifyPhysMmioExMap(pVM, GCPhys, cbRange, fNemNotify);
     pgmUnlock(pVM);
-
 #ifdef VBOX_WITH_REM
-    /*
-     * Inform REM without holding the PGM lock.
-     */
-    if (!fRamExists && (pFirstMmio->fFlags & PGMREGMMIORANGE_F_MMIO2))
+    if (!fRamExists && (pFirstMmio->fFlags & PGMREGMMIORANGE_F_MMIO2)) /** @todo this doesn't look right. */
         REMR3NotifyPhysRamRegister(pVM, GCPhys, cbRange, REM_NOTIFY_PHYS_RAM_FLAGS_MMIO2);
 #endif
-    return VINF_SUCCESS;
+    return rc;
 }
 
@@ -3567,18 +3570,19 @@
     int rc = pgmLock(pVM);
     AssertRCReturn(rc, rc);
-    AssertReturnStmt(pFirstMmio->fFlags & PGMREGMMIORANGE_F_MAPPED, pgmUnlock(pVM), VERR_WRONG_ORDER);
+    uint16_t const fOldFlags = pFirstMmio->fFlags;
+    AssertReturnStmt(fOldFlags & PGMREGMMIORANGE_F_MAPPED, pgmUnlock(pVM), VERR_WRONG_ORDER);
 
     /*
      * If plain MMIO, we must deregister the handlers first.
      */
-    if (!(pFirstMmio->fFlags & PGMREGMMIORANGE_F_MMIO2))
+    if (!(fOldFlags & PGMREGMMIORANGE_F_MMIO2))
     {
         PPGMREGMMIORANGE pCurMmio = pFirstMmio;
-        rc = pgmHandlerPhysicalExDeregister(pVM, pFirstMmio->pPhysHandlerR3);
+        rc = pgmHandlerPhysicalExDeregister(pVM, pFirstMmio->pPhysHandlerR3, RT_BOOL(fOldFlags & PGMREGMMIORANGE_F_OVERLAPPING));
         AssertRCReturnStmt(rc, pgmUnlock(pVM), rc);
         while (!(pCurMmio->fFlags & PGMREGMMIORANGE_F_LAST_CHUNK))
         {
             pCurMmio = pCurMmio->pNextR3;
-            rc = pgmHandlerPhysicalExDeregister(pVM, pCurMmio->pPhysHandlerR3);
+            rc = pgmHandlerPhysicalExDeregister(pVM, pCurMmio->pPhysHandlerR3, RT_BOOL(fOldFlags & PGMREGMMIORANGE_F_OVERLAPPING));
             AssertRCReturnStmt(rc, pgmUnlock(pVM), VERR_PGM_PHYS_MMIO_EX_IPE);
         }
@@ -3590,9 +3594,6 @@
      * Unmap it.
      */
-#ifdef VBOX_WITH_REM
-    RTGCPHYS        GCPhysRangeREM;
-    bool            fInformREM;
-#endif
-    if (pFirstMmio->fFlags & PGMREGMMIORANGE_F_OVERLAPPING)
+    RTGCPHYS const GCPhysRangeNotify = pFirstMmio->RamRange.GCPhys;
+    if (fOldFlags & PGMREGMMIORANGE_F_OVERLAPPING)
     {
         /*
@@ -3604,5 +3605,5 @@
          */
         /* Only one chunk allowed when overlapping! */
-        Assert(pFirstMmio->fFlags & PGMREGMMIORANGE_F_LAST_CHUNK);
+        Assert(fOldFlags & PGMREGMMIORANGE_F_LAST_CHUNK);
 
         /* Restore the RAM pages we've replaced. */
@@ -3612,5 +3613,5 @@
 
         uint32_t cPagesLeft = pFirstMmio->RamRange.cb >> PAGE_SHIFT;
-        if (pFirstMmio->fFlags & PGMREGMMIORANGE_F_MMIO2)
+        if (fOldFlags & PGMREGMMIORANGE_F_MMIO2)
             pVM->pgm.s.cZeroPages += cPagesLeft;
 
@@ -3624,8 +3625,4 @@
         /* Flush physical page map TLB. */
         pgmPhysInvalidatePageMapTLB(pVM);
-#ifdef VBOX_WITH_REM
-        GCPhysRangeREM = NIL_RTGCPHYS;  /* shuts up gcc */
-        fInformREM     = false;
-#endif
 
         /* Update range state. */
@@ -3639,8 +3636,4 @@
          * Unlink the chunks related to the MMIO/MMIO2 region.
          */
-#ifdef VBOX_WITH_REM
-        GCPhysRangeREM = pFirstMmio->RamRange.GCPhys;
-        fInformREM     = RT_BOOL(pFirstMmio->fFlags & PGMREGMMIORANGE_F_MMIO2);
-#endif
         for (PPGMREGMMIORANGE pCurMmio = pFirstMmio; ; pCurMmio = pCurMmio->pNextR3)
         {
@@ -3665,15 +3658,16 @@
     pgmPhysInvalidRamRangeTlbs(pVM);
 
+    /*
+     * Notify NEM while holding the lock (experimental) and REM without (like always).
+     */
+    uint32_t const fNemFlags = (fOldFlags & PGMREGMMIORANGE_F_MMIO2       ? NEM_NOTIFY_PHYS_MMIO_EX_F_MMIO2   : 0)
+                             | (fOldFlags & PGMREGMMIORANGE_F_OVERLAPPING ? NEM_NOTIFY_PHYS_MMIO_EX_F_REPLACE : 0);
+    rc = NEMR3NotifyPhysMmioExUnmap(pVM, GCPhysRangeNotify, cbRange, fNemFlags);
     pgmUnlock(pVM);
-
 #ifdef VBOX_WITH_REM
-    /*
-     * Inform REM without holding the PGM lock.
-     */
-    if (fInformREM)
-        REMR3NotifyPhysRamDeregister(pVM, GCPhysRangeREM, cbRange);
+    if ((fOldFlags & (PGMREGMMIORANGE_F_OVERLAPPING | PGMREGMMIORANGE_F_MMIO2)) == PGMREGMMIORANGE_F_MMIO2)
+        REMR3NotifyPhysRamDeregister(pVM, GCPhysRangeNotify, cbRange);
 #endif
-
-    return VINF_SUCCESS;
+    return rc;
 }
 
@@ -4091,4 +4085,9 @@
 
 
+            /* Notify NEM before we register handlers. */
+            uint32_t const fNemNotify = (fRamExists ? NEM_NOTIFY_PHYS_ROM_F_REPLACE : 0)
+                                      | (fFlags & PGMPHYS_ROM_FLAGS_SHADOWED ? NEM_NOTIFY_PHYS_ROM_F_SHADOW : 0);
+            rc = NEMR3NotifyPhysRomRegisterEarly(pVM, GCPhys, cb, fNemNotify);
+
             /*
              * !HACK ALERT!  REM + (Shadowed) ROM ==> mess.
@@ -4105,13 +4104,15 @@
                 REMR3NotifyPhysRomRegister(pVM, GCPhys, cb, NULL, true /* fShadowed */);
 #endif
-                rc = PGMHandlerPhysicalRegister(pVM, GCPhys, GCPhysLast, pVM->pgm.s.hRomPhysHandlerType,
-                                                pRomNew, MMHyperCCToR0(pVM, pRomNew), MMHyperCCToRC(pVM, pRomNew),
-                                                pszDesc);
+                if (RT_SUCCESS(rc))
+                    rc = PGMHandlerPhysicalRegister(pVM, GCPhys, GCPhysLast, pVM->pgm.s.hRomPhysHandlerType,
+                                                    pRomNew, MMHyperCCToR0(pVM, pRomNew), MMHyperCCToRC(pVM, pRomNew),
+                                                    pszDesc);
             }
             else
             {
-                rc = PGMHandlerPhysicalRegister(pVM, GCPhys, GCPhysLast, pVM->pgm.s.hRomPhysHandlerType,
-                                                pRomNew, MMHyperCCToR0(pVM, pRomNew), MMHyperCCToRC(pVM, pRomNew),
-                                                pszDesc);
+                if (RT_SUCCESS(rc))
+                    rc = PGMHandlerPhysicalRegister(pVM, GCPhys, GCPhysLast, pVM->pgm.s.hRomPhysHandlerType,
+                                                    pRomNew, MMHyperCCToR0(pVM, pRomNew), MMHyperCCToRC(pVM, pRomNew),
+                                                    pszDesc);
 #ifdef VBOX_WITH_REM
                 REMR3NotifyPhysRomRegister(pVM, GCPhys, cb, NULL, false /* fShadowed */);
@@ -4203,5 +4204,7 @@
                         pgmPhysInvalidatePageMapTLB(pVM);
                         GMMR3AllocatePagesCleanup(pReq);
-                        return VINF_SUCCESS;
+
+                        /* Notify NEM again. */
+                        return NEMR3NotifyPhysRomRegisterLate(pVM, GCPhys, cb, fNemNotify);
                     }
 
@@ -4535,4 +4538,5 @@
         REMR3A20Set(pVCpu->pVMR3, pVCpu, fEnable);
 #endif
+        NEMR3NotifySetA20(pVCpu, fEnable);
 #ifdef PGM_WITH_A20
         pVCpu->pgm.s.fSyncFlags |= PGM_SYNC_UPDATE_PAGE_BIT_VIRTUAL;
Index: trunk/src/VBox/VMM/include/NEMInternal.h
===================================================================
--- trunk/src/VBox/VMM/include/NEMInternal.h	(revision 70953)
+++ trunk/src/VBox/VMM/include/NEMInternal.h	(revision 70954)
@@ -115,4 +115,10 @@
 void    nemR3NativeReset(PVM pVM);
 void    nemR3NativeResetCpu(PVMCPU pVCpu);
+int     nemR3NativeNotifyPhysRamRegister(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb);
+int     nemR3NativeNotifyPhysMmioExMap(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t fFlags);
+int     nemR3NativeNotifyPhysMmioExUnmap(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t fFlags);
+int     nemR3NativeNotifyPhysRomRegisterEarly(PVM pVM, RTGCPHYS GCPhys, RTUINT cb, uint32_t fFlags);
+int     nemR3NativeNotifyPhysRomRegisterLate(PVM pVM, RTGCPHYS GCPhys, RTUINT cb, uint32_t fFlags);
+void    nemR3NativeNotifySetA20(PVMCPU pVCpu, bool fEnabled);
 #endif
 
Index: trunk/src/VBox/VMM/include/PGMInternal.h
===================================================================
--- trunk/src/VBox/VMM/include/PGMInternal.h	(revision 70953)
+++ trunk/src/VBox/VMM/include/PGMInternal.h	(revision 70954)
@@ -4195,5 +4195,5 @@
 int             pgmHandlerPhysicalExDup(PVM pVM, PPGMPHYSHANDLER pPhysHandlerSrc, PPGMPHYSHANDLER *ppPhysHandler);
 int             pgmHandlerPhysicalExRegister(PVM pVM, PPGMPHYSHANDLER pPhysHandler, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast);
-int             pgmHandlerPhysicalExDeregister(PVM pVM, PPGMPHYSHANDLER pPhysHandler);
+int             pgmHandlerPhysicalExDeregister(PVM pVM, PPGMPHYSHANDLER pPhysHandler, int fRestoreAsRAM);
 int             pgmHandlerPhysicalExDestroy(PVM pVM, PPGMPHYSHANDLER pHandler);
 void            pgmR3HandlerPhysicalUpdateAll(PVM pVM);
