xref: /illumos-gate/usr/src/test/os-tests/tests/xsave/xsave_util.h (revision d17be682a2c70b4505d43c830bbd2603da11918d)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2023 Oxide Computer Company
14  */
15 
16 #ifndef _XSAVE_UTIL_H
17 #define	_XSAVE_UTIL_H
18 
19 /*
20  * This file contains misc. pieces for use between our tests. This is
21  * implemented in both xsave_util.c and xsave_asm32.s and xsave_asm64.s.
22  */
23 
24 #ifndef	_ASM
25 #include <sys/types.h>
26 #include <stdint.h>
27 #include <ucontext.h>
28 #include <stdio.h>
29 #include <procfs.h>
30 #include <libproc.h>
31 #endif	/* !_ASM */
32 
33 #ifdef __cplusplus
34 extern "C" {
35 #endif
36 
37 /*
38  * While we would prefer an enum, this is a macro so it can be shared with the
39  * assembler code.
40  */
41 #define	XSU_XMM	0
42 #define	XSU_YMM	1
43 #define	XSU_ZMM	2
44 
45 /*
46  * These are definitions that vary based on whether we're in an ILP32 or LP64
47  * environment because of how the ISA works.
48  */
49 #ifdef __amd64
50 #define	XSU_MAX_XMM	16
51 #define	XSU_MAX_YMM	16
52 #define	XSU_MAX_ZMM	32
53 #else
54 #define	XSU_MAX_XMM	8
55 #define	XSU_MAX_YMM	8
56 #define	XSU_MAX_ZMM	8
57 #endif
58 
59 #define	XSU_XMM_U32	4
60 #define	XSU_YMM_U32	8
61 #define	XSU_ZMM_U32	16
62 
63 #ifndef	_ASM
64 
65 /*
66  * Redefine the xsave header here for the test cases so we can avoid exposing
67  * this out of the kernel. Right now the uc_xsave_t isn't defined under
68  * _KMEMUSER and we're trying to hold onto that (or a similar style solution)
69  * while we can.
70  */
71 #define	UC_XSAVE_VERS	(('u' << 24) | ('c' << 16) | 0x01)
72 typedef struct uc_xsave {
73 	uint32_t ucx_vers;
74 	uint32_t ucx_len;
75 	uint64_t ucx_bv;
76 } uc_xsave_t;
77 
78 /*
79  * This structure represents a generic AVX-512 FPU state that can hold up to 32
80  * registers. If only XMM or YMM are valid, then the first 8 and 16 bytes will
81  * be valid respectively and the latter 16 entries won't be used in 64-bit code.
82  * In 32-bit code only the valid FPU entries will present.
83  */
84 typedef struct xsu_fpu {
85 	upad512_t	xf_reg[32];
86 	uint64_t	xf_opmask[8];
87 } xsu_fpu_t;
88 
89 extern uint32_t xsu_hwsupport(void);
90 
91 /*
92  * This deterministically fills the contents of an FPU structure. It will zero
93  * the entire structure and then fill in the appropriate parts based on the type
94  * of FPU we have.
95  */
96 extern void xsu_fill(xsu_fpu_t *, uint32_t, uint32_t);
97 
98 /*
99  * Dump the contents of the FPU in a deterministic fashion to a specified file.
100  */
101 extern void xsu_dump(FILE *, const xsu_fpu_t *, uint32_t);
102 
103 /*
104  * These routines read and write the state of the FPU. This will cover the
105  * selected hardware bits.
106  */
107 extern void xsu_setfpu(const xsu_fpu_t *, uint32_t);
108 extern void xsu_getfpu(xsu_fpu_t *, uint32_t);
109 
110 /*
111  * This is used to overwrite the contents of a ucontext_t with the resulting FPU
112  * state. The xc_xsave will be replaced with a pointer to something of our own
113  * sizing.
114  */
115 extern void xsu_overwrite_uctx(ucontext_t *, const xsu_fpu_t *, uint32_t);
116 
117 /*
118  * Diff two different fpu sets and see if they're identical or not. Only the
119  * bytes that correspond to the indicated pieces will be checked.
120  */
121 extern boolean_t xsu_same(const xsu_fpu_t *, const xsu_fpu_t *, uint32_t);
122 
123 /*
124  * This function allocates and sets up the prxregset_hdr_t and associated notes
125  * with their expected values based on the hardware support values.
126  */
127 extern void xsu_xregs_alloc(void **, size_t *, uint32_t);
128 
129 /*
130  * This is a common function that just sleeps and is meant to be here for test
131  * programs that want a thread to mess with.
132  */
133 extern void *xsu_sleeper_thread(void *);
134 
135 /*
136  * Convert a given xsu_fpu_t state into something that we can set via xregs.
137  */
138 extern void xsu_fpu_to_xregs(const xsu_fpu_t *, uint32_t, prxregset_t **,
139     size_t *);
140 
141 typedef struct xsu_proc {
142 	char *xp_prog;
143 	char *xp_arg;
144 	const char *xp_object;
145 	const char *xp_symname;
146 	struct ps_prochandle *xp_proc;
147 	uintptr_t xp_addr;
148 	ulong_t xp_instr;
149 	int xp_wait;
150 } xsu_proc_t;
151 
152 /*
153  * This pair of functions gives us a mini-debugging context. The first sets up a
154  * program that is ready and paused at a breakpoint.
155  */
156 extern void xsu_proc_bkpt(xsu_proc_t *);
157 extern void xsu_proc_finish(xsu_proc_t *);
158 
159 /*
160  * Set the xmm portion of an fpregset based on a seed.
161  */
162 extern void xsu_fpregset_xmm_set(fpregset_t *, uint32_t);
163 extern void xsu_xregs_xmm_set(prxregset_t *, uint32_t);
164 
165 /*
166  * Go through and see if the data in an fpregs section is equivalent to an xregs
167  * XMM section. This focuses on the control words and xmm data, we do not bother
168  * with the x87 registers themselves and not all of the 32-bit pieces.
169  */
170 extern boolean_t xsu_fpregs_cmp(const fpregset_t *, const prxregset_t *);
171 
172 /*
173  * Given two xregs structures, check if the given component in them has
174  * identical data. Note, this assumes that the structure is valid-ish. That is,
175  * that all the info structures point to valid data.
176  */
177 extern boolean_t xsu_xregs_comp_equal(const prxregset_t *, const prxregset_t *,
178     uint32_t);
179 
180 /*
181  * Allocate a stack and fill out the uc_stack member for a ucontext_t.
182  * Subsequent calls will reuse the same allocated stack.
183  */
184 extern void xsu_ustack_alloc(ucontext_t *);
185 
186 #endif	/* !_ASM */
187 
188 #ifdef __cplusplus
189 }
190 #endif
191 
192 #endif /* _XSAVE_UTIL_H */
193