6to4: fix interface error handling
[openwrt.git] / tools / firmware-utils / src / mkzynfw.c
old mode 100755 (executable)
new mode 100644 (file)
index fe4efca..36c176f
@@ -1,40 +1,29 @@
 /*
- *  $Id$
  *
- *  Copyright (C) 2007 OpenWrt.org
- *  Copyright (C) 2007 Gabor Juhos <juhosg@freemail.hu>
+ *  Copyright (C) 2007-2008 OpenWrt.org
+ *  Copyright (C) 2007-2008 Gabor Juhos <juhosg at openwrt.org>
  *
- *  This code was based on the information of the ZyXEL's firmware 
- *  image format written by Kolja Waschk, can be found at: 
+ *  This code was based on the information of the ZyXEL's firmware
+ *  image format written by Kolja Waschk, can be found at:
  *  http://www.ixo.de/info/zyxel_uclinux
  *
- *  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 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.
  *
- *  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., 51 Franklin Street, Fifth Floor,
- *  Boston, MA  02110-1301, USA.
  */
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdint.h>
 #include <string.h>
-#include <unistd.h>     /* for unlink() */
+#include <unistd.h>    /* for unlink() */
 #include <libgen.h>
-#include <getopt.h>     /* for getopt() */
+#include <getopt.h>    /* for getopt() */
 #include <stdarg.h>
 #include <errno.h>
 #include <sys/stat.h>
-#include <endian.h>     /* for __BYTE_ORDER */
+#include <endian.h>    /* for __BYTE_ORDER */
 #if defined(__CYGWIN__)
 #  include <byteswap.h>
 #endif
@@ -100,11 +89,13 @@ struct fw_mmap {
 struct board_info {
        char *name;             /* model name */
        char *desc;             /* description */
+       uint16_t vendor;        /* vendor id */
        uint16_t model;         /* model id */
        uint32_t flash_base;    /* flash base address */
        uint32_t flash_size;    /* board flash size */
        uint32_t code_start;    /* code start address */
-       uint32_t fw_offs;       /* offset of the firmware within the flash */
+       uint32_t romio_offs;    /* offset of the firmware within the flash */
+       uint32_t bootext_size;  /* maximum size of bootext block */
 };
 
 /*
@@ -127,24 +118,44 @@ int num_blocks = 0;
 #define AR7_FLASH_BASE         0xB0000000
 #define AR7_CODE_START         0x94008000
 
-#define BOARD(n, d, m, fb, fs, cs, fo) { \
-       .name = (n), .desc=(d), .model = (m), \
-       .flash_base = (fb), .flash_size = (fs)<<20, \
-       .code_start = (cs), .fw_offs = (fo) \
+#define ATHEROS_FLASH_BASE     0xBFC00000
+#define ATHEROS_CODE_START     0x80e00000
+
+#define AR71XX_FLASH_BASE      0xBFC00000
+#define AR71XX_CODE_START      0x81E00000
+
+#define BOARD(n, d, v, m, fb, fs, cs, fo) {            \
+       .name = (n), .desc=(d),                         \
+       .vendor = (v), .model = (m),                    \
+       .flash_base = (fb), .flash_size = (fs)<<20,     \
+       .code_start = (cs), .romio_offs = (fo),         \
+       .bootext_size = BOOTEXT_DEF_SIZE                \
        }
 
-#define ADMBOARD1(n, d, m, fs) BOARD(n, d, m, \
+#define ADMBOARD1(n, d, m, fs) BOARD(n, d, ZYNOS_VENDOR_ID_ZYXEL, m, \
        ADM5120_FLASH_BASE, fs, ADM5120_CODE_START, 0x8000)
 
-#define ADMBOARD2(n, d, m, fs) BOARD(n, d, m, \
+#define ADMBOARD2(n, d, m, fs) BOARD(n, d, ZYNOS_VENDOR_ID_ZYXEL, m, \
        ADM5120_FLASH_BASE, fs, ADM5120_CODE_START, 0x10000)
 
-#define AR7BOARD1(n, d, m, fs) BOARD(n, d, m, \
+#define AR7BOARD1(n, d, m, fs) BOARD(n, d, ZYNOS_VENDOR_ID_ZYXEL, m, \
        AR7_FLASH_BASE, fs, AR7_CODE_START, 0x8000)
 
+#define ATHEROSBOARD1(n, d, m, fs) BOARD(n, d, ZYNOS_VENDOR_ID_ZYXEL, m, \
+       ATHEROS_FLASH_BASE, fs, ATHEROS_CODE_START, 0x30000)
+
+#define AR71XXBOARD1(n, d, m, fs) {            \
+       .name = (n), .desc=(d),                         \
+       .vendor = (ZYNOS_VENDOR_ID_ZYXEL), .model = (m),                        \
+       .flash_base = (AR71XX_FLASH_BASE), .flash_size = (fs)<<20,      \
+       .code_start = (AR71XX_CODE_START), .romio_offs = (0x40000),             \
+       .bootext_size = 0x30000         \
+       }
+
+
 static struct board_info boards[] = {
-       /* 
-        * Infineon/ADMtek ADM5120 based boards 
+       /*
+        * Infineon/ADMtek ADM5120 based boards
         */
        ADMBOARD2("ES-2024A",   "ZyXEL ES-2024A", ZYNOS_MODEL_ES_2024A, 4),
        ADMBOARD2("ES-2024PWR", "ZyXEL ES-2024PWR", ZYNOS_MODEL_ES_2024PWR, 4),
@@ -165,8 +176,21 @@ static struct board_info boards[] = {
        ADMBOARD1("P-335Plus",  "ZyXEL Prestige 335Plus", ZYNOS_MODEL_P_335PLUS, 4),
        ADMBOARD1("P-335U",     "ZyXEL Prestige 335U", ZYNOS_MODEL_P_335U, 4),
        ADMBOARD1("P-335WT",    "ZyXEL Prestige 335WT", ZYNOS_MODEL_P_335WT, 4),
+
+       {
+               .name           = "P-2602HW-D1A",
+               .desc           = "ZyXEL P-2602HW-D1A",
+               .vendor         = ZYNOS_VENDOR_ID_ZYXEL,
+               .model          = ZYNOS_MODEL_P_2602HW_D1A,
+               .flash_base     = AR7_FLASH_BASE,
+               .flash_size     = 4*1024*1024,
+               .code_start     = 0x94008000,
+               .romio_offs     = 0x20000,
+               .bootext_size   = BOOTEXT_DEF_SIZE,
+       },
+
 #if 0
-       /* 
+       /*
         * Texas Instruments AR7 based boards
         */
        AR7BOARD1("P-660H-61",  "ZyXEL P-660H-61", ZYNOS_MODEL_P_660H_61, 2),
@@ -186,6 +210,28 @@ static struct board_info boards[] = {
        AR7BOARD1("P-660R-D1",  "ZyXEL P-660R-D1", ZYNOS_MODEL_P_660R_D1, 2),
        AR7BOARD1("P-660R-D3",  "ZyXEL P-660R-D3", ZYNOS_MODEL_P_660R_D3, 2),
 #endif
+       {
+               .name           = "O2SURF",
+               .desc           = "O2 DSL Surf & Phone",
+               .vendor         = ZYNOS_VENDOR_ID_O2,
+               .model          = ZYNOS_MODEL_O2SURF,
+               .flash_base     = AR7_FLASH_BASE,
+               .flash_size     = 8*1024*1024,
+               .code_start     = 0x94014000,
+               .romio_offs     = 0x40000,
+               .bootext_size   = BOOTEXT_DEF_SIZE,
+       },
+
+       /*
+:x
+        */
+       ATHEROSBOARD1("NBG-318S", "ZyXEL NBG-318S", ZYNOS_MODEL_NBG_318S, 4),
+
+       /*
+        * Atheros ar71xx based boards
+        */
+       AR71XXBOARD1("NBG-460N", "ZyXEL NBG-460N", ZYNOS_MODEL_NBG_460N, 4),
+
        {.name = NULL}
 };
 
@@ -194,18 +240,20 @@ static struct board_info boards[] = {
  */
 #define ERR(fmt, ...) do { \
        fflush(0); \
-       fprintf(stderr, "[%s] *** error: " fmt "\n", progname, ## __VA_ARGS__ ); \
+       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 ", %s\n", progname, ## __VA_ARGS__ \
-               , strerror(save)); \
+       fprintf(stderr, "[%s] *** error: " fmt ", %s\n", \
+                       progname, ## __VA_ARGS__, strerror(save)); \
 } while (0)
 
 #define WARN(fmt, ...) do { \
-       fprintf(stderr, "[%s] *** warning: " fmt "\n", progname, ## __VA_ARGS__ ); \
+       fprintf(stderr, "[%s] *** warning: " fmt "\n", \
+                       progname, ## __VA_ARGS__ ); \
 } while (0)
 
 #define DBG(lev, fmt, ...) do { \
@@ -259,7 +307,7 @@ str2u32(char *arg, uint32_t *val)
 {
        char *err = NULL;
        uint32_t t;
-       
+
        errno=0;
        t = strtoul(arg, &err, 0);
        if (errno || (err==arg) || ((err != NULL) && *err)) {
@@ -282,7 +330,7 @@ str2u16(char *arg, uint16_t *val)
        if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x10000)) {
                return -1;
        }
-       
+
        *val = t & 0xFFFF;
        return 0;
 }
@@ -298,7 +346,7 @@ str2u8(char *arg, uint8_t *val)
        if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x100)) {
                return -1;
        }
-       
+
        *val = t & 0xFF;
        return 0;
 }
@@ -310,7 +358,7 @@ str2sig(char *arg, uint32_t *sig)
                return -1;
 
        *sig = arg[0] | (arg[1] << 8) | (arg[2] << 16) | (arg[3] << 24);
-       
+
        return 0;
 }
 
@@ -483,7 +531,7 @@ write_out_padding(FILE *outfile, size_t len, uint8_t padc,
 
                if (write_out_data(outfile, buf, buflen, css))
                        return -1;
-                       
+
                len -= buflen;
        }
 
@@ -521,7 +569,7 @@ write_out_header(FILE *outfile, struct zyn_rombin_hdr *hdr)
        }
 
        /* setup temporary header fields */
-       memset(&t,0, sizeof(t));
+       memset(&t, 0, sizeof(t));
        t.addr = HOST_TO_BE32(hdr->addr);
        memcpy(&t.sig, ROMBIN_SIGNATURE, ROMBIN_SIG_LEN);
        t.type = hdr->type;
@@ -532,6 +580,15 @@ write_out_header(FILE *outfile, struct zyn_rombin_hdr *hdr)
        t.ccsum = HOST_TO_BE16(hdr->ccsum);
        t.mmap_addr = HOST_TO_BE32(hdr->mmap_addr);
 
+       DBG(2, "hdr.addr      = 0x%08x", hdr->addr);
+       DBG(2, "hdr.type      = 0x%02x", hdr->type);
+       DBG(2, "hdr.osize     = 0x%08x", hdr->osize);
+       DBG(2, "hdr.csize     = 0x%08x", hdr->csize);
+       DBG(2, "hdr.flags     = 0x%02x", hdr->flags);
+       DBG(2, "hdr.ocsum     = 0x%04x", hdr->ocsum);
+       DBG(2, "hdr.ccsum     = 0x%04x", hdr->ccsum);
+       DBG(2, "hdr.mmap_addr = 0x%08x", hdr->mmap_addr);
+
        return write_out_data(outfile, (uint8_t *)&t, sizeof(t), NULL);
 }
 
@@ -545,19 +602,21 @@ write_out_mmap(FILE *outfile, struct fw_mmap *mmap, struct csum_state *css)
        char *data;
        int res;
 
-       memset(buf,0,sizeof(buf));
+       memset(buf, 0, sizeof(buf));
 
        mh = (struct zyn_mmt_hdr *)buf;
 
        /* TODO: needs to recreate the memory map too? */
        mh->count=0;
-       
+
        /* Build user data section */
        data = buf+sizeof(*mh);
-       data += sprintf(data,"Model 1 %d", BE16_TO_HOST(board->model));
+       data += sprintf(data, "Vendor 1 %d", board->vendor);
+       *data++ = '\0';
+       data += sprintf(data, "Model 1 %d", BE16_TO_HOST(board->model));
        *data++ = '\0';
        /* TODO: make hardware version configurable? */
-       data += sprintf(data,"HwVerRange 2 %d %d", 0, 0);
+       data += sprintf(data, "HwVerRange 2 %d %d", 0, 0);
        *data++ = '\0';
 
        user_size = (uint8_t *)data - buf;
@@ -566,7 +625,7 @@ write_out_mmap(FILE *outfile, struct fw_mmap *mmap, struct csum_state *css)
        mh->csum = HOST_TO_BE16(csum_buf(buf+sizeof(*mh), user_size));
 
        res = write_out_data(outfile, buf, sizeof(buf), css);
-       
+
        return res;
 }
 
@@ -591,6 +650,35 @@ block_stat_file(struct fw_block *block)
 }
 
 
+int
+read_magic(uint16_t *magic)
+{
+       FILE *f;
+       int res;
+
+       errno = 0;
+       f = fopen(bootext_block->file_name,"r");
+       if (errno) {
+               ERRS("unable to open file: %s", bootext_block->file_name);
+               return -1;
+       }
+
+       errno = 0;
+       fread(magic, 2, 1, f);
+       if (errno != 0) {
+               ERRS("unable to read from file: %s", bootext_block->file_name);
+               res = -1;
+               goto err;
+       }
+
+       res = 0;
+
+err:
+       fclose(f);
+       return res;
+}
+
+
 int
 write_out_file(FILE *outfile, char *name, size_t len, struct csum_state *css)
 {
@@ -638,7 +726,7 @@ int
 write_out_block(FILE *outfile, struct fw_block *block, struct csum_state *css)
 {
        int res;
-       
+
        if (block == NULL)
                return 0;
 
@@ -648,7 +736,7 @@ write_out_block(FILE *outfile, struct fw_block *block, struct csum_state *css)
        if (block->file_size == 0)
                return 0;
 
-       res = write_out_file(outfile, block->file_name, 
+       res = write_out_file(outfile, block->file_name,
                        block->file_size, css);
        return res;
 }
@@ -664,17 +752,22 @@ write_out_image(FILE *outfile)
        int i, res;
        uint32_t offset;
        uint32_t padlen;
+       uint16_t csum;
+       uint16_t t;
 
        /* setup header fields */
+       memset(&hdr, 0, sizeof(hdr));
        hdr.addr = board->code_start;
        hdr.type = OBJECT_TYPE_BOOTEXT;
-       hdr.flags = ROMBIN_FLAG_40;
+       hdr.flags = ROMBIN_FLAG_OCSUM;
+
+       offset = board->romio_offs;
 
        res = write_out_header(outfile, &hdr);
        if (res)
                return res;
 
-       offset = sizeof(hdr);
+       offset += sizeof(hdr);
 
        csum_init(&css);
        res = write_out_block(outfile, bootext_block, &css);
@@ -682,42 +775,81 @@ write_out_image(FILE *outfile)
                return res;
 
        offset += bootext_block->file_size;
+       if (offset > (board->romio_offs + board->bootext_size)) {
+               ERR("bootext file '%s' is too big", bootext_block->file_name);
+               return -1;
+       }
 
-       padlen = ALIGN(offset,MMAP_ALIGN) - offset;
+       padlen = ALIGN(offset, MMAP_ALIGN) - offset;
        res = write_out_padding(outfile, padlen, 0xFF, &css);
        if (res)
                return res;
 
        offset += padlen;
 
-       mmap.addr = board->flash_base + board->fw_offs + offset;
-       hdr.mmap_addr = mmap.addr;
+       mmap.addr = board->flash_base + offset;
        res = write_out_mmap(outfile, &mmap, &css);
        if (res)
                return res;
 
        offset += MMAP_DATA_SIZE;
-       hdr.osize = offset - sizeof(hdr);
-       hdr.ocsum = csum_get(&css);
 
-       for (i=0; i < num_blocks; i++) {
+       if ((offset - board->romio_offs) < board->bootext_size) {
+               padlen = board->romio_offs + board->bootext_size - offset;
+               res = write_out_padding(outfile, padlen, 0xFF, &css);
+               if (res)
+                       return res;
+               offset += padlen;
+
+               DBG(2, "bootext end at %08x", offset);
+       }
+
+       for (i = 0; i < num_blocks; i++) {
                block = &blocks[i];
 
                if (block->type == BLOCK_TYPE_BOOTEXT)
                        continue;
 
-               padlen = ALIGN(offset,block->align) - offset;
-               res = write_out_padding(outfile, padlen, 0xFF, NULL);
+               padlen = ALIGN(offset, block->align) - offset;
+               res = write_out_padding(outfile, padlen, 0xFF, &css);
                if (res)
                        return res;
                offset += padlen;
 
-               res = write_out_block(outfile, block, NULL);
+               res = write_out_block(outfile, block, &css);
                if (res)
                        return res;
                offset += block->file_size;
        }
 
+       padlen = ALIGN(offset, 4) - offset;
+       res = write_out_padding(outfile, padlen, 0xFF, &css);
+       if (res)
+               return res;
+       offset += padlen;
+
+       csum = csum_get(&css);
+       hdr.mmap_addr = mmap.addr;
+       hdr.osize = 2;
+
+       res = read_magic(&hdr.ocsum);
+       if (res)
+               return res;
+       hdr.ocsum = BE16_TO_HOST(hdr.ocsum);
+
+       if (csum <= hdr.ocsum)
+               t = hdr.ocsum - csum;
+       else
+               t = hdr.ocsum - csum - 1;
+
+       DBG(2, "ocsum=%04x, csum=%04x, fix=%04x", hdr.ocsum, csum, t);
+
+       t = HOST_TO_BE16(t);
+       res = write_out_data(outfile, (uint8_t *)&t, 2, NULL);
+       if (res)
+               return res;
+
+
        res = write_out_header(outfile, &hdr);
 
        return res;
@@ -775,7 +907,7 @@ parse_opt_ofname(char ch, char *arg)
                return -1;
        }
 
-       if (required_arg(ch, arg)) 
+       if (required_arg(ch, arg))
                return -1;
 
        ofname = arg;
@@ -794,13 +926,13 @@ parse_opt_block(char ch, char *arg)
        struct fw_block *block;
        int i;
 
-       if ( num_blocks > MAX_NUM_BLOCKS ) {
+       if ( num_blocks >= MAX_NUM_BLOCKS ) {
                ERR("too many blocks specified");
                return -1;
        }
 
        block = &blocks[num_blocks++];
-       
+
        /* setup default field values */
        block->padc = 0xFF;
 
@@ -833,7 +965,7 @@ parse_opt_block(char ch, char *arg)
                }
        }
 
-       if(block->type == BLOCK_TYPE_BOOTEXT)
+       if (block->type == BLOCK_TYPE_BOOTEXT)
                return 0;
 
        p = argv[i++];
@@ -867,12 +999,13 @@ calc_block_offsets(int type, uint32_t *offset)
                        continue;
 
                next_offs = ALIGN(*offset, block->align);
-               avail = board->flash_size - board->fw_offs - next_offs;
-               if (next_offs + block->file_size > avail) {
+               avail = board->flash_size - next_offs;
+               if (block->file_size > avail) {
                        ERR("file %s is too big, offset = %u, size=%u,"
-                               " align = %u", block->file_name, 
-                               (unsigned)next_offs, 
-                               (unsigned)block->file_size, 
+                               " avail = %u, align = %u", block->file_name,
+                               (unsigned)next_offs,
+                               (unsigned)block->file_size,
+                               (unsigned)avail,
                                (unsigned)block->align);
                        res = -1;
                        break;
@@ -881,7 +1014,7 @@ calc_block_offsets(int type, uint32_t *offset)
                block->padlen = next_offs - *offset;
                *offset += block->file_size;
        }
-       
+
        return res;
 }
 
@@ -901,7 +1034,7 @@ process_blocks(void)
                        return res;
        }
 
-       offset = board->fw_offs + bootext_block->file_size;
+       offset = board->romio_offs + bootext_block->file_size;
        res = calc_block_offsets(BLOCK_TYPE_RAW, &offset);
 
        return res;
@@ -916,13 +1049,13 @@ main(int argc, char *argv[])
        int res = EXIT_FAILURE;
 
        FILE *outfile;
-       
+
        progname=basename(argv[0]);
 
        opterr = 0;  /* could not print standard getopt error messages */
        while ( 1 ) {
                optinvalid = 0;
-               
+
                c = getopt(argc, argv, "b:B:ho:r:v");
                if (c == -1)
                        break;
@@ -968,7 +1101,6 @@ main(int argc, char *argv[])
                ERR("invalid option: %s", argv[optind]);
                goto out;
        }
-       
 
        if (process_blocks() != 0) {
                goto out;
This page took 0.038969 seconds and 4 git commands to generate.