1#!/usr/bin/env python3 2# SPDX-License-Identifier: GPL-2.0 3import argparse 4import re 5import shutil 6import subprocess 7import sys 8import os 9 10script = os.path.relpath(__file__) 11 12DESCRIPTION = f""" 13For Intel CPUs, update the microcode revisions that determine 14X86_BUG_OLD_MICROCODE. 15 16This script is intended to be run in response to releases of the 17official Intel microcode GitHub repository: 18https://github.com/intel/Intel-Linux-Processor-Microcode-Data-Files.git 19 20It takes the Intel microcode files as input and uses iucode-tool to 21extract the revision information. It prints the output in the format 22expected by intel-ucode-defs.h. 23 24Usage: 25 ./{script} /path/to/microcode/files > /path/to/intel-ucode-defs.h 26 27Typically, someone at Intel would see a new public release, wait for at 28least three months to ensure the update is stable, run this script to 29refresh the intel-ucode-defs.h file, and send a patch upstream to update 30the mainline and stable versions. 31 32Any exception to this process should be supported with an appropriate 33justification. 34""" 35 36SIG_RE = re.compile(r'sig (0x[0-9a-fA-F]+)') 37PFM_RE = re.compile(r'pf_mask (0x[0-9a-fA-F]+)') 38REV_RE = re.compile(r'rev (0x[0-9a-fA-F]+)') 39 40# Functions to extract family, model, and stepping 41def bits(val, bottom, top): 42 mask = (1 << (top + 1 - bottom)) - 1 43 return (val >> bottom) & mask 44 45def family(sig): 46 if bits(sig, 8, 11) == 0xf: 47 return bits(sig, 8, 11) + bits(sig, 20, 27) 48 return bits(sig, 8, 11) 49 50def model(sig): 51 return bits(sig, 4, 7) | (bits(sig, 16, 19) << 4) 52 53def step(sig): 54 return bits(sig, 0, 3) 55 56class Ucode: 57 def __init__(self, sig, pfm, rev): 58 self.family = family(sig) 59 self.model = model(sig) 60 self.steppings = 1 << step(sig) 61 self.platforms = pfm 62 self.rev = rev 63 64 self.key = (self.family, self.model, self.steppings, self.platforms) 65 66 def __eq__(self, other): 67 return self.key == other.key 68 69 def __hash__(self): 70 return hash(self.key) 71 72 def __str__(self): 73 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 }," % \ 74 (self.family, self.model, self.steppings, self.platforms, self.rev) 75 76def main(): 77 parser = argparse.ArgumentParser(description=DESCRIPTION, 78 formatter_class=argparse.RawDescriptionHelpFormatter) 79 parser.add_argument('ucode_files', nargs='+', help='Path(s) to the microcode files') 80 81 args = parser.parse_args() 82 83 # Process the microcode files using iucode-tool 84 iucode_tool = shutil.which("iucode-tool") or shutil.which("iucode_tool") 85 if iucode_tool is None: 86 print("Error: iucode-tool not found, please install it", file=sys.stderr) 87 sys.exit(1) 88 89 cmd = [iucode_tool, '--list-all'] + args.ucode_files 90 91 result = subprocess.run(cmd, capture_output=True, text=True) 92 if result.returncode != 0: 93 print("Error: iucode-tool ran into an error, exiting", file=sys.stderr) 94 if result.stderr: 95 print(result.stderr, file=sys.stderr, end='') 96 sys.exit(1) 97 98 ucodes = set() 99 100 # Parse the output of iucode-tool 101 for line in result.stdout.splitlines(): 102 sig_match = SIG_RE.search(line) 103 pfm_match = PFM_RE.search(line) 104 rev_match = REV_RE.search(line) 105 106 if not (sig_match and pfm_match and rev_match): 107 continue 108 109 sig = int(sig_match.group(1), 16) 110 pfm = int(pfm_match.group(1), 16) 111 rev = int(rev_match.group(1), 16) 112 debug_rev = bits(rev, 31, 31) 113 if debug_rev != 0: 114 print("Error: Debug ucode file found, exiting", file=sys.stderr) 115 sys.exit(1) 116 117 ucodes.add(Ucode(sig, pfm, rev)) 118 119 if not ucodes: 120 print("Error: No valid microcode files found, exiting", file=sys.stderr) 121 sys.exit(1) 122 123 # Sort and print the microcode entries 124 print("/* SPDX-License-Identifier: GPL-2.0 */") 125 print("/* Auto-generated by scripts/update-intel-ucode-defs.py */") 126 for u in sorted(ucodes, key=lambda x: x.key): 127 print(u) 128 129if __name__ == "__main__": 130 main() 131