diff options
Diffstat (limited to 'release/src/btools/fpkg.c')
-rw-r--r-- | release/src/btools/fpkg.c | 330 |
1 files changed, 330 insertions, 0 deletions
diff --git a/release/src/btools/fpkg.c b/release/src/btools/fpkg.c new file mode 100644 index 00000000..8e0244e1 --- /dev/null +++ b/release/src/btools/fpkg.c @@ -0,0 +1,330 @@ +/* + + fpkg - Package a firmware + Copyright (C) 2007 Jonathan Zarate + + 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 <string.h> +#include <unistd.h> +#include <getopt.h> +#include <time.h> +#include <stdint.h> +#include <sys/stat.h> +#include <arpa/inet.h> + + +#define ROUNDUP(n, a) ((n + (a - 1)) & ~(a - 1)) + +#define TRX_MAGIC 0x30524448 +#define TRX_VERSION 1 +#define TRX_MAX_OFFSET 3 +#define TRX_MAX_LEN ((8 * 1024 * 1024) - ((256 + 128) * 1024)) // 8MB - (256K cfe + 128K cfg) + +typedef struct { + uint32_t magic; + uint32_t length; + uint32_t crc32; + uint32_t flag_version; + uint32_t offsets[TRX_MAX_OFFSET]; +} trx_t; + +typedef struct { + uint32_t crc32; + uint32_t magic; +} moto_t; + +typedef struct { + uint8_t magic[4]; + uint8_t extra1[4]; + uint8_t date[3]; + uint8_t version[3]; + uint8_t u2nd[4]; + uint8_t hardware; + uint8_t serial; + uint16_t flags; + uint8_t extra2[10]; +} cytan_t; + +uint32_t *crc_table = NULL; +trx_t *trx = NULL; +int trx_count = 0; +int trx_final = 0; +int trx_padding; +time_t max_time = 0; + +int crc_init(void) +{ + uint32_t c; + int i, j; + + if (crc_table == NULL) { + if ((crc_table = malloc(sizeof(uint32_t) * 256)) == NULL) return 0; + for (i = 255; i >= 0; --i) { + c = i; + for (j = 8; j > 0; --j) { + if (c & 1) c = (c >> 1) ^ 0xEDB88320L; + else c >>= 1; + } + crc_table[i] = c; + } + } + return 1; +} + +void crc_done(void) +{ + free(crc_table); + crc_table = NULL; +} + +uint32_t crc_calc(uint32_t crc, uint8_t *buf, int len) +{ + while (len-- > 0) { + crc = crc_table[(crc ^ *buf) & 0xFF] ^ (crc >> 8); + ++buf; + } + return crc; +} + +void help(void) +{ + fprintf(stderr, + "fpkg - Package a firmware\n" + "Copyright (C) 2007 Jonathan Zarate\n" + "\n" + "Usage: -i <input> [-i <input>] {output}\n" + "Output:\n" + " TRX: -t <output file>\n" + " Linksys: -l <id>,<output file>\n" + " W54G WRT54G / WRT54GL\n" + " W54U WRTSL54GS\n" + " W54S WRTS54GS\n" + " W54s WRT54GS v4\n" + " Motorola: -m <id>,<output file>\n" + " 0x10577000 WE800\n" + " 0x10577040 WA840\n" + " 0x10577050 WR850\n" + "\n" + ); + exit(1); +} + +void load_image(const char *fname) +{ + struct stat st; + FILE *f; + long rsize; + char *p; + + if (trx_final) { + fprintf(stderr, "Cannot load another image if an output has already been written.\n"); + exit(1); + } + if (trx_count >= TRX_MAX_OFFSET) { + fprintf(stderr, "Too many input files.\n"); + exit(1); + } + + if (stat(fname, &st) != 0) { + perror(fname); + exit(1); + } + if (st.st_ctime > max_time) max_time = st.st_ctime; + + rsize = ROUNDUP(st.st_size, 4); + if ((trx->length + rsize) > TRX_MAX_LEN) { + fprintf(stderr, "Total size is too big.\n"); + exit(1); + } + + p = (char *)trx + trx->length; + if ((f = fopen(fname, "r")) == NULL) { + perror(fname); + exit(1); + } + if (fread((char *)trx + trx->length, st.st_size, 1, f) != 1) { + perror(fname); + exit(1); + } + fclose(f); + + trx->offsets[trx_count++] = trx->length; + trx->length += rsize; +} + +void finalize_trx(void) +{ + uint32_t len; + + if (trx_count == 0) { + fprintf(stderr, "No image was loaded.\n"); + exit(1); + } + + if (trx_final) return; + trx_final = 1; + + len = trx->length; + + trx->length = ROUNDUP(len, 4096); + trx->magic = TRX_MAGIC; + trx->flag_version = TRX_VERSION << 16; + trx->crc32 = crc_calc(0xFFFFFFFF, (void *)&trx->flag_version, + trx->length - (sizeof(*trx) - (sizeof(trx->flag_version) + sizeof(trx->offsets)))); + + trx_padding = trx->length - len; +} + +void create_trx(const char *fname) +{ + FILE *f; + + finalize_trx(); + + printf("Creating TRX: %s\n", fname); + + if (((f = fopen(fname, "w")) == NULL) || + (fwrite(trx, trx->length, 1, f) != 1)) { + perror(fname); + exit(1); + } + fclose(f); +} + +void create_cytan(const char *fname, const char *pattern) +{ + FILE *f; + cytan_t h; + char padding[1024 - sizeof(h)]; + struct tm *tm; + + if (strlen(pattern) != 4) { + fprintf(stderr, "Linksys signature must be 4 characters. \"%s\" is invalid.\n", pattern); + exit(1); + } + + finalize_trx(); + + printf("Creating Linksys %s: %s\n", pattern, fname); + + memset(&h, 0, sizeof(h)); + memcpy(h.magic, pattern, 4); + memcpy(h.u2nd, "U2ND", 4); + h.version[0] = 4; // 4.0.0 should be >= *_VERSION_FROM defined in code_pattern.h + h.flags = 0xFF; + tm = localtime(&max_time); + h.date[0] = tm->tm_year - 100; + h.date[1] = tm->tm_mon + 1; + h.date[2] = tm->tm_mday; + + memset(padding, 0, sizeof(padding)); + + if (((f = fopen(fname, "w")) == NULL) || + (fwrite(&h, sizeof(h), 1, f) != 1) || + (fwrite(trx, trx->length, 1, f) != 1) || + (fwrite(padding, sizeof(padding), 1, f) != 1)) { + perror(fname); + exit(1); + } + fclose(f); +} + +void create_moto(const char *fname, const char *signature) +{ + FILE *f; + moto_t h; + char *p; + + h.magic = strtoul(signature, &p, 0); + if (*p != 0) help(); + + finalize_trx(); + + printf("Creating Motorola 0x%08X: %s\n", h.magic, fname); + + h.magic = htonl(h.magic); + h.crc32 = crc_calc(0xFFFFFFFF, (void *)&h.magic, sizeof(h.magic)); + h.crc32 = htonl(crc_calc(h.crc32, (void *)trx, trx->length)); + + if (((f = fopen(fname, "w")) == NULL) || + (fwrite(&h, sizeof(h), 1, f) != 1) || + (fwrite(trx, trx->length, 1, f) != 1)) { + perror(fname); + exit(1); + } + fclose(f); +} + +int main(int argc, char **argv) +{ + char s[256]; + char *p; + int o; + + printf("\n"); + + if ((!crc_init()) || ((trx = calloc(1, TRX_MAX_LEN)) == NULL)) { + fprintf(stderr, "Not enough memory\n"); + exit(1); + } + trx->length = sizeof(*trx); + + while ((o = getopt(argc, argv, "i:t:l:m:")) != -1) { + switch (o) { + case 'i': + load_image(optarg); + break; + case 't': + create_trx(optarg); + break; + case 'l': + case 'm': + if (strlen(optarg) >= sizeof(s)) help(); + strcpy(s, optarg); + if ((p = strchr(s, ',')) == NULL) help(); + *p = 0; + ++p; + if (o == 'l') create_cytan(p, s); + else create_moto(p, s); + break; + default: + help(); + return 1; + } + } + + if (trx_count == 0) { + help(); + } + else { + finalize_trx(); + printf("\nTRX Image:\n"); + printf(" Total Size .... : %u (%.2fK)\n", trx->length, trx->length / 1024.0); + printf(" Images ...... : %u\n", trx->length - trx_padding); + printf(" Padding ..... : %d\n", trx_padding); + printf(" CRC-32 ........ : %8X\n", trx->crc32); + printf(" 128K Blocks ... : %u\n", (ROUNDUP(trx->length, (128 * 1024)) / (128 * 1024))); + printf(" Offsets:\n"); + for (o = 0; o < TRX_MAX_OFFSET; ++o) { + printf(" %d: 0x%08X\n", o, trx->offsets[o]); + } + } + printf("\n"); + return 0; +} |