系统调用--学习总结

来源:互联网 发布:对网络交友的看法 编辑:程序博客网 时间:2024/04/28 11:57

linux内核设计和实现–系统调用学习总结

过程

应用程序(用户空间)经常会使用系统调用来和内核通信,其主要目的是访问(或读或写)只有内核能直接管理的资源,比如读取文件。之所以这些资源只允许内核调用分配,主要有三个原因:一,系统调用为用户空间提供了一种硬件的抽象接口,而不需要关系底层是哪种硬件系统、哪种文件系统、磁盘介质等;二,保证系统的稳定和安全,内核可以根据权限、用户类型和一些规则对需要进行访问进行裁决,避免应用程序错误的使用硬件设备,甚至危害到系统;三,方便多应用进程并行管理,保证各个进程能正确使用系统资源,避免不同进程对同一个资源访问、修改导致相互干扰。

应用程序在调用系统调用时,陷入内核态执行对应的函数,此时应用程序被称作通过系统调用在内核空间运行,而内核被称作允许于进程上下文(还有个中断上下文);

每个系统调用对应一个系统调用号,系统调用号一旦分配就不能修改,系统调用号和系统调用是一一对应的,应用程序调用系统调用时,也是通过系统调用号映射到对应的系统调用执行函数;系统调用号存储在sys_call_table表中;

系统调用函数实现在内核上,应用程序是无法直接执行内核代码;内核是在受保护的地址空间上运行(真实的物理内存段),应用程序是运行于虚拟内存地址上。因此,应用程序通过软中断的方法告知内核执行对应的系统调用,并返回结果。通过触发一个异常使系统切换到内核态去处理异常处理程序(软中断处理函数),该处理程序实际就是系统调用处理程序system_call().

陷入内核态,还需要把系统调用号传给内核(后续还有系统调用的参数也需要传入内核);X86上,通过eax寄存器传入内核(各个参数也是通过各种寄存器传入内核,甚至系统调用的返回值也是通过寄存器返回到应用空间)。

实现

一。参数检查
应用进程再调用系统调用时,各参数通过各种寄存器(ebx\ecx\edx\esi\edi)传入内核,内核需要验证参数的合法性;其中最重要的是传入的指针是否有效,检查包括:1.指针指向的内存区域属于用户空间。进程运行于用户空间、虚拟的内存地址,且进程不能访问内核地址空间,因此,传入的指针指向的内存也不能是内核地址空间;2.指针指向的内存地址是该进程的地址空间,进程通过系统调用陷入内核态,内核必须保证传入的指针指向的内存是该进程的地址空间,而不是其他的进程的;3.指针指向的内存必须有对应操作的访问权限,如读操作,那么该内存必须要有可读权限,或写、执行等权限时,内存必须有对应的权限;

内核提供了两个方法来完成上述检查和内核空间与用户空间数据的来回拷贝:1.向用户空间写数据–copy_to_user(),有三个参数(类似memcpy),第一个参数是进程空间中的目的内存地址,第二个参数内核空间的源地址,最后一个是拷贝的长度;2.从用户空间读数据–copy_from_user(),类似copy_to_user(),只是参数位置换了。

2.系统调用上下文

内核在执行系统调用时,处于进程上下文。current指针(内核中进程调度的指针)指向当前任务,即引起系统调用的那个进程;
内核在进程上下文中,内核同样可以休眠(如在系统调用中阻塞或显示调用schedule()–进程调度(硬中断处理程序是不能休眠的)),并且也可以被抢占(可抢占式系统,进程调度被更高优先级的进程抢占);因此,有可能在执行某个系统调用时,系统被其他进程抢占,而新的进程可能执行相同的系统调用,所以必须保证系统调用是可重入的;

3.从用户空间访问系统调用

一般系统调用需要编译到libc库中,应用程序链接该库才能使用系统调用。除此之外,linux提供了一组宏,用户直接对系统调用进行访问。它会设置好寄存器并调用陷入指令—_syscalln(),其中n是0~6,表示系统调用参数个数;如open系统调用,不靠库支持,可以在应用程序中如下定义即可以直接使用

#define NR_open 5 /* 系统调用号 */_syscall3(long, open, const char*, filename, int flags, int, modes)

NR_open在《asm/unistd.h》中定义,是系统调用号该宏会被扩展成内嵌汇编的C函数;由汇编语言执行:将系统调用号和参数压入寄存器并触发软中断陷入内核态。

0 0
原创粉丝点击