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 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 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 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 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 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 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 125 static void sve_sigill(void) 126 { 127 /* RDVL x0, #0 */ 128 asm volatile(".inst 0x04bf5000" : : : "x0"); 129 } 130 131 static void sve2_sigill(void) 132 { 133 /* SQABS Z0.b, P0/M, Z0.B */ 134 asm volatile(".inst 0x4408A000" : : : "z0"); 135 } 136 137 static void sve2p1_sigill(void) 138 { 139 /* BFADD Z0.H, Z0.H, Z0.H */ 140 asm volatile(".inst 0x65000000" : : : "z0"); 141 } 142 143 static void sveaes_sigill(void) 144 { 145 /* AESD z0.b, z0.b, z0.b */ 146 asm volatile(".inst 0x4522e400" : : : "z0"); 147 } 148 149 static void svepmull_sigill(void) 150 { 151 /* PMULLB Z0.Q, Z0.D, Z0.D */ 152 asm volatile(".inst 0x45006800" : : : "z0"); 153 } 154 155 static void svebitperm_sigill(void) 156 { 157 /* BDEP Z0.B, Z0.B, Z0.B */ 158 asm volatile(".inst 0x4500b400" : : : "z0"); 159 } 160 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 167 static void svesm4_sigill(void) 168 { 169 /* SM4E Z0.S, Z0.S, Z0.S */ 170 asm volatile(".inst 0x4523e000" : : : "z0"); 171 } 172 173 static void svei8mm_sigill(void) 174 { 175 /* USDOT Z0.S, Z0.B, Z0.B[0] */ 176 asm volatile(".inst 0x44a01800" : : : "z0"); 177 } 178 179 static void svef32mm_sigill(void) 180 { 181 /* FMMLA Z0.S, Z0.S, Z0.S */ 182 asm volatile(".inst 0x64a0e400" : : : "z0"); 183 } 184 185 static void svef64mm_sigill(void) 186 { 187 /* FMMLA Z0.D, Z0.D, Z0.D */ 188 asm volatile(".inst 0x64e0e400" : : : "z0"); 189 } 190 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 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 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 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