1 /* $NetBSD: m68k_syscall.c,v 1.55 2023/10/05 19:41:04 ad 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: m68k_syscall.c,v 1.55 2023/10/05 19:41:04 ad Exp $");
69
70 #include "opt_execfmt.h"
71 #include "opt_compat_netbsd.h"
72 #include "opt_compat_aout_m68k.h"
73
74 #include <sys/param.h>
75 #include <sys/systm.h>
76 #include <sys/proc.h>
77 #include <sys/kmem.h>
78 #include <sys/acct.h>
79 #include <sys/kernel.h>
80 #include <sys/syscall.h>
81 #include <sys/syscallvar.h>
82 #include <sys/syslog.h>
83 #include <sys/ktrace.h>
84
85 #include <machine/psl.h>
86 #include <machine/cpu.h>
87 #include <machine/reg.h>
88
89 #include <uvm/uvm_extern.h>
90
91 /*
92 * Defined in machine-specific code (usually trap.c)
93 * XXX: This will disappear when all m68k ports share common trap() code...
94 */
95 extern void machine_userret(struct lwp *, struct frame *, u_quad_t);
96
97 void syscall(register_t, struct frame);
98
99 void aoutm68k_syscall_intern(struct proc *);
100 static void syscall_plain(register_t, struct lwp *, struct frame *);
101 static void syscall_fancy(register_t, struct lwp *, struct frame *);
102
103
104 /*
105 * Process a system call.
106 */
107 void
syscall(register_t code,struct frame frame)108 syscall(register_t code, struct frame frame)
109 {
110 struct lwp *l;
111 struct proc *p;
112 u_quad_t sticks;
113
114 curcpu()->ci_data.cpu_nsyscall++;
115 if (!USERMODE(frame.f_sr))
116 panic("syscall");
117
118 l = curlwp;
119 p = l->l_proc;
120 sticks = p->p_sticks;
121 l->l_md.md_regs = frame.f_regs;
122
123 (p->p_md.md_syscall)(code, l, &frame);
124
125 machine_userret(l, &frame, sticks);
126 }
127
128 void
syscall_intern(struct proc * p)129 syscall_intern(struct proc *p)
130 {
131
132 if (trace_is_enabled(p))
133 p->p_md.md_syscall = syscall_fancy;
134 else
135 p->p_md.md_syscall = syscall_plain;
136 }
137
138 /*
139 * Not worth the effort of a whole new set of syscall_{plain,fancy} functions
140 */
141 void
aoutm68k_syscall_intern(struct proc * p)142 aoutm68k_syscall_intern(struct proc *p)
143 {
144
145 if (trace_is_enabled(p))
146 p->p_md.md_syscall = syscall_fancy;
147 else
148 p->p_md.md_syscall = syscall_plain;
149 }
150
151 static void
syscall_plain(register_t code,struct lwp * l,struct frame * frame)152 syscall_plain(register_t code, struct lwp *l, struct frame *frame)
153 {
154 char *params;
155 const struct sysent *callp;
156 int error, nsys;
157 size_t argsize;
158 register_t args[16], rval[2];
159 struct proc *p = l->l_proc;
160
161 nsys = p->p_emul->e_nsysent;
162 callp = p->p_emul->e_sysent;
163
164 params = (char *)frame->f_regs[SP] + sizeof(int);
165
166 switch (code) {
167 case SYS_syscall:
168 /*
169 * Code is first argument, followed by actual args.
170 */
171 error = ufetch_long((void *)params, (u_long *)&code);
172 if (error)
173 goto bad;
174 params += sizeof(int);
175 #if defined(COMPAT_13) || defined(COMPAT_16)
176 /*
177 * XXX sigreturn requires special stack manipulation
178 * that is only done if entered via the sigreturn
179 * trap. Cannot allow it here so make sure we fail.
180 */
181 switch (code) {
182 #ifdef COMPAT_13
183 case SYS_compat_13_sigreturn13:
184 #endif
185 #ifdef COMPAT_16
186 case SYS_compat_16___sigreturn14:
187 #endif
188 code = nsys;
189 break;
190 }
191 #endif
192 break;
193 case SYS___syscall:
194 /*
195 * Like syscall, but code is a quad, so as to maintain
196 * quad alignment for the rest of the arguments.
197 */
198 error = ufetch_long((void *)(params +
199 _QUAD_LOWWORD * sizeof(int)),
200 (u_long *)&code);
201 if (error)
202 goto bad;
203 params += sizeof(quad_t);
204 break;
205 default:
206 break;
207 }
208
209 if (code < 0 || code >= nsys)
210 callp += p->p_emul->e_nosys; /* illegal */
211 else
212 callp += code;
213
214 argsize = callp->sy_argsize;
215 if (argsize) {
216 error = copyin(params, (void *)args, argsize);
217 if (error)
218 goto bad;
219 }
220
221 rval[0] = 0;
222 rval[1] = frame->f_regs[D1];
223 error = sy_call(callp, l, args, rval);
224
225 switch (error) {
226 case 0:
227 /*
228 * Reinitialize proc pointer `p' as it may be different
229 * if this is a child returning from fork syscall.
230 */
231 l = curlwp;
232 p = l->l_proc;
233 frame->f_regs[D0] = rval[0];
234 frame->f_regs[D1] = rval[1];
235 frame->f_sr &= ~PSL_C; /* carry bit */
236 #ifdef COMPAT_50
237 /*
238 * Starting with the 5.0 release all libc assembler
239 * stubs properly handle returning pointers in %a0
240 * themselves, so no need to copy the syscall return
241 * value there. However, -current binaries post 4.0
242 * but pre-5.0 might still require this copy, so we
243 * select this behaviour based on COMPAT_50 as we have
244 * no equivalent for the exact in-between version.
245 */
246
247 /*
248 * Some pre-m68k ELF libc assembler stubs assume
249 * %a0 is preserved across system calls...
250 */
251 if (p->p_emul == &emul_netbsd)
252 frame->f_regs[A0] = rval[0];
253 #endif
254 break;
255 case ERESTART:
256 /*
257 * We always enter through a `trap' instruction, which is 2
258 * bytes, so adjust the pc by that amount.
259 */
260 frame->f_pc = frame->f_pc - 2;
261 break;
262 case EJUSTRETURN:
263 /* nothing to do */
264 break;
265 default:
266 bad:
267 /*
268 * XXX: SVR4 uses this code-path, so we may have
269 * to translate errno. XXX OBSOLETE
270 */
271 if (p->p_emul->e_errno)
272 error = p->p_emul->e_errno[error];
273 frame->f_regs[D0] = error;
274 frame->f_sr |= PSL_C; /* carry bit */
275 break;
276 }
277 }
278
279 static void
syscall_fancy(register_t code,struct lwp * l,struct frame * frame)280 syscall_fancy(register_t code, struct lwp *l, struct frame *frame)
281 {
282 char *params;
283 const struct sysent *callp;
284 int error, nsys;
285 size_t argsize;
286 register_t args[16], rval[2];
287 struct proc *p = l->l_proc;
288
289 nsys = p->p_emul->e_nsysent;
290 callp = p->p_emul->e_sysent;
291
292 params = (char *)frame->f_regs[SP] + sizeof(int);
293
294 switch (code) {
295 case SYS_syscall:
296 /*
297 * Code is first argument, followed by actual args.
298 */
299 error = ufetch_long((void *)params, (u_long *)&code);
300 if (error)
301 goto bad;
302 params += sizeof(int);
303 #if defined(COMPAT_13) || defined(COMPAT_16)
304 /*
305 * XXX sigreturn requires special stack manipulation
306 * that is only done if entered via the sigreturn
307 * trap. Cannot allow it here so make sure we fail.
308 */
309 switch (code) {
310 #ifdef COMPAT_13
311 case SYS_compat_13_sigreturn13:
312 #endif
313 #ifdef COMPAT_16
314 case SYS_compat_16___sigreturn14:
315 #endif
316 code = nsys;
317 break;
318 }
319 #endif
320 break;
321 case SYS___syscall:
322 /*
323 * Like syscall, but code is a quad, so as to maintain
324 * quad alignment for the rest of the arguments.
325 */
326 error = ufetch_long((void *)(params +
327 _QUAD_LOWWORD * sizeof(int)),
328 (u_long *)&code);
329 if (error)
330 goto bad;
331 params += sizeof(quad_t);
332 break;
333 default:
334 break;
335 }
336
337 if (code < 0 || code >= nsys)
338 callp += p->p_emul->e_nosys; /* illegal */
339 else
340 callp += code;
341
342 argsize = callp->sy_argsize;
343 if (argsize) {
344 error = copyin(params, (void *)args, argsize);
345 if (error)
346 goto bad;
347 }
348
349 if ((error = trace_enter(code, callp, args)) != 0)
350 goto out;
351
352 rval[0] = 0;
353 rval[1] = frame->f_regs[D1];
354 error = sy_call(callp, l, args, rval);
355 out:
356 switch (error) {
357 case 0:
358 /*
359 * Reinitialize lwp/proc pointers as they may be different
360 * if this is a child returning from fork syscall.
361 */
362 l = curlwp;
363 p = l->l_proc;
364 frame->f_regs[D0] = rval[0];
365 frame->f_regs[D1] = rval[1];
366 frame->f_sr &= ~PSL_C; /* carry bit */
367 #ifdef COMPAT_50
368 /* see syscall_plain for a comment explaining this */
369
370 /*
371 * Some pre-m68k ELF libc assembler stubs assume
372 * %a0 is preserved across system calls...
373 */
374 if (p->p_emul == &emul_netbsd)
375 frame->f_regs[A0] = rval[0];
376 #endif
377 break;
378 case ERESTART:
379 /*
380 * We always enter through a `trap' instruction, which is 2
381 * bytes, so adjust the pc by that amount.
382 */
383 frame->f_pc = frame->f_pc - 2;
384 break;
385 case EJUSTRETURN:
386 /* nothing to do */
387 break;
388 default:
389 bad:
390 /*
391 * XXX: SVR4 uses this code-path, so we may have
392 * to translate errno.
393 */
394 if (p->p_emul->e_errno)
395 error = p->p_emul->e_errno[error];
396 frame->f_regs[D0] = error;
397 frame->f_sr |= PSL_C; /* carry bit */
398 break;
399 }
400
401 trace_exit(code, callp, args, rval, error);
402 }
403
404 void
md_child_return(struct lwp * l)405 md_child_return(struct lwp *l)
406 {
407 /* See cpu_lwp_fork() */
408 struct frame *f = (struct frame *)l->l_md.md_regs;
409
410 f->f_regs[D0] = 0;
411 f->f_sr &= ~PSL_C;
412 f->f_format = FMT0;
413
414 machine_userret(l, f, 0);
415 }
416
417 /*
418 * Start a new LWP
419 */
420 void
startlwp(void * arg)421 startlwp(void *arg)
422 {
423 ucontext_t *uc = arg;
424 lwp_t *l = curlwp;
425 struct frame *f = (struct frame *)l->l_md.md_regs;
426 int error __diagused;
427
428 f->f_regs[D0] = 0;
429 f->f_sr &= ~PSL_C;
430 f->f_format = FMT0;
431
432 error = cpu_setmcontext(l, &uc->uc_mcontext, uc->uc_flags);
433 KASSERT(error == 0);
434
435 kmem_free(uc, sizeof(ucontext_t));
436 machine_userret(l, f, 0);
437 }
438
439 /*
440 * Process the tail end of a posix_spawn() for the child.
441 */
442 void
cpu_spawn_return(struct lwp * l)443 cpu_spawn_return(struct lwp *l)
444 {
445 struct frame *f = (struct frame *)l->l_md.md_regs;
446
447 machine_userret(l, f, 0);
448 }
449