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 }
112