1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2022 ARM Limited.
4  * Original author: Mark Brown <broonie@kernel.org>
5  */
6 
7 // SPDX-License-Identifier: GPL-2.0-only
8 
9 #include <linux/sched.h>
10 #include <linux/wait.h>
11 
12 #define EXPECTED_TESTS 1
13 
14 static void putstr(const char *str)
15 {
16 	write(1, str, strlen(str));
17 }
18 
19 static void putnum(unsigned int num)
20 {
21 	char c;
22 
23 	if (num / 10)
24 		putnum(num / 10);
25 
26 	c = '0' + (num % 10);
27 	write(1, &c, 1);
28 }
29 
30 static int tests_run;
31 static int tests_passed;
32 static int tests_failed;
33 static int tests_skipped;
34 
35 static void print_summary(void)
36 {
37 	if (tests_passed + tests_failed + tests_skipped != EXPECTED_TESTS)
38 		putstr("# UNEXPECTED TEST COUNT: ");
39 
40 	putstr("# Totals: pass:");
41 	putnum(tests_passed);
42 	putstr(" fail:");
43 	putnum(tests_failed);
44 	putstr(" xfail:0 xpass:0 skip:");
45 	putnum(tests_skipped);
46 	putstr(" error:0\n");
47 }
48 
49 int fork_test(void);
50 int verify_fork(void);
51 
52 /*
53  * If we fork the value in the parent should be unchanged and the
54  * child should start with the same value.  This is called from the
55  * fork_test() asm function.
56  */
57 int fork_test_c(void)
58 {
59 	pid_t newpid, waiting;
60 	int child_status, parent_result;
61 
62 	newpid = fork();
63 	if (newpid == 0) {
64 		/* In child */
65 		if (!verify_fork()) {
66 			putstr("# ZA state invalid in child\n");
67 			exit(0);
68 		} else {
69 			exit(1);
70 		}
71 	}
72 	if (newpid < 0) {
73 		putstr("# fork() failed: -");
74 		putnum(-newpid);
75 		putstr("\n");
76 		return 0;
77 	}
78 
79 	parent_result = verify_fork();
80 	if (!parent_result)
81 		putstr("# ZA state invalid in parent\n");
82 
83 	for (;;) {
84 		waiting = waitpid(newpid, &child_status, 0);
85 
86 		if (waiting < 0) {
87 			if (errno == EINTR)
88 				continue;
89 			putstr("# waitpid() failed: ");
90 			putnum(errno);
91 			putstr("\n");
92 			return 0;
93 		}
94 		if (waiting != newpid) {
95 			putstr("# waitpid() returned wrong PID\n");
96 			return 0;
97 		}
98 
99 		if (!WIFEXITED(child_status)) {
100 			putstr("# child did not exit\n");
101 			return 0;
102 		}
103 
104 		return WEXITSTATUS(child_status) && parent_result;
105 	}
106 }
107 
108 #define run_test(name)			     \
109 	if (name()) {			     \
110 		tests_passed++;		     \
111 	} else {			     \
112 		tests_failed++;		     \
113 		putstr("not ");		     \
114 	}				     \
115 	putstr("ok ");			     \
116 	putnum(++tests_run);		     \
117 	putstr(" " #name "\n");
118 
119 int main(int argc, char **argv)
120 {
121 	int ret, i;
122 
123 	putstr("TAP version 13\n");
124 	putstr("1..");
125 	putnum(EXPECTED_TESTS);
126 	putstr("\n");
127 
128 	putstr("# PID: ");
129 	putnum(getpid());
130 	putstr("\n");
131 
132 	/*
133 	 * This test is run with nolibc which doesn't support hwcap and
134 	 * it's probably disproportionate to implement so instead check
135 	 * for the default vector length configuration in /proc.
136 	 */
137 	ret = open("/proc/sys/abi/sme_default_vector_length", O_RDONLY, 0);
138 	if (ret >= 0) {
139 		run_test(fork_test);
140 
141 	} else {
142 		putstr("# SME support not present\n");
143 
144 		for (i = 0; i < EXPECTED_TESTS; i++) {
145 			putstr("ok ");
146 			putnum(i);
147 			putstr(" skipped\n");
148 		}
149 
150 		tests_skipped += EXPECTED_TESTS;
151 	}
152 
153 	print_summary();
154 
155 	return 0;
156 }
157