[PATCH v3] powerpc: Add tests for sPAPR h-calls

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Introduce a test for sPAPR hypercalls, starting with the
three hypercalls H_SET_SPRG0, H_PAGE_INIT and H_RANDOM.

Signed-off-by: Thomas Huth <thuth@xxxxxxxxxx>
---
 v3:
 - Use report_xfail() in H_RANDOM test to report whether the
   h-call is available or not

 v2:
 - Rebased to the final version of Andrew's initial ppc64
   support patches that got merged yesterday
 - Added a test for the H_RANDOM hypercall

 Please note that you need the latest QEMU development version
 since some of the hypercalls have only been added recently.

 In case somebody wants to review the description of the h-calls, you
 can find them in LoPAPR, chapters 14.5.4.3.1, 14.5.4.3.3 and 14.15.1.
 See: https://members.openpowerfoundation.org/document/dl/469

 lib/powerpc/asm/hcall.h |   3 +
 powerpc/Makefile.common |   5 +-
 powerpc/spapr_hcall.c   | 167 ++++++++++++++++++++++++++++++++++++++++++++++++
 powerpc/unittests.cfg   |   3 +
 4 files changed, 177 insertions(+), 1 deletion(-)
 create mode 100644 powerpc/spapr_hcall.c

diff --git a/lib/powerpc/asm/hcall.h b/lib/powerpc/asm/hcall.h
index 750c655..f6f9ea8 100644
--- a/lib/powerpc/asm/hcall.h
+++ b/lib/powerpc/asm/hcall.h
@@ -15,8 +15,11 @@
 #define H_PRIVILEGE		-3
 #define H_PARAMETER		-4
 
+#define H_SET_SPRG0		0x24
 #define H_SET_DABR		0x28
+#define H_PAGE_INIT		0x2c
 #define H_PUT_TERM_CHAR		0x58
+#define H_RANDOM		0x300
 
 #ifndef __ASSEMBLY__
 /*
diff --git a/powerpc/Makefile.common b/powerpc/Makefile.common
index b526668..2ce6494 100644
--- a/powerpc/Makefile.common
+++ b/powerpc/Makefile.common
@@ -5,7 +5,8 @@
 #
 
 tests-common = \
-	$(TEST_DIR)/selftest.elf
+	$(TEST_DIR)/selftest.elf \
+	$(TEST_DIR)/spapr_hcall.elf
 
 all: $(TEST_DIR)/boot_rom.bin test_cases
 
@@ -63,3 +64,5 @@ generated_files = $(asm-offsets)
 test_cases: $(generated_files) $(tests-common) $(tests)
 
 $(TEST_DIR)/selftest.elf: $(cstart.o) $(reloc.o) $(TEST_DIR)/selftest.o
+
+$(TEST_DIR)/spapr_hcall.elf: $(cstart.o) $(reloc.o) $(TEST_DIR)/spapr_hcall.o
diff --git a/powerpc/spapr_hcall.c b/powerpc/spapr_hcall.c
new file mode 100644
index 0000000..46731e1
--- /dev/null
+++ b/powerpc/spapr_hcall.c
@@ -0,0 +1,167 @@
+/*
+ * Test sPAPR hypervisor calls (aka. h-calls)
+ *
+ * Copyright 2016  Thomas Huth, Red Hat Inc.
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.
+ */
+#include <libcflat.h>
+#include <util.h>
+#include <alloc.h>
+#include <asm/hcall.h>
+
+#define PAGE_SIZE 4096
+
+#define H_ZERO_PAGE	(1UL << (63-48))
+#define H_COPY_PAGE	(1UL << (63-49))
+
+#define mfspr(nr) ({ \
+	uint64_t ret; \
+	asm volatile("mfspr %0,%1" : "=r"(ret) : "i"(nr)); \
+	ret; \
+})
+
+#define SPR_SPRG0	0x110
+
+/**
+ * Test the H_SET_SPRG0 h-call by setting some values and checking whether
+ * the SPRG0 register contains the correct values afterwards
+ */
+static void test_h_set_sprg0(int argc, char **argv)
+{
+	uint64_t sprg0, sprg0_orig;
+	int rc;
+
+	if (argc > 1)
+		report_abort("Unsupported argument: '%s'", argv[1]);
+
+	sprg0_orig = mfspr(SPR_SPRG0);
+
+	rc = hcall(H_SET_SPRG0, 0xcafebabedeadbeefULL);
+	sprg0 = mfspr(SPR_SPRG0);
+	report("sprg0 = 0xcafebabedeadbeef",
+		rc == H_SUCCESS && sprg0 == 0xcafebabedeadbeefULL);
+
+	rc = hcall(H_SET_SPRG0, 0xaaaaaaaa55555555ULL);
+	sprg0 = mfspr(SPR_SPRG0);
+	report("sprg0 = 0xaaaaaaaa55555555",
+		rc == H_SUCCESS && sprg0 == 0xaaaaaaaa55555555ULL);
+
+	rc = hcall(H_SET_SPRG0, sprg0_orig);
+	sprg0 = mfspr(SPR_SPRG0);
+	report("sprg0 = 0x%llx",
+		rc == H_SUCCESS && sprg0 == sprg0_orig, sprg0_orig);
+}
+
+/**
+ * Test the H_PAGE_INIT h-call by using it to clear and to copy a page, and
+ * by checking for the correct values in the destination page afterwards
+ */
+static void test_h_page_init(int argc, char **argv)
+{
+	u8 *dst, *src;
+	int rc;
+
+	if (argc > 1)
+		report_abort("Unsupported argument: '%s'", argv[1]);
+
+	dst = memalign(PAGE_SIZE, PAGE_SIZE);
+	src = memalign(PAGE_SIZE, PAGE_SIZE);
+	if (!dst || !src)
+		report_abort("Failed to alloc memory");
+
+	memset(dst, 0xaa, PAGE_SIZE);
+	rc = hcall(H_PAGE_INIT, H_ZERO_PAGE, dst, src);
+	report("h_zero_page", rc == H_SUCCESS && *(uint64_t*)dst == 0);
+
+	*(uint64_t*)src = 0xbeefc0dedeadcafeULL;
+	rc = hcall(H_PAGE_INIT, H_COPY_PAGE, dst, src);
+	report("h_copy_page",
+		rc == H_SUCCESS && *(uint64_t*)dst == 0xbeefc0dedeadcafeULL);
+
+	*(uint64_t*)src = 0x9abcdef012345678ULL;
+	rc = hcall(H_PAGE_INIT, H_COPY_PAGE|H_ZERO_PAGE, dst, src);
+	report("h_copy_page+h_zero_page",
+		rc == H_SUCCESS &&  *(uint64_t*)dst == 0x9abcdef012345678ULL);
+
+	rc = hcall(H_PAGE_INIT, H_ZERO_PAGE, dst + 0x123, src);
+	report("h_zero_page unaligned dst", rc == H_PARAMETER);
+
+	rc = hcall(H_PAGE_INIT, H_COPY_PAGE, dst, src + 0x123);
+	report("h_copy_page unaligned src", rc == H_PARAMETER);
+}
+
+static int h_random(uint64_t *val)
+{
+	register uint64_t r3 asm("r3") = H_RANDOM;
+	register uint64_t r4 asm("r4");
+
+	asm volatile (" sc 1 " : "+r"(r3), "=r"(r4) : "r"(r3));
+	*val = r4;
+
+	return r3;
+}
+
+/**
+ * Test H_RANDOM by calling it a couple of times to check whether all bit
+ * positions really toggle (there should be no "stuck" bits in the output)
+ */
+static void test_h_random(int argc, char **argv)
+{
+	uint64_t rval, val0, val1;
+	int rc, i;
+
+	if (argc > 1)
+		report_abort("Unsupported argument: '%s'", argv[1]);
+
+	/* H_RANDOM is optional - so check for sane return values first */
+	rc = h_random(&rval);
+	report_xfail("h-call available", rc == H_FUNCTION, rc == H_SUCCESS);
+	if (rc != H_SUCCESS)
+		return;
+
+	val0 = 0ULL;
+	val1 = ~0ULL;
+
+	i = 100;
+	do {
+		rc = h_random(&rval);
+		if (rc != H_SUCCESS)
+			break;
+		val0 |= rval;
+		val1 &= rval;
+	} while (i-- > 0 && (val0 != ~0ULL || val1 != 0ULL));
+
+	report("no stuck bits", rc == H_SUCCESS && val0 == ~0ULL && val1 == 0);
+}
+
+struct {
+	const char *name;
+	void (*func)(int argc, char **argv);
+} hctests[] = {
+	{ "h_set_sprg0", test_h_set_sprg0 },
+	{ "h_page_init", test_h_page_init },
+	{ "h_random", test_h_random },
+	{ NULL, NULL }
+};
+
+int main(int argc, char **argv)
+{
+	int all = 0;
+	int i;
+
+	report_prefix_push("hypercall");
+
+	if (!argc || (argc == 1 && !strcmp(argv[0], "all")))
+		all = 1;
+
+	for (i = 0; hctests[i].name != NULL; i++) {
+		report_prefix_push(hctests[i].name);
+		if (all || strcmp(argv[0], hctests[i].name) == 0) {
+			hctests[i].func(argc, argv);
+		}
+		report_prefix_pop();
+	}
+
+	return report_summary();
+}
diff --git a/powerpc/unittests.cfg b/powerpc/unittests.cfg
index 60f9be8..d858436 100644
--- a/powerpc/unittests.cfg
+++ b/powerpc/unittests.cfg
@@ -28,3 +28,6 @@ file = selftest.elf
 smp = 2
 extra_params = -m 256 -append 'setup smp=2 mem=256'
 groups = selftest
+
+[spapr_hcall]
+file = spapr_hcall.elf
-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe kvm-ppc" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [KVM Development]     [KVM ARM]     [KVM ia64]     [Linux Virtualization]     [Linux USB Devel]     [Linux Video]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux