/* $NetBSD: syscall.c,v 1.53 2013/11/03 22:22:03 mrg Exp $ */ /* * Copyright (C) 2002 Matt Thomas * Copyright (C) 1995, 1996 Wolfgang Solfrank. * Copyright (C) 1995, 1996 TooLs GmbH. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by TooLs GmbH. * 4. The name of TooLs GmbH may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "opt_altivec.h" #include "opt_multiprocessor.h" /* DO NOT INCLUDE opt_compat_XXX.h */ /* If needed, they will be included by file that includes this one */ #include #include #include #include #include #include #include #include #include #include #include #define FIRSTARG 3 /* first argument is in reg 3 */ #define NARGREG 8 /* 8 args are in registers */ #define MOREARGS(sp) ((void *)((uintptr_t)(sp) + 8)) /* more args go here */ #ifndef EMULNAME #include #define EMULNAME(x) (x) #define EMULNAMEU(x) (x) __KERNEL_RCSID(0, "$NetBSD: syscall.c,v 1.53 2013/11/03 22:22:03 mrg Exp $"); void child_return(void *arg) { struct lwp * const l = arg; struct trapframe * const tf = l->l_md.md_utf; tf->tf_fixreg[FIRSTARG] = 0; tf->tf_fixreg[FIRSTARG + 1] = 1; tf->tf_cr &= ~0x10000000; tf->tf_srr1 &= ~(PSL_FP|PSL_VEC); /* Disable FP & AltiVec, as we can't be them. */ ktrsysret(SYS_fork, 0, 0); /* Profiling? XXX */ } #endif #include static void EMULNAME(syscall)(struct trapframe *); void EMULNAME(syscall)(struct trapframe *tf) { struct lwp * const l = curlwp; struct proc * const p = l->l_proc; const struct sysent *callp; size_t argsize; register_t code; register_t *params, rval[2]; register_t args[10]; int error; int n; LWP_CACHE_CREDS(l, p); curcpu()->ci_ev_scalls.ev_count++; code = tf->tf_fixreg[0]; params = tf->tf_fixreg + FIRSTARG; n = NARGREG; { switch (code) { case EMULNAMEU(SYS_syscall): /* * code is first argument, * followed by actual args. */ code = *params++; n -= 1; break; #if !defined(COMPAT_LINUX) case EMULNAMEU(SYS___syscall): params++; code = *params++; n -= 2; break; #endif default: break; } code &= EMULNAMEU(SYS_NSYSENT) - 1; callp = p->p_emul->e_sysent + code; } argsize = callp->sy_argsize; if (argsize > n * sizeof(register_t)) { memcpy(args, params, n * sizeof(register_t)); error = copyin(MOREARGS(tf->tf_fixreg[1]), args + n, argsize - n * sizeof(register_t)); if (error) goto bad; params = args; } error = sy_invoke(callp, l, params, rval, code); if (__predict_true(error == 0)) { tf->tf_fixreg[FIRSTARG] = rval[0]; tf->tf_fixreg[FIRSTARG + 1] = rval[1]; tf->tf_cr &= ~0x10000000; } else { switch (error) { case ERESTART: /* * Set user's pc back to redo the system call. */ tf->tf_srr0 -= 4; break; case EJUSTRETURN: /* nothing to do */ break; default: bad: if (p->p_emul->e_errno) error = p->p_emul->e_errno[error]; tf->tf_fixreg[FIRSTARG] = error; tf->tf_cr |= 0x10000000; break; } } userret(l, tf); } void EMULNAME(syscall_intern)(struct proc *); void EMULNAME(syscall_intern)(struct proc *p) { p->p_md.md_syscall = EMULNAME(syscall); }