VirtualBox

Changeset 102604 in vbox for trunk/src/VBox/VMM/VMMR3


Ignore:
Timestamp:
Dec 15, 2023 6:49:33 AM (13 months ago)
Author:
vboxsync
Message:

VMM/CPUM: bugref:10498 Fix the maximum physical address width supported by the variable-range MTRR MSRs when it differs from what is reported via CPUID.

File:
1 edited

Legend:

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

    r102588 r102604  
    30483048
    30493049/**
     3050 * Checks and fixes the maximum physical address width supported by the
     3051 * variable-range MTRR MSRs to be consistent with what is reported in CPUID.
     3052 *
     3053 * @returns VBox status code.
     3054 * @param   pVM         The cross context VM structure.
     3055 * @param   cVarMtrrs   The number of variable-range MTRRs reported to the guest.
     3056 */
     3057static int cpumR3FixVarMtrrPhysAddrWidths(PVM pVM, uint8_t const cVarMtrrs)
     3058{
     3059    AssertLogRelMsgReturn(cVarMtrrs <= RT_ELEMENTS(pVM->apCpusR3[0]->cpum.s.GuestMsrs.msr.aMtrrVarMsrs),
     3060                          ("Invalid number of variable range MTRRs reported (%u)\n", cVarMtrrs),
     3061                          VERR_CPUM_IPE_2);
     3062
     3063    /*
     3064     * CPUID determines the actual maximum physical address width reported and supported.
     3065     * If the CPU DB profile reported fewer address bits, we must correct it here by
     3066     * updating the MSR write #GP masks of all the variable-range MTRR MSRs. Otherwise,
     3067     * they cause problems when guests write to these MTRR MSRs, see @bugref{10498#c32}.
     3068     */
     3069    for (uint8_t iVarMtrr = 0; iVarMtrr < cVarMtrrs; iVarMtrr++)
     3070    {
     3071        PCPUMMSRRANGE pBaseRange = cpumLookupMsrRange(pVM, MSR_IA32_MTRR_PHYSBASE0 + (iVarMtrr * 2));
     3072        AssertLogRelMsgReturn(pBaseRange, ("Failed to lookup the IA32_MTRR_PHYSBASE[%u] MSR range\n", iVarMtrr),
     3073                              VERR_NOT_FOUND);
     3074
     3075        PCPUMMSRRANGE pMaskRange = cpumLookupMsrRange(pVM, MSR_IA32_MTRR_PHYSMASK0 + (iVarMtrr * 2));
     3076        AssertLogRelMsgReturn(pBaseRange, ("Failed to lookup the IA32_MTRR_PHYSMASK[%u] MSR range\n", iVarMtrr),
     3077                              VERR_NOT_FOUND);
     3078
     3079        uint64_t const fBaseWrGpMask = pBaseRange->fWrGpMask;
     3080        uint64_t const fMaskWrGpMask = pMaskRange->fWrGpMask;
     3081
     3082        uint8_t const  cGuestMaxPhysAddrWidth           = pVM->cpum.s.GuestFeatures.cMaxPhysAddrWidth;
     3083        uint8_t const  cProfilePhysBaseMaxPhysAddrWidth = ASMBitLastSetU64(~fBaseWrGpMask);
     3084        uint8_t const  cProfilePhysMaskMaxPhysAddrWidth = ASMBitLastSetU64(~fMaskWrGpMask);
     3085
     3086        AssertLogRelMsgReturn(cProfilePhysBaseMaxPhysAddrWidth == cProfilePhysMaskMaxPhysAddrWidth,
     3087                              ("IA32_MTRR_PHYSBASE and IA32_MTRR_PHYSMASK report different physical address widths (%u and %u)\n",
     3088                               cProfilePhysBaseMaxPhysAddrWidth, cProfilePhysMaskMaxPhysAddrWidth),
     3089                              VERR_CPUM_IPE_2);
     3090        AssertLogRelMsgReturn(cProfilePhysBaseMaxPhysAddrWidth > 12 && cProfilePhysBaseMaxPhysAddrWidth <= 64,
     3091                              ("IA32_MTRR_PHYSBASE and IA32_MTRR_PHYSMASK reports an invalid physical address width of %u bits\n",
     3092                               cProfilePhysBaseMaxPhysAddrWidth), VERR_CPUM_IPE_2);
     3093
     3094        if (cProfilePhysBaseMaxPhysAddrWidth < cGuestMaxPhysAddrWidth)
     3095        {
     3096            uint64_t fNewBaseWrGpMask = fBaseWrGpMask;
     3097            uint64_t fNewMaskWrGpMask = fMaskWrGpMask;
     3098            int8_t   cBits = cGuestMaxPhysAddrWidth - cProfilePhysBaseMaxPhysAddrWidth;
     3099            while (cBits)
     3100            {
     3101                uint64_t const fWrGpAndMask = ~(uint64_t)RT_BIT_64(cProfilePhysBaseMaxPhysAddrWidth + cBits - 1);
     3102                fNewBaseWrGpMask &= fWrGpAndMask;
     3103                fNewMaskWrGpMask &= fWrGpAndMask;
     3104                --cBits;
     3105            }
     3106
     3107            pBaseRange->fWrGpMask = fBaseWrGpMask;
     3108            pMaskRange->fWrGpMask = fMaskWrGpMask;
     3109
     3110            LogRel(("CPUM: Updated IA32_MTRR_PHYSBASE[%u] MSR write #GP mask (old=%#016RX64 new=%#016RX64)\n",
     3111                    iVarMtrr, fBaseWrGpMask, fNewBaseWrGpMask));
     3112            LogRel(("CPUM: Updated IA32_MTRR_PHYSMASK[%u] MSR write #GP mask (old=%#016RX64 new=%#016RX64)\n",
     3113                    iVarMtrr, fMaskWrGpMask, fNewMaskWrGpMask));
     3114        }
     3115    }
     3116
     3117    return VINF_SUCCESS;
     3118}
     3119
     3120
     3121/**
     3122 * Initialize MTRR capability based on what the guest CPU profile (typically host)
     3123 * supports.
     3124 * 
     3125 * @reports VBox status code.
     3126 * @param   pVM     The cross context VM structure.
     3127 */
     3128static int cpumR3InitMtrrCap(PVM pVM)
     3129{
     3130#ifdef RT_ARCH_AMD64
     3131    Assert(pVM->cpum.s.HostFeatures.fMtrr);
     3132#endif
     3133
     3134    /* Lookup the number of variable-range MTRRs supported by the CPU profile. */
     3135    PCCPUMMSRRANGE pMtrrCapRange = cpumLookupMsrRange(pVM, MSR_IA32_MTRR_CAP);
     3136    AssertLogRelMsgReturn(pMtrrCapRange, ("Failed to lookup IA32_MTRR_CAP MSR range\n"), VERR_NOT_FOUND);
     3137    uint8_t const cProfileVarRangeRegs = pMtrrCapRange->uValue & MSR_IA32_MTRR_CAP_VCNT_MASK;
     3138
     3139    /* Construct guest MTRR support capabilities. */
     3140    uint8_t const  cGuestVarRangeRegs = RT_MIN(cProfileVarRangeRegs, CPUMCTX_MAX_MTRRVAR_COUNT);
     3141    uint64_t const uGstMtrrCap        = cGuestVarRangeRegs
     3142                                      | MSR_IA32_MTRR_CAP_FIX
     3143                                      | MSR_IA32_MTRR_CAP_WC;
     3144    for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
     3145    {
     3146        PVMCPU pVCpu = pVM->apCpusR3[idCpu];
     3147        pVCpu->cpum.s.GuestMsrs.msr.MtrrCap     = uGstMtrrCap;
     3148        pVCpu->cpum.s.GuestMsrs.msr.MtrrDefType = MSR_IA32_MTRR_DEF_TYPE_FIXED_EN
     3149                                                | MSR_IA32_MTRR_DEF_TYPE_MTRR_EN
     3150                                                | X86_MTRR_MT_UC;
     3151    }
     3152
     3153    LogRel(("CPUM: Enabled fixed-range MTRRs and %u variable-range MTRRs\n", cGuestVarRangeRegs));
     3154
     3155    /*
     3156     * Ensure that the maximum physical address width supported by the variable-range MTRRs
     3157     * are consistent with what is reported to the guest via CPUID.
     3158     */
     3159    return cpumR3FixVarMtrrPhysAddrWidths(pVM, cGuestVarRangeRegs);
     3160}
     3161
     3162
     3163/**
    30503164 * Initializes the emulated CPU's CPUID & MSR information.
    30513165 *
     
    33083422            if (pVM->cpum.s.fMtrrRead)
    33093423            {
    3310 #ifdef RT_ARCH_AMD64
    3311                 Assert(pVM->cpum.s.HostFeatures.fMtrr);
    3312 #endif
    3313                 /* Lookup the number of variable-range MTRRs supported by the CPU profile. */
    3314                 PCCPUMMSRRANGE pMtrrCapRange = cpumLookupMsrRange(pVM, MSR_IA32_MTRR_CAP);
    3315                 AssertLogRelReturn(pMtrrCapRange, VERR_CPUM_IPE_2);
    3316                 uint8_t const cProfileVarRangeRegs = pMtrrCapRange->uValue & MSR_IA32_MTRR_CAP_VCNT_MASK;
    3317 
    3318                 /* Construct guest MTRR support capabilities. */
    3319                 uint8_t const  cGuestVarRangeRegs = RT_MIN(cProfileVarRangeRegs, CPUMCTX_MAX_MTRRVAR_COUNT);
    3320                 uint64_t const uGstMtrrCap        = cGuestVarRangeRegs
    3321                                                   | MSR_IA32_MTRR_CAP_FIX
    3322                                                   | MSR_IA32_MTRR_CAP_WC;
    3323                 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
    3324                 {
    3325                     PVMCPU pVCpu = pVM->apCpusR3[idCpu];
    3326                     pVCpu->cpum.s.GuestMsrs.msr.MtrrCap     = uGstMtrrCap;
    3327                     pVCpu->cpum.s.GuestMsrs.msr.MtrrDefType = MSR_IA32_MTRR_DEF_TYPE_FIXED_EN
    3328                                                             | MSR_IA32_MTRR_DEF_TYPE_MTRR_EN
    3329                                                             | X86_MTRR_MT_UC;
    3330                 }
    3331                 LogRel(("CPUM: Enabled fixed-range MTRRs and %u variable-range MTRRs\n", cGuestVarRangeRegs));
     3424                rc = cpumR3InitMtrrCap(pVM);
     3425                if (RT_SUCCESS(rc))
     3426                { /* likely */ }
     3427                else
     3428                    return rc;
    33323429            }
    33333430        }
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