1 /* $NetBSD: syscall.c,v 1.18 2010/12/20 00:25:45 matt Exp $ */ 2 3 /* 4 * Copyright (c) 1994 Ludd, University of Lule}, Sweden. 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 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed at Ludd, University of Lule}. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* All bugs are subject to removal without further notice */ 34 35 #include <sys/cdefs.h> 36 __KERNEL_RCSID(0, "$NetBSD: syscall.c,v 1.18 2010/12/20 00:25:45 matt Exp $"); 37 38 #include "opt_multiprocessor.h" 39 #include "opt_sa.h" 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/cpu.h> 44 #include <sys/ktrace.h> 45 #include <sys/proc.h> 46 #include <sys/sa.h> 47 #include <sys/savar.h> 48 #include <sys/syscall.h> 49 #include <sys/syscallvar.h> 50 51 #include <machine/userret.h> 52 53 #ifdef TRAPDEBUG 54 int startsysc = 0; 55 #define TDB(a) if (startsysc) printf a 56 #else 57 #define TDB(a) 58 #endif 59 60 void syscall(struct trapframe *); 61 62 void 63 syscall_intern(struct proc *p) 64 { 65 p->p_trace_enabled = trace_is_enabled(p); 66 p->p_md.md_syscall = syscall; 67 } 68 69 void 70 syscall(struct trapframe *frame) 71 { 72 int error; 73 int rval[2]; 74 int args[2+SYS_MAXSYSARGS]; /* add two for SYS___syscall + padding */ 75 struct trapframe * const exptr = frame; 76 struct lwp * const l = curlwp; 77 struct proc * const p = l->l_proc; 78 struct pcb *pcb = lwp_getpcb(l); 79 const struct emul * const emul = p->p_emul; 80 const struct sysent *callp = emul->e_sysent; 81 const u_quad_t oticks = p->p_sticks; 82 83 TDB(("trap syscall %s pc %lx, psl %lx, sp %lx, pid %d, frame %p\n", 84 syscallnames[frame->code], frame->pc, frame->psl,frame->sp, 85 p->p_pid,frame)); 86 87 curcpu()->ci_data.cpu_nsyscall++; 88 89 LWP_CACHE_CREDS(l, p); 90 91 pcb->framep = frame; 92 93 if ((unsigned long) frame->code >= emul->e_nsysent) 94 callp += emul->e_nosys; 95 else 96 callp += frame->code; 97 98 rval[0] = 0; 99 rval[1] = frame->r1; 100 101 if (callp->sy_narg) { 102 error = copyin((char*)frame->ap + 4, args, callp->sy_argsize); 103 if (error) 104 goto bad; 105 } 106 107 #ifdef KERN_SA 108 if (__predict_false((l->l_savp) 109 && (l->l_savp->savp_pflags & SAVP_FLAG_DELIVERING))) 110 l->l_savp->savp_pflags &= ~SAVP_FLAG_DELIVERING; 111 #endif 112 113 /* 114 * Only trace if tracing is enabled and the syscall isn't indirect 115 * (SYS_syscall or SYS___syscall) 116 */ 117 if (__predict_true(!p->p_trace_enabled) 118 || __predict_false(callp->sy_flags & SYCALL_INDIRECT) 119 || (error = trace_enter(frame->code, args, callp->sy_narg)) == 0) { 120 error = sy_call(callp, curlwp, args, rval); 121 } 122 123 KASSERT(exptr == pcb->framep); 124 TDB(("return %s pc %lx, psl %lx, sp %lx, pid %d, err %d r0 %d, r1 %d, " 125 "frame %p\n", syscallnames[exptr->code], exptr->pc, exptr->psl, 126 exptr->sp, p->p_pid, error, rval[0], rval[1], exptr)); 127 bad: 128 switch (error) { 129 case 0: 130 exptr->r1 = rval[1]; 131 exptr->r0 = rval[0]; 132 exptr->psl &= ~PSL_C; 133 break; 134 135 case EJUSTRETURN: 136 break; 137 138 case ERESTART: 139 /* assumes CHMK $n was used */ 140 exptr->pc -= (exptr->code > 63 ? 4 : 2); 141 break; 142 143 default: 144 exptr->r0 = error; 145 exptr->psl |= PSL_C; 146 break; 147 } 148 149 if (__predict_false(p->p_trace_enabled) 150 && __predict_true(!(callp->sy_flags & SYCALL_INDIRECT))) 151 trace_exit(frame->code, rval, error); 152 153 userret(l, frame, oticks); 154 } 155 156 void 157 child_return(void *arg) 158 { 159 struct lwp *l = arg; 160 struct pcb *pcb = lwp_getpcb(l); 161 162 userret(l, pcb->framep, 0); 163 ktrsysret(SYS_fork, 0, 0); 164 } 165