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 #endif  /* !_ASM */
 181 
 182 #ifdef __cplusplus
 183 }
 184 #endif
 185 
 186 #endif /* _XSAVE_UTIL_H */