|
@@ -31,6 +31,9 @@
|
|
|
#include <time.h>
|
|
|
#else
|
|
|
#include <common.h>
|
|
|
+#include <errno.h>
|
|
|
+#include <asm/io.h>
|
|
|
+DECLARE_GLOBAL_DATA_PTR;
|
|
|
#endif /* !USE_HOSTCC*/
|
|
|
|
|
|
#include <bootstage.h>
|
|
@@ -1448,6 +1451,22 @@ void fit_conf_print(const void *fit, int noffset, const char *p)
|
|
|
printf("%s FDT: %s\n", p, uname);
|
|
|
}
|
|
|
|
|
|
+int fit_image_select(const void *fit, int rd_noffset, int verify)
|
|
|
+{
|
|
|
+ fit_image_print(fit, rd_noffset, " ");
|
|
|
+
|
|
|
+ if (verify) {
|
|
|
+ puts(" Verifying Hash Integrity ... ");
|
|
|
+ if (!fit_image_verify(fit, rd_noffset)) {
|
|
|
+ puts("Bad Data Hash\n");
|
|
|
+ return -EACCES;
|
|
|
+ }
|
|
|
+ puts("OK\n");
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* fit_check_ramdisk - verify FIT format ramdisk subimage
|
|
|
* @fit_hdr: pointer to the FIT ramdisk header
|
|
@@ -1490,3 +1509,215 @@ int fit_check_ramdisk(const void *fit, int rd_noffset, uint8_t arch,
|
|
|
bootstage_mark(BOOTSTAGE_ID_FIT_RD_CHECK_ALL_OK);
|
|
|
return 1;
|
|
|
}
|
|
|
+
|
|
|
+int fit_get_node_from_config(bootm_headers_t *images, const char *prop_name,
|
|
|
+ ulong addr)
|
|
|
+{
|
|
|
+ int cfg_noffset;
|
|
|
+ void *fit_hdr;
|
|
|
+ int noffset;
|
|
|
+
|
|
|
+ debug("* %s: using config '%s' from image at 0x%08lx\n",
|
|
|
+ prop_name, images->fit_uname_cfg, addr);
|
|
|
+
|
|
|
+ /* Check whether configuration has this property defined */
|
|
|
+ fit_hdr = map_sysmem(addr, 0);
|
|
|
+ cfg_noffset = fit_conf_get_node(fit_hdr, images->fit_uname_cfg);
|
|
|
+ if (cfg_noffset < 0) {
|
|
|
+ debug("* %s: no such config\n", prop_name);
|
|
|
+ return -ENOENT;
|
|
|
+ }
|
|
|
+
|
|
|
+ noffset = fit_conf_get_prop_node(fit_hdr, cfg_noffset, prop_name);
|
|
|
+ if (noffset < 0) {
|
|
|
+ debug("* %s: no '%s' in config\n", prop_name, prop_name);
|
|
|
+ return -ENOLINK;
|
|
|
+ }
|
|
|
+
|
|
|
+ return noffset;
|
|
|
+}
|
|
|
+
|
|
|
+int fit_image_load(bootm_headers_t *images, const char *prop_name, ulong addr,
|
|
|
+ const char **fit_unamep, const char *fit_uname_config,
|
|
|
+ int arch, int image_type, int bootstage_id,
|
|
|
+ enum fit_load_op load_op, ulong *datap, ulong *lenp)
|
|
|
+{
|
|
|
+ int cfg_noffset, noffset;
|
|
|
+ const char *fit_uname;
|
|
|
+ const void *fit;
|
|
|
+ const void *buf;
|
|
|
+ size_t size;
|
|
|
+ int type_ok, os_ok;
|
|
|
+ ulong load, data, len;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ fit = map_sysmem(addr, 0);
|
|
|
+ fit_uname = fit_unamep ? *fit_unamep : NULL;
|
|
|
+ printf("## Loading %s from FIT Image at %08lx ...\n", prop_name, addr);
|
|
|
+
|
|
|
+ bootstage_mark(bootstage_id + BOOTSTAGE_SUB_FORMAT);
|
|
|
+ if (!fit_check_format(fit)) {
|
|
|
+ printf("Bad FIT %s image format!\n", prop_name);
|
|
|
+ bootstage_error(bootstage_id + BOOTSTAGE_SUB_FORMAT);
|
|
|
+ return -ENOEXEC;
|
|
|
+ }
|
|
|
+ bootstage_mark(bootstage_id + BOOTSTAGE_SUB_FORMAT_OK);
|
|
|
+ if (fit_uname) {
|
|
|
+ /* get ramdisk component image node offset */
|
|
|
+ bootstage_mark(bootstage_id + BOOTSTAGE_SUB_UNIT_NAME);
|
|
|
+ noffset = fit_image_get_node(fit, fit_uname);
|
|
|
+ } else {
|
|
|
+ /*
|
|
|
+ * no image node unit name, try to get config
|
|
|
+ * node first. If config unit node name is NULL
|
|
|
+ * fit_conf_get_node() will try to find default config node
|
|
|
+ */
|
|
|
+ bootstage_mark(bootstage_id + BOOTSTAGE_SUB_NO_UNIT_NAME);
|
|
|
+ if (IMAGE_ENABLE_BEST_MATCH && !fit_uname_config) {
|
|
|
+ cfg_noffset = fit_conf_find_compat(fit, gd_fdt_blob());
|
|
|
+ } else {
|
|
|
+ cfg_noffset = fit_conf_get_node(fit,
|
|
|
+ fit_uname_config);
|
|
|
+ }
|
|
|
+ if (cfg_noffset < 0) {
|
|
|
+ puts("Could not find configuration node\n");
|
|
|
+ bootstage_error(bootstage_id +
|
|
|
+ BOOTSTAGE_SUB_NO_UNIT_NAME);
|
|
|
+ return -ENOENT;
|
|
|
+ }
|
|
|
+ fit_uname_config = fdt_get_name(fit, cfg_noffset, NULL);
|
|
|
+ printf(" Using '%s' configuration\n", fit_uname_config);
|
|
|
+ if (image_type == IH_TYPE_KERNEL) {
|
|
|
+ /* Remember (and possibly verify) this config */
|
|
|
+ images->fit_uname_cfg = fit_uname_config;
|
|
|
+ if (IMAGE_ENABLE_VERIFY && images->verify) {
|
|
|
+ puts(" Verifying Hash Integrity ... ");
|
|
|
+ if (!fit_config_verify(fit, cfg_noffset)) {
|
|
|
+ puts("Bad Data Hash\n");
|
|
|
+ bootstage_error(bootstage_id +
|
|
|
+ BOOTSTAGE_SUB_HASH);
|
|
|
+ return -EACCES;
|
|
|
+ }
|
|
|
+ puts("OK\n");
|
|
|
+ }
|
|
|
+ bootstage_mark(BOOTSTAGE_ID_FIT_CONFIG);
|
|
|
+ }
|
|
|
+
|
|
|
+ noffset = fit_conf_get_prop_node(fit, cfg_noffset,
|
|
|
+ prop_name);
|
|
|
+ fit_uname = fit_get_name(fit, noffset, NULL);
|
|
|
+ }
|
|
|
+ if (noffset < 0) {
|
|
|
+ puts("Could not find subimage node\n");
|
|
|
+ bootstage_error(bootstage_id + BOOTSTAGE_SUB_SUBNODE);
|
|
|
+ return -ENOENT;
|
|
|
+ }
|
|
|
+
|
|
|
+ printf(" Trying '%s' %s subimage\n", fit_uname, prop_name);
|
|
|
+
|
|
|
+ ret = fit_image_select(fit, noffset, images->verify);
|
|
|
+ if (ret) {
|
|
|
+ bootstage_error(bootstage_id + BOOTSTAGE_SUB_HASH);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ bootstage_mark(bootstage_id + BOOTSTAGE_SUB_CHECK_ARCH);
|
|
|
+ if (!fit_image_check_target_arch(fit, noffset)) {
|
|
|
+ puts("Unsupported Architecture\n");
|
|
|
+ bootstage_error(bootstage_id + BOOTSTAGE_SUB_CHECK_ARCH);
|
|
|
+ return -ENOEXEC;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (image_type == IH_TYPE_FLATDT &&
|
|
|
+ !fit_image_check_comp(fit, noffset, IH_COMP_NONE)) {
|
|
|
+ puts("FDT image is compressed");
|
|
|
+ return -EPROTONOSUPPORT;
|
|
|
+ }
|
|
|
+
|
|
|
+ bootstage_mark(bootstage_id + BOOTSTAGE_SUB_CHECK_ALL);
|
|
|
+ type_ok = fit_image_check_type(fit, noffset, image_type) ||
|
|
|
+ (image_type == IH_TYPE_KERNEL &&
|
|
|
+ fit_image_check_type(fit, noffset,
|
|
|
+ IH_TYPE_KERNEL_NOLOAD));
|
|
|
+ os_ok = image_type == IH_TYPE_FLATDT ||
|
|
|
+ fit_image_check_os(fit, noffset, IH_OS_LINUX);
|
|
|
+ if (!type_ok || !os_ok) {
|
|
|
+ printf("No Linux %s %s Image\n", genimg_get_arch_name(arch),
|
|
|
+ genimg_get_type_name(image_type));
|
|
|
+ bootstage_error(bootstage_id + BOOTSTAGE_SUB_CHECK_ALL);
|
|
|
+ return -EIO;
|
|
|
+ }
|
|
|
+
|
|
|
+ bootstage_mark(bootstage_id + BOOTSTAGE_SUB_CHECK_ALL_OK);
|
|
|
+
|
|
|
+ /* get image data address and length */
|
|
|
+ if (fit_image_get_data(fit, noffset, &buf, &size)) {
|
|
|
+ printf("Could not find %s subimage data!\n", prop_name);
|
|
|
+ bootstage_error(bootstage_id + BOOTSTAGE_SUB_GET_DATA);
|
|
|
+ return -ENOMEDIUM;
|
|
|
+ }
|
|
|
+ len = (ulong)size;
|
|
|
+
|
|
|
+ /* verify that image data is a proper FDT blob */
|
|
|
+ if (image_type == IH_TYPE_FLATDT && fdt_check_header((char *)buf)) {
|
|
|
+ puts("Subimage data is not a FDT");
|
|
|
+ return -ENOEXEC;
|
|
|
+ }
|
|
|
+
|
|
|
+ bootstage_mark(bootstage_id + BOOTSTAGE_SUB_GET_DATA_OK);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Work-around for eldk-4.2 which gives this warning if we try to
|
|
|
+ * case in the unmap_sysmem() call:
|
|
|
+ * warning: initialization discards qualifiers from pointer target type
|
|
|
+ */
|
|
|
+ {
|
|
|
+ void *vbuf = (void *)buf;
|
|
|
+
|
|
|
+ data = map_to_sysmem(vbuf);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (load_op == FIT_LOAD_IGNORED) {
|
|
|
+ /* Don't load */
|
|
|
+ } else if (fit_image_get_load(fit, noffset, &load)) {
|
|
|
+ if (load_op == FIT_LOAD_REQUIRED) {
|
|
|
+ printf("Can't get %s subimage load address!\n",
|
|
|
+ prop_name);
|
|
|
+ bootstage_error(bootstage_id + BOOTSTAGE_SUB_LOAD);
|
|
|
+ return -EBADF;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ ulong image_start, image_end;
|
|
|
+ ulong load_end;
|
|
|
+ void *dst;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * move image data to the load address,
|
|
|
+ * make sure we don't overwrite initial image
|
|
|
+ */
|
|
|
+ image_start = addr;
|
|
|
+ image_end = addr + fit_get_size(fit);
|
|
|
+
|
|
|
+ load_end = load + len;
|
|
|
+ if (image_type != IH_TYPE_KERNEL &&
|
|
|
+ load < image_end && load_end > image_start) {
|
|
|
+ printf("Error: %s overwritten\n", prop_name);
|
|
|
+ return -EXDEV;
|
|
|
+ }
|
|
|
+
|
|
|
+ printf(" Loading %s from 0x%08lx to 0x%08lx\n",
|
|
|
+ prop_name, data, load);
|
|
|
+
|
|
|
+ dst = map_sysmem(load, len);
|
|
|
+ memmove(dst, buf, len);
|
|
|
+ data = load;
|
|
|
+ }
|
|
|
+ bootstage_mark(bootstage_id + BOOTSTAGE_SUB_LOAD);
|
|
|
+
|
|
|
+ *datap = data;
|
|
|
+ *lenp = len;
|
|
|
+ if (fit_unamep)
|
|
|
+ *fit_unamep = (char *)fit_uname;
|
|
|
+
|
|
|
+ return noffset;
|
|
|
+}
|