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