Add a regression test that runs one vCPU and then tries to change the VM-scoped PMU counter count through an idle sibling. Verify that SET_NR_COUNTERS fails with EBUSY once any vCPU has run. Assisted-by: Codex:gpt-5.6-sol Signed-off-by: Akihiko Odaki --- .../selftests/kvm/arm64/vpmu_counter_access.c | 47 ++++++++++++++++++++-- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c b/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c index 22223395969e..05135bcdb462 100644 --- a/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c +++ b/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c @@ -443,11 +443,10 @@ static void destroy_vpmu_vm(void) kvm_vm_free(vpmu_vm.vm); } -static void run_vcpu(struct kvm_vcpu *vcpu, u64 pmcr_n) +static void run_vcpu(struct kvm_vcpu *vcpu) { struct ucall uc; - vcpu_args_set(vcpu, 1, pmcr_n); vcpu_run(vcpu); switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: @@ -461,6 +460,11 @@ static void run_vcpu(struct kvm_vcpu *vcpu, u64 pmcr_n) } } +static void guest_code_done(void) +{ + GUEST_DONE(); +} + static void test_create_vpmu_vm_with_nr_counters(unsigned int nr_counters, bool expect_fail) { struct kvm_vcpu *vcpu; @@ -503,7 +507,8 @@ static void run_access_test(u64 pmcr_n) /* Save the initial sp to restore them later to run the guest again */ sp = vcpu_get_reg(vcpu, ctxt_reg_alias(vcpu, SYS_SP_EL1)); - run_vcpu(vcpu, pmcr_n); + vcpu_args_set(vcpu, 1, pmcr_n); + run_vcpu(vcpu); /* * Reset and re-initialize the vCPU, and run the guest code again to @@ -516,7 +521,8 @@ static void run_access_test(u64 pmcr_n) vcpu_set_reg(vcpu, ctxt_reg_alias(vcpu, SYS_SP_EL1), sp); vcpu_set_reg(vcpu, ARM64_CORE_REG(regs.pc), (u64)guest_code); - run_vcpu(vcpu, pmcr_n); + vcpu_args_set(vcpu, 1, pmcr_n); + run_vcpu(vcpu); destroy_vpmu_vm(); } @@ -622,6 +628,37 @@ static bool kvm_supports_nr_counters_attr(void) return supported; } +static void test_set_nr_counters_after_vcpu_run(void) +{ + struct kvm_vcpu *running_vcpu, *stopped_vcpu; + unsigned int nr_counters = 0; + struct kvm_vcpu_init init; + struct kvm_vm *vm; + int ret; + u64 irq = 23; + + vm = vm_create(2); + vm_ioctl(vm, KVM_ARM_PREFERRED_TARGET, &init); + init.features[0] |= BIT(KVM_ARM_VCPU_PMU_V3); + running_vcpu = aarch64_vcpu_add(vm, 0, &init, guest_code_done); + stopped_vcpu = aarch64_vcpu_add(vm, 1, &init, guest_code_done); + kvm_arch_vm_finalize_vcpus(vm); + + vcpu_device_attr_set(running_vcpu, KVM_ARM_VCPU_PMU_V3_CTRL, + KVM_ARM_VCPU_PMU_V3_IRQ, &irq); + vcpu_device_attr_set(running_vcpu, KVM_ARM_VCPU_PMU_V3_CTRL, + KVM_ARM_VCPU_PMU_V3_INIT, NULL); + run_vcpu(running_vcpu); + + ret = __vcpu_device_attr_set(stopped_vcpu, KVM_ARM_VCPU_PMU_V3_CTRL, + KVM_ARM_VCPU_PMU_V3_SET_NR_COUNTERS, + &nr_counters); + TEST_ASSERT(ret == -1 && errno == EBUSY, + KVM_IOCTL_ERROR(KVM_SET_DEVICE_ATTR, ret)); + + kvm_vm_free(vm); +} + int main(void) { u64 i, pmcr_n; @@ -630,6 +667,8 @@ int main(void) TEST_REQUIRE(kvm_supports_vgic_v3()); TEST_REQUIRE(kvm_supports_nr_counters_attr()); + test_set_nr_counters_after_vcpu_run(); + pmcr_n = get_pmcr_n_limit(); for (i = 0; i <= pmcr_n; i++) { run_access_test(i); -- 2.55.0