無料Wikiサービス | デモページ
検索

アクセス数
最近のコメント
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
はじめ - ノース
はじめ - ノース
はじめ - 楽打連動ユーザー
はじめ - 楽打連動ユーザー
Adsense
広告情報が設定されていません。

システムコール


カーネルへの切り替えはint 80またはsysenterによる方法とがあります。そしてその両方をサポートするためvsyscallというもので、int 80かsysenterを振り分ける仕組みを取り入れているそうです。ここではint 80の内容です。

カーネルが起動すると、trap_init関数からset_system_gate(SYSCALL_VECTOR, &system_call)で、ソフト割り込みint 0x80でsystem_callがコールされるよ設定します。すなわちユーザプロセスがint 0x80を実行すると、コードセグメントディスクリプターCSが__KERNEL_CSに切り替わり。特権レベル0であるカーネルモードとして実行できることになります。特権レベルとはCSの下位2ビットにより決定され、__KERNEL_CSでは0、__USER_CSでは3に設定されています。

カーネルモードモードに切り替わると、スタックも切り替わり、ユーザプロセスからスタック経由で渡された引数は、そのままでは参照できなくなります。従ってユーザプロセスのglibc内でint 80を発行する前に、ユーザスタックで渡された引数をレジスタにセットしなおして、int 80すなわち、system_callがコールされることになります。

レジスタはAXにファンクションコード、BX,CX,DX,SI,DIと続く引数がセットされます。

system_callではレジスタで渡された引数を、再度カーネルスタックにDI,SI,DX,CX,BX順にpushすることで、該当の処理関数へとコールします。従ってカーネルサイドの各処理関数はCの引数参照規約で、ユーザプロセスから渡されて引数を参照することができるようになっています。
ENTRY(system_call)
       RING0_INT_FRAME                 # can't unwind into user space anyway
       pushl %eax                      # save orig_eax
       CFI_ADJUST_CFA_OFFSET 4
       SAVE_ALL                       <- レジスター群をカーネルスタックにpush
       GET_THREAD_INFO(%ebp)
       testw $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)
       jnz syscall_trace_entry        <- straceされていればその処理
       cmpl $(nr_syscalls), %eax
       jae syscall_badsys
syscall_call:
       call *sys_call_table(,%eax,4)  <- AXコードに応じたシステム関数のコール
       movl %eax,PT_EAX(%esp)         <- 返り値をAXにセット
SAVE_ALLでレジスタ群をカーネルスタックに退避し、GET_THREAD_INFOでbpにthred_infoのポインタを取得し、そこからstraceされていないかチェックします。されていれば関数を呼び出す前に、syscall_trace_entryへジャンプしています。そこではsyscall_trace_entryの処理が終わるとsyscall_callにジャンプするようになっています。

sys_call_tableは、処理関数のアドレスが番号順に設定されているテーブルです。サイズは4バイトです。従ってAXを4倍したsys_call_tableからのオフセットに目的とする処理があり、そこをコールすることで、AXコード(システムコール)が呼び出されるようになっています。

p/s
sys_call_tableに新規にテーブルを追加して、該当する処理を書けば、簡単にシステムコールを追加できそうです。


最終更新 2010/03/23 16:03:34 - north
(2010/03/22 15:07:58 作成)