ARM中断及其处理
2013-12-16 10:43
232 查看
1,关于硬件部分的介绍。
value in the interrupt offset register shows which interrupt request of IRQ mode is in the INTPND register.SUBSRCPND:比如SRCPND[9]叫INT_WDT_AC97,意思是说WatchDogTimer或者AC97有中断,到底是那个,还得看SUBSRCPND[13:14],如果13那就是WDT,如果是 14那就是AC97。INTSUBMSK:SUB寄存器的存在可以理解为“共享中断设置寄存器(INTMSK等等)”的“详细说明”,就是指明共享中断包括了哪些东西。
EXTINT0/1/2:接下来的这三个寄存器用于设置外部中断的触发方式。EINTMASK:某位写1,则对应的位中断屏蔽EINTPEND:中断发生,则相应的为置1
~ 0x00000000~0x0000001CV=1 ~ 0xffff0000~0xffff001C从这里可以看出,前面犯了一个错误,即中断发生时,PC指针不一定跳到0x00000000。现在就剩下一个问题了,0xffff0000这个地址,是怎么样和linux的中断联系起来的。(2)事实上,在通过对CP15协处理器c1bit【13】进行操作之后,硬件接收到中断时,可以是跳转到0xffff0000这个地址,这个地址并不存在存储介质,所以我们需要对这个“虚拟地址”进行映射(这里特别要注意,“映射”和虚拟内存中的“查表”是不一样的),详细的在:http://tanatseng.blog.163.com/blog/static/174991629201121801359435/。这样一来,PC跳到0xffff0000这个地址以后,发现自己其实是在物理内存的某一个地址上,而这个地址接下来的1C个字节中,存储了中断向量表。中断向量表的位置就是这么来的。
[cpp]
view plaincopyprint?
struct irp_desc {
irp_flow_handler_t handle_irq;//当前中断的处理函数入口
struct irq_chip *chip;//低层的硬件访问
struct irqaction *action;//用户提供的中断处理函数链表
unsigned int status;//irq状态
const char *name;//中断名称
}___cacheline_internodealinged_in_smp;
中断处理的过程大致是这样的:
(1)发生中断时,CPU执行异常向量vector_irq的代码
(2)在vector_irq里面,最终会调用中断处理的总入口函数asm_do_IRQ。
(3)asm_do_IRQ根据中断号调用irq_desc数组项中的hand_irq。
(4)hand_irq会使用chip成员中的函数来设置硬件,比如清楚中断,禁止中断,重新使能中断等。
(5)handle_irq逐个调用用户在action链表中注册的处理函数。
以上都很好理解,整个初始化部分,简单理解无非就是三个结构体 的初始化。对于用户而言,需要关心(5),如何在action链表中注册中断处理函数。
[cpp]
view plaincopyprint?
int request_irq(unsigned int irq, irq_handler_t handler, unsigned long irqflags, const char *devname, void *devid);
对于二,其实只要多次调用request_irq这个函数即可。分两种情况:
①如果action链表为空,则直接链入
②否则先判断新建的irqaction结构和链表中的irqaction结构所表示的中断类型是否一致;即是否都申明为“可共享的”(IRQF_SHARED)、是否都使用形同的触发方式(电平、边沿、极性),如果一致,则将新建的irqaction结构链入。
这两段话中提到一个概念共享中断。网上查到大致是这么来说明的:
例如有A和B两个设备,公用了CPU的一根外部中断线INT0.当设置为共享中断时,A设备发生了中断,B设备产生的中断依然可以被CPU识别。设置为非共享中断时,则A设备发生中断时,不再接收B设备的中断信号。
问题又来了,对于上述的这个情况,如果是共享中断,CPU如何进行判断,哪一个设备对应哪一个中断呢??
这里涉及到request_irq中dev_id这个参数的应用,大致有两个作用,
一.在中断处理程序释放时使用到dev_id
二.将使用该中断处理程序的设备结构体传递给该中断处理程序
具体在这里:http://www.cublog.cn/u2/60011/showart_1086513.html
view plaincopyprint?
void free_irq(unsigned int irq, void *dev_id);
1.1ARM920T的中断
两种中断模式:FIQ,IRQ。1.2几个寄存器
SRCPND:请求中断的中断源。可以有多个位被置为1,可读可写,用完清0。只对irq模式有效。INTPND:当前正在执行的中断服务程序。只有一个为被置为1,可读可写,用完清0只对irq模式有效。INTMOD:某一位置1,则该位的中断源被设置为FIQ模式,否则为IRQ模式。INTMSK:某位为1,则该 位的中断被忽略INTOFFSET:Thevalue in the interrupt offset register shows which interrupt request of IRQ mode is in the INTPND register.SUBSRCPND:比如SRCPND[9]叫INT_WDT_AC97,意思是说WatchDogTimer或者AC97有中断,到底是那个,还得看SUBSRCPND[13:14],如果13那就是WDT,如果是 14那就是AC97。INTSUBMSK:SUB寄存器的存在可以理解为“共享中断设置寄存器(INTMSK等等)”的“详细说明”,就是指明共享中断包括了哪些东西。
EXTINT0/1/2:接下来的这三个寄存器用于设置外部中断的触发方式。EINTMASK:某位写1,则对应的位中断屏蔽EINTPEND:中断发生,则相应的为置1
1.3硬件部分的小结
2 中断过程以及linux对中断的处理过程
2.1 一些设置
2.1.1中断向量表在哪里
硬件发生中断后,ARM架构cpu的异常向量基址可以是0x00000000,也可以是0xffff0000,linux内核使用的是后者。看到这里的时候,遇到一个问题。为什么是这两个地址,按照它字面的意思,应该是这两个地址可以根据硬件来选择的。那么如果是这样,在哪儿选,怎么选?(1)通过查看数据手册,s3c2440有效的映射空间是1G(0x40000000),显然,0xffff0000已经超过了1G的范围,那么可以肯定,0xffff0000是一个虚拟地址。那么如果是虚拟地址,是怎么实现的?还有一个问题不容忽略,对于硬件而言,发生中断后PC指针肯定是跳到物理地址的0x0地址,也就是说,无论是虚拟地址0x00000000还是0xffff0000,最后其实都是映射到物理地址的0x00000000。当然,在这之间还有个小问题没有解决,到底linux是通过什么来确定到底使用哪一个地址的?答案如下:ARMv4以下的版本,该地址固定为0;ARMv4及以上版本,ARM中断向量表的地址由CP15协处理器c1寄存器中V位(bit[13])控制,V和中断向量表的对应关系如下:V=0~ 0x00000000~0x0000001CV=1 ~ 0xffff0000~0xffff001C从这里可以看出,前面犯了一个错误,即中断发生时,PC指针不一定跳到0x00000000。现在就剩下一个问题了,0xffff0000这个地址,是怎么样和linux的中断联系起来的。(2)事实上,在通过对CP15协处理器c1bit【13】进行操作之后,硬件接收到中断时,可以是跳转到0xffff0000这个地址,这个地址并不存在存储介质,所以我们需要对这个“虚拟地址”进行映射(这里特别要注意,“映射”和虚拟内存中的“查表”是不一样的),详细的在:http://tanatseng.blog.163.com/blog/static/174991629201121801359435/。这样一来,PC跳到0xffff0000这个地址以后,发现自己其实是在物理内存的某一个地址上,而这个地址接下来的1C个字节中,存储了中断向量表。中断向量表的位置就是这么来的。
2.1.2中断向量表的建立
在确定了中断向量表的位置之后,后面的事情就好办了,无非是向量表以及函数的一些copy动作。原理比较简单。不多说了。2.1.3小结
前面简单介绍了一些东西,与用户的编程关系不大。由操作系统或者硬件完成。了解这些,有助于后面一些复杂概念的理解。2.2 操作系统都干了些什么以及用户该怎么做
2.2.1 初始化部分
linux通过一个isr_desc结构体数组来描述中断:每个数组项对应一个中断。[cpp]
view plaincopyprint?
struct irp_desc {
irp_flow_handler_t handle_irq;//当前中断的处理函数入口
struct irq_chip *chip;//低层的硬件访问
struct irqaction *action;//用户提供的中断处理函数链表
unsigned int status;//irq状态
const char *name;//中断名称
}___cacheline_internodealinged_in_smp;
中断处理的过程大致是这样的:
(1)发生中断时,CPU执行异常向量vector_irq的代码
(2)在vector_irq里面,最终会调用中断处理的总入口函数asm_do_IRQ。
(3)asm_do_IRQ根据中断号调用irq_desc数组项中的hand_irq。
(4)hand_irq会使用chip成员中的函数来设置硬件,比如清楚中断,禁止中断,重新使能中断等。
(5)handle_irq逐个调用用户在action链表中注册的处理函数。
以上都很好理解,整个初始化部分,简单理解无非就是三个结构体 的初始化。对于用户而言,需要关心(5),如何在action链表中注册中断处理函数。
2.2.2 action链表中注册中断处理函数
对于用户,注册部分只是调用一个函数就已经结束了,剩下的内核会自动完成。2.2.3 几个问题
到此,还有几个小小的问题。第一,在request_irq这个函数中的参数 irq,取值范围是多少,32还是60?s3c2440发生中断时,可能是一个或者一组中断的中断号,那么这个irq是指具体的中断还是某一类中断呢?第二,之前提到,成员函数action是一个链表,中断在处理服务子程序时会一次调用action链表中的各个函数,在2.2.2的开始我们只是将一个函数注册进入内核,如果有多个中断服务子程序呢?对于一,irq的取值范围是0-31.也就是说注册函数只是想内核说明中断时哪一种类型,具体是哪一个中断,是内核调用asm_do_IRQ,然后再由asm_do_IRQ调用irq_decs.handle来计算的。计算完成之后,假设计算的中断号为INTno,那么再调用irq_decs[INTno].handle来做具体的中断服务。[cpp]
view plaincopyprint?
int request_irq(unsigned int irq, irq_handler_t handler, unsigned long irqflags, const char *devname, void *devid);
对于二,其实只要多次调用request_irq这个函数即可。分两种情况:
①如果action链表为空,则直接链入
②否则先判断新建的irqaction结构和链表中的irqaction结构所表示的中断类型是否一致;即是否都申明为“可共享的”(IRQF_SHARED)、是否都使用形同的触发方式(电平、边沿、极性),如果一致,则将新建的irqaction结构链入。
这两段话中提到一个概念共享中断。网上查到大致是这么来说明的:
例如有A和B两个设备,公用了CPU的一根外部中断线INT0.当设置为共享中断时,A设备发生了中断,B设备产生的中断依然可以被CPU识别。设置为非共享中断时,则A设备发生中断时,不再接收B设备的中断信号。
问题又来了,对于上述的这个情况,如果是共享中断,CPU如何进行判断,哪一个设备对应哪一个中断呢??
这里涉及到request_irq中dev_id这个参数的应用,大致有两个作用,
一.在中断处理程序释放时使用到dev_id
二.将使用该中断处理程序的设备结构体传递给该中断处理程序
具体在这里:http://www.cublog.cn/u2/60011/showart_1086513.html
2.3卸载中断处理函数
[cpp]view plaincopyprint?
void free_irq(unsigned int irq, void *dev_id);
相关文章推荐
- arm中断及其处理
- 【ARM】arm异常中断处理知识点
- ARM周立功模板启动代码中断处理文件IRQ.C的中文解释
- ARM中断异常处理的返回
- ARM中断处理流程的分析
- ARM Linux对中断的处理--中断注册方法
- 【ARM】2410裸机系列-中断处理
- Arm异常中断返回时的处理
- ucOS-II基于ARM920T的中断处理过程
- ARM Linux对中断的处理--中断处理
- ARM中断处理过程
- ARM中断学习一/[友善2440test中的中断处理部分]
- ARM中断分析之二:裸机下面的中断处理
- linux for arm的中断处理流程[转载自:http://hi.baidu.com/wudx05/blog/item/5314935c834f4e41fbf2c0dc.html]
- 为什么ARM的frq中断的处理速度比较快
- ARM Linux对中断的处理--中断处理
- ARM中断处理过程
- 【ARM】arm异常中断处理知识点
- linux 中断处理(基于linux-3.7.2 arm linux)
- 16.2 软中断CPU报文队列及其处理