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}
996