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 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 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 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 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 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 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 162 static inline void clear_xstate_header(struct xsave_buffer *xbuf) 163 { 164 memset(&xbuf->header, 0, sizeof(xbuf->header)); 165 } 166 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 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 183 static inline struct _fpx_sw_bytes *get_fpx_sw_bytes(void *xbuf) 184 { 185 return xbuf + SW_BYTES_OFFSET; 186 } 187 188 static inline uint64_t get_fpx_sw_bytes_features(void *buffer) 189 { 190 return *(uint64_t *)(buffer + SW_BYTES_BV_OFFSET); 191 } 192 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 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