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