1/*	$NetBSD: ibcs2_syscall.c,v 1.45 2009/03/14 15:36:07 dsl Exp $	*/
2
3/*-
4 * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Charles M. Hannum.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33__KERNEL_RCSID(0, "$NetBSD: ibcs2_syscall.c,v 1.45 2009/03/14 15:36:07 dsl Exp $");
34
35#if defined(_KERNEL_OPT)
36#include "opt_vm86.h"
37#endif
38
39#include <sys/param.h>
40#include <sys/systm.h>
41#include <sys/proc.h>
42#include <sys/signal.h>
43#include <sys/syscall.h>
44#include <sys/syscallvar.h>
45
46#include <uvm/uvm_extern.h>
47
48#include <machine/cpu.h>
49#include <machine/psl.h>
50#include <machine/userret.h>
51
52#include <compat/ibcs2/ibcs2_errno.h>
53#include <compat/ibcs2/ibcs2_exec.h>
54#include <compat/ibcs2/ibcs2_syscall.h>
55#include <machine/ibcs2_machdep.h>
56
57void ibcs2_syscall_plain(struct trapframe *);
58void ibcs2_syscall_fancy(struct trapframe *);
59extern struct sysent ibcs2_sysent[];
60
61void
62ibcs2_syscall_intern(struct proc *p)
63{
64
65	if (trace_is_enabled(p))
66		p->p_md.md_syscall = ibcs2_syscall_fancy;
67	else
68		p->p_md.md_syscall = ibcs2_syscall_plain;
69}
70
71/*
72 * syscall(frame):
73 *	System call request from POSIX system call gate interface to kernel.
74 * Like trap(), argument is call by reference.
75 */
76void
77ibcs2_syscall_plain(struct trapframe *frame)
78{
79	char *params;
80	const struct sysent *callp;
81	struct lwp *l;
82	int error;
83	size_t argsize;
84	register_t code, args[8], rval[2];
85
86	l = curlwp;
87	LWP_CACHE_CREDS(l, l->l_proc);
88
89	code = frame->tf_eax;
90	if (IBCS2_HIGH_SYSCALL(code))
91		code = IBCS2_CVT_HIGH_SYSCALL(code);
92	callp = ibcs2_sysent;
93	params = (char *)frame->tf_esp + sizeof(int);
94
95	switch (code) {
96	case SYS_syscall:
97		/*
98		 * Code is first argument, followed by actual args.
99		 */
100		code = fuword(params);
101		params += sizeof(int);
102		break;
103	default:
104		break;
105	}
106
107	code &= (IBCS2_SYS_NSYSENT - 1);
108	callp += code;
109	argsize = callp->sy_argsize;
110	if (argsize) {
111		error = copyin(params, (void *)args, argsize);
112		if (error)
113			goto bad;
114	}
115
116	rval[0] = 0;
117	rval[1] = 0;
118
119	error = sy_call(callp, l, args, rval);
120
121	switch (error) {
122	case 0:
123		frame->tf_eax = rval[0];
124		frame->tf_edx = rval[1];
125		frame->tf_eflags &= ~PSL_C;	/* carry bit */
126		break;
127	case ERESTART:
128		/*
129		 * The offset to adjust the PC by depends on whether we entered
130		 * the kernel through the trap or call gate.  We pushed the
131		 * size of the instruction into tf_err on entry.
132		 */
133		frame->tf_eip -= frame->tf_err;
134		break;
135	case EJUSTRETURN:
136		/* nothing to do */
137		break;
138	default:
139	bad:
140		error = native_to_ibcs2_errno[error];
141		frame->tf_eax = error;
142		frame->tf_eflags |= PSL_C;	/* carry bit */
143		break;
144	}
145
146	userret(l);
147}
148
149/*
150 * syscall(frame):
151 *	System call request from POSIX system call gate interface to kernel.
152 * Like trap(), argument is call by reference.
153 */
154void
155ibcs2_syscall_fancy(struct trapframe *frame)
156{
157	char * params;
158	const struct sysent *callp;
159	struct lwp *l;
160	int error;
161	size_t argsize;
162	register_t code, args[8], rval[2];
163
164	l = curlwp;
165	LWP_CACHE_CREDS(l, l->l_proc);
166
167	code = frame->tf_eax;
168	if (IBCS2_HIGH_SYSCALL(code))
169		code = IBCS2_CVT_HIGH_SYSCALL(code);
170	callp = ibcs2_sysent;
171	params = (char *)frame->tf_esp + sizeof(int);
172
173	switch (code) {
174	case SYS_syscall:
175		/*
176		 * Code is first argument, followed by actual args.
177		 */
178		code = fuword(params);
179		params += sizeof(int);
180		break;
181	default:
182		break;
183	}
184
185	code &= (IBCS2_SYS_NSYSENT - 1);
186	callp += code;
187	argsize = callp->sy_argsize;
188	if (argsize) {
189		error = copyin(params, (void *)args, argsize);
190		if (error)
191			goto bad;
192	}
193
194	if ((error = trace_enter(code, args, callp->sy_narg)) == 0) {
195		rval[0] = 0;
196		rval[1] = 0;
197		error = sy_call(callp, l, args, rval);
198	}
199
200	switch (error) {
201	case 0:
202		frame->tf_eax = rval[0];
203		frame->tf_edx = rval[1];
204		frame->tf_eflags &= ~PSL_C;	/* carry bit */
205		break;
206	case ERESTART:
207		/*
208		 * The offset to adjust the PC by depends on whether we entered
209		 * the kernel through the trap or call gate.  We pushed the
210		 * size of the instruction into tf_err on entry.
211		 */
212		frame->tf_eip -= frame->tf_err;
213		break;
214	case EJUSTRETURN:
215		/* nothing to do */
216		break;
217	default:
218	bad:
219		error = native_to_ibcs2_errno[error];
220		frame->tf_eax = error;
221		frame->tf_eflags |= PSL_C;	/* carry bit */
222		break;
223	}
224
225	trace_exit(code, rval, error);
226
227	userret(l);
228}
229