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