]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
cpu/hotplug: Boot HT siblings at least once
authorThomas Gleixner <tglx@linutronix.de>
Fri, 29 Jun 2018 14:05:48 +0000 (16:05 +0200)
committerKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Sat, 11 Aug 2018 00:44:37 +0000 (20:44 -0400)
Due to the way Machine Check Exceptions work on X86 hyperthreads it's
required to boot up _all_ logical cores at least once in order to set the
CR4.MCE bit.

So instead of ignoring the sibling threads right away, let them boot up
once so they can configure themselves. After they came out of the initial
boot stage check whether its a "secondary" sibling and cancel the operation
which puts the CPU back into offline state.

Reported-by: Dave Hansen <dave.hansen@intel.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Tony Luck <tony.luck@intel.com>
Orabug: 28220674
CVE: CVE-2018-3620

(cherry picked from commit 0cc3cd21657be04cb0559fe8063f2130493f92cf)

Signed-off-by: Mihai Carabas <mihai.carabas@oracle.com>
Reviewed-by: Darren Kenny <darren.kenny@oracle.com>
Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Conflicts:
kernel/cpu.c
Contextual: The following changes were applied to the initial commit:
- used a per-cpu variable booted_once because struct cpuhp_cpu_state doesn't
exist in the current version
- cpu_smt_allowed check from bringup_wait_for_ap is done in _cpu_up
- taking into account that boot_cpu_state_init doesn't exist in the current
version (it was added by cff7d378: cpu/hotplug: Convert to a state machine
for the control processor), the per-cpu variable booted_once isn't made static
and it is set on true in start_kernel

include/linux/cpu.h
init/main.c
kernel/cpu.c

index b7c865c997adc1acc17e039b7e68925f56a07b7d..3c58810123e4e0bcbef6bae2fbeb9ddc8ae57b6f 100644 (file)
@@ -298,6 +298,7 @@ void arch_cpu_idle_exit(void);
 void arch_cpu_idle_dead(void);
 
 DECLARE_PER_CPU(bool, cpu_dead_idle);
+DECLARE_PER_CPU(bool, booted_once);
 
 int cpu_report_state(int cpu);
 int cpu_check_up_prepare(int cpu);
index 1b124c04e1578534109ff771d84fd72df2fcd471..1b9ee932507db0ab6ee29b6fe1441ed5c58424f7 100644 (file)
@@ -533,6 +533,7 @@ asmlinkage __visible void __init start_kernel(void)
        setup_command_line(command_line);
        setup_nr_cpu_ids();
        setup_per_cpu_areas();
+       this_cpu_write(booted_once, true);
        smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */
 
        build_all_zonelists(NULL, NULL);
index 217e6501c0f6f1ae004089dca79b40df915e9050..0383a1eee12e9e2c1473c86c94fb5d9077ac5b91 100644 (file)
@@ -29,6 +29,7 @@
 #ifdef CONFIG_SMP
 /* Serializes the updates to cpu_online_mask, cpu_present_mask */
 static DEFINE_MUTEX(cpu_add_remove_lock);
+DEFINE_PER_CPU(bool, booted_once);
 
 /*
  * The following two APIs (cpu_maps_update_begin/done) must be used when
@@ -510,8 +511,19 @@ early_param("nosmt", smt_cmdline_disable);
 
 static inline bool cpu_smt_allowed(unsigned int cpu)
 {
-       return cpu_smt_control == CPU_SMT_ENABLED ||
-               topology_is_primary_thread(cpu);
+       if (cpu_smt_control == CPU_SMT_ENABLED)
+               return true;
+
+       if (topology_is_primary_thread(cpu))
+               return true;
+
+       /*
+        * On x86 it's required to boot all logical CPUs at least once so
+        * that the init code can get a chance to set CR4.MCE on each
+        * CPU. Otherwise, a broadacasted MCE observing CR4.MCE=0b on any
+        * core will shutdown the machine.
+        */
+       return !per_cpu(booted_once, cpu);
 }
 #else
 static inline bool cpu_smt_allowed(unsigned int cpu) { return true; }
@@ -566,6 +578,18 @@ out_notify:
 out:
        cpu_hotplug_done();
 
+       /*
+        * SMT soft disabling on X86 requires to bring the CPU out of the
+        * BIOS 'wait for SIPI' state in order to set the CR4.MCE bit.  The
+        * CPU marked itself as booted_once in cpu_notify_starting() so the
+        * cpu_smt_allowed() check will now return false if this is not the
+        * primary sibling.
+       */
+       if (!cpu_smt_allowed(cpu)) {
+               _cpu_down(cpu, 0);
+               ret = -ECANCELED;
+       }
+
        return ret;
 }
 
@@ -760,6 +784,7 @@ void notify_cpu_starting(unsigned int cpu)
        if (frozen_cpus != NULL && cpumask_test_cpu(cpu, frozen_cpus))
                val = CPU_STARTING_FROZEN;
 #endif /* CONFIG_PM_SLEEP_SMP */
+       this_cpu_write(booted_once, true);
        cpu_notify(val, (void *)(long)cpu);
 }