Re: [PATCH v5 32/44] KVM: x86/pmu: Disable interception of select PMU MSRs for mediated vPMUs

Mi, Dapeng
2025-10-09T02:19:51Z

On 10/2/2025 2:14 AM, Sean Christopherson wrote:
> On Fri, Sep 26, 2025, Sandipan Das wrote:
>> On 8/7/2025 1:26 AM, Sean Christopherson wrote:
>>> From: Dapeng Mi <dapeng1.mi@linux.intel.com>
>>>
>>> For vCPUs with a mediated vPMU, disable interception of counter MSRs for
>>> PMCs that are exposed to the guest, and for GLOBAL_CTRL and related MSRs
>>> if they are fully supported according to the vCPU model, i.e. if the MSRs
>>> and all bits supported by hardware exist from the guest's point of view.
>>>
>>> Do NOT passthrough event selector or fixed counter control MSRs, so that
>>> KVM can enforce userspace-defined event filters, e.g. to prevent use of
>>> AnyThread events (which is unfortunately a setting in the fixed counter
>>> control MSR).
>>>
>>> Defer support for nested passthrough of mediated PMU MSRs to the future,
>>> as the logic for nested MSR interception is unfortunately vendor specific.
> ...
>
>>> #define MSR_AMD64_LBR_SELECT 0xc000010e
>>> diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
>>> index 4246e1d2cfcc..817ef852bdf9 100644
>>> --- a/arch/x86/kvm/pmu.c
>>> +++ b/arch/x86/kvm/pmu.c
>>> @@ -715,18 +715,14 @@ int kvm_pmu_rdpmc(struct kvm_vcpu *vcpu, unsigned idx, u64 *data)
>>> return 0;
>>> }
>>>
>>> -bool kvm_need_rdpmc_intercept(struct kvm_vcpu *vcpu)
>>> +bool kvm_need_perf_global_ctrl_intercept(struct kvm_vcpu *vcpu)
>>> {
>>> struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
>>>
>>> if (!kvm_vcpu_has_mediated_pmu(vcpu))
>>> return true;
>>>
>>> - /*
>>> - * VMware allows access to these Pseduo-PMCs even when read via RDPMC
>>> - * in Ring3 when CR4.PCE=0.
>>> - */
>>> - if (enable_vmware_backdoor)
>>> + if (!kvm_pmu_has_perf_global_ctrl(pmu))
>>> return true;
>>>
>>> /*
>>> @@ -735,7 +731,22 @@ bool kvm_need_rdpmc_intercept(struct kvm_vcpu *vcpu)
>>> * capabilities themselves may be a subset of hardware capabilities.
>>> */
>>> return pmu->nr_arch_gp_counters != kvm_host_pmu.num_counters_gp ||
>>> - pmu->nr_arch_fixed_counters != kvm_host_pmu.num_counters_fixed ||
>>> + pmu->nr_arch_fixed_counters != kvm_host_pmu.num_counters_fixed;
>>> +}
>>> +EXPORT_SYMBOL_GPL(kvm_need_perf_global_ctrl_intercept);
>>> +
>>> +bool kvm_need_rdpmc_intercept(struct kvm_vcpu *vcpu)
>>> +{
>>> + struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
>>> +
>>> + /*
>>> + * VMware allows access to these Pseduo-PMCs even when read via RDPMC
>>> + * in Ring3 when CR4.PCE=0.
>>> + */
>>> + if (enable_vmware_backdoor)
>>> + return true;
>>> +
>>> + return kvm_need_perf_global_ctrl_intercept(vcpu) ||
>>> pmu->counter_bitmask[KVM_PMC_GP] != (BIT_ULL(kvm_host_pmu.bit_width_gp) - 1) ||
>>> pmu->counter_bitmask[KVM_PMC_FIXED] != (BIT_ULL(kvm_host_pmu.bit_width_fixed) - 1);
>>> }
>> There is a case for AMD processors where the global MSRs are absent in the guest
>> but the guest still uses the same number of counters as what is advertised by the
>> host capabilities. So RDPMC interception is not necessary for all cases where
>> global control is unavailable.o
> Hmm, I think Intel would be the same? Ah, no, because the host will have fixed
> counters, but the guest will not. However, that's not directly related to
> kvm_pmu_has_perf_global_ctrl(), so I think this would be correct?
>
> diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
> index 4414d070c4f9..4c5b2712ee4c 100644
> --- a/arch/x86/kvm/pmu.c
> +++ b/arch/x86/kvm/pmu.c
> @@ -744,16 +744,13 @@ int kvm_pmu_rdpmc(struct kvm_vcpu *vcpu, unsigned idx, u64 *data)
> return 0;
> }
>
> -bool kvm_need_perf_global_ctrl_intercept(struct kvm_vcpu *vcpu)
> +static bool kvm_need_pmc_intercept(struct kvm_vcpu *vcpu)

The function name kvm_need_pmc_intercept() seems a little bit misleading
and make users think this function is used to check if a certain PMC is
intercepted. Maybe we can rename the function to kvm_need_global_intercept().

Others look good to me. Thanks.

> {
> struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
>
> if (!kvm_vcpu_has_mediated_pmu(vcpu))
> return true;
>
> - if (!kvm_pmu_has_perf_global_ctrl(pmu))
> - return true;
> -
> /*
> * Note! Check *host* PMU capabilities, not KVM's PMU capabilities, as
> * KVM's capabilities are constrained based on KVM support, i.e. KVM's
> @@ -762,6 +759,13 @@ bool kvm_need_perf_global_ctrl_intercept(struct kvm_vcpu *vcpu)
> return pmu->nr_arch_gp_counters != kvm_host_pmu.num_counters_gp ||
> pmu->nr_arch_fixed_counters != kvm_host_pmu.num_counters_fixed;
> }
> +
> +bool kvm_need_perf_global_ctrl_intercept(struct kvm_vcpu *vcpu)
> +{
> +
> + return kvm_need_pmc_intercept(vcpu) ||
> + !kvm_pmu_has_perf_global_ctrl(vcpu_to_pmu(vcpu));
> +}
> EXPORT_SYMBOL_GPL(kvm_need_perf_global_ctrl_intercept);
>
> bool kvm_need_rdpmc_intercept(struct kvm_vcpu *vcpu)
> @@ -775,7 +779,7 @@ bool kvm_need_rdpmc_intercept(struct kvm_vcpu *vcpu)
> if (enable_vmware_backdoor)
> return true;
>
> - return kvm_need_perf_global_ctrl_intercept(vcpu) ||
> + return kvm_need_pmc_intercept(vcpu) ||
> pmu->counter_bitmask[KVM_PMC_GP] != (BIT_ULL(kvm_host_pmu.bit_width_gp) - 1) ||
> pmu->counter_bitmask[KVM_PMC_FIXED] != (BIT_ULL(kvm_host_pmu.bit_width_fixed) - 1);
> }
>