From a8b8f6625075c673e21ef9bb418a31b0858472b0 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 30 Sep 2012 00:20:50 -0400 Subject: ia64: clone() had been unused since 2004 Used to be used by kernel_thread(); dead code for 8 years... Note that it's not sys_clone/sys_clone2 - those are used just fine. Signed-off-by: Al Viro --- arch/ia64/kernel/entry.S | 6 ------ 1 file changed, 6 deletions(-) (limited to 'arch/ia64') diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index 1ccbe12a4d84..6b0648d97b4c 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S @@ -491,12 +491,6 @@ GLOBAL_ENTRY(kernel_execve) br.ret.sptk.many rp END(kernel_execve) -GLOBAL_ENTRY(clone) - mov r15=__NR_clone // put syscall number in place - break __BREAK_SYSCALL - br.ret.sptk.many rp -END(clone) - /* * Invoke a system call, but do some tracing before and after the call. * We MUST preserve the current register frame throughout this routine -- cgit v1.2.3-59-g8ed1b From c4aee363af2a81f9726c5fa13e136ebaf02852bd Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 30 Sep 2012 00:23:05 -0400 Subject: ia64: dead code in copy_thread() since 2004 It used to be called with NULL regs when creating idle threads on secondaries. Not used that way since wli had buried that kludge... Signed-off-by: Al Viro --- arch/ia64/kernel/process.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'arch/ia64') diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c index 35e106f2ed13..63a77b8b5cfa 100644 --- a/arch/ia64/kernel/process.c +++ b/arch/ia64/kernel/process.c @@ -401,15 +401,6 @@ copy_thread(unsigned long clone_flags, struct pt_regs *child_ptregs; int retval = 0; -#ifdef CONFIG_SMP - /* - * For SMP idle threads, fork_by_hand() calls do_fork with - * NULL regs. - */ - if (!regs) - return 0; -#endif - stack = ((struct switch_stack *) regs) - 1; child_ptregs = (struct pt_regs *) ((unsigned long) p + IA64_STK_OFFSET) - 1; -- cgit v1.2.3-59-g8ed1b From c19e6d67e4be16e20ff90f0baa98b16d926d23a5 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 30 Sep 2012 00:27:40 -0400 Subject: ia64: don't mess with ar_bspstore in kernel_thread() the only thing we use that for is in copy_thread(), where the way we set it will result in rbs_size being 0. Just move that calculating rbs_size and copying rbs to non-kernel-thread side of if (user_mode(regs)) in copy_thread() and set rbs_size to 0 on kernel thread side. Signed-off-by: Al Viro --- arch/ia64/kernel/process.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'arch/ia64') diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c index 63a77b8b5cfa..6a48775d9363 100644 --- a/arch/ia64/kernel/process.c +++ b/arch/ia64/kernel/process.c @@ -411,12 +411,11 @@ copy_thread(unsigned long clone_flags, rbs = (unsigned long) current + IA64_RBS_OFFSET; child_rbs = (unsigned long) p + IA64_RBS_OFFSET; - rbs_size = stack->ar_bspstore - rbs; - - /* copy the parent's register backing store to the child: */ - memcpy((void *) child_rbs, (void *) rbs, rbs_size); 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) { @@ -433,6 +432,7 @@ copy_thread(unsigned long clone_flags, * 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 */ } @@ -637,7 +637,6 @@ kernel_thread (int (*fn)(void *), void *arg, unsigned long flags) 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.ar_bspstore = (unsigned long) current + IA64_RBS_OFFSET; regs.sw.pr = (1 << PRED_KERNEL_STACK); return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s.pt, 0, NULL, NULL); } -- cgit v1.2.3-59-g8ed1b From 54d496c3915a10b5e46c5dd9de1a6d301ceb32bd Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 14 Oct 2012 15:43:06 -0400 Subject: ia64: switch to generic kernel_thread()/kernel_execve() Acked-by: Tony Luck Tested-by: Tony Luck Signed-off-by: Al Viro --- arch/ia64/Kconfig | 2 + arch/ia64/include/asm/processor.h | 16 ----- arch/ia64/kernel/entry.S | 29 ++++++--- arch/ia64/kernel/head.S | 13 ---- arch/ia64/kernel/process.c | 129 +++++++++++++++++--------------------- 5 files changed, 82 insertions(+), 107 deletions(-) (limited to 'arch/ia64') diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index 3279646120e3..670600468128 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig @@ -42,6 +42,8 @@ config IA64 select GENERIC_TIME_VSYSCALL_OLD select HAVE_MOD_ARCH_SPECIFIC select MODULES_USE_ELF_RELA + select GENERIC_KERNEL_THREAD + select GENERIC_KERNEL_EXECVE default y help The Itanium Processor Family is Intel's 64-bit successor to diff --git a/arch/ia64/include/asm/processor.h b/arch/ia64/include/asm/processor.h index 944152a50912..e0a899a1a8a6 100644 --- a/arch/ia64/include/asm/processor.h +++ b/arch/ia64/include/asm/processor.h @@ -340,22 +340,6 @@ struct task_struct; */ #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. */ extern unsigned long get_wchan (struct task_struct *p); diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index 6b0648d97b4c..0dea684e1905 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S @@ -484,13 +484,6 @@ GLOBAL_ENTRY(prefetch_stack) br.ret.sptk.many rp 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. * 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 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) PT_REGS_UNWIND_INFO(0) { /* @@ -610,6 +624,7 @@ GLOBAL_ENTRY(ia64_ret_from_clone) br.call.sptk.many rp=ia64_invoke_schedule_tail } .ret8: +(pKStk) br.call.sptk.many rp=call_payload adds r2=TI_FLAGS+IA64_TASK_SIZE,r13 ;; ld4 r2=[r2] diff --git a/arch/ia64/kernel/head.S b/arch/ia64/kernel/head.S index 629a250f7c19..4738ff7bd66a 100644 --- a/arch/ia64/kernel/head.S +++ b/arch/ia64/kernel/head.S @@ -1093,19 +1093,6 @@ GLOBAL_ENTRY(cycle_to_cputime) END(cycle_to_cputime) #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 /* diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c index 6a48775d9363..37686dbfd264 100644 --- a/arch/ia64/kernel/process.c +++ b/arch/ia64/kernel/process.c @@ -401,55 +401,15 @@ copy_thread(unsigned long clone_flags, struct pt_regs *child_ptregs; int retval = 0; - stack = ((struct switch_stack *) regs) - 1; - child_ptregs = (struct pt_regs *) ((unsigned long) p + IA64_STK_OFFSET) - 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; 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: */ 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 * 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 p->thread.flags = ((current->thread.flags & ~THREAD_FLAGS_TO_CLEAR) | THREAD_FLAGS_TO_SET); + 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 if (current->thread.pfm_context) pfm_inherit(p, child_ptregs); @@ -618,37 +636,6 @@ out: 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(®s, 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, ®s.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(). */ -- cgit v1.2.3-59-g8ed1b From 71b4ecc3d8056b2ed5cbc0d77af13fed38bcac49 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 14 Oct 2012 15:53:04 -0400 Subject: ia64: switch to generic sys_execve() Acked-by: Tony Luck Tested-by: Tony Luck Signed-off-by: Al Viro --- arch/ia64/include/asm/unistd.h | 1 + arch/ia64/kernel/entry.S | 4 +--- arch/ia64/kernel/process.c | 19 ------------------- 3 files changed, 2 insertions(+), 22 deletions(-) (limited to 'arch/ia64') diff --git a/arch/ia64/include/asm/unistd.h b/arch/ia64/include/asm/unistd.h index 8b3ff2f5b861..1574bca86138 100644 --- a/arch/ia64/include/asm/unistd.h +++ b/arch/ia64/include/asm/unistd.h @@ -29,6 +29,7 @@ #define __ARCH_WANT_SYS_RT_SIGACTION #define __ARCH_WANT_SYS_RT_SIGSUSPEND +#define __ARCH_WANT_SYS_EXECVE #if !defined(__ASSEMBLY__) && !defined(ASSEMBLER) diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index 0dea684e1905..940a67263629 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S @@ -61,14 +61,13 @@ ENTRY(ia64_execve) * Allocate 8 input registers since ptrace() may clobber them */ .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) - alloc loc1=ar.pfs,8,2,4,0 + alloc loc1=ar.pfs,8,2,3,0 mov loc0=rp .body mov out0=in0 // filename ;; // stop bit between alloc and call mov out1=in1 // argv mov out2=in2 // envp - add out3=16,sp // regs br.call.sptk.many rp=sys_execve .ret0: cmp4.ge p6,p7=r8,r0 @@ -76,7 +75,6 @@ ENTRY(ia64_execve) sxt4 r8=r8 // return 64-bit result ;; stf.spill [sp]=f0 -(p6) cmp.ne pKStk,pUStk=r0,r0 // a successful execve() lands us in user-mode... mov rp=loc0 (p6) mov ar.pfs=r0 // clear ar.pfs on success (p7) br.ret.sptk.many rp diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c index 37686dbfd264..25543a295ad9 100644 --- a/arch/ia64/kernel/process.c +++ b/arch/ia64/kernel/process.c @@ -617,25 +617,6 @@ dump_fpu (struct pt_regs *pt, elf_fpregset_t dst) return 1; /* f0-f31 are always valid so we always return 1 */ } -long -sys_execve (const char __user *filename, - const char __user *const __user *argv, - const char __user *const __user *envp, - struct pt_regs *regs) -{ - struct filename *fname; - int error; - - fname = getname(filename); - error = PTR_ERR(fname); - if (IS_ERR(fname)) - goto out; - error = do_execve(fname->name, argv, envp, regs); - putname(fname); -out: - return error; -} - /* * Flush thread state. This is called when a thread does an execve(). */ -- cgit v1.2.3-59-g8ed1b