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
putstr(const char * str)14 static void putstr(const char *str)
15 {
16 write(1, str, strlen(str));
17 }
18
putnum(unsigned int num)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
print_summary(void)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 */
fork_test_c(void)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
main(int argc,char ** argv)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