syscall.c revision 1.5
1205408Srdivacky/* $NetBSD: syscall.c,v 1.5 2002/10/30 06:37:38 manu Exp $ */ 2205408Srdivacky 3205408Srdivacky/* 4205408Srdivacky * Copyright (C) 2002 Matt Thomas 5205408Srdivacky * Copyright (C) 1995, 1996 Wolfgang Solfrank. 6205408Srdivacky * Copyright (C) 1995, 1996 TooLs GmbH. 7205408Srdivacky * All rights reserved. 8205408Srdivacky * 9205408Srdivacky * Redistribution and use in source and binary forms, with or without 10205408Srdivacky * modification, are permitted provided that the following conditions 11205408Srdivacky * are met: 12205408Srdivacky * 1. Redistributions of source code must retain the above copyright 13205408Srdivacky * notice, this list of conditions and the following disclaimer. 14205408Srdivacky * 2. Redistributions in binary form must reproduce the above copyright 15205408Srdivacky * notice, this list of conditions and the following disclaimer in the 16205408Srdivacky * documentation and/or other materials provided with the distribution. 17205408Srdivacky * 3. All advertising materials mentioning features or use of this software 18205408Srdivacky * must display the following acknowledgement: 19205408Srdivacky * This product includes software developed by TooLs GmbH. 20205408Srdivacky * 4. The name of TooLs GmbH may not be used to endorse or promote products 21205408Srdivacky * derived from this software without specific prior written permission. 22205408Srdivacky * 23205408Srdivacky * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 24205408Srdivacky * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25205408Srdivacky * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26205408Srdivacky * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27205408Srdivacky * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 28205408Srdivacky * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 29205408Srdivacky * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 30205408Srdivacky * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 31205408Srdivacky * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 32205408Srdivacky * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33205408Srdivacky */ 34205408Srdivacky 35205408Srdivacky#include "opt_altivec.h" 36205408Srdivacky#include "opt_ktrace.h" 37205408Srdivacky#include "opt_systrace.h" 38205408Srdivacky#include "opt_compat_linux.h" 39205408Srdivacky#include "opt_multiprocessor.h" 40205408Srdivacky 41205408Srdivacky#include <sys/param.h> 42205408Srdivacky#include <sys/proc.h> 43205408Srdivacky#include <sys/reboot.h> 44205408Srdivacky#include <sys/syscall.h> 45205408Srdivacky#include <sys/systm.h> 46205408Srdivacky#include <sys/user.h> 47205408Srdivacky#ifdef KTRACE 48205408Srdivacky#include <sys/ktrace.h> 49205408Srdivacky#endif 50205408Srdivacky#ifdef SYSTRACE 51205408Srdivacky#include <sys/systrace.h> 52205408Srdivacky#endif 53205408Srdivacky 54205408Srdivacky#include <uvm/uvm_extern.h> 55205408Srdivacky 56205408Srdivacky#include <powerpc/userret.h> 57205408Srdivacky#include <machine/cpu.h> 58205408Srdivacky#include <machine/frame.h> 59205408Srdivacky 60205408Srdivacky#ifdef COMPAT_LINUX 61205408Srdivacky#include <compat/linux/common/linux_types.h> 62205408Srdivacky#include <compat/linux/common/linux_errno.h> 63205408Srdivacky#include <compat/linux/linux_syscall.h> 64205408Srdivacky#include <compat/linux/common/linux_signal.h> 65205408Srdivacky#include <compat/linux/common/linux_siginfo.h> 66205408Srdivacky#include <compat/linux/arch/powerpc/linux_siginfo.h> 67205408Srdivacky#include <compat/linux/arch/powerpc/linux_machdep.h> 68205408Srdivacky#endif 69205408Srdivacky 70205408Srdivacky#define FIRSTARG 3 /* first argument is in reg 3 */ 71205408Srdivacky#define NARGREG 8 /* 8 args are in registers */ 72205408Srdivacky#define MOREARGS(sp) ((caddr_t)((uintptr_t)(sp) + 8)) /* more args go here */ 73205408Srdivacky 74205408Srdivacky#ifndef EMULNAME 75205408Srdivacky#define EMULNAME(x) (x) 76205408Srdivacky#endif 77205408Srdivacky 78205408Srdivackyvoid EMULNAME(syscall_plain)(struct trapframe *frame); 79205408Srdivackyvoid EMULNAME(syscall_fancy)(struct trapframe *frame); 80205408Srdivacky 81205408Srdivackyvoid 82205408SrdivackyEMULNAME(syscall_plain)(struct trapframe *frame) 83205408Srdivacky{ 84205408Srdivacky struct proc *p = curproc; 85205408Srdivacky const struct sysent *callp; 86205408Srdivacky size_t argsize; 87205408Srdivacky register_t code; 88205408Srdivacky register_t *params, rval[2]; 89205408Srdivacky register_t args[10]; 90205408Srdivacky int error; 91205408Srdivacky int n; 92205408Srdivacky 93205408Srdivacky curcpu()->ci_ev_scalls.ev_count++; 94205408Srdivacky 95205408Srdivacky code = frame->fixreg[0]; 96205408Srdivacky 97205408Srdivacky callp = p->p_emul->e_sysent; 98205408Srdivacky params = frame->fixreg + FIRSTARG; 99205408Srdivacky n = NARGREG; 100205408Srdivacky 101205408Srdivacky switch (code) { 102205408Srdivacky case SYS_syscall: 103205408Srdivacky /* 104205408Srdivacky * code is first argument, 105205408Srdivacky * followed by actual args. 106205408Srdivacky */ 107205408Srdivacky code = *params++; 108205408Srdivacky n -= 1; 109205408Srdivacky break; 110205408Srdivacky case SYS___syscall: 111205408Srdivacky params++; 112205408Srdivacky code = *params++; 113205408Srdivacky n -= 2; 114205408Srdivacky break; 115205408Srdivacky default: 116205408Srdivacky break; 117205408Srdivacky } 118205408Srdivacky 119205408Srdivacky code &= (SYS_NSYSENT - 1); 120205408Srdivacky callp += code; 121205408Srdivacky argsize = callp->sy_argsize; 122205408Srdivacky 123205408Srdivacky if (argsize > n * sizeof(register_t)) { 124205408Srdivacky memcpy(args, params, n * sizeof(register_t)); 125205408Srdivacky KERNEL_PROC_LOCK(p); 126205408Srdivacky error = copyin(MOREARGS(frame->fixreg[1]), 127205408Srdivacky args + n, 128205408Srdivacky argsize - n * sizeof(register_t)); 129205408Srdivacky KERNEL_PROC_UNLOCK(p); 130205408Srdivacky if (error) 131205408Srdivacky goto syscall_bad; 132205408Srdivacky params = args; 133205408Srdivacky } 134205408Srdivacky 135205408Srdivacky rval[0] = 0; 136205408Srdivacky rval[1] = 0; 137205408Srdivacky 138205408Srdivacky if ((callp->sy_flags & SYCALL_MPSAFE) == 0) { 139205408Srdivacky KERNEL_PROC_LOCK(p); 140205408Srdivacky } 141205408Srdivacky 142205408Srdivacky error = (*callp->sy_call)(p, params, rval); 143205408Srdivacky 144205408Srdivacky if ((callp->sy_flags & SYCALL_MPSAFE) == 0) { 145205408Srdivacky KERNEL_PROC_UNLOCK(p); 146205408Srdivacky } 147205408Srdivacky 148205408Srdivacky switch (error) { 149205408Srdivacky case 0: 150205408Srdivacky frame->fixreg[FIRSTARG] = rval[0]; 151205408Srdivacky frame->fixreg[FIRSTARG + 1] = rval[1]; 152205408Srdivacky frame->cr &= ~0x10000000; 153205408Srdivacky break; 154205408Srdivacky case ERESTART: 155205408Srdivacky /* 156205408Srdivacky * Set user's pc back to redo the system call. 157205408Srdivacky */ 158205408Srdivacky frame->srr0 -= 4; 159205408Srdivacky break; 160205408Srdivacky case EJUSTRETURN: 161205408Srdivacky /* nothing to do */ 162205408Srdivacky break; 163205408Srdivacky default: 164205408Srdivackysyscall_bad: 165205408Srdivacky if (p->p_emul->e_errno) 166205408Srdivacky error = p->p_emul->e_errno[error]; 167205408Srdivacky frame->fixreg[FIRSTARG] = error; 168205408Srdivacky frame->cr |= 0x10000000; 169205408Srdivacky break; 170205408Srdivacky } 171205408Srdivacky userret(p, frame); 172205408Srdivacky} 173205408Srdivacky 174205408Srdivackyvoid 175205408SrdivackyEMULNAME(syscall_fancy)(struct trapframe *frame) 176205408Srdivacky{ 177205408Srdivacky struct proc *p = curproc; 178205408Srdivacky const struct sysent *callp; 179205408Srdivacky size_t argsize; 180205408Srdivacky register_t code; 181205408Srdivacky register_t *params, rval[2]; 182205408Srdivacky register_t args[10]; 183205408Srdivacky int error; 184205408Srdivacky int n; 185205408Srdivacky 186205408Srdivacky KERNEL_PROC_LOCK(p); 187205408Srdivacky curcpu()->ci_ev_scalls.ev_count++; 188205408Srdivacky 189205408Srdivacky code = frame->fixreg[0]; 190205408Srdivacky callp = p->p_emul->e_sysent; 191205408Srdivacky params = frame->fixreg + FIRSTARG; 192205408Srdivacky n = NARGREG; 193205408Srdivacky 194205408Srdivacky switch (code) { 195205408Srdivacky case SYS_syscall: 196205408Srdivacky /* 197205408Srdivacky * code is first argument, 198205408Srdivacky * followed by actual args. 199205408Srdivacky */ 200205408Srdivacky code = *params++; 201205408Srdivacky n -= 1; 202205408Srdivacky break; 203205408Srdivacky case SYS___syscall: 204205408Srdivacky params++; 205205408Srdivacky code = *params++; 206205408Srdivacky n -= 2; 207205408Srdivacky break; 208205408Srdivacky default: 209205408Srdivacky break; 210205408Srdivacky } 211205408Srdivacky 212205408Srdivacky code &= (SYS_NSYSENT - 1); 213205408Srdivacky callp += code; 214205408Srdivacky argsize = callp->sy_argsize; 215205408Srdivacky 216205408Srdivacky if (argsize > n * sizeof(register_t)) { 217205408Srdivacky memcpy(args, params, n * sizeof(register_t)); 218205408Srdivacky error = copyin(MOREARGS(frame->fixreg[1]), 219205408Srdivacky args + n, 220205408Srdivacky argsize - n * sizeof(register_t)); 221205408Srdivacky if (error) 222205408Srdivacky goto syscall_bad; 223205408Srdivacky params = args; 224205408Srdivacky } 225205408Srdivacky 226205408Srdivacky if ((error = trace_enter(p, code, params, rval)) != 0) 227205408Srdivacky goto syscall_bad; 228205408Srdivacky 229205408Srdivacky rval[0] = 0; 230205408Srdivacky rval[1] = 0; 231205408Srdivacky 232205408Srdivacky error = (*callp->sy_call)(p, params, rval); 233205408Srdivacky switch (error) { 234205408Srdivacky case 0: 235205408Srdivacky frame->fixreg[FIRSTARG] = rval[0]; 236205408Srdivacky frame->fixreg[FIRSTARG + 1] = rval[1]; 237205408Srdivacky frame->cr &= ~0x10000000; 238205408Srdivacky break; 239205408Srdivacky case ERESTART: 240205408Srdivacky /* 241205408Srdivacky * Set user's pc back to redo the system call. 242205408Srdivacky */ 243205408Srdivacky frame->srr0 -= 4; 244205408Srdivacky break; 245205408Srdivacky case EJUSTRETURN: 246205408Srdivacky /* nothing to do */ 247205408Srdivacky break; 248205408Srdivacky default: 249205408Srdivackysyscall_bad: 250205408Srdivacky if (p->p_emul->e_errno) 251205408Srdivacky error = p->p_emul->e_errno[error]; 252205408Srdivacky frame->fixreg[FIRSTARG] = error; 253205408Srdivacky frame->cr |= 0x10000000; 254205408Srdivacky break; 255205408Srdivacky } 256205408Srdivacky KERNEL_PROC_UNLOCK(p); 257205408Srdivacky trace_exit(p, code, params, rval, error); 258205408Srdivacky userret(p, frame); 259205408Srdivacky} 260205408Srdivacky 261205408Srdivackyvoid 262205408SrdivackyEMULNAME(syscall_intern)(struct proc *p) 263205408Srdivacky{ 264205408Srdivacky#ifdef KTRACE 265205408Srdivacky if (p->p_traceflag & (KTRFAC_SYSCALL | KTRFAC_SYSRET)) { 266205408Srdivacky p->p_md.md_syscall = EMULNAME(syscall_fancy); 267205408Srdivacky return; 268205408Srdivacky } 269205408Srdivacky#endif 270205408Srdivacky#ifdef SYSTRACE 271205408Srdivacky if (ISSET(p->p_flag, P_SYSTRACE)) { 272205408Srdivacky p->p_md.md_syscall = EMULNAME(syscall_fancy); 273205408Srdivacky return; 274205408Srdivacky } 275205408Srdivacky#endif 276205408Srdivacky p->p_md.md_syscall = EMULNAME(syscall_plain); 277205408Srdivacky} 278205408Srdivacky 279205408Srdivacky