我要投搞

标签云

收藏小站

爱尚经典语录、名言、句子、散文、日志、唯美图片

当前位置:小鱼儿玄机2站资料 > 平台调用 >

《ARM与Linux些许问题》第四章:ARM平台系统调用原理分析

归档日期:05-16       文本归类:平台调用      文章编辑:爱尚语录

  一、介绍系统调用Linux用户空间主动进入内核空间的唯一方法

  从逻辑上来说,系统调用可被看成是一个内核与用户空间程序交互的接口;把用户进程的请求传达给内核,待内核把请求处理完毕后再将处理结果送回给用户空间。

  2.系统调用按照功能逻辑大致可分为“进程控制”、“文件系统控制”、“系统控制”、“存储管理”、“网络管理”、“socket控制”、“用户管理”和“进程间通信”几类。

  1.控制硬件系统调用往往作为硬件资源和用户空间的抽象接口,比如读写文件时用到的write/read调用。

  2.设置系统状态或读取内核数据因为系统调用是用户空间和内核的唯一通讯手段,所以用户设置系统状态、比如开/关某项内核服务(设置某个内核变量)或读取内核数据都必须通过系统调用。比如getpid、getpriority、setpriority和sethostname等。

  3.进程管理系统调用接口用来保证系统中进程能以多任务在虚拟内存环境下运行。比如fork、clone、execve和exit等。

  1.系统调用并非直接和程序员或系统管理员打交道,它仅仅是一个通过软中断机制向内核提交请求、获取内核服务的接口。而在实际使用中程序员调用的多是用户编程接口api,而管理员使用的则多是系统命令。

  2.用户编程接口(API)其实是一个函数定义,说明了如何获得一个给定的服务,比如read()、malloc()、free()、abs()等。

  往往会出现几种不同的API内部用到同一个系统调用,比如malloc()、free()内部利用brk()系统调用来扩大或缩小进程的堆;

  更有些API甚至不需要任何系统调用,因为它不需要内核服务、如计算整数绝对值的abs()接口。

  说明:上述封装并非必须;如果你愿意直接调用,Linux提供了一个syscall()的系统调用函数来实现调用。

  系统调用是一层用户进入内核的接口,它本身并非内核函数;进入内核后,不同的系统调用会找到对应到各自的内核函数专业术语叫:系统调用服务例程。

  系统调用利用了ARM体系结构中的软件中断,软件中断和我们常说的中断(硬件中断)不同之处在于它是通过软件指令触发而并非外设,也就是说由编程人员发出的一种异常;具体地讲就是调用SWI汇编指令(x86上int $0x80),这条汇编指令将产生向量为128的编程异常,ARM从用户模式切入管理模式、并强制R15-PC(程序计数器)为0x0000 0008,Linux从用户态进入内核态。见:《ARM与Linux些许问题》第一章:ARM工作模式

  之所以系统调用需要借助异常实现;是因为当用户态的进程调用一个系统调用时,CPU便被切换到内核态执行内核函数。我们前边分析ARM体系结构部分已经讲过进入内核态ARM高特权模式,必须经过系统的门机制异常(SWI汇编指令(x86上int $0x80等);其他异常用户空间无法利用,都是由内核使用的。)。

  1.SWI汇编指令(x86上int $0x80)指令的目的是产生一个编号为128的编程异常,这个编程异常对应中断描述符表IDT中的第128项也就是对应的系统门描述符。门描述符中含有一个预设的内核空间地址,它指向了系统调用处理程序:vector_SWI()(x86上system_call())。注意:不是系统调用服务程序本身。

  2.所有的用户空间系统调用函数都是通过调用SWI汇编指令(x86上int $0x80)异常、进入内核态,此时、ARM默认从某一固定地址执行程序(vector_SWI()(x86上system_call())的地址)。vector_SWI()(x86上system_call())这个内核函数又怎样分发这些系统调用到各自的内核服务程序中呢?Linux为每个系统调用都进行了编号(0_NR_syscall);同时在内核中保存一张系统调用表,该表中保存了系统调用编号和其对应的服务例程。因此,在系统调用通过门陷入内核前,需要把系统调用号一并传入内核。这个传递工作是通过把系统调用号装入相应寄存器实现的。

  有了如上的分析:系统调用处理程序vector_SWI()(x86上system_call())一旦运行;就可以从相应寄存器中得到数据,然后再去系统调用表中寻找相应的服务例程了。

  注意:除了系统调用号之外,有的系统调用还需要传递一些参数给内核;这是Linux在vector_SWI()(x86上system_call())调用时将参数等值传入其他寄存器。

  内核系统服务例程结束时,system_call()从相应寄存器中获得系统调用返回值,并把这个返回值放在曾保存用户态相应寄存器栈单元的那个位置;然后跳转到ret_from_sys_call(),终止系统调用处理程序的执行。

本文链接:http://noh1.net/pingtaidiaoyong/56.html