KVM allows userspace to write any value to MDCR_EL2.HPMN. However,
kvm_arm_set_nr_counters() rewrites HPMN for every vCPU whenever
userspace changes the PMU or its counter count. This can discard a
value previously restored with KVM_SET_ONE_REG.

The architecture only defines HPMN's value on warm reset. Stop
rewriting it after vCPU initialization and update nr_pmu_counters
directly instead. reset_mdcr() continues to initialize HPMN from the
counter count current at KVM_ARM_VCPU_INIT.

Fixes: c8823e51b534 ("KVM: arm64: Fix MDCR_EL2.HPMN reset value")
Closes: 
https://sashiko.dev/#/patchset/20260706-hybrid-v8-0-de459617b59d%40rsg.ci.i.u-tokyo.ac.jp?part=6
Assisted-by: Codex:gpt-5.5
Signed-off-by: Akihiko Odaki <[email protected]>
---
 arch/arm64/kvm/pmu-emul.c | 22 ++--------------------
 1 file changed, 2 insertions(+), 20 deletions(-)

diff --git a/arch/arm64/kvm/pmu-emul.c b/arch/arm64/kvm/pmu-emul.c
index 98305bbfc095..b5df6843dbcd 100644
--- a/arch/arm64/kvm/pmu-emul.c
+++ b/arch/arm64/kvm/pmu-emul.c
@@ -1022,30 +1022,12 @@ u8 kvm_arm_pmu_get_max_counters(struct kvm *kvm)
        return bitmap_weight(arm_pmu->cntr_mask, 
ARMV8_PMU_MAX_GENERAL_COUNTERS);
 }
 
-static void kvm_arm_set_nr_counters(struct kvm *kvm, unsigned int nr)
-{
-       kvm->arch.nr_pmu_counters = nr;
-
-       /* Reset MDCR_EL2.HPMN behind the vcpus' back... */
-       if (test_bit(KVM_ARM_VCPU_HAS_EL2, kvm->arch.vcpu_features)) {
-               struct kvm_vcpu *vcpu;
-               unsigned long i;
-
-               kvm_for_each_vcpu(i, vcpu, kvm) {
-                       u64 val = __vcpu_sys_reg(vcpu, MDCR_EL2);
-                       val &= ~MDCR_EL2_HPMN;
-                       val |= FIELD_PREP(MDCR_EL2_HPMN, 
kvm->arch.nr_pmu_counters);
-                       __vcpu_assign_sys_reg(vcpu, MDCR_EL2, val);
-               }
-       }
-}
-
 static void kvm_arm_set_pmu(struct kvm *kvm, struct arm_pmu *arm_pmu)
 {
        lockdep_assert_held(&kvm->arch.config_lock);
 
        kvm->arch.arm_pmu = arm_pmu;
-       kvm_arm_set_nr_counters(kvm, kvm_arm_pmu_get_max_counters(kvm));
+       kvm->arch.nr_pmu_counters = kvm_arm_pmu_get_max_counters(kvm);
 }
 
 /**
@@ -1111,7 +1093,7 @@ static int kvm_arm_pmu_v3_set_nr_counters(struct kvm_vcpu 
*vcpu, unsigned int n)
        if (n > kvm_arm_pmu_get_max_counters(kvm))
                return -EINVAL;
 
-       kvm_arm_set_nr_counters(kvm, n);
+       kvm->arch.nr_pmu_counters = n;
        return 0;
 }
 

-- 
2.55.0


Reply via email to