3.1 系统调用
系统调用是受控的内核入口:
- 系统调用将CPU从用户态切换到内核态,以便CPU访问受保护的内核内存。
- 系统调用的组成是固定的,每个系统调用由一个唯一的数字标识。
- 每个系统调用可辅之以一套参数,对用户空间与内核空间之间传递的信息进行规范。
系统调用过程:
- 应用程序通过调用C语言函数库中的外壳函数(wrapper)来发起系统调用。
- 通过堆栈,参数传入外壳函数;内核希望参数置入特定寄存器,于是外壳函数将上述参数复制到寄存器。
- 内核要区分每个系统调用,为此,外壳函数将系统调用编号复制到
%eax
中。 - 外壳函数执行中断机器指令(
int 0x80
),印发处理器从用户端切换到内核态,并执行系统中断向量指向的代码。 为响应中断
0x80
,内核调用system_call()
例程(位于汇编文件arch/i386/entry.S
中)处理该中断:- 在内核中保存寄存器值;
- 审核系统调用编号的有效性;
- 以系统调用编号对存放所有调用服务例程的列表(内核变量
sys_call_table
)进行索引,发现并调用相应的例程; - 从内核栈中恢复各寄存器值,并将系统调用返回值置于栈中;
- 返回到外壳函数,同时处理器切换回用户态。
若系统调用的返回值有误,外壳函数会使用该值设置全局变量
errno
。然后外壳函数返回调用程序,并返回一个整形值,表明系统调用是否成功。