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 (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #pragma ident   "%Z%%M% %I%     %E% SMI"
  27 
  28 #include <sys/types.h>
  29 #include <sys/errno.h>
  30 #include <sys/systm.h>
  31 #include <sys/atomic.h>
  32 #include <sys/kmem.h>
  33 #include <sys/machpcb.h>
  34 #include <sys/utrap.h>
  35 #include <sys/model.h>
  36 
  37 int
  38 install_utrap(utrap_entry_t type, utrap_handler_t new_handler,
  39         utrap_handler_t *old_handlerp)
  40 {
  41         struct proc *p = curthread->t_procp;
  42         utrap_handler_t *ov, *nv, *pv, *sv, *tmp;
  43         caddr32_t nv32;
  44         int idx;
  45 
  46         /*
  47          * Check trap number.
  48          */
  49         switch (type) {
  50         case UTRAP_V8P_FP_DISABLED:
  51 #ifdef SF_ERRATA_30 /* call causes fp-disabled */
  52                 {
  53                 extern int spitfire_call_bug;
  54 
  55                 if (spitfire_call_bug)
  56                         return ((int)set_errno(ENOSYS));
  57                 }
  58 #endif /* SF_ERRATA_30 */
  59                 idx = UTRAP_V8P_FP_DISABLED;
  60                 break;
  61         case UTRAP_V8P_MEM_ADDRESS_NOT_ALIGNED:
  62                 idx = UTRAP_V8P_MEM_ADDRESS_NOT_ALIGNED;
  63                 break;
  64         default:
  65                 return ((int)set_errno(EINVAL));
  66         }
  67         if (get_udatamodel() == DATAMODEL_LP64)
  68                 return ((int)set_errno(EINVAL));
  69 
  70         /*
  71          * Be sure handler address is word aligned.  The uintptr_t casts are
  72          * there to prevent warnings when using a certain compiler, and the
  73          * temporary 32 bit variable is intended to ensure proper code
  74          * generation and avoid a messy quadruple cast.
  75          */
  76         nv32 = (caddr32_t)(uintptr_t)new_handler;
  77         nv = (utrap_handler_t *)(uintptr_t)nv32;
  78         if (nv != UTRAP_UTH_NOCHANGE) {
  79                 if (((uintptr_t)nv) & 0x3)
  80                         return ((int)set_errno(EINVAL));
  81         }
  82         /*
  83          * Allocate proc space for saving the addresses to these user
  84          * trap handlers, which must later be freed. Use casptr to
  85          * do this atomically.
  86          */
  87         if (p->p_utraps == NULL) {
  88                 pv = sv = kmem_zalloc((UT_PRECISE_MAXTRAPS+1) *
  89                     sizeof (utrap_handler_t *), KM_SLEEP);
  90                 tmp = casptr(&p->p_utraps, NULL, sv);
  91                 if (tmp != NULL) {
  92                         kmem_free(pv, (UT_PRECISE_MAXTRAPS+1) *
  93                             sizeof (utrap_handler_t *));
  94                 }
  95         }
  96         ASSERT(p->p_utraps != NULL);
  97 
  98         /*
  99          * Use casptr to atomically install the handler.
 100          */
 101         ov = p->p_utraps[idx];
 102         if (new_handler != (utrap_handler_t)UTRAP_UTH_NOCHANGE) {
 103                 for (;;) {
 104                         tmp = casptr(&p->p_utraps[idx], ov, nv);
 105                         if (ov == tmp)
 106                                 break;
 107                         ov = tmp;
 108                 }
 109         }
 110         if (old_handlerp != NULL) {
 111                 if (suword32(old_handlerp, (uint32_t)(uintptr_t)ov) == -1)
 112                         return ((int)set_errno(EINVAL));
 113         }
 114         return (0);
 115 }
 116 
 117 void
 118 utrap_dup(struct proc *pp, struct proc *cp)
 119 {
 120         if (pp->p_utraps != NULL) {
 121                 cp->p_utraps = kmem_alloc((UT_PRECISE_MAXTRAPS+1) *
 122                     sizeof (utrap_handler_t *), KM_SLEEP);
 123                 bcopy(pp->p_utraps, cp->p_utraps,
 124                     (UT_PRECISE_MAXTRAPS+1) * sizeof (utrap_handler_t *));
 125         } else {
 126                 cp->p_utraps = NULL;
 127         }
 128 }
 129 
 130 void
 131 utrap_free(struct proc *p)
 132 {
 133         /* Free any kmem_alloc'ed space for user trap handlers. */
 134         if (p->p_utraps != NULL) {
 135                 kmem_free(p->p_utraps, (UT_PRECISE_MAXTRAPS+1) *
 136                     sizeof (utrap_handler_t *));
 137                 p->p_utraps = NULL;
 138         }
 139 }
 140 
 141 /*
 142  * The code below supports the set of user traps which are required and
 143  * "must be provided by all ABI-conforming implementations", according to
 144  * 3.3.3 User Traps of the SPARC V9 ABI SUPPLEMENT, Delta Document 1.38.
 145  * There is only 1 deferred trap in Ultra I&II, the asynchronous error
 146  * traps, which are not required, so the deferred args are not used.
 147  */
 148 /*ARGSUSED*/
 149 int
 150 sparc_utrap_install(utrap_entry_t type,
 151         utrap_handler_t new_precise, utrap_handler_t new_deferred,
 152         utrap_handler_t *old_precise, utrap_handler_t *old_deferred)
 153 {
 154         struct proc *p = curthread->t_procp;
 155         utrap_handler_t *ov, *nvp, *pv, *sv, *tmp;
 156         int idx;
 157 
 158         /*
 159          * Check trap number.
 160          */
 161         switch (type) {
 162         case UT_ILLTRAP_INSTRUCTION:
 163                 idx = UT_ILLTRAP_INSTRUCTION;
 164                 break;
 165         case UT_FP_DISABLED:
 166 #ifdef SF_ERRATA_30 /* call causes fp-disabled */
 167                 {
 168                 extern int spitfire_call_bug;
 169 
 170                 if (spitfire_call_bug)
 171                         return ((int)set_errno(ENOSYS));
 172                 }
 173 #endif /* SF_ERRATA_30 */
 174                 idx = UT_FP_DISABLED;
 175                 break;
 176         case UT_FP_EXCEPTION_IEEE_754:
 177                 idx = UT_FP_EXCEPTION_IEEE_754;
 178                 break;
 179         case UT_TAG_OVERFLOW:
 180                 idx = UT_TAG_OVERFLOW;
 181                 break;
 182         case UT_DIVISION_BY_ZERO:
 183                 idx = UT_DIVISION_BY_ZERO;
 184                 break;
 185         case UT_MEM_ADDRESS_NOT_ALIGNED:
 186                 idx = UT_MEM_ADDRESS_NOT_ALIGNED;
 187                 break;
 188         case UT_PRIVILEGED_ACTION:
 189                 idx = UT_PRIVILEGED_ACTION;
 190                 break;
 191         case UT_TRAP_INSTRUCTION_16:
 192         case UT_TRAP_INSTRUCTION_17:
 193         case UT_TRAP_INSTRUCTION_18:
 194         case UT_TRAP_INSTRUCTION_19:
 195         case UT_TRAP_INSTRUCTION_20:
 196         case UT_TRAP_INSTRUCTION_21:
 197         case UT_TRAP_INSTRUCTION_22:
 198         case UT_TRAP_INSTRUCTION_23:
 199         case UT_TRAP_INSTRUCTION_24:
 200         case UT_TRAP_INSTRUCTION_25:
 201         case UT_TRAP_INSTRUCTION_26:
 202         case UT_TRAP_INSTRUCTION_27:
 203         case UT_TRAP_INSTRUCTION_28:
 204         case UT_TRAP_INSTRUCTION_29:
 205         case UT_TRAP_INSTRUCTION_30:
 206         case UT_TRAP_INSTRUCTION_31:
 207                 idx = type;
 208                 break;
 209         default:
 210                 return ((int)set_errno(EINVAL));
 211         }
 212 
 213         if (get_udatamodel() == DATAMODEL_ILP32)
 214                 return ((int)set_errno(EINVAL));
 215 
 216         /*
 217          * Be sure handler address is word aligned.
 218          * There are no deferred traps, so ignore them.
 219          */
 220         nvp = (utrap_handler_t *)new_precise;
 221         if (nvp != UTRAP_UTH_NOCHANGE) {
 222                 if (((uintptr_t)nvp) & 0x3)
 223                         return ((int)set_errno(EINVAL));
 224         }
 225 
 226         /*
 227          * Allocate proc space for saving the addresses to these user
 228          * trap handlers, which must later be freed. Use casptr to
 229          * do this atomically.
 230          */
 231         if (p->p_utraps == NULL) {
 232                 pv = sv = kmem_zalloc((UT_PRECISE_MAXTRAPS+1) *
 233                     sizeof (utrap_handler_t *), KM_SLEEP);
 234                 tmp = casptr(&p->p_utraps, NULL, sv);
 235                 if (tmp != NULL) {
 236                         kmem_free(pv, (UT_PRECISE_MAXTRAPS+1) *
 237                             sizeof (utrap_handler_t *));
 238                 }
 239         }
 240         ASSERT(p->p_utraps != NULL);
 241 
 242         /*
 243          * Use casptr to atomically install the handlers.
 244          */
 245         ov = p->p_utraps[idx];
 246         if (new_precise != (utrap_handler_t)UTH_NOCHANGE) {
 247                 for (;;) {
 248                         tmp = casptr(&p->p_utraps[idx], ov, nvp);
 249                         if (ov == tmp)
 250                                 break;
 251                         ov = tmp;
 252                 }
 253         }
 254         if (old_precise != NULL) {
 255                 if (suword64(old_precise, (uint64_t)ov) == -1)
 256                         return ((int)set_errno(EINVAL));
 257         }
 258         return (0);
 259 }