diff options
author | Scott Anderson <saa@android.com> | 2012-02-06 13:39:56 -0800 |
---|---|---|
committer | Mike J. Chen <mjchen@google.com> | 2012-03-03 17:29:36 -0800 |
commit | 39782495f8485c4f131feaf7dfa15c8b8cce1c69 (patch) | |
tree | aa8366011cc84756dc948f0694b7e0f672d968a5 | |
parent | 4f620ec0985b4191c4f261377b3600c981c0acd0 (diff) | |
download | uboot-39782495f8485c4f131feaf7dfa15c8b8cce1c69.tar.gz |
PARTITION/BLOCK COMMAND: Add an md5 subcommand to blk command
To allow verification of the data written to block devices, it is
useful to be able to calculate the MD5 hash of a number of
sectors on a block device. To use this command, CONFIG_MD5 will
need to be defined in addition to CONFIG_CMD_BLK.
Change-Id: Ifae715179fd0be37be324306641418b545763bcc
Signed-off-by: Scott Anderson <saa@android.com>
-rw-r--r-- | common/cmd_blk.c | 54 | ||||
-rw-r--r-- | disk/part.c | 110 | ||||
-rw-r--r-- | include/part.h | 19 |
3 files changed, 174 insertions, 9 deletions
diff --git a/common/cmd_blk.c b/common/cmd_blk.c index 9160eaa67..9090f4675 100644 --- a/common/cmd_blk.c +++ b/common/cmd_blk.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Google, Inc. + * Copyright (C) 2011-2012 Google, Inc. * * Derived from cmd_sata.c, which is: * Copyright (C) 2000-2005, DENX Software Engineering @@ -50,7 +50,7 @@ int do_blk(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) disk_partition_t ptn; ulong addr; lbaint_t blk, cnt, blks_done; - int err, is_erase = 0, is_read = 0, is_write = 0; + int err, is_erase = 0, is_md5 = 0, is_read = 0, is_write = 0; /* * All of our commands are of the form "blk <action>" followed by * parameters. For convenience, convert argc and argv into @@ -126,6 +126,10 @@ int do_blk(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) } if (!strcmp(action, "erase")) is_erase = 1; +#ifdef CONFIG_MD5 + else if (!strcmp(action, "md5")) + is_md5 = 1; +#endif /* CONFIG_MD5 */ else if (!strcmp(action, "read")) is_read = 1; else if (!strcmp(action, "write")) @@ -143,11 +147,11 @@ int do_blk(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) return 1; } - if (is_erase) { + if (is_erase || is_md5) { /* Need blk#/partition and optional count. */ if (num_parm < 1 || num_parm > 2) { - puts("usage: blk erase blk# cnt\n"); - puts(" or: blk erase partition [cnt]\n"); + printf("usage: blk %s blk# cnt\n", action); + printf(" or: blk %s partition [cnt]\n", action); return 1; } } else { @@ -176,10 +180,25 @@ int do_blk(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) printf("Block %s: device %s block # 0x%lX, count 0x%lX ...\n", action, blk_curr_name, blk, cnt); - if (is_erase) + if (is_erase) { blks_done = blk_curr_dev->block_erase(blk_curr_dev->dev, blk, cnt); - else if (is_read) { +#ifdef CONFIG_MD5 + } else if (is_md5) { + unsigned char md5[16]; + blks_done = cnt; + partition_md5_helper(blk_curr_dev, blk, &blks_done, + md5); + if (blks_done == cnt) + printf("MD5SUM=" + "%02x%02x%02x%02x%02x%02x%02x%02x" + "%02x%02x%02x%02x%02x%02x%02x%02x\n", + md5[0], md5[1], md5[2], md5[3], + md5[4], md5[5], md5[6], md5[7], + md5[8], md5[9], md5[10], md5[11], + md5[12], md5[13], md5[14], md5[15]); +#endif /* CONFIG_MD5 */ + } else if (is_read) { blks_done = blk_curr_dev->block_read(blk_curr_dev->dev, blk, cnt, (void *)addr); /* flush cache after read */ @@ -209,9 +228,22 @@ int do_blk(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) printf("Block %s: device %s block # 0x%lX, count 0x%lX ...\n", action, blk_curr_name, ptn.start, cnt); - if (is_erase) + if (is_erase) { err = partition_erase_blks(blk_curr_dev, &ptn, &cnt); - else if (is_read) { +#ifdef CONFIG_MD5 + } else if (is_md5) { + unsigned char md5[16]; + err = partition_md5_blks(blk_curr_dev, &ptn, &cnt, md5); + if (!err) + printf("MD5SUM=" + "%02x%02x%02x%02x%02x%02x%02x%02x" + "%02x%02x%02x%02x%02x%02x%02x%02x\n", + md5[0], md5[1], md5[2], md5[3], + md5[4], md5[5], md5[6], md5[7], + md5[8], md5[9], md5[10], md5[11], + md5[12], md5[13], md5[14], md5[15]); +#endif /* CONFIG_MD5 */ + } else if (is_read) { err = partition_read_blks(blk_curr_dev, &ptn, &cnt, (void *)addr); /* flush cache after read */ @@ -235,6 +267,10 @@ U_BOOT_CMD( "blk partition [dev] - print partition table\n" "blk erase blk# cnt\n" "blk erase partition [cnt]\n" +#ifdef CONFIG_MD5 + "blk md5 blk# cnt\n" + "blk md5 partition [cnt]\n" +#endif /* CONFIG_MD5 */ "blk read addr blk# cnt\n" "blk read addr partition [cnt]\n" "blk write addr blk# cnt\n" diff --git a/disk/part.c b/disk/part.c index 918a81f9d..b905f7f00 100644 --- a/disk/part.c +++ b/disk/part.c @@ -1,6 +1,7 @@ /* * (C) Copyright 2001 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * Copyright (C) 2011-2012 Google, Inc. * * See file CREDITS for list of people who contributed to this * project. @@ -26,6 +27,10 @@ #include <errno.h> #include <ide.h> #include <part.h> +#ifdef CONFIG_MD5 +#include <malloc.h> +#include <u-boot/md5.h> +#endif #undef PART_DEBUG @@ -313,6 +318,99 @@ int partition_erase_bytes(block_dev_desc_t *dev, disk_partition_t *ptn, return _partition_erase(dev, ptn, bytecnt, NULL); } +#ifdef CONFIG_MD5 +void partition_md5_helper(block_dev_desc_t *dev, lbaint_t blk_start, + lbaint_t *blkcnt, unsigned char md5[16]) +{ + struct MD5Context context; + lbaint_t buf_blks, blks_left, blks_read; + unsigned char *buf; +#ifndef CONF_MD5_BUFLEN +#define CONF_MD5_BUFLEN (16*1024) +#endif + + buf_blks = CONF_MD5_BUFLEN / dev->blksz; + if (!buf_blks) { + *blkcnt = 0; + return; + } + buf = malloc(buf_blks * dev->blksz); + if (!buf) { + *blkcnt = 0; + return; + } + + MD5Init(&context); + blks_left = *blkcnt; + while (blks_left) { + if (blks_left < buf_blks) + buf_blks = blks_left; + + blks_read = dev->block_read(dev->dev, blk_start, buf_blks, + buf); + MD5Update(&context, buf, blks_read * dev->blksz); + blk_start += blks_read; + blks_left -= blks_read; + if (blks_read != buf_blks) + break; + } + MD5Final(md5, &context); + + free(buf); + *blkcnt -= blks_left; +} +static int _partition_md5(block_dev_desc_t *dev, disk_partition_t *ptn, + loff_t *bytecnt_p, lbaint_t *blkcnt_p, + unsigned char md5[16]) +{ + /* + * Fetch the number of bytes or blocks and then zero them right away + * to make the error handling easier. + */ + loff_t bytes_to_do = get_and_zero_loff_t(bytecnt_p); + lbaint_t blks_to_do = get_and_zero_lbaint_t(blkcnt_p), blks_done; + int err = _partition_validate(dev, ptn, bytecnt_p, blkcnt_p, + (void *)-1/*fake*/); + if (err) + return err; + + err = partition_read_pre(ptn); + if (err) + return err; + + if (bytes_to_do) { + blks_to_do = DIV_ROUND_UP(bytes_to_do, dev->blksz); + if (blks_to_do > ptn->size) + return -EFBIG; + } else if (!blks_to_do) + blks_to_do = ptn->size; + + blks_done = blks_to_do; + partition_md5_helper(dev, ptn->start, &blks_done, md5); + + if (blkcnt_p) + *blkcnt_p = blks_done; + if (bytecnt_p) + *bytecnt_p = (loff_t)blks_done * dev->blksz; + + err = partition_read_post(ptn); + + if (blks_done != blks_to_do) + return -EIO; + return err; +} +int partition_md5_blks(block_dev_desc_t *dev, disk_partition_t *ptn, + lbaint_t *blkcnt, unsigned char md5[16]) +{ + return _partition_md5(dev, ptn, NULL, blkcnt, md5); +} +int partition_md5_bytes(block_dev_desc_t *dev, disk_partition_t *ptn, + loff_t *bytecnt, unsigned char md5[16]) +{ + return _partition_md5(dev, ptn, bytecnt, NULL, md5); +} +#endif /* CONFIG_MD5 */ + static int _partition_read(block_dev_desc_t *dev, disk_partition_t *ptn, loff_t *bytecnt_p, lbaint_t *blkcnt_p, void *buffer) @@ -469,6 +567,18 @@ int partition_erase_bytes(block_dev_desc_t *dev, disk_partition_t *partition, { return -ENODEV; } +#ifdef CONFIG_MD5 +int partition_md5_blks(block_dev_desc_t *dev, disk_partition_t *ptn, + lbaint_t *blkcnt) +{ + return -ENODEV; +} +int partition_md5_bytes(block_dev_desc_t *dev, disk_partition_t *partition, + loff_t *bytecnt) +{ + return -ENODEV; +} +#endif /* CONFIG_MD5 */ int partition_read_blks(block_dev_desc_t *dev, disk_partition_t *ptn, lbaint_t *blkcnt, void *buffer) { diff --git a/include/part.h b/include/part.h index c0af7fdb3..b37d5e4ee 100644 --- a/include/part.h +++ b/include/part.h @@ -128,6 +128,14 @@ int partition_erase_blks(block_dev_desc_t *dev, disk_partition_t *partition, lbaint_t *blkcnt); int partition_erase_bytes(block_dev_desc_t *dev, disk_partition_t *partition, loff_t *bytecnt); +#ifdef CONFIG_MD5 +void partition_md5_helper(block_dev_desc_t *dev, lbaint_t blk_start, + lbaint_t *blkcnt, unsigned char md5[16]); +int partition_md5_blks(block_dev_desc_t *dev, disk_partition_t *partition, + lbaint_t *blkcnt, unsigned char md5[16]); +int partition_md5_bytes(block_dev_desc_t *dev, disk_partition_t *partition, + loff_t *bytecnt, unsigned char md5[16]); +#endif /* CONFIG_MD5 */ int partition_read_blks(block_dev_desc_t *dev, disk_partition_t *partition, lbaint_t *blkcnt, void *buffer); int partition_read_bytes(block_dev_desc_t *dev, disk_partition_t *partition, @@ -180,6 +188,17 @@ static inline int partition_erase_blks(block_dev_desc_t *dev, static inline int partition_erase_bytes(block_dev_desc_t *dev, disk_partition_t *partition, loff_t *bytecnt) { return -ENODEV; } +#ifdef CONFIG_MD5 +static inline void partition_md5_helper(block_dev_desc_t *dev, + lbaint_t blk_start, lbaint_t *blkcnt, + unsigned char md5[16]) { *blkcnt = 0; } +static inline int partition_md5_blks(block_dev_desc_t *dev, + disk_partition_t *partition, lbaint_t *blkcnt, + unsigned char md5[16]) { return -ENODEV; } +static inline int partition_md5_bytes(block_dev_desc_t *dev, + disk_partition_t *partition, loff_t *bytecnt, + unsigned char md5[16]) { return -ENODEV; } +#endif /* CONFIG_MD5 */ static inline int partition_read_blks(block_dev_desc_t *dev, disk_partition_t *partition, lbaint_t *blkcnt, void *buffer) { return -ENODEV; } |