Merge branch '2019-10-28-azure-ci-support'
[oweals/u-boot.git] / common / hash.c
index 9e9f84b9fb43b0c86b16bab668a9244f0419fd0b..d0d825e38986669835a26bf663cf5d7587a82476 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * Copyright (c) 2012 The Chromium OS Authors.
  *
@@ -6,17 +7,17 @@
  *
  * (C) Copyright 2000
  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
- *
- * SPDX-License-Identifier:    GPL-2.0+
  */
 
 #ifndef USE_HOSTCC
 #include <common.h>
 #include <command.h>
+#include <env.h>
 #include <malloc.h>
+#include <mapmem.h>
 #include <hw_sha.h>
 #include <asm/io.h>
-#include <asm/errno.h>
+#include <linux/errno.h>
 #else
 #include "mkimage.h"
 #include <time.h>
 #include <u-boot/sha256.h>
 #include <u-boot/md5.h>
 
-#ifdef CONFIG_SHA1
+#if !defined(USE_HOSTCC) && defined(CONFIG_NEEDS_MANUAL_RELOC)
+DECLARE_GLOBAL_DATA_PTR;
+#endif
+
+static void reloc_update(void);
+
+#if defined(CONFIG_SHA1) && !defined(CONFIG_SHA_PROG_HW_ACCEL)
 static int hash_init_sha1(struct hash_algo *algo, void **ctxp)
 {
        sha1_context *ctx = malloc(sizeof(sha1_context));
@@ -57,7 +64,7 @@ static int hash_finish_sha1(struct hash_algo *algo, void *ctx, void *dest_buf,
 }
 #endif
 
-#ifdef CONFIG_SHA256
+#if defined(CONFIG_SHA256) && !defined(CONFIG_SHA_PROG_HW_ACCEL)
 static int hash_init_sha256(struct hash_algo *algo, void **ctxp)
 {
        sha256_context *ctx = malloc(sizeof(sha256_context));
@@ -85,6 +92,33 @@ static int hash_finish_sha256(struct hash_algo *algo, void *ctx, void
 }
 #endif
 
+static int hash_init_crc16_ccitt(struct hash_algo *algo, void **ctxp)
+{
+       uint16_t *ctx = malloc(sizeof(uint16_t));
+       *ctx = 0;
+       *ctxp = ctx;
+       return 0;
+}
+
+static int hash_update_crc16_ccitt(struct hash_algo *algo, void *ctx,
+                                  const void *buf, unsigned int size,
+                                  int is_last)
+{
+       *((uint16_t *)ctx) = crc16_ccitt(*((uint16_t *)ctx), buf, size);
+       return 0;
+}
+
+static int hash_finish_crc16_ccitt(struct hash_algo *algo, void *ctx,
+                                  void *dest_buf, int size)
+{
+       if (size < algo->digest_size)
+               return -1;
+
+       *((uint16_t *)dest_buf) = *((uint16_t *)ctx);
+       free(ctx);
+       return 0;
+}
+
 static int hash_init_crc32(struct hash_algo *algo, void **ctxp)
 {
        uint32_t *ctx = malloc(sizeof(uint32_t));
@@ -112,90 +146,106 @@ static int hash_finish_crc32(struct hash_algo *algo, void *ctx, void *dest_buf,
 }
 
 /*
- * These are the hash algorithms we support. Chips which support accelerated
- * crypto could perhaps add named version of these algorithms here. Note that
- * algorithm names must be in lower case.
+ * These are the hash algorithms we support.  If we have hardware acceleration
+ * is enable we will use that, otherwise a software version of the algorithm.
+ * Note that algorithm names must be in lower case.
  */
 static struct hash_algo hash_algo[] = {
-       /*
-        * CONFIG_SHA_HW_ACCEL is defined if hardware acceleration is
-        * available.
-        */
-#ifdef CONFIG_SHA_HW_ACCEL
+#ifdef CONFIG_SHA1
        {
-               "sha1",
-               SHA1_SUM_LEN,
-               hw_sha1,
-               CHUNKSZ_SHA1,
-#ifdef CONFIG_SHA_PROG_HW_ACCEL
-               hw_sha_init,
-               hw_sha_update,
-               hw_sha_finish,
+               .name           = "sha1",
+               .digest_size    = SHA1_SUM_LEN,
+               .chunk_size     = CHUNKSZ_SHA1,
+#ifdef CONFIG_SHA_HW_ACCEL
+               .hash_func_ws   = hw_sha1,
+#else
+               .hash_func_ws   = sha1_csum_wd,
 #endif
-       }, {
-               "sha256",
-               SHA256_SUM_LEN,
-               hw_sha256,
-               CHUNKSZ_SHA256,
 #ifdef CONFIG_SHA_PROG_HW_ACCEL
-               hw_sha_init,
-               hw_sha_update,
-               hw_sha_finish,
+               .hash_init      = hw_sha_init,
+               .hash_update    = hw_sha_update,
+               .hash_finish    = hw_sha_finish,
+#else
+               .hash_init      = hash_init_sha1,
+               .hash_update    = hash_update_sha1,
+               .hash_finish    = hash_finish_sha1,
 #endif
        },
 #endif
-#ifdef CONFIG_SHA1
+#ifdef CONFIG_SHA256
        {
-               "sha1",
-               SHA1_SUM_LEN,
-               sha1_csum_wd,
-               CHUNKSZ_SHA1,
-               hash_init_sha1,
-               hash_update_sha1,
-               hash_finish_sha1,
+               .name           = "sha256",
+               .digest_size    = SHA256_SUM_LEN,
+               .chunk_size     = CHUNKSZ_SHA256,
+#ifdef CONFIG_SHA_HW_ACCEL
+               .hash_func_ws   = hw_sha256,
+#else
+               .hash_func_ws   = sha256_csum_wd,
+#endif
+#ifdef CONFIG_SHA_PROG_HW_ACCEL
+               .hash_init      = hw_sha_init,
+               .hash_update    = hw_sha_update,
+               .hash_finish    = hw_sha_finish,
+#else
+               .hash_init      = hash_init_sha256,
+               .hash_update    = hash_update_sha256,
+               .hash_finish    = hash_finish_sha256,
+#endif
        },
 #endif
-#ifdef CONFIG_SHA256
        {
-               "sha256",
-               SHA256_SUM_LEN,
-               sha256_csum_wd,
-               CHUNKSZ_SHA256,
-               hash_init_sha256,
-               hash_update_sha256,
-               hash_finish_sha256,
+               .name           = "crc16-ccitt",
+               .digest_size    = 2,
+               .chunk_size     = CHUNKSZ,
+               .hash_func_ws   = crc16_ccitt_wd_buf,
+               .hash_init      = hash_init_crc16_ccitt,
+               .hash_update    = hash_update_crc16_ccitt,
+               .hash_finish    = hash_finish_crc16_ccitt,
        },
-#endif
        {
-               "crc32",
-               4,
-               crc32_wd_buf,
-               CHUNKSZ_CRC32,
-               hash_init_crc32,
-               hash_update_crc32,
-               hash_finish_crc32,
+               .name           = "crc32",
+               .digest_size    = 4,
+               .chunk_size     = CHUNKSZ_CRC32,
+               .hash_func_ws   = crc32_wd_buf,
+               .hash_init      = hash_init_crc32,
+               .hash_update    = hash_update_crc32,
+               .hash_finish    = hash_finish_crc32,
        },
 };
 
-#if defined(CONFIG_SHA256) || defined(CONFIG_CMD_SHA1SUM)
-#define MULTI_HASH
-#endif
-
-#if defined(CONFIG_HASH_VERIFY) || defined(CONFIG_CMD_HASH)
-#define MULTI_HASH
-#endif
-
 /* Try to minimize code size for boards that don't want much hashing */
-#ifdef MULTI_HASH
+#if defined(CONFIG_SHA256) || defined(CONFIG_CMD_SHA1SUM) || \
+       defined(CONFIG_CRC32_VERIFY) || defined(CONFIG_CMD_HASH)
 #define multi_hash()   1
 #else
 #define multi_hash()   0
 #endif
 
+static void reloc_update(void)
+{
+#if !defined(USE_HOSTCC) && defined(CONFIG_NEEDS_MANUAL_RELOC)
+       int i;
+       static bool done;
+
+       if (!done) {
+               done = true;
+               for (i = 0; i < ARRAY_SIZE(hash_algo); i++) {
+                       hash_algo[i].name += gd->reloc_off;
+                       hash_algo[i].hash_func_ws += gd->reloc_off;
+                       hash_algo[i].hash_init += gd->reloc_off;
+                       hash_algo[i].hash_update += gd->reloc_off;
+                       hash_algo[i].hash_finish += gd->reloc_off;
+               }
+       }
+#endif
+}
+
 int hash_lookup_algo(const char *algo_name, struct hash_algo **algop)
 {
        int i;
 
+       reloc_update();
+
        for (i = 0; i < ARRAY_SIZE(hash_algo); i++) {
                if (!strcmp(algo_name, hash_algo[i].name)) {
                        *algop = &hash_algo[i];
@@ -212,6 +262,8 @@ int hash_progressive_lookup_algo(const char *algo_name,
 {
        int i;
 
+       reloc_update();
+
        for (i = 0; i < ARRAY_SIZE(hash_algo); i++) {
                if (!strcmp(algo_name, hash_algo[i].name)) {
                        if (hash_algo[i].hash_init) {
@@ -226,6 +278,49 @@ int hash_progressive_lookup_algo(const char *algo_name,
 }
 
 #ifndef USE_HOSTCC
+int hash_parse_string(const char *algo_name, const char *str, uint8_t *result)
+{
+       struct hash_algo *algo;
+       int ret;
+       int i;
+
+       ret = hash_lookup_algo(algo_name, &algo);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < algo->digest_size; i++) {
+               char chr[3];
+
+               strncpy(chr, &str[i * 2], 2);
+               result[i] = simple_strtoul(chr, NULL, 16);
+       }
+
+       return 0;
+}
+
+int hash_block(const char *algo_name, const void *data, unsigned int len,
+              uint8_t *output, int *output_size)
+{
+       struct hash_algo *algo;
+       int ret;
+
+       ret = hash_lookup_algo(algo_name, &algo);
+       if (ret)
+               return ret;
+
+       if (output_size && *output_size < algo->digest_size) {
+               debug("Output buffer size %d too small (need %d bytes)",
+                     *output_size, algo->digest_size);
+               return -ENOSPC;
+       }
+       if (output_size)
+               *output_size = algo->digest_size;
+       algo->hash_func_ws(data, len, output, algo->chunk_size);
+
+       return 0;
+}
+
+#if defined(CONFIG_CMD_HASH) || defined(CONFIG_CMD_SHA1SUM) || defined(CONFIG_CMD_CRC32)
 /**
  * store_result: Store the resulting sum to an address or variable
  *
@@ -265,7 +360,7 @@ static void store_result(struct hash_algo *algo, const uint8_t *sum,
                        str_ptr += 2;
                }
                *str_ptr = '\0';
-               setenv(dest, str_output);
+               env_set(dest, str_output);
        } else {
                ulong addr;
                void *buf;
@@ -314,7 +409,6 @@ static int parse_verify_sum(struct hash_algo *algo, char *verify_str,
                buf = map_sysmem(addr, algo->digest_size);
                memcpy(vsum, buf, algo->digest_size);
        } else {
-               unsigned int i;
                char *vsum_str;
                int digits = algo->digest_size * 2;
 
@@ -326,7 +420,7 @@ static int parse_verify_sum(struct hash_algo *algo, char *verify_str,
                if (strlen(verify_str) == digits)
                        vsum_str = verify_str;
                else {
-                       vsum_str = getenv(verify_str);
+                       vsum_str = env_get(verify_str);
                        if (vsum_str == NULL || strlen(vsum_str) != digits) {
                                printf("Expected %d hex digits in env var\n",
                                       digits);
@@ -334,19 +428,12 @@ static int parse_verify_sum(struct hash_algo *algo, char *verify_str,
                        }
                }
 
-               for (i = 0; i < algo->digest_size; i++) {
-                       char *nullp = vsum_str + (i + 1) * 2;
-                       char end = *nullp;
-
-                       *nullp = '\0';
-                       vsum[i] = simple_strtoul(vsum_str + (i * 2), NULL, 16);
-                       *nullp = end;
-               }
+               hash_parse_string(algo->name, vsum_str, vsum);
        }
        return 0;
 }
 
-void hash_show(struct hash_algo *algo, ulong addr, ulong len, uint8_t *output)
+static void hash_show(struct hash_algo *algo, ulong addr, ulong len, uint8_t *output)
 {
        int i;
 
@@ -355,28 +442,6 @@ void hash_show(struct hash_algo *algo, ulong addr, ulong len, uint8_t *output)
                printf("%02x", output[i]);
 }
 
-int hash_block(const char *algo_name, const void *data, unsigned int len,
-              uint8_t *output, int *output_size)
-{
-       struct hash_algo *algo;
-       int ret;
-
-       ret = hash_lookup_algo(algo_name, &algo);
-       if (ret)
-               return ret;
-
-       if (output_size && *output_size < algo->digest_size) {
-               debug("Output buffer size %d too small (need %d bytes)",
-                     *output_size, algo->digest_size);
-               return -ENOSPC;
-       }
-       if (output_size)
-               *output_size = algo->digest_size;
-       algo->hash_func_ws(data, len, output, algo->chunk_size);
-
-       return 0;
-}
-
 int hash_command(const char *algo_name, int flags, cmd_tbl_t *cmdtp, int flag,
                 int argc, char * const argv[])
 {
@@ -390,7 +455,7 @@ int hash_command(const char *algo_name, int flags, cmd_tbl_t *cmdtp, int flag,
 
        if (multi_hash()) {
                struct hash_algo *algo;
-               uint8_t output[HASH_MAX_DIGEST_SIZE];
+               u8 *output;
                uint8_t vsum[HASH_MAX_DIGEST_SIZE];
                void *buf;
 
@@ -405,12 +470,16 @@ int hash_command(const char *algo_name, int flags, cmd_tbl_t *cmdtp, int flag,
                        return 1;
                }
 
+               output = memalign(ARCH_DMA_MINALIGN,
+                                 sizeof(uint32_t) * HASH_MAX_DIGEST_SIZE);
+
                buf = map_sysmem(addr, len);
                algo->hash_func_ws(buf, len, output, algo->chunk_size);
                unmap_sysmem(buf);
 
                /* Try to avoid code bloat when verify is not needed */
-#ifdef CONFIG_HASH_VERIFY
+#if defined(CONFIG_CRC32_VERIFY) || defined(CONFIG_SHA1SUM_VERIFY) || \
+       defined(CONFIG_HASH_VERIFY)
                if (flags & HASH_FLAG_VERIFY) {
 #else
                if (0) {
@@ -439,6 +508,8 @@ int hash_command(const char *algo_name, int flags, cmd_tbl_t *cmdtp, int flag,
                                store_result(algo, output, *argv,
                                        flags & HASH_FLAG_ENV);
                        }
+               unmap_sysmem(output);
+
                }
 
        /* Horrible code size hack for boards that just want crc32 */
@@ -459,4 +530,5 @@ int hash_command(const char *algo_name, int flags, cmd_tbl_t *cmdtp, int flag,
 
        return 0;
 }
-#endif
+#endif /* CONFIG_CMD_HASH || CONFIG_CMD_SHA1SUM || CONFIG_CMD_CRC32) */
+#endif /* !USE_HOSTCC */