システムコールハンドラ
input/output
- input:システムコール番号
- output:システムコール結果値(成功:0、失敗:-1)
システムコールハンドラであるsyscall()の動作手順。
- システムコールパラメタがユーザアドレスに存在するか確認し、存在すればパラメタをカーネルアドレスにコピー。
- パラメタを元に、システムコールを実装するカーネル関数を呼び出す。
- 処理結果をユーザプロセスに渡す。
システムコール呼び出し(ソフトウェア割り込み発生 → 特権モード切り替えが伴う)の引数がどう渡されるか、というところ。
- 特権モードが切り替わる際にスタックがカーネルスタックに切り替わると、システムコール呼びだし時にもスタックが切り替わることになる
- 従ってユーザーモードのスタックにシステムコールの引数を積んでも、カーネルからは直接それを取り出すことができない。
- そのため、システムコールへの引数はレジスタ経由で渡される
- eflags, cs, eip, ss, esp はハードウェアによって例外(割り込み) 発生時にカーネルスタック上に退避される
- system_call() および sysenter_entry() 関数は SAVE_ALL マクロにより汎用レジスタおよび gs, es, ds, ebp 等をカーネルスタックに積む
- システムコールへの引数は ebx、ecx、edx、esi、edi、ebp の 6 つのレジスタによって渡される、のでここからそれらの引数を取り出して処理する
- なお、Linux のシステムコールは int 0x80 のソフトウェア割り込みまたは sysenter 命令によって実現されており、コールゲートは使われていない
- またレジスタ経由で引数を渡すので、ゲートディスクリプタのコピーカウントも利用しない
- この方法でユーザーモードからの引数渡しを実現することで、システムコールハンドラをほかの例外ハンドラと同じような構造にできるという利点が得られる。
システムコール処理失敗時の動作。
- システムコールは処理結果の戻り値をレジスタEAXに残す。
- ライブラリ関数がレジスタEAXを参照し、その値をグローバル変数errnoにコピーし、EAXに-1の値を代入。
- ユーザプロセスはEAXに-1が入っていることを確認し、システムコールが失敗したことを確認する。その後、グローバル変数errnoを参照し、エラーの原因を把握する。
システムコールが失敗する原因は2つしかない。
- システムコールが割り込まれたから。
- システムコールが割り込まれた場合後のシステムコールの処理は2種類のみ。
- システムコールを強制終了する。
- システムコールを再開する。プログラムカウンタをシステムコールトラップを発生させた命令に設定しなおす。(以前のプログラムカウンタはシステムコール終了後の命令に設定されているため。)
- カーネル関数がエラーを検出したから。
最終更新:2008年09月12日 01:17