
Hi Bin,
On 16 December 2014 at 01:04, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Tue, Dec 16, 2014 at 1:02 PM, Simon Glass sjg@chromium.org wrote:
Intel delivers microcode updates in a microcode.dat file which must be split up into individual files for each CPU. Add a tool which performs this task. It can list available microcode updates for each model and produce a new microcode update in U-Boot's .dtsi format.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Add function comments
- Fix problem with specifying the full microcode filename
- Allow 'list' command to display a list of matching microcode chunks
- Print a message when generating microcode
- Expand the help a little
- Print an error when an ambiguous microcode model is given
tools/microcode-tool | 1 + tools/microcode-tool.py | 245 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 246 insertions(+) create mode 120000 tools/microcode-tool create mode 100755 tools/microcode-tool.py
diff --git a/tools/microcode-tool b/tools/microcode-tool new file mode 120000 index 0000000..8be8507 --- /dev/null +++ b/tools/microcode-tool @@ -0,0 +1 @@ +microcode-tool.py \ No newline at end of file diff --git a/tools/microcode-tool.py b/tools/microcode-tool.py new file mode 100755 index 0000000..5dbb0db --- /dev/null +++ b/tools/microcode-tool.py @@ -0,0 +1,245 @@ +#!/usr/bin/env python +# +# Copyright (c) 2014 Google, Inc +# +# SPDX-License-Identifier: GPL-2.0+ +# +# +# 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: 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 = []
- 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.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, 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 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 microcodes.values():
if mcode.model.startswith(abbrev):
found.append(mcode)
if found:
break
- return found, tried
+def CreateFile(date, license, mcode, 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
mcode: Microcode object to write
outfile: Filename to write to ('-' for stdout)
- """
- out = '''/*%s
- This is a device tree fragment. Use #include to add these properties to a
- node.
- */
+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 = ''
- 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
- # Take care to avoid adding a space before a tab
- text = ''
- for line in license:
if line[0] == '\t':
text += '\n *' + line
else:
text += '\n * ' + line
- args = [text]
- args += [mcode.words[i] for i in range(7)]
- args.append(words)
- if outfile == '-':
print out % tuple(args)
- else:
if not outfile:
outfile = os.path.join(MICROCODE_DIR, mcode.name + '.dtsi')
print >>sys.stderr, "Writing micrcode for '%s' to '%s'" % (
mcode.name, outfile)
with open(outfile, 'w') as fd:
print >>fd, out % tuple(args)
+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('-m', '--model', type='string', action='store',
help='Model name to extract')
+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 options.mcfile:
- parser.error('You must specify a microcode file')
+date, license, microcodes = ParseFile(options.mcfile)
+if cmd == 'list':
- List(date, microcodes, options.model)
+elif cmd == 'license':
- print '\n'.join(license)
+elif cmd == 'create':
- if not options.model:
parser.error('You must specify a model to create')
- model = options.model.lower()
- mcode_list, tried = FindMicrocode(microcodes, model)
- if not mcode_list:
parser.error("Unknown model '%s' (%s) - try 'list' to list" %
(model, ', '.join(tried)))
- if 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, mcode_list[0], options.outfile)
+else:
- parser.error("Unknown command '%s'" % cmd)
--
$ ./tools/microcode-tool -d microcode.dat -m m0220661105_cv create Writing micrcode for 'm0220661105_cv' to 'arch/x86/dts/microcode/m0220661105_cv.dtsi' Traceback (most recent call last): File "./tools/microcode-tool", line 243, in <module> CreateFile(date, license, mcode_list[0], options.outfile) File "./tools/microcode-tool", line 188, in CreateFile with open(outfile, 'w') as fd: IOError: [Errno 2] No such file or directory: 'arch/x86/dts/microcode/m0220661105_cv.dtsi'
My understanding is that when calling microcode-tool without '-o' option, a default dtsi file will be created in arch/x86/dts/microcode/ directory with the model number as the file name. However testing above shows some python error. Could you please either print some user friendly message, or just create a default dtsi file?
I think it just needs to create the directory automatically. In my tree it already has this directory. The message seems OK to me though. I'll fix up the script a bit more.
Regards, Simon