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