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