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