summaryrefslogtreecommitdiff
path: root/release/src/btools/fpkg.c
diff options
context:
space:
mode:
Diffstat (limited to 'release/src/btools/fpkg.c')
-rw-r--r--release/src/btools/fpkg.c330
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;
+}