现在ARM7的使用日益普及,在使用中大家可能会忽略这样一个问题--ARM7会产生伪中断!而出现伪中断的概率很低,在通常的调试时这种现象很少出现,因此开发者很难发现这一问题。但对于高可靠系统,任何微小的bug也是不应该允许的。本文将分析ARM7产生伪中断的原因,并给出解决办法。
如果在执行禁止中断指令时内核接收倒中断请求,ARM7仍然相应中断。这种情况出现在IRQ和FIQ中断中。
例如,假设正在执行下面的代码:
MRS R0,CPSR
ORR R0,R0,#I_BIT:OR:F_BIT ;禁止IRQ和FIQ中断
MSR CPSR_C,R0
如果在执行MSR指令时接收到IRQ中断,则执行以下操作:
(1)保存IRQ中断;
(2)执行“MSR CPSR,R0”指令来完成CPSR的I位和F位设置;
(3)响应IRQ中断,因为CPSR的I位被置位前内核将对中断异常进行处理;
(4)CPSR(I位和F位已被置位)的内容移入SPSR_irq。
这就意味着,在IRQ中断服务程序的入口,人们可以看到IRQ中断被处理的异常效果,SPSR的I位被置位。在上面的例子中,CPSR和SPSR的F位都被置位。这表明在IRQ服务程序的入口处FIQ被禁止,FIQ将一直被禁止到重新使能。FIQ不能通过IRQ返回来自动重新使能。
尽管上例中的IRQ和FIQ中断都被禁止,但如果两个中断类型中只有一种被禁止,出现的情况与之类似。执行完禁止IRQ的MSR指令后内核才对IRQ进行处理,这通常不会产生任何问题,因为只有中断正好在一个周期之前到达才会被处理。
当中断程序通过下面的指令返回时:
SUBS PC,LR,#4
SPSR_irq的值恢复到CPSR。这时,CPSR的I位和F位将被置位,所有中断禁止。
但是,这样会造成以下情况。
情况1:调用一个特定程序,该程序可以是IRQ处理程序或普通程序。之后,系统必须保证IRQ在调用程序之前被禁止。程序利用这个限制条件来决定调用方式(通过监测SPSR的I位状态),并使用合适的指令返回。如果程序在执行禁止IRQ的MSR指令的过程中接收到IRQ时进入,置位SPSR的I位。因此,程序不可能通过IRQ来进入。
情况2:FIQ和IRQ通过同一条写CPSR的指令来禁止。这时,如果在写CPSR的过程中接收到IRQ,FIQ将在执行IRQ处理程序时被禁止。
解决方案:
在中断程序之前增加类似于下面的代码:
SUB LR,LR,#4 ;调整LR,指向返回
STMFD SP!,{...,LR} ;指定使用的寄存器
MRS LR,SPSR ;当中断禁止时,判断是否有中断产生
TST LR,#I_BIT ;
LDMNEFD SP!,{...,PC}^ ;如果有中断产生,立即返回
;由于该中断并未被响应,因此仍保持待处理状态
;它将在下次中断使能时再被重新处理
;以下为中断程序
这部分代码用于在写CPSR来禁止IRQ过程中检测IRQ中断的产生。如果检测到IRQ,程序立即返回,从而使得IRQ不被响应(清除),也禁止后面的IRQ。FIQ处理程序也可以使用类似的代码。 |