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