summaryrefslogtreecommitdiffstats
path: root/cpukit
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2015-11-11 11:49:45 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2015-11-17 07:47:31 +0100
commit0c9bf40b89cd6763f9ec5d913d440c8b0074a092 (patch)
tree04cba2fa026fd198cfa00a172b7c7357293d2d11 /cpukit
parentlibblock: Avoid NULL pointer access (diff)
downloadrtems-0c9bf40b89cd6763f9ec5d913d440c8b0074a092.tar.bz2
Fix interrupt epilogue for ARMv7-AR and PowerPC
Close #2470.
Diffstat (limited to 'cpukit')
-rw-r--r--cpukit/score/cpu/arm/arm_exc_interrupt.S27
1 files changed, 27 insertions, 0 deletions
diff --git a/cpukit/score/cpu/arm/arm_exc_interrupt.S b/cpukit/score/cpu/arm/arm_exc_interrupt.S
index 7930c32044..fcb1510b95 100644
--- a/cpukit/score/cpu/arm/arm_exc_interrupt.S
+++ b/cpukit/score/cpu/arm/arm_exc_interrupt.S
@@ -209,6 +209,33 @@ thread_dispatch_done:
/* Restore EXCHANGE_LR and EXCHANGE_SPSR registers from exchange area */
ldmia sp!, {EXCHANGE_LR, EXCHANGE_SPSR}
+#ifdef ARM_MULTILIB_HAS_LOAD_STORE_EXCLUSIVE
+ /*
+ * We must clear reservations here, since otherwise compare-and-swap
+ * atomic operations with interrupts enabled may yield wrong results.
+ * A compare-and-swap atomic operation is generated by the compiler
+ * like this:
+ *
+ * .L1:
+ * ldrex r1, [r0]
+ * cmp r1, r3
+ * bne .L2
+ * strex r3, r2, [r0]
+ * cmp r3, #0
+ * bne .L1
+ * .L2:
+ *
+ * Consider the following scenario. A thread is interrupted right
+ * before the strex. The interrupt updates the value using a
+ * compare-and-swap sequence. Everything is fine up to this point.
+ * The interrupt performs now a compare-and-swap sequence which fails
+ * with a branch to .L2. The current processor has now a reservation.
+ * The interrupt returns without further strex. The thread updates the
+ * value using the unrelated reservation of the interrupt.
+ */
+ clrex
+#endif
+
/* Return from interrupt */
subs pc, lr, #4