This is the mail archive of the
ecos-discuss@sources.redhat.com
mailing list for the eCos project.
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