您的位置:首页 > 运维架构 > Linux

《Linux内核设计与实现》--系统调用

2016-09-21 15:09 141 查看
现在系统中,内核提供了用户进程与内核进行交互的一组接口,这些接口让应用受限访问硬件设备。实际上这些接口注意是为了保证系统稳定可靠,避免应用程序恣意妄行。

1、与内核通信

系统调用时在用户空间和硬件设备之间添加一个中间层:

1、为用户空间提供一个抽象接口

2、限制应用程序使用硬件设备权限,避免应用不正确的使用硬件资源

3、出于实现多任务和虚拟内存及系统稳定性和安全性

2、API、POSIX、C库

1、应用程序一般直接是API(应用编程接口)

2、API是以C库的形式提供给应用程序

3、C库一般是将内核函数进行封装

3、系统调用

内核必需提供系统调用所希望完成的功能,但它完全可以按照自己的方式去实现,只要最后结果正确
所有的系统调用都要asmlinkage限定词
为保证32/64位兼容,系统调用在用户空间返回值时int,内核空间为long
1.系统调用号:
在Linux中每个系统调用被赋予一个系统调用号
系统调用号一旦分配不可改变,否则编译好的应用会崩溃
Linux上有一个“未实现”的系统调用sys_ni_syscall(),它除了返回-ENOSYS外不做其他任何工作
如果一个系统调用被删除,或变的不可用,这个函数去填补空缺
2.系统调用的性能
Linux系统调用比其他操作系统要快,原因:
1.Linux很短的上下文切换时间
2.系统调用处理程序和每个系统调用非常简洁

4、系统调用处理程序

通知内核的机制靠软中断实现(中断号128 既int$0x80),通过引发异常来促使系统切换到内核态去执行异常处理程序(系统调用处理程序)
指定恰当的系统调用:
在x86上通过eax寄存器将系统调用号传递给内核
system_call()函数通过将给定的系统调用号与NR_syscalls()作比较来检查其有效性
参数传递:在x86-32系统上,ebx,ecx,edx,esi,edi按照顺序存放前五个参数
给用户空间的返回值通过eax寄存器传递(x86)
最近x86处理器增加了一条sysenter的指令int中断指令相比,更快更专业的陷入内核执行系统调用的方式

5、系统调用的实现

实现系统调用:
每个系统调用都有一个明确的用途
系统调用的接口力求简洁,参数尽可能少
设计接口的时候要尽量为将来多做考虑
参数验证:
系统调用必须验证他们所有的参数是否合法有效,最重要的检查时检查用户提供的指针是否有效
在接受一个用户空间的指针之前,内核必须保证:
1.指针指向的内存区域属于用户空间,进程决不能让内核去读取内核空间的数据
2.指针指向的内存区域在进程的地址空间,进程决不能让内核去读取其他进程的数据
3.如果是读,内存标记为可读;如果是写,标记为可写;如果标记为可执行,进程决不能绕过内存访问限制

6、系统调用上下文

绑定一个系统调用的最后步骤:
1.首先,在系统调用表的最后加入一个表项
2.系统调用号定义于<asm/unistd.h>中
3.系统调用必须被编译进内核映像(不能编译为模块)
建立新的系统调用的利与弊:
利:系统调用创建容易且使用方便
Linux系统调用高性能
弊:需要一个系统调用号,由官方分配
系统调用加入稳定内核后被固化,它的接口不允许改动
需要将系统调用分别注册到每个需要支持的结构体系去
在脚本中不容易调用,也不能从文件系统直接访问系统调用
在主内核树之外很难维护和调用系统调用
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  系统调用