1 /* $NetBSD: linux_syscall.c,v 1.24 2015/03/07 18:54:57 christos Exp $ */
2
3 /*-
4 * Portions Copyright (c) 2000 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /*
30 * Copyright (c) 1988 University of Utah.
31 * Copyright (c) 1982, 1986, 1990, 1993
32 * The Regents of the University of California. All rights reserved.
33 *
34 * This code is derived from software contributed to Berkeley by
35 * the Systems Programming Group of the University of Utah Computer
36 * Science Department.
37 *
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
40 * are met:
41 * 1. Redistributions of source code must retain the above copyright
42 * notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 * notice, this list of conditions and the following disclaimer in the
45 * documentation and/or other materials provided with the distribution.
46 * 3. Neither the name of the University nor the names of its contributors
47 * may be used to endorse or promote products derived from this software
48 * without specific prior written permission.
49 *
50 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
51 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
54 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60 * SUCH DAMAGE.
61 *
62 * from: Utah $Hdr: trap.c 1.37 92/12/20$
63 *
64 * @(#)trap.c 8.5 (Berkeley) 1/4/94
65 */
66
67 #include <sys/cdefs.h>
68 __KERNEL_RCSID(0, "$NetBSD: linux_syscall.c,v 1.24 2015/03/07 18:54:57 christos Exp $");
69
70 #ifdef _KERNEL_OPT
71 #include "opt_execfmt.h"
72 #endif
73
74 #include <sys/param.h>
75 #include <sys/systm.h>
76 #include <sys/proc.h>
77 #include <sys/acct.h>
78 #include <sys/kernel.h>
79 #include <sys/syscall.h>
80 #include <sys/syscallvar.h>
81 #include <sys/syslog.h>
82
83 #include <machine/psl.h>
84 #include <machine/cpu.h>
85 #include <machine/reg.h>
86
87 #include <uvm/uvm_extern.h>
88
89 void linux_syscall_intern(struct proc *);
90 static void linux_syscall_plain(register_t, struct lwp *, struct frame *);
91 static void linux_syscall_fancy(register_t, struct lwp *, struct frame *);
92
93 void
linux_syscall_intern(struct proc * p)94 linux_syscall_intern(struct proc *p)
95 {
96
97 if (trace_is_enabled(p))
98 p->p_md.md_syscall = linux_syscall_fancy;
99 else
100 p->p_md.md_syscall = linux_syscall_plain;
101 }
102
103 static void
linux_syscall_plain(register_t code,struct lwp * l,struct frame * frame)104 linux_syscall_plain(register_t code, struct lwp *l, struct frame *frame)
105 {
106 struct proc *p = l->l_proc;
107 const struct sysent *callp;
108 int error, nsys;
109 size_t argsize;
110 register_t args[8], rval[2];
111
112 nsys = p->p_emul->e_nsysent;
113 callp = p->p_emul->e_sysent;
114
115 if (code < 0 || code >= nsys)
116 callp += p->p_emul->e_nosys; /* illegal */
117 else
118 callp += code;
119
120 argsize = callp->sy_argsize;
121
122 /*
123 * Linux passes the args in d1-d5
124 */
125 switch (argsize) {
126 case 20:
127 args[4] = frame->f_regs[D5];
128 case 16:
129 args[3] = frame->f_regs[D4];
130 case 12:
131 args[2] = frame->f_regs[D3];
132 case 8:
133 args[1] = frame->f_regs[D2];
134 case 4:
135 args[0] = frame->f_regs[D1];
136 case 0:
137 break;
138 default:
139 panic("linux syscall %d weird argsize %d",
140 code, argsize);
141 break;
142 }
143
144 rval[0] = 0;
145 rval[1] = frame->f_regs[D1];
146 error = sy_call(callp, l, args, rval);
147
148 switch (error) {
149 case 0:
150 /*
151 * Reinitialize proc pointer `p' as it may be different
152 * if this is a child returning from fork syscall.
153 */
154 p = curproc;
155 frame->f_regs[D0] = rval[0];
156 frame->f_regs[D1] = rval[1];
157 frame->f_sr &= ~PSL_C; /* carry bit */
158 break;
159 case ERESTART:
160 /*
161 * We always enter through a `trap' instruction, which is 2
162 * bytes, so adjust the pc by that amount.
163 */
164 frame->f_pc = frame->f_pc - 2;
165 break;
166 case EJUSTRETURN:
167 /* nothing to do */
168 break;
169 default:
170 if (p->p_emul->e_errno)
171 error = p->p_emul->e_errno[error];
172 frame->f_regs[D0] = error;
173 frame->f_sr |= PSL_C; /* carry bit */
174 break;
175 }
176 }
177
178 static void
linux_syscall_fancy(register_t code,struct lwp * l,struct frame * frame)179 linux_syscall_fancy(register_t code, struct lwp *l, struct frame *frame)
180 {
181 struct proc *p = l->l_proc;
182 const struct sysent *callp;
183 int error, nsys;
184 size_t argsize;
185 register_t args[8], rval[2];
186
187 nsys = p->p_emul->e_nsysent;
188 callp = p->p_emul->e_sysent;
189
190 if (code < 0 || code >= nsys)
191 callp += p->p_emul->e_nosys; /* illegal */
192 else
193 callp += code;
194
195 argsize = callp->sy_argsize;
196
197 /*
198 * Linux passes the args in d1-d5
199 */
200 switch (argsize) {
201 case 20:
202 args[4] = frame->f_regs[D5];
203 case 16:
204 args[3] = frame->f_regs[D4];
205 case 12:
206 args[2] = frame->f_regs[D3];
207 case 8:
208 args[1] = frame->f_regs[D2];
209 case 4:
210 args[0] = frame->f_regs[D1];
211 case 0:
212 break;
213 default:
214 panic("linux syscall %d weird argsize %d",
215 code, argsize);
216 break;
217 }
218
219 if ((error = trace_enter(code, callp, args)) != 0)
220 goto out;
221
222 rval[0] = 0;
223 rval[1] = frame->f_regs[D1];
224 error = sy_call(callp, l, args, rval);
225 out:
226 switch (error) {
227 case 0:
228 /*
229 * Reinitialize proc pointer `p' as it may be different
230 * if this is a child returning from fork syscall.
231 */
232 p = curproc;
233 frame->f_regs[D0] = rval[0];
234 frame->f_regs[D1] = rval[1];
235 frame->f_sr &= ~PSL_C; /* carry bit */
236 break;
237 case ERESTART:
238 /*
239 * We always enter through a `trap' instruction, which is 2
240 * bytes, so adjust the pc by that amount.
241 */
242 frame->f_pc = frame->f_pc - 2;
243 break;
244 case EJUSTRETURN:
245 /* nothing to do */
246 break;
247 default:
248 if (p->p_emul->e_errno)
249 error = p->p_emul->e_errno[error];
250 frame->f_regs[D0] = error;
251 frame->f_sr |= PSL_C; /* carry bit */
252 break;
253 }
254
255 trace_exit(code, callp, args, rval, error);
256 }
257