xref: /linux/tools/testing/selftests/x86/xstate.h (revision dd8845db6d05e81532110c271d5f1cef3975916a)
1 // SPDX-License-Identifier: GPL-2.0-only
2 #ifndef __SELFTESTS_X86_XSTATE_H
3 #define __SELFTESTS_X86_XSTATE_H
4 
5 #include <stdint.h>
6 #include <stdlib.h>
7 #include <string.h>
8 
9 #include "kselftest.h"
10 
11 #define XSAVE_HDR_OFFSET	512
12 #define XSAVE_HDR_SIZE		64
13 
14 /*
15  * List of XSAVE features Linux knows about. Copied from
16  * arch/x86/include/asm/fpu/types.h
17  */
18 enum xfeature {
19 	XFEATURE_FP,
20 	XFEATURE_SSE,
21 	XFEATURE_YMM,
22 	XFEATURE_BNDREGS,
23 	XFEATURE_BNDCSR,
24 	XFEATURE_OPMASK,
25 	XFEATURE_ZMM_Hi256,
26 	XFEATURE_Hi16_ZMM,
27 	XFEATURE_PT_UNIMPLEMENTED_SO_FAR,
28 	XFEATURE_PKRU,
29 	XFEATURE_PASID,
30 	XFEATURE_CET_USER,
31 	XFEATURE_CET_KERNEL_UNUSED,
32 	XFEATURE_RSRVD_COMP_13,
33 	XFEATURE_RSRVD_COMP_14,
34 	XFEATURE_LBR,
35 	XFEATURE_RSRVD_COMP_16,
36 	XFEATURE_XTILECFG,
37 	XFEATURE_XTILEDATA,
38 	XFEATURE_APX,
39 
40 	XFEATURE_MAX,
41 };
42 
43 /* Copied from arch/x86/kernel/fpu/xstate.c */
44 static const char *xfeature_names[] =
45 {
46 	"x87 floating point registers",
47 	"SSE registers",
48 	"AVX registers",
49 	"MPX bounds registers",
50 	"MPX CSR",
51 	"AVX-512 opmask",
52 	"AVX-512 Hi256",
53 	"AVX-512 ZMM_Hi256",
54 	"Processor Trace (unused)",
55 	"Protection Keys User registers",
56 	"PASID state",
57 	"Control-flow User registers",
58 	"Control-flow Kernel registers (unused)",
59 	"unknown xstate feature",
60 	"unknown xstate feature",
61 	"unknown xstate feature",
62 	"unknown xstate feature",
63 	"AMX Tile config",
64 	"AMX Tile data",
65 	"APX registers",
66 	"unknown xstate feature",
67 };
68 
69 struct xsave_buffer {
70 	union {
71 		struct {
72 			char legacy[XSAVE_HDR_OFFSET];
73 			char header[XSAVE_HDR_SIZE];
74 			char extended[0];
75 		};
76 		char bytes[0];
77 	};
78 };
79 
xsave(struct xsave_buffer * xbuf,uint64_t rfbm)80 static inline void xsave(struct xsave_buffer *xbuf, uint64_t rfbm)
81 {
82 	uint32_t rfbm_hi = rfbm >> 32;
83 	uint32_t rfbm_lo = rfbm;
84 
85 	asm volatile("xsave (%%rdi)"
86 		     : : "D" (xbuf), "a" (rfbm_lo), "d" (rfbm_hi)
87 		     : "memory");
88 }
89 
xrstor(struct xsave_buffer * xbuf,uint64_t rfbm)90 static inline void xrstor(struct xsave_buffer *xbuf, uint64_t rfbm)
91 {
92 	uint32_t rfbm_hi = rfbm >> 32;
93 	uint32_t rfbm_lo = rfbm;
94 
95 	asm volatile("xrstor (%%rdi)"
96 		     : : "D" (xbuf), "a" (rfbm_lo), "d" (rfbm_hi));
97 }
98 
xgetbv(uint32_t index)99 static inline uint64_t xgetbv(uint32_t index)
100 {
101 	uint32_t eax, edx;
102 
103 	asm volatile("xgetbv" : "=a" (eax), "=d" (edx) : "c" (index));
104 	return eax + ((uint64_t)edx << 32);
105 }
106 
107 #define CPUID_LEAF_XSTATE		0xd
108 #define CPUID_SUBLEAF_XSTATE_USER	0x0
109 
get_xbuf_size(void)110 static inline uint32_t get_xbuf_size(void)
111 {
112 	uint32_t eax, ebx, ecx, edx;
113 
114 	__cpuid_count(CPUID_LEAF_XSTATE, CPUID_SUBLEAF_XSTATE_USER,
115 		      eax, ebx, ecx, edx);
116 
117 	/*
118 	 * EBX enumerates the size (in bytes) required by the XSAVE
119 	 * instruction for an XSAVE area containing all the user state
120 	 * components corresponding to bits currently set in XCR0.
121 	 */
122 	return ebx;
123 }
124 
125 struct xstate_info {
126 	const char *name;
127 	uint32_t num;
128 	uint32_t mask;
129 	uint32_t xbuf_offset;
130 	uint32_t size;
131 };
132 
get_xstate_info(uint32_t xfeature_num)133 static inline struct xstate_info get_xstate_info(uint32_t xfeature_num)
134 {
135 	struct xstate_info xstate = { };
136 	uint32_t eax, ebx, ecx, edx;
137 
138 	if (xfeature_num >= XFEATURE_MAX) {
139 		ksft_print_msg("unknown state\n");
140 		return xstate;
141 	}
142 
143 	xstate.name = xfeature_names[xfeature_num];
144 	xstate.num  = xfeature_num;
145 	xstate.mask = 1 << xfeature_num;
146 
147 	__cpuid_count(CPUID_LEAF_XSTATE, xfeature_num,
148 		      eax, ebx, ecx, edx);
149 	xstate.size        = eax;
150 	xstate.xbuf_offset = ebx;
151 	return xstate;
152 }
153 
alloc_xbuf(void)154 static inline struct xsave_buffer *alloc_xbuf(void)
155 {
156 	uint32_t xbuf_size = get_xbuf_size();
157 
158 	/* XSAVE buffer should be 64B-aligned. */
159 	return aligned_alloc(64, xbuf_size);
160 }
161 
clear_xstate_header(struct xsave_buffer * xbuf)162 static inline void clear_xstate_header(struct xsave_buffer *xbuf)
163 {
164 	memset(&xbuf->header, 0, sizeof(xbuf->header));
165 }
166 
set_xstatebv(struct xsave_buffer * xbuf,uint64_t bv)167 static inline void set_xstatebv(struct xsave_buffer *xbuf, uint64_t bv)
168 {
169 	/* XSTATE_BV is at the beginning of the header: */
170 	*(uint64_t *)(&xbuf->header) = bv;
171 }
172 
get_xstatebv(struct xsave_buffer * xbuf)173 static inline uint64_t get_xstatebv(struct xsave_buffer *xbuf)
174 {
175 	return *(uint64_t *)(&xbuf->header);
176 }
177 
178 /* See 'struct _fpx_sw_bytes' at sigcontext.h */
179 #define SW_BYTES_OFFSET		464
180 /* N.B. The struct's field name varies so read from the offset. */
181 #define SW_BYTES_BV_OFFSET	(SW_BYTES_OFFSET + 8)
182 
get_fpx_sw_bytes(void * xbuf)183 static inline struct _fpx_sw_bytes *get_fpx_sw_bytes(void *xbuf)
184 {
185 	return xbuf + SW_BYTES_OFFSET;
186 }
187 
get_fpx_sw_bytes_features(void * buffer)188 static inline uint64_t get_fpx_sw_bytes_features(void *buffer)
189 {
190 	return *(uint64_t *)(buffer + SW_BYTES_BV_OFFSET);
191 }
192 
set_fpx_sw_bytes_features(void * buffer,uint64_t features)193 static inline void set_fpx_sw_bytes_features(void *buffer, uint64_t features)
194 {
195 	*(uint64_t *)(buffer + SW_BYTES_BV_OFFSET) = features;
196 }
197 
set_rand_data(struct xstate_info * xstate,struct xsave_buffer * xbuf)198 static inline void set_rand_data(struct xstate_info *xstate, struct xsave_buffer *xbuf)
199 {
200 	int *ptr = (int *)&xbuf->bytes[xstate->xbuf_offset];
201 	int data, i;
202 
203 	/*
204 	 * Ensure that 'data' is never 0.  This ensures that
205 	 * the registers are never in their initial configuration
206 	 * and thus never tracked as being in the init state.
207 	 */
208 	data = rand() | 1;
209 
210 	for (i = 0; i < xstate->size / sizeof(int); i++, ptr++)
211 		*ptr = data;
212 }
213 
214 /* Testing kernel's context switching and ABI support for the xstate. */
215 void test_xstate(uint32_t feature_num);
216 
217 #endif /* __SELFTESTS_X86_XSTATE_H */
218