/* * 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; }
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; }