Skip to content

Commit 7cf6198

Browse files
AndybnACTpalmer-dabbelt
authored andcommitted
selftests: Test RISC-V Vector prctl interface
This add a test for prctl interface that controls the use of userspace Vector. Signed-off-by: Andy Chiu <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Palmer Dabbelt <[email protected]>
1 parent 04a4722 commit 7cf6198

File tree

5 files changed

+318
-1
lines changed

5 files changed

+318
-1
lines changed

tools/testing/selftests/riscv/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
ARCH ?= $(shell uname -m 2>/dev/null || echo not)
66

77
ifneq (,$(filter $(ARCH),riscv))
8-
RISCV_SUBTARGETS ?= hwprobe
8+
RISCV_SUBTARGETS ?= hwprobe vector
99
else
1010
RISCV_SUBTARGETS :=
1111
endif
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
vstate_exec_nolibc
2+
vstate_prctl
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# SPDX-License-Identifier: GPL-2.0
2+
# Copyright (C) 2021 ARM Limited
3+
# Originally tools/testing/arm64/abi/Makefile
4+
5+
TEST_GEN_PROGS := vstate_prctl
6+
TEST_GEN_PROGS_EXTENDED := vstate_exec_nolibc
7+
8+
include ../../lib.mk
9+
10+
$(OUTPUT)/vstate_prctl: vstate_prctl.c ../hwprobe/sys_hwprobe.S
11+
$(CC) -static -o$@ $(CFLAGS) $(LDFLAGS) $^
12+
13+
$(OUTPUT)/vstate_exec_nolibc: vstate_exec_nolibc.c
14+
$(CC) -nostdlib -static -include ../../../../include/nolibc/nolibc.h \
15+
-Wall $(CFLAGS) $(LDFLAGS) $^ -o $@ -lgcc
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
#include <sys/prctl.h>
3+
4+
#define THIS_PROGRAM "./vstate_exec_nolibc"
5+
6+
int main(int argc, char **argv)
7+
{
8+
int rc, pid, status, test_inherit = 0;
9+
long ctrl, ctrl_c;
10+
char *exec_argv[2], *exec_envp[2];
11+
12+
if (argc > 1)
13+
test_inherit = 1;
14+
15+
ctrl = my_syscall1(__NR_prctl, PR_RISCV_V_GET_CONTROL);
16+
if (ctrl < 0) {
17+
puts("PR_RISCV_V_GET_CONTROL is not supported\n");
18+
return ctrl;
19+
}
20+
21+
if (test_inherit) {
22+
pid = fork();
23+
if (pid == -1) {
24+
puts("fork failed\n");
25+
exit(-1);
26+
}
27+
28+
/* child */
29+
if (!pid) {
30+
exec_argv[0] = THIS_PROGRAM;
31+
exec_argv[1] = NULL;
32+
exec_envp[0] = NULL;
33+
exec_envp[1] = NULL;
34+
/* launch the program again to check inherit */
35+
rc = execve(THIS_PROGRAM, exec_argv, exec_envp);
36+
if (rc) {
37+
puts("child execve failed\n");
38+
exit(-1);
39+
}
40+
}
41+
42+
} else {
43+
pid = fork();
44+
if (pid == -1) {
45+
puts("fork failed\n");
46+
exit(-1);
47+
}
48+
49+
if (!pid) {
50+
rc = my_syscall1(__NR_prctl, PR_RISCV_V_GET_CONTROL);
51+
if (rc != ctrl) {
52+
puts("child's vstate_ctrl not equal to parent's\n");
53+
exit(-1);
54+
}
55+
asm volatile (".option push\n\t"
56+
".option arch, +v\n\t"
57+
"vsetvli x0, x0, e32, m8, ta, ma\n\t"
58+
".option pop\n\t"
59+
);
60+
exit(ctrl);
61+
}
62+
}
63+
64+
rc = waitpid(-1, &status, 0);
65+
66+
if (WIFEXITED(status) && WEXITSTATUS(status) == -1) {
67+
puts("child exited abnormally\n");
68+
exit(-1);
69+
}
70+
71+
if (WIFSIGNALED(status)) {
72+
if (WTERMSIG(status) != SIGILL) {
73+
puts("child was terminated by unexpected signal\n");
74+
exit(-1);
75+
}
76+
77+
if ((ctrl & PR_RISCV_V_VSTATE_CTRL_CUR_MASK) != PR_RISCV_V_VSTATE_CTRL_OFF) {
78+
puts("child signaled by illegal V access but vstate_ctrl is not off\n");
79+
exit(-1);
80+
}
81+
82+
/* child terminated, and its vstate_ctrl is off */
83+
exit(ctrl);
84+
}
85+
86+
ctrl_c = WEXITSTATUS(status);
87+
if (test_inherit) {
88+
if (ctrl & PR_RISCV_V_VSTATE_CTRL_INHERIT) {
89+
if (!(ctrl_c & PR_RISCV_V_VSTATE_CTRL_INHERIT)) {
90+
puts("parent has inherit bit, but child has not\n");
91+
exit(-1);
92+
}
93+
}
94+
rc = (ctrl & PR_RISCV_V_VSTATE_CTRL_NEXT_MASK) >> 2;
95+
if (rc != PR_RISCV_V_VSTATE_CTRL_DEFAULT) {
96+
if (rc != (ctrl_c & PR_RISCV_V_VSTATE_CTRL_CUR_MASK)) {
97+
puts("parent's next setting does not equal to child's\n");
98+
exit(-1);
99+
}
100+
101+
if (!(ctrl & PR_RISCV_V_VSTATE_CTRL_INHERIT)) {
102+
if ((ctrl_c & PR_RISCV_V_VSTATE_CTRL_NEXT_MASK) !=
103+
PR_RISCV_V_VSTATE_CTRL_DEFAULT) {
104+
puts("must clear child's next vstate_ctrl if !inherit\n");
105+
exit(-1);
106+
}
107+
}
108+
}
109+
}
110+
return ctrl;
111+
}
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
#include <sys/prctl.h>
3+
#include <unistd.h>
4+
#include <asm/hwprobe.h>
5+
#include <errno.h>
6+
#include <sys/wait.h>
7+
8+
#include "../../kselftest.h"
9+
10+
/*
11+
* Rather than relying on having a new enough libc to define this, just do it
12+
* ourselves. This way we don't need to be coupled to a new-enough libc to
13+
* contain the call.
14+
*/
15+
long riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count,
16+
size_t cpu_count, unsigned long *cpus, unsigned int flags);
17+
18+
#define NEXT_PROGRAM "./vstate_exec_nolibc"
19+
static int launch_test(int test_inherit)
20+
{
21+
char *exec_argv[3], *exec_envp[1];
22+
int rc, pid, status;
23+
24+
pid = fork();
25+
if (pid < 0) {
26+
ksft_test_result_fail("fork failed %d", pid);
27+
return -1;
28+
}
29+
30+
if (!pid) {
31+
exec_argv[0] = NEXT_PROGRAM;
32+
exec_argv[1] = test_inherit != 0 ? "x" : NULL;
33+
exec_argv[2] = NULL;
34+
exec_envp[0] = NULL;
35+
/* launch the program again to check inherit */
36+
rc = execve(NEXT_PROGRAM, exec_argv, exec_envp);
37+
if (rc) {
38+
perror("execve");
39+
ksft_test_result_fail("child execve failed %d\n", rc);
40+
exit(-1);
41+
}
42+
}
43+
44+
rc = waitpid(-1, &status, 0);
45+
if (rc < 0) {
46+
ksft_test_result_fail("waitpid failed\n");
47+
return -3;
48+
}
49+
50+
if ((WIFEXITED(status) && WEXITSTATUS(status) == -1) ||
51+
WIFSIGNALED(status)) {
52+
ksft_test_result_fail("child exited abnormally\n");
53+
return -4;
54+
}
55+
56+
return WEXITSTATUS(status);
57+
}
58+
59+
int test_and_compare_child(long provided, long expected, int inherit)
60+
{
61+
int rc;
62+
63+
rc = prctl(PR_RISCV_V_SET_CONTROL, provided);
64+
if (rc != 0) {
65+
ksft_test_result_fail("prctl with provided arg %lx failed with code %d\n",
66+
provided, rc);
67+
return -1;
68+
}
69+
rc = launch_test(inherit);
70+
if (rc != expected) {
71+
ksft_test_result_fail("Test failed, check %d != %d\n", rc,
72+
expected);
73+
return -2;
74+
}
75+
return 0;
76+
}
77+
78+
#define PR_RISCV_V_VSTATE_CTRL_CUR_SHIFT 0
79+
#define PR_RISCV_V_VSTATE_CTRL_NEXT_SHIFT 2
80+
81+
int main(void)
82+
{
83+
struct riscv_hwprobe pair;
84+
long flag, expected;
85+
long rc;
86+
87+
pair.key = RISCV_HWPROBE_KEY_IMA_EXT_0;
88+
rc = riscv_hwprobe(&pair, 1, 0, NULL, 0);
89+
if (rc < 0) {
90+
ksft_test_result_fail("hwprobe() failed with %d\n", rc);
91+
return -1;
92+
}
93+
94+
if (pair.key != RISCV_HWPROBE_KEY_IMA_EXT_0) {
95+
ksft_test_result_fail("hwprobe cannot probe RISCV_HWPROBE_KEY_IMA_EXT_0\n");
96+
return -2;
97+
}
98+
99+
if (!(pair.value & RISCV_HWPROBE_IMA_V)) {
100+
rc = prctl(PR_RISCV_V_GET_CONTROL);
101+
if (rc != -1 || errno != EINVAL) {
102+
ksft_test_result_fail("GET_CONTROL should fail on kernel/hw without V\n");
103+
return -3;
104+
}
105+
106+
rc = prctl(PR_RISCV_V_SET_CONTROL, PR_RISCV_V_VSTATE_CTRL_ON);
107+
if (rc != -1 || errno != EINVAL) {
108+
ksft_test_result_fail("GET_CONTROL should fail on kernel/hw without V\n");
109+
return -4;
110+
}
111+
112+
ksft_test_result_skip("Vector not supported\n");
113+
return 0;
114+
}
115+
116+
flag = PR_RISCV_V_VSTATE_CTRL_ON;
117+
rc = prctl(PR_RISCV_V_SET_CONTROL, flag);
118+
if (rc != 0) {
119+
ksft_test_result_fail("Enabling V for current should always success\n");
120+
return -5;
121+
}
122+
123+
flag = PR_RISCV_V_VSTATE_CTRL_OFF;
124+
rc = prctl(PR_RISCV_V_SET_CONTROL, flag);
125+
if (rc != -1 || errno != EPERM) {
126+
ksft_test_result_fail("Disabling current's V alive must fail with EPERM(%d)\n",
127+
errno);
128+
return -5;
129+
}
130+
131+
/* Turn on next's vector explicitly and test */
132+
flag = PR_RISCV_V_VSTATE_CTRL_ON << PR_RISCV_V_VSTATE_CTRL_NEXT_SHIFT;
133+
if (test_and_compare_child(flag, PR_RISCV_V_VSTATE_CTRL_ON, 0))
134+
return -6;
135+
136+
/* Turn off next's vector explicitly and test */
137+
flag = PR_RISCV_V_VSTATE_CTRL_OFF << PR_RISCV_V_VSTATE_CTRL_NEXT_SHIFT;
138+
if (test_and_compare_child(flag, PR_RISCV_V_VSTATE_CTRL_OFF, 0))
139+
return -7;
140+
141+
/* Turn on next's vector explicitly and test inherit */
142+
flag = PR_RISCV_V_VSTATE_CTRL_ON << PR_RISCV_V_VSTATE_CTRL_NEXT_SHIFT;
143+
flag |= PR_RISCV_V_VSTATE_CTRL_INHERIT;
144+
expected = flag | PR_RISCV_V_VSTATE_CTRL_ON;
145+
if (test_and_compare_child(flag, expected, 0))
146+
return -8;
147+
148+
if (test_and_compare_child(flag, expected, 1))
149+
return -9;
150+
151+
/* Turn off next's vector explicitly and test inherit */
152+
flag = PR_RISCV_V_VSTATE_CTRL_OFF << PR_RISCV_V_VSTATE_CTRL_NEXT_SHIFT;
153+
flag |= PR_RISCV_V_VSTATE_CTRL_INHERIT;
154+
expected = flag | PR_RISCV_V_VSTATE_CTRL_OFF;
155+
if (test_and_compare_child(flag, expected, 0))
156+
return -10;
157+
158+
if (test_and_compare_child(flag, expected, 1))
159+
return -11;
160+
161+
/* arguments should fail with EINVAL */
162+
rc = prctl(PR_RISCV_V_SET_CONTROL, 0xff0);
163+
if (rc != -1 || errno != EINVAL) {
164+
ksft_test_result_fail("Undefined control argument should return EINVAL\n");
165+
return -12;
166+
}
167+
168+
rc = prctl(PR_RISCV_V_SET_CONTROL, 0x3);
169+
if (rc != -1 || errno != EINVAL) {
170+
ksft_test_result_fail("Undefined control argument should return EINVAL\n");
171+
return -12;
172+
}
173+
174+
rc = prctl(PR_RISCV_V_SET_CONTROL, 0xc);
175+
if (rc != -1 || errno != EINVAL) {
176+
ksft_test_result_fail("Undefined control argument should return EINVAL\n");
177+
return -12;
178+
}
179+
180+
rc = prctl(PR_RISCV_V_SET_CONTROL, 0xc);
181+
if (rc != -1 || errno != EINVAL) {
182+
ksft_test_result_fail("Undefined control argument should return EINVAL\n");
183+
return -12;
184+
}
185+
186+
ksft_test_result_pass("tests for riscv_v_vstate_ctrl pass\n");
187+
ksft_exit_pass();
188+
return 0;
189+
}

0 commit comments

Comments
 (0)