linux/tools/testing/selftests/powerpc/alignment/alignment_handler.c
<<
>>
Prefs
   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
  56int bufsize;
  57int debug;
  58int testing;
  59volatile int gotsig;
  60
  61void 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 */
 120void 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
 131int 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
 156void 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
 171int 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 */
 195int 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        /*
 234         * offset = 0 is aligned but tests the workaround for the P9N
 235         * DD2.1 vector CI load issue (see 5080332c2c89 "powerpc/64s:
 236         * Add workaround for P9 vector CI load issue")
 237         */
 238        for (offset = 0; offset < 16; offset++) {
 239                width = 16; /* vsx == 16 bytes */
 240                r = 0;
 241
 242                /* load pattern into memory byte by byte */
 243                preload_data(ci0, offset, width);
 244                preload_data(mem0, offset, width); // FIXME: remove??
 245                memcpy(ci0, mem0, bufsize);
 246                memcpy(ci1, mem1, bufsize); /* initialise output to the same */
 247
 248                /* sanity check */
 249                test_memcmp(mem0, ci0, width, offset, test_name);
 250
 251                r |= test_memcpy(ci1,  ci0,  width, offset, test_func);
 252                r |= test_memcpy(mem1, mem0, width, offset, test_func);
 253                if (r && !debug) {
 254                        printf("FAILED: Got signal");
 255                        rc = 1;
 256                        break;
 257                }
 258
 259                r |= test_memcmp(mem1, ci1, width, offset, test_name);
 260                if (r && !debug) {
 261                        printf("FAILED: Wrong Data");
 262                        rc = 1;
 263                        break;
 264                }
 265        }
 266
 267        if (rc == 0)
 268                printf("PASSED");
 269
 270        printf("\n");
 271
 272        munmap(ci0, bufsize);
 273        munmap(ci1, bufsize);
 274        free(mem0);
 275        free(mem1);
 276        close(fd);
 277
 278        return rc;
 279}
 280
 281static bool can_open_fb0(void)
 282{
 283        int fd;
 284
 285        fd = open("/dev/fb0", O_RDWR);
 286        if (fd < 0)
 287                return false;
 288
 289        close(fd);
 290        return true;
 291}
 292
 293int test_alignment_handler_vsx_206(void)
 294{
 295        int rc = 0;
 296
 297        SKIP_IF(!can_open_fb0());
 298        SKIP_IF(!have_hwcap(PPC_FEATURE_ARCH_2_06));
 299
 300        printf("VSX: 2.06B\n");
 301        LOAD_VSX_XFORM_TEST(lxvd2x);
 302        LOAD_VSX_XFORM_TEST(lxvw4x);
 303        LOAD_VSX_XFORM_TEST(lxsdx);
 304        LOAD_VSX_XFORM_TEST(lxvdsx);
 305        STORE_VSX_XFORM_TEST(stxvd2x);
 306        STORE_VSX_XFORM_TEST(stxvw4x);
 307        STORE_VSX_XFORM_TEST(stxsdx);
 308        return rc;
 309}
 310
 311int test_alignment_handler_vsx_207(void)
 312{
 313        int rc = 0;
 314
 315        SKIP_IF(!can_open_fb0());
 316        SKIP_IF(!have_hwcap2(PPC_FEATURE2_ARCH_2_07));
 317
 318        printf("VSX: 2.07B\n");
 319        LOAD_VSX_XFORM_TEST(lxsspx);
 320        LOAD_VSX_XFORM_TEST(lxsiwax);
 321        LOAD_VSX_XFORM_TEST(lxsiwzx);
 322        STORE_VSX_XFORM_TEST(stxsspx);
 323        STORE_VSX_XFORM_TEST(stxsiwx);
 324        return rc;
 325}
 326
 327int test_alignment_handler_vsx_300(void)
 328{
 329        int rc = 0;
 330
 331        SKIP_IF(!can_open_fb0());
 332
 333        SKIP_IF(!have_hwcap2(PPC_FEATURE2_ARCH_3_00));
 334        printf("VSX: 3.00B\n");
 335        LOAD_VMX_DFORM_TEST(lxsd);
 336        LOAD_VSX_XFORM_TEST(lxsibzx);
 337        LOAD_VSX_XFORM_TEST(lxsihzx);
 338        LOAD_VMX_DFORM_TEST(lxssp);
 339        LOAD_VSX_DFORM_TEST(lxv);
 340        LOAD_VSX_XFORM_TEST(lxvb16x);
 341        LOAD_VSX_XFORM_TEST(lxvh8x);
 342        LOAD_VSX_XFORM_TEST(lxvx);
 343        LOAD_VSX_XFORM_TEST(lxvwsx);
 344        LOAD_VSX_XFORM_TEST(lxvl);
 345        LOAD_VSX_XFORM_TEST(lxvll);
 346        STORE_VMX_DFORM_TEST(stxsd);
 347        STORE_VSX_XFORM_TEST(stxsibx);
 348        STORE_VSX_XFORM_TEST(stxsihx);
 349        STORE_VMX_DFORM_TEST(stxssp);
 350        STORE_VSX_DFORM_TEST(stxv);
 351        STORE_VSX_XFORM_TEST(stxvb16x);
 352        STORE_VSX_XFORM_TEST(stxvh8x);
 353        STORE_VSX_XFORM_TEST(stxvx);
 354        STORE_VSX_XFORM_TEST(stxvl);
 355        STORE_VSX_XFORM_TEST(stxvll);
 356        return rc;
 357}
 358
 359int test_alignment_handler_integer(void)
 360{
 361        int rc = 0;
 362
 363        SKIP_IF(!can_open_fb0());
 364
 365        printf("Integer\n");
 366        LOAD_DFORM_TEST(lbz);
 367        LOAD_DFORM_TEST(lbzu);
 368        LOAD_XFORM_TEST(lbzx);
 369        LOAD_XFORM_TEST(lbzux);
 370        LOAD_DFORM_TEST(lhz);
 371        LOAD_DFORM_TEST(lhzu);
 372        LOAD_XFORM_TEST(lhzx);
 373        LOAD_XFORM_TEST(lhzux);
 374        LOAD_DFORM_TEST(lha);
 375        LOAD_DFORM_TEST(lhau);
 376        LOAD_XFORM_TEST(lhax);
 377        LOAD_XFORM_TEST(lhaux);
 378        LOAD_XFORM_TEST(lhbrx);
 379        LOAD_DFORM_TEST(lwz);
 380        LOAD_DFORM_TEST(lwzu);
 381        LOAD_XFORM_TEST(lwzx);
 382        LOAD_XFORM_TEST(lwzux);
 383        LOAD_DFORM_TEST(lwa);
 384        LOAD_XFORM_TEST(lwax);
 385        LOAD_XFORM_TEST(lwaux);
 386        LOAD_XFORM_TEST(lwbrx);
 387        LOAD_DFORM_TEST(ld);
 388        LOAD_DFORM_TEST(ldu);
 389        LOAD_XFORM_TEST(ldx);
 390        LOAD_XFORM_TEST(ldux);
 391        LOAD_DFORM_TEST(lmw);
 392        STORE_DFORM_TEST(stb);
 393        STORE_XFORM_TEST(stbx);
 394        STORE_DFORM_TEST(stbu);
 395        STORE_XFORM_TEST(stbux);
 396        STORE_DFORM_TEST(sth);
 397        STORE_XFORM_TEST(sthx);
 398        STORE_DFORM_TEST(sthu);
 399        STORE_XFORM_TEST(sthux);
 400        STORE_XFORM_TEST(sthbrx);
 401        STORE_DFORM_TEST(stw);
 402        STORE_XFORM_TEST(stwx);
 403        STORE_DFORM_TEST(stwu);
 404        STORE_XFORM_TEST(stwux);
 405        STORE_XFORM_TEST(stwbrx);
 406        STORE_DFORM_TEST(std);
 407        STORE_XFORM_TEST(stdx);
 408        STORE_DFORM_TEST(stdu);
 409        STORE_XFORM_TEST(stdux);
 410        STORE_DFORM_TEST(stmw);
 411
 412        return rc;
 413}
 414
 415int test_alignment_handler_integer_206(void)
 416{
 417        int rc = 0;
 418
 419        SKIP_IF(!can_open_fb0());
 420        SKIP_IF(!have_hwcap(PPC_FEATURE_ARCH_2_06));
 421
 422        printf("Integer: 2.06\n");
 423
 424        LOAD_XFORM_TEST(ldbrx);
 425        STORE_XFORM_TEST(stdbrx);
 426
 427        return rc;
 428}
 429
 430int test_alignment_handler_vmx(void)
 431{
 432        int rc = 0;
 433
 434        SKIP_IF(!can_open_fb0());
 435        SKIP_IF(!have_hwcap(PPC_FEATURE_HAS_ALTIVEC));
 436
 437        printf("VMX\n");
 438        LOAD_VMX_XFORM_TEST(lvx);
 439
 440        /*
 441         * FIXME: These loads only load part of the register, so our
 442         * testing method doesn't work. Also they don't take alignment
 443         * faults, so it's kinda pointless anyway
 444         *
 445         LOAD_VMX_XFORM_TEST(lvebx)
 446         LOAD_VMX_XFORM_TEST(lvehx)
 447         LOAD_VMX_XFORM_TEST(lvewx)
 448         LOAD_VMX_XFORM_TEST(lvxl)
 449        */
 450        STORE_VMX_XFORM_TEST(stvx);
 451        STORE_VMX_XFORM_TEST(stvebx);
 452        STORE_VMX_XFORM_TEST(stvehx);
 453        STORE_VMX_XFORM_TEST(stvewx);
 454        STORE_VMX_XFORM_TEST(stvxl);
 455        return rc;
 456}
 457
 458int test_alignment_handler_fp(void)
 459{
 460        int rc = 0;
 461
 462        SKIP_IF(!can_open_fb0());
 463
 464        printf("Floating point\n");
 465        LOAD_FLOAT_DFORM_TEST(lfd);
 466        LOAD_FLOAT_XFORM_TEST(lfdx);
 467        LOAD_FLOAT_DFORM_TEST(lfdu);
 468        LOAD_FLOAT_XFORM_TEST(lfdux);
 469        LOAD_FLOAT_DFORM_TEST(lfs);
 470        LOAD_FLOAT_XFORM_TEST(lfsx);
 471        LOAD_FLOAT_DFORM_TEST(lfsu);
 472        LOAD_FLOAT_XFORM_TEST(lfsux);
 473        STORE_FLOAT_DFORM_TEST(stfd);
 474        STORE_FLOAT_XFORM_TEST(stfdx);
 475        STORE_FLOAT_DFORM_TEST(stfdu);
 476        STORE_FLOAT_XFORM_TEST(stfdux);
 477        STORE_FLOAT_DFORM_TEST(stfs);
 478        STORE_FLOAT_XFORM_TEST(stfsx);
 479        STORE_FLOAT_DFORM_TEST(stfsu);
 480        STORE_FLOAT_XFORM_TEST(stfsux);
 481        STORE_FLOAT_XFORM_TEST(stfiwx);
 482
 483        return rc;
 484}
 485
 486int test_alignment_handler_fp_205(void)
 487{
 488        int rc = 0;
 489
 490        SKIP_IF(!can_open_fb0());
 491        SKIP_IF(!have_hwcap(PPC_FEATURE_ARCH_2_05));
 492
 493        printf("Floating point: 2.05\n");
 494
 495        LOAD_FLOAT_DFORM_TEST(lfdp);
 496        LOAD_FLOAT_XFORM_TEST(lfdpx);
 497        LOAD_FLOAT_XFORM_TEST(lfiwax);
 498        STORE_FLOAT_DFORM_TEST(stfdp);
 499        STORE_FLOAT_XFORM_TEST(stfdpx);
 500
 501        return rc;
 502}
 503
 504int test_alignment_handler_fp_206(void)
 505{
 506        int rc = 0;
 507
 508        SKIP_IF(!can_open_fb0());
 509        SKIP_IF(!have_hwcap(PPC_FEATURE_ARCH_2_06));
 510
 511        printf("Floating point: 2.06\n");
 512
 513        LOAD_FLOAT_XFORM_TEST(lfiwzx);
 514
 515        return rc;
 516}
 517
 518void usage(char *prog)
 519{
 520        printf("Usage: %s [options]\n", prog);
 521        printf("  -d    Enable debug error output\n");
 522        printf("\n");
 523        printf("This test requires a POWER8 or POWER9 CPU and a usable ");
 524        printf("framebuffer at /dev/fb0.\n");
 525}
 526
 527int main(int argc, char *argv[])
 528{
 529
 530        struct sigaction sa;
 531        int rc = 0;
 532        int option = 0;
 533
 534        while ((option = getopt(argc, argv, "d")) != -1) {
 535                switch (option) {
 536                case 'd':
 537                        debug++;
 538                        break;
 539                default:
 540                        usage(argv[0]);
 541                        exit(1);
 542                }
 543        }
 544
 545        bufsize = getpagesize();
 546
 547        sa.sa_sigaction = sighandler;
 548        sigemptyset(&sa.sa_mask);
 549        sa.sa_flags = SA_SIGINFO;
 550        if (sigaction(SIGSEGV, &sa, NULL) == -1
 551            || sigaction(SIGBUS, &sa, NULL) == -1
 552            || sigaction(SIGILL, &sa, NULL) == -1) {
 553                perror("sigaction");
 554                exit(1);
 555        }
 556
 557        rc |= test_harness(test_alignment_handler_vsx_206,
 558                           "test_alignment_handler_vsx_206");
 559        rc |= test_harness(test_alignment_handler_vsx_207,
 560                           "test_alignment_handler_vsx_207");
 561        rc |= test_harness(test_alignment_handler_vsx_300,
 562                           "test_alignment_handler_vsx_300");
 563        rc |= test_harness(test_alignment_handler_integer,
 564                           "test_alignment_handler_integer");
 565        rc |= test_harness(test_alignment_handler_integer_206,
 566                           "test_alignment_handler_integer_206");
 567        rc |= test_harness(test_alignment_handler_vmx,
 568                           "test_alignment_handler_vmx");
 569        rc |= test_harness(test_alignment_handler_fp,
 570                           "test_alignment_handler_fp");
 571        rc |= test_harness(test_alignment_handler_fp_205,
 572                           "test_alignment_handler_fp_205");
 573        rc |= test_harness(test_alignment_handler_fp_206,
 574                           "test_alignment_handler_fp_206");
 575        return rc;
 576}
 577