From patchwork Thu Jul 2 04:01:21 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Chau X-Patchwork-Id: 1321315 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20161025 header.b=vOjAk4uU; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 49yFzj3rQ9z9sPF for ; Thu, 2 Jul 2020 21:21:53 +1000 (AEST) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 799268227F; Thu, 2 Jul 2020 13:14:39 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="vOjAk4uU"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id A2C4681B48; Thu, 2 Jul 2020 06:01:30 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,SPF_HELO_NONE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-pl1-x641.google.com (mail-pl1-x641.google.com [IPv6:2607:f8b0:4864:20::641]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 5B45A8006D for ; Thu, 2 Jul 2020 06:01:27 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=johnchau.2nd@gmail.com Received: by mail-pl1-x641.google.com with SMTP id x8so9862331plm.10 for ; Wed, 01 Jul 2020 21:01:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=niMCsIvWHXKEcElCvqgWRv5IfJnXGmaow0C+6u6tOyY=; b=vOjAk4uUNRdLNxQA9ZBcloSbuFZkP8dr7txoVxGDHatdVDeB1wAPZJaM9zVwU7K2cu y8RbKDlsaTwpFzREz73ix6LUIaifxSe0WKW3q3oZnUZ+fLJqK3mUR8r2svAGvPZ0scwl bGhZUJykbnxFwdZih1ENQCjjyQzxTgx5pDYcPo0ZXty6BcLTHU3jxOhy+VJ5UqSoBIEU 0vE8rO+xx7nJMIOCfvbKamOJnJC/xsgAOJ/FRJYZlLawzY8ki7iAs5iO6k0gWL9bf0hw hNCcLzmqrDO6X6mPanKGOkGZ74XKyeN1BlQzh6AClzTwbjCDNsM6IY4iEih3SzC0T0x7 vLRw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=niMCsIvWHXKEcElCvqgWRv5IfJnXGmaow0C+6u6tOyY=; b=r0uxCCUqteVh6Vz7JPqqjaOtdA2UAJmtRngqOvRZ2LirlvqE1iDsdPadadn1RCcZ9F v9i8SjWvvE9DRdpSOBCugZlvf8LjgGOadofgFq0h1lxU1KPBG8cZ4iN/Ab8MAK+3PCiX iVpvbO11qSE6SWIE5PBywZEj4RNnaCmoLSal5PIOSTZV+byzoQ2zZpL2PGwlXQg0BuLB hRJNTRnbzNG2FiyqjIml/btypi6ZdGuUCRv1RnE66sYBXI2WlIyxLuIBdVyWlBQuxPT8 8WfyvstwIqCBXsUVzChJ5dBlhWDW4FAf+kHaKfl/+tpg6b8CmQ4ZxtjY+sFi3vFgTuQr wimQ== X-Gm-Message-State: AOAM5301v+EtmahWFiwpgE3VjsmCBevQ5Hld1OUgScGr/jpflpI0r+pG cqN/nWYHdYrNn2XUtEcXeJ4Oo/F1 X-Google-Smtp-Source: ABdhPJyhLGogBe5X0MVXZnsu2LFdzmK1/h1oG/decsHXiOlSra2ALDu5YXZJ8ymGk+XCqc5IW/mxDg== X-Received: by 2002:a17:90a:aa83:: with SMTP id l3mr30553553pjq.73.1593662485570; Wed, 01 Jul 2020 21:01:25 -0700 (PDT) Received: from john-ubuntu.harmon.hk ([221.125.141.155]) by smtp.gmail.com with ESMTPSA id h6sm7416373pfg.25.2020.07.01.21.01.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 01 Jul 2020 21:01:25 -0700 (PDT) From: John Chau To: u-boot@lists.denx.de Cc: Tom Rini , John Chau Subject: [PATCH v3] cmd: add clone command Date: Thu, 2 Jul 2020 12:01:21 +0800 Message-Id: <20200702040121.7980-1-johnchau.2nd@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200629155441.GU8432@bill-the-cat> References: <20200629155441.GU8432@bill-the-cat> MIME-Version: 1.0 X-Mailman-Approved-At: Thu, 02 Jul 2020 13:12:53 +0200 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.102.3 at phobos.denx.de X-Virus-Status: Clean From: John Chau 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 --- Changes for v2: - Coding styles cleanup - removed useless "select CLONE" line from cmd/Kconfig - added buffer size check against block size of both devices - enabled this by default on sandbox in arch/Kconfig Changes for v3: - fixed buffer size check (condition inverted) arch/Kconfig | 1 + cmd/Kconfig | 8 ++++ cmd/Makefile | 1 + cmd/clone.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 135 insertions(+) create mode 100644 cmd/clone.c diff --git a/arch/Kconfig b/arch/Kconfig index ae9c93ed7b..4d7415d426 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -136,6 +136,7 @@ config SANDBOX imply ACPI_PMC imply ACPI_PMC_SANDBOX imply CMD_PMC + imply CMD_CLONE config SH bool "SuperH architecture" diff --git a/cmd/Kconfig b/cmd/Kconfig index 6403bc45a5..1e95de249f 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1067,6 +1067,14 @@ config CMD_MMC_SWRITE Enable support for the "mmc swrite" command to write Android sparse images to eMMC. +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 diff --git a/cmd/Makefile b/cmd/Makefile index f1dd513a4b..02663a1c73 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -95,6 +95,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 index 0000000000..9ece465537 --- /dev/null +++ b/cmd/clone.c @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2020 John Chau + * + */ + +#include +#include +#include +#include +#include + +#define BUFSIZE (1 * 1024 * 1024) +static int do_clone(cmd_tbl_t *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", + " \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)" +);