微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > Arm Linux系统调用流程详细解析

Arm Linux系统调用流程详细解析

时间:11-09 来源:互联网 点击:
Linux系统通过向内核发出系统调用(system call)实现了用户态进程和硬件设备之间的大部分接口。

系统调用是操作系统提供的服务,用户程序通过各种系统调用,来引用内核提供的各种服务,系统调用的执行让用户程序陷入内核,该陷入动作由swi软中断完成。

1、用户可以通过两种方式使用系统调用:

第一种方式是通过C库函数,包括系统调用在C库中的封装函数和其他普通函数。

第二种方式是使用_syscall宏。2.6.18版本之前的内核,在include/asm-i386/unistd.h文件中定义有7个_syscall宏,分别是:

_syscall0(type,name)  _syscall1(type,name,type1,arg1)  _syscall2(type,name,type1,arg1,type2,arg2)  _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3)  _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4)  _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5)  _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5,type6,arg6) 

其中,type表示所生成系统调用的返回值类型,name表示该系统调用的名称,typeN、argN分别表示第N个参数的类型和名称,它们的数目和_syscall后面的数字一样大。

这些宏的作用是创建名为name的函数,_syscall后面跟的数字指明了该函数的参数的个数。

比如sysinfo系统调用用于获取系统总体统计信息,使用_syscall宏定义为:

_syscall1(int, sysinfo, struct sysinfo *, info); 

展开后的形式为:

int sysinfo(struct sysinfo * info)  {        long __res;        __asm__ volatile("int $0x80" : "=a" (__res) : "0" (116),"b" ((long)(info)));        do {              if ((unsigned long)(__res) >= (unsigned long)(-(128 + 1)))     {                    errno = -(__res);                    __res  = -1;              }              return (int) (__res);        } while (0);  } 

可以看出,_syscall1(int, sysinfo, struct sysinfo *, info)展开成一个名为sysinfo的函数,原参数int就是函数的返回类型,原参数struct sysinfo *和info分别构成新函数的参数。

在程序文件里使用_syscall宏定义需要的系统调用,就可以在接下来的代码中通过系统调用名称直接调用该系统调用。下面是一个使用sysinfo系统调用的实例。

代码清单5.1 sysinfo系统调用使用实例

#include  #include  #include          #include        /* for struct sysinfo */  _syscall1(int, sysinfo, struct sysinfo *, info);       int main(void)  {    struct sysinfo s_info;    int error;  error = sysinfo(&s_info);    printf("code error = %d/n", error);    printf("Uptime = %lds/nLoad:       1 min %lu / 5 min %lu / 15 min %lu/n"             "RAM: total %lu / free %lu / shared %lu/n"             "Memory in buffers = %lu/nSwap: total %lu / free %lu/n"          "Number of processes = %d/n",    s_info.uptime,       s_info.loads[0], s_info.loads[1], s_info.loads[2],               s_info.totalram, s_info.freeram,  s_info.sharedram, s_info.bufferram, s_info.totalswap, s_info.freeswap,              s_info.procs);      exit(EXIT_SUCCESS);       } 

但是自2.6.19版本开始,_syscall宏被废除,我们需要使用syscall函数,通过指定系统调用号和一组参数来调用系统调用。

syscall函数原型为:

int syscall(int number, ...); 

其中number是系统调用号,number后面应顺序接上该系统调用的所有参数。下面是gettid系统调用的调用实例。

代码清单5.2 gettid系统调用使用实例

#include  #include  #include  #define __NR_gettid      224  int main(int argc, char *argv[])  {       pid_t tid;  tid = syscall(__NR_gettid);  }

大部分系统调用都包括了一个SYS_符号常量来指定自己到系统调用号的映射,因此上面第10行可重写为:

tid = syscall(SYS_gettid);  

2 系统调用与应用编程接口(API)区别

应用编程接口(API)与系统调用的不同在于,前者只是一个函数定义,说明了如何获得一个给定的服务,而后者是通过软件中断向内核发出的一个明确的请求。POSIX标准针对API,而不针对系统调用。Unix系统给程序员提供了很多API库函数。libc的标准c库所定义的一些API引用了封装例程(wrapper

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top