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

Commit 54d496c3 authored by Al Viro's avatar Al Viro
Browse files

ia64: switch to generic kernel_thread()/kernel_execve()

parent c19e6d67
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -42,6 +42,8 @@ config IA64
	select GENERIC_TIME_VSYSCALL_OLD
	select GENERIC_TIME_VSYSCALL_OLD
	select HAVE_MOD_ARCH_SPECIFIC
	select HAVE_MOD_ARCH_SPECIFIC
	select MODULES_USE_ELF_RELA
	select MODULES_USE_ELF_RELA
	select GENERIC_KERNEL_THREAD
	select GENERIC_KERNEL_EXECVE
	default y
	default y
	help
	help
	  The Itanium Processor Family is Intel's 64-bit successor to
	  The Itanium Processor Family is Intel's 64-bit successor to
+0 −16
Original line number Original line Diff line number Diff line
@@ -340,22 +340,6 @@ struct task_struct;
 */
 */
#define release_thread(dead_task)
#define release_thread(dead_task)


/*
 * This is the mechanism for creating a new kernel thread.
 *
 * NOTE 1: 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 free'd until both the parent and
 * the child have exited.
 *
 * NOTE 2: This MUST NOT be an inlined function.  Otherwise, we get
 * into trouble in init/main.c when the child thread returns to
 * do_basic_setup() and the timing is such that free_initmem() has
 * been called already.
 */
extern pid_t kernel_thread (int (*fn)(void *), void *arg, unsigned long flags);

/* Get wait channel for task P.  */
/* Get wait channel for task P.  */
extern unsigned long get_wchan (struct task_struct *p);
extern unsigned long get_wchan (struct task_struct *p);


+22 −7
Original line number Original line Diff line number Diff line
@@ -484,13 +484,6 @@ GLOBAL_ENTRY(prefetch_stack)
	br.ret.sptk.many rp
	br.ret.sptk.many rp
END(prefetch_stack)
END(prefetch_stack)


GLOBAL_ENTRY(kernel_execve)
	rum psr.ac
	mov r15=__NR_execve			// put syscall number in place
	break __BREAK_SYSCALL
	br.ret.sptk.many rp
END(kernel_execve)

	/*
	/*
	 * Invoke a system call, but do some tracing before and after the call.
	 * Invoke a system call, but do some tracing before and after the call.
	 * We MUST preserve the current register frame throughout this routine
	 * We MUST preserve the current register frame throughout this routine
@@ -594,6 +587,27 @@ GLOBAL_ENTRY(ia64_strace_leave_kernel)
.ret4:	br.cond.sptk ia64_leave_kernel
.ret4:	br.cond.sptk ia64_leave_kernel
END(ia64_strace_leave_kernel)
END(ia64_strace_leave_kernel)


ENTRY(call_payload)
	.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(0)
	/* call the kernel_thread payload; fn is in r4, arg - in r5 */
	alloc loc1=ar.pfs,0,3,1,0
	mov loc0=rp
	mov loc2=gp
	mov out0=r5		// arg
	ld8 r14 = [r4], 8	// fn.address
	;;
	mov b6 = r14
	ld8 gp = [r4]		// fn.gp
	;;
	br.call.sptk.many rp=b6	// fn(arg)
.ret12:	mov gp=loc2
	mov rp=loc0
	mov ar.pfs=loc1
	/* ... and if it has returned, we are going to userland */
	cmp.ne pKStk,pUStk=r0,r0
	br.ret.sptk.many rp
END(call_payload)

GLOBAL_ENTRY(ia64_ret_from_clone)
GLOBAL_ENTRY(ia64_ret_from_clone)
	PT_REGS_UNWIND_INFO(0)
	PT_REGS_UNWIND_INFO(0)
{	/*
{	/*
@@ -610,6 +624,7 @@ GLOBAL_ENTRY(ia64_ret_from_clone)
	br.call.sptk.many rp=ia64_invoke_schedule_tail
	br.call.sptk.many rp=ia64_invoke_schedule_tail
}
}
.ret8:
.ret8:
(pKStk)	br.call.sptk.many rp=call_payload
	adds r2=TI_FLAGS+IA64_TASK_SIZE,r13
	adds r2=TI_FLAGS+IA64_TASK_SIZE,r13
	;;
	;;
	ld4 r2=[r2]
	ld4 r2=[r2]
+0 −13
Original line number Original line Diff line number Diff line
@@ -1093,19 +1093,6 @@ GLOBAL_ENTRY(cycle_to_cputime)
END(cycle_to_cputime)
END(cycle_to_cputime)
#endif /* CONFIG_VIRT_CPU_ACCOUNTING */
#endif /* CONFIG_VIRT_CPU_ACCOUNTING */


GLOBAL_ENTRY(start_kernel_thread)
	.prologue
	.save rp, r0				// this is the end of the call-chain
	.body
	alloc r2 = ar.pfs, 0, 0, 2, 0
	mov out0 = r9
	mov out1 = r11;;
	br.call.sptk.many rp = kernel_thread_helper;;
	mov out0 = r8
	br.call.sptk.many rp = sys_exit;;
1:	br.sptk.few 1b				// not reached
END(start_kernel_thread)

#ifdef CONFIG_IA64_BRL_EMU
#ifdef CONFIG_IA64_BRL_EMU


/*
/*
+58 −71
Original line number Original line Diff line number Diff line
@@ -401,55 +401,15 @@ copy_thread(unsigned long clone_flags,
	struct pt_regs *child_ptregs;
	struct pt_regs *child_ptregs;
	int retval = 0;
	int retval = 0;


	stack = ((struct switch_stack *) regs) - 1;

	child_ptregs = (struct pt_regs *) ((unsigned long) p + IA64_STK_OFFSET) - 1;
	child_ptregs = (struct pt_regs *) ((unsigned long) p + IA64_STK_OFFSET) - 1;
	child_stack = (struct switch_stack *) child_ptregs - 1;
	child_stack = (struct switch_stack *) child_ptregs - 1;


	/* copy parent's switch_stack & pt_regs to child: */
	memcpy(child_stack, stack, sizeof(*child_ptregs) + sizeof(*child_stack));

	rbs = (unsigned long) current + IA64_RBS_OFFSET;
	rbs = (unsigned long) current + IA64_RBS_OFFSET;
	child_rbs = (unsigned long) p + IA64_RBS_OFFSET;
	child_rbs = (unsigned long) p + IA64_RBS_OFFSET;


	if (likely(user_mode(child_ptregs))) {
		/* copy the parent's register backing store to the child: */
		rbs_size = stack->ar_bspstore - rbs;
		memcpy((void *) child_rbs, (void *) rbs, rbs_size);
		if (clone_flags & CLONE_SETTLS)
			child_ptregs->r13 = regs->r16;	/* see sys_clone2() in entry.S */
		if (user_stack_base) {
			child_ptregs->r12 = user_stack_base + user_stack_size - 16;
			child_ptregs->ar_bspstore = user_stack_base;
			child_ptregs->ar_rnat = 0;
			child_ptregs->loadrs = 0;
		}
	} else {
		/*
		 * Note: we simply preserve the relative position of
		 * the stack pointer here.  There is no need to
		 * allocate a scratch area here, since that will have
		 * been taken care of by the caller of sys_clone()
		 * already.
		 */
		rbs_size = 0;
		child_ptregs->r12 = (unsigned long) child_ptregs - 16; /* kernel sp */
		child_ptregs->r13 = (unsigned long) p;		/* set `current' pointer */
	}
	child_stack->ar_bspstore = child_rbs + rbs_size;
	child_stack->b0 = (unsigned long) &ia64_ret_from_clone;

	/* copy parts of thread_struct: */
	/* copy parts of thread_struct: */
	p->thread.ksp = (unsigned long) child_stack - 16;
	p->thread.ksp = (unsigned long) child_stack - 16;


	/* stop some PSR bits from being inherited.
	 * the psr.up/psr.pp bits must be cleared on fork but inherited on execve()
	 * therefore we must specify them explicitly here and not include them in
	 * IA64_PSR_BITS_TO_CLEAR.
	 */
	child_ptregs->cr_ipsr = ((child_ptregs->cr_ipsr | IA64_PSR_BITS_TO_SET)
				 & ~(IA64_PSR_BITS_TO_CLEAR | IA64_PSR_PP | IA64_PSR_UP));

	/*
	/*
	 * NOTE: The calling convention considers all floating point
	 * NOTE: The calling convention considers all floating point
	 * registers in the high partition (fph) to be scratch.  Since
	 * registers in the high partition (fph) to be scratch.  Since
@@ -471,8 +431,66 @@ copy_thread(unsigned long clone_flags,
#	define THREAD_FLAGS_TO_SET	0
#	define THREAD_FLAGS_TO_SET	0
	p->thread.flags = ((current->thread.flags & ~THREAD_FLAGS_TO_CLEAR)
	p->thread.flags = ((current->thread.flags & ~THREAD_FLAGS_TO_CLEAR)
			   | THREAD_FLAGS_TO_SET);
			   | THREAD_FLAGS_TO_SET);

	ia64_drop_fpu(p);	/* don't pick up stale state from a CPU's fph */
	ia64_drop_fpu(p);	/* don't pick up stale state from a CPU's fph */


	if (unlikely(p->flags & PF_KTHREAD)) {
		if (unlikely(!user_stack_base)) {
			/* fork_idle() called us */
			return 0;
		}
		memset(child_stack, 0, sizeof(*child_ptregs) + sizeof(*child_stack));
		child_stack->r4 = user_stack_base;	/* payload */
		child_stack->r5 = user_stack_size;	/* argument */
		/*
		 * Preserve PSR bits, except for bits 32-34 and 37-45,
		 * which we can't read.
		 */
		child_ptregs->cr_ipsr = ia64_getreg(_IA64_REG_PSR) | IA64_PSR_BN;
		/* mark as valid, empty frame */
		child_ptregs->cr_ifs = 1UL << 63;
		child_stack->ar_fpsr = child_ptregs->ar_fpsr
			= ia64_getreg(_IA64_REG_AR_FPSR);
		child_stack->pr = (1 << PRED_KERNEL_STACK);
		child_stack->ar_bspstore = child_rbs;
		child_stack->b0 = (unsigned long) &ia64_ret_from_clone;

		/* stop some PSR bits from being inherited.
		 * the psr.up/psr.pp bits must be cleared on fork but inherited on execve()
		 * therefore we must specify them explicitly here and not include them in
		 * IA64_PSR_BITS_TO_CLEAR.
		 */
		child_ptregs->cr_ipsr = ((child_ptregs->cr_ipsr | IA64_PSR_BITS_TO_SET)
				 & ~(IA64_PSR_BITS_TO_CLEAR | IA64_PSR_PP | IA64_PSR_UP));

		return 0;
	}
	stack = ((struct switch_stack *) regs) - 1;
	/* copy parent's switch_stack & pt_regs to child: */
	memcpy(child_stack, stack, sizeof(*child_ptregs) + sizeof(*child_stack));

	/* copy the parent's register backing store to the child: */
	rbs_size = stack->ar_bspstore - rbs;
	memcpy((void *) child_rbs, (void *) rbs, rbs_size);
	if (clone_flags & CLONE_SETTLS)
		child_ptregs->r13 = regs->r16;	/* see sys_clone2() in entry.S */
	if (user_stack_base) {
		child_ptregs->r12 = user_stack_base + user_stack_size - 16;
		child_ptregs->ar_bspstore = user_stack_base;
		child_ptregs->ar_rnat = 0;
		child_ptregs->loadrs = 0;
	}
	child_stack->ar_bspstore = child_rbs + rbs_size;
	child_stack->b0 = (unsigned long) &ia64_ret_from_clone;

	/* stop some PSR bits from being inherited.
	 * the psr.up/psr.pp bits must be cleared on fork but inherited on execve()
	 * therefore we must specify them explicitly here and not include them in
	 * IA64_PSR_BITS_TO_CLEAR.
	 */
	child_ptregs->cr_ipsr = ((child_ptregs->cr_ipsr | IA64_PSR_BITS_TO_SET)
				 & ~(IA64_PSR_BITS_TO_CLEAR | IA64_PSR_PP | IA64_PSR_UP));

#ifdef CONFIG_PERFMON
#ifdef CONFIG_PERFMON
	if (current->thread.pfm_context)
	if (current->thread.pfm_context)
		pfm_inherit(p, child_ptregs);
		pfm_inherit(p, child_ptregs);
@@ -618,37 +636,6 @@ sys_execve (const char __user *filename,
	return error;
	return error;
}
}


pid_t
kernel_thread (int (*fn)(void *), void *arg, unsigned long flags)
{
	extern void start_kernel_thread (void);
	unsigned long *helper_fptr = (unsigned long *) &start_kernel_thread;
	struct {
		struct switch_stack sw;
		struct pt_regs pt;
	} regs;

	memset(&regs, 0, sizeof(regs));
	regs.pt.cr_iip = helper_fptr[0];	/* set entry point (IP) */
	regs.pt.r1 = helper_fptr[1];		/* set GP */
	regs.pt.r9 = (unsigned long) fn;	/* 1st argument */
	regs.pt.r11 = (unsigned long) arg;	/* 2nd argument */
	/* Preserve PSR bits, except for bits 32-34 and 37-45, which we can't read.  */
	regs.pt.cr_ipsr = ia64_getreg(_IA64_REG_PSR) | IA64_PSR_BN;
	regs.pt.cr_ifs = 1UL << 63;		/* mark as valid, empty frame */
	regs.sw.ar_fpsr = regs.pt.ar_fpsr = ia64_getreg(_IA64_REG_AR_FPSR);
	regs.sw.pr = (1 << PRED_KERNEL_STACK);
	return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs.pt, 0, NULL, NULL);
}
EXPORT_SYMBOL(kernel_thread);

/* This gets called from kernel_thread() via ia64_invoke_thread_helper().  */
int
kernel_thread_helper (int (*fn)(void *), void *arg)
{
	return (*fn)(arg);
}

/*
/*
 * Flush thread state.  This is called when a thread does an execve().
 * Flush thread state.  This is called when a thread does an execve().
 */
 */