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