void cpu_fork(struct proc *p1, struct proc *p2, void *stack, size_t stacksize, void (*func)(void *), void *arg) { struct pcb *pcbp; struct trapframe *tf; register_t sp, osp; #ifdef DIAGNOSTIC if (round_page(sizeof(struct user)) > NBPG) panic("USPACE too small for user"); #endif fpu_proc_save(p1); pcbp = &p2->p_addr->u_pcb; bcopy(&p1->p_addr->u_pcb, pcbp, sizeof(*pcbp)); /* space is cached for the copy{in,out}'s pleasure */ pcbp->pcb_space = p2->p_vmspace->vm_map.pmap->pm_space; pcbp->pcb_fpstate = pool_get(&hppa_fppl, PR_WAITOK); *pcbp->pcb_fpstate = *p1->p_addr->u_pcb.pcb_fpstate; /* reset any of the pending FPU exceptions from parent */ pcbp->pcb_fpstate->hfp_regs.fpr_regs[0] = HPPA_FPU_FORK(pcbp->pcb_fpstate->hfp_regs.fpr_regs[0]); pcbp->pcb_fpstate->hfp_regs.fpr_regs[1] = 0; pcbp->pcb_fpstate->hfp_regs.fpr_regs[2] = 0; pcbp->pcb_fpstate->hfp_regs.fpr_regs[3] = 0; p2->p_md.md_bpva = p1->p_md.md_bpva; p2->p_md.md_bpsave[0] = p1->p_md.md_bpsave[0]; p2->p_md.md_bpsave[1] = p1->p_md.md_bpsave[1]; sp = (register_t)p2->p_addr + NBPG; p2->p_md.md_regs = tf = (struct trapframe *)sp; sp += sizeof(struct trapframe); bcopy(p1->p_md.md_regs, tf, sizeof(*tf)); tf->tf_cr30 = (paddr_t)pcbp->pcb_fpstate; tf->tf_sr0 = tf->tf_sr1 = tf->tf_sr2 = tf->tf_sr3 = tf->tf_sr4 = tf->tf_sr5 = tf->tf_sr6 = tf->tf_iisq_head = tf->tf_iisq_tail = p2->p_vmspace->vm_map.pmap->pm_space; tf->tf_pidr1 = tf->tf_pidr2 = pmap_sid2pid(tf->tf_sr0); /* * theoretically these could be inherited from the father, * but just in case. */ tf->tf_sr7 = HPPA_SID_KERNEL; mfctl(CR_EIEM, tf->tf_eiem); tf->tf_ipsw = PSL_C | PSL_Q | PSL_P | PSL_D | PSL_I /* | PSL_L */ | (curcpu()->ci_psw & PSL_O); /* * If specified, give the child a different stack. */ if (stack != NULL) tf->tf_sp = (register_t)stack; /* * Build stack frames for the cpu_switchto & co. */ osp = sp + HPPA_FRAME_SIZE; *(register_t*)(osp - HPPA_FRAME_SIZE) = 0; *(register_t*)(osp + HPPA_FRAME_CRP) = (register_t)&switch_trampoline; *(register_t*)(osp) = (osp - HPPA_FRAME_SIZE); sp = osp + HPPA_FRAME_SIZE + 20*4; /* frame + calee-save registers */ *HPPA_FRAME_CARG(0, sp) = (register_t)arg; *HPPA_FRAME_CARG(1, sp) = KERNMODE(func); pcbp->pcb_ksp = sp; }
void cpu_fork(struct proc *p1, struct proc *p2, void *stack, size_t stacksize, void (*func)(void *), void *arg) { extern register_t switch_tramp_p; struct pcb *pcbp; struct trapframe *tf; register_t sp, osp; #ifdef DIAGNOSTIC if (round_page(sizeof(struct user) + sizeof(*tf)) > PAGE_SIZE) panic("USPACE too small for user"); #endif fpu_proc_save(p1); pcbp = &p2->p_addr->u_pcb; bcopy(&p1->p_addr->u_pcb, pcbp, sizeof(*pcbp)); /* space is cached for the copy{in,out}'s pleasure */ pcbp->pcb_space = p2->p_vmspace->vm_map.pmap->pm_space; pcbp->pcb_fpstate = pool_get(&hppa_fppl, PR_WAITOK); *pcbp->pcb_fpstate = *p1->p_addr->u_pcb.pcb_fpstate; /* reset any of the pending FPU exceptions from parent */ pcbp->pcb_fpstate->hfp_regs.fpr_regs[0] = HPPA_FPU_FORK(pcbp->pcb_fpstate->hfp_regs.fpr_regs[0]); pcbp->pcb_fpstate->hfp_regs.fpr_regs[1] = 0; pcbp->pcb_fpstate->hfp_regs.fpr_regs[2] = 0; pcbp->pcb_fpstate->hfp_regs.fpr_regs[3] = 0; sp = (register_t)p2->p_addr + PAGE_SIZE; p2->p_md.md_regs = tf = (struct trapframe *)sp; sp += sizeof(struct trapframe); bcopy(p1->p_md.md_regs, tf, sizeof(*tf)); tf->tf_vtop = (paddr_t)p2->p_vmspace->vm_map.pmap->pm_pdir; tf->tf_cr30 = (paddr_t)pcbp->pcb_fpstate; tf->tf_sr0 = tf->tf_sr1 = tf->tf_sr2 = tf->tf_sr3 = tf->tf_sr4 = tf->tf_sr5 = tf->tf_sr6 = tf->tf_iisq[0] = tf->tf_iisq[1] = p2->p_vmspace->vm_map.pmap->pm_space; tf->tf_pidr1 = tf->tf_pidr2 = pmap_sid2pid(tf->tf_sr0); /* * theoretically these could be inherited from the father, * but just in case. */ tf->tf_sr7 = HPPA_SID_KERNEL; tf->tf_eiem = mfctl(CR_EIEM); tf->tf_ipsw = PSL_C | PSL_Q | PSL_P | PSL_D | PSL_I /* | PSL_L */ | PSL_O | PSL_W; /* * If specified, give the child a different stack. */ if (stack != NULL) setstack(tf, (u_long)stack, 0); /* XXX ignore error? */ /* * Build stack frames for the cpu_switchto & co. */ osp = sp + HPPA_FRAME_SIZE; *(register_t*)(osp - HPPA_FRAME_SIZE) = 0; *(register_t*)(osp + HPPA_FRAME_RP) = switch_tramp_p; *(register_t*)(osp) = (osp - HPPA_FRAME_SIZE); sp = osp + HPPA_FRAME_SIZE + 20*8; /* frame + callee-saved registers */ *(register_t*)(sp - HPPA_FRAME_SIZE + 0) = (register_t)arg; *(register_t*)(sp - HPPA_FRAME_SIZE + 8) = KERNMODE(func); *(register_t*)(sp - HPPA_FRAME_SIZE + 16) = 0; /* cpl */ pcbp->pcb_ksp = sp; }