NetBSD-current /sbin/initが起動されるまで(1)
main()で一通りの初期化が終わって/sbin/initを起動する準備が整ったら、start_init()がfork()される:
if (fork1(l, 0, SIGCHLD, NULL, 0, start_init, NULL, NULL, &initproc)) panic("fork init");
start_init()の流れを順に見ていく。
/* * Now in process 1. */ strncpy(p->p_comm, "init", MAXCOMLEN);
proc構造体のプロセス名のフィールドにinitと書き込んでいる。
/* * Wait for main() to tell us that it's safe to exec. */ mutex_enter(proc_lock); while (start_init_exec == 0) cv_wait(&lbolt, proc_lock); mutex_exit(proc_lock);
main()がstart_init_execを1にするまで待つ。
一方、mainの最後には以下のようなコードがあってこれがstart_init_execを1にする:
/* * Okay, now we can let init(8) exec! It's off to userland! */ mutex_enter(proc_lock); start_init_exec = 1; cv_broadcast(&lbolt); mutex_exit(proc_lock);
ユーザプロセスのためのスタックをUVMから確保する。
/* * Need just enough stack to hold the faked-up "execve()" arguments. */ addr = (vaddr_t)STACK_ALLOC(USRSTACK, PAGE_SIZE); if (uvm_map(&p->p_vmspace->vm_map, &addr, PAGE_SIZE, NULL, UVM_UNKNOWN_OFFSET, 0, UVM_MAPFLAG(UVM_PROT_ALL, UVM_PROT_ALL, UVM_INH_COPY, UVM_ADV_NORMAL, UVM_FLAG_FIXED|UVM_FLAG_OVERLAY|UVM_FLAG_COPYONW)) != 0) panic("init: couldn't allocate argument space"); p->p_vmspace->vm_maxsaddr = (void *)STACK_MAX(addr, PAGE_SIZE);
boothowtoがinitのPATHを聞くようにしている時にプロンプトを出す処理。
if (boothowto & RB_ASKNAME) { printf("init path"); if (initpaths[ipx]) printf(" (default %s)", initpaths[ipx]); printf(": "); len = cngetsn(ipath, sizeof(ipath)-1); if (len == 0) { if (initpaths[ipx]) path = initpaths[ipx++]; else continue; } else { ipath[len] = '\0'; path = ipath; } } else { if ((path = initpaths[ipx++]) == NULL) break; }
ucpがさっきのスタックだ。
ucp = (char *)USRSTACK;
boothowtoを元に引数を作っている。
/* * Construct the boot flag argument. */ flagsp = flags; *flagsp++ = '-'; options = 0; if (boothowto & RB_SINGLE) { *flagsp++ = 's'; options = 1; }
さっきのスタックからメモリを確保して第一引数を積んでいる。
copyout()はカーネル→ユーザへのmemcpy()。
実際、memcpy()と何が違うんだろう・・・?
/* * Move out the flags (arg 1), if necessary. */ if (options != 0) { *flagsp++ = '\0'; i = flagsp - flags; #ifdef DEBUG printf("init: copying out flags `%s' %d\n", flags, i); #endif arg1 = STACK_ALLOC(ucp, i); ucp = STACK_MAX(arg1, i); (void)copyout((void *)flags, arg1, i); }
同様にファイル名もコピー。
/* * Move out the file name (also arg 0). */ i = strlen(path) + 1; #ifdef DEBUG printf("init: copying out path `%s' %d\n", path, i); #else if (boothowto & RB_ASKNAME || path != initpaths[0]) printf("init: trying %s\n", path); #endif arg0 = STACK_ALLOC(ucp, i); ucp = STACK_MAX(arg0, i); (void)copyout(path, arg0, i);
ファイル名、引数を構造体に詰めてexecveシステムコールに渡して一丁あがり。
/* * Move out the arg pointers. */ ucp = (void *)STACK_ALIGN(ucp, ALIGNBYTES); uap = (char **)STACK_ALLOC(ucp, sizeof(char *) * 3); SCARG(&args, path) = arg0; SCARG(&args, argp) = uap; SCARG(&args, envp) = NULL; slash = strrchr(path, '/'); if (slash) (void)suword((void *)uap++, (long)arg0 + (slash + 1 - path)); else (void)suword((void *)uap++, (long)arg0); if (options != 0) (void)suword((void *)uap++, (long)arg1); (void)suword((void *)uap++, 0); /* terminator */ /* * Now try to exec the program. If can't for any reason * other than it doesn't exist, complain. */ error = sys_execve(l, &args, retval); if (error == 0 || error == EJUSTRETURN) { KERNEL_UNLOCK_LAST(l); return; }
次はexecveについてみていこう。