syscall.c revision 1.12
1/*	$NetBSD: syscall.c,v 1.12 2002/11/04 00:01:03 matt 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_multiprocessor.h"
39
40#include <sys/param.h>
41#include <sys/proc.h>
42#include <sys/reboot.h>
43#include <sys/systm.h>
44#include <sys/user.h>
45#ifdef KTRACE
46#include <sys/ktrace.h>
47#endif
48#ifdef SYSTRACE
49#include <sys/systrace.h>
50#endif
51
52#include <uvm/uvm_extern.h>
53
54#include <powerpc/userret.h>
55#include <machine/cpu.h>
56#include <machine/frame.h>
57
58#define	FIRSTARG	3		/* first argument is in reg 3 */
59#define	NARGREG		8		/* 8 args are in registers */
60#define	MOREARGS(sp)	((caddr_t)((uintptr_t)(sp) + 8)) /* more args go here */
61
62#ifndef EMULNAME
63#include <sys/syscall.h>
64
65#define EMULNAME(x)	(x)
66#define EMULNAMEU(x)	(x)
67
68__KERNEL_RCSID(0, "$NetBSD: syscall.c,v 1.12 2002/11/04 00:01:03 matt Exp $");
69
70void
71child_return(void *arg)
72{
73	struct proc * const p = arg;
74	struct trapframe * const tf = trapframe(p);
75
76	KERNEL_PROC_UNLOCK(p);
77
78	tf->fixreg[FIRSTARG] = 0;
79	tf->fixreg[FIRSTARG + 1] = 1;
80	tf->cr &= ~0x10000000;
81	tf->srr1 &= ~(PSL_FP|PSL_VEC);	/* Disable FP & AltiVec, as we can't
82					   be them. */
83	p->p_addr->u_pcb.pcb_fpcpu = NULL;
84#ifdef	KTRACE
85	if (KTRPOINT(p, KTR_SYSRET)) {
86		KERNEL_PROC_LOCK(p);
87		ktrsysret(p, SYS_fork, 0, 0);
88		KERNEL_PROC_UNLOCK(p);
89	}
90#endif
91	/* Profiling?							XXX */
92	curcpu()->ci_schedstate.spc_curpriority = p->p_priority;
93}
94#endif
95
96static void EMULNAME(syscall_plain)(struct trapframe *);
97
98void
99EMULNAME(syscall_plain)(struct trapframe *frame)
100{
101	struct proc *p = curproc;
102	const struct sysent *callp;
103	size_t argsize;
104	register_t code;
105	register_t *params, rval[2];
106	register_t args[10];
107	int error;
108	int n;
109
110	curcpu()->ci_ev_scalls.ev_count++;
111
112	code = frame->fixreg[0];
113	params = frame->fixreg + FIRSTARG;
114	n = NARGREG;
115
116#ifdef COMPAT_MACH
117	if ((callp = mach_syscall_dispatch(code)) == NULL)
118#endif /* COMPAT_MACH */
119	{
120		switch (code) {
121		case EMULNAMEU(SYS_syscall):
122			/*
123			 * code is first argument,
124			 * followed by actual args.
125			 */
126			code = *params++;
127			n -= 1;
128			break;
129#if !defined(COMPAT_LINUX)
130		case EMULNAMEU(SYS___syscall):
131			params++;
132			code = *params++;
133			n -= 2;
134			break;
135#endif
136		default:
137			break;
138		}
139
140		callp = p->p_emul->e_sysent +
141		    (code & (EMULNAMEU(SYS_NSYSENT)-1));
142	}
143
144	argsize = callp->sy_argsize;
145
146	if (argsize > n * sizeof(register_t)) {
147		memcpy(args, params, n * sizeof(register_t));
148		KERNEL_PROC_LOCK(p);
149		error = copyin(MOREARGS(frame->fixreg[1]),
150		       args + n,
151		       argsize - n * sizeof(register_t));
152		KERNEL_PROC_UNLOCK(p);
153		if (error)
154			goto syscall_bad;
155		params = args;
156	}
157
158	rval[0] = 0;
159	rval[1] = 0;
160
161	if ((callp->sy_flags & SYCALL_MPSAFE) == 0) {
162		KERNEL_PROC_LOCK(p);
163	}
164
165	error = (*callp->sy_call)(p, params, rval);
166
167	if ((callp->sy_flags & SYCALL_MPSAFE) == 0) {
168		KERNEL_PROC_UNLOCK(p);
169	}
170
171	switch (error) {
172	case 0:
173		frame->fixreg[FIRSTARG] = rval[0];
174		frame->fixreg[FIRSTARG + 1] = rval[1];
175		frame->cr &= ~0x10000000;
176		break;
177	case ERESTART:
178		/*
179		 * Set user's pc back to redo the system call.
180		 */
181		frame->srr0 -= 4;
182		break;
183	case EJUSTRETURN:
184		/* nothing to do */
185		break;
186	default:
187syscall_bad:
188		if (p->p_emul->e_errno)
189			error = p->p_emul->e_errno[error];
190		frame->fixreg[FIRSTARG] = error;
191		frame->cr |= 0x10000000;
192		break;
193	}
194	userret(p, frame);
195}
196
197#if defined(KTRACE) || defined(SYSTRACE)
198static void EMULNAME(syscall_fancy)(struct trapframe *);
199
200void
201EMULNAME(syscall_fancy)(struct trapframe *frame)
202{
203	struct proc *p = curproc;
204	const struct sysent *callp;
205	size_t argsize;
206	register_t code;
207	register_t *params, rval[2];
208	register_t args[10];
209	int error;
210	int n;
211
212	KERNEL_PROC_LOCK(p);
213	curcpu()->ci_ev_scalls.ev_count++;
214
215	code = frame->fixreg[0];
216	params = frame->fixreg + FIRSTARG;
217	n = NARGREG;
218
219#ifdef COMPAT_MACH
220	if ((callp = mach_syscall_dispatch(code)) == NULL)
221#endif /* COMPAT_MACH */
222	{
223		switch (code) {
224		case EMULNAMEU(SYS_syscall):
225			/*
226			 * code is first argument,
227			 * followed by actual args.
228			 */
229			code = *params++;
230			n -= 1;
231			break;
232#if !defined(COMPAT_LINUX)
233		case EMULNAMEU(SYS___syscall):
234			params++;
235			code = *params++;
236			n -= 2;
237			break;
238#endif
239		default:
240			break;
241		}
242
243		callp = p->p_emul->e_sysent +
244		    (code & (EMULNAMEU(SYS_NSYSENT)-1));
245	}
246
247	argsize = callp->sy_argsize;
248
249	if (argsize > n * sizeof(register_t)) {
250		memcpy(args, params, n * sizeof(register_t));
251		error = copyin(MOREARGS(frame->fixreg[1]),
252		       args + n,
253		       argsize - n * sizeof(register_t));
254		if (error)
255			goto syscall_bad;
256		params = args;
257	}
258
259	if ((error = trace_enter(p, code, params, rval)) != 0)
260		goto syscall_bad;
261
262	rval[0] = 0;
263	rval[1] = 0;
264
265	error = (*callp->sy_call)(p, params, rval);
266	switch (error) {
267	case 0:
268		frame->fixreg[FIRSTARG] = rval[0];
269		frame->fixreg[FIRSTARG + 1] = rval[1];
270		frame->cr &= ~0x10000000;
271		break;
272	case ERESTART:
273		/*
274		 * Set user's pc back to redo the system call.
275		 */
276		frame->srr0 -= 4;
277		break;
278	case EJUSTRETURN:
279		/* nothing to do */
280		break;
281	default:
282syscall_bad:
283		if (p->p_emul->e_errno)
284			error = p->p_emul->e_errno[error];
285		frame->fixreg[FIRSTARG] = error;
286		frame->cr |= 0x10000000;
287		break;
288	}
289	KERNEL_PROC_UNLOCK(p);
290	trace_exit(p, code, params, rval, error);
291	userret(p, frame);
292}
293#endif /* KTRACE || SYSTRACE */
294
295void EMULNAME(syscall_intern)(struct proc *);
296
297void
298EMULNAME(syscall_intern)(struct proc *p)
299{
300#ifdef KTRACE
301	if (p->p_traceflag & (KTRFAC_SYSCALL | KTRFAC_SYSRET)) {
302		p->p_md.md_syscall = EMULNAME(syscall_fancy);
303		return;
304	}
305#endif
306#ifdef SYSTRACE
307	if (ISSET(p->p_flag, P_SYSTRACE)) {
308		p->p_md.md_syscall = EMULNAME(syscall_fancy);
309		return;
310	}
311#endif
312	p->p_md.md_syscall = EMULNAME(syscall_plain);
313}
314
315