Home | History | Annotate | Line # | Download | only in sparc64
      1 /*	$NetBSD: syscall.c,v 1.49 2023/10/05 19:41:06 ad Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2005 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Christos Zoulas.
      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) 1996-2002 Eduardo Horvath.  All rights reserved.
     34  * Copyright (c) 1996
     35  *	The President and Fellows of Harvard College. All rights reserved.
     36  * Copyright (c) 1992, 1993
     37  *	The Regents of the University of California.  All rights reserved.
     38  *
     39  * This software was developed by the Computer Systems Engineering group
     40  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
     41  * contributed to Berkeley.
     42  *
     43  * All advertising materials mentioning features or use of this software
     44  * must display the following acknowledgement:
     45  *	This product includes software developed by the University of
     46  *	California, Lawrence Berkeley Laboratory.
     47  *	This product includes software developed by Harvard University.
     48  *
     49  * Redistribution and use in source and binary forms, with or without
     50  * modification, are permitted provided that the following conditions
     51  * are met:
     52  * 1. Redistributions of source code must retain the above copyright
     53  *    notice, this list of conditions and the following disclaimer.
     54  * 2. Redistributions in binary form must reproduce the above copyright
     55  *    notice, this list of conditions and the following disclaimer in the
     56  *    documentation and/or other materials provided with the distribution.
     57  * 3. All advertising materials mentioning features or use of this software
     58  *    must display the following acknowledgement:
     59  *	This product includes software developed by the University of
     60  *	California, Berkeley and its contributors.
     61  *	This product includes software developed by Harvard University.
     62  * 4. Neither the name of the University nor the names of its contributors
     63  *    may be used to endorse or promote products derived from this software
     64  *    without specific prior written permission.
     65  *
     66  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     67  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     68  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     69  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     70  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     71  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     72  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     73  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     74  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     75  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     76  * SUCH DAMAGE.
     77  *
     78  *	@(#)trap.c	8.4 (Berkeley) 9/23/93
     79  */
     80 
     81 #include <sys/cdefs.h>
     82 __KERNEL_RCSID(0, "$NetBSD: syscall.c,v 1.49 2023/10/05 19:41:06 ad Exp $");
     83 
     84 #include <sys/param.h>
     85 #include <sys/systm.h>
     86 #include <sys/proc.h>
     87 #include <sys/signal.h>
     88 #include <sys/kmem.h>
     89 #include <sys/ktrace.h>
     90 #include <sys/syscall.h>
     91 #include <sys/syscallvar.h>
     92 
     93 #include <uvm/uvm_extern.h>
     94 
     95 #include <machine/cpu.h>
     96 #include <machine/ctlreg.h>
     97 #include <machine/trap.h>
     98 #include <machine/instr.h>
     99 #include <machine/pmap.h>
    100 #include <machine/frame.h>
    101 #include <machine/userret.h>
    102 
    103 #ifndef offsetof
    104 #define	offsetof(s, f) ((size_t)&((s *)0)->f)
    105 #endif
    106 #define	MAXARGS	8
    107 
    108 union args {
    109 	register32_t i[MAXARGS];
    110 	register64_t l[MAXARGS];
    111 	register_t   r[MAXARGS];
    112 };
    113 
    114 static inline int handle_old(struct trapframe64 *, register_t *);
    115 static inline int getargs(struct proc *, struct trapframe64 *,
    116     register_t *, const struct sysent **, union args *, int *);
    117 void syscall(struct trapframe64 *, register_t, register_t);
    118 
    119 /*
    120  * Handle old style system calls.
    121  */
    122 static inline int
    123 handle_old(struct trapframe64 *tf, register_t *code)
    124 {
    125 	int new = *code & (SYSCALL_G7RFLAG|SYSCALL_G2RFLAG|SYSCALL_G5RFLAG);
    126 	*code &= ~(SYSCALL_G7RFLAG|SYSCALL_G2RFLAG|SYSCALL_G5RFLAG);
    127 	if (new) {
    128 		/* note that G5RFLAG is multiple bits! */
    129 		if (__predict_true((new & SYSCALL_G5RFLAG) == SYSCALL_G5RFLAG))
    130 			tf->tf_pc = tf->tf_global[5];
    131 		else if (new & SYSCALL_G7RFLAG)
    132 			tf->tf_pc = tf->tf_global[7];
    133 		else
    134 			tf->tf_pc = tf->tf_global[2];
    135 	} else {
    136 		tf->tf_pc = tf->tf_npc;
    137 	}
    138 	return new;
    139 }
    140 
    141 
    142 /*
    143  * The first six system call arguments are in the six %o registers.
    144  * Any arguments beyond that are in the `argument extension' area
    145  * of the user's stack frame (see <machine/frame.h>).
    146  *
    147  * Check for ``special'' codes that alter this, namely syscall and
    148  * __syscall.  The latter takes a quad syscall number, so that other
    149  * arguments are at their natural alignments.  Adjust the number
    150  * of ``easy'' arguments as appropriate; we will copy the hard
    151  * ones later as needed.
    152  */
    153 static inline int
    154 getargs(struct proc *p, struct trapframe64 *tf, register_t *code,
    155     const struct sysent **callp, union args *args, int *s64)
    156 {
    157 	int64_t *ap = &tf->tf_out[0];
    158 	int i, error, nap = 6;
    159 	*s64 = tf->tf_out[6] & 1L; /* Do we have a 64-bit stack? */
    160 
    161 	*callp = p->p_emul->e_sysent;
    162 	switch (*code) {
    163 	case SYS_syscall:
    164 		*code = *ap++;
    165 		nap--;
    166 		break;
    167 	case SYS___syscall:
    168 		if (*s64) {
    169 			/* longs *are* quadwords */
    170 			*code = ap[0];
    171 			ap += 1;
    172 			nap -= 1;
    173 		} else {
    174 			*code = ap[_QUAD_LOWWORD];
    175 			ap += 2;
    176 			nap -= 2;
    177 		}
    178 		break;
    179 	}
    180 
    181 	if (*code >= p->p_emul->e_nsysent)
    182 		return ENOSYS;
    183 
    184 	*callp += *code;
    185 
    186 	if (*s64) {
    187 		/* 64-bit stack -- not really supported on 32-bit kernels */
    188 		register64_t *argp;
    189 #ifdef DEBUG
    190 #ifdef __arch64__
    191 		if ((p->p_flag & PK_32) != 0) {
    192 			printf("syscall(): 64-bit stack but P_32 set\n");
    193 #ifdef DDB
    194 			Debugger();
    195 #endif
    196 		}
    197 #else
    198 		printf("syscall(): 64-bit stack on a 32-bit kernel????\n");
    199 #ifdef DDB
    200 		Debugger();
    201 #endif
    202 #endif
    203 #endif
    204 		i = (*callp)->sy_narg;
    205 		if (__predict_false(i > nap)) {	/* usually false */
    206 			void *pos = (char *)(u_long)tf->tf_out[6] + BIAS +
    207 			   offsetof(struct frame64, fr_argx);
    208 			KASSERT(i <= MAXARGS);
    209 			/* Read the whole block in */
    210 			error = copyin(pos, &args->l[nap],
    211 			    (i - nap) * sizeof(*argp));
    212 			if (error)
    213 				return error;
    214 			i = nap;
    215 		}
    216 		for (argp = args->l; i--;)
    217 			*argp++ = *ap++;
    218 	} else {
    219 		register32_t *argp;
    220 
    221 		i = (long)(*callp)->sy_argsize / sizeof(register32_t);
    222 		if (__predict_false(i > nap)) {	/* usually false */
    223 			void *pos = (char *)(u_long)tf->tf_out[6] +
    224 			    offsetof(struct frame32, fr_argx);
    225 			KASSERT(i <= MAXARGS);
    226 			/* Read the whole block in */
    227 			error = copyin(pos, &args->i[nap],
    228 			    (i - nap) * sizeof(*argp));
    229 			if (error)
    230 				return error;
    231 			i = nap;
    232 		}
    233 		/* Need to convert from int64 to int32 or we lose */
    234 		for (argp = args->i; i--;)
    235 			*argp++ = *ap++;
    236 	}
    237 	return 0;
    238 }
    239 
    240 void
    241 syscall_intern(struct proc *p)
    242 {
    243 
    244 	p->p_trace_enabled = trace_is_enabled(p);
    245 	p->p_md.md_syscall = syscall;
    246 }
    247 
    248 /*
    249  * System calls.  `pc' is just a copy of tf->tf_pc.
    250  *
    251  * Note that the things labelled `out' registers in the trapframe were the
    252  * `in' registers within the syscall trap code (because of the automatic
    253  * `save' effect of each trap).  They are, however, the %o registers of the
    254  * thing that made the system call, and are named that way here.
    255  *
    256  * 32-bit system calls on a 64-bit system are a problem.  Each system call
    257  * argument is stored in the smaller of the argument's true size or a
    258  * `register_t'.  Now on a 64-bit machine all normal types can be stored in a
    259  * `register_t'.  (The only exceptions would be 128-bit `quad's or 128-bit
    260  * extended precision floating point values, which we don't support.)  For
    261  * 32-bit syscalls, 64-bit integers like `off_t's, double precision floating
    262  * point values, and several other types cannot fit in a 32-bit `register_t'.
    263  * These will require reading in two `register_t' values for one argument.
    264  *
    265  * In order to calculate the true size of the arguments and therefore whether
    266  * any argument needs to be split into two slots, the system call args
    267  * structure needs to be built with the appropriately sized register_t.
    268  * Otherwise the emul needs to do some magic to split oversized arguments.
    269  *
    270  * We can handle most this stuff for normal syscalls by using either a 32-bit
    271  * or 64-bit array of `register_t' arguments.  Unfortunately ktrace always
    272  * expects arguments to be `register_t's, so it loses badly.  What's worse,
    273  * ktrace may need to do size translations to massage the argument array
    274  * appropriately according to the emulation that is doing the ktrace.
    275  *
    276  */
    277 void
    278 syscall(struct trapframe64 *tf, register_t code, register_t pc)
    279 {
    280 	const struct sysent *callp;
    281 	struct lwp *l = curlwp;
    282 	union args args;
    283 	struct proc *p = l->l_proc;
    284 	int error, new;
    285 	register_t rval[2];
    286 	u_quad_t sticks;
    287 	vaddr_t opc, onpc;
    288 	int s64;
    289 
    290 	curcpu()->ci_data.cpu_nsyscall++;
    291 	sticks = p->p_sticks;
    292 	l->l_md.md_tf = tf;
    293 
    294 	/*
    295 	 * save pc/npc in case of ERESTART
    296 	 * adjust pc/npc to new values
    297 	 */
    298 	opc = tf->tf_pc;
    299 	onpc = tf->tf_npc;
    300 
    301 	new = handle_old(tf, &code);
    302 
    303 	tf->tf_npc = tf->tf_pc + 4;
    304 
    305 	if ((error = getargs(p, tf, &code, &callp, &args, &s64)) != 0)
    306 		goto bad;
    307 
    308 	rval[0] = 0;
    309 	rval[1] = tf->tf_out[1];
    310 
    311 #ifdef DIAGNOSTIC
    312 	KASSERT(p->p_pid != 0);
    313 	KASSERTMSG(!(tf->tf_tstate & TSTATE_PRIV),
    314 	    "syscall %ld, pid %d trap frame %p tstate %#" PRIx64
    315 	    " is privileged %s\n", code, p->p_pid, tf, tf->tf_tstate,
    316 	    (tf->tf_tstate & TSTATE_PRIV) ? "yes" : "no");
    317 	if (p->p_flag & PK_32) {
    318 		KASSERTMSG(tf->tf_tstate & TSTATE_AM,
    319 		    "32bit syscall %ld, pid %d trap frame %p tstate %#" PRIx64
    320 		    " has AM %s\n", code, p->p_pid, tf, tf->tf_tstate,
    321 		    (tf->tf_tstate & TSTATE_AM) ? "yes" : "no");
    322 	}
    323 #endif
    324 
    325 	error = sy_invoke(callp, l, args.r, rval, code);
    326 
    327 	switch (error) {
    328 	case 0:
    329 		/* Note: fork() does not return here in the child */
    330 		tf->tf_out[0] = rval[0];
    331 		tf->tf_out[1] = rval[1];
    332 		if (!new)
    333 			/* old system call convention: clear C on success */
    334 			tf->tf_tstate &= ~(((int64_t)(ICC_C | XCC_C)) <<
    335 					   TSTATE_CCR_SHIFT);	/* success */
    336 		break;
    337 
    338 	case ERESTART:
    339 		tf->tf_pc = opc;
    340 		tf->tf_npc = onpc;
    341 		break;
    342 
    343 	case EJUSTRETURN:
    344 		/* nothing to do */
    345 		break;
    346 
    347 	default:
    348 	bad:
    349 		if (p->p_emul->e_errno)
    350 			error = p->p_emul->e_errno[error];
    351 		tf->tf_out[0] = error;
    352 		tf->tf_tstate |= (((int64_t)(ICC_C | XCC_C)) <<
    353 		    TSTATE_CCR_SHIFT);	/* fail */
    354 		tf->tf_pc = onpc;
    355 		tf->tf_npc = tf->tf_pc + 4;
    356 		break;
    357 	}
    358 
    359 	userret(l, pc, sticks);
    360 	share_fpu(l, tf);
    361 }
    362 
    363 /*
    364  * Process the tail end of a fork() for the child.
    365  */
    366 void
    367 md_child_return(struct lwp *l)
    368 {
    369 
    370 	/*
    371 	 * Return values in the frame set by cpu_lwp_fork().
    372 	 */
    373 	userret(l, l->l_md.md_tf->tf_pc, 0);
    374 }
    375 
    376 /*
    377  * Process the tail end of a posix_spawn() for the child.
    378  */
    379 void
    380 cpu_spawn_return(struct lwp *l)
    381 {
    382 
    383 	userret(l, l->l_md.md_tf->tf_pc, 0);
    384 }
    385 
    386 /*
    387  * Start a new LWP
    388  */
    389 void
    390 startlwp(void *arg)
    391 {
    392 	ucontext_t *uc = arg;
    393 	lwp_t *l = curlwp;
    394 	int error __diagused;
    395 
    396 	error = cpu_setmcontext(l, &uc->uc_mcontext, uc->uc_flags);
    397 	KASSERT(error == 0);
    398 
    399 	kmem_free(uc, sizeof(ucontext_t));
    400 	userret(l, 0, 0);
    401 }
    402