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