xref: /netbsd-src/sys/arch/sh3/sh3/syscall.c (revision fad4c9f71477ae11cea2ee75ec82151ac770a534)
1 /*	$NetBSD: syscall.c,v 1.6 2006/03/07 07:21:50 thorpej Exp $	*/
2 
3 /*-
4  * Copyright (c) 2002 The NetBSD Foundation, Inc. All rights reserved.
5  * Copyright (c) 1990 The Regents of the University of California.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * the University of Utah, and William Jolitz.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  *	@(#)trap.c	7.4 (Berkeley) 5/13/91
36  */
37 
38 /*-
39  * Copyright (c) 1995 Charles M. Hannum.  All rights reserved.
40  *
41  * This code is derived from software contributed to Berkeley by
42  * the University of Utah, and William Jolitz.
43  *
44  * Redistribution and use in source and binary forms, with or without
45  * modification, are permitted provided that the following conditions
46  * are met:
47  * 1. Redistributions of source code must retain the above copyright
48  *    notice, this list of conditions and the following disclaimer.
49  * 2. Redistributions in binary form must reproduce the above copyright
50  *    notice, this list of conditions and the following disclaimer in the
51  *    documentation and/or other materials provided with the distribution.
52  * 3. All advertising materials mentioning features or use of this software
53  *    must display the following acknowledgement:
54  *	This product includes software developed by the University of
55  *	California, Berkeley and its contributors.
56  * 4. Neither the name of the University nor the names of its contributors
57  *    may be used to endorse or promote products derived from this software
58  *    without specific prior written permission.
59  *
60  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
61  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
62  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
63  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
64  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
65  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
66  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
67  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
68  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
69  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
70  * SUCH DAMAGE.
71  *
72  *	@(#)trap.c	7.4 (Berkeley) 5/13/91
73  */
74 
75 /*
76  * SH3 Trap and System call handling
77  *
78  * T.Horiuchi 1998.06.8
79  */
80 
81 #include <sys/param.h>
82 #include <sys/systm.h>
83 #include <sys/proc.h>
84 #include <sys/sa.h>
85 #include <sys/savar.h>
86 #include <sys/syscall.h>
87 
88 #include <sh3/userret.h>
89 
90 #include <uvm/uvm_extern.h>
91 
92 
93 static void syscall_plain(struct lwp *, struct trapframe *);
94 static void syscall_fancy(struct lwp *, struct trapframe *);
95 
96 
97 void
98 syscall_intern(struct proc *p)
99 {
100 
101 	if (trace_is_enabled(p))
102 		p->p_md.md_syscall = syscall_fancy;
103 	else
104 		p->p_md.md_syscall = syscall_plain;
105 }
106 
107 
108 /*
109  * System call request from POSIX system call gate interface to kernel.
110  *	l  ... curlwp when trap occurs.
111  *	tf ... full user context.
112  */
113 static void
114 syscall_plain(struct lwp *l, struct trapframe *tf)
115 {
116 	struct proc *p = l->l_proc;
117 	caddr_t params;
118 	const struct sysent *callp;
119 	int error, opc, nsys;
120 	size_t argsize;
121 	register_t code, args[8], rval[2], ocode;
122 
123 	uvmexp.syscalls++;
124 
125 	opc = tf->tf_spc;
126 	ocode = code = tf->tf_r0;
127 
128 	nsys = p->p_emul->e_nsysent;
129 	callp = p->p_emul->e_sysent;
130 
131 	params = (caddr_t)tf->tf_r15;
132 
133 	switch (code) {
134 	case SYS_syscall:
135 		/*
136 		 * Code is first argument, followed by actual args.
137 		 */
138 	        code = tf->tf_r4;  /* fuword(params); */
139 		/* params += sizeof(int); */
140 		break;
141 	case SYS___syscall:
142 		/*
143 		 * Like syscall, but code is a quad, so as to maintain
144 		 * quad alignment for the rest of the arguments.
145 		 */
146 		if (callp != sysent)
147 			break;
148 		/* fuword(params + _QUAD_LOWWORD * sizeof(int)); */
149 #if _BYTE_ORDER == BIG_ENDIAN
150 		code = tf->tf_r5;
151 #else
152 		code = tf->tf_r4;
153 #endif
154 		/* params += sizeof(quad_t); */
155 		break;
156 	default:
157 		break;
158 	}
159 	if (code < 0 || code >= nsys)
160 		callp += p->p_emul->e_nosys;		/* illegal */
161 	else
162 		callp += code;
163 	argsize = callp->sy_argsize;
164 
165 	if (ocode == SYS_syscall) {
166 		if (argsize) {
167 			args[0] = tf->tf_r5;
168 			args[1] = tf->tf_r6;
169 			args[2] = tf->tf_r7;
170 			if (argsize > 3 * sizeof(int)) {
171 				argsize -= 3 * sizeof(int);
172 				error = copyin(params, (caddr_t)&args[3],
173 					       argsize);
174 			} else
175 				error = 0;
176 		} else
177 			error = 0;
178 	}
179 	else if (ocode == SYS___syscall) {
180 		if (argsize) {
181 			args[0] = tf->tf_r6;
182 			args[1] = tf->tf_r7;
183 			if (argsize > 2 * sizeof(int)) {
184 				argsize -= 2 * sizeof(int);
185 				error = copyin(params, (caddr_t)&args[2],
186 					       argsize);
187 			} else
188 				error = 0;
189 		} else
190 			error = 0;
191 	} else {
192 		if (argsize) {
193 			args[0] = tf->tf_r4;
194 			args[1] = tf->tf_r5;
195 			args[2] = tf->tf_r6;
196 			args[3] = tf->tf_r7;
197 			if (argsize > 4 * sizeof(int)) {
198 				argsize -= 4 * sizeof(int);
199 				error = copyin(params, (caddr_t)&args[4],
200 					       argsize);
201 			} else
202 				error = 0;
203 		} else
204 			error = 0;
205 	}
206 
207 	if (error)
208 		goto bad;
209 
210 	rval[0] = 0;
211 	rval[1] = tf->tf_r1;
212 	error = (*callp->sy_call)(l, args, rval);
213 
214 	switch (error) {
215 	case 0:
216 		tf->tf_r0 = rval[0];
217 		tf->tf_r1 = rval[1];
218 		tf->tf_ssr |= PSL_TBIT;	/* T bit */
219 
220 		break;
221 	case ERESTART:
222 		/* 2 = TRAPA instruction size */
223 		tf->tf_spc = opc - 2;
224 
225 		break;
226 	case EJUSTRETURN:
227 		/* nothing to do */
228 		break;
229 	default:
230 	bad:
231 		if (p->p_emul->e_errno)
232 			error = p->p_emul->e_errno[error];
233 		tf->tf_r0 = error;
234 		tf->tf_ssr &= ~PSL_TBIT;	/* T bit */
235 
236 		break;
237 	}
238 
239 	userret(l);
240 }
241 
242 
243 /*
244  * Like syscall_plain but with trace_enter/trace_exit.
245  */
246 static void
247 syscall_fancy(struct lwp *l, struct trapframe *tf)
248 {
249 	struct proc *p = l->l_proc;
250 	caddr_t params;
251 	const struct sysent *callp;
252 	int error, opc, nsys;
253 	size_t argsize;
254 	register_t code, args[8], rval[2], ocode;
255 
256 	uvmexp.syscalls++;
257 
258 	opc = tf->tf_spc;
259 	ocode = code = tf->tf_r0;
260 
261 	nsys = p->p_emul->e_nsysent;
262 	callp = p->p_emul->e_sysent;
263 
264 	params = (caddr_t)tf->tf_r15;
265 
266 	switch (code) {
267 	case SYS_syscall:
268 		/*
269 		 * Code is first argument, followed by actual args.
270 		 */
271 	        code = tf->tf_r4;  /* fuword(params); */
272 		/* params += sizeof(int); */
273 		break;
274 	case SYS___syscall:
275 		/*
276 		 * Like syscall, but code is a quad, so as to maintain
277 		 * quad alignment for the rest of the arguments.
278 		 */
279 		if (callp != sysent)
280 			break;
281 		/* fuword(params + _QUAD_LOWWORD * sizeof(int)); */
282 #if _BYTE_ORDER == BIG_ENDIAN
283 		code = tf->tf_r5;
284 #else
285 		code = tf->tf_r4;
286 #endif
287 		/* params += sizeof(quad_t); */
288 		break;
289 	default:
290 		break;
291 	}
292 	if (code < 0 || code >= nsys)
293 		callp += p->p_emul->e_nosys;		/* illegal */
294 	else
295 		callp += code;
296 	argsize = callp->sy_argsize;
297 
298 	if (ocode == SYS_syscall) {
299 		if (argsize) {
300 			args[0] = tf->tf_r5;
301 			args[1] = tf->tf_r6;
302 			args[2] = tf->tf_r7;
303 			if (argsize > 3 * sizeof(int)) {
304 				argsize -= 3 * sizeof(int);
305 				error = copyin(params, (caddr_t)&args[3],
306 					       argsize);
307 			} else
308 				error = 0;
309 		} else
310 			error = 0;
311 	}
312 	else if (ocode == SYS___syscall) {
313 		if (argsize) {
314 			args[0] = tf->tf_r6;
315 			args[1] = tf->tf_r7;
316 			if (argsize > 2 * sizeof(int)) {
317 				argsize -= 2 * sizeof(int);
318 				error = copyin(params, (caddr_t)&args[2],
319 					       argsize);
320 			} else
321 				error = 0;
322 		} else
323 			error = 0;
324 	} else {
325 		if (argsize) {
326 			args[0] = tf->tf_r4;
327 			args[1] = tf->tf_r5;
328 			args[2] = tf->tf_r6;
329 			args[3] = tf->tf_r7;
330 			if (argsize > 4 * sizeof(int)) {
331 				argsize -= 4 * sizeof(int);
332 				error = copyin(params, (caddr_t)&args[4],
333 					       argsize);
334 			} else
335 				error = 0;
336 		} else
337 			error = 0;
338 	}
339 
340 	if (error)
341 		goto bad;
342 
343 	if ((error = trace_enter(l, code, code, NULL, args)) != 0)
344 		goto out;
345 
346 	rval[0] = 0;
347 	rval[1] = tf->tf_r1;
348 	error = (*callp->sy_call)(l, args, rval);
349 out:
350 	switch (error) {
351 	case 0:
352 		tf->tf_r0 = rval[0];
353 		tf->tf_r1 = rval[1];
354 		tf->tf_ssr |= PSL_TBIT;	/* T bit */
355 
356 		break;
357 	case ERESTART:
358 		/* 2 = TRAPA instruction size */
359 		tf->tf_spc = opc - 2;
360 
361 		break;
362 	case EJUSTRETURN:
363 		/* nothing to do */
364 		break;
365 	default:
366 	bad:
367 		if (p->p_emul->e_errno)
368 			error = p->p_emul->e_errno[error];
369 		tf->tf_r0 = error;
370 		tf->tf_ssr &= ~PSL_TBIT;	/* T bit */
371 
372 		break;
373 	}
374 
375 
376 	trace_exit(l, code, args, rval, error);
377 
378 	userret(l);
379 }
380