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