Loading arch/ia64/Kconfig +2 −0 Original line number Diff line number Diff line Loading @@ -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 Loading arch/ia64/include/asm/processor.h +0 −16 Original line number Diff line number Diff line Loading @@ -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); Loading arch/ia64/kernel/entry.S +22 −7 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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) { /* Loading @@ -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] Loading arch/ia64/kernel/head.S +0 −13 Original line number Diff line number Diff line Loading @@ -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 /* Loading arch/ia64/kernel/process.c +58 −71 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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); Loading Loading @@ -618,37 +636,6 @@ sys_execve (const char __user *filename, 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(). */ Loading Loading
arch/ia64/Kconfig +2 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
arch/ia64/include/asm/processor.h +0 −16 Original line number Diff line number Diff line Loading @@ -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); Loading
arch/ia64/kernel/entry.S +22 −7 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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) { /* Loading @@ -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] Loading
arch/ia64/kernel/head.S +0 −13 Original line number Diff line number Diff line Loading @@ -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 /* Loading
arch/ia64/kernel/process.c +58 −71 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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); Loading Loading @@ -618,37 +636,6 @@ sys_execve (const char __user *filename, 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(). */ Loading