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