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