summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--xen/arch/x86/cpu/microcode/amd.c11
-rw-r--r--xen/arch/x86/cpu/microcode/core.c24
-rw-r--r--xen/arch/x86/cpu/microcode/intel.c10
-rw-r--r--xen/arch/x86/cpu/microcode/private.h3
4 files changed, 33 insertions, 15 deletions
diff --git a/xen/arch/x86/cpu/microcode/amd.c b/xen/arch/x86/cpu/microcode/amd.c
index fe92e594f1..52182c1a23 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 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 ac3ceb567c..ceec1f1edc 100644
--- a/xen/arch/x86/cpu/microcode/core.c
+++ b/xen/arch/x86/cpu/microcode/core.c
@@ -608,16 +608,24 @@ static long microcode_update_helper(void *data)
* that ucode revision.
*/
spin_lock(&microcode_mutex);
- if ( microcode_cache &&
- microcode_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 = microcode_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 f6d01490e0..c26fbb8cc7 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 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 */
};