1 /* $NetBSD: syscall.c,v 1.13 2002/11/30 10:52:16 jdolecek Exp $ */ 2 3 /*- 4 * Copyright (c) 2001 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe and by Charles M. Hannum. 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 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* 40 * Copyright (c) 1988 University of Utah. 41 * Copyright (c) 1992, 1993 42 * The Regents of the University of California. All rights reserved. 43 * 44 * This code is derived from software contributed to Berkeley by 45 * the Systems Programming Group of the University of Utah Computer 46 * Science Department and Ralph Campbell. 47 * 48 * Redistribution and use in source and binary forms, with or without 49 * modification, are permitted provided that the following conditions 50 * are met: 51 * 1. Redistributions of source code must retain the above copyright 52 * notice, this list of conditions and the following disclaimer. 53 * 2. Redistributions in binary form must reproduce the above copyright 54 * notice, this list of conditions and the following disclaimer in the 55 * documentation and/or other materials provided with the distribution. 56 * 3. All advertising materials mentioning features or use of this software 57 * must display the following acknowledgement: 58 * This product includes software developed by the University of 59 * California, Berkeley and its contributors. 60 * 4. Neither the name of the University nor the names of its contributors 61 * may be used to endorse or promote products derived from this software 62 * without specific prior written permission. 63 * 64 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 65 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 66 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 67 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 68 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 69 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 70 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 71 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 72 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 73 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 74 * SUCH DAMAGE. 75 * 76 * from: Utah Hdr: trap.c 1.32 91/04/06 77 * 78 * @(#)trap.c 8.5 (Berkeley) 1/11/94 79 */ 80 81 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 82 83 __KERNEL_RCSID(0, "$NetBSD: syscall.c,v 1.13 2002/11/30 10:52:16 jdolecek Exp $"); 84 85 #if defined(_KERNEL_OPT) 86 #include "opt_ktrace.h" 87 #include "opt_systrace.h" 88 #include "opt_syscall_debug.h" 89 #endif 90 91 #include <sys/param.h> 92 #include <sys/systm.h> 93 #include <sys/proc.h> 94 #include <sys/user.h> 95 #include <sys/signal.h> 96 #ifdef KTRACE 97 #include <sys/ktrace.h> 98 #endif 99 #ifdef SYSTRACE 100 #include <sys/systrace.h> 101 #endif 102 #include <sys/syscall.h> 103 104 #include <uvm/uvm_extern.h> 105 106 #include <machine/cpu.h> 107 #include <mips/trap.h> 108 #include <mips/reg.h> 109 #include <mips/regnum.h> /* symbolic register indices */ 110 #include <mips/userret.h> 111 112 #ifndef EMULNAME 113 #define EMULNAME(x) (x) 114 #endif 115 116 #ifndef SYSCALL_SHIFT 117 #define SYSCALL_SHIFT 0 118 #endif 119 120 void EMULNAME(syscall_intern)(struct proc *); 121 void EMULNAME(syscall_plain)(struct proc *, u_int, u_int, u_int); 122 void EMULNAME(syscall_fancy)(struct proc *, u_int, u_int, u_int); 123 124 vaddr_t MachEmulateBranch(struct frame *, vaddr_t, u_int, int); 125 126 #define DELAYBRANCH(x) ((int)(x)<0) 127 128 void 129 EMULNAME(syscall_intern)(struct proc *p) 130 { 131 #ifdef KTRACE 132 if (p->p_traceflag & (KTRFAC_SYSCALL | KTRFAC_SYSRET)) { 133 p->p_md.md_syscall = EMULNAME(syscall_fancy); 134 return; 135 } 136 #endif 137 #ifdef SYSTRACE 138 if (ISSET(p->p_flag, P_SYSTRACE)) { 139 p->p_md.md_syscall = EMULNAME(syscall_fancy); 140 return; 141 } 142 #endif 143 p->p_md.md_syscall = EMULNAME(syscall_plain); 144 } 145 146 /* 147 * Process a system call. 148 * 149 * System calls are strange beasts. They are passed the syscall number 150 * in v0, and the arguments in the registers (as normal). They return 151 * an error flag in a3 (if a3 != 0 on return, the syscall had an error), 152 * and the return value (if any) in v0 and possibly v1. 153 * 154 * XXX Needs to be heavily rototilled for N32 or LP64 support. 155 */ 156 157 void 158 EMULNAME(syscall_plain)(struct proc *p, u_int status, u_int cause, u_int opc) 159 { 160 struct frame *frame = (struct frame *)p->p_md.md_regs; 161 register_t *args, copyargs[8]; 162 register_t *rval; 163 #if _MIPS_BSD_API == _MIPS_BSD_API_LP32_64CLEAN 164 register_t copyrval[2]; 165 #endif 166 mips_reg_t ov0; 167 size_t numsys, nsaved, nargs; 168 const struct sysent *callp; 169 int code, error; 170 171 uvmexp.syscalls++; 172 173 if (DELAYBRANCH(cause)) 174 frame->f_regs[PC] = MachEmulateBranch(frame, opc, 0, 0); 175 else 176 frame->f_regs[PC] = opc + sizeof(int); 177 178 callp = p->p_emul->e_sysent; 179 numsys = p->p_emul->e_nsysent; 180 ov0 = code = frame->f_regs[V0] - SYSCALL_SHIFT; 181 182 switch (code) { 183 case SYS_syscall: 184 case SYS___syscall: 185 args = copyargs; 186 if (code == SYS_syscall) { 187 /* 188 * Code is first argument, followed by actual args. 189 */ 190 code = frame->f_regs[A0] - SYSCALL_SHIFT; 191 args[0] = frame->f_regs[A1]; 192 args[1] = frame->f_regs[A2]; 193 args[2] = frame->f_regs[A3]; 194 nsaved = 3; 195 } else { 196 /* 197 * Like syscall, but code is a quad, so as to maintain 198 * quad alignment for the rest of the arguments. 199 */ 200 code = frame->f_regs[A0 + _QUAD_LOWWORD] 201 - SYSCALL_SHIFT; 202 args[0] = frame->f_regs[A2]; 203 args[1] = frame->f_regs[A3]; 204 nsaved = 2; 205 } 206 207 if (code >= p->p_emul->e_nsysent) 208 callp += p->p_emul->e_nosys; 209 else 210 callp += code; 211 nargs = callp->sy_argsize / sizeof(register_t); 212 213 if (nargs > nsaved) { 214 error = copyin( 215 ((register_t *)(vaddr_t)frame->f_regs[SP] + 4), 216 (args + nsaved), 217 (nargs - nsaved) * sizeof(register_t)); 218 if (error) 219 goto bad; 220 } 221 break; 222 223 default: 224 if (code >= p->p_emul->e_nsysent) 225 callp += p->p_emul->e_nosys; 226 else 227 callp += code; 228 nargs = callp->sy_narg; 229 230 if (nargs < 5) { 231 #if !defined(_MIPS_BSD_API) || _MIPS_BSD_API == _MIPS_BSD_API_LP32 232 args = (register_t *)&frame->f_regs[A0]; 233 #elif _MIPS_BSD_API == _MIPS_BSD_API_LP32_64CLEAN 234 args = copyargs; 235 args[0] = frame->f_regs[A0]; 236 args[1] = frame->f_regs[A1]; 237 args[2] = frame->f_regs[A2]; 238 args[3] = frame->f_regs[A3]; 239 #else 240 # error syscall not implemented for current MIPS ABI 241 #endif 242 } else { 243 args = copyargs; 244 error = copyin( 245 ((register_t *)(vaddr_t)frame->f_regs[SP] + 4), 246 (©args[4]), 247 (nargs - 4) * sizeof(register_t)); 248 if (error) 249 goto bad; 250 args[0] = frame->f_regs[A0]; 251 args[1] = frame->f_regs[A1]; 252 args[2] = frame->f_regs[A2]; 253 args[3] = frame->f_regs[A3]; 254 } 255 break; 256 } 257 258 #ifdef SYSCALL_DEBUG 259 scdebug_call(p, code, (register_t *)args); 260 #endif 261 262 #if !defined(_MIPS_BSD_API) || _MIPS_BSD_API == _MIPS_BSD_API_LP32 263 rval = (register_t *)&frame->f_regs[V0]; 264 rval[0] = 0; 265 /* rval[1] already has V1 */ 266 #elif _MIPS_BSD_API == _MIPS_BSD_API_LP32_64CLEAN 267 rval = copyrval; 268 rval[0] = 0; 269 rval[1] = frame->f_regs[V1]; 270 #endif 271 272 error = (*callp->sy_call)(p, args, rval); 273 274 switch (error) { 275 case 0: 276 #if _MIPS_BSD_API == _MIPS_BSD_API_LP32_64CLEAN 277 frame->f_regs[V0] = rval[0]; 278 frame->f_regs[V1] = rval[1]; 279 #endif 280 frame->f_regs[A3] = 0; 281 break; 282 case ERESTART: 283 frame->f_regs[V0] = ov0; /* restore syscall code */ 284 frame->f_regs[PC] = opc; 285 break; 286 case EJUSTRETURN: 287 break; /* nothing to do */ 288 default: 289 bad: 290 if (p->p_emul->e_errno) 291 error = p->p_emul->e_errno[error]; 292 frame->f_regs[V0] = error; 293 frame->f_regs[A3] = 1; 294 break; 295 } 296 297 #ifdef SYSCALL_DEBUG 298 scdebug_ret(p, code, error, rval); 299 #endif 300 301 userret(p); 302 } 303 304 void 305 EMULNAME(syscall_fancy)(struct proc *p, u_int status, u_int cause, u_int opc) 306 { 307 struct frame *frame = (struct frame *)p->p_md.md_regs; 308 register_t *args, copyargs[8]; 309 register_t *rval; 310 #if _MIPS_BSD_API == _MIPS_BSD_API_LP32_64CLEAN 311 register_t copyrval[2]; 312 #endif 313 mips_reg_t ov0; 314 size_t numsys, nsaved, nargs; 315 const struct sysent *callp; 316 int code, error; 317 318 uvmexp.syscalls++; 319 320 if (DELAYBRANCH(cause)) 321 frame->f_regs[PC] = MachEmulateBranch(frame, opc, 0, 0); 322 else 323 frame->f_regs[PC] = opc + sizeof(int); 324 325 callp = p->p_emul->e_sysent; 326 numsys = p->p_emul->e_nsysent; 327 ov0 = code = frame->f_regs[V0] - SYSCALL_SHIFT; 328 329 switch (code) { 330 case SYS_syscall: 331 case SYS___syscall: 332 args = copyargs; 333 if (code == SYS_syscall) { 334 /* 335 * Code is first argument, followed by actual args. 336 */ 337 code = frame->f_regs[A0] - SYSCALL_SHIFT; 338 args[0] = frame->f_regs[A1]; 339 args[1] = frame->f_regs[A2]; 340 args[2] = frame->f_regs[A3]; 341 nsaved = 3; 342 } else { 343 /* 344 * Like syscall, but code is a quad, so as to maintain 345 * quad alignment for the rest of the arguments. 346 */ 347 code = frame->f_regs[A0 + _QUAD_LOWWORD] 348 - SYSCALL_SHIFT; 349 args[0] = frame->f_regs[A2]; 350 args[1] = frame->f_regs[A3]; 351 nsaved = 2; 352 } 353 354 if (code >= p->p_emul->e_nsysent) 355 callp += p->p_emul->e_nosys; 356 else 357 callp += code; 358 nargs = callp->sy_argsize / sizeof(register_t); 359 360 if (nargs > nsaved) { 361 error = copyin( 362 ((register_t *)(vaddr_t)frame->f_regs[SP] + 4), 363 (args + nsaved), 364 (nargs - nsaved) * sizeof(register_t)); 365 if (error) 366 goto bad; 367 } 368 break; 369 370 default: 371 if (code >= p->p_emul->e_nsysent) 372 callp += p->p_emul->e_nosys; 373 else 374 callp += code; 375 nargs = callp->sy_narg; 376 377 if (nargs < 5) { 378 #if !defined(_MIPS_BSD_API) || _MIPS_BSD_API == _MIPS_BSD_API_LP32 379 args = (register_t *)&frame->f_regs[A0]; 380 #elif _MIPS_BSD_API == _MIPS_BSD_API_LP32_64CLEAN 381 args = copyargs; 382 args[0] = frame->f_regs[A0]; 383 args[1] = frame->f_regs[A1]; 384 args[2] = frame->f_regs[A2]; 385 args[3] = frame->f_regs[A3]; 386 #else 387 # error syscall not implemented for current MIPS ABI 388 #endif 389 } else { 390 args = copyargs; 391 error = copyin( 392 ((register_t *)(vaddr_t)frame->f_regs[SP] + 4), 393 (©args[4]), 394 (nargs - 4) * sizeof(register_t)); 395 if (error) 396 goto bad; 397 args[0] = frame->f_regs[A0]; 398 args[1] = frame->f_regs[A1]; 399 args[2] = frame->f_regs[A2]; 400 args[3] = frame->f_regs[A3]; 401 } 402 break; 403 } 404 405 if ((error = trace_enter(p, code, code, args, rval)) != 0) 406 goto bad; 407 408 #if !defined(_MIPS_BSD_API) || _MIPS_BSD_API == _MIPS_BSD_API_LP32 409 rval = (register_t *)&frame->f_regs[V0]; 410 rval[0] = 0; 411 /* rval[1] already has V1 */ 412 #elif _MIPS_BSD_API == _MIPS_BSD_API_LP32_64CLEAN 413 rval = copyrval; 414 rval[0] = 0; 415 rval[1] = frame->f_regs[V1]; 416 #endif 417 418 error = (*callp->sy_call)(p, args, rval); 419 420 switch (error) { 421 case 0: 422 #if _MIPS_BSD_API == _MIPS_BSD_API_LP32_64CLEAN 423 frame->f_regs[V0] = rval[0]; 424 frame->f_regs[V1] = rval[1]; 425 #endif 426 frame->f_regs[A3] = 0; 427 break; 428 case ERESTART: 429 frame->f_regs[V0] = ov0; /* restore syscall code */ 430 frame->f_regs[PC] = opc; 431 break; 432 case EJUSTRETURN: 433 break; /* nothing to do */ 434 default: 435 bad: 436 if (p->p_emul->e_errno) 437 error = p->p_emul->e_errno[error]; 438 frame->f_regs[V0] = error; 439 frame->f_regs[A3] = 1; 440 break; 441 } 442 443 trace_exit(p, code, args, rval, error); 444 445 userret(p); 446 } 447