From: Nicholas Piggin <npiggin@gmail.com>
To: kvm@vger.kernel.org
Cc: Laurent Vivier <lvivier@redhat.com>,
Thomas Huth <thuth@redhat.com>,
linuxppc-dev@lists.ozlabs.org,
Nicholas Piggin <npiggin@gmail.com>
Subject: [kvm-unit-tests v4 07/12] powerpc/spapr_vpa: Add basic VPA tests
Date: Thu, 8 Jun 2023 17:58:21 +1000 [thread overview]
Message-ID: <20230608075826.86217-8-npiggin@gmail.com> (raw)
In-Reply-To: <20230608075826.86217-1-npiggin@gmail.com>
The VPA is an optional memory structure shared between the hypervisor
and operating system, defined by PAPR. This test defines the structure
and adds registration, deregistration, and a few simple sanity tests.
[Thanks to Thomas Huth for suggesting many of the test cases.]
Reviewed-by: Thomas Huth <thuth@redhat.com>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
lib/powerpc/asm/hcall.h | 1 +
lib/ppc64/asm/vpa.h | 62 +++++++++++++++
powerpc/Makefile.ppc64 | 2 +-
powerpc/spapr_vpa.c | 172 ++++++++++++++++++++++++++++++++++++++++
powerpc/unittests.cfg | 3 +
5 files changed, 239 insertions(+), 1 deletion(-)
create mode 100644 lib/ppc64/asm/vpa.h
create mode 100644 powerpc/spapr_vpa.c
diff --git a/lib/powerpc/asm/hcall.h b/lib/powerpc/asm/hcall.h
index 1173feaa..e0f5009e 100644
--- a/lib/powerpc/asm/hcall.h
+++ b/lib/powerpc/asm/hcall.h
@@ -18,6 +18,7 @@
#define H_SET_SPRG0 0x24
#define H_SET_DABR 0x28
#define H_PAGE_INIT 0x2c
+#define H_REGISTER_VPA 0xDC
#define H_CEDE 0xE0
#define H_GET_TERM_CHAR 0x54
#define H_PUT_TERM_CHAR 0x58
diff --git a/lib/ppc64/asm/vpa.h b/lib/ppc64/asm/vpa.h
new file mode 100644
index 00000000..11dde018
--- /dev/null
+++ b/lib/ppc64/asm/vpa.h
@@ -0,0 +1,62 @@
+#ifndef _ASMPOWERPC_VPA_H_
+#define _ASMPOWERPC_VPA_H_
+/*
+ * This work is licensed under the terms of the GNU LGPL, version 2.
+ */
+
+#ifndef __ASSEMBLY__
+
+struct vpa {
+ uint32_t descriptor;
+ uint16_t size;
+ uint8_t reserved1[3];
+ uint8_t status;
+ uint8_t reserved2[14];
+ uint32_t fru_node_id;
+ uint32_t fru_proc_id;
+ uint8_t reserved3[56];
+ uint8_t vhpn_change_counters[8];
+ uint8_t reserved4[80];
+ uint8_t cede_latency;
+ uint8_t maintain_ebb;
+ uint8_t reserved5[6];
+ uint8_t dtl_enable_mask;
+ uint8_t dedicated_cpu_donate;
+ uint8_t maintain_fpr;
+ uint8_t maintain_pmc;
+ uint8_t reserved6[28];
+ uint64_t idle_estimate_purr;
+ uint8_t reserved7[28];
+ uint16_t maintain_nr_slb;
+ uint8_t idle;
+ uint8_t maintain_vmx;
+ uint32_t vp_dispatch_count;
+ uint32_t vp_dispatch_dispersion;
+ uint64_t vp_fault_count;
+ uint64_t vp_fault_tb;
+ uint64_t purr_exprop_idle;
+ uint64_t spurr_exprop_idle;
+ uint64_t purr_exprop_busy;
+ uint64_t spurr_exprop_busy;
+ uint64_t purr_donate_idle;
+ uint64_t spurr_donate_idle;
+ uint64_t purr_donate_busy;
+ uint64_t spurr_donate_busy;
+ uint64_t vp_wait3_tb;
+ uint64_t vp_wait2_tb;
+ uint64_t vp_wait1_tb;
+ uint64_t purr_exprop_adjunct_busy;
+ uint64_t spurr_exprop_adjunct_busy;
+ uint32_t supervisor_pagein_count;
+ uint8_t reserved8[4];
+ uint64_t purr_exprop_adjunct_idle;
+ uint64_t spurr_exprop_adjunct_idle;
+ uint64_t adjunct_insns_executed;
+ uint8_t reserved9[120];
+ uint64_t dtl_index;
+ uint8_t reserved10[96];
+};
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASMPOWERPC_VPA_H_ */
diff --git a/powerpc/Makefile.ppc64 b/powerpc/Makefile.ppc64
index ea684470..b0ed2b10 100644
--- a/powerpc/Makefile.ppc64
+++ b/powerpc/Makefile.ppc64
@@ -19,7 +19,7 @@ reloc.o = $(TEST_DIR)/reloc64.o
OBJDIRS += lib/ppc64
# ppc64 specific tests
-tests =
+tests = $(TEST_DIR)/spapr_vpa.elf
include $(SRCDIR)/$(TEST_DIR)/Makefile.common
diff --git a/powerpc/spapr_vpa.c b/powerpc/spapr_vpa.c
new file mode 100644
index 00000000..5586eb8d
--- /dev/null
+++ b/powerpc/spapr_vpa.c
@@ -0,0 +1,172 @@
+/*
+ * Test sPAPR "Per Virtual Processor Area" and H_REGISTER_VPA hypervisor call
+ * (also known as VPA, also known as lppaca in the Linux pseries kernel).
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.
+ */
+#include <libcflat.h>
+#include <libfdt/libfdt.h>
+#include <devicetree.h>
+#include <util.h>
+#include <alloc.h>
+#include <asm/processor.h>
+#include <asm/setup.h>
+#include <asm/hcall.h>
+#include <asm/vpa.h>
+#include <asm/io.h> /* for endian accessors */
+
+static int verbose;
+
+static void print_vpa(struct vpa *vpa)
+{
+ printf("VPA\n");
+ printf("descriptor: 0x%08x\n", be32_to_cpu(vpa->descriptor));
+ printf("size: 0x%04x\n", be16_to_cpu(vpa->size));
+ printf("status: 0x%02x\n", vpa->status);
+ printf("fru_node_id: 0x%08x\n", be32_to_cpu(vpa->fru_node_id));
+ printf("fru_proc_id: 0x%08x\n", be32_to_cpu(vpa->fru_proc_id));
+ printf("vhpn_change_counters: 0x%02x %02x %02x %02x %02x %02x %02x %02x\n", vpa->vhpn_change_counters[0], vpa->vhpn_change_counters[1], vpa->vhpn_change_counters[2], vpa->vhpn_change_counters[3], vpa->vhpn_change_counters[4], vpa->vhpn_change_counters[5], vpa->vhpn_change_counters[6], vpa->vhpn_change_counters[7]);
+ printf("vp_dispatch_count: 0x%08x\n", be32_to_cpu(vpa->vp_dispatch_count));
+ printf("vp_dispatch_dispersion: 0x%08x\n", be32_to_cpu(vpa->vp_dispatch_dispersion));
+ printf("vp_fault_count: 0x%08lx\n", be64_to_cpu(vpa->vp_fault_count));
+ printf("vp_fault_tb: 0x%08lx\n", be64_to_cpu(vpa->vp_fault_tb));
+ printf("purr_exprop_idle: 0x%08lx\n", be64_to_cpu(vpa->purr_exprop_idle));
+ printf("spurr_exprop_idle: 0x%08lx\n", be64_to_cpu(vpa->spurr_exprop_idle));
+ printf("purr_exprop_busy: 0x%08lx\n", be64_to_cpu(vpa->purr_exprop_busy));
+ printf("spurr_exprop_busy: 0x%08lx\n", be64_to_cpu(vpa->spurr_exprop_busy));
+ printf("purr_donate_idle: 0x%08lx\n", be64_to_cpu(vpa->purr_donate_idle));
+ printf("spurr_donate_idle: 0x%08lx\n", be64_to_cpu(vpa->spurr_donate_idle));
+ printf("purr_donate_busy: 0x%08lx\n", be64_to_cpu(vpa->purr_donate_busy));
+ printf("spurr_donate_busy: 0x%08lx\n", be64_to_cpu(vpa->spurr_donate_busy));
+ printf("vp_wait3_tb: 0x%08lx\n", be64_to_cpu(vpa->vp_wait3_tb));
+ printf("vp_wait2_tb: 0x%08lx\n", be64_to_cpu(vpa->vp_wait2_tb));
+ printf("vp_wait1_tb: 0x%08lx\n", be64_to_cpu(vpa->vp_wait1_tb));
+ printf("purr_exprop_adjunct_busy: 0x%08lx\n", be64_to_cpu(vpa->purr_exprop_adjunct_busy));
+ printf("spurr_exprop_adjunct_busy: 0x%08lx\n", be64_to_cpu(vpa->spurr_exprop_adjunct_busy));
+ printf("purr_exprop_adjunct_idle: 0x%08lx\n", be64_to_cpu(vpa->purr_exprop_adjunct_idle));
+ printf("spurr_exprop_adjunct_idle: 0x%08lx\n", be64_to_cpu(vpa->spurr_exprop_adjunct_idle));
+ printf("adjunct_insns_executed: 0x%08lx\n", be64_to_cpu(vpa->adjunct_insns_executed));
+ printf("dtl_index: 0x%08lx\n", be64_to_cpu(vpa->dtl_index));
+}
+
+#define SUBFUNC_RESERVED (0ULL << 45)
+#define SUBFUNC_REGISTER (1ULL << 45)
+#define SUBFUNC_DEREGISTER (5ULL << 45)
+
+/**
+ * Test the H_REGISTER_VPA h-call register/deregister calls.
+ */
+static void test_register_vpa(void)
+{
+ struct vpa *vpa;
+ uint32_t cpuid = fdt_boot_cpuid_phys(dt_fdt());
+ int rc;
+
+ report_prefix_push("H_REGISTER_VPA");
+
+ vpa = memalign(4096, sizeof(*vpa));
+
+ memset(vpa, 0, sizeof(*vpa));
+
+ vpa->size = cpu_to_be16(sizeof(*vpa));
+
+ rc = hcall(H_REGISTER_VPA, SUBFUNC_RESERVED, cpuid, vpa);
+ report(rc == H_PARAMETER, "Reserved sub-function fails with H_PARAMETER");
+
+ rc = hcall(H_REGISTER_VPA, SUBFUNC_REGISTER, 0xbadbad, vpa);
+ report(rc == H_PARAMETER, "Register with invalid proc-no fails");
+
+ rc = hcall(H_REGISTER_VPA, SUBFUNC_REGISTER, cpuid, (void *)vpa + 8);
+ report(rc == H_PARAMETER, "Register with VPA not cacheline aligned fails");
+
+
+ rc = hcall(H_REGISTER_VPA, SUBFUNC_REGISTER, cpuid, (void *)vpa + 4096 - 128);
+ report(rc == H_PARAMETER, "Register with VPA spanning 4096 bytes fails");
+
+ vpa->size = cpu_to_be16(632);
+ rc = hcall(H_REGISTER_VPA, SUBFUNC_REGISTER, cpuid, (void *)vpa);
+ report(rc == H_PARAMETER, "Register with VPA size < 640 bytes fails");
+ vpa->size = cpu_to_be16(sizeof(*vpa));
+
+ rc = hcall(H_REGISTER_VPA, SUBFUNC_REGISTER, cpuid, PHYSICAL_END);
+ report(rc == H_PARAMETER, "Register with VPA outside guest real memory fails");
+
+
+ rc = hcall(H_REGISTER_VPA, SUBFUNC_REGISTER, cpuid, vpa);
+ report(rc == H_SUCCESS, "VPA registered");
+
+ rc = hcall(H_REGISTER_VPA, SUBFUNC_DEREGISTER, cpuid, NULL);
+ report(rc == H_SUCCESS, "VPA deregistered");
+
+ /*
+ * From PAPR: "note no check is made that a valid VPA registration
+ * exists".
+ */
+ rc = hcall(H_REGISTER_VPA, SUBFUNC_DEREGISTER, cpuid, NULL);
+ report(rc == H_SUCCESS, "Deregister succeeds with no VPA registered");
+
+ rc = hcall(H_REGISTER_VPA, SUBFUNC_DEREGISTER, 0xbadbad, NULL);
+ report(rc == H_PARAMETER, "Deregister with invalid proc-no fails");
+
+ report_prefix_pop();
+}
+
+/**
+ * Test some VPA fields.
+ */
+static void test_vpa(void)
+{
+ struct vpa *vpa;
+ uint32_t cpuid = fdt_boot_cpuid_phys(dt_fdt());
+ int disp_count1, disp_count2;
+ int rc;
+
+ report_prefix_push("VPA");
+
+ vpa = memalign(4096, sizeof(*vpa));
+
+ memset(vpa, 0, sizeof(*vpa));
+
+ vpa->size = cpu_to_be16(sizeof(*vpa));
+
+ rc = hcall(H_REGISTER_VPA, SUBFUNC_REGISTER, cpuid, vpa);
+ if (rc != H_SUCCESS) {
+ report_skip("VPA could not be registered");
+ return;
+ }
+
+ if (verbose)
+ print_vpa(vpa);
+
+ disp_count1 = be32_to_cpu(vpa->vp_dispatch_count);
+ report(disp_count1 % 2 == 0, "Dispatch count is even while running");
+ msleep(100);
+ disp_count2 = be32_to_cpu(vpa->vp_dispatch_count);
+ report(disp_count1 != disp_count2, "Dispatch count increments over H_CEDE");
+
+ rc = hcall(H_REGISTER_VPA, SUBFUNC_DEREGISTER, cpuid, vpa);
+ if (rc != H_SUCCESS)
+ report_fail("Could not deregister after registration");
+
+ disp_count1 = be32_to_cpu(vpa->vp_dispatch_count);
+ report(disp_count1 % 2 == 1, "Dispatch count is odd after deregister");
+
+ report_prefix_pop();
+}
+
+int main(int argc, char *argv[])
+{
+ int i;
+
+ for (i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "-v") == 0) {
+ verbose = 1;
+ }
+ }
+
+ test_register_vpa();
+
+ test_vpa();
+
+ return report_summary();
+}
diff --git a/powerpc/unittests.cfg b/powerpc/unittests.cfg
index e206a225..dd5f361c 100644
--- a/powerpc/unittests.cfg
+++ b/powerpc/unittests.cfg
@@ -39,6 +39,9 @@ groups = selftest
[spapr_hcall]
file = spapr_hcall.elf
+[spapr_vpa]
+file = spapr_vpa.elf
+
[rtas-get-time-of-day]
file = rtas.elf
timeout = 5
--
2.40.1
next prev parent reply other threads:[~2023-06-08 8:05 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-06-08 7:58 [kvm-unit-tests v4 00/12] powerpc: updates, P10, PNV support Nicholas Piggin
2023-06-08 7:58 ` [kvm-unit-tests v4 01/12] powerpc: Report instruction address and MSR in unhandled exception error Nicholas Piggin
2023-06-21 14:53 ` Thomas Huth
2023-06-08 7:58 ` [kvm-unit-tests v4 02/12] powerpc: Add some checking to exception handler install Nicholas Piggin
2023-06-21 14:54 ` Thomas Huth
2023-06-08 7:58 ` [kvm-unit-tests v4 03/12] powerpc: Abstract H_CEDE calls into a sleep functions Nicholas Piggin
2023-07-03 13:13 ` Thomas Huth
2023-06-08 7:58 ` [kvm-unit-tests v4 04/12] powerpc: Add ISA v3.1 (POWER10) support to SPR test Nicholas Piggin
2023-06-08 7:58 ` [kvm-unit-tests v4 05/12] powerpc: Extract some common helpers and defines to headers Nicholas Piggin
2023-06-08 7:58 ` [kvm-unit-tests v4 06/12] powerpc/sprs: Specify SPRs with data rather than code Nicholas Piggin
2023-06-08 7:58 ` Nicholas Piggin [this message]
2023-06-08 7:58 ` [kvm-unit-tests v4 08/12] powerpc: Expand exception handler vector granularity Nicholas Piggin
2023-06-08 7:58 ` [kvm-unit-tests v4 09/12] powerpc: Add support for more interrupts including HV interrupts Nicholas Piggin
2023-06-08 7:58 ` [kvm-unit-tests v4 10/12] powerpc: Discover runtime load address dynamically Nicholas Piggin
2023-06-08 7:58 ` [kvm-unit-tests v4 11/12] powerpc: Support powernv machine with QEMU TCG Nicholas Piggin
2023-06-08 7:58 ` [kvm-unit-tests v4 12/12] powerpc/sprs: Test hypervisor registers on powernv machine Nicholas Piggin
2023-06-14 1:09 ` [kvm-unit-tests v4 00/12] powerpc: updates, P10, PNV support Joel Stanley
2023-06-15 3:02 ` Nicholas Piggin
2023-06-15 8:11 ` Joel Stanley
2023-07-03 13:27 ` Thomas Huth
2023-07-30 10:10 ` Nicholas Piggin
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=20230608075826.86217-8-npiggin@gmail.com \
--to=npiggin@gmail.com \
--cc=kvm@vger.kernel.org \
--cc=linuxppc-dev@lists.ozlabs.org \
--cc=lvivier@redhat.com \
--cc=thuth@redhat.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;
as well as URLs for NNTP newsgroup(s).