From dff933da765fd4855393846fa55286d1ff2d024a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 26 Sep 2012 01:21:14 -0400 Subject: sparc64: clear syscall_noerror on the entry to syscall, not on the exit Move that sucker to just before TI_FPDEPTH and replace stb with sth in etrap_save(). Take current_ds to its old place, so that we don't push wsaved into TI_... flags. That allows to lose clearing syscall_noerror on return from syscall. Signed-off-by: Al Viro --- arch/sparc/kernel/syscalls.S | 1 - 1 file changed, 1 deletion(-) (limited to 'arch/sparc/kernel/syscalls.S') diff --git a/arch/sparc/kernel/syscalls.S b/arch/sparc/kernel/syscalls.S index 7f5f65d0b3fd..b0ac10306425 100644 --- a/arch/sparc/kernel/syscalls.S +++ b/arch/sparc/kernel/syscalls.S @@ -222,7 +222,6 @@ ret_sys_call: ldx [%sp + PTREGS_OFF + PT_V9_TNPC], %l1 ! pc = npc 2: - stb %g0, [%g6 + TI_SYS_NOERROR] /* System call success, clear Carry condition code. */ andn %g3, %g2, %g3 3: -- cgit v1.2.3 From 1918c7f548dc5abfb37ab74bb3d036d36c92ba5e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 5 Oct 2012 22:37:01 -0400 Subject: sparc64: switch to generic kernel_thread() Signed-off-by: Al Viro --- arch/sparc/Kconfig | 1 + arch/sparc/include/asm/processor_64.h | 2 - arch/sparc/include/asm/ptrace.h | 3 + arch/sparc/kernel/process_64.c | 107 ++++++++++------------------------ arch/sparc/kernel/syscalls.S | 11 +++- 5 files changed, 42 insertions(+), 82 deletions(-) (limited to 'arch/sparc/kernel/syscalls.S') diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index b6b442b0d793..ab8bd62b8dbe 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -74,6 +74,7 @@ config SPARC64 select ARCH_HAVE_NMI_SAFE_CMPXCHG select HAVE_C_RECORDMCOUNT select NO_BOOTMEM + select GENERIC_KERNEL_THREAD config ARCH_DEFCONFIG string diff --git a/arch/sparc/include/asm/processor_64.h b/arch/sparc/include/asm/processor_64.h index 4e5a483122a0..5d81ff6b6933 100644 --- a/arch/sparc/include/asm/processor_64.h +++ b/arch/sparc/include/asm/processor_64.h @@ -188,8 +188,6 @@ do { \ /* Free all resources held by a thread. */ #define release_thread(tsk) do { } while (0) -extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); - extern unsigned long get_wchan(struct task_struct *task); #define task_pt_regs(tsk) (task_thread_info(tsk)->kregs) diff --git a/arch/sparc/include/asm/ptrace.h b/arch/sparc/include/asm/ptrace.h index 5b6019e327e5..7a4075003e76 100644 --- a/arch/sparc/include/asm/ptrace.h +++ b/arch/sparc/include/asm/ptrace.h @@ -32,6 +32,9 @@ static inline bool pt_regs_clear_syscall(struct pt_regs *regs) #define arch_ptrace_stop(exit_code, info) \ synchronize_user_stack() +#define current_pt_regs() \ + ((struct pt_regs *)((unsigned long)current_thread_info() + THREAD_SIZE) - 1) + struct global_reg_snapshot { unsigned long tstate; unsigned long tpc; diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c index 4c864c796507..e37512319296 100644 --- a/arch/sparc/kernel/process_64.c +++ b/arch/sparc/kernel/process_64.c @@ -538,64 +538,56 @@ asmlinkage long sparc_do_fork(unsigned long clone_flags, * Child --> %o0 == parents pid, %o1 == 1 */ int copy_thread(unsigned long clone_flags, unsigned long sp, - unsigned long unused, + unsigned long arg, struct task_struct *p, struct pt_regs *regs) { struct thread_info *t = task_thread_info(p); struct sparc_stackf *parent_sf; unsigned long child_stack_sz; char *child_trap_frame; - int kernel_thread; - - kernel_thread = (regs->tstate & TSTATE_PRIV) ? 1 : 0; - parent_sf = ((struct sparc_stackf *) regs) - 1; /* Calculate offset to stack_frame & pt_regs */ - child_stack_sz = ((STACKFRAME_SZ + TRACEREG_SZ) + - (kernel_thread ? STACKFRAME_SZ : 0)); + child_stack_sz = (STACKFRAME_SZ + TRACEREG_SZ); child_trap_frame = (task_stack_page(p) + (THREAD_SIZE - child_stack_sz)); - memcpy(child_trap_frame, parent_sf, child_stack_sz); - __thread_flag_byte_ptr(t)[TI_FLAG_BYTE_CWP] = - (regs->tstate + 1) & TSTATE_CWP; t->new_child = 1; t->ksp = ((unsigned long) child_trap_frame) - STACK_BIAS; t->kregs = (struct pt_regs *) (child_trap_frame + sizeof(struct sparc_stackf)); t->fpsaved[0] = 0; - if (kernel_thread) { - struct sparc_stackf *child_sf = (struct sparc_stackf *) - (child_trap_frame + (STACKFRAME_SZ + TRACEREG_SZ)); - - /* Zero terminate the stack backtrace. */ - child_sf->fp = NULL; - t->kregs->u_regs[UREG_FP] = - ((unsigned long) child_sf) - STACK_BIAS; - + if (unlikely(p->flags & PF_KTHREAD)) { + memset(child_trap_frame, 0, child_stack_sz); + __thread_flag_byte_ptr(t)[TI_FLAG_BYTE_CWP] = + (current_pt_regs()->tstate + 1) & TSTATE_CWP; t->current_ds = ASI_P; - t->kregs->u_regs[UREG_G6] = (unsigned long) t; - t->kregs->u_regs[UREG_G4] = (unsigned long) t->task; - } else { - if (t->flags & _TIF_32BIT) { - sp &= 0x00000000ffffffffUL; - regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL; - } - t->kregs->u_regs[UREG_FP] = sp; - t->current_ds = ASI_AIUS; - if (sp != regs->u_regs[UREG_FP]) { - unsigned long csp; - - csp = clone_stackframe(sp, regs->u_regs[UREG_FP]); - if (!csp) - return -EFAULT; - t->kregs->u_regs[UREG_FP] = csp; - } - if (t->utraps) - t->utraps[0]++; + t->kregs->u_regs[UREG_G1] = sp; /* function */ + t->kregs->u_regs[UREG_G2] = arg; + return 0; } + parent_sf = ((struct sparc_stackf *) regs) - 1; + memcpy(child_trap_frame, parent_sf, child_stack_sz); + if (t->flags & _TIF_32BIT) { + sp &= 0x00000000ffffffffUL; + regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL; + } + t->kregs->u_regs[UREG_FP] = sp; + __thread_flag_byte_ptr(t)[TI_FLAG_BYTE_CWP] = + (regs->tstate + 1) & TSTATE_CWP; + t->current_ds = ASI_AIUS; + if (sp != regs->u_regs[UREG_FP]) { + unsigned long csp; + + csp = clone_stackframe(sp, regs->u_regs[UREG_FP]); + if (!csp) + return -EFAULT; + t->kregs->u_regs[UREG_FP] = csp; + } + if (t->utraps) + t->utraps[0]++; + /* Set the return value for the child. */ t->kregs->u_regs[UREG_I0] = current->pid; t->kregs->u_regs[UREG_I1] = 1; @@ -609,45 +601,6 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, return 0; } -/* - * This is the mechanism for creating a new kernel thread. - * - * NOTE! Only a kernel-only process(ie the swapper or direct descendants - * who haven't done an "execve()") should use this: it will work within - * a system call from a "real" process, but the process memory space will - * not be freed until both the parent and the child have exited. - */ -pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) -{ - long retval; - - /* If the parent runs before fn(arg) is called by the child, - * the input registers of this function can be clobbered. - * So we stash 'fn' and 'arg' into global registers which - * will not be modified by the parent. - */ - __asm__ __volatile__("mov %4, %%g2\n\t" /* Save FN into global */ - "mov %5, %%g3\n\t" /* Save ARG into global */ - "mov %1, %%g1\n\t" /* Clone syscall nr. */ - "mov %2, %%o0\n\t" /* Clone flags. */ - "mov 0, %%o1\n\t" /* usp arg == 0 */ - "t 0x6d\n\t" /* Linux/Sparc clone(). */ - "brz,a,pn %%o1, 1f\n\t" /* Parent, just return. */ - " mov %%o0, %0\n\t" - "jmpl %%g2, %%o7\n\t" /* Call the function. */ - " mov %%g3, %%o0\n\t" /* Set arg in delay. */ - "mov %3, %%g1\n\t" - "t 0x6d\n\t" /* Linux/Sparc exit(). */ - /* Notreached by child. */ - "1:" : - "=r" (retval) : - "i" (__NR_clone), "r" (flags | CLONE_VM | CLONE_UNTRACED), - "i" (__NR_exit), "r" (fn), "r" (arg) : - "g1", "g2", "g3", "o0", "o1", "memory", "cc"); - return retval; -} -EXPORT_SYMBOL(kernel_thread); - typedef struct { union { unsigned int pr_regs[32]; diff --git a/arch/sparc/kernel/syscalls.S b/arch/sparc/kernel/syscalls.S index b0ac10306425..624f34162c38 100644 --- a/arch/sparc/kernel/syscalls.S +++ b/arch/sparc/kernel/syscalls.S @@ -112,11 +112,16 @@ sys_clone: ret_from_syscall: /* Clear current_thread_info()->new_child. */ stb %g0, [%g6 + TI_NEW_CHILD] - ldx [%g6 + TI_FLAGS], %l0 call schedule_tail mov %g7, %o0 - ba,pt %xcc, ret_sys_call - ldx [%sp + PTREGS_OFF + PT_V9_I0], %o0 + ldx [%sp + PTREGS_OFF + PT_V9_I0], %o0 + brnz,a,pt %o0, ret_sys_call + ldx [%g6 + TI_FLAGS], %l0 + ldx [%sp + PTREGS_OFF + PT_V9_G1], %l0 + call %l0 + ldx [%sp + PTREGS_OFF + PT_V9_G2], %o0 + call do_exit ! will not return + mov 0,%o0 .globl sparc_exit .type sparc_exit,#function -- cgit v1.2.3 From 2f12af35a988082700373acdebe049dfebaf49b6 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 26 Sep 2012 19:28:00 -0400 Subject: sparc64: switch to generic kernel_execve() Signed-off-by: Al Viro --- arch/sparc/Kconfig | 1 + arch/sparc/kernel/sys_sparc_64.c | 22 ---------------------- arch/sparc/kernel/syscalls.S | 10 +++++----- 3 files changed, 6 insertions(+), 27 deletions(-) (limited to 'arch/sparc/kernel/syscalls.S') diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index ab8bd62b8dbe..e47eb324d77a 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -75,6 +75,7 @@ config SPARC64 select HAVE_C_RECORDMCOUNT select NO_BOOTMEM select GENERIC_KERNEL_THREAD + select GENERIC_KERNEL_EXECVE config ARCH_DEFCONFIG string diff --git a/arch/sparc/kernel/sys_sparc_64.c b/arch/sparc/kernel/sys_sparc_64.c index 11c6c9603e71..adfe60ece05f 100644 --- a/arch/sparc/kernel/sys_sparc_64.c +++ b/arch/sparc/kernel/sys_sparc_64.c @@ -729,25 +729,3 @@ SYSCALL_DEFINE5(rt_sigaction, int, sig, const struct sigaction __user *, act, return ret; } - -/* - * 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, - const char *const argv[], - const char *const envp[]) -{ - long __res; - register long __g1 __asm__ ("g1") = __NR_execve; - register long __o0 __asm__ ("o0") = (long)(filename); - register long __o1 __asm__ ("o1") = (long)(argv); - register long __o2 __asm__ ("o2") = (long)(envp); - asm volatile ("t 0x6d\n\t" - "sub %%g0, %%o0, %0\n\t" - "movcc %%xcc, %%o0, %0\n\t" - : "=r" (__res), "=&r" (__o0) - : "1" (__o0), "r" (__o1), "r" (__o2), "r" (__g1) - : "cc"); - return __res; -} diff --git a/arch/sparc/kernel/syscalls.S b/arch/sparc/kernel/syscalls.S index 624f34162c38..f72c12433869 100644 --- a/arch/sparc/kernel/syscalls.S +++ b/arch/sparc/kernel/syscalls.S @@ -115,13 +115,13 @@ ret_from_syscall: call schedule_tail mov %g7, %o0 ldx [%sp + PTREGS_OFF + PT_V9_I0], %o0 - brnz,a,pt %o0, ret_sys_call + brnz,pt %o0, ret_sys_call ldx [%g6 + TI_FLAGS], %l0 - ldx [%sp + PTREGS_OFF + PT_V9_G1], %l0 - call %l0 + ldx [%sp + PTREGS_OFF + PT_V9_G1], %l1 + call %l1 ldx [%sp + PTREGS_OFF + PT_V9_G2], %o0 - call do_exit ! will not return - mov 0,%o0 + ba,pt %xcc, ret_sys_call + mov 0, %o0 .globl sparc_exit .type sparc_exit,#function -- cgit v1.2.3 From eb48ffcf0e55e511ae87e9d99117d5e2b9e27153 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 26 Sep 2012 19:44:26 -0400 Subject: sparc64: convert to generic execve We still have wrappers, but nowhere near as scary as they used to be. I'm not sure how necessary that flushw is now, TBH... Signed-off-by: Al Viro --- arch/sparc/include/asm/syscalls.h | 2 ++ arch/sparc/include/asm/unistd.h | 1 + arch/sparc/kernel/process_64.c | 29 ----------------------------- arch/sparc/kernel/sys_sparc32.c | 29 ----------------------------- arch/sparc/kernel/syscalls.S | 20 ++++++++------------ arch/sparc/kernel/systbls_64.S | 2 +- 6 files changed, 12 insertions(+), 71 deletions(-) (limited to 'arch/sparc/kernel/syscalls.S') diff --git a/arch/sparc/include/asm/syscalls.h b/arch/sparc/include/asm/syscalls.h index 45a43f637a14..4b05df397740 100644 --- a/arch/sparc/include/asm/syscalls.h +++ b/arch/sparc/include/asm/syscalls.h @@ -8,6 +8,8 @@ extern asmlinkage long sparc_do_fork(unsigned long clone_flags, struct pt_regs *regs, unsigned long stack_size); +#ifndef __arch64__ extern asmlinkage int sparc_execve(struct pt_regs *regs); +#endif #endif /* _SPARC64_SYSCALLS_H */ diff --git a/arch/sparc/include/asm/unistd.h b/arch/sparc/include/asm/unistd.h index 0ecea6ed943e..32bd0aaeedfa 100644 --- a/arch/sparc/include/asm/unistd.h +++ b/arch/sparc/include/asm/unistd.h @@ -45,6 +45,7 @@ #define __ARCH_WANT_COMPAT_SYS_TIME #define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND #define __ARCH_WANT_COMPAT_SYS_SENDFILE +#define __ARCH_WANT_SYS_EXECVE #endif /* diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c index 55aa68da213b..6b36e879b2a0 100644 --- a/arch/sparc/kernel/process_64.c +++ b/arch/sparc/kernel/process_64.c @@ -667,35 +667,6 @@ int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs) } EXPORT_SYMBOL(dump_fpu); -/* - * sparc_execve() executes a new program after the asm stub has set - * things up for us. This should basically do what I want it to. - */ -asmlinkage int sparc_execve(struct pt_regs *regs) -{ - int error, base = 0; - struct filename *filename; - - /* User register window flush is done by entry.S */ - - /* Check for indirect call. */ - if (regs->u_regs[UREG_G1] == 0) - base = 1; - - filename = getname((char __user *)regs->u_regs[base + UREG_I0]); - error = PTR_ERR(filename); - if (IS_ERR(filename)) - goto out; - error = do_execve(filename->name, - (const char __user *const __user *) - regs->u_regs[base + UREG_I1], - (const char __user *const __user *) - regs->u_regs[base + UREG_I2], regs); - putname(filename); -out: - return error; -} - unsigned long get_wchan(struct task_struct *task) { unsigned long pc, fp, bias = 0; diff --git a/arch/sparc/kernel/sys_sparc32.c b/arch/sparc/kernel/sys_sparc32.c index 2f116ff46b11..03c7e929ec34 100644 --- a/arch/sparc/kernel/sys_sparc32.c +++ b/arch/sparc/kernel/sys_sparc32.c @@ -396,35 +396,6 @@ asmlinkage long compat_sys_rt_sigaction(int sig, return ret; } -/* - * sparc32_execve() executes a new program after the asm stub has set - * things up for us. This should basically do what I want it to. - */ -asmlinkage long sparc32_execve(struct pt_regs *regs) -{ - int error, base = 0; - struct filename *filename; - - /* User register window flush is done by entry.S */ - - /* Check for indirect call. */ - if ((u32)regs->u_regs[UREG_G1] == 0) - base = 1; - - filename = getname(compat_ptr(regs->u_regs[base + UREG_I0])); - error = PTR_ERR(filename); - if (IS_ERR(filename)) - goto out; - - error = compat_do_execve(filename->name, - compat_ptr(regs->u_regs[base + UREG_I1]), - compat_ptr(regs->u_regs[base + UREG_I2]), regs); - - putname(filename); -out: - return error; -} - #ifdef CONFIG_MODULES asmlinkage long sys32_init_module(void __user *umod, u32 len, diff --git a/arch/sparc/kernel/syscalls.S b/arch/sparc/kernel/syscalls.S index f72c12433869..2ef41e67f0be 100644 --- a/arch/sparc/kernel/syscalls.S +++ b/arch/sparc/kernel/syscalls.S @@ -1,23 +1,19 @@ /* SunOS's execv() call only specifies the argv argument, the * environment settings are the same as the calling processes. */ -sys_execve: - sethi %hi(sparc_execve), %g1 - ba,pt %xcc, execve_merge - or %g1, %lo(sparc_execve), %g1 +sys64_execve: + set sys_execve, %g1 + jmpl %g1, %g0 + flushw #ifdef CONFIG_COMPAT sunos_execv: - stx %g0, [%sp + PTREGS_OFF + PT_V9_I2] + mov %g0, %o2 sys32_execve: - sethi %hi(sparc32_execve), %g1 - or %g1, %lo(sparc32_execve), %g1 -#endif - -execve_merge: - flushw + set compat_sys_execve, %g1 jmpl %g1, %g0 - add %sp, PTREGS_OFF, %o0 + flushw +#endif .align 32 sys_sparc_pipe: diff --git a/arch/sparc/kernel/systbls_64.S b/arch/sparc/kernel/systbls_64.S index 3a58e0d66f51..acad343667d0 100644 --- a/arch/sparc/kernel/systbls_64.S +++ b/arch/sparc/kernel/systbls_64.S @@ -106,7 +106,7 @@ sys_call_table: /*40*/ .word sys_newlstat, sys_dup, sys_sparc_pipe, sys_times, sys_nis_syscall .word sys_umount, sys_setgid, sys_getgid, sys_signal, sys_geteuid /*50*/ .word sys_getegid, sys_acct, sys_memory_ordering, sys_nis_syscall, sys_ioctl - .word sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys_execve + .word sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys64_execve /*60*/ .word sys_umask, sys_chroot, sys_newfstat, sys_fstat64, sys_getpagesize .word sys_msync, sys_vfork, sys_pread64, sys_pwrite64, sys_nis_syscall /*70*/ .word sys_nis_syscall, sys_mmap, sys_nis_syscall, sys_64_munmap, sys_mprotect -- cgit v1.2.3