From patchwork Wed Jun 29 08:01:10 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerome Forissier X-Patchwork-Id: 1649905 X-Patchwork-Delegate: ykai007@gmail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.a=rsa-sha256 header.s=google header.b=J7KHoQDx; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4LXv7T0ldlz9sG2 for ; Wed, 29 Jun 2022 18:01:57 +1000 (AEST) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 248A9842C0; Wed, 29 Jun 2022 10:01:48 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=linaro.org 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=linaro.org header.i=@linaro.org header.b="J7KHoQDx"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id DCDF48427E; Wed, 29 Jun 2022 10:01:45 +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,SPF_HELO_NONE,SPF_PASS, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-wm1-x336.google.com (mail-wm1-x336.google.com [IPv6:2a00:1450:4864:20::336]) (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 D4F5E838BB for ; Wed, 29 Jun 2022 10:01:42 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=jerome.forissier@linaro.org Received: by mail-wm1-x336.google.com with SMTP id k129so7418621wme.0 for ; Wed, 29 Jun 2022 01:01:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=KB4Uk96JKkQ9yLrjtoBlPgafS5K1Ek1CjAjCREuUWHI=; b=J7KHoQDxxm8wp0XbRep/u5yqU1SUT4gH65aTZvmim4oKKBCdcgT5avUV1XO5vVqe/g iu6IbtSTWu5E++M36d+JOcD91RuJ/UvGUFAfxoxgUPpDRCyGnDK01E+mmnRWq/m4ZhhU QxU5kNK+QGz+rNgPRBMfE2Q/NppWueQK50gI5utfRZaSd7Sk2Ao0O15xqClQEsKTWTGH CEdAI7AWkPr3gL0u7MeN9SE13sMUgkQao6GvwIkGrwIkfe0DAcVc9w/6Stbb2YD2W87/ 6AJuuneanWixJhDOnWavLXejzDyD4zrpcTK73JFByqssUIyqQK2U2CNsP0jpZnMvZhHT mLtw== 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=KB4Uk96JKkQ9yLrjtoBlPgafS5K1Ek1CjAjCREuUWHI=; b=O6TZdiGagkEfp4c/IEObQuk+HmiZ3NV7DRbnCpPjI6NyGq7rLln6WHbNDJEB0Xf9XV f00dbbyGElwqQ4VKBGRmj/OCZGZnLsc3TDq//UMusDuHTCUOZUObwy8m/jAY3n/JPrmz XGBpCJzowKZOGZJg+3e9Cum/j8acki1aZV4EINKDxwfxcPpkEK0eEcqL+fLw7PqoHKrk XZfoRgm3Z5NVbFtIzcduZrAyLIdQ9U/koU/C1a1IjRSm2VdhXrxqH58OTIeaxuSJnI8p EwycsLR64Nf63fgKQioGSzadP7jqUnCzO1JgEtOohH/dE3er3I7cbvFBUlFQCv005GiV DxVg== X-Gm-Message-State: AJIora+hDiJBVaNDsLa7/VvInf58VsC9koUi2+FkEuAeFXDu60cSqIJA QNV1bs/8FXrGztZaaUtoVMYsNylWQO1jgleGG1WN/Q== X-Google-Smtp-Source: AGRyM1u3H4CDtI+rdC+xtenLC8Jr8rkuaVUKblYW7xxyZz9kIMlrOaHQtbzWIB7ktuucXYpzc5xogQ== X-Received: by 2002:a05:600c:3659:b0:3a0:3915:8700 with SMTP id y25-20020a05600c365900b003a039158700mr2039599wmq.127.1656489702211; Wed, 29 Jun 2022 01:01:42 -0700 (PDT) Received: from jerome-XPS-13-9310.. ([2a01:e0a:3cb:7bb0:592b:5102:88ef:e71d]) by smtp.gmail.com with ESMTPSA id r5-20020a05600c320500b0039db500714fsm2168077wmp.6.2022.06.29.01.01.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 29 Jun 2022 01:01:41 -0700 (PDT) From: Jerome Forissier To: u-boot@lists.denx.de Cc: Jerome Forissier , Xavier Drudis Ferran , Jagan Teki , Simon Glass , Philipp Tomsich , Kever Yang , Alexandru Gagniuc , Jaehoon Chung , Heiko Schocher , Aswath Govindraju , Nishanth Menon Subject: [PATCH v2 1/2] spl: fit: add config option for temporary buffer when loading image Date: Wed, 29 Jun 2022 10:01:10 +0200 Message-Id: X-Mailer: git-send-email 2.34.1 In-Reply-To: References: 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 When the load address of a FIT image isn't properly aligned, spl_load_fit_image() may write past the end of the destination buffer. It is not an issue in many cases because the memory happens to be writeable and nothing important is present in the overflow. On RockPi4 however there is a configuration where a TF-A image (bl31_0xff3b0000.bin) has to be loaded into a 8K range of SRAM memory, between 0xff3b0000 and 0xff3b2000. The end address is a hard limit, because due to the way the hardware is wired, the addresses wrap and any overflow gets written back to 0xff3b0000 thus overwriting previous data. To address this problem, introduce a helper function which loads data using a temporary buffer allocated on the stack. The size of the buffer is defined by SPL_LOAD_FIT_IMAGE_BUFFER_SIZE (default 0x0 or disabled). Co-developed-by: Xavier Drudis Ferran Signed-off-by: Xavier Drudis Ferran Signed-off-by: Jerome Forissier --- common/spl/Kconfig | 45 +++++++++++++++++++++++++ common/spl/spl_fit.c | 79 ++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 118 insertions(+), 6 deletions(-) diff --git a/common/spl/Kconfig b/common/spl/Kconfig index 50ff113cab..d95141a6f6 100644 --- a/common/spl/Kconfig +++ b/common/spl/Kconfig @@ -1339,6 +1339,51 @@ config SPL_OPENSBI_LOAD_ADDR help Load address of the OpenSBI binary. +config SPL_LOAD_FIT_IMAGE_BUFFER_SIZE + hex "Read unaligned external FIT images to a temporary buffer in SPL" + default 0x0 + depends on SPL_LOAD_FIT + help + An aligned FIT image is such that it starts at the beginning + of a block in media and has a load_addr in its FIT header + that is DMA aligned in RAM. These aligned images can be read + directly from media to RAM. Unaligned external FIT images + are those that need reading some extra data before and/or after + the image because they don't occupy fully the blocks they're + in in media, or their destination is not DMA aligned and must + be read somewhere aligned before copying them to load_addr. + + With this option set to 0x0 full blocks will just be read in + the closest DMA aligned address, and the unaligned image + inside those read blocks will later be copied to + load_addr. Meanwhile memory outside [load_addr, + load_addr+length) will have been written. That's no problem + when the block length, image size and load_addr have been + taken into account when laying out memory. + + But in some cases not all memory is writable, or undesired + effects arise when writing outside [load_addr, + load_addr+length). For instance, in RK3399, one of the + images is ATF2, of size 8KiB which should be loaded into + INTMEM1, at address 0xff3b0000. This address is DMA aligned + but tight. It maps to a 8KiB SRAM area. If the image on + media is not block aligned some extra bytes get read before + and after, and everything extra written in + 0xff3b2000-0xff3bffff corrupts SRAM at + 0xff3b0000-0xff3b1fff before the image is memcpyied in place. + + With this option set to a nonzero value a DMA aligned buffer + will be allocated on the stack and the image will be read + in chuncks of blocks to this buffer, with each chunk being + memcpyied to [load_addr,load_addr+length), so never writing + outside the destination area. + + The advantage of enabling this option is safety, and the + disadvantage is more stack use and slower image load (one read + per chunk instead of just one). + + The default is 0x0 to replicate previous behaviour. + config TPL bool depends on SUPPORT_TPL diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c index 1bbf824684..56775fd744 100644 --- a/common/spl/spl_fit.c +++ b/common/spl/spl_fit.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -218,6 +219,64 @@ static int get_aligned_image_size(struct spl_load_info *info, int data_size, return (data_size + info->bl_len - 1) / info->bl_len; } +#if (CONFIG_SPL_LOAD_FIT_IMAGE_BUFFER_SIZE != 0x0) +static int load_with_tmpbuf(struct spl_load_info *info, ulong load_addr, + ulong sector, int offs, size_t len) +{ + ALLOC_CACHE_ALIGN_BUFFER(u8, buf, + CONFIG_SPL_LOAD_FIT_IMAGE_BUFFER_SIZE); + void *dst = (void *)load_addr; + int nsect = (len + offs + info->bl_len - 1) / info->bl_len; + int bufsect = (CONFIG_SPL_LOAD_FIT_IMAGE_BUFFER_SIZE) / info->bl_len; + size_t sz, tail = 0; + + if (offs) { + sz = info->bl_len - offs; + if (sz > len) + sz = len; + if (info->read(info, sector, 1, buf) != 1) + return -EIO; + memcpy(dst, buf + offs, sz); + dst += sz; + sector++; + nsect--; + } + + if (nsect) { + tail = (len + offs) % info->bl_len; + nsect--; + } + + while (nsect) { + int n = nsect; + + if (n > bufsect) + n = bufsect; + if (info->read(info, sector, n, buf) != n) + return -EIO; + sz = n * info->bl_len; + memcpy(dst, buf, sz); + dst += sz; + sector += n; + nsect -= n; + } + + if (tail) { + if (info->read(info, sector, 1, buf) != 1) + return -EIO; + memcpy(dst, buf, tail); + } + + return 0; +} +#else +static int load_with_tmpbuf(struct spl_load_info *info, ulong load_addr, + ulong sector, int offs, size_t len) +{ + return -ENOENT; +} +#endif + /** * spl_load_fit_image(): load the image described in a certain FIT node * @info: points to information about the device to load data from @@ -236,6 +295,7 @@ static int spl_load_fit_image(struct spl_load_info *info, ulong sector, const struct spl_fit_info *ctx, int node, struct spl_image_info *image_info) { + int ret; int offset; size_t length; int len; @@ -298,15 +358,22 @@ static int spl_load_fit_image(struct spl_load_info *info, ulong sector, overhead = get_aligned_image_overhead(info, offset); nr_sectors = get_aligned_image_size(info, length, offset); - - if (info->read(info, - sector + get_aligned_image_offset(info, offset), - nr_sectors, src_ptr) != nr_sectors) - return -EIO; + sector += get_aligned_image_offset(info, offset); + if (CONFIG_SPL_LOAD_FIT_IMAGE_BUFFER_SIZE) { + ret = load_with_tmpbuf(info, load_addr, sector, + overhead, len); + if (ret < 0) + return ret; + src = (void *)load_addr; + } else { + if (info->read(info, sector, nr_sectors, + src_ptr) != nr_sectors) + return -EIO; + src = src_ptr + overhead; + } debug("External data: dst=%p, offset=%x, size=%lx\n", src_ptr, offset, (unsigned long)length); - src = src_ptr + overhead; } else { /* Embedded data */ if (fit_image_get_data(fit, node, &data, &length)) {