summaryrefslogtreecommitdiff
path: root/common/hash.c
diff options
context:
space:
mode:
authorTom Rini <trini@ti.com>2013-03-04 11:14:27 -0500
committerTom Rini <trini@ti.com>2013-03-04 11:14:27 -0500
commit1c9f47ab2a2e9b62d08d39bfb9c4adc8f8edc5da (patch)
treefa4ee32d67f02d1c8fa80a55b9d85982cedac062 /common/hash.c
parentc259188b203d95e4a854e7e29b9e4472cc982f65 (diff)
parent218da0f35f4b5e5bf13d3dba6d975d4d5d65516f (diff)
downloadu-boot-imx-1c9f47ab2a2e9b62d08d39bfb9c4adc8f8edc5da.zip
u-boot-imx-1c9f47ab2a2e9b62d08d39bfb9c4adc8f8edc5da.tar.gz
u-boot-imx-1c9f47ab2a2e9b62d08d39bfb9c4adc8f8edc5da.tar.bz2
Merge branch 'mem' of git://git.denx.de/u-boot-x86
Diffstat (limited to 'common/hash.c')
-rw-r--r--common/hash.c194
1 files changed, 140 insertions, 54 deletions
diff --git a/common/hash.c b/common/hash.c
index e3a6e43..f5badcb 100644
--- a/common/hash.c
+++ b/common/hash.c
@@ -28,49 +28,87 @@
#include <hash.h>
#include <sha1.h>
#include <sha256.h>
+#include <asm/io.h>
/*
* These are the hash algorithms we support. Chips which support accelerated
- * crypto could perhaps add named version of these algorithms here.
+ * crypto could perhaps add named version of these algorithms here. Note that
+ * algorithm names must be in lower case.
*/
static struct hash_algo hash_algo[] = {
-#ifdef CONFIG_SHA1
+ /*
+ * This is CONFIG_CMD_SHA1SUM instead of CONFIG_SHA1 since otherwise
+ * it bloats the code for boards which use SHA1 but not the 'hash'
+ * or 'sha1sum' commands.
+ */
+#ifdef CONFIG_CMD_SHA1SUM
{
- "SHA1",
+ "sha1",
SHA1_SUM_LEN,
sha1_csum_wd,
CHUNKSZ_SHA1,
},
+#define MULTI_HASH
#endif
#ifdef CONFIG_SHA256
{
- "SHA256",
+ "sha256",
SHA256_SUM_LEN,
sha256_csum_wd,
CHUNKSZ_SHA256,
},
+#define MULTI_HASH
#endif
+ {
+ "crc32",
+ 4,
+ crc32_wd_buf,
+ CHUNKSZ_CRC32,
+ },
};
+#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
+#define multi_hash() 1
+#else
+#define multi_hash() 0
+#endif
+
/**
* store_result: Store the resulting sum to an address or variable
*
* @algo: Hash algorithm being used
* @sum: Hash digest (algo->digest_size bytes)
* @dest: Destination, interpreted as a hex address if it starts
- * with * or otherwise as an environment variable.
+ * with * (or allow_env_vars is 0) or otherwise as an
+ * environment variable.
+ * @allow_env_vars: non-zero to permit storing the result to an
+ * variable environment
*/
static void store_result(struct hash_algo *algo, const u8 *sum,
- const char *dest)
+ const char *dest, int allow_env_vars)
{
unsigned int i;
+ int env_var = 0;
- if (*dest == '*') {
- u8 *ptr;
+ /*
+ * If environment variables are allowed, then we assume that 'dest'
+ * is an environment variable, unless it starts with *, in which
+ * case we assume it is an address. If not allowed, it is always an
+ * address. This is to support the crc32 command.
+ */
+ if (allow_env_vars) {
+ if (*dest == '*')
+ dest++;
+ else
+ env_var = 1;
+ }
- ptr = (u8 *)simple_strtoul(dest + 1, NULL, 16);
- memcpy(ptr, sum, algo->digest_size);
- } else {
+ if (env_var) {
char str_output[HASH_MAX_DIGEST_SIZE * 2 + 1];
char *str_ptr = str_output;
@@ -80,6 +118,14 @@ static void store_result(struct hash_algo *algo, const u8 *sum,
}
str_ptr = '\0';
setenv(dest, str_output);
+ } else {
+ ulong addr;
+ void *buf;
+
+ addr = simple_strtoul(dest, NULL, 16);
+ buf = map_sysmem(addr, algo->digest_size);
+ memcpy(buf, sum, algo->digest_size);
+ unmap_sysmem(buf);
}
}
@@ -94,15 +140,31 @@ static void store_result(struct hash_algo *algo, const u8 *sum,
* Otherwise we assume it is an environment variable, and
* look up its value (it must contain a hex digest).
* @vsum: Returns binary digest value (algo->digest_size bytes)
+ * @allow_env_vars: non-zero to permit storing the result to an environment
+ * variable. If 0 then verify_str is assumed to be an
+ * address, and the * prefix is not expected.
* @return 0 if ok, non-zero on error
*/
-static int parse_verify_sum(struct hash_algo *algo, char *verify_str, u8 *vsum)
+static int parse_verify_sum(struct hash_algo *algo, char *verify_str, u8 *vsum,
+ int allow_env_vars)
{
- if (*verify_str == '*') {
- u8 *ptr;
+ int env_var = 0;
+
+ /* See comment above in store_result() */
+ if (allow_env_vars) {
+ if (*verify_str == '*')
+ verify_str++;
+ else
+ env_var = 1;
+ }
- ptr = (u8 *)simple_strtoul(verify_str + 1, NULL, 16);
- memcpy(vsum, ptr, algo->digest_size);
+ if (env_var) {
+ ulong addr;
+ void *buf;
+
+ addr = simple_strtoul(verify_str, NULL, 16);
+ buf = map_sysmem(addr, algo->digest_size);
+ memcpy(vsum, buf, algo->digest_size);
} else {
unsigned int i;
char *vsum_str;
@@ -141,7 +203,7 @@ static struct hash_algo *find_hash_algo(const char *name)
int i;
for (i = 0; i < ARRAY_SIZE(hash_algo); i++) {
- if (!strcasecmp(name, hash_algo[i].name))
+ if (!strcmp(name, hash_algo[i].name))
return &hash_algo[i];
}
@@ -158,63 +220,87 @@ static void show_hash(struct hash_algo *algo, ulong addr, ulong len,
printf("%02x", output[i]);
}
-int hash_command(const char *algo_name, int verify, cmd_tbl_t *cmdtp, int flag,
+int hash_command(const char *algo_name, int flags, cmd_tbl_t *cmdtp, int flag,
int argc, char * const argv[])
{
- struct hash_algo *algo;
ulong addr, len;
- u8 output[HASH_MAX_DIGEST_SIZE];
- u8 vsum[HASH_MAX_DIGEST_SIZE];
if (argc < 2)
return CMD_RET_USAGE;
- algo = find_hash_algo(algo_name);
- if (!algo) {
- printf("Unknown hash algorithm '%s'\n", algo_name);
- return CMD_RET_USAGE;
- }
addr = simple_strtoul(*argv++, NULL, 16);
len = simple_strtoul(*argv++, NULL, 16);
- argc -= 2;
- if (algo->digest_size > HASH_MAX_DIGEST_SIZE) {
- puts("HASH_MAX_DIGEST_SIZE exceeded\n");
- return 1;
- }
+ if (multi_hash()) {
+ struct hash_algo *algo;
+ u8 output[HASH_MAX_DIGEST_SIZE];
+ u8 vsum[HASH_MAX_DIGEST_SIZE];
+ void *buf;
- algo->hash_func_ws((const unsigned char *)addr, len, output,
- algo->chunk_size);
+ algo = find_hash_algo(algo_name);
+ if (!algo) {
+ printf("Unknown hash algorithm '%s'\n", algo_name);
+ return CMD_RET_USAGE;
+ }
+ argc -= 2;
- /* Try to avoid code bloat when verify is not needed */
+ if (algo->digest_size > HASH_MAX_DIGEST_SIZE) {
+ puts("HASH_MAX_DIGEST_SIZE exceeded\n");
+ return 1;
+ }
+
+ 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 (verify) {
+ if (flags & HASH_FLAG_VERIFY) {
#else
- if (0) {
+ if (0) {
#endif
- if (!argc)
- return CMD_RET_USAGE;
- if (parse_verify_sum(algo, *argv, vsum)) {
- printf("ERROR: %s does not contain a valid %s sum\n",
- *argv, algo->name);
- return 1;
- }
- if (memcmp(output, vsum, algo->digest_size) != 0) {
- int i;
+ if (!argc)
+ return CMD_RET_USAGE;
+ if (parse_verify_sum(algo, *argv, vsum,
+ flags & HASH_FLAG_ENV)) {
+ printf("ERROR: %s does not contain a valid "
+ "%s sum\n", *argv, algo->name);
+ return 1;
+ }
+ if (memcmp(output, vsum, algo->digest_size) != 0) {
+ int i;
+ show_hash(algo, addr, len, output);
+ printf(" != ");
+ for (i = 0; i < algo->digest_size; i++)
+ printf("%02x", vsum[i]);
+ puts(" ** ERROR **\n");
+ return 1;
+ }
+ } else {
show_hash(algo, addr, len, output);
- printf(" != ");
- for (i = 0; i < algo->digest_size; i++)
- printf("%02x", vsum[i]);
- puts(" ** ERROR **\n");
- return 1;
+ printf("\n");
+
+ if (argc) {
+ store_result(algo, output, *argv,
+ flags & HASH_FLAG_ENV);
+ }
}
+
+ /* Horrible code size hack for boards that just want crc32 */
} else {
- show_hash(algo, addr, len, output);
- printf("\n");
+ ulong crc;
+ ulong *ptr;
+
+ crc = crc32_wd(0, (const uchar *)addr, len, CHUNKSZ_CRC32);
- if (argc)
- store_result(algo, output, *argv);
+ printf("CRC32 for %08lx ... %08lx ==> %08lx\n",
+ addr, addr + len - 1, crc);
+
+ if (argc > 3) {
+ ptr = (ulong *)simple_strtoul(argv[3], NULL, 16);
+ *ptr = crc;
+ }
}
return 0;