[<prev] [next>] [day] [month] [year] [list]
Message-ID: <20250825171510.3332029-1-sohil.mehta@intel.com>
Date: Mon, 25 Aug 2025 10:15:10 -0700
From: Sohil Mehta <sohil.mehta@...el.com>
To: Dave Hansen <dave.hansen@...ux.intel.com>,
Borislav Petkov <bp@...en8.de>,
x86@...nel.org
Cc: 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 v3] 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.
The static list of microcode revisions needs to be updated periodically
in response to releases of the official microcode at:
https://github.com/intel/Intel-Linux-Processor-Microcode-Data-Files.git.
Introduce a simple script to extract the revision information from the
microcode files and print it in the precise format expected by the
microcode header. Having the script in the kernel mainly makes it easier
to update the header whenever needed.
Typically, someone at Intel would see a new public release, run this
script, refresh the intel-ucode-defs.h file and send a patch upstream to
update the mainline and stable versions.
Originally-by: Dave Hansen <dave.hansen@...ux.intel.com>
Signed-off-by: Sohil Mehta <sohil.mehta@...el.com>
---
v3:
- Include motivation for having the script in the kernel. (Boris)
- Update instructions to clarify typical usage. (Boris)
v2: https://lore.kernel.org/lkml/20250822004422.2908427-1-sohil.mehta@intel.com/
- Remove the extra command line arguments. (DaveH)
- Print to stdout instead of directly updating the header file. (DaveH)
- Take multiple directories as input. (DaveH)
---
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..14954e5e33c2
--- /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.
+
+This script is intended to be run in response to releases of the
+official Intel microcode GitHub repository:
+https://github.com/intel/Intel-Linux-Processor-Microcode-Data-Files.git
+
+It takes the Intel microcode files as input and uses iucode-tool to
+extract the revision information. It prints the output in the format
+expected by intel-ucode-defs.h.
+
+Usage:
+ ./{script} /path/to/microcode/files > /path/to/intel-ucode-defs.h
+
+Typically, someone at Intel would see a new release, run this script,
+refresh the intel-ucode-defs.h file, and send a patch upstream to update
+the mainline and stable versions.
+"""
+
+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