]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - common/image-fit.c
Merge branch 'tx51-bugfix' into karo-tx-merge
[karo-tx-uboot.git] / common / image-fit.c
index 3ba1ad3a604163dd55cd9ebae595b775d028bbd0..683c1a511d8f4882e6f16119d92569ffb6a36801 100644 (file)
@@ -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,6 +15,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>
@@ -124,6 +111,7 @@ static void fit_get_debug(const void *fit, int noffset,
              fdt_strerror(err));
 }
 
+#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_FIT_SPL_PRINT)
 /**
  * fit_print_contents - prints out the contents of the FIT format image
  * @fit: pointer to the FIT format image header
@@ -149,11 +137,8 @@ void fit_print_contents(const void *fit)
        const char *p;
        time_t timestamp;
 
-#ifdef USE_HOSTCC
-       p = "";
-#else
-       p = "   ";
-#endif
+       /* Indent string is defined in header image.h */
+       p = IMAGE_INDENT_STRING;
 
        /* Root node properties */
        ret = fit_get_desc(fit, 0, &desc);
@@ -228,6 +213,102 @@ 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 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,
+                                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, &timestamp))
+                       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 properies 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
@@ -272,10 +353,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);
@@ -323,61 +407,11 @@ void fit_image_print(const void *fit, int image_noffset, const char *p)
             noffset = fdt_next_node(fit, noffset, &ndepth)) {
                if (ndepth == 1) {
                        /* Direct child node of the component image node */
-                       fit_image_print_hash(fit, noffset, p);
+                       fit_image_print_verification_data(fit, noffset, p);
                }
        }
 }
-
-/**
- * fit_image_print_hash - 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
- *
- * fit_image_print_hash() lists properies for the processed hash node
- *
- * returns:
- *     no returned results
- */
-void fit_image_print_hash(const void *fit, int noffset, const char *p)
-{
-       char *algo;
-       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;
-
-       debug("%s  Hash node:    '%s'\n", p,
-             fit_get_name(fit, noffset, NULL));
-
-       printf("%s  Hash algo:    ", p);
-       if (fit_image_hash_get_algo(fit, noffset, &algo)) {
-               printf("invalid/unsupported\n");
-               return;
-       }
-       printf("%s\n", algo);
-
-       ret = fit_image_hash_get_value(fit, noffset, &value,
-                                       &value_len);
-       printf("%s  Hash value:   ", p);
-       if (ret) {
-               printf("unavailable\n");
-       } else {
-               for (i = 0; i < value_len; i++)
-                       printf("%02x", value[i]);
-               printf("\n");
-       }
-
-       debug("%s  Hash len:     %d\n", p, value_len);
-}
+#endif
 
 /**
  * fit_get_desc - get node description property
@@ -748,7 +782,6 @@ int fit_image_hash_get_value(const void *fit, int noffset, uint8_t **value,
        return 0;
 }
 
-#ifndef USE_HOSTCC
 /**
  * fit_image_hash_get_ignore - get hash ignore flag
  * @fit: pointer to the FIT format image header
@@ -763,7 +796,7 @@ int fit_image_hash_get_value(const void *fit, int noffset, uint8_t **value,
  *     0, on ignore not found
  *     value, on ignore found
  */
-int fit_image_hash_get_ignore(const void *fit, int noffset, int *ignore)
+static int fit_image_hash_get_ignore(const void *fit, int noffset, int *ignore)
 {
        int len;
        int *value;
@@ -776,7 +809,6 @@ int fit_image_hash_get_ignore(const void *fit, int noffset, int *ignore)
 
        return 0;
 }
-#endif
 
 /**
  * fit_set_timestamp - set node timestamp property
@@ -827,19 +859,19 @@ int fit_set_timestamp(void *fit, int noffset, time_t timestamp)
  *     0, on success
  *    -1, when algo is unsupported
  */
-static int calculate_hash(const void *data, int data_len, const char *algo,
+int calculate_hash(const void *data, int data_len, const char *algo,
                        uint8_t *value, int *value_len)
 {
-       if (strcmp(algo, "crc32") == 0) {
+       if (IMAGE_ENABLE_CRC32 && strcmp(algo, "crc32") == 0) {
                *((uint32_t *)value) = crc32_wd(0, data, data_len,
                                                        CHUNKSZ_CRC32);
                *((uint32_t *)value) = cpu_to_uimage(*((uint32_t *)value));
                *value_len = 4;
-       } else if (strcmp(algo, "sha1") == 0) {
+       } else if (IMAGE_ENABLE_SHA1 && strcmp(algo, "sha1") == 0) {
                sha1_csum_wd((unsigned char *)data, data_len,
                             (unsigned char *)value, CHUNKSZ_SHA1);
                *value_len = 20;
-       } else if (strcmp(algo, "md5") == 0) {
+       } else if (IMAGE_ENABLE_MD5 && strcmp(algo, "md5") == 0) {
                md5_wd((unsigned char *)data, data_len, value, CHUNKSZ_MD5);
                *value_len = 16;
        } else {
@@ -849,181 +881,60 @@ static int calculate_hash(const void *data, int data_len, const char *algo,
        return 0;
 }
 
-#ifdef USE_HOSTCC
-/**
- * fit_set_hashes - process FIT component image nodes and calculate hashes
- * @fit: pointer to the FIT format image header
- *
- * fit_set_hashes() adds hash values for all component images in the FIT blob.
- * Hashes are calculated for all component images which have hash subnodes
- * with algorithm property set to one of the supported hash algorithms.
- *
- * returns
- *     0, on success
- *     libfdt error code, on failure
- */
-int fit_set_hashes(void *fit)
-{
-       int images_noffset;
-       int noffset;
-       int ndepth;
-       int ret;
-
-       /* Find images parent node offset */
-       images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
-       if (images_noffset < 0) {
-               printf("Can't find images parent node '%s' (%s)\n",
-                      FIT_IMAGES_PATH, fdt_strerror(images_noffset));
-               return images_noffset;
-       }
-
-       /* Process its subnodes, print out component images details */
-       for (ndepth = 0, noffset = fdt_next_node(fit, images_noffset, &ndepth);
-            (noffset >= 0) && (ndepth > 0);
-            noffset = fdt_next_node(fit, noffset, &ndepth)) {
-               if (ndepth == 1) {
-                       /*
-                        * Direct child node of the images parent node,
-                        * i.e. component image node.
-                        */
-                       ret = fit_image_set_hashes(fit, noffset);
-                       if (ret)
-                               return ret;
-               }
-       }
-
-       return 0;
-}
-
-/**
- * fit_image_set_hashes - calculate/set hashes for given component image node
- * @fit: pointer to the FIT format image header
- * @image_noffset: requested component image node
- *
- * fit_image_set_hashes() adds hash values for an component image node. All
- * existing hash subnodes are checked, if algorithm property is set to one of
- * the supported hash algorithms, hash value is computed and corresponding
- * hash node property is set, for example:
- *
- * Input component image node structure:
- *
- * o image@1 (at image_noffset)
- *   | - data = [binary data]
- *   o hash@1
- *     |- algo = "sha1"
- *
- * Output component image node structure:
- *
- * o image@1 (at image_noffset)
- *   | - data = [binary data]
- *   o hash@1
- *     |- algo = "sha1"
- *     |- value = sha1(data)
- *
- * returns:
- *     0 on sucess
- *    <0 on failure
- */
-int fit_image_set_hashes(void *fit, int image_noffset)
+static int fit_image_check_hash(const void *fit, int noffset, const void *data,
+                               size_t size, char **err_msgp)
 {
-       const void *data;
-       size_t size;
-       char *algo;
        uint8_t value[FIT_MAX_HASH_LEN];
        int value_len;
-       int noffset;
-       int ndepth;
+       char *algo;
+       uint8_t *fit_value;
+       int fit_value_len;
+       int ignore;
 
-       /* Get image data and data length */
-       if (fit_image_get_data(fit, image_noffset, &data, &size)) {
-               printf("Can't get image data/size\n");
+       *err_msgp = NULL;
+
+       if (fit_image_hash_get_algo(fit, noffset, &algo)) {
+               *err_msgp = "Can't get hash algo property";
                return -1;
        }
+       printf("%s", algo);
 
-       /* 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 */
-
-                       /*
-                        * 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) {
-                               /* Not a hash subnode, skip it */
-                               continue;
-                       }
-
-                       if (fit_image_hash_get_algo(fit, noffset, &algo)) {
-                               printf("Can't get hash algo property for '%s' hash node in '%s' image node\n",
-                                      fit_get_name(fit, noffset, NULL),
-                                      fit_get_name(fit, image_noffset, NULL));
-                               return -1;
-                       }
-
-                       if (calculate_hash(data, size, algo, value,
-                                          &value_len)) {
-                               printf("Unsupported hash algorithm (%s) for '%s' hash node in '%s' image node\n",
-                                      algo, fit_get_name(fit, noffset, NULL),
-                                      fit_get_name(fit, image_noffset, NULL));
-                               return -1;
-                       }
-
-                       if (fit_image_hash_set_value(fit, noffset, value,
-                                                    value_len)) {
-                               printf("Can't set hash value for '%s' hash node in '%s' image node\n",
-                                      fit_get_name(fit, noffset, NULL),
-                                      fit_get_name(fit, image_noffset, NULL));
-                               return -1;
-                       }
+       if (IMAGE_ENABLE_IGNORE) {
+               fit_image_hash_get_ignore(fit, noffset, &ignore);
+               if (ignore) {
+                       printf("-skipped ");
+                       return 0;
                }
        }
 
-       return 0;
-}
+       if (fit_image_hash_get_value(fit, noffset, &fit_value,
+                                    &fit_value_len)) {
+               *err_msgp = "Can't get hash value property";
+               return -1;
+       }
 
-/**
- * fit_image_hash_set_value - set hash value in requested has node
- * @fit: pointer to the FIT format image header
- * @noffset: hash node offset
- * @value: hash value to be set
- * @value_len: hash value length
- *
- * fit_image_hash_set_value() attempts to set hash value in a node at offset
- * given and returns operation status to the caller.
- *
- * returns
- *     0, on success
- *     -1, on failure
- */
-int fit_image_hash_set_value(void *fit, int noffset, uint8_t *value,
-                               int value_len)
-{
-       int ret;
+       if (calculate_hash(data, size, algo, value, &value_len)) {
+               *err_msgp = "Unsupported hash algorithm";
+               return -1;
+       }
 
-       ret = fdt_setprop(fit, noffset, FIT_VALUE_PROP, value, value_len);
-       if (ret) {
-               printf("Can't set hash '%s' property for '%s' node(%s)\n",
-                      FIT_VALUE_PROP, fit_get_name(fit, noffset, NULL),
-                      fdt_strerror(ret));
+       if (value_len != fit_value_len) {
+               *err_msgp = "Bad hash value len";
+               return -1;
+       } else if (memcmp(value, fit_value, value_len) != 0) {
+               *err_msgp = "Bad hash value";
                return -1;
        }
 
        return 0;
 }
-#endif /* USE_HOSTCC */
 
 /**
- * fit_image_check_hashes - verify data intergity
+ * fit_image_verify - verify data intergity
  * @fit: pointer to the FIT format image header
  * @image_noffset: component image node offset
  *
- * fit_image_check_hashes() goes over component image hash nodes,
+ * fit_image_verify() goes over component image hash nodes,
  * re-calculates each data hash and compares with the value stored in hash
  * node.
  *
@@ -1031,110 +942,84 @@ int fit_image_hash_set_value(void *fit, int noffset, uint8_t *value,
  *     1, if all hashes are valid
  *     0, otherwise (or on error)
  */
-int fit_image_check_hashes(const void *fit, int image_noffset)
+int fit_image_verify(const void *fit, int image_noffset)
 {
        const void      *data;
        size_t          size;
-       char            *algo;
-       uint8_t         *fit_value;
-       int             fit_value_len;
-#ifndef USE_HOSTCC
-       int             ignore;
-#endif
-       uint8_t         value[FIT_MAX_HASH_LEN];
-       int             value_len;
-       int             noffset;
-       int             ndepth;
+       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)) {
-               printf("Can't get image data/size\n");
-               return 0;
+               err_msg = "Can't get image data/size";
+               goto error;
        }
 
-       /* 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 */
-
-                       /*
-                        * 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)
-                               continue;
-
-                       if (fit_image_hash_get_algo(fit, noffset, &algo)) {
-                               err_msg = " error!\nCan't get hash algo property";
-                               goto error;
-                       }
-                       printf("%s", algo);
-
-#ifndef USE_HOSTCC
-                       fit_image_hash_get_ignore(fit, noffset, &ignore);
-                       if (ignore) {
-                               printf("-skipped ");
-                               continue;
-                       }
-#endif
-
-                       if (fit_image_hash_get_value(fit, noffset, &fit_value,
-                                                    &fit_value_len)) {
-                               err_msg = " error!\nCan't get hash value "
-                                               "property";
-                               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;
+       }
 
-                       if (calculate_hash(data, size, algo, value,
-                                          &value_len)) {
-                               err_msg = " error!\n"
-                                               "Unsupported hash algorithm";
-                               goto error;
-                       }
+       /* Process all hash subnodes of the component image node */
+       for (noffset = fdt_first_subnode(fit, image_noffset);
+            noffset >= 0;
+            noffset = fdt_next_subnode(fit, noffset)) {
+               const char *name = fit_get_name(fit, noffset, NULL);
 
-                       if (value_len != fit_value_len) {
-                               err_msg = " error !\nBad hash value len";
-                               goto error;
-                       } else if (memcmp(value, fit_value, value_len) != 0) {
-                               err_msg = " error!\nBad hash value";
+               /*
+                * 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(name, FIT_HASH_NODENAME,
+                            strlen(FIT_HASH_NODENAME))) {
+                       if (fit_image_check_hash(fit, noffset, data, size,
+                                                &err_msg))
                                goto error;
-                       }
-                       printf("+ ");
+                       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("+ ");
                }
        }
 
        if (noffset == -FDT_ERR_TRUNCATED || noffset == -FDT_ERR_BADSTRUCTURE) {
-               err_msg = " error!\nCorrupted or truncated tree";
+               err_msg = "Corrupted or truncated tree";
                goto error;
        }
 
        return 1;
 
 error:
-       printf("%s for '%s' hash node in '%s' image node\n",
+       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;
 }
 
 /**
- * fit_all_image_check_hashes - verify data intergity for all images
+ * fit_all_image_verify - verify data intergity for all images
  * @fit: pointer to the FIT format image header
  *
- * fit_all_image_check_hashes() goes over all images in the FIT and
+ * fit_all_image_verify() goes over all images in the FIT and
  * for every images checks if all it's hashes are valid.
  *
  * returns:
  *     1, if all hashes of all images are valid
  *     0, otherwise (or on error)
  */
-int fit_all_image_check_hashes(const void *fit)
+int fit_all_image_verify(const void *fit)
 {
        int images_noffset;
        int noffset;
@@ -1164,7 +1049,7 @@ int fit_all_image_check_hashes(const void *fit)
                        printf("   Hash(es) for Image %u (%s): ", count++,
                               fit_get_name(fit, noffset, NULL));
 
-                       if (!fit_image_check_hashes(fit, noffset))
+                       if (!fit_image_verify(fit, noffset))
                                return 0;
                        printf("\n");
                }
@@ -1476,7 +1361,7 @@ int fit_conf_get_node(const void *fit, const char *conf_uname)
        return noffset;
 }
 
-static int __fit_conf_get_prop_node(const void *fit, int noffset,
+int fit_conf_get_prop_node(const void *fit, int noffset,
                const char *prop_name)
 {
        char *uname;
@@ -1490,63 +1375,6 @@ static 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
@@ -1590,47 +1418,234 @@ 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
- */
-#ifndef USE_HOSTCC
-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, "   ");
 
        if (verify) {
                puts("   Verifying Hash Integrity ... ");
-               if (!fit_image_check_hashes(fit, rd_noffset)) {
+               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;
+}
+
+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;
 }
-#endif /* USE_HOSTCC */