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