1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License, Version 1.0 only
   6  * (the "License").  You may not use this file except in compliance
   7  * with the License.
   8  *
   9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10  * or http://www.opensolaris.org/os/licensing.
  11  * See the License for the specific language governing permissions
  12  * and limitations under the License.
  13  *
  14  * When distributing Covered Code, include this CDDL HEADER in each
  15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16  * If applicable, add the following below this CDDL HEADER, with the
  17  * fields enclosed by brackets "[]" replaced with your own identifying
  18  * information: Portions Copyright [yyyy] [name of copyright owner]
  19  *
  20  * CDDL HEADER END
  21  */
  22 /*
  23  * Copyright 1994-1998,2003 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*
  28  * Copyright 2013 David Hoeppner.  All rights reserved.
  29  */
  30 
  31 #include <sys/types.h>
  32 #include <sys/t_lock.h>
  33 #include <sys/klwp.h>
  34 #include <sys/proc.h>
  35 #include <sys/ucontext.h>
  36 #include <sys/procfs.h>
  37 #include <sys/privregs.h>
  38 #include <sys/fp.h>
  39 #include <sys/cpuvar.h>
  40 #include <sys/cmn_err.h>
  41 #include <sys/disp.h>
  42 #include <sys/systm.h>
  43 #include <sys/archsystm.h>
  44 #include <sys/note.h>
  45 
  46 /*
  47  * Clear the struct ucontext extra register state pointer.
  48  */
  49 void
  50 xregs_clrptr(klwp_id_t lwp, ucontext_t *uc)
  51 {
  52         uc->uc_xrs.xrs_id = 0;
  53         uc->uc_xrs.xrs_ptr = NULL;
  54 }
  55 
  56 /*
  57  * Indicate whether or not an extra register state
  58  * pointer is associated with a struct ucontext.
  59  */
  60 int
  61 xregs_hasptr(klwp_id_t lwp, ucontext_t *uc)
  62 {
  63         _NOTE(ARGUNUSED(lwp));
  64 
  65         return (uc->uc_xrs.xrs_id == XRS_ID);
  66 }
  67 
  68 /*
  69  * Get the struct ucontext extra register state pointer field.
  70  */
  71 caddr_t
  72 xregs_getptr(klwp_id_t lwp, ucontext_t *uc)
  73 {
  74         _NOTE(ARGUNUSED(lwp));
  75 
  76         if (uc->uc_xrs.xrs_id == XRS_ID)
  77                 return (uc->uc_xrs.xrs_ptr);
  78 
  79         return (NULL);
  80 }
  81 
  82 /*
  83  * Set the struct ucontext extra register state pointer field.
  84  */
  85 void
  86 xregs_setptr(klwp_id_t lwp, ucontext_t *uc, caddr_t xrp)
  87 {
  88         _NOTE(ARGUNUSED(lwp));
  89 
  90         uc->uc_xrs.xrs_id = XRS_ID;
  91         uc->uc_xrs.xrs_ptr = xrp;
  92 }
  93 
  94 #if defined(_SYSCALL32_IMPL)
  95 
  96 void
  97 xregs_clrptr32(klwp_id_t lwp, ucontext32_t *uc)
  98 {
  99         _NOTE(ARGUNUSED(lwp));
 100 
 101         uc->uc_xrs.xrs_id = 0;
 102         uc->uc_xrs.xrs_ptr = NULL;
 103 }
 104 
 105 int
 106 xregs_hasptr32(klwp_id_t lwp, ucontext32_t *uc)
 107 {
 108         _NOTE(ARGUNUSED(lwp));
 109 
 110         return (uc->uc_xrs.xrs_id == XRS_ID);
 111 }
 112 
 113 caddr32_t
 114 xregs_getptr32(klwp_id_t lwp, ucontext32_t *uc)
 115 {
 116         _NOTE(ARGUNUSED(lwp));
 117 
 118         if (uc->uc_xrs.xrs_id == XRS_ID)
 119                 return (uc->uc_xrs.xrs_ptr);
 120 
 121         return (0);
 122 }
 123 
 124 void
 125 xregs_setptr32(klwp_id_t lwp, ucontext32_t *uc, caddr32_t xrp)
 126 {
 127         _NOTE(ARGUNUSED(lwp));
 128 
 129         uc->uc_xrs.xrs_id = XRS_ID;
 130         uc->uc_xrs.xrs_ptr = xrp;
 131 }
 132 
 133 #endif  /* _SYSCALL32_IMPL */
 134 
 135 /*
 136  * Fill in the extra register state area specified with the
 137  * specified lwp's floating point extra register state information.
 138  */
 139 void
 140 xregs_getfpregs(klwp_id_t lwp, caddr_t xrp)
 141 {
 142         prxregset_t *xregs = (prxregset_t *)xrp;
 143         kfpu_t *fp = lwptofpu(lwp);
 144 
 145         if (xregs == NULL)
 146                 return;
 147 
 148         kpreempt_disable();
 149 
 150         xregs->pr_type = XR_TYPE_XSAVE;
 151 
 152         kpreempt_enable();
 153 }
 154 
 155 /*
 156  * Fill in the extra register state area specified with
 157  * the specified kwp's extra register state information.
 158  */
 159 void
 160 xregs_get(klwp_id_t lwp, caddr_t xrp)
 161 {
 162 
 163         if (xrp != NULL) {
 164                 bzero(xrp, sizeof (prxregset_t));
 165                 xregs_getfpregs(lwp, xrp);
 166         }
 167 }
 168 
 169 /*
 170  * Set the specified lwp's floating-point extra
 171  * register state based on the specified input.
 172  */
 173 void
 174 xregs_setfpregs(klwp_id_t lwp, caddr_t xrp)
 175 {
 176         prxregset_t *xregs = (prxregset_t *)xrp;
 177         kfpu_t *fp = lwptofpu(lwp);
 178         fpu_ctx_t *fpu = &lwp->lwp_pcb.pcb_fpu;
 179 
 180         if (xregs == NULL)
 181                 return;
 182 
 183 #if defined(DEBUG)
 184         if (xregs->pr_type != XR_TYPE_XSAVE) {
 185                 cmn_err(CE_WARN,
 186                     "xregs_setfpregs: pr_type is %d and should be %d",
 187                     xregs->pr_type, XR_TYPE_XSAVE);
 188         }
 189 #endif  /* DEBUG */
 190 
 191         if (fpu->fpu_flags & FPU_EN) {
 192                 kpreempt_disable();
 193                 (void) kcopy(&xregs->pr_un.pr_xsave.pr_ymm,
 194                     &fp->kfpu_u.kfpu_xs.xs_ymm,
 195                     sizeof (&xregs->pr_un.pr_xsave.pr_ymm));
 196 
 197                 /*
 198                  * If not the current lwp then resume() will handle it.
 199                  */
 200                 if (lwp != ttolwp(curthread)) {
 201                         /* Force resume to reload fp regs */
 202                         kpreempt_enable();
 203                         return;
 204                 }
 205 
 206                 if (fpu_exists) {
 207                 }
 208 
 209                 kpreempt_enable();
 210         }
 211 }
 212 
 213 /*
 214  * Set the specified lwp's extra register
 215  * state based on the specified input.
 216  */
 217 void
 218 xregs_set(klwp_id_t lwp, caddr_t xrp)
 219 {
 220         if (xrp != NULL) {
 221                 xregs_setfpregs(lwp, xrp);
 222         }
 223 }
 224 
 225 /*
 226  * Return the size of the extra register state.
 227  */
 228 int
 229 xregs_getsize(proc_t *p)
 230 {
 231         return (sizeof (prxregset_t));
 232 }