[U-Boot] [PATCH v2 2/6] x86: ifdtool: Add support for early microcode access

Simon Glass sjg at chromium.org
Wed Dec 17 03:21:10 CET 2014


On 16 December 2014 at 02:33, Bin Meng <bmeng.cn at gmail.com> wrote:
> On Tue, Dec 16, 2014 at 1:02 PM, Simon Glass <sjg at chromium.org> wrote:
>> Some Intel CPUs use an 'FSP' binary blob which provides an inflexible
>> means of starting up the CPU. One result is that microcode updates can only
>> be done before RAM is available and therefore parsing of the device tree
>> is impracticle.
>>
>> Worse, the addess of the microcode update must be stored in ROM since a
>> pointer to its start address and size is passed to the 'FSP' blob. It is
>> not possible to perform any calculations to obtain the address and size.
>>
>> To work around this, ifdtool is enhanced to work out the address and size of
>> the first microcode update it finds in the supplied device tree. It then
>> writes these into the correct place in the ROM. U-Boot can then start up
>> the FSP correctly.
>>
>> Signed-off-by: Simon Glass <sjg at chromium.org>
>> ---
>>
>> Changes in v2:
>> - Finish off comments in write_uboot() function
>> - Write the correct microcode pointer to U-Boot (fix fdt->addr bug)
>>
>>  tools/Makefile  |   1 +
>>  tools/ifdtool.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++++++-----
>>  2 files changed, 103 insertions(+), 8 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/ifdtool.c b/tools/ifdtool.c
>> index 4077ba8..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
>> @@ -34,6 +35,8 @@
>>
>>  enum input_file_type_t {
>>         IF_normal,
>> +       IF_fdt,
>> +       IF_uboot,
>>  };
>>
>>  struct input_file {
>> @@ -703,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)
>> @@ -715,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) {
>> @@ -731,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;
>>  }
>>
>> @@ -800,7 +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;
>> -       struct input_file input_file[WRITE_MAX], *ifile;
>> +       struct input_file input_file[WRITE_MAX], *ifile, *fdt = NULL;
>>         unsigned char wr_idx, wr_num = 0;
>>         int rom_size = -1;
>>         bool write_it;
>> @@ -808,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;
>> @@ -817,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':
>> @@ -871,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);
>> @@ -904,6 +977,8 @@ 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) {
>> @@ -913,7 +988,12 @@ int main(int argc, char *argv[])
>>                                         exit(EXIT_FAILURE);
>>                                 }
>>                                 ifile->addr = strtol(optarg, NULL, 0);
>> -                               ifile->type = IF_normal;
>> +                               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,
>> @@ -970,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];
>> @@ -1034,9 +1121,16 @@ int main(int argc, char *argv[])
>>         if (mode_write) {
>>                 for (wr_idx = 0; wr_idx < wr_num; wr_idx++) {
>>                         ifile = &input_file[wr_idx];
>> -                       ret = write_data(image, size, ifile->addr,
>> +                       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)
>> +                       }
>> +                       if (ret < 0)
>>                                 break;
>>                 }
>>         }
>> @@ -1071,5 +1165,5 @@ int main(int argc, char *argv[])
>>         free(image);
>>         close(bios_fd);
>>
>> -       return ret ? 1 : 0;
>> +       return ret < 0 ? 1 : 0;
>>  }
>> --
>
> Reviewed-by: Bin Meng <bmeng.cn at gmail.com>

Applied to u-boot-x86.


More information about the U-Boot mailing list