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
ilrcpc_sigill(void)101 static void ilrcpc_sigill(void)
102 {
103 /* LDAPUR W0, [SP, #8] */
104 asm volatile(".inst 0x994083e0" : : : );
105 }
106
jscvt_sigill(void)107 static void jscvt_sigill(void)
108 {
109 /* FJCVTZS W0, D0 */
110 asm volatile(".inst 0x1e7e0000" : : : );
111 }
112
lrcpc_sigill(void)113 static void lrcpc_sigill(void)
114 {
115 /* LDAPR W0, [SP, #0] */
116 asm volatile(".inst 0xb8bfc3e0" : : : );
117 }
118
lse128_sigill(void)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
lut_sigill(void)133 static void lut_sigill(void)
134 {
135 /* LUTI2 V0.16B, { V0.16B }, V[0] */
136 asm volatile(".inst 0x4e801000");
137 }
138
mops_sigill(void)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
pmull_sigill(void)153 static void pmull_sigill(void)
154 {
155 /* PMULL V0.1Q, V0.1D, V0.1D */
156 asm volatile(".inst 0x0ee0e000" : : : );
157 }
158
poe_sigill(void)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
rng_sigill(void)165 static void rng_sigill(void)
166 {
167 asm volatile("mrs x0, S3_3_C2_C4_0" : : : "x0");
168 }
169
sha1_sigill(void)170 static void sha1_sigill(void)
171 {
172 /* SHA1H S0, S0 */
173 asm volatile(".inst 0x5e280800" : : : );
174 }
175
sha2_sigill(void)176 static void sha2_sigill(void)
177 {
178 /* SHA256H Q0, Q0, V0.4S */
179 asm volatile(".inst 0x5e004000" : : : );
180 }
181
sha512_sigill(void)182 static void sha512_sigill(void)
183 {
184 /* SHA512H Q0, Q0, V0.2D */
185 asm volatile(".inst 0xce608000" : : : );
186 }
187
sme_sigill(void)188 static void sme_sigill(void)
189 {
190 /* RDSVL x0, #0 */
191 asm volatile(".inst 0x04bf5800" : : : "x0");
192 }
193
sme2_sigill(void)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
sme2p1_sigill(void)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
smei16i32_sigill(void)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
smebi32i32_sigill(void)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
smeb16b16_sigill(void)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
smef16f16_sigill(void)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
smef8f16_sigill(void)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
smef8f32_sigill(void)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
smelutv2_sigill(void)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
smesf8dp2_sigill(void)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
smesf8dp4_sigill(void)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
smesf8fma_sigill(void)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
sve_sigill(void)338 static void sve_sigill(void)
339 {
340 /* RDVL x0, #0 */
341 asm volatile(".inst 0x04bf5000" : : : "x0");
342 }
343
sve2_sigill(void)344 static void sve2_sigill(void)
345 {
346 /* SQABS Z0.b, P0/M, Z0.B */
347 asm volatile(".inst 0x4408A000" : : : "z0");
348 }
349
sve2p1_sigill(void)350 static void sve2p1_sigill(void)
351 {
352 /* BFADD Z0.H, Z0.H, Z0.H */
353 asm volatile(".inst 0x65000000" : : : "z0");
354 }
355
sveaes_sigill(void)356 static void sveaes_sigill(void)
357 {
358 /* AESD z0.b, z0.b, z0.b */
359 asm volatile(".inst 0x4522e400" : : : "z0");
360 }
361
sveb16b16_sigill(void)362 static void sveb16b16_sigill(void)
363 {
364 /* BFADD ZA.H[W0, 0], {Z0.H-Z1.H} */
365 asm volatile(".inst 0xC1E41C00" : : : );
366 }
367
svepmull_sigill(void)368 static void svepmull_sigill(void)
369 {
370 /* PMULLB Z0.Q, Z0.D, Z0.D */
371 asm volatile(".inst 0x45006800" : : : "z0");
372 }
373
svebitperm_sigill(void)374 static void svebitperm_sigill(void)
375 {
376 /* BDEP Z0.B, Z0.B, Z0.B */
377 asm volatile(".inst 0x4500b400" : : : "z0");
378 }
379
svesha3_sigill(void)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
svesm4_sigill(void)386 static void svesm4_sigill(void)
387 {
388 /* SM4E Z0.S, Z0.S, Z0.S */
389 asm volatile(".inst 0x4523e000" : : : "z0");
390 }
391
svei8mm_sigill(void)392 static void svei8mm_sigill(void)
393 {
394 /* USDOT Z0.S, Z0.B, Z0.B[0] */
395 asm volatile(".inst 0x44a01800" : : : "z0");
396 }
397
svef32mm_sigill(void)398 static void svef32mm_sigill(void)
399 {
400 /* FMMLA Z0.S, Z0.S, Z0.S */
401 asm volatile(".inst 0x64a0e400" : : : "z0");
402 }
403
svef64mm_sigill(void)404 static void svef64mm_sigill(void)
405 {
406 /* FMMLA Z0.D, Z0.D, Z0.D */
407 asm volatile(".inst 0x64e0e400" : : : "z0");
408 }
409
svebf16_sigill(void)410 static void svebf16_sigill(void)
411 {
412 /* BFCVT Z0.H, P0/M, Z0.S */
413 asm volatile(".inst 0x658aa000" : : : "z0");
414 }
415
hbc_sigill(void)416 static void hbc_sigill(void)
417 {
418 /* BC.EQ +4 */
419 asm volatile("cmp xzr, xzr\n"
420 ".inst 0x54000030" : : : "cc");
421 }
422
uscat_sigbus(void)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
lrcpc3_sigill(void)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
cpuinfo_present(const char * name)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
install_sigaction(int signum,sighandler_fn handler)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
uninstall_sigaction(int signum)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
main(void)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