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