システムコールを呼び出すには、syscall()を呼び出すのだが、xv6ではどのような方法を取っているのだろうか。
void syscall(void) { int num; num = proc−>tf−>eax; if(num > 0 && num < NELEM(syscalls) && syscalls[num]) { proc−>tf−>eax = syscalls[num](); } else { cprintf("%d %s: unknown sys call %d\n", proc−>pid, proc−>name, num); proc−>tf−>eax = −1; } }
procのtf->eaxにシステムコールの番号が入っている。それに従って、syscallテーブルを参照して、該当するテーブルを読み出している。
static int (*syscalls[])(void) = { [SYS_fork] sys_fork, [SYS_exit] sys_exit, [SYS_wait] sys_wait, [SYS_pipe] sys_pipe, [SYS_read] sys_read, [SYS_kill] sys_kill, [SYS_exec] sys_exec, [SYS_fstat] sys_fstat, [SYS_chdir] sys_chdir, [SYS_dup] sys_dup, [SYS_getpid] sys_getpid, [SYS_sbrk] sys_sbrk, [SYS_sleep] sys_sleep, [SYS_uptime] sys_uptime, [SYS_open] sys_open, [SYS_write] sys_write, [SYS_mknod] sys_mknod, [SYS_unlink] sys_unlink, [SYS_link] sys_link, [SYS_mkdir] sys_mkdir, [SYS_close] sys_close, };
では、tf->eaxを設定しているのは?それがトラップフレームだ。
// Layout of the trap frame built on the stack by the // hardware and by trapasm.S, and passed to trap(). struct trapframe { // registers as pushed by pusha uint edi; uint esi; uint ebp; uint oesp; // useless & ignored uint ebx; uint edx; uint ecx; uint eax; // rest of trap frame ushort gs; ushort padding1; ushort fs; ushort padding2; ushort es; ushort padding3; ushort ds; ushort padding4; uint trapno; // below here defined by x86 hardware uint err; uint eip; ushort cs; ushort padding5; uint eflags; // below here only when crossing rings, such as from user to kernel uint esp; ushort ss; ushort padding6; };
このトラップフレームを利用して、カーネルとユーザプロセスでやりとりを行っている。