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\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 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 * Verify that we can read the default VL via proc, checking that it
206 * is set in a freshly spawned child.
207 */
proc_read_default(struct vec_data * data)208 static 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 /* Is this the actual default seen by new processes? */
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 /* Verify that we can write a minimum value and have it take effect */
proc_write_min(struct vec_data * data)231 static 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 /* What was the new value? */
245 ret = file_read_integer(data->default_vl_file, &new_default);
246 if (ret != 0)
247 return;
248
249 /* Did it take effect in a new process? */
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 /* Verify that we can write a maximum value and have it take effect */
proc_write_max(struct vec_data * data)266 static 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 /* -1 is accepted by the /proc interface as the maximum VL */
276 ret = file_write_integer(data->default_vl_file, -1);
277 if (ret != 0)
278 return;
279
280 /* What was the new value? */
281 ret = file_read_integer(data->default_vl_file, &new_default);
282 if (ret != 0)
283 return;
284
285 /* Did it take effect in a new process? */
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 /* Can we read back a VL from prctl? */
prctl_get(struct vec_data * data)302 static 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 /* Mask out any flags */
314 ret &= PR_SVE_VL_LEN_MASK;
315
316 /* Is that what we can read back directly? */
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 /* Does the prctl let us set the VL we already have? */
prctl_set_same(struct vec_data * data)326 static 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 /* Can we set a new VL for this process? */
prctl_set(struct vec_data * data)347 static 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 /* Try to set the minimum VL */
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 /* Try to set the maximum VL */
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 /* The _INHERIT flag should not be present when we read the VL */
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 /* If we didn't request it a new VL shouldn't affect the child */
prctl_set_no_child(struct vec_data * data)411 static 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 /* Ensure the default VL is different */
430 ret = file_write_integer(data->default_vl_file, data->max_vl);
431 if (ret != 0)
432 return;
433
434 /* Check that the child has the default we just set */
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 /* If we didn't request it a new VL shouldn't affect the child */
prctl_set_for_child(struct vec_data * data)449 static 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 /* The _INHERIT flag should be present when we read the VL */
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 /* Ensure the default VL is different */
481 ret = file_write_integer(data->default_vl_file, data->max_vl);
482 if (ret != 0)
483 return;
484
485 /* Check that the child inherited our VL */
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 /* _ONEXEC takes effect only in the child process */
prctl_set_onexec(struct vec_data * data)500 static 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 /* Set a known value for the default and our current VL */
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 /* Set a different value for the child to have on exec */
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 /* Our current VL should stay the same */
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 /* Check that the child inherited our VL */
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
552 typedef void (*test_type)(struct vec_data *);
553
554 static const test_type tests[] = {
555 /*
556 * The default/min/max tests must be first and in this order
557 * to provide data for other tests.
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
main(void)570 int 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