PowerPC のシステムコールの仕組み
PowerPCのカーネルソース (/usr/src/linux/arch/ppc/kernel の head.S、entry.S、misc.S) を眺めてシステムコールの流れを追ってみました。
システムコールに伴う処理の流れの概要は次のようになっています。
sc命令 (ユーザプログラム、r0にシステムコール番号、r3-r7に引数) ↓ 0xC00 の割り込みベクタ (linux/arch/ppc/kernel/head.S) ↓ レジスタ退避 (lr,ctr,cr,r0-r12) transfer_to_handler (linux/arch/ppc/kernel/head.S) ↓ 飛び先:DoSyscall、戻り先:ret_from_exceptを指定 DoSyscall (linux/arch/ppc/kernel/entry.S) ↓ r0 と sys_call_table (misc.S) から飛び先を決定 システムコールを実行 ↓ sys_XXX を実行 (XXXはシステムコール名) ret_from_except (linux/arch/ppc/kernel/entry.S) レジスタ復帰 (lr,ctr,cr,r0-r12) ↓ 戻る (r3に結果)
- PowerPCのシステムコールは sc 命令で実行が開始されます。 sc 命令を実行する前にレジスタにシステムコール番号と引数を設定します。
- r0 : システムコール番号
- r3 : システムコールの第1引数
- r4 : システムコールの第2引数
- r5 : システムコールの第3引数
- r6 : システムコールの第4引数
- r7 : システムコールの第5引数
- sc 命令は直後の命令のアドレスをSRR0レジスタに格納して、0xC00番地に格納してあるシステムコール割り込みベクタに処理を移します。
- システムコール割り込みベクタではレジスタをカーネルスタックに退避した後、システムコールハンドラであるDoSyscallとret_from_exceptのアドレスが分岐命令の次にデータとして格納してある状態で transfer_to_handler を呼び出します。
- transfer_to_handlerは、DoSyscallに処理を移します。
- DoSyscallはシステムコール番号からテーブル(misc.S)を参照して、実際のシステムコール関数を呼び出します。実行結果またはエラー番号をr3に書き込みます。
- ret_from_except でレジスタを復帰して、システムコール直後の命令に戻ります。
システムコール自体は、名前に「sys_」がついたCの関数としてカーネルソース中に分散して書かれています。Cの関数は引数をレジスタで渡すようになっていて、 r3 以降に順に引数が格納されて呼び出され、結果は r3 に返ります。