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