GNU Linux-libre 4.19.207-gnu1
[releases.git] / tools / testing / selftests / powerpc / alignment / alignment_handler.c
1 /*
2  * Test the powerpc alignment handler on POWER8/POWER9
3  *
4  * Copyright (C) 2017 IBM Corporation (Michael Neuling, Andrew Donnellan)
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version
9  * 2 of the License, or (at your option) any later version.
10  */
11
12 /*
13  * This selftest exercises the powerpc alignment fault handler.
14  *
15  * We create two sets of source and destination buffers, one in regular memory,
16  * the other cache-inhibited (we use /dev/fb0 for this).
17  *
18  * We initialise the source buffers, then use whichever set of load/store
19  * instructions is under test to copy bytes from the source buffers to the
20  * destination buffers. For the regular buffers, these instructions will
21  * execute normally. For the cache-inhibited buffers, these instructions
22  * will trap and cause an alignment fault, and the alignment fault handler
23  * will emulate the particular instruction under test. We then compare the
24  * destination buffers to ensure that the native and emulated cases give the
25  * same result.
26  *
27  * TODO:
28  *   - Any FIXMEs below
29  *   - Test VSX regs < 32 and > 32
30  *   - Test all loads and stores
31  *   - Check update forms do update register
32  *   - Test alignment faults over page boundary
33  *
34  * Some old binutils may not support all the instructions.
35  */
36
37
38 #include <sys/mman.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <fcntl.h>
42 #include <unistd.h>
43 #include <stdbool.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <assert.h>
48 #include <getopt.h>
49 #include <setjmp.h>
50 #include <signal.h>
51
52 #include <asm/cputable.h>
53
54 #include "utils.h"
55
56 int bufsize;
57 int debug;
58 int testing;
59 volatile int gotsig;
60
61 void sighandler(int sig, siginfo_t *info, void *ctx)
62 {
63         ucontext_t *ucp = ctx;
64
65         if (!testing) {
66                 signal(sig, SIG_DFL);
67                 kill(0, sig);
68         }
69         gotsig = sig;
70 #ifdef __powerpc64__
71         ucp->uc_mcontext.gp_regs[PT_NIP] += 4;
72 #else
73         ucp->uc_mcontext.uc_regs->gregs[PT_NIP] += 4;
74 #endif
75 }
76
77 #define XFORM(reg, n)  " " #reg " ,%"#n",%2 ;"
78 #define DFORM(reg, n)  " " #reg " ,0(%"#n") ;"
79
80 #define TEST(name, ld_op, st_op, form, ld_reg, st_reg)          \
81         void test_##name(char *s, char *d)                      \
82         {                                                       \
83                 asm volatile(                                   \
84                         #ld_op form(ld_reg, 0)                  \
85                         #st_op form(st_reg, 1)                  \
86                         :: "r"(s), "r"(d), "r"(0)               \
87                         : "memory", "vs0", "vs32", "r31");      \
88         }                                                       \
89         rc |= do_test(#name, test_##name)
90
91 #define LOAD_VSX_XFORM_TEST(op) TEST(op, op, stxvd2x, XFORM, 32, 32)
92 #define STORE_VSX_XFORM_TEST(op) TEST(op, lxvd2x, op, XFORM, 32, 32)
93 #define LOAD_VSX_DFORM_TEST(op) TEST(op, op, stxv, DFORM, 32, 32)
94 #define STORE_VSX_DFORM_TEST(op) TEST(op, lxv, op, DFORM, 32, 32)
95 #define LOAD_VMX_XFORM_TEST(op) TEST(op, op, stxvd2x, XFORM, 0, 32)
96 #define STORE_VMX_XFORM_TEST(op) TEST(op, lxvd2x, op, XFORM, 32, 0)
97 #define LOAD_VMX_DFORM_TEST(op) TEST(op, op, stxv, DFORM, 0, 32)
98 #define STORE_VMX_DFORM_TEST(op) TEST(op, lxv, op, DFORM, 32, 0)
99
100 #define LOAD_XFORM_TEST(op) TEST(op, op, stdx, XFORM, 31, 31)
101 #define STORE_XFORM_TEST(op) TEST(op, ldx, op, XFORM, 31, 31)
102 #define LOAD_DFORM_TEST(op) TEST(op, op, std, DFORM, 31, 31)
103 #define STORE_DFORM_TEST(op) TEST(op, ld, op, DFORM, 31, 31)
104
105 #define LOAD_FLOAT_DFORM_TEST(op)  TEST(op, op, stfd, DFORM, 0, 0)
106 #define STORE_FLOAT_DFORM_TEST(op) TEST(op, lfd, op, DFORM, 0, 0)
107 #define LOAD_FLOAT_XFORM_TEST(op)  TEST(op, op, stfdx, XFORM, 0, 0)
108 #define STORE_FLOAT_XFORM_TEST(op) TEST(op, lfdx, op, XFORM, 0, 0)
109
110
111 /* FIXME: Unimplemented tests: */
112 // STORE_DFORM_TEST(stq)   /* FIXME: need two registers for quad */
113 // STORE_DFORM_TEST(stswi) /* FIXME: string instruction */
114
115 // STORE_XFORM_TEST(stwat) /* AMO can't emulate or run on CI */
116 // STORE_XFORM_TEST(stdat) /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
117
118
119 /* preload byte by byte */
120 void preload_data(void *dst, int offset, int width)
121 {
122         char *c = dst;
123         int i;
124
125         c += offset;
126
127         for (i = 0 ; i < width ; i++)
128                 c[i] = i;
129 }
130
131 int test_memcpy(void *dst, void *src, int size, int offset,
132                 void (*test_func)(char *, char *))
133 {
134         char *s, *d;
135
136         s = src;
137         s += offset;
138         d = dst;
139         d += offset;
140
141         assert(size == 16);
142         gotsig = 0;
143         testing = 1;
144
145         test_func(s, d); /* run the actual test */
146
147         testing = 0;
148         if (gotsig) {
149                 if (debug)
150                         printf("  Got signal %i\n", gotsig);
151                 return 1;
152         }
153         return 0;
154 }
155
156 void dumpdata(char *s1, char *s2, int n, char *test_name)
157 {
158         int i;
159
160         printf("  %s: unexpected result:\n", test_name);
161         printf("    mem:");
162         for (i = 0; i < n; i++)
163                 printf(" %02x", s1[i]);
164         printf("\n");
165         printf("    ci: ");
166         for (i = 0; i < n; i++)
167                 printf(" %02x", s2[i]);
168         printf("\n");
169 }
170
171 int test_memcmp(void *s1, void *s2, int n, int offset, char *test_name)
172 {
173         char *s1c, *s2c;
174
175         s1c = s1;
176         s1c += offset;
177         s2c = s2;
178         s2c += offset;
179
180         if (memcmp(s1c, s2c, n)) {
181                 if (debug) {
182                         printf("\n  Compare failed. Offset:%i length:%i\n",
183                                offset, n);
184                         dumpdata(s1c, s2c, n, test_name);
185                 }
186                 return 1;
187         }
188         return 0;
189 }
190
191 /*
192  * Do two memcpy tests using the same instructions. One cachable
193  * memory and the other doesn't.
194  */
195 int do_test(char *test_name, void (*test_func)(char *, char *))
196 {
197         int offset, width, fd, rc, r;
198         void *mem0, *mem1, *ci0, *ci1;
199
200         printf("\tDoing %s:\t", test_name);
201
202         fd = open("/dev/fb0", O_RDWR);
203         if (fd < 0) {
204                 printf("\n");
205                 perror("Can't open /dev/fb0 now?");
206                 return 1;
207         }
208
209         ci0 = mmap(NULL, bufsize, PROT_WRITE, MAP_SHARED,
210                    fd, 0x0);
211         ci1 = mmap(NULL, bufsize, PROT_WRITE, MAP_SHARED,
212                    fd, bufsize);
213         if ((ci0 == MAP_FAILED) || (ci1 == MAP_FAILED)) {
214                 printf("\n");
215                 perror("mmap failed");
216                 SKIP_IF(1);
217         }
218
219         rc = posix_memalign(&mem0, bufsize, bufsize);
220         if (rc) {
221                 printf("\n");
222                 return rc;
223         }
224
225         rc = posix_memalign(&mem1, bufsize, bufsize);
226         if (rc) {
227                 printf("\n");
228                 free(mem0);
229                 return rc;
230         }
231
232         rc = 0;
233         /* offset = 0 no alignment fault, so skip */
234         for (offset = 1; offset < 16; offset++) {
235                 width = 16; /* vsx == 16 bytes */
236                 r = 0;
237
238                 /* load pattern into memory byte by byte */
239                 preload_data(ci0, offset, width);
240                 preload_data(mem0, offset, width); // FIXME: remove??
241                 memcpy(ci0, mem0, bufsize);
242                 memcpy(ci1, mem1, bufsize); /* initialise output to the same */
243
244                 /* sanity check */
245                 test_memcmp(mem0, ci0, width, offset, test_name);
246
247                 r |= test_memcpy(ci1,  ci0,  width, offset, test_func);
248                 r |= test_memcpy(mem1, mem0, width, offset, test_func);
249                 if (r && !debug) {
250                         printf("FAILED: Got signal");
251                         rc = 1;
252                         break;
253                 }
254
255                 r |= test_memcmp(mem1, ci1, width, offset, test_name);
256                 if (r && !debug) {
257                         printf("FAILED: Wrong Data");
258                         rc = 1;
259                         break;
260                 }
261         }
262
263         if (rc == 0)
264                 printf("PASSED");
265
266         printf("\n");
267
268         munmap(ci0, bufsize);
269         munmap(ci1, bufsize);
270         free(mem0);
271         free(mem1);
272         close(fd);
273
274         return rc;
275 }
276
277 static bool can_open_fb0(void)
278 {
279         int fd;
280
281         fd = open("/dev/fb0", O_RDWR);
282         if (fd < 0)
283                 return false;
284
285         close(fd);
286         return true;
287 }
288
289 int test_alignment_handler_vsx_206(void)
290 {
291         int rc = 0;
292
293         SKIP_IF(!can_open_fb0());
294         SKIP_IF(!have_hwcap(PPC_FEATURE_ARCH_2_06));
295
296         printf("VSX: 2.06B\n");
297         LOAD_VSX_XFORM_TEST(lxvd2x);
298         LOAD_VSX_XFORM_TEST(lxvw4x);
299         LOAD_VSX_XFORM_TEST(lxsdx);
300         LOAD_VSX_XFORM_TEST(lxvdsx);
301         STORE_VSX_XFORM_TEST(stxvd2x);
302         STORE_VSX_XFORM_TEST(stxvw4x);
303         STORE_VSX_XFORM_TEST(stxsdx);
304         return rc;
305 }
306
307 int test_alignment_handler_vsx_207(void)
308 {
309         int rc = 0;
310
311         SKIP_IF(!can_open_fb0());
312         SKIP_IF(!have_hwcap2(PPC_FEATURE2_ARCH_2_07));
313
314         printf("VSX: 2.07B\n");
315         LOAD_VSX_XFORM_TEST(lxsspx);
316         LOAD_VSX_XFORM_TEST(lxsiwax);
317         LOAD_VSX_XFORM_TEST(lxsiwzx);
318         STORE_VSX_XFORM_TEST(stxsspx);
319         STORE_VSX_XFORM_TEST(stxsiwx);
320         return rc;
321 }
322
323 int test_alignment_handler_vsx_300(void)
324 {
325         int rc = 0;
326
327         SKIP_IF(!can_open_fb0());
328
329         SKIP_IF(!have_hwcap2(PPC_FEATURE2_ARCH_3_00));
330         printf("VSX: 3.00B\n");
331         LOAD_VMX_DFORM_TEST(lxsd);
332         LOAD_VSX_XFORM_TEST(lxsibzx);
333         LOAD_VSX_XFORM_TEST(lxsihzx);
334         LOAD_VMX_DFORM_TEST(lxssp);
335         LOAD_VSX_DFORM_TEST(lxv);
336         LOAD_VSX_XFORM_TEST(lxvb16x);
337         LOAD_VSX_XFORM_TEST(lxvh8x);
338         LOAD_VSX_XFORM_TEST(lxvx);
339         LOAD_VSX_XFORM_TEST(lxvwsx);
340         LOAD_VSX_XFORM_TEST(lxvl);
341         LOAD_VSX_XFORM_TEST(lxvll);
342         STORE_VMX_DFORM_TEST(stxsd);
343         STORE_VSX_XFORM_TEST(stxsibx);
344         STORE_VSX_XFORM_TEST(stxsihx);
345         STORE_VMX_DFORM_TEST(stxssp);
346         STORE_VSX_DFORM_TEST(stxv);
347         STORE_VSX_XFORM_TEST(stxvb16x);
348         STORE_VSX_XFORM_TEST(stxvh8x);
349         STORE_VSX_XFORM_TEST(stxvx);
350         STORE_VSX_XFORM_TEST(stxvl);
351         STORE_VSX_XFORM_TEST(stxvll);
352         return rc;
353 }
354
355 int test_alignment_handler_integer(void)
356 {
357         int rc = 0;
358
359         SKIP_IF(!can_open_fb0());
360
361         printf("Integer\n");
362         LOAD_DFORM_TEST(lbz);
363         LOAD_DFORM_TEST(lbzu);
364         LOAD_XFORM_TEST(lbzx);
365         LOAD_XFORM_TEST(lbzux);
366         LOAD_DFORM_TEST(lhz);
367         LOAD_DFORM_TEST(lhzu);
368         LOAD_XFORM_TEST(lhzx);
369         LOAD_XFORM_TEST(lhzux);
370         LOAD_DFORM_TEST(lha);
371         LOAD_DFORM_TEST(lhau);
372         LOAD_XFORM_TEST(lhax);
373         LOAD_XFORM_TEST(lhaux);
374         LOAD_XFORM_TEST(lhbrx);
375         LOAD_DFORM_TEST(lwz);
376         LOAD_DFORM_TEST(lwzu);
377         LOAD_XFORM_TEST(lwzx);
378         LOAD_XFORM_TEST(lwzux);
379         LOAD_DFORM_TEST(lwa);
380         LOAD_XFORM_TEST(lwax);
381         LOAD_XFORM_TEST(lwaux);
382         LOAD_XFORM_TEST(lwbrx);
383         LOAD_DFORM_TEST(ld);
384         LOAD_DFORM_TEST(ldu);
385         LOAD_XFORM_TEST(ldx);
386         LOAD_XFORM_TEST(ldux);
387         STORE_DFORM_TEST(stb);
388         STORE_XFORM_TEST(stbx);
389         STORE_DFORM_TEST(stbu);
390         STORE_XFORM_TEST(stbux);
391         STORE_DFORM_TEST(sth);
392         STORE_XFORM_TEST(sthx);
393         STORE_DFORM_TEST(sthu);
394         STORE_XFORM_TEST(sthux);
395         STORE_XFORM_TEST(sthbrx);
396         STORE_DFORM_TEST(stw);
397         STORE_XFORM_TEST(stwx);
398         STORE_DFORM_TEST(stwu);
399         STORE_XFORM_TEST(stwux);
400         STORE_XFORM_TEST(stwbrx);
401         STORE_DFORM_TEST(std);
402         STORE_XFORM_TEST(stdx);
403         STORE_DFORM_TEST(stdu);
404         STORE_XFORM_TEST(stdux);
405
406 #ifdef __BIG_ENDIAN__
407         LOAD_DFORM_TEST(lmw);
408         STORE_DFORM_TEST(stmw);
409 #endif
410
411         return rc;
412 }
413
414 int test_alignment_handler_integer_206(void)
415 {
416         int rc = 0;
417
418         SKIP_IF(!can_open_fb0());
419         SKIP_IF(!have_hwcap(PPC_FEATURE_ARCH_2_06));
420
421         printf("Integer: 2.06\n");
422
423         LOAD_XFORM_TEST(ldbrx);
424         STORE_XFORM_TEST(stdbrx);
425
426         return rc;
427 }
428
429 int test_alignment_handler_vmx(void)
430 {
431         int rc = 0;
432
433         SKIP_IF(!can_open_fb0());
434         SKIP_IF(!have_hwcap(PPC_FEATURE_HAS_ALTIVEC));
435
436         printf("VMX\n");
437         LOAD_VMX_XFORM_TEST(lvx);
438
439         /*
440          * FIXME: These loads only load part of the register, so our
441          * testing method doesn't work. Also they don't take alignment
442          * faults, so it's kinda pointless anyway
443          *
444          LOAD_VMX_XFORM_TEST(lvebx)
445          LOAD_VMX_XFORM_TEST(lvehx)
446          LOAD_VMX_XFORM_TEST(lvewx)
447          LOAD_VMX_XFORM_TEST(lvxl)
448         */
449         STORE_VMX_XFORM_TEST(stvx);
450         STORE_VMX_XFORM_TEST(stvebx);
451         STORE_VMX_XFORM_TEST(stvehx);
452         STORE_VMX_XFORM_TEST(stvewx);
453         STORE_VMX_XFORM_TEST(stvxl);
454         return rc;
455 }
456
457 int test_alignment_handler_fp(void)
458 {
459         int rc = 0;
460
461         SKIP_IF(!can_open_fb0());
462
463         printf("Floating point\n");
464         LOAD_FLOAT_DFORM_TEST(lfd);
465         LOAD_FLOAT_XFORM_TEST(lfdx);
466         LOAD_FLOAT_DFORM_TEST(lfdu);
467         LOAD_FLOAT_XFORM_TEST(lfdux);
468         LOAD_FLOAT_DFORM_TEST(lfs);
469         LOAD_FLOAT_XFORM_TEST(lfsx);
470         LOAD_FLOAT_DFORM_TEST(lfsu);
471         LOAD_FLOAT_XFORM_TEST(lfsux);
472         STORE_FLOAT_DFORM_TEST(stfd);
473         STORE_FLOAT_XFORM_TEST(stfdx);
474         STORE_FLOAT_DFORM_TEST(stfdu);
475         STORE_FLOAT_XFORM_TEST(stfdux);
476         STORE_FLOAT_DFORM_TEST(stfs);
477         STORE_FLOAT_XFORM_TEST(stfsx);
478         STORE_FLOAT_DFORM_TEST(stfsu);
479         STORE_FLOAT_XFORM_TEST(stfsux);
480         STORE_FLOAT_XFORM_TEST(stfiwx);
481
482         return rc;
483 }
484
485 int test_alignment_handler_fp_205(void)
486 {
487         int rc = 0;
488
489         SKIP_IF(!can_open_fb0());
490         SKIP_IF(!have_hwcap(PPC_FEATURE_ARCH_2_05));
491
492         printf("Floating point: 2.05\n");
493
494         LOAD_FLOAT_DFORM_TEST(lfdp);
495         LOAD_FLOAT_XFORM_TEST(lfdpx);
496         LOAD_FLOAT_XFORM_TEST(lfiwax);
497         STORE_FLOAT_DFORM_TEST(stfdp);
498         STORE_FLOAT_XFORM_TEST(stfdpx);
499
500         return rc;
501 }
502
503 int test_alignment_handler_fp_206(void)
504 {
505         int rc = 0;
506
507         SKIP_IF(!can_open_fb0());
508         SKIP_IF(!have_hwcap(PPC_FEATURE_ARCH_2_06));
509
510         printf("Floating point: 2.06\n");
511
512         LOAD_FLOAT_XFORM_TEST(lfiwzx);
513
514         return rc;
515 }
516
517 void usage(char *prog)
518 {
519         printf("Usage: %s [options]\n", prog);
520         printf("  -d    Enable debug error output\n");
521         printf("\n");
522         printf("This test requires a POWER8 or POWER9 CPU and a usable ");
523         printf("framebuffer at /dev/fb0.\n");
524 }
525
526 int main(int argc, char *argv[])
527 {
528
529         struct sigaction sa;
530         int rc = 0;
531         int option = 0;
532
533         while ((option = getopt(argc, argv, "d")) != -1) {
534                 switch (option) {
535                 case 'd':
536                         debug++;
537                         break;
538                 default:
539                         usage(argv[0]);
540                         exit(1);
541                 }
542         }
543
544         bufsize = getpagesize();
545
546         sa.sa_sigaction = sighandler;
547         sigemptyset(&sa.sa_mask);
548         sa.sa_flags = SA_SIGINFO;
549         if (sigaction(SIGSEGV, &sa, NULL) == -1
550             || sigaction(SIGBUS, &sa, NULL) == -1
551             || sigaction(SIGILL, &sa, NULL) == -1) {
552                 perror("sigaction");
553                 exit(1);
554         }
555
556         rc |= test_harness(test_alignment_handler_vsx_206,
557                            "test_alignment_handler_vsx_206");
558         rc |= test_harness(test_alignment_handler_vsx_207,
559                            "test_alignment_handler_vsx_207");
560         rc |= test_harness(test_alignment_handler_vsx_300,
561                            "test_alignment_handler_vsx_300");
562         rc |= test_harness(test_alignment_handler_integer,
563                            "test_alignment_handler_integer");
564         rc |= test_harness(test_alignment_handler_integer_206,
565                            "test_alignment_handler_integer_206");
566         rc |= test_harness(test_alignment_handler_vmx,
567                            "test_alignment_handler_vmx");
568         rc |= test_harness(test_alignment_handler_fp,
569                            "test_alignment_handler_fp");
570         rc |= test_harness(test_alignment_handler_fp_205,
571                            "test_alignment_handler_fp_205");
572         rc |= test_harness(test_alignment_handler_fp_206,
573                            "test_alignment_handler_fp_206");
574         return rc;
575 }