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