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