From patchwork Fri Jul 22 17:43:16 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jassi Brar X-Patchwork-Id: 592479 Delivered-To: patch@linaro.org Received: by 2002:a05:7000:b811:0:0:0:0 with SMTP id fc17csp710778mab; Fri, 22 Jul 2022 10:44:18 -0700 (PDT) X-Google-Smtp-Source: AGRyM1srjNs/edRqw6z5knDseeVycsEHVdugDawEgENPTilFIRThqk7NHmy6dT1AQ9h/bFusHfg9 X-Received: by 2002:a02:6d1f:0:b0:33f:8d28:4d6d with SMTP id m31-20020a026d1f000000b0033f8d284d6dmr549172jac.16.1658511857908; Fri, 22 Jul 2022 10:44:17 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1658511857; cv=none; d=google.com; s=arc-20160816; b=UHVJ+S5puc+AJHE2EOIhjCwM4a1Sh1o01nsIG3JxgacjBMpe7hAbaRE6nZ8P+rGA9g Zu8AI0T/1SFNaUSleQAApSelM4fPSOCrs1FpZ1+ybhysFQHcuTyVYgqr2Rt0lhkm/F+i JLiQ5hRM+kM8uUn1C9a7yPnVH6CLOKGqv33d5er7ZhPIbtFlFSFxENDHIUD837oGAB6J jTiAe65UE6DFarZ6olIrrDcZG188q5QLn3Zu1WAikGBkoOjPQ7RGtS249MyrYx0Kh8es ksyr5PmLwCsKr492xucR0epW4j6kulShMxUGyGP0edB9RNGiLMRnk2I1c2gw8WWhyvgz HGVA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-transfer-encoding :mime-version:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=q6/wBxomtzb4iUaBLzhy3l36VqjsOzDIycNrjWp/Gu8=; b=0ZsjR1e1jivwikv/1o0LBO7/x11PH7NHwVbS7XgwNDZf0DmIHpMKIGs67Gjqkld9UU JhO/5l1ZdGJA0IfTWTQAYXMioTkTNP7l0KYcfS2yuNG6VZTNSonJtRRkfc2+O3fYd+nF F/p7KzFeiMPnwaXLaPqCJeZa3Bqreyzhg5LWcwSDuz004xaQQyB0qc/HGtE14Gx2c7H5 GYjpJr/2rogUqs9/BfL+BcfexCLnLdZ/uofxWdXpuxpmx6yBj4wXeDxSrdvRHBSvYyed Xbeonepb8HDYeycqcj+SNj2pi870RWC3brKXte7djRrKq3sxdfutqAU4OU12xow9nxOc bvhQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20210112 header.b="SlJ/ZoBZ"; spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 2a01:238:438b:c500:173d:9f52:ddab:ee01 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from phobos.denx.de (phobos.denx.de. [2a01:238:438b:c500:173d:9f52:ddab:ee01]) by mx.google.com with ESMTPS id m14-20020a026d0e000000b0033c74ff7630si4607704jac.97.2022.07.22.10.44.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 22 Jul 2022 10:44:17 -0700 (PDT) Received-SPF: pass (google.com: domain of u-boot-bounces@lists.denx.de designates 2a01:238:438b:c500:173d:9f52:ddab:ee01 as permitted sender) client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20210112 header.b="SlJ/ZoBZ"; spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 2a01:238:438b:c500:173d:9f52:ddab:ee01 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id D109B840B3; Fri, 22 Jul 2022 19:44:05 +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="SlJ/ZoBZ"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 9669383FB5; Fri, 22 Jul 2022 19:43:59 +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.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_FROM,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-io1-xd35.google.com (mail-io1-xd35.google.com [IPv6:2607:f8b0:4864:20::d35]) (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 EB4A883AC3 for ; Fri, 22 Jul 2022 19:43:55 +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=jassisinghbrar@gmail.com Received: by mail-io1-xd35.google.com with SMTP id n7so4155079ioo.7 for ; Fri, 22 Jul 2022 10:43:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=q6/wBxomtzb4iUaBLzhy3l36VqjsOzDIycNrjWp/Gu8=; b=SlJ/ZoBZpIfPS9y0KjloCIJWhpDvfeIlWiS+dxeAhM380Vzm3TkHAIxejYu5yikUGr ebHzntD6UmeGJ3ZmSEiBntGB6XZLoEaP65wtYYX71zEJo6JLX4jjppUorLt01UQ1Kcwm n1/nWRlXQ2sWFPxmCAKQZHIQoAKzQx9+upLQNuc5bPAYPdxtBkQG0zM5J7rZ+JfdUIvj y7PE9Uu56licw4soW6nhfSyrzPO35Stng2lYoEyVaRFAQhbOXSFMotiggYuwbkwfitOH Sj9qkB1DiMA6KXiJTYkBG58Q+Zc8KB4MUI2GhTHY2UsnHPVsbtb9QGH8Nwffe4sQhDyT kBSQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=q6/wBxomtzb4iUaBLzhy3l36VqjsOzDIycNrjWp/Gu8=; b=rf585QoDnC8Q5PQO9lgUfkE0ZwNh4ZZmMG1ffldU7O2SBsp0gEofo6iXVGrP5YasS3 KzvQbWIMrP44g7gG3+BqjoM3o9pZ89Awzly5RzNidCYubG/BVJbeHWzkN0aM2DtK+6MH V6/AnzQZAyg88IPzK+6U9lKu6X2MCEYRvYxizF6LBmL2oEgiN8iR7+OJKJ/77rg9OVd7 LKeroDU0YUslYCGE6DWw9BCZt2ckK6jTTDA2pttMXpmE2AKa8ML8fm/igI+R+VkDLUBK 30CXYVeVpQc5uzIH2ZpeBvvuNsSWg7kCzJqyh+7tN79XPAcg7ny8WGx9OU9czf/p2Mdf 6YSg== X-Gm-Message-State: AJIora9dQpHM0dVt5JA0RIQ89QuhRWINSvVRBFyoca3OnCWnfRyeKTHQ JvSR+wMUyeudHWYi1InVpPNaEBDOgaI= X-Received: by 2002:a05:6602:2c8f:b0:67c:31dc:ef6 with SMTP id i15-20020a0566022c8f00b0067c31dc0ef6mr317823iow.63.1658511834127; Fri, 22 Jul 2022 10:43:54 -0700 (PDT) Received: from localhost.localdomain (wnpgmb0311w-ds01-179-115.dynamic.bellmts.net. [206.45.179.115]) by smtp.gmail.com with ESMTPSA id s26-20020a02c51a000000b00339eedc7840sm2242348jam.94.2022.07.22.10.43.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 22 Jul 2022 10:43:53 -0700 (PDT) From: jassisinghbrar@gmail.com To: u-boot@lists.denx.de Cc: xypron.glpk@gmx.de, ilias.apalodimas@linaro.org, takahiro.akashi@linaro.org, patrick.delaunay@foss.st.com, patrice.chotard@foss.st.com, sjg@chromium.org, bmeng.cn@gmail.com, trini@konsulko.com, etienne.carriere@linaro.org, monstr@monstr.eu, Sughosh Ganu , Jassi Brar Subject: [PATCH 2/5] FWU: Add FWU metadata access driver for MTD storage regions Date: Fri, 22 Jul 2022 12:43:16 -0500 Message-Id: <20220722174319.64006-3-jassisinghbrar@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220722174319.64006-1-jassisinghbrar@gmail.com> References: <20220722174240.63935-1-jassisinghbrar@gmail.com> <20220722174319.64006-1-jassisinghbrar@gmail.com> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 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.103.6 at phobos.denx.de X-Virus-Status: Clean From: Sughosh Ganu In the FWU Multi Bank Update feature, the information about the updatable images is stored as part of the metadata, on a separate region. Add a driver for reading from and writing to the metadata when the updatable images and the metadata are stored on a raw MTD region. Signed-off-by: Sughosh Ganu Signed-off-by: Jassi Brar --- drivers/fwu-mdata/Kconfig | 8 + drivers/fwu-mdata/Makefile | 1 + drivers/fwu-mdata/fwu_mdata_mtd.c | 308 ++++++++++++++++++++++++++++++ 3 files changed, 317 insertions(+) create mode 100644 drivers/fwu-mdata/fwu_mdata_mtd.c diff --git a/drivers/fwu-mdata/Kconfig b/drivers/fwu-mdata/Kconfig index d5edef19d6..a8fa9ad783 100644 --- a/drivers/fwu-mdata/Kconfig +++ b/drivers/fwu-mdata/Kconfig @@ -14,3 +14,11 @@ config FWU_MDATA_GPT_BLK help Enable support for accessing FWU Metadata on GPT partitioned block devices. + +config FWU_MDATA_MTD + bool "FWU Metadata access for non-GPT MTD devices" + depends on DM_FWU_MDATA && MTD + help + Enable support for accessing FWU Metadata on non-partitioned + (or non-GPT partitioned, e.g. partition nodes in devicetree) + MTD devices. diff --git a/drivers/fwu-mdata/Makefile b/drivers/fwu-mdata/Makefile index 313049f67a..58f8023f16 100644 --- a/drivers/fwu-mdata/Makefile +++ b/drivers/fwu-mdata/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_DM_FWU_MDATA) += fwu-mdata-uclass.o obj-$(CONFIG_FWU_MDATA_GPT_BLK) += fwu_mdata_gpt_blk.o +obj-$(CONFIG_FWU_MDATA_MTD) += fwu_mdata_mtd.o diff --git a/drivers/fwu-mdata/fwu_mdata_mtd.c b/drivers/fwu-mdata/fwu_mdata_mtd.c new file mode 100644 index 0000000000..d543a419fd --- /dev/null +++ b/drivers/fwu-mdata/fwu_mdata_mtd.c @@ -0,0 +1,308 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022, Linaro Limited + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +struct fwu_mdata_mtd_priv { + struct mtd_info *mtd; + u32 pri_offset; + u32 sec_offset; +}; + +enum fwu_mtd_op { + FWU_MTD_READ, + FWU_MTD_WRITE, +}; + +static bool mtd_is_aligned_with_block_size(struct mtd_info *mtd, u64 size) +{ + return !do_div(size, mtd->erasesize); +} + +static int mtd_io_data(struct mtd_info *mtd, u32 offs, u32 size, void *data, + enum fwu_mtd_op op) +{ + struct mtd_oob_ops io_op ={}; + u64 lock_offs, lock_len; + size_t len; + void *buf; + int ret; + + if (!mtd_is_aligned_with_block_size(mtd, offs)) + return -EINVAL; + lock_offs = offs; + lock_len = round_up(size, mtd->erasesize); + + ret = mtd_unlock(mtd, lock_offs, lock_len); + if (ret && ret != -EOPNOTSUPP) + return ret; + + if (op == FWU_MTD_WRITE) { + struct erase_info erase_op = {}; + + /* This will expand erase size to align with the block size */ + erase_op.mtd = mtd; + erase_op.addr = lock_offs; + erase_op.len = lock_len; + erase_op.scrub = 0; + + ret = mtd_erase(mtd, &erase_op); + if (ret) + goto lock_out; + } + + /* Also, expand the write size to align with the write size */ + len = round_up(size, mtd->writesize); + + buf = memalign(ARCH_DMA_MINALIGN, len); + if (!buf) { + ret = -ENOMEM; + goto lock_out; + } + io_op.mode = MTD_OPS_AUTO_OOB; + io_op.len = len; + io_op.ooblen = 0; + io_op.datbuf = buf; + io_op.oobbuf = NULL; + + if (op == FWU_MTD_WRITE) { + memcpy(buf, data, size); + ret = mtd_write_oob(mtd, offs, &io_op); + } else { + ret = mtd_read_oob(mtd, offs, &io_op); + if (!ret) + memcpy(data, buf, size); + } + free(buf); + +lock_out: + mtd_lock(mtd, lock_offs, lock_len); + + return ret; +} + +static int fwu_mtd_load_mdata(struct mtd_info *mtd, struct fwu_mdata **mdata, + u32 offs, bool primary) +{ + size_t size = sizeof(struct fwu_mdata); + int ret; + + *mdata = malloc(size); + if (!*mdata) + return -ENOMEM; + + ret = mtd_io_data(mtd, offs, size, (void *)*mdata, FWU_MTD_READ); + if (ret >= 0) { + ret = fwu_verify_mdata(*mdata, primary); + if (ret < 0) { + free(*mdata); + *mdata = NULL; + } + } + + return ret; +} + +static int fwu_mtd_load_primary_mdata(struct fwu_mdata_mtd_priv *mtd_priv, + struct fwu_mdata **mdata) +{ + return fwu_mtd_load_mdata(mtd_priv->mtd, mdata, mtd_priv->pri_offset, true); +} + +static int fwu_mtd_load_secondary_mdata(struct fwu_mdata_mtd_priv *mtd_priv, + struct fwu_mdata **mdata) +{ + return fwu_mtd_load_mdata(mtd_priv->mtd, mdata, mtd_priv->sec_offset, false); +} + +static int fwu_mtd_save_primary_mdata(struct fwu_mdata_mtd_priv *mtd_priv, + struct fwu_mdata *mdata) +{ + return mtd_io_data(mtd_priv->mtd, mtd_priv->pri_offset, + sizeof(struct fwu_mdata), mdata, FWU_MTD_WRITE); +} + +static int fwu_mtd_save_secondary_mdata(struct fwu_mdata_mtd_priv *mtd_priv, + struct fwu_mdata *mdata) +{ + return mtd_io_data(mtd_priv->mtd, mtd_priv->sec_offset, + sizeof(struct fwu_mdata), mdata, FWU_MTD_WRITE); +} + +static int fwu_mtd_get_valid_mdata(struct fwu_mdata_mtd_priv *mtd_priv, + struct fwu_mdata **mdata) +{ + if (fwu_mtd_load_primary_mdata(mtd_priv, mdata) == 0) + return 0; + + log_err("Failed to load/verify primary mdata. Try secondary.\n"); + + if (fwu_mtd_load_secondary_mdata(mtd_priv, mdata) == 0) + return 0; + + log_err("Failed to load/verify secondary mdata.\n"); + + return -1; +} + +static int fwu_mtd_update_mdata(struct udevice *dev, struct fwu_mdata *mdata) +{ + struct fwu_mdata_mtd_priv *mtd_priv = dev_get_priv(dev); + int ret; + + /* Update mdata crc32 field */ + mdata->crc32 = crc32(0, (void *)&mdata->version, + sizeof(*mdata) - sizeof(u32)); + + /* First write the primary mdata */ + ret = fwu_mtd_save_primary_mdata(mtd_priv, mdata); + if (ret < 0) { + log_err("Failed to update the primary mdata.\n"); + return ret; + } + + /* And now the replica */ + ret = fwu_mtd_save_secondary_mdata(mtd_priv, mdata); + if (ret < 0) { + log_err("Failed to update the secondary mdata.\n"); + return ret; + } + + return 0; +} + +static int fwu_mtd_mdata_check(struct udevice *dev) +{ + struct fwu_mdata *primary = NULL, *secondary = NULL; + struct fwu_mdata_mtd_priv *mtd_priv = dev_get_priv(dev); + int ret; + + ret = fwu_mtd_load_primary_mdata(mtd_priv, &primary); + if (ret < 0) + log_err("Failed to read the primary mdata: %d\n", ret); + + ret = fwu_mtd_load_secondary_mdata(mtd_priv, &secondary); + if (ret < 0) + log_err("Failed to read the secondary mdata: %d\n", ret); + + if (primary && secondary) { + if (memcmp(primary, secondary, sizeof(struct fwu_mdata))) { + log_err("The primary and the secondary mdata are different\n"); + ret = -1; + } + } else if (primary) { + ret = fwu_mtd_save_secondary_mdata(mtd_priv, primary); + if (ret < 0) + log_err("Restoring secondary mdata partition failed\n"); + } else if (secondary) { + ret = fwu_mtd_save_primary_mdata(mtd_priv, secondary); + if (ret < 0) + log_err("Restoring primary mdata partition failed\n"); + } + + free(primary); + free(secondary); + return ret; +} + +static int fwu_mtd_get_mdata(struct udevice *dev, struct fwu_mdata **mdata) +{ + struct fwu_mdata_mtd_priv *mtd_priv = dev_get_priv(dev); + + return fwu_mtd_get_valid_mdata(mtd_priv, mdata); +} + +/** + * fwu_mdata_mtd_of_to_plat() - Translate from DT to fwu mdata device + */ +static int fwu_mdata_mtd_of_to_plat(struct udevice *dev) +{ + struct fwu_mdata_mtd_priv *mtd_priv = dev_get_priv(dev); + const fdt32_t *phandle_p = NULL; + struct udevice *mtd_dev; + struct mtd_info *mtd; + int ret, size; + u32 phandle; + + /* Find the FWU mdata storage device */ + phandle_p = ofnode_get_property(dev_ofnode(dev), + "fwu-mdata-store", &size); + if (!phandle_p) { + log_err("fwu-mdata-store property not found\n"); + return -ENOENT; + } + + phandle = fdt32_to_cpu(*phandle_p); + + ret = device_get_global_by_ofnode( + ofnode_get_by_phandle(phandle), + &mtd_dev); + if (ret) + return ret; + + mtd_probe_devices(); + + mtd_for_each_device(mtd) { + if (mtd->dev == mtd_dev) { + mtd_priv->mtd = mtd; + log_debug("Found the FWU mdata mtd device %s\n", mtd->name); + break; + } + } + if (!mtd_priv->mtd) { + log_err("Failed to find mtd device by fwu-mdata-store\n"); + return -ENOENT; + } + + /* Get the offset of primary and seconday mdata */ + ret = ofnode_read_u32_index(dev_ofnode(dev), "mdata-offsets", 0, + &mtd_priv->pri_offset); + if (ret) + return ret; + ret = ofnode_read_u32_index(dev_ofnode(dev), "mdata-offsets", 1, + &mtd_priv->sec_offset); + if (ret) + return ret; + + return 0; +} + +static int fwu_mdata_mtd_probe(struct udevice *dev) +{ + /* Ensure the metadata can be read. */ + return fwu_mtd_mdata_check(dev); +} + +static struct fwu_mdata_ops fwu_mtd_ops = { + .mdata_check = fwu_mtd_mdata_check, + .get_mdata = fwu_mtd_get_mdata, + .update_mdata = fwu_mtd_update_mdata, +}; + +static const struct udevice_id fwu_mdata_ids[] = { + { .compatible = "u-boot,fwu-mdata-mtd" }, + { } +}; + +U_BOOT_DRIVER(fwu_mdata_mtd) = { + .name = "fwu-mdata-mtd", + .id = UCLASS_FWU_MDATA, + .of_match = fwu_mdata_ids, + .ops = &fwu_mtd_ops, + .probe = fwu_mdata_mtd_probe, + .of_to_plat = fwu_mdata_mtd_of_to_plat, + .priv_auto = sizeof(struct fwu_mdata_mtd_priv), +};