All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Chang S. Bae" <chang.seok.bae@intel.com>
To: linux-kernel@vger.kernel.org
Cc: x86@kernel.org, tglx@kernel.org, mingo@redhat.com, bp@alien8.de,
	dave.hansen@linux.intel.com, hpa@zytor.com,
	chang.seok.bae@intel.com
Subject: [PATCH v2] x86/microcode/intel: Taint kernel on partial update
Date: Wed,  8 Jul 2026 21:18:03 +0000	[thread overview]
Message-ID: <20260708211803.402467-1-chang.seok.bae@intel.com> (raw)
In-Reply-To: <20260630191350.3837-1-chang.seok.bae@intel.com>

A modern individual microcode update contains firmware for many pieces of
silicon inside the CPU. Sometimes, a single update operation successfully
updates some components and not others leaving a partially-applied
update.

This may leave the system in an undefined and unreliable state. Fatal
failures are expected to be handled by the CPU itself, by raising #MC for
example. If the CPU instead reports a partial update, warn and taint the
kernel at least.

A partial update may still update the revision. Continue checking the
revision rather than an immediate error return so the update result
remains consistent with the revision changes.

Signed-off-by: Chang S. Bae <chang.seok.bae@intel.com>
---
V1 -> V2: Do not raise panic, inline cpuid check and massage the changelog (Dave)
---
 arch/x86/include/asm/msr-index.h      |  4 +++
 arch/x86/kernel/cpu/microcode/intel.c | 37 +++++++++++++++++++++++++++
 2 files changed, 41 insertions(+)

diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index 18c4be75e927..7273d340470d 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -977,6 +977,10 @@
 #define MSR_IA32_MCU_ENUMERATION	0x0000007b
 #define MCU_STAGING			BIT(4)
 
+#define MSR_IA32_MCU_STATUS		0x0000007c
+#define MCU_PARTIAL_UPDATE		BIT(0)
+#define AUTH_FAIL_ON_MCU_COMPONENT	BIT(1)
+
 #define MSR_IA32_UCODE_REV		0x0000008b
 
 /* Intel SGX Launch Enclave Public Key Hash MSRs */
diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c
index f4a444e6114d..913b0b32e39b 100644
--- a/arch/x86/kernel/cpu/microcode/intel.c
+++ b/arch/x86/kernel/cpu/microcode/intel.c
@@ -69,6 +69,9 @@ static const char ucode_path[] = "kernel/x86/microcode/GenuineIntel.bin";
 
 #define MBOX_XACTION_TIMEOUT_MS	(10 * MSEC_PER_SEC)
 
+#define CPUID_EDX_ARCH_CAP	BIT(29)
+#define MCU_STATUS_FAILURE_MASK	(MCU_PARTIAL_UPDATE | AUTH_FAIL_ON_MCU_COMPONENT)
+
 /* 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;
@@ -679,6 +682,24 @@ static void stage_microcode(void)
 	pr_info("Staging of patch revision 0x%x succeeded.\n", ucode_patch_late->hdr.rev);
 }
 
+/*
+ * __apply_microcode() is the only caller which may be invoked in the early
+ * loading path. Use raw CPUID/RDMSR functions.
+ */
+static bool update_status_available(void)
+{
+	if (native_cpuid_eax(0) < 7)
+		return false;
+
+	if (!(native_cpuid_edx(7) & CPUID_EDX_ARCH_CAP))
+		return false;
+
+	if (!(native_rdmsrq(MSR_IA32_ARCH_CAPABILITIES) & ARCH_CAP_MCU_ENUM))
+		return false;
+
+	return true;
+}
+
 static enum ucode_state __apply_microcode(struct ucode_cpu_info *uci,
 					  struct microcode_intel *mc,
 					  u32 *cur_rev)
@@ -702,6 +723,22 @@ static enum ucode_state __apply_microcode(struct ucode_cpu_info *uci,
 	/* write microcode via MSR 0x79 */
 	native_wrmsrq(MSR_IA32_UCODE_WRITE, (unsigned long)mc->bits);
 
+	/*
+	 * Warn and taint the kernel on a partial update. Fatal conditions are
+	 * expected to be handled by the CPU itself.
+	 *
+	 * Then, continue checking the revision since a partial update may still
+	 * advance the microcode revision.
+	 */
+	if (update_status_available()) {
+		u64 status = native_rdmsrq(MSR_IA32_MCU_STATUS);
+
+		if (status & MCU_STATUS_FAILURE_MASK) {
+			pr_warn_once("update incomplete (MSR_IA32_MCU_STATUS=0x%llx).\n", status);
+			add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK);
+		}
+	}
+
 	rev = intel_get_microcode_revision();
 	if (rev != mc->hdr.rev)
 		return UCODE_ERROR;
-- 
2.51.0


      parent reply	other threads:[~2026-07-08 21:43 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-30 19:13 [PATCH] x86/microcode/intel: Panic on partial microcode update Chang S. Bae
2026-06-30 21:38 ` Dave Hansen
2026-06-30 21:47   ` Dave Hansen
2026-06-30 23:21     ` Borislav Petkov
2026-07-01 19:02     ` Chang S. Bae
2026-07-18 22:54     ` Maciej W. Rozycki
2026-07-19 15:52       ` Dave Hansen
2026-07-08 21:18 ` Chang S. Bae [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260708211803.402467-1-chang.seok.bae@intel.com \
    --to=chang.seok.bae@intel.com \
    --cc=bp@alien8.de \
    --cc=dave.hansen@linux.intel.com \
    --cc=hpa@zytor.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@redhat.com \
    --cc=tglx@kernel.org \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.