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
cssc_sigill(void)36 static void cssc_sigill(void)
37 {
38 /* CNT x0, x0 */
39 asm volatile(".inst 0xdac01c00" : : : "x0");
40 }
41
rng_sigill(void)42 static void rng_sigill(void)
43 {
44 asm volatile("mrs x0, S3_3_C2_C4_0" : : : "x0");
45 }
46
sme_sigill(void)47 static void sme_sigill(void)
48 {
49 /* RDSVL x0, #0 */
50 asm volatile(".inst 0x04bf5800" : : : "x0");
51 }
52
sme2_sigill(void)53 static void sme2_sigill(void)
54 {
55 /* SMSTART ZA */
56 asm volatile("msr S0_3_C4_C5_3, xzr" : : : );
57
58 /* ZERO ZT0 */
59 asm volatile(".inst 0xc0480001" : : : );
60
61 /* SMSTOP */
62 asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
63 }
64
sme2p1_sigill(void)65 static void sme2p1_sigill(void)
66 {
67 /* SMSTART SM */
68 asm volatile("msr S0_3_C4_C3_3, xzr" : : : );
69
70 /* BFCLAMP { Z0.H - Z1.H }, Z0.H, Z0.H */
71 asm volatile(".inst 0xc120C000" : : : );
72
73 /* SMSTOP */
74 asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
75 }
76
smei16i32_sigill(void)77 static void smei16i32_sigill(void)
78 {
79 /* SMSTART */
80 asm volatile("msr S0_3_C4_C7_3, xzr" : : : );
81
82 /* SMOPA ZA0.S, P0/M, P0/M, Z0.B, Z0.B */
83 asm volatile(".inst 0xa0800000" : : : );
84
85 /* SMSTOP */
86 asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
87 }
88
smebi32i32_sigill(void)89 static void smebi32i32_sigill(void)
90 {
91 /* SMSTART */
92 asm volatile("msr S0_3_C4_C7_3, xzr" : : : );
93
94 /* BMOPA ZA0.S, P0/M, P0/M, Z0.B, Z0.B */
95 asm volatile(".inst 0x80800008" : : : );
96
97 /* SMSTOP */
98 asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
99 }
100
smeb16b16_sigill(void)101 static void smeb16b16_sigill(void)
102 {
103 /* SMSTART */
104 asm volatile("msr S0_3_C4_C7_3, xzr" : : : );
105
106 /* BFADD ZA.H[W0, 0], {Z0.H-Z1.H} */
107 asm volatile(".inst 0xC1E41C00" : : : );
108
109 /* SMSTOP */
110 asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
111 }
112
smef16f16_sigill(void)113 static void smef16f16_sigill(void)
114 {
115 /* SMSTART */
116 asm volatile("msr S0_3_C4_C7_3, xzr" : : : );
117
118 /* FADD ZA.H[W0, 0], { Z0.H-Z1.H } */
119 asm volatile(".inst 0xc1a41C00" : : : );
120
121 /* SMSTOP */
122 asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
123 }
124
sve_sigill(void)125 static void sve_sigill(void)
126 {
127 /* RDVL x0, #0 */
128 asm volatile(".inst 0x04bf5000" : : : "x0");
129 }
130
sve2_sigill(void)131 static void sve2_sigill(void)
132 {
133 /* SQABS Z0.b, P0/M, Z0.B */
134 asm volatile(".inst 0x4408A000" : : : "z0");
135 }
136
sve2p1_sigill(void)137 static void sve2p1_sigill(void)
138 {
139 /* BFADD Z0.H, Z0.H, Z0.H */
140 asm volatile(".inst 0x65000000" : : : "z0");
141 }
142
sveaes_sigill(void)143 static void sveaes_sigill(void)
144 {
145 /* AESD z0.b, z0.b, z0.b */
146 asm volatile(".inst 0x4522e400" : : : "z0");
147 }
148
svepmull_sigill(void)149 static void svepmull_sigill(void)
150 {
151 /* PMULLB Z0.Q, Z0.D, Z0.D */
152 asm volatile(".inst 0x45006800" : : : "z0");
153 }
154
svebitperm_sigill(void)155 static void svebitperm_sigill(void)
156 {
157 /* BDEP Z0.B, Z0.B, Z0.B */
158 asm volatile(".inst 0x4500b400" : : : "z0");
159 }
160
svesha3_sigill(void)161 static void svesha3_sigill(void)
162 {
163 /* EOR3 Z0.D, Z0.D, Z0.D, Z0.D */
164 asm volatile(".inst 0x4203800" : : : "z0");
165 }
166
svesm4_sigill(void)167 static void svesm4_sigill(void)
168 {
169 /* SM4E Z0.S, Z0.S, Z0.S */
170 asm volatile(".inst 0x4523e000" : : : "z0");
171 }
172
svei8mm_sigill(void)173 static void svei8mm_sigill(void)
174 {
175 /* USDOT Z0.S, Z0.B, Z0.B[0] */
176 asm volatile(".inst 0x44a01800" : : : "z0");
177 }
178
svef32mm_sigill(void)179 static void svef32mm_sigill(void)
180 {
181 /* FMMLA Z0.S, Z0.S, Z0.S */
182 asm volatile(".inst 0x64a0e400" : : : "z0");
183 }
184
svef64mm_sigill(void)185 static void svef64mm_sigill(void)
186 {
187 /* FMMLA Z0.D, Z0.D, Z0.D */
188 asm volatile(".inst 0x64e0e400" : : : "z0");
189 }
190
svebf16_sigill(void)191 static void svebf16_sigill(void)
192 {
193 /* BFCVT Z0.H, P0/M, Z0.S */
194 asm volatile(".inst 0x658aa000" : : : "z0");
195 }
196
197 static const struct hwcap_data {
198 const char *name;
199 unsigned long at_hwcap;
200 unsigned long hwcap_bit;
201 const char *cpuinfo;
202 sigill_fn sigill_fn;
203 bool sigill_reliable;
204 } hwcaps[] = {
205 {
206 .name = "CSSC",
207 .at_hwcap = AT_HWCAP2,
208 .hwcap_bit = HWCAP2_CSSC,
209 .cpuinfo = "cssc",
210 .sigill_fn = cssc_sigill,
211 },
212 {
213 .name = "RNG",
214 .at_hwcap = AT_HWCAP2,
215 .hwcap_bit = HWCAP2_RNG,
216 .cpuinfo = "rng",
217 .sigill_fn = rng_sigill,
218 },
219 {
220 .name = "RPRFM",
221 .at_hwcap = AT_HWCAP2,
222 .hwcap_bit = HWCAP2_RPRFM,
223 .cpuinfo = "rprfm",
224 },
225 {
226 .name = "SME",
227 .at_hwcap = AT_HWCAP2,
228 .hwcap_bit = HWCAP2_SME,
229 .cpuinfo = "sme",
230 .sigill_fn = sme_sigill,
231 .sigill_reliable = true,
232 },
233 {
234 .name = "SME2",
235 .at_hwcap = AT_HWCAP2,
236 .hwcap_bit = HWCAP2_SME2,
237 .cpuinfo = "sme2",
238 .sigill_fn = sme2_sigill,
239 .sigill_reliable = true,
240 },
241 {
242 .name = "SME 2.1",
243 .at_hwcap = AT_HWCAP2,
244 .hwcap_bit = HWCAP2_SME2P1,
245 .cpuinfo = "sme2p1",
246 .sigill_fn = sme2p1_sigill,
247 },
248 {
249 .name = "SME I16I32",
250 .at_hwcap = AT_HWCAP2,
251 .hwcap_bit = HWCAP2_SME_I16I32,
252 .cpuinfo = "smei16i32",
253 .sigill_fn = smei16i32_sigill,
254 },
255 {
256 .name = "SME BI32I32",
257 .at_hwcap = AT_HWCAP2,
258 .hwcap_bit = HWCAP2_SME_BI32I32,
259 .cpuinfo = "smebi32i32",
260 .sigill_fn = smebi32i32_sigill,
261 },
262 {
263 .name = "SME B16B16",
264 .at_hwcap = AT_HWCAP2,
265 .hwcap_bit = HWCAP2_SME_B16B16,
266 .cpuinfo = "smeb16b16",
267 .sigill_fn = smeb16b16_sigill,
268 },
269 {
270 .name = "SME F16F16",
271 .at_hwcap = AT_HWCAP2,
272 .hwcap_bit = HWCAP2_SME_F16F16,
273 .cpuinfo = "smef16f16",
274 .sigill_fn = smef16f16_sigill,
275 },
276 {
277 .name = "SVE",
278 .at_hwcap = AT_HWCAP,
279 .hwcap_bit = HWCAP_SVE,
280 .cpuinfo = "sve",
281 .sigill_fn = sve_sigill,
282 .sigill_reliable = true,
283 },
284 {
285 .name = "SVE 2",
286 .at_hwcap = AT_HWCAP2,
287 .hwcap_bit = HWCAP2_SVE2,
288 .cpuinfo = "sve2",
289 .sigill_fn = sve2_sigill,
290 },
291 {
292 .name = "SVE 2.1",
293 .at_hwcap = AT_HWCAP2,
294 .hwcap_bit = HWCAP2_SVE2P1,
295 .cpuinfo = "sve2p1",
296 .sigill_fn = sve2p1_sigill,
297 },
298 {
299 .name = "SVE AES",
300 .at_hwcap = AT_HWCAP2,
301 .hwcap_bit = HWCAP2_SVEAES,
302 .cpuinfo = "sveaes",
303 .sigill_fn = sveaes_sigill,
304 },
305 {
306 .name = "SVE2 PMULL",
307 .at_hwcap = AT_HWCAP2,
308 .hwcap_bit = HWCAP2_SVEPMULL,
309 .cpuinfo = "svepmull",
310 .sigill_fn = svepmull_sigill,
311 },
312 {
313 .name = "SVE2 BITPERM",
314 .at_hwcap = AT_HWCAP2,
315 .hwcap_bit = HWCAP2_SVEBITPERM,
316 .cpuinfo = "svebitperm",
317 .sigill_fn = svebitperm_sigill,
318 },
319 {
320 .name = "SVE2 SHA3",
321 .at_hwcap = AT_HWCAP2,
322 .hwcap_bit = HWCAP2_SVESHA3,
323 .cpuinfo = "svesha3",
324 .sigill_fn = svesha3_sigill,
325 },
326 {
327 .name = "SVE2 SM4",
328 .at_hwcap = AT_HWCAP2,
329 .hwcap_bit = HWCAP2_SVESM4,
330 .cpuinfo = "svesm4",
331 .sigill_fn = svesm4_sigill,
332 },
333 {
334 .name = "SVE2 I8MM",
335 .at_hwcap = AT_HWCAP2,
336 .hwcap_bit = HWCAP2_SVEI8MM,
337 .cpuinfo = "svei8mm",
338 .sigill_fn = svei8mm_sigill,
339 },
340 {
341 .name = "SVE2 F32MM",
342 .at_hwcap = AT_HWCAP2,
343 .hwcap_bit = HWCAP2_SVEF32MM,
344 .cpuinfo = "svef32mm",
345 .sigill_fn = svef32mm_sigill,
346 },
347 {
348 .name = "SVE2 F64MM",
349 .at_hwcap = AT_HWCAP2,
350 .hwcap_bit = HWCAP2_SVEF64MM,
351 .cpuinfo = "svef64mm",
352 .sigill_fn = svef64mm_sigill,
353 },
354 {
355 .name = "SVE2 BF16",
356 .at_hwcap = AT_HWCAP2,
357 .hwcap_bit = HWCAP2_SVEBF16,
358 .cpuinfo = "svebf16",
359 .sigill_fn = svebf16_sigill,
360 },
361 {
362 .name = "SVE2 EBF16",
363 .at_hwcap = AT_HWCAP2,
364 .hwcap_bit = HWCAP2_SVE_EBF16,
365 .cpuinfo = "sveebf16",
366 },
367 };
368
369 static bool seen_sigill;
370
handle_sigill(int sig,siginfo_t * info,void * context)371 static void handle_sigill(int sig, siginfo_t *info, void *context)
372 {
373 ucontext_t *uc = context;
374
375 seen_sigill = true;
376
377 /* Skip over the offending instruction */
378 uc->uc_mcontext.pc += 4;
379 }
380
cpuinfo_present(const char * name)381 bool cpuinfo_present(const char *name)
382 {
383 FILE *f;
384 char buf[2048], name_space[30], name_newline[30];
385 char *s;
386
387 /*
388 * The feature should appear with a leading space and either a
389 * trailing space or a newline.
390 */
391 snprintf(name_space, sizeof(name_space), " %s ", name);
392 snprintf(name_newline, sizeof(name_newline), " %s\n", name);
393
394 f = fopen("/proc/cpuinfo", "r");
395 if (!f) {
396 ksft_print_msg("Failed to open /proc/cpuinfo\n");
397 return false;
398 }
399
400 while (fgets(buf, sizeof(buf), f)) {
401 /* Features: line? */
402 if (strncmp(buf, "Features\t:", strlen("Features\t:")) != 0)
403 continue;
404
405 /* All CPUs should be symmetric, don't read any more */
406 fclose(f);
407
408 s = strstr(buf, name_space);
409 if (s)
410 return true;
411 s = strstr(buf, name_newline);
412 if (s)
413 return true;
414
415 return false;
416 }
417
418 ksft_print_msg("Failed to find Features in /proc/cpuinfo\n");
419 fclose(f);
420 return false;
421 }
422
main(void)423 int main(void)
424 {
425 const struct hwcap_data *hwcap;
426 int i, ret;
427 bool have_cpuinfo, have_hwcap;
428 struct sigaction sa;
429
430 ksft_print_header();
431 ksft_set_plan(ARRAY_SIZE(hwcaps) * TESTS_PER_HWCAP);
432
433 memset(&sa, 0, sizeof(sa));
434 sa.sa_sigaction = handle_sigill;
435 sa.sa_flags = SA_RESTART | SA_SIGINFO;
436 sigemptyset(&sa.sa_mask);
437 ret = sigaction(SIGILL, &sa, NULL);
438 if (ret < 0)
439 ksft_exit_fail_msg("Failed to install SIGILL handler: %s (%d)\n",
440 strerror(errno), errno);
441
442 for (i = 0; i < ARRAY_SIZE(hwcaps); i++) {
443 hwcap = &hwcaps[i];
444
445 have_hwcap = getauxval(hwcap->at_hwcap) & hwcap->hwcap_bit;
446 have_cpuinfo = cpuinfo_present(hwcap->cpuinfo);
447
448 if (have_hwcap)
449 ksft_print_msg("%s present\n", hwcap->name);
450
451 ksft_test_result(have_hwcap == have_cpuinfo,
452 "cpuinfo_match_%s\n", hwcap->name);
453
454 if (hwcap->sigill_fn) {
455 seen_sigill = false;
456 hwcap->sigill_fn();
457
458 if (have_hwcap) {
459 /* Should be able to use the extension */
460 ksft_test_result(!seen_sigill, "sigill_%s\n",
461 hwcap->name);
462 } else if (hwcap->sigill_reliable) {
463 /* Guaranteed a SIGILL */
464 ksft_test_result(seen_sigill, "sigill_%s\n",
465 hwcap->name);
466 } else {
467 /* Missing SIGILL might be fine */
468 ksft_print_msg("SIGILL %sreported for %s\n",
469 seen_sigill ? "" : "not ",
470 hwcap->name);
471 ksft_test_result_skip("sigill_%s\n",
472 hwcap->name);
473 }
474 } else {
475 ksft_test_result_skip("sigill_%s\n",
476 hwcap->name);
477 }
478 }
479
480 ksft_print_cnts();
481
482 return 0;
483 }
484