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 mops_sigill(void)
43 {
44 	char dst[1], src[1];
45 	register char *dstp asm ("x0") = dst;
46 	register char *srcp asm ("x1") = src;
47 	register long size asm ("x2") = 1;
48 
49 	/* CPYP [x0]!, [x1]!, x2! */
50 	asm volatile(".inst 0x1d010440"
51 		     : "+r" (dstp), "+r" (srcp), "+r" (size)
52 		     :
53 		     : "cc", "memory");
54 }
55 
56 static void rng_sigill(void)
57 {
58 	asm volatile("mrs x0, S3_3_C2_C4_0" : : : "x0");
59 }
60 
61 static void sme_sigill(void)
62 {
63 	/* RDSVL x0, #0 */
64 	asm volatile(".inst 0x04bf5800" : : : "x0");
65 }
66 
67 static void sme2_sigill(void)
68 {
69 	/* SMSTART ZA */
70 	asm volatile("msr S0_3_C4_C5_3, xzr" : : : );
71 
72 	/* ZERO ZT0 */
73 	asm volatile(".inst 0xc0480001" : : : );
74 
75 	/* SMSTOP */
76 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
77 }
78 
79 static void sme2p1_sigill(void)
80 {
81 	/* SMSTART SM */
82 	asm volatile("msr S0_3_C4_C3_3, xzr" : : : );
83 
84 	/* BFCLAMP { Z0.H - Z1.H }, Z0.H, Z0.H */
85 	asm volatile(".inst 0xc120C000" : : : );
86 
87 	/* SMSTOP */
88 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
89 }
90 
91 static void smei16i32_sigill(void)
92 {
93 	/* SMSTART */
94 	asm volatile("msr S0_3_C4_C7_3, xzr" : : : );
95 
96 	/* SMOPA ZA0.S, P0/M, P0/M, Z0.B, Z0.B */
97 	asm volatile(".inst 0xa0800000" : : : );
98 
99 	/* SMSTOP */
100 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
101 }
102 
103 static void smebi32i32_sigill(void)
104 {
105 	/* SMSTART */
106 	asm volatile("msr S0_3_C4_C7_3, xzr" : : : );
107 
108 	/* BMOPA ZA0.S, P0/M, P0/M, Z0.B, Z0.B */
109 	asm volatile(".inst 0x80800008" : : : );
110 
111 	/* SMSTOP */
112 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
113 }
114 
115 static void smeb16b16_sigill(void)
116 {
117 	/* SMSTART */
118 	asm volatile("msr S0_3_C4_C7_3, xzr" : : : );
119 
120 	/* BFADD ZA.H[W0, 0], {Z0.H-Z1.H} */
121 	asm volatile(".inst 0xC1E41C00" : : : );
122 
123 	/* SMSTOP */
124 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
125 }
126 
127 static void smef16f16_sigill(void)
128 {
129 	/* SMSTART */
130 	asm volatile("msr S0_3_C4_C7_3, xzr" : : : );
131 
132 	/* FADD ZA.H[W0, 0], { Z0.H-Z1.H } */
133 	asm volatile(".inst 0xc1a41C00" : : : );
134 
135 	/* SMSTOP */
136 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
137 }
138 
139 static void sve_sigill(void)
140 {
141 	/* RDVL x0, #0 */
142 	asm volatile(".inst 0x04bf5000" : : : "x0");
143 }
144 
145 static void sve2_sigill(void)
146 {
147 	/* SQABS Z0.b, P0/M, Z0.B */
148 	asm volatile(".inst 0x4408A000" : : : "z0");
149 }
150 
151 static void sve2p1_sigill(void)
152 {
153 	/* BFADD Z0.H, Z0.H, Z0.H */
154 	asm volatile(".inst 0x65000000" : : : "z0");
155 }
156 
157 static void sveaes_sigill(void)
158 {
159 	/* AESD z0.b, z0.b, z0.b */
160 	asm volatile(".inst 0x4522e400" : : : "z0");
161 }
162 
163 static void svepmull_sigill(void)
164 {
165 	/* PMULLB Z0.Q, Z0.D, Z0.D */
166 	asm volatile(".inst 0x45006800" : : : "z0");
167 }
168 
169 static void svebitperm_sigill(void)
170 {
171 	/* BDEP Z0.B, Z0.B, Z0.B */
172 	asm volatile(".inst 0x4500b400" : : : "z0");
173 }
174 
175 static void svesha3_sigill(void)
176 {
177 	/* EOR3 Z0.D, Z0.D, Z0.D, Z0.D */
178 	asm volatile(".inst 0x4203800" : : : "z0");
179 }
180 
181 static void svesm4_sigill(void)
182 {
183 	/* SM4E Z0.S, Z0.S, Z0.S */
184 	asm volatile(".inst 0x4523e000" : : : "z0");
185 }
186 
187 static void svei8mm_sigill(void)
188 {
189 	/* USDOT Z0.S, Z0.B, Z0.B[0] */
190 	asm volatile(".inst 0x44a01800" : : : "z0");
191 }
192 
193 static void svef32mm_sigill(void)
194 {
195 	/* FMMLA Z0.S, Z0.S, Z0.S */
196 	asm volatile(".inst 0x64a0e400" : : : "z0");
197 }
198 
199 static void svef64mm_sigill(void)
200 {
201 	/* FMMLA Z0.D, Z0.D, Z0.D */
202 	asm volatile(".inst 0x64e0e400" : : : "z0");
203 }
204 
205 static void svebf16_sigill(void)
206 {
207 	/* BFCVT Z0.H, P0/M, Z0.S */
208 	asm volatile(".inst 0x658aa000" : : : "z0");
209 }
210 
211 static const struct hwcap_data {
212 	const char *name;
213 	unsigned long at_hwcap;
214 	unsigned long hwcap_bit;
215 	const char *cpuinfo;
216 	sigill_fn sigill_fn;
217 	bool sigill_reliable;
218 } hwcaps[] = {
219 	{
220 		.name = "CSSC",
221 		.at_hwcap = AT_HWCAP2,
222 		.hwcap_bit = HWCAP2_CSSC,
223 		.cpuinfo = "cssc",
224 		.sigill_fn = cssc_sigill,
225 	},
226 	{
227 		.name = "MOPS",
228 		.at_hwcap = AT_HWCAP2,
229 		.hwcap_bit = HWCAP2_MOPS,
230 		.cpuinfo = "mops",
231 		.sigill_fn = mops_sigill,
232 		.sigill_reliable = true,
233 	},
234 	{
235 		.name = "RNG",
236 		.at_hwcap = AT_HWCAP2,
237 		.hwcap_bit = HWCAP2_RNG,
238 		.cpuinfo = "rng",
239 		.sigill_fn = rng_sigill,
240 	},
241 	{
242 		.name = "RPRFM",
243 		.at_hwcap = AT_HWCAP2,
244 		.hwcap_bit = HWCAP2_RPRFM,
245 		.cpuinfo = "rprfm",
246 	},
247 	{
248 		.name = "SME",
249 		.at_hwcap = AT_HWCAP2,
250 		.hwcap_bit = HWCAP2_SME,
251 		.cpuinfo = "sme",
252 		.sigill_fn = sme_sigill,
253 		.sigill_reliable = true,
254 	},
255 	{
256 		.name = "SME2",
257 		.at_hwcap = AT_HWCAP2,
258 		.hwcap_bit = HWCAP2_SME2,
259 		.cpuinfo = "sme2",
260 		.sigill_fn = sme2_sigill,
261 		.sigill_reliable = true,
262 	},
263 	{
264 		.name = "SME 2.1",
265 		.at_hwcap = AT_HWCAP2,
266 		.hwcap_bit = HWCAP2_SME2P1,
267 		.cpuinfo = "sme2p1",
268 		.sigill_fn = sme2p1_sigill,
269 	},
270 	{
271 		.name = "SME I16I32",
272 		.at_hwcap = AT_HWCAP2,
273 		.hwcap_bit = HWCAP2_SME_I16I32,
274 		.cpuinfo = "smei16i32",
275 		.sigill_fn = smei16i32_sigill,
276 	},
277 	{
278 		.name = "SME BI32I32",
279 		.at_hwcap = AT_HWCAP2,
280 		.hwcap_bit = HWCAP2_SME_BI32I32,
281 		.cpuinfo = "smebi32i32",
282 		.sigill_fn = smebi32i32_sigill,
283 	},
284 	{
285 		.name = "SME B16B16",
286 		.at_hwcap = AT_HWCAP2,
287 		.hwcap_bit = HWCAP2_SME_B16B16,
288 		.cpuinfo = "smeb16b16",
289 		.sigill_fn = smeb16b16_sigill,
290 	},
291 	{
292 		.name = "SME F16F16",
293 		.at_hwcap = AT_HWCAP2,
294 		.hwcap_bit = HWCAP2_SME_F16F16,
295 		.cpuinfo = "smef16f16",
296 		.sigill_fn = smef16f16_sigill,
297 	},
298 	{
299 		.name = "SVE",
300 		.at_hwcap = AT_HWCAP,
301 		.hwcap_bit = HWCAP_SVE,
302 		.cpuinfo = "sve",
303 		.sigill_fn = sve_sigill,
304 		.sigill_reliable = true,
305 	},
306 	{
307 		.name = "SVE 2",
308 		.at_hwcap = AT_HWCAP2,
309 		.hwcap_bit = HWCAP2_SVE2,
310 		.cpuinfo = "sve2",
311 		.sigill_fn = sve2_sigill,
312 	},
313 	{
314 		.name = "SVE 2.1",
315 		.at_hwcap = AT_HWCAP2,
316 		.hwcap_bit = HWCAP2_SVE2P1,
317 		.cpuinfo = "sve2p1",
318 		.sigill_fn = sve2p1_sigill,
319 	},
320 	{
321 		.name = "SVE AES",
322 		.at_hwcap = AT_HWCAP2,
323 		.hwcap_bit = HWCAP2_SVEAES,
324 		.cpuinfo = "sveaes",
325 		.sigill_fn = sveaes_sigill,
326 	},
327 	{
328 		.name = "SVE2 PMULL",
329 		.at_hwcap = AT_HWCAP2,
330 		.hwcap_bit = HWCAP2_SVEPMULL,
331 		.cpuinfo = "svepmull",
332 		.sigill_fn = svepmull_sigill,
333 	},
334 	{
335 		.name = "SVE2 BITPERM",
336 		.at_hwcap = AT_HWCAP2,
337 		.hwcap_bit = HWCAP2_SVEBITPERM,
338 		.cpuinfo = "svebitperm",
339 		.sigill_fn = svebitperm_sigill,
340 	},
341 	{
342 		.name = "SVE2 SHA3",
343 		.at_hwcap = AT_HWCAP2,
344 		.hwcap_bit = HWCAP2_SVESHA3,
345 		.cpuinfo = "svesha3",
346 		.sigill_fn = svesha3_sigill,
347 	},
348 	{
349 		.name = "SVE2 SM4",
350 		.at_hwcap = AT_HWCAP2,
351 		.hwcap_bit = HWCAP2_SVESM4,
352 		.cpuinfo = "svesm4",
353 		.sigill_fn = svesm4_sigill,
354 	},
355 	{
356 		.name = "SVE2 I8MM",
357 		.at_hwcap = AT_HWCAP2,
358 		.hwcap_bit = HWCAP2_SVEI8MM,
359 		.cpuinfo = "svei8mm",
360 		.sigill_fn = svei8mm_sigill,
361 	},
362 	{
363 		.name = "SVE2 F32MM",
364 		.at_hwcap = AT_HWCAP2,
365 		.hwcap_bit = HWCAP2_SVEF32MM,
366 		.cpuinfo = "svef32mm",
367 		.sigill_fn = svef32mm_sigill,
368 	},
369 	{
370 		.name = "SVE2 F64MM",
371 		.at_hwcap = AT_HWCAP2,
372 		.hwcap_bit = HWCAP2_SVEF64MM,
373 		.cpuinfo = "svef64mm",
374 		.sigill_fn = svef64mm_sigill,
375 	},
376 	{
377 		.name = "SVE2 BF16",
378 		.at_hwcap = AT_HWCAP2,
379 		.hwcap_bit = HWCAP2_SVEBF16,
380 		.cpuinfo = "svebf16",
381 		.sigill_fn = svebf16_sigill,
382 	},
383 	{
384 		.name = "SVE2 EBF16",
385 		.at_hwcap = AT_HWCAP2,
386 		.hwcap_bit = HWCAP2_SVE_EBF16,
387 		.cpuinfo = "sveebf16",
388 	},
389 };
390 
391 static bool seen_sigill;
392 
393 static void handle_sigill(int sig, siginfo_t *info, void *context)
394 {
395 	ucontext_t *uc = context;
396 
397 	seen_sigill = true;
398 
399 	/* Skip over the offending instruction */
400 	uc->uc_mcontext.pc += 4;
401 }
402 
403 bool cpuinfo_present(const char *name)
404 {
405 	FILE *f;
406 	char buf[2048], name_space[30], name_newline[30];
407 	char *s;
408 
409 	/*
410 	 * The feature should appear with a leading space and either a
411 	 * trailing space or a newline.
412 	 */
413 	snprintf(name_space, sizeof(name_space), " %s ", name);
414 	snprintf(name_newline, sizeof(name_newline), " %s\n", name);
415 
416 	f = fopen("/proc/cpuinfo", "r");
417 	if (!f) {
418 		ksft_print_msg("Failed to open /proc/cpuinfo\n");
419 		return false;
420 	}
421 
422 	while (fgets(buf, sizeof(buf), f)) {
423 		/* Features: line? */
424 		if (strncmp(buf, "Features\t:", strlen("Features\t:")) != 0)
425 			continue;
426 
427 		/* All CPUs should be symmetric, don't read any more */
428 		fclose(f);
429 
430 		s = strstr(buf, name_space);
431 		if (s)
432 			return true;
433 		s = strstr(buf, name_newline);
434 		if (s)
435 			return true;
436 
437 		return false;
438 	}
439 
440 	ksft_print_msg("Failed to find Features in /proc/cpuinfo\n");
441 	fclose(f);
442 	return false;
443 }
444 
445 int main(void)
446 {
447 	const struct hwcap_data *hwcap;
448 	int i, ret;
449 	bool have_cpuinfo, have_hwcap;
450 	struct sigaction sa;
451 
452 	ksft_print_header();
453 	ksft_set_plan(ARRAY_SIZE(hwcaps) * TESTS_PER_HWCAP);
454 
455 	memset(&sa, 0, sizeof(sa));
456 	sa.sa_sigaction = handle_sigill;
457 	sa.sa_flags = SA_RESTART | SA_SIGINFO;
458 	sigemptyset(&sa.sa_mask);
459 	ret = sigaction(SIGILL, &sa, NULL);
460 	if (ret < 0)
461 		ksft_exit_fail_msg("Failed to install SIGILL handler: %s (%d)\n",
462 				   strerror(errno), errno);
463 
464 	for (i = 0; i < ARRAY_SIZE(hwcaps); i++) {
465 		hwcap = &hwcaps[i];
466 
467 		have_hwcap = getauxval(hwcap->at_hwcap) & hwcap->hwcap_bit;
468 		have_cpuinfo = cpuinfo_present(hwcap->cpuinfo);
469 
470 		if (have_hwcap)
471 			ksft_print_msg("%s present\n", hwcap->name);
472 
473 		ksft_test_result(have_hwcap == have_cpuinfo,
474 				 "cpuinfo_match_%s\n", hwcap->name);
475 
476 		if (hwcap->sigill_fn) {
477 			seen_sigill = false;
478 			hwcap->sigill_fn();
479 
480 			if (have_hwcap) {
481 				/* Should be able to use the extension */
482 				ksft_test_result(!seen_sigill, "sigill_%s\n",
483 						 hwcap->name);
484 			} else if (hwcap->sigill_reliable) {
485 				/* Guaranteed a SIGILL */
486 				ksft_test_result(seen_sigill, "sigill_%s\n",
487 						 hwcap->name);
488 			} else {
489 				/* Missing SIGILL might be fine */
490 				ksft_print_msg("SIGILL %sreported for %s\n",
491 					       seen_sigill ? "" : "not ",
492 					       hwcap->name);
493 				ksft_test_result_skip("sigill_%s\n",
494 						      hwcap->name);
495 			}
496 		} else {
497 			ksft_test_result_skip("sigill_%s\n",
498 					      hwcap->name);
499 		}
500 	}
501 
502 	ksft_print_cnts();
503 
504 	return 0;
505 }
506