xref: /linux/tools/testing/selftests/x86/amx.c (revision 001821b0e79716c4e17c71d8e053a23599a7a508)
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