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