Index: trunk/src/VBox/VMM/VMMAll/TMAllCpu.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMAll/TMAllCpu.cpp	(revision 32418)
+++ trunk/src/VBox/VMM/VMMAll/TMAllCpu.cpp	(revision 32419)
@@ -39,6 +39,10 @@
 DECLINLINE(uint64_t) tmCpuTickGetRawVirtual(PVM pVM, bool fCheckTimers)
 {
-    uint64_t u64 = TMVirtualSyncGetEx(pVM, fCheckTimers);
-    if (u64 != TMCLOCK_FREQ_VIRTUAL)
+    uint64_t u64;
+    if (fCheckTimers)
+        u64 = TMVirtualSyncGet(pVM);
+    else
+        u64 = TMVirtualSyncGetNoCheck(pVM);
+    if (u64 != TMCLOCK_FREQ_VIRTUAL) /* what's the use of this test, document! */
         u64 = ASMMultU64ByU32DivByU32(u64, pVM->tm.s.cTSCTicksPerSecond, TMCLOCK_FREQ_VIRTUAL);
     return u64;
@@ -94,4 +98,40 @@
     AssertFailed();
     return VERR_INTERNAL_ERROR;
+}
+
+/**
+ * Record why we refused to use offsetted TSC.
+ *
+ * Used by TMCpuTickCanUseRealTSC and TMCpuTickGetDeadlineAndTscOffset.
+ *
+ * @param   pVM         The VM handle.
+ * @param   pVCpu       The current CPU.
+ */
+DECLINLINE(void) tmCpuTickRecordOffsettedTscRefusal(PVM pVM, PVMCPU pVCpu)
+{
+
+    /* Sample the reason for refusing. */
+    if (!pVM->tm.s.fMaybeUseOffsettedHostTSC)
+       STAM_COUNTER_INC(&pVM->tm.s.StatTSCNotFixed);
+    else if (!pVCpu->tm.s.fTSCTicking)
+       STAM_COUNTER_INC(&pVM->tm.s.StatTSCNotTicking);
+    else if (!pVM->tm.s.fTSCUseRealTSC)
+    {
+        if (pVM->tm.s.fVirtualSyncCatchUp)
+        {
+           if (pVM->tm.s.u32VirtualSyncCatchUpPercentage <= 10)
+               STAM_COUNTER_INC(&pVM->tm.s.StatTSCCatchupLE010);
+           else if (pVM->tm.s.u32VirtualSyncCatchUpPercentage <= 25)
+               STAM_COUNTER_INC(&pVM->tm.s.StatTSCCatchupLE025);
+           else if (pVM->tm.s.u32VirtualSyncCatchUpPercentage <= 100)
+               STAM_COUNTER_INC(&pVM->tm.s.StatTSCCatchupLE100);
+           else
+               STAM_COUNTER_INC(&pVM->tm.s.StatTSCCatchupOther);
+        }
+        else if (!pVM->tm.s.fVirtualSyncTicking)
+           STAM_COUNTER_INC(&pVM->tm.s.StatTSCSyncNotTicking);
+        else if (pVM->tm.s.fVirtualWarpDrive)
+           STAM_COUNTER_INC(&pVM->tm.s.StatTSCWarp);
+    }
 }
 
@@ -156,29 +196,103 @@
 
 #ifdef VBOX_WITH_STATISTICS
-    /* Sample the reason for refusing. */
-    if (!pVM->tm.s.fMaybeUseOffsettedHostTSC)
-       STAM_COUNTER_INC(&pVM->tm.s.StatTSCNotFixed);
-    else if (!pVCpu->tm.s.fTSCTicking)
-       STAM_COUNTER_INC(&pVM->tm.s.StatTSCNotTicking);
-    else if (!pVM->tm.s.fTSCUseRealTSC)
-    {
-        if (pVM->tm.s.fVirtualSyncCatchUp)
-        {
-           if (pVM->tm.s.u32VirtualSyncCatchUpPercentage <= 10)
-               STAM_COUNTER_INC(&pVM->tm.s.StatTSCCatchupLE010);
-           else if (pVM->tm.s.u32VirtualSyncCatchUpPercentage <= 25)
-               STAM_COUNTER_INC(&pVM->tm.s.StatTSCCatchupLE025);
-           else if (pVM->tm.s.u32VirtualSyncCatchUpPercentage <= 100)
-               STAM_COUNTER_INC(&pVM->tm.s.StatTSCCatchupLE100);
-           else
-               STAM_COUNTER_INC(&pVM->tm.s.StatTSCCatchupOther);
-        }
-        else if (!pVM->tm.s.fVirtualSyncTicking)
-           STAM_COUNTER_INC(&pVM->tm.s.StatTSCSyncNotTicking);
-        else if (pVM->tm.s.fVirtualWarpDrive)
-           STAM_COUNTER_INC(&pVM->tm.s.StatTSCWarp);
-    }
+    tmCpuTickRecordOffsettedTscRefusal(pVM, pVCpu);
 #endif
     return false;
+}
+
+
+/**
+ * Calculates the number of host CPU ticks till the next virtual sync deadline.
+ *
+ * @note    To save work, this function will not bother calculating the accurate
+ *          tick count for deadlines that are more than a second ahead.
+ *
+ * @returns The number of host cpu ticks to the next deadline.  Max one second.
+ * @param   cNsToDeadline       The number of nano seconds to the next virtual
+ *                              sync deadline.
+ */
+DECLINLINE(uint64_t) tmCpuCalcTicksToDeadline(uint64_t cNsToDeadline)
+{
+    AssertCompile(TMCLOCK_FREQ_VIRTUAL <= _4G);
+    if (RT_UNLIKELY(cNsToDeadline >= TMCLOCK_FREQ_VIRTUAL))
+        return SUPGetCpuHzFromGIP(g_pSUPGlobalInfoPage);
+    uint64_t cTicks = ASMMultU64ByU32DivByU32(SUPGetCpuHzFromGIP(g_pSUPGlobalInfoPage),
+                                              cNsToDeadline,
+                                              TMCLOCK_FREQ_VIRTUAL);
+    if (cTicks > 4000)
+        cTicks -= 4000; /* fudge to account for overhead */
+    else
+        cTicks >>= 1;
+    return cTicks;
+}
+
+
+/**
+ * Gets the next deadline in host CPU clock ticks and the TSC offset if we can
+ * use the raw TSC.
+ *
+ * @returns The number of host CPU clock ticks to the next timer deadline.
+ * @param   pVCpu           The current CPU.
+ * @param   poffRealTSC     The offset against the TSC of the current CPU.
+ * @thread  EMT(pVCpu).
+ * @remarks Superset of TMCpuTickCanUseRealTSC.
+ */
+VMM_INT_DECL(uint64_t) TMCpuTickGetDeadlineAndTscOffset(PVMCPU pVCpu, bool *pfOffsettedTsc, uint64_t *poffRealTSC)
+{
+    PVM         pVM = pVCpu->CTX_SUFF(pVM);
+    uint64_t    cTicksToDeadline;
+
+    /*
+     * We require:
+     *     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)
+     *     3. Either that we're using the real TSC as time source or
+     *          a) we don't have any lag to catch up, and
+     *          b) the virtual sync clock hasn't been halted by an expired timer, and
+     *          c) we're not using warp drive (accelerated virtual guest time).
+     */
+    if (    pVM->tm.s.fMaybeUseOffsettedHostTSC
+        &&  RT_LIKELY(pVCpu->tm.s.fTSCTicking)
+        &&  (   pVM->tm.s.fTSCUseRealTSC
+             || (   !pVM->tm.s.fVirtualSyncCatchUp
+                 && RT_LIKELY(pVM->tm.s.fVirtualSyncTicking)
+                 && !pVM->tm.s.fVirtualWarpDrive))
+       )
+    {
+        *pfOffsettedTsc = true;
+        if (!pVM->tm.s.fTSCUseRealTSC)
+        {
+            /* The source is the timer synchronous virtual clock. */
+            Assert(pVM->tm.s.fTSCVirtualized);
+
+            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. */
+            if (pVM->tm.s.fTSCVirtualized)
+                *poffRealTSC = pVCpu->tm.s.offTSCRawSrc;
+            else
+                *poffRealTSC = 0;
+            cTicksToDeadline = tmCpuCalcTicksToDeadline(TMVirtualSyncGetNsToDeadline(pVM));
+        }
+    }
+    else
+    {
+#ifdef VBOX_WITH_STATISTICS
+        tmCpuTickRecordOffsettedTscRefusal(pVM, pVCpu);
+#endif
+        *pfOffsettedTsc  = false;
+        *poffRealTSC     = 0;
+        cTicksToDeadline = tmCpuCalcTicksToDeadline(TMVirtualSyncGetNsToDeadline(pVM));
+    }
+    return cTicksToDeadline;
 }
 
Index: trunk/src/VBox/VMM/VMMAll/TMAllVirtual.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMAll/TMAllVirtual.cpp	(revision 32418)
+++ trunk/src/VBox/VMM/VMMAll/TMAllVirtual.cpp	(revision 32419)
@@ -370,5 +370,5 @@
 VMM_INT_DECL(uint64_t) TMVirtualGet(PVM pVM)
 {
-    return tmVirtualGet(pVM, true /* check timers */);
+    return tmVirtualGet(pVM, true /*fCheckTimers*/);
 }
 
@@ -388,4 +388,19 @@
 {
     return tmVirtualGet(pVM, false /*fCheckTimers*/);
+}
+
+
+/**
+ * Converts the dead line interval from TMCLOCK_VIRTUAL to host nano seconds.
+ *
+ * @returns Host nano second count.
+ * @param   pVM                     The VM handle.
+ * @param   cVirtTicksToDeadline    The TMCLOCK_VIRTUAL interval.
+ */
+DECLINLINE(uint64_t) tmVirtualVirtToNsDeadline(PVM pVM, uint64_t cVirtTicksToDeadline)
+{
+    if (RT_UNLIKELY(pVM->tm.s.fVirtualWarpDrive))
+        return ASMMultU64ByU32DivByU32(cVirtTicksToDeadline, 100, pVM->tm.s.u32VirtualWarpDrivePercentage);
+    return cVirtTicksToDeadline;
 }
 
@@ -398,6 +413,9 @@
  * @param   u64                 raw virtual time.
  * @param   off                 offVirtualSync.
- */
-DECLINLINE(uint64_t) tmVirtualSyncGetHandleCatchUpLocked(PVM pVM, uint64_t u64, uint64_t off)
+ * @param   pcNsToDeadline      Where to return the number of nano seconds to
+ *                              the next virtual sync timer deadline. Can be
+ *                              NULL.
+ */
+DECLINLINE(uint64_t) tmVirtualSyncGetHandleCatchUpLocked(PVM pVM, uint64_t u64, uint64_t off, uint64_t *pcNsToDeadline)
 {
     STAM_COUNTER_INC(&pVM->tm.s.StatVirtualSyncGetLocked);
@@ -451,4 +469,12 @@
         if (fUpdatePrev)
             ASMAtomicWriteU64(&pVM->tm.s.u64VirtualSyncCatchUpPrev, u64);
+        if (pcNsToDeadline)
+        {
+            uint64_t cNsToDeadline = u64Expire - u64;
+            if (pVM->tm.s.fVirtualSyncCatchUp)
+                cNsToDeadline = ASMMultU64ByU32DivByU32(cNsToDeadline, 100,
+                                                        pVM->tm.s.u32VirtualSyncCatchUpPercentage + 100);
+            *pcNsToDeadline = tmVirtualVirtToNsDeadline(pVM, cNsToDeadline);
+        }
         tmVirtualSyncUnlock(pVM);
     }
@@ -466,4 +492,6 @@
         tmVirtualSyncUnlock(pVM);
 
+        if (pcNsToDeadline)
+            *pcNsToDeadline = 0;
 #ifdef IN_RING3
         REMR3NotifyTimerPending(pVM, pVCpuDst);
@@ -486,6 +514,9 @@
  * @param   pVM                 The VM handle.
  * @param   u64                 The virtual clock timestamp.
- */
-DECLINLINE(uint64_t) tmVirtualSyncGetLocked(PVM pVM, uint64_t u64)
+ * @param   pcNsToDeadline      Where to return the number of nano seconds to
+ *                              the next virtual sync timer deadline.  Can be
+ *                              NULL.
+ */
+DECLINLINE(uint64_t) tmVirtualSyncGetLocked(PVM pVM, uint64_t u64, uint64_t *pcNsToDeadline)
 {
     /*
@@ -496,4 +527,6 @@
         u64 = ASMAtomicUoReadU64(&pVM->tm.s.u64VirtualSync);
         tmVirtualSyncUnlock(pVM);
+        if (pcNsToDeadline)
+            *pcNsToDeadline = 0;
         STAM_COUNTER_INC(&pVM->tm.s.StatVirtualSyncGetLocked);
         Log6(("tmVirtualSyncGetLocked -> %'RU64 [stopped]\n", u64));
@@ -506,5 +539,5 @@
     uint64_t off = ASMAtomicUoReadU64(&pVM->tm.s.offVirtualSync);
     if (ASMAtomicUoReadBool(&pVM->tm.s.fVirtualSyncCatchUp))
-        return tmVirtualSyncGetHandleCatchUpLocked(pVM, u64, off);
+        return tmVirtualSyncGetHandleCatchUpLocked(pVM, u64, off, pcNsToDeadline);
 
     /*
@@ -516,5 +549,9 @@
     uint64_t u64Expire = ASMAtomicReadU64(&pVM->tm.s.CTX_SUFF(paTimerQueues)[TMCLOCK_VIRTUAL_SYNC].u64Expire);
     if (u64 < u64Expire)
+    {
         tmVirtualSyncUnlock(pVM);
+        if (pcNsToDeadline)
+            *pcNsToDeadline = tmVirtualVirtToNsDeadline(pVM, u64Expire - u64);
+    }
     else
     {
@@ -534,4 +571,6 @@
         VMR3NotifyCpuFFU(pVCpuDst->pUVCpu, VMNOTIFYFF_FLAGS_DONE_REM);
 #endif
+        if (pcNsToDeadline)
+            *pcNsToDeadline = 0;
         STAM_COUNTER_INC(&pVM->tm.s.StatVirtualSyncGetSetFF);
         STAM_COUNTER_INC(&pVM->tm.s.StatVirtualSyncGetExpired);
@@ -547,14 +586,21 @@
  *
  * @returns The timestamp.
- * @param   pVM     VM handle.
- * @param   fCheckTimers    Check timers or not
+ * @param   pVM                 VM handle.
+ * @param   fCheckTimers        Check timers or not
+ * @param   pcNsToDeadline      Where to return the number of nano seconds to
+ *                              the next virtual sync timer deadline.  Can be
+ *                              NULL.
  * @thread  EMT.
  */
-DECLINLINE(uint64_t) tmVirtualSyncGetEx(PVM pVM, bool fCheckTimers)
+DECLINLINE(uint64_t) tmVirtualSyncGetEx(PVM pVM, bool fCheckTimers, uint64_t *pcNsToDeadline)
 {
     STAM_COUNTER_INC(&pVM->tm.s.StatVirtualSyncGet);
 
     if (!pVM->tm.s.fVirtualSyncTicking)
+    {
+        if (pcNsToDeadline)
+            *pcNsToDeadline = 0;
         return pVM->tm.s.u64VirtualSync;
+    }
 
     /*
@@ -594,6 +640,9 @@
             {
                 off = u64 - off;
-                if (off < ASMAtomicReadU64(&pVM->tm.s.CTX_SUFF(paTimerQueues)[TMCLOCK_VIRTUAL_SYNC].u64Expire))
+                uint64_t const u64Expire = ASMAtomicReadU64(&pVM->tm.s.CTX_SUFF(paTimerQueues)[TMCLOCK_VIRTUAL_SYNC].u64Expire);
+                if (off < u64Expire)
                 {
+                    if (pcNsToDeadline)
+                        *pcNsToDeadline = tmVirtualVirtToNsDeadline(pVM, u64Expire - off);
                     STAM_COUNTER_INC(&pVM->tm.s.StatVirtualSyncGetLockless);
                     Log6(("tmVirtualSyncGetEx -> %'RU64 [lockless]\n", off));
@@ -608,4 +657,6 @@
         if (RT_LIKELY(!ASMAtomicReadBool(&pVM->tm.s.fVirtualSyncTicking)))
         {
+            if (pcNsToDeadline)
+                *pcNsToDeadline = 0;
             STAM_COUNTER_INC(&pVM->tm.s.StatVirtualSyncGetLockless);
             Log6(("tmVirtualSyncGetEx -> %'RU64 [lockless/stopped]\n", off));
@@ -639,5 +690,5 @@
         int rcLock = tmVirtualSyncTryLock(pVM);
         if (RT_SUCCESS_NP(rcLock))
-            return tmVirtualSyncGetLocked(pVM, u64);
+            return tmVirtualSyncGetLocked(pVM, u64, pcNsToDeadline);
 
         /* Re-check the ticking flag. */
@@ -648,4 +699,6 @@
                 && cOuterTries > 0)
                 continue;
+            if (pcNsToDeadline)
+                *pcNsToDeadline = 0;
             Log6(("tmVirtualSyncGetEx -> %'RU64 [stopped]\n", off));
             return off;
@@ -727,5 +780,15 @@
         else
             Log4(("TM: %'RU64/-%'8RU64: exp tmr [NoLock]\n", u64, pVM->tm.s.offVirtualSync - pVM->tm.s.offVirtualSyncGivenUp));
+        if (pcNsToDeadline)
+            *pcNsToDeadline = 0;
         STAM_COUNTER_INC(&pVM->tm.s.StatVirtualSyncGetExpired);
+    }
+    else if (pcNsToDeadline)
+    {
+        uint64_t cNsToDeadline = u64Expire - u64;
+        if (ASMAtomicReadBool(&pVM->tm.s.fVirtualSyncCatchUp))
+            cNsToDeadline = ASMMultU64ByU32DivByU32(cNsToDeadline, 100,
+                                                    ASMAtomicReadU32(&pVM->tm.s.u32VirtualSyncCatchUpPercentage) + 100);
+        *pcNsToDeadline = tmVirtualVirtToNsDeadline(pVM, cNsToDeadline);
     }
 
@@ -745,5 +808,5 @@
 VMM_INT_DECL(uint64_t) TMVirtualSyncGet(PVM pVM)
 {
-    return tmVirtualSyncGetEx(pVM, true /* check timers */);
+    return tmVirtualSyncGetEx(pVM, true /*fCheckTimers*/, NULL /*pcNsToDeadline*/);
 }
 
@@ -760,5 +823,5 @@
 VMM_INT_DECL(uint64_t) TMVirtualSyncGetNoCheck(PVM pVM)
 {
-    return tmVirtualSyncGetEx(pVM, false /* check timers */);
+    return tmVirtualSyncGetEx(pVM, false /*fCheckTimers*/, NULL /*pcNsToDeadline*/);
 }
 
@@ -775,5 +838,41 @@
 VMM_INT_DECL(uint64_t) TMVirtualSyncGetEx(PVM pVM, bool fCheckTimers)
 {
-    return tmVirtualSyncGetEx(pVM, fCheckTimers);
+    return tmVirtualSyncGetEx(pVM, fCheckTimers, NULL /*pcNsToDeadline*/);
+}
+
+
+/**
+ * Gets the current TMCLOCK_VIRTUAL_SYNC time and ticks to the next deadline
+ * without checking timers running on TMCLOCK_VIRTUAL.
+ *
+ * @returns The timestamp.
+ * @param   pVM                 VM handle.
+ * @param   pcNsToDeadline      Where to return the number of nano seconds to
+ *                              the next virtual sync timer deadline.
+ * @thread  EMT.
+ * @remarks May set the timer and virtual sync FFs.
+ */
+VMM_INT_DECL(uint64_t) TMVirtualSyncGetWithDeadlineNoCheck(PVM pVM, uint64_t *pcNsToDeadline)
+{
+    uint64_t cNsToDeadlineTmp;       /* try convince the compiler to skip the if tests. */
+    uint64_t u64Now = tmVirtualSyncGetEx(pVM, false /*fCheckTimers*/, &cNsToDeadlineTmp);
+    *pcNsToDeadline = cNsToDeadlineTmp;
+    return u64Now;
+}
+
+
+/**
+ * Gets the number of nano seconds to the next virtual sync deadline.
+ *
+ * @returns The number of TMCLOCK_VIRTUAL ticks.
+ * @param   pVM                 VM handle.
+ * @thread  EMT.
+ * @remarks May set the timer and virtual sync FFs.
+ */
+VMM_INT_DECL(uint64_t) TMVirtualSyncGetNsToDeadline(PVM pVM)
+{
+    uint64_t cNsToDeadline;
+    tmVirtualSyncGetEx(pVM, false /*fCheckTimers*/, &cNsToDeadline);
+    return cNsToDeadline;
 }
 
Index: trunk/src/VBox/VMM/VMMR0/HWVMXR0.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMR0/HWVMXR0.cpp	(revision 32418)
+++ trunk/src/VBox/VMM/VMMR0/HWVMXR0.cpp	(revision 32419)
@@ -395,5 +395,8 @@
         val  = pVM->hwaccm.s.vmx.msr.vmx_pin_ctls.n.disallowed0;
         /* External and non-maskable interrupts cause VM-exits. */
-        val  = val | VMX_VMCS_CTRL_PIN_EXEC_CONTROLS_EXT_INT_EXIT | VMX_VMCS_CTRL_PIN_EXEC_CONTROLS_NMI_EXIT;
+        val |= VMX_VMCS_CTRL_PIN_EXEC_CONTROLS_EXT_INT_EXIT | VMX_VMCS_CTRL_PIN_EXEC_CONTROLS_NMI_EXIT;
+        /* enable the preemption timer. */
+        if (pVM->hwaccm.s.vmx.fUsePreemptTimer)
+            val |= VMX_VMCS_CTRL_PIN_EXEC_CONTROLS_PREEMPT_TIMER;
         val &= pVM->hwaccm.s.vmx.msr.vmx_pin_ctls.n.allowed1;
 
@@ -1888,5 +1891,16 @@
 #endif /* VBOX_WITH_AUTO_MSR_LOAD_RESTORE */
 
-    if (TMCpuTickCanUseRealTSC(pVCpu, &pVCpu->hwaccm.s.vmx.u64TSCOffset))
+    bool fOffsettedTsc;
+    if (pVM->hwaccm.s.vmx.fUsePreemptTimer)
+    {
+        uint64_t cTicksToDeadline = TMCpuTickGetDeadlineAndTscOffset(pVCpu, &fOffsettedTsc, &pVCpu->hwaccm.s.vmx.u64TSCOffset);
+        cTicksToDeadline >>= pVM->hwaccm.s.vmx.cPreemptTimerShift;
+        uint32_t cPreemptionTickCount = (uint32_t)RT_MIN(cTicksToDeadline, UINT32_MAX - 16);
+        rc = VMXWriteVMCS(VMX_VMCS32_GUEST_PREEMPTION_TIMER_VALUE, cPreemptionTickCount);
+        AssertRC(rc);
+    }
+    else
+        fOffsettedTsc = TMCpuTickCanUseRealTSC(pVCpu, &pVCpu->hwaccm.s.vmx.u64TSCOffset);
+    if (fOffsettedTsc)
     {
         uint64_t u64CurTSC = ASMReadTSC();
@@ -3957,5 +3971,8 @@
 
     case VMX_EXIT_PREEMPTION_TIMER:     /* 52 VMX-preemption timer expired. The preemption timer counted down to zero. */
-        goto ResumeExecution;
+        if (!TMTimerPollBool(pVM, pVCpu))
+            goto ResumeExecution;
+        rc = VINF_EM_RAW_TIMER_PENDING;
+        break;
 
     default:
