Linux内核-系统调用

Posted by keys961 on March 19, 2019

1. 与内核通信

系统调用是用户空间进程和硬件设备的中间层,作用:

  • 提供抽象接口
  • 保证系统稳定安全
  • 作为用户空间访问内核的唯一入口

2. 系统调用

如何定义系统调用:

  • 添加限定词asmlinkage(编译指令),通知编译器仅从栈中提取参数
  • 函数返回long,兼容32位和64位系统
  • 命名规则:以sys_开头

2.1. 系统调用号

每个系统调用的调用号唯一,一旦分配就不准变更,且删除系统调用的调用号不能回收利用

针对无效系统调用(填补空缺),有sys_ni_syscall(),仅返回-ENOSYS

注册的系统调用列表存在sys_call_table,x86-64定义于arch/i386/kernal/syscall_64.c中。

2.2. 系统调用性能

要比其它OS快且简洁,因此Linux上下文切换时间短。

3. 系统调用处理程序

用户空间不能直接访问和执行内核代码(内核空间受保护),因此使用软中断通知内核。

x86中,使用指令int $0x80(第128号中断程序),将系统切换到内核态,而该中断程序是系统调用处理程序。(程序在entry_64.S文件中编写)

3.1. 指定系统调用

x86上,系统调用号通过eax传递,检查通过后,调用:call *sys_call_table(, %rax, 8)

3.2. 参数传递

前5个参数用ebx,ecx,edx,esi,edi顺序存储,若参数过多,应指定一个寄存器作为指针,它指向存放参数的用户空间地址。

返回值也通过寄存器传递,x86是eax

4. 系统调用实现

可参考OS实验课

5. 系统调用上下文

内核执行系统调用式处于进程上下文current指向引发系统调用的进程。

由于Linux内核可抢占,因此执行系统调用时内核可以休眠且被抢占。因此编写系统调用一定要注意可重入

系统调用返回时,控制权仍在system_call()(系统调用入口函数),它会负责切换到用户空间并继续执行用户进程。