diff options
author | Chris Zankel <czankel@tensilica.com> | 2006-12-10 13:18:52 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.osdl.org> | 2006-12-10 20:55:39 +0300 |
commit | fc4fb2adf944d45a7f3d4d38df991c79ffdb6a43 (patch) | |
tree | bee95910d719861e2a189f7464b6bd6de6f22d1c /arch/xtensa | |
parent | 173d6681380aa1d60dfc35ed7178bd7811ba2784 (diff) | |
download | linux-fc4fb2adf944d45a7f3d4d38df991c79ffdb6a43.tar.xz |
[PATCH] xtensa: fix system call interface
This is a long outstanding patch to finally fix the syscall interface. The
constants used for the system calls are those we have provided in our libc
patches. This patch also fixes the shmbuf and stat structure, and fcntl
definitions.
Signed-off-by: Chris Zankel <chris@zankel.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/xtensa')
-rw-r--r-- | arch/xtensa/kernel/asm-offsets.c | 5 | ||||
-rw-r--r-- | arch/xtensa/kernel/entry.S | 228 | ||||
-rw-r--r-- | arch/xtensa/kernel/process.c | 71 | ||||
-rw-r--r-- | arch/xtensa/kernel/ptrace.c | 26 | ||||
-rw-r--r-- | arch/xtensa/kernel/signal.c | 12 | ||||
-rw-r--r-- | arch/xtensa/kernel/syscall.c | 95 | ||||
-rw-r--r-- | arch/xtensa/kernel/syscalls.c | 288 | ||||
-rw-r--r-- | arch/xtensa/kernel/syscalls.h | 247 |
8 files changed, 317 insertions, 655 deletions
diff --git a/arch/xtensa/kernel/asm-offsets.c b/arch/xtensa/kernel/asm-offsets.c index 7cd1d7f8f608..b256cfbef344 100644 --- a/arch/xtensa/kernel/asm-offsets.c +++ b/arch/xtensa/kernel/asm-offsets.c @@ -87,6 +87,11 @@ int main(void) DEFINE(MM_CONTEXT, offsetof (struct mm_struct, context)); BLANK(); DEFINE(PT_SINGLESTEP_BIT, PT_SINGLESTEP_BIT); + + /* constants */ + DEFINE(_CLONE_VM, CLONE_VM); + DEFINE(_CLONE_UNTRACED, CLONE_UNTRACED); + return 0; } diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S index c0b56b17927f..9e271ba009bf 100644 --- a/arch/xtensa/kernel/entry.S +++ b/arch/xtensa/kernel/entry.S @@ -1004,13 +1004,10 @@ ENTRY(fast_syscall_kernel) rsr a0, DEPC # get syscall-nr _beqz a0, fast_syscall_spill_registers - - addi a0, a0, -__NR_sysxtensa - _beqz a0, fast_syscall_sysxtensa + _beqi a0, __NR_xtensa, fast_syscall_xtensa j kernel_exception - ENTRY(fast_syscall_user) /* Skip syscall. */ @@ -1024,9 +1021,7 @@ ENTRY(fast_syscall_user) rsr a0, DEPC # get syscall-nr _beqz a0, fast_syscall_spill_registers - - addi a0, a0, -__NR_sysxtensa - _beqz a0, fast_syscall_sysxtensa + _beqi a0, __NR_xtensa, fast_syscall_xtensa j user_exception @@ -1047,18 +1042,19 @@ ENTRY(fast_syscall_unrecoverable) /* * sysxtensa syscall handler * - * int sysxtensa (XTENSA_ATOMIC_SET, ptr, val, unused); - * int sysxtensa (XTENSA_ATOMIC_ADD, ptr, val, unused); - * int sysxtensa (XTENSA_ATOMIC_EXG_ADD, ptr, val, unused); - * int sysxtensa (XTENSA_ATOMIC_CMP_SWP, ptr, oldval, newval); - * a2 a6 a3 a4 a5 + * int sysxtensa (SYS_XTENSA_ATOMIC_SET, ptr, val, unused); + * int sysxtensa (SYS_XTENSA_ATOMIC_ADD, ptr, val, unused); + * int sysxtensa (SYS_XTENSA_ATOMIC_EXG_ADD, ptr, val, unused); + * int sysxtensa (SYS_XTENSA_ATOMIC_CMP_SWP, ptr, oldval, newval); + * a2 a6 a3 a4 a5 * * Entry condition: * - * a0: trashed, original value saved on stack (PT_AREG0) + * a0: a2 (syscall-nr), original value saved on stack (PT_AREG0) * a1: a1 - * a2: new stack pointer, original in DEPC - * a3: dispatch table + * a2: new stack pointer, original in a0 and DEPC + * a3: dispatch table, original in excsave_1 + * a4..a15: unchanged * depc: a2, original value saved on stack (PT_DEPC) * excsave_1: a3 * @@ -1091,59 +1087,62 @@ ENTRY(fast_syscall_unrecoverable) #define CATCH \ 67: -ENTRY(fast_syscall_sysxtensa) - - _beqz a6, 1f - _blti a6, SYSXTENSA_COUNT, 2f +ENTRY(fast_syscall_xtensa) -1: j user_exception - -2: xsr a3, EXCSAVE_1 # restore a3, excsave1 - s32i a7, a2, PT_AREG7 + xsr a3, EXCSAVE_1 # restore a3, excsave1 + s32i a7, a2, PT_AREG7 # we need an additional register movi a7, 4 # sizeof(unsigned int) - access_ok a0, a3, a7, a2, .Leac + access_ok a3, a7, a0, a2, .Leac # a0: scratch reg, a2: sp - _beqi a6, SYSXTENSA_ATOMIC_SET, .Lset - _beqi a6, SYSXTENSA_ATOMIC_EXG_ADD, .Lexg - _beqi a6, SYSXTENSA_ATOMIC_ADD, .Ladd + addi a6, a6, -1 # assuming SYS_XTENSA_ATOMIC_SET = 1 + _bgeui a6, SYS_XTENSA_COUNT - 1, .Lill + _bnei a6, SYS_XTENSA_ATOMIC_CMP_SWP - 1, .Lnswp - /* Fall through for SYSXTENSA_ATOMIC_CMP_SWP */ + /* Fall through for ATOMIC_CMP_SWP. */ .Lswp: /* Atomic compare and swap */ -TRY l32i a7, a3, 0 # read old value - bne a7, a4, 1f # same as old value? jump - s32i a5, a3, 0 # different, modify value - movi a7, 1 # and return 1 - j .Lret - -1: movi a7, 0 # same values: return 0 - j .Lret - -.Ladd: /* Atomic add */ -.Lexg: /* Atomic (exchange) add */ +TRY l32i a0, a3, 0 # read old value + bne a0, a4, 1f # same as old value? jump +TRY s32i a5, a3, 0 # different, modify value + l32i a7, a2, PT_AREG7 # restore a7 + l32i a0, a2, PT_AREG0 # restore a0 + movi a2, 1 # and return 1 + addi a6, a6, 1 # restore a6 (really necessary?) + rfe -TRY l32i a7, a3, 0 - add a4, a4, a7 - s32i a4, a3, 0 - j .Lret +1: l32i a7, a2, PT_AREG7 # restore a7 + l32i a0, a2, PT_AREG0 # restore a0 + movi a2, 0 # return 0 (note that we cannot set + addi a6, a6, 1 # restore a6 (really necessary?) + rfe -.Lset: /* Atomic set */ +.Lnswp: /* Atomic set, add, and exg_add. */ -TRY l32i a7, a3, 0 # read old value as return value - s32i a4, a3, 0 # write new value +TRY l32i a7, a3, 0 # orig + add a0, a4, a7 # + arg + moveqz a0, a4, a6 # set +TRY s32i a0, a3, 0 # write new value -.Lret: mov a0, a2 + mov a0, a2 mov a2, a7 - l32i a7, a0, PT_AREG7 - l32i a3, a0, PT_AREG3 - l32i a0, a0, PT_AREG0 + l32i a7, a0, PT_AREG7 # restore a7 + l32i a0, a0, PT_AREG0 # restore a0 + addi a6, a6, 1 # restore a6 (really necessary?) rfe CATCH -.Leac: movi a7, -EFAULT - j .Lret +.Leac: l32i a7, a2, PT_AREG7 # restore a7 + l32i a0, a2, PT_AREG0 # restore a0 + movi a2, -EFAULT + rfe + +.Lill: l32i a7, a2, PT_AREG0 # restore a7 + l32i a0, a2, PT_AREG0 # restore a0 + movi a2, -EINVAL + rfe + @@ -1907,6 +1906,103 @@ ENTRY(fast_coprocessor) #endif /* XCHAL_EXTRA_SA_SIZE */ /* + * System Calls. + * + * void system_call (struct pt_regs* regs, int exccause) + * a2 a3 + */ + +ENTRY(system_call) + entry a1, 32 + + /* regs->syscall = regs->areg[2] */ + + l32i a3, a2, PT_AREG2 + mov a6, a2 + movi a4, do_syscall_trace_enter + s32i a3, a2, PT_SYSCALL + callx4 a4 + + /* syscall = sys_call_table[syscall_nr] */ + + movi a4, sys_call_table; + movi a5, __NR_syscall_count + movi a6, -ENOSYS + bgeu a3, a5, 1f + + addx4 a4, a3, a4 + l32i a4, a4, 0 + movi a5, sys_ni_syscall; + beq a4, a5, 1f + + /* Load args: arg0 - arg5 are passed via regs. */ + + l32i a6, a2, PT_AREG6 + l32i a7, a2, PT_AREG3 + l32i a8, a2, PT_AREG4 + l32i a9, a2, PT_AREG5 + l32i a10, a2, PT_AREG8 + l32i a11, a2, PT_AREG9 + + /* Pass one additional argument to the syscall: pt_regs (on stack) */ + s32i a2, a1, 0 + + callx4 a4 + +1: /* regs->areg[2] = return_value */ + + s32i a6, a2, PT_AREG2 + movi a4, do_syscall_trace_leave + mov a6, a2 + callx4 a4 + retw + + +/* + * Create a kernel thread + * + * int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) + * a2 a2 a3 a4 + */ + +ENTRY(kernel_thread) + entry a1, 16 + + mov a5, a2 # preserve fn over syscall + mov a7, a3 # preserve args over syscall + + movi a3, _CLONE_VM | _CLONE_UNTRACED + movi a2, __NR_clone + or a6, a4, a3 # arg0: flags + mov a3, a1 # arg1: sp + syscall + + beq a3, a1, 1f # branch if parent + mov a6, a7 # args + callx4 a5 # fn(args) + + movi a2, __NR_exit + syscall # return value of fn(args) still in a6 + +1: retw + +/* + * Do a system call from kernel instead of calling sys_execve, so we end up + * with proper pt_regs. + * + * int kernel_execve(const char *fname, char *const argv[], charg *const envp[]) + * a2 a2 a3 a4 + */ + +ENTRY(kernel_execve) + entry a1, 16 + mov a6, a2 # arg0 is in a6 + movi a2, __NR_execve + syscall + + retw + +/* * Task switch. * * struct task* _switch_to (struct task* prev, struct task* next) @@ -1964,33 +2060,9 @@ ENTRY(ret_from_fork) movi a4, schedule_tail callx4 a4 - movi a4, do_syscall_trace + movi a4, do_syscall_trace_leave + mov a6, a1 callx4 a4 j common_exception_return - - -/* - * Table of syscalls - */ - -.data -.align 4 -.global sys_call_table -sys_call_table: - -#define SYSCALL(call, narg) .word call -#include "syscalls.h" - -/* - * Number of arguments of each syscall - */ - -.global sys_narg_table -sys_narg_table: - -#undef SYSCALL -#define SYSCALL(call, narg) .byte narg -#include "syscalls.h" - diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c index 3785f3481d71..795bd5ac6f4c 100644 --- a/arch/xtensa/kernel/process.c +++ b/arch/xtensa/kernel/process.c @@ -161,36 +161,6 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, /* - * Create a kernel thread - */ - -int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) -{ - long retval; - __asm__ __volatile__ - ("mov a5, %4\n\t" /* preserve fn in a5 */ - "mov a6, %3\n\t" /* preserve and setup arg in a6 */ - "movi a2, %1\n\t" /* load __NR_clone for syscall*/ - "mov a3, sp\n\t" /* sp check and sys_clone */ - "mov a4, %5\n\t" /* load flags for syscall */ - "syscall\n\t" - "beq a3, sp, 1f\n\t" /* branch if parent */ - "callx4 a5\n\t" /* call fn */ - "movi a2, %2\n\t" /* load __NR_exit for syscall */ - "mov a3, a6\n\t" /* load fn return value */ - "syscall\n" - "1:\n\t" - "mov %0, a2\n\t" /* parent returns zero */ - :"=r" (retval) - :"i" (__NR_clone), "i" (__NR_exit), - "r" (arg), "r" (fn), - "r" (flags | CLONE_VM) - : "a2", "a3", "a4", "a5", "a6" ); - return retval; -} - - -/* * These bracket the sleeping functions.. */ @@ -452,3 +422,44 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *r) { return dump_task_fpu(regs, current, r); } + +asmlinkage +long xtensa_clone(unsigned long clone_flags, unsigned long newsp, + void __user *parent_tid, void *child_tls, + void __user *child_tid, long a5, + struct pt_regs *regs) +{ + if (!newsp) + newsp = regs->areg[1]; + return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid); +} + +/* + * * xtensa_execve() executes a new program. + * */ + +asmlinkage +long xtensa_execve(char __user *name, char __user * __user *argv, + char __user * __user *envp, + long a3, long a4, long a5, + struct pt_regs *regs) +{ + long error; + char * filename; + + filename = getname(name); + error = PTR_ERR(filename); + if (IS_ERR(filename)) + goto out; + // FIXME: release coprocessor?? + error = do_execve(filename, argv, envp, regs); + if (error == 0) { + task_lock(current); + current->ptrace &= ~PT_DTRACE; + task_unlock(current); + } + putname(filename); +out: + return error; +} + diff --git a/arch/xtensa/kernel/ptrace.c b/arch/xtensa/kernel/ptrace.c index 604c3c3c6759..8b6d3d0623b6 100644 --- a/arch/xtensa/kernel/ptrace.c +++ b/arch/xtensa/kernel/ptrace.c @@ -332,12 +332,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) void do_syscall_trace(void) { - if (!test_thread_flag(TIF_SYSCALL_TRACE)) - return; - - if (!(current->ptrace & PT_PTRACED)) - return; - /* * The 0x80 provides a way for the tracing parent to distinguish * between a syscall stop and SIGTRAP delivery @@ -354,3 +348,23 @@ void do_syscall_trace(void) current->exit_code = 0; } } + +void do_syscall_trace_enter(struct pt_regs *regs) +{ + if (test_thread_flag(TIF_SYSCALL_TRACE) + && (current->ptrace & PT_PTRACED)) + do_syscall_trace(); + +#if 0 + if (unlikely(current->audit_context)) + audit_syscall_entry(current, AUDIT_ARCH_XTENSA..); +#endif +} + +void do_syscall_trace_leave(struct pt_regs *regs) +{ + if ((test_thread_flag(TIF_SYSCALL_TRACE)) + && (current->ptrace & PT_PTRACED)) + do_syscall_trace(); +} + diff --git a/arch/xtensa/kernel/signal.c b/arch/xtensa/kernel/signal.c index 6af7f4145990..c6d9880a4cdb 100644 --- a/arch/xtensa/kernel/signal.c +++ b/arch/xtensa/kernel/signal.c @@ -46,7 +46,7 @@ extern struct task_struct *coproc_owners[]; * Atomically swap in the new signal mask, and wait for a signal. */ -int sys_sigsuspend(struct pt_regs *regs) +int xtensa_sigsuspend(struct pt_regs *regs) { old_sigset_t mask = (old_sigset_t) regs->areg[3]; sigset_t saveset; @@ -68,7 +68,7 @@ int sys_sigsuspend(struct pt_regs *regs) } asmlinkage int -sys_rt_sigsuspend(struct pt_regs *regs) +xtensa_rt_sigsuspend(struct pt_regs *regs) { sigset_t *unewset = (sigset_t *) regs->areg[4]; size_t sigsetsize = (size_t) regs->areg[3]; @@ -96,7 +96,7 @@ sys_rt_sigsuspend(struct pt_regs *regs) } asmlinkage int -sys_sigaction(int sig, const struct old_sigaction *act, +xtensa_sigaction(int sig, const struct old_sigaction *act, struct old_sigaction *oact) { struct k_sigaction new_ka, old_ka; @@ -128,7 +128,7 @@ sys_sigaction(int sig, const struct old_sigaction *act, } asmlinkage int -sys_sigaltstack(struct pt_regs *regs) +xtensa_sigaltstack(struct pt_regs *regs) { const stack_t *uss = (stack_t *) regs->areg[4]; stack_t *uoss = (stack_t *) regs->areg[3]; @@ -350,7 +350,7 @@ setup_sigcontext(struct sigcontext *sc, struct _cpstate *cpstate, return err; } -asmlinkage int sys_sigreturn(struct pt_regs *regs) +asmlinkage int xtensa_sigreturn(struct pt_regs *regs) { struct sigframe *frame = (struct sigframe *)regs->areg[1]; sigset_t set; @@ -382,7 +382,7 @@ badframe: return 0; } -asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) +asmlinkage int xtensa_rt_sigreturn(struct pt_regs *regs) { struct rt_sigframe *frame = (struct rt_sigframe *)regs->areg[1]; sigset_t set; diff --git a/arch/xtensa/kernel/syscall.c b/arch/xtensa/kernel/syscall.c new file mode 100644 index 000000000000..418268f49766 --- /dev/null +++ b/arch/xtensa/kernel/syscall.c @@ -0,0 +1,95 @@ +/* + * arch/xtensa/kernel/syscall.c + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001 - 2005 Tensilica Inc. + * Copyright (C) 2000 Silicon Graphics, Inc. + * Copyright (C) 1995 - 2000 by Ralf Baechle + * + * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com> + * Marc Gauthier <marc@tensilica.com, marc@alumni.uwaterloo.ca> + * Chris Zankel <chris@zankel.net> + * Kevin Chea + * + */ +#include <asm/uaccess.h> +#include <asm/syscalls.h> +#include <asm/unistd.h> +#include <linux/linkage.h> +#include <linux/stringify.h> +#include <linux/errno.h> +#include <linux/syscalls.h> +#include <linux/file.h> +#include <linux/fs.h> +#include <linux/mman.h> +#include <linux/shm.h> + +typedef void (*syscall_t)(void); + +syscall_t sys_call_table[__NR_syscall_count] /* FIXME __cacheline_aligned */= { + [0 ... __NR_syscall_count - 1] = (syscall_t)&sys_ni_syscall, + +#undef __SYSCALL +#define __SYSCALL(nr,symbol,nargs) [ nr ] = (syscall_t)symbol, +#undef _XTENSA_UNISTD_H +#undef __KERNEL_SYSCALLS__ +#include <asm/unistd.h> +}; + +/* + * xtensa_pipe() is the normal C calling standard for creating a pipe. It's not + * the way unix traditional does this, though. + */ + +asmlinkage long xtensa_pipe(int __user *userfds) +{ + int fd[2]; + int error; + + error = do_pipe(fd); + if (!error) { + if (copy_to_user(userfds, fd, 2 * sizeof(int))) + error = -EFAULT; + } + return error; +} + + +asmlinkage long xtensa_mmap2(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long pgoff) +{ + int error = -EBADF; + struct file * file = NULL; + + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + if (!(flags & MAP_ANONYMOUS)) { + file = fget(fd); + if (!file) + goto out; + } + + down_write(¤t->mm->mmap_sem); + error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); + up_write(¤t->mm->mmap_sem); + + if (file) + fput(file); +out: + return error; +} + +asmlinkage long xtensa_shmat(int shmid, char __user *shmaddr, int shmflg) +{ + unsigned long ret; + long err; + + err = do_shmat(shmid, shmaddr, shmflg, &ret); + if (err) + return err; + return (long)ret; +} + diff --git a/arch/xtensa/kernel/syscalls.c b/arch/xtensa/kernel/syscalls.c deleted file mode 100644 index f9a5a752ca69..000000000000 --- a/arch/xtensa/kernel/syscalls.c +++ /dev/null @@ -1,288 +0,0 @@ -/* - * arch/xtensa/kernel/syscalls.c - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2001 - 2005 Tensilica Inc. - * Copyright (C) 2000 Silicon Graphics, Inc. - * Copyright (C) 1995 - 2000 by Ralf Baechle - * - * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com> - * Marc Gauthier <marc@tensilica.com, marc@alumni.uwaterloo.ca> - * Chris Zankel <chris@zankel.net> - * Kevin Chea - * - */ - -#define DEBUG 0 - -#include <linux/linkage.h> -#include <linux/mm.h> -#include <linux/smp.h> -#include <linux/smp_lock.h> -#include <linux/mman.h> -#include <linux/sched.h> -#include <linux/file.h> -#include <linux/slab.h> -#include <linux/utsname.h> -#include <linux/unistd.h> -#include <linux/stringify.h> -#include <linux/syscalls.h> -#include <linux/sem.h> -#include <linux/msg.h> -#include <linux/shm.h> -#include <linux/errno.h> -#include <asm/ptrace.h> -#include <asm/signal.h> -#include <asm/uaccess.h> -#include <asm/hardirq.h> -#include <asm/mman.h> -#include <asm/shmparam.h> -#include <asm/page.h> - -extern void do_syscall_trace(void); -typedef int (*syscall_t)(void *a0,...); -extern syscall_t sys_call_table[]; -extern unsigned char sys_narg_table[]; - -/* - * sys_pipe() is the normal C calling standard for creating a pipe. It's not - * the way unix traditional does this, though. - */ - -int sys_pipe(int __user *userfds) -{ - int fd[2]; - int error; - - error = do_pipe(fd); - if (!error) { - if (copy_to_user(userfds, fd, 2 * sizeof(int))) - error = -EFAULT; - } - return error; -} - -/* - * Common code for old and new mmaps. - */ -long sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, - unsigned long flags, unsigned long fd, unsigned long pgoff) -{ - int error = -EBADF; - struct file * file = NULL; - - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - if (!(flags & MAP_ANONYMOUS)) { - file = fget(fd); - if (!file) - goto out; - } - - down_write(¤t->mm->mmap_sem); - error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); - up_write(¤t->mm->mmap_sem); - - if (file) - fput(file); -out: - return error; -} - -int sys_clone(struct pt_regs *regs) -{ - unsigned long clone_flags; - unsigned long newsp; - int __user *parent_tidptr, *child_tidptr; - clone_flags = regs->areg[4]; - newsp = regs->areg[3]; - parent_tidptr = (int __user *)regs->areg[5]; - child_tidptr = (int __user *)regs->areg[6]; - if (!newsp) - newsp = regs->areg[1]; - return do_fork(clone_flags,newsp,regs,0,parent_tidptr,child_tidptr); -} - -/* - * sys_execve() executes a new program. - */ - -int sys_execve(struct pt_regs *regs) -{ - int error; - char * filename; - - filename = getname((char *) (long)regs->areg[5]); - error = PTR_ERR(filename); - if (IS_ERR(filename)) - goto out; - error = do_execve(filename, (char **) (long)regs->areg[3], - (char **) (long)regs->areg[4], regs); - putname(filename); - -out: - return error; -} - -int sys_uname(struct old_utsname * name) -{ - if (name && !copy_to_user(name, utsname(), sizeof (*name))) - return 0; - return -EFAULT; -} - -/* - * Build the string table for the builtin "poor man's strace". - */ - -#if DEBUG -#define SYSCALL(fun, narg) #fun, -static char *sfnames[] = { -#include "syscalls.h" -}; -#undef SYS -#endif - -void system_call (struct pt_regs *regs) -{ - syscall_t syscall; - unsigned long parm0, parm1, parm2, parm3, parm4, parm5; - int nargs, res; - unsigned int syscallnr; - int ps; - -#if DEBUG - int i; - unsigned long parms[6]; - char *sysname; -#endif - - regs->syscall = regs->areg[2]; - - do_syscall_trace(); - - /* Have to load after syscall_trace because strace - * sometimes changes regs->syscall. - */ - syscallnr = regs->syscall; - - parm0 = parm1 = parm2 = parm3 = parm4 = parm5 = 0; - - /* Restore interrupt level to syscall invoker's. - * If this were in assembly, we wouldn't disable - * interrupts in the first place: - */ - local_save_flags (ps); - local_irq_restore((ps & ~PS_INTLEVEL_MASK) | - (regs->ps & PS_INTLEVEL_MASK) ); - - if (syscallnr > __NR_Linux_syscalls) { - regs->areg[2] = -ENOSYS; - return; - } - - syscall = sys_call_table[syscallnr]; - nargs = sys_narg_table[syscallnr]; - - if (syscall == NULL) { - regs->areg[2] = -ENOSYS; - return; - } - - /* There shouldn't be more than six arguments in the table! */ - - if (nargs > 6) - panic("Internal error - too many syscall arguments (%d)!\n", - nargs); - - /* Linux takes system-call arguments in registers. The ABI - * and Xtensa software conventions require the system-call - * number in a2. If an argument exists in a2, we move it to - * the next available register. Note that for improved - * efficiency, we do NOT shift all parameters down one - * register to maintain the original order. - * - * At best case (zero arguments), we just write the syscall - * number to a2. At worst case (1 to 6 arguments), we move - * the argument in a2 to the next available register, then - * write the syscall number to a2. - * - * For clarity, the following truth table enumerates all - * possibilities. - * - * arguments syscall number arg0, arg1, arg2, arg3, arg4, arg5 - * --------- -------------- ---------------------------------- - * 0 a2 - * 1 a2 a3 - * 2 a2 a4, a3 - * 3 a2 a5, a3, a4 - * 4 a2 a6, a3, a4, a5 - * 5 a2 a7, a3, a4, a5, a6 - * 6 a2 a8, a3, a4, a5, a6, a7 - */ - if (nargs) { - parm0 = regs->areg[nargs+2]; - parm1 = regs->areg[3]; - parm2 = regs->areg[4]; - parm3 = regs->areg[5]; - parm4 = regs->areg[6]; - parm5 = regs->areg[7]; - } else /* nargs == 0 */ - parm0 = (unsigned long) regs; - -#if DEBUG - parms[0] = parm0; - parms[1] = parm1; - parms[2] = parm2; - parms[3] = parm3; - parms[4] = parm4; - parms[5] = parm5; - - sysname = sfnames[syscallnr]; - if (strncmp(sysname, "sys_", 4) == 0) - sysname = sysname + 4; - - printk("\017SYSCALL:I:%x:%d:%s %s(", regs->pc, current->pid, - current->comm, sysname); - for (i = 0; i < nargs; i++) - printk((i>0) ? ", %#lx" : "%#lx", parms[i]); - printk(")\n"); -#endif - - res = syscall((void *)parm0, parm1, parm2, parm3, parm4, parm5); - -#if DEBUG - printk("\017SYSCALL:O:%d:%s %s(",current->pid, current->comm, sysname); - for (i = 0; i < nargs; i++) - printk((i>0) ? ", %#lx" : "%#lx", parms[i]); - if (res < 4096) - printk(") = %d\n", res); - else - printk(") = %#x\n", res); -#endif /* DEBUG */ - - regs->areg[2] = res; - do_syscall_trace(); -} - -/* - * Do a system call from kernel instead of calling sys_execve so we - * end up with proper pt_regs. - */ -int kernel_execve(const char *filename, char *const argv[], char *const envp[]) -{ - long __res; - asm volatile ( - " mov a5, %2 \n" - " mov a4, %4 \n" - " mov a3, %3 \n" - " movi a2, %1 \n" - " syscall \n" - " mov %0, a2 \n" - : "=a" (__res) - : "i" (__NR_execve), "a" (filename), "a" (argv), "a" (envp) - : "a2", "a3", "a4", "a5"); - return __res; -} diff --git a/arch/xtensa/kernel/syscalls.h b/arch/xtensa/kernel/syscalls.h deleted file mode 100644 index 216c10a31501..000000000000 --- a/arch/xtensa/kernel/syscalls.h +++ /dev/null @@ -1,247 +0,0 @@ -/* - * arch/xtensa/kernel/syscalls.h - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1995, 1996, 1997, 1998 by Ralf Baechle - * Copyright (C) 2001 - 2005 Tensilica Inc. - * - * Changes by Joe Taylor <joe@tensilica.com> - */ - -/* - * This file is being included twice - once to build a list of all - * syscalls and once to build a table of how many arguments each syscall - * accepts. Syscalls that receive a pointer to the saved registers are - * marked as having zero arguments. - * - * The binary compatibility calls are in a separate list. - * - * Entry '0' used to be system_call. It's removed to disable indirect - * system calls for now so user tasks can't recurse. See mips' - * sys_syscall for a comparable example. - */ - -SYSCALL(0, 0) /* 00 */ -SYSCALL(sys_exit, 1) -SYSCALL(sys_ni_syscall, 0) -SYSCALL(sys_read, 3) -SYSCALL(sys_write, 3) -SYSCALL(sys_open, 3) /* 05 */ -SYSCALL(sys_close, 1) -SYSCALL(sys_ni_syscall, 3) -SYSCALL(sys_creat, 2) -SYSCALL(sys_link, 2) -SYSCALL(sys_unlink, 1) /* 10 */ -SYSCALL(sys_execve, 0) -SYSCALL(sys_chdir, 1) -SYSCALL(sys_ni_syscall, 1) -SYSCALL(sys_mknod, 3) -SYSCALL(sys_chmod, 2) /* 15 */ -SYSCALL(sys_lchown, 3) -SYSCALL(sys_ni_syscall, 0) -SYSCALL(sys_newstat, 2) -SYSCALL(sys_lseek, 3) -SYSCALL(sys_getpid, 0) /* 20 */ -SYSCALL(sys_mount, 5) -SYSCALL(sys_ni_syscall, 1) -SYSCALL(sys_setuid, 1) -SYSCALL(sys_getuid, 0) -SYSCALL(sys_ni_syscall, 1) /* 25 */ -SYSCALL(sys_ptrace, 4) -SYSCALL(sys_ni_syscall, 1) -SYSCALL(sys_newfstat, 2) -SYSCALL(sys_ni_syscall, 0) -SYSCALL(sys_utime, 2) /* 30 */ -SYSCALL(sys_ni_syscall, 0) -SYSCALL(sys_ni_syscall, 0) -SYSCALL(sys_access, 2) -SYSCALL(sys_ni_syscall, 1) -SYSCALL(sys_ni_syscall, 0) /* 35 */ -SYSCALL(sys_sync, 0) -SYSCALL(sys_kill, 2) -SYSCALL(sys_rename, 2) -SYSCALL(sys_mkdir, 2) -SYSCALL(sys_rmdir, 1) /* 40 */ -SYSCALL(sys_dup, 1) -SYSCALL(sys_pipe, 1) -SYSCALL(sys_times, 1) -SYSCALL(sys_ni_syscall, 0) -SYSCALL(sys_brk, 1) /* 45 */ -SYSCALL(sys_setgid, 1) -SYSCALL(sys_getgid, 0) -SYSCALL(sys_ni_syscall, 0) -SYSCALL(sys_geteuid, 0) -SYSCALL(sys_getegid, 0) /* 50 */ -SYSCALL(sys_acct, 1) -SYSCALL(sys_umount, 2) -SYSCALL(sys_ni_syscall, 0) -SYSCALL(sys_ioctl, 3) -SYSCALL(sys_fcntl, 3) /* 55 */ -SYSCALL(sys_ni_syscall, 2) -SYSCALL(sys_setpgid, 2) -SYSCALL(sys_ni_syscall, 0) -SYSCALL(sys_ni_syscall, 0) -SYSCALL(sys_umask, 1) /* 60 */ -SYSCALL(sys_chroot, 1) -SYSCALL(sys_ustat, 2) -SYSCALL(sys_dup2, 2) -SYSCALL(sys_getppid, 0) -SYSCALL(sys_ni_syscall, 0) /* 65 */ -SYSCALL(sys_setsid, 0) -SYSCALL(sys_sigaction, 3) -SYSCALL(sys_ni_syscall, 0) -SYSCALL(sys_ni_syscall, 1) -SYSCALL(sys_setreuid, 2) /* 70 */ -SYSCALL(sys_setregid, 2) -SYSCALL(sys_sigsuspend, 0) -SYSCALL(sys_ni_syscall, 1) -SYSCALL(sys_sethostname, 2) -SYSCALL(sys_setrlimit, 2) /* 75 */ -SYSCALL(sys_getrlimit, 2) -SYSCALL(sys_getrusage, 2) -SYSCALL(sys_gettimeofday, 2) -SYSCALL(sys_settimeofday, 2) -SYSCALL(sys_getgroups, 2) /* 80 */ -SYSCALL(sys_setgroups, 2) -SYSCALL(sys_ni_syscall, 0) -SYSCALL(sys_symlink, 2) -SYSCALL(sys_newlstat, 2) -SYSCALL(sys_readlink, 3) /* 85 */ -SYSCALL(sys_uselib, 1) -SYSCALL(sys_swapon, 2) -SYSCALL(sys_reboot, 3) -SYSCALL(sys_ni_syscall, 3) -SYSCALL(sys_ni_syscall, 6) /* 90 */ -SYSCALL(sys_munmap, 2) -SYSCALL(sys_truncate, 2) -SYSCALL(sys_ftruncate, 2) -SYSCALL(sys_fchmod, 2) -SYSCALL(sys_fchown, 3) /* 95 */ -SYSCALL(sys_getpriority, 2) -SYSCALL(sys_setpriority, 3) -SYSCALL(sys_ni_syscall, 0) -SYSCALL(sys_statfs, 2) -SYSCALL(sys_fstatfs, 2) /* 100 */ -SYSCALL(sys_ni_syscall, 3) -SYSCALL(sys_ni_syscall, 2) -SYSCALL(sys_syslog, 3) -SYSCALL(sys_setitimer, 3) -SYSCALL(sys_getitimer, 2) /* 105 */ -SYSCALL(sys_newstat, 2) -SYSCALL(sys_newlstat, 2) -SYSCALL(sys_newfstat, 2) -SYSCALL(sys_uname, 1) -SYSCALL(sys_ni_syscall, 0) /* 110 */ -SYSCALL(sys_vhangup, 0) -SYSCALL(sys_ni_syscall, 0) -SYSCALL(sys_ni_syscall, 0) -SYSCALL(sys_wait4, 4) -SYSCALL(sys_swapoff, 1) /* 115 */ -SYSCALL(sys_sysinfo, 1) -SYSCALL(sys_ni_syscall, 0) -SYSCALL(sys_fsync, 1) -SYSCALL(sys_sigreturn, 0) -SYSCALL(sys_clone, 0) /* 120 */ -SYSCALL(sys_setdomainname, 2) -SYSCALL(sys_newuname, 1) -SYSCALL(sys_ni_syscall, 0) -SYSCALL(sys_adjtimex, 1) -SYSCALL(sys_mprotect, 3) /* 125 */ -SYSCALL(sys_ni_syscall, 3) -SYSCALL(sys_ni_syscall, 2) -SYSCALL(sys_init_module, 2) -SYSCALL(sys_delete_module, 1) -SYSCALL(sys_ni_syscall, 1) /* 130 */ -SYSCALL(sys_quotactl, 0) -SYSCALL(sys_getpgid, 1) -SYSCALL(sys_fchdir, 1) -SYSCALL(sys_bdflush, 2) -SYSCALL(sys_sysfs, 3) /* 135 */ -SYSCALL(sys_personality, 1) -SYSCALL(sys_ni_syscall, 0) -SYSCALL(sys_setfsuid, 1) -SYSCALL(sys_setfsgid, 1) -SYSCALL(sys_llseek, 5) /* 140 */ -SYSCALL(sys_getdents, 3) -SYSCALL(sys_select, 5) -SYSCALL(sys_flock, 2) -SYSCALL(sys_msync, 3) -SYSCALL(sys_readv, 3) /* 145 */ -SYSCALL(sys_writev, 3) -SYSCALL(sys_ni_syscall, 3) -SYSCALL(sys_ni_syscall, 3) -SYSCALL(sys_ni_syscall, 4) /* handled in fast syscall handler. */ -SYSCALL(sys_ni_syscall, 0) /* 150 */ -SYSCALL(sys_getsid, 1) -SYSCALL(sys_fdatasync, 1) -SYSCALL(sys_sysctl, 1) -SYSCALL(sys_mlock, 2) -SYSCALL(sys_munlock, 2) /* 155 */ -SYSCALL(sys_mlockall, 1) -SYSCALL(sys_munlockall, 0) -SYSCALL(sys_sched_setparam,2) -SYSCALL(sys_sched_getparam,2) -SYSCALL(sys_sched_setscheduler,3) /* 160 */ -SYSCALL(sys_sched_getscheduler,1) -SYSCALL(sys_sched_yield,0) -SYSCALL(sys_sched_get_priority_max,1) -SYSCALL(sys_sched_get_priority_min,1) -SYSCALL(sys_sched_rr_get_interval,2) /* 165 */ -SYSCALL(sys_nanosleep,2) -SYSCALL(sys_mremap,4) -SYSCALL(sys_accept, 3) -SYSCALL(sys_bind, 3) -SYSCALL(sys_connect, 3) /* 170 */ -SYSCALL(sys_getpeername, 3) -SYSCALL(sys_getsockname, 3) -SYSCALL(sys_getsockopt, 5) -SYSCALL(sys_listen, 2) -SYSCALL(sys_recv, 4) /* 175 */ -SYSCALL(sys_recvfrom, 6) -SYSCALL(sys_recvmsg, 3) -SYSCALL(sys_send, 4) -SYSCALL(sys_sendmsg, 3) -SYSCALL(sys_sendto, 6) /* 180 */ -SYSCALL(sys_setsockopt, 5) -SYSCALL(sys_shutdown, 2) -SYSCALL(sys_socket, 3) -SYSCALL(sys_socketpair, 4) -SYSCALL(sys_setresuid, 3) /* 185 */ -SYSCALL(sys_getresuid, 3) -SYSCALL(sys_ni_syscall, 5) -SYSCALL(sys_poll, 3) -SYSCALL(sys_nfsservctl, 3) -SYSCALL(sys_setresgid, 3) /* 190 */ -SYSCALL(sys_getresgid, 3) -SYSCALL(sys_prctl, 5) -SYSCALL(sys_rt_sigreturn, 0) -SYSCALL(sys_rt_sigaction, 4) -SYSCALL(sys_rt_sigprocmask, 4) /* 195 */ -SYSCALL(sys_rt_sigpending, 2) -SYSCALL(sys_rt_sigtimedwait, 4) -SYSCALL(sys_rt_sigqueueinfo, 3) -SYSCALL(sys_rt_sigsuspend, 0) -SYSCALL(sys_pread64, 5) /* 200 */ -SYSCALL(sys_pwrite64, 5) -SYSCALL(sys_chown, 3) -SYSCALL(sys_getcwd, 2) -SYSCALL(sys_capget, 2) -SYSCALL(sys_capset, 2) /* 205 */ -SYSCALL(sys_sigaltstack, 0) -SYSCALL(sys_sendfile, 4) -SYSCALL(sys_ni_syscall, 0) -SYSCALL(sys_ni_syscall, 0) -SYSCALL(sys_mmap, 6) /* 210 */ -SYSCALL(sys_truncate64, 2) -SYSCALL(sys_ftruncate64, 2) -SYSCALL(sys_stat64, 2) -SYSCALL(sys_lstat64, 2) -SYSCALL(sys_fstat64, 2) /* 215 */ -SYSCALL(sys_pivot_root, 2) -SYSCALL(sys_mincore, 3) -SYSCALL(sys_madvise, 3) -SYSCALL(sys_getdents64, 3) -SYSCALL(sys_ni_syscall, 0) /* 220 */ |