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