]> git.kernelconcepts.de Git - karo-tx-uboot.git/commitdiff
x86: ifdtool: Support collating microcode into one place
authorSimon Glass <sjg@chromium.org>
Sat, 15 Aug 2015 20:37:53 +0000 (14:37 -0600)
committerLothar Waßmann <LW@KARO-electronics.de>
Thu, 10 Sep 2015 09:29:45 +0000 (11:29 +0200)
The Intel Firmware Support Package (FSP) requires that microcode be provided
very early before the device tree can be scanned. We already support adding
a pointer to the microcode data in a place where early init code can access.

However this just points into the device tree and can only point to a single
lot of microcode. For boards which may have different CPU types we must
support multiple microcodes and pass all of them to the FSP in one place.

Enhance ifdtool to scan all the microcode, place it together in the ROM and
update the microcode pointer to point there. This allows us to pass multiple
microcode blocks to the FSP using its existing API.

Enable the flag in the Makefile so that this feature is used by default for
all boards.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Tested-by: Bin Meng <bmeng.cn@gmail.com>
Makefile
tools/ifdtool.c

index 7279ea9148b4bcf6c2519def68fc614c67f22cac..6895830741dac1a5c235ea455ee6b7adb183f271 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1043,6 +1043,7 @@ IFDTOOL_FLAGS  = -f 0:$(objtree)/u-boot.dtb
 IFDTOOL_FLAGS += -m 0x$(shell $(NM) u-boot |grep _dt_ucode_base_size |cut -d' ' -f1)
 IFDTOOL_FLAGS += -U $(CONFIG_SYS_TEXT_BASE):$(objtree)/u-boot.bin
 IFDTOOL_FLAGS += -w $(CONFIG_SYS_X86_START16):$(objtree)/u-boot-x86-16bit.bin
+IFDTOOL_FLAGS += -C
 
 ifneq ($(CONFIG_HAVE_INTEL_ME),)
 IFDTOOL_ME_FLAGS  = -D $(srctree)/board/$(BOARDDIR)/descriptor.bin
index b794516189cd66991b6826f6f58b089864dfe7fe..d966c563da4a261360003def2568cfc6b00414ae 100644 (file)
@@ -768,6 +768,8 @@ static int scan_ucode(const void *blob, char *ucode_base, int *countp,
                        return -ENOENT;
                }
 
+               if (ucode_base)
+                       memcpy(ucode, data, data_size);
                ucode += data_size;
        }
 
@@ -782,15 +784,19 @@ static int scan_ucode(const void *blob, char *ucode_base, int *countp,
 }
 
 static int write_ucode(char *image, int size, struct input_file *fdt,
-                      int fdt_size, unsigned int ucode_ptr)
+                      int fdt_size, unsigned int ucode_ptr,
+                      int collate_ucode)
 {
        const char *data = NULL;
+       char *ucode_buf;
        const void *blob;
+       char *ucode_base;
        uint32_t *ptr;
        int ucode_size;
        int data_size;
        int offset;
        int count;
+       int ret;
 
        blob = (void *)image + (uint32_t)(fdt->addr + size);
 
@@ -805,12 +811,43 @@ static int write_ucode(char *image, int size, struct input_file *fdt,
                return -ENOENT;
        }
 
-       if (count > 1) {
+       if (count > 1 && !collate_ucode) {
                fprintf(stderr,
-                       "Cannot handle multiple microcode blocks\n");
+                       "Cannot handle multiple microcode blocks - please use -C flag to collate them\n");
                return -EMLINK;
        }
 
+       /*
+        * Collect the microcode into a buffer and place it immediately above
+        * the device tree.
+        */
+       if (collate_ucode && count > 1) {
+               ucode_buf = malloc(ucode_size);
+               if (!ucode_buf) {
+                       fprintf(stderr,
+                               "Out of memory for microcode (%d bytes)\n",
+                               ucode_size);
+                       return -ENOMEM;
+               }
+               ret = scan_ucode(blob, ucode_buf, NULL, NULL, NULL);
+               if (ret < 0)
+                       return ret;
+
+               debug("Collated %d microcode block(s)\n", count);
+
+               /*
+                * Place microcode area immediately above the FDT, aligned
+                * to a 16-byte boundary.
+                */
+               ucode_base = (char *)(((unsigned long)blob + fdt_size + 15) &
+                               ~15);
+
+               data = ucode_base;
+               data_size = ucode_size;
+               memcpy(ucode_base, ucode_buf, ucode_size);
+               free(ucode_buf);
+       }
+
        offset = (uint32_t)(ucode_ptr + size);
        ptr = (void *)image + offset;
 
@@ -819,7 +856,8 @@ static int write_ucode(char *image, int size, struct input_file *fdt,
        debug("Wrote microcode pointer at %x: addr=%x, size=%x\n", ucode_ptr,
              ptr[0], ptr[1]);
 
-       return 0;
+       return (collate_ucode ? data + data_size : (char *)blob + fdt_size) -
+                       image;
 }
 
 /**
@@ -837,7 +875,8 @@ static int write_ucode(char *image, int size, struct input_file *fdt,
  * @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)
+                      struct input_file *fdt, unsigned int ucode_ptr,
+                      int collate_ucode)
 {
        const void *blob;
        int uboot_size, fdt_size;
@@ -852,8 +891,10 @@ static int write_uboot(char *image, int size, struct input_file *uboot,
                return fdt_size;
        blob = (void *)image + (uint32_t)(fdt->addr + size);
 
-       if (ucode_ptr)
-               return write_ucode(image, size, fdt, fdt_size, ucode_ptr);
+       if (ucode_ptr) {
+               return write_ucode(image, size, fdt, fdt_size, ucode_ptr,
+                                  collate_ucode);
+       }
 
        return ((char *)blob + fdt_size) - image;
 }
@@ -919,7 +960,7 @@ int main(int argc, char *argv[])
        int mode_dump = 0, mode_extract = 0, mode_inject = 0;
        int mode_spifreq = 0, mode_em100 = 0, mode_locked = 0;
        int mode_unlocked = 0, mode_write = 0, mode_write_descriptor = 0;
-       int create = 0;
+       int create = 0, collate_ucode = 0;
        char *region_type_string = NULL, *inject_fname = NULL;
        char *desc_fname = NULL, *addr_str = NULL;
        int region_type = -1, inputfreq = 0;
@@ -939,6 +980,7 @@ int main(int argc, char *argv[])
        int ret;
        static struct option long_options[] = {
                {"create", 0, NULL, 'c'},
+               {"collate-microcode", 0, NULL, 'C'},
                {"dump", 0, NULL, 'd'},
                {"descriptor", 1, NULL, 'D'},
                {"em100", 0, NULL, 'e'},
@@ -957,12 +999,15 @@ int main(int argc, char *argv[])
                {0, 0, 0, 0}
        };
 
-       while ((opt = getopt_long(argc, argv, "cdD:ef:hi:lm:r:s:uU:vw:x?",
+       while ((opt = getopt_long(argc, argv, "cCdD:ef:hi:lm:r:s:uU:vw:x?",
                                  long_options, &option_index)) != EOF) {
                switch (opt) {
                case 'c':
                        create = 1;
                        break;
+               case 'C':
+                       collate_ucode = 1;
+                       break;
                case 'd':
                        mode_dump = 1;
                        break;
@@ -1186,7 +1231,7 @@ int main(int argc, char *argv[])
                                continue;
                        } else if (ifile->type == IF_uboot) {
                                ret = write_uboot(image, size, ifile, fdt,
-                                                 ucode_ptr);
+                                                 ucode_ptr, collate_ucode);
                                offset_uboot_top = ret;
                        } else {
                                ret = write_data(image, size, ifile->addr,