aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel/process.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/kernel/process.c')
-rw-r--r--arch/arm/kernel/process.c81
1 files changed, 16 insertions, 65 deletions
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 693b744fd572..f98c17ff1957 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -31,9 +31,9 @@
31#include <linux/random.h> 31#include <linux/random.h>
32#include <linux/hw_breakpoint.h> 32#include <linux/hw_breakpoint.h>
33#include <linux/cpuidle.h> 33#include <linux/cpuidle.h>
34#include <linux/leds.h>
34 35
35#include <asm/cacheflush.h> 36#include <asm/cacheflush.h>
36#include <asm/leds.h>
37#include <asm/processor.h> 37#include <asm/processor.h>
38#include <asm/thread_notify.h> 38#include <asm/thread_notify.h>
39#include <asm/stacktrace.h> 39#include <asm/stacktrace.h>
@@ -189,7 +189,7 @@ void cpu_idle(void)
189 while (1) { 189 while (1) {
190 tick_nohz_idle_enter(); 190 tick_nohz_idle_enter();
191 rcu_idle_enter(); 191 rcu_idle_enter();
192 leds_event(led_idle_start); 192 ledtrig_cpu(CPU_LED_IDLE_START);
193 while (!need_resched()) { 193 while (!need_resched()) {
194#ifdef CONFIG_HOTPLUG_CPU 194#ifdef CONFIG_HOTPLUG_CPU
195 if (cpu_is_offline(smp_processor_id())) 195 if (cpu_is_offline(smp_processor_id()))
@@ -220,7 +220,7 @@ void cpu_idle(void)
220 } else 220 } else
221 local_irq_enable(); 221 local_irq_enable();
222 } 222 }
223 leds_event(led_idle_end); 223 ledtrig_cpu(CPU_LED_IDLE_END);
224 rcu_idle_exit(); 224 rcu_idle_exit();
225 tick_nohz_idle_exit(); 225 tick_nohz_idle_exit();
226 schedule_preempt_disabled(); 226 schedule_preempt_disabled();
@@ -373,6 +373,7 @@ void release_thread(struct task_struct *dead_task)
373} 373}
374 374
375asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); 375asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
376asmlinkage void ret_from_kernel_thread(void) __asm__("ret_from_kernel_thread");
376 377
377int 378int
378copy_thread(unsigned long clone_flags, unsigned long stack_start, 379copy_thread(unsigned long clone_flags, unsigned long stack_start,
@@ -381,13 +382,20 @@ copy_thread(unsigned long clone_flags, unsigned long stack_start,
381 struct thread_info *thread = task_thread_info(p); 382 struct thread_info *thread = task_thread_info(p);
382 struct pt_regs *childregs = task_pt_regs(p); 383 struct pt_regs *childregs = task_pt_regs(p);
383 384
384 *childregs = *regs;
385 childregs->ARM_r0 = 0;
386 childregs->ARM_sp = stack_start;
387
388 memset(&thread->cpu_context, 0, sizeof(struct cpu_context_save)); 385 memset(&thread->cpu_context, 0, sizeof(struct cpu_context_save));
386
387 if (likely(regs)) {
388 *childregs = *regs;
389 childregs->ARM_r0 = 0;
390 childregs->ARM_sp = stack_start;
391 thread->cpu_context.pc = (unsigned long)ret_from_fork;
392 } else {
393 thread->cpu_context.r4 = stk_sz;
394 thread->cpu_context.r5 = stack_start;
395 thread->cpu_context.pc = (unsigned long)ret_from_kernel_thread;
396 childregs->ARM_cpsr = SVC_MODE;
397 }
389 thread->cpu_context.sp = (unsigned long)childregs; 398 thread->cpu_context.sp = (unsigned long)childregs;
390 thread->cpu_context.pc = (unsigned long)ret_from_fork;
391 399
392 clear_ptrace_hw_breakpoint(p); 400 clear_ptrace_hw_breakpoint(p);
393 401
@@ -423,63 +431,6 @@ int dump_fpu (struct pt_regs *regs, struct user_fp *fp)
423} 431}
424EXPORT_SYMBOL(dump_fpu); 432EXPORT_SYMBOL(dump_fpu);
425 433
426/*
427 * Shuffle the argument into the correct register before calling the
428 * thread function. r4 is the thread argument, r5 is the pointer to
429 * the thread function, and r6 points to the exit function.
430 */
431extern void kernel_thread_helper(void);
432asm( ".pushsection .text\n"
433" .align\n"
434" .type kernel_thread_helper, #function\n"
435"kernel_thread_helper:\n"
436#ifdef CONFIG_TRACE_IRQFLAGS
437" bl trace_hardirqs_on\n"
438#endif
439" msr cpsr_c, r7\n"
440" mov r0, r4\n"
441" mov lr, r6\n"
442" mov pc, r5\n"
443" .size kernel_thread_helper, . - kernel_thread_helper\n"
444" .popsection");
445
446#ifdef CONFIG_ARM_UNWIND
447extern void kernel_thread_exit(long code);
448asm( ".pushsection .text\n"
449" .align\n"
450" .type kernel_thread_exit, #function\n"
451"kernel_thread_exit:\n"
452" .fnstart\n"
453" .cantunwind\n"
454" bl do_exit\n"
455" nop\n"
456" .fnend\n"
457" .size kernel_thread_exit, . - kernel_thread_exit\n"
458" .popsection");
459#else
460#define kernel_thread_exit do_exit
461#endif
462
463/*
464 * Create a kernel thread.
465 */
466pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
467{
468 struct pt_regs regs;
469
470 memset(&regs, 0, sizeof(regs));
471
472 regs.ARM_r4 = (unsigned long)arg;
473 regs.ARM_r5 = (unsigned long)fn;
474 regs.ARM_r6 = (unsigned long)kernel_thread_exit;
475 regs.ARM_r7 = SVC_MODE | PSR_ENDSTATE | PSR_ISETSTATE;
476 regs.ARM_pc = (unsigned long)kernel_thread_helper;
477 regs.ARM_cpsr = regs.ARM_r7 | PSR_I_BIT;
478
479 return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
480}
481EXPORT_SYMBOL(kernel_thread);
482
483unsigned long get_wchan(struct task_struct *p) 434unsigned long get_wchan(struct task_struct *p)
484{ 435{
485 struct stackframe frame; 436 struct stackframe frame;