syscall.c revision 1.2
1/*	$NetBSD: syscall.c,v 1.2 2002/07/11 19:32:43 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_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 <machine/cpu.h>
57#include <machine/frame.h>
58
59#ifdef COMPAT_LINUX
60#include <compat/linux/common/linux_types.h>
61#include <compat/linux/common/linux_errno.h>
62#include <compat/linux/linux_syscall.h>
63#include <compat/linux/common/linux_signal.h>
64#include <compat/linux/common/linux_siginfo.h>
65#include <compat/linux/arch/powerpc/linux_siginfo.h>
66#include <compat/linux/arch/powerpc/linux_machdep.h>
67#endif
68
69#define	FIRSTARG	3		/* first argument is in reg 3 */
70#define	NARGREG		8		/* 8 args are in registers */
71#define	MOREARGS(sp)	((caddr_t)((uintptr_t)(sp) + 8)) /* more args go here */
72
73static void syscall_fancy(struct trapframe *frame);
74
75void
76syscall_fancy(struct trapframe *frame)
77{
78	struct proc *p = curproc;
79	const struct sysent *callp;
80	size_t argsize;
81	register_t code;
82	register_t *params, rval[2];
83	register_t args[10];
84	int error;
85	int n;
86
87	KERNEL_PROC_LOCK(p);
88
89	curcpu()->ci_ev_scalls.ev_count++;
90	uvmexp.syscalls++;
91
92	code = frame->fixreg[0];
93	callp = p->p_emul->e_sysent;
94	params = frame->fixreg + FIRSTARG;
95	n = NARGREG;
96
97	switch (code) {
98	case SYS_syscall:
99		/*
100		 * code is first argument,
101		 * followed by actual args.
102		 */
103		code = *params++;
104		n -= 1;
105		break;
106	case SYS___syscall:
107		params++;
108		code = *params++;
109		n -= 2;
110		break;
111	default:
112		break;
113	}
114
115	code &= (SYS_NSYSENT - 1);
116	callp += code;
117	argsize = callp->sy_argsize;
118
119	if (argsize > n * sizeof(register_t)) {
120		memcpy(args, params, n * sizeof(register_t));
121		error = copyin(MOREARGS(frame->fixreg[1]),
122		       args + n,
123		       argsize - n * sizeof(register_t));
124		if (error)
125			goto syscall_bad;
126		params = args;
127	}
128
129	if ((error = trace_enter(p, code, params, rval)) != 0)
130		goto syscall_bad;
131
132	rval[0] = 0;
133	rval[1] = 0;
134
135	error = (*callp->sy_call)(p, params, rval);
136	switch (error) {
137	case 0:
138		frame->fixreg[FIRSTARG] = rval[0];
139		frame->fixreg[FIRSTARG + 1] = rval[1];
140		frame->cr &= ~0x10000000;
141		break;
142	case ERESTART:
143		/*
144		 * Set user's pc back to redo the system call.
145		 */
146		frame->srr0 -= 4;
147		break;
148	case EJUSTRETURN:
149		/* nothing to do */
150		break;
151	default:
152syscall_bad:
153		if (p->p_emul->e_errno)
154			error = p->p_emul->e_errno[error];
155		frame->fixreg[FIRSTARG] = error;
156		frame->cr |= 0x10000000;
157		break;
158	}
159	KERNEL_PROC_UNLOCK(p);
160	trace_exit(p, code, params, rval, error);
161}
162
163void
164syscall_intern(struct proc *p)
165{
166	p->p_md.md_syscall = syscall_fancy;
167}
168
169#ifdef COMPAT_LINUX
170void
171linux_syscall_intern(struct proc *p)
172{
173	p->p_md.md_syscall = syscall_fancy;
174}
175#endif
176
177void
178child_return(void *arg)
179{
180	struct proc * const p = arg;
181	struct trapframe * const tf = trapframe(p);
182
183	KERNEL_PROC_UNLOCK(p);
184
185	tf->fixreg[FIRSTARG] = 0;
186	tf->fixreg[FIRSTARG + 1] = 1;
187	tf->cr &= ~0x10000000;
188	tf->srr1 &= ~(PSL_FP|PSL_VEC);	/* Disable FP & AltiVec, as we can't
189					   be them. */
190	p->p_addr->u_pcb.pcb_fpcpu = NULL;
191#ifdef	KTRACE
192	if (KTRPOINT(p, KTR_SYSRET)) {
193		KERNEL_PROC_LOCK(p);
194		ktrsysret(p, SYS_fork, 0, 0);
195		KERNEL_PROC_UNLOCK(p);
196	}
197#endif
198	/* Profiling?							XXX */
199	curcpu()->ci_schedstate.spc_curpriority = p->p_priority;
200}
201
202