VirtualBox

Ignore:
Timestamp:
Feb 20, 2015 6:10:12 PM (10 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
98427
Message:

SUPDrv,VMM: Added SUPR0TscDeltaMeasureBySetIndex to SUPDrv (bumping version req) so that VMMR0.cpp can, if necessary, trigger a delta measurement prior to doing RC and HM stuff. Also, made the context hook set the return-to-ring3 force flag if we're rescheduled on a CPU with an TSC delta needing measuring. This is probably code that will almost never get called...

Location:
trunk/src/VBox/HostDrivers/Support
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/HostDrivers/Support/SUPDrv.cpp

    r54331 r54339  
    180180    { "SUPR0PageFree",                          (void *)SUPR0PageFree },
    181181    { "SUPR0Printf",                            (void *)SUPR0Printf },
     182    { "SUPR0TscDeltaMeasureBySetIndex",         (void *)SUPR0TscDeltaMeasureBySetIndex },
    182183    { "SUPR0TracerDeregisterDrv",               (void *)SUPR0TracerDeregisterDrv },
    183184    { "SUPR0TracerDeregisterImpl",              (void *)SUPR0TracerDeregisterImpl },
  • trunk/src/VBox/HostDrivers/Support/SUPDrvGip.cpp

    r54334 r54339  
    27932793 *
    27942794 * @returns VBox status code.
     2795 * @retval  VERR_SUPDRV_TSC_DELTA_MEASUREMENT_FAILED on pure measurement
     2796 *          failure.
    27952797 * @param   pDevExt         Pointer to the device instance data.
    27962798 * @param   idxWorker       The index of the worker CPU from the GIP's array of
     
    34033405}
    34043406
    3405 
    34063407#endif /* SUPDRV_USE_TSC_DELTA_THREAD */
     3408
     3409/**
     3410 * Measure the TSC delta for the CPU given by its CPU set index.
     3411 *
     3412 * @returns VBox status code.
     3413 * @retval  VERR_INTERRUPTED if interrupted while waiting.
     3414 * @retval  VERR_SUPDRV_TSC_DELTA_MEASUREMENT_FAILED if we were unable to get a
     3415 *          measurment.
     3416 * @retval  VERR_CPU_OFFLINE if the specified CPU is offline.
     3417 * @retval  VERR_CPU_OFFLINE if the specified CPU is offline.
     3418 *
     3419 * @param   pSession        The caller's session.  GIP must've been mapped.
     3420 * @param   iCpuSet         The CPU set index of the CPU to measure.
     3421 * @param   fFlags          Flags, SUP_TSCDELTA_MEASURE_F_XXX.
     3422 * @param   cMsWaitRetry    Number of milliseconds to wait between each retry.
     3423 * @param   cMsWaitThread   Number of milliseconds to wait for the thread to get
     3424 *                          ready.
     3425 * @param   cTries          Number of times to try, pass 0 for the default.
     3426 */
     3427SUPR0DECL(int) SUPR0TscDeltaMeasureBySetIndex(PSUPDRVSESSION pSession, uint32_t iCpuSet, uint32_t fFlags,
     3428                                              RTMSINTERVAL cMsWaitRetry, RTMSINTERVAL cMsWaitThread, uint32_t cTries)
     3429{
     3430    PSUPDRVDEVEXT       pDevExt;
     3431    PSUPGLOBALINFOPAGE  pGip;
     3432    uint16_t            iGipCpu;
     3433    int                 rc;
     3434#ifdef SUPDRV_USE_TSC_DELTA_THREAD
     3435    uint64_t            msTsStartWait;
     3436    uint32_t            iWaitLoop;
     3437#endif
     3438
     3439    /*
     3440     * Validate and adjust the input.
     3441     */
     3442    AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
     3443    if (!pSession->fGipReferenced)
     3444        return VERR_WRONG_ORDER;
     3445
     3446    pDevExt = pSession->pDevExt;
     3447    AssertReturn(SUP_IS_DEVEXT_VALID(pDevExt), VERR_INVALID_PARAMETER);
     3448
     3449    pGip = pDevExt->pGip;
     3450    AssertPtrReturn(pGip, VERR_INTERNAL_ERROR_2);
     3451
     3452    AssertReturn(iCpuSet < RTCPUSET_MAX_CPUS, VERR_INVALID_CPU_INDEX);
     3453    AssertReturn(iCpuSet < RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx), VERR_INVALID_CPU_INDEX);
     3454    iGipCpu = pGip->aiCpuFromCpuSetIdx[iCpuSet];
     3455    AssertReturn(iGipCpu < pGip->cCpus, VERR_INVALID_CPU_INDEX);
     3456
     3457    if (fFlags & ~SUP_TSCDELTA_MEASURE_F_VALID_MASK)
     3458        return VERR_INVALID_FLAGS;
     3459
     3460    if (cTries == 0)
     3461        cTries = 12;
     3462    else if (cTries > 256)
     3463        cTries = 256;
     3464
     3465    if (cMsWaitRetry > 1000)
     3466        cMsWaitRetry = 1000;
     3467
     3468    /*
     3469     * The request is a noop if the TSC delta isn't being used.
     3470     */
     3471    if (pGip->enmUseTscDelta <= SUPGIPUSETSCDELTA_ZERO_CLAIMED)
     3472        return VINF_SUCCESS;
     3473
     3474#ifdef SUPDRV_USE_TSC_DELTA_THREAD
     3475    /*
     3476     * Has the TSC already been measured and we're not forced to redo it?
     3477     */
     3478    if (   pGip->aCPUs[iGipCpu].i64TSCDelta != INT64_MAX
     3479        && !(fFlags & SUP_TSCDELTA_MEASURE_F_FORCE))
     3480        return VINF_SUCCESS;
     3481
     3482    /*
     3483     * Asynchronous request? Forward it to the thread, no waiting.
     3484     */
     3485    if (fFlags & SUP_TSCDELTA_MEASURE_F_ASYNC)
     3486    {
     3487        /** @todo Async. doesn't implement options like retries, waiting. We'll need
     3488         *        to pass those options to the thread somehow and implement it in the
     3489         *        thread. Check if anyone uses/needs fAsync before implementing this. */
     3490        RTSpinlockAcquire(pDevExt->hTscDeltaSpinlock);
     3491        RTCpuSetAddByIndex(&pDevExt->TscDeltaCpuSet, iCpuSet);
     3492        if (   pDevExt->enmTscDeltaThreadState == kTscDeltaThreadState_Listening
     3493            || pDevExt->enmTscDeltaThreadState == kTscDeltaThreadState_Measuring)
     3494        {
     3495            pDevExt->enmTscDeltaThreadState = kTscDeltaThreadState_WaitAndMeasure;
     3496            rc = VINF_SUCCESS;
     3497        }
     3498        else
     3499            rc = VERR_THREAD_IS_DEAD;
     3500        RTSpinlockRelease(pDevExt->hTscDeltaSpinlock);
     3501        RTThreadUserSignal(pDevExt->hTscDeltaThread);
     3502        return VINF_SUCCESS;
     3503    }
     3504
     3505    /*
     3506     * If a TSC-delta measurement request is already being serviced by the thread,
     3507     * wait 'cTries' times if a retry-timeout is provided, otherwise bail as busy.
     3508     */
     3509    msTsStartWait = RTTimeSystemMilliTS();
     3510    for (iWaitLoop = 0;; iWaitLoop++)
     3511    {
     3512        uint64_t cMsElapsed;
     3513        SUPDRVTSCDELTATHREADSTATE enmState;
     3514        RTSpinlockAcquire(pDevExt->hTscDeltaSpinlock);
     3515        enmState = pDevExt->enmTscDeltaThreadState;
     3516        RTSpinlockRelease(pDevExt->hTscDeltaSpinlock);
     3517
     3518        if (enmState == kTscDeltaThreadState_Measuring)
     3519        { /* Must wait, the thread is busy. */ }
     3520        else if (enmState == kTscDeltaThreadState_WaitAndMeasure)
     3521        { /* Must wait, this state only says what will happen next. */ }
     3522        else if (enmState == kTscDeltaThreadState_Terminating)
     3523        { /* Must wait, this state only says what should happen next. */ }
     3524        else
     3525            break; /* All other states, the thread is either idly listening or dead. */
     3526
     3527        /* Wait or fail. */
     3528        if (cMsWaitThread == 0)
     3529            return VERR_SUPDRV_TSC_DELTA_MEASUREMENT_BUSY;
     3530        cMsElapsed = RTTimeSystemMilliTS() - msTsStartWait;
     3531        if (cMsElapsed >= cMsWaitThread)
     3532            return VERR_SUPDRV_TSC_DELTA_MEASUREMENT_BUSY;
     3533
     3534        rc = RTThreadSleep(RT_MIN(cMsWaitThread - cMsElapsed, RT_MIN(iWaitLoop + 1, 10)));
     3535        if (rc == VERR_INTERRUPTED)
     3536            return rc;
     3537    }
     3538#endif /* SUPDRV_USE_TSC_DELTA_THREAD */
     3539
     3540    /*
     3541     * Try measure the TSC delta the given number of times.
     3542     */
     3543    for (;;)
     3544    {
     3545        /* Unless we're forced to measure the delta, check whether it's done already. */
     3546        if (   !(fFlags & SUP_TSCDELTA_MEASURE_F_FORCE)
     3547            && pGip->aCPUs[iGipCpu].i64TSCDelta != INT64_MAX)
     3548        {
     3549            rc = VINF_SUCCESS;
     3550            break;
     3551        }
     3552
     3553        /* Measure it. */
     3554        rc = supdrvMeasureTscDeltaOne(pDevExt, iGipCpu);
     3555        if (rc != VERR_SUPDRV_TSC_DELTA_MEASUREMENT_FAILED)
     3556        {
     3557            Assert(pGip->aCPUs[iGipCpu].i64TSCDelta != INT64_MAX || RT_FAILURE_NP(rc));
     3558            break;
     3559        }
     3560
     3561        /* Retry? */
     3562        if (cTries <= 1)
     3563            break;
     3564        cTries--;
     3565
     3566        if (cMsWaitRetry)
     3567        {
     3568            rc = RTThreadSleep(cMsWaitRetry);
     3569            if (rc == VERR_INTERRUPTED)
     3570                break;
     3571        }
     3572    }
     3573
     3574    return rc;
     3575}
    34073576
    34083577
     
    34173586int VBOXCALL supdrvIOCtl_TscDeltaMeasure(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPTSCDELTAMEASURE pReq)
    34183587{
    3419     PSUPGLOBALINFOPAGE pGip;
    3420     RTCPUID            idCpuWorker;
    3421     int                rc;
    3422     int16_t            cTries;
    3423     RTMSINTERVAL       cMsWaitRetry;
    3424     uint16_t           iCpu;
    3425 
    3426     /*
    3427      * Validate.
     3588    uint32_t        cTries;
     3589    uint32_t        iCpuSet;
     3590    uint32_t        fFlags;
     3591    RTMSINTERVAL    cMsWaitRetry;
     3592
     3593    /*
     3594     * Validate and adjust/resolve the input so they can be passed onto SUPR0TscDeltaMeasureBySetIndex.
    34283595     */
    34293596    AssertPtr(pDevExt); AssertPtr(pSession); AssertPtr(pReq); /* paranoia^2 */
    3430     if (pSession->GipMapObjR3 == NIL_RTR0MEMOBJ)
    3431         return VERR_WRONG_ORDER;
    3432     pGip = pDevExt->pGip;
    3433     AssertReturn(pGip, VERR_INTERNAL_ERROR_2);
    3434 
    3435     idCpuWorker = pReq->u.In.idCpu;
    3436     if (idCpuWorker == NIL_RTCPUID)
     3597
     3598    if (pReq->u.In.idCpu == NIL_RTCPUID)
    34373599        return VERR_INVALID_CPU_ID;
    3438     cTries       = RT_MAX(pReq->u.In.cRetries + 1, 10);
     3600    iCpuSet = RTMpCpuIdToSetIndex(pReq->u.In.idCpu);
     3601    if (iCpuSet >= RTCPUSET_MAX_CPUS)
     3602        return VERR_INVALID_CPU_ID;
     3603
     3604    cTries = pReq->u.In.cRetries == 0 ? 0 : (uint32_t)pReq->u.In.cRetries + 1;
     3605
    34393606    cMsWaitRetry = RT_MAX(pReq->u.In.cMsWaitRetry, 5);
    34403607
    3441     /*
    3442      * The request is a noop if the TSC delta isn't being used.
    3443      */
    3444     pGip = pDevExt->pGip;
    3445     if (pGip->enmUseTscDelta <= SUPGIPUSETSCDELTA_ZERO_CLAIMED)
    3446         return VINF_SUCCESS;
    3447 
    3448     rc = VERR_CPU_NOT_FOUND;
    3449     for (iCpu = 0; iCpu < pGip->cCpus; iCpu++)
    3450     {
    3451         PSUPGIPCPU pGipCpuWorker = &pGip->aCPUs[iCpu];
    3452         if (pGipCpuWorker->idCpu == idCpuWorker)
    3453         {
    3454             if (   pGipCpuWorker->i64TSCDelta != INT64_MAX
    3455                 && !pReq->u.In.fForce)
    3456                 return VINF_SUCCESS;
    3457 
    3458 #ifdef SUPDRV_USE_TSC_DELTA_THREAD
    3459             if (pReq->u.In.fAsync)
    3460             {
    3461                 /** @todo Async. doesn't implement options like retries, waiting. We'll need
    3462                  *        to pass those options to the thread somehow and implement it in the
    3463                  *        thread. Check if anyone uses/needs fAsync before implementing this. */
    3464                 RTSpinlockAcquire(pDevExt->hTscDeltaSpinlock);
    3465                 RTCpuSetAddByIndex(&pDevExt->TscDeltaCpuSet, pGipCpuWorker->iCpuSet);
    3466                 if (   pDevExt->enmTscDeltaThreadState == kTscDeltaThreadState_Listening
    3467                     || pDevExt->enmTscDeltaThreadState == kTscDeltaThreadState_Measuring)
    3468                 {
    3469                     pDevExt->enmTscDeltaThreadState = kTscDeltaThreadState_WaitAndMeasure;
    3470                 }
    3471                 RTSpinlockRelease(pDevExt->hTscDeltaSpinlock);
    3472                 RTThreadUserSignal(pDevExt->hTscDeltaThread);
    3473                 return VINF_SUCCESS;
    3474             }
    3475 
    3476             /*
    3477              * If a TSC-delta measurement request is already being serviced by the thread,
    3478              * wait 'cTries' times if a retry-timeout is provided, otherwise bail as busy.
    3479              */
    3480             while (cTries-- > 0)
    3481             {
    3482                 SUPDRVTSCDELTATHREADSTATE enmState;
    3483                 RTSpinlockAcquire(pDevExt->hTscDeltaSpinlock);
    3484                 enmState = pDevExt->enmTscDeltaThreadState;
    3485                 RTSpinlockRelease(pDevExt->hTscDeltaSpinlock);
    3486 
    3487                 if (   enmState == kTscDeltaThreadState_Measuring
    3488                     || enmState == kTscDeltaThreadState_WaitAndMeasure)
    3489                 {
    3490                     if (   !cTries
    3491                         || !cMsWaitRetry)
    3492                         return VERR_SUPDRV_TSC_DELTA_MEASUREMENT_BUSY;
    3493                     if (cMsWaitRetry)
    3494                         RTThreadSleep(cMsWaitRetry);
    3495                 }
    3496             }
    3497             cTries = RT_MAX(pReq->u.In.cRetries + 1, 10);
    3498 #endif
    3499 
    3500             while (cTries-- > 0)
    3501             {
    3502                 rc = supdrvMeasureTscDeltaOne(pDevExt, iCpu);
    3503                 if (RT_SUCCESS(rc))
    3504                 {
    3505                     Assert(pGipCpuWorker->i64TSCDelta != INT64_MAX);
    3506                     break;
    3507                 }
    3508 
    3509                 if (cMsWaitRetry)
    3510                     RTThreadSleep(cMsWaitRetry);
    3511             }
    3512 
    3513             break;
    3514         }
    3515     }
    3516     return rc;
     3608    fFlags = 0;
     3609    if (pReq->u.In.fAsync)
     3610        fFlags |= SUP_TSCDELTA_MEASURE_F_ASYNC;
     3611    if (pReq->u.In.fForce)
     3612        fFlags |= SUP_TSCDELTA_MEASURE_F_FORCE;
     3613
     3614    return SUPR0TscDeltaMeasureBySetIndex(pSession, iCpuSet, fFlags, cMsWaitRetry,
     3615                                          cTries == 0 ? 5*RT_MS_1SEC : cMsWaitRetry * cTries /*cMsWaitThread*/,
     3616                                          cTries);
    35173617}
    35183618
  • trunk/src/VBox/HostDrivers/Support/SUPDrvIOC.h

    r54331 r54339  
    213213 *
    214214 * @todo Pending work on next major version change:
    215  *          - Fix SUPTSCREAD padding (#if 0 -> #if 1).
    216  */
    217 #define SUPDRV_IOC_VERSION                              0x001f0001
     215 *          - (nothing)
     216 */
     217#define SUPDRV_IOC_VERSION                              0x001f0002
    218218
    219219/** SUP_IOCTL_COOKIE. */
  • trunk/src/VBox/HostDrivers/Support/SUPLib.cpp

    r54308 r54339  
    280280        CookieReq.u.In.u32ReqVersion = SUPDRV_IOC_VERSION;
    281281        const uint32_t uMinVersion = (SUPDRV_IOC_VERSION & 0xffff0000) == 0x001f0000
    282                                    ? 0x001f0001
     282                                   ? 0x001f0002
    283283                                   : SUPDRV_IOC_VERSION & 0xffff0000;
    284284        CookieReq.u.In.u32MinVersion = uMinVersion;
Note: See TracChangeset for help on using the changeset viewer.

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