From 305d012ea65ef9bdb5d36bcaf5aa7d1a76e621bd Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 2 Apr 2007 17:10:48 +0000 Subject: [PATCH] Add ADM5120 based edimax image generation utilities SVN-Revision: 6840 --- tools/firmware-utils/Makefile | 1 + tools/firmware-utils/src/csysimg.h | 78 ++ tools/firmware-utils/src/mkcsysimg.c | 1111 ++++++++++++++++++++++++++ 3 files changed, 1190 insertions(+) create mode 100644 tools/firmware-utils/src/csysimg.h create mode 100644 tools/firmware-utils/src/mkcsysimg.c diff --git a/tools/firmware-utils/Makefile b/tools/firmware-utils/Makefile index c9d9bae1e1..2518e34f65 100644 --- a/tools/firmware-utils/Makefile +++ b/tools/firmware-utils/Makefile @@ -28,6 +28,7 @@ define Build/Compile $(call cc,srec2bin) $(call cc,mksyshdr) $(call cc,mkmylofw) + $(call cc,mkcsysimg) endef define Build/Install diff --git a/tools/firmware-utils/src/csysimg.h b/tools/firmware-utils/src/csysimg.h new file mode 100644 index 0000000000..c3d5767439 --- /dev/null +++ b/tools/firmware-utils/src/csysimg.h @@ -0,0 +1,78 @@ +/* + * $Id$ + * + * Copyright (C) 2007 Gabor Juhos + * + * This program was based on the code found in various Linux + * source tarballs released by Edimax for it's devices. + * Original author: David Hsu + * + * 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., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#define SIG_LEN 4 + +#define ADM_CODE_ADDR 0x80500000 +#define ADM_WEBP_ADDR 0x10000 +#define ADM_WEBP_SIZE 0x10000 +#define ADM_BOOT_SIZE 0x8000 +#define ADM_CONF_SIZE 0x8000 +#define ADM_BOOT_SIG "\x00\x60\x1A\x40" + + +/* + * Generic signatures + */ +#define SIG_CSYS "CSYS" +#define SIG_CONF "HS\x00\x00" +#define SIG_BOOT_RTL "\x00\x00\x40\x21" + +/* + * Web page signatures + */ +#define SIG_BR6104K "WB4K" +#define SIG_BR6104KP "WBKP" +#define SIG_BR6104IPC "WBIP" +#define SIG_BR6114WG SIG_BR6104IPC +#define SIG_BR6524K "2-K-" +#define SIG_BR6524KP "2-KP" /* FIXME: valid? */ +#define SIG_BR6524WG "2-WG" /* FIXME: valid? */ +#define SIG_BR6524WP "2-WP" /* FIXME: valid? */ +#define SIG_BR6541K "4--K" +#define SIG_BR6541KP "4-KP" /* FIXME: valid? */ +#define SIG_BR6541WP "4-WP" /* FIXME: valid? */ +#define SIG_EW7207APg "EWAS" +#define SIG_PS1205UWg "4000" +#define SIG_PS3205U "5010" +#define SIG_PS3205UWg "5011" + +#define SIG_H2BR4 SIG_BR6524K +#define SIG_H2WR54G SIG_BR6524WG + +#define SIG_XRT401D SIG_BR6104K +#define SIG_XRT402D SIG_BR6524K + +/* + * CSYS image file header + */ +struct csys_header { + unsigned char sig[SIG_LEN]; + uint32_t addr; + uint32_t size; +}; + + + diff --git a/tools/firmware-utils/src/mkcsysimg.c b/tools/firmware-utils/src/mkcsysimg.c new file mode 100644 index 0000000000..073e8be69f --- /dev/null +++ b/tools/firmware-utils/src/mkcsysimg.c @@ -0,0 +1,1111 @@ +/* + * $Id$ + * + * Copyright (C) 2007 Gabor Juhos + * + * This program was based on the code found in various Linux + * source tarballs released by Edimax for it's devices. + * Original author: David Hsu + * + * 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., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include /* for unlink() */ +#include +#include /* for getopt() */ +#include +#include +#include +#include /* for __BYTE_ORDER */ +#if defined(__CYGWIN__) +# include +#endif + +#include "csysimg.h" + +#if (__BYTE_ORDER == __LITTLE_ENDIAN) +# define HOST_TO_LE16(x) (x) +# define HOST_TO_LE32(x) (x) +# define LE16_TO_HOST(x) (x) +# define LE32_TO_HOST(x) (x) +#else +# define HOST_TO_LE16(x) bswap_16(x) +# define HOST_TO_LE32(x) bswap_32(x) +# define LE16_TO_HOST(x) bswap_16(x) +# define LE32_TO_HOST(x) bswap_32(x) +#endif + +#define ALIGN(x,y) ((x)+((y)-1)) & ~((y)-1) + +#define MAX_NUM_BLOCKS 8 +#define MAX_ARG_COUNT 32 +#define MAX_ARG_LEN 1024 +#define FILE_BUF_LEN (16*1024) +#define CSYS_PADC 0xFF + +#define BLOCK_TYPE_BOOT 0 +#define BLOCK_TYPE_CONF 1 +#define BLOCK_TYPE_WEBP 2 +#define BLOCK_TYPE_CODE 3 +#define BLOCK_TYPE_XTRA 4 + + +struct csum_state{ + int size; + uint16_t val; + uint16_t tmp; + int odd; +}; + + +struct csys_block { + int type; /* type of the block */ + + int need_file; + char *file_name; /* name of the file */ + uint32_t file_size; /* length of the file */ + + uint32_t size; + int size_set; + uint8_t padc; + + uint32_t size_hdr; + uint32_t size_csum; + uint32_t size_avail; + + unsigned char sig[SIG_LEN]; + uint32_t addr; + int addr_set; + struct csum_state *css; +}; + + +struct board_info { + char *model; + char *name; + uint32_t flash_size; + + char sig_boot[SIG_LEN]; + char sig_conf[SIG_LEN]; + char sig_webp[SIG_LEN]; + + uint32_t boot_size; + uint32_t conf_size; + uint32_t webp_size; + uint32_t webp_size_max; + uint32_t code_size; + + uint32_t addr_code; + uint32_t addr_webp; +}; + +#define BOARD(m, n, f, sigb, sigw, bs, cs, ws, ac, aw) {\ + .model = m, .name = n, .flash_size = f<<20, \ + .sig_boot = sigb, .sig_conf = SIG_CONF, .sig_webp = sigw, \ + .boot_size = bs, .conf_size = cs, \ + .webp_size = ws, .webp_size_max = 3*0x10000, \ + .addr_code = ac, .addr_webp = aw \ + } + +#define BOARD_ADM(m,n,f, sigw) BOARD(m,n,f, ADM_BOOT_SIG, sigw, \ + ADM_BOOT_SIZE, ADM_CONF_SIZE, ADM_WEBP_SIZE, \ + ADM_CODE_ADDR, ADM_WEBP_ADDR) + + +/* + * Globals + */ +char *progname; +char *ofname = NULL; +int verblevel = 0; +int size_check = 1; + +struct board_info *board = NULL; + +struct csys_block *boot_block = NULL; +struct csys_block *conf_block = NULL; +struct csys_block *webp_block = NULL; +struct csys_block *code_block = NULL; + +struct csys_block blocks[MAX_NUM_BLOCKS]; +int num_blocks = 0; + + +static struct board_info boards[] = { + /* The original Edimax products */ + BOARD_ADM("BR-6104K", "Edimax BR-6104K", 2, SIG_BR6104K), + BOARD_ADM("BR-6104KP", "Edimax BR-6104KP", 2, SIG_BR6104KP), + BOARD_ADM("BR-6114WG", "Edimax BR-6114WG", 2, SIG_BR6114WG), + BOARD_ADM("BR-6524K", "Edimax BR-6524K", 2, SIG_BR6524K), + BOARD_ADM("BR-6524KP", "Edimax BR-6524KP", 2, SIG_BR6524KP), + BOARD_ADM("BR-6524WG", "Edimax BR-6524WG", 4, SIG_BR6524WG), + BOARD_ADM("BR-6524WP", "Edimax BR-6524WP", 4, SIG_BR6524WP), + BOARD_ADM("BR-6541K", "Edimax BR-6541K", 2, SIG_BR6541K), + BOARD_ADM("BR-6541KP", "Edimax BR-6541K", 2, SIG_BR6541KP), + BOARD_ADM("BR-6541WP", "Edimax BR-6541WP", 4, SIG_BR6541WP), + BOARD_ADM("EW-7207APg", "Edimax EW-7207APg", 2, SIG_EW7207APg), + BOARD_ADM("PS-1205UWg", "Edimax PS-1205UWg", 2, SIG_PS1205UWg), + BOARD_ADM("PS-3205U", "Edimax PS-3205U", 2, SIG_PS3205U), + BOARD_ADM("PS-3205UWg", "Edimax PS-3205UWg", 2, SIG_PS3205UWg), + + /* Hawking products */ + BOARD_ADM("H2BR4", "Hawking H2BR4", 2, SIG_H2BR4), + BOARD_ADM("H2WR54G", "Hawking H2WR54G", 4, SIG_H2WR54G), + + /* Planet products */ + BOARD_ADM("XRT-401D", "Planet XRT-401D", 2, SIG_XRT401D), + BOARD_ADM("XRT-402D", "Planet XRT-402D", 2, SIG_XRT402D), + + {.model = NULL} +}; + +/* + * Helper routines + */ +void +errmsgv(int syserr, const char *fmt, va_list arg_ptr) +{ + int save = errno; + + fflush(0); + fprintf(stderr, "%s: error, ", progname); + vfprintf(stderr, fmt, arg_ptr); + if (syserr != 0) { + fprintf(stderr, " (%s)", strerror(save)); + } + fprintf(stderr, "\n"); +} + +void +errmsg(int syserr, const char *fmt, ...) +{ + va_list arg_ptr; + va_start(arg_ptr, fmt); + errmsgv(syserr, fmt, arg_ptr); + va_end(arg_ptr); +} + +void +dbgmsg(int level, const char *fmt, ...) +{ + va_list arg_ptr; + if (verblevel >= level) { + fflush(0); + va_start(arg_ptr, fmt); + vfprintf(stderr, fmt, arg_ptr); + fprintf(stderr, "\n"); + va_end(arg_ptr); + } +} + + +void +usage(int status) +{ + FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout; + 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" +" valid values:\n" + ); + for (board = boards; board->model != NULL; board++){ + fprintf(stream, +" %-12s: %s\n", + board->model, board->name); + }; + fprintf(stream, +" -d disable check for available space\n" +" add boot code to the image\n" +" -b [:[:]]\n" +" add boot code to the image\n" +" -c [:[:]]\n" +" add configuration settings to the image\n" +" -r :[][:[:]]\n" +" add runtime code to the image" +" -w [:[][:[:]]]\n" +" add webpages to the image" +" -x [:[:]]\n" +" add extra data at the end of the image\n" +" -h show this screen\n" +"Parameters:\n" +" write output to the file \n" + ); + + exit(status); +} + + +/* + * argument parsing + */ +int +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)) { + return -1; + } + + *val = t; + return 0; +} + + +int +str2u16(char *arg, uint16_t *val) +{ + char *err = NULL; + uint32_t t; + + errno=0; + t = strtoul(arg, &err, 0); + if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x10000)) { + return -1; + } + + *val = t & 0xFFFF; + return 0; +} + +int +str2u8(char *arg, uint8_t *val) +{ + char *err = NULL; + uint32_t t; + + errno=0; + t = strtoul(arg, &err, 0); + if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x100)) { + return -1; + } + + *val = t & 0xFF; + return 0; +} + +int +str2sig(char *arg, uint32_t *sig) +{ + if (strlen(arg) != 4) + return -1; + + *sig = arg[0] | (arg[1] << 8) | (arg[2] << 16) | (arg[3] << 24); + + return 0; +} + + +int +parse_arg(char *arg, char *buf, char *argv[]) +{ + int res = 0; + size_t argl; + char *tok; + char **ap = &buf; + int i; + + memset(argv, 0, MAX_ARG_COUNT * sizeof(void *)); + + if ((arg == NULL)) { + /* no arguments */ + return 0; + } + + argl = strlen(arg); + if (argl == 0) { + /* no arguments */ + return 0; + } + + if (argl >= MAX_ARG_LEN) { + /* argument is too long */ + argl = MAX_ARG_LEN-1; + } + + memcpy(buf, arg, argl); + buf[argl] = '\0'; + + for (i = 0; i < MAX_ARG_COUNT; i++) { + tok = strsep(ap, ":"); + if (tok == NULL) { + break; + } +#if 0 + else if (tok[0] == '\0') { + break; + } +#endif + argv[i] = tok; + res++; + } + + return res; +} + + +int +required_arg(char c, char *arg) +{ + if (arg == NULL || *arg != '-') + return 0; + + errmsg(0,"option -%c requires an argument\n", c); + return -1; +} + + +int +is_empty_arg(char *arg) +{ + int ret = 1; + if (arg != NULL) { + if (*arg) ret = 0; + }; + return ret; +} + + +void +csum8_update(uint8_t *p, uint32_t len, struct csum_state *css) +{ + for ( ; len > 0; len --) { + css->val += *p++; + } +} + + +uint16_t +csum8_get(struct csum_state *css) +{ + uint8_t t; + + t = css->val; + return ~t + 1; +} + + +void +csum16_update(uint8_t *p, uint32_t len, struct csum_state *css) +{ + uint16_t t; + + if (css->odd) { + t = css->tmp + (p[0]<<8); + css->val += LE16_TO_HOST(t); + css->odd = 0; + len--; + p++; + } + + for ( ; len > 1; len -= 2, p +=2 ) { + t = p[0] + (p[1] << 8); + css->val += LE16_TO_HOST(t); + } + + if (len == 1) { + css->tmp = p[0]; + css->odd = 1; + } +} + + +uint16_t +csum16_get(struct csum_state *css) +{ + char pad = 0; + + csum16_update(&pad, 1, css); + return ~css->val + 1; +} + + +void +csum_init(struct csum_state *css, int size) +{ + css->val = 0; + css->tmp = 0; + css->odd = 0; + css->size = size; +} + + +void +csum_update(uint8_t *p, uint32_t len, struct csum_state *css) +{ + switch (css->size) { + case 1: + csum8_update(p,len,css); + break; + case 2: + csum16_update(p,len,css); + break; + } +} + + +uint16_t +csum_get(struct csum_state *css) +{ + uint16_t ret; + + switch (css->size) { + case 1: + ret = csum8_get(css); + break; + case 2: + ret = csum16_get(css); + break; + } + + return ret; +} + + +/* + * routines to write data to the output file + */ +int +write_out_data(FILE *outfile, uint8_t *data, size_t len, + struct csum_state *css) +{ + errno = 0; + + fwrite(data, len, 1, outfile); + if (errno) { + errmsg(1,"unable to write output file"); + return -1; + } + + if (css) { + csum_update(data, len, css); + } + + return 0; +} + + +int +write_out_padding(FILE *outfile, size_t len, uint8_t padc, + struct csum_state *css) +{ + uint8_t buf[512]; + size_t buflen = sizeof(buf); + + memset(buf, padc, buflen); + while (len > 0) { + if (len < buflen) + buflen = len; + + if (write_out_data(outfile, buf, buflen, css)) + return -1; + + len -= buflen; + } + + return 0; +} + + +int +block_stat_file(struct csys_block *block) +{ + struct stat st; + int res; + + if (block->file_name == NULL) + return 0; + + res = stat(block->file_name, &st); + if (res){ + errmsg(1, "stat failed on %s", block->file_name); + return res; + } + + block->file_size = st.st_size; + return 0; +} + + +int +block_writeout_hdr(FILE *outfile, struct csys_block *block) +{ + struct csys_header hdr; + int res; + + if (block->size_hdr == 0) + return 0; + + /* setup header fields */ + memcpy(hdr.sig, block->sig, 4); + hdr.addr = HOST_TO_LE32(block->addr); + hdr.size = HOST_TO_LE32(block->size-block->size_hdr); + + dbgmsg(1,"writing header for block"); + res = write_out_data(outfile, (uint8_t *)&hdr, sizeof(hdr),NULL); + return res; + +} + + +int +block_writeout_file(FILE *outfile, struct csys_block *block) +{ + char buf[FILE_BUF_LEN]; + size_t buflen = sizeof(buf); + FILE *f; + size_t len; + int res; + + if (block->file_name == NULL) + return 0; + + if (block->file_size == 0) + return 0; + + errno = 0; + f = fopen(block->file_name,"r"); + if (errno) { + errmsg(1,"unable to open file: %s", block->file_name); + return -1; + } + + len = block->file_size; + while (len > 0) { + if (len < buflen) + buflen = len; + + /* read data from source file */ + errno = 0; + fread(buf, buflen, 1, f); + if (errno != 0) { + errmsg(1,"unable to read from file: %s", + block->file_name); + res = -1; + break; + } + + res = write_out_data(outfile, buf, buflen, block->css); + if (res) + break; + + len -= buflen; + } + + fclose(f); + return res; +} + + +int +block_writeout_data(FILE *outfile, struct csys_block *block) +{ + int res; + size_t padlen; + + res = block_writeout_file(outfile, block); + if (res) + return res; + + /* write padding data if neccesary */ + padlen = block->size_avail - block->file_size; + dbgmsg(1,"padding block, length=%d", padlen); + res = write_out_padding(outfile, padlen, block->padc, block->css); + + return res; +} + + +int +block_writeout_csum(FILE *outfile, struct csys_block *block) +{ + uint16_t csum; + int res; + + if (block->size_csum == 0) + return 0; + + dbgmsg(1,"writing checksum for block"); + csum = HOST_TO_LE16(csum_get(block->css)); + res = write_out_data(outfile, (uint8_t *)&csum, block->size_csum, NULL); + + return res; +} + + +int +block_writeout(FILE *outfile, struct csys_block *block) +{ + int res; + struct csum_state css; + + res = 0; + + if (block == NULL) + return res; + + block->css = NULL; + + dbgmsg(2, "writing block, file=%s, file_size=%d, space=%d", + block->file_name, block->file_size, block->size_avail); + res = block_writeout_hdr(outfile, block); + if (res) + return res; + + if (block->size_csum != 0) { + block->css = &css; + csum_init(&css, block->size_csum); + } + + res = block_writeout_data(outfile, block); + if (res) + return res; + + res = block_writeout_csum(outfile, block); + if (res) + return res; + + return res; +} + + +int +write_out_blocks(FILE *outfile) +{ + struct csys_block *block; + int i, res; + + res = block_writeout(outfile, boot_block); + if (res) + return res; + + res = block_writeout(outfile, conf_block); + if (res) + return res; + + res = block_writeout(outfile, webp_block); + if (res) + return res; + + res = block_writeout(outfile, code_block); + if (res) + return res; + + res = 0; + for (i=0; i < num_blocks; i++) { + block = &blocks[i]; + + if (block->type != BLOCK_TYPE_XTRA) + continue; + + res = block_writeout(outfile, block); + if (res) + break; + } + + return res; +} + + +struct board_info * +find_board(char *model) +{ + struct board_info *ret; + struct board_info *board; + + ret = NULL; + for (board = boards; board->model != NULL; board++){ + if (strcmp(model, board->model) == 0) { + ret = board; + break; + } + }; + + return ret; +} + + +int +parse_opt_board(char ch, char *arg) +{ + + dbgmsg(1,"parsing board option: -%c %s", ch, arg); + + if (board != NULL) { + errmsg(0,"only one board option allowed"); + return -1; + } + + if (required_arg(ch, arg)) + return -1; + + board = find_board(arg); + if (board == NULL){ + errmsg(0,"invalid/unknown board specified: %s", arg); + return -1; + } + + return 0; +} + + +int +parse_opt_block(char ch, char *arg) +{ + char buf[MAX_ARG_LEN]; + char *argv[MAX_ARG_COUNT]; + int argc; + char *p; + struct csys_block *block; + int i; + + if ( num_blocks > MAX_NUM_BLOCKS ) { + errmsg(0,"too many blocks specified"); + return -1; + } + + block = &blocks[num_blocks]; + + /* setup default field values */ + block->need_file = 1; + block->padc = 0xFF; + + switch (ch) { + case 'b': + if (boot_block) { + errmsg(0,"only one boot block allowed"); + break; + } + block->type = BLOCK_TYPE_BOOT; + boot_block = block; + break; + case 'c': + if (conf_block) { + errmsg(0,"only one config block allowed"); + break; + } + block->type = BLOCK_TYPE_CONF; + conf_block = block; + break; + case 'w': + if (webp_block) { + errmsg(0,"only one web block allowed"); + break; + } + block->type = BLOCK_TYPE_WEBP; + block->size_hdr = sizeof(struct csys_header); + block->size_csum = 1; + block->need_file = 0; + webp_block = block; + break; + case 'r': + if (code_block) { + errmsg(0,"only one runtime block allowed"); + break; + } + block->type = BLOCK_TYPE_CODE; + block->size_hdr = sizeof(struct csys_header); + block->size_csum = 2; + code_block = block; + break; + case 'x': + block->type = BLOCK_TYPE_XTRA; + break; + default: + errmsg(0,"unknown block type \"%c\"", ch); + return -1; + } + + argc = parse_arg(arg, buf, argv); + + i = 0; + p = argv[i++]; + if (!is_empty_arg(p)) { + block->file_name = strdup(p); + if (block->file_name == NULL) { + errmsg(0,"not enough memory"); + return -1; + } + } else if (block->need_file){ + errmsg(0,"no file specified in %s", arg); + return -1; + } + + if (block->size_hdr) { + p = argv[i++]; + if (!is_empty_arg(p)) { + if (str2u32(p, &block->addr) != 0) { + errmsg(0,"invalid start address in %s", arg); + return -1; + } + block->addr_set = 1; + } + } + + p = argv[i++]; + if (!is_empty_arg(p)) { + if (str2u32(p, &block->size) != 0) { + errmsg(0,"invalid block size in %s", arg); + return -1; + } + block->size_set = 1; + } + + p = argv[i++]; + if (!is_empty_arg(p) && (str2u8(p, &block->padc) != 0)) { + errmsg(0,"invalid paddig character in %s", arg); + return -1; + } + + num_blocks++; + + return 0; +} + + +int +process_blocks(void) +{ + struct csys_block *block; + uint32_t size_avail; + int i; + int res; + + /* collecting stats */ + for (i = 0; i < num_blocks; i++) { + block = &blocks[i]; + res = block_stat_file(block); + if (res) + return res; + } + + size_avail = board->flash_size; + + /* bootloader */ + block = boot_block; + if (block) { + if (block->size_set) { + board->boot_size= block->size; + } else { + block->size = board->boot_size; + } + if (block->size > size_avail) { + errmsg(0,"boot block is too big"); + return -1; + } + } + size_avail -= board->boot_size; + + /* configuration data */ + block = conf_block; + if (block) { + if (block->size_set) { + board->conf_size = block->size; + } else { + block->size = board->conf_size; + } + if (block->size > size_avail) { + errmsg(0,"config block is too big"); + return -1; + } + + } + size_avail -= board->conf_size; + + /* webpages */ + block = webp_block; + if (block) { + if (block->size_set == 0) + block->size = board->webp_size; + board->webp_size = block->size; + if (block->size > board->webp_size_max) { + errmsg(0,"webpages block is too big"); + return -1; + } + memcpy(block->sig, board->sig_webp, 4); + if (block->addr_set == 0) + block->addr = board->addr_webp; + } + size_avail -= board->webp_size; + + /* runtime code */ + block = code_block; + if (block) { + if (block->size_set == 0) { + block->size =ALIGN(block->file_size+ block->size_hdr + + block->size_csum, 0x10000); + } + board->code_size = block->size; + if (board->code_size > size_avail) { + errmsg(0,"code block is too big"); + if (size_check) + return -1; + } + memcpy(code_block->sig, SIG_CSYS, 4); + if (code_block->addr_set == 0) + code_block->addr = board->addr_code; + } + size_avail -= board->code_size; + + for (i = 0; i < num_blocks; i++) { + block = &blocks[i]; + + if (block->type != BLOCK_TYPE_XTRA) + continue; + + if (block->size_set == 0) + block->size = ALIGN(block->file_size, 0x10000); + + if (block->size > size_avail) { + errmsg(0,"no space for file %s", + block->file_name); + if (size_check) + return -1; + } + + size_avail -= block->size; + } + + for (i = 0; i < num_blocks; i++) { + block = &blocks[i]; + + block->size_avail = block->size - block->size_hdr - + block->size_csum; + + if (block->size_avail < block->file_size) { + errmsg(0,"file %s is too big, size=%d, avail=%d", + block->file_name, block->file_size, + block->size_avail); + res = -1; + break; + } + } + + return res; +} + + +int +main(int argc, char *argv[]) +{ + int optinvalid = 0; /* flag for invalid option */ + int c; + 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:c:dB:hr:vw:x:"); + if (c == -1) + break; + + switch (c) { + case 'b': + case 'c': + case 'r': + case 'x': + optinvalid = parse_opt_block(c,optarg); + break; + case 'w': + if (optarg != NULL && *optarg == '-') { + /* rollback */ + optind--; + optarg = NULL; + } + optinvalid = parse_opt_block(c,optarg); + break; + case 'd': + size_check = 0; + break; + case 'B': + optinvalid = parse_opt_board(c,optarg); + break; + case 'v': + verblevel++; + break; + case 'h': + usage(EXIT_SUCCESS); + break; + default: + optinvalid = 1; + break; + } + if (optinvalid != 0 ){ + errmsg(0, "invalid option: -%c", optopt); + goto out; + } + } + + if (optind == argc) { + errmsg(0, "no output file specified"); + goto out; + } + + ofname = argv[optind++]; + + if (optind < argc) { + errmsg(0, "invalid option: %s", argv[optind]); + goto out; + } + + + if (board == NULL) { + errmsg(0, "no board specified"); + goto out; + } + + if (process_blocks() != 0) { + goto out; + } + + outfile = fopen(ofname, "w"); + if (outfile == NULL) { + errmsg(1, "could not open \"%s\" for writing", ofname); + goto out; + } + + if (write_out_blocks(outfile) != 0) + goto out_flush; + + dbgmsg(1,"Image file %s completed.", ofname); + + res = EXIT_SUCCESS; + +out_flush: + fflush(outfile); + fclose(outfile); + if (res != EXIT_SUCCESS) { + unlink(ofname); + } +out: + return res; +}