int copy_thread()

in kernel/process.c [152:202]


int copy_thread(unsigned long clone_flags, unsigned long stack_start,
		unsigned long stk_sz, struct task_struct *p, unsigned long tls)
{
	struct pt_regs *childregs = task_pt_regs(p);

	memset(&p->thread.cpu_context, 0, sizeof(struct cpu_context));

	if (unlikely(p->flags & (PF_KTHREAD | PF_IO_WORKER))) {
		memset(childregs, 0, sizeof(struct pt_regs));
		/* kernel thread fn */
		p->thread.cpu_context.r6 = stack_start;
		/* kernel thread argument */
		p->thread.cpu_context.r7 = stk_sz;
	} else {
		*childregs = *current_pt_regs();
		if (stack_start)
			childregs->sp = stack_start;
		/* child get zero as ret. */
		childregs->uregs[0] = 0;
		childregs->osp = 0;
		if (clone_flags & CLONE_SETTLS)
			childregs->uregs[25] = tls;
	}
	/* cpu context switching  */
	p->thread.cpu_context.pc = (unsigned long)ret_from_fork;
	p->thread.cpu_context.sp = (unsigned long)childregs;

#if IS_ENABLED(CONFIG_FPU)
	if (used_math()) {
# if !IS_ENABLED(CONFIG_LAZY_FPU)
		unlazy_fpu(current);
# else
		preempt_disable();
		if (last_task_used_math == current)
			save_fpu(current);
		preempt_enable();
# endif
		p->thread.fpu = current->thread.fpu;
		clear_fpu(task_pt_regs(p));
		set_stopped_child_used_math(p);
	}
#endif

#ifdef CONFIG_HWZOL
	childregs->lb = 0;
	childregs->le = 0;
	childregs->lc = 0;
#endif

	return 0;
}