示例#1
0
int copy_thread(unsigned long clone_flags,
		unsigned long usp, unsigned long stk_size,
		struct task_struct *p, struct pt_regs *regs)
{
	unsigned long child_tos = KSTK_TOS(p);
	struct pt_regs *childregs;

	if(!user_mode(regs)) {
		/* kernel thread */
		
		if(usp != 0)
			panic("trying to start kernel thread with usp != 0");

		/* childregs = full task switch frame on kernel stack of child */
		childregs = (struct pt_regs *)(child_tos) - 1;
		*childregs = *regs;

		childregs->r4 = 0;
		regs->r4 = p->pid;

		/* return via ret_from_fork */
		childregs->lkr = (unsigned long)ret_from_fork;

		/* setup ksp/usp */
		p->thread.ksp = (unsigned long)childregs - 4; /* perhaps not necessary */
		childregs->sp = p->thread.ksp;
		p->thread.usp = 0;
		p->thread.which_stack = 0; /* kernel stack */

		//printk("copy_thread1: ->pid=%d tsp=%lx r5=%lx p->thread.usp=%lx\n",
		//		p->pid, task_stack_page(p), childregs->r5, p->thread.ksp, p->thread.usp);
	} else {
		/* userspace thread (vfork, clone) */
		
		unsigned long ra_in_syscall;
		struct pt_regs* childsyscallregs;
	
		//asm volatile("break");

		/* this was brought to us by sys_tct_vfork in kernel/sys_tct.c */
		ra_in_syscall = regs->r1;

		/* childsyscallregs = full syscall frame on kernel stack of child */
		childsyscallregs = (struct pt_regs *)(child_tos) - 1;
		/* no need to return value here, it will be set by task switch frame */ 
		/* copy task switch frame, child shall return with the same register as parent entered the syscall except for return value of syscall */
		childregs = childsyscallregs - 1;
		
		/* child shall have same syscall context to restore as parent has */
		*childsyscallregs = *regs;

		regs->r4 = p->pid; /* parents get child's pid as the retval */
		
		/* user stack pointer is sharef with the parent per definition of vfork */
		p->thread.usp = usp;
		
		/* kernel stack pointer is not shared with parent, it is the beginning of the just created new task switch segment on the kernel itself */
		p->thread.ksp = (unsigned long)childregs - 4;
		p->thread.which_stack = 0; /* resume from ksp */

		/* child returns via ret_from_fork */
		childregs->lkr = (unsigned long)ret_from_fork;
		/* child shall return to where sys_vfork_wrapper has been called */
		childregs->r5 = ra_in_syscall;
		/* child gets zero as return value from syscall */
		childregs->r4 = 0;
		/* after task switch segment return the stack pointer shall point to the syscall frame */
		childregs->sp = (unsigned long)childsyscallregs - 4;
	
	}
	return 0;
}
示例#2
0
int copy_thread(unsigned long clone_flags,
		unsigned long usp, unsigned long stk_size,
		struct task_struct * p, struct pt_regs * regs)
{
	unsigned long child_tos = KSTK_TOS(p);
	struct pt_regs *childregs;

	if (!user_mode(regs)) {
		/* kernel thread */

		if( usp != 0 )
			panic("trying to start kernel thread with usp != 0");

		/* childregs = full task switch frame on kernel stack of child */
		childregs = (struct pt_regs *)(child_tos) - 1;
		*childregs = *regs;

		/* return via ret_from_fork */
		childregs->ra = (unsigned long)ret_from_fork;

		/* setup ksp/usp */
		p->thread.ksp = (unsigned long)childregs - 4; /* perhaps not necessary */
		childregs->sp = p->thread.ksp;
		p->thread.usp = 0;
		p->thread.which_stack = 0; /* kernel stack */

		//printk("copy_thread1: ->pid=%d tsp=%lx r5=%lx p->thread.ksp=%lx p->thread.usp=%lx\n",
		//		p->pid, task_stack_page(p), childregs->r5, p->thread.ksp, p->thread.usp);
	} else {
		/* userspace thread (vfork, clone) */

		struct pt_regs* childsyscallregs;

		/* childsyscallregs = full syscall frame on kernel stack of child */
		childsyscallregs = (struct pt_regs *)(child_tos) - 1; /* 32 = safety */
		/* child shall have same syscall context to restore as parent has ... */
		*childsyscallregs = *regs;

		/* childregs = full task switch frame on kernel stack of child below * childsyscallregs */
		childregs = childsyscallregs - 1;
		memset(childregs, 0, sizeof(childregs));

		/* user stack pointer is shared with the parent per definition of vfork */
		p->thread.usp = usp;

		/* kernel stack pointer is not shared with parent, it is the beginning of
		 * the just created new task switch segment on the kernel stack */
		p->thread.ksp = (unsigned long)childregs - 4;
		p->thread.which_stack = 0; /* resume from ksp */

		/* child returns via ret_from_fork */
		childregs->ra = (unsigned long)ret_from_fork;
		/* child shall return to where sys_vfork_wrapper has been called */
		childregs->r13 = (unsigned long)syscall_tail;
		/* child gets zero as return value from syscall */
		childregs->r11 = 0;
		/* after task switch segment return the stack pointer shall point to the
		 * syscall frame */
		childregs->sp = (unsigned long)childsyscallregs - 4;

		/*printk("copy_thread2: ->pid=%d p=%lx regs=%lx childregs=%lx r5=%lx ra=%lx "
				"dsf=%lx p->thread.ksp=%lx p->thread.usp=%lx\n",
				p->pid, p, regs, childregs, childregs->r5, childregs->ra,
				dup_syscallframe, p->thread.ksp, p->thread.usp);*/
	}

	return 0;
}