システムコール
カーネルへの切り替えは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の引数参照規約で、ユーザプロセスから渡されて引数を参照することができるようになっています。
sys_call_tableは、処理関数のアドレスが番号順に設定されているテーブルです。サイズは4バイトです。従ってAXを4倍したsys_call_tableからのオフセットに目的とする処理があり、そこをコールすることで、AXコード(システムコール)が呼び出されるようになっています。
p/s
sys_call_tableに新規にテーブルを追加して、該当する処理を書けば、簡単にシステムコールを追加できそうです。
カーネルが起動すると、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に新規にテーブルを追加して、該当する処理を書けば、簡単にシステムコールを追加できそうです。