Index: /trunk/src/VBox/VMM/VMMR0/HMR0.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/HMR0.cpp	(revision 80586)
+++ /trunk/src/VBox/VMM/VMMR0/HMR0.cpp	(revision 80587)
@@ -87,14 +87,15 @@
     /** @name Ring-0 method table for AMD-V and VT-x specific operations.
      * @{ */
-    DECLR0CALLBACKMEMBER(int,  pfnEnterSession, (PVMCPUCC pVCpu));
-    DECLR0CALLBACKMEMBER(void, pfnThreadCtxCallback, (RTTHREADCTXEVENT enmEvent, PVMCPUCC pVCpu, bool fGlobalInit));
-    DECLR0CALLBACKMEMBER(int,  pfnExportHostState, (PVMCPUCC pVCpu));
+    DECLR0CALLBACKMEMBER(int,          pfnEnterSession, (PVMCPUCC pVCpu));
+    DECLR0CALLBACKMEMBER(void,         pfnThreadCtxCallback, (RTTHREADCTXEVENT enmEvent, PVMCPUCC pVCpu, bool fGlobalInit));
+    DECLR0CALLBACKMEMBER(int,          pfnCallRing3Callback, (PVMCPUCC pVCpu, VMMCALLRING3 enmOperation));
+    DECLR0CALLBACKMEMBER(int,          pfnExportHostState, (PVMCPUCC pVCpu));
     DECLR0CALLBACKMEMBER(VBOXSTRICTRC, pfnRunGuestCode, (PVMCPUCC pVCpu));
-    DECLR0CALLBACKMEMBER(int,  pfnEnableCpu, (PHMPHYSCPU pHostCpu, PVMCC pVM, void *pvCpuPage, RTHCPHYS HCPhysCpuPage,
-                                              bool fEnabledByHost, PCSUPHWVIRTMSRS pHwvirtMsrs));
-    DECLR0CALLBACKMEMBER(int,  pfnDisableCpu, (void *pvCpuPage, RTHCPHYS HCPhysCpuPage));
-    DECLR0CALLBACKMEMBER(int,  pfnInitVM, (PVMCC pVM));
-    DECLR0CALLBACKMEMBER(int,  pfnTermVM, (PVMCC pVM));
-    DECLR0CALLBACKMEMBER(int,  pfnSetupVM, (PVMCC pVM));
+    DECLR0CALLBACKMEMBER(int,          pfnEnableCpu, (PHMPHYSCPU pHostCpu, PVMCC pVM, void *pvCpuPage, RTHCPHYS HCPhysCpuPage,
+                                                      bool fEnabledByHost, PCSUPHWVIRTMSRS pHwvirtMsrs));
+    DECLR0CALLBACKMEMBER(int,          pfnDisableCpu, (void *pvCpuPage, RTHCPHYS HCPhysCpuPage));
+    DECLR0CALLBACKMEMBER(int,          pfnInitVM, (PVMCC pVM));
+    DECLR0CALLBACKMEMBER(int,          pfnTermVM, (PVMCC pVM));
+    DECLR0CALLBACKMEMBER(int,          pfnSetupVM, (PVMCC pVM));
     /** @} */
 
@@ -269,4 +270,10 @@
 }
 
+static DECLCALLBACK(int) hmR0DummyCallRing3Callback(PVMCPUCC pVCpu, VMMCALLRING3 enmOperation)
+{
+    RT_NOREF2(pVCpu, enmOperation);
+    return VINF_SUCCESS;
+}
+
 static DECLCALLBACK(VBOXSTRICTRC) hmR0DummyRunGuestCode(PVMCPUCC pVCpu)
 {
@@ -466,4 +473,5 @@
             g_HmR0.pfnEnterSession      = VMXR0Enter;
             g_HmR0.pfnThreadCtxCallback = VMXR0ThreadCtxCallback;
+            g_HmR0.pfnCallRing3Callback = VMXR0CallRing3Callback;
             g_HmR0.pfnExportHostState   = VMXR0ExportHostState;
             g_HmR0.pfnRunGuestCode      = VMXR0RunGuestCode;
@@ -518,4 +526,5 @@
     g_HmR0.pfnEnterSession      = SVMR0Enter;
     g_HmR0.pfnThreadCtxCallback = SVMR0ThreadCtxCallback;
+    g_HmR0.pfnCallRing3Callback = SVMR0CallRing3Callback;
     g_HmR0.pfnExportHostState   = SVMR0ExportHostState;
     g_HmR0.pfnRunGuestCode      = SVMR0RunGuestCode;
@@ -588,4 +597,5 @@
     g_HmR0.pfnEnterSession      = hmR0DummyEnter;
     g_HmR0.pfnThreadCtxCallback = hmR0DummyThreadCtxCallback;
+    g_HmR0.pfnCallRing3Callback = hmR0DummyCallRing3Callback;
     g_HmR0.pfnExportHostState   = hmR0DummyExportHostState;
     g_HmR0.pfnRunGuestCode      = hmR0DummyRunGuestCode;
@@ -1339,4 +1349,21 @@
 
 /**
+ * Notification callback before performing a longjump to ring-3.
+ *
+ * @returns VBox status code.
+ * @param   pVCpu           The cross context virtual CPU structure.
+ * @param   enmOperation    The operation causing the ring-3 longjump.
+ * @param   pvUser          User argument, currently unused, NULL.
+ */
+static DECLCALLBACK(int) hmR0CallRing3Callback(PVMCPUCC pVCpu, VMMCALLRING3 enmOperation, void *pvUser)
+{
+    RT_NOREF(pvUser);
+    Assert(pVCpu);
+    Assert(g_HmR0.pfnCallRing3Callback);
+    return g_HmR0.pfnCallRing3Callback(pVCpu, enmOperation);
+}
+
+
+/**
  * Turns on HM on the CPU if necessary and initializes the bare minimum state
  * required for entering HM context.
@@ -1359,4 +1386,7 @@
     if (!pHostCpu->fConfigured)
         rc = hmR0EnableCpu(pVCpu->CTX_SUFF(pVM), idCpu);
+
+    /* Register a callback to fire prior to performing a longjmp to ring-3 so HM can disable VT-x/AMD-V if needed. */
+    VMMRZCallRing3SetNotification(pVCpu, hmR0CallRing3Callback, NULL /* pvUser */);
 
     /* Reload host-state (back from ring-3/migrated CPUs) and shared guest/host bits. */
@@ -1456,4 +1486,6 @@
     pVCpu->hm.s.idEnteredCpu = NIL_RTCPUID;
 
+    /* De-register the longjmp-to-ring 3 callback now that we have reliquished hardware resources. */
+    VMMRZCallRing3RemoveNotification(pVCpu);
     return VINF_SUCCESS;
 }
Index: /trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp	(revision 80586)
+++ /trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp	(revision 80587)
@@ -2888,5 +2888,5 @@
      *
      * Consider this scenario: #VMEXIT -> VMMRZCallRing3Enable() -> do stuff that causes a longjmp
-     * -> hmR0SvmCallRing3Callback() -> VMMRZCallRing3Disable() -> hmR0SvmImportGuestState()
+     * -> SVMR0CallRing3Callback() -> VMMRZCallRing3Disable() -> hmR0SvmImportGuestState()
      * -> Sets VMCPU_FF_HM_UPDATE_CR3 pending -> return from the longjmp -> continue with #VMEXIT
      * handling -> hmR0SvmImportGuestState() and here we are.
@@ -2945,5 +2945,5 @@
     /*
      * !!! IMPORTANT !!!
-     * If you modify code here, make sure to check whether hmR0SvmCallRing3Callback() needs to be updated too.
+     * If you modify code here, make sure to check whether SVMR0CallRing3Callback() needs to be updated too.
      */
 
@@ -3008,5 +3008,5 @@
     /*
      * !!! IMPORTANT !!!
-     * If you modify code here, make sure to check whether hmR0SvmCallRing3Callback() needs to be updated too.
+     * If you modify code here, make sure to check whether SVMR0CallRing3Callback() needs to be updated too.
      */
 
@@ -3044,10 +3044,7 @@
  * @param   pVCpu           The cross context virtual CPU structure.
  * @param   enmOperation    The operation causing the ring-3 longjump.
- * @param   pvUser          The user argument, NULL (currently unused).
- */
-static DECLCALLBACK(int) hmR0SvmCallRing3Callback(PVMCPUCC pVCpu, VMMCALLRING3 enmOperation, void *pvUser)
-{
-    RT_NOREF_PV(pvUser);
-
+ */
+VMMR0DECL(int) SVMR0CallRing3Callback(PVMCPUCC pVCpu, VMMCALLRING3 enmOperation)
+{
     if (enmOperation == VMMCALLRING3_VM_R0_ASSERTION)
     {
@@ -3129,4 +3126,7 @@
     hmR0SvmLeaveSession(pVCpu);
     STAM_COUNTER_DEC(&pVCpu->hm.s.StatSwitchLongJmpToR3);
+
+    /* Thread-context hooks are unregistered at this point!!! */
+    /* Ring-3 callback notifications are unregistered at this point!!! */
 
     VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TO_R3);
@@ -3155,7 +3155,4 @@
 
     STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchExitToR3);
-
-    /* We do -not- want any longjmp notifications after this! We must return to ring-3 ASAP. */
-    VMMRZCallRing3RemoveNotification(pVCpu);
     VMMRZCallRing3Enable(pVCpu);
 
@@ -4789,6 +4786,4 @@
          * better than a kernel panic. This also disables flushing of the R0-logger instance.
          */
-        VMMRZCallRing3Disable(pVCpu);
-        VMMRZCallRing3RemoveNotification(pVCpu);
         hmR0SvmPreRunGuestCommitted(pVCpu, &SvmTransient);
 
@@ -4954,12 +4949,14 @@
 VMMR0DECL(VBOXSTRICTRC) SVMR0RunGuestCode(PVMCPUCC pVCpu)
 {
+    AssertPtr(pVCpu);
+    PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
     Assert(VMMRZCallRing3IsEnabled(pVCpu));
+    Assert(!ASMAtomicUoReadU64(&pCtx->fExtrn));
     HMSVM_ASSERT_PREEMPT_SAFE(pVCpu);
-    VMMRZCallRing3SetNotification(pVCpu, hmR0SvmCallRing3Callback, NULL /* pvUser */);
 
     uint32_t cLoops = 0;
     int      rc;
 #ifdef VBOX_WITH_NESTED_HWVIRT_SVM
-    if (!CPUMIsGuestInSvmNestedHwVirtMode(&pVCpu->cpum.GstCtx))
+    if (!CPUMIsGuestInSvmNestedHwVirtMode(pCtx))
 #endif
     {
@@ -4996,4 +4993,5 @@
     /* Prepare to return to ring-3. This will remove longjmp notifications. */
     rc = hmR0SvmExitToRing3(pVCpu, rc);
+    Assert(!ASMAtomicUoReadU64(&pCtx->fExtrn));
     Assert(!VMMRZCallRing3IsNotificationSet(pVCpu));
     return rc;
Index: /trunk/src/VBox/VMM/VMMR0/HMSVMR0.h
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/HMSVMR0.h	(revision 80586)
+++ /trunk/src/VBox/VMM/VMMR0/HMSVMR0.h	(revision 80587)
@@ -41,4 +41,5 @@
 VMMR0DECL(int)          SVMR0Enter(PVMCPUCC pVCpu);
 VMMR0DECL(void)         SVMR0ThreadCtxCallback(RTTHREADCTXEVENT enmEvent, PVMCPUCC pVCpu, bool fGlobalInit);
+VMMR0DECL(int)          SVMR0CallRing3Callback(PVMCPUCC pVCpu, VMMCALLRING3 enmOperation);
 VMMR0DECL(int)          SVMR0EnableCpu(PHMPHYSCPU pHostCpu, PVMCC pVM, void *pvPageCpu, RTHCPHYS HCPhysCpuPage,
                                        bool fEnabledBySystem, PCSUPHWVIRTMSRS pHwvirtMsrs);
Index: /trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp	(revision 80586)
+++ /trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp	(revision 80587)
@@ -7252,5 +7252,5 @@
 {
     int      rc   = VINF_SUCCESS;
-    PVMCC      pVM  = pVCpu->CTX_SUFF(pVM);
+    PVMCC    pVM  = pVCpu->CTX_SUFF(pVM);
     PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
     uint32_t u32Val;
@@ -7555,5 +7555,5 @@
      * Honor any pending CR3 updates.
      *
-     * Consider this scenario: VM-exit -> VMMRZCallRing3Enable() -> do stuff that causes a longjmp -> hmR0VmxCallRing3Callback()
+     * Consider this scenario: VM-exit -> VMMRZCallRing3Enable() -> do stuff that causes a longjmp -> VMXR0CallRing3Callback()
      * -> VMMRZCallRing3Disable() -> hmR0VmxImportGuestState() -> Sets VMCPU_FF_HM_UPDATE_CR3 pending -> return from the longjmp
      * -> continue with VM-exit handling -> hmR0VmxImportGuestState() and here we are.
@@ -7873,5 +7873,5 @@
     /*
      * !!! IMPORTANT !!!
-     * If you modify code here, check whether hmR0VmxCallRing3Callback() needs to be updated too.
+     * If you modify code here, check whether VMXR0CallRing3Callback() needs to be updated too.
      */
 
@@ -8001,5 +8001,5 @@
     /*
      * !!! IMPORTANT !!!
-     * If you modify code here, make sure to check whether hmR0VmxCallRing3Callback() needs to be updated too.
+     * If you modify code here, make sure to check whether VMXR0CallRing3Callback() needs to be updated too.
      */
 
@@ -8010,7 +8010,6 @@
     VMMR0ThreadCtxHookDisable(pVCpu);
 
-    /* Leave HM context. This takes care of local init (term). */
+    /* Leave HM context. This takes care of local init (term) and deregistering the longjmp-to-ring-3 callback. */
     int rc = HMR0LeaveCpu(pVCpu);
-
     HM_RESTORE_PREEMPT();
     return rc;
@@ -8123,4 +8122,5 @@
 
     /* Thread-context hooks are unregistered at this point!!! */
+    /* Ring-3 callback notifications are unregistered at this point!!! */
 
     /* Sync recompiler state. */
@@ -8150,9 +8150,5 @@
 
     STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchExitToR3);
-
-    /* We do -not- want any longjmp notifications after this! We must return to ring-3 ASAP. */
-    VMMRZCallRing3RemoveNotification(pVCpu);
     VMMRZCallRing3Enable(pVCpu);
-
     return rc;
 }
@@ -8166,9 +8162,7 @@
  * @param   pVCpu           The cross context virtual CPU structure.
  * @param   enmOperation    The operation causing the ring-3 longjump.
- * @param   pvUser          User argument, currently unused, NULL.
- */
-static DECLCALLBACK(int) hmR0VmxCallRing3Callback(PVMCPUCC pVCpu, VMMCALLRING3 enmOperation, void *pvUser)
-{
-    RT_NOREF(pvUser);
+ */
+VMMR0DECL(int) VMXR0CallRing3Callback(PVMCPUCC pVCpu, VMMCALLRING3 enmOperation)
+{
     if (enmOperation == VMMCALLRING3_VM_R0_ASSERTION)
     {
@@ -8180,6 +8174,5 @@
         VMMRZCallRing3RemoveNotification(pVCpu);
         VMMRZCallRing3Disable(pVCpu);
-        RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER;
-        RTThreadPreemptDisable(&PreemptState);
+        HM_DISABLE_PREEMPT(pVCpu);
 
         PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
@@ -8208,11 +8201,12 @@
         /** @todo eliminate the need for calling VMMR0ThreadCtxHookDisable here!  */
         VMMR0ThreadCtxHookDisable(pVCpu);
+
+        /* Leave HM context. This takes care of local init (term). */
         HMR0LeaveCpu(pVCpu);
-        RTThreadPreemptRestore(&PreemptState);
+        HM_RESTORE_PREEMPT();
         return VINF_SUCCESS;
     }
 
     Assert(pVCpu);
-    Assert(pvUser);
     Assert(VMMRZCallRing3IsEnabled(pVCpu));
     HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
@@ -12363,6 +12357,4 @@
     HMVMX_ASSERT_PREEMPT_SAFE(pVCpu);
 
-    VMMRZCallRing3SetNotification(pVCpu, hmR0VmxCallRing3Callback, pCtx);
-
     VBOXSTRICTRC rcStrict;
     uint32_t     cLoops = 0;
Index: /trunk/src/VBox/VMM/VMMR0/HMVMXR0.h
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/HMVMXR0.h	(revision 80586)
+++ /trunk/src/VBox/VMM/VMMR0/HMVMXR0.h	(revision 80587)
@@ -33,4 +33,5 @@
 VMMR0DECL(int)          VMXR0Enter(PVMCPUCC pVCpu);
 VMMR0DECL(void)         VMXR0ThreadCtxCallback(RTTHREADCTXEVENT enmEvent, PVMCPUCC pVCpu, bool fGlobalInit);
+VMMR0DECL(int)          VMXR0CallRing3Callback(PVMCPUCC pVCpu, VMMCALLRING3 enmOperation);
 VMMR0DECL(int)          VMXR0EnableCpu(PHMPHYSCPU pHostCpu, PVMCC pVM, void *pvPageCpu, RTHCPHYS pPageCpuPhys,
                                        bool fEnabledBySystem, PCSUPHWVIRTMSRS pHwvirtMsrs);
Index: /trunk/src/VBox/VMM/VMMR0/VMMR0.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/VMMR0.cpp	(revision 80586)
+++ /trunk/src/VBox/VMM/VMMR0/VMMR0.cpp	(revision 80587)
@@ -1015,5 +1015,5 @@
      * @bugref{7726#c19} explains the need for this trick:
      *
-     *      hmR0VmxCallRing3Callback/hmR0SvmCallRing3Callback &
+     *      VMXR0CallRing3Callback/SVMR0CallRing3Callback &
      *      hmR0VmxLeaveSession/hmR0SvmLeaveSession disables context hooks during
      *      longjmp & normal return to ring-3, which opens a window where we may be
