1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (C) 2021 ARM Limited.
4 */
5
6 #include <errno.h>
7 #include <stdbool.h>
8 #include <stddef.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <unistd.h>
13 #include <sys/auxv.h>
14 #include <sys/prctl.h>
15 #include <asm/hwcap.h>
16 #include <asm/sigcontext.h>
17 #include <asm/unistd.h>
18
19 #include "../../kselftest.h"
20
21 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
22 #define NUM_VL ((SVE_VQ_MAX - SVE_VQ_MIN) + 1)
23
24 extern void do_syscall(int sve_vl);
25
fill_random(void * buf,size_t size)26 static void fill_random(void *buf, size_t size)
27 {
28 int i;
29 uint32_t *lbuf = buf;
30
31 /* random() returns a 32 bit number regardless of the size of long */
32 for (i = 0; i < size / sizeof(uint32_t); i++)
33 lbuf[i] = random();
34 }
35
36 /*
37 * We also repeat the test for several syscalls to try to expose different
38 * behaviour.
39 */
40 static struct syscall_cfg {
41 int syscall_nr;
42 const char *name;
43 } syscalls[] = {
44 { __NR_getpid, "getpid()" },
45 { __NR_sched_yield, "sched_yield()" },
46 };
47
48 #define NUM_GPR 31
49 uint64_t gpr_in[NUM_GPR];
50 uint64_t gpr_out[NUM_GPR];
51
setup_gpr(struct syscall_cfg * cfg,int sve_vl)52 static void setup_gpr(struct syscall_cfg *cfg, int sve_vl)
53 {
54 fill_random(gpr_in, sizeof(gpr_in));
55 gpr_in[8] = cfg->syscall_nr;
56 memset(gpr_out, 0, sizeof(gpr_out));
57 }
58
check_gpr(struct syscall_cfg * cfg,int sve_vl)59 static int check_gpr(struct syscall_cfg *cfg, int sve_vl)
60 {
61 int errors = 0;
62 int i;
63
64 /*
65 * GPR x0-x7 may be clobbered, and all others should be preserved.
66 */
67 for (i = 9; i < ARRAY_SIZE(gpr_in); i++) {
68 if (gpr_in[i] != gpr_out[i]) {
69 ksft_print_msg("%s SVE VL %d mismatch in GPR %d: %llx != %llx\n",
70 cfg->name, sve_vl, i,
71 gpr_in[i], gpr_out[i]);
72 errors++;
73 }
74 }
75
76 return errors;
77 }
78
79 #define NUM_FPR 32
80 uint64_t fpr_in[NUM_FPR * 2];
81 uint64_t fpr_out[NUM_FPR * 2];
82
setup_fpr(struct syscall_cfg * cfg,int sve_vl)83 static void setup_fpr(struct syscall_cfg *cfg, int sve_vl)
84 {
85 fill_random(fpr_in, sizeof(fpr_in));
86 memset(fpr_out, 0, sizeof(fpr_out));
87 }
88
check_fpr(struct syscall_cfg * cfg,int sve_vl)89 static int check_fpr(struct syscall_cfg *cfg, int sve_vl)
90 {
91 int errors = 0;
92 int i;
93
94 if (!sve_vl) {
95 for (i = 0; i < ARRAY_SIZE(fpr_in); i++) {
96 if (fpr_in[i] != fpr_out[i]) {
97 ksft_print_msg("%s Q%d/%d mismatch %llx != %llx\n",
98 cfg->name,
99 i / 2, i % 2,
100 fpr_in[i], fpr_out[i]);
101 errors++;
102 }
103 }
104 }
105
106 return errors;
107 }
108
109 static uint8_t z_zero[__SVE_ZREG_SIZE(SVE_VQ_MAX)];
110 uint8_t z_in[SVE_NUM_PREGS * __SVE_ZREG_SIZE(SVE_VQ_MAX)];
111 uint8_t z_out[SVE_NUM_PREGS * __SVE_ZREG_SIZE(SVE_VQ_MAX)];
112
setup_z(struct syscall_cfg * cfg,int sve_vl)113 static void setup_z(struct syscall_cfg *cfg, int sve_vl)
114 {
115 fill_random(z_in, sizeof(z_in));
116 fill_random(z_out, sizeof(z_out));
117 }
118
check_z(struct syscall_cfg * cfg,int sve_vl)119 static int check_z(struct syscall_cfg *cfg, int sve_vl)
120 {
121 size_t reg_size = sve_vl;
122 int errors = 0;
123 int i;
124
125 if (!sve_vl)
126 return 0;
127
128 /*
129 * After a syscall the low 128 bits of the Z registers should
130 * be preserved and the rest be zeroed or preserved.
131 */
132 for (i = 0; i < SVE_NUM_ZREGS; i++) {
133 void *in = &z_in[reg_size * i];
134 void *out = &z_out[reg_size * i];
135
136 if (memcmp(in, out, SVE_VQ_BYTES) != 0) {
137 ksft_print_msg("%s SVE VL %d Z%d low 128 bits changed\n",
138 cfg->name, sve_vl, i);
139 errors++;
140 }
141 }
142
143 return errors;
144 }
145
146 uint8_t p_in[SVE_NUM_PREGS * __SVE_PREG_SIZE(SVE_VQ_MAX)];
147 uint8_t p_out[SVE_NUM_PREGS * __SVE_PREG_SIZE(SVE_VQ_MAX)];
148
setup_p(struct syscall_cfg * cfg,int sve_vl)149 static void setup_p(struct syscall_cfg *cfg, int sve_vl)
150 {
151 fill_random(p_in, sizeof(p_in));
152 fill_random(p_out, sizeof(p_out));
153 }
154
check_p(struct syscall_cfg * cfg,int sve_vl)155 static int check_p(struct syscall_cfg *cfg, int sve_vl)
156 {
157 size_t reg_size = sve_vq_from_vl(sve_vl) * 2; /* 1 bit per VL byte */
158
159 int errors = 0;
160 int i;
161
162 if (!sve_vl)
163 return 0;
164
165 /* After a syscall the P registers should be preserved or zeroed */
166 for (i = 0; i < SVE_NUM_PREGS * reg_size; i++)
167 if (p_out[i] && (p_in[i] != p_out[i]))
168 errors++;
169 if (errors)
170 ksft_print_msg("%s SVE VL %d predicate registers non-zero\n",
171 cfg->name, sve_vl);
172
173 return errors;
174 }
175
176 uint8_t ffr_in[__SVE_PREG_SIZE(SVE_VQ_MAX)];
177 uint8_t ffr_out[__SVE_PREG_SIZE(SVE_VQ_MAX)];
178
setup_ffr(struct syscall_cfg * cfg,int sve_vl)179 static void setup_ffr(struct syscall_cfg *cfg, int sve_vl)
180 {
181 /*
182 * It is only valid to set a contiguous set of bits starting
183 * at 0. For now since we're expecting this to be cleared by
184 * a syscall just set all bits.
185 */
186 memset(ffr_in, 0xff, sizeof(ffr_in));
187 fill_random(ffr_out, sizeof(ffr_out));
188 }
189
check_ffr(struct syscall_cfg * cfg,int sve_vl)190 static int check_ffr(struct syscall_cfg *cfg, int sve_vl)
191 {
192 size_t reg_size = sve_vq_from_vl(sve_vl) * 2; /* 1 bit per VL byte */
193 int errors = 0;
194 int i;
195
196 if (!sve_vl)
197 return 0;
198
199 /* After a syscall the P registers should be preserved or zeroed */
200 for (i = 0; i < reg_size; i++)
201 if (ffr_out[i] && (ffr_in[i] != ffr_out[i]))
202 errors++;
203 if (errors)
204 ksft_print_msg("%s SVE VL %d FFR non-zero\n",
205 cfg->name, sve_vl);
206
207 return errors;
208 }
209
210 typedef void (*setup_fn)(struct syscall_cfg *cfg, int sve_vl);
211 typedef int (*check_fn)(struct syscall_cfg *cfg, int sve_vl);
212
213 /*
214 * Each set of registers has a setup function which is called before
215 * the syscall to fill values in a global variable for loading by the
216 * test code and a check function which validates that the results are
217 * as expected. Vector lengths are passed everywhere, a vector length
218 * of 0 should be treated as do not test.
219 */
220 static struct {
221 setup_fn setup;
222 check_fn check;
223 } regset[] = {
224 { setup_gpr, check_gpr },
225 { setup_fpr, check_fpr },
226 { setup_z, check_z },
227 { setup_p, check_p },
228 { setup_ffr, check_ffr },
229 };
230
do_test(struct syscall_cfg * cfg,int sve_vl)231 static bool do_test(struct syscall_cfg *cfg, int sve_vl)
232 {
233 int errors = 0;
234 int i;
235
236 for (i = 0; i < ARRAY_SIZE(regset); i++)
237 regset[i].setup(cfg, sve_vl);
238
239 do_syscall(sve_vl);
240
241 for (i = 0; i < ARRAY_SIZE(regset); i++)
242 errors += regset[i].check(cfg, sve_vl);
243
244 return errors == 0;
245 }
246
test_one_syscall(struct syscall_cfg * cfg)247 static void test_one_syscall(struct syscall_cfg *cfg)
248 {
249 int sve_vq, sve_vl;
250
251 /* FPSIMD only case */
252 ksft_test_result(do_test(cfg, 0),
253 "%s FPSIMD\n", cfg->name);
254
255 if (!(getauxval(AT_HWCAP) & HWCAP_SVE))
256 return;
257
258 for (sve_vq = SVE_VQ_MAX; sve_vq > 0; --sve_vq) {
259 sve_vl = prctl(PR_SVE_SET_VL, sve_vq * 16);
260 if (sve_vl == -1)
261 ksft_exit_fail_msg("PR_SVE_SET_VL failed: %s (%d)\n",
262 strerror(errno), errno);
263
264 sve_vl &= PR_SVE_VL_LEN_MASK;
265
266 if (sve_vq != sve_vq_from_vl(sve_vl))
267 sve_vq = sve_vq_from_vl(sve_vl);
268
269 ksft_test_result(do_test(cfg, sve_vl),
270 "%s SVE VL %d\n", cfg->name, sve_vl);
271 }
272 }
273
sve_count_vls(void)274 int sve_count_vls(void)
275 {
276 unsigned int vq;
277 int vl_count = 0;
278 int vl;
279
280 if (!(getauxval(AT_HWCAP) & HWCAP_SVE))
281 return 0;
282
283 /*
284 * Enumerate up to SVE_VQ_MAX vector lengths
285 */
286 for (vq = SVE_VQ_MAX; vq > 0; --vq) {
287 vl = prctl(PR_SVE_SET_VL, vq * 16);
288 if (vl == -1)
289 ksft_exit_fail_msg("PR_SVE_SET_VL failed: %s (%d)\n",
290 strerror(errno), errno);
291
292 vl &= PR_SVE_VL_LEN_MASK;
293
294 if (vq != sve_vq_from_vl(vl))
295 vq = sve_vq_from_vl(vl);
296
297 vl_count++;
298 }
299
300 return vl_count;
301 }
302
main(void)303 int main(void)
304 {
305 int i;
306
307 srandom(getpid());
308
309 ksft_print_header();
310 ksft_set_plan(ARRAY_SIZE(syscalls) * (sve_count_vls() + 1));
311
312 for (i = 0; i < ARRAY_SIZE(syscalls); i++)
313 test_one_syscall(&syscalls[i]);
314
315 ksft_print_cnts();
316
317 return 0;
318 }
319