VirtualBox

Changeset 79648 in vbox


Ignore:
Timestamp:
Jul 10, 2019 4:54:24 AM (6 years ago)
Author:
vboxsync
Message:

VMM/HMVMXR0: Nested VMX: bugref:9180 Fix TSC offsetting when using nested-guests. We should only remove the RDTSC exiting control when -both- the guest and nested-guest allow it. Fixed statistics on TSC offset vs intercept to be more useful (not just when changing controls which is optimized to avoid vmwrites when unneeded and on CPU migrations etc). Use the new macros added in r131955.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp

    r79637 r79648  
    924924
    925925
    926 #if 0
    927 /**
    928  * Checks whether one of the given Processor-based VM-execution controls are set.
    929  *
    930  * @returns @c true if set, @c false otherwise.
     926/**
     927 * Sets the given Processor-based VM-execution controls.
     928 *
     929 * @param   pVmxTransient   The VMX-transient structure.
     930 * @param   uProcCtls       The Processor-based VM-execution controls to set.
     931 */
     932static void hmR0VmxSetProcCtlsVmcs(PVMXTRANSIENT pVmxTransient, uint32_t uProcCtls)
     933{
     934    PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
     935    if ((pVmcsInfo->u32ProcCtls & uProcCtls) != uProcCtls)
     936    {
     937        pVmcsInfo->u32ProcCtls |= uProcCtls;
     938        int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
     939        AssertRC(rc);
     940    }
     941}
     942
     943
     944/**
     945 * Removes the given Processor-based VM-execution controls.
     946 *
    931947 * @param   pVCpu           The cross context virtual CPU structure.
    932948 * @param   pVmxTransient   The VMX-transient structure.
    933  * @param   uProcCtls       The Processor-based VM-execution controls to check.
    934  *
    935  * @remarks This will not check merged controls when executing a nested-guest
    936  *          but the original control specified by the guest hypervisor.
    937  */
    938 static bool hmR0VmxIsProcCtlsSet(PVMCPU pVCpu, PCVMXTRANSIENT pVmxTransient, uint32_t uProcCtls)
    939 {
    940     if (!pVmxTransient->fIsNestedGuest)
    941     {
    942         PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
    943         return RT_BOOL(pVmcsInfo->u32ProcCtls & uProcCtls);
    944     }
    945     return CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, uProcCtls);
    946 }
    947 
    948 
    949 /**
    950  * Checks whether one of the given Secondary Processor-based VM-execution controls
    951  * are set.
    952  *
    953  * @returns @c true if set, @c false otherwise.
    954  * @param   pVCpu           The cross context virtual CPU structure.
    955  * @param   pVmxTransient   The VMX-transient structure.
    956  * @param   uProcCtls2      The Secondary Processor-based VM-execution controls to
    957  *                          check.
    958  *
    959  * @remarks This will not check merged controls when executing a nested-guest
    960  *          but the original control specified by the guest hypervisor.
    961  */
    962 static bool hmR0VmxIsProcCtls2Set(PVMCPU pVCpu, PCVMXTRANSIENT pVmxTransient, uint32_t uProcCtls2)
    963 {
    964     if (!pVmxTransient->fIsNestedGuest)
    965     {
    966         PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
    967         return RT_BOOL(pVmcsInfo->u32ProcCtls2 & uProcCtls2);
    968     }
    969     return CPUMIsGuestVmxProcCtls2Set(pVCpu, &pVCpu->cpum.GstCtx, uProcCtls2);
    970 }
    971 
    972 
    973 /**
    974  * Checks whether one of the given VM-entry controls are set.
    975  *
    976  * @returns @c true if set, @c false otherwise.
    977  * @param   pVCpu           The cross context virtual CPU structure.
    978  * @param   pVmxTransient   The VMX-transient structure.
    979  * @param   uEntryCtls      The VM-entry controls to check.
    980  *
    981  * @remarks This will not check merged controls when executing a nested-guest
    982  *          but the original control specified by the guest hypervisor.
    983  */
    984 static bool hmR0VmxIsEntryCtlsSet(PVMCPU pVCpu, PCVMXTRANSIENT pVmxTransient, uint32_t uEntryCtls)
    985 {
    986     if (!pVmxTransient->fIsNestedGuest)
    987     {
    988         PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
    989         return RT_BOOL(pVmcsInfo->u32EntryCtls & uEntryCtls);
    990     }
    991     return CPUMIsGuestVmxEntryCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, uEntryCtls);
    992 }
    993 
    994 
    995 /**
    996  * Checks whether one of the given VM-exit controls are set.
    997  *
    998  * @returns @c true if set, @c false otherwise.
    999  * @param   pVCpu           The cross context virtual CPU structure.
    1000  * @param   pVmxTransient   The VMX-transient structure.
    1001  * @param   uExitCtls       The VM-exit controls to check.
    1002  *
    1003  * @remarks This will not check merged controls when executing a nested-guest
    1004  *          but the original control specified by the guest hypervisor.
    1005  */
    1006 static bool hmR0VmxIsExitCtlsSet(PVMCPU pVCpu, PCVMXTRANSIENT pVmxTransient, uint32_t uExitCtls)
    1007 {
    1008     if (!pVmxTransient->fIsNestedGuest)
    1009     {
    1010         PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
    1011         return RT_BOOL(pVmcsInfo->u32ExitCtls & uExitCtls);
    1012     }
    1013     return CPUMIsGuestVmxExitCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, uExitCtls);
    1014 }
     949 * @param   uProcCtls       The Processor-based VM-execution controls to remove.
     950 *
     951 * @remarks When executing a nested-guest, this will not remove any of the specified
     952 *          controls if the guest hypervisor has set any one of them.
     953 */
     954static void hmR0VmxRemoveProcCtlsVmcs(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, uint32_t uProcCtls)
     955{
     956#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
     957    bool const fRemoveCtls = !pVmxTransient->fIsNestedGuest
     958                           ? true
     959                           : !CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_RDTSC_EXIT);
     960#else
     961    bool const fRemoveCtls = true;
    1015962#endif
     963    PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
     964    if (   fRemoveCtls
     965        && (pVmcsInfo->u32ProcCtls & uProcCtls))
     966    {
     967        pVmcsInfo->u32ProcCtls &= ~uProcCtls;
     968        int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
     969        AssertRC(rc);
     970    }
     971}
     972
     973
     974/**
     975 * Sets the TSC offset for the current VMCS.
     976 *
     977 * @param   uTscOffset  The TSC offset to set.
     978 * @param   pVmcsInfo   The VMCS info. object.
     979 */
     980static void hmR0VmxSetTscOffsetVmcs(PVMXVMCSINFO pVmcsInfo, uint64_t uTscOffset)
     981{
     982    if (pVmcsInfo->u64TscOffset != uTscOffset)
     983    {
     984        int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_TSC_OFFSET_FULL, uTscOffset);
     985        AssertRC(rc);
     986        pVmcsInfo->u64TscOffset = uTscOffset;
     987    }
     988}
    1016989
    1017990
     
    75247497    }
    75257498
    7526     uint32_t uProcCtls = pVmcsInfo->u32ProcCtls;
    75277499    if (   fOffsettedTsc
    75287500        && RT_LIKELY(!pVCpu->hm.s.fDebugWantRdTscExit))
     
    75307502        if (pVmxTransient->fIsNestedGuest)
    75317503            uTscOffset = CPUMApplyNestedGuestTscOffset(pVCpu, uTscOffset);
    7532         if (pVmcsInfo->u64TscOffset != uTscOffset)
    7533         {
    7534             int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_TSC_OFFSET_FULL, uTscOffset);
    7535             AssertRC(rc);
    7536             pVmcsInfo->u64TscOffset = uTscOffset;
    7537         }
    7538 
    7539         if (uProcCtls & VMX_PROC_CTLS_RDTSC_EXIT)
    7540         {
    7541             uProcCtls &= ~VMX_PROC_CTLS_RDTSC_EXIT;
    7542             int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, uProcCtls);
    7543             AssertRC(rc);
    7544             pVmcsInfo->u32ProcCtls = uProcCtls;
    7545         }
    7546         STAM_COUNTER_INC(&pVCpu->hm.s.StatTscOffset);
     7504        hmR0VmxSetTscOffsetVmcs(pVmcsInfo, uTscOffset);
     7505        hmR0VmxRemoveProcCtlsVmcs(pVCpu, pVmxTransient, VMX_PROC_CTLS_RDTSC_EXIT);
    75477506    }
    75487507    else
    75497508    {
    75507509        /* We can't use TSC-offsetting (non-fixed TSC, warp drive active etc.), VM-exit on RDTSC(P). */
    7551         if (!(uProcCtls & VMX_PROC_CTLS_RDTSC_EXIT))
    7552         {
    7553             uProcCtls |= VMX_PROC_CTLS_RDTSC_EXIT;
    7554             int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, uProcCtls);
    7555             AssertRC(rc);
    7556             pVmcsInfo->u32ProcCtls = uProcCtls;
    7557         }
    7558         STAM_COUNTER_INC(&pVCpu->hm.s.StatTscIntercept);
     7510        hmR0VmxSetProcCtlsVmcs(pVmxTransient, VMX_PROC_CTLS_RDTSC_EXIT);
    75597511    }
    75607512}
     
    93459297                /*
    93469298                 * If we eventually support nested-guest execution without unrestricted guest execution,
    9347                  * we should clear fInterceptEvents here.
     9299                 * we should set fInterceptEvents here.
    93489300                 */
    93499301                Assert(!pVmxTransient->fIsNestedGuest);
     
    93779329     * Update guest CR2 if this is a page-fault.
    93789330     */
    9379     if (   VMX_ENTRY_INT_INFO_TYPE(u32IntInfo) == VMX_EXIT_INT_INFO_TYPE_HW_XCPT
    9380         && uVector == X86_XCPT_PF)
     9331    if (VMX_ENTRY_INT_INFO_IS_XCPT_PF(u32IntInfo))
    93819332        pCtx->cr2 = GCPtrFault;
    93829333
     
    100239974{
    100249975#define HMVMX_ERROR_BREAK(err)              { uError = (err); break; }
    10025 #define HMVMX_CHECK_BREAK(expr, err)        if (!(expr)) { \
    10026                                                 uError = (err); \
    10027                                                 break; \
    10028                                             } else do { } while (0)
     9976#define HMVMX_CHECK_BREAK(expr, err)        do { \
     9977                                                if (!(expr)) { uError = (err); break; } \
     9978                                            } while (0)
    100299979
    100309980    int        rc;
     
    1013510085        rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &u32EntryInfo);
    1013610086        AssertRCBreak(rc);
    10137         if (   VMX_ENTRY_INT_INFO_IS_VALID(u32EntryInfo)
    10138             && VMX_ENTRY_INT_INFO_TYPE(u32EntryInfo) == VMX_EXIT_INT_INFO_TYPE_EXT_INT)
    10139         {
     10087        if (VMX_ENTRY_INT_INFO_IS_EXT_INT(u32EntryInfo))
    1014010088            HMVMX_CHECK_BREAK(u32Eflags & X86_EFL_IF, VMX_IGS_RFLAGS_IF_INVALID);
    10141         }
    1014210089
    1014310090        /*
     
    1050010447                          || !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI),
    1050110448                          VMX_IGS_INTERRUPTIBILITY_STATE_STI_EFL_INVALID);
    10502         if (VMX_ENTRY_INT_INFO_IS_VALID(u32EntryInfo))
    10503         {
    10504             if (VMX_ENTRY_INT_INFO_TYPE(u32EntryInfo) == VMX_EXIT_INT_INFO_TYPE_EXT_INT)
    10505             {
    10506                 HMVMX_CHECK_BREAK(   !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
    10507                                   && !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS),
    10508                                   VMX_IGS_INTERRUPTIBILITY_STATE_EXT_INT_INVALID);
    10509             }
    10510             else if (VMX_ENTRY_INT_INFO_TYPE(u32EntryInfo) == VMX_EXIT_INT_INFO_TYPE_NMI)
    10511             {
    10512                 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS),
    10513                                   VMX_IGS_INTERRUPTIBILITY_STATE_MOVSS_INVALID);
    10514                 HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI),
    10515                                   VMX_IGS_INTERRUPTIBILITY_STATE_STI_INVALID);
    10516             }
     10449        if (VMX_ENTRY_INT_INFO_IS_EXT_INT(u32EntryInfo))
     10450        {
     10451            HMVMX_CHECK_BREAK(   !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
     10452                              && !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS),
     10453                              VMX_IGS_INTERRUPTIBILITY_STATE_EXT_INT_INVALID);
     10454        }
     10455        else if (VMX_ENTRY_INT_INFO_IS_XCPT_NMI(u32EntryInfo))
     10456        {
     10457            HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS),
     10458                              VMX_IGS_INTERRUPTIBILITY_STATE_MOVSS_INVALID);
     10459            HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI),
     10460                              VMX_IGS_INTERRUPTIBILITY_STATE_STI_INVALID);
    1051710461        }
    1051810462        /** @todo Assumes the processor is not in SMM. */
     
    1052310467                             VMX_IGS_INTERRUPTIBILITY_STATE_SMI_SMM_INVALID);
    1052410468        if (   (pVmcsInfo->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
    10525             && VMX_ENTRY_INT_INFO_IS_VALID(u32EntryInfo)
    10526             && VMX_ENTRY_INT_INFO_TYPE(u32EntryInfo) == VMX_EXIT_INT_INFO_TYPE_NMI)
     10469            && VMX_ENTRY_INT_INFO_IS_XCPT_NMI(u32EntryInfo))
    1052710470        {
    1052810471            HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI),
     
    1132411267    }
    1132511268
     11269    /* Record statistics of how often we use TSC offsetting as opposed to intercepting RDTSC/P. */
     11270    bool const fIsRdtscIntercepted = RT_BOOL(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_RDTSC_EXIT);
     11271    if (!fIsRdtscIntercepted)
     11272        STAM_COUNTER_INC(&pVCpu->hm.s.StatTscOffset);
     11273    else
     11274        STAM_COUNTER_INC(&pVCpu->hm.s.StatTscIntercept);
     11275
    1132611276    ASMAtomicWriteBool(&pVCpu->hm.s.fCheckedTLBFlush, true);    /* Used for TLB flushing, set this across the world switch. */
    1132711277    hmR0VmxFlushTaggedTlb(pHostCpu, pVCpu, pVmcsInfo);          /* Invalidate the appropriate guest entries from the TLB. */
     
    1134311293     */
    1134411294    if (    (pVmcsInfo->u32ProcCtls2 & VMX_PROC_CTLS2_RDTSCP)
    11345         && !(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_RDTSC_EXIT))
     11295        && !fIsRdtscIntercepted)
    1134611296    {
    1134711297        hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_TSC_AUX);
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