Chinaunix首页 | 论坛 | 博客
  • 博客访问: 154504
  • 博文数量: 31
  • 博客积分: 1455
  • 博客等级: 上尉
  • 技术积分: 340
  • 用 户 组: 普通用户
  • 注册时间: 2010-03-09 02:20
文章存档

2012年(2)

2011年(18)

2010年(11)

分类: 嵌入式

2010-04-23 01:16:18

原来ARM7内核都有这样的问题,在禁止了中断后仍可能丢出中断
以前看别人的代码,反正拿来用就是,从来没想会有这样的事情。

叫伪中断真有欺骗性,其实大方点叫bug啦。好在ARM官方给出了workaround,也不麻烦,
编程注意就是了。转文如下:

==============================================================



What happens if an interrupt occurs as it is being disabled?

Applies to: 

If an interrupt is received by the core during execution of an instruction that disables interrupts, the ARM7 family will still take the interrupt. This occurs for both IRQ and FIQ interrupts.

For example, consider the follow instruction sequence:

MRS r0, cpsr
ORR r0, r0, #I_Bit:OR:F_Bit ;disable IRQ and FIQ interrupts
MSR cpsr_c, r0

If an IRQ interrupt is received during execution of the MSR instruction, then the behavior will be as follows:

  • The IRQ interrupt is latched
  • The MSR cpsr, r0 executes to completion setting both the I bit and the F bit in the CPSR
  • The IRQ interrupt is taken because the core was committed to taking the interrupt exception before the I bit was set in the CPSR.
  • The CPSR (with the I bit and F bit set) is moved to the SPSR_irq

This means that, on entry to the IRQ interrupt service routine, one can see the unusual effect that an IRQ interrupt has just been taken while the I bit in the SPSR is set. In the example above, the F bit will also be set in both the CPSR and SPSR. This means that FIQs are disabled upon entry to the IRQ service routine, and will remain so until explicitly re-enabled. FIQs will not be re-enabled automatically by the IRQ return sequence.

Although the example shows both IRQ and FIQ interrupts being disabled, similar behavior occurs when only one of the two interrupt types is being disabled. The fact that the core processes the IRQ after completion of the MSR instruction which disables IRQs does not normally cause a problem, since an interrupt arriving just one cycle earlier would be expected to be taken. When the interrupt routine returns with an instruction like:

SUBS pc, lr, #4

the SPSR_IRQ is restored to the CPSR. The CPSR will now have the I bit and F bit set, and therefore execution will continue with all interrupts disabled.

However, this can cause problems in the following cases:

Problem 1: A particular routine may be called as an IRQ handler, or as a regular subroutine. When the routine is called as a regular subroutine, the calling code must first disable interrupts. The routine determines how it was called by examining the I bit of the SPSR and returns using the appropriate instruction. If the routine is entered due to an IRQ being received during execution of the MSR instruction which disables IRQs, then the I bit in the SPSR will be set. The routine would therefore assume that it could not have been entered via an IRQ.

Problem 2: FIQs and IRQs are both disabled by the same write to the CPSR. In this case, if an IRQ is received during the CPSR write, FIQs will be disabled for the execution time of the IRQ handler. This may not be acceptable in a system where FIQs must not be disabled for more than a few cycles.

Workaround:

There are 3 suggested workarounds. Which of these is most applicable will depend upon the requirements of the particular system.

  1. Add code similar to the following at the start of the interrupt routine.

    SUB lr, lr, #4 ; Adjust LR to point to return
    STMFD sp!, {..., lr} ; Get some free regs
    MRS lr, SPSR ; See if we got an interrupt while
    TST lr, #I_Bit ; interrupts were disabled.
    LDMNEFD sp!, {..., pc}^ ; If so, just return immediately.
    ; The interrupt will remain
    ; pending since we haven't
    ; acknowledged it and will be
    ; reissued when interrupts are next
    ; enabled.
    ; Rest of interrupt routine

    This code will test for the situation where the IRQ was received during a write to disable IRQs. If this is the case, the code returns immediately - resulting in the IRQ not being acknowledged (cleared), and further IRQs being disabled.

    Similar code may also be applied to the FIQ handler, in order to resolve the first issue.

    This is the recommended workaround, as it overcomes both problems mentioned above. However, in the case of problem two, it does add several cycles to the maximum length of time FIQs will be disabled.

  2. Disable IRQs and FIQs using separate writes to the CPSR, eg:

    MRS r0, cpsr
    ORR r0, r0, #I_Bit ;disable IRQs
    MSR cpsr_c, r0
    ORR r0, r0, #F_Bit ;disable FIQs
    MSR cpsr_c, r0

    This is the best workaround where the maximum time for which FIQs are disabled is critical (it does not increase this time at all). However, it does not solve problem one, and requires extra instructions at every point where IRQs and FIQs are disabled together.

  3. Re-enable FIQs at the beginning of the IRQ handler. As the required state of all bits in the c field of the CPSR are known, this can be most efficiently be achieved by writing an immediate value to CPSR_c, for example:

    MSR cpsr_c, #I_Bit:OR:irq_MODE ;IRQ should be disabled
    ;FIQ enabled
    ;ARM state, IRQ mode

    This requires only the IRQ handler to be modified, and FIQs may be re-enabled more quickly than by using workaround 1. However, this should only be used if the system can guarantee that FIQs are never disabled while IRQs are enabled. It does not address problem one.


阅读(2240) | 评论(2) | 转发(0) |
给主人留下些什么吧!~~

征征1682010-04-23 10:04:01

有点小复杂!!!

安何2010-04-23 08:55:53