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