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 ARCH_MIN_VL SVE_VL_MIN
25
26 struct vec_data {
27 const char *name;
28 unsigned long hwcap_type;
29 unsigned long hwcap;
30 const char *rdvl_binary;
31 int (*rdvl)(void);
32
33 int prctl_get;
34 int prctl_set;
35 const char *default_vl_file;
36
37 int default_vl;
38 int min_vl;
39 int max_vl;
40 };
41
42
43 static struct vec_data vec_data[] = {
44 {
45 .name = "SVE",
46 .hwcap_type = AT_HWCAP,
47 .hwcap = HWCAP_SVE,
48 .rdvl = rdvl_sve,
49 .rdvl_binary = "./rdvl-sve",
50 .prctl_get = PR_SVE_GET_VL,
51 .prctl_set = PR_SVE_SET_VL,
52 .default_vl_file = "/proc/sys/abi/sve_default_vector_length",
53 },
54 {
55 .name = "SME",
56 .hwcap_type = AT_HWCAP2,
57 .hwcap = HWCAP2_SME,
58 .rdvl = rdvl_sme,
59 .rdvl_binary = "./rdvl-sme",
60 .prctl_get = PR_SME_GET_VL,
61 .prctl_set = PR_SME_SET_VL,
62 .default_vl_file = "/proc/sys/abi/sme_default_vector_length",
63 },
64 };
65
stdio_read_integer(FILE * f,const char * what,int * val)66 static int stdio_read_integer(FILE *f, const char *what, int *val)
67 {
68 int n = 0;
69 int ret;
70
71 ret = fscanf(f, "%d%*1[\n]%n", val, &n);
72 if (ret < 1 || n < 1) {
73 ksft_print_msg("failed to parse integer from %s\n", what);
74 return -1;
75 }
76
77 return 0;
78 }
79
80 /* Start a new process and return the vector length it sees */
get_child_rdvl(struct vec_data * data)81 static int get_child_rdvl(struct vec_data *data)
82 {
83 FILE *out;
84 int pipefd[2];
85 pid_t pid, child;
86 int read_vl, ret;
87
88 ret = pipe(pipefd);
89 if (ret == -1) {
90 ksft_print_msg("pipe() failed: %d (%s)\n",
91 errno, strerror(errno));
92 return -1;
93 }
94
95 fflush(stdout);
96
97 child = fork();
98 if (child == -1) {
99 ksft_print_msg("fork() failed: %d (%s)\n",
100 errno, strerror(errno));
101 close(pipefd[0]);
102 close(pipefd[1]);
103 return -1;
104 }
105
106 /* Child: put vector length on the pipe */
107 if (child == 0) {
108 /*
109 * Replace stdout with the pipe, errors to stderr from
110 * here as kselftest prints to stdout.
111 */
112 ret = dup2(pipefd[1], 1);
113 if (ret == -1) {
114 fprintf(stderr, "dup2() %d\n", errno);
115 exit(EXIT_FAILURE);
116 }
117
118 /* exec() a new binary which puts the VL on stdout */
119 ret = execl(data->rdvl_binary, data->rdvl_binary, NULL);
120 fprintf(stderr, "execl(%s) failed: %d (%s)\n",
121 data->rdvl_binary, errno, strerror(errno));
122
123 exit(EXIT_FAILURE);
124 }
125
126 close(pipefd[1]);
127
128 /* Parent; wait for the exit status from the child & verify it */
129 do {
130 pid = wait(&ret);
131 if (pid == -1) {
132 ksft_print_msg("wait() failed: %d (%s)\n",
133 errno, strerror(errno));
134 close(pipefd[0]);
135 return -1;
136 }
137 } while (pid != child);
138
139 assert(pid == child);
140
141 if (!WIFEXITED(ret)) {
142 ksft_print_msg("child exited abnormally\n");
143 close(pipefd[0]);
144 return -1;
145 }
146
147 if (WEXITSTATUS(ret) != 0) {
148 ksft_print_msg("child returned error %d\n",
149 WEXITSTATUS(ret));
150 close(pipefd[0]);
151 return -1;
152 }
153
154 out = fdopen(pipefd[0], "r");
155 if (!out) {
156 ksft_print_msg("failed to open child stdout\n");
157 close(pipefd[0]);
158 return -1;
159 }
160
161 ret = stdio_read_integer(out, "child", &read_vl);
162 fclose(out);
163 if (ret != 0)
164 return ret;
165
166 return read_vl;
167 }
168
file_read_integer(const char * name,int * val)169 static int file_read_integer(const char *name, int *val)
170 {
171 FILE *f;
172 int ret;
173
174 f = fopen(name, "r");
175 if (!f) {
176 ksft_test_result_fail("Unable to open %s: %d (%s)\n",
177 name, errno,
178 strerror(errno));
179 return -1;
180 }
181
182 ret = stdio_read_integer(f, name, val);
183 fclose(f);
184
185 return ret;
186 }
187
file_write_integer(const char * name,int val)188 static int file_write_integer(const char *name, int val)
189 {
190 FILE *f;
191
192 f = fopen(name, "w");
193 if (!f) {
194 ksft_test_result_fail("Unable to open %s: %d (%s)\n",
195 name, errno,
196 strerror(errno));
197 return -1;
198 }
199
200 fprintf(f, "%d", val);
201 fclose(f);
202
203 return 0;
204 }
205
206 /*
207 * Verify that we can read the default VL via proc, checking that it
208 * is set in a freshly spawned child.
209 */
proc_read_default(struct vec_data * data)210 static void proc_read_default(struct vec_data *data)
211 {
212 int default_vl, child_vl, ret;
213
214 ret = file_read_integer(data->default_vl_file, &default_vl);
215 if (ret != 0)
216 return;
217
218 /* Is this the actual default seen by new processes? */
219 child_vl = get_child_rdvl(data);
220 if (child_vl != default_vl) {
221 ksft_test_result_fail("%s is %d but child VL is %d\n",
222 data->default_vl_file,
223 default_vl, child_vl);
224 return;
225 }
226
227 ksft_test_result_pass("%s default vector length %d\n", data->name,
228 default_vl);
229 data->default_vl = default_vl;
230 }
231
232 /* Verify that we can write a minimum value and have it take effect */
proc_write_min(struct vec_data * data)233 static void proc_write_min(struct vec_data *data)
234 {
235 int ret, new_default, child_vl;
236
237 if (geteuid() != 0) {
238 ksft_test_result_skip("Need to be root to write to /proc\n");
239 return;
240 }
241
242 ret = file_write_integer(data->default_vl_file, ARCH_MIN_VL);
243 if (ret != 0)
244 return;
245
246 /* What was the new value? */
247 ret = file_read_integer(data->default_vl_file, &new_default);
248 if (ret != 0)
249 return;
250
251 /* Did it take effect in a new process? */
252 child_vl = get_child_rdvl(data);
253 if (child_vl != new_default) {
254 ksft_test_result_fail("%s is %d but child VL is %d\n",
255 data->default_vl_file,
256 new_default, child_vl);
257 return;
258 }
259
260 ksft_test_result_pass("%s minimum vector length %d\n", data->name,
261 new_default);
262 data->min_vl = new_default;
263
264 file_write_integer(data->default_vl_file, data->default_vl);
265 }
266
267 /* Verify that we can write a maximum value and have it take effect */
proc_write_max(struct vec_data * data)268 static void proc_write_max(struct vec_data *data)
269 {
270 int ret, new_default, child_vl;
271
272 if (geteuid() != 0) {
273 ksft_test_result_skip("Need to be root to write to /proc\n");
274 return;
275 }
276
277 /* -1 is accepted by the /proc interface as the maximum VL */
278 ret = file_write_integer(data->default_vl_file, -1);
279 if (ret != 0)
280 return;
281
282 /* What was the new value? */
283 ret = file_read_integer(data->default_vl_file, &new_default);
284 if (ret != 0)
285 return;
286
287 /* Did it take effect in a new process? */
288 child_vl = get_child_rdvl(data);
289 if (child_vl != new_default) {
290 ksft_test_result_fail("%s is %d but child VL is %d\n",
291 data->default_vl_file,
292 new_default, child_vl);
293 return;
294 }
295
296 ksft_test_result_pass("%s maximum vector length %d\n", data->name,
297 new_default);
298 data->max_vl = new_default;
299
300 file_write_integer(data->default_vl_file, data->default_vl);
301 }
302
303 /* Can we read back a VL from prctl? */
prctl_get(struct vec_data * data)304 static void prctl_get(struct vec_data *data)
305 {
306 int ret;
307
308 ret = prctl(data->prctl_get);
309 if (ret == -1) {
310 ksft_test_result_fail("%s prctl() read failed: %d (%s)\n",
311 data->name, errno, strerror(errno));
312 return;
313 }
314
315 /* Mask out any flags */
316 ret &= PR_SVE_VL_LEN_MASK;
317
318 /* Is that what we can read back directly? */
319 if (ret == data->rdvl())
320 ksft_test_result_pass("%s current VL is %d\n",
321 data->name, ret);
322 else
323 ksft_test_result_fail("%s prctl() VL %d but RDVL is %d\n",
324 data->name, ret, data->rdvl());
325 }
326
327 /* Does the prctl let us set the VL we already have? */
prctl_set_same(struct vec_data * data)328 static void prctl_set_same(struct vec_data *data)
329 {
330 int cur_vl = data->rdvl();
331 int ret;
332
333 ret = prctl(data->prctl_set, cur_vl);
334 if (ret < 0) {
335 ksft_test_result_fail("%s prctl set failed: %d (%s)\n",
336 data->name, errno, strerror(errno));
337 return;
338 }
339
340 ksft_test_result(cur_vl == data->rdvl(),
341 "%s set VL %d and have VL %d\n",
342 data->name, cur_vl, data->rdvl());
343 }
344
345 /* Can we set a new VL for this process? */
prctl_set(struct vec_data * data)346 static void prctl_set(struct vec_data *data)
347 {
348 int ret;
349
350 if (data->min_vl == data->max_vl) {
351 ksft_test_result_skip("%s only one VL supported\n",
352 data->name);
353 return;
354 }
355
356 /* Try to set the minimum VL */
357 ret = prctl(data->prctl_set, data->min_vl);
358 if (ret < 0) {
359 ksft_test_result_fail("%s prctl set failed for %d: %d (%s)\n",
360 data->name, data->min_vl,
361 errno, strerror(errno));
362 return;
363 }
364
365 if ((ret & PR_SVE_VL_LEN_MASK) != data->min_vl) {
366 ksft_test_result_fail("%s prctl set %d but return value is %d\n",
367 data->name, data->min_vl, data->rdvl());
368 return;
369 }
370
371 if (data->rdvl() != data->min_vl) {
372 ksft_test_result_fail("%s set %d but RDVL is %d\n",
373 data->name, data->min_vl, data->rdvl());
374 return;
375 }
376
377 /* Try to set the maximum VL */
378 ret = prctl(data->prctl_set, data->max_vl);
379 if (ret < 0) {
380 ksft_test_result_fail("%s prctl set failed for %d: %d (%s)\n",
381 data->name, data->max_vl,
382 errno, strerror(errno));
383 return;
384 }
385
386 if ((ret & PR_SVE_VL_LEN_MASK) != data->max_vl) {
387 ksft_test_result_fail("%s prctl() set %d but return value is %d\n",
388 data->name, data->max_vl, data->rdvl());
389 return;
390 }
391
392 /* The _INHERIT flag should not be present when we read the VL */
393 ret = prctl(data->prctl_get);
394 if (ret == -1) {
395 ksft_test_result_fail("%s prctl() read failed: %d (%s)\n",
396 data->name, errno, strerror(errno));
397 return;
398 }
399
400 if (ret & PR_SVE_VL_INHERIT) {
401 ksft_test_result_fail("%s prctl() reports _INHERIT\n",
402 data->name);
403 return;
404 }
405
406 ksft_test_result_pass("%s prctl() set min/max\n", data->name);
407 }
408
409 /* If we didn't request it a new VL shouldn't affect the child */
prctl_set_no_child(struct vec_data * data)410 static void prctl_set_no_child(struct vec_data *data)
411 {
412 int ret, child_vl;
413
414 if (data->min_vl == data->max_vl) {
415 ksft_test_result_skip("%s only one VL supported\n",
416 data->name);
417 return;
418 }
419
420 ret = prctl(data->prctl_set, data->min_vl);
421 if (ret < 0) {
422 ksft_test_result_fail("%s prctl set failed for %d: %d (%s)\n",
423 data->name, data->min_vl,
424 errno, strerror(errno));
425 return;
426 }
427
428 /* Ensure the default VL is different */
429 ret = file_write_integer(data->default_vl_file, data->max_vl);
430 if (ret != 0)
431 return;
432
433 /* Check that the child has the default we just set */
434 child_vl = get_child_rdvl(data);
435 if (child_vl != data->max_vl) {
436 ksft_test_result_fail("%s is %d but child VL is %d\n",
437 data->default_vl_file,
438 data->max_vl, child_vl);
439 return;
440 }
441
442 ksft_test_result_pass("%s vector length used default\n", data->name);
443
444 file_write_integer(data->default_vl_file, data->default_vl);
445 }
446
447 /* If we didn't request it a new VL shouldn't affect the child */
prctl_set_for_child(struct vec_data * data)448 static void prctl_set_for_child(struct vec_data *data)
449 {
450 int ret, child_vl;
451
452 if (data->min_vl == data->max_vl) {
453 ksft_test_result_skip("%s only one VL supported\n",
454 data->name);
455 return;
456 }
457
458 ret = prctl(data->prctl_set, data->min_vl | PR_SVE_VL_INHERIT);
459 if (ret < 0) {
460 ksft_test_result_fail("%s prctl set failed for %d: %d (%s)\n",
461 data->name, data->min_vl,
462 errno, strerror(errno));
463 return;
464 }
465
466 /* The _INHERIT flag should be present when we read the VL */
467 ret = prctl(data->prctl_get);
468 if (ret == -1) {
469 ksft_test_result_fail("%s prctl() read failed: %d (%s)\n",
470 data->name, errno, strerror(errno));
471 return;
472 }
473 if (!(ret & PR_SVE_VL_INHERIT)) {
474 ksft_test_result_fail("%s prctl() does not report _INHERIT\n",
475 data->name);
476 return;
477 }
478
479 /* Ensure the default VL is different */
480 ret = file_write_integer(data->default_vl_file, data->max_vl);
481 if (ret != 0)
482 return;
483
484 /* Check that the child inherited our VL */
485 child_vl = get_child_rdvl(data);
486 if (child_vl != data->min_vl) {
487 ksft_test_result_fail("%s is %d but child VL is %d\n",
488 data->default_vl_file,
489 data->min_vl, child_vl);
490 return;
491 }
492
493 ksft_test_result_pass("%s vector length was inherited\n", data->name);
494
495 file_write_integer(data->default_vl_file, data->default_vl);
496 }
497
498 /* _ONEXEC takes effect only in the child process */
prctl_set_onexec(struct vec_data * data)499 static void prctl_set_onexec(struct vec_data *data)
500 {
501 int ret, child_vl;
502
503 if (data->min_vl == data->max_vl) {
504 ksft_test_result_skip("%s only one VL supported\n",
505 data->name);
506 return;
507 }
508
509 /* Set a known value for the default and our current VL */
510 ret = file_write_integer(data->default_vl_file, data->max_vl);
511 if (ret != 0)
512 return;
513
514 ret = prctl(data->prctl_set, data->max_vl);
515 if (ret < 0) {
516 ksft_test_result_fail("%s prctl set failed for %d: %d (%s)\n",
517 data->name, data->min_vl,
518 errno, strerror(errno));
519 return;
520 }
521
522 /* Set a different value for the child to have on exec */
523 ret = prctl(data->prctl_set, data->min_vl | PR_SVE_SET_VL_ONEXEC);
524 if (ret < 0) {
525 ksft_test_result_fail("%s prctl set failed for %d: %d (%s)\n",
526 data->name, data->min_vl,
527 errno, strerror(errno));
528 return;
529 }
530
531 /* Our current VL should stay the same */
532 if (data->rdvl() != data->max_vl) {
533 ksft_test_result_fail("%s VL changed by _ONEXEC prctl()\n",
534 data->name);
535 return;
536 }
537
538 /* Check that the child inherited our VL */
539 child_vl = get_child_rdvl(data);
540 if (child_vl != data->min_vl) {
541 ksft_test_result_fail("Set %d _ONEXEC but child VL is %d\n",
542 data->min_vl, child_vl);
543 return;
544 }
545
546 ksft_test_result_pass("%s vector length set on exec\n", data->name);
547
548 file_write_integer(data->default_vl_file, data->default_vl);
549 }
550
551 /* For each VQ verify that setting via prctl() does the right thing */
prctl_set_all_vqs(struct vec_data * data)552 static void prctl_set_all_vqs(struct vec_data *data)
553 {
554 int ret, vq, vl, new_vl;
555 int errors = 0;
556
557 if (!data->min_vl || !data->max_vl) {
558 ksft_test_result_skip("%s Failed to enumerate VLs, not testing VL setting\n",
559 data->name);
560 return;
561 }
562
563 for (vq = SVE_VQ_MIN; vq <= SVE_VQ_MAX; vq++) {
564 vl = sve_vl_from_vq(vq);
565
566 /* Attempt to set the VL */
567 ret = prctl(data->prctl_set, vl);
568 if (ret < 0) {
569 errors++;
570 ksft_print_msg("%s prctl set failed for %d: %d (%s)\n",
571 data->name, vl,
572 errno, strerror(errno));
573 continue;
574 }
575
576 new_vl = ret & PR_SVE_VL_LEN_MASK;
577
578 /* Check that we actually have the reported new VL */
579 if (data->rdvl() != new_vl) {
580 ksft_print_msg("Set %s VL %d but RDVL reports %d\n",
581 data->name, new_vl, data->rdvl());
582 errors++;
583 }
584
585 /* Was that the VL we asked for? */
586 if (new_vl == vl)
587 continue;
588
589 /* Should round up to the minimum VL if below it */
590 if (vl < data->min_vl) {
591 if (new_vl != data->min_vl) {
592 ksft_print_msg("%s VL %d returned %d not minimum %d\n",
593 data->name, vl, new_vl,
594 data->min_vl);
595 errors++;
596 }
597
598 continue;
599 }
600
601 /* Should round down to maximum VL if above it */
602 if (vl > data->max_vl) {
603 if (new_vl != data->max_vl) {
604 ksft_print_msg("%s VL %d returned %d not maximum %d\n",
605 data->name, vl, new_vl,
606 data->max_vl);
607 errors++;
608 }
609
610 continue;
611 }
612
613 /* Otherwise we should've rounded down */
614 if (!(new_vl < vl)) {
615 ksft_print_msg("%s VL %d returned %d, did not round down\n",
616 data->name, vl, new_vl);
617 errors++;
618
619 continue;
620 }
621 }
622
623 ksft_test_result(errors == 0, "%s prctl() set all VLs, %d errors\n",
624 data->name, errors);
625 }
626
627 typedef void (*test_type)(struct vec_data *);
628
629 static const test_type tests[] = {
630 /*
631 * The default/min/max tests must be first and in this order
632 * to provide data for other tests.
633 */
634 proc_read_default,
635 proc_write_min,
636 proc_write_max,
637
638 prctl_get,
639 prctl_set_same,
640 prctl_set,
641 prctl_set_no_child,
642 prctl_set_for_child,
643 prctl_set_onexec,
644 prctl_set_all_vqs,
645 };
646
main(void)647 int main(void)
648 {
649 int i, j;
650
651 ksft_print_header();
652 ksft_set_plan(ARRAY_SIZE(tests) * ARRAY_SIZE(vec_data));
653
654 for (i = 0; i < ARRAY_SIZE(vec_data); i++) {
655 struct vec_data *data = &vec_data[i];
656 unsigned long supported;
657
658 supported = getauxval(data->hwcap_type) & data->hwcap;
659
660 for (j = 0; j < ARRAY_SIZE(tests); j++) {
661 if (supported)
662 tests[j](data);
663 else
664 ksft_test_result_skip("%s not supported\n",
665 data->name);
666 }
667 }
668
669 ksft_exit_pass();
670 }
671