Re: [PATCH V5 6/7] KVM: x86/pmu: Emulate RDPMC on performance metrics

From: Mi, Dapeng

Date: Thu Jun 25 2026 - 05:20:52 EST



On 6/25/2026 11:45 AM, Zide Chen wrote:
> If the host has the PERF_METRICS capability but it's not present on
> the guest, RDPMC interception must be enabled and KVM should inject
> an #GP when the guest attempts to read it.
>
> If the guest has PERF_METRICS, but RDPMC interception is enabled for
> other reasons, KVM needs to emulate RDPMC with type 2000H.
>
> For simplicity, Metrics Clear Mode is not supported.
>
> Signed-off-by: Zide Chen <zide.chen@xxxxxxxxx>
> ---
> v5: new patch.
> ---
> arch/x86/kvm/pmu.c | 30 ++++++++++++++++++++++++++----
> 1 file changed, 26 insertions(+), 4 deletions(-)
>
> diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
> index 7aafc5db1346..af5b14f44e4b 100644
> --- a/arch/x86/kvm/pmu.c
> +++ b/arch/x86/kvm/pmu.c
> @@ -755,6 +755,16 @@ static int kvm_pmu_rdpmc_vmware(struct kvm_vcpu *vcpu, unsigned idx, u64 *data)
> return 0;
> }
>
> +static int kvm_pmu_rdpmc_metrics(struct kvm_vcpu *vcpu,
> + unsigned idx, u64 *data)
> +{
> + if (!kvm_vcpu_has_perf_metrics(vcpu))
> + return 1;
> +
> + *data = vcpu_to_pmu(vcpu)->perf_metrics;
> + return 0;
> +}
> +
> int kvm_pmu_rdpmc(struct kvm_vcpu *vcpu, unsigned idx, u64 *data)
> {
> struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
> @@ -767,15 +777,18 @@ int kvm_pmu_rdpmc(struct kvm_vcpu *vcpu, unsigned idx, u64 *data)
> if (is_vmware_backdoor_pmc(idx))
> return kvm_pmu_rdpmc_vmware(vcpu, idx, data);
>
> - pmc = kvm_pmu_call(rdpmc_ecx_to_pmc)(vcpu, idx, &mask);
> - if (!pmc)
> - return 1;
> -
> if (!kvm_is_cr4_bit_set(vcpu, X86_CR4_PCE) &&
> (kvm_x86_call(get_cpl)(vcpu) != 0) &&
> kvm_is_cr0_bit_set(vcpu, X86_CR0_PE))
> return 1;
>
> + if (idx & INTEL_PMC_FIXED_RDPMC_METRICS)

I'm not quite sure if this check is good enough. Although the SDM vol.2
says "Performance metrics use type 2000H. This type can be used only if
IA32_PERF_CAPABILITIES.PERF_METRICS_AVAILABLE[bit 15]=1. For this type, the
index in ECX[15:0] is implementation specific." It doesn't say the PMC
index must be 0, but we always set the PMC index to 0 when reading topdown
metrics.

Could you please test to run the rdpmc instruction to read topdown metrics
with valid and invalid PMC index on real HW and look what would happen? Thanks.


> + return kvm_pmu_rdpmc_metrics(vcpu, idx, data);
> +
> + pmc = kvm_pmu_call(rdpmc_ecx_to_pmc)(vcpu, idx, &mask);
> + if (!pmc)
> + return 1;
> +
> *data = pmc_read_counter(pmc) & mask;
> return 0;
> }
> @@ -803,6 +816,14 @@ bool kvm_need_perf_global_ctrl_intercept(struct kvm_vcpu *vcpu)
> }
> EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_need_perf_global_ctrl_intercept);
>
> +static bool kvm_need_perf_metrics_intercept(struct kvm_vcpu *vcpu)
> +{
> + if (!(kvm_host.perf_capabilities & PERF_CAP_PERF_METRICS))
> + return false;
> +
> + return !kvm_vcpu_has_perf_metrics(vcpu);
> +}
> +
> bool kvm_need_rdpmc_intercept(struct kvm_vcpu *vcpu)
> {
> struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
> @@ -815,6 +836,7 @@ bool kvm_need_rdpmc_intercept(struct kvm_vcpu *vcpu)
> return true;
>
> return kvm_need_any_pmc_intercept(vcpu) ||
> + kvm_need_perf_metrics_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);
> }