]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - arch/x86/kernel/cpu/common.c
Merge branch 'stable/for-jens-4.12' of git://git.kernel.org/pub/scm/linux/kernel...
[mirror_ubuntu-artful-kernel.git] / arch / x86 / kernel / cpu / common.c
index 58094a1f9e9d301e11d2c93a1ecc126e1715002e..c8b39870f33e8d5579eb1b30ecd24ace23de9d86 100644 (file)
@@ -448,19 +448,60 @@ void load_percpu_segment(int cpu)
        load_stack_canary_segment();
 }
 
+/* Setup the fixmap mapping only once per-processor */
+static inline void setup_fixmap_gdt(int cpu)
+{
+#ifdef CONFIG_X86_64
+       /* On 64-bit systems, we use a read-only fixmap GDT. */
+       pgprot_t prot = PAGE_KERNEL_RO;
+#else
+       /*
+        * On native 32-bit systems, the GDT cannot be read-only because
+        * our double fault handler uses a task gate, and entering through
+        * a task gate needs to change an available TSS to busy.  If the GDT
+        * is read-only, that will triple fault.
+        *
+        * On Xen PV, the GDT must be read-only because the hypervisor requires
+        * it.
+        */
+       pgprot_t prot = boot_cpu_has(X86_FEATURE_XENPV) ?
+               PAGE_KERNEL_RO : PAGE_KERNEL;
+#endif
+
+       __set_fixmap(get_cpu_gdt_ro_index(cpu), get_cpu_gdt_paddr(cpu), prot);
+}
+
+/* Load the original GDT from the per-cpu structure */
+void load_direct_gdt(int cpu)
+{
+       struct desc_ptr gdt_descr;
+
+       gdt_descr.address = (long)get_cpu_gdt_rw(cpu);
+       gdt_descr.size = GDT_SIZE - 1;
+       load_gdt(&gdt_descr);
+}
+EXPORT_SYMBOL_GPL(load_direct_gdt);
+
+/* Load a fixmap remapping of the per-cpu GDT */
+void load_fixmap_gdt(int cpu)
+{
+       struct desc_ptr gdt_descr;
+
+       gdt_descr.address = (long)get_cpu_gdt_ro(cpu);
+       gdt_descr.size = GDT_SIZE - 1;
+       load_gdt(&gdt_descr);
+}
+EXPORT_SYMBOL_GPL(load_fixmap_gdt);
+
 /*
  * Current gdt points %fs at the "master" per-cpu area: after this,
  * it's on the real one.
  */
 void switch_to_new_gdt(int cpu)
 {
-       struct desc_ptr gdt_descr;
-
-       gdt_descr.address = (long)get_cpu_gdt_table(cpu);
-       gdt_descr.size = GDT_SIZE - 1;
-       load_gdt(&gdt_descr);
+       /* Load the original GDT */
+       load_direct_gdt(cpu);
        /* Reload the per-cpu base */
-
        load_percpu_segment(cpu);
 }
 
@@ -1108,7 +1149,6 @@ static void identify_cpu(struct cpuinfo_x86 *c)
        detect_ht(c);
 #endif
 
-       init_hypervisor(c);
        x86_init_rdrand(c);
        x86_init_cache_qos(c);
        setup_pku(c);
@@ -1526,6 +1566,9 @@ void cpu_init(void)
 
        if (is_uv_system())
                uv_cpu_init();
+
+       setup_fixmap_gdt(cpu);
+       load_fixmap_gdt(cpu);
 }
 
 #else
@@ -1581,6 +1624,9 @@ void cpu_init(void)
        dbg_restore_debug_regs();
 
        fpu__init_cpu();
+
+       setup_fixmap_gdt(cpu);
+       load_fixmap_gdt(cpu);
 }
 #endif