Home | History | Annotate | Line # | Download | only in sparc
      1 /*	$NetBSD: syscall.c,v 1.33 2023/10/05 19:41:05 ad Exp $ */
      2 
      3 /*
      4  * Copyright (c) 1996
      5  *	The President and Fellows of Harvard College. All rights reserved.
      6  * Copyright (c) 1992, 1993
      7  *	The Regents of the University of California.  All rights reserved.
      8  *
      9  * This software was developed by the Computer Systems Engineering group
     10  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
     11  * contributed to Berkeley.
     12  *
     13  * All advertising materials mentioning features or use of this software
     14  * must display the following acknowledgement:
     15  *	This product includes software developed by the University of
     16  *	California, Lawrence Berkeley Laboratory.
     17  *	This product includes software developed by Harvard University.
     18  *
     19  * Redistribution and use in source and binary forms, with or without
     20  * modification, are permitted provided that the following conditions
     21  * are met:
     22  * 1. Redistributions of source code must retain the above copyright
     23  *    notice, this list of conditions and the following disclaimer.
     24  * 2. Redistributions in binary form must reproduce the above copyright
     25  *    notice, this list of conditions and the following disclaimer in the
     26  *    documentation and/or other materials provided with the distribution.
     27  * 3. All advertising materials mentioning features or use of this software
     28  *    must display the following acknowledgement:
     29  *	This product includes software developed by the University of
     30  *	California, Berkeley and its contributors.
     31  *	This product includes software developed by Harvard University.
     32  * 4. Neither the name of the University nor the names of its contributors
     33  *    may be used to endorse or promote products derived from this software
     34  *    without specific prior written permission.
     35  *
     36  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     37  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     38  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     39  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     40  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     41  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     42  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     43  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     44  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     45  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     46  * SUCH DAMAGE.
     47  *
     48  *	@(#)trap.c	8.4 (Berkeley) 9/23/93
     49  */
     50 
     51 #include <sys/cdefs.h>
     52 __KERNEL_RCSID(0, "$NetBSD: syscall.c,v 1.33 2023/10/05 19:41:05 ad Exp $");
     53 
     54 #include "opt_sparc_arch.h"
     55 #include "opt_multiprocessor.h"
     56 
     57 #include <sys/param.h>
     58 #include <sys/systm.h>
     59 #include <sys/proc.h>
     60 #include <sys/signal.h>
     61 #include <sys/syscall.h>
     62 #include <sys/syscallvar.h>
     63 #include <sys/ktrace.h>
     64 
     65 #include <uvm/uvm_extern.h>
     66 
     67 #include <sparc/sparc/asm.h>
     68 #include <machine/cpu.h>
     69 #include <machine/ctlreg.h>
     70 #include <machine/trap.h>
     71 #include <machine/instr.h>
     72 #include <machine/pmap.h>
     73 #include <machine/userret.h>
     74 
     75 #ifdef DDB
     76 #include <machine/db_machdep.h>
     77 #else
     78 #include <machine/frame.h>
     79 #endif
     80 
     81 #include <sparc/fpu/fpu_extern.h>
     82 #include <sparc/sparc/memreg.h>
     83 #include <sparc/sparc/cpuvar.h>
     84 
     85 #define MAXARGS	8
     86 union args {
     87 	uint64_t aligned;
     88 	register_t i[MAXARGS];
     89 };
     90 
     91 union rval {
     92 	uint64_t aligned;
     93 	register_t o[2];
     94 };
     95 
     96 static inline int handle_new(struct trapframe *, register_t *);
     97 static inline int getargs(struct proc *p, struct trapframe *,
     98     register_t *, const struct sysent **, union args *);
     99 #ifdef FPU_DEBUG
    100 static inline void save_fpu(struct trapframe *);
    101 #endif
    102 void syscall(register_t, struct trapframe *, register_t);
    103 
    104 static inline int
    105 handle_new(struct trapframe *tf, register_t *code)
    106 {
    107 	int new = *code & (SYSCALL_G7RFLAG|SYSCALL_G2RFLAG|SYSCALL_G5RFLAG);
    108 	*code &= ~(SYSCALL_G7RFLAG|SYSCALL_G2RFLAG|SYSCALL_G5RFLAG);
    109 	if (new) {
    110 		/* jmp %g5, (or %g2 or %g7, deprecated) on success */
    111 		if (__predict_true((new & SYSCALL_G5RFLAG) == SYSCALL_G5RFLAG))
    112 			tf->tf_pc = tf->tf_global[5];
    113 		else if (new & SYSCALL_G2RFLAG)
    114 			tf->tf_pc = tf->tf_global[2];
    115 		else
    116 			tf->tf_pc = tf->tf_global[7];
    117 	} else {
    118 		tf->tf_pc = tf->tf_npc;
    119 	}
    120 	return new;
    121 }
    122 
    123 /*
    124  * The first six system call arguments are in the six %o registers.
    125  * Any arguments beyond that are in the `argument extension' area
    126  * of the user's stack frame (see <machine/frame.h>).
    127  *
    128  * Check for ``special'' codes that alter this, namely syscall and
    129  * __syscall.  The latter takes a quad syscall number, so that other
    130  * arguments are at their natural alignments.  Adjust the number
    131  * of ``easy'' arguments as appropriate; we will copy the hard
    132  * ones later as needed.
    133  */
    134 static inline int
    135 getargs(struct proc *p, struct trapframe *tf, register_t *code,
    136     const struct sysent **callp, union args *args)
    137 {
    138 	int *ap = &tf->tf_out[0];
    139 	int error, i, nap = 6;
    140 
    141 	*callp = p->p_emul->e_sysent;
    142 
    143 	switch (*code) {
    144 	case SYS_syscall:
    145 		*code = *ap++;
    146 		nap--;
    147 		break;
    148 	case SYS___syscall:
    149 		if (!(p->p_emul->e_flags & EMUL_HAS_SYS___syscall))
    150 			break;
    151 		*code = ap[_QUAD_LOWWORD];
    152 		ap += 2;
    153 		nap -= 2;
    154 		break;
    155 	}
    156 
    157 	if (*code >= p->p_emul->e_nsysent)
    158 		return ENOSYS;
    159 
    160 	*callp += *code;
    161 	i = (*callp)->sy_argsize / sizeof(register_t);
    162 	if (__predict_false(i > nap)) {	/* usually false */
    163 		void *off = (char *)tf->tf_out[6] +
    164 		    offsetof(struct frame, fr_argx);
    165 #ifdef DIAGNOSTIC
    166 		KASSERT(i <= MAXARGS);
    167 #endif
    168 		error = copyin(off, &args->i[nap], (i - nap) * sizeof(*ap));
    169 		if (error)
    170 			return error;
    171 		i = nap;
    172 	}
    173 	copywords(ap, args->i, i * sizeof(*ap));
    174 	return 0;
    175 }
    176 
    177 #ifdef FPU_DEBUG
    178 static inline void
    179 save_fpu(struct trapframe *tf)
    180 {
    181 	struct lwp *l = curlwp;
    182 
    183 	if ((tf->tf_psr & PSR_EF) != 0) {
    184 		if (cpuinfo.fplwp != l)
    185 			panic("FPU enabled but wrong proc (3) [l=%p, fwlp=%p]",
    186 				l, cpuinfo.fplwp);
    187 		savefpstate(l->l_md.md_fpstate);
    188 		l->l_md.md_fpu = NULL;
    189 		cpuinfo.fplwp = NULL;
    190 		tf->tf_psr &= ~PSR_EF;
    191 		setpsr(getpsr() & ~PSR_EF);
    192 	}
    193 }
    194 #endif
    195 
    196 void
    197 syscall_intern(struct proc *p)
    198 {
    199 
    200 	p->p_trace_enabled = trace_is_enabled(p);
    201 	p->p_md.md_syscall = syscall;
    202 }
    203 
    204 /*
    205  * System calls.  `pc' is just a copy of tf->tf_pc.
    206  *
    207  * Note that the things labelled `out' registers in the trapframe were the
    208  * `in' registers within the syscall trap code (because of the automatic
    209  * `save' effect of each trap).  They are, however, the %o registers of the
    210  * thing that made the system call, and are named that way here.
    211  */
    212 void
    213 syscall(register_t code, struct trapframe *tf, register_t pc)
    214 {
    215 	const struct sysent *callp;
    216 	struct proc *p;
    217 	struct lwp *l;
    218 	int error, new;
    219 	union args args;
    220 	union rval rval;
    221 	int opc, onpc;
    222 	u_quad_t sticks;
    223 
    224 	curcpu()->ci_data.cpu_nsyscall++;	/* XXXSMP */
    225 	l = curlwp;
    226 	p = l->l_proc;
    227 
    228 	sticks = p->p_sticks;
    229 	l->l_md.md_tf = tf;
    230 
    231 #ifdef FPU_DEBUG
    232 	save_fpu(tf);
    233 #endif
    234 
    235 	/*
    236 	 * save pc/npc in case of ERESTART
    237 	 * adjust pc/npc to new values
    238 	 */
    239 	opc = tf->tf_pc;
    240 	onpc = tf->tf_npc;
    241 
    242 	new = handle_new(tf, &code);
    243 
    244 	tf->tf_npc = tf->tf_pc + 4;
    245 
    246 	if ((error = getargs(p, tf, &code, &callp, &args)) != 0)
    247 		goto bad;
    248 
    249 	rval.o[0] = 0;
    250 	rval.o[1] = tf->tf_out[1];
    251 
    252 	error = sy_invoke(callp, l, args.i, rval.o, code);
    253 
    254 	switch (error) {
    255 	case 0:
    256 		/* Note: fork() does not return here in the child */
    257 		tf->tf_out[0] = rval.o[0];
    258 		tf->tf_out[1] = rval.o[1];
    259 		if (!new) {
    260 			/* old system call convention: clear C on success */
    261 			tf->tf_psr &= ~PSR_C;	/* success */
    262 		}
    263 		break;
    264 
    265 	case ERESTART:
    266 		tf->tf_pc = opc;
    267 		tf->tf_npc = onpc;
    268 		break;
    269 
    270 	case EJUSTRETURN:
    271 		/* nothing to do */
    272 		break;
    273 
    274 	default:
    275 	bad:
    276 		if (p->p_emul->e_errno)
    277 			error = p->p_emul->e_errno[error];
    278 		tf->tf_out[0] = error;
    279 		tf->tf_psr |= PSR_C;	/* fail */
    280 		tf->tf_pc = onpc;
    281 		tf->tf_npc = tf->tf_pc + 4;
    282 		break;
    283 	}
    284 
    285 	userret(l, pc, sticks);
    286 	share_fpu(l, tf);
    287 }
    288 
    289 /*
    290  * Process the tail end of a fork() for the child.
    291  */
    292 void
    293 md_child_return(struct lwp *l)
    294 {
    295 
    296 	/*
    297 	 * Return values in the frame set by cpu_lwp_fork().
    298 	 */
    299 	userret(l, l->l_md.md_tf->tf_pc, 0);
    300 }
    301 
    302 /*
    303  * Process the tail end of a posix_spawn() for the child.
    304  */
    305 void
    306 cpu_spawn_return(struct lwp *l)
    307 {
    308 
    309 	userret(l, l->l_md.md_tf->tf_pc, 0);
    310 }
    311