#!/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 public release, wait for at least three months to ensure the update is stable, run this script to refresh the intel-ucode-defs.h file, and send a patch upstream to update the mainline and stable versions. As always, there can be exceptions to the above process which should be supported by appropriate justification. """ 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 return (val >> bottom) & mask 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) class Ucode: def __init__(self, sig, pfm, rev): self.sig = sig self.platforms = pfm self.rev = rev self.family = family(sig) self.model = model(sig) self.steppings = 1 << step(sig) self.key = (self.family, self.model, self.steppings, self.platforms) def __eq__(self, other): return self.key == other.key def __hash__(self): return hash(self.key) def __str__(self): return "{ .flags = X86_CPU_ID_FLAG_ENTRY_VALID, .vendor = X86_VENDOR_INTEL, .family = 0x%x, .model = 0x%02x, .steppings = 0x%04x, .platform_mask = 0x%02x, .driver_data = 0x%x }," % \ (self.family, self.model, self.steppings, self.platforms, self.rev) ucodes = set() # Parse the output of iucode-tool 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) pfm = re.search('pf_mask (0x[0-9a-fA-F]+)', line).group(1) sig = int(sig, 16) rev = int(rev, 16) pfm = int(pfm, 16) debug_rev = bits(rev, 31, 31) if debug_rev != 0: print("Error: Debug ucode file found, exiting", file=sys.stderr) sys.exit(1) ucodes.add(Ucode(sig, pfm, rev)) if not ucodes: print("Error: No valid microcode files found, exiting", file=sys.stderr) sys.exit(1) # Sort and print the microcode entries for u in sorted(ucodes, key=lambda x: x.key): print(u)