1 /* $NetBSD: syscall.c,v 1.46 2011/01/18 01:02:55 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_multiprocessor.h" 37 #include "opt_sa.h" 38 /* DO NOT INCLUDE opt_compat_XXX.h */ 39 /* If needed, they will be included by file that includes this one */ 40 41 #include <sys/param.h> 42 #include <sys/cpu.h> 43 #include <sys/ktrace.h> 44 #include <sys/proc.h> 45 #include <sys/reboot.h> 46 #include <sys/systm.h> 47 #include <sys/sa.h> 48 #include <sys/savar.h> 49 #include <sys/syscallvar.h> 50 51 #include <uvm/uvm_extern.h> 52 53 #include <powerpc/frame.h> 54 #include <powerpc/pcb.h> 55 #include <powerpc/userret.h> 56 57 #define FIRSTARG 3 /* first argument is in reg 3 */ 58 #define NARGREG 8 /* 8 args are in registers */ 59 #define MOREARGS(sp) ((void *)((uintptr_t)(sp) + 8)) /* more args go here */ 60 61 #ifndef EMULNAME 62 #include <sys/syscall.h> 63 64 #define EMULNAME(x) (x) 65 #define EMULNAMEU(x) (x) 66 67 __KERNEL_RCSID(0, "$NetBSD: syscall.c,v 1.46 2011/01/18 01:02:55 matt Exp $"); 68 69 void 70 child_return(void *arg) 71 { 72 struct lwp * const l = arg; 73 struct trapframe * const tf = trapframe(l); 74 75 tf->tf_fixreg[FIRSTARG] = 0; 76 tf->tf_fixreg[FIRSTARG + 1] = 1; 77 tf->tf_cr &= ~0x10000000; 78 tf->tf_srr1 &= ~(PSL_FP|PSL_VEC); /* Disable FP & AltiVec, as we can't 79 be them. */ 80 ktrsysret(SYS_fork, 0, 0); 81 /* Profiling? XXX */ 82 } 83 #endif 84 85 static void EMULNAME(syscall_plain)(struct trapframe *); 86 87 #include <powerpc/spr.h> 88 89 void 90 EMULNAME(syscall_plain)(struct trapframe *tf) 91 { 92 struct lwp *l = curlwp; 93 struct proc *p = l->l_proc; 94 const struct sysent *callp; 95 size_t argsize; 96 register_t code; 97 register_t *params, rval[2]; 98 register_t args[10]; 99 int error; 100 int n; 101 102 LWP_CACHE_CREDS(l, p); 103 curcpu()->ci_ev_scalls.ev_count++; 104 curcpu()->ci_data.cpu_nsyscall++; 105 106 code = tf->tf_fixreg[0]; 107 params = tf->tf_fixreg + FIRSTARG; 108 n = NARGREG; 109 110 #ifdef KERN_SA 111 if (__predict_false((l->l_savp) 112 && (l->l_savp->savp_pflags & SAVP_FLAG_DELIVERING))) 113 l->l_savp->savp_pflags &= ~SAVP_FLAG_DELIVERING; 114 #endif 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 error = copyin(MOREARGS(tf->tf_fixreg[1]), 149 args + n, 150 argsize - n * sizeof(register_t)); 151 if (error) 152 goto bad; 153 params = args; 154 } 155 156 rval[0] = 0; 157 rval[1] = 0; 158 159 error = sy_call(callp, l, params, rval); 160 161 switch (error) { 162 case 0: 163 tf->tf_fixreg[FIRSTARG] = rval[0]; 164 tf->tf_fixreg[FIRSTARG + 1] = rval[1]; 165 tf->tf_cr &= ~0x10000000; 166 #ifdef COMPAT_MACH 167 /* 168 * For regular system calls, on success, 169 * the next instruction is skipped 170 */ 171 if ((tf->tf_fixreg[0] < p->p_emul->e_nsysent) 172 && (tf->tf_fixreg[0] >= 0)) 173 tf->tf_srr0 += 4; 174 #endif /* COMPAT_MACH */ 175 break; 176 case ERESTART: 177 /* 178 * Set user's pc back to redo the system call. 179 */ 180 tf->tf_srr0 -= 4; 181 break; 182 case EJUSTRETURN: 183 /* nothing to do */ 184 break; 185 default: 186 bad: 187 if (p->p_emul->e_errno) 188 error = p->p_emul->e_errno[error]; 189 tf->tf_fixreg[FIRSTARG] = error; 190 tf->tf_cr |= 0x10000000; 191 break; 192 } 193 194 userret(l, tf); 195 } 196 197 static void EMULNAME(syscall_fancy)(struct trapframe *); 198 199 void 200 EMULNAME(syscall_fancy)(struct trapframe *tf) 201 { 202 struct lwp *l = curlwp; 203 struct proc *p = l->l_proc; 204 const struct sysent *callp; 205 size_t argsize; 206 register_t code; 207 register_t realcode; 208 register_t *params, rval[2]; 209 register_t args[10]; 210 int error; 211 int n; 212 213 LWP_CACHE_CREDS(l, p); 214 215 curcpu()->ci_ev_scalls.ev_count++; 216 217 code = tf->tf_fixreg[0]; 218 params = tf->tf_fixreg + FIRSTARG; 219 n = NARGREG; 220 221 #ifdef KERN_SA 222 if (__predict_false((l->l_savp) 223 && (l->l_savp->savp_pflags & SAVP_FLAG_DELIVERING))) 224 l->l_savp->savp_pflags &= ~SAVP_FLAG_DELIVERING; 225 #endif 226 227 realcode = code; 228 #ifdef COMPAT_MACH 229 if ((callp = mach_syscall_dispatch(&code)) == NULL) 230 #endif /* COMPAT_MACH */ 231 { 232 switch (code) { 233 case EMULNAMEU(SYS_syscall): 234 /* 235 * code is first argument, 236 * followed by actual args. 237 */ 238 code = *params++; 239 n -= 1; 240 break; 241 #if !defined(COMPAT_LINUX) 242 case EMULNAMEU(SYS___syscall): 243 params++; 244 code = *params++; 245 n -= 2; 246 break; 247 #endif 248 default: 249 break; 250 } 251 252 code &= EMULNAMEU(SYS_NSYSENT) - 1; 253 callp = p->p_emul->e_sysent + code; 254 realcode = code; 255 } 256 257 argsize = callp->sy_argsize; 258 259 if (argsize > n * sizeof(register_t)) { 260 memcpy(args, params, n * sizeof(register_t)); 261 error = copyin(MOREARGS(tf->tf_fixreg[1]), 262 args + n, 263 argsize - n * sizeof(register_t)); 264 if (error) 265 goto bad; 266 params = args; 267 } 268 269 if ((error = trace_enter(realcode, params, callp->sy_narg)) != 0) 270 goto out; 271 272 rval[0] = 0; 273 rval[1] = 0; 274 275 error = sy_call(callp, l, params, rval); 276 out: 277 switch (error) { 278 case 0: 279 tf->tf_fixreg[FIRSTARG] = rval[0]; 280 tf->tf_fixreg[FIRSTARG + 1] = rval[1]; 281 tf->tf_cr &= ~0x10000000; 282 #ifdef COMPAT_MACH 283 /* 284 * For regular system calls, on success, 285 * the next instruction is skipped 286 */ 287 if ((tf->tf_fixreg[0] < p->p_emul->e_nsysent) 288 && (tf->tf_fixreg[0] >= 0)) 289 tf->tf_srr0 += 4; 290 #endif /* COMPAT_MACH */ 291 break; 292 case ERESTART: 293 /* 294 * Set user's pc back to redo the system call. 295 */ 296 tf->tf_srr0 -= 4; 297 break; 298 case EJUSTRETURN: 299 /* nothing to do */ 300 break; 301 default: 302 bad: 303 if (p->p_emul->e_errno) 304 error = p->p_emul->e_errno[error]; 305 tf->tf_fixreg[FIRSTARG] = error; 306 tf->tf_cr |= 0x10000000; 307 break; 308 } 309 trace_exit(realcode, rval, error); 310 userret(l, tf); 311 } 312 313 void EMULNAME(syscall_intern)(struct proc *); 314 315 void 316 EMULNAME(syscall_intern)(struct proc *p) 317 { 318 319 if (trace_is_enabled(p)) 320 p->p_md.md_syscall = EMULNAME(syscall_fancy); 321 else 322 p->p_md.md_syscall = EMULNAME(syscall_plain); 323 } 324