xref: /illumos-gate/usr/src/uts/sparc/v9/syscall/install_utrap.c (revision 445f2479fe3d7435daab18bf2cdc310b86cd6738)
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