syscall.c revision 1.12
1/* $NetBSD: syscall.c,v 1.12 2002/11/04 00:01:03 matt 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 40#include <sys/param.h> 41#include <sys/proc.h> 42#include <sys/reboot.h> 43#include <sys/systm.h> 44#include <sys/user.h> 45#ifdef KTRACE 46#include <sys/ktrace.h> 47#endif 48#ifdef SYSTRACE 49#include <sys/systrace.h> 50#endif 51 52#include <uvm/uvm_extern.h> 53 54#include <powerpc/userret.h> 55#include <machine/cpu.h> 56#include <machine/frame.h> 57 58#define FIRSTARG 3 /* first argument is in reg 3 */ 59#define NARGREG 8 /* 8 args are in registers */ 60#define MOREARGS(sp) ((caddr_t)((uintptr_t)(sp) + 8)) /* more args go here */ 61 62#ifndef EMULNAME 63#include <sys/syscall.h> 64 65#define EMULNAME(x) (x) 66#define EMULNAMEU(x) (x) 67 68__KERNEL_RCSID(0, "$NetBSD: syscall.c,v 1.12 2002/11/04 00:01:03 matt Exp $"); 69 70void 71child_return(void *arg) 72{ 73 struct proc * const p = arg; 74 struct trapframe * const tf = trapframe(p); 75 76 KERNEL_PROC_UNLOCK(p); 77 78 tf->fixreg[FIRSTARG] = 0; 79 tf->fixreg[FIRSTARG + 1] = 1; 80 tf->cr &= ~0x10000000; 81 tf->srr1 &= ~(PSL_FP|PSL_VEC); /* Disable FP & AltiVec, as we can't 82 be them. */ 83 p->p_addr->u_pcb.pcb_fpcpu = NULL; 84#ifdef KTRACE 85 if (KTRPOINT(p, KTR_SYSRET)) { 86 KERNEL_PROC_LOCK(p); 87 ktrsysret(p, SYS_fork, 0, 0); 88 KERNEL_PROC_UNLOCK(p); 89 } 90#endif 91 /* Profiling? XXX */ 92 curcpu()->ci_schedstate.spc_curpriority = p->p_priority; 93} 94#endif 95 96static void EMULNAME(syscall_plain)(struct trapframe *); 97 98void 99EMULNAME(syscall_plain)(struct trapframe *frame) 100{ 101 struct proc *p = curproc; 102 const struct sysent *callp; 103 size_t argsize; 104 register_t code; 105 register_t *params, rval[2]; 106 register_t args[10]; 107 int error; 108 int n; 109 110 curcpu()->ci_ev_scalls.ev_count++; 111 112 code = frame->fixreg[0]; 113 params = frame->fixreg + FIRSTARG; 114 n = NARGREG; 115 116#ifdef COMPAT_MACH 117 if ((callp = mach_syscall_dispatch(code)) == NULL) 118#endif /* COMPAT_MACH */ 119 { 120 switch (code) { 121 case EMULNAMEU(SYS_syscall): 122 /* 123 * code is first argument, 124 * followed by actual args. 125 */ 126 code = *params++; 127 n -= 1; 128 break; 129#if !defined(COMPAT_LINUX) 130 case EMULNAMEU(SYS___syscall): 131 params++; 132 code = *params++; 133 n -= 2; 134 break; 135#endif 136 default: 137 break; 138 } 139 140 callp = p->p_emul->e_sysent + 141 (code & (EMULNAMEU(SYS_NSYSENT)-1)); 142 } 143 144 argsize = callp->sy_argsize; 145 146 if (argsize > n * sizeof(register_t)) { 147 memcpy(args, params, n * sizeof(register_t)); 148 KERNEL_PROC_LOCK(p); 149 error = copyin(MOREARGS(frame->fixreg[1]), 150 args + n, 151 argsize - n * sizeof(register_t)); 152 KERNEL_PROC_UNLOCK(p); 153 if (error) 154 goto syscall_bad; 155 params = args; 156 } 157 158 rval[0] = 0; 159 rval[1] = 0; 160 161 if ((callp->sy_flags & SYCALL_MPSAFE) == 0) { 162 KERNEL_PROC_LOCK(p); 163 } 164 165 error = (*callp->sy_call)(p, params, rval); 166 167 if ((callp->sy_flags & SYCALL_MPSAFE) == 0) { 168 KERNEL_PROC_UNLOCK(p); 169 } 170 171 switch (error) { 172 case 0: 173 frame->fixreg[FIRSTARG] = rval[0]; 174 frame->fixreg[FIRSTARG + 1] = rval[1]; 175 frame->cr &= ~0x10000000; 176 break; 177 case ERESTART: 178 /* 179 * Set user's pc back to redo the system call. 180 */ 181 frame->srr0 -= 4; 182 break; 183 case EJUSTRETURN: 184 /* nothing to do */ 185 break; 186 default: 187syscall_bad: 188 if (p->p_emul->e_errno) 189 error = p->p_emul->e_errno[error]; 190 frame->fixreg[FIRSTARG] = error; 191 frame->cr |= 0x10000000; 192 break; 193 } 194 userret(p, frame); 195} 196 197#if defined(KTRACE) || defined(SYSTRACE) 198static void EMULNAME(syscall_fancy)(struct trapframe *); 199 200void 201EMULNAME(syscall_fancy)(struct trapframe *frame) 202{ 203 struct proc *p = curproc; 204 const struct sysent *callp; 205 size_t argsize; 206 register_t code; 207 register_t *params, rval[2]; 208 register_t args[10]; 209 int error; 210 int n; 211 212 KERNEL_PROC_LOCK(p); 213 curcpu()->ci_ev_scalls.ev_count++; 214 215 code = frame->fixreg[0]; 216 params = frame->fixreg + FIRSTARG; 217 n = NARGREG; 218 219#ifdef COMPAT_MACH 220 if ((callp = mach_syscall_dispatch(code)) == NULL) 221#endif /* COMPAT_MACH */ 222 { 223 switch (code) { 224 case EMULNAMEU(SYS_syscall): 225 /* 226 * code is first argument, 227 * followed by actual args. 228 */ 229 code = *params++; 230 n -= 1; 231 break; 232#if !defined(COMPAT_LINUX) 233 case EMULNAMEU(SYS___syscall): 234 params++; 235 code = *params++; 236 n -= 2; 237 break; 238#endif 239 default: 240 break; 241 } 242 243 callp = p->p_emul->e_sysent + 244 (code & (EMULNAMEU(SYS_NSYSENT)-1)); 245 } 246 247 argsize = callp->sy_argsize; 248 249 if (argsize > n * sizeof(register_t)) { 250 memcpy(args, params, n * sizeof(register_t)); 251 error = copyin(MOREARGS(frame->fixreg[1]), 252 args + n, 253 argsize - n * sizeof(register_t)); 254 if (error) 255 goto syscall_bad; 256 params = args; 257 } 258 259 if ((error = trace_enter(p, code, params, rval)) != 0) 260 goto syscall_bad; 261 262 rval[0] = 0; 263 rval[1] = 0; 264 265 error = (*callp->sy_call)(p, params, rval); 266 switch (error) { 267 case 0: 268 frame->fixreg[FIRSTARG] = rval[0]; 269 frame->fixreg[FIRSTARG + 1] = rval[1]; 270 frame->cr &= ~0x10000000; 271 break; 272 case ERESTART: 273 /* 274 * Set user's pc back to redo the system call. 275 */ 276 frame->srr0 -= 4; 277 break; 278 case EJUSTRETURN: 279 /* nothing to do */ 280 break; 281 default: 282syscall_bad: 283 if (p->p_emul->e_errno) 284 error = p->p_emul->e_errno[error]; 285 frame->fixreg[FIRSTARG] = error; 286 frame->cr |= 0x10000000; 287 break; 288 } 289 KERNEL_PROC_UNLOCK(p); 290 trace_exit(p, code, params, rval, error); 291 userret(p, frame); 292} 293#endif /* KTRACE || SYSTRACE */ 294 295void EMULNAME(syscall_intern)(struct proc *); 296 297void 298EMULNAME(syscall_intern)(struct proc *p) 299{ 300#ifdef KTRACE 301 if (p->p_traceflag & (KTRFAC_SYSCALL | KTRFAC_SYSRET)) { 302 p->p_md.md_syscall = EMULNAME(syscall_fancy); 303 return; 304 } 305#endif 306#ifdef SYSTRACE 307 if (ISSET(p->p_flag, P_SYSTRACE)) { 308 p->p_md.md_syscall = EMULNAME(syscall_fancy); 309 return; 310 } 311#endif 312 p->p_md.md_syscall = EMULNAME(syscall_plain); 313} 314 315