summaryrefslogtreecommitdiff
path: root/arch/i386
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@evo.osdl.org>2005-07-22 15:23:47 -0400
committerLinus Torvalds <torvalds@evo.osdl.org>2005-07-22 15:23:47 -0400
commitb339a18b81a1f6ca1455559594f5df872b9e59f4 (patch)
tree1c3a34047734e5923484353dbe710b167ad7c72b /arch/i386
parentf60f700876cd51de9de69f3a3c865d95e287a24d (diff)
downloadlwn-b339a18b81a1f6ca1455559594f5df872b9e59f4.tar.gz
lwn-b339a18b81a1f6ca1455559594f5df872b9e59f4.zip
Fix up incorrect "unlikely()" on %gs reload in x86 __switch_to
These days %gs is normally the TLS segment, so it's no longer zero. As a result, we shouldn't just assume that %fs/%gs tend to be zero together, but test them independently instead. Also, fix setting of debug registers to use the "next" pointer instead of "current". It so happens that the scheduler will have set the new current pointer before calling __switch_to(), but that's just an implementation detail.
Diffstat (limited to 'arch/i386')
-rw-r--r--arch/i386/kernel/process.c20
1 files changed, 12 insertions, 8 deletions
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
index ba243a4cc119..d9492058aaf3 100644
--- a/arch/i386/kernel/process.c
+++ b/arch/i386/kernel/process.c
@@ -700,23 +700,27 @@ struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct tas
/*
* Restore %fs and %gs if needed.
+ *
+ * Glibc normally makes %fs be zero, and %gs is one of
+ * the TLS segments.
*/
- if (unlikely(prev->fs | prev->gs | next->fs | next->gs)) {
+ if (unlikely(prev->fs | next->fs))
loadsegment(fs, next->fs);
+
+ if (prev->gs | next->gs)
loadsegment(gs, next->gs);
- }
/*
* Now maybe reload the debug registers
*/
if (unlikely(next->debugreg[7])) {
- set_debugreg(current->thread.debugreg[0], 0);
- set_debugreg(current->thread.debugreg[1], 1);
- set_debugreg(current->thread.debugreg[2], 2);
- set_debugreg(current->thread.debugreg[3], 3);
+ set_debugreg(next->debugreg[0], 0);
+ set_debugreg(next->debugreg[1], 1);
+ set_debugreg(next->debugreg[2], 2);
+ set_debugreg(next->debugreg[3], 3);
/* no 4 and 5 */
- set_debugreg(current->thread.debugreg[6], 6);
- set_debugreg(current->thread.debugreg[7], 7);
+ set_debugreg(next->debugreg[6], 6);
+ set_debugreg(next->debugreg[7], 7);
}
if (unlikely(prev->io_bitmap_ptr || next->io_bitmap_ptr))