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