Home | History | Annotate | Line # | Download | only in arm
      1 /*	$NetBSD: syscall.c,v 1.69 2023/10/05 19:41:03 ad Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2000, 2003 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Charles M. Hannum.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 /*
     33  * Copyright (c) 1994-1998 Mark Brinicombe.
     34  * Copyright (c) 1994 Brini.
     35  * All rights reserved.
     36  *
     37  * This code is derived from software written for Brini by Mark Brinicombe
     38  *
     39  * Redistribution and use in source and binary forms, with or without
     40  * modification, are permitted provided that the following conditions
     41  * are met:
     42  * 1. Redistributions of source code must retain the above copyright
     43  *    notice, this list of conditions and the following disclaimer.
     44  * 2. Redistributions in binary form must reproduce the above copyright
     45  *    notice, this list of conditions and the following disclaimer in the
     46  *    documentation and/or other materials provided with the distribution.
     47  * 3. All advertising materials mentioning features or use of this software
     48  *    must display the following acknowledgement:
     49  *	This product includes software developed by Mark Brinicombe
     50  *	for the NetBSD Project.
     51  * 4. The name of the company nor the name of the author may be used to
     52  *    endorse or promote products derived from this software without specific
     53  *    prior written permission.
     54  *
     55  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
     56  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     57  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     58  * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
     59  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     60  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     61  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     62  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     63  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     64  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     65  * SUCH DAMAGE.
     66  *
     67  * syscall entry handling
     68  *
     69  * Created      : 09/11/94
     70  */
     71 
     72 #include <sys/param.h>
     73 
     74 __KERNEL_RCSID(0, "$NetBSD: syscall.c,v 1.69 2023/10/05 19:41:03 ad Exp $");
     75 
     76 #include <sys/cpu.h>
     77 #include <sys/device.h>
     78 #include <sys/errno.h>
     79 #include <sys/kernel.h>
     80 #include <sys/reboot.h>
     81 #include <sys/signalvar.h>
     82 #include <sys/syscall.h>
     83 #include <sys/syscallvar.h>
     84 #include <sys/systm.h>
     85 #include <sys/ktrace.h>
     86 
     87 #include <uvm/uvm_extern.h>
     88 
     89 #include <machine/frame.h>
     90 #include <arm/swi.h>
     91 #include <arm/locore.h>
     92 
     93 void
     94 swi_handler(trapframe_t *tf)
     95 {
     96 	lwp_t * const l = curlwp;
     97 	uint32_t insn;
     98 
     99 	/*
    100 	 * Enable interrupts if they were enabled before the exception.
    101 	 * Since all syscalls *should* come from user mode it will always
    102 	 * be safe to enable them, but check anyway.
    103 	 */
    104 	KASSERT(VALID_PSR(tf->tf_spsr));
    105 	restore_interrupts(tf->tf_spsr & IF32_bits);
    106 
    107 #ifndef THUMB_CODE
    108 	/*
    109 	 * Make sure the program counter is correctly aligned so we
    110 	 * don't take an alignment fault trying to read the opcode.
    111 	 */
    112 	if (__predict_false(((tf->tf_pc - INSN_SIZE) & 3) != 0)) {
    113 		ksiginfo_t ksi;
    114 		/* Give the user an illegal instruction signal. */
    115 		KSI_INIT_TRAP(&ksi);
    116 		ksi.ksi_signo = SIGILL;
    117 		ksi.ksi_code = ILL_ILLOPC;
    118 		ksi.ksi_addr = (uint32_t *)(intptr_t) (tf->tf_pc-INSN_SIZE);
    119 #if 0
    120 		/* maybe one day we'll do emulations */
    121 		(*l->l_proc->p_emul->e_trapsignal)(l, &ksi);
    122 #else
    123 		trapsignal(l, &ksi);
    124 #endif
    125 		userret(l);
    126 		return;
    127 	}
    128 #endif
    129 
    130 #ifdef THUMB_CODE
    131 	if (tf->tf_spsr & PSR_T_bit) {
    132 		insn = 0xef000000 | SWI_OS_NETBSD | tf->tf_r0;
    133 		tf->tf_r0 = tf->tf_ip;
    134 	}
    135 	else
    136 #endif
    137 	{
    138 		insn = read_insn(tf->tf_pc - INSN_SIZE, true);
    139 	}
    140 
    141 	KASSERTMSG(tf == lwp_trapframe(l), "tf %p vs %p", tf, lwp_trapframe(l));
    142 
    143 #ifdef CPU_ARM7
    144 	/*
    145 	 * This code is only needed if we are including support for the ARM7
    146 	 * core. Other CPUs do not need it but it does not hurt.
    147 	 */
    148 
    149 	/*
    150 	 * ARM700/ARM710 match sticks and sellotape job ...
    151 	 *
    152 	 * I know this affects GPS/VLSI ARM700/ARM710 + various ARM7500.
    153 	 *
    154 	 * On occasion data aborts are mishandled and end up calling
    155 	 * the swi vector.
    156 	 *
    157 	 * If the instruction that caused the exception is not a SWI
    158 	 * then we hit the bug.
    159 	 */
    160 	if ((insn & 0x0f000000) != 0x0f000000) {
    161 		tf->tf_pc -= INSN_SIZE;
    162 		curcpu()->ci_arm700bugcount.ev_count++;
    163 		userret(l);
    164 		return;
    165 	}
    166 #endif	/* CPU_ARM7 */
    167 
    168 	curcpu()->ci_data.cpu_nsyscall++;
    169 
    170 	(*l->l_proc->p_md.md_syscall)(tf, l, insn);
    171 }
    172 
    173 void syscall(struct trapframe *, lwp_t *, uint32_t);
    174 
    175 void
    176 syscall_intern(struct proc *p)
    177 {
    178 	p->p_md.md_syscall = syscall;
    179 }
    180 
    181 void
    182 syscall(struct trapframe *tf, lwp_t *l, uint32_t insn)
    183 {
    184 	struct proc * const p = l->l_proc;
    185 	const struct sysent *callp;
    186 	int error;
    187 	u_int nargs, off = 0;
    188 	register_t *args;
    189 	uint64_t copyargs64[sizeof(register_t) *
    190 			    (2+SYS_MAXSYSARGS+1)/sizeof(uint64_t)];
    191 	register_t *copyargs = (register_t *)copyargs64;
    192 	register_t rval[2];
    193 	ksiginfo_t ksi;
    194 	const uint32_t os_mask = insn & SWI_OS_MASK;
    195 	uint32_t code = insn & 0x000fffff;
    196 
    197 	/* test new official and old unofficial NetBSD ranges */
    198 	if (__predict_false(os_mask != SWI_OS_NETBSD)
    199 	    && __predict_false(os_mask != 0)) {
    200 
    201 		const uint32_t swi = __SHIFTOUT(insn, __BITS(23,0));
    202 		if (swi == SWI_IMB || swi == SWI_IMBrange) {
    203 			userret(l);
    204 			return;
    205 		}
    206 
    207 		/* Undefined so illegal instruction */
    208 		KSI_INIT_TRAP(&ksi);
    209 		ksi.ksi_signo = SIGILL;
    210 		ksi.ksi_code = ILL_ILLTRP;
    211 #ifdef THUMB_CODE
    212 		if (tf->tf_spsr & PSR_T_bit)
    213 			ksi.ksi_addr = (void *)(tf->tf_pc - THUMB_INSN_SIZE);
    214 		else
    215 #endif
    216 			ksi.ksi_addr = (void *)(tf->tf_pc - INSN_SIZE);
    217 		ksi.ksi_trap = insn;
    218 		trapsignal(l, &ksi);
    219 		userret(l);
    220 		return;
    221 	}
    222 
    223 	code &= (SYS_NSYSENT - 1);
    224 
    225 	if (__predict_false(code == SYS_syscall)) {
    226 		off = 1;
    227 		code = tf->tf_r0;
    228 		code &= (SYS_NSYSENT - 1);
    229 		if (__predict_false(code == SYS_syscall)) {
    230 			error = EINVAL;
    231 			goto bad;
    232 		}
    233 	}
    234 
    235 	callp = p->p_emul->e_sysent + code;
    236 	nargs = callp->sy_narg;
    237 
    238 	if ((nargs+off) > 4) {
    239 		args = copyargs;
    240 		memcpy(args, &tf->tf_r0+off, (4-off) * sizeof(register_t));
    241 		error = copyin((void *)tf->tf_usr_sp, args + 4 - off,
    242 		    (nargs - 4 + off) * sizeof(register_t));
    243 		if (error)
    244 			goto bad;
    245 	} else {
    246 		args = &tf->tf_r0 + off;
    247 	}
    248 
    249 	error = sy_invoke(callp, l, args, rval, code);
    250 
    251 	switch (error) {
    252 	case 0:
    253 		tf->tf_r0 = rval[0];
    254 		tf->tf_r1 = rval[1];
    255 
    256 		tf->tf_spsr &= ~PSR_C_bit;	/* carry bit */
    257 		break;
    258 
    259 	case ERESTART:
    260 		/*
    261 		 * Reconstruct the pc to point at the swi.
    262 		 */
    263 #ifdef THUMB_CODE
    264 		if (tf->tf_spsr & PSR_T_bit)
    265 			tf->tf_pc -= THUMB_INSN_SIZE;
    266 		else
    267 #endif
    268 			tf->tf_pc -= INSN_SIZE;
    269 		break;
    270 
    271 	case EJUSTRETURN:
    272 		/* nothing to do */
    273 		break;
    274 
    275 	default:
    276 	bad:
    277 		tf->tf_r0 = error;
    278 		tf->tf_spsr |= PSR_C_bit;	/* carry bit */
    279 		break;
    280 	}
    281 
    282 	userret(l);
    283 }
    284 
    285 void
    286 md_child_return(struct lwp *l)
    287 {
    288 	struct trapframe * const tf = lwp_trapframe(l);
    289 
    290 	tf->tf_r0 = 0;
    291 	tf->tf_spsr &= ~PSR_C_bit;	/* carry bit */
    292 
    293 	userret(l);
    294 }
    295 
    296 /*
    297  * Process the tail end of a posix_spawn() for the child.
    298  */
    299 void
    300 cpu_spawn_return(struct lwp *l)
    301 {
    302 
    303 	userret(l);
    304 }
    305