1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2022 ARM Limited.
4  */
5 
6 #include <errno.h>
7 #include <signal.h>
8 #include <stdbool.h>
9 #include <stddef.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <sys/auxv.h>
15 #include <sys/prctl.h>
16 #include <asm/hwcap.h>
17 #include <asm/sigcontext.h>
18 #include <asm/unistd.h>
19 
20 #include "../../kselftest.h"
21 
22 #define TESTS_PER_HWCAP 2
23 
24 /*
25  * Function expected to generate SIGILL when the feature is not
26  * supported and return when it is supported. If SIGILL is generated
27  * then the handler must be able to skip over the instruction safely.
28  *
29  * Note that it is expected that for many architecture extensions
30  * there are no specific traps due to no architecture state being
31  * added so we may not fault if running on a kernel which doesn't know
32  * to add the hwcap.
33  */
34 typedef void (*sigill_fn)(void);
35 
36 static void cssc_sigill(void)
37 {
38 	/* CNT x0, x0 */
39 	asm volatile(".inst 0xdac01c00" : : : "x0");
40 }
41 
42 static void rng_sigill(void)
43 {
44 	asm volatile("mrs x0, S3_3_C2_C4_0" : : : "x0");
45 }
46 
47 static void sme_sigill(void)
48 {
49 	/* RDSVL x0, #0 */
50 	asm volatile(".inst 0x04bf5800" : : : "x0");
51 }
52 
53 static void sve_sigill(void)
54 {
55 	/* RDVL x0, #0 */
56 	asm volatile(".inst 0x04bf5000" : : : "x0");
57 }
58 
59 static void sve2_sigill(void)
60 {
61 	/* SQABS Z0.b, P0/M, Z0.B */
62 	asm volatile(".inst 0x4408A000" : : : "z0");
63 }
64 
65 static void sve2p1_sigill(void)
66 {
67 	/* BFADD Z0.H, Z0.H, Z0.H */
68 	asm volatile(".inst 0x65000000" : : : "z0");
69 }
70 
71 static void sveaes_sigill(void)
72 {
73 	/* AESD z0.b, z0.b, z0.b */
74 	asm volatile(".inst 0x4522e400" : : : "z0");
75 }
76 
77 static void svepmull_sigill(void)
78 {
79 	/* PMULLB Z0.Q, Z0.D, Z0.D */
80 	asm volatile(".inst 0x45006800" : : : "z0");
81 }
82 
83 static void svebitperm_sigill(void)
84 {
85 	/* BDEP Z0.B, Z0.B, Z0.B */
86 	asm volatile(".inst 0x4500b400" : : : "z0");
87 }
88 
89 static void svesha3_sigill(void)
90 {
91 	/* EOR3 Z0.D, Z0.D, Z0.D, Z0.D */
92 	asm volatile(".inst 0x4203800" : : : "z0");
93 }
94 
95 static void svesm4_sigill(void)
96 {
97 	/* SM4E Z0.S, Z0.S, Z0.S */
98 	asm volatile(".inst 0x4523e000" : : : "z0");
99 }
100 
101 static void svei8mm_sigill(void)
102 {
103 	/* USDOT Z0.S, Z0.B, Z0.B[0] */
104 	asm volatile(".inst 0x44a01800" : : : "z0");
105 }
106 
107 static void svef32mm_sigill(void)
108 {
109 	/* FMMLA Z0.S, Z0.S, Z0.S */
110 	asm volatile(".inst 0x64a0e400" : : : "z0");
111 }
112 
113 static void svef64mm_sigill(void)
114 {
115 	/* FMMLA Z0.D, Z0.D, Z0.D */
116 	asm volatile(".inst 0x64e0e400" : : : "z0");
117 }
118 
119 static void svebf16_sigill(void)
120 {
121 	/* BFCVT Z0.H, P0/M, Z0.S */
122 	asm volatile(".inst 0x658aa000" : : : "z0");
123 }
124 
125 static const struct hwcap_data {
126 	const char *name;
127 	unsigned long at_hwcap;
128 	unsigned long hwcap_bit;
129 	const char *cpuinfo;
130 	sigill_fn sigill_fn;
131 	bool sigill_reliable;
132 } hwcaps[] = {
133 	{
134 		.name = "CSSC",
135 		.at_hwcap = AT_HWCAP2,
136 		.hwcap_bit = HWCAP2_CSSC,
137 		.cpuinfo = "cssc",
138 		.sigill_fn = cssc_sigill,
139 	},
140 	{
141 		.name = "RNG",
142 		.at_hwcap = AT_HWCAP2,
143 		.hwcap_bit = HWCAP2_RNG,
144 		.cpuinfo = "rng",
145 		.sigill_fn = rng_sigill,
146 	},
147 	{
148 		.name = "RPRFM",
149 		.at_hwcap = AT_HWCAP2,
150 		.hwcap_bit = HWCAP2_RPRFM,
151 		.cpuinfo = "rprfm",
152 	},
153 	{
154 		.name = "SME",
155 		.at_hwcap = AT_HWCAP2,
156 		.hwcap_bit = HWCAP2_SME,
157 		.cpuinfo = "sme",
158 		.sigill_fn = sme_sigill,
159 		.sigill_reliable = true,
160 	},
161 	{
162 		.name = "SVE",
163 		.at_hwcap = AT_HWCAP,
164 		.hwcap_bit = HWCAP_SVE,
165 		.cpuinfo = "sve",
166 		.sigill_fn = sve_sigill,
167 		.sigill_reliable = true,
168 	},
169 	{
170 		.name = "SVE 2",
171 		.at_hwcap = AT_HWCAP2,
172 		.hwcap_bit = HWCAP2_SVE2,
173 		.cpuinfo = "sve2",
174 		.sigill_fn = sve2_sigill,
175 	},
176 	{
177 		.name = "SVE 2.1",
178 		.at_hwcap = AT_HWCAP2,
179 		.hwcap_bit = HWCAP2_SVE2P1,
180 		.cpuinfo = "sve2p1",
181 		.sigill_fn = sve2p1_sigill,
182 	},
183 	{
184 		.name = "SVE AES",
185 		.at_hwcap = AT_HWCAP2,
186 		.hwcap_bit = HWCAP2_SVEAES,
187 		.cpuinfo = "sveaes",
188 		.sigill_fn = sveaes_sigill,
189 	},
190 	{
191 		.name = "SVE2 PMULL",
192 		.at_hwcap = AT_HWCAP2,
193 		.hwcap_bit = HWCAP2_SVEPMULL,
194 		.cpuinfo = "svepmull",
195 		.sigill_fn = svepmull_sigill,
196 	},
197 	{
198 		.name = "SVE2 BITPERM",
199 		.at_hwcap = AT_HWCAP2,
200 		.hwcap_bit = HWCAP2_SVEBITPERM,
201 		.cpuinfo = "svebitperm",
202 		.sigill_fn = svebitperm_sigill,
203 	},
204 	{
205 		.name = "SVE2 SHA3",
206 		.at_hwcap = AT_HWCAP2,
207 		.hwcap_bit = HWCAP2_SVESHA3,
208 		.cpuinfo = "svesha3",
209 		.sigill_fn = svesha3_sigill,
210 	},
211 	{
212 		.name = "SVE2 SM4",
213 		.at_hwcap = AT_HWCAP2,
214 		.hwcap_bit = HWCAP2_SVESM4,
215 		.cpuinfo = "svesm4",
216 		.sigill_fn = svesm4_sigill,
217 	},
218 	{
219 		.name = "SVE2 I8MM",
220 		.at_hwcap = AT_HWCAP2,
221 		.hwcap_bit = HWCAP2_SVEI8MM,
222 		.cpuinfo = "svei8mm",
223 		.sigill_fn = svei8mm_sigill,
224 	},
225 	{
226 		.name = "SVE2 F32MM",
227 		.at_hwcap = AT_HWCAP2,
228 		.hwcap_bit = HWCAP2_SVEF32MM,
229 		.cpuinfo = "svef32mm",
230 		.sigill_fn = svef32mm_sigill,
231 	},
232 	{
233 		.name = "SVE2 F64MM",
234 		.at_hwcap = AT_HWCAP2,
235 		.hwcap_bit = HWCAP2_SVEF64MM,
236 		.cpuinfo = "svef64mm",
237 		.sigill_fn = svef64mm_sigill,
238 	},
239 	{
240 		.name = "SVE2 BF16",
241 		.at_hwcap = AT_HWCAP2,
242 		.hwcap_bit = HWCAP2_SVEBF16,
243 		.cpuinfo = "svebf16",
244 		.sigill_fn = svebf16_sigill,
245 	},
246 	{
247 		.name = "SVE2 EBF16",
248 		.at_hwcap = AT_HWCAP2,
249 		.hwcap_bit = HWCAP2_SVE_EBF16,
250 		.cpuinfo = "sveebf16",
251 	},
252 };
253 
254 static bool seen_sigill;
255 
256 static void handle_sigill(int sig, siginfo_t *info, void *context)
257 {
258 	ucontext_t *uc = context;
259 
260 	seen_sigill = true;
261 
262 	/* Skip over the offending instruction */
263 	uc->uc_mcontext.pc += 4;
264 }
265 
266 bool cpuinfo_present(const char *name)
267 {
268 	FILE *f;
269 	char buf[2048], name_space[30], name_newline[30];
270 	char *s;
271 
272 	/*
273 	 * The feature should appear with a leading space and either a
274 	 * trailing space or a newline.
275 	 */
276 	snprintf(name_space, sizeof(name_space), " %s ", name);
277 	snprintf(name_newline, sizeof(name_newline), " %s\n", name);
278 
279 	f = fopen("/proc/cpuinfo", "r");
280 	if (!f) {
281 		ksft_print_msg("Failed to open /proc/cpuinfo\n");
282 		return false;
283 	}
284 
285 	while (fgets(buf, sizeof(buf), f)) {
286 		/* Features: line? */
287 		if (strncmp(buf, "Features\t:", strlen("Features\t:")) != 0)
288 			continue;
289 
290 		/* All CPUs should be symmetric, don't read any more */
291 		fclose(f);
292 
293 		s = strstr(buf, name_space);
294 		if (s)
295 			return true;
296 		s = strstr(buf, name_newline);
297 		if (s)
298 			return true;
299 
300 		return false;
301 	}
302 
303 	ksft_print_msg("Failed to find Features in /proc/cpuinfo\n");
304 	fclose(f);
305 	return false;
306 }
307 
308 int main(void)
309 {
310 	const struct hwcap_data *hwcap;
311 	int i, ret;
312 	bool have_cpuinfo, have_hwcap;
313 	struct sigaction sa;
314 
315 	ksft_print_header();
316 	ksft_set_plan(ARRAY_SIZE(hwcaps) * TESTS_PER_HWCAP);
317 
318 	memset(&sa, 0, sizeof(sa));
319 	sa.sa_sigaction = handle_sigill;
320 	sa.sa_flags = SA_RESTART | SA_SIGINFO;
321 	sigemptyset(&sa.sa_mask);
322 	ret = sigaction(SIGILL, &sa, NULL);
323 	if (ret < 0)
324 		ksft_exit_fail_msg("Failed to install SIGILL handler: %s (%d)\n",
325 				   strerror(errno), errno);
326 
327 	for (i = 0; i < ARRAY_SIZE(hwcaps); i++) {
328 		hwcap = &hwcaps[i];
329 
330 		have_hwcap = getauxval(hwcap->at_hwcap) & hwcap->hwcap_bit;
331 		have_cpuinfo = cpuinfo_present(hwcap->cpuinfo);
332 
333 		if (have_hwcap)
334 			ksft_print_msg("%s present\n", hwcap->name);
335 
336 		ksft_test_result(have_hwcap == have_cpuinfo,
337 				 "cpuinfo_match_%s\n", hwcap->name);
338 
339 		if (hwcap->sigill_fn) {
340 			seen_sigill = false;
341 			hwcap->sigill_fn();
342 
343 			if (have_hwcap) {
344 				/* Should be able to use the extension */
345 				ksft_test_result(!seen_sigill, "sigill_%s\n",
346 						 hwcap->name);
347 			} else if (hwcap->sigill_reliable) {
348 				/* Guaranteed a SIGILL */
349 				ksft_test_result(seen_sigill, "sigill_%s\n",
350 						 hwcap->name);
351 			} else {
352 				/* Missing SIGILL might be fine */
353 				ksft_print_msg("SIGILL %sreported for %s\n",
354 					       seen_sigill ? "" : "not ",
355 					       hwcap->name);
356 				ksft_test_result_skip("sigill_%s\n",
357 						      hwcap->name);
358 			}
359 		} else {
360 			ksft_test_result_skip("sigill_%s\n",
361 					      hwcap->name);
362 		}
363 	}
364 
365 	ksft_print_cnts();
366 
367 	return 0;
368 }
369