linux/tools/testing/selftests/powerpc/alignment/alignment_handler.c
<<
>>
Prefs
   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
  52int bufsize;
  53int debug;
  54int testing;
  55volatile int gotsig;
  56
  57void 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 */
 116void 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
 127int 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
 152void 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
 167int 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 */
 191int 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
 273static 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
 285int 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
 303int 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
 319int 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
 351int 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
 407int 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
 422int 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
 450int 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
 478int 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
 496int 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
 510void 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
 519int 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}
 569