分类: LINUX
2008-12-14 17:28:59
大家当然也可以在我的blog里面讨论。
打个比方: 一个傻子让妈妈喂饭: “妈妈, 我饿了”(SRCPND 对应bit 置1 ) , 但是啥子不知道吃多少才能饱(脑子毁掉了,要不怎么啥呢?) 。 妈妈知道喂两碗就行了 。 所以当妈妈喂了两碗之后, 不再喂了(相当于中断处理完毕) 。
然后告诉啥子, 行了 ,饱了(相当于SRCPND 清0) ,啥子相信妈妈的话, only相信妈妈的话 。
否则 ,如果妈妈不说“行了, 吃饱了,不要再吃了”这样的话, 啥子就一个劲的问问“ 妈妈, 我饿,俄” ,结果妈妈(也是个傻妈妈,难怪啥子是遗传的) ,一个劲的喂 , 结果什么活也干不了了,同时也把傻子儿子撑死了。
我怎么会突然想到这么一个比喻, 我真是个天才啊! --bob
|
word档案:
1.3 s
从这里:
可以看出: s
这些中断源来自来自两部分:内部外设,比如DMA 控制器,uart ,i
第二部分是外部中断请求的pin脚。
流程是这样:
当中断控制器接收到中断请求后, 经过仲裁过程后(选择了一个优先级高的IRQ或者FIQ),然后才向CPU发出 IRQ或者FIQ的请求。
至于到底这个中断源产生的IRQ还是FIQ , 这个要根据interrupt mode register设置了:
从这里我们也可以看出, IRQ和FIQ只是两种模式而已。 也就是说 , 当一个中断源被配置成IRQ或者FIQ的时候 , 中断控制器处理她的request的方式是不同的。
那是不是每个中断源可以随便设置自己的模式呢?显然不行。(想想, 如果发给大家的都是VIP卡, 那这个VIP卡显然就是普通的卡,被少数人拥有的才是VIP卡)
显然,只有紧急的中断才可以配置成FIQ , 也就是只有一个中断源才可以配置成FIQ模式,也就是VIP只有一个。
翻译出来是这样:
过程很简单,
过程这样:当中断源请求服务后, SRCPND对应set 1 , 经过仲裁后, 对应的INTPND的bit 会被被置 1 (前提是没有mask这个中断源) , 如果mask 了, INTPND的对应的bit就不会自动set 1 。
接下来,就取决于CPSR的 F-bit 和 I-bit了,如果他们置1 了,INTPND 也置1 , 那么就调用中断服务routine , 否则如果F-bit或者I-bit 是0 ,那么就不会调用中断服务routine 了。
所以 ,从这里就可以看出 SRCPND 和 INTPND 的 关系了: SRCPND set 1 表示中断源产生了request ,
而INTPND 仅仅表示这个中断源没有被mask掉 ,中断控制器可以向CPU发出request了,以上这些都是从interrupt controller的角度来说的, 至于CPU 处不处理(也就是是否调用中断处理routine)就得 看 CPSR 寄存器里面F-bit和I-bit了, 如果都被set成0了, 那么显然CPU是不会鸟 中断控制器的(从英文来看:(If the F-bit of PSR in ARM920T CPU is set to 1, the CPU does not accept the Fast Interrupt Request (FIQ) from the
interrupt
controller. Likewise, If I-bit of the PSR is set to 1, the CPU does not
accept the Interrupt Request (IRQ) from the interrupt controller. So,
the interrupt controller can receive interrupts by clearing F-bit or
I-bit of the PSR to 0 and setting the corresponding bit of INTMSK to 0 , 这里用了 accept ,那就是说 interrupt发了request ,可是CPU 不能accept) 。
可以看出,
可以看出 , FIQ是不需要仲裁的, 显然从这点可以看出 FIQ 的效率肯定比IRQ高 ,因为FIQ必须要仲裁。
来自中断源的中断请求必须首先在SRCPND 寄存器里面注册一下(即对应的bit 置1) 。
这些请求又分为两组, 至于怎么分,就得看 中断模式寄存器了。
关于SRCPND 这里面说的很明确了, 就是 只要触发了中断, SRCPND对应的bit就会被自动置1 , 仅仅表示产生了中断, 等待着被服务(kernel调用interrupt service) 。 而无论INTMASK对应的bit 是否是1 , SRCPND都会被自动置1 。
这一点 ,上面已经说的很清楚了。
这个说的就是 关于如何清除 SRCPND , 以及何时清除的问题了, 还有就是如果 你不clear SRCPND相应的bit会导致什么后果:
显然上面说的很清楚了, SRCPND 仅仅表示 中断请求的状态, 如果 kernel都处理了这个中断(调用了中断处理函数) ,就应该告诉 中断控制器(我已经处理完了, 你tmd别烦了) 。
如果没有清除会有什么样的后果: 我想, 中断控制器可不知道kernel已经处理完了这个中断, 还在那里等着kernel去处理呢, 这样kernel也傻了, 就会去反复的处理的这个中断)。
打个比方: 一个傻子让妈妈喂饭: “妈妈, 我饿了”(SRCPND 对应bit 置1 ) , 但是啥子不知道吃多少才能饱(脑子毁掉了,要不怎么啥呢?) 。 妈妈知道喂两碗就行了 。 所以当妈妈喂了两碗之后, 不再喂了(相当于中断处理完毕) 。
然后告诉啥子, 行了 ,饱了(相当于SRCPND 清0) ,啥子相信妈妈的话, only相信妈妈的话 。
否则 ,如果妈妈不说“行了, 吃饱了,不要再吃了”这样的话, 啥子就一个劲的问问“ 妈妈, 我饿,俄” ,结果妈妈(也是个傻妈妈,难怪啥子是遗传的) ,一个劲的喂 , 结果什么活也干不了了,同时也把傻子儿子撑死了。
我怎么会突然想到这么一个比喻, 我真是个天才啊! --bob
?对于CPU都是这样的吗? 就是 interrupt service routine 里面必须清楚中断的标志bit吗?
又想到一个比喻: 古代奸臣误国,好多正直大臣的奏折并不能被直接传递到皇帝手中 ,比如大奸臣魏忠贤。
魏忠贤好比是中断控制器 , 皇帝好比是CPU 。
奏章要首先经过魏忠贤的手, 如果魏忠贤屏蔽掉某个大臣的奏章(mask),那么皇帝肯定没有机会看了。
但是假使奏章通过魏忠贤(interrupt controller)传给皇帝了, 可是皇帝是个糊涂蛋, 只知玩乐,误了朝政, 奏折堆积如山(就相当于 F-bit=1,I-bit=1)了。
所以封建国家, 既要有好大臣(狄仁杰,什么奏章都敢上奏,不管是否是弹劾自己的), 又要有好皇帝(唐太宗,勤于政事)啊。
当一个中断控制器连接了128个中断源的时候, CPU怎么知道哪个中断源产生了中断呢?继而调用对应的中断处理函数呢?
一般的原理都是这样的:
显然,要回答这个问题, 必须要搞清楚, CPU是肯定不知道哪个中断源产生了中断的, 谁知道呢?只有中断控制器才知道的, 那么,CPU就要查询中断控制器就好了。 问题是中断控制器的那个register 的标志bit 被置1 , 肯定是硬件做的,
知道这些就足够了。
当中断源触发了一个中断的时候, 中断控制器要提供一个寄存器来标志哪个源产生中断, 类似2410 就提供INTPND(32个bit,bit置1 就表示对应的source产生了中断) , 那么CPU就会读取这个寄存器,以确定中断号(get_irqnr_and_base这是个汇编宏)。 问题在于CPU怎么知道要去读呢? 显然要中断控制器给CPU发一个IRQ的request , 这样CPU才会去读(实际上是一段汇编代码) 。
继而才会调用asm_do_IRQ(irq_number)来处理中断, 继而可以通过irq号找到对应中断的中断描述符(irq descriptor),找到了中断描述符,就找到了,handler , 然后 调用 ->handler() 就可以处理中断了。
1.2 中断处理函数是如何被called ?
[自己的分析bob]
中断首先是一个硬件行为, 而处理中断呢, 显然又是一个软件行为,作为driver writer only 实现中断处理函数, 并与中断号进行关联也就ok了。那么就引出一个问题? 当硬件触发中断的时候,怎么调用到中断处理函数的呢?
要搞清楚这个问题,就要搞清楚,发生中断的时候 CPU做了什么
以arm为例,当产生IRQ请求的时候, CPU做了什么:
1> 处理器切换到特定的中断请求模式(IRQ模式),表明产生了中断。
2> 前一个模式的cpsr被保存到新的模式下的spsr。
3> PC 指针被保存到新的模式的lr 寄存器
4> 关中断----在cpsr中禁止I-bit ,会立即阻止其他的IRQ产生。
5> 处理器跳转到异常向量表中相应的入口(对于IRQ , 显然pc=0x18) 。
说道这里,就涉及到了异常向量表,这个异常向量表就是软件和CPU的接口。 CPU知道一个source触发了中断,怎么调用执行一些函数(汇编,或者c语言),就是靠异常向量表(事实上,exception vector table 也是由汇编组成的)
异常 |
模式 |
向量表偏移 |
复位(reset) |
SVC |
+0x00 |
未定义指令 |
UND |
+0x04 |
软件中断(SWI) |
SVC |
+0x08 |
欲取指终止 |
ABT |
+0x |
数据终止 |
ABT |
+0x10 |
未分配 |
-- |
+0x14 |
IRQ |
IRQ |
+0x18 |
FIQ |
FIQ |
+0x |
表 arm异常,对应模式及向量表偏移(摘自arm体系结构与编程一书)
从这表中, 我们很清楚了, 当触发IRQ的时候, CPU会最后跳入0x18 这个入口 , 那我们做kernel的人, 只需在这个入口填入自己的指令(当然是汇编语句) , 来调用 中断处理函数,可能这样。
中断-à cpu jump 到0x18 ,同时要把irqno传入相应的寄存器 à 调用一个中断通用处理函数比如叫 asm_do_IRQ(unsigned int irqno) à asm_do_IRQ() 这个函数根据irqno 就可以找到对应的中断描述符 à 然后调用中断描述符里面的handler() 了 。
那具体的kernel里面的细节是什么样的呢? 具体看下面这篇转载的文章即可。代码分析的就比较透彻了, 事实上我们只要上面说的流程,对于driver writer已经足够了。
【转载】
那么 当硬件触发中断的时候, kernel里面的 asm_do_IRQ() 是如何被调用到呢?
遭到一篇很好的文章:
http://hi.baidu.com/wudx05/blog/item/5314935c834f4e41fbf2c0dc.html