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 3 23 24 /* 25 * Function expected to generate exception when the feature is not 26 * supported and return when it is supported. If the specific exception 27 * is generated then the handler must be able to skip over the 28 * instruction safely. 29 * 30 * Note that it is expected that for many architecture extensions 31 * there are no specific traps due to no architecture state being 32 * added so we may not fault if running on a kernel which doesn't know 33 * to add the hwcap. 34 */ 35 typedef void (*sig_fn)(void); 36 37 static void aes_sigill(void) 38 { 39 /* AESE V0.16B, V0.16B */ 40 asm volatile(".inst 0x4e284800" : : : ); 41 } 42 43 static void atomics_sigill(void) 44 { 45 /* STADD W0, [SP] */ 46 asm volatile(".inst 0xb82003ff" : : : ); 47 } 48 49 static void crc32_sigill(void) 50 { 51 /* CRC32W W0, W0, W1 */ 52 asm volatile(".inst 0x1ac14800" : : : ); 53 } 54 55 static void cssc_sigill(void) 56 { 57 /* CNT x0, x0 */ 58 asm volatile(".inst 0xdac01c00" : : : "x0"); 59 } 60 61 static void fp_sigill(void) 62 { 63 asm volatile("fmov s0, #1"); 64 } 65 66 static void ilrcpc_sigill(void) 67 { 68 /* LDAPUR W0, [SP, #8] */ 69 asm volatile(".inst 0x994083e0" : : : ); 70 } 71 72 static void jscvt_sigill(void) 73 { 74 /* FJCVTZS W0, D0 */ 75 asm volatile(".inst 0x1e7e0000" : : : ); 76 } 77 78 static void lrcpc_sigill(void) 79 { 80 /* LDAPR W0, [SP, #0] */ 81 asm volatile(".inst 0xb8bfc3e0" : : : ); 82 } 83 84 static void mops_sigill(void) 85 { 86 char dst[1], src[1]; 87 register char *dstp asm ("x0") = dst; 88 register char *srcp asm ("x1") = src; 89 register long size asm ("x2") = 1; 90 91 /* CPYP [x0]!, [x1]!, x2! */ 92 asm volatile(".inst 0x1d010440" 93 : "+r" (dstp), "+r" (srcp), "+r" (size) 94 : 95 : "cc", "memory"); 96 } 97 98 static void pmull_sigill(void) 99 { 100 /* PMULL V0.1Q, V0.1D, V0.1D */ 101 asm volatile(".inst 0x0ee0e000" : : : ); 102 } 103 104 static void rng_sigill(void) 105 { 106 asm volatile("mrs x0, S3_3_C2_C4_0" : : : "x0"); 107 } 108 109 static void sha1_sigill(void) 110 { 111 /* SHA1H S0, S0 */ 112 asm volatile(".inst 0x5e280800" : : : ); 113 } 114 115 static void sha2_sigill(void) 116 { 117 /* SHA256H Q0, Q0, V0.4S */ 118 asm volatile(".inst 0x5e004000" : : : ); 119 } 120 121 static void sha512_sigill(void) 122 { 123 /* SHA512H Q0, Q0, V0.2D */ 124 asm volatile(".inst 0xce608000" : : : ); 125 } 126 127 static void sme_sigill(void) 128 { 129 /* RDSVL x0, #0 */ 130 asm volatile(".inst 0x04bf5800" : : : "x0"); 131 } 132 133 static void sme2_sigill(void) 134 { 135 /* SMSTART ZA */ 136 asm volatile("msr S0_3_C4_C5_3, xzr" : : : ); 137 138 /* ZERO ZT0 */ 139 asm volatile(".inst 0xc0480001" : : : ); 140 141 /* SMSTOP */ 142 asm volatile("msr S0_3_C4_C6_3, xzr" : : : ); 143 } 144 145 static void sme2p1_sigill(void) 146 { 147 /* SMSTART SM */ 148 asm volatile("msr S0_3_C4_C3_3, xzr" : : : ); 149 150 /* BFCLAMP { Z0.H - Z1.H }, Z0.H, Z0.H */ 151 asm volatile(".inst 0xc120C000" : : : ); 152 153 /* SMSTOP */ 154 asm volatile("msr S0_3_C4_C6_3, xzr" : : : ); 155 } 156 157 static void smei16i32_sigill(void) 158 { 159 /* SMSTART */ 160 asm volatile("msr S0_3_C4_C7_3, xzr" : : : ); 161 162 /* SMOPA ZA0.S, P0/M, P0/M, Z0.B, Z0.B */ 163 asm volatile(".inst 0xa0800000" : : : ); 164 165 /* SMSTOP */ 166 asm volatile("msr S0_3_C4_C6_3, xzr" : : : ); 167 } 168 169 static void smebi32i32_sigill(void) 170 { 171 /* SMSTART */ 172 asm volatile("msr S0_3_C4_C7_3, xzr" : : : ); 173 174 /* BMOPA ZA0.S, P0/M, P0/M, Z0.B, Z0.B */ 175 asm volatile(".inst 0x80800008" : : : ); 176 177 /* SMSTOP */ 178 asm volatile("msr S0_3_C4_C6_3, xzr" : : : ); 179 } 180 181 static void smeb16b16_sigill(void) 182 { 183 /* SMSTART */ 184 asm volatile("msr S0_3_C4_C7_3, xzr" : : : ); 185 186 /* BFADD ZA.H[W0, 0], {Z0.H-Z1.H} */ 187 asm volatile(".inst 0xC1E41C00" : : : ); 188 189 /* SMSTOP */ 190 asm volatile("msr S0_3_C4_C6_3, xzr" : : : ); 191 } 192 193 static void smef16f16_sigill(void) 194 { 195 /* SMSTART */ 196 asm volatile("msr S0_3_C4_C7_3, xzr" : : : ); 197 198 /* FADD ZA.H[W0, 0], { Z0.H-Z1.H } */ 199 asm volatile(".inst 0xc1a41C00" : : : ); 200 201 /* SMSTOP */ 202 asm volatile("msr S0_3_C4_C6_3, xzr" : : : ); 203 } 204 205 static void sve_sigill(void) 206 { 207 /* RDVL x0, #0 */ 208 asm volatile(".inst 0x04bf5000" : : : "x0"); 209 } 210 211 static void sve2_sigill(void) 212 { 213 /* SQABS Z0.b, P0/M, Z0.B */ 214 asm volatile(".inst 0x4408A000" : : : "z0"); 215 } 216 217 static void sve2p1_sigill(void) 218 { 219 /* BFADD Z0.H, Z0.H, Z0.H */ 220 asm volatile(".inst 0x65000000" : : : "z0"); 221 } 222 223 static void sveaes_sigill(void) 224 { 225 /* AESD z0.b, z0.b, z0.b */ 226 asm volatile(".inst 0x4522e400" : : : "z0"); 227 } 228 229 static void svepmull_sigill(void) 230 { 231 /* PMULLB Z0.Q, Z0.D, Z0.D */ 232 asm volatile(".inst 0x45006800" : : : "z0"); 233 } 234 235 static void svebitperm_sigill(void) 236 { 237 /* BDEP Z0.B, Z0.B, Z0.B */ 238 asm volatile(".inst 0x4500b400" : : : "z0"); 239 } 240 241 static void svesha3_sigill(void) 242 { 243 /* EOR3 Z0.D, Z0.D, Z0.D, Z0.D */ 244 asm volatile(".inst 0x4203800" : : : "z0"); 245 } 246 247 static void svesm4_sigill(void) 248 { 249 /* SM4E Z0.S, Z0.S, Z0.S */ 250 asm volatile(".inst 0x4523e000" : : : "z0"); 251 } 252 253 static void svei8mm_sigill(void) 254 { 255 /* USDOT Z0.S, Z0.B, Z0.B[0] */ 256 asm volatile(".inst 0x44a01800" : : : "z0"); 257 } 258 259 static void svef32mm_sigill(void) 260 { 261 /* FMMLA Z0.S, Z0.S, Z0.S */ 262 asm volatile(".inst 0x64a0e400" : : : "z0"); 263 } 264 265 static void svef64mm_sigill(void) 266 { 267 /* FMMLA Z0.D, Z0.D, Z0.D */ 268 asm volatile(".inst 0x64e0e400" : : : "z0"); 269 } 270 271 static void svebf16_sigill(void) 272 { 273 /* BFCVT Z0.H, P0/M, Z0.S */ 274 asm volatile(".inst 0x658aa000" : : : "z0"); 275 } 276 277 static void uscat_sigbus(void) 278 { 279 /* unaligned atomic access */ 280 asm volatile("ADD x1, sp, #2" : : : ); 281 /* STADD W0, [X1] */ 282 asm volatile(".inst 0xb820003f" : : : ); 283 } 284 285 static const struct hwcap_data { 286 const char *name; 287 unsigned long at_hwcap; 288 unsigned long hwcap_bit; 289 const char *cpuinfo; 290 sig_fn sigill_fn; 291 bool sigill_reliable; 292 sig_fn sigbus_fn; 293 bool sigbus_reliable; 294 } hwcaps[] = { 295 { 296 .name = "AES", 297 .at_hwcap = AT_HWCAP, 298 .hwcap_bit = HWCAP_AES, 299 .cpuinfo = "aes", 300 .sigill_fn = aes_sigill, 301 }, 302 { 303 .name = "CRC32", 304 .at_hwcap = AT_HWCAP, 305 .hwcap_bit = HWCAP_CRC32, 306 .cpuinfo = "crc32", 307 .sigill_fn = crc32_sigill, 308 }, 309 { 310 .name = "CSSC", 311 .at_hwcap = AT_HWCAP2, 312 .hwcap_bit = HWCAP2_CSSC, 313 .cpuinfo = "cssc", 314 .sigill_fn = cssc_sigill, 315 }, 316 { 317 .name = "FP", 318 .at_hwcap = AT_HWCAP, 319 .hwcap_bit = HWCAP_FP, 320 .cpuinfo = "fp", 321 .sigill_fn = fp_sigill, 322 }, 323 { 324 .name = "JSCVT", 325 .at_hwcap = AT_HWCAP, 326 .hwcap_bit = HWCAP_JSCVT, 327 .cpuinfo = "jscvt", 328 .sigill_fn = jscvt_sigill, 329 }, 330 { 331 .name = "LRCPC", 332 .at_hwcap = AT_HWCAP, 333 .hwcap_bit = HWCAP_LRCPC, 334 .cpuinfo = "lrcpc", 335 .sigill_fn = lrcpc_sigill, 336 }, 337 { 338 .name = "LRCPC2", 339 .at_hwcap = AT_HWCAP, 340 .hwcap_bit = HWCAP_ILRCPC, 341 .cpuinfo = "ilrcpc", 342 .sigill_fn = ilrcpc_sigill, 343 }, 344 { 345 .name = "LSE", 346 .at_hwcap = AT_HWCAP, 347 .hwcap_bit = HWCAP_ATOMICS, 348 .cpuinfo = "atomics", 349 .sigill_fn = atomics_sigill, 350 }, 351 { 352 .name = "LSE2", 353 .at_hwcap = AT_HWCAP, 354 .hwcap_bit = HWCAP_USCAT, 355 .cpuinfo = "uscat", 356 .sigill_fn = atomics_sigill, 357 .sigbus_fn = uscat_sigbus, 358 .sigbus_reliable = true, 359 }, 360 { 361 .name = "MOPS", 362 .at_hwcap = AT_HWCAP2, 363 .hwcap_bit = HWCAP2_MOPS, 364 .cpuinfo = "mops", 365 .sigill_fn = mops_sigill, 366 .sigill_reliable = true, 367 }, 368 { 369 .name = "PMULL", 370 .at_hwcap = AT_HWCAP, 371 .hwcap_bit = HWCAP_PMULL, 372 .cpuinfo = "pmull", 373 .sigill_fn = pmull_sigill, 374 }, 375 { 376 .name = "RNG", 377 .at_hwcap = AT_HWCAP2, 378 .hwcap_bit = HWCAP2_RNG, 379 .cpuinfo = "rng", 380 .sigill_fn = rng_sigill, 381 }, 382 { 383 .name = "RPRFM", 384 .at_hwcap = AT_HWCAP2, 385 .hwcap_bit = HWCAP2_RPRFM, 386 .cpuinfo = "rprfm", 387 }, 388 { 389 .name = "SHA1", 390 .at_hwcap = AT_HWCAP, 391 .hwcap_bit = HWCAP_SHA1, 392 .cpuinfo = "sha1", 393 .sigill_fn = sha1_sigill, 394 }, 395 { 396 .name = "SHA2", 397 .at_hwcap = AT_HWCAP, 398 .hwcap_bit = HWCAP_SHA2, 399 .cpuinfo = "sha2", 400 .sigill_fn = sha2_sigill, 401 }, 402 { 403 .name = "SHA512", 404 .at_hwcap = AT_HWCAP, 405 .hwcap_bit = HWCAP_SHA512, 406 .cpuinfo = "sha512", 407 .sigill_fn = sha512_sigill, 408 }, 409 { 410 .name = "SME", 411 .at_hwcap = AT_HWCAP2, 412 .hwcap_bit = HWCAP2_SME, 413 .cpuinfo = "sme", 414 .sigill_fn = sme_sigill, 415 .sigill_reliable = true, 416 }, 417 { 418 .name = "SME2", 419 .at_hwcap = AT_HWCAP2, 420 .hwcap_bit = HWCAP2_SME2, 421 .cpuinfo = "sme2", 422 .sigill_fn = sme2_sigill, 423 .sigill_reliable = true, 424 }, 425 { 426 .name = "SME 2.1", 427 .at_hwcap = AT_HWCAP2, 428 .hwcap_bit = HWCAP2_SME2P1, 429 .cpuinfo = "sme2p1", 430 .sigill_fn = sme2p1_sigill, 431 }, 432 { 433 .name = "SME I16I32", 434 .at_hwcap = AT_HWCAP2, 435 .hwcap_bit = HWCAP2_SME_I16I32, 436 .cpuinfo = "smei16i32", 437 .sigill_fn = smei16i32_sigill, 438 }, 439 { 440 .name = "SME BI32I32", 441 .at_hwcap = AT_HWCAP2, 442 .hwcap_bit = HWCAP2_SME_BI32I32, 443 .cpuinfo = "smebi32i32", 444 .sigill_fn = smebi32i32_sigill, 445 }, 446 { 447 .name = "SME B16B16", 448 .at_hwcap = AT_HWCAP2, 449 .hwcap_bit = HWCAP2_SME_B16B16, 450 .cpuinfo = "smeb16b16", 451 .sigill_fn = smeb16b16_sigill, 452 }, 453 { 454 .name = "SME F16F16", 455 .at_hwcap = AT_HWCAP2, 456 .hwcap_bit = HWCAP2_SME_F16F16, 457 .cpuinfo = "smef16f16", 458 .sigill_fn = smef16f16_sigill, 459 }, 460 { 461 .name = "SVE", 462 .at_hwcap = AT_HWCAP, 463 .hwcap_bit = HWCAP_SVE, 464 .cpuinfo = "sve", 465 .sigill_fn = sve_sigill, 466 .sigill_reliable = true, 467 }, 468 { 469 .name = "SVE 2", 470 .at_hwcap = AT_HWCAP2, 471 .hwcap_bit = HWCAP2_SVE2, 472 .cpuinfo = "sve2", 473 .sigill_fn = sve2_sigill, 474 }, 475 { 476 .name = "SVE 2.1", 477 .at_hwcap = AT_HWCAP2, 478 .hwcap_bit = HWCAP2_SVE2P1, 479 .cpuinfo = "sve2p1", 480 .sigill_fn = sve2p1_sigill, 481 }, 482 { 483 .name = "SVE AES", 484 .at_hwcap = AT_HWCAP2, 485 .hwcap_bit = HWCAP2_SVEAES, 486 .cpuinfo = "sveaes", 487 .sigill_fn = sveaes_sigill, 488 }, 489 { 490 .name = "SVE2 PMULL", 491 .at_hwcap = AT_HWCAP2, 492 .hwcap_bit = HWCAP2_SVEPMULL, 493 .cpuinfo = "svepmull", 494 .sigill_fn = svepmull_sigill, 495 }, 496 { 497 .name = "SVE2 BITPERM", 498 .at_hwcap = AT_HWCAP2, 499 .hwcap_bit = HWCAP2_SVEBITPERM, 500 .cpuinfo = "svebitperm", 501 .sigill_fn = svebitperm_sigill, 502 }, 503 { 504 .name = "SVE2 SHA3", 505 .at_hwcap = AT_HWCAP2, 506 .hwcap_bit = HWCAP2_SVESHA3, 507 .cpuinfo = "svesha3", 508 .sigill_fn = svesha3_sigill, 509 }, 510 { 511 .name = "SVE2 SM4", 512 .at_hwcap = AT_HWCAP2, 513 .hwcap_bit = HWCAP2_SVESM4, 514 .cpuinfo = "svesm4", 515 .sigill_fn = svesm4_sigill, 516 }, 517 { 518 .name = "SVE2 I8MM", 519 .at_hwcap = AT_HWCAP2, 520 .hwcap_bit = HWCAP2_SVEI8MM, 521 .cpuinfo = "svei8mm", 522 .sigill_fn = svei8mm_sigill, 523 }, 524 { 525 .name = "SVE2 F32MM", 526 .at_hwcap = AT_HWCAP2, 527 .hwcap_bit = HWCAP2_SVEF32MM, 528 .cpuinfo = "svef32mm", 529 .sigill_fn = svef32mm_sigill, 530 }, 531 { 532 .name = "SVE2 F64MM", 533 .at_hwcap = AT_HWCAP2, 534 .hwcap_bit = HWCAP2_SVEF64MM, 535 .cpuinfo = "svef64mm", 536 .sigill_fn = svef64mm_sigill, 537 }, 538 { 539 .name = "SVE2 BF16", 540 .at_hwcap = AT_HWCAP2, 541 .hwcap_bit = HWCAP2_SVEBF16, 542 .cpuinfo = "svebf16", 543 .sigill_fn = svebf16_sigill, 544 }, 545 { 546 .name = "SVE2 EBF16", 547 .at_hwcap = AT_HWCAP2, 548 .hwcap_bit = HWCAP2_SVE_EBF16, 549 .cpuinfo = "sveebf16", 550 }, 551 }; 552 553 typedef void (*sighandler_fn)(int, siginfo_t *, void *); 554 555 #define DEF_SIGHANDLER_FUNC(SIG, NUM) \ 556 static bool seen_##SIG; \ 557 static void handle_##SIG(int sig, siginfo_t *info, void *context) \ 558 { \ 559 ucontext_t *uc = context; \ 560 \ 561 seen_##SIG = true; \ 562 /* Skip over the offending instruction */ \ 563 uc->uc_mcontext.pc += 4; \ 564 } 565 566 DEF_SIGHANDLER_FUNC(sigill, SIGILL); 567 DEF_SIGHANDLER_FUNC(sigbus, SIGBUS); 568 569 bool cpuinfo_present(const char *name) 570 { 571 FILE *f; 572 char buf[2048], name_space[30], name_newline[30]; 573 char *s; 574 575 /* 576 * The feature should appear with a leading space and either a 577 * trailing space or a newline. 578 */ 579 snprintf(name_space, sizeof(name_space), " %s ", name); 580 snprintf(name_newline, sizeof(name_newline), " %s\n", name); 581 582 f = fopen("/proc/cpuinfo", "r"); 583 if (!f) { 584 ksft_print_msg("Failed to open /proc/cpuinfo\n"); 585 return false; 586 } 587 588 while (fgets(buf, sizeof(buf), f)) { 589 /* Features: line? */ 590 if (strncmp(buf, "Features\t:", strlen("Features\t:")) != 0) 591 continue; 592 593 /* All CPUs should be symmetric, don't read any more */ 594 fclose(f); 595 596 s = strstr(buf, name_space); 597 if (s) 598 return true; 599 s = strstr(buf, name_newline); 600 if (s) 601 return true; 602 603 return false; 604 } 605 606 ksft_print_msg("Failed to find Features in /proc/cpuinfo\n"); 607 fclose(f); 608 return false; 609 } 610 611 static int install_sigaction(int signum, sighandler_fn handler) 612 { 613 int ret; 614 struct sigaction sa; 615 616 memset(&sa, 0, sizeof(sa)); 617 sa.sa_sigaction = handler; 618 sa.sa_flags = SA_RESTART | SA_SIGINFO; 619 sigemptyset(&sa.sa_mask); 620 ret = sigaction(signum, &sa, NULL); 621 if (ret < 0) 622 ksft_exit_fail_msg("Failed to install SIGNAL handler: %s (%d)\n", 623 strerror(errno), errno); 624 625 return ret; 626 } 627 628 static void uninstall_sigaction(int signum) 629 { 630 if (sigaction(signum, NULL, NULL) < 0) 631 ksft_exit_fail_msg("Failed to uninstall SIGNAL handler: %s (%d)\n", 632 strerror(errno), errno); 633 } 634 635 #define DEF_INST_RAISE_SIG(SIG, NUM) \ 636 static bool inst_raise_##SIG(const struct hwcap_data *hwcap, \ 637 bool have_hwcap) \ 638 { \ 639 if (!hwcap->SIG##_fn) { \ 640 ksft_test_result_skip(#SIG"_%s\n", hwcap->name); \ 641 /* assume that it would raise exception in default */ \ 642 return true; \ 643 } \ 644 \ 645 install_sigaction(NUM, handle_##SIG); \ 646 \ 647 seen_##SIG = false; \ 648 hwcap->SIG##_fn(); \ 649 \ 650 if (have_hwcap) { \ 651 /* Should be able to use the extension */ \ 652 ksft_test_result(!seen_##SIG, \ 653 #SIG"_%s\n", hwcap->name); \ 654 } else if (hwcap->SIG##_reliable) { \ 655 /* Guaranteed a SIGNAL */ \ 656 ksft_test_result(seen_##SIG, \ 657 #SIG"_%s\n", hwcap->name); \ 658 } else { \ 659 /* Missing SIGNAL might be fine */ \ 660 ksft_print_msg(#SIG"_%sreported for %s\n", \ 661 seen_##SIG ? "" : "not ", \ 662 hwcap->name); \ 663 ksft_test_result_skip(#SIG"_%s\n", \ 664 hwcap->name); \ 665 } \ 666 \ 667 uninstall_sigaction(NUM); \ 668 return seen_##SIG; \ 669 } 670 671 DEF_INST_RAISE_SIG(sigill, SIGILL); 672 DEF_INST_RAISE_SIG(sigbus, SIGBUS); 673 674 int main(void) 675 { 676 int i; 677 const struct hwcap_data *hwcap; 678 bool have_cpuinfo, have_hwcap, raise_sigill; 679 680 ksft_print_header(); 681 ksft_set_plan(ARRAY_SIZE(hwcaps) * TESTS_PER_HWCAP); 682 683 for (i = 0; i < ARRAY_SIZE(hwcaps); i++) { 684 hwcap = &hwcaps[i]; 685 686 have_hwcap = getauxval(hwcap->at_hwcap) & hwcap->hwcap_bit; 687 have_cpuinfo = cpuinfo_present(hwcap->cpuinfo); 688 689 if (have_hwcap) 690 ksft_print_msg("%s present\n", hwcap->name); 691 692 ksft_test_result(have_hwcap == have_cpuinfo, 693 "cpuinfo_match_%s\n", hwcap->name); 694 695 /* 696 * Testing for SIGBUS only makes sense after make sure 697 * that the instruction does not cause a SIGILL signal. 698 */ 699 raise_sigill = inst_raise_sigill(hwcap, have_hwcap); 700 if (!raise_sigill) 701 inst_raise_sigbus(hwcap, have_hwcap); 702 else 703 ksft_test_result_skip("sigbus_%s\n", hwcap->name); 704 } 705 706 ksft_print_cnts(); 707 708 return 0; 709 } 710