]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
cmd: add clone command
authorJohn Chau <john@harmon.hk>
Thu, 2 Jul 2020 04:01:21 +0000 (12:01 +0800)
committerTom Rini <trini@konsulko.com>
Wed, 5 Aug 2020 03:29:59 +0000 (23:29 -0400)
This patch adds a feature for block device cloning similar to dd
command, this should be useful for boot-strapping a device where
usb gadget or networking is not available. For instance one can
clone a factory image into a blank emmc from an external sd card.

Signed-off-by: John Chau <john@harmon.hk>
arch/Kconfig
cmd/Kconfig
cmd/Makefile
cmd/clone.c [new file with mode: 0644]

index 7f3cbe2ec88a974c5d8c2a9aac750742106af78e..2174336fa00c6368b2d171f8803396e08beaffd8 100644 (file)
@@ -139,6 +139,7 @@ config SANDBOX
        imply ACPI_PMC
        imply ACPI_PMC_SANDBOX
        imply CMD_PMC
+       imply CMD_CLONE
 
 config SH
        bool "SuperH architecture"
index d7136b0e7902eaa5c5976a56a1db502e129cbcd5..e11176451b149678bda51d8261c9617ada6d2f67 100644 (file)
@@ -1148,6 +1148,14 @@ config CMD_MMC_SWRITE
 
 endif
 
+config CMD_CLONE
+       bool "clone"
+       depends on BLK
+       help
+         Enable storage cloning over block devices, useful for
+         initial flashing by external block device without network
+         or usb support.
+
 config CMD_MTD
        bool "mtd"
        depends on MTD
index 6e0086ba07faa95bc6df5bbf981ec654f95ccbda..70750375d12865569aa45a9230e89f1f9a7b8422 100644 (file)
@@ -98,6 +98,7 @@ obj-$(CONFIG_CMD_MMC) += mmc.o
 obj-$(CONFIG_MP) += mp.o
 obj-$(CONFIG_CMD_MTD) += mtd.o
 obj-$(CONFIG_CMD_MTDPARTS) += mtdparts.o
+obj-$(CONFIG_CMD_CLONE) += clone.o
 ifneq ($(CONFIG_CMD_NAND)$(CONFIG_CMD_SF),)
 obj-y += legacy-mtd-utils.o
 endif
diff --git a/cmd/clone.c b/cmd/clone.c
new file mode 100644 (file)
index 0000000..97747f8
--- /dev/null
@@ -0,0 +1,126 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020 John Chau <john@harmon.hk>
+ *
+ */
+
+#include <common.h>
+#include <command.h>
+#include <malloc.h>
+#include <part.h>
+#include <blk.h>
+#include <vsprintf.h>
+
+#define BUFSIZE (1 * 1024 * 1024)
+static int do_clone(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
+{
+       int srcdev, destdev;
+       struct blk_desc *srcdesc, *destdesc;
+       int srcbz, destbz, ret;
+       char *unit, *buf;
+       unsigned long wrcnt, rdcnt, requested, srcblk, destblk;
+       unsigned long timer;
+       const unsigned long buffersize = 1024 * 1024;
+
+       if (argc < 6)
+               return CMD_RET_USAGE;
+
+       srcdev = blk_get_device_by_str(argv[1], argv[2], &srcdesc);
+       destdev = blk_get_device_by_str(argv[3], argv[4], &destdesc);
+       if (srcdev < 0) {
+               printf("Unable to open source device\n");
+               return 1;
+       } else if (destdev < 0) {
+               printf("Unable to open destination device\n");
+               return 1;
+       }
+       requested = simple_strtoul(argv[5], &unit, 10);
+       srcbz = srcdesc->blksz;
+       destbz = destdesc->blksz;
+
+       if ((srcbz * (buffersize / srcbz) != buffersize) &&
+           (destbz * (buffersize / destbz) != buffersize)) {
+               printf("failed: cannot match device block sizes\n");
+               return 1;
+       }
+       if (requested == 0) {
+               unsigned long a = srcdesc->lba * srcdesc->blksz;
+               unsigned long b = destdesc->lba * destdesc->blksz;
+
+               if (a > b)
+                       requested = a;
+               else
+                       requested = b;
+       } else {
+               switch (unit[0]) {
+               case 'g':
+               case 'G':
+                       requested *= 1024;
+               case 'm':
+               case 'M':
+                       requested *= 1024;
+               case 'k':
+               case 'K':
+                       requested *= 1024;
+                       break;
+               }
+       }
+       printf("Copying %ld bytes from %s:%s to %s:%s\n",
+              requested, argv[1], argv[2], argv[3], argv[4]);
+       wrcnt = 0;
+       rdcnt = 0;
+       buf = (char *)malloc(BUFSIZE);
+       srcblk = 0;
+       destblk = 0;
+       timer = get_timer(0);
+       while (wrcnt < requested) {
+               unsigned long toread = BUFSIZE / srcbz;
+               unsigned long towrite = BUFSIZE / destbz;
+               unsigned long offset = 0;
+
+read:
+               ret = blk_dread(srcdesc, srcblk, toread, buf + offset);
+               if (ret < 0) {
+                       printf("Src read error @blk %ld\n", srcblk);
+                       goto exit;
+               }
+               rdcnt += ret * srcbz;
+               srcblk += ret;
+               if (ret < toread) {
+                       toread -= ret;
+                       offset += ret * srcbz;
+                       goto read;
+               }
+               offset = 0;
+write:
+               ret = blk_dwrite(destdesc, destblk, towrite, buf + offset);
+               if (ret < 0) {
+                       printf("Dest write error @blk %ld\n", srcblk);
+                       goto exit;
+               }
+               wrcnt += ret * destbz;
+               destblk += ret;
+               if (ret < towrite) {
+                       towrite -= ret;
+                       offset += ret * destbz;
+                       goto write;
+               }
+       }
+
+exit:
+       timer = get_timer(timer);
+       timer = 1000 * timer / CONFIG_SYS_HZ;
+       printf("%ld read\n", rdcnt);
+       printf("%ld written\n", wrcnt);
+       printf("%ldms, %ldkB/s\n", timer, wrcnt / timer);
+       free(buf);
+
+       return 0;
+}
+
+U_BOOT_CMD(
+       clone, 6, 1, do_clone,
+       "simple storage cloning",
+       "<src interface> <src dev> <dest interface> <dest dev> <size[K/M/G]>\n"
+       "clone storage from 'src dev' on 'src interface' to 'dest dev' on 'dest interface' with maximum 'size' bytes (or 0 for clone to end)"
+);