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