aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Anderson <saa@android.com>2012-02-06 13:39:56 -0800
committerMike J. Chen <mjchen@google.com>2012-03-03 17:29:36 -0800
commit39782495f8485c4f131feaf7dfa15c8b8cce1c69 (patch)
treeaa8366011cc84756dc948f0694b7e0f672d968a5
parent4f620ec0985b4191c4f261377b3600c981c0acd0 (diff)
downloaduboot-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.c54
-rw-r--r--disk/part.c110
-rw-r--r--include/part.h19
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; }