[U-Boot] [PATCH v2 2/6] x86: ifdtool: Add support for early microcode access
Bin Meng
bmeng.cn at gmail.com
Tue Dec 16 10:33:59 CET 2014
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>
More information about the U-Boot
mailing list