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