]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.6-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 5 Mar 2025 17:25:00 +0000 (18:25 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 5 Mar 2025 17:25:00 +0000 (18:25 +0100)
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

47 files changed:
queue-6.6/series
queue-6.6/x86-apic-provide-apic_force_nmi_on_cpu.patch [new file with mode: 0644]
queue-6.6/x86-microcode-32-move-early-loading-after-paging-enable.patch [new file with mode: 0644]
queue-6.6/x86-microcode-add-per-cpu-control-field.patch [new file with mode: 0644]
queue-6.6/x86-microcode-add-per-cpu-result-state.patch [new file with mode: 0644]
queue-6.6/x86-microcode-amd-add-get_patch_level.patch [new file with mode: 0644]
queue-6.6/x86-microcode-amd-cache-builtin-initrd-microcode-early.patch [new file with mode: 0644]
queue-6.6/x86-microcode-amd-cache-builtin-microcode-too.patch [new file with mode: 0644]
queue-6.6/x86-microcode-amd-flush-patch-buffer-mapping-after-application.patch [new file with mode: 0644]
queue-6.6/x86-microcode-amd-get-rid-of-the-_load_microcode_amd-forward-declaration.patch [new file with mode: 0644]
queue-6.6/x86-microcode-amd-have-__apply_microcode_amd-return-bool.patch [new file with mode: 0644]
queue-6.6/x86-microcode-amd-load-only-sha256-checksummed-patches.patch [new file with mode: 0644]
queue-6.6/x86-microcode-amd-make-__verify_patch_size-return-bool.patch [new file with mode: 0644]
queue-6.6/x86-microcode-amd-merge-early_apply_microcode-into-its-single-callsite.patch [new file with mode: 0644]
queue-6.6/x86-microcode-amd-pay-attention-to-the-stepping-dynamically.patch [new file with mode: 0644]
queue-6.6/x86-microcode-amd-return-bool-from-find_blobs_in_containers.patch [new file with mode: 0644]
queue-6.6/x86-microcode-amd-split-load_microcode_amd.patch [new file with mode: 0644]
queue-6.6/x86-microcode-amd-use-cached-microcode-for-ap-load.patch [new file with mode: 0644]
queue-6.6/x86-microcode-amd-use-correct-per-cpu-ucode_cpu_info.patch [new file with mode: 0644]
queue-6.6/x86-microcode-amd-use-the-family-model-stepping-encoded-in-the-patch-id.patch [new file with mode: 0644]
queue-6.6/x86-microcode-clarify-the-late-load-logic.patch [new file with mode: 0644]
queue-6.6/x86-microcode-clean-up-mc_cpu_down_prep.patch [new file with mode: 0644]
queue-6.6/x86-microcode-get-rid-of-the-schedule-work-indirection.patch [new file with mode: 0644]
queue-6.6/x86-microcode-handle-nosmt-correctly.patch [new file with mode: 0644]
queue-6.6/x86-microcode-handle-offline-cpus-correctly.patch [new file with mode: 0644]
queue-6.6/x86-microcode-intel-cleanup-code-further.patch [new file with mode: 0644]
queue-6.6/x86-microcode-intel-remove-unnecessary-cache-writeback-and-invalidation.patch [new file with mode: 0644]
queue-6.6/x86-microcode-intel-reuse-intel_cpu_collect_info.patch [new file with mode: 0644]
queue-6.6/x86-microcode-intel-rework-intel_cpu_collect_info.patch [new file with mode: 0644]
queue-6.6/x86-microcode-intel-rework-intel_find_matching_signature.patch [new file with mode: 0644]
queue-6.6/x86-microcode-intel-rip-out-mixed-stepping-support-for-intel-cpus.patch [new file with mode: 0644]
queue-6.6/x86-microcode-intel-save-the-microcode-only-after-a-successful-late-load.patch [new file with mode: 0644]
queue-6.6/x86-microcode-intel-set-new-revision-only-after-a-successful-update.patch [new file with mode: 0644]
queue-6.6/x86-microcode-intel-simplify-and-rename-generic_load_microcode.patch [new file with mode: 0644]
queue-6.6/x86-microcode-intel-simplify-early-loading.patch [new file with mode: 0644]
queue-6.6/x86-microcode-intel-simplify-scan_microcode.patch [new file with mode: 0644]
queue-6.6/x86-microcode-intel-switch-to-kvmalloc.patch [new file with mode: 0644]
queue-6.6/x86-microcode-intel-unify-microcode-apply-functions.patch [new file with mode: 0644]
queue-6.6/x86-microcode-mop-up-early-loading-leftovers.patch [new file with mode: 0644]
queue-6.6/x86-microcode-prepare-for-minimal-revision-check.patch [new file with mode: 0644]
queue-6.6/x86-microcode-protect-against-instrumentation.patch [new file with mode: 0644]
queue-6.6/x86-microcode-provide-new-control-functions.patch [new file with mode: 0644]
queue-6.6/x86-microcode-remove-pointless-apply-invocation.patch [new file with mode: 0644]
queue-6.6/x86-microcode-rendezvous-and-load-in-nmi.patch [new file with mode: 0644]
queue-6.6/x86-microcode-replace-the-all-in-one-rendevous-handler.patch [new file with mode: 0644]
queue-6.6/x86-microcode-rework-early-revisions-reporting.patch [new file with mode: 0644]
queue-6.6/x86-microcode-sanitize-__wait_for_cpus.patch [new file with mode: 0644]

index 902b7aa05bd594a7b1797b59b0ed825b58c5c518..2ea5dee5bd1fbe7713167b6203b350f4992e44a8 100644 (file)
@@ -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 (file)
index 0000000..680867b
--- /dev/null
@@ -0,0 +1,113 @@
+From 086f78d30a378e824e4743080fc6fe22254a42c4 Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Mon, 2 Oct 2023 14:00:07 +0200
+Subject: x86/apic: Provide apic_force_nmi_on_cpu()
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+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 <tglx@linutronix.de>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Link: https://lore.kernel.org/r/20231002115903.603100036@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..e5dd656
--- /dev/null
@@ -0,0 +1,838 @@
+From a78cf1d31b4ae70395034948d005a1b3ee252746 Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Tue, 17 Oct 2023 23:23:32 +0200
+Subject: x86/microcode/32: Move early loading after paging enable
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+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 <tglx@linutronix.de>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Link: https://lore.kernel.org/r/20231017211722.348298216@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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(&current_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 <asm/apic.h>
+ #include <asm/io_apic.h>
+ #include <asm/bios_ebda.h>
++#include <asm/microcode.h>
+ #include <asm/tlbflush.h>
+ #include <asm/bootparam_utils.h>
+@@ -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 (file)
index 0000000..3c98497
--- /dev/null
@@ -0,0 +1,87 @@
+From d996a8d18c72a9cd3ed58ab98e3a06db064ac520 Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Mon, 2 Oct 2023 14:00:01 +0200
+Subject: x86/microcode: Add per CPU control field
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+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 <tglx@linutronix.de>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Link: https://lore.kernel.org/r/20231002115903.319959519@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..4e6831d
--- /dev/null
@@ -0,0 +1,243 @@
+From facaa441b953dc69f317559214cb4ecc66b91b12 Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Tue, 17 Oct 2023 23:24:05 +0200
+Subject: x86/microcode: Add per CPU result state
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+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 <tglx@linutronix.de>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Link: https://lore.kernel.org/r/20231017211723.632681010@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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, &microcode_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 (file)
index 0000000..39488fa
--- /dev/null
@@ -0,0 +1,141 @@
+From dcfc9697e6569d326cfef8ae6e068f94ce9cc947 Mon Sep 17 00:00:00 2001
+From: "Borislav Petkov (AMD)" <bp@alien8.de>
+Date: Thu, 23 Jan 2025 13:02:32 +0100
+Subject: x86/microcode/AMD: Add get_patch_level()
+
+From: "Borislav Petkov (AMD)" <bp@alien8.de>
+
+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) <bp@alien8.de>
+Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
+Link: https://lore.kernel.org/r/20250211163648.30531-6-bp@kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..c6cb293
--- /dev/null
@@ -0,0 +1,100 @@
+From 774c3e2de69911f2baaaaab1b3ef55ea25776a30 Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Tue, 17 Oct 2023 23:23:53 +0200
+Subject: x86/microcode/amd: Cache builtin/initrd microcode early
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+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 <tglx@linutronix.de>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Link: https://lore.kernel.org/r/20231017211723.187566507@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..d6e5151
--- /dev/null
@@ -0,0 +1,33 @@
+From 743fc38b6a60d7764b20ec7c383f327ff80d29c0 Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Tue, 10 Oct 2023 17:08:43 +0200
+Subject: x86/microcode/amd: Cache builtin microcode too
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+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 <tglx@linutronix.de>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Link: https://lore.kernel.org/r/20231010150702.495139089@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..31e3a06
--- /dev/null
@@ -0,0 +1,90 @@
+From 43796fa7351ee4f2b5bcc747e69a73d3fe722c34 Mon Sep 17 00:00:00 2001
+From: "Borislav Petkov (AMD)" <bp@alien8.de>
+Date: Tue, 19 Nov 2024 12:21:33 +0100
+Subject: x86/microcode/AMD: Flush patch buffer mapping after application
+
+From: "Borislav Petkov (AMD)" <bp@alien8.de>
+
+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 <thomas.de_schampheleire@nokia.com>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Tested-by: Thomas De Schampheleire <thomas.de_schampheleire@nokia.com>
+Cc: <stable@kernel.org> # 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 <gregkh@linuxfoundation.org>
+---
+ 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 <asm/setup.h>
+ #include <asm/cpu.h>
+ #include <asm/msr.h>
++#include <asm/tlb.h>
+ #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 (file)
index 0000000..257a269
--- /dev/null
@@ -0,0 +1,91 @@
+From 4dd1f715003bc4b5d86f83d849f069c3243bdcf4 Mon Sep 17 00:00:00 2001
+From: "Borislav Petkov (AMD)" <bp@alien8.de>
+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)" <bp@alien8.de>
+
+commit b39c387164879eef71886fc93cee5ca7dd7bf500 upstream
+
+Simply move save_microcode_in_initrd() down.
+
+No functional changes.
+
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
+Link: https://lore.kernel.org/r/20250211163648.30531-5-bp@kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..f81639b
--- /dev/null
@@ -0,0 +1,69 @@
+From 51afb39e8de36dc4e1f48cb1ad1109c734d5f085 Mon Sep 17 00:00:00 2001
+From: "Borislav Petkov (AMD)" <bp@alien8.de>
+Date: Mon, 18 Nov 2024 17:17:24 +0100
+Subject: x86/microcode/AMD: Have __apply_microcode_amd() return bool
+
+From: "Borislav Petkov (AMD)" <bp@alien8.de>
+
+commit 78e0aadbd4c6807a06a9d25bc190fe515d3f3c42 upstream
+
+This is the natural thing to do anyway.
+
+No functional changes.
+
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..d074068
--- /dev/null
@@ -0,0 +1,639 @@
+From 261d80764841b43ba45e79bf1798a4472a30e5b4 Mon Sep 17 00:00:00 2001
+From: "Borislav Petkov (AMD)" <bp@alien8.de>
+Date: Thu, 23 Jan 2025 14:44:53 +0100
+Subject: x86/microcode/AMD: Load only SHA256-checksummed patches
+
+From: "Borislav Petkov (AMD)" <bp@alien8.de>
+
+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) <bp@alien8.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 <linux/earlycpio.h>
+ #include <linux/firmware.h>
++#include <linux/bsearch.h>
+ #include <linux/uaccess.h>
+ #include <linux/vmalloc.h>
+ #include <linux/initrd.h>
+ #include <linux/kernel.h>
+ #include <linux/pci.h>
++#include <crypto/sha2.h>
++
+ #include <asm/microcode.h>
+ #include <asm/processor.h>
++#include <asm/cmdline.h>
+ #include <asm/setup.h>
+ #include <asm/cpu.h>
+ #include <asm/msr.h>
+@@ -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-<at>-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 (file)
index 0000000..c6457ea
--- /dev/null
@@ -0,0 +1,79 @@
+From 251ca274aa7d61a36f63239b72a6fca05ec00875 Mon Sep 17 00:00:00 2001
+From: Nikolay Borisov <nik.borisov@suse.com>
+Date: Fri, 18 Oct 2024 18:51:50 +0300
+Subject: x86/microcode/AMD: Make __verify_patch_size() return bool
+
+From: Nikolay Borisov <nik.borisov@suse.com>
+
+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 <nik.borisov@suse.com>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Link: https://lore.kernel.org/r/20241018155151.702350-3-nik.borisov@suse.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..5a7dcd4
--- /dev/null
@@ -0,0 +1,104 @@
+From d0ac6b03dd875fe519561db889f5ba3466d1a53b Mon Sep 17 00:00:00 2001
+From: "Borislav Petkov (AMD)" <bp@alien8.de>
+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)" <bp@alien8.de>
+
+commit dc15675074dcfd79a2f10a6e39f96b0244961a01 upstream
+
+No functional changes.
+
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
+Link: https://lore.kernel.org/r/20250211163648.30531-4-bp@kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..e0f8161
--- /dev/null
@@ -0,0 +1,100 @@
+From d3b57478de5a355a804aea35da762a9c9e345b46 Mon Sep 17 00:00:00 2001
+From: "Borislav Petkov (AMD)" <bp@alien8.de>
+Date: Mon, 21 Oct 2024 10:27:52 +0200
+Subject: x86/microcode/AMD: Pay attention to the stepping dynamically
+
+From: "Borislav Petkov (AMD)" <bp@alien8.de>
+
+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 <axboe@kernel.dk>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Tested-by: Jens Axboe <axboe@kernel.dk>
+Link: https://lore.kernel.org/r/91194406-3fdf-4e38-9838-d334af538f74@kernel.dk
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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, &microcode_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, &microcode_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 (file)
index 0000000..85e9072
--- /dev/null
@@ -0,0 +1,69 @@
+From 10f93d372e36136bd6b87c6f818cba54da688ed4 Mon Sep 17 00:00:00 2001
+From: Nikolay Borisov <nik.borisov@suse.com>
+Date: Fri, 18 Oct 2024 18:51:49 +0300
+Subject: x86/microcode/AMD: Return bool from find_blobs_in_containers()
+
+From: Nikolay Borisov <nik.borisov@suse.com>
+
+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 <nik.borisov@suse.com>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Link: https://lore.kernel.org/r/20241018155151.702350-2-nik.borisov@suse.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..deab297
--- /dev/null
@@ -0,0 +1,100 @@
+From a33c9b7c9df314a89aa8c43889a6a92495a6f29b Mon Sep 17 00:00:00 2001
+From: "Borislav Petkov (AMD)" <bp@alien8.de>
+Date: Mon, 21 Oct 2024 10:38:21 +0200
+Subject: x86/microcode/AMD: Split load_microcode_amd()
+
+From: "Borislav Petkov (AMD)" <bp@alien8.de>
+
+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 <axboe@kernel.dk>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Tested-by: Jens Axboe <axboe@kernel.dk>
+Link: https://lore.kernel.org/r/91194406-3fdf-4e38-9838-d334af538f74@kernel.dk
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..56a3cba
--- /dev/null
@@ -0,0 +1,152 @@
+From b22b6b6d2a1cf29b63c249b79a3fe6416d6c210f Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Tue, 17 Oct 2023 23:23:55 +0200
+Subject: x86/microcode/amd: Use cached microcode for AP load
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+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 <tglx@linutronix.de>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Link: https://lore.kernel.org/r/20231017211723.243426023@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..e6d2e88
--- /dev/null
@@ -0,0 +1,46 @@
+From 52739801d858deb1410e3847a998ba8227c555ec Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Tue, 10 Oct 2023 17:08:41 +0200
+Subject: x86/microcode/amd: Use correct per CPU ucode_cpu_info
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+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 <tglx@linutronix.de>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Link: https://lore.kernel.org/r/20231010150702.433454320@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..5a25d70
--- /dev/null
@@ -0,0 +1,447 @@
+From 00b063b90e31be03012dea13cf6190ac39a5d2e5 Mon Sep 17 00:00:00 2001
+From: Borislav Petkov <bp@alien8.de>
+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 <bp@alien8.de>
+
+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) <bp@alien8.de>
+Link: https://lore.kernel.org/r/20240725112037.GBZqI1BbUk1KMlOJ_D@fat_crate.local
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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, &microcode_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, &microcode_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 (file)
index 0000000..b08fd70
--- /dev/null
@@ -0,0 +1,101 @@
+From 17f713d29969a723f51eb4d4d1cdccb545b035ae Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Mon, 2 Oct 2023 13:59:57 +0200
+Subject: x86/microcode: Clarify the late load logic
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+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 <tglx@linutronix.de>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Reviewed-by: Nikolay Borisov <nik.borisov@suse.com>
+Link: https://lore.kernel.org/r/20231002115903.145048840@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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, &microcode_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, &microcode_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 (file)
index 0000000..e2fe09c
--- /dev/null
@@ -0,0 +1,43 @@
+From 6759862c3c76d50ae5b05490ffe9c83964e64bc8 Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Mon, 2 Oct 2023 13:59:55 +0200
+Subject: x86/microcode: Clean up mc_cpu_down_prep()
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+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 <tglx@linutronix.de>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Link: https://lore.kernel.org/r/20231002115903.028651784@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..dc6ef74
--- /dev/null
@@ -0,0 +1,76 @@
+From 1b43c9ce45068f82226605c7e253aee7ff8ec634 Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Tue, 17 Oct 2023 23:23:58 +0200
+Subject: x86/microcode: Get rid of the schedule work indirection
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+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 <tglx@linutronix.de>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Link: https://lore.kernel.org/r/20231017211723.354748138@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..aec5ae4
--- /dev/null
@@ -0,0 +1,167 @@
+From 760ac4ae4059a69e68c07e4bfa151a733fa059c8 Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Mon, 2 Oct 2023 13:59:56 +0200
+Subject: x86/microcode: Handle "nosmt" correctly
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+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 <tglx@linutronix.de>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Link: https://lore.kernel.org/r/20231002115903.087472735@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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, &microcode_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 (file)
index 0000000..f0bd347
--- /dev/null
@@ -0,0 +1,249 @@
+From 55d40b5d38571a06c143786742b425d2e083c67c Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Mon, 2 Oct 2023 14:00:08 +0200
+Subject: x86/microcode: Handle "offline" CPUs correctly
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+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 <tglx@linutronix.de>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Link: https://lore.kernel.org/r/20231002115903.660850472@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..7a4dfdc
--- /dev/null
@@ -0,0 +1,162 @@
+From 8d78a5ff8ee83e456d68102d9d7ae8c6766fa7ce Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Mon, 2 Oct 2023 13:59:41 +0200
+Subject: x86/microcode/intel: Cleanup code further
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+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 <tglx@linutronix.de>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Link: https://lore.kernel.org/r/20231002115902.389400871@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 &microcode_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 (file)
index 0000000..60be7a9
--- /dev/null
@@ -0,0 +1,70 @@
+From f602940dde8cafbe9518143dc1cfca3c17c17478 Mon Sep 17 00:00:00 2001
+From: "Chang S. Bae" <chang.seok.bae@intel.com>
+Date: Tue, 1 Oct 2024 09:10:36 -0700
+Subject: x86/microcode/intel: Remove unnecessary cache writeback and invalidation
+
+From: "Chang S. Bae" <chang.seok.bae@intel.com>
+
+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 <yanhua1.wu@intel.com>
+Reported-by: William Xie <william.xie@intel.com>
+Signed-off-by: Chang S. Bae <chang.seok.bae@intel.com>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Acked-by: Ashok Raj <ashok.raj@intel.com>
+Tested-by: Yan Hua Wu <yanhua1.wu@intel.com>
+Link: https://lore.kernel.org/r/20241001161042.465584-2-chang.seok.bae@intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..893bfba
--- /dev/null
@@ -0,0 +1,44 @@
+From 5aa5d3f9c1e431e15a849caf6f502152901cfff3 Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Mon, 2 Oct 2023 13:59:49 +0200
+Subject: x86/microcode/intel: Reuse intel_cpu_collect_info()
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+commit 11f96ac4c21e701650c7d8349b252973185ac6ce upstream
+
+No point for an almost duplicate function.
+
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Link: https://lore.kernel.org/r/20231002115902.741173606@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..6ec0467
--- /dev/null
@@ -0,0 +1,118 @@
+From 3959c233b1a962997ecb8854d484882a2025b1c1 Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Tue, 17 Oct 2023 23:23:45 +0200
+Subject: x86/microcode/intel: Rework intel_cpu_collect_info()
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+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 <tglx@linutronix.de>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Link: https://lore.kernel.org/r/20231017211722.851573238@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..74e499a
--- /dev/null
@@ -0,0 +1,127 @@
+From 19c08250133b454726b8efd5a7c6fd27859af202 Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Mon, 2 Oct 2023 13:59:50 +0200
+Subject: x86/microcode/intel: Rework intel_find_matching_signature()
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+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 <tglx@linutronix.de>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Link: https://lore.kernel.org/r/20231002115902.797820205@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..a0e9968
--- /dev/null
@@ -0,0 +1,303 @@
+From 58ea3102876845d0088b8ebe8458cfac8251d4e3 Mon Sep 17 00:00:00 2001
+From: Ashok Raj <ashok.raj@intel.com>
+Date: Tue, 17 Oct 2023 23:23:33 +0200
+Subject: x86/microcode/intel: Rip out mixed stepping support for Intel CPUs
+
+From: Ashok Raj <ashok.raj@intel.com>
+
+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 <tglx@linutronix.de>
+Signed-off-by: Ashok Raj <ashok.raj@intel.com>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Link: https://lore.kernel.org/r/20231017211722.404362809@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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, &microcode_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, &microcode_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, &microcode_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 <asm/cpu.h>
+ #include <asm/microcode.h>
+-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 (file)
index 0000000..d9947cd
--- /dev/null
@@ -0,0 +1,123 @@
+From 9b3fa0e8651fe1988c3103d1bca401cca0341258 Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+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 <tglx@linutronix.de>
+
+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 <tglx@linutronix.de>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Link: https://lore.kernel.org/r/20231002115902.505491309@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..14aaed9
--- /dev/null
@@ -0,0 +1,63 @@
+From 9f96838d0ac5ce33575968c2596eba004118f885 Mon Sep 17 00:00:00 2001
+From: "Borislav Petkov (AMD)" <bp@alien8.de>
+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)" <bp@alien8.de>
+
+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 <ashok.raj@intel.com>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Tested-by: Ashok Raj <ashok.raj@intel.com>
+Link: https://lore.kernel.org/r/ZWjVt5dNRjbcvlzR@a4bf019067fa.jf.intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..56c44d3
--- /dev/null
@@ -0,0 +1,116 @@
+From 439bbf98a0eeb839da26fe91d0dd0fb158957de3 Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Mon, 2 Oct 2023 13:59:40 +0200
+Subject: x86/microcode/intel: Simplify and rename generic_load_microcode()
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+commit 6b072022ab2e1e83b7588144ee0080f7197b71da upstream
+
+so it becomes less obfuscated and rename it because there is nothing
+generic about it.
+
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Link: https://lore.kernel.org/r/20231002115902.330295409@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..d4d11c2
--- /dev/null
@@ -0,0 +1,389 @@
+From 3c4ebaefd467735f9aec389f02264f17fc7e0f3a Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Mon, 2 Oct 2023 13:59:43 +0200
+Subject: x86/microcode/intel: Simplify early loading
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+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 <tglx@linutronix.de>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Link: https://lore.kernel.org/r/20231017211722.629085215@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..9239408
--- /dev/null
@@ -0,0 +1,79 @@
+From 0487743593c7df7d637db9048c5727bd7c1cea03 Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Mon, 2 Oct 2023 13:59:39 +0200
+Subject: x86/microcode/intel: Simplify scan_microcode()
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+commit b0f0bf5eef5fac6ba30b7cac15ca4cb01f8a6ca9 upstream
+
+Make it readable and comprehensible.
+
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Link: https://lore.kernel.org/r/20231002115902.271940980@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..2b393b0
--- /dev/null
@@ -0,0 +1,147 @@
+From 0937c0624d82085ec90acde324c0bd6d9accfa20 Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Mon, 2 Oct 2023 13:59:45 +0200
+Subject: x86/microcode/intel: Switch to kvmalloc()
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+commit f24f204405f9875bc539c6e88553fd5ac913c867 upstream
+
+Microcode blobs are getting larger and might soon reach the kmalloc()
+limit. Switch over kvmalloc().
+
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Link: https://lore.kernel.org/r/20231002115902.564323243@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 <linux/earlycpio.h>
+ #include <linux/firmware.h>
+ #include <linux/uaccess.h>
+-#include <linux/vmalloc.h>
+ #include <linux/initrd.h>
+ #include <linux/kernel.h>
+ #include <linux/slab.h>
+@@ -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 (file)
index 0000000..1652b9b
--- /dev/null
@@ -0,0 +1,183 @@
+From 661c46050f078216190d6137423d04a49bfe44ae Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Tue, 17 Oct 2023 23:23:44 +0200
+Subject: x86/microcode/intel: Unify microcode apply() functions
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+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) <bp@alien8.de>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Link: https://lore.kernel.org/r/20231017211722.795508212@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..09de080
--- /dev/null
@@ -0,0 +1,75 @@
+From 3f7517298aa0e62866887bff84df0ae84cec2b96 Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Tue, 17 Oct 2023 23:23:56 +0200
+Subject: x86/microcode: Mop up early loading leftovers
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+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 <tglx@linutronix.de>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Link: https://lore.kernel.org/r/20231017211723.298854846@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..11699ef
--- /dev/null
@@ -0,0 +1,184 @@
+From 1aa144827ab0a7f4c1f30ac972f4ec66f079afb3 Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Tue, 17 Oct 2023 23:24:16 +0200
+Subject: x86/microcode: Prepare for minimal revision check
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+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 <tglx@linutronix.de>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Link: https://lore.kernel.org/r/20231017211724.079611170@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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: <bool>
++                      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, &microcode_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 (file)
index 0000000..81c0e0e
--- /dev/null
@@ -0,0 +1,213 @@
+From 27c67e37da3074932dc5811ec05c30fdeaab8939 Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Mon, 2 Oct 2023 14:00:06 +0200
+Subject: x86/microcode: Protect against instrumentation
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+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 <tglx@linutronix.de>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Link: https://lore.kernel.org/r/20231002115903.545969323@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..25309ee
--- /dev/null
@@ -0,0 +1,127 @@
+From 284ad8d909ac86b325f5e3a4798e90df4af30d8c Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Mon, 2 Oct 2023 14:00:02 +0200
+Subject: x86/microcode: Provide new control functions
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+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 <tglx@linutronix.de>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Link: https://lore.kernel.org/r/20231002115903.377922731@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..98a0468
--- /dev/null
@@ -0,0 +1,91 @@
+From bcdf3a18c00f084fe58ca11dc7c2e58c7ee1ae49 Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Tue, 17 Oct 2023 23:23:49 +0200
+Subject: x86/microcode: Remove pointless apply() invocation
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+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) <bp@alien8.de>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Link: https://lore.kernel.org/r/20231017211723.018821624@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..1f150c9
--- /dev/null
@@ -0,0 +1,210 @@
+From 1b3dbb4473d085a7845d6348b8838c4796dde230 Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Mon, 2 Oct 2023 14:00:05 +0200
+Subject: x86/microcode: Rendezvous and load in NMI
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+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 <tglx@linutronix.de>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Link: https://lore.kernel.org/r/20231002115903.489900814@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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(&microcode_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 <linux/miscdevice.h>
+ #include <linux/capability.h>
+ #include <linux/firmware.h>
++#include <linux/cpumask.h>
+ #include <linux/kernel.h>
+ #include <linux/delay.h>
+ #include <linux/mutex.h>
+@@ -31,6 +32,7 @@
+ #include <linux/fs.h>
+ #include <linux/mm.h>
++#include <asm/apic.h>
+ #include <asm/cpu_device_id.h>
+ #include <asm/perf_event.h>
+ #include <asm/processor.h>
+@@ -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(&microcode_nmi_handler_enable);
++
+       stop_machine_cpuslocked(load_cpus_stopped, NULL, cpu_online_mask);
++      if (microcode_ops->use_nmi)
++              static_branch_disable_cpuslocked(&microcode_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 <asm/reboot.h>
+ #include <asm/cache.h>
+ #include <asm/nospec-branch.h>
++#include <asm/microcode.h>
+ #include <asm/sev.h>
+ #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 (file)
index 0000000..89ce6d4
--- /dev/null
@@ -0,0 +1,110 @@
+From 305f7001fdf2d3452a142a0afb726f180e664c95 Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Mon, 2 Oct 2023 14:00:03 +0200
+Subject: x86/microcode: Replace the all-in-one rendevous handler
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+commit 0bf871651211b58c7b19f40b746b646d5311e2ec upstream
+
+with a new handler which just separates the control flow of primary and
+secondary CPUs.
+
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Link: https://lore.kernel.org/r/20231002115903.433704135@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..e20f021
--- /dev/null
@@ -0,0 +1,279 @@
+From 343ac1f3a5241bcaf0e50e741ce06f9be092310f Mon Sep 17 00:00:00 2001
+From: "Borislav Petkov (AMD)" <bp@alien8.de>
+Date: Wed, 15 Nov 2023 22:02:12 +0100
+Subject: x86/microcode: Rework early revisions reporting
+
+From: "Borislav Petkov (AMD)" <bp@alien8.de>
+
+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 <torvalds@linux-foundation.org>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
+Link: https://lore.kernel.org/r/CAHk-=wg=%2B8rceshMkB4VnKxmRccVLtBLPBawnewZuuqyx5U=3A@mail.gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 &microcode_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 (file)
index 0000000..51cfbd9
--- /dev/null
@@ -0,0 +1,109 @@
+From 14dd21cf8c2a8ecf32f7c4cd986675eff64de4ed Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Mon, 2 Oct 2023 13:59:59 +0200
+Subject: x86/microcode: Sanitize __wait_for_cpus()
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+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 <tglx@linutronix.de>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Link: https://lore.kernel.org/r/20231002115903.204251527@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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