From patchwork Fri Oct 15 04:08:10 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Holland X-Patchwork-Id: 1541276 X-Patchwork-Delegate: andre.przywara@arm.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=sholland.org header.i=@sholland.org header.a=rsa-sha256 header.s=fm1 header.b=LQ08OXP3; dkim=pass (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.a=rsa-sha256 header.s=fm1 header.b=FgxZesEa; dkim-atps=neutral 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=) 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) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4HVt6s5zz8z9ssD for ; Fri, 15 Oct 2021 15:08:36 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 8BE9F83818; Fri, 15 Oct 2021 06:08:25 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=sholland.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=sholland.org header.i=@sholland.org header.b="LQ08OXP3"; dkim=pass (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.b="FgxZesEa"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id A829683820; Fri, 15 Oct 2021 06:08:21 +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,RCVD_IN_MSPIKE_H2,SPF_HELO_PASS, SPF_PASS autolearn=ham autolearn_force=no version=3.4.2 Received: from out3-smtp.messagingengine.com (out3-smtp.messagingengine.com [66.111.4.27]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 0EB7683816 for ; Fri, 15 Oct 2021 06:08:15 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=sholland.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=samuel@sholland.org Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.nyi.internal (Postfix) with ESMTP id 524885C00F8; Fri, 15 Oct 2021 00:08:14 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute3.internal (MEProxy); Fri, 15 Oct 2021 00:08:14 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sholland.org; h= from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=fm1; bh=rwDje9pb0vmOd OH6e+m9XV2jiO2RZpgZ+fRnrPGsKG4=; b=LQ08OXP3Mzid7QrDc2kQQx7LGzZA5 kY2UmYPJmGZQ1t0pphGJz1Vt9Z8N+uXBCfg2tYM33xd+2tydGkVgmfRCexTdkJr9 v69W7M84BCa/50S8DSdIMTZygZVBrB73mUWTXV44y2cw8a521ntu0/tQLEsbVSqq TvhD4UCLDFk5QG7M7c7nletvtedR7hrxilTMKDeUnAm7yCFTXxCzjDlYmB79w2Y1 +ROPKmd2d8xZCEiA2xMb5dbR6nuj+IOvu6gDjK0X763uOMb38FLndCgx1pthIU1E md2WNT115sH2mjhMaOsGQXe1g7eMPFYHVyAns26ROSJHqWaMFPHW2g5+Q== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:date:from :in-reply-to:message-id:mime-version:references:subject:to :x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm1; bh=rwDje9pb0vmOdOH6e+m9XV2jiO2RZpgZ+fRnrPGsKG4=; b=FgxZesEa yErr8cIVbZUJbPCUIwIQr4MAO5k9Xlt2j801IUNQSucibegUkracm+3KprzSWzop utoztogSRNpcg7YgJB/VL84OQFwh8ZgT+6UdHCt7ut+krpb7G06j/Qs++mNgEqdl KM9sasrGQVLvuyDVlc7XHzPEkMA++o6A1XwP8SuZn1vIKVGeKglMCuHlqTG+QtDE 5eHIapfakkyjKKPRWYqHPZ8qQhcbAwTV3ERkBV3yWkYvSe5QuhQZI6+vXDTvkiBO 1U2IpTsfNTX+xLBHKlqXlFb5sacQ3dTjV1Beumpkcr1mH8gBYSnUXh0cPE2F/1LN CwYLscCdI866Dw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvtddrvddufedgjeegucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpefurghmuhgv lhcujfholhhlrghnugcuoehsrghmuhgvlhesshhhohhllhgrnhgurdhorhhgqeenucggtf frrghtthgvrhhnpeduhfejfedvhffgfeehtefghfeiiefgfeehgfdvvdevfeegjeehjedv gfejheeuieenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhroh hmpehsrghmuhgvlhesshhhohhllhgrnhgurdhorhhg X-ME-Proxy: Received: by mail.messagingengine.com (Postfix) with ESMTPA; Fri, 15 Oct 2021 00:08:13 -0400 (EDT) From: Samuel Holland To: u-boot@lists.denx.de, Jagan Teki , Andre Przywara Cc: Samuel Holland Subject: [RFC PATCH 1/1] tools: mkimage: Add Allwinner TOC1 support Date: Thu, 14 Oct 2021 23:08:10 -0500 Message-Id: <20211015040811.56856-2-samuel@sholland.org> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20211015040811.56856-1-samuel@sholland.org> References: <20211015040811.56856-1-samuel@sholland.org> MIME-Version: 1.0 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.103.2 at phobos.denx.de X-Virus-Status: Clean TOC1 is an container format used by Allwinner's boot0 that can hold multiple images. It supports encryption and signatures, but that functionality is not implemented, only the basic "non-secure" subset. A config file is used to provide the list of data files to include. Its path is passed as the argument to "-d". It contains sections of the following form: [name] file = /path/to/file addr = 0x12345678 Specific well-known names, such as "dtb", "opensbi", and "u-boot", are used by the bootloader to distinguish the items inside the image. Signed-off-by: Samuel Holland --- common/image.c | 1 + include/image.h | 1 + include/sunxi_image.h | 26 ++++ tools/Makefile | 1 + tools/sunxi_toc1.c | 318 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 347 insertions(+) create mode 100644 tools/sunxi_toc1.c diff --git a/common/image.c b/common/image.c index d15b47ebbe..a2b925c0c5 100644 --- a/common/image.c +++ b/common/image.c @@ -186,6 +186,7 @@ static const table_entry_t uimage_type[] = { { IH_TYPE_COPRO, "copro", "Coprocessor Image"}, { IH_TYPE_SUNXI_EGON, "sunxi_egon", "Allwinner eGON Boot Image" }, { IH_TYPE_SUNXI_TOC0, "sunxi_toc0", "Allwinner TOC0 Boot Image" }, + { IH_TYPE_SUNXI_TOC1, "sunxi_toc1", "Allwinner TOC1 Boot Image" }, { -1, "", "", }, }; diff --git a/include/image.h b/include/image.h index 1547246ec8..eb165f34da 100644 --- a/include/image.h +++ b/include/image.h @@ -228,6 +228,7 @@ enum { IH_TYPE_COPRO, /* Coprocessor Image for remoteproc*/ IH_TYPE_SUNXI_EGON, /* Allwinner eGON Boot Image */ IH_TYPE_SUNXI_TOC0, /* Allwinner TOC0 Boot Image */ + IH_TYPE_SUNXI_TOC1, /* Allwinner TOC1 Boot Image */ IH_TYPE_COUNT, /* Number of image types */ }; diff --git a/include/sunxi_image.h b/include/sunxi_image.h index 379ca9196e..98f381bbe6 100644 --- a/include/sunxi_image.h +++ b/include/sunxi_image.h @@ -116,4 +116,30 @@ struct __packed toc0_item_info { #define TOC0_ITEM_INFO_NAME_KEY 0x00010303 #define TOC0_ITEM_INFO_END "IIE;" +struct __packed toc1_main_info { + uint8_t name[16]; + __le32 magic; + __le32 checksum; + __le32 serial; + __le32 status; + __le32 num_items; + __le32 length; + __le32 major_version; + __le32 minor_version; + __le32 reserved[3]; + uint8_t end[4]; +}; + +struct __packed toc1_item_info { + uint8_t name[64]; + __le32 offset; + __le32 length; + __le32 encryption; + __le32 type; + __le32 load_addr; + __le32 index; + __le32 reserved[69]; + uint8_t end[4]; +}; + #endif diff --git a/tools/Makefile b/tools/Makefile index e2aeb097aa..8b42f3ff6f 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -132,6 +132,7 @@ dumpimage-mkimage-objs := aisimage.o \ $(ROCKCHIP_OBS) \ socfpgaimage.o \ sunxi_egon.o \ + sunxi_toc1.o \ lib/crc16.o \ lib/hash-checksum.o \ lib/sha1.o \ diff --git a/tools/sunxi_toc1.c b/tools/sunxi_toc1.c new file mode 100644 index 0000000000..7dd3f5d52a --- /dev/null +++ b/tools/sunxi_toc1.c @@ -0,0 +1,318 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2018 Arm Ltd. + * (C) Copyright 2020-2021 Samuel Holland + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include "imagetool.h" +#include "mkimage.h" + +#define SECTOR_SIZE 512 + +struct item_desc { + const char *name; + const char *file; + unsigned long addr; + long length; +}; + +static uint32_t toc1_header_length(uint32_t num_items) +{ + return ALIGN(sizeof(struct toc1_main_info) + + sizeof(struct toc1_item_info) * num_items, SECTOR_SIZE); +} + +static int toc1_parse_cfg(const char *file, struct item_desc **desc, + uint32_t *main_length, uint32_t *num_items) +{ + struct item_desc *descs = NULL; + int ret = EXIT_FAILURE; + FILE *cfg, *fp = NULL; + uint32_t ndescs = 0; + char *line = NULL; + size_t len = 0; + + *desc = NULL; + *main_length = 0; + *num_items = 0; + + cfg = fopen(file, "r"); + if (!cfg) + return ret; + + while (getline(&line, &len, cfg) > 0) { + char *end, *s; + + if (line[0] == '[') { + s = line + 1; + end = strchr(s, ']'); + if (!end || end[1] != '\n') + goto err; + end[0] = '\0'; + + ndescs++; + descs = reallocarray(descs, ndescs, sizeof(*descs)); + if (!descs) + goto err; + + descs[ndescs - 1].name = strdup(s); + } else if (line[0] != '#' && line[0] != '\n') { + s = strchr(line, '='); + if (!s) + goto err; + while ((++s)[0] == ' ') + ; + end = strchr(s, '\n'); + if (!end) + goto err; + end[0] = '\0'; + + if (!strncmp(line, "file", strlen("file"))) { + fp = fopen(s, "rb"); + if (!fp) + goto err; + if (fseek(fp, 0, SEEK_END) < 0) + goto err; + descs[ndescs - 1].file = strdup(s); + descs[ndescs - 1].length = ftell(fp); + *main_length += ALIGN(descs[ndescs - 1].length, + SECTOR_SIZE); + fclose(fp); + fp = NULL; + } else if (!strncmp(line, "addr", strlen("addr"))) { + descs[ndescs - 1].addr = strtoul(s, NULL, 0); + } else { + goto err; + } + } + } + + *desc = descs; + *main_length += toc1_header_length(ndescs); + *num_items = ndescs; + + ret = EXIT_SUCCESS; + +err: + if (fp) + fclose(fp); + if (ret) + free(descs); + free(line); + fclose(cfg); + + return ret; +} + +static int toc1_create(uint8_t *buf, uint32_t len, + const struct item_desc *desc, uint32_t num_items) +{ + struct toc1_main_info *main = (void *)buf; + struct toc1_item_info *item = (void *)(main + 1); + uint32_t item_offset, item_length; + uint32_t *buf32 = (void *)buf; + int ret = EXIT_FAILURE; + uint32_t checksum = 0; + FILE *fp = NULL; + int i; + + /* Create the main TOC1 header. */ + main->magic = cpu_to_le32(TOC0_MAIN_INFO_MAGIC); + main->checksum = cpu_to_le32(BROM_STAMP_VALUE); + main->num_items = cpu_to_le32(num_items); + memcpy(main->end, TOC0_MAIN_INFO_END, sizeof(main->end)); + + item_offset = 0; + item_length = toc1_header_length(num_items); + + for (i = 0; i < num_items; ++i, ++item, ++desc) { + item_offset = item_offset + item_length; + item_length = desc->length; + + /* Create the item header. */ + memcpy(item->name, desc->name, + strnlen(desc->name, sizeof(item->name))); + item->offset = cpu_to_le32(item_offset); + item->length = cpu_to_le32(item_length); + item->load_addr = cpu_to_le32(desc->addr); + memcpy(item->end, TOC0_ITEM_INFO_END, sizeof(item->end)); + + /* Read in the data. */ + fp = fopen(desc->file, "rb"); + if (!fp) + goto err; + if (!fread(buf + item_offset, item_length, 1, fp)) + goto err; + fclose(fp); + fp = NULL; + + /* Pad the sectors with 0xff to be flash-friendly. */ + item_offset = item_offset + item_length; + item_length = ALIGN(item_offset, SECTOR_SIZE) - item_offset; + memset(buf + item_offset, 0xff, item_length); + } + + /* Fill in the total padded file length. */ + item_offset = item_offset + item_length; + main->length = cpu_to_le32(item_offset); + + /* Verify enough space was provided when creating the image. */ + assert(len >= item_offset); + + /* Calculate the checksum. Yes, it's that simple. */ + for (i = 0; i < item_offset / 4; ++i) + checksum += le32_to_cpu(buf32[i]); + main->checksum = cpu_to_le32(checksum); + + ret = EXIT_SUCCESS; + +err: + if (fp) + fclose(fp); + + return ret; +} + +static int toc1_verify(const uint8_t *buf, uint32_t len) +{ + const struct toc1_main_info *main = (void *)buf; + const struct toc1_item_info *item = (void *)(main + 1); + uint32_t checksum = BROM_STAMP_VALUE; + uint32_t main_length, num_items; + uint32_t *buf32 = (void *)buf; + int ret = EXIT_FAILURE; + int i; + + num_items = le32_to_cpu(main->num_items); + main_length = le32_to_cpu(main->length); + + if (len < main_length || main_length < toc1_header_length(num_items)) + goto err; + + /* Verify the main header. */ + if (le32_to_cpu(main->magic) != TOC0_MAIN_INFO_MAGIC) + goto err; + /* Verify the checksum without modifying the buffer. */ + for (i = 0; i < main_length / 4; ++i) + checksum += le32_to_cpu(buf32[i]); + if (checksum != 2 * le32_to_cpu(main->checksum)) + goto err; + /* The length must be at least 512 byte aligned. */ + if (main_length % SECTOR_SIZE) + goto err; + if (memcmp(main->end, TOC0_MAIN_INFO_END, sizeof(main->end))) + goto err; + + /* Verify each item header. */ + for (i = 0; i < num_items; ++i, ++item) + if (memcmp(item->end, TOC0_ITEM_INFO_END, sizeof(item->end))) + goto err; + + ret = EXIT_SUCCESS; + +err: + return ret; +} + +static int toc1_check_params(struct image_tool_params *params) +{ + if (!params->dflag) + return -EINVAL; + + return 0; +} + +static int toc1_verify_header(unsigned char *buf, int image_size, + struct image_tool_params *params) +{ + return toc1_verify(buf, image_size); +} + +static void toc1_print_header(const void *buf) +{ + const struct toc1_main_info *main = buf; + const struct toc1_item_info *item = (void *)(main + 1); + uint32_t head_length, main_length, num_items; + uint32_t item_offset, item_length, item_addr; + int i; + + num_items = le32_to_cpu(main->num_items); + head_length = sizeof(*main) + num_items * sizeof(*item); + main_length = le32_to_cpu(main->length); + + printf("Allwinner TOC1 Image\n" + "Size: %d bytes\n" + "Contents: %d items\n" + " 00000000:%08x Headers\n", + main_length, num_items, head_length); + + for (i = 0; i < num_items; ++i, ++item) { + item_offset = le32_to_cpu(item->offset); + item_length = le32_to_cpu(item->length); + item_addr = le32_to_cpu(item->load_addr); + + printf(" %08x:%08x => %08x %s\n", + item_offset, item_length, item_addr, item->name); + } +} + +static void toc1_set_header(void *buf, struct stat *sbuf, int ifd, + struct image_tool_params *params) +{ + /* Image is already written below. */ +} + +static int toc1_check_image_type(uint8_t type) +{ + return type == IH_TYPE_SUNXI_TOC1 ? 0 : 1; +} + +static int toc1_vrec_header(struct image_tool_params *params, + struct image_type_params *tparams) +{ + uint32_t main_length, num_items; + struct item_desc *desc; + int ret; + + /* This "header" contains the entire image. */ + params->skipcpy = 1; + + ret = toc1_parse_cfg(params->datafile, &desc, &main_length, &num_items); + if (ret) + exit(ret); + + tparams->header_size = main_length; + tparams->hdr = calloc(tparams->header_size, 1); + if (!tparams->hdr) + exit(ret); + + ret = toc1_create(tparams->hdr, tparams->header_size, desc, num_items); + if (ret) + exit(ret); + + return 0; +} + +U_BOOT_IMAGE_TYPE( + sunxi_toc1, + "Allwinner TOC1 Boot Image support", + 0, + NULL, + toc1_check_params, + toc1_verify_header, + toc1_print_header, + toc1_set_header, + NULL, + toc1_check_image_type, + NULL, + toc1_vrec_header +);