1 // SPDX-License-Identifier: GPL-2.0-only
2 #define THIS_PROGRAM "./vstate_exec_nolibc"
3 
4 int main(int argc, char **argv)
5 {
6 	int rc, pid, status, test_inherit = 0;
7 	long ctrl, ctrl_c;
8 	char *exec_argv[2], *exec_envp[2];
9 
10 	if (argc > 1)
11 		test_inherit = 1;
12 
13 	ctrl = my_syscall1(__NR_prctl, PR_RISCV_V_GET_CONTROL);
14 	if (ctrl < 0) {
15 		puts("PR_RISCV_V_GET_CONTROL is not supported\n");
16 		return ctrl;
17 	}
18 
19 	if (test_inherit) {
20 		pid = fork();
21 		if (pid == -1) {
22 			puts("fork failed\n");
23 			exit(-1);
24 		}
25 
26 		/* child  */
27 		if (!pid) {
28 			exec_argv[0] = THIS_PROGRAM;
29 			exec_argv[1] = NULL;
30 			exec_envp[0] = NULL;
31 			exec_envp[1] = NULL;
32 			/* launch the program again to check inherit */
33 			rc = execve(THIS_PROGRAM, exec_argv, exec_envp);
34 			if (rc) {
35 				puts("child execve failed\n");
36 				exit(-1);
37 			}
38 		}
39 
40 	} else {
41 		pid = fork();
42 		if (pid == -1) {
43 			puts("fork failed\n");
44 			exit(-1);
45 		}
46 
47 		if (!pid) {
48 			rc = my_syscall1(__NR_prctl, PR_RISCV_V_GET_CONTROL);
49 			if (rc != ctrl) {
50 				puts("child's vstate_ctrl not equal to parent's\n");
51 				exit(-1);
52 			}
53 			asm volatile (".option push\n\t"
54 				      ".option arch, +v\n\t"
55 				      "vsetvli x0, x0, e32, m8, ta, ma\n\t"
56 				      ".option pop\n\t"
57 				      );
58 			exit(ctrl);
59 		}
60 	}
61 
62 	rc = waitpid(-1, &status, 0);
63 
64 	if (WIFEXITED(status) && WEXITSTATUS(status) == -1) {
65 		puts("child exited abnormally\n");
66 		exit(-1);
67 	}
68 
69 	if (WIFSIGNALED(status)) {
70 		if (WTERMSIG(status) != SIGILL) {
71 			puts("child was terminated by unexpected signal\n");
72 			exit(-1);
73 		}
74 
75 		if ((ctrl & PR_RISCV_V_VSTATE_CTRL_CUR_MASK) != PR_RISCV_V_VSTATE_CTRL_OFF) {
76 			puts("child signaled by illegal V access but vstate_ctrl is not off\n");
77 			exit(-1);
78 		}
79 
80 		/* child terminated, and its vstate_ctrl is off */
81 		exit(ctrl);
82 	}
83 
84 	ctrl_c = WEXITSTATUS(status);
85 	if (test_inherit) {
86 		if (ctrl & PR_RISCV_V_VSTATE_CTRL_INHERIT) {
87 			if (!(ctrl_c & PR_RISCV_V_VSTATE_CTRL_INHERIT)) {
88 				puts("parent has inherit bit, but child has not\n");
89 				exit(-1);
90 			}
91 		}
92 		rc = (ctrl & PR_RISCV_V_VSTATE_CTRL_NEXT_MASK) >> 2;
93 		if (rc != PR_RISCV_V_VSTATE_CTRL_DEFAULT) {
94 			if (rc != (ctrl_c & PR_RISCV_V_VSTATE_CTRL_CUR_MASK)) {
95 				puts("parent's next setting does not equal to child's\n");
96 				exit(-1);
97 			}
98 
99 			if (!(ctrl & PR_RISCV_V_VSTATE_CTRL_INHERIT)) {
100 				if ((ctrl_c & PR_RISCV_V_VSTATE_CTRL_NEXT_MASK) !=
101 				    PR_RISCV_V_VSTATE_CTRL_DEFAULT) {
102 					puts("must clear child's next vstate_ctrl if !inherit\n");
103 					exit(-1);
104 				}
105 			}
106 		}
107 	}
108 	return ctrl;
109 }
110