Index: /trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp	(revision 48261)
+++ /trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp	(revision 48262)
@@ -1627,4 +1627,5 @@
 
             VMMRZCallRing3Enable(pVCpu);                         /* Restore longjmp state. */
+            STAM_COUNTER_INC(&pVCpu->hm.s.StatPreemptPreempting);
             break;
         }
Index: /trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp	(revision 48261)
+++ /trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp	(revision 48262)
@@ -7006,5 +7006,4 @@
         case RTTHREADCTXEVENT_PREEMPTING:
         {
-            /** @todo Stats. */
             Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
             Assert(VMMR0ThreadCtxHooksAreRegistered(pVCpu));
@@ -7031,4 +7030,5 @@
             /* Restore longjmp state. */
             VMMRZCallRing3Enable(pVCpu);
+            STAM_COUNTER_INC(&pVCpu->hm.s.StatPreemptPreempting);
             break;
         }
@@ -7036,5 +7036,4 @@
         case RTTHREADCTXEVENT_RESUMED:
         {
-            /** @todo Stats. */
             Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
             Assert(VMMR0ThreadCtxHooksAreRegistered(pVCpu));
@@ -7060,4 +7059,6 @@
             }
             pVCpu->hm.s.fLeaveDone = false;
+
+            /* Restore longjmp state. */
             VMMRZCallRing3Enable(pVCpu);
             break;
@@ -7119,11 +7120,8 @@
     LogFlowFunc(("pVM=%p pVCpu=%p\n", pVM, pVCpu));
 
-    /* When thread-context hooks are available, this is done later (when preemption/interrupts are disabled). */
-    if (!VMMR0ThreadCtxHooksAreRegistered(pVCpu))
-    {
-        Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
-        return hmR0VmxSaveHostState(pVM, pVCpu);
-    }
-    return VINF_SUCCESS;
+    /* Save the host state here while entering HM context. When thread-context hooks are used, we might get preempted
+       and have to resave the host state but most of the time we won't be, so do it here before we disable interrupts. */
+    Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
+    return hmR0VmxSaveHostState(pVM, pVCpu);
 }
 
@@ -7466,16 +7464,4 @@
 
     /*
-     * Load the host state bits as we may've been preempted (only happens when
-     * thread-context hooks are used).
-     */
-    if (pVCpu->hm.s.fContextUseFlags & HM_CHANGED_HOST_CONTEXT)
-    {
-        Assert(VMMR0ThreadCtxHooksAreRegistered(pVCpu));
-        int rc = hmR0VmxSaveHostState(pVM, pVCpu);
-        AssertRC(rc);
-    }
-    Assert(!(pVCpu->hm.s.fContextUseFlags & HM_CHANGED_HOST_CONTEXT));
-
-    /*
      * If we are injecting events to a real-on-v86 mode guest, we may have to update
      * RIP and some other registers, i.e. hmR0VmxInjectPendingEvent()->hmR0VmxInjectEventVmcs().
@@ -7489,5 +7475,20 @@
     }
 
-    /* Load the state shared between host and guest (FPU, debug). */
+    /*
+     * Load the host state bits as we may've been preempted (only happens when
+     * thread-context hooks are used).
+     */
+    if (pVCpu->hm.s.fContextUseFlags & HM_CHANGED_HOST_CONTEXT)
+    {
+        Assert(VMMR0ThreadCtxHooksAreRegistered(pVCpu));
+        int rc = hmR0VmxSaveHostState(pVM, pVCpu);
+        AssertRC(rc);
+        STAM_COUNTER_INC(&pVCpu->hm.s.StatPreemptSaveHostState);
+    }
+    Assert(!(pVCpu->hm.s.fContextUseFlags & HM_CHANGED_HOST_CONTEXT));
+
+    /*
+     * Load the state shared between host and guest (FPU, debug).
+     */
     if (pVCpu->hm.s.fContextUseFlags & HM_CHANGED_HOST_GUEST_SHARED_STATE)
         hmR0VmxLoadSharedState(pVM, pVCpu, pMixedCtx);
@@ -7501,5 +7502,5 @@
 
     PHMGLOBALCPUINFO pCpu = HMR0GetCurrentCpu();
-    RTCPUID idCurrentCpu  = pCpu->idCpu;
+    RTCPUID  idCurrentCpu = pCpu->idCpu;
     if (   pVmxTransient->fUpdateTscOffsettingAndPreemptTimer
         || idCurrentCpu != pVCpu->hm.s.idLastCpu)
@@ -7511,5 +7512,4 @@
     ASMAtomicWriteBool(&pVCpu->hm.s.fCheckedTLBFlush, true);    /* Used for TLB-shootdowns, set this across the world switch. */
     hmR0VmxFlushTaggedTlb(pVCpu, pCpu);                         /* Invalidate the appropriate guest entries from the TLB. */
-
     Assert(idCurrentCpu == pVCpu->hm.s.idLastCpu);
     pVCpu->hm.s.vmx.LastError.idCurrentCpu = idCurrentCpu;      /* Update the error reporting info. with the current host CPU. */
Index: /trunk/src/VBox/VMM/VMMR3/HM.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/HM.cpp	(revision 48261)
+++ /trunk/src/VBox/VMM/VMMR3/HM.cpp	(revision 48262)
@@ -705,4 +705,7 @@
         HM_REG_COUNTER(&pVCpu->hm.s.StatInjectPendingReflect,   "/HM/CPU%d/EventInject/PendingReflect", "Reflecting an exception back to the guest.");
 
+        HM_REG_COUNTER(&pVCpu->hm.s.StatPreemptPreempting,      "/HM/CPU%d/Preempt/Preempting", "EMT has been preempted while in HM context.");
+        HM_REG_COUNTER(&pVCpu->hm.s.StatPreemptSaveHostState,   "/HM/CPU%d/Preempt/SaveHostState", "Preemption caused us to resave host state.");
+
         HM_REG_COUNTER(&pVCpu->hm.s.StatFlushPage,              "/HM/CPU%d/Flush/Page", "Invalidating a guest page on all guest CPUs.");
         HM_REG_COUNTER(&pVCpu->hm.s.StatFlushPageManual,        "/HM/CPU%d/Flush/Page/Virt", "Invalidating a guest page using guest-virtual address.");
Index: /trunk/src/VBox/VMM/include/HMInternal.h
===================================================================
--- /trunk/src/VBox/VMM/include/HMInternal.h	(revision 48261)
+++ /trunk/src/VBox/VMM/include/HMInternal.h	(revision 48262)
@@ -826,4 +826,7 @@
     STAMCOUNTER             StatPendingHostIrq;
 
+    STAMCOUNTER             StatPreemptPreempting;
+    STAMCOUNTER             StatPreemptSaveHostState;
+
     STAMCOUNTER             StatFlushPage;
     STAMCOUNTER             StatFlushPageManual;
