Re: [PATCH v5 17/44] KVM: x86/pmu: Snapshot host (i.e. perf's) reported PMU capabilities

Sandipan Das
2025-08-13T09:56:45Z

On 07-08-2025 01:26, Sean Christopherson wrote:
> Take a snapshot of the unadulterated PMU capabilities provided by perf so
> that KVM can compare guest vPMU capabilities against hardware capabilities
> when determining whether or not to intercept PMU MSRs (and RDPMC).
>
> Signed-off-by: Sean Christopherson <seanjc@google.com>
> ---
> arch/x86/kvm/pmu.c | 15 ++++++++++-----
> 1 file changed, 10 insertions(+), 5 deletions(-)
>
> diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
> index 3206412a35a1..0f3e011824ed 100644
> --- a/arch/x86/kvm/pmu.c
> +++ b/arch/x86/kvm/pmu.c
> @@ -26,6 +26,10 @@
> /* This is enough to filter the vast majority of currently defined events. */
> #define KVM_PMU_EVENT_FILTER_MAX_EVENTS 300
>
> +/* Unadultered PMU capabilities of the host, i.e. of hardware. */
> +static struct x86_pmu_capability __read_mostly kvm_host_pmu;
> +
> +/* KVM's PMU capabilities, i.e. the intersection of KVM and hardware support. */
> struct x86_pmu_capability __read_mostly kvm_pmu_cap;
> EXPORT_SYMBOL_GPL(kvm_pmu_cap);
>
> @@ -104,6 +108,8 @@ void kvm_init_pmu_capability(const struct kvm_pmu_ops *pmu_ops)
> bool is_intel = boot_cpu_data.x86_vendor == X86_VENDOR_INTEL;
> int min_nr_gp_ctrs = pmu_ops->MIN_NR_GP_COUNTERS;
>
> + perf_get_x86_pmu_capability(&kvm_host_pmu);
> +
> /*
> * Hybrid PMUs don't play nice with virtualization without careful
> * configuration by userspace, and KVM's APIs for reporting supported
> @@ -114,18 +120,16 @@ void kvm_init_pmu_capability(const struct kvm_pmu_ops *pmu_ops)
> enable_pmu = false;
>
> if (enable_pmu) {
> - perf_get_x86_pmu_capability(&kvm_pmu_cap);
> -
> /*
> * WARN if perf did NOT disable hardware PMU if the number of
> * architecturally required GP counters aren't present, i.e. if
> * there are a non-zero number of counters, but fewer than what
> * is architecturally required.
> */
> - if (!kvm_pmu_cap.num_counters_gp ||
> - WARN_ON_ONCE(kvm_pmu_cap.num_counters_gp < min_nr_gp_ctrs))
> + if (!kvm_host_pmu.num_counters_gp ||
> + WARN_ON_ONCE(kvm_host_pmu.num_counters_gp < min_nr_gp_ctrs))
> enable_pmu = false;
> - else if (is_intel && !kvm_pmu_cap.version)
> + else if (is_intel && !kvm_host_pmu.version)
> enable_pmu = false;
> }
>
> @@ -134,6 +138,7 @@ void kvm_init_pmu_capability(const struct kvm_pmu_ops *pmu_ops)
> return;
> }
>
> + memcpy(&kvm_pmu_cap, &kvm_host_pmu, sizeof(kvm_host_pmu));
> kvm_pmu_cap.version = min(kvm_pmu_cap.version, 2);
> kvm_pmu_cap.num_counters_gp = min(kvm_pmu_cap.num_counters_gp,
> pmu_ops->MAX_NR_GP_COUNTERS);

Reviewed-by: Sandipan Das <sandipan.das@amd.com>