syscall.c revision 1.5
1205408Srdivacky/*	$NetBSD: syscall.c,v 1.5 2002/10/30 06:37:38 manu Exp $	*/
2205408Srdivacky
3205408Srdivacky/*
4205408Srdivacky * Copyright (C) 2002 Matt Thomas
5205408Srdivacky * Copyright (C) 1995, 1996 Wolfgang Solfrank.
6205408Srdivacky * Copyright (C) 1995, 1996 TooLs GmbH.
7205408Srdivacky * All rights reserved.
8205408Srdivacky *
9205408Srdivacky * Redistribution and use in source and binary forms, with or without
10205408Srdivacky * modification, are permitted provided that the following conditions
11205408Srdivacky * are met:
12205408Srdivacky * 1. Redistributions of source code must retain the above copyright
13205408Srdivacky *    notice, this list of conditions and the following disclaimer.
14205408Srdivacky * 2. Redistributions in binary form must reproduce the above copyright
15205408Srdivacky *    notice, this list of conditions and the following disclaimer in the
16205408Srdivacky *    documentation and/or other materials provided with the distribution.
17205408Srdivacky * 3. All advertising materials mentioning features or use of this software
18205408Srdivacky *    must display the following acknowledgement:
19205408Srdivacky *	This product includes software developed by TooLs GmbH.
20205408Srdivacky * 4. The name of TooLs GmbH may not be used to endorse or promote products
21205408Srdivacky *    derived from this software without specific prior written permission.
22205408Srdivacky *
23205408Srdivacky * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
24205408Srdivacky * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25205408Srdivacky * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26205408Srdivacky * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27205408Srdivacky * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28205408Srdivacky * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
29205408Srdivacky * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30205408Srdivacky * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31205408Srdivacky * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32205408Srdivacky * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33205408Srdivacky */
34205408Srdivacky
35205408Srdivacky#include "opt_altivec.h"
36205408Srdivacky#include "opt_ktrace.h"
37205408Srdivacky#include "opt_systrace.h"
38205408Srdivacky#include "opt_compat_linux.h"
39205408Srdivacky#include "opt_multiprocessor.h"
40205408Srdivacky
41205408Srdivacky#include <sys/param.h>
42205408Srdivacky#include <sys/proc.h>
43205408Srdivacky#include <sys/reboot.h>
44205408Srdivacky#include <sys/syscall.h>
45205408Srdivacky#include <sys/systm.h>
46205408Srdivacky#include <sys/user.h>
47205408Srdivacky#ifdef KTRACE
48205408Srdivacky#include <sys/ktrace.h>
49205408Srdivacky#endif
50205408Srdivacky#ifdef SYSTRACE
51205408Srdivacky#include <sys/systrace.h>
52205408Srdivacky#endif
53205408Srdivacky
54205408Srdivacky#include <uvm/uvm_extern.h>
55205408Srdivacky
56205408Srdivacky#include <powerpc/userret.h>
57205408Srdivacky#include <machine/cpu.h>
58205408Srdivacky#include <machine/frame.h>
59205408Srdivacky
60205408Srdivacky#ifdef COMPAT_LINUX
61205408Srdivacky#include <compat/linux/common/linux_types.h>
62205408Srdivacky#include <compat/linux/common/linux_errno.h>
63205408Srdivacky#include <compat/linux/linux_syscall.h>
64205408Srdivacky#include <compat/linux/common/linux_signal.h>
65205408Srdivacky#include <compat/linux/common/linux_siginfo.h>
66205408Srdivacky#include <compat/linux/arch/powerpc/linux_siginfo.h>
67205408Srdivacky#include <compat/linux/arch/powerpc/linux_machdep.h>
68205408Srdivacky#endif
69205408Srdivacky
70205408Srdivacky#define	FIRSTARG	3		/* first argument is in reg 3 */
71205408Srdivacky#define	NARGREG		8		/* 8 args are in registers */
72205408Srdivacky#define	MOREARGS(sp)	((caddr_t)((uintptr_t)(sp) + 8)) /* more args go here */
73205408Srdivacky
74205408Srdivacky#ifndef EMULNAME
75205408Srdivacky#define EMULNAME(x)	(x)
76205408Srdivacky#endif
77205408Srdivacky
78205408Srdivackyvoid EMULNAME(syscall_plain)(struct trapframe *frame);
79205408Srdivackyvoid EMULNAME(syscall_fancy)(struct trapframe *frame);
80205408Srdivacky
81205408Srdivackyvoid
82205408SrdivackyEMULNAME(syscall_plain)(struct trapframe *frame)
83205408Srdivacky{
84205408Srdivacky	struct proc *p = curproc;
85205408Srdivacky	const struct sysent *callp;
86205408Srdivacky	size_t argsize;
87205408Srdivacky	register_t code;
88205408Srdivacky	register_t *params, rval[2];
89205408Srdivacky	register_t args[10];
90205408Srdivacky	int error;
91205408Srdivacky	int n;
92205408Srdivacky
93205408Srdivacky	curcpu()->ci_ev_scalls.ev_count++;
94205408Srdivacky
95205408Srdivacky	code = frame->fixreg[0];
96205408Srdivacky
97205408Srdivacky	callp = p->p_emul->e_sysent;
98205408Srdivacky	params = frame->fixreg + FIRSTARG;
99205408Srdivacky	n = NARGREG;
100205408Srdivacky
101205408Srdivacky	switch (code) {
102205408Srdivacky	case SYS_syscall:
103205408Srdivacky		/*
104205408Srdivacky		 * code is first argument,
105205408Srdivacky		 * followed by actual args.
106205408Srdivacky		 */
107205408Srdivacky		code = *params++;
108205408Srdivacky		n -= 1;
109205408Srdivacky		break;
110205408Srdivacky	case SYS___syscall:
111205408Srdivacky		params++;
112205408Srdivacky		code = *params++;
113205408Srdivacky		n -= 2;
114205408Srdivacky		break;
115205408Srdivacky	default:
116205408Srdivacky		break;
117205408Srdivacky	}
118205408Srdivacky
119205408Srdivacky	code &= (SYS_NSYSENT - 1);
120205408Srdivacky	callp += code;
121205408Srdivacky	argsize = callp->sy_argsize;
122205408Srdivacky
123205408Srdivacky	if (argsize > n * sizeof(register_t)) {
124205408Srdivacky		memcpy(args, params, n * sizeof(register_t));
125205408Srdivacky		KERNEL_PROC_LOCK(p);
126205408Srdivacky		error = copyin(MOREARGS(frame->fixreg[1]),
127205408Srdivacky		       args + n,
128205408Srdivacky		       argsize - n * sizeof(register_t));
129205408Srdivacky		KERNEL_PROC_UNLOCK(p);
130205408Srdivacky		if (error)
131205408Srdivacky			goto syscall_bad;
132205408Srdivacky		params = args;
133205408Srdivacky	}
134205408Srdivacky
135205408Srdivacky	rval[0] = 0;
136205408Srdivacky	rval[1] = 0;
137205408Srdivacky
138205408Srdivacky	if ((callp->sy_flags & SYCALL_MPSAFE) == 0) {
139205408Srdivacky		KERNEL_PROC_LOCK(p);
140205408Srdivacky	}
141205408Srdivacky
142205408Srdivacky	error = (*callp->sy_call)(p, params, rval);
143205408Srdivacky
144205408Srdivacky	if ((callp->sy_flags & SYCALL_MPSAFE) == 0) {
145205408Srdivacky		KERNEL_PROC_UNLOCK(p);
146205408Srdivacky	}
147205408Srdivacky
148205408Srdivacky	switch (error) {
149205408Srdivacky	case 0:
150205408Srdivacky		frame->fixreg[FIRSTARG] = rval[0];
151205408Srdivacky		frame->fixreg[FIRSTARG + 1] = rval[1];
152205408Srdivacky		frame->cr &= ~0x10000000;
153205408Srdivacky		break;
154205408Srdivacky	case ERESTART:
155205408Srdivacky		/*
156205408Srdivacky		 * Set user's pc back to redo the system call.
157205408Srdivacky		 */
158205408Srdivacky		frame->srr0 -= 4;
159205408Srdivacky		break;
160205408Srdivacky	case EJUSTRETURN:
161205408Srdivacky		/* nothing to do */
162205408Srdivacky		break;
163205408Srdivacky	default:
164205408Srdivackysyscall_bad:
165205408Srdivacky		if (p->p_emul->e_errno)
166205408Srdivacky			error = p->p_emul->e_errno[error];
167205408Srdivacky		frame->fixreg[FIRSTARG] = error;
168205408Srdivacky		frame->cr |= 0x10000000;
169205408Srdivacky		break;
170205408Srdivacky	}
171205408Srdivacky	userret(p, frame);
172205408Srdivacky}
173205408Srdivacky
174205408Srdivackyvoid
175205408SrdivackyEMULNAME(syscall_fancy)(struct trapframe *frame)
176205408Srdivacky{
177205408Srdivacky	struct proc *p = curproc;
178205408Srdivacky	const struct sysent *callp;
179205408Srdivacky	size_t argsize;
180205408Srdivacky	register_t code;
181205408Srdivacky	register_t *params, rval[2];
182205408Srdivacky	register_t args[10];
183205408Srdivacky	int error;
184205408Srdivacky	int n;
185205408Srdivacky
186205408Srdivacky	KERNEL_PROC_LOCK(p);
187205408Srdivacky	curcpu()->ci_ev_scalls.ev_count++;
188205408Srdivacky
189205408Srdivacky	code = frame->fixreg[0];
190205408Srdivacky	callp = p->p_emul->e_sysent;
191205408Srdivacky	params = frame->fixreg + FIRSTARG;
192205408Srdivacky	n = NARGREG;
193205408Srdivacky
194205408Srdivacky	switch (code) {
195205408Srdivacky	case SYS_syscall:
196205408Srdivacky		/*
197205408Srdivacky		 * code is first argument,
198205408Srdivacky		 * followed by actual args.
199205408Srdivacky		 */
200205408Srdivacky		code = *params++;
201205408Srdivacky		n -= 1;
202205408Srdivacky		break;
203205408Srdivacky	case SYS___syscall:
204205408Srdivacky		params++;
205205408Srdivacky		code = *params++;
206205408Srdivacky		n -= 2;
207205408Srdivacky		break;
208205408Srdivacky	default:
209205408Srdivacky		break;
210205408Srdivacky	}
211205408Srdivacky
212205408Srdivacky	code &= (SYS_NSYSENT - 1);
213205408Srdivacky	callp += code;
214205408Srdivacky	argsize = callp->sy_argsize;
215205408Srdivacky
216205408Srdivacky	if (argsize > n * sizeof(register_t)) {
217205408Srdivacky		memcpy(args, params, n * sizeof(register_t));
218205408Srdivacky		error = copyin(MOREARGS(frame->fixreg[1]),
219205408Srdivacky		       args + n,
220205408Srdivacky		       argsize - n * sizeof(register_t));
221205408Srdivacky		if (error)
222205408Srdivacky			goto syscall_bad;
223205408Srdivacky		params = args;
224205408Srdivacky	}
225205408Srdivacky
226205408Srdivacky	if ((error = trace_enter(p, code, params, rval)) != 0)
227205408Srdivacky		goto syscall_bad;
228205408Srdivacky
229205408Srdivacky	rval[0] = 0;
230205408Srdivacky	rval[1] = 0;
231205408Srdivacky
232205408Srdivacky	error = (*callp->sy_call)(p, params, rval);
233205408Srdivacky	switch (error) {
234205408Srdivacky	case 0:
235205408Srdivacky		frame->fixreg[FIRSTARG] = rval[0];
236205408Srdivacky		frame->fixreg[FIRSTARG + 1] = rval[1];
237205408Srdivacky		frame->cr &= ~0x10000000;
238205408Srdivacky		break;
239205408Srdivacky	case ERESTART:
240205408Srdivacky		/*
241205408Srdivacky		 * Set user's pc back to redo the system call.
242205408Srdivacky		 */
243205408Srdivacky		frame->srr0 -= 4;
244205408Srdivacky		break;
245205408Srdivacky	case EJUSTRETURN:
246205408Srdivacky		/* nothing to do */
247205408Srdivacky		break;
248205408Srdivacky	default:
249205408Srdivackysyscall_bad:
250205408Srdivacky		if (p->p_emul->e_errno)
251205408Srdivacky			error = p->p_emul->e_errno[error];
252205408Srdivacky		frame->fixreg[FIRSTARG] = error;
253205408Srdivacky		frame->cr |= 0x10000000;
254205408Srdivacky		break;
255205408Srdivacky	}
256205408Srdivacky	KERNEL_PROC_UNLOCK(p);
257205408Srdivacky	trace_exit(p, code, params, rval, error);
258205408Srdivacky	userret(p, frame);
259205408Srdivacky}
260205408Srdivacky
261205408Srdivackyvoid
262205408SrdivackyEMULNAME(syscall_intern)(struct proc *p)
263205408Srdivacky{
264205408Srdivacky#ifdef KTRACE
265205408Srdivacky	if (p->p_traceflag & (KTRFAC_SYSCALL | KTRFAC_SYSRET)) {
266205408Srdivacky		p->p_md.md_syscall = EMULNAME(syscall_fancy);
267205408Srdivacky		return;
268205408Srdivacky	}
269205408Srdivacky#endif
270205408Srdivacky#ifdef SYSTRACE
271205408Srdivacky	if (ISSET(p->p_flag, P_SYSTRACE)) {
272205408Srdivacky		p->p_md.md_syscall = EMULNAME(syscall_fancy);
273205408Srdivacky		return;
274205408Srdivacky	}
275205408Srdivacky#endif
276205408Srdivacky	p->p_md.md_syscall = EMULNAME(syscall_plain);
277205408Srdivacky}
278205408Srdivacky
279205408Srdivacky