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