Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c78e0643 authored by Al Viro's avatar Al Viro
Browse files

sparc32: switch to generic kernel_thread()



Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 32942bc7
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -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
@@ -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
+0 −1
Original line number Original line Diff line number Diff line
@@ -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 *);


+10 −0
Original line number Original line Diff line number Diff line
@@ -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
+45 −79
Original line number Original line Diff line number Diff line
@@ -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);
@@ -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);


	/*
	/*
@@ -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;
@@ -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. */
@@ -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;