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