On Mon, 20 Jul 2026 at 06:39, Akihiko Odaki
<[email protected]> 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 <[email protected]>

Reviewed-by: Fuad Tabba <[email protected]>

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

Reply via email to