From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id BD820C19F2D for ; Tue, 9 Aug 2022 13:02:11 +0000 (UTC) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 426F584A3D; Tue, 9 Aug 2022 15:01:45 +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="s3/ph24a"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id AA91384A40; Tue, 9 Aug 2022 15:01:13 +0200 (CEST) Received: from mail-io1-xd33.google.com (mail-io1-xd33.google.com [IPv6:2607:f8b0:4864:20::d33]) (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 4F5B484A3E for ; Tue, 9 Aug 2022 15:00:40 +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-io1-xd33.google.com with SMTP id d187so2714899iof.4 for ; Tue, 09 Aug 2022 06:00:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc; bh=iiM0N/+2FEg/5dBHEhSFBsCNRl8qPvEy1Ft4+1GvSjg=; b=s3/ph24aGl1zvd/1UWwbDYzEpFc6sjDLXNTRrHhD58RDtxTOA9jAt4nrJ6c/GH9A8p 5iNlorsWGf3ySaDm64X9GXRlGxhpSmQsmK6XXxd2IaxJ4wMwfEGtOOyywzww7PJQwmeM 5dEhI07uNTwu06XqOIuM/y1OpAS+qI47ciitXsNPJidWcP6vUriEazwTOg9TkVMY+N4Y sBOSAaMRV8RFao5ts/nO8hZpZR7IJtwMsoFgUdIPVynC1H4pRn2ijdGp5J5hjbm2NL3j gJt/ITsWebu6B1USR3JfHyutrbUuY5GZ1dBvB7Nu6MYPZSevapDO/DYV6WNxNPBHZ23k l5tA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc; bh=iiM0N/+2FEg/5dBHEhSFBsCNRl8qPvEy1Ft4+1GvSjg=; b=nWFnFETStHXirPilbJt2G7qdcm4ldAlShyf6neBGKI+AeM6VHXB8apNTORl1DbeBZL ozuCH7Ia51pBrA/olnnrQG8DToxXIOXfrp3KD047c/CFU7/aAiO0fPEfWuGlPBwMhcxq 3RM4oHNejh/yjJBGJOPEyiBtlZDQ0CNxTaNx9VRNJZTfSwEGpXKXdeVvFmIwA/R9zBtS Tz5584ihkZyu4Ms/3sMcfAITMKYtmZpV8MElYjcCsUCWreq4vmH9OYcG7qqvrIsEeHPz tb5cKIzVyDa589TiszLYa5cR3V0I4kUZIMS0jSFYQZGYUcNbgvGCAeLS/5nhrmm9FJjU p2Gw== X-Gm-Message-State: ACgBeo2V75m3mAZX0Gp48PCA1a2kCDjs4JGBhypF8p103yfLJLztA+Kb Tu5KH94ZrSpmOAMmf4xrE3w9TnS2U6RIGF2p X-Google-Smtp-Source: AA6agR6uhUhTb5+zNGtdiWZe5AqpBP1tiQuIfzaLjpOPC/+Swkwd2/EgZ8Veh8Jp7b3pAmJ65b5ObQ== X-Received: by 2002:a05:6638:4809:b0:342:6dbe:6f85 with SMTP id cp9-20020a056638480900b003426dbe6f85mr10677185jab.78.1660050039730; Tue, 09 Aug 2022 06:00:39 -0700 (PDT) Received: from maple.netwinder.org (rfs.netwinder.org. [206.248.184.2]) by smtp.gmail.com with ESMTPSA id g12-20020a056e021a2c00b002dea1e18a94sm1022197ile.47.2022.08.09.06.00.38 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 09 Aug 2022 06:00:39 -0700 (PDT) From: Ralph Siemsen To: u-boot@lists.denx.de Cc: Michel Pollet , Ralph Siemsen , AKASHI Takahiro , Andre Przywara , Heiko Thiery , =?UTF-8?q?Pali=20Roh=C3=A1r?= , Samuel Holland , Simon Glass , Stefan Roese Subject: [RFC PATCH v1 9/9] tools: Add tool to create Renesas SPKG images Date: Tue, 9 Aug 2022 08:59:59 -0400 Message-Id: <20220809125959.217333-10-ralph.siemsen@linaro.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220809125959.217333-1-ralph.siemsen@linaro.org> References: <20220809125959.217333-1-ralph.siemsen@linaro.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 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: Michel Pollet Renesas RZ/N1 devices contain BootROM code that loads a custom SPKG image from QSPI, NAND or USB DFU. This tool converts a binary image into an SPKG. SPKGs can optionally be signed, however this tool does not currently support signed SPKGs. Signed-off-by: Michel Pollet Signed-off-by: Ralph Siemsen --- This tool could possibly be incorporated into mkimage / imagetools. However it is unclear how to handle the extra commandline parameters (NAND ECC settings, etc). So for now it is stand-alone tool. tools/Makefile | 2 + tools/spkg_header.h | 49 +++++++ tools/spkg_utility.c | 306 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 357 insertions(+) create mode 100644 tools/spkg_header.h create mode 100644 tools/spkg_utility.c diff --git a/tools/Makefile b/tools/Makefile index 005e7362a3..c5dc92a13f 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -68,6 +68,8 @@ HOSTCFLAGS_img2srec.o := -pedantic hostprogs-$(CONFIG_XWAY_SWAP_BYTES) += xway-swap-bytes HOSTCFLAGS_xway-swap-bytes.o := -pedantic +hostprogs-$(CONFIG_ARCH_RZN1) += spkg_utility + hostprogs-y += mkenvimage mkenvimage-objs := mkenvimage.o os_support.o lib/crc32.o diff --git a/tools/spkg_header.h b/tools/spkg_header.h new file mode 100644 index 0000000000..029930cbf8 --- /dev/null +++ b/tools/spkg_header.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Renesas RZ/N1 Linux tools: Package Table format + * (C) 2015-2016 Renesas Electronics Europe, LTD + * All rights reserved. + */ + +#ifndef _SKGT_HEADER_H_ +#define _SKGT_HEADER_H_ + +#define SPKG_HEADER_SIGNATURE (('R'<<0)|('Z'<<8)|('N'<<16)|('1'<<24)) +#define SPKG_HEADER_COUNT 8 +#define SPKG_BLP_SIZE 264 + +#define SPKG_HEADER_SIZE 24 +#define SPKG_HEADER_SIZE_ALL (SPKG_HEADER_SIZE * SPKG_HEADER_COUNT) +#define SPKG_HEADER_CRC_SIZE 4 + +/* Index into SPKG */ +#define INDEX_BLP_START SPKG_HEADER_SIZE_ALL +#define INDEX_IMAGE_START (INDEX_BLP_START + SPKG_BLP_SIZE) + +/* Flags, not supported by ROM code, only used for U-Boot SPL */ +enum { + SPKG_CODE_NONSEC_BIT = 0, + SPKG_CODE_HYP_BIT, +}; + +/* SPKG header */ +struct spkg_hdr { + uint32_t signature; + 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 */ +} __attribute__((packed)); + +struct spkg_file { + struct spkg_hdr header[SPKG_HEADER_COUNT]; + uint8_t blp[SPKG_BLP_SIZE]; + uint8_t data[0]; + /* then the CRC */ +} __attribute__((packed)); + +#endif diff --git a/tools/spkg_utility.c b/tools/spkg_utility.c new file mode 100644 index 0000000000..235e23e0f1 --- /dev/null +++ b/tools/spkg_utility.c @@ -0,0 +1,306 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * This is a utility to create a SPKG file. + * It packages the binary code into the SPKG. + * + * (C) Copyright 2016 Renesas Electronics Europe Ltd + */ + +#include +#include +#include +#include +#include + +#include "spkg_header.h" + +/* For Windows compatibility */ +#ifndef htole32 +#if __BYTE_ORDER == __LITTLE_ENDIAN + #define htole32(x) (x) +#elif __BYTE_ORDER == __BIG_ENDIAN + #define htole32(x) __builtin_bswap32((uint32_t)(x)) +#endif +#endif + +#define MAX_PATH 300 + +// Note: Order of bit fields is not used, this is purely just holding the SPKG information. +struct spkg_header { + char input[MAX_PATH]; + char output[MAX_PATH + 5]; + unsigned int version:4; + unsigned int ecc_enable:1; + unsigned int ecc_block_size:2; + unsigned int ecc_scheme:3; + unsigned int ecc_bytes:8; + unsigned int dummy_blp_length:10; + unsigned int payload_length:24; + unsigned int spl_nonsec:1; + unsigned int spl_hyp:1; + unsigned int load_address; + unsigned int execution_offset; + uint32_t padding; +}; + +struct spkg_header g_header = { + .version = 1, + .padding = 256, +}; + +int verbose; + +static uint32_t crc32(const uint8_t *message, uint32_t l) +{ + uint32_t crc = ~0; + + while (l--) { + uint32_t byte = *message++; // Get next byte. + + crc = crc ^ byte; + for (int8_t j = 7; j >= 0; j--) { // Do eight times. + uint32_t mask = -(crc & 1); + + crc = (crc >> 1) ^ (0xEDB88320 & mask); + } + } + return ~crc; +} + +static int spkg_write(struct spkg_header *h, FILE *file_input, FILE *file_SPKG) +{ + int i; + uint32_t length_inputfile; + uint32_t length_read; + uint32_t length_written; + uint32_t length_total; + uint32_t padding = 0; + uint8_t *data, *start; + uint32_t crc; + + /* Calculate length of input file */ + fseek(file_input, 0, SEEK_END); // seek to end of file + length_inputfile = ftell(file_input); // get current file pointer + fseek(file_input, 0, SEEK_SET); // seek back to beginning of file + + /* Set payload_length field. */ + h->payload_length = + length_inputfile + h->dummy_blp_length + SPKG_HEADER_CRC_SIZE; + + /* Calculate total length of SPKG */ + length_total = + (SPKG_HEADER_SIZE * SPKG_HEADER_COUNT) + h->dummy_blp_length + + length_inputfile + SPKG_HEADER_CRC_SIZE; + padding = h->padding ? h->padding - (length_total % h->padding) : 0; + length_total += padding; + /* Padding needs to be part of the payload size, otherwise the ROM DFU + * refuses to accept the extra bytes and return and error. + */ + h->payload_length += padding; + + printf("Addr: 0x%08x ", h->load_address); + printf("In: %8d ", length_inputfile); + printf("padding to %3dKB: %6d ", h->padding / 1024, padding); + printf("Total: 0x%08x ", length_total); + printf("%s\n", h->output); + + /* Create and zero array for SPKG */ + data = malloc(length_total); + memset(data, 0, length_total); + + /* Fill the SPKG with the headers */ + { + struct spkg_hdr head = { + .signature = SPKG_HEADER_SIGNATURE, + .version = h->version, + .ecc = (h->ecc_enable << 5) | (h->ecc_block_size << 1), + .ecc_scheme = h->ecc_scheme, + .ecc_bytes = h->ecc_bytes, + .payload_length = htole32((h->payload_length << 8) | + (h->spl_nonsec << SPKG_CODE_NONSEC_BIT) | + (h->spl_hyp << SPKG_CODE_HYP_BIT)), + .load_address = htole32(h->load_address), + .execution_offset = htole32(h->execution_offset), + }; + + head.crc = crc32((uint8_t *)&head, sizeof(head) - SPKG_HEADER_CRC_SIZE); + for (i = 0; i < SPKG_HEADER_COUNT; i++) + ((struct spkg_hdr *)data)[i] = head; + } + + start = data + INDEX_BLP_START; + + /* Fill the SPKG with the Dummy BLp */ + for (i = 0; i < h->dummy_blp_length; i++) + *start++ = 0x88; + /* Fill the SPKG with the data from the code file. */ + length_read = + fread(start, sizeof(char), length_inputfile, + file_input); + + if (length_read != length_inputfile) { + fprintf(stderr, "Error reading %s: ferror=%d, feof=%d\n", + h->input, ferror(file_input), feof(file_input)); + + return -1; + } + /* fill padding with flash friendly one bits */ + memset(start + length_inputfile + SPKG_HEADER_CRC_SIZE, 0xff, padding); + + /* Add Payload CRC */ + crc = crc32(&data[INDEX_BLP_START], + h->dummy_blp_length + length_inputfile + padding); + + start += length_inputfile + padding; + start[0] = crc; + start[1] = crc >> 8; + start[2] = crc >> 16; + start[3] = crc >> 24; + + /* Write the completed SKPG to file */ + length_written = fwrite(data, sizeof(char), length_total, file_SPKG); + + if (length_written != length_total) { + fprintf(stderr, "Error writing to %s\n", h->output); + return -1; + } + + return 0; +} + +const char *usage = + "%s\n" + " [-i ] : input file\n" + " [-o ] : output file\n" + " [--load_address ] : code load address\n" + " [--execution_offset ] : starting offset\n" + " [--nand_ecc_enable] : Enable nand ECC\n" + " [--nand_ecc_blksize ] : Block size code\n" + " 0=256 bytes, 1=512 bytes, 2=1024 bytes\n" + " [--nand_ecc_scheme ] : ECC scheme code\n" + " 0=BCH2 1=BCH4 2=BCH8 3=BCH16 4=BCH24 5=BCH32\n" + " [--add_dummy_blp] : Add a passthru BLP\n" + " [--spl_nonsec] : Code package run in NONSEC\n" + " [--spl_hyp] : Code package run in HYP (and NONSEC)\n" + " [--padding [K|M]] : Pass SPKG to size block\n" + ; + +static int spkg_parse_option(struct spkg_header *h, const char *name, + const char *sz, uint32_t value) +{ +// printf("%s %s=%s %08x\n", __func__, name, sz, value); + if (!strcmp("file_input", name) || !strcmp("i", name)) { + strncpy(h->input, sz, sizeof(h->input) - 1); + h->input[sizeof(h->input) - 1] = 0; + } else if (!strcmp("file_output", name) || !strcmp("o", name)) { + strncpy(h->output, sz, sizeof(h->output) - 1); + h->output[sizeof(h->output) - 1] = 0; + } else if (!strcmp("version", name)) { + h->version = value; + } else if (!strcmp("load_address", name)) { + h->load_address = value; + } else if (!strcmp("execution_offset", name)) { + h->execution_offset = value; + } else if (!strcmp("nand_ecc_enable", name)) { + h->ecc_enable = value; + } else if (!strcmp("nand_ecc_blksize", name)) { + h->ecc_block_size = value; + } else if (!strcmp("nand_ecc_scheme", name)) { + h->ecc_scheme = value; + } else if (!strcmp("nand_bytes_per_ecc_block", name)) { + h->ecc_bytes = value; + } else if (!strcmp("add_dummy_blp", name)) { + h->dummy_blp_length = value ? SPKG_BLP_SIZE : 0; + } else if (!strcmp("spl_nonsec", name)) { + h->spl_nonsec = !!value; + } else if (!strcmp("spl_hyp", name)) { + h->spl_hyp = !!value; + } else if (!strcmp("help", name) || !strcmp("h", name)) { + fprintf(stderr, usage, "spkg_utility"); + exit(0); + } else if (!strcmp("padding", name) && sz && value) { + if (strchr(sz, 'K')) + h->padding = value * 1024; + else if (strchr(sz, 'M')) + h->padding = value * 1024 * 1024; + else + h->padding = value; + } else { + return -1; + } + + return 0; +} + +int main(int argc, char *argv[]) +{ + FILE *file_SPKG = NULL; + FILE *file_input = NULL; + int result = -1; + + for (int i = 1; i < argc; i++) { + unsigned long value = 0; + char *name = argv[i]; + char *sz = NULL; + + if (!name || name[0] != '-') { + fprintf(stderr, "%s invalid argument '%s'\n", + argv[0], argv[i]); + return -1; + } + name++; + if (name[0] == '-') + name++; + + if (i < argc - 1 && argv[i + 1][0] != '-') + sz = argv[++i]; + + if (sz) { + if (!sscanf(sz, "0x%lx", &value)) + sscanf(sz, "%lu", &value); + } else { + value = 1; + } + if (spkg_parse_option(&g_header, name, sz, value)) { + fprintf(stderr, "%s Error invalid '%s'\n", + argv[0], argv[i]); + return -1; + } + } + + if (!g_header.input[0]) { + fprintf(stderr, usage, argv[0]); + exit(1); + } + if (!g_header.output[0]) + snprintf(g_header.output, sizeof(g_header.output), + "%s.spkg", g_header.input); + if (verbose) + printf("%s -> %s\n", g_header.input, g_header.output); + + /*NOTE: Using binary mode as this seems necessary if running in Windows */ + file_SPKG = fopen(g_header.output, "wb"); + file_input = fopen(g_header.input, "rb"); + + if (!file_SPKG) + perror(g_header.output); + if (!file_input) + perror(g_header.input); + + if (file_input && file_SPKG) + result = spkg_write(&g_header, file_input, file_SPKG); + + if (file_SPKG) + fclose(file_SPKG); + if (file_input) + fclose(file_input); + + if (result >= 0) { + if (verbose) + printf("%s created\n", g_header.output); + } else { + fprintf(stderr, "ERROR creating %s\n", g_header.output); + } + + return result; +} -- 2.25.1