xref: /linux/tools/testing/selftests/arm64/abi/hwcap.c (revision 7da70f41da81ebe624ac4c222792693be7c395d2)
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 <linux/auxvec.h>
15 #include <linux/compiler.h>
16 #include <sys/auxv.h>
17 #include <sys/prctl.h>
18 #include <asm/hwcap.h>
19 #include <asm/sigcontext.h>
20 #include <asm/unistd.h>
21 
22 #include <linux/auxvec.h>
23 
24 #include "kselftest.h"
25 
26 #define TESTS_PER_HWCAP 3
27 
28 #ifndef AT_HWCAP3
29 #define AT_HWCAP3 29
30 #endif
31 
32 /*
33  * Function expected to generate exception when the feature is not
34  * supported and return when it is supported. If the specific exception
35  * is generated then the handler must be able to skip over the
36  * instruction safely.
37  *
38  * Note that it is expected that for many architecture extensions
39  * there are no specific traps due to no architecture state being
40  * added so we may not fault if running on a kernel which doesn't know
41  * to add the hwcap.
42  */
43 typedef void (*sig_fn)(void);
44 
45 static void aes_sigill(void)
46 {
47 	/* AESE V0.16B, V0.16B */
48 	asm volatile(".inst 0x4e284800" : : : );
49 }
50 
51 static void atomics_sigill(void)
52 {
53 	/* STADD W0, [SP] */
54 	asm volatile(".inst 0xb82003ff" : : : );
55 }
56 
57 static void cmpbr_sigill(void)
58 {
59 	asm volatile(".inst 0x74C00040\n" /* CBEQ w0, w0, +8 */
60 		     "udf #0" : : : "cc"); /* UDF #0 */
61 }
62 
63 static void crc32_sigill(void)
64 {
65 	/* CRC32W W0, W0, W1 */
66 	asm volatile(".inst 0x1ac14800" : : : );
67 }
68 
69 static void cssc_sigill(void)
70 {
71 	/* CNT x0, x0 */
72 	asm volatile(".inst 0xdac01c00" : : : "x0");
73 }
74 
75 static void f8cvt_sigill(void)
76 {
77 	/* FSCALE V0.4H, V0.4H, V0.4H */
78 	asm volatile(".inst 0x2ec03c00");
79 }
80 
81 static void f8dp2_sigill(void)
82 {
83 	/* FDOT V0.4H, V0.4H, V0.5H */
84 	asm volatile(".inst 0xe40fc00");
85 }
86 
87 static void f8dp4_sigill(void)
88 {
89 	/* FDOT V0.2S, V0.2S, V0.2S */
90 	asm volatile(".inst 0xe00fc00");
91 }
92 
93 static void f8fma_sigill(void)
94 {
95 	/* FMLALB V0.8H, V0.16B, V0.16B */
96 	asm volatile(".inst 0xec0fc00");
97 }
98 
99 static void f8mm4_sigill(void)
100 {
101 	/* FMMLA V0.4SH, V0.16B, V0.16B */
102 	asm volatile(".inst 0x6e00ec00");
103 }
104 
105 static void f8mm8_sigill(void)
106 {
107 	/* FMMLA V0.4S, V0.16B, V0.16B */
108 	asm volatile(".inst 0x6e80ec00");
109 }
110 
111 static void f16f32dot_sigill(void)
112 {
113 	/* FDOT V0.2S, V0.4H, V0.2H[0] */
114 	asm volatile(".inst 0xf409000");
115 }
116 
117 static void f16f32mm_sigill(void)
118 {
119 	/* FMMLA V0.4S, V0.8H, V0.8H */
120 	asm volatile(".inst 0x4e40ec00");
121 }
122 
123 static void f16mm_sigill(void)
124 {
125 	/* FMMLA V0.8H, V0.8H, V0.8H */
126 	asm volatile(".inst 0x4ec0ec00");
127 }
128 
129 static void faminmax_sigill(void)
130 {
131 	/* FAMIN V0.4H, V0.4H, V0.4H */
132 	asm volatile(".inst 0x2ec01c00");
133 }
134 
135 static void fp_sigill(void)
136 {
137 	asm volatile("fmov s0, #1");
138 }
139 
140 static void fpmr_sigill(void)
141 {
142 	asm volatile("mrs x0, S3_3_C4_C4_2" : : : "x0");
143 }
144 
145 static void fprcvt_sigill(void)
146 {
147 	/* FCVTAS S0, H0 */
148 	asm volatile(".inst 0x1efa0000");
149 }
150 
151 static void gcs_sigill(void)
152 {
153 	unsigned long *gcspr;
154 
155 	asm volatile(
156 		"mrs	%0, S3_3_C2_C5_1"
157 	: "=r" (gcspr)
158 	:
159 	: "cc");
160 }
161 
162 static void ilrcpc_sigill(void)
163 {
164 	/* LDAPUR W0, [SP, #8] */
165 	asm volatile(".inst 0x994083e0" : : : );
166 }
167 
168 static void jscvt_sigill(void)
169 {
170 	/* FJCVTZS W0, D0 */
171 	asm volatile(".inst 0x1e7e0000" : : : );
172 }
173 
174 static void lrcpc_sigill(void)
175 {
176 	/* LDAPR W0, [SP, #0] */
177 	asm volatile(".inst 0xb8bfc3e0" : : : );
178 }
179 
180 static void lse128_sigill(void)
181 {
182 	u64 __attribute__ ((aligned (16))) mem[2] = { 10, 20 };
183 	register u64 *memp asm ("x0") = mem;
184 	register u64 val0 asm ("x1") = 5;
185 	register u64 val1 asm ("x2") = 4;
186 
187 	/* SWPP X1, X2, [X0] */
188 	asm volatile(".inst 0x19228001"
189 		     : "+r" (memp), "+r" (val0), "+r" (val1)
190 		     :
191 		     : "cc", "memory");
192 }
193 
194 static void lsfe_sigill(void)
195 {
196 	float __attribute__ ((aligned (16))) mem;
197 	register float *memp asm ("x0") = &mem;
198 
199 	/* STFADD H0, [X0] */
200 	asm volatile(".inst 0x7c20801f"
201 		     : "+r" (memp)
202 		     :
203 		     : "memory");
204 }
205 
206 static void lut_sigill(void)
207 {
208 	/* LUTI2 V0.16B, { V0.16B }, V[0] */
209 	asm volatile(".inst 0x4e801000");
210 }
211 
212 static void sve_lut6_sigill(void)
213 {
214 	/* LUTI6 Z0.H, { Z0.H, Z1.H }, Z0[0] */
215 	asm volatile(".inst 0x4560ac00");
216 }
217 
218 static void mops_sigill(void)
219 {
220 	char dst[1], src[1];
221 	register char *dstp asm ("x0") = dst;
222 	register char *srcp asm ("x1") = src;
223 	register long size asm ("x2") = 1;
224 
225 	/* CPYP [x0]!, [x1]!, x2! */
226 	asm volatile(".inst 0x1d010440"
227 		     : "+r" (dstp), "+r" (srcp), "+r" (size)
228 		     :
229 		     : "cc", "memory");
230 }
231 
232 static void pmull_sigill(void)
233 {
234 	/* PMULL V0.1Q, V0.1D, V0.1D */
235 	asm volatile(".inst 0x0ee0e000" : : : );
236 }
237 
238 static void poe_sigill(void)
239 {
240 	/* mrs x0, POR_EL0 */
241 	asm volatile("mrs x0, S3_3_C10_C2_4" : : : "x0");
242 }
243 
244 static void rng_sigill(void)
245 {
246 	asm volatile("mrs x0, S3_3_C2_C4_0" : : : "x0");
247 }
248 
249 static void sha1_sigill(void)
250 {
251 	/* SHA1H S0, S0 */
252 	asm volatile(".inst 0x5e280800" : : : );
253 }
254 
255 static void sha2_sigill(void)
256 {
257 	/* SHA256H Q0, Q0, V0.4S */
258 	asm volatile(".inst 0x5e004000" : : : );
259 }
260 
261 static void sha512_sigill(void)
262 {
263 	/* SHA512H Q0, Q0, V0.2D */
264 	asm volatile(".inst 0xce608000" : : : );
265 }
266 
267 static void sme_sigill(void)
268 {
269 	/* RDSVL x0, #0 */
270 	asm volatile(".inst 0x04bf5800" : : : "x0");
271 }
272 
273 static void sme2_sigill(void)
274 {
275 	/* SMSTART ZA */
276 	asm volatile("msr S0_3_C4_C5_3, xzr" : : : );
277 
278 	/* ZERO ZT0 */
279 	asm volatile(".inst 0xc0480001" : : : );
280 
281 	/* SMSTOP */
282 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
283 }
284 
285 static void sme2p1_sigill(void)
286 {
287 	/* SMSTART SM */
288 	asm volatile("msr S0_3_C4_C3_3, xzr" : : : );
289 
290 	/* BFCLAMP { Z0.H - Z1.H }, Z0.H, Z0.H */
291 	asm volatile(".inst 0xc120C000" : : : );
292 
293 	/* SMSTOP */
294 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
295 }
296 
297 static void sme2p2_sigill(void)
298 {
299 	/* SMSTART SM */
300 	asm volatile("msr S0_3_C4_C3_3, xzr" : : : );
301 
302 	/* UXTB Z0.D, P0/Z, Z0.D  */
303 	asm volatile(".inst 0x4c1a000" : : : );
304 
305 	/* SMSTOP */
306 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
307 }
308 
309 static void sme2p3_sigill(void)
310 {
311 	/* SMSTART SM */
312 	asm volatile("msr S0_3_C4_C3_3, xzr" : : : );
313 
314 	/* ADDQP Z0.B, Z0.B, Z0.B */
315 	asm volatile(".inst 0x4207800" : : : "z0");
316 
317 	/* SMSTOP */
318 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
319 }
320 
321 static void sme_aes_sigill(void)
322 {
323 	/* SMSTART SM */
324 	asm volatile("msr S0_3_C4_C3_3, xzr" : : : );
325 
326 	/* AESD z0.b, z0.b, z0.b */
327 	asm volatile(".inst 0x4522e400" : : : "z0");
328 
329 	/* SMSTOP */
330 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
331 }
332 
333 static void sme_sbitperm_sigill(void)
334 {
335 	/* SMSTART SM */
336 	asm volatile("msr S0_3_C4_C3_3, xzr" : : : );
337 
338 	/* BDEP Z0.B, Z0.B, Z0.B */
339 	asm volatile(".inst 0x4500b400" : : : "z0");
340 
341 	/* SMSTOP */
342 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
343 }
344 
345 static void smei16i32_sigill(void)
346 {
347 	/* SMSTART */
348 	asm volatile("msr S0_3_C4_C7_3, xzr" : : : );
349 
350 	/* SMOPA ZA0.S, P0/M, P0/M, Z0.B, Z0.B */
351 	asm volatile(".inst 0xa0800000" : : : );
352 
353 	/* SMSTOP */
354 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
355 }
356 
357 static void smebi32i32_sigill(void)
358 {
359 	/* SMSTART */
360 	asm volatile("msr S0_3_C4_C7_3, xzr" : : : );
361 
362 	/* BMOPA ZA0.S, P0/M, P0/M, Z0.B, Z0.B */
363 	asm volatile(".inst 0x80800008" : : : );
364 
365 	/* SMSTOP */
366 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
367 }
368 
369 static void smeb16b16_sigill(void)
370 {
371 	/* SMSTART */
372 	asm volatile("msr S0_3_C4_C7_3, xzr" : : : );
373 
374 	/* BFADD ZA.H[W0, 0], {Z0.H-Z1.H} */
375 	asm volatile(".inst 0xC1E41C00" : : : );
376 
377 	/* SMSTOP */
378 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
379 }
380 
381 static void smef16f16_sigill(void)
382 {
383 	/* SMSTART */
384 	asm volatile("msr S0_3_C4_C7_3, xzr" : : : );
385 
386 	/* FADD ZA.H[W0, 0], { Z0.H-Z1.H } */
387 	asm volatile(".inst 0xc1a41C00" : : : );
388 
389 	/* SMSTOP */
390 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
391 }
392 
393 static void smef8f16_sigill(void)
394 {
395 	/* SMSTART */
396 	asm volatile("msr S0_3_C4_C7_3, xzr" : : : );
397 
398 	/* FDOT ZA.H[W0, 0], Z0.B-Z1.B, Z0.B-Z1.B */
399 	asm volatile(".inst 0xc1a01020" : : : );
400 
401 	/* SMSTOP */
402 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
403 }
404 
405 static void smef8f32_sigill(void)
406 {
407 	/* SMSTART */
408 	asm volatile("msr S0_3_C4_C7_3, xzr" : : : );
409 
410 	/* FDOT ZA.S[W0, 0], { Z0.B-Z1.B }, Z0.B[0] */
411 	asm volatile(".inst 0xc1500038" : : : );
412 
413 	/* SMSTOP */
414 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
415 }
416 
417 static void smelut6_sigill(void)
418 {
419 	/* SMSTART */
420 	asm volatile("msr S0_3_C4_C7_3, xzr" : : : );
421 
422 	/* LUTI6 { Z0.B-Z3.B }, ZT0, { Z0-Z2 } */
423 	asm volatile(".inst 0xc08a0000" : : : );
424 
425 	/* SMSTOP */
426 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
427 }
428 
429 static void smelutv2_sigill(void)
430 {
431 	/* SMSTART */
432 	asm volatile("msr S0_3_C4_C7_3, xzr" : : : );
433 
434 	/* LUTI4 { Z0.B-Z3.B }, ZT0, { Z0-Z1 } */
435 	asm volatile(".inst 0xc08b0000" : : : );
436 
437 	/* SMSTOP */
438 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
439 }
440 
441 static void smesf8dp2_sigill(void)
442 {
443 	/* SMSTART */
444 	asm volatile("msr S0_3_C4_C7_3, xzr" : : : );
445 
446 	/* FDOT Z0.H, Z0.B, Z0.B[0] */
447 	asm volatile(".inst 0x64204400" : : : );
448 
449 	/* SMSTOP */
450 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
451 }
452 
453 static void smesf8dp4_sigill(void)
454 {
455 	/* SMSTART */
456 	asm volatile("msr S0_3_C4_C7_3, xzr" : : : );
457 
458 	/* FDOT Z0.S, Z0.B, Z0.B[0] */
459 	asm volatile(".inst 0xc1a41C00" : : : );
460 
461 	/* SMSTOP */
462 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
463 }
464 
465 static void smesf8fma_sigill(void)
466 {
467 	/* SMSTART */
468 	asm volatile("msr S0_3_C4_C7_3, xzr" : : : );
469 
470 	/* FMLALB Z0.8H, Z0.B, Z0.B */
471 	asm volatile(".inst 0x64205000");
472 
473 	/* SMSTOP */
474 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
475 }
476 
477 static void smesfexpa_sigill(void)
478 {
479 	/* SMSTART */
480 	asm volatile("msr S0_3_C4_C7_3, xzr" : : : );
481 
482 	/* FEXPA Z0.D, Z0.D */
483 	asm volatile(".inst 0x04e0b800");
484 
485 	/* SMSTOP */
486 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
487 }
488 
489 static void smesmop4_sigill(void)
490 {
491 	/* SMSTART */
492 	asm volatile("msr S0_3_C4_C7_3, xzr" : : : );
493 
494 	/* SMOP4A ZA0.S, Z0.B, { Z0.B - Z1.B } */
495 	asm volatile(".inst 0x80108000");
496 
497 	/* SMSTOP */
498 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
499 }
500 
501 static void smestmop_sigill(void)
502 {
503 	/* SMSTART */
504 	asm volatile("msr S0_3_C4_C7_3, xzr" : : : );
505 
506 	/* STMOPA ZA0.S, { Z0.H - Z1.H }, Z0.H, Z20[0] */
507 	asm volatile(".inst 0x80408008");
508 
509 	/* SMSTOP */
510 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
511 }
512 
513 static void sve_sigill(void)
514 {
515 	/* RDVL x0, #0 */
516 	asm volatile(".inst 0x04bf5000" : : : "x0");
517 }
518 
519 static void sve2_sigill(void)
520 {
521 	/* SQABS Z0.b, P0/M, Z0.B */
522 	asm volatile(".inst 0x4408A000" : : : "z0");
523 }
524 
525 static void sve2p1_sigill(void)
526 {
527 	/* LD1Q {Z0.Q}, P0/Z, [Z0.D, X0] */
528 	asm volatile(".inst 0xC400A000" : : : "z0");
529 }
530 
531 static void sve2p2_sigill(void)
532 {
533 	/* NOT Z0.D, P0/Z, Z0.D */
534 	asm volatile(".inst 0x4cea000" : : : "z0");
535 }
536 
537 static void sve2p3_sigill(void)
538 {
539 	/* ADDQP Z0.B, Z0.B, Z0.B */
540 	asm volatile(".inst 0x4207800" : : : "z0");
541 }
542 
543 static void sveaes_sigill(void)
544 {
545 	/* AESD z0.b, z0.b, z0.b */
546 	asm volatile(".inst 0x4522e400" : : : "z0");
547 }
548 
549 static void sveaes2_sigill(void)
550 {
551 	/* AESD {Z0.B - Z1.B }, { Z0.B - Z1.B }, Z0.Q */
552 	asm volatile(".inst 0x4522ec00" : : : "z0");
553 }
554 
555 static void sveb16b16_sigill(void)
556 {
557 	/* BFADD Z0.H, Z0.H, Z0.H */
558 	asm volatile(".inst 0x65000000" : : : );
559 }
560 
561 static void sveb16mm_sigill(void)
562 {
563 	/* BFMMLA Z0.H, Z0.H, Z0.H */
564 	asm volatile(".inst 0x64e0e000" : : : );
565 }
566 
567 static void svebfscale_sigill(void)
568 {
569 	/* BFSCALE Z0.H, P0/M, Z0.H, Z0.H */
570 	asm volatile(".inst 0x65098000" : : : "z0");
571 }
572 
573 static void svef16mm_sigill(void)
574 {
575 	/* FMMLA Z0.S, Z0.H, Z0.H */
576 	asm volatile(".inst 0x6420e400");
577 }
578 
579 static void svepmull_sigill(void)
580 {
581 	/* PMULLB Z0.Q, Z0.D, Z0.D */
582 	asm volatile(".inst 0x45006800" : : : "z0");
583 }
584 
585 static void svebitperm_sigill(void)
586 {
587 	/* BDEP Z0.B, Z0.B, Z0.B */
588 	asm volatile(".inst 0x4500b400" : : : "z0");
589 }
590 
591 static void svesha3_sigill(void)
592 {
593 	/* EOR3 Z0.D, Z0.D, Z0.D, Z0.D */
594 	asm volatile(".inst 0x4203800" : : : "z0");
595 }
596 
597 static void sveeltperm_sigill(void)
598 {
599 	/* COMPACT Z0.B, P0, Z0.B */
600 	asm volatile(".inst 0x5218000" : : : "x0");
601 }
602 
603 static void svesm4_sigill(void)
604 {
605 	/* SM4E Z0.S, Z0.S, Z0.S */
606 	asm volatile(".inst 0x4523e000" : : : "z0");
607 }
608 
609 static void svei8mm_sigill(void)
610 {
611 	/* USDOT Z0.S, Z0.B, Z0.B[0] */
612 	asm volatile(".inst 0x44a01800" : : : "z0");
613 }
614 
615 static void svef32mm_sigill(void)
616 {
617 	/* FMMLA Z0.S, Z0.S, Z0.S */
618 	asm volatile(".inst 0x64a0e400" : : : "z0");
619 }
620 
621 static void svef64mm_sigill(void)
622 {
623 	/* FMMLA Z0.D, Z0.D, Z0.D */
624 	asm volatile(".inst 0x64e0e400" : : : "z0");
625 }
626 
627 static void svebf16_sigill(void)
628 {
629 	/* BFCVT Z0.H, P0/M, Z0.S */
630 	asm volatile(".inst 0x658aa000" : : : "z0");
631 }
632 
633 static void hbc_sigill(void)
634 {
635 	/* BC.EQ +4 */
636 	asm volatile("cmp xzr, xzr\n"
637 		     ".inst 0x54000030" : : : "cc");
638 }
639 
640 static void uscat_sigbus(void)
641 {
642 	/* unaligned atomic access */
643 	asm volatile("ADD x1, sp, #2" : : : );
644 	/* STADD W0, [X1] */
645 	asm volatile(".inst 0xb820003f" : : : );
646 }
647 
648 static void lrcpc3_sigill(void)
649 {
650 	int data[2] = { 1, 2 };
651 
652 	register int *src asm ("x0") = data;
653 	register int data0 asm ("w2") = 0;
654 	register int data1 asm ("w3") = 0;
655 
656 	/* LDIAPP w2, w3, [x0] */
657 	asm volatile(".inst 0x99431802"
658 	              : "=r" (data0), "=r" (data1) : "r" (src) :);
659 }
660 
661 static void ignore_signal(int sig, siginfo_t *info, void *context)
662 {
663 	ucontext_t *uc = context;
664 
665 	uc->uc_mcontext.pc += 4;
666 }
667 
668 static void ls64_sigill(void)
669 {
670 	struct sigaction ign, old;
671 	char src[64] __aligned(64) = { 1 };
672 
673 	/*
674 	 * LS64 requires target memory to be Device/Non-cacheable (if
675 	 * FEAT_LS64WB not supported) and the completer supports these
676 	 * instructions, otherwise we'll receive a SIGBUS. Since we are only
677 	 * testing the ABI here, so just ignore the SIGBUS and see if we can
678 	 * execute the instructions without receiving a SIGILL. Restore the
679 	 * handler of SIGBUS after this test.
680 	 */
681 	ign.sa_sigaction = ignore_signal;
682 	ign.sa_flags = SA_SIGINFO | SA_RESTART;
683 	sigemptyset(&ign.sa_mask);
684 	sigaction(SIGBUS, &ign, &old);
685 
686 	register void *xn asm ("x8") = src;
687 	register u64 xt_1 asm ("x0");
688 
689 	/* LD64B x0, [x8] */
690 	asm volatile(".inst 0xf83fd100" : "=r" (xt_1) : "r" (xn)
691 		     : "x1", "x2", "x3", "x4", "x5", "x6", "x7");
692 
693 	/* ST64B x0, [x8] */
694 	asm volatile(".inst 0xf83f9100" : : "r" (xt_1), "r" (xn)
695 		     : "x1", "x2", "x3", "x4", "x5", "x6", "x7");
696 
697 	sigaction(SIGBUS, &old, NULL);
698 }
699 
700 static const struct hwcap_data {
701 	const char *name;
702 	unsigned long at_hwcap;
703 	unsigned long hwcap_bit;
704 	const char *cpuinfo;
705 	sig_fn sigill_fn;
706 	bool sigill_reliable;
707 	sig_fn sigbus_fn;
708 	bool sigbus_reliable;
709 } hwcaps[] = {
710 	{
711 		.name = "AES",
712 		.at_hwcap = AT_HWCAP,
713 		.hwcap_bit = HWCAP_AES,
714 		.cpuinfo = "aes",
715 		.sigill_fn = aes_sigill,
716 	},
717 	{
718 		.name = "CMPBR",
719 		.at_hwcap = AT_HWCAP,
720 		.hwcap_bit = HWCAP_CMPBR,
721 		.cpuinfo = "cmpbr",
722 		.sigill_fn = cmpbr_sigill,
723 	},
724 	{
725 		.name = "CRC32",
726 		.at_hwcap = AT_HWCAP,
727 		.hwcap_bit = HWCAP_CRC32,
728 		.cpuinfo = "crc32",
729 		.sigill_fn = crc32_sigill,
730 	},
731 	{
732 		.name = "CSSC",
733 		.at_hwcap = AT_HWCAP2,
734 		.hwcap_bit = HWCAP2_CSSC,
735 		.cpuinfo = "cssc",
736 		.sigill_fn = cssc_sigill,
737 	},
738 	{
739 		.name = "F8CVT",
740 		.at_hwcap = AT_HWCAP2,
741 		.hwcap_bit = HWCAP2_F8CVT,
742 		.cpuinfo = "f8cvt",
743 		.sigill_fn = f8cvt_sigill,
744 	},
745 	{
746 		.name = "F8DP4",
747 		.at_hwcap = AT_HWCAP2,
748 		.hwcap_bit = HWCAP2_F8DP4,
749 		.cpuinfo = "f8dp4",
750 		.sigill_fn = f8dp4_sigill,
751 	},
752 	{
753 		.name = "F8DP2",
754 		.at_hwcap = AT_HWCAP2,
755 		.hwcap_bit = HWCAP2_F8DP2,
756 		.cpuinfo = "f8dp2",
757 		.sigill_fn = f8dp2_sigill,
758 	},
759 	{
760 		.name = "F8E5M2",
761 		.at_hwcap = AT_HWCAP2,
762 		.hwcap_bit = HWCAP2_F8E5M2,
763 		.cpuinfo = "f8e5m2",
764 	},
765 	{
766 		.name = "F8E4M3",
767 		.at_hwcap = AT_HWCAP2,
768 		.hwcap_bit = HWCAP2_F8E4M3,
769 		.cpuinfo = "f8e4m3",
770 	},
771 	{
772 		.name = "F8FMA",
773 		.at_hwcap = AT_HWCAP2,
774 		.hwcap_bit = HWCAP2_F8FMA,
775 		.cpuinfo = "f8fma",
776 		.sigill_fn = f8fma_sigill,
777 	},
778 	{
779 		.name = "F8MM8",
780 		.at_hwcap = AT_HWCAP,
781 		.hwcap_bit = HWCAP_F8MM8,
782 		.cpuinfo = "f8mm8",
783 		.sigill_fn = f8mm8_sigill,
784 	},
785 	{
786 		.name = "F8MM4",
787 		.at_hwcap = AT_HWCAP,
788 		.hwcap_bit = HWCAP_F8MM4,
789 		.cpuinfo = "f8mm4",
790 		.sigill_fn = f8mm4_sigill,
791 	},
792 	{
793 		.name = "F16MM",
794 		.at_hwcap = AT_HWCAP3,
795 		.hwcap_bit = HWCAP3_F16MM,
796 		.cpuinfo = "f16mm",
797 		.sigill_fn = f16mm_sigill,
798 	},
799 	{
800 		.name = "F16F32DOT",
801 		.at_hwcap = AT_HWCAP3,
802 		.hwcap_bit = HWCAP3_F16F32DOT,
803 		.cpuinfo = "f16f32dot",
804 		.sigill_fn = f16f32dot_sigill,
805 	},
806 	{
807 		.name = "F16F32MM",
808 		.at_hwcap = AT_HWCAP3,
809 		.hwcap_bit = HWCAP3_F16F32MM,
810 		.cpuinfo = "f16f32mm",
811 		.sigill_fn = f16f32mm_sigill,
812 	},
813 	{
814 		.name = "FAMINMAX",
815 		.at_hwcap = AT_HWCAP2,
816 		.hwcap_bit = HWCAP2_FAMINMAX,
817 		.cpuinfo = "faminmax",
818 		.sigill_fn = faminmax_sigill,
819 	},
820 	{
821 		.name = "FP",
822 		.at_hwcap = AT_HWCAP,
823 		.hwcap_bit = HWCAP_FP,
824 		.cpuinfo = "fp",
825 		.sigill_fn = fp_sigill,
826 	},
827 	{
828 		.name = "FPMR",
829 		.at_hwcap = AT_HWCAP2,
830 		.hwcap_bit = HWCAP2_FPMR,
831 		.cpuinfo = "fpmr",
832 		.sigill_fn = fpmr_sigill,
833 		.sigill_reliable = true,
834 	},
835 	{
836 		.name = "FPRCVT",
837 		.at_hwcap = AT_HWCAP,
838 		.hwcap_bit = HWCAP_FPRCVT,
839 		.cpuinfo = "fprcvt",
840 		.sigill_fn = fprcvt_sigill,
841 	},
842 	{
843 		.name = "GCS",
844 		.at_hwcap = AT_HWCAP,
845 		.hwcap_bit = HWCAP_GCS,
846 		.cpuinfo = "gcs",
847 		.sigill_fn = gcs_sigill,
848 		.sigill_reliable = true,
849 	},
850 	{
851 		.name = "JSCVT",
852 		.at_hwcap = AT_HWCAP,
853 		.hwcap_bit = HWCAP_JSCVT,
854 		.cpuinfo = "jscvt",
855 		.sigill_fn = jscvt_sigill,
856 	},
857 	{
858 		.name = "LRCPC",
859 		.at_hwcap = AT_HWCAP,
860 		.hwcap_bit = HWCAP_LRCPC,
861 		.cpuinfo = "lrcpc",
862 		.sigill_fn = lrcpc_sigill,
863 	},
864 	{
865 		.name = "LRCPC2",
866 		.at_hwcap = AT_HWCAP,
867 		.hwcap_bit = HWCAP_ILRCPC,
868 		.cpuinfo = "ilrcpc",
869 		.sigill_fn = ilrcpc_sigill,
870 	},
871 	{
872 		.name = "LRCPC3",
873 		.at_hwcap = AT_HWCAP2,
874 		.hwcap_bit = HWCAP2_LRCPC3,
875 		.cpuinfo = "lrcpc3",
876 		.sigill_fn = lrcpc3_sigill,
877 	},
878 	{
879 		.name = "LSE",
880 		.at_hwcap = AT_HWCAP,
881 		.hwcap_bit = HWCAP_ATOMICS,
882 		.cpuinfo = "atomics",
883 		.sigill_fn = atomics_sigill,
884 	},
885 	{
886 		.name = "LSE2",
887 		.at_hwcap = AT_HWCAP,
888 		.hwcap_bit = HWCAP_USCAT,
889 		.cpuinfo = "uscat",
890 		.sigill_fn = atomics_sigill,
891 		.sigbus_fn = uscat_sigbus,
892 		.sigbus_reliable = true,
893 	},
894 	{
895 		.name = "LSE128",
896 		.at_hwcap = AT_HWCAP2,
897 		.hwcap_bit = HWCAP2_LSE128,
898 		.cpuinfo = "lse128",
899 		.sigill_fn = lse128_sigill,
900 	},
901 	{
902 		.name = "LSFE",
903 		.at_hwcap = AT_HWCAP3,
904 		.hwcap_bit = HWCAP3_LSFE,
905 		.cpuinfo = "lsfe",
906 		.sigill_fn = lsfe_sigill,
907 	},
908 	{
909 		.name = "LUT",
910 		.at_hwcap = AT_HWCAP2,
911 		.hwcap_bit = HWCAP2_LUT,
912 		.cpuinfo = "lut",
913 		.sigill_fn = lut_sigill,
914 	},
915 	{
916 		.name = "MOPS",
917 		.at_hwcap = AT_HWCAP2,
918 		.hwcap_bit = HWCAP2_MOPS,
919 		.cpuinfo = "mops",
920 		.sigill_fn = mops_sigill,
921 		.sigill_reliable = true,
922 	},
923 	{
924 		.name = "PMULL",
925 		.at_hwcap = AT_HWCAP,
926 		.hwcap_bit = HWCAP_PMULL,
927 		.cpuinfo = "pmull",
928 		.sigill_fn = pmull_sigill,
929 	},
930 	{
931 		.name = "POE",
932 		.at_hwcap = AT_HWCAP2,
933 		.hwcap_bit = HWCAP2_POE,
934 		.cpuinfo = "poe",
935 		.sigill_fn = poe_sigill,
936 		.sigill_reliable = true,
937 	},
938 	{
939 		.name = "RNG",
940 		.at_hwcap = AT_HWCAP2,
941 		.hwcap_bit = HWCAP2_RNG,
942 		.cpuinfo = "rng",
943 		.sigill_fn = rng_sigill,
944 	},
945 	{
946 		.name = "RPRFM",
947 		.at_hwcap = AT_HWCAP2,
948 		.hwcap_bit = HWCAP2_RPRFM,
949 		.cpuinfo = "rprfm",
950 	},
951 	{
952 		.name = "SHA1",
953 		.at_hwcap = AT_HWCAP,
954 		.hwcap_bit = HWCAP_SHA1,
955 		.cpuinfo = "sha1",
956 		.sigill_fn = sha1_sigill,
957 	},
958 	{
959 		.name = "SHA2",
960 		.at_hwcap = AT_HWCAP,
961 		.hwcap_bit = HWCAP_SHA2,
962 		.cpuinfo = "sha2",
963 		.sigill_fn = sha2_sigill,
964 	},
965 	{
966 		.name = "SHA512",
967 		.at_hwcap = AT_HWCAP,
968 		.hwcap_bit = HWCAP_SHA512,
969 		.cpuinfo = "sha512",
970 		.sigill_fn = sha512_sigill,
971 	},
972 	{
973 		.name = "SME",
974 		.at_hwcap = AT_HWCAP2,
975 		.hwcap_bit = HWCAP2_SME,
976 		.cpuinfo = "sme",
977 		.sigill_fn = sme_sigill,
978 		.sigill_reliable = true,
979 	},
980 	{
981 		.name = "SME2",
982 		.at_hwcap = AT_HWCAP2,
983 		.hwcap_bit = HWCAP2_SME2,
984 		.cpuinfo = "sme2",
985 		.sigill_fn = sme2_sigill,
986 		.sigill_reliable = true,
987 	},
988 	{
989 		.name = "SME 2.1",
990 		.at_hwcap = AT_HWCAP2,
991 		.hwcap_bit = HWCAP2_SME2P1,
992 		.cpuinfo = "sme2p1",
993 		.sigill_fn = sme2p1_sigill,
994 	},
995 	{
996 		.name = "SME 2.2",
997 		.at_hwcap = AT_HWCAP,
998 		.hwcap_bit = HWCAP_SME2P2,
999 		.cpuinfo = "sme2p2",
1000 		.sigill_fn = sme2p2_sigill,
1001 	},
1002 	{
1003 		.name = "SME 2.3",
1004 		.at_hwcap = AT_HWCAP3,
1005 		.hwcap_bit = HWCAP3_SME2P3,
1006 		.cpuinfo = "sme2p3",
1007 		.sigill_fn = sme2p3_sigill,
1008 	},
1009 	{
1010 		.name = "SME AES",
1011 		.at_hwcap = AT_HWCAP,
1012 		.hwcap_bit = HWCAP_SME_AES,
1013 		.cpuinfo = "smeaes",
1014 		.sigill_fn = sme_aes_sigill,
1015 	},
1016 	{
1017 		.name = "SME I16I32",
1018 		.at_hwcap = AT_HWCAP2,
1019 		.hwcap_bit = HWCAP2_SME_I16I32,
1020 		.cpuinfo = "smei16i32",
1021 		.sigill_fn = smei16i32_sigill,
1022 	},
1023 	{
1024 		.name = "SME BI32I32",
1025 		.at_hwcap = AT_HWCAP2,
1026 		.hwcap_bit = HWCAP2_SME_BI32I32,
1027 		.cpuinfo = "smebi32i32",
1028 		.sigill_fn = smebi32i32_sigill,
1029 	},
1030 	{
1031 		.name = "SME B16B16",
1032 		.at_hwcap = AT_HWCAP2,
1033 		.hwcap_bit = HWCAP2_SME_B16B16,
1034 		.cpuinfo = "smeb16b16",
1035 		.sigill_fn = smeb16b16_sigill,
1036 	},
1037 	{
1038 		.name = "SME F16F16",
1039 		.at_hwcap = AT_HWCAP2,
1040 		.hwcap_bit = HWCAP2_SME_F16F16,
1041 		.cpuinfo = "smef16f16",
1042 		.sigill_fn = smef16f16_sigill,
1043 	},
1044 	{
1045 		.name = "SME F8F16",
1046 		.at_hwcap = AT_HWCAP2,
1047 		.hwcap_bit = HWCAP2_SME_F8F16,
1048 		.cpuinfo = "smef8f16",
1049 		.sigill_fn = smef8f16_sigill,
1050 	},
1051 	{
1052 		.name = "SME F8F32",
1053 		.at_hwcap = AT_HWCAP2,
1054 		.hwcap_bit = HWCAP2_SME_F8F32,
1055 		.cpuinfo = "smef8f32",
1056 		.sigill_fn = smef8f32_sigill,
1057 	},
1058 	{
1059 		.name = "SME LUT6",
1060 		.at_hwcap = AT_HWCAP3,
1061 		.hwcap_bit = HWCAP3_SME_LUT6,
1062 		.cpuinfo = "smelut6",
1063 		.sigill_fn = smelut6_sigill,
1064 	},
1065 	{
1066 		.name = "SME LUTV2",
1067 		.at_hwcap = AT_HWCAP2,
1068 		.hwcap_bit = HWCAP2_SME_LUTV2,
1069 		.cpuinfo = "smelutv2",
1070 		.sigill_fn = smelutv2_sigill,
1071 	},
1072 	{
1073 		.name = "SME SBITPERM",
1074 		.at_hwcap = AT_HWCAP,
1075 		.hwcap_bit = HWCAP_SME_SBITPERM,
1076 		.cpuinfo = "smesbitperm",
1077 		.sigill_fn = sme_sbitperm_sigill,
1078 	},
1079 	{
1080 		.name = "SME SF8FMA",
1081 		.at_hwcap = AT_HWCAP2,
1082 		.hwcap_bit = HWCAP2_SME_SF8FMA,
1083 		.cpuinfo = "smesf8fma",
1084 		.sigill_fn = smesf8fma_sigill,
1085 	},
1086 	{
1087 		.name = "SME SF8DP2",
1088 		.at_hwcap = AT_HWCAP2,
1089 		.hwcap_bit = HWCAP2_SME_SF8DP2,
1090 		.cpuinfo = "smesf8dp2",
1091 		.sigill_fn = smesf8dp2_sigill,
1092 	},
1093 	{
1094 		.name = "SME SF8DP4",
1095 		.at_hwcap = AT_HWCAP2,
1096 		.hwcap_bit = HWCAP2_SME_SF8DP4,
1097 		.cpuinfo = "smesf8dp4",
1098 		.sigill_fn = smesf8dp4_sigill,
1099 	},
1100 	{
1101 		.name = "SME SFEXPA",
1102 		.at_hwcap = AT_HWCAP,
1103 		.hwcap_bit = HWCAP_SME_SFEXPA,
1104 		.cpuinfo = "smesfexpa",
1105 		.sigill_fn = smesfexpa_sigill,
1106 	},
1107 	{
1108 		.name = "SME SMOP4",
1109 		.at_hwcap = AT_HWCAP,
1110 		.hwcap_bit = HWCAP_SME_SMOP4,
1111 		.cpuinfo = "smesmop4",
1112 		.sigill_fn = smesmop4_sigill,
1113 	},
1114 	{
1115 		.name = "SME STMOP",
1116 		.at_hwcap = AT_HWCAP,
1117 		.hwcap_bit = HWCAP_SME_STMOP,
1118 		.cpuinfo = "smestmop",
1119 		.sigill_fn = smestmop_sigill,
1120 	},
1121 	{
1122 		.name = "SVE",
1123 		.at_hwcap = AT_HWCAP,
1124 		.hwcap_bit = HWCAP_SVE,
1125 		.cpuinfo = "sve",
1126 		.sigill_fn = sve_sigill,
1127 		.sigill_reliable = true,
1128 	},
1129 	{
1130 		.name = "SVE 2",
1131 		.at_hwcap = AT_HWCAP2,
1132 		.hwcap_bit = HWCAP2_SVE2,
1133 		.cpuinfo = "sve2",
1134 		.sigill_fn = sve2_sigill,
1135 	},
1136 	{
1137 		.name = "SVE 2.1",
1138 		.at_hwcap = AT_HWCAP2,
1139 		.hwcap_bit = HWCAP2_SVE2P1,
1140 		.cpuinfo = "sve2p1",
1141 		.sigill_fn = sve2p1_sigill,
1142 	},
1143 	{
1144 		.name = "SVE 2.2",
1145 		.at_hwcap = AT_HWCAP,
1146 		.hwcap_bit = HWCAP_SVE2P2,
1147 		.cpuinfo = "sve2p2",
1148 		.sigill_fn = sve2p2_sigill,
1149 	},
1150 	{
1151 		.name = "SVE 2.3",
1152 		.at_hwcap = AT_HWCAP3,
1153 		.hwcap_bit = HWCAP3_SVE2P3,
1154 		.cpuinfo = "sve2p3",
1155 		.sigill_fn = sve2p3_sigill,
1156 	},
1157 	{
1158 		.name = "SVE AES",
1159 		.at_hwcap = AT_HWCAP2,
1160 		.hwcap_bit = HWCAP2_SVEAES,
1161 		.cpuinfo = "sveaes",
1162 		.sigill_fn = sveaes_sigill,
1163 	},
1164 	{
1165 		.name = "SVE AES2",
1166 		.at_hwcap = AT_HWCAP,
1167 		.hwcap_bit = HWCAP_SVE_AES2,
1168 		.cpuinfo = "sveaes2",
1169 		.sigill_fn = sveaes2_sigill,
1170 	},
1171 	{
1172 		.name = "SVE B16MM",
1173 		.at_hwcap = AT_HWCAP3,
1174 		.hwcap_bit = HWCAP3_SVE_B16MM,
1175 		.cpuinfo = "sveb16mm",
1176 		.sigill_fn = sveb16mm_sigill,
1177 	},
1178 	{
1179 		.name = "SVE BFSCALE",
1180 		.at_hwcap = AT_HWCAP,
1181 		.hwcap_bit = HWCAP_SVE_BFSCALE,
1182 		.cpuinfo = "svebfscale",
1183 		.sigill_fn = svebfscale_sigill,
1184 	},
1185 	{
1186 		.name = "SVE ELTPERM",
1187 		.at_hwcap = AT_HWCAP,
1188 		.hwcap_bit = HWCAP_SVE_ELTPERM,
1189 		.cpuinfo = "sveeltperm",
1190 		.sigill_fn = sveeltperm_sigill,
1191 	},
1192 	{
1193 		.name = "SVE F16MM",
1194 		.at_hwcap = AT_HWCAP,
1195 		.hwcap_bit = HWCAP_SVE_F16MM,
1196 		.cpuinfo = "svef16mm",
1197 		.sigill_fn = svef16mm_sigill,
1198 	},
1199 	{
1200 		.name = "SVE_LUT6",
1201 		.at_hwcap = AT_HWCAP3,
1202 		.hwcap_bit = HWCAP3_SVE_LUT6,
1203 		.cpuinfo = "svelut6",
1204 		.sigill_fn = sve_lut6_sigill,
1205 	},
1206 	{
1207 		.name = "SVE2 B16B16",
1208 		.at_hwcap = AT_HWCAP2,
1209 		.hwcap_bit = HWCAP2_SVE_B16B16,
1210 		.cpuinfo = "sveb16b16",
1211 		.sigill_fn = sveb16b16_sigill,
1212 	},
1213 	{
1214 		.name = "SVE2 PMULL",
1215 		.at_hwcap = AT_HWCAP2,
1216 		.hwcap_bit = HWCAP2_SVEPMULL,
1217 		.cpuinfo = "svepmull",
1218 		.sigill_fn = svepmull_sigill,
1219 	},
1220 	{
1221 		.name = "SVE2 BITPERM",
1222 		.at_hwcap = AT_HWCAP2,
1223 		.hwcap_bit = HWCAP2_SVEBITPERM,
1224 		.cpuinfo = "svebitperm",
1225 		.sigill_fn = svebitperm_sigill,
1226 	},
1227 	{
1228 		.name = "SVE2 SHA3",
1229 		.at_hwcap = AT_HWCAP2,
1230 		.hwcap_bit = HWCAP2_SVESHA3,
1231 		.cpuinfo = "svesha3",
1232 		.sigill_fn = svesha3_sigill,
1233 	},
1234 	{
1235 		.name = "SVE2 SM4",
1236 		.at_hwcap = AT_HWCAP2,
1237 		.hwcap_bit = HWCAP2_SVESM4,
1238 		.cpuinfo = "svesm4",
1239 		.sigill_fn = svesm4_sigill,
1240 	},
1241 	{
1242 		.name = "SVE2 I8MM",
1243 		.at_hwcap = AT_HWCAP2,
1244 		.hwcap_bit = HWCAP2_SVEI8MM,
1245 		.cpuinfo = "svei8mm",
1246 		.sigill_fn = svei8mm_sigill,
1247 	},
1248 	{
1249 		.name = "SVE2 F32MM",
1250 		.at_hwcap = AT_HWCAP2,
1251 		.hwcap_bit = HWCAP2_SVEF32MM,
1252 		.cpuinfo = "svef32mm",
1253 		.sigill_fn = svef32mm_sigill,
1254 	},
1255 	{
1256 		.name = "SVE2 F64MM",
1257 		.at_hwcap = AT_HWCAP2,
1258 		.hwcap_bit = HWCAP2_SVEF64MM,
1259 		.cpuinfo = "svef64mm",
1260 		.sigill_fn = svef64mm_sigill,
1261 	},
1262 	{
1263 		.name = "SVE2 BF16",
1264 		.at_hwcap = AT_HWCAP2,
1265 		.hwcap_bit = HWCAP2_SVEBF16,
1266 		.cpuinfo = "svebf16",
1267 		.sigill_fn = svebf16_sigill,
1268 	},
1269 	{
1270 		.name = "SVE2 EBF16",
1271 		.at_hwcap = AT_HWCAP2,
1272 		.hwcap_bit = HWCAP2_SVE_EBF16,
1273 		.cpuinfo = "sveebf16",
1274 	},
1275 	{
1276 		.name = "HBC",
1277 		.at_hwcap = AT_HWCAP2,
1278 		.hwcap_bit = HWCAP2_HBC,
1279 		.cpuinfo = "hbc",
1280 		.sigill_fn = hbc_sigill,
1281 		.sigill_reliable = true,
1282 	},
1283 	{
1284 		.name = "MTE_FAR",
1285 		.at_hwcap = AT_HWCAP3,
1286 		.hwcap_bit = HWCAP3_MTE_FAR,
1287 		.cpuinfo = "mtefar",
1288 	},
1289 	{
1290 		.name = "MTE_STOREONLY",
1291 		.at_hwcap = AT_HWCAP3,
1292 		.hwcap_bit = HWCAP3_MTE_STORE_ONLY,
1293 		.cpuinfo = "mtestoreonly",
1294 	},
1295 	{
1296 		.name = "LS64",
1297 		.at_hwcap = AT_HWCAP3,
1298 		.hwcap_bit = HWCAP3_LS64,
1299 		.cpuinfo = "ls64",
1300 		.sigill_fn = ls64_sigill,
1301 		.sigill_reliable = true,
1302 	},
1303 };
1304 
1305 typedef void (*sighandler_fn)(int, siginfo_t *, void *);
1306 
1307 #define DEF_SIGHANDLER_FUNC(SIG, NUM)					\
1308 static bool seen_##SIG;							\
1309 static void handle_##SIG(int sig, siginfo_t *info, void *context)	\
1310 {									\
1311 	ucontext_t *uc = context;					\
1312 									\
1313 	seen_##SIG = true;						\
1314 	/* Skip over the offending instruction */			\
1315 	uc->uc_mcontext.pc += 4;					\
1316 }
1317 
1318 DEF_SIGHANDLER_FUNC(sigill, SIGILL);
1319 DEF_SIGHANDLER_FUNC(sigbus, SIGBUS);
1320 
1321 bool cpuinfo_present(const char *name)
1322 {
1323 	FILE *f;
1324 	char buf[2048], name_space[30], name_newline[30];
1325 	char *s;
1326 
1327 	/*
1328 	 * The feature should appear with a leading space and either a
1329 	 * trailing space or a newline.
1330 	 */
1331 	snprintf(name_space, sizeof(name_space), " %s ", name);
1332 	snprintf(name_newline, sizeof(name_newline), " %s\n", name);
1333 
1334 	f = fopen("/proc/cpuinfo", "r");
1335 	if (!f) {
1336 		ksft_print_msg("Failed to open /proc/cpuinfo\n");
1337 		return false;
1338 	}
1339 
1340 	while (fgets(buf, sizeof(buf), f)) {
1341 		/* Features: line? */
1342 		if (strncmp(buf, "Features\t:", strlen("Features\t:")) != 0)
1343 			continue;
1344 
1345 		/* All CPUs should be symmetric, don't read any more */
1346 		fclose(f);
1347 
1348 		s = strstr(buf, name_space);
1349 		if (s)
1350 			return true;
1351 		s = strstr(buf, name_newline);
1352 		if (s)
1353 			return true;
1354 
1355 		return false;
1356 	}
1357 
1358 	ksft_print_msg("Failed to find Features in /proc/cpuinfo\n");
1359 	fclose(f);
1360 	return false;
1361 }
1362 
1363 static int install_sigaction(int signum, sighandler_fn handler)
1364 {
1365 	int ret;
1366 	struct sigaction sa;
1367 
1368 	memset(&sa, 0, sizeof(sa));
1369 	sa.sa_sigaction = handler;
1370 	sa.sa_flags = SA_RESTART | SA_SIGINFO;
1371 	sigemptyset(&sa.sa_mask);
1372 	ret = sigaction(signum, &sa, NULL);
1373 	if (ret < 0)
1374 		ksft_exit_fail_msg("Failed to install SIGNAL handler: %s (%d)\n",
1375 				   strerror(errno), errno);
1376 
1377 	return ret;
1378 }
1379 
1380 static void uninstall_sigaction(int signum)
1381 {
1382 	if (sigaction(signum, NULL, NULL) < 0)
1383 		ksft_exit_fail_msg("Failed to uninstall SIGNAL handler: %s (%d)\n",
1384 				   strerror(errno), errno);
1385 }
1386 
1387 #define DEF_INST_RAISE_SIG(SIG, NUM)					\
1388 static bool inst_raise_##SIG(const struct hwcap_data *hwcap,		\
1389 				bool have_hwcap)			\
1390 {									\
1391 	if (!hwcap->SIG##_fn) {						\
1392 		ksft_test_result_skip(#SIG"_%s\n", hwcap->name);	\
1393 		/* assume that it would raise exception in default */	\
1394 		return true;						\
1395 	}								\
1396 									\
1397 	install_sigaction(NUM, handle_##SIG);				\
1398 									\
1399 	seen_##SIG = false;						\
1400 	hwcap->SIG##_fn();						\
1401 									\
1402 	if (have_hwcap) {						\
1403 		/* Should be able to use the extension */		\
1404 		ksft_test_result(!seen_##SIG,				\
1405 				#SIG"_%s\n", hwcap->name);		\
1406 	} else if (hwcap->SIG##_reliable) {				\
1407 		/* Guaranteed a SIGNAL */				\
1408 		ksft_test_result(seen_##SIG,				\
1409 				#SIG"_%s\n", hwcap->name);		\
1410 	} else {							\
1411 		/* Missing SIGNAL might be fine */			\
1412 		ksft_print_msg(#SIG"_%sreported for %s\n",		\
1413 				seen_##SIG ? "" : "not ",		\
1414 				hwcap->name);				\
1415 		ksft_test_result_skip(#SIG"_%s\n",			\
1416 					hwcap->name);			\
1417 	}								\
1418 									\
1419 	uninstall_sigaction(NUM);					\
1420 	return seen_##SIG;						\
1421 }
1422 
1423 DEF_INST_RAISE_SIG(sigill, SIGILL);
1424 DEF_INST_RAISE_SIG(sigbus, SIGBUS);
1425 
1426 int main(void)
1427 {
1428 	int i;
1429 	const struct hwcap_data *hwcap;
1430 	bool have_cpuinfo, have_hwcap, raise_sigill;
1431 
1432 	ksft_print_header();
1433 	ksft_set_plan(ARRAY_SIZE(hwcaps) * TESTS_PER_HWCAP);
1434 
1435 	for (i = 0; i < ARRAY_SIZE(hwcaps); i++) {
1436 		hwcap = &hwcaps[i];
1437 
1438 		have_hwcap = getauxval(hwcap->at_hwcap) & hwcap->hwcap_bit;
1439 		have_cpuinfo = cpuinfo_present(hwcap->cpuinfo);
1440 
1441 		if (have_hwcap)
1442 			ksft_print_msg("%s present\n", hwcap->name);
1443 
1444 		ksft_test_result(have_hwcap == have_cpuinfo,
1445 				 "cpuinfo_match_%s\n", hwcap->name);
1446 
1447 		/*
1448 		 * Testing for SIGBUS only makes sense after make sure
1449 		 * that the instruction does not cause a SIGILL signal.
1450 		 */
1451 		raise_sigill = inst_raise_sigill(hwcap, have_hwcap);
1452 		if (!raise_sigill)
1453 			inst_raise_sigbus(hwcap, have_hwcap);
1454 		else
1455 			ksft_test_result_skip("sigbus_%s\n", hwcap->name);
1456 	}
1457 
1458 	ksft_print_cnts();
1459 
1460 	return 0;
1461 }
1462