プロセス1実行編⑦(システムコール) void syscall(void) (Xv6を読む~OSコードリーディング~)
前回
jupiteroak.hatenablog.com
トップページ
jupiteroak.hatenablog.com
syscall.c
https://github.com/mit-pdos/xv6-public/blob/master/syscall.c#L131
void syscall(void) { int num; struct proc *curproc = myproc(); num = curproc->tf->eax; if(num > 0 && num < NELEM(syscalls) && syscalls[num]) { curproc->tf->eax = syscalls[num](); } else { cprintf("%d %s: unknown sys call %d\n", curproc->pid, curproc->name, num); curproc->tf->eax = -1; } }
syscall関数は、eaxレジスタにセットされたシステムコール番号に対応するシステムコールを呼び出します。
処理の内容
struct proc *curproc = myproc();
システムコールを呼び出したプロセスに関連しているプロセスディスクリプタを取得します。
num = curproc->tf->eax;
カーネルスタックに退避させてあるハードウェアコンテキストからeaxレジスタの値を取得します。
eaxレジスタの値は、initcode.sで設定したシステムコール番号の値です。
if(num > 0 && num < NELEM(syscalls) && syscalls[num]) { curproc->tf->eax = syscalls[num]();
システムコール番号の値が1以上、かつ、システムコール番号の値が21以下、かつ、システムコール番号に対応する関数がsyscalls配列に用意されていることを確認します。syscalls配列は、戻り値int型・引数なしの関数ポインタの配列で、それぞれの要素にシステムコールに対応する関数が格納されています。
num > 0 && num < NELEM(syscalls) && syscalls[num] が真となる場合→システムコール番号の値が1以上、かつ、システムコール番号の値が21以下、かつ、システムコール番号に対応する関数がsyscalls配列に用意されている場合は、syscalls[num]を使ってシステムコールに対応する関数を呼び出します。
今回は、execシステムコールを呼び出しているので、num(eaxレジスタにセットされている値)は7(SYS_exec)となり、syscalls配列のインデックス7の要素であるsys_exec関数が呼び出されます。
また、システムコールに対応する関数の戻り値(システムコールの結果)はeaxレジスタにセットしなければならないので、システムコールに対応する関数の戻り値で、curproc->tf->eax(カーネルスタックに退避させてあるeaxレジスタの値)を更新します。
} else { cprintf("%d %s: unknown sys call %d\n", curproc->pid, curproc->name, num); curproc->tf->eax = -1; }
num > 0 && num < NELEM(syscalls) && syscalls[num] が偽となる場合→システムコール番号が不正な値の場合は、cprintf関数を呼び出してメッセージを出力し、システムコールの結果が失敗したことを示す-1で、curproc->tf->eax(カーネルスタックに退避させてあるeaxレジスタの値)を更新します。