syscall.c revision 1.4
1/*	$NetBSD: syscall.c,v 1.4 2002/08/02 03:46:45 chs Exp $	*/
2
3/*
4 * Copyright (C) 2002 Matt Thomas
5 * Copyright (C) 1995, 1996 Wolfgang Solfrank.
6 * Copyright (C) 1995, 1996 TooLs GmbH.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 *    must display the following acknowledgement:
19 *	This product includes software developed by TooLs GmbH.
20 * 4. The name of TooLs GmbH may not be used to endorse or promote products
21 *    derived from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
29 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35#include "opt_altivec.h"
36#include "opt_ktrace.h"
37#include "opt_systrace.h"
38#include "opt_compat_linux.h"
39#include "opt_multiprocessor.h"
40
41#include <sys/param.h>
42#include <sys/proc.h>
43#include <sys/reboot.h>
44#include <sys/syscall.h>
45#include <sys/systm.h>
46#include <sys/user.h>
47#ifdef KTRACE
48#include <sys/ktrace.h>
49#endif
50#ifdef SYSTRACE
51#include <sys/systrace.h>
52#endif
53
54#include <uvm/uvm_extern.h>
55
56#include <powerpc/userret.h>
57#include <machine/cpu.h>
58#include <machine/frame.h>
59
60#ifdef COMPAT_LINUX
61#include <compat/linux/common/linux_types.h>
62#include <compat/linux/common/linux_errno.h>
63#include <compat/linux/linux_syscall.h>
64#include <compat/linux/common/linux_signal.h>
65#include <compat/linux/common/linux_siginfo.h>
66#include <compat/linux/arch/powerpc/linux_siginfo.h>
67#include <compat/linux/arch/powerpc/linux_machdep.h>
68#endif
69
70#define	FIRSTARG	3		/* first argument is in reg 3 */
71#define	NARGREG		8		/* 8 args are in registers */
72#define	MOREARGS(sp)	((caddr_t)((uintptr_t)(sp) + 8)) /* more args go here */
73
74void syscall_plain(struct trapframe *frame);
75void syscall_fancy(struct trapframe *frame);
76
77void
78syscall_plain(struct trapframe *frame)
79{
80	struct proc *p = curproc;
81	const struct sysent *callp;
82	size_t argsize;
83	register_t code;
84	register_t *params, rval[2];
85	register_t args[10];
86	int error;
87	int n;
88
89	curcpu()->ci_ev_scalls.ev_count++;
90
91	code = frame->fixreg[0];
92	callp = p->p_emul->e_sysent;
93	params = frame->fixreg + FIRSTARG;
94	n = NARGREG;
95
96	switch (code) {
97	case SYS_syscall:
98		/*
99		 * code is first argument,
100		 * followed by actual args.
101		 */
102		code = *params++;
103		n -= 1;
104		break;
105	case SYS___syscall:
106		params++;
107		code = *params++;
108		n -= 2;
109		break;
110	default:
111		break;
112	}
113
114	code &= (SYS_NSYSENT - 1);
115	callp += code;
116	argsize = callp->sy_argsize;
117
118	if (argsize > n * sizeof(register_t)) {
119		memcpy(args, params, n * sizeof(register_t));
120		KERNEL_PROC_LOCK(p);
121		error = copyin(MOREARGS(frame->fixreg[1]),
122		       args + n,
123		       argsize - n * sizeof(register_t));
124		KERNEL_PROC_UNLOCK(p);
125		if (error)
126			goto syscall_bad;
127		params = args;
128	}
129
130	rval[0] = 0;
131	rval[1] = 0;
132
133	if ((callp->sy_flags & SYCALL_MPSAFE) == 0) {
134		KERNEL_PROC_LOCK(p);
135	}
136
137	error = (*callp->sy_call)(p, params, rval);
138
139	if ((callp->sy_flags & SYCALL_MPSAFE) == 0) {
140		KERNEL_PROC_UNLOCK(p);
141	}
142
143	switch (error) {
144	case 0:
145		frame->fixreg[FIRSTARG] = rval[0];
146		frame->fixreg[FIRSTARG + 1] = rval[1];
147		frame->cr &= ~0x10000000;
148		break;
149	case ERESTART:
150		/*
151		 * Set user's pc back to redo the system call.
152		 */
153		frame->srr0 -= 4;
154		break;
155	case EJUSTRETURN:
156		/* nothing to do */
157		break;
158	default:
159syscall_bad:
160		if (p->p_emul->e_errno)
161			error = p->p_emul->e_errno[error];
162		frame->fixreg[FIRSTARG] = error;
163		frame->cr |= 0x10000000;
164		break;
165	}
166	userret(p, frame);
167}
168
169void
170syscall_fancy(struct trapframe *frame)
171{
172	struct proc *p = curproc;
173	const struct sysent *callp;
174	size_t argsize;
175	register_t code;
176	register_t *params, rval[2];
177	register_t args[10];
178	int error;
179	int n;
180
181	KERNEL_PROC_LOCK(p);
182	curcpu()->ci_ev_scalls.ev_count++;
183
184	code = frame->fixreg[0];
185	callp = p->p_emul->e_sysent;
186	params = frame->fixreg + FIRSTARG;
187	n = NARGREG;
188
189	switch (code) {
190	case SYS_syscall:
191		/*
192		 * code is first argument,
193		 * followed by actual args.
194		 */
195		code = *params++;
196		n -= 1;
197		break;
198	case SYS___syscall:
199		params++;
200		code = *params++;
201		n -= 2;
202		break;
203	default:
204		break;
205	}
206
207	code &= (SYS_NSYSENT - 1);
208	callp += code;
209	argsize = callp->sy_argsize;
210
211	if (argsize > n * sizeof(register_t)) {
212		memcpy(args, params, n * sizeof(register_t));
213		error = copyin(MOREARGS(frame->fixreg[1]),
214		       args + n,
215		       argsize - n * sizeof(register_t));
216		if (error)
217			goto syscall_bad;
218		params = args;
219	}
220
221	if ((error = trace_enter(p, code, params, rval)) != 0)
222		goto syscall_bad;
223
224	rval[0] = 0;
225	rval[1] = 0;
226
227	error = (*callp->sy_call)(p, params, rval);
228	switch (error) {
229	case 0:
230		frame->fixreg[FIRSTARG] = rval[0];
231		frame->fixreg[FIRSTARG + 1] = rval[1];
232		frame->cr &= ~0x10000000;
233		break;
234	case ERESTART:
235		/*
236		 * Set user's pc back to redo the system call.
237		 */
238		frame->srr0 -= 4;
239		break;
240	case EJUSTRETURN:
241		/* nothing to do */
242		break;
243	default:
244syscall_bad:
245		if (p->p_emul->e_errno)
246			error = p->p_emul->e_errno[error];
247		frame->fixreg[FIRSTARG] = error;
248		frame->cr |= 0x10000000;
249		break;
250	}
251	KERNEL_PROC_UNLOCK(p);
252	trace_exit(p, code, params, rval, error);
253	userret(p, frame);
254}
255
256void
257syscall_intern(struct proc *p)
258{
259#ifdef KTRACE
260	if (p->p_traceflag & (KTRFAC_SYSCALL | KTRFAC_SYSRET)) {
261		p->p_md.md_syscall = syscall_fancy;
262		return;
263	}
264#endif
265#ifdef SYSTRACE
266	if (ISSET(p->p_flag, P_SYSTRACE)) {
267		p->p_md.md_syscall = syscall_fancy;
268		return;
269	}
270#endif
271	p->p_md.md_syscall = syscall_plain;
272}
273
274#ifdef COMPAT_LINUX
275void
276linux_syscall_intern(struct proc *p)
277{
278	p->p_md.md_syscall = syscall_fancy;
279}
280#endif
281
282void
283child_return(void *arg)
284{
285	struct proc * const p = arg;
286	struct trapframe * const tf = trapframe(p);
287
288	KERNEL_PROC_UNLOCK(p);
289
290	tf->fixreg[FIRSTARG] = 0;
291	tf->fixreg[FIRSTARG + 1] = 1;
292	tf->cr &= ~0x10000000;
293	tf->srr1 &= ~(PSL_FP|PSL_VEC);	/* Disable FP & AltiVec, as we can't
294					   be them. */
295	p->p_addr->u_pcb.pcb_fpcpu = NULL;
296#ifdef	KTRACE
297	if (KTRPOINT(p, KTR_SYSRET)) {
298		KERNEL_PROC_LOCK(p);
299		ktrsysret(p, SYS_fork, 0, 0);
300		KERNEL_PROC_UNLOCK(p);
301	}
302#endif
303	/* Profiling?							XXX */
304	curcpu()->ci_schedstate.spc_curpriority = p->p_priority;
305}
306