法楽日記

デジタル散策記&マインド探訪記

FreeBSD 11.1R: システムコールのカーネル側の入口関数

FreeBSD 11.1R では、ユーザ空間でシステムコール xxx() が呼び出されると、カーネル空間にある sys_xxx() が呼び出されます。カーネル空間にある sys_xxx() は、必要に応じて引数をチェックしたりユーザ空間からデータをコピーしたりした後、kern_xxx() を呼び出して実処理をしてもらい、その後で必要に応じデータをユーザ空間にコピーして、最後にエラー番号を返します(エラーがないときはゼロを返します)。システムコール xxx() の引数は sys_xxx() の第2引数で構造体のメンバーとして渡されます。

これらの関数のソースコードは sys/kern 以下にありますので、grep などで探せばすぐに見つかります(例えば sys_socket() と kern_socket() は sys/kern/uipc_syscalls.c で定義されています)。また、sys_xxx() のプロトタイプ宣言と第2引数の構造体の宣言は sys/sys/sysproto.h で、kern_xxx() のプロトタイプ宣言は sys/sys/syscallsubr.h で行われています。エラー番号は sys/sys/errno.h で定義されています。

なお、カーネル空間にある sys_xxx() も kern_xxx() も慣習的にこのような名前がつけられているだけで、リンカーなどで特殊な処理をしている訳ではないようです。

ところで、ユーザ空間からカーネル空間に引数などをコピーするときは copyin() が、カーネル空間からユーザ空間に結果を返すときは copyout() が、それぞれ呼び出されます。実装は CPU ごとに行われていて(おそらく高速化のため)、例えば i386 用は sys/i386/i386/support.s で定義されています。