NetBSD-current /sbin/initが起動されるまで(5)
forkされたプロセスがどう動くのか見てみる。
コンテキストスイッチが起きると、mi_switch()が呼ばれる。
/* Pick new LWP to run. */ if (newl == NULL) { newl = nextlwp(ci, spc); }
nextlwp()によってforkされたプロセスが次のプロセス(newl)に選ばれる。
細かい処理を経て、最終的にアーキテクチャ依存のコンテキスト切り替え関数が呼ばれる。
/* Switch to the new LWP.. */
prevlwp = cpu_switchto(l, newl, returning);
cpu_switchto()はMIPSアーキテクチャではarch/mips/mips/locore.Sにある。
lw a0, L_ADDR(MIPS_CURLWP) move v0, s6 # Save return value REG_PROLOGUE REG_L t0, U_PCB_CONTEXT+SF_REG_SR(a0) DYNAMIC_STATUS_MASK(t0,ra) # machine dependent masking REG_L ra, U_PCB_CONTEXT+SF_REG_RA(a0) REG_L s0, U_PCB_CONTEXT+SF_REG_S0(a0) REG_L s1, U_PCB_CONTEXT+SF_REG_S1(a0) REG_L s2, U_PCB_CONTEXT+SF_REG_S2(a0) REG_L s3, U_PCB_CONTEXT+SF_REG_S3(a0) REG_L s4, U_PCB_CONTEXT+SF_REG_S4(a0) REG_L s5, U_PCB_CONTEXT+SF_REG_S5(a0) REG_L s6, U_PCB_CONTEXT+SF_REG_S6(a0) REG_L s7, U_PCB_CONTEXT+SF_REG_S7(a0) REG_L sp, U_PCB_CONTEXT+SF_REG_SP(a0) REG_L s8, U_PCB_CONTEXT+SF_REG_S8(a0) REG_EPILOGUE mtc0 t0, MIPS_COP_0_STATUS COP0_SYNC j ra nop END(cpu_switchto)
単にコンテキストスイッチをやって、最後にはraへジャンプする。
cpu_lwp_fork()では、RAにlwp_trampolineのアドレスを設定していた。
なので、lwp_trampolineが実行されるはずだから、次はlwp_trampolineを見てみる。
/* * mipsN_lwp_trampoline() * * Arrange for a function to be invoked neatly, after a cpu_switch(). * Call the service function with one argument, specified by the s0 * and s1 respectively. There is no need register save operation. */ LEAF(MIPSX(lwp_trampoline)) addu sp, sp, -CALLFRAME_SIZ # Call lwp_startup(), with args from cpu_switchto()/cpu_setfunc() la t0, _C_LABEL(lwp_startup) move a0, v0 jal ra, t0 move a1, s7
a0 = v0, a1 = s7を代入してlwp_startupを起動している。
cpu_lwp_fork()でs7にl2を設定していたのは確かなのだが、v0にl1を設定したのはどこでなのだろうか?
(
/* * Called by MD code when a new LWP begins execution. Must be called * with the previous LWP locked (so at splsched), or if there is no * previous LWP, at splsched. */ void lwp_startup(struct lwp *prev, struct lwp *new) { KASSERT(kpreempt_disabled()); if (prev != NULL) { /* * Normalize the count of the spin-mutexes, it was * increased in mi_switch(). Unmark the state of * context switch - it is finished for previous LWP. */ curcpu()->ci_mtx_count++; membar_exit(); prev->l_ctxswtch = 0; } KPREEMPT_DISABLE(new); spl0(); pmap_activate(new); LOCKDEBUG_BARRIER(NULL, 0); KPREEMPT_ENABLE(new); if ((new->l_pflag & LP_MPSAFE) == 0) { KERNEL_LOCK(1, new); } }
良くわからないがロック周りの処理に見える。
# Call the routine specified by cpu_setfunc() jal ra, s0 move a0, s1
cpu_lwp_fork()で指定されたfuncを実行している。
終わるとここに戻ってくる。
# # Return to user (won't happen if a kernel thread) # # Make sure to disable interrupts here, as otherwise # we can take an interrupt *after* EXL is set, and # end up returning to a bogus PC since the PC is not # saved if EXL=1. # .set noat mtc0 zero, MIPS_COP_0_STATUS # disable int COP0_SYNC nop # 3 op delay nop nop li a0, MIPS_SR_EXL # set exception level mtc0 a0, MIPS_COP_0_STATUS COP0_SYNC nop nop move a1, sp addu a1, sp, CALLFRAME_SIZ # REG_L a0, FRAME_SR(a1) REG_L t0, FRAME_MULLO(a1) REG_L t1, FRAME_MULHI(a1) REG_L v0, FRAME_EPC(a1) mtlo t0 mthi t1 _MTC0 v0, MIPS_COP_0_EXC_PC COP0_SYNC nop move k1, a1 #ifdef IPL_ICU_MASK .set at lw t0, FRAME_PPL(k1) sw t0, _C_LABEL(md_imask) jal _C_LABEL(md_imask_update) nop .set noat #endif REG_L AT, FRAME_AST(k1) REG_L v0, FRAME_V0(k1) REG_L v1, FRAME_V1(k1) REG_L a0, FRAME_A0(k1) REG_L a1, FRAME_A1(k1) REG_L a2, FRAME_A2(k1) REG_L a3, FRAME_A3(k1) REG_L t0, FRAME_T0(k1) REG_L t1, FRAME_T1(k1) REG_L t2, FRAME_T2(k1) REG_L t3, FRAME_T3(k1) REG_L ta0, FRAME_TA0(k1) REG_L ta1, FRAME_TA1(k1) REG_L ta2, FRAME_TA2(k1) REG_L ta3, FRAME_TA3(k1) REG_L s0, FRAME_S0(k1) REG_L s1, FRAME_S1(k1) REG_L s2, FRAME_S2(k1) REG_L s3, FRAME_S3(k1) REG_L s4, FRAME_S4(k1) REG_L s5, FRAME_S5(k1) REG_L s6, FRAME_S6(k1) REG_L s7, FRAME_S7(k1) REG_L t8, FRAME_T8(k1) REG_L t9, FRAME_T9(k1) REG_L k0, FRAME_SR(k1) DYNAMIC_STATUS_MASK(k0, sp) # machine dependent masking REG_L gp, FRAME_GP(k1) REG_L s8, FRAME_S8(k1) REG_L ra, FRAME_RA(k1) REG_L sp, FRAME_SP(k1) mtc0 k0, MIPS_COP_0_STATUS COP0_SYNC nop nop eret .set at END(MIPSX(lwp_trampoline))
スタックに積んであるフレームをリストアしてスイッチしている。
さて、このフレームには何が乗っているのか?
cpu_lwp_fork()を読み返してみると、親プロセスのPCBをスタックフレームにコピーしている。
という事は、fork()を呼んだ時点へ戻るはず。