Part12:内核异常(中断)处理体系结构(基于2.6.22.6内核)

1 异常处理体系结构
说到“异常”,得先理解Linux内核的异常有哪些,如下表所示

ARM架构内核中常见异常
异常的处理体系初始化由两个函数完成:trap_init() 和 init_IRQ()
因为中断是异常的一种,且不同板子的中断设置不同,因此有个单独的初始化函数init_IRQ()
下面先看看trap_init 如何完成“异常”的初始化,并搭建异常整个处理体系。
trap_init的主要工作就是复制“异常向量”到0xffff,0000 且复制异常向量的处理函数到0xffff,0000 + 0x200
trap_init
上面的vector_stubs是个宏,解释如下vector_stub宏解释

OK, 那分支表的处理函数怎样处理的呢?看下面的举例
__irq_usr
不同异常有对应的处理函数
备注:上图截取自韦东山老师的《嵌入式Linux应用开发完全手册》第20章

OK,最后梳理下ARM架构下的Linux内核异常处理体系结构,如下图

ARM架构Linux内核的异常处理体系结构

2 中断处理体系结构
好了,有了上面的理解,自然会想各异常对应的总入口函数究竟如何处理异常的?对吗
这里继续以“asm_do_IRQ”这个中断总入口函数为例,因为我们这里就要讲解“中断处理体系“”了呀

对于“中断处理体系结构”,必须清楚支撑/构成这一体系的三大结构体, 还是看图:)

中断处理体系结构的三大结构体
上面的中断处理流程真是这样吗? 跟进去看看
asm_do_IRQ
的确如此,但问题来了,谁初始化了irq_desc数组呢?即上面说到的那三个结构体呢?
还记得开头说的那句,中断处理体系因为跟开发板息息相关,因此抽象出中断处理的共性,用init_IRQ()进行初始化
现在看看init_IRQ如何初始化
init_IRQ最后,梳理下ARM架构的Linux内核中断处理体系结构,如下

ARM架构Linux内核的中断处理体系结构
中断处理流程如下:
(1)发生中断时,CPU执行异常向量vector_irq代码
(2)在vector_irq里面,最终会调用中断处理的总入口函数asm_do_IRQ
(3)asm_do_IRQ根据中断号调用irq_desc数组项中的handle_irq
(4)handle_irq会使用chip成员中的函数来设置硬件,比如清除中断、禁止中断、重新使能中断等
(5)handle_irq 逐个调用用户在action链表中注册的处理函数
可见,中断体系结构的初始化就是构造这些数据结构,比如irq_desc数组项中的handle_irq、chip等成员
用户注册中断时就是构造action链表;用户卸载中断时就是从action链表中去除不需要的项

3 编写中断相关的驱动
3.1 用户注册中断处理函数
有了前面对中断处理体系的理解,不难发现,要编写中断相关的驱动只需三步走,首先用户即驱动程序
通过request_irq函数向内核注册中断处理函数,request_irq函数根据中断号找到irq_desc数组项,然后在它的action
链表中添加一个表项。
request_irq函数原型如下
int request_irq(unsigned int irq, irq_handler_t handler,
unsigned long irqflags, const char *devname, void *dev_id)

request_action
setup_irq函数

3.2 中断的处理过程
对于中断这种异常,对应的中断总入口函数是asm_do_IRQ,前面提到 里面调用了irq_desc[irqno].handle_irq指向的函数
而这个函数会先调用硬件相关的函数去使能/关闭中断,再逐一调用用户注册的处理函数,即执行action->handler指向的函数。
那如何action链表有多个时,是如何调用处理的呢?
目标很明确:既然同一中断号对应不同处理函数,那首先需辨别是哪个中断源触发的,其次再调用对应的函数。
具体来讲:
以外部中断EINT8-ENIT23为例,看下图

EINT8-ENIT23
分辨中断源再调用处理函数

3.3 卸载中断处理函数
调用 free_irq 函数卸载,函数原型如下
void free_irq(unsigned int irq, void *dev_id)
从所需参数可看出,卸载时需根据irq找到 irq_desc[]数组某项,然后根据dev_id找到action链表中某一节点并卸载即可
因此,对于同一中断有不同处理函数,即action链表不止一个节点时,需保证dev_id唯一才能卸载,而这要求
在注册中断处理函数时指定,确保dev_id的唯一性

因此,卸载过程包含两步:
1.根据 irq、dev_id找到action链表某项,并删除
2.如果aciton链表只有一项,还要调用IRQ_DESC[IRQ].CHIP->SHUTDOWN或IRQ_DESC[IRQ].CHIP->DISABLE
	来关闭中断。(对于不止一个链表节点,删除某节点时当然不能关闭啦,其它处理函数还要用呢)

另外,注意:中断是很珍贵的资源,不用时记得卸载掉。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值