From: Greg Kroah-Hartman Date: Wed, 5 Mar 2025 17:25:00 +0000 (+0100) Subject: 6.6-stable patches X-Git-Tag: v6.6.81~10 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=cc9d1491c45b02f166277ed716edcb8a9d215f47;p=thirdparty%2Fkernel%2Fstable-queue.git 6.6-stable patches added patches: x86-apic-provide-apic_force_nmi_on_cpu.patch x86-microcode-32-move-early-loading-after-paging-enable.patch x86-microcode-add-per-cpu-control-field.patch x86-microcode-add-per-cpu-result-state.patch x86-microcode-amd-add-get_patch_level.patch x86-microcode-amd-cache-builtin-initrd-microcode-early.patch x86-microcode-amd-cache-builtin-microcode-too.patch x86-microcode-amd-flush-patch-buffer-mapping-after-application.patch x86-microcode-amd-get-rid-of-the-_load_microcode_amd-forward-declaration.patch x86-microcode-amd-have-__apply_microcode_amd-return-bool.patch x86-microcode-amd-load-only-sha256-checksummed-patches.patch x86-microcode-amd-make-__verify_patch_size-return-bool.patch x86-microcode-amd-merge-early_apply_microcode-into-its-single-callsite.patch x86-microcode-amd-pay-attention-to-the-stepping-dynamically.patch x86-microcode-amd-return-bool-from-find_blobs_in_containers.patch x86-microcode-amd-split-load_microcode_amd.patch x86-microcode-amd-use-cached-microcode-for-ap-load.patch x86-microcode-amd-use-correct-per-cpu-ucode_cpu_info.patch x86-microcode-amd-use-the-family-model-stepping-encoded-in-the-patch-id.patch x86-microcode-clarify-the-late-load-logic.patch x86-microcode-clean-up-mc_cpu_down_prep.patch x86-microcode-get-rid-of-the-schedule-work-indirection.patch x86-microcode-handle-nosmt-correctly.patch x86-microcode-handle-offline-cpus-correctly.patch x86-microcode-intel-cleanup-code-further.patch x86-microcode-intel-remove-unnecessary-cache-writeback-and-invalidation.patch x86-microcode-intel-reuse-intel_cpu_collect_info.patch x86-microcode-intel-rework-intel_cpu_collect_info.patch x86-microcode-intel-rework-intel_find_matching_signature.patch x86-microcode-intel-rip-out-mixed-stepping-support-for-intel-cpus.patch x86-microcode-intel-save-the-microcode-only-after-a-successful-late-load.patch x86-microcode-intel-set-new-revision-only-after-a-successful-update.patch x86-microcode-intel-simplify-and-rename-generic_load_microcode.patch x86-microcode-intel-simplify-early-loading.patch x86-microcode-intel-simplify-scan_microcode.patch x86-microcode-intel-switch-to-kvmalloc.patch x86-microcode-intel-unify-microcode-apply-functions.patch x86-microcode-mop-up-early-loading-leftovers.patch x86-microcode-prepare-for-minimal-revision-check.patch x86-microcode-protect-against-instrumentation.patch x86-microcode-provide-new-control-functions.patch x86-microcode-remove-pointless-apply-invocation.patch x86-microcode-rendezvous-and-load-in-nmi.patch x86-microcode-replace-the-all-in-one-rendevous-handler.patch x86-microcode-rework-early-revisions-reporting.patch x86-microcode-sanitize-__wait_for_cpus.patch --- diff --git a/queue-6.6/series b/queue-6.6/series index 902b7aa05b..2ea5dee5bd 100644 --- a/queue-6.6/series +++ b/queue-6.6/series @@ -97,3 +97,49 @@ tun-add-missing-bpf_net_ctx_clear-in-do_xdp_generic.patch gve-set-xdp-redirect-target-only-when-it-is-available.patch intel_idle-handle-older-cpus-which-stop-the-tsc-in-deeper-c-states-correctly.patch arm64-dts-rockchip-disable-dma-for-uart5-on-px30-ringneck.patch +x86-microcode-32-move-early-loading-after-paging-enable.patch +x86-microcode-intel-rip-out-mixed-stepping-support-for-intel-cpus.patch +x86-microcode-intel-simplify-scan_microcode.patch +x86-microcode-intel-simplify-and-rename-generic_load_microcode.patch +x86-microcode-intel-cleanup-code-further.patch +x86-microcode-intel-simplify-early-loading.patch +x86-microcode-intel-save-the-microcode-only-after-a-successful-late-load.patch +x86-microcode-intel-switch-to-kvmalloc.patch +x86-microcode-intel-unify-microcode-apply-functions.patch +x86-microcode-intel-rework-intel_cpu_collect_info.patch +x86-microcode-intel-reuse-intel_cpu_collect_info.patch +x86-microcode-intel-rework-intel_find_matching_signature.patch +x86-microcode-remove-pointless-apply-invocation.patch +x86-microcode-amd-use-correct-per-cpu-ucode_cpu_info.patch +x86-microcode-amd-cache-builtin-microcode-too.patch +x86-microcode-amd-cache-builtin-initrd-microcode-early.patch +x86-microcode-amd-use-cached-microcode-for-ap-load.patch +x86-microcode-mop-up-early-loading-leftovers.patch +x86-microcode-get-rid-of-the-schedule-work-indirection.patch +x86-microcode-clean-up-mc_cpu_down_prep.patch +x86-microcode-handle-nosmt-correctly.patch +x86-microcode-clarify-the-late-load-logic.patch +x86-microcode-sanitize-__wait_for_cpus.patch +x86-microcode-add-per-cpu-result-state.patch +x86-microcode-add-per-cpu-control-field.patch +x86-microcode-provide-new-control-functions.patch +x86-microcode-replace-the-all-in-one-rendevous-handler.patch +x86-microcode-rendezvous-and-load-in-nmi.patch +x86-microcode-protect-against-instrumentation.patch +x86-apic-provide-apic_force_nmi_on_cpu.patch +x86-microcode-handle-offline-cpus-correctly.patch +x86-microcode-prepare-for-minimal-revision-check.patch +x86-microcode-rework-early-revisions-reporting.patch +x86-microcode-intel-set-new-revision-only-after-a-successful-update.patch +x86-microcode-amd-use-the-family-model-stepping-encoded-in-the-patch-id.patch +x86-microcode-amd-pay-attention-to-the-stepping-dynamically.patch +x86-microcode-amd-split-load_microcode_amd.patch +x86-microcode-intel-remove-unnecessary-cache-writeback-and-invalidation.patch +x86-microcode-amd-flush-patch-buffer-mapping-after-application.patch +x86-microcode-amd-return-bool-from-find_blobs_in_containers.patch +x86-microcode-amd-make-__verify_patch_size-return-bool.patch +x86-microcode-amd-have-__apply_microcode_amd-return-bool.patch +x86-microcode-amd-merge-early_apply_microcode-into-its-single-callsite.patch +x86-microcode-amd-get-rid-of-the-_load_microcode_amd-forward-declaration.patch +x86-microcode-amd-add-get_patch_level.patch +x86-microcode-amd-load-only-sha256-checksummed-patches.patch diff --git a/queue-6.6/x86-apic-provide-apic_force_nmi_on_cpu.patch b/queue-6.6/x86-apic-provide-apic_force_nmi_on_cpu.patch new file mode 100644 index 0000000000..680867b9b2 --- /dev/null +++ b/queue-6.6/x86-apic-provide-apic_force_nmi_on_cpu.patch @@ -0,0 +1,113 @@ +From 086f78d30a378e824e4743080fc6fe22254a42c4 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Mon, 2 Oct 2023 14:00:07 +0200 +Subject: x86/apic: Provide apic_force_nmi_on_cpu() + +From: Thomas Gleixner + +commit 9cab5fb776d4367e26950cf759211e948335288e upstream + +When SMT siblings are soft-offlined and parked in one of the play_dead() +variants they still react on NMI, which is problematic on affected Intel +CPUs. The default play_dead() variant uses MWAIT on modern CPUs, which is +not guaranteed to be safe when updated concurrently. + +Right now late loading is prevented when not all SMT siblings are online, +but as they still react on NMI, it is possible to bring them out of their +park position into a trivial rendezvous handler. + +Provide a function which allows to do that. I does sanity checks whether +the target is in the cpus_booted_once_mask and whether the APIC driver +supports it. + +Mark X2APIC and XAPIC as capable, but exclude 32bit and the UV and NUMACHIP +variants as that needs feedback from the relevant experts. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Borislav Petkov (AMD) +Link: https://lore.kernel.org/r/20231002115903.603100036@linutronix.de +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/include/asm/apic.h | 5 ++++- + arch/x86/kernel/apic/apic_flat_64.c | 2 ++ + arch/x86/kernel/apic/ipi.c | 8 ++++++++ + arch/x86/kernel/apic/x2apic_cluster.c | 1 + + arch/x86/kernel/apic/x2apic_phys.c | 1 + + 5 files changed, 16 insertions(+), 1 deletion(-) + +--- a/arch/x86/include/asm/apic.h ++++ b/arch/x86/include/asm/apic.h +@@ -277,7 +277,8 @@ struct apic { + + u32 disable_esr : 1, + dest_mode_logical : 1, +- x2apic_set_max_apicid : 1; ++ x2apic_set_max_apicid : 1, ++ nmi_to_offline_cpu : 1; + + u32 (*calc_dest_apicid)(unsigned int cpu); + +@@ -543,6 +544,8 @@ extern bool default_check_apicid_used(ph + extern void default_ioapic_phys_id_map(physid_mask_t *phys_map, physid_mask_t *retmap); + extern int default_cpu_present_to_apicid(int mps_cpu); + ++void apic_send_nmi_to_offline_cpu(unsigned int cpu); ++ + #else /* CONFIG_X86_LOCAL_APIC */ + + static inline unsigned int read_apic_id(void) { return 0; } +--- a/arch/x86/kernel/apic/apic_flat_64.c ++++ b/arch/x86/kernel/apic/apic_flat_64.c +@@ -103,6 +103,7 @@ static struct apic apic_flat __ro_after_ + .send_IPI_allbutself = default_send_IPI_allbutself, + .send_IPI_all = default_send_IPI_all, + .send_IPI_self = default_send_IPI_self, ++ .nmi_to_offline_cpu = true, + + .read = native_apic_mem_read, + .write = native_apic_mem_write, +@@ -175,6 +176,7 @@ static struct apic apic_physflat __ro_af + .send_IPI_allbutself = default_send_IPI_allbutself, + .send_IPI_all = default_send_IPI_all, + .send_IPI_self = default_send_IPI_self, ++ .nmi_to_offline_cpu = true, + + .read = native_apic_mem_read, + .write = native_apic_mem_write, +--- a/arch/x86/kernel/apic/ipi.c ++++ b/arch/x86/kernel/apic/ipi.c +@@ -97,6 +97,14 @@ sendmask: + __apic_send_IPI_mask(mask, CALL_FUNCTION_VECTOR); + } + ++void apic_send_nmi_to_offline_cpu(unsigned int cpu) ++{ ++ if (WARN_ON_ONCE(!apic->nmi_to_offline_cpu)) ++ return; ++ if (WARN_ON_ONCE(!cpumask_test_cpu(cpu, &cpus_booted_once_mask))) ++ return; ++ apic->send_IPI(cpu, NMI_VECTOR); ++} + #endif /* CONFIG_SMP */ + + static inline int __prepare_ICR2(unsigned int mask) +--- a/arch/x86/kernel/apic/x2apic_cluster.c ++++ b/arch/x86/kernel/apic/x2apic_cluster.c +@@ -251,6 +251,7 @@ static struct apic apic_x2apic_cluster _ + .send_IPI_allbutself = x2apic_send_IPI_allbutself, + .send_IPI_all = x2apic_send_IPI_all, + .send_IPI_self = x2apic_send_IPI_self, ++ .nmi_to_offline_cpu = true, + + .read = native_apic_msr_read, + .write = native_apic_msr_write, +--- a/arch/x86/kernel/apic/x2apic_phys.c ++++ b/arch/x86/kernel/apic/x2apic_phys.c +@@ -166,6 +166,7 @@ static struct apic apic_x2apic_phys __ro + .send_IPI_allbutself = x2apic_send_IPI_allbutself, + .send_IPI_all = x2apic_send_IPI_all, + .send_IPI_self = x2apic_send_IPI_self, ++ .nmi_to_offline_cpu = true, + + .read = native_apic_msr_read, + .write = native_apic_msr_write, diff --git a/queue-6.6/x86-microcode-32-move-early-loading-after-paging-enable.patch b/queue-6.6/x86-microcode-32-move-early-loading-after-paging-enable.patch new file mode 100644 index 0000000000..e5dd65633d --- /dev/null +++ b/queue-6.6/x86-microcode-32-move-early-loading-after-paging-enable.patch @@ -0,0 +1,838 @@ +From a78cf1d31b4ae70395034948d005a1b3ee252746 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Tue, 17 Oct 2023 23:23:32 +0200 +Subject: x86/microcode/32: Move early loading after paging enable + +From: Thomas Gleixner + +commit 0b62f6cb07738d7211d926c39f6946b87f72e792 upstream. + +32-bit loads microcode before paging is enabled. The commit which +introduced that has zero justification in the changelog. The cover +letter has slightly more content, but it does not give any technical +justification either: + + "The problem in current microcode loading method is that we load a + microcode way, way too late; ideally we should load it before turning + paging on. This may only be practical on 32 bits since we can't get + to 64-bit mode without paging on, but we should still do it as early + as at all possible." + +Handwaving word salad with zero technical content. + +Someone claimed in an offlist conversation that this is required for +curing the ATOM erratum AAE44/AAF40/AAG38/AAH41. That erratum requires +an microcode update in order to make the usage of PSE safe. But during +early boot, PSE is completely irrelevant and it is evaluated way later. + +Neither is it relevant for the AP on single core HT enabled CPUs as the +microcode loading on the AP is not doing anything. + +On dual core CPUs there is a theoretical problem if a split of an +executable large page between enabling paging including PSE and loading +the microcode happens. But that's only theoretical, it's practically +irrelevant because the affected dual core CPUs are 64bit enabled and +therefore have paging and PSE enabled before loading the microcode on +the second core. So why would it work on 64-bit but not on 32-bit? + +The erratum: + + "AAG38 Code Fetch May Occur to Incorrect Address After a Large Page is + Split Into 4-Kbyte Pages + + Problem: If software clears the PS (page size) bit in a present PDE + (page directory entry), that will cause linear addresses mapped through + this PDE to use 4-KByte pages instead of using a large page after old + TLB entries are invalidated. Due to this erratum, if a code fetch uses + this PDE before the TLB entry for the large page is invalidated then it + may fetch from a different physical address than specified by either the + old large page translation or the new 4-KByte page translation. This + erratum may also cause speculative code fetches from incorrect addresses." + +The practical relevance for this is exactly zero because there is no +splitting of large text pages during early boot-time, i.e. between paging +enable and microcode loading, and neither during CPU hotplug. + +IOW, this load microcode before paging enable is yet another voodoo +programming solution in search of a problem. What's worse is that it causes +at least two serious problems: + + 1) When stackprotector is enabled, the microcode loader code has the + stackprotector mechanics enabled. The read from the per CPU variable + __stack_chk_guard is always accessing the virtual address either + directly on UP or via %fs on SMP. In physical address mode this + results in an access to memory above 3GB. So this works by chance as + the hardware returns the same value when there is no RAM at this + physical address. When there is RAM populated above 3G then the read + is by chance the same as nothing changes that memory during the very + early boot stage. That's not necessarily true during runtime CPU + hotplug. + + 2) When function tracing is enabled, the relevant microcode loader + functions and the functions invoked from there will call into the + tracing code and evaluate global and per CPU variables in physical + address mode. What could potentially go wrong? + +Cure this and move the microcode loading after the early paging enable, use +the new temporary initrd mapping and remove the gunk in the microcode +loader which is required to handle physical address mode. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Borislav Petkov (AMD) +Link: https://lore.kernel.org/r/20231017211722.348298216@linutronix.de +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/include/asm/microcode.h | 5 - + arch/x86/kernel/cpu/common.c | 12 --- + arch/x86/kernel/cpu/microcode/amd.c | 103 ++++++++------------------- + arch/x86/kernel/cpu/microcode/core.c | 78 ++++---------------- + arch/x86/kernel/cpu/microcode/intel.c | 116 ++++--------------------------- + arch/x86/kernel/cpu/microcode/internal.h | 2 + arch/x86/kernel/head32.c | 3 + arch/x86/kernel/head_32.S | 10 -- + arch/x86/kernel/smpboot.c | 12 +-- + 9 files changed, 72 insertions(+), 269 deletions(-) + +--- a/arch/x86/include/asm/microcode.h ++++ b/arch/x86/include/asm/microcode.h +@@ -68,11 +68,6 @@ static inline u32 intel_get_microcode_re + + return rev; + } +- +-void show_ucode_info_early(void); +- +-#else /* CONFIG_CPU_SUP_INTEL */ +-static inline void show_ucode_info_early(void) { } + #endif /* !CONFIG_CPU_SUP_INTEL */ + + #endif /* _ASM_X86_MICROCODE_H */ +--- a/arch/x86/kernel/cpu/common.c ++++ b/arch/x86/kernel/cpu/common.c +@@ -2224,8 +2224,6 @@ static inline void setup_getcpu(int cpu) + } + + #ifdef CONFIG_X86_64 +-static inline void ucode_cpu_init(int cpu) { } +- + static inline void tss_setup_ist(struct tss_struct *tss) + { + /* Set up the per-CPU TSS IST stacks */ +@@ -2236,16 +2234,8 @@ static inline void tss_setup_ist(struct + /* Only mapped when SEV-ES is active */ + tss->x86_tss.ist[IST_INDEX_VC] = __this_cpu_ist_top_va(VC); + } +- + #else /* CONFIG_X86_64 */ +- +-static inline void ucode_cpu_init(int cpu) +-{ +- show_ucode_info_early(); +-} +- + static inline void tss_setup_ist(struct tss_struct *tss) { } +- + #endif /* !CONFIG_X86_64 */ + + static inline void tss_setup_io_bitmap(struct tss_struct *tss) +@@ -2301,8 +2291,6 @@ void cpu_init(void) + struct task_struct *cur = current; + int cpu = raw_smp_processor_id(); + +- ucode_cpu_init(cpu); +- + #ifdef CONFIG_NUMA + if (this_cpu_read(numa_node) == 0 && + early_cpu_to_node(cpu) != NUMA_NO_NODE) +--- a/arch/x86/kernel/cpu/microcode/amd.c ++++ b/arch/x86/kernel/cpu/microcode/amd.c +@@ -121,24 +121,20 @@ static u16 find_equiv_id(struct equiv_cp + + /* + * Check whether there is a valid microcode container file at the beginning +- * of @buf of size @buf_size. Set @early to use this function in the early path. ++ * of @buf of size @buf_size. + */ +-static bool verify_container(const u8 *buf, size_t buf_size, bool early) ++static bool verify_container(const u8 *buf, size_t buf_size) + { + u32 cont_magic; + + if (buf_size <= CONTAINER_HDR_SZ) { +- if (!early) +- pr_debug("Truncated microcode container header.\n"); +- ++ pr_debug("Truncated microcode container header.\n"); + return false; + } + + cont_magic = *(const u32 *)buf; + if (cont_magic != UCODE_MAGIC) { +- if (!early) +- pr_debug("Invalid magic value (0x%08x).\n", cont_magic); +- ++ pr_debug("Invalid magic value (0x%08x).\n", cont_magic); + return false; + } + +@@ -147,23 +143,20 @@ static bool verify_container(const u8 *b + + /* + * Check whether there is a valid, non-truncated CPU equivalence table at the +- * beginning of @buf of size @buf_size. Set @early to use this function in the +- * early path. ++ * beginning of @buf of size @buf_size. + */ +-static bool verify_equivalence_table(const u8 *buf, size_t buf_size, bool early) ++static bool verify_equivalence_table(const u8 *buf, size_t buf_size) + { + const u32 *hdr = (const u32 *)buf; + u32 cont_type, equiv_tbl_len; + +- if (!verify_container(buf, buf_size, early)) ++ if (!verify_container(buf, buf_size)) + return false; + + cont_type = hdr[1]; + if (cont_type != UCODE_EQUIV_CPU_TABLE_TYPE) { +- if (!early) +- pr_debug("Wrong microcode container equivalence table type: %u.\n", +- cont_type); +- ++ pr_debug("Wrong microcode container equivalence table type: %u.\n", ++ cont_type); + return false; + } + +@@ -172,9 +165,7 @@ static bool verify_equivalence_table(con + equiv_tbl_len = hdr[2]; + if (equiv_tbl_len < sizeof(struct equiv_cpu_entry) || + buf_size < equiv_tbl_len) { +- if (!early) +- pr_debug("Truncated equivalence table.\n"); +- ++ pr_debug("Truncated equivalence table.\n"); + return false; + } + +@@ -183,22 +174,19 @@ static bool verify_equivalence_table(con + + /* + * Check whether there is a valid, non-truncated microcode patch section at the +- * beginning of @buf of size @buf_size. Set @early to use this function in the +- * early path. ++ * beginning of @buf of size @buf_size. + * + * On success, @sh_psize returns the patch size according to the section header, + * to the caller. + */ + static bool +-__verify_patch_section(const u8 *buf, size_t buf_size, u32 *sh_psize, bool early) ++__verify_patch_section(const u8 *buf, size_t buf_size, u32 *sh_psize) + { + u32 p_type, p_size; + const u32 *hdr; + + if (buf_size < SECTION_HDR_SIZE) { +- if (!early) +- pr_debug("Truncated patch section.\n"); +- ++ pr_debug("Truncated patch section.\n"); + return false; + } + +@@ -207,17 +195,13 @@ __verify_patch_section(const u8 *buf, si + p_size = hdr[1]; + + if (p_type != UCODE_UCODE_TYPE) { +- if (!early) +- pr_debug("Invalid type field (0x%x) in container file section header.\n", +- p_type); +- ++ pr_debug("Invalid type field (0x%x) in container file section header.\n", ++ p_type); + return false; + } + + if (p_size < sizeof(struct microcode_header_amd)) { +- if (!early) +- pr_debug("Patch of size %u too short.\n", p_size); +- ++ pr_debug("Patch of size %u too short.\n", p_size); + return false; + } + +@@ -269,7 +253,7 @@ static unsigned int __verify_patch_size( + * 0: success + */ + static int +-verify_patch(u8 family, const u8 *buf, size_t buf_size, u32 *patch_size, bool early) ++verify_patch(u8 family, const u8 *buf, size_t buf_size, u32 *patch_size) + { + struct microcode_header_amd *mc_hdr; + unsigned int ret; +@@ -277,7 +261,7 @@ verify_patch(u8 family, const u8 *buf, s + u16 proc_id; + u8 patch_fam; + +- if (!__verify_patch_section(buf, buf_size, &sh_psize, early)) ++ if (!__verify_patch_section(buf, buf_size, &sh_psize)) + return -1; + + /* +@@ -292,16 +276,13 @@ verify_patch(u8 family, const u8 *buf, s + * size sh_psize, as the section claims. + */ + if (buf_size < sh_psize) { +- if (!early) +- pr_debug("Patch of size %u truncated.\n", sh_psize); +- ++ pr_debug("Patch of size %u truncated.\n", sh_psize); + return -1; + } + + ret = __verify_patch_size(family, sh_psize, buf_size); + if (!ret) { +- if (!early) +- pr_debug("Per-family patch size mismatch.\n"); ++ pr_debug("Per-family patch size mismatch.\n"); + return -1; + } + +@@ -309,8 +290,7 @@ verify_patch(u8 family, const u8 *buf, s + + mc_hdr = (struct microcode_header_amd *)(buf + SECTION_HDR_SIZE); + if (mc_hdr->nb_dev_id || mc_hdr->sb_dev_id) { +- if (!early) +- pr_err("Patch-ID 0x%08x: chipset-specific code unsupported.\n", mc_hdr->patch_id); ++ pr_err("Patch-ID 0x%08x: chipset-specific code unsupported.\n", mc_hdr->patch_id); + return -1; + } + +@@ -337,7 +317,7 @@ static size_t parse_container(u8 *ucode, + u16 eq_id; + u8 *buf; + +- if (!verify_equivalence_table(ucode, size, true)) ++ if (!verify_equivalence_table(ucode, size)) + return 0; + + buf = ucode; +@@ -364,7 +344,7 @@ static size_t parse_container(u8 *ucode, + u32 patch_size; + int ret; + +- ret = verify_patch(x86_family(desc->cpuid_1_eax), buf, size, &patch_size, true); ++ ret = verify_patch(x86_family(desc->cpuid_1_eax), buf, size, &patch_size); + if (ret < 0) { + /* + * Patch verification failed, skip to the next container, if +@@ -456,14 +436,8 @@ static bool early_apply_microcode(u32 cp + { + struct cont_desc desc = { 0 }; + struct microcode_amd *mc; +- u32 rev, dummy, *new_rev; + bool ret = false; +- +-#ifdef CONFIG_X86_32 +- new_rev = (u32 *)__pa_nodebug(&ucode_new_rev); +-#else +- new_rev = &ucode_new_rev; +-#endif ++ u32 rev, dummy; + + desc.cpuid_1_eax = cpuid_1_eax; + +@@ -484,8 +458,8 @@ static bool early_apply_microcode(u32 cp + return ret; + + if (!__apply_microcode_amd(mc)) { +- *new_rev = mc->hdr.patch_id; +- ret = true; ++ ucode_new_rev = mc->hdr.patch_id; ++ ret = true; + } + + return ret; +@@ -514,26 +488,13 @@ static bool get_builtin_microcode(struct + + static void find_blobs_in_containers(unsigned int cpuid_1_eax, struct cpio_data *ret) + { +- struct ucode_cpu_info *uci; + struct cpio_data cp; +- const char *path; +- bool use_pa; +- +- if (IS_ENABLED(CONFIG_X86_32)) { +- uci = (struct ucode_cpu_info *)__pa_nodebug(ucode_cpu_info); +- path = (const char *)__pa_nodebug(ucode_path); +- use_pa = true; +- } else { +- uci = ucode_cpu_info; +- path = ucode_path; +- use_pa = false; +- } + + if (!get_builtin_microcode(&cp, x86_family(cpuid_1_eax))) +- cp = find_microcode_in_initrd(path, use_pa); ++ cp = find_microcode_in_initrd(ucode_path); + + /* Needed in load_microcode_amd() */ +- uci->cpu_sig.sig = cpuid_1_eax; ++ ucode_cpu_info->cpu_sig.sig = cpuid_1_eax; + + *ret = cp; + } +@@ -562,7 +523,7 @@ int __init save_microcode_in_initrd_amd( + enum ucode_state ret; + struct cpio_data cp; + +- cp = find_microcode_in_initrd(ucode_path, false); ++ cp = find_microcode_in_initrd(ucode_path); + if (!(cp.data && cp.size)) + return -EINVAL; + +@@ -738,7 +699,7 @@ static size_t install_equiv_cpu_table(co + u32 equiv_tbl_len; + const u32 *hdr; + +- if (!verify_equivalence_table(buf, buf_size, false)) ++ if (!verify_equivalence_table(buf, buf_size)) + return 0; + + hdr = (const u32 *)buf; +@@ -784,7 +745,7 @@ static int verify_and_add_patch(u8 famil + u16 proc_id; + int ret; + +- ret = verify_patch(family, fw, leftover, patch_size, false); ++ ret = verify_patch(family, fw, leftover, patch_size); + if (ret) + return ret; + +@@ -918,7 +879,7 @@ static enum ucode_state request_microcod + } + + ret = UCODE_ERROR; +- if (!verify_container(fw->data, fw->size, false)) ++ if (!verify_container(fw->data, fw->size)) + goto fw_release; + + ret = load_microcode_amd(c->x86, fw->data, fw->size); +--- a/arch/x86/kernel/cpu/microcode/core.c ++++ b/arch/x86/kernel/cpu/microcode/core.c +@@ -90,10 +90,7 @@ static bool amd_check_current_patch_leve + + native_rdmsr(MSR_AMD64_PATCH_LEVEL, lvl, dummy); + +- if (IS_ENABLED(CONFIG_X86_32)) +- levels = (u32 *)__pa_nodebug(&final_levels); +- else +- levels = final_levels; ++ levels = final_levels; + + for (i = 0; levels[i]; i++) { + if (lvl == levels[i]) +@@ -105,17 +102,8 @@ static bool amd_check_current_patch_leve + static bool __init check_loader_disabled_bsp(void) + { + static const char *__dis_opt_str = "dis_ucode_ldr"; +- +-#ifdef CONFIG_X86_32 +- const char *cmdline = (const char *)__pa_nodebug(boot_command_line); +- const char *option = (const char *)__pa_nodebug(__dis_opt_str); +- bool *res = (bool *)__pa_nodebug(&dis_ucode_ldr); +- +-#else /* CONFIG_X86_64 */ + const char *cmdline = boot_command_line; + const char *option = __dis_opt_str; +- bool *res = &dis_ucode_ldr; +-#endif + + /* + * CPUID(1).ECX[31]: reserved for hypervisor use. This is still not +@@ -123,17 +111,17 @@ static bool __init check_loader_disabled + * that's good enough as they don't land on the BSP path anyway. + */ + if (native_cpuid_ecx(1) & BIT(31)) +- return *res; ++ return true; + + if (x86_cpuid_vendor() == X86_VENDOR_AMD) { + if (amd_check_current_patch_level()) +- return *res; ++ return true; + } + + if (cmdline_find_option_bool(cmdline, option) <= 0) +- *res = false; ++ dis_ucode_ldr = false; + +- return *res; ++ return dis_ucode_ldr; + } + + void __init load_ucode_bsp(void) +@@ -171,20 +159,11 @@ void __init load_ucode_bsp(void) + load_ucode_amd_early(cpuid_1_eax); + } + +-static bool check_loader_disabled_ap(void) +-{ +-#ifdef CONFIG_X86_32 +- return *((bool *)__pa_nodebug(&dis_ucode_ldr)); +-#else +- return dis_ucode_ldr; +-#endif +-} +- + void load_ucode_ap(void) + { + unsigned int cpuid_1_eax; + +- if (check_loader_disabled_ap()) ++ if (dis_ucode_ldr) + return; + + cpuid_1_eax = native_cpuid_eax(1); +@@ -232,40 +211,28 @@ out: + return ret; + } + +-struct cpio_data find_microcode_in_initrd(const char *path, bool use_pa) ++struct cpio_data find_microcode_in_initrd(const char *path) + { + #ifdef CONFIG_BLK_DEV_INITRD + unsigned long start = 0; + size_t size; + + #ifdef CONFIG_X86_32 +- struct boot_params *params; +- +- if (use_pa) +- params = (struct boot_params *)__pa_nodebug(&boot_params); +- else +- params = &boot_params; +- +- size = params->hdr.ramdisk_size; +- +- /* +- * Set start only if we have an initrd image. We cannot use initrd_start +- * because it is not set that early yet. +- */ ++ size = boot_params.hdr.ramdisk_size; ++ /* Early load on BSP has a temporary mapping. */ + if (size) +- start = params->hdr.ramdisk_image; ++ start = initrd_start_early; + +-# else /* CONFIG_X86_64 */ ++#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 ++#endif + + /* + * Fixup the start address: after reserve_initrd() runs, initrd_start +@@ -276,23 +243,10 @@ struct cpio_data find_microcode_in_initr + * initrd_gone is for the hotplug case where we've thrown out initrd + * already. + */ +- if (!use_pa) { +- if (initrd_gone) +- return (struct cpio_data){ NULL, 0, "" }; +- if (initrd_start) +- start = initrd_start; +- } else { +- /* +- * The picture with physical addresses is a bit different: we +- * need to get the *physical* address to which the ramdisk was +- * relocated, i.e., relocated_ramdisk (not initrd_start) and +- * since we're running from physical addresses, we need to access +- * relocated_ramdisk through its *physical* address too. +- */ +- u64 *rr = (u64 *)__pa_nodebug(&relocated_ramdisk); +- if (*rr) +- start = *rr; +- } ++ if (initrd_gone) ++ return (struct cpio_data){ NULL, 0, "" }; ++ if (initrd_start) ++ start = initrd_start; + + return find_cpio_data(path, (void *)start, size, NULL); + #else /* !CONFIG_BLK_DEV_INITRD */ +--- a/arch/x86/kernel/cpu/microcode/intel.c ++++ b/arch/x86/kernel/cpu/microcode/intel.c +@@ -319,15 +319,8 @@ static void save_microcode_patch(struct + if (!intel_find_matching_signature(p->data, uci->cpu_sig.sig, uci->cpu_sig.pf)) + return; + +- /* +- * Save for early loading. On 32-bit, that needs to be a physical +- * address as the APs are running from physical addresses, before +- * paging has been enabled. +- */ +- if (IS_ENABLED(CONFIG_X86_32)) +- intel_ucode_patch = (struct microcode_intel *)__pa_nodebug(p->data); +- else +- intel_ucode_patch = p->data; ++ /* Save for early loading */ ++ intel_ucode_patch = p->data; + } + + /* +@@ -420,66 +413,10 @@ static bool load_builtin_intel_microcode + return false; + } + +-static void print_ucode_info(int old_rev, int new_rev, unsigned int date) +-{ +- pr_info_once("updated early: 0x%x -> 0x%x, date = %04x-%02x-%02x\n", +- old_rev, +- new_rev, +- date & 0xffff, +- date >> 24, +- (date >> 16) & 0xff); +-} +- +-#ifdef CONFIG_X86_32 +- +-static int delay_ucode_info; +-static int current_mc_date; +-static int early_old_rev; +- +-/* +- * Print early updated ucode info after printk works. This is delayed info dump. +- */ +-void show_ucode_info_early(void) +-{ +- struct ucode_cpu_info uci; +- +- if (delay_ucode_info) { +- intel_cpu_collect_info(&uci); +- print_ucode_info(early_old_rev, uci.cpu_sig.rev, current_mc_date); +- delay_ucode_info = 0; +- } +-} +- +-/* +- * At this point, we can not call printk() yet. Delay printing microcode info in +- * show_ucode_info_early() until printk() works. +- */ +-static void print_ucode(int old_rev, int new_rev, int date) +-{ +- int *delay_ucode_info_p; +- int *current_mc_date_p; +- int *early_old_rev_p; +- +- delay_ucode_info_p = (int *)__pa_nodebug(&delay_ucode_info); +- current_mc_date_p = (int *)__pa_nodebug(¤t_mc_date); +- early_old_rev_p = (int *)__pa_nodebug(&early_old_rev); +- +- *delay_ucode_info_p = 1; +- *current_mc_date_p = date; +- *early_old_rev_p = old_rev; +-} +-#else +- +-static inline void print_ucode(int old_rev, int new_rev, int date) +-{ +- print_ucode_info(old_rev, new_rev, date); +-} +-#endif +- +-static int apply_microcode_early(struct ucode_cpu_info *uci, bool early) ++static int apply_microcode_early(struct ucode_cpu_info *uci) + { + struct microcode_intel *mc; +- u32 rev, old_rev; ++ u32 rev, old_rev, date; + + mc = uci->mc; + if (!mc) +@@ -513,11 +450,9 @@ static int apply_microcode_early(struct + + uci->cpu_sig.rev = rev; + +- if (early) +- print_ucode(old_rev, uci->cpu_sig.rev, mc->hdr.date); +- else +- print_ucode_info(old_rev, uci->cpu_sig.rev, mc->hdr.date); +- ++ date = mc->hdr.date; ++ pr_info_once("updated early: 0x%x -> 0x%x, date = %04x-%02x-%02x\n", ++ old_rev, rev, date & 0xffff, date >> 24, (date >> 16) & 0xff); + return 0; + } + +@@ -535,7 +470,7 @@ int __init save_microcode_in_initrd_inte + intel_ucode_patch = NULL; + + if (!load_builtin_intel_microcode(&cp)) +- cp = find_microcode_in_initrd(ucode_path, false); ++ cp = find_microcode_in_initrd(ucode_path); + + if (!(cp.data && cp.size)) + return 0; +@@ -551,21 +486,11 @@ int __init save_microcode_in_initrd_inte + */ + static struct microcode_intel *__load_ucode_intel(struct ucode_cpu_info *uci) + { +- static const char *path; + struct cpio_data cp; +- bool use_pa; +- +- if (IS_ENABLED(CONFIG_X86_32)) { +- path = (const char *)__pa_nodebug(ucode_path); +- use_pa = true; +- } else { +- path = ucode_path; +- use_pa = false; +- } + + /* try built-in microcode first */ + if (!load_builtin_intel_microcode(&cp)) +- cp = find_microcode_in_initrd(path, use_pa); ++ cp = find_microcode_in_initrd(ucode_path); + + if (!(cp.data && cp.size)) + return NULL; +@@ -586,30 +511,21 @@ void __init load_ucode_intel_bsp(void) + + uci.mc = patch; + +- apply_microcode_early(&uci, true); ++ apply_microcode_early(&uci); + } + + void load_ucode_intel_ap(void) + { +- struct microcode_intel *patch, **iup; + struct ucode_cpu_info uci; + +- if (IS_ENABLED(CONFIG_X86_32)) +- iup = (struct microcode_intel **) __pa_nodebug(&intel_ucode_patch); +- else +- iup = &intel_ucode_patch; +- +- if (!*iup) { +- patch = __load_ucode_intel(&uci); +- if (!patch) ++ if (!intel_ucode_patch) { ++ intel_ucode_patch = __load_ucode_intel(&uci); ++ if (!intel_ucode_patch) + return; +- +- *iup = patch; + } + +- uci.mc = *iup; +- +- apply_microcode_early(&uci, true); ++ uci.mc = intel_ucode_patch; ++ apply_microcode_early(&uci); + } + + static struct microcode_intel *find_patch(struct ucode_cpu_info *uci) +@@ -647,7 +563,7 @@ void reload_ucode_intel(void) + + uci.mc = p; + +- apply_microcode_early(&uci, false); ++ apply_microcode_early(&uci); + } + + static int collect_cpu_info(int cpu_num, struct cpu_signature *csig) +--- a/arch/x86/kernel/cpu/microcode/internal.h ++++ b/arch/x86/kernel/cpu/microcode/internal.h +@@ -44,7 +44,7 @@ struct microcode_ops { + }; + + extern struct ucode_cpu_info ucode_cpu_info[]; +-struct cpio_data find_microcode_in_initrd(const char *path, bool use_pa); ++struct cpio_data find_microcode_in_initrd(const char *path); + + #define MAX_UCODE_COUNT 128 + +--- a/arch/x86/kernel/head32.c ++++ b/arch/x86/kernel/head32.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -34,6 +35,8 @@ asmlinkage __visible void __init __noret + /* Make sure IDT is set up before any exception happens */ + idt_setup_early_handler(); + ++ load_ucode_bsp(); ++ + cr4_init_shadow(); + + sanitize_boot_params(&boot_params); +--- a/arch/x86/kernel/head_32.S ++++ b/arch/x86/kernel/head_32.S +@@ -118,11 +118,6 @@ SYM_CODE_START(startup_32) + movl %eax, pa(olpc_ofw_pgd) + #endif + +-#ifdef CONFIG_MICROCODE +- /* Early load ucode on BSP. */ +- call load_ucode_bsp +-#endif +- + /* Create early pagetables. */ + call mk_early_pgtbl_32 + +@@ -157,11 +152,6 @@ SYM_FUNC_START(startup_32_smp) + movl %eax,%ss + leal -__PAGE_OFFSET(%ecx),%esp + +-#ifdef CONFIG_MICROCODE +- /* Early load ucode on AP. */ +- call load_ucode_ap +-#endif +- + .Ldefault_entry: + movl $(CR0_STATE & ~X86_CR0_PG),%eax + movl %eax,%cr0 +--- a/arch/x86/kernel/smpboot.c ++++ b/arch/x86/kernel/smpboot.c +@@ -259,12 +259,9 @@ static void notrace start_secondary(void + cpu_init_exception_handling(); + + /* +- * 32-bit systems load the microcode from the ASM startup code for +- * historical reasons. +- * +- * On 64-bit systems load it before reaching the AP alive +- * synchronization point below so it is not part of the full per +- * CPU serialized bringup part when "parallel" bringup is enabled. ++ * Load the microcode before reaching the AP alive synchronization ++ * point below so it is not part of the full per CPU serialized ++ * bringup part when "parallel" bringup is enabled. + * + * That's even safe when hyperthreading is enabled in the CPU as + * the core code starts the primary threads first and leaves the +@@ -277,8 +274,7 @@ static void notrace start_secondary(void + * CPUID, MSRs etc. must be strictly serialized to maintain + * software state correctness. + */ +- if (IS_ENABLED(CONFIG_X86_64)) +- load_ucode_ap(); ++ load_ucode_ap(); + + /* + * Synchronization point with the hotplug core. Sets this CPUs diff --git a/queue-6.6/x86-microcode-add-per-cpu-control-field.patch b/queue-6.6/x86-microcode-add-per-cpu-control-field.patch new file mode 100644 index 0000000000..3c984972ce --- /dev/null +++ b/queue-6.6/x86-microcode-add-per-cpu-control-field.patch @@ -0,0 +1,87 @@ +From d996a8d18c72a9cd3ed58ab98e3a06db064ac520 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Mon, 2 Oct 2023 14:00:01 +0200 +Subject: x86/microcode: Add per CPU control field + +From: Thomas Gleixner + +commit ba3aeb97cb2c53025356f31c5a0a294385194115 upstream + +Add a per CPU control field to ucode_ctrl and define constants for it +which are going to be used to control the loading state machine. + +In theory this could be a global control field, but a global control does +not cover the following case: + + 15 primary CPUs load microcode successfully + 1 primary CPU fails and returns with an error code + +With global control the sibling of the failed CPU would either try again or +the whole operation would be aborted with the consequence that the 15 +siblings do not invoke the apply path and end up with inconsistent software +state. The result in dmesg would be inconsistent too. + +There are two additional fields added and initialized: + +ctrl_cpu and secondaries. ctrl_cpu is the CPU number of the primary thread +for now, but with the upcoming uniform loading at package or system scope +this will be one CPU per package or just one CPU. Secondaries hands the +control CPU a CPU mask which will be required to release the secondary CPUs +out of the wait loop. + +Preparatory change for implementing a properly split control flow for +primary and secondary CPUs. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Borislav Petkov (AMD) +Link: https://lore.kernel.org/r/20231002115903.319959519@linutronix.de +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/cpu/microcode/core.c | 20 ++++++++++++++++++-- + 1 file changed, 18 insertions(+), 2 deletions(-) + +--- a/arch/x86/kernel/cpu/microcode/core.c ++++ b/arch/x86/kernel/cpu/microcode/core.c +@@ -252,8 +252,19 @@ static struct platform_device *microcode + * 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; + }; + + static DEFINE_PER_CPU(struct microcode_ctrl, ucode_ctrl); +@@ -398,7 +409,7 @@ static int load_late_stop_cpus(void) + */ + static bool setup_cpus(void) + { +- struct microcode_ctrl ctrl = { .result = -1, }; ++ struct microcode_ctrl ctrl = { .ctrl = SCTRL_WAIT, .result = -1, }; + unsigned int cpu; + + for_each_cpu_and(cpu, cpu_present_mask, &cpus_booted_once_mask) { +@@ -408,7 +419,12 @@ static bool setup_cpus(void) + return false; + } + } +- /* Initialize the per CPU state */ ++ ++ /* ++ * Initialize the per CPU state. This is core scope for now, ++ * but prepared to take package or system scope into account. ++ */ ++ ctrl.ctrl_cpu = cpumask_first(topology_sibling_cpumask(cpu)); + per_cpu(ucode_ctrl, cpu) = ctrl; + } + return true; diff --git a/queue-6.6/x86-microcode-add-per-cpu-result-state.patch b/queue-6.6/x86-microcode-add-per-cpu-result-state.patch new file mode 100644 index 0000000000..4e6831d30c --- /dev/null +++ b/queue-6.6/x86-microcode-add-per-cpu-result-state.patch @@ -0,0 +1,243 @@ +From facaa441b953dc69f317559214cb4ecc66b91b12 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Tue, 17 Oct 2023 23:24:05 +0200 +Subject: x86/microcode: Add per CPU result state + +From: Thomas Gleixner + +commit 4b753955e9151ad2f722137a7bcbafda756186b3 upstream + +The microcode rendezvous is purely acting on global state, which does +not allow to analyze fails in a coherent way. + +Introduce per CPU state where the results are written into, which allows to +analyze the return codes of the individual CPUs. + +Initialize the state when walking the cpu_present_mask in the online +check to avoid another for_each_cpu() loop. + +Enhance the result print out with that. + +The structure is intentionally named ucode_ctrl as it will gain control +fields in subsequent changes. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Borislav Petkov (AMD) +Link: https://lore.kernel.org/r/20231017211723.632681010@linutronix.de +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/cpu/microcode/core.c | 112 ++++++++++++++++++------------- + arch/x86/kernel/cpu/microcode/internal.h | 1 + 2 files changed, 67 insertions(+), 46 deletions(-) + +--- a/arch/x86/kernel/cpu/microcode/core.c ++++ b/arch/x86/kernel/cpu/microcode/core.c +@@ -252,6 +252,11 @@ static struct platform_device *microcode + * requirement can be relaxed in the future. Right now, this is conservative + * and good. + */ ++struct microcode_ctrl { ++ enum ucode_state result; ++}; ++ ++static DEFINE_PER_CPU(struct microcode_ctrl, ucode_ctrl); + static atomic_t late_cpus_in, late_cpus_out; + + static bool wait_for_cpus(atomic_t *cnt) +@@ -274,23 +279,19 @@ static bool wait_for_cpus(atomic_t *cnt) + return false; + } + +-/* +- * Returns: +- * < 0 - on error +- * 0 - success (no update done or microcode was updated) +- */ +-static int __reload_late(void *info) ++static int load_cpus_stopped(void *unused) + { + int cpu = smp_processor_id(); +- enum ucode_state err; +- int ret = 0; ++ enum ucode_state ret; + + /* + * Wait for all CPUs to arrive. A load will not be attempted unless all + * CPUs show up. + * */ +- if (!wait_for_cpus(&late_cpus_in)) +- return -1; ++ if (!wait_for_cpus(&late_cpus_in)) { ++ this_cpu_write(ucode_ctrl.result, UCODE_TIMEOUT); ++ return 0; ++ } + + /* + * On an SMT system, it suffices to load the microcode on one sibling of +@@ -299,17 +300,11 @@ static int __reload_late(void *info) + * loading attempts happen on multiple threads of an SMT core. See + * below. + */ +- if (cpumask_first(topology_sibling_cpumask(cpu)) == cpu) +- err = microcode_ops->apply_microcode(cpu); +- else ++ if (cpumask_first(topology_sibling_cpumask(cpu)) != cpu) + goto wait_for_siblings; + +- if (err >= UCODE_NFOUND) { +- if (err == UCODE_ERROR) { +- pr_warn("Error reloading microcode on CPU %d\n", cpu); +- ret = -1; +- } +- } ++ ret = microcode_ops->apply_microcode(cpu); ++ this_cpu_write(ucode_ctrl.result, ret); + + wait_for_siblings: + if (!wait_for_cpus(&late_cpus_out)) +@@ -321,19 +316,18 @@ wait_for_siblings: + * per-cpu cpuinfo can be updated with right microcode + * revision. + */ +- if (cpumask_first(topology_sibling_cpumask(cpu)) != cpu) +- err = microcode_ops->apply_microcode(cpu); ++ if (cpumask_first(topology_sibling_cpumask(cpu)) == cpu) ++ return 0; + +- return ret; ++ ret = microcode_ops->apply_microcode(cpu); ++ this_cpu_write(ucode_ctrl.result, ret); ++ return 0; + } + +-/* +- * Reload microcode late on all CPUs. Wait for a sec until they +- * all gather together. +- */ +-static int microcode_reload_late(void) ++static int load_late_stop_cpus(void) + { +- int old = boot_cpu_data.microcode, ret; ++ unsigned int cpu, updated = 0, failed = 0, timedout = 0, siblings = 0; ++ int old_rev = boot_cpu_data.microcode; + struct cpuinfo_x86 prev_info; + + pr_err("Attempting late microcode loading - it is dangerous and taints the kernel.\n"); +@@ -348,26 +342,47 @@ static int microcode_reload_late(void) + */ + store_cpu_caps(&prev_info); + +- ret = stop_machine_cpuslocked(__reload_late, NULL, cpu_online_mask); ++ stop_machine_cpuslocked(load_cpus_stopped, NULL, cpu_online_mask); ++ ++ /* Analyze the results */ ++ for_each_cpu_and(cpu, cpu_present_mask, &cpus_booted_once_mask) { ++ switch (per_cpu(ucode_ctrl.result, cpu)) { ++ case UCODE_UPDATED: updated++; break; ++ case UCODE_TIMEOUT: timedout++; break; ++ case UCODE_OK: siblings++; break; ++ default: failed++; break; ++ } ++ } + + if (microcode_ops->finalize_late_load) +- microcode_ops->finalize_late_load(ret); ++ microcode_ops->finalize_late_load(!updated); + +- if (!ret) { +- pr_info("Reload succeeded, microcode revision: 0x%x -> 0x%x\n", +- old, boot_cpu_data.microcode); +- microcode_check(&prev_info); +- add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK); +- } else { +- pr_info("Reload failed, current microcode revision: 0x%x\n", +- boot_cpu_data.microcode); ++ if (!updated) { ++ /* Nothing changed. */ ++ if (!failed && !timedout) ++ return 0; ++ pr_err("update failed: %u CPUs failed %u CPUs timed out\n", ++ failed, timedout); ++ return -EIO; + } +- return ret; ++ ++ add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK); ++ pr_info("load: updated on %u primary CPUs with %u siblings\n", updated, siblings); ++ if (failed || timedout) { ++ pr_err("load incomplete. %u CPUs timed out or failed\n", ++ num_online_cpus() - (updated + siblings)); ++ } ++ pr_info("revision: 0x%x -> 0x%x\n", old_rev, boot_cpu_data.microcode); ++ microcode_check(&prev_info); ++ ++ return updated + siblings == num_online_cpus() ? 0 : -EIO; + } + + /* +- * Ensure that all required CPUs which are present and have been booted +- * once are online. ++ * This function does two things: ++ * ++ * 1) Ensure that all required CPUs which are present and have been booted ++ * once are online. + * + * To pass this check, all primary threads must be online. + * +@@ -378,9 +393,12 @@ static int microcode_reload_late(void) + * behaviour is undefined. The default play_dead() implementation on + * modern CPUs uses MWAIT, which is also not guaranteed to be safe + * against a microcode update which affects MWAIT. ++ * ++ * 2) Initialize the per CPU control structure + */ +-static bool ensure_cpus_are_online(void) ++static bool setup_cpus(void) + { ++ struct microcode_ctrl ctrl = { .result = -1, }; + unsigned int cpu; + + for_each_cpu_and(cpu, cpu_present_mask, &cpus_booted_once_mask) { +@@ -390,18 +408,20 @@ static bool ensure_cpus_are_online(void) + return false; + } + } ++ /* Initialize the per CPU state */ ++ per_cpu(ucode_ctrl, cpu) = ctrl; + } + return true; + } + +-static int ucode_load_late_locked(void) ++static int load_late_locked(void) + { +- if (!ensure_cpus_are_online()) ++ if (!setup_cpus()) + return -EBUSY; + + switch (microcode_ops->request_microcode_fw(0, µcode_pdev->dev)) { + case UCODE_NEW: +- return microcode_reload_late(); ++ return load_late_stop_cpus(); + case UCODE_NFOUND: + return -ENOENT; + default: +@@ -421,7 +441,7 @@ static ssize_t reload_store(struct devic + return -EINVAL; + + cpus_read_lock(); +- ret = ucode_load_late_locked(); ++ ret = load_late_locked(); + cpus_read_unlock(); + + return ret ? : size; +--- a/arch/x86/kernel/cpu/microcode/internal.h ++++ b/arch/x86/kernel/cpu/microcode/internal.h +@@ -16,6 +16,7 @@ enum ucode_state { + UCODE_UPDATED, + UCODE_NFOUND, + UCODE_ERROR, ++ UCODE_TIMEOUT, + }; + + struct microcode_ops { diff --git a/queue-6.6/x86-microcode-amd-add-get_patch_level.patch b/queue-6.6/x86-microcode-amd-add-get_patch_level.patch new file mode 100644 index 0000000000..39488fa319 --- /dev/null +++ b/queue-6.6/x86-microcode-amd-add-get_patch_level.patch @@ -0,0 +1,141 @@ +From dcfc9697e6569d326cfef8ae6e068f94ce9cc947 Mon Sep 17 00:00:00 2001 +From: "Borislav Petkov (AMD)" +Date: Thu, 23 Jan 2025 13:02:32 +0100 +Subject: x86/microcode/AMD: Add get_patch_level() + +From: "Borislav Petkov (AMD)" + +commit 037e81fb9d2dfe7b31fd97e5f578854e38f09887 upstream + +Put the MSR_AMD64_PATCH_LEVEL reading of the current microcode revision +the hw has, into a separate function. + +Signed-off-by: Borislav Petkov (AMD) +Reviewed-by: Thomas Gleixner +Link: https://lore.kernel.org/r/20250211163648.30531-6-bp@kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/cpu/microcode/amd.c | 46 ++++++++++++++++++------------------ + 1 file changed, 24 insertions(+), 22 deletions(-) + +--- a/arch/x86/kernel/cpu/microcode/amd.c ++++ b/arch/x86/kernel/cpu/microcode/amd.c +@@ -147,6 +147,15 @@ ucode_path[] __maybe_unused = "kernel/x8 + */ + static u32 bsp_cpuid_1_eax __ro_after_init; + ++static u32 get_patch_level(void) ++{ ++ u32 rev, dummy __always_unused; ++ ++ native_rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy); ++ ++ return rev; ++} ++ + static union cpuid_1_eax ucode_rev_to_cpuid(unsigned int val) + { + union zen_patch_rev p; +@@ -486,10 +495,10 @@ static void scan_containers(u8 *ucode, s + } + } + +-static bool __apply_microcode_amd(struct microcode_amd *mc, unsigned int psize) ++static bool __apply_microcode_amd(struct microcode_amd *mc, u32 *cur_rev, ++ unsigned int psize) + { + unsigned long p_addr = (unsigned long)&mc->hdr.data_code; +- u32 rev, dummy; + + native_wrmsrl(MSR_AMD64_PATCH_LOADER, p_addr); + +@@ -507,9 +516,8 @@ static bool __apply_microcode_amd(struct + } + + /* verify patch application was successful */ +- native_rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy); +- +- if (rev != mc->hdr.patch_id) ++ *cur_rev = get_patch_level(); ++ if (*cur_rev != mc->hdr.patch_id) + return false; + + return true; +@@ -567,11 +575,12 @@ void __init load_ucode_amd_bsp(struct ea + struct cont_desc desc = { }; + struct microcode_amd *mc; + struct cpio_data cp = { }; +- u32 dummy; ++ u32 rev; + + bsp_cpuid_1_eax = cpuid_1_eax; + +- native_rdmsr(MSR_AMD64_PATCH_LEVEL, ed->old_rev, dummy); ++ rev = get_patch_level(); ++ ed->old_rev = rev; + + /* Needed in load_microcode_amd() */ + ucode_cpu_info[0].cpu_sig.sig = cpuid_1_eax; +@@ -593,8 +602,8 @@ void __init load_ucode_amd_bsp(struct ea + if (ed->old_rev > mc->hdr.patch_id) + return; + +- if (__apply_microcode_amd(mc, desc.psize)) +- native_rdmsr(MSR_AMD64_PATCH_LEVEL, ed->new_rev, dummy); ++ if (__apply_microcode_amd(mc, &rev, desc.psize)) ++ ed->new_rev = rev; + } + + static inline bool patch_cpus_equivalent(struct ucode_patch *p, +@@ -696,14 +705,9 @@ static void free_cache(void) + static struct ucode_patch *find_patch(unsigned int cpu) + { + struct ucode_cpu_info *uci = ucode_cpu_info + cpu; +- u32 rev, dummy __always_unused; + u16 equiv_id; + +- /* fetch rev if not populated yet: */ +- if (!uci->cpu_sig.rev) { +- rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy); +- uci->cpu_sig.rev = rev; +- } ++ uci->cpu_sig.rev = get_patch_level(); + + if (x86_family(bsp_cpuid_1_eax) < 0x17) { + equiv_id = find_equiv_id(&equiv_table, uci->cpu_sig.sig); +@@ -726,22 +730,20 @@ void reload_ucode_amd(unsigned int cpu) + + mc = p->data; + +- rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy); +- ++ rev = get_patch_level(); + if (rev < mc->hdr.patch_id) { +- if (__apply_microcode_amd(mc, p->size)) +- pr_info_once("reload revision: 0x%08x\n", mc->hdr.patch_id); ++ if (__apply_microcode_amd(mc, &rev, p->size)) ++ pr_info_once("reload revision: 0x%08x\n", rev); + } + } + + static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig) + { +- struct cpuinfo_x86 *c = &cpu_data(cpu); + struct ucode_cpu_info *uci = ucode_cpu_info + cpu; + struct ucode_patch *p; + + csig->sig = cpuid_eax(0x00000001); +- csig->rev = c->microcode; ++ csig->rev = get_patch_level(); + + /* + * a patch could have been loaded early, set uci->mc so that +@@ -782,7 +784,7 @@ static enum ucode_state apply_microcode_ + goto out; + } + +- if (!__apply_microcode_amd(mc_amd, p->size)) { ++ if (!__apply_microcode_amd(mc_amd, &rev, p->size)) { + pr_err("CPU%d: update failed for patch_level=0x%08x\n", + cpu, mc_amd->hdr.patch_id); + return UCODE_ERROR; diff --git a/queue-6.6/x86-microcode-amd-cache-builtin-initrd-microcode-early.patch b/queue-6.6/x86-microcode-amd-cache-builtin-initrd-microcode-early.patch new file mode 100644 index 0000000000..c6cb29317d --- /dev/null +++ b/queue-6.6/x86-microcode-amd-cache-builtin-initrd-microcode-early.patch @@ -0,0 +1,100 @@ +From 774c3e2de69911f2baaaaab1b3ef55ea25776a30 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Tue, 17 Oct 2023 23:23:53 +0200 +Subject: x86/microcode/amd: Cache builtin/initrd microcode early + +From: Thomas Gleixner + +commit a7939f01672034a58ad3fdbce69bb6c665ce0024 upstream + +There is no reason to scan builtin/initrd microcode on each AP. + +Cache the builtin/initrd microcode in an early initcall so that the +early AP loader can utilize the cache. + +The existing fs initcall which invoked save_microcode_in_initrd_amd() is +still required to maintain the initrd_gone flag. Rename it accordingly. +This will be removed once the AP loader code is converted to use the +cache. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Borislav Petkov (AMD) +Link: https://lore.kernel.org/r/20231017211723.187566507@linutronix.de +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/cpu/microcode/amd.c | 8 +++++++- + arch/x86/kernel/cpu/microcode/core.c | 26 ++++---------------------- + 2 files changed, 11 insertions(+), 23 deletions(-) + +--- a/arch/x86/kernel/cpu/microcode/amd.c ++++ b/arch/x86/kernel/cpu/microcode/amd.c +@@ -527,12 +527,17 @@ void load_ucode_amd_early(unsigned int c + + static enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t size); + +-int __init save_microcode_in_initrd_amd(unsigned int cpuid_1_eax) ++static int __init save_microcode_in_initrd(void) + { ++ unsigned int cpuid_1_eax = native_cpuid_eax(1); ++ struct cpuinfo_x86 *c = &boot_cpu_data; + struct cont_desc desc = { 0 }; + enum ucode_state ret; + struct cpio_data cp; + ++ if (dis_ucode_ldr || c->x86_vendor != X86_VENDOR_AMD || c->x86 < 0x10) ++ return 0; ++ + find_blobs_in_containers(cpuid_1_eax, &cp); + if (!(cp.data && cp.size)) + return -EINVAL; +@@ -549,6 +554,7 @@ int __init save_microcode_in_initrd_amd( + + return 0; + } ++early_initcall(save_microcode_in_initrd); + + /* + * a small, trivial cache of per-family ucode patches +--- a/arch/x86/kernel/cpu/microcode/core.c ++++ b/arch/x86/kernel/cpu/microcode/core.c +@@ -180,30 +180,13 @@ void load_ucode_ap(void) + } + } + +-static int __init save_microcode_in_initrd(void) ++/* Temporary workaround until find_microcode_in_initrd() is __init */ ++static int __init mark_initrd_gone(void) + { +- struct cpuinfo_x86 *c = &boot_cpu_data; +- int ret = -EINVAL; +- +- if (dis_ucode_ldr) { +- ret = 0; +- goto out; +- } +- +- switch (c->x86_vendor) { +- case X86_VENDOR_AMD: +- if (c->x86 >= 0x10) +- ret = save_microcode_in_initrd_amd(cpuid_eax(1)); +- break; +- default: +- break; +- } +- +-out: + initrd_gone = true; +- +- return ret; ++ return 0; + } ++fs_initcall(mark_initrd_gone); + + struct cpio_data find_microcode_in_initrd(const char *path) + { +@@ -621,5 +604,4 @@ static int __init microcode_init(void) + return error; + + } +-fs_initcall(save_microcode_in_initrd); + late_initcall(microcode_init); diff --git a/queue-6.6/x86-microcode-amd-cache-builtin-microcode-too.patch b/queue-6.6/x86-microcode-amd-cache-builtin-microcode-too.patch new file mode 100644 index 0000000000..d6e515164d --- /dev/null +++ b/queue-6.6/x86-microcode-amd-cache-builtin-microcode-too.patch @@ -0,0 +1,33 @@ +From 743fc38b6a60d7764b20ec7c383f327ff80d29c0 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Tue, 10 Oct 2023 17:08:43 +0200 +Subject: x86/microcode/amd: Cache builtin microcode too + +From: Thomas Gleixner + +commit d419d28261e72e1c9ec418711b3da41df2265139 upstream + +save_microcode_in_initrd_amd() fails to cache builtin microcode and only +scans initrd. + +Use find_blobs_in_containers() instead which covers both. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Borislav Petkov (AMD) +Link: https://lore.kernel.org/r/20231010150702.495139089@linutronix.de +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/cpu/microcode/amd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/x86/kernel/cpu/microcode/amd.c ++++ b/arch/x86/kernel/cpu/microcode/amd.c +@@ -533,7 +533,7 @@ int __init save_microcode_in_initrd_amd( + enum ucode_state ret; + struct cpio_data cp; + +- cp = find_microcode_in_initrd(ucode_path); ++ find_blobs_in_containers(cpuid_1_eax, &cp); + if (!(cp.data && cp.size)) + return -EINVAL; + diff --git a/queue-6.6/x86-microcode-amd-flush-patch-buffer-mapping-after-application.patch b/queue-6.6/x86-microcode-amd-flush-patch-buffer-mapping-after-application.patch new file mode 100644 index 0000000000..31e3a06ffb --- /dev/null +++ b/queue-6.6/x86-microcode-amd-flush-patch-buffer-mapping-after-application.patch @@ -0,0 +1,90 @@ +From 43796fa7351ee4f2b5bcc747e69a73d3fe722c34 Mon Sep 17 00:00:00 2001 +From: "Borislav Petkov (AMD)" +Date: Tue, 19 Nov 2024 12:21:33 +0100 +Subject: x86/microcode/AMD: Flush patch buffer mapping after application + +From: "Borislav Petkov (AMD)" + +commit c809b0d0e52d01c30066367b2952c4c4186b1047 upstream + +Due to specific requirements while applying microcode patches on Zen1 +and 2, the patch buffer mapping needs to be flushed from the TLB after +application. Do so. + +If not, unnecessary and unnatural delays happen in the boot process. + +Reported-by: Thomas De Schampheleire +Signed-off-by: Borislav Petkov (AMD) +Tested-by: Thomas De Schampheleire +Cc: # f1d84b59cbb9 ("x86/mm: Carve out INVLPG inline asm for use by others") +Link: https://lore.kernel.org/r/ZyulbYuvrkshfsd2@antipodes +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/cpu/microcode/amd.c | 25 ++++++++++++++++++++----- + 1 file changed, 20 insertions(+), 5 deletions(-) + +--- a/arch/x86/kernel/cpu/microcode/amd.c ++++ b/arch/x86/kernel/cpu/microcode/amd.c +@@ -34,6 +34,7 @@ + #include + #include + #include ++#include + + #include "internal.h" + +@@ -485,11 +486,25 @@ static void scan_containers(u8 *ucode, s + } + } + +-static int __apply_microcode_amd(struct microcode_amd *mc) ++static int __apply_microcode_amd(struct microcode_amd *mc, unsigned int psize) + { ++ unsigned long p_addr = (unsigned long)&mc->hdr.data_code; + u32 rev, dummy; + +- native_wrmsrl(MSR_AMD64_PATCH_LOADER, (u64)(long)&mc->hdr.data_code); ++ native_wrmsrl(MSR_AMD64_PATCH_LOADER, p_addr); ++ ++ if (x86_family(bsp_cpuid_1_eax) == 0x17) { ++ unsigned long p_addr_end = p_addr + psize - 1; ++ ++ invlpg(p_addr); ++ ++ /* ++ * Flush next page too if patch image is crossing a page ++ * boundary. ++ */ ++ if (p_addr >> PAGE_SHIFT != p_addr_end >> PAGE_SHIFT) ++ invlpg(p_addr_end); ++ } + + /* verify patch application was successful */ + native_rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy); +@@ -531,7 +546,7 @@ static bool early_apply_microcode(u32 ol + if (old_rev > mc->hdr.patch_id) + return ret; + +- return !__apply_microcode_amd(mc); ++ return !__apply_microcode_amd(mc, desc.psize); + } + + static bool get_builtin_microcode(struct cpio_data *cp) +@@ -747,7 +762,7 @@ void reload_ucode_amd(unsigned int cpu) + rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy); + + if (rev < mc->hdr.patch_id) { +- if (!__apply_microcode_amd(mc)) ++ if (!__apply_microcode_amd(mc, p->size)) + pr_info_once("reload revision: 0x%08x\n", mc->hdr.patch_id); + } + } +@@ -800,7 +815,7 @@ static enum ucode_state apply_microcode_ + goto out; + } + +- if (__apply_microcode_amd(mc_amd)) { ++ if (__apply_microcode_amd(mc_amd, p->size)) { + pr_err("CPU%d: update failed for patch_level=0x%08x\n", + cpu, mc_amd->hdr.patch_id); + return UCODE_ERROR; diff --git a/queue-6.6/x86-microcode-amd-get-rid-of-the-_load_microcode_amd-forward-declaration.patch b/queue-6.6/x86-microcode-amd-get-rid-of-the-_load_microcode_amd-forward-declaration.patch new file mode 100644 index 0000000000..257a269925 --- /dev/null +++ b/queue-6.6/x86-microcode-amd-get-rid-of-the-_load_microcode_amd-forward-declaration.patch @@ -0,0 +1,91 @@ +From 4dd1f715003bc4b5d86f83d849f069c3243bdcf4 Mon Sep 17 00:00:00 2001 +From: "Borislav Petkov (AMD)" +Date: Thu, 23 Jan 2025 12:51:37 +0100 +Subject: x86/microcode/AMD: Get rid of the _load_microcode_amd() forward declaration + +From: "Borislav Petkov (AMD)" + +commit b39c387164879eef71886fc93cee5ca7dd7bf500 upstream + +Simply move save_microcode_in_initrd() down. + +No functional changes. + +Signed-off-by: Borislav Petkov (AMD) +Reviewed-by: Thomas Gleixner +Link: https://lore.kernel.org/r/20250211163648.30531-5-bp@kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/cpu/microcode/amd.c | 54 +++++++++++++++++------------------- + 1 file changed, 26 insertions(+), 28 deletions(-) + +--- a/arch/x86/kernel/cpu/microcode/amd.c ++++ b/arch/x86/kernel/cpu/microcode/amd.c +@@ -597,34 +597,6 @@ void __init load_ucode_amd_bsp(struct ea + native_rdmsr(MSR_AMD64_PATCH_LEVEL, ed->new_rev, dummy); + } + +-static enum ucode_state _load_microcode_amd(u8 family, const u8 *data, size_t size); +- +-static int __init save_microcode_in_initrd(void) +-{ +- unsigned int cpuid_1_eax = native_cpuid_eax(1); +- struct cpuinfo_x86 *c = &boot_cpu_data; +- struct cont_desc desc = { 0 }; +- enum ucode_state ret; +- struct cpio_data cp; +- +- if (dis_ucode_ldr || c->x86_vendor != X86_VENDOR_AMD || c->x86 < 0x10) +- return 0; +- +- if (!find_blobs_in_containers(&cp)) +- return -EINVAL; +- +- scan_containers(cp.data, cp.size, &desc); +- if (!desc.mc) +- return -EINVAL; +- +- ret = _load_microcode_amd(x86_family(cpuid_1_eax), desc.data, desc.size); +- if (ret > UCODE_UPDATED) +- return -EINVAL; +- +- return 0; +-} +-early_initcall(save_microcode_in_initrd); +- + static inline bool patch_cpus_equivalent(struct ucode_patch *p, + struct ucode_patch *n, + bool ignore_stepping) +@@ -1008,6 +980,32 @@ static enum ucode_state load_microcode_a + return ret; + } + ++static int __init save_microcode_in_initrd(void) ++{ ++ unsigned int cpuid_1_eax = native_cpuid_eax(1); ++ struct cpuinfo_x86 *c = &boot_cpu_data; ++ struct cont_desc desc = { 0 }; ++ enum ucode_state ret; ++ struct cpio_data cp; ++ ++ if (dis_ucode_ldr || c->x86_vendor != X86_VENDOR_AMD || c->x86 < 0x10) ++ return 0; ++ ++ if (!find_blobs_in_containers(&cp)) ++ return -EINVAL; ++ ++ scan_containers(cp.data, cp.size, &desc); ++ if (!desc.mc) ++ return -EINVAL; ++ ++ ret = _load_microcode_amd(x86_family(cpuid_1_eax), desc.data, desc.size); ++ if (ret > UCODE_UPDATED) ++ return -EINVAL; ++ ++ return 0; ++} ++early_initcall(save_microcode_in_initrd); ++ + /* + * AMD microcode firmware naming convention, up to family 15h they are in + * the legacy file: diff --git a/queue-6.6/x86-microcode-amd-have-__apply_microcode_amd-return-bool.patch b/queue-6.6/x86-microcode-amd-have-__apply_microcode_amd-return-bool.patch new file mode 100644 index 0000000000..f81639ba22 --- /dev/null +++ b/queue-6.6/x86-microcode-amd-have-__apply_microcode_amd-return-bool.patch @@ -0,0 +1,69 @@ +From 51afb39e8de36dc4e1f48cb1ad1109c734d5f085 Mon Sep 17 00:00:00 2001 +From: "Borislav Petkov (AMD)" +Date: Mon, 18 Nov 2024 17:17:24 +0100 +Subject: x86/microcode/AMD: Have __apply_microcode_amd() return bool + +From: "Borislav Petkov (AMD)" + +commit 78e0aadbd4c6807a06a9d25bc190fe515d3f3c42 upstream + +This is the natural thing to do anyway. + +No functional changes. + +Signed-off-by: Borislav Petkov (AMD) +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/cpu/microcode/amd.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +--- a/arch/x86/kernel/cpu/microcode/amd.c ++++ b/arch/x86/kernel/cpu/microcode/amd.c +@@ -486,7 +486,7 @@ static void scan_containers(u8 *ucode, s + } + } + +-static int __apply_microcode_amd(struct microcode_amd *mc, unsigned int psize) ++static bool __apply_microcode_amd(struct microcode_amd *mc, unsigned int psize) + { + unsigned long p_addr = (unsigned long)&mc->hdr.data_code; + u32 rev, dummy; +@@ -510,9 +510,9 @@ static int __apply_microcode_amd(struct + native_rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy); + + if (rev != mc->hdr.patch_id) +- return -1; ++ return false; + +- return 0; ++ return true; + } + + /* +@@ -546,7 +546,7 @@ static bool early_apply_microcode(u32 ol + if (old_rev > mc->hdr.patch_id) + return ret; + +- return !__apply_microcode_amd(mc, desc.psize); ++ return __apply_microcode_amd(mc, desc.psize); + } + + static bool get_builtin_microcode(struct cpio_data *cp) +@@ -765,7 +765,7 @@ void reload_ucode_amd(unsigned int cpu) + rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy); + + if (rev < mc->hdr.patch_id) { +- if (!__apply_microcode_amd(mc, p->size)) ++ if (__apply_microcode_amd(mc, p->size)) + pr_info_once("reload revision: 0x%08x\n", mc->hdr.patch_id); + } + } +@@ -818,7 +818,7 @@ static enum ucode_state apply_microcode_ + goto out; + } + +- if (__apply_microcode_amd(mc_amd, p->size)) { ++ if (!__apply_microcode_amd(mc_amd, p->size)) { + pr_err("CPU%d: update failed for patch_level=0x%08x\n", + cpu, mc_amd->hdr.patch_id); + return UCODE_ERROR; diff --git a/queue-6.6/x86-microcode-amd-load-only-sha256-checksummed-patches.patch b/queue-6.6/x86-microcode-amd-load-only-sha256-checksummed-patches.patch new file mode 100644 index 0000000000..d074068b58 --- /dev/null +++ b/queue-6.6/x86-microcode-amd-load-only-sha256-checksummed-patches.patch @@ -0,0 +1,639 @@ +From 261d80764841b43ba45e79bf1798a4472a30e5b4 Mon Sep 17 00:00:00 2001 +From: "Borislav Petkov (AMD)" +Date: Thu, 23 Jan 2025 14:44:53 +0100 +Subject: x86/microcode/AMD: Load only SHA256-checksummed patches + +From: "Borislav Petkov (AMD)" + +commit 50cef76d5cb0e199cda19f026842560f6eedc4f7 upstream + +Load patches for which the driver carries a SHA256 checksum of the patch +blob. + +This can be disabled by adding "microcode.amd_sha_check=off" on the +kernel cmdline. But it is highly NOT recommended. + +Signed-off-by: Borislav Petkov (AMD) +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/Kconfig | 1 + arch/x86/kernel/cpu/microcode/amd.c | 111 +++++++ + arch/x86/kernel/cpu/microcode/amd_shas.c | 444 +++++++++++++++++++++++++++++++ + 3 files changed, 554 insertions(+), 2 deletions(-) + create mode 100644 arch/x86/kernel/cpu/microcode/amd_shas.c + +--- a/arch/x86/Kconfig ++++ b/arch/x86/Kconfig +@@ -1313,6 +1313,7 @@ config X86_REBOOTFIXUPS + config MICROCODE + def_bool y + depends on CPU_SUP_AMD || CPU_SUP_INTEL ++ select CRYPTO_LIB_SHA256 if CPU_SUP_AMD + + config MICROCODE_LATE_LOADING + bool "Late microcode loading (DANGEROUS)" +--- a/arch/x86/kernel/cpu/microcode/amd.c ++++ b/arch/x86/kernel/cpu/microcode/amd.c +@@ -23,14 +23,18 @@ + + #include + #include ++#include + #include + #include + #include + #include + #include + ++#include ++ + #include + #include ++#include + #include + #include + #include +@@ -147,6 +151,98 @@ ucode_path[] __maybe_unused = "kernel/x8 + */ + static u32 bsp_cpuid_1_eax __ro_after_init; + ++static bool sha_check = true; ++ ++struct patch_digest { ++ u32 patch_id; ++ u8 sha256[SHA256_DIGEST_SIZE]; ++}; ++ ++#include "amd_shas.c" ++ ++static int cmp_id(const void *key, const void *elem) ++{ ++ struct patch_digest *pd = (struct patch_digest *)elem; ++ u32 patch_id = *(u32 *)key; ++ ++ if (patch_id == pd->patch_id) ++ return 0; ++ else if (patch_id < pd->patch_id) ++ return -1; ++ else ++ return 1; ++} ++ ++static bool need_sha_check(u32 cur_rev) ++{ ++ switch (cur_rev >> 8) { ++ case 0x80012: return cur_rev <= 0x800126f; break; ++ case 0x83010: return cur_rev <= 0x830107c; break; ++ case 0x86001: return cur_rev <= 0x860010e; break; ++ case 0x86081: return cur_rev <= 0x8608108; break; ++ case 0x87010: return cur_rev <= 0x8701034; break; ++ case 0x8a000: return cur_rev <= 0x8a0000a; break; ++ case 0xa0011: return cur_rev <= 0xa0011da; break; ++ case 0xa0012: return cur_rev <= 0xa001243; break; ++ case 0xa1011: return cur_rev <= 0xa101153; break; ++ case 0xa1012: return cur_rev <= 0xa10124e; break; ++ case 0xa1081: return cur_rev <= 0xa108109; break; ++ case 0xa2010: return cur_rev <= 0xa20102f; break; ++ case 0xa2012: return cur_rev <= 0xa201212; break; ++ case 0xa6012: return cur_rev <= 0xa60120a; break; ++ case 0xa7041: return cur_rev <= 0xa704109; break; ++ case 0xa7052: return cur_rev <= 0xa705208; break; ++ case 0xa7080: return cur_rev <= 0xa708009; break; ++ case 0xa70c0: return cur_rev <= 0xa70C009; break; ++ case 0xaa002: return cur_rev <= 0xaa00218; break; ++ default: break; ++ } ++ ++ pr_info("You should not be seeing this. Please send the following couple of lines to x86--kernel.org\n"); ++ pr_info("CPUID(1).EAX: 0x%x, current revision: 0x%x\n", bsp_cpuid_1_eax, cur_rev); ++ return true; ++} ++ ++static bool verify_sha256_digest(u32 patch_id, u32 cur_rev, const u8 *data, unsigned int len) ++{ ++ struct patch_digest *pd = NULL; ++ u8 digest[SHA256_DIGEST_SIZE]; ++ struct sha256_state s; ++ int i; ++ ++ if (x86_family(bsp_cpuid_1_eax) < 0x17 || ++ x86_family(bsp_cpuid_1_eax) > 0x19) ++ return true; ++ ++ if (!need_sha_check(cur_rev)) ++ return true; ++ ++ if (!sha_check) ++ return true; ++ ++ pd = bsearch(&patch_id, phashes, ARRAY_SIZE(phashes), sizeof(struct patch_digest), cmp_id); ++ if (!pd) { ++ pr_err("No sha256 digest for patch ID: 0x%x found\n", patch_id); ++ return false; ++ } ++ ++ sha256_init(&s); ++ sha256_update(&s, data, len); ++ sha256_final(&s, digest); ++ ++ if (memcmp(digest, pd->sha256, sizeof(digest))) { ++ pr_err("Patch 0x%x SHA256 digest mismatch!\n", patch_id); ++ ++ for (i = 0; i < SHA256_DIGEST_SIZE; i++) ++ pr_cont("0x%x ", digest[i]); ++ pr_info("\n"); ++ ++ return false; ++ } ++ ++ return true; ++} ++ + static u32 get_patch_level(void) + { + u32 rev, dummy __always_unused; +@@ -500,6 +596,9 @@ static bool __apply_microcode_amd(struct + { + unsigned long p_addr = (unsigned long)&mc->hdr.data_code; + ++ if (!verify_sha256_digest(mc->hdr.patch_id, *cur_rev, (const u8 *)p_addr, psize)) ++ return -1; ++ + native_wrmsrl(MSR_AMD64_PATCH_LOADER, p_addr); + + if (x86_family(bsp_cpuid_1_eax) == 0x17) { +@@ -575,8 +674,17 @@ void __init load_ucode_amd_bsp(struct ea + struct cont_desc desc = { }; + struct microcode_amd *mc; + struct cpio_data cp = { }; ++ char buf[4]; + u32 rev; + ++ if (cmdline_find_option(boot_command_line, "microcode.amd_sha_check", buf, 4)) { ++ if (!strncmp(buf, "off", 3)) { ++ sha_check = false; ++ pr_warn_once("It is a very very bad idea to disable the blobs SHA check!\n"); ++ add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK); ++ } ++ } ++ + bsp_cpuid_1_eax = cpuid_1_eax; + + rev = get_patch_level(); +@@ -906,8 +1014,7 @@ static int verify_and_add_patch(u8 famil + } + + /* Scan the blob in @data and add microcode patches to the cache. */ +-static enum ucode_state __load_microcode_amd(u8 family, const u8 *data, +- size_t size) ++static enum ucode_state __load_microcode_amd(u8 family, const u8 *data, size_t size) + { + u8 *fw = (u8 *)data; + size_t offset; +--- /dev/null ++++ b/arch/x86/kernel/cpu/microcode/amd_shas.c +@@ -0,0 +1,444 @@ ++/* Keep 'em sorted. */ ++static const struct patch_digest phashes[] = { ++ { 0x8001227, { ++ 0x99,0xc0,0x9b,0x2b,0xcc,0x9f,0x52,0x1b, ++ 0x1a,0x5f,0x1d,0x83,0xa1,0x6c,0xc4,0x46, ++ 0xe2,0x6c,0xda,0x73,0xfb,0x2d,0x23,0xa8, ++ 0x77,0xdc,0x15,0x31,0x33,0x4a,0x46,0x18, ++ } ++ }, ++ { 0x8001250, { ++ 0xc0,0x0b,0x6b,0x19,0xfd,0x5c,0x39,0x60, ++ 0xd5,0xc3,0x57,0x46,0x54,0xe4,0xd1,0xaa, ++ 0xa8,0xf7,0x1f,0xa8,0x6a,0x60,0x3e,0xe3, ++ 0x27,0x39,0x8e,0x53,0x30,0xf8,0x49,0x19, ++ } ++ }, ++ { 0x800126e, { ++ 0xf3,0x8b,0x2b,0xb6,0x34,0xe3,0xc8,0x2c, ++ 0xef,0xec,0x63,0x6d,0xc8,0x76,0x77,0xb3, ++ 0x25,0x5a,0xb7,0x52,0x8c,0x83,0x26,0xe6, ++ 0x4c,0xbe,0xbf,0xe9,0x7d,0x22,0x6a,0x43, ++ } ++ }, ++ { 0x800126f, { ++ 0x2b,0x5a,0xf2,0x9c,0xdd,0xd2,0x7f,0xec, ++ 0xec,0x96,0x09,0x57,0xb0,0x96,0x29,0x8b, ++ 0x2e,0x26,0x91,0xf0,0x49,0x33,0x42,0x18, ++ 0xdd,0x4b,0x65,0x5a,0xd4,0x15,0x3d,0x33, ++ } ++ }, ++ { 0x800820d, { ++ 0x68,0x98,0x83,0xcd,0x22,0x0d,0xdd,0x59, ++ 0x73,0x2c,0x5b,0x37,0x1f,0x84,0x0e,0x67, ++ 0x96,0x43,0x83,0x0c,0x46,0x44,0xab,0x7c, ++ 0x7b,0x65,0x9e,0x57,0xb5,0x90,0x4b,0x0e, ++ } ++ }, ++ { 0x8301025, { ++ 0xe4,0x7d,0xdb,0x1e,0x14,0xb4,0x5e,0x36, ++ 0x8f,0x3e,0x48,0x88,0x3c,0x6d,0x76,0xa1, ++ 0x59,0xc6,0xc0,0x72,0x42,0xdf,0x6c,0x30, ++ 0x6f,0x0b,0x28,0x16,0x61,0xfc,0x79,0x77, ++ } ++ }, ++ { 0x8301055, { ++ 0x81,0x7b,0x99,0x1b,0xae,0x2d,0x4f,0x9a, ++ 0xef,0x13,0xce,0xb5,0x10,0xaf,0x6a,0xea, ++ 0xe5,0xb0,0x64,0x98,0x10,0x68,0x34,0x3b, ++ 0x9d,0x7a,0xd6,0x22,0x77,0x5f,0xb3,0x5b, ++ } ++ }, ++ { 0x8301072, { ++ 0xcf,0x76,0xa7,0x1a,0x49,0xdf,0x2a,0x5e, ++ 0x9e,0x40,0x70,0xe5,0xdd,0x8a,0xa8,0x28, ++ 0x20,0xdc,0x91,0xd8,0x2c,0xa6,0xa0,0xb1, ++ 0x2d,0x22,0x26,0x94,0x4b,0x40,0x85,0x30, ++ } ++ }, ++ { 0x830107a, { ++ 0x2a,0x65,0x8c,0x1a,0x5e,0x07,0x21,0x72, ++ 0xdf,0x90,0xa6,0x51,0x37,0xd3,0x4b,0x34, ++ 0xc4,0xda,0x03,0xe1,0x8a,0x6c,0xfb,0x20, ++ 0x04,0xb2,0x81,0x05,0xd4,0x87,0xf4,0x0a, ++ } ++ }, ++ { 0x830107b, { ++ 0xb3,0x43,0x13,0x63,0x56,0xc1,0x39,0xad, ++ 0x10,0xa6,0x2b,0xcc,0x02,0xe6,0x76,0x2a, ++ 0x1e,0x39,0x58,0x3e,0x23,0x6e,0xa4,0x04, ++ 0x95,0xea,0xf9,0x6d,0xc2,0x8a,0x13,0x19, ++ } ++ }, ++ { 0x830107c, { ++ 0x21,0x64,0xde,0xfb,0x9f,0x68,0x96,0x47, ++ 0x70,0x5c,0xe2,0x8f,0x18,0x52,0x6a,0xac, ++ 0xa4,0xd2,0x2e,0xe0,0xde,0x68,0x66,0xc3, ++ 0xeb,0x1e,0xd3,0x3f,0xbc,0x51,0x1d,0x38, ++ } ++ }, ++ { 0x860010d, { ++ 0x86,0xb6,0x15,0x83,0xbc,0x3b,0x9c,0xe0, ++ 0xb3,0xef,0x1d,0x99,0x84,0x35,0x15,0xf7, ++ 0x7c,0x2a,0xc6,0x42,0xdb,0x73,0x07,0x5c, ++ 0x7d,0xc3,0x02,0xb5,0x43,0x06,0x5e,0xf8, ++ } ++ }, ++ { 0x8608108, { ++ 0x14,0xfe,0x57,0x86,0x49,0xc8,0x68,0xe2, ++ 0x11,0xa3,0xcb,0x6e,0xff,0x6e,0xd5,0x38, ++ 0xfe,0x89,0x1a,0xe0,0x67,0xbf,0xc4,0xcc, ++ 0x1b,0x9f,0x84,0x77,0x2b,0x9f,0xaa,0xbd, ++ } ++ }, ++ { 0x8701034, { ++ 0xc3,0x14,0x09,0xa8,0x9c,0x3f,0x8d,0x83, ++ 0x9b,0x4c,0xa5,0xb7,0x64,0x8b,0x91,0x5d, ++ 0x85,0x6a,0x39,0x26,0x1e,0x14,0x41,0xa8, ++ 0x75,0xea,0xa6,0xf9,0xc9,0xd1,0xea,0x2b, ++ } ++ }, ++ { 0x8a00008, { ++ 0xd7,0x2a,0x93,0xdc,0x05,0x2f,0xa5,0x6e, ++ 0x0c,0x61,0x2c,0x07,0x9f,0x38,0xe9,0x8e, ++ 0xef,0x7d,0x2a,0x05,0x4d,0x56,0xaf,0x72, ++ 0xe7,0x56,0x47,0x6e,0x60,0x27,0xd5,0x8c, ++ } ++ }, ++ { 0x8a0000a, { ++ 0x73,0x31,0x26,0x22,0xd4,0xf9,0xee,0x3c, ++ 0x07,0x06,0xe7,0xb9,0xad,0xd8,0x72,0x44, ++ 0x33,0x31,0xaa,0x7d,0xc3,0x67,0x0e,0xdb, ++ 0x47,0xb5,0xaa,0xbc,0xf5,0xbb,0xd9,0x20, ++ } ++ }, ++ { 0xa00104c, { ++ 0x3c,0x8a,0xfe,0x04,0x62,0xd8,0x6d,0xbe, ++ 0xa7,0x14,0x28,0x64,0x75,0xc0,0xa3,0x76, ++ 0xb7,0x92,0x0b,0x97,0x0a,0x8e,0x9c,0x5b, ++ 0x1b,0xc8,0x9d,0x3a,0x1e,0x81,0x3d,0x3b, ++ } ++ }, ++ { 0xa00104e, { ++ 0xc4,0x35,0x82,0x67,0xd2,0x86,0xe5,0xb2, ++ 0xfd,0x69,0x12,0x38,0xc8,0x77,0xba,0xe0, ++ 0x70,0xf9,0x77,0x89,0x10,0xa6,0x74,0x4e, ++ 0x56,0x58,0x13,0xf5,0x84,0x70,0x28,0x0b, ++ } ++ }, ++ { 0xa001053, { ++ 0x92,0x0e,0xf4,0x69,0x10,0x3b,0xf9,0x9d, ++ 0x31,0x1b,0xa6,0x99,0x08,0x7d,0xd7,0x25, ++ 0x7e,0x1e,0x89,0xba,0x35,0x8d,0xac,0xcb, ++ 0x3a,0xb4,0xdf,0x58,0x12,0xcf,0xc0,0xc3, ++ } ++ }, ++ { 0xa001058, { ++ 0x33,0x7d,0xa9,0xb5,0x4e,0x62,0x13,0x36, ++ 0xef,0x66,0xc9,0xbd,0x0a,0xa6,0x3b,0x19, ++ 0xcb,0xf5,0xc2,0xc3,0x55,0x47,0x20,0xec, ++ 0x1f,0x7b,0xa1,0x44,0x0e,0x8e,0xa4,0xb2, ++ } ++ }, ++ { 0xa001075, { ++ 0x39,0x02,0x82,0xd0,0x7c,0x26,0x43,0xe9, ++ 0x26,0xa3,0xd9,0x96,0xf7,0x30,0x13,0x0a, ++ 0x8a,0x0e,0xac,0xe7,0x1d,0xdc,0xe2,0x0f, ++ 0xcb,0x9e,0x8d,0xbc,0xd2,0xa2,0x44,0xe0, ++ } ++ }, ++ { 0xa001078, { ++ 0x2d,0x67,0xc7,0x35,0xca,0xef,0x2f,0x25, ++ 0x4c,0x45,0x93,0x3f,0x36,0x01,0x8c,0xce, ++ 0xa8,0x5b,0x07,0xd3,0xc1,0x35,0x3c,0x04, ++ 0x20,0xa2,0xfc,0xdc,0xe6,0xce,0x26,0x3e, ++ } ++ }, ++ { 0xa001079, { ++ 0x43,0xe2,0x05,0x9c,0xfd,0xb7,0x5b,0xeb, ++ 0x5b,0xe9,0xeb,0x3b,0x96,0xf4,0xe4,0x93, ++ 0x73,0x45,0x3e,0xac,0x8d,0x3b,0xe4,0xdb, ++ 0x10,0x31,0xc1,0xe4,0xa2,0xd0,0x5a,0x8a, ++ } ++ }, ++ { 0xa00107a, { ++ 0x5f,0x92,0xca,0xff,0xc3,0x59,0x22,0x5f, ++ 0x02,0xa0,0x91,0x3b,0x4a,0x45,0x10,0xfd, ++ 0x19,0xe1,0x8a,0x6d,0x9a,0x92,0xc1,0x3f, ++ 0x75,0x78,0xac,0x78,0x03,0x1d,0xdb,0x18, ++ } ++ }, ++ { 0xa001143, { ++ 0x56,0xca,0xf7,0x43,0x8a,0x4c,0x46,0x80, ++ 0xec,0xde,0xe5,0x9c,0x50,0x84,0x9a,0x42, ++ 0x27,0xe5,0x51,0x84,0x8f,0x19,0xc0,0x8d, ++ 0x0c,0x25,0xb4,0xb0,0x8f,0x10,0xf3,0xf8, ++ } ++ }, ++ { 0xa001144, { ++ 0x42,0xd5,0x9b,0xa7,0xd6,0x15,0x29,0x41, ++ 0x61,0xc4,0x72,0x3f,0xf3,0x06,0x78,0x4b, ++ 0x65,0xf3,0x0e,0xfa,0x9c,0x87,0xde,0x25, ++ 0xbd,0xb3,0x9a,0xf4,0x75,0x13,0x53,0xdc, ++ } ++ }, ++ { 0xa00115d, { ++ 0xd4,0xc4,0x49,0x36,0x89,0x0b,0x47,0xdd, ++ 0xfb,0x2f,0x88,0x3b,0x5f,0xf2,0x8e,0x75, ++ 0xc6,0x6c,0x37,0x5a,0x90,0x25,0x94,0x3e, ++ 0x36,0x9c,0xae,0x02,0x38,0x6c,0xf5,0x05, ++ } ++ }, ++ { 0xa001173, { ++ 0x28,0xbb,0x9b,0xd1,0xa0,0xa0,0x7e,0x3a, ++ 0x59,0x20,0xc0,0xa9,0xb2,0x5c,0xc3,0x35, ++ 0x53,0x89,0xe1,0x4c,0x93,0x2f,0x1d,0xc3, ++ 0xe5,0xf7,0xf3,0xc8,0x9b,0x61,0xaa,0x9e, ++ } ++ }, ++ { 0xa0011a8, { ++ 0x97,0xc6,0x16,0x65,0x99,0xa4,0x85,0x3b, ++ 0xf6,0xce,0xaa,0x49,0x4a,0x3a,0xc5,0xb6, ++ 0x78,0x25,0xbc,0x53,0xaf,0x5d,0xcf,0xf4, ++ 0x23,0x12,0xbb,0xb1,0xbc,0x8a,0x02,0x2e, ++ } ++ }, ++ { 0xa0011ce, { ++ 0xcf,0x1c,0x90,0xa3,0x85,0x0a,0xbf,0x71, ++ 0x94,0x0e,0x80,0x86,0x85,0x4f,0xd7,0x86, ++ 0xae,0x38,0x23,0x28,0x2b,0x35,0x9b,0x4e, ++ 0xfe,0xb8,0xcd,0x3d,0x3d,0x39,0xc9,0x6a, ++ } ++ }, ++ { 0xa0011d1, { ++ 0xdf,0x0e,0xca,0xde,0xf6,0xce,0x5c,0x1e, ++ 0x4c,0xec,0xd7,0x71,0x83,0xcc,0xa8,0x09, ++ 0xc7,0xc5,0xfe,0xb2,0xf7,0x05,0xd2,0xc5, ++ 0x12,0xdd,0xe4,0xf3,0x92,0x1c,0x3d,0xb8, ++ } ++ }, ++ { 0xa0011d3, { ++ 0x91,0xe6,0x10,0xd7,0x57,0xb0,0x95,0x0b, ++ 0x9a,0x24,0xee,0xf7,0xcf,0x56,0xc1,0xa6, ++ 0x4a,0x52,0x7d,0x5f,0x9f,0xdf,0xf6,0x00, ++ 0x65,0xf7,0xea,0xe8,0x2a,0x88,0xe2,0x26, ++ } ++ }, ++ { 0xa0011d5, { ++ 0xed,0x69,0x89,0xf4,0xeb,0x64,0xc2,0x13, ++ 0xe0,0x51,0x1f,0x03,0x26,0x52,0x7d,0xb7, ++ 0x93,0x5d,0x65,0xca,0xb8,0x12,0x1d,0x62, ++ 0x0d,0x5b,0x65,0x34,0x69,0xb2,0x62,0x21, ++ } ++ }, ++ { 0xa001223, { ++ 0xfb,0x32,0x5f,0xc6,0x83,0x4f,0x8c,0xb8, ++ 0xa4,0x05,0xf9,0x71,0x53,0x01,0x16,0xc4, ++ 0x83,0x75,0x94,0xdd,0xeb,0x7e,0xb7,0x15, ++ 0x8e,0x3b,0x50,0x29,0x8a,0x9c,0xcc,0x45, ++ } ++ }, ++ { 0xa001224, { ++ 0x0e,0x0c,0xdf,0xb4,0x89,0xee,0x35,0x25, ++ 0xdd,0x9e,0xdb,0xc0,0x69,0x83,0x0a,0xad, ++ 0x26,0xa9,0xaa,0x9d,0xfc,0x3c,0xea,0xf9, ++ 0x6c,0xdc,0xd5,0x6d,0x8b,0x6e,0x85,0x4a, ++ } ++ }, ++ { 0xa001227, { ++ 0xab,0xc6,0x00,0x69,0x4b,0x50,0x87,0xad, ++ 0x5f,0x0e,0x8b,0xea,0x57,0x38,0xce,0x1d, ++ 0x0f,0x75,0x26,0x02,0xf6,0xd6,0x96,0xe9, ++ 0x87,0xb9,0xd6,0x20,0x27,0x7c,0xd2,0xe0, ++ } ++ }, ++ { 0xa001229, { ++ 0x7f,0x49,0x49,0x48,0x46,0xa5,0x50,0xa6, ++ 0x28,0x89,0x98,0xe2,0x9e,0xb4,0x7f,0x75, ++ 0x33,0xa7,0x04,0x02,0xe4,0x82,0xbf,0xb4, ++ 0xa5,0x3a,0xba,0x24,0x8d,0x31,0x10,0x1d, ++ } ++ }, ++ { 0xa00122e, { ++ 0x56,0x94,0xa9,0x5d,0x06,0x68,0xfe,0xaf, ++ 0xdf,0x7a,0xff,0x2d,0xdf,0x74,0x0f,0x15, ++ 0x66,0xfb,0x00,0xb5,0x51,0x97,0x9b,0xfa, ++ 0xcb,0x79,0x85,0x46,0x25,0xb4,0xd2,0x10, ++ } ++ }, ++ { 0xa001231, { ++ 0x0b,0x46,0xa5,0xfc,0x18,0x15,0xa0,0x9e, ++ 0xa6,0xdc,0xb7,0xff,0x17,0xf7,0x30,0x64, ++ 0xd4,0xda,0x9e,0x1b,0xc3,0xfc,0x02,0x3b, ++ 0xe2,0xc6,0x0e,0x41,0x54,0xb5,0x18,0xdd, ++ } ++ }, ++ { 0xa001234, { ++ 0x88,0x8d,0xed,0xab,0xb5,0xbd,0x4e,0xf7, ++ 0x7f,0xd4,0x0e,0x95,0x34,0x91,0xff,0xcc, ++ 0xfb,0x2a,0xcd,0xf7,0xd5,0xdb,0x4c,0x9b, ++ 0xd6,0x2e,0x73,0x50,0x8f,0x83,0x79,0x1a, ++ } ++ }, ++ { 0xa001236, { ++ 0x3d,0x30,0x00,0xb9,0x71,0xba,0x87,0x78, ++ 0xa8,0x43,0x55,0xc4,0x26,0x59,0xcf,0x9d, ++ 0x93,0xce,0x64,0x0e,0x8b,0x72,0x11,0x8b, ++ 0xa3,0x8f,0x51,0xe9,0xca,0x98,0xaa,0x25, ++ } ++ }, ++ { 0xa001238, { ++ 0x72,0xf7,0x4b,0x0c,0x7d,0x58,0x65,0xcc, ++ 0x00,0xcc,0x57,0x16,0x68,0x16,0xf8,0x2a, ++ 0x1b,0xb3,0x8b,0xe1,0xb6,0x83,0x8c,0x7e, ++ 0xc0,0xcd,0x33,0xf2,0x8d,0xf9,0xef,0x59, ++ } ++ }, ++ { 0xa00820c, { ++ 0xa8,0x0c,0x81,0xc0,0xa6,0x00,0xe7,0xf3, ++ 0x5f,0x65,0xd3,0xb9,0x6f,0xea,0x93,0x63, ++ 0xf1,0x8c,0x88,0x45,0xd7,0x82,0x80,0xd1, ++ 0xe1,0x3b,0x8d,0xb2,0xf8,0x22,0x03,0xe2, ++ } ++ }, ++ { 0xa10113e, { ++ 0x05,0x3c,0x66,0xd7,0xa9,0x5a,0x33,0x10, ++ 0x1b,0xf8,0x9c,0x8f,0xed,0xfc,0xa7,0xa0, ++ 0x15,0xe3,0x3f,0x4b,0x1d,0x0d,0x0a,0xd5, ++ 0xfa,0x90,0xc4,0xed,0x9d,0x90,0xaf,0x53, ++ } ++ }, ++ { 0xa101144, { ++ 0xb3,0x0b,0x26,0x9a,0xf8,0x7c,0x02,0x26, ++ 0x35,0x84,0x53,0xa4,0xd3,0x2c,0x7c,0x09, ++ 0x68,0x7b,0x96,0xb6,0x93,0xef,0xde,0xbc, ++ 0xfd,0x4b,0x15,0xd2,0x81,0xd3,0x51,0x47, ++ } ++ }, ++ { 0xa101148, { ++ 0x20,0xd5,0x6f,0x40,0x4a,0xf6,0x48,0x90, ++ 0xc2,0x93,0x9a,0xc2,0xfd,0xac,0xef,0x4f, ++ 0xfa,0xc0,0x3d,0x92,0x3c,0x6d,0x01,0x08, ++ 0xf1,0x5e,0xb0,0xde,0xb4,0x98,0xae,0xc4, ++ } ++ }, ++ { 0xa10123e, { ++ 0x03,0xb9,0x2c,0x76,0x48,0x93,0xc9,0x18, ++ 0xfb,0x56,0xfd,0xf7,0xe2,0x1d,0xca,0x4d, ++ 0x1d,0x13,0x53,0x63,0xfe,0x42,0x6f,0xfc, ++ 0x19,0x0f,0xf1,0xfc,0xa7,0xdd,0x89,0x1b, ++ } ++ }, ++ { 0xa101244, { ++ 0x71,0x56,0xb5,0x9f,0x21,0xbf,0xb3,0x3c, ++ 0x8c,0xd7,0x36,0xd0,0x34,0x52,0x1b,0xb1, ++ 0x46,0x2f,0x04,0xf0,0x37,0xd8,0x1e,0x72, ++ 0x24,0xa2,0x80,0x84,0x83,0x65,0x84,0xc0, ++ } ++ }, ++ { 0xa101248, { ++ 0xed,0x3b,0x95,0xa6,0x68,0xa7,0x77,0x3e, ++ 0xfc,0x17,0x26,0xe2,0x7b,0xd5,0x56,0x22, ++ 0x2c,0x1d,0xef,0xeb,0x56,0xdd,0xba,0x6e, ++ 0x1b,0x7d,0x64,0x9d,0x4b,0x53,0x13,0x75, ++ } ++ }, ++ { 0xa108108, { ++ 0xed,0xc2,0xec,0xa1,0x15,0xc6,0x65,0xe9, ++ 0xd0,0xef,0x39,0xaa,0x7f,0x55,0x06,0xc6, ++ 0xf5,0xd4,0x3f,0x7b,0x14,0xd5,0x60,0x2c, ++ 0x28,0x1e,0x9c,0x59,0x69,0x99,0x4d,0x16, ++ } ++ }, ++ { 0xa20102d, { ++ 0xf9,0x6e,0xf2,0x32,0xd3,0x0f,0x5f,0x11, ++ 0x59,0xa1,0xfe,0xcc,0xcd,0x9b,0x42,0x89, ++ 0x8b,0x89,0x2f,0xb5,0xbb,0x82,0xef,0x23, ++ 0x8c,0xe9,0x19,0x3e,0xcc,0x3f,0x7b,0xb4, ++ } ++ }, ++ { 0xa201210, { ++ 0xe8,0x6d,0x51,0x6a,0x8e,0x72,0xf3,0xfe, ++ 0x6e,0x16,0xbc,0x62,0x59,0x40,0x17,0xe9, ++ 0x6d,0x3d,0x0e,0x6b,0xa7,0xac,0xe3,0x68, ++ 0xf7,0x55,0xf0,0x13,0xbb,0x22,0xf6,0x41, ++ } ++ }, ++ { 0xa404107, { ++ 0xbb,0x04,0x4e,0x47,0xdd,0x5e,0x26,0x45, ++ 0x1a,0xc9,0x56,0x24,0xa4,0x4c,0x82,0xb0, ++ 0x8b,0x0d,0x9f,0xf9,0x3a,0xdf,0xc6,0x81, ++ 0x13,0xbc,0xc5,0x25,0xe4,0xc5,0xc3,0x99, ++ } ++ }, ++ { 0xa500011, { ++ 0x23,0x3d,0x70,0x7d,0x03,0xc3,0xc4,0xf4, ++ 0x2b,0x82,0xc6,0x05,0xda,0x80,0x0a,0xf1, ++ 0xd7,0x5b,0x65,0x3a,0x7d,0xab,0xdf,0xa2, ++ 0x11,0x5e,0x96,0x7e,0x71,0xe9,0xfc,0x74, ++ } ++ }, ++ { 0xa601209, { ++ 0x66,0x48,0xd4,0x09,0x05,0xcb,0x29,0x32, ++ 0x66,0xb7,0x9a,0x76,0xcd,0x11,0xf3,0x30, ++ 0x15,0x86,0xcc,0x5d,0x97,0x0f,0xc0,0x46, ++ 0xe8,0x73,0xe2,0xd6,0xdb,0xd2,0x77,0x1d, ++ } ++ }, ++ { 0xa704107, { ++ 0xf3,0xc6,0x58,0x26,0xee,0xac,0x3f,0xd6, ++ 0xce,0xa1,0x72,0x47,0x3b,0xba,0x2b,0x93, ++ 0x2a,0xad,0x8e,0x6b,0xea,0x9b,0xb7,0xc2, ++ 0x64,0x39,0x71,0x8c,0xce,0xe7,0x41,0x39, ++ } ++ }, ++ { 0xa705206, { ++ 0x8d,0xc0,0x76,0xbd,0x58,0x9f,0x8f,0xa4, ++ 0x12,0x9d,0x21,0xfb,0x48,0x21,0xbc,0xe7, ++ 0x67,0x6f,0x04,0x18,0xae,0x20,0x87,0x4b, ++ 0x03,0x35,0xe9,0xbe,0xfb,0x06,0xdf,0xfc, ++ } ++ }, ++ { 0xa708007, { ++ 0x6b,0x76,0xcc,0x78,0xc5,0x8a,0xa3,0xe3, ++ 0x32,0x2d,0x79,0xe4,0xc3,0x80,0xdb,0xb2, ++ 0x07,0xaa,0x3a,0xe0,0x57,0x13,0x72,0x80, ++ 0xdf,0x92,0x73,0x84,0x87,0x3c,0x73,0x93, ++ } ++ }, ++ { 0xa70c005, { ++ 0x88,0x5d,0xfb,0x79,0x64,0xd8,0x46,0x3b, ++ 0x4a,0x83,0x8e,0x77,0x7e,0xcf,0xb3,0x0f, ++ 0x1f,0x1f,0xf1,0x97,0xeb,0xfe,0x56,0x55, ++ 0xee,0x49,0xac,0xe1,0x8b,0x13,0xc5,0x13, ++ } ++ }, ++ { 0xaa00116, { ++ 0xe8,0x4c,0x2c,0x88,0xa1,0xac,0x24,0x63, ++ 0x65,0xe5,0xaa,0x2d,0x16,0xa9,0xc3,0xf5, ++ 0xfe,0x1d,0x5e,0x65,0xc7,0xaa,0x92,0x4d, ++ 0x91,0xee,0x76,0xbb,0x4c,0x66,0x78,0xc9, ++ } ++ }, ++ { 0xaa00212, { ++ 0xbd,0x57,0x5d,0x0a,0x0a,0x30,0xc1,0x75, ++ 0x95,0x58,0x5e,0x93,0x02,0x28,0x43,0x71, ++ 0xed,0x42,0x29,0xc8,0xec,0x34,0x2b,0xb2, ++ 0x1a,0x65,0x4b,0xfe,0x07,0x0f,0x34,0xa1, ++ } ++ }, ++ { 0xaa00213, { ++ 0xed,0x58,0xb7,0x76,0x81,0x7f,0xd9,0x3a, ++ 0x1a,0xff,0x8b,0x34,0xb8,0x4a,0x99,0x0f, ++ 0x28,0x49,0x6c,0x56,0x2b,0xdc,0xb7,0xed, ++ 0x96,0xd5,0x9d,0xc1,0x7a,0xd4,0x51,0x9b, ++ } ++ }, ++ { 0xaa00215, { ++ 0x55,0xd3,0x28,0xcb,0x87,0xa9,0x32,0xe9, ++ 0x4e,0x85,0x4b,0x7c,0x6b,0xd5,0x7c,0xd4, ++ 0x1b,0x51,0x71,0x3a,0x0e,0x0b,0xdc,0x9b, ++ 0x68,0x2f,0x46,0xee,0xfe,0xc6,0x6d,0xef, ++ } ++ }, ++}; diff --git a/queue-6.6/x86-microcode-amd-make-__verify_patch_size-return-bool.patch b/queue-6.6/x86-microcode-amd-make-__verify_patch_size-return-bool.patch new file mode 100644 index 0000000000..c6457ea7c8 --- /dev/null +++ b/queue-6.6/x86-microcode-amd-make-__verify_patch_size-return-bool.patch @@ -0,0 +1,79 @@ +From 251ca274aa7d61a36f63239b72a6fca05ec00875 Mon Sep 17 00:00:00 2001 +From: Nikolay Borisov +Date: Fri, 18 Oct 2024 18:51:50 +0300 +Subject: x86/microcode/AMD: Make __verify_patch_size() return bool + +From: Nikolay Borisov + +commit d8317f3d8e6b412ff51ea66f1de2b2f89835f811 upstream + +The result of that function is in essence boolean, so simplify to return the +result of the relevant expression. It also makes it follow the convention used +by __verify_patch_section(). + +No functional changes. + +Signed-off-by: Nikolay Borisov +Signed-off-by: Borislav Petkov (AMD) +Link: https://lore.kernel.org/r/20241018155151.702350-3-nik.borisov@suse.com +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/cpu/microcode/amd.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +--- a/arch/x86/kernel/cpu/microcode/amd.c ++++ b/arch/x86/kernel/cpu/microcode/amd.c +@@ -285,13 +285,13 @@ __verify_patch_section(const u8 *buf, si + * exceed the per-family maximum). @sh_psize is the size read from the section + * header. + */ +-static unsigned int __verify_patch_size(u32 sh_psize, size_t buf_size) ++static bool __verify_patch_size(u32 sh_psize, size_t buf_size) + { + u8 family = x86_family(bsp_cpuid_1_eax); + u32 max_size; + + if (family >= 0x15) +- return min_t(u32, sh_psize, buf_size); ++ goto ret; + + #define F1XH_MPB_MAX_SIZE 2048 + #define F14H_MPB_MAX_SIZE 1824 +@@ -305,13 +305,15 @@ static unsigned int __verify_patch_size( + break; + default: + WARN(1, "%s: WTF family: 0x%x\n", __func__, family); +- return 0; ++ return false; + } + +- if (sh_psize > min_t(u32, buf_size, max_size)) +- return 0; ++ if (sh_psize > max_size) ++ return false; + +- return sh_psize; ++ret: ++ /* Working with the whole buffer so < is ok. */ ++ return sh_psize <= buf_size; + } + + /* +@@ -326,7 +328,6 @@ static int verify_patch(const u8 *buf, s + { + u8 family = x86_family(bsp_cpuid_1_eax); + struct microcode_header_amd *mc_hdr; +- unsigned int ret; + u32 sh_psize; + u16 proc_id; + u8 patch_fam; +@@ -350,8 +351,7 @@ static int verify_patch(const u8 *buf, s + return -1; + } + +- ret = __verify_patch_size(sh_psize, buf_size); +- if (!ret) { ++ if (!__verify_patch_size(sh_psize, buf_size)) { + pr_debug("Per-family patch size mismatch.\n"); + return -1; + } diff --git a/queue-6.6/x86-microcode-amd-merge-early_apply_microcode-into-its-single-callsite.patch b/queue-6.6/x86-microcode-amd-merge-early_apply_microcode-into-its-single-callsite.patch new file mode 100644 index 0000000000..5a7dcd4ac6 --- /dev/null +++ b/queue-6.6/x86-microcode-amd-merge-early_apply_microcode-into-its-single-callsite.patch @@ -0,0 +1,104 @@ +From d0ac6b03dd875fe519561db889f5ba3466d1a53b Mon Sep 17 00:00:00 2001 +From: "Borislav Petkov (AMD)" +Date: Thu, 23 Jan 2025 12:46:45 +0100 +Subject: x86/microcode/AMD: Merge early_apply_microcode() into its single callsite + +From: "Borislav Petkov (AMD)" + +commit dc15675074dcfd79a2f10a6e39f96b0244961a01 upstream + +No functional changes. + +Signed-off-by: Borislav Petkov (AMD) +Reviewed-by: Thomas Gleixner +Link: https://lore.kernel.org/r/20250211163648.30531-4-bp@kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/cpu/microcode/amd.c | 60 +++++++++++++++--------------------- + 1 file changed, 26 insertions(+), 34 deletions(-) + +--- a/arch/x86/kernel/cpu/microcode/amd.c ++++ b/arch/x86/kernel/cpu/microcode/amd.c +@@ -515,39 +515,6 @@ static bool __apply_microcode_amd(struct + return true; + } + +-/* +- * Early load occurs before we can vmalloc(). So we look for the microcode +- * patch container file in initrd, traverse equivalent cpu table, look for a +- * matching microcode patch, and update, all in initrd memory in place. +- * When vmalloc() is available for use later -- on 64-bit during first AP load, +- * and on 32-bit during save_microcode_in_initrd_amd() -- we can call +- * load_microcode_amd() to save equivalent cpu table and microcode patches in +- * kernel heap memory. +- * +- * Returns true if container found (sets @desc), false otherwise. +- */ +-static bool early_apply_microcode(u32 old_rev, void *ucode, size_t size) +-{ +- struct cont_desc desc = { 0 }; +- struct microcode_amd *mc; +- bool ret = false; +- +- scan_containers(ucode, size, &desc); +- +- mc = desc.mc; +- if (!mc) +- return ret; +- +- /* +- * Allow application of the same revision to pick up SMT-specific +- * changes even if the revision of the other SMT thread is already +- * up-to-date. +- */ +- if (old_rev > mc->hdr.patch_id) +- return ret; +- +- return __apply_microcode_amd(mc, desc.psize); +-} + + static bool get_builtin_microcode(struct cpio_data *cp) + { +@@ -586,8 +553,19 @@ static bool __init find_blobs_in_contain + return found; + } + ++/* ++ * Early load occurs before we can vmalloc(). So we look for the microcode ++ * patch container file in initrd, traverse equivalent cpu table, look for a ++ * matching microcode patch, and update, all in initrd memory in place. ++ * When vmalloc() is available for use later -- on 64-bit during first AP load, ++ * and on 32-bit during save_microcode_in_initrd() -- we can call ++ * load_microcode_amd() to save equivalent cpu table and microcode patches in ++ * kernel heap memory. ++ */ + void __init load_ucode_amd_bsp(struct early_load_data *ed, unsigned int cpuid_1_eax) + { ++ struct cont_desc desc = { }; ++ struct microcode_amd *mc; + struct cpio_data cp = { }; + u32 dummy; + +@@ -601,7 +579,21 @@ void __init load_ucode_amd_bsp(struct ea + if (!find_blobs_in_containers(&cp)) + return; + +- if (early_apply_microcode(ed->old_rev, cp.data, cp.size)) ++ scan_containers(cp.data, cp.size, &desc); ++ ++ mc = desc.mc; ++ if (!mc) ++ return; ++ ++ /* ++ * Allow application of the same revision to pick up SMT-specific ++ * changes even if the revision of the other SMT thread is already ++ * up-to-date. ++ */ ++ if (ed->old_rev > mc->hdr.patch_id) ++ return; ++ ++ if (__apply_microcode_amd(mc, desc.psize)) + native_rdmsr(MSR_AMD64_PATCH_LEVEL, ed->new_rev, dummy); + } + diff --git a/queue-6.6/x86-microcode-amd-pay-attention-to-the-stepping-dynamically.patch b/queue-6.6/x86-microcode-amd-pay-attention-to-the-stepping-dynamically.patch new file mode 100644 index 0000000000..e0f8161066 --- /dev/null +++ b/queue-6.6/x86-microcode-amd-pay-attention-to-the-stepping-dynamically.patch @@ -0,0 +1,100 @@ +From d3b57478de5a355a804aea35da762a9c9e345b46 Mon Sep 17 00:00:00 2001 +From: "Borislav Petkov (AMD)" +Date: Mon, 21 Oct 2024 10:27:52 +0200 +Subject: x86/microcode/AMD: Pay attention to the stepping dynamically + +From: "Borislav Petkov (AMD)" + +commit d1744a4c975b1acbe8b498356d28afbc46c88428 upstream + +Commit in Fixes changed how a microcode patch is loaded on Zen and newer but +the patch matching needs to happen with different rigidity, depending on what +is being done: + +1) When the patch is added to the patches cache, the stepping must be ignored + because the driver still supports different steppings per system + +2) When the patch is matched for loading, then the stepping must be taken into + account because each CPU needs the patch matching its exact stepping + +Take care of that by making the matching smarter. + +Fixes: 94838d230a6c ("x86/microcode/AMD: Use the family,model,stepping encoded in the patch ID") +Reported-by: Jens Axboe +Signed-off-by: Borislav Petkov (AMD) +Tested-by: Jens Axboe +Link: https://lore.kernel.org/r/91194406-3fdf-4e38-9838-d334af538f74@kernel.dk +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/cpu/microcode/amd.c | 26 ++++++++++++++++++-------- + 1 file changed, 18 insertions(+), 8 deletions(-) + +--- a/arch/x86/kernel/cpu/microcode/amd.c ++++ b/arch/x86/kernel/cpu/microcode/amd.c +@@ -615,16 +615,19 @@ static int __init save_microcode_in_init + } + early_initcall(save_microcode_in_initrd); + +-static inline bool patch_cpus_equivalent(struct ucode_patch *p, struct ucode_patch *n) ++static inline bool patch_cpus_equivalent(struct ucode_patch *p, ++ struct ucode_patch *n, ++ bool ignore_stepping) + { + /* Zen and newer hardcode the f/m/s in the patch ID */ + if (x86_family(bsp_cpuid_1_eax) >= 0x17) { + union cpuid_1_eax p_cid = ucode_rev_to_cpuid(p->patch_id); + union cpuid_1_eax n_cid = ucode_rev_to_cpuid(n->patch_id); + +- /* Zap stepping */ +- p_cid.stepping = 0; +- n_cid.stepping = 0; ++ if (ignore_stepping) { ++ p_cid.stepping = 0; ++ n_cid.stepping = 0; ++ } + + return p_cid.full == n_cid.full; + } else { +@@ -646,13 +649,13 @@ static struct ucode_patch *cache_find_pa + WARN_ON_ONCE(!n.patch_id); + + list_for_each_entry(p, µcode_cache, plist) +- if (patch_cpus_equivalent(p, &n)) ++ if (patch_cpus_equivalent(p, &n, false)) + return p; + + return NULL; + } + +-static inline bool patch_newer(struct ucode_patch *p, struct ucode_patch *n) ++static inline int patch_newer(struct ucode_patch *p, struct ucode_patch *n) + { + /* Zen and newer hardcode the f/m/s in the patch ID */ + if (x86_family(bsp_cpuid_1_eax) >= 0x17) { +@@ -661,6 +664,9 @@ static inline bool patch_newer(struct uc + zp.ucode_rev = p->patch_id; + zn.ucode_rev = n->patch_id; + ++ if (zn.stepping != zp.stepping) ++ return -1; ++ + return zn.rev > zp.rev; + } else { + return n->patch_id > p->patch_id; +@@ -670,10 +676,14 @@ static inline bool patch_newer(struct uc + static void update_cache(struct ucode_patch *new_patch) + { + struct ucode_patch *p; ++ int ret; + + list_for_each_entry(p, µcode_cache, plist) { +- if (patch_cpus_equivalent(p, new_patch)) { +- if (!patch_newer(p, new_patch)) { ++ if (patch_cpus_equivalent(p, new_patch, true)) { ++ ret = patch_newer(p, new_patch); ++ if (ret < 0) ++ continue; ++ else if (!ret) { + /* we already have the latest patch */ + kfree(new_patch->data); + kfree(new_patch); diff --git a/queue-6.6/x86-microcode-amd-return-bool-from-find_blobs_in_containers.patch b/queue-6.6/x86-microcode-amd-return-bool-from-find_blobs_in_containers.patch new file mode 100644 index 0000000000..85e907270b --- /dev/null +++ b/queue-6.6/x86-microcode-amd-return-bool-from-find_blobs_in_containers.patch @@ -0,0 +1,69 @@ +From 10f93d372e36136bd6b87c6f818cba54da688ed4 Mon Sep 17 00:00:00 2001 +From: Nikolay Borisov +Date: Fri, 18 Oct 2024 18:51:49 +0300 +Subject: x86/microcode/AMD: Return bool from find_blobs_in_containers() + +From: Nikolay Borisov + +commit a85c08aaa665b5436d325f6d7138732a0e1315ce upstream + +Instead of open-coding the check for size/data move it inside the +function and make it return a boolean indicating whether data was found +or not. + +No functional changes. + + [ bp: Write @ret in find_blobs_in_containers() only on success. ] + +Signed-off-by: Nikolay Borisov +Signed-off-by: Borislav Petkov (AMD) +Link: https://lore.kernel.org/r/20241018155151.702350-2-nik.borisov@suse.com +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/cpu/microcode/amd.c | 15 +++++++++------ + 1 file changed, 9 insertions(+), 6 deletions(-) + +--- a/arch/x86/kernel/cpu/microcode/amd.c ++++ b/arch/x86/kernel/cpu/microcode/amd.c +@@ -571,14 +571,19 @@ static bool get_builtin_microcode(struct + return false; + } + +-static void __init find_blobs_in_containers(struct cpio_data *ret) ++static bool __init find_blobs_in_containers(struct cpio_data *ret) + { + struct cpio_data cp; ++ bool found; + + if (!get_builtin_microcode(&cp)) + cp = find_microcode_in_initrd(ucode_path); + +- *ret = cp; ++ found = cp.data && cp.size; ++ if (found) ++ *ret = cp; ++ ++ return found; + } + + void __init load_ucode_amd_bsp(struct early_load_data *ed, unsigned int cpuid_1_eax) +@@ -593,8 +598,7 @@ void __init load_ucode_amd_bsp(struct ea + /* Needed in load_microcode_amd() */ + ucode_cpu_info[0].cpu_sig.sig = cpuid_1_eax; + +- find_blobs_in_containers(&cp); +- if (!(cp.data && cp.size)) ++ if (!find_blobs_in_containers(&cp)) + return; + + if (early_apply_microcode(ed->old_rev, cp.data, cp.size)) +@@ -614,8 +618,7 @@ static int __init save_microcode_in_init + if (dis_ucode_ldr || c->x86_vendor != X86_VENDOR_AMD || c->x86 < 0x10) + return 0; + +- find_blobs_in_containers(&cp); +- if (!(cp.data && cp.size)) ++ if (!find_blobs_in_containers(&cp)) + return -EINVAL; + + scan_containers(cp.data, cp.size, &desc); diff --git a/queue-6.6/x86-microcode-amd-split-load_microcode_amd.patch b/queue-6.6/x86-microcode-amd-split-load_microcode_amd.patch new file mode 100644 index 0000000000..deab297d8a --- /dev/null +++ b/queue-6.6/x86-microcode-amd-split-load_microcode_amd.patch @@ -0,0 +1,100 @@ +From a33c9b7c9df314a89aa8c43889a6a92495a6f29b Mon Sep 17 00:00:00 2001 +From: "Borislav Petkov (AMD)" +Date: Mon, 21 Oct 2024 10:38:21 +0200 +Subject: x86/microcode/AMD: Split load_microcode_amd() + +From: "Borislav Petkov (AMD)" + +commit 1d81d85d1a19e50d5237dc67d6b825c34ae13de8 upstream + +This function should've been split a long time ago because it is used in +two paths: + +1) On the late loading path, when the microcode is loaded through the + request_firmware interface + +2) In the save_microcode_in_initrd() path which collects all the + microcode patches which are relevant for the current system before + the initrd with the microcode container has been jettisoned. + + In that path, it is not really necessary to iterate over the nodes on + a system and match a patch however it didn't cause any trouble so it + was left for a later cleanup + +However, that later cleanup was expedited by the fact that Jens was +enabling "Use L3 as a NUMA node" in the BIOS setting in his machine and +so this causes the NUMA CPU masks used in cpumask_of_node() to be +generated *after* 2) above happened on the first node. Which means, all +those masks were funky, wrong, uninitialized and whatnot, leading to +explosions when dereffing c->microcode in load_microcode_amd(). + +So split that function and do only the necessary work needed at each +stage. + +Fixes: 94838d230a6c ("x86/microcode/AMD: Use the family,model,stepping encoded in the patch ID") +Reported-by: Jens Axboe +Signed-off-by: Borislav Petkov (AMD) +Tested-by: Jens Axboe +Link: https://lore.kernel.org/r/91194406-3fdf-4e38-9838-d334af538f74@kernel.dk +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/cpu/microcode/amd.c | 25 +++++++++++++++++-------- + 1 file changed, 17 insertions(+), 8 deletions(-) + +--- a/arch/x86/kernel/cpu/microcode/amd.c ++++ b/arch/x86/kernel/cpu/microcode/amd.c +@@ -586,7 +586,7 @@ void __init load_ucode_amd_bsp(struct ea + native_rdmsr(MSR_AMD64_PATCH_LEVEL, ed->new_rev, dummy); + } + +-static enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t size); ++static enum ucode_state _load_microcode_amd(u8 family, const u8 *data, size_t size); + + static int __init save_microcode_in_initrd(void) + { +@@ -607,7 +607,7 @@ static int __init save_microcode_in_init + if (!desc.mc) + return -EINVAL; + +- ret = load_microcode_amd(x86_family(cpuid_1_eax), desc.data, desc.size); ++ ret = _load_microcode_amd(x86_family(cpuid_1_eax), desc.data, desc.size); + if (ret > UCODE_UPDATED) + return -EINVAL; + +@@ -956,21 +956,30 @@ static enum ucode_state __load_microcode + return UCODE_OK; + } + +-static enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t size) ++static enum ucode_state _load_microcode_amd(u8 family, const u8 *data, size_t size) + { +- struct cpuinfo_x86 *c; +- unsigned int nid, cpu; +- struct ucode_patch *p; + enum ucode_state ret; + + /* free old equiv table */ + free_equiv_cpu_table(); + + ret = __load_microcode_amd(family, data, size); +- if (ret != UCODE_OK) { ++ if (ret != UCODE_OK) + cleanup(); ++ ++ return ret; ++} ++ ++static enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t size) ++{ ++ struct cpuinfo_x86 *c; ++ unsigned int nid, cpu; ++ struct ucode_patch *p; ++ enum ucode_state ret; ++ ++ ret = _load_microcode_amd(family, data, size); ++ if (ret != UCODE_OK) + return ret; +- } + + for_each_node(nid) { + cpu = cpumask_first(cpumask_of_node(nid)); diff --git a/queue-6.6/x86-microcode-amd-use-cached-microcode-for-ap-load.patch b/queue-6.6/x86-microcode-amd-use-cached-microcode-for-ap-load.patch new file mode 100644 index 0000000000..56a3cba36a --- /dev/null +++ b/queue-6.6/x86-microcode-amd-use-cached-microcode-for-ap-load.patch @@ -0,0 +1,152 @@ +From b22b6b6d2a1cf29b63c249b79a3fe6416d6c210f Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Tue, 17 Oct 2023 23:23:55 +0200 +Subject: x86/microcode/amd: Use cached microcode for AP load + +From: Thomas Gleixner + +commit 5af05b8d51a8e3ff5905663655c0f46d1aaae44a upstream + +Now that the microcode cache is initialized before the APs are brought +up, there is no point in scanning builtin/initrd microcode during AP +loading. + +Convert the AP loader to utilize the cache, which in turn makes the CPU +hotplug callback which applies the microcode after initrd/builtin is +gone, obsolete as the early loading during late hotplug operations +including the resume path depends now only on the cache. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Borislav Petkov (AMD) +Link: https://lore.kernel.org/r/20231017211723.243426023@linutronix.de +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/cpu/microcode/amd.c | 20 +++++++++++--------- + arch/x86/kernel/cpu/microcode/core.c | 15 ++------------- + arch/x86/kernel/cpu/microcode/internal.h | 2 -- + 3 files changed, 13 insertions(+), 24 deletions(-) + +--- a/arch/x86/kernel/cpu/microcode/amd.c ++++ b/arch/x86/kernel/cpu/microcode/amd.c +@@ -496,7 +496,7 @@ static bool get_builtin_microcode(struct + return false; + } + +-static void find_blobs_in_containers(unsigned int cpuid_1_eax, struct cpio_data *ret) ++static void __init find_blobs_in_containers(unsigned int cpuid_1_eax, struct cpio_data *ret) + { + struct cpio_data cp; + +@@ -506,12 +506,12 @@ static void find_blobs_in_containers(uns + *ret = cp; + } + +-static void apply_ucode_from_containers(unsigned int cpuid_1_eax) ++void __init load_ucode_amd_bsp(unsigned int cpuid_1_eax) + { + struct cpio_data cp = { }; + + /* Needed in load_microcode_amd() */ +- ucode_cpu_info[smp_processor_id()].cpu_sig.sig = cpuid_1_eax; ++ ucode_cpu_info[0].cpu_sig.sig = cpuid_1_eax; + + find_blobs_in_containers(cpuid_1_eax, &cp); + if (!(cp.data && cp.size)) +@@ -520,11 +520,6 @@ static void apply_ucode_from_containers( + early_apply_microcode(cpuid_1_eax, cp.data, cp.size); + } + +-void load_ucode_amd_early(unsigned int cpuid_1_eax) +-{ +- return apply_ucode_from_containers(cpuid_1_eax); +-} +- + static enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t size); + + static int __init save_microcode_in_initrd(void) +@@ -608,7 +603,6 @@ static struct ucode_patch *find_patch(un + struct ucode_cpu_info *uci = ucode_cpu_info + cpu; + u16 equiv_id; + +- + equiv_id = find_equiv_id(&equiv_table, uci->cpu_sig.sig); + if (!equiv_id) + return NULL; +@@ -710,6 +704,14 @@ out: + return ret; + } + ++void load_ucode_amd_ap(unsigned int cpuid_1_eax) ++{ ++ unsigned int cpu = smp_processor_id(); ++ ++ ucode_cpu_info[cpu].cpu_sig.sig = cpuid_1_eax; ++ apply_microcode_amd(cpu); ++} ++ + static size_t install_equiv_cpu_table(const u8 *buf, size_t buf_size) + { + u32 equiv_tbl_len; +--- a/arch/x86/kernel/cpu/microcode/core.c ++++ b/arch/x86/kernel/cpu/microcode/core.c +@@ -154,7 +154,7 @@ void __init load_ucode_bsp(void) + if (intel) + load_ucode_intel_bsp(); + else +- load_ucode_amd_early(cpuid_1_eax); ++ load_ucode_amd_bsp(cpuid_1_eax); + } + + void load_ucode_ap(void) +@@ -173,7 +173,7 @@ void load_ucode_ap(void) + break; + case X86_VENDOR_AMD: + if (x86_family(cpuid_1_eax) >= 0x10) +- load_ucode_amd_early(cpuid_1_eax); ++ load_ucode_amd_ap(cpuid_1_eax); + break; + default: + break; +@@ -494,15 +494,6 @@ static struct syscore_ops mc_syscore_ops + .resume = microcode_bsp_resume, + }; + +-static int mc_cpu_starting(unsigned int cpu) +-{ +- enum ucode_state err = microcode_ops->apply_microcode(cpu); +- +- pr_debug("%s: CPU%d, err: %d\n", __func__, cpu, err); +- +- return err == UCODE_ERROR; +-} +- + static int mc_cpu_online(unsigned int cpu) + { + struct device *dev = get_cpu_device(cpu); +@@ -590,8 +581,6 @@ static int __init microcode_init(void) + schedule_on_each_cpu(setup_online_cpu); + + register_syscore_ops(&mc_syscore_ops); +- cpuhp_setup_state_nocalls(CPUHP_AP_MICROCODE_LOADER, "x86/microcode:starting", +- mc_cpu_starting, NULL); + cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "x86/microcode:online", + mc_cpu_online, mc_cpu_down_prep); + +--- a/arch/x86/kernel/cpu/microcode/internal.h ++++ b/arch/x86/kernel/cpu/microcode/internal.h +@@ -91,7 +91,6 @@ extern bool initrd_gone; + #ifdef CONFIG_CPU_SUP_AMD + void load_ucode_amd_bsp(unsigned int family); + void load_ucode_amd_ap(unsigned int family); +-void load_ucode_amd_early(unsigned int cpuid_1_eax); + int save_microcode_in_initrd_amd(unsigned int family); + void reload_ucode_amd(unsigned int cpu); + struct microcode_ops *init_amd_microcode(void); +@@ -99,7 +98,6 @@ void exit_amd_microcode(void); + #else /* CONFIG_CPU_SUP_AMD */ + static inline void load_ucode_amd_bsp(unsigned int family) { } + static inline void load_ucode_amd_ap(unsigned int family) { } +-static inline void load_ucode_amd_early(unsigned int family) { } + static inline int save_microcode_in_initrd_amd(unsigned int family) { return -EINVAL; } + static inline void reload_ucode_amd(unsigned int cpu) { } + static inline struct microcode_ops *init_amd_microcode(void) { return NULL; } diff --git a/queue-6.6/x86-microcode-amd-use-correct-per-cpu-ucode_cpu_info.patch b/queue-6.6/x86-microcode-amd-use-correct-per-cpu-ucode_cpu_info.patch new file mode 100644 index 0000000000..e6d2e880ed --- /dev/null +++ b/queue-6.6/x86-microcode-amd-use-correct-per-cpu-ucode_cpu_info.patch @@ -0,0 +1,46 @@ +From 52739801d858deb1410e3847a998ba8227c555ec Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Tue, 10 Oct 2023 17:08:41 +0200 +Subject: x86/microcode/amd: Use correct per CPU ucode_cpu_info + +From: Thomas Gleixner + +commit ecfd41089348fa4cc767dc588367e9fdf8cb6b9d upstream + +find_blobs_in_containers() is invoked on every CPU but overwrites +unconditionally ucode_cpu_info of CPU0. + +Fix this by using the proper CPU data and move the assignment into the +call site apply_ucode_from_containers() so that the function can be +reused. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Borislav Petkov (AMD) +Link: https://lore.kernel.org/r/20231010150702.433454320@linutronix.de +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/cpu/microcode/amd.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/arch/x86/kernel/cpu/microcode/amd.c ++++ b/arch/x86/kernel/cpu/microcode/amd.c +@@ -503,9 +503,6 @@ static void find_blobs_in_containers(uns + if (!get_builtin_microcode(&cp, x86_family(cpuid_1_eax))) + cp = find_microcode_in_initrd(ucode_path); + +- /* Needed in load_microcode_amd() */ +- ucode_cpu_info->cpu_sig.sig = cpuid_1_eax; +- + *ret = cp; + } + +@@ -513,6 +510,9 @@ static void apply_ucode_from_containers( + { + struct cpio_data cp = { }; + ++ /* Needed in load_microcode_amd() */ ++ ucode_cpu_info[smp_processor_id()].cpu_sig.sig = cpuid_1_eax; ++ + find_blobs_in_containers(cpuid_1_eax, &cp); + if (!(cp.data && cp.size)) + return; diff --git a/queue-6.6/x86-microcode-amd-use-the-family-model-stepping-encoded-in-the-patch-id.patch b/queue-6.6/x86-microcode-amd-use-the-family-model-stepping-encoded-in-the-patch-id.patch new file mode 100644 index 0000000000..5a25d70d89 --- /dev/null +++ b/queue-6.6/x86-microcode-amd-use-the-family-model-stepping-encoded-in-the-patch-id.patch @@ -0,0 +1,447 @@ +From 00b063b90e31be03012dea13cf6190ac39a5d2e5 Mon Sep 17 00:00:00 2001 +From: Borislav Petkov +Date: Thu, 25 Jul 2024 13:20:37 +0200 +Subject: x86/microcode/AMD: Use the family,model,stepping encoded in the patch ID + +From: Borislav Petkov + +commit 94838d230a6c835ced1bad06b8759e0a5f19c1d3 upstream + +On Zen and newer, the family, model and stepping is part of the +microcode patch ID so that the equivalence table the driver has been +using, is not needed anymore. + +So switch the driver to use that from now on. + +The equivalence table in the microcode blob should still remain in case +there's need to pass some additional information to the kernel loader. + +Signed-off-by: Borislav Petkov (AMD) +Link: https://lore.kernel.org/r/20240725112037.GBZqI1BbUk1KMlOJ_D@fat_crate.local +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/cpu/microcode/amd.c | 190 +++++++++++++++++++++++++++++------- + 1 file changed, 158 insertions(+), 32 deletions(-) + +--- a/arch/x86/kernel/cpu/microcode/amd.c ++++ b/arch/x86/kernel/cpu/microcode/amd.c +@@ -91,6 +91,31 @@ static struct equiv_cpu_table { + struct equiv_cpu_entry *entry; + } equiv_table; + ++union zen_patch_rev { ++ struct { ++ __u32 rev : 8, ++ stepping : 4, ++ model : 4, ++ __reserved : 4, ++ ext_model : 4, ++ ext_fam : 8; ++ }; ++ __u32 ucode_rev; ++}; ++ ++union cpuid_1_eax { ++ struct { ++ __u32 stepping : 4, ++ model : 4, ++ family : 4, ++ __reserved0 : 4, ++ ext_model : 4, ++ ext_fam : 8, ++ __reserved1 : 4; ++ }; ++ __u32 full; ++}; ++ + /* + * This points to the current valid container of microcode patches which we will + * save from the initrd/builtin before jettisoning its contents. @mc is the +@@ -98,7 +123,6 @@ static struct equiv_cpu_table { + */ + struct cont_desc { + struct microcode_amd *mc; +- u32 cpuid_1_eax; + u32 psize; + u8 *data; + size_t size; +@@ -111,10 +135,42 @@ struct cont_desc { + static const char + ucode_path[] __maybe_unused = "kernel/x86/microcode/AuthenticAMD.bin"; + ++/* ++ * This is CPUID(1).EAX on the BSP. It is used in two ways: ++ * ++ * 1. To ignore the equivalence table on Zen1 and newer. ++ * ++ * 2. To match which patches to load because the patch revision ID ++ * already contains the f/m/s for which the microcode is destined ++ * for. ++ */ ++static u32 bsp_cpuid_1_eax __ro_after_init; ++ ++static union cpuid_1_eax ucode_rev_to_cpuid(unsigned int val) ++{ ++ union zen_patch_rev p; ++ union cpuid_1_eax c; ++ ++ p.ucode_rev = val; ++ c.full = 0; ++ ++ c.stepping = p.stepping; ++ c.model = p.model; ++ c.ext_model = p.ext_model; ++ c.family = 0xf; ++ c.ext_fam = p.ext_fam; ++ ++ return c; ++} ++ + static u16 find_equiv_id(struct equiv_cpu_table *et, u32 sig) + { + unsigned int i; + ++ /* Zen and newer do not need an equivalence table. */ ++ if (x86_family(bsp_cpuid_1_eax) >= 0x17) ++ return 0; ++ + if (!et || !et->num_entries) + return 0; + +@@ -161,6 +217,10 @@ static bool verify_equivalence_table(con + if (!verify_container(buf, buf_size)) + return false; + ++ /* Zen and newer do not need an equivalence table. */ ++ if (x86_family(bsp_cpuid_1_eax) >= 0x17) ++ return true; ++ + cont_type = hdr[1]; + if (cont_type != UCODE_EQUIV_CPU_TABLE_TYPE) { + pr_debug("Wrong microcode container equivalence table type: %u.\n", +@@ -224,8 +284,9 @@ __verify_patch_section(const u8 *buf, si + * exceed the per-family maximum). @sh_psize is the size read from the section + * header. + */ +-static unsigned int __verify_patch_size(u8 family, u32 sh_psize, size_t buf_size) ++static unsigned int __verify_patch_size(u32 sh_psize, size_t buf_size) + { ++ u8 family = x86_family(bsp_cpuid_1_eax); + u32 max_size; + + if (family >= 0x15) +@@ -260,9 +321,9 @@ static unsigned int __verify_patch_size( + * positive: patch is not for this family, skip it + * 0: success + */ +-static int +-verify_patch(u8 family, const u8 *buf, size_t buf_size, u32 *patch_size) ++static int verify_patch(const u8 *buf, size_t buf_size, u32 *patch_size) + { ++ u8 family = x86_family(bsp_cpuid_1_eax); + struct microcode_header_amd *mc_hdr; + unsigned int ret; + u32 sh_psize; +@@ -288,7 +349,7 @@ verify_patch(u8 family, const u8 *buf, s + return -1; + } + +- ret = __verify_patch_size(family, sh_psize, buf_size); ++ ret = __verify_patch_size(sh_psize, buf_size); + if (!ret) { + pr_debug("Per-family patch size mismatch.\n"); + return -1; +@@ -310,6 +371,15 @@ verify_patch(u8 family, const u8 *buf, s + return 0; + } + ++static bool mc_patch_matches(struct microcode_amd *mc, u16 eq_id) ++{ ++ /* Zen and newer do not need an equivalence table. */ ++ if (x86_family(bsp_cpuid_1_eax) >= 0x17) ++ return ucode_rev_to_cpuid(mc->hdr.patch_id).full == bsp_cpuid_1_eax; ++ else ++ return eq_id == mc->hdr.processor_rev_id; ++} ++ + /* + * This scans the ucode blob for the proper container as we can have multiple + * containers glued together. Returns the equivalence ID from the equivalence +@@ -338,7 +408,7 @@ static size_t parse_container(u8 *ucode, + * doesn't contain a patch for the CPU, scan through the whole container + * so that it can be skipped in case there are other containers appended. + */ +- eq_id = find_equiv_id(&table, desc->cpuid_1_eax); ++ eq_id = find_equiv_id(&table, bsp_cpuid_1_eax); + + buf += hdr[2] + CONTAINER_HDR_SZ; + size -= hdr[2] + CONTAINER_HDR_SZ; +@@ -352,7 +422,7 @@ static size_t parse_container(u8 *ucode, + u32 patch_size; + int ret; + +- ret = verify_patch(x86_family(desc->cpuid_1_eax), buf, size, &patch_size); ++ ret = verify_patch(buf, size, &patch_size); + if (ret < 0) { + /* + * Patch verification failed, skip to the next container, if +@@ -365,7 +435,7 @@ static size_t parse_container(u8 *ucode, + } + + mc = (struct microcode_amd *)(buf + SECTION_HDR_SIZE); +- if (eq_id == mc->hdr.processor_rev_id) { ++ if (mc_patch_matches(mc, eq_id)) { + desc->psize = patch_size; + desc->mc = mc; + } +@@ -423,6 +493,7 @@ static int __apply_microcode_amd(struct + + /* verify patch application was successful */ + native_rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy); ++ + if (rev != mc->hdr.patch_id) + return -1; + +@@ -440,14 +511,12 @@ static int __apply_microcode_amd(struct + * + * Returns true if container found (sets @desc), false otherwise. + */ +-static bool early_apply_microcode(u32 cpuid_1_eax, u32 old_rev, void *ucode, size_t size) ++static bool early_apply_microcode(u32 old_rev, void *ucode, size_t size) + { + struct cont_desc desc = { 0 }; + struct microcode_amd *mc; + bool ret = false; + +- desc.cpuid_1_eax = cpuid_1_eax; +- + scan_containers(ucode, size, &desc); + + mc = desc.mc; +@@ -465,9 +534,10 @@ static bool early_apply_microcode(u32 cp + return !__apply_microcode_amd(mc); + } + +-static bool get_builtin_microcode(struct cpio_data *cp, unsigned int family) ++static bool get_builtin_microcode(struct cpio_data *cp) + { + char fw_name[36] = "amd-ucode/microcode_amd.bin"; ++ u8 family = x86_family(bsp_cpuid_1_eax); + struct firmware fw; + + if (IS_ENABLED(CONFIG_X86_32)) +@@ -486,11 +556,11 @@ static bool get_builtin_microcode(struct + return false; + } + +-static void __init find_blobs_in_containers(unsigned int cpuid_1_eax, struct cpio_data *ret) ++static void __init find_blobs_in_containers(struct cpio_data *ret) + { + struct cpio_data cp; + +- if (!get_builtin_microcode(&cp, x86_family(cpuid_1_eax))) ++ if (!get_builtin_microcode(&cp)) + cp = find_microcode_in_initrd(ucode_path); + + *ret = cp; +@@ -501,16 +571,18 @@ void __init load_ucode_amd_bsp(struct ea + struct cpio_data cp = { }; + u32 dummy; + ++ bsp_cpuid_1_eax = cpuid_1_eax; ++ + native_rdmsr(MSR_AMD64_PATCH_LEVEL, ed->old_rev, dummy); + + /* Needed in load_microcode_amd() */ + ucode_cpu_info[0].cpu_sig.sig = cpuid_1_eax; + +- find_blobs_in_containers(cpuid_1_eax, &cp); ++ find_blobs_in_containers(&cp); + if (!(cp.data && cp.size)) + return; + +- if (early_apply_microcode(cpuid_1_eax, ed->old_rev, cp.data, cp.size)) ++ if (early_apply_microcode(ed->old_rev, cp.data, cp.size)) + native_rdmsr(MSR_AMD64_PATCH_LEVEL, ed->new_rev, dummy); + } + +@@ -527,12 +599,10 @@ static int __init save_microcode_in_init + if (dis_ucode_ldr || c->x86_vendor != X86_VENDOR_AMD || c->x86 < 0x10) + return 0; + +- find_blobs_in_containers(cpuid_1_eax, &cp); ++ find_blobs_in_containers(&cp); + if (!(cp.data && cp.size)) + return -EINVAL; + +- desc.cpuid_1_eax = cpuid_1_eax; +- + scan_containers(cp.data, cp.size, &desc); + if (!desc.mc) + return -EINVAL; +@@ -545,26 +615,65 @@ static int __init save_microcode_in_init + } + early_initcall(save_microcode_in_initrd); + ++static inline bool patch_cpus_equivalent(struct ucode_patch *p, struct ucode_patch *n) ++{ ++ /* Zen and newer hardcode the f/m/s in the patch ID */ ++ if (x86_family(bsp_cpuid_1_eax) >= 0x17) { ++ union cpuid_1_eax p_cid = ucode_rev_to_cpuid(p->patch_id); ++ union cpuid_1_eax n_cid = ucode_rev_to_cpuid(n->patch_id); ++ ++ /* Zap stepping */ ++ p_cid.stepping = 0; ++ n_cid.stepping = 0; ++ ++ return p_cid.full == n_cid.full; ++ } else { ++ return p->equiv_cpu == n->equiv_cpu; ++ } ++} ++ + /* + * a small, trivial cache of per-family ucode patches + */ +-static struct ucode_patch *cache_find_patch(u16 equiv_cpu) ++static struct ucode_patch *cache_find_patch(struct ucode_cpu_info *uci, u16 equiv_cpu) + { + struct ucode_patch *p; ++ struct ucode_patch n; ++ ++ n.equiv_cpu = equiv_cpu; ++ n.patch_id = uci->cpu_sig.rev; ++ ++ WARN_ON_ONCE(!n.patch_id); + + list_for_each_entry(p, µcode_cache, plist) +- if (p->equiv_cpu == equiv_cpu) ++ if (patch_cpus_equivalent(p, &n)) + return p; ++ + return NULL; + } + ++static inline bool patch_newer(struct ucode_patch *p, struct ucode_patch *n) ++{ ++ /* Zen and newer hardcode the f/m/s in the patch ID */ ++ if (x86_family(bsp_cpuid_1_eax) >= 0x17) { ++ union zen_patch_rev zp, zn; ++ ++ zp.ucode_rev = p->patch_id; ++ zn.ucode_rev = n->patch_id; ++ ++ return zn.rev > zp.rev; ++ } else { ++ return n->patch_id > p->patch_id; ++ } ++} ++ + static void update_cache(struct ucode_patch *new_patch) + { + struct ucode_patch *p; + + list_for_each_entry(p, µcode_cache, plist) { +- if (p->equiv_cpu == new_patch->equiv_cpu) { +- if (p->patch_id >= new_patch->patch_id) { ++ if (patch_cpus_equivalent(p, new_patch)) { ++ if (!patch_newer(p, new_patch)) { + /* we already have the latest patch */ + kfree(new_patch->data); + kfree(new_patch); +@@ -595,13 +704,22 @@ static void free_cache(void) + static struct ucode_patch *find_patch(unsigned int cpu) + { + struct ucode_cpu_info *uci = ucode_cpu_info + cpu; ++ u32 rev, dummy __always_unused; + u16 equiv_id; + +- equiv_id = find_equiv_id(&equiv_table, uci->cpu_sig.sig); +- if (!equiv_id) +- return NULL; ++ /* fetch rev if not populated yet: */ ++ if (!uci->cpu_sig.rev) { ++ rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy); ++ uci->cpu_sig.rev = rev; ++ } ++ ++ if (x86_family(bsp_cpuid_1_eax) < 0x17) { ++ equiv_id = find_equiv_id(&equiv_table, uci->cpu_sig.sig); ++ if (!equiv_id) ++ return NULL; ++ } + +- return cache_find_patch(equiv_id); ++ return cache_find_patch(uci, equiv_id); + } + + void reload_ucode_amd(unsigned int cpu) +@@ -651,7 +769,7 @@ static enum ucode_state apply_microcode_ + struct ucode_cpu_info *uci; + struct ucode_patch *p; + enum ucode_state ret; +- u32 rev, dummy __always_unused; ++ u32 rev; + + BUG_ON(raw_smp_processor_id() != cpu); + +@@ -661,11 +779,11 @@ static enum ucode_state apply_microcode_ + if (!p) + return UCODE_NFOUND; + ++ rev = uci->cpu_sig.rev; ++ + mc_amd = p->data; + uci->mc = p->data; + +- rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy); +- + /* need to apply patch? */ + if (rev > mc_amd->hdr.patch_id) { + ret = UCODE_OK; +@@ -711,6 +829,10 @@ static size_t install_equiv_cpu_table(co + hdr = (const u32 *)buf; + equiv_tbl_len = hdr[2]; + ++ /* Zen and newer do not need an equivalence table. */ ++ if (x86_family(bsp_cpuid_1_eax) >= 0x17) ++ goto out; ++ + equiv_table.entry = vmalloc(equiv_tbl_len); + if (!equiv_table.entry) { + pr_err("failed to allocate equivalent CPU table\n"); +@@ -720,12 +842,16 @@ static size_t install_equiv_cpu_table(co + memcpy(equiv_table.entry, buf + CONTAINER_HDR_SZ, equiv_tbl_len); + equiv_table.num_entries = equiv_tbl_len / sizeof(struct equiv_cpu_entry); + ++out: + /* add header length */ + return equiv_tbl_len + CONTAINER_HDR_SZ; + } + + static void free_equiv_cpu_table(void) + { ++ if (x86_family(bsp_cpuid_1_eax) >= 0x17) ++ return; ++ + vfree(equiv_table.entry); + memset(&equiv_table, 0, sizeof(equiv_table)); + } +@@ -751,7 +877,7 @@ static int verify_and_add_patch(u8 famil + u16 proc_id; + int ret; + +- ret = verify_patch(family, fw, leftover, patch_size); ++ ret = verify_patch(fw, leftover, patch_size); + if (ret) + return ret; + +@@ -776,7 +902,7 @@ static int verify_and_add_patch(u8 famil + patch->patch_id = mc_hdr->patch_id; + patch->equiv_cpu = proc_id; + +- pr_debug("%s: Added patch_id: 0x%08x, proc_id: 0x%04x\n", ++ pr_debug("%s: Adding patch_id: 0x%08x, proc_id: 0x%04x\n", + __func__, patch->patch_id, proc_id); + + /* ... and add to cache. */ diff --git a/queue-6.6/x86-microcode-clarify-the-late-load-logic.patch b/queue-6.6/x86-microcode-clarify-the-late-load-logic.patch new file mode 100644 index 0000000000..b08fd70b39 --- /dev/null +++ b/queue-6.6/x86-microcode-clarify-the-late-load-logic.patch @@ -0,0 +1,101 @@ +From 17f713d29969a723f51eb4d4d1cdccb545b035ae Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Mon, 2 Oct 2023 13:59:57 +0200 +Subject: x86/microcode: Clarify the late load logic + +From: Thomas Gleixner + +commit 6f059e634dcd0d725854514c94c114bbdd83950d upstream + +reload_store() is way too complicated. Split the inner workings out and +make the following enhancements: + + - Taint the kernel only when the microcode was actually updated. If. e.g. + the rendezvous fails, then nothing happened and there is no reason for + tainting. + + - Return useful error codes + +Signed-off-by: Thomas Gleixner +Signed-off-by: Borislav Petkov (AMD) +Reviewed-by: Nikolay Borisov +Link: https://lore.kernel.org/r/20231002115903.145048840@linutronix.de +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/cpu/microcode/core.c | 41 ++++++++++++++++------------------- + 1 file changed, 19 insertions(+), 22 deletions(-) + +--- a/arch/x86/kernel/cpu/microcode/core.c ++++ b/arch/x86/kernel/cpu/microcode/core.c +@@ -362,11 +362,11 @@ static int microcode_reload_late(void) + pr_info("Reload succeeded, microcode revision: 0x%x -> 0x%x\n", + old, boot_cpu_data.microcode); + microcode_check(&prev_info); ++ add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK); + } else { + pr_info("Reload failed, current microcode revision: 0x%x\n", + boot_cpu_data.microcode); + } +- + return ret; + } + +@@ -399,40 +399,37 @@ static bool ensure_cpus_are_online(void) + return true; + } + ++static int ucode_load_late_locked(void) ++{ ++ if (!ensure_cpus_are_online()) ++ return -EBUSY; ++ ++ switch (microcode_ops->request_microcode_fw(0, µcode_pdev->dev)) { ++ case UCODE_NEW: ++ return microcode_reload_late(); ++ case UCODE_NFOUND: ++ return -ENOENT; ++ default: ++ return -EBADFD; ++ } ++} ++ + static ssize_t reload_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) + { +- enum ucode_state tmp_ret = UCODE_OK; +- int bsp = boot_cpu_data.cpu_index; + unsigned long val; +- ssize_t ret = 0; ++ ssize_t ret; + + ret = kstrtoul(buf, 0, &val); + if (ret || val != 1) + return -EINVAL; + + cpus_read_lock(); +- +- if (!ensure_cpus_are_online()) { +- ret = -EBUSY; +- goto put; +- } +- +- tmp_ret = microcode_ops->request_microcode_fw(bsp, µcode_pdev->dev); +- if (tmp_ret != UCODE_NEW) +- goto put; +- +- ret = microcode_reload_late(); +-put: ++ ret = ucode_load_late_locked(); + cpus_read_unlock(); + +- if (ret == 0) +- ret = size; +- +- add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK); +- +- return ret; ++ return ret ? : size; + } + + static DEVICE_ATTR_WO(reload); diff --git a/queue-6.6/x86-microcode-clean-up-mc_cpu_down_prep.patch b/queue-6.6/x86-microcode-clean-up-mc_cpu_down_prep.patch new file mode 100644 index 0000000000..e2fe09c4d0 --- /dev/null +++ b/queue-6.6/x86-microcode-clean-up-mc_cpu_down_prep.patch @@ -0,0 +1,43 @@ +From 6759862c3c76d50ae5b05490ffe9c83964e64bc8 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Mon, 2 Oct 2023 13:59:55 +0200 +Subject: x86/microcode: Clean up mc_cpu_down_prep() + +From: Thomas Gleixner + +commit ba48aa32388ac652256baa8d0a6092d350160da0 upstream + +This function has nothing to do with suspend. It's a hotplug +callback. Remove the bogus comment. + +Drop the pointless debug printk. The hotplug core provides tracepoints +which track the invocation of those callbacks. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Borislav Petkov (AMD) +Link: https://lore.kernel.org/r/20231002115903.028651784@linutronix.de +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/cpu/microcode/core.c | 8 +------- + 1 file changed, 1 insertion(+), 7 deletions(-) + +--- a/arch/x86/kernel/cpu/microcode/core.c ++++ b/arch/x86/kernel/cpu/microcode/core.c +@@ -498,16 +498,10 @@ static int mc_cpu_online(unsigned int cp + + static int mc_cpu_down_prep(unsigned int cpu) + { +- struct device *dev; +- +- dev = get_cpu_device(cpu); ++ struct device *dev = get_cpu_device(cpu); + + microcode_fini_cpu(cpu); +- +- /* Suspend is in progress, only remove the interface */ + sysfs_remove_group(&dev->kobj, &mc_attr_group); +- pr_debug("%s: CPU%d\n", __func__, cpu); +- + return 0; + } + diff --git a/queue-6.6/x86-microcode-get-rid-of-the-schedule-work-indirection.patch b/queue-6.6/x86-microcode-get-rid-of-the-schedule-work-indirection.patch new file mode 100644 index 0000000000..dc6ef74003 --- /dev/null +++ b/queue-6.6/x86-microcode-get-rid-of-the-schedule-work-indirection.patch @@ -0,0 +1,76 @@ +From 1b43c9ce45068f82226605c7e253aee7ff8ec634 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Tue, 17 Oct 2023 23:23:58 +0200 +Subject: x86/microcode: Get rid of the schedule work indirection + +From: Thomas Gleixner + +commit 2e1997335ceb6fc819862804f51d4fe83593c138 upstream + +Scheduling work on all CPUs to collect the microcode information is just +another extra step for no value. Let the CPU hotplug callback registration +do it. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Borislav Petkov (AMD) +Link: https://lore.kernel.org/r/20231017211723.354748138@linutronix.de +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/cpu/microcode/core.c | 29 ++++++++++------------------- + 1 file changed, 10 insertions(+), 19 deletions(-) + +--- a/arch/x86/kernel/cpu/microcode/core.c ++++ b/arch/x86/kernel/cpu/microcode/core.c +@@ -481,8 +481,16 @@ static struct syscore_ops mc_syscore_ops + + static int mc_cpu_online(unsigned int cpu) + { ++ struct ucode_cpu_info *uci = ucode_cpu_info + cpu; + struct device *dev = get_cpu_device(cpu); + ++ memset(uci, 0, sizeof(*uci)); ++ ++ microcode_ops->collect_cpu_info(cpu, &uci->cpu_sig); ++ cpu_data(cpu).microcode = uci->cpu_sig.rev; ++ if (!cpu) ++ boot_cpu_data.microcode = uci->cpu_sig.rev; ++ + if (sysfs_create_group(&dev->kobj, &mc_attr_group)) + pr_err("Failed to create group for CPU%d\n", cpu); + return 0; +@@ -503,20 +511,6 @@ static int mc_cpu_down_prep(unsigned int + return 0; + } + +-static void setup_online_cpu(struct work_struct *work) +-{ +- int cpu = smp_processor_id(); +- struct ucode_cpu_info *uci = ucode_cpu_info + cpu; +- +- memset(uci, 0, sizeof(*uci)); +- +- microcode_ops->collect_cpu_info(cpu, &uci->cpu_sig); +- cpu_data(cpu).microcode = uci->cpu_sig.rev; +- if (!cpu) +- boot_cpu_data.microcode = uci->cpu_sig.rev; +- mc_cpu_online(cpu); +-} +- + static struct attribute *cpu_root_microcode_attrs[] = { + #ifdef CONFIG_MICROCODE_LATE_LOADING + &dev_attr_reload.attr, +@@ -562,12 +556,9 @@ static int __init microcode_init(void) + } + } + +- /* Do per-CPU setup */ +- schedule_on_each_cpu(setup_online_cpu); +- + register_syscore_ops(&mc_syscore_ops); +- cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "x86/microcode:online", +- mc_cpu_online, mc_cpu_down_prep); ++ cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/microcode:online", ++ mc_cpu_online, mc_cpu_down_prep); + + pr_info("Microcode Update Driver: v%s.", DRIVER_VERSION); + diff --git a/queue-6.6/x86-microcode-handle-nosmt-correctly.patch b/queue-6.6/x86-microcode-handle-nosmt-correctly.patch new file mode 100644 index 0000000000..aec5ae4175 --- /dev/null +++ b/queue-6.6/x86-microcode-handle-nosmt-correctly.patch @@ -0,0 +1,167 @@ +From 760ac4ae4059a69e68c07e4bfa151a733fa059c8 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Mon, 2 Oct 2023 13:59:56 +0200 +Subject: x86/microcode: Handle "nosmt" correctly + +From: Thomas Gleixner + +commit 634ac23ad609b3ddd9e0e478bd5afbf49d3a2556 upstream + +On CPUs where microcode loading is not NMI-safe the SMT siblings which +are parked in one of the play_dead() variants still react to NMIs. + +So if an NMI hits while the primary thread updates the microcode the +resulting behaviour is undefined. The default play_dead() implementation on +modern CPUs is using MWAIT which is not guaranteed to be safe against +a microcode update which affects MWAIT. + +Take the cpus_booted_once_mask into account to detect this case and +refuse to load late if the vendor specific driver does not advertise +that late loading is NMI safe. + +AMD stated that this is safe, so mark the AMD driver accordingly. + +This requirement will be partially lifted in later changes. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Borislav Petkov (AMD) +Link: https://lore.kernel.org/r/20231002115903.087472735@linutronix.de +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/Kconfig | 2 - + arch/x86/kernel/cpu/microcode/amd.c | 9 +++-- + arch/x86/kernel/cpu/microcode/core.c | 51 +++++++++++++++++++------------ + arch/x86/kernel/cpu/microcode/internal.h | 13 +++---- + 4 files changed, 44 insertions(+), 31 deletions(-) + +--- a/arch/x86/Kconfig ++++ b/arch/x86/Kconfig +@@ -1317,7 +1317,7 @@ config MICROCODE + config MICROCODE_LATE_LOADING + bool "Late microcode loading (DANGEROUS)" + default n +- depends on MICROCODE ++ depends on MICROCODE && SMP + help + Loading microcode late, when the system is up and executing instructions + is a tricky business and should be avoided if possible. Just the sequence +--- a/arch/x86/kernel/cpu/microcode/amd.c ++++ b/arch/x86/kernel/cpu/microcode/amd.c +@@ -917,10 +917,11 @@ static void microcode_fini_cpu_amd(int c + } + + static struct microcode_ops microcode_amd_ops = { +- .request_microcode_fw = request_microcode_amd, +- .collect_cpu_info = collect_cpu_info_amd, +- .apply_microcode = apply_microcode_amd, +- .microcode_fini_cpu = microcode_fini_cpu_amd, ++ .request_microcode_fw = request_microcode_amd, ++ .collect_cpu_info = collect_cpu_info_amd, ++ .apply_microcode = apply_microcode_amd, ++ .microcode_fini_cpu = microcode_fini_cpu_amd, ++ .nmi_safe = true, + }; + + struct microcode_ops * __init init_amd_microcode(void) +--- a/arch/x86/kernel/cpu/microcode/core.c ++++ b/arch/x86/kernel/cpu/microcode/core.c +@@ -254,23 +254,6 @@ static struct platform_device *microcode + */ + #define SPINUNIT 100 /* 100 nsec */ + +-static int check_online_cpus(void) +-{ +- unsigned int cpu; +- +- /* +- * Make sure all CPUs are online. It's fine for SMT to be disabled if +- * all the primary threads are still online. +- */ +- for_each_present_cpu(cpu) { +- if (topology_is_primary_thread(cpu) && !cpu_online(cpu)) { +- pr_err("Not all CPUs online, aborting microcode update.\n"); +- return -EINVAL; +- } +- } +- +- return 0; +-} + + static atomic_t late_cpus_in; + static atomic_t late_cpus_out; +@@ -387,6 +370,35 @@ static int microcode_reload_late(void) + return ret; + } + ++/* ++ * Ensure that all required CPUs which are present and have been booted ++ * once are online. ++ * ++ * To pass this check, all primary threads must be online. ++ * ++ * If the microcode load is not safe against NMI then all SMT threads ++ * must be online as well because they still react to NMIs when they are ++ * soft-offlined and parked in one of the play_dead() variants. So if a ++ * NMI hits while the primary thread updates the microcode the resulting ++ * behaviour is undefined. The default play_dead() implementation on ++ * modern CPUs uses MWAIT, which is also not guaranteed to be safe ++ * against a microcode update which affects MWAIT. ++ */ ++static bool ensure_cpus_are_online(void) ++{ ++ unsigned int cpu; ++ ++ for_each_cpu_and(cpu, cpu_present_mask, &cpus_booted_once_mask) { ++ if (!cpu_online(cpu)) { ++ if (topology_is_primary_thread(cpu) || !microcode_ops->nmi_safe) { ++ pr_err("CPU %u not online\n", cpu); ++ return false; ++ } ++ } ++ } ++ return true; ++} ++ + static ssize_t reload_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +@@ -402,9 +414,10 @@ static ssize_t reload_store(struct devic + + cpus_read_lock(); + +- ret = check_online_cpus(); +- if (ret) ++ if (!ensure_cpus_are_online()) { ++ ret = -EBUSY; + goto put; ++ } + + tmp_ret = microcode_ops->request_microcode_fw(bsp, µcode_pdev->dev); + if (tmp_ret != UCODE_NEW) +--- a/arch/x86/kernel/cpu/microcode/internal.h ++++ b/arch/x86/kernel/cpu/microcode/internal.h +@@ -20,18 +20,17 @@ enum ucode_state { + + struct microcode_ops { + enum ucode_state (*request_microcode_fw)(int cpu, struct device *dev); +- + void (*microcode_fini_cpu)(int cpu); + + /* +- * The generic 'microcode_core' part guarantees that +- * the callbacks below run on a target cpu when they +- * are being called. ++ * The generic 'microcode_core' part guarantees that the callbacks ++ * below run on a target CPU when they are being called. + * See also the "Synchronization" section in microcode_core.c. + */ +- enum ucode_state (*apply_microcode)(int cpu); +- int (*collect_cpu_info)(int cpu, struct cpu_signature *csig); +- void (*finalize_late_load)(int result); ++ enum ucode_state (*apply_microcode)(int cpu); ++ int (*collect_cpu_info)(int cpu, struct cpu_signature *csig); ++ void (*finalize_late_load)(int result); ++ unsigned int nmi_safe : 1; + }; + + extern struct ucode_cpu_info ucode_cpu_info[]; diff --git a/queue-6.6/x86-microcode-handle-offline-cpus-correctly.patch b/queue-6.6/x86-microcode-handle-offline-cpus-correctly.patch new file mode 100644 index 0000000000..f0bd3473c3 --- /dev/null +++ b/queue-6.6/x86-microcode-handle-offline-cpus-correctly.patch @@ -0,0 +1,249 @@ +From 55d40b5d38571a06c143786742b425d2e083c67c Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Mon, 2 Oct 2023 14:00:08 +0200 +Subject: x86/microcode: Handle "offline" CPUs correctly + +From: Thomas Gleixner + +commit 8f849ff63bcbc77670da03cb8f2b78b06257f455 upstream + +Offline CPUs need to be parked in a safe loop when microcode update is +in progress on the primary CPU. Currently, offline CPUs are parked in +mwait_play_dead(), and for Intel CPUs, its not a safe instruction, +because the MWAIT instruction can be patched in the new microcode update +that can cause instability. + + - Add a new microcode state 'UCODE_OFFLINE' to report status on per-CPU + basis. + - Force NMI on the offline CPUs. + +Wake up offline CPUs while the update is in progress and then return +them back to mwait_play_dead() after microcode update is complete. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Borislav Petkov (AMD) +Link: https://lore.kernel.org/r/20231002115903.660850472@linutronix.de +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/include/asm/microcode.h | 1 + arch/x86/kernel/cpu/microcode/core.c | 112 +++++++++++++++++++++++++++++-- + arch/x86/kernel/cpu/microcode/internal.h | 1 + arch/x86/kernel/nmi.c | 5 + + 4 files changed, 113 insertions(+), 6 deletions(-) + +--- a/arch/x86/include/asm/microcode.h ++++ b/arch/x86/include/asm/microcode.h +@@ -71,6 +71,7 @@ static inline u32 intel_get_microcode_re + #endif /* !CONFIG_CPU_SUP_INTEL */ + + bool microcode_nmi_handler(void); ++void microcode_offline_nmi_handler(void); + + #ifdef CONFIG_MICROCODE_LATE_LOADING + DECLARE_STATIC_KEY_FALSE(microcode_nmi_handler_enable); +--- a/arch/x86/kernel/cpu/microcode/core.c ++++ b/arch/x86/kernel/cpu/microcode/core.c +@@ -272,8 +272,9 @@ struct microcode_ctrl { + + 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 atomic_t late_cpus_in; ++static cpumask_t cpu_offline_mask; + + static noinstr bool wait_for_cpus(atomic_t *cnt) + { +@@ -381,7 +382,7 @@ static noinstr void load_secondary(unsig + instrumentation_end(); + } + +-static void load_primary(unsigned int cpu) ++static void __load_primary(unsigned int cpu) + { + struct cpumask *secondaries = topology_sibling_cpumask(cpu); + enum sibling_ctrl ctrl; +@@ -416,6 +417,67 @@ static void load_primary(unsigned int cp + } + } + ++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(); +@@ -472,6 +534,7 @@ static int load_cpus_stopped(void *unuse + static int load_late_stop_cpus(void) + { + unsigned int cpu, updated = 0, failed = 0, timedout = 0, siblings = 0; ++ unsigned int nr_offl, offline = 0; + int old_rev = boot_cpu_data.microcode; + struct cpuinfo_x86 prev_info; + +@@ -479,6 +542,7 @@ static int load_late_stop_cpus(void) + pr_err("You should switch to early loading, if possible.\n"); + + atomic_set(&late_cpus_in, num_online_cpus()); ++ atomic_set(&offline_in_nmi, 0); + loops_per_usec = loops_per_jiffy / (TICK_NSEC / 1000); + + /* +@@ -501,6 +565,7 @@ static int load_late_stop_cpus(void) + case UCODE_UPDATED: updated++; break; + case UCODE_TIMEOUT: timedout++; break; + case UCODE_OK: siblings++; break; ++ case UCODE_OFFLINE: offline++; break; + default: failed++; break; + } + } +@@ -512,6 +577,13 @@ static int load_late_stop_cpus(void) + /* Nothing changed. */ + if (!failed && !timedout) + return 0; ++ ++ nr_offl = cpumask_weight(&cpu_offline_mask); ++ if (offline < nr_offl) { ++ pr_warn("%u offline siblings did not respond.\n", ++ nr_offl - atomic_read(&offline_in_nmi)); ++ return -EIO; ++ } + pr_err("update failed: %u CPUs failed %u CPUs timed out\n", + failed, timedout); + return -EIO; +@@ -545,19 +617,49 @@ static int load_late_stop_cpus(void) + * modern CPUs uses MWAIT, which is also not guaranteed to be safe + * against a microcode update which affects MWAIT. + * +- * 2) Initialize the per CPU control structure ++ * As soft-offlined CPUs still react on NMIs, the SMT sibling ++ * restriction can be lifted when the vendor driver signals to use NMI ++ * for rendezvous and the APIC provides a mechanism to send an NMI to a ++ * soft-offlined CPU. The soft-offlined CPUs are then able to ++ * participate in the rendezvous in a trivial stub handler. ++ * ++ * 2) Initialize the per CPU control structure and create a cpumask ++ * which contains "offline"; secondary threads, so they can be handled ++ * correctly by a control CPU. + */ + static bool setup_cpus(void) + { + struct microcode_ctrl ctrl = { .ctrl = SCTRL_WAIT, .result = -1, }; ++ bool allow_smt_offline; + unsigned int cpu; + ++ allow_smt_offline = microcode_ops->nmi_safe || ++ (microcode_ops->use_nmi && apic->nmi_to_offline_cpu); ++ ++ cpumask_clear(&cpu_offline_mask); ++ + for_each_cpu_and(cpu, cpu_present_mask, &cpus_booted_once_mask) { ++ /* ++ * Offline CPUs sit in one of the play_dead() functions ++ * with interrupts disabled, but they still react on NMIs ++ * and execute arbitrary code. Also MWAIT being updated ++ * while the offline CPU sits there is not necessarily safe ++ * on all CPU variants. ++ * ++ * Mark them in the offline_cpus mask which will be handled ++ * by CPU0 later in the update process. ++ * ++ * Ensure that the primary thread is online so that it is ++ * guaranteed that all cores are updated. ++ */ + if (!cpu_online(cpu)) { +- if (topology_is_primary_thread(cpu) || !microcode_ops->nmi_safe) { +- pr_err("CPU %u not online\n", cpu); ++ if (topology_is_primary_thread(cpu) || !allow_smt_offline) { ++ pr_err("CPU %u not online, loading aborted\n", cpu); + return false; + } ++ cpumask_set_cpu(cpu, &cpu_offline_mask); ++ per_cpu(ucode_ctrl, cpu) = ctrl; ++ continue; + } + + /* +--- a/arch/x86/kernel/cpu/microcode/internal.h ++++ b/arch/x86/kernel/cpu/microcode/internal.h +@@ -17,6 +17,7 @@ enum ucode_state { + UCODE_NFOUND, + UCODE_ERROR, + UCODE_TIMEOUT, ++ UCODE_OFFLINE, + }; + + struct microcode_ops { +--- a/arch/x86/kernel/nmi.c ++++ b/arch/x86/kernel/nmi.c +@@ -502,8 +502,11 @@ DEFINE_IDTENTRY_RAW(exc_nmi) + if (IS_ENABLED(CONFIG_NMI_CHECK_CPU)) + raw_atomic_long_inc(&nsp->idt_calls); + +- if (IS_ENABLED(CONFIG_SMP) && arch_cpu_is_offline(smp_processor_id())) ++ if (IS_ENABLED(CONFIG_SMP) && arch_cpu_is_offline(smp_processor_id())) { ++ if (microcode_nmi_handler_enabled()) ++ microcode_offline_nmi_handler(); + return; ++ } + + if (this_cpu_read(nmi_state) != NMI_NOT_RUNNING) { + this_cpu_write(nmi_state, NMI_LATCHED); diff --git a/queue-6.6/x86-microcode-intel-cleanup-code-further.patch b/queue-6.6/x86-microcode-intel-cleanup-code-further.patch new file mode 100644 index 0000000000..7a4dfdc8c2 --- /dev/null +++ b/queue-6.6/x86-microcode-intel-cleanup-code-further.patch @@ -0,0 +1,162 @@ +From 8d78a5ff8ee83e456d68102d9d7ae8c6766fa7ce Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Mon, 2 Oct 2023 13:59:41 +0200 +Subject: x86/microcode/intel: Cleanup code further + +From: Thomas Gleixner + +commit 0177669ee61de4dc641f9ad86a3df6f22327cf6c upstream + +Sanitize the microcode scan loop, fixup printks and move the loading +function for builtin microcode next to the place where it is used and mark +it __init. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Borislav Petkov (AMD) +Link: https://lore.kernel.org/r/20231002115902.389400871@linutronix.de +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/cpu/microcode/intel.c | 76 ++++++++++++++-------------------- + 1 file changed, 32 insertions(+), 44 deletions(-) + +--- a/arch/x86/kernel/cpu/microcode/intel.c ++++ b/arch/x86/kernel/cpu/microcode/intel.c +@@ -36,7 +36,7 @@ static const char ucode_path[] = "kernel + static struct microcode_intel *intel_ucode_patch __read_mostly; + + /* last level cache size per core */ +-static int llc_size_per_core __ro_after_init; ++static unsigned int llc_size_per_core __ro_after_init; + + /* microcode format is extended from prescott processors */ + struct extended_signature { +@@ -294,29 +294,6 @@ static struct microcode_intel *scan_micr + return patch; + } + +-static bool load_builtin_intel_microcode(struct cpio_data *cp) +-{ +- unsigned int eax = 1, ebx, ecx = 0, edx; +- struct firmware fw; +- char name[30]; +- +- if (IS_ENABLED(CONFIG_X86_32)) +- return false; +- +- native_cpuid(&eax, &ebx, &ecx, &edx); +- +- sprintf(name, "intel-ucode/%02x-%02x-%02x", +- x86_family(eax), x86_model(eax), x86_stepping(eax)); +- +- if (firmware_request_builtin(&fw, name)) { +- cp->size = fw.size; +- cp->data = (void *)fw.data; +- return true; +- } +- +- return false; +-} +- + static int apply_microcode_early(struct ucode_cpu_info *uci) + { + struct microcode_intel *mc; +@@ -360,6 +337,28 @@ static int apply_microcode_early(struct + return 0; + } + ++static bool load_builtin_intel_microcode(struct cpio_data *cp) ++{ ++ unsigned int eax = 1, ebx, ecx = 0, edx; ++ struct firmware fw; ++ char name[30]; ++ ++ if (IS_ENABLED(CONFIG_X86_32)) ++ return false; ++ ++ native_cpuid(&eax, &ebx, &ecx, &edx); ++ ++ sprintf(name, "intel-ucode/%02x-%02x-%02x", ++ x86_family(eax), x86_model(eax), x86_stepping(eax)); ++ ++ if (firmware_request_builtin(&fw, name)) { ++ cp->size = fw.size; ++ cp->data = (void *)fw.data; ++ return true; ++ } ++ return false; ++} ++ + int __init save_microcode_in_initrd_intel(void) + { + struct ucode_cpu_info uci; +@@ -432,25 +431,16 @@ void load_ucode_intel_ap(void) + apply_microcode_early(&uci); + } + +-/* Accessor for microcode pointer */ +-static struct microcode_intel *ucode_get_patch(void) +-{ +- return intel_ucode_patch; +-} +- + void reload_ucode_intel(void) + { +- struct microcode_intel *p; + struct ucode_cpu_info uci; + + intel_cpu_collect_info(&uci); + +- p = ucode_get_patch(); +- if (!p) ++ uci.mc = intel_ucode_patch; ++ if (!uci.mc) + return; + +- uci.mc = p; +- + apply_microcode_early(&uci); + } + +@@ -488,8 +478,7 @@ static enum ucode_state apply_microcode_ + if (WARN_ON(raw_smp_processor_id() != cpu)) + return UCODE_ERROR; + +- /* Look for a newer patch in our cache: */ +- mc = ucode_get_patch(); ++ mc = intel_ucode_patch; + if (!mc) { + mc = uci->mc; + if (!mc) +@@ -680,18 +669,17 @@ static enum ucode_state request_microcod + } + + static struct microcode_ops microcode_intel_ops = { +- .request_microcode_fw = request_microcode_fw, +- .collect_cpu_info = collect_cpu_info, +- .apply_microcode = apply_microcode_intel, ++ .request_microcode_fw = request_microcode_fw, ++ .collect_cpu_info = collect_cpu_info, ++ .apply_microcode = apply_microcode_intel, + }; + +-static int __init calc_llc_size_per_core(struct cpuinfo_x86 *c) ++static __init void calc_llc_size_per_core(struct cpuinfo_x86 *c) + { + u64 llc_size = c->x86_cache_size * 1024ULL; + + do_div(llc_size, c->x86_max_cores); +- +- return (int)llc_size; ++ llc_size_per_core = (unsigned int)llc_size; + } + + struct microcode_ops * __init init_intel_microcode(void) +@@ -704,7 +692,7 @@ struct microcode_ops * __init init_intel + return NULL; + } + +- llc_size_per_core = calc_llc_size_per_core(c); ++ calc_llc_size_per_core(c); + + return µcode_intel_ops; + } diff --git a/queue-6.6/x86-microcode-intel-remove-unnecessary-cache-writeback-and-invalidation.patch b/queue-6.6/x86-microcode-intel-remove-unnecessary-cache-writeback-and-invalidation.patch new file mode 100644 index 0000000000..60be7a93ed --- /dev/null +++ b/queue-6.6/x86-microcode-intel-remove-unnecessary-cache-writeback-and-invalidation.patch @@ -0,0 +1,70 @@ +From f602940dde8cafbe9518143dc1cfca3c17c17478 Mon Sep 17 00:00:00 2001 +From: "Chang S. Bae" +Date: Tue, 1 Oct 2024 09:10:36 -0700 +Subject: x86/microcode/intel: Remove unnecessary cache writeback and invalidation + +From: "Chang S. Bae" + +commit 9a819753b0209c6edebdea447a1aa53e8c697653 upstream + +Currently, an unconditional cache flush is performed during every +microcode update. Although the original changelog did not mention +a specific erratum, this measure was primarily intended to address +a specific microcode bug, the load of which has already been blocked by +is_blacklisted(). Therefore, this cache flush is no longer necessary. + +Additionally, the side effects of doing this have been overlooked. It +increases CPU rendezvous time during late loading, where the cache flush +takes between 1x to 3.5x longer than the actual microcode update. + +Remove native_wbinvd() and update the erratum name to align with the +latest errata documentation, document ID 334163 Version 022US. + + [ bp: Zap the flaky documentation URL. ] + +Fixes: 91df9fdf5149 ("x86/microcode/intel: Writeback and invalidate caches before updating microcode") +Reported-by: Yan Hua Wu +Reported-by: William Xie +Signed-off-by: Chang S. Bae +Signed-off-by: Borislav Petkov (AMD) +Acked-by: Ashok Raj +Tested-by: Yan Hua Wu +Link: https://lore.kernel.org/r/20241001161042.465584-2-chang.seok.bae@intel.com +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/cpu/microcode/intel.c | 10 ++-------- + 1 file changed, 2 insertions(+), 8 deletions(-) + +--- a/arch/x86/kernel/cpu/microcode/intel.c ++++ b/arch/x86/kernel/cpu/microcode/intel.c +@@ -319,12 +319,6 @@ static enum ucode_state __apply_microcod + return UCODE_OK; + } + +- /* +- * Writeback and invalidate caches before updating microcode to avoid +- * internal issues depending on what the microcode is updating. +- */ +- native_wbinvd(); +- + /* write microcode via MSR 0x79 */ + native_wrmsrl(MSR_IA32_UCODE_WRITE, (unsigned long)mc->bits); + +@@ -551,7 +545,7 @@ static bool is_blacklisted(unsigned int + /* + * Late loading on model 79 with microcode revision less than 0x0b000021 + * and LLC size per core bigger than 2.5MB may result in a system hang. +- * This behavior is documented in item BDF90, #334165 (Intel Xeon ++ * This behavior is documented in item BDX90, #334165 (Intel Xeon + * Processor E7-8800/4800 v4 Product Family). + */ + if (c->x86 == 6 && +@@ -559,7 +553,7 @@ static bool is_blacklisted(unsigned int + c->x86_stepping == 0x01 && + llc_size_per_core > 2621440 && + c->microcode < 0x0b000021) { +- pr_err_once("Erratum BDF90: late loading with revision < 0x0b000021 (0x%x) disabled.\n", c->microcode); ++ pr_err_once("Erratum BDX90: late loading with revision < 0x0b000021 (0x%x) disabled.\n", c->microcode); + pr_err_once("Please consider either early loading through initrd/built-in or a potential BIOS update.\n"); + return true; + } diff --git a/queue-6.6/x86-microcode-intel-reuse-intel_cpu_collect_info.patch b/queue-6.6/x86-microcode-intel-reuse-intel_cpu_collect_info.patch new file mode 100644 index 0000000000..893bfba838 --- /dev/null +++ b/queue-6.6/x86-microcode-intel-reuse-intel_cpu_collect_info.patch @@ -0,0 +1,44 @@ +From 5aa5d3f9c1e431e15a849caf6f502152901cfff3 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Mon, 2 Oct 2023 13:59:49 +0200 +Subject: x86/microcode/intel: Reuse intel_cpu_collect_info() + +From: Thomas Gleixner + +commit 11f96ac4c21e701650c7d8349b252973185ac6ce upstream + +No point for an almost duplicate function. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Borislav Petkov (AMD) +Link: https://lore.kernel.org/r/20231002115902.741173606@linutronix.de +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/cpu/microcode/intel.c | 16 +--------------- + 1 file changed, 1 insertion(+), 15 deletions(-) + +--- a/arch/x86/kernel/cpu/microcode/intel.c ++++ b/arch/x86/kernel/cpu/microcode/intel.c +@@ -435,21 +435,7 @@ void reload_ucode_intel(void) + + static int collect_cpu_info(int cpu_num, struct cpu_signature *csig) + { +- struct cpuinfo_x86 *c = &cpu_data(cpu_num); +- unsigned int val[2]; +- +- memset(csig, 0, sizeof(*csig)); +- +- csig->sig = cpuid_eax(0x00000001); +- +- if ((c->x86_model >= 5) || (c->x86 > 6)) { +- /* get processor flags from MSR 0x17 */ +- rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]); +- csig->pf = 1 << ((val[1] >> 18) & 7); +- } +- +- csig->rev = c->microcode; +- ++ intel_collect_cpu_info(csig); + return 0; + } + diff --git a/queue-6.6/x86-microcode-intel-rework-intel_cpu_collect_info.patch b/queue-6.6/x86-microcode-intel-rework-intel_cpu_collect_info.patch new file mode 100644 index 0000000000..6ec0467cd8 --- /dev/null +++ b/queue-6.6/x86-microcode-intel-rework-intel_cpu_collect_info.patch @@ -0,0 +1,118 @@ +From 3959c233b1a962997ecb8854d484882a2025b1c1 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Tue, 17 Oct 2023 23:23:45 +0200 +Subject: x86/microcode/intel: Rework intel_cpu_collect_info() + +From: Thomas Gleixner + +commit 164aa1ca537238c46923ccacd8995b4265aee47b upstream + +Nothing needs struct ucode_cpu_info. Make it take struct cpu_signature, +let it return a boolean and simplify the implementation. Rename it now +that the silly name clash with collect_cpu_info() is gone. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Borislav Petkov (AMD) +Link: https://lore.kernel.org/r/20231017211722.851573238@linutronix.de +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/include/asm/cpu.h | 4 ++-- + arch/x86/kernel/cpu/microcode/intel.c | 33 +++++++++------------------------ + drivers/platform/x86/intel/ifs/load.c | 8 +++----- + 3 files changed, 14 insertions(+), 31 deletions(-) + +--- a/arch/x86/include/asm/cpu.h ++++ b/arch/x86/include/asm/cpu.h +@@ -71,9 +71,9 @@ static inline void init_ia32_feat_ctl(st + + extern __noendbr void cet_disable(void); + +-struct ucode_cpu_info; ++struct cpu_signature; + +-int intel_cpu_collect_info(struct ucode_cpu_info *uci); ++void intel_collect_cpu_info(struct cpu_signature *sig); + + static inline bool intel_cpu_signatures_match(unsigned int s1, unsigned int p1, + unsigned int s2, unsigned int p2) +--- a/arch/x86/kernel/cpu/microcode/intel.c ++++ b/arch/x86/kernel/cpu/microcode/intel.c +@@ -68,36 +68,21 @@ static inline unsigned int exttable_size + return et->count * EXT_SIGNATURE_SIZE + EXT_HEADER_SIZE; + } + +-int intel_cpu_collect_info(struct ucode_cpu_info *uci) ++void intel_collect_cpu_info(struct cpu_signature *sig) + { +- unsigned int val[2]; +- unsigned int family, model; +- struct cpu_signature csig = { 0 }; +- unsigned int eax, ebx, ecx, edx; ++ sig->sig = cpuid_eax(1); ++ sig->pf = 0; ++ sig->rev = intel_get_microcode_revision(); + +- memset(uci, 0, sizeof(*uci)); ++ if (x86_model(sig->sig) >= 5 || x86_family(sig->sig) > 6) { ++ unsigned int val[2]; + +- eax = 0x00000001; +- ecx = 0; +- native_cpuid(&eax, &ebx, &ecx, &edx); +- csig.sig = eax; +- +- family = x86_family(eax); +- model = x86_model(eax); +- +- if (model >= 5 || family > 6) { + /* get processor flags from MSR 0x17 */ + native_rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]); +- csig.pf = 1 << ((val[1] >> 18) & 7); ++ sig->pf = 1 << ((val[1] >> 18) & 7); + } +- +- csig.rev = intel_get_microcode_revision(); +- +- uci->cpu_sig = csig; +- +- return 0; + } +-EXPORT_SYMBOL_GPL(intel_cpu_collect_info); ++EXPORT_SYMBOL_GPL(intel_collect_cpu_info); + + /* + * Returns 1 if update has been found, 0 otherwise. +@@ -391,7 +376,7 @@ static __init struct microcode_intel *ge + if (!(cp.data && cp.size)) + return NULL; + +- intel_cpu_collect_info(uci); ++ intel_collect_cpu_info(&uci->cpu_sig); + + return scan_microcode(cp.data, cp.size, uci, save); + } +--- a/drivers/platform/x86/intel/ifs/load.c ++++ b/drivers/platform/x86/intel/ifs/load.c +@@ -227,7 +227,7 @@ out: + + static int image_sanity_check(struct device *dev, const struct microcode_header_intel *data) + { +- struct ucode_cpu_info uci; ++ struct cpu_signature sig; + + /* Provide a specific error message when loading an older/unsupported image */ + if (data->hdrver != MC_HEADER_TYPE_IFS) { +@@ -240,11 +240,9 @@ static int image_sanity_check(struct dev + return -EINVAL; + } + +- intel_cpu_collect_info(&uci); ++ intel_collect_cpu_info(&sig); + +- if (!intel_find_matching_signature((void *)data, +- uci.cpu_sig.sig, +- uci.cpu_sig.pf)) { ++ if (!intel_find_matching_signature((void *)data, sig.sig, sig.pf)) { + dev_err(dev, "cpu signature, processor flags not matching\n"); + return -EINVAL; + } diff --git a/queue-6.6/x86-microcode-intel-rework-intel_find_matching_signature.patch b/queue-6.6/x86-microcode-intel-rework-intel_find_matching_signature.patch new file mode 100644 index 0000000000..74e499a05a --- /dev/null +++ b/queue-6.6/x86-microcode-intel-rework-intel_find_matching_signature.patch @@ -0,0 +1,127 @@ +From 19c08250133b454726b8efd5a7c6fd27859af202 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Mon, 2 Oct 2023 13:59:50 +0200 +Subject: x86/microcode/intel: Rework intel_find_matching_signature() + +From: Thomas Gleixner + +commit b7fcd995b261c9976e05f47554529c98a0f1cbb0 upstream + +Take a cpu_signature argument and work from there. Move the match() +helper next to the callsite as there is no point for having it in +a header. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Borislav Petkov (AMD) +Link: https://lore.kernel.org/r/20231002115902.797820205@linutronix.de +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/include/asm/cpu.h | 16 +--------------- + arch/x86/kernel/cpu/microcode/intel.c | 31 +++++++++++++++++++------------ + drivers/platform/x86/intel/ifs/load.c | 2 +- + 3 files changed, 21 insertions(+), 28 deletions(-) + +--- a/arch/x86/include/asm/cpu.h ++++ b/arch/x86/include/asm/cpu.h +@@ -75,22 +75,8 @@ struct cpu_signature; + + void intel_collect_cpu_info(struct cpu_signature *sig); + +-static inline bool intel_cpu_signatures_match(unsigned int s1, unsigned int p1, +- unsigned int s2, unsigned int p2) +-{ +- if (s1 != s2) +- return false; +- +- /* Processor flags are either both 0 ... */ +- if (!p1 && !p2) +- return true; +- +- /* ... or they intersect. */ +- return p1 & p2; +-} +- + extern u64 x86_read_arch_cap_msr(void); +-int intel_find_matching_signature(void *mc, unsigned int csig, int cpf); ++bool intel_find_matching_signature(void *mc, struct cpu_signature *sig); + int intel_microcode_sanity_check(void *mc, bool print_err, int hdr_type); + + extern struct cpumask cpus_stop_mask; +--- a/arch/x86/kernel/cpu/microcode/intel.c ++++ b/arch/x86/kernel/cpu/microcode/intel.c +@@ -84,29 +84,36 @@ void intel_collect_cpu_info(struct cpu_s + } + EXPORT_SYMBOL_GPL(intel_collect_cpu_info); + +-/* +- * Returns 1 if update has been found, 0 otherwise. +- */ +-int intel_find_matching_signature(void *mc, unsigned int csig, int cpf) ++static inline bool cpu_signatures_match(struct cpu_signature *s1, unsigned int sig2, ++ unsigned int pf2) ++{ ++ if (s1->sig != sig2) ++ return false; ++ ++ /* Processor flags are either both 0 or they intersect. */ ++ return ((!s1->pf && !pf2) || (s1->pf & pf2)); ++} ++ ++bool intel_find_matching_signature(void *mc, struct cpu_signature *sig) + { + struct microcode_header_intel *mc_hdr = mc; +- struct extended_sigtable *ext_hdr; + struct extended_signature *ext_sig; ++ struct extended_sigtable *ext_hdr; + int i; + +- if (intel_cpu_signatures_match(csig, cpf, mc_hdr->sig, mc_hdr->pf)) +- return 1; ++ if (cpu_signatures_match(sig, mc_hdr->sig, mc_hdr->pf)) ++ return true; + + /* Look for ext. headers: */ + if (get_totalsize(mc_hdr) <= intel_microcode_get_datasize(mc_hdr) + MC_HEADER_SIZE) +- return 0; ++ return false; + + ext_hdr = mc + intel_microcode_get_datasize(mc_hdr) + MC_HEADER_SIZE; + ext_sig = (void *)ext_hdr + EXT_HEADER_SIZE; + + for (i = 0; i < ext_hdr->count; i++) { +- if (intel_cpu_signatures_match(csig, cpf, ext_sig->sig, ext_sig->pf)) +- return 1; ++ if (cpu_signatures_match(sig, ext_sig->sig, ext_sig->pf)) ++ return true; + ext_sig++; + } + return 0; +@@ -268,7 +275,7 @@ static __init struct microcode_intel *sc + intel_microcode_sanity_check(data, false, MC_HEADER_TYPE_MICROCODE) < 0) + break; + +- if (!intel_find_matching_signature(data, uci->cpu_sig.sig, uci->cpu_sig.pf)) ++ if (!intel_find_matching_signature(data, &uci->cpu_sig)) + continue; + + /* +@@ -512,7 +519,7 @@ static enum ucode_state parse_microcode_ + if (cur_rev >= mc_header.rev) + continue; + +- if (!intel_find_matching_signature(mc, uci->cpu_sig.sig, uci->cpu_sig.pf)) ++ if (!intel_find_matching_signature(mc, &uci->cpu_sig)) + continue; + + kvfree(new_mc); +--- a/drivers/platform/x86/intel/ifs/load.c ++++ b/drivers/platform/x86/intel/ifs/load.c +@@ -242,7 +242,7 @@ static int image_sanity_check(struct dev + + intel_collect_cpu_info(&sig); + +- if (!intel_find_matching_signature((void *)data, sig.sig, sig.pf)) { ++ if (!intel_find_matching_signature((void *)data, &sig)) { + dev_err(dev, "cpu signature, processor flags not matching\n"); + return -EINVAL; + } diff --git a/queue-6.6/x86-microcode-intel-rip-out-mixed-stepping-support-for-intel-cpus.patch b/queue-6.6/x86-microcode-intel-rip-out-mixed-stepping-support-for-intel-cpus.patch new file mode 100644 index 0000000000..a0e9968286 --- /dev/null +++ b/queue-6.6/x86-microcode-intel-rip-out-mixed-stepping-support-for-intel-cpus.patch @@ -0,0 +1,303 @@ +From 58ea3102876845d0088b8ebe8458cfac8251d4e3 Mon Sep 17 00:00:00 2001 +From: Ashok Raj +Date: Tue, 17 Oct 2023 23:23:33 +0200 +Subject: x86/microcode/intel: Rip out mixed stepping support for Intel CPUs + +From: Ashok Raj + +commit ae76d951f6537001bdf77894d19cd4a446de337e upstream + +Mixed steppings aren't supported on Intel CPUs. Only one microcode patch +is required for the entire system. The caching of microcode blobs which +match the family and model is therefore pointless and in fact is +dysfunctional as CPU hotplug updates use only a single microcode blob, +i.e. the one where *intel_ucode_patch points to. + +Remove the microcode cache and make it an AMD local feature. + + [ tglx: + - save only at the end. Otherwise random microcode ends up in the + pointer for early loading + - free the ucode patch pointer in save_microcode_patch() only + after kmemdup() has succeeded, as reported by Andrew Cooper ] + +Originally-by: Thomas Gleixner +Signed-off-by: Ashok Raj +Signed-off-by: Thomas Gleixner +Signed-off-by: Borislav Petkov (AMD) +Link: https://lore.kernel.org/r/20231017211722.404362809@linutronix.de +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/cpu/microcode/amd.c | 10 ++ + arch/x86/kernel/cpu/microcode/core.c | 2 + arch/x86/kernel/cpu/microcode/intel.c | 133 +++++-------------------------- + arch/x86/kernel/cpu/microcode/internal.h | 10 -- + 4 files changed, 34 insertions(+), 121 deletions(-) + +--- a/arch/x86/kernel/cpu/microcode/amd.c ++++ b/arch/x86/kernel/cpu/microcode/amd.c +@@ -37,6 +37,16 @@ + + #include "internal.h" + ++struct ucode_patch { ++ struct list_head plist; ++ void *data; ++ unsigned int size; ++ u32 patch_id; ++ u16 equiv_cpu; ++}; ++ ++static LIST_HEAD(microcode_cache); ++ + #define UCODE_MAGIC 0x00414d44 + #define UCODE_EQUIV_CPU_TABLE_TYPE 0x00000000 + #define UCODE_UCODE_TYPE 0x00000001 +--- a/arch/x86/kernel/cpu/microcode/core.c ++++ b/arch/x86/kernel/cpu/microcode/core.c +@@ -46,8 +46,6 @@ static bool dis_ucode_ldr = true; + + bool initrd_gone; + +-LIST_HEAD(microcode_cache); +- + /* + * Synchronization. + * +--- a/arch/x86/kernel/cpu/microcode/intel.c ++++ b/arch/x86/kernel/cpu/microcode/intel.c +@@ -33,10 +33,10 @@ + static const char ucode_path[] = "kernel/x86/microcode/GenuineIntel.bin"; + + /* Current microcode patch used in early patching on the APs. */ +-static struct microcode_intel *intel_ucode_patch; ++static struct microcode_intel *intel_ucode_patch __read_mostly; + + /* last level cache size per core */ +-static int llc_size_per_core; ++static int llc_size_per_core __ro_after_init; + + /* microcode format is extended from prescott processors */ + struct extended_signature { +@@ -253,74 +253,17 @@ static int has_newer_microcode(void *mc, + return intel_find_matching_signature(mc, csig, cpf); + } + +-static struct ucode_patch *memdup_patch(void *data, unsigned int size) ++static void save_microcode_patch(void *data, unsigned int size) + { +- struct ucode_patch *p; ++ struct microcode_header_intel *p; + +- p = kzalloc(sizeof(struct ucode_patch), GFP_KERNEL); ++ p = kmemdup(data, size, GFP_KERNEL); + if (!p) +- return NULL; +- +- p->data = kmemdup(data, size, GFP_KERNEL); +- if (!p->data) { +- kfree(p); +- return NULL; +- } +- +- return p; +-} +- +-static void save_microcode_patch(struct ucode_cpu_info *uci, void *data, unsigned int size) +-{ +- struct microcode_header_intel *mc_hdr, *mc_saved_hdr; +- struct ucode_patch *iter, *tmp, *p = NULL; +- bool prev_found = false; +- unsigned int sig, pf; +- +- mc_hdr = (struct microcode_header_intel *)data; +- +- list_for_each_entry_safe(iter, tmp, µcode_cache, plist) { +- mc_saved_hdr = (struct microcode_header_intel *)iter->data; +- sig = mc_saved_hdr->sig; +- pf = mc_saved_hdr->pf; +- +- if (intel_find_matching_signature(data, sig, pf)) { +- prev_found = true; +- +- if (mc_hdr->rev <= mc_saved_hdr->rev) +- continue; +- +- p = memdup_patch(data, size); +- if (!p) +- pr_err("Error allocating buffer %p\n", data); +- else { +- list_replace(&iter->plist, &p->plist); +- kfree(iter->data); +- kfree(iter); +- } +- } +- } +- +- /* +- * There weren't any previous patches found in the list cache; save the +- * newly found. +- */ +- if (!prev_found) { +- p = memdup_patch(data, size); +- if (!p) +- pr_err("Error allocating buffer for %p\n", data); +- else +- list_add_tail(&p->plist, µcode_cache); +- } +- +- if (!p) +- return; +- +- if (!intel_find_matching_signature(p->data, uci->cpu_sig.sig, uci->cpu_sig.pf)) + return; + ++ kfree(intel_ucode_patch); + /* Save for early loading */ +- intel_ucode_patch = p->data; ++ intel_ucode_patch = (struct microcode_intel *)p; + } + + /* +@@ -332,6 +275,7 @@ scan_microcode(void *data, size_t size, + { + struct microcode_header_intel *mc_header; + struct microcode_intel *patch = NULL; ++ u32 cur_rev = uci->cpu_sig.rev; + unsigned int mc_size; + + while (size) { +@@ -341,8 +285,7 @@ scan_microcode(void *data, size_t size, + mc_header = (struct microcode_header_intel *)data; + + mc_size = get_totalsize(mc_header); +- if (!mc_size || +- mc_size > size || ++ if (!mc_size || mc_size > size || + intel_microcode_sanity_check(data, false, MC_HEADER_TYPE_MICROCODE) < 0) + break; + +@@ -354,31 +297,16 @@ scan_microcode(void *data, size_t size, + continue; + } + +- if (save) { +- save_microcode_patch(uci, data, mc_size); ++ /* BSP scan: Check whether there is newer microcode */ ++ if (!save && cur_rev >= mc_header->rev) + goto next; +- } +- + +- if (!patch) { +- if (!has_newer_microcode(data, +- uci->cpu_sig.sig, +- uci->cpu_sig.pf, +- uci->cpu_sig.rev)) +- goto next; +- +- } else { +- struct microcode_header_intel *phdr = &patch->hdr; +- +- if (!has_newer_microcode(data, +- phdr->sig, +- phdr->pf, +- phdr->rev)) +- goto next; +- } ++ /* Save scan: Check whether there is newer or matching microcode */ ++ if (save && cur_rev != mc_header->rev) ++ goto next; + +- /* We have a newer patch, save it. */ + patch = data; ++ cur_rev = mc_header->rev; + + next: + data += mc_size; +@@ -387,6 +315,9 @@ next: + if (size) + return NULL; + ++ if (save && patch) ++ save_microcode_patch(patch, mc_size); ++ + return patch; + } + +@@ -528,26 +459,10 @@ void load_ucode_intel_ap(void) + apply_microcode_early(&uci); + } + +-static struct microcode_intel *find_patch(struct ucode_cpu_info *uci) ++/* Accessor for microcode pointer */ ++static struct microcode_intel *ucode_get_patch(void) + { +- struct microcode_header_intel *phdr; +- struct ucode_patch *iter, *tmp; +- +- list_for_each_entry_safe(iter, tmp, µcode_cache, plist) { +- +- phdr = (struct microcode_header_intel *)iter->data; +- +- if (phdr->rev <= uci->cpu_sig.rev) +- continue; +- +- if (!intel_find_matching_signature(phdr, +- uci->cpu_sig.sig, +- uci->cpu_sig.pf)) +- continue; +- +- return iter->data; +- } +- return NULL; ++ return intel_ucode_patch; + } + + void reload_ucode_intel(void) +@@ -557,7 +472,7 @@ void reload_ucode_intel(void) + + intel_cpu_collect_info(&uci); + +- p = find_patch(&uci); ++ p = ucode_get_patch(); + if (!p) + return; + +@@ -601,7 +516,7 @@ static enum ucode_state apply_microcode_ + return UCODE_ERROR; + + /* Look for a newer patch in our cache: */ +- mc = find_patch(uci); ++ mc = ucode_get_patch(); + if (!mc) { + mc = uci->mc; + if (!mc) +@@ -730,7 +645,7 @@ static enum ucode_state generic_load_mic + uci->mc = (struct microcode_intel *)new_mc; + + /* Save for CPU hotplug */ +- save_microcode_patch(uci, new_mc, new_mc_size); ++ save_microcode_patch(new_mc, new_mc_size); + + pr_debug("CPU%d found a matching microcode update with version 0x%x (current=0x%x)\n", + cpu, new_rev, uci->cpu_sig.rev); +--- a/arch/x86/kernel/cpu/microcode/internal.h ++++ b/arch/x86/kernel/cpu/microcode/internal.h +@@ -8,16 +8,6 @@ + #include + #include + +-struct ucode_patch { +- struct list_head plist; +- void *data; /* Intel uses only this one */ +- unsigned int size; +- u32 patch_id; +- u16 equiv_cpu; +-}; +- +-extern struct list_head microcode_cache; +- + struct device; + + enum ucode_state { diff --git a/queue-6.6/x86-microcode-intel-save-the-microcode-only-after-a-successful-late-load.patch b/queue-6.6/x86-microcode-intel-save-the-microcode-only-after-a-successful-late-load.patch new file mode 100644 index 0000000000..d9947cdc7e --- /dev/null +++ b/queue-6.6/x86-microcode-intel-save-the-microcode-only-after-a-successful-late-load.patch @@ -0,0 +1,123 @@ +From 9b3fa0e8651fe1988c3103d1bca401cca0341258 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Mon, 2 Oct 2023 13:59:44 +0200 +Subject: x86/microcode/intel: Save the microcode only after a successful late-load + +From: Thomas Gleixner + +commit 2a1dada3d1cf8f80a27663653a371d99dbf5d540 upstream + +There are situations where the late microcode is loaded into memory but +is not applied: + + 1) The rendezvous fails + 2) The microcode is rejected by the CPUs + +If any of this happens then the pointer which was updated at firmware +load time is stale and subsequent CPU hotplug operations either fail to +update or create inconsistent microcode state. + +Save the loaded microcode in a separate pointer before the late load is +attempted and when successful, update the hotplug pointer accordingly +via a new microcode_ops callback. + +Remove the pointless fallback in the loader to a microcode pointer which +is never populated. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Borislav Petkov (AMD) +Link: https://lore.kernel.org/r/20231002115902.505491309@linutronix.de +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/cpu/microcode/core.c | 4 ++++ + arch/x86/kernel/cpu/microcode/intel.c | 30 +++++++++++++++--------------- + arch/x86/kernel/cpu/microcode/internal.h | 1 + + 3 files changed, 20 insertions(+), 15 deletions(-) + +--- a/arch/x86/kernel/cpu/microcode/core.c ++++ b/arch/x86/kernel/cpu/microcode/core.c +@@ -403,6 +403,10 @@ static int microcode_reload_late(void) + store_cpu_caps(&prev_info); + + ret = stop_machine_cpuslocked(__reload_late, NULL, cpu_online_mask); ++ ++ if (microcode_ops->finalize_late_load) ++ microcode_ops->finalize_late_load(ret); ++ + if (!ret) { + pr_info("Reload succeeded, microcode revision: 0x%x -> 0x%x\n", + old, boot_cpu_data.microcode); +--- a/arch/x86/kernel/cpu/microcode/intel.c ++++ b/arch/x86/kernel/cpu/microcode/intel.c +@@ -36,6 +36,7 @@ static const char ucode_path[] = "kernel + + /* Current microcode patch used in early patching on the APs. */ + static struct microcode_intel *ucode_patch_va __read_mostly; ++static struct microcode_intel *ucode_patch_late __read_mostly; + + /* last level cache size per core */ + static unsigned int llc_size_per_core __ro_after_init; +@@ -470,12 +471,9 @@ static enum ucode_state apply_microcode_ + if (WARN_ON(raw_smp_processor_id() != cpu)) + return UCODE_ERROR; + +- mc = ucode_patch_va; +- if (!mc) { +- mc = uci->mc; +- if (!mc) +- return UCODE_NFOUND; +- } ++ mc = ucode_patch_late; ++ if (!mc) ++ return UCODE_NFOUND; + + /* + * Save us the MSR write below - which is a particular expensive +@@ -594,15 +592,7 @@ static enum ucode_state parse_microcode_ + if (!new_mc) + return UCODE_NFOUND; + +- /* Save for CPU hotplug */ +- save_microcode_patch((struct microcode_intel *)new_mc); +- uci->mc = ucode_patch_va; +- +- vfree(new_mc); +- +- pr_debug("CPU%d found a matching microcode update with version 0x%x (current=0x%x)\n", +- cpu, cur_rev, uci->cpu_sig.rev); +- ++ ucode_patch_late = (struct microcode_intel *)new_mc; + return UCODE_NEW; + } + +@@ -659,10 +649,20 @@ static enum ucode_state request_microcod + return ret; + } + ++static void finalize_late_load(int result) ++{ ++ if (!result) ++ save_microcode_patch(ucode_patch_late); ++ ++ vfree(ucode_patch_late); ++ ucode_patch_late = NULL; ++} ++ + static struct microcode_ops microcode_intel_ops = { + .request_microcode_fw = request_microcode_fw, + .collect_cpu_info = collect_cpu_info, + .apply_microcode = apply_microcode_intel, ++ .finalize_late_load = finalize_late_load, + }; + + static __init void calc_llc_size_per_core(struct cpuinfo_x86 *c) +--- a/arch/x86/kernel/cpu/microcode/internal.h ++++ b/arch/x86/kernel/cpu/microcode/internal.h +@@ -31,6 +31,7 @@ struct microcode_ops { + */ + enum ucode_state (*apply_microcode)(int cpu); + int (*collect_cpu_info)(int cpu, struct cpu_signature *csig); ++ void (*finalize_late_load)(int result); + }; + + extern struct ucode_cpu_info ucode_cpu_info[]; diff --git a/queue-6.6/x86-microcode-intel-set-new-revision-only-after-a-successful-update.patch b/queue-6.6/x86-microcode-intel-set-new-revision-only-after-a-successful-update.patch new file mode 100644 index 0000000000..14aaed90fc --- /dev/null +++ b/queue-6.6/x86-microcode-intel-set-new-revision-only-after-a-successful-update.patch @@ -0,0 +1,63 @@ +From 9f96838d0ac5ce33575968c2596eba004118f885 Mon Sep 17 00:00:00 2001 +From: "Borislav Petkov (AMD)" +Date: Fri, 1 Dec 2023 14:35:06 +0100 +Subject: x86/microcode/intel: Set new revision only after a successful update + +From: "Borislav Petkov (AMD)" + +commit 9c21ea53e6bd1104c637b80a0688040f184cc761 upstream + +This was meant to be done only when early microcode got updated +successfully. Move it into the if-branch. + +Also, make sure the current revision is read unconditionally and only +once. + +Fixes: 080990aa3344 ("x86/microcode: Rework early revisions reporting") +Reported-by: Ashok Raj +Signed-off-by: Borislav Petkov (AMD) +Tested-by: Ashok Raj +Link: https://lore.kernel.org/r/ZWjVt5dNRjbcvlzR@a4bf019067fa.jf.intel.com +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/cpu/microcode/intel.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +--- a/arch/x86/kernel/cpu/microcode/intel.c ++++ b/arch/x86/kernel/cpu/microcode/intel.c +@@ -370,14 +370,14 @@ static __init struct microcode_intel *ge + { + struct cpio_data cp; + ++ intel_collect_cpu_info(&uci->cpu_sig); ++ + if (!load_builtin_intel_microcode(&cp)) + cp = find_microcode_in_initrd(ucode_path); + + if (!(cp.data && cp.size)) + return NULL; + +- intel_collect_cpu_info(&uci->cpu_sig); +- + return scan_microcode(cp.data, cp.size, uci, save); + } + +@@ -410,13 +410,13 @@ void __init load_ucode_intel_bsp(struct + { + struct ucode_cpu_info uci; + +- ed->old_rev = intel_get_microcode_revision(); +- + uci.mc = get_microcode_blob(&uci, false); +- if (uci.mc && apply_microcode_early(&uci) == UCODE_UPDATED) +- ucode_patch_va = UCODE_BSP_LOADED; ++ ed->old_rev = uci.cpu_sig.rev; + +- ed->new_rev = uci.cpu_sig.rev; ++ if (uci.mc && apply_microcode_early(&uci) == UCODE_UPDATED) { ++ ucode_patch_va = UCODE_BSP_LOADED; ++ ed->new_rev = uci.cpu_sig.rev; ++ } + } + + void load_ucode_intel_ap(void) diff --git a/queue-6.6/x86-microcode-intel-simplify-and-rename-generic_load_microcode.patch b/queue-6.6/x86-microcode-intel-simplify-and-rename-generic_load_microcode.patch new file mode 100644 index 0000000000..56c44d387e --- /dev/null +++ b/queue-6.6/x86-microcode-intel-simplify-and-rename-generic_load_microcode.patch @@ -0,0 +1,116 @@ +From 439bbf98a0eeb839da26fe91d0dd0fb158957de3 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Mon, 2 Oct 2023 13:59:40 +0200 +Subject: x86/microcode/intel: Simplify and rename generic_load_microcode() + +From: Thomas Gleixner + +commit 6b072022ab2e1e83b7588144ee0080f7197b71da upstream + +so it becomes less obfuscated and rename it because there is nothing +generic about it. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Borislav Petkov (AMD) +Link: https://lore.kernel.org/r/20231002115902.330295409@linutronix.de +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/cpu/microcode/intel.c | 47 ++++++++++++---------------------- + 1 file changed, 17 insertions(+), 30 deletions(-) + +--- a/arch/x86/kernel/cpu/microcode/intel.c ++++ b/arch/x86/kernel/cpu/microcode/intel.c +@@ -240,19 +240,6 @@ int intel_microcode_sanity_check(void *m + } + EXPORT_SYMBOL_GPL(intel_microcode_sanity_check); + +-/* +- * Returns 1 if update has been found, 0 otherwise. +- */ +-static int has_newer_microcode(void *mc, unsigned int csig, int cpf, int new_rev) +-{ +- struct microcode_header_intel *mc_hdr = mc; +- +- if (mc_hdr->rev <= new_rev) +- return 0; +- +- return intel_find_matching_signature(mc, csig, cpf); +-} +- + static void save_microcode_patch(void *data, unsigned int size) + { + struct microcode_header_intel *p; +@@ -559,14 +546,12 @@ out: + return ret; + } + +-static enum ucode_state generic_load_microcode(int cpu, struct iov_iter *iter) ++static enum ucode_state parse_microcode_blobs(int cpu, struct iov_iter *iter) + { + struct ucode_cpu_info *uci = ucode_cpu_info + cpu; + unsigned int curr_mc_size = 0, new_mc_size = 0; +- enum ucode_state ret = UCODE_OK; +- int new_rev = uci->cpu_sig.rev; ++ int cur_rev = uci->cpu_sig.rev; + u8 *new_mc = NULL, *mc = NULL; +- unsigned int csig, cpf; + + while (iov_iter_count(iter)) { + struct microcode_header_intel mc_header; +@@ -583,6 +568,7 @@ static enum ucode_state generic_load_mic + pr_err("error! Bad data in microcode data file (totalsize too small)\n"); + break; + } ++ + data_size = mc_size - sizeof(mc_header); + if (data_size > iov_iter_count(iter)) { + pr_err("error! Bad data in microcode data file (truncated file?)\n"); +@@ -605,16 +591,17 @@ static enum ucode_state generic_load_mic + break; + } + +- csig = uci->cpu_sig.sig; +- cpf = uci->cpu_sig.pf; +- if (has_newer_microcode(mc, csig, cpf, new_rev)) { +- vfree(new_mc); +- new_rev = mc_header.rev; +- new_mc = mc; +- new_mc_size = mc_size; +- mc = NULL; /* trigger new vmalloc */ +- ret = UCODE_NEW; +- } ++ if (cur_rev >= mc_header.rev) ++ continue; ++ ++ if (!intel_find_matching_signature(mc, uci->cpu_sig.sig, uci->cpu_sig.pf)) ++ continue; ++ ++ vfree(new_mc); ++ cur_rev = mc_header.rev; ++ new_mc = mc; ++ new_mc_size = mc_size; ++ mc = NULL; + } + + vfree(mc); +@@ -634,9 +621,9 @@ static enum ucode_state generic_load_mic + save_microcode_patch(new_mc, new_mc_size); + + pr_debug("CPU%d found a matching microcode update with version 0x%x (current=0x%x)\n", +- cpu, new_rev, uci->cpu_sig.rev); ++ cpu, cur_rev, uci->cpu_sig.rev); + +- return ret; ++ return UCODE_NEW; + } + + static bool is_blacklisted(unsigned int cpu) +@@ -685,7 +672,7 @@ static enum ucode_state request_microcod + kvec.iov_base = (void *)firmware->data; + kvec.iov_len = firmware->size; + iov_iter_kvec(&iter, ITER_SOURCE, &kvec, 1, firmware->size); +- ret = generic_load_microcode(cpu, &iter); ++ ret = parse_microcode_blobs(cpu, &iter); + + release_firmware(firmware); + diff --git a/queue-6.6/x86-microcode-intel-simplify-early-loading.patch b/queue-6.6/x86-microcode-intel-simplify-early-loading.patch new file mode 100644 index 0000000000..d4d11c2ce5 --- /dev/null +++ b/queue-6.6/x86-microcode-intel-simplify-early-loading.patch @@ -0,0 +1,389 @@ +From 3c4ebaefd467735f9aec389f02264f17fc7e0f3a Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Mon, 2 Oct 2023 13:59:43 +0200 +Subject: x86/microcode/intel: Simplify early loading + +From: Thomas Gleixner + +commit dd5e3e3ca6ac011582a9f3f987493bf6741568c0 upstream. + +The early loading code is overly complicated: + + - It scans the builtin/initrd for microcode not only on the BSP, but also + on all APs during early boot and then later in the boot process it + scans again to duplicate and save the microcode before initrd goes + away. + + That's a pointless exercise because this can be simply done before + bringing up the APs when the memory allocator is up and running. + + - Saving the microcode from within the scan loop is completely + non-obvious and a left over of the microcode cache. + + This can be done at the call site now which makes it obvious. + +Rework the code so that only the BSP scans the builtin/initrd microcode +once during early boot and save it away in an early initcall for later +use. + + [ bp: Test and fold in a fix from tglx ontop which handles the need to + distinguish what save_microcode() does depending on when it is + called: + + - when on the BSP during early load, it needs to find a newer + revision than the one currently loaded on the BSP + + - later, before SMP init, it still runs on the BSP and gets the BSP + revision just loaded and uses that revision to know which patch + to save for the APs. For that it needs to find the exact one as + on the BSP. + ] + +Signed-off-by: Thomas Gleixner +Signed-off-by: Borislav Petkov (AMD) +Link: https://lore.kernel.org/r/20231017211722.629085215@linutronix.de +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/cpu/microcode/core.c | 6 - + arch/x86/kernel/cpu/microcode/intel.c | 163 ++++++++++++++----------------- + arch/x86/kernel/cpu/microcode/internal.h | 3 + 3 files changed, 79 insertions(+), 93 deletions(-) + +--- a/arch/x86/kernel/cpu/microcode/core.c ++++ b/arch/x86/kernel/cpu/microcode/core.c +@@ -42,7 +42,7 @@ + #define DRIVER_VERSION "2.2" + + static struct microcode_ops *microcode_ops; +-static bool dis_ucode_ldr = true; ++bool dis_ucode_ldr = true; + + bool initrd_gone; + +@@ -191,10 +191,6 @@ static int __init save_microcode_in_init + } + + switch (c->x86_vendor) { +- case X86_VENDOR_INTEL: +- if (c->x86 >= 6) +- ret = save_microcode_in_initrd_intel(); +- break; + case X86_VENDOR_AMD: + if (c->x86 >= 0x10) + ret = save_microcode_in_initrd_amd(cpuid_eax(1)); +--- a/arch/x86/kernel/cpu/microcode/intel.c ++++ b/arch/x86/kernel/cpu/microcode/intel.c +@@ -32,8 +32,10 @@ + + static const char ucode_path[] = "kernel/x86/microcode/GenuineIntel.bin"; + ++#define UCODE_BSP_LOADED ((struct microcode_intel *)0x1UL) ++ + /* Current microcode patch used in early patching on the APs. */ +-static struct microcode_intel *intel_ucode_patch __read_mostly; ++static struct microcode_intel *ucode_patch_va __read_mostly; + + /* last level cache size per core */ + static unsigned int llc_size_per_core __ro_after_init; +@@ -240,22 +242,30 @@ int intel_microcode_sanity_check(void *m + } + EXPORT_SYMBOL_GPL(intel_microcode_sanity_check); + +-static void save_microcode_patch(void *data, unsigned int size) ++static void update_ucode_pointer(struct microcode_intel *mc) + { +- struct microcode_header_intel *p; ++ kfree(ucode_patch_va); ++ ++ /* ++ * Save the virtual address for early loading and for eventual free ++ * on late loading. ++ */ ++ ucode_patch_va = mc; ++} + +- p = kmemdup(data, size, GFP_KERNEL); +- if (!p) +- return; ++static void save_microcode_patch(struct microcode_intel *patch) ++{ ++ struct microcode_intel *mc; + +- kfree(intel_ucode_patch); +- /* Save for early loading */ +- intel_ucode_patch = (struct microcode_intel *)p; ++ mc = kmemdup(patch, get_totalsize(&patch->hdr), GFP_KERNEL); ++ if (mc) ++ update_ucode_pointer(mc); + } + +-/* Scan CPIO for microcode matching the boot CPU's family, model, stepping */ +-static struct microcode_intel *scan_microcode(void *data, size_t size, +- struct ucode_cpu_info *uci, bool save) ++/* Scan blob for microcode matching the boot CPUs family, model, stepping */ ++static __init struct microcode_intel *scan_microcode(void *data, size_t size, ++ struct ucode_cpu_info *uci, ++ bool save) + { + struct microcode_header_intel *mc_header; + struct microcode_intel *patch = NULL; +@@ -273,35 +283,35 @@ static struct microcode_intel *scan_micr + if (!intel_find_matching_signature(data, uci->cpu_sig.sig, uci->cpu_sig.pf)) + continue; + +- /* BSP scan: Check whether there is newer microcode */ +- if (!save && cur_rev >= mc_header->rev) +- continue; +- +- /* Save scan: Check whether there is newer or matching microcode */ +- if (save && cur_rev != mc_header->rev) ++ /* ++ * For saving the early microcode, find the matching revision which ++ * was loaded on the BSP. ++ * ++ * On the BSP during early boot, find a newer revision than ++ * actually loaded in the CPU. ++ */ ++ if (save) { ++ if (cur_rev != mc_header->rev) ++ continue; ++ } else if (cur_rev >= mc_header->rev) { + continue; ++ } + + patch = data; + cur_rev = mc_header->rev; + } + +- if (size) +- return NULL; +- +- if (save && patch) +- save_microcode_patch(patch, mc_size); +- +- return patch; ++ return size ? NULL : patch; + } + +-static int apply_microcode_early(struct ucode_cpu_info *uci) ++static enum ucode_state apply_microcode_early(struct ucode_cpu_info *uci) + { + struct microcode_intel *mc; + u32 rev, old_rev, date; + + mc = uci->mc; + if (!mc) +- return 0; ++ return UCODE_NFOUND; + + /* + * Save us the MSR write below - which is a particular expensive +@@ -327,17 +337,17 @@ static int apply_microcode_early(struct + + rev = intel_get_microcode_revision(); + if (rev != mc->hdr.rev) +- return -1; ++ return UCODE_ERROR; + + uci->cpu_sig.rev = rev; + + date = mc->hdr.date; + pr_info_once("updated early: 0x%x -> 0x%x, date = %04x-%02x-%02x\n", + old_rev, rev, date & 0xffff, date >> 24, (date >> 16) & 0xff); +- return 0; ++ return UCODE_UPDATED; + } + +-static bool load_builtin_intel_microcode(struct cpio_data *cp) ++static __init bool load_builtin_intel_microcode(struct cpio_data *cp) + { + unsigned int eax = 1, ebx, ecx = 0, edx; + struct firmware fw; +@@ -359,89 +369,71 @@ static bool load_builtin_intel_microcode + return false; + } + +-int __init save_microcode_in_initrd_intel(void) ++static __init struct microcode_intel *get_microcode_blob(struct ucode_cpu_info *uci, bool save) + { +- struct ucode_cpu_info uci; + struct cpio_data cp; + +- /* +- * initrd is going away, clear patch ptr. We will scan the microcode one +- * last time before jettisoning and save a patch, if found. Then we will +- * update that pointer too, with a stable patch address to use when +- * resuming the cores. +- */ +- intel_ucode_patch = NULL; +- + if (!load_builtin_intel_microcode(&cp)) + cp = find_microcode_in_initrd(ucode_path); + + if (!(cp.data && cp.size)) +- return 0; ++ return NULL; + +- intel_cpu_collect_info(&uci); ++ intel_cpu_collect_info(uci); + +- scan_microcode(cp.data, cp.size, &uci, true); +- return 0; ++ return scan_microcode(cp.data, cp.size, uci, save); + } + + /* +- * @res_patch, output: a pointer to the patch we found. ++ * Invoked from an early init call to save the microcode blob which was ++ * selected during early boot when mm was not usable. The microcode must be ++ * saved because initrd is going away. It's an early init call so the APs ++ * just can use the pointer and do not have to scan initrd/builtin firmware ++ * again. + */ +-static struct microcode_intel *__load_ucode_intel(struct ucode_cpu_info *uci) ++static int __init save_builtin_microcode(void) + { +- struct cpio_data cp; +- +- /* try built-in microcode first */ +- if (!load_builtin_intel_microcode(&cp)) +- cp = find_microcode_in_initrd(ucode_path); ++ struct ucode_cpu_info uci; + +- if (!(cp.data && cp.size)) +- return NULL; ++ if (xchg(&ucode_patch_va, NULL) != UCODE_BSP_LOADED) ++ return 0; + +- intel_cpu_collect_info(uci); ++ if (dis_ucode_ldr || boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) ++ return 0; + +- return scan_microcode(cp.data, cp.size, uci, false); ++ uci.mc = get_microcode_blob(&uci, true); ++ if (uci.mc) ++ save_microcode_patch(uci.mc); ++ return 0; + } ++early_initcall(save_builtin_microcode); + ++/* Load microcode on BSP from initrd or builtin blobs */ + void __init load_ucode_intel_bsp(void) + { +- struct microcode_intel *patch; + struct ucode_cpu_info uci; + +- patch = __load_ucode_intel(&uci); +- if (!patch) +- return; +- +- uci.mc = patch; +- +- apply_microcode_early(&uci); ++ uci.mc = get_microcode_blob(&uci, false); ++ if (uci.mc && apply_microcode_early(&uci) == UCODE_UPDATED) ++ ucode_patch_va = UCODE_BSP_LOADED; + } + + void load_ucode_intel_ap(void) + { + struct ucode_cpu_info uci; + +- if (!intel_ucode_patch) { +- intel_ucode_patch = __load_ucode_intel(&uci); +- if (!intel_ucode_patch) +- return; +- } +- +- uci.mc = intel_ucode_patch; +- apply_microcode_early(&uci); ++ uci.mc = ucode_patch_va; ++ if (uci.mc) ++ apply_microcode_early(&uci); + } + ++/* Reload microcode on resume */ + void reload_ucode_intel(void) + { +- struct ucode_cpu_info uci; +- +- intel_cpu_collect_info(&uci); +- +- uci.mc = intel_ucode_patch; +- if (!uci.mc) +- return; ++ struct ucode_cpu_info uci = { .mc = ucode_patch_va, }; + +- apply_microcode_early(&uci); ++ if (uci.mc) ++ apply_microcode_early(&uci); + } + + static int collect_cpu_info(int cpu_num, struct cpu_signature *csig) +@@ -478,7 +470,7 @@ static enum ucode_state apply_microcode_ + if (WARN_ON(raw_smp_processor_id() != cpu)) + return UCODE_ERROR; + +- mc = intel_ucode_patch; ++ mc = ucode_patch_va; + if (!mc) { + mc = uci->mc; + if (!mc) +@@ -538,8 +530,8 @@ out: + static enum ucode_state parse_microcode_blobs(int cpu, struct iov_iter *iter) + { + struct ucode_cpu_info *uci = ucode_cpu_info + cpu; +- unsigned int curr_mc_size = 0, new_mc_size = 0; + int cur_rev = uci->cpu_sig.rev; ++ unsigned int curr_mc_size = 0; + u8 *new_mc = NULL, *mc = NULL; + + while (iov_iter_count(iter)) { +@@ -589,7 +581,6 @@ static enum ucode_state parse_microcode_ + vfree(new_mc); + cur_rev = mc_header.rev; + new_mc = mc; +- new_mc_size = mc_size; + mc = NULL; + } + +@@ -603,11 +594,11 @@ static enum ucode_state parse_microcode_ + if (!new_mc) + return UCODE_NFOUND; + +- vfree(uci->mc); +- uci->mc = (struct microcode_intel *)new_mc; +- + /* Save for CPU hotplug */ +- save_microcode_patch(new_mc, new_mc_size); ++ save_microcode_patch((struct microcode_intel *)new_mc); ++ uci->mc = ucode_patch_va; ++ ++ vfree(new_mc); + + pr_debug("CPU%d found a matching microcode update with version 0x%x (current=0x%x)\n", + cpu, cur_rev, uci->cpu_sig.rev); +--- a/arch/x86/kernel/cpu/microcode/internal.h ++++ b/arch/x86/kernel/cpu/microcode/internal.h +@@ -84,6 +84,7 @@ static inline unsigned int x86_cpuid_fam + return x86_family(eax); + } + ++extern bool dis_ucode_ldr; + extern bool initrd_gone; + + #ifdef CONFIG_CPU_SUP_AMD +@@ -107,13 +108,11 @@ static inline void exit_amd_microcode(vo + #ifdef CONFIG_CPU_SUP_INTEL + void load_ucode_intel_bsp(void); + void load_ucode_intel_ap(void); +-int save_microcode_in_initrd_intel(void); + void reload_ucode_intel(void); + struct microcode_ops *init_intel_microcode(void); + #else /* CONFIG_CPU_SUP_INTEL */ + static inline void load_ucode_intel_bsp(void) { } + static inline void load_ucode_intel_ap(void) { } +-static inline int save_microcode_in_initrd_intel(void) { return -EINVAL; } + static inline void reload_ucode_intel(void) { } + static inline struct microcode_ops *init_intel_microcode(void) { return NULL; } + #endif /* !CONFIG_CPU_SUP_INTEL */ diff --git a/queue-6.6/x86-microcode-intel-simplify-scan_microcode.patch b/queue-6.6/x86-microcode-intel-simplify-scan_microcode.patch new file mode 100644 index 0000000000..9239408d27 --- /dev/null +++ b/queue-6.6/x86-microcode-intel-simplify-scan_microcode.patch @@ -0,0 +1,79 @@ +From 0487743593c7df7d637db9048c5727bd7c1cea03 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Mon, 2 Oct 2023 13:59:39 +0200 +Subject: x86/microcode/intel: Simplify scan_microcode() + +From: Thomas Gleixner + +commit b0f0bf5eef5fac6ba30b7cac15ca4cb01f8a6ca9 upstream + +Make it readable and comprehensible. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Borislav Petkov (AMD) +Link: https://lore.kernel.org/r/20231002115902.271940980@linutronix.de +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/cpu/microcode/intel.c | 28 +++++++--------------------- + 1 file changed, 7 insertions(+), 21 deletions(-) + +--- a/arch/x86/kernel/cpu/microcode/intel.c ++++ b/arch/x86/kernel/cpu/microcode/intel.c +@@ -266,22 +266,16 @@ static void save_microcode_patch(void *d + intel_ucode_patch = (struct microcode_intel *)p; + } + +-/* +- * Get microcode matching with BSP's model. Only CPUs with the same model as +- * BSP can stay in the platform. +- */ +-static struct microcode_intel * +-scan_microcode(void *data, size_t size, struct ucode_cpu_info *uci, bool save) ++/* Scan CPIO for microcode matching the boot CPU's family, model, stepping */ ++static struct microcode_intel *scan_microcode(void *data, size_t size, ++ struct ucode_cpu_info *uci, bool save) + { + struct microcode_header_intel *mc_header; + struct microcode_intel *patch = NULL; + u32 cur_rev = uci->cpu_sig.rev; + unsigned int mc_size; + +- while (size) { +- if (size < sizeof(struct microcode_header_intel)) +- break; +- ++ for (; size >= sizeof(struct microcode_header_intel); size -= mc_size, data += mc_size) { + mc_header = (struct microcode_header_intel *)data; + + mc_size = get_totalsize(mc_header); +@@ -289,27 +283,19 @@ scan_microcode(void *data, size_t size, + intel_microcode_sanity_check(data, false, MC_HEADER_TYPE_MICROCODE) < 0) + break; + +- size -= mc_size; +- +- if (!intel_find_matching_signature(data, uci->cpu_sig.sig, +- uci->cpu_sig.pf)) { +- data += mc_size; ++ if (!intel_find_matching_signature(data, uci->cpu_sig.sig, uci->cpu_sig.pf)) + continue; +- } + + /* BSP scan: Check whether there is newer microcode */ + if (!save && cur_rev >= mc_header->rev) +- goto next; ++ continue; + + /* Save scan: Check whether there is newer or matching microcode */ + if (save && cur_rev != mc_header->rev) +- goto next; ++ continue; + + patch = data; + cur_rev = mc_header->rev; +- +-next: +- data += mc_size; + } + + if (size) diff --git a/queue-6.6/x86-microcode-intel-switch-to-kvmalloc.patch b/queue-6.6/x86-microcode-intel-switch-to-kvmalloc.patch new file mode 100644 index 0000000000..2b393b0c08 --- /dev/null +++ b/queue-6.6/x86-microcode-intel-switch-to-kvmalloc.patch @@ -0,0 +1,147 @@ +From 0937c0624d82085ec90acde324c0bd6d9accfa20 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Mon, 2 Oct 2023 13:59:45 +0200 +Subject: x86/microcode/intel: Switch to kvmalloc() + +From: Thomas Gleixner + +commit f24f204405f9875bc539c6e88553fd5ac913c867 upstream + +Microcode blobs are getting larger and might soon reach the kmalloc() +limit. Switch over kvmalloc(). + +Signed-off-by: Thomas Gleixner +Signed-off-by: Borislav Petkov (AMD) +Link: https://lore.kernel.org/r/20231002115902.564323243@linutronix.de +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/cpu/microcode/intel.c | 48 +++++++++++++++++----------------- + 1 file changed, 25 insertions(+), 23 deletions(-) + +--- a/arch/x86/kernel/cpu/microcode/intel.c ++++ b/arch/x86/kernel/cpu/microcode/intel.c +@@ -14,7 +14,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -245,7 +244,7 @@ EXPORT_SYMBOL_GPL(intel_microcode_sanity + + static void update_ucode_pointer(struct microcode_intel *mc) + { +- kfree(ucode_patch_va); ++ kvfree(ucode_patch_va); + + /* + * Save the virtual address for early loading and for eventual free +@@ -256,11 +255,14 @@ static void update_ucode_pointer(struct + + static void save_microcode_patch(struct microcode_intel *patch) + { ++ unsigned int size = get_totalsize(&patch->hdr); + struct microcode_intel *mc; + +- mc = kmemdup(patch, get_totalsize(&patch->hdr), GFP_KERNEL); ++ mc = kvmemdup(patch, size, GFP_KERNEL); + if (mc) + update_ucode_pointer(mc); ++ else ++ pr_err("Unable to allocate microcode memory size: %u\n", size); + } + + /* Scan blob for microcode matching the boot CPUs family, model, stepping */ +@@ -539,36 +541,34 @@ static enum ucode_state parse_microcode_ + + if (!copy_from_iter_full(&mc_header, sizeof(mc_header), iter)) { + pr_err("error! Truncated or inaccessible header in microcode data file\n"); +- break; ++ goto fail; + } + + mc_size = get_totalsize(&mc_header); + if (mc_size < sizeof(mc_header)) { + pr_err("error! Bad data in microcode data file (totalsize too small)\n"); +- break; ++ goto fail; + } +- + data_size = mc_size - sizeof(mc_header); + if (data_size > iov_iter_count(iter)) { + pr_err("error! Bad data in microcode data file (truncated file?)\n"); +- break; ++ goto fail; + } + + /* For performance reasons, reuse mc area when possible */ + if (!mc || mc_size > curr_mc_size) { +- vfree(mc); +- mc = vmalloc(mc_size); ++ kvfree(mc); ++ mc = kvmalloc(mc_size, GFP_KERNEL); + if (!mc) +- break; ++ goto fail; + curr_mc_size = mc_size; + } + + memcpy(mc, &mc_header, sizeof(mc_header)); + data = mc + sizeof(mc_header); + if (!copy_from_iter_full(data, data_size, iter) || +- intel_microcode_sanity_check(mc, true, MC_HEADER_TYPE_MICROCODE) < 0) { +- break; +- } ++ intel_microcode_sanity_check(mc, true, MC_HEADER_TYPE_MICROCODE) < 0) ++ goto fail; + + if (cur_rev >= mc_header.rev) + continue; +@@ -576,24 +576,26 @@ static enum ucode_state parse_microcode_ + if (!intel_find_matching_signature(mc, uci->cpu_sig.sig, uci->cpu_sig.pf)) + continue; + +- vfree(new_mc); ++ kvfree(new_mc); + cur_rev = mc_header.rev; + new_mc = mc; + mc = NULL; + } + +- vfree(mc); +- +- if (iov_iter_count(iter)) { +- vfree(new_mc); +- return UCODE_ERROR; +- } ++ if (iov_iter_count(iter)) ++ goto fail; + ++ kvfree(mc); + if (!new_mc) + return UCODE_NFOUND; + + ucode_patch_late = (struct microcode_intel *)new_mc; + return UCODE_NEW; ++ ++fail: ++ kvfree(mc); ++ kvfree(new_mc); ++ return UCODE_ERROR; + } + + static bool is_blacklisted(unsigned int cpu) +@@ -652,9 +654,9 @@ static enum ucode_state request_microcod + static void finalize_late_load(int result) + { + if (!result) +- save_microcode_patch(ucode_patch_late); +- +- vfree(ucode_patch_late); ++ update_ucode_pointer(ucode_patch_late); ++ else ++ kvfree(ucode_patch_late); + ucode_patch_late = NULL; + } + diff --git a/queue-6.6/x86-microcode-intel-unify-microcode-apply-functions.patch b/queue-6.6/x86-microcode-intel-unify-microcode-apply-functions.patch new file mode 100644 index 0000000000..1652b9bcaa --- /dev/null +++ b/queue-6.6/x86-microcode-intel-unify-microcode-apply-functions.patch @@ -0,0 +1,183 @@ +From 661c46050f078216190d6137423d04a49bfe44ae Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Tue, 17 Oct 2023 23:23:44 +0200 +Subject: x86/microcode/intel: Unify microcode apply() functions + +From: Thomas Gleixner + +commit 3973718cff1e3a5d88ea78ec28ecca2afa60b30b upstream + +Deduplicate the early and late apply() functions. + + [ bp: Rename the function which does the actual application to + __apply_microcode() to differentiate it from + microcode_ops.apply_microcode(). ] + +Signed-off-by: Borislav Petkov (AMD) +Signed-off-by: Thomas Gleixner +Link: https://lore.kernel.org/r/20231017211722.795508212@linutronix.de +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/cpu/microcode/intel.c | 106 +++++++++++----------------------- + 1 file changed, 37 insertions(+), 69 deletions(-) + +--- a/arch/x86/kernel/cpu/microcode/intel.c ++++ b/arch/x86/kernel/cpu/microcode/intel.c +@@ -307,12 +307,12 @@ static __init struct microcode_intel *sc + return size ? NULL : patch; + } + +-static enum ucode_state apply_microcode_early(struct ucode_cpu_info *uci) ++static enum ucode_state __apply_microcode(struct ucode_cpu_info *uci, ++ struct microcode_intel *mc, ++ u32 *cur_rev) + { +- struct microcode_intel *mc; +- u32 rev, old_rev, date; ++ u32 rev; + +- mc = uci->mc; + if (!mc) + return UCODE_NFOUND; + +@@ -321,14 +321,12 @@ static enum ucode_state apply_microcode_ + * operation - when the other hyperthread has updated the microcode + * already. + */ +- rev = intel_get_microcode_revision(); +- if (rev >= mc->hdr.rev) { +- uci->cpu_sig.rev = rev; ++ *cur_rev = intel_get_microcode_revision(); ++ if (*cur_rev >= mc->hdr.rev) { ++ uci->cpu_sig.rev = *cur_rev; + return UCODE_OK; + } + +- old_rev = rev; +- + /* + * Writeback and invalidate caches before updating microcode to avoid + * internal issues depending on what the microcode is updating. +@@ -343,13 +341,24 @@ static enum ucode_state apply_microcode_ + return UCODE_ERROR; + + uci->cpu_sig.rev = rev; +- +- date = mc->hdr.date; +- pr_info_once("updated early: 0x%x -> 0x%x, date = %04x-%02x-%02x\n", +- old_rev, rev, date & 0xffff, date >> 24, (date >> 16) & 0xff); + return UCODE_UPDATED; + } + ++static enum ucode_state apply_microcode_early(struct ucode_cpu_info *uci) ++{ ++ struct microcode_intel *mc = uci->mc; ++ enum ucode_state ret; ++ u32 cur_rev, date; ++ ++ ret = __apply_microcode(uci, mc, &cur_rev); ++ if (ret == UCODE_UPDATED) { ++ date = mc->hdr.date; ++ pr_info_once("updated early: 0x%x -> 0x%x, date = %04x-%02x-%02x\n", ++ cur_rev, mc->hdr.rev, date & 0xffff, date >> 24, (date >> 16) & 0xff); ++ } ++ return ret; ++} ++ + static __init bool load_builtin_intel_microcode(struct cpio_data *cp) + { + unsigned int eax = 1, ebx, ecx = 0, edx; +@@ -459,70 +468,29 @@ static int collect_cpu_info(int cpu_num, + return 0; + } + +-static enum ucode_state apply_microcode_intel(int cpu) ++static enum ucode_state apply_microcode_late(int cpu) + { + struct ucode_cpu_info *uci = ucode_cpu_info + cpu; +- struct cpuinfo_x86 *c = &cpu_data(cpu); +- bool bsp = c->cpu_index == boot_cpu_data.cpu_index; +- struct microcode_intel *mc; ++ struct microcode_intel *mc = ucode_patch_late; + enum ucode_state ret; +- static int prev_rev; +- u32 rev; +- +- /* We should bind the task to the CPU */ +- if (WARN_ON(raw_smp_processor_id() != cpu)) +- return UCODE_ERROR; +- +- mc = ucode_patch_late; +- if (!mc) +- return UCODE_NFOUND; +- +- /* +- * Save us the MSR write below - which is a particular expensive +- * operation - when the other hyperthread has updated the microcode +- * already. +- */ +- rev = intel_get_microcode_revision(); +- if (rev >= mc->hdr.rev) { +- ret = UCODE_OK; +- goto out; +- } ++ u32 cur_rev; + +- /* +- * Writeback and invalidate caches before updating microcode to avoid +- * internal issues depending on what the microcode is updating. +- */ +- native_wbinvd(); +- +- /* write microcode via MSR 0x79 */ +- wrmsrl(MSR_IA32_UCODE_WRITE, (unsigned long)mc->bits); +- +- rev = intel_get_microcode_revision(); +- +- if (rev != mc->hdr.rev) { +- pr_err("CPU%d update to revision 0x%x failed\n", +- cpu, mc->hdr.rev); ++ if (WARN_ON_ONCE(smp_processor_id() != cpu)) + return UCODE_ERROR; +- } + +- if (bsp && rev != prev_rev) { +- pr_info("updated to revision 0x%x, date = %04x-%02x-%02x\n", +- rev, +- mc->hdr.date & 0xffff, +- mc->hdr.date >> 24, ++ ret = __apply_microcode(uci, mc, &cur_rev); ++ if (ret != UCODE_UPDATED && ret != UCODE_OK) ++ return ret; ++ ++ if (!cpu && uci->cpu_sig.rev != cur_rev) { ++ pr_info("Updated to revision 0x%x, date = %04x-%02x-%02x\n", ++ uci->cpu_sig.rev, mc->hdr.date & 0xffff, mc->hdr.date >> 24, + (mc->hdr.date >> 16) & 0xff); +- prev_rev = rev; + } + +- ret = UCODE_UPDATED; +- +-out: +- uci->cpu_sig.rev = rev; +- c->microcode = rev; +- +- /* Update boot_cpu_data's revision too, if we're on the BSP: */ +- if (bsp) +- boot_cpu_data.microcode = rev; ++ cpu_data(cpu).microcode = uci->cpu_sig.rev; ++ if (!cpu) ++ boot_cpu_data.microcode = uci->cpu_sig.rev; + + return ret; + } +@@ -663,7 +631,7 @@ static void finalize_late_load(int resul + static struct microcode_ops microcode_intel_ops = { + .request_microcode_fw = request_microcode_fw, + .collect_cpu_info = collect_cpu_info, +- .apply_microcode = apply_microcode_intel, ++ .apply_microcode = apply_microcode_late, + .finalize_late_load = finalize_late_load, + }; + diff --git a/queue-6.6/x86-microcode-mop-up-early-loading-leftovers.patch b/queue-6.6/x86-microcode-mop-up-early-loading-leftovers.patch new file mode 100644 index 0000000000..09de080844 --- /dev/null +++ b/queue-6.6/x86-microcode-mop-up-early-loading-leftovers.patch @@ -0,0 +1,75 @@ +From 3f7517298aa0e62866887bff84df0ae84cec2b96 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Tue, 17 Oct 2023 23:23:56 +0200 +Subject: x86/microcode: Mop up early loading leftovers + +From: Thomas Gleixner + +commit 8529e8ab6c6fab8ebf06ead98e77d7646b42fc48 upstream + +Get rid of the initrd_gone hack which was required to keep +find_microcode_in_initrd() functional after init. + +As find_microcode_in_initrd() is now only used during init, mark it +accordingly. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Borislav Petkov (AMD) +Link: https://lore.kernel.org/r/20231017211723.298854846@linutronix.de +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/cpu/microcode/core.c | 17 +---------------- + arch/x86/kernel/cpu/microcode/internal.h | 1 - + 2 files changed, 1 insertion(+), 17 deletions(-) + +--- a/arch/x86/kernel/cpu/microcode/core.c ++++ b/arch/x86/kernel/cpu/microcode/core.c +@@ -44,8 +44,6 @@ + static struct microcode_ops *microcode_ops; + bool dis_ucode_ldr = true; + +-bool initrd_gone; +- + /* + * Synchronization. + * +@@ -180,15 +178,7 @@ void load_ucode_ap(void) + } + } + +-/* Temporary workaround until find_microcode_in_initrd() is __init */ +-static int __init mark_initrd_gone(void) +-{ +- initrd_gone = true; +- return 0; +-} +-fs_initcall(mark_initrd_gone); +- +-struct cpio_data find_microcode_in_initrd(const char *path) ++struct cpio_data __init find_microcode_in_initrd(const char *path) + { + #ifdef CONFIG_BLK_DEV_INITRD + unsigned long start = 0; +@@ -216,12 +206,7 @@ struct cpio_data find_microcode_in_initr + * 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. +- * +- * initrd_gone is for the hotplug case where we've thrown out initrd +- * already. + */ +- if (initrd_gone) +- return (struct cpio_data){ NULL, 0, "" }; + if (initrd_start) + start = initrd_start; + +--- a/arch/x86/kernel/cpu/microcode/internal.h ++++ b/arch/x86/kernel/cpu/microcode/internal.h +@@ -86,7 +86,6 @@ static inline unsigned int x86_cpuid_fam + } + + extern bool dis_ucode_ldr; +-extern bool initrd_gone; + + #ifdef CONFIG_CPU_SUP_AMD + void load_ucode_amd_bsp(unsigned int family); diff --git a/queue-6.6/x86-microcode-prepare-for-minimal-revision-check.patch b/queue-6.6/x86-microcode-prepare-for-minimal-revision-check.patch new file mode 100644 index 0000000000..11699ef216 --- /dev/null +++ b/queue-6.6/x86-microcode-prepare-for-minimal-revision-check.patch @@ -0,0 +1,184 @@ +From 1aa144827ab0a7f4c1f30ac972f4ec66f079afb3 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Tue, 17 Oct 2023 23:24:16 +0200 +Subject: x86/microcode: Prepare for minimal revision check + +From: Thomas Gleixner + +commit 9407bda845dd19756e276d4f3abc15a20777ba45 upstream + +Applying microcode late can be fatal for the running kernel when the +update changes functionality which is in use already in a non-compatible +way, e.g. by removing a CPUID bit. + +There is no way for admins which do not have access to the vendors deep +technical support to decide whether late loading of such a microcode is +safe or not. + +Intel has added a new field to the microcode header which tells the +minimal microcode revision which is required to be active in the CPU in +order to be safe. + +Provide infrastructure for handling this in the core code and a command +line switch which allows to enforce it. + +If the update is considered safe the kernel is not tainted and the annoying +warning message not emitted. If it's enforced and the currently loaded +microcode revision is not safe for late loading then the load is aborted. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Borislav Petkov (AMD) +Link: https://lore.kernel.org/r/20231017211724.079611170@linutronix.de +Signed-off-by: Greg Kroah-Hartman +--- + Documentation/admin-guide/kernel-parameters.txt | 5 +++++ + arch/x86/Kconfig | 23 ++++++++++++++++++++++- + arch/x86/kernel/cpu/microcode/amd.c | 3 +++ + arch/x86/kernel/cpu/microcode/core.c | 19 ++++++++++++++----- + arch/x86/kernel/cpu/microcode/intel.c | 3 +++ + arch/x86/kernel/cpu/microcode/internal.h | 2 ++ + 6 files changed, 49 insertions(+), 6 deletions(-) + +--- a/Documentation/admin-guide/kernel-parameters.txt ++++ b/Documentation/admin-guide/kernel-parameters.txt +@@ -3287,6 +3287,11 @@ + + mga= [HW,DRM] + ++ microcode.force_minrev= [X86] ++ Format: ++ Enable or disable the microcode minimal revision ++ enforcement for the runtime microcode loader. ++ + min_addr=nn[KMG] [KNL,BOOT,IA-64] All physical memory below this + physical address is ignored. + +--- a/arch/x86/Kconfig ++++ b/arch/x86/Kconfig +@@ -1323,7 +1323,28 @@ config MICROCODE_LATE_LOADING + is a tricky business and should be avoided if possible. Just the sequence + of synchronizing all cores and SMT threads is one fragile dance which does + not guarantee that cores might not softlock after the loading. Therefore, +- use this at your own risk. Late loading taints the kernel too. ++ use this at your own risk. Late loading taints the kernel unless the ++ microcode header indicates that it is safe for late loading via the ++ minimal revision check. This minimal revision check can be enforced on ++ the kernel command line with "microcode.minrev=Y". ++ ++config MICROCODE_LATE_FORCE_MINREV ++ bool "Enforce late microcode loading minimal revision check" ++ default n ++ depends on MICROCODE_LATE_LOADING ++ help ++ To prevent that users load microcode late which modifies already ++ in use features, newer microcode patches have a minimum revision field ++ in the microcode header, which tells the kernel which minimum ++ revision must be active in the CPU to safely load that new microcode ++ late into the running system. If disabled the check will not ++ be enforced but the kernel will be tainted when the minimal ++ revision check fails. ++ ++ This minimal revision check can also be controlled via the ++ "microcode.minrev" parameter on the kernel command line. ++ ++ If unsure say Y. + + config X86_MSR + tristate "/dev/cpu/*/msr - Model-specific register support" +--- a/arch/x86/kernel/cpu/microcode/amd.c ++++ b/arch/x86/kernel/cpu/microcode/amd.c +@@ -888,6 +888,9 @@ static enum ucode_state request_microcod + enum ucode_state ret = UCODE_NFOUND; + const struct firmware *fw; + ++ if (force_minrev) ++ return UCODE_NFOUND; ++ + if (c->x86 >= 0x15) + snprintf(fw_name, sizeof(fw_name), "amd-ucode/microcode_amd_fam%.2xh.bin", c->x86); + +--- a/arch/x86/kernel/cpu/microcode/core.c ++++ b/arch/x86/kernel/cpu/microcode/core.c +@@ -46,6 +46,9 @@ + 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. + * +@@ -531,15 +534,17 @@ static int load_cpus_stopped(void *unuse + return 0; + } + +-static int load_late_stop_cpus(void) ++static int load_late_stop_cpus(bool is_safe) + { + unsigned int cpu, updated = 0, failed = 0, timedout = 0, siblings = 0; + unsigned int nr_offl, offline = 0; + int old_rev = boot_cpu_data.microcode; + struct cpuinfo_x86 prev_info; + +- pr_err("Attempting late microcode loading - it is dangerous and taints the kernel.\n"); +- pr_err("You should switch to early loading, if possible.\n"); ++ if (!is_safe) { ++ pr_err("Late microcode loading without minimal revision check.\n"); ++ pr_err("You should switch to early loading, if possible.\n"); ++ } + + atomic_set(&late_cpus_in, num_online_cpus()); + atomic_set(&offline_in_nmi, 0); +@@ -589,7 +594,9 @@ static int load_late_stop_cpus(void) + return -EIO; + } + +- add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK); ++ if (!is_safe || failed || timedout) ++ add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK); ++ + pr_info("load: updated on %u primary CPUs with %u siblings\n", updated, siblings); + if (failed || timedout) { + pr_err("load incomplete. %u CPUs timed out or failed\n", +@@ -679,7 +686,9 @@ static int load_late_locked(void) + + switch (microcode_ops->request_microcode_fw(0, µcode_pdev->dev)) { + case UCODE_NEW: +- return load_late_stop_cpus(); ++ return load_late_stop_cpus(false); ++ case UCODE_NEW_SAFE: ++ return load_late_stop_cpus(true); + case UCODE_NFOUND: + return -ENOENT; + default: +--- a/arch/x86/kernel/cpu/microcode/intel.c ++++ b/arch/x86/kernel/cpu/microcode/intel.c +@@ -480,6 +480,9 @@ static enum ucode_state parse_microcode_ + unsigned int curr_mc_size = 0; + u8 *new_mc = NULL, *mc = NULL; + ++ if (force_minrev) ++ return UCODE_NFOUND; ++ + while (iov_iter_count(iter)) { + struct microcode_header_intel mc_header; + unsigned int mc_size, data_size; +--- a/arch/x86/kernel/cpu/microcode/internal.h ++++ b/arch/x86/kernel/cpu/microcode/internal.h +@@ -13,6 +13,7 @@ struct device; + enum ucode_state { + UCODE_OK = 0, + UCODE_NEW, ++ UCODE_NEW_SAFE, + UCODE_UPDATED, + UCODE_NFOUND, + UCODE_ERROR, +@@ -88,6 +89,7 @@ static inline unsigned int x86_cpuid_fam + } + + extern bool dis_ucode_ldr; ++extern bool force_minrev; + + #ifdef CONFIG_CPU_SUP_AMD + void load_ucode_amd_bsp(unsigned int family); diff --git a/queue-6.6/x86-microcode-protect-against-instrumentation.patch b/queue-6.6/x86-microcode-protect-against-instrumentation.patch new file mode 100644 index 0000000000..81c0e0ee49 --- /dev/null +++ b/queue-6.6/x86-microcode-protect-against-instrumentation.patch @@ -0,0 +1,213 @@ +From 27c67e37da3074932dc5811ec05c30fdeaab8939 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Mon, 2 Oct 2023 14:00:06 +0200 +Subject: x86/microcode: Protect against instrumentation + +From: Thomas Gleixner + +commit 1582c0f4a21303792f523fe2839dd8433ee630c0 upstream + +The wait for control loop in which the siblings are waiting for the +microcode update on the primary thread must be protected against +instrumentation as instrumentation can end up in #INT3, #DB or #PF, +which then returns with IRET. That IRET reenables NMI which is the +opposite of what the NMI rendezvous is trying to achieve. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Borislav Petkov (AMD) +Link: https://lore.kernel.org/r/20231002115903.545969323@linutronix.de +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/cpu/microcode/core.c | 111 ++++++++++++++++++++++++++--------- + 1 file changed, 83 insertions(+), 28 deletions(-) + +--- a/arch/x86/kernel/cpu/microcode/core.c ++++ b/arch/x86/kernel/cpu/microcode/core.c +@@ -272,54 +272,65 @@ struct microcode_ctrl { + + DEFINE_STATIC_KEY_FALSE(microcode_nmi_handler_enable); + static DEFINE_PER_CPU(struct microcode_ctrl, ucode_ctrl); ++static unsigned int loops_per_usec; + static atomic_t late_cpus_in; + +-static bool wait_for_cpus(atomic_t *cnt) ++static noinstr bool wait_for_cpus(atomic_t *cnt) + { +- unsigned int timeout; ++ unsigned int timeout, loops; + +- WARN_ON_ONCE(atomic_dec_return(cnt) < 0); ++ WARN_ON_ONCE(raw_atomic_dec_return(cnt) < 0); + + for (timeout = 0; timeout < USEC_PER_SEC; timeout++) { +- if (!atomic_read(cnt)) ++ if (!raw_atomic_read(cnt)) + return true; + +- udelay(1); ++ 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)) ++ 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 */ +- atomic_inc(cnt); ++ raw_atomic_inc(cnt); + return false; + } + +-static bool wait_for_ctrl(void) ++static noinstr bool wait_for_ctrl(void) + { +- unsigned int timeout; ++ unsigned int timeout, loops; + + for (timeout = 0; timeout < USEC_PER_SEC; timeout++) { +- if (this_cpu_read(ucode_ctrl.ctrl) != SCTRL_WAIT) ++ if (raw_cpu_read(ucode_ctrl.ctrl) != SCTRL_WAIT) + return true; +- udelay(1); ++ ++ for (loops = 0; loops < loops_per_usec; loops++) ++ cpu_relax(); ++ + /* If invoked directly, tickle the NMI watchdog */ +- if (!microcode_ops->use_nmi && !(timeout % 1000)) ++ if (!microcode_ops->use_nmi && !(timeout % USEC_PER_MSEC)) { ++ instrumentation_begin(); + touch_nmi_watchdog(); ++ instrumentation_end(); ++ } + } + return false; + } + +-static void load_secondary(unsigned int cpu) ++/* ++ * 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) + { +- unsigned int ctrl_cpu = this_cpu_read(ucode_ctrl.ctrl_cpu); +- enum ucode_state ret; +- + /* Initial rendezvous to ensure that all CPUs have arrived */ + if (!wait_for_cpus(&late_cpus_in)) { +- pr_err_once("load: %d CPUs timed out\n", atomic_read(&late_cpus_in) - 1); +- this_cpu_write(ucode_ctrl.result, UCODE_TIMEOUT); +- return; ++ raw_cpu_write(ucode_ctrl.result, UCODE_TIMEOUT); ++ return false; + } + + /* +@@ -329,9 +340,33 @@ static void load_secondary(unsigned int + * scheduler, watchdogs etc. There is no way to safely evacuate the + * machine. + */ +- if (!wait_for_ctrl()) +- panic("Microcode load: Primary CPU %d timed out\n", ctrl_cpu); ++ 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. +@@ -343,6 +378,7 @@ static void load_secondary(unsigned int + + this_cpu_write(ucode_ctrl.result, ret); + this_cpu_write(ucode_ctrl.ctrl, SCTRL_DONE); ++ instrumentation_end(); + } + + static void load_primary(unsigned int cpu) +@@ -380,25 +416,43 @@ static void load_primary(unsigned int cp + } + } + +-static bool microcode_update_handler(void) ++static noinstr bool microcode_update_handler(void) + { +- unsigned int cpu = smp_processor_id(); ++ unsigned int cpu = raw_smp_processor_id(); + +- if (this_cpu_read(ucode_ctrl.ctrl_cpu) == cpu) ++ if (raw_cpu_read(ucode_ctrl.ctrl_cpu) == cpu) { ++ instrumentation_begin(); + load_primary(cpu); +- else ++ instrumentation_end(); ++ } else { + load_secondary(cpu); ++ } + ++ instrumentation_begin(); + touch_nmi_watchdog(); ++ instrumentation_end(); ++ + return true; + } + +-bool microcode_nmi_handler(void) ++/* ++ * Protection against instrumentation is required for CPUs which are not ++ * safe against an NMI which is delivered to the secondary SMT sibling ++ * while the primary thread updates the microcode. Instrumentation can end ++ * up in #INT3, #DB and #PF. The IRET from those exceptions reenables NMI ++ * which is the opposite of what the NMI rendezvous is trying to achieve. ++ * ++ * The primary thread is safe versus instrumentation as the actual ++ * microcode update handles this correctly. It's only the sibling code ++ * path which must be NMI safe until the primary thread completed the ++ * update. ++ */ ++bool noinstr microcode_nmi_handler(void) + { +- if (!this_cpu_read(ucode_ctrl.nmi_enabled)) ++ if (!raw_cpu_read(ucode_ctrl.nmi_enabled)) + return false; + +- this_cpu_write(ucode_ctrl.nmi_enabled, false); ++ raw_cpu_write(ucode_ctrl.nmi_enabled, false); + return microcode_update_handler(); + } + +@@ -425,6 +479,7 @@ static int load_late_stop_cpus(void) + pr_err("You should switch to early loading, if possible.\n"); + + atomic_set(&late_cpus_in, num_online_cpus()); ++ loops_per_usec = loops_per_jiffy / (TICK_NSEC / 1000); + + /* + * Take a snapshot before the microcode update in order to compare and diff --git a/queue-6.6/x86-microcode-provide-new-control-functions.patch b/queue-6.6/x86-microcode-provide-new-control-functions.patch new file mode 100644 index 0000000000..25309ee939 --- /dev/null +++ b/queue-6.6/x86-microcode-provide-new-control-functions.patch @@ -0,0 +1,127 @@ +From 284ad8d909ac86b325f5e3a4798e90df4af30d8c Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Mon, 2 Oct 2023 14:00:02 +0200 +Subject: x86/microcode: Provide new control functions + +From: Thomas Gleixner + +commit 6067788f04b1020b316344fe34746f96d594a042 upstream + +The current all in one code is unreadable and really not suited for +adding future features like uniform loading with package or system +scope. + +Provide a set of new control functions which split the handling of the +primary and secondary CPUs. These will replace the current rendezvous +all in one function in the next step. This is intentionally a separate +change because diff makes an complete unreadable mess otherwise. + +So the flow separates the primary and the secondary CPUs into their own +functions which use the control field in the per CPU ucode_ctrl struct. + + primary() secondary() + wait_for_all() wait_for_all() + apply_ucode() wait_for_release() + release() apply_ucode() + +Signed-off-by: Thomas Gleixner +Signed-off-by: Borislav Petkov (AMD) +Link: https://lore.kernel.org/r/20231002115903.377922731@linutronix.de +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/cpu/microcode/core.c | 84 +++++++++++++++++++++++++++++++++++ + 1 file changed, 84 insertions(+) + +--- a/arch/x86/kernel/cpu/microcode/core.c ++++ b/arch/x86/kernel/cpu/microcode/core.c +@@ -290,6 +290,90 @@ static bool wait_for_cpus(atomic_t *cnt) + return false; + } + ++static bool wait_for_ctrl(void) ++{ ++ unsigned int timeout; ++ ++ for (timeout = 0; timeout < USEC_PER_SEC; timeout++) { ++ if (this_cpu_read(ucode_ctrl.ctrl) != SCTRL_WAIT) ++ return true; ++ udelay(1); ++ if (!(timeout % 1000)) ++ touch_nmi_watchdog(); ++ } ++ return false; ++} ++ ++static __maybe_unused void load_secondary(unsigned int cpu) ++{ ++ unsigned int ctrl_cpu = this_cpu_read(ucode_ctrl.ctrl_cpu); ++ enum ucode_state ret; ++ ++ /* Initial rendezvous to ensure that all CPUs have arrived */ ++ if (!wait_for_cpus(&late_cpus_in)) { ++ pr_err_once("load: %d CPUs timed out\n", atomic_read(&late_cpus_in) - 1); ++ this_cpu_write(ucode_ctrl.result, UCODE_TIMEOUT); ++ return; ++ } ++ ++ /* ++ * 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()) ++ panic("Microcode load: Primary CPU %d timed out\n", ctrl_cpu); ++ ++ /* ++ * 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); ++} ++ ++static __maybe_unused 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 int load_cpus_stopped(void *unused) + { + int cpu = smp_processor_id(); diff --git a/queue-6.6/x86-microcode-remove-pointless-apply-invocation.patch b/queue-6.6/x86-microcode-remove-pointless-apply-invocation.patch new file mode 100644 index 0000000000..98a0468679 --- /dev/null +++ b/queue-6.6/x86-microcode-remove-pointless-apply-invocation.patch @@ -0,0 +1,91 @@ +From bcdf3a18c00f084fe58ca11dc7c2e58c7ee1ae49 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Tue, 17 Oct 2023 23:23:49 +0200 +Subject: x86/microcode: Remove pointless apply() invocation + +From: Thomas Gleixner + +commit b48b26f992a3828b4ae274669f99ce68451d4904 upstream + +Microcode is applied on the APs during early bringup. There is no point +in trying to apply the microcode again during the hotplug operations and +neither at the point where the microcode device is initialized. + +Collect CPU info and microcode revision in setup_online_cpu() for now. +This will move to the CPU hotplug callback later. + + [ bp: Leave the starting notifier for the following scenario: + + - boot, late load, suspend to disk, resume + + without the starting notifier, only the last core manages to update the + microcode upon resume: + + # rdmsr -a 0x8b + 10000bf + 10000bf + 10000bf + 10000bf + 10000bf + 10000dc <---- + + This is on an AMD F10h machine. + + For the future, one should check whether potential unification of + the CPU init path could cover the resume path too so that this can + be simplified even more. + + tglx: This is caused by the odd handling of APs which try to find the + microcode blob in builtin or initrd instead of caching the microcode + blob during early init before the APs are brought up. Will be cleaned + up in a later step. ] + +Signed-off-by: Borislav Petkov (AMD) +Signed-off-by: Thomas Gleixner +Link: https://lore.kernel.org/r/20231017211723.018821624@linutronix.de +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/cpu/microcode/core.c | 23 ++++++----------------- + 1 file changed, 6 insertions(+), 17 deletions(-) + +--- a/arch/x86/kernel/cpu/microcode/core.c ++++ b/arch/x86/kernel/cpu/microcode/core.c +@@ -493,17 +493,6 @@ static void microcode_fini_cpu(int cpu) + microcode_ops->microcode_fini_cpu(cpu); + } + +-static enum ucode_state microcode_init_cpu(int cpu) +-{ +- struct ucode_cpu_info *uci = ucode_cpu_info + cpu; +- +- memset(uci, 0, sizeof(*uci)); +- +- microcode_ops->collect_cpu_info(cpu, &uci->cpu_sig); +- +- return microcode_ops->apply_microcode(cpu); +-} +- + /** + * microcode_bsp_resume - Update boot CPU microcode during resume. + */ +@@ -558,14 +547,14 @@ static int mc_cpu_down_prep(unsigned int + static void setup_online_cpu(struct work_struct *work) + { + int cpu = smp_processor_id(); +- enum ucode_state err; ++ struct ucode_cpu_info *uci = ucode_cpu_info + cpu; + +- err = microcode_init_cpu(cpu); +- if (err == UCODE_ERROR) { +- pr_err("Error applying microcode on CPU%d\n", cpu); +- return; +- } ++ memset(uci, 0, sizeof(*uci)); + ++ microcode_ops->collect_cpu_info(cpu, &uci->cpu_sig); ++ cpu_data(cpu).microcode = uci->cpu_sig.rev; ++ if (!cpu) ++ boot_cpu_data.microcode = uci->cpu_sig.rev; + mc_cpu_online(cpu); + } + diff --git a/queue-6.6/x86-microcode-rendezvous-and-load-in-nmi.patch b/queue-6.6/x86-microcode-rendezvous-and-load-in-nmi.patch new file mode 100644 index 0000000000..1f150c9191 --- /dev/null +++ b/queue-6.6/x86-microcode-rendezvous-and-load-in-nmi.patch @@ -0,0 +1,210 @@ +From 1b3dbb4473d085a7845d6348b8838c4796dde230 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Mon, 2 Oct 2023 14:00:05 +0200 +Subject: x86/microcode: Rendezvous and load in NMI + +From: Thomas Gleixner + +commit 7eb314a22800457396f541c655697dabd71e44a7 upstream + +stop_machine() does not prevent the spin-waiting sibling from handling +an NMI, which is obviously violating the whole concept of rendezvous. + +Implement a static branch right in the beginning of the NMI handler +which is nopped out except when enabled by the late loading mechanism. + +The late loader enables the static branch before stop_machine() is +invoked. Each CPU has an nmi_enable in its control structure which +indicates whether the CPU should go into the update routine. + +This is required to bridge the gap between enabling the branch and +actually being at the point where it is required to enter the loader +wait loop. + +Each CPU which arrives in the stopper thread function sets that flag and +issues a self NMI right after that. If the NMI function sees the flag +clear, it returns. If it's set it clears the flag and enters the +rendezvous. + +This is safe against a real NMI which hits in between setting the flag +and sending the NMI to itself. The real NMI will be swallowed by the +microcode update and the self NMI will then let stuff continue. +Otherwise this would end up with a spurious NMI. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Borislav Petkov (AMD) +Link: https://lore.kernel.org/r/20231002115903.489900814@linutronix.de +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/include/asm/microcode.h | 12 ++++++++ + arch/x86/kernel/cpu/microcode/core.c | 42 ++++++++++++++++++++++++++++--- + arch/x86/kernel/cpu/microcode/intel.c | 1 + arch/x86/kernel/cpu/microcode/internal.h | 3 +- + arch/x86/kernel/nmi.c | 4 ++ + 5 files changed, 57 insertions(+), 5 deletions(-) + +--- a/arch/x86/include/asm/microcode.h ++++ b/arch/x86/include/asm/microcode.h +@@ -70,4 +70,16 @@ static inline u32 intel_get_microcode_re + } + #endif /* !CONFIG_CPU_SUP_INTEL */ + ++bool microcode_nmi_handler(void); ++ ++#ifdef CONFIG_MICROCODE_LATE_LOADING ++DECLARE_STATIC_KEY_FALSE(microcode_nmi_handler_enable); ++static __always_inline bool microcode_nmi_handler_enabled(void) ++{ ++ return static_branch_unlikely(µcode_nmi_handler_enable); ++} ++#else ++static __always_inline bool microcode_nmi_handler_enabled(void) { return false; } ++#endif ++ + #endif /* _ASM_X86_MICROCODE_H */ +--- a/arch/x86/kernel/cpu/microcode/core.c ++++ b/arch/x86/kernel/cpu/microcode/core.c +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -31,6 +32,7 @@ + #include + #include + ++#include + #include + #include + #include +@@ -265,8 +267,10 @@ 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; + +@@ -282,7 +286,8 @@ static bool wait_for_cpus(atomic_t *cnt) + + udelay(1); + +- if (!(timeout % USEC_PER_MSEC)) ++ /* If invoked directly, tickle the NMI watchdog */ ++ if (!microcode_ops->use_nmi && !(timeout % USEC_PER_MSEC)) + touch_nmi_watchdog(); + } + /* Prevent the late comers from making progress and let them time out */ +@@ -298,7 +303,8 @@ static bool wait_for_ctrl(void) + if (this_cpu_read(ucode_ctrl.ctrl) != SCTRL_WAIT) + return true; + udelay(1); +- if (!(timeout % 1000)) ++ /* If invoked directly, tickle the NMI watchdog */ ++ if (!microcode_ops->use_nmi && !(timeout % 1000)) + touch_nmi_watchdog(); + } + return false; +@@ -374,7 +380,7 @@ static void load_primary(unsigned int cp + } + } + +-static int load_cpus_stopped(void *unused) ++static bool microcode_update_handler(void) + { + unsigned int cpu = smp_processor_id(); + +@@ -383,7 +389,29 @@ static int load_cpus_stopped(void *unuse + else + load_secondary(cpu); + +- /* No point to wait here. The CPUs will all wait in stop_machine(). */ ++ touch_nmi_watchdog(); ++ return true; ++} ++ ++bool microcode_nmi_handler(void) ++{ ++ if (!this_cpu_read(ucode_ctrl.nmi_enabled)) ++ return false; ++ ++ this_cpu_write(ucode_ctrl.nmi_enabled, false); ++ return microcode_update_handler(); ++} ++ ++static int load_cpus_stopped(void *unused) ++{ ++ if (microcode_ops->use_nmi) { ++ /* Enable the NMI handler and raise NMI */ ++ this_cpu_write(ucode_ctrl.nmi_enabled, true); ++ apic->send_IPI(smp_processor_id(), NMI_VECTOR); ++ } else { ++ /* Just invoke the handler directly */ ++ microcode_update_handler(); ++ } + return 0; + } + +@@ -404,8 +432,14 @@ static int load_late_stop_cpus(void) + */ + store_cpu_caps(&prev_info); + ++ if (microcode_ops->use_nmi) ++ static_branch_enable_cpuslocked(µcode_nmi_handler_enable); ++ + stop_machine_cpuslocked(load_cpus_stopped, NULL, cpu_online_mask); + ++ if (microcode_ops->use_nmi) ++ static_branch_disable_cpuslocked(µcode_nmi_handler_enable); ++ + /* Analyze the results */ + for_each_cpu_and(cpu, cpu_present_mask, &cpus_booted_once_mask) { + switch (per_cpu(ucode_ctrl.result, cpu)) { +--- a/arch/x86/kernel/cpu/microcode/intel.c ++++ b/arch/x86/kernel/cpu/microcode/intel.c +@@ -611,6 +611,7 @@ static struct microcode_ops microcode_in + .collect_cpu_info = collect_cpu_info, + .apply_microcode = apply_microcode_late, + .finalize_late_load = finalize_late_load, ++ .use_nmi = IS_ENABLED(CONFIG_X86_64), + }; + + static __init void calc_llc_size_per_core(struct cpuinfo_x86 *c) +--- a/arch/x86/kernel/cpu/microcode/internal.h ++++ b/arch/x86/kernel/cpu/microcode/internal.h +@@ -31,7 +31,8 @@ struct microcode_ops { + enum ucode_state (*apply_microcode)(int cpu); + int (*collect_cpu_info)(int cpu, struct cpu_signature *csig); + void (*finalize_late_load)(int result); +- unsigned int nmi_safe : 1; ++ unsigned int nmi_safe : 1, ++ use_nmi : 1; + }; + + extern struct ucode_cpu_info ucode_cpu_info[]; +--- a/arch/x86/kernel/nmi.c ++++ b/arch/x86/kernel/nmi.c +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + #include + + #define CREATE_TRACE_POINTS +@@ -343,6 +344,9 @@ static noinstr void default_do_nmi(struc + + instrumentation_begin(); + ++ if (microcode_nmi_handler_enabled() && microcode_nmi_handler()) ++ goto out; ++ + handled = nmi_handle(NMI_LOCAL, regs); + __this_cpu_add(nmi_stats.normal, handled); + if (handled) { diff --git a/queue-6.6/x86-microcode-replace-the-all-in-one-rendevous-handler.patch b/queue-6.6/x86-microcode-replace-the-all-in-one-rendevous-handler.patch new file mode 100644 index 0000000000..89ce6d44e3 --- /dev/null +++ b/queue-6.6/x86-microcode-replace-the-all-in-one-rendevous-handler.patch @@ -0,0 +1,110 @@ +From 305f7001fdf2d3452a142a0afb726f180e664c95 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Mon, 2 Oct 2023 14:00:03 +0200 +Subject: x86/microcode: Replace the all-in-one rendevous handler + +From: Thomas Gleixner + +commit 0bf871651211b58c7b19f40b746b646d5311e2ec upstream + +with a new handler which just separates the control flow of primary and +secondary CPUs. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Borislav Petkov (AMD) +Link: https://lore.kernel.org/r/20231002115903.433704135@linutronix.de +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/cpu/microcode/core.c | 51 ++++++----------------------------- + 1 file changed, 9 insertions(+), 42 deletions(-) + +--- a/arch/x86/kernel/cpu/microcode/core.c ++++ b/arch/x86/kernel/cpu/microcode/core.c +@@ -268,7 +268,7 @@ struct microcode_ctrl { + }; + + static DEFINE_PER_CPU(struct microcode_ctrl, ucode_ctrl); +-static atomic_t late_cpus_in, late_cpus_out; ++static atomic_t late_cpus_in; + + static bool wait_for_cpus(atomic_t *cnt) + { +@@ -304,7 +304,7 @@ static bool wait_for_ctrl(void) + return false; + } + +-static __maybe_unused void load_secondary(unsigned int cpu) ++static void load_secondary(unsigned int cpu) + { + unsigned int ctrl_cpu = this_cpu_read(ucode_ctrl.ctrl_cpu); + enum ucode_state ret; +@@ -339,7 +339,7 @@ static __maybe_unused void load_secondar + this_cpu_write(ucode_ctrl.ctrl, SCTRL_DONE); + } + +-static __maybe_unused void load_primary(unsigned int cpu) ++static void load_primary(unsigned int cpu) + { + struct cpumask *secondaries = topology_sibling_cpumask(cpu); + enum sibling_ctrl ctrl; +@@ -376,46 +376,14 @@ static __maybe_unused void load_primary( + + static int load_cpus_stopped(void *unused) + { +- int cpu = smp_processor_id(); +- enum ucode_state ret; +- +- /* +- * Wait for all CPUs to arrive. A load will not be attempted unless all +- * CPUs show up. +- * */ +- if (!wait_for_cpus(&late_cpus_in)) { +- this_cpu_write(ucode_ctrl.result, UCODE_TIMEOUT); +- return 0; +- } +- +- /* +- * On an SMT system, it suffices to load the microcode on one sibling of +- * the core because the microcode engine is shared between the threads. +- * Synchronization still needs to take place so that no concurrent +- * loading attempts happen on multiple threads of an SMT core. See +- * below. +- */ +- if (cpumask_first(topology_sibling_cpumask(cpu)) != cpu) +- goto wait_for_siblings; ++ unsigned int cpu = smp_processor_id(); + +- ret = microcode_ops->apply_microcode(cpu); +- this_cpu_write(ucode_ctrl.result, ret); +- +-wait_for_siblings: +- if (!wait_for_cpus(&late_cpus_out)) +- panic("Timeout during microcode update!\n"); +- +- /* +- * At least one thread has completed update on each core. +- * For others, simply call the update to make sure the +- * per-cpu cpuinfo can be updated with right microcode +- * revision. +- */ +- if (cpumask_first(topology_sibling_cpumask(cpu)) == cpu) +- return 0; ++ if (this_cpu_read(ucode_ctrl.ctrl_cpu) == cpu) ++ load_primary(cpu); ++ else ++ load_secondary(cpu); + +- ret = microcode_ops->apply_microcode(cpu); +- this_cpu_write(ucode_ctrl.result, ret); ++ /* No point to wait here. The CPUs will all wait in stop_machine(). */ + return 0; + } + +@@ -429,7 +397,6 @@ static int load_late_stop_cpus(void) + pr_err("You should switch to early loading, if possible.\n"); + + atomic_set(&late_cpus_in, num_online_cpus()); +- atomic_set(&late_cpus_out, num_online_cpus()); + + /* + * Take a snapshot before the microcode update in order to compare and diff --git a/queue-6.6/x86-microcode-rework-early-revisions-reporting.patch b/queue-6.6/x86-microcode-rework-early-revisions-reporting.patch new file mode 100644 index 0000000000..e20f0213c3 --- /dev/null +++ b/queue-6.6/x86-microcode-rework-early-revisions-reporting.patch @@ -0,0 +1,279 @@ +From 343ac1f3a5241bcaf0e50e741ce06f9be092310f Mon Sep 17 00:00:00 2001 +From: "Borislav Petkov (AMD)" +Date: Wed, 15 Nov 2023 22:02:12 +0100 +Subject: x86/microcode: Rework early revisions reporting + +From: "Borislav Petkov (AMD)" + +commit 080990aa3344123673f686cda2df0d1b0deee046 upstream + +The AMD side of the loader issues the microcode revision for each +logical thread on the system, which can become really noisy on huge +machines. And doing that doesn't make a whole lot of sense - the +microcode revision is already in /proc/cpuinfo. + +So in case one is interested in the theoretical support of mixed silicon +steppings on AMD, one can check there. + +What is also missing on the AMD side - something which people have +requested before - is showing the microcode revision the CPU had +*before* the early update. + +So abstract that up in the main code and have the BSP on each vendor +provide those revision numbers. + +Then, dump them only once on driver init. + +On Intel, do not dump the patch date - it is not needed. + +Reported-by: Linus Torvalds +Signed-off-by: Borislav Petkov (AMD) +Reviewed-by: Thomas Gleixner +Link: https://lore.kernel.org/r/CAHk-=wg=%2B8rceshMkB4VnKxmRccVLtBLPBawnewZuuqyx5U=3A@mail.gmail.com +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/cpu/microcode/amd.c | 39 ++++++++----------------------- + arch/x86/kernel/cpu/microcode/core.c | 11 +++++++- + arch/x86/kernel/cpu/microcode/intel.c | 17 +++++-------- + arch/x86/kernel/cpu/microcode/internal.h | 14 +++++++---- + 4 files changed, 37 insertions(+), 44 deletions(-) + +--- a/arch/x86/kernel/cpu/microcode/amd.c ++++ b/arch/x86/kernel/cpu/microcode/amd.c +@@ -104,8 +104,6 @@ struct cont_desc { + size_t size; + }; + +-static u32 ucode_new_rev; +- + /* + * Microcode patch container file is prepended to the initrd in cpio + * format. See Documentation/arch/x86/microcode.rst +@@ -442,12 +440,11 @@ static int __apply_microcode_amd(struct + * + * Returns true if container found (sets @desc), false otherwise. + */ +-static bool early_apply_microcode(u32 cpuid_1_eax, void *ucode, size_t size) ++static bool early_apply_microcode(u32 cpuid_1_eax, u32 old_rev, void *ucode, size_t size) + { + struct cont_desc desc = { 0 }; + struct microcode_amd *mc; + bool ret = false; +- u32 rev, dummy; + + desc.cpuid_1_eax = cpuid_1_eax; + +@@ -457,22 +454,15 @@ static bool early_apply_microcode(u32 cp + if (!mc) + return ret; + +- native_rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy); +- + /* + * Allow application of the same revision to pick up SMT-specific + * changes even if the revision of the other SMT thread is already + * up-to-date. + */ +- if (rev > mc->hdr.patch_id) ++ if (old_rev > mc->hdr.patch_id) + return ret; + +- if (!__apply_microcode_amd(mc)) { +- ucode_new_rev = mc->hdr.patch_id; +- ret = true; +- } +- +- return ret; ++ return !__apply_microcode_amd(mc); + } + + static bool get_builtin_microcode(struct cpio_data *cp, unsigned int family) +@@ -506,9 +496,12 @@ static void __init find_blobs_in_contain + *ret = cp; + } + +-void __init load_ucode_amd_bsp(unsigned int cpuid_1_eax) ++void __init load_ucode_amd_bsp(struct early_load_data *ed, unsigned int cpuid_1_eax) + { + struct cpio_data cp = { }; ++ u32 dummy; ++ ++ native_rdmsr(MSR_AMD64_PATCH_LEVEL, ed->old_rev, dummy); + + /* Needed in load_microcode_amd() */ + ucode_cpu_info[0].cpu_sig.sig = cpuid_1_eax; +@@ -517,7 +510,8 @@ void __init load_ucode_amd_bsp(unsigned + if (!(cp.data && cp.size)) + return; + +- early_apply_microcode(cpuid_1_eax, cp.data, cp.size); ++ if (early_apply_microcode(cpuid_1_eax, ed->old_rev, cp.data, cp.size)) ++ native_rdmsr(MSR_AMD64_PATCH_LEVEL, ed->new_rev, dummy); + } + + static enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t size); +@@ -625,10 +619,8 @@ void reload_ucode_amd(unsigned int cpu) + rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy); + + if (rev < mc->hdr.patch_id) { +- if (!__apply_microcode_amd(mc)) { +- ucode_new_rev = mc->hdr.patch_id; +- pr_info("reload patch_level=0x%08x\n", ucode_new_rev); +- } ++ if (!__apply_microcode_amd(mc)) ++ pr_info_once("reload revision: 0x%08x\n", mc->hdr.patch_id); + } + } + +@@ -649,8 +641,6 @@ static int collect_cpu_info_amd(int cpu, + if (p && (p->patch_id == csig->rev)) + uci->mc = p->data; + +- pr_info("CPU%d: patch_level=0x%08x\n", cpu, csig->rev); +- + return 0; + } + +@@ -691,8 +681,6 @@ static enum ucode_state apply_microcode_ + rev = mc_amd->hdr.patch_id; + ret = UCODE_UPDATED; + +- pr_info("CPU%d: new patch_level=0x%08x\n", cpu, rev); +- + out: + uci->cpu_sig.rev = rev; + c->microcode = rev; +@@ -935,11 +923,6 @@ struct microcode_ops * __init init_amd_m + pr_warn("AMD CPU family 0x%x not supported\n", c->x86); + return NULL; + } +- +- if (ucode_new_rev) +- pr_info_once("microcode updated early to new patch_level=0x%08x\n", +- ucode_new_rev); +- + return µcode_amd_ops; + } + +--- a/arch/x86/kernel/cpu/microcode/core.c ++++ b/arch/x86/kernel/cpu/microcode/core.c +@@ -77,6 +77,8 @@ static u32 final_levels[] = { + 0, /* T-101 terminator */ + }; + ++struct early_load_data early_data; ++ + /* + * Check the current patch level on this CPU. + * +@@ -155,9 +157,9 @@ void __init load_ucode_bsp(void) + return; + + if (intel) +- load_ucode_intel_bsp(); ++ load_ucode_intel_bsp(&early_data); + else +- load_ucode_amd_bsp(cpuid_1_eax); ++ load_ucode_amd_bsp(&early_data, cpuid_1_eax); + } + + void load_ucode_ap(void) +@@ -828,6 +830,11 @@ static int __init microcode_init(void) + if (!microcode_ops) + return -ENODEV; + ++ pr_info_once("Current revision: 0x%08x\n", (early_data.new_rev ?: early_data.old_rev)); ++ ++ if (early_data.new_rev) ++ pr_info_once("Updated early from: 0x%08x\n", early_data.old_rev); ++ + microcode_pdev = platform_device_register_simple("microcode", -1, NULL, 0); + if (IS_ERR(microcode_pdev)) + return PTR_ERR(microcode_pdev); +--- a/arch/x86/kernel/cpu/microcode/intel.c ++++ b/arch/x86/kernel/cpu/microcode/intel.c +@@ -339,16 +339,9 @@ static enum ucode_state __apply_microcod + static enum ucode_state apply_microcode_early(struct ucode_cpu_info *uci) + { + struct microcode_intel *mc = uci->mc; +- enum ucode_state ret; +- u32 cur_rev, date; ++ u32 cur_rev; + +- ret = __apply_microcode(uci, mc, &cur_rev); +- if (ret == UCODE_UPDATED) { +- date = mc->hdr.date; +- pr_info_once("updated early: 0x%x -> 0x%x, date = %04x-%02x-%02x\n", +- cur_rev, mc->hdr.rev, date & 0xffff, date >> 24, (date >> 16) & 0xff); +- } +- return ret; ++ return __apply_microcode(uci, mc, &cur_rev); + } + + static __init bool load_builtin_intel_microcode(struct cpio_data *cp) +@@ -413,13 +406,17 @@ static int __init save_builtin_microcode + early_initcall(save_builtin_microcode); + + /* Load microcode on BSP from initrd or builtin blobs */ +-void __init load_ucode_intel_bsp(void) ++void __init load_ucode_intel_bsp(struct early_load_data *ed) + { + struct ucode_cpu_info uci; + ++ ed->old_rev = intel_get_microcode_revision(); ++ + uci.mc = get_microcode_blob(&uci, false); + if (uci.mc && apply_microcode_early(&uci) == UCODE_UPDATED) + ucode_patch_va = UCODE_BSP_LOADED; ++ ++ ed->new_rev = uci.cpu_sig.rev; + } + + void load_ucode_intel_ap(void) +--- a/arch/x86/kernel/cpu/microcode/internal.h ++++ b/arch/x86/kernel/cpu/microcode/internal.h +@@ -37,6 +37,12 @@ struct microcode_ops { + use_nmi : 1; + }; + ++struct early_load_data { ++ u32 old_rev; ++ u32 new_rev; ++}; ++ ++extern struct early_load_data early_data; + extern struct ucode_cpu_info ucode_cpu_info[]; + struct cpio_data find_microcode_in_initrd(const char *path); + +@@ -92,14 +98,14 @@ extern bool dis_ucode_ldr; + extern bool force_minrev; + + #ifdef CONFIG_CPU_SUP_AMD +-void load_ucode_amd_bsp(unsigned int family); ++void load_ucode_amd_bsp(struct early_load_data *ed, unsigned int family); + void load_ucode_amd_ap(unsigned int family); + int save_microcode_in_initrd_amd(unsigned int family); + void reload_ucode_amd(unsigned int cpu); + struct microcode_ops *init_amd_microcode(void); + void exit_amd_microcode(void); + #else /* CONFIG_CPU_SUP_AMD */ +-static inline void load_ucode_amd_bsp(unsigned int family) { } ++static inline void load_ucode_amd_bsp(struct early_load_data *ed, unsigned int family) { } + static inline void load_ucode_amd_ap(unsigned int family) { } + static inline int save_microcode_in_initrd_amd(unsigned int family) { return -EINVAL; } + static inline void reload_ucode_amd(unsigned int cpu) { } +@@ -108,12 +114,12 @@ static inline void exit_amd_microcode(vo + #endif /* !CONFIG_CPU_SUP_AMD */ + + #ifdef CONFIG_CPU_SUP_INTEL +-void load_ucode_intel_bsp(void); ++void load_ucode_intel_bsp(struct early_load_data *ed); + void load_ucode_intel_ap(void); + void reload_ucode_intel(void); + struct microcode_ops *init_intel_microcode(void); + #else /* CONFIG_CPU_SUP_INTEL */ +-static inline void load_ucode_intel_bsp(void) { } ++static inline void load_ucode_intel_bsp(struct early_load_data *ed) { } + static inline void load_ucode_intel_ap(void) { } + static inline void reload_ucode_intel(void) { } + static inline struct microcode_ops *init_intel_microcode(void) { return NULL; } diff --git a/queue-6.6/x86-microcode-sanitize-__wait_for_cpus.patch b/queue-6.6/x86-microcode-sanitize-__wait_for_cpus.patch new file mode 100644 index 0000000000..51cfbd9285 --- /dev/null +++ b/queue-6.6/x86-microcode-sanitize-__wait_for_cpus.patch @@ -0,0 +1,109 @@ +From 14dd21cf8c2a8ecf32f7c4cd986675eff64de4ed Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Mon, 2 Oct 2023 13:59:59 +0200 +Subject: x86/microcode: Sanitize __wait_for_cpus() + +From: Thomas Gleixner + +commit 0772b9aa1a8f7322dce8588c231cff8b57298a53 upstream + +The code is too complicated for no reason: + + - The return value is pointless as this is a strict boolean. + + - It's way simpler to count down from num_online_cpus() and check for + zero. + + - The timeout argument is pointless as this is always one second. + + - Touching the NMI watchdog every 100ns does not make any sense, neither + does checking every 100ns. This is really not a hotpath operation. + +Preload the atomic counter with the number of online CPUs and simplify the +whole timeout logic. Delay for one microsecond and touch the NMI watchdog +once per millisecond. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Borislav Petkov (AMD) +Link: https://lore.kernel.org/r/20231002115903.204251527@linutronix.de +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/cpu/microcode/core.c | 39 +++++++++++++++-------------------- + 1 file changed, 17 insertions(+), 22 deletions(-) + +--- a/arch/x86/kernel/cpu/microcode/core.c ++++ b/arch/x86/kernel/cpu/microcode/core.c +@@ -252,31 +252,26 @@ static struct platform_device *microcode + * requirement can be relaxed in the future. Right now, this is conservative + * and good. + */ +-#define SPINUNIT 100 /* 100 nsec */ ++static atomic_t late_cpus_in, late_cpus_out; + +- +-static atomic_t late_cpus_in; +-static atomic_t late_cpus_out; +- +-static int __wait_for_cpus(atomic_t *t, long long timeout) ++static bool wait_for_cpus(atomic_t *cnt) + { +- int all_cpus = num_online_cpus(); ++ unsigned int timeout; + +- atomic_inc(t); ++ WARN_ON_ONCE(atomic_dec_return(cnt) < 0); + +- while (atomic_read(t) < all_cpus) { +- if (timeout < SPINUNIT) { +- pr_err("Timeout while waiting for CPUs rendezvous, remaining: %d\n", +- all_cpus - atomic_read(t)); +- return 1; +- } ++ for (timeout = 0; timeout < USEC_PER_SEC; timeout++) { ++ if (!atomic_read(cnt)) ++ return true; + +- ndelay(SPINUNIT); +- timeout -= SPINUNIT; ++ udelay(1); + +- touch_nmi_watchdog(); ++ if (!(timeout % USEC_PER_MSEC)) ++ touch_nmi_watchdog(); + } +- return 0; ++ /* Prevent the late comers from making progress and let them time out */ ++ atomic_inc(cnt); ++ return false; + } + + /* +@@ -294,7 +289,7 @@ static int __reload_late(void *info) + * Wait for all CPUs to arrive. A load will not be attempted unless all + * CPUs show up. + * */ +- if (__wait_for_cpus(&late_cpus_in, NSEC_PER_SEC)) ++ if (!wait_for_cpus(&late_cpus_in)) + return -1; + + /* +@@ -317,7 +312,7 @@ static int __reload_late(void *info) + } + + wait_for_siblings: +- if (__wait_for_cpus(&late_cpus_out, NSEC_PER_SEC)) ++ if (!wait_for_cpus(&late_cpus_out)) + panic("Timeout during microcode update!\n"); + + /* +@@ -344,8 +339,8 @@ static int microcode_reload_late(void) + pr_err("Attempting late microcode loading - it is dangerous and taints the kernel.\n"); + pr_err("You should switch to early loading, if possible.\n"); + +- atomic_set(&late_cpus_in, 0); +- atomic_set(&late_cpus_out, 0); ++ atomic_set(&late_cpus_in, num_online_cpus()); ++ atomic_set(&late_cpus_out, num_online_cpus()); + + /* + * Take a snapshot before the microcode update in order to compare and