VirtualBox

Changeset 91988 in vbox


Ignore:
Timestamp:
Oct 22, 2021 3:23:54 AM (4 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
147796
Message:

VMM/TM: Fixed race while switching TSC modes.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMR3/TM.cpp

    r91939 r91988  
    12161216     * Switch TM TSC mode back to the original mode after a reset for
    12171217     * paravirtualized guests that alter the TM TSC mode during operation.
     1218     * We're already in an EMT rendezvous at this point.
    12181219     */
    12191220    if (   pVM->tm.s.fTSCModeSwitchAllowed
     
    36363637{
    36373638    AssertPtr(pVM); Assert(pVM->tm.s.fTSCModeSwitchAllowed); NOREF(pVCpuEmt); NOREF(pvData);
    3638     Assert(pVM->tm.s.enmTSCMode != TMTSCMODE_REAL_TSC_OFFSET);
    36393639    Assert(pVM->tm.s.enmTSCMode != TMTSCMODE_NATIVE_API); /** @todo figure out NEM/win and paravirt */
    36403640    Assert(tmR3HasFixedTSC(pVM));
    36413641
    3642     /*
    3643      * The return value of TMCpuTickGet() and the guest's TSC value for each
    3644      * CPU must remain constant across the TM TSC mode-switch.  Thus we have
    3645      * the following equation (new/old signifies the new/old tsc modes):
    3646      *      uNewTsc = uOldTsc
    3647      *
    3648      * Where (see tmCpuTickGetInternal):
    3649      *      uOldTsc = uRawOldTsc - offTscRawSrcOld
    3650      *      uNewTsc = uRawNewTsc - offTscRawSrcNew
    3651      *
    3652      * Solve it for offTscRawSrcNew without replacing uOldTsc:
    3653      *     uRawNewTsc - offTscRawSrcNew = uOldTsc
    3654      *  => -offTscRawSrcNew = uOldTsc - uRawNewTsc
    3655      *  => offTscRawSrcNew  = uRawNewTsc - uOldTsc
    3656      */
    3657     uint64_t uRawOldTsc = tmR3CpuTickGetRawVirtualNoCheck(pVM);
    3658     uint64_t uRawNewTsc = SUPReadTsc();
    3659     uint32_t cCpus = pVM->cCpus;
    3660     for (uint32_t i = 0; i < cCpus; i++)
    3661     {
    3662         PVMCPU   pVCpu   = pVM->apCpusR3[i];
    3663         uint64_t uOldTsc = uRawOldTsc - pVCpu->tm.s.offTSCRawSrc;
    3664         pVCpu->tm.s.offTSCRawSrc = uRawNewTsc - uOldTsc;
    3665         Assert(uRawNewTsc - pVCpu->tm.s.offTSCRawSrc >= uOldTsc); /* paranoia^256 */
    3666     }
    3667 
    3668     LogRel(("TM: Switching TSC mode from '%s' to '%s'\n", tmR3GetTSCModeNameEx(pVM->tm.s.enmTSCMode),
    3669             tmR3GetTSCModeNameEx(TMTSCMODE_REAL_TSC_OFFSET)));
    3670     pVM->tm.s.enmTSCMode = TMTSCMODE_REAL_TSC_OFFSET;
     3642    if (pVM->tm.s.enmTSCMode != TMTSCMODE_REAL_TSC_OFFSET)
     3643    {
     3644        /*
     3645         * The return value of TMCpuTickGet() and the guest's TSC value for each
     3646         * CPU must remain constant across the TM TSC mode-switch.  Thus we have
     3647         * the following equation (new/old signifies the new/old tsc modes):
     3648         *      uNewTsc = uOldTsc
     3649         *
     3650         * Where (see tmCpuTickGetInternal):
     3651         *      uOldTsc = uRawOldTsc - offTscRawSrcOld
     3652         *      uNewTsc = uRawNewTsc - offTscRawSrcNew
     3653         *
     3654         * Solve it for offTscRawSrcNew without replacing uOldTsc:
     3655         *     uRawNewTsc - offTscRawSrcNew = uOldTsc
     3656         *  => -offTscRawSrcNew = uOldTsc - uRawNewTsc
     3657         *  => offTscRawSrcNew  = uRawNewTsc - uOldTsc
     3658         */
     3659        uint64_t uRawOldTsc = tmR3CpuTickGetRawVirtualNoCheck(pVM);
     3660        uint64_t uRawNewTsc = SUPReadTsc();
     3661        uint32_t cCpus = pVM->cCpus;
     3662        for (uint32_t i = 0; i < cCpus; i++)
     3663        {
     3664            PVMCPU   pVCpu   = pVM->apCpusR3[i];
     3665            uint64_t uOldTsc = uRawOldTsc - pVCpu->tm.s.offTSCRawSrc;
     3666            pVCpu->tm.s.offTSCRawSrc = uRawNewTsc - uOldTsc;
     3667            Assert(uRawNewTsc - pVCpu->tm.s.offTSCRawSrc >= uOldTsc); /* paranoia^256 */
     3668        }
     3669
     3670        LogRel(("TM: Switching TSC mode from '%s' to '%s'\n", tmR3GetTSCModeNameEx(pVM->tm.s.enmTSCMode),
     3671                tmR3GetTSCModeNameEx(TMTSCMODE_REAL_TSC_OFFSET)));
     3672        pVM->tm.s.enmTSCMode = TMTSCMODE_REAL_TSC_OFFSET;
     3673    }
    36713674    return VINF_SUCCESS;
    36723675}
     
    36853688    int rc = VINF_SUCCESS;
    36863689    if (pVM->tm.s.fTSCModeSwitchAllowed)
    3687     {
    3688         if (pVM->tm.s.enmTSCMode != TMTSCMODE_REAL_TSC_OFFSET)
    3689             rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, tmR3CpuTickParavirtEnable, NULL);
    3690     }
     3690        rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, tmR3CpuTickParavirtEnable, NULL);
    36913691    else
    36923692        LogRel(("TM: Host/VM is not suitable for using TSC mode '%s', request to change TSC mode ignored\n",
     
    37043704{
    37053705    AssertPtr(pVM); Assert(pVM->tm.s.fTSCModeSwitchAllowed); NOREF(pVCpuEmt);
    3706     Assert(   pVM->tm.s.enmTSCMode == TMTSCMODE_REAL_TSC_OFFSET
    3707            && pVM->tm.s.enmTSCMode != pVM->tm.s.enmOriginalTSCMode);
    37083706    RT_NOREF1(pvData);
    37093707
    3710     /*
    3711      * See tmR3CpuTickParavirtEnable for an explanation of the conversion math.
    3712      */
    3713     uint64_t uRawOldTsc = SUPReadTsc();
    3714     uint64_t uRawNewTsc = tmR3CpuTickGetRawVirtualNoCheck(pVM);
    3715     uint32_t cCpus = pVM->cCpus;
    3716     for (uint32_t i = 0; i < cCpus; i++)
    3717     {
    3718         PVMCPU   pVCpu   = pVM->apCpusR3[i];
    3719         uint64_t uOldTsc = uRawOldTsc - pVCpu->tm.s.offTSCRawSrc;
    3720         pVCpu->tm.s.offTSCRawSrc = uRawNewTsc - uOldTsc;
    3721         Assert(uRawNewTsc - pVCpu->tm.s.offTSCRawSrc >= uOldTsc); /* paranoia^256 */
    3722 
    3723         /* Update the last-seen tick here as we havent't been updating it (as we don't
    3724            need it) while in pure TSC-offsetting mode. */
    3725         pVCpu->tm.s.u64TSCLastSeen = uOldTsc;
    3726     }
    3727 
    3728     LogRel(("TM: Switching TSC mode from '%s' to '%s'\n", tmR3GetTSCModeNameEx(pVM->tm.s.enmTSCMode),
    3729             tmR3GetTSCModeNameEx(pVM->tm.s.enmOriginalTSCMode)));
    3730     pVM->tm.s.enmTSCMode = pVM->tm.s.enmOriginalTSCMode;
     3708    if (   pVM->tm.s.enmTSCMode == TMTSCMODE_REAL_TSC_OFFSET
     3709        && pVM->tm.s.enmTSCMode != pVM->tm.s.enmOriginalTSCMode)
     3710    {
     3711        /*
     3712         * See tmR3CpuTickParavirtEnable for an explanation of the conversion math.
     3713         */
     3714        uint64_t uRawOldTsc = SUPReadTsc();
     3715        uint64_t uRawNewTsc = tmR3CpuTickGetRawVirtualNoCheck(pVM);
     3716        uint32_t cCpus = pVM->cCpus;
     3717        for (uint32_t i = 0; i < cCpus; i++)
     3718        {
     3719            PVMCPU   pVCpu   = pVM->apCpusR3[i];
     3720            uint64_t uOldTsc = uRawOldTsc - pVCpu->tm.s.offTSCRawSrc;
     3721            pVCpu->tm.s.offTSCRawSrc = uRawNewTsc - uOldTsc;
     3722            Assert(uRawNewTsc - pVCpu->tm.s.offTSCRawSrc >= uOldTsc); /* paranoia^256 */
     3723
     3724            /* Update the last-seen tick here as we havent't been updating it (as we don't
     3725               need it) while in pure TSC-offsetting mode. */
     3726            pVCpu->tm.s.u64TSCLastSeen = uOldTsc;
     3727        }
     3728
     3729        LogRel(("TM: Switching TSC mode from '%s' to '%s'\n", tmR3GetTSCModeNameEx(pVM->tm.s.enmTSCMode),
     3730                tmR3GetTSCModeNameEx(pVM->tm.s.enmOriginalTSCMode)));
     3731        pVM->tm.s.enmTSCMode = pVM->tm.s.enmOriginalTSCMode;
     3732    }
    37313733    return VINF_SUCCESS;
    37323734}
     
    37453747{
    37463748    int rc = VINF_SUCCESS;
    3747     if (   pVM->tm.s.fTSCModeSwitchAllowed
    3748         && pVM->tm.s.enmTSCMode == TMTSCMODE_REAL_TSC_OFFSET
    3749         && pVM->tm.s.enmTSCMode != pVM->tm.s.enmOriginalTSCMode)
     3749    if (pVM->tm.s.fTSCModeSwitchAllowed)
    37503750        rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, tmR3CpuTickParavirtDisable, NULL);
    37513751    pVM->tm.s.fParavirtTscEnabled = false;
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