diff options
Diffstat (limited to 'arch/blackfin/kernel')
-rw-r--r-- | arch/blackfin/kernel/entry.S | 22 | ||||
-rw-r--r-- | arch/blackfin/kernel/process.c | 55 |
2 files changed, 25 insertions, 52 deletions
diff --git a/arch/blackfin/kernel/entry.S b/arch/blackfin/kernel/entry.S index f33792cc1a0d..78f4f637e155 100644 --- a/arch/blackfin/kernel/entry.S +++ b/arch/blackfin/kernel/entry.S @@ -46,22 +46,16 @@ ENTRY(_ret_from_fork) SP += -12; pseudo_long_call _schedule_tail, p5; SP += 12; - r0 = [sp + PT_IPEND]; - cc = bittst(r0,1); - if cc jump .Lin_kernel; + p1 = [sp++]; + r0 = [sp++]; + cc = p1 == 0; + if cc jump .Lfork; + sp += -12; + call (p1); + sp += 12; +.Lfork: RESTORE_CONTEXT rti; -.Lin_kernel: - bitclr(r0,1); - [sp + PT_IPEND] = r0; - /* do a 'fake' RTI by jumping to [RETI] - * to avoid clearing supervisor mode in child - */ - r0 = [sp + PT_PC]; - [sp + PT_P0] = r0; - - RESTORE_ALL_SYS - jump (p0); ENDPROC(_ret_from_fork) ENTRY(_sys_vfork) diff --git a/arch/blackfin/kernel/process.c b/arch/blackfin/kernel/process.c index bb1cc721fcf7..9945b94c63d4 100644 --- a/arch/blackfin/kernel/process.c +++ b/arch/blackfin/kernel/process.c @@ -102,40 +102,6 @@ void cpu_idle(void) } /* - * This gets run with P1 containing the - * function to call, and R1 containing - * the "args". Note P0 is clobbered on the way here. - */ -void kernel_thread_helper(void); -__asm__(".section .text\n" - ".align 4\n" - "_kernel_thread_helper:\n\t" - "\tsp += -12;\n\t" - "\tr0 = r1;\n\t" "\tcall (p1);\n\t" "\tcall _do_exit;\n" ".previous"); - -/* - * 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.r1 = (unsigned long)arg; - regs.p1 = (unsigned long)fn; - regs.pc = (unsigned long)kernel_thread_helper; - regs.orig_p0 = -1; - /* Set bit 2 to tell ret_from_fork we should be returning to kernel - mode. */ - regs.ipend = 0x8002; - __asm__ __volatile__("%0 = syscfg;":"=da"(regs.syscfg):); - return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, - NULL); -} -EXPORT_SYMBOL(kernel_thread); - -/* * Do necessary setup to start up a newly executed thread. * * pass the data segment into user programs if it exists, @@ -193,13 +159,26 @@ copy_thread(unsigned long clone_flags, struct task_struct *p, struct pt_regs *regs) { struct pt_regs *childregs; + unsigned long *v; childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1; - *childregs = *regs; - childregs->r0 = 0; + v = ((unsigned long *)childregs) - 2; + if (unlikely(!regs)) { + memset(childregs, 0, sizeof(struct pt_regs)); + v[0] = usp; + v[1] = topstk; + childregs->orig_p0 = -1; + childregs->ipend = 0x8000; + __asm__ __volatile__("%0 = syscfg;":"=da"(childregs->syscfg):); + p->thread.usp = 0; + } else { + *childregs = *regs; + childregs->r0 = 0; + p->thread.usp = usp; + v[0] = v[1] = 0; + } - p->thread.usp = usp; - p->thread.ksp = (unsigned long)childregs; + p->thread.ksp = (unsigned long)v; p->thread.pc = (unsigned long)ret_from_fork; return 0; |