xref: /linux/tools/testing/selftests/arm64/abi/hwcap.c (revision 1e525507)
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 3
23 
24 /*
25  * Function expected to generate exception when the feature is not
26  * supported and return when it is supported. If the specific exception
27  * is generated then the handler must be able to skip over the
28  * instruction safely.
29  *
30  * Note that it is expected that for many architecture extensions
31  * there are no specific traps due to no architecture state being
32  * added so we may not fault if running on a kernel which doesn't know
33  * to add the hwcap.
34  */
35 typedef void (*sig_fn)(void);
36 
37 static void aes_sigill(void)
38 {
39 	/* AESE V0.16B, V0.16B */
40 	asm volatile(".inst 0x4e284800" : : : );
41 }
42 
43 static void atomics_sigill(void)
44 {
45 	/* STADD W0, [SP] */
46 	asm volatile(".inst 0xb82003ff" : : : );
47 }
48 
49 static void crc32_sigill(void)
50 {
51 	/* CRC32W W0, W0, W1 */
52 	asm volatile(".inst 0x1ac14800" : : : );
53 }
54 
55 static void cssc_sigill(void)
56 {
57 	/* CNT x0, x0 */
58 	asm volatile(".inst 0xdac01c00" : : : "x0");
59 }
60 
61 static void f8cvt_sigill(void)
62 {
63 	/* FSCALE V0.4H, V0.4H, V0.4H */
64 	asm volatile(".inst 0x2ec03c00");
65 }
66 
67 static void f8dp2_sigill(void)
68 {
69 	/* FDOT V0.4H, V0.4H, V0.5H */
70 	asm volatile(".inst 0xe40fc00");
71 }
72 
73 static void f8dp4_sigill(void)
74 {
75 	/* FDOT V0.2S, V0.2S, V0.2S */
76 	asm volatile(".inst 0xe00fc00");
77 }
78 
79 static void f8fma_sigill(void)
80 {
81 	/* FMLALB V0.8H, V0.16B, V0.16B */
82 	asm volatile(".inst 0xec0fc00");
83 }
84 
85 static void faminmax_sigill(void)
86 {
87 	/* FAMIN V0.4H, V0.4H, V0.4H */
88 	asm volatile(".inst 0x2ec01c00");
89 }
90 
91 static void fp_sigill(void)
92 {
93 	asm volatile("fmov s0, #1");
94 }
95 
96 static void fpmr_sigill(void)
97 {
98 	asm volatile("mrs x0, S3_3_C4_C4_2" : : : "x0");
99 }
100 
101 static void ilrcpc_sigill(void)
102 {
103 	/* LDAPUR W0, [SP, #8] */
104 	asm volatile(".inst 0x994083e0" : : : );
105 }
106 
107 static void jscvt_sigill(void)
108 {
109 	/* FJCVTZS W0, D0 */
110 	asm volatile(".inst 0x1e7e0000" : : : );
111 }
112 
113 static void lrcpc_sigill(void)
114 {
115 	/* LDAPR W0, [SP, #0] */
116 	asm volatile(".inst 0xb8bfc3e0" : : : );
117 }
118 
119 static void lse128_sigill(void)
120 {
121 	u64 __attribute__ ((aligned (16))) mem[2] = { 10, 20 };
122 	register u64 *memp asm ("x0") = mem;
123 	register u64 val0 asm ("x1") = 5;
124 	register u64 val1 asm ("x2") = 4;
125 
126 	/* SWPP X1, X2, [X0] */
127 	asm volatile(".inst 0x19228001"
128 		     : "+r" (memp), "+r" (val0), "+r" (val1)
129 		     :
130 		     : "cc", "memory");
131 }
132 
133 static void lut_sigill(void)
134 {
135 	/* LUTI2 V0.16B, { V0.16B }, V[0] */
136 	asm volatile(".inst 0x4e801000");
137 }
138 
139 static void mops_sigill(void)
140 {
141 	char dst[1], src[1];
142 	register char *dstp asm ("x0") = dst;
143 	register char *srcp asm ("x1") = src;
144 	register long size asm ("x2") = 1;
145 
146 	/* CPYP [x0]!, [x1]!, x2! */
147 	asm volatile(".inst 0x1d010440"
148 		     : "+r" (dstp), "+r" (srcp), "+r" (size)
149 		     :
150 		     : "cc", "memory");
151 }
152 
153 static void pmull_sigill(void)
154 {
155 	/* PMULL V0.1Q, V0.1D, V0.1D */
156 	asm volatile(".inst 0x0ee0e000" : : : );
157 }
158 
159 static void rng_sigill(void)
160 {
161 	asm volatile("mrs x0, S3_3_C2_C4_0" : : : "x0");
162 }
163 
164 static void sha1_sigill(void)
165 {
166 	/* SHA1H S0, S0 */
167 	asm volatile(".inst 0x5e280800" : : : );
168 }
169 
170 static void sha2_sigill(void)
171 {
172 	/* SHA256H Q0, Q0, V0.4S */
173 	asm volatile(".inst 0x5e004000" : : : );
174 }
175 
176 static void sha512_sigill(void)
177 {
178 	/* SHA512H Q0, Q0, V0.2D */
179 	asm volatile(".inst 0xce608000" : : : );
180 }
181 
182 static void sme_sigill(void)
183 {
184 	/* RDSVL x0, #0 */
185 	asm volatile(".inst 0x04bf5800" : : : "x0");
186 }
187 
188 static void sme2_sigill(void)
189 {
190 	/* SMSTART ZA */
191 	asm volatile("msr S0_3_C4_C5_3, xzr" : : : );
192 
193 	/* ZERO ZT0 */
194 	asm volatile(".inst 0xc0480001" : : : );
195 
196 	/* SMSTOP */
197 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
198 }
199 
200 static void sme2p1_sigill(void)
201 {
202 	/* SMSTART SM */
203 	asm volatile("msr S0_3_C4_C3_3, xzr" : : : );
204 
205 	/* BFCLAMP { Z0.H - Z1.H }, Z0.H, Z0.H */
206 	asm volatile(".inst 0xc120C000" : : : );
207 
208 	/* SMSTOP */
209 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
210 }
211 
212 static void smei16i32_sigill(void)
213 {
214 	/* SMSTART */
215 	asm volatile("msr S0_3_C4_C7_3, xzr" : : : );
216 
217 	/* SMOPA ZA0.S, P0/M, P0/M, Z0.B, Z0.B */
218 	asm volatile(".inst 0xa0800000" : : : );
219 
220 	/* SMSTOP */
221 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
222 }
223 
224 static void smebi32i32_sigill(void)
225 {
226 	/* SMSTART */
227 	asm volatile("msr S0_3_C4_C7_3, xzr" : : : );
228 
229 	/* BMOPA ZA0.S, P0/M, P0/M, Z0.B, Z0.B */
230 	asm volatile(".inst 0x80800008" : : : );
231 
232 	/* SMSTOP */
233 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
234 }
235 
236 static void smeb16b16_sigill(void)
237 {
238 	/* SMSTART */
239 	asm volatile("msr S0_3_C4_C7_3, xzr" : : : );
240 
241 	/* BFADD ZA.H[W0, 0], {Z0.H-Z1.H} */
242 	asm volatile(".inst 0xC1E41C00" : : : );
243 
244 	/* SMSTOP */
245 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
246 }
247 
248 static void smef16f16_sigill(void)
249 {
250 	/* SMSTART */
251 	asm volatile("msr S0_3_C4_C7_3, xzr" : : : );
252 
253 	/* FADD ZA.H[W0, 0], { Z0.H-Z1.H } */
254 	asm volatile(".inst 0xc1a41C00" : : : );
255 
256 	/* SMSTOP */
257 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
258 }
259 
260 static void smef8f16_sigill(void)
261 {
262 	/* SMSTART */
263 	asm volatile("msr S0_3_C4_C7_3, xzr" : : : );
264 
265 	/* FDOT ZA.H[W0, 0], Z0.B-Z1.B, Z0.B-Z1.B */
266 	asm volatile(".inst 0xc1a01020" : : : );
267 
268 	/* SMSTOP */
269 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
270 }
271 
272 static void smef8f32_sigill(void)
273 {
274 	/* SMSTART */
275 	asm volatile("msr S0_3_C4_C7_3, xzr" : : : );
276 
277 	/* FDOT ZA.S[W0, 0], { Z0.B-Z1.B }, Z0.B[0] */
278 	asm volatile(".inst 0xc1500038" : : : );
279 
280 	/* SMSTOP */
281 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
282 }
283 
284 static void smelutv2_sigill(void)
285 {
286 	/* SMSTART */
287 	asm volatile("msr S0_3_C4_C7_3, xzr" : : : );
288 
289 	/* LUTI4 { Z0.B-Z3.B }, ZT0, { Z0-Z1 } */
290 	asm volatile(".inst 0xc08b0000" : : : );
291 
292 	/* SMSTOP */
293 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
294 }
295 
296 static void smesf8dp2_sigill(void)
297 {
298 	/* SMSTART */
299 	asm volatile("msr S0_3_C4_C7_3, xzr" : : : );
300 
301 	/* FDOT Z0.H, Z0.B, Z0.B[0] */
302 	asm volatile(".inst 0x64204400" : : : );
303 
304 	/* SMSTOP */
305 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
306 }
307 
308 static void smesf8dp4_sigill(void)
309 {
310 	/* SMSTART */
311 	asm volatile("msr S0_3_C4_C7_3, xzr" : : : );
312 
313 	/* FDOT Z0.S, Z0.B, Z0.B[0] */
314 	asm volatile(".inst 0xc1a41C00" : : : );
315 
316 	/* SMSTOP */
317 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
318 }
319 
320 static void smesf8fma_sigill(void)
321 {
322 	/* SMSTART */
323 	asm volatile("msr S0_3_C4_C7_3, xzr" : : : );
324 
325 	/* FMLALB V0.8H, V0.16B, V0.16B */
326 	asm volatile(".inst 0xec0fc00");
327 
328 	/* SMSTOP */
329 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
330 }
331 
332 static void sve_sigill(void)
333 {
334 	/* RDVL x0, #0 */
335 	asm volatile(".inst 0x04bf5000" : : : "x0");
336 }
337 
338 static void sve2_sigill(void)
339 {
340 	/* SQABS Z0.b, P0/M, Z0.B */
341 	asm volatile(".inst 0x4408A000" : : : "z0");
342 }
343 
344 static void sve2p1_sigill(void)
345 {
346 	/* BFADD Z0.H, Z0.H, Z0.H */
347 	asm volatile(".inst 0x65000000" : : : "z0");
348 }
349 
350 static void sveaes_sigill(void)
351 {
352 	/* AESD z0.b, z0.b, z0.b */
353 	asm volatile(".inst 0x4522e400" : : : "z0");
354 }
355 
356 static void sveb16b16_sigill(void)
357 {
358 	/* BFADD ZA.H[W0, 0], {Z0.H-Z1.H} */
359 	asm volatile(".inst 0xC1E41C00" : : : );
360 }
361 
362 static void svepmull_sigill(void)
363 {
364 	/* PMULLB Z0.Q, Z0.D, Z0.D */
365 	asm volatile(".inst 0x45006800" : : : "z0");
366 }
367 
368 static void svebitperm_sigill(void)
369 {
370 	/* BDEP Z0.B, Z0.B, Z0.B */
371 	asm volatile(".inst 0x4500b400" : : : "z0");
372 }
373 
374 static void svesha3_sigill(void)
375 {
376 	/* EOR3 Z0.D, Z0.D, Z0.D, Z0.D */
377 	asm volatile(".inst 0x4203800" : : : "z0");
378 }
379 
380 static void svesm4_sigill(void)
381 {
382 	/* SM4E Z0.S, Z0.S, Z0.S */
383 	asm volatile(".inst 0x4523e000" : : : "z0");
384 }
385 
386 static void svei8mm_sigill(void)
387 {
388 	/* USDOT Z0.S, Z0.B, Z0.B[0] */
389 	asm volatile(".inst 0x44a01800" : : : "z0");
390 }
391 
392 static void svef32mm_sigill(void)
393 {
394 	/* FMMLA Z0.S, Z0.S, Z0.S */
395 	asm volatile(".inst 0x64a0e400" : : : "z0");
396 }
397 
398 static void svef64mm_sigill(void)
399 {
400 	/* FMMLA Z0.D, Z0.D, Z0.D */
401 	asm volatile(".inst 0x64e0e400" : : : "z0");
402 }
403 
404 static void svebf16_sigill(void)
405 {
406 	/* BFCVT Z0.H, P0/M, Z0.S */
407 	asm volatile(".inst 0x658aa000" : : : "z0");
408 }
409 
410 static void hbc_sigill(void)
411 {
412 	/* BC.EQ +4 */
413 	asm volatile("cmp xzr, xzr\n"
414 		     ".inst 0x54000030" : : : "cc");
415 }
416 
417 static void uscat_sigbus(void)
418 {
419 	/* unaligned atomic access */
420 	asm volatile("ADD x1, sp, #2" : : : );
421 	/* STADD W0, [X1] */
422 	asm volatile(".inst 0xb820003f" : : : );
423 }
424 
425 static void lrcpc3_sigill(void)
426 {
427 	int data[2] = { 1, 2 };
428 
429 	register int *src asm ("x0") = data;
430 	register int data0 asm ("w2") = 0;
431 	register int data1 asm ("w3") = 0;
432 
433 	/* LDIAPP w2, w3, [x0] */
434 	asm volatile(".inst 0x99431802"
435 	              : "=r" (data0), "=r" (data1) : "r" (src) :);
436 }
437 
438 static const struct hwcap_data {
439 	const char *name;
440 	unsigned long at_hwcap;
441 	unsigned long hwcap_bit;
442 	const char *cpuinfo;
443 	sig_fn sigill_fn;
444 	bool sigill_reliable;
445 	sig_fn sigbus_fn;
446 	bool sigbus_reliable;
447 } hwcaps[] = {
448 	{
449 		.name = "AES",
450 		.at_hwcap = AT_HWCAP,
451 		.hwcap_bit = HWCAP_AES,
452 		.cpuinfo = "aes",
453 		.sigill_fn = aes_sigill,
454 	},
455 	{
456 		.name = "CRC32",
457 		.at_hwcap = AT_HWCAP,
458 		.hwcap_bit = HWCAP_CRC32,
459 		.cpuinfo = "crc32",
460 		.sigill_fn = crc32_sigill,
461 	},
462 	{
463 		.name = "CSSC",
464 		.at_hwcap = AT_HWCAP2,
465 		.hwcap_bit = HWCAP2_CSSC,
466 		.cpuinfo = "cssc",
467 		.sigill_fn = cssc_sigill,
468 	},
469 	{
470 		.name = "F8CVT",
471 		.at_hwcap = AT_HWCAP2,
472 		.hwcap_bit = HWCAP2_F8CVT,
473 		.cpuinfo = "f8cvt",
474 		.sigill_fn = f8cvt_sigill,
475 	},
476 	{
477 		.name = "F8DP4",
478 		.at_hwcap = AT_HWCAP2,
479 		.hwcap_bit = HWCAP2_F8DP4,
480 		.cpuinfo = "f8dp4",
481 		.sigill_fn = f8dp4_sigill,
482 	},
483 	{
484 		.name = "F8DP2",
485 		.at_hwcap = AT_HWCAP2,
486 		.hwcap_bit = HWCAP2_F8DP2,
487 		.cpuinfo = "f8dp4",
488 		.sigill_fn = f8dp2_sigill,
489 	},
490 	{
491 		.name = "F8E5M2",
492 		.at_hwcap = AT_HWCAP2,
493 		.hwcap_bit = HWCAP2_F8E5M2,
494 		.cpuinfo = "f8e5m2",
495 	},
496 	{
497 		.name = "F8E4M3",
498 		.at_hwcap = AT_HWCAP2,
499 		.hwcap_bit = HWCAP2_F8E4M3,
500 		.cpuinfo = "f8e4m3",
501 	},
502 	{
503 		.name = "F8FMA",
504 		.at_hwcap = AT_HWCAP2,
505 		.hwcap_bit = HWCAP2_F8FMA,
506 		.cpuinfo = "f8fma",
507 		.sigill_fn = f8fma_sigill,
508 	},
509 	{
510 		.name = "FAMINMAX",
511 		.at_hwcap = AT_HWCAP2,
512 		.hwcap_bit = HWCAP2_FAMINMAX,
513 		.cpuinfo = "faminmax",
514 		.sigill_fn = faminmax_sigill,
515 	},
516 	{
517 		.name = "FP",
518 		.at_hwcap = AT_HWCAP,
519 		.hwcap_bit = HWCAP_FP,
520 		.cpuinfo = "fp",
521 		.sigill_fn = fp_sigill,
522 	},
523 	{
524 		.name = "FPMR",
525 		.at_hwcap = AT_HWCAP2,
526 		.hwcap_bit = HWCAP2_FPMR,
527 		.cpuinfo = "fpmr",
528 		.sigill_fn = fpmr_sigill,
529 		.sigill_reliable = true,
530 	},
531 	{
532 		.name = "JSCVT",
533 		.at_hwcap = AT_HWCAP,
534 		.hwcap_bit = HWCAP_JSCVT,
535 		.cpuinfo = "jscvt",
536 		.sigill_fn = jscvt_sigill,
537 	},
538 	{
539 		.name = "LRCPC",
540 		.at_hwcap = AT_HWCAP,
541 		.hwcap_bit = HWCAP_LRCPC,
542 		.cpuinfo = "lrcpc",
543 		.sigill_fn = lrcpc_sigill,
544 	},
545 	{
546 		.name = "LRCPC2",
547 		.at_hwcap = AT_HWCAP,
548 		.hwcap_bit = HWCAP_ILRCPC,
549 		.cpuinfo = "ilrcpc",
550 		.sigill_fn = ilrcpc_sigill,
551 	},
552 	{
553 		.name = "LRCPC3",
554 		.at_hwcap = AT_HWCAP2,
555 		.hwcap_bit = HWCAP2_LRCPC3,
556 		.cpuinfo = "lrcpc3",
557 		.sigill_fn = lrcpc3_sigill,
558 	},
559 	{
560 		.name = "LSE",
561 		.at_hwcap = AT_HWCAP,
562 		.hwcap_bit = HWCAP_ATOMICS,
563 		.cpuinfo = "atomics",
564 		.sigill_fn = atomics_sigill,
565 	},
566 	{
567 		.name = "LSE2",
568 		.at_hwcap = AT_HWCAP,
569 		.hwcap_bit = HWCAP_USCAT,
570 		.cpuinfo = "uscat",
571 		.sigill_fn = atomics_sigill,
572 		.sigbus_fn = uscat_sigbus,
573 		.sigbus_reliable = true,
574 	},
575 	{
576 		.name = "LSE128",
577 		.at_hwcap = AT_HWCAP2,
578 		.hwcap_bit = HWCAP2_LSE128,
579 		.cpuinfo = "lse128",
580 		.sigill_fn = lse128_sigill,
581 	},
582 	{
583 		.name = "LUT",
584 		.at_hwcap = AT_HWCAP2,
585 		.hwcap_bit = HWCAP2_LUT,
586 		.cpuinfo = "lut",
587 		.sigill_fn = lut_sigill,
588 	},
589 	{
590 		.name = "MOPS",
591 		.at_hwcap = AT_HWCAP2,
592 		.hwcap_bit = HWCAP2_MOPS,
593 		.cpuinfo = "mops",
594 		.sigill_fn = mops_sigill,
595 		.sigill_reliable = true,
596 	},
597 	{
598 		.name = "PMULL",
599 		.at_hwcap = AT_HWCAP,
600 		.hwcap_bit = HWCAP_PMULL,
601 		.cpuinfo = "pmull",
602 		.sigill_fn = pmull_sigill,
603 	},
604 	{
605 		.name = "RNG",
606 		.at_hwcap = AT_HWCAP2,
607 		.hwcap_bit = HWCAP2_RNG,
608 		.cpuinfo = "rng",
609 		.sigill_fn = rng_sigill,
610 	},
611 	{
612 		.name = "RPRFM",
613 		.at_hwcap = AT_HWCAP2,
614 		.hwcap_bit = HWCAP2_RPRFM,
615 		.cpuinfo = "rprfm",
616 	},
617 	{
618 		.name = "SHA1",
619 		.at_hwcap = AT_HWCAP,
620 		.hwcap_bit = HWCAP_SHA1,
621 		.cpuinfo = "sha1",
622 		.sigill_fn = sha1_sigill,
623 	},
624 	{
625 		.name = "SHA2",
626 		.at_hwcap = AT_HWCAP,
627 		.hwcap_bit = HWCAP_SHA2,
628 		.cpuinfo = "sha2",
629 		.sigill_fn = sha2_sigill,
630 	},
631 	{
632 		.name = "SHA512",
633 		.at_hwcap = AT_HWCAP,
634 		.hwcap_bit = HWCAP_SHA512,
635 		.cpuinfo = "sha512",
636 		.sigill_fn = sha512_sigill,
637 	},
638 	{
639 		.name = "SME",
640 		.at_hwcap = AT_HWCAP2,
641 		.hwcap_bit = HWCAP2_SME,
642 		.cpuinfo = "sme",
643 		.sigill_fn = sme_sigill,
644 		.sigill_reliable = true,
645 	},
646 	{
647 		.name = "SME2",
648 		.at_hwcap = AT_HWCAP2,
649 		.hwcap_bit = HWCAP2_SME2,
650 		.cpuinfo = "sme2",
651 		.sigill_fn = sme2_sigill,
652 		.sigill_reliable = true,
653 	},
654 	{
655 		.name = "SME 2.1",
656 		.at_hwcap = AT_HWCAP2,
657 		.hwcap_bit = HWCAP2_SME2P1,
658 		.cpuinfo = "sme2p1",
659 		.sigill_fn = sme2p1_sigill,
660 	},
661 	{
662 		.name = "SME I16I32",
663 		.at_hwcap = AT_HWCAP2,
664 		.hwcap_bit = HWCAP2_SME_I16I32,
665 		.cpuinfo = "smei16i32",
666 		.sigill_fn = smei16i32_sigill,
667 	},
668 	{
669 		.name = "SME BI32I32",
670 		.at_hwcap = AT_HWCAP2,
671 		.hwcap_bit = HWCAP2_SME_BI32I32,
672 		.cpuinfo = "smebi32i32",
673 		.sigill_fn = smebi32i32_sigill,
674 	},
675 	{
676 		.name = "SME B16B16",
677 		.at_hwcap = AT_HWCAP2,
678 		.hwcap_bit = HWCAP2_SME_B16B16,
679 		.cpuinfo = "smeb16b16",
680 		.sigill_fn = smeb16b16_sigill,
681 	},
682 	{
683 		.name = "SME F16F16",
684 		.at_hwcap = AT_HWCAP2,
685 		.hwcap_bit = HWCAP2_SME_F16F16,
686 		.cpuinfo = "smef16f16",
687 		.sigill_fn = smef16f16_sigill,
688 	},
689 	{
690 		.name = "SME F8F16",
691 		.at_hwcap = AT_HWCAP2,
692 		.hwcap_bit = HWCAP2_SME_F8F16,
693 		.cpuinfo = "smef8f16",
694 		.sigill_fn = smef8f16_sigill,
695 	},
696 	{
697 		.name = "SME F8F32",
698 		.at_hwcap = AT_HWCAP2,
699 		.hwcap_bit = HWCAP2_SME_F8F32,
700 		.cpuinfo = "smef8f32",
701 		.sigill_fn = smef8f32_sigill,
702 	},
703 	{
704 		.name = "SME LUTV2",
705 		.at_hwcap = AT_HWCAP2,
706 		.hwcap_bit = HWCAP2_SME_LUTV2,
707 		.cpuinfo = "smelutv2",
708 		.sigill_fn = smelutv2_sigill,
709 	},
710 	{
711 		.name = "SME SF8FMA",
712 		.at_hwcap = AT_HWCAP2,
713 		.hwcap_bit = HWCAP2_SME_SF8FMA,
714 		.cpuinfo = "smesf8fma",
715 		.sigill_fn = smesf8fma_sigill,
716 	},
717 	{
718 		.name = "SME SF8DP2",
719 		.at_hwcap = AT_HWCAP2,
720 		.hwcap_bit = HWCAP2_SME_SF8DP2,
721 		.cpuinfo = "smesf8dp2",
722 		.sigill_fn = smesf8dp2_sigill,
723 	},
724 	{
725 		.name = "SME SF8DP4",
726 		.at_hwcap = AT_HWCAP2,
727 		.hwcap_bit = HWCAP2_SME_SF8DP4,
728 		.cpuinfo = "smesf8dp4",
729 		.sigill_fn = smesf8dp4_sigill,
730 	},
731 	{
732 		.name = "SVE",
733 		.at_hwcap = AT_HWCAP,
734 		.hwcap_bit = HWCAP_SVE,
735 		.cpuinfo = "sve",
736 		.sigill_fn = sve_sigill,
737 		.sigill_reliable = true,
738 	},
739 	{
740 		.name = "SVE 2",
741 		.at_hwcap = AT_HWCAP2,
742 		.hwcap_bit = HWCAP2_SVE2,
743 		.cpuinfo = "sve2",
744 		.sigill_fn = sve2_sigill,
745 	},
746 	{
747 		.name = "SVE 2.1",
748 		.at_hwcap = AT_HWCAP2,
749 		.hwcap_bit = HWCAP2_SVE2P1,
750 		.cpuinfo = "sve2p1",
751 		.sigill_fn = sve2p1_sigill,
752 	},
753 	{
754 		.name = "SVE AES",
755 		.at_hwcap = AT_HWCAP2,
756 		.hwcap_bit = HWCAP2_SVEAES,
757 		.cpuinfo = "sveaes",
758 		.sigill_fn = sveaes_sigill,
759 	},
760 	{
761 		.name = "SVE2 B16B16",
762 		.at_hwcap = AT_HWCAP2,
763 		.hwcap_bit = HWCAP2_SVE_B16B16,
764 		.cpuinfo = "sveb16b16",
765 		.sigill_fn = sveb16b16_sigill,
766 	},
767 	{
768 		.name = "SVE2 PMULL",
769 		.at_hwcap = AT_HWCAP2,
770 		.hwcap_bit = HWCAP2_SVEPMULL,
771 		.cpuinfo = "svepmull",
772 		.sigill_fn = svepmull_sigill,
773 	},
774 	{
775 		.name = "SVE2 BITPERM",
776 		.at_hwcap = AT_HWCAP2,
777 		.hwcap_bit = HWCAP2_SVEBITPERM,
778 		.cpuinfo = "svebitperm",
779 		.sigill_fn = svebitperm_sigill,
780 	},
781 	{
782 		.name = "SVE2 SHA3",
783 		.at_hwcap = AT_HWCAP2,
784 		.hwcap_bit = HWCAP2_SVESHA3,
785 		.cpuinfo = "svesha3",
786 		.sigill_fn = svesha3_sigill,
787 	},
788 	{
789 		.name = "SVE2 SM4",
790 		.at_hwcap = AT_HWCAP2,
791 		.hwcap_bit = HWCAP2_SVESM4,
792 		.cpuinfo = "svesm4",
793 		.sigill_fn = svesm4_sigill,
794 	},
795 	{
796 		.name = "SVE2 I8MM",
797 		.at_hwcap = AT_HWCAP2,
798 		.hwcap_bit = HWCAP2_SVEI8MM,
799 		.cpuinfo = "svei8mm",
800 		.sigill_fn = svei8mm_sigill,
801 	},
802 	{
803 		.name = "SVE2 F32MM",
804 		.at_hwcap = AT_HWCAP2,
805 		.hwcap_bit = HWCAP2_SVEF32MM,
806 		.cpuinfo = "svef32mm",
807 		.sigill_fn = svef32mm_sigill,
808 	},
809 	{
810 		.name = "SVE2 F64MM",
811 		.at_hwcap = AT_HWCAP2,
812 		.hwcap_bit = HWCAP2_SVEF64MM,
813 		.cpuinfo = "svef64mm",
814 		.sigill_fn = svef64mm_sigill,
815 	},
816 	{
817 		.name = "SVE2 BF16",
818 		.at_hwcap = AT_HWCAP2,
819 		.hwcap_bit = HWCAP2_SVEBF16,
820 		.cpuinfo = "svebf16",
821 		.sigill_fn = svebf16_sigill,
822 	},
823 	{
824 		.name = "SVE2 EBF16",
825 		.at_hwcap = AT_HWCAP2,
826 		.hwcap_bit = HWCAP2_SVE_EBF16,
827 		.cpuinfo = "sveebf16",
828 	},
829 	{
830 		.name = "HBC",
831 		.at_hwcap = AT_HWCAP2,
832 		.hwcap_bit = HWCAP2_HBC,
833 		.cpuinfo = "hbc",
834 		.sigill_fn = hbc_sigill,
835 		.sigill_reliable = true,
836 	},
837 };
838 
839 typedef void (*sighandler_fn)(int, siginfo_t *, void *);
840 
841 #define DEF_SIGHANDLER_FUNC(SIG, NUM)					\
842 static bool seen_##SIG;							\
843 static void handle_##SIG(int sig, siginfo_t *info, void *context)	\
844 {									\
845 	ucontext_t *uc = context;					\
846 									\
847 	seen_##SIG = true;						\
848 	/* Skip over the offending instruction */			\
849 	uc->uc_mcontext.pc += 4;					\
850 }
851 
852 DEF_SIGHANDLER_FUNC(sigill, SIGILL);
853 DEF_SIGHANDLER_FUNC(sigbus, SIGBUS);
854 
855 bool cpuinfo_present(const char *name)
856 {
857 	FILE *f;
858 	char buf[2048], name_space[30], name_newline[30];
859 	char *s;
860 
861 	/*
862 	 * The feature should appear with a leading space and either a
863 	 * trailing space or a newline.
864 	 */
865 	snprintf(name_space, sizeof(name_space), " %s ", name);
866 	snprintf(name_newline, sizeof(name_newline), " %s\n", name);
867 
868 	f = fopen("/proc/cpuinfo", "r");
869 	if (!f) {
870 		ksft_print_msg("Failed to open /proc/cpuinfo\n");
871 		return false;
872 	}
873 
874 	while (fgets(buf, sizeof(buf), f)) {
875 		/* Features: line? */
876 		if (strncmp(buf, "Features\t:", strlen("Features\t:")) != 0)
877 			continue;
878 
879 		/* All CPUs should be symmetric, don't read any more */
880 		fclose(f);
881 
882 		s = strstr(buf, name_space);
883 		if (s)
884 			return true;
885 		s = strstr(buf, name_newline);
886 		if (s)
887 			return true;
888 
889 		return false;
890 	}
891 
892 	ksft_print_msg("Failed to find Features in /proc/cpuinfo\n");
893 	fclose(f);
894 	return false;
895 }
896 
897 static int install_sigaction(int signum, sighandler_fn handler)
898 {
899 	int ret;
900 	struct sigaction sa;
901 
902 	memset(&sa, 0, sizeof(sa));
903 	sa.sa_sigaction = handler;
904 	sa.sa_flags = SA_RESTART | SA_SIGINFO;
905 	sigemptyset(&sa.sa_mask);
906 	ret = sigaction(signum, &sa, NULL);
907 	if (ret < 0)
908 		ksft_exit_fail_msg("Failed to install SIGNAL handler: %s (%d)\n",
909 				   strerror(errno), errno);
910 
911 	return ret;
912 }
913 
914 static void uninstall_sigaction(int signum)
915 {
916 	if (sigaction(signum, NULL, NULL) < 0)
917 		ksft_exit_fail_msg("Failed to uninstall SIGNAL handler: %s (%d)\n",
918 				   strerror(errno), errno);
919 }
920 
921 #define DEF_INST_RAISE_SIG(SIG, NUM)					\
922 static bool inst_raise_##SIG(const struct hwcap_data *hwcap,		\
923 				bool have_hwcap)			\
924 {									\
925 	if (!hwcap->SIG##_fn) {						\
926 		ksft_test_result_skip(#SIG"_%s\n", hwcap->name);	\
927 		/* assume that it would raise exception in default */	\
928 		return true;						\
929 	}								\
930 									\
931 	install_sigaction(NUM, handle_##SIG);				\
932 									\
933 	seen_##SIG = false;						\
934 	hwcap->SIG##_fn();						\
935 									\
936 	if (have_hwcap) {						\
937 		/* Should be able to use the extension */		\
938 		ksft_test_result(!seen_##SIG,				\
939 				#SIG"_%s\n", hwcap->name);		\
940 	} else if (hwcap->SIG##_reliable) {				\
941 		/* Guaranteed a SIGNAL */				\
942 		ksft_test_result(seen_##SIG,				\
943 				#SIG"_%s\n", hwcap->name);		\
944 	} else {							\
945 		/* Missing SIGNAL might be fine */			\
946 		ksft_print_msg(#SIG"_%sreported for %s\n",		\
947 				seen_##SIG ? "" : "not ",		\
948 				hwcap->name);				\
949 		ksft_test_result_skip(#SIG"_%s\n",			\
950 					hwcap->name);			\
951 	}								\
952 									\
953 	uninstall_sigaction(NUM);					\
954 	return seen_##SIG;						\
955 }
956 
957 DEF_INST_RAISE_SIG(sigill, SIGILL);
958 DEF_INST_RAISE_SIG(sigbus, SIGBUS);
959 
960 int main(void)
961 {
962 	int i;
963 	const struct hwcap_data *hwcap;
964 	bool have_cpuinfo, have_hwcap, raise_sigill;
965 
966 	ksft_print_header();
967 	ksft_set_plan(ARRAY_SIZE(hwcaps) * TESTS_PER_HWCAP);
968 
969 	for (i = 0; i < ARRAY_SIZE(hwcaps); i++) {
970 		hwcap = &hwcaps[i];
971 
972 		have_hwcap = getauxval(hwcap->at_hwcap) & hwcap->hwcap_bit;
973 		have_cpuinfo = cpuinfo_present(hwcap->cpuinfo);
974 
975 		if (have_hwcap)
976 			ksft_print_msg("%s present\n", hwcap->name);
977 
978 		ksft_test_result(have_hwcap == have_cpuinfo,
979 				 "cpuinfo_match_%s\n", hwcap->name);
980 
981 		/*
982 		 * Testing for SIGBUS only makes sense after make sure
983 		 * that the instruction does not cause a SIGILL signal.
984 		 */
985 		raise_sigill = inst_raise_sigill(hwcap, have_hwcap);
986 		if (!raise_sigill)
987 			inst_raise_sigbus(hwcap, have_hwcap);
988 		else
989 			ksft_test_result_skip("sigbus_%s\n", hwcap->name);
990 	}
991 
992 	ksft_print_cnts();
993 
994 	return 0;
995 }
996