📄 mkzynfw.c
字号:
/* * $Id: mkzynfw.c 11559 2008-06-22 19:02:42Z juhosg $ * * 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: * 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 version 2 as published * by the Free Software Foundation. * */#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 "zynos.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)# define HOST_TO_BE16(x) bswap_16(x)# define HOST_TO_BE32(x) bswap_32(x)# define BE16_TO_HOST(x) bswap_16(x)# define BE32_TO_HOST(x) bswap_32(x)#else# define HOST_TO_BE16(x) (x)# define HOST_TO_BE32(x) (x)# define BE16_TO_HOST(x) (x)# define BE32_TO_HOST(x) (x)# 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)struct csum_state{ int odd; uint32_t sum; uint32_t tmp;};struct fw_block { uint32_t align; /* alignment of this block */ char *file_name; /* name of the file */ uint32_t file_size; /* length of the file */ char *mmap_name; /* name in the MMAP table */ int type; /* block type */ uint32_t padlen; uint8_t padc;};#define BLOCK_TYPE_BOOTEXT 0#define BLOCK_TYPE_RAW 1struct fw_mmap { uint32_t addr; uint32_t size; uint32_t user_addr; uint32_t user_size;};#define MMAP_DATA_SIZE 1024#define MMAP_ALIGN 16struct 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 romio_offs; /* offset of the firmware within the flash */ uint32_t bootext_size; /* maximum size of bootext block */};/* * Globals */char *progname;char *ofname = NULL;int verblevel = 0;struct board_info *board = NULL;struct fw_block blocks[MAX_NUM_BLOCKS];struct fw_block *bootext_block = NULL;int num_blocks = 0;#define ADM5120_FLASH_BASE 0xBFC00000#define ADM5120_CODE_START 0x80008000/* TODO: check values for AR7 */#define AR7_FLASH_BASE 0xB0000000#define AR7_CODE_START 0x94008000#define ATHEROS_FLASH_BASE 0xBFC00000#define ATHEROS_CODE_START 0x80e00000#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, ZYNOS_VENDOR_ID_ZYXEL, m, \ ADM5120_FLASH_BASE, fs, ADM5120_CODE_START, 0x8000)#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, 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)static struct board_info 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), ADMBOARD2("ES-2108", "ZyXEL ES-2108", ZYNOS_MODEL_ES_2108, 4), ADMBOARD2("ES-2108-F", "ZyXEL ES-2108-F", ZYNOS_MODEL_ES_2108_F, 4), ADMBOARD2("ES-2108-G", "ZyXEL ES-2108-G", ZYNOS_MODEL_ES_2108_G, 4), ADMBOARD2("ES-2108-LC", "ZyXEL ES-2108-LC", ZYNOS_MODEL_ES_2108_LC, 4), ADMBOARD2("ES-2108PWR", "ZyXEL ES-2108PWR", ZYNOS_MODEL_ES_2108PWR, 4), ADMBOARD1("HS-100", "ZyXEL HomeSafe 100", ZYNOS_MODEL_HS_100, 2), ADMBOARD1("HS-100W", "ZyXEL HomeSafe 100W", ZYNOS_MODEL_HS_100W, 2), ADMBOARD1("P-334", "ZyXEL Prestige 334", ZYNOS_MODEL_P_334, 2), ADMBOARD1("P-334U", "ZyXEL Prestige 334U", ZYNOS_MODEL_P_334U, 4), ADMBOARD1("P-334W", "ZyXEL Prestige 334W", ZYNOS_MODEL_P_334W, 2), ADMBOARD1("P-334WH", "ZyXEL Prestige 334WH", ZYNOS_MODEL_P_334WH, 4), ADMBOARD1("P-334WHD", "ZyXEL Prestige 334WHD", ZYNOS_MODEL_P_334WHD, 4), ADMBOARD1("P-334WT", "ZyXEL Prestige 334WT", ZYNOS_MODEL_P_334WT, 4), ADMBOARD1("P-335", "ZyXEL Prestige 335", ZYNOS_MODEL_P_335, 4), 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), AR7BOARD1("P-660H-63", "ZyXEL P-660H-63", ZYNOS_MODEL_P_660H_63, 2), AR7BOARD1("P-660H-D1", "ZyXEL P-660H-D1", ZYNOS_MODEL_P_660H_D1, 2), AR7BOARD1("P-660H-D3", "ZyXEL P-660H-D3", ZYNOS_MODEL_P_660H_D3, 2), AR7BOARD1("P-660HW-61", "ZyXEL P-660HW-61", ZYNOS_MODEL_P_660HW_61, 2), AR7BOARD1("P-660HW-63", "ZyXEL P-660HW-63", ZYNOS_MODEL_P_660HW_63, 2), AR7BOARD1("P-660HW-67", "ZyXEL P-660HW-67", ZYNOS_MODEL_P_660HW_67, 2), AR7BOARD1("P-660HW-D1", "ZyXEL P-660HW-D1", ZYNOS_MODEL_P_660HW_D1, 2), AR7BOARD1("P-660HW-D3", "ZyXEL P-660HW-D3", ZYNOS_MODEL_P_660HW_D3, 2), AR7BOARD1("P-660R-61", "ZyXEL P-660R-61", ZYNOS_MODEL_P_660R_61, 2), AR7BOARD1("P-660R-61C", "ZyXEL P-660R-61C", ZYNOS_MODEL_P_660R_61C, 2), AR7BOARD1("P-660R-63", "ZyXEL P-660R-63", ZYNOS_MODEL_P_660R_63, 2), AR7BOARD1("P-660R-63C", "ZyXEL P-660R-63C", ZYNOS_MODEL_P_660R_63C, 2), AR7BOARD1("P-660R-67", "ZyXEL P-660R-67", ZYNOS_MODEL_P_660R_67, 2), 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), {.name = 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 ", %s\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 -2/* * Helper routines */voidusage(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 <board> create image for the board specified with <board>.\n"" valid <board> values:\n" ); for (board = boards; board->name != NULL; board++){ fprintf(stream," %-12s= %s\n", board->name, board->desc); }; fprintf(stream," -b <file>[:<align>]\n"" add boot extension block to the image\n"" -r <file>[:<align>]\n"" add raw block to the image\n"" -o <file> write output to the file <file>\n"" -h show this screen\n" ); exit(status);}/* * 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 -1;}intis_empty_arg(char *arg){ int ret = 1; if (arg != NULL) { if (*arg) ret = 0; }; return ret;}voidcsum_init(struct csum_state *css){ css->odd = 0; css->sum = 0; css->tmp = 0;}voidcsum_update(uint8_t *p, uint32_t len, struct csum_state *css){ if (len == 0) return; if (css->odd) { css->sum += (css->tmp << 8) + p[0]; if (css->sum > 0xFFFF) { css->sum += 1; css->sum &= 0xFFFF; } css->odd = 0; len--; p++; } for ( ; len > 1; len -= 2, p +=2 ) { css->sum += (p[0] << 8) + p[1]; if (css->sum > 0xFFFF) { css->sum += 1; css->sum &= 0xFFFF; } } if (len == 1){ css->tmp = p[0]; css->odd = 1; }}uint16_tcsum_get(struct csum_state *css){ char pad = 0; csum_update(&pad, 1, css); return css->sum;}uint16_tcsum_buf(uint8_t *p, uint32_t len){ struct csum_state css; csum_init(&css); csum_update(p, len, &css); return csum_get(&css);}/* * 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) { ERR("unable to write output file"); return -1; } 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); 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;}intwrite_out_data_align(FILE *outfile, uint8_t *data, size_t len, size_t align, struct csum_state *css){ size_t padlen; int res; res = write_out_data(outfile, data, len, css); if (res) return res; padlen = ALIGN(len,align) - len; res = write_out_padding(outfile, padlen, 0xFF, css); return res;}intwrite_out_header(FILE *outfile, struct zyn_rombin_hdr *hdr){ struct zyn_rombin_hdr t; errno = 0; if (fseek(outfile, 0, SEEK_SET) != 0) { ERRS("fseek failed on output file"); return -1; } /* setup temporary header fields */ memset(&t, 0, sizeof(t)); t.addr = HOST_TO_BE32(hdr->addr);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -