/** * fit_write_images() - Write out a list of images to the FIT * * We always include the main image (params->datafile). If there are device * tree files, we include an fdt@ node for each of those too. */ static int fit_write_images(struct image_tool_params *params, char *fdt) { struct content_info *cont; const char *typename; char str[100]; int upto; int ret; fdt_begin_node(fdt, "images"); /* First the main image */ typename = genimg_get_type_short_name(params->fit_image_type); snprintf(str, sizeof(str), "%s@1", typename); fdt_begin_node(fdt, str); fdt_property_string(fdt, "description", params->imagename); fdt_property_string(fdt, "type", typename); fdt_property_string(fdt, "arch", genimg_get_arch_name(params->arch)); fdt_property_string(fdt, "os", genimg_get_os_short_name(params->os)); fdt_property_string(fdt, "compression", genimg_get_comp_short_name(params->comp)); fdt_property_u32(fdt, "load", params->addr); fdt_property_u32(fdt, "entry", params->ep); /* * Put data last since it is large. SPL may only load the first part * of the DT, so this way it can access all the above fields. */ ret = fdt_property_file(params, fdt, "data", params->datafile); if (ret) return ret; fdt_end_node(fdt); /* Now the device tree files if available */ upto = 0; for (cont = params->content_head; cont; cont = cont->next) { if (cont->type != IH_TYPE_FLATDT) continue; snprintf(str, sizeof(str), "%s@%d", FIT_FDT_PROP, ++upto); fdt_begin_node(fdt, str); get_basename(str, sizeof(str), cont->fname); fdt_property_string(fdt, "description", str); ret = fdt_property_file(params, fdt, "data", cont->fname); if (ret) return ret; fdt_property_string(fdt, "type", typename); fdt_property_string(fdt, "arch", genimg_get_arch_short_name(params->arch)); fdt_property_string(fdt, "compression", genimg_get_comp_short_name(IH_COMP_NONE)); fdt_end_node(fdt); } fdt_end_node(fdt); return 0; }
static void image_print_type(const image_header_t *hdr) { const char *os, *arch, *type, *comp; os = genimg_get_os_name(image_get_os(hdr)); arch = genimg_get_arch_name(image_get_arch(hdr)); type = genimg_get_type_name(image_get_type(hdr)); comp = genimg_get_comp_name(image_get_comp(hdr)); printf("%s %s %s (%s)\n", arch, os, type, comp); }
/** * image_get_ramdisk - get and verify ramdisk image * @rd_addr: ramdisk image start address * @arch: expected ramdisk architecture * @verify: checksum verification flag * * image_get_ramdisk() returns a pointer to the verified ramdisk image * header. Routine receives image start address and expected architecture * flag. Verification done covers data and header integrity and os/type/arch * fields checking. * * If dataflash support is enabled routine checks for dataflash addresses * and handles required dataflash reads. * * returns: * pointer to a ramdisk image header, if image was found and valid * otherwise, return NULL */ static const image_header_t *image_get_ramdisk(ulong rd_addr, uint8_t arch, int verify) { const image_header_t *rd_hdr = (const image_header_t *)rd_addr; if (!image_check_magic(rd_hdr)) { puts("Bad Magic Number\n"); bootstage_error(BOOTSTAGE_ID_RD_MAGIC); return NULL; } if (!image_check_hcrc(rd_hdr)) { puts("Bad Header Checksum\n"); bootstage_error(BOOTSTAGE_ID_RD_HDR_CHECKSUM); return NULL; } bootstage_mark(BOOTSTAGE_ID_RD_MAGIC); image_print_contents(rd_hdr); if (verify) { puts(" Verifying Checksum ... "); if (!image_check_dcrc(rd_hdr)) { puts("Bad Data CRC\n"); bootstage_error(BOOTSTAGE_ID_RD_CHECKSUM); return NULL; } puts("OK\n"); } bootstage_mark(BOOTSTAGE_ID_RD_HDR_CHECKSUM); if (!image_check_os(rd_hdr, IH_OS_LINUX) || !image_check_arch(rd_hdr, arch) || !image_check_type(rd_hdr, IH_TYPE_RAMDISK)) { printf("No Linux %s Ramdisk Image\n", genimg_get_arch_name(arch)); bootstage_error(BOOTSTAGE_ID_RAMDISK); return NULL; } return rd_hdr; }
/** * fit_image_print - prints out the FIT component image details * @fit: pointer to the FIT format image header * @image_noffset: offset of the component image node * @p: pointer to prefix string * * fit_image_print() lists all mandatory properies for the processed component * image. If present, hash nodes are printed out as well. Load * address for images of type firmware is also printed out. Since the load * address is not mandatory for firmware images, it will be output as * "unavailable" when not present. * * returns: * no returned results */ void fit_image_print(const void *fit, int image_noffset, const char *p) { char *desc; uint8_t type, arch, os, comp; size_t size; ulong load, entry; const void *data; int noffset; int ndepth; int ret; /* Mandatory properties */ ret = fit_get_desc(fit, image_noffset, &desc); printf("%s Description: ", p); if (ret) printf("unavailable\n"); else printf("%s\n", desc); fit_image_get_type(fit, image_noffset, &type); printf("%s Type: %s\n", p, genimg_get_type_name(type)); fit_image_get_comp(fit, image_noffset, &comp); printf("%s Compression: %s\n", p, genimg_get_comp_name(comp)); ret = fit_image_get_data(fit, image_noffset, &data, &size); #ifndef USE_HOSTCC printf("%s Data Start: ", p); if (ret) { printf("unavailable\n"); } else { void *vdata = (void *)data; printf("0x%08lx\n", (ulong)map_to_sysmem(vdata)); } #endif printf("%s Data Size: ", p); if (ret) printf("unavailable\n"); else genimg_print_size(size); /* Remaining, type dependent properties */ if ((type == IH_TYPE_KERNEL) || (type == IH_TYPE_STANDALONE) || (type == IH_TYPE_RAMDISK) || (type == IH_TYPE_FIRMWARE) || (type == IH_TYPE_FLATDT)) { fit_image_get_arch(fit, image_noffset, &arch); printf("%s Architecture: %s\n", p, genimg_get_arch_name(arch)); } if ((type == IH_TYPE_KERNEL) || (type == IH_TYPE_RAMDISK)) { fit_image_get_os(fit, image_noffset, &os); printf("%s OS: %s\n", p, genimg_get_os_name(os)); } if ((type == IH_TYPE_KERNEL) || (type == IH_TYPE_STANDALONE) || (type == IH_TYPE_FIRMWARE) || (type == IH_TYPE_RAMDISK)) { ret = fit_image_get_load(fit, image_noffset, &load); printf("%s Load Address: ", p); if (ret) printf("unavailable\n"); else printf("0x%08lx\n", load); } if ((type == IH_TYPE_KERNEL) || (type == IH_TYPE_STANDALONE) || (type == IH_TYPE_RAMDISK)) { fit_image_get_entry(fit, image_noffset, &entry); printf("%s Entry Point: ", p); if (ret) printf("unavailable\n"); else printf("0x%08lx\n", entry); } /* Process all hash subnodes of the component image node */ for (ndepth = 0, noffset = fdt_next_node(fit, image_noffset, &ndepth); (noffset >= 0) && (ndepth > 0); noffset = fdt_next_node(fit, noffset, &ndepth)) { if (ndepth == 1) { /* Direct child node of the component image node */ fit_image_print_verification_data(fit, noffset, p); } } }
int fit_image_load(bootm_headers_t *images, const char *prop_name, ulong addr, const char **fit_unamep, const char **fit_uname_configp, 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 char *fit_uname_config; 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; fit_uname_config = fit_uname_configp ? *fit_uname_configp : 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 -ENOENT; } 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; if (fit_uname_configp) *fit_uname_configp = (char *)fit_uname_config; return noffset; }