VirtualBox

Changeset 54339 in vbox


Ignore:
Timestamp:
Feb 20, 2015 6:10:12 PM (10 years ago)
Author:
vboxsync
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
Files:
9 edited

Legend:

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

    r54333 r54339  
    18061806SUPR0DECL(bool) SUPR0SuspendVTxOnCpu(void);
    18071807SUPR0DECL(void) SUPR0ResumeVTxOnCpu(bool fSuspended);
     1808#define SUP_TSCDELTA_MEASURE_F_FORCE        RT_BIT_32(0)
     1809#define SUP_TSCDELTA_MEASURE_F_ASYNC        RT_BIT_32(1)
     1810#define SUP_TSCDELTA_MEASURE_F_VALID_MASK   UINT32_C(0x00000003)
     1811SUPR0DECL(int) SUPR0TscDeltaMeasureBySetIndex(PSUPDRVSESSION pSession, uint32_t iCpuSet, uint32_t fFlags,
     1812                                              RTMSINTERVAL cMsWaitRetry, RTMSINTERVAL cMsWaitThread, uint32_t cTries);
    18081813
    18091814/** @name Absolute symbols
  • trunk/include/VBox/vmm/cpum.h

    r53615 r54339  
    13361336VMMR0_INT_DECL(void)    CPUMR0LoadHyperDebugState(PVMCPU pVCpu, bool fDr6);
    13371337#ifdef VBOX_WITH_VMMR0_DISABLE_LAPIC_NMI
    1338 VMMR0_INT_DECL(void)    CPUMR0SetLApic(PVMCPU pVCpu, RTCPUID idHostCpu);
     1338VMMR0_INT_DECL(void)    CPUMR0SetLApic(PVMCPU pVCpu, uint32_t iHostCpuSet);
    13391339#endif
    13401340
  • 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;
  • trunk/src/VBox/HostDrivers/linux/load.sh

    r48952 r54339  
    2424
    2525set -e
    26 kmk -C "${MY_DIR}/src/vboxdrv" "$@"
     26make -C "${MY_DIR}/src/vboxdrv" "$@"
    2727sudo make -C "${MY_DIR}/src/" unload
    2828echo "Installing SUPDrv (aka VBoxDrv/vboxdrv)"
  • trunk/src/VBox/VMM/VMMR0/CPUMR0.cpp

    r53836 r54339  
    998998 * @param   pVCpu       Pointer to the cross context CPU structure of the
    999999 *                      calling EMT.
    1000  * @param   idHostCpu   The ID of the current host CPU.
    1001  */
    1002 VMMR0_INT_DECL(void) CPUMR0SetLApic(PVMCPU pVCpu, RTCPUID idHostCpu)
    1003 {
    1004     int idxCpu = RTMpCpuIdToSetIndex(idHostCpu);
    1005     pVCpu->cpum.s.pvApicBase = g_aLApics[idxCpu].pv;
    1006     pVCpu->cpum.s.fX2Apic    = g_aLApics[idxCpu].fX2Apic;
     1000 * @param   iHostCpuSet The CPU set index of the current host CPU.
     1001 */
     1002VMMR0_INT_DECL(void) CPUMR0SetLApic(PVMCPU pVCpu, uint32_t iHostCpuSet)
     1003{
     1004    Assert(iHostCpuSet <= RT_ELEMENTS(g_aLApics));
     1005    pVCpu->cpum.s.pvApicBase = g_aLApics[iHostCpuSet].pv;
     1006    pVCpu->cpum.s.fX2Apic    = g_aLApics[iHostCpuSet].fX2Apic;
    10071007//    Log6(("CPUMR0SetLApic: pvApicBase=%p fX2Apic=%d\n", g_aLApics[idxCpu].pv, g_aLApics[idxCpu].fX2Apic));
    10081008}
  • trunk/src/VBox/VMM/VMMR0/VMMR0.cpp

    r54256 r54339  
    566566
    567567            /* We need to update the VCPU <-> host CPU mapping. */
    568             RTCPUID idHostCpu  = RTMpCpuId();
    569             pVCpu->iHostCpuSet = RTMpCpuIdToSetIndex(idHostCpu);
     568            RTCPUID idHostCpu    = RTMpCpuId();
     569            uint32_t iHostCpuSet = RTMpCpuIdToSetIndex(idHostCpu);
     570            pVCpu->iHostCpuSet   = iHostCpuSet;
    570571            ASMAtomicWriteU32(&pVCpu->idHostCpu, idHostCpu);
     572
     573            /* In the very unlikely event that the GIP delta for the CPU we're
     574               rescheduled needs calculating, try force a return to ring-3.
     575               We unfortunately cannot do the measurements right here. */
     576            if (RT_UNLIKELY(SUPIsTscDeltaAvailableForCpuSetIndex(iHostCpuSet)))
     577                VMCPU_FF_SET(pVCpu, VMCPU_FF_TO_R3);
    571578
    572579            /* Invoke the HM-specific thread-context callback. */
     
    862869#endif
    863870
    864             /* Disable preemption and update the periodic preemption timer. */
     871            /*
     872             * Disable preemption.
     873             */
    865874            RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER;
    866875            RTThreadPreemptDisable(&PreemptState);
    867             RTCPUID idHostCpu = RTMpCpuId();
     876
     877            /*
     878             * Get the host CPU identifiers, make sure they are valid and that
     879             * we've got a TSC delta for the CPU.
     880             */
     881            RTCPUID  idHostCpu   = RTMpCpuId();
     882            uint32_t iHostCpuSet = RTMpCpuIdToSetIndex(idHostCpu);
     883            if (RT_LIKELY(   iHostCpuSet < RTCPUSET_MAX_CPUS
     884                          && SUPIsTscDeltaAvailableForCpuSetIndex(iHostCpuSet)))
     885            {
     886                /*
     887                 * Commit the CPU identifiers and update the periodict preemption timer if it's active.
     888                 */
    868889#ifdef VBOX_WITH_VMMR0_DISABLE_LAPIC_NMI
    869             CPUMR0SetLApic(pVCpu, idHostCpu);
    870 #endif
    871             pVCpu->iHostCpuSet = RTMpCpuIdToSetIndex(idHostCpu);
    872             ASMAtomicWriteU32(&pVCpu->idHostCpu, idHostCpu);
    873             if (pVM->vmm.s.fUsePeriodicPreemptionTimers)
    874                 GVMMR0SchedUpdatePeriodicPreemptionTimer(pVM, pVCpu->idHostCpu, TMCalcHostTimerFrequency(pVM, pVCpu));
    875 
    876             /* We might need to disable VT-x if the active switcher turns off paging. */
    877             bool fVTxDisabled;
    878             int rc = HMR0EnterSwitcher(pVM, pVM->vmm.s.enmSwitcher, &fVTxDisabled);
    879             if (RT_SUCCESS(rc))
     890                CPUMR0SetLApic(pVCpu, iHostCpuSet);
     891#endif
     892                pVCpu->iHostCpuSet = iHostCpuSet;
     893                ASMAtomicWriteU32(&pVCpu->idHostCpu, idHostCpu);
     894
     895                if (pVM->vmm.s.fUsePeriodicPreemptionTimers)
     896                    GVMMR0SchedUpdatePeriodicPreemptionTimer(pVM, pVCpu->idHostCpu, TMCalcHostTimerFrequency(pVM, pVCpu));
     897
     898                /*
     899                 * We might need to disable VT-x if the active switcher turns off paging.
     900                  */
     901                bool fVTxDisabled;
     902                int rc = HMR0EnterSwitcher(pVM, pVM->vmm.s.enmSwitcher, &fVTxDisabled);
     903                if (RT_SUCCESS(rc))
     904                {
     905                    /*
     906                     * Disable interrupts and run raw-mode code.  The loop is for efficiently
     907                     * dispatching tracepoints that fired in raw-mode context.
     908                     */
     909                    RTCCUINTREG uFlags = ASMIntDisableFlags();
     910
     911                    for (;;)
     912                    {
     913                        VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC);
     914                        TMNotifyStartOfExecution(pVCpu);
     915
     916                        rc = pVM->vmm.s.pfnR0ToRawMode(pVM);
     917                        pVCpu->vmm.s.iLastGZRc = rc;
     918
     919                        TMNotifyEndOfExecution(pVCpu);
     920                        VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED);
     921
     922                        if (rc != VINF_VMM_CALL_TRACER)
     923                            break;
     924                        SUPR0TracerUmodProbeFire(pVM->pSession, &pVCpu->vmm.s.TracerCtx);
     925                    }
     926
     927                    /*
     928                     * Re-enable VT-x before we dispatch any pending host interrupts and
     929                     * re-enables interrupts.
     930                     */
     931                    HMR0LeaveSwitcher(pVM, fVTxDisabled);
     932
     933                    if (    rc == VINF_EM_RAW_INTERRUPT
     934                        ||  rc == VINF_EM_RAW_INTERRUPT_HYPER)
     935                        TRPMR0DispatchHostInterrupt(pVM);
     936
     937                    ASMSetFlags(uFlags);
     938
     939                    /* Fire dtrace probe and collect statistics. */
     940                    VBOXVMM_R0_VMM_RETURN_TO_RING3_RC(pVCpu, CPUMQueryGuestCtxPtr(pVCpu), rc);
     941#ifdef VBOX_WITH_STATISTICS
     942                    STAM_COUNTER_INC(&pVM->vmm.s.StatRunRC);
     943                    vmmR0RecordRC(pVM, pVCpu, rc);
     944#endif
     945                }
     946                else
     947                    pVCpu->vmm.s.iLastGZRc = rc;
     948
     949                /*
     950                 * Invalidate the host CPU identifiers as we restore preemption.
     951                 */
     952                pVCpu->iHostCpuSet = UINT32_MAX;
     953                ASMAtomicWriteU32(&pVCpu->idHostCpu, NIL_RTCPUID);
     954
     955                RTThreadPreemptRestore(&PreemptState);
     956            }
     957            /*
     958             * Invalid CPU set index or TSC delta in need of measuring.
     959             */
     960            else
    880961            {
    881                 RTCCUINTREG uFlags = ASMIntDisableFlags();
    882 
    883                 for (;;)
     962                RTThreadPreemptRestore(&PreemptState);
     963                if (iHostCpuSet < RTCPUSET_MAX_CPUS)
    884964                {
    885                     VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC);
    886                     TMNotifyStartOfExecution(pVCpu);
    887 
    888                     rc = pVM->vmm.s.pfnR0ToRawMode(pVM);
    889                     pVCpu->vmm.s.iLastGZRc = rc;
    890 
    891                     TMNotifyEndOfExecution(pVCpu);
    892                     VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED);
    893 
    894                     if (rc != VINF_VMM_CALL_TRACER)
    895                         break;
    896                     SUPR0TracerUmodProbeFire(pVM->pSession, &pVCpu->vmm.s.TracerCtx);
     965                    int rc = SUPR0TscDeltaMeasureBySetIndex(pVM->pSession, iHostCpuSet, 0 /*fFlags*/,
     966                                                            2 /*cMsWaitRetry*/, 5*RT_MS_1SEC /*cMsWaitThread*/,
     967                                                            0 /*default cTries*/);
     968                    if (RT_SUCCESS(rc) || rc == VERR_CPU_OFFLINE)
     969                        pVCpu->vmm.s.iLastGZRc = VINF_EM_RAW_TO_R3;
     970                    else
     971                        pVCpu->vmm.s.iLastGZRc = rc;
    897972                }
    898 
    899                 /* Re-enable VT-x if previously turned off. */
    900                 HMR0LeaveSwitcher(pVM, fVTxDisabled);
    901 
    902                 if (    rc == VINF_EM_RAW_INTERRUPT
    903                     ||  rc == VINF_EM_RAW_INTERRUPT_HYPER)
    904                     TRPMR0DispatchHostInterrupt(pVM);
    905 
    906                 ASMSetFlags(uFlags);
    907 
    908                 VBOXVMM_R0_VMM_RETURN_TO_RING3_RC(pVCpu, CPUMQueryGuestCtxPtr(pVCpu), rc);
    909 #ifdef VBOX_WITH_STATISTICS
    910                 STAM_COUNTER_INC(&pVM->vmm.s.StatRunRC);
    911                 vmmR0RecordRC(pVM, pVCpu, rc);
    912 #endif
     973                else
     974                    pVCpu->vmm.s.iLastGZRc = VERR_INVALID_CPU_INDEX;
    913975            }
    914             else
    915                 pVCpu->vmm.s.iLastGZRc = rc;
    916             pVCpu->iHostCpuSet = UINT32_MAX;
    917             ASMAtomicWriteU32(&pVCpu->idHostCpu, NIL_RTCPUID);
    918             RTThreadPreemptRestore(&PreemptState);
    919976            break;
    920977        }
     
    925982        case VMMR0_DO_HM_RUN:
    926983        {
     984            /*
     985             * Disable preemption.
     986             */
    927987            Assert(!VMMR0ThreadCtxHooksAreRegistered(pVCpu));
    928988            RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER;
    929989            RTThreadPreemptDisable(&PreemptState);
    930990
    931             /* Update the VCPU <-> host CPU mapping before doing anything else. */
    932             RTCPUID  idHostCpu = RTMpCpuId();
    933             pVCpu->iHostCpuSet = RTMpCpuIdToSetIndex(idHostCpu);
    934             ASMAtomicWriteU32(&pVCpu->idHostCpu, idHostCpu);
    935 
    936             if (pVM->vmm.s.fUsePeriodicPreemptionTimers)
    937                 GVMMR0SchedUpdatePeriodicPreemptionTimer(pVM, pVCpu->idHostCpu, TMCalcHostTimerFrequency(pVM, pVCpu));
     991            /*
     992             * Get the host CPU identifiers, make sure they are valid and that
     993             * we've got a TSC delta for the CPU.
     994             */
     995            RTCPUID  idHostCpu   = RTMpCpuId();
     996            uint32_t iHostCpuSet = RTMpCpuIdToSetIndex(idHostCpu);
     997            if (RT_LIKELY(   iHostCpuSet < RTCPUSET_MAX_CPUS
     998                          && SUPIsTscDeltaAvailableForCpuSetIndex(iHostCpuSet)))
     999            {
     1000                pVCpu->iHostCpuSet = iHostCpuSet;
     1001                ASMAtomicWriteU32(&pVCpu->idHostCpu, idHostCpu);
     1002
     1003                /*
     1004                 * Update the periodict preemption timer if it's active.
     1005                 */
     1006                if (pVM->vmm.s.fUsePeriodicPreemptionTimers)
     1007                    GVMMR0SchedUpdatePeriodicPreemptionTimer(pVM, pVCpu->idHostCpu, TMCalcHostTimerFrequency(pVM, pVCpu));
     1008
    9381009#ifdef LOG_ENABLED
    939             if (pVCpu->idCpu > 0)
    940             {
    941                 /* Lazy registration of ring 0 loggers. */
    942                 PVMMR0LOGGER pR0Logger = pVCpu->vmm.s.pR0LoggerR0;
    943                 if (    pR0Logger
    944                     &&  !pR0Logger->fRegistered)
     1010                /*
     1011                 * Ugly: Lazy registration of ring 0 loggers.
     1012                 */
     1013                if (pVCpu->idCpu > 0)
    9451014                {
    946                     RTLogSetDefaultInstanceThread(&pR0Logger->Logger, (uintptr_t)pVM->pSession);
    947                     pR0Logger->fRegistered = true;
     1015                    PVMMR0LOGGER pR0Logger = pVCpu->vmm.s.pR0LoggerR0;
     1016                    if (    pR0Logger
     1017                        && RT_UNLIKELY(!pR0Logger->fRegistered))
     1018                    {
     1019                        RTLogSetDefaultInstanceThread(&pR0Logger->Logger, (uintptr_t)pVM->pSession);
     1020                        pR0Logger->fRegistered = true;
     1021                    }
    9481022                }
     1023#endif
     1024
     1025                int  rc;
     1026                bool fPreemptRestored = false;
     1027                if (!HMR0SuspendPending())
     1028                {
     1029                    /*
     1030                     * Register thread-context hooks if required.
     1031                     */
     1032                    if (    VMMR0ThreadCtxHooksAreCreated(pVCpu)
     1033                        && !VMMR0ThreadCtxHooksAreRegistered(pVCpu))
     1034                    {
     1035                        rc = VMMR0ThreadCtxHooksRegister(pVCpu, vmmR0ThreadCtxCallback);
     1036                        AssertRC(rc);
     1037                    }
     1038
     1039                    /*
     1040                     * Enter HM context.
     1041                     */
     1042                    rc = HMR0Enter(pVM, pVCpu);
     1043                    if (RT_SUCCESS(rc))
     1044                    {
     1045                        VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_HM);
     1046
     1047                        /*
     1048                         * When preemption hooks are in place, enable preemption now that
     1049                         * we're in HM context.
     1050                         */
     1051                        if (VMMR0ThreadCtxHooksAreRegistered(pVCpu))
     1052                        {
     1053                            fPreemptRestored = true;
     1054                            RTThreadPreemptRestore(&PreemptState);
     1055                        }
     1056
     1057                        /*
     1058                         * Setup the longjmp machinery and execute guest code (calls HMR0RunGuestCode).
     1059                         */
     1060                        rc = vmmR0CallRing3SetJmp(&pVCpu->vmm.s.CallRing3JmpBufR0, HMR0RunGuestCode, pVM, pVCpu);
     1061
     1062                        /*
     1063                         * Assert sanity on the way out.  Using manual assertions code here as normal
     1064                         * assertions are going to panic the host since we're outside the setjmp/longjmp zone.
     1065                         */
     1066                        if (RT_UNLIKELY(   VMCPU_GET_STATE(pVCpu) != VMCPUSTATE_STARTED_HM
     1067                                        && RT_SUCCESS_NP(rc)  && rc !=  VINF_VMM_CALL_HOST ))
     1068                        {
     1069                            pVM->vmm.s.szRing0AssertMsg1[0] = '\0';
     1070                            RTStrPrintf(pVM->vmm.s.szRing0AssertMsg2, sizeof(pVM->vmm.s.szRing0AssertMsg2),
     1071                                        "Got VMCPU state %d expected %d.\n", VMCPU_GET_STATE(pVCpu), VMCPUSTATE_STARTED_HM);
     1072                            rc = VERR_VMM_WRONG_HM_VMCPU_STATE;
     1073                        }
     1074                        else if (RT_UNLIKELY(VMMR0ThreadCtxHooksAreRegistered(pVCpu)))
     1075                        {
     1076                            pVM->vmm.s.szRing0AssertMsg1[0] = '\0';
     1077                            RTStrPrintf(pVM->vmm.s.szRing0AssertMsg2, sizeof(pVM->vmm.s.szRing0AssertMsg2),
     1078                                        "Thread-context hooks still registered! VCPU=%p Id=%u rc=%d.\n", pVCpu, pVCpu->idCpu, rc);
     1079                            rc = VERR_INVALID_STATE;
     1080                        }
     1081
     1082                        VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED);
     1083                    }
     1084                    STAM_COUNTER_INC(&pVM->vmm.s.StatRunRC);
     1085                }
     1086                /*
     1087                 * The system is about to go into suspend mode; go back to ring 3.
     1088                 */
     1089                else
     1090                    rc = VINF_EM_RAW_INTERRUPT;
     1091
     1092                pVCpu->vmm.s.iLastGZRc = rc;
     1093
     1094                /*
     1095                 * Invalidate the host CPU identifiers as we restore preemption.
     1096                 */
     1097                pVCpu->iHostCpuSet = UINT32_MAX;
     1098                ASMAtomicWriteU32(&pVCpu->idHostCpu, NIL_RTCPUID);
     1099
     1100                if (!fPreemptRestored)
     1101                    RTThreadPreemptRestore(&PreemptState);
     1102
     1103                /* Fire dtrace probe and collect statistics. */
     1104                VBOXVMM_R0_VMM_RETURN_TO_RING3_HM(pVCpu, CPUMQueryGuestCtxPtr(pVCpu), rc);
     1105#ifdef VBOX_WITH_STATISTICS
     1106                vmmR0RecordRC(pVM, pVCpu, rc);
     1107#endif
    9491108            }
    950 #endif
    951 
    952             int  rc;
    953             bool fPreemptRestored = false;
    954             if (!HMR0SuspendPending())
    955             {
    956                 /* Register thread-context hooks if required. */
    957                 if (    VMMR0ThreadCtxHooksAreCreated(pVCpu)
    958                     && !VMMR0ThreadCtxHooksAreRegistered(pVCpu))
    959                 {
    960                     rc = VMMR0ThreadCtxHooksRegister(pVCpu, vmmR0ThreadCtxCallback);
    961                     AssertRC(rc);
    962                 }
    963 
    964                 /* Enter HM context. */
    965                 rc = HMR0Enter(pVM, pVCpu);
    966                 if (RT_SUCCESS(rc))
    967                 {
    968                     VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_HM);
    969 
    970                     /* When preemption hooks are in place, enable preemption now that we're in HM context. */
    971                     if (VMMR0ThreadCtxHooksAreRegistered(pVCpu))
    972                     {
    973                         fPreemptRestored = true;
    974                         RTThreadPreemptRestore(&PreemptState);
    975                     }
    976 
    977                     /* Setup the longjmp machinery and execute guest code. */
    978                     rc = vmmR0CallRing3SetJmp(&pVCpu->vmm.s.CallRing3JmpBufR0, HMR0RunGuestCode, pVM, pVCpu);
    979 
    980                     /* Manual assert as normal assertions are going to crash in this case. */
    981                     if (RT_UNLIKELY(   VMCPU_GET_STATE(pVCpu) != VMCPUSTATE_STARTED_HM
    982                                     && RT_SUCCESS_NP(rc)  && rc !=  VINF_VMM_CALL_HOST ))
    983                     {
    984                         pVM->vmm.s.szRing0AssertMsg1[0] = '\0';
    985                         RTStrPrintf(pVM->vmm.s.szRing0AssertMsg2, sizeof(pVM->vmm.s.szRing0AssertMsg2),
    986                                     "Got VMCPU state %d expected %d.\n", VMCPU_GET_STATE(pVCpu), VMCPUSTATE_STARTED_HM);
    987                         rc = VERR_VMM_WRONG_HM_VMCPU_STATE;
    988                     }
    989                     else if (RT_UNLIKELY(VMMR0ThreadCtxHooksAreRegistered(pVCpu)))
    990                     {
    991                         pVM->vmm.s.szRing0AssertMsg1[0] = '\0';
    992                         RTStrPrintf(pVM->vmm.s.szRing0AssertMsg2, sizeof(pVM->vmm.s.szRing0AssertMsg2),
    993                                     "Thread-context hooks still registered! VCPU=%p Id=%u rc=%d.\n", pVCpu, pVCpu->idCpu, rc);
    994                         rc = VERR_INVALID_STATE;
    995                     }
    996 
    997                     VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED);
    998                 }
    999                 STAM_COUNTER_INC(&pVM->vmm.s.StatRunRC);
    1000             }
     1109            /*
     1110             * Invalid CPU set index or TSC delta in need of measuring.
     1111             */
    10011112            else
    10021113            {
    1003                 /* System is about to go into suspend mode; go back to ring 3. */
    1004                 rc = VINF_EM_RAW_INTERRUPT;
     1114                RTThreadPreemptRestore(&PreemptState);
     1115                if (iHostCpuSet < RTCPUSET_MAX_CPUS)
     1116                {
     1117                    int rc = SUPR0TscDeltaMeasureBySetIndex(pVM->pSession, iHostCpuSet, 0 /*fFlags*/,
     1118                                                            2 /*cMsWaitRetry*/, 5*RT_MS_1SEC /*cMsWaitThread*/,
     1119                                                            0 /*default cTries*/);
     1120                    if (RT_SUCCESS(rc) || rc == VERR_CPU_OFFLINE)
     1121                        pVCpu->vmm.s.iLastGZRc = VINF_EM_RAW_TO_R3;
     1122                    else
     1123                        pVCpu->vmm.s.iLastGZRc = rc;
     1124                }
     1125                else
     1126                    pVCpu->vmm.s.iLastGZRc = VERR_INVALID_CPU_INDEX;
    10051127            }
    1006             pVCpu->vmm.s.iLastGZRc = rc;
    1007 
    1008             /* Clear the VCPU <-> host CPU mapping as we've left HM context. */
    1009             pVCpu->iHostCpuSet = UINT32_MAX;
    1010             ASMAtomicWriteU32(&pVCpu->idHostCpu, NIL_RTCPUID);
    1011 
    1012             if (!fPreemptRestored)
    1013                 RTThreadPreemptRestore(&PreemptState);
    1014 
    1015             VBOXVMM_R0_VMM_RETURN_TO_RING3_HM(pVCpu, CPUMQueryGuestCtxPtr(pVCpu), rc);
    1016 #ifdef VBOX_WITH_STATISTICS
    1017             vmmR0RecordRC(pVM, pVCpu, rc);
    1018 #endif
    1019             /* No special action required for external interrupts, just return. */
    10201128            break;
    10211129        }
     
    11971305        case VMMR0_DO_CALL_HYPERVISOR:
    11981306        {
    1199             int rc;
     1307            /*
     1308             * Validate input / context.
     1309             */
     1310            if (RT_UNLIKELY(idCpu != 0))
     1311                return VERR_INVALID_CPU_ID;
     1312            if (RT_UNLIKELY(pVM->cCpus != 1))
     1313                return VERR_INVALID_PARAMETER;
     1314            PVMCPU pVCpu = &pVM->aCpus[idCpu];
     1315#ifndef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
     1316            if (RT_UNLIKELY(!PGMGetHyperCR3(pVCpu)))
     1317                return VERR_PGM_NO_CR3_SHADOW_ROOT;
     1318#endif
     1319
     1320            /*
     1321             * Disable interrupts.
     1322             */
     1323            RTCCUINTREG fFlags = ASMIntDisableFlags();
     1324
     1325            /*
     1326             * Get the host CPU identifiers, make sure they are valid and that
     1327             * we've got a TSC delta for the CPU.
     1328             */
     1329            RTCPUID  idHostCpu   = RTMpCpuId();
     1330            uint32_t iHostCpuSet = RTMpCpuIdToSetIndex(idHostCpu);
     1331            if (RT_UNLIKELY(iHostCpuSet >= RTCPUSET_MAX_CPUS))
     1332            {
     1333                ASMSetFlags(fFlags);
     1334                return VERR_INVALID_CPU_INDEX;
     1335            }
     1336            if (RT_UNLIKELY(!SUPIsTscDeltaAvailableForCpuSetIndex(iHostCpuSet)))
     1337            {
     1338                ASMSetFlags(fFlags);
     1339                int rc = SUPR0TscDeltaMeasureBySetIndex(pVM->pSession, iHostCpuSet, 0 /*fFlags*/,
     1340                                                        2 /*cMsWaitRetry*/, 5*RT_MS_1SEC /*cMsWaitThread*/,
     1341                                                        0 /*default cTries*/);
     1342                if (RT_FAILURE(rc) && rc != VERR_CPU_OFFLINE)
     1343                    return rc;
     1344            }
     1345
     1346            /*
     1347             * Commit the CPU identifiers.
     1348             */
     1349#ifdef VBOX_WITH_VMMR0_DISABLE_LAPIC_NMI
     1350            CPUMR0SetLApic(pVCpu, iHostCpuSet);
     1351#endif
     1352            pVCpu->iHostCpuSet = iHostCpuSet;
     1353            ASMAtomicWriteU32(&pVCpu->idHostCpu, idHostCpu);
     1354
     1355            /*
     1356             * We might need to disable VT-x if the active switcher turns off paging.
     1357             */
    12001358            bool fVTxDisabled;
    1201 
    1202 #ifndef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
    1203             if (RT_UNLIKELY(!PGMGetHyperCR3(VMMGetCpu0(pVM))))
    1204                 return VERR_PGM_NO_CR3_SHADOW_ROOT;
    1205 #endif
    1206 
    1207             RTCCUINTREG fFlags = ASMIntDisableFlags();
    1208 
    1209 #ifdef VBOX_WITH_VMMR0_DISABLE_LAPIC_NMI
    1210             RTCPUID idHostCpu = RTMpCpuId();
    1211             CPUMR0SetLApic(&pVM->aCpus[0], idHostCpu);
    1212 #endif
    1213 
    1214             /* We might need to disable VT-x if the active switcher turns off paging. */
    1215             rc = HMR0EnterSwitcher(pVM, pVM->vmm.s.enmSwitcher, &fVTxDisabled);
    1216             if (RT_FAILURE(rc))
    1217                 return rc;
    1218 
    1219             rc = pVM->vmm.s.pfnR0ToRawMode(pVM);
    1220 
    1221             /* Re-enable VT-x if previously turned off. */
    1222             HMR0LeaveSwitcher(pVM, fVTxDisabled);
    1223 
    1224             /** @todo dispatch interrupts? */
     1359            int rc = HMR0EnterSwitcher(pVM, pVM->vmm.s.enmSwitcher, &fVTxDisabled);
     1360            if (RT_SUCCESS(rc))
     1361            {
     1362                /*
     1363                 * Go through the wormhole...
     1364                 */
     1365                rc = pVM->vmm.s.pfnR0ToRawMode(pVM);
     1366
     1367                /*
     1368                 * Re-enable VT-x before we dispatch any pending host interrupts.
     1369                 */
     1370                HMR0LeaveSwitcher(pVM, fVTxDisabled);
     1371
     1372                if (   rc == VINF_EM_RAW_INTERRUPT
     1373                    || rc == VINF_EM_RAW_INTERRUPT_HYPER)
     1374                    TRPMR0DispatchHostInterrupt(pVM);
     1375            }
     1376
     1377            /*
     1378             * Invalidate the host CPU identifiers as we restore interrupts.
     1379             */
     1380            pVCpu->iHostCpuSet = UINT32_MAX;
     1381            ASMAtomicWriteU32(&pVCpu->idHostCpu, NIL_RTCPUID);
    12251382            ASMSetFlags(fFlags);
    12261383            return rc;
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