Linux系统调用初始化:
在start_kernel()中调用trap_init(),设置中断向量表。
#define SYSCALL_VECTOR 0x80
set_system_gate (SYSCALL_VECTOR, &system_call) ; //当系统遇到INT80H中断时,即CPU跳转到相应中断服务程序,&system_call为中断服务程序入口地址
系统调用号如下
#define __NR_exit 1
#define __NR_fork 2
......
#define __NR_open 5
......
#define __NR_socketcall 102
......
系统表用表如下
.data
ENTRY (sys_call_table)
.long SYMBOL_NAME(sys_ni_syscall) //0
.long SYMBOL_NAME(sys_exit) //1
.long SYMBOL_NAME(sys_fork) //2
.......
.long SYMBOL_NAME(sys_open) //5
......
.long SYMBOL_NAME(sys_socketcall) //102
......
宏命令展开函数,一共6个,用于系统调用格式转换和参数传递
#define _syscall1(type, name, type1, arg1)\
type name(type arg1)\
{\
long __res;\
__asm_volatile("int $0x80"\
: "=a" (__res) \
: "0" (__NR_# #name), "b" ((long)(arg1)));\
__syscall_return(type, __res);\
}
#define _syscall2(type, name, type1, arg1, type2,arg2)\
......
#define _syscall6(type, name, type1, arg1, type2, arg2, type3,arg3, type4, arg4, type5, arg5, type6, arg6)
软中断INT80H代码
ENTRY(system_call)
pushl %eax
SAVE_ALL # 这两句为保存现场
GET_CURRENT(%ebx) #得到进程的ask_struct
testb $ 0x02, tsk_ptrace(%ebx) # PT_TRACESYS
jne tracesys
cmpl $(NR_syscalls), %eax
jae badsys
call *SYMBOL_NAME(sys_call_table)( , % eax, 4)
movl %eax, EAX(%esp)
ENTRY(ret_from_sys_call)
...
ENTRY(ret_from_sys_call)
cli
cmpl $ 0,need_resched( %ebx)
jne reschedule
cmpl $0, sigpending( %ebx)
jne signal_return //有无信号量
restore_all:
RESTORE_ALL //恢复现场
ALIGEN
signal_return:
....
#define RESTORE_ALL
popl ......
......
iret;
系统调用过程:用户进程下执行系统调用命令->转换为_syscallN()展开的函数->执行INT80H软中断->查找系统调用表->找到执行对应内核函数->进入内核模式执行相关操作->ret_from_sys_call结束调用->恢复现场,回到用户进程
举例说明:
1. int open (char* filename, int flag, int mode)
2. 转换为_syscall3()展开的函数为 _syscall3(int, __NR_open, const char*, file, int, flag, int, mode) ,__NR_open变成系统调用号5,存入EAX,file、flag、mode依次存入EBX、ECX,EDX
3. 执行INT80H软中断,保护现场, call *SYMBOL_NAME(sys_call_table) (, %eax, 4)
4. 根据系统调用号5在系统调用表上找到对应内核函数 asmlinkage long sys_open (const char* file name, int flag, int mode)
5. CPU进入内核态,执行相关open操作
6. ret_from_sys_call返回到用户模式