xref: /netbsd/sys/arch/sh3/sh3/syscall.c (revision 6550d01e)
1 /*	$NetBSD: syscall.c,v 1.13 2010/12/20 00:25:43 matt 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 "opt_sa.h"
82 
83 #include <sys/param.h>
84 #include <sys/systm.h>
85 #include <sys/proc.h>
86 #include <sys/sa.h>
87 #include <sys/savar.h>
88 #include <sys/syscall.h>
89 #include <sys/syscallvar.h>
90 
91 #include <sh3/userret.h>
92 
93 #include <uvm/uvm_extern.h>
94 
95 
96 static void syscall_plain(struct lwp *, struct trapframe *);
97 static void syscall_fancy(struct lwp *, struct trapframe *);
98 
99 
100 void
101 syscall_intern(struct proc *p)
102 {
103 
104 	if (trace_is_enabled(p))
105 		p->p_md.md_syscall = syscall_fancy;
106 	else
107 		p->p_md.md_syscall = syscall_plain;
108 }
109 
110 
111 /*
112  * System call request from POSIX system call gate interface to kernel.
113  *	l  ... curlwp when trap occurs.
114  *	tf ... full user context.
115  */
116 static void
117 syscall_plain(struct lwp *l, struct trapframe *tf)
118 {
119 	struct proc *p = l->l_proc;
120 	void *params;
121 	const struct sysent *callp;
122 	int error, opc, nsys;
123 	size_t argsize;
124 	register_t code, args[8], rval[2], ocode;
125 
126 	curcpu()->ci_data.cpu_nsyscall++;
127 
128 	opc = tf->tf_spc;
129 	ocode = code = tf->tf_r0;
130 
131 	nsys = p->p_emul->e_nsysent;
132 	callp = p->p_emul->e_sysent;
133 
134 #ifdef KERN_SA
135 	if (__predict_false((l->l_savp)
136             && (l->l_savp->savp_pflags & SAVP_FLAG_DELIVERING)))
137 		l->l_savp->savp_pflags &= ~SAVP_FLAG_DELIVERING;
138 #endif
139 
140 	params = (void *)tf->tf_r15;
141 
142 	switch (code) {
143 	case SYS_syscall:
144 		/*
145 		 * Code is first argument, followed by actual args.
146 		 */
147 	        code = tf->tf_r4;  /* fuword(params); */
148 		/* params += sizeof(int); */
149 		break;
150 	case SYS___syscall:
151 		/*
152 		 * Like syscall, but code is a quad, so as to maintain
153 		 * quad alignment for the rest of the arguments.
154 		 */
155 		if (callp != sysent)
156 			break;
157 		/* fuword(params + _QUAD_LOWWORD * sizeof(int)); */
158 #if _BYTE_ORDER == BIG_ENDIAN
159 		code = tf->tf_r5;
160 #else
161 		code = tf->tf_r4;
162 #endif
163 		/* params += sizeof(quad_t); */
164 		break;
165 	default:
166 		break;
167 	}
168 	if (code < 0 || code >= nsys)
169 		callp += p->p_emul->e_nosys;		/* illegal */
170 	else
171 		callp += code;
172 	argsize = callp->sy_argsize;
173 
174 	if (ocode == SYS_syscall) {
175 		if (argsize) {
176 			args[0] = tf->tf_r5;
177 			args[1] = tf->tf_r6;
178 			args[2] = tf->tf_r7;
179 			if (argsize > 3 * sizeof(int)) {
180 				argsize -= 3 * sizeof(int);
181 				error = copyin(params, (void *)&args[3],
182 					       argsize);
183 			} else
184 				error = 0;
185 		} else
186 			error = 0;
187 	}
188 	else if (ocode == SYS___syscall) {
189 		if (argsize) {
190 			args[0] = tf->tf_r6;
191 			args[1] = tf->tf_r7;
192 			if (argsize > 2 * sizeof(int)) {
193 				argsize -= 2 * sizeof(int);
194 				error = copyin(params, (void *)&args[2],
195 					       argsize);
196 			} else
197 				error = 0;
198 		} else
199 			error = 0;
200 	} else {
201 		if (argsize) {
202 			args[0] = tf->tf_r4;
203 			args[1] = tf->tf_r5;
204 			args[2] = tf->tf_r6;
205 			args[3] = tf->tf_r7;
206 			if (argsize > 4 * sizeof(int)) {
207 				argsize -= 4 * sizeof(int);
208 				error = copyin(params, (void *)&args[4],
209 					       argsize);
210 			} else
211 				error = 0;
212 		} else
213 			error = 0;
214 	}
215 
216 	if (error)
217 		goto bad;
218 
219 	rval[0] = 0;
220 	rval[1] = tf->tf_r1;
221 	error = sy_call(callp, l, args, rval);
222 
223 	switch (error) {
224 	case 0:
225 		tf->tf_r0 = rval[0];
226 		tf->tf_r1 = rval[1];
227 		tf->tf_ssr |= PSL_TBIT;	/* T bit */
228 
229 		break;
230 	case ERESTART:
231 		/* 2 = TRAPA instruction size */
232 		tf->tf_spc = opc - 2;
233 
234 		break;
235 	case EJUSTRETURN:
236 		/* nothing to do */
237 		break;
238 	default:
239 	bad:
240 		if (p->p_emul->e_errno)
241 			error = p->p_emul->e_errno[error];
242 		tf->tf_r0 = error;
243 		tf->tf_ssr &= ~PSL_TBIT;	/* T bit */
244 
245 		break;
246 	}
247 
248 	userret(l);
249 }
250 
251 
252 /*
253  * Like syscall_plain but with trace_enter/trace_exit.
254  */
255 static void
256 syscall_fancy(struct lwp *l, struct trapframe *tf)
257 {
258 	struct proc *p = l->l_proc;
259 	void *params;
260 	const struct sysent *callp;
261 	int error, opc, nsys;
262 	size_t argsize;
263 	register_t code, args[8], rval[2], ocode;
264 
265 	curcpu()->ci_data.cpu_nsyscall++;
266 
267 	opc = tf->tf_spc;
268 	ocode = code = tf->tf_r0;
269 
270 	nsys = p->p_emul->e_nsysent;
271 	callp = p->p_emul->e_sysent;
272 
273 #ifdef KERN_SA
274 	if (__predict_false((l->l_savp)
275             && (l->l_savp->savp_pflags & SAVP_FLAG_DELIVERING)))
276 		l->l_savp->savp_pflags &= ~SAVP_FLAG_DELIVERING;
277 #endif
278 
279 	params = (void *)tf->tf_r15;
280 
281 	switch (code) {
282 	case SYS_syscall:
283 		/*
284 		 * Code is first argument, followed by actual args.
285 		 */
286 	        code = tf->tf_r4;  /* fuword(params); */
287 		/* params += sizeof(int); */
288 		break;
289 	case SYS___syscall:
290 		/*
291 		 * Like syscall, but code is a quad, so as to maintain
292 		 * quad alignment for the rest of the arguments.
293 		 */
294 		if (callp != sysent)
295 			break;
296 		/* fuword(params + _QUAD_LOWWORD * sizeof(int)); */
297 #if _BYTE_ORDER == BIG_ENDIAN
298 		code = tf->tf_r5;
299 #else
300 		code = tf->tf_r4;
301 #endif
302 		/* params += sizeof(quad_t); */
303 		break;
304 	default:
305 		break;
306 	}
307 	if (code < 0 || code >= nsys)
308 		callp += p->p_emul->e_nosys;		/* illegal */
309 	else
310 		callp += code;
311 	argsize = callp->sy_argsize;
312 
313 	if (ocode == SYS_syscall) {
314 		if (argsize) {
315 			args[0] = tf->tf_r5;
316 			args[1] = tf->tf_r6;
317 			args[2] = tf->tf_r7;
318 			if (argsize > 3 * sizeof(int)) {
319 				argsize -= 3 * sizeof(int);
320 				error = copyin(params, (void *)&args[3],
321 					       argsize);
322 			} else
323 				error = 0;
324 		} else
325 			error = 0;
326 	}
327 	else if (ocode == SYS___syscall) {
328 		if (argsize) {
329 			args[0] = tf->tf_r6;
330 			args[1] = tf->tf_r7;
331 			if (argsize > 2 * sizeof(int)) {
332 				argsize -= 2 * sizeof(int);
333 				error = copyin(params, (void *)&args[2],
334 					       argsize);
335 			} else
336 				error = 0;
337 		} else
338 			error = 0;
339 	} else {
340 		if (argsize) {
341 			args[0] = tf->tf_r4;
342 			args[1] = tf->tf_r5;
343 			args[2] = tf->tf_r6;
344 			args[3] = tf->tf_r7;
345 			if (argsize > 4 * sizeof(int)) {
346 				argsize -= 4 * sizeof(int);
347 				error = copyin(params, (void *)&args[4],
348 					       argsize);
349 			} else
350 				error = 0;
351 		} else
352 			error = 0;
353 	}
354 
355 	if (error)
356 		goto bad;
357 
358 	if ((error = trace_enter(code, args, callp->sy_narg)) != 0)
359 		goto out;
360 
361 	rval[0] = 0;
362 	rval[1] = tf->tf_r1;
363 	error = sy_call(callp, l, args, rval);
364 out:
365 	switch (error) {
366 	case 0:
367 		tf->tf_r0 = rval[0];
368 		tf->tf_r1 = rval[1];
369 		tf->tf_ssr |= PSL_TBIT;	/* T bit */
370 
371 		break;
372 	case ERESTART:
373 		/* 2 = TRAPA instruction size */
374 		tf->tf_spc = opc - 2;
375 
376 		break;
377 	case EJUSTRETURN:
378 		/* nothing to do */
379 		break;
380 	default:
381 	bad:
382 		if (p->p_emul->e_errno)
383 			error = p->p_emul->e_errno[error];
384 		tf->tf_r0 = error;
385 		tf->tf_ssr &= ~PSL_TBIT;	/* T bit */
386 
387 		break;
388 	}
389 
390 
391 	trace_exit(code, rval, error);
392 
393 	userret(l);
394 }
395