xref: /linux/tools/testing/selftests/arm64/abi/hwcap.c (revision be239684b18e1cdcafcf8c7face4a2f562c745ad)
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 fp_sigill(void)
62 {
63 	asm volatile("fmov s0, #1");
64 }
65 
66 static void ilrcpc_sigill(void)
67 {
68 	/* LDAPUR W0, [SP, #8] */
69 	asm volatile(".inst 0x994083e0" : : : );
70 }
71 
72 static void jscvt_sigill(void)
73 {
74 	/* FJCVTZS W0, D0 */
75 	asm volatile(".inst 0x1e7e0000" : : : );
76 }
77 
78 static void lrcpc_sigill(void)
79 {
80 	/* LDAPR W0, [SP, #0] */
81 	asm volatile(".inst 0xb8bfc3e0" : : : );
82 }
83 
84 static void lse128_sigill(void)
85 {
86 	u64 __attribute__ ((aligned (16))) mem[2] = { 10, 20 };
87 	register u64 *memp asm ("x0") = mem;
88 	register u64 val0 asm ("x1") = 5;
89 	register u64 val1 asm ("x2") = 4;
90 
91 	/* SWPP X1, X2, [X0] */
92 	asm volatile(".inst 0x19228001"
93 		     : "+r" (memp), "+r" (val0), "+r" (val1)
94 		     :
95 		     : "cc", "memory");
96 }
97 
98 static void mops_sigill(void)
99 {
100 	char dst[1], src[1];
101 	register char *dstp asm ("x0") = dst;
102 	register char *srcp asm ("x1") = src;
103 	register long size asm ("x2") = 1;
104 
105 	/* CPYP [x0]!, [x1]!, x2! */
106 	asm volatile(".inst 0x1d010440"
107 		     : "+r" (dstp), "+r" (srcp), "+r" (size)
108 		     :
109 		     : "cc", "memory");
110 }
111 
112 static void pmull_sigill(void)
113 {
114 	/* PMULL V0.1Q, V0.1D, V0.1D */
115 	asm volatile(".inst 0x0ee0e000" : : : );
116 }
117 
118 static void rng_sigill(void)
119 {
120 	asm volatile("mrs x0, S3_3_C2_C4_0" : : : "x0");
121 }
122 
123 static void sha1_sigill(void)
124 {
125 	/* SHA1H S0, S0 */
126 	asm volatile(".inst 0x5e280800" : : : );
127 }
128 
129 static void sha2_sigill(void)
130 {
131 	/* SHA256H Q0, Q0, V0.4S */
132 	asm volatile(".inst 0x5e004000" : : : );
133 }
134 
135 static void sha512_sigill(void)
136 {
137 	/* SHA512H Q0, Q0, V0.2D */
138 	asm volatile(".inst 0xce608000" : : : );
139 }
140 
141 static void sme_sigill(void)
142 {
143 	/* RDSVL x0, #0 */
144 	asm volatile(".inst 0x04bf5800" : : : "x0");
145 }
146 
147 static void sme2_sigill(void)
148 {
149 	/* SMSTART ZA */
150 	asm volatile("msr S0_3_C4_C5_3, xzr" : : : );
151 
152 	/* ZERO ZT0 */
153 	asm volatile(".inst 0xc0480001" : : : );
154 
155 	/* SMSTOP */
156 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
157 }
158 
159 static void sme2p1_sigill(void)
160 {
161 	/* SMSTART SM */
162 	asm volatile("msr S0_3_C4_C3_3, xzr" : : : );
163 
164 	/* BFCLAMP { Z0.H - Z1.H }, Z0.H, Z0.H */
165 	asm volatile(".inst 0xc120C000" : : : );
166 
167 	/* SMSTOP */
168 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
169 }
170 
171 static void smei16i32_sigill(void)
172 {
173 	/* SMSTART */
174 	asm volatile("msr S0_3_C4_C7_3, xzr" : : : );
175 
176 	/* SMOPA ZA0.S, P0/M, P0/M, Z0.B, Z0.B */
177 	asm volatile(".inst 0xa0800000" : : : );
178 
179 	/* SMSTOP */
180 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
181 }
182 
183 static void smebi32i32_sigill(void)
184 {
185 	/* SMSTART */
186 	asm volatile("msr S0_3_C4_C7_3, xzr" : : : );
187 
188 	/* BMOPA ZA0.S, P0/M, P0/M, Z0.B, Z0.B */
189 	asm volatile(".inst 0x80800008" : : : );
190 
191 	/* SMSTOP */
192 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
193 }
194 
195 static void smeb16b16_sigill(void)
196 {
197 	/* SMSTART */
198 	asm volatile("msr S0_3_C4_C7_3, xzr" : : : );
199 
200 	/* BFADD ZA.H[W0, 0], {Z0.H-Z1.H} */
201 	asm volatile(".inst 0xC1E41C00" : : : );
202 
203 	/* SMSTOP */
204 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
205 }
206 
207 static void smef16f16_sigill(void)
208 {
209 	/* SMSTART */
210 	asm volatile("msr S0_3_C4_C7_3, xzr" : : : );
211 
212 	/* FADD ZA.H[W0, 0], { Z0.H-Z1.H } */
213 	asm volatile(".inst 0xc1a41C00" : : : );
214 
215 	/* SMSTOP */
216 	asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
217 }
218 
219 static void sve_sigill(void)
220 {
221 	/* RDVL x0, #0 */
222 	asm volatile(".inst 0x04bf5000" : : : "x0");
223 }
224 
225 static void sve2_sigill(void)
226 {
227 	/* SQABS Z0.b, P0/M, Z0.B */
228 	asm volatile(".inst 0x4408A000" : : : "z0");
229 }
230 
231 static void sve2p1_sigill(void)
232 {
233 	/* BFADD Z0.H, Z0.H, Z0.H */
234 	asm volatile(".inst 0x65000000" : : : "z0");
235 }
236 
237 static void sveaes_sigill(void)
238 {
239 	/* AESD z0.b, z0.b, z0.b */
240 	asm volatile(".inst 0x4522e400" : : : "z0");
241 }
242 
243 static void sveb16b16_sigill(void)
244 {
245 	/* BFADD ZA.H[W0, 0], {Z0.H-Z1.H} */
246 	asm volatile(".inst 0xC1E41C00" : : : );
247 }
248 
249 static void svepmull_sigill(void)
250 {
251 	/* PMULLB Z0.Q, Z0.D, Z0.D */
252 	asm volatile(".inst 0x45006800" : : : "z0");
253 }
254 
255 static void svebitperm_sigill(void)
256 {
257 	/* BDEP Z0.B, Z0.B, Z0.B */
258 	asm volatile(".inst 0x4500b400" : : : "z0");
259 }
260 
261 static void svesha3_sigill(void)
262 {
263 	/* EOR3 Z0.D, Z0.D, Z0.D, Z0.D */
264 	asm volatile(".inst 0x4203800" : : : "z0");
265 }
266 
267 static void svesm4_sigill(void)
268 {
269 	/* SM4E Z0.S, Z0.S, Z0.S */
270 	asm volatile(".inst 0x4523e000" : : : "z0");
271 }
272 
273 static void svei8mm_sigill(void)
274 {
275 	/* USDOT Z0.S, Z0.B, Z0.B[0] */
276 	asm volatile(".inst 0x44a01800" : : : "z0");
277 }
278 
279 static void svef32mm_sigill(void)
280 {
281 	/* FMMLA Z0.S, Z0.S, Z0.S */
282 	asm volatile(".inst 0x64a0e400" : : : "z0");
283 }
284 
285 static void svef64mm_sigill(void)
286 {
287 	/* FMMLA Z0.D, Z0.D, Z0.D */
288 	asm volatile(".inst 0x64e0e400" : : : "z0");
289 }
290 
291 static void svebf16_sigill(void)
292 {
293 	/* BFCVT Z0.H, P0/M, Z0.S */
294 	asm volatile(".inst 0x658aa000" : : : "z0");
295 }
296 
297 static void hbc_sigill(void)
298 {
299 	/* BC.EQ +4 */
300 	asm volatile("cmp xzr, xzr\n"
301 		     ".inst 0x54000030" : : : "cc");
302 }
303 
304 static void uscat_sigbus(void)
305 {
306 	/* unaligned atomic access */
307 	asm volatile("ADD x1, sp, #2" : : : );
308 	/* STADD W0, [X1] */
309 	asm volatile(".inst 0xb820003f" : : : );
310 }
311 
312 static void lrcpc3_sigill(void)
313 {
314 	int data[2] = { 1, 2 };
315 
316 	register int *src asm ("x0") = data;
317 	register int data0 asm ("w2") = 0;
318 	register int data1 asm ("w3") = 0;
319 
320 	/* LDIAPP w2, w3, [x0] */
321 	asm volatile(".inst 0x99431802"
322 	              : "=r" (data0), "=r" (data1) : "r" (src) :);
323 }
324 
325 static const struct hwcap_data {
326 	const char *name;
327 	unsigned long at_hwcap;
328 	unsigned long hwcap_bit;
329 	const char *cpuinfo;
330 	sig_fn sigill_fn;
331 	bool sigill_reliable;
332 	sig_fn sigbus_fn;
333 	bool sigbus_reliable;
334 } hwcaps[] = {
335 	{
336 		.name = "AES",
337 		.at_hwcap = AT_HWCAP,
338 		.hwcap_bit = HWCAP_AES,
339 		.cpuinfo = "aes",
340 		.sigill_fn = aes_sigill,
341 	},
342 	{
343 		.name = "CRC32",
344 		.at_hwcap = AT_HWCAP,
345 		.hwcap_bit = HWCAP_CRC32,
346 		.cpuinfo = "crc32",
347 		.sigill_fn = crc32_sigill,
348 	},
349 	{
350 		.name = "CSSC",
351 		.at_hwcap = AT_HWCAP2,
352 		.hwcap_bit = HWCAP2_CSSC,
353 		.cpuinfo = "cssc",
354 		.sigill_fn = cssc_sigill,
355 	},
356 	{
357 		.name = "FP",
358 		.at_hwcap = AT_HWCAP,
359 		.hwcap_bit = HWCAP_FP,
360 		.cpuinfo = "fp",
361 		.sigill_fn = fp_sigill,
362 	},
363 	{
364 		.name = "JSCVT",
365 		.at_hwcap = AT_HWCAP,
366 		.hwcap_bit = HWCAP_JSCVT,
367 		.cpuinfo = "jscvt",
368 		.sigill_fn = jscvt_sigill,
369 	},
370 	{
371 		.name = "LRCPC",
372 		.at_hwcap = AT_HWCAP,
373 		.hwcap_bit = HWCAP_LRCPC,
374 		.cpuinfo = "lrcpc",
375 		.sigill_fn = lrcpc_sigill,
376 	},
377 	{
378 		.name = "LRCPC2",
379 		.at_hwcap = AT_HWCAP,
380 		.hwcap_bit = HWCAP_ILRCPC,
381 		.cpuinfo = "ilrcpc",
382 		.sigill_fn = ilrcpc_sigill,
383 	},
384 	{
385 		.name = "LRCPC3",
386 		.at_hwcap = AT_HWCAP2,
387 		.hwcap_bit = HWCAP2_LRCPC3,
388 		.cpuinfo = "lrcpc3",
389 		.sigill_fn = lrcpc3_sigill,
390 	},
391 	{
392 		.name = "LSE",
393 		.at_hwcap = AT_HWCAP,
394 		.hwcap_bit = HWCAP_ATOMICS,
395 		.cpuinfo = "atomics",
396 		.sigill_fn = atomics_sigill,
397 	},
398 	{
399 		.name = "LSE2",
400 		.at_hwcap = AT_HWCAP,
401 		.hwcap_bit = HWCAP_USCAT,
402 		.cpuinfo = "uscat",
403 		.sigill_fn = atomics_sigill,
404 		.sigbus_fn = uscat_sigbus,
405 		.sigbus_reliable = true,
406 	},
407 	{
408 		.name = "LSE128",
409 		.at_hwcap = AT_HWCAP2,
410 		.hwcap_bit = HWCAP2_LSE128,
411 		.cpuinfo = "lse128",
412 		.sigill_fn = lse128_sigill,
413 	},
414 	{
415 		.name = "MOPS",
416 		.at_hwcap = AT_HWCAP2,
417 		.hwcap_bit = HWCAP2_MOPS,
418 		.cpuinfo = "mops",
419 		.sigill_fn = mops_sigill,
420 		.sigill_reliable = true,
421 	},
422 	{
423 		.name = "PMULL",
424 		.at_hwcap = AT_HWCAP,
425 		.hwcap_bit = HWCAP_PMULL,
426 		.cpuinfo = "pmull",
427 		.sigill_fn = pmull_sigill,
428 	},
429 	{
430 		.name = "RNG",
431 		.at_hwcap = AT_HWCAP2,
432 		.hwcap_bit = HWCAP2_RNG,
433 		.cpuinfo = "rng",
434 		.sigill_fn = rng_sigill,
435 	},
436 	{
437 		.name = "RPRFM",
438 		.at_hwcap = AT_HWCAP2,
439 		.hwcap_bit = HWCAP2_RPRFM,
440 		.cpuinfo = "rprfm",
441 	},
442 	{
443 		.name = "SHA1",
444 		.at_hwcap = AT_HWCAP,
445 		.hwcap_bit = HWCAP_SHA1,
446 		.cpuinfo = "sha1",
447 		.sigill_fn = sha1_sigill,
448 	},
449 	{
450 		.name = "SHA2",
451 		.at_hwcap = AT_HWCAP,
452 		.hwcap_bit = HWCAP_SHA2,
453 		.cpuinfo = "sha2",
454 		.sigill_fn = sha2_sigill,
455 	},
456 	{
457 		.name = "SHA512",
458 		.at_hwcap = AT_HWCAP,
459 		.hwcap_bit = HWCAP_SHA512,
460 		.cpuinfo = "sha512",
461 		.sigill_fn = sha512_sigill,
462 	},
463 	{
464 		.name = "SME",
465 		.at_hwcap = AT_HWCAP2,
466 		.hwcap_bit = HWCAP2_SME,
467 		.cpuinfo = "sme",
468 		.sigill_fn = sme_sigill,
469 		.sigill_reliable = true,
470 	},
471 	{
472 		.name = "SME2",
473 		.at_hwcap = AT_HWCAP2,
474 		.hwcap_bit = HWCAP2_SME2,
475 		.cpuinfo = "sme2",
476 		.sigill_fn = sme2_sigill,
477 		.sigill_reliable = true,
478 	},
479 	{
480 		.name = "SME 2.1",
481 		.at_hwcap = AT_HWCAP2,
482 		.hwcap_bit = HWCAP2_SME2P1,
483 		.cpuinfo = "sme2p1",
484 		.sigill_fn = sme2p1_sigill,
485 	},
486 	{
487 		.name = "SME I16I32",
488 		.at_hwcap = AT_HWCAP2,
489 		.hwcap_bit = HWCAP2_SME_I16I32,
490 		.cpuinfo = "smei16i32",
491 		.sigill_fn = smei16i32_sigill,
492 	},
493 	{
494 		.name = "SME BI32I32",
495 		.at_hwcap = AT_HWCAP2,
496 		.hwcap_bit = HWCAP2_SME_BI32I32,
497 		.cpuinfo = "smebi32i32",
498 		.sigill_fn = smebi32i32_sigill,
499 	},
500 	{
501 		.name = "SME B16B16",
502 		.at_hwcap = AT_HWCAP2,
503 		.hwcap_bit = HWCAP2_SME_B16B16,
504 		.cpuinfo = "smeb16b16",
505 		.sigill_fn = smeb16b16_sigill,
506 	},
507 	{
508 		.name = "SME F16F16",
509 		.at_hwcap = AT_HWCAP2,
510 		.hwcap_bit = HWCAP2_SME_F16F16,
511 		.cpuinfo = "smef16f16",
512 		.sigill_fn = smef16f16_sigill,
513 	},
514 	{
515 		.name = "SVE",
516 		.at_hwcap = AT_HWCAP,
517 		.hwcap_bit = HWCAP_SVE,
518 		.cpuinfo = "sve",
519 		.sigill_fn = sve_sigill,
520 		.sigill_reliable = true,
521 	},
522 	{
523 		.name = "SVE 2",
524 		.at_hwcap = AT_HWCAP2,
525 		.hwcap_bit = HWCAP2_SVE2,
526 		.cpuinfo = "sve2",
527 		.sigill_fn = sve2_sigill,
528 	},
529 	{
530 		.name = "SVE 2.1",
531 		.at_hwcap = AT_HWCAP2,
532 		.hwcap_bit = HWCAP2_SVE2P1,
533 		.cpuinfo = "sve2p1",
534 		.sigill_fn = sve2p1_sigill,
535 	},
536 	{
537 		.name = "SVE AES",
538 		.at_hwcap = AT_HWCAP2,
539 		.hwcap_bit = HWCAP2_SVEAES,
540 		.cpuinfo = "sveaes",
541 		.sigill_fn = sveaes_sigill,
542 	},
543 	{
544 		.name = "SVE2 B16B16",
545 		.at_hwcap = AT_HWCAP2,
546 		.hwcap_bit = HWCAP2_SVE_B16B16,
547 		.cpuinfo = "sveb16b16",
548 		.sigill_fn = sveb16b16_sigill,
549 	},
550 	{
551 		.name = "SVE2 PMULL",
552 		.at_hwcap = AT_HWCAP2,
553 		.hwcap_bit = HWCAP2_SVEPMULL,
554 		.cpuinfo = "svepmull",
555 		.sigill_fn = svepmull_sigill,
556 	},
557 	{
558 		.name = "SVE2 BITPERM",
559 		.at_hwcap = AT_HWCAP2,
560 		.hwcap_bit = HWCAP2_SVEBITPERM,
561 		.cpuinfo = "svebitperm",
562 		.sigill_fn = svebitperm_sigill,
563 	},
564 	{
565 		.name = "SVE2 SHA3",
566 		.at_hwcap = AT_HWCAP2,
567 		.hwcap_bit = HWCAP2_SVESHA3,
568 		.cpuinfo = "svesha3",
569 		.sigill_fn = svesha3_sigill,
570 	},
571 	{
572 		.name = "SVE2 SM4",
573 		.at_hwcap = AT_HWCAP2,
574 		.hwcap_bit = HWCAP2_SVESM4,
575 		.cpuinfo = "svesm4",
576 		.sigill_fn = svesm4_sigill,
577 	},
578 	{
579 		.name = "SVE2 I8MM",
580 		.at_hwcap = AT_HWCAP2,
581 		.hwcap_bit = HWCAP2_SVEI8MM,
582 		.cpuinfo = "svei8mm",
583 		.sigill_fn = svei8mm_sigill,
584 	},
585 	{
586 		.name = "SVE2 F32MM",
587 		.at_hwcap = AT_HWCAP2,
588 		.hwcap_bit = HWCAP2_SVEF32MM,
589 		.cpuinfo = "svef32mm",
590 		.sigill_fn = svef32mm_sigill,
591 	},
592 	{
593 		.name = "SVE2 F64MM",
594 		.at_hwcap = AT_HWCAP2,
595 		.hwcap_bit = HWCAP2_SVEF64MM,
596 		.cpuinfo = "svef64mm",
597 		.sigill_fn = svef64mm_sigill,
598 	},
599 	{
600 		.name = "SVE2 BF16",
601 		.at_hwcap = AT_HWCAP2,
602 		.hwcap_bit = HWCAP2_SVEBF16,
603 		.cpuinfo = "svebf16",
604 		.sigill_fn = svebf16_sigill,
605 	},
606 	{
607 		.name = "SVE2 EBF16",
608 		.at_hwcap = AT_HWCAP2,
609 		.hwcap_bit = HWCAP2_SVE_EBF16,
610 		.cpuinfo = "sveebf16",
611 	},
612 	{
613 		.name = "HBC",
614 		.at_hwcap = AT_HWCAP2,
615 		.hwcap_bit = HWCAP2_HBC,
616 		.cpuinfo = "hbc",
617 		.sigill_fn = hbc_sigill,
618 		.sigill_reliable = true,
619 	},
620 };
621 
622 typedef void (*sighandler_fn)(int, siginfo_t *, void *);
623 
624 #define DEF_SIGHANDLER_FUNC(SIG, NUM)					\
625 static bool seen_##SIG;							\
626 static void handle_##SIG(int sig, siginfo_t *info, void *context)	\
627 {									\
628 	ucontext_t *uc = context;					\
629 									\
630 	seen_##SIG = true;						\
631 	/* Skip over the offending instruction */			\
632 	uc->uc_mcontext.pc += 4;					\
633 }
634 
635 DEF_SIGHANDLER_FUNC(sigill, SIGILL);
636 DEF_SIGHANDLER_FUNC(sigbus, SIGBUS);
637 
638 bool cpuinfo_present(const char *name)
639 {
640 	FILE *f;
641 	char buf[2048], name_space[30], name_newline[30];
642 	char *s;
643 
644 	/*
645 	 * The feature should appear with a leading space and either a
646 	 * trailing space or a newline.
647 	 */
648 	snprintf(name_space, sizeof(name_space), " %s ", name);
649 	snprintf(name_newline, sizeof(name_newline), " %s\n", name);
650 
651 	f = fopen("/proc/cpuinfo", "r");
652 	if (!f) {
653 		ksft_print_msg("Failed to open /proc/cpuinfo\n");
654 		return false;
655 	}
656 
657 	while (fgets(buf, sizeof(buf), f)) {
658 		/* Features: line? */
659 		if (strncmp(buf, "Features\t:", strlen("Features\t:")) != 0)
660 			continue;
661 
662 		/* All CPUs should be symmetric, don't read any more */
663 		fclose(f);
664 
665 		s = strstr(buf, name_space);
666 		if (s)
667 			return true;
668 		s = strstr(buf, name_newline);
669 		if (s)
670 			return true;
671 
672 		return false;
673 	}
674 
675 	ksft_print_msg("Failed to find Features in /proc/cpuinfo\n");
676 	fclose(f);
677 	return false;
678 }
679 
680 static int install_sigaction(int signum, sighandler_fn handler)
681 {
682 	int ret;
683 	struct sigaction sa;
684 
685 	memset(&sa, 0, sizeof(sa));
686 	sa.sa_sigaction = handler;
687 	sa.sa_flags = SA_RESTART | SA_SIGINFO;
688 	sigemptyset(&sa.sa_mask);
689 	ret = sigaction(signum, &sa, NULL);
690 	if (ret < 0)
691 		ksft_exit_fail_msg("Failed to install SIGNAL handler: %s (%d)\n",
692 				   strerror(errno), errno);
693 
694 	return ret;
695 }
696 
697 static void uninstall_sigaction(int signum)
698 {
699 	if (sigaction(signum, NULL, NULL) < 0)
700 		ksft_exit_fail_msg("Failed to uninstall SIGNAL handler: %s (%d)\n",
701 				   strerror(errno), errno);
702 }
703 
704 #define DEF_INST_RAISE_SIG(SIG, NUM)					\
705 static bool inst_raise_##SIG(const struct hwcap_data *hwcap,		\
706 				bool have_hwcap)			\
707 {									\
708 	if (!hwcap->SIG##_fn) {						\
709 		ksft_test_result_skip(#SIG"_%s\n", hwcap->name);	\
710 		/* assume that it would raise exception in default */	\
711 		return true;						\
712 	}								\
713 									\
714 	install_sigaction(NUM, handle_##SIG);				\
715 									\
716 	seen_##SIG = false;						\
717 	hwcap->SIG##_fn();						\
718 									\
719 	if (have_hwcap) {						\
720 		/* Should be able to use the extension */		\
721 		ksft_test_result(!seen_##SIG,				\
722 				#SIG"_%s\n", hwcap->name);		\
723 	} else if (hwcap->SIG##_reliable) {				\
724 		/* Guaranteed a SIGNAL */				\
725 		ksft_test_result(seen_##SIG,				\
726 				#SIG"_%s\n", hwcap->name);		\
727 	} else {							\
728 		/* Missing SIGNAL might be fine */			\
729 		ksft_print_msg(#SIG"_%sreported for %s\n",		\
730 				seen_##SIG ? "" : "not ",		\
731 				hwcap->name);				\
732 		ksft_test_result_skip(#SIG"_%s\n",			\
733 					hwcap->name);			\
734 	}								\
735 									\
736 	uninstall_sigaction(NUM);					\
737 	return seen_##SIG;						\
738 }
739 
740 DEF_INST_RAISE_SIG(sigill, SIGILL);
741 DEF_INST_RAISE_SIG(sigbus, SIGBUS);
742 
743 int main(void)
744 {
745 	int i;
746 	const struct hwcap_data *hwcap;
747 	bool have_cpuinfo, have_hwcap, raise_sigill;
748 
749 	ksft_print_header();
750 	ksft_set_plan(ARRAY_SIZE(hwcaps) * TESTS_PER_HWCAP);
751 
752 	for (i = 0; i < ARRAY_SIZE(hwcaps); i++) {
753 		hwcap = &hwcaps[i];
754 
755 		have_hwcap = getauxval(hwcap->at_hwcap) & hwcap->hwcap_bit;
756 		have_cpuinfo = cpuinfo_present(hwcap->cpuinfo);
757 
758 		if (have_hwcap)
759 			ksft_print_msg("%s present\n", hwcap->name);
760 
761 		ksft_test_result(have_hwcap == have_cpuinfo,
762 				 "cpuinfo_match_%s\n", hwcap->name);
763 
764 		/*
765 		 * Testing for SIGBUS only makes sense after make sure
766 		 * that the instruction does not cause a SIGILL signal.
767 		 */
768 		raise_sigill = inst_raise_sigill(hwcap, have_hwcap);
769 		if (!raise_sigill)
770 			inst_raise_sigbus(hwcap, have_hwcap);
771 		else
772 			ksft_test_result_skip("sigbus_%s\n", hwcap->name);
773 	}
774 
775 	ksft_print_cnts();
776 
777 	return 0;
778 }
779