1 /* $NetBSD: syscall.c,v 1.16 2002/11/29 11:56:36 manu 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.16 2002/11/29 11:56:36 manu Exp $"); 69 70 void 71 child_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 96 static void EMULNAME(syscall_plain)(struct trapframe *); 97 98 void 99 EMULNAME(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 #ifdef COMPAT_MACH 177 /* 178 * For regular system calls, on success, 179 * the next instruction is skipped 180 */ 181 if ((frame->fixreg[0] < p->p_emul->e_nsysent) 182 && (frame->fixreg[0] >= 0)) 183 frame->srr0 += 4; 184 #endif /* COMPAT_MACH */ 185 break; 186 case ERESTART: 187 /* 188 * Set user's pc back to redo the system call. 189 */ 190 frame->srr0 -= 4; 191 break; 192 case EJUSTRETURN: 193 /* nothing to do */ 194 break; 195 default: 196 syscall_bad: 197 if (p->p_emul->e_errno) 198 error = p->p_emul->e_errno[error]; 199 frame->fixreg[FIRSTARG] = error; 200 frame->cr |= 0x10000000; 201 break; 202 } 203 userret(p, frame); 204 } 205 206 #if defined(KTRACE) || defined(SYSTRACE) 207 static void EMULNAME(syscall_fancy)(struct trapframe *); 208 209 void 210 EMULNAME(syscall_fancy)(struct trapframe *frame) 211 { 212 struct proc *p = curproc; 213 const struct sysent *callp; 214 size_t argsize; 215 register_t code; 216 register_t realcode; 217 register_t *params, rval[2]; 218 register_t args[10]; 219 int error; 220 int n; 221 222 KERNEL_PROC_LOCK(p); 223 curcpu()->ci_ev_scalls.ev_count++; 224 225 code = frame->fixreg[0]; 226 params = frame->fixreg + FIRSTARG; 227 n = NARGREG; 228 229 realcode = code; 230 #ifdef COMPAT_MACH 231 if ((callp = mach_syscall_dispatch(&code)) == NULL) 232 #endif /* COMPAT_MACH */ 233 { 234 switch (code) { 235 case EMULNAMEU(SYS_syscall): 236 /* 237 * code is first argument, 238 * followed by actual args. 239 */ 240 code = *params++; 241 n -= 1; 242 break; 243 #if !defined(COMPAT_LINUX) 244 case EMULNAMEU(SYS___syscall): 245 params++; 246 code = *params++; 247 n -= 2; 248 break; 249 #endif 250 default: 251 break; 252 } 253 254 code &= EMULNAMEU(SYS_NSYSENT) - 1; 255 callp = p->p_emul->e_sysent + code; 256 realcode = code; 257 } 258 259 argsize = callp->sy_argsize; 260 261 if (argsize > n * sizeof(register_t)) { 262 memcpy(args, params, n * sizeof(register_t)); 263 error = copyin(MOREARGS(frame->fixreg[1]), 264 args + n, 265 argsize - n * sizeof(register_t)); 266 if (error) 267 goto syscall_bad; 268 params = args; 269 } 270 271 if ((error = trace_enter(p, code, realcode, params, rval)) != 0) 272 goto syscall_bad; 273 274 rval[0] = 0; 275 rval[1] = 0; 276 277 error = (*callp->sy_call)(p, params, rval); 278 switch (error) { 279 case 0: 280 frame->fixreg[FIRSTARG] = rval[0]; 281 frame->fixreg[FIRSTARG + 1] = rval[1]; 282 frame->cr &= ~0x10000000; 283 #ifdef COMPAT_MACH 284 /* 285 * For regular system calls, on success, 286 * the next instruction is skipped 287 */ 288 if ((frame->fixreg[0] < p->p_emul->e_nsysent) 289 && (frame->fixreg[0] >= 0)) 290 frame->srr0 += 4; 291 #endif /* COMPAT_MACH */ 292 break; 293 case ERESTART: 294 /* 295 * Set user's pc back to redo the system call. 296 */ 297 frame->srr0 -= 4; 298 break; 299 case EJUSTRETURN: 300 /* nothing to do */ 301 break; 302 default: 303 syscall_bad: 304 if (p->p_emul->e_errno) 305 error = p->p_emul->e_errno[error]; 306 frame->fixreg[FIRSTARG] = error; 307 frame->cr |= 0x10000000; 308 break; 309 } 310 KERNEL_PROC_UNLOCK(p); 311 trace_exit(p, realcode, params, rval, error); 312 userret(p, frame); 313 } 314 #endif /* KTRACE || SYSTRACE */ 315 316 void EMULNAME(syscall_intern)(struct proc *); 317 318 void 319 EMULNAME(syscall_intern)(struct proc *p) 320 { 321 #ifdef KTRACE 322 if (p->p_traceflag & (KTRFAC_SYSCALL | KTRFAC_SYSRET)) { 323 p->p_md.md_syscall = EMULNAME(syscall_fancy); 324 return; 325 } 326 #endif 327 #ifdef SYSTRACE 328 if (ISSET(p->p_flag, P_SYSTRACE)) { 329 p->p_md.md_syscall = EMULNAME(syscall_fancy); 330 return; 331 } 332 #endif 333 p->p_md.md_syscall = EMULNAME(syscall_plain); 334 } 335 336