xref: /kvm-unit-tests/powerpc/spapr_hcall.c (revision a9abb1b82d6d6bd0821a7234433b4de975e2245f)
1c20e1e54SThomas Huth /*
2c20e1e54SThomas Huth  * Test sPAPR hypervisor calls (aka. h-calls)
3c20e1e54SThomas Huth  *
4c20e1e54SThomas Huth  * Copyright 2016  Thomas Huth, Red Hat Inc.
5c20e1e54SThomas Huth  *
6c20e1e54SThomas Huth  * This work is licensed under the terms of the GNU LGPL, version 2.
7c20e1e54SThomas Huth  */
8c20e1e54SThomas Huth #include <libcflat.h>
9c20e1e54SThomas Huth #include <util.h>
10c20e1e54SThomas Huth #include <alloc.h>
11c20e1e54SThomas Huth #include <asm/hcall.h>
12c20e1e54SThomas Huth 
13c20e1e54SThomas Huth #define PAGE_SIZE 4096
14c20e1e54SThomas Huth 
15c20e1e54SThomas Huth #define H_ZERO_PAGE	(1UL << (63-48))
16c20e1e54SThomas Huth #define H_COPY_PAGE	(1UL << (63-49))
17c20e1e54SThomas Huth 
18c20e1e54SThomas Huth #define mfspr(nr) ({ \
19c20e1e54SThomas Huth 	uint64_t ret; \
20c20e1e54SThomas Huth 	asm volatile("mfspr %0,%1" : "=r"(ret) : "i"(nr)); \
21c20e1e54SThomas Huth 	ret; \
22c20e1e54SThomas Huth })
23c20e1e54SThomas Huth 
24c20e1e54SThomas Huth #define SPR_SPRG0	0x110
25c20e1e54SThomas Huth 
26c20e1e54SThomas Huth /**
27c20e1e54SThomas Huth  * Test the H_SET_SPRG0 h-call by setting some values and checking whether
28c20e1e54SThomas Huth  * the SPRG0 register contains the correct values afterwards
29c20e1e54SThomas Huth  */
30c20e1e54SThomas Huth static void test_h_set_sprg0(int argc, char **argv)
31c20e1e54SThomas Huth {
32c20e1e54SThomas Huth 	uint64_t sprg0, sprg0_orig;
33c20e1e54SThomas Huth 	int rc;
34c20e1e54SThomas Huth 
35c20e1e54SThomas Huth 	if (argc > 1)
36c20e1e54SThomas Huth 		report_abort("Unsupported argument: '%s'", argv[1]);
37c20e1e54SThomas Huth 
38c20e1e54SThomas Huth 	sprg0_orig = mfspr(SPR_SPRG0);
39c20e1e54SThomas Huth 
40c20e1e54SThomas Huth 	rc = hcall(H_SET_SPRG0, 0xcafebabedeadbeefULL);
41c20e1e54SThomas Huth 	sprg0 = mfspr(SPR_SPRG0);
42c20e1e54SThomas Huth 	report("sprg0 = 0xcafebabedeadbeef",
43c20e1e54SThomas Huth 		rc == H_SUCCESS && sprg0 == 0xcafebabedeadbeefULL);
44c20e1e54SThomas Huth 
45c20e1e54SThomas Huth 	rc = hcall(H_SET_SPRG0, 0xaaaaaaaa55555555ULL);
46c20e1e54SThomas Huth 	sprg0 = mfspr(SPR_SPRG0);
47c20e1e54SThomas Huth 	report("sprg0 = 0xaaaaaaaa55555555",
48c20e1e54SThomas Huth 		rc == H_SUCCESS && sprg0 == 0xaaaaaaaa55555555ULL);
49c20e1e54SThomas Huth 
50c20e1e54SThomas Huth 	rc = hcall(H_SET_SPRG0, sprg0_orig);
51c20e1e54SThomas Huth 	sprg0 = mfspr(SPR_SPRG0);
52c20e1e54SThomas Huth 	report("sprg0 = 0x%llx",
53c20e1e54SThomas Huth 		rc == H_SUCCESS && sprg0 == sprg0_orig, sprg0_orig);
54c20e1e54SThomas Huth }
55c20e1e54SThomas Huth 
56c20e1e54SThomas Huth /**
57c20e1e54SThomas Huth  * Test the H_PAGE_INIT h-call by using it to clear and to copy a page, and
58c20e1e54SThomas Huth  * by checking for the correct values in the destination page afterwards
59c20e1e54SThomas Huth  */
60c20e1e54SThomas Huth static void test_h_page_init(int argc, char **argv)
61c20e1e54SThomas Huth {
62c20e1e54SThomas Huth 	u8 *dst, *src;
63c20e1e54SThomas Huth 	int rc;
64c20e1e54SThomas Huth 
65c20e1e54SThomas Huth 	if (argc > 1)
66c20e1e54SThomas Huth 		report_abort("Unsupported argument: '%s'", argv[1]);
67c20e1e54SThomas Huth 
68c20e1e54SThomas Huth 	dst = memalign(PAGE_SIZE, PAGE_SIZE);
69c20e1e54SThomas Huth 	src = memalign(PAGE_SIZE, PAGE_SIZE);
70c20e1e54SThomas Huth 	if (!dst || !src)
71c20e1e54SThomas Huth 		report_abort("Failed to alloc memory");
72c20e1e54SThomas Huth 
73c20e1e54SThomas Huth 	memset(dst, 0xaa, PAGE_SIZE);
74c20e1e54SThomas Huth 	rc = hcall(H_PAGE_INIT, H_ZERO_PAGE, dst, src);
75c20e1e54SThomas Huth 	report("h_zero_page", rc == H_SUCCESS && *(uint64_t*)dst == 0);
76c20e1e54SThomas Huth 
77c20e1e54SThomas Huth 	*(uint64_t*)src = 0xbeefc0dedeadcafeULL;
78c20e1e54SThomas Huth 	rc = hcall(H_PAGE_INIT, H_COPY_PAGE, dst, src);
79c20e1e54SThomas Huth 	report("h_copy_page",
80c20e1e54SThomas Huth 		rc == H_SUCCESS && *(uint64_t*)dst == 0xbeefc0dedeadcafeULL);
81c20e1e54SThomas Huth 
82c20e1e54SThomas Huth 	*(uint64_t*)src = 0x9abcdef012345678ULL;
83c20e1e54SThomas Huth 	rc = hcall(H_PAGE_INIT, H_COPY_PAGE|H_ZERO_PAGE, dst, src);
84c20e1e54SThomas Huth 	report("h_copy_page+h_zero_page",
85c20e1e54SThomas Huth 		rc == H_SUCCESS &&  *(uint64_t*)dst == 0x9abcdef012345678ULL);
86c20e1e54SThomas Huth 
87c20e1e54SThomas Huth 	rc = hcall(H_PAGE_INIT, H_ZERO_PAGE, dst + 0x123, src);
88c20e1e54SThomas Huth 	report("h_zero_page unaligned dst", rc == H_PARAMETER);
89c20e1e54SThomas Huth 
90c20e1e54SThomas Huth 	rc = hcall(H_PAGE_INIT, H_COPY_PAGE, dst, src + 0x123);
91c20e1e54SThomas Huth 	report("h_copy_page unaligned src", rc == H_PARAMETER);
92c20e1e54SThomas Huth }
93c20e1e54SThomas Huth 
94c20e1e54SThomas Huth static int h_random(uint64_t *val)
95c20e1e54SThomas Huth {
96c20e1e54SThomas Huth 	register uint64_t r3 asm("r3") = H_RANDOM;
97c20e1e54SThomas Huth 	register uint64_t r4 asm("r4");
98c20e1e54SThomas Huth 
9943c8baceSThomas Huth 	asm volatile (" sc 1 "	: "+r"(r3), "=r"(r4) :
10043c8baceSThomas Huth 				: "r0", "r5", "r6", "r7", "r8", "r9", "r10",
10143c8baceSThomas Huth 				  "r11", "r12", "xer", "ctr", "cc");
102c20e1e54SThomas Huth 	*val = r4;
103c20e1e54SThomas Huth 
104c20e1e54SThomas Huth 	return r3;
105c20e1e54SThomas Huth }
106c20e1e54SThomas Huth 
107c20e1e54SThomas Huth /**
108c20e1e54SThomas Huth  * Test H_RANDOM by calling it a couple of times to check whether all bit
109c20e1e54SThomas Huth  * positions really toggle (there should be no "stuck" bits in the output)
110c20e1e54SThomas Huth  */
111c20e1e54SThomas Huth static void test_h_random(int argc, char **argv)
112c20e1e54SThomas Huth {
113c20e1e54SThomas Huth 	uint64_t rval, val0, val1;
114c20e1e54SThomas Huth 	int rc, i;
115c20e1e54SThomas Huth 
116c20e1e54SThomas Huth 	if (argc > 1)
117c20e1e54SThomas Huth 		report_abort("Unsupported argument: '%s'", argv[1]);
118c20e1e54SThomas Huth 
119c20e1e54SThomas Huth 	/* H_RANDOM is optional - so check for sane return values first */
120c20e1e54SThomas Huth 	rc = h_random(&rval);
121c20e1e54SThomas Huth 	report_xfail("h-call available", rc == H_FUNCTION, rc == H_SUCCESS);
122c20e1e54SThomas Huth 	if (rc != H_SUCCESS)
123c20e1e54SThomas Huth 		return;
124c20e1e54SThomas Huth 
125c20e1e54SThomas Huth 	val0 = 0ULL;
126c20e1e54SThomas Huth 	val1 = ~0ULL;
127c20e1e54SThomas Huth 
128c20e1e54SThomas Huth 	i = 100;
129c20e1e54SThomas Huth 	do {
130c20e1e54SThomas Huth 		rc = h_random(&rval);
131c20e1e54SThomas Huth 		if (rc != H_SUCCESS)
132c20e1e54SThomas Huth 			break;
133c20e1e54SThomas Huth 		val0 |= rval;
134c20e1e54SThomas Huth 		val1 &= rval;
135c20e1e54SThomas Huth 	} while (i-- > 0 && (val0 != ~0ULL || val1 != 0ULL));
136c20e1e54SThomas Huth 
137c20e1e54SThomas Huth 	report("no stuck bits", rc == H_SUCCESS && val0 == ~0ULL && val1 == 0);
138c20e1e54SThomas Huth }
139c20e1e54SThomas Huth 
140c20e1e54SThomas Huth struct {
141c20e1e54SThomas Huth 	const char *name;
142c20e1e54SThomas Huth 	void (*func)(int argc, char **argv);
143c20e1e54SThomas Huth } hctests[] = {
144c20e1e54SThomas Huth 	{ "h_set_sprg0", test_h_set_sprg0 },
145c20e1e54SThomas Huth 	{ "h_page_init", test_h_page_init },
146c20e1e54SThomas Huth 	{ "h_random", test_h_random },
147c20e1e54SThomas Huth 	{ NULL, NULL }
148c20e1e54SThomas Huth };
149c20e1e54SThomas Huth 
150c20e1e54SThomas Huth int main(int argc, char **argv)
151c20e1e54SThomas Huth {
152c20e1e54SThomas Huth 	int all = 0;
153c20e1e54SThomas Huth 	int i;
154c20e1e54SThomas Huth 
155c20e1e54SThomas Huth 	report_prefix_push("hypercall");
156c20e1e54SThomas Huth 
157*a9abb1b8SAndrew Jones 	if (argc < 2 || (argc == 2 && !strcmp(argv[1], "all")))
158c20e1e54SThomas Huth 		all = 1;
159c20e1e54SThomas Huth 
160c20e1e54SThomas Huth 	for (i = 0; hctests[i].name != NULL; i++) {
161c20e1e54SThomas Huth 		report_prefix_push(hctests[i].name);
162*a9abb1b8SAndrew Jones 		if (all || strcmp(argv[1], hctests[i].name) == 0) {
163*a9abb1b8SAndrew Jones 			hctests[i].func(argc-1, &argv[1]);
164c20e1e54SThomas Huth 		}
165c20e1e54SThomas Huth 		report_prefix_pop();
166c20e1e54SThomas Huth 	}
167c20e1e54SThomas Huth 
168c20e1e54SThomas Huth 	return report_summary();
169c20e1e54SThomas Huth }
170