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