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
37int
38install_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
117void
118utrap_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
130void
131utrap_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*/
149int
150sparc_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