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

[Xen-devel] [PATCH v11 7/7] microcode: reject late ucode loading if any core is parked



If a core with all of its thread being parked, late ucode loading
which currently only loads ucode on online threads would lead to
differing ucode revisions in the system. In general, keeping ucode
revision consistent would be less error-prone. To this end, if there
is a parked thread doesn't have an online sibling thread, late ucode
loading is rejected.

Two threads are on the same core or computing unit iff they have
the same phys_proc_id and cpu_core_id/compute_unit_id. Based on
phys_proc_id and cpu_core_id/compute_unit_id, an unique core id
is generated for each thread. And use a bitmap to reduce the
number of comparison.

Signed-off-by: Chao Gao <chao.gao@xxxxxxxxx>
---
Alternatively, we can mask the thread id off apicid and use it
as the unique core id. It needs to introduce new field in cpuinfo_x86
to record the mask for thread id. So I don't take this way.
---
 xen/arch/x86/microcode.c        | 75 +++++++++++++++++++++++++++++++++++++++++
 xen/include/asm-x86/processor.h |  1 +
 2 files changed, 76 insertions(+)

diff --git a/xen/arch/x86/microcode.c b/xen/arch/x86/microcode.c
index b9fa8bb..b70eb16 100644
--- a/xen/arch/x86/microcode.c
+++ b/xen/arch/x86/microcode.c
@@ -573,6 +573,64 @@ static int do_microcode_update(void *patch)
     return ret;
 }
 
+static unsigned int unique_core_id(unsigned int cpu, unsigned int socket_shift)
+{
+    unsigned int core_id = cpu_to_cu(cpu);
+
+    if ( core_id == INVALID_CUID )
+        core_id = cpu_to_core(cpu);
+
+    return (cpu_to_socket(cpu) << socket_shift) + core_id;
+}
+
+static int has_parked_core(void)
+{
+    int ret = 0;
+
+    if ( park_offline_cpus )
+    {
+        unsigned int cpu, max_bits, core_width;
+        unsigned int max_sockets = 1, max_cores = 1;
+        struct cpuinfo_x86 *c = cpu_data;
+        unsigned long *bitmap;
+
+        for_each_present_cpu(cpu)
+        {
+            if ( x86_cpu_to_apicid[cpu] == BAD_APICID )
+                continue;
+
+            /* Note that cpu_to_socket() get an ID starting from 0. */
+            if ( cpu_to_socket(cpu) + 1 > max_sockets )
+                max_sockets = cpu_to_socket(cpu) + 1;
+
+            if ( c[cpu].x86_max_cores > max_cores )
+                max_cores = c[cpu].x86_max_cores;
+        }
+
+        core_width = fls(max_cores);
+        max_bits = max_sockets << core_width;
+        bitmap = xzalloc_array(unsigned long, BITS_TO_LONGS(max_bits));
+        if ( !bitmap )
+            return -ENOMEM;
+
+        for_each_present_cpu(cpu)
+        {
+            if ( cpu_online(cpu) || x86_cpu_to_apicid[cpu] == BAD_APICID )
+                continue;
+
+            __set_bit(unique_core_id(cpu, core_width), bitmap);
+        }
+
+        for_each_online_cpu(cpu)
+            __clear_bit(unique_core_id(cpu, core_width), bitmap);
+
+        ret = (find_first_bit(bitmap, max_bits) < max_bits);
+        xfree(bitmap);
+    }
+
+    return ret;
+}
+
 int microcode_update(XEN_GUEST_HANDLE_PARAM(const_void) buf, unsigned long len)
 {
     int ret;
@@ -611,6 +669,23 @@ int microcode_update(XEN_GUEST_HANDLE_PARAM(const_void) 
buf, unsigned long len)
      */
     ASSERT(cpumask_first(&cpu_online_map) == nmi_cpu);
 
+    /*
+     * If there is a core with all of its threads parked, late loading may
+     * cause differing ucode revisions in the system. Refuse this operation.
+     */
+    ret = has_parked_core();
+    if ( ret )
+    {
+        if ( ret > 0 )
+        {
+            printk(XENLOG_WARNING
+                   "Ucode loading aborted: found a parked core\n");
+            ret = -EPERM;
+        }
+        xfree(buffer);
+        goto put;
+    }
+
     patch = parse_blob(buffer, len);
     xfree(buffer);
     if ( IS_ERR(patch) )
diff --git a/xen/include/asm-x86/processor.h b/xen/include/asm-x86/processor.h
index c92956f..753deec 100644
--- a/xen/include/asm-x86/processor.h
+++ b/xen/include/asm-x86/processor.h
@@ -171,6 +171,7 @@ extern unsigned int init_intel_cacheinfo(struct cpuinfo_x86 
*c);
 
 #define cpu_to_core(_cpu)   (cpu_data[_cpu].cpu_core_id)
 #define cpu_to_socket(_cpu) (cpu_data[_cpu].phys_proc_id)
+#define cpu_to_cu(_cpu)     (cpu_data[_cpu].compute_unit_id)
 
 unsigned int apicid_to_socket(unsigned int);
 
-- 
1.8.3.1


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

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