Index: /trunk/include/VBox/sup.h
===================================================================
--- /trunk/include/VBox/sup.h	(revision 53429)
+++ /trunk/include/VBox/sup.h	(revision 53430)
@@ -4,5 +4,5 @@
 
 /*
- * Copyright (C) 2006-2012 Oracle Corporation
+ * Copyright (C) 2006-2014 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -339,7 +339,8 @@
      * This is index by ApicId via the aiCpuFromApicId table.
      *
-     * The clock and frequency information is updated for all CPUs if u32Mode
-     * is SUPGIPMODE_ASYNC_TSC, otherwise (SUPGIPMODE_SYNC_TSC) only the first
-     * entry is updated. */
+     * The clock and frequency information is updated for all CPUs if @c u32Mode
+     * is SUPGIPMODE_ASYNC_TSC. If @c u32Mode is SUPGIPMODE_SYNC_TSC only the first
+     * entry is updated. If @c u32Mode is SUPGIPMODE_SYNC_TSC the TSC frequency in
+     * @c u64CpuHz is copied to all CPUs. */
     SUPGIPCPU           aCPUs[1];
 } SUPGLOBALINFOPAGE;
@@ -374,4 +375,6 @@
     /** Each core has it's own TSC. */
     SUPGIPMODE_ASYNC_TSC,
+    /** The TSC of the cores are non-stop and have a constant frequency. */
+    SUPGIPMODE_INVARIANT_TSC,
     /** The usual 32-bit hack. */
     SUPGIPMODE_32BIT_HACK = 0x7fffffff
@@ -424,5 +427,5 @@
 SUPDECL(PSUPGLOBALINFOPAGE)             SUPGetGIP(void);
 
-#ifdef ___iprt_asm_amd64_x86_h
+
 /**
  * Gets the TSC frequency of the calling CPU.
@@ -435,11 +438,13 @@
     unsigned iCpu;
 
-    if (RT_UNLIKELY(!pGip || pGip->u32Magic != SUPGLOBALINFOPAGE_MAGIC))
+    if (RT_UNLIKELY(!pGip || pGip->u32Magic != SUPGLOBALINFOPAGE_MAGIC || !pGip->u64CpuHz))
         return UINT64_MAX;
 
-    if (pGip->u32Mode != SUPGIPMODE_ASYNC_TSC)
+    if (   pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC
+        || pGip->u32Mode == SUPGIPMODE_SYNC_TSC)
         iCpu = 0;
     else
     {
+        Assert(pGip->u32Mode == SUPGIPMODE_ASYNC_TSC);
         iCpu = pGip->aiCpuFromApicId[ASMGetApicId()];
         if (iCpu >= pGip->cCpus)
@@ -449,5 +454,5 @@
     return pGip->aCPUs[iCpu].u64CpuHz;
 }
-#endif
+
 
 /**
@@ -1468,19 +1473,19 @@
 
 /**
- * Gets the GIP mode name given the GIP mode.
- *
- * @returns The name
- * @param   enmGipMode      The GIP mode.
+ * Gets the descriptive GIP mode name.
+ *
+ * @returns The name.
+ * @param   pGip      Pointer to the GIP.
  */
 DECLINLINE(const char *) SUPGetGIPModeName(PSUPGLOBALINFOPAGE pGip)
 {
-    Assert(pGip);
+    AssertReturn(pGip, NULL);
     switch (pGip->u32Mode)
     {
-        /* case SUPGIPMODE_INVARIANT_TSC:  return "Invariant"; */
-        case SUPGIPMODE_SYNC_TSC:       return "Synchronous";
-        case SUPGIPMODE_ASYNC_TSC:      return "Asynchronous";
-        case SUPGIPMODE_INVALID:        return "Invalid";
-        default:                        return "???";
+        case SUPGIPMODE_INVARIANT_TSC: return "Invariant";
+        case SUPGIPMODE_SYNC_TSC:      return "Synchronous";
+        case SUPGIPMODE_ASYNC_TSC:     return "Asynchronous";
+        case SUPGIPMODE_INVALID:       return "Invalid";
+        default:                       return "???";
     }
 }
@@ -1497,5 +1502,5 @@
     PSUPGLOBALINFOPAGE pGip = g_pSUPGlobalInfoPage;
     if (   pGip
-        && pGip->u32Mode == SUPGIPMODE_SYNC_TSC)   /** @todo use INVARIANT_TSC */
+        && pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC)
     {
         uint64_t uLo;
@@ -1506,17 +1511,14 @@
 
         /* Arbitrary tolerance threshold, tweak later if required, perhaps
-           more tolerance on higher frequencies and less tolerance on lower. */
+           more tolerance on lower frequencies and less tolerance on higher. */
         uLo = (pGip->u64CpuHz << 10) / 1025;
         uHi = pGip->u64CpuHz + (pGip->u64CpuHz - uLo);
         if (   u64CpuHz < uLo
             || u64CpuHz > uHi)
-        {
             return false;
-        }
         return true;
     }
     return false;
 }
-
 
 
@@ -1531,5 +1533,8 @@
  *                          applied or not (optional, can be NULL).
  *
- * @remarks Maybe called with interrupts disabled!
+ * @note If you change the delta calculation made here, make sure to update the
+ *       assembly version in sup.mac! Also update supdrvGipMpEvent() while
+ *       re-adjusting deltas while choosing a new GIP master.
+ * @remarks Maybe called with interrupts disabled in ring-0!
  */
 DECLINLINE(int) SUPTscDeltaApply(PSUPGLOBALINFOPAGE pGip, uint64_t *puTsc, uint16_t idApic, bool *pfDeltaApplied)
@@ -1562,5 +1567,9 @@
 
 /**
- * Reads the delta-adjusted TSC.
+ * Gets the delta-adjusted TSC, must only be called when GIP mode is invariant
+ * (i.e. when TSC deltas are likely to be computed and available).
+ *
+ * In other GIP modes, like async, we don't bother with computing TSC deltas and
+ * therefore it is meaningless to call this function, use SUPReadTSC() instead.
  *
  * @returns VBox status code.
@@ -1572,7 +1581,7 @@
  *                          updated for other failures.
  *
- * @remarks May be called with interrupts disabled!
- */
-DECLINLINE(int) SUPReadTsc(uint64_t *puTsc, uint16_t *pidApic)
+ * @remarks May be called with interrupts disabled in ring-0!
+ */
+DECLINLINE(int) SUPGetTsc(uint64_t *puTsc, uint16_t *pidApic)
 {
 #ifdef IN_RING3
@@ -1599,4 +1608,26 @@
     return fDeltaApplied ? VINF_SUCCESS : VERR_SUPDRV_TSC_READ_FAILED;
 #endif
+}
+
+
+/**
+ * Reads the host TSC value.
+ * If applicable, normalizes the host TSC value with intercpu TSC deltas.
+ *
+ * @returns the TSC value.
+ *
+ * @remarks Requires GIP to be initialized.
+ */
+DECLINLINE(uint64_t) SUPReadTsc(void)
+{
+    if (g_pSUPGlobalInfoPage->u32Mode == SUPGIPMODE_INVARIANT_TSC)
+    {
+        uint64_t u64Tsc = UINT64_MAX;
+        int rc = SUPGetTsc(&u64Tsc, NULL /* pidApic */);
+        AssertRC(rc);
+        return u64Tsc;
+    }
+    else
+        return ASMReadTSC();
 }
 
Index: /trunk/include/VBox/sup.mac
===================================================================
--- /trunk/include/VBox/sup.mac	(revision 53429)
+++ /trunk/include/VBox/sup.mac	(revision 53430)
@@ -123,4 +123,21 @@
 endstruc
 
+;;
+; Macro to apply per-CPU TSC delta to the TSC value read in through rdtsc.
+;
+; @param   %1    The pSupGipCpu pointer
+; @remarks edx:eax contains the 64-bit TSC value to apply the delta to.
+%macro SUPTscDeltaApply 1
+    ; Check if we have a valid TSC-delta, i.e. != INT64_MAX.
+    cmp     dword [%1 + SUPGIPCPU.i64TSCDelta + 4], 0xffffffff
+    jne     %%valid_delta
+    cmp     dword [%1 + SUPGIPCPU.i64TSCDelta], 0x7fffffff
+    je      %%done
+%%valid_delta:
+    ; Subtract the delta from edx:eax
+    sub     eax, dword [%1 + SUPGIPCPU.i64TSCDelta + 4]
+    sbb     edx, dword [%1 + SUPGIPCPU.i64TSCDelta]
+%%done:
+%endmacro
 
 %endif
Index: /trunk/src/VBox/HostDrivers/Support/SUPDrv.c
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/SUPDrv.c	(revision 53429)
+++ /trunk/src/VBox/HostDrivers/Support/SUPDrv.c	(revision 53430)
@@ -121,4 +121,6 @@
  *  master with a timeout. */
 #define GIP_TSC_DELTA_SYNC_PRESTART_WORKER  5
+/** The TSC-refinement interval in seconds. */
+#define GIP_TSC_REFINE_INTERVAL             5
 
 AssertCompile(GIP_TSC_DELTA_PRIMER_LOOPS < GIP_TSC_DELTA_READ_TIME_LOOPS);
@@ -134,4 +136,7 @@
 # define DO_NOT_START_GIP
 #endif
+
+/** Whether the application of TSC-deltas is required. */
+#define GIP_ARE_TSC_DELTAS_APPLICABLE(a_pGip)  ((a_pGip)->u32Mode == SUPGIPMODE_INVARIANT_TSC && !g_fOsTscDeltasInSync)
 
 
@@ -148,5 +153,5 @@
 static int                  supdrvIOCtl_LdrGetSymbol(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPLDRGETSYMBOL pReq);
 static int                  supdrvIDC_LdrGetSymbol(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPDRVIDCREQGETSYM pReq);
-static int                  supdrvLdrSetVMMR0EPs(PSUPDRVDEVEXT pDevExt, void *pvVMMR0, void *pvVMMR0EntryInt, void *pvVMMR0EntryFast, void *pvVMMR0EntryEx);
+static int                  supdrvLdrSetVMMR0EPs(PSUPDRVDEVEXT pDevExt, void *pvVMMR0, void *pvVMMR0EntryInt,void *pvVMMR0EntryFast, void *pvVMMR0EntryEx);
 static void                 supdrvLdrUnsetVMMR0EPs(PSUPDRVDEVEXT pDevExt);
 static int                  supdrvLdrAddUsage(PSUPDRVSESSION pSession, PSUPDRVLDRIMAGE pImage);
@@ -164,7 +169,6 @@
 static DECLCALLBACK(void)   supdrvGipAsyncTimer(PRTTIMER pTimer, void *pvUser, uint64_t iTick);
 static DECLCALLBACK(void)   supdrvGipMpEvent(RTMPEVENT enmEvent, RTCPUID idCpu, void *pvUser);
-static bool                 supdrvIsInvariantTsc(void);
-static void                 supdrvGipInit(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE pGip, RTHCPHYS HCPhys,
-                                          uint64_t u64NanoTS, unsigned uUpdateHz, unsigned uUpdateIntervalNS, unsigned cCpus);
+static void                 supdrvGipInit(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE pGip, RTHCPHYS HCPhys, uint64_t u64NanoTS,
+                                          unsigned uUpdateHz, unsigned uUpdateIntervalNS, unsigned cCpus);
 static DECLCALLBACK(void)   supdrvGipInitOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2);
 static void                 supdrvGipTerm(PSUPGLOBALINFOPAGE pGip);
@@ -206,7 +210,9 @@
 static volatile uint32_t    g_cMpOnOffEvents;
 /** TSC reading during start of TSC frequency refinement phase. */
-static uint64_t             g_u64TSCAnchor;
+static uint64_t             g_u64TscAnchor;
 /** Timestamp (in nanosec) during start of TSC frequency refinement phase. */
 static uint64_t             g_u64NanoTSAnchor;
+/** Pointer to the timer used to refine the TSC frequency. */
+static PRTTIMER             g_pTscRefineTimer;
 /** Whether the host OS has already normalized the hardware TSC deltas across
  *  CPUs. */
@@ -3927,10 +3933,11 @@
  * updating.
  *
+ * @param   pGip             Pointer to the GIP.
  * @param   pGipCpu          The per CPU structure for this CPU.
  * @param   u64NanoTS        The current time.
  */
-static void supdrvGipReInitCpu(PSUPGIPCPU pGipCpu, uint64_t u64NanoTS)
-{
-    pGipCpu->u64TSC    = ASMReadTSC() - pGipCpu->u32UpdateIntervalTSC;
+static void supdrvGipReInitCpu(PSUPGLOBALINFOPAGE pGip, PSUPGIPCPU pGipCpu, uint64_t u64NanoTS)
+{
+    pGipCpu->u64TSC    = SUPReadTsc() - pGipCpu->u32UpdateIntervalTSC;
     pGipCpu->u64NanoTS = u64NanoTS;
 }
@@ -3950,5 +3957,5 @@
 
     if (RT_LIKELY(iCpu < pGip->cCpus && pGip->aCPUs[iCpu].idCpu == idCpu))
-        supdrvGipReInitCpu(&pGip->aCPUs[iCpu], *(uint64_t *)pvUser2);
+        supdrvGipReInitCpu(pGip, &pGip->aCPUs[iCpu], *(uint64_t *)pvUser2);
 
     NOREF(pvUser2);
@@ -4030,4 +4037,6 @@
                  * The more interrupts the better...
                  */
+                /** @todo On Windows, RTTimerRequestSystemGranularity() always succeeds, so
+                 *        whats the point of the remaining calls? */
                 if (   RT_SUCCESS_NP(RTTimerRequestSystemGranularity(  976563 /* 1024 HZ */, &u32SystemResolution))
                     || RT_SUCCESS_NP(RTTimerRequestSystemGranularity( 1000000 /* 1000 HZ */, &u32SystemResolution))
@@ -4050,12 +4059,13 @@
 
                 u64NanoTS = RTTimeSystemNanoTS() - pGipR0->u32UpdateIntervalNS;
-                if (   pGipR0->u32Mode == SUPGIPMODE_SYNC_TSC
+                if (   pGipR0->u32Mode == SUPGIPMODE_INVARIANT_TSC
+                    || pGipR0->u32Mode == SUPGIPMODE_SYNC_TSC
                     || RTMpGetOnlineCount() == 1)
-                    supdrvGipReInitCpu(&pGipR0->aCPUs[0], u64NanoTS);
+                    supdrvGipReInitCpu(pGipR0, &pGipR0->aCPUs[0], u64NanoTS);
                 else
                     RTMpOnAll(supdrvGipReInitCpuCallback, pGipR0, &u64NanoTS);
 
 #ifndef DO_NOT_START_GIP
-                rc = RTTimerStart(pDevExt->pGipTimer, 0); AssertRC(rc);
+                rc = RTTimerStart(pDevExt->pGipTimer, 0 /* fire ASAP */); AssertRC(rc);
 #endif
                 rc = VINF_SUCCESS;
@@ -5610,4 +5620,30 @@
 
 
+/**
+ * Returns whether the host CPU sports an invariant TSC or not.
+ *
+ * @returns true if invariant TSC is supported, false otherwise.
+ */
+static bool supdrvIsInvariantTsc(void)
+{
+    static bool s_fQueried        = false;
+    static bool s_fIsInvariantTsc = false;
+    if (!s_fQueried)
+    {
+        uint32_t uEax, uEbx, uEcx, uEdx;
+        ASMCpuId(0x80000000, &uEax, &uEbx, &uEcx, &uEdx);
+        if (uEax >= 0x80000007)
+        {
+            ASMCpuId(0x80000007, &uEax, &uEbx, &uEcx, &uEdx);
+            if (uEdx & X86_CPUID_AMD_ADVPOWER_EDX_TSCINVAR)
+                s_fIsInvariantTsc = true;
+        }
+        s_fQueried = true;
+    }
+
+    return s_fIsInvariantTsc;
+}
+
+
 #ifdef SUPDRV_USE_TSC_DELTA_THREAD
 /**
@@ -5702,5 +5738,8 @@
                 cConsecutiveTimeouts = 0;
                 if (!cTimesMeasured++)
+                {
                     rc = supdrvMeasureTscDeltas(pDevExt, NULL /* pidxMaster */);
+                    RTCpuSetCopy(&pDevExt->TscDeltaObtainedCpuSet, &pDevExt->pGip->OnlineCpuSet);
+                }
                 else
                 {
@@ -5721,4 +5760,6 @@
                             rc |= supdrvMeasureTscDeltaOne(pDevExt, iCpu);
                             RTCpuSetDel(&pDevExt->TscDeltaCpuSet, pGipCpuWorker->idCpu);
+                            if (pGipCpuWorker->i64TSCDelta != INT64_MAX)
+                                RTCpuSetAdd(&pDevExt->TscDeltaObtainedCpuSet, pGipCpuWorker->idCpu);
                         }
                     }
@@ -5831,6 +5872,6 @@
     {
         /* Signal a few more times before giving up. */
-        int cTries = 5;
-        while (--cTries > 0)
+        int cTriesLeft = 5;
+        while (--cTriesLeft > 0)
         {
             RTThreadUserSignal(pDevExt->hTscDeltaThread);
@@ -5856,7 +5897,8 @@
  *          notifications!
  */
-static int supdrvTscDeltaInit(PSUPDRVDEVEXT pDevExt)
-{
-    Assert(!g_fOsTscDeltasInSync);
+static int supdrvTscDeltaThreadInit(PSUPDRVDEVEXT pDevExt)
+{
+    Assert(GIP_ARE_TSC_DELTAS_APPLICABLE(pDevExt->pGip));
+
     int rc = RTSpinlockCreate(&pDevExt->hTscDeltaSpinlock, RTSPINLOCK_FLAGS_INTERRUPT_UNSAFE, "VBoxTscSpnLck");
     if (RT_SUCCESS(rc))
@@ -5868,4 +5910,5 @@
             pDevExt->cMsTscDeltaTimeout = 1;
             RTCpuSetEmpty(&pDevExt->TscDeltaCpuSet);
+            RTCpuSetEmpty(&pDevExt->TscDeltaObtainedCpuSet);
             rc = RTThreadCreate(&pDevExt->hTscDeltaThread, supdrvTscDeltaThread, pDevExt, 0 /* cbStack */,
                                 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "VBoxTscThread");
@@ -5926,4 +5969,35 @@
     pDevExt->rcTscDelta = VERR_NOT_AVAILABLE;
 }
+
+
+/**
+ * Waits for TSC-delta measurements to be completed for all online CPUs.
+ *
+ * @returns VBox status code.
+ * @param   pDevExt         Pointer to the device instance data.
+ */
+static int supdrvTscDeltaThreadWaitForOnlineCpus(PSUPDRVDEVEXT pDevExt)
+{
+    int cTriesLeft = 5;
+    int cMsTotalWait;
+    int cMsWaited = 0;
+    int cMsWaitGranularity = 1;
+
+    PSUPGLOBALINFOPAGE pGip = pDevExt->pGip;
+    AssertReturn(pGip, VERR_INVALID_POINTER);
+
+    cMsTotalWait = RT_MIN(pGip->cPresentCpus + 2, 150);
+    while (cTriesLeft-- > 0)
+    {
+        if (RTCpuSetIsEqual(&pDevExt->TscDeltaObtainedCpuSet, &pGip->OnlineCpuSet))
+            return VINF_SUCCESS;
+        RTThreadSleep(cMsWaitGranularity);
+        cMsWaited += cMsWaitGranularity;
+        if (cMsWaited >= cMsTotalWait)
+            break;
+    }
+
+    return VERR_TIMEOUT;
+}
 #endif /* SUPDRV_USE_TSC_DELTA_THREAD */
 
@@ -5935,16 +6009,17 @@
  * the CPU frequency up, while for the invariant cases using a sleeping method.
  *
- * The TSC frequency can vary on systems that are not reported as invariant.
- * However, on such systems the object of this function is to find out what the
- * nominal, maximum TSC frequency under normal CPU operation.
+ * The TSC frequency can vary on systems which are not reported as invariant.
+ * On such systems the object of this function is to find out what the nominal,
+ * maximum TSC frequency under 'normal' CPU operation.
  *
  * @returns VBox status code.
- * @param   pGip        Pointer to the GIP.
- *
- * @remarks Must be called only after measuring the TSC deltas.
- */
-static int supdrvGipMeasureTscFreq(PSUPGLOBALINFOPAGE pGip)
+ * @param   pDevExt        Pointer to the device instance.
+ *
+ * @remarks Must be called only -after- measuring the TSC deltas.
+ */
+static int supdrvGipMeasureTscFreq(PSUPDRVDEVEXT pDevExt)
 {
     int cTriesLeft = 4;
+    PSUPGLOBALINFOPAGE pGip = pDevExt->pGip;
 
     /* Assert order. */
@@ -5976,11 +6051,8 @@
         ASMSetFlags(uFlags);
 
-        /* Activate this when implemented invariant TSC GIP mode. Otherwise systems that are really invariant
-           which get detected as async will break. */
-#if 0
-        if (supdrvIsInvariantTsc())
+        if (pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC)
         {
             /*
-             * Sleep wait since the TSC frequency is constant, eases host load.
+             * Sleep-wait since the TSC frequency is constant, it eases host load.
              * Shorter interval produces more variance in the frequency (esp. Windows).
              */
@@ -5992,5 +6064,4 @@
         }
         else
-#endif
         {
             /* Busy-wait keeping the frequency up and measure. */
@@ -6010,8 +6081,5 @@
         ASMSetFlags(uFlags);
 
-        /* Activate this when implemented invariant TSC GIP mode. Otherwise systems that are really invariant
-           which get detected as async will break. */
-#if 0
-        if (supdrvIsInvariantTsc())        /** @todo replace with enum check. */
+        if (GIP_ARE_TSC_DELTAS_APPLICABLE(pGip))
         {
             int rc;
@@ -6024,10 +6092,24 @@
                 || !fAppliedAfter)
             {
+#ifdef SUPDRV_USE_TSC_DELTA_THREAD
+                /*
+                 * The TSC-delta measurements are kicked-off asynchronously as each host CPU is initialized.
+                 * Therefore, if we failed to have a delta for the CPU(s) we were scheduled on (idApicBefore
+                 * and idApicAfter) then wait until we have TSC-delta measurements for all online CPUs and
+                 * proceed. This should be triggered just once if we're rather unlucky.
+                 */
+                rc = supdrvTscDeltaThreadWaitForOnlineCpus(pDevExt);
+                if (rc == VERR_TIMEOUT)
+                {
+                    SUPR0Printf("vboxdrv: supdrvGipMeasureTscFreq: timedout waiting for TSC-delta measurements.\n");
+                    return VERR_SUPDRV_TSC_FREQ_MEASUREMENT_FAILED;
+                }
+#else
                 SUPR0Printf("vboxdrv: supdrvGipMeasureTscFreq: idApicBefore=%u idApicAfter=%u cTriesLeft=%u\n",
                             idApicBefore, idApicAfter, cTriesLeft);
+#endif
                 continue;
             }
         }
-#endif
 
         /*
@@ -6035,8 +6117,139 @@
          */
         pGip->u64CpuHz = ((u64TscAfter - u64TscBefore) * RT_NS_1SEC_64) / (u64NanoTsAfter - u64NanoTsBefore);
+        if (pGip->u32Mode != SUPGIPMODE_ASYNC_TSC)
+            pGip->aCPUs[0].u64CpuHz = pGip->u64CpuHz;
         return VINF_SUCCESS;
     }
 
     return VERR_SUPDRV_TSC_FREQ_MEASUREMENT_FAILED;
+}
+
+
+/**
+ * Timer callback function for TSC frequency refinement in invariant GIP mode.
+ *
+ * @param   pTimer      The timer.
+ * @param   pvUser      Opaque pointer to the GIP.
+ * @param   iTick       The timer tick.
+ */
+static DECLCALLBACK(void) supdrvRefineTscTimer(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
+{
+    uint8_t            idApic;
+    uint64_t           u64DeltaNanoTS;
+    uint64_t           u64DeltaTsc;
+    uint64_t           u64NanoTS;
+    uint64_t           u64Tsc;
+    RTCCUINTREG        uFlags;
+    bool               fDeltaApplied = false;
+    PSUPGLOBALINFOPAGE pGip = (PSUPGLOBALINFOPAGE)pvUser;
+
+    /* Paranoia. */
+    Assert(pGip);
+    Assert(pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC);
+
+    u64NanoTS = RTTimeSystemNanoTS();
+    while (RTTimeSystemNanoTS() == u64NanoTS)
+        ASMNopPause();
+    uFlags    = ASMIntDisableFlags();
+    idApic    = ASMGetApicId();
+    u64Tsc    = ASMReadTSC();
+    u64NanoTS = RTTimeSystemNanoTS();
+    ASMSetFlags(uFlags);
+    SUPTscDeltaApply(pGip, &u64Tsc, idApic, &fDeltaApplied);
+    u64DeltaNanoTS = u64NanoTS - g_u64NanoTSAnchor;
+    u64DeltaTsc = u64Tsc - g_u64TscAnchor;
+
+    if (   pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC
+        && !fDeltaApplied)
+    {
+        SUPR0Printf("vboxdrv: failed to refine TSC frequency as TSC-deltas unavailable after %d seconds!\n",
+                    GIP_TSC_REFINE_INTERVAL);
+        return;
+    }
+
+    /* Calculate the TSC frequency. */
+    if (   u64DeltaTsc < UINT64_MAX / RT_NS_1SEC
+        && u64DeltaNanoTS < UINT32_MAX)
+        pGip->u64CpuHz = ASMMultU64ByU32DivByU32(u64DeltaTsc, RT_NS_1SEC, u64DeltaNanoTS);
+    else
+    {
+        /* Try not to lose precision, the larger the interval the more likely we overflow. */
+        if (   u64DeltaTsc < UINT64_MAX / RT_NS_100MS
+            && u64DeltaNanoTS / 10 < UINT32_MAX)
+            pGip->u64CpuHz = ASMMultU64ByU32DivByU32(u64DeltaTsc, RT_NS_100MS, u64DeltaNanoTS / 10);
+        else if (   u64DeltaTsc < UINT64_MAX / RT_NS_10MS
+                 && u64DeltaNanoTS / 100 < UINT32_MAX)
+            pGip->u64CpuHz = ASMMultU64ByU32DivByU32(u64DeltaTsc, RT_NS_10MS, u64DeltaNanoTS / 100);
+        else if (   u64DeltaTsc < UINT64_MAX / RT_NS_1MS
+                 && u64DeltaNanoTS / 1000 < UINT32_MAX)
+            pGip->u64CpuHz = ASMMultU64ByU32DivByU32(u64DeltaTsc, RT_NS_1MS, u64DeltaNanoTS / 1000);
+        else /* Screw it. */
+            pGip->u64CpuHz = u64DeltaTsc / (u64DeltaNanoTS / RT_NS_1SEC_64);
+    }
+
+    /* Update rest of GIP. */
+    Assert(pGip->u32Mode != SUPGIPMODE_ASYNC_TSC); /* See SUPGetCpuHzFromGIP().*/
+    pGip->aCPUs[0].u64CpuHz = pGip->u64CpuHz;
+}
+
+
+/**
+ * Starts the TSC-frequency refinement phase asynchronously.
+ *
+ * @param   pDevExt        Pointer to the device instance data.
+ */
+static void supdrvRefineTscFreq(PSUPDRVDEVEXT pDevExt)
+{
+    uint64_t            u64NanoTS;
+    RTCCUINTREG         uFlags;
+    uint8_t             idApic;
+    int                 rc;
+    bool                fDeltaApplied = false;
+    PSUPGLOBALINFOPAGE  pGip;
+
+    /* Validate. */
+    Assert(pDevExt);
+    Assert(pDevExt->pGip);
+
+    pGip = pDevExt->pGip;
+    u64NanoTS = RTTimeSystemNanoTS();
+    while (RTTimeSystemNanoTS() == u64NanoTS)
+        ASMNopPause();
+    uFlags            = ASMIntDisableFlags();
+    idApic            = ASMGetApicId();
+    g_u64TscAnchor    = ASMReadTSC();
+    g_u64NanoTSAnchor = RTTimeSystemNanoTS();
+    ASMSetFlags(uFlags);
+    SUPTscDeltaApply(pGip, &g_u64TscAnchor, idApic, &fDeltaApplied);
+
+#ifdef SUPDRV_USE_TSC_DELTA_THREAD
+    if (   pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC
+        && !fDeltaApplied)
+    {
+        rc = supdrvTscDeltaThreadWaitForOnlineCpus(pDevExt);
+        if (rc == VERR_TIMEOUT)
+        {
+            SUPR0Printf("vboxdrv: Skipping refinement of TSC frequency as TSC-delta measurement timed out!\n");
+            return;
+        }
+    }
+#endif
+
+    rc = RTTimerCreateEx(&g_pTscRefineTimer, 0 /* one-shot */, RTTIMER_FLAGS_CPU_ANY, supdrvRefineTscTimer, pGip);
+    if (RT_SUCCESS(rc))
+    {
+        /*
+         * Refine the TSC frequency measurement over a long interval. Ideally, we want to keep the
+         * interval as small as possible while gaining the most consistent and accurate frequency
+         * (compared to what the host OS might have measured).
+         *
+         * In theory, we gain more accuracy with longer intervals, but we want VMs to startup with the
+         * same TSC frequency whenever possible so we need to keep the interval short.
+         */
+        rc = RTTimerStart(g_pTscRefineTimer, GIP_TSC_REFINE_INTERVAL * RT_NS_1SEC_64);
+        AssertRC(rc);
+    }
+    else
+        OSDBGPRINT(("RTTimerCreateEx failed to create one-shot timer. rc=%Rrc\n", rc));
 }
 
@@ -6107,4 +6320,5 @@
                     && !supdrvOSGetForcedAsyncTscMode(pDevExt)))
     {
+        /* Basically invariant Windows boxes, should never be detected as async. */
         OSDBGPRINT(("supdrvGipCreate: The TSC-deltas should be normalized by the host OS, but verifying shows it's not!\n"));
         return VERR_INTERNAL_ERROR_2;
@@ -6112,8 +6326,8 @@
 
 #ifdef SUPDRV_USE_TSC_DELTA_THREAD
-    if (!g_fOsTscDeltasInSync)
+    if (GIP_ARE_TSC_DELTAS_APPLICABLE(pGip))
     {
         /* Initialize TSC-delta measurement thread before executing any Mp event callbacks. */
-        rc = supdrvTscDeltaInit(pDevExt);
+        rc = supdrvTscDeltaThreadInit(pDevExt);
     }
 #endif
@@ -6126,7 +6340,7 @@
             if (RT_SUCCESS(rc))
             {
+                uint16_t iCpu;
 #ifndef SUPDRV_USE_TSC_DELTA_THREAD
-                uint16_t iCpu;
-                if (!g_fOsTscDeltasInSync)
+                if (GIP_ARE_TSC_DELTAS_APPLICABLE(pGip))
                 {
                     /*
@@ -6151,10 +6365,7 @@
                 if (RT_SUCCESS(rc))
                 {
-                    rc = supdrvGipMeasureTscFreq(pGip);
+                    rc = supdrvGipMeasureTscFreq(pDevExt);
                     if (RT_SUCCESS(rc))
                     {
-                        if (supdrvIsInvariantTsc())
-                            pGip->aCPUs[0].u64CpuHz = pGip->u64CpuHz;
-
                         /*
                          * Create the timer.
@@ -6180,9 +6391,11 @@
                             Log(("supdrvGipCreate: %u ns interval.\n", u32Interval));
                             g_pSUPGlobalInfoPage = pGip;
+                            if (pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC)
+                                supdrvRefineTscFreq(pDevExt);
                             return VINF_SUCCESS;
                         }
                         else
                         {
-                            OSDBGPRINT(("supdrvGipCreate: RTTimerCreateEx failed (%u ns interval). rc=%Rrc\n", u32Interval, rc));
+                            OSDBGPRINT(("supdrvGipCreate: failed create GIP timer at %u ns interval. rc=%Rrc\n", u32Interval, rc));
                             Assert(!pDevExt->pGipTimer);
                         }
@@ -6235,4 +6448,13 @@
 
     /*
+     * Destroy the TSC-refinement one-shot timer.
+     */
+    if (g_pTscRefineTimer)
+    {
+        RTTimerDestroy(g_pTscRefineTimer);
+        g_pTscRefineTimer = NULL;
+    }
+
+    /*
      * Invalid the GIP data.
      */
@@ -6274,25 +6496,29 @@
  * Timer callback function sync GIP mode.
  * @param   pTimer      The timer.
- * @param   pvUser      The device extension.
+ * @param   pvUser      Opaque pointer to the device extension.
+ * @param   iTick       The timer tick.
  */
 static DECLCALLBACK(void) supdrvGipSyncTimer(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
 {
-    RTCCUINTREG     fOldFlags = ASMIntDisableFlags(); /* No interruptions please (real problem on S10). */
-    uint64_t        u64TSC    = ASMReadTSC();
-    uint64_t        NanoTS    = RTTimeSystemNanoTS();
-    PSUPDRVDEVEXT   pDevExt   = (PSUPDRVDEVEXT)pvUser;
-
-    if (supdrvIsInvariantTsc())
-    {
-        PSUPGIPCPU         pGipCpu;
-        unsigned           iCpu;
-        PSUPGLOBALINFOPAGE pGip = pDevExt->pGip;
-        uint8_t            idApic = ASMGetApicId();
-
-        iCpu = pGip->aiCpuFromApicId[idApic];
-        Assert(iCpu < pGip->cCpus);
-        pGipCpu = &pGip->aCPUs[iCpu];
-        Assert(pGipCpu->idCpu == RTMpCpuId());
-
+    RTCCUINTREG        uFlags;
+    uint64_t           u64TSC;
+    uint64_t           u64NanoTS;
+    PSUPDRVDEVEXT      pDevExt = (PSUPDRVDEVEXT)pvUser;
+    PSUPGLOBALINFOPAGE pGip = pDevExt->pGip;
+
+    /*
+     * Synchronize with the host OS clock tick before reading the TSC.
+     * Especially important on Windows where the granularity is terrible.
+     */
+    u64NanoTS = RTTimeSystemNanoTS();
+    while (u64NanoTS == RTTimeSystemNanoTS())
+        ASMNopPause();
+
+    uFlags    = ASMIntDisableFlags(); /* No interruptions please (real problem on S10). */
+    u64TSC    = ASMReadTSC();
+    u64NanoTS = RTTimeSystemNanoTS();
+
+    if (GIP_ARE_TSC_DELTAS_APPLICABLE(pGip))
+    {
         /*
          * The calculations in supdrvGipUpdate() is very timing sensitive and doesn't handle
@@ -6304,65 +6530,11 @@
          * fire on the CPU they were registered/started on. Darwin, Solaris need verification.
          */
-        if (pGipCpu->i64TSCDelta != INT64_MAX)
-            u64TSC -= pGipCpu->i64TSCDelta;
-    }
-
-    supdrvGipUpdate(pDevExt, NanoTS, u64TSC, NIL_RTCPUID, iTick);
-
-    ASMSetFlags(fOldFlags);
-
-    if (supdrvIsInvariantTsc())
-    {
-        /*
-         * Refine the TSC frequency measurement over a longer interval. Ideally, we want to keep the
-         * interval as small as possible while gaining the most consistent and accurate frequency
-         * (compared to what the host OS might have measured).
-         *
-         * In theory, we gain more accuracy with  longer intervals, but we want VMs to startup with the
-         * same TSC frequency whenever possible so we need to keep the interval short.
-         */
-        uint8_t            idApic;
-        uint64_t           u64NanoTS;
-        PSUPGLOBALINFOPAGE pGip = pDevExt->pGip;
-        const int          cSeconds = 3;
-        if (RT_UNLIKELY(iTick == 3))    /* Helps with more consistent values across multiple runs (esp. Windows). */
-        {
-            u64NanoTS = RTTimeSystemNanoTS();
-            while (RTTimeSystemNanoTS() == u64NanoTS)
-                ASMNopPause();
-            fOldFlags         = ASMIntDisableFlags();
-            idApic            = ASMGetApicId();
-            g_u64TSCAnchor    = ASMReadTSC();
-            g_u64NanoTSAnchor = RTTimeSystemNanoTS();
-            ASMSetFlags(fOldFlags);
-            SUPTscDeltaApply(pGip, &g_u64TSCAnchor, idApic, NULL /* pfDeltaApplied */);
-            ++g_u64TSCAnchor;
-        }
-        else if (g_u64TSCAnchor)
-        {
-            uint64_t u64DeltaNanoTS;
-            u64NanoTS = RTTimeSystemNanoTS();
-            while (RTTimeSystemNanoTS() == u64NanoTS)
-                ASMNopPause();
-            fOldFlags = ASMIntDisableFlags();
-            idApic    = ASMGetApicId();
-            u64TSC    = ASMReadTSC();
-            u64NanoTS = RTTimeSystemNanoTS();
-            ASMSetFlags(fOldFlags);
-            SUPTscDeltaApply(pGip, &u64TSC, idApic, NULL /* pfDeltaApplied */);
-            u64DeltaNanoTS = u64NanoTS - g_u64NanoTSAnchor;
-            if (u64DeltaNanoTS >= cSeconds * RT_NS_1SEC_64)
-            {
-                uint16_t iCpu;
-                if (u64DeltaNanoTS < UINT32_MAX)
-                    pGip->u64CpuHz = ASMMultU64ByU32DivByU32(u64TSC - g_u64TSCAnchor, RT_NS_1SEC, u64DeltaNanoTS);
-                else
-                    pGip->u64CpuHz = (u64TSC - g_u64TSCAnchor) / (u64DeltaNanoTS / RT_NS_1SEC);
-
-                pGip->aCPUs[0].u64CpuHz = pGip->u64CpuHz;
-                g_u64TSCAnchor = 0;
-            }
-        }
-    }
+        Assert(!ASMIntAreEnabled());
+        SUPTscDeltaApply(pGip, &u64TSC, ASMGetApicId(), NULL /* pfDeltaApplied */);
+    }
+
+    supdrvGipUpdate(pDevExt, u64NanoTS, u64TSC, NIL_RTCPUID, iTick);
+
+    ASMSetFlags(uFlags);
 }
 
@@ -6371,5 +6543,6 @@
  * Timer callback function for async GIP mode.
  * @param   pTimer      The timer.
- * @param   pvUser      The device extension.
+ * @param   pvUser      Opaque pointer to the device extension.
+ * @param   iTick       The timer tick.
  */
 static DECLCALLBACK(void) supdrvGipAsyncTimer(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
@@ -6491,12 +6664,11 @@
      * update the state and it'll get serviced when the thread's listening interval times out.
      */
-    if (   !g_fOsTscDeltasInSync
-        && supdrvIsInvariantTsc())
-    {
-        RTCpuSetAdd(&pDevExt->TscDeltaCpuSet, idCpu);
+    if (GIP_ARE_TSC_DELTAS_APPLICABLE(pGip))
+    {
         RTSpinlockAcquire(pDevExt->hTscDeltaSpinlock);
         if (   pDevExt->enmTscDeltaState == kSupDrvTscDeltaState_Listening
             || pDevExt->enmTscDeltaState == kSupDrvTscDeltaState_Measuring)
         {
+            RTCpuSetAdd(&pDevExt->TscDeltaCpuSet, idCpu);
             pDevExt->enmTscDeltaState = kSupDrvTscDeltaState_WaitAndMeasure;
         }
@@ -6550,7 +6722,13 @@
     }
 
-    /* Reset the TSC delta (if required), we will recalculate it lazily. */
-    if (!g_fOsTscDeltasInSync)
+    /* Reset the TSC delta, we will recalculate it lazily. */
+    if (GIP_ARE_TSC_DELTAS_APPLICABLE(pGip))
         ASMAtomicWriteS64(&pGip->aCPUs[i].i64TSCDelta, INT64_MAX);
+
+#ifdef SUPDRV_USE_TSC_DELTA_THREAD
+    /* Remove this CPU from the set of CPUs that we have obtained the TSC deltas. */
+    if (supdrvIsInvariantTsc())
+        RTCpuSetDel(&pDevExt->TscDeltaObtainedCpuSet, idCpu);
+#endif
 
     /* commit it */
@@ -6653,30 +6831,4 @@
         }
     }
-}
-
-
-/**
- * Returns whether the host CPU sports an invariant TSC or not.
- *
- * @returns true if invariant TSC is supported, false otherwise.
- */
-static bool supdrvIsInvariantTsc(void)
-{
-    static bool s_fQueried        = false;
-    static bool s_fIsInvariantTsc = false;
-    if (!s_fQueried)
-    {
-        uint32_t uEax, uEbx, uEcx, uEdx;
-        ASMCpuId(0x80000000, &uEax, &uEbx, &uEcx, &uEdx);
-        if (uEax >= 0x80000007)
-        {
-            ASMCpuId(0x80000007, &uEax, &uEbx, &uEcx, &uEdx);
-            if (uEdx & X86_CPUID_AMD_ADVPOWER_EDX_TSCINVAR)
-                s_fIsInvariantTsc = true;
-        }
-        s_fQueried = true;
-    }
-
-    return s_fIsInvariantTsc;
 }
 
@@ -6927,9 +7079,10 @@
     AssertReturn(pDevExt, VERR_INVALID_PARAMETER);
     AssertReturn(pDevExt->pGip, VERR_INVALID_PARAMETER);
-    Assert(!g_fOsTscDeltasInSync);
 
     pGip          = pDevExt->pGip;
     idMaster      = pDevExt->idGipMaster;
     pGipCpuWorker = &pGip->aCPUs[idxWorker];
+
+    Assert(GIP_ARE_TSC_DELTAS_APPLICABLE(pGip));
 
     if (pGipCpuWorker->idCpu == idMaster)
@@ -6992,11 +7145,5 @@
     uint32_t   cOnlineCpus    = pGip->cOnlineCpus;
 
-    Assert(!g_fOsTscDeltasInSync);
-
-    /*
-     * If we determined the TSC is async., don't bother with measuring deltas.
-     */
-    if (RT_UNLIKELY(pGip->u32Mode == SUPGIPMODE_ASYNC_TSC))
-        return VINF_SUCCESS;
+    Assert(GIP_ARE_TSC_DELTAS_APPLICABLE(pGip));
 
     /*
@@ -7170,11 +7317,10 @@
 static SUPGIPMODE supdrvGipDetermineTscMode(PSUPDRVDEVEXT pDevExt)
 {
-#if 0
+    /* Trust CPUs that declare their TSC to be invariant. */
     if (supdrvIsInvariantTsc())
-        return SUPGIPMODE_SYNC_TSC;     /** @todo Switch to SUPGIPMODE_INVARIANT_TSC later. */
-#endif
-
-    /*
-     * On SMP we're faced with two problems:
+        return SUPGIPMODE_INVARIANT_TSC;
+
+    /*
+     * Without invariant CPU ID bit - On SMP we're faced with two problems:
      *      (1) There might be a skew between the CPU, so that cpu0
      *          returns a TSC that is slightly different from cpu1.
@@ -7203,4 +7349,5 @@
          * won't trust it unless it has the TscInvariant bit is set.
          */
+        /** @todo this is now redundant. remove later. */
         /* Check for "AuthenticAMD" */
         ASMCpuId(0, &uEAX, &uEBX, &uECX, &uEDX);
@@ -7213,5 +7360,5 @@
             {
                 ASMCpuId(0x80000007, &uEAX, &uEBX, &uECX, &uEDX);
-                if (    !(uEDX & RT_BIT(8))/* TscInvariant */
+                if (    !(uEDX & X86_CPUID_AMD_ADVPOWER_EDX_TSCINVAR) /* TscInvariant */
                     &&  (uEDX & 0x3e))  /* STC|TM|THERMTRIP|VID|FID. Ignore TS. */
                     return SUPGIPMODE_ASYNC_TSC;
@@ -7409,7 +7556,10 @@
      * Calc TSC delta.
      */
-    /** @todo validate the NanoTS delta, don't trust the OS to call us when it should... */
     u64TSCDelta = u64TSC - pGipCpu->u64TSC;
     ASMAtomicWriteU64(&pGipCpu->u64TSC, u64TSC);
+
+    /* We don't need to keep realculating the frequency when it's invariant. */
+    if (pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC)
+        return;
 
     if (u64TSCDelta >> 32)
@@ -7437,4 +7587,34 @@
 
     /*
+     * Validate the NanoTS deltas between timer fires with an arbitrary threshold of 0.5%.
+     * Wait until we have at least one full history since the above history reset. The
+     * assumption is that the majority of the previous history values will be tolerable.
+     * See @bugref{6710} comment #67.
+     */
+    if (   u32TransactionId > 23 /* 7 + (8 * 2) */
+        && pGip->u32Mode != SUPGIPMODE_ASYNC_TSC)
+    {
+        uint32_t uNanoTsThreshold = pGip->u32UpdateIntervalNS / 200;
+        if (   pGipCpu->u32PrevUpdateIntervalNS > pGip->u32UpdateIntervalNS + uNanoTsThreshold
+            || pGipCpu->u32PrevUpdateIntervalNS < pGip->u32UpdateIntervalNS - uNanoTsThreshold)
+        {
+            uint32_t u32;
+            u32  = pGipCpu->au32TSCHistory[0];
+            u32 += pGipCpu->au32TSCHistory[1];
+            u32 += pGipCpu->au32TSCHistory[2];
+            u32 += pGipCpu->au32TSCHistory[3];
+            u32 >>= 2;
+            u64TSCDelta  = pGipCpu->au32TSCHistory[4];
+            u64TSCDelta += pGipCpu->au32TSCHistory[5];
+            u64TSCDelta += pGipCpu->au32TSCHistory[6];
+            u64TSCDelta += pGipCpu->au32TSCHistory[7];
+            u64TSCDelta >>= 2;
+            u64TSCDelta += u32;
+            u64TSCDelta >>= 1;
+        }
+    }
+
+
+    /*
      * TSC History.
      */
@@ -7451,5 +7631,5 @@
      * However, this problem existed before the invariant mode was introduced.
      */
-    if (   supdrvIsInvariantTsc()
+    if (   pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC
         || pGip->u32UpdateHz >= 1000)
     {
@@ -7489,7 +7669,4 @@
     ASMAtomicWriteU32(&pGipCpu->u32UpdateIntervalTSC, u32UpdateIntervalTSC + u32UpdateIntervalTSCSlack);
 
-    if (supdrvIsInvariantTsc())
-        return;
-
     /*
      * CpuHz.
@@ -7548,5 +7725,6 @@
      * Recalc the update frequency every 0x800th time.
      */
-    if (!(pGipCpu->u32TransactionId & (GIP_UPDATEHZ_RECALC_FREQ * 2 - 2)))
+    if (   pGip->u32Mode != SUPGIPMODE_INVARIANT_TSC   /* cuz we're not recalculating the frequency on invariants hosts. */
+        && !(pGipCpu->u32TransactionId & (GIP_UPDATEHZ_RECALC_FREQ * 2 - 2)))
     {
         if (pGip->u64NanoTSLastUpdateHz)
@@ -7566,5 +7744,5 @@
 #endif
         }
-        ASMAtomicWriteU64(&pGip->u64NanoTSLastUpdateHz, u64NanoTS + 1);
+        ASMAtomicWriteU64(&pGip->u64NanoTSLastUpdateHz, u64NanoTS | 1);
     }
 
@@ -7684,5 +7862,5 @@
         return VERR_INVALID_CPU_ID;
 
-    if (g_fOsTscDeltasInSync)
+    if (!GIP_ARE_TSC_DELTAS_APPLICABLE(pGip))
         return VINF_SUCCESS;
 
@@ -7705,5 +7883,5 @@
                  *        to pass those options to the thread somehow and implement it in the
                  *        thread. Check if anyone uses/needs fAsync before implementing this. */
-                RTCpuSetAdd(&pDevExt->TscDeltaCpuSet, idCpu);
+                RTCpuSetAdd(&pDevExt->TscDeltaCpuSet, pGipCpuWorker->idCpu);
                 RTSpinlockAcquire(pDevExt->hTscDeltaSpinlock);
                 if (   pDevExt->enmTscDeltaState == kSupDrvTscDeltaState_Listening
@@ -7718,5 +7896,5 @@
 #endif
 
-            while (cTries--)
+            while (cTries-- > 0)
             {
                 rc = supdrvMeasureTscDeltaOne(pDevExt, iCpu);
@@ -7764,5 +7942,5 @@
     while (cTries-- > 0)
     {
-        rc = SUPReadTsc(&uTsc, &idApic);
+        rc = SUPGetTsc(&uTsc, &idApic);
         if (RT_SUCCESS(rc))
         {
@@ -7773,8 +7951,7 @@
         else
         {
+            /* If we failed to have a TSC-delta, measurement the TSC-delta and retry. */
             int rc2;
             uint16_t iCpu;
-
-            /* If we failed to have a delta, measurement the delta and retry. */
             AssertMsgReturn(idApic < RT_ELEMENTS(pGip->aiCpuFromApicId),
                             ("idApic=%u ArraySize=%u\n", idApic, RT_ELEMENTS(pGip->aiCpuFromApicId)), VERR_INVALID_CPU_INDEX);
@@ -7782,5 +7959,5 @@
             AssertMsgReturn(iCpu < pGip->cCpus, ("iCpu=%u cCpus=%u\n", iCpu, pGip->cCpus), VERR_INVALID_CPU_INDEX);
 
-            Assert(!g_fOsTscDeltasInSync);
+            Assert(GIP_ARE_TSC_DELTAS_APPLICABLE(pGip));
             rc2 = supdrvMeasureTscDeltaOne(pDevExt, iCpu);
             if (RT_SUCCESS(rc2))
Index: /trunk/src/VBox/HostDrivers/Support/SUPDrvInternal.h
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/SUPDrvInternal.h	(revision 53429)
+++ /trunk/src/VBox/HostDrivers/Support/SUPDrvInternal.h	(revision 53430)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2013 Oracle Corporation
+ * Copyright (C) 2006-2014 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -232,5 +232,6 @@
 
 #if 0
-/**  Use a dedicated kernel thread to service TSC-delta measurement requests. */
+/**  Use a dedicated kernel thread to service TSC-delta measurement requests.
+ *   @todo Test on servers with many CPUs and sockets. */
 #define SUPDRV_USE_TSC_DELTA_THREAD
 #endif
@@ -693,4 +694,6 @@
     /** The set of CPUs we need to take measurements for. */
     RTCPUSET                        TscDeltaCpuSet;
+    /** The set of CPUs we have completed taken measurements for. */
+    RTCPUSET                        TscDeltaObtainedCpuSet;
     /** Whether the TSC-delta measurement was successful. */
     int                             rcTscDelta;
Index: /trunk/src/VBox/HostDrivers/Support/testcase/tstGIP-2.cpp
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/testcase/tstGIP-2.cpp	(revision 53429)
+++ /trunk/src/VBox/HostDrivers/Support/testcase/tstGIP-2.cpp	(revision 53430)
@@ -39,4 +39,27 @@
 #include <iprt/initterm.h>
 #include <iprt/getopt.h>
+#include <iprt/x86.h>
+
+
+/**
+ * Checks whether the CPU advertises an invariant TSC or not.
+ *
+ * @returns true if invariant, false otherwise.
+ */
+bool tstIsInvariantTsc(void)
+{
+    if (ASMHasCpuId())
+    {
+        uint32_t uEax, uEbx, uEcx, uEdx;
+        ASMCpuId(0x80000000, &uEax, &uEbx, &uEcx, &uEdx);
+        if (uEax >= 0x80000007)
+        {
+            ASMCpuId(0x80000007, &uEax, &uEbx, &uEcx, &uEdx);
+            if (uEdx & X86_CPUID_AMD_ADVPOWER_EDX_TSCINVAR)
+                return true;
+        }
+    }
+    return false;
+}
 
 
@@ -64,4 +87,5 @@
     uint64_t uCpuHzRef = 0;
     uint64_t uCpuHzOverallDeviation = 0;
+    int64_t  iCpuHzMaxDeviation = 0;
     int32_t cCpuHzOverallDevCnt = 0;
     RTGETOPTUNION ValueUnion;
@@ -144,6 +168,9 @@
                             else
                             {
-                                if (pCpu->u32TransactionId > 7)
+                                /* Wait until the history validation code takes effect. */
+                                if (pCpu->u32TransactionId > 23 + (8 * 2) + 1)
                                 {
+                                    if (RT_ABS(iCpuHzDeviation) > RT_ABS(iCpuHzMaxDeviation))
+                                        iCpuHzMaxDeviation = iCpuHzDeviation;
                                     uCpuHzOverallDeviation += uCpuHzDeviation;
                                     cCpuHzOverallDevCnt++;
@@ -222,8 +249,12 @@
                     RTPrintf("tstGIP-2: offline: %lld\n", g_pSUPGlobalInfoPage->aCPUs[iCpu].i64TSCDelta);
 
-            if (uCpuHzRef)
+            RTPrintf("CPUID.Invariant-TSC    : %RTbool\n", tstIsInvariantTsc());
+            if (   uCpuHzRef
+                && cCpuHzOverallDevCnt)
             {
-                uint32_t uPct = (uint32_t)(uCpuHzOverallDeviation * 100000 / cCpuHzOverallDevCnt / uCpuHzRef + 5);
-                RTPrintf("tstGIP-2: Overall CpuHz deviation: %d.%02d%%\n", uPct / 1000, (uPct % 1000) / 10);
+                uint32_t uPct    = (uint32_t)(uCpuHzOverallDeviation * 100000 / cCpuHzOverallDevCnt / uCpuHzRef + 5);
+                uint32_t uMaxPct = (uint32_t)(RT_ABS(iCpuHzMaxDeviation) * 100000 / uCpuHzRef + 5);
+                RTPrintf("Average CpuHz deviation: %d.%02d%%\n", uPct / 1000, (uPct % 1000) / 10);
+                RTPrintf("Maximum CpuHz deviation: %d.%02d%% (%RI64 ticks)\n", uMaxPct / 1000, (uMaxPct % 1000) / 10, iCpuHzMaxDeviation);
             }
         }
@@ -240,2 +271,3 @@
     return !!rc;
 }
+
Index: /trunk/src/VBox/Runtime/common/time/timesup.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/time/timesup.cpp	(revision 53429)
+++ /trunk/src/VBox/Runtime/common/time/timesup.cpp	(revision 53430)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2011 Oracle Corporation
+ * Copyright (C) 2006-2014 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -124,5 +124,6 @@
     if (    pGip
         &&  pGip->u32Magic == SUPGLOBALINFOPAGE_MAGIC
-        &&  (   pGip->u32Mode == SUPGIPMODE_SYNC_TSC
+        &&  (   pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC
+             || pGip->u32Mode == SUPGIPMODE_SYNC_TSC
              || pGip->u32Mode == SUPGIPMODE_ASYNC_TSC))
         return rtTimeNanoTSInternalRediscover(pData);
@@ -146,13 +147,14 @@
     if (    pGip
         &&  pGip->u32Magic == SUPGLOBALINFOPAGE_MAGIC
-        &&  (   pGip->u32Mode == SUPGIPMODE_SYNC_TSC
+        &&  (   pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC
+             || pGip->u32Mode == SUPGIPMODE_SYNC_TSC
              || pGip->u32Mode == SUPGIPMODE_ASYNC_TSC))
     {
         if (ASMCpuId_EDX(1) & X86_CPUID_FEATURE_EDX_SSE2)
-            iWorker = pGip->u32Mode == SUPGIPMODE_SYNC_TSC
+            iWorker = pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC || pGip->u32Mode == SUPGIPMODE_SYNC_TSC
                     ? RTTIMENANO_WORKER_SYNC_LFENCE
                     : RTTIMENANO_WORKER_ASYNC_LFENCE;
         else
-            iWorker = pGip->u32Mode == SUPGIPMODE_SYNC_TSC
+            iWorker = pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC || pGip->u32Mode == SUPGIPMODE_SYNC_TSC
                     ? RTTIMENANO_WORKER_SYNC_CPUID
                     : RTTIMENANO_WORKER_ASYNC_CPUID;
Index: /trunk/src/VBox/Runtime/common/time/timesupA.mac
===================================================================
--- /trunk/src/VBox/Runtime/common/time/timesupA.mac	(revision 53429)
+++ /trunk/src/VBox/Runtime/common/time/timesupA.mac	(revision 53430)
@@ -5,5 +5,5 @@
 
 ;
-; Copyright (C) 2006-2011 Oracle Corporation
+; Copyright (C) 2006-2014 Oracle Corporation
 ;
 ; This file is part of VirtualBox Open Source Edition (OSE), as
@@ -126,4 +126,5 @@
     mov     u32UpdateIntervalTSC, edx
     rdtsc
+    SupTscDeltaApply edi        ; Apply inter-cpu TSC-delta to have the normalized TSC value in edx:eax
     mov     ecx, [edi + SUPGIPCPU.u64NanoTS]
     mov     u64CurNanoTS, ecx
@@ -544,4 +545,5 @@
     mov     u32UpdateIntervalTSC, [pGipCPU + SUPGIPCPU.u32UpdateIntervalTSC]
     rdtsc
+    SUPTscDeltaApply pGipCPU
     mov     u64PrevNanoTS,        [pData + RTTIMENANOTSDATA.pu64Prev]
     mov     u64PrevNanoTS,        [u64PrevNanoTS]
Index: /trunk/src/VBox/Runtime/common/time/timesupref.h
===================================================================
--- /trunk/src/VBox/Runtime/common/time/timesupref.h	(revision 53429)
+++ /trunk/src/VBox/Runtime/common/time/timesupref.h	(revision 53430)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2011 Oracle Corporation
+ * Copyright (C) 2006-2014 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
Index: /trunk/src/VBox/VMM/VMMAll/TMAllCpu.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/TMAllCpu.cpp	(revision 53429)
+++ /trunk/src/VBox/VMM/VMMAll/TMAllCpu.cpp	(revision 53430)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2012 Oracle Corporation
+ * Copyright (C) 2006-2014 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -64,14 +64,12 @@
     {
         pVCpu->tm.s.fTSCTicking = true;
-        if (pVM->tm.s.fTSCVirtualized)
-        {
-            /** @todo Test that pausing and resuming doesn't cause lag! (I.e. that we're
-             *        unpaused before the virtual time and stopped after it. */
-            if (pVM->tm.s.fTSCUseRealTSC)
-                pVCpu->tm.s.offTSCRawSrc = ASMReadTSC() - pVCpu->tm.s.u64TSC;
-            else
-                pVCpu->tm.s.offTSCRawSrc = tmCpuTickGetRawVirtual(pVM, false /* don't check for pending timers */)
-                                         - pVCpu->tm.s.u64TSC;
-        }
+
+        /** @todo Test that pausing and resuming doesn't cause lag! (I.e. that we're
+         *        unpaused before the virtual time and stopped after it. */
+        if (pVM->tm.s.enmMode == TMMODE_REAL_TSC_OFFSET)
+            pVCpu->tm.s.offTSCRawSrc = ASMReadTSC() - pVCpu->tm.s.u64TSC;
+        else
+            pVCpu->tm.s.offTSCRawSrc = tmCpuTickGetRawVirtual(pVM, false /* don't check for pending timers */)
+                                     - pVCpu->tm.s.u64TSC;
         return VINF_SUCCESS;
     }
@@ -94,30 +92,27 @@
         /* TSC must be ticking before calling tmCpuTickGetRawVirtual()! */
         pVCpu->tm.s.fTSCTicking = true;
-        if (pVM->tm.s.fTSCVirtualized)
-        {
-            uint32_t c = ASMAtomicIncU32(&pVM->tm.s.cTSCsTicking);
-            AssertMsgReturn(c <= pVM->cCpus, ("%u vs %u\n", c, pVM->cCpus), VERR_TM_VIRTUAL_TICKING_IPE);
-            if (c == 1)
-            {
-                /* The first VCPU to resume. */
-                uint64_t    offTSCRawSrcOld = pVCpu->tm.s.offTSCRawSrc;
-
-                STAM_COUNTER_INC(&pVM->tm.s.StatTSCResume);
-
-                /* When resuming, use the TSC value of the last stopped VCPU to avoid the TSC going back. */
-                if (pVM->tm.s.fTSCUseRealTSC)
-                    pVCpu->tm.s.offTSCRawSrc = ASMReadTSC() - pVM->tm.s.u64LastPausedTSC;
-                else
-                    pVCpu->tm.s.offTSCRawSrc = tmCpuTickGetRawVirtual(pVM, false /* don't check for pending timers */)
-                                             - pVM->tm.s.u64LastPausedTSC;
-
-                /* Calculate the offset for other VCPUs to use. */
-                pVM->tm.s.offTSCPause = pVCpu->tm.s.offTSCRawSrc - offTSCRawSrcOld;
-            }
+        uint32_t c = ASMAtomicIncU32(&pVM->tm.s.cTSCsTicking);
+        AssertMsgReturn(c <= pVM->cCpus, ("%u vs %u\n", c, pVM->cCpus), VERR_TM_VIRTUAL_TICKING_IPE);
+        if (c == 1)
+        {
+            /* The first VCPU to resume. */
+            uint64_t    offTSCRawSrcOld = pVCpu->tm.s.offTSCRawSrc;
+
+            STAM_COUNTER_INC(&pVM->tm.s.StatTSCResume);
+
+            /* When resuming, use the TSC value of the last stopped VCPU to avoid the TSC going back. */
+            if (pVM->tm.s.enmMode == TMMODE_REAL_TSC_OFFSET)
+                pVCpu->tm.s.offTSCRawSrc = ASMReadTSC() - pVM->tm.s.u64LastPausedTSC;
             else
-            {
-                /* All other VCPUs (if any). */
-                pVCpu->tm.s.offTSCRawSrc += pVM->tm.s.offTSCPause;
-            }
+                pVCpu->tm.s.offTSCRawSrc = tmCpuTickGetRawVirtual(pVM, false /* don't check for pending timers */)
+                                         - pVM->tm.s.u64LastPausedTSC;
+
+            /* Calculate the offset for other VCPUs to use. */
+            pVM->tm.s.offTSCPause = pVCpu->tm.s.offTSCRawSrc - offTSCRawSrcOld;
+        }
+        else
+        {
+            /* All other VCPUs (if any). */
+            pVCpu->tm.s.offTSCRawSrc += pVM->tm.s.offTSCPause;
         }
     }
@@ -187,9 +182,9 @@
 {
     /* Sample the reason for refusing. */
-    if (!pVM->tm.s.fMaybeUseOffsettedHostTSC)
+    if (pVM->tm.s.enmMode != TMMODE_DYNAMIC)
        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)
+    else if (pVM->tm.s.enmMode != TMMODE_REAL_TSC_OFFSET)
     {
         if (pVM->tm.s.fVirtualSyncCatchUp)
@@ -240,16 +235,14 @@
      */
     *pfParavirtTsc = GIMIsParavirtTscEnabled(pVM);
-    if (    pVM->tm.s.fMaybeUseOffsettedHostTSC
+    if (    pVM->tm.s.enmMode == TMMODE_DYNAMIC
         &&  RT_LIKELY(pVCpu->tm.s.fTSCTicking)
-        &&  (   pVM->tm.s.fTSCUseRealTSC
+        &&  (   pVM->tm.s.enmMode == TMMODE_REAL_TSC_OFFSET
              || (   !pVM->tm.s.fVirtualSyncCatchUp
                  && RT_LIKELY(pVM->tm.s.fVirtualSyncTicking)
                  && !pVM->tm.s.fVirtualWarpDrive)))
     {
-        if (!pVM->tm.s.fTSCUseRealTSC)
+        if (pVM->tm.s.enmMode != TMMODE_REAL_TSC_OFFSET)
         {
             /* The source is the timer synchronous virtual clock. */
-            Assert(pVM->tm.s.fTSCVirtualized);
-
             if (poffRealTSC)
             {
@@ -266,8 +259,5 @@
         {
             /* The source is the real TSC. */
-            if (pVM->tm.s.fTSCVirtualized)
-                *poffRealTSC = 0 - pVCpu->tm.s.offTSCRawSrc;
-            else
-                *poffRealTSC = 0;
+            *poffRealTSC = 0 - pVCpu->tm.s.offTSCRawSrc;
         }
         /** @todo count this? */
@@ -339,7 +329,7 @@
      */
     *pfParavirtTsc = GIMIsParavirtTscEnabled(pVM);
-    if (    pVM->tm.s.fMaybeUseOffsettedHostTSC
+    if (    pVM->tm.s.enmMode == TMMODE_DYNAMIC
         &&  RT_LIKELY(pVCpu->tm.s.fTSCTicking)
-        &&  (   pVM->tm.s.fTSCUseRealTSC
+        &&  (   pVM->tm.s.enmMode == TMMODE_REAL_TSC_OFFSET
              || (   !pVM->tm.s.fVirtualSyncCatchUp
                  && RT_LIKELY(pVM->tm.s.fVirtualSyncTicking)
@@ -347,9 +337,7 @@
     {
         *pfOffsettedTsc = true;
-        if (!pVM->tm.s.fTSCUseRealTSC)
+        if (pVM->tm.s.enmMode != TMMODE_REAL_TSC_OFFSET)
         {
             /* The source is the timer synchronous virtual clock. */
-            Assert(pVM->tm.s.fTSCVirtualized);
-
             uint64_t cNsToDeadline;
             uint64_t u64NowVirtSync = TMVirtualSyncGetWithDeadlineNoCheck(pVM, &cNsToDeadline);
@@ -364,8 +352,5 @@
         {
             /* The source is the real TSC. */
-            if (pVM->tm.s.fTSCVirtualized)
-                *poffRealTSC = 0 - pVCpu->tm.s.offTSCRawSrc;
-            else
-                *poffRealTSC = 0;
+            *poffRealTSC = 0 - pVCpu->tm.s.offTSCRawSrc;
             cTicksToDeadline = tmCpuCalcTicksToDeadline(TMVirtualSyncGetNsToDeadline(pVM));
         }
@@ -398,14 +383,9 @@
     {
         PVM pVM = pVCpu->CTX_SUFF(pVM);
-        if (pVM->tm.s.fTSCVirtualized)
-        {
-            if (pVM->tm.s.fTSCUseRealTSC)
-                u64 = ASMReadTSC();
-            else
-                u64 = tmCpuTickGetRawVirtual(pVM, fCheckTimers);
-            u64 -= pVCpu->tm.s.offTSCRawSrc;
-        }
+        if (pVM->tm.s.enmMode == TMMODE_REAL_TSC_OFFSET)
+            u64 = ASMReadTSC();
         else
-            u64 = ASMReadTSC();
+            u64 = tmCpuTickGetRawVirtual(pVM, fCheckTimers);
+        u64 -= pVCpu->tm.s.offTSCRawSrc;
 
         /* Always return a value higher than what the guest has already seen. */
@@ -523,5 +503,7 @@
 VMMDECL(uint64_t) TMCpuTicksPerSecond(PVM pVM)
 {
-    if (pVM->tm.s.fTSCUseRealTSC)
+    /** @todo revisit this, not sure why we need to get the rate from GIP for
+     *        real-tsc-offset. */
+    if (pVM->tm.s.enmMode == TMMODE_REAL_TSC_OFFSET)
     {
         uint64_t cTSCTicksPerSecond = SUPGetCpuHzFromGIP(g_pSUPGlobalInfoPage);
Index: /trunk/src/VBox/VMM/VMMR3/TM.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/TM.cpp	(revision 53429)
+++ /trunk/src/VBox/VMM/VMMR3/TM.cpp	(revision 53430)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2013 Oracle Corporation
+ * Copyright (C) 2006-2014 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -167,4 +167,5 @@
 *******************************************************************************/
 static bool                 tmR3HasFixedTSC(PVM pVM);
+static const char *         tmR3GetModeName(PVM pVM);
 static uint64_t             tmR3CalibrateTSC(PVM pVM);
 static DECLCALLBACK(int)    tmR3Save(PVM pVM, PSSMHANDLE pSSM);
@@ -271,5 +272,6 @@
     if (ASMCpuId_EDX(1) & X86_CPUID_FEATURE_EDX_SSE2)
     {
-        if (g_pSUPGlobalInfoPage->u32Mode == SUPGIPMODE_SYNC_TSC)
+        if (   g_pSUPGlobalInfoPage->u32Mode == SUPGIPMODE_INVARIANT_TSC
+            || g_pSUPGlobalInfoPage->u32Mode == SUPGIPMODE_SYNC_TSC)
             pVM->tm.s.pfnVirtualGetRawR3 = RTTimeNanoTSLFenceSync;
         else
@@ -278,5 +280,6 @@
     else
     {
-        if (g_pSUPGlobalInfoPage->u32Mode == SUPGIPMODE_SYNC_TSC)
+        if (   g_pSUPGlobalInfoPage->u32Mode == SUPGIPMODE_INVARIANT_TSC
+            || g_pSUPGlobalInfoPage->u32Mode == SUPGIPMODE_SYNC_TSC)
             pVM->tm.s.pfnVirtualGetRawR3 = RTTimeNanoTSLegacySync;
         else
@@ -310,54 +313,91 @@
 
     /*
+     * Handle deprecated TM settings.
+     */
+    do
+    {
+        /** @todo make these runtime warnings instead of errors that refuse to start
+         *        the VM? */
+        bool fTSCVirtualized;
+        rc = CFGMR3QueryBool(pCfgHandle, "TSCVirtualized", &fTSCVirtualized);
+        if (RT_SUCCESS(rc))
+            return VMSetError(pVM, VERR_CFGM_CONFIG_UNKNOWN_VALUE, RT_SRC_POS,
+                              N_("Configuration error: TM setting \"TSCVirtualized\" is no longer supported. Use the \"Mode\" setting instead."));
+
+        bool fForceUseRealTSC;
+        rc = CFGMR3QueryBool(pCfgHandle, "UseRealTSC", &fForceUseRealTSC);
+        if (RT_SUCCESS(rc))
+            return VMSetError(pVM, VERR_CFGM_CONFIG_UNKNOWN_VALUE, RT_SRC_POS,
+                              N_("Configuration error: TM setting \"UseRealTSC\" is no longer supported. Use the \"Mode\" setting instead."));
+
+        bool fMaybeUseOffsettedHostTSC;
+        rc = CFGMR3QueryBool(pCfgHandle, "MaybeUseOffsettedHostTSC", &fMaybeUseOffsettedHostTSC);
+        if (RT_SUCCESS(rc))
+            return VMSetError(pVM, VERR_CFGM_CONFIG_UNKNOWN_VALUE, RT_SRC_POS,
+                              N_("Configuration error: TM setting \"MaybeUseOffsettedHostTSC\" is no longer supported. Use the \"Mode\" setting instead."));
+    } while(0);
+
+    /*
+     * Validate the rest of the TM settings.
+     */
+    if (!CFGMR3AreValuesValid(pCfgHandle,
+                              "Mode\0"
+                              "TSCTicksPerSecond\0"
+                              "TSCTiedToExecution\0"
+                              "TSCNotTiedToHalt\0"
+                              "ScheduleSlack\0"
+                              "CatchUpStopThreshold\0"
+                              "CatchUpGiveUpThreshold\0"
+                              "CatchUpStartThreshold\0"
+                              "CatchUpPrecentage\0"
+                              "UTCOffset\0"
+                              "WarpDrivePercentage\0"
+                              "HostHzMax\0"
+                              "HostHzFudgeFactorTimerCpu\0"
+                              "HostHzFudgeFactorOtherCpu\0"
+                              "HostHzFudgeFactorCatchUp100\0"
+                              "HostHzFudgeFactorCatchUp200\0"
+                              "HostHzFudgeFactorCatchUp400\0"
+                              "TimerMillies\0"
+                              ))
+        return VMSetError(pVM, VERR_CFGM_CONFIG_UNKNOWN_NODE, RT_SRC_POS, N_("Configuration error: Invalid config key for TM."));
+
+    /*
      * Determine the TSC configuration and frequency.
      */
-    /* mode */
-    /** @cfgm{/TM/TSCVirtualized,bool,true}
-     * Use a virtualize TSC, i.e. trap all TSC access. */
-    rc = CFGMR3QueryBool(pCfgHandle, "TSCVirtualized", &pVM->tm.s.fTSCVirtualized);
+    /** @cfgm{/TM/Mode, string}
+     *  The name of the time-keeping mode. The default is picked dynamically based
+     *  on configuration of the VM. */
+    char szMode[32];
+    rc = CFGMR3QueryString(pCfgHandle, "Mode", szMode, sizeof(szMode));
     if (rc == VERR_CFGM_VALUE_NOT_FOUND)
-        pVM->tm.s.fTSCVirtualized = true; /* trap rdtsc */
+        pVM->tm.s.enmMode = tmR3HasFixedTSC(pVM) ? TMMODE_DYNAMIC : TMMODE_VIRT_TSC_EMULATED;
     else if (RT_FAILURE(rc))
-        return VMSetError(pVM, rc, RT_SRC_POS,
-                          N_("Configuration error: Failed to querying bool value \"UseRealTSC\""));
-
-    /* source */
-    /** @cfgm{/TM/UseRealTSC,bool,false}
-     * Use the real TSC as time source for the TSC instead of the synchronous
-     * virtual clock (false, default). */
-    rc = CFGMR3QueryBool(pCfgHandle, "UseRealTSC", &pVM->tm.s.fTSCUseRealTSC);
-    if (rc == VERR_CFGM_VALUE_NOT_FOUND)
-        pVM->tm.s.fTSCUseRealTSC = false; /* use virtual time */
-    else if (RT_FAILURE(rc))
-        return VMSetError(pVM, rc, RT_SRC_POS,
-                          N_("Configuration error: Failed to querying bool value \"UseRealTSC\""));
-    if (!pVM->tm.s.fTSCUseRealTSC)
-        pVM->tm.s.fTSCVirtualized = true;
-
-    /* TSC reliability */
-    /** @cfgm{/TM/MaybeUseOffsettedHostTSC,bool,detect}
-     * Whether the CPU has a fixed TSC rate and may be used in offsetted mode with
-     * VT-x/AMD-V execution.  This is autodetected in a very restrictive way by
-     * default. */
-    rc = CFGMR3QueryBool(pCfgHandle, "MaybeUseOffsettedHostTSC", &pVM->tm.s.fMaybeUseOffsettedHostTSC);
-    if (rc == VERR_CFGM_VALUE_NOT_FOUND)
-    {
-        if (!pVM->tm.s.fTSCUseRealTSC)
-            pVM->tm.s.fMaybeUseOffsettedHostTSC = tmR3HasFixedTSC(pVM);
+        return VMSetError(pVM, rc, RT_SRC_POS, N_("Configuration error: Failed to querying string value \"Mode\""));
+    else
+    {
+        AssertRC(rc);
+        if (!RTStrCmp(szMode, "VirtTSCEmulated"))
+            pVM->tm.s.enmMode = TMMODE_VIRT_TSC_EMULATED;
+        else if (!RTStrCmp(szMode, "RealTSCOffset"))
+            pVM->tm.s.enmMode = TMMODE_REAL_TSC_OFFSET;
+        else if (!RTStrCmp(szMode, "Dynamic"))
+            pVM->tm.s.enmMode = TMMODE_DYNAMIC;
         else
-            pVM->tm.s.fMaybeUseOffsettedHostTSC = true;
-        /** @todo needs a better fix, for now disable offsetted mode for VMs
-         * with more than one VCPU. With the current TSC handling (frequent
-         * switching between offsetted mode and taking VM exits, on all VCPUs
-         * without any kind of coordination) it will lead to inconsistent TSC
-         * behavior with guest SMP, including TSC going backwards. */
-        if (   pVM->cCpus != 1
-            && !pVM->tm.s.fTSCUseRealTSC)
-            pVM->tm.s.fMaybeUseOffsettedHostTSC = false;
-    }
+            return VMSetError(pVM, rc, RT_SRC_POS, N_("Configuration error: Unrecognized TM mode value \"%s\""), szMode);
+    }
+
+    /** @todo needs a better fix, for now disable offsetted mode for VMs
+     * with more than one VCPU. With the current TSC handling (frequent
+     * switching between offsetted mode and taking VM exits, on all VCPUs
+     * without any kind of coordination) it will lead to inconsistent TSC
+     * behavior with guest SMP, including TSC going backwards. */
+    if (   pVM->cCpus != 1
+        && pVM->tm.s.enmMode != TMMODE_REAL_TSC_OFFSET)
+        pVM->tm.s.enmMode = TMMODE_VIRT_TSC_EMULATED;
 
     /** @cfgm{/TM/TSCTicksPerSecond, uint32_t, Current TSC frequency from GIP}
      * The number of TSC ticks per second (i.e. the TSC frequency). This will
-     * override TSCUseRealTSC, TSCVirtualized and MaybeUseOffsettedHostTSC.
+     * override TSCtTSC, TSCVirtualized and MaybeUseOffsettedHostTSC.
      */
     rc = CFGMR3QueryU64(pCfgHandle, "TSCTicksPerSecond", &pVM->tm.s.cTSCTicksPerSecond);
@@ -365,9 +405,9 @@
     {
         pVM->tm.s.cTSCTicksPerSecond = tmR3CalibrateTSC(pVM);
-        if (    !pVM->tm.s.fTSCUseRealTSC
-            &&  pVM->tm.s.cTSCTicksPerSecond >= _4G)
+        if (   pVM->tm.s.enmMode != TMMODE_REAL_TSC_OFFSET
+            && pVM->tm.s.cTSCTicksPerSecond >= _4G)
         {
             pVM->tm.s.cTSCTicksPerSecond = _4G - 1; /* (A limitation of our math code) */
-            pVM->tm.s.fMaybeUseOffsettedHostTSC = false;
+            pVM->tm.s.enmMode = TMMODE_VIRT_TSC_EMULATED;
         }
     }
@@ -382,6 +422,5 @@
     else
     {
-        pVM->tm.s.fTSCUseRealTSC = pVM->tm.s.fMaybeUseOffsettedHostTSC = false;
-        pVM->tm.s.fTSCVirtualized = true;
+        pVM->tm.s.enmMode = TMMODE_VIRT_TSC_EMULATED;
     }
 
@@ -398,10 +437,5 @@
                           N_("Configuration error: Failed to querying bool value \"TSCTiedToExecution\""));
     if (pVM->tm.s.fTSCTiedToExecution)
-    {
-        /* tied to execution, override all other settings. */
-        pVM->tm.s.fTSCVirtualized = true;
-        pVM->tm.s.fTSCUseRealTSC = true;
-        pVM->tm.s.fMaybeUseOffsettedHostTSC = false;
-    }
+        pVM->tm.s.enmMode = TMMODE_VIRT_TSC_EMULATED;
 
     /** @cfgm{/TM/TSCNotTiedToHalt, bool, true}
@@ -412,14 +446,4 @@
         return VMSetError(pVM, rc, RT_SRC_POS,
                           N_("Configuration error: Failed to querying bool value \"TSCNotTiedToHalt\""));
-
-    /* setup and report */
-    if (pVM->tm.s.fTSCVirtualized)
-        CPUMR3SetCR4Feature(pVM, X86_CR4_TSD, ~X86_CR4_TSD);
-    else
-        CPUMR3SetCR4Feature(pVM, 0, ~X86_CR4_TSD);
-    LogRel(("TM: cTSCTicksPerSecond=%#RX64 (%'RU64) fTSCVirtualized=%RTbool fTSCUseRealTSC=%RTbool\n"
-            "TM: fMaybeUseOffsettedHostTSC=%RTbool TSCTiedToExecution=%RTbool TSCNotTiedToHalt=%RTbool\n",
-            pVM->tm.s.cTSCTicksPerSecond, pVM->tm.s.cTSCTicksPerSecond, pVM->tm.s.fTSCVirtualized, pVM->tm.s.fTSCUseRealTSC,
-            pVM->tm.s.fMaybeUseOffsettedHostTSC, pVM->tm.s.fTSCTiedToExecution, pVM->tm.s.fTSCNotTiedToHalt));
 
     /*
@@ -525,5 +549,15 @@
     pVM->tm.s.fVirtualWarpDrive = pVM->tm.s.u32VirtualWarpDrivePercentage != 100;
     if (pVM->tm.s.fVirtualWarpDrive)
-        LogRel(("TM: u32VirtualWarpDrivePercentage=%RI32\n", pVM->tm.s.u32VirtualWarpDrivePercentage));
+    {
+        pVM->tm.s.enmMode = TMMODE_VIRT_TSC_EMULATED;
+        LogRel(("TM: Warp-drive active. u32VirtualWarpDrivePercentage=%RI32\n", pVM->tm.s.u32VirtualWarpDrivePercentage));
+    }
+
+    /* Setup and report */
+    CPUMR3SetCR4Feature(pVM, X86_CR4_TSD, ~X86_CR4_TSD);
+    LogRel(("TM: cTSCTicksPerSecond=%#RX64 (%'RU64) enmMode=%d (%s)\n"
+            "TM: TSCTiedToExecution=%RTbool TSCNotTiedToHalt=%RTbool\n",
+            pVM->tm.s.cTSCTicksPerSecond, pVM->tm.s.cTSCTicksPerSecond, pVM->tm.s.enmMode, tmR3GetModeName(pVM),
+            pVM->tm.s.fTSCTiedToExecution, pVM->tm.s.fTSCNotTiedToHalt));
 
     /*
@@ -776,4 +810,8 @@
 static bool tmR3HasFixedTSC(PVM pVM)
 {
+    PSUPGLOBALINFOPAGE pGip = g_pSUPGlobalInfoPage;
+    if (pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC)
+        return true;
+
     if (ASMHasCpuId())
     {
@@ -782,4 +820,6 @@
         if (CPUMGetHostCpuVendor(pVM) == CPUMCPUVENDOR_AMD)
         {
+            /** @todo This is redundant as it would get satisified in the invariant case
+             *        above. Remove later or keep around for sync mode override?  */
             /*
              * AuthenticAMD - Check for APM support and that TscInvariant is set.
@@ -792,9 +832,8 @@
             if (uEAX >= 0x80000007)
             {
-                PSUPGLOBALINFOPAGE pGip = g_pSUPGlobalInfoPage;
-
                 ASMCpuId(0x80000007, &uEAX, &uEBX, &uECX, &uEDX);
                 if (   (uEDX & X86_CPUID_AMD_ADVPOWER_EDX_TSCINVAR) /* TscInvariant */
-                    && pGip->u32Mode == SUPGIPMODE_SYNC_TSC /* no fixed tsc if the gip timer is in async mode */)
+                    && (   pGip->u32Mode == SUPGIPMODE_SYNC_TSC     /* No fixed tsc if the gip timer is in async mode. */
+                        || pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC))
                     return true;
             }
@@ -852,7 +891,13 @@
 {
     /*
-     * Use GIP when available present.
+     * Use GIP when available.
      */
     uint64_t u64Hz = SUPGetCpuHzFromGIP(g_pSUPGlobalInfoPage);
+    if (g_pSUPGlobalInfoPage->u32Mode == SUPGIPMODE_INVARIANT_TSC)
+    {
+        Assert(u64Hz != UINT64_MAX);
+        return u64Hz;
+    }
+
     if (u64Hz != UINT64_MAX)
     {
@@ -864,5 +909,5 @@
             /* Spin for 40ms to try push up the CPU frequency and get a more reliable CpuHz value. */
             const uint64_t u64 = RTTimeMilliTS();
-            while ((RTTimeMilliTS() - u64) < 40 /*ms*/)
+            while ((RTTimeMilliTS() - u64) < 40 /* ms */)
                 /* nothing */;
         }
@@ -873,5 +918,5 @@
     }
 
-    /* call this once first to make sure it's initialized. */
+    /* Call this once first to make sure it's initialized. */
     RTTimeNanoTS();
 
@@ -1278,5 +1323,5 @@
             pVM->tm.s.u64LastPausedTSC = pVCpu->tm.s.u64TSC;
 
-        if (pVM->tm.s.fTSCUseRealTSC)
+        if (pVM->tm.s.enmMode == TMMODE_REAL_TSC_OFFSET)
             pVCpu->tm.s.offTSCRawSrc = 0; /** @todo TSC restore stuff and HWACC. */
     }
@@ -1285,9 +1330,11 @@
     if (RT_FAILURE(rc))
         return rc;
-    if (!pVM->tm.s.fTSCUseRealTSC)
+    if (pVM->tm.s.enmMode != TMMODE_REAL_TSC_OFFSET)
         pVM->tm.s.cTSCTicksPerSecond = u64Hz;
-
-    LogRel(("TM: cTSCTicksPerSecond=%#RX64 (%'RU64) fTSCVirtualized=%RTbool fTSCUseRealTSC=%RTbool (state load)\n",
-            pVM->tm.s.cTSCTicksPerSecond, pVM->tm.s.cTSCTicksPerSecond, pVM->tm.s.fTSCVirtualized, pVM->tm.s.fTSCUseRealTSC));
+    /** @todo Compare with real TSC rate even when restoring with real-tsc-offset
+     *        mode. */
+
+    LogRel(("TM: cTSCTicksPerSecond=%#RX64 (%'RU64) enmMode=%d (%s) (state load)\n",
+            pVM->tm.s.cTSCTicksPerSecond, pVM->tm.s.cTSCTicksPerSecond, pVM->tm.s.enmMode, tmR3GetModeName(pVM)));
 
     /*
@@ -2803,4 +2850,6 @@
         TMR3NotifySuspend(pVM, pVCpu);
 
+    /** @todo should probably switch TM mode to virt-tsc-emulated if it isn't
+     *        already. */
     pVM->tm.s.u32VirtualWarpDrivePercentage = u32Percent;
     pVM->tm.s.fVirtualWarpDrive = u32Percent != 100;
@@ -3148,11 +3197,10 @@
          */
         pHlp->pfnPrintf(pHlp,
-                        "Cpu Tick: %18RU64 (%#016RX64) %RU64Hz %s%s",
+                        "Cpu Tick: %18RU64 (%#016RX64) %RU64Hz %s - virtualized",
                         u64TSC, u64TSC, TMCpuTicksPerSecond(pVM),
-                        pVCpu->tm.s.fTSCTicking ? "ticking" : "paused",
-                        pVM->tm.s.fTSCVirtualized ? " - virtualized" : "");
-        if (pVM->tm.s.fTSCUseRealTSC)
+                        pVCpu->tm.s.fTSCTicking ? "ticking" : "paused");
+        if (pVM->tm.s.enmMode == TMMODE_REAL_TSC_OFFSET)
         {
-            pHlp->pfnPrintf(pHlp, " - real tsc");
+            pHlp->pfnPrintf(pHlp, " - real tsc offset");
             if (pVCpu->tm.s.offTSCRawSrc)
                 pHlp->pfnPrintf(pHlp, "\n          offset %RU64", pVCpu->tm.s.offTSCRawSrc);
@@ -3198,2 +3246,21 @@
 }
 
+
+/**
+ * Gets the descriptive TM mode name.
+ *
+ * @returns The name.
+ * @param   pVM      Pointer to the VM.
+ */
+static const char * tmR3GetModeName(PVM pVM)
+{
+    Assert(pVM);
+    switch (pVM->tm.s.enmMode)
+    {
+        case TMMODE_REAL_TSC_OFFSET:    return "RealTscOffset";
+        case TMMODE_VIRT_TSC_EMULATED:  return "VirtTscEmulated";
+        case TMMODE_DYNAMIC:            return "Dynamic";
+        default:                        return "?????";
+    }
+}
+
Index: /trunk/src/VBox/VMM/include/TMInternal.h
===================================================================
--- /trunk/src/VBox/VMM/include/TMInternal.h	(revision 53429)
+++ /trunk/src/VBox/VMM/include/TMInternal.h	(revision 53430)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2012 Oracle Corporation
+ * Copyright (C) 2006-2014 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -316,4 +316,20 @@
 typedef TMCPULOADSTATE *PTMCPULOADSTATE;
 
+
+/**
+ * TM mode.
+ * The main modes of how TM abstracts time.
+ */
+typedef enum TMMODE
+{
+    /** The guest TSC is an emulated virtual TSC. */
+    TMMODE_VIRT_TSC_EMULATED = 1,
+    /** The guest TSC is an offset of the real TSC. */
+    TMMODE_REAL_TSC_OFFSET,
+    /** The guest TSC is dynamically derived through emulation or offsetting. */
+    TMMODE_DYNAMIC
+} TMMODE;
+
+
 /**
  * Converts a TM pointer into a VM pointer.
@@ -334,15 +350,7 @@
     RTUINT                      offVM;
 
-    /** Set if we fully virtualize the TSC, i.e. intercept all rdtsc instructions.
-     * Config variable: TSCVirtualized (bool) */
-    bool                        fTSCVirtualized;
-    /** Set if we use the real TSC as time source or if we use the virtual clock.
-     * If fTSCVirtualized is set we maintain a offset to the TSC and pausing/resuming the
-     * ticking. fTSCVirtualized = false implies fTSCUseRealTSC = true.
-     * Config variable: TSCUseRealTSC (bool) */
-    bool                        fTSCUseRealTSC;
-    /** Flag indicating that the host TSC is suitable for use in AMD-V and VT-x mode.
-     * Config variable: MaybeUseOffsettedHostTSC (boolean) */
-    bool                        fMaybeUseOffsettedHostTSC;
+    /** The current timekeeping mode of the VM.
+     *  Config variable: Mode (string) */
+    TMMODE                      enmMode;
     /** Whether the TSC is tied to the execution of code.
      * Config variable: TSCTiedToExecution (bool) */
@@ -351,5 +359,6 @@
      * Config variable: TSCNotTiedToHalt (bool) */
     bool                        fTSCNotTiedToHalt;
-    bool                        afAlignment0[2]; /**< alignment padding */
+    /** Alignment. */
+    bool                        afAlignment0[2];
     /** The ID of the virtual CPU that normally runs the timers. */
     VMCPUID                     idTimerCpu;
@@ -357,5 +366,6 @@
     /** The number of CPU clock ticks per second (TMCLOCK_TSC).
      * Config variable: TSCTicksPerSecond (64-bit unsigned int)
-     * The config variable implies fTSCVirtualized = true and fTSCUseRealTSC = false. */
+     * The config variable implies @c enmMode would be
+     * TMMODE_VIRT_TSC_EMULATED. */
     uint64_t                    cTSCTicksPerSecond;
     /** The TSC difference introduced by pausing the VM. */
@@ -374,5 +384,6 @@
     /** Virtual timer synchronous time catch-up active. */
     bool volatile               fVirtualSyncCatchUp;
-    bool                        afAlignment1[1]; /**< alignment padding */
+    /** Alignment. */
+    bool                        afAlignment1[1];
     /** WarpDrive percentage.
      * 100% is normal (fVirtualSyncNormal == true). When other than 100% we apply
@@ -781,5 +792,4 @@
     Assert(PDMCritSectIsOwner(&(a_pVM)->tm.s.TimerCritSect))
 
-
 /** @} */
 
Index: /trunk/src/VBox/VMM/testcase/tstVMStruct.h
===================================================================
--- /trunk/src/VBox/VMM/testcase/tstVMStruct.h	(revision 53429)
+++ /trunk/src/VBox/VMM/testcase/tstVMStruct.h	(revision 53430)
@@ -8,5 +8,5 @@
 
 /*
- * Copyright (C) 2006-2013 Oracle Corporation
+ * Copyright (C) 2006-2014 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -1011,5 +1011,5 @@
     GEN_CHECK_OFF(TM, pvGIPRC);
     GEN_CHECK_OFF(TMCPU, fTSCTicking);
-    GEN_CHECK_OFF(TM, fTSCUseRealTSC);
+    GEN_CHECK_OFF(TM, enmMode);
     GEN_CHECK_OFF(TM, fTSCTiedToExecution);
     GEN_CHECK_OFF(TMCPU, offTSCRawSrc);
