This is the mail archive of the ecos-discuss@sources.redhat.com mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: ARM vector.s -- suspicious code in return_from_exception


Thanks for the patch mark.

Now how about the following case:
timer interrupt occurs, return_from_exception is called, spsr is written, ....
and another interrupt occures. As I understand interrupts are enabled during
task switches (but I still never found out where :-) ) and at least the fiq can
interrupt the code. This will mess-up the spsr in supervisor mode. This makes it
more important not to use spsr when interrupts are enabled.

One solution is to always disable interrupts (irq+fiq) in return_from_exception.
Another solution is to preserve spsr. Below is my solution. It has yet one flaw,
it does not read-modify-write the cpsr register, which might give problems on
future arm cores. But does the code work on these cores anyway?

Eric.

        //
        // Return from exception
        //
return_from_exception:

        // check pre-exception mode
        ldr     r2,[sp,#armreg_cpsr]
        and     r0,r2,#(CPSR_MODE_BITS)
        cmp     r0,#CPSR_SUPERVISOR_MODE
        beq     return_to_supervisor

        // To pre-supervisor mode to restore banked registers
        add     r1, sp, #armreg_r8
        orr     r0,r0,#(CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE)
        msr     cpsr, r0

        // Restore banked registers
        ldmfd   r1,{r8-r14}

        // Back to supervisor mode and disable interrupts
        mov     r0,#(CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE|CPSR_SUPERVISOR_MODE)
        msr     cpsr, r0

        // Prepare data for "ldmfd r2, {r0-r7,pc}^" in FIQ mode
        ldr     r0,[sp,#armreg_pc]
        str     r0,[sp,#armreg_r8]
        mov     r0,#(CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE|CPSR_FIQ_MODE)

        // Restore banked registers in supervisor mode. This makes the data on
        // stack unprotected, so make sure interrupts are disabled and no
exceptions occure!
        mov     r1,sp
        ldr     lr,[r1,#armreg_svclr]
        ldr     sp,[r1,#armreg_svcsp]

        // Switch to FIQ mode (because the FIQ-spsr is the only spsr register I
        // may mess up. The consequence is that the FIQ cannot be debugged
safely)
        msr     cpsr, r0

        // Return from exception
        msr     spsr, r2
        ldmfd   r1, {r0-r7,pc}^

return_to_supervisor:
#if 1 // #ifdef __thumb__
        // Disable interrupts
        mov     r0,#(CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE|CPSR_SUPERVISOR_MODE)
        msr     cpsr, r0

        // Restore banked registers in supervisor mode. This makes the data on
        // stack unprotected, so make sure interrupts are disabled and no
exception occures!
        add     r1, sp, #armreg_r8
        ldmfd   r1, {r8-r14}           // armreg_svcsp is *not* valid (not saved
correctly) so do not use
        sub     r1, r1, #armreg_r8

        // Prepare registers for ldmfd r2, {r0-r7,pc}^ in FIQ mode
        ldr     r0,[r1,#armreg_pc]
        str     r0,[r1,#armreg_r8]
        mov     r0,#(CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE|CPSR_FIQ_MODE)

        // Switch to FIQ mode (because the FIQ-spsr is the only spsr register I
        // may mess up. The consequence is that the FIQ cannot be debugged
safely)
        msr     cpsr, r0

        // Return from exception
        msr     spsr, r2
        ldmfd   r1, {r0-r7,pc}^
#else
        msr     cpsr, r2
        ldmfd   sp, {r0-r14, pc}
#endif



-- 
Before posting, please read the FAQ: http://sources.redhat.com/fom/ecos
and search the list archive: http://sources.redhat.com/ml/ecos-discuss


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]