/*
 * Finish a fork operation, with process p2 nearly set up.
 * Copy and update the pcb and trap frame, making the child ready to run.
 * 
 * Rig the child's kernel stack so that it will start out in
 * proc_trampoline() and call child_return() with p2 as an
 * argument. This causes the newly-created child process to go
 * directly to user level with an apparent return value of 0 from
 * fork(), while the parent process returns normally.
 *
 * p1 is the process being forked; if p1 == &proc0, we are creating
 * a kernel thread, and the return path and argument are specified with
 * `func' and `arg'.
 *
 * If an alternate user-level stack is requested (with non-zero values
 * in both the stack and stacksize args), set up the user stack pointer
 * accordingly.
 */
void
cpu_lwp_fork(struct lwp *l1, struct lwp *l2, void *stack, size_t stacksize,
    void (*func)(void *), void *arg)
{
	struct pcb *pcb1, *pcb2;
	struct trapframe *tf;

	pcb1 = lwp_getpcb(l1);
	pcb2 = lwp_getpcb(l2);

	/* Copy pcb from lwp l1 to l2. */
	if (l1 == curlwp) {
		/* Sync the PCB before we copy it. */
		savectx(pcb1);
#if 0
		/* ia64_highfp_save(???); */
#endif
	} else {
		KASSERT(l1 == &lwp0);
	}

	*pcb2 = *pcb1;

	l2->l_md.md_flags = l1->l_md.md_flags;
	l2->l_md.md_tf = (struct trapframe *)(uvm_lwp_getuarea(l2) + USPACE) - 1;
	l2->l_md.md_astpending = 0;

        /*
	 * Copy the trapframe.
	 */
	tf = l2->l_md.md_tf;
	*tf = *l1->l_md.md_tf;

        /*
	 * If specified, give the child a different stack.
	 */
	if (stack != NULL)
		tf->tf_special.sp = (unsigned long)stack + stacksize;

	/* Set-up the return values as expected by the fork() libc stub. */
	if (tf->tf_special.psr & IA64_PSR_IS) {
		tf->tf_scratch.gr8 = 0;
		tf->tf_scratch.gr10 = 1;
	} else {
		tf->tf_scratch.gr8 = 0;
		tf->tf_scratch.gr9 = 1;
		tf->tf_scratch.gr10 = 0;
	}

	tf->tf_scratch.gr2 = (unsigned long)FDESC_FUNC(func);
	tf->tf_scratch.gr3 = (unsigned long)arg;
	pcb2->pcb_special.sp = (unsigned long)tf - 16;
	pcb2->pcb_special.rp = (unsigned long)FDESC_FUNC(lwp_trampoline);
	pcb2->pcb_special.pfs = 0;

	return;
}
Exemplo n.º 2
0
void
cpu_set_upcall(struct thread *td, struct thread *td0)
{
	struct pcb *pcb;
	struct trapframe *tf;

	ia64_highfp_save(td0);

	tf = td->td_frame;
	KASSERT(tf != NULL, ("foo"));
	bcopy(td0->td_frame, tf, sizeof(*tf));
	tf->tf_length = sizeof(struct trapframe);
	tf->tf_flags = FRAME_SYSCALL;
	tf->tf_special.ndirty = 0;
	tf->tf_special.bspstore &= ~0x1ffUL;
	tf->tf_scratch.gr8 = 0;
	tf->tf_scratch.gr9 = 1;
	tf->tf_scratch.gr10 = 0;

	pcb = td->td_pcb;
	KASSERT(pcb != NULL, ("foo"));
	bcopy(td0->td_pcb, pcb, sizeof(*pcb));
	pcb->pcb_special.bspstore = td->td_kstack;
	pcb->pcb_special.pfs = 0;
	pcb->pcb_current_pmap = vmspace_pmap(td->td_proc->p_vmspace);
	pcb->pcb_special.sp = (uintptr_t)tf - 16;
	pcb->pcb_special.rp = FDESC_FUNC(fork_trampoline);
	cpu_set_fork_handler(td, (void (*)(void*))fork_return, td);

	/* Setup to release the spin count in fork_exit(). */
	td->td_md.md_spinlock_count = 1;
	td->td_md.md_saved_intr = 1;
}