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

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

时间:11-09 来源:互联网 点击:

routine)(其唯一目的就是发布系统调用)。通常情况下,每个系统调用对应一个封装例程,而封装例程定义了应用程序使用的API。反之则不然,一个API没必要对应一个特定的系统调用。从编程者的观点看,API和系统调用之间的差别是没有关系的:唯一相关的事情就是函数名、参数类型及返回代码的含义。然而,从内核设计者的观点看,这种差别确实有关系,因为系统调用属于内核,而用户态的库函数不属于内核。

大部分封装例程返回一个整数,其值的含义依赖于相应的系统调用。返回-1通常表示内核不能满足进程的请求。系统调用处理程序的失败可能是由无效参数引起的,也可能是因为缺乏可用资源,或硬件出了问题等等。在libd库中定义的errno变量包含特定的出错码。每个出错码定义为一个常量宏。

当用户态的进程调用一个系统调用时,CPU切换到内核态并开始执行一个内核函数。因为内核实现了很多不同的系统调用,因此进程必须传递一个名为系统调用号(system call number)的参数来识别所需的系统调用。所有的系统调用都返回一个整数值。这些返回值与封装例程返回值的约定是不同的。在内核中,整数或0表示系统调用成功结束,而负数表示一个出错条件。在后一种情况下,这个值就是存放在errno变量中必须返回给应用程序的负出错码。

3 系统调用执行过程

ARM Linux系统利用SWI指令来从用户空间进入内核空间,还是先让我们了解下这个SWI指令吧。SWI指令用于产生软件中断,从而实现从用户模式变换到管理模式,CPSR保存到管理模式的SPSR,执行转移到SWI向量。在其他模式下也可使用SWI指令,处理器同样地切换到管理模式。指令格式如下:

SWI{cond} immed_24

其中:

immed_2424位立即数,值为从0——16215之间的整数。

使用SWI指令时,通常使用一下两种方法进行参数传递,SWI异常处理程序可以提供相关的服务,这两种方法均是用户软件协定。SWI异常中断处理程序要通过读取引起软件中断的SWI指令,以取得24为立即数。

1)、指令中24位的立即数指定了用户请求的服务类型,参数通过通用寄存器传递。如:

MOV R0,#34SWI 12

2)、指令中的24位立即数被忽略,用户请求的服务类型有寄存器R0的只决定,参数通过其他的通用寄存器传递。如:

MOV R0, #12MOV R1, #34SWI 0

在SWI异常处理程序中,去除SWI立即数的步骤为:首先确定一起软中断的SWI指令时ARM指令还是Thumb指令,这可通过对SPSR访问得到;然后取得该SWI指令的地址,这可通过访问LR寄存器得到;接着读出指令,分解出立即数(低24位)。

由用户空间进入系统调用

通常情况下,我们写的代码都是通过封装的C lib来调用系统调用的。以0.9.30版uClibc中的open为例,来追踪一下这个封装的函数是如何一步一步的调用系统调用的。在include/fcntl.h中有定义:

# define open open64

open实际上只是open64的一个别名而已。

在libc/sysdeps/linux/common/open64.c中可以看到:

extern __typeof(open64) __libc_open64;extern __typeof(open) __libc_open;

可见open64也只不过是__libc_open64的别名,而__libc_open64函数在同一个文件中定义:

libc_hidden_proto(__libc_open64)int __libc_open64 (const char *file, int oflag, ...){mode_t mode = 0;if (oflag & O_CREAT){va_list arg;va_start (arg, oflag);mode = va_arg (arg, mode_t);va_end (arg);}return __libc_open(file, oflag  O_LARGEFILE, mode);}libc_hidden_def(__libc_open64)

最终__libc_open64又调用了__libc_open函数,这个函数在文件libc/sysdeps/linux/common/open.c中定义:

libc_hidden_proto(__libc_open)int __libc_open(const char *file, int oflag, ...){mode_t mode = 0;if (oflag & O_CREAT) {va_list arg;va_start (arg, oflag);mode = va_arg (arg, mode_t);va_end (arg);}return __syscall_open(file, oflag, mode);}libc_hidden_def(__libc_open)

__syscall_open在同一个文件中定义:

static __inline__ _syscall3(int, __syscall_open, const char *, file, int, flags, __kernel_mode_t, mode)

在文件libc/sysdeps/linux/arm/bits/syscalls.h文件中可以看到:

#undef _syscall3#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \type name(type1 arg1,type2 arg2,type3 arg3) \{ \return (type) (INLINE_SYSCALL(name, 3, arg1, arg2, arg3)); \}

这个宏实际上完成定义一个函数的工作,这个宏的第一个参数是函数的返回值类型,第二个参数是函数名,之后的参数就如同它的参数名

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

网站地图

Top