1*ed093b41SRobert Mustacchi /*
2*ed093b41SRobert Mustacchi  * This file and its contents are supplied under the terms of the
3*ed093b41SRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4*ed093b41SRobert Mustacchi  * You may only use this file in accordance with the terms of version
5*ed093b41SRobert Mustacchi  * 1.0 of the CDDL.
6*ed093b41SRobert Mustacchi  *
7*ed093b41SRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8*ed093b41SRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9*ed093b41SRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10*ed093b41SRobert Mustacchi  */
11*ed093b41SRobert Mustacchi 
12*ed093b41SRobert Mustacchi /*
13*ed093b41SRobert Mustacchi  * Copyright 2023 Oxide Computer Company
14*ed093b41SRobert Mustacchi  */
15*ed093b41SRobert Mustacchi 
16*ed093b41SRobert Mustacchi /*
17*ed093b41SRobert Mustacchi  * This attempts to do a series of writes to the /proc control file that have
18*ed093b41SRobert Mustacchi  * invalid data for the xregs state. The way that this works is that we create a
19*ed093b41SRobert Mustacchi  * thread that will be detached and just sleeps whenever it wakes up. We direct
20*ed093b41SRobert Mustacchi  * this thread to stop with a directed PCSTOP via libproc.
21*ed093b41SRobert Mustacchi  */
22*ed093b41SRobert Mustacchi 
23*ed093b41SRobert Mustacchi #include <err.h>
24*ed093b41SRobert Mustacchi #include <stdlib.h>
25*ed093b41SRobert Mustacchi #include <libproc.h>
26*ed093b41SRobert Mustacchi #include <thread.h>
27*ed093b41SRobert Mustacchi #include <errno.h>
28*ed093b41SRobert Mustacchi #include <string.h>
29*ed093b41SRobert Mustacchi #include <sys/sysmacros.h>
30*ed093b41SRobert Mustacchi #include <sys/debug.h>
31*ed093b41SRobert Mustacchi #include <sys/x86_archext.h>
32*ed093b41SRobert Mustacchi 
33*ed093b41SRobert Mustacchi #include "xsave_util.h"
34*ed093b41SRobert Mustacchi 
35*ed093b41SRobert Mustacchi static prxregset_t *bad_xregs_pxr;
36*ed093b41SRobert Mustacchi static size_t bad_xregs_size;
37*ed093b41SRobert Mustacchi 
38*ed093b41SRobert Mustacchi typedef struct bad_xregs_test {
39*ed093b41SRobert Mustacchi 	const char *bxt_desc;
40*ed093b41SRobert Mustacchi 	int bxt_errno;
41*ed093b41SRobert Mustacchi 	uint32_t bxt_min;
42*ed093b41SRobert Mustacchi 	void (*bxt_setup)(void **, size_t *);
43*ed093b41SRobert Mustacchi } bad_xregs_test_t;
44*ed093b41SRobert Mustacchi 
45*ed093b41SRobert Mustacchi static void
bad_xregs_no_data(void ** bufp,size_t * sizep)46*ed093b41SRobert Mustacchi bad_xregs_no_data(void **bufp, size_t *sizep)
47*ed093b41SRobert Mustacchi {
48*ed093b41SRobert Mustacchi 	*bufp = NULL;
49*ed093b41SRobert Mustacchi 	*sizep = 0;
50*ed093b41SRobert Mustacchi }
51*ed093b41SRobert Mustacchi 
52*ed093b41SRobert Mustacchi static void
bad_xregs_null_buf(void ** bufp,size_t * sizep)53*ed093b41SRobert Mustacchi bad_xregs_null_buf(void **bufp, size_t *sizep)
54*ed093b41SRobert Mustacchi {
55*ed093b41SRobert Mustacchi 	*bufp = NULL;
56*ed093b41SRobert Mustacchi 	*sizep = sizeof (prxregset_hdr_t);
57*ed093b41SRobert Mustacchi }
58*ed093b41SRobert Mustacchi 
59*ed093b41SRobert Mustacchi static void
bad_xregs_short_hdr(void ** bufp,size_t * sizep)60*ed093b41SRobert Mustacchi bad_xregs_short_hdr(void **bufp, size_t *sizep)
61*ed093b41SRobert Mustacchi {
62*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = calloc(1, sizeof (prxregset_hdr_t));
63*ed093b41SRobert Mustacchi 	if (hdr == NULL) {
64*ed093b41SRobert Mustacchi 		err(EXIT_FAILURE, "failed to allocate header");
65*ed093b41SRobert Mustacchi 	}
66*ed093b41SRobert Mustacchi 
67*ed093b41SRobert Mustacchi 	hdr->pr_type = PR_TYPE_XSAVE;
68*ed093b41SRobert Mustacchi 	hdr->pr_size = sizeof (prxregset_hdr_t);
69*ed093b41SRobert Mustacchi 
70*ed093b41SRobert Mustacchi 	*bufp = hdr;
71*ed093b41SRobert Mustacchi 	*sizep = sizeof (prxregset_hdr_t) - 4;
72*ed093b41SRobert Mustacchi }
73*ed093b41SRobert Mustacchi 
74*ed093b41SRobert Mustacchi static void
bad_xregs_hdr_too_large(void ** bufp,size_t * sizep)75*ed093b41SRobert Mustacchi bad_xregs_hdr_too_large(void **bufp, size_t *sizep)
76*ed093b41SRobert Mustacchi {
77*ed093b41SRobert Mustacchi 	uint32_t large = 32 * 1024 * 1024; /* 4 MiB */
78*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = malloc(32 * 1024 * 1024);
79*ed093b41SRobert Mustacchi 	if (hdr == NULL) {
80*ed093b41SRobert Mustacchi 		err(EXIT_FAILURE, "failed to allocate regset");
81*ed093b41SRobert Mustacchi 	}
82*ed093b41SRobert Mustacchi 
83*ed093b41SRobert Mustacchi 	(void) memcpy(hdr, bad_xregs_pxr, bad_xregs_size);
84*ed093b41SRobert Mustacchi 	hdr->pr_size = large;
85*ed093b41SRobert Mustacchi 
86*ed093b41SRobert Mustacchi 	*bufp = hdr;
87*ed093b41SRobert Mustacchi 	*sizep = large;
88*ed093b41SRobert Mustacchi }
89*ed093b41SRobert Mustacchi 
90*ed093b41SRobert Mustacchi static prxregset_hdr_t *
bad_xregs_std_init(void ** bufp,size_t * sizep)91*ed093b41SRobert Mustacchi bad_xregs_std_init(void **bufp, size_t *sizep)
92*ed093b41SRobert Mustacchi {
93*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = malloc(bad_xregs_size);
94*ed093b41SRobert Mustacchi 	if (hdr == NULL) {
95*ed093b41SRobert Mustacchi 		err(EXIT_FAILURE, "failed to allocate regset");
96*ed093b41SRobert Mustacchi 	}
97*ed093b41SRobert Mustacchi 
98*ed093b41SRobert Mustacchi 	(void) memcpy(hdr, bad_xregs_pxr, bad_xregs_size);
99*ed093b41SRobert Mustacchi 
100*ed093b41SRobert Mustacchi 	*bufp = hdr;
101*ed093b41SRobert Mustacchi 	*sizep = bad_xregs_size;
102*ed093b41SRobert Mustacchi 	return (hdr);
103*ed093b41SRobert Mustacchi }
104*ed093b41SRobert Mustacchi 
105*ed093b41SRobert Mustacchi static void
bad_xregs_missing_data(void ** bufp,size_t * sizep)106*ed093b41SRobert Mustacchi bad_xregs_missing_data(void **bufp, size_t *sizep)
107*ed093b41SRobert Mustacchi {
108*ed093b41SRobert Mustacchi 	(void) bad_xregs_std_init(bufp, sizep);
109*ed093b41SRobert Mustacchi 	*sizep /= 2;
110*ed093b41SRobert Mustacchi }
111*ed093b41SRobert Mustacchi 
112*ed093b41SRobert Mustacchi static void
bad_xregs_hdr_bad_type(void ** bufp,size_t * sizep)113*ed093b41SRobert Mustacchi bad_xregs_hdr_bad_type(void **bufp, size_t *sizep)
114*ed093b41SRobert Mustacchi {
115*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = bad_xregs_std_init(bufp, sizep);
116*ed093b41SRobert Mustacchi 	hdr->pr_type = PR_TYPE_XSAVE + 167;
117*ed093b41SRobert Mustacchi }
118*ed093b41SRobert Mustacchi 
119*ed093b41SRobert Mustacchi static void
bad_xregs_hdr_bad_flags(void ** bufp,size_t * sizep)120*ed093b41SRobert Mustacchi bad_xregs_hdr_bad_flags(void **bufp, size_t *sizep)
121*ed093b41SRobert Mustacchi {
122*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = bad_xregs_std_init(bufp, sizep);
123*ed093b41SRobert Mustacchi 	hdr->pr_flags = 0x123;
124*ed093b41SRobert Mustacchi }
125*ed093b41SRobert Mustacchi 
126*ed093b41SRobert Mustacchi static void
bad_xregs_hdr_bad_pad0(void ** bufp,size_t * sizep)127*ed093b41SRobert Mustacchi bad_xregs_hdr_bad_pad0(void **bufp, size_t *sizep)
128*ed093b41SRobert Mustacchi {
129*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = bad_xregs_std_init(bufp, sizep);
130*ed093b41SRobert Mustacchi 	hdr->pr_pad[0] = 0x456;
131*ed093b41SRobert Mustacchi }
132*ed093b41SRobert Mustacchi 
133*ed093b41SRobert Mustacchi static void
bad_xregs_hdr_bad_pad1(void ** bufp,size_t * sizep)134*ed093b41SRobert Mustacchi bad_xregs_hdr_bad_pad1(void **bufp, size_t *sizep)
135*ed093b41SRobert Mustacchi {
136*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = bad_xregs_std_init(bufp, sizep);
137*ed093b41SRobert Mustacchi 	hdr->pr_pad[1] = 0x789;
138*ed093b41SRobert Mustacchi }
139*ed093b41SRobert Mustacchi 
140*ed093b41SRobert Mustacchi static void
bad_xregs_hdr_bad_pad2(void ** bufp,size_t * sizep)141*ed093b41SRobert Mustacchi bad_xregs_hdr_bad_pad2(void **bufp, size_t *sizep)
142*ed093b41SRobert Mustacchi {
143*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = bad_xregs_std_init(bufp, sizep);
144*ed093b41SRobert Mustacchi 	hdr->pr_pad[2] = 0xabc;
145*ed093b41SRobert Mustacchi }
146*ed093b41SRobert Mustacchi 
147*ed093b41SRobert Mustacchi static void
bad_xregs_hdr_bad_pad3(void ** bufp,size_t * sizep)148*ed093b41SRobert Mustacchi bad_xregs_hdr_bad_pad3(void **bufp, size_t *sizep)
149*ed093b41SRobert Mustacchi {
150*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = bad_xregs_std_init(bufp, sizep);
151*ed093b41SRobert Mustacchi 	hdr->pr_pad[3] = 0xdef;
152*ed093b41SRobert Mustacchi }
153*ed093b41SRobert Mustacchi 
154*ed093b41SRobert Mustacchi static void
bad_xregs_hdr_no_info(void ** bufp,size_t * sizep)155*ed093b41SRobert Mustacchi bad_xregs_hdr_no_info(void **bufp, size_t *sizep)
156*ed093b41SRobert Mustacchi {
157*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = bad_xregs_std_init(bufp, sizep);
158*ed093b41SRobert Mustacchi 	hdr->pr_ninfo = 0;
159*ed093b41SRobert Mustacchi }
160*ed093b41SRobert Mustacchi 
161*ed093b41SRobert Mustacchi static void
bad_xregs_hdr_no_info_len(void ** bufp,size_t * sizep)162*ed093b41SRobert Mustacchi bad_xregs_hdr_no_info_len(void **bufp, size_t *sizep)
163*ed093b41SRobert Mustacchi {
164*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = bad_xregs_std_init(bufp, sizep);
165*ed093b41SRobert Mustacchi 	uint32_t len = sizeof (prxregset_hdr_t) + sizeof (prxregset_info_t) *
166*ed093b41SRobert Mustacchi 	    hdr->pr_ninfo;
167*ed093b41SRobert Mustacchi 	hdr->pr_size = len - 4;
168*ed093b41SRobert Mustacchi }
169*ed093b41SRobert Mustacchi 
170*ed093b41SRobert Mustacchi static void
bad_xregs_info_type(void ** bufp,size_t * sizep)171*ed093b41SRobert Mustacchi bad_xregs_info_type(void **bufp, size_t *sizep)
172*ed093b41SRobert Mustacchi {
173*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = bad_xregs_std_init(bufp, sizep);
174*ed093b41SRobert Mustacchi 	hdr->pr_info[0].pri_type = 0xbaddcafe;
175*ed093b41SRobert Mustacchi }
176*ed093b41SRobert Mustacchi 
177*ed093b41SRobert Mustacchi static void
bad_xregs_info_flags(void ** bufp,size_t * sizep)178*ed093b41SRobert Mustacchi bad_xregs_info_flags(void **bufp, size_t *sizep)
179*ed093b41SRobert Mustacchi {
180*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = bad_xregs_std_init(bufp, sizep);
181*ed093b41SRobert Mustacchi 	VERIFY3U(hdr->pr_ninfo, >=, 2);
182*ed093b41SRobert Mustacchi 	hdr->pr_info[1].pri_flags = 0x120b0;
183*ed093b41SRobert Mustacchi }
184*ed093b41SRobert Mustacchi 
185*ed093b41SRobert Mustacchi static prxregset_info_t *
bad_xregs_find_info(prxregset_hdr_t * hdr,uint32_t type)186*ed093b41SRobert Mustacchi bad_xregs_find_info(prxregset_hdr_t *hdr, uint32_t type)
187*ed093b41SRobert Mustacchi {
188*ed093b41SRobert Mustacchi 	for (uint32_t i = 0; i < hdr->pr_ninfo; i++) {
189*ed093b41SRobert Mustacchi 		if (hdr->pr_info[i].pri_type == type) {
190*ed093b41SRobert Mustacchi 			return (&hdr->pr_info[i]);
191*ed093b41SRobert Mustacchi 		}
192*ed093b41SRobert Mustacchi 	}
193*ed093b41SRobert Mustacchi 
194*ed093b41SRobert Mustacchi 	return (NULL);
195*ed093b41SRobert Mustacchi }
196*ed093b41SRobert Mustacchi 
197*ed093b41SRobert Mustacchi static void
bad_xregs_info_xcr_len(void ** bufp,size_t * sizep)198*ed093b41SRobert Mustacchi bad_xregs_info_xcr_len(void **bufp, size_t *sizep)
199*ed093b41SRobert Mustacchi {
200*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = bad_xregs_std_init(bufp, sizep);
201*ed093b41SRobert Mustacchi 	prxregset_info_t *info = bad_xregs_find_info(hdr, PRX_INFO_XCR);
202*ed093b41SRobert Mustacchi 	VERIFY3P(info, !=, NULL);
203*ed093b41SRobert Mustacchi 	info->pri_size--;
204*ed093b41SRobert Mustacchi }
205*ed093b41SRobert Mustacchi 
206*ed093b41SRobert Mustacchi static void
bad_xregs_info_xcr_off(void ** bufp,size_t * sizep)207*ed093b41SRobert Mustacchi bad_xregs_info_xcr_off(void **bufp, size_t *sizep)
208*ed093b41SRobert Mustacchi {
209*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = bad_xregs_std_init(bufp, sizep);
210*ed093b41SRobert Mustacchi 	prxregset_info_t *info = bad_xregs_find_info(hdr, PRX_INFO_XCR);
211*ed093b41SRobert Mustacchi 	VERIFY3P(info, !=, NULL);
212*ed093b41SRobert Mustacchi 	info->pri_offset++;
213*ed093b41SRobert Mustacchi }
214*ed093b41SRobert Mustacchi 
215*ed093b41SRobert Mustacchi static void
bad_xregs_info_xsave_len(void ** bufp,size_t * sizep)216*ed093b41SRobert Mustacchi bad_xregs_info_xsave_len(void **bufp, size_t *sizep)
217*ed093b41SRobert Mustacchi {
218*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = bad_xregs_std_init(bufp, sizep);
219*ed093b41SRobert Mustacchi 	prxregset_info_t *info = bad_xregs_find_info(hdr, PRX_INFO_XSAVE);
220*ed093b41SRobert Mustacchi 	VERIFY3P(info, !=, NULL);
221*ed093b41SRobert Mustacchi 	info->pri_size--;
222*ed093b41SRobert Mustacchi }
223*ed093b41SRobert Mustacchi 
224*ed093b41SRobert Mustacchi static void
bad_xregs_info_xsave_off(void ** bufp,size_t * sizep)225*ed093b41SRobert Mustacchi bad_xregs_info_xsave_off(void **bufp, size_t *sizep)
226*ed093b41SRobert Mustacchi {
227*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = bad_xregs_std_init(bufp, sizep);
228*ed093b41SRobert Mustacchi 	prxregset_info_t *info = bad_xregs_find_info(hdr, PRX_INFO_XSAVE);
229*ed093b41SRobert Mustacchi 	VERIFY3P(info, !=, NULL);
230*ed093b41SRobert Mustacchi 	info->pri_offset--;
231*ed093b41SRobert Mustacchi }
232*ed093b41SRobert Mustacchi 
233*ed093b41SRobert Mustacchi static void
bad_xregs_info_ymm_len(void ** bufp,size_t * sizep)234*ed093b41SRobert Mustacchi bad_xregs_info_ymm_len(void **bufp, size_t *sizep)
235*ed093b41SRobert Mustacchi {
236*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = bad_xregs_std_init(bufp, sizep);
237*ed093b41SRobert Mustacchi 	prxregset_info_t *info = bad_xregs_find_info(hdr, PRX_INFO_YMM);
238*ed093b41SRobert Mustacchi 	VERIFY3P(info, !=, NULL);
239*ed093b41SRobert Mustacchi 	info->pri_size--;
240*ed093b41SRobert Mustacchi }
241*ed093b41SRobert Mustacchi 
242*ed093b41SRobert Mustacchi static void
bad_xregs_info_ymm_off(void ** bufp,size_t * sizep)243*ed093b41SRobert Mustacchi bad_xregs_info_ymm_off(void **bufp, size_t *sizep)
244*ed093b41SRobert Mustacchi {
245*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = bad_xregs_std_init(bufp, sizep);
246*ed093b41SRobert Mustacchi 	prxregset_info_t *info = bad_xregs_find_info(hdr, PRX_INFO_YMM);
247*ed093b41SRobert Mustacchi 	VERIFY3P(info, !=, NULL);
248*ed093b41SRobert Mustacchi 	info->pri_offset--;
249*ed093b41SRobert Mustacchi }
250*ed093b41SRobert Mustacchi 
251*ed093b41SRobert Mustacchi static void
bad_xregs_info_opmask_len(void ** bufp,size_t * sizep)252*ed093b41SRobert Mustacchi bad_xregs_info_opmask_len(void **bufp, size_t *sizep)
253*ed093b41SRobert Mustacchi {
254*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = bad_xregs_std_init(bufp, sizep);
255*ed093b41SRobert Mustacchi 	prxregset_info_t *info = bad_xregs_find_info(hdr, PRX_INFO_OPMASK);
256*ed093b41SRobert Mustacchi 	VERIFY3P(info, !=, NULL);
257*ed093b41SRobert Mustacchi 	info->pri_size--;
258*ed093b41SRobert Mustacchi }
259*ed093b41SRobert Mustacchi 
260*ed093b41SRobert Mustacchi static void
bad_xregs_info_opmask_off(void ** bufp,size_t * sizep)261*ed093b41SRobert Mustacchi bad_xregs_info_opmask_off(void **bufp, size_t *sizep)
262*ed093b41SRobert Mustacchi {
263*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = bad_xregs_std_init(bufp, sizep);
264*ed093b41SRobert Mustacchi 	prxregset_info_t *info = bad_xregs_find_info(hdr, PRX_INFO_OPMASK);
265*ed093b41SRobert Mustacchi 	VERIFY3P(info, !=, NULL);
266*ed093b41SRobert Mustacchi 	info->pri_offset--;
267*ed093b41SRobert Mustacchi }
268*ed093b41SRobert Mustacchi 
269*ed093b41SRobert Mustacchi static void
bad_xregs_info_zmm_len(void ** bufp,size_t * sizep)270*ed093b41SRobert Mustacchi bad_xregs_info_zmm_len(void **bufp, size_t *sizep)
271*ed093b41SRobert Mustacchi {
272*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = bad_xregs_std_init(bufp, sizep);
273*ed093b41SRobert Mustacchi 	prxregset_info_t *info = bad_xregs_find_info(hdr, PRX_INFO_ZMM);
274*ed093b41SRobert Mustacchi 	VERIFY3P(info, !=, NULL);
275*ed093b41SRobert Mustacchi 	info->pri_size--;
276*ed093b41SRobert Mustacchi }
277*ed093b41SRobert Mustacchi 
278*ed093b41SRobert Mustacchi static void
bad_xregs_info_zmm_off(void ** bufp,size_t * sizep)279*ed093b41SRobert Mustacchi bad_xregs_info_zmm_off(void **bufp, size_t *sizep)
280*ed093b41SRobert Mustacchi {
281*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = bad_xregs_std_init(bufp, sizep);
282*ed093b41SRobert Mustacchi 	prxregset_info_t *info = bad_xregs_find_info(hdr, PRX_INFO_ZMM);
283*ed093b41SRobert Mustacchi 	VERIFY3P(info, !=, NULL);
284*ed093b41SRobert Mustacchi 	info->pri_offset--;
285*ed093b41SRobert Mustacchi }
286*ed093b41SRobert Mustacchi 
287*ed093b41SRobert Mustacchi static void
bad_xregs_info_hi_zmm_len(void ** bufp,size_t * sizep)288*ed093b41SRobert Mustacchi bad_xregs_info_hi_zmm_len(void **bufp, size_t *sizep)
289*ed093b41SRobert Mustacchi {
290*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = bad_xregs_std_init(bufp, sizep);
291*ed093b41SRobert Mustacchi 	prxregset_info_t *info = bad_xregs_find_info(hdr, PRX_INFO_HI_ZMM);
292*ed093b41SRobert Mustacchi 	VERIFY3P(info, !=, NULL);
293*ed093b41SRobert Mustacchi 	info->pri_size--;
294*ed093b41SRobert Mustacchi }
295*ed093b41SRobert Mustacchi 
296*ed093b41SRobert Mustacchi static void
bad_xregs_info_hi_zmm_off(void ** bufp,size_t * sizep)297*ed093b41SRobert Mustacchi bad_xregs_info_hi_zmm_off(void **bufp, size_t *sizep)
298*ed093b41SRobert Mustacchi {
299*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = bad_xregs_std_init(bufp, sizep);
300*ed093b41SRobert Mustacchi 	prxregset_info_t *info = bad_xregs_find_info(hdr, PRX_INFO_HI_ZMM);
301*ed093b41SRobert Mustacchi 	VERIFY3P(info, !=, NULL);
302*ed093b41SRobert Mustacchi 	info->pri_offset--;
303*ed093b41SRobert Mustacchi }
304*ed093b41SRobert Mustacchi 
305*ed093b41SRobert Mustacchi static void
bad_xregs_info_exceeds_len0(void ** bufp,size_t * sizep)306*ed093b41SRobert Mustacchi bad_xregs_info_exceeds_len0(void **bufp, size_t *sizep)
307*ed093b41SRobert Mustacchi {
308*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = bad_xregs_std_init(bufp, sizep);
309*ed093b41SRobert Mustacchi 	hdr->pr_info[0].pri_offset = hdr->pr_size + 4;
310*ed093b41SRobert Mustacchi }
311*ed093b41SRobert Mustacchi 
312*ed093b41SRobert Mustacchi static void
bad_xregs_info_exceeds_len1(void ** bufp,size_t * sizep)313*ed093b41SRobert Mustacchi bad_xregs_info_exceeds_len1(void **bufp, size_t *sizep)
314*ed093b41SRobert Mustacchi {
315*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = bad_xregs_std_init(bufp, sizep);
316*ed093b41SRobert Mustacchi 	hdr->pr_info[0].pri_offset = hdr->pr_size - hdr->pr_info[0].pri_size +
317*ed093b41SRobert Mustacchi 	    8;
318*ed093b41SRobert Mustacchi }
319*ed093b41SRobert Mustacchi 
320*ed093b41SRobert Mustacchi static void
bad_xregs_info_overlaps(void ** bufp,size_t * sizep)321*ed093b41SRobert Mustacchi bad_xregs_info_overlaps(void **bufp, size_t *sizep)
322*ed093b41SRobert Mustacchi {
323*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = bad_xregs_std_init(bufp, sizep);
324*ed093b41SRobert Mustacchi 	hdr->pr_info[0].pri_offset = sizeof (prxregset_hdr_t) + 8;
325*ed093b41SRobert Mustacchi }
326*ed093b41SRobert Mustacchi 
327*ed093b41SRobert Mustacchi static void
bad_xregs_trim_entry(prxregset_hdr_t * hdr,uint32_t type)328*ed093b41SRobert Mustacchi bad_xregs_trim_entry(prxregset_hdr_t *hdr, uint32_t type)
329*ed093b41SRobert Mustacchi {
330*ed093b41SRobert Mustacchi 	boolean_t found = B_FALSE;
331*ed093b41SRobert Mustacchi 	/*
332*ed093b41SRobert Mustacchi 	 * Walk the info structures and clip out everything after the xsave
333*ed093b41SRobert Mustacchi 	 * entry. This almost suggets it'd be nice to have a nop type that was
334*ed093b41SRobert Mustacchi 	 * ignored.
335*ed093b41SRobert Mustacchi 	 */
336*ed093b41SRobert Mustacchi 	for (uint32_t i = 0; i < hdr->pr_ninfo; i++) {
337*ed093b41SRobert Mustacchi 		if (hdr->pr_info[i].pri_type == type) {
338*ed093b41SRobert Mustacchi 			found = B_TRUE;
339*ed093b41SRobert Mustacchi 		}
340*ed093b41SRobert Mustacchi 
341*ed093b41SRobert Mustacchi 		if (found && i + 1 != hdr->pr_ninfo) {
342*ed093b41SRobert Mustacchi 			hdr->pr_info[i] = hdr->pr_info[i + 1];
343*ed093b41SRobert Mustacchi 		}
344*ed093b41SRobert Mustacchi 	}
345*ed093b41SRobert Mustacchi 
346*ed093b41SRobert Mustacchi 	VERIFY3U(found, ==, B_TRUE);
347*ed093b41SRobert Mustacchi 	hdr->pr_ninfo--;
348*ed093b41SRobert Mustacchi }
349*ed093b41SRobert Mustacchi 
350*ed093b41SRobert Mustacchi static void
bad_xregs_no_xsave(void ** bufp,size_t * sizep)351*ed093b41SRobert Mustacchi bad_xregs_no_xsave(void **bufp, size_t *sizep)
352*ed093b41SRobert Mustacchi {
353*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = bad_xregs_std_init(bufp, sizep);
354*ed093b41SRobert Mustacchi 	bad_xregs_trim_entry(hdr, PRX_INFO_XSAVE);
355*ed093b41SRobert Mustacchi }
356*ed093b41SRobert Mustacchi 
357*ed093b41SRobert Mustacchi static void
bad_xregs_missing_xstate(void ** bufp,size_t * sizep)358*ed093b41SRobert Mustacchi bad_xregs_missing_xstate(void **bufp, size_t *sizep)
359*ed093b41SRobert Mustacchi {
360*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = bad_xregs_std_init(bufp, sizep);
361*ed093b41SRobert Mustacchi 	bad_xregs_trim_entry(hdr, PRX_INFO_YMM);
362*ed093b41SRobert Mustacchi 	prxregset_info_t *info = bad_xregs_find_info(hdr, PRX_INFO_XSAVE);
363*ed093b41SRobert Mustacchi 	VERIFY3P(info, !=, NULL);
364*ed093b41SRobert Mustacchi 	prxregset_xsave_t *xsave = (void *)((uintptr_t)*bufp +
365*ed093b41SRobert Mustacchi 	    info->pri_offset);
366*ed093b41SRobert Mustacchi 
367*ed093b41SRobert Mustacchi 	xsave->prx_xsh_xstate_bv |= XFEATURE_AVX;
368*ed093b41SRobert Mustacchi }
369*ed093b41SRobert Mustacchi 
370*ed093b41SRobert Mustacchi static void
bad_xregs_xcr_bad_xcr0(void ** bufp,size_t * sizep)371*ed093b41SRobert Mustacchi bad_xregs_xcr_bad_xcr0(void **bufp, size_t *sizep)
372*ed093b41SRobert Mustacchi {
373*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = bad_xregs_std_init(bufp, sizep);
374*ed093b41SRobert Mustacchi 	prxregset_info_t *info = bad_xregs_find_info(hdr, PRX_INFO_XCR);
375*ed093b41SRobert Mustacchi 	VERIFY3P(info, !=, NULL);
376*ed093b41SRobert Mustacchi 	prxregset_xcr_t *xcr = (void *)((uintptr_t)*bufp + info->pri_offset);
377*ed093b41SRobert Mustacchi 	xcr->prx_xcr_xcr0 = ~xcr->prx_xcr_xcr0;
378*ed093b41SRobert Mustacchi }
379*ed093b41SRobert Mustacchi 
380*ed093b41SRobert Mustacchi static void
bad_xregs_xcr_bad_xfd(void ** bufp,size_t * sizep)381*ed093b41SRobert Mustacchi bad_xregs_xcr_bad_xfd(void **bufp, size_t *sizep)
382*ed093b41SRobert Mustacchi {
383*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = bad_xregs_std_init(bufp, sizep);
384*ed093b41SRobert Mustacchi 	prxregset_info_t *info = bad_xregs_find_info(hdr, PRX_INFO_XCR);
385*ed093b41SRobert Mustacchi 	VERIFY3P(info, !=, NULL);
386*ed093b41SRobert Mustacchi 	prxregset_xcr_t *xcr = (void *)((uintptr_t)*bufp + info->pri_offset);
387*ed093b41SRobert Mustacchi 	xcr->prx_xcr_xfd = ~xcr->prx_xcr_xfd;
388*ed093b41SRobert Mustacchi }
389*ed093b41SRobert Mustacchi 
390*ed093b41SRobert Mustacchi static void
bad_xregs_xcr_bad_pad0(void ** bufp,size_t * sizep)391*ed093b41SRobert Mustacchi bad_xregs_xcr_bad_pad0(void **bufp, size_t *sizep)
392*ed093b41SRobert Mustacchi {
393*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = bad_xregs_std_init(bufp, sizep);
394*ed093b41SRobert Mustacchi 	prxregset_info_t *info = bad_xregs_find_info(hdr, PRX_INFO_XCR);
395*ed093b41SRobert Mustacchi 	VERIFY3P(info, !=, NULL);
396*ed093b41SRobert Mustacchi 	prxregset_xcr_t *xcr = (void *)((uintptr_t)*bufp + info->pri_offset);
397*ed093b41SRobert Mustacchi 	xcr->prx_xcr_pad[0] = 0xdeadbeef;
398*ed093b41SRobert Mustacchi }
399*ed093b41SRobert Mustacchi 
400*ed093b41SRobert Mustacchi static void
bad_xregs_xcr_bad_pad1(void ** bufp,size_t * sizep)401*ed093b41SRobert Mustacchi bad_xregs_xcr_bad_pad1(void **bufp, size_t *sizep)
402*ed093b41SRobert Mustacchi {
403*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = bad_xregs_std_init(bufp, sizep);
404*ed093b41SRobert Mustacchi 	prxregset_info_t *info = bad_xregs_find_info(hdr, PRX_INFO_XCR);
405*ed093b41SRobert Mustacchi 	VERIFY3P(info, !=, NULL);
406*ed093b41SRobert Mustacchi 	prxregset_xcr_t *xcr = (void *)((uintptr_t)*bufp + info->pri_offset);
407*ed093b41SRobert Mustacchi 	xcr->prx_xcr_pad[1] = 0xf00b412;
408*ed093b41SRobert Mustacchi }
409*ed093b41SRobert Mustacchi 
410*ed093b41SRobert Mustacchi static void
bad_xregs_xsave_bad_xbv(void ** bufp,size_t * sizep)411*ed093b41SRobert Mustacchi bad_xregs_xsave_bad_xbv(void **bufp, size_t *sizep)
412*ed093b41SRobert Mustacchi {
413*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = bad_xregs_std_init(bufp, sizep);
414*ed093b41SRobert Mustacchi 	prxregset_info_t *info = bad_xregs_find_info(hdr, PRX_INFO_XSAVE);
415*ed093b41SRobert Mustacchi 	VERIFY3P(info, !=, NULL);
416*ed093b41SRobert Mustacchi 	prxregset_xsave_t *xsave = (void *)((uintptr_t)*bufp +
417*ed093b41SRobert Mustacchi 	    info->pri_offset);
418*ed093b41SRobert Mustacchi 	/*
419*ed093b41SRobert Mustacchi 	 * bit 8 is a supervisor state that we don't currently have defined in
420*ed093b41SRobert Mustacchi 	 * <sys/x86_archext.h> and should always end up being something we don't
421*ed093b41SRobert Mustacchi 	 * see in userland.
422*ed093b41SRobert Mustacchi 	 */
423*ed093b41SRobert Mustacchi 	xsave->prx_xsh_xstate_bv |= (1 << 8);
424*ed093b41SRobert Mustacchi }
425*ed093b41SRobert Mustacchi 
426*ed093b41SRobert Mustacchi static void
bad_xregs_xsave_bad_xcomp(void ** bufp,size_t * sizep)427*ed093b41SRobert Mustacchi bad_xregs_xsave_bad_xcomp(void **bufp, size_t *sizep)
428*ed093b41SRobert Mustacchi {
429*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = bad_xregs_std_init(bufp, sizep);
430*ed093b41SRobert Mustacchi 	prxregset_info_t *info = bad_xregs_find_info(hdr, PRX_INFO_XSAVE);
431*ed093b41SRobert Mustacchi 	VERIFY3P(info, !=, NULL);
432*ed093b41SRobert Mustacchi 	prxregset_xsave_t *xsave = (void *)((uintptr_t)*bufp +
433*ed093b41SRobert Mustacchi 	    info->pri_offset);
434*ed093b41SRobert Mustacchi 	/*
435*ed093b41SRobert Mustacchi 	 * bit 63 is used to say that this is valid. Given that we don't support
436*ed093b41SRobert Mustacchi 	 * it, we just set that bit as the most realistic example of what could
437*ed093b41SRobert Mustacchi 	 * happen.
438*ed093b41SRobert Mustacchi 	 */
439*ed093b41SRobert Mustacchi 	xsave->prx_xsh_xcomp_bv |= (1ULL << 63);
440*ed093b41SRobert Mustacchi }
441*ed093b41SRobert Mustacchi 
442*ed093b41SRobert Mustacchi static void
bad_xregs_xsave_bad_rsvd0(void ** bufp,size_t * sizep)443*ed093b41SRobert Mustacchi bad_xregs_xsave_bad_rsvd0(void **bufp, size_t *sizep)
444*ed093b41SRobert Mustacchi {
445*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = bad_xregs_std_init(bufp, sizep);
446*ed093b41SRobert Mustacchi 	prxregset_info_t *info = bad_xregs_find_info(hdr, PRX_INFO_XSAVE);
447*ed093b41SRobert Mustacchi 	VERIFY3P(info, !=, NULL);
448*ed093b41SRobert Mustacchi 	prxregset_xsave_t *xsave = (void *)((uintptr_t)*bufp +
449*ed093b41SRobert Mustacchi 	    info->pri_offset);
450*ed093b41SRobert Mustacchi 	xsave->prx_xsh_reserved[0] = 0xff10;
451*ed093b41SRobert Mustacchi }
452*ed093b41SRobert Mustacchi 
453*ed093b41SRobert Mustacchi static void
bad_xregs_xsave_bad_rsvd1(void ** bufp,size_t * sizep)454*ed093b41SRobert Mustacchi bad_xregs_xsave_bad_rsvd1(void **bufp, size_t *sizep)
455*ed093b41SRobert Mustacchi {
456*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = bad_xregs_std_init(bufp, sizep);
457*ed093b41SRobert Mustacchi 	prxregset_info_t *info = bad_xregs_find_info(hdr, PRX_INFO_XSAVE);
458*ed093b41SRobert Mustacchi 	VERIFY3P(info, !=, NULL);
459*ed093b41SRobert Mustacchi 	prxregset_xsave_t *xsave = (void *)((uintptr_t)*bufp +
460*ed093b41SRobert Mustacchi 	    info->pri_offset);
461*ed093b41SRobert Mustacchi 	xsave->prx_xsh_reserved[1] = 0x87654321;
462*ed093b41SRobert Mustacchi }
463*ed093b41SRobert Mustacchi 
464*ed093b41SRobert Mustacchi static void
bad_xregs_xsave_bad_rsvd2(void ** bufp,size_t * sizep)465*ed093b41SRobert Mustacchi bad_xregs_xsave_bad_rsvd2(void **bufp, size_t *sizep)
466*ed093b41SRobert Mustacchi {
467*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = bad_xregs_std_init(bufp, sizep);
468*ed093b41SRobert Mustacchi 	prxregset_info_t *info = bad_xregs_find_info(hdr, PRX_INFO_XSAVE);
469*ed093b41SRobert Mustacchi 	VERIFY3P(info, !=, NULL);
470*ed093b41SRobert Mustacchi 	prxregset_xsave_t *xsave = (void *)((uintptr_t)*bufp +
471*ed093b41SRobert Mustacchi 	    info->pri_offset);
472*ed093b41SRobert Mustacchi 	xsave->prx_xsh_reserved[2] = 0x167169;
473*ed093b41SRobert Mustacchi }
474*ed093b41SRobert Mustacchi 
475*ed093b41SRobert Mustacchi static void
bad_xregs_xsave_bad_rsvd3(void ** bufp,size_t * sizep)476*ed093b41SRobert Mustacchi bad_xregs_xsave_bad_rsvd3(void **bufp, size_t *sizep)
477*ed093b41SRobert Mustacchi {
478*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = bad_xregs_std_init(bufp, sizep);
479*ed093b41SRobert Mustacchi 	prxregset_info_t *info = bad_xregs_find_info(hdr, PRX_INFO_XSAVE);
480*ed093b41SRobert Mustacchi 	VERIFY3P(info, !=, NULL);
481*ed093b41SRobert Mustacchi 	prxregset_xsave_t *xsave = (void *)((uintptr_t)*bufp +
482*ed093b41SRobert Mustacchi 	    info->pri_offset);
483*ed093b41SRobert Mustacchi 	xsave->prx_xsh_reserved[3] = 0xff7;
484*ed093b41SRobert Mustacchi }
485*ed093b41SRobert Mustacchi 
486*ed093b41SRobert Mustacchi static void
bad_xregs_xsave_bad_rsvd4(void ** bufp,size_t * sizep)487*ed093b41SRobert Mustacchi bad_xregs_xsave_bad_rsvd4(void **bufp, size_t *sizep)
488*ed093b41SRobert Mustacchi {
489*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = bad_xregs_std_init(bufp, sizep);
490*ed093b41SRobert Mustacchi 	prxregset_info_t *info = bad_xregs_find_info(hdr, PRX_INFO_XSAVE);
491*ed093b41SRobert Mustacchi 	VERIFY3P(info, !=, NULL);
492*ed093b41SRobert Mustacchi 	prxregset_xsave_t *xsave = (void *)((uintptr_t)*bufp +
493*ed093b41SRobert Mustacchi 	    info->pri_offset);
494*ed093b41SRobert Mustacchi 	xsave->prx_xsh_reserved[4] = 0x00f00;
495*ed093b41SRobert Mustacchi }
496*ed093b41SRobert Mustacchi 
497*ed093b41SRobert Mustacchi static void
bad_xregs_xsave_bad_rsvd5(void ** bufp,size_t * sizep)498*ed093b41SRobert Mustacchi bad_xregs_xsave_bad_rsvd5(void **bufp, size_t *sizep)
499*ed093b41SRobert Mustacchi {
500*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = bad_xregs_std_init(bufp, sizep);
501*ed093b41SRobert Mustacchi 	prxregset_info_t *info = bad_xregs_find_info(hdr, PRX_INFO_XSAVE);
502*ed093b41SRobert Mustacchi 	VERIFY3P(info, !=, NULL);
503*ed093b41SRobert Mustacchi 	prxregset_xsave_t *xsave = (void *)((uintptr_t)*bufp +
504*ed093b41SRobert Mustacchi 	    info->pri_offset);
505*ed093b41SRobert Mustacchi 	xsave->prx_xsh_reserved[5] = 0x2374013;
506*ed093b41SRobert Mustacchi }
507*ed093b41SRobert Mustacchi 
508*ed093b41SRobert Mustacchi /*
509*ed093b41SRobert Mustacchi  * The following tests are all 32-bit specific.
510*ed093b41SRobert Mustacchi  */
511*ed093b41SRobert Mustacchi #ifdef __i386
512*ed093b41SRobert Mustacchi static void
bad_xregs_ymm_ilp32(void ** bufp,size_t * sizep)513*ed093b41SRobert Mustacchi bad_xregs_ymm_ilp32(void **bufp, size_t *sizep)
514*ed093b41SRobert Mustacchi {
515*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = bad_xregs_std_init(bufp, sizep);
516*ed093b41SRobert Mustacchi 	prxregset_info_t *info = bad_xregs_find_info(hdr, PRX_INFO_YMM);
517*ed093b41SRobert Mustacchi 	VERIFY3P(info, !=, NULL);
518*ed093b41SRobert Mustacchi 	prxregset_ymm_t *ymm = (void *)((uintptr_t)*bufp + info->pri_offset);
519*ed093b41SRobert Mustacchi 	ymm->prx_rsvd[4]._l[3] = 0x12345;
520*ed093b41SRobert Mustacchi }
521*ed093b41SRobert Mustacchi 
522*ed093b41SRobert Mustacchi static void
bad_xregs_zmm_ilp32(void ** bufp,size_t * sizep)523*ed093b41SRobert Mustacchi bad_xregs_zmm_ilp32(void **bufp, size_t *sizep)
524*ed093b41SRobert Mustacchi {
525*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = bad_xregs_std_init(bufp, sizep);
526*ed093b41SRobert Mustacchi 	prxregset_info_t *info = bad_xregs_find_info(hdr, PRX_INFO_ZMM);
527*ed093b41SRobert Mustacchi 	VERIFY3P(info, !=, NULL);
528*ed093b41SRobert Mustacchi 	prxregset_zmm_t *zmm = (void *)((uintptr_t)*bufp + info->pri_offset);
529*ed093b41SRobert Mustacchi 	zmm->prx_rsvd[2]._l[5] = 0x23456;
530*ed093b41SRobert Mustacchi }
531*ed093b41SRobert Mustacchi 
532*ed093b41SRobert Mustacchi static void
bad_xregs_hi_zmm_ilp32(void ** bufp,size_t * sizep)533*ed093b41SRobert Mustacchi bad_xregs_hi_zmm_ilp32(void **bufp, size_t *sizep)
534*ed093b41SRobert Mustacchi {
535*ed093b41SRobert Mustacchi 	prxregset_hdr_t *hdr = bad_xregs_std_init(bufp, sizep);
536*ed093b41SRobert Mustacchi 	prxregset_info_t *info = bad_xregs_find_info(hdr, PRX_INFO_HI_ZMM);
537*ed093b41SRobert Mustacchi 	VERIFY3P(info, !=, NULL);
538*ed093b41SRobert Mustacchi 	prxregset_hi_zmm_t *hi_zmm = (void *)((uintptr_t)*bufp +
539*ed093b41SRobert Mustacchi 	    info->pri_offset);
540*ed093b41SRobert Mustacchi 	hi_zmm->prx_rsvd[1]._l[9] = 0x34567;
541*ed093b41SRobert Mustacchi }
542*ed093b41SRobert Mustacchi #endif	/* __i386 */
543*ed093b41SRobert Mustacchi 
544*ed093b41SRobert Mustacchi static const bad_xregs_test_t bad_tests[] = {
545*ed093b41SRobert Mustacchi 	{ "no data (NULL buffer)", EINVAL, XSU_YMM, bad_xregs_no_data },
546*ed093b41SRobert Mustacchi 	{ "NULL buffer, non-zero count", EFAULT, XSU_YMM, bad_xregs_null_buf },
547*ed093b41SRobert Mustacchi 	{ "incomplete prxregset_hdr_t", EINVAL, XSU_YMM, bad_xregs_short_hdr },
548*ed093b41SRobert Mustacchi 	{ "prxregset_hdr_t has wrong type", EINVAL, XSU_YMM,
549*ed093b41SRobert Mustacchi 	    bad_xregs_hdr_bad_type },
550*ed093b41SRobert Mustacchi 	{ "prxregset_hdr_t size is too large", EINVAL, XSU_YMM,
551*ed093b41SRobert Mustacchi 	    bad_xregs_hdr_too_large },
552*ed093b41SRobert Mustacchi 	{ "prxregset_hdr_t size bigger than /proc write", EINVAL, XSU_YMM,
553*ed093b41SRobert Mustacchi 	    bad_xregs_missing_data },
554*ed093b41SRobert Mustacchi 	{ "prxregset_hdr_t invalid flags", EINVAL, XSU_YMM,
555*ed093b41SRobert Mustacchi 	    bad_xregs_hdr_bad_flags },
556*ed093b41SRobert Mustacchi 	{ "prxregset_hdr_t invalid pad[0]", EINVAL, XSU_YMM,
557*ed093b41SRobert Mustacchi 	    bad_xregs_hdr_bad_pad0 },
558*ed093b41SRobert Mustacchi 	{ "prxregset_hdr_t invalid pad[1]", EINVAL, XSU_YMM,
559*ed093b41SRobert Mustacchi 	    bad_xregs_hdr_bad_pad1 },
560*ed093b41SRobert Mustacchi 	{ "prxregset_hdr_t invalid pad[2]", EINVAL, XSU_YMM,
561*ed093b41SRobert Mustacchi 	    bad_xregs_hdr_bad_pad2 },
562*ed093b41SRobert Mustacchi 	{ "prxregset_hdr_t invalid pad[3]", EINVAL, XSU_YMM,
563*ed093b41SRobert Mustacchi 	    bad_xregs_hdr_bad_pad3 },
564*ed093b41SRobert Mustacchi 	{ "prxregset_hdr_t no info structures", EINVAL, XSU_YMM,
565*ed093b41SRobert Mustacchi 	    bad_xregs_hdr_no_info },
566*ed093b41SRobert Mustacchi 	{ "prxregset_hdr_t len doesn't cover info structures", EINVAL, XSU_YMM,
567*ed093b41SRobert Mustacchi 	    bad_xregs_hdr_no_info_len },
568*ed093b41SRobert Mustacchi 	{ "prxregset_info_t has bad flags", EINVAL, XSU_YMM,
569*ed093b41SRobert Mustacchi 	    bad_xregs_info_flags },
570*ed093b41SRobert Mustacchi 	{ "prxregset_info_t has bad type", EINVAL, XSU_YMM,
571*ed093b41SRobert Mustacchi 	    bad_xregs_info_type },
572*ed093b41SRobert Mustacchi 	{ "prxregset_info_t has bad len (XCR)", EINVAL, XSU_YMM,
573*ed093b41SRobert Mustacchi 	    bad_xregs_info_xcr_len },
574*ed093b41SRobert Mustacchi 	{ "prxregset_info_t has bad align (XCR)", EINVAL, XSU_YMM,
575*ed093b41SRobert Mustacchi 	    bad_xregs_info_xcr_off },
576*ed093b41SRobert Mustacchi 	{ "prxregset_info_t has bad len (XSAVE)", EINVAL, XSU_YMM,
577*ed093b41SRobert Mustacchi 	    bad_xregs_info_xsave_len },
578*ed093b41SRobert Mustacchi 	{ "prxregset_info_t has bad align (XSAVE)", EINVAL, XSU_YMM,
579*ed093b41SRobert Mustacchi 	    bad_xregs_info_xsave_off },
580*ed093b41SRobert Mustacchi 	{ "prxregset_info_t has bad len (YMM)", EINVAL, XSU_YMM,
581*ed093b41SRobert Mustacchi 	    bad_xregs_info_ymm_len },
582*ed093b41SRobert Mustacchi 	{ "prxregset_info_t has bad align (YMM)", EINVAL, XSU_YMM,
583*ed093b41SRobert Mustacchi 	    bad_xregs_info_ymm_off },
584*ed093b41SRobert Mustacchi 	{ "prxregset_info_t has bad len (OPMASK)", EINVAL, XSU_ZMM,
585*ed093b41SRobert Mustacchi 	    bad_xregs_info_opmask_len },
586*ed093b41SRobert Mustacchi 	{ "prxregset_info_t has bad align (OPMASK)", EINVAL, XSU_ZMM,
587*ed093b41SRobert Mustacchi 	    bad_xregs_info_opmask_off },
588*ed093b41SRobert Mustacchi 	{ "prxregset_info_t has bad len (ZMM)", EINVAL, XSU_ZMM,
589*ed093b41SRobert Mustacchi 	    bad_xregs_info_zmm_len },
590*ed093b41SRobert Mustacchi 	{ "prxregset_info_t has bad align (ZMM)", EINVAL, XSU_ZMM,
591*ed093b41SRobert Mustacchi 	    bad_xregs_info_zmm_off },
592*ed093b41SRobert Mustacchi 	{ "prxregset_info_t has bad len (HI ZMM)", EINVAL, XSU_ZMM,
593*ed093b41SRobert Mustacchi 	    bad_xregs_info_hi_zmm_len },
594*ed093b41SRobert Mustacchi 	{ "prxregset_info_t has bad align (HI ZMM)", EINVAL, XSU_ZMM,
595*ed093b41SRobert Mustacchi 	    bad_xregs_info_hi_zmm_off },
596*ed093b41SRobert Mustacchi 	{ "prxregset_info_t offset exceeds total len (offset beyond len)",
597*ed093b41SRobert Mustacchi 	    EINVAL, XSU_YMM, bad_xregs_info_exceeds_len0 },
598*ed093b41SRobert Mustacchi 	{ "prxregset_info_t offset exceeds total len (size+offset beyond len)",
599*ed093b41SRobert Mustacchi 	    EINVAL, XSU_YMM, bad_xregs_info_exceeds_len1 },
600*ed093b41SRobert Mustacchi 	{ "prxregset_info_t offset overlaps info", EINVAL, XSU_YMM,
601*ed093b41SRobert Mustacchi 	    bad_xregs_info_overlaps },
602*ed093b41SRobert Mustacchi 	{ "prxregset_t missing xsave struct", EINVAL, XSU_YMM,
603*ed093b41SRobert Mustacchi 	    bad_xregs_no_xsave },
604*ed093b41SRobert Mustacchi 	{ "prxregset_t missing xstate bit-vector entry", EINVAL, XSU_YMM,
605*ed093b41SRobert Mustacchi 	    bad_xregs_missing_xstate },
606*ed093b41SRobert Mustacchi 	{ "prxregset_xcr_t modified xcr0", EINVAL, XSU_YMM,
607*ed093b41SRobert Mustacchi 	    bad_xregs_xcr_bad_xcr0 },
608*ed093b41SRobert Mustacchi 	{ "prxregset_xcr_t modified xfd", EINVAL, XSU_YMM,
609*ed093b41SRobert Mustacchi 	    bad_xregs_xcr_bad_xfd },
610*ed093b41SRobert Mustacchi 	{ "prxregset_xcr_t modified pad[0]", EINVAL, XSU_YMM,
611*ed093b41SRobert Mustacchi 	    bad_xregs_xcr_bad_pad0 },
612*ed093b41SRobert Mustacchi 	{ "prxregset_xcr_t modified pad[1]", EINVAL, XSU_YMM,
613*ed093b41SRobert Mustacchi 	    bad_xregs_xcr_bad_pad1 },
614*ed093b41SRobert Mustacchi 	{ "prxregset_xsave_t illegal xbv comp", EINVAL, XSU_YMM,
615*ed093b41SRobert Mustacchi 	    bad_xregs_xsave_bad_xbv },
616*ed093b41SRobert Mustacchi 	{ "prxregset_xsave_t illegal compressed comp", EINVAL, XSU_YMM,
617*ed093b41SRobert Mustacchi 	    bad_xregs_xsave_bad_xcomp },
618*ed093b41SRobert Mustacchi 	{ "prxregset_xsave_t illegal rsvd[0]", EINVAL, XSU_YMM,
619*ed093b41SRobert Mustacchi 	    bad_xregs_xsave_bad_rsvd0 },
620*ed093b41SRobert Mustacchi 	{ "prxregset_xsave_t illegal rsvd[1]", EINVAL, XSU_YMM,
621*ed093b41SRobert Mustacchi 	    bad_xregs_xsave_bad_rsvd1 },
622*ed093b41SRobert Mustacchi 	{ "prxregset_xsave_t illegal rsvd[2]", EINVAL, XSU_YMM,
623*ed093b41SRobert Mustacchi 	    bad_xregs_xsave_bad_rsvd2 },
624*ed093b41SRobert Mustacchi 	{ "prxregset_xsave_t illegal rsvd[3]", EINVAL, XSU_YMM,
625*ed093b41SRobert Mustacchi 	    bad_xregs_xsave_bad_rsvd3 },
626*ed093b41SRobert Mustacchi 	{ "prxregset_xsave_t illegal rsvd[4]", EINVAL, XSU_YMM,
627*ed093b41SRobert Mustacchi 	    bad_xregs_xsave_bad_rsvd4 },
628*ed093b41SRobert Mustacchi 	{ "prxregset_xsave_t illegal rsvd[5]", EINVAL, XSU_YMM,
629*ed093b41SRobert Mustacchi 	    bad_xregs_xsave_bad_rsvd5 },
630*ed093b41SRobert Mustacchi /*
631*ed093b41SRobert Mustacchi  * These next sets of tests are specific to 32-bit binaries as they're not
632*ed093b41SRobert Mustacchi  * allowed to access a bunch of the additional registers that exist.
633*ed093b41SRobert Mustacchi  */
634*ed093b41SRobert Mustacchi #ifdef __i386
635*ed093b41SRobert Mustacchi 	{ "prxregset_ymm_t has non-zero reserved i386 reg", EINVAL, XSU_YMM,
636*ed093b41SRobert Mustacchi 	    bad_xregs_ymm_ilp32 },
637*ed093b41SRobert Mustacchi 	{ "prxregset_zmm_t has non-zero reserved i386 reg", EINVAL, XSU_ZMM,
638*ed093b41SRobert Mustacchi 	    bad_xregs_zmm_ilp32 },
639*ed093b41SRobert Mustacchi 	{ "prxregset_hi_zmm_t has non-zero reserved i386 reg", EINVAL, XSU_ZMM,
640*ed093b41SRobert Mustacchi 	    bad_xregs_hi_zmm_ilp32 },
641*ed093b41SRobert Mustacchi #endif
642*ed093b41SRobert Mustacchi };
643*ed093b41SRobert Mustacchi 
644*ed093b41SRobert Mustacchi int
main(void)645*ed093b41SRobert Mustacchi main(void)
646*ed093b41SRobert Mustacchi {
647*ed093b41SRobert Mustacchi 	int ret;
648*ed093b41SRobert Mustacchi 	int estatus = EXIT_SUCCESS;
649*ed093b41SRobert Mustacchi 	struct ps_prochandle *P;
650*ed093b41SRobert Mustacchi 	struct ps_lwphandle *L;
651*ed093b41SRobert Mustacchi 	thread_t targ;
652*ed093b41SRobert Mustacchi 	uint32_t hwsup;
653*ed093b41SRobert Mustacchi 	uint32_t nskip = 0;
654*ed093b41SRobert Mustacchi 
655*ed093b41SRobert Mustacchi 	hwsup = xsu_hwsupport();
656*ed093b41SRobert Mustacchi 	P = Pgrab(getpid(), PGRAB_RDONLY, &ret);
657*ed093b41SRobert Mustacchi 	if (P == NULL) {
658*ed093b41SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to grab ourself: %s",
659*ed093b41SRobert Mustacchi 		    Pgrab_error(ret));
660*ed093b41SRobert Mustacchi 	}
661*ed093b41SRobert Mustacchi 
662*ed093b41SRobert Mustacchi 	ret = thr_create(NULL, 0, xsu_sleeper_thread, NULL, THR_DETACHED,
663*ed093b41SRobert Mustacchi 	    &targ);
664*ed093b41SRobert Mustacchi 	if (ret != 0) {
665*ed093b41SRobert Mustacchi 		errc(EXIT_FAILURE, ret, "failed to create sleeper thread");
666*ed093b41SRobert Mustacchi 	}
667*ed093b41SRobert Mustacchi 
668*ed093b41SRobert Mustacchi 	L = Lgrab(P, targ, &ret);
669*ed093b41SRobert Mustacchi 	if (L == NULL) {
670*ed093b41SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to grab our sleeper thread: %s",
671*ed093b41SRobert Mustacchi 		    Lgrab_error(ret));
672*ed093b41SRobert Mustacchi 	}
673*ed093b41SRobert Mustacchi 
674*ed093b41SRobert Mustacchi 	ret = Lstop(L, 0);
675*ed093b41SRobert Mustacchi 	if (ret != 0) {
676*ed093b41SRobert Mustacchi 		err(EXIT_FAILURE, "failed to stop the sleeper thread");
677*ed093b41SRobert Mustacchi 	}
678*ed093b41SRobert Mustacchi 
679*ed093b41SRobert Mustacchi 	if (Lgetxregs(L, &bad_xregs_pxr, &bad_xregs_size) != 0) {
680*ed093b41SRobert Mustacchi 		err(EXIT_FAILURE, "failed to get basic xregs");
681*ed093b41SRobert Mustacchi 	}
682*ed093b41SRobert Mustacchi 
683*ed093b41SRobert Mustacchi 	if (bad_xregs_size < sizeof (prxregset_hdr_t)) {
684*ed093b41SRobert Mustacchi 		errx(EXIT_FAILURE, "found bad regset size: %zu",
685*ed093b41SRobert Mustacchi 		    bad_xregs_size);
686*ed093b41SRobert Mustacchi 	}
687*ed093b41SRobert Mustacchi 
688*ed093b41SRobert Mustacchi 	for (size_t i = 0; i < ARRAY_SIZE(bad_tests); i++) {
689*ed093b41SRobert Mustacchi 		void *buf = NULL;
690*ed093b41SRobert Mustacchi 		size_t len = 0;
691*ed093b41SRobert Mustacchi 
692*ed093b41SRobert Mustacchi 		if (bad_tests[i].bxt_min > hwsup) {
693*ed093b41SRobert Mustacchi 			warnx("TEST SKIPPED: %s: requires greater hwsup than "
694*ed093b41SRobert Mustacchi 			    "supported (0x%x)", bad_tests[i].bxt_desc,
695*ed093b41SRobert Mustacchi 			    bad_tests[i].bxt_min);
696*ed093b41SRobert Mustacchi 			nskip++;
697*ed093b41SRobert Mustacchi 			continue;
698*ed093b41SRobert Mustacchi 		}
699*ed093b41SRobert Mustacchi 
700*ed093b41SRobert Mustacchi 		bad_tests[i].bxt_setup(&buf, &len);
701*ed093b41SRobert Mustacchi 		if (Lsetxregs(L, buf, len) != -1) {
702*ed093b41SRobert Mustacchi 			warnx("TEST FAILED: %s: Lsetxregs returned 0, not -1!",
703*ed093b41SRobert Mustacchi 			    bad_tests[i].bxt_desc);
704*ed093b41SRobert Mustacchi 			estatus = EXIT_FAILURE;
705*ed093b41SRobert Mustacchi 		} else if (errno != bad_tests[i].bxt_errno) {
706*ed093b41SRobert Mustacchi 			warnx("TEST FAILED: %s: Lsetxregs errno was %d, "
707*ed093b41SRobert Mustacchi 			    "expected %d", bad_tests[i].bxt_desc, errno,
708*ed093b41SRobert Mustacchi 			    bad_tests[i].bxt_errno);
709*ed093b41SRobert Mustacchi 			estatus = EXIT_FAILURE;
710*ed093b41SRobert Mustacchi 		} else {
711*ed093b41SRobert Mustacchi 			(void) printf("TEST PASSED: %s\n",
712*ed093b41SRobert Mustacchi 			    bad_tests[i].bxt_desc);
713*ed093b41SRobert Mustacchi 		}
714*ed093b41SRobert Mustacchi 		free(buf);
715*ed093b41SRobert Mustacchi 	}
716*ed093b41SRobert Mustacchi 
717*ed093b41SRobert Mustacchi 	if (estatus == EXIT_SUCCESS && nskip > 0) {
718*ed093b41SRobert Mustacchi 		warnx("While tests were successful, %u tests were skipped "
719*ed093b41SRobert Mustacchi 		    "due to missing hardware support", nskip);
720*ed093b41SRobert Mustacchi 	}
721*ed093b41SRobert Mustacchi 
722*ed093b41SRobert Mustacchi 	exit(estatus);
723*ed093b41SRobert Mustacchi }
724