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

Sean Christopherson
2025-10-01T18:14:26Z

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)
{
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);
}