1 /* $NetBSD: syscall.c,v 1.42 2010/12/20 00:25:38 matt 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 * 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) 1992, 1993 34 * The Regents of the University of California. All rights reserved. 35 * 36 * This code is derived from software contributed to Berkeley by 37 * the Systems Programming Group of the University of Utah Computer 38 * Science Department and Ralph Campbell. 39 * 40 * Redistribution and use in source and binary forms, with or without 41 * modification, are permitted provided that the following conditions 42 * are met: 43 * 1. Redistributions of source code must retain the above copyright 44 * notice, this list of conditions and the following disclaimer. 45 * 2. Redistributions in binary form must reproduce the above copyright 46 * notice, this list of conditions and the following disclaimer in the 47 * documentation and/or other materials provided with the distribution. 48 * 3. Neither the name of the University nor the names of its contributors 49 * may be used to endorse or promote products derived from this software 50 * without specific prior written permission. 51 * 52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 62 * SUCH DAMAGE. 63 * 64 * from: Utah Hdr: trap.c 1.32 91/04/06 65 * 66 * @(#)trap.c 8.5 (Berkeley) 1/11/94 67 */ 68 /* 69 * Copyright (c) 1988 University of Utah. 70 * 71 * This code is derived from software contributed to Berkeley by 72 * the Systems Programming Group of the University of Utah Computer 73 * Science Department and Ralph Campbell. 74 * 75 * Redistribution and use in source and binary forms, with or without 76 * modification, are permitted provided that the following conditions 77 * are met: 78 * 1. Redistributions of source code must retain the above copyright 79 * notice, this list of conditions and the following disclaimer. 80 * 2. Redistributions in binary form must reproduce the above copyright 81 * notice, this list of conditions and the following disclaimer in the 82 * documentation and/or other materials provided with the distribution. 83 * 3. All advertising materials mentioning features or use of this software 84 * must display the following acknowledgement: 85 * This product includes software developed by the University of 86 * California, Berkeley and its contributors. 87 * 4. Neither the name of the University nor the names of its contributors 88 * may be used to endorse or promote products derived from this software 89 * without specific prior written permission. 90 * 91 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 92 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 93 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 94 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 95 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 96 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 97 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 98 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 99 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 100 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 101 * SUCH DAMAGE. 102 * 103 * from: Utah Hdr: trap.c 1.32 91/04/06 104 * 105 * @(#)trap.c 8.5 (Berkeley) 1/11/94 106 */ 107 108 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 109 110 __KERNEL_RCSID(0, "$NetBSD: syscall.c,v 1.42 2010/12/20 00:25:38 matt Exp $"); 111 112 #if defined(_KERNEL_OPT) 113 #include "opt_sa.h" 114 #endif 115 116 #include <sys/param.h> 117 #include <sys/systm.h> 118 #include <sys/endian.h> 119 #include <sys/proc.h> 120 #include <sys/signal.h> 121 #include <sys/syscall.h> 122 #include <sys/syscallvar.h> 123 #include <sys/sa.h> 124 #include <sys/savar.h> 125 126 #include <uvm/uvm_extern.h> 127 128 #include <machine/cpu.h> 129 #include <mips/trap.h> 130 #include <mips/reg.h> 131 #include <mips/regnum.h> /* symbolic register indices */ 132 #include <mips/userret.h> 133 134 #ifndef EMULNAME 135 #define EMULNAME(x) (x) 136 #endif 137 138 #ifndef SYSCALL_SHIFT 139 #define SYSCALL_SHIFT 0 140 #endif 141 142 void EMULNAME(syscall_intern)(struct proc *); 143 static void EMULNAME(syscall)(struct lwp *, uint32_t, uint32_t, vaddr_t); 144 145 register_t MachEmulateBranch(struct frame *, register_t, u_int, int); 146 147 void 148 EMULNAME(syscall_intern)(struct proc *p) 149 { 150 p->p_md.md_syscall = EMULNAME(syscall); 151 } 152 153 /* 154 * Process a system call. 155 * 156 * System calls are strange beasts. They are passed the syscall number 157 * in v0, and the arguments in the registers (as normal). They return 158 * an error flag in a3 (if a3 != 0 on return, the syscall had an error), 159 * and the return value (if any) in v0 and possibly v1. 160 */ 161 162 void 163 EMULNAME(syscall)(struct lwp *l, u_int status, u_int cause, vaddr_t opc) 164 { 165 struct proc *p = l->l_proc; 166 struct frame *frame = l->l_md.md_regs; 167 mips_reg_t *fargs = &frame->f_regs[_R_A0]; 168 register_t *args = NULL; 169 register_t copyargs[2+SYS_MAXSYSARGS]; 170 mips_reg_t saved_v0; 171 vaddr_t usp; 172 size_t nargs; 173 const struct sysent *callp; 174 int code, error; 175 #if defined(__mips_o32) 176 const int abi = _MIPS_BSD_API_O32; 177 KASSERTMSG(p->p_md.md_abi == abi, 178 ("pid %d(%p): md_abi(%d) != abi(%d)", 179 p->p_pid, p, p->p_md.md_abi, abi)); 180 size_t nregs = 4; 181 #else 182 const int abi = p->p_md.md_abi; 183 size_t nregs = _MIPS_SIM_NEWABI_P(abi) ? 8 : 4; 184 size_t i; 185 #endif 186 187 LWP_CACHE_CREDS(l, p); 188 189 curcpu()->ci_data.cpu_nsyscall++; 190 191 if (cause & MIPS_CR_BR_DELAY) 192 frame->f_regs[_R_PC] = MachEmulateBranch(frame, opc, 0, 0); 193 else 194 frame->f_regs[_R_PC] = opc + sizeof(uint32_t); 195 196 callp = p->p_emul->e_sysent; 197 saved_v0 = code = frame->f_regs[_R_V0]; 198 199 code -= SYSCALL_SHIFT; 200 201 #ifdef KERN_SA 202 if (__predict_false((l->l_savp) 203 && (l->l_savp->savp_pflags & SAVP_FLAG_DELIVERING))) 204 l->l_savp->savp_pflags &= ~SAVP_FLAG_DELIVERING; 205 #endif 206 207 if (code == SYS_syscall 208 || (code == SYS___syscall && abi != _MIPS_BSD_API_O32)) { 209 /* 210 * Code is first argument, followed by actual args. 211 */ 212 code = *fargs++ - SYSCALL_SHIFT; 213 nregs--; 214 } else if (code == SYS___syscall) { 215 /* 216 * Like syscall, but code is a quad, so as to maintain 217 * quad alignment for the rest of the arguments. 218 */ 219 code = fargs[_QUAD_LOWWORD] - SYSCALL_SHIFT; 220 fargs += 2; 221 nregs -= 2; 222 } 223 224 if (code >= p->p_emul->e_nsysent) 225 callp += p->p_emul->e_nosys; 226 else 227 callp += code; 228 229 nargs = callp->sy_narg; 230 frame->f_regs[_R_V0] = 0; 231 #if !defined(__mips_o32) 232 if (abi != _MIPS_BSD_API_O32) { 233 #endif 234 CTASSERT(sizeof(copyargs[0]) == sizeof(fargs[0])); 235 if (nargs <= nregs) { 236 /* 237 * Just use the frame for the source of arguments 238 */ 239 args = fargs; 240 } else { 241 const size_t nsaved = _MIPS_SIM_NEWABI_P(abi) ? 0 : 4; 242 KASSERT(nargs <= __arraycount(copyargs)); 243 args = copyargs; 244 /* 245 * Copy the arguments passed via register from the 246 * trap frame to our argument array 247 */ 248 memcpy(copyargs, fargs, nregs * sizeof(register_t)); 249 /* 250 * Start copying args skipping the register slots 251 * slots on the stack. 252 */ 253 usp = frame->f_regs[_R_SP] + nsaved*sizeof(register_t); 254 error = copyin((register_t *)usp, ©args[nregs], 255 (nargs - nregs) * sizeof(copyargs[0])); 256 if (error) 257 goto bad; 258 } 259 #if !defined(__mips_o32) 260 } else do { 261 /* 262 * The only difference between O32 and N32 is the calling 263 * sequence. If you make O32 264 */ 265 int32_t copy32args[SYS_MAXSYSARGS]; 266 int32_t *cargs = copy32args; 267 unsigned int arg64mask = SYCALL_ARG_64_MASK(callp); 268 bool doing_arg64; 269 size_t narg64 = SYCALL_NARGS64(callp); 270 /* 271 * All arguments are 32bits wide and 64bit arguments use 272 * two 32bit registers or stack slots. We need to remarshall 273 * them into 64bit slots 274 */ 275 args = copyargs; 276 CTASSERT(sizeof(copy32args[0]) != sizeof(fargs[0])); 277 278 /* 279 * If there are no 64bit arguments and all arguments were in 280 * registers, just use the frame for the source of arguments 281 */ 282 if (nargs <= nregs && narg64 == 0) { 283 args = fargs; 284 break; 285 } 286 287 if (nregs <= nargs + narg64) { 288 /* 289 * Grab the non-register arguments from the stack 290 * after skipping the slots for the 4 register passed 291 * arguments. 292 */ 293 usp = frame->f_regs[_R_SP] + 4*sizeof(int32_t); 294 error = copyin((int32_t *)usp, copy32args, 295 (nargs + narg64 - nregs) * sizeof(copy32args[0])); 296 if (error) 297 goto bad; 298 } 299 /* 300 * Copy all the arguments to copyargs, starting with the ones 301 * in registers. Using the hints in the 64bit argmask, 302 * we marshall the passed 32bit values into 64bit slots. If we 303 * encounter a 64 bit argument, we grab two adjacent 32bit 304 * values and synthesize the 64bit argument. 305 */ 306 for (i = 0, doing_arg64 = false; i < nargs + narg64;) { 307 register_t arg; 308 if (nregs > 0) { 309 arg = (int32_t) *fargs++; 310 nregs--; 311 } else { 312 arg = *cargs++; 313 } 314 if (__predict_true((arg64mask & 1) == 0)) { 315 /* 316 * Just copy it with sign extension on 317 */ 318 copyargs[i++] = (int32_t) arg; 319 arg64mask >>= 1; 320 continue; 321 } 322 /* 323 * 64bit arg. grab the low 32 bits, discard the high. 324 */ 325 arg = (uint32_t)arg; 326 if (!doing_arg64) { 327 /* 328 * Pick up the 1st word of a 64bit arg. 329 * If lowword == 1 then highword == 0, 330 * so this is the highword and thus 331 * shifted left by 32, otherwise 332 * lowword == 0 and highword == 1 so 333 * it isn't shifted at all. Remember 334 * we still need another word. 335 */ 336 doing_arg64 = true; 337 copyargs[i] = arg << (_QUAD_LOWWORD*32); 338 narg64--; /* one less 64bit arg */ 339 } else { 340 /* 341 * Pick up the 2nd word of a 64bit arg. 342 * if highword == 1, it's shifted left 343 * by 32, otherwise lowword == 1 and 344 * highword == 0 so it isn't shifted at 345 * all. And now head to the next argument. 346 */ 347 doing_arg64 = false; 348 copyargs[i++] |= arg << (_QUAD_HIGHWORD*32); 349 arg64mask >>= 1; 350 } 351 } 352 } while (/*CONSTCOND*/ 0); /* avoid a goto */ 353 #endif 354 355 #ifdef MIPS_SYSCALL_DEBUG 356 if (p->p_emul->e_syscallnames) 357 printf("syscall %s:", p->p_emul->e_syscallnames[code]); 358 else 359 printf("syscall %u:", code); 360 if (nargs == 0) 361 printf(" <no args>"); 362 else for (size_t j = 0; j < nargs; j++) { 363 if (j == nregs) printf(" *"); 364 printf(" [%s%zu]=%#"PRIxREGISTER, 365 SYCALL_ARG_64_P(callp, j) ? "+" : "", 366 j, args[j]); 367 } 368 printf("\n"); 369 #endif 370 371 if (__predict_false(p->p_trace_enabled) 372 && (error = trace_enter(code, args, nargs)) != 0) 373 goto out; 374 375 error = (*callp->sy_call)(l, args, &frame->f_regs[_R_V0]); 376 377 out: 378 switch (error) { 379 case 0: 380 #if !defined(__mips_o32) 381 if (abi == _MIPS_BSD_API_O32 && SYCALL_RET_64_P(callp)) { 382 /* 383 * If this is from O32 and it's a 64bit quantity, 384 * split it into 2 32bit values in adjacent registers. 385 */ 386 mips_reg_t tmp = frame->f_regs[_R_V0]; 387 frame->f_regs[_R_V0 + _QUAD_LOWWORD] = (int32_t) tmp; 388 frame->f_regs[_R_V0 + _QUAD_HIGHWORD] = tmp >> 32; 389 } 390 #endif 391 #ifdef MIPS_SYSCALL_DEBUG 392 if (p->p_emul->e_syscallnames) 393 printf("syscall %s:", p->p_emul->e_syscallnames[code]); 394 else 395 printf("syscall %u:", code); 396 printf(" return v0=%#"PRIxREGISTER" v1=%#"PRIxREGISTER"\n", 397 frame->f_regs[_R_V0], frame->f_regs[_R_V1]); 398 #endif 399 frame->f_regs[_R_A3] = 0; 400 break; 401 case ERESTART: 402 frame->f_regs[_R_V0] = saved_v0; /* restore syscall code */ 403 frame->f_regs[_R_PC] = opc; 404 break; 405 case EJUSTRETURN: 406 break; /* nothing to do */ 407 default: 408 bad: 409 if (p->p_emul->e_errno) 410 error = p->p_emul->e_errno[error]; 411 frame->f_regs[_R_V0] = error; 412 frame->f_regs[_R_A3] = 1; 413 #ifdef MIPS_SYSCALL_DEBUG 414 if (p->p_emul->e_syscallnames) 415 printf("syscall %s:", p->p_emul->e_syscallnames[code]); 416 else 417 printf("syscall %u:", code); 418 printf(" return error=%d\n", error); 419 #endif 420 break; 421 } 422 423 if (__predict_false(p->p_trace_enabled)) 424 trace_exit(code, &frame->f_regs[_R_V0], error); 425 426 userret(l); 427 } 428