aboutsummaryrefslogtreecommitdiffstats
path: root/scripts/update-intel-ucode-defs.py
blob: 9d6cc2c6075fe1322126c29fb9d2ecb57886e975 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#!/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()