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