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