Arm® Errata #752770: Interrupted loads to SP can cause erroneous
behavior
Revisions Affected:
Revision C and earlier
Details:
An interrupt occurring during the
data-phase of a single word load to the stack-pointer (SP/R13) can cause an
erroneous behavior of the device. In all cases, returning from the interrupt will
result in the load instruction being executed an additional time. For all
instructions performing an update to the base register, the base register will be
erroneously updated on each execution, resulting in the stack-pointer being loaded
from an incorrect memory location.The affected instructions that can
result in the load transaction being repeated are:
- LDR SP,[Rn],#imm
- LDR SP,[Rn,#imm]!
- LDR SP,[Rn,#imm]
- LDR SP,[Rn]
- LDR SP,[Rn,Rm]
The affected instructions that
can result in the stack-pointer being loaded from an incorrect memory address
are:
- LDR SP,[Rn],#imm
- LDR SP,[Rn,#imm]!
Conditions:
- An LDR is executed, with SP/R13 as the destination.
- The address for the LDR is successfully issued to the memory
system.
- An interrupt is taken before the data has been returned and
written to the stack-pointer.
Implications:
Unless the load is being performed to device memory or
strongly-ordered memory, there should be no implications from the repetition of
the load.
- In the unlikely event that the load is being performed
to device memory or strongly-ordered memory, the repeated read can
result in the final stack-pointer value being different than had only a
single load been performed.
- Interruption of the two write-back forms of the
instruction can result in both the base register value and the final
stack-pointer value being incorrect. This can result in apparent stack
corruption and subsequent unintended modification of memory.
Workaround:
Most compilers ensure this bug is not
triggered by not emitting the affected instruction sequence and not using the
instructions in the compiler runtime libraries. This includes:
- IAR from v6.21
- All versions of TI's Arm compiler (CCS)
A workaround for both issues can
be implemented by replacing the direct load to the stack-pointer, with an
intermediate load to a general-purpose register followed by a move to the
stack-pointer.
If repeated
reads are acceptable, then the base register update issue may be worked around by
performing the stack-pointer load without the base increment followed by a
subsequent ADD or SUB instruction to perform the appropriate update to the base
register.