Loading arch/sparc/Kconfig +1 −1 Original line number Original line Diff line number Diff line Loading @@ -40,6 +40,7 @@ config SPARC select GENERIC_STRNCPY_FROM_USER select GENERIC_STRNCPY_FROM_USER select GENERIC_STRNLEN_USER select GENERIC_STRNLEN_USER select MODULES_USE_ELF_RELA select MODULES_USE_ELF_RELA select GENERIC_KERNEL_THREAD config SPARC32 config SPARC32 def_bool !64BIT def_bool !64BIT Loading Loading @@ -74,7 +75,6 @@ config SPARC64 select ARCH_HAVE_NMI_SAFE_CMPXCHG select ARCH_HAVE_NMI_SAFE_CMPXCHG select HAVE_C_RECORDMCOUNT select HAVE_C_RECORDMCOUNT select NO_BOOTMEM select NO_BOOTMEM select GENERIC_KERNEL_THREAD select GENERIC_KERNEL_EXECVE select GENERIC_KERNEL_EXECVE config ARCH_DEFCONFIG config ARCH_DEFCONFIG Loading arch/sparc/include/asm/processor_32.h +0 −1 Original line number Original line Diff line number Diff line Loading @@ -106,7 +106,6 @@ static inline void start_thread(struct pt_regs * regs, unsigned long pc, /* Free all resources held by a thread. */ /* Free all resources held by a thread. */ #define release_thread(tsk) do { } while(0) #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 *); extern unsigned long get_wchan(struct task_struct *); Loading arch/sparc/kernel/entry.S +10 −0 Original line number Original line Diff line number Diff line Loading @@ -983,6 +983,16 @@ ret_from_fork: b ret_sys_call b ret_sys_call ld [%sp + STACKFRAME_SZ + PT_I0], %o0 ld [%sp + STACKFRAME_SZ + PT_I0], %o0 .globl ret_from_kernel_thread ret_from_kernel_thread: call schedule_tail ld [%g3 + TI_TASK], %o0 ld [%sp + STACKFRAME_SZ + PT_G1], %l0 call %l0 ld [%sp + STACKFRAME_SZ + PT_G2], %o0 call do_exit /* won't return */ clr %o0 /* Linux native system calls enter here... */ /* Linux native system calls enter here... */ .align 4 .align 4 .globl linux_sparc_syscall .globl linux_sparc_syscall Loading arch/sparc/kernel/process_32.c +45 −79 Original line number Original line Diff line number Diff line Loading @@ -316,9 +316,10 @@ asmlinkage int sparc_do_fork(unsigned long clone_flags, * XXX See comment above sys_vfork in sparc64. todo. * XXX See comment above sys_vfork in sparc64. todo. */ */ extern void ret_from_fork(void); extern void ret_from_fork(void); extern void ret_from_kernel_thread(void); int copy_thread(unsigned long clone_flags, unsigned long sp, 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 task_struct *p, struct pt_regs *regs) { { struct thread_info *ti = task_thread_info(p); struct thread_info *ti = task_thread_info(p); Loading @@ -336,16 +337,13 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, } } /* /* * p->thread_info new_stack childregs * p->thread_info new_stack childregs stack bottom * ! ! ! {if(PSR_PS) } * ! ! ! ! * V V (stk.fr.) V (pt_regs) { (stk.fr.) } * V V (stk.fr.) V (pt_regs) V * +----- - - - - - ------+===========+============={+==========}+ * +----- - - - - - ------+===========+=============+ */ */ new_stack = task_stack_page(p) + THREAD_SIZE; new_stack = task_stack_page(p) + THREAD_SIZE; if (regs->psr & PSR_PS) new_stack -= STACKFRAME_SZ; new_stack -= STACKFRAME_SZ + TRACEREG_SZ; new_stack -= STACKFRAME_SZ + TRACEREG_SZ; memcpy(new_stack, (char *)regs - STACKFRAME_SZ, STACKFRAME_SZ + TRACEREG_SZ); childregs = (struct pt_regs *) (new_stack + STACKFRAME_SZ); childregs = (struct pt_regs *) (new_stack + STACKFRAME_SZ); /* /* Loading @@ -356,25 +354,29 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, * Thus, kpsr|=PSR_PIL. * Thus, kpsr|=PSR_PIL. */ */ ti->ksp = (unsigned long) new_stack; ti->ksp = (unsigned long) new_stack; ti->kpc = (((unsigned long) ret_from_fork) - 0x8); p->thread.kregs = childregs; ti->kpsr = current->thread.fork_kpsr | PSR_PIL; ti->kwim = current->thread.fork_kwim; if(regs->psr & PSR_PS) { extern struct pt_regs fake_swapper_regs; p->thread.kregs = &fake_swapper_regs; if (unlikely(p->flags & PF_KTHREAD)) { new_stack += STACKFRAME_SZ + TRACEREG_SZ; extern int nwindows; childregs->u_regs[UREG_FP] = (unsigned long) new_stack; unsigned long psr; memset(new_stack, 0, STACKFRAME_SZ + TRACEREG_SZ); p->thread.flags |= SPARC_FLAG_KTHREAD; p->thread.flags |= SPARC_FLAG_KTHREAD; p->thread.current_ds = KERNEL_DS; p->thread.current_ds = KERNEL_DS; memcpy(new_stack, (void *)regs->u_regs[UREG_FP], STACKFRAME_SZ); ti->kpc = (((unsigned long) ret_from_kernel_thread) - 0x8); childregs->u_regs[UREG_G6] = (unsigned long) ti; childregs->u_regs[UREG_G1] = sp; /* function */ } else { childregs->u_regs[UREG_G2] = arg; p->thread.kregs = childregs; psr = childregs->psr = get_psr(); ti->kpsr = psr | PSR_PIL; ti->kwim = 1 << (((psr & PSR_CWP) + 1) % nwindows); return 0; } memcpy(new_stack, (char *)regs - STACKFRAME_SZ, STACKFRAME_SZ + TRACEREG_SZ); childregs->u_regs[UREG_FP] = sp; childregs->u_regs[UREG_FP] = sp; p->thread.flags &= ~SPARC_FLAG_KTHREAD; p->thread.flags &= ~SPARC_FLAG_KTHREAD; p->thread.current_ds = USER_DS; p->thread.current_ds = USER_DS; ti->kpc = (((unsigned long) ret_from_fork) - 0x8); ti->kpsr = current->thread.fork_kpsr | PSR_PIL; ti->kwim = current->thread.fork_kwim; if (sp != regs->u_regs[UREG_FP]) { if (sp != regs->u_regs[UREG_FP]) { struct sparc_stackf __user *childstack; struct sparc_stackf __user *childstack; Loading Loading @@ -405,7 +407,6 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, childregs->u_regs[UREG_FP] = (unsigned long)childstack; childregs->u_regs[UREG_FP] = (unsigned long)childstack; } } } #ifdef CONFIG_SMP #ifdef CONFIG_SMP /* FPU must be disabled on SMP. */ /* FPU must be disabled on SMP. */ Loading Loading @@ -503,41 +504,6 @@ asmlinkage int sparc_execve(struct pt_regs *regs) return error; return error; } } /* * 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; __asm__ __volatile__("mov %4, %%g2\n\t" /* Set aside fn ptr... */ "mov %5, %%g3\n\t" /* and arg. */ "mov %1, %%g1\n\t" "mov %2, %%o0\n\t" /* Clone flags. */ "mov 0, %%o1\n\t" /* usp arg == 0 */ "t 0x10\n\t" /* Linux/Sparc clone(). */ "cmp %%o1, 0\n\t" "be 1f\n\t" /* The parent, just return. */ " nop\n\t" /* Delay slot. */ "jmpl %%g2, %%o7\n\t" /* Call the function. */ " mov %%g3, %%o0\n\t" /* Get back the arg in delay. */ "mov %3, %%g1\n\t" "t 0x10\n\t" /* Linux/Sparc exit(). */ /* Notreached by child. */ "1: mov %%o0, %0\n\t" : "=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); unsigned long get_wchan(struct task_struct *task) unsigned long get_wchan(struct task_struct *task) { { unsigned long pc, fp, bias = 0; unsigned long pc, fp, bias = 0; Loading Loading
arch/sparc/Kconfig +1 −1 Original line number Original line Diff line number Diff line Loading @@ -40,6 +40,7 @@ config SPARC select GENERIC_STRNCPY_FROM_USER select GENERIC_STRNCPY_FROM_USER select GENERIC_STRNLEN_USER select GENERIC_STRNLEN_USER select MODULES_USE_ELF_RELA select MODULES_USE_ELF_RELA select GENERIC_KERNEL_THREAD config SPARC32 config SPARC32 def_bool !64BIT def_bool !64BIT Loading Loading @@ -74,7 +75,6 @@ config SPARC64 select ARCH_HAVE_NMI_SAFE_CMPXCHG select ARCH_HAVE_NMI_SAFE_CMPXCHG select HAVE_C_RECORDMCOUNT select HAVE_C_RECORDMCOUNT select NO_BOOTMEM select NO_BOOTMEM select GENERIC_KERNEL_THREAD select GENERIC_KERNEL_EXECVE select GENERIC_KERNEL_EXECVE config ARCH_DEFCONFIG config ARCH_DEFCONFIG Loading
arch/sparc/include/asm/processor_32.h +0 −1 Original line number Original line Diff line number Diff line Loading @@ -106,7 +106,6 @@ static inline void start_thread(struct pt_regs * regs, unsigned long pc, /* Free all resources held by a thread. */ /* Free all resources held by a thread. */ #define release_thread(tsk) do { } while(0) #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 *); extern unsigned long get_wchan(struct task_struct *); Loading
arch/sparc/kernel/entry.S +10 −0 Original line number Original line Diff line number Diff line Loading @@ -983,6 +983,16 @@ ret_from_fork: b ret_sys_call b ret_sys_call ld [%sp + STACKFRAME_SZ + PT_I0], %o0 ld [%sp + STACKFRAME_SZ + PT_I0], %o0 .globl ret_from_kernel_thread ret_from_kernel_thread: call schedule_tail ld [%g3 + TI_TASK], %o0 ld [%sp + STACKFRAME_SZ + PT_G1], %l0 call %l0 ld [%sp + STACKFRAME_SZ + PT_G2], %o0 call do_exit /* won't return */ clr %o0 /* Linux native system calls enter here... */ /* Linux native system calls enter here... */ .align 4 .align 4 .globl linux_sparc_syscall .globl linux_sparc_syscall Loading
arch/sparc/kernel/process_32.c +45 −79 Original line number Original line Diff line number Diff line Loading @@ -316,9 +316,10 @@ asmlinkage int sparc_do_fork(unsigned long clone_flags, * XXX See comment above sys_vfork in sparc64. todo. * XXX See comment above sys_vfork in sparc64. todo. */ */ extern void ret_from_fork(void); extern void ret_from_fork(void); extern void ret_from_kernel_thread(void); int copy_thread(unsigned long clone_flags, unsigned long sp, 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 task_struct *p, struct pt_regs *regs) { { struct thread_info *ti = task_thread_info(p); struct thread_info *ti = task_thread_info(p); Loading @@ -336,16 +337,13 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, } } /* /* * p->thread_info new_stack childregs * p->thread_info new_stack childregs stack bottom * ! ! ! {if(PSR_PS) } * ! ! ! ! * V V (stk.fr.) V (pt_regs) { (stk.fr.) } * V V (stk.fr.) V (pt_regs) V * +----- - - - - - ------+===========+============={+==========}+ * +----- - - - - - ------+===========+=============+ */ */ new_stack = task_stack_page(p) + THREAD_SIZE; new_stack = task_stack_page(p) + THREAD_SIZE; if (regs->psr & PSR_PS) new_stack -= STACKFRAME_SZ; new_stack -= STACKFRAME_SZ + TRACEREG_SZ; new_stack -= STACKFRAME_SZ + TRACEREG_SZ; memcpy(new_stack, (char *)regs - STACKFRAME_SZ, STACKFRAME_SZ + TRACEREG_SZ); childregs = (struct pt_regs *) (new_stack + STACKFRAME_SZ); childregs = (struct pt_regs *) (new_stack + STACKFRAME_SZ); /* /* Loading @@ -356,25 +354,29 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, * Thus, kpsr|=PSR_PIL. * Thus, kpsr|=PSR_PIL. */ */ ti->ksp = (unsigned long) new_stack; ti->ksp = (unsigned long) new_stack; ti->kpc = (((unsigned long) ret_from_fork) - 0x8); p->thread.kregs = childregs; ti->kpsr = current->thread.fork_kpsr | PSR_PIL; ti->kwim = current->thread.fork_kwim; if(regs->psr & PSR_PS) { extern struct pt_regs fake_swapper_regs; p->thread.kregs = &fake_swapper_regs; if (unlikely(p->flags & PF_KTHREAD)) { new_stack += STACKFRAME_SZ + TRACEREG_SZ; extern int nwindows; childregs->u_regs[UREG_FP] = (unsigned long) new_stack; unsigned long psr; memset(new_stack, 0, STACKFRAME_SZ + TRACEREG_SZ); p->thread.flags |= SPARC_FLAG_KTHREAD; p->thread.flags |= SPARC_FLAG_KTHREAD; p->thread.current_ds = KERNEL_DS; p->thread.current_ds = KERNEL_DS; memcpy(new_stack, (void *)regs->u_regs[UREG_FP], STACKFRAME_SZ); ti->kpc = (((unsigned long) ret_from_kernel_thread) - 0x8); childregs->u_regs[UREG_G6] = (unsigned long) ti; childregs->u_regs[UREG_G1] = sp; /* function */ } else { childregs->u_regs[UREG_G2] = arg; p->thread.kregs = childregs; psr = childregs->psr = get_psr(); ti->kpsr = psr | PSR_PIL; ti->kwim = 1 << (((psr & PSR_CWP) + 1) % nwindows); return 0; } memcpy(new_stack, (char *)regs - STACKFRAME_SZ, STACKFRAME_SZ + TRACEREG_SZ); childregs->u_regs[UREG_FP] = sp; childregs->u_regs[UREG_FP] = sp; p->thread.flags &= ~SPARC_FLAG_KTHREAD; p->thread.flags &= ~SPARC_FLAG_KTHREAD; p->thread.current_ds = USER_DS; p->thread.current_ds = USER_DS; ti->kpc = (((unsigned long) ret_from_fork) - 0x8); ti->kpsr = current->thread.fork_kpsr | PSR_PIL; ti->kwim = current->thread.fork_kwim; if (sp != regs->u_regs[UREG_FP]) { if (sp != regs->u_regs[UREG_FP]) { struct sparc_stackf __user *childstack; struct sparc_stackf __user *childstack; Loading Loading @@ -405,7 +407,6 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, childregs->u_regs[UREG_FP] = (unsigned long)childstack; childregs->u_regs[UREG_FP] = (unsigned long)childstack; } } } #ifdef CONFIG_SMP #ifdef CONFIG_SMP /* FPU must be disabled on SMP. */ /* FPU must be disabled on SMP. */ Loading Loading @@ -503,41 +504,6 @@ asmlinkage int sparc_execve(struct pt_regs *regs) return error; return error; } } /* * 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; __asm__ __volatile__("mov %4, %%g2\n\t" /* Set aside fn ptr... */ "mov %5, %%g3\n\t" /* and arg. */ "mov %1, %%g1\n\t" "mov %2, %%o0\n\t" /* Clone flags. */ "mov 0, %%o1\n\t" /* usp arg == 0 */ "t 0x10\n\t" /* Linux/Sparc clone(). */ "cmp %%o1, 0\n\t" "be 1f\n\t" /* The parent, just return. */ " nop\n\t" /* Delay slot. */ "jmpl %%g2, %%o7\n\t" /* Call the function. */ " mov %%g3, %%o0\n\t" /* Get back the arg in delay. */ "mov %3, %%g1\n\t" "t 0x10\n\t" /* Linux/Sparc exit(). */ /* Notreached by child. */ "1: mov %%o0, %0\n\t" : "=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); unsigned long get_wchan(struct task_struct *task) unsigned long get_wchan(struct task_struct *task) { { unsigned long pc, fp, bias = 0; unsigned long pc, fp, bias = 0; Loading