From patchwork Sat May 13 01:36:57 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ralph Siemsen X-Patchwork-Id: 681594 Delivered-To: patch@linaro.org Received: by 2002:adf:fd8f:0:0:0:0:0 with SMTP id d15csp62698wrr; Fri, 12 May 2023 18:39:21 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ41xjqeNdgfj0H90qKyjjp7SfTaMc6asEKd6QEWzaXWf2dJMd6EgSlDysH0L+q8y9tKPAaQ X-Received: by 2002:a17:90a:384b:b0:24d:dc79:5901 with SMTP id l11-20020a17090a384b00b0024ddc795901mr27792399pjf.26.1683941961595; Fri, 12 May 2023 18:39:21 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1683941961; cv=none; d=google.com; s=arc-20160816; b=DjPZcYOHf8ZdVn9ELskc7tnbmMMq9AHVZvH5qxHn7E5Gr2XB6OCwpJO3FucSq9mi2e p2ye6S9E6243sW41kg46pT+bj36tfIjfhogFLcI7tJCNySDP+lkc4ohSH1Y5w8m3vMg5 zDjeww0QbnuEbV1kILF92uBkbMDgC3PiFJEc3gKJmn6uL8MEeHQZ2lk/cPyNePYvnASg 0RsaFCv2B69x2C2oI4zZCQp+DT2157ky+PdAt1MygvNTu0ekBRBHGMR9M/gqgUk1Ec3x 1cC1ow/9xCYRIK8t+WSaFtFqihspk+FEGFTfq3RGRE1eYerGKNKox/ObXb1lBFCdquR/ jpWw== 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=zB/j7DZ/EMHROsccO1PDH/LY7EiTtqAju7YcvQOfdio=; b=bf9eVoQVY0DQKDgC+uwMCukhzJJiiSlEvPqTFthwFtzgTuPpCYO9G4eC57duZbCgwN Ess+j/O3wMVhtNqvNdk8XSQv48do2y5KAjS0hEK+pvWK5vRdV2SCzapA7BXP6cYiKKF5 dL9R0xSKeZdLLFySRk4QxkgHHCjMr5/Kcbzgzj2Z6vavzcDeOaVMIJHhO7uUYG9dc9cH EJfIaSY+kCxMSNv8M5uKMC5AuBVGIejQHp1BCPfVTtkCoys3SWqgv1Qc4mbZK800iivJ o4q+tzFijhR50IqBEcQRwvKgZ0LrZk+LCx5vY2e1PM5dElo9JCGgyd1SMQGNe6ikJze7 Zetw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=mbbgzst9; 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=NONE dis=NONE) header.from=linaro.org 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 ds6-20020a17090b08c600b00232f57260c1si24146420pjb.1.2023.05.12.18.39.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 12 May 2023 18:39:21 -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=@linaro.org header.s=google header.b=mbbgzst9; 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=NONE dis=NONE) header.from=linaro.org Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 6DD0C86380; Sat, 13 May 2023 03:37:32 +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="mbbgzst9"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id E738E8630B; Sat, 13 May 2023 03:37:22 +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-qv1-xf29.google.com (mail-qv1-xf29.google.com [IPv6:2607:f8b0:4864:20::f29]) (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 B8306862B1 for ; Sat, 13 May 2023 03:37:14 +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=ralph.siemsen@linaro.org Received: by mail-qv1-xf29.google.com with SMTP id 6a1803df08f44-619ca08c166so50754976d6.1 for ; Fri, 12 May 2023 18:37:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1683941834; x=1686533834; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=zB/j7DZ/EMHROsccO1PDH/LY7EiTtqAju7YcvQOfdio=; b=mbbgzst9uNelN39Z1A/sXGY4gX9l+c1yseKWoMe+Qy9GrqUsFwKZG9PSOEv3DQ7Yx+ IrB5YaS/JM6N5RGpjy3call0NhWoQpbC/WEP94FymeRcU6cQt+QMAtv3Kg9CmOsyJwpa wPEoKKrWW/QvZ+6uLL9qISX2ujzCoEmRhW1RrwVfFMsAAFraTX1SeRt7FNGLYVa/Z8gO PsE3+Di76zmEgcN//igIVLSbuwnjSGh73bBueLoh9e1mKnvfdFqE0BzB/zgjEYgdXHx0 By87FGcZ/OqAWO5Qht4fip3JdccxMVshD9Dk00a3PML5txvfRbKSOkb/ypKz7B7zzbBE Z9Jw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1683941834; x=1686533834; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=zB/j7DZ/EMHROsccO1PDH/LY7EiTtqAju7YcvQOfdio=; b=WrWxNyQDdBAC7VvPC7NdGfd3DiGWr1sV0BzUepyfSrJIGS/wQL9qgUj0tHSZUtvrJn jqoaGiEVhbfopufDYWy84AoSl/828LHaAesPWj6/2B1DsJi+Nqz6878uNqkSEZc9piZx wctu+1EVfVRhXmK3hOU04ZzuQV33ga44zBIcvhuVXpjUXFQKXxT2nCFMF1c4sAYIe1Ac +yOl2JrffBX4MOEqr0qC/drzNcmE+fH73Ll/zPymVbikpITF9rhmQIpYm2hAhJ8lPTZJ 5Y2LAd/lDUPkIDuO6gDg9wYqIYU/Atu+Mmn8jKmJBXYfLE4NhoW1zEg25ajMMRkW8R89 xtvA== X-Gm-Message-State: AC+VfDx75bAjb1z6Ud5jw4ONko0UmBVOVZfaURtZFalbu4GrVnsVouw/ Najwoe+CWSBfF/R2zlipRRBVIP52ZrfvJ4DBYZeWPg== X-Received: by 2002:a05:6214:2aad:b0:621:2d89:524a with SMTP id js13-20020a0562142aad00b006212d89524amr28252610qvb.32.1683941834159; Fri, 12 May 2023 18:37:14 -0700 (PDT) Received: from maple.netwinder.org (rfs.netwinder.org. [206.248.184.2]) by smtp.gmail.com with ESMTPSA id fi19-20020a0562141a5300b0061b608dc4c1sm3379399qvb.94.2023.05.12.18.37.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 12 May 2023 18:37:13 -0700 (PDT) From: Ralph Siemsen To: u-boot@lists.denx.de Cc: Marek Vasut , Ralph Siemsen , Simon Glass , Marek Vasut , Heiko Thiery , Heinrich Schuchardt , Marc Kleine-Budde , Massimo Pegorer , Mattijs Korpershoek , Max Krummenacher , =?utf-8?q?Pali_Roh=C3=A1r?= , Roman Kopytin , Safae Ouajih , Sean Anderson , Steven Lawrance , Sughosh Ganu , Weijie Gao Subject: [PATCH v7 09/10] tools: spkgimage: add Renesas SPKG format Date: Fri, 12 May 2023 21:36:57 -0400 Message-Id: <20230513013658.2330651-10-ralph.siemsen@linaro.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20230513013658.2330651-1-ralph.siemsen@linaro.org> References: <20230513013658.2330651-1-ralph.siemsen@linaro.org> 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.8 at phobos.denx.de X-Virus-Status: Clean Renesas RZ/N1 devices contain BootROM code that loads a custom SPKG image from QSPI, NAND or USB DFU. Support this format in mkimage tool. SPKGs can optionally be signed, however creation of signed SPKG is not currently supported. Example of how to use it: tools/mkimage -n board/schneider/rzn1-snarc/spkgimage.cfg \ -T spkgimage -a 0x20040000 -e 0x20040000 \ -d u-boot.bin u-boot.bin.spkg The config file (spkgimage.cfg in this example) contains additional parameters such as NAND ECC settings. Signed-off-by: Ralph Siemsen Reviewed-by: Simon Glass Reviewed-by: Marek Vasut --- Changes in v7: - restore static globals for the config file structure - restore check_image_types() to only recognise SPKG. For details of why this is necessary refer to https://lore.kernel.org/u-boot/20220826150123.GA1235411@maple.netwinder.org/ Changes in v5: - use strcspn() instead of open-coded loop for \n removal - rename source files to include vendor name - replace static globals with dynamically allocated structure - update print_header function signature Changes in v4: - added tags - add RZ/N1 board documentation - added binman support Changes in v3: - provide definition of __packed (as done in kwbimage.h) - explain why a local copy of roundup() is needed - document spkgimage in doc/mkimage.1 - add range checks when parsing config file values - add line numbers for reporting errors in config file - rename SPKG_HEADER_SIGNATURE to SPKG_HEADER_MARKER - fix segfault when image is padded by less than 4 bytes - minor style and typo fixes Changes in v2: - rewrote the stand-alone spkg_utility to integrate into mkimage board/schneider/rzn1-snarc/spkgimage.cfg | 26 ++ boot/image.c | 1 + doc/mkimage.1 | 45 +++ include/image.h | 1 + tools/Makefile | 1 + tools/renesas_spkgimage.c | 336 +++++++++++++++++++++++ tools/renesas_spkgimage.h | 87 ++++++ 7 files changed, 497 insertions(+) create mode 100644 board/schneider/rzn1-snarc/spkgimage.cfg create mode 100644 tools/renesas_spkgimage.c create mode 100644 tools/renesas_spkgimage.h diff --git a/board/schneider/rzn1-snarc/spkgimage.cfg b/board/schneider/rzn1-snarc/spkgimage.cfg new file mode 100644 index 0000000000..b5faf96b00 --- /dev/null +++ b/board/schneider/rzn1-snarc/spkgimage.cfg @@ -0,0 +1,26 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# (C) Copyright 2022 Schneider Electric +# +# SPKG image header, for booting on RZ/N1 + +# b[35:32] SPKG version +VERSION 1 + +# b[42:41] ECC Block size: 0=256 bytes, 1=512 bytes, 2=1024 bytes +NAND_ECC_BLOCK_SIZE 1 + +# b[45] NAND enable (boolean) +NAND_ECC_ENABLE 1 + +# b[50:48] ECC Scheme: 0=BCH2 1=BCH4 2=BCH8 3=BCH16 4=BCH24 5=BCH32 +NAND_ECC_SCHEME 3 + +# b[63:56] ECC bytes per block +NAND_BYTES_PER_ECC_BLOCK 28 + +# Provide dummy BLp header (boolean) +ADD_DUMMY_BLP 1 + +# Pad the image to a multiple of +PADDING 64K diff --git a/boot/image.c b/boot/image.c index 958dbf8534..5c4f9b807d 100644 --- a/boot/image.c +++ b/boot/image.c @@ -181,6 +181,7 @@ static const table_entry_t uimage_type[] = { { IH_TYPE_SUNXI_EGON, "sunxi_egon", "Allwinner eGON Boot Image" }, { IH_TYPE_SUNXI_TOC0, "sunxi_toc0", "Allwinner TOC0 Boot Image" }, { IH_TYPE_FDT_LEGACY, "fdt_legacy", "legacy Image with Flat Device Tree ", }, + { IH_TYPE_RENESAS_SPKG, "spkgimage", "Renesas SPKG Image" }, { -1, "", "", }, }; diff --git a/doc/mkimage.1 b/doc/mkimage.1 index d8727ec73c..76c7859bb0 100644 --- a/doc/mkimage.1 +++ b/doc/mkimage.1 @@ -662,6 +662,51 @@ rk3568 .TE .RE . +.SS spkgimage +The primary configuration file consists of lines containing key/value pairs +delimited by whitespace. An example follows. +.PP +.RS +.EX +# Comments and blank lines may be used +.I key1 value1 +.I key2 value2 +.EE +.RE +.P +The supported +.I key +types are as follows. +.TP +.B VERSION +.TQ +.B NAND_ECC_BLOCK_SIZE +.TQ +.B NAND_ECC_ENABLE +.TQ +.B NAND_ECC_SCHEME +.TQ +.B NAND_BYTES_PER_ECC_BLOCK +These all take a positive integer value as their argument. +The value will be copied directly into the respective field +of the SPKG header structure. For details on these values, +refer to Section 7.4 of the Renesas RZ/N1 User's Manual. +. +.TP +.B ADD_DUMMY_BLP +Takes a numeric argument, which is treated as a boolean. Any nonzero +value will cause a fake BLp security header to be included in the SPKG +output. +. +.TP +.B PADDING +Takes a positive integer value, with an optional +.B K +or +.B M +suffix, indicating KiB / MiB respectively. +The output SPKG file will be padded to a multiple of this value. +. .SS sunxi_egon The primary configuration is the name to use for the device tree. . diff --git a/include/image.h b/include/image.h index 456197d6fd..01a6787d21 100644 --- a/include/image.h +++ b/include/image.h @@ -230,6 +230,7 @@ enum image_type_t { IH_TYPE_SUNXI_EGON, /* Allwinner eGON Boot Image */ IH_TYPE_SUNXI_TOC0, /* Allwinner TOC0 Boot Image */ IH_TYPE_FDT_LEGACY, /* Binary Flat Device Tree Blob in a Legacy Image */ + IH_TYPE_RENESAS_SPKG, /* Renesas SPKG image */ IH_TYPE_COUNT, /* Number of image types */ }; diff --git a/tools/Makefile b/tools/Makefile index 38699b069d..d793cf3bec 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -122,6 +122,7 @@ dumpimage-mkimage-objs := aisimage.o \ os_support.o \ pblimage.o \ pbl_crc32.o \ + renesas_spkgimage.o \ vybridimage.o \ stm32image.o \ $(ROCKCHIP_OBS) \ diff --git a/tools/renesas_spkgimage.c b/tools/renesas_spkgimage.c new file mode 100644 index 0000000000..fa0a468cc4 --- /dev/null +++ b/tools/renesas_spkgimage.c @@ -0,0 +1,336 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Generate Renesas RZ/N1 BootROM header (SPKG) + * (C) Copyright 2022 Schneider Electric + * + * Based on spkg_utility.c + * (C) Copyright 2016 Renesas Electronics Europe Ltd + */ + +#include "imagetool.h" +#include +#include +#include +#include +#include +#include "renesas_spkgimage.h" + +/* Note: the ordering of the bitfields does not matter */ +struct config_file { + unsigned int version:1; + unsigned int ecc_block_size:2; + unsigned int ecc_enable:1; + unsigned int ecc_scheme:3; + unsigned int ecc_bytes:8; + unsigned int blp_len; + unsigned int padding; +}; + +static struct config_file conf; + +static int check_range(const char *name, int val, int min, int max) +{ + if (val < min) { + fprintf(stderr, "Warning: param '%s' adjusted to min %d\n", + name, min); + val = min; + } + + if (val > max) { + fprintf(stderr, "Warning: param '%s' adjusted to max %d\n", + name, max); + val = max; + } + + return val; +} + +static int spkgimage_parse_config_line(char *line, size_t line_num) +{ + char *saveptr; + char *delim = "\t "; + char *name = strtok_r(line, delim, &saveptr); + char *val_str = strtok_r(NULL, delim, &saveptr); + int value = atoi(val_str); + + if (!strcmp("VERSION", name)) { + conf.version = check_range(name, value, 1, 15); + } else if (!strcmp("NAND_ECC_ENABLE", name)) { + conf.ecc_enable = check_range(name, value, 0, 1); + } else if (!strcmp("NAND_ECC_BLOCK_SIZE", name)) { + conf.ecc_block_size = check_range(name, value, 0, 2); + } else if (!strcmp("NAND_ECC_SCHEME", name)) { + conf.ecc_scheme = check_range(name, value, 0, 7); + } else if (!strcmp("NAND_BYTES_PER_ECC_BLOCK", name)) { + conf.ecc_bytes = check_range(name, value, 0, 255); + } else if (!strcmp("ADD_DUMMY_BLP", name)) { + conf.blp_len = value ? SPKG_BLP_SIZE : 0; + } else if (!strcmp("PADDING", name)) { + if (strrchr(val_str, 'K')) + value = value * 1024; + else if (strrchr(val_str, 'M')) + value = value * 1024 * 1024; + conf.padding = check_range(name, value, 1, INT_MAX); + } else { + fprintf(stderr, + "config error: unknown keyword on line %ld\n", + line_num); + return -EINVAL; + } + + return 0; +} + +static int spkgimage_parse_config_file(char *filename) +{ + FILE *fcfg; + char line[256]; + size_t line_num = 0; + + fcfg = fopen(filename, "r"); + if (!fcfg) + return -EINVAL; + + while (fgets(line, sizeof(line), fcfg)) { + line_num += 1; + + /* Skip blank lines and comments */ + if (line[0] == '\n' || line[0] == '#') + continue; + + /* Strip any trailing newline */ + line[strcspn(line, "\n")] = 0; + + /* Parse the line */ + if (spkgimage_parse_config_line(line, line_num)) + return -EINVAL; + } + + fclose(fcfg); + + /* Avoid divide-by-zero later on */ + if (!conf.padding) + conf.padding = 1; + + return 0; +} + +static int spkgimage_check_params(struct image_tool_params *params) +{ + if (!params->addr) { + fprintf(stderr, "Error: Load Address must be set.\n"); + return -EINVAL; + } + + if (!params->imagename || !params->imagename[0]) { + fprintf(stderr, "Error: Image name must be set.\n"); + return -EINVAL; + } + + if (!params->datafile) { + fprintf(stderr, "Error: Data filename must be set.\n"); + return -EINVAL; + } + + return 0; +} + +static int spkgimage_verify_header(unsigned char *ptr, int size, + struct image_tool_params *param) +{ + struct spkg_file *file = (struct spkg_file *)ptr; + struct spkg_hdr *header = (struct spkg_hdr *)ptr; + char marker[4] = SPKG_HEADER_MARKER; + uint32_t payload_length; + uint32_t crc; + uint8_t *crc_buf; + + /* Check the marker bytes */ + if (memcmp(header->marker, marker, 4)) { + fprintf(stderr, "Error: invalid marker bytes\n"); + return -EINVAL; + } + + /* Check the CRC */ + crc = crc32(0, ptr, SPKG_HEADER_SIZE - SPKG_CRC_SIZE); + if (crc != header->crc) { + fprintf(stderr, "Error: invalid header CRC=\n"); + return -EINVAL; + } + + /* Check all copies of header are the same */ + for (int i = 1; i < SPKG_HEADER_COUNT; i++) { + if (memcmp(&header[0], &header[i], SPKG_HEADER_SIZE)) { + fprintf(stderr, "Error: header %d mismatch\n", i); + return -EINVAL; + } + } + + /* Check the payload CRC */ + payload_length = le32_to_cpu(header->payload_length) >> 8; + crc_buf = file->payload + payload_length - SPKG_CRC_SIZE; + crc = crc32(0, file->payload, payload_length - SPKG_CRC_SIZE); + if (crc_buf[0] != (crc & 0xff) || + crc_buf[1] != (crc >> 8 & 0xff) || + crc_buf[2] != (crc >> 16 & 0xff) || + crc_buf[3] != (crc >> 24 & 0xff)) { + fprintf(stderr, "Error: invalid payload CRC\n"); + return -EINVAL; + } + + return 0; +} + +static void spkgimage_print_header(const void *ptr, + struct image_tool_params *image) +{ + const struct spkg_hdr *h = ptr; + uint32_t offset = le32_to_cpu(h->execution_offset); + + printf("Image type\t: Renesas SPKG Image\n"); + printf("Marker\t\t: %c%c%c%c\n", + h->marker[0], h->marker[1], h->marker[2], h->marker[3]); + printf("Version\t\t: %d\n", h->version); + printf("ECC\t\t: "); + if (h->ecc & 0x20) + printf("Scheme %d, Block size %d, Strength %d\n", + h->ecc_scheme, (h->ecc >> 1) & 3, h->ecc_bytes); + else + printf("Not enabled\n"); + printf("Payload length\t: %d\n", le32_to_cpu(h->payload_length) >> 8); + printf("Load address\t: 0x%08x\n", le32_to_cpu(h->load_address)); + printf("Execution offset: 0x%08x (%s mode)\n", offset & ~1, + offset & 1 ? "THUMB" : "ARM"); + printf("Header checksum\t: 0x%08x\n", le32_to_cpu(h->crc)); +} + +/* + * This is the same as the macro version in include/kernel.h. + * However we cannot include that header, because for host tools, + * it ends up pulling in the host /usr/include/linux/kernel.h, + * which lacks the definition of roundup(). + */ +static inline uint32_t roundup(uint32_t x, uint32_t y) +{ + return ((x + y - 1) / y) * y; +} + +static int spkgimage_vrec_header(struct image_tool_params *params, + struct image_type_params *tparams) +{ + struct stat s; + struct spkg_file *out_buf; + + /* Parse the config file */ + if (spkgimage_parse_config_file(params->imagename)) { + fprintf(stderr, "Error parsing config file\n"); + exit(EXIT_FAILURE); + } + + /* Get size of input data file */ + if (stat(params->datafile, &s)) { + fprintf(stderr, "Could not stat data file: %s: %s\n", + params->datafile, strerror(errno)); + exit(EXIT_FAILURE); + } + params->orig_file_size = s.st_size; + + /* Determine size of resulting SPKG file */ + uint32_t header_len = SPKG_HEADER_SIZE * SPKG_HEADER_COUNT; + uint32_t payload_len = conf.blp_len + s.st_size + SPKG_CRC_SIZE; + uint32_t total_len = header_len + payload_len; + + /* Round up to next multiple of padding size */ + uint32_t padded_len = roundup(total_len, conf.padding); + + /* Number of padding bytes to add */ + conf.padding = padded_len - total_len; + + /* Fixup payload_len to include padding bytes */ + payload_len += conf.padding; + + /* Prepare the header */ + struct spkg_hdr header = { + .marker = SPKG_HEADER_MARKER, + .version = conf.version, + .ecc = (conf.ecc_enable << 5) | (conf.ecc_block_size << 1), + .ecc_scheme = conf.ecc_scheme, + .ecc_bytes = conf.ecc_bytes, + .payload_length = cpu_to_le32(payload_len << 8), + .load_address = cpu_to_le32(params->addr), + .execution_offset = cpu_to_le32(params->ep - params->addr), + }; + header.crc = crc32(0, (uint8_t *)&header, + sizeof(header) - SPKG_CRC_SIZE); + + /* The SPKG contains 8 copies of the header */ + out_buf = malloc(sizeof(struct spkg_file)); + if (!out_buf) { + fprintf(stderr, "Error: Data filename must be set.\n"); + return -ENOMEM; + } + tparams->hdr = out_buf; + tparams->header_size = sizeof(struct spkg_file); + + /* Fill the SPKG with the headers */ + for (int i = 0; i < SPKG_HEADER_COUNT; i++) + memcpy(&out_buf->header[i], &header, sizeof(header)); + + /* Extra bytes to allocate in the output file */ + return conf.blp_len + conf.padding + 4; +} + +static void spkgimage_set_header(void *ptr, struct stat *sbuf, int ifd, + struct image_tool_params *params) +{ + uint8_t *payload = ptr + SPKG_HEADER_SIZE * SPKG_HEADER_COUNT; + uint8_t *file_end = payload + conf.blp_len + params->orig_file_size; + uint8_t *crc_buf = file_end + conf.padding; + uint32_t crc; + + /* Make room for the Dummy BLp header */ + memmove(payload + conf.blp_len, payload, params->orig_file_size); + + /* Fill the SPKG with the Dummy BLp */ + memset(payload, 0x88, conf.blp_len); + + /* + * mkimage copy_file() pads the input file with zeros. + * Replace those zeros with flash friendly one bits. + * The original version skipped the first 4 bytes, + * probably an oversight, but for consistency we + * keep the same behaviour. + */ + if (conf.padding >= 4) + memset(file_end + 4, 0xff, conf.padding - 4); + + /* Add Payload CRC */ + crc = crc32(0, payload, crc_buf - payload); + crc_buf[0] = crc; + crc_buf[1] = crc >> 8; + crc_buf[2] = crc >> 16; + crc_buf[3] = crc >> 24; +} + +static int spkgimage_check_image_types(uint8_t type) +{ + return type == IH_TYPE_RENESAS_SPKG ? 0 : -EINVAL; +} + +/* + * spkgimage type parameter definition + */ +U_BOOT_IMAGE_TYPE( + spkgimage, + "Renesas SPKG Image", + 0, + NULL, + spkgimage_check_params, + spkgimage_verify_header, + spkgimage_print_header, + spkgimage_set_header, + NULL, + spkgimage_check_image_types, + NULL, + spkgimage_vrec_header +); diff --git a/tools/renesas_spkgimage.h b/tools/renesas_spkgimage.h new file mode 100644 index 0000000000..367e113de9 --- /dev/null +++ b/tools/renesas_spkgimage.h @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Renesas RZ/N1 Package Table format + * (C) 2015-2016 Renesas Electronics Europe, LTD + * All rights reserved. + * + * Converted to mkimage plug-in + * (C) Copyright 2022 Schneider Electric + */ + +#ifndef _SPKGIMAGE_H_ +#define _SPKGIMAGE_H_ + +#ifdef __GNUC__ +#define __packed __attribute((packed)) +#else +#define __packed +#endif + +#define SPKG_HEADER_MARKER {'R', 'Z', 'N', '1'} +#define SPKG_HEADER_SIZE 24 +#define SPKG_HEADER_COUNT 8 +#define SPKG_BLP_SIZE 264 +#define SPKG_CRC_SIZE 4 + +/** + * struct spkg_hdr - SPKG header + * @marker: magic pattern "RZN1" + * @version: header version (currently 1) + * @ecc: ECC enable and block size. + * @ecc_scheme: ECC algorithm selction + * @ecc_bytes: ECC bytes per block + * @payload_length: length of the payload (including CRC) + * @load_address: address in memory where payload should be loaded + * @execution_offset: offset from @load_address where execution starts + * @crc: 32-bit CRC of the above header fields + * + * SPKG header format is defined by Renesas. It is documented in the Reneasas + * RZ/N1 User Manual, Chapter 7.4 ("SPKG format"). + * + * The BootROM searches this header in order to find and validate the boot + * payload. It is therefore mandatory to wrap the payload in this header. + * + * The ECC-related fields @ecc @ecc_scheme @ecc_bytes are used only when + * booting from NAND flash, and they are only used while fetching the payload. + * These values are used to initialize the ECC controller. To avoid using + * non-portable bitfields, struct spkg_hdr uses uint8_t for these fields, so + * the user must shift the values into the correct spot. + * + * The payload will be loaded into memory at @payload_address. + * Execution then jumps to @payload_address + @execution_offset. + * The LSB of @execution_offset selects between ARM and Thumb mode, + * as per the usual ARM interworking convention. + */ +struct spkg_hdr { + uint8_t marker[4]; /* aka magic */ + uint8_t version; + uint8_t ecc; + uint8_t ecc_scheme; + uint8_t ecc_bytes; + uint32_t payload_length; /* only HIGHER 24 bits */ + uint32_t load_address; + uint32_t execution_offset; + uint32_t crc; /* of this header */ +} __packed; + +/** + * struct spkg_file - complete SPKG image + * + * A SPKG image consists of 8 identical copies of struct spkg_hdr, each one + * occupying 24 bytes, for a total of 192 bytes. + * + * This is followed by the payload (the u-boot binary), and a 32-bit CRC. + * + * Optionally, the payload can be being with security header ("BLp_header"). + * This feature is not currently supported in mkimage. + * + * The payload is typically padded with 0xFF bytes so as to bring the total + * image size to a multiple of the flash erase size (often 64kB). + */ +struct spkg_file { + struct spkg_hdr header[SPKG_HEADER_COUNT]; + uint8_t payload[0]; + /* then the CRC */ +} __packed; + +#endif