init実行

久しぶりにxv6の処理を読んでいる。
コンパクトなコードでここまで処理を実装しているのは凄いの一言に尽きるが、特に気になったinitに関してメモ。

initcode.S(_binary_initcode_start)

    initcode.sは仮想アドレス0x00000000に配置されている。
    非常に単純なアセンブラ で記述されており、処理内容は以下の2つである。
    1. fs.img上のinitを実行(syscall exec)する。
    2. initcode自身を終了(sys call exit)する。

# exec(init, argv)
.globl start
start:
  pushl $argv
  pushl $init
  pushl $0  // where caller pc would be
  movl $SYS_exec, %eax
  int $T_SYSCALL

# for(;;) exit();
exit:
  movl $SYS_exit, %eax
  int $T_SYSCALL
  jmp exit

# char init = "/init\0";
init:
  .string "/init\0"

# char *argv = { init, 0 };
.p2align 2
argv:
  .long init
  .long 0
init.c(init)

    fork(sys call fork)を実行する。
    親プロセス側は子プロセスの終了待ち。
    子プロセス側はshell(sh.c)を実行する。

int
main(void)
{
  int pid, wpid;

  if(open("console", O_RDWR) < 0){
    mknod("console", 1, 1);
    open("console", O_RDWR);
  }
  dup(0);  // stdout
  dup(0);  // stderr

  for(;;){
    printf(1, "init: starting sh\n");
    pid = fork();
    if(pid < 0){
      printf(1, "init: fork failed\n");
      exit();
    }
    if(pid == 0){
      exec("sh", argv);
      printf(1, "init: exec sh failed\n");
      exit();
    }
    while*1 >= 0 && wpid != pid)
      printf(1, "zombie!\n");
  }
}

*1:wpid=wait(