Home | History | Annotate | Line # | Download | only in m68k
      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
    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
    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
    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
    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
    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
    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
    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
    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