Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

KVM: arm64: selftests: Use the vCPU attr for setting nr of PMU counters

Configuring the number of implemented counters via PMCR_EL0.N was a bad
idea in retrospect as it interacts poorly with nested. Migrate the
selftest to use the vCPU attribute instead of the KVM_SET_ONE_REG
mechanism.

Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
Signed-off-by: Marc Zyngier <maz@kernel.org>

authored by

Oliver Upton and committed by
Marc Zyngier
7ae44d1c 0910778e

+28 -31
+28 -31
tools/testing/selftests/kvm/arm64/vpmu_counter_access.c
··· 44 44 return FIELD_GET(ARMV8_PMU_PMCR_N, pmcr); 45 45 } 46 46 47 - static void set_pmcr_n(uint64_t *pmcr, uint64_t pmcr_n) 48 - { 49 - u64p_replace_bits((__u64 *) pmcr, pmcr_n, ARMV8_PMU_PMCR_N); 50 - } 51 - 52 47 static uint64_t get_counters_mask(uint64_t n) 53 48 { 54 49 uint64_t mask = BIT(ARMV8_PMU_CYCLE_IDX); ··· 409 414 .attr = KVM_ARM_VCPU_PMU_V3_IRQ, 410 415 .addr = (uint64_t)&irq, 411 416 }; 412 - struct kvm_device_attr init_attr = { 413 - .group = KVM_ARM_VCPU_PMU_V3_CTRL, 414 - .attr = KVM_ARM_VCPU_PMU_V3_INIT, 415 - }; 416 417 417 418 /* The test creates the vpmu_vm multiple times. Ensure a clean state */ 418 419 memset(&vpmu_vm, 0, sizeof(vpmu_vm)); ··· 435 444 pmuver >= ID_AA64DFR0_EL1_PMUVer_IMP, 436 445 "Unexpected PMUVER (0x%x) on the vCPU with PMUv3", pmuver); 437 446 438 - /* Initialize vPMU */ 439 447 vcpu_ioctl(vpmu_vm.vcpu, KVM_SET_DEVICE_ATTR, &irq_attr); 440 - vcpu_ioctl(vpmu_vm.vcpu, KVM_SET_DEVICE_ATTR, &init_attr); 441 448 } 442 449 443 450 static void destroy_vpmu_vm(void) ··· 461 472 } 462 473 } 463 474 464 - static void test_create_vpmu_vm_with_pmcr_n(uint64_t pmcr_n, bool expect_fail) 475 + static void test_create_vpmu_vm_with_nr_counters(unsigned int nr_counters, bool expect_fail) 465 476 { 466 477 struct kvm_vcpu *vcpu; 467 - uint64_t pmcr, pmcr_orig; 478 + unsigned int prev; 479 + int ret; 468 480 469 481 create_vpmu_vm(guest_code); 470 482 vcpu = vpmu_vm.vcpu; 471 483 472 - pmcr_orig = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_PMCR_EL0)); 473 - pmcr = pmcr_orig; 484 + prev = get_pmcr_n(vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_PMCR_EL0))); 474 485 475 - /* 476 - * Setting a larger value of PMCR.N should not modify the field, and 477 - * return a success. 478 - */ 479 - set_pmcr_n(&pmcr, pmcr_n); 480 - vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_PMCR_EL0), pmcr); 481 - pmcr = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_PMCR_EL0)); 486 + ret = __vcpu_device_attr_set(vcpu, KVM_ARM_VCPU_PMU_V3_CTRL, 487 + KVM_ARM_VCPU_PMU_V3_SET_NR_COUNTERS, &nr_counters); 482 488 483 489 if (expect_fail) 484 - TEST_ASSERT(pmcr_orig == pmcr, 485 - "PMCR.N modified by KVM to a larger value (PMCR: 0x%lx) for pmcr_n: 0x%lx", 486 - pmcr, pmcr_n); 490 + TEST_ASSERT(ret && errno == EINVAL, 491 + "Setting more PMU counters (%u) than available (%u) unexpectedly succeeded", 492 + nr_counters, prev); 487 493 else 488 - TEST_ASSERT(pmcr_n == get_pmcr_n(pmcr), 489 - "Failed to update PMCR.N to %lu (received: %lu)", 490 - pmcr_n, get_pmcr_n(pmcr)); 494 + TEST_ASSERT(!ret, KVM_IOCTL_ERROR(KVM_SET_DEVICE_ATTR, ret)); 495 + 496 + vcpu_device_attr_set(vcpu, KVM_ARM_VCPU_PMU_V3_CTRL, KVM_ARM_VCPU_PMU_V3_INIT, NULL); 491 497 } 492 498 493 499 /* ··· 497 513 498 514 pr_debug("Test with pmcr_n %lu\n", pmcr_n); 499 515 500 - test_create_vpmu_vm_with_pmcr_n(pmcr_n, false); 516 + test_create_vpmu_vm_with_nr_counters(pmcr_n, false); 501 517 vcpu = vpmu_vm.vcpu; 502 518 503 519 /* Save the initial sp to restore them later to run the guest again */ ··· 538 554 uint64_t set_reg_id, clr_reg_id, reg_val; 539 555 uint64_t valid_counters_mask, max_counters_mask; 540 556 541 - test_create_vpmu_vm_with_pmcr_n(pmcr_n, false); 557 + test_create_vpmu_vm_with_nr_counters(pmcr_n, false); 542 558 vcpu = vpmu_vm.vcpu; 543 559 544 560 valid_counters_mask = get_counters_mask(pmcr_n); ··· 592 608 { 593 609 pr_debug("Error test with pmcr_n %lu (larger than the host)\n", pmcr_n); 594 610 595 - test_create_vpmu_vm_with_pmcr_n(pmcr_n, true); 611 + test_create_vpmu_vm_with_nr_counters(pmcr_n, true); 596 612 destroy_vpmu_vm(); 597 613 } 598 614 ··· 610 626 return get_pmcr_n(pmcr); 611 627 } 612 628 629 + static bool kvm_supports_nr_counters_attr(void) 630 + { 631 + bool supported; 632 + 633 + create_vpmu_vm(NULL); 634 + supported = !__vcpu_has_device_attr(vpmu_vm.vcpu, KVM_ARM_VCPU_PMU_V3_CTRL, 635 + KVM_ARM_VCPU_PMU_V3_SET_NR_COUNTERS); 636 + destroy_vpmu_vm(); 637 + 638 + return supported; 639 + } 640 + 613 641 int main(void) 614 642 { 615 643 uint64_t i, pmcr_n; 616 644 617 645 TEST_REQUIRE(kvm_has_cap(KVM_CAP_ARM_PMU_V3)); 618 646 TEST_REQUIRE(kvm_supports_vgic_v3()); 647 + TEST_REQUIRE(kvm_supports_nr_counters_attr()); 619 648 620 649 pmcr_n = get_pmcr_n_limit(); 621 650 for (i = 0; i <= pmcr_n; i++) {