sunos_syscall.c revision 1.22
1/*	$NetBSD: sunos_syscall.c,v 1.22 2011/02/08 20:20:16 rmind 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 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/*
30 * Copyright (c) 1988 University of Utah.
31 * Copyright (c) 1982, 1986, 1990, 1993
32 *	The Regents of the University of California.  All rights reserved.
33 *
34 * This code is derived from software contributed to Berkeley by
35 * the Systems Programming Group of the University of Utah Computer
36 * Science Department.
37 *
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
40 * are met:
41 * 1. Redistributions of source code must retain the above copyright
42 *    notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 *    notice, this list of conditions and the following disclaimer in the
45 *    documentation and/or other materials provided with the distribution.
46 * 3. Neither the name of the University nor the names of its contributors
47 *    may be used to endorse or promote products derived from this software
48 *    without specific prior written permission.
49 *
50 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
51 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
54 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60 * SUCH DAMAGE.
61 *
62 * from: Utah $Hdr: trap.c 1.37 92/12/20$
63 *
64 *	@(#)trap.c	8.5 (Berkeley) 1/4/94
65 */
66
67#include <sys/cdefs.h>
68__KERNEL_RCSID(0, "$NetBSD: sunos_syscall.c,v 1.22 2011/02/08 20:20:16 rmind Exp $");
69
70#ifdef _KERNEL_OPT
71#include "opt_execfmt.h"
72#endif
73
74#include <sys/param.h>
75#include <sys/systm.h>
76#include <sys/proc.h>
77#include <sys/acct.h>
78#include <sys/kernel.h>
79#include <sys/syscall.h>
80#include <sys/syscallvar.h>
81#include <sys/syslog.h>
82
83#include <machine/psl.h>
84#include <machine/cpu.h>
85#include <machine/reg.h>
86
87#include <uvm/uvm_extern.h>
88
89#include <compat/sunos/sunos_syscall.h>
90#include <compat/sunos/sunos_exec.h>
91
92void	sunos_syscall_intern(struct proc *);
93static void sunos_syscall_plain(register_t, struct lwp *, struct frame *);
94static void sunos_syscall_fancy(register_t, struct lwp *, struct frame *);
95
96void
97sunos_syscall_intern(struct proc *p)
98{
99
100	if (trace_is_enabled(p))
101		p->p_md.md_syscall = sunos_syscall_fancy;
102	else
103		p->p_md.md_syscall = sunos_syscall_plain;
104}
105
106static void
107sunos_syscall_plain(register_t code, struct lwp *l, struct frame *frame)
108{
109	struct proc *p = l->l_proc;
110	char *params;
111	const struct sysent *callp;
112	int error, nsys;
113	size_t argsize;
114	register_t args[16], rval[2];
115
116	nsys = p->p_emul->e_nsysent;
117	callp = p->p_emul->e_sysent;
118
119	/*
120	 * SunOS passes the syscall-number on the stack, whereas
121	 * BSD passes it in D0. So, we have to get the real "code"
122	 * from the stack, and clean up the stack, as SunOS glue
123	 * code assumes the kernel pops the syscall argument the
124	 * glue pushed on the stack. Sigh...
125	 */
126	code = fuword((void *)frame->f_regs[SP]);
127
128	/*
129	 * XXX
130	 * Don't do this for sunos_sigreturn, as there's no stored pc
131	 * on the stack to skip, the argument follows the syscall
132	 * number without a gap.
133	 */
134	if (code != SUNOS_SYS_sigreturn) {
135		frame->f_regs[SP] += sizeof (int);
136		/*
137		 * remember that we adjusted the SP,
138		 * might have to undo this if the system call
139		 * returns ERESTART.
140		 */
141		l->l_md.md_flags |= MDL_STACKADJ;
142	} else
143		l->l_md.md_flags &= ~MDL_STACKADJ;
144
145	params = (char *)frame->f_regs[SP] + sizeof(int);
146
147	switch (code) {
148	case SUNOS_SYS_syscall:
149		/*
150		 * Code is first argument, followed by actual args.
151		 */
152		code = fuword(params);
153		params += sizeof(int);
154		break;
155	default:
156		break;
157	}
158
159	if (code < 0 || code >= nsys)
160		callp += p->p_emul->e_nosys;		/* illegal */
161	else
162		callp += code;
163
164	argsize = callp->sy_argsize;
165	if (argsize) {
166		error = copyin(params, (void *)args, argsize);
167		if (error)
168			goto bad;
169	}
170
171	rval[0] = 0;
172	rval[1] = frame->f_regs[D1];
173	error = sy_call(callp, l, args, rval);
174
175	switch (error) {
176	case 0:
177		/*
178		 * Reinitialize proc pointer `p' as it may be different
179		 * if this is a child returning from fork syscall.
180		 */
181		p = curproc;
182		frame->f_regs[D0] = rval[0];
183		frame->f_regs[D1] = rval[1];
184		frame->f_sr &= ~PSL_C;	/* carry bit */
185		break;
186	case ERESTART:
187		/*
188		 * We always enter through a `trap' instruction, which is 2
189		 * bytes, so adjust the pc by that amount.
190		 */
191		frame->f_pc = frame->f_pc - 2;
192		break;
193	case EJUSTRETURN:
194		/* nothing to do */
195		break;
196	default:
197	bad:
198		frame->f_regs[D0] = error;
199		frame->f_sr |= PSL_C;	/* carry bit */
200		break;
201	}
202
203	/* need new p-value for this */
204	if (l->l_md.md_flags & MDL_STACKADJ) {
205		l->l_md.md_flags &= ~MDL_STACKADJ;
206		if (error == ERESTART)
207			frame->f_regs[SP] -= sizeof (int);
208	}
209}
210
211static void
212sunos_syscall_fancy(register_t code, struct lwp *l, struct frame *frame)
213{
214	struct proc *p = l->l_proc;
215	char *params;
216	const struct sysent *callp;
217	int error, nsys;
218	size_t argsize;
219	register_t args[16], rval[2];
220
221	nsys = p->p_emul->e_nsysent;
222	callp = p->p_emul->e_sysent;
223
224	/*
225	 * SunOS passes the syscall-number on the stack, whereas
226	 * BSD passes it in D0. So, we have to get the real "code"
227	 * from the stack, and clean up the stack, as SunOS glue
228	 * code assumes the kernel pops the syscall argument the
229	 * glue pushed on the stack. Sigh...
230	 */
231	code = fuword((void *)frame->f_regs[SP]);
232
233	/*
234	 * XXX
235	 * Don't do this for sunos_sigreturn, as there's no stored pc
236	 * on the stack to skip, the argument follows the syscall
237	 * number without a gap.
238	 */
239	if (code != SUNOS_SYS_sigreturn) {
240		frame->f_regs[SP] += sizeof (int);
241		/*
242		 * remember that we adjusted the SP,
243		 * might have to undo this if the system call
244		 * returns ERESTART.
245		 */
246		l->l_md.md_flags |= MDL_STACKADJ;
247	} else
248		l->l_md.md_flags &= ~MDL_STACKADJ;
249
250	params = (char *)frame->f_regs[SP] + sizeof(int);
251
252	switch (code) {
253	case SUNOS_SYS_syscall:
254		/*
255		 * Code is first argument, followed by actual args.
256		 */
257		code = fuword(params);
258		params += sizeof(int);
259		break;
260	default:
261		break;
262	}
263
264	if (code < 0 || code >= nsys)
265		callp += p->p_emul->e_nosys;		/* illegal */
266	else
267		callp += code;
268
269	argsize = callp->sy_argsize;
270	if (argsize) {
271		error = copyin(params, (void *)args, argsize);
272		if (error)
273			goto bad;
274	}
275
276	if ((error = trace_enter(code, args, callp->sy_narg)) != 0)
277		goto out;
278
279	rval[0] = 0;
280	rval[1] = frame->f_regs[D1];
281	error = sy_call(callp, l, args, rval);
282out:
283	switch (error) {
284	case 0:
285		/*
286		 * Reinitialize proc pointer `p' as it may be different
287		 * if this is a child returning from fork syscall.
288		 */
289		p = curproc;
290		frame->f_regs[D0] = rval[0];
291		frame->f_regs[D1] = rval[1];
292		frame->f_sr &= ~PSL_C;	/* carry bit */
293		break;
294	case ERESTART:
295		/*
296		 * We always enter through a `trap' instruction, which is 2
297		 * bytes, so adjust the pc by that amount.
298		 */
299		frame->f_pc = frame->f_pc - 2;
300		break;
301	case EJUSTRETURN:
302		/* nothing to do */
303		break;
304	default:
305	bad:
306		frame->f_regs[D0] = error;
307		frame->f_sr |= PSL_C;	/* carry bit */
308		break;
309	}
310
311	/* need new p-value for this */
312	if (l->l_md.md_flags & MDL_STACKADJ) {
313		l->l_md.md_flags &= ~MDL_STACKADJ;
314		if (error == ERESTART)
315			frame->f_regs[SP] -= sizeof (int);
316	}
317
318	trace_exit(code, rval, error);
319}
320