Re: [PATCH v9 02/16] KVM: arm64: PMU: Stop updating MDCR_EL2.HPMN
From: Fuad Tabba
Date: Wed Jul 29 2026 - 11:25:44 EST
On Mon, 20 Jul 2026 at 06:39, Akihiko Odaki
<odaki@xxxxxxxxxxxxxxxxxxxxxx> wrote:
>
> 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 <odaki@xxxxxxxxxxxxxxxxxxxxxx>
Reviewed-by: Fuad Tabba <fuad.tabba@xxxxxxxxx>
Cheers,
/fuad
> ---
> 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
>
>