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 <stdio.h> 44 #include <stdlib.h> 45 #include <string.h> 46 #include <assert.h> 47 #include <getopt.h> 48 #include <setjmp.h> 49 #include <signal.h> 50 51 #include "utils.h" 52 53 int bufsize; 54 int debug; 55 int testing; 56 volatile int gotsig; 57 58 void sighandler(int sig, siginfo_t *info, void *ctx) 59 { 60 ucontext_t *ucp = ctx; 61 62 if (!testing) { 63 signal(sig, SIG_DFL); 64 kill(0, sig); 65 } 66 gotsig = sig; 67 #ifdef __powerpc64__ 68 ucp->uc_mcontext.gp_regs[PT_NIP] += 4; 69 #else 70 ucp->uc_mcontext.uc_regs->gregs[PT_NIP] += 4; 71 #endif 72 } 73 74 #define XFORM(reg, n) " " #reg " ,%"#n",%2 ;" 75 #define DFORM(reg, n) " " #reg " ,0(%"#n") ;" 76 77 #define TEST(name, ld_op, st_op, form, ld_reg, st_reg) \ 78 void test_##name(char *s, char *d) \ 79 { \ 80 asm volatile( \ 81 #ld_op form(ld_reg, 0) \ 82 #st_op form(st_reg, 1) \ 83 :: "r"(s), "r"(d), "r"(0) \ 84 : "memory", "vs0", "vs32", "r31"); \ 85 } \ 86 rc |= do_test(#name, test_##name) 87 88 #define LOAD_VSX_XFORM_TEST(op) TEST(op, op, stxvd2x, XFORM, 32, 32) 89 #define STORE_VSX_XFORM_TEST(op) TEST(op, lxvd2x, op, XFORM, 32, 32) 90 #define LOAD_VSX_DFORM_TEST(op) TEST(op, op, stxv, DFORM, 32, 32) 91 #define STORE_VSX_DFORM_TEST(op) TEST(op, lxv, op, DFORM, 32, 32) 92 #define LOAD_VMX_XFORM_TEST(op) TEST(op, op, stxvd2x, XFORM, 0, 32) 93 #define STORE_VMX_XFORM_TEST(op) TEST(op, lxvd2x, op, XFORM, 32, 0) 94 #define LOAD_VMX_DFORM_TEST(op) TEST(op, op, stxv, DFORM, 0, 32) 95 #define STORE_VMX_DFORM_TEST(op) TEST(op, lxv, op, DFORM, 32, 0) 96 97 #define LOAD_XFORM_TEST(op) TEST(op, op, stdx, XFORM, 31, 31) 98 #define STORE_XFORM_TEST(op) TEST(op, ldx, op, XFORM, 31, 31) 99 #define LOAD_DFORM_TEST(op) TEST(op, op, std, DFORM, 31, 31) 100 #define STORE_DFORM_TEST(op) TEST(op, ld, op, DFORM, 31, 31) 101 102 #define LOAD_FLOAT_DFORM_TEST(op) TEST(op, op, stfd, DFORM, 0, 0) 103 #define STORE_FLOAT_DFORM_TEST(op) TEST(op, lfd, op, DFORM, 0, 0) 104 #define LOAD_FLOAT_XFORM_TEST(op) TEST(op, op, stfdx, XFORM, 0, 0) 105 #define STORE_FLOAT_XFORM_TEST(op) TEST(op, lfdx, op, XFORM, 0, 0) 106 107 108 /* FIXME: Unimplemented tests: */ 109 // STORE_DFORM_TEST(stq) /* FIXME: need two registers for quad */ 110 // STORE_DFORM_TEST(stswi) /* FIXME: string instruction */ 111 112 // STORE_XFORM_TEST(stwat) /* AMO can't emulate or run on CI */ 113 // STORE_XFORM_TEST(stdat) /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */ 114 115 116 /* preload byte by byte */ 117 void preload_data(void *dst, int offset, int width) 118 { 119 char *c = dst; 120 int i; 121 122 c += offset; 123 124 for (i = 0 ; i < width ; i++) 125 c[i] = i; 126 } 127 128 int test_memcpy(void *dst, void *src, int size, int offset, 129 void (*test_func)(char *, char *)) 130 { 131 char *s, *d; 132 133 s = src; 134 s += offset; 135 d = dst; 136 d += offset; 137 138 assert(size == 16); 139 gotsig = 0; 140 testing = 1; 141 142 test_func(s, d); /* run the actual test */ 143 144 testing = 0; 145 if (gotsig) { 146 if (debug) 147 printf(" Got signal %i\n", gotsig); 148 return 1; 149 } 150 return 0; 151 } 152 153 void dumpdata(char *s1, char *s2, int n, char *test_name) 154 { 155 int i; 156 157 printf(" %s: unexpected result:\n", test_name); 158 printf(" mem:"); 159 for (i = 0; i < n; i++) 160 printf(" %02x", s1[i]); 161 printf("\n"); 162 printf(" ci: "); 163 for (i = 0; i < n; i++) 164 printf(" %02x", s2[i]); 165 printf("\n"); 166 } 167 168 int test_memcmp(void *s1, void *s2, int n, int offset, char *test_name) 169 { 170 char *s1c, *s2c; 171 172 s1c = s1; 173 s1c += offset; 174 s2c = s2; 175 s2c += offset; 176 177 if (memcmp(s1c, s2c, n)) { 178 if (debug) { 179 printf("\n Compare failed. Offset:%i length:%i\n", 180 offset, n); 181 dumpdata(s1c, s2c, n, test_name); 182 } 183 return 1; 184 } 185 return 0; 186 } 187 188 /* 189 * Do two memcpy tests using the same instructions. One cachable 190 * memory and the other doesn't. 191 */ 192 int do_test(char *test_name, void (*test_func)(char *, char *)) 193 { 194 int offset, width, fd, rc = 0, r; 195 void *mem0, *mem1, *ci0, *ci1; 196 197 printf("\tDoing %s:\t", test_name); 198 199 fd = open("/dev/fb0", O_RDWR); 200 if (fd < 0) { 201 printf("\n"); 202 perror("Can't open /dev/fb0"); 203 SKIP_IF(1); 204 } 205 206 ci0 = mmap(NULL, bufsize, PROT_WRITE, MAP_SHARED, 207 fd, 0x0); 208 ci1 = mmap(NULL, bufsize, PROT_WRITE, MAP_SHARED, 209 fd, bufsize); 210 if ((ci0 == MAP_FAILED) || (ci1 == MAP_FAILED)) { 211 printf("\n"); 212 perror("mmap failed"); 213 SKIP_IF(1); 214 } 215 216 rc = posix_memalign(&mem0, bufsize, bufsize); 217 if (rc) { 218 printf("\n"); 219 return rc; 220 } 221 222 rc = posix_memalign(&mem1, bufsize, bufsize); 223 if (rc) { 224 printf("\n"); 225 free(mem0); 226 return rc; 227 } 228 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 break; 248 } 249 250 r |= test_memcmp(mem1, ci1, width, offset, test_name); 251 rc |= r; 252 if (r && !debug) { 253 printf("FAILED: Wrong Data"); 254 break; 255 } 256 } 257 if (!r) 258 printf("PASSED"); 259 printf("\n"); 260 261 munmap(ci0, bufsize); 262 munmap(ci1, bufsize); 263 free(mem0); 264 free(mem1); 265 266 return rc; 267 } 268 269 int test_alignment_handler_vsx_206(void) 270 { 271 int rc = 0; 272 273 printf("VSX: 2.06B\n"); 274 LOAD_VSX_XFORM_TEST(lxvd2x); 275 LOAD_VSX_XFORM_TEST(lxvw4x); 276 LOAD_VSX_XFORM_TEST(lxsdx); 277 LOAD_VSX_XFORM_TEST(lxvdsx); 278 STORE_VSX_XFORM_TEST(stxvd2x); 279 STORE_VSX_XFORM_TEST(stxvw4x); 280 STORE_VSX_XFORM_TEST(stxsdx); 281 return rc; 282 } 283 284 int test_alignment_handler_vsx_207(void) 285 { 286 int rc = 0; 287 288 printf("VSX: 2.07B\n"); 289 LOAD_VSX_XFORM_TEST(lxsspx); 290 LOAD_VSX_XFORM_TEST(lxsiwax); 291 LOAD_VSX_XFORM_TEST(lxsiwzx); 292 STORE_VSX_XFORM_TEST(stxsspx); 293 STORE_VSX_XFORM_TEST(stxsiwx); 294 return rc; 295 } 296 297 int test_alignment_handler_vsx_300(void) 298 { 299 int rc = 0; 300 301 SKIP_IF(!have_hwcap2(PPC_FEATURE2_ARCH_3_00)); 302 printf("VSX: 3.00B\n"); 303 LOAD_VMX_DFORM_TEST(lxsd); 304 LOAD_VSX_XFORM_TEST(lxsibzx); 305 LOAD_VSX_XFORM_TEST(lxsihzx); 306 LOAD_VMX_DFORM_TEST(lxssp); 307 LOAD_VSX_DFORM_TEST(lxv); 308 LOAD_VSX_XFORM_TEST(lxvb16x); 309 LOAD_VSX_XFORM_TEST(lxvh8x); 310 LOAD_VSX_XFORM_TEST(lxvx); 311 LOAD_VSX_XFORM_TEST(lxvwsx); 312 LOAD_VSX_XFORM_TEST(lxvl); 313 LOAD_VSX_XFORM_TEST(lxvll); 314 STORE_VMX_DFORM_TEST(stxsd); 315 STORE_VSX_XFORM_TEST(stxsibx); 316 STORE_VSX_XFORM_TEST(stxsihx); 317 STORE_VMX_DFORM_TEST(stxssp); 318 STORE_VSX_DFORM_TEST(stxv); 319 STORE_VSX_XFORM_TEST(stxvb16x); 320 STORE_VSX_XFORM_TEST(stxvh8x); 321 STORE_VSX_XFORM_TEST(stxvx); 322 STORE_VSX_XFORM_TEST(stxvl); 323 STORE_VSX_XFORM_TEST(stxvll); 324 return rc; 325 } 326 327 int test_alignment_handler_integer(void) 328 { 329 int rc = 0; 330 331 printf("Integer\n"); 332 LOAD_DFORM_TEST(lbz); 333 LOAD_DFORM_TEST(lbzu); 334 LOAD_XFORM_TEST(lbzx); 335 LOAD_XFORM_TEST(lbzux); 336 LOAD_DFORM_TEST(lhz); 337 LOAD_DFORM_TEST(lhzu); 338 LOAD_XFORM_TEST(lhzx); 339 LOAD_XFORM_TEST(lhzux); 340 LOAD_DFORM_TEST(lha); 341 LOAD_DFORM_TEST(lhau); 342 LOAD_XFORM_TEST(lhax); 343 LOAD_XFORM_TEST(lhaux); 344 LOAD_XFORM_TEST(lhbrx); 345 LOAD_DFORM_TEST(lwz); 346 LOAD_DFORM_TEST(lwzu); 347 LOAD_XFORM_TEST(lwzx); 348 LOAD_XFORM_TEST(lwzux); 349 LOAD_DFORM_TEST(lwa); 350 LOAD_XFORM_TEST(lwax); 351 LOAD_XFORM_TEST(lwaux); 352 LOAD_XFORM_TEST(lwbrx); 353 LOAD_DFORM_TEST(ld); 354 LOAD_DFORM_TEST(ldu); 355 LOAD_XFORM_TEST(ldx); 356 LOAD_XFORM_TEST(ldux); 357 LOAD_XFORM_TEST(ldbrx); 358 LOAD_DFORM_TEST(lmw); 359 STORE_DFORM_TEST(stb); 360 STORE_XFORM_TEST(stbx); 361 STORE_DFORM_TEST(stbu); 362 STORE_XFORM_TEST(stbux); 363 STORE_DFORM_TEST(sth); 364 STORE_XFORM_TEST(sthx); 365 STORE_DFORM_TEST(sthu); 366 STORE_XFORM_TEST(sthux); 367 STORE_XFORM_TEST(sthbrx); 368 STORE_DFORM_TEST(stw); 369 STORE_XFORM_TEST(stwx); 370 STORE_DFORM_TEST(stwu); 371 STORE_XFORM_TEST(stwux); 372 STORE_XFORM_TEST(stwbrx); 373 STORE_DFORM_TEST(std); 374 STORE_XFORM_TEST(stdx); 375 STORE_DFORM_TEST(stdu); 376 STORE_XFORM_TEST(stdux); 377 STORE_XFORM_TEST(stdbrx); 378 STORE_DFORM_TEST(stmw); 379 return rc; 380 } 381 382 int test_alignment_handler_vmx(void) 383 { 384 int rc = 0; 385 386 printf("VMX\n"); 387 LOAD_VMX_XFORM_TEST(lvx); 388 389 /* 390 * FIXME: These loads only load part of the register, so our 391 * testing method doesn't work. Also they don't take alignment 392 * faults, so it's kinda pointless anyway 393 * 394 LOAD_VMX_XFORM_TEST(lvebx) 395 LOAD_VMX_XFORM_TEST(lvehx) 396 LOAD_VMX_XFORM_TEST(lvewx) 397 LOAD_VMX_XFORM_TEST(lvxl) 398 */ 399 STORE_VMX_XFORM_TEST(stvx); 400 STORE_VMX_XFORM_TEST(stvebx); 401 STORE_VMX_XFORM_TEST(stvehx); 402 STORE_VMX_XFORM_TEST(stvewx); 403 STORE_VMX_XFORM_TEST(stvxl); 404 return rc; 405 } 406 407 int test_alignment_handler_fp(void) 408 { 409 int rc = 0; 410 411 printf("Floating point\n"); 412 LOAD_FLOAT_DFORM_TEST(lfd); 413 LOAD_FLOAT_XFORM_TEST(lfdx); 414 LOAD_FLOAT_DFORM_TEST(lfdp); 415 LOAD_FLOAT_XFORM_TEST(lfdpx); 416 LOAD_FLOAT_DFORM_TEST(lfdu); 417 LOAD_FLOAT_XFORM_TEST(lfdux); 418 LOAD_FLOAT_DFORM_TEST(lfs); 419 LOAD_FLOAT_XFORM_TEST(lfsx); 420 LOAD_FLOAT_DFORM_TEST(lfsu); 421 LOAD_FLOAT_XFORM_TEST(lfsux); 422 LOAD_FLOAT_XFORM_TEST(lfiwzx); 423 LOAD_FLOAT_XFORM_TEST(lfiwax); 424 STORE_FLOAT_DFORM_TEST(stfd); 425 STORE_FLOAT_XFORM_TEST(stfdx); 426 STORE_FLOAT_DFORM_TEST(stfdp); 427 STORE_FLOAT_XFORM_TEST(stfdpx); 428 STORE_FLOAT_DFORM_TEST(stfdu); 429 STORE_FLOAT_XFORM_TEST(stfdux); 430 STORE_FLOAT_DFORM_TEST(stfs); 431 STORE_FLOAT_XFORM_TEST(stfsx); 432 STORE_FLOAT_DFORM_TEST(stfsu); 433 STORE_FLOAT_XFORM_TEST(stfsux); 434 STORE_FLOAT_XFORM_TEST(stfiwx); 435 436 return rc; 437 } 438 439 void usage(char *prog) 440 { 441 printf("Usage: %s [options]\n", prog); 442 printf(" -d Enable debug error output\n"); 443 printf("\n"); 444 printf("This test requires a POWER8 or POWER9 CPU and a usable "); 445 printf("framebuffer at /dev/fb0.\n"); 446 } 447 448 int main(int argc, char *argv[]) 449 { 450 451 struct sigaction sa; 452 int rc = 0; 453 int option = 0; 454 455 while ((option = getopt(argc, argv, "d")) != -1) { 456 switch (option) { 457 case 'd': 458 debug++; 459 break; 460 default: 461 usage(argv[0]); 462 exit(1); 463 } 464 } 465 466 bufsize = getpagesize(); 467 468 sa.sa_sigaction = sighandler; 469 sigemptyset(&sa.sa_mask); 470 sa.sa_flags = SA_SIGINFO; 471 if (sigaction(SIGSEGV, &sa, NULL) == -1 472 || sigaction(SIGBUS, &sa, NULL) == -1 473 || sigaction(SIGILL, &sa, NULL) == -1) { 474 perror("sigaction"); 475 exit(1); 476 } 477 478 rc |= test_harness(test_alignment_handler_vsx_206, 479 "test_alignment_handler_vsx_206"); 480 rc |= test_harness(test_alignment_handler_vsx_207, 481 "test_alignment_handler_vsx_207"); 482 rc |= test_harness(test_alignment_handler_vsx_300, 483 "test_alignment_handler_vsx_300"); 484 rc |= test_harness(test_alignment_handler_integer, 485 "test_alignment_handler_integer"); 486 rc |= test_harness(test_alignment_handler_vmx, 487 "test_alignment_handler_vmx"); 488 rc |= test_harness(test_alignment_handler_fp, 489 "test_alignment_handler_fp"); 490 return rc; 491 } 492