10f6d91a3SChang S. Bae // SPDX-License-Identifier: GPL-2.0-only 20f6d91a3SChang S. Bae #ifndef __SELFTESTS_X86_XSTATE_H 30f6d91a3SChang S. Bae #define __SELFTESTS_X86_XSTATE_H 40f6d91a3SChang S. Bae 50f6d91a3SChang S. Bae #include <stdint.h> 60f6d91a3SChang S. Bae 70f6d91a3SChang S. Bae #include "../kselftest.h" 80f6d91a3SChang S. Bae 90f6d91a3SChang S. Bae #define XSAVE_HDR_OFFSET 512 100f6d91a3SChang S. Bae #define XSAVE_HDR_SIZE 64 110f6d91a3SChang S. Bae 123fcb4d61SChang S. Bae /* 133fcb4d61SChang S. Bae * List of XSAVE features Linux knows about. Copied from 143fcb4d61SChang S. Bae * arch/x86/include/asm/fpu/types.h 153fcb4d61SChang S. Bae */ 163fcb4d61SChang S. Bae enum xfeature { 173fcb4d61SChang S. Bae XFEATURE_FP, 183fcb4d61SChang S. Bae XFEATURE_SSE, 193fcb4d61SChang S. Bae XFEATURE_YMM, 203fcb4d61SChang S. Bae XFEATURE_BNDREGS, 213fcb4d61SChang S. Bae XFEATURE_BNDCSR, 223fcb4d61SChang S. Bae XFEATURE_OPMASK, 233fcb4d61SChang S. Bae XFEATURE_ZMM_Hi256, 243fcb4d61SChang S. Bae XFEATURE_Hi16_ZMM, 253fcb4d61SChang S. Bae XFEATURE_PT_UNIMPLEMENTED_SO_FAR, 263fcb4d61SChang S. Bae XFEATURE_PKRU, 273fcb4d61SChang S. Bae XFEATURE_PASID, 283fcb4d61SChang S. Bae XFEATURE_CET_USER, 293fcb4d61SChang S. Bae XFEATURE_CET_KERNEL_UNUSED, 303fcb4d61SChang S. Bae XFEATURE_RSRVD_COMP_13, 313fcb4d61SChang S. Bae XFEATURE_RSRVD_COMP_14, 323fcb4d61SChang S. Bae XFEATURE_LBR, 333fcb4d61SChang S. Bae XFEATURE_RSRVD_COMP_16, 343fcb4d61SChang S. Bae XFEATURE_XTILECFG, 353fcb4d61SChang S. Bae XFEATURE_XTILEDATA, 363fcb4d61SChang S. Bae 373fcb4d61SChang S. Bae XFEATURE_MAX, 383fcb4d61SChang S. Bae }; 393fcb4d61SChang S. Bae 403fcb4d61SChang S. Bae /* Copied from arch/x86/kernel/fpu/xstate.c */ 413fcb4d61SChang S. Bae static const char *xfeature_names[] = 423fcb4d61SChang S. Bae { 433fcb4d61SChang S. Bae "x87 floating point registers", 443fcb4d61SChang S. Bae "SSE registers", 453fcb4d61SChang S. Bae "AVX registers", 463fcb4d61SChang S. Bae "MPX bounds registers", 473fcb4d61SChang S. Bae "MPX CSR", 483fcb4d61SChang S. Bae "AVX-512 opmask", 493fcb4d61SChang S. Bae "AVX-512 Hi256", 503fcb4d61SChang S. Bae "AVX-512 ZMM_Hi256", 513fcb4d61SChang S. Bae "Processor Trace (unused)", 523fcb4d61SChang S. Bae "Protection Keys User registers", 533fcb4d61SChang S. Bae "PASID state", 543fcb4d61SChang S. Bae "Control-flow User registers", 553fcb4d61SChang S. Bae "Control-flow Kernel registers (unused)", 563fcb4d61SChang S. Bae "unknown xstate feature", 573fcb4d61SChang S. Bae "unknown xstate feature", 583fcb4d61SChang S. Bae "unknown xstate feature", 593fcb4d61SChang S. Bae "unknown xstate feature", 603fcb4d61SChang S. Bae "AMX Tile config", 613fcb4d61SChang S. Bae "AMX Tile data", 623fcb4d61SChang S. Bae "unknown xstate feature", 633fcb4d61SChang S. Bae }; 643fcb4d61SChang S. Bae 650f6d91a3SChang S. Bae struct xsave_buffer { 660f6d91a3SChang S. Bae union { 670f6d91a3SChang S. Bae struct { 680f6d91a3SChang S. Bae char legacy[XSAVE_HDR_OFFSET]; 690f6d91a3SChang S. Bae char header[XSAVE_HDR_SIZE]; 700f6d91a3SChang S. Bae char extended[0]; 710f6d91a3SChang S. Bae }; 720f6d91a3SChang S. Bae char bytes[0]; 730f6d91a3SChang S. Bae }; 740f6d91a3SChang S. Bae }; 750f6d91a3SChang S. Bae 760f6d91a3SChang S. Bae static inline void xsave(struct xsave_buffer *xbuf, uint64_t rfbm) 770f6d91a3SChang S. Bae { 780f6d91a3SChang S. Bae uint32_t rfbm_hi = rfbm >> 32; 790f6d91a3SChang S. Bae uint32_t rfbm_lo = rfbm; 800f6d91a3SChang S. Bae 810f6d91a3SChang S. Bae asm volatile("xsave (%%rdi)" 820f6d91a3SChang S. Bae : : "D" (xbuf), "a" (rfbm_lo), "d" (rfbm_hi) 830f6d91a3SChang S. Bae : "memory"); 840f6d91a3SChang S. Bae } 850f6d91a3SChang S. Bae 860f6d91a3SChang S. Bae static inline void xrstor(struct xsave_buffer *xbuf, uint64_t rfbm) 870f6d91a3SChang S. Bae { 880f6d91a3SChang S. Bae uint32_t rfbm_hi = rfbm >> 32; 890f6d91a3SChang S. Bae uint32_t rfbm_lo = rfbm; 900f6d91a3SChang S. Bae 910f6d91a3SChang S. Bae asm volatile("xrstor (%%rdi)" 920f6d91a3SChang S. Bae : : "D" (xbuf), "a" (rfbm_lo), "d" (rfbm_hi)); 930f6d91a3SChang S. Bae } 940f6d91a3SChang S. Bae 950f6d91a3SChang S. Bae #define CPUID_LEAF_XSTATE 0xd 960f6d91a3SChang S. Bae #define CPUID_SUBLEAF_XSTATE_USER 0x0 970f6d91a3SChang S. Bae 980f6d91a3SChang S. Bae static inline uint32_t get_xbuf_size(void) 990f6d91a3SChang S. Bae { 1000f6d91a3SChang S. Bae uint32_t eax, ebx, ecx, edx; 1010f6d91a3SChang S. Bae 1020f6d91a3SChang S. Bae __cpuid_count(CPUID_LEAF_XSTATE, CPUID_SUBLEAF_XSTATE_USER, 1030f6d91a3SChang S. Bae eax, ebx, ecx, edx); 1040f6d91a3SChang S. Bae 1050f6d91a3SChang S. Bae /* 1060f6d91a3SChang S. Bae * EBX enumerates the size (in bytes) required by the XSAVE 1070f6d91a3SChang S. Bae * instruction for an XSAVE area containing all the user state 1080f6d91a3SChang S. Bae * components corresponding to bits currently set in XCR0. 1090f6d91a3SChang S. Bae */ 1100f6d91a3SChang S. Bae return ebx; 1110f6d91a3SChang S. Bae } 1120f6d91a3SChang S. Bae 1130f6d91a3SChang S. Bae struct xstate_info { 1143fcb4d61SChang S. Bae const char *name; 1150f6d91a3SChang S. Bae uint32_t num; 1160f6d91a3SChang S. Bae uint32_t mask; 1170f6d91a3SChang S. Bae uint32_t xbuf_offset; 1180f6d91a3SChang S. Bae uint32_t size; 1190f6d91a3SChang S. Bae }; 1200f6d91a3SChang S. Bae 1210f6d91a3SChang S. Bae static inline struct xstate_info get_xstate_info(uint32_t xfeature_num) 1220f6d91a3SChang S. Bae { 1230f6d91a3SChang S. Bae struct xstate_info xstate = { }; 1240f6d91a3SChang S. Bae uint32_t eax, ebx, ecx, edx; 1250f6d91a3SChang S. Bae 1263fcb4d61SChang S. Bae if (xfeature_num >= XFEATURE_MAX) { 1273fcb4d61SChang S. Bae ksft_print_msg("unknown state\n"); 1283fcb4d61SChang S. Bae return xstate; 1293fcb4d61SChang S. Bae } 1303fcb4d61SChang S. Bae 1313fcb4d61SChang S. Bae xstate.name = xfeature_names[xfeature_num]; 1320f6d91a3SChang S. Bae xstate.num = xfeature_num; 1330f6d91a3SChang S. Bae xstate.mask = 1 << xfeature_num; 1340f6d91a3SChang S. Bae 1350f6d91a3SChang S. Bae __cpuid_count(CPUID_LEAF_XSTATE, xfeature_num, 1360f6d91a3SChang S. Bae eax, ebx, ecx, edx); 1370f6d91a3SChang S. Bae xstate.size = eax; 1380f6d91a3SChang S. Bae xstate.xbuf_offset = ebx; 1390f6d91a3SChang S. Bae return xstate; 1400f6d91a3SChang S. Bae } 1410f6d91a3SChang S. Bae 1420f6d91a3SChang S. Bae static inline struct xsave_buffer *alloc_xbuf(void) 1430f6d91a3SChang S. Bae { 1440f6d91a3SChang S. Bae uint32_t xbuf_size = get_xbuf_size(); 1450f6d91a3SChang S. Bae 1460f6d91a3SChang S. Bae /* XSAVE buffer should be 64B-aligned. */ 1470f6d91a3SChang S. Bae return aligned_alloc(64, xbuf_size); 1480f6d91a3SChang S. Bae } 1490f6d91a3SChang S. Bae 1500f6d91a3SChang S. Bae static inline void clear_xstate_header(struct xsave_buffer *xbuf) 1510f6d91a3SChang S. Bae { 1520f6d91a3SChang S. Bae memset(&xbuf->header, 0, sizeof(xbuf->header)); 1530f6d91a3SChang S. Bae } 1540f6d91a3SChang S. Bae 1550f6d91a3SChang S. Bae static inline void set_xstatebv(struct xsave_buffer *xbuf, uint64_t bv) 1560f6d91a3SChang S. Bae { 1570f6d91a3SChang S. Bae /* XSTATE_BV is at the beginning of the header: */ 1580f6d91a3SChang S. Bae *(uint64_t *)(&xbuf->header) = bv; 1590f6d91a3SChang S. Bae } 1600f6d91a3SChang S. Bae 1610f6d91a3SChang S. Bae /* See 'struct _fpx_sw_bytes' at sigcontext.h */ 1620f6d91a3SChang S. Bae #define SW_BYTES_OFFSET 464 1630f6d91a3SChang S. Bae /* N.B. The struct's field name varies so read from the offset. */ 1640f6d91a3SChang S. Bae #define SW_BYTES_BV_OFFSET (SW_BYTES_OFFSET + 8) 1650f6d91a3SChang S. Bae 1660f6d91a3SChang S. Bae static inline struct _fpx_sw_bytes *get_fpx_sw_bytes(void *xbuf) 1670f6d91a3SChang S. Bae { 1680f6d91a3SChang S. Bae return xbuf + SW_BYTES_OFFSET; 1690f6d91a3SChang S. Bae } 1700f6d91a3SChang S. Bae 1710f6d91a3SChang S. Bae static inline uint64_t get_fpx_sw_bytes_features(void *buffer) 1720f6d91a3SChang S. Bae { 1730f6d91a3SChang S. Bae return *(uint64_t *)(buffer + SW_BYTES_BV_OFFSET); 1740f6d91a3SChang S. Bae } 1750f6d91a3SChang S. Bae 1760f6d91a3SChang S. Bae static inline void set_rand_data(struct xstate_info *xstate, struct xsave_buffer *xbuf) 1770f6d91a3SChang S. Bae { 1780f6d91a3SChang S. Bae int *ptr = (int *)&xbuf->bytes[xstate->xbuf_offset]; 1790f6d91a3SChang S. Bae int data, i; 1800f6d91a3SChang S. Bae 1810f6d91a3SChang S. Bae /* 1820f6d91a3SChang S. Bae * Ensure that 'data' is never 0. This ensures that 1830f6d91a3SChang S. Bae * the registers are never in their initial configuration 1840f6d91a3SChang S. Bae * and thus never tracked as being in the init state. 1850f6d91a3SChang S. Bae */ 1860f6d91a3SChang S. Bae data = rand() | 1; 1870f6d91a3SChang S. Bae 1880f6d91a3SChang S. Bae for (i = 0; i < xstate->size / sizeof(int); i++, ptr++) 1890f6d91a3SChang S. Bae *ptr = data; 1900f6d91a3SChang S. Bae } 1910f6d91a3SChang S. Bae 192*10d8a204SChang S. Bae /* Testing kernel's context switching and ABI support for the xstate. */ 193*10d8a204SChang S. Bae void test_xstate(uint32_t feature_num); 19440f6852eSChang S. Bae 1950f6d91a3SChang S. Bae #endif /* __SELFTESTS_X86_XSTATE_H */ 196