xref: /netbsd-src/sys/arch/m68k/m68k/m68k_syscall.c (revision 68fa58437753598de948829082f591c269b48777)
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