0001
0002
0003 #define _GNU_SOURCE
0004 #include <err.h>
0005 #include <errno.h>
0006 #include <pthread.h>
0007 #include <setjmp.h>
0008 #include <stdio.h>
0009 #include <string.h>
0010 #include <stdbool.h>
0011 #include <unistd.h>
0012 #include <x86intrin.h>
0013
0014 #include <sys/auxv.h>
0015 #include <sys/mman.h>
0016 #include <sys/shm.h>
0017 #include <sys/syscall.h>
0018 #include <sys/wait.h>
0019
0020 #include "../kselftest.h" /* For __cpuid_count() */
0021
0022 #ifndef __x86_64__
0023 # error This test is 64-bit only
0024 #endif
0025
0026 #define XSAVE_HDR_OFFSET 512
0027 #define XSAVE_HDR_SIZE 64
0028
0029 struct xsave_buffer {
0030 union {
0031 struct {
0032 char legacy[XSAVE_HDR_OFFSET];
0033 char header[XSAVE_HDR_SIZE];
0034 char extended[0];
0035 };
0036 char bytes[0];
0037 };
0038 };
0039
0040 static inline uint64_t xgetbv(uint32_t index)
0041 {
0042 uint32_t eax, edx;
0043
0044 asm volatile("xgetbv;"
0045 : "=a" (eax), "=d" (edx)
0046 : "c" (index));
0047 return eax + ((uint64_t)edx << 32);
0048 }
0049
0050 static inline void xsave(struct xsave_buffer *xbuf, uint64_t rfbm)
0051 {
0052 uint32_t rfbm_lo = rfbm;
0053 uint32_t rfbm_hi = rfbm >> 32;
0054
0055 asm volatile("xsave (%%rdi)"
0056 : : "D" (xbuf), "a" (rfbm_lo), "d" (rfbm_hi)
0057 : "memory");
0058 }
0059
0060 static inline void xrstor(struct xsave_buffer *xbuf, uint64_t rfbm)
0061 {
0062 uint32_t rfbm_lo = rfbm;
0063 uint32_t rfbm_hi = rfbm >> 32;
0064
0065 asm volatile("xrstor (%%rdi)"
0066 : : "D" (xbuf), "a" (rfbm_lo), "d" (rfbm_hi));
0067 }
0068
0069
0070 #define fatal_error(msg, ...) err(1, "[FAIL]\t" msg, ##__VA_ARGS__)
0071
0072 static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
0073 int flags)
0074 {
0075 struct sigaction sa;
0076
0077 memset(&sa, 0, sizeof(sa));
0078 sa.sa_sigaction = handler;
0079 sa.sa_flags = SA_SIGINFO | flags;
0080 sigemptyset(&sa.sa_mask);
0081 if (sigaction(sig, &sa, 0))
0082 fatal_error("sigaction");
0083 }
0084
0085 static void clearhandler(int sig)
0086 {
0087 struct sigaction sa;
0088
0089 memset(&sa, 0, sizeof(sa));
0090 sa.sa_handler = SIG_DFL;
0091 sigemptyset(&sa.sa_mask);
0092 if (sigaction(sig, &sa, 0))
0093 fatal_error("sigaction");
0094 }
0095
0096 #define XFEATURE_XTILECFG 17
0097 #define XFEATURE_XTILEDATA 18
0098 #define XFEATURE_MASK_XTILECFG (1 << XFEATURE_XTILECFG)
0099 #define XFEATURE_MASK_XTILEDATA (1 << XFEATURE_XTILEDATA)
0100 #define XFEATURE_MASK_XTILE (XFEATURE_MASK_XTILECFG | XFEATURE_MASK_XTILEDATA)
0101
0102 #define CPUID_LEAF1_ECX_XSAVE_MASK (1 << 26)
0103 #define CPUID_LEAF1_ECX_OSXSAVE_MASK (1 << 27)
0104 static inline void check_cpuid_xsave(void)
0105 {
0106 uint32_t eax, ebx, ecx, edx;
0107
0108
0109
0110
0111
0112
0113 __cpuid_count(1, 0, eax, ebx, ecx, edx);
0114 if (!(ecx & CPUID_LEAF1_ECX_XSAVE_MASK))
0115 fatal_error("cpuid: no CPU xsave support");
0116 if (!(ecx & CPUID_LEAF1_ECX_OSXSAVE_MASK))
0117 fatal_error("cpuid: no OS xsave support");
0118 }
0119
0120 static uint32_t xbuf_size;
0121
0122 static struct {
0123 uint32_t xbuf_offset;
0124 uint32_t size;
0125 } xtiledata;
0126
0127 #define CPUID_LEAF_XSTATE 0xd
0128 #define CPUID_SUBLEAF_XSTATE_USER 0x0
0129 #define TILE_CPUID 0x1d
0130 #define TILE_PALETTE_ID 0x1
0131
0132 static void check_cpuid_xtiledata(void)
0133 {
0134 uint32_t eax, ebx, ecx, edx;
0135
0136 __cpuid_count(CPUID_LEAF_XSTATE, CPUID_SUBLEAF_XSTATE_USER,
0137 eax, ebx, ecx, edx);
0138
0139
0140
0141
0142
0143
0144
0145
0146 xbuf_size = ebx;
0147
0148 __cpuid_count(CPUID_LEAF_XSTATE, XFEATURE_XTILEDATA,
0149 eax, ebx, ecx, edx);
0150
0151
0152
0153
0154 if (!eax || !ebx)
0155 fatal_error("xstate cpuid: invalid tile data size/offset: %d/%d",
0156 eax, ebx);
0157
0158 xtiledata.size = eax;
0159 xtiledata.xbuf_offset = ebx;
0160 }
0161
0162
0163
0164 struct xsave_buffer *alloc_xbuf(void)
0165 {
0166 struct xsave_buffer *xbuf;
0167
0168
0169 xbuf = aligned_alloc(64, xbuf_size);
0170 if (!xbuf)
0171 fatal_error("aligned_alloc()");
0172 return xbuf;
0173 }
0174
0175 static inline void clear_xstate_header(struct xsave_buffer *buffer)
0176 {
0177 memset(&buffer->header, 0, sizeof(buffer->header));
0178 }
0179
0180 static inline uint64_t get_xstatebv(struct xsave_buffer *buffer)
0181 {
0182
0183 return *(uint64_t *)&buffer->header;
0184 }
0185
0186 static inline void set_xstatebv(struct xsave_buffer *buffer, uint64_t bv)
0187 {
0188
0189 *(uint64_t *)(&buffer->header) = bv;
0190 }
0191
0192 static void set_rand_tiledata(struct xsave_buffer *xbuf)
0193 {
0194 int *ptr = (int *)&xbuf->bytes[xtiledata.xbuf_offset];
0195 int data;
0196 int i;
0197
0198
0199
0200
0201
0202
0203 data = rand() | 1;
0204
0205 for (i = 0; i < xtiledata.size / sizeof(int); i++, ptr++)
0206 *ptr = data;
0207 }
0208
0209 struct xsave_buffer *stashed_xsave;
0210
0211 static void init_stashed_xsave(void)
0212 {
0213 stashed_xsave = alloc_xbuf();
0214 if (!stashed_xsave)
0215 fatal_error("failed to allocate stashed_xsave\n");
0216 clear_xstate_header(stashed_xsave);
0217 }
0218
0219 static void free_stashed_xsave(void)
0220 {
0221 free(stashed_xsave);
0222 }
0223
0224
0225 #define SW_BYTES_OFFSET 464
0226
0227 #define SW_BYTES_BV_OFFSET (SW_BYTES_OFFSET + 8)
0228
0229 static inline struct _fpx_sw_bytes *get_fpx_sw_bytes(void *buffer)
0230 {
0231 return (struct _fpx_sw_bytes *)(buffer + SW_BYTES_OFFSET);
0232 }
0233
0234 static inline uint64_t get_fpx_sw_bytes_features(void *buffer)
0235 {
0236 return *(uint64_t *)(buffer + SW_BYTES_BV_OFFSET);
0237 }
0238
0239
0240 #define SIGNAL_BUF_LEN 1000
0241 char signal_message_buffer[SIGNAL_BUF_LEN];
0242 void sig_print(char *msg)
0243 {
0244 int left = SIGNAL_BUF_LEN - strlen(signal_message_buffer) - 1;
0245
0246 strncat(signal_message_buffer, msg, left);
0247 }
0248
0249 static volatile bool noperm_signaled;
0250 static int noperm_errs;
0251
0252
0253
0254
0255 static void handle_noperm(int sig, siginfo_t *si, void *ctx_void)
0256 {
0257 ucontext_t *ctx = (ucontext_t *)ctx_void;
0258 void *xbuf = ctx->uc_mcontext.fpregs;
0259 struct _fpx_sw_bytes *sw_bytes;
0260 uint64_t features;
0261
0262
0263 signal_message_buffer[0] = '\0';
0264 sig_print("\tAt SIGILL handler,\n");
0265
0266 if (si->si_code != ILL_ILLOPC) {
0267 noperm_errs++;
0268 sig_print("[FAIL]\tInvalid signal code.\n");
0269 } else {
0270 sig_print("[OK]\tValid signal code (ILL_ILLOPC).\n");
0271 }
0272
0273 sw_bytes = get_fpx_sw_bytes(xbuf);
0274
0275
0276
0277
0278
0279
0280
0281
0282
0283 if (sw_bytes->xstate_size <= xtiledata.xbuf_offset) {
0284 sig_print("[OK]\tValid xstate size\n");
0285 } else {
0286 noperm_errs++;
0287 sig_print("[FAIL]\tInvalid xstate size\n");
0288 }
0289
0290 features = get_fpx_sw_bytes_features(xbuf);
0291
0292
0293
0294
0295 if ((features & XFEATURE_MASK_XTILEDATA) == 0) {
0296 sig_print("[OK]\tValid xstate mask\n");
0297 } else {
0298 noperm_errs++;
0299 sig_print("[FAIL]\tInvalid xstate mask\n");
0300 }
0301
0302 noperm_signaled = true;
0303 ctx->uc_mcontext.gregs[REG_RIP] += 3;
0304 }
0305
0306
0307 static inline bool xrstor_safe(struct xsave_buffer *xbuf, uint64_t mask)
0308 {
0309 noperm_signaled = false;
0310 xrstor(xbuf, mask);
0311
0312
0313 printf("%s", signal_message_buffer);
0314
0315
0316
0317
0318 signal_message_buffer[0] = '\0';
0319
0320 if (noperm_errs)
0321 fatal_error("saw %d errors in noperm signal handler\n", noperm_errs);
0322
0323 return !noperm_signaled;
0324 }
0325
0326
0327
0328
0329
0330
0331
0332 static inline bool load_rand_tiledata(struct xsave_buffer *xbuf)
0333 {
0334 clear_xstate_header(xbuf);
0335 set_xstatebv(xbuf, XFEATURE_MASK_XTILEDATA);
0336 set_rand_tiledata(xbuf);
0337 return xrstor_safe(xbuf, XFEATURE_MASK_XTILEDATA);
0338 }
0339
0340
0341 static inline void init_xtiledata(void)
0342 {
0343 clear_xstate_header(stashed_xsave);
0344 xrstor_safe(stashed_xsave, XFEATURE_MASK_XTILEDATA);
0345 }
0346
0347 enum expected_result { FAIL_EXPECTED, SUCCESS_EXPECTED };
0348
0349
0350
0351 #define ARCH_GET_XCOMP_PERM 0x1022
0352 #define ARCH_REQ_XCOMP_PERM 0x1023
0353
0354 static void req_xtiledata_perm(void)
0355 {
0356 syscall(SYS_arch_prctl, ARCH_REQ_XCOMP_PERM, XFEATURE_XTILEDATA);
0357 }
0358
0359 static void validate_req_xcomp_perm(enum expected_result exp)
0360 {
0361 unsigned long bitmask, expected_bitmask;
0362 long rc;
0363
0364 rc = syscall(SYS_arch_prctl, ARCH_GET_XCOMP_PERM, &bitmask);
0365 if (rc) {
0366 fatal_error("prctl(ARCH_GET_XCOMP_PERM) error: %ld", rc);
0367 } else if (!(bitmask & XFEATURE_MASK_XTILECFG)) {
0368 fatal_error("ARCH_GET_XCOMP_PERM returns XFEATURE_XTILECFG off.");
0369 }
0370
0371 rc = syscall(SYS_arch_prctl, ARCH_REQ_XCOMP_PERM, XFEATURE_XTILEDATA);
0372 if (exp == FAIL_EXPECTED) {
0373 if (rc) {
0374 printf("[OK]\tARCH_REQ_XCOMP_PERM saw expected failure..\n");
0375 return;
0376 }
0377
0378 fatal_error("ARCH_REQ_XCOMP_PERM saw unexpected success.\n");
0379 } else if (rc) {
0380 fatal_error("ARCH_REQ_XCOMP_PERM saw unexpected failure.\n");
0381 }
0382
0383 expected_bitmask = bitmask | XFEATURE_MASK_XTILEDATA;
0384
0385 rc = syscall(SYS_arch_prctl, ARCH_GET_XCOMP_PERM, &bitmask);
0386 if (rc) {
0387 fatal_error("prctl(ARCH_GET_XCOMP_PERM) error: %ld", rc);
0388 } else if (bitmask != expected_bitmask) {
0389 fatal_error("ARCH_REQ_XCOMP_PERM set a wrong bitmask: %lx, expected: %lx.\n",
0390 bitmask, expected_bitmask);
0391 } else {
0392 printf("\tARCH_REQ_XCOMP_PERM is successful.\n");
0393 }
0394 }
0395
0396 static void validate_xcomp_perm(enum expected_result exp)
0397 {
0398 bool load_success = load_rand_tiledata(stashed_xsave);
0399
0400 if (exp == FAIL_EXPECTED) {
0401 if (load_success) {
0402 noperm_errs++;
0403 printf("[FAIL]\tLoad tiledata succeeded.\n");
0404 } else {
0405 printf("[OK]\tLoad tiledata failed.\n");
0406 }
0407 } else if (exp == SUCCESS_EXPECTED) {
0408 if (load_success) {
0409 printf("[OK]\tLoad tiledata succeeded.\n");
0410 } else {
0411 noperm_errs++;
0412 printf("[FAIL]\tLoad tiledata failed.\n");
0413 }
0414 }
0415 }
0416
0417 #ifndef AT_MINSIGSTKSZ
0418 # define AT_MINSIGSTKSZ 51
0419 #endif
0420
0421 static void *alloc_altstack(unsigned int size)
0422 {
0423 void *altstack;
0424
0425 altstack = mmap(NULL, size, PROT_READ | PROT_WRITE,
0426 MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
0427
0428 if (altstack == MAP_FAILED)
0429 fatal_error("mmap() for altstack");
0430
0431 return altstack;
0432 }
0433
0434 static void setup_altstack(void *addr, unsigned long size, enum expected_result exp)
0435 {
0436 stack_t ss;
0437 int rc;
0438
0439 memset(&ss, 0, sizeof(ss));
0440 ss.ss_size = size;
0441 ss.ss_sp = addr;
0442
0443 rc = sigaltstack(&ss, NULL);
0444
0445 if (exp == FAIL_EXPECTED) {
0446 if (rc) {
0447 printf("[OK]\tsigaltstack() failed.\n");
0448 } else {
0449 fatal_error("sigaltstack() succeeded unexpectedly.\n");
0450 }
0451 } else if (rc) {
0452 fatal_error("sigaltstack()");
0453 }
0454 }
0455
0456 static void test_dynamic_sigaltstack(void)
0457 {
0458 unsigned int small_size, enough_size;
0459 unsigned long minsigstksz;
0460 void *altstack;
0461
0462 minsigstksz = getauxval(AT_MINSIGSTKSZ);
0463 printf("\tAT_MINSIGSTKSZ = %lu\n", minsigstksz);
0464
0465
0466
0467
0468
0469
0470 if (minsigstksz == 0) {
0471 printf("no support for AT_MINSIGSTKSZ, skipping sigaltstack tests\n");
0472 return;
0473 }
0474
0475 enough_size = minsigstksz * 2;
0476
0477 altstack = alloc_altstack(enough_size);
0478 printf("\tAllocate memory for altstack (%u bytes).\n", enough_size);
0479
0480
0481
0482
0483
0484 small_size = minsigstksz - xtiledata.size;
0485 printf("\tAfter sigaltstack() with small size (%u bytes).\n", small_size);
0486 setup_altstack(altstack, small_size, SUCCESS_EXPECTED);
0487 validate_req_xcomp_perm(FAIL_EXPECTED);
0488
0489
0490
0491
0492
0493
0494 printf("\tAfter sigaltstack() with enough size (%u bytes).\n", enough_size);
0495 setup_altstack(altstack, enough_size, SUCCESS_EXPECTED);
0496 validate_req_xcomp_perm(SUCCESS_EXPECTED);
0497
0498
0499
0500
0501
0502
0503
0504 printf("\tThen, sigaltstack() with small size (%u bytes).\n", small_size);
0505 setup_altstack(altstack, small_size, FAIL_EXPECTED);
0506 }
0507
0508 static void test_dynamic_state(void)
0509 {
0510 pid_t parent, child, grandchild;
0511
0512 parent = fork();
0513 if (parent < 0) {
0514
0515 fatal_error("fork");
0516 } else if (parent > 0) {
0517 int status;
0518
0519
0520 wait(&status);
0521 if (!WIFEXITED(status) || WEXITSTATUS(status))
0522 fatal_error("arch_prctl test parent exit");
0523 return;
0524 }
0525
0526
0527 printf("[RUN]\tCheck ARCH_REQ_XCOMP_PERM around process fork() and sigaltack() test.\n");
0528
0529 printf("\tFork a child.\n");
0530 child = fork();
0531 if (child < 0) {
0532 fatal_error("fork");
0533 } else if (child > 0) {
0534 int status;
0535
0536 wait(&status);
0537 if (!WIFEXITED(status) || WEXITSTATUS(status))
0538 fatal_error("arch_prctl test child exit");
0539 _exit(0);
0540 }
0541
0542
0543
0544
0545
0546 printf("\tTest XCOMP_PERM at child.\n");
0547 validate_xcomp_perm(FAIL_EXPECTED);
0548
0549
0550
0551
0552
0553 printf("\tTest dynamic sigaltstack at child:\n");
0554 test_dynamic_sigaltstack();
0555
0556
0557 printf("\tTest XCOMP_PERM again at child.\n");
0558 validate_xcomp_perm(SUCCESS_EXPECTED);
0559
0560 printf("\tFork a grandchild.\n");
0561 grandchild = fork();
0562 if (grandchild < 0) {
0563
0564 fatal_error("fork");
0565 } else if (!grandchild) {
0566
0567 printf("\tTest XCOMP_PERM at grandchild.\n");
0568
0569
0570
0571
0572
0573 validate_xcomp_perm(SUCCESS_EXPECTED);
0574 } else {
0575 int status;
0576
0577
0578 wait(&status);
0579 if (!WIFEXITED(status) || WEXITSTATUS(status))
0580 fatal_error("fork test grandchild");
0581 }
0582
0583 _exit(0);
0584 }
0585
0586
0587
0588
0589
0590
0591
0592 static inline bool __validate_tiledata_regs(struct xsave_buffer *xbuf1)
0593 {
0594 struct xsave_buffer *xbuf2;
0595 int ret;
0596
0597 xbuf2 = alloc_xbuf();
0598 if (!xbuf2)
0599 fatal_error("failed to allocate XSAVE buffer\n");
0600
0601 xsave(xbuf2, XFEATURE_MASK_XTILEDATA);
0602 ret = memcmp(&xbuf1->bytes[xtiledata.xbuf_offset],
0603 &xbuf2->bytes[xtiledata.xbuf_offset],
0604 xtiledata.size);
0605
0606 free(xbuf2);
0607
0608 if (ret == 0)
0609 return false;
0610 return true;
0611 }
0612
0613 static inline void validate_tiledata_regs_same(struct xsave_buffer *xbuf)
0614 {
0615 int ret = __validate_tiledata_regs(xbuf);
0616
0617 if (ret != 0)
0618 fatal_error("TILEDATA registers changed");
0619 }
0620
0621 static inline void validate_tiledata_regs_changed(struct xsave_buffer *xbuf)
0622 {
0623 int ret = __validate_tiledata_regs(xbuf);
0624
0625 if (ret == 0)
0626 fatal_error("TILEDATA registers did not change");
0627 }
0628
0629
0630
0631 static void test_fork(void)
0632 {
0633 pid_t child, grandchild;
0634
0635 child = fork();
0636 if (child < 0) {
0637
0638 fatal_error("fork");
0639 } else if (child > 0) {
0640
0641 int status;
0642
0643 wait(&status);
0644 if (!WIFEXITED(status) || WEXITSTATUS(status))
0645 fatal_error("fork test child");
0646 return;
0647 }
0648
0649 printf("[RUN]\tCheck tile data inheritance.\n\tBefore fork(), load tiledata\n");
0650
0651 load_rand_tiledata(stashed_xsave);
0652
0653 grandchild = fork();
0654 if (grandchild < 0) {
0655
0656 fatal_error("fork");
0657 } else if (grandchild > 0) {
0658
0659 int status;
0660
0661 wait(&status);
0662 if (!WIFEXITED(status) || WEXITSTATUS(status))
0663 fatal_error("fork test grand child");
0664 _exit(0);
0665 }
0666
0667
0668
0669
0670
0671
0672 validate_tiledata_regs_changed(stashed_xsave);
0673
0674 _exit(0);
0675 }
0676
0677
0678
0679 static struct _ctxtswtest_cfg {
0680 unsigned int iterations;
0681 unsigned int num_threads;
0682 } ctxtswtest_config;
0683
0684 struct futex_info {
0685 pthread_t thread;
0686 int nr;
0687 pthread_mutex_t mutex;
0688 struct futex_info *next;
0689 };
0690
0691 static void *check_tiledata(void *info)
0692 {
0693 struct futex_info *finfo = (struct futex_info *)info;
0694 struct xsave_buffer *xbuf;
0695 int i;
0696
0697 xbuf = alloc_xbuf();
0698 if (!xbuf)
0699 fatal_error("unable to allocate XSAVE buffer");
0700
0701
0702
0703
0704
0705 load_rand_tiledata(xbuf);
0706 for (i = 0; i < ctxtswtest_config.iterations; i++) {
0707 pthread_mutex_lock(&finfo->mutex);
0708
0709
0710
0711
0712
0713 validate_tiledata_regs_same(xbuf);
0714
0715
0716 load_rand_tiledata(xbuf);
0717
0718
0719
0720
0721
0722
0723
0724
0725
0726
0727 pthread_mutex_unlock(&finfo->next->mutex);
0728 }
0729
0730 free(xbuf);
0731
0732
0733
0734
0735 return finfo;
0736 }
0737
0738 static int create_threads(int num, struct futex_info *finfo)
0739 {
0740 int i;
0741
0742 for (i = 0; i < num; i++) {
0743 int next_nr;
0744
0745 finfo[i].nr = i;
0746
0747
0748
0749
0750
0751 pthread_mutex_init(&finfo[i].mutex, NULL);
0752 pthread_mutex_lock(&finfo[i].mutex);
0753
0754 next_nr = (i + 1) % num;
0755 finfo[i].next = &finfo[next_nr];
0756
0757 if (pthread_create(&finfo[i].thread, NULL, check_tiledata, &finfo[i]))
0758 fatal_error("pthread_create()");
0759 }
0760 return 0;
0761 }
0762
0763 static void affinitize_cpu0(void)
0764 {
0765 cpu_set_t cpuset;
0766
0767 CPU_ZERO(&cpuset);
0768 CPU_SET(0, &cpuset);
0769
0770 if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0)
0771 fatal_error("sched_setaffinity to CPU 0");
0772 }
0773
0774 static void test_context_switch(void)
0775 {
0776 struct futex_info *finfo;
0777 int i;
0778
0779
0780 affinitize_cpu0();
0781
0782 req_xtiledata_perm();
0783
0784 printf("[RUN]\tCheck tiledata context switches, %d iterations, %d threads.\n",
0785 ctxtswtest_config.iterations,
0786 ctxtswtest_config.num_threads);
0787
0788
0789 finfo = malloc(sizeof(*finfo) * ctxtswtest_config.num_threads);
0790 if (!finfo)
0791 fatal_error("malloc()");
0792
0793 create_threads(ctxtswtest_config.num_threads, finfo);
0794
0795
0796
0797
0798
0799
0800
0801
0802
0803
0804
0805 pthread_mutex_unlock(&finfo[0].mutex);
0806
0807
0808 for (i = 0; i < ctxtswtest_config.num_threads; i++) {
0809 void *thread_retval;
0810 int rc;
0811
0812 rc = pthread_join(finfo[i].thread, &thread_retval);
0813
0814 if (rc)
0815 fatal_error("pthread_join() failed for thread %d err: %d\n",
0816 i, rc);
0817
0818 if (thread_retval != &finfo[i])
0819 fatal_error("unexpected thread retval for thread %d: %p\n",
0820 i, thread_retval);
0821
0822 }
0823
0824 printf("[OK]\tNo incorrect case was found.\n");
0825
0826 free(finfo);
0827 }
0828
0829 int main(void)
0830 {
0831
0832 check_cpuid_xsave();
0833 check_cpuid_xtiledata();
0834
0835 init_stashed_xsave();
0836 sethandler(SIGILL, handle_noperm, 0);
0837
0838 test_dynamic_state();
0839
0840
0841 req_xtiledata_perm();
0842
0843 test_fork();
0844
0845 ctxtswtest_config.iterations = 10;
0846 ctxtswtest_config.num_threads = 5;
0847 test_context_switch();
0848
0849 clearhandler(SIGILL);
0850 free_stashed_xsave();
0851
0852 return 0;
0853 }