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