X-Git-Url: https://git.kernelconcepts.de/?a=blobdiff_plain;f=common%2Fimage-fit.c;h=255c4cac9cafa328d33cd382e524207c1728c7cc;hb=91cbd792c46c916ef196c5b7cd16ff592d2f3632;hp=254feecaad7cf807bf905aabfc49f806bc92f70c;hpb=a19b0dd62d7b8efc658fa1aa685ff5665878f3ee;p=karo-tx-uboot.git diff --git a/common/image-fit.c b/common/image-fit.c index 254feecaad..255c4cac9c 100644 --- a/common/image-fit.c +++ b/common/image-fit.c @@ -6,23 +6,7 @@ * (C) Copyright 2000-2006 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * SPDX-License-Identifier: GPL-2.0+ */ #ifdef USE_HOSTCC @@ -31,12 +15,16 @@ #include #else #include +#include +#include +DECLARE_GLOBAL_DATA_PTR; #endif /* !USE_HOSTCC*/ #include -#include #include #include +#include +#include /*****************************************************************************/ /* New uImage format routines */ @@ -71,7 +59,7 @@ static int fit_parse_spec(const char *spec, char sepc, ulong addr_curr, * @conf_name double pointer to a char, will hold pointer to a configuration * unit name * - * fit_parse_conf() expects configuration spec in the for of []#, + * fit_parse_conf() expects configuration spec in the form of []#, * where is a FIT image address that contains configuration * with a unit name. * @@ -97,7 +85,7 @@ int fit_parse_conf(const char *spec, ulong addr_curr, * subimage * @image_name: double pointer to a char, will hold pointer to a subimage name * - * fit_parse_subimage() expects subimage spec in the for of + * fit_parse_subimage() expects subimage spec in the form of * []:, where is a FIT image address that contains * subimage with a unit name. * @@ -231,42 +219,45 @@ void fit_print_contents(const void *fit) * @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 properies 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) +static void fit_image_print_data(const void *fit, int noffset, const char *p, + const char *type) { - char *algo; + const char *keyname; uint8_t *value; int value_len; - int i, ret; - - /* - * Check subnode name, must be equal to "hash". - * Multiple hash nodes require unique unit node - * names, e.g. hash@1, hash@2, etc. - */ - if (strncmp(fit_get_name(fit, noffset, NULL), - FIT_HASH_NODENAME, - strlen(FIT_HASH_NODENAME)) != 0) - return; + char *algo; + int required; + int ret, i; - debug("%s Hash node: '%s'\n", p, + debug("%s %s node: '%s'\n", p, type, fit_get_name(fit, noffset, NULL)); - - printf("%s Hash algo: ", p); + printf("%s %s algo: ", p, type); if (fit_image_hash_get_algo(fit, noffset, &algo)) { printf("invalid/unsupported\n"); return; } - printf("%s\n", algo); + 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 Hash value: ", p); + printf("%s %s value: ", p, type); if (ret) { printf("unavailable\n"); } else { @@ -275,7 +266,18 @@ static void fit_image_print_data(const void *fit, int noffset, const char *p) printf("\n"); } - debug("%s Hash len: %d\n", p, value_len); + 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); + } } /** @@ -300,8 +302,12 @@ static void fit_image_print_verification_data(const void *fit, int noffset, * 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); + 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"); + } } /** @@ -338,6 +344,17 @@ void fit_image_print(const void *fit, int image_noffset, const char *p) else printf("%s\n", desc); + if (IMAGE_ENABLE_TIMESTAMP) { + time_t timestamp; + + ret = fit_get_timestamp(fit, 0, ×tamp); + printf("%s Created: ", p); + if (ret) + printf("unavailable\n"); + else + genimg_print_time(timestamp); + } + fit_image_get_type(fit, image_noffset, &type); printf("%s Type: %s\n", p, genimg_get_type_name(type)); @@ -348,10 +365,13 @@ void fit_image_print(const void *fit, int image_noffset, const char *p) #ifndef USE_HOSTCC printf("%s Data Start: ", p); - if (ret) + if (ret) { printf("unavailable\n"); - else - printf("0x%08lx\n", (ulong)data); + } else { + void *vdata = (void *)data; + + printf("0x%08lx\n", (ulong)map_to_sysmem(vdata)); + } #endif printf("%s Data Size: ", p); @@ -813,7 +833,7 @@ static int fit_image_hash_get_ignore(const void *fit, int noffset, int *ignore) * * returns: * 0, on success - * -1, on property read failure + * -ENOSPC if no space in device tree, -1 for other error */ int fit_set_timestamp(void *fit, int noffset, time_t timestamp) { @@ -827,7 +847,7 @@ int fit_set_timestamp(void *fit, int noffset, time_t timestamp) printf("Can't set '%s' property for '%s' node (%s)\n", FIT_TIMESTAMP_PROP, fit_get_name(fit, noffset, NULL), fdt_strerror(ret)); - return -1; + return ret == -FDT_ERR_NOSPACE ? -ENOSPC : -1; } return 0; @@ -863,6 +883,10 @@ int calculate_hash(const void *data, int data_len, const char *algo, sha1_csum_wd((unsigned char *)data, data_len, (unsigned char *)value, CHUNKSZ_SHA1); *value_len = 20; + } else if (IMAGE_ENABLE_SHA256 && strcmp(algo, "sha256") == 0) { + sha256_csum_wd((unsigned char *)data, data_len, + (unsigned char *)value, CHUNKSZ_SHA256); + *value_len = SHA256_SUM_LEN; } else if (IMAGE_ENABLE_MD5 && strcmp(algo, "md5") == 0) { md5_wd((unsigned char *)data, data_len, value, CHUNKSZ_MD5); *value_len = 16; @@ -938,13 +962,23 @@ int fit_image_verify(const void *fit, int image_noffset) { const void *data; size_t size; - int noffset; + 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"; - return 0; + goto error; + } + + /* Verify all required signatures */ + if (IMAGE_ENABLE_VERIFY && + fit_image_verify_required_sigs(fit, image_noffset, data, size, + gd_fdt_blob(), &verify_all)) { + err_msg = "Unable to verify required signature"; + goto error; } /* Process all hash subnodes of the component image node */ @@ -964,6 +998,15 @@ int fit_image_verify(const void *fit, int image_noffset) &err_msg)) goto error; puts("+ "); + } else if (IMAGE_ENABLE_VERIFY && verify_all && + !strncmp(name, FIT_SIG_NODENAME, + strlen(FIT_SIG_NODENAME))) { + ret = fit_image_check_sig(fit, noffset, data, + size, -1, &err_msg); + if (ret) + puts("- "); + else + puts("+ "); } } @@ -1293,7 +1336,7 @@ int fit_conf_find_compat(const void *fit, const void *fdt) * * When NULL is provided in second argument fit_conf_get_node() will search * for a default configuration node instead. Default configuration node unit - * name is retrived from FIT_DEFAULT_PROP property of the '/configurations' + * name is retrieved from FIT_DEFAULT_PROP property of the '/configurations' * node. * * returns: @@ -1348,63 +1391,6 @@ int fit_conf_get_prop_node(const void *fit, int noffset, return fit_image_get_node(fit, uname); } -/** - * fit_conf_get_kernel_node - get kernel image node offset that corresponds to - * a given configuration - * @fit: pointer to the FIT format image header - * @noffset: configuration node offset - * - * fit_conf_get_kernel_node() retrives kernel image node unit name from - * configuration FIT_KERNEL_PROP property and translates it to the node - * offset. - * - * returns: - * image node offset when found (>=0) - * negative number on failure (FDT_ERR_* code) - */ -int fit_conf_get_kernel_node(const void *fit, int noffset) -{ - return fit_conf_get_prop_node(fit, noffset, FIT_KERNEL_PROP); -} - -/** - * fit_conf_get_ramdisk_node - get ramdisk image node offset that corresponds to - * a given configuration - * @fit: pointer to the FIT format image header - * @noffset: configuration node offset - * - * fit_conf_get_ramdisk_node() retrives ramdisk image node unit name from - * configuration FIT_KERNEL_PROP property and translates it to the node - * offset. - * - * returns: - * image node offset when found (>=0) - * negative number on failure (FDT_ERR_* code) - */ -int fit_conf_get_ramdisk_node(const void *fit, int noffset) -{ - return fit_conf_get_prop_node(fit, noffset, FIT_RAMDISK_PROP); -} - -/** - * fit_conf_get_fdt_node - get fdt image node offset that corresponds to - * a given configuration - * @fit: pointer to the FIT format image header - * @noffset: configuration node offset - * - * fit_conf_get_fdt_node() retrives fdt image node unit name from - * configuration FIT_KERNEL_PROP property and translates it to the node - * offset. - * - * returns: - * image node offset when found (>=0) - * negative number on failure (FDT_ERR_* code) - */ -int fit_conf_get_fdt_node(const void *fit, int noffset) -{ - return fit_conf_get_prop_node(fit, noffset, FIT_FDT_PROP); -} - /** * fit_conf_print - prints out the FIT configuration details * @fit: pointer to the FIT format image header @@ -1448,22 +1434,7 @@ void fit_conf_print(const void *fit, int noffset, const char *p) printf("%s FDT: %s\n", p, uname); } -/** - * fit_check_ramdisk - verify FIT format ramdisk subimage - * @fit_hdr: pointer to the FIT ramdisk header - * @rd_noffset: ramdisk subimage node offset within FIT image - * @arch: requested ramdisk image architecture type - * @verify: data CRC verification flag - * - * fit_check_ramdisk() verifies integrity of the ramdisk subimage and from - * specified FIT image. - * - * returns: - * 1, on success - * 0, on failure - */ -int fit_check_ramdisk(const void *fit, int rd_noffset, uint8_t arch, - int verify) +int fit_image_select(const void *fit, int rd_noffset, int verify) { fit_image_print(fit, rd_noffset, " "); @@ -1471,22 +1442,254 @@ int fit_check_ramdisk(const void *fit, int rd_noffset, uint8_t arch, puts(" Verifying Hash Integrity ... "); if (!fit_image_verify(fit, rd_noffset)) { puts("Bad Data Hash\n"); - bootstage_error(BOOTSTAGE_ID_FIT_RD_HASH); - return 0; + return -EACCES; } puts("OK\n"); } - bootstage_mark(BOOTSTAGE_ID_FIT_RD_CHECK_ALL); - if (!fit_image_check_os(fit, rd_noffset, IH_OS_LINUX) || - !fit_image_check_arch(fit, rd_noffset, arch) || - !fit_image_check_type(fit, rd_noffset, IH_TYPE_RAMDISK)) { - printf("No Linux %s Ramdisk Image\n", - genimg_get_arch_name(arch)); - bootstage_error(BOOTSTAGE_ID_FIT_RD_CHECK_ALL); - return 0; + return 0; +} + +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; } - bootstage_mark(BOOTSTAGE_ID_FIT_RD_CHECK_ALL_OK); - return 1; + 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; +} + +/** + * fit_get_image_type_property() - get property name for IH_TYPE_... + * + * @return the properly name where we expect to find the image in the + * config node + */ +static const char *fit_get_image_type_property(int type) +{ + /* + * This is sort-of available in the uimage_type[] table in image.c + * but we don't have access to the sohrt name, and "fdt" is different + * anyway. So let's just keep it here. + */ + switch (type) { + case IH_TYPE_FLATDT: + return FIT_FDT_PROP; + case IH_TYPE_KERNEL: + return FIT_KERNEL_PROP; + case IH_TYPE_RAMDISK: + return FIT_RAMDISK_PROP; + } + + return "unknown"; +} + +int fit_image_load(bootm_headers_t *images, 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; + 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; + prop_name = fit_get_image_type_property(image_type); + 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 FIT 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); +#ifndef USE_HOSTCC + if (!fit_image_check_target_arch(fit, noffset)) { + puts("Unsupported Architecture\n"); + bootstage_error(bootstage_id + BOOTSTAGE_SUB_CHECK_ARCH); + 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; + } + + 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(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 + * cast 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 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, + * 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; }