diff options
| author | Al Viro <viro@zeniv.linux.org.uk> | 2012-10-05 22:37:01 -0400 | 
|---|---|---|
| committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-10-14 19:26:52 -0400 | 
| commit | 1918c7f548dc5abfb37ab74bb3d036d36c92ba5e (patch) | |
| tree | c6f1a678fd6dac2ab93579a7246afb27cc7f9f26 | |
| parent | dff933da765fd4855393846fa55286d1ff2d024a (diff) | |
| download | linux-1918c7f548dc5abfb37ab74bb3d036d36c92ba5e.tar.bz2 | |
sparc64: switch to generic kernel_thread()
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
| -rw-r--r-- | arch/sparc/Kconfig | 1 | ||||
| -rw-r--r-- | arch/sparc/include/asm/processor_64.h | 2 | ||||
| -rw-r--r-- | arch/sparc/include/asm/ptrace.h | 3 | ||||
| -rw-r--r-- | arch/sparc/kernel/process_64.c | 107 | ||||
| -rw-r--r-- | arch/sparc/kernel/syscalls.S | 11 | 
5 files changed, 42 insertions, 82 deletions
| 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 |