xref: /netbsd/sys/arch/m68k/m68k/m68k_syscall.c (revision c4a72b64)
1 /*	$NetBSD: m68k_syscall.c,v 1.5 2002/11/15 20:06:02 manu Exp $	*/
2 
3 /*-
4  * Portions Copyright (c) 2000 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *        This product includes software developed by the NetBSD
18  *        Foundation, Inc. and its contributors.
19  * 4. Neither the name of The NetBSD Foundation nor the names of its
20  *    contributors may be used to endorse or promote products derived
21  *    from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
24  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
27  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 /*
37  * Copyright (c) 1988 University of Utah.
38  * Copyright (c) 1982, 1986, 1990, 1993
39  *	The Regents of the University of California.  All rights reserved.
40  *
41  * This code is derived from software contributed to Berkeley by
42  * the Systems Programming Group of the University of Utah Computer
43  * Science Department.
44  *
45  * Redistribution and use in source and binary forms, with or without
46  * modification, are permitted provided that the following conditions
47  * are met:
48  * 1. Redistributions of source code must retain the above copyright
49  *    notice, this list of conditions and the following disclaimer.
50  * 2. Redistributions in binary form must reproduce the above copyright
51  *    notice, this list of conditions and the following disclaimer in the
52  *    documentation and/or other materials provided with the distribution.
53  * 3. All advertising materials mentioning features or use of this software
54  *    must display the following acknowledgement:
55  *	This product includes software developed by the University of
56  *	California, Berkeley and its contributors.
57  * 4. Neither the name of the University nor the names of its contributors
58  *    may be used to endorse or promote products derived from this software
59  *    without specific prior written permission.
60  *
61  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
62  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
63  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
64  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
65  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
66  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
67  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
68  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
69  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
70  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
71  * SUCH DAMAGE.
72  *
73  * from: Utah $Hdr: trap.c 1.37 92/12/20$
74  *
75  *	@(#)trap.c	8.5 (Berkeley) 1/4/94
76  */
77 
78 #include "opt_syscall_debug.h"
79 #include "opt_execfmt.h"
80 #include "opt_ktrace.h"
81 #include "opt_systrace.h"
82 #include "opt_compat_netbsd.h"
83 #include "opt_compat_aout_m68k.h"
84 
85 #include <sys/param.h>
86 #include <sys/systm.h>
87 #include <sys/proc.h>
88 #include <sys/acct.h>
89 #include <sys/kernel.h>
90 #include <sys/syscall.h>
91 #include <sys/syslog.h>
92 #include <sys/user.h>
93 #ifdef KTRACE
94 #include <sys/ktrace.h>
95 #endif
96 #ifdef SYSTRACE
97 #include <sys/systrace.h>
98 #endif
99 
100 #include <machine/psl.h>
101 #include <machine/cpu.h>
102 #include <machine/reg.h>
103 
104 #include <uvm/uvm_extern.h>
105 
106 /*
107  * Defined in machine-specific code (usually trap.c)
108  * XXX: This will disappear when all m68k ports share common trap() code...
109  */
110 extern void machine_userret(struct proc *, struct frame *, u_quad_t);
111 
112 void syscall(register_t, struct frame);
113 
114 void	syscall_intern(struct proc *);
115 #ifdef COMPAT_AOUT_M68K
116 void	aoutm68k_syscall_intern(struct proc *);
117 #endif
118 static void syscall_plain(register_t, struct proc *, struct frame *);
119 #if defined(KTRACE) || defined(SYSTRACE)
120 static void syscall_fancy(register_t, struct proc *, struct frame *);
121 #endif
122 
123 
124 /*
125  * Process a system call.
126  */
127 void
128 syscall(code, frame)
129 	register_t code;
130 	struct frame frame;
131 {
132 	struct proc *p;
133 	u_quad_t sticks;
134 
135 	uvmexp.syscalls++;
136 	if (!USERMODE(frame.f_sr))
137 		panic("syscall");
138 
139 	p = curproc;
140 	sticks = p->p_sticks;
141 	p->p_md.md_regs = frame.f_regs;
142 
143 	(p->p_md.md_syscall)(code, p, &frame);
144 
145 	machine_userret(p, &frame, sticks);
146 }
147 
148 void
149 syscall_intern(struct proc *p)
150 {
151 
152 #ifdef KTRACE
153 	if (p->p_traceflag & (KTRFAC_SYSCALL | KTRFAC_SYSRET))
154 		p->p_md.md_syscall = syscall_fancy;
155 	else
156 #endif
157 #ifdef SYSTRACE
158 	if (ISSET(p->p_flag, P_SYSTRACE))
159 		p->p_md.md_syscall = syscall_fancy;
160 	else
161 #endif
162 		p->p_md.md_syscall = syscall_plain;
163 }
164 
165 #ifdef COMPAT_AOUT_M68K
166 /*
167  * Not worth the effort of a whole new set of syscall_{plain,fancy} functions
168  */
169 void
170 aoutm68k_syscall_intern(struct proc *p)
171 {
172 
173 #ifdef KTRACE
174 	if (p->p_traceflag & (KTRFAC_SYSCALL | KTRFAC_SYSRET))
175 		p->p_md.md_syscall = syscall_fancy;
176 	else
177 #endif
178 #ifdef SYSTRACE
179 	if (ISSET(p->p_flag, P_SYSTRACE))
180 		p->p_md.md_syscall = syscall_fancy;
181 	else
182 #endif
183 		p->p_md.md_syscall = syscall_plain;
184 }
185 #endif
186 
187 static void
188 syscall_plain(register_t code, struct proc *p, struct frame *frame)
189 {
190 	caddr_t params;
191 	const struct sysent *callp;
192 	int error, nsys;
193 	size_t argsize;
194 	register_t args[16], rval[2];
195 
196 	nsys = p->p_emul->e_nsysent;
197 	callp = p->p_emul->e_sysent;
198 
199 	params = (caddr_t)frame->f_regs[SP] + sizeof(int);
200 
201 	switch (code) {
202 	case SYS_syscall:
203 		/*
204 		 * Code is first argument, followed by actual args.
205 		 */
206 		code = fuword(params);
207 		params += sizeof(int);
208 		/*
209 		 * XXX sigreturn requires special stack manipulation
210 		 * that is only done if entered via the sigreturn
211 		 * trap.  Cannot allow it here so make sure we fail.
212 		 */
213 		switch (code) {
214 #ifdef COMPAT_13
215 		case SYS_compat_13_sigreturn13:
216 #endif
217 		case SYS___sigreturn14:
218 			code = nsys;
219 			break;
220 		}
221 		break;
222 	case SYS___syscall:
223 		/*
224 		 * Like syscall, but code is a quad, so as to maintain
225 		 * quad alignment for the rest of the arguments.
226 		 */
227 		code = fuword(params + _QUAD_LOWWORD * sizeof(int));
228 		params += sizeof(quad_t);
229 		break;
230 	default:
231 		break;
232 	}
233 
234 	if (code < 0 || code >= nsys)
235 		callp += p->p_emul->e_nosys;		/* illegal */
236 	else
237 		callp += code;
238 
239 	argsize = callp->sy_argsize;
240 	if (argsize) {
241 		error = copyin(params, (caddr_t)args, argsize);
242 		if (error)
243 			goto bad;
244 	}
245 
246 #ifdef SYSCALL_DEBUG
247 	scdebug_call(p, code, args);
248 #endif
249 
250 	rval[0] = 0;
251 	rval[1] = frame->f_regs[D1];
252 	error = (*callp->sy_call)(p, args, rval);
253 
254 	switch (error) {
255 	case 0:
256 		/*
257 		 * Reinitialize proc pointer `p' as it may be different
258 		 * if this is a child returning from fork syscall.
259 		 */
260 		p = curproc;
261 		frame->f_regs[D0] = rval[0];
262 		frame->f_regs[D1] = rval[1];
263 		frame->f_sr &= ~PSL_C;	/* carry bit */
264 #ifdef COMPAT_AOUT_M68K
265 		{
266 			extern struct emul emul_netbsd_aoutm68k;
267 
268 			/*
269 			 * Some pre-m68k ELF libc assembler stubs assume
270 			 * %a0 is preserved across system calls...
271 			 */
272 			if (p->p_emul != &emul_netbsd_aoutm68k)
273 				frame->f_regs[A0] = rval[0];
274 		}
275 #endif
276 		break;
277 	case ERESTART:
278 		/*
279 		 * We always enter through a `trap' instruction, which is 2
280 		 * bytes, so adjust the pc by that amount.
281 		 */
282 		frame->f_pc = frame->f_pc - 2;
283 		break;
284 	case EJUSTRETURN:
285 		/* nothing to do */
286 		break;
287 	default:
288 	bad:
289 		/*
290 		 * XXX: HPUX and SVR4 use this code-path, so we may have
291 		 * to translate errno.
292 		 */
293 		if (p->p_emul->e_errno)
294 			error = p->p_emul->e_errno[error];
295 		frame->f_regs[D0] = error;
296 		frame->f_sr |= PSL_C;	/* carry bit */
297 		break;
298 	}
299 
300 #ifdef SYSCALL_DEBUG
301         scdebug_ret(p, code, error, rval)
302 #endif
303 }
304 
305 #if defined(KTRACE) || defined(SYSTRACE)
306 static void
307 syscall_fancy(register_t code, struct proc *p, struct frame *frame)
308 {
309 	caddr_t params;
310 	const struct sysent *callp;
311 	int error, nsys;
312 	size_t argsize;
313 	register_t args[16], rval[2];
314 
315 	nsys = p->p_emul->e_nsysent;
316 	callp = p->p_emul->e_sysent;
317 
318 	params = (caddr_t)frame->f_regs[SP] + sizeof(int);
319 
320 	switch (code) {
321 	case SYS_syscall:
322 		/*
323 		 * Code is first argument, followed by actual args.
324 		 */
325 		code = fuword(params);
326 		params += sizeof(int);
327 		/*
328 		 * XXX sigreturn requires special stack manipulation
329 		 * that is only done if entered via the sigreturn
330 		 * trap.  Cannot allow it here so make sure we fail.
331 		 */
332 		switch (code) {
333 #ifdef COMPAT_13
334 		case SYS_compat_13_sigreturn13:
335 #endif
336 		case SYS___sigreturn14:
337 			code = nsys;
338 			break;
339 		}
340 		break;
341 	case SYS___syscall:
342 		/*
343 		 * Like syscall, but code is a quad, so as to maintain
344 		 * quad alignment for the rest of the arguments.
345 		 */
346 		code = fuword(params + _QUAD_LOWWORD * sizeof(int));
347 		params += sizeof(quad_t);
348 		break;
349 	default:
350 		break;
351 	}
352 
353 	if (code < 0 || code >= nsys)
354 		callp += p->p_emul->e_nosys;		/* illegal */
355 	else
356 		callp += code;
357 
358 	argsize = callp->sy_argsize;
359 	if (argsize) {
360 		error = copyin(params, (caddr_t)args, argsize);
361 		if (error)
362 			goto bad;
363 	}
364 
365 	if ((error = trace_enter(p, code, code, args, rval)) != 0)
366 		goto bad;
367 
368 	rval[0] = 0;
369 	rval[1] = frame->f_regs[D1];
370 	error = (*callp->sy_call)(p, args, rval);
371 
372 	switch (error) {
373 	case 0:
374 		/*
375 		 * Reinitialize proc pointer `p' as it may be different
376 		 * if this is a child returning from fork syscall.
377 		 */
378 		p = curproc;
379 		frame->f_regs[D0] = rval[0];
380 		frame->f_regs[D1] = rval[1];
381 		frame->f_sr &= ~PSL_C;	/* carry bit */
382 #ifdef COMPAT_AOUT_M68K
383 		{
384 			extern struct emul emul_netbsd_aoutm68k;
385 
386 			/*
387 			 * Some pre-m68k ELF libc assembler stubs assume
388 			 * %a0 is preserved across system calls...
389 			 */
390 			if (p->p_emul != &emul_netbsd_aoutm68k)
391 				frame->f_regs[A0] = rval[0];
392 		}
393 #endif
394 		break;
395 	case ERESTART:
396 		/*
397 		 * We always enter through a `trap' instruction, which is 2
398 		 * bytes, so adjust the pc by that amount.
399 		 */
400 		frame->f_pc = frame->f_pc - 2;
401 		break;
402 	case EJUSTRETURN:
403 		/* nothing to do */
404 		break;
405 	default:
406 	bad:
407 		/*
408 		 * XXX: HPUX and SVR4 use this code-path, so we may have
409 		 * to translate errno.
410 		 */
411 		if (p->p_emul->e_errno)
412 			error = p->p_emul->e_errno[error];
413 		frame->f_regs[D0] = error;
414 		frame->f_sr |= PSL_C;	/* carry bit */
415 		break;
416 	}
417 
418 	trace_exit(p, code, args, rval, error);
419 }
420 #endif /* KTRACE || SYSTRACE */
421 
422 void
423 child_return(arg)
424 	void *arg;
425 {
426 	struct proc *p = arg;
427 	/* See cpu_fork() */
428 	struct frame *f = (struct frame *)p->p_md.md_regs;
429 
430 	f->f_regs[D0] = 0;
431 	f->f_sr &= ~PSL_C;
432 	f->f_format = FMT0;
433 
434 	machine_userret(p, f, 0);
435 #ifdef KTRACE
436 	if (KTRPOINT(p, KTR_SYSRET))
437 		ktrsysret(p, SYS_fork, 0, 0);
438 #endif
439 }
440