| #!/usr/bin/env 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. | |
| Any exception to this process should be supported with an appropriate | |
| justification. | |
| """ | |
| SIG_RE = re.compile(r'sig (0x[0-9a-fA-F]+)') | |
| PFM_RE = re.compile(r'pf_mask (0x[0-9a-fA-F]+)') | |
| REV_RE = re.compile(r'rev (0x[0-9a-fA-F]+)') | |
| # 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.family = family(sig) | |
| self.model = model(sig) | |
| self.steppings = 1 << step(sig) | |
| self.platforms = pfm | |
| self.rev = rev | |
| 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) | |
| def main(): | |
| 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 | |
| iucode_tool = shutil.which("iucode-tool") or shutil.which("iucode_tool") | |
| if iucode_tool is None: | |
| print("Error: iucode-tool not found, please install it", file=sys.stderr) | |
| sys.exit(1) | |
| cmd = [iucode_tool, '--list-all'] + args.ucode_files | |
| result = subprocess.run(cmd, capture_output=True, text=True) | |
| if result.returncode != 0: | |
| print("Error: iucode-tool ran into an error, exiting", file=sys.stderr) | |
| if result.stderr: | |
| print(result.stderr, file=sys.stderr, end='') | |
| sys.exit(1) | |
| ucodes = set() | |
| # Parse the output of iucode-tool | |
| for line in result.stdout.splitlines(): | |
| sig_match = SIG_RE.search(line) | |
| pfm_match = PFM_RE.search(line) | |
| rev_match = REV_RE.search(line) | |
| if not (sig_match and pfm_match and rev_match): | |
| continue | |
| sig = int(sig_match.group(1), 16) | |
| pfm = int(pfm_match.group(1), 16) | |
| rev = int(rev_match.group(1), 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 | |
| print("/* SPDX-License-Identifier: GPL-2.0 */") | |
| print("/* Auto-generated by scripts/update-intel-ucode-defs.py */") | |
| for u in sorted(ucodes, key=lambda x: x.key): | |
| print(u) | |
| if __name__ == "__main__": | |
| main() |