[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250822004422.2908427-1-sohil.mehta@intel.com>
Date: Thu, 21 Aug 2025 17:44:22 -0700
From: Sohil Mehta <sohil.mehta@...el.com>
To: Dave Hansen <dave.hansen@...ux.intel.com>,
x86@...nel.org
Cc: Borislav Petkov <bp@...en8.de>,
Thomas Gleixner <tglx@...utronix.de>,
Ingo Molnar <mingo@...hat.com>,
"H . Peter Anvin" <hpa@...or.com>,
Peter Zijlstra <peterz@...radead.org>,
Josh Poimboeuf <jpoimboe@...nel.org>,
Pawan Gupta <pawan.kumar.gupta@...ux.intel.com>,
Dave Hansen <dave.hansen@...el.com>,
Nikolay Borisov <nik.borisov@...e.com>,
Andrew Cooper <andrew.cooper3@...rix.com>,
Sohil Mehta <sohil.mehta@...el.com>,
linux-kernel@...r.kernel.org
Subject: [PATCH v2] scripts/x86/intel: Add a script to update the minimum ucode revisions
The kernel maintains a table of minimum expected microcode revisions for
Intel CPUs in intel-ucode-defs.h. Systems with microcode older than
these revisions are flagged with X86_BUG_OLD_MICROCODE. For more
details, refer to Documentation/admin-guide/hw-vuln/old_microcode.rst.
Add a simple script to keep the header file up-to-date based on released
microcode updates.
Originally-by: Dave Hansen <dave.hansen@...ux.intel.com>
Signed-off-by: Sohil Mehta <sohil.mehta@...el.com>
---
v2:
- Remove the extra command line arguments.
- Print to stdout instead of directly updating the header file.
- Take multiple directories as input.
v1: https://lore.kernel.org/lkml/20250818190137.3525414-1-sohil.mehta@intel.com/
---
MAINTAINERS | 1 +
scripts/update-intel-ucode-defs.py | 118 +++++++++++++++++++++++++++++
2 files changed, 119 insertions(+)
create mode 100755 scripts/update-intel-ucode-defs.py
diff --git a/MAINTAINERS b/MAINTAINERS
index daf520a13bdf..a819559ec672 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -27260,6 +27260,7 @@ S: Maintained
F: Documentation/admin-guide/hw-vuln/
F: arch/x86/include/asm/nospec-branch.h
F: arch/x86/kernel/cpu/bugs.c
+F: scripts/update-intel-ucode-defs.py
X86 MCE INFRASTRUCTURE
M: Tony Luck <tony.luck@...el.com>
diff --git a/scripts/update-intel-ucode-defs.py b/scripts/update-intel-ucode-defs.py
new file mode 100755
index 000000000000..96e91640033a
--- /dev/null
+++ b/scripts/update-intel-ucode-defs.py
@@ -0,0 +1,118 @@
+#!/usr/bin/python3
+# SPDX-License-Identifier: GPL-2.0
+import argparse
+import re
+import shutil
+import subprocess
+import sys
+import os
+
+script = os.path.relpath(__file__)
+
+DESCRIPTION = f"""
+For Intel CPUs, update the microcode revisions that determine
+X86_BUG_OLD_MICROCODE.
+
+The script takes the Intel microcode files as input and uses the
+iucode-tool to extract the revision information. It prints the output in
+the format expected by intel-ucode-defs.h.
+
+A typical usage is to get the desired release of the Intel Microcode
+Update Package at:
+https://github.com/intel/Intel-Linux-Processor-Microcode-Data-Files.git
+
+And run:
+ ./{script} /path/to/microcode/files > /path/to/intel-ucode-defs.h
+
+Note: The microcode revisions are usually updated shortly after a new
+microcode package is released, allowing a reasonable time for systems to
+get the update.
+"""
+
+parser = argparse.ArgumentParser(description=DESCRIPTION,
+ formatter_class=argparse.RawDescriptionHelpFormatter)
+parser.add_argument('ucode_files', nargs='+', help='Path(s) to the microcode files')
+
+args = parser.parse_args()
+
+# Process the microcode files using iucode-tool
+if shutil.which("iucode-tool") is None:
+ print("Error: iucode-tool not found, please install it", file=sys.stderr)
+ sys.exit(1)
+
+cmd = ['iucode-tool', '--list-all' ]
+cmd.extend(args.ucode_files)
+
+process = subprocess.Popen(cmd, stdout=subprocess.PIPE, universal_newlines=True)
+process.wait()
+if process.returncode != 0:
+ print("Error: iucode-tool ran into an error, exiting", file=sys.stderr)
+ sys.exit(1)
+
+# Functions to extract family, model, and stepping
+def bits(val, bottom, top):
+ mask = (1 << (top + 1 - bottom)) - 1
+ mask = mask << bottom
+ return (val & mask) >> bottom
+
+def family(sig):
+ if bits(sig, 8, 11) == 0xf:
+ return bits(sig, 8, 11) + bits(sig, 20, 27)
+ return bits(sig, 8, 11)
+
+def model(sig):
+ return bits(sig, 4, 7) | (bits(sig, 16, 19) << 4)
+
+def step(sig):
+ return bits(sig, 0, 3)
+
+# Parse the output of iucode-tool
+siglist = []
+for line in process.stdout:
+ if line.find(" sig ") == -1:
+ continue
+ sig = re.search('sig (0x[0-9a-fA-F]+)', line).group(1)
+ rev = re.search('rev (0x[0-9a-fA-F]+)', line).group(1)
+ sig = int(sig, 16)
+ rev = int(rev, 16)
+ debug_rev = bits(rev, 31, 31)
+ if debug_rev != 0:
+ print("Error: Debug ucode file found, exiting", file=sys.stderr)
+ sys.exit(1);
+
+ sigrev = {}
+ sigrev['sig'] = sig
+ sigrev['rev'] = rev
+ siglist = siglist + [ sigrev ]
+
+# Remove duplicates, if any
+sigdict = {}
+for sr in siglist:
+ existing = sigdict.get(sr['sig'])
+ if existing != None:
+ # If the existing one is newer, just move on:
+ if existing['rev'] > sr['rev']:
+ continue
+ sigdict[sr['sig']] = sr
+
+# Prepare the microcode entries
+ucode_entries = []
+for sig in sigdict:
+ rev = sigdict[sig]
+ ucode_entries.append({
+ 'family': family(sig),
+ 'model': model(sig),
+ 'steppings': 1 << step(sig),
+ 'rev': rev['rev'],
+ 'sig': sig
+ })
+
+if not ucode_entries:
+ print("Error: No valid microcode files found, exiting", file=sys.stderr)
+ sys.exit(1)
+
+# Sort and print the microcode entries
+ucode_entries.sort(key=lambda x: (x['family'], x['model'], x['steppings']))
+for entry in ucode_entries:
+ print("{ .flags = X86_CPU_ID_FLAG_ENTRY_VALID, .vendor = X86_VENDOR_INTEL, .family = 0x%x, .model = 0x%02x, .steppings = 0x%04x, .driver_data = 0x%x }," %
+ (entry['family'], entry['model'], entry['steppings'], entry['rev']))
--
2.43.0
Powered by blists - more mailing lists