xref: /linux/scripts/update-intel-ucode-defs.py (revision 0eaed89c18aeedf0898baf2dbf5ff027c6795152)
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