root/tools/testing/selftests/powerpc/alignment/alignment_handler.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sighandler
  2. preload_data
  3. test_memcpy
  4. dumpdata
  5. test_memcmp
  6. do_test
  7. can_open_fb0
  8. test_alignment_handler_vsx_206
  9. test_alignment_handler_vsx_207
  10. test_alignment_handler_vsx_300
  11. test_alignment_handler_integer
  12. test_alignment_handler_integer_206
  13. test_alignment_handler_vmx
  14. test_alignment_handler_fp
  15. test_alignment_handler_fp_205
  16. test_alignment_handler_fp_206
  17. usage
  18. main

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

/* [<][>][^][v][top][bottom][index][help] */