|
@@ -226,8 +226,20 @@ static void notrace __restore_processor_state(struct saved_context *ctxt)
|
|
load_idt((const struct desc_ptr *)&ctxt->idt_limit);
|
|
load_idt((const struct desc_ptr *)&ctxt->idt_limit);
|
|
#endif
|
|
#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
|
|
#ifdef CONFIG_X86_32
|
|
loadsegment(es, ctxt->es);
|
|
loadsegment(es, ctxt->es);
|
|
@@ -248,13 +260,14 @@ static void notrace __restore_processor_state(struct saved_context *ctxt)
|
|
load_gs_index(ctxt->gs);
|
|
load_gs_index(ctxt->gs);
|
|
asm volatile ("movw %0, %%ss" :: "r" (ctxt->ss));
|
|
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_FS_BASE, ctxt->fs_base);
|
|
- wrmsrl(MSR_GS_BASE, ctxt->gs_base);
|
|
|
|
wrmsrl(MSR_KERNEL_GS_BASE, ctxt->gs_kernel_base);
|
|
wrmsrl(MSR_KERNEL_GS_BASE, ctxt->gs_kernel_base);
|
|
#endif
|
|
#endif
|
|
|
|
|
|
- fix_processor_context();
|
|
|
|
-
|
|
|
|
do_fpu_end();
|
|
do_fpu_end();
|
|
tsc_verify_tsc_adjust(true);
|
|
tsc_verify_tsc_adjust(true);
|
|
x86_platform.restore_sched_clock_state();
|
|
x86_platform.restore_sched_clock_state();
|