From patchwork Fri Sep 30 07:31:20 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Wagner X-Patchwork-Id: 117047 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 9F6EDB6F92 for ; Fri, 30 Sep 2011 17:30:36 +1000 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 5F24428485; Fri, 30 Sep 2011 09:30:34 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id ggw9VAia9smg; Fri, 30 Sep 2011 09:30:33 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 58EB2284D9; Fri, 30 Sep 2011 09:30:32 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 15F5F284D9 for ; Fri, 30 Sep 2011 09:30:29 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id rKE4QoXYhs6R for ; Fri, 30 Sep 2011 09:30:27 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail.free-electrons.com (mail.free-electrons.com [88.190.12.23]) by theia.denx.de (Postfix) with ESMTP id 5A9E528485 for ; Fri, 30 Sep 2011 09:30:25 +0200 (CEST) Received: by mail.free-electrons.com (Postfix, from userid 106) id D6835143; Fri, 30 Sep 2011 09:30:23 +0200 (CEST) Received: from localhost.localdomain (col31-4-88-188-83-94.fbx.proxad.net [88.188.83.94]) by mail.free-electrons.com (Postfix) with ESMTPSA id 3DCDE187; Fri, 30 Sep 2011 09:30:13 +0200 (CEST) From: David Wagner To: u-boot@lists.denx.de Date: Fri, 30 Sep 2011 09:31:20 +0200 Message-Id: <1317367880-13986-1-git-send-email-david.wagner@free-electrons.com> X-Mailer: git-send-email 1.7.0.4 In-Reply-To: <1312555798-29542-1-git-send-email-david.wagner@free-electrons.com> References: <1312555798-29542-1-git-send-email-david.wagner@free-electrons.com> Subject: [U-Boot] [PATCHv8] new tool mkenvimage: generates an env image from an arbitrary config file X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.9 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de This tool takes a key=value configuration file (same as would a `printenv' show) and generates the corresponding environment image, ready to be flashed. use case: flash the environment with an external tool Signed-off-by: David Wagner Acked-by; Mike Frysinger Tested-by: Thomas Petazzoni --- change since v7: add a missing header (stdlib.h) tools/Makefile | 5 + tools/mkenvimage.c | 271 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 276 insertions(+), 0 deletions(-) create mode 100644 tools/mkenvimage.c diff --git a/tools/Makefile b/tools/Makefile index fc741d3..da7caf0 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -66,6 +66,7 @@ BIN_FILES-$(CONFIG_BUILD_ENVCRC) += envcrc$(SFX) BIN_FILES-$(CONFIG_CMD_NET) += gen_eth_addr$(SFX) BIN_FILES-$(CONFIG_CMD_LOADS) += img2srec$(SFX) BIN_FILES-$(CONFIG_XWAY_SWAP_BYTES) += xway-swap-bytes$(SFX) +BIN_FILES-y += mkenvimage$(SFX) BIN_FILES-y += mkimage$(SFX) BIN_FILES-$(CONFIG_NETCONSOLE) += ncb$(SFX) BIN_FILES-$(CONFIG_SHA1_CHECK_UB_IMG) += ubsha1$(SFX) @@ -89,6 +90,7 @@ OBJ_FILES-$(CONFIG_XWAY_SWAP_BYTES) += xway-swap-bytes.o NOPED_OBJ_FILES-y += kwbimage.o NOPED_OBJ_FILES-y += imximage.o NOPED_OBJ_FILES-y += omapimage.o +NOPED_OBJ_FILES-y += mkenvimage.o NOPED_OBJ_FILES-y += mkimage.o OBJ_FILES-$(CONFIG_NETCONSOLE) += ncb.o NOPED_OBJ_FILES-y += os_support.o @@ -184,6 +186,9 @@ $(obj)xway-swap-bytes$(SFX): $(obj)xway-swap-bytes.o $(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^ $(HOSTSTRIP) $@ +$(obj)mkenvimage$(SFX): $(obj)crc32.o $(obj)mkenvimage.o + $(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^ + $(obj)mkimage$(SFX): $(obj)crc32.o \ $(obj)default_image.o \ $(obj)fit_image.o \ diff --git a/tools/mkenvimage.c b/tools/mkenvimage.c new file mode 100644 index 0000000..ad2c8d3 --- /dev/null +++ b/tools/mkenvimage.c @@ -0,0 +1,271 @@ +/* + * (C) Copyright 2011 Free Electrons + * David Wagner + * + * Inspired from envcrc.c: + * (C) Copyright 2001 + * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define CRC_SIZE sizeof(uint32_t) + +static void usage(const char *exec_name) +{ + fprintf(stderr, "%s [-h] [-r] [-b] [-p ] " + "-s -o \n" + "\n" + "This tool takes a key=value input file (same as would a " + "`printenv' show) and generates the corresponding environment " + "image, ready to be flashed.\n" + "\n" + "\tThe input file is in format:\n" + "\t\tkey1=value1\n" + "\t\tkey2=value2\n" + "\t\t...\n" + "\t-r : the environment has multiple copies in flash\n" + "\t-b : the target is big endian (default is little endian)\n" + "\t-p : fill the image with bytes instead of " + "0xff bytes\n" + "\n" + "If the input file is \"-\", data is read from standard input\n", + exec_name); +} + +int main(int argc, char **argv) +{ + uint32_t crc, targetendian_crc; + const char *txt_filename = NULL, *bin_filename = NULL; + int txt_fd, bin_fd; + unsigned char *dataptr, *envptr; + unsigned char *filebuf = NULL; + unsigned int filesize = 0, envsize = 0, datasize = 0; + int bigendian = 0; + int redundant = 0; + unsigned char padbyte = 0xff; + + int option; + int ret = EXIT_SUCCESS; + + struct stat txt_file_stat; + + int fp, ep; + + /* Parse the cmdline */ + while ((option = getopt(argc, argv, "s:o:rbp:h")) != -1) { + switch (option) { + case 's': + datasize = strtol(optarg, NULL, 0); + break; + case 'o': + bin_filename = strdup(optarg); + if (!bin_filename) { + fprintf(stderr, "Can't strdup() the output " + "filename\n"); + return EXIT_FAILURE; + } + break; + case 'r': + redundant = 1; + break; + case 'b': + bigendian = 1; + break; + case 'p': + padbyte = strtol(optarg, NULL, 0); + break; + case 'h': + usage(argv[0]); + return EXIT_SUCCESS; + default: + fprintf(stderr, "Wrong option -%c\n", option); + usage(argv[0]); + return EXIT_FAILURE; + } + } + + /* Check datasize and allocate the data */ + if (datasize == 0) { + fprintf(stderr, + "Please specify the size of the envrionnment " + "partition.\n"); + usage(argv[0]); + return EXIT_FAILURE; + } + + dataptr = malloc(datasize * sizeof(*dataptr)); + if (!dataptr) { + fprintf(stderr, "Can't alloc dataptr.\n"); + return EXIT_FAILURE; + } + + /* + * envptr points to the beginning of the actual environment (after the + * crc and possible `redundant' bit + */ + envsize = datasize - (CRC_SIZE + redundant); + envptr = dataptr + CRC_SIZE + redundant; + + /* Pad the environment with the padding byte */ + memset(envptr, padbyte, envsize); + + /* Open the input file ... */ + if (optind >= argc) { + fprintf(stderr, "Please specify an input filename\n"); + return EXIT_FAILURE; + } + + txt_filename = argv[optind]; + if (strcmp(txt_filename, "-") == 0) { + int readbytes = 0; + int readlen = sizeof(*envptr) * 2048; + txt_fd = STDIN_FILENO; + + do { + filebuf = realloc(filebuf, readlen); + readbytes = read(txt_fd, filebuf + filesize, readlen); + filesize += readbytes; + } while (readbytes == readlen); + + } else { + txt_fd = open(txt_filename, O_RDONLY); + if (txt_fd == -1) { + fprintf(stderr, "Can't open \"%s\": %s\n", + txt_filename, strerror(errno)); + return EXIT_FAILURE; + } + /* ... and check it */ + ret = fstat(txt_fd, &txt_file_stat); + if (ret == -1) { + fprintf(stderr, "Can't stat() on \"%s\": " + "%s\n", txt_filename, strerror(errno)); + return EXIT_FAILURE; + } + + filesize = txt_file_stat.st_size; + /* Read the raw input file and transform it */ + filebuf = malloc(sizeof(*envptr) * filesize); + ret = read(txt_fd, filebuf, sizeof(*envptr) * filesize); + if (ret != sizeof(*envptr) * filesize) { + fprintf(stderr, "Can't read the whole input file\n"); + return EXIT_FAILURE; + } + ret = close(txt_fd); + } + /* + * The right test to do is "=>" (not ">") because of the additionnal + * ending \0. See below. + */ + if (filesize >= envsize) { + fprintf(stderr, "The input file is larger than the " + "envrionnment partition size\n"); + return EXIT_FAILURE; + } + + /* Replace newlines separating variables with \0 */ + for (fp = 0, ep = 0 ; fp < filesize ; fp++) { + if (filebuf[fp] == '\n') { + if (fp == 0) { + /* + * Newline at the beggining of the file ? + * Ignore it. + */ + continue; + } else if (filebuf[fp-1] == '\\') { + /* + * Embedded newline in a variable. + * + * The backslash was added to the envptr ; + * rewind and replace it with a newline + */ + ep--; + envptr[ep++] = '\n'; + } else { + /* End of a variable */ + envptr[ep++] = '\0'; + } + } else if (filebuf[fp] == '#') { + if (fp != 0 && filebuf[fp-1] == '\n') { + /* This line is a comment, let's skip it */ + while (fp < txt_file_stat.st_size && fp++ && + filebuf[fp] != '\n'); + } else { + envptr[ep++] = filebuf[fp]; + } + } else { + envptr[ep++] = filebuf[fp]; + } + } + /* + * Make sure there is a final '\0' + * And do it again on the next byte to mark the end of the environment. + */ + if (envptr[ep-1] != '\0') { + envptr[ep++] = '\0'; + /* + * The text file doesn't have an ending newline. We need to + * check the env size again to make sure we have room for two \0 + */ + if (ep >= envsize) { + fprintf(stderr, "The environment file is too large for " + "the target environment storage\n"); + return EXIT_FAILURE; + } + envptr[ep] = '\0'; + } else { + envptr[ep] = '\0'; + } + + /* Computes the CRC and put it at the beginning of the data */ + crc = crc32(0, envptr, envsize); + targetendian_crc = bigendian ? cpu_to_be32(crc) : cpu_to_le32(crc); + + memcpy(dataptr, &targetendian_crc, sizeof(uint32_t)); + + bin_fd = creat(bin_filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + if (bin_fd == -1) { + fprintf(stderr, "Can't open output file \"%s\": %s\n", + bin_filename, strerror(errno)); + return EXIT_FAILURE; + } + + if (write(bin_fd, dataptr, sizeof(*dataptr) * datasize) != + sizeof(*dataptr) * datasize) { + fprintf(stderr, "write() failed: %s\n", strerror(errno)); + return EXIT_FAILURE; + } + + ret = close(bin_fd); + + return ret; +}