From: Raghavendra Rao Ananta <rananta@google.com>
To: Oliver Upton <oliver.upton@linux.dev>, Marc Zyngier <maz@kernel.org>
Cc: Alexandru Elisei <alexandru.elisei@arm.com>,
James Morse <james.morse@arm.com>,
Suzuki K Poulose <suzuki.poulose@arm.com>,
Paolo Bonzini <pbonzini@redhat.com>,
Zenghui Yu <yuzenghui@huawei.com>,
Shaoqin Huang <shahuang@redhat.com>,
Jing Zhang <jingzhangos@google.com>,
Reiji Watanabe <reijiw@google.com>,
Colton Lewis <coltonlewis@google.com>,
Raghavendra Rao Anata <rananta@google.com>,
linux-arm-kernel@lists.infradead.org, kvmarm@lists.linux.dev,
linux-kernel@vger.kernel.org, kvm@vger.kernel.org
Subject: [PATCH v5 10/12] KVM: selftests: aarch64: Introduce vpmu_counter_access test
Date: Thu, 17 Aug 2023 00:30:27 +0000 [thread overview]
Message-ID: <20230817003029.3073210-11-rananta@google.com> (raw)
In-Reply-To: <20230817003029.3073210-1-rananta@google.com>
From: Reiji Watanabe <reijiw@google.com>
Introduce vpmu_counter_access test for arm64 platforms.
The test configures PMUv3 for a vCPU, sets PMCR_EL0.N for the vCPU,
and check if the guest can consistently see the same number of the
PMU event counters (PMCR_EL0.N) that userspace sets.
This test case is done with each of the PMCR_EL0.N values from
0 to 31 (With the PMCR_EL0.N values greater than the host value,
the test expects KVM_SET_ONE_REG for the PMCR_EL0 to fail).
Signed-off-by: Reiji Watanabe <reijiw@google.com>
Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
---
tools/testing/selftests/kvm/Makefile | 1 +
.../kvm/aarch64/vpmu_counter_access.c | 235 ++++++++++++++++++
2 files changed, 236 insertions(+)
create mode 100644 tools/testing/selftests/kvm/aarch64/vpmu_counter_access.c
diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile
index c692cc86e7da8..a1599e2b82e38 100644
--- a/tools/testing/selftests/kvm/Makefile
+++ b/tools/testing/selftests/kvm/Makefile
@@ -148,6 +148,7 @@ TEST_GEN_PROGS_aarch64 += aarch64/smccc_filter
TEST_GEN_PROGS_aarch64 += aarch64/vcpu_width_config
TEST_GEN_PROGS_aarch64 += aarch64/vgic_init
TEST_GEN_PROGS_aarch64 += aarch64/vgic_irq
+TEST_GEN_PROGS_aarch64 += aarch64/vpmu_counter_access
TEST_GEN_PROGS_aarch64 += access_tracking_perf_test
TEST_GEN_PROGS_aarch64 += demand_paging_test
TEST_GEN_PROGS_aarch64 += dirty_log_test
diff --git a/tools/testing/selftests/kvm/aarch64/vpmu_counter_access.c b/tools/testing/selftests/kvm/aarch64/vpmu_counter_access.c
new file mode 100644
index 0000000000000..d0afec07948ef
--- /dev/null
+++ b/tools/testing/selftests/kvm/aarch64/vpmu_counter_access.c
@@ -0,0 +1,235 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * vpmu_counter_access - Test vPMU event counter access
+ *
+ * Copyright (c) 2022 Google LLC.
+ *
+ * This test checks if the guest can see the same number of the PMU event
+ * counters (PMCR_EL0.N) that userspace sets.
+ * This test runs only when KVM_CAP_ARM_PMU_V3 is supported on the host.
+ */
+#include <kvm_util.h>
+#include <processor.h>
+#include <test_util.h>
+#include <vgic.h>
+#include <perf/arm_pmuv3.h>
+#include <linux/bitfield.h>
+
+/* The max number of the PMU event counters (excluding the cycle counter) */
+#define ARMV8_PMU_MAX_GENERAL_COUNTERS (ARMV8_PMU_MAX_COUNTERS - 1)
+
+struct vpmu_vm {
+ struct kvm_vm *vm;
+ struct kvm_vcpu *vcpu;
+ int gic_fd;
+};
+
+static void guest_sync_handler(struct ex_regs *regs)
+{
+ uint64_t esr, ec;
+
+ esr = read_sysreg(esr_el1);
+ ec = (esr >> ESR_EC_SHIFT) & ESR_EC_MASK;
+ GUEST_ASSERT_3(0, regs->pc, esr, ec);
+}
+
+/*
+ * The guest is configured with PMUv3 with @expected_pmcr_n number of
+ * event counters.
+ * Check if @expected_pmcr_n is consistent with PMCR_EL0.N.
+ */
+static void guest_code(uint64_t expected_pmcr_n)
+{
+ uint64_t pmcr, pmcr_n;
+
+ GUEST_ASSERT(expected_pmcr_n <= ARMV8_PMU_MAX_GENERAL_COUNTERS);
+
+ pmcr = read_sysreg(pmcr_el0);
+ pmcr_n = FIELD_GET(ARMV8_PMU_PMCR_N, pmcr);
+
+ /* Make sure that PMCR_EL0.N indicates the value userspace set */
+ GUEST_ASSERT_2(pmcr_n == expected_pmcr_n, pmcr_n, expected_pmcr_n);
+
+ GUEST_DONE();
+}
+
+#define GICD_BASE_GPA 0x8000000ULL
+#define GICR_BASE_GPA 0x80A0000ULL
+
+/* Create a VM that has one vCPU with PMUv3 configured. */
+static struct vpmu_vm *create_vpmu_vm(void *guest_code)
+{
+ struct kvm_vcpu_init init;
+ uint8_t pmuver, ec;
+ uint64_t dfr0, irq = 23;
+ struct vpmu_vm *vpmu_vm;
+ struct kvm_device_attr irq_attr = {
+ .group = KVM_ARM_VCPU_PMU_V3_CTRL,
+ .attr = KVM_ARM_VCPU_PMU_V3_IRQ,
+ .addr = (uint64_t)&irq,
+ };
+ struct kvm_device_attr init_attr = {
+ .group = KVM_ARM_VCPU_PMU_V3_CTRL,
+ .attr = KVM_ARM_VCPU_PMU_V3_INIT,
+ };
+
+ vpmu_vm = calloc(1, sizeof(*vpmu_vm));
+ TEST_ASSERT(vpmu_vm, "Failed to allocate vpmu_vm");
+
+ vpmu_vm->vm = vm_create(1);
+ vm_init_descriptor_tables(vpmu_vm->vm);
+ for (ec = 0; ec < ESR_EC_NUM; ec++) {
+ vm_install_sync_handler(vpmu_vm->vm, VECTOR_SYNC_CURRENT, ec,
+ guest_sync_handler);
+ }
+
+ /* Create vCPU with PMUv3 */
+ vm_ioctl(vpmu_vm->vm, KVM_ARM_PREFERRED_TARGET, &init);
+ init.features[0] |= (1 << KVM_ARM_VCPU_PMU_V3);
+ vpmu_vm->vcpu = aarch64_vcpu_add(vpmu_vm->vm, 0, &init, guest_code);
+ vcpu_init_descriptor_tables(vpmu_vm->vcpu);
+ vpmu_vm->gic_fd = vgic_v3_setup(vpmu_vm->vm, 1, 64,
+ GICD_BASE_GPA, GICR_BASE_GPA);
+
+ /* Make sure that PMUv3 support is indicated in the ID register */
+ vcpu_get_reg(vpmu_vm->vcpu,
+ KVM_ARM64_SYS_REG(SYS_ID_AA64DFR0_EL1), &dfr0);
+ pmuver = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64DFR0_PMUVER), dfr0);
+ TEST_ASSERT(pmuver != ID_AA64DFR0_PMUVER_IMP_DEF &&
+ pmuver >= ID_AA64DFR0_PMUVER_8_0,
+ "Unexpected PMUVER (0x%x) on the vCPU with PMUv3", pmuver);
+
+ /* Initialize vPMU */
+ vcpu_ioctl(vpmu_vm->vcpu, KVM_SET_DEVICE_ATTR, &irq_attr);
+ vcpu_ioctl(vpmu_vm->vcpu, KVM_SET_DEVICE_ATTR, &init_attr);
+
+ return vpmu_vm;
+}
+
+static void destroy_vpmu_vm(struct vpmu_vm *vpmu_vm)
+{
+ close(vpmu_vm->gic_fd);
+ kvm_vm_free(vpmu_vm->vm);
+ free(vpmu_vm);
+}
+
+static void run_vcpu(struct kvm_vcpu *vcpu, uint64_t pmcr_n)
+{
+ struct ucall uc;
+
+ vcpu_args_set(vcpu, 1, pmcr_n);
+ vcpu_run(vcpu);
+ switch (get_ucall(vcpu, &uc)) {
+ case UCALL_ABORT:
+ REPORT_GUEST_ASSERT_2(uc, "values:%#lx %#lx");
+ break;
+ case UCALL_DONE:
+ break;
+ default:
+ TEST_FAIL("Unknown ucall %lu", uc.cmd);
+ break;
+ }
+}
+
+/*
+ * Create a guest with one vCPU, set the PMCR_EL0.N for the vCPU to @pmcr_n,
+ * and run the test.
+ */
+static void run_test(uint64_t pmcr_n)
+{
+ struct vpmu_vm *vpmu_vm;
+ struct kvm_vcpu *vcpu;
+ uint64_t sp, pmcr, pmcr_orig;
+ struct kvm_vcpu_init init;
+
+ pr_debug("Test with pmcr_n %lu\n", pmcr_n);
+ vpmu_vm = create_vpmu_vm(guest_code);
+
+ vcpu = vpmu_vm->vcpu;
+
+ /* Save the initial sp to restore them later to run the guest again */
+ vcpu_get_reg(vcpu, ARM64_CORE_REG(sp_el1), &sp);
+
+ /* Update the PMCR_EL0.N with @pmcr_n */
+ vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_PMCR_EL0), &pmcr_orig);
+ pmcr = pmcr_orig & ~ARMV8_PMU_PMCR_N;
+ pmcr |= (pmcr_n << ARMV8_PMU_PMCR_N_SHIFT);
+ vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_PMCR_EL0), pmcr);
+
+ run_vcpu(vcpu, pmcr_n);
+
+ /*
+ * Reset and re-initialize the vCPU, and run the guest code again to
+ * check if PMCR_EL0.N is preserved.
+ */
+ vm_ioctl(vpmu_vm->vm, KVM_ARM_PREFERRED_TARGET, &init);
+ init.features[0] |= (1 << KVM_ARM_VCPU_PMU_V3);
+ aarch64_vcpu_setup(vcpu, &init);
+ vcpu_init_descriptor_tables(vcpu);
+ vcpu_set_reg(vcpu, ARM64_CORE_REG(sp_el1), sp);
+ vcpu_set_reg(vcpu, ARM64_CORE_REG(regs.pc), (uint64_t)guest_code);
+
+ run_vcpu(vcpu, pmcr_n);
+
+ destroy_vpmu_vm(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.
+ * The attempt should fail as @pmcr_n is too big to set for the vCPU.
+ */
+static void run_error_test(uint64_t pmcr_n)
+{
+ struct vpmu_vm *vpmu_vm;
+ struct kvm_vcpu *vcpu;
+ int ret;
+ uint64_t pmcr, pmcr_orig;
+
+ pr_debug("Error test with pmcr_n %lu (larger than the host)\n", pmcr_n);
+ vpmu_vm = create_vpmu_vm(guest_code);
+ vcpu = vpmu_vm->vcpu;
+
+ /* Update the PMCR_EL0.N with @pmcr_n */
+ vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_PMCR_EL0), &pmcr_orig);
+ pmcr = pmcr_orig & ~ARMV8_PMU_PMCR_N;
+ pmcr |= (pmcr_n << ARMV8_PMU_PMCR_N_SHIFT);
+
+ /* This should fail as @pmcr_n is too big to set for the vCPU */
+ ret = __vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_PMCR_EL0), pmcr);
+ TEST_ASSERT(ret, "Setting PMCR to 0x%lx (orig PMCR 0x%lx) didn't fail",
+ pmcr, pmcr_orig);
+
+ destroy_vpmu_vm(vpmu_vm);
+}
+
+/*
+ * Return the default number of implemented PMU event counters excluding
+ * the cycle counter (i.e. PMCR_EL0.N value) for the guest.
+ */
+static uint64_t get_pmcr_n_limit(void)
+{
+ struct vpmu_vm *vpmu_vm;
+ uint64_t pmcr;
+
+ vpmu_vm = create_vpmu_vm(guest_code);
+ vcpu_get_reg(vpmu_vm->vcpu, KVM_ARM64_SYS_REG(SYS_PMCR_EL0), &pmcr);
+ destroy_vpmu_vm(vpmu_vm);
+ return FIELD_GET(ARMV8_PMU_PMCR_N, pmcr);
+}
+
+int main(void)
+{
+ uint64_t i, pmcr_n;
+
+ TEST_REQUIRE(kvm_has_cap(KVM_CAP_ARM_PMU_V3));
+
+ pmcr_n = get_pmcr_n_limit();
+ for (i = 0; i <= pmcr_n; i++)
+ run_test(i);
+
+ for (i = pmcr_n + 1; i < ARMV8_PMU_MAX_COUNTERS; i++)
+ run_error_test(i);
+
+ return 0;
+}
--
2.41.0.694.ge786442a9b-goog
next prev parent reply other threads:[~2023-08-17 0:31 UTC|newest]
Thread overview: 41+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-08-17 0:30 [PATCH v5 00/12] KVM: arm64: PMU: Allow userspace to limit the number of PMCs on vCPU Raghavendra Rao Ananta
2023-08-17 0:30 ` [PATCH v5 01/12] KVM: arm64: PMU: Introduce a helper to set the guest's PMU Raghavendra Rao Ananta
2023-09-15 19:22 ` Oliver Upton
2023-09-18 17:24 ` Raghavendra Rao Ananta
2023-08-17 0:30 ` [PATCH v5 02/12] KVM: arm64: PMU: Set the default PMU for the guest on vCPU reset Raghavendra Rao Ananta
2023-08-17 5:03 ` kernel test robot
2023-08-17 7:54 ` kernel test robot
2023-09-15 19:33 ` Oliver Upton
2023-09-18 16:41 ` Raghavendra Rao Ananta
2023-09-18 16:47 ` Oliver Upton
2023-09-18 16:58 ` Raghavendra Rao Ananta
2023-08-17 0:30 ` [PATCH v5 03/12] KVM: arm64: PMU: Clear PM{C,I}NTEN{SET,CLR} and PMOVS{SET,CLR} " Raghavendra Rao Ananta
2023-08-17 0:30 ` [PATCH v5 04/12] KVM: arm64: PMU: Don't define the sysreg reset() for PM{USERENR,CCFILTR}_EL0 Raghavendra Rao Ananta
2023-08-17 0:30 ` [PATCH v5 05/12] KVM: arm64: PMU: Simplify extracting PMCR_EL0.N Raghavendra Rao Ananta
2023-08-17 6:38 ` kernel test robot
2023-09-15 19:56 ` Oliver Upton
2023-09-18 16:53 ` Raghavendra Rao Ananta
2023-08-17 0:30 ` [PATCH v5 06/12] KVM: arm64: PMU: Add a helper to read a vCPU's PMCR_EL0 Raghavendra Rao Ananta
2023-08-17 0:30 ` [PATCH v5 07/12] KVM: arm64: PMU: Set PMCR_EL0.N for vCPU based on the associated PMU Raghavendra Rao Ananta
2023-08-17 0:30 ` [PATCH v5 08/12] KVM: arm64: PMU: Allow userspace to limit PMCR_EL0.N for the guest Raghavendra Rao Ananta
2023-08-21 12:12 ` Shaoqin Huang
2023-08-21 23:28 ` Raghavendra Rao Ananta
2023-08-22 3:26 ` Shaoqin Huang
2023-09-15 20:36 ` Oliver Upton
2023-09-18 17:02 ` Raghavendra Rao Ananta
2023-08-22 10:05 ` Shaoqin Huang
2023-08-23 16:06 ` Raghavendra Rao Ananta
2023-08-24 8:50 ` Shaoqin Huang
2023-08-25 22:34 ` Raghavendra Rao Ananta
2023-08-26 2:40 ` Shaoqin Huang
2023-09-15 20:53 ` Oliver Upton
2023-09-15 21:54 ` Oliver Upton
2023-09-18 17:11 ` Raghavendra Rao Ananta
2023-09-18 17:22 ` Raghavendra Rao Ananta
2023-09-18 17:07 ` Raghavendra Rao Ananta
2023-08-17 0:30 ` [PATCH v5 09/12] tools: Import arm_pmuv3.h Raghavendra Rao Ananta
2023-08-17 0:30 ` Raghavendra Rao Ananta [this message]
2023-09-15 21:00 ` [PATCH v5 10/12] KVM: selftests: aarch64: Introduce vpmu_counter_access test Oliver Upton
2023-09-18 17:20 ` Raghavendra Rao Ananta
2023-08-17 0:30 ` [PATCH v5 11/12] KVM: selftests: aarch64: vPMU register test for implemented counters Raghavendra Rao Ananta
2023-08-17 0:30 ` [PATCH v5 12/12] KVM: selftests: aarch64: vPMU register test for unimplemented counters Raghavendra Rao Ananta
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20230817003029.3073210-11-rananta@google.com \
--to=rananta@google.com \
--cc=alexandru.elisei@arm.com \
--cc=coltonlewis@google.com \
--cc=james.morse@arm.com \
--cc=jingzhangos@google.com \
--cc=kvm@vger.kernel.org \
--cc=kvmarm@lists.linux.dev \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=maz@kernel.org \
--cc=oliver.upton@linux.dev \
--cc=pbonzini@redhat.com \
--cc=reijiw@google.com \
--cc=shahuang@redhat.com \
--cc=suzuki.poulose@arm.com \
--cc=yuzenghui@huawei.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox