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