1 // SPDX-License-Identifier: GPL-2.0
12 #include <x86intrin.h>
17 #include <sys/ptrace.h>
18 #include <sys/syscall.h>
22 #include "../kselftest.h" /* For __cpuid_count() */
25 # error This test is 64-bit only
28 #define XSAVE_HDR_OFFSET 512
29 #define XSAVE_HDR_SIZE 64
34 char legacy
[XSAVE_HDR_OFFSET
];
35 char header
[XSAVE_HDR_SIZE
];
42 static inline void xsave(struct xsave_buffer
*xbuf
, uint64_t rfbm
)
44 uint32_t rfbm_lo
= rfbm
;
45 uint32_t rfbm_hi
= rfbm
>> 32;
47 asm volatile("xsave (%%rdi)"
48 : : "D" (xbuf
), "a" (rfbm_lo
), "d" (rfbm_hi
)
52 static inline void xrstor(struct xsave_buffer
*xbuf
, uint64_t rfbm
)
54 uint32_t rfbm_lo
= rfbm
;
55 uint32_t rfbm_hi
= rfbm
>> 32;
57 asm volatile("xrstor (%%rdi)"
58 : : "D" (xbuf
), "a" (rfbm_lo
), "d" (rfbm_hi
));
61 /* err() exits and will not return */
62 #define fatal_error(msg, ...) err(1, "[FAIL]\t" msg, ##__VA_ARGS__)
64 static void sethandler(int sig
, void (*handler
)(int, siginfo_t
*, void *),
69 memset(&sa
, 0, sizeof(sa
));
70 sa
.sa_sigaction
= handler
;
71 sa
.sa_flags
= SA_SIGINFO
| flags
;
72 sigemptyset(&sa
.sa_mask
);
73 if (sigaction(sig
, &sa
, 0))
74 fatal_error("sigaction");
77 static void clearhandler(int sig
)
81 memset(&sa
, 0, sizeof(sa
));
82 sa
.sa_handler
= SIG_DFL
;
83 sigemptyset(&sa
.sa_mask
);
84 if (sigaction(sig
, &sa
, 0))
85 fatal_error("sigaction");
88 #define XFEATURE_XTILECFG 17
89 #define XFEATURE_XTILEDATA 18
90 #define XFEATURE_MASK_XTILECFG (1 << XFEATURE_XTILECFG)
91 #define XFEATURE_MASK_XTILEDATA (1 << XFEATURE_XTILEDATA)
92 #define XFEATURE_MASK_XTILE (XFEATURE_MASK_XTILECFG | XFEATURE_MASK_XTILEDATA)
94 #define CPUID_LEAF1_ECX_XSAVE_MASK (1 << 26)
95 #define CPUID_LEAF1_ECX_OSXSAVE_MASK (1 << 27)
97 static uint32_t xbuf_size
;
100 uint32_t xbuf_offset
;
104 #define CPUID_LEAF_XSTATE 0xd
105 #define CPUID_SUBLEAF_XSTATE_USER 0x0
106 #define TILE_CPUID 0x1d
107 #define TILE_PALETTE_ID 0x1
109 static void check_cpuid_xtiledata(void)
111 uint32_t eax
, ebx
, ecx
, edx
;
113 __cpuid_count(CPUID_LEAF_XSTATE
, CPUID_SUBLEAF_XSTATE_USER
,
117 * EBX enumerates the size (in bytes) required by the XSAVE
118 * instruction for an XSAVE area containing all the user state
119 * components corresponding to bits currently set in XCR0.
121 * Stash that off so it can be used to allocate buffers later.
125 __cpuid_count(CPUID_LEAF_XSTATE
, XFEATURE_XTILEDATA
,
128 * eax: XTILEDATA state component size
129 * ebx: XTILEDATA state component offset in user buffer
132 fatal_error("xstate cpuid: invalid tile data size/offset: %d/%d",
135 xtiledata
.size
= eax
;
136 xtiledata
.xbuf_offset
= ebx
;
139 /* The helpers for managing XSAVE buffer and tile states: */
141 struct xsave_buffer
*alloc_xbuf(void)
143 struct xsave_buffer
*xbuf
;
145 /* XSAVE buffer should be 64B-aligned. */
146 xbuf
= aligned_alloc(64, xbuf_size
);
148 fatal_error("aligned_alloc()");
152 static inline void clear_xstate_header(struct xsave_buffer
*buffer
)
154 memset(&buffer
->header
, 0, sizeof(buffer
->header
));
157 static inline void set_xstatebv(struct xsave_buffer
*buffer
, uint64_t bv
)
159 /* XSTATE_BV is at the beginning of the header: */
160 *(uint64_t *)(&buffer
->header
) = bv
;
163 static void set_rand_tiledata(struct xsave_buffer
*xbuf
)
165 int *ptr
= (int *)&xbuf
->bytes
[xtiledata
.xbuf_offset
];
170 * Ensure that 'data' is never 0. This ensures that
171 * the registers are never in their initial configuration
172 * and thus never tracked as being in the init state.
176 for (i
= 0; i
< xtiledata
.size
/ sizeof(int); i
++, ptr
++)
180 struct xsave_buffer
*stashed_xsave
;
182 static void init_stashed_xsave(void)
184 stashed_xsave
= alloc_xbuf();
186 fatal_error("failed to allocate stashed_xsave\n");
187 clear_xstate_header(stashed_xsave
);
190 static void free_stashed_xsave(void)
195 /* See 'struct _fpx_sw_bytes' at sigcontext.h */
196 #define SW_BYTES_OFFSET 464
197 /* N.B. The struct's field name varies so read from the offset. */
198 #define SW_BYTES_BV_OFFSET (SW_BYTES_OFFSET + 8)
200 static inline struct _fpx_sw_bytes
*get_fpx_sw_bytes(void *buffer
)
202 return (struct _fpx_sw_bytes
*)(buffer
+ SW_BYTES_OFFSET
);
205 static inline uint64_t get_fpx_sw_bytes_features(void *buffer
)
207 return *(uint64_t *)(buffer
+ SW_BYTES_BV_OFFSET
);
210 /* Work around printf() being unsafe in signals: */
211 #define SIGNAL_BUF_LEN 1000
212 char signal_message_buffer
[SIGNAL_BUF_LEN
];
213 void sig_print(char *msg
)
215 int left
= SIGNAL_BUF_LEN
- strlen(signal_message_buffer
) - 1;
217 strncat(signal_message_buffer
, msg
, left
);
220 static volatile bool noperm_signaled
;
221 static int noperm_errs
;
223 * Signal handler for when AMX is used but
224 * permission has not been obtained.
226 static void handle_noperm(int sig
, siginfo_t
*si
, void *ctx_void
)
228 ucontext_t
*ctx
= (ucontext_t
*)ctx_void
;
229 void *xbuf
= ctx
->uc_mcontext
.fpregs
;
230 struct _fpx_sw_bytes
*sw_bytes
;
233 /* Reset the signal message buffer: */
234 signal_message_buffer
[0] = '\0';
235 sig_print("\tAt SIGILL handler,\n");
237 if (si
->si_code
!= ILL_ILLOPC
) {
239 sig_print("[FAIL]\tInvalid signal code.\n");
241 sig_print("[OK]\tValid signal code (ILL_ILLOPC).\n");
244 sw_bytes
= get_fpx_sw_bytes(xbuf
);
246 * Without permission, the signal XSAVE buffer should not
247 * have room for AMX register state (aka. xtiledata).
248 * Check that the size does not overlap with where xtiledata
251 * This also implies that no state components *PAST*
252 * XTILEDATA (features >=19) can be present in the buffer.
254 if (sw_bytes
->xstate_size
<= xtiledata
.xbuf_offset
) {
255 sig_print("[OK]\tValid xstate size\n");
258 sig_print("[FAIL]\tInvalid xstate size\n");
261 features
= get_fpx_sw_bytes_features(xbuf
);
263 * Without permission, the XTILEDATA feature
264 * bit should not be set.
266 if ((features
& XFEATURE_MASK_XTILEDATA
) == 0) {
267 sig_print("[OK]\tValid xstate mask\n");
270 sig_print("[FAIL]\tInvalid xstate mask\n");
273 noperm_signaled
= true;
274 ctx
->uc_mcontext
.gregs
[REG_RIP
] += 3; /* Skip the faulting XRSTOR */
277 /* Return true if XRSTOR is successful; otherwise, false. */
278 static inline bool xrstor_safe(struct xsave_buffer
*xbuf
, uint64_t mask
)
280 noperm_signaled
= false;
283 /* Print any messages produced by the signal code: */
284 printf("%s", signal_message_buffer
);
286 * Reset the buffer to make sure any future printing
287 * only outputs new messages:
289 signal_message_buffer
[0] = '\0';
292 fatal_error("saw %d errors in noperm signal handler\n", noperm_errs
);
294 return !noperm_signaled
;
298 * Use XRSTOR to populate the XTILEDATA registers with
301 * Return true if successful; otherwise, false.
303 static inline bool load_rand_tiledata(struct xsave_buffer
*xbuf
)
305 clear_xstate_header(xbuf
);
306 set_xstatebv(xbuf
, XFEATURE_MASK_XTILEDATA
);
307 set_rand_tiledata(xbuf
);
308 return xrstor_safe(xbuf
, XFEATURE_MASK_XTILEDATA
);
311 /* Return XTILEDATA to its initial configuration. */
312 static inline void init_xtiledata(void)
314 clear_xstate_header(stashed_xsave
);
315 xrstor_safe(stashed_xsave
, XFEATURE_MASK_XTILEDATA
);
318 enum expected_result
{ FAIL_EXPECTED
, SUCCESS_EXPECTED
};
320 /* arch_prctl() and sigaltstack() test */
322 #define ARCH_GET_XCOMP_SUPP 0x1021
323 #define ARCH_GET_XCOMP_PERM 0x1022
324 #define ARCH_REQ_XCOMP_PERM 0x1023
326 static void req_xtiledata_perm(void)
328 syscall(SYS_arch_prctl
, ARCH_REQ_XCOMP_PERM
, XFEATURE_XTILEDATA
);
331 static void validate_req_xcomp_perm(enum expected_result exp
)
333 unsigned long bitmask
, expected_bitmask
;
336 rc
= syscall(SYS_arch_prctl
, ARCH_GET_XCOMP_PERM
, &bitmask
);
338 fatal_error("prctl(ARCH_GET_XCOMP_PERM) error: %ld", rc
);
339 } else if (!(bitmask
& XFEATURE_MASK_XTILECFG
)) {
340 fatal_error("ARCH_GET_XCOMP_PERM returns XFEATURE_XTILECFG off.");
343 rc
= syscall(SYS_arch_prctl
, ARCH_REQ_XCOMP_PERM
, XFEATURE_XTILEDATA
);
344 if (exp
== FAIL_EXPECTED
) {
346 printf("[OK]\tARCH_REQ_XCOMP_PERM saw expected failure..\n");
350 fatal_error("ARCH_REQ_XCOMP_PERM saw unexpected success.\n");
352 fatal_error("ARCH_REQ_XCOMP_PERM saw unexpected failure.\n");
355 expected_bitmask
= bitmask
| XFEATURE_MASK_XTILEDATA
;
357 rc
= syscall(SYS_arch_prctl
, ARCH_GET_XCOMP_PERM
, &bitmask
);
359 fatal_error("prctl(ARCH_GET_XCOMP_PERM) error: %ld", rc
);
360 } else if (bitmask
!= expected_bitmask
) {
361 fatal_error("ARCH_REQ_XCOMP_PERM set a wrong bitmask: %lx, expected: %lx.\n",
362 bitmask
, expected_bitmask
);
364 printf("\tARCH_REQ_XCOMP_PERM is successful.\n");
368 static void validate_xcomp_perm(enum expected_result exp
)
370 bool load_success
= load_rand_tiledata(stashed_xsave
);
372 if (exp
== FAIL_EXPECTED
) {
375 printf("[FAIL]\tLoad tiledata succeeded.\n");
377 printf("[OK]\tLoad tiledata failed.\n");
379 } else if (exp
== SUCCESS_EXPECTED
) {
381 printf("[OK]\tLoad tiledata succeeded.\n");
384 printf("[FAIL]\tLoad tiledata failed.\n");
389 #ifndef AT_MINSIGSTKSZ
390 # define AT_MINSIGSTKSZ 51
393 static void *alloc_altstack(unsigned int size
)
397 altstack
= mmap(NULL
, size
, PROT_READ
| PROT_WRITE
,
398 MAP_PRIVATE
| MAP_ANONYMOUS
| MAP_STACK
, -1, 0);
400 if (altstack
== MAP_FAILED
)
401 fatal_error("mmap() for altstack");
406 static void setup_altstack(void *addr
, unsigned long size
, enum expected_result exp
)
411 memset(&ss
, 0, sizeof(ss
));
415 rc
= sigaltstack(&ss
, NULL
);
417 if (exp
== FAIL_EXPECTED
) {
419 printf("[OK]\tsigaltstack() failed.\n");
421 fatal_error("sigaltstack() succeeded unexpectedly.\n");
424 fatal_error("sigaltstack()");
428 static void test_dynamic_sigaltstack(void)
430 unsigned int small_size
, enough_size
;
431 unsigned long minsigstksz
;
434 minsigstksz
= getauxval(AT_MINSIGSTKSZ
);
435 printf("\tAT_MINSIGSTKSZ = %lu\n", minsigstksz
);
437 * getauxval() itself can return 0 for failure or
438 * success. But, in this case, AT_MINSIGSTKSZ
439 * will always return a >=0 value if implemented.
442 if (minsigstksz
== 0) {
443 printf("no support for AT_MINSIGSTKSZ, skipping sigaltstack tests\n");
447 enough_size
= minsigstksz
* 2;
449 altstack
= alloc_altstack(enough_size
);
450 printf("\tAllocate memory for altstack (%u bytes).\n", enough_size
);
453 * Try setup_altstack() with a size which can not fit
454 * XTILEDATA. ARCH_REQ_XCOMP_PERM should fail.
456 small_size
= minsigstksz
- xtiledata
.size
;
457 printf("\tAfter sigaltstack() with small size (%u bytes).\n", small_size
);
458 setup_altstack(altstack
, small_size
, SUCCESS_EXPECTED
);
459 validate_req_xcomp_perm(FAIL_EXPECTED
);
462 * Try setup_altstack() with a size derived from
463 * AT_MINSIGSTKSZ. It should be more than large enough
464 * and thus ARCH_REQ_XCOMP_PERM should succeed.
466 printf("\tAfter sigaltstack() with enough size (%u bytes).\n", enough_size
);
467 setup_altstack(altstack
, enough_size
, SUCCESS_EXPECTED
);
468 validate_req_xcomp_perm(SUCCESS_EXPECTED
);
471 * Try to coerce setup_altstack() to again accept a
472 * too-small altstack. This ensures that big-enough
473 * sigaltstacks can not shrink to a too-small value
474 * once XTILEDATA permission is established.
476 printf("\tThen, sigaltstack() with small size (%u bytes).\n", small_size
);
477 setup_altstack(altstack
, small_size
, FAIL_EXPECTED
);
480 static void test_dynamic_state(void)
482 pid_t parent
, child
, grandchild
;
488 } else if (parent
> 0) {
490 /* fork() succeeded. Now in the parent. */
493 if (!WIFEXITED(status
) || WEXITSTATUS(status
))
494 fatal_error("arch_prctl test parent exit");
497 /* fork() succeeded. Now in the child . */
499 printf("[RUN]\tCheck ARCH_REQ_XCOMP_PERM around process fork() and sigaltack() test.\n");
501 printf("\tFork a child.\n");
505 } else if (child
> 0) {
509 if (!WIFEXITED(status
) || WEXITSTATUS(status
))
510 fatal_error("arch_prctl test child exit");
515 * The permission request should fail without an
516 * XTILEDATA-compatible signal stack
518 printf("\tTest XCOMP_PERM at child.\n");
519 validate_xcomp_perm(FAIL_EXPECTED
);
522 * Set up an XTILEDATA-compatible signal stack and
523 * also obtain permission to populate XTILEDATA.
525 printf("\tTest dynamic sigaltstack at child:\n");
526 test_dynamic_sigaltstack();
528 /* Ensure that XTILEDATA can be populated. */
529 printf("\tTest XCOMP_PERM again at child.\n");
530 validate_xcomp_perm(SUCCESS_EXPECTED
);
532 printf("\tFork a grandchild.\n");
534 if (grandchild
< 0) {
537 } else if (!grandchild
) {
538 /* fork() succeeded. Now in the (grand)child. */
539 printf("\tTest XCOMP_PERM at grandchild.\n");
542 * Ensure that the grandchild inherited
543 * permission and a compatible sigaltstack:
545 validate_xcomp_perm(SUCCESS_EXPECTED
);
548 /* fork() succeeded. Now in the parent. */
551 if (!WIFEXITED(status
) || WEXITSTATUS(status
))
552 fatal_error("fork test grandchild");
558 static inline int __compare_tiledata_state(struct xsave_buffer
*xbuf1
, struct xsave_buffer
*xbuf2
)
560 return memcmp(&xbuf1
->bytes
[xtiledata
.xbuf_offset
],
561 &xbuf2
->bytes
[xtiledata
.xbuf_offset
],
566 * Save current register state and compare it to @xbuf1.'
568 * Returns false if @xbuf1 matches the registers.
569 * Returns true if @xbuf1 differs from the registers.
571 static inline bool __validate_tiledata_regs(struct xsave_buffer
*xbuf1
)
573 struct xsave_buffer
*xbuf2
;
576 xbuf2
= alloc_xbuf();
578 fatal_error("failed to allocate XSAVE buffer\n");
580 xsave(xbuf2
, XFEATURE_MASK_XTILEDATA
);
581 ret
= __compare_tiledata_state(xbuf1
, xbuf2
);
590 static inline void validate_tiledata_regs_same(struct xsave_buffer
*xbuf
)
592 int ret
= __validate_tiledata_regs(xbuf
);
595 fatal_error("TILEDATA registers changed");
598 static inline void validate_tiledata_regs_changed(struct xsave_buffer
*xbuf
)
600 int ret
= __validate_tiledata_regs(xbuf
);
603 fatal_error("TILEDATA registers did not change");
606 /* tiledata inheritance test */
608 static void test_fork(void)
610 pid_t child
, grandchild
;
616 } else if (child
> 0) {
617 /* fork() succeeded. Now in the parent. */
621 if (!WIFEXITED(status
) || WEXITSTATUS(status
))
622 fatal_error("fork test child");
625 /* fork() succeeded. Now in the child. */
626 printf("[RUN]\tCheck tile data inheritance.\n\tBefore fork(), load tiledata\n");
628 load_rand_tiledata(stashed_xsave
);
631 if (grandchild
< 0) {
634 } else if (grandchild
> 0) {
635 /* fork() succeeded. Still in the first child. */
639 if (!WIFEXITED(status
) || WEXITSTATUS(status
))
640 fatal_error("fork test grand child");
643 /* fork() succeeded. Now in the (grand)child. */
646 * TILEDATA registers are not preserved across fork().
647 * Ensure that their value has changed:
649 validate_tiledata_regs_changed(stashed_xsave
);
654 /* Context switching test */
656 static struct _ctxtswtest_cfg
{
657 unsigned int iterations
;
658 unsigned int num_threads
;
664 pthread_mutex_t mutex
;
665 struct futex_info
*next
;
668 static void *check_tiledata(void *info
)
670 struct futex_info
*finfo
= (struct futex_info
*)info
;
671 struct xsave_buffer
*xbuf
;
676 fatal_error("unable to allocate XSAVE buffer");
679 * Load random data into 'xbuf' and then restore
680 * it to the tile registers themselves.
682 load_rand_tiledata(xbuf
);
683 for (i
= 0; i
< ctxtswtest_config
.iterations
; i
++) {
684 pthread_mutex_lock(&finfo
->mutex
);
687 * Ensure the register values have not
688 * diverged from those recorded in 'xbuf'.
690 validate_tiledata_regs_same(xbuf
);
692 /* Load new, random values into xbuf and registers */
693 load_rand_tiledata(xbuf
);
696 * The last thread's last unlock will be for
697 * thread 0's mutex. However, thread 0 will
698 * have already exited the loop and the mutex
699 * will already be unlocked.
701 * Because this is not an ERRORCHECK mutex,
702 * that inconsistency will be silently ignored.
704 pthread_mutex_unlock(&finfo
->next
->mutex
);
709 * Return this thread's finfo, which is
710 * a unique value for this thread.
715 static int create_threads(int num
, struct futex_info
*finfo
)
719 for (i
= 0; i
< num
; i
++) {
724 * Thread 'i' will wait on this mutex to
725 * be unlocked. Lock it immediately after
728 pthread_mutex_init(&finfo
[i
].mutex
, NULL
);
729 pthread_mutex_lock(&finfo
[i
].mutex
);
731 next_nr
= (i
+ 1) % num
;
732 finfo
[i
].next
= &finfo
[next_nr
];
734 if (pthread_create(&finfo
[i
].thread
, NULL
, check_tiledata
, &finfo
[i
]))
735 fatal_error("pthread_create()");
740 static void affinitize_cpu0(void)
747 if (sched_setaffinity(0, sizeof(cpuset
), &cpuset
) != 0)
748 fatal_error("sched_setaffinity to CPU 0");
751 static void test_context_switch(void)
753 struct futex_info
*finfo
;
756 /* Affinitize to one CPU to force context switches */
759 req_xtiledata_perm();
761 printf("[RUN]\tCheck tiledata context switches, %d iterations, %d threads.\n",
762 ctxtswtest_config
.iterations
,
763 ctxtswtest_config
.num_threads
);
766 finfo
= malloc(sizeof(*finfo
) * ctxtswtest_config
.num_threads
);
768 fatal_error("malloc()");
770 create_threads(ctxtswtest_config
.num_threads
, finfo
);
773 * This thread wakes up thread 0
774 * Thread 0 will wake up 1
775 * Thread 1 will wake up 2
777 * the last thread will wake up 0
779 * ... this will repeat for the configured
780 * number of iterations.
782 pthread_mutex_unlock(&finfo
[0].mutex
);
784 /* Wait for all the threads to finish: */
785 for (i
= 0; i
< ctxtswtest_config
.num_threads
; i
++) {
789 rc
= pthread_join(finfo
[i
].thread
, &thread_retval
);
792 fatal_error("pthread_join() failed for thread %d err: %d\n",
795 if (thread_retval
!= &finfo
[i
])
796 fatal_error("unexpected thread retval for thread %d: %p\n",
801 printf("[OK]\tNo incorrect case was found.\n");
809 * Make sure the ptracee has the expanded kernel buffer on the first
810 * use. Then, initialize the state before performing the state
811 * injection from the ptracer.
813 static inline void ptracee_firstuse_tiledata(void)
815 load_rand_tiledata(stashed_xsave
);
820 * Ptracer injects the randomized tile data state. It also reads
821 * before and after that, which will execute the kernel's state copy
822 * functions. So, the tester is advised to double-check any emitted
825 static void ptracer_inject_tiledata(pid_t target
)
827 struct xsave_buffer
*xbuf
;
832 fatal_error("unable to allocate XSAVE buffer");
834 printf("\tRead the init'ed tiledata via ptrace().\n");
837 iov
.iov_len
= xbuf_size
;
839 memset(stashed_xsave
, 0, xbuf_size
);
841 if (ptrace(PTRACE_GETREGSET
, target
, (uint32_t)NT_X86_XSTATE
, &iov
))
842 fatal_error("PTRACE_GETREGSET");
844 if (!__compare_tiledata_state(stashed_xsave
, xbuf
))
845 printf("[OK]\tThe init'ed tiledata was read from ptracee.\n");
847 printf("[FAIL]\tThe init'ed tiledata was not read from ptracee.\n");
849 printf("\tInject tiledata via ptrace().\n");
851 load_rand_tiledata(xbuf
);
853 memcpy(&stashed_xsave
->bytes
[xtiledata
.xbuf_offset
],
854 &xbuf
->bytes
[xtiledata
.xbuf_offset
],
857 if (ptrace(PTRACE_SETREGSET
, target
, (uint32_t)NT_X86_XSTATE
, &iov
))
858 fatal_error("PTRACE_SETREGSET");
860 if (ptrace(PTRACE_GETREGSET
, target
, (uint32_t)NT_X86_XSTATE
, &iov
))
861 fatal_error("PTRACE_GETREGSET");
863 if (!__compare_tiledata_state(stashed_xsave
, xbuf
))
864 printf("[OK]\tTiledata was correctly written to ptracee.\n");
866 printf("[FAIL]\tTiledata was not correctly written to ptracee.\n");
869 static void test_ptrace(void)
878 if (ptrace(PTRACE_TRACEME
, 0, NULL
, NULL
))
879 err(1, "PTRACE_TRACEME");
881 ptracee_firstuse_tiledata();
889 } while (WSTOPSIG(status
) != SIGTRAP
);
891 ptracer_inject_tiledata(child
);
893 ptrace(PTRACE_DETACH
, child
, NULL
, NULL
);
895 if (!WIFEXITED(status
) || WEXITSTATUS(status
))
896 err(1, "ptrace test");
901 unsigned long features
;
904 rc
= syscall(SYS_arch_prctl
, ARCH_GET_XCOMP_SUPP
, &features
);
905 if (rc
|| (features
& XFEATURE_MASK_XTILE
) != XFEATURE_MASK_XTILE
) {
906 ksft_print_msg("no AMX support\n");
910 check_cpuid_xtiledata();
912 init_stashed_xsave();
913 sethandler(SIGILL
, handle_noperm
, 0);
915 test_dynamic_state();
917 /* Request permission for the following tests */
918 req_xtiledata_perm();
922 ctxtswtest_config
.iterations
= 10;
923 ctxtswtest_config
.num_threads
= 5;
924 test_context_switch();
928 clearhandler(SIGILL
);
929 free_stashed_xsave();