From patchwork Sun Sep 20 20:39:16 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Lamparter X-Patchwork-Id: 520042 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from arrakis.dune.hu (arrakis.dune.hu [78.24.191.176]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id BB94C14027C for ; Mon, 21 Sep 2015 06:40:54 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=googlemail.com header.i=@googlemail.com header.b=vSoJDoCn; dkim-atps=neutral Received: from arrakis.dune.hu (localhost [127.0.0.1]) by arrakis.dune.hu (Postfix) with ESMTP id AB13728BE8E; Sun, 20 Sep 2015 22:39:25 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on arrakis.dune.hu X-Spam-Level: X-Spam-Status: No, score=-1.5 required=5.0 tests=BAYES_00,FREEMAIL_FROM, T_DKIM_INVALID autolearn=unavailable version=3.3.2 Received: from arrakis.dune.hu (localhost [127.0.0.1]) by arrakis.dune.hu (Postfix) with ESMTP id E900328BE3D for ; Sun, 20 Sep 2015 22:39:13 +0200 (CEST) X-policyd-weight: using cached result; rate: -8.5 Received: from mail-wi0-f171.google.com (mail-wi0-f171.google.com [209.85.212.171]) by arrakis.dune.hu (Postfix) with ESMTPS for ; Sun, 20 Sep 2015 22:39:13 +0200 (CEST) Received: by wicge5 with SMTP id ge5so91538343wic.0 for ; Sun, 20 Sep 2015 13:40:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20120113; h=from:to:cc:subject:date:message-id:user-agent:mime-version :content-transfer-encoding:content-type; bh=e6lPAvUA8AETtb4CW9bOq5oC3SG5KF/w6LNdUhbnD0E=; b=vSoJDoCnKe1Y8aXAdK6PX2ef0picKBe3rdDERezhBpJBK4dHAqBLxzdNR+pokfegh6 N323/iC1T1b/X4uMRTZaI8klh1BtflpS4ciFB8e9WR0l3boJ6m2vI7o7+3QXapCavhDW h4f34+Pqtckmg+nW5I3NUe8QqGi1WcLFnf0wndaNN14gXRmAsgkM7GUrVbbbTyn7GtWW R/mS3GGFdHmq4RO5n3kqJnCi67KipBB6v9Thv1qYDB9BOuD2vlqQfbs0mbse+so8dGqc tm26ab8c+pN02JGeeDeJyZ03iXiP/TKN2bXx7O6VaE86N1R4tRYddoQKPgk25SUyqvq+ ZBPw== X-Received: by 10.180.99.232 with SMTP id et8mr9075715wib.80.1442781627250; Sun, 20 Sep 2015 13:40:27 -0700 (PDT) Received: from debian64.daheim (pD9F8891E.dip0.t-ipconnect.de. [217.248.137.30]) by smtp.googlemail.com with ESMTPSA id jc9sm9950763wic.6.2015.09.20.13.40.26 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 20 Sep 2015 13:40:26 -0700 (PDT) From: Thomas Hebb X-Google-Original-From: Thomas Hebb Received: from localhost.daheim ([127.0.0.1] helo=debian64.localnet) by debian64.daheim with esmtps (TLS1.0:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.86) (envelope-from ) id 1ZdlPN-0001Rt-Io; Sun, 20 Sep 2015 22:40:25 +0200 To: openwrt-devel@lists.openwrt.org Date: Sun, 20 Sep 2015 22:39:16 +0200 Message-ID: <3641367.eEQHx7583K@debian64> User-Agent: KMail/4.14.2 (Linux/4.3.0-rc1-wl+; KDE/4.14.10; x86_64; ; ) MIME-Version: 1.0 Cc: tommyhebb@gmail.com Subject: [OpenWrt-Devel] [PATCH v4 3/5] firmware-utils mkmerakifw: firmware generator for MR18 X-BeenThere: openwrt-devel@lists.openwrt.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: OpenWrt Development List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: openwrt-devel-bounces@lists.openwrt.org Sender: "openwrt-devel" From: Thomas Hebb This patch adds firmware generation tool for Cisco's MR18 Signed-off-by: Thomas Hebb --- tools/firmware-utils/Makefile | 1 + tools/firmware-utils/src/mkmerakifw.c | 263 ++++++++++++++++++++++++++++++++++ 2 files changed, 264 insertions(+) create mode 100644 tools/firmware-utils/src/mkmerakifw.c diff --git a/tools/firmware-utils/Makefile b/tools/firmware-utils/Makefile index bd69cb4..dc922b0 100644 --- a/tools/firmware-utils/Makefile +++ b/tools/firmware-utils/Makefile @@ -73,6 +73,7 @@ define Host/Compile $(call cc,mkrtn56uimg, -lz) $(call cc,dgn3500sum) $(call cc,edimax_fw_header, -Wall) + $(call cc,mkmerakifw sha1, -Wall) endef define Host/Install diff --git a/tools/firmware-utils/src/mkmerakifw.c b/tools/firmware-utils/src/mkmerakifw.c new file mode 100644 index 0000000..241bb33 --- /dev/null +++ b/tools/firmware-utils/src/mkmerakifw.c @@ -0,0 +1,263 @@ +/* + * Copyright (C) 2015 Thomas Hebb + * + * The format of the header this tool generates was first documented by + * Chris Blake in a shell script of the + * same purpose. I have created this reimplementation at his request. The + * original script can be found at: + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sha1.h" + +#define PADDING_BYTE 0xff + +#define HDR_LENGTH 0x00000400 +#define HDR_OFF_MAGIC1 0 +#define HDR_OFF_HDRLEN 4 +#define HDR_OFF_IMAGELEN 8 +#define HDR_OFF_CHECKSUM 12 +#define HDR_OFF_MAGIC2 32 +#define HDR_OFF_FILLER 36 +#define HDR_OFF_STATICHASH 40 + +struct board_info { + uint32_t magic; + uint32_t imagelen; + unsigned char statichash[20]; + char *id; + char *description; +}; + +/* + * Globals + */ +static char *progname; + +static char *board_id; +static const struct board_info *board; + +static const struct board_info boards[] = { + { + .id = "mr18", + .description = "Meraki MR18 Access Point", + .magic = 0x8e73ed8a, + .imagelen = 0x00800000, + .statichash = {0xda, 0x39, 0xa3, 0xee, 0x5e, + 0x6b, 0x4b, 0x0d, 0x32, 0x55, + 0xbf, 0xef, 0x95, 0x60, 0x18, + 0x90, 0xaf, 0xd8, 0x07, 0x09}, + }, { + /* terminating entry */ + } +}; + +/* + * Message macros + */ +#define ERR(fmt, ...) do { \ + fflush(0); \ + fprintf(stderr, "[%s] *** error: " fmt "\n", \ + progname, ## __VA_ARGS__); \ +} while (0) + +#define ERRS(fmt, ...) do { \ + int save = errno; \ + fflush(0); \ + fprintf(stderr, "[%s] *** error: " fmt "\n", \ + progname, ## __VA_ARGS__, strerror(save)); \ +} while (0) + +static const struct board_info *find_board(const char *id) +{ + const struct board_info *ret; + const struct board_info *board; + + ret = NULL; + for (board = boards; board->id != NULL; board++) { + if (strcasecmp(id, board->id) == 0) { + ret = board; + break; + } + } + + return ret; +} + +static void usage(int status) +{ + FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout; + const struct board_info *board; + + fprintf(stream, "Usage: %s [OPTIONS...]\n", progname); + fprintf(stream, +"\n" +"Options:\n" +" -B create image for the board specified with \n" +" -i read kernel image from the file \n" +" -o write output to the file \n" +" -s strip padding from the end of the image\n" +" -h show this screen\n" + ); + + fprintf(stream, "\nBoards:\n"); + for (board = boards; board->id != NULL; board++) + fprintf(stream, " %-16s%s\n", board->id, board->description); + + exit(status); +} + +void writel(unsigned char *buf, size_t offset, uint32_t value) +{ + value = htonl(value); + memcpy(buf + offset, &value, sizeof(uint32_t)); +} + +int main(int argc, char *argv[]) +{ + int ret = EXIT_FAILURE; + long klen; + size_t kspace; + unsigned char *kernel; + size_t buflen; + unsigned char *buf; + bool strip_padding = false; + char *ofname = NULL, *ifname = NULL; + FILE *out, *in; + + progname = basename(argv[0]); + + while (1) { + int c; + + c = getopt(argc, argv, "B:i:o:sh"); + if (c == -1) + break; + + switch (c) { + case 'B': + board_id = optarg; + break; + case 'i': + ifname = optarg; + break; + case 'o': + ofname = optarg; + break; + case 's': + strip_padding = true; + break; + case 'h': + usage(EXIT_SUCCESS); + break; + default: + usage(EXIT_FAILURE); + break; + } + } + + if (board_id == NULL) { + ERR("no board specified"); + goto err; + } + + board = find_board(board_id); + if (board == NULL) { + ERR("unknown board \"%s\"", board_id); + goto err; + } + + if (ifname == NULL) { + ERR("no input file specified"); + goto err; + } + + if (ofname == NULL) { + ERR("no output file specified"); + goto err; + } + + in = fopen(ifname, "r"); + if (in == NULL) { + ERRS("could not open \"%s\" for reading: %s", ifname); + goto err; + } + + buflen = board->imagelen; + kspace = buflen - HDR_LENGTH; + + /* Get kernel length */ + fseek(in, 0, SEEK_END); + klen = ftell(in); + rewind(in); + + if (klen > kspace) { + ERR("file \"%s\" is too big - max size: 0x%08lX\n", + ifname, kspace); + goto err_close_in; + } + + /* If requested, resize buffer to remove padding */ + if (strip_padding) + buflen = klen + HDR_LENGTH; + + /* Allocate and initialize buffer for final image */ + buf = malloc(buflen); + if (buf == NULL) { + ERRS("no memory for buffer: %s\n"); + goto err_close_in; + } + memset(buf, PADDING_BYTE, buflen); + + /* Load kernel */ + kernel = buf + HDR_LENGTH; + fread(kernel, klen, 1, in); + + /* Write magic values and filler */ + writel(buf, HDR_OFF_MAGIC1, board->magic); + writel(buf, HDR_OFF_MAGIC2, board->magic); + writel(buf, HDR_OFF_FILLER, 0); + + /* Write header and image length */ + writel(buf, HDR_OFF_HDRLEN, HDR_LENGTH); + writel(buf, HDR_OFF_IMAGELEN, klen); + + /* Write checksum and static hash */ + sha1_csum(kernel, klen, buf + HDR_OFF_CHECKSUM); + memcpy(buf + HDR_OFF_STATICHASH, board->statichash, 20); + + /* Save finished image */ + out = fopen(ofname, "w"); + if (out == NULL) { + ERRS("could not open \"%s\" for writing: %s", ofname); + goto err_free; + } + fwrite(buf, buflen, 1, out); + + ret = EXIT_SUCCESS; + + fclose(out); + +err_free: + free(buf); + +err_close_in: + fclose(in); + +err: + return ret; +}