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 --- 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