1
2
3
4
5
6#include <assert.h>
7#include <errno.h>
8#include <fcntl.h>
9#include <stddef.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <unistd.h>
14#include <sys/auxv.h>
15#include <sys/prctl.h>
16#include <sys/types.h>
17#include <sys/wait.h>
18#include <asm/sigcontext.h>
19#include <asm/hwcap.h>
20
21#include "../../kselftest.h"
22#include "rdvl.h"
23
24#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
25
26#define ARCH_MIN_VL SVE_VL_MIN
27
28struct vec_data {
29 const char *name;
30 unsigned long hwcap_type;
31 unsigned long hwcap;
32 const char *rdvl_binary;
33 int (*rdvl)(void);
34
35 int prctl_get;
36 int prctl_set;
37 const char *default_vl_file;
38
39 int default_vl;
40 int min_vl;
41 int max_vl;
42};
43
44
45static struct vec_data vec_data[] = {
46 {
47 .name = "SVE",
48 .hwcap_type = AT_HWCAP,
49 .hwcap = HWCAP_SVE,
50 .rdvl = rdvl_sve,
51 .rdvl_binary = "./rdvl-sve",
52 .prctl_get = PR_SVE_GET_VL,
53 .prctl_set = PR_SVE_SET_VL,
54 .default_vl_file = "/proc/sys/abi/sve_default_vector_length",
55 },
56};
57
58static int stdio_read_integer(FILE *f, const char *what, int *val)
59{
60 int n = 0;
61 int ret;
62
63 ret = fscanf(f, "%d%*1[\n]%n", val, &n);
64 if (ret < 1 || n < 1) {
65 ksft_print_msg("failed to parse integer from %s\n", what);
66 return -1;
67 }
68
69 return 0;
70}
71
72
73static int get_child_rdvl(struct vec_data *data)
74{
75 FILE *out;
76 int pipefd[2];
77 pid_t pid, child;
78 int read_vl, ret;
79
80 ret = pipe(pipefd);
81 if (ret == -1) {
82 ksft_print_msg("pipe() failed: %d (%s)\n",
83 errno, strerror(errno));
84 return -1;
85 }
86
87 fflush(stdout);
88
89 child = fork();
90 if (child == -1) {
91 ksft_print_msg("fork() failed: %d (%s)\n",
92 errno, strerror(errno));
93 close(pipefd[0]);
94 close(pipefd[1]);
95 return -1;
96 }
97
98
99 if (child == 0) {
100
101
102
103
104 ret = dup2(pipefd[1], 1);
105 if (ret == -1) {
106 fprintf(stderr, "dup2() %d\n", errno);
107 exit(EXIT_FAILURE);
108 }
109
110
111 ret = execl(data->rdvl_binary, data->rdvl_binary, NULL);
112 fprintf(stderr, "execl(%s) failed: %d\n",
113 data->rdvl_binary, errno, strerror(errno));
114
115 exit(EXIT_FAILURE);
116 }
117
118 close(pipefd[1]);
119
120
121 do {
122 pid = wait(&ret);
123 if (pid == -1) {
124 ksft_print_msg("wait() failed: %d (%s)\n",
125 errno, strerror(errno));
126 close(pipefd[0]);
127 return -1;
128 }
129 } while (pid != child);
130
131 assert(pid == child);
132
133 if (!WIFEXITED(ret)) {
134 ksft_print_msg("child exited abnormally\n");
135 close(pipefd[0]);
136 return -1;
137 }
138
139 if (WEXITSTATUS(ret) != 0) {
140 ksft_print_msg("child returned error %d\n",
141 WEXITSTATUS(ret));
142 close(pipefd[0]);
143 return -1;
144 }
145
146 out = fdopen(pipefd[0], "r");
147 if (!out) {
148 ksft_print_msg("failed to open child stdout\n");
149 close(pipefd[0]);
150 return -1;
151 }
152
153 ret = stdio_read_integer(out, "child", &read_vl);
154 fclose(out);
155 if (ret != 0)
156 return ret;
157
158 return read_vl;
159}
160
161static int file_read_integer(const char *name, int *val)
162{
163 FILE *f;
164 int ret;
165
166 f = fopen(name, "r");
167 if (!f) {
168 ksft_test_result_fail("Unable to open %s: %d (%s)\n",
169 name, errno,
170 strerror(errno));
171 return -1;
172 }
173
174 ret = stdio_read_integer(f, name, val);
175 fclose(f);
176
177 return ret;
178}
179
180static int file_write_integer(const char *name, int val)
181{
182 FILE *f;
183 int ret;
184
185 f = fopen(name, "w");
186 if (!f) {
187 ksft_test_result_fail("Unable to open %s: %d (%s)\n",
188 name, errno,
189 strerror(errno));
190 return -1;
191 }
192
193 fprintf(f, "%d", val);
194 fclose(f);
195 if (ret < 0) {
196 ksft_test_result_fail("Error writing %d to %s\n",
197 val, name);
198 return -1;
199 }
200
201 return 0;
202}
203
204
205
206
207
208static void proc_read_default(struct vec_data *data)
209{
210 int default_vl, child_vl, ret;
211
212 ret = file_read_integer(data->default_vl_file, &default_vl);
213 if (ret != 0)
214 return;
215
216
217 child_vl = get_child_rdvl(data);
218 if (child_vl != default_vl) {
219 ksft_test_result_fail("%s is %d but child VL is %d\n",
220 data->default_vl_file,
221 default_vl, child_vl);
222 return;
223 }
224
225 ksft_test_result_pass("%s default vector length %d\n", data->name,
226 default_vl);
227 data->default_vl = default_vl;
228}
229
230
231static void proc_write_min(struct vec_data *data)
232{
233 int ret, new_default, child_vl;
234
235 if (geteuid() != 0) {
236 ksft_test_result_skip("Need to be root to write to /proc\n");
237 return;
238 }
239
240 ret = file_write_integer(data->default_vl_file, ARCH_MIN_VL);
241 if (ret != 0)
242 return;
243
244
245 ret = file_read_integer(data->default_vl_file, &new_default);
246 if (ret != 0)
247 return;
248
249
250 child_vl = get_child_rdvl(data);
251 if (child_vl != new_default) {
252 ksft_test_result_fail("%s is %d but child VL is %d\n",
253 data->default_vl_file,
254 new_default, child_vl);
255 return;
256 }
257
258 ksft_test_result_pass("%s minimum vector length %d\n", data->name,
259 new_default);
260 data->min_vl = new_default;
261
262 file_write_integer(data->default_vl_file, data->default_vl);
263}
264
265
266static void proc_write_max(struct vec_data *data)
267{
268 int ret, new_default, child_vl;
269
270 if (geteuid() != 0) {
271 ksft_test_result_skip("Need to be root to write to /proc\n");
272 return;
273 }
274
275
276 ret = file_write_integer(data->default_vl_file, -1);
277 if (ret != 0)
278 return;
279
280
281 ret = file_read_integer(data->default_vl_file, &new_default);
282 if (ret != 0)
283 return;
284
285
286 child_vl = get_child_rdvl(data);
287 if (child_vl != new_default) {
288 ksft_test_result_fail("%s is %d but child VL is %d\n",
289 data->default_vl_file,
290 new_default, child_vl);
291 return;
292 }
293
294 ksft_test_result_pass("%s maximum vector length %d\n", data->name,
295 new_default);
296 data->max_vl = new_default;
297
298 file_write_integer(data->default_vl_file, data->default_vl);
299}
300
301
302static void prctl_get(struct vec_data *data)
303{
304 int ret;
305
306 ret = prctl(data->prctl_get);
307 if (ret == -1) {
308 ksft_test_result_fail("%s prctl() read failed: %d (%s)\n",
309 data->name, errno, strerror(errno));
310 return;
311 }
312
313
314 ret &= PR_SVE_VL_LEN_MASK;
315
316
317 if (ret == data->rdvl())
318 ksft_test_result_pass("%s current VL is %d\n",
319 data->name, ret);
320 else
321 ksft_test_result_fail("%s prctl() VL %d but RDVL is %d\n",
322 data->name, ret, data->rdvl());
323}
324
325
326static void prctl_set_same(struct vec_data *data)
327{
328 int cur_vl = data->rdvl();
329 int ret;
330
331 ret = prctl(data->prctl_set, cur_vl);
332 if (ret < 0) {
333 ksft_test_result_fail("%s prctl set failed: %d (%s)\n",
334 data->name, errno, strerror(errno));
335 return;
336 }
337
338 if (cur_vl != data->rdvl())
339 ksft_test_result_pass("%s current VL is %d\n",
340 data->name, ret);
341 else
342 ksft_test_result_fail("%s prctl() VL %d but RDVL is %d\n",
343 data->name, ret, data->rdvl());
344}
345
346
347static void prctl_set(struct vec_data *data)
348{
349 int ret;
350
351 if (data->min_vl == data->max_vl) {
352 ksft_test_result_skip("%s only one VL supported\n",
353 data->name);
354 return;
355 }
356
357
358 ret = prctl(data->prctl_set, data->min_vl);
359 if (ret < 0) {
360 ksft_test_result_fail("%s prctl set failed for %d: %d (%s)\n",
361 data->name, data->min_vl,
362 errno, strerror(errno));
363 return;
364 }
365
366 if ((ret & PR_SVE_VL_LEN_MASK) != data->min_vl) {
367 ksft_test_result_fail("%s prctl set %d but return value is %d\n",
368 data->name, data->min_vl, data->rdvl());
369 return;
370 }
371
372 if (data->rdvl() != data->min_vl) {
373 ksft_test_result_fail("%s set %d but RDVL is %d\n",
374 data->name, data->min_vl, data->rdvl());
375 return;
376 }
377
378
379 ret = prctl(data->prctl_set, data->max_vl);
380 if (ret < 0) {
381 ksft_test_result_fail("%s prctl set failed for %d: %d (%s)\n",
382 data->name, data->max_vl,
383 errno, strerror(errno));
384 return;
385 }
386
387 if ((ret & PR_SVE_VL_LEN_MASK) != data->max_vl) {
388 ksft_test_result_fail("%s prctl() set %d but return value is %d\n",
389 data->name, data->max_vl, data->rdvl());
390 return;
391 }
392
393
394 ret = prctl(data->prctl_get);
395 if (ret == -1) {
396 ksft_test_result_fail("%s prctl() read failed: %d (%s)\n",
397 data->name, errno, strerror(errno));
398 return;
399 }
400
401 if (ret & PR_SVE_VL_INHERIT) {
402 ksft_test_result_fail("%s prctl() reports _INHERIT\n",
403 data->name);
404 return;
405 }
406
407 ksft_test_result_pass("%s prctl() set min/max\n", data->name);
408}
409
410
411static void prctl_set_no_child(struct vec_data *data)
412{
413 int ret, child_vl;
414
415 if (data->min_vl == data->max_vl) {
416 ksft_test_result_skip("%s only one VL supported\n",
417 data->name);
418 return;
419 }
420
421 ret = prctl(data->prctl_set, data->min_vl);
422 if (ret < 0) {
423 ksft_test_result_fail("%s prctl set failed for %d: %d (%s)\n",
424 data->name, data->min_vl,
425 errno, strerror(errno));
426 return;
427 }
428
429
430 ret = file_write_integer(data->default_vl_file, data->max_vl);
431 if (ret != 0)
432 return;
433
434
435 child_vl = get_child_rdvl(data);
436 if (child_vl != data->max_vl) {
437 ksft_test_result_fail("%s is %d but child VL is %d\n",
438 data->default_vl_file,
439 data->max_vl, child_vl);
440 return;
441 }
442
443 ksft_test_result_pass("%s vector length used default\n", data->name);
444
445 file_write_integer(data->default_vl_file, data->default_vl);
446}
447
448
449static void prctl_set_for_child(struct vec_data *data)
450{
451 int ret, child_vl;
452
453 if (data->min_vl == data->max_vl) {
454 ksft_test_result_skip("%s only one VL supported\n",
455 data->name);
456 return;
457 }
458
459 ret = prctl(data->prctl_set, data->min_vl | PR_SVE_VL_INHERIT);
460 if (ret < 0) {
461 ksft_test_result_fail("%s prctl set failed for %d: %d (%s)\n",
462 data->name, data->min_vl,
463 errno, strerror(errno));
464 return;
465 }
466
467
468 ret = prctl(data->prctl_get);
469 if (ret == -1) {
470 ksft_test_result_fail("%s prctl() read failed: %d (%s)\n",
471 data->name, errno, strerror(errno));
472 return;
473 }
474 if (!(ret & PR_SVE_VL_INHERIT)) {
475 ksft_test_result_fail("%s prctl() does not report _INHERIT\n",
476 data->name);
477 return;
478 }
479
480
481 ret = file_write_integer(data->default_vl_file, data->max_vl);
482 if (ret != 0)
483 return;
484
485
486 child_vl = get_child_rdvl(data);
487 if (child_vl != data->min_vl) {
488 ksft_test_result_fail("%s is %d but child VL is %d\n",
489 data->default_vl_file,
490 data->min_vl, child_vl);
491 return;
492 }
493
494 ksft_test_result_pass("%s vector length was inherited\n", data->name);
495
496 file_write_integer(data->default_vl_file, data->default_vl);
497}
498
499
500static void prctl_set_onexec(struct vec_data *data)
501{
502 int ret, child_vl;
503
504 if (data->min_vl == data->max_vl) {
505 ksft_test_result_skip("%s only one VL supported\n",
506 data->name);
507 return;
508 }
509
510
511 ret = file_write_integer(data->default_vl_file, data->max_vl);
512 if (ret != 0)
513 return;
514
515 ret = prctl(data->prctl_set, data->max_vl);
516 if (ret < 0) {
517 ksft_test_result_fail("%s prctl set failed for %d: %d (%s)\n",
518 data->name, data->min_vl,
519 errno, strerror(errno));
520 return;
521 }
522
523
524 ret = prctl(data->prctl_set, data->min_vl | PR_SVE_SET_VL_ONEXEC);
525 if (ret < 0) {
526 ksft_test_result_fail("%s prctl set failed for %d: %d (%s)\n",
527 data->name, data->min_vl,
528 errno, strerror(errno));
529 return;
530 }
531
532
533 if (data->rdvl() != data->max_vl) {
534 ksft_test_result_fail("%s VL changed by _ONEXEC prctl()\n",
535 data->name);
536 return;
537 }
538
539
540 child_vl = get_child_rdvl(data);
541 if (child_vl != data->min_vl) {
542 ksft_test_result_fail("Set %d _ONEXEC but child VL is %d\n",
543 data->min_vl, child_vl);
544 return;
545 }
546
547 ksft_test_result_pass("%s vector length set on exec\n", data->name);
548
549 file_write_integer(data->default_vl_file, data->default_vl);
550}
551
552typedef void (*test_type)(struct vec_data *);
553
554static const test_type tests[] = {
555
556
557
558
559 proc_read_default,
560 proc_write_min,
561 proc_write_max,
562
563 prctl_get,
564 prctl_set,
565 prctl_set_no_child,
566 prctl_set_for_child,
567 prctl_set_onexec,
568};
569
570int main(void)
571{
572 int i, j;
573
574 ksft_print_header();
575 ksft_set_plan(ARRAY_SIZE(tests) * ARRAY_SIZE(vec_data));
576
577 for (i = 0; i < ARRAY_SIZE(vec_data); i++) {
578 struct vec_data *data = &vec_data[i];
579 unsigned long supported;
580
581 supported = getauxval(data->hwcap_type) & data->hwcap;
582
583 for (j = 0; j < ARRAY_SIZE(tests); j++) {
584 if (supported)
585 tests[j](data);
586 else
587 ksft_test_result_skip("%s not supported\n",
588 data->name);
589 }
590 }
591
592 ksft_exit_pass();
593}
594