~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/powerpc/alignment/alignment_handler.c

Version: ~ [ linux-5.15-rc1 ] ~ [ linux-5.14.5 ] ~ [ linux-5.13.18 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.66 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.147 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.206 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.246 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.282 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.283 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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         LOAD_DFORM_TEST(lmw);
388         STORE_DFORM_TEST(stb);
389         STORE_XFORM_TEST(stbx);
390         STORE_DFORM_TEST(stbu);
391         STORE_XFORM_TEST(stbux);
392         STORE_DFORM_TEST(sth);
393         STORE_XFORM_TEST(sthx);
394         STORE_DFORM_TEST(sthu);
395         STORE_XFORM_TEST(sthux);
396         STORE_XFORM_TEST(sthbrx);
397         STORE_DFORM_TEST(stw);
398         STORE_XFORM_TEST(stwx);
399         STORE_DFORM_TEST(stwu);
400         STORE_XFORM_TEST(stwux);
401         STORE_XFORM_TEST(stwbrx);
402         STORE_DFORM_TEST(std);
403         STORE_XFORM_TEST(stdx);
404         STORE_DFORM_TEST(stdu);
405         STORE_XFORM_TEST(stdux);
406         STORE_DFORM_TEST(stmw);
407 
408         return rc;
409 }
410 
411 int test_alignment_handler_integer_206(void)
412 {
413         int rc = 0;
414 
415         SKIP_IF(!can_open_fb0());
416         SKIP_IF(!have_hwcap(PPC_FEATURE_ARCH_2_06));
417 
418         printf("Integer: 2.06\n");
419 
420         LOAD_XFORM_TEST(ldbrx);
421         STORE_XFORM_TEST(stdbrx);
422 
423         return rc;
424 }
425 
426 int test_alignment_handler_vmx(void)
427 {
428         int rc = 0;
429 
430         SKIP_IF(!can_open_fb0());
431         SKIP_IF(!have_hwcap(PPC_FEATURE_HAS_ALTIVEC));
432 
433         printf("VMX\n");
434         LOAD_VMX_XFORM_TEST(lvx);
435 
436         /*
437          * FIXME: These loads only load part of the register, so our
438          * testing method doesn't work. Also they don't take alignment
439          * faults, so it's kinda pointless anyway
440          *
441          LOAD_VMX_XFORM_TEST(lvebx)
442          LOAD_VMX_XFORM_TEST(lvehx)
443          LOAD_VMX_XFORM_TEST(lvewx)
444          LOAD_VMX_XFORM_TEST(lvxl)
445         */
446         STORE_VMX_XFORM_TEST(stvx);
447         STORE_VMX_XFORM_TEST(stvebx);
448         STORE_VMX_XFORM_TEST(stvehx);
449         STORE_VMX_XFORM_TEST(stvewx);
450         STORE_VMX_XFORM_TEST(stvxl);
451         return rc;
452 }
453 
454 int test_alignment_handler_fp(void)
455 {
456         int rc = 0;
457 
458         SKIP_IF(!can_open_fb0());
459 
460         printf("Floating point\n");
461         LOAD_FLOAT_DFORM_TEST(lfd);
462         LOAD_FLOAT_XFORM_TEST(lfdx);
463         LOAD_FLOAT_DFORM_TEST(lfdu);
464         LOAD_FLOAT_XFORM_TEST(lfdux);
465         LOAD_FLOAT_DFORM_TEST(lfs);
466         LOAD_FLOAT_XFORM_TEST(lfsx);
467         LOAD_FLOAT_DFORM_TEST(lfsu);
468         LOAD_FLOAT_XFORM_TEST(lfsux);
469         STORE_FLOAT_DFORM_TEST(stfd);
470         STORE_FLOAT_XFORM_TEST(stfdx);
471         STORE_FLOAT_DFORM_TEST(stfdu);
472         STORE_FLOAT_XFORM_TEST(stfdux);
473         STORE_FLOAT_DFORM_TEST(stfs);
474         STORE_FLOAT_XFORM_TEST(stfsx);
475         STORE_FLOAT_DFORM_TEST(stfsu);
476         STORE_FLOAT_XFORM_TEST(stfsux);
477         STORE_FLOAT_XFORM_TEST(stfiwx);
478 
479         return rc;
480 }
481 
482 int test_alignment_handler_fp_205(void)
483 {
484         int rc = 0;
485 
486         SKIP_IF(!can_open_fb0());
487         SKIP_IF(!have_hwcap(PPC_FEATURE_ARCH_2_05));
488 
489         printf("Floating point: 2.05\n");
490 
491         LOAD_FLOAT_DFORM_TEST(lfdp);
492         LOAD_FLOAT_XFORM_TEST(lfdpx);
493         LOAD_FLOAT_XFORM_TEST(lfiwax);
494         STORE_FLOAT_DFORM_TEST(stfdp);
495         STORE_FLOAT_XFORM_TEST(stfdpx);
496 
497         return rc;
498 }
499 
500 int test_alignment_handler_fp_206(void)
501 {
502         int rc = 0;
503 
504         SKIP_IF(!can_open_fb0());
505         SKIP_IF(!have_hwcap(PPC_FEATURE_ARCH_2_06));
506 
507         printf("Floating point: 2.06\n");
508 
509         LOAD_FLOAT_XFORM_TEST(lfiwzx);
510 
511         return rc;
512 }
513 
514 void usage(char *prog)
515 {
516         printf("Usage: %s [options]\n", prog);
517         printf("  -d    Enable debug error output\n");
518         printf("\n");
519         printf("This test requires a POWER8 or POWER9 CPU and a usable ");
520         printf("framebuffer at /dev/fb0.\n");
521 }
522 
523 int main(int argc, char *argv[])
524 {
525 
526         struct sigaction sa;
527         int rc = 0;
528         int option = 0;
529 
530         while ((option = getopt(argc, argv, "d")) != -1) {
531                 switch (option) {
532                 case 'd':
533                         debug++;
534                         break;
535                 default:
536                         usage(argv[0]);
537                         exit(1);
538                 }
539         }
540 
541         bufsize = getpagesize();
542 
543         sa.sa_sigaction = sighandler;
544         sigemptyset(&sa.sa_mask);
545         sa.sa_flags = SA_SIGINFO;
546         if (sigaction(SIGSEGV, &sa, NULL) == -1
547             || sigaction(SIGBUS, &sa, NULL) == -1
548             || sigaction(SIGILL, &sa, NULL) == -1) {
549                 perror("sigaction");
550                 exit(1);
551         }
552 
553         rc |= test_harness(test_alignment_handler_vsx_206,
554                            "test_alignment_handler_vsx_206");
555         rc |= test_harness(test_alignment_handler_vsx_207,
556                            "test_alignment_handler_vsx_207");
557         rc |= test_harness(test_alignment_handler_vsx_300,
558                            "test_alignment_handler_vsx_300");
559         rc |= test_harness(test_alignment_handler_integer,
560                            "test_alignment_handler_integer");
561         rc |= test_harness(test_alignment_handler_integer_206,
562                            "test_alignment_handler_integer_206");
563         rc |= test_harness(test_alignment_handler_vmx,
564                            "test_alignment_handler_vmx");
565         rc |= test_harness(test_alignment_handler_fp,
566                            "test_alignment_handler_fp");
567         rc |= test_harness(test_alignment_handler_fp_205,
568                            "test_alignment_handler_fp_205");
569         rc |= test_harness(test_alignment_handler_fp_206,
570                            "test_alignment_handler_fp_206");
571         return rc;
572 }
573 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp