Loading arch/sparc/Kconfig +1 −0 Original line number Diff line number Diff line Loading @@ -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 Loading arch/sparc/include/asm/processor_64.h +0 −2 Original line number Diff line number Diff line Loading @@ -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) Loading arch/sparc/include/asm/ptrace.h +3 −0 Original line number Diff line number Diff line Loading @@ -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; Loading arch/sparc/kernel/process_64.c +30 −77 Original line number Diff line number Diff line Loading @@ -538,51 +538,44 @@ 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 { 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; Loading @@ -594,7 +587,6 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, } if (t->utraps) t->utraps[0]++; } /* Set the return value for the child. */ t->kregs->u_regs[UREG_I0] = current->pid; Loading @@ -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]; Loading arch/sparc/kernel/syscalls.S +8 −3 Original line number Diff line number Diff line Loading @@ -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 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 Loading Loading
arch/sparc/Kconfig +1 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
arch/sparc/include/asm/processor_64.h +0 −2 Original line number Diff line number Diff line Loading @@ -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) Loading
arch/sparc/include/asm/ptrace.h +3 −0 Original line number Diff line number Diff line Loading @@ -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; Loading
arch/sparc/kernel/process_64.c +30 −77 Original line number Diff line number Diff line Loading @@ -538,51 +538,44 @@ 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 { 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; Loading @@ -594,7 +587,6 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, } if (t->utraps) t->utraps[0]++; } /* Set the return value for the child. */ t->kregs->u_regs[UREG_I0] = current->pid; Loading @@ -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]; Loading
arch/sparc/kernel/syscalls.S +8 −3 Original line number Diff line number Diff line Loading @@ -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 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 Loading