[PATCH v4 05/21] KVM: x86/pmu: Use pmc_exists in PMC lookup helpers

From: Zide Chen

Date: Thu Nov 12 2026 - 17:02:49 EST


pmu->nr_arch_{gp,fixed}_counters cannot represent non-contiguous GP or
fixed counters.

Introduce kvm_is_{gp,fixed}_pmc_supported() to validate counter indices
via pmu->pmc_exists, and switch the PMC lookup helpers to use them in
preparation for dropping nr_arch_{gp,fixed}_counters.

No functional change intended.

Co-developed-by: Dapeng Mi <dapeng1.mi@xxxxxxxxxxxxxxx>
Signed-off-by: Dapeng Mi <dapeng1.mi@xxxxxxxxxxxxxxx>
Signed-off-by: Zide Chen <zide.chen@xxxxxxxxx>
---
v4:
- Move kvm_for_each_{gp,fixed}_counter() and kvm_{gp,fixed}_pmc_mask()
to the patch where they are first used. (Yosry)
- Move pmc_exists64 union to the patch where they are first used.
- Retitle to reflect that this patch now converts PMC lookup helpers.
- Do not carry over Jim's Reviewed-by due to above changes.

v2:
- Rename kvm_{gp,fixed}_pmc_supported() to
kvm_is_{gp,fixed}_pmc_supported() and simplify them by removing the
temporary bitmap. (Sean)
- Split kvm_for_each_set_pmc_idx() to kvm_for_each_gp_counter() and
kvm_for_each_fixed_counter(). (Sean)
---
arch/x86/kvm/pmu.h | 30 ++++++++++++++++++++++++------
1 file changed, 24 insertions(+), 6 deletions(-)

diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h
index 090c9bbb74f4..fbab4f5c9181 100644
--- a/arch/x86/kvm/pmu.h
+++ b/arch/x86/kvm/pmu.h
@@ -88,6 +88,18 @@ static inline bool kvm_vcpu_has_mediated_pmu(struct kvm_vcpu *vcpu)
return enable_mediated_pmu && vcpu_to_pmu(vcpu)->version;
}

+static inline bool kvm_is_gp_pmc_supported(struct kvm_pmu *pmu, unsigned int idx)
+{
+ return idx < KVM_MAX_NR_GP_COUNTERS &&
+ test_bit(idx, pmu->pmc_exists);
+}
+
+static inline bool kvm_is_fixed_pmc_supported(struct kvm_pmu *pmu, unsigned int idx)
+{
+ return idx < KVM_MAX_NR_FIXED_COUNTERS &&
+ test_bit(KVM_FIXED_PMC_BASE_IDX + idx, pmu->pmc_exists);
+}
+
/*
* KVM tracks all counters in 64-bit bitmaps, with general purpose counters
* mapped to bits 31:0 and fixed counters mapped to 63:32, e.g. fixed counter 0
@@ -104,11 +116,11 @@ static inline bool kvm_vcpu_has_mediated_pmu(struct kvm_vcpu *vcpu)
*/
static inline struct kvm_pmc *kvm_pmc_idx_to_pmc(struct kvm_pmu *pmu, int idx)
{
- if (idx < pmu->nr_arch_gp_counters)
+ if (kvm_is_gp_pmc_supported(pmu, idx))
return &pmu->gp_counters[idx];

idx -= KVM_FIXED_PMC_BASE_IDX;
- if (idx >= 0 && idx < pmu->nr_arch_fixed_counters)
+ if (kvm_is_fixed_pmc_supported(pmu, idx))
return &pmu->fixed_counters[idx];

return NULL;
@@ -168,9 +180,12 @@ static inline bool kvm_valid_perf_global_ctrl(struct kvm_pmu *pmu,
static inline struct kvm_pmc *get_gp_pmc(struct kvm_pmu *pmu, u32 msr,
u32 base)
{
- if (msr >= base && msr < base + pmu->nr_arch_gp_counters) {
+ if (msr >= base && msr < base + KVM_MAX_NR_GP_COUNTERS) {
u32 index = array_index_nospec(msr - base,
- pmu->nr_arch_gp_counters);
+ KVM_MAX_NR_GP_COUNTERS);
+
+ if (!kvm_is_gp_pmc_supported(pmu, index))
+ return NULL;

return &pmu->gp_counters[index];
}
@@ -183,9 +198,12 @@ static inline struct kvm_pmc *get_fixed_pmc(struct kvm_pmu *pmu, u32 msr)
{
int base = MSR_CORE_PERF_FIXED_CTR0;

- if (msr >= base && msr < base + pmu->nr_arch_fixed_counters) {
+ if (msr >= base && msr < base + KVM_MAX_NR_FIXED_COUNTERS) {
u32 index = array_index_nospec(msr - base,
- pmu->nr_arch_fixed_counters);
+ KVM_MAX_NR_FIXED_COUNTERS);
+
+ if (!kvm_is_fixed_pmc_supported(pmu, index))
+ return NULL;

return &pmu->fixed_counters[index];
}
--
2.56.1