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

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

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.系统调用号定义于

3.系统调用必须被编译进内核映像(不能编译为模块)

建立新的系统调用的利与弊:

利:系统调用创建容易且使用方便

Linux系统调用高性能

弊:需要一个系统调用号,由官方分配

系统调用加入稳定内核后被固化,它的接口不允许改动

需要将系统调用分别注册到每个需要支持的结构体系去

在脚本中不容易调用,也不能从文件系统直接访问系统调用

在主内核树之外很难维护和调用系统调用

你可能感兴趣的:(Linux,系统,系统调用)