Index: /trunk/include/VBox/vmm/tm.h
===================================================================
--- /trunk/include/VBox/vmm/tm.h	(revision 54064)
+++ /trunk/include/VBox/vmm/tm.h	(revision 54065)
@@ -134,5 +134,5 @@
 VMM_INT_DECL(uint64_t)  TMCpuTickGetNoCheck(PVMCPU pVCpu);
 VMM_INT_DECL(bool)      TMCpuTickCanUseRealTSC(PVMCPU pVCpu, uint64_t *poffRealTSC, bool *pfParavirtTsc);
-VMM_INT_DECL(uint64_t)  TMCpuTickGetDeadlineAndTscOffset(PVMCPU pVCpu, bool *pfOffsettedTsc, bool *pfParavirtTsc, uint64_t *poffRealTSC);
+VMM_INT_DECL(uint64_t)  TMCpuTickGetDeadlineAndTscOffset(PVMCPU pVCpu, uint64_t *poffRealTSC, bool *pfOffsettedTsc, bool *pfParavirtTsc);
 VMM_INT_DECL(int)       TMCpuTickSet(PVM pVM, PVMCPU pVCpu, uint64_t u64Tick);
 VMM_INT_DECL(int)       TMCpuTickSetLastSeen(PVMCPU pVCpu, uint64_t u64LastSeenTick);
@@ -269,4 +269,7 @@
 VMMR3_INT_DECL(void)    TMR3VirtualSyncFF(PVM pVM, PVMCPU pVCpu);
 VMMR3_INT_DECL(PRTTIMESPEC) TMR3UtcNow(PVM pVM, PRTTIMESPEC pTime);
+
+VMMR3_INT_DECL(int)     TMR3CpuTickParavirtEnable(PVM pVM);
+VMMR3_INT_DECL(int)     TMR3CpuTickParavirtDisable(PVM pVM);
 /** @} */
 #endif /* IN_RING3 */
Index: /trunk/src/VBox/VMM/VMMAll/TMAll.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/TMAll.cpp	(revision 54064)
+++ /trunk/src/VBox/VMM/VMMAll/TMAll.cpp	(revision 54065)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2013 Oracle Corporation
+ * Copyright (C) 2006-2015 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -2575,2 +2575,3 @@
     return uHz;
 }
+
Index: /trunk/src/VBox/VMM/VMMAll/TMAllCpu.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/TMAllCpu.cpp	(revision 54064)
+++ /trunk/src/VBox/VMM/VMMAll/TMAllCpu.cpp	(revision 54065)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2014 Oracle Corporation
+ * Copyright (C) 2006-2015 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -174,5 +174,5 @@
  * Record why we refused to use offsetted TSC.
  *
- * Used by TMCpuTickCanUseRealTSC and TMCpuTickGetDeadlineAndTscOffset.
+ * Used by TMCpuTickCanUseRealTSC() and TMCpuTickGetDeadlineAndTscOffset().
  *
  * @param   pVM         Pointer to the VM.
@@ -213,18 +213,16 @@
  * @param   pVCpu           Pointer to the VMCPU.
  * @param   poffRealTSC     The offset against the TSC of the current CPU.
- *                          Can be NULL.
- * @param   pfParavirtTsc   Where to store whether paravirt. TSC can be used or
- *                          not.
- * @thread EMT(pVCpu).
+ * @param   pfParavirtTsc   Where to store whether paravirt. TSC is enabled.
+ *
+ * @thread  EMT(pVCpu).
+ * @see     TMCpuTickGetDeadlineAndTscOffset().
  */
 VMM_INT_DECL(bool) TMCpuTickCanUseRealTSC(PVMCPU pVCpu, uint64_t *poffRealTSC, bool *pfParavirtTsc)
 {
     PVM pVM = pVCpu->CTX_SUFF(pVM);
-    bool fParavirtTsc = false;
+    bool fOffsettedTsc = false;
 
     /*
      * We require:
-     *     1. Use of a paravirtualized TSC is enabled by the guest.
-     *     (OR)
      *     1. A fixed TSC, this is checked at init time.
      *     2. That the TSC is ticking (we shouldn't be here if it isn't)
@@ -234,33 +232,30 @@
      *          c) we're not using warp drive (accelerated virtual guest time).
      */
-    *pfParavirtTsc = GIMIsParavirtTscEnabled(pVM);
-    if (    pVM->tm.s.enmTSCMode == TMTSCMODE_DYNAMIC
-        &&  RT_LIKELY(pVCpu->tm.s.fTSCTicking)
-        &&  (   pVM->tm.s.enmTSCMode == TMTSCMODE_REAL_TSC_OFFSET
-             || (   !pVM->tm.s.fVirtualSyncCatchUp
-                 && RT_LIKELY(pVM->tm.s.fVirtualSyncTicking)
-                 && !pVM->tm.s.fVirtualWarpDrive)))
-    {
-        if (pVM->tm.s.enmTSCMode != TMTSCMODE_REAL_TSC_OFFSET)
-        {
-            /* The source is the timer synchronous virtual clock. */
-            if (poffRealTSC)
-            {
-                uint64_t u64Now = tmCpuTickGetRawVirtual(pVM, false /* don't check for pending timers */)
-                                - pVCpu->tm.s.offTSCRawSrc;
-                /** @todo When we start collecting statistics on how much time we spend executing
-                 * guest code before exiting, we should check this against the next virtual sync
-                 * timer timeout. If it's lower than the avg. length, we should trap rdtsc to increase
-                 * the chance that we'll get interrupted right after the timer expired. */
-                *poffRealTSC = u64Now - ASMReadTSC();
-            }
-        }
-        else if (poffRealTSC)
-        {
-            /* The source is the real TSC. */
-            *poffRealTSC = 0 - pVCpu->tm.s.offTSCRawSrc;
-        }
-        /** @todo count this? */
-        return true;
+    Assert(pVCpu->tm.s.fTSCTicking);
+    *pfParavirtTsc = pVM->tm.s.fParavirtTscEnabled;
+
+    if (pVM->tm.s.enmTSCMode == TMTSCMODE_REAL_TSC_OFFSET)
+    {
+        /* The source is the real TSC. */
+        *poffRealTSC = 0 - pVCpu->tm.s.offTSCRawSrc;
+        return true;    /** @todo count this? */
+    }
+
+    if (   pVM->tm.s.enmTSCMode == TMTSCMODE_DYNAMIC
+        && !pVM->tm.s.fVirtualSyncCatchUp
+        && RT_LIKELY(pVM->tm.s.fVirtualSyncTicking)
+        && !pVM->tm.s.fVirtualWarpDrive)
+    {
+        /* The source is the timer synchronous virtual clock. */
+        uint64_t u64Now = tmCpuTickGetRawVirtual(pVM, false /* don't check for pending timers */)
+                        - pVCpu->tm.s.offTSCRawSrc;
+        /** @todo When we start collecting statistics on how much time we spend executing
+         * guest code before exiting, we should check this against the next virtual sync
+         * timer timeout. If it's lower than the avg. length, we should trap rdtsc to increase
+         * the chance that we'll get interrupted right after the timer expired. */
+        uint64_t u64TSC = ASMReadTSC();     /** @todo should be replaced with SUPReadTSC() eventually. */
+        *poffRealTSC = u64Now - u64TSC;
+        fOffsettedTsc = u64Now >= pVCpu->tm.s.u64TSCLastSeen;
+        return true;    /** @todo count this? */
     }
 
@@ -304,21 +299,19 @@
  * @returns The number of host CPU clock ticks to the next timer deadline.
  * @param   pVCpu           The current CPU.
- * @param   pfParavirtTsc   Where to store whether paravirt. TSC can be used or
- *                          not.
  * @param   poffRealTSC     The offset against the TSC of the current CPU.
+ * @param   pfOffsettedTsc  Where to store whether TSC offsetting can be used.
+ * @param   pfParavirtTsc   Where to store whether paravirt. TSC is enabled.
  *
  * @thread  EMT(pVCpu).
- * @remarks Superset of TMCpuTickCanUseRealTSC().
- */
-VMM_INT_DECL(uint64_t) TMCpuTickGetDeadlineAndTscOffset(PVMCPU pVCpu, bool *pfOffsettedTsc, bool *pfParavirtTsc,
-                                                        uint64_t *poffRealTSC)
-{
-    PVM         pVM = pVCpu->CTX_SUFF(pVM);
-    uint64_t    cTicksToDeadline;
+ * @see     TMCpuTickCanUseRealTSC().
+ */
+VMM_INT_DECL(uint64_t) TMCpuTickGetDeadlineAndTscOffset(PVMCPU pVCpu, uint64_t *poffRealTSC, bool *pfOffsettedTsc,
+                                                        bool *pfParavirtTsc)
+{
+    PVM      pVM = pVCpu->CTX_SUFF(pVM);
+    uint64_t cTicksToDeadline;
 
     /*
      * We require:
-     *     1. Use of a paravirtualized TSC is enabled by the guest.
-     *     (OR)
      *     1. A fixed TSC, this is checked at init time.
      *     2. That the TSC is ticking (we shouldn't be here if it isn't)
@@ -328,42 +321,40 @@
      *          c) we're not using warp drive (accelerated virtual guest time).
      */
-    *pfParavirtTsc = GIMIsParavirtTscEnabled(pVM);
-    if (    pVM->tm.s.enmTSCMode == TMTSCMODE_DYNAMIC
-        &&  RT_LIKELY(pVCpu->tm.s.fTSCTicking)
-        &&  (   pVM->tm.s.enmTSCMode == TMTSCMODE_REAL_TSC_OFFSET
-             || (   !pVM->tm.s.fVirtualSyncCatchUp
-                 && RT_LIKELY(pVM->tm.s.fVirtualSyncTicking)
-                 && !pVM->tm.s.fVirtualWarpDrive)))
-    {
+    Assert(pVCpu->tm.s.fTSCTicking);
+    *pfParavirtTsc = pVM->tm.s.fParavirtTscEnabled;
+
+    if (pVM->tm.s.enmTSCMode == TMTSCMODE_REAL_TSC_OFFSET)
+    {
+        /* The source is the real TSC. */
+        *poffRealTSC    = 0 - pVCpu->tm.s.offTSCRawSrc;
         *pfOffsettedTsc = true;
-        if (pVM->tm.s.enmTSCMode != TMTSCMODE_REAL_TSC_OFFSET)
-        {
-            /* The source is the timer synchronous virtual clock. */
-            uint64_t cNsToDeadline;
-            uint64_t u64NowVirtSync = TMVirtualSyncGetWithDeadlineNoCheck(pVM, &cNsToDeadline);
-            uint64_t u64Now = u64NowVirtSync != TMCLOCK_FREQ_VIRTUAL /* what's the use of this? */
-                            ? ASMMultU64ByU32DivByU32(u64NowVirtSync, pVM->tm.s.cTSCTicksPerSecond, TMCLOCK_FREQ_VIRTUAL)
-                            : u64NowVirtSync;
-            u64Now -= pVCpu->tm.s.offTSCRawSrc;
-            *poffRealTSC = u64Now - ASMReadTSC();
-            cTicksToDeadline = tmCpuCalcTicksToDeadline(cNsToDeadline);
-        }
-        else
-        {
-            /* The source is the real TSC. */
-            *poffRealTSC = 0 - pVCpu->tm.s.offTSCRawSrc;
-            cTicksToDeadline = tmCpuCalcTicksToDeadline(TMVirtualSyncGetNsToDeadline(pVM));
-        }
-    }
-    else
-    {
+        cTicksToDeadline = tmCpuCalcTicksToDeadline(TMVirtualSyncGetNsToDeadline(pVM));
+        return cTicksToDeadline;
+    }
+
+    if (   pVM->tm.s.enmTSCMode == TMTSCMODE_DYNAMIC
+        && !pVM->tm.s.fVirtualSyncCatchUp
+        && RT_LIKELY(pVM->tm.s.fVirtualSyncTicking)
+        && !pVM->tm.s.fVirtualWarpDrive)
+    {
+        /* The source is the timer synchronous virtual clock. */
+        uint64_t cNsToDeadline;
+        uint64_t u64NowVirtSync = TMVirtualSyncGetWithDeadlineNoCheck(pVM, &cNsToDeadline);
+        uint64_t u64Now = u64NowVirtSync != TMCLOCK_FREQ_VIRTUAL /* what's the use of this? */
+                        ? ASMMultU64ByU32DivByU32(u64NowVirtSync, pVM->tm.s.cTSCTicksPerSecond, TMCLOCK_FREQ_VIRTUAL)
+                        : u64NowVirtSync;
+        u64Now -= pVCpu->tm.s.offTSCRawSrc;
+        *poffRealTSC     = u64Now - ASMReadTSC();        /** @todo replace with SUPReadTSC() eventually. */
+        *pfOffsettedTsc  = u64Now >= pVCpu->tm.s.u64TSCLastSeen;
+        cTicksToDeadline = tmCpuCalcTicksToDeadline(cNsToDeadline);
+        return cTicksToDeadline;
+    }
+
 #ifdef VBOX_WITH_STATISTICS
-        tmCpuTickRecordOffsettedTscRefusal(pVM, pVCpu);
+    tmCpuTickRecordOffsettedTscRefusal(pVM, pVCpu);
 #endif
-        *pfOffsettedTsc  = false;
-        *poffRealTSC     = 0;
-        cTicksToDeadline = tmCpuCalcTicksToDeadline(TMVirtualSyncGetNsToDeadline(pVM));
-    }
-
+    *pfOffsettedTsc  = false;
+    *poffRealTSC     = 0;
+    cTicksToDeadline = tmCpuCalcTicksToDeadline(TMVirtualSyncGetNsToDeadline(pVM));
     return cTicksToDeadline;
 }
@@ -395,5 +386,5 @@
         {
             STAM_COUNTER_INC(&pVM->tm.s.StatTSCUnderflow);
-            pVCpu->tm.s.u64TSCLastSeen += 64;   /* @todo choose a good increment here */
+            pVCpu->tm.s.u64TSCLastSeen += 64;   /** @todo choose a good increment here */
             u64 = pVCpu->tm.s.u64TSCLastSeen;
         }
@@ -503,7 +494,6 @@
 VMMDECL(uint64_t) TMCpuTicksPerSecond(PVM pVM)
 {
-    /** @todo revisit this, not sure why we need to get the rate from GIP for
-     *        real-tsc-offset. */
-    if (pVM->tm.s.enmTSCMode == TMTSCMODE_REAL_TSC_OFFSET)
+    if (   pVM->tm.s.enmTSCMode == TMTSCMODE_REAL_TSC_OFFSET
+        && g_pSUPGlobalInfoPage->u32Mode != SUPGIPMODE_INVARIANT_TSC)
     {
         uint64_t cTSCTicksPerSecond = SUPGetCpuHzFromGIP(g_pSUPGlobalInfoPage);
Index: /trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp	(revision 54064)
+++ /trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp	(revision 54065)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2013-2014 Oracle Corporation
+ * Copyright (C) 2013-2015 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -2257,32 +2257,24 @@
 static void hmR0SvmUpdateTscOffsetting(PVMCPU pVCpu)
 {
-    bool     fParavirtTsc = false;
+    bool fParavirtTsc;
+    bool fCanUseRealTsc;
     PSVMVMCB pVmcb = (PSVMVMCB)pVCpu->hm.s.svm.pvVmcb;
-    if (TMCpuTickCanUseRealTSC(pVCpu, &pVmcb->ctrl.u64TSCOffset, &fParavirtTsc))
-    {
-        uint64_t u64CurTSC   = ASMReadTSC();
-        uint64_t u64LastTick = TMCpuTickGetLastSeen(pVCpu);
-
-        if (u64CurTSC + pVmcb->ctrl.u64TSCOffset >= TMCpuTickGetLastSeen(pVCpu))
-        {
-            pVmcb->ctrl.u32InterceptCtrl1 &= ~SVM_CTRL1_INTERCEPT_RDTSC;
-            pVmcb->ctrl.u32InterceptCtrl2 &= ~SVM_CTRL2_INTERCEPT_RDTSCP;
-            STAM_COUNTER_INC(&pVCpu->hm.s.StatTscOffset);
-        }
-        else
-        {
-            pVmcb->ctrl.u32InterceptCtrl1 |= SVM_CTRL1_INTERCEPT_RDTSC;
-            pVmcb->ctrl.u32InterceptCtrl2 |= SVM_CTRL2_INTERCEPT_RDTSCP;
-            STAM_COUNTER_INC(&pVCpu->hm.s.StatTscInterceptOverFlow);
-        }
+    fCanUseRealTsc = TMCpuTickCanUseRealTSC(pVCpu, &pVmcb->ctrl.u64TSCOffset, &fParavirtTsc);
+    if (fCanUseRealTsc)
+    {
+        pVmcb->ctrl.u32InterceptCtrl1 &= ~SVM_CTRL1_INTERCEPT_RDTSC;
+        pVmcb->ctrl.u32InterceptCtrl2 &= ~SVM_CTRL2_INTERCEPT_RDTSCP;
+        STAM_COUNTER_INC(&pVCpu->hm.s.StatTscOffset);
     }
     else
     {
-        Assert(!fParavirtTsc);
         pVmcb->ctrl.u32InterceptCtrl1 |= SVM_CTRL1_INTERCEPT_RDTSC;
         pVmcb->ctrl.u32InterceptCtrl2 |= SVM_CTRL2_INTERCEPT_RDTSCP;
         STAM_COUNTER_INC(&pVCpu->hm.s.StatTscIntercept);
     }
-
+    pVmcb->ctrl.u64VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_INTERCEPTS;
+
+    /** @todo later optimize this to be done elsewhere and not before every
+     *        VM-entry. */
     if (fParavirtTsc)
     {
@@ -2291,6 +2283,4 @@
         STAM_COUNTER_INC(&pVCpu->hm.s.StatTscParavirt);
     }
-
-    pVmcb->ctrl.u64VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_INTERCEPTS;
 }
 
@@ -3200,8 +3190,6 @@
     }
 
-    /** @todo Last-seen-tick shouldn't be necessary when TM supports invariant
-     *        mode. */
     if (!(pVmcb->ctrl.u32InterceptCtrl1 & SVM_CTRL1_INTERCEPT_RDTSC))
-        TMCpuTickSetLastSeen(pVCpu, ASMReadTSC() + pVmcb->ctrl.u64TSCOffset);
+        TMCpuTickSetLastSeen(pVCpu, ASMReadTSC() + pVmcb->ctrl.u64TSCOffset);     /** @todo use SUPReadTSC() eventually. */
 
     STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatInGC, &pVCpu->hm.s.StatExit1, x);
@@ -4357,4 +4345,6 @@
     HMSVM_CHECK_SINGLE_STEP(pVCpu, rc);
     STAM_COUNTER_INC(&pVCpu->hm.s.StatExitHlt);
+    if (rc != VINF_SUCCESS)
+        STAM_COUNTER_INC(&pVCpu->hm.s.StatExitHltToR3);
     return rc;
 }
Index: /trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp	(revision 54064)
+++ /trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp	(revision 54065)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2012-2014 Oracle Corporation
+ * Copyright (C) 2012-2015 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -5606,6 +5606,6 @@
     if (pVM->hm.s.vmx.fUsePreemptTimer)
     {
-        uint64_t cTicksToDeadline = TMCpuTickGetDeadlineAndTscOffset(pVCpu, &fOffsettedTsc, &fParavirtTsc,
-                                                                     &pVCpu->hm.s.vmx.u64TSCOffset);
+        uint64_t cTicksToDeadline = TMCpuTickGetDeadlineAndTscOffset(pVCpu, &pVCpu->hm.s.vmx.u64TSCOffset, &fOffsettedTsc,
+                                                                     &fParavirtTsc);
 
         /* Make sure the returned values have sane upper and lower boundaries. */
@@ -5616,9 +5616,11 @@
 
         uint32_t cPreemptionTickCount = (uint32_t)RT_MIN(cTicksToDeadline, UINT32_MAX - 16);
-        rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_PREEMPT_TIMER_VALUE, cPreemptionTickCount);            AssertRC(rc);
+        rc = VMXWriteVmcs32(VMX_VMCS32_GUEST_PREEMPT_TIMER_VALUE, cPreemptionTickCount);        AssertRC(rc);
     }
     else
         fOffsettedTsc = TMCpuTickCanUseRealTSC(pVCpu, &pVCpu->hm.s.vmx.u64TSCOffset, &fParavirtTsc);
 
+    /** @todo later optimize this to be done elsewhere and not before every
+     *        VM-entry. */
     if (fParavirtTsc)
     {
@@ -5630,21 +5632,10 @@
     if (fOffsettedTsc)
     {
-        uint64_t u64CurTSC = ASMReadTSC();
-        if (u64CurTSC + pVCpu->hm.s.vmx.u64TSCOffset >= TMCpuTickGetLastSeen(pVCpu))
-        {
-            /* Note: VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT takes precedence over TSC_OFFSET, applies to RDTSCP too. */
-            rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_TSC_OFFSET_FULL, pVCpu->hm.s.vmx.u64TSCOffset);     AssertRC(rc);
-
-            pVCpu->hm.s.vmx.u32ProcCtls &= ~VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT;
-            rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);            AssertRC(rc);
-            STAM_COUNTER_INC(&pVCpu->hm.s.StatTscOffset);
-        }
-        else
-        {
-            /* VM-exit on RDTSC(P) as we would otherwise pass decreasing TSC values to the guest. */
-            pVCpu->hm.s.vmx.u32ProcCtls |= VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT;
-            rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);            AssertRC(rc);
-            STAM_COUNTER_INC(&pVCpu->hm.s.StatTscInterceptOverFlow);
-        }
+        /* Note: VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT takes precedence over TSC_OFFSET, applies to RDTSCP too. */
+        rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_TSC_OFFSET_FULL, pVCpu->hm.s.vmx.u64TSCOffset);     AssertRC(rc);
+
+        pVCpu->hm.s.vmx.u32ProcCtls &= ~VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT;
+        rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);            AssertRC(rc);
+        STAM_COUNTER_INC(&pVCpu->hm.s.StatTscOffset);
     }
     else
@@ -5652,5 +5643,5 @@
         /* We can't use TSC-offsetting (non-fixed TSC, warp drive active etc.), VM-exit on RDTSC(P). */
         pVCpu->hm.s.vmx.u32ProcCtls |= VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT;
-        rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);                AssertRC(rc);
+        rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVCpu->hm.s.vmx.u32ProcCtls);            AssertRC(rc);
         STAM_COUNTER_INC(&pVCpu->hm.s.StatTscIntercept);
     }
@@ -8713,8 +8704,6 @@
     pVmxTransient->fVectoringDoublePF  = false;                 /* Vectoring double page-fault needs to be determined later. */
 
-    /** @todo Last-seen-tick shouldn't be necessary when TM supports invariant
-     *        mode. */
     if (!(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT))
-        TMCpuTickSetLastSeen(pVCpu, ASMReadTSC() + pVCpu->hm.s.vmx.u64TSCOffset);
+        TMCpuTickSetLastSeen(pVCpu, ASMReadTSC() + pVCpu->hm.s.vmx.u64TSCOffset);     /** @todo use SUPReadTSC() eventually. */
 
     STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatInGC, &pVCpu->hm.s.StatExit1, x);
@@ -8839,5 +8828,5 @@
         }
 
-        /* Profiling the VM-exit. */
+        /* Profile the VM-exit. */
         AssertMsg(VmxTransient.uExitReason <= VMX_EXIT_MAX, ("%#x\n", VmxTransient.uExitReason));
         STAM_COUNTER_INC(&pVCpu->hm.s.StatExitAll);
@@ -8922,5 +8911,6 @@
             return VBOXSTRICTRC_TODO(rcStrict);
         }
-        /* Profiling the VM-exit. */
+
+        /* Profile the VM-exit. */
         AssertMsg(VmxTransient.uExitReason <= VMX_EXIT_MAX, ("%#x\n", VmxTransient.uExitReason));
         STAM_COUNTER_INC(&pVCpu->hm.s.StatExitAll);
@@ -10461,4 +10451,6 @@
 
     STAM_COUNTER_INC(&pVCpu->hm.s.StatExitHlt);
+    if (rc != VINF_SUCCESS)
+        STAM_COUNTER_INC(&pVCpu->hm.s.StatExitHltToR3);
     return rc;
 }
Index: /trunk/src/VBox/VMM/VMMR3/GIM.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/GIM.cpp	(revision 54064)
+++ /trunk/src/VBox/VMM/VMMR3/GIM.cpp	(revision 54065)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2014 Oracle Corporation
+ * Copyright (C) 2014-2015 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -275,5 +275,4 @@
     if (uVersion != GIM_SAVED_STATE_VERSION)
         return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
-
 
     /** @todo Load per-CPU data. */
Index: /trunk/src/VBox/VMM/VMMR3/GIMHv.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/GIMHv.cpp	(revision 54064)
+++ /trunk/src/VBox/VMM/VMMR3/GIMHv.cpp	(revision 54065)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2014 Oracle Corporation
+ * Copyright (C) 2014-2015 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -586,7 +586,10 @@
         pRefTsc->u32TscSequence  = u32TscSeq;
         pRefTsc->u64TscScale     = ((INT64_C(10000) << 32) / u64TscKHz) << 32;
-
-        LogRel(("GIM: HyperV: Enabled TSC page at %#RGp - u64TscScale=%#RX64 u64TscKHz=%#RX64 (%'RU64)\n", GCPhysTscPage,
-                pRefTsc->u64TscScale, u64TscKHz, u64TscKHz));
+        pRefTsc->i64TscOffset    = 0;
+
+        LogRel(("GIM: HyperV: Enabled TSC page at %#RGp - u64TscScale=%#RX64 u64TscKHz=%#RX64 (%'RU64) Seq=%#RU32\n",
+                GCPhysTscPage, pRefTsc->u64TscScale, u64TscKHz, u64TscKHz, pRefTsc->u32TscSequence));
+
+        TMR3CpuTickParavirtEnable(pVM);
         return VINF_SUCCESS;
     }
@@ -613,4 +616,6 @@
         Assert(!pRegion->fMapped);
         LogRel(("GIM: HyperV: Disabled TSC-page\n"));
+
+        TMR3CpuTickParavirtDisable(pVM);
         return VINF_SUCCESS;
     }
Index: /trunk/src/VBox/VMM/VMMR3/HM.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/HM.cpp	(revision 54064)
+++ /trunk/src/VBox/VMM/VMMR3/HM.cpp	(revision 54065)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2014 Oracle Corporation
+ * Copyright (C) 2006-2015 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -687,4 +687,5 @@
         HM_REG_COUNTER(&pVCpu->hm.s.StatExitInt,                "/HM/CPU%d/Exit/Instr/Int", "Guest attempted to execute INT.");
         HM_REG_COUNTER(&pVCpu->hm.s.StatExitHlt,                "/HM/CPU%d/Exit/Instr/Hlt", "Guest attempted to execute HLT.");
+        HM_REG_COUNTER(&pVCpu->hm.s.StatExitHltToR3,            "/HM/CPU%d/Exit/HltToR3", "HLT causing us to go to ring-3.");
         HM_REG_COUNTER(&pVCpu->hm.s.StatExitXdtrAccess,         "/HM/CPU%d/Exit/Instr/XdtrAccess", "Guest attempted to access descriptor table register (GDTR, IDTR, LDTR).");
         HM_REG_COUNTER(&pVCpu->hm.s.StatExitIOWrite,            "/HM/CPU%d/Exit/IO/Write", "I/O write.");
@@ -733,9 +734,7 @@
         HM_REG_COUNTER(&pVCpu->hm.s.StatTlbShootdownFlush,      "/HM/CPU%d/Flush/Shootdown/TLB", "Inter-VCPU request to flush entire guest-TLB.");
 
-        HM_REG_COUNTER(&pVCpu->hm.s.StatTscOffsetAdjusted,      "/HM/CPU%d/TSC/OffsetAdjusted", "TSC offset overflowed for paravirt. TSC. Fudged.");
         HM_REG_COUNTER(&pVCpu->hm.s.StatTscParavirt,            "/HM/CPU%d/TSC/Paravirt", "Paravirtualized TSC in effect.");
         HM_REG_COUNTER(&pVCpu->hm.s.StatTscOffset,              "/HM/CPU%d/TSC/Offset", "TSC offsetting is in effect.");
         HM_REG_COUNTER(&pVCpu->hm.s.StatTscIntercept,           "/HM/CPU%d/TSC/Intercept", "Intercept TSC accesses.");
-        HM_REG_COUNTER(&pVCpu->hm.s.StatTscInterceptOverFlow,   "/HM/CPU%d/TSC/InterceptOverflow", "TSC offset overflow, fallback to intercept TSC accesses.");
 
         HM_REG_COUNTER(&pVCpu->hm.s.StatDRxArmed,               "/HM/CPU%d/Debug/Armed", "Loaded guest-debug state while loading guest-state.");
Index: /trunk/src/VBox/VMM/VMMR3/TM.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/TM.cpp	(revision 54064)
+++ /trunk/src/VBox/VMM/VMMR3/TM.cpp	(revision 54065)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2014 Oracle Corporation
+ * Copyright (C) 2006-2015 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -126,4 +126,5 @@
 #include <VBox/vmm/mm.h>
 #include <VBox/vmm/hm.h>
+#include <VBox/vmm/gim.h>
 #include <VBox/vmm/ssm.h>
 #include <VBox/vmm/dbgf.h>
@@ -181,4 +182,5 @@
 static DECLCALLBACK(void)   tmR3TimerInfoActive(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
 static DECLCALLBACK(void)   tmR3InfoClocks(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
+static DECLCALLBACK(VBOXSTRICTRC) tmR3CpuTickParavirtToggle(PVM pVM, PVMCPU pVCpu, void *pvData);
 
 
@@ -331,4 +333,5 @@
     rc = CFGMR3ValidateConfig(pCfgHandle, "/TM/",
                               "TSCMode|"
+                              "TSCModeSwitchAllowed|"
                               "TSCTicksPerSecond|"
                               "TSCTiedToExecution|"
@@ -378,5 +381,5 @@
     }
     else if (RT_FAILURE(rc))
-        return VMSetError(pVM, rc, RT_SRC_POS, N_("Configuration error: Failed to querying string value \"Mode\""));
+        return VMSetError(pVM, rc, RT_SRC_POS, N_("Configuration error: Failed to querying string value \"TSCMode\""));
     else
     {
@@ -388,6 +391,21 @@
             pVM->tm.s.enmTSCMode = TMTSCMODE_DYNAMIC;
         else
-            return VMSetError(pVM, rc, RT_SRC_POS, N_("Configuration error: Unrecognized TM mode value \"%s\""), szTSCMode);
-    }
+            return VMSetError(pVM, rc, RT_SRC_POS, N_("Configuration error: Unrecognized TM TSC mode value \"%s\""), szTSCMode);
+    }
+
+    /**
+     * @cfgm{/TM/TSCModeSwitchAllowed, bool, Whether TM TSC mode switch is allowed
+     *      at runtime}
+     * When using paravirtualized guests, we dynamically switch TSC modes to a more
+     * optimal one for performance. This setting allows overriding this behaviour.
+     */
+    rc = CFGMR3QueryBool(pCfgHandle, "TSCModeSwitchAllowed", &pVM->tm.s.fTSCModeSwitchAllowed);
+    if (rc == VERR_CFGM_VALUE_NOT_FOUND)
+    {
+        /* This is finally determined in TMR3InitFinalize() as GIM isn't initialized yet. */
+        pVM->tm.s.fTSCModeSwitchAllowed = true;
+    }
+    else if (RT_FAILURE(rc))
+        return VMSetError(pVM, rc, RT_SRC_POS, N_("Configuration error: Failed to querying bool value \"TSCModeSwitchAllowed\""));
 
     /** @cfgm{/TM/TSCTicksPerSecond, uint32_t, Current TSC frequency from GIP}
@@ -548,5 +566,41 @@
     }
 
-    /* Setup and report */
+    /*
+     * Gather the Host Hz configuration values.
+     */
+    rc = CFGMR3QueryU32Def(pCfgHandle, "HostHzMax", &pVM->tm.s.cHostHzMax, 20000);
+    if (RT_FAILURE(rc))
+        return VMSetError(pVM, rc, RT_SRC_POS,
+                          N_("Configuration error: Failed to querying uint32_t value \"HostHzMax\""));
+
+    rc = CFGMR3QueryU32Def(pCfgHandle, "HostHzFudgeFactorTimerCpu", &pVM->tm.s.cPctHostHzFudgeFactorTimerCpu, 111);
+    if (RT_FAILURE(rc))
+        return VMSetError(pVM, rc, RT_SRC_POS,
+                          N_("Configuration error: Failed to querying uint32_t value \"HostHzFudgeFactorTimerCpu\""));
+
+    rc = CFGMR3QueryU32Def(pCfgHandle, "HostHzFudgeFactorOtherCpu", &pVM->tm.s.cPctHostHzFudgeFactorOtherCpu, 110);
+    if (RT_FAILURE(rc))
+        return VMSetError(pVM, rc, RT_SRC_POS,
+                          N_("Configuration error: Failed to querying uint32_t value \"HostHzFudgeFactorOtherCpu\""));
+
+    rc = CFGMR3QueryU32Def(pCfgHandle, "HostHzFudgeFactorCatchUp100", &pVM->tm.s.cPctHostHzFudgeFactorCatchUp100, 300);
+    if (RT_FAILURE(rc))
+        return VMSetError(pVM, rc, RT_SRC_POS,
+                          N_("Configuration error: Failed to querying uint32_t value \"HostHzFudgeFactorCatchUp100\""));
+
+    rc = CFGMR3QueryU32Def(pCfgHandle, "HostHzFudgeFactorCatchUp200", &pVM->tm.s.cPctHostHzFudgeFactorCatchUp200, 250);
+    if (RT_FAILURE(rc))
+        return VMSetError(pVM, rc, RT_SRC_POS,
+                          N_("Configuration error: Failed to querying uint32_t value \"HostHzFudgeFactorCatchUp200\""));
+
+    rc = CFGMR3QueryU32Def(pCfgHandle, "HostHzFudgeFactorCatchUp400", &pVM->tm.s.cPctHostHzFudgeFactorCatchUp400, 200);
+    if (RT_FAILURE(rc))
+        return VMSetError(pVM, rc, RT_SRC_POS,
+                          N_("Configuration error: Failed to querying uint32_t value \"HostHzFudgeFactorCatchUp400\""));
+
+    /*
+     * Finally, setup and report.
+     */
+    pVM->tm.s.enmOriginalTSCMode = pVM->tm.s.enmTSCMode;
     CPUMR3SetCR4Feature(pVM, X86_CR4_TSD, ~X86_CR4_TSD);
     LogRel(("TM: cTSCTicksPerSecond=%#RX64 (%'RU64) enmTSCMode=%d (%s)\n"
@@ -556,35 +610,39 @@
 
     /*
-     * Gather the Host Hz configuration values.
-     */
-    rc = CFGMR3QueryU32Def(pCfgHandle, "HostHzMax", &pVM->tm.s.cHostHzMax, 20000);
-    if (RT_FAILURE(rc))
-        return VMSetError(pVM, rc, RT_SRC_POS,
-                          N_("Configuration error: Failed to querying uint32_t value \"HostHzMax\""));
-
-    rc = CFGMR3QueryU32Def(pCfgHandle, "HostHzFudgeFactorTimerCpu", &pVM->tm.s.cPctHostHzFudgeFactorTimerCpu, 111);
-    if (RT_FAILURE(rc))
-        return VMSetError(pVM, rc, RT_SRC_POS,
-                          N_("Configuration error: Failed to querying uint32_t value \"HostHzFudgeFactorTimerCpu\""));
-
-    rc = CFGMR3QueryU32Def(pCfgHandle, "HostHzFudgeFactorOtherCpu", &pVM->tm.s.cPctHostHzFudgeFactorOtherCpu, 110);
-    if (RT_FAILURE(rc))
-        return VMSetError(pVM, rc, RT_SRC_POS,
-                          N_("Configuration error: Failed to querying uint32_t value \"HostHzFudgeFactorOtherCpu\""));
-
-    rc = CFGMR3QueryU32Def(pCfgHandle, "HostHzFudgeFactorCatchUp100", &pVM->tm.s.cPctHostHzFudgeFactorCatchUp100, 300);
-    if (RT_FAILURE(rc))
-        return VMSetError(pVM, rc, RT_SRC_POS,
-                          N_("Configuration error: Failed to querying uint32_t value \"HostHzFudgeFactorCatchUp100\""));
-
-    rc = CFGMR3QueryU32Def(pCfgHandle, "HostHzFudgeFactorCatchUp200", &pVM->tm.s.cPctHostHzFudgeFactorCatchUp200, 250);
-    if (RT_FAILURE(rc))
-        return VMSetError(pVM, rc, RT_SRC_POS,
-                          N_("Configuration error: Failed to querying uint32_t value \"HostHzFudgeFactorCatchUp200\""));
-
-    rc = CFGMR3QueryU32Def(pCfgHandle, "HostHzFudgeFactorCatchUp400", &pVM->tm.s.cPctHostHzFudgeFactorCatchUp400, 200);
-    if (RT_FAILURE(rc))
-        return VMSetError(pVM, rc, RT_SRC_POS,
-                          N_("Configuration error: Failed to querying uint32_t value \"HostHzFudgeFactorCatchUp400\""));
+     * Dump the GIPCPU TSC-deltas, iterate using the Apic Id to get master at the beginning in most cases.
+     */
+    unsigned cGipCpus = RT_ELEMENTS(g_pSUPGlobalInfoPage->aiCpuFromApicId);
+    for (unsigned i = 0; i < cGipCpus; i++)
+    {
+        uint16_t iCpu  = g_pSUPGlobalInfoPage->aiCpuFromApicId[i];
+#if 1
+        if (iCpu != UINT16_MAX)
+            LogRel(("TM: GIP - CPU[%d]: idApic=%d i64TSCDelta=%RI64\n", g_pSUPGlobalInfoPage->aCPUs[iCpu].idCpu,
+                    g_pSUPGlobalInfoPage->aCPUs[iCpu].idApic, g_pSUPGlobalInfoPage->aCPUs[iCpu].i64TSCDelta));
+#else
+        /* Dump 2 entries per line, saves vertical space in release log but more dumps bytes due to formatting. */
+        uint16_t iCpu2 = UINT16_MAX;
+        for (unsigned k = i + 1; k < cGipCpus; k++)
+        {
+            iCpu2 = g_pSUPGlobalInfoPage->aiCpuFromApicId[k];
+            if (iCpu2 != UINT16_MAX)
+            {
+                i = k + 1;
+                break;
+            }
+        }
+        if (   iCpu  != UINT16_MAX
+            && iCpu2 != UINT16_MAX)
+        {
+            LogRel(("TM: GIP - CPU[%d]: idApic=%d i64TSCDelta=%-4lld CPU[%d]: idApic=%d i64TSCDelta=%lld\n",
+                    g_pSUPGlobalInfoPage->aCPUs[iCpu].idCpu, g_pSUPGlobalInfoPage->aCPUs[iCpu].idApic,
+                    g_pSUPGlobalInfoPage->aCPUs[iCpu].i64TSCDelta, g_pSUPGlobalInfoPage->aCPUs[iCpu2].idCpu,
+                    g_pSUPGlobalInfoPage->aCPUs[iCpu2].idApic, g_pSUPGlobalInfoPage->aCPUs[iCpu2].i64TSCDelta));
+        }
+        else if (iCpu != UINT16_MAX)
+            LogRel(("TM: GIP - CPU[%d]: idApic=%d i64TSCDelta=%lld\n", g_pSUPGlobalInfoPage->aCPUs[iCpu].idCpu,
+                    g_pSUPGlobalInfoPage->aCPUs[iCpu].idApic));
+#endif
+    }
 
     /*
@@ -1027,4 +1085,8 @@
 #endif
 
+    /*
+     * GIM is now initialized. Determine if TSC mode switching is allowed (respecting CFGM override).
+     */
+    pVM->tm.s.fTSCModeSwitchAllowed &= GIMIsEnabled(pVM) && HMIsEnabled(pVM);
     return rc;
 }
@@ -1153,4 +1215,18 @@
     PVMCPU pVCpuDst = &pVM->aCpus[pVM->tm.s.idTimerCpu];
     VMCPU_FF_CLEAR(pVCpuDst, VMCPU_FF_TIMER); /** @todo FIXME: this isn't right. */
+
+    /*
+     * Switch TM TSC mode back to the original mode after a reset for
+     * paravirtualized guests that alter the TM TSC mode during operation.
+     */
+    if (   pVM->tm.s.fTSCModeSwitchAllowed
+        && pVM->tm.s.enmTSCMode != pVM->tm.s.enmOriginalTSCMode)
+    {
+        bool fParavirtTSC = false;
+        tmR3CpuTickParavirtToggle(pVM, NULL /* pVCpuEmt */, &fParavirtTSC);
+    }
+    Assert(!GIMIsParavirtTscEnabled(pVM));
+    pVM->tm.s.fParavirtTscEnabled = false;
+
     TM_UNLOCK_TIMERS(pVM);
 }
@@ -3055,4 +3131,138 @@
 #endif /* !VBOX_WITHOUT_NS_ACCOUNTING */
 
+
+/**
+ * Switch TM TSC mode to the most appropriate/efficient one.
+ *
+ * @returns strict VBox status code.
+ * @param   pVM         Pointer to the VM.
+ * @param   pVCpuEmt    Pointer to the VMCPU it's called on, can be NULL.
+ * @param   pvData      Opaque pointer to whether usage of paravirt. TSC is
+ *                      enabled or disabled by the guest OS.
+ *
+ * @thread  EMT.
+ * @remarks Must only be called during an EMTs rendezvous.
+ */
+static DECLCALLBACK(VBOXSTRICTRC) tmR3CpuTickParavirtToggle(PVM pVM, PVMCPU pVCpuEmt, void *pvData)
+{
+    Assert(pVM);
+    Assert(pvData);
+    Assert(pVM->tm.s.fTSCModeSwitchAllowed);
+    NOREF(pVCpuEmt);
+
+    bool *pfEnable = (bool *)pvData;
+    if (*pfEnable)
+    {
+        if (pVM->tm.s.enmTSCMode != TMTSCMODE_REAL_TSC_OFFSET)
+        {
+            uint64_t u64NowVirtSync = TMVirtualSyncGetNoCheck(pVM);
+            uint64_t u64Now = ASMMultU64ByU32DivByU32(u64NowVirtSync, pVM->tm.s.cTSCTicksPerSecond, TMCLOCK_FREQ_VIRTUAL);
+            uint32_t cCpus  = pVM->cCpus;
+            uint64_t u64RealTSC = ASMReadTSC();
+            for (uint32_t i = 0; i < cCpus; i++)
+            {
+                PVMCPU   pVCpu = &pVM->aCpus[i];
+                uint64_t u64TickOld = u64Now - pVCpu->tm.s.offTSCRawSrc;
+
+                /*
+                 * The return value of TMCpuTickGet() and the guest's TSC value (u64Tick) must
+                 * remain constant across the TM TSC mode-switch.
+                 * OldTick = VrSync - CurOff
+                 * NewTick = RealTsc - NewOff
+                 * NewTick = OldTick
+                 *  => RealTsc - NewOff = VrSync - CurOff
+                 *  => NewOff = CurOff + RealTsc - VrSync
+                 */
+                pVCpu->tm.s.offTSCRawSrc = pVCpu->tm.s.offTSCRawSrc + u64RealTSC  - u64Now;
+
+                /* If the new offset results in the TSC going backwards, re-adjust the offset. */
+                if (u64RealTSC - pVCpu->tm.s.offTSCRawSrc < u64TickOld)
+                    pVCpu->tm.s.offTSCRawSrc += u64TickOld - u64RealTSC;
+                Assert(u64RealTSC - pVCpu->tm.s.offTSCRawSrc >= u64TickOld);
+            }
+            pVM->tm.s.enmTSCMode = TMTSCMODE_REAL_TSC_OFFSET;
+            LogRel(("TM: Switched TSC mode. New enmTSCMode=%d (%s)\n", pVM->tm.s.enmTSCMode, tmR3GetTSCModeName(pVM)));
+        }
+    }
+    else
+    {
+        if (   pVM->tm.s.enmTSCMode == TMTSCMODE_REAL_TSC_OFFSET
+            && pVM->tm.s.enmTSCMode != pVM->tm.s.enmOriginalTSCMode)
+        {
+            uint64_t u64NowVirtSync = TMVirtualSyncGetNoCheck(pVM);
+            uint64_t u64Now     = ASMMultU64ByU32DivByU32(u64NowVirtSync, pVM->tm.s.cTSCTicksPerSecond, TMCLOCK_FREQ_VIRTUAL);
+            uint64_t u64RealTSC = ASMReadTSC();          /** @todo replace with SUPReadTSC() eventually. */
+            uint32_t cCpus      = pVM->cCpus;
+            for (uint32_t i = 0; i < cCpus; i++)
+            {
+                PVMCPU   pVCpu      = &pVM->aCpus[i];
+                uint64_t u64TickOld = u64RealTSC - pVCpu->tm.s.offTSCRawSrc;
+
+                /* Update the last-seen tick here as we havent't been updating it (as we don't
+                   need it) while in pure TSC-offsetting mode. */
+                pVCpu->tm.s.u64TSCLastSeen = pVCpu->tm.s.u64TSC;
+
+                /*
+                 * The return value of TMCpuTickGet() and the guest's TSC value (u64Tick) must
+                 * remain constant across the TM TSC mode-switch.
+                 * OldTick = RealTsc - CurOff
+                 * NewTick = VrSync - NewOff
+                 * NewTick = OldTick
+                 *  => VrSync - NewOff = RealTsc - CurOff
+                 *  => NewOff = CurOff + VrSync - RealTsc
+                 */
+                pVCpu->tm.s.offTSCRawSrc = pVCpu->tm.s.offTSCRawSrc + u64Now - u64RealTSC;
+
+                /* If the new offset results in the TSC going backwards, re-adjust the offset. */
+                if (u64Now - pVCpu->tm.s.offTSCRawSrc < u64TickOld)
+                    pVCpu->tm.s.offTSCRawSrc += u64TickOld - u64Now;
+                Assert(u64Now - pVCpu->tm.s.offTSCRawSrc >= u64TickOld);
+            }
+            pVM->tm.s.enmTSCMode = pVM->tm.s.enmOriginalTSCMode;
+            LogRel(("TM: Switched TSC mode. New enmTSCMode=%d (%s)\n", pVM->tm.s.enmTSCMode, tmR3GetTSCModeName(pVM)));
+        }
+    }
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Notify TM that the guest has enabled usage of a paravirtualized TSC.
+ *
+ * @returns VBox status code.
+ * @param   pVM     Pointer to the VM.
+ */
+VMMR3_INT_DECL(int) TMR3CpuTickParavirtEnable(PVM pVM)
+{
+    int rc = VINF_SUCCESS;
+    if (pVM->tm.s.fTSCModeSwitchAllowed)
+    {
+        bool fEnable = true;
+        rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, tmR3CpuTickParavirtToggle, (void *)&fEnable);
+    }
+    pVM->tm.s.fParavirtTscEnabled = true;
+    return rc;
+}
+
+
+/**
+ * Notify TM that the guest has disabled usage of a paravirtualized TSC.
+ *
+ * @returns VBox status code.
+ * @param   pVM     Pointer to the VM.
+ */
+VMMR3_INT_DECL(int) TMR3CpuTickParavirtDisable(PVM pVM)
+{
+    int rc = VINF_SUCCESS;
+    if (pVM->tm.s.fTSCModeSwitchAllowed)
+    {
+        bool fEnable = false;
+        rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, tmR3CpuTickParavirtToggle, (void *)&fEnable);
+    }
+    pVM->tm.s.fParavirtTscEnabled = false;
+    return rc;
+}
+
+
 /**
  * Gets the 5 char clock name for the info tables.
@@ -3254,6 +3464,6 @@
         case TMTSCMODE_VIRT_TSC_EMULATED:  return "VirtTscEmulated";
         case TMTSCMODE_DYNAMIC:            return "Dynamic";
-        default:                           return "?????";
-    }
-}
-
+        default:                           return "???";
+    }
+}
+
Index: /trunk/src/VBox/VMM/VMMR3/VM.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/VM.cpp	(revision 54064)
+++ /trunk/src/VBox/VMM/VMMR3/VM.cpp	(revision 54065)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2014 Oracle Corporation
+ * Copyright (C) 2006-2015 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -2797,5 +2797,5 @@
         CSAMR3Reset(pVM);
 #endif
-        GIMR3Reset(pVM);                /* This must come *before* PDM. */
+        GIMR3Reset(pVM);                /* This must come *before* PDM and TM. */
         PDMR3Reset(pVM);
         PGMR3Reset(pVM);
Index: /trunk/src/VBox/VMM/include/HMInternal.h
===================================================================
--- /trunk/src/VBox/VMM/include/HMInternal.h	(revision 54064)
+++ /trunk/src/VBox/VMM/include/HMInternal.h	(revision 54065)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2014 Oracle Corporation
+ * Copyright (C) 2006-2015 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -896,4 +896,5 @@
     STAMCOUNTER             StatExitXdtrAccess;
     STAMCOUNTER             StatExitHlt;
+    STAMCOUNTER             StatExitHltToR3;
     STAMCOUNTER             StatExitMwait;
     STAMCOUNTER             StatExitMonitor;
@@ -938,9 +939,7 @@
     STAMCOUNTER             StatSwitchLongJmpToR3;
 
-    STAMCOUNTER             StatTscOffsetAdjusted;
     STAMCOUNTER             StatTscParavirt;
     STAMCOUNTER             StatTscOffset;
     STAMCOUNTER             StatTscIntercept;
-    STAMCOUNTER             StatTscInterceptOverFlow;
 
     STAMCOUNTER             StatExitReasonNpf;
Index: /trunk/src/VBox/VMM/include/TMInternal.h
===================================================================
--- /trunk/src/VBox/VMM/include/TMInternal.h	(revision 54064)
+++ /trunk/src/VBox/VMM/include/TMInternal.h	(revision 54065)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2014 Oracle Corporation
+ * Copyright (C) 2006-2015 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -324,9 +324,9 @@
 typedef enum TMTSCMODE
 {
-    /** The guest TSC is an emulated virtual TSC. */
+    /** The guest TSC is an emulated, virtual TSC. */
     TMTSCMODE_VIRT_TSC_EMULATED = 1,
     /** The guest TSC is an offset of the real TSC. */
     TMTSCMODE_REAL_TSC_OFFSET,
-    /** The guest TSC is dynamically derived through emulation or offsetting. */
+    /** The guest TSC is dynamically derived through emulating or offsetting. */
     TMTSCMODE_DYNAMIC
 } TMTSCMODE;
@@ -355,4 +355,8 @@
      *  Config variable: Mode (string). */
     TMTSCMODE                   enmTSCMode;
+    /** The original TSC mode of the VM. */
+    TMTSCMODE                   enmOriginalTSCMode;
+    /** Alignment padding. */
+    uint32_t                    u32Alignment0;
     /** Whether the TSC is tied to the execution of code.
      * Config variable: TSCTiedToExecution (bool) */
@@ -361,6 +365,8 @@
      * Config variable: TSCNotTiedToHalt (bool) */
     bool                        fTSCNotTiedToHalt;
-    /** Alignment padding. */
-    bool                        afAlignment0[2];
+    /** Whether TM TSC mode switching is allowed at runtime. */
+    bool                        fTSCModeSwitchAllowed;
+    /** Whether the guest has enabled use of paravirtualized TSC. */
+    bool                        fParavirtTscEnabled;
     /** The ID of the virtual CPU that normally runs the timers. */
     VMCPUID                     idTimerCpu;
@@ -685,6 +691,6 @@
     bool                        afAlignment0[3]; /**< alignment padding */
 
-    /** The offset between the raw TSC source and the Guest TSC.
-     * Only valid if fTicking is set and and fTSCUseRealTSC is clear. */
+    /** The offset between the host tick (TSC/virtual depending on the TSC mode) and
+     *  the guest tick. */
     uint64_t                    offTSCRawSrc;
 
