diff options
author | Pantelis Antoniou | 2017-09-04 23:12:16 +0300 |
---|---|---|
committer | Simon Glass | 2017-09-15 05:27:49 -0600 |
commit | 169043d826e6b0db3c67a60acbedfc72c43aae5d (patch) | |
tree | 847a005598b2bee3418fdff9cf5dc47bfbf8d5ac | |
parent | 7c3dc776b91a683b2f7dd40ed91361124a3a91c0 (diff) |
fit: Introduce methods for applying overlays on fit-load
Introduce an overlay based method for constructing a base DT blob
to pass to the kernel.
It is based on a specific method now to get the FDT from a FIT image
named boot_get_fdt_fit().
Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
Acked-by: Simon Glass <sjg@chromium.org>
-rw-r--r-- | common/image-fdt.c | 7 | ||||
-rw-r--r-- | common/image-fit.c | 181 | ||||
-rw-r--r-- | include/image.h | 25 |
3 files changed, 205 insertions, 8 deletions
diff --git a/common/image-fdt.c b/common/image-fdt.c index da4d0070815..a2ef4098365 100644 --- a/common/image-fdt.c +++ b/common/image-fdt.c @@ -356,17 +356,16 @@ int boot_get_fdt(int flag, int argc, char * const argv[], uint8_t arch, if (fit_check_format(buf)) { ulong load, len; - fdt_noffset = fit_image_load(images, + fdt_noffset = boot_get_fdt_fit(images, fdt_addr, &fit_uname_fdt, &fit_uname_config, - arch, IH_TYPE_FLATDT, - BOOTSTAGE_ID_FIT_FDT_START, - FIT_LOAD_OPTIONAL, &load, &len); + arch, &load, &len); images->fit_hdr_fdt = map_sysmem(fdt_addr, 0); images->fit_uname_fdt = fit_uname_fdt; images->fit_noffset_fdt = fdt_noffset; fdt_addr = load; + break; } else #endif diff --git a/common/image-fit.c b/common/image-fit.c index e75cb649a49..7f17fd1410e 100644 --- a/common/image-fit.c +++ b/common/image-fit.c @@ -19,6 +19,7 @@ #include <errno.h> #include <mapmem.h> #include <asm/io.h> +#include <malloc.h> DECLARE_GLOBAL_DATA_PTR; #endif /* !USE_HOSTCC*/ @@ -434,6 +435,10 @@ void fit_image_print(const void *fit, int image_noffset, const char *p) printf("0x%08lx\n", load); } + /* optional load address for FDT */ + if (type == IH_TYPE_FLATDT && !fit_image_get_load(fit, image_noffset, &load)) + printf("%s Load Address: 0x%08lx\n", p, load); + if ((type == IH_TYPE_KERNEL) || (type == IH_TYPE_STANDALONE) || (type == IH_TYPE_RAMDISK)) { ret = fit_image_get_entry(fit, image_noffset, &entry); @@ -1454,6 +1459,8 @@ int fit_conf_get_node(const void *fit, const char *conf_uname) { int noffset, confs_noffset; int len; + const char *s; + char *conf_uname_copy = NULL; confs_noffset = fdt_path_offset(fit, FIT_CONFS_PATH); if (confs_noffset < 0) { @@ -1475,12 +1482,29 @@ int fit_conf_get_node(const void *fit, const char *conf_uname) debug("Found default configuration: '%s'\n", conf_uname); } + s = strchr(conf_uname, '#'); + if (s) { + len = s - conf_uname; + conf_uname_copy = malloc(len + 1); + if (!conf_uname_copy) { + debug("Can't allocate uname copy: '%s'\n", + conf_uname); + return -ENOMEM; + } + memcpy(conf_uname_copy, conf_uname, len); + conf_uname_copy[len] = '\0'; + conf_uname = conf_uname_copy; + } + noffset = fdt_subnode_offset(fit, confs_noffset, conf_uname); if (noffset < 0) { debug("Can't get node offset for configuration unit name: '%s' (%s)\n", conf_uname, fdt_strerror(noffset)); } + if (conf_uname_copy) + free(conf_uname_copy); + return noffset; } @@ -1527,7 +1551,7 @@ void fit_conf_print(const void *fit, int noffset, const char *p) char *desc; const char *uname; int ret; - int loadables_index; + int fdt_index, loadables_index; /* Mandatory properties */ ret = fit_get_desc(fit, noffset, &desc); @@ -1549,9 +1573,17 @@ void fit_conf_print(const void *fit, int noffset, const char *p) if (uname) printf("%s Init Ramdisk: %s\n", p, uname); - uname = fdt_getprop(fit, noffset, FIT_FDT_PROP, NULL); - if (uname) - printf("%s FDT: %s\n", p, uname); + for (fdt_index = 0; + uname = fdt_stringlist_get(fit, noffset, FIT_FDT_PROP, + fdt_index, NULL), uname; + fdt_index++) { + + if (fdt_index == 0) + printf("%s FDT: ", p); + else + printf("%s ", p); + printf("%s\n", uname); + } uname = fdt_getprop(fit, noffset, FIT_FPGA_PROP, NULL); if (uname) @@ -1888,3 +1920,144 @@ int boot_get_setup_fit(bootm_headers_t *images, uint8_t arch, return ret; } + +#ifndef USE_HOSTCC +int boot_get_fdt_fit(bootm_headers_t *images, ulong addr, + const char **fit_unamep, const char **fit_uname_configp, + int arch, ulong *datap, ulong *lenp) +{ + int fdt_noffset, cfg_noffset, count; + const void *fit; + const char *fit_uname = NULL; + const char *fit_uname_config = NULL; + char *fit_uname_config_copy = NULL; + char *next_config = NULL; + ulong load, len; +#ifdef CONFIG_OF_LIBFDT_OVERLAY + ulong image_start, image_end; + ulong ovload, ovlen; + const char *uconfig; + const char *uname; + void *base, *ov; + int i, err, noffset, ov_noffset; +#endif + + fit_uname = fit_unamep ? *fit_unamep : NULL; + + if (fit_uname_configp && *fit_uname_configp) { + fit_uname_config_copy = strdup(*fit_uname_configp); + if (!fit_uname_config_copy) + return -ENOMEM; + + next_config = strchr(fit_uname_config_copy, '#'); + if (next_config) + *next_config++ = '\0'; + if (next_config - 1 > fit_uname_config_copy) + fit_uname_config = fit_uname_config_copy; + } + + fdt_noffset = fit_image_load(images, + addr, &fit_uname, &fit_uname_config, + arch, IH_TYPE_FLATDT, + BOOTSTAGE_ID_FIT_FDT_START, + FIT_LOAD_OPTIONAL, &load, &len); + + if (fdt_noffset < 0) + goto out; + + debug("fit_uname=%s, fit_uname_config=%s\n", + fit_uname ? fit_uname : "<NULL>", + fit_uname_config ? fit_uname_config : "<NULL>"); + + fit = map_sysmem(addr, 0); + + cfg_noffset = fit_conf_get_node(fit, fit_uname_config); + + /* single blob, or error just return as well */ + count = fit_conf_get_prop_node_count(fit, cfg_noffset, FIT_FDT_PROP); + if (count <= 1 && !next_config) + goto out; + + /* we need to apply overlays */ + +#ifdef CONFIG_OF_LIBFDT_OVERLAY + image_start = addr; + image_end = addr + fit_get_size(fit); + /* verify that relocation took place by load address not being in fit */ + if (load >= image_start && load < image_end) { + /* check is simplified; fit load checks for overlaps */ + printf("Overlayed FDT requires relocation\n"); + fdt_noffset = -EBADF; + goto out; + } + + base = map_sysmem(load, len); + + /* apply extra configs in FIT first, followed by args */ + for (i = 1; ; i++) { + if (i < count) { + noffset = fit_conf_get_prop_node_index(fit, cfg_noffset, + FIT_FDT_PROP, i); + uname = fit_get_name(fit, noffset, NULL); + uconfig = NULL; + } else { + if (!next_config) + break; + uconfig = next_config; + next_config = strchr(next_config, '#'); + if (next_config) + *next_config++ = '\0'; + uname = NULL; + } + + debug("%d: using uname=%s uconfig=%s\n", i, uname, uconfig); + + ov_noffset = fit_image_load(images, + addr, &uname, &uconfig, + arch, IH_TYPE_FLATDT, + BOOTSTAGE_ID_FIT_FDT_START, + FIT_LOAD_REQUIRED, &ovload, &ovlen); + if (ov_noffset < 0) { + printf("load of %s failed\n", uname); + continue; + } + debug("%s loaded at 0x%08lx len=0x%08lx\n", + uname, ovload, ovlen); + ov = map_sysmem(ovload, ovlen); + + base = map_sysmem(load, len + ovlen); + err = fdt_open_into(base, base, len + ovlen); + if (err < 0) { + printf("failed on fdt_open_into\n"); + fdt_noffset = err; + goto out; + } + /* the verbose method prints out messages on error */ + err = fdt_overlay_apply_verbose(base, ov); + if (err < 0) { + fdt_noffset = err; + goto out; + } + fdt_pack(base); + len = fdt_totalsize(base); + } +#else + printf("config with overlays but CONFIG_OF_LIBFDT_OVERLAY not set\n"); + fdt_noffset = -EBADF; +#endif + +out: + if (datap) + *datap = load; + if (lenp) + *lenp = len; + if (fit_unamep) + *fit_unamep = fit_uname; + if (fit_uname_configp) + *fit_uname_configp = fit_uname_config; + + if (fit_uname_config_copy) + free(fit_uname_config_copy); + return fdt_noffset; +} +#endif diff --git a/include/image.h b/include/image.h index 339f79c6dc0..af98ed9f25c 100644 --- a/include/image.h +++ b/include/image.h @@ -594,6 +594,31 @@ int boot_get_setup_fit(bootm_headers_t *images, uint8_t arch, ulong *setup_start, ulong *setup_len); /** + * boot_get_fdt_fit() - load a DTB from a FIT file (applying overlays) + * + * This deals with all aspects of loading an DTB from a FIT. + * The correct base image based on configuration will be selected, and + * then any overlays specified will be applied (as present in fit_uname_configp). + * + * @param images Boot images structure + * @param addr Address of FIT in memory + * @param fit_unamep On entry this is the requested image name + * (e.g. "kernel@1") or NULL to use the default. On exit + * points to the selected image name + * @param fit_uname_configp On entry this is the requested configuration + * name (e.g. "conf@1") or NULL to use the default. On + * exit points to the selected configuration name. + * @param arch Expected architecture (IH_ARCH_...) + * @param datap Returns address of loaded image + * @param lenp Returns length of loaded image + * + * @return node offset of base image, or -ve error code on error + */ +int boot_get_fdt_fit(bootm_headers_t *images, ulong addr, + const char **fit_unamep, const char **fit_uname_configp, + int arch, ulong *datap, ulong *lenp); + +/** * fit_image_load() - load an image from a FIT * * This deals with all aspects of loading an image from a FIT, including |