📄 mkcsysimg.c
字号:
/* * $Id$ * * Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org> * * This program was based on the code found in various Linux * source tarballs released by Edimax for it's devices. * Original author: David Hsu <davidhsu@realtek.com.tw> * * 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 <stdio.h>#include <stdlib.h>#include <stdint.h>#include <string.h>#include <unistd.h> /* for unlink() */#include <libgen.h>#include <getopt.h> /* for getopt() */#include <stdarg.h>#include <errno.h>#include <sys/stat.h>#include <endian.h> /* for __BYTE_ORDER */#if defined(__CYGWIN__)# include <byteswap.h>#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 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#define DEFAULT_BLOCK_ALIGN 0x10000U#define CSUM_SIZE_NONE 0#define CSUM_SIZE_8 1#define CSUM_SIZE_16 2struct 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 */ unsigned char sig[SIG_LEN]; uint32_t addr; int addr_set; uint32_t align; int align_set; uint8_t padc; uint32_t size; uint32_t size_hdr; uint32_t size_csum; uint32_t size_avail; 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 invalid_causes_error = 1;int keep_invalid_images = 0;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-6104Wg", "Edimax BR-6104Wg", 2, SIG_BR6104Wg), 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), /* Conceptronic products */ BOARD_ADM("C54BSR4", "Conceptronic C54BSR4", 2, SIG_C54BSR4), {.model = NULL}};/* * 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)#define WARN(fmt, ...) do { \ fprintf(stderr, "[%s] *** warning: " fmt "\n", progname, ## __VA_ARGS__ ); \} while (0)#define DBG(lev, fmt, ...) do { \ if (verblevel < lev) \ break;\ fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \} while (0)#define ERR_FATAL -1#define ERR_INVALID_IMAGE -2voidusage(int status){ FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout; struct board_info *board; fprintf(stream, "Usage: %s [OPTIONS...] <file>\n", progname); fprintf(stream,"\n""Options:\n"" -B <board> create image for the board specified with <board>.\n"" valid <board> values:\n" ); for (board = boards; board->model != NULL; board++){ fprintf(stream," %-12s: %s\n", board->model, board->name); }; fprintf(stream," -d don't throw error on invalid images\n"" -k keep invalid images\n"" -b <file>[:<align>[:<padc>]]\n"" add boot code to the image\n"" -c <file>[:<align>[:<padc>]]\n"" add configuration settings to the image\n"" -r <file>:[<addr>][:<align>[:<padc>]]\n"" add runtime code to the image\n"" -w [<file>:[<addr>][:<align>[:<padc>]]]\n"" add webpages to the image\n"" -x <file>[:<align>[:<padc>]]\n"" add extra data at the end of the image\n"" -h show this screen\n""Parameters:\n"" <file> write output to the file <file>\n" ); exit(status);}static inline uint32_t align(uint32_t base, uint32_t alignment){ uint32_t ret; if (alignment) { ret = (base + alignment - 1); ret &= ~(alignment-1); } else { ret = base; } return ret;}/* * argument parsing */intstr2u32(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;}intstr2u16(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;}intstr2u8(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;}intstr2sig(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;}intparse_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;}intrequired_arg(char c, char *arg){ if (arg == NULL || *arg != '-') return 0; ERR("option -%c requires an argument\n", c); return ERR_FATAL;}intis_empty_arg(char *arg){ int ret = 1; if (arg != NULL) { if (*arg) ret = 0; }; return ret;}voidcsum8_update(uint8_t *p, uint32_t len, struct csum_state *css){ for ( ; len > 0; len --) { css->val += *p++; }}uint16_tcsum8_get(struct csum_state *css){ uint8_t t; t = css->val; return ~t + 1;}voidcsum16_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_tcsum16_get(struct csum_state *css){ char pad = 0; csum16_update(&pad, 1, css); return ~css->val + 1;}voidcsum_init(struct csum_state *css, int size){ css->val = 0; css->tmp = 0; css->odd = 0; css->size = size;}voidcsum_update(uint8_t *p, uint32_t len, struct csum_state *css){ switch (css->size) { case CSUM_SIZE_8: csum8_update(p,len,css); break; case CSUM_SIZE_16: csum16_update(p,len,css); break; }}uint16_tcsum_get(struct csum_state *css){ uint16_t ret; switch (css->size) { case CSUM_SIZE_8: ret = csum8_get(css); break; case CSUM_SIZE_16: ret = csum16_get(css); break; } return ret;}/* * routines to write data to the output file */intwrite_out_data(FILE *outfile, uint8_t *data, size_t len, struct csum_state *css){ errno = 0; fwrite(data, len, 1, outfile); if (errno) { ERRS("unable to write output file"); return ERR_FATAL; } if (css) { csum_update(data, len, css); } return 0;}intwrite_out_padding(FILE *outfile, size_t len, uint8_t padc, struct csum_state *css){ uint8_t buf[512]; size_t buflen = sizeof(buf); int err; memset(buf, padc, buflen); while (len > 0) { if (len < buflen) buflen = len; err = write_out_data(outfile, buf, buflen, css); if (err) return err; len -= buflen; } return 0;}intblock_stat_file(struct csys_block *block){ struct stat st; int err; if (block->file_name == NULL) return 0; err = stat(block->file_name, &st); if (err){ ERRS("stat failed on %s", block->file_name); return ERR_FATAL; } block->file_size = st.st_size; return 0;}intblock_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->align-block->size_hdr);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -