alignment_handler.c 13 KB

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