xen/pvh: Load GDT/GS in early PV bootup code for BSP.
authorMukesh Rathor <mukesh.rathor@oracle.com>
Fri, 13 Dec 2013 18:03:37 +0000 (13:03 -0500)
committerKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Mon, 6 Jan 2014 15:44:10 +0000 (10:44 -0500)
During early bootup we start life using the Xen provided
GDT, which means that we are running with %cs segment set
to FLAT_KERNEL_CS (FLAT_RING3_CS64 0xe033, GDT index 261).

But for PVH we want to be use HVM type mechanism for
segment operations. As such we need to switch to the HVM
one and also reload ourselves with the __KERNEL_CS:eip
to run in the proper GDT and segment.

For HVM this is usually done in 'secondary_startup_64' in
(head_64.S) but since we are not taking that bootup
path (we start in PV - xen_start_kernel) we need to do
that in the early PV bootup paths.

For good measure we also zero out the %fs, %ds, and %es
(not strictly needed as Xen has already cleared them
for us). The %gs is loaded by 'switch_to_new_gdt'.

Signed-off-by: Mukesh Rathor <mukesh.rathor@oracle.com>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Reviewed-by: David Vrabel <david.vrabel@citrix.com>
arch/x86/xen/enlighten.c

index 23ead29..1170d00 100644 (file)
@@ -1410,8 +1410,43 @@ static void __init xen_boot_params_init_edd(void)
  * we do this, we have to be careful not to call any stack-protected
  * function, which is most of the kernel.
  */
-static void __init xen_setup_stackprotector(void)
+static void __init xen_setup_gdt(void)
 {
+       if (xen_feature(XENFEAT_auto_translated_physmap)) {
+#ifdef CONFIG_X86_64
+               unsigned long dummy;
+
+               switch_to_new_gdt(0); /* GDT and GS set */
+
+               /* We are switching of the Xen provided GDT to our HVM mode
+                * GDT. The new GDT has  __KERNEL_CS with CS.L = 1
+                * and we are jumping to reload it.
+                */
+               asm volatile ("pushq %0\n"
+                             "leaq 1f(%%rip),%0\n"
+                             "pushq %0\n"
+                             "lretq\n"
+                             "1:\n"
+                             : "=&r" (dummy) : "0" (__KERNEL_CS));
+
+               /*
+                * While not needed, we also set the %es, %ds, and %fs
+                * to zero. We don't care about %ss as it is NULL.
+                * Strictly speaking this is not needed as Xen zeros those
+                * out (and also MSR_FS_BASE, MSR_GS_BASE, MSR_KERNEL_GS_BASE)
+                *
+                * Linux zeros them in cpu_init() and in secondary_startup_64
+                * (for BSP).
+                */
+               loadsegment(es, 0);
+               loadsegment(ds, 0);
+               loadsegment(fs, 0);
+#else
+               /* PVH: TODO Implement. */
+               BUG();
+#endif
+               return; /* PVH does not need any PV GDT ops. */
+       }
        pv_cpu_ops.write_gdt_entry = xen_write_gdt_entry_boot;
        pv_cpu_ops.load_gdt = xen_load_gdt_boot;
 
@@ -1494,7 +1529,7 @@ asmlinkage void __init xen_start_kernel(void)
         * Set up kernel GDT and segment registers, mainly so that
         * -fstack-protector code can be executed.
         */
-       xen_setup_stackprotector();
+       xen_setup_gdt();
 
        xen_init_irq_ops();
        xen_init_cpuid_mask();