[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen stable-4.7] x86: Move microcode loading earlier



commit 2c6ef37466526e96513629ac98ce30c7df508b5c
Author:     Ross Lagerwall <ross.lagerwall@xxxxxxxxxx>
AuthorDate: Thu Mar 22 10:23:21 2018 +0100
Commit:     Jan Beulich <jbeulich@xxxxxxxx>
CommitDate: Thu Mar 22 10:23:21 2018 +0100

    x86: Move microcode loading earlier
    
    Move microcode loading earlier for the boot CPU and secondary CPUs so
    that it takes place before identify_cpu() is called for each CPU.
    Without this, the detected features may be wrong if the new microcode
    loading adjusts the feature bits. That could mean that some fixes (e.g.
    d6e9f8d4f35d ("x86/vmx: fix vmentry failure with TSX bits in LBR"))
    don't work as expected.
    
    Previously during boot, the microcode loader was invoked for each
    secondary CPU started and then again for each CPU as part of an
    initcall. Simplify the code so that it is invoked exactly once for each
    CPU during boot.
    
    Signed-off-by: Ross Lagerwall <ross.lagerwall@xxxxxxxxxx>
    Reviewed-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
    Tested-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
    master commit: f97838bbd980a0104e16c4a12fbf514f9fa805f1
    master date: 2017-04-19 17:08:01 +0100
---
 xen/arch/x86/Makefile           |   1 -
 xen/arch/x86/cpu/common.c       |   2 +
 xen/arch/x86/microcode.c        | 131 +++++++++++++++++-----------------------
 xen/arch/x86/microcode_amd.c    |   3 +-
 xen/arch/x86/microcode_intel.c  |   3 +-
 xen/arch/x86/setup.c            |   2 +
 xen/arch/x86/smpboot.c          |  33 +++++-----
 xen/include/asm-x86/processor.h |   4 ++
 xen/include/xen/smp.h           |   2 +
 9 files changed, 85 insertions(+), 96 deletions(-)

diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile
index ad434262d6..271c8cf31e 100644
--- a/xen/arch/x86/Makefile
+++ b/xen/arch/x86/Makefile
@@ -38,7 +38,6 @@ obj-y += irq.o
 obj-$(CONFIG_KEXEC) += machine_kexec.o
 obj-y += microcode_amd.o
 obj-y += microcode_intel.o
-# This must come after the vendor specific files.
 obj-y += microcode.o
 obj-y += mm.o x86_64/mm.o
 obj-y += monitor.o
diff --git a/xen/arch/x86/cpu/common.c b/xen/arch/x86/cpu/common.c
index 50e9f330f4..7d4c5b46f3 100644
--- a/xen/arch/x86/cpu/common.c
+++ b/xen/arch/x86/cpu/common.c
@@ -251,6 +251,8 @@ static void __init early_cpu_detect(void)
                if (hap_paddr_bits > PADDR_BITS)
                        hap_paddr_bits = PADDR_BITS;
        }
+
+       initialize_cpu_data(0);
 }
 
 static void generic_identify(struct cpuinfo_x86 *c)
diff --git a/xen/arch/x86/microcode.c b/xen/arch/x86/microcode.c
index c20bde6676..807b51e56e 100644
--- a/xen/arch/x86/microcode.c
+++ b/xen/arch/x86/microcode.c
@@ -44,7 +44,6 @@ static module_t __initdata ucode_mod;
 static void *(*__initdata ucode_mod_map)(const module_t *);
 static signed int __initdata ucode_mod_idx;
 static bool_t __initdata ucode_mod_forced;
-static cpumask_t __initdata init_mask;
 
 /*
  * If we scan the initramfs.cpio for the early microcode code
@@ -342,50 +341,23 @@ int microcode_update(XEN_GUEST_HANDLE_PARAM(const_void) 
buf, unsigned long len)
     return continue_hypercall_on_cpu(info->cpu, do_microcode_update, info);
 }
 
-static void __init _do_microcode_update(unsigned long data)
-{
-    void *_data = (void *)data;
-    size_t len = ucode_blob.size ? ucode_blob.size : ucode_mod.mod_end;
-
-    microcode_update_cpu(_data, len);
-    cpumask_set_cpu(smp_processor_id(), &init_mask);
-}
-
 static int __init microcode_init(void)
 {
-    void *data;
-    static struct tasklet __initdata tasklet;
-    unsigned int cpu;
-
-    if ( !microcode_ops )
-        return 0;
-
-    if ( !ucode_mod.mod_end && !ucode_blob.size )
-        return 0;
-
-    data = ucode_blob.size ? ucode_blob.data : ucode_mod_map(&ucode_mod);
-
-    if ( !data )
-        return -ENOMEM;
-
-    if ( microcode_ops->start_update && microcode_ops->start_update() != 0 )
-        goto out;
-
-    softirq_tasklet_init(&tasklet, _do_microcode_update, (unsigned long)data);
-
-    for_each_online_cpu ( cpu )
+    /*
+     * At this point, all CPUs should have updated their microcode
+     * via the early_microcode_* paths so free the microcode blob.
+     */
+    if ( ucode_blob.size )
     {
-        tasklet_schedule_on_cpu(&tasklet, cpu);
-        do {
-            process_pending_softirqs();
-        } while ( !cpumask_test_cpu(cpu, &init_mask) );
+        xfree(ucode_blob.data);
+        ucode_blob.size = 0;
+        ucode_blob.data = NULL;
     }
-
-out:
-    if ( ucode_blob.size )
-        xfree(data);
-    else
+    else if ( ucode_mod.mod_end )
+    {
         ucode_mod_map(NULL);
+        ucode_mod.mod_end = 0;
+    }
 
     return 0;
 }
@@ -410,50 +382,55 @@ static struct notifier_block microcode_percpu_nfb = {
     .notifier_call = microcode_percpu_callback,
 };
 
-static int __init microcode_presmp_init(void)
+int __init early_microcode_update_cpu(bool_t start_update)
+{
+    int rc = 0;
+    void *data = NULL;
+    size_t len;
+
+    if ( ucode_blob.size )
+    {
+        len = ucode_blob.size;
+        data = ucode_blob.data;
+    }
+    else if ( ucode_mod.mod_end )
+    {
+        len = ucode_mod.mod_end;
+        data = ucode_mod_map(&ucode_mod);
+    }
+    if ( data )
+    {
+        if ( start_update && microcode_ops->start_update )
+            rc = microcode_ops->start_update();
+
+        if ( rc )
+            return rc;
+
+        return microcode_update_cpu(data, len);
+    }
+    else
+        return -ENOMEM;
+}
+
+int __init early_microcode_init(void)
 {
+    int rc;
+
+    rc = microcode_init_intel();
+    if ( rc )
+        return rc;
+
+    rc = microcode_init_amd();
+    if ( rc )
+        return rc;
+
     if ( microcode_ops )
     {
         if ( ucode_mod.mod_end || ucode_blob.size )
-        {
-            void *data;
-            size_t len;
-            int rc = 0;
-
-            if ( ucode_blob.size )
-            {
-                len = ucode_blob.size;
-                data = ucode_blob.data;
-            }
-            else
-            {
-                len = ucode_mod.mod_end;
-                data = ucode_mod_map(&ucode_mod);
-            }
-            if ( data )
-                rc = microcode_update_cpu(data, len);
-            else
-                rc = -ENOMEM;
-
-            if ( !ucode_blob.size )
-                ucode_mod_map(NULL);
-
-            if ( rc )
-            {
-                if ( ucode_blob.size )
-                {
-                    xfree(ucode_blob.data);
-                    ucode_blob.size = 0;
-                    ucode_blob.data = NULL;
-                }
-                else
-                    ucode_mod.mod_end = 0;
-            }
-        }
+            rc = early_microcode_update_cpu(1);
 
         register_cpu_notifier(&microcode_percpu_nfb);
     }
 
     return 0;
 }
-presmp_initcall(microcode_presmp_init);
diff --git a/xen/arch/x86/microcode_amd.c b/xen/arch/x86/microcode_amd.c
index f97b3de597..f494e996b1 100644
--- a/xen/arch/x86/microcode_amd.c
+++ b/xen/arch/x86/microcode_amd.c
@@ -632,10 +632,9 @@ static const struct microcode_ops microcode_amd_ops = {
     .start_update                     = start_update,
 };
 
-static __init int microcode_init_amd(void)
+int __init microcode_init_amd(void)
 {
     if ( boot_cpu_data.x86_vendor == X86_VENDOR_AMD )
         microcode_ops = &microcode_amd_ops;
     return 0;
 }
-presmp_initcall(microcode_init_amd);
diff --git a/xen/arch/x86/microcode_intel.c b/xen/arch/x86/microcode_intel.c
index 6949c25c99..56b07707e8 100644
--- a/xen/arch/x86/microcode_intel.c
+++ b/xen/arch/x86/microcode_intel.c
@@ -403,10 +403,9 @@ static const struct microcode_ops microcode_intel_ops = {
     .apply_microcode                  = apply_microcode,
 };
 
-static __init int microcode_init_intel(void)
+int __init microcode_init_intel(void)
 {
     if ( boot_cpu_data.x86_vendor == X86_VENDOR_INTEL )
         microcode_ops = &microcode_intel_ops;
     return 0;
 }
-presmp_initcall(microcode_init_intel);
diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c
index 01a8569ba9..f5051e3e35 100644
--- a/xen/arch/x86/setup.c
+++ b/xen/arch/x86/setup.c
@@ -1403,6 +1403,8 @@ void __init noreturn __start_xen(unsigned long mbi_p)
 
     timer_init();
 
+    early_microcode_init();
+
     identify_cpu(&boot_cpu_data);
 
     set_in_cr4(X86_CR4_OSFXSR | X86_CR4_OSXMMEXCPT);
diff --git a/xen/arch/x86/smpboot.c b/xen/arch/x86/smpboot.c
index eb567d3a64..e5305de47b 100644
--- a/xen/arch/x86/smpboot.c
+++ b/xen/arch/x86/smpboot.c
@@ -82,22 +82,22 @@ static enum cpu_state {
 
 void *stack_base[NR_CPUS];
 
+void initialize_cpu_data(unsigned int cpu)
+{
+    cpu_data[cpu] = boot_cpu_data;
+}
+
 static void smp_store_cpu_info(int id)
 {
-    struct cpuinfo_x86 *c = cpu_data + id;
     unsigned int socket;
 
-    *c = boot_cpu_data;
-    if ( id != 0 )
-    {
-        identify_cpu(c);
+    identify_cpu(&cpu_data[id]);
 
-        socket = cpu_to_socket(id);
-        if ( !socket_cpumask[socket] )
-        {
-            socket_cpumask[socket] = secondary_socket_cpumask;
-            secondary_socket_cpumask = NULL;
-        }
+    socket = cpu_to_socket(id);
+    if ( !socket_cpumask[socket] )
+    {
+        socket_cpumask[socket] = secondary_socket_cpumask;
+        secondary_socket_cpumask = NULL;
     }
 }
 
@@ -337,6 +337,13 @@ void start_secondary(void *unused)
 
     cpu_init();
 
+    initialize_cpu_data(cpu);
+
+    if ( system_state <= SYS_STATE_smp_boot )
+        early_microcode_update_cpu(0);
+    else
+        microcode_resume_cpu(cpu);
+
     smp_callin();
 
     setup_secondary_APIC_clock();
@@ -367,8 +374,6 @@ void start_secondary(void *unused)
     local_irq_enable();
     mtrr_ap_init();
 
-    microcode_resume_cpu(cpu);
-
     wmb();
     startup_cpu_idle_loop();
 }
@@ -1022,7 +1027,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
     mtrr_aps_sync_begin();
 
     /* Setup boot CPU information */
-    smp_store_cpu_info(0); /* Final full version of the data */
+    initialize_cpu_data(0); /* Final full version of the data */
     print_cpu_info(0);
 
     boot_cpu_physical_apicid = get_apic_id();
diff --git a/xen/include/asm-x86/processor.h b/xen/include/asm-x86/processor.h
index 9906f38f2d..7683d5ca51 100644
--- a/xen/include/asm-x86/processor.h
+++ b/xen/include/asm-x86/processor.h
@@ -617,6 +617,10 @@ int wrmsr_hypervisor_regs(uint32_t idx, uint64_t val);
 void microcode_set_module(unsigned int);
 int microcode_update(XEN_GUEST_HANDLE_PARAM(const_void), unsigned long len);
 int microcode_resume_cpu(unsigned int cpu);
+int early_microcode_update_cpu(bool_t start_update);
+int early_microcode_init(void);
+int microcode_init_intel(void);
+int microcode_init_amd(void);
 
 enum get_cpu_vendor {
    gcv_host_early,
diff --git a/xen/include/xen/smp.h b/xen/include/xen/smp.h
index 6febb5605c..c55f57f09e 100644
--- a/xen/include/xen/smp.h
+++ b/xen/include/xen/smp.h
@@ -71,4 +71,6 @@ int alloc_cpu_id(void);
 
 extern void *stack_base[NR_CPUS];
 
+void initialize_cpu_data(unsigned int cpu);
+
 #endif /* __XEN_SMP_H__ */
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.7

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/xen-changelog

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.