1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (C) 2021 ARM Limited.
4 * Original author: Mark Brown <broonie@kernel.org>
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
28 struct 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
45 static 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
stdio_read_integer(FILE * f,const char * what,int * val)58 static 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 /* Start a new process and return the vector length it sees */
get_child_rdvl(struct vec_data * data)73 static 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 /* Child: put vector length on the pipe */
99 if (child == 0) {
100 /*
101 * Replace stdout with the pipe, errors to stderr from
102 * here as kselftest prints to stdout.
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 /* exec() a new binary which puts the VL on stdout */
111 ret = execl(data->rdvl_binary, data->rdvl_binary, NULL);
112 fprintf(stderr, "execl(%s) failed: %d (%s)\n",
113 data->rdvl_binary, errno, strerror(errno));
114
115 exit(EXIT_FAILURE);
116 }
117
118 close(pipefd[1]);
119
120 /* Parent; wait for the exit status from the child & verify it */
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
file_read_integer(const char * name,int * val)161 static 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
file_write_integer(const char * name,int val)180 static int file_write_integer(const char *name, int val)
181 {
182 FILE *f;
183
184 f = fopen(name, "w");
185 if (!f) {
186 ksft_test_result_fail("Unable to open %s: %d (%s)\n",
187 name, errno,
188 strerror(errno));
189 return -1;
190 }
191
192 fprintf(f, "%d", val);
193 fclose(f);
194
195 return 0;
196 }
197
198 /*
199 * Verify that we can read the default VL via proc, checking that it
200 * is set in a freshly spawned child.
201 */
proc_read_default(struct vec_data * data)202 static void proc_read_default(struct vec_data *data)
203 {
204 int default_vl, child_vl, ret;
205
206 ret = file_read_integer(data->default_vl_file, &default_vl);
207 if (ret != 0)
208 return;
209
210 /* Is this the actual default seen by new processes? */
211 child_vl = get_child_rdvl(data);
212 if (child_vl != default_vl) {
213 ksft_test_result_fail("%s is %d but child VL is %d\n",
214 data->default_vl_file,
215 default_vl, child_vl);
216 return;
217 }
218
219 ksft_test_result_pass("%s default vector length %d\n", data->name,
220 default_vl);
221 data->default_vl = default_vl;
222 }
223
224 /* Verify that we can write a minimum value and have it take effect */
proc_write_min(struct vec_data * data)225 static void proc_write_min(struct vec_data *data)
226 {
227 int ret, new_default, child_vl;
228
229 if (geteuid() != 0) {
230 ksft_test_result_skip("Need to be root to write to /proc\n");
231 return;
232 }
233
234 ret = file_write_integer(data->default_vl_file, ARCH_MIN_VL);
235 if (ret != 0)
236 return;
237
238 /* What was the new value? */
239 ret = file_read_integer(data->default_vl_file, &new_default);
240 if (ret != 0)
241 return;
242
243 /* Did it take effect in a new process? */
244 child_vl = get_child_rdvl(data);
245 if (child_vl != new_default) {
246 ksft_test_result_fail("%s is %d but child VL is %d\n",
247 data->default_vl_file,
248 new_default, child_vl);
249 return;
250 }
251
252 ksft_test_result_pass("%s minimum vector length %d\n", data->name,
253 new_default);
254 data->min_vl = new_default;
255
256 file_write_integer(data->default_vl_file, data->default_vl);
257 }
258
259 /* Verify that we can write a maximum value and have it take effect */
proc_write_max(struct vec_data * data)260 static void proc_write_max(struct vec_data *data)
261 {
262 int ret, new_default, child_vl;
263
264 if (geteuid() != 0) {
265 ksft_test_result_skip("Need to be root to write to /proc\n");
266 return;
267 }
268
269 /* -1 is accepted by the /proc interface as the maximum VL */
270 ret = file_write_integer(data->default_vl_file, -1);
271 if (ret != 0)
272 return;
273
274 /* What was the new value? */
275 ret = file_read_integer(data->default_vl_file, &new_default);
276 if (ret != 0)
277 return;
278
279 /* Did it take effect in a new process? */
280 child_vl = get_child_rdvl(data);
281 if (child_vl != new_default) {
282 ksft_test_result_fail("%s is %d but child VL is %d\n",
283 data->default_vl_file,
284 new_default, child_vl);
285 return;
286 }
287
288 ksft_test_result_pass("%s maximum vector length %d\n", data->name,
289 new_default);
290 data->max_vl = new_default;
291
292 file_write_integer(data->default_vl_file, data->default_vl);
293 }
294
295 /* Can we read back a VL from prctl? */
prctl_get(struct vec_data * data)296 static void prctl_get(struct vec_data *data)
297 {
298 int ret;
299
300 ret = prctl(data->prctl_get);
301 if (ret == -1) {
302 ksft_test_result_fail("%s prctl() read failed: %d (%s)\n",
303 data->name, errno, strerror(errno));
304 return;
305 }
306
307 /* Mask out any flags */
308 ret &= PR_SVE_VL_LEN_MASK;
309
310 /* Is that what we can read back directly? */
311 if (ret == data->rdvl())
312 ksft_test_result_pass("%s current VL is %d\n",
313 data->name, ret);
314 else
315 ksft_test_result_fail("%s prctl() VL %d but RDVL is %d\n",
316 data->name, ret, data->rdvl());
317 }
318
319 /* Does the prctl let us set the VL we already have? */
prctl_set_same(struct vec_data * data)320 static void prctl_set_same(struct vec_data *data)
321 {
322 int cur_vl = data->rdvl();
323 int ret;
324
325 ret = prctl(data->prctl_set, cur_vl);
326 if (ret < 0) {
327 ksft_test_result_fail("%s prctl set failed: %d (%s)\n",
328 data->name, errno, strerror(errno));
329 return;
330 }
331
332 ksft_test_result(cur_vl == data->rdvl(),
333 "%s set VL %d and have VL %d\n",
334 data->name, cur_vl, data->rdvl());
335 }
336
337 /* Can we set a new VL for this process? */
prctl_set(struct vec_data * data)338 static void prctl_set(struct vec_data *data)
339 {
340 int ret;
341
342 if (data->min_vl == data->max_vl) {
343 ksft_test_result_skip("%s only one VL supported\n",
344 data->name);
345 return;
346 }
347
348 /* Try to set the minimum VL */
349 ret = prctl(data->prctl_set, data->min_vl);
350 if (ret < 0) {
351 ksft_test_result_fail("%s prctl set failed for %d: %d (%s)\n",
352 data->name, data->min_vl,
353 errno, strerror(errno));
354 return;
355 }
356
357 if ((ret & PR_SVE_VL_LEN_MASK) != data->min_vl) {
358 ksft_test_result_fail("%s prctl set %d but return value is %d\n",
359 data->name, data->min_vl, data->rdvl());
360 return;
361 }
362
363 if (data->rdvl() != data->min_vl) {
364 ksft_test_result_fail("%s set %d but RDVL is %d\n",
365 data->name, data->min_vl, data->rdvl());
366 return;
367 }
368
369 /* Try to set the maximum VL */
370 ret = prctl(data->prctl_set, data->max_vl);
371 if (ret < 0) {
372 ksft_test_result_fail("%s prctl set failed for %d: %d (%s)\n",
373 data->name, data->max_vl,
374 errno, strerror(errno));
375 return;
376 }
377
378 if ((ret & PR_SVE_VL_LEN_MASK) != data->max_vl) {
379 ksft_test_result_fail("%s prctl() set %d but return value is %d\n",
380 data->name, data->max_vl, data->rdvl());
381 return;
382 }
383
384 /* The _INHERIT flag should not be present when we read the VL */
385 ret = prctl(data->prctl_get);
386 if (ret == -1) {
387 ksft_test_result_fail("%s prctl() read failed: %d (%s)\n",
388 data->name, errno, strerror(errno));
389 return;
390 }
391
392 if (ret & PR_SVE_VL_INHERIT) {
393 ksft_test_result_fail("%s prctl() reports _INHERIT\n",
394 data->name);
395 return;
396 }
397
398 ksft_test_result_pass("%s prctl() set min/max\n", data->name);
399 }
400
401 /* If we didn't request it a new VL shouldn't affect the child */
prctl_set_no_child(struct vec_data * data)402 static void prctl_set_no_child(struct vec_data *data)
403 {
404 int ret, child_vl;
405
406 if (data->min_vl == data->max_vl) {
407 ksft_test_result_skip("%s only one VL supported\n",
408 data->name);
409 return;
410 }
411
412 ret = prctl(data->prctl_set, data->min_vl);
413 if (ret < 0) {
414 ksft_test_result_fail("%s prctl set failed for %d: %d (%s)\n",
415 data->name, data->min_vl,
416 errno, strerror(errno));
417 return;
418 }
419
420 /* Ensure the default VL is different */
421 ret = file_write_integer(data->default_vl_file, data->max_vl);
422 if (ret != 0)
423 return;
424
425 /* Check that the child has the default we just set */
426 child_vl = get_child_rdvl(data);
427 if (child_vl != data->max_vl) {
428 ksft_test_result_fail("%s is %d but child VL is %d\n",
429 data->default_vl_file,
430 data->max_vl, child_vl);
431 return;
432 }
433
434 ksft_test_result_pass("%s vector length used default\n", data->name);
435
436 file_write_integer(data->default_vl_file, data->default_vl);
437 }
438
439 /* If we didn't request it a new VL shouldn't affect the child */
prctl_set_for_child(struct vec_data * data)440 static void prctl_set_for_child(struct vec_data *data)
441 {
442 int ret, child_vl;
443
444 if (data->min_vl == data->max_vl) {
445 ksft_test_result_skip("%s only one VL supported\n",
446 data->name);
447 return;
448 }
449
450 ret = prctl(data->prctl_set, data->min_vl | PR_SVE_VL_INHERIT);
451 if (ret < 0) {
452 ksft_test_result_fail("%s prctl set failed for %d: %d (%s)\n",
453 data->name, data->min_vl,
454 errno, strerror(errno));
455 return;
456 }
457
458 /* The _INHERIT flag should be present when we read the VL */
459 ret = prctl(data->prctl_get);
460 if (ret == -1) {
461 ksft_test_result_fail("%s prctl() read failed: %d (%s)\n",
462 data->name, errno, strerror(errno));
463 return;
464 }
465 if (!(ret & PR_SVE_VL_INHERIT)) {
466 ksft_test_result_fail("%s prctl() does not report _INHERIT\n",
467 data->name);
468 return;
469 }
470
471 /* Ensure the default VL is different */
472 ret = file_write_integer(data->default_vl_file, data->max_vl);
473 if (ret != 0)
474 return;
475
476 /* Check that the child inherited our VL */
477 child_vl = get_child_rdvl(data);
478 if (child_vl != data->min_vl) {
479 ksft_test_result_fail("%s is %d but child VL is %d\n",
480 data->default_vl_file,
481 data->min_vl, child_vl);
482 return;
483 }
484
485 ksft_test_result_pass("%s vector length was inherited\n", data->name);
486
487 file_write_integer(data->default_vl_file, data->default_vl);
488 }
489
490 /* _ONEXEC takes effect only in the child process */
prctl_set_onexec(struct vec_data * data)491 static void prctl_set_onexec(struct vec_data *data)
492 {
493 int ret, child_vl;
494
495 if (data->min_vl == data->max_vl) {
496 ksft_test_result_skip("%s only one VL supported\n",
497 data->name);
498 return;
499 }
500
501 /* Set a known value for the default and our current VL */
502 ret = file_write_integer(data->default_vl_file, data->max_vl);
503 if (ret != 0)
504 return;
505
506 ret = prctl(data->prctl_set, data->max_vl);
507 if (ret < 0) {
508 ksft_test_result_fail("%s prctl set failed for %d: %d (%s)\n",
509 data->name, data->min_vl,
510 errno, strerror(errno));
511 return;
512 }
513
514 /* Set a different value for the child to have on exec */
515 ret = prctl(data->prctl_set, data->min_vl | PR_SVE_SET_VL_ONEXEC);
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 /* Our current VL should stay the same */
524 if (data->rdvl() != data->max_vl) {
525 ksft_test_result_fail("%s VL changed by _ONEXEC prctl()\n",
526 data->name);
527 return;
528 }
529
530 /* Check that the child inherited our VL */
531 child_vl = get_child_rdvl(data);
532 if (child_vl != data->min_vl) {
533 ksft_test_result_fail("Set %d _ONEXEC but child VL is %d\n",
534 data->min_vl, child_vl);
535 return;
536 }
537
538 ksft_test_result_pass("%s vector length set on exec\n", data->name);
539
540 file_write_integer(data->default_vl_file, data->default_vl);
541 }
542
543 /* For each VQ verify that setting via prctl() does the right thing */
prctl_set_all_vqs(struct vec_data * data)544 static void prctl_set_all_vqs(struct vec_data *data)
545 {
546 int ret, vq, vl, new_vl;
547 int errors = 0;
548
549 if (!data->min_vl || !data->max_vl) {
550 ksft_test_result_skip("%s Failed to enumerate VLs, not testing VL setting\n",
551 data->name);
552 return;
553 }
554
555 for (vq = SVE_VQ_MIN; vq <= SVE_VQ_MAX; vq++) {
556 vl = sve_vl_from_vq(vq);
557
558 /* Attempt to set the VL */
559 ret = prctl(data->prctl_set, vl);
560 if (ret < 0) {
561 errors++;
562 ksft_print_msg("%s prctl set failed for %d: %d (%s)\n",
563 data->name, vl,
564 errno, strerror(errno));
565 continue;
566 }
567
568 new_vl = ret & PR_SVE_VL_LEN_MASK;
569
570 /* Check that we actually have the reported new VL */
571 if (data->rdvl() != new_vl) {
572 ksft_print_msg("Set %s VL %d but RDVL reports %d\n",
573 data->name, new_vl, data->rdvl());
574 errors++;
575 }
576
577 /* Was that the VL we asked for? */
578 if (new_vl == vl)
579 continue;
580
581 /* Should round up to the minimum VL if below it */
582 if (vl < data->min_vl) {
583 if (new_vl != data->min_vl) {
584 ksft_print_msg("%s VL %d returned %d not minimum %d\n",
585 data->name, vl, new_vl,
586 data->min_vl);
587 errors++;
588 }
589
590 continue;
591 }
592
593 /* Should round down to maximum VL if above it */
594 if (vl > data->max_vl) {
595 if (new_vl != data->max_vl) {
596 ksft_print_msg("%s VL %d returned %d not maximum %d\n",
597 data->name, vl, new_vl,
598 data->max_vl);
599 errors++;
600 }
601
602 continue;
603 }
604
605 /* Otherwise we should've rounded down */
606 if (!(new_vl < vl)) {
607 ksft_print_msg("%s VL %d returned %d, did not round down\n",
608 data->name, vl, new_vl);
609 errors++;
610
611 continue;
612 }
613 }
614
615 ksft_test_result(errors == 0, "%s prctl() set all VLs, %d errors\n",
616 data->name, errors);
617 }
618
619 typedef void (*test_type)(struct vec_data *);
620
621 static const test_type tests[] = {
622 /*
623 * The default/min/max tests must be first and in this order
624 * to provide data for other tests.
625 */
626 proc_read_default,
627 proc_write_min,
628 proc_write_max,
629
630 prctl_get,
631 prctl_set_same,
632 prctl_set,
633 prctl_set_no_child,
634 prctl_set_for_child,
635 prctl_set_onexec,
636 prctl_set_all_vqs,
637 };
638
main(void)639 int main(void)
640 {
641 int i, j;
642
643 ksft_print_header();
644 ksft_set_plan(ARRAY_SIZE(tests) * ARRAY_SIZE(vec_data));
645
646 for (i = 0; i < ARRAY_SIZE(vec_data); i++) {
647 struct vec_data *data = &vec_data[i];
648 unsigned long supported;
649
650 supported = getauxval(data->hwcap_type) & data->hwcap;
651
652 for (j = 0; j < ARRAY_SIZE(tests); j++) {
653 if (supported)
654 tests[j](data);
655 else
656 ksft_test_result_skip("%s not supported\n",
657 data->name);
658 }
659 }
660
661 ksft_exit_pass();
662 }
663