1
2
3
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
24extern void do_syscall(int sve_vl);
25
26static void fill_random(void *buf, size_t size)
27{
28 int i;
29 uint32_t *lbuf = buf;
30
31
32 for (i = 0; i < size / sizeof(uint32_t); i++)
33 lbuf[i] = random();
34}
35
36
37
38
39
40static 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
49uint64_t gpr_in[NUM_GPR];
50uint64_t gpr_out[NUM_GPR];
51
52static 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
59static int check_gpr(struct syscall_cfg *cfg, int sve_vl)
60{
61 int errors = 0;
62 int i;
63
64
65
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
80uint64_t fpr_in[NUM_FPR * 2];
81uint64_t fpr_out[NUM_FPR * 2];
82
83static 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
89static 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
109static uint8_t z_zero[__SVE_ZREG_SIZE(SVE_VQ_MAX)];
110uint8_t z_in[SVE_NUM_PREGS * __SVE_ZREG_SIZE(SVE_VQ_MAX)];
111uint8_t z_out[SVE_NUM_PREGS * __SVE_ZREG_SIZE(SVE_VQ_MAX)];
112
113static 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
119static 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
130
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
146uint8_t p_in[SVE_NUM_PREGS * __SVE_PREG_SIZE(SVE_VQ_MAX)];
147uint8_t p_out[SVE_NUM_PREGS * __SVE_PREG_SIZE(SVE_VQ_MAX)];
148
149static 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
155static int check_p(struct syscall_cfg *cfg, int sve_vl)
156{
157 size_t reg_size = sve_vq_from_vl(sve_vl) * 2;
158
159 int errors = 0;
160 int i;
161
162 if (!sve_vl)
163 return 0;
164
165
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
176uint8_t ffr_in[__SVE_PREG_SIZE(SVE_VQ_MAX)];
177uint8_t ffr_out[__SVE_PREG_SIZE(SVE_VQ_MAX)];
178
179static void setup_ffr(struct syscall_cfg *cfg, int sve_vl)
180{
181
182
183
184
185
186 memset(ffr_in, 0xff, sizeof(ffr_in));
187 fill_random(ffr_out, sizeof(ffr_out));
188}
189
190static int check_ffr(struct syscall_cfg *cfg, int sve_vl)
191{
192 size_t reg_size = sve_vq_from_vl(sve_vl) * 2;
193 int errors = 0;
194 int i;
195
196 if (!sve_vl)
197 return 0;
198
199
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
210typedef void (*setup_fn)(struct syscall_cfg *cfg, int sve_vl);
211typedef int (*check_fn)(struct syscall_cfg *cfg, int sve_vl);
212
213
214
215
216
217
218
219
220static 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
231static 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
247static void test_one_syscall(struct syscall_cfg *cfg)
248{
249 int sve_vq, sve_vl;
250
251
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
274int 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
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
303int 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