summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '0052-x86-ucode-AMD-apply-the-patch-early-on-every-logical.patch')
-rw-r--r--0052-x86-ucode-AMD-apply-the-patch-early-on-every-logical.patch154
1 files changed, 154 insertions, 0 deletions
diff --git a/0052-x86-ucode-AMD-apply-the-patch-early-on-every-logical.patch b/0052-x86-ucode-AMD-apply-the-patch-early-on-every-logical.patch
new file mode 100644
index 0000000..22a214b
--- /dev/null
+++ b/0052-x86-ucode-AMD-apply-the-patch-early-on-every-logical.patch
@@ -0,0 +1,154 @@
+From e9a7942f6c1638c668605fbf6d6e02bc7bff2582 Mon Sep 17 00:00:00 2001
+From: Sergey Dyasli <sergey.dyasli@citrix.com>
+Date: Fri, 3 Mar 2023 07:58:35 +0100
+Subject: [PATCH 52/89] x86/ucode/AMD: apply the patch early on every logical
+ thread
+
+The original issue has been reported on AMD Bulldozer-based CPUs where
+ucode loading loses the LWP feature bit in order to gain the IBPB bit.
+LWP disabling is per-SMT/CMT core modification and needs to happen on
+each sibling thread despite the shared microcode engine. Otherwise,
+logical CPUs will end up with different cpuid capabilities.
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=216211
+
+Guests running under Xen happen to be not affected because of levelling
+logic for the feature masking/override MSRs which causes the LWP bit to
+fall out and hides the issue. The latest recommendation from AMD, after
+discussing this bug, is to load ucode on every logical CPU.
+
+In Linux kernel this issue has been addressed by e7ad18d1169c
+("x86/microcode/AMD: Apply the patch early on every logical thread").
+Follow the same approach in Xen.
+
+Introduce SAME_UCODE match result and use it for early AMD ucode
+loading. Take this opportunity and move opt_ucode_allow_same out of
+compare_revisions() to the relevant callers and also modify the warning
+message based on it. Intel's side of things is modified for consistency
+but provides no functional change.
+
+Signed-off-by: Sergey Dyasli <sergey.dyasli@citrix.com>
+Reviewed-by: Jan Beulich <jbeulich@suse.com>
+master commit: f4ef8a41b80831db2136bdaff9f946a1a4b051e7
+master date: 2023-02-21 15:08:05 +0100
+---
+ xen/arch/x86/cpu/microcode/amd.c | 11 ++++++++---
+ xen/arch/x86/cpu/microcode/core.c | 26 +++++++++++++++++---------
+ xen/arch/x86/cpu/microcode/intel.c | 10 +++++++---
+ xen/arch/x86/cpu/microcode/private.h | 3 ++-
+ 4 files changed, 34 insertions(+), 16 deletions(-)
+
+diff --git a/xen/arch/x86/cpu/microcode/amd.c b/xen/arch/x86/cpu/microcode/amd.c
+index 8195707ee1..ded8fe90e6 100644
+--- a/xen/arch/x86/cpu/microcode/amd.c
++++ b/xen/arch/x86/cpu/microcode/amd.c
+@@ -176,8 +176,8 @@ static enum microcode_match_result compare_revisions(
+ if ( new_rev > old_rev )
+ return NEW_UCODE;
+
+- if ( opt_ucode_allow_same && new_rev == old_rev )
+- return NEW_UCODE;
++ if ( new_rev == old_rev )
++ return SAME_UCODE;
+
+ return OLD_UCODE;
+ }
+@@ -220,8 +220,13 @@ static int cf_check apply_microcode(const struct microcode_patch *patch)
+ unsigned int cpu = smp_processor_id();
+ struct cpu_signature *sig = &per_cpu(cpu_sig, cpu);
+ uint32_t rev, old_rev = sig->rev;
++ enum microcode_match_result result = microcode_fits(patch);
+
+- if ( microcode_fits(patch) != NEW_UCODE )
++ /*
++ * 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 ( result != NEW_UCODE && result != SAME_UCODE )
+ return -EINVAL;
+
+ if ( check_final_patch_levels(sig) )
+diff --git a/xen/arch/x86/cpu/microcode/core.c b/xen/arch/x86/cpu/microcode/core.c
+index 452a7ca773..57ecc5358b 100644
+--- a/xen/arch/x86/cpu/microcode/core.c
++++ b/xen/arch/x86/cpu/microcode/core.c
+@@ -610,17 +610,25 @@ static long cf_check microcode_update_helper(void *data)
+ * that ucode revision.
+ */
+ spin_lock(&microcode_mutex);
+- if ( microcode_cache &&
+- alternative_call(ucode_ops.compare_patch,
+- patch, microcode_cache) != NEW_UCODE )
++ if ( microcode_cache )
+ {
+- spin_unlock(&microcode_mutex);
+- printk(XENLOG_WARNING "microcode: couldn't find any newer revision "
+- "in the provided blob!\n");
+- microcode_free_patch(patch);
+- ret = -ENOENT;
++ enum microcode_match_result result;
+
+- goto put;
++ result = alternative_call(ucode_ops.compare_patch, patch,
++ microcode_cache);
++
++ if ( result != NEW_UCODE &&
++ !(opt_ucode_allow_same && result == SAME_UCODE) )
++ {
++ spin_unlock(&microcode_mutex);
++ printk(XENLOG_WARNING
++ "microcode: couldn't find any newer%s revision in the provided blob!\n",
++ opt_ucode_allow_same ? " (or the same)" : "");
++ microcode_free_patch(patch);
++ ret = -ENOENT;
++
++ goto put;
++ }
+ }
+ spin_unlock(&microcode_mutex);
+
+diff --git a/xen/arch/x86/cpu/microcode/intel.c b/xen/arch/x86/cpu/microcode/intel.c
+index f5ba6d76d7..cb08f63d2e 100644
+--- a/xen/arch/x86/cpu/microcode/intel.c
++++ b/xen/arch/x86/cpu/microcode/intel.c
+@@ -232,8 +232,8 @@ static enum microcode_match_result compare_revisions(
+ if ( new_rev > old_rev )
+ return NEW_UCODE;
+
+- if ( opt_ucode_allow_same && new_rev == old_rev )
+- return NEW_UCODE;
++ if ( new_rev == old_rev )
++ return SAME_UCODE;
+
+ /*
+ * Treat pre-production as always applicable - anyone using pre-production
+@@ -290,8 +290,12 @@ static int cf_check apply_microcode(const struct microcode_patch *patch)
+ unsigned int cpu = smp_processor_id();
+ struct cpu_signature *sig = &this_cpu(cpu_sig);
+ uint32_t rev, old_rev = sig->rev;
++ enum microcode_match_result result;
++
++ result = microcode_update_match(patch);
+
+- if ( microcode_update_match(patch) != NEW_UCODE )
++ if ( result != NEW_UCODE &&
++ !(opt_ucode_allow_same && result == SAME_UCODE) )
+ return -EINVAL;
+
+ wbinvd();
+diff --git a/xen/arch/x86/cpu/microcode/private.h b/xen/arch/x86/cpu/microcode/private.h
+index c085a10268..feafab0677 100644
+--- a/xen/arch/x86/cpu/microcode/private.h
++++ b/xen/arch/x86/cpu/microcode/private.h
+@@ -6,7 +6,8 @@
+ extern bool opt_ucode_allow_same;
+
+ enum microcode_match_result {
+- OLD_UCODE, /* signature matched, but revision id is older or equal */
++ OLD_UCODE, /* signature matched, but revision id is older */
++ SAME_UCODE, /* signature matched, but revision id is the same */
+ NEW_UCODE, /* signature matched, but revision id is newer */
+ MIS_UCODE, /* signature mismatched */
+ };
+--
+2.40.0
+