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