1 /* $NetBSD: linux_syscall.c,v 1.2 2002/11/15 20:06:02 manu Exp $ */ 2 3 /*- 4 * Portions Copyright (c) 2000 The NetBSD Foundation, Inc. 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 by the NetBSD 18 * Foundation, Inc. and its contributors. 19 * 4. Neither the name of The NetBSD Foundation nor the names of its 20 * contributors may be used to endorse or promote products derived 21 * from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 24 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 25 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 27 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 * POSSIBILITY OF SUCH DAMAGE. 34 */ 35 36 /* 37 * Copyright (c) 1988 University of Utah. 38 * Copyright (c) 1982, 1986, 1990, 1993 39 * The Regents of the University of California. All rights reserved. 40 * 41 * This code is derived from software contributed to Berkeley by 42 * the Systems Programming Group of the University of Utah Computer 43 * Science Department. 44 * 45 * Redistribution and use in source and binary forms, with or without 46 * modification, are permitted provided that the following conditions 47 * are met: 48 * 1. Redistributions of source code must retain the above copyright 49 * notice, this list of conditions and the following disclaimer. 50 * 2. Redistributions in binary form must reproduce the above copyright 51 * notice, this list of conditions and the following disclaimer in the 52 * documentation and/or other materials provided with the distribution. 53 * 3. All advertising materials mentioning features or use of this software 54 * must display the following acknowledgement: 55 * This product includes software developed by the University of 56 * California, Berkeley and its contributors. 57 * 4. Neither the name of the University nor the names of its contributors 58 * may be used to endorse or promote products derived from this software 59 * without specific prior written permission. 60 * 61 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 62 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 63 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 64 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 65 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 66 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 67 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 68 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 69 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 70 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 71 * SUCH DAMAGE. 72 * 73 * from: Utah $Hdr: trap.c 1.37 92/12/20$ 74 * 75 * @(#)trap.c 8.5 (Berkeley) 1/4/94 76 */ 77 78 #include "opt_syscall_debug.h" 79 #include "opt_execfmt.h" 80 #include "opt_ktrace.h" 81 #include "opt_systrace.h" 82 83 #include <sys/param.h> 84 #include <sys/systm.h> 85 #include <sys/proc.h> 86 #include <sys/acct.h> 87 #include <sys/kernel.h> 88 #include <sys/syscall.h> 89 #include <sys/syslog.h> 90 #include <sys/user.h> 91 #ifdef KTRACE 92 #include <sys/ktrace.h> 93 #endif 94 #ifdef SYSTRACE 95 #include <sys/systrace.h> 96 #endif 97 98 #include <machine/psl.h> 99 #include <machine/cpu.h> 100 #include <machine/reg.h> 101 102 #include <uvm/uvm_extern.h> 103 104 void linux_syscall_intern(struct proc *); 105 static void linux_syscall_plain(register_t, struct proc *, struct frame *); 106 static void linux_syscall_fancy(register_t, struct proc *, struct frame *); 107 108 void 109 linux_syscall_intern(struct proc *p) 110 { 111 112 #ifdef KTRACE 113 if (p->p_traceflag & (KTRFAC_SYSCALL | KTRFAC_SYSRET)) 114 p->p_md.md_syscall = linux_syscall_fancy; 115 else 116 #endif 117 #ifdef SYSTRACE 118 if (ISSET(p->p_flag, P_SYSTRACE)) 119 p->p_md.md_syscall = linux_syscall_fancy; 120 else 121 #endif 122 p->p_md.md_syscall = linux_syscall_plain; 123 } 124 125 static void 126 linux_syscall_plain(register_t code, struct proc *p, struct frame *frame) 127 { 128 caddr_t params; 129 const struct sysent *callp; 130 int error, nsys; 131 size_t argsize; 132 register_t args[8], rval[2]; 133 134 nsys = p->p_emul->e_nsysent; 135 callp = p->p_emul->e_sysent; 136 params = (caddr_t)frame->f_regs[SP] + sizeof(int); 137 138 if (code < 0 || code >= nsys) 139 callp += p->p_emul->e_nosys; /* illegal */ 140 else 141 callp += code; 142 143 argsize = callp->sy_argsize; 144 145 /* 146 * Linux passes the args in d1-d5 147 */ 148 switch (argsize) { 149 case 20: 150 args[4] = frame->f_regs[D5]; 151 case 16: 152 args[3] = frame->f_regs[D4]; 153 case 12: 154 args[2] = frame->f_regs[D3]; 155 case 8: 156 args[1] = frame->f_regs[D2]; 157 case 4: 158 args[0] = frame->f_regs[D1]; 159 case 0: 160 break; 161 default: 162 panic("linux syscall %d weird argsize %d", 163 code, argsize); 164 break; 165 } 166 167 #ifdef SYSCALL_DEBUG 168 scdebug_call(p, code, args); 169 #endif 170 171 rval[0] = 0; 172 rval[1] = frame->f_regs[D1]; 173 error = (*callp->sy_call)(p, args, rval); 174 175 switch (error) { 176 case 0: 177 /* 178 * Reinitialize proc pointer `p' as it may be different 179 * if this is a child returning from fork syscall. 180 */ 181 p = curproc; 182 frame->f_regs[D0] = rval[0]; 183 frame->f_regs[D1] = rval[1]; 184 frame->f_sr &= ~PSL_C; /* carry bit */ 185 break; 186 case ERESTART: 187 /* 188 * We always enter through a `trap' instruction, which is 2 189 * bytes, so adjust the pc by that amount. 190 */ 191 frame->f_pc = frame->f_pc - 2; 192 break; 193 case EJUSTRETURN: 194 /* nothing to do */ 195 break; 196 default: 197 if (p->p_emul->e_errno) 198 error = p->p_emul->e_errno[error]; 199 frame->f_regs[D0] = error; 200 frame->f_sr |= PSL_C; /* carry bit */ 201 break; 202 } 203 204 #ifdef SYSCALL_DEBUG 205 scdebug_ret(p, code, error, rval); 206 #endif 207 } 208 209 static void 210 linux_syscall_fancy(register_t code, struct proc *p, struct frame *frame) 211 { 212 caddr_t params; 213 const struct sysent *callp; 214 int error, nsys; 215 size_t argsize; 216 register_t args[8], rval[2]; 217 218 nsys = p->p_emul->e_nsysent; 219 callp = p->p_emul->e_sysent; 220 params = (caddr_t)frame->f_regs[SP] + sizeof(int); 221 222 if (code < 0 || code >= nsys) 223 callp += p->p_emul->e_nosys; /* illegal */ 224 else 225 callp += code; 226 227 argsize = callp->sy_argsize; 228 229 /* 230 * Linux passes the args in d1-d5 231 */ 232 switch (argsize) { 233 case 20: 234 args[4] = frame->f_regs[D5]; 235 case 16: 236 args[3] = frame->f_regs[D4]; 237 case 12: 238 args[2] = frame->f_regs[D3]; 239 case 8: 240 args[1] = frame->f_regs[D2]; 241 case 4: 242 args[0] = frame->f_regs[D1]; 243 case 0: 244 break; 245 default: 246 panic("linux syscall %d weird argsize %d", 247 code, argsize); 248 break; 249 } 250 251 if ((error = trace_enter(p, code, code, args, rval)) != 0) 252 goto bad; 253 254 rval[0] = 0; 255 rval[1] = frame->f_regs[D1]; 256 error = (*callp->sy_call)(p, args, rval); 257 258 switch (error) { 259 case 0: 260 /* 261 * Reinitialize proc pointer `p' as it may be different 262 * if this is a child returning from fork syscall. 263 */ 264 p = curproc; 265 frame->f_regs[D0] = rval[0]; 266 frame->f_regs[D1] = rval[1]; 267 frame->f_sr &= ~PSL_C; /* carry bit */ 268 break; 269 case ERESTART: 270 /* 271 * We always enter through a `trap' instruction, which is 2 272 * bytes, so adjust the pc by that amount. 273 */ 274 frame->f_pc = frame->f_pc - 2; 275 break; 276 case EJUSTRETURN: 277 /* nothing to do */ 278 break; 279 default: 280 bad: 281 if (p->p_emul->e_errno) 282 error = p->p_emul->e_errno[error]; 283 frame->f_regs[D0] = error; 284 frame->f_sr |= PSL_C; /* carry bit */ 285 break; 286 } 287 288 trace_exit(p, code, args, rval, error); 289 } 290