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