FreeBSD/sys/mips/mips/vm_machdep.c
/*
 * Finish a fork operation, with process p2 nearly set up.
 * Copy and update the pcb, set up the stack so that the child
 * ready to run and return to user mode.
 */
Finish a fork operation, with process p2 nearly set up.
Copy and update the pcb, set up the stack so that the child
ready to run and return to user mode.
Finish a fork operation with process p2 nearly set up . Copy and update the pcb set up the stack so that the child ready to run and return to user mode .
void
cpu_fork(register struct thread *td1,register struct proc *p2,
    struct thread *td2,int flags)
{
	register struct proc *p1;
	struct pcb *pcb2;
	p1 = td1->td_proc;
	if ((flags & RFPROC) == 0)
		return;
	pcb2 = td2->td_pcb;
	bcopy(td1->td_pcb, pcb2, sizeof(*pcb2));
	td2->td_md.md_flags = td1->td_md.md_flags & MDTD_FPUSED;
	td2->td_frame->v0 = 0;
	td2->td_frame->v1 = 1;
	td2->td_frame->a3 = 0;
	if (td1 == PCPU_GET(fpcurthread))
		MipsSaveCurFPState(td1);
	pcb2->pcb_context[PCB_REG_RA] = (register_t)(intptr_t)fork_trampoline;
	pcb2->pcb_context[PCB_REG_SP] = (register_t)(((vm_offset_t)td2->td_pcb &
	    ~(sizeof(__int64_t) - 1)) - CALLFRAME_SIZ);
	pcb2->pcb_context[PCB_REG_S0] = (register_t)(intptr_t)fork_return;
	pcb2->pcb_context[PCB_REG_S1] = (register_t)(intptr_t)td2;
	pcb2->pcb_context[PCB_REG_S2] = (register_t)(intptr_t)td2->td_frame;
	pcb2->pcb_context[PCB_REG_SR] = mips_rd_status() &
	    (MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_INT_MASK);
	td2->td_md.md_tls = td1->td_md.md_tls;
	td2->td_md.md_saved_intr = MIPS_SR_INT_IE;
	td2->td_md.md_spinlock_count = 1;
#ifdef CPU_CNMIPS
	if (td1->td_md.md_flags & MDTD_COP2USED) {
		if (td1->td_md.md_cop2owner == COP2_OWNER_USERLAND) {
			if (td1->td_md.md_ucop2)
				octeon_cop2_save(td1->td_md.md_ucop2);
			else
				panic("cpu_fork: ucop2 is NULL but COP2 is enabled");
		}
		else {
			if (td1->td_md.md_cop2)
				octeon_cop2_save(td1->td_md.md_cop2);
			else
				panic("cpu_fork: cop2 is NULL but COP2 is enabled");
		}
	}
	if (td1->td_md.md_cop2) {
		td2->td_md.md_cop2 = octeon_cop2_alloc_ctx();
		memcpy(td2->td_md.md_cop2, td1->td_md.md_cop2, 
			sizeof(*td1->td_md.md_cop2));
	}
	if (td1->td_md.md_ucop2) {
		td2->td_md.md_ucop2 = octeon_cop2_alloc_ctx();
		memcpy(td2->td_md.md_ucop2, td1->td_md.md_ucop2, 
			sizeof(*td1->td_md.md_ucop2));
	}
	td2->td_md.md_cop2owner = td1->td_md.md_cop2owner;
	pcb2->pcb_context[PCB_REG_SR] |= MIPS_SR_PX | MIPS_SR_UX | MIPS_SR_KX | MIPS_SR_SX;
	td2->td_frame->sr &= ~MIPS_SR_COP_2_BIT;
	pcb2->pcb_context[PCB_REG_SR] &= ~MIPS_SR_COP_2_BIT;
#endif
}
void cpu_fork ( register struct thread * td1 , register struct proc * p2 , struct thread * td2 , int flags ) { register struct proc * p1 ; struct pcb * pcb2 ; p1 = td1 -> td_proc ; if ( ( flags & RFPROC ) == 0 ) return ; pcb2 = td2 -> td_pcb ; bcopy ( td1 -> td_pcb , pcb2 , sizeof ( * pcb2 ) ) ; td2 -> td_md . md_flags = td1 -> td_md . md_flags & MDTD_FPUSED ; td2 -> td_frame -> v0 = 0 ; td2 -> td_frame -> v1 = 1 ; td2 -> td_frame -> a3 = 0 ; if ( td1 == PCPU_GET ( fpcurthread ) ) MipsSaveCurFPState ( td1 ) ; pcb2 -> pcb_context [ PCB_REG_RA ] = ( register_t ) ( intptr_t ) fork_trampoline ; pcb2 -> pcb_context [ PCB_REG_SP ] = ( register_t ) ( ( ( vm_offset_t ) td2 -> td_pcb & ~ ( sizeof ( __int64_t ) - 1 ) ) - CALLFRAME_SIZ ) ; pcb2 -> pcb_context [ PCB_REG_S0 ] = ( register_t ) ( intptr_t ) fork_return ; pcb2 -> pcb_context [ PCB_REG_S1 ] = ( register_t ) ( intptr_t ) td2 ; pcb2 -> pcb_context [ PCB_REG_S2 ] = ( register_t ) ( intptr_t ) td2 -> td_frame ; pcb2 -> pcb_context [ PCB_REG_SR ] = mips_rd_status ( ) & ( MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_INT_MASK ) ; td2 -> td_md . md_tls = td1 -> td_md . md_tls ; td2 -> td_md . md_saved_intr = MIPS_SR_INT_IE ; td2 -> td_md . md_spinlock_count = 1 ; #ifdef CPU_CNMIPS if ( td1 -> td_md . md_flags & MDTD_COP2USED ) { if ( td1 -> td_md . md_cop2owner == COP2_OWNER_USERLAND ) { if ( td1 -> td_md . md_ucop2 ) octeon_cop2_save ( td1 -> td_md . md_ucop2 ) ; else panic ( " " ) ; } else { if ( td1 -> td_md . md_cop2 ) octeon_cop2_save ( td1 -> td_md . md_cop2 ) ; else panic ( " " ) ; } } if ( td1 -> td_md . md_cop2 ) { td2 -> td_md . md_cop2 = octeon_cop2_alloc_ctx ( ) ; memcpy ( td2 -> td_md . md_cop2 , td1 -> td_md . md_cop2 , sizeof ( * td1 -> td_md . md_cop2 ) ) ; } if ( td1 -> td_md . md_ucop2 ) { td2 -> td_md . md_ucop2 = octeon_cop2_alloc_ctx ( ) ; memcpy ( td2 -> td_md . md_ucop2 , td1 -> td_md . md_ucop2 , sizeof ( * td1 -> td_md . md_ucop2 ) ) ; } td2 -> td_md . md_cop2owner = td1 -> td_md . md_cop2owner ; pcb2 -> pcb_context [ PCB_REG_SR ] |= MIPS_SR_PX | MIPS_SR_UX | MIPS_SR_KX | MIPS_SR_SX ; td2 -> td_frame -> sr &= ~ MIPS_SR_COP_2_BIT ; pcb2 -> pcb_context [ PCB_REG_SR ] &= ~ MIPS_SR_COP_2_BIT ; #endif }
Finish a fork operation, with process p2 nearly set up.
Finish a fork operation with process p2 nearly set up .
/* It is assumed that the vm_thread_alloc called
	 * cpu_thread_alloc() before cpu_fork is called.
	 */ /* Point the pcb to the top of the stack */ /* Copy p1's pcb, note that in this case
	 * our pcb also includes the td_frame being copied
	 * too. The older mips2 code did an additional copy
	 * of the td_frame, for us that's not needed any
	 * longer (this copy does them both) 
	 */ /* Point mdproc and then copy over td1's contents
	 * md_proc is empty for MIPS
	 */ /*
	 * Set up return-value registers as fork() libc stub expects.
	 */ /* Make sp 64-bit aligned */ /*
	 * FREEBSD_DEVELOPERS_FIXME:
	 * Setup any other CPU-Specific registers (Not MIPS Standard)
	 * and/or bits in other standard MIPS registers (if CPU-Specific)
	 *  that are needed.
	 */ /* Clear COP2 bits for userland & kernel */