1 // SPDX-License-Identifier: GPL-2.0 2 3 #define _GNU_SOURCE 4 #include <err.h> 5 #include <errno.h> 6 #include <pthread.h> 7 #include <setjmp.h> 8 #include <stdio.h> 9 #include <string.h> 10 #include <stdbool.h> 11 #include <unistd.h> 12 #include <x86intrin.h> 13 14 #include <sys/auxv.h> 15 #include <sys/mman.h> 16 #include <sys/shm.h> 17 #include <sys/ptrace.h> 18 #include <sys/syscall.h> 19 #include <sys/wait.h> 20 #include <sys/uio.h> 21 22 #include "../kselftest.h" /* For __cpuid_count() */ 23 24 #ifndef __x86_64__ 25 # error This test is 64-bit only 26 #endif 27 28 #define XSAVE_HDR_OFFSET 512 29 #define XSAVE_HDR_SIZE 64 30 31 struct xsave_buffer { 32 union { 33 struct { 34 char legacy[XSAVE_HDR_OFFSET]; 35 char header[XSAVE_HDR_SIZE]; 36 char extended[0]; 37 }; 38 char bytes[0]; 39 }; 40 }; 41 42 static inline uint64_t xgetbv(uint32_t index) 43 { 44 uint32_t eax, edx; 45 46 asm volatile("xgetbv;" 47 : "=a" (eax), "=d" (edx) 48 : "c" (index)); 49 return eax + ((uint64_t)edx << 32); 50 } 51 52 static inline void xsave(struct xsave_buffer *xbuf, uint64_t rfbm) 53 { 54 uint32_t rfbm_lo = rfbm; 55 uint32_t rfbm_hi = rfbm >> 32; 56 57 asm volatile("xsave (%%rdi)" 58 : : "D" (xbuf), "a" (rfbm_lo), "d" (rfbm_hi) 59 : "memory"); 60 } 61 62 static inline void xrstor(struct xsave_buffer *xbuf, uint64_t rfbm) 63 { 64 uint32_t rfbm_lo = rfbm; 65 uint32_t rfbm_hi = rfbm >> 32; 66 67 asm volatile("xrstor (%%rdi)" 68 : : "D" (xbuf), "a" (rfbm_lo), "d" (rfbm_hi)); 69 } 70 71 /* err() exits and will not return */ 72 #define fatal_error(msg, ...) err(1, "[FAIL]\t" msg, ##__VA_ARGS__) 73 74 static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), 75 int flags) 76 { 77 struct sigaction sa; 78 79 memset(&sa, 0, sizeof(sa)); 80 sa.sa_sigaction = handler; 81 sa.sa_flags = SA_SIGINFO | flags; 82 sigemptyset(&sa.sa_mask); 83 if (sigaction(sig, &sa, 0)) 84 fatal_error("sigaction"); 85 } 86 87 static void clearhandler(int sig) 88 { 89 struct sigaction sa; 90 91 memset(&sa, 0, sizeof(sa)); 92 sa.sa_handler = SIG_DFL; 93 sigemptyset(&sa.sa_mask); 94 if (sigaction(sig, &sa, 0)) 95 fatal_error("sigaction"); 96 } 97 98 #define XFEATURE_XTILECFG 17 99 #define XFEATURE_XTILEDATA 18 100 #define XFEATURE_MASK_XTILECFG (1 << XFEATURE_XTILECFG) 101 #define XFEATURE_MASK_XTILEDATA (1 << XFEATURE_XTILEDATA) 102 #define XFEATURE_MASK_XTILE (XFEATURE_MASK_XTILECFG | XFEATURE_MASK_XTILEDATA) 103 104 #define CPUID_LEAF1_ECX_XSAVE_MASK (1 << 26) 105 #define CPUID_LEAF1_ECX_OSXSAVE_MASK (1 << 27) 106 107 static uint32_t xbuf_size; 108 109 static struct { 110 uint32_t xbuf_offset; 111 uint32_t size; 112 } xtiledata; 113 114 #define CPUID_LEAF_XSTATE 0xd 115 #define CPUID_SUBLEAF_XSTATE_USER 0x0 116 #define TILE_CPUID 0x1d 117 #define TILE_PALETTE_ID 0x1 118 119 static void check_cpuid_xtiledata(void) 120 { 121 uint32_t eax, ebx, ecx, edx; 122 123 __cpuid_count(CPUID_LEAF_XSTATE, CPUID_SUBLEAF_XSTATE_USER, 124 eax, ebx, ecx, edx); 125 126 /* 127 * EBX enumerates the size (in bytes) required by the XSAVE 128 * instruction for an XSAVE area containing all the user state 129 * components corresponding to bits currently set in XCR0. 130 * 131 * Stash that off so it can be used to allocate buffers later. 132 */ 133 xbuf_size = ebx; 134 135 __cpuid_count(CPUID_LEAF_XSTATE, XFEATURE_XTILEDATA, 136 eax, ebx, ecx, edx); 137 /* 138 * eax: XTILEDATA state component size 139 * ebx: XTILEDATA state component offset in user buffer 140 */ 141 if (!eax || !ebx) 142 fatal_error("xstate cpuid: invalid tile data size/offset: %d/%d", 143 eax, ebx); 144 145 xtiledata.size = eax; 146 xtiledata.xbuf_offset = ebx; 147 } 148 149 /* The helpers for managing XSAVE buffer and tile states: */ 150 151 struct xsave_buffer *alloc_xbuf(void) 152 { 153 struct xsave_buffer *xbuf; 154 155 /* XSAVE buffer should be 64B-aligned. */ 156 xbuf = aligned_alloc(64, xbuf_size); 157 if (!xbuf) 158 fatal_error("aligned_alloc()"); 159 return xbuf; 160 } 161 162 static inline void clear_xstate_header(struct xsave_buffer *buffer) 163 { 164 memset(&buffer->header, 0, sizeof(buffer->header)); 165 } 166 167 static inline uint64_t get_xstatebv(struct xsave_buffer *buffer) 168 { 169 /* XSTATE_BV is at the beginning of the header: */ 170 return *(uint64_t *)&buffer->header; 171 } 172 173 static inline void set_xstatebv(struct xsave_buffer *buffer, uint64_t bv) 174 { 175 /* XSTATE_BV is at the beginning of the header: */ 176 *(uint64_t *)(&buffer->header) = bv; 177 } 178 179 static void set_rand_tiledata(struct xsave_buffer *xbuf) 180 { 181 int *ptr = (int *)&xbuf->bytes[xtiledata.xbuf_offset]; 182 int data; 183 int i; 184 185 /* 186 * Ensure that 'data' is never 0. This ensures that 187 * the registers are never in their initial configuration 188 * and thus never tracked as being in the init state. 189 */ 190 data = rand() | 1; 191 192 for (i = 0; i < xtiledata.size / sizeof(int); i++, ptr++) 193 *ptr = data; 194 } 195 196 struct xsave_buffer *stashed_xsave; 197 198 static void init_stashed_xsave(void) 199 { 200 stashed_xsave = alloc_xbuf(); 201 if (!stashed_xsave) 202 fatal_error("failed to allocate stashed_xsave\n"); 203 clear_xstate_header(stashed_xsave); 204 } 205 206 static void free_stashed_xsave(void) 207 { 208 free(stashed_xsave); 209 } 210 211 /* See 'struct _fpx_sw_bytes' at sigcontext.h */ 212 #define SW_BYTES_OFFSET 464 213 /* N.B. The struct's field name varies so read from the offset. */ 214 #define SW_BYTES_BV_OFFSET (SW_BYTES_OFFSET + 8) 215 216 static inline struct _fpx_sw_bytes *get_fpx_sw_bytes(void *buffer) 217 { 218 return (struct _fpx_sw_bytes *)(buffer + SW_BYTES_OFFSET); 219 } 220 221 static inline uint64_t get_fpx_sw_bytes_features(void *buffer) 222 { 223 return *(uint64_t *)(buffer + SW_BYTES_BV_OFFSET); 224 } 225 226 /* Work around printf() being unsafe in signals: */ 227 #define SIGNAL_BUF_LEN 1000 228 char signal_message_buffer[SIGNAL_BUF_LEN]; 229 void sig_print(char *msg) 230 { 231 int left = SIGNAL_BUF_LEN - strlen(signal_message_buffer) - 1; 232 233 strncat(signal_message_buffer, msg, left); 234 } 235 236 static volatile bool noperm_signaled; 237 static int noperm_errs; 238 /* 239 * Signal handler for when AMX is used but 240 * permission has not been obtained. 241 */ 242 static void handle_noperm(int sig, siginfo_t *si, void *ctx_void) 243 { 244 ucontext_t *ctx = (ucontext_t *)ctx_void; 245 void *xbuf = ctx->uc_mcontext.fpregs; 246 struct _fpx_sw_bytes *sw_bytes; 247 uint64_t features; 248 249 /* Reset the signal message buffer: */ 250 signal_message_buffer[0] = '\0'; 251 sig_print("\tAt SIGILL handler,\n"); 252 253 if (si->si_code != ILL_ILLOPC) { 254 noperm_errs++; 255 sig_print("[FAIL]\tInvalid signal code.\n"); 256 } else { 257 sig_print("[OK]\tValid signal code (ILL_ILLOPC).\n"); 258 } 259 260 sw_bytes = get_fpx_sw_bytes(xbuf); 261 /* 262 * Without permission, the signal XSAVE buffer should not 263 * have room for AMX register state (aka. xtiledata). 264 * Check that the size does not overlap with where xtiledata 265 * will reside. 266 * 267 * This also implies that no state components *PAST* 268 * XTILEDATA (features >=19) can be present in the buffer. 269 */ 270 if (sw_bytes->xstate_size <= xtiledata.xbuf_offset) { 271 sig_print("[OK]\tValid xstate size\n"); 272 } else { 273 noperm_errs++; 274 sig_print("[FAIL]\tInvalid xstate size\n"); 275 } 276 277 features = get_fpx_sw_bytes_features(xbuf); 278 /* 279 * Without permission, the XTILEDATA feature 280 * bit should not be set. 281 */ 282 if ((features & XFEATURE_MASK_XTILEDATA) == 0) { 283 sig_print("[OK]\tValid xstate mask\n"); 284 } else { 285 noperm_errs++; 286 sig_print("[FAIL]\tInvalid xstate mask\n"); 287 } 288 289 noperm_signaled = true; 290 ctx->uc_mcontext.gregs[REG_RIP] += 3; /* Skip the faulting XRSTOR */ 291 } 292 293 /* Return true if XRSTOR is successful; otherwise, false. */ 294 static inline bool xrstor_safe(struct xsave_buffer *xbuf, uint64_t mask) 295 { 296 noperm_signaled = false; 297 xrstor(xbuf, mask); 298 299 /* Print any messages produced by the signal code: */ 300 printf("%s", signal_message_buffer); 301 /* 302 * Reset the buffer to make sure any future printing 303 * only outputs new messages: 304 */ 305 signal_message_buffer[0] = '\0'; 306 307 if (noperm_errs) 308 fatal_error("saw %d errors in noperm signal handler\n", noperm_errs); 309 310 return !noperm_signaled; 311 } 312 313 /* 314 * Use XRSTOR to populate the XTILEDATA registers with 315 * random data. 316 * 317 * Return true if successful; otherwise, false. 318 */ 319 static inline bool load_rand_tiledata(struct xsave_buffer *xbuf) 320 { 321 clear_xstate_header(xbuf); 322 set_xstatebv(xbuf, XFEATURE_MASK_XTILEDATA); 323 set_rand_tiledata(xbuf); 324 return xrstor_safe(xbuf, XFEATURE_MASK_XTILEDATA); 325 } 326 327 /* Return XTILEDATA to its initial configuration. */ 328 static inline void init_xtiledata(void) 329 { 330 clear_xstate_header(stashed_xsave); 331 xrstor_safe(stashed_xsave, XFEATURE_MASK_XTILEDATA); 332 } 333 334 enum expected_result { FAIL_EXPECTED, SUCCESS_EXPECTED }; 335 336 /* arch_prctl() and sigaltstack() test */ 337 338 #define ARCH_GET_XCOMP_SUPP 0x1021 339 #define ARCH_GET_XCOMP_PERM 0x1022 340 #define ARCH_REQ_XCOMP_PERM 0x1023 341 342 static void req_xtiledata_perm(void) 343 { 344 syscall(SYS_arch_prctl, ARCH_REQ_XCOMP_PERM, XFEATURE_XTILEDATA); 345 } 346 347 static void validate_req_xcomp_perm(enum expected_result exp) 348 { 349 unsigned long bitmask, expected_bitmask; 350 long rc; 351 352 rc = syscall(SYS_arch_prctl, ARCH_GET_XCOMP_PERM, &bitmask); 353 if (rc) { 354 fatal_error("prctl(ARCH_GET_XCOMP_PERM) error: %ld", rc); 355 } else if (!(bitmask & XFEATURE_MASK_XTILECFG)) { 356 fatal_error("ARCH_GET_XCOMP_PERM returns XFEATURE_XTILECFG off."); 357 } 358 359 rc = syscall(SYS_arch_prctl, ARCH_REQ_XCOMP_PERM, XFEATURE_XTILEDATA); 360 if (exp == FAIL_EXPECTED) { 361 if (rc) { 362 printf("[OK]\tARCH_REQ_XCOMP_PERM saw expected failure..\n"); 363 return; 364 } 365 366 fatal_error("ARCH_REQ_XCOMP_PERM saw unexpected success.\n"); 367 } else if (rc) { 368 fatal_error("ARCH_REQ_XCOMP_PERM saw unexpected failure.\n"); 369 } 370 371 expected_bitmask = bitmask | XFEATURE_MASK_XTILEDATA; 372 373 rc = syscall(SYS_arch_prctl, ARCH_GET_XCOMP_PERM, &bitmask); 374 if (rc) { 375 fatal_error("prctl(ARCH_GET_XCOMP_PERM) error: %ld", rc); 376 } else if (bitmask != expected_bitmask) { 377 fatal_error("ARCH_REQ_XCOMP_PERM set a wrong bitmask: %lx, expected: %lx.\n", 378 bitmask, expected_bitmask); 379 } else { 380 printf("\tARCH_REQ_XCOMP_PERM is successful.\n"); 381 } 382 } 383 384 static void validate_xcomp_perm(enum expected_result exp) 385 { 386 bool load_success = load_rand_tiledata(stashed_xsave); 387 388 if (exp == FAIL_EXPECTED) { 389 if (load_success) { 390 noperm_errs++; 391 printf("[FAIL]\tLoad tiledata succeeded.\n"); 392 } else { 393 printf("[OK]\tLoad tiledata failed.\n"); 394 } 395 } else if (exp == SUCCESS_EXPECTED) { 396 if (load_success) { 397 printf("[OK]\tLoad tiledata succeeded.\n"); 398 } else { 399 noperm_errs++; 400 printf("[FAIL]\tLoad tiledata failed.\n"); 401 } 402 } 403 } 404 405 #ifndef AT_MINSIGSTKSZ 406 # define AT_MINSIGSTKSZ 51 407 #endif 408 409 static void *alloc_altstack(unsigned int size) 410 { 411 void *altstack; 412 413 altstack = mmap(NULL, size, PROT_READ | PROT_WRITE, 414 MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); 415 416 if (altstack == MAP_FAILED) 417 fatal_error("mmap() for altstack"); 418 419 return altstack; 420 } 421 422 static void setup_altstack(void *addr, unsigned long size, enum expected_result exp) 423 { 424 stack_t ss; 425 int rc; 426 427 memset(&ss, 0, sizeof(ss)); 428 ss.ss_size = size; 429 ss.ss_sp = addr; 430 431 rc = sigaltstack(&ss, NULL); 432 433 if (exp == FAIL_EXPECTED) { 434 if (rc) { 435 printf("[OK]\tsigaltstack() failed.\n"); 436 } else { 437 fatal_error("sigaltstack() succeeded unexpectedly.\n"); 438 } 439 } else if (rc) { 440 fatal_error("sigaltstack()"); 441 } 442 } 443 444 static void test_dynamic_sigaltstack(void) 445 { 446 unsigned int small_size, enough_size; 447 unsigned long minsigstksz; 448 void *altstack; 449 450 minsigstksz = getauxval(AT_MINSIGSTKSZ); 451 printf("\tAT_MINSIGSTKSZ = %lu\n", minsigstksz); 452 /* 453 * getauxval() itself can return 0 for failure or 454 * success. But, in this case, AT_MINSIGSTKSZ 455 * will always return a >=0 value if implemented. 456 * Just check for 0. 457 */ 458 if (minsigstksz == 0) { 459 printf("no support for AT_MINSIGSTKSZ, skipping sigaltstack tests\n"); 460 return; 461 } 462 463 enough_size = minsigstksz * 2; 464 465 altstack = alloc_altstack(enough_size); 466 printf("\tAllocate memory for altstack (%u bytes).\n", enough_size); 467 468 /* 469 * Try setup_altstack() with a size which can not fit 470 * XTILEDATA. ARCH_REQ_XCOMP_PERM should fail. 471 */ 472 small_size = minsigstksz - xtiledata.size; 473 printf("\tAfter sigaltstack() with small size (%u bytes).\n", small_size); 474 setup_altstack(altstack, small_size, SUCCESS_EXPECTED); 475 validate_req_xcomp_perm(FAIL_EXPECTED); 476 477 /* 478 * Try setup_altstack() with a size derived from 479 * AT_MINSIGSTKSZ. It should be more than large enough 480 * and thus ARCH_REQ_XCOMP_PERM should succeed. 481 */ 482 printf("\tAfter sigaltstack() with enough size (%u bytes).\n", enough_size); 483 setup_altstack(altstack, enough_size, SUCCESS_EXPECTED); 484 validate_req_xcomp_perm(SUCCESS_EXPECTED); 485 486 /* 487 * Try to coerce setup_altstack() to again accept a 488 * too-small altstack. This ensures that big-enough 489 * sigaltstacks can not shrink to a too-small value 490 * once XTILEDATA permission is established. 491 */ 492 printf("\tThen, sigaltstack() with small size (%u bytes).\n", small_size); 493 setup_altstack(altstack, small_size, FAIL_EXPECTED); 494 } 495 496 static void test_dynamic_state(void) 497 { 498 pid_t parent, child, grandchild; 499 500 parent = fork(); 501 if (parent < 0) { 502 /* fork() failed */ 503 fatal_error("fork"); 504 } else if (parent > 0) { 505 int status; 506 /* fork() succeeded. Now in the parent. */ 507 508 wait(&status); 509 if (!WIFEXITED(status) || WEXITSTATUS(status)) 510 fatal_error("arch_prctl test parent exit"); 511 return; 512 } 513 /* fork() succeeded. Now in the child . */ 514 515 printf("[RUN]\tCheck ARCH_REQ_XCOMP_PERM around process fork() and sigaltack() test.\n"); 516 517 printf("\tFork a child.\n"); 518 child = fork(); 519 if (child < 0) { 520 fatal_error("fork"); 521 } else if (child > 0) { 522 int status; 523 524 wait(&status); 525 if (!WIFEXITED(status) || WEXITSTATUS(status)) 526 fatal_error("arch_prctl test child exit"); 527 _exit(0); 528 } 529 530 /* 531 * The permission request should fail without an 532 * XTILEDATA-compatible signal stack 533 */ 534 printf("\tTest XCOMP_PERM at child.\n"); 535 validate_xcomp_perm(FAIL_EXPECTED); 536 537 /* 538 * Set up an XTILEDATA-compatible signal stack and 539 * also obtain permission to populate XTILEDATA. 540 */ 541 printf("\tTest dynamic sigaltstack at child:\n"); 542 test_dynamic_sigaltstack(); 543 544 /* Ensure that XTILEDATA can be populated. */ 545 printf("\tTest XCOMP_PERM again at child.\n"); 546 validate_xcomp_perm(SUCCESS_EXPECTED); 547 548 printf("\tFork a grandchild.\n"); 549 grandchild = fork(); 550 if (grandchild < 0) { 551 /* fork() failed */ 552 fatal_error("fork"); 553 } else if (!grandchild) { 554 /* fork() succeeded. Now in the (grand)child. */ 555 printf("\tTest XCOMP_PERM at grandchild.\n"); 556 557 /* 558 * Ensure that the grandchild inherited 559 * permission and a compatible sigaltstack: 560 */ 561 validate_xcomp_perm(SUCCESS_EXPECTED); 562 } else { 563 int status; 564 /* fork() succeeded. Now in the parent. */ 565 566 wait(&status); 567 if (!WIFEXITED(status) || WEXITSTATUS(status)) 568 fatal_error("fork test grandchild"); 569 } 570 571 _exit(0); 572 } 573 574 static inline int __compare_tiledata_state(struct xsave_buffer *xbuf1, struct xsave_buffer *xbuf2) 575 { 576 return memcmp(&xbuf1->bytes[xtiledata.xbuf_offset], 577 &xbuf2->bytes[xtiledata.xbuf_offset], 578 xtiledata.size); 579 } 580 581 /* 582 * Save current register state and compare it to @xbuf1.' 583 * 584 * Returns false if @xbuf1 matches the registers. 585 * Returns true if @xbuf1 differs from the registers. 586 */ 587 static inline bool __validate_tiledata_regs(struct xsave_buffer *xbuf1) 588 { 589 struct xsave_buffer *xbuf2; 590 int ret; 591 592 xbuf2 = alloc_xbuf(); 593 if (!xbuf2) 594 fatal_error("failed to allocate XSAVE buffer\n"); 595 596 xsave(xbuf2, XFEATURE_MASK_XTILEDATA); 597 ret = __compare_tiledata_state(xbuf1, xbuf2); 598 599 free(xbuf2); 600 601 if (ret == 0) 602 return false; 603 return true; 604 } 605 606 static inline void validate_tiledata_regs_same(struct xsave_buffer *xbuf) 607 { 608 int ret = __validate_tiledata_regs(xbuf); 609 610 if (ret != 0) 611 fatal_error("TILEDATA registers changed"); 612 } 613 614 static inline void validate_tiledata_regs_changed(struct xsave_buffer *xbuf) 615 { 616 int ret = __validate_tiledata_regs(xbuf); 617 618 if (ret == 0) 619 fatal_error("TILEDATA registers did not change"); 620 } 621 622 /* tiledata inheritance test */ 623 624 static void test_fork(void) 625 { 626 pid_t child, grandchild; 627 628 child = fork(); 629 if (child < 0) { 630 /* fork() failed */ 631 fatal_error("fork"); 632 } else if (child > 0) { 633 /* fork() succeeded. Now in the parent. */ 634 int status; 635 636 wait(&status); 637 if (!WIFEXITED(status) || WEXITSTATUS(status)) 638 fatal_error("fork test child"); 639 return; 640 } 641 /* fork() succeeded. Now in the child. */ 642 printf("[RUN]\tCheck tile data inheritance.\n\tBefore fork(), load tiledata\n"); 643 644 load_rand_tiledata(stashed_xsave); 645 646 grandchild = fork(); 647 if (grandchild < 0) { 648 /* fork() failed */ 649 fatal_error("fork"); 650 } else if (grandchild > 0) { 651 /* fork() succeeded. Still in the first child. */ 652 int status; 653 654 wait(&status); 655 if (!WIFEXITED(status) || WEXITSTATUS(status)) 656 fatal_error("fork test grand child"); 657 _exit(0); 658 } 659 /* fork() succeeded. Now in the (grand)child. */ 660 661 /* 662 * TILEDATA registers are not preserved across fork(). 663 * Ensure that their value has changed: 664 */ 665 validate_tiledata_regs_changed(stashed_xsave); 666 667 _exit(0); 668 } 669 670 /* Context switching test */ 671 672 static struct _ctxtswtest_cfg { 673 unsigned int iterations; 674 unsigned int num_threads; 675 } ctxtswtest_config; 676 677 struct futex_info { 678 pthread_t thread; 679 int nr; 680 pthread_mutex_t mutex; 681 struct futex_info *next; 682 }; 683 684 static void *check_tiledata(void *info) 685 { 686 struct futex_info *finfo = (struct futex_info *)info; 687 struct xsave_buffer *xbuf; 688 int i; 689 690 xbuf = alloc_xbuf(); 691 if (!xbuf) 692 fatal_error("unable to allocate XSAVE buffer"); 693 694 /* 695 * Load random data into 'xbuf' and then restore 696 * it to the tile registers themselves. 697 */ 698 load_rand_tiledata(xbuf); 699 for (i = 0; i < ctxtswtest_config.iterations; i++) { 700 pthread_mutex_lock(&finfo->mutex); 701 702 /* 703 * Ensure the register values have not 704 * diverged from those recorded in 'xbuf'. 705 */ 706 validate_tiledata_regs_same(xbuf); 707 708 /* Load new, random values into xbuf and registers */ 709 load_rand_tiledata(xbuf); 710 711 /* 712 * The last thread's last unlock will be for 713 * thread 0's mutex. However, thread 0 will 714 * have already exited the loop and the mutex 715 * will already be unlocked. 716 * 717 * Because this is not an ERRORCHECK mutex, 718 * that inconsistency will be silently ignored. 719 */ 720 pthread_mutex_unlock(&finfo->next->mutex); 721 } 722 723 free(xbuf); 724 /* 725 * Return this thread's finfo, which is 726 * a unique value for this thread. 727 */ 728 return finfo; 729 } 730 731 static int create_threads(int num, struct futex_info *finfo) 732 { 733 int i; 734 735 for (i = 0; i < num; i++) { 736 int next_nr; 737 738 finfo[i].nr = i; 739 /* 740 * Thread 'i' will wait on this mutex to 741 * be unlocked. Lock it immediately after 742 * initialization: 743 */ 744 pthread_mutex_init(&finfo[i].mutex, NULL); 745 pthread_mutex_lock(&finfo[i].mutex); 746 747 next_nr = (i + 1) % num; 748 finfo[i].next = &finfo[next_nr]; 749 750 if (pthread_create(&finfo[i].thread, NULL, check_tiledata, &finfo[i])) 751 fatal_error("pthread_create()"); 752 } 753 return 0; 754 } 755 756 static void affinitize_cpu0(void) 757 { 758 cpu_set_t cpuset; 759 760 CPU_ZERO(&cpuset); 761 CPU_SET(0, &cpuset); 762 763 if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0) 764 fatal_error("sched_setaffinity to CPU 0"); 765 } 766 767 static void test_context_switch(void) 768 { 769 struct futex_info *finfo; 770 int i; 771 772 /* Affinitize to one CPU to force context switches */ 773 affinitize_cpu0(); 774 775 req_xtiledata_perm(); 776 777 printf("[RUN]\tCheck tiledata context switches, %d iterations, %d threads.\n", 778 ctxtswtest_config.iterations, 779 ctxtswtest_config.num_threads); 780 781 782 finfo = malloc(sizeof(*finfo) * ctxtswtest_config.num_threads); 783 if (!finfo) 784 fatal_error("malloc()"); 785 786 create_threads(ctxtswtest_config.num_threads, finfo); 787 788 /* 789 * This thread wakes up thread 0 790 * Thread 0 will wake up 1 791 * Thread 1 will wake up 2 792 * ... 793 * the last thread will wake up 0 794 * 795 * ... this will repeat for the configured 796 * number of iterations. 797 */ 798 pthread_mutex_unlock(&finfo[0].mutex); 799 800 /* Wait for all the threads to finish: */ 801 for (i = 0; i < ctxtswtest_config.num_threads; i++) { 802 void *thread_retval; 803 int rc; 804 805 rc = pthread_join(finfo[i].thread, &thread_retval); 806 807 if (rc) 808 fatal_error("pthread_join() failed for thread %d err: %d\n", 809 i, rc); 810 811 if (thread_retval != &finfo[i]) 812 fatal_error("unexpected thread retval for thread %d: %p\n", 813 i, thread_retval); 814 815 } 816 817 printf("[OK]\tNo incorrect case was found.\n"); 818 819 free(finfo); 820 } 821 822 /* Ptrace test */ 823 824 /* 825 * Make sure the ptracee has the expanded kernel buffer on the first 826 * use. Then, initialize the state before performing the state 827 * injection from the ptracer. 828 */ 829 static inline void ptracee_firstuse_tiledata(void) 830 { 831 load_rand_tiledata(stashed_xsave); 832 init_xtiledata(); 833 } 834 835 /* 836 * Ptracer injects the randomized tile data state. It also reads 837 * before and after that, which will execute the kernel's state copy 838 * functions. So, the tester is advised to double-check any emitted 839 * kernel messages. 840 */ 841 static void ptracer_inject_tiledata(pid_t target) 842 { 843 struct xsave_buffer *xbuf; 844 struct iovec iov; 845 846 xbuf = alloc_xbuf(); 847 if (!xbuf) 848 fatal_error("unable to allocate XSAVE buffer"); 849 850 printf("\tRead the init'ed tiledata via ptrace().\n"); 851 852 iov.iov_base = xbuf; 853 iov.iov_len = xbuf_size; 854 855 memset(stashed_xsave, 0, xbuf_size); 856 857 if (ptrace(PTRACE_GETREGSET, target, (uint32_t)NT_X86_XSTATE, &iov)) 858 fatal_error("PTRACE_GETREGSET"); 859 860 if (!__compare_tiledata_state(stashed_xsave, xbuf)) 861 printf("[OK]\tThe init'ed tiledata was read from ptracee.\n"); 862 else 863 printf("[FAIL]\tThe init'ed tiledata was not read from ptracee.\n"); 864 865 printf("\tInject tiledata via ptrace().\n"); 866 867 load_rand_tiledata(xbuf); 868 869 memcpy(&stashed_xsave->bytes[xtiledata.xbuf_offset], 870 &xbuf->bytes[xtiledata.xbuf_offset], 871 xtiledata.size); 872 873 if (ptrace(PTRACE_SETREGSET, target, (uint32_t)NT_X86_XSTATE, &iov)) 874 fatal_error("PTRACE_SETREGSET"); 875 876 if (ptrace(PTRACE_GETREGSET, target, (uint32_t)NT_X86_XSTATE, &iov)) 877 fatal_error("PTRACE_GETREGSET"); 878 879 if (!__compare_tiledata_state(stashed_xsave, xbuf)) 880 printf("[OK]\tTiledata was correctly written to ptracee.\n"); 881 else 882 printf("[FAIL]\tTiledata was not correctly written to ptracee.\n"); 883 } 884 885 static void test_ptrace(void) 886 { 887 pid_t child; 888 int status; 889 890 child = fork(); 891 if (child < 0) { 892 err(1, "fork"); 893 } else if (!child) { 894 if (ptrace(PTRACE_TRACEME, 0, NULL, NULL)) 895 err(1, "PTRACE_TRACEME"); 896 897 ptracee_firstuse_tiledata(); 898 899 raise(SIGTRAP); 900 _exit(0); 901 } 902 903 do { 904 wait(&status); 905 } while (WSTOPSIG(status) != SIGTRAP); 906 907 ptracer_inject_tiledata(child); 908 909 ptrace(PTRACE_DETACH, child, NULL, NULL); 910 wait(&status); 911 if (!WIFEXITED(status) || WEXITSTATUS(status)) 912 err(1, "ptrace test"); 913 } 914 915 int main(void) 916 { 917 unsigned long features; 918 long rc; 919 920 rc = syscall(SYS_arch_prctl, ARCH_GET_XCOMP_SUPP, &features); 921 if (rc || (features & XFEATURE_MASK_XTILE) != XFEATURE_MASK_XTILE) { 922 ksft_print_msg("no AMX support\n"); 923 return KSFT_SKIP; 924 } 925 926 check_cpuid_xtiledata(); 927 928 init_stashed_xsave(); 929 sethandler(SIGILL, handle_noperm, 0); 930 931 test_dynamic_state(); 932 933 /* Request permission for the following tests */ 934 req_xtiledata_perm(); 935 936 test_fork(); 937 938 ctxtswtest_config.iterations = 10; 939 ctxtswtest_config.num_threads = 5; 940 test_context_switch(); 941 942 test_ptrace(); 943 944 clearhandler(SIGILL); 945 free_stashed_xsave(); 946 947 return 0; 948 } 949