xen64: Clear %fs on xen_load_tls()
authorEduardo Habkost <ehabkost@redhat.com>
Tue, 8 Jul 2008 22:07:10 +0000 (15:07 -0700)
committerIngo Molnar <mingo@elte.hu>
Wed, 16 Jul 2008 09:04:55 +0000 (11:04 +0200)
We need to do this, otherwise we can get a GPF on hypercall return
after TLS descriptor is cleared but %fs is still pointing to it.

Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
Cc: Stephen Tweedie <sct@redhat.com>
Cc: Eduardo Habkost <ehabkost@redhat.com>
Cc: Mark McLoughlin <markmc@redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
arch/x86/xen/enlighten.c

index 0172ba77452339afd245c0488690cda23d7d1c00..c13698faae54b30e24ec28deda512136bdf7d2db 100644 (file)
@@ -364,14 +364,6 @@ static void load_TLS_descriptor(struct thread_struct *t,
 
 static void xen_load_tls(struct thread_struct *t, unsigned int cpu)
 {
-       xen_mc_batch();
-
-       load_TLS_descriptor(t, cpu, 0);
-       load_TLS_descriptor(t, cpu, 1);
-       load_TLS_descriptor(t, cpu, 2);
-
-       xen_mc_issue(PARAVIRT_LAZY_CPU);
-
        /*
         * XXX sleazy hack: If we're being called in a lazy-cpu zone,
         * it means we're in a context switch, and %gs has just been
@@ -380,9 +372,30 @@ static void xen_load_tls(struct thread_struct *t, unsigned int cpu)
         * Either way, it has been saved, and the new value will get
         * loaded properly.  This will go away as soon as Xen has been
         * modified to not save/restore %gs for normal hypercalls.
+        *
+        * On x86_64, this hack is not used for %gs, because gs points
+        * to KERNEL_GS_BASE (and uses it for PDA references), so we
+        * must not zero %gs on x86_64
+        *
+        * For x86_64, we need to zero %fs, otherwise we may get an
+        * exception between the new %fs descriptor being loaded and
+        * %fs being effectively cleared at __switch_to().
         */
-       if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_CPU)
+       if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_CPU) {
+#ifdef CONFIG_X86_32
                loadsegment(gs, 0);
+#else
+               loadsegment(fs, 0);
+#endif
+       }
+
+       xen_mc_batch();
+
+       load_TLS_descriptor(t, cpu, 0);
+       load_TLS_descriptor(t, cpu, 1);
+       load_TLS_descriptor(t, cpu, 2);
+
+       xen_mc_issue(PARAVIRT_LAZY_CPU);
 }
 
 #ifdef CONFIG_X86_64