/* * Copy architecture-specific thread state */ int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg, struct task_struct *p) { struct thread_info *ti = task_thread_info(p); struct hexagon_switch_stack *ss; struct pt_regs *childregs; asmlinkage void ret_from_fork(void); childregs = (struct pt_regs *) (((unsigned long) ti + THREAD_SIZE) - sizeof(*childregs)); ti->regs = childregs; /* * Establish kernel stack pointer and initial PC for new thread * Note that unlike the usual situation, we do not copy the * parent's callee-saved here; those are in pt_regs and whatever * we leave here will be overridden on return to userland. */ ss = (struct hexagon_switch_stack *) ((unsigned long) childregs - sizeof(*ss)); ss->lr = (unsigned long)ret_from_fork; p->thread.switch_sp = ss; if (unlikely(p->flags & PF_KTHREAD)) { memset(childregs, 0, sizeof(struct pt_regs)); /* r24 <- fn, r25 <- arg */ ss->r24 = usp; ss->r25 = arg; pt_set_kmode(childregs); return 0; } memcpy(childregs, current_pt_regs(), sizeof(*childregs)); ss->r2524 = 0; if (usp) pt_set_rte_sp(childregs, usp); /* Child sees zero return value */ childregs->r00 = 0; /* * The clone syscall has the C signature: * int [r0] clone(int flags [r0], * void *child_frame [r1], * void *parent_tid [r2], * void *child_tid [r3], * void *thread_control_block [r4]); * ugp is used to provide TLS support. */ if (clone_flags & CLONE_SETTLS) childregs->ugp = childregs->r04; /* * Parent sees new pid -- not necessary, not even possible at * this point in the fork process * Might also want to set things like ti->addr_limit */ return 0; }
int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) { struct pt_regs regs; memset(®s, 0, sizeof(regs)); /* * Yes, we're exploting illicit knowledge of the ABI here. */ regs.r00 = (unsigned long) arg; regs.r01 = (unsigned long) fn; pt_set_elr(®s, (unsigned long)kernel_thread_helper); pt_set_kmode(®s); return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); }