| 1 | |
| 2 | |
| 3 | import argparse
|
| 4 | import re
|
| 5 | import shutil
|
| 6 | import subprocess
|
| 7 | import sys
|
| 8 | import os
|
| 9 |
|
| 10 | script = os.path.relpath(__file__)
|
| 11 |
|
| 12 | DESCRIPTION = f"""
|
| 13 | For Intel CPUs, update the microcode revisions that determine
|
| 14 | X86_BUG_OLD_MICROCODE.
|
| 15 |
|
| 16 | This script is intended to be run in response to releases of the
|
| 17 | official Intel microcode GitHub repository:
|
| 18 | https://github.com/intel/Intel-Linux-Processor-Microcode-Data-Files.git
|
| 19 |
|
| 20 | It takes the Intel microcode files as input and uses iucode-tool to
|
| 21 | extract the revision information. It prints the output in the format
|
| 22 | expected by intel-ucode-defs.h.
|
| 23 |
|
| 24 | Usage:
|
| 25 | ./{script} /path/to/microcode/files > /path/to/intel-ucode-defs.h
|
| 26 |
|
| 27 | Typically, someone at Intel would see a new public release, wait for at
|
| 28 | least three months to ensure the update is stable, run this script to
|
| 29 | refresh the intel-ucode-defs.h file, and send a patch upstream to update
|
| 30 | the mainline and stable versions.
|
| 31 |
|
| 32 | Any exception to this process should be supported with an appropriate
|
| 33 | justification.
|
| 34 | """
|
| 35 |
|
| 36 | SIG_RE = re.compile(r'sig (0x[0-9a-fA-F]+)')
|
| 37 | PFM_RE = re.compile(r'pf_mask (0x[0-9a-fA-F]+)')
|
| 38 | REV_RE = re.compile(r'rev (0x[0-9a-fA-F]+)')
|
| 39 |
|
| 40 | |
| 41 | def bits(val, bottom, top):
|
| 42 | mask = (1 << (top + 1 - bottom)) - 1
|
| 43 | return (val >> bottom) & mask
|
| 44 |
|
| 45 | def 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 |
|
| 50 | def model(sig):
|
| 51 | return bits(sig, 4, 7) | (bits(sig, 16, 19) << 4)
|
| 52 |
|
| 53 | def step(sig):
|
| 54 | return bits(sig, 0, 3)
|
| 55 |
|
| 56 | class 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 |
|
| 76 | def 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 | |
| 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 | |
| 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 | |
| 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 |
|
| 129 | if __name__ == "__main__":
|
| 130 | main()
|