VirtualBox

Changeset 53430 in vbox for trunk


Ignore:
Timestamp:
Dec 3, 2014 1:18:41 PM (10 years ago)
Author:
vboxsync
Message:

VMM/TM: First step in introducing the invariant TM mode.

Location:
trunk
Files:
12 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/sup.h

    r53269 r53430  
    44
    55/*
    6  * Copyright (C) 2006-2012 Oracle Corporation
     6 * Copyright (C) 2006-2014 Oracle Corporation
    77 *
    88 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    339339     * This is index by ApicId via the aiCpuFromApicId table.
    340340     *
    341      * The clock and frequency information is updated for all CPUs if u32Mode
    342      * is SUPGIPMODE_ASYNC_TSC, otherwise (SUPGIPMODE_SYNC_TSC) only the first
    343      * entry is updated. */
     341     * The clock and frequency information is updated for all CPUs if @c u32Mode
     342     * is SUPGIPMODE_ASYNC_TSC. If @c u32Mode is SUPGIPMODE_SYNC_TSC only the first
     343     * entry is updated. If @c u32Mode is SUPGIPMODE_SYNC_TSC the TSC frequency in
     344     * @c u64CpuHz is copied to all CPUs. */
    344345    SUPGIPCPU           aCPUs[1];
    345346} SUPGLOBALINFOPAGE;
     
    374375    /** Each core has it's own TSC. */
    375376    SUPGIPMODE_ASYNC_TSC,
     377    /** The TSC of the cores are non-stop and have a constant frequency. */
     378    SUPGIPMODE_INVARIANT_TSC,
    376379    /** The usual 32-bit hack. */
    377380    SUPGIPMODE_32BIT_HACK = 0x7fffffff
     
    424427SUPDECL(PSUPGLOBALINFOPAGE)             SUPGetGIP(void);
    425428
    426 #ifdef ___iprt_asm_amd64_x86_h
     429
    427430/**
    428431 * Gets the TSC frequency of the calling CPU.
     
    435438    unsigned iCpu;
    436439
    437     if (RT_UNLIKELY(!pGip || pGip->u32Magic != SUPGLOBALINFOPAGE_MAGIC))
     440    if (RT_UNLIKELY(!pGip || pGip->u32Magic != SUPGLOBALINFOPAGE_MAGIC || !pGip->u64CpuHz))
    438441        return UINT64_MAX;
    439442
    440     if (pGip->u32Mode != SUPGIPMODE_ASYNC_TSC)
     443    if (   pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC
     444        || pGip->u32Mode == SUPGIPMODE_SYNC_TSC)
    441445        iCpu = 0;
    442446    else
    443447    {
     448        Assert(pGip->u32Mode == SUPGIPMODE_ASYNC_TSC);
    444449        iCpu = pGip->aiCpuFromApicId[ASMGetApicId()];
    445450        if (iCpu >= pGip->cCpus)
     
    449454    return pGip->aCPUs[iCpu].u64CpuHz;
    450455}
    451 #endif
     456
    452457
    453458/**
     
    14681473
    14691474/**
    1470  * Gets the GIP mode name given the GIP mode.
    1471  *
    1472  * @returns The name
    1473  * @param   enmGipMode      The GIP mode.
     1475 * Gets the descriptive GIP mode name.
     1476 *
     1477 * @returns The name.
     1478 * @param   pGip      Pointer to the GIP.
    14741479 */
    14751480DECLINLINE(const char *) SUPGetGIPModeName(PSUPGLOBALINFOPAGE pGip)
    14761481{
    1477     Assert(pGip);
     1482    AssertReturn(pGip, NULL);
    14781483    switch (pGip->u32Mode)
    14791484    {
    1480         /* case SUPGIPMODE_INVARIANT_TSC:  return "Invariant"; */
    1481         case SUPGIPMODE_SYNC_TSC:       return "Synchronous";
    1482         case SUPGIPMODE_ASYNC_TSC:      return "Asynchronous";
    1483         case SUPGIPMODE_INVALID:        return "Invalid";
    1484         default:                        return "???";
     1485        case SUPGIPMODE_INVARIANT_TSC: return "Invariant";
     1486        case SUPGIPMODE_SYNC_TSC:      return "Synchronous";
     1487        case SUPGIPMODE_ASYNC_TSC:     return "Asynchronous";
     1488        case SUPGIPMODE_INVALID:       return "Invalid";
     1489        default:                       return "???";
    14851490    }
    14861491}
     
    14971502    PSUPGLOBALINFOPAGE pGip = g_pSUPGlobalInfoPage;
    14981503    if (   pGip
    1499         && pGip->u32Mode == SUPGIPMODE_SYNC_TSC)   /** @todo use INVARIANT_TSC */
     1504        && pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC)
    15001505    {
    15011506        uint64_t uLo;
     
    15061511
    15071512        /* Arbitrary tolerance threshold, tweak later if required, perhaps
    1508            more tolerance on higher frequencies and less tolerance on lower. */
     1513           more tolerance on lower frequencies and less tolerance on higher. */
    15091514        uLo = (pGip->u64CpuHz << 10) / 1025;
    15101515        uHi = pGip->u64CpuHz + (pGip->u64CpuHz - uLo);
    15111516        if (   u64CpuHz < uLo
    15121517            || u64CpuHz > uHi)
    1513         {
    15141518            return false;
    1515         }
    15161519        return true;
    15171520    }
    15181521    return false;
    15191522}
    1520 
    15211523
    15221524
     
    15311533 *                          applied or not (optional, can be NULL).
    15321534 *
    1533  * @remarks Maybe called with interrupts disabled!
     1535 * @note If you change the delta calculation made here, make sure to update the
     1536 *       assembly version in sup.mac! Also update supdrvGipMpEvent() while
     1537 *       re-adjusting deltas while choosing a new GIP master.
     1538 * @remarks Maybe called with interrupts disabled in ring-0!
    15341539 */
    15351540DECLINLINE(int) SUPTscDeltaApply(PSUPGLOBALINFOPAGE pGip, uint64_t *puTsc, uint16_t idApic, bool *pfDeltaApplied)
     
    15621567
    15631568/**
    1564  * Reads the delta-adjusted TSC.
     1569 * Gets the delta-adjusted TSC, must only be called when GIP mode is invariant
     1570 * (i.e. when TSC deltas are likely to be computed and available).
     1571 *
     1572 * In other GIP modes, like async, we don't bother with computing TSC deltas and
     1573 * therefore it is meaningless to call this function, use SUPReadTSC() instead.
    15651574 *
    15661575 * @returns VBox status code.
     
    15721581 *                          updated for other failures.
    15731582 *
    1574  * @remarks May be called with interrupts disabled!
    1575  */
    1576 DECLINLINE(int) SUPReadTsc(uint64_t *puTsc, uint16_t *pidApic)
     1583 * @remarks May be called with interrupts disabled in ring-0!
     1584 */
     1585DECLINLINE(int) SUPGetTsc(uint64_t *puTsc, uint16_t *pidApic)
    15771586{
    15781587#ifdef IN_RING3
     
    15991608    return fDeltaApplied ? VINF_SUCCESS : VERR_SUPDRV_TSC_READ_FAILED;
    16001609#endif
     1610}
     1611
     1612
     1613/**
     1614 * Reads the host TSC value.
     1615 * If applicable, normalizes the host TSC value with intercpu TSC deltas.
     1616 *
     1617 * @returns the TSC value.
     1618 *
     1619 * @remarks Requires GIP to be initialized.
     1620 */
     1621DECLINLINE(uint64_t) SUPReadTsc(void)
     1622{
     1623    if (g_pSUPGlobalInfoPage->u32Mode == SUPGIPMODE_INVARIANT_TSC)
     1624    {
     1625        uint64_t u64Tsc = UINT64_MAX;
     1626        int rc = SUPGetTsc(&u64Tsc, NULL /* pidApic */);
     1627        AssertRC(rc);
     1628        return u64Tsc;
     1629    }
     1630    else
     1631        return ASMReadTSC();
    16011632}
    16021633
  • trunk/include/VBox/sup.mac

    r53269 r53430  
    123123endstruc
    124124
     125;;
     126; Macro to apply per-CPU TSC delta to the TSC value read in through rdtsc.
     127;
     128; @param   %1    The pSupGipCpu pointer
     129; @remarks edx:eax contains the 64-bit TSC value to apply the delta to.
     130%macro SUPTscDeltaApply 1
     131    ; Check if we have a valid TSC-delta, i.e. != INT64_MAX.
     132    cmp     dword [%1 + SUPGIPCPU.i64TSCDelta + 4], 0xffffffff
     133    jne     %%valid_delta
     134    cmp     dword [%1 + SUPGIPCPU.i64TSCDelta], 0x7fffffff
     135    je      %%done
     136%%valid_delta:
     137    ; Subtract the delta from edx:eax
     138    sub     eax, dword [%1 + SUPGIPCPU.i64TSCDelta + 4]
     139    sbb     edx, dword [%1 + SUPGIPCPU.i64TSCDelta]
     140%%done:
     141%endmacro
    125142
    126143%endif
  • trunk/src/VBox/HostDrivers/Support/SUPDrv.c

    r53396 r53430  
    121121 *  master with a timeout. */
    122122#define GIP_TSC_DELTA_SYNC_PRESTART_WORKER  5
     123/** The TSC-refinement interval in seconds. */
     124#define GIP_TSC_REFINE_INTERVAL             5
    123125
    124126AssertCompile(GIP_TSC_DELTA_PRIMER_LOOPS < GIP_TSC_DELTA_READ_TIME_LOOPS);
     
    134136# define DO_NOT_START_GIP
    135137#endif
     138
     139/** Whether the application of TSC-deltas is required. */
     140#define GIP_ARE_TSC_DELTAS_APPLICABLE(a_pGip)  ((a_pGip)->u32Mode == SUPGIPMODE_INVARIANT_TSC && !g_fOsTscDeltasInSync)
    136141
    137142
     
    148153static int                  supdrvIOCtl_LdrGetSymbol(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPLDRGETSYMBOL pReq);
    149154static int                  supdrvIDC_LdrGetSymbol(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPDRVIDCREQGETSYM pReq);
    150 static int                  supdrvLdrSetVMMR0EPs(PSUPDRVDEVEXT pDevExt, void *pvVMMR0, void *pvVMMR0EntryInt, void *pvVMMR0EntryFast, void *pvVMMR0EntryEx);
     155static int                  supdrvLdrSetVMMR0EPs(PSUPDRVDEVEXT pDevExt, void *pvVMMR0, void *pvVMMR0EntryInt,void *pvVMMR0EntryFast, void *pvVMMR0EntryEx);
    151156static void                 supdrvLdrUnsetVMMR0EPs(PSUPDRVDEVEXT pDevExt);
    152157static int                  supdrvLdrAddUsage(PSUPDRVSESSION pSession, PSUPDRVLDRIMAGE pImage);
     
    164169static DECLCALLBACK(void)   supdrvGipAsyncTimer(PRTTIMER pTimer, void *pvUser, uint64_t iTick);
    165170static DECLCALLBACK(void)   supdrvGipMpEvent(RTMPEVENT enmEvent, RTCPUID idCpu, void *pvUser);
    166 static bool                 supdrvIsInvariantTsc(void);
    167 static void                 supdrvGipInit(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE pGip, RTHCPHYS HCPhys,
    168                                           uint64_t u64NanoTS, unsigned uUpdateHz, unsigned uUpdateIntervalNS, unsigned cCpus);
     171static void                 supdrvGipInit(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE pGip, RTHCPHYS HCPhys, uint64_t u64NanoTS,
     172                                          unsigned uUpdateHz, unsigned uUpdateIntervalNS, unsigned cCpus);
    169173static DECLCALLBACK(void)   supdrvGipInitOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2);
    170174static void                 supdrvGipTerm(PSUPGLOBALINFOPAGE pGip);
     
    206210static volatile uint32_t    g_cMpOnOffEvents;
    207211/** TSC reading during start of TSC frequency refinement phase. */
    208 static uint64_t             g_u64TSCAnchor;
     212static uint64_t             g_u64TscAnchor;
    209213/** Timestamp (in nanosec) during start of TSC frequency refinement phase. */
    210214static uint64_t             g_u64NanoTSAnchor;
     215/** Pointer to the timer used to refine the TSC frequency. */
     216static PRTTIMER             g_pTscRefineTimer;
    211217/** Whether the host OS has already normalized the hardware TSC deltas across
    212218 *  CPUs. */
     
    39273933 * updating.
    39283934 *
     3935 * @param   pGip             Pointer to the GIP.
    39293936 * @param   pGipCpu          The per CPU structure for this CPU.
    39303937 * @param   u64NanoTS        The current time.
    39313938 */
    3932 static void supdrvGipReInitCpu(PSUPGIPCPU pGipCpu, uint64_t u64NanoTS)
    3933 {
    3934     pGipCpu->u64TSC    = ASMReadTSC() - pGipCpu->u32UpdateIntervalTSC;
     3939static void supdrvGipReInitCpu(PSUPGLOBALINFOPAGE pGip, PSUPGIPCPU pGipCpu, uint64_t u64NanoTS)
     3940{
     3941    pGipCpu->u64TSC    = SUPReadTsc() - pGipCpu->u32UpdateIntervalTSC;
    39353942    pGipCpu->u64NanoTS = u64NanoTS;
    39363943}
     
    39503957
    39513958    if (RT_LIKELY(iCpu < pGip->cCpus && pGip->aCPUs[iCpu].idCpu == idCpu))
    3952         supdrvGipReInitCpu(&pGip->aCPUs[iCpu], *(uint64_t *)pvUser2);
     3959        supdrvGipReInitCpu(pGip, &pGip->aCPUs[iCpu], *(uint64_t *)pvUser2);
    39533960
    39543961    NOREF(pvUser2);
     
    40304037                 * The more interrupts the better...
    40314038                 */
     4039                /** @todo On Windows, RTTimerRequestSystemGranularity() always succeeds, so
     4040                 *        whats the point of the remaining calls? */
    40324041                if (   RT_SUCCESS_NP(RTTimerRequestSystemGranularity(  976563 /* 1024 HZ */, &u32SystemResolution))
    40334042                    || RT_SUCCESS_NP(RTTimerRequestSystemGranularity( 1000000 /* 1000 HZ */, &u32SystemResolution))
     
    40504059
    40514060                u64NanoTS = RTTimeSystemNanoTS() - pGipR0->u32UpdateIntervalNS;
    4052                 if (   pGipR0->u32Mode == SUPGIPMODE_SYNC_TSC
     4061                if (   pGipR0->u32Mode == SUPGIPMODE_INVARIANT_TSC
     4062                    || pGipR0->u32Mode == SUPGIPMODE_SYNC_TSC
    40534063                    || RTMpGetOnlineCount() == 1)
    4054                     supdrvGipReInitCpu(&pGipR0->aCPUs[0], u64NanoTS);
     4064                    supdrvGipReInitCpu(pGipR0, &pGipR0->aCPUs[0], u64NanoTS);
    40554065                else
    40564066                    RTMpOnAll(supdrvGipReInitCpuCallback, pGipR0, &u64NanoTS);
    40574067
    40584068#ifndef DO_NOT_START_GIP
    4059                 rc = RTTimerStart(pDevExt->pGipTimer, 0); AssertRC(rc);
     4069                rc = RTTimerStart(pDevExt->pGipTimer, 0 /* fire ASAP */); AssertRC(rc);
    40604070#endif
    40614071                rc = VINF_SUCCESS;
     
    56105620
    56115621
     5622/**
     5623 * Returns whether the host CPU sports an invariant TSC or not.
     5624 *
     5625 * @returns true if invariant TSC is supported, false otherwise.
     5626 */
     5627static bool supdrvIsInvariantTsc(void)
     5628{
     5629    static bool s_fQueried        = false;
     5630    static bool s_fIsInvariantTsc = false;
     5631    if (!s_fQueried)
     5632    {
     5633        uint32_t uEax, uEbx, uEcx, uEdx;
     5634        ASMCpuId(0x80000000, &uEax, &uEbx, &uEcx, &uEdx);
     5635        if (uEax >= 0x80000007)
     5636        {
     5637            ASMCpuId(0x80000007, &uEax, &uEbx, &uEcx, &uEdx);
     5638            if (uEdx & X86_CPUID_AMD_ADVPOWER_EDX_TSCINVAR)
     5639                s_fIsInvariantTsc = true;
     5640        }
     5641        s_fQueried = true;
     5642    }
     5643
     5644    return s_fIsInvariantTsc;
     5645}
     5646
     5647
    56125648#ifdef SUPDRV_USE_TSC_DELTA_THREAD
    56135649/**
     
    57025738                cConsecutiveTimeouts = 0;
    57035739                if (!cTimesMeasured++)
     5740                {
    57045741                    rc = supdrvMeasureTscDeltas(pDevExt, NULL /* pidxMaster */);
     5742                    RTCpuSetCopy(&pDevExt->TscDeltaObtainedCpuSet, &pDevExt->pGip->OnlineCpuSet);
     5743                }
    57055744                else
    57065745                {
     
    57215760                            rc |= supdrvMeasureTscDeltaOne(pDevExt, iCpu);
    57225761                            RTCpuSetDel(&pDevExt->TscDeltaCpuSet, pGipCpuWorker->idCpu);
     5762                            if (pGipCpuWorker->i64TSCDelta != INT64_MAX)
     5763                                RTCpuSetAdd(&pDevExt->TscDeltaObtainedCpuSet, pGipCpuWorker->idCpu);
    57235764                        }
    57245765                    }
     
    58315872    {
    58325873        /* Signal a few more times before giving up. */
    5833         int cTries = 5;
    5834         while (--cTries > 0)
     5874        int cTriesLeft = 5;
     5875        while (--cTriesLeft > 0)
    58355876        {
    58365877            RTThreadUserSignal(pDevExt->hTscDeltaThread);
     
    58565897 *          notifications!
    58575898 */
    5858 static int supdrvTscDeltaInit(PSUPDRVDEVEXT pDevExt)
    5859 {
    5860     Assert(!g_fOsTscDeltasInSync);
     5899static int supdrvTscDeltaThreadInit(PSUPDRVDEVEXT pDevExt)
     5900{
     5901    Assert(GIP_ARE_TSC_DELTAS_APPLICABLE(pDevExt->pGip));
     5902
    58615903    int rc = RTSpinlockCreate(&pDevExt->hTscDeltaSpinlock, RTSPINLOCK_FLAGS_INTERRUPT_UNSAFE, "VBoxTscSpnLck");
    58625904    if (RT_SUCCESS(rc))
     
    58685910            pDevExt->cMsTscDeltaTimeout = 1;
    58695911            RTCpuSetEmpty(&pDevExt->TscDeltaCpuSet);
     5912            RTCpuSetEmpty(&pDevExt->TscDeltaObtainedCpuSet);
    58705913            rc = RTThreadCreate(&pDevExt->hTscDeltaThread, supdrvTscDeltaThread, pDevExt, 0 /* cbStack */,
    58715914                                RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "VBoxTscThread");
     
    59265969    pDevExt->rcTscDelta = VERR_NOT_AVAILABLE;
    59275970}
     5971
     5972
     5973/**
     5974 * Waits for TSC-delta measurements to be completed for all online CPUs.
     5975 *
     5976 * @returns VBox status code.
     5977 * @param   pDevExt         Pointer to the device instance data.
     5978 */
     5979static int supdrvTscDeltaThreadWaitForOnlineCpus(PSUPDRVDEVEXT pDevExt)
     5980{
     5981    int cTriesLeft = 5;
     5982    int cMsTotalWait;
     5983    int cMsWaited = 0;
     5984    int cMsWaitGranularity = 1;
     5985
     5986    PSUPGLOBALINFOPAGE pGip = pDevExt->pGip;
     5987    AssertReturn(pGip, VERR_INVALID_POINTER);
     5988
     5989    cMsTotalWait = RT_MIN(pGip->cPresentCpus + 2, 150);
     5990    while (cTriesLeft-- > 0)
     5991    {
     5992        if (RTCpuSetIsEqual(&pDevExt->TscDeltaObtainedCpuSet, &pGip->OnlineCpuSet))
     5993            return VINF_SUCCESS;
     5994        RTThreadSleep(cMsWaitGranularity);
     5995        cMsWaited += cMsWaitGranularity;
     5996        if (cMsWaited >= cMsTotalWait)
     5997            break;
     5998    }
     5999
     6000    return VERR_TIMEOUT;
     6001}
    59286002#endif /* SUPDRV_USE_TSC_DELTA_THREAD */
    59296003
     
    59356009 * the CPU frequency up, while for the invariant cases using a sleeping method.
    59366010 *
    5937  * The TSC frequency can vary on systems that are not reported as invariant.
    5938  * However, on such systems the object of this function is to find out what the
    5939  * nominal, maximum TSC frequency under normal CPU operation.
     6011 * The TSC frequency can vary on systems which are not reported as invariant.
     6012 * On such systems the object of this function is to find out what the nominal,
     6013 * maximum TSC frequency under 'normal' CPU operation.
    59406014 *
    59416015 * @returns VBox status code.
    5942  * @param   pGip        Pointer to the GIP.
    5943  *
    5944  * @remarks Must be called only after measuring the TSC deltas.
    5945  */
    5946 static int supdrvGipMeasureTscFreq(PSUPGLOBALINFOPAGE pGip)
     6016 * @param   pDevExt        Pointer to the device instance.
     6017 *
     6018 * @remarks Must be called only -after- measuring the TSC deltas.
     6019 */
     6020static int supdrvGipMeasureTscFreq(PSUPDRVDEVEXT pDevExt)
    59476021{
    59486022    int cTriesLeft = 4;
     6023    PSUPGLOBALINFOPAGE pGip = pDevExt->pGip;
    59496024
    59506025    /* Assert order. */
     
    59766051        ASMSetFlags(uFlags);
    59776052
    5978         /* Activate this when implemented invariant TSC GIP mode. Otherwise systems that are really invariant
    5979            which get detected as async will break. */
    5980 #if 0
    5981         if (supdrvIsInvariantTsc())
     6053        if (pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC)
    59826054        {
    59836055            /*
    5984              * Sleep wait since the TSC frequency is constant, eases host load.
     6056             * Sleep-wait since the TSC frequency is constant, it eases host load.
    59856057             * Shorter interval produces more variance in the frequency (esp. Windows).
    59866058             */
     
    59926064        }
    59936065        else
    5994 #endif
    59956066        {
    59966067            /* Busy-wait keeping the frequency up and measure. */
     
    60106081        ASMSetFlags(uFlags);
    60116082
    6012         /* Activate this when implemented invariant TSC GIP mode. Otherwise systems that are really invariant
    6013            which get detected as async will break. */
    6014 #if 0
    6015         if (supdrvIsInvariantTsc())        /** @todo replace with enum check. */
     6083        if (GIP_ARE_TSC_DELTAS_APPLICABLE(pGip))
    60166084        {
    60176085            int rc;
     
    60246092                || !fAppliedAfter)
    60256093            {
     6094#ifdef SUPDRV_USE_TSC_DELTA_THREAD
     6095                /*
     6096                 * The TSC-delta measurements are kicked-off asynchronously as each host CPU is initialized.
     6097                 * Therefore, if we failed to have a delta for the CPU(s) we were scheduled on (idApicBefore
     6098                 * and idApicAfter) then wait until we have TSC-delta measurements for all online CPUs and
     6099                 * proceed. This should be triggered just once if we're rather unlucky.
     6100                 */
     6101                rc = supdrvTscDeltaThreadWaitForOnlineCpus(pDevExt);
     6102                if (rc == VERR_TIMEOUT)
     6103                {
     6104                    SUPR0Printf("vboxdrv: supdrvGipMeasureTscFreq: timedout waiting for TSC-delta measurements.\n");
     6105                    return VERR_SUPDRV_TSC_FREQ_MEASUREMENT_FAILED;
     6106                }
     6107#else
    60266108                SUPR0Printf("vboxdrv: supdrvGipMeasureTscFreq: idApicBefore=%u idApicAfter=%u cTriesLeft=%u\n",
    60276109                            idApicBefore, idApicAfter, cTriesLeft);
     6110#endif
    60286111                continue;
    60296112            }
    60306113        }
    6031 #endif
    60326114
    60336115        /*
     
    60356117         */
    60366118        pGip->u64CpuHz = ((u64TscAfter - u64TscBefore) * RT_NS_1SEC_64) / (u64NanoTsAfter - u64NanoTsBefore);
     6119        if (pGip->u32Mode != SUPGIPMODE_ASYNC_TSC)
     6120            pGip->aCPUs[0].u64CpuHz = pGip->u64CpuHz;
    60376121        return VINF_SUCCESS;
    60386122    }
    60396123
    60406124    return VERR_SUPDRV_TSC_FREQ_MEASUREMENT_FAILED;
     6125}
     6126
     6127
     6128/**
     6129 * Timer callback function for TSC frequency refinement in invariant GIP mode.
     6130 *
     6131 * @param   pTimer      The timer.
     6132 * @param   pvUser      Opaque pointer to the GIP.
     6133 * @param   iTick       The timer tick.
     6134 */
     6135static DECLCALLBACK(void) supdrvRefineTscTimer(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
     6136{
     6137    uint8_t            idApic;
     6138    uint64_t           u64DeltaNanoTS;
     6139    uint64_t           u64DeltaTsc;
     6140    uint64_t           u64NanoTS;
     6141    uint64_t           u64Tsc;
     6142    RTCCUINTREG        uFlags;
     6143    bool               fDeltaApplied = false;
     6144    PSUPGLOBALINFOPAGE pGip = (PSUPGLOBALINFOPAGE)pvUser;
     6145
     6146    /* Paranoia. */
     6147    Assert(pGip);
     6148    Assert(pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC);
     6149
     6150    u64NanoTS = RTTimeSystemNanoTS();
     6151    while (RTTimeSystemNanoTS() == u64NanoTS)
     6152        ASMNopPause();
     6153    uFlags    = ASMIntDisableFlags();
     6154    idApic    = ASMGetApicId();
     6155    u64Tsc    = ASMReadTSC();
     6156    u64NanoTS = RTTimeSystemNanoTS();
     6157    ASMSetFlags(uFlags);
     6158    SUPTscDeltaApply(pGip, &u64Tsc, idApic, &fDeltaApplied);
     6159    u64DeltaNanoTS = u64NanoTS - g_u64NanoTSAnchor;
     6160    u64DeltaTsc = u64Tsc - g_u64TscAnchor;
     6161
     6162    if (   pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC
     6163        && !fDeltaApplied)
     6164    {
     6165        SUPR0Printf("vboxdrv: failed to refine TSC frequency as TSC-deltas unavailable after %d seconds!\n",
     6166                    GIP_TSC_REFINE_INTERVAL);
     6167        return;
     6168    }
     6169
     6170    /* Calculate the TSC frequency. */
     6171    if (   u64DeltaTsc < UINT64_MAX / RT_NS_1SEC
     6172        && u64DeltaNanoTS < UINT32_MAX)
     6173        pGip->u64CpuHz = ASMMultU64ByU32DivByU32(u64DeltaTsc, RT_NS_1SEC, u64DeltaNanoTS);
     6174    else
     6175    {
     6176        /* Try not to lose precision, the larger the interval the more likely we overflow. */
     6177        if (   u64DeltaTsc < UINT64_MAX / RT_NS_100MS
     6178            && u64DeltaNanoTS / 10 < UINT32_MAX)
     6179            pGip->u64CpuHz = ASMMultU64ByU32DivByU32(u64DeltaTsc, RT_NS_100MS, u64DeltaNanoTS / 10);
     6180        else if (   u64DeltaTsc < UINT64_MAX / RT_NS_10MS
     6181                 && u64DeltaNanoTS / 100 < UINT32_MAX)
     6182            pGip->u64CpuHz = ASMMultU64ByU32DivByU32(u64DeltaTsc, RT_NS_10MS, u64DeltaNanoTS / 100);
     6183        else if (   u64DeltaTsc < UINT64_MAX / RT_NS_1MS
     6184                 && u64DeltaNanoTS / 1000 < UINT32_MAX)
     6185            pGip->u64CpuHz = ASMMultU64ByU32DivByU32(u64DeltaTsc, RT_NS_1MS, u64DeltaNanoTS / 1000);
     6186        else /* Screw it. */
     6187            pGip->u64CpuHz = u64DeltaTsc / (u64DeltaNanoTS / RT_NS_1SEC_64);
     6188    }
     6189
     6190    /* Update rest of GIP. */
     6191    Assert(pGip->u32Mode != SUPGIPMODE_ASYNC_TSC); /* See SUPGetCpuHzFromGIP().*/
     6192    pGip->aCPUs[0].u64CpuHz = pGip->u64CpuHz;
     6193}
     6194
     6195
     6196/**
     6197 * Starts the TSC-frequency refinement phase asynchronously.
     6198 *
     6199 * @param   pDevExt        Pointer to the device instance data.
     6200 */
     6201static void supdrvRefineTscFreq(PSUPDRVDEVEXT pDevExt)
     6202{
     6203    uint64_t            u64NanoTS;
     6204    RTCCUINTREG         uFlags;
     6205    uint8_t             idApic;
     6206    int                 rc;
     6207    bool                fDeltaApplied = false;
     6208    PSUPGLOBALINFOPAGE  pGip;
     6209
     6210    /* Validate. */
     6211    Assert(pDevExt);
     6212    Assert(pDevExt->pGip);
     6213
     6214    pGip = pDevExt->pGip;
     6215    u64NanoTS = RTTimeSystemNanoTS();
     6216    while (RTTimeSystemNanoTS() == u64NanoTS)
     6217        ASMNopPause();
     6218    uFlags            = ASMIntDisableFlags();
     6219    idApic            = ASMGetApicId();
     6220    g_u64TscAnchor    = ASMReadTSC();
     6221    g_u64NanoTSAnchor = RTTimeSystemNanoTS();
     6222    ASMSetFlags(uFlags);
     6223    SUPTscDeltaApply(pGip, &g_u64TscAnchor, idApic, &fDeltaApplied);
     6224
     6225#ifdef SUPDRV_USE_TSC_DELTA_THREAD
     6226    if (   pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC
     6227        && !fDeltaApplied)
     6228    {
     6229        rc = supdrvTscDeltaThreadWaitForOnlineCpus(pDevExt);
     6230        if (rc == VERR_TIMEOUT)
     6231        {
     6232            SUPR0Printf("vboxdrv: Skipping refinement of TSC frequency as TSC-delta measurement timed out!\n");
     6233            return;
     6234        }
     6235    }
     6236#endif
     6237
     6238    rc = RTTimerCreateEx(&g_pTscRefineTimer, 0 /* one-shot */, RTTIMER_FLAGS_CPU_ANY, supdrvRefineTscTimer, pGip);
     6239    if (RT_SUCCESS(rc))
     6240    {
     6241        /*
     6242         * Refine the TSC frequency measurement over a long interval. Ideally, we want to keep the
     6243         * interval as small as possible while gaining the most consistent and accurate frequency
     6244         * (compared to what the host OS might have measured).
     6245         *
     6246         * In theory, we gain more accuracy with longer intervals, but we want VMs to startup with the
     6247         * same TSC frequency whenever possible so we need to keep the interval short.
     6248         */
     6249        rc = RTTimerStart(g_pTscRefineTimer, GIP_TSC_REFINE_INTERVAL * RT_NS_1SEC_64);
     6250        AssertRC(rc);
     6251    }
     6252    else
     6253        OSDBGPRINT(("RTTimerCreateEx failed to create one-shot timer. rc=%Rrc\n", rc));
    60416254}
    60426255
     
    61076320                    && !supdrvOSGetForcedAsyncTscMode(pDevExt)))
    61086321    {
     6322        /* Basically invariant Windows boxes, should never be detected as async. */
    61096323        OSDBGPRINT(("supdrvGipCreate: The TSC-deltas should be normalized by the host OS, but verifying shows it's not!\n"));
    61106324        return VERR_INTERNAL_ERROR_2;
     
    61126326
    61136327#ifdef SUPDRV_USE_TSC_DELTA_THREAD
    6114     if (!g_fOsTscDeltasInSync)
     6328    if (GIP_ARE_TSC_DELTAS_APPLICABLE(pGip))
    61156329    {
    61166330        /* Initialize TSC-delta measurement thread before executing any Mp event callbacks. */
    6117         rc = supdrvTscDeltaInit(pDevExt);
     6331        rc = supdrvTscDeltaThreadInit(pDevExt);
    61186332    }
    61196333#endif
     
    61266340            if (RT_SUCCESS(rc))
    61276341            {
     6342                uint16_t iCpu;
    61286343#ifndef SUPDRV_USE_TSC_DELTA_THREAD
    6129                 uint16_t iCpu;
    6130                 if (!g_fOsTscDeltasInSync)
     6344                if (GIP_ARE_TSC_DELTAS_APPLICABLE(pGip))
    61316345                {
    61326346                    /*
     
    61516365                if (RT_SUCCESS(rc))
    61526366                {
    6153                     rc = supdrvGipMeasureTscFreq(pGip);
     6367                    rc = supdrvGipMeasureTscFreq(pDevExt);
    61546368                    if (RT_SUCCESS(rc))
    61556369                    {
    6156                         if (supdrvIsInvariantTsc())
    6157                             pGip->aCPUs[0].u64CpuHz = pGip->u64CpuHz;
    6158 
    61596370                        /*
    61606371                         * Create the timer.
     
    61806391                            Log(("supdrvGipCreate: %u ns interval.\n", u32Interval));
    61816392                            g_pSUPGlobalInfoPage = pGip;
     6393                            if (pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC)
     6394                                supdrvRefineTscFreq(pDevExt);
    61826395                            return VINF_SUCCESS;
    61836396                        }
    61846397                        else
    61856398                        {
    6186                             OSDBGPRINT(("supdrvGipCreate: RTTimerCreateEx failed (%u ns interval). rc=%Rrc\n", u32Interval, rc));
     6399                            OSDBGPRINT(("supdrvGipCreate: failed create GIP timer at %u ns interval. rc=%Rrc\n", u32Interval, rc));
    61876400                            Assert(!pDevExt->pGipTimer);
    61886401                        }
     
    62356448
    62366449    /*
     6450     * Destroy the TSC-refinement one-shot timer.
     6451     */
     6452    if (g_pTscRefineTimer)
     6453    {
     6454        RTTimerDestroy(g_pTscRefineTimer);
     6455        g_pTscRefineTimer = NULL;
     6456    }
     6457
     6458    /*
    62376459     * Invalid the GIP data.
    62386460     */
     
    62746496 * Timer callback function sync GIP mode.
    62756497 * @param   pTimer      The timer.
    6276  * @param   pvUser      The device extension.
     6498 * @param   pvUser      Opaque pointer to the device extension.
     6499 * @param   iTick       The timer tick.
    62776500 */
    62786501static DECLCALLBACK(void) supdrvGipSyncTimer(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
    62796502{
    6280     RTCCUINTREG     fOldFlags = ASMIntDisableFlags(); /* No interruptions please (real problem on S10). */
    6281     uint64_t        u64TSC    = ASMReadTSC();
    6282     uint64_t        NanoTS    = RTTimeSystemNanoTS();
    6283     PSUPDRVDEVEXT   pDevExt   = (PSUPDRVDEVEXT)pvUser;
    6284 
    6285     if (supdrvIsInvariantTsc())
    6286     {
    6287         PSUPGIPCPU         pGipCpu;
    6288         unsigned           iCpu;
    6289         PSUPGLOBALINFOPAGE pGip = pDevExt->pGip;
    6290         uint8_t            idApic = ASMGetApicId();
    6291 
    6292         iCpu = pGip->aiCpuFromApicId[idApic];
    6293         Assert(iCpu < pGip->cCpus);
    6294         pGipCpu = &pGip->aCPUs[iCpu];
    6295         Assert(pGipCpu->idCpu == RTMpCpuId());
    6296 
     6503    RTCCUINTREG        uFlags;
     6504    uint64_t           u64TSC;
     6505    uint64_t           u64NanoTS;
     6506    PSUPDRVDEVEXT      pDevExt = (PSUPDRVDEVEXT)pvUser;
     6507    PSUPGLOBALINFOPAGE pGip = pDevExt->pGip;
     6508
     6509    /*
     6510     * Synchronize with the host OS clock tick before reading the TSC.
     6511     * Especially important on Windows where the granularity is terrible.
     6512     */
     6513    u64NanoTS = RTTimeSystemNanoTS();
     6514    while (u64NanoTS == RTTimeSystemNanoTS())
     6515        ASMNopPause();
     6516
     6517    uFlags    = ASMIntDisableFlags(); /* No interruptions please (real problem on S10). */
     6518    u64TSC    = ASMReadTSC();
     6519    u64NanoTS = RTTimeSystemNanoTS();
     6520
     6521    if (GIP_ARE_TSC_DELTAS_APPLICABLE(pGip))
     6522    {
    62976523        /*
    62986524         * The calculations in supdrvGipUpdate() is very timing sensitive and doesn't handle
     
    63046530         * fire on the CPU they were registered/started on. Darwin, Solaris need verification.
    63056531         */
    6306         if (pGipCpu->i64TSCDelta != INT64_MAX)
    6307             u64TSC -= pGipCpu->i64TSCDelta;
    6308     }
    6309 
    6310     supdrvGipUpdate(pDevExt, NanoTS, u64TSC, NIL_RTCPUID, iTick);
    6311 
    6312     ASMSetFlags(fOldFlags);
    6313 
    6314     if (supdrvIsInvariantTsc())
    6315     {
    6316         /*
    6317          * Refine the TSC frequency measurement over a longer interval. Ideally, we want to keep the
    6318          * interval as small as possible while gaining the most consistent and accurate frequency
    6319          * (compared to what the host OS might have measured).
    6320          *
    6321          * In theory, we gain more accuracy with  longer intervals, but we want VMs to startup with the
    6322          * same TSC frequency whenever possible so we need to keep the interval short.
    6323          */
    6324         uint8_t            idApic;
    6325         uint64_t           u64NanoTS;
    6326         PSUPGLOBALINFOPAGE pGip = pDevExt->pGip;
    6327         const int          cSeconds = 3;
    6328         if (RT_UNLIKELY(iTick == 3))    /* Helps with more consistent values across multiple runs (esp. Windows). */
    6329         {
    6330             u64NanoTS = RTTimeSystemNanoTS();
    6331             while (RTTimeSystemNanoTS() == u64NanoTS)
    6332                 ASMNopPause();
    6333             fOldFlags         = ASMIntDisableFlags();
    6334             idApic            = ASMGetApicId();
    6335             g_u64TSCAnchor    = ASMReadTSC();
    6336             g_u64NanoTSAnchor = RTTimeSystemNanoTS();
    6337             ASMSetFlags(fOldFlags);
    6338             SUPTscDeltaApply(pGip, &g_u64TSCAnchor, idApic, NULL /* pfDeltaApplied */);
    6339             ++g_u64TSCAnchor;
    6340         }
    6341         else if (g_u64TSCAnchor)
    6342         {
    6343             uint64_t u64DeltaNanoTS;
    6344             u64NanoTS = RTTimeSystemNanoTS();
    6345             while (RTTimeSystemNanoTS() == u64NanoTS)
    6346                 ASMNopPause();
    6347             fOldFlags = ASMIntDisableFlags();
    6348             idApic    = ASMGetApicId();
    6349             u64TSC    = ASMReadTSC();
    6350             u64NanoTS = RTTimeSystemNanoTS();
    6351             ASMSetFlags(fOldFlags);
    6352             SUPTscDeltaApply(pGip, &u64TSC, idApic, NULL /* pfDeltaApplied */);
    6353             u64DeltaNanoTS = u64NanoTS - g_u64NanoTSAnchor;
    6354             if (u64DeltaNanoTS >= cSeconds * RT_NS_1SEC_64)
    6355             {
    6356                 uint16_t iCpu;
    6357                 if (u64DeltaNanoTS < UINT32_MAX)
    6358                     pGip->u64CpuHz = ASMMultU64ByU32DivByU32(u64TSC - g_u64TSCAnchor, RT_NS_1SEC, u64DeltaNanoTS);
    6359                 else
    6360                     pGip->u64CpuHz = (u64TSC - g_u64TSCAnchor) / (u64DeltaNanoTS / RT_NS_1SEC);
    6361 
    6362                 pGip->aCPUs[0].u64CpuHz = pGip->u64CpuHz;
    6363                 g_u64TSCAnchor = 0;
    6364             }
    6365         }
    6366     }
     6532        Assert(!ASMIntAreEnabled());
     6533        SUPTscDeltaApply(pGip, &u64TSC, ASMGetApicId(), NULL /* pfDeltaApplied */);
     6534    }
     6535
     6536    supdrvGipUpdate(pDevExt, u64NanoTS, u64TSC, NIL_RTCPUID, iTick);
     6537
     6538    ASMSetFlags(uFlags);
    63676539}
    63686540
     
    63716543 * Timer callback function for async GIP mode.
    63726544 * @param   pTimer      The timer.
    6373  * @param   pvUser      The device extension.
     6545 * @param   pvUser      Opaque pointer to the device extension.
     6546 * @param   iTick       The timer tick.
    63746547 */
    63756548static DECLCALLBACK(void) supdrvGipAsyncTimer(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
     
    64916664     * update the state and it'll get serviced when the thread's listening interval times out.
    64926665     */
    6493     if (   !g_fOsTscDeltasInSync
    6494         && supdrvIsInvariantTsc())
    6495     {
    6496         RTCpuSetAdd(&pDevExt->TscDeltaCpuSet, idCpu);
     6666    if (GIP_ARE_TSC_DELTAS_APPLICABLE(pGip))
     6667    {
    64976668        RTSpinlockAcquire(pDevExt->hTscDeltaSpinlock);
    64986669        if (   pDevExt->enmTscDeltaState == kSupDrvTscDeltaState_Listening
    64996670            || pDevExt->enmTscDeltaState == kSupDrvTscDeltaState_Measuring)
    65006671        {
     6672            RTCpuSetAdd(&pDevExt->TscDeltaCpuSet, idCpu);
    65016673            pDevExt->enmTscDeltaState = kSupDrvTscDeltaState_WaitAndMeasure;
    65026674        }
     
    65506722    }
    65516723
    6552     /* Reset the TSC delta (if required), we will recalculate it lazily. */
    6553     if (!g_fOsTscDeltasInSync)
     6724    /* Reset the TSC delta, we will recalculate it lazily. */
     6725    if (GIP_ARE_TSC_DELTAS_APPLICABLE(pGip))
    65546726        ASMAtomicWriteS64(&pGip->aCPUs[i].i64TSCDelta, INT64_MAX);
     6727
     6728#ifdef SUPDRV_USE_TSC_DELTA_THREAD
     6729    /* Remove this CPU from the set of CPUs that we have obtained the TSC deltas. */
     6730    if (supdrvIsInvariantTsc())
     6731        RTCpuSetDel(&pDevExt->TscDeltaObtainedCpuSet, idCpu);
     6732#endif
    65556733
    65566734    /* commit it */
     
    66536831        }
    66546832    }
    6655 }
    6656 
    6657 
    6658 /**
    6659  * Returns whether the host CPU sports an invariant TSC or not.
    6660  *
    6661  * @returns true if invariant TSC is supported, false otherwise.
    6662  */
    6663 static bool supdrvIsInvariantTsc(void)
    6664 {
    6665     static bool s_fQueried        = false;
    6666     static bool s_fIsInvariantTsc = false;
    6667     if (!s_fQueried)
    6668     {
    6669         uint32_t uEax, uEbx, uEcx, uEdx;
    6670         ASMCpuId(0x80000000, &uEax, &uEbx, &uEcx, &uEdx);
    6671         if (uEax >= 0x80000007)
    6672         {
    6673             ASMCpuId(0x80000007, &uEax, &uEbx, &uEcx, &uEdx);
    6674             if (uEdx & X86_CPUID_AMD_ADVPOWER_EDX_TSCINVAR)
    6675                 s_fIsInvariantTsc = true;
    6676         }
    6677         s_fQueried = true;
    6678     }
    6679 
    6680     return s_fIsInvariantTsc;
    66816833}
    66826834
     
    69277079    AssertReturn(pDevExt, VERR_INVALID_PARAMETER);
    69287080    AssertReturn(pDevExt->pGip, VERR_INVALID_PARAMETER);
    6929     Assert(!g_fOsTscDeltasInSync);
    69307081
    69317082    pGip          = pDevExt->pGip;
    69327083    idMaster      = pDevExt->idGipMaster;
    69337084    pGipCpuWorker = &pGip->aCPUs[idxWorker];
     7085
     7086    Assert(GIP_ARE_TSC_DELTAS_APPLICABLE(pGip));
    69347087
    69357088    if (pGipCpuWorker->idCpu == idMaster)
     
    69927145    uint32_t   cOnlineCpus    = pGip->cOnlineCpus;
    69937146
    6994     Assert(!g_fOsTscDeltasInSync);
    6995 
    6996     /*
    6997      * If we determined the TSC is async., don't bother with measuring deltas.
    6998      */
    6999     if (RT_UNLIKELY(pGip->u32Mode == SUPGIPMODE_ASYNC_TSC))
    7000         return VINF_SUCCESS;
     7147    Assert(GIP_ARE_TSC_DELTAS_APPLICABLE(pGip));
    70017148
    70027149    /*
     
    71707317static SUPGIPMODE supdrvGipDetermineTscMode(PSUPDRVDEVEXT pDevExt)
    71717318{
    7172 #if 0
     7319    /* Trust CPUs that declare their TSC to be invariant. */
    71737320    if (supdrvIsInvariantTsc())
    7174         return SUPGIPMODE_SYNC_TSC;     /** @todo Switch to SUPGIPMODE_INVARIANT_TSC later. */
    7175 #endif
    7176 
    7177     /*
    7178      * On SMP we're faced with two problems:
     7321        return SUPGIPMODE_INVARIANT_TSC;
     7322
     7323    /*
     7324     * Without invariant CPU ID bit - On SMP we're faced with two problems:
    71797325     *      (1) There might be a skew between the CPU, so that cpu0
    71807326     *          returns a TSC that is slightly different from cpu1.
     
    72037349         * won't trust it unless it has the TscInvariant bit is set.
    72047350         */
     7351        /** @todo this is now redundant. remove later. */
    72057352        /* Check for "AuthenticAMD" */
    72067353        ASMCpuId(0, &uEAX, &uEBX, &uECX, &uEDX);
     
    72137360            {
    72147361                ASMCpuId(0x80000007, &uEAX, &uEBX, &uECX, &uEDX);
    7215                 if (    !(uEDX & RT_BIT(8))/* TscInvariant */
     7362                if (    !(uEDX & X86_CPUID_AMD_ADVPOWER_EDX_TSCINVAR) /* TscInvariant */
    72167363                    &&  (uEDX & 0x3e))  /* STC|TM|THERMTRIP|VID|FID. Ignore TS. */
    72177364                    return SUPGIPMODE_ASYNC_TSC;
     
    74097556     * Calc TSC delta.
    74107557     */
    7411     /** @todo validate the NanoTS delta, don't trust the OS to call us when it should... */
    74127558    u64TSCDelta = u64TSC - pGipCpu->u64TSC;
    74137559    ASMAtomicWriteU64(&pGipCpu->u64TSC, u64TSC);
     7560
     7561    /* We don't need to keep realculating the frequency when it's invariant. */
     7562    if (pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC)
     7563        return;
    74147564
    74157565    if (u64TSCDelta >> 32)
     
    74377587
    74387588    /*
     7589     * Validate the NanoTS deltas between timer fires with an arbitrary threshold of 0.5%.
     7590     * Wait until we have at least one full history since the above history reset. The
     7591     * assumption is that the majority of the previous history values will be tolerable.
     7592     * See @bugref{6710} comment #67.
     7593     */
     7594    if (   u32TransactionId > 23 /* 7 + (8 * 2) */
     7595        && pGip->u32Mode != SUPGIPMODE_ASYNC_TSC)
     7596    {
     7597        uint32_t uNanoTsThreshold = pGip->u32UpdateIntervalNS / 200;
     7598        if (   pGipCpu->u32PrevUpdateIntervalNS > pGip->u32UpdateIntervalNS + uNanoTsThreshold
     7599            || pGipCpu->u32PrevUpdateIntervalNS < pGip->u32UpdateIntervalNS - uNanoTsThreshold)
     7600        {
     7601            uint32_t u32;
     7602            u32  = pGipCpu->au32TSCHistory[0];
     7603            u32 += pGipCpu->au32TSCHistory[1];
     7604            u32 += pGipCpu->au32TSCHistory[2];
     7605            u32 += pGipCpu->au32TSCHistory[3];
     7606            u32 >>= 2;
     7607            u64TSCDelta  = pGipCpu->au32TSCHistory[4];
     7608            u64TSCDelta += pGipCpu->au32TSCHistory[5];
     7609            u64TSCDelta += pGipCpu->au32TSCHistory[6];
     7610            u64TSCDelta += pGipCpu->au32TSCHistory[7];
     7611            u64TSCDelta >>= 2;
     7612            u64TSCDelta += u32;
     7613            u64TSCDelta >>= 1;
     7614        }
     7615    }
     7616
     7617
     7618    /*
    74397619     * TSC History.
    74407620     */
     
    74517631     * However, this problem existed before the invariant mode was introduced.
    74527632     */
    7453     if (   supdrvIsInvariantTsc()
     7633    if (   pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC
    74547634        || pGip->u32UpdateHz >= 1000)
    74557635    {
     
    74897669    ASMAtomicWriteU32(&pGipCpu->u32UpdateIntervalTSC, u32UpdateIntervalTSC + u32UpdateIntervalTSCSlack);
    74907670
    7491     if (supdrvIsInvariantTsc())
    7492         return;
    7493 
    74947671    /*
    74957672     * CpuHz.
     
    75487725     * Recalc the update frequency every 0x800th time.
    75497726     */
    7550     if (!(pGipCpu->u32TransactionId & (GIP_UPDATEHZ_RECALC_FREQ * 2 - 2)))
     7727    if (   pGip->u32Mode != SUPGIPMODE_INVARIANT_TSC   /* cuz we're not recalculating the frequency on invariants hosts. */
     7728        && !(pGipCpu->u32TransactionId & (GIP_UPDATEHZ_RECALC_FREQ * 2 - 2)))
    75517729    {
    75527730        if (pGip->u64NanoTSLastUpdateHz)
     
    75667744#endif
    75677745        }
    7568         ASMAtomicWriteU64(&pGip->u64NanoTSLastUpdateHz, u64NanoTS + 1);
     7746        ASMAtomicWriteU64(&pGip->u64NanoTSLastUpdateHz, u64NanoTS | 1);
    75697747    }
    75707748
     
    76847862        return VERR_INVALID_CPU_ID;
    76857863
    7686     if (g_fOsTscDeltasInSync)
     7864    if (!GIP_ARE_TSC_DELTAS_APPLICABLE(pGip))
    76877865        return VINF_SUCCESS;
    76887866
     
    77057883                 *        to pass those options to the thread somehow and implement it in the
    77067884                 *        thread. Check if anyone uses/needs fAsync before implementing this. */
    7707                 RTCpuSetAdd(&pDevExt->TscDeltaCpuSet, idCpu);
     7885                RTCpuSetAdd(&pDevExt->TscDeltaCpuSet, pGipCpuWorker->idCpu);
    77087886                RTSpinlockAcquire(pDevExt->hTscDeltaSpinlock);
    77097887                if (   pDevExt->enmTscDeltaState == kSupDrvTscDeltaState_Listening
     
    77187896#endif
    77197897
    7720             while (cTries--)
     7898            while (cTries-- > 0)
    77217899            {
    77227900                rc = supdrvMeasureTscDeltaOne(pDevExt, iCpu);
     
    77647942    while (cTries-- > 0)
    77657943    {
    7766         rc = SUPReadTsc(&uTsc, &idApic);
     7944        rc = SUPGetTsc(&uTsc, &idApic);
    77677945        if (RT_SUCCESS(rc))
    77687946        {
     
    77737951        else
    77747952        {
     7953            /* If we failed to have a TSC-delta, measurement the TSC-delta and retry. */
    77757954            int rc2;
    77767955            uint16_t iCpu;
    7777 
    7778             /* If we failed to have a delta, measurement the delta and retry. */
    77797956            AssertMsgReturn(idApic < RT_ELEMENTS(pGip->aiCpuFromApicId),
    77807957                            ("idApic=%u ArraySize=%u\n", idApic, RT_ELEMENTS(pGip->aiCpuFromApicId)), VERR_INVALID_CPU_INDEX);
     
    77827959            AssertMsgReturn(iCpu < pGip->cCpus, ("iCpu=%u cCpus=%u\n", iCpu, pGip->cCpus), VERR_INVALID_CPU_INDEX);
    77837960
    7784             Assert(!g_fOsTscDeltasInSync);
     7961            Assert(GIP_ARE_TSC_DELTAS_APPLICABLE(pGip));
    77857962            rc2 = supdrvMeasureTscDeltaOne(pDevExt, iCpu);
    77867963            if (RT_SUCCESS(rc2))
  • trunk/src/VBox/HostDrivers/Support/SUPDrvInternal.h

    r53396 r53430  
    55
    66/*
    7  * Copyright (C) 2006-2013 Oracle Corporation
     7 * Copyright (C) 2006-2014 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    232232
    233233#if 0
    234 /**  Use a dedicated kernel thread to service TSC-delta measurement requests. */
     234/**  Use a dedicated kernel thread to service TSC-delta measurement requests.
     235 *   @todo Test on servers with many CPUs and sockets. */
    235236#define SUPDRV_USE_TSC_DELTA_THREAD
    236237#endif
     
    693694    /** The set of CPUs we need to take measurements for. */
    694695    RTCPUSET                        TscDeltaCpuSet;
     696    /** The set of CPUs we have completed taken measurements for. */
     697    RTCPUSET                        TscDeltaObtainedCpuSet;
    695698    /** Whether the TSC-delta measurement was successful. */
    696699    int                             rcTscDelta;
  • trunk/src/VBox/HostDrivers/Support/testcase/tstGIP-2.cpp

    r53358 r53430  
    3939#include <iprt/initterm.h>
    4040#include <iprt/getopt.h>
     41#include <iprt/x86.h>
     42
     43
     44/**
     45 * Checks whether the CPU advertises an invariant TSC or not.
     46 *
     47 * @returns true if invariant, false otherwise.
     48 */
     49bool tstIsInvariantTsc(void)
     50{
     51    if (ASMHasCpuId())
     52    {
     53        uint32_t uEax, uEbx, uEcx, uEdx;
     54        ASMCpuId(0x80000000, &uEax, &uEbx, &uEcx, &uEdx);
     55        if (uEax >= 0x80000007)
     56        {
     57            ASMCpuId(0x80000007, &uEax, &uEbx, &uEcx, &uEdx);
     58            if (uEdx & X86_CPUID_AMD_ADVPOWER_EDX_TSCINVAR)
     59                return true;
     60        }
     61    }
     62    return false;
     63}
    4164
    4265
     
    6487    uint64_t uCpuHzRef = 0;
    6588    uint64_t uCpuHzOverallDeviation = 0;
     89    int64_t  iCpuHzMaxDeviation = 0;
    6690    int32_t cCpuHzOverallDevCnt = 0;
    6791    RTGETOPTUNION ValueUnion;
     
    144168                            else
    145169                            {
    146                                 if (pCpu->u32TransactionId > 7)
     170                                /* Wait until the history validation code takes effect. */
     171                                if (pCpu->u32TransactionId > 23 + (8 * 2) + 1)
    147172                                {
     173                                    if (RT_ABS(iCpuHzDeviation) > RT_ABS(iCpuHzMaxDeviation))
     174                                        iCpuHzMaxDeviation = iCpuHzDeviation;
    148175                                    uCpuHzOverallDeviation += uCpuHzDeviation;
    149176                                    cCpuHzOverallDevCnt++;
     
    222249                    RTPrintf("tstGIP-2: offline: %lld\n", g_pSUPGlobalInfoPage->aCPUs[iCpu].i64TSCDelta);
    223250
    224             if (uCpuHzRef)
     251            RTPrintf("CPUID.Invariant-TSC    : %RTbool\n", tstIsInvariantTsc());
     252            if (   uCpuHzRef
     253                && cCpuHzOverallDevCnt)
    225254            {
    226                 uint32_t uPct = (uint32_t)(uCpuHzOverallDeviation * 100000 / cCpuHzOverallDevCnt / uCpuHzRef + 5);
    227                 RTPrintf("tstGIP-2: Overall CpuHz deviation: %d.%02d%%\n", uPct / 1000, (uPct % 1000) / 10);
     255                uint32_t uPct    = (uint32_t)(uCpuHzOverallDeviation * 100000 / cCpuHzOverallDevCnt / uCpuHzRef + 5);
     256                uint32_t uMaxPct = (uint32_t)(RT_ABS(iCpuHzMaxDeviation) * 100000 / uCpuHzRef + 5);
     257                RTPrintf("Average CpuHz deviation: %d.%02d%%\n", uPct / 1000, (uPct % 1000) / 10);
     258                RTPrintf("Maximum CpuHz deviation: %d.%02d%% (%RI64 ticks)\n", uMaxPct / 1000, (uMaxPct % 1000) / 10, iCpuHzMaxDeviation);
    228259            }
    229260        }
     
    240271    return !!rc;
    241272}
     273
  • trunk/src/VBox/Runtime/common/time/timesup.cpp

    r48935 r53430  
    55
    66/*
    7  * Copyright (C) 2006-2011 Oracle Corporation
     7 * Copyright (C) 2006-2014 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    124124    if (    pGip
    125125        &&  pGip->u32Magic == SUPGLOBALINFOPAGE_MAGIC
    126         &&  (   pGip->u32Mode == SUPGIPMODE_SYNC_TSC
     126        &&  (   pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC
     127             || pGip->u32Mode == SUPGIPMODE_SYNC_TSC
    127128             || pGip->u32Mode == SUPGIPMODE_ASYNC_TSC))
    128129        return rtTimeNanoTSInternalRediscover(pData);
     
    146147    if (    pGip
    147148        &&  pGip->u32Magic == SUPGLOBALINFOPAGE_MAGIC
    148         &&  (   pGip->u32Mode == SUPGIPMODE_SYNC_TSC
     149        &&  (   pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC
     150             || pGip->u32Mode == SUPGIPMODE_SYNC_TSC
    149151             || pGip->u32Mode == SUPGIPMODE_ASYNC_TSC))
    150152    {
    151153        if (ASMCpuId_EDX(1) & X86_CPUID_FEATURE_EDX_SSE2)
    152             iWorker = pGip->u32Mode == SUPGIPMODE_SYNC_TSC
     154            iWorker = pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC || pGip->u32Mode == SUPGIPMODE_SYNC_TSC
    153155                    ? RTTIMENANO_WORKER_SYNC_LFENCE
    154156                    : RTTIMENANO_WORKER_ASYNC_LFENCE;
    155157        else
    156             iWorker = pGip->u32Mode == SUPGIPMODE_SYNC_TSC
     158            iWorker = pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC || pGip->u32Mode == SUPGIPMODE_SYNC_TSC
    157159                    ? RTTIMENANO_WORKER_SYNC_CPUID
    158160                    : RTTIMENANO_WORKER_ASYNC_CPUID;
  • trunk/src/VBox/Runtime/common/time/timesupA.mac

    r44528 r53430  
    55
    66;
    7 ; Copyright (C) 2006-2011 Oracle Corporation
     7; Copyright (C) 2006-2014 Oracle Corporation
    88;
    99; This file is part of VirtualBox Open Source Edition (OSE), as
     
    126126    mov     u32UpdateIntervalTSC, edx
    127127    rdtsc
     128    SupTscDeltaApply edi        ; Apply inter-cpu TSC-delta to have the normalized TSC value in edx:eax
    128129    mov     ecx, [edi + SUPGIPCPU.u64NanoTS]
    129130    mov     u64CurNanoTS, ecx
     
    544545    mov     u32UpdateIntervalTSC, [pGipCPU + SUPGIPCPU.u32UpdateIntervalTSC]
    545546    rdtsc
     547    SUPTscDeltaApply pGipCPU
    546548    mov     u64PrevNanoTS,        [pData + RTTIMENANOTSDATA.pu64Prev]
    547549    mov     u64PrevNanoTS,        [u64PrevNanoTS]
  • trunk/src/VBox/Runtime/common/time/timesupref.h

    r44528 r53430  
    55
    66/*
    7  * Copyright (C) 2006-2011 Oracle Corporation
     7 * Copyright (C) 2006-2014 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
  • trunk/src/VBox/VMM/VMMAll/TMAllCpu.cpp

    r53325 r53430  
    55
    66/*
    7  * Copyright (C) 2006-2012 Oracle Corporation
     7 * Copyright (C) 2006-2014 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    6464    {
    6565        pVCpu->tm.s.fTSCTicking = true;
    66         if (pVM->tm.s.fTSCVirtualized)
    67         {
    68             /** @todo Test that pausing and resuming doesn't cause lag! (I.e. that we're
    69              *        unpaused before the virtual time and stopped after it. */
    70             if (pVM->tm.s.fTSCUseRealTSC)
    71                 pVCpu->tm.s.offTSCRawSrc = ASMReadTSC() - pVCpu->tm.s.u64TSC;
    72             else
    73                 pVCpu->tm.s.offTSCRawSrc = tmCpuTickGetRawVirtual(pVM, false /* don't check for pending timers */)
    74                                          - pVCpu->tm.s.u64TSC;
    75         }
     66
     67        /** @todo Test that pausing and resuming doesn't cause lag! (I.e. that we're
     68         *        unpaused before the virtual time and stopped after it. */
     69        if (pVM->tm.s.enmMode == TMMODE_REAL_TSC_OFFSET)
     70            pVCpu->tm.s.offTSCRawSrc = ASMReadTSC() - pVCpu->tm.s.u64TSC;
     71        else
     72            pVCpu->tm.s.offTSCRawSrc = tmCpuTickGetRawVirtual(pVM, false /* don't check for pending timers */)
     73                                     - pVCpu->tm.s.u64TSC;
    7674        return VINF_SUCCESS;
    7775    }
     
    9492        /* TSC must be ticking before calling tmCpuTickGetRawVirtual()! */
    9593        pVCpu->tm.s.fTSCTicking = true;
    96         if (pVM->tm.s.fTSCVirtualized)
    97         {
    98             uint32_t c = ASMAtomicIncU32(&pVM->tm.s.cTSCsTicking);
    99             AssertMsgReturn(c <= pVM->cCpus, ("%u vs %u\n", c, pVM->cCpus), VERR_TM_VIRTUAL_TICKING_IPE);
    100             if (c == 1)
    101             {
    102                 /* The first VCPU to resume. */
    103                 uint64_t    offTSCRawSrcOld = pVCpu->tm.s.offTSCRawSrc;
    104 
    105                 STAM_COUNTER_INC(&pVM->tm.s.StatTSCResume);
    106 
    107                 /* When resuming, use the TSC value of the last stopped VCPU to avoid the TSC going back. */
    108                 if (pVM->tm.s.fTSCUseRealTSC)
    109                     pVCpu->tm.s.offTSCRawSrc = ASMReadTSC() - pVM->tm.s.u64LastPausedTSC;
    110                 else
    111                     pVCpu->tm.s.offTSCRawSrc = tmCpuTickGetRawVirtual(pVM, false /* don't check for pending timers */)
    112                                              - pVM->tm.s.u64LastPausedTSC;
    113 
    114                 /* Calculate the offset for other VCPUs to use. */
    115                 pVM->tm.s.offTSCPause = pVCpu->tm.s.offTSCRawSrc - offTSCRawSrcOld;
    116             }
     94        uint32_t c = ASMAtomicIncU32(&pVM->tm.s.cTSCsTicking);
     95        AssertMsgReturn(c <= pVM->cCpus, ("%u vs %u\n", c, pVM->cCpus), VERR_TM_VIRTUAL_TICKING_IPE);
     96        if (c == 1)
     97        {
     98            /* The first VCPU to resume. */
     99            uint64_t    offTSCRawSrcOld = pVCpu->tm.s.offTSCRawSrc;
     100
     101            STAM_COUNTER_INC(&pVM->tm.s.StatTSCResume);
     102
     103            /* When resuming, use the TSC value of the last stopped VCPU to avoid the TSC going back. */
     104            if (pVM->tm.s.enmMode == TMMODE_REAL_TSC_OFFSET)
     105                pVCpu->tm.s.offTSCRawSrc = ASMReadTSC() - pVM->tm.s.u64LastPausedTSC;
    117106            else
    118             {
    119                 /* All other VCPUs (if any). */
    120                 pVCpu->tm.s.offTSCRawSrc += pVM->tm.s.offTSCPause;
    121             }
     107                pVCpu->tm.s.offTSCRawSrc = tmCpuTickGetRawVirtual(pVM, false /* don't check for pending timers */)
     108                                         - pVM->tm.s.u64LastPausedTSC;
     109
     110            /* Calculate the offset for other VCPUs to use. */
     111            pVM->tm.s.offTSCPause = pVCpu->tm.s.offTSCRawSrc - offTSCRawSrcOld;
     112        }
     113        else
     114        {
     115            /* All other VCPUs (if any). */
     116            pVCpu->tm.s.offTSCRawSrc += pVM->tm.s.offTSCPause;
    122117        }
    123118    }
     
    187182{
    188183    /* Sample the reason for refusing. */
    189     if (!pVM->tm.s.fMaybeUseOffsettedHostTSC)
     184    if (pVM->tm.s.enmMode != TMMODE_DYNAMIC)
    190185       STAM_COUNTER_INC(&pVM->tm.s.StatTSCNotFixed);
    191186    else if (!pVCpu->tm.s.fTSCTicking)
    192187       STAM_COUNTER_INC(&pVM->tm.s.StatTSCNotTicking);
    193     else if (!pVM->tm.s.fTSCUseRealTSC)
     188    else if (pVM->tm.s.enmMode != TMMODE_REAL_TSC_OFFSET)
    194189    {
    195190        if (pVM->tm.s.fVirtualSyncCatchUp)
     
    240235     */
    241236    *pfParavirtTsc = GIMIsParavirtTscEnabled(pVM);
    242     if (    pVM->tm.s.fMaybeUseOffsettedHostTSC
     237    if (    pVM->tm.s.enmMode == TMMODE_DYNAMIC
    243238        &&  RT_LIKELY(pVCpu->tm.s.fTSCTicking)
    244         &&  (   pVM->tm.s.fTSCUseRealTSC
     239        &&  (   pVM->tm.s.enmMode == TMMODE_REAL_TSC_OFFSET
    245240             || (   !pVM->tm.s.fVirtualSyncCatchUp
    246241                 && RT_LIKELY(pVM->tm.s.fVirtualSyncTicking)
    247242                 && !pVM->tm.s.fVirtualWarpDrive)))
    248243    {
    249         if (!pVM->tm.s.fTSCUseRealTSC)
     244        if (pVM->tm.s.enmMode != TMMODE_REAL_TSC_OFFSET)
    250245        {
    251246            /* The source is the timer synchronous virtual clock. */
    252             Assert(pVM->tm.s.fTSCVirtualized);
    253 
    254247            if (poffRealTSC)
    255248            {
     
    266259        {
    267260            /* The source is the real TSC. */
    268             if (pVM->tm.s.fTSCVirtualized)
    269                 *poffRealTSC = 0 - pVCpu->tm.s.offTSCRawSrc;
    270             else
    271                 *poffRealTSC = 0;
     261            *poffRealTSC = 0 - pVCpu->tm.s.offTSCRawSrc;
    272262        }
    273263        /** @todo count this? */
     
    339329     */
    340330    *pfParavirtTsc = GIMIsParavirtTscEnabled(pVM);
    341     if (    pVM->tm.s.fMaybeUseOffsettedHostTSC
     331    if (    pVM->tm.s.enmMode == TMMODE_DYNAMIC
    342332        &&  RT_LIKELY(pVCpu->tm.s.fTSCTicking)
    343         &&  (   pVM->tm.s.fTSCUseRealTSC
     333        &&  (   pVM->tm.s.enmMode == TMMODE_REAL_TSC_OFFSET
    344334             || (   !pVM->tm.s.fVirtualSyncCatchUp
    345335                 && RT_LIKELY(pVM->tm.s.fVirtualSyncTicking)
     
    347337    {
    348338        *pfOffsettedTsc = true;
    349         if (!pVM->tm.s.fTSCUseRealTSC)
     339        if (pVM->tm.s.enmMode != TMMODE_REAL_TSC_OFFSET)
    350340        {
    351341            /* The source is the timer synchronous virtual clock. */
    352             Assert(pVM->tm.s.fTSCVirtualized);
    353 
    354342            uint64_t cNsToDeadline;
    355343            uint64_t u64NowVirtSync = TMVirtualSyncGetWithDeadlineNoCheck(pVM, &cNsToDeadline);
     
    364352        {
    365353            /* The source is the real TSC. */
    366             if (pVM->tm.s.fTSCVirtualized)
    367                 *poffRealTSC = 0 - pVCpu->tm.s.offTSCRawSrc;
    368             else
    369                 *poffRealTSC = 0;
     354            *poffRealTSC = 0 - pVCpu->tm.s.offTSCRawSrc;
    370355            cTicksToDeadline = tmCpuCalcTicksToDeadline(TMVirtualSyncGetNsToDeadline(pVM));
    371356        }
     
    398383    {
    399384        PVM pVM = pVCpu->CTX_SUFF(pVM);
    400         if (pVM->tm.s.fTSCVirtualized)
    401         {
    402             if (pVM->tm.s.fTSCUseRealTSC)
    403                 u64 = ASMReadTSC();
    404             else
    405                 u64 = tmCpuTickGetRawVirtual(pVM, fCheckTimers);
    406             u64 -= pVCpu->tm.s.offTSCRawSrc;
    407         }
     385        if (pVM->tm.s.enmMode == TMMODE_REAL_TSC_OFFSET)
     386            u64 = ASMReadTSC();
    408387        else
    409             u64 = ASMReadTSC();
     388            u64 = tmCpuTickGetRawVirtual(pVM, fCheckTimers);
     389        u64 -= pVCpu->tm.s.offTSCRawSrc;
    410390
    411391        /* Always return a value higher than what the guest has already seen. */
     
    523503VMMDECL(uint64_t) TMCpuTicksPerSecond(PVM pVM)
    524504{
    525     if (pVM->tm.s.fTSCUseRealTSC)
     505    /** @todo revisit this, not sure why we need to get the rate from GIP for
     506     *        real-tsc-offset. */
     507    if (pVM->tm.s.enmMode == TMMODE_REAL_TSC_OFFSET)
    526508    {
    527509        uint64_t cTSCTicksPerSecond = SUPGetCpuHzFromGIP(g_pSUPGlobalInfoPage);
  • trunk/src/VBox/VMM/VMMR3/TM.cpp

    r53326 r53430  
    55
    66/*
    7  * Copyright (C) 2006-2013 Oracle Corporation
     7 * Copyright (C) 2006-2014 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    167167*******************************************************************************/
    168168static bool                 tmR3HasFixedTSC(PVM pVM);
     169static const char *         tmR3GetModeName(PVM pVM);
    169170static uint64_t             tmR3CalibrateTSC(PVM pVM);
    170171static DECLCALLBACK(int)    tmR3Save(PVM pVM, PSSMHANDLE pSSM);
     
    271272    if (ASMCpuId_EDX(1) & X86_CPUID_FEATURE_EDX_SSE2)
    272273    {
    273         if (g_pSUPGlobalInfoPage->u32Mode == SUPGIPMODE_SYNC_TSC)
     274        if (   g_pSUPGlobalInfoPage->u32Mode == SUPGIPMODE_INVARIANT_TSC
     275            || g_pSUPGlobalInfoPage->u32Mode == SUPGIPMODE_SYNC_TSC)
    274276            pVM->tm.s.pfnVirtualGetRawR3 = RTTimeNanoTSLFenceSync;
    275277        else
     
    278280    else
    279281    {
    280         if (g_pSUPGlobalInfoPage->u32Mode == SUPGIPMODE_SYNC_TSC)
     282        if (   g_pSUPGlobalInfoPage->u32Mode == SUPGIPMODE_INVARIANT_TSC
     283            || g_pSUPGlobalInfoPage->u32Mode == SUPGIPMODE_SYNC_TSC)
    281284            pVM->tm.s.pfnVirtualGetRawR3 = RTTimeNanoTSLegacySync;
    282285        else
     
    310313
    311314    /*
     315     * Handle deprecated TM settings.
     316     */
     317    do
     318    {
     319        /** @todo make these runtime warnings instead of errors that refuse to start
     320         *        the VM? */
     321        bool fTSCVirtualized;
     322        rc = CFGMR3QueryBool(pCfgHandle, "TSCVirtualized", &fTSCVirtualized);
     323        if (RT_SUCCESS(rc))
     324            return VMSetError(pVM, VERR_CFGM_CONFIG_UNKNOWN_VALUE, RT_SRC_POS,
     325                              N_("Configuration error: TM setting \"TSCVirtualized\" is no longer supported. Use the \"Mode\" setting instead."));
     326
     327        bool fForceUseRealTSC;
     328        rc = CFGMR3QueryBool(pCfgHandle, "UseRealTSC", &fForceUseRealTSC);
     329        if (RT_SUCCESS(rc))
     330            return VMSetError(pVM, VERR_CFGM_CONFIG_UNKNOWN_VALUE, RT_SRC_POS,
     331                              N_("Configuration error: TM setting \"UseRealTSC\" is no longer supported. Use the \"Mode\" setting instead."));
     332
     333        bool fMaybeUseOffsettedHostTSC;
     334        rc = CFGMR3QueryBool(pCfgHandle, "MaybeUseOffsettedHostTSC", &fMaybeUseOffsettedHostTSC);
     335        if (RT_SUCCESS(rc))
     336            return VMSetError(pVM, VERR_CFGM_CONFIG_UNKNOWN_VALUE, RT_SRC_POS,
     337                              N_("Configuration error: TM setting \"MaybeUseOffsettedHostTSC\" is no longer supported. Use the \"Mode\" setting instead."));
     338    } while(0);
     339
     340    /*
     341     * Validate the rest of the TM settings.
     342     */
     343    if (!CFGMR3AreValuesValid(pCfgHandle,
     344                              "Mode\0"
     345                              "TSCTicksPerSecond\0"
     346                              "TSCTiedToExecution\0"
     347                              "TSCNotTiedToHalt\0"
     348                              "ScheduleSlack\0"
     349                              "CatchUpStopThreshold\0"
     350                              "CatchUpGiveUpThreshold\0"
     351                              "CatchUpStartThreshold\0"
     352                              "CatchUpPrecentage\0"
     353                              "UTCOffset\0"
     354                              "WarpDrivePercentage\0"
     355                              "HostHzMax\0"
     356                              "HostHzFudgeFactorTimerCpu\0"
     357                              "HostHzFudgeFactorOtherCpu\0"
     358                              "HostHzFudgeFactorCatchUp100\0"
     359                              "HostHzFudgeFactorCatchUp200\0"
     360                              "HostHzFudgeFactorCatchUp400\0"
     361                              "TimerMillies\0"
     362                              ))
     363        return VMSetError(pVM, VERR_CFGM_CONFIG_UNKNOWN_NODE, RT_SRC_POS, N_("Configuration error: Invalid config key for TM."));
     364
     365    /*
    312366     * Determine the TSC configuration and frequency.
    313367     */
    314     /* mode */
    315     /** @cfgm{/TM/TSCVirtualized,bool,true}
    316      * Use a virtualize TSC, i.e. trap all TSC access. */
    317     rc = CFGMR3QueryBool(pCfgHandle, "TSCVirtualized", &pVM->tm.s.fTSCVirtualized);
     368    /** @cfgm{/TM/Mode, string}
     369     *  The name of the time-keeping mode. The default is picked dynamically based
     370     *  on configuration of the VM. */
     371    char szMode[32];
     372    rc = CFGMR3QueryString(pCfgHandle, "Mode", szMode, sizeof(szMode));
    318373    if (rc == VERR_CFGM_VALUE_NOT_FOUND)
    319         pVM->tm.s.fTSCVirtualized = true; /* trap rdtsc */
     374        pVM->tm.s.enmMode = tmR3HasFixedTSC(pVM) ? TMMODE_DYNAMIC : TMMODE_VIRT_TSC_EMULATED;
    320375    else if (RT_FAILURE(rc))
    321         return VMSetError(pVM, rc, RT_SRC_POS,
    322                           N_("Configuration error: Failed to querying bool value \"UseRealTSC\""));
    323 
    324     /* source */
    325     /** @cfgm{/TM/UseRealTSC,bool,false}
    326      * Use the real TSC as time source for the TSC instead of the synchronous
    327      * virtual clock (false, default). */
    328     rc = CFGMR3QueryBool(pCfgHandle, "UseRealTSC", &pVM->tm.s.fTSCUseRealTSC);
    329     if (rc == VERR_CFGM_VALUE_NOT_FOUND)
    330         pVM->tm.s.fTSCUseRealTSC = false; /* use virtual time */
    331     else if (RT_FAILURE(rc))
    332         return VMSetError(pVM, rc, RT_SRC_POS,
    333                           N_("Configuration error: Failed to querying bool value \"UseRealTSC\""));
    334     if (!pVM->tm.s.fTSCUseRealTSC)
    335         pVM->tm.s.fTSCVirtualized = true;
    336 
    337     /* TSC reliability */
    338     /** @cfgm{/TM/MaybeUseOffsettedHostTSC,bool,detect}
    339      * Whether the CPU has a fixed TSC rate and may be used in offsetted mode with
    340      * VT-x/AMD-V execution.  This is autodetected in a very restrictive way by
    341      * default. */
    342     rc = CFGMR3QueryBool(pCfgHandle, "MaybeUseOffsettedHostTSC", &pVM->tm.s.fMaybeUseOffsettedHostTSC);
    343     if (rc == VERR_CFGM_VALUE_NOT_FOUND)
    344     {
    345         if (!pVM->tm.s.fTSCUseRealTSC)
    346             pVM->tm.s.fMaybeUseOffsettedHostTSC = tmR3HasFixedTSC(pVM);
     376        return VMSetError(pVM, rc, RT_SRC_POS, N_("Configuration error: Failed to querying string value \"Mode\""));
     377    else
     378    {
     379        AssertRC(rc);
     380        if (!RTStrCmp(szMode, "VirtTSCEmulated"))
     381            pVM->tm.s.enmMode = TMMODE_VIRT_TSC_EMULATED;
     382        else if (!RTStrCmp(szMode, "RealTSCOffset"))
     383            pVM->tm.s.enmMode = TMMODE_REAL_TSC_OFFSET;
     384        else if (!RTStrCmp(szMode, "Dynamic"))
     385            pVM->tm.s.enmMode = TMMODE_DYNAMIC;
    347386        else
    348             pVM->tm.s.fMaybeUseOffsettedHostTSC = true;
    349         /** @todo needs a better fix, for now disable offsetted mode for VMs
    350          * with more than one VCPU. With the current TSC handling (frequent
    351          * switching between offsetted mode and taking VM exits, on all VCPUs
    352          * without any kind of coordination) it will lead to inconsistent TSC
    353          * behavior with guest SMP, including TSC going backwards. */
    354         if (   pVM->cCpus != 1
    355             && !pVM->tm.s.fTSCUseRealTSC)
    356             pVM->tm.s.fMaybeUseOffsettedHostTSC = false;
    357     }
     387            return VMSetError(pVM, rc, RT_SRC_POS, N_("Configuration error: Unrecognized TM mode value \"%s\""), szMode);
     388    }
     389
     390    /** @todo needs a better fix, for now disable offsetted mode for VMs
     391     * with more than one VCPU. With the current TSC handling (frequent
     392     * switching between offsetted mode and taking VM exits, on all VCPUs
     393     * without any kind of coordination) it will lead to inconsistent TSC
     394     * behavior with guest SMP, including TSC going backwards. */
     395    if (   pVM->cCpus != 1
     396        && pVM->tm.s.enmMode != TMMODE_REAL_TSC_OFFSET)
     397        pVM->tm.s.enmMode = TMMODE_VIRT_TSC_EMULATED;
    358398
    359399    /** @cfgm{/TM/TSCTicksPerSecond, uint32_t, Current TSC frequency from GIP}
    360400     * The number of TSC ticks per second (i.e. the TSC frequency). This will
    361      * override TSCUseRealTSC, TSCVirtualized and MaybeUseOffsettedHostTSC.
     401     * override TSCtTSC, TSCVirtualized and MaybeUseOffsettedHostTSC.
    362402     */
    363403    rc = CFGMR3QueryU64(pCfgHandle, "TSCTicksPerSecond", &pVM->tm.s.cTSCTicksPerSecond);
     
    365405    {
    366406        pVM->tm.s.cTSCTicksPerSecond = tmR3CalibrateTSC(pVM);
    367         if (    !pVM->tm.s.fTSCUseRealTSC
    368             &&  pVM->tm.s.cTSCTicksPerSecond >= _4G)
     407        if (   pVM->tm.s.enmMode != TMMODE_REAL_TSC_OFFSET
     408            && pVM->tm.s.cTSCTicksPerSecond >= _4G)
    369409        {
    370410            pVM->tm.s.cTSCTicksPerSecond = _4G - 1; /* (A limitation of our math code) */
    371             pVM->tm.s.fMaybeUseOffsettedHostTSC = false;
     411            pVM->tm.s.enmMode = TMMODE_VIRT_TSC_EMULATED;
    372412        }
    373413    }
     
    382422    else
    383423    {
    384         pVM->tm.s.fTSCUseRealTSC = pVM->tm.s.fMaybeUseOffsettedHostTSC = false;
    385         pVM->tm.s.fTSCVirtualized = true;
     424        pVM->tm.s.enmMode = TMMODE_VIRT_TSC_EMULATED;
    386425    }
    387426
     
    398437                          N_("Configuration error: Failed to querying bool value \"TSCTiedToExecution\""));
    399438    if (pVM->tm.s.fTSCTiedToExecution)
    400     {
    401         /* tied to execution, override all other settings. */
    402         pVM->tm.s.fTSCVirtualized = true;
    403         pVM->tm.s.fTSCUseRealTSC = true;
    404         pVM->tm.s.fMaybeUseOffsettedHostTSC = false;
    405     }
     439        pVM->tm.s.enmMode = TMMODE_VIRT_TSC_EMULATED;
    406440
    407441    /** @cfgm{/TM/TSCNotTiedToHalt, bool, true}
     
    412446        return VMSetError(pVM, rc, RT_SRC_POS,
    413447                          N_("Configuration error: Failed to querying bool value \"TSCNotTiedToHalt\""));
    414 
    415     /* setup and report */
    416     if (pVM->tm.s.fTSCVirtualized)
    417         CPUMR3SetCR4Feature(pVM, X86_CR4_TSD, ~X86_CR4_TSD);
    418     else
    419         CPUMR3SetCR4Feature(pVM, 0, ~X86_CR4_TSD);
    420     LogRel(("TM: cTSCTicksPerSecond=%#RX64 (%'RU64) fTSCVirtualized=%RTbool fTSCUseRealTSC=%RTbool\n"
    421             "TM: fMaybeUseOffsettedHostTSC=%RTbool TSCTiedToExecution=%RTbool TSCNotTiedToHalt=%RTbool\n",
    422             pVM->tm.s.cTSCTicksPerSecond, pVM->tm.s.cTSCTicksPerSecond, pVM->tm.s.fTSCVirtualized, pVM->tm.s.fTSCUseRealTSC,
    423             pVM->tm.s.fMaybeUseOffsettedHostTSC, pVM->tm.s.fTSCTiedToExecution, pVM->tm.s.fTSCNotTiedToHalt));
    424448
    425449    /*
     
    525549    pVM->tm.s.fVirtualWarpDrive = pVM->tm.s.u32VirtualWarpDrivePercentage != 100;
    526550    if (pVM->tm.s.fVirtualWarpDrive)
    527         LogRel(("TM: u32VirtualWarpDrivePercentage=%RI32\n", pVM->tm.s.u32VirtualWarpDrivePercentage));
     551    {
     552        pVM->tm.s.enmMode = TMMODE_VIRT_TSC_EMULATED;
     553        LogRel(("TM: Warp-drive active. u32VirtualWarpDrivePercentage=%RI32\n", pVM->tm.s.u32VirtualWarpDrivePercentage));
     554    }
     555
     556    /* Setup and report */
     557    CPUMR3SetCR4Feature(pVM, X86_CR4_TSD, ~X86_CR4_TSD);
     558    LogRel(("TM: cTSCTicksPerSecond=%#RX64 (%'RU64) enmMode=%d (%s)\n"
     559            "TM: TSCTiedToExecution=%RTbool TSCNotTiedToHalt=%RTbool\n",
     560            pVM->tm.s.cTSCTicksPerSecond, pVM->tm.s.cTSCTicksPerSecond, pVM->tm.s.enmMode, tmR3GetModeName(pVM),
     561            pVM->tm.s.fTSCTiedToExecution, pVM->tm.s.fTSCNotTiedToHalt));
    528562
    529563    /*
     
    776810static bool tmR3HasFixedTSC(PVM pVM)
    777811{
     812    PSUPGLOBALINFOPAGE pGip = g_pSUPGlobalInfoPage;
     813    if (pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC)
     814        return true;
     815
    778816    if (ASMHasCpuId())
    779817    {
     
    782820        if (CPUMGetHostCpuVendor(pVM) == CPUMCPUVENDOR_AMD)
    783821        {
     822            /** @todo This is redundant as it would get satisified in the invariant case
     823             *        above. Remove later or keep around for sync mode override?  */
    784824            /*
    785825             * AuthenticAMD - Check for APM support and that TscInvariant is set.
     
    792832            if (uEAX >= 0x80000007)
    793833            {
    794                 PSUPGLOBALINFOPAGE pGip = g_pSUPGlobalInfoPage;
    795 
    796834                ASMCpuId(0x80000007, &uEAX, &uEBX, &uECX, &uEDX);
    797835                if (   (uEDX & X86_CPUID_AMD_ADVPOWER_EDX_TSCINVAR) /* TscInvariant */
    798                     && pGip->u32Mode == SUPGIPMODE_SYNC_TSC /* no fixed tsc if the gip timer is in async mode */)
     836                    && (   pGip->u32Mode == SUPGIPMODE_SYNC_TSC     /* No fixed tsc if the gip timer is in async mode. */
     837                        || pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC))
    799838                    return true;
    800839            }
     
    852891{
    853892    /*
    854      * Use GIP when available present.
     893     * Use GIP when available.
    855894     */
    856895    uint64_t u64Hz = SUPGetCpuHzFromGIP(g_pSUPGlobalInfoPage);
     896    if (g_pSUPGlobalInfoPage->u32Mode == SUPGIPMODE_INVARIANT_TSC)
     897    {
     898        Assert(u64Hz != UINT64_MAX);
     899        return u64Hz;
     900    }
     901
    857902    if (u64Hz != UINT64_MAX)
    858903    {
     
    864909            /* Spin for 40ms to try push up the CPU frequency and get a more reliable CpuHz value. */
    865910            const uint64_t u64 = RTTimeMilliTS();
    866             while ((RTTimeMilliTS() - u64) < 40 /*ms*/)
     911            while ((RTTimeMilliTS() - u64) < 40 /* ms */)
    867912                /* nothing */;
    868913        }
     
    873918    }
    874919
    875     /* call this once first to make sure it's initialized. */
     920    /* Call this once first to make sure it's initialized. */
    876921    RTTimeNanoTS();
    877922
     
    12781323            pVM->tm.s.u64LastPausedTSC = pVCpu->tm.s.u64TSC;
    12791324
    1280         if (pVM->tm.s.fTSCUseRealTSC)
     1325        if (pVM->tm.s.enmMode == TMMODE_REAL_TSC_OFFSET)
    12811326            pVCpu->tm.s.offTSCRawSrc = 0; /** @todo TSC restore stuff and HWACC. */
    12821327    }
     
    12851330    if (RT_FAILURE(rc))
    12861331        return rc;
    1287     if (!pVM->tm.s.fTSCUseRealTSC)
     1332    if (pVM->tm.s.enmMode != TMMODE_REAL_TSC_OFFSET)
    12881333        pVM->tm.s.cTSCTicksPerSecond = u64Hz;
    1289 
    1290     LogRel(("TM: cTSCTicksPerSecond=%#RX64 (%'RU64) fTSCVirtualized=%RTbool fTSCUseRealTSC=%RTbool (state load)\n",
    1291             pVM->tm.s.cTSCTicksPerSecond, pVM->tm.s.cTSCTicksPerSecond, pVM->tm.s.fTSCVirtualized, pVM->tm.s.fTSCUseRealTSC));
     1334    /** @todo Compare with real TSC rate even when restoring with real-tsc-offset
     1335     *        mode. */
     1336
     1337    LogRel(("TM: cTSCTicksPerSecond=%#RX64 (%'RU64) enmMode=%d (%s) (state load)\n",
     1338            pVM->tm.s.cTSCTicksPerSecond, pVM->tm.s.cTSCTicksPerSecond, pVM->tm.s.enmMode, tmR3GetModeName(pVM)));
    12921339
    12931340    /*
     
    28032850        TMR3NotifySuspend(pVM, pVCpu);
    28042851
     2852    /** @todo should probably switch TM mode to virt-tsc-emulated if it isn't
     2853     *        already. */
    28052854    pVM->tm.s.u32VirtualWarpDrivePercentage = u32Percent;
    28062855    pVM->tm.s.fVirtualWarpDrive = u32Percent != 100;
     
    31483197         */
    31493198        pHlp->pfnPrintf(pHlp,
    3150                         "Cpu Tick: %18RU64 (%#016RX64) %RU64Hz %s%s",
     3199                        "Cpu Tick: %18RU64 (%#016RX64) %RU64Hz %s - virtualized",
    31513200                        u64TSC, u64TSC, TMCpuTicksPerSecond(pVM),
    3152                         pVCpu->tm.s.fTSCTicking ? "ticking" : "paused",
    3153                         pVM->tm.s.fTSCVirtualized ? " - virtualized" : "");
    3154         if (pVM->tm.s.fTSCUseRealTSC)
     3201                        pVCpu->tm.s.fTSCTicking ? "ticking" : "paused");
     3202        if (pVM->tm.s.enmMode == TMMODE_REAL_TSC_OFFSET)
    31553203        {
    3156             pHlp->pfnPrintf(pHlp, " - real tsc");
     3204            pHlp->pfnPrintf(pHlp, " - real tsc offset");
    31573205            if (pVCpu->tm.s.offTSCRawSrc)
    31583206                pHlp->pfnPrintf(pHlp, "\n          offset %RU64", pVCpu->tm.s.offTSCRawSrc);
     
    31983246}
    31993247
     3248
     3249/**
     3250 * Gets the descriptive TM mode name.
     3251 *
     3252 * @returns The name.
     3253 * @param   pVM      Pointer to the VM.
     3254 */
     3255static const char * tmR3GetModeName(PVM pVM)
     3256{
     3257    Assert(pVM);
     3258    switch (pVM->tm.s.enmMode)
     3259    {
     3260        case TMMODE_REAL_TSC_OFFSET:    return "RealTscOffset";
     3261        case TMMODE_VIRT_TSC_EMULATED:  return "VirtTscEmulated";
     3262        case TMMODE_DYNAMIC:            return "Dynamic";
     3263        default:                        return "?????";
     3264    }
     3265}
     3266
  • trunk/src/VBox/VMM/include/TMInternal.h

    r52764 r53430  
    55
    66/*
    7  * Copyright (C) 2006-2012 Oracle Corporation
     7 * Copyright (C) 2006-2014 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    316316typedef TMCPULOADSTATE *PTMCPULOADSTATE;
    317317
     318
     319/**
     320 * TM mode.
     321 * The main modes of how TM abstracts time.
     322 */
     323typedef enum TMMODE
     324{
     325    /** The guest TSC is an emulated virtual TSC. */
     326    TMMODE_VIRT_TSC_EMULATED = 1,
     327    /** The guest TSC is an offset of the real TSC. */
     328    TMMODE_REAL_TSC_OFFSET,
     329    /** The guest TSC is dynamically derived through emulation or offsetting. */
     330    TMMODE_DYNAMIC
     331} TMMODE;
     332
     333
    318334/**
    319335 * Converts a TM pointer into a VM pointer.
     
    334350    RTUINT                      offVM;
    335351
    336     /** Set if we fully virtualize the TSC, i.e. intercept all rdtsc instructions.
    337      * Config variable: TSCVirtualized (bool) */
    338     bool                        fTSCVirtualized;
    339     /** Set if we use the real TSC as time source or if we use the virtual clock.
    340      * If fTSCVirtualized is set we maintain a offset to the TSC and pausing/resuming the
    341      * ticking. fTSCVirtualized = false implies fTSCUseRealTSC = true.
    342      * Config variable: TSCUseRealTSC (bool) */
    343     bool                        fTSCUseRealTSC;
    344     /** Flag indicating that the host TSC is suitable for use in AMD-V and VT-x mode.
    345      * Config variable: MaybeUseOffsettedHostTSC (boolean) */
    346     bool                        fMaybeUseOffsettedHostTSC;
     352    /** The current timekeeping mode of the VM.
     353     *  Config variable: Mode (string) */
     354    TMMODE                      enmMode;
    347355    /** Whether the TSC is tied to the execution of code.
    348356     * Config variable: TSCTiedToExecution (bool) */
     
    351359     * Config variable: TSCNotTiedToHalt (bool) */
    352360    bool                        fTSCNotTiedToHalt;
    353     bool                        afAlignment0[2]; /**< alignment padding */
     361    /** Alignment. */
     362    bool                        afAlignment0[2];
    354363    /** The ID of the virtual CPU that normally runs the timers. */
    355364    VMCPUID                     idTimerCpu;
     
    357366    /** The number of CPU clock ticks per second (TMCLOCK_TSC).
    358367     * Config variable: TSCTicksPerSecond (64-bit unsigned int)
    359      * The config variable implies fTSCVirtualized = true and fTSCUseRealTSC = false. */
     368     * The config variable implies @c enmMode would be
     369     * TMMODE_VIRT_TSC_EMULATED. */
    360370    uint64_t                    cTSCTicksPerSecond;
    361371    /** The TSC difference introduced by pausing the VM. */
     
    374384    /** Virtual timer synchronous time catch-up active. */
    375385    bool volatile               fVirtualSyncCatchUp;
    376     bool                        afAlignment1[1]; /**< alignment padding */
     386    /** Alignment. */
     387    bool                        afAlignment1[1];
    377388    /** WarpDrive percentage.
    378389     * 100% is normal (fVirtualSyncNormal == true). When other than 100% we apply
     
    781792    Assert(PDMCritSectIsOwner(&(a_pVM)->tm.s.TimerCritSect))
    782793
    783 
    784794/** @} */
    785795
  • trunk/src/VBox/VMM/testcase/tstVMStruct.h

    r51301 r53430  
    88
    99/*
    10  * Copyright (C) 2006-2013 Oracle Corporation
     10 * Copyright (C) 2006-2014 Oracle Corporation
    1111 *
    1212 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    10111011    GEN_CHECK_OFF(TM, pvGIPRC);
    10121012    GEN_CHECK_OFF(TMCPU, fTSCTicking);
    1013     GEN_CHECK_OFF(TM, fTSCUseRealTSC);
     1013    GEN_CHECK_OFF(TM, enmMode);
    10141014    GEN_CHECK_OFF(TM, fTSCTiedToExecution);
    10151015    GEN_CHECK_OFF(TMCPU, offTSCRawSrc);
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette