syscall.c revision 1.27
1/* $NetBSD: syscall.c,v 1.27 2006/03/05 19:08:39 christos Exp $ */ 2 3/* 4 * Copyright (C) 2002 Matt Thomas 5 * Copyright (C) 1995, 1996 Wolfgang Solfrank. 6 * Copyright (C) 1995, 1996 TooLs GmbH. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by TooLs GmbH. 20 * 4. The name of TooLs GmbH may not be used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 28 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 29 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 31 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 32 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35#include "opt_altivec.h" 36#include "opt_ktrace.h" 37#include "opt_systrace.h" 38#include "opt_multiprocessor.h" 39/* DO NOT INCLUDE opt_compat_XXX.h */ 40/* If needed, they will be included by file that includes this one */ 41 42#include <sys/param.h> 43#include <sys/proc.h> 44#include <sys/reboot.h> 45#include <sys/systm.h> 46#include <sys/user.h> 47#include <sys/sa.h> 48#include <sys/savar.h> 49#ifdef KTRACE 50#include <sys/ktrace.h> 51#endif 52#ifdef SYSTRACE 53#include <sys/systrace.h> 54#endif 55 56#include <uvm/uvm_extern.h> 57 58#include <powerpc/userret.h> 59#include <machine/cpu.h> 60#include <machine/frame.h> 61 62#define FIRSTARG 3 /* first argument is in reg 3 */ 63#define NARGREG 8 /* 8 args are in registers */ 64#define MOREARGS(sp) ((caddr_t)((uintptr_t)(sp) + 8)) /* more args go here */ 65 66#ifndef EMULNAME 67#include <sys/syscall.h> 68 69#define EMULNAME(x) (x) 70#define EMULNAMEU(x) (x) 71 72__KERNEL_RCSID(0, "$NetBSD: syscall.c,v 1.27 2006/03/05 19:08:39 christos Exp $"); 73 74void 75child_return(void *arg) 76{ 77 struct lwp * const l = arg; 78#ifdef KTRACE 79 struct proc * const p = l->l_proc; 80#endif 81 struct trapframe * const tf = trapframe(l); 82 83 KERNEL_PROC_UNLOCK(l); 84 85 tf->fixreg[FIRSTARG] = 0; 86 tf->fixreg[FIRSTARG + 1] = 1; 87 tf->cr &= ~0x10000000; 88 tf->srr1 &= ~(PSL_FP|PSL_VEC); /* Disable FP & AltiVec, as we can't 89 be them. */ 90 l->l_addr->u_pcb.pcb_fpcpu = NULL; 91#ifdef KTRACE 92 if (KTRPOINT(p, KTR_SYSRET)) { 93 KERNEL_PROC_LOCK(l); 94 ktrsysret(l, SYS_fork, 0, 0); 95 KERNEL_PROC_UNLOCK(l); 96 } 97#endif 98 /* Profiling? XXX */ 99 curcpu()->ci_schedstate.spc_curpriority = l->l_priority; 100} 101#endif 102 103static void EMULNAME(syscall_plain)(struct trapframe *); 104 105void 106EMULNAME(syscall_plain)(struct trapframe *frame) 107{ 108 struct lwp *l = curlwp; 109 struct proc *p = l->l_proc; 110 const struct sysent *callp; 111 size_t argsize; 112 register_t code; 113 register_t *params, rval[2]; 114 register_t args[10]; 115 int error; 116 int n; 117 118 curcpu()->ci_ev_scalls.ev_count++; 119 120 code = frame->fixreg[0]; 121 params = frame->fixreg + FIRSTARG; 122 n = NARGREG; 123 124#ifdef COMPAT_MACH 125 if ((callp = mach_syscall_dispatch(&code)) == NULL) 126#endif /* COMPAT_MACH */ 127 { 128 switch (code) { 129 case EMULNAMEU(SYS_syscall): 130 /* 131 * code is first argument, 132 * followed by actual args. 133 */ 134 code = *params++; 135 n -= 1; 136 break; 137#if !defined(COMPAT_LINUX) 138 case EMULNAMEU(SYS___syscall): 139 params++; 140 code = *params++; 141 n -= 2; 142 break; 143#endif 144 default: 145 break; 146 } 147 148 callp = p->p_emul->e_sysent + 149 (code & (EMULNAMEU(SYS_NSYSENT)-1)); 150 } 151 152 argsize = callp->sy_argsize; 153 154 if (argsize > n * sizeof(register_t)) { 155 memcpy(args, params, n * sizeof(register_t)); 156 KERNEL_PROC_LOCK(l); 157 error = copyin(MOREARGS(frame->fixreg[1]), 158 args + n, 159 argsize - n * sizeof(register_t)); 160 KERNEL_PROC_UNLOCK(l); 161 if (error) 162 goto bad; 163 params = args; 164 } 165 166 rval[0] = 0; 167 rval[1] = 0; 168 169 if ((callp->sy_flags & SYCALL_MPSAFE) == 0) { 170 KERNEL_PROC_LOCK(l); 171 } 172 173 error = (*callp->sy_call)(l, params, rval); 174 175 if ((callp->sy_flags & SYCALL_MPSAFE) == 0) { 176 KERNEL_PROC_UNLOCK(l); 177 } 178 switch (error) { 179 case 0: 180 frame->fixreg[FIRSTARG] = rval[0]; 181 frame->fixreg[FIRSTARG + 1] = rval[1]; 182 frame->cr &= ~0x10000000; 183#ifdef COMPAT_MACH 184 /* 185 * For regular system calls, on success, 186 * the next instruction is skipped 187 */ 188 if ((frame->fixreg[0] < p->p_emul->e_nsysent) 189 && (frame->fixreg[0] >= 0)) 190 frame->srr0 += 4; 191#endif /* COMPAT_MACH */ 192 break; 193 case ERESTART: 194 /* 195 * Set user's pc back to redo the system call. 196 */ 197 frame->srr0 -= 4; 198 break; 199 case EJUSTRETURN: 200 /* nothing to do */ 201 break; 202 default: 203 bad: 204 if (p->p_emul->e_errno) 205 error = p->p_emul->e_errno[error]; 206 frame->fixreg[FIRSTARG] = error; 207 frame->cr |= 0x10000000; 208 break; 209 } 210 userret(l, frame); 211} 212 213#if defined(KTRACE) || defined(SYSTRACE) 214static void EMULNAME(syscall_fancy)(struct trapframe *); 215 216void 217EMULNAME(syscall_fancy)(struct trapframe *frame) 218{ 219 struct lwp *l = curlwp; 220 struct proc *p = l->l_proc; 221 const struct sysent *callp; 222 size_t argsize; 223 register_t code; 224 register_t realcode; 225 register_t *params, rval[2]; 226 register_t args[10]; 227 int error; 228 int n; 229 230 KERNEL_PROC_LOCK(l); 231 curcpu()->ci_ev_scalls.ev_count++; 232 233 code = frame->fixreg[0]; 234 params = frame->fixreg + FIRSTARG; 235 n = NARGREG; 236 237 realcode = code; 238#ifdef COMPAT_MACH 239 if ((callp = mach_syscall_dispatch(&code)) == NULL) 240#endif /* COMPAT_MACH */ 241 { 242 switch (code) { 243 case EMULNAMEU(SYS_syscall): 244 /* 245 * code is first argument, 246 * followed by actual args. 247 */ 248 code = *params++; 249 n -= 1; 250 break; 251#if !defined(COMPAT_LINUX) 252 case EMULNAMEU(SYS___syscall): 253 params++; 254 code = *params++; 255 n -= 2; 256 break; 257#endif 258 default: 259 break; 260 } 261 262 code &= EMULNAMEU(SYS_NSYSENT) - 1; 263 callp = p->p_emul->e_sysent + code; 264 realcode = code; 265 } 266 267 argsize = callp->sy_argsize; 268 269 if (argsize > n * sizeof(register_t)) { 270 memcpy(args, params, n * sizeof(register_t)); 271 error = copyin(MOREARGS(frame->fixreg[1]), 272 args + n, 273 argsize - n * sizeof(register_t)); 274 if (error) 275 goto bad; 276 params = args; 277 } 278 279 if ((error = trace_enter(l, code, realcode, callp - code, params)) != 0) 280 goto out; 281 282 rval[0] = 0; 283 rval[1] = 0; 284 285 error = (*callp->sy_call)(l, params, rval); 286out: 287 switch (error) { 288 case 0: 289 frame->fixreg[FIRSTARG] = rval[0]; 290 frame->fixreg[FIRSTARG + 1] = rval[1]; 291 frame->cr &= ~0x10000000; 292#ifdef COMPAT_MACH 293 /* 294 * For regular system calls, on success, 295 * the next instruction is skipped 296 */ 297 if ((frame->fixreg[0] < p->p_emul->e_nsysent) 298 && (frame->fixreg[0] >= 0)) 299 frame->srr0 += 4; 300#endif /* COMPAT_MACH */ 301 break; 302 case ERESTART: 303 /* 304 * Set user's pc back to redo the system call. 305 */ 306 frame->srr0 -= 4; 307 break; 308 case EJUSTRETURN: 309 /* nothing to do */ 310 break; 311 default: 312 bad: 313 if (p->p_emul->e_errno) 314 error = p->p_emul->e_errno[error]; 315 frame->fixreg[FIRSTARG] = error; 316 frame->cr |= 0x10000000; 317 break; 318 } 319 KERNEL_PROC_UNLOCK(l); 320 trace_exit(l, realcode, params, rval, error); 321 userret(l, frame); 322} 323#endif /* KTRACE || SYSTRACE */ 324 325void EMULNAME(syscall_intern)(struct proc *); 326 327void 328EMULNAME(syscall_intern)(struct proc *p) 329{ 330 if (proc_is_traced_p(p)) 331 p->p_md.md_syscall = EMULNAME(syscall_fancy); 332 else 333 p->p_md.md_syscall = EMULNAME(syscall_plain); 334} 335