xref: /illumos-gate/usr/src/uts/sparc/v9/syscall/install_utrap.c (revision 75d94465dbafa487b716482dc36d5150a4ec9853)
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
install_utrap(utrap_entry_t type,utrap_handler_t new_handler,utrap_handler_t * old_handlerp)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
utrap_dup(struct proc * pp,struct proc * cp)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
utrap_free(struct proc * p)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
sparc_utrap_install(utrap_entry_t type,utrap_handler_t new_precise,utrap_handler_t new_deferred,utrap_handler_t * old_precise,utrap_handler_t * old_deferred)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