summaryrefslogtreecommitdiffstats
path: root/sys/arm64
diff options
context:
space:
mode:
authorandrew <andrew@FreeBSD.org>2016-02-12 12:38:04 +0000
committerandrew <andrew@FreeBSD.org>2016-02-12 12:38:04 +0000
commit9305b5748d57bfc77ebc4868162f0fedcc0d887e (patch)
tree95a1a95950225bb3b8d447662016224986ce3ccb /sys/arm64
parent1ca3ca2fd307dd0124940aac802e60893a53f0d8 (diff)
downloadFreeBSD-src-9305b5748d57bfc77ebc4868162f0fedcc0d887e.zip
FreeBSD-src-9305b5748d57bfc77ebc4868162f0fedcc0d887e.tar.gz
Only update curthread and curpcb after we have finished using the old
values. If switching from a thread that used floating-point registers to a thread that is still running, but holding the blocked_lock lock we would switch the curthread to the new (running) thread, then call critical_enter. This will non-atomically increment td_critnest, and later call critical_exit to non-atomically decrement this value. This can happen at the same time as the new thread is still running on the old core, also calling these functions. In this case there will be a race between these non-atomic operations. This can be an issue as we could loose one of these operations leading to the value to not return to zero. If, later on, we then hit a data abort we check if the td_critnest is zero. If this check fails we will panic the kernel. This has been observed when running pcmstat on a Cavium ThunderX. The pcm thread will use the blocked_lock lock and there is a high chance userspace will use the floating-point registers. When, later on, pmcstat triggers a data abort we will hit this panic. The fix is to update these values after storing the floating-point state. This means we use the correct curthread while storing the state so it will not be an issue that the changes to td_critnest are non-atomic. Sponsored by: ABT Systems Ltd
Diffstat (limited to 'sys/arm64')
-rw-r--r--sys/arm64/arm64/swtch.S12
1 files changed, 5 insertions, 7 deletions
diff --git a/sys/arm64/arm64/swtch.S b/sys/arm64/arm64/swtch.S
index 3175e87..35153c2 100644
--- a/sys/arm64/arm64/swtch.S
+++ b/sys/arm64/arm64/swtch.S
@@ -129,12 +129,6 @@ END(cpu_throw)
* x3 to x7, x16 and x17 are caller saved
*/
ENTRY(cpu_switch)
- /* Store the new curthread */
- str x1, [x18, #PC_CURTHREAD]
- /* And the new pcb */
- ldr x4, [x1, #TD_PCB]
- str x4, [x18, #PC_CURPCB]
-
/*
* Save the old context.
*/
@@ -174,10 +168,14 @@ ENTRY(cpu_switch)
mov x0, x19
#endif
+ /* Store the new curthread */
+ str x1, [x18, #PC_CURTHREAD]
+
/*
- * Restore the saved context.
+ * Restore the saved context and set it as curpcb.
*/
ldr x4, [x1, #TD_PCB]
+ str x4, [x18, #PC_CURPCB]
/*
* TODO: We may need to flush the cache here if switching
OpenPOWER on IntegriCloud