diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/Makefile | 1 | ||||
-rw-r--r-- | tools/buildman/README | 14 | ||||
-rw-r--r-- | tools/ifdtool.c | 161 | ||||
l--------- | tools/microcode-tool | 1 | ||||
-rwxr-xr-x | tools/microcode-tool.py | 253 |
5 files changed, 399 insertions, 31 deletions
diff --git a/tools/Makefile b/tools/Makefile index a4216a1..e549f8e 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -126,6 +126,7 @@ hostprogs-$(CONFIG_EXYNOS5250) += mkexynosspl hostprogs-$(CONFIG_EXYNOS5420) += mkexynosspl HOSTCFLAGS_mkexynosspl.o := -pedantic +ifdtool-objs := $(LIBFDT_OBJS) ifdtool.o hostprogs-$(CONFIG_X86) += ifdtool hostprogs-$(CONFIG_MX23) += mxsboot diff --git a/tools/buildman/README b/tools/buildman/README index bfb2f18..0f8ea20 100644 --- a/tools/buildman/README +++ b/tools/buildman/README @@ -42,7 +42,7 @@ Theory of Operation Buildman is a builder. It is not make, although it runs make. It does not produce any useful output on the terminal while building, except for progress information (except with -v, see below). All the output (errors, -warnings and binaries if you are ask for them) is stored in output +warnings and binaries if you ask for them) is stored in output directories, which you can look at while the build is progressing, or when it is finished. @@ -121,7 +121,7 @@ You can also use -x to specifically exclude some boards. For example: means to build all arm boards except nvidia, freescale and anything ending with 'ball'. -It is convenient to use the -n option to see whaat will be built based on +It is convenient to use the -n option to see what will be built based on the subset given. Buildman does not store intermediate object files. It optionally copies @@ -371,7 +371,7 @@ in an hour and 15 minutes. Use this time to buy a faster computer. To find out how the build went, ask for a summary with -s. You can do this -either before the build completes (presumably in another terminal) or or +either before the build completes (presumably in another terminal) or afterwards. Let's work through an example of how this is used: $ ./tools/buildman/buildman -b lcd9b -s @@ -439,7 +439,7 @@ again. At commit 16, the error moves - you can see that the old error at line 120 is fixed, but there is a new one at line 126. This is probably only because -we added some code and moved the broken line father down the file. +we added some code and moved the broken line further down the file. If many boards have the same error, then -e will display the error only once. This makes the output as concise as possible. To see which boards have @@ -647,8 +647,8 @@ This shows that commit 19 has increased text size for arm (although only one board was built) and by 96 bytes for powerpc. This increase was offset in both cases by reductions in rodata and data/bss. -Shown below the summary lines is the sizes for each board. Below each board -is the sizes for each function. This information starts with: +Shown below the summary lines are the sizes for each board. Below each board +are the sizes for each function. This information starts with: add - number of functions added / removed grow - number of functions which grew / shrunk @@ -817,7 +817,7 @@ TODO This has mostly be written in my spare time as a response to my difficulties in testing large series of patches. Apart from tidying up there is quite a bit of scope for improvement. Things like better error diffs and easier -access to log files. Also it would be nice it buildman could 'hunt' for +access to log files. Also it would be nice if buildman could 'hunt' for problems, perhaps by building a few boards for each arch, or checking commits for changed files and building only boards which use those files. diff --git a/tools/ifdtool.c b/tools/ifdtool.c index 4a27b82..fe8366b 100644 --- a/tools/ifdtool.c +++ b/tools/ifdtool.c @@ -18,6 +18,7 @@ #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> +#include <libfdt.h> #include "ifdtool.h" #undef DEBUG @@ -32,6 +33,18 @@ #define FLREG_BASE(reg) ((reg & 0x00000fff) << 12); #define FLREG_LIMIT(reg) (((reg & 0x0fff0000) >> 4) | 0xfff); +enum input_file_type_t { + IF_normal, + IF_fdt, + IF_uboot, +}; + +struct input_file { + char *fname; + unsigned int addr; + enum input_file_type_t type; +}; + /** * find_fd() - Find the flash description in the ROM image * @@ -54,7 +67,8 @@ static struct fdbar_t *find_fd(char *image, int size) return NULL; } - debug("Found Flash Descriptor signature at 0x%08x\n", i); + debug("Found Flash Descriptor signature at 0x%08lx\n", + (char *)ptr - image); return (struct fdbar_t *)ptr; } @@ -464,6 +478,16 @@ static int write_regions(char *image, int size) return ret; } +static int perror_fname(const char *fmt, const char *fname) +{ + char msg[strlen(fmt) + strlen(fname) + 1]; + + sprintf(msg, fmt, fname); + perror(msg); + + return -1; +} + /** * write_image() - Write the image to a file * @@ -480,10 +504,10 @@ static int write_image(char *filename, char *image, int size) new_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); - if (write(new_fd, image, size) != size) { - perror("Error while writing"); - return -1; - } + if (new_fd < 0) + return perror_fname("Could not open file '%s'", filename); + if (write(new_fd, image, size) != size) + return perror_fname("Could not write file '%s'", filename); close(new_fd); return 0; @@ -585,14 +609,10 @@ int open_for_read(const char *fname, int *sizep) int fd = open(fname, O_RDONLY); struct stat buf; - if (fd == -1) { - perror("Could not open file"); - return -1; - } - if (fstat(fd, &buf) == -1) { - perror("Could not stat file"); - return -1; - } + if (fd == -1) + return perror_fname("Could not open file '%s'", fname); + if (fstat(fd, &buf) == -1) + return perror_fname("Could not stat file '%s'", fname); *sizep = buf.st_size; debug("File %s is %d bytes\n", fname, *sizep); @@ -686,7 +706,7 @@ int inject_region(char *image, int size, int region_type, char *region_fname) * 0xffffffff so use an address relative to that. For an * 8MB ROM the start address is 0xfff80000. * @write_fname: Filename to add to the image - * @return 0 if OK, -ve on error + * @return number of bytes written if OK, -ve on error */ static int write_data(char *image, int size, unsigned int addr, const char *write_fname) @@ -698,7 +718,7 @@ static int write_data(char *image, int size, unsigned int addr, if (write_fd < 0) return write_fd; - offset = addr + size; + offset = (uint32_t)(addr + size); debug("Writing %s to offset %#x\n", write_fname, offset); if (offset < 0 || offset + write_size > size) { @@ -714,6 +734,68 @@ static int write_data(char *image, int size, unsigned int addr, close(write_fd); + return write_size; +} + +/** + * write_uboot() - Write U-Boot, device tree and microcode pointer + * + * This writes U-Boot into a place in the flash, followed by its device tree. + * The microcode pointer is written so that U-Boot can find the microcode in + * the device tree very early in boot. + * + * @image: Pointer to image + * @size: Size of image in bytes + * @uboot: Input file information for u-boot.bin + * @fdt: Input file information for u-boot.dtb + * @ucode_ptr: Address in U-Boot where the microcode pointer should be placed + * @return 0 if OK, -ve on error + */ +static int write_uboot(char *image, int size, struct input_file *uboot, + struct input_file *fdt, unsigned int ucode_ptr) +{ + const void *blob; + const char *data; + int uboot_size; + uint32_t *ptr; + int data_size; + int offset; + int node; + int ret; + + uboot_size = write_data(image, size, uboot->addr, uboot->fname); + if (uboot_size < 0) + return uboot_size; + fdt->addr = uboot->addr + uboot_size; + debug("U-Boot size %#x, FDT at %#x\n", uboot_size, fdt->addr); + ret = write_data(image, size, fdt->addr, fdt->fname); + if (ret < 0) + return ret; + + if (ucode_ptr) { + blob = (void *)image + (uint32_t)(fdt->addr + size); + debug("DTB at %lx\n", (char *)blob - image); + node = fdt_node_offset_by_compatible(blob, 0, + "intel,microcode"); + if (node < 0) { + debug("No microcode found in FDT: %s\n", + fdt_strerror(node)); + return -ENOENT; + } + data = fdt_getprop(blob, node, "data", &data_size); + if (!data) { + debug("No microcode data found in FDT: %s\n", + fdt_strerror(data_size)); + return -ENOENT; + } + offset = ucode_ptr - uboot->addr; + ptr = (void *)image + offset; + ptr[0] = uboot->addr + (data - image); + ptr[1] = data_size; + debug("Wrote microcode pointer at %x: addr=%x, size=%x\n", + ucode_ptr, ptr[0], ptr[1]); + } + return 0; } @@ -783,8 +865,7 @@ int main(int argc, char *argv[]) char *desc_fname = NULL, *addr_str = NULL; int region_type = -1, inputfreq = 0; enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ; - unsigned int addr[WRITE_MAX]; - char *wr_fname[WRITE_MAX]; + struct input_file input_file[WRITE_MAX], *ifile, *fdt = NULL; unsigned char wr_idx, wr_num = 0; int rom_size = -1; bool write_it; @@ -792,6 +873,8 @@ int main(int argc, char *argv[]) char *outfile = NULL; struct stat buf; int size = 0; + unsigned int ucode_ptr = 0; + bool have_uboot = false; int bios_fd; char *image; int ret; @@ -801,18 +884,21 @@ int main(int argc, char *argv[]) {"descriptor", 1, NULL, 'D'}, {"em100", 0, NULL, 'e'}, {"extract", 0, NULL, 'x'}, + {"fdt", 1, NULL, 'f'}, {"inject", 1, NULL, 'i'}, {"lock", 0, NULL, 'l'}, + {"microcode", 1, NULL, 'm'}, {"romsize", 1, NULL, 'r'}, {"spifreq", 1, NULL, 's'}, {"unlock", 0, NULL, 'u'}, + {"uboot", 1, NULL, 'U'}, {"write", 1, NULL, 'w'}, {"version", 0, NULL, 'v'}, {"help", 0, NULL, 'h'}, {0, 0, 0, 0} }; - while ((opt = getopt_long(argc, argv, "cdD:ehi:lr:s:uvw:x?", + while ((opt = getopt_long(argc, argv, "cdD:ef:hi:lm:r:s:uU:vw:x?", long_options, &option_index)) != EOF) { switch (opt) { case 'c': @@ -855,6 +941,9 @@ int main(int argc, char *argv[]) case 'l': mode_locked = 1; break; + case 'm': + ucode_ptr = strtoul(optarg, NULL, 0); + break; case 'r': rom_size = strtol(optarg, NULL, 0); debug("ROM size %d\n", rom_size); @@ -888,14 +977,23 @@ int main(int argc, char *argv[]) exit(EXIT_SUCCESS); break; case 'w': + case 'U': + case 'f': + ifile = &input_file[wr_num]; mode_write = 1; if (wr_num < WRITE_MAX) { if (get_two_words(optarg, &addr_str, - &wr_fname[wr_num])) { + &ifile->fname)) { print_usage(argv[0]); exit(EXIT_FAILURE); } - addr[wr_num] = strtol(optarg, NULL, 0); + ifile->addr = strtol(optarg, NULL, 0); + ifile->type = opt == 'f' ? IF_fdt : + opt == 'U' ? IF_uboot : IF_normal; + if (ifile->type == IF_fdt) + fdt = ifile; + else if (ifile->type == IF_uboot) + have_uboot = true; wr_num++; } else { fprintf(stderr, @@ -952,6 +1050,13 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); } + if (have_uboot && !fdt) { + fprintf(stderr, + "You must supply a device tree file for U-Boot\n\n"); + print_usage(argv[0]); + exit(EXIT_FAILURE); + } + filename = argv[optind]; if (optind + 2 != argc) outfile = argv[optind + 1]; @@ -1015,9 +1120,17 @@ int main(int argc, char *argv[]) if (mode_write) { for (wr_idx = 0; wr_idx < wr_num; wr_idx++) { - ret = write_data(image, size, - addr[wr_idx], wr_fname[wr_idx]); - if (ret) + ifile = &input_file[wr_idx]; + if (ifile->type == IF_fdt) { + continue; + } else if (ifile->type == IF_uboot) { + ret = write_uboot(image, size, ifile, fdt, + ucode_ptr); + } else { + ret = write_data(image, size, ifile->addr, + ifile->fname); + } + if (ret < 0) break; } } @@ -1052,5 +1165,5 @@ int main(int argc, char *argv[]) free(image); close(bios_fd); - return ret ? 1 : 0; + return ret < 0 ? 1 : 0; } 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..003716d --- /dev/null +++ b/tools/microcode-tool.py @@ -0,0 +1,253 @@ +#!/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_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 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_text, 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. + * + * 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 = '' + 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_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 >> sys.stderr, "Creating directory '%s'" % MICROCODE_DIR + os.makedirs(MICROCODE_DIR) + outfile = os.path.join(MICROCODE_DIR, mcode.name + '.dtsi') + print >> sys.stderr, "Writing microcode for '%s' to '%s'" % ( + mcode.name, outfile) + with open(outfile, 'w') as fd: + print >> fd, out % tuple(args) + +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('-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_text, microcodes = ParseFile(options.mcfile) + + 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() + 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_text, mcode_list[0], options.outfile) + else: + parser.error("Unknown command '%s'" % cmd) + +if __name__ == "__main__": + MicrocodeTool() |