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 2
23 
24 /*
25  * Function expected to generate SIGILL when the feature is not
26  * supported and return when it is supported. If SIGILL is generated
27  * then the handler must be able to skip over the instruction safely.
28  *
29  * Note that it is expected that for many architecture extensions
30  * there are no specific traps due to no architecture state being
31  * added so we may not fault if running on a kernel which doesn't know
32  * to add the hwcap.
33  */
34 typedef void (*sigill_fn)(void);
35 
36 static void cssc_sigill(void)
37 {
38 	/* CNT x0, x0 */
39 	asm volatile(".inst 0xdac01c00" : : : "x0");
40 }
41 
42 static void rng_sigill(void)
43 {
44 	asm volatile("mrs x0, S3_3_C2_C4_0" : : : "x0");
45 }
46 
47 static void sme_sigill(void)
48 {
49 	/* RDSVL x0, #0 */
50 	asm volatile(".inst 0x04bf5800" : : : "x0");
51 }
52 
53 static void sve_sigill(void)
54 {
55 	/* RDVL x0, #0 */
56 	asm volatile(".inst 0x04bf5000" : : : "x0");
57 }
58 
59 static void sve2_sigill(void)
60 {
61 	/* SQABS Z0.b, P0/M, Z0.B */
62 	asm volatile(".inst 0x4408A000" : : : "z0");
63 }
64 
65 static void sveaes_sigill(void)
66 {
67 	/* AESD z0.b, z0.b, z0.b */
68 	asm volatile(".inst 0x4522e400" : : : "z0");
69 }
70 
71 static void svepmull_sigill(void)
72 {
73 	/* PMULLB Z0.Q, Z0.D, Z0.D */
74 	asm volatile(".inst 0x45006800" : : : "z0");
75 }
76 
77 static void svebitperm_sigill(void)
78 {
79 	/* BDEP Z0.B, Z0.B, Z0.B */
80 	asm volatile(".inst 0x4500b400" : : : "z0");
81 }
82 
83 static void svesha3_sigill(void)
84 {
85 	/* EOR3 Z0.D, Z0.D, Z0.D, Z0.D */
86 	asm volatile(".inst 0x4203800" : : : "z0");
87 }
88 
89 static void svesm4_sigill(void)
90 {
91 	/* SM4E Z0.S, Z0.S, Z0.S */
92 	asm volatile(".inst 0x4523e000" : : : "z0");
93 }
94 
95 static void svei8mm_sigill(void)
96 {
97 	/* USDOT Z0.S, Z0.B, Z0.B[0] */
98 	asm volatile(".inst 0x44a01800" : : : "z0");
99 }
100 
101 static void svef32mm_sigill(void)
102 {
103 	/* FMMLA Z0.S, Z0.S, Z0.S */
104 	asm volatile(".inst 0x64a0e400" : : : "z0");
105 }
106 
107 static void svef64mm_sigill(void)
108 {
109 	/* FMMLA Z0.D, Z0.D, Z0.D */
110 	asm volatile(".inst 0x64e0e400" : : : "z0");
111 }
112 
113 static void svebf16_sigill(void)
114 {
115 	/* BFCVT Z0.H, P0/M, Z0.S */
116 	asm volatile(".inst 0x658aa000" : : : "z0");
117 }
118 
119 static const struct hwcap_data {
120 	const char *name;
121 	unsigned long at_hwcap;
122 	unsigned long hwcap_bit;
123 	const char *cpuinfo;
124 	sigill_fn sigill_fn;
125 	bool sigill_reliable;
126 } hwcaps[] = {
127 	{
128 		.name = "CSSC",
129 		.at_hwcap = AT_HWCAP2,
130 		.hwcap_bit = HWCAP2_CSSC,
131 		.cpuinfo = "cssc",
132 		.sigill_fn = cssc_sigill,
133 	},
134 	{
135 		.name = "RNG",
136 		.at_hwcap = AT_HWCAP2,
137 		.hwcap_bit = HWCAP2_RNG,
138 		.cpuinfo = "rng",
139 		.sigill_fn = rng_sigill,
140 	},
141 	{
142 		.name = "RPRFM",
143 		.at_hwcap = AT_HWCAP2,
144 		.hwcap_bit = HWCAP2_RPRFM,
145 		.cpuinfo = "rprfm",
146 	},
147 	{
148 		.name = "SME",
149 		.at_hwcap = AT_HWCAP2,
150 		.hwcap_bit = HWCAP2_SME,
151 		.cpuinfo = "sme",
152 		.sigill_fn = sme_sigill,
153 		.sigill_reliable = true,
154 	},
155 	{
156 		.name = "SVE",
157 		.at_hwcap = AT_HWCAP,
158 		.hwcap_bit = HWCAP_SVE,
159 		.cpuinfo = "sve",
160 		.sigill_fn = sve_sigill,
161 		.sigill_reliable = true,
162 	},
163 	{
164 		.name = "SVE 2",
165 		.at_hwcap = AT_HWCAP2,
166 		.hwcap_bit = HWCAP2_SVE2,
167 		.cpuinfo = "sve2",
168 		.sigill_fn = sve2_sigill,
169 	},
170 	{
171 		.name = "SVE AES",
172 		.at_hwcap = AT_HWCAP2,
173 		.hwcap_bit = HWCAP2_SVEAES,
174 		.cpuinfo = "sveaes",
175 		.sigill_fn = sveaes_sigill,
176 	},
177 	{
178 		.name = "SVE2 PMULL",
179 		.at_hwcap = AT_HWCAP2,
180 		.hwcap_bit = HWCAP2_SVEPMULL,
181 		.cpuinfo = "svepmull",
182 		.sigill_fn = svepmull_sigill,
183 	},
184 	{
185 		.name = "SVE2 BITPERM",
186 		.at_hwcap = AT_HWCAP2,
187 		.hwcap_bit = HWCAP2_SVEBITPERM,
188 		.cpuinfo = "svebitperm",
189 		.sigill_fn = svebitperm_sigill,
190 	},
191 	{
192 		.name = "SVE2 SHA3",
193 		.at_hwcap = AT_HWCAP2,
194 		.hwcap_bit = HWCAP2_SVESHA3,
195 		.cpuinfo = "svesha3",
196 		.sigill_fn = svesha3_sigill,
197 	},
198 	{
199 		.name = "SVE2 SM4",
200 		.at_hwcap = AT_HWCAP2,
201 		.hwcap_bit = HWCAP2_SVESM4,
202 		.cpuinfo = "svesm4",
203 		.sigill_fn = svesm4_sigill,
204 	},
205 	{
206 		.name = "SVE2 I8MM",
207 		.at_hwcap = AT_HWCAP2,
208 		.hwcap_bit = HWCAP2_SVEI8MM,
209 		.cpuinfo = "svei8mm",
210 		.sigill_fn = svei8mm_sigill,
211 	},
212 	{
213 		.name = "SVE2 F32MM",
214 		.at_hwcap = AT_HWCAP2,
215 		.hwcap_bit = HWCAP2_SVEF32MM,
216 		.cpuinfo = "svef32mm",
217 		.sigill_fn = svef32mm_sigill,
218 	},
219 	{
220 		.name = "SVE2 F64MM",
221 		.at_hwcap = AT_HWCAP2,
222 		.hwcap_bit = HWCAP2_SVEF64MM,
223 		.cpuinfo = "svef64mm",
224 		.sigill_fn = svef64mm_sigill,
225 	},
226 	{
227 		.name = "SVE2 BF16",
228 		.at_hwcap = AT_HWCAP2,
229 		.hwcap_bit = HWCAP2_SVEBF16,
230 		.cpuinfo = "svebf16",
231 		.sigill_fn = svebf16_sigill,
232 	},
233 	{
234 		.name = "SVE2 EBF16",
235 		.at_hwcap = AT_HWCAP2,
236 		.hwcap_bit = HWCAP2_SVE_EBF16,
237 		.cpuinfo = "sveebf16",
238 	},
239 };
240 
241 static bool seen_sigill;
242 
243 static void handle_sigill(int sig, siginfo_t *info, void *context)
244 {
245 	ucontext_t *uc = context;
246 
247 	seen_sigill = true;
248 
249 	/* Skip over the offending instruction */
250 	uc->uc_mcontext.pc += 4;
251 }
252 
253 bool cpuinfo_present(const char *name)
254 {
255 	FILE *f;
256 	char buf[2048], name_space[30], name_newline[30];
257 	char *s;
258 
259 	/*
260 	 * The feature should appear with a leading space and either a
261 	 * trailing space or a newline.
262 	 */
263 	snprintf(name_space, sizeof(name_space), " %s ", name);
264 	snprintf(name_newline, sizeof(name_newline), " %s\n", name);
265 
266 	f = fopen("/proc/cpuinfo", "r");
267 	if (!f) {
268 		ksft_print_msg("Failed to open /proc/cpuinfo\n");
269 		return false;
270 	}
271 
272 	while (fgets(buf, sizeof(buf), f)) {
273 		/* Features: line? */
274 		if (strncmp(buf, "Features\t:", strlen("Features\t:")) != 0)
275 			continue;
276 
277 		/* All CPUs should be symmetric, don't read any more */
278 		fclose(f);
279 
280 		s = strstr(buf, name_space);
281 		if (s)
282 			return true;
283 		s = strstr(buf, name_newline);
284 		if (s)
285 			return true;
286 
287 		return false;
288 	}
289 
290 	ksft_print_msg("Failed to find Features in /proc/cpuinfo\n");
291 	fclose(f);
292 	return false;
293 }
294 
295 int main(void)
296 {
297 	const struct hwcap_data *hwcap;
298 	int i, ret;
299 	bool have_cpuinfo, have_hwcap;
300 	struct sigaction sa;
301 
302 	ksft_print_header();
303 	ksft_set_plan(ARRAY_SIZE(hwcaps) * TESTS_PER_HWCAP);
304 
305 	memset(&sa, 0, sizeof(sa));
306 	sa.sa_sigaction = handle_sigill;
307 	sa.sa_flags = SA_RESTART | SA_SIGINFO;
308 	sigemptyset(&sa.sa_mask);
309 	ret = sigaction(SIGILL, &sa, NULL);
310 	if (ret < 0)
311 		ksft_exit_fail_msg("Failed to install SIGILL handler: %s (%d)\n",
312 				   strerror(errno), errno);
313 
314 	for (i = 0; i < ARRAY_SIZE(hwcaps); i++) {
315 		hwcap = &hwcaps[i];
316 
317 		have_hwcap = getauxval(hwcap->at_hwcap) & hwcap->hwcap_bit;
318 		have_cpuinfo = cpuinfo_present(hwcap->cpuinfo);
319 
320 		if (have_hwcap)
321 			ksft_print_msg("%s present\n", hwcap->name);
322 
323 		ksft_test_result(have_hwcap == have_cpuinfo,
324 				 "cpuinfo_match_%s\n", hwcap->name);
325 
326 		if (hwcap->sigill_fn) {
327 			seen_sigill = false;
328 			hwcap->sigill_fn();
329 
330 			if (have_hwcap) {
331 				/* Should be able to use the extension */
332 				ksft_test_result(!seen_sigill, "sigill_%s\n",
333 						 hwcap->name);
334 			} else if (hwcap->sigill_reliable) {
335 				/* Guaranteed a SIGILL */
336 				ksft_test_result(seen_sigill, "sigill_%s\n",
337 						 hwcap->name);
338 			} else {
339 				/* Missing SIGILL might be fine */
340 				ksft_print_msg("SIGILL %sreported for %s\n",
341 					       seen_sigill ? "" : "not ",
342 					       hwcap->name);
343 				ksft_test_result_skip("sigill_%s\n",
344 						      hwcap->name);
345 			}
346 		} else {
347 			ksft_test_result_skip("sigill_%s\n",
348 					      hwcap->name);
349 		}
350 	}
351 
352 	ksft_print_cnts();
353 
354 	return 0;
355 }
356