1 /* $NetBSD: sunos_syscall.c,v 1.24 2019/04/06 03:06:26 thorpej 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: sunos_syscall.c,v 1.24 2019/04/06 03:06:26 thorpej 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 #include <compat/sunos/sunos_syscall.h>
90 #include <compat/sunos/sunos_exec.h>
91
92 void sunos_syscall_intern(struct proc *);
93 static void sunos_syscall_plain(register_t, struct lwp *, struct frame *);
94 static void sunos_syscall_fancy(register_t, struct lwp *, struct frame *);
95
96 void
sunos_syscall_intern(struct proc * p)97 sunos_syscall_intern(struct proc *p)
98 {
99
100 if (trace_is_enabled(p))
101 p->p_md.md_syscall = sunos_syscall_fancy;
102 else
103 p->p_md.md_syscall = sunos_syscall_plain;
104 }
105
106 static void
sunos_syscall_plain(register_t code,struct lwp * l,struct frame * frame)107 sunos_syscall_plain(register_t code, struct lwp *l, struct frame *frame)
108 {
109 struct proc *p = l->l_proc;
110 char *params;
111 const struct sysent *callp;
112 int error, nsys;
113 size_t argsize;
114 register_t args[16], rval[2];
115
116 nsys = p->p_emul->e_nsysent;
117 callp = p->p_emul->e_sysent;
118
119 /*
120 * SunOS passes the syscall-number on the stack, whereas
121 * BSD passes it in D0. So, we have to get the real "code"
122 * from the stack, and clean up the stack, as SunOS glue
123 * code assumes the kernel pops the syscall argument the
124 * glue pushed on the stack. Sigh...
125 */
126 error = ufetch_long((void *)frame->f_regs[SP], (u_long *)&code);
127 if (error)
128 goto bad;
129
130 /*
131 * XXX
132 * Don't do this for sunos_sigreturn, as there's no stored pc
133 * on the stack to skip, the argument follows the syscall
134 * number without a gap.
135 */
136 if (code != SUNOS_SYS_sigreturn) {
137 frame->f_regs[SP] += sizeof (int);
138 /*
139 * remember that we adjusted the SP,
140 * might have to undo this if the system call
141 * returns ERESTART.
142 */
143 l->l_md.md_flags |= MDL_STACKADJ;
144 } else
145 l->l_md.md_flags &= ~MDL_STACKADJ;
146
147 params = (char *)frame->f_regs[SP] + sizeof(int);
148
149 switch (code) {
150 case SUNOS_SYS_syscall:
151 /*
152 * Code is first argument, followed by actual args.
153 */
154 error = ufetch_long((void *)params, (u_long *)&code);
155 if (error)
156 goto bad;
157 params += sizeof(int);
158 break;
159 default:
160 break;
161 }
162
163 if (code < 0 || code >= nsys)
164 callp += p->p_emul->e_nosys; /* illegal */
165 else
166 callp += code;
167
168 argsize = callp->sy_argsize;
169 if (argsize) {
170 error = copyin(params, (void *)args, argsize);
171 if (error)
172 goto bad;
173 }
174
175 rval[0] = 0;
176 rval[1] = frame->f_regs[D1];
177 error = sy_call(callp, l, args, rval);
178
179 switch (error) {
180 case 0:
181 /*
182 * Reinitialize proc pointer `p' as it may be different
183 * if this is a child returning from fork syscall.
184 */
185 p = curproc;
186 frame->f_regs[D0] = rval[0];
187 frame->f_regs[D1] = rval[1];
188 frame->f_sr &= ~PSL_C; /* carry bit */
189 break;
190 case ERESTART:
191 /*
192 * We always enter through a `trap' instruction, which is 2
193 * bytes, so adjust the pc by that amount.
194 */
195 frame->f_pc = frame->f_pc - 2;
196 break;
197 case EJUSTRETURN:
198 /* nothing to do */
199 break;
200 default:
201 bad:
202 frame->f_regs[D0] = error;
203 frame->f_sr |= PSL_C; /* carry bit */
204 break;
205 }
206
207 /* need new p-value for this */
208 if (l->l_md.md_flags & MDL_STACKADJ) {
209 l->l_md.md_flags &= ~MDL_STACKADJ;
210 if (error == ERESTART)
211 frame->f_regs[SP] -= sizeof (int);
212 }
213 }
214
215 static void
sunos_syscall_fancy(register_t code,struct lwp * l,struct frame * frame)216 sunos_syscall_fancy(register_t code, struct lwp *l, struct frame *frame)
217 {
218 struct proc *p = l->l_proc;
219 char *params;
220 const struct sysent *callp;
221 int error, nsys;
222 size_t argsize;
223 register_t args[16], rval[2];
224
225 nsys = p->p_emul->e_nsysent;
226 callp = p->p_emul->e_sysent;
227
228 /*
229 * SunOS passes the syscall-number on the stack, whereas
230 * BSD passes it in D0. So, we have to get the real "code"
231 * from the stack, and clean up the stack, as SunOS glue
232 * code assumes the kernel pops the syscall argument the
233 * glue pushed on the stack. Sigh...
234 */
235 error = ufetch_long((void *)frame->f_regs[SP], (u_long *)&code);
236 if (error)
237 goto bad;
238
239 /*
240 * XXX
241 * Don't do this for sunos_sigreturn, as there's no stored pc
242 * on the stack to skip, the argument follows the syscall
243 * number without a gap.
244 */
245 if (code != SUNOS_SYS_sigreturn) {
246 frame->f_regs[SP] += sizeof (int);
247 /*
248 * remember that we adjusted the SP,
249 * might have to undo this if the system call
250 * returns ERESTART.
251 */
252 l->l_md.md_flags |= MDL_STACKADJ;
253 } else
254 l->l_md.md_flags &= ~MDL_STACKADJ;
255
256 params = (char *)frame->f_regs[SP] + sizeof(int);
257
258 switch (code) {
259 case SUNOS_SYS_syscall:
260 /*
261 * Code is first argument, followed by actual args.
262 */
263 error = ufetch_long((void *)params, (u_long *)&code);
264 if (error)
265 goto bad;
266 params += sizeof(int);
267 break;
268 default:
269 break;
270 }
271
272 if (code < 0 || code >= nsys)
273 callp += p->p_emul->e_nosys; /* illegal */
274 else
275 callp += code;
276
277 argsize = callp->sy_argsize;
278 if (argsize) {
279 error = copyin(params, (void *)args, argsize);
280 if (error)
281 goto bad;
282 }
283
284 if ((error = trace_enter(code, callp, args)) != 0)
285 goto out;
286
287 rval[0] = 0;
288 rval[1] = frame->f_regs[D1];
289 error = sy_call(callp, l, args, rval);
290 out:
291 switch (error) {
292 case 0:
293 /*
294 * Reinitialize proc pointer `p' as it may be different
295 * if this is a child returning from fork syscall.
296 */
297 p = curproc;
298 frame->f_regs[D0] = rval[0];
299 frame->f_regs[D1] = rval[1];
300 frame->f_sr &= ~PSL_C; /* carry bit */
301 break;
302 case ERESTART:
303 /*
304 * We always enter through a `trap' instruction, which is 2
305 * bytes, so adjust the pc by that amount.
306 */
307 frame->f_pc = frame->f_pc - 2;
308 break;
309 case EJUSTRETURN:
310 /* nothing to do */
311 break;
312 default:
313 bad:
314 frame->f_regs[D0] = error;
315 frame->f_sr |= PSL_C; /* carry bit */
316 break;
317 }
318
319 /* need new p-value for this */
320 if (l->l_md.md_flags & MDL_STACKADJ) {
321 l->l_md.md_flags &= ~MDL_STACKADJ;
322 if (error == ERESTART)
323 frame->f_regs[SP] -= sizeof (int);
324 }
325
326 trace_exit(code, callp, args, rval, error);
327 }
328