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 (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 | /* FIXME: Unimplemented tests: */ |
138 | // STORE_DFORM_TEST(stq) /* FIXME: need two registers for quad */ |
139 | // STORE_DFORM_TEST(stswi) /* FIXME: string instruction */ |
140 | |
141 | // STORE_XFORM_TEST(stwat) /* AMO can't emulate or run on CI */ |
142 | // STORE_XFORM_TEST(stdat) /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */ |
143 | |
144 | |
145 | /* preload byte by byte */ |
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); /* run the actual test */ |
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(s1: s1c, s2: 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; /* vsx == 16 bytes */ |
267 | r = 0; |
268 | |
269 | /* load pattern into memory byte by byte */ |
270 | preload_data(dst: ci0, offset, width); |
271 | preload_data(dst: mem0, offset, width); // FIXME: remove?? |
272 | memcpy(ci0, mem0, bufsize); |
273 | memcpy(ci1, mem1, bufsize); /* initialise output to the same */ |
274 | |
275 | /* sanity check */ |
276 | test_memcmp(s1: mem0, s2: ci0, n: width, offset, test_name); |
277 | |
278 | r |= test_memcpy(dst: ci1, src: ci0, size: width, offset, test_func); |
279 | r |= test_memcpy(dst: mem1, src: mem0, size: width, offset, test_func); |
280 | if (r && !debug) { |
281 | printf("FAILED: Got signal" ); |
282 | rc = 1; |
283 | break; |
284 | } |
285 | |
286 | r |= test_memcmp(s1: mem1, s2: ci1, n: 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(prog: 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 | } |
681 | |