summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornwhitehorn <nwhitehorn@FreeBSD.org>2015-02-09 02:17:21 +0000
committernwhitehorn <nwhitehorn@FreeBSD.org>2015-02-09 02:17:21 +0000
commit492377c13f5239980005bc551fb37b2b0c6cb51e (patch)
treeece8cbcc3339340563db9ebb7d0ed4789451f10d
parent04847b0c514062f3113985d59e6d03a6fa5bf21c (diff)
downloadFreeBSD-src-492377c13f5239980005bc551fb37b2b0c6cb51e.zip
FreeBSD-src-492377c13f5239980005bc551fb37b2b0c6cb51e.tar.gz
Fix an extremely subtle concurrency bug triggered by running on 32-thread
POWER8 systems. During thread switch, there was a very small window when the stack pointer was set to the stack pointer of the outgoing thread, but after the lock on that thread had already been released. If, during that window, the outgoing thread were rescheduled on another CPU and begin execution and an exception were taken on the original CPU, the trap handler and the outgoing thread would simultaneously execute on the same stack, causing memory corruption. Fix this by making sure to release the old thread only after cpu_switch() is done with its stack. MFC after: 2 weeks Sponsored by: FreeBSD Foundation
-rw-r--r--sys/powerpc/powerpc/swtch64.S17
1 files changed, 11 insertions, 6 deletions
diff --git a/sys/powerpc/powerpc/swtch64.S b/sys/powerpc/powerpc/swtch64.S
index 6722bb6..ffecd1e 100644
--- a/sys/powerpc/powerpc/swtch64.S
+++ b/sys/powerpc/powerpc/swtch64.S
@@ -72,6 +72,8 @@ TOC_ENTRY(blocked_lock)
*/
ENTRY(cpu_throw)
mr %r13, %r4
+ li %r14,0 /* Tell cpu_switchin not to release a thread */
+
b cpu_switchin
/*
@@ -139,10 +141,7 @@ ENTRY(cpu_switch)
bl pmap_deactivate /* Deactivate the current pmap */
nop
- addi %r1,%r1,48
-
sync /* Make sure all of that finished */
- std %r16,TD_LOCK(%r14) /* ULE: update old thread's lock */
cpu_switchin:
#if defined(SMP) && defined(SCHED_ULE)
@@ -154,14 +153,20 @@ blocked_loop:
beq- blocked_loop
isync
#endif
+
+ ld %r17,TD_PCB(%r13) /* Get new PCB */
+ ld %r1,PCB_SP(%r17) /* Load the stack pointer */
- mfsprg %r7,0 /* Get the pcpu pointer */
+ /* Release old thread now that we have a stack pointer set up */
+ cmpdi %r14,0
+ beq- 1f
+ std %r16,TD_LOCK(%r14) /* ULE: update old thread's lock */
+
+1: mfsprg %r7,0 /* Get the pcpu pointer */
std %r13,PC_CURTHREAD(%r7) /* Store new current thread */
ld %r17,TD_PCB(%r13) /* Store new current PCB */
std %r17,PC_CURPCB(%r7)
- stdu %r1,-48(%r1)
-
mr %r3,%r13 /* Get new thread ptr */
bl pmap_activate /* Activate the new address space */
nop
OpenPOWER on IntegriCloud