]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - arch/x86/power/cpu.c
x86/power: Fix some ordering bugs in __restore_processor_context()
[linux.git] / arch / x86 / power / cpu.c
index 84fcfde53f8f3f5bb4b85efc20ab106c419dcc11..5191de14f4df9aea4e452925cda5b9845d8d1bf4 100644 (file)
@@ -226,8 +226,20 @@ static void notrace __restore_processor_state(struct saved_context *ctxt)
        load_idt((const struct desc_ptr *)&ctxt->idt_limit);
 #endif
 
+#ifdef CONFIG_X86_64
        /*
-        * segment registers
+        * We need GSBASE restored before percpu access can work.
+        * percpu access can happen in exception handlers or in complicated
+        * helpers like load_gs_index().
+        */
+       wrmsrl(MSR_GS_BASE, ctxt->gs_base);
+#endif
+
+       fix_processor_context();
+
+       /*
+        * Restore segment registers.  This happens after restoring the GDT
+        * and LDT, which happen in fix_processor_context().
         */
 #ifdef CONFIG_X86_32
        loadsegment(es, ctxt->es);
@@ -248,13 +260,14 @@ static void notrace __restore_processor_state(struct saved_context *ctxt)
        load_gs_index(ctxt->gs);
        asm volatile ("movw %0, %%ss" :: "r" (ctxt->ss));
 
+       /*
+        * Restore FSBASE and user GSBASE after reloading the respective
+        * segment selectors.
+        */
        wrmsrl(MSR_FS_BASE, ctxt->fs_base);
-       wrmsrl(MSR_GS_BASE, ctxt->gs_base);
        wrmsrl(MSR_KERNEL_GS_BASE, ctxt->gs_kernel_base);
 #endif
 
-       fix_processor_context();
-
        do_fpu_end();
        tsc_verify_tsc_adjust(true);
        x86_platform.restore_sched_clock_state();