X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=common%2Fimage-fit.c;h=e346fed550e842538430eb6fcb0a6b192784eeaa;hb=18cfa612a9f80249062297befbca7dfa90264622;hp=1b0234a90cb1eefcc7533f630491e8a68098292a;hpb=58c8c0963b1c720802c46ac4288c897e5f9cd296;p=platform%2Fkernel%2Fu-boot.git diff --git a/common/image-fit.c b/common/image-fit.c index 1b0234a..e346fed 100644 --- a/common/image-fit.c +++ b/common/image-fit.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (c) 2013, Google Inc. * @@ -5,8 +6,6 @@ * * (C) Copyright 2000-2006 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. - * - * SPDX-License-Identifier: GPL-2.0+ */ #ifdef USE_HOSTCC @@ -14,13 +13,16 @@ #include #else #include +#include #include #include #include #include +#include DECLARE_GLOBAL_DATA_PTR; #endif /* !USE_HOSTCC*/ +#include #include #include #include @@ -141,7 +143,191 @@ int fit_get_subimage_count(const void *fit, int images_noffset) return count; } -#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_FIT_SPL_PRINT) +#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_FIT_PRINT) +/** + * fit_image_print_data() - prints out the hash node details + * @fit: pointer to the FIT format image header + * @noffset: offset of the hash node + * @p: pointer to prefix string + * @type: Type of information to print ("hash" or "sign") + * + * fit_image_print_data() lists properties for the processed hash node + * + * This function avoid using puts() since it prints a newline on the host + * but does not in U-Boot. + * + * returns: + * no returned results + */ +static void fit_image_print_data(const void *fit, int noffset, const char *p, + const char *type) +{ + const char *keyname; + uint8_t *value; + int value_len; + char *algo; + const char *padding; + int required; + int ret, i; + + debug("%s %s node: '%s'\n", p, type, + fit_get_name(fit, noffset, NULL)); + printf("%s %s algo: ", p, type); + if (fit_image_hash_get_algo(fit, noffset, &algo)) { + printf("invalid/unsupported\n"); + return; + } + printf("%s", algo); + keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); + required = fdt_getprop(fit, noffset, "required", NULL) != NULL; + if (keyname) + printf(":%s", keyname); + if (required) + printf(" (required)"); + printf("\n"); + + padding = fdt_getprop(fit, noffset, "padding", NULL); + if (padding) + printf("%s %s padding: %s\n", p, type, padding); + + ret = fit_image_hash_get_value(fit, noffset, &value, + &value_len); + printf("%s %s value: ", p, type); + if (ret) { + printf("unavailable\n"); + } else { + for (i = 0; i < value_len; i++) + printf("%02x", value[i]); + printf("\n"); + } + + debug("%s %s len: %d\n", p, type, value_len); + + /* Signatures have a time stamp */ + if (IMAGE_ENABLE_TIMESTAMP && keyname) { + time_t timestamp; + + printf("%s Timestamp: ", p); + if (fit_get_timestamp(fit, noffset, ×tamp)) + printf("unavailable\n"); + else + genimg_print_time(timestamp); + } +} + +/** + * fit_image_print_verification_data() - prints out the hash/signature details + * @fit: pointer to the FIT format image header + * @noffset: offset of the hash or signature node + * @p: pointer to prefix string + * + * This lists properties for the processed hash node + * + * returns: + * no returned results + */ +static void fit_image_print_verification_data(const void *fit, int noffset, + const char *p) +{ + const char *name; + + /* + * Check subnode name, must be equal to "hash" or "signature". + * Multiple hash/signature nodes require unique unit node + * names, e.g. hash-1, hash-2, signature-1, signature-2, etc. + */ + name = fit_get_name(fit, noffset, NULL); + if (!strncmp(name, FIT_HASH_NODENAME, strlen(FIT_HASH_NODENAME))) { + fit_image_print_data(fit, noffset, p, "Hash"); + } else if (!strncmp(name, FIT_SIG_NODENAME, + strlen(FIT_SIG_NODENAME))) { + fit_image_print_data(fit, noffset, p, "Sign"); + } +} + +/** + * fit_conf_print - prints out the FIT configuration details + * @fit: pointer to the FIT format image header + * @noffset: offset of the configuration node + * @p: pointer to prefix string + * + * fit_conf_print() lists all mandatory properties for the processed + * configuration node. + * + * returns: + * no returned results + */ +static void fit_conf_print(const void *fit, int noffset, const char *p) +{ + char *desc; + const char *uname; + int ret; + int fdt_index, loadables_index; + int ndepth; + + /* Mandatory properties */ + ret = fit_get_desc(fit, noffset, &desc); + printf("%s Description: ", p); + if (ret) + printf("unavailable\n"); + else + printf("%s\n", desc); + + uname = fdt_getprop(fit, noffset, FIT_KERNEL_PROP, NULL); + printf("%s Kernel: ", p); + if (!uname) + printf("unavailable\n"); + else + printf("%s\n", uname); + + /* Optional properties */ + uname = fdt_getprop(fit, noffset, FIT_RAMDISK_PROP, NULL); + if (uname) + printf("%s Init Ramdisk: %s\n", p, uname); + + uname = fdt_getprop(fit, noffset, FIT_FIRMWARE_PROP, NULL); + if (uname) + printf("%s Firmware: %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) + printf("%s FPGA: %s\n", p, uname); + + /* Print out all of the specified loadables */ + for (loadables_index = 0; + uname = fdt_stringlist_get(fit, noffset, FIT_LOADABLE_PROP, + loadables_index, NULL), uname; + loadables_index++) { + if (loadables_index == 0) { + printf("%s Loadables: ", p); + } else { + printf("%s ", p); + } + printf("%s\n", uname); + } + + /* Process all hash subnodes of the component configuration node */ + for (ndepth = 0, noffset = fdt_next_node(fit, noffset, &ndepth); + (noffset >= 0) && (ndepth > 0); + noffset = fdt_next_node(fit, noffset, &ndepth)) { + if (ndepth == 1) { + /* Direct child node of the component configuration node */ + fit_image_print_verification_data(fit, noffset, p); + } + } +} + /** * fit_print_contents - prints out the contents of the FIT format image * @fit: pointer to the FIT format image header @@ -244,102 +430,6 @@ void fit_print_contents(const void *fit) } /** - * fit_image_print_data() - prints out the hash node details - * @fit: pointer to the FIT format image header - * @noffset: offset of the hash node - * @p: pointer to prefix string - * @type: Type of information to print ("hash" or "sign") - * - * fit_image_print_data() lists properties for the processed hash node - * - * This function avoid using puts() since it prints a newline on the host - * but does not in U-Boot. - * - * returns: - * no returned results - */ -static void fit_image_print_data(const void *fit, int noffset, const char *p, - const char *type) -{ - const char *keyname; - uint8_t *value; - int value_len; - char *algo; - int required; - int ret, i; - - debug("%s %s node: '%s'\n", p, type, - fit_get_name(fit, noffset, NULL)); - printf("%s %s algo: ", p, type); - if (fit_image_hash_get_algo(fit, noffset, &algo)) { - printf("invalid/unsupported\n"); - return; - } - printf("%s", algo); - keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); - required = fdt_getprop(fit, noffset, "required", NULL) != NULL; - if (keyname) - printf(":%s", keyname); - if (required) - printf(" (required)"); - printf("\n"); - - ret = fit_image_hash_get_value(fit, noffset, &value, - &value_len); - printf("%s %s value: ", p, type); - if (ret) { - printf("unavailable\n"); - } else { - for (i = 0; i < value_len; i++) - printf("%02x", value[i]); - printf("\n"); - } - - debug("%s %s len: %d\n", p, type, value_len); - - /* Signatures have a time stamp */ - if (IMAGE_ENABLE_TIMESTAMP && keyname) { - time_t timestamp; - - printf("%s Timestamp: ", p); - if (fit_get_timestamp(fit, noffset, ×tamp)) - printf("unavailable\n"); - else - genimg_print_time(timestamp); - } -} - -/** - * fit_image_print_verification_data() - prints out the hash/signature details - * @fit: pointer to the FIT format image header - * @noffset: offset of the hash or signature node - * @p: pointer to prefix string - * - * This lists properties for the processed hash node - * - * returns: - * no returned results - */ -static void fit_image_print_verification_data(const void *fit, int noffset, - const char *p) -{ - const char *name; - - /* - * Check subnode name, must be equal to "hash" or "signature". - * Multiple hash/signature nodes require unique unit node - * names, e.g. hash@1, hash@2, signature@1, signature@2, etc. - */ - name = fit_get_name(fit, noffset, NULL); - if (!strncmp(name, FIT_HASH_NODENAME, strlen(FIT_HASH_NODENAME))) { - fit_image_print_data(fit, noffset, p, "Hash"); - } else if (!strncmp(name, FIT_SIG_NODENAME, - strlen(FIT_SIG_NODENAME))) { - fit_image_print_data(fit, noffset, p, "Sign"); - } -} - -/** * 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 @@ -390,7 +480,7 @@ void fit_image_print(const void *fit, int image_noffset, const char *p) 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); + ret = fit_image_get_data_and_size(fit, image_noffset, &data, &size); #ifndef USE_HOSTCC printf("%s Data Start: ", p); @@ -417,7 +507,8 @@ void fit_image_print(const void *fit, int image_noffset, const char *p) printf("%s Architecture: %s\n", p, genimg_get_arch_name(arch)); } - if ((type == IH_TYPE_KERNEL) || (type == IH_TYPE_RAMDISK)) { + if ((type == IH_TYPE_KERNEL) || (type == IH_TYPE_RAMDISK) || + (type == IH_TYPE_FIRMWARE)) { fit_image_get_os(fit, image_noffset, &os); printf("%s OS: %s\n", p, genimg_get_os_name(os)); } @@ -433,6 +524,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); @@ -453,8 +548,10 @@ void fit_image_print(const void *fit, int image_noffset, const char *p) } } } - -#endif /* !defined(CONFIG_SPL_BUILD) || defined(CONFIG_FIT_SPL_PRINT) */ +#else +void fit_print_contents(const void *fit) { } +void fit_image_print(const void *fit, int image_noffset, const char *p) { } +#endif /* !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_FIT_PRINT) */ /** * fit_get_desc - get node description property @@ -732,48 +829,169 @@ int fit_image_get_load(const void *fit, int noffset, ulong *load) * This gets the entry point address property for a given component image * node. * - * fit_image_get_entry() finds entry point address property in a given - * component image node. If the property is found, its value is returned - * to the caller. + * fit_image_get_entry() finds entry point address property in a given + * component image node. If the property is found, its value is returned + * to the caller. + * + * returns: + * 0, on success + * -1, on failure + */ +int fit_image_get_entry(const void *fit, int noffset, ulong *entry) +{ + return fit_image_get_address(fit, noffset, FIT_ENTRY_PROP, entry); +} + +/** + * fit_image_get_data - get data property and its size for a given component image node + * @fit: pointer to the FIT format image header + * @noffset: component image node offset + * @data: double pointer to void, will hold data property's data address + * @size: pointer to size_t, will hold data property's data size + * + * fit_image_get_data() finds data property in a given component image node. + * If the property is found its data start address and size are returned to + * the caller. + * + * returns: + * 0, on success + * -1, on failure + */ +int fit_image_get_data(const void *fit, int noffset, + const void **data, size_t *size) +{ + int len; + + *data = fdt_getprop(fit, noffset, FIT_DATA_PROP, &len); + if (*data == NULL) { + fit_get_debug(fit, noffset, FIT_DATA_PROP, len); + *size = 0; + return -1; + } + + *size = len; + return 0; +} + +/** + * Get 'data-offset' property from a given image node. + * + * @fit: pointer to the FIT image header + * @noffset: component image node offset + * @data_offset: holds the data-offset property + * + * returns: + * 0, on success + * -ENOENT if the property could not be found + */ +int fit_image_get_data_offset(const void *fit, int noffset, int *data_offset) +{ + const fdt32_t *val; + + val = fdt_getprop(fit, noffset, FIT_DATA_OFFSET_PROP, NULL); + if (!val) + return -ENOENT; + + *data_offset = fdt32_to_cpu(*val); + + return 0; +} + +/** + * Get 'data-position' property from a given image node. + * + * @fit: pointer to the FIT image header + * @noffset: component image node offset + * @data_position: holds the data-position property + * + * returns: + * 0, on success + * -ENOENT if the property could not be found + */ +int fit_image_get_data_position(const void *fit, int noffset, + int *data_position) +{ + const fdt32_t *val; + + val = fdt_getprop(fit, noffset, FIT_DATA_POSITION_PROP, NULL); + if (!val) + return -ENOENT; + + *data_position = fdt32_to_cpu(*val); + + return 0; +} + +/** + * Get 'data-size' property from a given image node. + * + * @fit: pointer to the FIT image header + * @noffset: component image node offset + * @data_size: holds the data-size property * * returns: * 0, on success - * -1, on failure + * -ENOENT if the property could not be found */ -int fit_image_get_entry(const void *fit, int noffset, ulong *entry) +int fit_image_get_data_size(const void *fit, int noffset, int *data_size) { - return fit_image_get_address(fit, noffset, FIT_ENTRY_PROP, entry); + const fdt32_t *val; + + val = fdt_getprop(fit, noffset, FIT_DATA_SIZE_PROP, NULL); + if (!val) + return -ENOENT; + + *data_size = fdt32_to_cpu(*val); + + return 0; } /** - * fit_image_get_data - get data property and its size for a given component image node + * fit_image_get_data_and_size - get data and its size including + * both embedded and external data * @fit: pointer to the FIT format image header * @noffset: component image node offset * @data: double pointer to void, will hold data property's data address * @size: pointer to size_t, will hold data property's data size * - * fit_image_get_data() finds data property in a given component image node. - * If the property is found its data start address and size are returned to - * the caller. + * fit_image_get_data_and_size() finds data and its size including + * both embedded and external data. If the property is found + * its data start address and size are returned to the caller. * * returns: * 0, on success - * -1, on failure + * otherwise, on failure */ -int fit_image_get_data(const void *fit, int noffset, - const void **data, size_t *size) +int fit_image_get_data_and_size(const void *fit, int noffset, + const void **data, size_t *size) { + bool external_data = false; + int offset; int len; + int ret; - *data = fdt_getprop(fit, noffset, FIT_DATA_PROP, &len); - if (*data == NULL) { - fit_get_debug(fit, noffset, FIT_DATA_PROP, len); - *size = 0; - return -1; + if (!fit_image_get_data_position(fit, noffset, &offset)) { + external_data = true; + } else if (!fit_image_get_data_offset(fit, noffset, &offset)) { + external_data = true; + /* + * For FIT with external data, figure out where + * the external images start. This is the base + * for the data-offset properties in each image. + */ + offset += ((fdt_totalsize(fit) + 3) & ~3); } - *size = len; - return 0; + if (external_data) { + debug("External Data\n"); + ret = fit_image_get_data_size(fit, noffset, &len); + *data = fit + offset; + *size = len; + } else { + ret = fit_image_get_data(fit, noffset, data, size); + } + + return ret; } /** @@ -989,34 +1207,14 @@ static int fit_image_check_hash(const void *fit, int noffset, const void *data, return 0; } -/** - * fit_image_verify - verify data integrity - * @fit: pointer to the FIT format image header - * @image_noffset: component image node offset - * - * fit_image_verify() goes over component image hash nodes, - * re-calculates each data hash and compares with the value stored in hash - * node. - * - * returns: - * 1, if all hashes are valid - * 0, otherwise (or on error) - */ -int fit_image_verify(const void *fit, int image_noffset) +int fit_image_verify_with_data(const void *fit, int image_noffset, + const void *data, size_t size) { - const void *data; - size_t size; int noffset = 0; char *err_msg = ""; int verify_all = 1; int ret; - /* Get image data and data length */ - if (fit_image_get_data(fit, image_noffset, &data, &size)) { - err_msg = "Can't get image data/size"; - goto error; - } - /* Verify all required signatures */ if (IMAGE_ENABLE_VERIFY && fit_image_verify_required_sigs(fit, image_noffset, data, size, @@ -1026,13 +1224,13 @@ int fit_image_verify(const void *fit, int image_noffset) } /* Process all hash subnodes of the component image node */ - fdt_for_each_subnode(fit, noffset, image_noffset) { + fdt_for_each_subnode(noffset, fit, image_noffset) { const char *name = fit_get_name(fit, noffset, NULL); /* * Check subnode name, must be equal to "hash". * Multiple hash nodes require unique unit node - * names, e.g. hash@1, hash@2, etc. + * names, e.g. hash-1, hash-2, etc. */ if (!strncmp(name, FIT_HASH_NODENAME, strlen(FIT_HASH_NODENAME))) { @@ -1074,6 +1272,38 @@ error: } /** + * fit_image_verify - verify data integrity + * @fit: pointer to the FIT format image header + * @image_noffset: component image node offset + * + * fit_image_verify() goes over component image hash nodes, + * re-calculates each data hash and compares with the value stored in hash + * node. + * + * returns: + * 1, if all hashes are valid + * 0, otherwise (or on error) + */ +int fit_image_verify(const void *fit, int image_noffset) +{ + const void *data; + size_t size; + int noffset = 0; + char *err_msg = ""; + + /* Get image data and data length */ + if (fit_image_get_data_and_size(fit, image_noffset, &data, &size)) { + err_msg = "Can't get image data/size"; + printf("error!\n%s for '%s' hash node in '%s' image node\n", + err_msg, fit_get_name(fit, noffset, NULL), + fit_get_name(fit, image_noffset, NULL)); + return 0; + } + + return fit_image_verify_with_data(fit, image_noffset, data, size); +} + +/** * fit_all_image_verify - verify data integrity for all images * @fit: pointer to the FIT format image header * @@ -1161,11 +1391,18 @@ int fit_image_check_os(const void *fit, int noffset, uint8_t os) int fit_image_check_arch(const void *fit, int noffset, uint8_t arch) { uint8_t image_arch; + int aarch32_support = 0; + +#ifdef CONFIG_ARM64_SUPPORT_AARCH32 + aarch32_support = 1; +#endif if (fit_image_get_arch(fit, noffset, &image_arch)) return 0; return (arch == image_arch) || - (arch == IH_ARCH_I386 && image_arch == IH_ARCH_X86_64); + (arch == IH_ARCH_I386 && image_arch == IH_ARCH_X86_64) || + (arch == IH_ARCH_ARM64 && image_arch == IH_ARCH_ARM && + aarch32_support); } /** @@ -1262,15 +1499,15 @@ int fit_check_format(const void *fit) * * / o image-tree * |-o images - * | |-o fdt@1 - * | |-o fdt@2 + * | |-o fdt-1 + * | |-o fdt-2 * | * |-o configurations - * |-o config@1 - * | |-fdt = fdt@1 + * |-o config-1 + * | |-fdt = fdt-1 * | - * |-o config@2 - * |-fdt = fdt@2 + * |-o config-2 + * |-fdt = fdt-2 * * / o U-Boot fdt * |-compatible = "foo,bar", "bim,bam" @@ -1285,6 +1522,10 @@ int fit_check_format(const void *fit) * compatible list, "foo,bar", matches a compatible string in the root of fdt1. * "bim,bam" in fdt2 matches the second string which isn't as good as fdt1. * + * As an optimization, the compatible property from the FDT's root node can be + * copied into the configuration node in the FIT image. This is required to + * match configurations with compressed FDTs. + * * returns: * offset to the configuration to use if one was found * -1 otherwise @@ -1317,48 +1558,62 @@ int fit_conf_find_compat(const void *fit, const void *fdt) for (noffset = fdt_next_node(fit, confs_noffset, &ndepth); (noffset >= 0) && (ndepth > 0); noffset = fdt_next_node(fit, noffset, &ndepth)) { - const void *kfdt; + const void *fdt; const char *kfdt_name; - int kfdt_noffset; + int kfdt_noffset, compat_noffset; const char *cur_fdt_compat; int len; - size_t size; + size_t sz; int i; if (ndepth > 1) continue; - kfdt_name = fdt_getprop(fit, noffset, "fdt", &len); - if (!kfdt_name) { - debug("No fdt property found.\n"); - continue; - } - kfdt_noffset = fdt_subnode_offset(fit, images_noffset, - kfdt_name); - if (kfdt_noffset < 0) { - debug("No image node named \"%s\" found.\n", - kfdt_name); - continue; - } - /* - * Get a pointer to this configuration's fdt. - */ - if (fit_image_get_data(fit, kfdt_noffset, &kfdt, &size)) { - debug("Failed to get fdt \"%s\".\n", kfdt_name); - continue; + /* If there's a compat property in the config node, use that. */ + if (fdt_getprop(fit, noffset, "compatible", NULL)) { + fdt = fit; /* search in FIT image */ + compat_noffset = noffset; /* search under config node */ + } else { /* Otherwise extract it from the kernel FDT. */ + kfdt_name = fdt_getprop(fit, noffset, "fdt", &len); + if (!kfdt_name) { + debug("No fdt property found.\n"); + continue; + } + kfdt_noffset = fdt_subnode_offset(fit, images_noffset, + kfdt_name); + if (kfdt_noffset < 0) { + debug("No image node named \"%s\" found.\n", + kfdt_name); + continue; + } + + if (!fit_image_check_comp(fit, kfdt_noffset, + IH_COMP_NONE)) { + debug("Can't extract compat from \"%s\" " + "(compressed)\n", kfdt_name); + continue; + } + + /* search in this config's kernel FDT */ + if (fit_image_get_data(fit, kfdt_noffset, &fdt, &sz)) { + debug("Failed to get fdt \"%s\".\n", kfdt_name); + continue; + } + + compat_noffset = 0; /* search kFDT under root node */ } len = fdt_compat_len; cur_fdt_compat = fdt_compat; /* * Look for a match for each U-Boot compatibility string in - * turn in this configuration's fdt. + * turn in the compat string property. */ for (i = 0; len > 0 && (!best_match_offset || best_match_pos > i); i++) { int cur_len = strlen(cur_fdt_compat) + 1; - if (!fdt_node_check_compatible(kfdt, 0, + if (!fdt_node_check_compatible(fdt, compat_noffset, cur_fdt_compat)) { best_match_offset = noffset; best_match_pos = i; @@ -1398,6 +1653,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) { @@ -1419,101 +1676,60 @@ 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; } -int fit_conf_get_prop_node(const void *fit, int noffset, +int fit_conf_get_prop_node_count(const void *fit, int noffset, const char *prop_name) { - char *uname; + return fdt_stringlist_count(fit, noffset, prop_name); +} + +int fit_conf_get_prop_node_index(const void *fit, int noffset, + const char *prop_name, int index) +{ + const char *uname; int len; /* get kernel image unit name from configuration kernel property */ - uname = (char *)fdt_getprop(fit, noffset, prop_name, &len); + uname = fdt_stringlist_get(fit, noffset, prop_name, index, &len); if (uname == NULL) return len; return fit_image_get_node(fit, uname); } -/** - * fit_conf_print - prints out the FIT configuration details - * @fit: pointer to the FIT format image header - * @noffset: offset of the configuration node - * @p: pointer to prefix string - * - * fit_conf_print() lists all mandatory properties for the processed - * configuration node. - * - * returns: - * no returned results - */ -void fit_conf_print(const void *fit, int noffset, const char *p) +int fit_conf_get_prop_node(const void *fit, int noffset, + const char *prop_name) { - char *desc; - char *uname; - int ret; - int loadables_index; - - /* Mandatory properties */ - ret = fit_get_desc(fit, noffset, &desc); - printf("%s Description: ", p); - if (ret) - printf("unavailable\n"); - else - printf("%s\n", desc); - - uname = (char *)fdt_getprop(fit, noffset, FIT_KERNEL_PROP, NULL); - printf("%s Kernel: ", p); - if (uname == NULL) - printf("unavailable\n"); - else - printf("%s\n", uname); - - /* Optional properties */ - uname = (char *)fdt_getprop(fit, noffset, FIT_RAMDISK_PROP, NULL); - if (uname) - printf("%s Init Ramdisk: %s\n", p, uname); - - uname = (char *)fdt_getprop(fit, noffset, FIT_FDT_PROP, NULL); - if (uname) - printf("%s FDT: %s\n", p, uname); - - uname = (char *)fdt_getprop(fit, noffset, FIT_FPGA_PROP, NULL); - if (uname) - printf("%s FPGA: %s\n", p, uname); - - /* Print out all of the specified loadables */ - for (loadables_index = 0; - fdt_get_string_index(fit, noffset, - FIT_LOADABLE_PROP, - loadables_index, - (const char **)&uname) == 0; - loadables_index++) - { - if (loadables_index == 0) { - printf("%s Loadables: ", p); - } else { - printf("%s ", p); - } - printf("%s\n", uname); - } + return fit_conf_get_prop_node_index(fit, noffset, prop_name, 0); } static int fit_image_select(const void *fit, int rd_noffset, int verify) { -#if !defined(USE_HOSTCC) && defined(CONFIG_FIT_IMAGE_POST_PROCESS) - const void *data; - size_t size; - int ret; -#endif - fit_image_print(fit, rd_noffset, " "); if (verify) { @@ -1525,23 +1741,6 @@ static int fit_image_select(const void *fit, int rd_noffset, int verify) puts("OK\n"); } -#if !defined(USE_HOSTCC) && defined(CONFIG_FIT_IMAGE_POST_PROCESS) - ret = fit_image_get_data(fit, rd_noffset, &data, &size); - if (ret) - return ret; - - /* perform any post-processing on the image data */ - board_fit_image_post_process((void **)&data, &size); - - /* - * update U-Boot's understanding of the "data" property start address - * and size according to the performed post-processing - */ - ret = fdt_setprop((void *)fit, rd_noffset, FIT_DATA_PROP, data, size); - if (ret) - return ret; -#endif - return 0; } @@ -1598,6 +1797,8 @@ static const char *fit_get_image_type_property(int type) return FIT_LOADABLE_PROP; case IH_TYPE_FPGA: return FIT_FPGA_PROP; + case IH_TYPE_STANDALONE: + return FIT_STANDALONE_PROP; } return "unknown"; @@ -1611,18 +1812,24 @@ int fit_image_load(bootm_headers_t *images, ulong addr, int cfg_noffset, noffset; const char *fit_uname; const char *fit_uname_config; + const char *fit_base_uname_config; const void *fit; - const void *buf; + void *buf; + void *loadbuf; size_t size; int type_ok, os_ok; - ulong load, data, len; - uint8_t os; + ulong load, load_end, data, len; + uint8_t os, comp; +#ifndef USE_HOSTCC + uint8_t os_arch; +#endif const char *prop_name; int ret; fit = map_sysmem(addr, 0); fit_uname = fit_unamep ? *fit_unamep : NULL; fit_uname_config = fit_uname_configp ? *fit_uname_configp : NULL; + fit_base_uname_config = NULL; prop_name = fit_get_image_type_property(image_type); printf("## Loading %s from FIT Image at %08lx ...\n", prop_name, addr); @@ -1656,24 +1863,26 @@ int fit_image_load(bootm_headers_t *images, ulong addr, 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"); + + fit_base_uname_config = fdt_get_name(fit, cfg_noffset, NULL); + printf(" Using '%s' configuration\n", fit_base_uname_config); + /* Remember this config */ + if (image_type == IH_TYPE_KERNEL) + images->fit_uname_cfg = fit_base_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; } - bootstage_mark(BOOTSTAGE_ID_FIT_CONFIG); + 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); @@ -1700,11 +1909,11 @@ int fit_image_load(bootm_headers_t *images, ulong addr, return -ENOEXEC; } #endif - if (image_type == IH_TYPE_FLATDT && - !fit_image_check_comp(fit, noffset, IH_COMP_NONE)) { - puts("FDT image is compressed"); - return -EPROTONOSUPPORT; - } + +#ifndef USE_HOSTCC + fit_image_get_arch(fit, noffset, &os_arch); + images->os.arch = os_arch; +#endif bootstage_mark(bootstage_id + BOOTSTAGE_SUB_CHECK_ALL); type_ok = fit_image_check_type(fit, noffset, image_type) || @@ -1736,32 +1945,24 @@ int fit_image_load(bootm_headers_t *images, ulong addr, bootstage_mark(bootstage_id + BOOTSTAGE_SUB_CHECK_ALL_OK); /* get image data address and length */ - if (fit_image_get_data(fit, noffset, &buf, &size)) { + if (fit_image_get_data_and_size(fit, noffset, + (const void **)&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(buf)) { - puts("Subimage data is not a FDT"); - return -ENOEXEC; - } - bootstage_mark(bootstage_id + BOOTSTAGE_SUB_GET_DATA_OK); +#if !defined(USE_HOSTCC) && defined(CONFIG_FIT_IMAGE_POST_PROCESS) + /* perform any post-processing on the image data */ + board_fit_image_post_process(&buf, &size); +#endif - /* - * Work-around for eldk-4.2 which gives this warning if we try to - * cast in the unmap_sysmem() call: - * warning: initialization discards qualifiers from pointer target type - */ - { - void *vbuf = (void *)buf; + len = (ulong)size; - data = map_to_sysmem(vbuf); - } + bootstage_mark(bootstage_id + BOOTSTAGE_SUB_GET_DATA_OK); + data = map_to_sysmem(buf); + load = data; if (load_op == FIT_LOAD_IGNORED) { /* Don't load */ } else if (fit_image_get_load(fit, noffset, &load)) { @@ -1773,8 +1974,6 @@ int fit_image_load(bootm_headers_t *images, ulong addr, } } else if (load_op != FIT_LOAD_OPTIONAL_NON_ZERO || load) { ulong image_start, image_end; - ulong load_end; - void *dst; /* * move image data to the load address, @@ -1792,19 +1991,51 @@ int fit_image_load(bootm_headers_t *images, ulong addr, printf(" Loading %s from 0x%08lx to 0x%08lx\n", prop_name, data, load); + } else { + load = data; /* No load address specified */ + } + + comp = IH_COMP_NONE; + loadbuf = buf; + /* Kernel images get decompressed later in bootm_load_os(). */ + if (!(image_type == IH_TYPE_KERNEL || + image_type == IH_TYPE_KERNEL_NOLOAD) && + !fit_image_get_comp(fit, noffset, &comp) && + comp != IH_COMP_NONE) { + ulong max_decomp_len = len * 20; + if (load == data) { + loadbuf = malloc(max_decomp_len); + load = map_to_sysmem(loadbuf); + } else { + loadbuf = map_sysmem(load, max_decomp_len); + } + if (image_decomp(comp, load, data, image_type, + loadbuf, buf, len, max_decomp_len, &load_end)) { + printf("Error decompressing %s\n", prop_name); - dst = map_sysmem(load, len); - memmove(dst, buf, len); - data = load; + return -ENOEXEC; + } + len = load_end - load; + } else if (load != data) { + loadbuf = map_sysmem(load, len); + memcpy(loadbuf, buf, len); + } + + /* verify that image data is a proper FDT blob */ + if (image_type == IH_TYPE_FLATDT && fdt_check_header(loadbuf)) { + puts("Subimage data is not a FDT"); + return -ENOEXEC; } + bootstage_mark(bootstage_id + BOOTSTAGE_SUB_LOAD); - *datap = data; + *datap = load; *lenp = len; if (fit_unamep) *fit_unamep = (char *)fit_uname; if (fit_uname_configp) - *fit_uname_configp = (char *)fit_uname_config; + *fit_uname_configp = (char *)(fit_uname_config ? : + fit_base_uname_config); return noffset; } @@ -1828,3 +2059,156 @@ 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 : "", + fit_uname_config ? fit_uname_config : ""); + + 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; + + /* + * fit_image_load() would load the first FDT from the + * extra config only when uconfig is specified. + * Check if the extra config contains multiple FDTs and + * if so, load them. + */ + cfg_noffset = fit_conf_get_node(fit, uconfig); + + i = 0; + count = fit_conf_get_prop_node_count(fit, cfg_noffset, + FIT_FDT_PROP); + } + + 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