Re: [PATCH v9 08/16] KVM: arm64: selftests: Cover PMU state in MDCR_EL2

Fuad Tabba <[email protected]>
Newsgroups dev.linux.lists.kvmarm,org.infradead.lists.linux-arm-kernel,org.kernel.vger.kvm,org.kernel.vger.linux-doc,org.kernel.vger.linux-hardening,org.kernel.vger.linux-kernel,org.kernel.vger.linux-kselftest
Message-ID <CA+EHjTyEnNGrZHbHKK9cW0-kOynrDqZVwRb0MeLAM=wGUYFbRw@mail.gmail.com>
On Mon, 20 Jul 2026 at 06:44, Akihiko Odaki
<[email protected]> wrote:
>
> Add MDCR_EL2 coverage to vpmu_counter_access when EL2 is available.
>
> For each configured PMCR_EL0.N value, verify that an arbitrary HPMN
> value, including one above the configured counter count, round-trips
> through KVM_SET_ONE_REG and survives SET_NR_COUNTERS. Also verify that
> HPME can be toggled without disturbing HPMN and that KVM_ARM_VCPU_INIT
> resets HPMN from the configured count.
>
> Assisted-by: Codex:gpt-5.5
> Signed-off-by: Akihiko Odaki <[email protected]>

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

Cheers,
/fuad

> ---
>  .../selftests/kvm/arm64/vpmu_counter_access.c      | 90 ++++++++++++++++++++--
>  1 file changed, 85 insertions(+), 5 deletions(-)
>
> diff --git a/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c b/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c
> index 3b5bb421f401..73f04e4c6ca3 100644
> --- a/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c
> +++ b/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c
> @@ -25,6 +25,14 @@
>  /* The cycle counter bit position that's common among the PMU registers */
>  #define ARMV8_PMU_CYCLE_IDX            31
>
> +#ifndef MDCR_EL2_HPMN
> +#define MDCR_EL2_HPMN                  GENMASK_ULL(4, 0)
> +#endif
> +
> +#ifndef MDCR_EL2_HPME
> +#define MDCR_EL2_HPME                  BIT_ULL(7)
> +#endif
> +
>  struct vpmu_vm {
>         struct kvm_vm *vm;
>         struct kvm_vcpu *vcpu;
> @@ -466,15 +474,12 @@ static void guest_code_done(void)
>         GUEST_DONE();
>  }
>
> -static void test_create_vpmu_vm_with_nr_counters(unsigned int nr_counters, bool expect_fail)
> +static void set_nr_counters(struct kvm_vcpu *vcpu,
> +                           unsigned int nr_counters, bool expect_fail)
>  {
> -       struct kvm_vcpu *vcpu;
>         unsigned int prev;
>         int ret;
>
> -       create_vpmu_vm(guest_code);
> -       vcpu = vpmu_vm.vcpu;
> -
>         prev = get_pmcr_n(vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_PMCR_EL0)));
>
>         ret = __vcpu_device_attr_set(vcpu, KVM_ARM_VCPU_PMU_V3_CTRL,
> @@ -486,6 +491,17 @@ static void test_create_vpmu_vm_with_nr_counters(unsigned int nr_counters, bool
>                             nr_counters, prev);
>         else
>                 TEST_ASSERT(!ret, KVM_IOCTL_ERROR(KVM_SET_DEVICE_ATTR, ret));
> +}
> +
> +static void test_create_vpmu_vm_with_nr_counters(unsigned int nr_counters,
> +                                                bool expect_fail)
> +{
> +       struct kvm_vcpu *vcpu;
> +
> +       create_vpmu_vm(guest_code);
> +       vcpu = vpmu_vm.vcpu;
> +
> +       set_nr_counters(vcpu, nr_counters, expect_fail);
>
>         vcpu_device_attr_set(vcpu, KVM_ARM_VCPU_PMU_V3_CTRL, KVM_ARM_VCPU_PMU_V3_INIT, NULL);
>  }
> @@ -588,6 +604,69 @@ static void run_pmregs_validity_test(u64 pmcr_n)
>         destroy_vpmu_vm();
>  }
>
> +static void run_mdcr_el2_validity_test(u64 pmcr_n)
> +{
> +       struct kvm_vcpu_init init;
> +       struct kvm_vcpu *vcpu;
> +       u64 expected_mdcr, mdcr;
> +
> +       pr_debug("MDCR_EL2 test with pmcr_n %lu\n", pmcr_n);
> +
> +       create_vpmu_vm(guest_code);
> +       if (!vm_supports_el2(vpmu_vm.vm)) {
> +               destroy_vpmu_vm();
> +               return;
> +       }
> +
> +       vcpu = vpmu_vm.vcpu;
> +
> +       mdcr = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_MDCR_EL2));
> +       expected_mdcr = u64_replace_bits(mdcr, FIELD_MAX(MDCR_EL2_HPMN),
> +                                        MDCR_EL2_HPMN);
> +       vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_MDCR_EL2),
> +                    expected_mdcr);
> +
> +       mdcr = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_MDCR_EL2));
> +       TEST_ASSERT(mdcr == expected_mdcr,
> +                   "MDCR_EL2 was not properly updated after HPMN write (expected 0x%lx, got 0x%lx)",
> +                   expected_mdcr, mdcr);
> +
> +       set_nr_counters(vcpu, pmcr_n, false);
> +
> +       mdcr = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_MDCR_EL2));
> +       TEST_ASSERT(mdcr == expected_mdcr,
> +                   "MDCR_EL2 changed after PMU_V3_SET_NR_COUNTERS (expected 0x%lx, got 0x%lx)",
> +                   expected_mdcr, mdcr);
> +
> +       vcpu_device_attr_set(vcpu, KVM_ARM_VCPU_PMU_V3_CTRL,
> +                            KVM_ARM_VCPU_PMU_V3_INIT, NULL);
> +
> +       mdcr = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_MDCR_EL2));
> +       TEST_ASSERT(mdcr == expected_mdcr,
> +                   "MDCR_EL2 changed after PMU_V3_INIT (expected 0x%lx, got 0x%lx)",
> +                   expected_mdcr, mdcr);
> +
> +       expected_mdcr = mdcr ^ MDCR_EL2_HPME;
> +       vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_MDCR_EL2),
> +                    expected_mdcr);
> +
> +       mdcr = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_MDCR_EL2));
> +       TEST_ASSERT(mdcr == expected_mdcr,
> +                   "MDCR_EL2 was not properly updated after HPME write (expected 0x%lx, got 0x%lx)",
> +                   expected_mdcr, mdcr);
> +
> +       kvm_get_default_vcpu_target(vpmu_vm.vm, &init);
> +       init.features[0] |= (1 << KVM_ARM_VCPU_PMU_V3);
> +       aarch64_vcpu_setup(vcpu, &init);
> +
> +       mdcr = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_MDCR_EL2));
> +       TEST_ASSERT(FIELD_GET(MDCR_EL2_HPMN, mdcr) == pmcr_n,
> +                   "MDCR_EL2.HPMN is not reset after INIT (expected %lu, got %lu)",
> +                   pmcr_n, FIELD_GET(MDCR_EL2_HPMN, mdcr));
> +
> +       destroy_vpmu_vm();
> +}
> +
>  /*
>   * Create a guest with one vCPU, and attempt to set the PMCR_EL0.N for
>   * the vCPU to @pmcr_n, which is larger than the host value.
> @@ -672,6 +751,7 @@ int main(void)
>         for (i = 0; i <= pmcr_n; i++) {
>                 run_access_test(i);
>                 run_pmregs_validity_test(i);
> +               run_mdcr_el2_validity_test(i);
>         }
>
>         for (i = pmcr_n + 1; i < ARMV8_PMU_MAX_COUNTERS; i++)
>
> --
> 2.55.0
>
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.