微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > ARM Linux系统调用的原理

ARM Linux系统调用的原理

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

理程序一样,要做的第一件事当然就是保护现场了。紧接着是获得系统调用的系统调用号。然后以系统调用号作为索引来查找系统调用表,如果系统调用号正常的话,就会调用相应的处理例程来处理,就是上面的那个ldrcc pc, [tbl, scno, lsl #2]语句,然后通过例程ret_fast_syscall来返回。

在这个地方我们接着来讨论ABI的问题。现在,我们首先来看两个宏,一个是CONFIG_OABI_COMPAT 意思是说与old ABI兼容,另一个是CONFIG_AEABI 意思是说指定现在的方式为EABI。这两个宏可以同时配置,也可以都不配,也可以配置任何一种。我们来看一下内核是怎么处理这一问题的。我们知 道,sys_call_table 在内核中是个跳转表,这个表中存储的是一系列的函数指针,这些指针就是系统调用函数的指针,如(sys_open)。内核是根据一个系统调用号(对于 EABI来说为系统调用表的索引)找到实际该调用内核哪个函数,然后通过运行该函数完成系统调用的。

首先,对于old ABI,内核给出的处理是为它建立一个单独的system call table,叫sys_oabi_call_table。这样,兼容方式下就会有两个system call table, 以old ABI方式的系统调用会执行old_syscall_table表中的系统调用函数,EABI方式的系统调用会用sys_call_table中的函数指 针。
配置无外乎以下4中:
第一、两个宏都配置行为就是上面说的那样。
第二、只配置CONFIG_OABI_COMPAT,那么以oldABI方式调用的会用sys_oabi_call_table,以EABI方式调用的用sys_call_table,和1实质上是相同的。只是情况1更加明确。
第三、只配置CONFIG_AEABI系统中不存在sys_oabi_call_table,对old ABI方式调用不兼容。只能 以EABI方式调用,用sys_call_table。

第四、两个都没有配置,系统默认会只允许old ABI方式,但是不存在old_syscall_table,最终会通过sys_call_table 完成函数调用

系统会根据ABI的不同而将相应的系统调用表的基地址加载进tbl寄存器,也就是r8寄存器。接下来来看系统调用表,如前面所说的那样,有两个,同样都在文件arch/arm/kernel/entry-armv.S中:

#define ABI(native, compat) native

#ifdef CONFIG_AEABI

#define OBSOLETE(syscall)sys_ni_syscall

#else

#define OBSOLETE(syscall) syscall

#endif

.type sys_call_table, #object

ENTRY(sys_call_table)

#include "calls.S"

#undef ABI

#undef OBSOLETE

另外一个为:

#define ABI(native, compat) compat

#define OBSOLETE(syscall) syscall

.type sys_oabi_call_table, #object

ENTRY(sys_oabi_call_table)

#include "calls.S"

#undef ABI

#undef OBSOLETE

这样看来貌似两个系统调用表是完全一样的。这里预处理指令include的独特用法也挺有意思,系统调用表的内容就是整个arch/arm/kernel/calls.S文件的内容(由于太长,这里就不全部列出了):

/* 0 */ CALL(sys_restart_syscall)

CALL(sys_exit)

CALL(sys_fork_wrapper)

CALL(sys_read)

CALL(sys_write)

/* 5 */ CALL(sys_open)

CALL(sys_close)

……

上面的CALL()是个宏,它同样在文件arch/arm/kernel/entry-armv.S中定义:

#define CALL(x) .equNR_syscalls,NR_syscalls+1

#include "calls.S"

#undef CALL

#define CALL(x) .long x

在定义宏CALL()的地方,我们看到calls.S已经被包含了一次,只不过在这里,不是为了建立系统调用表,而仅仅是为了获得系统的系统调用的数量,并保存在宏NR_syscalls中。在SWI向量中,我们也看到,是使用了这个宏的。

最后再罗嗦一点,如果用sys_open来搜的话,是搜不到系统调用open的定义的,系统调用函数都是用宏来定义的,比如对于open,有这样的定义:

fs/open.c

1066 SYSCALL_DEFINE3(open, const char__user *, filename, int, flags, int, mode)

1067 {

1068 long ret;

1069

1070 if (force_o_largefile())

1071 flags = O_LARGEFILE;

1072

1073 ret = do_sys_open(AT_FDCWD, filename,flags, mode);

1074 /* avoid REGPARM breakage on x86: */

1075 asmlinkage_protect(3, ret, filename,flags, mode);

1076 return ret;

1077 }

继续回到vector_swi,如果系统调用号不正确,则会调用arm_syscall函数来进行处理,这个函数定义如下:

arch/arm/kernel/traps.c

465 #define NR(x) ((__ARM_NR_##x) -__ARM_NR_BASE)

466 asmlinkage int arm_syscall(int no,struct pt_regs *regs)

467 {

468struct thread_info *thread = current_thread_info();

469siginfo_t info;

470

471if ((no >> 16) != (__ARM_NR_BASE>> 16))

472 return bad_syscall(no, regs);

473

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

网站地图

Top