Fix up incorrect "unlikely()" on %gs reload in x86 __switch_to
authorLinus Torvalds <torvalds@evo.osdl.org>
Fri, 22 Jul 2005 19:23:47 +0000 (15:23 -0400)
committerLinus Torvalds <torvalds@evo.osdl.org>
Fri, 22 Jul 2005 19:23:47 +0000 (15:23 -0400)
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.

arch/i386/kernel/process.c

index ba243a4cc119fd35774bfc26e3fb3587bb31c741..d9492058aaf32c4821723967d3e158ef4de49616 100644 (file)
@@ -700,23 +700,27 @@ struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct tas
 
        /*
         * Restore %fs and %gs if needed.
 
        /*
         * 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);
                loadsegment(fs, next->fs);
+
+       if (prev->gs | next->gs)
                loadsegment(gs, next->gs);
                loadsegment(gs, next->gs);
-       }
 
        /*
         * Now maybe reload the debug registers
         */
        if (unlikely(next->debugreg[7])) {
 
        /*
         * 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 */
                /* 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))
        }
 
        if (unlikely(prev->io_bitmap_ptr || next->io_bitmap_ptr))