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 } 258