Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
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 /* err() exits and will not return */
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      * CPUID.1:ECX.XSAVE[bit 26] enumerates general
0110      * support for the XSAVE feature set, including
0111      * XGETBV.
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      * EBX enumerates the size (in bytes) required by the XSAVE
0141      * instruction for an XSAVE area containing all the user state
0142      * components corresponding to bits currently set in XCR0.
0143      *
0144      * Stash that off so it can be used to allocate buffers later.
0145      */
0146     xbuf_size = ebx;
0147 
0148     __cpuid_count(CPUID_LEAF_XSTATE, XFEATURE_XTILEDATA,
0149               eax, ebx, ecx, edx);
0150     /*
0151      * eax: XTILEDATA state component size
0152      * ebx: XTILEDATA state component offset in user buffer
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 /* The helpers for managing XSAVE buffer and tile states: */
0163 
0164 struct xsave_buffer *alloc_xbuf(void)
0165 {
0166     struct xsave_buffer *xbuf;
0167 
0168     /* XSAVE buffer should be 64B-aligned. */
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     /* XSTATE_BV is at the beginning of the header: */
0183     return *(uint64_t *)&buffer->header;
0184 }
0185 
0186 static inline void set_xstatebv(struct xsave_buffer *buffer, uint64_t bv)
0187 {
0188     /* XSTATE_BV is at the beginning of the header: */
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      * Ensure that 'data' is never 0.  This ensures that
0200      * the registers are never in their initial configuration
0201      * and thus never tracked as being in the init state.
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 /* See 'struct _fpx_sw_bytes' at sigcontext.h */
0225 #define SW_BYTES_OFFSET     464
0226 /* N.B. The struct's field name varies so read from the offset. */
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 /* Work around printf() being unsafe in signals: */
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  * Signal handler for when AMX is used but
0253  * permission has not been obtained.
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     /* Reset the signal message buffer: */
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      * Without permission, the signal XSAVE buffer should not
0276      * have room for AMX register state (aka. xtiledata).
0277      * Check that the size does not overlap with where xtiledata
0278      * will reside.
0279      *
0280      * This also implies that no state components *PAST*
0281      * XTILEDATA (features >=19) can be present in the buffer.
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      * Without permission, the XTILEDATA feature
0293      * bit should not be set.
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; /* Skip the faulting XRSTOR */
0304 }
0305 
0306 /* Return true if XRSTOR is successful; otherwise, false. */
0307 static inline bool xrstor_safe(struct xsave_buffer *xbuf, uint64_t mask)
0308 {
0309     noperm_signaled = false;
0310     xrstor(xbuf, mask);
0311 
0312     /* Print any messages produced by the signal code: */
0313     printf("%s", signal_message_buffer);
0314     /*
0315      * Reset the buffer to make sure any future printing
0316      * only outputs new messages:
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  * Use XRSTOR to populate the XTILEDATA registers with
0328  * random data.
0329  *
0330  * Return true if successful; otherwise, false.
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 /* Return XTILEDATA to its initial configuration. */
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 /* arch_prctl() and sigaltstack() test */
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      * getauxval() itself can return 0 for failure or
0466      * success.  But, in this case, AT_MINSIGSTKSZ
0467      * will always return a >=0 value if implemented.
0468      * Just check for 0.
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      * Try setup_altstack() with a size which can not fit
0482      * XTILEDATA.  ARCH_REQ_XCOMP_PERM should fail.
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      * Try setup_altstack() with a size derived from
0491      * AT_MINSIGSTKSZ.  It should be more than large enough
0492      * and thus ARCH_REQ_XCOMP_PERM should succeed.
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      * Try to coerce setup_altstack() to again accept a
0500      * too-small altstack.  This ensures that big-enough
0501      * sigaltstacks can not shrink to a too-small value
0502      * once XTILEDATA permission is established.
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         /* fork() failed */
0515         fatal_error("fork");
0516     } else if (parent > 0) {
0517         int status;
0518         /* fork() succeeded.  Now in the parent. */
0519 
0520         wait(&status);
0521         if (!WIFEXITED(status) || WEXITSTATUS(status))
0522             fatal_error("arch_prctl test parent exit");
0523         return;
0524     }
0525     /* fork() succeeded.  Now in the child . */
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      * The permission request should fail without an
0544      * XTILEDATA-compatible signal stack
0545      */
0546     printf("\tTest XCOMP_PERM at child.\n");
0547     validate_xcomp_perm(FAIL_EXPECTED);
0548 
0549     /*
0550      * Set up an XTILEDATA-compatible signal stack and
0551      * also obtain permission to populate XTILEDATA.
0552      */
0553     printf("\tTest dynamic sigaltstack at child:\n");
0554     test_dynamic_sigaltstack();
0555 
0556     /* Ensure that XTILEDATA can be populated. */
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         /* fork() failed */
0564         fatal_error("fork");
0565     } else if (!grandchild) {
0566         /* fork() succeeded.  Now in the (grand)child. */
0567         printf("\tTest XCOMP_PERM at grandchild.\n");
0568 
0569         /*
0570          * Ensure that the grandchild inherited
0571          * permission and a compatible sigaltstack:
0572          */
0573         validate_xcomp_perm(SUCCESS_EXPECTED);
0574     } else {
0575         int status;
0576         /* fork() succeeded.  Now in the parent. */
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  * Save current register state and compare it to @xbuf1.'
0588  *
0589  * Returns false if @xbuf1 matches the registers.
0590  * Returns true  if @xbuf1 differs from the registers.
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 /* tiledata inheritance test */
0630 
0631 static void test_fork(void)
0632 {
0633     pid_t child, grandchild;
0634 
0635     child = fork();
0636     if (child < 0) {
0637         /* fork() failed */
0638         fatal_error("fork");
0639     } else if (child > 0) {
0640         /* fork() succeeded.  Now in the parent. */
0641         int status;
0642 
0643         wait(&status);
0644         if (!WIFEXITED(status) || WEXITSTATUS(status))
0645             fatal_error("fork test child");
0646         return;
0647     }
0648     /* fork() succeeded.  Now in the child. */
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         /* fork() failed */
0656         fatal_error("fork");
0657     } else if (grandchild > 0) {
0658         /* fork() succeeded.  Still in the first child. */
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     /* fork() succeeded.  Now in the (grand)child. */
0667 
0668     /*
0669      * TILEDATA registers are not preserved across fork().
0670      * Ensure that their value has changed:
0671      */
0672     validate_tiledata_regs_changed(stashed_xsave);
0673 
0674     _exit(0);
0675 }
0676 
0677 /* Context switching test */
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      * Load random data into 'xbuf' and then restore
0703      * it to the tile registers themselves.
0704      */
0705     load_rand_tiledata(xbuf);
0706     for (i = 0; i < ctxtswtest_config.iterations; i++) {
0707         pthread_mutex_lock(&finfo->mutex);
0708 
0709         /*
0710          * Ensure the register values have not
0711          * diverged from those recorded in 'xbuf'.
0712          */
0713         validate_tiledata_regs_same(xbuf);
0714 
0715         /* Load new, random values into xbuf and registers */
0716         load_rand_tiledata(xbuf);
0717 
0718         /*
0719          * The last thread's last unlock will be for
0720          * thread 0's mutex.  However, thread 0 will
0721          * have already exited the loop and the mutex
0722          * will already be unlocked.
0723          *
0724          * Because this is not an ERRORCHECK mutex,
0725          * that inconsistency will be silently ignored.
0726          */
0727         pthread_mutex_unlock(&finfo->next->mutex);
0728     }
0729 
0730     free(xbuf);
0731     /*
0732      * Return this thread's finfo, which is
0733      * a unique value for this thread.
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          * Thread 'i' will wait on this mutex to
0748          * be unlocked.  Lock it immediately after
0749          * initialization:
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     /* Affinitize to one CPU to force context switches */
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      * This thread wakes up thread 0
0797      * Thread 0 will wake up 1
0798      * Thread 1 will wake up 2
0799      * ...
0800      * the last thread will wake up 0
0801      *
0802      * ... this will repeat for the configured
0803      * number of iterations.
0804      */
0805     pthread_mutex_unlock(&finfo[0].mutex);
0806 
0807     /* Wait for all the threads to finish: */
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     /* Check hardware availability at first */
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     /* Request permission for the following tests */
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 }