aboutsummaryrefslogtreecommitdiffstats
path: root/roms/u-boot/tools/microcode-tool.py
diff options
context:
space:
mode:
authorAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
committerAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
commitaf1a266670d040d2f4083ff309d732d648afba2a (patch)
tree2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/u-boot/tools/microcode-tool.py
parente02cda008591317b1625707ff8e115a4841aa889 (diff)
Add submodule dependency filesHEADmaster
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/u-boot/tools/microcode-tool.py')
-rwxr-xr-xroms/u-boot/tools/microcode-tool.py316
1 files changed, 316 insertions, 0 deletions
diff --git a/roms/u-boot/tools/microcode-tool.py b/roms/u-boot/tools/microcode-tool.py
new file mode 100755
index 000000000..24c02c4fc
--- /dev/null
+++ b/roms/u-boot/tools/microcode-tool.py
@@ -0,0 +1,316 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (c) 2014 Google, Inc
+#
+# Intel microcode update tool
+
+from optparse import OptionParser
+import os
+import re
+import struct
+import sys
+
+MICROCODE_DIR = 'arch/x86/dts/microcode'
+
+class Microcode:
+ """Holds information about the microcode for a particular model of CPU.
+
+ Attributes:
+ name: Name of the CPU this microcode is for, including any version
+ information (e.g. 'm12206a7_00000029')
+ model: Model code string (this is cpuid(1).eax, e.g. '206a7')
+ words: List of hex words containing the microcode. The first 16 words
+ are the public header.
+ """
+ def __init__(self, name, data):
+ self.name = name
+ # Convert data into a list of hex words
+ self.words = []
+ for value in ''.join(data).split(','):
+ hexval = value.strip()
+ if hexval:
+ self.words.append(int(hexval, 0))
+
+ # The model is in the 4rd hex word
+ self.model = '%x' % self.words[3]
+
+def ParseFile(fname):
+ """Parse a micrcode.dat file and return the component parts
+
+ Args:
+ fname: Filename to parse
+ Returns:
+ 3-Tuple:
+ date: String containing date from the file's header
+ license_text: List of text lines for the license file
+ microcodes: List of Microcode objects from the file
+ """
+ re_date = re.compile('/\* *(.* [0-9]{4}) *\*/$')
+ re_license = re.compile('/[^-*+] *(.*)$')
+ re_name = re.compile('/\* *(.*)\.inc *\*/', re.IGNORECASE)
+ microcodes = {}
+ license_text = []
+ date = ''
+ data = []
+ name = None
+ with open(fname) as fd:
+ for line in fd:
+ line = line.rstrip()
+ m_date = re_date.match(line)
+ m_license = re_license.match(line)
+ m_name = re_name.match(line)
+ if m_name:
+ if name:
+ microcodes[name] = Microcode(name, data)
+ name = m_name.group(1).lower()
+ data = []
+ elif m_license:
+ license_text.append(m_license.group(1))
+ elif m_date:
+ date = m_date.group(1)
+ else:
+ data.append(line)
+ if name:
+ microcodes[name] = Microcode(name, data)
+ return date, license_text, microcodes
+
+def ParseHeaderFiles(fname_list):
+ """Parse a list of header files and return the component parts
+
+ Args:
+ fname_list: List of files to parse
+ Returns:
+ date: String containing date from the file's header
+ license_text: List of text lines for the license file
+ microcodes: List of Microcode objects from the file
+ """
+ microcodes = {}
+ license_text = []
+ date = ''
+ name = None
+ for fname in fname_list:
+ name = os.path.basename(fname).lower()
+ name = os.path.splitext(name)[0]
+ data = []
+ with open(fname) as fd:
+ license_start = False
+ license_end = False
+ for line in fd:
+ line = line.rstrip()
+
+ if len(line) >= 2:
+ if line[0] == '/' and line[1] == '*':
+ license_start = True
+ continue
+ if line[0] == '*' and line[1] == '/':
+ license_end = True
+ continue
+ if license_start and not license_end:
+ # Ignore blank line
+ if len(line) > 0:
+ license_text.append(line)
+ continue
+ # Omit anything after the last comma
+ words = line.split(',')[:-1]
+ data += [word + ',' for word in words]
+ microcodes[name] = Microcode(name, data)
+ return date, license_text, microcodes
+
+
+def List(date, microcodes, model):
+ """List the available microcode chunks
+
+ Args:
+ date: Date of the microcode file
+ microcodes: Dict of Microcode objects indexed by name
+ model: Model string to search for, or None
+ """
+ print('Date: %s' % date)
+ if model:
+ mcode_list, tried = FindMicrocode(microcodes, model.lower())
+ print('Matching models %s:' % (', '.join(tried)))
+ else:
+ print('All models:')
+ mcode_list = [microcodes[m] for m in list(microcodes.keys())]
+ for mcode in mcode_list:
+ print('%-20s: model %s' % (mcode.name, mcode.model))
+
+def FindMicrocode(microcodes, model):
+ """Find all the microcode chunks which match the given model.
+
+ This model is something like 306a9 (the value returned in eax from
+ cpuid(1) when running on Intel CPUs). But we allow a partial match,
+ omitting the last 1 or two characters to allow many families to have the
+ same microcode.
+
+ If the model name is ambiguous we return a list of matches.
+
+ Args:
+ microcodes: Dict of Microcode objects indexed by name
+ model: String containing model name to find
+ Returns:
+ Tuple:
+ List of matching Microcode objects
+ List of abbreviations we tried
+ """
+ # Allow a full name to be used
+ mcode = microcodes.get(model)
+ if mcode:
+ return [mcode], []
+
+ tried = []
+ found = []
+ for i in range(3):
+ abbrev = model[:-i] if i else model
+ tried.append(abbrev)
+ for mcode in list(microcodes.values()):
+ if mcode.model.startswith(abbrev):
+ found.append(mcode)
+ if found:
+ break
+ return found, tried
+
+def CreateFile(date, license_text, mcodes, outfile):
+ """Create a microcode file in U-Boot's .dtsi format
+
+ Args:
+ date: String containing date of original microcode file
+ license: List of text lines for the license file
+ mcodes: Microcode objects to write (normally only 1)
+ outfile: Filename to write to ('-' for stdout)
+ """
+ out = '''/*%s
+ * ---
+ * This is a device tree fragment. Use #include to add these properties to a
+ * node.
+ *
+ * Date: %s
+ */
+
+compatible = "intel,microcode";
+intel,header-version = <%d>;
+intel,update-revision = <%#x>;
+intel,date-code = <%#x>;
+intel,processor-signature = <%#x>;
+intel,checksum = <%#x>;
+intel,loader-revision = <%d>;
+intel,processor-flags = <%#x>;
+
+/* The first 48-bytes are the public header which repeats the above data */
+data = <%s
+\t>;'''
+ words = ''
+ add_comments = len(mcodes) > 1
+ for mcode in mcodes:
+ if add_comments:
+ words += '\n/* %s */' % mcode.name
+ for i in range(len(mcode.words)):
+ if not (i & 3):
+ words += '\n'
+ val = mcode.words[i]
+ # Change each word so it will be little-endian in the FDT
+ # This data is needed before RAM is available on some platforms so
+ # we cannot do an endianness swap on boot.
+ val = struct.unpack("<I", struct.pack(">I", val))[0]
+ words += '\t%#010x' % val
+
+ # Use the first microcode for the headers
+ mcode = mcodes[0]
+
+ # Take care to avoid adding a space before a tab
+ text = ''
+ for line in license_text:
+ if line[0] == '\t':
+ text += '\n *' + line
+ else:
+ text += '\n * ' + line
+ args = [text, date]
+ args += [mcode.words[i] for i in range(7)]
+ args.append(words)
+ if outfile == '-':
+ print(out % tuple(args))
+ else:
+ if not outfile:
+ if not os.path.exists(MICROCODE_DIR):
+ print("Creating directory '%s'" % MICROCODE_DIR, file=sys.stderr)
+ os.makedirs(MICROCODE_DIR)
+ outfile = os.path.join(MICROCODE_DIR, mcode.name + '.dtsi')
+ print("Writing microcode for '%s' to '%s'" % (
+ ', '.join([mcode.name for mcode in mcodes]), outfile), file=sys.stderr)
+ with open(outfile, 'w') as fd:
+ print(out % tuple(args), file=fd)
+
+def MicrocodeTool():
+ """Run the microcode tool"""
+ commands = 'create,license,list'.split(',')
+ parser = OptionParser()
+ parser.add_option('-d', '--mcfile', type='string', action='store',
+ help='Name of microcode.dat file')
+ parser.add_option('-H', '--headerfile', type='string', action='append',
+ help='Name of .h file containing microcode')
+ parser.add_option('-m', '--model', type='string', action='store',
+ help="Model name to extract ('all' for all)")
+ parser.add_option('-M', '--multiple', type='string', action='store',
+ help="Allow output of multiple models")
+ parser.add_option('-o', '--outfile', type='string', action='store',
+ help='Filename to use for output (- for stdout), default is'
+ ' %s/<name>.dtsi' % MICROCODE_DIR)
+ parser.usage += """ command
+
+ Process an Intel microcode file (use -h for help). Commands:
+
+ create Create microcode .dtsi file for a model
+ list List available models in microcode file
+ license Print the license
+
+ Typical usage:
+
+ ./tools/microcode-tool -d microcode.dat -m 306a create
+
+ This will find the appropriate file and write it to %s.""" % MICROCODE_DIR
+
+ (options, args) = parser.parse_args()
+ if not args:
+ parser.error('Please specify a command')
+ cmd = args[0]
+ if cmd not in commands:
+ parser.error("Unknown command '%s'" % cmd)
+
+ if (not not options.mcfile) != (not not options.mcfile):
+ parser.error("You must specify either header files or a microcode file, not both")
+ if options.headerfile:
+ date, license_text, microcodes = ParseHeaderFiles(options.headerfile)
+ elif options.mcfile:
+ date, license_text, microcodes = ParseFile(options.mcfile)
+ else:
+ parser.error('You must specify a microcode file (or header files)')
+
+ if cmd == 'list':
+ List(date, microcodes, options.model)
+ elif cmd == 'license':
+ print('\n'.join(license_text))
+ elif cmd == 'create':
+ if not options.model:
+ parser.error('You must specify a model to create')
+ model = options.model.lower()
+ if options.model == 'all':
+ options.multiple = True
+ mcode_list = list(microcodes.values())
+ tried = []
+ else:
+ mcode_list, tried = FindMicrocode(microcodes, model)
+ if not mcode_list:
+ parser.error("Unknown model '%s' (%s) - try 'list' to list" %
+ (model, ', '.join(tried)))
+ if not options.multiple and len(mcode_list) > 1:
+ parser.error("Ambiguous model '%s' (%s) matched %s - try 'list' "
+ "to list or specify a particular file" %
+ (model, ', '.join(tried),
+ ', '.join([m.name for m in mcode_list])))
+ CreateFile(date, license_text, mcode_list, options.outfile)
+ else:
+ parser.error("Unknown command '%s'" % cmd)
+
+if __name__ == "__main__":
+ MicrocodeTool()