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