// SPDX-License-Identifier: GPL-2.0-or-later/* * CPU Microcode Update Driver for Linux * * Copyright (C) 2000-2006 Tigran Aivazian <aivazian.tigran@gmail.com> * 2006 Shaohua Li <shaohua.li@intel.com> * 2013-2016 Borislav Petkov <bp@alien8.de> * * X86 CPU microcode early update for Linux: * * Copyright (C) 2012 Fenghua Yu <fenghua.yu@intel.com> * H Peter Anvin" <hpa@zytor.com> * (C) 2015 Borislav Petkov <bp@alien8.de> * * This driver allows to upgrade microcode on x86 processors. */ #define pr_fmt(fmt) "microcode: " fmt #include <linux/platform_device.h>#include <linux/stop_machine.h>#include <linux/syscore_ops.h>#include <linux/miscdevice.h>#include <linux/capability.h>#include <linux/firmware.h>#include <linux/cpumask.h>#include <linux/kernel.h>#include <linux/delay.h>#include <linux/mutex.h>#include <linux/cpu.h>#include <linux/nmi.h>#include <linux/fs.h>#include <linux/mm.h> #include <asm/apic.h>#include <asm/cpu_device_id.h>#include <asm/perf_event.h>#include <asm/processor.h>#include <asm/cmdline.h>#include <asm/setup.h> #include "internal.h" static struct microcode_ops *microcode_ops;bool dis_ucode_ldr = true; bool force_minrev = IS_ENABLED(CONFIG_MICROCODE_LATE_FORCE_MINREV);module_param(force_minrev, bool, S_IRUSR | S_IWUSR); /* * Synchronization. * * All non cpu-hotplug-callback call sites use: * * - cpus_read_lock/unlock() to synchronize with * the cpu-hotplug-callback call sites. * * We guarantee that only a single cpu is being * updated at any particular moment of time. */struct ucode_cpu_info ucode_cpu_info[NR_CPUS]; /* * Those patch levels cannot be updated to newer ones and thus should be final. */static u32 final_levels[] = { 0x01000098, 0x0100009f, 0x010000af, 0, /* T-101 terminator */}; struct early_load_data early_data; /* * Check the current patch level on this CPU. * * Returns: * - true: if update should stop * - false: otherwise */static bool amd_check_current_patch_level(void){ u32 lvl, dummy, i; u32 *levels; native_rdmsr(MSR_AMD64_PATCH_LEVEL, lvl, dummy); levels = final_levels; for (i = 0; levels[i]; i++) { if (lvl == levels[i]) return true; } return false;} static bool __init check_loader_disabled_bsp(void){ static const char *__dis_opt_str = "dis_ucode_ldr"; const char *cmdline = boot_command_line; const char *option = __dis_opt_str; /* * CPUID(1).ECX[31]: reserved for hypervisor use. This is still not * completely accurate as xen pv guests don't see that CPUID bit set but * that's good enough as they don't land on the BSP path anyway. */ if (native_cpuid_ecx(1) & BIT(31)) return true; if (x86_cpuid_vendor() == X86_VENDOR_AMD) { if (amd_check_current_patch_level()) return true; } if (cmdline_find_option_bool(cmdline, option) <= 0) dis_ucode_ldr = false; return dis_ucode_ldr;} void __init load_ucode_bsp(void){ unsigned int cpuid_1_eax; bool intel = true; if (!have_cpuid_p()) return; cpuid_1_eax = native_cpuid_eax(1); switch (x86_cpuid_vendor()) { case X86_VENDOR_INTEL: if (x86_family(cpuid_1_eax) < 6) return; break; case X86_VENDOR_AMD: if (x86_family(cpuid_1_eax) < 0x10) return; intel = false; break; default: return; } if (check_loader_disabled_bsp()) return; if (intel) load_ucode_intel_bsp(&early_data); else load_ucode_amd_bsp(&early_data, cpuid_1_eax);} void load_ucode_ap(void){ unsigned int cpuid_1_eax; if (dis_ucode_ldr) return; cpuid_1_eax = native_cpuid_eax(1); switch (x86_cpuid_vendor()) { case X86_VENDOR_INTEL: if (x86_family(cpuid_1_eax) >= 6) load_ucode_intel_ap(); break; case X86_VENDOR_AMD: if (x86_family(cpuid_1_eax) >= 0x10) load_ucode_amd_ap(cpuid_1_eax); break; default: break; }} struct cpio_data __init find_microcode_in_initrd(const char *path){#ifdef CONFIG_BLK_DEV_INITRD unsigned long start = 0; size_t size; #ifdef CONFIG_X86_32 size = boot_params.hdr.ramdisk_size; /* Early load on BSP has a temporary mapping. */ if (size) start = initrd_start_early; #else /* CONFIG_X86_64 */ size = (unsigned long)boot_params.ext_ramdisk_size << 32; size |= boot_params.hdr.ramdisk_size; if (size) { start = (unsigned long)boot_params.ext_ramdisk_image << 32; start |= boot_params.hdr.ramdisk_image; start += PAGE_OFFSET; }#endif /* * Fixup the start address: after reserve_initrd() runs, initrd_start * has the virtual address of the beginning of the initrd. It also * possibly relocates the ramdisk. In either case, initrd_start contains * the updated address so use that instead. */ if (initrd_start) start = initrd_start; return find_cpio_data(path, (void *)start, size, NULL);#else /* !CONFIG_BLK_DEV_INITRD */ return (struct cpio_data){ NULL, 0, "" };#endif} static void reload_early_microcode(unsigned int cpu){ int vendor, family; vendor = x86_cpuid_vendor(); family = x86_cpuid_family(); switch (vendor) { case X86_VENDOR_INTEL: if (family >= 6) reload_ucode_intel(); break; case X86_VENDOR_AMD: if (family >= 0x10) reload_ucode_amd(cpu); break; default: break; }} /* fake device for request_firmware */static struct platform_device *microcode_pdev; #ifdef CONFIG_MICROCODE_LATE_LOADING/* * Late loading dance. Why the heavy-handed stomp_machine effort? * * - HT siblings must be idle and not execute other code while the other sibling * is loading microcode in order to avoid any negative interactions caused by * the loading. * * - In addition, microcode update on the cores must be serialized until this * requirement can be relaxed in the future. Right now, this is conservative * and good. */enum sibling_ctrl { /* Spinwait with timeout */ SCTRL_WAIT, /* Invoke the microcode_apply() callback */ SCTRL_APPLY, /* Proceed without invoking the microcode_apply() callback */ SCTRL_DONE,}; struct microcode_ctrl { enum sibling_ctrl ctrl; enum ucode_state result; unsigned int ctrl_cpu; bool nmi_enabled;}; DEFINE_STATIC_KEY_FALSE(microcode_nmi_handler_enable);static DEFINE_PER_CPU(struct microcode_ctrl, ucode_ctrl);static atomic_t late_cpus_in, offline_in_nmi;static unsigned int loops_per_usec;static cpumask_t cpu_offline_mask; static noinstr bool wait_for_cpus(atomic_t *cnt){ unsigned int timeout, loops; WARN_ON_ONCE(raw_atomic_dec_return(cnt) < 0); for (timeout = 0; timeout < USEC_PER_SEC; timeout++) { if (!raw_atomic_read(cnt)) return true; for (loops = 0; loops < loops_per_usec; loops++) cpu_relax(); /* If invoked directly, tickle the NMI watchdog */ if (!microcode_ops->use_nmi && !(timeout % USEC_PER_MSEC)) { instrumentation_begin(); touch_nmi_watchdog(); instrumentation_end(); } } /* Prevent the late comers from making progress and let them time out */ raw_atomic_inc(cnt); return false;} static noinstr bool wait_for_ctrl(void){ unsigned int timeout, loops; for (timeout = 0; timeout < USEC_PER_SEC; timeout++) { if (raw_cpu_read(ucode_ctrl.ctrl) != SCTRL_WAIT) return true; for (loops = 0; loops < loops_per_usec; loops++) cpu_relax(); /* If invoked directly, tickle the NMI watchdog */ if (!microcode_ops->use_nmi && !(timeout % USEC_PER_MSEC)) { instrumentation_begin(); touch_nmi_watchdog(); instrumentation_end(); } } return false;} /* * Protected against instrumentation up to the point where the primary * thread completed the update. See microcode_nmi_handler() for details. */static noinstr bool load_secondary_wait(unsigned int ctrl_cpu){ /* Initial rendezvous to ensure that all CPUs have arrived */ if (!wait_for_cpus(&late_cpus_in)) { raw_cpu_write(ucode_ctrl.result, UCODE_TIMEOUT); return false; } /* * Wait for primary threads to complete. If one of them hangs due * to the update, there is no way out. This is non-recoverable * because the CPU might hold locks or resources and confuse the * scheduler, watchdogs etc. There is no way to safely evacuate the * machine. */ if (wait_for_ctrl()) return true; instrumentation_begin(); panic("Microcode load: Primary CPU %d timed out\n", ctrl_cpu); instrumentation_end();} /* * Protected against instrumentation up to the point where the primary * thread completed the update. See microcode_nmi_handler() for details. */static noinstr void load_secondary(unsigned int cpu){ unsigned int ctrl_cpu = raw_cpu_read(ucode_ctrl.ctrl_cpu); enum ucode_state ret; if (!load_secondary_wait(ctrl_cpu)) { instrumentation_begin(); pr_err_once("load: %d CPUs timed out\n", atomic_read(&late_cpus_in) - 1); instrumentation_end(); return; } /* Primary thread completed. Allow to invoke instrumentable code */ instrumentation_begin(); /* * If the primary succeeded then invoke the apply() callback, * otherwise copy the state from the primary thread. */ if (this_cpu_read(ucode_ctrl.ctrl) == SCTRL_APPLY) ret = microcode_ops->apply_microcode(cpu); else ret = per_cpu(ucode_ctrl.result, ctrl_cpu); this_cpu_write(ucode_ctrl.result, ret); this_cpu_write(ucode_ctrl.ctrl, SCTRL_DONE); instrumentation_end();} static void __load_primary(unsigned int cpu){ struct cpumask *secondaries = topology_sibling_cpumask(cpu); enum sibling_ctrl ctrl; enum ucode_state ret; unsigned int sibling; /* Initial rendezvous to ensure that all CPUs have arrived */ if (!wait_for_cpus(&late_cpus_in)) { this_cpu_write(ucode_ctrl.result, UCODE_TIMEOUT); pr_err_once("load: %d CPUs timed out\n", atomic_read(&late_cpus_in) - 1); return; } ret = microcode_ops->apply_microcode(cpu); this_cpu_write(ucode_ctrl.result, ret); this_cpu_write(ucode_ctrl.ctrl, SCTRL_DONE); /* * If the update was successful, let the siblings run the apply() * callback. If not, tell them it's done. This also covers the * case where the CPU has uniform loading at package or system * scope implemented but does not advertise it. */ if (ret == UCODE_UPDATED || ret == UCODE_OK) ctrl = SCTRL_APPLY; else ctrl = SCTRL_DONE; for_each_cpu(sibling, secondaries) { if (sibling != cpu) per_cpu(ucode_ctrl.ctrl, sibling) = ctrl; }} static bool kick_offline_cpus(unsigned int nr_offl){ unsigned int cpu, timeout; for_each_cpu(cpu, &cpu_offline_mask) { /* Enable the rendezvous handler and send NMI */ per_cpu(ucode_ctrl.nmi_enabled, cpu) = true; apic_send_nmi_to_offline_cpu(cpu); } /* Wait for them to arrive */ for (timeout = 0; timeout < (USEC_PER_SEC / 2); timeout++) { if (atomic_read(&offline_in_nmi) == nr_offl) return true; udelay(1); } /* Let the others time out */ return false;} static void release_offline_cpus(void){ unsigned int cpu; for_each_cpu(cpu, &cpu_offline_mask) per_cpu(ucode_ctrl.ctrl, cpu) = SCTRL_DONE;} static void load_primary(unsigned int cpu){ unsigned int nr_offl = cpumask_weight(&cpu_offline_mask); bool proceed = true; /* Kick soft-offlined SMT siblings if required */ if (!cpu && nr_offl) proceed = kick_offline_cpus(nr_offl); /* If the soft-offlined CPUs did not respond, abort */ if (proceed) __load_primary(cpu); /* Unconditionally release soft-offlined SMT siblings if required */ if (!cpu && nr_offl) release_offline_cpus();} /* * Minimal stub rendezvous handler for soft-offlined CPUs which participate * in the NMI rendezvous to protect against a concurrent NMI on affected * CPUs. */void noinstr microcode_offline_nmi_handler(void){ if (!raw_cpu_read(ucode_ctrl.nmi_enabled)) return; raw_cpu_write(ucode_ctrl.nmi_enabled, false); raw_cpu_write(ucode_ctrl.result, UCODE_OFFLINE); raw_atomic_inc(&offline_in_nmi); wait_for_ctrl();} static noinstr bool microcode_update_handler(void){ unsigned int cpu = raw_smp_processor_id(); if (raw_cpu_read(ucode_ctrl.ctrl_cpu) == cpu) { instrumentation_begin(); load_primary(cpu); instrumentation_end(); } else { load_secondary(cpu); } instrumentation_begin(); touch_nmi_watchdog(); instrumentation_end(); return true;} /* * Protection against instrumentation is required for CPUs which are not * safe against an NMI which is delivered to the secondary SMT siblingLines 1–500 of 856. Load more
// SPDX-License-Identifier: GPL-2.0-or-later /* * CPU Microcode Update Driver for Linux * * Copyright (C) 2000-2006 Tigran Aivazian <aivazian.tigran@gmail.com> * 2006 Shaohua Li <shaohua.li@intel.com> * 2013-2016 Borislav Petkov <bp@alien8.de> * * X86 CPU microcode early update for Linux: * * Copyright (C) 2012 Fenghua Yu <fenghua.yu@intel.com> * H Peter Anvin" <hpa@zytor.com> * (C) 2015 Borislav Petkov <bp@alien8.de> * * This driver allows to upgrade microcode on x86 processors. */ #define pr_fmt(fmt) "microcode: " fmt #include <linux/platform_device.h> #include <linux/stop_machine.h> #include <linux/syscore_ops.h> #include <linux/miscdevice.h> #include <linux/capability.h> #include <linux/firmware.h> #include <linux/cpumask.h> #include <linux/kernel.h> #include <linux/delay.h> #include <linux/mutex.h> #include <linux/cpu.h> #include <linux/nmi.h> #include <linux/fs.h> #include <linux/mm.h> #include <asm/apic.h> #include <asm/cpu_device_id.h> #include <asm/perf_event.h> #include <asm/processor.h> #include <asm/cmdline.h> #include <asm/setup.h> #include "internal.h" static struct microcode_ops *microcode_ops; bool dis_ucode_ldr = true; bool force_minrev = IS_ENABLED(CONFIG_MICROCODE_LATE_FORCE_MINREV); module_param(force_minrev, bool, S_IRUSR | S_IWUSR); /* * Synchronization. * * All non cpu-hotplug-callback call sites use: * * - cpus_read_lock/unlock() to synchronize with * the cpu-hotplug-callback call sites. * * We guarantee that only a single cpu is being * updated at any particular moment of time. */ struct ucode_cpu_info ucode_cpu_info[NR_CPUS]; /* * Those patch levels cannot be updated to newer ones and thus should be final. */ static u32 final_levels[] = { 0x01000098, 0x0100009f, 0x010000af, 0, /* T-101 terminator */ }; struct early_load_data early_data; /* * Check the current patch level on this CPU. * * Returns: * - true: if update should stop * - false: otherwise */ static bool amd_check_current_patch_level(void) { u32 lvl, dummy, i; u32 *levels; native_rdmsr(MSR_AMD64_PATCH_LEVEL, lvl, dummy); levels = final_levels; for (i = 0; levels[i]; i++) { if (lvl == levels[i]) return true; } return false; } static bool __init check_loader_disabled_bsp(void) { static const char *__dis_opt_str = "dis_ucode_ldr"; const char *cmdline = boot_command_line; const char *option = __dis_opt_str; /* * CPUID(1).ECX[31]: reserved for hypervisor use. This is still not * completely accurate as xen pv guests don't see that CPUID bit set but * that's good enough as they don't land on the BSP path anyway. */ if (native_cpuid_ecx(1) & BIT(31)) return true; if (x86_cpuid_vendor() == X86_VENDOR_AMD) { if (amd_check_current_patch_level()) return true; } if (cmdline_find_option_bool(cmdline, option) <= 0) dis_ucode_ldr = false; return dis_ucode_ldr; } void __init load_ucode_bsp(void) { unsigned int cpuid_1_eax; bool intel = true; if (!have_cpuid_p()) return; cpuid_1_eax = native_cpuid_eax(1); switch (x86_cpuid_vendor()) { case X86_VENDOR_INTEL: if (x86_family(cpuid_1_eax) < 6) return; break; case X86_VENDOR_AMD: if (x86_family(cpuid_1_eax) < 0x10) return; intel = false; break; default: return; } if (check_loader_disabled_bsp()) return; if (intel) load_ucode_intel_bsp(&early_data); else load_ucode_amd_bsp(&early_data, cpuid_1_eax); } void load_ucode_ap(void) { unsigned int cpuid_1_eax; if (dis_ucode_ldr) return; cpuid_1_eax = native_cpuid_eax(1); switch (x86_cpuid_vendor()) { case X86_VENDOR_INTEL: if (x86_family(cpuid_1_eax) >= 6) load_ucode_intel_ap(); break; case X86_VENDOR_AMD: if (x86_family(cpuid_1_eax) >= 0x10) load_ucode_amd_ap(cpuid_1_eax); break; default: break; } } struct cpio_data __init find_microcode_in_initrd(const char *path) { #ifdef CONFIG_BLK_DEV_INITRD unsigned long start = 0; size_t size; #ifdef CONFIG_X86_32 size = boot_params.hdr.ramdisk_size; /* Early load on BSP has a temporary mapping. */ if (size) start = initrd_start_early; #else /* CONFIG_X86_64 */ size = (unsigned long)boot_params.ext_ramdisk_size << 32; size |= boot_params.hdr.ramdisk_size; if (size) { start = (unsigned long)boot_params.ext_ramdisk_image << 32; start |= boot_params.hdr.ramdisk_image; start += PAGE_OFFSET; } #endif /* * Fixup the start address: after reserve_initrd() runs, initrd_start * has the virtual address of the beginning of the initrd. It also * possibly relocates the ramdisk. In either case, initrd_start contains * the updated address so use that instead. */ if (initrd_start) start = initrd_start; return find_cpio_data(path, (void *)start, size, NULL); #else /* !CONFIG_BLK_DEV_INITRD */ return (struct cpio_data){ NULL, 0, "" }; #endif } static void reload_early_microcode(unsigned int cpu) { int vendor, family; vendor = x86_cpuid_vendor(); family = x86_cpuid_family(); switch (vendor) { case X86_VENDOR_INTEL: if (family >= 6) reload_ucode_intel(); break; case X86_VENDOR_AMD: if (family >= 0x10) reload_ucode_amd(cpu); break; default: break; } } /* fake device for request_firmware */ static struct platform_device *microcode_pdev; #ifdef CONFIG_MICROCODE_LATE_LOADING /* * Late loading dance. Why the heavy-handed stomp_machine effort? * * - HT siblings must be idle and not execute other code while the other sibling * is loading microcode in order to avoid any negative interactions caused by * the loading. * * - In addition, microcode update on the cores must be serialized until this * requirement can be relaxed in the future. Right now, this is conservative * and good. */ enum sibling_ctrl { /* Spinwait with timeout */ SCTRL_WAIT, /* Invoke the microcode_apply() callback */ SCTRL_APPLY, /* Proceed without invoking the microcode_apply() callback */ SCTRL_DONE, }; struct microcode_ctrl { enum sibling_ctrl ctrl; enum ucode_state result; unsigned int ctrl_cpu; bool nmi_enabled; }; DEFINE_STATIC_KEY_FALSE(microcode_nmi_handler_enable); static DEFINE_PER_CPU(struct microcode_ctrl, ucode_ctrl); static atomic_t late_cpus_in, offline_in_nmi; static unsigned int loops_per_usec; static cpumask_t cpu_offline_mask; static noinstr bool wait_for_cpus(atomic_t *cnt) { unsigned int timeout, loops; WARN_ON_ONCE(raw_atomic_dec_return(cnt) < 0); for (timeout = 0; timeout < USEC_PER_SEC; timeout++) { if (!raw_atomic_read(cnt)) return true; for (loops = 0; loops < loops_per_usec; loops++) cpu_relax(); /* If invoked directly, tickle the NMI watchdog */ if (!microcode_ops->use_nmi && !(timeout % USEC_PER_MSEC)) { instrumentation_begin(); touch_nmi_watchdog(); instrumentation_end(); } } /* Prevent the late comers from making progress and let them time out */ raw_atomic_inc(cnt); return false; } static noinstr bool wait_for_ctrl(void) { unsigned int timeout, loops; for (timeout = 0; timeout < USEC_PER_SEC; timeout++) { if (raw_cpu_read(ucode_ctrl.ctrl) != SCTRL_WAIT) return true; for (loops = 0; loops < loops_per_usec; loops++) cpu_relax(); /* If invoked directly, tickle the NMI watchdog */ if (!microcode_ops->use_nmi && !(timeout % USEC_PER_MSEC)) { instrumentation_begin(); touch_nmi_watchdog(); instrumentation_end(); } } return false; } /* * Protected against instrumentation up to the point where the primary * thread completed the update. See microcode_nmi_handler() for details. */ static noinstr bool load_secondary_wait(unsigned int ctrl_cpu) { /* Initial rendezvous to ensure that all CPUs have arrived */ if (!wait_for_cpus(&late_cpus_in)) { raw_cpu_write(ucode_ctrl.result, UCODE_TIMEOUT); return false; } /* * Wait for primary threads to complete. If one of them hangs due * to the update, there is no way out. This is non-recoverable * because the CPU might hold locks or resources and confuse the * scheduler, watchdogs etc. There is no way to safely evacuate the * machine. */ if (wait_for_ctrl()) return true; instrumentation_begin(); panic("Microcode load: Primary CPU %d timed out\n", ctrl_cpu); instrumentation_end(); } /* * Protected against instrumentation up to the point where the primary * thread completed the update. See microcode_nmi_handler() for details. */ static noinstr void load_secondary(unsigned int cpu) { unsigned int ctrl_cpu = raw_cpu_read(ucode_ctrl.ctrl_cpu); enum ucode_state ret; if (!load_secondary_wait(ctrl_cpu)) { instrumentation_begin(); pr_err_once("load: %d CPUs timed out\n", atomic_read(&late_cpus_in) - 1); instrumentation_end(); return; } /* Primary thread completed. Allow to invoke instrumentable code */ instrumentation_begin(); /* * If the primary succeeded then invoke the apply() callback, * otherwise copy the state from the primary thread. */ if (this_cpu_read(ucode_ctrl.ctrl) == SCTRL_APPLY) ret = microcode_ops->apply_microcode(cpu); else ret = per_cpu(ucode_ctrl.result, ctrl_cpu); this_cpu_write(ucode_ctrl.result, ret); this_cpu_write(ucode_ctrl.ctrl, SCTRL_DONE); instrumentation_end(); } static void __load_primary(unsigned int cpu) { struct cpumask *secondaries = topology_sibling_cpumask(cpu); enum sibling_ctrl ctrl; enum ucode_state ret; unsigned int sibling; /* Initial rendezvous to ensure that all CPUs have arrived */ if (!wait_for_cpus(&late_cpus_in)) { this_cpu_write(ucode_ctrl.result, UCODE_TIMEOUT); pr_err_once("load: %d CPUs timed out\n", atomic_read(&late_cpus_in) - 1); return; } ret = microcode_ops->apply_microcode(cpu); this_cpu_write(ucode_ctrl.result, ret); this_cpu_write(ucode_ctrl.ctrl, SCTRL_DONE); /* * If the update was successful, let the siblings run the apply() * callback. If not, tell them it's done. This also covers the * case where the CPU has uniform loading at package or system * scope implemented but does not advertise it. */ if (ret == UCODE_UPDATED || ret == UCODE_OK) ctrl = SCTRL_APPLY; else ctrl = SCTRL_DONE; for_each_cpu(sibling, secondaries) { if (sibling != cpu) per_cpu(ucode_ctrl.ctrl, sibling) = ctrl; } } static bool kick_offline_cpus(unsigned int nr_offl) { unsigned int cpu, timeout; for_each_cpu(cpu, &cpu_offline_mask) { /* Enable the rendezvous handler and send NMI */ per_cpu(ucode_ctrl.nmi_enabled, cpu) = true; apic_send_nmi_to_offline_cpu(cpu); } /* Wait for them to arrive */ for (timeout = 0; timeout < (USEC_PER_SEC / 2); timeout++) { if (atomic_read(&offline_in_nmi) == nr_offl) return true; udelay(1); } /* Let the others time out */ return false; } static void release_offline_cpus(void) { unsigned int cpu; for_each_cpu(cpu, &cpu_offline_mask) per_cpu(ucode_ctrl.ctrl, cpu) = SCTRL_DONE; } static void load_primary(unsigned int cpu) { unsigned int nr_offl = cpumask_weight(&cpu_offline_mask); bool proceed = true; /* Kick soft-offlined SMT siblings if required */ if (!cpu && nr_offl) proceed = kick_offline_cpus(nr_offl); /* If the soft-offlined CPUs did not respond, abort */ if (proceed) __load_primary(cpu); /* Unconditionally release soft-offlined SMT siblings if required */ if (!cpu && nr_offl) release_offline_cpus(); } /* * Minimal stub rendezvous handler for soft-offlined CPUs which participate * in the NMI rendezvous to protect against a concurrent NMI on affected * CPUs. */ void noinstr microcode_offline_nmi_handler(void) { if (!raw_cpu_read(ucode_ctrl.nmi_enabled)) return; raw_cpu_write(ucode_ctrl.nmi_enabled, false); raw_cpu_write(ucode_ctrl.result, UCODE_OFFLINE); raw_atomic_inc(&offline_in_nmi); wait_for_ctrl(); } static noinstr bool microcode_update_handler(void) { unsigned int cpu = raw_smp_processor_id(); if (raw_cpu_read(ucode_ctrl.ctrl_cpu) == cpu) { instrumentation_begin(); load_primary(cpu); instrumentation_end(); } else { load_secondary(cpu); } instrumentation_begin(); touch_nmi_watchdog(); instrumentation_end(); return true; } /* * Protection against instrumentation is required for CPUs which are not * safe against an NMI which is delivered to the secondary SMT sibling