[PATCH v6 7/8] KVM: x86/pmu: Emulate RDPMC on performance metrics

From: Zide Chen

Date: Mon Jun 29 2026 - 19:33:44 EST


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 a PERF_METRICS RDPMC.

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>
---
v6:
- Merge kvm_pmu_rdpmc_metrics() into intel_emulate_rdpmc().
- Reject non-zero index.
v5:
- new patch.
---
arch/x86/kvm/pmu.c | 7 +++++++
arch/x86/kvm/vmx/pmu_intel.c | 14 ++++++++++++++
2 files changed, 21 insertions(+)

diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
index 8ef2d4761790..04b9c840f218 100644
--- a/arch/x86/kvm/pmu.c
+++ b/arch/x86/kvm/pmu.c
@@ -806,6 +806,12 @@ 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)
+{
+ return (kvm_host.perf_capabilities & PERF_CAP_PERF_METRICS) &&
+ !kvm_vcpu_has_perf_metrics(vcpu);
+}
+
bool kvm_need_rdpmc_intercept(struct kvm_vcpu *vcpu)
{
struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
@@ -818,6 +824,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);
}
diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c
index 080677372c9b..93b5a8360377 100644
--- a/arch/x86/kvm/vmx/pmu_intel.c
+++ b/arch/x86/kvm/vmx/pmu_intel.c
@@ -30,6 +30,7 @@
*/
#define INTEL_RDPMC_GP 0
#define INTEL_RDPMC_FIXED INTEL_PMC_FIXED_RDPMC_BASE
+#define INTEL_RDPMC_METRICS INTEL_PMC_FIXED_RDPMC_METRICS

#define INTEL_RDPMC_TYPE_MASK GENMASK(31, 16)
#define INTEL_RDPMC_INDEX_MASK GENMASK(15, 0)
@@ -124,6 +125,19 @@ static int intel_emulate_rdpmc(struct kvm_vcpu *vcpu, unsigned int idx,
counters = pmu->gp_counters;
num_counters = pmu->nr_arch_gp_counters;
break;
+ case INTEL_RDPMC_METRICS:
+ if (!kvm_vcpu_has_perf_metrics(vcpu))
+ return 1;
+
+ /*
+ * The index in ECX[15:0] is implementation specific, but no
+ * platform currently supports a non-zero index.
+ */
+ if (idx)
+ return 1;
+
+ *data = pmu->perf_metrics;
+ return 0;
default:
return 1;
}
--
2.54.0