Loading arch/arm/Kconfig +1 −0 Original line number Diff line number Diff line Loading @@ -49,6 +49,7 @@ config ARM select GENERIC_STRNCPY_FROM_USER select GENERIC_STRNLEN_USER select DCACHE_WORD_ACCESS if (CPU_V6 || CPU_V6K || CPU_V7) && !CPU_BIG_ENDIAN select GENERIC_KERNEL_THREAD help The ARM series is a line of low-power-consumption RISC chip designs licensed by ARM Ltd and targeted at embedded applications and Loading arch/arm/include/asm/processor.h +0 −5 Original line number Diff line number Diff line Loading @@ -85,11 +85,6 @@ unsigned long get_wchan(struct task_struct *p); #define cpu_relax() barrier() #endif /* * Create a new kernel thread */ extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); #define task_pt_regs(p) \ ((struct pt_regs *)(THREAD_START_SP + task_stack_page(p)) - 1) Loading arch/arm/kernel/entry-common.S +12 −0 Original line number Diff line number Diff line Loading @@ -91,6 +91,18 @@ ENTRY(ret_from_fork) b ret_slow_syscall ENDPROC(ret_from_fork) ENTRY(ret_from_kernel_thread) UNWIND(.fnstart) UNWIND(.cantunwind) bl schedule_tail mov r0, r4 adr lr, BSYM(1f) @ kernel threads should not exit mov pc, r5 1: bl do_exit nop UNWIND(.fnend) ENDPROC(ret_from_kernel_thread) .equ NR_syscalls,0 #define CALL(x) .equ NR_syscalls,NR_syscalls+1 #include "calls.S" Loading arch/arm/kernel/process.c +13 −62 Original line number Diff line number Diff line Loading @@ -373,6 +373,7 @@ void release_thread(struct task_struct *dead_task) } asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); asmlinkage void ret_from_kernel_thread(void) __asm__("ret_from_kernel_thread"); int copy_thread(unsigned long clone_flags, unsigned long stack_start, Loading @@ -381,13 +382,20 @@ copy_thread(unsigned long clone_flags, unsigned long stack_start, struct thread_info *thread = task_thread_info(p); struct pt_regs *childregs = task_pt_regs(p); memset(&thread->cpu_context, 0, sizeof(struct cpu_context_save)); if (likely(regs)) { *childregs = *regs; childregs->ARM_r0 = 0; childregs->ARM_sp = stack_start; memset(&thread->cpu_context, 0, sizeof(struct cpu_context_save)); thread->cpu_context.sp = (unsigned long)childregs; thread->cpu_context.pc = (unsigned long)ret_from_fork; } else { thread->cpu_context.r4 = stk_sz; thread->cpu_context.r5 = stack_start; thread->cpu_context.pc = (unsigned long)ret_from_kernel_thread; childregs->ARM_cpsr = SVC_MODE; } thread->cpu_context.sp = (unsigned long)childregs; clear_ptrace_hw_breakpoint(p); Loading Loading @@ -423,63 +431,6 @@ int dump_fpu (struct pt_regs *regs, struct user_fp *fp) } EXPORT_SYMBOL(dump_fpu); /* * Shuffle the argument into the correct register before calling the * thread function. r4 is the thread argument, r5 is the pointer to * the thread function, and r6 points to the exit function. */ extern void kernel_thread_helper(void); asm( ".pushsection .text\n" " .align\n" " .type kernel_thread_helper, #function\n" "kernel_thread_helper:\n" #ifdef CONFIG_TRACE_IRQFLAGS " bl trace_hardirqs_on\n" #endif " msr cpsr_c, r7\n" " mov r0, r4\n" " mov lr, r6\n" " mov pc, r5\n" " .size kernel_thread_helper, . - kernel_thread_helper\n" " .popsection"); #ifdef CONFIG_ARM_UNWIND extern void kernel_thread_exit(long code); asm( ".pushsection .text\n" " .align\n" " .type kernel_thread_exit, #function\n" "kernel_thread_exit:\n" " .fnstart\n" " .cantunwind\n" " bl do_exit\n" " nop\n" " .fnend\n" " .size kernel_thread_exit, . - kernel_thread_exit\n" " .popsection"); #else #define kernel_thread_exit do_exit #endif /* * Create a kernel thread. */ pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) { struct pt_regs regs; memset(®s, 0, sizeof(regs)); regs.ARM_r4 = (unsigned long)arg; regs.ARM_r5 = (unsigned long)fn; regs.ARM_r6 = (unsigned long)kernel_thread_exit; regs.ARM_r7 = SVC_MODE | PSR_ENDSTATE | PSR_ISETSTATE; regs.ARM_pc = (unsigned long)kernel_thread_helper; regs.ARM_cpsr = regs.ARM_r7 | PSR_I_BIT; return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); } EXPORT_SYMBOL(kernel_thread); unsigned long get_wchan(struct task_struct *p) { struct stackframe frame; Loading Loading
arch/arm/Kconfig +1 −0 Original line number Diff line number Diff line Loading @@ -49,6 +49,7 @@ config ARM select GENERIC_STRNCPY_FROM_USER select GENERIC_STRNLEN_USER select DCACHE_WORD_ACCESS if (CPU_V6 || CPU_V6K || CPU_V7) && !CPU_BIG_ENDIAN select GENERIC_KERNEL_THREAD help The ARM series is a line of low-power-consumption RISC chip designs licensed by ARM Ltd and targeted at embedded applications and Loading
arch/arm/include/asm/processor.h +0 −5 Original line number Diff line number Diff line Loading @@ -85,11 +85,6 @@ unsigned long get_wchan(struct task_struct *p); #define cpu_relax() barrier() #endif /* * Create a new kernel thread */ extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); #define task_pt_regs(p) \ ((struct pt_regs *)(THREAD_START_SP + task_stack_page(p)) - 1) Loading
arch/arm/kernel/entry-common.S +12 −0 Original line number Diff line number Diff line Loading @@ -91,6 +91,18 @@ ENTRY(ret_from_fork) b ret_slow_syscall ENDPROC(ret_from_fork) ENTRY(ret_from_kernel_thread) UNWIND(.fnstart) UNWIND(.cantunwind) bl schedule_tail mov r0, r4 adr lr, BSYM(1f) @ kernel threads should not exit mov pc, r5 1: bl do_exit nop UNWIND(.fnend) ENDPROC(ret_from_kernel_thread) .equ NR_syscalls,0 #define CALL(x) .equ NR_syscalls,NR_syscalls+1 #include "calls.S" Loading
arch/arm/kernel/process.c +13 −62 Original line number Diff line number Diff line Loading @@ -373,6 +373,7 @@ void release_thread(struct task_struct *dead_task) } asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); asmlinkage void ret_from_kernel_thread(void) __asm__("ret_from_kernel_thread"); int copy_thread(unsigned long clone_flags, unsigned long stack_start, Loading @@ -381,13 +382,20 @@ copy_thread(unsigned long clone_flags, unsigned long stack_start, struct thread_info *thread = task_thread_info(p); struct pt_regs *childregs = task_pt_regs(p); memset(&thread->cpu_context, 0, sizeof(struct cpu_context_save)); if (likely(regs)) { *childregs = *regs; childregs->ARM_r0 = 0; childregs->ARM_sp = stack_start; memset(&thread->cpu_context, 0, sizeof(struct cpu_context_save)); thread->cpu_context.sp = (unsigned long)childregs; thread->cpu_context.pc = (unsigned long)ret_from_fork; } else { thread->cpu_context.r4 = stk_sz; thread->cpu_context.r5 = stack_start; thread->cpu_context.pc = (unsigned long)ret_from_kernel_thread; childregs->ARM_cpsr = SVC_MODE; } thread->cpu_context.sp = (unsigned long)childregs; clear_ptrace_hw_breakpoint(p); Loading Loading @@ -423,63 +431,6 @@ int dump_fpu (struct pt_regs *regs, struct user_fp *fp) } EXPORT_SYMBOL(dump_fpu); /* * Shuffle the argument into the correct register before calling the * thread function. r4 is the thread argument, r5 is the pointer to * the thread function, and r6 points to the exit function. */ extern void kernel_thread_helper(void); asm( ".pushsection .text\n" " .align\n" " .type kernel_thread_helper, #function\n" "kernel_thread_helper:\n" #ifdef CONFIG_TRACE_IRQFLAGS " bl trace_hardirqs_on\n" #endif " msr cpsr_c, r7\n" " mov r0, r4\n" " mov lr, r6\n" " mov pc, r5\n" " .size kernel_thread_helper, . - kernel_thread_helper\n" " .popsection"); #ifdef CONFIG_ARM_UNWIND extern void kernel_thread_exit(long code); asm( ".pushsection .text\n" " .align\n" " .type kernel_thread_exit, #function\n" "kernel_thread_exit:\n" " .fnstart\n" " .cantunwind\n" " bl do_exit\n" " nop\n" " .fnend\n" " .size kernel_thread_exit, . - kernel_thread_exit\n" " .popsection"); #else #define kernel_thread_exit do_exit #endif /* * Create a kernel thread. */ pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) { struct pt_regs regs; memset(®s, 0, sizeof(regs)); regs.ARM_r4 = (unsigned long)arg; regs.ARM_r5 = (unsigned long)fn; regs.ARM_r6 = (unsigned long)kernel_thread_exit; regs.ARM_r7 = SVC_MODE | PSR_ENDSTATE | PSR_ISETSTATE; regs.ARM_pc = (unsigned long)kernel_thread_helper; regs.ARM_cpsr = regs.ARM_r7 | PSR_I_BIT; return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); } EXPORT_SYMBOL(kernel_thread); unsigned long get_wchan(struct task_struct *p) { struct stackframe frame; Loading