设为首页 收藏本站
查看: 678|回复: 0

[经验分享] 基于linux-3.3内核的ARM异常处理之swi异常处理

[复制链接]

尚未签到

发表于 2015-12-9 16:05:49 | 显示全部楼层 |阅读模式
接前面两篇继续,这篇讲swi(software_interrupt,软中断)异常处理

在上一篇的源码中我们看到swi异常用的是ldr指令绝对跳转,其他异常用的是b指令相对跳转
   W(b)vector_und + stubs_offset
    W(ldr)pc, .LCvswi + stubs_offset
为什么会这样呢?
猜想因为swi的异常处理代码的入口并不在__stubs_start~~~__stubs_end之间,其他几种异常的处理代码都在
__stubs_start~~~__stubs_end之间,而相对跳转的寻址范围是正负32M

在之前讲系统调用那篇博文中,我们知道系统调用在glibc库的源码中最后会产生一个swi异常
处理器检测到这个异常会跳到异常向量表,接着会从异常向量表取出跳转指令(绝对跳转)执行:
W(ldr)pc, .LCvswi + stubs_offset

swi异常处理的入口在:

linux-3.3\arch\arm\kernel\entry-common.S 347行
ENTRY(vector_swi)
……
……
……
代码比较多,就不贴出来了,很多汇编自己也不会,根据代码和注释说一下这段代码的主要工作:

首先就是保存cpu现场,这样在执行了系统调用后,才能顺利恢复cpu用户态进程;
切换处理器工作模式。
获取系统调用号scno。
根据调用号在系统调用跳转表中索引出实际要执行的系统调用函数入口
ldrccpc, [tbl, scno, lsl #2]@ call sys_* routine
并进入执行;tbl中存放的即为系统调用跳转表起始地址,根据EABI,OABI配置的不同会有不同的跳转表
sys_call_table或sys_oabi_call_table,我们这里是前者。

ENTRY(sys_call_table)
#include "calls.S"
#undef ABI
#undef OBSOLETE

可以看到跳转表就是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实际是宏定义,在arch/arm/kernel/entry-common.S中,如下:
#define CALL(x) .equ NR_syscalls,NR_syscalls+1
#include "calls.S"
#undef CALL
#define CALL(x) .long x
在定义宏CALL()的地方,我们看到calls.S已经被包含了一次,只不过在这里,不是为了建立系统调用表,
而仅仅是为了获得系统的系统调用的数量,并保存在宏NR_syscalls中。在SWI异常处理中,我们也看到,
是使用了这个宏NR_syscalls来检查用户空间传进的调用号是否有效;

从上面我们可以看到最后有效的宏定义是#define CALL(x) .long x,前面的只是用来计算系统调用的
个数(用法很妙),因此CALL(sys_open)就是.long sys_open,也就是sys_open函数的入口地址,其他一样;

下面我们以open系统调用进行分析,其系统调用号存放在linux/arch/arm/include/asm/unistd.h
文件中,如下:

#if defined(__thumb__) || defined(__ARM_EABI__)
#define __NR_SYSCALL_BASE0
#else
#define __NR_SYSCALL_BASE__NR_OABI_SYSCALL_BASE
#endif

#define __NR_open(__NR_SYSCALL_BASE+  5)

但是,我们在内核源码中搜索sys_open时,并未找到其函数实例,只找到其系统调用原型如下:
/include/linux/syscalls.h  521行
asmlinkage long sys_open(const char __user *filename,
int flags, umode_t mode);

那么sys_open到底在哪里定义?
这里首先给出sys_open的定义,在\linux-3.3\fs\open.c中 997行
SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
{
long ret;

if (force_o_largefile())
flags |= O_LARGEFILE;

ret = do_sys_open(AT_FDCWD, filename, flags, mode);
/* avoid REGPARM breakage on x86: */
asmlinkage_protect(3, ret, filename, flags, mode);
return ret;
}

为什么sys_open函数会是上面的这个函数呢?

首先来解释一下SYSCALL_DEFINEx 中的x表示上层应用函数的参数个数,比如open()函数有3个参数,
因此会对应到SYSCALL_DEFINE3。
下面我们来分析SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)

SYSCALL_DEFINE3是个宏,定义在linux-3.3\include\linux\Syscalls.h  196行
#define SYSCALL_DEFINE1(name, ...) SYSCALL_DEFINEx(1, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE2(name, ...) SYSCALL_DEFINEx(2, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE4(name, ...) SYSCALL_DEFINEx(4, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE5(name, ...) SYSCALL_DEFINEx(5, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE6(name, ...) SYSCALL_DEFINEx(6, _##name, __VA_ARGS__)

继续分解 226行
#define SYSCALL_DEFINEx(x, sname, ...)\
__SYSCALL_DEFINEx(x, sname, __VA_ARGS__)

进一步分解  248行
#define __SYSCALL_DEFINEx(x, name, ...)\
asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__))

由此再分解为如下:
asmlinkage long sys####open(__SC_DECL##3(__VA_ARGS__))
即asmlinkage long sys_open(__SC_DECL3(__VA_ARGS__))

__SC_DECL3也是宏,它的作用就是分解出形参
#define __SC_DECL1(t1, a1)t1 a1
#define __SC_DECL2(t2, a2, ...) t2 a2, __SC_DECL1(__VA_ARGS__)
#define __SC_DECL3(t3, a3, ...) t3 a3, __SC_DECL2(__VA_ARGS__)
#define __SC_DECL4(t4, a4, ...) t4 a4, __SC_DECL3(__VA_ARGS__)
#define __SC_DECL5(t5, a5, ...) t5 a5, __SC_DECL4(__VA_ARGS__)
#define __SC_DECL6(t6, a6, ...) t6 a6, __SC_DECL5(__VA_ARGS__)

到这里已经很清楚了,SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
解析出来就是sys_open,open系统调用最后调用的就是它,然后它在调用do_sys_open。其他系统调用是一样的原理。

关于do_sys_open本篇暂不分析

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-148892-1-1.html 上篇帖子: 基于linux-3.3内核的ARM异常处理之irq异常处理 下篇帖子: linux驱动调试--段错误之栈信息分析
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表