1*433d6423SLionel Sambuc /* The kernel call implemented in this file: 2*433d6423SLionel Sambuc * m_type: SYS_FORK 3*433d6423SLionel Sambuc * 4*433d6423SLionel Sambuc * The parameters for this kernel call are: 5*433d6423SLionel Sambuc * m_lsys_krn_sys_fork.endpt (parent, process that forked) 6*433d6423SLionel Sambuc * m_lsys_krn_sys_fork.slot (child's process table slot) 7*433d6423SLionel Sambuc * m_lsys_krn_sys_fork.flags (fork flags) 8*433d6423SLionel Sambuc * m_krn_lsys_sys_fork.endpt (endpoint of the child) 9*433d6423SLionel Sambuc * m_krn_lsys_sys_fork.msgaddr (new memory map for the child) 10*433d6423SLionel Sambuc */ 11*433d6423SLionel Sambuc 12*433d6423SLionel Sambuc #include "kernel/system.h" 13*433d6423SLionel Sambuc #include "kernel/vm.h" 14*433d6423SLionel Sambuc #include <signal.h> 15*433d6423SLionel Sambuc #include <string.h> 16*433d6423SLionel Sambuc #include <assert.h> 17*433d6423SLionel Sambuc 18*433d6423SLionel Sambuc #include <minix/endpoint.h> 19*433d6423SLionel Sambuc #include <minix/u64.h> 20*433d6423SLionel Sambuc 21*433d6423SLionel Sambuc #if USE_FORK 22*433d6423SLionel Sambuc 23*433d6423SLionel Sambuc /*===========================================================================* 24*433d6423SLionel Sambuc * do_fork * 25*433d6423SLionel Sambuc *===========================================================================*/ 26*433d6423SLionel Sambuc int do_fork(struct proc * caller, message * m_ptr) 27*433d6423SLionel Sambuc { 28*433d6423SLionel Sambuc /* Handle sys_fork(). 29*433d6423SLionel Sambuc * m_lsys_krn_sys_fork.endpt has forked. 30*433d6423SLionel Sambuc * The child is m_lsys_krn_sys_fork.slot. 31*433d6423SLionel Sambuc */ 32*433d6423SLionel Sambuc #if defined(__i386__) 33*433d6423SLionel Sambuc char *old_fpu_save_area_p; 34*433d6423SLionel Sambuc #endif 35*433d6423SLionel Sambuc register struct proc *rpc; /* child process pointer */ 36*433d6423SLionel Sambuc struct proc *rpp; /* parent process pointer */ 37*433d6423SLionel Sambuc int gen; 38*433d6423SLionel Sambuc int p_proc; 39*433d6423SLionel Sambuc int namelen; 40*433d6423SLionel Sambuc 41*433d6423SLionel Sambuc if(!isokendpt(m_ptr->m_lsys_krn_sys_fork.endpt, &p_proc)) 42*433d6423SLionel Sambuc return EINVAL; 43*433d6423SLionel Sambuc 44*433d6423SLionel Sambuc rpp = proc_addr(p_proc); 45*433d6423SLionel Sambuc rpc = proc_addr(m_ptr->m_lsys_krn_sys_fork.slot); 46*433d6423SLionel Sambuc if (isemptyp(rpp) || ! isemptyp(rpc)) return(EINVAL); 47*433d6423SLionel Sambuc 48*433d6423SLionel Sambuc assert(!(rpp->p_misc_flags & MF_DELIVERMSG)); 49*433d6423SLionel Sambuc 50*433d6423SLionel Sambuc /* needs to be receiving so we know where the message buffer is */ 51*433d6423SLionel Sambuc if(!RTS_ISSET(rpp, RTS_RECEIVING)) { 52*433d6423SLionel Sambuc printf("kernel: fork not done synchronously?\n"); 53*433d6423SLionel Sambuc return EINVAL; 54*433d6423SLionel Sambuc } 55*433d6423SLionel Sambuc 56*433d6423SLionel Sambuc /* make sure that the FPU context is saved in parent before copy */ 57*433d6423SLionel Sambuc save_fpu(rpp); 58*433d6423SLionel Sambuc /* Copy parent 'proc' struct to child. And reinitialize some fields. */ 59*433d6423SLionel Sambuc gen = _ENDPOINT_G(rpc->p_endpoint); 60*433d6423SLionel Sambuc #if defined(__i386__) 61*433d6423SLionel Sambuc old_fpu_save_area_p = rpc->p_seg.fpu_state; 62*433d6423SLionel Sambuc #endif 63*433d6423SLionel Sambuc *rpc = *rpp; /* copy 'proc' struct */ 64*433d6423SLionel Sambuc #if defined(__i386__) 65*433d6423SLionel Sambuc rpc->p_seg.fpu_state = old_fpu_save_area_p; 66*433d6423SLionel Sambuc if(proc_used_fpu(rpp)) 67*433d6423SLionel Sambuc memcpy(rpc->p_seg.fpu_state, rpp->p_seg.fpu_state, FPU_XFP_SIZE); 68*433d6423SLionel Sambuc #endif 69*433d6423SLionel Sambuc if(++gen >= _ENDPOINT_MAX_GENERATION) /* increase generation */ 70*433d6423SLionel Sambuc gen = 1; /* generation number wraparound */ 71*433d6423SLionel Sambuc rpc->p_nr = m_ptr->m_lsys_krn_sys_fork.slot; /* this was obliterated by copy */ 72*433d6423SLionel Sambuc rpc->p_endpoint = _ENDPOINT(gen, rpc->p_nr); /* new endpoint of slot */ 73*433d6423SLionel Sambuc 74*433d6423SLionel Sambuc rpc->p_reg.retreg = 0; /* child sees pid = 0 to know it is child */ 75*433d6423SLionel Sambuc rpc->p_user_time = 0; /* set all the accounting times to 0 */ 76*433d6423SLionel Sambuc rpc->p_sys_time = 0; 77*433d6423SLionel Sambuc 78*433d6423SLionel Sambuc rpc->p_misc_flags &= 79*433d6423SLionel Sambuc ~(MF_VIRT_TIMER | MF_PROF_TIMER | MF_SC_TRACE | MF_SPROF_SEEN | MF_STEP); 80*433d6423SLionel Sambuc rpc->p_virt_left = 0; /* disable, clear the process-virtual timers */ 81*433d6423SLionel Sambuc rpc->p_prof_left = 0; 82*433d6423SLionel Sambuc 83*433d6423SLionel Sambuc /* Mark process name as being a forked copy */ 84*433d6423SLionel Sambuc namelen = strlen(rpc->p_name); 85*433d6423SLionel Sambuc #define FORKSTR "*F" 86*433d6423SLionel Sambuc if(namelen+strlen(FORKSTR) < sizeof(rpc->p_name)) 87*433d6423SLionel Sambuc strcat(rpc->p_name, FORKSTR); 88*433d6423SLionel Sambuc 89*433d6423SLionel Sambuc /* the child process is not runnable until it's scheduled. */ 90*433d6423SLionel Sambuc RTS_SET(rpc, RTS_NO_QUANTUM); 91*433d6423SLionel Sambuc reset_proc_accounting(rpc); 92*433d6423SLionel Sambuc 93*433d6423SLionel Sambuc rpc->p_cpu_time_left = 0; 94*433d6423SLionel Sambuc rpc->p_cycles = 0; 95*433d6423SLionel Sambuc rpc->p_kcall_cycles = 0; 96*433d6423SLionel Sambuc rpc->p_kipc_cycles = 0; 97*433d6423SLionel Sambuc rpc->p_signal_received = 0; 98*433d6423SLionel Sambuc 99*433d6423SLionel Sambuc /* If the parent is a privileged process, take away the privileges from the 100*433d6423SLionel Sambuc * child process and inhibit it from running by setting the NO_PRIV flag. 101*433d6423SLionel Sambuc * The caller should explicitly set the new privileges before executing. 102*433d6423SLionel Sambuc */ 103*433d6423SLionel Sambuc if (priv(rpp)->s_flags & SYS_PROC) { 104*433d6423SLionel Sambuc rpc->p_priv = priv_addr(USER_PRIV_ID); 105*433d6423SLionel Sambuc rpc->p_rts_flags |= RTS_NO_PRIV; 106*433d6423SLionel Sambuc } 107*433d6423SLionel Sambuc 108*433d6423SLionel Sambuc /* Calculate endpoint identifier, so caller knows what it is. */ 109*433d6423SLionel Sambuc m_ptr->m_krn_lsys_sys_fork.endpt = rpc->p_endpoint; 110*433d6423SLionel Sambuc m_ptr->m_krn_lsys_sys_fork.msgaddr = rpp->p_delivermsg_vir; 111*433d6423SLionel Sambuc 112*433d6423SLionel Sambuc /* Don't schedule process in VM mode until it has a new pagetable. */ 113*433d6423SLionel Sambuc if(m_ptr->m_lsys_krn_sys_fork.flags & PFF_VMINHIBIT) { 114*433d6423SLionel Sambuc RTS_SET(rpc, RTS_VMINHIBIT); 115*433d6423SLionel Sambuc } 116*433d6423SLionel Sambuc 117*433d6423SLionel Sambuc /* 118*433d6423SLionel Sambuc * Only one in group should have RTS_SIGNALED, child doesn't inherit tracing. 119*433d6423SLionel Sambuc */ 120*433d6423SLionel Sambuc RTS_UNSET(rpc, (RTS_SIGNALED | RTS_SIG_PENDING | RTS_P_STOP)); 121*433d6423SLionel Sambuc (void) sigemptyset(&rpc->p_pending); 122*433d6423SLionel Sambuc 123*433d6423SLionel Sambuc #if defined(__i386__) 124*433d6423SLionel Sambuc rpc->p_seg.p_cr3 = 0; 125*433d6423SLionel Sambuc rpc->p_seg.p_cr3_v = NULL; 126*433d6423SLionel Sambuc #elif defined(__arm__) 127*433d6423SLionel Sambuc rpc->p_seg.p_ttbr = 0; 128*433d6423SLionel Sambuc rpc->p_seg.p_ttbr_v = NULL; 129*433d6423SLionel Sambuc #endif 130*433d6423SLionel Sambuc 131*433d6423SLionel Sambuc return OK; 132*433d6423SLionel Sambuc } 133*433d6423SLionel Sambuc 134*433d6423SLionel Sambuc #endif /* USE_FORK */ 135