Index: trunk/src/VBox/VMM/VMMAll/NEMAllNativeTemplate-win.cpp.h
===================================================================
--- trunk/src/VBox/VMM/VMMAll/NEMAllNativeTemplate-win.cpp.h	(revision 72923)
+++ trunk/src/VBox/VMM/VMMAll/NEMAllNativeTemplate-win.cpp.h	(revision 72924)
@@ -151,10 +151,16 @@
 NEM_TMPL_STATIC int nemHCWinCopyStateToHyperV(PVM pVM, PVMCPU pVCpu)
 {
-# ifdef NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS
-    int rc = VMMR3CallR0Emt(pVM, pVCpu, VMMR0_DO_NEM_EXPORT_STATE, 0, NULL);
-    AssertLogRelRCReturn(rc, rc);
-    return rc;
-
-# else
+# if defined(NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS) || defined(NEM_WIN_WITH_RING0_RUNLOOP)
+#  if !defined(NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS) && defined(NEM_WIN_WITH_RING0_RUNLOOP)
+    if (pVM->nem.s.fUseRing0Runloop)
+#  endif
+    {
+        int rc = VMMR3CallR0Emt(pVM, pVCpu, VMMR0_DO_NEM_EXPORT_STATE, 0, NULL);
+        AssertLogRelRCReturn(rc, rc);
+        return rc;
+    }
+# endif
+# ifndef NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS
+
     /*
      * The following is very similar to what nemR0WinExportState() does.
@@ -480,17 +486,22 @@
 NEM_TMPL_STATIC int nemHCWinCopyStateFromHyperV(PVM pVM, PVMCPU pVCpu, uint64_t fWhat)
 {
-# ifdef NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS
-    /* See NEMR0ImportState */
-    int rc = VMMR3CallR0Emt(pVM, pVCpu, VMMR0_DO_NEM_IMPORT_STATE, fWhat, NULL);
-    if (RT_SUCCESS(rc))
+# if defined(NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS) || defined(NEM_WIN_WITH_RING0_RUNLOOP)
+#  if !defined(NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS) && defined(NEM_WIN_WITH_RING0_RUNLOOP)
+    if (pVM->nem.s.fUseRing0Runloop)
+#  endif
+    {
+        /* See NEMR0ImportState */
+        int rc = VMMR3CallR0Emt(pVM, pVCpu, VMMR0_DO_NEM_IMPORT_STATE, fWhat, NULL);
+        if (RT_SUCCESS(rc))
+            return rc;
+        if (rc == VERR_NEM_FLUSH_TLB)
+            return PGMFlushTLB(pVCpu, pVCpu->cpum.GstCtx.cr3, true /*fGlobal*/);
+        if (rc == VERR_NEM_CHANGE_PGM_MODE)
+            return PGMChangeMode(pVCpu, pVCpu->cpum.GstCtx.cr0, pVCpu->cpum.GstCtx.cr4, pVCpu->cpum.GstCtx.msrEFER);
+        AssertLogRelRCReturn(rc, rc);
         return rc;
-    if (rc == VERR_NEM_FLUSH_TLB)
-        return PGMFlushTLB(pVCpu, pVCpu->cpum.GstCtx.cr3, true /*fGlobal*/);
-    if (rc == VERR_NEM_CHANGE_PGM_MODE)
-        return PGMChangeMode(pVCpu, pVCpu->cpum.GstCtx.cr0, pVCpu->cpum.GstCtx.cr4, pVCpu->cpum.GstCtx.msrEFER);
-    AssertLogRelRCReturn(rc, rc);
-    return rc;
-
-# else
+    }
+# endif
+# ifndef NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS
     WHV_REGISTER_NAME  aenmNames[128];
 
@@ -1122,4 +1133,5 @@
 
 #ifdef IN_RING0
+# ifdef NEM_WIN_WITH_RING0_RUNLOOP
     /** @todo improve and secure this translation */
     PGVM pGVM = GVMMR0ByHandle(pVCpu->pVMR0->hSelf);
@@ -1130,4 +1142,8 @@
 
     return nemR0WinImportState(pGVM, &pGVM->aCpus[idCpu], &pVCpu->cpum.GstCtx, fWhat);
+# else
+    RT_NOREF(pVCpu, fWhat);
+    return VERR_NOT_IMPLEMENTED;
+# endif
 #else
     return nemHCWinCopyStateFromHyperV(pVCpu->pVMR3, pVCpu, fWhat);
@@ -1153,15 +1169,20 @@
     AssertReturn(VM_IS_NEM_ENABLED(pVM), VERR_NEM_IPE_9);
 
-# ifdef NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS
-    /* Call ring-0 and get the values. */
-    int rc = VMMR3CallR0Emt(pVM, pVCpu, VMMR0_DO_NEM_QUERY_CPU_TICK, 0, NULL);
-    AssertLogRelRCReturn(rc, rc);
-    *pcTicks = pVCpu->nem.s.Hypercall.QueryCpuTick.cTicks;
-    if (puAux)
-        *puAux = pVCpu->cpum.GstCtx.fExtrn & CPUMCTX_EXTRN_TSC_AUX
-               ? pVCpu->nem.s.Hypercall.QueryCpuTick.uAux : CPUMGetGuestTscAux(pVCpu);
-    return VINF_SUCCESS;
-
-# else
+# if defined(NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS) || defined(NEM_WIN_WITH_RING0_RUNLOOP)
+#  if !defined(NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS) && defined(NEM_WIN_WITH_RING0_RUNLOOP)
+    if (pVM->nem.s.fUseRing0Runloop)
+#  endif
+    {
+        /* Call ring-0 and get the values. */
+        int rc = VMMR3CallR0Emt(pVM, pVCpu, VMMR0_DO_NEM_QUERY_CPU_TICK, 0, NULL);
+        AssertLogRelRCReturn(rc, rc);
+        *pcTicks = pVCpu->nem.s.Hypercall.QueryCpuTick.cTicks;
+        if (puAux)
+            *puAux = pVCpu->cpum.GstCtx.fExtrn & CPUMCTX_EXTRN_TSC_AUX
+                   ? pVCpu->nem.s.Hypercall.QueryCpuTick.uAux : CPUMGetGuestTscAux(pVCpu);
+        return VINF_SUCCESS;
+    }
+# endif
+# ifndef NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS
     /* Call the offical API. */
     WHV_REGISTER_NAME  aenmNames[2] = { WHvX64RegisterTsc, WHvX64RegisterTscAux };
@@ -1177,6 +1198,7 @@
         *pcTicks = pVCpu->cpum.GstCtx.fExtrn & CPUMCTX_EXTRN_TSC_AUX ? aValues[0].Reg64 : CPUMGetGuestTscAux(pVCpu);
     return VINF_SUCCESS;
-#endif
+# endif /* !NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS */
 #else  /* IN_RING0 */
+# ifdef NEM_WIN_WITH_RING0_RUNLOOP
     /** @todo improve and secure this translation */
     PGVM pGVM = GVMMR0ByHandle(pVCpu->pVMR0->hSelf);
@@ -1190,4 +1212,8 @@
         *puAux = CPUMGetGuestTscAux(pVCpu);
     return rc;
+# else
+    RT_NOREF(pVCpu, pcTicks, puAux);
+    return VERR_NOT_IMPLEMENTED;
+# endif
 #endif /* IN_RING0 */
 }
@@ -1207,4 +1233,5 @@
 {
 #ifdef IN_RING0
+# ifdef NEM_WIN_WITH_RING0_RUNLOOP
     /** @todo improve and secure this translation */
     PGVM pGVM = GVMMR0ByHandle(pVM->hSelf);
@@ -1215,13 +1242,22 @@
 
     return nemR0WinResumeCpuTickOnAll(pGVM, &pGVM->aCpus[idCpu], uPausedTscValue);
+# else
+    RT_NOREF(pVM, pVCpu, uPausedTscValue);
+    return VERR_NOT_IMPLEMENTED;
+# endif
 #else  /* IN_RING3 */
     VMCPU_ASSERT_EMT_RETURN(pVCpu, VERR_VM_THREAD_NOT_EMT);
     AssertReturn(VM_IS_NEM_ENABLED(pVM), VERR_NEM_IPE_9);
 
-# ifdef NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS
-    /* Call ring-0 and do it all there. */
-    return VMMR3CallR0Emt(pVM, pVCpu, VMMR0_DO_NEM_RESUME_CPU_TICK_ON_ALL, uPausedTscValue, NULL);
-
-# else
+# if defined(NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS) || defined(NEM_WIN_WITH_RING0_RUNLOOP)
+#  if !defined(NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS) && defined(NEM_WIN_WITH_RING0_RUNLOOP)
+    if (pVM->nem.s.fUseRing0Runloop)
+#  endif
+    {
+        /* Call ring-0 and do it all there. */
+        return VMMR3CallR0Emt(pVM, pVCpu, VMMR0_DO_NEM_RESUME_CPU_TICK_ON_ALL, uPausedTscValue, NULL);
+    }
+# endif
+# ifndef NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS
     /*
      * Call the offical API to do the job.
@@ -1256,5 +1292,5 @@
 
     return VINF_SUCCESS;
-# endif
+# endif /* !NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS */
 #endif /* IN_RING3 */
 }
@@ -1341,5 +1377,5 @@
 
 
-#ifdef NEM_WIN_USE_OUR_OWN_RUN_API
+#if defined(NEM_WIN_USE_OUR_OWN_RUN_API) || defined(NEM_WIN_WITH_RING0_RUNLOOP)
 # ifdef IN_RING3 /* hopefully not needed in ring-0, as we'd need KTHREADs and KeAlertThread. */
 /**
@@ -1408,5 +1444,5 @@
 }
 # endif /* IN_RING3 */
-#endif /* NEM_WIN_USE_OUR_OWN_RUN_API */
+#endif /* NEM_WIN_USE_OUR_OWN_RUN_API || NEM_WIN_WITH_RING0_RUNLOOP */
 
 
@@ -1479,5 +1515,5 @@
     while (0)
 
-#ifdef NEM_WIN_USE_OUR_OWN_RUN_API
+#ifdef NEM_WIN_TEMPLATE_MODE_OWN_RUN_API
 /**
  * Translates the execution stat bitfield into a short log string, VID version.
@@ -1517,9 +1553,9 @@
         SWITCH_IT("RM");
 }
-#endif /* IN_RING3 && !NEM_WIN_USE_OUR_OWN_RUN_API */
+#endif /* IN_RING3 && !NEM_WIN_TEMPLATE_MODE_OWN_RUN_API */
 #undef SWITCH_IT
 
 
-#ifdef NEM_WIN_USE_OUR_OWN_RUN_API
+#ifdef NEM_WIN_TEMPLATE_MODE_OWN_RUN_API
 /**
  * Advances the guest RIP and clear EFLAGS.RF, VID version.
@@ -1572,5 +1608,5 @@
         VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
 }
-#endif /* IN_RING3 && !NEM_WIN_USE_OUR_OWN_RUN_API */
+#endif /* IN_RING3 && !NEM_WIN_TEMPLATE_MODE_OWN_RUN_API */
 
 
@@ -1796,5 +1832,5 @@
 
 
-#if defined(IN_RING0) && defined(NEM_WIN_USE_OUR_OWN_RUN_API)
+#if defined(IN_RING0) && defined(NEM_WIN_TEMPLATE_MODE_OWN_RUN_API)
 /**
  * Wrapper around nemR0WinImportState that converts VERR_NEM_CHANGE_PGM_MODE and
@@ -1825,7 +1861,7 @@
     AssertMsgFailedReturn(("%s/%u: nemR0WinImportState failed: %Rrc\n", pszCaller, pGVCpu->idCpu, rc), rc);
 }
-#endif /* IN_RING0 && NEM_WIN_USE_OUR_OWN_RUN_API*/
-
-#if defined(NEM_WIN_USE_OUR_OWN_RUN_API) || defined(IN_RING3)
+#endif /* IN_RING0 && NEM_WIN_TEMPLATE_MODE_OWN_RUN_API*/
+
+#if defined(NEM_WIN_TEMPLATE_MODE_OWN_RUN_API) || defined(IN_RING3)
 /**
  * Wrapper around nemR0WinImportStateStrict and nemHCWinCopyStateFromHyperV.
@@ -1843,17 +1879,17 @@
     if (pVCpu->cpum.GstCtx.fExtrn & fWhat)
     {
-#ifdef IN_RING0
+# ifdef IN_RING0
         return nemR0WinImportStateStrict(pGVCpu->pGVM, pGVCpu, pVCpu, fWhat, pszCaller);
-#else
+# else
         RT_NOREF(pGVCpu, pszCaller);
         int rc = nemHCWinCopyStateFromHyperV(pVCpu->pVMR3, pVCpu, fWhat);
         AssertRCReturn(rc, rc);
-#endif
+# endif
     }
     return VINF_SUCCESS;
 }
-#endif /* NEM_WIN_USE_OUR_OWN_RUN_API || IN_RING3 */
-
-#ifdef NEM_WIN_USE_OUR_OWN_RUN_API
+#endif /* NEM_WIN_TEMPLATE_MODE_OWN_RUN_API || IN_RING3 */
+
+#ifdef NEM_WIN_TEMPLATE_MODE_OWN_RUN_API
 /**
  * Copies register state from the X64 intercept message header.
@@ -1917,8 +1953,8 @@
     pVCpu->cpum.GstCtx.fExtrn &= ~(CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_NEM_WIN_INHIBIT_INT);
 }
-#endif /* IN_RING3 && !NEM_WIN_USE_OUR_OWN_RUN_API */
-
-
-#ifdef NEM_WIN_USE_OUR_OWN_RUN_API
+#endif /* IN_RING3 && !NEM_WIN_TEMPLATE_MODE_OWN_RUN_API */
+
+
+#ifdef NEM_WIN_TEMPLATE_MODE_OWN_RUN_API
 /**
  * Deals with memory intercept message.
@@ -2142,8 +2178,8 @@
     return rcStrict;
 }
-#endif /* IN_RING3 && !NEM_WIN_USE_OUR_OWN_RUN_API */
-
-
-#ifdef NEM_WIN_USE_OUR_OWN_RUN_API
+#endif /* IN_RING3 && !NEM_WIN_TEMPLATE_MODE_OWN_RUN_API */
+
+
+#ifdef NEM_WIN_TEMPLATE_MODE_OWN_RUN_API
 /**
  * Deals with I/O port intercept message.
@@ -2524,8 +2560,8 @@
     return rcStrict;
 }
-#endif /* IN_RING3 && !NEM_WIN_USE_OUR_OWN_RUN_API */
-
-
-#ifdef NEM_WIN_USE_OUR_OWN_RUN_API
+#endif /* IN_RING3 && !NEM_WIN_TEMPLATE_MODE_OWN_RUN_API */
+
+
+#ifdef NEM_WIN_TEMPLATE_MODE_OWN_RUN_API
 /**
  * Deals with interrupt window message.
@@ -2599,8 +2635,8 @@
     return VINF_SUCCESS;
 }
-#endif /* IN_RING3 && !NEM_WIN_USE_OUR_OWN_RUN_API */
-
-
-#ifdef NEM_WIN_USE_OUR_OWN_RUN_API
+#endif /* IN_RING3 && !NEM_WIN_TEMPLATE_MODE_OWN_RUN_API */
+
+
+#ifdef NEM_WIN_TEMPLATE_MODE_OWN_RUN_API
 /**
  * Deals with CPUID intercept message.
@@ -2767,8 +2803,8 @@
     return rcStrict;
 }
-#endif /* IN_RING3 && !NEM_WIN_USE_OUR_OWN_RUN_API */
-
-
-#ifdef NEM_WIN_USE_OUR_OWN_RUN_API
+#endif /* IN_RING3 && !NEM_WIN_TEMPLATE_MODE_OWN_RUN_API */
+
+
+#ifdef NEM_WIN_TEMPLATE_MODE_OWN_RUN_API
 /**
  * Deals with MSR intercept message.
@@ -3051,5 +3087,5 @@
     return rcStrict;
 }
-#endif /* IN_RING3 && !NEM_WIN_USE_OUR_OWN_RUN_API */
+#endif /* IN_RING3 && !NEM_WIN_TEMPLATE_MODE_OWN_RUN_API */
 
 
@@ -3119,5 +3155,5 @@
 
 
-#ifdef NEM_WIN_USE_OUR_OWN_RUN_API
+#ifdef NEM_WIN_TEMPLATE_MODE_OWN_RUN_API
 /**
  * Copies state included in a exception intercept message.
@@ -3166,8 +3202,8 @@
         pVCpu->cpum.GstCtx.fExtrn &= ~CPUMCTX_EXTRN_NEM_WIN_EVENT_INJECT;
 }
-#endif /* IN_RING3 && !NEM_WIN_USE_OUR_OWN_RUN_API */
-
-
-#ifdef NEM_WIN_USE_OUR_OWN_RUN_API
+#endif /* IN_RING3 && !NEM_WIN_TEMPLATE_MODE_OWN_RUN_API */
+
+
+#ifdef NEM_WIN_TEMPLATE_MODE_OWN_RUN_API
 /**
  * Deals with exception intercept message (HvMessageTypeX64ExceptionIntercept).
@@ -3399,8 +3435,8 @@
     return rcStrict;
 }
-#endif /* IN_RING3 && !NEM_WIN_USE_OUR_OWN_RUN_API */
-
-
-#ifdef NEM_WIN_USE_OUR_OWN_RUN_API
+#endif /* IN_RING3 && !NEM_WIN_TEMPLATE_MODE_OWN_RUN_API */
+
+
+#ifdef NEM_WIN_TEMPLATE_MODE_OWN_RUN_API
 /**
  * Deals with unrecoverable exception (triple fault).
@@ -3519,8 +3555,8 @@
 
 }
-#endif /* IN_RING3 && !NEM_WIN_USE_OUR_OWN_RUN_API */
-
-
-#ifdef NEM_WIN_USE_OUR_OWN_RUN_API
+#endif /* IN_RING3 && !NEM_WIN_TEMPLATE_MODE_OWN_RUN_API */
+
+
+#ifdef NEM_WIN_TEMPLATE_MODE_OWN_RUN_API
 /**
  * Handles messages (VM exits).
@@ -3683,5 +3719,5 @@
     }
 }
-#endif /* IN_RING3 && !NEM_WIN_USE_OUR_OWN_RUN_API */
+#endif /* IN_RING3 && !NEM_WIN_TEMPLATE_MODE_OWN_RUN_API */
 
 
@@ -3740,5 +3776,5 @@
 
 
-#ifdef NEM_WIN_USE_OUR_OWN_RUN_API
+#ifdef NEM_WIN_TEMPLATE_MODE_OWN_RUN_API
 /**
  * Worker for nemHCWinRunGC that stops the execution on the way out.
@@ -3898,7 +3934,7 @@
     return rcStrict;
 }
-#endif /* NEM_WIN_USE_OUR_OWN_RUN_API */
-
-#if defined(NEM_WIN_USE_OUR_OWN_RUN_API) || defined(IN_RING3)
+#endif /* NEM_WIN_TEMPLATE_MODE_OWN_RUN_API */
+
+#if defined(NEM_WIN_TEMPLATE_MODE_OWN_RUN_API) || defined(IN_RING3)
 
 /**
@@ -4048,5 +4084,5 @@
      * everything every time.  This will be optimized later.
      */
-# ifdef NEM_WIN_USE_OUR_OWN_RUN_API
+# ifdef NEM_WIN_TEMPLATE_MODE_OWN_RUN_API
     VID_MESSAGE_MAPPING_HEADER volatile *pMappingHeader = (VID_MESSAGE_MAPPING_HEADER volatile *)pVCpu->nem.s.pvMsgSlotMapping;
     uint32_t        cMillies            = 5000; /** @todo lower this later... */
@@ -4079,5 +4115,5 @@
                                      | VMCPU_FF_INTERRUPT_NMI  | VMCPU_FF_INTERRUPT_SMI))
         {
-# ifdef NEM_WIN_USE_OUR_OWN_RUN_API
+# ifdef NEM_WIN_TEMPLATE_MODE_OWN_RUN_API
             /* Make sure the CPU isn't executing. */
             if (pVCpu->nem.s.fHandleAndGetFlags == VID_MSHAGN_F_GET_NEXT_MESSAGE)
@@ -4118,5 +4154,5 @@
             || pVCpu->nem.s.fCurrentInterruptWindows != pVCpu->nem.s.fDesiredInterruptWindows)
         {
-# ifdef NEM_WIN_USE_OUR_OWN_RUN_API
+# ifdef NEM_WIN_TEMPLATE_MODE_OWN_RUN_API
             Assert(pVCpu->nem.s.fHandleAndGetFlags != VID_MSHAGN_F_GET_NEXT_MESSAGE /* not running */);
 # endif
@@ -4136,5 +4172,5 @@
             && !VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_TO_R3_MASK))
         {
-# ifdef NEM_WIN_USE_OUR_OWN_RUN_API
+# ifdef NEM_WIN_TEMPLATE_MODE_OWN_RUN_API
             if (pVCpu->nem.s.fHandleAndGetFlags)
             { /* Very likely that the CPU does NOT need starting (pending msg, running). */ }
@@ -4157,9 +4193,9 @@
                 pVCpu->nem.s.fHandleAndGetFlags = VID_MSHAGN_F_GET_NEXT_MESSAGE;
             }
-# endif /* NEM_WIN_USE_OUR_OWN_RUN_API */
+# endif /* NEM_WIN_TEMPLATE_MODE_OWN_RUN_API */
 
             if (VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC_NEM_WAIT, VMCPUSTATE_STARTED_EXEC_NEM))
             {
-# ifdef NEM_WIN_USE_OUR_OWN_RUN_API
+# ifdef NEM_WIN_TEMPLATE_MODE_OWN_RUN_API
 #  ifdef IN_RING0
                 pVCpu->nem.s.uIoCtlBuf.MsgSlotHandleAndGetNext.iCpu     = pGVCpu->idCpu;
@@ -4189,5 +4225,5 @@
                      * Deal with the message.
                      */
-# ifdef NEM_WIN_USE_OUR_OWN_RUN_API
+# ifdef NEM_WIN_TEMPLATE_MODE_OWN_RUN_API
                     rcStrict = nemHCWinHandleMessage(pVM, pVCpu, pMappingHeader, pGVCpu);
                     pVCpu->nem.s.fHandleAndGetFlags |= VID_MSHAGN_F_HANDLE_MESSAGE;
@@ -4206,5 +4242,5 @@
                 else
                 {
-# ifdef NEM_WIN_USE_OUR_OWN_RUN_API
+# ifdef NEM_WIN_TEMPLATE_MODE_OWN_RUN_API
 
                     /* VID.SYS merges STATUS_ALERTED and STATUS_USER_APC into STATUS_TIMEOUT,
@@ -4263,5 +4299,5 @@
      * state and return to EM.  We don't sync back the whole state if we can help it.
      */
-# ifdef NEM_WIN_USE_OUR_OWN_RUN_API
+# ifdef NEM_WIN_TEMPLATE_MODE_OWN_RUN_API
     if (pVCpu->nem.s.fHandleAndGetFlags == VID_MSHAGN_F_GET_NEXT_MESSAGE)
     {
@@ -4337,5 +4373,5 @@
 }
 
-#endif /* defined(NEM_WIN_USE_OUR_OWN_RUN_API) || defined(IN_RING3) */
+#endif /* defined(NEM_WIN_TEMPLATE_MODE_OWN_RUN_API) || defined(IN_RING3) */
 
 /**
Index: trunk/src/VBox/VMM/VMMR0/NEMR0Native-win.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMR0/NEMR0Native-win.cpp	(revision 72923)
+++ trunk/src/VBox/VMM/VMMR0/NEMR0Native-win.cpp	(revision 72924)
@@ -82,8 +82,10 @@
                                       uint32_t cPages, uint32_t fFlags);
 NEM_TMPL_STATIC int  nemR0WinUnmapPages(PGVM pGVM, PGVMCPU pGVCpu, RTGCPHYS GCPhys, uint32_t cPages);
+#if defined(NEM_WIN_WITH_RING0_RUNLOOP) || defined(NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS)
 NEM_TMPL_STATIC int  nemR0WinExportState(PGVM pGVM, PGVMCPU pGVCpu, PCPUMCTX pCtx);
 NEM_TMPL_STATIC int  nemR0WinImportState(PGVM pGVM, PGVMCPU pGVCpu, PCPUMCTX pCtx, uint64_t fWhat);
 NEM_TMPL_STATIC int  nemR0WinQueryCpuTick(PGVM pGVM, PGVMCPU pGVCpu, uint64_t *pcTicks, uint32_t *pcAux);
 NEM_TMPL_STATIC int  nemR0WinResumeCpuTickOnAll(PGVM pGVM, PGVMCPU pGVCpu, uint64_t uPausedTscValue);
+#endif
 DECLINLINE(NTSTATUS) nemR0NtPerformIoControl(PGVM pGVM, uint32_t uFunction, void *pvInput, uint32_t cbInput,
                                              void *pvOutput, uint32_t cbOutput);
@@ -93,5 +95,12 @@
  * Instantate the code we share with ring-0.
  */
+#ifdef NEM_WIN_WITH_RING0_RUNLOOP
+# define NEM_WIN_TEMPLATE_MODE_OWN_RUN_API
+#else
+# undef NEM_WIN_TEMPLATE_MODE_OWN_RUN_API
+#endif
 #include "../VMMAll/NEMAllNativeTemplate-win.cpp.h"
+
+
 
 /**
@@ -582,4 +591,5 @@
 
 
+#if defined(NEM_WIN_WITH_RING0_RUNLOOP) || defined(NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS)
 /**
  * Worker for NEMR0ExportState.
@@ -722,5 +732,5 @@
 
     /* Segments */
-#define COPY_OUT_SEG(a_idx, a_enmName, a_SReg) \
+# define COPY_OUT_SEG(a_idx, a_enmName, a_SReg) \
         do { \
             HV_REGISTER_ASSOC_ZERO_PADDING(&pInput->Elements[a_idx]); \
@@ -1098,10 +1108,10 @@
         pInput->Elements[iReg].Value.Reg64          = pCtx->msrPAT;
         iReg++;
-#if 0 /** @todo HvX64RegisterMtrrCap is read only?  Seems it's not even readable. */
+# if 0 /** @todo HvX64RegisterMtrrCap is read only?  Seems it's not even readable. */
         HV_REGISTER_ASSOC_ZERO_PADDING_AND_HI64(&pInput->Elements[iReg]);
         pInput->Elements[iReg].Name                 = HvX64RegisterMtrrCap;
         pInput->Elements[iReg].Value.Reg64          = CPUMGetGuestIa32MtrrCap(pVCpu);
         iReg++;
-#endif
+# endif
 
         PCPUMCTXMSRS pCtxMsrs = CPUMQueryGuestCtxMsrsPtr(pVCpu);
@@ -1163,5 +1173,5 @@
         iReg++;
 
-#if 0 /** @todo Why can't we write these on Intel systems? Not that we really care... */
+# if 0 /** @todo Why can't we write these on Intel systems? Not that we really care... */
         const CPUMCPUVENDOR enmCpuVendor = CPUMGetHostCpuVendor(pGVM->pVM);
         if (enmCpuVendor != CPUMCPUVENDOR_AMD)
@@ -1176,5 +1186,5 @@
             iReg++;
         }
-#endif
+# endif
     }
 
@@ -1260,4 +1270,5 @@
     return VINF_SUCCESS;
 }
+#endif /* NEM_WIN_WITH_RING0_RUNLOOP || NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS */
 
 
@@ -1273,4 +1284,5 @@
 VMMR0_INT_DECL(int)  NEMR0ExportState(PGVM pGVM, PVM pVM, VMCPUID idCpu)
 {
+#if defined(NEM_WIN_WITH_RING0_RUNLOOP) || defined(NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS)
     /*
      * Validate the call.
@@ -1289,7 +1301,12 @@
     }
     return rc;
+#else
+    RT_NOREF(pGVM, pVM, idCpu);
+    return VERR_NOT_IMPLEMENTED;
+#endif
 }
 
 
+#if defined(NEM_WIN_WITH_RING0_RUNLOOP) || defined(NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS)
 /**
  * Worker for NEMR0ImportState.
@@ -1470,14 +1487,14 @@
     }
 
-#ifdef LOG_ENABLED
+# ifdef LOG_ENABLED
     const CPUMCPUVENDOR enmCpuVendor = CPUMGetHostCpuVendor(pGVM->pVM);
-#endif
+# endif
     if (fWhat & CPUMCTX_EXTRN_OTHER_MSRS)
     {
         pInput->Names[iReg++] = HvX64RegisterApicBase; /// @todo APIC BASE
         pInput->Names[iReg++] = HvX64RegisterPat;
-#if 0 /*def LOG_ENABLED*/ /** @todo something's wrong with HvX64RegisterMtrrCap? (AMD) */
+# if 0 /*def LOG_ENABLED*/ /** @todo something's wrong with HvX64RegisterMtrrCap? (AMD) */
         pInput->Names[iReg++] = HvX64RegisterMtrrCap;
-#endif
+# endif
         pInput->Names[iReg++] = HvX64RegisterMtrrDefType;
         pInput->Names[iReg++] = HvX64RegisterMtrrFix64k00000;
@@ -1493,12 +1510,12 @@
         pInput->Names[iReg++] = HvX64RegisterMtrrFix4kF8000;
         pInput->Names[iReg++] = HvX64RegisterTscAux;
-#if 0 /** @todo why can't we read HvX64RegisterIa32MiscEnable? */
+# if 0 /** @todo why can't we read HvX64RegisterIa32MiscEnable? */
         if (enmCpuVendor != CPUMCPUVENDOR_AMD)
             pInput->Names[iReg++] = HvX64RegisterIa32MiscEnable;
-#endif
-#ifdef LOG_ENABLED
+# endif
+# ifdef LOG_ENABLED
         if (enmCpuVendor != CPUMCPUVENDOR_AMD)
             pInput->Names[iReg++] = HvX64RegisterIa32FeatureControl;
-#endif
+# endif
     }
 
@@ -1609,5 +1626,5 @@
 
     /* Segments */
-#define COPY_BACK_SEG(a_idx, a_enmName, a_SReg) \
+# define COPY_BACK_SEG(a_idx, a_enmName, a_SReg) \
         do { \
             Assert(pInput->Names[a_idx] == a_enmName); \
@@ -1989,10 +2006,10 @@
         iReg++;
 
-#if 0 /*def LOG_ENABLED*/ /** @todo something's wrong with HvX64RegisterMtrrCap? (AMD) */
+# if 0 /*def LOG_ENABLED*/ /** @todo something's wrong with HvX64RegisterMtrrCap? (AMD) */
         Assert(pInput->Names[iReg] == HvX64RegisterMtrrCap);
         if (paValues[iReg].Reg64 != CPUMGetGuestIa32MtrrCap(pVCpu))
             Log7(("NEM/%u: MSR MTRR_CAP changed %RX64 -> %RX64 (!!)\n", pVCpu->idCpu, CPUMGetGuestIa32MtrrCap(pVCpu), paValues[iReg].Reg64));
         iReg++;
-#endif
+# endif
 
         PCPUMCTXMSRS pCtxMsrs = CPUMQueryGuestCtxMsrsPtr(pVCpu);
@@ -2077,5 +2094,5 @@
         iReg++;
 
-#if 0 /** @todo why can't we even read HvX64RegisterIa32MiscEnable? */
+# if 0 /** @todo why can't we even read HvX64RegisterIa32MiscEnable? */
         if (enmCpuVendor != CPUMCPUVENDOR_AMD)
         {
@@ -2086,6 +2103,6 @@
             iReg++;
         }
-#endif
-#ifdef LOG_ENABLED
+# endif
+# ifdef LOG_ENABLED
         if (enmCpuVendor != CPUMCPUVENDOR_AMD)
         {
@@ -2095,5 +2112,5 @@
             iReg++;
         }
-#endif
+# endif
     }
 
@@ -2179,4 +2196,5 @@
     return rc;
 }
+#endif /* NEM_WIN_WITH_RING0_RUNLOOP || NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS */
 
 
@@ -2194,4 +2212,5 @@
 VMMR0_INT_DECL(int) NEMR0ImportState(PGVM pGVM, PVM pVM, VMCPUID idCpu, uint64_t fWhat)
 {
+#if defined(NEM_WIN_WITH_RING0_RUNLOOP) || defined(NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS)
     /*
      * Validate the call.
@@ -2210,7 +2229,12 @@
     }
     return rc;
+#else
+    RT_NOREF(pGVM, pVM, idCpu, fWhat);
+    return VERR_NOT_IMPLEMENTED;
+#endif
 }
 
 
+#if defined(NEM_WIN_WITH_RING0_RUNLOOP) || defined(NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS)
 /**
  * Worker for NEMR0QueryCpuTick and the ring-0 NEMHCQueryCpuTick.
@@ -2258,4 +2282,5 @@
     return VINF_SUCCESS;
 }
+#endif /* NEM_WIN_WITH_RING0_RUNLOOP || NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS */
 
 
@@ -2271,4 +2296,5 @@
 VMMR0_INT_DECL(int) NEMR0QueryCpuTick(PGVM pGVM, PVM pVM, VMCPUID idCpu)
 {
+#if defined(NEM_WIN_WITH_RING0_RUNLOOP) || defined(NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS)
     /*
      * Validate the call.
@@ -2290,7 +2316,12 @@
     }
     return rc;
+#else
+    RT_NOREF(pGVM, pVM, idCpu);
+    return VERR_NOT_IMPLEMENTED;
+#endif
 }
 
 
+#if defined(NEM_WIN_WITH_RING0_RUNLOOP) || defined(NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS)
 /**
  * Worker for NEMR0ResumeCpuTickOnAll and the ring-0 NEMHCResumeCpuTickOnAll.
@@ -2360,4 +2391,5 @@
     return VINF_SUCCESS;
 }
+#endif /* NEM_WIN_WITH_RING0_RUNLOOP || NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS */
 
 
@@ -2374,4 +2406,5 @@
 VMMR0_INT_DECL(int) NEMR0ResumeCpuTickOnAll(PGVM pGVM, PVM pVM, VMCPUID idCpu, uint64_t uPausedTscValue)
 {
+#if defined(NEM_WIN_WITH_RING0_RUNLOOP) || defined(NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS)
     /*
      * Validate the call.
@@ -2392,4 +2425,8 @@
     }
     return rc;
+#else
+    RT_NOREF(pGVM, pVM, idCpu, uPausedTscValue);
+    return VERR_NOT_IMPLEMENTED;
+#endif
 }
 
@@ -2397,5 +2434,5 @@
 VMMR0_INT_DECL(VBOXSTRICTRC) NEMR0RunGuestCode(PGVM pGVM, VMCPUID idCpu)
 {
-#ifdef NEM_WIN_USE_OUR_OWN_RUN_API
+#ifdef NEM_WIN_WITH_RING0_RUNLOOP
     PVM pVM = pGVM->pVM;
     return nemHCWinRunGC(pVM, &pVM->aCpus[idCpu], pGVM, &pGVM->aCpus[idCpu]);
Index: trunk/src/VBox/VMM/VMMR3/NEMR3.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMR3/NEMR3.cpp	(revision 72923)
+++ trunk/src/VBox/VMM/VMMR3/NEMR3.cpp	(revision 72924)
@@ -78,5 +78,9 @@
                                   "/NEM/",
                                   "Enabled"
-                                  "|Allow64BitGuests",
+                                  "|Allow64BitGuests"
+#ifdef RT_OS_WINDOWS
+                                  "|UseRing0Runloop"
+#endif
+                                  ,
                                   "" /* pszValidNodes */, "NEM" /* pszWho */, 0 /* uInstance */);
     if (RT_FAILURE(rc))
@@ -90,5 +94,5 @@
 
 #ifdef VBOX_WITH_64_BITS_GUESTS
-    /** @cfgm{/HM/Allow64BitGuests, bool, 32-bit:false, 64-bit:true}
+    /** @cfgm{/NEM/Allow64BitGuests, bool, 32-bit:false, 64-bit:true}
      * Enables AMD64 CPU features.
      * On 32-bit hosts this isn't default and require host CPU support. 64-bit hosts
@@ -100,4 +104,18 @@
 #endif
 
+#ifdef RT_OS_WINDOWS
+    /** @cfgm{/NEM/UseRing0Runloop, bool, true}
+     * Whether to use the ring-0 runloop (if enabled in the build) or the ring-3 one.
+     * The latter is generally slower.  This option serves as a way out in case
+     * something breaks in the ring-0 loop. */
+# ifdef NEM_WIN_USE_RING0_RUNLOOP_BY_DEFAULT
+    bool fUseRing0Runloop = true;
+# else
+    bool fUseRing0Runloop = false;
+# endif
+    rc = CFGMR3QueryBoolDef(pCfgNem, "UseRing0Runloop", &fUseRing0Runloop, fUseRing0Runloop);
+    AssertLogRelRCReturn(rc, rc);
+    pVM->nem.s.fUseRing0Runloop = fUseRing0Runloop;
+#endif
 
     return VINF_SUCCESS;
Index: trunk/src/VBox/VMM/VMMR3/NEMR3Native-win.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMR3/NEMR3Native-win.cpp	(revision 72923)
+++ trunk/src/VBox/VMM/VMMR3/NEMR3Native-win.cpp	(revision 72924)
@@ -234,4 +234,9 @@
  * Instantate the code we share with ring-0.
  */
+#ifdef NEM_WIN_USE_OUR_OWN_RUN_API
+# define NEM_WIN_TEMPLATE_MODE_OWN_RUN_API
+#else
+# undef NEM_WIN_TEMPLATE_MODE_OWN_RUN_API
+#endif
 #include "../VMMAll/NEMAllNativeTemplate-win.cpp.h"
 
@@ -1388,36 +1393,47 @@
         Assert((HANDLE)pVCpu->nem.s.hNativeThreadHandle != INVALID_HANDLE_VALUE);
 
-#ifdef NEM_WIN_USE_OUR_OWN_RUN_API
-        VID_MAPPED_MESSAGE_SLOT MappedMsgSlot = { NULL, UINT32_MAX, UINT32_MAX };
-        if (g_pfnVidMessageSlotMap(hPartitionDevice, &MappedMsgSlot, iCpu))
+#ifndef NEM_WIN_USE_OUR_OWN_RUN_API
+# ifdef NEM_WIN_WITH_RING0_RUNLOOP
+        if (!pVM->nem.s.fUseRing0Runloop)
+# endif
         {
-            AssertLogRelMsg(MappedMsgSlot.iCpu == iCpu && MappedMsgSlot.uParentAdvisory == UINT32_MAX,
-                            ("%#x %#x (iCpu=%#x)\n", MappedMsgSlot.iCpu, MappedMsgSlot.uParentAdvisory, iCpu));
-            pVCpu->nem.s.pvMsgSlotMapping = MappedMsgSlot.pMsgBlock;
+            hrc = WHvCreateVirtualProcessor(hPartition, iCpu, 0 /*fFlags*/);
+            if (FAILED(hrc))
+            {
+                NTSTATUS const rcNtLast  = RTNtLastStatusValue();
+                DWORD const    dwErrLast = RTNtLastErrorValue();
+                while (iCpu-- > 0)
+                {
+                    HRESULT hrc2 = WHvDeleteVirtualProcessor(hPartition, iCpu);
+                    AssertLogRelMsg(SUCCEEDED(hrc2), ("WHvDeleteVirtualProcessor(%p, %u) -> %Rhrc (Last=%#x/%u)\n",
+                                                      hPartition, iCpu, hrc2, RTNtLastStatusValue(),
+                                                      RTNtLastErrorValue()));
+                }
+                return VMSetError(pVM, VERR_NEM_VM_CREATE_FAILED, RT_SRC_POS,
+                                  "Call to WHvSetupPartition failed: %Rhrc (Last=%#x/%u)", hrc, rcNtLast, dwErrLast);
+            }
         }
+# ifdef NEM_WIN_WITH_RING0_RUNLOOP
         else
+# endif
+#endif /* !NEM_WIN_USE_OUR_OWN_RUN_API */
+#if defined(NEM_WIN_WITH_RING0_RUNLOOP) || defined(NEM_WIN_USE_OUR_OWN_RUN_API)
         {
-            NTSTATUS const rcNtLast  = RTNtLastStatusValue();
-            DWORD const    dwErrLast = RTNtLastErrorValue();
-            return VMSetError(pVM, VERR_NEM_VM_CREATE_FAILED, RT_SRC_POS,
-                              "Call to WHvSetupPartition failed: %Rhrc (Last=%#x/%u)", hrc, rcNtLast, dwErrLast);
+            VID_MAPPED_MESSAGE_SLOT MappedMsgSlot = { NULL, UINT32_MAX, UINT32_MAX };
+            if (g_pfnVidMessageSlotMap(hPartitionDevice, &MappedMsgSlot, iCpu))
+            {
+                AssertLogRelMsg(MappedMsgSlot.iCpu == iCpu && MappedMsgSlot.uParentAdvisory == UINT32_MAX,
+                                ("%#x %#x (iCpu=%#x)\n", MappedMsgSlot.iCpu, MappedMsgSlot.uParentAdvisory, iCpu));
+                pVCpu->nem.s.pvMsgSlotMapping = MappedMsgSlot.pMsgBlock;
+            }
+            else
+            {
+                NTSTATUS const rcNtLast  = RTNtLastStatusValue();
+                DWORD const    dwErrLast = RTNtLastErrorValue();
+                return VMSetError(pVM, VERR_NEM_VM_CREATE_FAILED, RT_SRC_POS,
+                                  "Call to WHvSetupPartition failed: %Rhrc (Last=%#x/%u)", hrc, rcNtLast, dwErrLast);
+            }
         }
-#else
-        hrc = WHvCreateVirtualProcessor(hPartition, iCpu, 0 /*fFlags*/);
-        if (FAILED(hrc))
-        {
-            NTSTATUS const rcNtLast  = RTNtLastStatusValue();
-            DWORD const    dwErrLast = RTNtLastErrorValue();
-            while (iCpu-- > 0)
-            {
-                HRESULT hrc2 = WHvDeleteVirtualProcessor(hPartition, iCpu);
-                AssertLogRelMsg(SUCCEEDED(hrc2), ("WHvDeleteVirtualProcessor(%p, %u) -> %Rhrc (Last=%#x/%u)\n",
-                                                  hPartition, iCpu, hrc2, RTNtLastStatusValue(),
-                                                  RTNtLastErrorValue()));
-            }
-            return VMSetError(pVM, VERR_NEM_VM_CREATE_FAILED, RT_SRC_POS,
-                              "Call to WHvSetupPartition failed: %Rhrc (Last=%#x/%u)", hrc, rcNtLast, dwErrLast);
-        }
-#endif /* !NEM_WIN_USE_OUR_OWN_RUN_API */
+#endif
     }
     pVM->nem.s.fCreatedEmts = true;
@@ -1583,11 +1599,15 @@
         while (iCpu-- > 0)
         {
-#ifdef NEM_WIN_USE_OUR_OWN_RUN_API
             pVM->aCpus[iCpu].nem.s.pvMsgSlotMapping = NULL;
-#else
-            HRESULT hrc = WHvDeleteVirtualProcessor(hPartition, iCpu);
-            AssertLogRelMsg(SUCCEEDED(hrc), ("WHvDeleteVirtualProcessor(%p, %u) -> %Rhrc (Last=%#x/%u)\n",
-                                             hPartition, iCpu, hrc, RTNtLastStatusValue(),
-                                             RTNtLastErrorValue()));
+#ifndef NEM_WIN_USE_OUR_OWN_RUN_API
+# ifdef NEM_WIN_WITH_RING0_RUNLOOP
+            if (!pVM->nem.s.fUseRing0Runloop)
+# endif
+            {
+                HRESULT hrc = WHvDeleteVirtualProcessor(hPartition, iCpu);
+                AssertLogRelMsg(SUCCEEDED(hrc), ("WHvDeleteVirtualProcessor(%p, %u) -> %Rhrc (Last=%#x/%u)\n",
+                                                 hPartition, iCpu, hrc, RTNtLastStatusValue(),
+                                                 RTNtLastErrorValue()));
+            }
 #endif
         }
@@ -1634,79 +1654,81 @@
 VBOXSTRICTRC nemR3NativeRunGC(PVM pVM, PVMCPU pVCpu)
 {
-#if !defined(NEM_WIN_USE_OUR_OWN_RUN_API) || 0
-    return nemHCWinRunGC(pVM, pVCpu, NULL /*pGVM*/, NULL /*pGVCpu*/);
-#else
-    for (;;)
+#ifdef NEM_WIN_WITH_RING0_RUNLOOP
+    if (pVM->nem.s.fUseRing0Runloop)
     {
-        VBOXSTRICTRC rcStrict = VMMR3CallR0EmtFast(pVM, pVCpu, VMMR0_DO_NEM_RUN);
-        if (RT_SUCCESS(rcStrict))
+        for (;;)
         {
-            /*
-             * We deal with VINF_NEM_CHANGE_PGM_MODE, VINF_NEM_FLUSH_TLB and
-             * VINF_NEM_UPDATE_APIC_BASE  here, since we're running the risk of
-             * getting these while we already got another RC (I/O ports).
-             *
-             * The APIC base update and a PGM update can happen at the same time, so
-             * we don't depend on the status code for that and always checks it first.
-             */
-            /* APIC base: */
-            if (pVCpu->nem.s.uPendingApicBase != UINT64_MAX)
+            VBOXSTRICTRC rcStrict = VMMR3CallR0EmtFast(pVM, pVCpu, VMMR0_DO_NEM_RUN);
+            if (RT_SUCCESS(rcStrict))
             {
-                LogFlow(("nemR3NativeRunGC: calling APICSetBaseMsr(,%RX64)...\n", pVCpu->nem.s.uPendingApicBase));
-                VBOXSTRICTRC rc2 = APICSetBaseMsr(pVCpu, pVCpu->nem.s.uPendingApicBase);
-                AssertLogRelMsg(rc2 == VINF_SUCCESS, ("rc2=%Rrc [%#RX64]\n", VBOXSTRICTRC_VAL(rc2), pVCpu->nem.s.uPendingApicBase));
-                pVCpu->nem.s.uPendingApicBase = UINT64_MAX;
-            }
-
-            /* Status codes: */
-            VBOXSTRICTRC rcPending = pVCpu->nem.s.rcPending;
-            pVCpu->nem.s.rcPending = VINF_SUCCESS;
-            if (   rcStrict == VINF_NEM_CHANGE_PGM_MODE
-                || rcStrict == VINF_PGM_CHANGE_MODE
-                || rcPending == VINF_NEM_CHANGE_PGM_MODE )
-            {
-                LogFlow(("nemR3NativeRunGC: calling PGMChangeMode...\n"));
-                int rc = PGMChangeMode(pVCpu, CPUMGetGuestCR0(pVCpu), CPUMGetGuestCR4(pVCpu), CPUMGetGuestEFER(pVCpu));
-                AssertRCReturn(rc, rc);
+                /*
+                 * We deal with VINF_NEM_CHANGE_PGM_MODE, VINF_NEM_FLUSH_TLB and
+                 * VINF_NEM_UPDATE_APIC_BASE  here, since we're running the risk of
+                 * getting these while we already got another RC (I/O ports).
+                 *
+                 * The APIC base update and a PGM update can happen at the same time, so
+                 * we don't depend on the status code for that and always checks it first.
+                 */
+                /* APIC base: */
+                if (pVCpu->nem.s.uPendingApicBase != UINT64_MAX)
+                {
+                    LogFlow(("nemR3NativeRunGC: calling APICSetBaseMsr(,%RX64)...\n", pVCpu->nem.s.uPendingApicBase));
+                    VBOXSTRICTRC rc2 = APICSetBaseMsr(pVCpu, pVCpu->nem.s.uPendingApicBase);
+                    AssertLogRelMsg(rc2 == VINF_SUCCESS, ("rc2=%Rrc [%#RX64]\n", VBOXSTRICTRC_VAL(rc2), pVCpu->nem.s.uPendingApicBase));
+                    pVCpu->nem.s.uPendingApicBase = UINT64_MAX;
+                }
+
+                /* Status codes: */
+                VBOXSTRICTRC rcPending = pVCpu->nem.s.rcPending;
+                pVCpu->nem.s.rcPending = VINF_SUCCESS;
                 if (   rcStrict == VINF_NEM_CHANGE_PGM_MODE
                     || rcStrict == VINF_PGM_CHANGE_MODE
-                    || rcStrict == VINF_NEM_FLUSH_TLB)
+                    || rcPending == VINF_NEM_CHANGE_PGM_MODE )
                 {
-                    if (   !VM_FF_IS_PENDING(pVM, VM_FF_HIGH_PRIORITY_POST_MASK | VM_FF_HP_R0_PRE_HM_MASK)
-                        && !VMCPU_FF_IS_PENDING(pVCpu,   (VMCPU_FF_HIGH_PRIORITY_POST_MASK | VMCPU_FF_HP_R0_PRE_HM_MASK)
-                                                       & ~VMCPU_FF_RESUME_GUEST_MASK))
+                    LogFlow(("nemR3NativeRunGC: calling PGMChangeMode...\n"));
+                    int rc = PGMChangeMode(pVCpu, CPUMGetGuestCR0(pVCpu), CPUMGetGuestCR4(pVCpu), CPUMGetGuestEFER(pVCpu));
+                    AssertRCReturn(rc, rc);
+                    if (   rcStrict == VINF_NEM_CHANGE_PGM_MODE
+                        || rcStrict == VINF_PGM_CHANGE_MODE
+                        || rcStrict == VINF_NEM_FLUSH_TLB)
                     {
-                        VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_RESUME_GUEST_MASK);
-                        continue;
+                        if (   !VM_FF_IS_PENDING(pVM, VM_FF_HIGH_PRIORITY_POST_MASK | VM_FF_HP_R0_PRE_HM_MASK)
+                            && !VMCPU_FF_IS_PENDING(pVCpu,   (VMCPU_FF_HIGH_PRIORITY_POST_MASK | VMCPU_FF_HP_R0_PRE_HM_MASK)
+                                                           & ~VMCPU_FF_RESUME_GUEST_MASK))
+                        {
+                            VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_RESUME_GUEST_MASK);
+                            continue;
+                        }
+                        rcStrict = VINF_SUCCESS;
                     }
-                    rcStrict = VINF_SUCCESS;
                 }
+                else if (rcStrict == VINF_NEM_FLUSH_TLB || rcPending == VINF_NEM_FLUSH_TLB)
+                {
+                    LogFlow(("nemR3NativeRunGC: calling PGMFlushTLB...\n"));
+                    int rc = PGMFlushTLB(pVCpu, CPUMGetGuestCR3(pVCpu), true);
+                    AssertRCReturn(rc, rc);
+                    if (rcStrict == VINF_NEM_FLUSH_TLB || rcStrict == VINF_NEM_CHANGE_PGM_MODE)
+                    {
+                        if (   !VM_FF_IS_PENDING(pVM, VM_FF_HIGH_PRIORITY_POST_MASK | VM_FF_HP_R0_PRE_HM_MASK)
+                            && !VMCPU_FF_IS_PENDING(pVCpu,   (VMCPU_FF_HIGH_PRIORITY_POST_MASK | VMCPU_FF_HP_R0_PRE_HM_MASK)
+                                                           & ~VMCPU_FF_RESUME_GUEST_MASK))
+                        {
+                            VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_RESUME_GUEST_MASK);
+                            continue;
+                        }
+                        rcStrict = VINF_SUCCESS;
+                    }
+                }
+                else if (rcStrict == VINF_NEM_UPDATE_APIC_BASE || rcPending == VERR_NEM_UPDATE_APIC_BASE)
+                    continue;
+                else
+                    AssertMsg(rcPending == VINF_SUCCESS, ("rcPending=%Rrc\n", VBOXSTRICTRC_VAL(rcPending) ));
             }
-            else if (rcStrict == VINF_NEM_FLUSH_TLB || rcPending == VINF_NEM_FLUSH_TLB)
-            {
-                LogFlow(("nemR3NativeRunGC: calling PGMFlushTLB...\n"));
-                int rc = PGMFlushTLB(pVCpu, CPUMGetGuestCR3(pVCpu), true);
-                AssertRCReturn(rc, rc);
-                if (rcStrict == VINF_NEM_FLUSH_TLB || rcStrict == VINF_NEM_CHANGE_PGM_MODE)
-                {
-                    if (   !VM_FF_IS_PENDING(pVM, VM_FF_HIGH_PRIORITY_POST_MASK | VM_FF_HP_R0_PRE_HM_MASK)
-                        && !VMCPU_FF_IS_PENDING(pVCpu,   (VMCPU_FF_HIGH_PRIORITY_POST_MASK | VMCPU_FF_HP_R0_PRE_HM_MASK)
-                                                       & ~VMCPU_FF_RESUME_GUEST_MASK))
-                    {
-                        VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_RESUME_GUEST_MASK);
-                        continue;
-                    }
-                    rcStrict = VINF_SUCCESS;
-                }
-            }
-            else if (rcStrict == VINF_NEM_UPDATE_APIC_BASE || rcPending == VERR_NEM_UPDATE_APIC_BASE)
-                continue;
-            else
-                AssertMsg(rcPending == VINF_SUCCESS, ("rcPending=%Rrc\n", VBOXSTRICTRC_VAL(rcPending) ));
+            LogFlow(("nemR3NativeRunGC: returns %Rrc\n", VBOXSTRICTRC_VAL(rcStrict) ));
+            return rcStrict;
         }
-        LogFlow(("nemR3NativeRunGC: returns %Rrc\n", VBOXSTRICTRC_VAL(rcStrict) ));
-        return rcStrict;
     }
 #endif
+    return nemHCWinRunGC(pVM, pVCpu, NULL /*pGVM*/, NULL /*pGVCpu*/);
 }
 
@@ -1741,8 +1763,15 @@
     nemHCWinCancelRunVirtualProcessor(pVM, pVCpu);
 #else
-    Log8(("nemR3NativeNotifyFF: canceling %u\n", pVCpu->idCpu));
-    HRESULT hrc = WHvCancelRunVirtualProcessor(pVM->nem.s.hPartition, pVCpu->idCpu, 0);
-    AssertMsg(SUCCEEDED(hrc), ("WHvCancelRunVirtualProcessor -> hrc=%Rhrc\n", hrc));
-    RT_NOREF_PV(hrc);
+# ifdef NEM_WIN_WITH_RING0_RUNLOOP
+    if (pVM->nem.s.fUseRing0Runloop)
+        nemHCWinCancelRunVirtualProcessor(pVM, pVCpu);
+    else
+# endif
+    {
+        Log8(("nemR3NativeNotifyFF: canceling %u\n", pVCpu->idCpu));
+        HRESULT hrc = WHvCancelRunVirtualProcessor(pVM->nem.s.hPartition, pVCpu->idCpu, 0);
+        AssertMsg(SUCCEEDED(hrc), ("WHvCancelRunVirtualProcessor -> hrc=%Rhrc\n", hrc));
+        RT_NOREF_PV(hrc);
+    }
 #endif
     RT_NOREF_PV(fFlags);
Index: trunk/src/VBox/VMM/include/NEMInternal.h
===================================================================
--- trunk/src/VBox/VMM/include/NEMInternal.h	(revision 72923)
+++ trunk/src/VBox/VMM/include/NEMInternal.h	(revision 72924)
@@ -45,6 +45,8 @@
  */
 # define NEM_WIN_USE_HYPERCALLS_FOR_PAGES
-# define NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS
-# define NEM_WIN_USE_OUR_OWN_RUN_API
+//# define NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS /**< Applies to ring-3 code only. Useful for testing VID API. */
+//# define NEM_WIN_USE_OUR_OWN_RUN_API          /**< Applies to ring-3 code only. Useful for testing VID API. */
+# define NEM_WIN_WITH_RING0_RUNLOOP             /**< Enables the ring-0 runloop. */
+# define NEM_WIN_USE_RING0_RUNLOOP_BY_DEFAULT   /**< For quickly testing ring-3 API without messing with CFGM. */
 # if defined(NEM_WIN_USE_OUR_OWN_RUN_API) && !defined(NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS)
 #  error "NEM_WIN_USE_OUR_OWN_RUN_API requires NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS"
@@ -52,4 +54,7 @@
 # if defined(NEM_WIN_USE_OUR_OWN_RUN_API) && !defined(NEM_WIN_USE_HYPERCALLS_FOR_PAGES)
 #  error "NEM_WIN_USE_OUR_OWN_RUN_API requires NEM_WIN_USE_HYPERCALLS_FOR_PAGES"
+# endif
+# if defined(NEM_WIN_WITH_RING0_RUNLOOP) && !defined(NEM_WIN_USE_HYPERCALLS_FOR_PAGES)
+#  error "NEM_WIN_WITH_RING0_RUNLOOP requires NEM_WIN_USE_HYPERCALLS_FOR_PAGES"
 # endif
 
@@ -148,4 +153,6 @@
     /** WHvRunVpExitReasonException is supported. */
     bool                        fExtendedXcptExit : 1;
+    /** Set if we're using the ring-0 API to do the work. */
+    bool                        fUseRing0Runloop : 1;
     /** Set if we've started more than one CPU and cannot mess with A20. */
     bool                        fA20Fixed : 1;
@@ -228,7 +235,10 @@
      * This is set to UINT64_MAX when not pending  */
     uint64_t                    uPendingApicBase;
-# ifdef NEM_WIN_USE_OUR_OWN_RUN_API
+# ifdef NEM_WIN_WITH_RING0_RUNLOOP
     /** Pending VINF_NEM_CHANGE_PGM_MODE, VINF_NEM_FLUSH_TLB or VINF_NEM_UPDATE_APIC_BASE. */
     int32_t                     rcPending;
+# else
+    uint32_t                    uPadding;
+# endif
     /** The VID_MSHAGN_F_XXX flags.
      * Either VID_MSHAGN_F_HANDLE_MESSAGE | VID_MSHAGN_F_GET_NEXT_MESSAGE or zero. */
@@ -236,5 +246,4 @@
     /** What VidMessageSlotMap returns and is used for passing exit info. */
     RTR3PTR                     pvMsgSlotMapping;
-# endif
     /** The windows thread handle. */
     RTR3PTR                     hNativeThreadHandle;
