aboutsummaryrefslogtreecommitdiffstats
path: root/tools/firmware-utils/src
diff options
context:
space:
mode:
Diffstat (limited to 'tools/firmware-utils/src')
-rw-r--r--tools/firmware-utils/src/addpattern.c49
-rw-r--r--tools/firmware-utils/src/airlink.c332
-rw-r--r--tools/firmware-utils/src/asustrx.c256
-rw-r--r--[l---------]tools/firmware-utils/src/bcm_tag.h71
-rw-r--r--tools/firmware-utils/src/bcmalgo.c248
-rw-r--r--tools/firmware-utils/src/bcmalgo.h83
-rw-r--r--tools/firmware-utils/src/buffalo-enc.c36
-rw-r--r--tools/firmware-utils/src/buffalo-lib.c6
-rw-r--r--tools/firmware-utils/src/buffalo-lib.h20
-rw-r--r--tools/firmware-utils/src/buffalo-tag.c46
-rw-r--r--tools/firmware-utils/src/buffalo-tftp.c2
-rw-r--r--tools/firmware-utils/src/csysimg.h1
-rw-r--r--tools/firmware-utils/src/dgfirmware.c1
-rw-r--r--tools/firmware-utils/src/dgn3500sum.c166
-rw-r--r--tools/firmware-utils/src/dns313-header.c239
-rw-r--r--tools/firmware-utils/src/edimax_fw_header.c386
-rw-r--r--tools/firmware-utils/src/fix-u-media-header.c354
-rw-r--r--tools/firmware-utils/src/hcsmakeimage.c203
-rw-r--r--tools/firmware-utils/src/imagetag.c101
-rw-r--r--tools/firmware-utils/src/imagetag.ggo2
-rw-r--r--tools/firmware-utils/src/imagetag_cmdline.c178
-rw-r--r--tools/firmware-utils/src/imagetag_cmdline.h61
-rw-r--r--tools/firmware-utils/src/jcgimage.c425
-rw-r--r--tools/firmware-utils/src/lzma2eva.c2
-rw-r--r--tools/firmware-utils/src/md5.c551
-rw-r--r--tools/firmware-utils/src/md5.h92
-rw-r--r--tools/firmware-utils/src/mkbrnimg.c22
-rw-r--r--tools/firmware-utils/src/mkbuffaloimg.c223
-rw-r--r--tools/firmware-utils/src/mkcameofw.c433
-rw-r--r--tools/firmware-utils/src/mkcasfw.c8
-rw-r--r--tools/firmware-utils/src/mkchkimg.c22
-rw-r--r--tools/firmware-utils/src/mkcsysimg.c9
-rw-r--r--tools/firmware-utils/src/mkdapimg.c226
-rw-r--r--tools/firmware-utils/src/mkdapimg2.c204
-rw-r--r--tools/firmware-utils/src/mkdcs932.c39
-rw-r--r--tools/firmware-utils/src/mkdhpimg.c85
-rw-r--r--tools/firmware-utils/src/mkdlinkfw-lib.c172
-rw-r--r--tools/firmware-utils/src/mkdlinkfw-lib.h83
-rw-r--r--tools/firmware-utils/src/mkdlinkfw.c665
-rw-r--r--tools/firmware-utils/src/mkdniimg.c2
-rw-r--r--tools/firmware-utils/src/mkfwimage.c20
-rw-r--r--tools/firmware-utils/src/mkfwimage2.c6
-rw-r--r--tools/firmware-utils/src/mkheader_gemtek.c211
-rw-r--r--tools/firmware-utils/src/mkhilinkfw.c323
-rw-r--r--tools/firmware-utils/src/mkmerakifw-old.c369
-rw-r--r--tools/firmware-utils/src/mkmerakifw.c320
-rw-r--r--tools/firmware-utils/src/mkplanexfw.c2
-rw-r--r--tools/firmware-utils/src/mkporayfw.c791
-rw-r--r--tools/firmware-utils/src/mkrtn56uimg.c293
-rw-r--r--tools/firmware-utils/src/mksenaofw.c420
-rw-r--r--tools/firmware-utils/src/mksercommfw.c255
-rw-r--r--tools/firmware-utils/src/mktplinkfw-lib.c265
-rw-r--r--tools/firmware-utils/src/mktplinkfw-lib.h68
-rw-r--r--tools/firmware-utils/src/mktplinkfw.c769
-rw-r--r--tools/firmware-utils/src/mktplinkfw2.c628
-rw-r--r--tools/firmware-utils/src/mkwrggimg.c283
-rw-r--r--tools/firmware-utils/src/mkzcfw.c2
-rw-r--r--tools/firmware-utils/src/mkzynfw.c5
-rw-r--r--tools/firmware-utils/src/nand_ecc.c2
-rw-r--r--tools/firmware-utils/src/osbridge-crc.c2
-rw-r--r--tools/firmware-utils/src/oseama.c556
-rw-r--r--tools/firmware-utils/src/otrx.c592
-rw-r--r--tools/firmware-utils/src/pc1crypt.c2
-rw-r--r--tools/firmware-utils/src/ptgen.c126
-rw-r--r--tools/firmware-utils/src/seama.c529
-rw-r--r--tools/firmware-utils/src/seama.h108
-rw-r--r--tools/firmware-utils/src/spw303v.c2
-rw-r--r--tools/firmware-utils/src/srec2bin.c2
-rw-r--r--tools/firmware-utils/src/tplink-safeloader.c2084
-rw-r--r--tools/firmware-utils/src/trx.c22
-rw-r--r--tools/firmware-utils/src/wndr3700.c150
-rw-r--r--tools/firmware-utils/src/wrt400n.c2
-rw-r--r--tools/firmware-utils/src/xorimage.c1
-rw-r--r--tools/firmware-utils/src/zyimage.c148
-rw-r--r--tools/firmware-utils/src/zyxbcm.c259
75 files changed, 14076 insertions, 1645 deletions
diff --git a/tools/firmware-utils/src/addpattern.c b/tools/firmware-utils/src/addpattern.c
index da6797c9ced..9bc48653356 100644
--- a/tools/firmware-utils/src/addpattern.c
+++ b/tools/firmware-utils/src/addpattern.c
@@ -58,6 +58,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <errno.h>
#include <time.h>
#include <unistd.h>
#include <sys/stat.h>
@@ -77,10 +78,11 @@
/* (from 3.00.24 firmware cyutils.h) */
#define SUPPORT_4704_CHIP 0x0008
#define SUPPORT_5352E_CHIP 0x0010
+/* (from WD My Net Wi-Fi Range Extender's cyutils.s) */
+#define SUPPORT_4703_CHIP 0x0020
struct code_header { /* from cyutils.h */
- char magic[4];
- char res1[4]; /* for extra magic */
+ char magic[8];
char fwdate[3];
char fwvern[3];
char id[4]; /* U2ND */
@@ -105,11 +107,25 @@ struct board_info {
struct board_info boards[] = {
{
+ .id = "E2100L",
+ .pattern = "NL1X",
+ .hw_ver = 0x00,
+ .sn = 0x0f,
+ .flags = {0x3f, 0x00},
+ },
+ {
.id = "WRT160NL",
.pattern = "NL16",
.hw_ver = 0x00,
.sn = 0x0f,
.flags = {0x3f, 0x00},
+ },
+ {
+ .id = "mynet-rext",
+ .pattern = "WDHNSTFH",
+ .hw_ver = 0x00,
+ .sn = 0x00,
+ .flags = {0x3f, 0x00},
}, {
/* Terminating entry */
.id = NULL,
@@ -126,6 +142,20 @@ void usage(void)
exit(EXIT_FAILURE);
}
+static time_t source_date_epoch = -1;
+static void set_source_date_epoch() {
+ char *env = getenv("SOURCE_DATE_EPOCH");
+ char *endptr = env;
+ errno = 0;
+ if (env && *env) {
+ source_date_epoch = strtoull(env, &endptr, 10);
+ if (errno || (endptr && *endptr != '\0')) {
+ fprintf(stderr, "Invalid SOURCE_DATE_EPOCH");
+ exit(1);
+ }
+ }
+}
+
struct board_info *find_board(char *id)
{
struct board_info *board;
@@ -243,8 +273,8 @@ int main(int argc, char **argv)
hdr->flags[1] = board->flags[1];
}
- if (strlen(pattern) != 4) {
- fprintf(stderr, "illegal pattern \"%s\": length != 4\n", pattern);
+ if (strlen(pattern) > 8) {
+ fprintf(stderr, "illegal pattern \"%s\"\n", pattern);
usage();
}
@@ -258,7 +288,10 @@ int main(int argc, char **argv)
usage();
}
- if (time(&t) == (time_t)(-1)) {
+ set_source_date_epoch();
+ if (source_date_epoch != -1) {
+ t = source_date_epoch;
+ } else if ((time(&t) == (time_t)(-1))) {
fprintf(stderr, "time call failed\n");
return EXIT_FAILURE;
}
@@ -270,16 +303,16 @@ int main(int argc, char **argv)
return EXIT_FAILURE;
}
- memcpy(&hdr->magic, pattern, 4);
+ memcpy(hdr->magic, pattern, strlen(pattern));
if (pbotflag)
- memcpy(&hdr->res1, pbotpat, 4);
+ memcpy(&hdr->magic[4], pbotpat, 4);
hdr->fwdate[0] = ptm->tm_year % 100;
hdr->fwdate[1] = ptm->tm_mon + 1;
hdr->fwdate[2] = ptm->tm_mday;
hdr->fwvern[0] = v0;
hdr->fwvern[1] = v1;
hdr->fwvern[2] = v2;
- memcpy(&hdr->id, CODE_ID, strlen(CODE_ID));
+ memcpy(hdr->id, CODE_ID, strlen(CODE_ID));
off = sizeof(struct code_header);
diff --git a/tools/firmware-utils/src/airlink.c b/tools/firmware-utils/src/airlink.c
deleted file mode 100644
index 560a58df59e..00000000000
--- a/tools/firmware-utils/src/airlink.c
+++ /dev/null
@@ -1,332 +0,0 @@
-/*
- * Thanks to Vassily Galinsky for this tool
-*****************************************************************************
-AIRLINK AR525W firmware image structure
- -8:-5 Extended (httpd) header checksum - sum2
- -4:-1 Extended (httpd) header magic - "ARRN" - 0x4e525241
- 0: 3 Standard (tftpd) header magic - "GMTK" - 0x4b544d47
- 4: 7 Standard (tftpd) header checksum - sum1
- 8: b 0
- c: f Size of compressed linux kernel
- 10:13 Size of firmware image file with standard header
- 14:17 Product code - 0x5
- 18:1b Bootloader checksum - sum0
- 1c:1f 0
- 20: Compressed linux kernel
- - Squashfs or jffs2 file system - kernel dependent - either 32 bytes or sector aligned
-*****************************************************************************/
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <netinet/in.h>
-
-typedef unsigned char uchar;
-
-uint32_t crctab[257] = {
- 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
- 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
- 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
- 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
- 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
- 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
- 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
- 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
- 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
- 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
- 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
- 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
- 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
- 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
- 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
- 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
- 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
- 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
- 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
- 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
- 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
- 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
- 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
- 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
- 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
- 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
- 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
- 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
- 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
- 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
- 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
- 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
- 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
- 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
- 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
- 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
- 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
- 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
- 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
- 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
- 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
- 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
- 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
- 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
- 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
- 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
- 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
- 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
- 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
- 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
- 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
- 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
- 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
- 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
- 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
- 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
- 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
- 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
- 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
- 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
- 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
- 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
- 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
- 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
- 0
-};
-
-uint32_t header[] = {
- 0x00000000, 0x4e525241,
- 0x4b544d47, 0x00000000, 0x00000000, 0x000afd4a,
- 0x00000000, 0x00000005, 0x00000000, 0x00000000
-};
-
-static int JFFS2 = 0;
-
-int generate_image(char *kname, char *fsname, char *fname, int EHDR)
-{
- int i;
- uint32_t lenk, lens;
- uchar *bk, *bs;
- int fkd, ffd, fsd;
- fkd = open(kname, O_RDONLY);
- ffd = creat(fname, 0644);
- if ((fkd < 0) || (ffd < 0))
- return -1;
- if (fsname) {
- fsd = open(fsname, O_RDONLY);
- if (fsd < 0)
- return -1;
- }
- lenk = lseek(fkd, 0, SEEK_END);
- header[5] = lenk;
- bk = (uchar *) mmap(NULL, lenk, PROT_READ, MAP_SHARED, fkd, 0);
- if (bk == MAP_FAILED)
- return -1;
- if (fsname) {
- lens = lseek(fsd, 0, SEEK_END);
- bs = (uchar *) mmap(NULL, lens, PROT_READ, MAP_SHARED, fsd,
- 0);
- if (bs == MAP_FAILED)
- return -1;
- }
- if (EHDR)
- write(ffd, header, 0x28);
- else
- write(ffd, header + 2, 0x20);
- write(ffd, bk, lenk);
- lenk += 0x20;
- if (!JFFS2) JFFS2 = 0x20;
- printf("Padding header+kernel - 0x%x + 0x%x = 0x%x\n",
- lenk, ((lenk - 1 + JFFS2) / JFFS2) * JFFS2 - lenk,
- ((lenk - 1 + JFFS2) / JFFS2) * JFFS2);
- for (i = 0; i < ((lenk - 1 + JFFS2) / JFFS2) * JFFS2 - lenk; i++)
- write(ffd, header, 1);
- if (fsname) {
- write(ffd, bs, lens);
- close(fsd);
- }
- close(ffd);
- close(fkd);
- return 0;
-}
-
-uint32_t crc32(uchar * buf, uint32_t len)
-{
- register int i;
- uint32_t sum;
- register uint32_t s0;
- s0 = ~0;
- for (i = 0; i < len; i++) {
- s0 = (s0 >> 8) ^ crctab[(uchar) (s0 & 0xFF) ^ buf[i]];
- }
- sum = ~s0;
- return sum;
-}
-
-void usage(char *prog)
-{
- printf("Usage: %s [-b 0/1] image_filename \n", prog);
- printf(" update checksums for firmware file\n");
- printf
- ("Usage: %s [-b 0/1] [-j erasesize_in_kibytes] [-e] kernel filesystem image_filename \n",
- prog);
- printf(" generate firmware file and update checksums\n");
- printf("--------------------------------------------------\n");
- printf(" -e - generate header for web upload\n");
- printf(" -b 0/1 - clear/update bootloader checksum\n");
- printf(" -j erasesize_in_kibytes - generate header for jffs2 filesystem\n");
-}
-
-int main(int argc, char **argv)
-{
- uchar b[0x400];
- char EHDR = 0;
- char BHDR = 0;
- int c, fd;
- extern char *optarg;
- extern int optind, optopt;
-
- while ((c = getopt(argc, argv, "b:ej:")) != -1) {
- switch (c) {
- case 'b':
- if (optarg[0] == '1')
- BHDR = 1;
- break;
- case 'e':
- EHDR = 1;
- break;
- case 'j':
- sscanf(optarg, "%i", &JFFS2);
- JFFS2 *= 1024;
- break;
- case '?':
- fprintf(stderr, "\nError: unknown arg %c\n\n\n",
- optopt);
- usage(argv[0]);
- exit(-1);
- }
- }
- if (((argc - optind) < 1) && ((argc - optind) > 3)) {
- usage(argv[0]);
- exit(-1);
- }
- if ((argc - optind) == 3)
- if (generate_image
- (argv[optind], argv[optind + 1], argv[optind + 2],
- EHDR)) {
- fprintf(stderr,
- "\nError generating image file %s\n\n\n",
- argv[argc - 1]);
- usage(argv[0]);
- exit(-1);
- }
- if ((argc - optind) == 2)
- if (generate_image
- (argv[optind], NULL, argv[optind + 1], EHDR)) {
- fprintf(stderr,
- "\nError generating image file %s\n\n\n",
- argv[argc - 1]);
- usage(argv[0]);
- exit(-1);
- }
-
- fd = open(argv[argc - 1], O_RDWR);
- if (fd < 0) {
- fprintf(stderr, "\nImage file not found %s\n\n\n",
- argv[argc - 1]);
- usage(argv[0]);
- exit(-1);
- }
- long i, len = lseek(fd, 0, SEEK_END);
- lseek(fd, 0, SEEK_SET);
- uchar *buf = malloc(len);
- read(fd, buf, len);
- uint32_t sum, l0;
- uint32_t MagicS = 0x474d544b;
- uint32_t MagicE = 0x4152524e;
- if (ntohl(*((uint32_t *) buf)) == MagicS) {
- fprintf(stderr,
- "Image without extra 8 bytes - Standard header\n");
- buf[0x10] = len & 0xff;
- buf[0x11] = (len >> 8) & 0xff;
- buf[0x12] = (len >> 16) & 0xff;
- buf[0x13] = (len >> 24) & 0xff;
- lseek(fd, 0x10, SEEK_SET);
- write(fd, buf + 0x10, 0x4);
- EHDR = 0;
- } else if ((ntohl(*((uint32_t *) (buf + 0x8))) == MagicS)
- && ((ntohl(*((uint32_t *) (buf + 0x4))) == MagicE))) {
- fprintf(stderr,
- "Image with extra 8 bytes - Extended header\n");
- *((uint32_t *) (buf + 0x18)) = len - 8;
- buf[0x18] = (len - 8) & 0xff;
- buf[0x19] = ((len - 8) >> 8) & 0xff;
- buf[0x1a] = ((len - 8) >> 16) & 0xff;
- buf[0x1b] = ((len - 8) >> 24) & 0xff;
- lseek(fd, 0x18, SEEK_SET);
- write(fd, buf + 0x18, 0x4);
- buf += 8;
- EHDR = 1;
- } else if (len == buf[0x10] | ((uint32_t)buf[0x11] << 8) | ((uint32_t)buf[0x12] << 16) | ((uint32_t)buf[0x13] << 24)) {
- fprintf(stderr,
- "Image without extra 8 bytes - Standard header\n");
- EHDR = 0;
- } else if (len == (buf[0x18] | ((uint32_t)buf[0x19] << 8) | ((uint32_t)buf[0x1a] << 16) | ((uint32_t)buf[0x1b] << 24)) + 8) {
- fprintf(stderr,
- "Image with extra 8 bytes - Extended header\n");
- buf += 8;
- EHDR = 1;
- } else {
- fprintf(stderr, "ERROR: Wrong image size\n");
- exit(-1);
- }
- l0 = buf[0x10] | ((uint32_t)buf[0x11] << 8) | ((uint32_t)buf[0x12] << 16) | ((uint32_t)buf[0x13] << 24);
- if (!BHDR)
- *((uint32_t *) & buf[0x18]) = 0;
- unsigned long sum0 = buf[0x18] | ((uint32_t)buf[0x19] << 8) | ((uint32_t)buf[0x1a] << 16) | ((uint32_t)buf[0x1b] << 24);
- unsigned long sum1 = buf[0x4] | ((uint32_t)buf[0x5] << 8) | ((uint32_t)buf[0x6] << 16) | ((uint32_t)buf[0x7] << 24);
- *((uint32_t *) & buf[0x4]) = 0x0L;
- memcpy(b, buf, 0x100);
- memcpy(b + 0x100, buf + ((l0 >> 1) - ((l0 & 0x6) >> 1)), 0x100);
- memcpy(b + 0x200, buf + (l0 - 0x200), 0x200);
- *((uint32_t *) & b[0x18]) = 0x0L;
-
- sum = crc32(b, 0x400);
- printf("CRC32 sum0 - (%x, %x, %x)\n", sum, sum0, 0x400);
- if (EHDR)
- lseek(fd, 0x20, SEEK_SET);
- else
- lseek(fd, 0x18, SEEK_SET);
- buf[0x18] = (BHDR ? sum : sum0) & 0xff;
- buf[0x19] = ((BHDR ? sum : sum0) >> 8) & 0xff;
- buf[0x1a] = ((BHDR ? sum : sum0) >> 16) & 0xff;
- buf[0x1b] = ((BHDR ? sum : sum0) >> 24) & 0xff;
- write(fd, &buf[0x18], 0x4);
-
- sum = crc32(buf, l0);
- printf("CRC32 sum1 - (%x, %x, %x)\n", sum, sum1, l0);
- if (EHDR)
- lseek(fd, 0xC, SEEK_SET);
- else
- lseek(fd, 0x4, SEEK_SET);
- buf[0x4] = sum & 0xff;
- buf[0x5] = (sum >> 8) & 0xff;
- buf[0x6] = (sum >> 16) & 0xff;
- buf[0x7] = (sum >> 24) & 0xff;
- write(fd, &buf[0x4], 0x4);
- if (EHDR) {
- unsigned long sum2 = buf[-0x8] | ((uint32_t)buf[-0x7] << 8) | ((uint32_t)buf[-0x6] << 16) | ((uint32_t)buf[-0x5] << 24);
- *((uint32_t *) & buf[-0x8]) = 0L;
- sum = crc32(buf - 0x4, len - 0x4);
- printf("CRC32 sum2 - (%x, %x, %x)\n", sum, sum2,
- len - 0x4);
- lseek(fd, 0, SEEK_SET);
- *((uint32_t *) & buf[-0x8]) = htonl(sum);
- write(fd, &buf[-0x8], 0x4);
- buf -= 8;
- }
- close(fd);
- free(buf);
- return 0;
-}
diff --git a/tools/firmware-utils/src/asustrx.c b/tools/firmware-utils/src/asustrx.c
new file mode 100644
index 00000000000..67f2680b31b
--- /dev/null
+++ b/tools/firmware-utils/src/asustrx.c
@@ -0,0 +1,256 @@
+/*
+ * asustrx
+ *
+ * Copyright (C) 2015 Rafał Miłecki <zajec5@gmail.com>
+ *
+ * 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.
+ */
+
+#include <byteswap.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define cpu_to_le32(x) bswap_32(x)
+#define le32_to_cpu(x) bswap_32(x)
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+#define cpu_to_le32(x) (x)
+#define le32_to_cpu(x) (x)
+#else
+#error "Unsupported endianness"
+#endif
+
+#define TRX_MAGIC 0x30524448
+#define TRX_FLAGS_OFFSET 12
+
+struct trx_header {
+ uint32_t magic;
+ uint32_t length;
+ uint32_t crc32;
+ uint16_t flags;
+ uint16_t version;
+ uint32_t offset[3];
+};
+
+struct asustrx_tail {
+ uint8_t version[4];
+ char productid[12];
+ uint8_t unused[48];
+};
+
+char *in_path = NULL;
+char *out_path = NULL;
+char *productid = NULL;
+uint8_t version[4] = { };
+
+static const uint32_t crc32_tbl[] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
+ 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+ 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+ 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
+ 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+ 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
+ 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
+ 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+ 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+ 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
+ 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
+ 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+ 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
+ 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+ 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+ 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
+ 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
+ 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+ 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+ 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
+ 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+ 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
+ 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
+ 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+ 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+ 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
+ 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
+ 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+ 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
+ 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+ 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+ 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
+ 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
+ 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+ 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
+};
+
+static void parse_options(int argc, char **argv) {
+ int c;
+
+ while ((c = getopt(argc, argv, "i:o:p:v:")) != -1) {
+ switch (c) {
+ case 'i':
+ in_path = optarg;
+ break;
+ case 'o':
+ out_path = optarg;
+ break;
+ case 'p':
+ productid = optarg;
+ break;
+ case 'v':
+ if (sscanf(optarg, "%hu.%hu.%hu.%hu", &version[0], &version[1], &version[2], &version[3]) != 4)
+ fprintf(stderr, "Version %s doesn't match suppored 4-digits format\n", optarg);
+ break;
+ }
+ }
+}
+
+static void usage() {
+ printf("Usage:\n");
+ printf("\t-i file\t\t\t\tinput TRX file\n");
+ printf("\t-o file\t\t\t\toutput Asus TRX file\n");
+ printf("\t-p productid\t\t\tproduct (device) ID\n");
+ printf("\t-v version\t\t\tfirmware version formatted with 4 digits like: 1.2.3.4\n");
+}
+
+int main(int argc, char **argv) {
+ struct trx_header hdr;
+ struct asustrx_tail tail = { };
+ FILE *in, *out;
+ uint8_t buf[1024];
+ size_t bytes;
+ size_t length = 0;
+ uint32_t crc32 = 0xffffffff;
+ int i;
+ int err = 0;
+
+ /* Parse & validate arguments */
+ parse_options(argc, argv);
+ if (!in_path || !out_path || !productid) {
+ usage();
+ err = -EINVAL;
+ goto err;
+ }
+
+ /* Fill Asus tail */
+ tail.version[0] = version[0];
+ tail.version[1] = version[1];
+ tail.version[2] = version[2];
+ tail.version[3] = version[3];
+ strncpy(tail.productid, productid, sizeof(tail.productid));
+
+ /* Open files */
+ in = fopen(in_path, "r");
+ if (!in) {
+ fprintf(stderr, "Couldn't open %s\n", in_path);
+ err = -EIO;
+ goto err;
+ }
+ out = fopen(out_path, "w+");
+ if (!out) {
+ fprintf(stderr, "Couldn't open %s\n", out_path);
+ err = -EIO;
+ goto err;
+ }
+
+ /* Check is there is empty place for Asus tail */
+ bytes = sizeof(struct asustrx_tail);
+ fseek(in, -bytes, SEEK_END);
+ if (fread(buf, 1, bytes, in) != bytes) {
+ fprintf(stderr, "Couldn't read %zu B from %s\n", bytes, in_path);
+ err = -EIO;
+ goto err;
+ }
+ for (i = 0; i < bytes; i++) {
+ if (buf[i]) {
+ fprintf(stderr, "Input TRX doesn't have last 64 B empty %s\n", out_path);
+ err = -ENOSPC;
+ goto err;
+ }
+ }
+
+ /* Copy whole TRX */
+ rewind(in);
+ while ((bytes = fread(buf, 1, sizeof(buf), in)) > 0) {
+ if (fwrite(buf, 1, bytes, out) != bytes) {
+ fprintf(stderr, "Couldn't write %zu B to %s\n", bytes, out_path);
+ err = -EIO;
+ goto err;
+ }
+ }
+
+ /* Overwrite last 64 B with Asus tail */
+ bytes = sizeof(tail);
+ fseek(out, -bytes, SEEK_CUR);
+ if (fwrite(&tail, 1, bytes, out) != bytes) {
+ fprintf(stderr, "Couldn't write %zu B to %s\n", bytes, out_path);
+ err = -EIO;
+ goto err;
+ }
+
+ /* Calculate crc32 */
+ fseek(out, TRX_FLAGS_OFFSET, SEEK_SET);
+ length = TRX_FLAGS_OFFSET;
+ while ((bytes = fread(buf, 1, sizeof(buf), out )) > 0) {
+ length += bytes;
+ for (i = 0; i < bytes; i++)
+ crc32 = crc32_tbl[(crc32 ^ buf[i]) & 0xff] ^ (crc32 >> 8);
+ }
+
+ /* Update header */
+ bytes = sizeof(hdr);
+ rewind(out);
+ if (fread(&hdr, 1, sizeof(hdr), out) != bytes) {
+ fprintf(stderr, "Couldn't read %zu B from %s\n", bytes, in_path);
+ err = -EIO;
+ goto err;
+ }
+ hdr.crc32 = cpu_to_le32(crc32);
+ rewind(out);
+ if (fwrite(&hdr, 1, bytes, out) != bytes) {
+ fprintf(stderr, "Couldn't write %zu B to %s\n", bytes, out_path);
+ err = -EIO;
+ goto err;
+ }
+
+err:
+ if (out)
+ fclose(out);
+ if (in)
+ fclose(in);
+ return err;
+}
diff --git a/tools/firmware-utils/src/bcm_tag.h b/tools/firmware-utils/src/bcm_tag.h
index 2e977a2d7a6..2730edc9ad9 120000..100644
--- a/tools/firmware-utils/src/bcm_tag.h
+++ b/tools/firmware-utils/src/bcm_tag.h
@@ -1 +1,70 @@
-../../../target/linux/brcm63xx/files/arch/mips/include/asm/mach-bcm63xx/bcm_tag.h \ No newline at end of file
+#ifndef __BCM63XX_TAG_H
+#define __BCM63XX_TAG_H
+
+#define TAGVER_LEN 4 /* Length of Tag Version */
+#define TAGLAYOUT_LEN 4 /* Length of FlashLayoutVer */
+#define SIG1_LEN 20 /* Company Signature 1 Length */
+#define SIG2_LEN 14 /* Company Signature 2 Lenght */
+#define BOARDID_LEN 16 /* Length of BoardId */
+#define ENDIANFLAG_LEN 2 /* Endian Flag Length */
+#define CHIPID_LEN 6 /* Chip Id Length */
+#define IMAGE_LEN 10 /* Length of Length Field */
+#define ADDRESS_LEN 12 /* Length of Address field */
+#define DUALFLAG_LEN 2 /* Dual Image flag Length */
+#define INACTIVEFLAG_LEN 2 /* Inactie Flag Length */
+#define RSASIG_LEN 20 /* Length of RSA Signature in tag */
+#define TAGINFO1_LEN 30 /* Length of vendor information field1 in tag */
+#define FLASHLAYOUTVER_LEN 4 /* Length of Flash Layout Version String tag */
+#define TAGINFO2_LEN 16 /* Length of vendor information field2 in tag */
+#define CRC_LEN 4 /* Length of CRC in bytes */
+#define ALTTAGINFO_LEN 54 /* Alternate length for vendor information; Pirelli */
+
+#define NUM_PIRELLI 2
+#define IMAGETAG_CRC_START 0xFFFFFFFF
+
+#define PIRELLI_BOARDS { \
+ "AGPF-S0", \
+ "DWV-S0", \
+}
+
+/*
+ * The broadcom firmware assumes the rootfs starts the image,
+ * therefore uses the rootfs start (flashImageAddress)
+ * to determine where to flash the image. Since we have the kernel first
+ * we have to give it the kernel address, but the crc uses the length
+ * associated with this address (rootLength), which is added to the kernel
+ * length (kernelLength) to determine the length of image to flash and thus
+ * needs to be rootfs + deadcode (jffs2 EOF marker)
+*/
+
+struct bcm_tag {
+ char tagVersion[TAGVER_LEN]; // 0-3: Version of the image tag
+ char sig_1[SIG1_LEN]; // 4-23: Company Line 1
+ char sig_2[SIG2_LEN]; // 24-37: Company Line 2
+ char chipid[CHIPID_LEN]; // 38-43: Chip this image is for
+ char boardid[BOARDID_LEN]; // 44-59: Board name
+ char big_endian[ENDIANFLAG_LEN]; // 60-61: Map endianness -- 1 BE 0 LE
+ char totalLength[IMAGE_LEN]; // 62-71: Total length of image
+ char cfeAddress[ADDRESS_LEN]; // 72-83: Address in memory of CFE
+ char cfeLength[IMAGE_LEN]; // 84-93: Size of CFE
+ char flashImageStart[ADDRESS_LEN]; // 94-105: Address in memory of image start (kernel for OpenWRT, rootfs for stock firmware)
+ char flashRootLength[IMAGE_LEN]; // 106-115: Size of rootfs for flashing
+ char kernelAddress[ADDRESS_LEN]; // 116-127: Address in memory of kernel
+ char kernelLength[IMAGE_LEN]; // 128-137: Size of kernel
+ char dualImage[DUALFLAG_LEN]; // 138-139: Unused at present
+ char inactiveFlag[INACTIVEFLAG_LEN]; // 140-141: Unused at present
+ char rsa_signature[RSASIG_LEN]; // 142-161: RSA Signature (unused at present; some vendors may use this)
+ char information1[TAGINFO1_LEN]; // 162-191: Compilation and related information (not generated/used by OpenWRT)
+ char flashLayoutVer[FLASHLAYOUTVER_LEN];// 192-195: Version flash layout
+ char fskernelCRC[CRC_LEN]; // 196-199: kernel+rootfs CRC32
+ char information2[TAGINFO2_LEN]; // 200-215: Unused at present except Alice Gate where is is information
+ char imageCRC[CRC_LEN]; // 216-219: CRC32 of image less imagetag (kernel for Alice Gate)
+ char rootfsCRC[CRC_LEN]; // 220-223: CRC32 of rootfs partition
+ char kernelCRC[CRC_LEN]; // 224-227: CRC32 of kernel partition
+ char imageSequence[4]; // 228-231: Image sequence number
+ char rootLength[4]; // 232-235: steal from reserved1 to keep the real root length so we can use in the flash map even after we have change the rootLength to 0 to satisfy devices that check CRC on every boot
+ char headerCRC[CRC_LEN]; // 236-239: CRC32 of header excluding tagVersion
+ char reserved2[16]; // 240-255: Unused at present
+};
+
+#endif /* __BCM63XX_TAG_H */
diff --git a/tools/firmware-utils/src/bcmalgo.c b/tools/firmware-utils/src/bcmalgo.c
new file mode 100644
index 00000000000..e7d3b113bec
--- /dev/null
+++ b/tools/firmware-utils/src/bcmalgo.c
@@ -0,0 +1,248 @@
+#include <stdlib.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <string.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include "bcmalgo.h"
+
+
+#define UTIL_VERSION "0.1"
+#define ENDIAN_REVERSE_NEEDED
+
+uint32_t reverse_endian32 ( uint32_t data )
+{
+#ifdef ENDIAN_REVERSE_NEEDED
+ return 0 | ( data & 0x000000ff ) << 24
+ | ( data & 0x0000ff00 ) << 8
+ | ( data & 0x00ff0000 ) >> 8
+ | ( data & 0xff000000 ) >> 24;
+#else
+ return data;
+#endif
+}
+
+uint16_t reverse_endian16 ( uint16_t data )
+{
+#ifdef ENDIAN_REVERSE_NEEDED
+ return 0 | ( data & 0x00ff ) << 8
+ | ( data & 0xff00 ) >> 8;
+#else
+ return data;
+#endif
+}
+
+
+
+uint32_t get_buffer_crc ( char* filebuffer,size_t size )
+{
+
+ long crc=0xffffffffL;
+ long crcxor = 0xffffffffL;
+ long num4 = 0xffffffffL;
+ long num5 = size;
+ long num6 = 0x4c11db7L;
+ long num7 = 0x80000000L;
+ int i;
+ long j;
+ for ( i = 0; i < ( num5 ); i++ )
+ {
+ long num2 = filebuffer[i];
+ for ( j = 0x80L; j != 0L; j = j >> 1 )
+ {
+ long num3 = crc & num7;
+ crc = crc << 1;
+ if ( ( num2 & j ) != 0L )
+ {
+ num3 ^= num7;
+ }
+ if ( num3 != 0L )
+ {
+ crc ^= num6;
+ }
+ }
+ }
+ crc ^= crcxor;
+ crc &= num4;
+
+ uint8_t b1 = ( uint8_t ) ( ( crc & -16777216L ) >> 0x18 );
+ uint8_t b2 = ( uint8_t ) ( ( crc & 0xff0000L ) >> 0x10 );
+ uint8_t b3 = ( uint8_t ) ( ( crc & 0xff00L ) >> 8 );
+ uint8_t b4 = ( uint8_t ) ( crc & 0xffL );
+ int32_t crc_result = ( b1 | b2 << 8| b3 << 16| b4 <<24 );
+ return reverse_endian32 ( crc_result );
+}
+
+//Thnx to Vector for the algo.
+uint32_t get_file_crc ( char* filename )
+{
+ struct stat buf;
+ stat ( filename,&buf );
+ char* filebuffer = malloc ( buf.st_size+10 );
+ FILE* fd = fopen ( filename,"r" );
+ fread ( filebuffer, 1, buf.st_size,fd );
+ fclose ( fd );
+ uint32_t crc = get_buffer_crc ( filebuffer,buf.st_size );
+ free ( filebuffer );
+ return crc;
+}
+
+
+
+uint16_t get_hcs ( ldr_header_t* hd )
+{
+ uint8_t* head = ( uint8_t* ) hd;
+ uint8_t hcs_minor;
+ uint8_t hcs_major;
+ uint16_t n = 0xffff;
+ uint16_t m = 0;
+ int state = 0;
+ int i,j;
+ for ( i = 0; i < 0x54; i++ )
+ {
+ uint16_t m = head[i];
+ m = m << 8;
+ for ( j = 0; j < 8; j++ )
+ {
+ if ( ( ( n ^ m ) & 0x8000 ) == 0 )
+ {
+ state = 0;
+ }
+ else
+ {
+ state = 1;
+ }
+ n = n << 1;
+ if ( state )
+ {
+ n ^= 0x1021;
+ }
+ m = m << 1;
+ }
+ n &= 0xffff;
+ }
+ n ^= 0xffff;
+ hcs_major = ( uint8_t ) ( ( n & 0xff00 ) >> 8 );
+ hcs_minor = ( uint8_t ) ( n & 0xff );
+ uint16_t hcs = hcs_major <<8 | hcs_minor;
+ return hcs;
+}
+
+ldr_header_t* construct_header ( uint32_t magic, uint16_t rev_maj,uint16_t rev_min, uint32_t build_date, uint32_t filelen, uint32_t ldaddress, const char* filename, uint32_t crc_data )
+{
+ ldr_header_t* hd = malloc ( sizeof ( ldr_header_t ) );
+ hd->magic=reverse_endian16 ( magic );
+ hd->control=0; //FixMe: Make use of it once compression is around
+ hd->rev_min = reverse_endian16 ( rev_min );
+ hd->rev_maj = reverse_endian16 ( rev_maj );
+ hd->build_date = reverse_endian32 ( build_date );
+ hd->filelen = reverse_endian32 ( filelen );
+ hd->ldaddress = reverse_endian32 ( ldaddress );
+ printf ( "Creating header for %s...\n", filename );
+ if ( strlen ( filename ) >63 )
+ {
+ printf ( "[!] Filename too long - stripping it to 63 bytes.\n" );
+ strncpy ( ( char* ) &hd->filename, filename, 63 );
+ hd->filename[63]=0x00;
+ }
+ else
+ {
+ strcpy ( ( char* ) &hd->filename, filename );
+ }
+ hd->crc=reverse_endian32 ( crc_data );
+ hd->hcs = reverse_endian16 ( get_hcs ( hd ) );
+ return hd;
+}
+
+static char control_unc[] = "Uncompressed";
+static char control_lz[] = "LZRW1/KH";
+static char control_mlzo[] = "mini-LZO";
+static char control_nrv[] = "NRV2D99 [Bootloader?]";
+static char control_nstdlzma[] = "(non-standard) LZMA";
+static char control_unk[] = "Unknown";
+char* get_control_info ( uint16_t control )
+{
+ control = reverse_endian16 ( control );
+ switch ( control )
+ {
+ case 0:
+ return control_unc;
+ break;
+ case 1:
+ return control_lz;
+ break;
+ case 2:
+ return control_mlzo;
+ break;
+ case 3:
+ return control_unc;
+ break;
+ case 4:
+ return control_nrv;
+ break;
+ case 5:
+ return control_nstdlzma;
+ break;
+ case 6:
+ return control_unc;
+ break;
+ case 7:
+ return control_unc;
+ break;
+ default:
+ return control_unk;
+ break;
+ }
+
+}
+
+int dump_header ( ldr_header_t* hd )
+{
+ printf ( "=== Header Information ===\n" );
+ printf ( "Header magic:\t0x%04X\n",reverse_endian16 ( hd->magic ) );
+ printf ( "Control:\t0x%04X (%s)\n",reverse_endian16 ( hd->control ), get_control_info ( hd->control ) );
+ printf ( "Major rev. :\t0x%04X\n",reverse_endian16 ( hd->rev_maj ) );
+ printf ( "Minor rev. :\t0x%04X\n",reverse_endian16 ( hd->rev_min ) );
+ printf ( "File name :\t%s\n", ( char* ) &hd->filename );
+ printf ( "File length:\t%d bytes\n", reverse_endian32 ( hd->filelen ) );
+ printf ( "Build time:\t0x%08X //FixMe: print in human-readable form\n", reverse_endian32 ( hd->build_date ) ); //FixMe:
+ printf ( "HCS:\t\t0x%04X ",reverse_endian16 ( hd->hcs ) );
+ uint16_t hcs = get_hcs ( hd );
+ int ret=0;
+ if ( hcs ==reverse_endian16 ( hd->hcs ) )
+ {
+ printf ( "(OK!)\n" );
+ }
+ else
+ {
+ printf ( "(ERROR! expected 0x%04X)\n",hcs );
+ ret=1;
+ }
+//printf("HCS:\t0x%02X",reverse_endian32(hd->hcs));
+ printf ( "Load address:\t0x%08X\n", reverse_endian32 ( hd->ldaddress ) ); //FixMe:
+ printf ( "HNW:\t\t0x%04X\n",reverse_endian16 ( hd->her_znaet_chto ) ); //Hell knows what
+ printf ( "CRC:\t\t0x%08X\n",reverse_endian32 ( hd->crc ) );
+ printf ( "=== Binary Header Dump===\n" );
+ int i,j;
+ uint8_t* head = ( uint8_t* ) hd;
+ for ( i=0;i<=sizeof ( ldr_header_t );i++ )
+ {
+ if ( i % 8==0 )
+ printf ( "\n" );
+ printf ( "0x%02x ",head[i] );
+ }
+ printf ( "\n\n== End Of Header dump ==\n" );
+ return ret;
+}
+
+
+void print_copyright()
+{
+ printf ( "Part of bcm-utils package ver. " UTIL_VERSION " \n" );
+ printf ( "Copyright (C) 2009 Andrew 'Necromant' Andrianov\n"
+ "This is free software, and you are welcome to redistribute it\n"
+ "under certain conditions. See COPYING for details\n" );
+}
diff --git a/tools/firmware-utils/src/bcmalgo.h b/tools/firmware-utils/src/bcmalgo.h
new file mode 100644
index 00000000000..46647cf6d3d
--- /dev/null
+++ b/tools/firmware-utils/src/bcmalgo.h
@@ -0,0 +1,83 @@
+#ifndef bcmutils_H
+#define bcmutils_H
+
+typedef struct
+{
+ uint16_t magic;
+ uint16_t control;
+ uint16_t rev_maj;
+ uint16_t rev_min;
+ uint32_t build_date;
+ uint32_t filelen;
+ uint32_t ldaddress;
+ char filename[64];
+ uint16_t hcs;
+ uint16_t her_znaet_chto; //v dushe ne ebu
+ uint32_t crc;
+} ldr_header_t;
+
+
+/**
+ * Reverses endianess of a 32bit int, if the ENDIAN_REVERSE_NEEDED defined at compile-time
+ * @param data
+ * @return
+ */
+uint32_t reverse_endian32 ( uint32_t data );
+
+/**
+ * Reverses endianess of a 16bit int, if the ENDIAN_REVERSE_NEEDED defined at compile-time
+ * @param data
+ * @return
+ */
+uint16_t reverse_endian16 ( uint16_t data );
+/**
+ * Calculates the strange crc (used by bcm modems) of the file. Thnx fly out to Vector for the algorithm.
+ * @param filename
+ * @return
+ */
+uint32_t get_file_crc ( char* filename );
+
+/**
+ * Calculates HCS of the header.
+ * @param hd
+ * @return
+ */
+uint16_t get_hcs ( ldr_header_t* hd );
+
+/**
+ * Constructs the header of the image with the information given It also automagically calculates HCS and writes it there.
+ * @param magic - magic device bytes
+ * @param rev_maj - major revision
+ * @param rev_min - minor revision
+ * @param build_date - build date (seconds from EPOCH UTC)
+ * @param filelen - file length in bytes
+ * @param ldaddress - Load adress
+ * @param filename - filename
+ * @param crc_data - the crc of the data
+ * @return
+ */
+ldr_header_t* construct_header ( uint32_t magic, uint16_t rev_maj,uint16_t rev_min, uint32_t build_date, uint32_t filelen, uint32_t ldaddress, const char* filename, uint32_t crc_data );
+
+/**
+ * Dumps header information to stdout.
+ * @param hd
+ */
+int dump_header ( ldr_header_t* hd );
+
+
+/**
+ * Returns a null terminated string describing what the control number meens
+ * DO NOT FREE IT!!!
+ * @param control
+ * @return
+ */
+char* get_control_info ( uint16_t control );
+#endif
+
+/**
+ * Calculates bcmCRC of a data buffer.
+ * @param filebuffer - pointer to buffer
+ * @param size - buffer size
+ * @return
+ */
+uint32_t get_buffer_crc ( char* filebuffer, size_t size );
diff --git a/tools/firmware-utils/src/buffalo-enc.c b/tools/firmware-utils/src/buffalo-enc.c
index 13d270b3f73..08fad4ee61b 100644
--- a/tools/firmware-utils/src/buffalo-enc.c
+++ b/tools/firmware-utils/src/buffalo-enc.c
@@ -34,6 +34,8 @@ static unsigned char seed = 'O';
static char *product;
static char *version;
static int do_decrypt;
+static int offset;
+static int size;
void usage(int status)
{
@@ -52,6 +54,8 @@ void usage(int status)
" -p <product> set product name to <product>\n"
" -v <version> set version to <version>\n"
" -h show this screen\n"
+" -O Offset of encrypted data in file (decryption)\n"
+" -S Size of unencrypted data in file (encryption)\n"
);
exit(status);
@@ -85,8 +89,9 @@ static int decrypt_file(void)
memset(&ep, '\0', sizeof(ep));
ep.key = (unsigned char *) crypt_key;
+ ep.longstate = longstate;
- err = decrypt_buf(&ep, buf, src_len);
+ err = decrypt_buf(&ep, buf + offset, src_len - offset);
if (err) {
ERR("unable to decrypt '%s'", ifname);
goto out;
@@ -99,7 +104,7 @@ static int decrypt_file(void)
printf("Data len\t: %u\n", ep.datalen);
printf("Checksum\t: 0x%08x\n", ep.csum);
- err = write_buf_to_file(ofname, buf, ep.datalen);
+ err = write_buf_to_file(ofname, buf + offset, ep.datalen);
if (err) {
ERR("unable to write to file '%s'", ofname);
goto out;
@@ -115,7 +120,7 @@ out:
static int encrypt_file(void)
{
struct enc_param ep;
- ssize_t src_len;
+ ssize_t src_len, tail_dst, tail_len, tail_src;
unsigned char *buf;
uint32_t hdrlen;
ssize_t totlen = 0;
@@ -128,8 +133,12 @@ static int encrypt_file(void)
goto out;
}
- totlen = enc_compute_buf_len(product, version, src_len);
- hdrlen = enc_compute_header_len(product, version);
+ if (size) {
+ tail_dst = enc_compute_buf_len(product, version, size);
+ tail_len = src_len - size;
+ totlen = tail_dst + tail_len;
+ } else
+ totlen = enc_compute_buf_len(product, version, src_len);
buf = malloc(totlen);
if (buf == NULL) {
@@ -137,12 +146,21 @@ static int encrypt_file(void)
goto out;
}
+ hdrlen = enc_compute_header_len(product, version);
+
err = read_file_to_buf(ifname, &buf[hdrlen], src_len);
if (err) {
ERR("unable to read from file '%s'", ofname);
goto free_buf;
}
+ if (size) {
+ tail_src = hdrlen + size;
+ memmove(&buf[tail_dst], &buf[tail_src], tail_len);
+ memset(&buf[tail_src], 0, tail_dst - tail_src);
+ src_len = size;
+ }
+
memset(&ep, '\0', sizeof(ep));
ep.key = (unsigned char *) crypt_key;
ep.seed = seed;
@@ -238,7 +256,7 @@ int main(int argc, char *argv[])
while ( 1 ) {
int c;
- c = getopt(argc, argv, "adi:m:o:hp:v:k:r:s:");
+ c = getopt(argc, argv, "adi:m:o:hlp:v:k:O:r:s:S:");
if (c == -1)
break;
@@ -270,6 +288,12 @@ int main(int argc, char *argv[])
case 's':
seed = strtoul(optarg, NULL, 16);
break;
+ case 'O':
+ offset = strtoul(optarg, NULL, 0);
+ break;
+ case 'S':
+ size = strtoul(optarg, NULL, 0);
+ break;
case 'h':
usage(EXIT_SUCCESS);
break;
diff --git a/tools/firmware-utils/src/buffalo-lib.c b/tools/firmware-utils/src/buffalo-lib.c
index 29aee9f88dd..b1d5ede0a28 100644
--- a/tools/firmware-utils/src/buffalo-lib.c
+++ b/tools/firmware-utils/src/buffalo-lib.c
@@ -179,7 +179,7 @@ int bcrypt_buf(unsigned char seed, unsigned char *key, unsigned char *src,
uint32_t buffalo_csum(uint32_t csum, void *buf, unsigned long len)
{
- char *p = buf;
+ signed char *p = buf;
while (len--) {
int i;
@@ -249,10 +249,10 @@ static uint32_t get_be32(void *data)
static int check_magic(void *magic)
{
- if (!memcmp("start", magic, ENC_MAGIC_LEN));
+ if (!memcmp("start", magic, ENC_MAGIC_LEN))
return 0;
- if (!memcmp("asar1", magic, ENC_MAGIC_LEN));
+ if (!memcmp("asar1", magic, ENC_MAGIC_LEN))
return 0;
return -1;
diff --git a/tools/firmware-utils/src/buffalo-lib.h b/tools/firmware-utils/src/buffalo-lib.h
index ba8a5081294..7eb9bf53987 100644
--- a/tools/firmware-utils/src/buffalo-lib.h
+++ b/tools/firmware-utils/src/buffalo-lib.h
@@ -69,6 +69,26 @@ struct buffalo_tag2 {
uint8_t unknown2[3];
} __attribute ((packed));
+struct buffalo_tag3 {
+ unsigned char product[TAG_PRODUCT_LEN];
+ unsigned char brand[TAG_BRAND_LEN];
+ unsigned char ver_major[TAG_VERSION_LEN];
+ unsigned char ver_minor[TAG_VERSION_LEN];
+ unsigned char region_code[2];
+ uint32_t region_mask;
+ unsigned char unknown0[2];
+ unsigned char language[TAG_LANGUAGE_LEN];
+ unsigned char platform[TAG_PLATFORM_LEN];
+ unsigned char hwv[TAG_HWVER_LEN];
+ unsigned char hwv_val[TAG_HWVER_VAL_LEN];
+ uint8_t unknown1[24];
+
+ uint32_t total_len;
+ uint32_t crc;
+ uint32_t len1;
+ uint32_t base2;
+} __attribute ((packed));
+
#define ENC_PRODUCT_LEN 32
#define ENC_VERSION_LEN 8
#define ENC_MAGIC_LEN 6
diff --git a/tools/firmware-utils/src/buffalo-tag.c b/tools/firmware-utils/src/buffalo-tag.c
index b5db72ef968..6d479f7fba9 100644
--- a/tools/firmware-utils/src/buffalo-tag.c
+++ b/tools/firmware-utils/src/buffalo-tag.c
@@ -48,6 +48,7 @@ static uint32_t base2;
static char *region_code;
static uint32_t region_mask;
static int num_regions;
+static int dhp;
void usage(int status)
{
@@ -63,6 +64,7 @@ void usage(int status)
" -d <base2>\n"
" -f <flag> set flag to <flag>\n"
" -i <file> read input from the file <file>\n"
+" -I <file> read input from the file <file> for DHP series\n"
" -l <language> set language to <language>\n"
" -m <version> set minor version to <version>\n"
" -o <file> write output to the file <file>\n"
@@ -227,6 +229,37 @@ static void fixup_tag2(unsigned char *buf, ssize_t buflen)
tag->crc = htonl(buffalo_crc(buf, buflen));
}
+static void fixup_tag3(unsigned char *buf, ssize_t totlen)
+{
+ struct buffalo_tag3 *tag = (struct buffalo_tag3 *) buf;
+
+ memset(tag, '\0', sizeof(*tag));
+
+ memcpy(tag->brand, brand, strlen(brand));
+ memcpy(tag->product, product, strlen(product));
+ memcpy(tag->platform, platform, strlen(platform));
+ memcpy(tag->ver_major, major, strlen(major));
+ memcpy(tag->ver_minor, minor, strlen(minor));
+ memcpy(tag->language, language, strlen(language));
+
+ if (num_regions > 1) {
+ tag->region_code[0] = 'M';
+ tag->region_code[1] = '_';
+ tag->region_mask = htonl(region_mask);
+ } else {
+ memcpy(tag->region_code, region_code, 2);
+ }
+
+ tag->total_len = htonl(totlen);
+ tag->len1 = htonl(fsize[0]);
+ tag->base2 = htonl(base2);
+
+ if (hwver) {
+ memcpy(tag->hwv, "hwv", 3);
+ memcpy(tag->hwv_val, hwver, strlen(hwver));
+ }
+}
+
static int tag_file(void)
{
unsigned char *buf;
@@ -237,7 +270,9 @@ static int tag_file(void)
int ret = -1;
int i;
- if (num_files == 1)
+ if (dhp)
+ hdrlen = sizeof(struct buffalo_tag3);
+ else if (num_files == 1)
hdrlen = sizeof(struct buffalo_tag);
else
hdrlen = sizeof(struct buffalo_tag2);
@@ -270,7 +305,9 @@ static int tag_file(void)
offset += fsize[i];
}
- if (num_files == 1)
+ if (dhp)
+ fixup_tag3(buf, fsize[0] + 200);
+ else if (num_files == 1)
fixup_tag(buf, buflen);
else
fixup_tag2(buf, buflen);
@@ -299,7 +336,7 @@ int main(int argc, char *argv[])
while ( 1 ) {
int c;
- c = getopt(argc, argv, "a:b:c:d:f:hi:l:m:o:p:r:sv:w:");
+ c = getopt(argc, argv, "a:b:c:d:f:hi:l:m:o:p:r:sv:w:I:");
if (c == -1)
break;
@@ -319,6 +356,9 @@ int main(int argc, char *argv[])
case 'f':
flag = strtoul(optarg, NULL, 2);
break;
+ case 'I':
+ dhp = 1;
+ /* FALLTHROUGH */
case 'i':
err = process_ifname(optarg);
if (err)
diff --git a/tools/firmware-utils/src/buffalo-tftp.c b/tools/firmware-utils/src/buffalo-tftp.c
index 1a2551a41c7..087f9955b64 100644
--- a/tools/firmware-utils/src/buffalo-tftp.c
+++ b/tools/firmware-utils/src/buffalo-tftp.c
@@ -70,7 +70,6 @@ static int crypt_file(void)
{
unsigned char *buf = NULL;
ssize_t src_len;
- ssize_t crypt_len;
int err;
int ret = -1;
@@ -92,7 +91,6 @@ static int crypt_file(void)
goto out;
}
- crypt_len = (src_len > 512) ? 512 : src_len;
if (do_decrypt)
crypt_header(buf, 512, crypt_key2, crypt_key1);
else
diff --git a/tools/firmware-utils/src/csysimg.h b/tools/firmware-utils/src/csysimg.h
index 19dfbd4334c..65ab062f31e 100644
--- a/tools/firmware-utils/src/csysimg.h
+++ b/tools/firmware-utils/src/csysimg.h
@@ -49,6 +49,7 @@
#define SIG_BR6114WG SIG_BR6104IPC
#define SIG_BR6524K "2-K-"
#define SIG_BR6524KP "2-KP" /* FIXME: valid? */
+#define SIG_BR6524N "WNRA"
#define SIG_BR6524WG "2-WG" /* FIXME: valid? */
#define SIG_BR6524WP "2-WP" /* FIXME: valid? */
#define SIG_BR6541K "4--K"
diff --git a/tools/firmware-utils/src/dgfirmware.c b/tools/firmware-utils/src/dgfirmware.c
index 5ff3b69646d..e3257f10779 100644
--- a/tools/firmware-utils/src/dgfirmware.c
+++ b/tools/firmware-utils/src/dgfirmware.c
@@ -1,5 +1,6 @@
#include <stdlib.h>
#include <stdio.h>
+#include <string.h>
#define IMG_SIZE 0x3e0000
diff --git a/tools/firmware-utils/src/dgn3500sum.c b/tools/firmware-utils/src/dgn3500sum.c
new file mode 100644
index 00000000000..eb80e6c01b0
--- /dev/null
+++ b/tools/firmware-utils/src/dgn3500sum.c
@@ -0,0 +1,166 @@
+/* **************************************************************************
+
+ This program creates a modified 16bit checksum used for the Netgear
+ DGN3500 series routers. The difference between this and a standard
+ checksum is that every 0x100 bytes added 0x100 have to be subtracted
+ from the sum.
+
+ (C) 2013 Marco Antonio Mauro <marcus90 at gmail.com>
+
+ Based on previous unattributed work.
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ ************************************************************************* */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+unsigned char PidDataWW[70] =
+{
+ 0x73, 0x45, 0x72, 0x43, 0x6F, 0x4D, 0x6D, 0x00, 0x00, 0x00, 0x00, 0x59, 0x50, 0x35, 0x37, 0x32,
+ 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x37,
+ 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73,
+ 0x45, 0x72, 0x43, 0x6F, 0x4D, 0x6D,
+} ;
+
+unsigned char PidDataDE[70] =
+{
+ 0x73, 0x45, 0x72, 0x43, 0x6F, 0x4D, 0x6D, 0x00, 0x00, 0x00, 0x00, 0x59, 0x50, 0x35, 0x37, 0x32,
+ 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x37,
+ 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73,
+ 0x45, 0x72, 0x43, 0x6F, 0x4D, 0x6D,
+} ;
+
+unsigned char PidDataNA[70] =
+{
+ 0x73, 0x45, 0x72, 0x43, 0x6F, 0x4D, 0x6D, 0x00, 0x00, 0x00, 0x00, 0x59, 0x50, 0x35, 0x37, 0x32,
+ 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x37,
+ 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73,
+ 0x45, 0x72, 0x43, 0x6F, 0x4D, 0x6D,
+} ;
+
+/* *******************************************************************
+ Reads the file into memory and returns pointer to the buffer. */
+static char *readfile(char *filename, int *size)
+{
+ FILE *fp;
+ char *buffer;
+ struct stat info;
+
+ if (stat(filename,&info)!=0)
+ return NULL;
+
+ if ((fp=fopen(filename,"r"))==NULL)
+ return NULL;
+
+ buffer=NULL;
+ for (;;)
+ {
+ if ((buffer=(char *)malloc(info.st_size+1))==NULL)
+ break;
+
+ if (fread(buffer,1,info.st_size,fp)!=info.st_size)
+ {
+ free(buffer);
+ buffer=NULL;
+ break;
+ }
+
+ buffer[info.st_size]='\0';
+ if(size) *size = info.st_size;
+
+ break;
+ }
+
+ (void)fclose(fp);
+
+ return buffer;
+}
+
+
+/* ******************************************************************* */
+int main(int argc, char** argv)
+{
+ unsigned long start, i;
+ char *endptr, *buffer, *p;
+ int count; // size of file in bytes
+ unsigned short sum = 0, sum1 = 0;
+ char sumbuf[9];
+
+ if(argc < 3) {
+ printf("ERROR: Argument missing!\n\nUsage %s filename starting offset in hex [PID code]\n\n", argv[0]);
+ return 1;
+ }
+
+
+ FILE *fp = fopen(argv[1], "a");
+ if(!fp) {
+ printf("ERROR: File not writeable!\n");
+ return 1;
+ }
+ if(argc == 4)
+ {
+ printf("%s: PID type: %s\n", argv[0], argv[3]);
+ if(strcmp(argv[3], "DE")==0)
+ fwrite(PidDataDE, sizeof(PidDataDE), sizeof(char), fp); /* write DE pid */
+ else if(strcmp(argv[3], "NA")==0)
+ fwrite(PidDataNA, sizeof(PidDataNA), sizeof(char), fp); /* write NA pid */
+ else /* if(strcmp(argv[3], "WW")) */
+ fwrite(PidDataWW, sizeof(PidDataWW), sizeof(char), fp); /* write WW pid */
+ }
+ else
+ fwrite(PidDataWW, sizeof(PidDataWW), sizeof(char), fp); /* write WW pid if unspecified */
+
+ fclose(fp);
+
+ /* Read the file to calculate the checksums */
+ buffer = readfile(argv[1], &count);
+ if(!buffer) {
+ printf("ERROR: File %s not found!\n", argv[1]);
+ return 1;
+ }
+
+ p = buffer;
+ for(i = 0; i < count; i++)
+ {
+ sum += p[i];
+ }
+
+ start = strtol(argv[2], &endptr, 16);
+ p = buffer+start;
+ for(i = 0; i < count - start; i++)
+ {
+ sum1 += p[i];
+ }
+
+ sprintf(sumbuf,"%04X%04X",sum1,sum);
+ /* Append the 2 checksums to end of file */
+ fp = fopen(argv[1], "a");
+ if(!fp) {
+ printf("ERROR: File not writeable!\n");
+ return 1;
+ }
+ fwrite(sumbuf, 8, sizeof(char), fp);
+ fclose(fp);
+ free(buffer);
+ return 0;
+}
diff --git a/tools/firmware-utils/src/dns313-header.c b/tools/firmware-utils/src/dns313-header.c
new file mode 100644
index 00000000000..e69e57e7baa
--- /dev/null
+++ b/tools/firmware-utils/src/dns313-header.c
@@ -0,0 +1,239 @@
+/*
+ * dns313-header.c
+ *
+ * Program to add the modified U-Boot header to a binary used with
+ * the D-Link DNS-313 boot loader when booting directly from an
+ * EXT2 formatted hard drive.
+ *
+ * The DNS313 use the same header on zImage, ramdisk, rootfs.
+ *
+ * Written by Linus Walleij <linus.walleij@linaro.org>
+ * License terms: GPLv2
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+/*
+ * This is the U-Boot magic number, so the U-Boot header was used
+ * (obviously) as a template for this custom header.
+ */
+#define IH_MAGIC 0x27051956
+#define HEADER_SIZE 0x68
+
+#define OFFSET_MAGIC 0x00
+#define OFFSET_HCRC 0x04
+#define OFFSET_TIME 0x08
+#define OFFSET_SIZE 0x0c
+#define OFFSET_LOAD 0x10
+#define OFFSET_EP 0x14
+#define OFFSET_DCRC 0x18
+#define OFFSET_OS 0x1c
+#define OFFSET_ARCH 0x1d
+#define OFFSET_TYPE 0x1e
+#define OFFSET_COMP 0x1f
+#define OFFSET_NAME 0x20
+#define NAME_LEN 0x20
+#define OFFSET_MODEL 0x40
+#define MODEL_LEN 0x10
+#define OFFSET_VERSION 0x50
+#define VERSION_LEN 0x10
+#define OFFSET_MAC 0x60
+#define MAC_LEN 6
+
+static const uint32_t crc32_table[256] = {
+ 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,
+ 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL,
+ 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL,
+ 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL,
+ 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL,
+ 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL,
+ 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL,
+ 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL,
+ 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL,
+ 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL,
+ 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL,
+ 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,
+ 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL,
+ 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL,
+ 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL,
+ 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL,
+ 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL,
+ 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL,
+ 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL,
+ 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL,
+ 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL,
+ 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL,
+ 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL,
+ 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,
+ 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL,
+ 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL,
+ 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL,
+ 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL,
+ 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL,
+ 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL,
+ 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL,
+ 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL,
+ 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL,
+ 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL,
+ 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL,
+ 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,
+ 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL,
+ 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL,
+ 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL,
+ 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL,
+ 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL,
+ 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL,
+ 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL,
+ 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL,
+ 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL,
+ 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL,
+ 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL,
+ 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,
+ 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL,
+ 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL,
+ 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL,
+ 0x2d02ef8dUL
+};
+
+static uint32_t crc32(uint32_t crc,
+ const unsigned char *buf,
+ unsigned int len)
+{
+ crc = crc ^ 0xffffffffUL;
+ do {
+ crc = crc32_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8);
+ } while (--len);
+ return crc ^ 0xffffffffUL;
+}
+
+static void be_wr(unsigned char *buf, uint32_t val)
+{
+ buf[0] = (val >> 24) & 0xFFU;
+ buf[1] = (val >> 16) & 0xFFU;
+ buf[2] = (val >> 8) & 0xFFU;
+ buf[3] = val & 0xFFU;
+}
+
+int main(int argc, char **argv)
+{
+ int fdin;
+ int fdout;
+ struct stat sb;
+ uint32_t filesize;
+ uint32_t padding;
+ int ret = 0;
+ const char *pathin;
+ const char *pathout;
+ unsigned char *buffer;
+ unsigned char *infop;
+ uint32_t sum;
+ size_t bufsize;
+ size_t bytes;
+ int i;
+
+ if (argc < 3) {
+ printf("Too few arguments.\n");
+ printf("%s <infile> <outfile>\n", argv[0]);
+ }
+
+ pathin = argv[1];
+ pathout = argv[2];
+
+ ret = stat(pathin, &sb);
+ if (ret < 0)
+ return ret;
+
+ filesize = sb.st_size;
+ padding = filesize % 4;
+ printf("INFILE: %s, size: %08x bytes\n", pathin, filesize);
+ /* File + extended header size */
+ bufsize = filesize + HEADER_SIZE;
+
+ printf("Allocate %08x bytes\n", bufsize);
+ buffer = malloc(bufsize);
+ if (!buffer) {
+ printf("OOM: could not allocate buffer\n");
+ return 0;
+ }
+
+ memset(buffer, 0x00, bufsize);
+
+ /* Read file to buffer */
+ fdin = open(pathin, O_RDONLY);
+ if (!fdin) {
+ printf("ERROR: could not open input file\n");
+ return 0;
+ }
+ bytes = read(fdin, buffer + HEADER_SIZE, filesize);
+ if (bytes < filesize) {
+ printf("ERROR: could not read entire file\n");
+ return 0;
+ }
+ close(fdin);
+
+ /* PREP HEADER AND FOOTER */
+ infop = buffer;
+
+ be_wr(buffer + OFFSET_MAGIC, IH_MAGIC);
+
+ /* FIXME: use actual time */
+ be_wr(buffer + OFFSET_TIME, 0x4c06738c);
+ be_wr(buffer + OFFSET_SIZE, filesize);
+
+ /* Load address & entry point */
+ be_wr(buffer + OFFSET_LOAD, 0x00008000);
+ be_wr(buffer + OFFSET_EP, 0x00008000);
+
+ buffer[OFFSET_OS] = 0x05; /* Linux */
+ buffer[OFFSET_ARCH] = 0x02; /* ARM */
+ buffer[OFFSET_TYPE] = 0x02; /* OS kernel image */
+ buffer[OFFSET_COMP] = 0x01; /* gzip */
+
+ /* The vendor firmware just hardcodes this */
+ strncpy(buffer + OFFSET_NAME, "kernel.img", NAME_LEN);
+ buffer[OFFSET_NAME + NAME_LEN - 1] = '\0';
+ strncpy(buffer + OFFSET_MODEL, "dns-313v3", MODEL_LEN);
+ buffer[OFFSET_MODEL + MODEL_LEN - 1] = '\0';
+ strncpy(buffer + OFFSET_VERSION, "2.01b04", VERSION_LEN);
+ buffer[OFFSET_VERSION + VERSION_LEN - 1] = '\0';
+ /* Just some MAC address from the example */
+ buffer[OFFSET_MAC] = 0x00;
+ buffer[OFFSET_MAC + 1] = 0x80;
+ buffer[OFFSET_MAC + 2] = 0xc8;
+ buffer[OFFSET_MAC + 3] = 0x16;
+ buffer[OFFSET_MAC + 4] = 0x81;
+ buffer[OFFSET_MAC + 5] = 0x68;
+
+ /* Checksum payload */
+ sum = crc32(0, buffer + HEADER_SIZE, filesize);
+ be_wr(buffer + OFFSET_DCRC, sum);
+ printf("data checksum: 0x%08x\n", sum);
+
+ /* Checksum header, then write that into the header checksum */
+ sum = crc32(0, buffer, HEADER_SIZE);
+ be_wr(buffer + OFFSET_HCRC, sum);
+ printf("header checksum: 0x%08x\n", sum);
+
+ printf("OUTFILE: %s, size: %08x bytes\n", pathout, bufsize);
+ fdout = open(pathout, O_RDWR|O_CREAT|O_TRUNC,S_IRWXU|S_IRGRP);
+ if (!fdout) {
+ printf("ERROR: could not open output file\n");
+ return 0;
+ }
+ bytes = write(fdout, buffer, bufsize);
+ if (bytes < bufsize) {
+ printf("ERROR: could not write complete output file\n");
+ return 0;
+ }
+ close(fdout);
+
+ free(buffer);
+
+ return 0;
+}
diff --git a/tools/firmware-utils/src/edimax_fw_header.c b/tools/firmware-utils/src/edimax_fw_header.c
new file mode 100644
index 00000000000..b85e3a1781c
--- /dev/null
+++ b/tools/firmware-utils/src/edimax_fw_header.c
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2014 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * 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 <arpa/inet.h>
+#include <netinet/in.h>
+
+#define MAX_MAGIC_LEN 16
+#define MAX_MODEL_LEN 32
+#define MAX_VERSION_LEN 14
+#define MAX_MTD_NAME_LEN 16
+
+#define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
+
+struct edimax_header {
+ char magic[MAX_MAGIC_LEN];
+ char model[MAX_MODEL_LEN];
+ unsigned char force;
+ unsigned char header_csum;
+ unsigned char data_csum;
+ uint32_t data_size;
+ uint32_t start_addr;
+ uint32_t end_addr;
+ char fw_version[MAX_VERSION_LEN];
+ unsigned char type;
+ char mtd_name[MAX_MTD_NAME_LEN];
+} __attribute__ ((packed));
+
+/*
+ * Globals
+ */
+static char *ofname;
+static char *ifname;
+static char *progname;
+
+static char *model;
+static char *magic = "eDiMaX";
+static char *fw_version = "";
+static char *mtd_name;
+static int force;
+static uint32_t start_addr;
+static uint32_t end_addr;
+static uint8_t image_type;
+static int data_size;
+
+/*
+ * 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 DBG(fmt, ...) do { \
+ fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
+} while (0)
+
+static void usage(int status)
+{
+ FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+
+ fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+ fprintf(stream,
+"\n"
+"Options:\n"
+" -e <addr> set end addr to <addr>\n"
+" -f set force flag\n"
+" -h show this screen\n"
+" -i <file> read input data from the file <file>\n"
+" -o <file> write output to the file <file>\n"
+" -m <model> set model to <model>\n"
+" -M <magic> set image magic to <magic>\n"
+" -n <name> set MTD device name to <name>\n"
+" -s <addr> set start address to <addr>\n"
+" -t <type> set image type to <type>\n"
+" -v <version> set firmware version to <version>\n"
+ );
+
+ exit(status);
+}
+
+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
+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;
+}
+
+static int get_file_size(char *name)
+{
+ struct stat st;
+ int res;
+
+ res = stat(name, &st);
+ if (res){
+ ERRS("stat failed on %s", name);
+ return -1;
+ }
+
+ return st.st_size;
+}
+
+static int read_to_buf(char *name, char *buf, int buflen)
+{
+ FILE *f;
+ int ret = EXIT_FAILURE;
+
+ f = fopen(name, "r");
+ if (f == NULL) {
+ ERRS("could not open \"%s\" for reading", name);
+ goto out;
+ }
+
+ errno = 0;
+ fread(buf, buflen, 1, f);
+ if (errno != 0) {
+ ERRS("unable to read from file \"%s\"", name);
+ goto out_close;
+ }
+
+ ret = EXIT_SUCCESS;
+
+out_close:
+ fclose(f);
+out:
+ return ret;
+}
+
+static int check_options(void)
+{
+#define CHKSTR(_name, _msg) \
+ do { \
+ if (_name == NULL) { \
+ ERR("no %s specified", _msg); \
+ return -1; \
+ } \
+ } while (0)
+
+#define CHKSTRLEN(_name, _msg) \
+ do { \
+ int field_len; \
+ CHKSTR(_name, _msg); \
+ field_len = FIELD_SIZEOF(struct edimax_header, _name) - 1; \
+ if (strlen(_name) > field_len) { \
+ ERR("'%s' is too long, max %s length is %d", \
+ _name, _msg, field_len); \
+ return -1; \
+ } \
+ } while (0)
+
+ CHKSTR(ofname, "output file");
+ CHKSTR(ifname, "input file");
+
+ CHKSTRLEN(magic, "magic");
+ CHKSTRLEN(model, "model");
+ CHKSTRLEN(mtd_name, "MTD device name");
+ CHKSTRLEN(fw_version, "firware version");
+
+ data_size = get_file_size(ifname);
+ if (data_size < 0)
+ return -1;
+
+ return 0;
+}
+
+static int write_fw(char *data, int len)
+{
+ FILE *f;
+ int ret = EXIT_FAILURE;
+
+ f = fopen(ofname, "w");
+ if (f == NULL) {
+ ERRS("could not open \"%s\" for writing", ofname);
+ goto out;
+ }
+
+ errno = 0;
+ fwrite(data, len, 1, f);
+ if (errno) {
+ ERRS("unable to write output file");
+ goto out_flush;
+ }
+
+ DBG("firmware file \"%s\" completed", ofname);
+
+ ret = EXIT_SUCCESS;
+
+out_flush:
+ fflush(f);
+ fclose(f);
+ if (ret != EXIT_SUCCESS) {
+ unlink(ofname);
+ }
+out:
+ return ret;
+}
+
+static unsigned char checksum(unsigned char *p, unsigned len)
+{
+ unsigned char csum = 0;
+
+ while (len--)
+ csum += *p++;
+
+ csum ^= 0xb9;
+
+ return csum;
+}
+
+static int build_fw(void)
+{
+ int buflen;
+ char *buf;
+ char *data;
+ struct edimax_header *hdr;
+ int ret = EXIT_FAILURE;
+
+ buflen = sizeof(struct edimax_header) + data_size;
+
+ buf = malloc(buflen);
+ if (!buf) {
+ ERR("no memory for buffer\n");
+ goto out;
+ }
+
+ data = buf + sizeof(struct edimax_header);
+
+ /* read input file */
+ ret = read_to_buf(ifname, data, data_size);
+ if (ret)
+ goto out_free_buf;
+
+ /* fill firmware header */
+ hdr = (struct edimax_header *)buf;
+ memset(hdr, 0, sizeof(struct edimax_header));
+
+ strncpy(hdr->model, model, sizeof(hdr->model));
+ strncpy(hdr->magic, magic, sizeof(hdr->magic));
+ strncpy(hdr->fw_version, fw_version, sizeof(hdr->fw_version));
+ strncpy(hdr->mtd_name, mtd_name, sizeof(hdr->mtd_name));
+
+ hdr->force = force;
+ hdr->start_addr = htonl(start_addr);
+ hdr->end_addr = htonl(end_addr);
+ hdr->data_size = htonl(data_size);
+ hdr->type = image_type;
+
+ hdr->data_csum = checksum((unsigned char *)data, data_size);
+ hdr->header_csum = checksum((unsigned char *)hdr,
+ sizeof(struct edimax_header));
+
+ ret = write_fw(buf, buflen);
+ if (ret)
+ goto out_free_buf;
+
+ ret = EXIT_SUCCESS;
+
+out_free_buf:
+ free(buf);
+out:
+ return ret;
+}
+
+int main(int argc, char *argv[])
+{
+ int ret = EXIT_FAILURE;
+
+ progname = basename(argv[0]);
+
+ while (1) {
+ int c;
+
+ c = getopt(argc, argv, "e:fhi:o:m:M:n:s:t:v:");
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'e':
+ if (str2u32(optarg, &end_addr)) {
+ ERR("%s is invalid '%s'",
+ "end address", optarg);
+ goto out;
+ }
+ break;
+ case 'f':
+ force = 1;
+ break;
+ case 'i':
+ ifname = optarg;
+ break;
+ case 'h':
+ usage(EXIT_SUCCESS);
+ break;
+ case 'o':
+ ofname = optarg;
+ break;
+ case 'm':
+ model = optarg;
+ break;
+ case 'M':
+ magic = optarg;
+ break;
+ case 'n':
+ mtd_name = optarg;
+ break;
+ case 's':
+ if (str2u32(optarg, &start_addr)) {
+ ERR("%s is invalid '%s'",
+ "start address", optarg);
+ goto out;
+ }
+ break;
+ case 't':
+ if (str2u8(optarg, &image_type)) {
+ ERR("%s is invalid '%s'",
+ "image type", optarg);
+ goto out;
+ }
+ break;
+ case 'v':
+ fw_version = optarg;
+ break;
+ default:
+ usage(EXIT_FAILURE);
+ break;
+ }
+ }
+
+ ret = check_options();
+ if (ret)
+ goto out;
+
+ ret = build_fw();
+
+out:
+ return ret;
+}
diff --git a/tools/firmware-utils/src/fix-u-media-header.c b/tools/firmware-utils/src/fix-u-media-header.c
new file mode 100644
index 00000000000..21f184e66da
--- /dev/null
+++ b/tools/firmware-utils/src/fix-u-media-header.c
@@ -0,0 +1,354 @@
+/*
+ * Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * 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 "cyg_crc.h"
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#define IH_MAGIC 0x27051956 /* Image Magic Number */
+#define IH_NMLEN 32 /* Image Name Length */
+
+#define UM_MAGIC 0x55525F46
+#define UM_HEADER_LEN 12
+
+/*
+ * all data in network byte order (aka natural aka bigendian)
+ */
+struct u_media_header {
+ uint32_t ih_magic; /* Image Header Magic Number */
+ uint32_t ih_hcrc; /* Image Header CRC Checksum */
+ uint32_t ih_time; /* Image Creation Timestamp */
+ uint32_t ih_size; /* Image Data Size */
+ uint32_t ih_load; /* Data Load Address */
+ uint32_t ih_ep; /* Entry Point Address */
+ uint32_t ih_dcrc; /* Image Data CRC Checksum */
+ uint8_t ih_os; /* Operating System */
+ uint8_t ih_arch; /* CPU architecture */
+ uint8_t ih_type; /* Image Type */
+ uint8_t ih_comp; /* Compression Type */
+ uint8_t ih_name[IH_NMLEN - UM_HEADER_LEN]; /* Image Name */
+
+ uint32_t ih_UMedia_magic; /* U-Media magic number */
+ uint32_t ih_UMedia_boardID; /* U-Media board ID */
+ uint8_t ih_UMedia_imageType; /* U-Media image type */
+ uint8_t ih_UMedia_LoadDefault; /* U-Media load to factory default setting */
+ uint8_t ih_UMedia_temp1; /* U-Media didn't use this tag */
+ uint8_t ih_UMedia_temp2; /* U-Media didn't use this tag */
+} __attribute__ ((packed));
+
+struct if_info {
+ char *file_name; /* name of the file */
+ uint32_t file_size; /* length of the file */
+};
+
+static char *progname;
+static char *ofname;
+static struct if_info if_info;
+static int factory_defaults;
+static uint32_t board_id;
+static uint8_t image_type;
+
+/*
+ * 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 DBG(fmt, ...) do { \
+ fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
+} while (0)
+
+static void usage(int status)
+{
+ FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+
+ fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+ fprintf(stream,
+"\n"
+"Options:\n"
+" -B <board_id> set board ID to <board_id>\n"
+" -i <file> read input from the file <file>\n"
+" -F load factory defaults\n"
+" -o <file> write output to the file <file>\n"
+" -T <type> set image type to <type>\n"
+" -h show this screen\n"
+ );
+
+ exit(status);
+}
+
+static 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;
+}
+
+static 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)) {
+ return -1;
+ }
+
+ if (t > 255)
+ return -1;
+
+ *val = t;
+ return 0;
+}
+
+static int get_file_stat(struct if_info *fdata)
+{
+ struct stat st;
+ int res;
+
+ if (fdata->file_name == NULL)
+ return 0;
+
+ res = stat(fdata->file_name, &st);
+ if (res){
+ ERRS("stat failed on %s", fdata->file_name);
+ return res;
+ }
+
+ fdata->file_size = st.st_size;
+ return 0;
+}
+
+static int read_to_buf(struct if_info *fdata, char *buf)
+{
+ FILE *f;
+ int ret = EXIT_FAILURE;
+
+ f = fopen(fdata->file_name, "r");
+ if (f == NULL) {
+ ERRS("could not open \"%s\" for reading", fdata->file_name);
+ goto out;
+ }
+
+ errno = 0;
+ fread(buf, fdata->file_size, 1, f);
+ if (errno != 0) {
+ ERRS("unable to read from file \"%s\"", fdata->file_name);
+ goto out_close;
+ }
+
+ ret = EXIT_SUCCESS;
+
+out_close:
+ fclose(f);
+out:
+ return ret;
+}
+
+static int check_options(void)
+{
+ int ret;
+
+ if (ofname == NULL) {
+ ERR("no %s specified", "output file");
+ return -1;
+ }
+
+ if (if_info.file_name == NULL) {
+ ERR("no %s specified", "input file");
+ return -1;
+ }
+
+ ret = get_file_stat(&if_info);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int write_fw(char *data, int len)
+{
+ FILE *f;
+ int ret = EXIT_FAILURE;
+
+ f = fopen(ofname, "w");
+ if (f == NULL) {
+ ERRS("could not open \"%s\" for writing", ofname);
+ goto out;
+ }
+
+ errno = 0;
+ fwrite(data, len, 1, f);
+ if (errno) {
+ ERRS("unable to write output file");
+ goto out_flush;
+ }
+
+ ret = EXIT_SUCCESS;
+
+out_flush:
+ fflush(f);
+ fclose(f);
+ if (ret != EXIT_SUCCESS) {
+ unlink(ofname);
+ }
+out:
+ return ret;
+}
+
+static int fix_header(void)
+{
+ int buflen;
+ char *buf;
+ uint32_t crc, crc_orig;
+ struct u_media_header *hdr;
+ int ret = EXIT_FAILURE;
+
+ buflen = if_info.file_size;
+ if (buflen < sizeof(*hdr)) {
+ ERR("invalid input file\n");
+ return ret;
+ }
+
+ buf = malloc(buflen);
+ if (!buf) {
+ ERR("no memory for buffer\n");
+ goto out;
+ }
+
+ ret = read_to_buf(&if_info, buf);
+ if (ret)
+ goto out_free_buf;
+
+ hdr = (struct u_media_header *) buf;
+ if (ntohl(hdr->ih_magic) != IH_MAGIC) {
+ ERR("invalid input file, bad magic\n");
+ goto out_free_buf;
+ }
+
+ /* verify header CRC */
+ crc_orig = ntohl(hdr->ih_hcrc);
+ hdr->ih_hcrc = 0;
+ crc = cyg_ether_crc32((unsigned char *)hdr, sizeof(*hdr));
+ if (crc != crc_orig) {
+ ERR("invalid input file, bad header CRC\n");
+ goto out_free_buf;
+ }
+
+ hdr->ih_name[IH_NMLEN - UM_HEADER_LEN - 1] = '\0';
+
+ /* set U-Media specific fields */
+ hdr->ih_UMedia_magic = htonl(UM_MAGIC);
+ hdr->ih_UMedia_boardID = htonl(board_id);
+ hdr->ih_UMedia_imageType = image_type;
+ hdr->ih_UMedia_LoadDefault = (factory_defaults) ? 1 : 0;
+
+ /* update header CRC */
+ crc = cyg_ether_crc32((unsigned char *)hdr, sizeof(*hdr));
+ hdr->ih_hcrc = htonl(crc);
+
+ ret = write_fw(buf, buflen);
+ if (ret)
+ goto out_free_buf;
+
+ DBG("U-Media header fixed in \"%s\"", ofname);
+
+ ret = EXIT_SUCCESS;
+
+out_free_buf:
+ free(buf);
+out:
+ return ret;
+}
+
+int main(int argc, char *argv[])
+{
+ int ret = EXIT_FAILURE;
+
+ progname = basename(argv[0]);
+
+ while (1) {
+ int c;
+
+ c = getopt(argc, argv, "B:Fi:o:T:h");
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'B':
+ if (str2u32(optarg, &board_id)) {
+ ERR("%s is invalid '%s'",
+ "board ID", optarg);
+ goto out;
+ }
+ break;
+ case 'T':
+ if (str2u8(optarg, &image_type)) {
+ ERR("%s is invalid '%s'",
+ "image type", optarg);
+ goto out;
+ }
+ break;
+ case 'F':
+ factory_defaults = 1;
+ break;
+ case 'i':
+ if_info.file_name = optarg;
+ break;
+ case 'o':
+ ofname = optarg;
+ break;
+ case 'h':
+ usage(EXIT_SUCCESS);
+ break;
+ default:
+ usage(EXIT_FAILURE);
+ break;
+ }
+ }
+
+ ret = check_options();
+ if (ret)
+ goto out;
+
+ ret = fix_header();
+
+out:
+ return ret;
+}
diff --git a/tools/firmware-utils/src/hcsmakeimage.c b/tools/firmware-utils/src/hcsmakeimage.c
new file mode 100644
index 00000000000..7baa7b5845e
--- /dev/null
+++ b/tools/firmware-utils/src/hcsmakeimage.c
@@ -0,0 +1,203 @@
+#include <stdlib.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <string.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <libgen.h>
+#include "bcmalgo.h"
+
+
+int flag_print_version;
+int flag_print_help;
+int flag_compress;
+
+uint16_t sa2100_magic = 0x2100;
+uint16_t sa3349_magic = 0x3349;
+uint32_t default_date = 0x00000000; //A long time ago in a galaxy far far away....
+uint32_t default_load_address = 0x80010000; //The default load_address for the firmware image
+
+static void print_help ( const char* ename )
+{
+ printf ( "Firmware image packer and calculator for broadcom-based modems.\n" );
+ printf ( "Part of bcm-utils package.\n" );
+ printf ( "(c) 2009 Necromant (http://necromant.ath.cx). Thanks to Luke-jr for his initial work.\n" );
+ printf ( "usage: %s [options]\n", ename );
+ printf ( "Valid options are:\n" );
+ printf ( "--magic_bytes=value \t- specify magic bytes at the beginning of the image. default - 3349\n" );
+ printf ( "\t\t\t these can be sa2100 (for DPC2100 modem),\n\t\t\t sa3349 (haxorware guys use this one for some reason),\n\t\t\t or a custom hex value e.g. 0xFFFF\n" );
+ printf ( "--compress \t\t - Make use of LZMA (weird!) compression (Doesn't work yet).\n" );
+ printf ( "--rev_maj=value\t\t - major revision number. default 0\n" );
+ printf ( "--rev_min=value\t\t - minor revision number default 0\n" );
+ printf ( "--filename=value\t - use this filename in header instead of default (input filename)\n" );
+ printf ( "--ldaddress=value\t - hex value of the target load address. defaults to 0x80010000\n" );
+ printf ( "--input_file=value\t - What file are we packing?\n" );
+ printf ( "--output_file=value\t - What file shall we write? (default: image.bin)\n" );
+#ifdef _HAX0RSTYLE
+ printf ( "--credz\t - Give some credz!\n" );
+#endif
+ printf ( "\n" );
+}
+
+static time_t source_date_epoch = -1;
+static void set_source_date_epoch() {
+ char *env = getenv("SOURCE_DATE_EPOCH");
+ char *endptr = env;
+ errno = 0;
+ if (env && *env) {
+ source_date_epoch = strtoull(env, &endptr, 10);
+ if (errno || (endptr && *endptr != '\0')) {
+ fprintf(stderr, "Invalid SOURCE_DATE_EPOCH");
+ exit(1);
+ }
+ }
+}
+
+int main ( int argc, char** argv )
+{
+ if ( argc<2 )
+ {
+ print_help ( argv[0] );
+ }
+
+ static struct option long_options[] =
+ {
+ {"magic_bytes", required_argument, 0, 'm'},
+ {"rev_maj", required_argument, 0, 'j'},
+ {"rev_min", required_argument, 0, 'n'},
+ {"ldaddress", required_argument, 0, 'l'},
+ {"filename", required_argument, 0, 'f'},
+ {"input_file", required_argument, 0, 'i'},
+ {"output_file", required_argument, 0, 'o'},
+ {"compress", no_argument, &flag_compress, 'c'},
+ {"version", no_argument, &flag_print_version, 'v'},
+ {"help", no_argument, &flag_print_help, 'h'},
+ {0, 0, 0, 0}
+ };
+ int option_index = 0;
+ int opt_result=0;
+ char* filename=NULL;
+ char* input=NULL;
+ char* magic=NULL;
+ char* major=NULL;
+ char* minor=NULL;
+ char* ldaddr=NULL;
+ char* output=NULL;
+
+ while ( opt_result>=0 )
+ {
+ opt_result = getopt_long ( argc, argv, "m:j:n:f:i:o:vh", long_options, &option_index );
+ switch ( opt_result )
+ {
+ case 0:
+ printf ( "o!\n" );
+ break;
+ case 'h':
+ print_help ( argv[0] );
+ break;
+ case 'l':
+ ldaddr=optarg;
+ break;
+ case 'f':
+ filename=optarg;
+ break;
+ case 'i':
+ input=optarg;
+ break;
+ case 'o':
+ output=optarg;
+ break;
+ case 'm':
+ magic=optarg;
+ break;
+ case 'j':
+ major=optarg;
+ break;
+ case 'n':
+ minor=optarg;
+ break;
+ }
+ }
+ if ( input==NULL )
+ {
+ printf ( "Telepaths are still on holidays. I guess you should tell me what file should I process.\n\n" );
+ exit ( 1 );
+ }
+ if ( access ( input,R_OK ) !=0 )
+ {
+ printf ( "I cannot access the file %s. Is it there? Am I allowed?\n\n", input );
+ exit ( 1 );
+ }
+ uint32_t magicnum=sa2100_magic;
+
+ if ( magic )
+ {
+ if ( strcmp ( magic,"sa2100" ) ==0 ) magicnum=sa2100_magic; else
+ if ( strcmp ( magic,"sa3349" ) ==0 ) magicnum=sa3349_magic; else
+ {
+ sscanf ( magic, "0x%04X", &magicnum );
+ }
+ }
+ unsigned int majrev=0;
+ if ( major )
+ {
+ sscanf ( major, "%d", &majrev );
+ }
+ unsigned int minrev=0;
+ if ( minor )
+ {
+ sscanf ( minor, "%d", &minrev );
+ }
+ uint32_t ldaddress = default_load_address;
+ if ( ldaddr )
+ {
+ sscanf ( ldaddr, "0x%08X", &ldaddress );
+ }
+ char* dupe = strdup(input);
+ char* fname = basename ( dupe );
+ if ( filename )
+ {
+ fname = filename;
+ }
+
+ time_t t = -1;
+ set_source_date_epoch();
+ if (source_date_epoch != -1) {
+ t = source_date_epoch;
+ } else if ((time(&t) == (time_t)(-1))) {
+ fprintf(stderr, "time call failed\n");
+ return EXIT_FAILURE;
+ }
+
+ struct stat buf;
+ stat ( input,&buf );
+ ldr_header_t* head = construct_header ( magicnum, (uint16_t) majrev, (uint16_t) minrev, ( uint32_t ) t, ( uint32_t ) buf.st_size, ldaddress, fname, get_file_crc ( input ) );
+ free(dupe);
+ //uint32_t magic, uint16_t rev_maj,uint16_t rev_min, uint32_t build_date, uint32_t filelen, uint32_t ldaddress, const char* filename, uint32_t crc
+ //FILE* fd = fopen ("/tftpboot/haxorware11rev32.bin","r");
+ //fread(head,sizeof(ldr_header_t),1,fd);
+ char* filebuffer = malloc ( buf.st_size+10 );
+ FILE* fd = fopen ( input,"r" );
+ fread ( filebuffer, 1, buf.st_size,fd );
+ if (!output)
+ {
+ output = malloc(strlen(input+5));
+ strcpy(output,input);
+ strcat(output,".bin");
+ }
+ dump_header ( head );
+ FILE* fd_out = fopen ( output,"w+" );
+ if (!fd_out)
+ {
+ fprintf(stderr, "Failed to open output file: %s\n", output);
+ exit(1);
+ }
+ fwrite ( head,1,sizeof ( ldr_header_t ),fd_out );
+ fwrite ( filebuffer,1,buf.st_size,fd_out );
+ printf("Firmware image %s is ready\n", output);
+ return 0;
+}
diff --git a/tools/firmware-utils/src/imagetag.c b/tools/firmware-utils/src/imagetag.c
index bebaba2f29d..bc70399ccaa 100644
--- a/tools/firmware-utils/src/imagetag.c
+++ b/tools/firmware-utils/src/imagetag.c
@@ -11,13 +11,14 @@
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
-#include <time.h>
#include <unistd.h>
#include <sys/stat.h>
#include <netinet/in.h>
+#include <inttypes.h>
#include "bcm_tag.h"
#include "imagetag_cmdline.h"
+#include "cyg_crc.h"
#define DEADCODE 0xDEADC0DE
@@ -30,54 +31,11 @@ struct kernelhdr {
static char pirellitab[NUM_PIRELLI][BOARDID_LEN] = PIRELLI_BOARDS;
-static uint32_t crc32tab[256] = {
- 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
- 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
- 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
- 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
- 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
- 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
- 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
- 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
- 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
- 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
- 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
- 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
- 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
- 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
- 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
- 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
- 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
- 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
- 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
- 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
- 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
- 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
- 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
- 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
- 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
- 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
- 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
- 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
- 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
- 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
- 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
- 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
-};
-
void int2tag(char *tag, uint32_t value) {
uint32_t network = htonl(value);
memcpy(tag, (char *)(&network), 4);
}
-uint32_t crc32(uint32_t crc, uint8_t *data, size_t len)
-{
- while (len--)
- crc = (crc >> 8) ^ crc32tab[(crc ^ *data++) & 0xFF];
-
- return crc;
-}
-
uint32_t compute_crc32(uint32_t crc, FILE *binfile, size_t compute_start, size_t compute_len)
{
uint8_t readbuf[1024];
@@ -88,14 +46,14 @@ uint32_t compute_crc32(uint32_t crc, FILE *binfile, size_t compute_start, size_t
/* read block of 1024 bytes */
while (binfile && !feof(binfile) && !ferror(binfile) && (compute_len >= sizeof(readbuf))) {
read = fread(readbuf, sizeof(uint8_t), sizeof(readbuf), binfile);
- crc = crc32(crc, readbuf, read);
+ crc = cyg_crc32_accumulate(crc, readbuf, read);
compute_len = compute_len - read;
}
/* Less than 1024 bytes remains, read compute_len bytes */
if (binfile && !feof(binfile) && !ferror(binfile) && (compute_len > 0)) {
read = fread(readbuf, sizeof(uint8_t), compute_len, binfile);
- crc = crc32(crc, readbuf, read);
+ crc = cyg_crc32_accumulate(crc, readbuf, read);
}
return crc;
@@ -125,7 +83,8 @@ int tagfile(const char *kernel, const char *rootfs, const char *bin, \
struct kernelhdr khdr;
FILE *kernelfile = NULL, *rootfsfile = NULL, *binfile = NULL, *cfefile = NULL;
size_t cfeoff, cfelen, kerneloff, kernellen, rootfsoff, rootfslen, \
- read, imagelen, rootfsoffpadlen = 0, kernelfslen, kerneloffpadlen = 0, oldrootfslen;
+ read, imagelen, rootfsoffpadlen = 0, kernelfslen, kerneloffpadlen = 0, oldrootfslen, \
+ rootfsend;
uint8_t readbuf[1024];
uint32_t imagecrc = IMAGETAG_CRC_START;
uint32_t kernelcrc = IMAGETAG_CRC_START;
@@ -199,11 +158,19 @@ int tagfile(const char *kernel, const char *rootfs, const char *bin, \
kernellen += sizeof(khdr);
}
- /* Build the rootfs address and length (start and end do need to be aligned on flash erase block boundaries */
+ /* Build the rootfs address and length */
rootfsoff = kerneloff + kernellen;
- rootfsoff = (rootfsoff % block_size) > 0 ? (((rootfsoff / block_size) + 1) * block_size) : rootfsoff;
- rootfslen = getlen(rootfsfile);
- rootfslen = ( (rootfslen % block_size) > 0 ? (((rootfslen / block_size) + 1) * block_size) : rootfslen );
+ /* align the start if requested */
+ if (args->align_rootfs_flag)
+ rootfsoff = (rootfsoff % block_size) > 0 ? (((rootfsoff / block_size) + 1) * block_size) : rootfsoff;
+ else
+ rootfsoff = (rootfsoff % 4) > 0 ? (((rootfsoff / 4) + 1) * 4) : rootfsoff;
+
+ /* align the end */
+ rootfsend = rootfsoff + getlen(rootfsfile);
+ if ((rootfsend % block_size) > 0)
+ rootfsend = (((rootfsend / block_size) + 1) * block_size);
+ rootfslen = rootfsend - rootfsoff;
imagelen = rootfsoff + rootfslen - kerneloff + sizeof(deadcode);
rootfsoffpadlen = rootfsoff - (kerneloff + kernellen);
@@ -231,6 +198,19 @@ int tagfile(const char *kernel, const char *rootfs, const char *bin, \
fseek(binfile, rootfsoff + rootfslen - fwaddr + cfelen, SEEK_SET);
fwrite(&deadcode, sizeof(uint32_t), 1, binfile);
+ oldrootfslen = rootfslen;
+ if (args->pad_given) {
+ uint32_t allfs = 0xffffffff;
+ uint32_t pad_size = args->pad_arg * 1024 * 1024;
+
+ printf("Padding image to %d bytes ...\n", pad_size);
+ while (imagelen < pad_size) {
+ fwrite(&allfs, sizeof(uint32_t), 1, binfile);
+ imagelen += 4;
+ rootfslen += 4;
+ }
+ }
+
/* Flush the binfile buffer so that when we read from file, it contains
* everything in the buffer
*/
@@ -260,6 +240,7 @@ int tagfile(const char *kernel, const char *rootfs, const char *bin, \
rootfslen = oldrootfslen;
rootfslen = ( (rootfslen % block_size) > 0 ? (((rootfslen / block_size) + 1) * block_size) : rootfslen );
kerneloffpadlen = rootfslen - oldrootfslen;
+ oldrootfslen = rootfslen;
kerneloff = rootfsoff + rootfslen;
kernellen = getlen(kernelfile);
@@ -325,7 +306,7 @@ int tagfile(const char *kernel, const char *rootfs, const char *bin, \
sprintf(tag.totalLength, "%lu", imagelen);
if (args->cfe_given) {
- sprintf(tag.cfeAddress, "%lu", flash_start);
+ sprintf(tag.cfeAddress, "%" PRIu32, flash_start);
sprintf(tag.cfeLength, "%lu", cfelen);
} else {
/* We don't include CFE */
@@ -343,7 +324,7 @@ int tagfile(const char *kernel, const char *rootfs, const char *bin, \
sprintf(tag.flashImageStart, "%lu", kerneloff);
sprintf(tag.flashRootLength, "%lu", rootfslen + sizeof(deadcode));
}
- int2tag(tag.rootLength, rootfslen + sizeof(deadcode));
+ int2tag(tag.rootLength, oldrootfslen + sizeof(deadcode));
if (args->rsa_signature_given) {
strncpy(tag.rsa_signature, args->rsa_signature_arg, RSASIG_LEN);
@@ -366,7 +347,7 @@ int tagfile(const char *kernel, const char *rootfs, const char *bin, \
}
if (args->altinfo_given) {
- strncpy(&tag.information1[0], args->altinfo_arg, ALTTAGINFO_LEN);
+ strncpy(tag.information1, args->altinfo_arg, TAGINFO1_LEN);
}
if (args->second_image_flag_given) {
@@ -397,7 +378,7 @@ int tagfile(const char *kernel, const char *rootfs, const char *bin, \
int2tag(&(tag.rootfsCRC[0]), rootfscrc);
int2tag(tag.kernelCRC, kernelcrc);
int2tag(tag.fskernelCRC, kernelfscrc);
- int2tag(tag.headerCRC, crc32(IMAGETAG_CRC_START, (uint8_t*)&tag, sizeof(tag) - 20));
+ int2tag(tag.headerCRC, cyg_crc32_accumulate(IMAGETAG_CRC_START, (uint8_t*)&tag, sizeof(tag) - 20));
fseek(binfile, 0L, SEEK_SET);
fwrite(&tag, sizeof(uint8_t), sizeof(tag), binfile);
@@ -418,7 +399,7 @@ int main(int argc, char **argv)
kernel = rootfs = bin = NULL;
- if (cmdline_parser(argc, argv, &parsed_args)) {
+ if (imagetag_cmdline(argc, argv, &parsed_args)) {
exit(1);
}
@@ -483,6 +464,14 @@ int main(int argc, char **argv)
exit(1);
}
}
+
+ if (parsed_args.pad_given) {
+ if (parsed_args.pad_arg < 0) {
+ fprintf(stderr, "Error: pad size must be positive.\r");
+ exit(1);
+ }
+ }
+
flash_start = strtoul(parsed_args.flash_start_arg, NULL, 16);
image_offset = strtoul(parsed_args.image_offset_arg, NULL, 16);
block_size = strtoul(parsed_args.block_size_arg, NULL, 16);
diff --git a/tools/firmware-utils/src/imagetag.ggo b/tools/firmware-utils/src/imagetag.ggo
index 7e8e7d90e32..73184852935 100644
--- a/tools/firmware-utils/src/imagetag.ggo
+++ b/tools/firmware-utils/src/imagetag.ggo
@@ -42,3 +42,5 @@ option "second-image-flag" - "Dual Image Flag (2=not-specified)." values="0", "1
option "inactive" - "Inactive Flag (2=not-specified)." values="0", "1", "2" default="2" typestr="flag-value" optional
option "reserved2" - "String for second reserved section." string optional
option "kernel-file-has-header" - "Indicates that the kernel file includes the kernel header with correct load address and entry point, so no changes are needed" flag off
+option "pad" p "Pad the image to this size if smaller (in MiB)" int typestr="size (in MiB)" optional
+option "align-rootfs" - "Align the rootfs start to erase block size" flag off
diff --git a/tools/firmware-utils/src/imagetag_cmdline.c b/tools/firmware-utils/src/imagetag_cmdline.c
index 91ac90b09d0..86c90bbb678 100644
--- a/tools/firmware-utils/src/imagetag_cmdline.c
+++ b/tools/firmware-utils/src/imagetag_cmdline.c
@@ -1,7 +1,7 @@
/*
- File autogenerated by gengetopt version 2.22.4
+ File autogenerated by gengetopt version 2.22.5
generated with the following command:
- gengetopt --file-name=imagetag_cmdline --file-name=imagetag_cmdline
+ gengetopt -i imagetag.ggo -f imagetag_cmdline --file-name=imagetag_cmdline
The developers of gengetopt consider the fixed text that goes in all
gengetopt output files to be in the public domain:
@@ -58,13 +58,16 @@ const char *gengetopt_args_info_help[] = {
" --inactive=flag-value Inactive Flag (2=not-specified). (possible \n values=\"0\", \"1\", \"2\" default=`2')",
" --reserved2=STRING String for second reserved section.",
" --kernel-file-has-header Indicates that the kernel file includes the \n kernel header with correct load address and \n entry point, so no changes are needed \n (default=off)",
+ " -p, --pad=size (in MiB) Pad the image to this size if smaller (in MiB)",
+ " --align-rootfs Align the rootfs start to erase block size \n (default=off)",
0
};
typedef enum {ARG_NO
, ARG_FLAG
, ARG_STRING
-} cmdline_parser_arg_type;
+ , ARG_INT
+} imagetag_cmdline_arg_type;
static
void clear_given (struct gengetopt_args_info *args_info);
@@ -72,14 +75,14 @@ static
void clear_args (struct gengetopt_args_info *args_info);
static int
-cmdline_parser_internal (int argc, char **argv, struct gengetopt_args_info *args_info,
- struct cmdline_parser_params *params, const char *additional_error);
+imagetag_cmdline_internal (int argc, char **argv, struct gengetopt_args_info *args_info,
+ struct imagetag_cmdline_params *params, const char *additional_error);
static int
-cmdline_parser_required2 (struct gengetopt_args_info *args_info, const char *prog_name, const char *additional_error);
+imagetag_cmdline_required2 (struct gengetopt_args_info *args_info, const char *prog_name, const char *additional_error);
-const char *cmdline_parser_second_image_flag_values[] = {"0", "1", "2", 0}; /*< Possible values for second-image-flag. */
-const char *cmdline_parser_inactive_values[] = {"0", "1", "2", 0}; /*< Possible values for inactive. */
+const char *imagetag_cmdline_second_image_flag_values[] = {"0", "1", "2", 0}; /*< Possible values for second-image-flag. */
+const char *imagetag_cmdline_inactive_values[] = {"0", "1", "2", 0}; /*< Possible values for inactive. */
static char *
gengetopt_strdup (const char *s);
@@ -113,6 +116,8 @@ void clear_given (struct gengetopt_args_info *args_info)
args_info->inactive_given = 0 ;
args_info->reserved2_given = 0 ;
args_info->kernel_file_has_header_given = 0 ;
+ args_info->pad_given = 0 ;
+ args_info->align_rootfs_given = 0 ;
}
static
@@ -165,6 +170,8 @@ void clear_args (struct gengetopt_args_info *args_info)
args_info->reserved2_arg = NULL;
args_info->reserved2_orig = NULL;
args_info->kernel_file_has_header_flag = 0;
+ args_info->pad_orig = NULL;
+ args_info->align_rootfs_flag = 0;
}
@@ -199,19 +206,21 @@ void init_args_info(struct gengetopt_args_info *args_info)
args_info->inactive_help = gengetopt_args_info_help[23] ;
args_info->reserved2_help = gengetopt_args_info_help[24] ;
args_info->kernel_file_has_header_help = gengetopt_args_info_help[25] ;
+ args_info->pad_help = gengetopt_args_info_help[26] ;
+ args_info->align_rootfs_help = gengetopt_args_info_help[27] ;
}
void
-cmdline_parser_print_version (void)
+imagetag_cmdline_print_version (void)
{
printf ("%s %s\n",
- (strlen(CMDLINE_PARSER_PACKAGE_NAME) ? CMDLINE_PARSER_PACKAGE_NAME : CMDLINE_PARSER_PACKAGE),
- CMDLINE_PARSER_VERSION);
+ (strlen(IMAGETAG_CMDLINE_PACKAGE_NAME) ? IMAGETAG_CMDLINE_PACKAGE_NAME : IMAGETAG_CMDLINE_PACKAGE),
+ IMAGETAG_CMDLINE_VERSION);
}
static void print_help_common(void) {
- cmdline_parser_print_version ();
+ imagetag_cmdline_print_version ();
if (strlen(gengetopt_args_info_purpose) > 0)
printf("\n%s\n", gengetopt_args_info_purpose);
@@ -226,7 +235,7 @@ static void print_help_common(void) {
}
void
-cmdline_parser_print_help (void)
+imagetag_cmdline_print_help (void)
{
int i = 0;
print_help_common();
@@ -235,7 +244,7 @@ cmdline_parser_print_help (void)
}
void
-cmdline_parser_init (struct gengetopt_args_info *args_info)
+imagetag_cmdline_init (struct gengetopt_args_info *args_info)
{
clear_given (args_info);
clear_args (args_info);
@@ -243,7 +252,7 @@ cmdline_parser_init (struct gengetopt_args_info *args_info)
}
void
-cmdline_parser_params_init(struct cmdline_parser_params *params)
+imagetag_cmdline_params_init(struct imagetag_cmdline_params *params)
{
if (params)
{
@@ -255,12 +264,12 @@ cmdline_parser_params_init(struct cmdline_parser_params *params)
}
}
-struct cmdline_parser_params *
-cmdline_parser_params_create(void)
+struct imagetag_cmdline_params *
+imagetag_cmdline_params_create(void)
{
- struct cmdline_parser_params *params =
- (struct cmdline_parser_params *)malloc(sizeof(struct cmdline_parser_params));
- cmdline_parser_params_init(params);
+ struct imagetag_cmdline_params *params =
+ (struct imagetag_cmdline_params *)malloc(sizeof(struct imagetag_cmdline_params));
+ imagetag_cmdline_params_init(params);
return params;
}
@@ -276,7 +285,7 @@ free_string_field (char **s)
static void
-cmdline_parser_release (struct gengetopt_args_info *args_info)
+imagetag_cmdline_release (struct gengetopt_args_info *args_info)
{
free_string_field (&(args_info->kernel_arg));
@@ -323,6 +332,7 @@ cmdline_parser_release (struct gengetopt_args_info *args_info)
free_string_field (&(args_info->inactive_orig));
free_string_field (&(args_info->reserved2_arg));
free_string_field (&(args_info->reserved2_orig));
+ free_string_field (&(args_info->pad_orig));
@@ -384,13 +394,13 @@ write_into_file(FILE *outfile, const char *opt, const char *arg, const char *val
int
-cmdline_parser_dump(FILE *outfile, struct gengetopt_args_info *args_info)
+imagetag_cmdline_dump(FILE *outfile, struct gengetopt_args_info *args_info)
{
int i = 0;
if (!outfile)
{
- fprintf (stderr, "%s: cannot dump options to stream\n", CMDLINE_PARSER_PACKAGE);
+ fprintf (stderr, "%s: cannot dump options to stream\n", IMAGETAG_CMDLINE_PACKAGE);
return EXIT_FAILURE;
}
@@ -439,13 +449,17 @@ cmdline_parser_dump(FILE *outfile, struct gengetopt_args_info *args_info)
if (args_info->rsa_signature_given)
write_into_file(outfile, "rsa-signature", args_info->rsa_signature_orig, 0);
if (args_info->second_image_flag_given)
- write_into_file(outfile, "second-image-flag", args_info->second_image_flag_orig, cmdline_parser_second_image_flag_values);
+ write_into_file(outfile, "second-image-flag", args_info->second_image_flag_orig, imagetag_cmdline_second_image_flag_values);
if (args_info->inactive_given)
- write_into_file(outfile, "inactive", args_info->inactive_orig, cmdline_parser_inactive_values);
+ write_into_file(outfile, "inactive", args_info->inactive_orig, imagetag_cmdline_inactive_values);
if (args_info->reserved2_given)
write_into_file(outfile, "reserved2", args_info->reserved2_orig, 0);
if (args_info->kernel_file_has_header_given)
write_into_file(outfile, "kernel-file-has-header", 0, 0 );
+ if (args_info->pad_given)
+ write_into_file(outfile, "pad", args_info->pad_orig, 0);
+ if (args_info->align_rootfs_given)
+ write_into_file(outfile, "align-rootfs", 0, 0 );
i = EXIT_SUCCESS;
@@ -453,7 +467,7 @@ cmdline_parser_dump(FILE *outfile, struct gengetopt_args_info *args_info)
}
int
-cmdline_parser_file_save(const char *filename, struct gengetopt_args_info *args_info)
+imagetag_cmdline_file_save(const char *filename, struct gengetopt_args_info *args_info)
{
FILE *outfile;
int i = 0;
@@ -462,20 +476,20 @@ cmdline_parser_file_save(const char *filename, struct gengetopt_args_info *args_
if (!outfile)
{
- fprintf (stderr, "%s: cannot open file for writing: %s\n", CMDLINE_PARSER_PACKAGE, filename);
+ fprintf (stderr, "%s: cannot open file for writing: %s\n", IMAGETAG_CMDLINE_PACKAGE, filename);
return EXIT_FAILURE;
}
- i = cmdline_parser_dump(outfile, args_info);
+ i = imagetag_cmdline_dump(outfile, args_info);
fclose (outfile);
return i;
}
void
-cmdline_parser_free (struct gengetopt_args_info *args_info)
+imagetag_cmdline_free (struct gengetopt_args_info *args_info)
{
- cmdline_parser_release (args_info);
+ imagetag_cmdline_release (args_info);
}
/** @brief replacement of strdup, which is not standard */
@@ -494,21 +508,21 @@ gengetopt_strdup (const char *s)
}
int
-cmdline_parser (int argc, char **argv, struct gengetopt_args_info *args_info)
+imagetag_cmdline (int argc, char **argv, struct gengetopt_args_info *args_info)
{
- return cmdline_parser2 (argc, argv, args_info, 0, 1, 1);
+ return imagetag_cmdline2 (argc, argv, args_info, 0, 1, 1);
}
int
-cmdline_parser_ext (int argc, char **argv, struct gengetopt_args_info *args_info,
- struct cmdline_parser_params *params)
+imagetag_cmdline_ext (int argc, char **argv, struct gengetopt_args_info *args_info,
+ struct imagetag_cmdline_params *params)
{
int result;
- result = cmdline_parser_internal (argc, argv, args_info, params, 0);
+ result = imagetag_cmdline_internal (argc, argv, args_info, params, 0);
if (result == EXIT_FAILURE)
{
- cmdline_parser_free (args_info);
+ imagetag_cmdline_free (args_info);
exit (EXIT_FAILURE);
}
@@ -516,10 +530,10 @@ cmdline_parser_ext (int argc, char **argv, struct gengetopt_args_info *args_info
}
int
-cmdline_parser2 (int argc, char **argv, struct gengetopt_args_info *args_info, int override, int initialize, int check_required)
+imagetag_cmdline2 (int argc, char **argv, struct gengetopt_args_info *args_info, int override, int initialize, int check_required)
{
int result;
- struct cmdline_parser_params params;
+ struct imagetag_cmdline_params params;
params.override = override;
params.initialize = initialize;
@@ -527,11 +541,11 @@ cmdline_parser2 (int argc, char **argv, struct gengetopt_args_info *args_info, i
params.check_ambiguity = 0;
params.print_errors = 1;
- result = cmdline_parser_internal (argc, argv, args_info, &params, 0);
+ result = imagetag_cmdline_internal (argc, argv, args_info, &params, 0);
if (result == EXIT_FAILURE)
{
- cmdline_parser_free (args_info);
+ imagetag_cmdline_free (args_info);
exit (EXIT_FAILURE);
}
@@ -539,16 +553,16 @@ cmdline_parser2 (int argc, char **argv, struct gengetopt_args_info *args_info, i
}
int
-cmdline_parser_required (struct gengetopt_args_info *args_info, const char *prog_name)
+imagetag_cmdline_required (struct gengetopt_args_info *args_info, const char *prog_name)
{
int result = EXIT_SUCCESS;
- if (cmdline_parser_required2(args_info, prog_name, 0) > 0)
+ if (imagetag_cmdline_required2(args_info, prog_name, 0) > 0)
result = EXIT_FAILURE;
if (result == EXIT_FAILURE)
{
- cmdline_parser_free (args_info);
+ imagetag_cmdline_free (args_info);
exit (EXIT_FAILURE);
}
@@ -556,7 +570,7 @@ cmdline_parser_required (struct gengetopt_args_info *args_info, const char *prog
}
int
-cmdline_parser_required2 (struct gengetopt_args_info *args_info, const char *prog_name, const char *additional_error)
+imagetag_cmdline_required2 (struct gengetopt_args_info *args_info, const char *prog_name, const char *additional_error)
{
int error = 0;
FIX_UNUSED (additional_error);
@@ -623,8 +637,8 @@ static char *package_name = 0;
* @param possible_values the possible values for this option (if specified)
* @param default_value the default value (in case the option only accepts fixed values)
* @param arg_type the type of this option
- * @param check_ambiguity @see cmdline_parser_params.check_ambiguity
- * @param override @see cmdline_parser_params.override
+ * @param check_ambiguity @see imagetag_cmdline_params.check_ambiguity
+ * @param override @see imagetag_cmdline_params.override
* @param no_free whether to free a possible previous value
* @param multiple_option whether this is a multiple option
* @param long_opt the corresponding long option
@@ -636,7 +650,7 @@ int update_arg(void *field, char **orig_field,
unsigned int *field_given, unsigned int *prev_given,
char *value, const char *possible_values[],
const char *default_value,
- cmdline_parser_arg_type arg_type,
+ imagetag_cmdline_arg_type arg_type,
int check_ambiguity, int override,
int no_free, int multiple_option,
const char *long_opt, char short_opt,
@@ -690,6 +704,9 @@ int update_arg(void *field, char **orig_field,
case ARG_FLAG:
*((int *)field) = !*((int *)field);
break;
+ case ARG_INT:
+ if (val) *((int *)field) = strtol (val, &stop_char, 0);
+ break;
case ARG_STRING:
if (val) {
string_field = (char **)field;
@@ -702,6 +719,17 @@ int update_arg(void *field, char **orig_field,
break;
};
+ /* check numeric conversion */
+ switch(arg_type) {
+ case ARG_INT:
+ if (val && !(stop_char && *stop_char == '\0')) {
+ fprintf(stderr, "%s: invalid numeric value: %s\n", package_name, val);
+ return 1; /* failure */
+ }
+ break;
+ default:
+ ;
+ };
/* store the original value */
switch(arg_type) {
@@ -725,9 +753,9 @@ int update_arg(void *field, char **orig_field,
int
-cmdline_parser_internal (
+imagetag_cmdline_internal (
int argc, char **argv, struct gengetopt_args_info *args_info,
- struct cmdline_parser_params *params, const char *additional_error)
+ struct imagetag_cmdline_params *params, const char *additional_error)
{
int c; /* Character of the parsed option. */
@@ -747,9 +775,9 @@ cmdline_parser_internal (
check_ambiguity = params->check_ambiguity;
if (initialize)
- cmdline_parser_init (args_info);
+ imagetag_cmdline_init (args_info);
- cmdline_parser_init (&local_args_info);
+ imagetag_cmdline_init (&local_args_info);
optarg = 0;
optind = 0;
@@ -787,23 +815,25 @@ cmdline_parser_internal (
{ "inactive", 1, NULL, 0 },
{ "reserved2", 1, NULL, 0 },
{ "kernel-file-has-header", 0, NULL, 0 },
+ { "pad", 1, NULL, 'p' },
+ { "align-rootfs", 0, NULL, 0 },
{ 0, 0, 0, 0 }
};
- c = getopt_long (argc, argv, "hVi:f:o:b:c:s:n:v:a:m:k:l:e:y:1:2:r:", long_options, &option_index);
+ c = getopt_long (argc, argv, "hVi:f:o:b:c:s:n:v:a:m:k:l:e:y:1:2:r:p:", long_options, &option_index);
if (c == -1) break; /* Exit from `while (1)' loop. */
switch (c)
{
case 'h': /* Print help and exit. */
- cmdline_parser_print_help ();
- cmdline_parser_free (&local_args_info);
+ imagetag_cmdline_print_help ();
+ imagetag_cmdline_free (&local_args_info);
exit (EXIT_SUCCESS);
case 'V': /* Print version and exit. */
- cmdline_parser_print_version ();
- cmdline_parser_free (&local_args_info);
+ imagetag_cmdline_print_version ();
+ imagetag_cmdline_free (&local_args_info);
exit (EXIT_SUCCESS);
case 'i': /* File with LZMA compressed kernel to include in the image.. */
@@ -1010,6 +1040,18 @@ cmdline_parser_internal (
goto failure;
break;
+ case 'p': /* Pad the image to this size if smaller (in MiB). */
+
+
+ if (update_arg( (void *)&(args_info->pad_arg),
+ &(args_info->pad_orig), &(args_info->pad_given),
+ &(local_args_info.pad_given), optarg, 0, 0, ARG_INT,
+ check_ambiguity, override, 0, 0,
+ "pad", 'p',
+ additional_error))
+ goto failure;
+
+ break;
case 0: /* Long option with no short option */
/* File with CFE to include in the image.. */
@@ -1059,7 +1101,7 @@ cmdline_parser_internal (
if (update_arg( (void *)&(args_info->second_image_flag_arg),
&(args_info->second_image_flag_orig), &(args_info->second_image_flag_given),
- &(local_args_info.second_image_flag_given), optarg, cmdline_parser_second_image_flag_values, "2", ARG_STRING,
+ &(local_args_info.second_image_flag_given), optarg, imagetag_cmdline_second_image_flag_values, "2", ARG_STRING,
check_ambiguity, override, 0, 0,
"second-image-flag", '-',
additional_error))
@@ -1073,7 +1115,7 @@ cmdline_parser_internal (
if (update_arg( (void *)&(args_info->inactive_arg),
&(args_info->inactive_orig), &(args_info->inactive_given),
- &(local_args_info.inactive_given), optarg, cmdline_parser_inactive_values, "2", ARG_STRING,
+ &(local_args_info.inactive_given), optarg, imagetag_cmdline_inactive_values, "2", ARG_STRING,
check_ambiguity, override, 0, 0,
"inactive", '-',
additional_error))
@@ -1106,6 +1148,18 @@ cmdline_parser_internal (
goto failure;
}
+ /* Align the rootfs start to erase block size. */
+ else if (strcmp (long_options[option_index].name, "align-rootfs") == 0)
+ {
+
+
+ if (update_arg((void *)&(args_info->align_rootfs_flag), 0, &(args_info->align_rootfs_given),
+ &(local_args_info.align_rootfs_given), optarg, 0, 0, ARG_FLAG,
+ check_ambiguity, override, 1, 0, "align-rootfs", '-',
+ additional_error))
+ goto failure;
+
+ }
break;
case '?': /* Invalid option. */
@@ -1113,7 +1167,7 @@ cmdline_parser_internal (
goto failure;
default: /* bug: option not considered. */
- fprintf (stderr, "%s: option unknown: %c%s\n", CMDLINE_PARSER_PACKAGE, c, (additional_error ? additional_error : ""));
+ fprintf (stderr, "%s: option unknown: %c%s\n", IMAGETAG_CMDLINE_PACKAGE, c, (additional_error ? additional_error : ""));
abort ();
} /* switch */
} /* while */
@@ -1122,10 +1176,10 @@ cmdline_parser_internal (
if (check_required)
{
- error += cmdline_parser_required2 (args_info, argv[0], additional_error);
+ error += imagetag_cmdline_required2 (args_info, argv[0], additional_error);
}
- cmdline_parser_release (&local_args_info);
+ imagetag_cmdline_release (&local_args_info);
if ( error )
return (EXIT_FAILURE);
@@ -1134,6 +1188,6 @@ cmdline_parser_internal (
failure:
- cmdline_parser_release (&local_args_info);
+ imagetag_cmdline_release (&local_args_info);
return (EXIT_FAILURE);
}
diff --git a/tools/firmware-utils/src/imagetag_cmdline.h b/tools/firmware-utils/src/imagetag_cmdline.h
index c566a9f2932..3f55c509bb3 100644
--- a/tools/firmware-utils/src/imagetag_cmdline.h
+++ b/tools/firmware-utils/src/imagetag_cmdline.h
@@ -1,6 +1,6 @@
/** @file imagetag_cmdline.h
* @brief The header file for the command line option parser
- * generated by GNU Gengetopt version 2.22.4
+ * generated by GNU Gengetopt version 2.22.5
* http://www.gnu.org/software/gengetopt.
* DO NOT modify this file, since it can be overwritten
* @author GNU Gengetopt by Lorenzo Bettini */
@@ -19,19 +19,19 @@
extern "C" {
#endif /* __cplusplus */
-#ifndef CMDLINE_PARSER_PACKAGE
+#ifndef IMAGETAG_CMDLINE_PACKAGE
/** @brief the program name (used for printing errors) */
-#define CMDLINE_PARSER_PACKAGE "imagetag"
+#define IMAGETAG_CMDLINE_PACKAGE "imagetag"
#endif
-#ifndef CMDLINE_PARSER_PACKAGE_NAME
+#ifndef IMAGETAG_CMDLINE_PACKAGE_NAME
/** @brief the complete program name (used for help and version) */
-#define CMDLINE_PARSER_PACKAGE_NAME "imagetag"
+#define IMAGETAG_CMDLINE_PACKAGE_NAME "imagetag"
#endif
-#ifndef CMDLINE_PARSER_VERSION
+#ifndef IMAGETAG_CMDLINE_VERSION
/** @brief the program version */
-#define CMDLINE_PARSER_VERSION "2.0.0"
+#define IMAGETAG_CMDLINE_VERSION "2.0.0"
#endif
/** @brief Where the command line options are stored */
@@ -109,6 +109,11 @@ struct gengetopt_args_info
const char *reserved2_help; /**< @brief String for second reserved section. help description. */
int kernel_file_has_header_flag; /**< @brief Indicates that the kernel file includes the kernel header with correct load address and entry point, so no changes are needed (default=off). */
const char *kernel_file_has_header_help; /**< @brief Indicates that the kernel file includes the kernel header with correct load address and entry point, so no changes are needed help description. */
+ int pad_arg; /**< @brief Pad the image to this size if smaller (in MiB). */
+ char * pad_orig; /**< @brief Pad the image to this size if smaller (in MiB) original value given at command line. */
+ const char *pad_help; /**< @brief Pad the image to this size if smaller (in MiB) help description. */
+ int align_rootfs_flag; /**< @brief Align the rootfs start to erase block size (default=off). */
+ const char *align_rootfs_help; /**< @brief Align the rootfs start to erase block size help description. */
unsigned int help_given ; /**< @brief Whether help was given. */
unsigned int version_given ; /**< @brief Whether version was given. */
@@ -136,11 +141,13 @@ struct gengetopt_args_info
unsigned int inactive_given ; /**< @brief Whether inactive was given. */
unsigned int reserved2_given ; /**< @brief Whether reserved2 was given. */
unsigned int kernel_file_has_header_given ; /**< @brief Whether kernel-file-has-header was given. */
+ unsigned int pad_given ; /**< @brief Whether pad was given. */
+ unsigned int align_rootfs_given ; /**< @brief Whether align-rootfs was given. */
} ;
/** @brief The additional parameters to pass to parser functions */
-struct cmdline_parser_params
+struct imagetag_cmdline_params
{
int override; /**< @brief whether to override possibly already present options (default 0) */
int initialize; /**< @brief whether to initialize the option structure gengetopt_args_info (default 1) */
@@ -163,7 +170,7 @@ extern const char *gengetopt_args_info_help[];
* @param args_info the structure where option information will be stored
* @return 0 if everything went fine, NON 0 if an error took place
*/
-int cmdline_parser (int argc, char **argv,
+int imagetag_cmdline (int argc, char **argv,
struct gengetopt_args_info *args_info);
/**
@@ -175,9 +182,9 @@ int cmdline_parser (int argc, char **argv,
* @param initialize whether to initialize the option structure my_args_info
* @param check_required whether to check that all required options were provided
* @return 0 if everything went fine, NON 0 if an error took place
- * @deprecated use cmdline_parser_ext() instead
+ * @deprecated use imagetag_cmdline_ext() instead
*/
-int cmdline_parser2 (int argc, char **argv,
+int imagetag_cmdline2 (int argc, char **argv,
struct gengetopt_args_info *args_info,
int override, int initialize, int check_required);
@@ -189,9 +196,9 @@ int cmdline_parser2 (int argc, char **argv,
* @param params additional parameters for the parser
* @return 0 if everything went fine, NON 0 if an error took place
*/
-int cmdline_parser_ext (int argc, char **argv,
+int imagetag_cmdline_ext (int argc, char **argv,
struct gengetopt_args_info *args_info,
- struct cmdline_parser_params *params);
+ struct imagetag_cmdline_params *params);
/**
* Save the contents of the option struct into an already open FILE stream.
@@ -199,7 +206,7 @@ int cmdline_parser_ext (int argc, char **argv,
* @param args_info the option struct to dump
* @return 0 if everything went fine, NON 0 if an error took place
*/
-int cmdline_parser_dump(FILE *outfile,
+int imagetag_cmdline_dump(FILE *outfile,
struct gengetopt_args_info *args_info);
/**
@@ -209,44 +216,44 @@ int cmdline_parser_dump(FILE *outfile,
* @param args_info the option struct to save
* @return 0 if everything went fine, NON 0 if an error took place
*/
-int cmdline_parser_file_save(const char *filename,
+int imagetag_cmdline_file_save(const char *filename,
struct gengetopt_args_info *args_info);
/**
* Print the help
*/
-void cmdline_parser_print_help(void);
+void imagetag_cmdline_print_help(void);
/**
* Print the version
*/
-void cmdline_parser_print_version(void);
+void imagetag_cmdline_print_version(void);
/**
- * Initializes all the fields a cmdline_parser_params structure
+ * Initializes all the fields a imagetag_cmdline_params structure
* to their default values
* @param params the structure to initialize
*/
-void cmdline_parser_params_init(struct cmdline_parser_params *params);
+void imagetag_cmdline_params_init(struct imagetag_cmdline_params *params);
/**
- * Allocates dynamically a cmdline_parser_params structure and initializes
+ * Allocates dynamically a imagetag_cmdline_params structure and initializes
* all its fields to their default values
- * @return the created and initialized cmdline_parser_params structure
+ * @return the created and initialized imagetag_cmdline_params structure
*/
-struct cmdline_parser_params *cmdline_parser_params_create(void);
+struct imagetag_cmdline_params *imagetag_cmdline_params_create(void);
/**
* Initializes the passed gengetopt_args_info structure's fields
* (also set default values for options that have a default)
* @param args_info the structure to initialize
*/
-void cmdline_parser_init (struct gengetopt_args_info *args_info);
+void imagetag_cmdline_init (struct gengetopt_args_info *args_info);
/**
* Deallocates the string fields of the gengetopt_args_info structure
* (but does not deallocate the structure itself)
* @param args_info the structure to deallocate
*/
-void cmdline_parser_free (struct gengetopt_args_info *args_info);
+void imagetag_cmdline_free (struct gengetopt_args_info *args_info);
/**
* Checks that all the required options were specified
@@ -255,11 +262,11 @@ void cmdline_parser_free (struct gengetopt_args_info *args_info);
* possible errors
* @return
*/
-int cmdline_parser_required (struct gengetopt_args_info *args_info,
+int imagetag_cmdline_required (struct gengetopt_args_info *args_info,
const char *prog_name);
-extern const char *cmdline_parser_second_image_flag_values[]; /**< @brief Possible values for second-image-flag. */
-extern const char *cmdline_parser_inactive_values[]; /**< @brief Possible values for inactive. */
+extern const char *imagetag_cmdline_second_image_flag_values[]; /**< @brief Possible values for second-image-flag. */
+extern const char *imagetag_cmdline_inactive_values[]; /**< @brief Possible values for inactive. */
#ifdef __cplusplus
diff --git a/tools/firmware-utils/src/jcgimage.c b/tools/firmware-utils/src/jcgimage.c
new file mode 100644
index 00000000000..354c26be19b
--- /dev/null
+++ b/tools/firmware-utils/src/jcgimage.c
@@ -0,0 +1,425 @@
+/*
+ * jcgimage - Create a JCG firmware image
+ *
+ * Copyright (C) 2015 Reinhard Max <reinhard@m4x.de>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+/*
+ * JCG firmware update images consist of a 512 byte header and a
+ * modified uImage (details below) as the payload.
+ *
+ * The payload is obfuscated by XORing it with a key that is generated
+ * from parts of the header. Fortunately only non-essential parts of
+ * the header are used for this and zeroing them results in a zero
+ * key, effectively disabling the obfuscation and allowing us to use
+ * clear text payloads.
+ *
+ * The mandatory parts of the header are:
+ *
+ * - A magic string of "YSZJ" at offset 0.
+ * - A value of 1 at offset 39 (header format version?)
+ * - A CRC32 checksum of the payload at offset 504.
+ * - A CRC32 checksum of the header at offset 508.
+ *
+ * An image constructed by these rules will be accepted by JCG's
+ * U-Boot in resuce mode via TFTP and the payload will be written to
+ * the flash starting at offset 0x00050000.
+ *
+ * JCG's U-Boot does check the content or size of the payload
+ * image. If it is too large, it wraps around and overwrites U-Boot,
+ * requiring JTAG to revive the board. To prevent such bricking from
+ * happening, this tool refuses to build such overlong images.
+ *
+ * Two more conditions have to be met for a JCG image to be accepted
+ * as a valid update by the web interface of the stock firware:
+ *
+ * - The bytes at offsets 109 and 111 in the header must be a binary
+ * representation of the first two components of the firmware
+ * version as displayed in the update web form, or it will be
+ * rejected as "incorrect product".
+ *
+ * - The payload must start with a valid uImage header whose data
+ * CRC checksum matches the whole rest of the update file rather
+ * than just the number of bytes specified in the size field of the
+ * header.
+ *
+ * This last condition is met by JCG's original firmware images,
+ * because they have both, kernel and rootfs inside the uImage and
+ * abuse the last four bytes of the name field to record the offset of
+ * the file system from the start of the uImage header. This tool
+ * produces such images when called with -k and -r, which are meant to
+ * repack the original firmware after modifying the file systen,
+ * e.g. to add debugging tools and enable shell access.
+ *
+ * In contrast, OpenWrt sysupgrade images consist of a uImage that
+ * only contains the kernel and has the rootfs appended to it. Hence,
+ * the CRC over kernel and file system does not match the one in the
+ * uImage header. Fixing this by adjusting the uImage header is not
+ * possible, because it makes the uImage unusable for booting. Instead
+ * we append four "patch" bytes to the end of the file system, that
+ * are calculated to force the checksum of kernel+fs to be the same as
+ * for the kernel alone.
+ *
+ */
+
+#include <zlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <libgen.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <err.h>
+#include <time.h>
+#include <sys/mman.h>
+#include <arpa/inet.h>
+#include <assert.h>
+
+/*
+ * JCG Firmware image header
+ */
+#define JH_MAGIC 0x59535a4a /* "YSZJ" */
+struct jcg_header {
+ uint32_t jh_magic;
+ uint8_t jh_version[32]; /* Firmware version string.
+ Fill with zeros to avoid encryption */
+ uint32_t jh_type; /* must be 1 */
+ uint8_t jh_info[64]; /* Firmware info string. Fill with
+ zeros to avoid encryption */
+ uint32_t jh_time; /* Image creation time in seconds since
+ * the Epoch. Does not seem to be used
+ * by the stock firmware. */
+ uint16_t jh_major; /* Major fimware version */
+ uint16_t jh_minor; /* Minor fimrmware version */
+ uint8_t jh_unknown[392]; /* Apparently unused and all zeros */
+ uint32_t jh_dcrc; /* CRC checksum of the payload */
+ uint32_t jh_hcrc; /* CRC checksum of the header */
+};
+
+/*
+ * JCG uses a modified uImage header that replaces the last four bytes
+ * of the image name with the length of the kernel in the image.
+ */
+#define IH_MAGIC 0x27051956 /* Image Magic Number */
+#define IH_NMLEN 28 /* Image Name Length */
+
+struct uimage_header {
+ uint32_t ih_magic; /* Image Header Magic Number */
+ uint32_t ih_hcrc; /* Image Header CRC Checksum */
+ uint32_t ih_time; /* Image Creation Timestamp */
+ uint32_t ih_size; /* Image Data Size */
+ uint32_t ih_load; /* Data Load Address */
+ uint32_t ih_ep; /* Entry Point Address */
+ uint32_t ih_dcrc; /* Image Data CRC Checksum */
+ uint8_t ih_os; /* Operating System */
+ uint8_t ih_arch; /* CPU architecture */
+ uint8_t ih_type; /* Image Type */
+ uint8_t ih_comp; /* Compression Type */
+ uint8_t ih_name[IH_NMLEN];/* Image Name */
+ uint32_t ih_fsoff; /* Offset of the file system
+ partition from the start of
+ the header */
+};
+
+/*
+ * Open the named file and return its size and file descriptor.
+ * Exit in case of errors.
+ */
+int
+opensize(char *name, size_t *size)
+{
+ struct stat s;
+ int fd = open(name, O_RDONLY);
+ if (fd < 0) {
+ err(1, "cannot open \"%s\"", name);
+ }
+ if (fstat(fd, &s) == -1) {
+ err(1, "cannot stat \"%s\"", name);
+ }
+ *size = s.st_size;
+ return fd;
+}
+
+static time_t source_date_epoch = -1;
+static void set_source_date_epoch() {
+ char *env = getenv("SOURCE_DATE_EPOCH");
+ char *endptr = env;
+ errno = 0;
+ if (env && *env) {
+ source_date_epoch = strtoull(env, &endptr, 10);
+ if (errno || (endptr && *endptr != '\0')) {
+ fprintf(stderr, "Invalid SOURCE_DATE_EPOCH");
+ exit(1);
+ }
+ }
+}
+
+/*
+ * Write the JCG header
+ */
+void
+mkjcgheader(struct jcg_header *h, size_t psize, char *version)
+{
+ uLong crc;
+ uint16_t major = 0, minor = 0;
+ void *payload = (void *)h + sizeof(*h);
+ time_t t;
+
+ if (source_date_epoch != -1) {
+ t = source_date_epoch;
+ } else if ((time(&t) == (time_t)(-1))) {
+ err(1, "time call failed");
+ }
+
+ if (version != NULL) {
+ if (sscanf(version, "%hu.%hu", &major, &minor) != 2) {
+ err(1, "cannot parse version \"%s\"", version);
+ }
+ }
+
+ memset(h, 0, sizeof(*h));
+ h->jh_magic = htonl(JH_MAGIC);
+ h->jh_type = htonl(1);
+ h->jh_time = htonl(t);
+ h->jh_major = htons(major);
+ h->jh_minor = htons(minor);
+
+ /* CRC over JCG payload (uImage) */
+ crc = crc32(0L, Z_NULL, 0);
+ crc = crc32(crc, payload, psize);
+ h->jh_dcrc = htonl(crc);
+
+ /* CRC over JCG header */
+ crc = crc32(0L, Z_NULL, 0);
+ crc = crc32(crc, (void *)h, sizeof(*h));
+ h->jh_hcrc = htonl(crc);
+}
+
+/*
+ * Write the uImage header
+ */
+void
+mkuheader(struct uimage_header *h, size_t ksize, size_t fsize)
+{
+ uLong crc;
+ void *payload = (void *)h + sizeof(*h);
+
+ // printf("mkuheader: %p, %zd, %zd\n", h, ksize, fsize);
+ memset(h, 0, sizeof(*h));
+ h->ih_magic = htonl(IH_MAGIC);
+ h->ih_time = htonl(time(NULL));
+ h->ih_size = htonl(ksize + fsize);
+ h->ih_load = htonl(0x80000000);
+ h->ih_ep = htonl(0x80292000);
+ h->ih_os = 0x05;
+ h->ih_arch = 0x05;
+ h->ih_type = 0x02;
+ h->ih_comp = 0x03;
+ h->ih_fsoff = htonl(sizeof(*h) + ksize);
+ strcpy((char *)h->ih_name, "Linux Kernel Image");
+
+ /* CRC over uImage payload (kernel and file system) */
+ crc = crc32(0L, Z_NULL, 0);
+ crc = crc32(crc, payload, ntohl(h->ih_size));
+ h->ih_dcrc = htonl(crc);
+ printf("CRC1: %08lx\n", crc);
+
+ /* CRC over uImage header */
+ crc = crc32(0L, Z_NULL, 0);
+ crc = crc32(crc, (void *)h, sizeof(*h));
+ h->ih_hcrc = htonl(crc);
+ printf("CRC2: %08lx\n", crc);
+}
+
+/*
+ * Calculate a "patch" value and write it into the last four bytes of
+ * buf, so that the CRC32 checksum of the whole buffer is dcrc.
+ *
+ * Based on: SAR-PR-2006-05: Reversing CRC – Theory and Practice.
+ * Martin Stigge, Henryk Plötz, Wolf Müller, Jens-Peter Redlich.
+ * http://sar.informatik.hu-berlin.de/research/publications/#SAR-PR-2006-05
+ */
+void
+craftcrc(uint32_t dcrc, uint8_t *buf, size_t len)
+{
+ int i;
+ uint32_t a;
+ uint32_t patch = 0;
+ uint32_t crc = crc32(0L, Z_NULL, 0);
+
+ a = ~dcrc;
+ for (i = 0; i < 32; i++) {
+ if (patch & 1) {
+ patch = (patch >> 1) ^ 0xedb88320L;
+ } else {
+ patch >>= 1;
+ }
+ if (a & 1) {
+ patch ^= 0x5b358fd3L;
+ }
+ a >>= 1;
+ }
+ patch ^= ~crc32(crc, buf, len - 4);
+ for (i = 0; i < 4; i++) {
+ buf[len - 4 + i] = patch & 0xff;
+ patch >>= 8;
+ }
+ /* Verify that we actually get the desired result */
+ crc = crc32(0L, Z_NULL, 0);
+ crc = crc32(crc, buf, len);
+ if (crc != dcrc) {
+ errx(1, "CRC patching is broken: wanted %08x, but got %08x.",
+ dcrc, crc);
+ }
+}
+
+void
+usage() {
+ fprintf(stderr, "Usage:\n"
+ "jcgimage -o outfile -u uImage [-v version]\n"
+ "jcgimage -o outfile -k kernel -f rootfs [-v version]\n");
+ exit(1);
+}
+
+#define MODE_UNKNOWN 0
+#define MODE_UIMAGE 1
+#define MODE_KR 2
+
+/* The output image must not be larger than 4MiB - 5*64kiB */
+#define MAXSIZE (size_t)(4 * 1024 * 1024 - 5 * 64 * 1024)
+
+int
+main(int argc, char **argv)
+{
+ struct jcg_header *jh;
+ struct uimage_header *uh;
+ int c;
+ char *imagefile = NULL;
+ char *file1 = NULL;
+ char *file2 = NULL;
+ char *version = NULL;
+ int mode = MODE_UNKNOWN;
+ int fdo, fd1, fd2;
+ size_t size1, size2, sizeu, sizeo, off1, off2;
+ void *map;
+
+ /* Make sure the headers have the right size */
+ assert(sizeof(struct jcg_header) == 512);
+ assert(sizeof(struct uimage_header) == 64);
+ set_source_date_epoch();
+
+ while ((c = getopt(argc, argv, "o:k:f:u:v:h")) != -1) {
+ switch (c) {
+ case 'o':
+ imagefile = optarg;
+ break;
+ case 'k':
+ if (mode == MODE_UIMAGE) {
+ errx(1,"-k cannot be combined with -u");
+ }
+ mode = MODE_KR;
+ file1 = optarg;
+ break;
+ case 'f':
+ if (mode == MODE_UIMAGE) {
+ errx(1,"-f cannot be combined with -u");
+ }
+ mode = MODE_KR;
+ file2 = optarg;
+ break;
+ case 'u':
+ if (mode == MODE_KR) {
+ errx(1,"-u cannot be combined with -k and -r");
+ }
+ mode = MODE_UIMAGE;
+ file1 = optarg;
+ break;
+ case 'v':
+ version = optarg;
+ break;
+ case 'h':
+ default:
+ usage();
+ }
+ }
+ if (optind != argc) {
+ errx(1, "illegal arg \"%s\"", argv[optind]);
+ }
+ if (imagefile == NULL) {
+ errx(1, "no output file specified");
+ }
+ if (mode == MODE_UNKNOWN) {
+ errx(1, "specify either -u or -k and -r");
+ }
+ if (mode == MODE_KR) {
+ if (file1 == NULL || file2 == NULL) {
+ errx(1,"need -k and -r");
+ }
+ fd2 = opensize(file2, &size2);
+ }
+ fd1 = opensize(file1, &size1);
+ if (mode == MODE_UIMAGE) {
+ off1 = sizeof(*jh);
+ sizeu = size1 + 4;
+ sizeo = sizeof(*jh) + sizeu;
+ } else {
+ off1 = sizeof(*jh) + sizeof(*uh);
+ off2 = sizeof(*jh) + sizeof(*uh) + size1;
+ sizeu = sizeof(*uh) + size1 + size2;
+ sizeo = sizeof(*jh) + sizeu;
+ }
+
+ if (sizeo > MAXSIZE) {
+ errx(1,"payload too large: %zd > %zd\n", sizeo, MAXSIZE);
+ }
+
+ fdo = open(imagefile, O_RDWR | O_CREAT | O_TRUNC, 00644);
+ if (fdo < 0) {
+ err(1, "cannot open \"%s\"", imagefile);
+ }
+
+ if (ftruncate(fdo, sizeo) == -1) {
+ err(1, "cannot grow \"%s\" to %zd bytes", imagefile, sizeo);
+ }
+ map = mmap(NULL, sizeo, PROT_READ|PROT_WRITE, MAP_SHARED, fdo, 0);
+ uh = map + sizeof(*jh);
+ if (map == MAP_FAILED) {
+ err(1, "cannot mmap \"%s\"", imagefile);
+ }
+
+ if (read(fd1, map + off1, size1) != size1) {
+ err(1, "cannot copy %s", file1);
+ }
+
+ if (mode == MODE_KR) {
+ if (read(fd2, map+off2, size2) != size2) {
+ err(1, "cannot copy %s", file2);
+ }
+ mkuheader(uh, size1, size2);
+ } else if (mode == MODE_UIMAGE) {
+ craftcrc(ntohl(uh->ih_dcrc), (void*)uh + sizeof(*uh),
+ sizeu - sizeof(*uh));
+ }
+ mkjcgheader(map, sizeu, version);
+ munmap(map, sizeo);
+ close(fdo);
+ return 0;
+}
diff --git a/tools/firmware-utils/src/lzma2eva.c b/tools/firmware-utils/src/lzma2eva.c
index 0bc13fa4f34..1d7e3648899 100644
--- a/tools/firmware-utils/src/lzma2eva.c
+++ b/tools/firmware-utils/src/lzma2eva.c
@@ -48,7 +48,7 @@ main(int argc, char *argv[])
const char *infile, *outfile;
FILE *in, *out;
- static const uint8_t buf[4096];
+ static uint8_t buf[4096];
size_t elems;
uint8_t properties;
diff --git a/tools/firmware-utils/src/md5.c b/tools/firmware-utils/src/md5.c
index 20397603834..52d96accd30 100644
--- a/tools/firmware-utils/src/md5.c
+++ b/tools/firmware-utils/src/md5.c
@@ -1,307 +1,296 @@
-
-
/*
- ***********************************************************************
- ** md5.c -- the source code for MD5 routines **
- ** RSA Data Security, Inc. MD5 Message-Digest Algorithm **
- ** Created: 2/17/90 RLR **
- ** Revised: 1/91 SRD,AJ,BSK,JT Reference C ver., 7/10 constant corr. **
- ***********************************************************************
+ * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
+ * MD5 Message-Digest Algorithm (RFC 1321).
+ *
+ * Homepage:
+ * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
+ *
+ * Author:
+ * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
+ *
+ * This software was written by Alexander Peslyak in 2001. No copyright is
+ * claimed, and the software is hereby placed in the public domain.
+ * In case this attempt to disclaim copyright and place the software in the
+ * public domain is deemed null and void, then the software is
+ * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
+ * general public under the following terms:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted.
+ *
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
+ *
+ * (This is a heavily cut-down "BSD license".)
+ *
+ * This differs from Colin Plumb's older public domain implementation in that
+ * no exactly 32-bit integer data type is required (any 32-bit or wider
+ * unsigned integer data type will do), there's no compile-time endianness
+ * configuration, and the function prototypes match OpenSSL's. No code from
+ * Colin Plumb's implementation has been reused; this comment merely compares
+ * the properties of the two independent implementations.
+ *
+ * The primary goals of this implementation are portability and ease of use.
+ * It is meant to be fast, but not as fast as possible. Some known
+ * optimizations are not included to reduce source code size and avoid
+ * compile-time configuration.
*/
-/*
- ***********************************************************************
- ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
- ** **
- ** License to copy and use this software is granted provided that **
- ** it is identified as the "RSA Data Security, Inc. MD5 Message- **
- ** Digest Algorithm" in all material mentioning or referencing this **
- ** software or this function. **
- ** **
- ** License is also granted to make and use derivative works **
- ** provided that such works are identified as "derived from the RSA **
- ** Data Security, Inc. MD5 Message-Digest Algorithm" in all **
- ** material mentioning or referencing the derived work. **
- ** **
- ** RSA Data Security, Inc. makes no representations concerning **
- ** either the merchantability of this software or the suitability **
- ** of this software for any particular purpose. It is provided "as **
- ** is" without express or implied warranty of any kind. **
- ** **
- ** These notices must be retained in any copies of any part of this **
- ** documentation and/or software. **
- ***********************************************************************
- */
+#ifndef HAVE_OPENSSL
#include <string.h>
+
#include "md5.h"
/*
- ***********************************************************************
- ** Message-digest routines: **
- ** To form the message digest for a message M **
- ** (1) Initialize a context buffer mdContext using MD5_Init **
- ** (2) Call MD5_Update on mdContext and M **
- ** (3) Call MD5_Final on mdContext **
- ** The message digest is now in mdContext->digest[0...15] **
- ***********************************************************************
+ * The basic MD5 functions.
+ *
+ * F and G are optimized compared to their RFC 1321 definitions for
+ * architectures that lack an AND-NOT instruction, just like in Colin Plumb's
+ * implementation.
+ */
+#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
+#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
+#define H(x, y, z) (((x) ^ (y)) ^ (z))
+#define H2(x, y, z) ((x) ^ ((y) ^ (z)))
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+
+/*
+ * The MD5 transformation for all four rounds.
*/
+#define STEP(f, a, b, c, d, x, t, s) \
+ (a) += f((b), (c), (d)) + (x) + (t); \
+ (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
+ (a) += (b);
-/* forward declaration */
-static void Transform ();
-
-static unsigned char PADDING[64] = {
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-/* F, G, H and I are basic MD5 functions */
-#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
-#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
-#define H(x, y, z) ((x) ^ (y) ^ (z))
-#define I(x, y, z) ((y) ^ ((x) | (~z)))
-
-/* ROTATE_LEFT rotates x left n bits */
-#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
-
-/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */
-/* Rotation is separate from addition to prevent recomputation */
-#define FF(a, b, c, d, x, s, ac) \
- {(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
- (a) = ROTATE_LEFT ((a), (s)); \
- (a) += (b); \
- }
-#define GG(a, b, c, d, x, s, ac) \
- {(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
- (a) = ROTATE_LEFT ((a), (s)); \
- (a) += (b); \
- }
-#define HH(a, b, c, d, x, s, ac) \
- {(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
- (a) = ROTATE_LEFT ((a), (s)); \
- (a) += (b); \
- }
-#define II(a, b, c, d, x, s, ac) \
- {(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
- (a) = ROTATE_LEFT ((a), (s)); \
- (a) += (b); \
- }
-
-#ifdef __STDC__
-#define UL(x) x##U
+/*
+ * SET reads 4 input bytes in little-endian byte order and stores them
+ * in a properly aligned word in host byte order.
+ *
+ * The check for little-endian architectures that tolerate unaligned
+ * memory accesses is just an optimization. Nothing will break if it
+ * doesn't work.
+ */
+#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
+#define SET(n) \
+ (*(MD5_u32plus *)&ptr[(n) * 4])
+#define GET(n) \
+ SET(n)
#else
-#define UL(x) x
+#define SET(n) \
+ (ctx->block[(n)] = \
+ (MD5_u32plus)ptr[(n) * 4] | \
+ ((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \
+ ((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \
+ ((MD5_u32plus)ptr[(n) * 4 + 3] << 24))
+#define GET(n) \
+ (ctx->block[(n)])
#endif
-/* The routine MD5_Init initializes the message-digest context
- mdContext. All fields are set to zero.
+/*
+ * This processes one or more 64-byte data blocks, but does NOT update
+ * the bit counters. There are no alignment requirements.
*/
-void MD5_Init (mdContext)
-MD5_CTX *mdContext;
+static const void *body(MD5_CTX *ctx, const void *data, unsigned long size)
{
- mdContext->i[0] = mdContext->i[1] = (UINT4)0;
-
- /* Load magic initialization constants.
- */
- mdContext->buf[0] = (UINT4)0x67452301;
- mdContext->buf[1] = (UINT4)0xefcdab89;
- mdContext->buf[2] = (UINT4)0x98badcfe;
- mdContext->buf[3] = (UINT4)0x10325476;
+ const unsigned char *ptr;
+ MD5_u32plus a, b, c, d;
+ MD5_u32plus saved_a, saved_b, saved_c, saved_d;
+
+ ptr = (const unsigned char *)data;
+
+ a = ctx->a;
+ b = ctx->b;
+ c = ctx->c;
+ d = ctx->d;
+
+ do {
+ saved_a = a;
+ saved_b = b;
+ saved_c = c;
+ saved_d = d;
+
+/* Round 1 */
+ STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
+ STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
+ STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
+ STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
+ STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
+ STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
+ STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
+ STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
+ STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
+ STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
+ STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
+ STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
+ STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
+ STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
+ STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
+ STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
+
+/* Round 2 */
+ STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
+ STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
+ STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
+ STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
+ STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
+ STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
+ STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
+ STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
+ STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
+ STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
+ STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
+ STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
+ STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
+ STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
+ STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
+ STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
+
+/* Round 3 */
+ STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
+ STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11)
+ STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
+ STEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23)
+ STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
+ STEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11)
+ STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
+ STEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23)
+ STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
+ STEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11)
+ STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
+ STEP(H2, b, c, d, a, GET(6), 0x04881d05, 23)
+ STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
+ STEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11)
+ STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
+ STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23)
+
+/* Round 4 */
+ STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
+ STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
+ STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
+ STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
+ STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
+ STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
+ STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
+ STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
+ STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
+ STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
+ STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
+ STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
+ STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
+ STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
+ STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
+ STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
+
+ a += saved_a;
+ b += saved_b;
+ c += saved_c;
+ d += saved_d;
+
+ ptr += 64;
+ } while (size -= 64);
+
+ ctx->a = a;
+ ctx->b = b;
+ ctx->c = c;
+ ctx->d = d;
+
+ return ptr;
}
-/* The routine MD5Update updates the message-digest context to
- account for the presence of each of the characters inBuf[0..inLen-1]
- in the message whose digest is being computed.
- */
-void MD5_Update (mdContext, inBuf, inLen)
-MD5_CTX *mdContext;
-unsigned char *inBuf;
-unsigned int inLen;
+void MD5_Init(MD5_CTX *ctx)
{
- UINT4 in[16];
- int mdi;
- unsigned int i, ii;
-
- /* compute number of bytes mod 64 */
- mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
-
- /* update number of bits */
- if ((mdContext->i[0] + ((UINT4)inLen << 3)) < mdContext->i[0])
- mdContext->i[1]++;
- mdContext->i[0] += ((UINT4)inLen << 3);
- mdContext->i[1] += ((UINT4)inLen >> 29);
-
- while (inLen--) {
- /* add new character to buffer, increment mdi */
- mdContext->in[mdi++] = *inBuf++;
-
- /* transform if necessary */
- if (mdi == 0x40) {
- for (i = 0, ii = 0; i < 16; i++, ii += 4)
- in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
- (((UINT4)mdContext->in[ii+2]) << 16) |
- (((UINT4)mdContext->in[ii+1]) << 8) |
- ((UINT4)mdContext->in[ii]);
- Transform (mdContext->buf, in);
- mdi = 0;
- }
- }
+ ctx->a = 0x67452301;
+ ctx->b = 0xefcdab89;
+ ctx->c = 0x98badcfe;
+ ctx->d = 0x10325476;
+
+ ctx->lo = 0;
+ ctx->hi = 0;
}
-/* The routine MD5Final terminates the message-digest computation and
- ends with the desired message digest in mdContext->digest[0...15].
- */
-void MD5_Final (hash, mdContext)
-unsigned char hash[];
-MD5_CTX *mdContext;
+void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size)
{
- UINT4 in[16];
- int mdi;
- unsigned int i, ii;
- unsigned int padLen;
-
- /* save number of bits */
- in[14] = mdContext->i[0];
- in[15] = mdContext->i[1];
-
- /* compute number of bytes mod 64 */
- mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
-
- /* pad out to 56 mod 64 */
- padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi);
- MD5_Update (mdContext, PADDING, padLen);
-
- /* append length in bits and transform */
- for (i = 0, ii = 0; i < 14; i++, ii += 4)
- in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
- (((UINT4)mdContext->in[ii+2]) << 16) |
- (((UINT4)mdContext->in[ii+1]) << 8) |
- ((UINT4)mdContext->in[ii]);
- Transform (mdContext->buf, in);
-
- /* store buffer in digest */
- for (i = 0, ii = 0; i < 4; i++, ii += 4) {
- mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF);
- mdContext->digest[ii+1] =
- (unsigned char)((mdContext->buf[i] >> 8) & 0xFF);
- mdContext->digest[ii+2] =
- (unsigned char)((mdContext->buf[i] >> 16) & 0xFF);
- mdContext->digest[ii+3] =
- (unsigned char)((mdContext->buf[i] >> 24) & 0xFF);
- }
- memcpy(hash, mdContext->digest, 16);
+ MD5_u32plus saved_lo;
+ unsigned long used, available;
+
+ saved_lo = ctx->lo;
+ if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
+ ctx->hi++;
+ ctx->hi += size >> 29;
+
+ used = saved_lo & 0x3f;
+
+ if (used) {
+ available = 64 - used;
+
+ if (size < available) {
+ memcpy(&ctx->buffer[used], data, size);
+ return;
+ }
+
+ memcpy(&ctx->buffer[used], data, available);
+ data = (const unsigned char *)data + available;
+ size -= available;
+ body(ctx, ctx->buffer, 64);
+ }
+
+ if (size >= 64) {
+ data = body(ctx, data, size & ~(unsigned long)0x3f);
+ size &= 0x3f;
+ }
+
+ memcpy(ctx->buffer, data, size);
}
-/* Basic MD5 step. Transforms buf based on in.
- */
-static void Transform (buf, in)
-UINT4 *buf;
-UINT4 *in;
+void MD5_Final(unsigned char *result, MD5_CTX *ctx)
{
- UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
-
- /* Round 1 */
-#define S11 7
-#define S12 12
-#define S13 17
-#define S14 22
- FF ( a, b, c, d, in[ 0], S11, UL(3614090360)); /* 1 */
- FF ( d, a, b, c, in[ 1], S12, UL(3905402710)); /* 2 */
- FF ( c, d, a, b, in[ 2], S13, UL( 606105819)); /* 3 */
- FF ( b, c, d, a, in[ 3], S14, UL(3250441966)); /* 4 */
- FF ( a, b, c, d, in[ 4], S11, UL(4118548399)); /* 5 */
- FF ( d, a, b, c, in[ 5], S12, UL(1200080426)); /* 6 */
- FF ( c, d, a, b, in[ 6], S13, UL(2821735955)); /* 7 */
- FF ( b, c, d, a, in[ 7], S14, UL(4249261313)); /* 8 */
- FF ( a, b, c, d, in[ 8], S11, UL(1770035416)); /* 9 */
- FF ( d, a, b, c, in[ 9], S12, UL(2336552879)); /* 10 */
- FF ( c, d, a, b, in[10], S13, UL(4294925233)); /* 11 */
- FF ( b, c, d, a, in[11], S14, UL(2304563134)); /* 12 */
- FF ( a, b, c, d, in[12], S11, UL(1804603682)); /* 13 */
- FF ( d, a, b, c, in[13], S12, UL(4254626195)); /* 14 */
- FF ( c, d, a, b, in[14], S13, UL(2792965006)); /* 15 */
- FF ( b, c, d, a, in[15], S14, UL(1236535329)); /* 16 */
-
- /* Round 2 */
-#define S21 5
-#define S22 9
-#define S23 14
-#define S24 20
- GG ( a, b, c, d, in[ 1], S21, UL(4129170786)); /* 17 */
- GG ( d, a, b, c, in[ 6], S22, UL(3225465664)); /* 18 */
- GG ( c, d, a, b, in[11], S23, UL( 643717713)); /* 19 */
- GG ( b, c, d, a, in[ 0], S24, UL(3921069994)); /* 20 */
- GG ( a, b, c, d, in[ 5], S21, UL(3593408605)); /* 21 */
- GG ( d, a, b, c, in[10], S22, UL( 38016083)); /* 22 */
- GG ( c, d, a, b, in[15], S23, UL(3634488961)); /* 23 */
- GG ( b, c, d, a, in[ 4], S24, UL(3889429448)); /* 24 */
- GG ( a, b, c, d, in[ 9], S21, UL( 568446438)); /* 25 */
- GG ( d, a, b, c, in[14], S22, UL(3275163606)); /* 26 */
- GG ( c, d, a, b, in[ 3], S23, UL(4107603335)); /* 27 */
- GG ( b, c, d, a, in[ 8], S24, UL(1163531501)); /* 28 */
- GG ( a, b, c, d, in[13], S21, UL(2850285829)); /* 29 */
- GG ( d, a, b, c, in[ 2], S22, UL(4243563512)); /* 30 */
- GG ( c, d, a, b, in[ 7], S23, UL(1735328473)); /* 31 */
- GG ( b, c, d, a, in[12], S24, UL(2368359562)); /* 32 */
-
- /* Round 3 */
-#define S31 4
-#define S32 11
-#define S33 16
-#define S34 23
- HH ( a, b, c, d, in[ 5], S31, UL(4294588738)); /* 33 */
- HH ( d, a, b, c, in[ 8], S32, UL(2272392833)); /* 34 */
- HH ( c, d, a, b, in[11], S33, UL(1839030562)); /* 35 */
- HH ( b, c, d, a, in[14], S34, UL(4259657740)); /* 36 */
- HH ( a, b, c, d, in[ 1], S31, UL(2763975236)); /* 37 */
- HH ( d, a, b, c, in[ 4], S32, UL(1272893353)); /* 38 */
- HH ( c, d, a, b, in[ 7], S33, UL(4139469664)); /* 39 */
- HH ( b, c, d, a, in[10], S34, UL(3200236656)); /* 40 */
- HH ( a, b, c, d, in[13], S31, UL( 681279174)); /* 41 */
- HH ( d, a, b, c, in[ 0], S32, UL(3936430074)); /* 42 */
- HH ( c, d, a, b, in[ 3], S33, UL(3572445317)); /* 43 */
- HH ( b, c, d, a, in[ 6], S34, UL( 76029189)); /* 44 */
- HH ( a, b, c, d, in[ 9], S31, UL(3654602809)); /* 45 */
- HH ( d, a, b, c, in[12], S32, UL(3873151461)); /* 46 */
- HH ( c, d, a, b, in[15], S33, UL( 530742520)); /* 47 */
- HH ( b, c, d, a, in[ 2], S34, UL(3299628645)); /* 48 */
-
- /* Round 4 */
-#define S41 6
-#define S42 10
-#define S43 15
-#define S44 21
- II ( a, b, c, d, in[ 0], S41, UL(4096336452)); /* 49 */
- II ( d, a, b, c, in[ 7], S42, UL(1126891415)); /* 50 */
- II ( c, d, a, b, in[14], S43, UL(2878612391)); /* 51 */
- II ( b, c, d, a, in[ 5], S44, UL(4237533241)); /* 52 */
- II ( a, b, c, d, in[12], S41, UL(1700485571)); /* 53 */
- II ( d, a, b, c, in[ 3], S42, UL(2399980690)); /* 54 */
- II ( c, d, a, b, in[10], S43, UL(4293915773)); /* 55 */
- II ( b, c, d, a, in[ 1], S44, UL(2240044497)); /* 56 */
- II ( a, b, c, d, in[ 8], S41, UL(1873313359)); /* 57 */
- II ( d, a, b, c, in[15], S42, UL(4264355552)); /* 58 */
- II ( c, d, a, b, in[ 6], S43, UL(2734768916)); /* 59 */
- II ( b, c, d, a, in[13], S44, UL(1309151649)); /* 60 */
- II ( a, b, c, d, in[ 4], S41, UL(4149444226)); /* 61 */
- II ( d, a, b, c, in[11], S42, UL(3174756917)); /* 62 */
- II ( c, d, a, b, in[ 2], S43, UL( 718787259)); /* 63 */
- II ( b, c, d, a, in[ 9], S44, UL(3951481745)); /* 64 */
-
- buf[0] += a;
- buf[1] += b;
- buf[2] += c;
- buf[3] += d;
+ unsigned long used, available;
+
+ used = ctx->lo & 0x3f;
+
+ ctx->buffer[used++] = 0x80;
+
+ available = 64 - used;
+
+ if (available < 8) {
+ memset(&ctx->buffer[used], 0, available);
+ body(ctx, ctx->buffer, 64);
+ used = 0;
+ available = 64;
+ }
+
+ memset(&ctx->buffer[used], 0, available - 8);
+
+ ctx->lo <<= 3;
+ ctx->buffer[56] = ctx->lo;
+ ctx->buffer[57] = ctx->lo >> 8;
+ ctx->buffer[58] = ctx->lo >> 16;
+ ctx->buffer[59] = ctx->lo >> 24;
+ ctx->buffer[60] = ctx->hi;
+ ctx->buffer[61] = ctx->hi >> 8;
+ ctx->buffer[62] = ctx->hi >> 16;
+ ctx->buffer[63] = ctx->hi >> 24;
+
+ body(ctx, ctx->buffer, 64);
+
+ result[0] = ctx->a;
+ result[1] = ctx->a >> 8;
+ result[2] = ctx->a >> 16;
+ result[3] = ctx->a >> 24;
+ result[4] = ctx->b;
+ result[5] = ctx->b >> 8;
+ result[6] = ctx->b >> 16;
+ result[7] = ctx->b >> 24;
+ result[8] = ctx->c;
+ result[9] = ctx->c >> 8;
+ result[10] = ctx->c >> 16;
+ result[11] = ctx->c >> 24;
+ result[12] = ctx->d;
+ result[13] = ctx->d >> 8;
+ result[14] = ctx->d >> 16;
+ result[15] = ctx->d >> 24;
+
+ memset(ctx, 0, sizeof(*ctx));
}
-/*
- ***********************************************************************
- ** End of md5.c **
- ******************************** (cut) ********************************
- */
+#endif
diff --git a/tools/firmware-utils/src/md5.h b/tools/firmware-utils/src/md5.h
index f7a0c964183..2da44bf355a 100644
--- a/tools/firmware-utils/src/md5.h
+++ b/tools/firmware-utils/src/md5.h
@@ -1,65 +1,45 @@
/*
- ***********************************************************************
- ** md5.h -- header file for implementation of MD5 **
- ** RSA Data Security, Inc. MD5 Message-Digest Algorithm **
- ** Created: 2/17/90 RLR **
- ** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version **
- ** Revised (for MD5): RLR 4/27/91 **
- ** -- G modified to have y&~z instead of y&z **
- ** -- FF, GG, HH modified to add in last register done **
- ** -- Access pattern: round 2 works mod 5, round 3 works mod 3 **
- ** -- distinct additive constant for each step **
- ** -- round 4 added, working mod 7 **
- ***********************************************************************
+ * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
+ * MD5 Message-Digest Algorithm (RFC 1321).
+ *
+ * Homepage:
+ * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
+ *
+ * Author:
+ * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
+ *
+ * This software was written by Alexander Peslyak in 2001. No copyright is
+ * claimed, and the software is hereby placed in the public domain.
+ * In case this attempt to disclaim copyright and place the software in the
+ * public domain is deemed null and void, then the software is
+ * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
+ * general public under the following terms:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted.
+ *
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
+ *
+ * See md5.c for more information.
*/
-/*
- ***********************************************************************
- ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
- ** **
- ** License to copy and use this software is granted provided that **
- ** it is identified as the "RSA Data Security, Inc. MD5 Message- **
- ** Digest Algorithm" in all material mentioning or referencing this **
- ** software or this function. **
- ** **
- ** License is also granted to make and use derivative works **
- ** provided that such works are identified as "derived from the RSA **
- ** Data Security, Inc. MD5 Message-Digest Algorithm" in all **
- ** material mentioning or referencing the derived work. **
- ** **
- ** RSA Data Security, Inc. makes no representations concerning **
- ** either the merchantability of this software or the suitability **
- ** of this software for any particular purpose. It is provided "as **
- ** is" without express or implied warranty of any kind. **
- ** **
- ** These notices must be retained in any copies of any part of this **
- ** documentation and/or software. **
- ***********************************************************************
- */
+#ifdef HAVE_OPENSSL
+#include <openssl/md5.h>
+#elif !defined(_MD5_H)
+#define _MD5_H
-#ifndef __MD5_INCLUDE__
+/* Any 32-bit or wider unsigned integer data type will do */
+typedef unsigned int MD5_u32plus;
-/* typedef a 32-bit type */
-#ifdef _LP64
-typedef unsigned int UINT4;
-typedef int INT4;
-#else
-typedef unsigned long UINT4;
-typedef long INT4;
-#endif
-#define _UINT4_T
-
-/* Data structure for MD5 (Message-Digest) computation */
typedef struct {
- UINT4 i[2]; /* number of _bits_ handled mod 2^64 */
- UINT4 buf[4]; /* scratch buffer */
- unsigned char in[64]; /* input buffer */
- unsigned char digest[16]; /* actual digest after MD5Final call */
+ MD5_u32plus lo, hi;
+ MD5_u32plus a, b, c, d;
+ unsigned char buffer[64];
+ MD5_u32plus block[16];
} MD5_CTX;
-void MD5_Init ();
-void MD5_Update ();
-void MD5_Final ();
+extern void MD5_Init(MD5_CTX *ctx);
+extern void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size);
+extern void MD5_Final(unsigned char *result, MD5_CTX *ctx);
-#define __MD5_INCLUDE__
-#endif /* __MD5_INCLUDE__ */
+#endif
diff --git a/tools/firmware-utils/src/mkbrnimg.c b/tools/firmware-utils/src/mkbrnimg.c
index fff92c4ef66..b7a73ff59d2 100644
--- a/tools/firmware-utils/src/mkbrnimg.c
+++ b/tools/firmware-utils/src/mkbrnimg.c
@@ -32,9 +32,14 @@
static uint32_t crc32[1<<BPB];
+static char *output_file = "default-brnImage";
+static uint32_t magic = 0x12345678;
+static char *signature = "BRNDTW502";
+static uint32_t crc32_poly = 0x2083b8ed;
+
static void init_crc32()
{
- const uint32_t poly = ntohl(0x2083b8ed);
+ const uint32_t poly = ntohl(crc32_poly);
int n;
for (n = 0; n < 1<<BPB; n++) {
@@ -61,21 +66,17 @@ static void usage(const char *) __attribute__ (( __noreturn__ ));
static void usage(const char *mess)
{
fprintf(stderr, "Error: %s\n", mess);
- fprintf(stderr, "Usage: mkbrnimg [-o output_file] [-m magic] [-s signature] kernel_file [additional files]\n");
+ fprintf(stderr, "Usage: mkbrnimg [-o output_file] [-m magic] [-s signature] [-p crc32 poly] kernel_file [additional files]\n");
fprintf(stderr, "\n");
exit(1);
}
-static char *output_file = "default-brnImage";
-static uint32_t magic = 0x12345678;
-static char *signature = "BRNDTW502";
-
static void parseopts(int *argc, char ***argv)
{
char *endptr;
int res;
- while ((res = getopt(*argc, *argv, "o:m:s:")) != -1) {
+ while ((res = getopt(*argc, *argv, "o:m:s:p:")) != -1) {
switch (res) {
default:
usage("Unknown option");
@@ -91,6 +92,11 @@ static void parseopts(int *argc, char ***argv)
case 's':
signature = optarg;
break;
+ case 'p':
+ crc32_poly = strtoul(optarg, &endptr, 0);
+ if (endptr == optarg || *endptr != 0)
+ usage("'crc32 poly' must be a decimal or hexadecimal 32-bit value");
+ break;
}
}
*argc -= optind;
@@ -136,7 +142,7 @@ static void appendfile(int outfd, char *path, int kernel) {
// write padding
padded_len = ((len + sizeof(footer) + sizeof(padding) - 1) & ~(sizeof(padding) - 1)) - sizeof(footer);
- fprintf(stderr, "len=%08x padded_len=%08x\n", len, padded_len);
+ fprintf(stderr, "len=%08zx padded_len=%08zx\n", len, padded_len);
write(outfd, padding, padded_len - len);
// write footer
diff --git a/tools/firmware-utils/src/mkbuffaloimg.c b/tools/firmware-utils/src/mkbuffaloimg.c
new file mode 100644
index 00000000000..364dda005b0
--- /dev/null
+++ b/tools/firmware-utils/src/mkbuffaloimg.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2016 FUKAUMI Naoki <naobsd@gmail.com>
+ *
+ * Based on mkdniimg.c
+ *
+ * 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>
+
+#define DNI_HDR_LEN 128
+
+/*
+ * Globals
+ */
+static char *ifname;
+static char *progname;
+static char *ofname;
+static char *version = "0.00_0.00";
+static char *region = "JP";
+static char *rootfs_size;
+static char *kernel_size;
+
+static char *board_id;
+/*
+ * 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)
+
+void usage(int status)
+{
+ FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+
+ fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+ fprintf(stream,
+"\n"
+"Options:\n"
+" -B <board> create image for the board specified with <board>\n"
+" -i <file> read input from the file <file>\n"
+" -o <file> write output to the file <file>\n"
+" -v <version> set image version to <version>\n"
+" -r <region> set image region to <region>\n"
+" -R <rootfs_size> set RootfsSize to <rootfs_size>\n"
+" -K <kernel_size> set KernelSize to <kernel_size>\n"
+" -h show this screen\n"
+ );
+
+ exit(status);
+}
+
+int main(int argc, char *argv[])
+{
+ int res = EXIT_FAILURE;
+ int buflen;
+ int err;
+ struct stat st;
+ char *buf;
+ int i;
+ uint8_t csum;
+
+ FILE *outfile, *infile;
+
+ progname = basename(argv[0]);
+
+ while ( 1 ) {
+ int c;
+
+ c = getopt(argc, argv, "B:i:o:v:r:R:K:h");
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'B':
+ board_id = optarg;
+ break;
+ case 'i':
+ ifname = optarg;
+ break;
+ case 'o':
+ ofname = optarg;
+ break;
+ case 'v':
+ version = optarg;
+ break;
+ case 'r':
+ region = optarg;
+ break;
+ case 'R':
+ rootfs_size = optarg;
+ break;
+ case 'K':
+ kernel_size = optarg;
+ break;
+ case 'h':
+ usage(EXIT_SUCCESS);
+ break;
+ default:
+ usage(EXIT_FAILURE);
+ break;
+ }
+ }
+
+ if (board_id == NULL) {
+ ERR("no board specified");
+ goto err;
+ }
+
+ if (rootfs_size == NULL) {
+ ERR("no rootfs_size specified");
+ goto err;
+ }
+
+ if (kernel_size == NULL) {
+ ERR("no kernel_size specified");
+ goto err;
+ }
+
+ if (ifname == NULL) {
+ ERR("no input file specified");
+ goto err;
+ }
+
+ if (ofname == NULL) {
+ ERR("no output file specified");
+ goto err;
+ }
+
+ err = stat(ifname, &st);
+ if (err){
+ ERRS("stat failed on %s", ifname);
+ goto err;
+ }
+
+ buflen = st.st_size + DNI_HDR_LEN + 1;
+ buf = malloc(buflen);
+ if (!buf) {
+ ERR("no memory for buffer\n");
+ goto err;
+ }
+
+ memset(buf, 0, DNI_HDR_LEN);
+ snprintf(buf, DNI_HDR_LEN, "device:%s\nversion:%s\nregion:%s\n"
+ "RootfsSize:%s\nKernelSize:%s\nInfoHeadSize:128\n",
+ board_id, version, region, rootfs_size, kernel_size);
+ buf[DNI_HDR_LEN - 2] = 0x12;
+ buf[DNI_HDR_LEN - 1] = 0x32;
+
+ infile = fopen(ifname, "r");
+ if (infile == NULL) {
+ ERRS("could not open \"%s\" for reading", ifname);
+ goto err_free;
+ }
+
+ errno = 0;
+ fread(buf + DNI_HDR_LEN, st.st_size, 1, infile);
+ if (errno != 0) {
+ ERRS("unable to read from file %s", ifname);
+ goto err_close_in;
+ }
+
+ csum = 0;
+ for (i = 0; i < (st.st_size + DNI_HDR_LEN); i++)
+ csum += buf[i];
+
+ csum = 0xff - csum;
+ buf[st.st_size + DNI_HDR_LEN] = csum;
+
+ outfile = fopen(ofname, "w");
+ if (outfile == NULL) {
+ ERRS("could not open \"%s\" for writing", ofname);
+ goto err_close_in;
+ }
+
+ errno = 0;
+ fwrite(buf, buflen, 1, outfile);
+ if (errno) {
+ ERRS("unable to write to file %s", ofname);
+ goto err_close_out;
+ }
+
+ res = EXIT_SUCCESS;
+
+ fflush(outfile);
+
+ err_close_out:
+ fclose(outfile);
+ if (res != EXIT_SUCCESS) {
+ unlink(ofname);
+ }
+
+ err_close_in:
+ fclose(infile);
+
+ err_free:
+ free(buf);
+
+ err:
+ return res;
+}
diff --git a/tools/firmware-utils/src/mkcameofw.c b/tools/firmware-utils/src/mkcameofw.c
new file mode 100644
index 00000000000..e0da4baf330
--- /dev/null
+++ b/tools/firmware-utils/src/mkcameofw.c
@@ -0,0 +1,433 @@
+/*
+ * Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * 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 <arpa/inet.h>
+#include <netinet/in.h>
+
+#define MAX_MODEL_LEN 20
+#define MAX_SIGNATURE_LEN 30
+#define MAX_REGION_LEN 4
+#define MAX_VERSION_LEN 12
+
+#define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
+
+struct file_info {
+ char *file_name; /* name of the file */
+ uint32_t file_size; /* length of the file */
+ uint32_t write_size;
+};
+
+struct img_header {
+ uint32_t checksum;
+ uint32_t image_size;
+ uint32_t kernel_size;
+ char model[MAX_MODEL_LEN];
+ char signature[MAX_SIGNATURE_LEN];
+ char region[MAX_REGION_LEN];
+ char version[MAX_VERSION_LEN];
+ unsigned char header_len;
+ unsigned char is_tgz;
+ unsigned char pad[4];
+} __attribute__ ((packed));
+
+/*
+ * Globals
+ */
+static char *ofname;
+static char *progname;
+
+static char *model;
+static char *signature;
+static char *region = "DEF";
+static char *version;
+static struct file_info kernel_info;
+static struct file_info rootfs_info;
+static uint32_t kernel_size;
+static uint32_t image_size;
+static int combined;
+
+/*
+ * 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 DBG(fmt, ...) do { \
+ fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
+} while (0)
+
+static void usage(int status)
+{
+ FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+
+ fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+ fprintf(stream,
+"\n"
+"Options:\n"
+" -k <file> read kernel image from the file <file>\n"
+" -c use the kernel image as a combined image\n"
+" -M <model> set model to <model>\n"
+" -o <file> write output to the file <file>\n"
+" -r <file> read rootfs image from the file <file>\n"
+" -S <signature> set image signature to <signature>\n"
+" -R <region> set image region to <region>\n"
+" -V <version> set image version to <version>\n"
+" -I <size> set image size to <size>\n"
+" -K <size> set kernel size to <size>\n"
+" -h show this screen\n"
+ );
+
+ exit(status);
+}
+
+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;
+}
+
+static int get_file_stat(struct file_info *fdata)
+{
+ struct stat st;
+ int res;
+
+ if (fdata->file_name == NULL)
+ return 0;
+
+ res = stat(fdata->file_name, &st);
+ if (res){
+ ERRS("stat failed on %s", fdata->file_name);
+ return res;
+ }
+
+ fdata->file_size = st.st_size;
+ fdata->write_size = fdata->file_size;
+ return 0;
+}
+
+static int read_to_buf(struct file_info *fdata, char *buf)
+{
+ FILE *f;
+ int ret = EXIT_FAILURE;
+
+ f = fopen(fdata->file_name, "r");
+ if (f == NULL) {
+ ERRS("could not open \"%s\" for reading", fdata->file_name);
+ goto out;
+ }
+
+ errno = 0;
+ fread(buf, fdata->file_size, 1, f);
+ if (errno != 0) {
+ ERRS("unable to read from file \"%s\"", fdata->file_name);
+ goto out_close;
+ }
+
+ ret = EXIT_SUCCESS;
+
+out_close:
+ fclose(f);
+out:
+ return ret;
+}
+
+static int check_options(void)
+{
+ int ret;
+
+#define CHKSTR(_name, _msg) \
+ do { \
+ if (_name == NULL) { \
+ ERR("no %s specified", _msg); \
+ return -1; \
+ } \
+ } while (0)
+
+#define CHKSTRLEN(_name, _msg) \
+ do { \
+ int field_len; \
+ CHKSTR(_name, _msg); \
+ field_len = FIELD_SIZEOF(struct img_header, _name) - 1; \
+ if (strlen(_name) > field_len) { \
+ ERR("%s is too long, max length is %d", \
+ _msg, field_len); \
+ return -1; \
+ } \
+ } while (0)
+
+ CHKSTRLEN(model, "model");
+ CHKSTRLEN(signature, "signature");
+ CHKSTRLEN(region, "region");
+ CHKSTRLEN(version, "version");
+ CHKSTR(ofname, "output file");
+ CHKSTR(kernel_info.file_name, "kernel image");
+
+ ret = get_file_stat(&kernel_info);
+ if (ret)
+ return ret;
+
+ if (combined) {
+ if (!kernel_size) {
+ ERR("kernel size must be specified for combined images");
+ return -1; \
+ }
+
+ if (!image_size)
+ image_size = kernel_info.file_size;
+
+ if (kernel_info.file_size > image_size) {
+ ERR("kernel image is too big");
+ return -1;
+ }
+
+ kernel_info.write_size = image_size;
+ } else {
+ CHKSTR(rootfs_info.file_name, "rootfs image");
+
+ ret = get_file_stat(&rootfs_info);
+ if (ret)
+ return ret;
+
+ if (kernel_size) {
+ /* override kernel size */
+ kernel_info.write_size = kernel_size;
+ }
+
+ if (image_size) {
+ if (image_size < kernel_info.write_size)
+ kernel_info.write_size = image_size;
+
+ /* override rootfs size */
+ rootfs_info.write_size = image_size - kernel_info.write_size;
+ }
+
+ if (kernel_info.file_size > kernel_info.write_size) {
+ ERR("kernel image is too big");
+ return -1;
+ }
+
+ if (rootfs_info.file_size > rootfs_info.write_size) {
+ ERR("rootfs image is too big");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int write_fw(char *data, int len)
+{
+ FILE *f;
+ int ret = EXIT_FAILURE;
+
+ f = fopen(ofname, "w");
+ if (f == NULL) {
+ ERRS("could not open \"%s\" for writing", ofname);
+ goto out;
+ }
+
+ errno = 0;
+ fwrite(data, len, 1, f);
+ if (errno) {
+ ERRS("unable to write output file");
+ goto out_flush;
+ }
+
+ DBG("firmware file \"%s\" completed", ofname);
+
+ ret = EXIT_SUCCESS;
+
+out_flush:
+ fflush(f);
+ fclose(f);
+ if (ret != EXIT_SUCCESS) {
+ unlink(ofname);
+ }
+out:
+ return ret;
+}
+
+static uint32_t get_csum(unsigned char *p, uint32_t len)
+{
+ uint32_t csum = 0;
+
+ while (len--)
+ csum += *p++;
+
+ return csum;
+}
+
+static int build_fw(void)
+{
+ int buflen;
+ char *buf;
+ char *p;
+ uint32_t csum;
+ struct img_header *hdr;
+ int ret = EXIT_FAILURE;
+
+ buflen = sizeof(struct img_header) +
+ kernel_info.write_size + rootfs_info.write_size;
+
+ buf = malloc(buflen);
+ if (!buf) {
+ ERR("no memory for buffer\n");
+ goto out;
+ }
+
+ memset(buf, 0, buflen);
+
+ p = buf + sizeof(struct img_header);
+
+ /* read kernel data */
+ ret = read_to_buf(&kernel_info, p);
+ if (ret)
+ goto out_free_buf;
+
+ if (!combined) {
+ p += kernel_info.write_size;
+
+ /* read rootfs data */
+ ret = read_to_buf(&rootfs_info, p);
+ if (ret)
+ goto out_free_buf;
+ }
+
+ csum = get_csum((unsigned char *)(buf + sizeof(struct img_header)),
+ buflen - sizeof(struct img_header));
+
+ /* fill firmware header */
+ hdr = (struct img_header *) buf;
+
+ hdr->checksum = htonl(csum);
+ hdr->image_size = htonl(buflen - sizeof(struct img_header));
+ if (!combined)
+ hdr->kernel_size = htonl(kernel_info.write_size);
+ else
+ hdr->kernel_size = htonl(kernel_size);
+ hdr->header_len = sizeof(struct img_header);
+ strncpy(hdr->model, model, sizeof(hdr->model));
+ strncpy(hdr->signature, signature, sizeof(hdr->signature));
+ strncpy(hdr->version, version, sizeof(hdr->version));
+ strncpy(hdr->region, region, sizeof(hdr->region));
+
+ ret = write_fw(buf, buflen);
+ if (ret)
+ goto out_free_buf;
+
+ ret = EXIT_SUCCESS;
+
+out_free_buf:
+ free(buf);
+out:
+ return ret;
+}
+
+int main(int argc, char *argv[])
+{
+ int ret = EXIT_FAILURE;
+
+ progname = basename(argv[0]);
+
+ while (1) {
+ int c;
+
+ c = getopt(argc, argv, "M:S:V:R:k:K:I:r:o:hc");
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'M':
+ model = optarg;
+ break;
+ case 'S':
+ signature = optarg;
+ break;
+ case 'V':
+ version = optarg;
+ break;
+ case 'R':
+ region = optarg;
+ break;
+ case 'k':
+ kernel_info.file_name = optarg;
+ break;
+ case 'K':
+ if (str2u32(optarg, &kernel_size)) {
+ ERR("%s is invalid '%s'",
+ "kernel size", optarg);
+ goto out;
+ }
+ break;
+ case 'I':
+ if (str2u32(optarg, &image_size)) {
+ ERR("%s is invalid '%s'",
+ "image size", optarg);
+ goto out;
+ }
+ break;
+ case 'r':
+ rootfs_info.file_name = optarg;
+ break;
+ case 'c':
+ combined = 1;
+ break;
+ case 'o':
+ ofname = optarg;
+ break;
+ case 'h':
+ usage(EXIT_SUCCESS);
+ break;
+ default:
+ usage(EXIT_FAILURE);
+ break;
+ }
+ }
+
+ ret = check_options();
+ if (ret)
+ goto out;
+
+ ret = build_fw();
+
+out:
+ return ret;
+}
+
diff --git a/tools/firmware-utils/src/mkcasfw.c b/tools/firmware-utils/src/mkcasfw.c
index 626e77d4c49..5655bf1894c 100644
--- a/tools/firmware-utils/src/mkcasfw.c
+++ b/tools/firmware-utils/src/mkcasfw.c
@@ -258,7 +258,7 @@ static struct board_info boards[] = {
#define ERRS(fmt, ...) do { \
int save = errno; \
fflush(0); \
- fprintf(stderr, "[%s] *** error: " fmt "\n", \
+ fprintf(stderr, "[%s] *** error: " fmt ": %s\n", \
progname, ## __VA_ARGS__, strerror(save)); \
} while (0)
@@ -708,7 +708,7 @@ image_writeout(FILE *outfile, struct image_desc *desc)
/* write padding data if neccesary */
padlen = desc->out_size - desc->file_size;
- DBG(1,"padding desc, length=%d", padlen);
+ DBG(1,"padding desc, length=%zu", padlen);
res = write_out_padding(outfile, padlen, desc->padc, &css);
desc->csum = csum_get(&css);
@@ -985,11 +985,11 @@ main(int argc, char *argv[])
res = ERR_FATAL;
if (keep_invalid_images == 0) {
- WARN("generation of invalid images disabled", ofname);
+ WARN("generation of invalid images \"%s\" disabled", ofname);
goto out;
}
- WARN("generating invalid image", ofname);
+ WARN("generating invalid image: \"%s\"", ofname);
}
outfile = fopen(ofname, "w");
diff --git a/tools/firmware-utils/src/mkchkimg.c b/tools/firmware-utils/src/mkchkimg.c
index e152f7d4685..0fe01f07079 100644
--- a/tools/firmware-utils/src/mkchkimg.c
+++ b/tools/firmware-utils/src/mkchkimg.c
@@ -31,6 +31,20 @@
#define MAX_BOARD_ID_LEN (64)
+/*
+ * Note on the reserved field of the chk_header:
+ * OFW naming scheme is typically: DEVICENAME-VA.B.C.D_E.F.G.chk, with A-G
+ * between 0 and 255. For instance: EX3700_EX3800-V1.0.0.58_1.0.38.chk
+ * The reserved field works like this:
+ * reserved[0]: region code. 1 for WW (WorldWide) and 2 for NA (North America)
+ * reserved[1]: A
+ * reserved[2]: B
+ * reserved[3]: C
+ * reserved[4]: D
+ * reserved[5]: E
+ * reserved[6]: F
+ * reserved[7]: G
+ */
struct chk_header {
uint32_t magic;
uint32_t header_len;
@@ -248,10 +262,10 @@ main (int argc, char * argv[])
hdr->reserved[1] = 1; /* Major */
hdr->reserved[2] = 1; /* Minor */
hdr->reserved[3] = 99; /* Build */
- hdr->reserved[4] = 0; /* Unknown t1 ? was 1 */
- hdr->reserved[5] = 0; /* Unknonw t2 ? was 0 */
- hdr->reserved[6] = 0; /* Unknonw t3 ? was 1 */
- hdr->reserved[7] = 0; /* Unused ? */
+ hdr->reserved[4] = 0;
+ hdr->reserved[5] = 0;
+ hdr->reserved[6] = 0;
+ hdr->reserved[7] = 0;
message (" Board Id: %s", board_id);
message (" Region: %s", region == 1 ? "World Wide (WW)"
: (region == 2 ? "North America (NA)" : "Unknown"));
diff --git a/tools/firmware-utils/src/mkcsysimg.c b/tools/firmware-utils/src/mkcsysimg.c
index 4f2352a60e7..77fbbaa57fa 100644
--- a/tools/firmware-utils/src/mkcsysimg.c
+++ b/tools/firmware-utils/src/mkcsysimg.c
@@ -160,6 +160,7 @@ static struct board_info boards[] = {
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-6524N", "Edimax BR-6524N", 2, SIG_BR6524N),
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),
@@ -198,7 +199,7 @@ static struct board_info boards[] = {
#define ERRS(fmt, ...) do { \
int save = errno; \
fflush(0); \
- fprintf(stderr, "[%s] *** error: " fmt "\n", progname, ## __VA_ARGS__ \
+ fprintf(stderr, "[%s] *** error: " fmt ": %s\n", progname, ## __VA_ARGS__ \
, strerror(save)); \
} while (0)
@@ -646,7 +647,7 @@ block_writeout_data(FILE *outfile, struct csys_block *block)
/* write padding data if neccesary */
padlen = block->size_avail - block->file_size;
- DBG(1,"padding block, length=%d", padlen);
+ DBG(1,"padding block, length=%zu", padlen);
res = write_out_padding(outfile, padlen, block->padc, block->css);
return res;
@@ -1121,11 +1122,11 @@ main(int argc, char *argv[])
res = ERR_FATAL;
if (keep_invalid_images == 0) {
- WARN("generation of invalid images disabled", ofname);
+ WARN("generation of invalid images \"%s\" disabled", ofname);
goto out;
}
- WARN("generating invalid image", ofname);
+ WARN("generating invalid image: \"%s\"", ofname);
}
outfile = fopen(ofname, "w");
diff --git a/tools/firmware-utils/src/mkdapimg.c b/tools/firmware-utils/src/mkdapimg.c
new file mode 100644
index 00000000000..ed662d8ecc0
--- /dev/null
+++ b/tools/firmware-utils/src/mkdapimg.c
@@ -0,0 +1,226 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <libgen.h>
+#include <stdarg.h>
+#include <getopt.h>
+#include <string.h>
+#include <errno.h>
+
+#include <netinet/in.h> // htonl
+
+// Usage: mkdapimg [-p] [-m <model>] -s <sig> -i <input> -o <output>
+//
+// e.g.: mkdapimg -s RT3052-AP-DAP1350-3 -i sysupgarde.bin -o factory.bin
+//
+// If the model string <model> is not given, we will assume that
+// the leading characters upto the first "-" is the model.
+//
+// The "-p" (patch) option is used to patch the exisiting image with the
+// specified model and signature.
+// The "-x" (fix) option will recalculate the payload size and checksum
+// during the patch mode operation.
+
+// The img_hdr_struct was taken from the D-Link SDK:
+// DAP-1350_A1_FW1.11NA_GPL/GPL_Source_Code/Uboot/DAP-1350/httpd/header.h
+
+#define MAX_MODEL_NAME_LEN 20
+#define MAX_SIG_LEN 30
+#define MAX_REGION_LEN 4
+#define MAX_VERSION_LEN 12
+
+struct img_hdr_struct {
+ uint32_t checksum;
+ char model[MAX_MODEL_NAME_LEN];
+ char sig[MAX_SIG_LEN];
+ uint8_t partition;
+ uint8_t hdr_len;
+ uint8_t rsv1;
+ uint8_t rsv2;
+ uint32_t flash_byte_cnt;
+} imghdr ;
+
+char *progname;
+
+void
+perrexit(int code, char *msg)
+{
+ fprintf(stderr, "%s: %s: %s\n", progname, msg, strerror(errno));
+ exit(code);
+}
+
+void
+usage()
+{
+ fprintf(stderr, "usage: %s [-p] [-m model] [-r region] [-v version] -s signature -i input -o output\n", progname);
+ exit(1);
+}
+
+int
+main(int ac, char *av[])
+{
+ char model[MAX_MODEL_NAME_LEN+1];
+ char signature[MAX_SIG_LEN+1];
+ char region[MAX_REGION_LEN+1];
+ char version[MAX_VERSION_LEN+1];
+ int patchmode = 0;
+ int fixmode = 0;
+ int have_regionversion = 0;
+
+ FILE *ifile, *ofile;
+ int c;
+ uint32_t cksum;
+ uint32_t bcnt;
+
+ progname = basename(av[0]);
+ memset(model, 0, sizeof(model));
+ memset(signature, 0, sizeof(signature));
+ memset(region, 0, sizeof(region));
+ memset(version, 0, sizeof(version));
+
+ while ( 1 ) {
+ int c;
+
+ c = getopt(ac, av, "pxm:r:v:s:i:o:");
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'p':
+ patchmode = 1;
+ break;
+ case 'x':
+ fixmode = 1;
+ break;
+ case 'm':
+ if (strlen(optarg) > MAX_MODEL_NAME_LEN) {
+ fprintf(stderr, "%s: model name exceeds %d chars\n",
+ progname, MAX_MODEL_NAME_LEN);
+ exit(1);
+ }
+ strcpy(model, optarg);
+ break;
+ case 'r':
+ if (strlen(optarg) > MAX_REGION_LEN) {
+ fprintf(stderr, "%s: region exceeds %d chars\n",
+ progname, MAX_REGION_LEN);
+ exit(1);
+ }
+ have_regionversion = 1;
+ strcpy(region, optarg);
+ break;
+ case 'v':
+ if (strlen(optarg) > MAX_VERSION_LEN) {
+ fprintf(stderr, "%s: version exceeds %d chars\n",
+ progname, MAX_VERSION_LEN);
+ exit(1);
+ }
+ have_regionversion = 1;
+ strcpy(version, optarg);
+ break;
+ case 's':
+ if (strlen(optarg) > MAX_SIG_LEN) {
+ fprintf(stderr, "%s: signature exceeds %d chars\n",
+ progname, MAX_SIG_LEN);
+ exit(1);
+ }
+ strcpy(signature, optarg);
+ break;
+ case 'i':
+ if ((ifile = fopen(optarg, "r")) == NULL)
+ perrexit(1, optarg);
+ break;
+ case 'o':
+ if ((ofile = fopen(optarg, "w")) == NULL)
+ perrexit(1, optarg);
+ break;
+ default:
+ usage();
+ }
+ }
+
+ if (signature[0] == 0 || ifile == NULL || ofile == NULL) {
+ usage();
+ }
+
+ if (model[0] == 0) {
+ char *p = strchr(signature, '-');
+ if (p == NULL) {
+ fprintf(stderr, "%s: model name unknown\n", progname);
+ exit(1);
+ }
+ if (p - signature > MAX_MODEL_NAME_LEN) {
+ *p = 0;
+ fprintf(stderr, "%s: auto model name failed, string %s too long\n", progname, signature);
+ exit(1);
+ }
+ strncpy(model, signature, p - signature);
+ }
+
+ if (patchmode) {
+ if (fread(&imghdr, sizeof(imghdr), 1, ifile) < 0)
+ perrexit(2, "fread on input");
+ }
+
+ for (bcnt = 0, cksum = 0 ; (c = fgetc(ifile)) != EOF ; bcnt++)
+ cksum += c & 0xff;
+
+ if (fseek(ifile, patchmode ? sizeof(imghdr) : 0, SEEK_SET) < 0)
+ perrexit(2, "fseek on input");
+
+ if (patchmode == 0) {
+ // Fill in the header
+ memset(&imghdr, 0, sizeof(imghdr));
+ imghdr.checksum = htonl(cksum);
+ imghdr.partition = 0 ; // don't care?
+ imghdr.hdr_len = sizeof(imghdr);
+ if (have_regionversion) {
+ imghdr.hdr_len += MAX_REGION_LEN;
+ imghdr.hdr_len += MAX_VERSION_LEN;
+ }
+ imghdr.flash_byte_cnt = htonl(bcnt);
+ } else {
+ if (ntohl(imghdr.checksum) != cksum) {
+ fprintf(stderr, "%s: patch mode, checksum mismatch\n",
+ progname);
+ if (fixmode) {
+ fprintf(stderr, "%s: fixing\n", progname);
+ imghdr.checksum = htonl(cksum);
+ } else
+ exit(3);
+ } else if (ntohl(imghdr.flash_byte_cnt) != bcnt) {
+ fprintf(stderr, "%s: patch mode, size mismatch\n",
+ progname);
+ if (fixmode) {
+ fprintf(stderr, "%s: fixing\n", progname);
+ imghdr.flash_byte_cnt = htonl(bcnt);
+ } else
+ exit(3);
+ }
+ }
+
+ strncpy(imghdr.model, model, MAX_MODEL_NAME_LEN);
+ strncpy(imghdr.sig, signature, MAX_SIG_LEN);
+
+ if (fwrite(&imghdr, sizeof(imghdr), 1, ofile) < 0)
+ perrexit(2, "fwrite header on output");
+ if (have_regionversion) {
+ if (fwrite(&region, MAX_REGION_LEN, 1, ofile) < 0)
+ perrexit(2, "fwrite header on output");
+ if (fwrite(&version, MAX_VERSION_LEN, 1, ofile) < 0)
+ perrexit(2, "fwrite header on output");
+ }
+
+ while ((c = fgetc(ifile)) != EOF) {
+ if (fputc(c, ofile) == EOF)
+ perrexit(2, "fputc on output");
+ }
+
+ if (ferror(ifile))
+ perrexit(2, "fgetc on input");
+
+
+ fclose(ofile);
+ fclose(ifile);
+}
diff --git a/tools/firmware-utils/src/mkdapimg2.c b/tools/firmware-utils/src/mkdapimg2.c
new file mode 100644
index 00000000000..aef003c280c
--- /dev/null
+++ b/tools/firmware-utils/src/mkdapimg2.c
@@ -0,0 +1,204 @@
+/*
+ * 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.
+ *
+ * (C) Nicolò Veronese <nicveronese@gmail.com>
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <libgen.h>
+#include <stdarg.h>
+#include <getopt.h>
+#include <string.h>
+#include <errno.h>
+
+#include <netinet/in.h> // htonl
+
+// Usage: mkdapimg2 -s signature [-v version] [-r region]
+// [-k uImage block size] -i <input> -o <output>
+//
+// NOTE: The kernel block size is used to know the offset of the rootfs
+// in the image file.
+//
+// The system writes in the uImage partition until the end of uImage
+// is reached, after that, the system jumps to the offset specified with the -k
+// parameter and begin writing at the beginning of the rootfs MTD partition.
+//
+// If the -k parameter is the size of the original uImage partition, the system
+// continue writing in the rootfs partition starting from the last block
+// that has been wrote. (This is useful if the new kernel size is
+// different from the original one)
+//
+// Example:
+// ------------------------------------------
+// Creating 7 MTD partitions on "ath-nor0":
+// 0x000000000000-0x000000010000 : "u-boot"
+// 0x000000010000-0x000000020000 : "ART"
+// 0x000000020000-0x000000030000 : "MP"
+// 0x000000030000-0x000000040000 : "config"
+// 0x000000040000-0x000000120000 : "uImage"
+// 0x000000120000-0x000000800000 : "rootfs"
+// 0x000000040000-0x000000800000 : "firmware"
+// ------------------------------------------
+//
+// 0x000000120000-0x000000040000 = 0xE0000 -> 917504
+//
+// e.g.: mkdapimg2 -s HONEYBEE-FIRMWARE-DAP-1330 -v 1.00.21 -r Default
+// -k 917504 -i sysupgarde.bin -o factory.bin
+//
+//
+// The img_hdr_struct was taken from the D-Link SDK:
+// DAP-1330_OSS-firmware_1.00b21/DAP-1330_OSS-firmware_1.00b21/uboot/uboot.patch
+
+#define MAX_SIGN_LEN 32
+#define MAX_FW_VER_LEN 16
+#define MAX_REG_LEN 8
+
+struct img_hdr_struct {
+ uint32_t hdr_len;
+ uint32_t checksum;
+ uint32_t total_size;
+ uint32_t kernel_size;
+ char signature[MAX_SIGN_LEN];
+ char fw_ver[MAX_FW_VER_LEN];
+ char fw_reg[MAX_REG_LEN];
+} imghdr ;
+
+char *progname;
+
+void
+perrexit(int code, char *msg)
+{
+ fprintf(stderr, "%s: %s: %s\n", progname, msg, strerror(errno));
+ exit(code);
+}
+
+void
+usage()
+{
+ fprintf(stderr, "usage: %s -s signature [-v version] [-r region] [-k uImage part size] -i <input> -o <output>\n", progname);
+ exit(1);
+}
+
+int
+main(int ac, char *av[])
+{
+ char signature[MAX_SIGN_LEN];
+ char version[MAX_FW_VER_LEN];
+ char region[MAX_REG_LEN];
+ int kernel = 0;
+
+ FILE *ifile, *ofile;
+ int c;
+
+ uint32_t cksum;
+ uint32_t bcnt;
+
+ progname = basename(av[0]);
+
+ memset(signature, 0, sizeof(signature));
+ memset(version, 0, sizeof(version));
+ memset(region, 0, sizeof(region));
+
+ while ( 1 ) {
+ char *ptr;
+ int c;
+
+ c = getopt(ac, av, "s:v:r:k:i:o:");
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 's':
+ if (strlen(optarg) > MAX_SIGN_LEN + 1) {
+ fprintf(stderr, "%s: signature exceeds %d chars\n",
+ progname, MAX_SIGN_LEN);
+ exit(1);
+ }
+ strcpy(signature, optarg);
+ break;
+ case 'v':
+ if (strlen(optarg) > MAX_FW_VER_LEN + 1) {
+ fprintf(stderr, "%s: version exceeds %d chars\n",
+ progname, MAX_FW_VER_LEN);
+ exit(1);
+ }
+ strcpy(version, optarg);
+ break;
+ case 'r':
+ if (strlen(optarg) > MAX_REG_LEN + 1) {
+ fprintf(stderr, "%s: region exceeds %d chars\n",
+ progname, MAX_REG_LEN);
+ exit(1);
+ }
+ strcpy(region, optarg);
+ break;
+ case 'k':
+ kernel = strtoul(optarg, &ptr, 0);
+ if(ptr[0] == 'k'){
+ kernel *= 1000;
+ }
+ break;
+ case 'i':
+ if ((ifile = fopen(optarg, "r")) == NULL)
+ perrexit(1, optarg);
+ break;
+ case 'o':
+ if ((ofile = fopen(optarg, "w")) == NULL)
+ perrexit(1, optarg);
+ break;
+ default:
+ usage();
+ }
+ }
+
+ if (signature[0] == 0 || ifile == NULL || ofile == NULL) {
+ usage();
+ exit(1);
+ }
+
+ for (bcnt = 0, cksum = 0 ; (c = fgetc(ifile)) != EOF ; bcnt++)
+ cksum += c & 0xff;
+
+ if (fseek(ifile, 0, SEEK_SET) < 0)
+ perrexit(2, "fseek on input");
+
+ // Fill in the header
+ memset(&imghdr, 0, sizeof(imghdr));
+ imghdr.hdr_len = sizeof(imghdr);
+ imghdr.checksum = htonl(cksum);
+ imghdr.total_size = htonl(bcnt);
+ imghdr.kernel_size = htonl(kernel);
+
+ strncpy(imghdr.signature, signature, MAX_SIGN_LEN);
+ strncpy(imghdr.fw_ver, version, MAX_FW_VER_LEN);
+ strncpy(imghdr.fw_reg, region, MAX_REG_LEN);
+
+ if (fwrite(&imghdr, sizeof(imghdr), 1, ofile) < 0)
+ perrexit(2, "fwrite header on output");
+
+ while ((c = fgetc(ifile)) != EOF) {
+ if (fputc(c, ofile) == EOF)
+ perrexit(2, "fputc on output");
+ }
+
+ if (ferror(ifile))
+ perrexit(2, "fgetc on input");
+
+ fclose(ofile);
+ fclose(ifile);
+
+ fprintf(stderr, "imgHdr.hdr_len = %lu\n", sizeof(imghdr));
+ fprintf(stderr, "imgHdr.checksum = 0x%08x\n", cksum);
+ fprintf(stderr, "imgHdr.total_size = 0x%08x\n", bcnt);
+ fprintf(stderr, "imgHdr.kernel_size = 0x%08x\n", kernel);
+ fprintf(stderr, "imgHdr.header = %s\n", signature);
+ fprintf(stderr, "imgHdr.fw_ver = %s\n", version);
+ fprintf(stderr, "imgHdr.fw_reg = %s\n", region);
+
+ return 0;
+}
diff --git a/tools/firmware-utils/src/mkdcs932.c b/tools/firmware-utils/src/mkdcs932.c
new file mode 100644
index 00000000000..28c67aa3b30
--- /dev/null
+++ b/tools/firmware-utils/src/mkdcs932.c
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ *
+ * (C) John Crispin <blogic@openwrt.org>
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <errno.h>
+
+int main(int argc, char **argv)
+{
+ uint32_t t = 0, sum = 0x55aa55aa;
+ int fd;
+
+ if ((argc != 2) || ((fd = open(argv[1], O_RDWR)) == -1)) {
+ fprintf(stderr, "Usage: %s input_file\n", *argv);
+ return -EINVAL;
+ }
+
+ lseek(fd, -4, SEEK_END);
+ write(fd, &t, 4);
+ lseek(fd, 0, SEEK_SET);
+
+ while (read(fd, &t, 4) > 0)
+ sum -= t;
+
+ lseek(fd, -4, SEEK_END);
+ write(fd, &sum, 4);
+ close(fd);
+
+ return 0;
+}
diff --git a/tools/firmware-utils/src/mkdhpimg.c b/tools/firmware-utils/src/mkdhpimg.c
new file mode 100644
index 00000000000..e61d0425043
--- /dev/null
+++ b/tools/firmware-utils/src/mkdhpimg.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2016 FUKAUMI Naoki <naobsd@gmail.com>
+ *
+ * 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 <sys/stat.h>
+#include <err.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "buffalo-lib.h"
+
+#define DHP_HEADER_SIZE 20
+
+static char *progname;
+
+static void
+usage(void)
+{
+
+ fprintf(stderr, "usage: %s <in> <out>\n", progname);
+ exit(EXIT_FAILURE);
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct stat in_st;
+ size_t size;
+ uint32_t crc;
+ int in, out;
+ uint8_t *buf;
+
+ progname = argv[0];
+
+ if (argc != 3)
+ usage();
+
+ if ((in = open(argv[1], O_RDONLY)) == -1)
+ err(EXIT_FAILURE, "%s", argv[1]);
+
+ if (fstat(in, &in_st) == -1)
+ err(EXIT_FAILURE, "%s", argv[1]);
+
+ size = DHP_HEADER_SIZE + in_st.st_size;
+
+ if ((buf = malloc(size)) == NULL)
+ err(EXIT_FAILURE, "malloc");
+
+ memset(buf, 0, DHP_HEADER_SIZE);
+ buf[0x0] = 0x62;
+ buf[0x1] = 0x67;
+ buf[0x2] = 0x6e;
+ buf[0xb] = 0xb1;
+ buf[0xc] = (size >> 24) & 0xff;
+ buf[0xd] = (size >> 16) & 0xff;
+ buf[0xe] = (size >> 8) & 0xff;
+ buf[0xf] = size & 0xff;
+
+ read(in, &buf[DHP_HEADER_SIZE], in_st.st_size);
+ close(in);
+
+ crc = buffalo_crc(buf, size);
+ buf[0x10] = (crc >> 24) & 0xff;
+ buf[0x11] = (crc >> 16) & 0xff;
+ buf[0x12] = (crc >> 8) & 0xff;
+ buf[0x13] = crc & 0xff;
+
+ if ((out = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0644)) == -1)
+ err(EXIT_FAILURE, "%s", argv[2]);
+ write(out, buf, size);
+ close(out);
+
+ free(buf);
+
+ return EXIT_SUCCESS;
+}
diff --git a/tools/firmware-utils/src/mkdlinkfw-lib.c b/tools/firmware-utils/src/mkdlinkfw-lib.c
new file mode 100644
index 00000000000..fcab8562319
--- /dev/null
+++ b/tools/firmware-utils/src/mkdlinkfw-lib.c
@@ -0,0 +1,172 @@
+/*
+ * mkdlinkfw
+ *
+ * Copyright (C) 2018 Paweł Dembicki <paweldembicki@gmail.com>
+ *
+ * This tool is based on mktplinkfw.
+ * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008,2009 Wang Jian <lark@linux.net.cn>
+ *
+ * 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.
+ */
+
+#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 <stdbool.h>
+#include <endian.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <zlib.h> /*for crc32 */
+
+#include "mkdlinkfw-lib.h"
+
+extern char *progname;
+
+static unsigned char jffs2_eof_mark[4] = { 0xde, 0xad, 0xc0, 0xde };
+
+uint32_t jboot_timestamp(void)
+{
+ time_t rawtime;
+ time(&rawtime);
+ return (((uint32_t) rawtime) - TIMESTAMP_MAGIC) >> 2;
+}
+
+uint16_t jboot_checksum(uint16_t start_val, uint16_t *data, int size)
+{
+ uint32_t counter = start_val;
+ uint16_t *ptr = data;
+
+ while (size > 1) {
+ counter += *ptr;
+ ++ptr;
+ while (counter >> 16)
+ counter = (uint16_t) counter + (counter >> 16);
+ size -= 2;
+ }
+ if (size > 0) {
+ counter += *(uint8_t *) ptr;
+ counter -= 0xFF;
+ }
+ while (counter >> 16)
+ counter = (uint16_t) counter + (counter >> 16);
+ return counter;
+}
+
+int get_file_stat(struct file_info *fdata)
+{
+ struct stat st;
+ int res;
+
+ if (fdata->file_name == NULL)
+ return 0;
+
+ res = stat(fdata->file_name, &st);
+ if (res) {
+ ERRS("stat failed on %s", fdata->file_name);
+ return res;
+ }
+
+ fdata->file_size = st.st_size;
+ return 0;
+}
+
+int read_to_buf(const struct file_info *fdata, char *buf)
+{
+ FILE *f;
+ int ret = EXIT_FAILURE;
+
+ f = fopen(fdata->file_name, "r");
+ if (f == NULL) {
+ ERRS("could not open \"%s\" for reading", fdata->file_name);
+ goto out;
+ }
+
+ errno = 0;
+ fread(buf, fdata->file_size, 1, f);
+ if (errno != 0) {
+ ERRS("unable to read from file \"%s\"", fdata->file_name);
+ goto out_close;
+ }
+
+ ret = EXIT_SUCCESS;
+
+ out_close:
+ fclose(f);
+ out:
+ return ret;
+}
+
+int pad_jffs2(char *buf, int currlen, int maxlen)
+{
+ int len;
+ uint32_t pad_mask;
+
+ len = currlen;
+ pad_mask = (4 * 1024) | (64 * 1024); /* EOF at 4KB and at 64KB */
+ while ((len < maxlen) && (pad_mask != 0)) {
+ uint32_t mask;
+ int i;
+
+ for (i = 10; i < 32; i++) {
+ mask = 1 << i;
+ if (pad_mask & mask)
+ break;
+ }
+
+ len = ALIGN(len, mask);
+
+ for (i = 10; i < 32; i++) {
+ mask = 1 << i;
+ if ((len & (mask - 1)) == 0)
+ pad_mask &= ~mask;
+ }
+
+ for (i = 0; i < sizeof(jffs2_eof_mark); i++)
+ buf[len + i] = jffs2_eof_mark[i];
+
+ len += sizeof(jffs2_eof_mark);
+ }
+
+ return len;
+}
+
+int write_fw(const char *ofname, const char *data, int len)
+{
+ FILE *f;
+ int ret = EXIT_FAILURE;
+
+ f = fopen(ofname, "w");
+ if (f == NULL) {
+ ERRS("could not open \"%s\" for writing", ofname);
+ goto out;
+ }
+
+ errno = 0;
+ fwrite(data, len, 1, f);
+ if (errno) {
+ ERRS("unable to write output file");
+ goto out_flush;
+ }
+
+ DBG("firmware file \"%s\" completed", ofname);
+
+ ret = EXIT_SUCCESS;
+
+ out_flush:
+ fflush(f);
+ fclose(f);
+ if (ret != EXIT_SUCCESS)
+ unlink(ofname);
+ out:
+ return ret;
+}
diff --git a/tools/firmware-utils/src/mkdlinkfw-lib.h b/tools/firmware-utils/src/mkdlinkfw-lib.h
new file mode 100644
index 00000000000..d61124cb636
--- /dev/null
+++ b/tools/firmware-utils/src/mkdlinkfw-lib.h
@@ -0,0 +1,83 @@
+/*
+ * mkdlinkfw
+ *
+ * Copyright (C) 2018 Paweł Dembicki <paweldembicki@gmail.com>
+ *
+ * This tool is based on mktplinkfw.
+ * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008,2009 Wang Jian <lark@linux.net.cn>
+ *
+ * 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.
+ */
+
+#ifndef mkdlinkfw_lib_h
+#define mkdlinkfw_lib_h
+
+#define AUH_MAGIC "DLK"
+#define AUH_SIZE 80
+#define AUH_LVPS 0x01
+#define AUH_HDR_ID 0x4842
+#define AUH_HDR_VER 0x02
+#define AUH_SEC_ID 0x04
+#define AUH_INFO_TYPE 0x04
+
+#define STAG_SIZE 16
+#define STAG_ID 0x04
+#define STAG_MAGIC 0x2B24
+#define STAG_CMARK_FACTORY 0xFF
+
+#define SCH2_SIZE 40
+#define SCH2_MAGIC 0x2124
+#define SCH2_VER 0x02
+
+#define FLAT 0
+#define JZ 1
+#define GZIP 2
+#define LZMA 3
+
+#define RAM_ENTRY_ADDR 0x80000000
+#define RAM_LOAD_ADDR 0x80000000
+#define JBOOT_SIZE 0x10000
+
+#define ALL_HEADERS_SIZE (AUH_SIZE + STAG_SIZE + SCH2_SIZE)
+#define MAX_HEADER_COUNTER 10
+#define TIMESTAMP_MAGIC 0x35016f00L
+
+#define FACTORY 0
+#define SYSUPGRADE 1
+
+#define ALIGN(x, a) ({ typeof(a) __a = (a); (((x) + __a - 1) & ~(__a - 1)); })
+
+#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 DBG(fmt, ...) do { \
+ fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__); \
+} while (0)
+
+struct file_info {
+ char *file_name; /* name of the file */
+ uint32_t file_size; /* length of the file */
+};
+
+uint32_t jboot_timestamp(void);
+uint16_t jboot_checksum(uint16_t start_val, uint16_t *data, int size);
+int get_file_stat(struct file_info *fdata);
+int read_to_buf(const struct file_info *fdata, char *buf);
+int pad_jffs2(char *buf, int currlen, int maxlen);
+int write_fw(const char *ofname, const char *data, int len);
+
+#endif /* mkdlinkfw_lib_h */
diff --git a/tools/firmware-utils/src/mkdlinkfw.c b/tools/firmware-utils/src/mkdlinkfw.c
new file mode 100644
index 00000000000..87605004fe9
--- /dev/null
+++ b/tools/firmware-utils/src/mkdlinkfw.c
@@ -0,0 +1,665 @@
+/*
+ * mkdlinkfw
+ *
+ * Copyright (C) 2018 Paweł Dembicki <paweldembicki@gmail.com>
+ *
+ * This tool is based on mktplinkfw.
+ * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008,2009 Wang Jian <lark@linux.net.cn>
+ *
+ * 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.
+ */
+
+#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 <stdbool.h>
+#include <endian.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <zlib.h> /*for crc32 */
+
+#include "mkdlinkfw-lib.h"
+
+/* ARM update header 2.0
+ * used only in factory images to erase and flash selected area
+ */
+struct auh_header {
+ uint8_t rom_id[12]; /* 12-bit rom-id unique per router type */
+ uint16_t derange; /* used for scramble header */
+ uint16_t image_checksum; /* jboot_checksum of flashed data */
+
+ uint32_t space1; /* zeros */
+ uint32_t space2; /* zeros */
+ uint16_t space3; /* zerosu */
+ uint8_t lpvs; /* must be 0x01 */
+ uint8_t mbz; /* bust be 0 */
+ uint32_t time_stamp; /* timestamp calculated in jboot way */
+
+ uint32_t erase_start; /* erase start address */
+ uint32_t erase_length; /* erase length address */
+ uint32_t data_offset; /* data start address */
+ uint32_t data_length; /* data length address */
+
+ uint32_t space4; /* zeros */
+ uint32_t space5; /* zeros */
+ uint32_t space6; /* zeros */
+ uint32_t space7; /* zeros */
+
+ uint16_t header_id; /* magic 0x4842 */
+ uint16_t header_version; /* 0x02 for 2.0 */
+ uint16_t space8; /* zeros */
+ uint8_t section_id; /* section id */
+ uint8_t image_info_type; /* (?) 0x04 in factory images */
+ uint32_t image_info_offset; /* (?) zeros in factory images */
+ uint16_t family_member; /* unique per router type */
+ uint16_t header_checksum; /* negated jboot_checksum of header data */
+};
+
+struct stag_header { /* used only of sch2 wrapped kernel data */
+ uint8_t cmark; /* in factory 0xFF ,in sysuograde must be the same as id */
+ uint8_t id; /* 0x04 */
+ uint16_t magic; /* magic 0x2B24 */
+ uint32_t time_stamp; /* timestamp calculated in jboot way */
+ uint32_t image_length; /* lentgh of kernel + sch2 header */
+ uint16_t image_checksum; /* negated jboot_checksum of sch2 + kernel */
+ uint16_t tag_checksum; /* negated jboot_checksum of stag header data */
+};
+
+struct sch2_header { /* used only in kernel partitions */
+ uint16_t magic; /* magic 0x2124 */
+ uint8_t cp_type; /* 0x00 for flat, 0x01 for jz, 0x02 for gzip, 0x03 for lzma */
+ uint8_t version; /* 0x02 for sch2 */
+ uint32_t ram_addr; /* ram entry address */
+ uint32_t image_len; /* kernel image length */
+ uint32_t image_crc32; /* kernel image crc */
+ uint32_t start_addr; /* ram start address */
+ uint32_t rootfs_addr; /* rootfs flash address */
+ uint32_t rootfs_len; /* rootfls length */
+ uint32_t rootfs_crc32; /* rootfs crc32 */
+ uint32_t header_crc32; /* sch2 header crc32, durring calculation this area is replaced by zero */
+ uint16_t header_length; /* sch2 header length: 0x28 */
+ uint16_t cmd_line_length; /* cmd line length, known zeros */
+};
+
+/* globals */
+static struct file_info inspect_info;
+struct file_info kernel_info;
+struct file_info rootfs_info;
+struct file_info image_info;
+
+char *ofname;
+char *progname;
+uint32_t firmware_size;
+uint16_t family_member;
+char *rom_id[12] = { 0 };
+
+char image_type;
+int add_jffs2_eof;
+
+static void usage(int status)
+{
+ fprintf(stderr, "Usage: %s [OPTIONS...]\n", progname);
+ fprintf(stderr,
+ "\n"
+ "Options:\n"
+ " -i <file> inspect given firmware file <file>\n"
+ " -f set family member id (hexval prefixed with 0x)\n"
+ " -F <file> read image and convert it to FACTORY\n"
+ " -k <file> read kernel image from the file <file>\n"
+ " -r <file> read rootfs image from the file <file>\n"
+ " -o <file> write output to the file <file>\n"
+ " -s <size> set firmware partition size\n"
+ " -m <version> set rom id to <version> (12-bit string val: \"DLK*********\")\n"
+ " -h show this screen\n");
+
+ exit(status);
+}
+
+void print_auh_header(struct auh_header *printed_header)
+{
+ printf("\trom_id: %s\n"
+ "\tderange: 0x%04X\n"
+ "\timage_checksum: 0x%04X\n"
+ "\tspace1: 0x%08X\n"
+ "\tspace2: 0x%08X\n"
+ "\tspace3: 0x%04X\n"
+ "\tlpvs: 0x%02X\n"
+ "\tmbz: 0x%02X\n"
+ "\ttime_stamp: 0x%08X\n"
+ "\terase_start: 0x%08X\n"
+ "\terase_length: 0x%08X\n"
+ "\tdata_offset: 0x%08X\n"
+ "\tdata_length: 0x%08X\n"
+ "\tspace4: 0x%08X\n"
+ "\tspace5: 0x%08X\n"
+ "\tspace6: 0x%08X\n"
+ "\tspace7: 0x%08X\n"
+ "\theader_id: 0x%04X\n"
+ "\theader_version: 0x%02X\n"
+ "\tspace8: 0x%04X\n"
+ "\tsection_id: 0x%02X\n"
+ "\timage_info_type: 0x%02X\n"
+ "\timage_info_offset 0x%08X\n"
+ "\tfamily_member: 0x%04X\n"
+ "\theader_checksum: 0x%04X\n",
+ printed_header->rom_id,
+ printed_header->derange,
+ printed_header->image_checksum,
+ printed_header->space1,
+ printed_header->space2,
+ printed_header->space3,
+ printed_header->lpvs,
+ printed_header->mbz,
+ printed_header->time_stamp,
+ printed_header->erase_start,
+ printed_header->erase_length,
+ printed_header->data_offset,
+ printed_header->data_length,
+ printed_header->space4,
+ printed_header->space5,
+ printed_header->space6,
+ printed_header->space7,
+ printed_header->header_id,
+ printed_header->header_version,
+ printed_header->space8,
+ printed_header->section_id,
+ printed_header->image_info_type,
+ printed_header->image_info_offset,
+ printed_header->family_member, printed_header->header_checksum);
+}
+
+void print_stag_header(struct stag_header *printed_header)
+{
+ printf("\tcmark: 0x%02X\n"
+ "\tid: 0x%02X\n"
+ "\tmagic: 0x%04X\n"
+ "\ttime_stamp: 0x%08X\n"
+ "\timage_length: 0x%04X\n"
+ "\timage_checksum: 0x%04X\n"
+ "\ttag_checksum: 0x%04X\n",
+ printed_header->cmark,
+ printed_header->id,
+ printed_header->magic,
+ printed_header->time_stamp,
+ printed_header->image_length,
+ printed_header->image_checksum, printed_header->tag_checksum);
+}
+
+void print_sch2_header(struct sch2_header *printed_header)
+{
+ printf("\tmagic: 0x%04X\n"
+ "\tcp_type: 0x%02X\n"
+ "\tversion: 0x%02X\n"
+ "\tram_addr: 0x%08X\n"
+ "\timage_len: 0x%08X\n"
+ "\timage_crc32: 0x%08X\n"
+ "\tstart_addr: 0x%08X\n"
+ "\trootfs_addr: 0x%08X\n"
+ "\trootfs_len: 0x%08X\n"
+ "\trootfs_crc32: 0x%08X\n"
+ "\theader_crc32: 0x%08X\n"
+ "\theader_length: 0x%04X\n"
+ "\tcmd_line_length: 0x%04X\n",
+ printed_header->magic,
+ printed_header->cp_type,
+ printed_header->version,
+ printed_header->ram_addr,
+ printed_header->image_len,
+ printed_header->image_crc32,
+ printed_header->start_addr,
+ printed_header->rootfs_addr,
+ printed_header->rootfs_len,
+ printed_header->rootfs_crc32,
+ printed_header->header_crc32,
+ printed_header->header_length, printed_header->cmd_line_length);
+}
+
+static int find_auh_headers(char *buf)
+{
+ char *tmp_buf = buf;
+ struct auh_header *tmp_header[MAX_HEADER_COUNTER];
+ int header_counter = 0;
+
+ int ret = EXIT_FAILURE;
+
+ while (tmp_buf - buf <= inspect_info.file_size - AUH_SIZE) {
+ if (!memcmp(tmp_buf, AUH_MAGIC, 3)) {
+ if (((struct auh_header *)tmp_buf)->header_checksum ==
+ (uint16_t) ~jboot_checksum(0, (uint16_t *) tmp_buf,
+ AUH_SIZE - 2)) {
+ uint16_t checksum = 0;
+ printf("Find proper AUH header at: 0x%lX!\n",
+ tmp_buf - buf);
+ tmp_header[header_counter] =
+ (struct auh_header *)tmp_buf;
+ checksum =
+ jboot_checksum(0, (uint16_t *) ((char *)
+ tmp_header
+ [header_counter]
+ + AUH_SIZE),
+ tmp_header
+ [header_counter]->data_length);
+ if (tmp_header[header_counter]->image_checksum
+ == checksum)
+ printf("Image checksum ok.\n");
+ else
+ ERR("Image checksum incorrect! Stored: 0x%X Calculated: 0x%X\n", tmp_header[header_counter]->image_checksum, checksum);
+ header_counter++;
+ if (header_counter > MAX_HEADER_COUNTER)
+ break;
+ }
+ }
+ tmp_buf++;
+ }
+
+ if (header_counter == 0)
+ ERR("Can't find proper AUH header!\n");
+ else if (header_counter > MAX_HEADER_COUNTER)
+ ERR("To many AUH headers!\n");
+ else {
+ for (int i = 0; i < header_counter; i++) {
+ printf("AUH %d:\n", i);
+ print_auh_header(tmp_header[i]);
+ }
+
+ ret = EXIT_SUCCESS;
+ }
+
+ return ret;
+}
+
+static int check_stag_header(char *buf, struct stag_header *header)
+{
+
+ int ret = EXIT_FAILURE;
+
+ uint8_t cmark_tmp = header->cmark;
+ header->cmark = header->id;
+
+ if (header->tag_checksum ==
+ (uint16_t) ~jboot_checksum(0, (uint16_t *) header,
+ STAG_SIZE - 2)) {
+ uint16_t checksum = 0;
+ printf("Find proper STAG header at: 0x%lX!\n",
+ (char *)header - buf);
+ checksum =
+ jboot_checksum(0, (uint16_t *) ((char *)header + STAG_SIZE),
+ header->image_length);
+ if (header->image_checksum == checksum) {
+ printf("Image checksum ok.\n");
+ header->cmark = cmark_tmp;
+ print_stag_header(header);
+ ret = EXIT_SUCCESS;
+ } else
+ ERR("Image checksum incorrect! Stored: 0x%X Calculated: 0x%X\n", header->image_checksum, checksum);
+ } else
+ ERR("STAG header checksum incorrect!");
+
+ header->cmark = cmark_tmp;
+ return ret;
+}
+
+static int check_sch2_header(char *buf, struct sch2_header *header)
+{
+
+ int ret = EXIT_FAILURE;
+
+ uint32_t crc32_tmp = header->header_crc32;
+ header->header_crc32 = 0;
+
+ if (crc32_tmp == crc32(0, (uint8_t *) header, header->header_length)) {
+ uint32_t crc32_val;
+ printf("Find proper SCH2 header at: 0x%lX!\n",
+ (char *)header - buf);
+
+ crc32_val =
+ crc32(0, (uint8_t *) header + header->header_length,
+ header->image_len);
+ if (header->image_crc32 == crc32_val) {
+ printf("Kernel checksum ok.\n");
+
+ header->header_crc32 = crc32_tmp;
+ print_sch2_header(header);
+ ret = EXIT_SUCCESS;
+ } else
+ ERR("Kernel checksum incorrect! Stored: 0x%X Calculated: 0x%X\n", header->image_crc32, crc32_val);
+
+ } else
+ ERR("SCH2 header checksum incorrect!");
+
+ header->header_crc32 = crc32_tmp;
+ return ret;
+}
+
+static int inspect_fw(void)
+{
+ char *buf;
+ struct stag_header *stag_header_kernel;
+ struct sch2_header *sch2_header_kernel;
+ int ret = EXIT_FAILURE;
+
+ buf = malloc(inspect_info.file_size);
+ if (!buf) {
+ ERR("no memory for buffer!\n");
+ goto out;
+ }
+
+ ret = read_to_buf(&inspect_info, buf);
+ if (ret)
+ goto out_free_buf;
+
+ ret = find_auh_headers(buf);
+ if (ret)
+ goto out_free_buf;
+
+ stag_header_kernel = (struct stag_header *)(buf + AUH_SIZE);
+
+ ret = check_stag_header(buf, stag_header_kernel);
+ if (ret)
+ goto out_free_buf;
+
+ sch2_header_kernel = (struct sch2_header *)(buf + AUH_SIZE + STAG_SIZE);
+
+ ret = check_sch2_header(buf, sch2_header_kernel);
+ if (ret)
+ goto out_free_buf;
+
+ out_free_buf:
+ free(buf);
+ out:
+ return ret;
+}
+
+static int check_options(void)
+{
+ int ret;
+
+ if (inspect_info.file_name) {
+ ret = get_file_stat(&inspect_info);
+ if (ret)
+ return ret;
+
+ return 0;
+ }
+
+ return 0;
+}
+
+int fill_sch2(struct sch2_header *header, char *kernel_ptr, char *rootfs_ptr)
+{
+
+ header->magic = SCH2_MAGIC;
+ header->cp_type = LZMA;
+ header->version = SCH2_VER;
+ header->ram_addr = RAM_LOAD_ADDR;
+ header->image_len = kernel_info.file_size;
+ header->image_crc32 = crc32(0, (uint8_t *) kernel_ptr, kernel_info.file_size);
+ header->start_addr = RAM_ENTRY_ADDR;
+ header->rootfs_addr =
+ JBOOT_SIZE + STAG_SIZE + SCH2_SIZE + kernel_info.file_size;
+ header->rootfs_len = rootfs_info.file_size;
+ header->rootfs_crc32 = crc32(0, (uint8_t *) rootfs_ptr, rootfs_info.file_size);
+ header->header_crc32 = 0;
+ header->header_length = SCH2_SIZE;
+ header->cmd_line_length = 0;
+
+ header->header_crc32 = crc32(0, (uint8_t *) header, header->header_length);
+
+ return EXIT_SUCCESS;
+}
+
+int fill_stag(struct stag_header *header, uint32_t length)
+{
+ header->cmark = STAG_ID;
+ header->id = STAG_ID;
+ header->magic = STAG_MAGIC;
+ header->time_stamp = jboot_timestamp();
+ header->image_length = length + SCH2_SIZE;
+ header->image_checksum =
+ jboot_checksum(0, (uint16_t *) ((char *)header + STAG_SIZE),
+ header->image_length);
+ header->tag_checksum =
+ ~jboot_checksum(0, (uint16_t *) header, STAG_SIZE - 2);
+
+ if (image_type == FACTORY)
+ header->cmark = STAG_CMARK_FACTORY;
+
+ return EXIT_SUCCESS;
+};
+
+int fill_auh(struct auh_header *header, uint32_t length)
+{
+ memcpy(header->rom_id, rom_id, 12);
+ header->derange = 0;
+ header->image_checksum =
+ jboot_checksum(0, (uint16_t *) ((char *)header + AUH_SIZE), length);
+ header->space1 = 0;
+ header->space2 = 0;
+ header->space3 = 0;
+ header->lpvs = AUH_LVPS;
+ header->mbz = 0;
+ header->time_stamp = jboot_timestamp();
+ header->erase_start = JBOOT_SIZE;
+ header->erase_length = firmware_size;
+ header->data_offset = JBOOT_SIZE;
+ header->data_length = length;
+ header->space4 = 0;
+ header->space5 = 0;
+ header->space6 = 0;
+ header->space7 = 0;
+ header->header_id = AUH_HDR_ID;
+ header->header_version = AUH_HDR_VER;
+ header->space8 = 0;
+ header->section_id = AUH_SEC_ID;
+ header->image_info_type = AUH_INFO_TYPE;
+ header->image_info_offset = 0;
+ header->family_member = family_member;
+ header->header_checksum =
+ ~jboot_checksum(0, (uint16_t *) header, AUH_SIZE - 2);
+
+ return EXIT_SUCCESS;
+}
+
+int build_fw(void)
+{
+ char *buf;
+ char *kernel_ptr;
+ char *rootfs_ptr;
+ int ret = EXIT_FAILURE;
+ int writelen;
+
+ struct stag_header *stag_header_kernel;
+ struct sch2_header *sch2_header_kernel;
+
+ if (!kernel_info.file_name | !rootfs_info.file_name)
+ goto out;
+
+ ret = get_file_stat(&kernel_info);
+ if (ret)
+ goto out;
+ ret = get_file_stat(&rootfs_info);
+ if (ret)
+ goto out;
+
+ buf = malloc(firmware_size);
+ if (!buf) {
+ ERR("no memory for buffer\n");
+ goto out;
+ }
+
+ if (rootfs_info.file_size + kernel_info.file_size + ALL_HEADERS_SIZE >
+ firmware_size) {
+ ERR("data is bigger than firmware_size!\n");
+ goto out;
+ }
+
+ memset(buf, 0xff, firmware_size);
+
+ stag_header_kernel = (struct stag_header *)buf;
+
+ sch2_header_kernel =
+ (struct sch2_header *)((char *)stag_header_kernel + STAG_SIZE);
+ kernel_ptr = (char *)sch2_header_kernel + SCH2_SIZE;
+
+ ret = read_to_buf(&kernel_info, kernel_ptr);
+ if (ret)
+ goto out_free_buf;
+
+ rootfs_ptr = kernel_ptr + kernel_info.file_size;
+
+ ret = read_to_buf(&rootfs_info, rootfs_ptr);
+ if (ret)
+ goto out_free_buf;
+
+ writelen = rootfs_ptr + rootfs_info.file_size - buf;
+
+ fill_sch2(sch2_header_kernel, kernel_ptr, rootfs_ptr);
+ fill_stag(stag_header_kernel, kernel_info.file_size);
+
+ ret = write_fw(ofname, buf, writelen);
+ if (ret)
+ goto out_free_buf;
+
+ ret = EXIT_SUCCESS;
+
+ out_free_buf:
+ free(buf);
+ out:
+ return ret;
+}
+
+int wrap_fw(void)
+{
+ char *buf;
+ char *image_ptr;
+ int ret = EXIT_FAILURE;
+ int writelen;
+
+ struct auh_header *auh_header_kernel;
+
+ if (!image_info.file_name)
+ goto out;
+
+ ret = get_file_stat(&image_info);
+ if (ret)
+ goto out;
+
+ buf = malloc(firmware_size);
+ if (!buf) {
+ ERR("no memory for buffer\n");
+ goto out;
+ }
+
+ if (image_info.file_size + AUH_SIZE >
+ firmware_size) {
+ ERR("data is bigger than firmware_size!\n");
+ goto out;
+ }
+ if (!family_member) {
+ ERR("No family_member!\n");
+ goto out;
+ }
+ if (!(rom_id[0])) {
+ ERR("No rom_id!\n");
+ goto out;
+ }
+ memset(buf, 0xff, firmware_size);
+
+ image_ptr = (char *)(buf + AUH_SIZE);
+
+ ret = read_to_buf(&image_info, image_ptr);
+ if (ret)
+ goto out_free_buf;
+
+ writelen = image_ptr + image_info.file_size - buf;
+
+ auh_header_kernel = (struct auh_header *)buf;
+ fill_auh(auh_header_kernel, writelen - AUH_SIZE);
+
+ ret = write_fw(ofname, buf, writelen);
+ if (ret)
+ goto out_free_buf;
+
+ ret = EXIT_SUCCESS;
+
+ out_free_buf:
+ free(buf);
+ out:
+ return ret;
+}
+
+int main(int argc, char *argv[])
+{
+ int ret = EXIT_FAILURE;
+
+ progname = basename(argv[0]);
+ image_type = SYSUPGRADE;
+ family_member = 0;
+ firmware_size = 0;
+
+ while (1) {
+ int c;
+
+ c = getopt(argc, argv, "f:F:i:hk:m:o:r:s:");
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'f':
+ sscanf(optarg, "0x%hx", &family_member);
+ break;
+ case 'F':
+ image_info.file_name = optarg;
+ image_type = FACTORY;
+ break;
+ case 'i':
+ inspect_info.file_name = optarg;
+ break;
+ case 'k':
+ kernel_info.file_name = optarg;
+ break;
+ case 'm':
+ if (strlen(optarg) == 12)
+ memcpy(rom_id, optarg, 12);
+ break;
+ case 'r':
+ rootfs_info.file_name = optarg;
+ break;
+ case 'o':
+ ofname = optarg;
+ break;
+ case 's':
+ sscanf(optarg, "0x%x", &firmware_size);
+ break;
+ default:
+ usage(EXIT_FAILURE);
+ break;
+ }
+ }
+
+ ret = check_options();
+ if (ret)
+ goto out;
+
+ if (!inspect_info.file_name) {
+ if (image_type == FACTORY)
+ ret = wrap_fw();
+ else
+ ret = build_fw();
+ }
+ else
+ ret = inspect_fw();
+
+ out:
+ return ret;
+
+}
diff --git a/tools/firmware-utils/src/mkdniimg.c b/tools/firmware-utils/src/mkdniimg.c
index 7230f09d492..852b07dd9f6 100644
--- a/tools/firmware-utils/src/mkdniimg.c
+++ b/tools/firmware-utils/src/mkdniimg.c
@@ -43,7 +43,7 @@ static char *board_id;
#define ERRS(fmt, ...) do { \
int save = errno; \
fflush(0); \
- fprintf(stderr, "[%s] *** error: " fmt "\n", \
+ fprintf(stderr, "[%s] *** error: " fmt ": %s\n", \
progname, ## __VA_ARGS__, strerror(save)); \
} while (0)
diff --git a/tools/firmware-utils/src/mkfwimage.c b/tools/firmware-utils/src/mkfwimage.c
index a527014b551..d8d5239cc55 100644
--- a/tools/firmware-utils/src/mkfwimage.c
+++ b/tools/firmware-utils/src/mkfwimage.c
@@ -61,7 +61,7 @@ fw_layout_t fw_layout_data[] = {
.name = "RSPRO",
.kern_start = 0xbf030000,
.kern_entry = 0x80060000,
- .firmware_max_length= 0x00B00000,
+ .firmware_max_length= 0x00F00000,
},
{
.name = "LS-SR71",
@@ -79,6 +79,12 @@ fw_layout_t fw_layout_data[] = {
.name = "XM",
.kern_start = 0x9f050000,
.kern_entry = 0x80002000,
+ .firmware_max_length= 0x00760000,
+ },
+ {
+ .name = "UBDEV01",
+ .kern_start = 0x9f050000,
+ .kern_entry = 0x80002000,
.firmware_max_length= 0x006A0000,
},
{ .name = "",
@@ -104,8 +110,6 @@ typedef struct part_data {
#define OPTIONS "B:hv:m:o:r:k:"
-static int debug = 0;
-
typedef struct image_info {
char magic[16];
char version[256];
@@ -236,9 +240,9 @@ static int create_image_layout(const char* kernelfile, const char* rootfsfile, c
fw_layout_t* p;
p = &fw_layout_data[0];
- while ((strlen(p->name) != 0) && (strncmp(p->name, board_name, sizeof(board_name)) != 0))
+ while (*p->name && (strcmp(p->name, board_name) != 0))
p++;
- if (p->name == NULL) {
+ if (!*p->name) {
printf("BUG! Unable to find default fw layout!\n");
exit(-1);
}
@@ -247,7 +251,7 @@ static int create_image_layout(const char* kernelfile, const char* rootfsfile, c
strcpy(kernel->partition_name, "kernel");
kernel->partition_index = 1;
kernel->partition_baseaddr = p->kern_start;
- if ( (kernel->partition_length = filelength(kernelfile)) < 0) return (-1);
+ if ( (kernel->partition_length = filelength(kernelfile)) == (u_int32_t)-1) return (-1);
kernel->partition_memaddr = p->kern_entry;
kernel->partition_entryaddr = p->kern_entry;
strncpy(kernel->filename, kernelfile, sizeof(kernel->filename));
@@ -263,8 +267,8 @@ static int create_image_layout(const char* kernelfile, const char* rootfsfile, c
rootfs->partition_entryaddr = 0x00000000;
strncpy(rootfs->filename, rootfsfile, sizeof(rootfs->filename));
-printf("kernel: %d 0x%08x\n", kernel->partition_length, kernel->partition_baseaddr);
-printf("root: %d 0x%08x\n", rootfs->partition_length, rootfs->partition_baseaddr);
+ printf("kernel: %d 0x%08x\n", kernel->partition_length, kernel->partition_baseaddr);
+ printf("root: %d 0x%08x\n", rootfs->partition_length, rootfs->partition_baseaddr);
im->part_count = 2;
return 0;
diff --git a/tools/firmware-utils/src/mkfwimage2.c b/tools/firmware-utils/src/mkfwimage2.c
index ee09abba1ae..89a98051b43 100644
--- a/tools/firmware-utils/src/mkfwimage2.c
+++ b/tools/firmware-utils/src/mkfwimage2.c
@@ -197,6 +197,10 @@ int str2u32(char *arg, u_int32_t *val)
return 0;
}
+#ifndef STRINGIFY
+#define STRINGIFY2(X) #X
+#define STRINGIFY(X) STRINGIFY2(X)
+#endif
static int image_layout_add_partition(const char *part_desc)
{
part_data_t *d;
@@ -212,7 +216,7 @@ static int image_layout_add_partition(const char *part_desc)
}
d = &im.parts[im.part_count];
- t = sscanf(part_desc, "%15[a-zA-Z]:%15[0-9a-fA-Fx]:%15[0-9a-fA-Fx]:%15[0-9a-fA-Fx]:%15[0-9a-fA-Fx]:%256s",
+ t = sscanf(part_desc, "%15[-0-9a-zA-Z]:%15[0-9a-fA-Fx]:%15[0-9a-fA-Fx]:%15[0-9a-fA-Fx]:%15[0-9a-fA-Fx]:%"STRINGIFY(PATH_MAX)"s",
d->partition_name,
offset,
length,
diff --git a/tools/firmware-utils/src/mkheader_gemtek.c b/tools/firmware-utils/src/mkheader_gemtek.c
new file mode 100644
index 00000000000..9e618efbadd
--- /dev/null
+++ b/tools/firmware-utils/src/mkheader_gemtek.c
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2014 Claudio Leite <leitec@staticky.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * Builds a proper flash image for routers using some Gemtek
+ * OEM boards. These include the Airlink101 AR725W, the
+ * Asante SmartHub 600 (AWRT-600N), and Linksys WRT100/110.
+ *
+ * The resulting image is compatible with the factory firmware
+ * web upgrade and TFTP interface.
+ *
+ * To build:
+ * gcc -O2 -o mkheader_gemtek mkheader_gemtek.c -lz
+ *
+ * Claudio Leite <leitec@staticky.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <zlib.h> /* for crc32() */
+
+/*
+ * The header is in little-endian format. In case
+ * we are on a BE host, we need to swap binary
+ * values.
+ */
+#ifdef __APPLE__
+# include <libkern/OSByteOrder.h>
+# define le32 OSSwapHostToLittleInt32
+#else
+# if defined(__linux__)
+# include <endian.h>
+# if __BYTE_ORDER == __BIG_ENDIAN
+# define CPU_BIG_ENDIAN
+# endif
+# else
+# include <sys/endian.h> /* BSD's should have this */
+# if _BYTE_ORDER == _BIG_ENDIAN
+# define CPU_BIG_ENDIAN
+# endif
+# endif
+# ifdef CPU_BIG_ENDIAN
+# define le32(x) (((x & 0xff000000) >> 24) | \
+ ((x & 0x00ff0000) >> 8) | \
+ ((x & 0x0000ff00) << 8) | \
+ ((x & 0x000000ff) << 24))
+# else
+# define le32(x) (x)
+# endif
+#endif
+
+struct gemtek_header {
+ uint8_t magic[4];
+ uint8_t version[4];
+ uint32_t product_id;
+ uint32_t imagesz;
+ uint32_t checksum;
+ uint32_t fast_checksum;
+ uint8_t build[4];
+ uint8_t lang[4];
+};
+
+#define HDRLEN sizeof(struct gemtek_header)
+
+struct machines {
+ char *desc;
+ char *id;
+ uint32_t maxsize;
+ struct gemtek_header header;
+};
+
+struct machines mach_def[] = {
+ {"Airlink101 AR725W", "ar725w", 0x340000,
+ {"GMTK", "1003", le32(0x03000001), 0, 0,
+ 0, "01\0\0", "EN\0\0"}},
+ {"Asante AWRT-600N", "awrt600n", 0x340000,
+ {"A600", "1005", le32(0x03000001), 0, 0,
+ 0, "01\0\0", "EN\0\0"}},
+ {"Linksys WRT100", "wrt100", 0x320000,
+ {"GMTK", "1007", le32(0x03040001), 0, 0,
+ 0, "2\0\0\0", "EN\0\0"}},
+ {"Linksys WRT110", "wrt110", 0x320000,
+ {"GMTK", "1007", le32(0x03040001), 0, 0,
+ 0, "2\0\0\0", "EN\0\0"}},
+ {0}
+};
+
+int
+main(int argc, char *argv[])
+{
+ unsigned long res, flen;
+ struct gemtek_header my_hdr;
+ FILE *f, *f_out;
+ int image_type = -1, index;
+ uint8_t *buf;
+ uint32_t crc;
+
+ if (argc < 3) {
+ fprintf(stderr, "mkheader_gemtek <uImage> <webflash image> [machine ID]\n");
+ fprintf(stderr, " where [machine ID] is one of:\n");
+ for (index = 0; mach_def[index].desc != 0; index++) {
+ fprintf(stderr, " %-10s %s", mach_def[index].id, mach_def[index].desc);
+ if (index == 0)
+ fprintf(stderr, " (default)\n");
+ else
+ fprintf(stderr, "\n");
+ }
+
+ exit(-1);
+ }
+
+ if (argc == 4) {
+ for(index = 0; mach_def[index].id != 0; index++) {
+ if(strcmp(mach_def[index].id, argv[3]) == 0) {
+ image_type = index;
+ break;
+ }
+ }
+
+ if(image_type == -1) {
+ fprintf(stderr, "\nERROR: invalid machine type\n");
+ exit(-1);
+ }
+ } else
+ image_type = 0;
+
+ printf("Opening %s...\n", argv[1]);
+
+ f = fopen(argv[1], "r");
+ if(!f) {
+ fprintf(stderr, "\nERROR: couldn't open input image\n");
+ exit(-1);
+ }
+
+ fseek(f, 0, SEEK_END);
+ flen = (unsigned long) ftell(f);
+
+ printf(" %lu (0x%lX) bytes long\n", flen, flen);
+
+ if (flen > mach_def[image_type].maxsize) {
+ fprintf(stderr, "\nERROR: image exceeds maximum compatible size\n");
+ goto f_error;
+ }
+
+ buf = malloc(flen + HDRLEN);
+ if (!buf) {
+ fprintf(stderr, "\nERROR: couldn't allocate buffer\n");
+ goto f_error;
+ }
+ rewind(f);
+ res = fread(buf + HDRLEN, 1, flen, f);
+ if (res != flen) {
+ perror("Couldn't read entire file: fread()");
+ goto f_error;
+ }
+ fclose(f);
+
+ printf("\nCreating %s...\n", argv[2]);
+
+ memcpy(&my_hdr, &mach_def[image_type].header, HDRLEN);
+
+ printf(" Using %s magic\n", mach_def[image_type].desc);
+
+ my_hdr.imagesz = le32(flen + HDRLEN);
+ memcpy(my_hdr.lang, "EN", 2);
+
+ memcpy(buf, &my_hdr, HDRLEN);
+
+ crc = crc32(0, buf, flen + HDRLEN);
+ printf(" CRC32: %08X\n", crc);
+
+ my_hdr.checksum = le32(crc);
+ memcpy(buf, &my_hdr, HDRLEN);
+
+ printf(" Writing...\n");
+
+ f_out = fopen(argv[2], "w");
+ if(!f_out) {
+ fprintf(stderr, "\nERROR: couldn't open output image\n");
+ exit(-1);
+ }
+
+ fwrite(buf, 1, flen + HDRLEN, f_out);
+
+ fclose(f_out);
+
+ free(buf);
+ return 0;
+
+f_error:
+ fclose(f);
+ exit(-1);
+}
diff --git a/tools/firmware-utils/src/mkhilinkfw.c b/tools/firmware-utils/src/mkhilinkfw.c
new file mode 100644
index 00000000000..55908e5caa7
--- /dev/null
+++ b/tools/firmware-utils/src/mkhilinkfw.c
@@ -0,0 +1,323 @@
+/*
+ * Copyright (C) 2013 Jeff Kent <jeff@jkent.net>
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * This tool encrypts and decrypts uImage formatted firmware for Hilink
+ * HLK-RM04 wireless modules. It will also truncate a dump of mtd6 and make
+ * it an image suitable for flashing via the stock firmware upgrade page.
+ *
+ * Build instructions:
+ * gcc -lcrypto hlkcrypt.c -o hlkcrypt
+ */
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <openssl/des.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#define DES_KEY "H@L9K*(3"
+
+#ifndef min
+#define min(a,b) \
+ ({ __typeof__ (a) _a = (a); \
+ __typeof__ (b) _b = (b); \
+ _a < _b ? _a : _b; })
+#endif
+
+#define IH_MAGIC 0x27051956
+#define IH_NMLEN 32
+typedef struct image_header {
+ uint32_t ih_magic; /* Image Header Magic Number */
+ uint32_t ih_hcrc; /* Image Header CRC Checksum */
+ uint32_t ih_time; /* Image Creation Timestamp */
+ uint32_t ih_size; /* Image Data Size */
+ uint32_t ih_load; /* Data Load Address */
+ uint32_t ih_ep; /* Entry Point Address */
+ uint32_t ih_dcrc; /* Image Data CRC Checksum */
+ uint8_t ih_os; /* Operating System */
+ uint8_t ih_arch; /* CPU architecture */
+ uint8_t ih_type; /* Image Type */
+ uint8_t ih_comp; /* Compression Type */
+ uint8_t ih_name[IH_NMLEN]; /* Image Name */
+} image_header_t;
+
+static int temp_fd = -1;
+static DES_key_schedule schedule;
+
+static void show_usage(const char *arg0);
+static void exit_cleanup(void);
+static void copy_file(int src, int dst);
+static void do_encrypt(void *p, off_t len);
+static void do_decrypt(void *p, off_t len);
+
+
+int main(int argc, char **argv)
+{
+ int encrypt_opt = 0;
+ int decrypt_opt = 0;
+ int input_opt = 0;
+ int output_opt = 0;
+ char *input_filename = NULL;
+ char *output_filename = NULL;
+
+ int input_fd;
+ int output_fd;
+ off_t file_len;
+ char *p;
+ char buf[sizeof(image_header_t) + 3];
+ image_header_t *header;
+
+ while (1) {
+ static struct option long_options[] = {
+ {"encrypt", no_argument, 0, 'e'},
+ {"decrypt", no_argument, 0, 'd'},
+ {"input", required_argument, 0, 'i'},
+ {"output", required_argument, 0, 'o'},
+ {0, 0, 0, 0 }
+ };
+ int option_index = 0;
+ int c = getopt_long(argc, argv, "dei:o:",
+ long_options, &option_index);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'd':
+ decrypt_opt++;
+ if (decrypt_opt > 1) {
+ fprintf(stderr, "%s: decrypt may only be specified once\n",
+ argv[0]);
+ show_usage(argv[0]);
+ }
+ break;
+
+ case 'e':
+ encrypt_opt++;
+ if (encrypt_opt > 1) {
+ fprintf(stderr, "%s: encrypt may only be specified once\n",
+ argv[0]);
+ show_usage(argv[0]);
+ }
+ break;
+
+ case 'i':
+ input_opt++;
+ if (input_opt > 1) {
+ fprintf(stderr, "%s: only one input file may be specified\n",
+ argv[0]);
+ show_usage(argv[0]);
+ }
+ if (strcmp("-", optarg) != 0) {
+ input_filename = optarg;
+ }
+ break;
+
+ case 'o':
+ output_opt++;
+ if (output_opt > 1) {
+ fprintf(stderr, "%s: only one output file may be specified\n",
+ argv[0]);
+ show_usage(argv[0]);
+ }
+ if (strcmp("-", optarg) != 0) {
+ output_filename = optarg;
+ }
+ break;
+
+ case '?':
+ exit(-1);
+
+ default:
+ abort();
+ }
+ }
+
+ if (decrypt_opt && encrypt_opt) {
+ fprintf(stderr, "%s: decrypt and encrypt may not be used together\n",
+ argv[0]);
+ show_usage(argv[0]);
+ }
+
+ if (!decrypt_opt && !encrypt_opt) {
+ fprintf(stderr, "%s: neither decrypt or encrypt were specified\n",
+ argv[0]);
+ show_usage(argv[0]);
+ }
+
+ temp_fd = fileno(tmpfile());
+ if (temp_fd < 0) {
+ fprintf(stderr, "Can't create temporary file\n");
+ exit(EXIT_FAILURE);
+ }
+
+ atexit(exit_cleanup);
+ DES_set_key_unchecked((const_DES_cblock *)DES_KEY, &schedule);
+
+ if (input_filename) {
+ input_fd = open(input_filename, O_RDONLY);
+ if (input_fd < 0) {
+ fprintf(stderr, "Can't open %s for reading: %s\n", input_filename,
+ strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ copy_file(input_fd, temp_fd);
+ close(input_fd);
+ }
+ else {
+ copy_file(STDIN_FILENO, temp_fd);
+ }
+
+ file_len = lseek(temp_fd, 0, SEEK_CUR);
+ if (file_len < 64) {
+ fprintf(stderr, "Not enough data\n");
+ exit(EXIT_FAILURE);
+ }
+
+ p = mmap(0, file_len, PROT_READ|PROT_WRITE, MAP_SHARED, temp_fd, 0);
+ if (p == MAP_FAILED) {
+ fprintf(stderr, "mmap failed: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ if (encrypt_opt) {
+ header = (image_header_t *)p;
+ off_t len = min(file_len,
+ ntohl(header->ih_size) + sizeof(image_header_t));
+ if (ntohl(header->ih_magic) != IH_MAGIC) {
+ fprintf(stderr, "Header magic incorrect: "
+ "expected 0x%08X, got 0x%08X\n",
+ IH_MAGIC, ntohl(header->ih_magic));
+ munmap(p, file_len);
+ exit(EXIT_FAILURE);
+ }
+ do_encrypt(p, len);
+ munmap(p, file_len);
+ if (len != file_len) {
+ if (ftruncate(temp_fd, len) < 0) {
+ fprintf(stderr, "ftruncate failed: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ }
+ }
+
+ if (decrypt_opt) {
+ off_t header_len = min(file_len, sizeof(image_header_t) + 3);
+ memcpy(buf, p, header_len);
+ do_decrypt(buf, header_len);
+ header = (image_header_t *)buf;
+ if (ntohl(header->ih_magic) != IH_MAGIC) {
+ fprintf(stderr, "Header magic incorrect: "
+ "expected 0x%08X, got 0x%08X\n",
+ IH_MAGIC, ntohl(header->ih_magic));
+ exit(EXIT_FAILURE);
+ }
+ do_decrypt(p, file_len);
+ munmap(p, file_len);
+ }
+
+ lseek(temp_fd, 0, SEEK_SET);
+ if (output_filename) {
+ output_fd = creat(output_filename, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+ if (output_fd < 0) {
+ fprintf(stderr, "Can't open %s for writing: %s\n",
+ output_filename, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ copy_file(temp_fd, output_fd);
+ close(output_fd);
+ }
+ else {
+ copy_file(temp_fd, STDOUT_FILENO);
+ }
+
+ exit(EXIT_SUCCESS);
+ return 0;
+}
+
+static void show_usage(const char *arg0)
+{
+ fprintf(stderr, "usage: %s -d|-e [-i FILE] [-o FILE]\n\n", arg0);
+ fprintf(stderr, "%-15s %s\n", "-d, --decrypt", "decrypt data");
+ fprintf(stderr, "%-15s %s\n", "-e, --encrypt", "encrypt data");
+ fprintf(stderr, "%-15s %s\n", "-i, --input", "intput file (defaults to stdin)");
+ fprintf(stderr, "%-15s %s\n", "-o, --output", "output file (defaults to stdout)");
+ exit(-1);
+}
+
+static void exit_cleanup(void)
+{
+ if (temp_fd >= 0) {
+ close(temp_fd);
+ }
+}
+
+static void copy_file(int src, int dst)
+{
+ char buf[4096];
+ ssize_t size;
+
+ while ((size = read(src, buf, 4096)) > 0) {
+ write(dst, buf, size);
+ }
+}
+
+static void do_encrypt(void *p, off_t len)
+{
+ DES_cblock *pblock;
+ int num_blocks;
+
+ num_blocks = len / 8;
+ pblock = (DES_cblock *) p;
+ while (num_blocks--) {
+ DES_ecb_encrypt(pblock, pblock, &schedule, DES_ENCRYPT);
+ pblock++;
+ }
+
+ num_blocks = (len - 3) / 8;
+ pblock = (DES_cblock *) (p + 3);
+ while (num_blocks--) {
+ DES_ecb_encrypt(pblock, pblock, &schedule, DES_ENCRYPT);
+ pblock++;
+ }
+}
+
+static void do_decrypt(void *p, off_t len)
+{
+ DES_cblock *pblock;
+ int num_blocks;
+
+ num_blocks = (len - 3) / 8;
+ pblock = (DES_cblock *) (p + 3);
+ while (num_blocks--) {
+ DES_ecb_encrypt(pblock, pblock, &schedule, DES_DECRYPT);
+ pblock++;
+ }
+
+ num_blocks = len / 8;
+ pblock = (DES_cblock *) p;
+ while (num_blocks--) {
+ DES_ecb_encrypt(pblock, pblock, &schedule, DES_DECRYPT);
+ pblock++;
+ }
+}
diff --git a/tools/firmware-utils/src/mkmerakifw-old.c b/tools/firmware-utils/src/mkmerakifw-old.c
new file mode 100644
index 00000000000..05317c2a5b4
--- /dev/null
+++ b/tools/firmware-utils/src/mkmerakifw-old.c
@@ -0,0 +1,369 @@
+/*
+ * Copyright (C) 2015 Thomas Hebb <tommyhebb@gmail.com>
+ * Copyright (C) 2016 Christian Lamparter <chunkeey@googlemail.com>
+ *
+ * The format of the header this tool generates was first documented by
+ * Chris Blake <chrisrblake93 (at) gmail.com> in a shell script of the
+ * same purpose. I have created this reimplementation at his request. The
+ * original script can be found at:
+ * <https://github.com/riptidewave93/meraki-partbuilder>
+ *
+ * Support for the old header format, which is used by the Cisco Z1 AP
+ * has been reverse engineered from the nandloader's nand_load_bk function.
+ * The original code is part of Cisco's GPL code and can be found at:
+ * <https://github.com/riptidewave93/meraki-linux>
+ *
+ * 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 <stdbool.h>
+#include <string.h>
+#include <libgen.h>
+#include <endian.h>
+#include <getopt.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+#define PADDING_BYTE 0xff
+
+#define HDR_LENGTH 0x00000020
+#define HDR_OFF_MAGIC1 0
+#define HDR_OFF_LOAD_ADDR 4
+#define HDR_OFF_IMAGELEN 8
+#define HDR_OFF_ENTRY 12
+#define HDR_OFF_CHECKSUM 16
+#define HDR_OFF_FILLER0 20
+#define HDR_OFF_FILLER1 24
+#define HDR_OFF_FILLER2 28
+
+struct board_info {
+ char *id;
+ char *description;
+ uint32_t magic;
+ uint32_t imagelen;
+ uint32_t load_addr;
+ uint32_t entry;
+};
+
+/*
+ * Globals
+ */
+static char *progname;
+static bool strip_padding;
+
+static char *board_id;
+static const struct board_info *board;
+
+static const struct board_info boards[] = {
+ {
+ .id = "z1",
+ .description = "Meraki Z1 Access Point",
+ .magic = 0x4d495053,
+ .imagelen = 0x007e0000,
+ .load_addr = 0x80060000,
+ .entry = 0x80060000
+ }, {
+ /* terminating entry */
+ }
+};
+
+/*
+ * 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)
+
+static const struct board_info *find_board(const char *id)
+{
+ const struct board_info *ret;
+ const struct board_info *board;
+
+ ret = NULL;
+ for (board = boards; board->id != NULL; board++) {
+ if (strcasecmp(id, board->id) == 0) {
+ ret = board;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static void usage(int status)
+{
+ FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+ const 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"
+" -i <file> read kernel image from the file <file>\n"
+" -o <file> write output to the file <file>\n"
+" -s strip padding from the end of the image\n"
+" -h show this screen\n"
+ );
+
+ fprintf(stream, "\nBoards:\n");
+ for (board = boards; board->id != NULL; board++)
+ fprintf(stream, " %-16s%s\n", board->id, board->description);
+
+ exit(status);
+}
+
+static void writel(unsigned char *buf, size_t offset, uint32_t value)
+{
+ value = htonl(value);
+ memcpy(buf + offset, &value, sizeof(uint32_t));
+}
+
+static const uint32_t crc32_table[] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
+ 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+ 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+ 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
+ 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+ 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
+ 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
+ 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+ 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+ 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
+ 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
+ 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+ 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
+ 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+ 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+ 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
+ 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
+ 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+ 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+ 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
+ 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+ 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
+ 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
+ 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+ 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+ 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
+ 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
+ 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+ 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
+ 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+ 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+ 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
+ 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
+ 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+ 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
+};
+
+static inline uint32_t crc32_accumulate_8(const uint32_t crc, const uint8_t ch)
+{
+ return crc32_table[(crc ^ ch) & 0xff] ^ (crc >> 8);
+}
+
+static void crc32_csum(uint8_t *buf, const size_t len)
+{
+ uint32_t crc;
+ size_t i;
+
+ crc = ~0;
+ for (i = 0; i < len; i += 4) {
+ crc = crc32_accumulate_8(crc, buf[i + 3]);
+ crc = crc32_accumulate_8(crc, buf[i + 2]);
+ crc = crc32_accumulate_8(crc, buf[i + 1]);
+ crc = crc32_accumulate_8(crc, buf[i]);
+ }
+ crc = ~crc;
+
+ writel(buf, HDR_OFF_CHECKSUM, crc);
+}
+
+
+static int meraki_build_hdr(const struct board_info *board, const size_t klen,
+ FILE *out, FILE *in)
+{
+ unsigned char *kernel;
+ unsigned char *buf;
+ size_t buflen;
+ size_t kspace;
+
+ size_t rc;
+ buflen = board->imagelen;
+ kspace = buflen - HDR_LENGTH;
+
+ if (klen > kspace) {
+ ERR("kernel file is too big - max size: 0x%08lX\n", kspace);
+ return EXIT_FAILURE;
+ }
+
+ /* If requested, resize buffer to remove padding */
+ if (strip_padding)
+ buflen = klen + HDR_LENGTH;
+
+ /* Allocate and initialize buffer for final image */
+ buf = malloc(buflen);
+ if (buf == NULL) {
+ ERRS("no memory for buffer: %s\n");
+ return EXIT_FAILURE;
+ }
+ memset(buf, PADDING_BYTE, buflen);
+
+ /* Load kernel */
+ kernel = buf + HDR_LENGTH;
+ fread(kernel, klen, 1, in);
+
+ /* Write magic values and filler */
+ writel(buf, HDR_OFF_MAGIC1, board->magic);
+ writel(buf, HDR_OFF_FILLER0, 0);
+ writel(buf, HDR_OFF_FILLER1, 0);
+ writel(buf, HDR_OFF_FILLER2, 0);
+
+ /* Write load and kernel entry point address */
+ writel(buf, HDR_OFF_LOAD_ADDR, board->load_addr);
+ writel(buf, HDR_OFF_ENTRY, board->entry);
+
+ /* Write header and image length */
+ writel(buf, HDR_OFF_IMAGELEN, klen);
+
+ /* this gets replaced later, after the checksum has been calculated */
+ writel(buf, HDR_OFF_CHECKSUM, 0);
+
+ /* Write checksum */
+ crc32_csum(buf, klen + HDR_LENGTH);
+
+ rc = fwrite(buf, buflen, 1, out);
+
+ free(buf);
+
+ return rc == 1 ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+int main(int argc, char *argv[])
+{
+ int ret = EXIT_FAILURE;
+ char *ofname = NULL, *ifname = NULL;
+ FILE *out, *in;
+ size_t klen;
+
+ progname = basename(argv[0]);
+
+ while (1) {
+ int c;
+
+ c = getopt(argc, argv, "B:i:o:sh");
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'B':
+ board_id = optarg;
+ break;
+ case 'i':
+ ifname = optarg;
+ break;
+ case 'o':
+ ofname = optarg;
+ break;
+ case 's':
+ strip_padding = true;
+ break;
+ case 'h':
+ usage(EXIT_SUCCESS);
+ break;
+ default:
+ usage(EXIT_FAILURE);
+ break;
+ }
+ }
+
+ if (board_id == NULL) {
+ ERR("no board specified");
+ goto err;
+ }
+
+ board = find_board(board_id);
+ if (board == NULL) {
+ ERR("unknown board \"%s\"", board_id);
+ goto err;
+ }
+
+ if (ifname == NULL) {
+ ERR("no input file specified");
+ goto err;
+ }
+
+ if (ofname == NULL) {
+ ERR("no output file specified");
+ goto err;
+ }
+
+ in = fopen(ifname, "r");
+ if (in == NULL) {
+ ERRS("could not open \"%s\" for reading: %s", ifname);
+ goto err;
+ }
+
+ /* Get kernel length */
+ fseek(in, 0, SEEK_END);
+ klen = ftell(in);
+ rewind(in);
+
+ out = fopen(ofname, "w");
+ if (out == NULL) {
+ ERRS("could not open \"%s\" for writing: %s", ofname);
+ goto err_close_in;
+ }
+
+ ret = meraki_build_hdr(board, klen, out, in);
+ fclose(out);
+
+err_close_in:
+ fclose(in);
+
+err:
+ return ret;
+}
diff --git a/tools/firmware-utils/src/mkmerakifw.c b/tools/firmware-utils/src/mkmerakifw.c
new file mode 100644
index 00000000000..1a50f1658f7
--- /dev/null
+++ b/tools/firmware-utils/src/mkmerakifw.c
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2015 Thomas Hebb <tommyhebb@gmail.com>
+ *
+ * The format of the header this tool generates was first documented by
+ * Chris Blake <chrisrblake93 (at) gmail.com> in a shell script of the
+ * same purpose. I have created this reimplementation at his request. The
+ * original script can be found at:
+ * <https://github.com/riptidewave93/meraki-partbuilder>
+ *
+ * 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 <stdbool.h>
+#include <string.h>
+#include <libgen.h>
+#include <getopt.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+#include "sha1.h"
+
+#define PADDING_BYTE 0xff
+
+#define HDR_LENGTH 0x00000400
+#define HDR_OFF_MAGIC1 0
+#define HDR_OFF_HDRLEN 4
+#define HDR_OFF_IMAGELEN 8
+#define HDR_OFF_CHECKSUM 12
+#define HDR_OFF_MAGIC2 32
+#define HDR_OFF_MAGIC3 36
+#define HDR_OFF_STATICHASH 40
+#define HDR_OFF_KERNEL_OFFSET 40
+#define HDR_OFF_RAMDISK_OFFSET 44
+#define HDR_OFF_FDT_OFFSET 48
+#define HDR_OFF_UNKNOWN_OFFSET 52
+
+struct board_info {
+ uint32_t magic1;
+ uint32_t magic2;
+ uint32_t magic3;
+ uint32_t imagelen;
+ union {
+ unsigned char statichash[20];
+ struct {
+ uint32_t kernel_offset;
+ uint32_t ramdisk_offset;
+ uint32_t fdt_offset;
+ uint32_t unknown_offset;
+ } mx60;
+ } u;
+ char *id;
+ char *description;
+};
+
+/*
+ * Globals
+ */
+static char *progname;
+
+static char *board_id;
+static const struct board_info *board;
+
+static const struct board_info boards[] = {
+ {
+ .id = "mr18",
+ .description = "Meraki MR18 Access Point",
+ .magic1 = 0x8e73ed8a,
+ .magic2 = 0x8e73ed8a,
+ .imagelen = 0x00800000,
+ .u.statichash = {0xda, 0x39, 0xa3, 0xee, 0x5e,
+ 0x6b, 0x4b, 0x0d, 0x32, 0x55,
+ 0xbf, 0xef, 0x95, 0x60, 0x18,
+ 0x90, 0xaf, 0xd8, 0x07, 0x09},
+ }, {
+ .id = "mr24",
+ .description = "Meraki MR24 Access Point",
+ .magic1 = 0x8e73ed8a,
+ .magic2 = 0x8e73ed8a,
+ .imagelen = 0x00800000,
+ .u.statichash = {0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff},
+ }, {
+ .id = "mx60",
+ .description = "Meraki MX60/MX60W Security Appliance",
+ .magic1 = 0x8e73ed8a,
+ .magic2 = 0xa1f0beef, /* Enables use of load addr in statichash */
+ .magic3 = 0x00060001, /* This goes along with magic2 */
+ .imagelen = 0x3fd00000,
+ /* The static hash below does the following:
+ * 1st Row: Kernel Offset
+ * 2nd Row: Ramdisk Offset
+ * 3rd Row: FDT Offset
+ * 4th Row: ? Unused/Unknown ?
+ * 5th Row: ? Unused/Unknown ?
+ */
+ .u.mx60 = {
+ .kernel_offset = 0x10000,
+ .ramdisk_offset = 0x3FFC00,
+ .fdt_offset = 0x0400,
+ .unknown_offset = 0x0400,
+ },
+ }, {
+ /* terminating entry */
+ }
+};
+
+/*
+ * 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)
+
+static const struct board_info *find_board(const char *id)
+{
+ const struct board_info *ret;
+ const struct board_info *board;
+
+ ret = NULL;
+ for (board = boards; board->id != NULL; board++) {
+ if (strcasecmp(id, board->id) == 0) {
+ ret = board;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static void usage(int status)
+{
+ FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+ const 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"
+" -i <file> read kernel image from the file <file>\n"
+" -o <file> write output to the file <file>\n"
+" -s strip padding from the end of the image\n"
+" -h show this screen\n"
+ );
+
+ fprintf(stream, "\nBoards:\n");
+ for (board = boards; board->id != NULL; board++)
+ fprintf(stream, " %-16s%s\n", board->id, board->description);
+
+ exit(status);
+}
+
+void writel(unsigned char *buf, size_t offset, uint32_t value)
+{
+ value = htonl(value);
+ memcpy(buf + offset, &value, sizeof(uint32_t));
+}
+
+int main(int argc, char *argv[])
+{
+ int ret = EXIT_FAILURE;
+ long klen;
+ size_t kspace;
+ unsigned char *kernel;
+ size_t buflen;
+ unsigned char *buf;
+ bool strip_padding = false;
+ char *ofname = NULL, *ifname = NULL;
+ FILE *out, *in;
+
+ progname = basename(argv[0]);
+
+ while (1) {
+ int c;
+
+ c = getopt(argc, argv, "B:i:o:sh");
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'B':
+ board_id = optarg;
+ break;
+ case 'i':
+ ifname = optarg;
+ break;
+ case 'o':
+ ofname = optarg;
+ break;
+ case 's':
+ strip_padding = true;
+ break;
+ case 'h':
+ usage(EXIT_SUCCESS);
+ break;
+ default:
+ usage(EXIT_FAILURE);
+ break;
+ }
+ }
+
+ if (board_id == NULL) {
+ ERR("no board specified");
+ goto err;
+ }
+
+ board = find_board(board_id);
+ if (board == NULL) {
+ ERR("unknown board \"%s\"", board_id);
+ goto err;
+ }
+
+ if (ifname == NULL) {
+ ERR("no input file specified");
+ goto err;
+ }
+
+ if (ofname == NULL) {
+ ERR("no output file specified");
+ goto err;
+ }
+
+ in = fopen(ifname, "r");
+ if (in == NULL) {
+ ERRS("could not open \"%s\" for reading: %s", ifname);
+ goto err;
+ }
+
+ buflen = board->imagelen;
+ kspace = buflen - HDR_LENGTH;
+
+ /* Get kernel length */
+ fseek(in, 0, SEEK_END);
+ klen = ftell(in);
+ rewind(in);
+
+ if (klen > kspace) {
+ ERR("file \"%s\" is too big - max size: 0x%08lX\n",
+ ifname, kspace);
+ goto err_close_in;
+ }
+
+ /* If requested, resize buffer to remove padding */
+ if (strip_padding)
+ buflen = klen + HDR_LENGTH;
+
+ /* Allocate and initialize buffer for final image */
+ buf = malloc(buflen);
+ if (buf == NULL) {
+ ERRS("no memory for buffer: %s\n");
+ goto err_close_in;
+ }
+ memset(buf, PADDING_BYTE, buflen);
+
+ /* Load kernel */
+ kernel = buf + HDR_LENGTH;
+ fread(kernel, klen, 1, in);
+
+ /* Write magic values */
+ writel(buf, HDR_OFF_MAGIC1, board->magic1);
+ writel(buf, HDR_OFF_MAGIC2, board->magic2);
+ writel(buf, HDR_OFF_MAGIC3, board->magic3);
+
+ /* Write header and image length */
+ writel(buf, HDR_OFF_HDRLEN, HDR_LENGTH);
+ writel(buf, HDR_OFF_IMAGELEN, klen);
+
+ /* Write checksum and static hash */
+ sha1_csum(kernel, klen, buf + HDR_OFF_CHECKSUM);
+
+ switch (board->magic2) {
+ case 0xa1f0beef:
+ writel(buf, HDR_OFF_KERNEL_OFFSET, board->u.mx60.kernel_offset);
+ writel(buf, HDR_OFF_RAMDISK_OFFSET, board->u.mx60.ramdisk_offset);
+ writel(buf, HDR_OFF_FDT_OFFSET, board->u.mx60.fdt_offset),
+ writel(buf, HDR_OFF_UNKNOWN_OFFSET, board->u.mx60.unknown_offset);
+ break;
+
+ case 0x8e73ed8a:
+ memcpy(buf + HDR_OFF_STATICHASH, board->u.statichash, 20);
+ break;
+ }
+
+ /* Save finished image */
+ out = fopen(ofname, "w");
+ if (out == NULL) {
+ ERRS("could not open \"%s\" for writing: %s", ofname);
+ goto err_free;
+ }
+ fwrite(buf, buflen, 1, out);
+
+ ret = EXIT_SUCCESS;
+
+ fclose(out);
+
+err_free:
+ free(buf);
+
+err_close_in:
+ fclose(in);
+
+err:
+ return ret;
+}
diff --git a/tools/firmware-utils/src/mkplanexfw.c b/tools/firmware-utils/src/mkplanexfw.c
index 1bdccb7c026..0b71f80438f 100644
--- a/tools/firmware-utils/src/mkplanexfw.c
+++ b/tools/firmware-utils/src/mkplanexfw.c
@@ -82,7 +82,7 @@ static struct board_info boards[] = {
#define ERRS(fmt, ...) do { \
int save = errno; \
fflush(0); \
- fprintf(stderr, "[%s] *** error: " fmt "\n", \
+ fprintf(stderr, "[%s] *** error: " fmt ": %s\n", \
progname, ## __VA_ARGS__, strerror(save)); \
} while (0)
diff --git a/tools/firmware-utils/src/mkporayfw.c b/tools/firmware-utils/src/mkporayfw.c
new file mode 100644
index 00000000000..6ec4f320d93
--- /dev/null
+++ b/tools/firmware-utils/src/mkporayfw.c
@@ -0,0 +1,791 @@
+/*
+ * Builder/viewer/extractor utility for Poray firmware image files
+ *
+ * Copyright (C) 2013 Michel Stempin <michel.stempin@wanadoo.fr>
+ * Copyright (C) 2013 Felix Kaechele <felix@fetzig.org>
+ * Copyright (C) 2013 <admin@openschemes.com>
+ *
+ * This tool is based on:
+ * TP-Link firmware upgrade tool.
+ * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * Itself based on:
+ * TP-Link WR941 V2 firmware checksum fixing tool.
+ * Copyright (C) 2008,2009 Wang Jian <lark@linux.net.cn>
+ *
+ * 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>
+#include <libgen.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#if (__BYTE_ORDER == __BIG_ENDIAN)
+# define HOST_TO_BE32(x) (x)
+# define BE32_TO_HOST(x) (x)
+# define HOST_TO_LE32(x) bswap_32(x)
+# define LE32_TO_HOST(x) bswap_32(x)
+#else
+# define HOST_TO_BE32(x) bswap_32(x)
+# define BE32_TO_HOST(x) bswap_32(x)
+# define HOST_TO_LE32(x) (x)
+# define LE32_TO_HOST(x) (x)
+#endif
+
+/* Fixed header flags */
+#define HEADER_FLAGS 0x020e0000
+
+/* Recognized Hardware ID magic */
+#define HWID_HAME_MPR_A1_L8 0x32473352
+#define HWID_PORAY_R50B 0x31353033
+#define HWID_PORAY_R50D 0x33353033
+#define HWID_PORAY_R50E 0x34353033
+#define HWID_PORAY_M3 0x31353335
+#define HWID_PORAY_M4 0x32353335
+#define HWID_PORAY_Q3 0x33353335
+#define HWID_PORAY_X5_X6 0x35353335
+#define HWID_PORAY_X8 0x36353335
+#define HWID_PORAY_X1 0x38353335
+#define HWID_NEXX_WT1520 0x30353332
+#define HWID_NEXX_WT3020 0x30323033
+#define HWID_A5_V11 0x32473352
+
+/* Recognized XOR obfuscation keys */
+#define KEY_HAME 0
+#define KEY_PORAY_1 1
+#define KEY_PORAY_2 2
+#define KEY_PORAY_3 3
+#define KEY_PORAY_4 4
+#define KEY_NEXX_1 5
+#define KEY_NEXX_2 6
+#define KEY_A5_V11 7
+
+/* XOR key length */
+#define KEY_LEN 15
+
+struct file_info {
+ char *file_name; /* Name of the file */
+ uint32_t file_size; /* Length of the file */
+};
+
+struct fw_header {
+ uint32_t hw_id; /* Hardware id */
+ uint32_t firmware_len; /* Firmware data length */
+ uint32_t flags; /* Header flags */
+ uint8_t pad[16];
+} __attribute__ ((packed));
+
+struct flash_layout {
+ char *id;
+ uint32_t fw_max_len;
+};
+
+struct board_info {
+ char *id;
+ uint32_t hw_id;
+ char *layout_id;
+ uint32_t key;
+};
+
+/*
+ * Globals
+ */
+static char *ofname;
+static char *progname;
+
+static char *board_id;
+static struct board_info *board;
+static char *layout_id;
+static struct flash_layout *layout;
+static char *opt_hw_id;
+static uint32_t hw_id;
+static struct file_info firmware_info;
+static uint32_t firmware_len = 0;
+
+static int inspect = 0;
+static int extract = 0;
+
+static uint8_t key[][KEY_LEN] = {
+ {0xC8, 0x3C, 0x3A, 0x93, 0xA2, 0x95, 0xC3, 0x63, 0x48, 0x45, 0x58, 0x09, 0x12, 0x03, 0x08},
+ {0x89, 0x6B, 0x5A, 0x93, 0x92, 0x95, 0xC3, 0x63, 0xD0, 0xA3, 0x9C, 0x92, 0x2E, 0xE6, 0xC7},
+ {0xC9, 0x1C, 0x3A, 0x93, 0x92, 0x95, 0xC3, 0x63, 0xD0, 0xA3, 0x9C, 0x92, 0x2E, 0xE6, 0xC7},
+ {0x19, 0x1B, 0x3A, 0x93, 0x92, 0x95, 0xC3, 0x63, 0xD0, 0xA3, 0x9C, 0x92, 0x2E, 0xE6, 0xC7},
+ {0x79, 0x7B, 0x7A, 0x93, 0x92, 0x95, 0xC3, 0x63, 0xD0, 0xA3, 0x9C, 0x92, 0x2E, 0xE6, 0xC7},
+ {0x19, 0x1C, 0x4A, 0x93, 0x96, 0x95, 0xC3, 0x63, 0xD0, 0xA3, 0x9C, 0x92, 0x2E, 0x16, 0xC6},
+ {0x39, 0x1C, 0x4A, 0x93, 0x96, 0x95, 0xC3, 0x63, 0xD0, 0xA3, 0x9C, 0x92, 0x2E, 0x16, 0xC6},
+ {0xC8, 0x3C, 0x3A, 0x93, 0xA2, 0x95, 0xC3, 0x63, 0x48, 0x45, 0x58, 0x09, 0x20, 0x11, 0x08},
+};
+
+static struct flash_layout layouts[] = {
+ {
+ .id = "4M",
+ .fw_max_len = 0x3c0000,
+ }, {
+ .id = "8M",
+ .fw_max_len = 0x7c0000,
+ }, {
+ /* terminating entry */
+ }
+};
+
+static struct board_info boards[] = {
+ {
+ .id = "A5-V11",
+ .hw_id = HWID_A5_V11,
+ .layout_id = "4M",
+ .key = KEY_A5_V11,
+ }, {
+ .id = "MPR-A1",
+ .hw_id = HWID_HAME_MPR_A1_L8,
+ .layout_id = "4M",
+ .key = KEY_HAME,
+ }, {
+ .id = "MPR-L8",
+ .hw_id = HWID_HAME_MPR_A1_L8,
+ .layout_id = "4M",
+ .key = KEY_HAME,
+ }, {
+ .id = "R50B",
+ .hw_id = HWID_PORAY_R50B,
+ .layout_id = "4M",
+ .key = KEY_PORAY_2,
+ }, {
+ .id = "R50D",
+ .hw_id = HWID_PORAY_R50D,
+ .layout_id = "4M",
+ .key = KEY_PORAY_3,
+ }, {
+ .id = "R50E",
+ .hw_id = HWID_PORAY_R50E,
+ .layout_id = "4M",
+ .key = KEY_PORAY_4,
+ }, {
+ .id = "M3",
+ .hw_id = HWID_PORAY_M3,
+ .layout_id = "4M",
+ .key = KEY_PORAY_1,
+ }, {
+ .id = "M4",
+ .hw_id = HWID_PORAY_M4,
+ .layout_id = "4M",
+ .key = KEY_PORAY_1,
+ }, {
+ .id = "Q3",
+ .hw_id = HWID_PORAY_Q3,
+ .layout_id = "4M",
+ .key = KEY_PORAY_1,
+ }, {
+ .id = "X5 or X6",
+ .hw_id = HWID_PORAY_X5_X6,
+ .layout_id = "8M",
+ .key = KEY_PORAY_1,
+ }, {
+ .id = "X5",
+ .hw_id = HWID_PORAY_X5_X6,
+ .layout_id = "8M",
+ .key = KEY_PORAY_1,
+ }, {
+ .id = "X6",
+ .hw_id = HWID_PORAY_X5_X6,
+ .layout_id = "8M",
+ .key = KEY_PORAY_1,
+ }, {
+ .id = "X8",
+ .hw_id = HWID_PORAY_X8,
+ .layout_id = "8M",
+ .key = KEY_PORAY_1,
+ }, {
+ .id = "X1",
+ .hw_id = HWID_PORAY_X1,
+ .layout_id = "8M",
+ .key = KEY_PORAY_1,
+ }, {
+ .id = "WT1520",
+ .hw_id = HWID_NEXX_WT1520,
+ .layout_id = "4M",
+ .key = KEY_NEXX_1,
+ }, {
+ .id = "WT1520",
+ .hw_id = HWID_NEXX_WT1520,
+ .layout_id = "8M",
+ .key = KEY_NEXX_1,
+ }, {
+ .id = "WT3020",
+ .hw_id = HWID_NEXX_WT3020,
+ .layout_id = "4M",
+ .key = KEY_NEXX_2,
+ }, {
+ .id = "WT3020",
+ .hw_id = HWID_NEXX_WT3020,
+ .layout_id = "8M",
+ .key = KEY_NEXX_2,
+ }, {
+
+
+
+
+ /* terminating entry */
+ }
+};
+
+/*
+ * 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 DBG(fmt, ...) do { \
+ fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
+} while (0)
+
+/*
+ * Find a board by its name
+ */
+static struct board_info *find_board(char *id)
+{
+ struct board_info *ret;
+ struct board_info *board;
+
+ ret = NULL;
+ for (board = boards; board->id != NULL; board++){
+ if (strcasecmp(id, board->id) == 0) {
+ ret = board;
+ break;
+ }
+ };
+
+ return ret;
+}
+
+/*
+ * Find a board by its hardware ID
+ */
+static struct board_info *find_board_by_hwid(uint32_t hw_id)
+{
+ struct board_info *board;
+
+ for (board = boards; board->id != NULL; board++) {
+ if (hw_id == board->hw_id)
+ return board;
+ };
+
+ return NULL;
+}
+
+/*
+ * Find a Flash memory layout by its name
+ */
+static struct flash_layout *find_layout(char *id)
+{
+ struct flash_layout *ret;
+ struct flash_layout *l;
+
+ ret = NULL;
+ for (l = layouts; l->id != NULL; l++){
+ if (strcasecmp(id, l->id) == 0) {
+ ret = l;
+ break;
+ }
+ };
+
+ return ret;
+}
+
+/*
+ * Display usage
+ */
+static void usage(int status)
+{
+ FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+
+ fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+ fprintf(stream,
+"\n"
+"Options:\n"
+" -B <board> create image for the board specified with <board>\n"
+" -H <hwid> use hardware id specified with <hwid>\n"
+" -F <id> use flash layout specified with <id>\n"
+" -f <file> read firmware image from the file <file>\n"
+" -o <file> write output to the file <file>\n"
+" -i inspect given firmware file (requires -f)\n"
+" -x extract combined kernel and rootfs while inspecting (implies -i)\n"
+" -h show this screen\n"
+ );
+
+ exit(status);
+}
+
+/*
+ * Get file statistics
+ */
+static int get_file_stat(struct file_info *fdata)
+{
+ struct stat st;
+ int res;
+
+ if (fdata->file_name == NULL) {
+ return 0;
+ }
+ res = stat(fdata->file_name, &st);
+ if (res){
+ ERRS("stat failed on %s", fdata->file_name);
+ return res;
+ }
+
+ fdata->file_size = st.st_size;
+ return 0;
+}
+
+/*
+ * Read file into buffer
+ */
+static int read_to_buf(struct file_info *fdata, uint8_t *buf)
+{
+ FILE *f;
+ int ret = EXIT_FAILURE;
+
+ f = fopen(fdata->file_name, "rb");
+ if (f == NULL) {
+ ERRS("could not open \"%s\" for reading", fdata->file_name);
+ goto out;
+ }
+
+ errno = 0;
+ fread(buf, fdata->file_size, 1, f);
+ if (errno != 0) {
+ ERRS("unable to read from file \"%s\"", fdata->file_name);
+ goto out_close;
+ }
+
+ ret = EXIT_SUCCESS;
+
+ out_close:
+ fclose(f);
+ out:
+ return ret;
+}
+
+/*
+ * Check command line options
+ */
+static int check_options(void)
+{
+ int ret;
+
+ if (firmware_info.file_name == NULL) {
+ ERR("no firmware image specified");
+ return -1;
+ }
+
+ ret = get_file_stat(&firmware_info);
+ if (ret)
+ return ret;
+
+ if (inspect)
+ return 0;
+
+ if (board_id == NULL && opt_hw_id == NULL) {
+ ERR("either board or hardware id must be specified");
+ return -1;
+ }
+
+ if (board_id) {
+ board = find_board(board_id);
+ if (board == NULL) {
+ ERR("unknown/unsupported board id \"%s\"", board_id);
+ return -1;
+ }
+ if (layout_id == NULL) {
+ layout_id = board->layout_id;
+ }
+ hw_id = board->hw_id;
+ } else {
+ hw_id = strtoul(opt_hw_id, NULL, 0);
+ board = find_board_by_hwid(hw_id);
+ if (layout_id == NULL) {
+ layout_id = board->layout_id;
+ }
+ }
+
+ layout = find_layout(layout_id);
+ if (layout == NULL) {
+ ERR("unknown flash layout \"%s\"", layout_id);
+ return -1;
+ }
+
+ firmware_len = firmware_info.file_size;
+
+ if (firmware_info.file_size >
+ layout->fw_max_len - sizeof (struct fw_header)) {
+ ERR("firmware image is too big");
+ return -1;
+ }
+
+ if (ofname == NULL) {
+ ERR("no output file specified");
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Fill in firmware header
+ */
+static void fill_header(uint8_t *buf)
+{
+ struct fw_header *hdr = (struct fw_header *) buf;
+
+ memset(hdr, 0, sizeof (struct fw_header));
+ hdr->hw_id = HOST_TO_LE32(hw_id);
+ hdr->firmware_len = HOST_TO_LE32(firmware_len);
+ hdr->flags = HOST_TO_LE32(HEADER_FLAGS);
+}
+
+/*
+ * Compute firmware checksum
+ */
+static uint16_t checksum_fw(uint8_t *data, int len)
+{
+ int i;
+ int32_t checksum = 0;
+
+ for (i = 0; i < len - 1; i += 2) {
+ checksum += (data[i + 1] << 8) | data[i];
+ }
+ if (i < len) {
+ checksum += data[i];
+ }
+ checksum = checksum + (checksum >> 16) + 0xffff;
+ checksum = ~(checksum + (checksum >> 16)) & 0xffff;
+ return (uint16_t) checksum;
+}
+
+/*
+ * (De)obfuscate firmware using an XOR operation with a fixed length key
+ */
+static void xor_fw(uint8_t *data, int len)
+{
+ int i;
+
+ for (i = 0; i <= len; i++) {
+ data[i] ^= key[board->key][i % KEY_LEN];
+ }
+}
+
+/*
+ * Write firmware to file
+ */
+static int write_fw(uint8_t *data, int len)
+{
+ FILE *f;
+ int ret = EXIT_FAILURE;
+
+ f = fopen(ofname, "wb");
+ if (f == NULL) {
+ ERRS("could not open \"%s\" for writing", ofname);
+ goto out;
+ }
+
+ errno = 0;
+ fwrite(data, len, 1, f);
+ if (errno) {
+ ERRS("unable to write output file");
+ goto out_flush;
+ }
+
+ DBG("firmware file \"%s\" completed", ofname);
+
+ ret = EXIT_SUCCESS;
+
+ out_flush:
+ fflush(f);
+ fclose(f);
+ if (ret != EXIT_SUCCESS) {
+ unlink(ofname);
+ }
+ out:
+ return ret;
+}
+
+/*
+ * Build firmware file
+ */
+static int build_fw(void)
+{
+ int buflen;
+ uint8_t *buf, *p;
+ int ret = EXIT_FAILURE;
+ int writelen = 0;
+ uint16_t checksum;
+
+ buflen = layout->fw_max_len;
+
+ buf = (uint8_t *) malloc(buflen);
+ if (!buf) {
+ ERR("no memory for buffer\n");
+ goto out;
+ }
+
+ memset(buf, 0xff, buflen);
+ p = buf + sizeof (struct fw_header);
+ ret = read_to_buf(&firmware_info, p);
+ if (ret) {
+ goto out_free_buf;
+ }
+ writelen = sizeof (struct fw_header) + firmware_len + 2;
+
+ /* Fill in header */
+ fill_header(buf);
+
+ /* Compute firmware checksum */
+ checksum = checksum_fw(buf + sizeof (struct fw_header), firmware_len);
+
+ /* Cannot use network order function because checksum is not word-aligned */
+ buf[writelen - 1] = checksum >> 8;
+ buf[writelen - 2] = checksum & 0xff;
+
+ /* XOR obfuscate firmware */
+ xor_fw(buf + sizeof (struct fw_header), firmware_len + 2);
+
+ /* Write firmware file */
+ ret = write_fw(buf, writelen);
+ if (ret) {
+ goto out_free_buf;
+ }
+ ret = EXIT_SUCCESS;
+
+ out_free_buf:
+ free(buf);
+ out:
+ return ret;
+}
+
+/* Helper functions to inspect_fw() representing different output formats */
+static inline void inspect_fw_pstr(char *label, char *str)
+{
+ printf("%-23s: %s\n", label, str);
+}
+
+static inline void inspect_fw_phex(char *label, uint32_t val)
+{
+ printf("%-23s: 0x%08x\n", label, val);
+}
+
+static inline void inspect_fw_phexpost(char *label,
+ uint32_t val, char *post)
+{
+ printf("%-23s: 0x%08x (%s)\n", label, val, post);
+}
+
+static inline void inspect_fw_phexdef(char *label,
+ uint32_t val, uint32_t defval)
+{
+ printf("%-23s: 0x%08x ", label, val);
+
+ if (val == defval) {
+ printf("(== OpenWrt default)\n");
+ } else {
+ printf("(OpenWrt default: 0x%08x)\n", defval);
+ }
+}
+
+static inline void inspect_fw_phexexp(char *label,
+ uint32_t val, uint32_t expval)
+{
+ printf("%-23s: 0x%08x ", label, val);
+
+ if (val == expval) {
+ printf("(ok)\n");
+ } else {
+ printf("(expected: 0x%08x)\n", expval);
+ }
+}
+
+static inline void inspect_fw_phexdec(char *label, uint32_t val)
+{
+ printf("%-23s: 0x%08x / %8u bytes\n", label, val, val);
+}
+
+static inline void inspect_fw_pchecksum(char *label,
+ uint16_t val, uint16_t expval)
+{
+ printf("%-23s: 0x%04x ", label, val);
+ if (val == expval) {
+ printf("(ok)\n");
+ } else {
+ printf("(expected: 0x%04x)\n", expval);
+ }
+}
+
+static int inspect_fw(void)
+{
+ uint8_t *buf;
+ struct fw_header *hdr;
+ int ret = EXIT_FAILURE;
+ uint16_t computed_checksum, file_checksum;
+
+ buf = (uint8_t *) malloc(firmware_info.file_size);
+ if (!buf) {
+ ERR("no memory for buffer!\n");
+ goto out;
+ }
+
+ ret = read_to_buf(&firmware_info, buf);
+ if (ret) {
+ goto out_free_buf;
+ }
+ hdr = (struct fw_header *)buf;
+
+ inspect_fw_pstr("File name", firmware_info.file_name);
+ inspect_fw_phexdec("File size", firmware_info.file_size);
+
+ printf("\n");
+
+ inspect_fw_phexdec("Header size", sizeof (struct fw_header));
+ board = find_board_by_hwid(LE32_TO_HOST(hdr->hw_id));
+ if (board) {
+ layout = find_layout(board->layout_id);
+ inspect_fw_phexpost("Hardware ID",
+ LE32_TO_HOST( hdr->hw_id), board->id);
+ } else {
+ inspect_fw_phexpost("Hardware ID",
+ LE32_TO_HOST(hdr->hw_id), "unknown");
+ }
+ inspect_fw_phexdec("Firmware data length",
+ LE32_TO_HOST(hdr->firmware_len));
+
+ inspect_fw_phexexp("Flags",
+ LE32_TO_HOST(hdr->flags), HEADER_FLAGS);
+ printf("\n");
+
+ /* XOR unobfuscate firmware */
+ xor_fw(buf + sizeof (struct fw_header), LE32_TO_HOST(hdr->firmware_len) + 2);
+
+ /* Compute firmware checksum */
+ computed_checksum = checksum_fw(buf + sizeof (struct fw_header), LE32_TO_HOST(hdr->firmware_len));
+
+ /* Cannot use network order function because checksum is not word-aligned */
+ file_checksum = (buf[firmware_info.file_size - 1] << 8) | buf[firmware_info.file_size - 2];
+ inspect_fw_pchecksum("Firmware checksum", computed_checksum, file_checksum);
+
+ /* Verify checksum */
+ if (computed_checksum != file_checksum) {
+ ret = -1;
+ ERR("checksums do not match");
+ goto out_free_buf;
+ }
+
+ printf("\n");
+
+ if (extract) {
+ FILE *fp;
+ char *filename;
+
+ if (ofname == NULL) {
+ filename = malloc(strlen(firmware_info.file_name) + 10);
+ sprintf(filename, "%s-firmware", firmware_info.file_name);
+ } else {
+ filename = ofname;
+ }
+ printf("Extracting firmware to \"%s\"...\n", filename);
+ fp = fopen(filename, "wb");
+ if (fp) {
+ if (!fwrite(buf + sizeof (struct fw_header),
+ LE32_TO_HOST(hdr->firmware_len), 1, fp)) {
+ ERRS("error in fwrite(): %s", strerror(errno));
+ }
+ fclose(fp);
+ } else {
+ ERRS("error in fopen(): %s", strerror(errno));
+ }
+ if (ofname == NULL) {
+ free(filename);
+ }
+ printf("\n");
+ }
+
+ out_free_buf:
+ free(buf);
+ out:
+ return ret;
+}
+
+/*
+ * Main entry point
+ */
+int main(int argc, char *argv[])
+{
+ int ret = EXIT_FAILURE;
+
+ progname = basename(argv[0]);
+
+ int c;
+
+ while ((c = getopt(argc, argv, "B:H:F:f:o:ixh")) != -1) {
+ switch (c) {
+ case 'B':
+ board_id = optarg;
+ break;
+ case 'H':
+ opt_hw_id = optarg;
+ break;
+ case 'F':
+ layout_id = optarg;
+ break;
+ case 'f':
+ firmware_info.file_name = optarg;
+ break;
+ case 'o':
+ ofname = optarg;
+ break;
+ case 'i':
+ inspect = 1;
+ break;
+ case 'x':
+ inspect = 1;
+ extract = 1;
+ break;
+ case 'h':
+ usage(EXIT_SUCCESS);
+ break;
+ default:
+ usage(EXIT_FAILURE);
+ break;
+ }
+ }
+
+ ret = check_options();
+ if (ret) {
+ goto out;
+ }
+ if (!inspect) {
+ ret = build_fw();
+ } else {
+ ret = inspect_fw();
+ }
+
+ out:
+ return ret;
+}
diff --git a/tools/firmware-utils/src/mkrtn56uimg.c b/tools/firmware-utils/src/mkrtn56uimg.c
new file mode 100644
index 00000000000..92aaf314a17
--- /dev/null
+++ b/tools/firmware-utils/src/mkrtn56uimg.c
@@ -0,0 +1,293 @@
+/*
+ *
+ * Copyright (C) 2014 OpenWrt.org
+ * Copyright (C) 2014 Mikko Hissa <mikko.hissa@werzek.com>
+ *
+ * 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 <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <zlib.h>
+
+#define IH_MAGIC 0x27051956
+#define IH_NMLEN 32
+#define IH_PRODLEN 23
+
+#define IH_TYPE_INVALID 0
+#define IH_TYPE_STANDALONE 1
+#define IH_TYPE_KERNEL 2
+#define IH_TYPE_RAMDISK 3
+#define IH_TYPE_MULTI 4
+#define IH_TYPE_FIRMWARE 5
+#define IH_TYPE_SCRIPT 6
+#define IH_TYPE_FILESYSTEM 7
+
+/*
+ * Compression Types
+ */
+#define IH_COMP_NONE 0
+#define IH_COMP_GZIP 1
+#define IH_COMP_BZIP2 2
+#define IH_COMP_LZMA 3
+
+typedef struct {
+ uint8_t major;
+ uint8_t minor;
+} version_t;
+
+typedef struct {
+ version_t kernel;
+ version_t fs;
+ uint8_t productid[IH_PRODLEN];
+ uint8_t sub_fs;
+ uint32_t ih_ksz;
+} asus_t;
+
+typedef struct image_header {
+ uint32_t ih_magic;
+ uint32_t ih_hcrc;
+ uint32_t ih_time;
+ uint32_t ih_size;
+ uint32_t ih_load;
+ uint32_t ih_ep;
+ uint32_t ih_dcrc;
+ uint8_t ih_os;
+ uint8_t ih_arch;
+ uint8_t ih_type;
+ uint8_t ih_comp;
+ union {
+ uint8_t ih_name[IH_NMLEN];
+ asus_t asus;
+ } tail;
+} image_header_t;
+
+typedef struct squashfs_sb {
+ uint32_t s_magic;
+ uint32_t pad0[9];
+ uint64_t bytes_used;
+} squashfs_sb_t;
+
+typedef enum {
+ NONE, FACTORY, SYSUPGRADE,
+} op_mode_t;
+
+void
+calc_crc(image_header_t *hdr, void *data, uint32_t len)
+{
+ /*
+ * Calculate payload checksum
+ */
+ hdr->ih_dcrc = htonl(crc32(0, (Bytef *)data, len));
+ hdr->ih_size = htonl(len);
+ /*
+ * Calculate header checksum
+ */
+ hdr->ih_hcrc = 0;
+ hdr->ih_hcrc = htonl(crc32(0, (Bytef *)hdr, sizeof(image_header_t)));
+}
+
+
+static void
+usage(const char *progname, int status)
+{
+ FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+ int i;
+
+ fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+ fprintf(stream, "\n"
+ "Options:\n"
+ " -f <file> generate a factory flash image <file>\n"
+ " -s <file> generate a sysupgrade flash image <file>\n"
+ " -h show this screen\n");
+ exit(status);
+}
+
+int
+process_image(char *progname, char *filename, op_mode_t opmode)
+{
+ int fd, len;
+ void *data, *ptr;
+ char namebuf[IH_NMLEN];
+ struct stat sbuf;
+ uint32_t checksum, offset_kernel, offset_sqfs, offset_end,
+ offset_sec_header, offset_eb, offset_image_end;
+ squashfs_sb_t *sqs;
+ image_header_t *hdr;
+
+ if ((fd = open(filename, O_RDWR, 0666)) < 0) {
+ fprintf (stderr, "%s: Can't open %s: %s\n",
+ progname, filename, strerror(errno));
+ return (EXIT_FAILURE);
+ }
+
+ if (fstat(fd, &sbuf) < 0) {
+ fprintf (stderr, "%s: Can't stat %s: %s\n",
+ progname, filename, strerror(errno));
+ return (EXIT_FAILURE);
+ }
+
+ if ((unsigned)sbuf.st_size < sizeof(image_header_t)) {
+ fprintf (stderr,
+ "%s: Bad size: \"%s\" is no valid image\n",
+ progname, filename);
+ return (EXIT_FAILURE);
+ }
+
+ ptr = (void *)mmap(0, sbuf.st_size,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED,
+ fd, 0);
+
+ if ((caddr_t)ptr == (caddr_t)-1) {
+ fprintf (stderr, "%s: Can't read %s: %s\n",
+ progname, filename, strerror(errno));
+ return (EXIT_FAILURE);
+ }
+
+ hdr = ptr;
+
+ if (ntohl(hdr->ih_magic) != IH_MAGIC) {
+ fprintf (stderr,
+ "%s: Bad Magic Number: \"%s\" is no valid image\n",
+ progname, filename);
+ return (EXIT_FAILURE);
+ }
+
+ if (opmode == FACTORY) {
+ strncpy(namebuf, hdr->tail.ih_name, IH_NMLEN);
+ hdr->tail.asus.kernel.major = 0;
+ hdr->tail.asus.kernel.minor = 0;
+ hdr->tail.asus.fs.major = 0;
+ hdr->tail.asus.fs.minor = 0;
+ strncpy((char *)&hdr->tail.asus.productid, "RT-N56U", IH_PRODLEN);
+ }
+
+ if (hdr->tail.asus.ih_ksz == 0)
+ hdr->tail.asus.ih_ksz = htonl(ntohl(hdr->ih_size) + sizeof(image_header_t));
+
+ offset_kernel = sizeof(image_header_t);
+ offset_sqfs = ntohl(hdr->tail.asus.ih_ksz);
+ sqs = ptr + offset_sqfs;
+ offset_sec_header = offset_sqfs + sqs->bytes_used;
+
+ /*
+ * Reserve space for the second header.
+ */
+ offset_end = offset_sec_header + sizeof(image_header_t);
+ offset_eb = ((offset_end>>16)+1)<<16;
+
+ if (opmode == FACTORY)
+ offset_image_end = offset_eb + 4;
+ else
+ offset_image_end = sbuf.st_size;
+ /*
+ * Move the second header at the end of the image.
+ */
+ offset_end = offset_sec_header;
+ offset_sec_header = offset_eb - sizeof(image_header_t);
+
+ /*
+ * Remove jffs2 markers between squashfs and eb boundary.
+ */
+ if (opmode == FACTORY)
+ memset(ptr+offset_end, 0xff ,offset_eb - offset_end);
+
+ /*
+ * Grow the image if needed.
+ */
+ if (offset_image_end > sbuf.st_size) {
+ (void) munmap((void *)ptr, sbuf.st_size);
+ ftruncate(fd, offset_image_end);
+ ptr = (void *)mmap(0, offset_image_end,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED,
+ fd, 0);
+ /*
+ * jffs2 marker
+ */
+ if (opmode == FACTORY) {
+ *(uint8_t *)(ptr+offset_image_end-4) = 0xde;
+ *(uint8_t *)(ptr+offset_image_end-3) = 0xad;
+ *(uint8_t *)(ptr+offset_image_end-2) = 0xc0;
+ *(uint8_t *)(ptr+offset_image_end-1) = 0xde;
+ }
+ }
+
+ /*
+ * Calculate checksums for the second header to be used after flashing.
+ */
+ if (opmode == FACTORY) {
+ hdr = ptr+offset_sec_header;
+ memcpy(hdr, ptr, sizeof(image_header_t));
+ strncpy(hdr->tail.ih_name, namebuf, IH_NMLEN);
+ calc_crc(hdr, ptr+offset_kernel, offset_sqfs - offset_kernel);
+ calc_crc((image_header_t *)ptr, ptr+offset_kernel, offset_image_end - offset_kernel);
+ } else {
+ calc_crc((image_header_t *)ptr, ptr+offset_kernel, offset_sqfs - offset_kernel);
+ }
+
+ if (sbuf.st_size > offset_image_end)
+ (void) munmap((void *)ptr, sbuf.st_size);
+ else
+ (void) munmap((void *)ptr, offset_image_end);
+
+ ftruncate(fd, offset_image_end);
+ (void) close (fd);
+
+ return EXIT_SUCCESS;
+}
+
+int
+main(int argc, char **argv)
+{
+ int opt;
+ char *filename, *progname;
+ op_mode_t opmode = NONE;
+
+ progname = argv[0];
+
+ while ((opt = getopt(argc, argv,":s:f:h?")) != -1) {
+ switch (opt) {
+ case 's':
+ opmode = SYSUPGRADE;
+ filename = optarg;
+ break;
+ case 'f':
+ opmode = FACTORY;
+ filename = optarg;
+ break;
+ case 'h':
+ opmode = NONE;
+ default:
+ usage(progname, EXIT_FAILURE);
+ opmode = NONE;
+ }
+ }
+
+ if(filename == NULL)
+ opmode = NONE;
+
+ switch (opmode) {
+ case NONE:
+ usage(progname, EXIT_FAILURE);
+ break;
+ case FACTORY:
+ case SYSUPGRADE:
+ return process_image(progname, filename, opmode);
+ break;
+ }
+
+ return EXIT_SUCCESS;
+}
+
diff --git a/tools/firmware-utils/src/mksenaofw.c b/tools/firmware-utils/src/mksenaofw.c
new file mode 100644
index 00000000000..0f10ebdfbeb
--- /dev/null
+++ b/tools/firmware-utils/src/mksenaofw.c
@@ -0,0 +1,420 @@
+/*
+ *
+ * Copyright (C) 2012 OpenWrt.org
+ * Copyright (C) 2012 Mikko Hissa <mikko.hissa@uta.fi>
+ *
+ * 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 <string.h>
+#include <stdarg.h>
+#include <libgen.h>
+#include <errno.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include "md5.h"
+
+#define HDR_LEN 0x60
+#define BUF_SIZE 0x200
+#define VERSION_SIZE 0x10
+#define MD5_SIZE 0x10
+#define PAD_SIZE 0x20
+
+#define DEFAULT_BLOCK_SIZE 65535
+
+#define DEFAULT_HEAD_VALUE 0x0
+#define DEFAULT_VERSION "123"
+#define DEFAULT_MAGIC 0x12345678
+
+typedef struct {
+ uint32_t head;
+ uint32_t vendor_id;
+ uint32_t product_id;
+ uint8_t version[VERSION_SIZE];
+ uint32_t firmware_type;
+ uint32_t filesize;
+ uint32_t zero;
+ uint8_t md5sum[MD5_SIZE];
+ uint8_t pad[PAD_SIZE];
+ uint32_t chksum;
+ uint32_t magic;
+} img_header;
+
+typedef struct {
+ uint8_t id;
+ char * name;
+} firmware_type;
+
+typedef enum {
+ NONE, ENCODE, DECODE
+} op_mode;
+
+static firmware_type FIRMWARE_TYPES[] = {
+ { 0x01, "bootloader" },
+ { 0x02, "kernel" },
+ { 0x03, "kernelapp" },
+ { 0x04, "apps" },
+ /* The types below this line vary by manufacturer */
+ { 0x05, "littleapps (D-Link)/factoryapps (EnGenius)" },
+ { 0x06, "sounds (D-Link)/littleapps (EnGenius)" },
+ { 0x07, "userconfig (D-Link)/appdata (EnGenius)" },
+ { 0x08, "userconfig (EnGenius)"},
+ { 0x09, "odmapps (EnGenius)"},
+ { 0x0a, "factoryapps (D-Link)" },
+ { 0x0b, "odmapps (D-Link)" },
+ { 0x0c, "langpack (D-Link)" }
+};
+
+static long get_file_size(const char *filename)
+{
+ FILE *fp_file;
+ long result;
+
+ fp_file = fopen(filename, "r");
+ if (!fp_file)
+ return -1;
+ fseek(fp_file, 0, SEEK_END);
+ result = ftell(fp_file);
+ fclose(fp_file);
+ return result;
+}
+
+static int header_checksum(void *data, int len)
+{
+ int i;
+ int sum;
+
+ sum = 0;
+ if (data != NULL && len >= 0) {
+ for (i = 0; i < len; ++i)
+ sum += *(unsigned char *) (data + i);
+ return sum;
+ }
+
+ return -1;
+}
+
+static int md5_file(const char *filename, uint8_t *dst)
+{
+ FILE *fp_src;
+ MD5_CTX ctx;
+ char buf[BUF_SIZE];
+ size_t bytes_read;
+
+ MD5_Init(&ctx);
+
+ fp_src = fopen(filename, "r+b");
+ if (!fp_src) {
+ return -1;
+ }
+ while (!feof(fp_src)) {
+ bytes_read = fread(&buf, 1, BUF_SIZE, fp_src);
+ MD5_Update(&ctx, &buf, bytes_read);
+ }
+ fclose(fp_src);
+
+ MD5_Final(dst, &ctx);
+
+ return 0;
+}
+
+static int encode_image(const char *input_file_name,
+ const char *output_file_name, img_header *header, int block_size)
+{
+ char buf[BUF_SIZE];
+ size_t bytes_read;
+ size_t pad_len = 0;
+ size_t bytes_avail;
+
+ FILE *fp_input;
+ FILE *fp_output;
+
+ int i;
+ long magic;
+
+ fp_input = fopen(input_file_name, "r+b");
+ if (!fp_input) {
+ fprintf(stderr, "Cannot open %s !!\n", input_file_name);
+ return -1;
+ }
+
+ fp_output = fopen(output_file_name, "w+b");
+ if (!fp_output) {
+ fprintf(stderr, "Cannot open %s !!\n", output_file_name);
+ fclose(fp_input);
+ return -1;
+ }
+
+ header->filesize = get_file_size(input_file_name);
+ if (!header->filesize) {
+ fprintf(stderr, "File %s open/size error!\n", input_file_name);
+ fclose(fp_input);
+ fclose(fp_output);
+ return -1;
+ }
+ /*
+ * Zero padding
+ */
+ if (block_size > 0) {
+ pad_len = block_size - (header->filesize % block_size);
+ }
+
+ if (md5_file(input_file_name, (uint8_t *) &header->md5sum) < 0) {
+ fprintf(stderr, "MD5 failed on file %s\n", input_file_name);
+ fclose(fp_input);
+ fclose(fp_output);
+ return -1;
+ }
+ header->zero = 0;
+ header->chksum = header_checksum(header, HDR_LEN);
+ header->head = htonl(header->head);
+ header->vendor_id = htonl(header->vendor_id);
+ header->product_id = htonl(header->product_id);
+ header->firmware_type = htonl(header->firmware_type);
+ header->filesize = htonl(header->filesize);
+ header->chksum = htonl(header->chksum);
+ magic = header->magic;
+ header->magic = htonl(header->magic);
+
+ fwrite(header, HDR_LEN, 1, fp_output);
+
+ while (!feof(fp_input) || pad_len > 0) {
+
+ if (!feof(fp_input))
+ bytes_read = fread(&buf, 1, BUF_SIZE, fp_input);
+ else
+ bytes_read = 0;
+
+ /*
+ * No more bytes read, start padding
+ */
+ if (bytes_read < BUF_SIZE && pad_len > 0) {
+ bytes_avail = BUF_SIZE - bytes_read;
+ memset( &buf[bytes_read], 0, bytes_avail);
+ bytes_read += bytes_avail < pad_len ? bytes_avail : pad_len;
+ pad_len -= bytes_avail < pad_len ? bytes_avail : pad_len;
+ }
+
+ for (i = 0; i < bytes_read; i++)
+ buf[i] ^= magic >> (i % 8) & 0xff;
+ fwrite(&buf, bytes_read, 1, fp_output);
+ }
+
+ fclose(fp_input);
+ fclose(fp_output);
+ return 1;
+}
+
+int decode_image(const char *input_file_name, const char *output_file_name)
+{
+ img_header header;
+ char buf[BUF_SIZE];
+
+ FILE *fp_input;
+ FILE *fp_output;
+ unsigned int i;
+
+ size_t bytes_read;
+ size_t bytes_written;
+
+ fp_input = fopen(input_file_name, "r+b");
+ if (!fp_input) {
+ fprintf(stderr, "Cannot open %s !!\n", input_file_name);
+ fclose(fp_input);
+ return -1;
+ }
+
+ fp_output = fopen(output_file_name, "w+b");
+ if (!fp_output) {
+ fprintf(stderr, "Cannot open %s !!\n", output_file_name);
+ fclose(fp_output);
+ return -1;
+ }
+
+ if (fread(&header, 1, HDR_LEN, fp_input) != HDR_LEN) {
+ fprintf(stderr, "Incorrect header size!!");
+ fclose(fp_input);
+ fclose(fp_output);
+ return -1;
+ }
+
+ header.head = ntohl(header.head);
+ header.vendor_id = ntohl(header.vendor_id);
+ header.product_id = ntohl(header.product_id);
+ header.firmware_type = ntohl(header.firmware_type);
+ header.filesize = ntohl(header.filesize);
+ header.chksum = ntohl(header.chksum);
+ header.magic = ntohl(header.magic);
+
+ bytes_written = 0;
+ while (!feof(fp_input)) {
+
+ bytes_read = fread(&buf, 1, BUF_SIZE, fp_input);
+ for (i = 0; i < bytes_read; i++)
+ buf[i] ^= header.magic >> (i % 8) & 0xff;
+
+ /*
+ * Handle padded source file
+ */
+ if (bytes_written + bytes_read > header.filesize) {
+ bytes_read = header.filesize - bytes_written;
+ if (bytes_read > 0)
+ fwrite(&buf, bytes_read, 1, fp_output);
+ break;
+ }
+
+ fwrite(&buf, bytes_read, 1, fp_output);
+ bytes_written += bytes_read;
+ }
+
+ fclose(fp_input);
+ fclose(fp_output);
+
+ return 1;
+}
+
+static void usage(const char *progname, int status)
+{
+ FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+ int i;
+
+ fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+ fprintf(stream, "\n"
+ "Options:\n"
+ " -e <file> encode image file <file>\n"
+ " -d <file> decode image file <file>\n"
+ " -o <file> write output to the file <file>\n"
+ " -t <type> set image type to <type>\n"
+ " valid image <type> values:\n");
+ for (i = 0; i < sizeof(FIRMWARE_TYPES) / sizeof(firmware_type); i++) {
+ fprintf(stream, " %-5i= %s\n", FIRMWARE_TYPES[i].id,
+ FIRMWARE_TYPES[i].name);
+ }
+ fprintf(stream, " -v <version> set image version to <version>\n"
+ " -r <vendor> set image vendor id to <vendor>\n"
+ " -p <product> set image product id to <product>\n"
+ " -m <magic> set encoding magic <magic>\n"
+ " -z enable image padding to <blocksize>\n"
+ " -b <blocksize> set image <blocksize>, defaults to %u\n"
+ " -h show this screen\n", DEFAULT_BLOCK_SIZE);
+ exit(status);
+}
+
+int main(int argc, char *argv[])
+{
+ int opt;
+ char *input_file, *output_file, *progname = NULL;
+ op_mode mode = NONE;
+ int tmp, i, pad = 0;
+ int block_size;
+ img_header header;
+
+ block_size = DEFAULT_BLOCK_SIZE;
+ progname = basename(argv[0]);
+
+ memset(&header, 0, sizeof( img_header ));
+ header.magic = DEFAULT_MAGIC;
+ header.head = DEFAULT_HEAD_VALUE;
+ strncpy( (char*)&header.version, DEFAULT_VERSION, VERSION_SIZE - 1);
+
+ while ((opt = getopt(argc, argv, ":o:e:d:t:v:r:p:m:b:h?z")) != -1) {
+ switch (opt) {
+ case 'e':
+ input_file = optarg;
+ mode = ENCODE;
+ break;
+ case 'd':
+ input_file = optarg;
+ mode = DECODE;
+ break;
+ case 'o':
+ output_file = optarg;
+ break;
+ case 't':
+ tmp = strtol(optarg, 0, 10);
+ for (i = 0; i < sizeof(FIRMWARE_TYPES) / sizeof(firmware_type);
+ i++) {
+ if (FIRMWARE_TYPES[i].id == tmp) {
+ header.firmware_type = FIRMWARE_TYPES[i].id;
+ break;
+ }
+ }
+ if (header.firmware_type == 0) {
+ fprintf(stderr, "Invalid firmware type \"0\"!\n");
+ usage(progname, EXIT_FAILURE);
+ }
+ break;
+ case 'v':
+ strncpy( (char*)&header.version, optarg,
+ VERSION_SIZE - 1);
+ break;
+ case 'r':
+ header.vendor_id = strtol(optarg, 0, 0);
+ break;
+ case 'p':
+ header.product_id = strtol(optarg, 0, 0);
+ break;
+ case 'm':
+ header.magic = strtoul(optarg, 0, 16);
+ break;
+ case 'z':
+ pad = 1;
+ break;
+ case 'b':
+ block_size = strtol(optarg, 0, 10);
+ break;
+ case 'h':
+ usage(progname, EXIT_SUCCESS);
+ break;
+ case ':':
+ fprintf(stderr, "Option -%c requires an operand\n", optopt);
+ usage(progname, EXIT_FAILURE);
+ break;
+ case '?':
+ fprintf(stderr, "Unrecognized option: -%c\n", optopt);
+ usage(progname, EXIT_FAILURE);
+ break;
+ default:
+ usage(progname, EXIT_FAILURE);
+ break;
+ }
+ }
+
+ /* Check required arguments */
+ if (mode == NONE) {
+ fprintf(stderr, "A mode must be defined\n");
+ usage(progname, EXIT_FAILURE);
+ }
+
+ if (input_file == NULL || output_file == NULL) {
+ fprintf(stderr, "Input and output files must be defined\n");
+ usage(progname, EXIT_FAILURE);
+ }
+
+ if (mode == DECODE) {
+ if (decode_image(input_file, output_file) < 0)
+ return EXIT_FAILURE;
+
+ return EXIT_SUCCESS;
+ }
+
+ if (header.firmware_type == 0) {
+ fprintf(stderr, "Firmware type must be defined\n");
+ usage(progname, EXIT_FAILURE);
+ }
+
+ if (header.vendor_id == 0 || header.product_id == 0) {
+ fprintf(stderr, "Vendor ID and Product ID must be defined and non-zero\n");
+ usage(progname, EXIT_FAILURE);
+ }
+
+ if (encode_image(input_file, output_file, &header, pad ? block_size : 0) < 0)
+ return EXIT_FAILURE;
+
+ return EXIT_SUCCESS;
+}
diff --git a/tools/firmware-utils/src/mksercommfw.c b/tools/firmware-utils/src/mksercommfw.c
new file mode 100644
index 00000000000..7f31d4f4c79
--- /dev/null
+++ b/tools/firmware-utils/src/mksercommfw.c
@@ -0,0 +1,255 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+/* #define DEBUG 1 */
+
+/*
+ * Fw Header Layout for Netgear / Sercomm devices
+ * */
+static const char *magic = "sErCoMm"; /* 7 */
+/* 7-11: version control/download control ? */
+unsigned char version[4] = {0x00, 0x01, 0x00, 0x00};
+char *hwID = ""; /* 11-43 , ASCII/HEX */
+char *hwVer = ""; /* 44-57 , ASCII/HEX */
+char *swVer = ""; /* 58-62 , ASCII/HEX */
+/* magic again. */
+
+#define HEADER_SIZE 71
+
+/* null bytes until 511 */
+u_int32_t checksum = 0xFF; /* checksum */
+/* 512 onwards -> ZIP containing rootfs with the same Header */
+
+
+/* appended on rootfs for the Header. */
+const int footer_size = 128;
+
+struct file_info {
+ char *file_name; /* name of the file */
+ char *file_data; /* data of the file in memory */
+ u_int32_t file_size; /* length of the file */
+};
+
+u_int8_t getCheckSum(char *data, int len)
+{
+
+ int32_t previous = 0;
+ u_int32_t new = 0;
+
+ for (u_int32_t i = 0; i < len; i++) {
+ new = (data[i] + previous) % 256;
+ previous = new | previous & -256;
+ }
+ return (u_int8_t) new;
+}
+
+void *bufferFile(struct file_info *finfo, int dontload)
+{
+ int fs = 0;
+ FILE *f = NULL;
+
+#ifdef DEBUG
+ printf("Opening file: %s\n", finfo->file_name);
+#endif
+ f = fopen(finfo->file_name, "rb");
+ if (f == NULL) {
+ perror("Error");
+ exit(1);
+ }
+
+ fseek(f, 0L, SEEK_END);
+ fs = ftell(f);
+ rewind(f);
+
+#ifdef DEBUG
+ printf("Filesize: %i .\n", fs);
+#endif
+
+ finfo->file_size = fs;
+
+ if (dontload) {
+ return 0;
+ }
+
+ char *data = malloc(fs);
+ finfo->file_data = data;
+
+ int read = fread(data, fs, 1, f);
+
+ if (read != 1) {
+ printf("Error reading file %s.", finfo->file_name);
+ exit(1);
+ }
+
+#ifdef DEBUG
+ printf("File: read successfully %i bytes.\n", read*fs);
+#endif
+ fclose(f);
+}
+
+void *writeFile(struct file_info *finfo)
+{
+
+#ifdef DEBUG
+ printf("Writing file: %s.\n", finfo->file_name);
+#endif
+
+ FILE *fout = fopen(finfo->file_name, "w");
+
+ if (!fwrite(finfo->file_data, finfo->file_size, 1, fout)) {
+ printf("Wanted to write, but something went wrong.\n");
+ fclose(fout);
+ exit(1);
+ }
+ fclose(fout);
+}
+
+void *rmFile(struct file_info *finfo)
+{
+ remove(finfo->file_name);
+ free(finfo->file_data);
+ finfo->file_size = 0;
+}
+
+void *usage(char *argv[])
+{
+ printf("Usage: %s <sysupgradefile> <kernel_offset> <HWID> <HWVER> <SWID>\n"
+ "All are positional arguments ... \n"
+ " sysupgradefile: File with the kernel uimage at 0\n"
+ " kernel_offset: Offset in Hex where the kernel is located\n"
+ " HWID: Hardware ID, ASCII\n"
+ " HWVER: Hardware Version, ASCII\n"
+ " SWID: Software Version, Hex\n"
+ " \n"
+ " ", argv[0]);
+}
+
+int main(int argc, char *argv[])
+{
+ printf("Building fw image for sercomm devices.\n");
+
+ if (argc == 2) {
+ struct file_info myfile = {argv[1], 0, 0};
+ bufferFile(&myfile, 0);
+ char chksum = getCheckSum(myfile.file_data, myfile.file_size);
+ printf("Checksum for File: %X.\n", chksum);
+ return 0;
+ }
+
+ if (argc != 6) {
+ usage(argv);
+ return 1;
+ }
+
+ /* Args */
+
+ struct file_info sysupgrade = {argv[1], 0, 0};
+ bufferFile(&sysupgrade, 0);
+
+ int kernel_offset = 0x90000; /* offset for the kernel inside the rootfs, default val */
+ sscanf(argv[2], "%X", &kernel_offset);
+#ifdef DEBUG
+ printf("Kernel_offset: at %X/%i bytes.\n", kernel_offset, kernel_offset);
+#endif
+ char *hwID = argv[3];
+ char *hwVer = argv[4];
+ u_int32_t swVer = 0;
+ sscanf(argv[5],"%4X",&swVer);
+ swVer = bswap_32(swVer);
+
+ char *rootfsname = malloc(2*strlen(sysupgrade.file_name) + 8);
+ sprintf(rootfsname, "%s.rootfs", sysupgrade.file_name);
+
+ char *zipfsname = malloc(2*strlen(rootfsname) + 5);
+ sprintf(zipfsname, "%s.zip", rootfsname);
+ /* / Args */
+
+#ifdef DEBUG
+ printf("Building header: %s %s %2X %s.\n", hwID , hwVer, swVer, magic);
+#endif
+ /* Construct the firmware header/magic */
+ struct file_info header = {0, 0, 0};
+ header.file_size = HEADER_SIZE;
+ header.file_data = malloc(HEADER_SIZE);
+ bzero(header.file_data, header.file_size);
+
+ char *tg = header.file_data;
+ strcpy(tg, magic);
+ memcpy(tg+7, version, 4*sizeof(char));
+ strcpy(tg+11, hwID);
+ strcpy(tg+45, hwVer);
+ memcpy(tg+55, &swVer,sizeof(u_int32_t));
+ strcpy(tg+63, magic);
+
+#ifdef DEBUG
+ printf("Header done, now creating rootfs.");
+#endif
+ /* Construct a rootfs */
+ struct file_info rootfs = {0, 0, 0};
+ rootfs.file_size = sysupgrade.file_size + kernel_offset + footer_size;
+ rootfs.file_data = malloc(rootfs.file_size);
+ bzero(rootfs.file_data, rootfs.file_size);
+ rootfs.file_name = rootfsname;
+
+ /* copy Owrt image to Kernel location */
+ memcpy(rootfs.file_data+kernel_offset, sysupgrade.file_data, sysupgrade.file_size);
+
+ /* 22 added to get away from sysup image, no other reason.
+ * updater searches for magic anyway */
+ tg = rootfs.file_data + kernel_offset + sysupgrade.file_size+22;
+
+ memcpy(tg, header.file_data, header.file_size);
+ writeFile(&rootfs);
+
+#ifdef DEBUG
+ printf("Preparing to zip.\n");
+#endif
+ /* now that we got the rootfs, repeat the whole thing again(sorta):
+ * 1. zip the rootfs */
+ char *zipper = malloc(5 + 2*strlen(rootfs.file_name) + 4);
+ sprintf(zipper, "%s %s %s", "zip ", zipfsname, rootfs.file_name);
+ int ret = system(zipper);
+
+ /* clear rootfs file */
+ rmFile(&rootfs);
+
+ /* and load zipped fs */
+ struct file_info zippedfs = {zipfsname, 0, 0};
+ bufferFile(&zippedfs, 0);
+
+#ifdef DEBUG
+ printf("Creating Image.\n");
+#endif
+
+ /* 2. create new file 512+rootfs size */
+ struct file_info image = {argv[1], 0, 0};
+ image.file_data = malloc(zippedfs.file_size + 512);
+ image.file_size = zippedfs.file_size + 512;
+
+ /* 3. copy zipfile at loc 512 */
+ memcpy(image.file_data+512, zippedfs.file_data, zippedfs.file_size);
+ rmFile(&zippedfs);
+
+ /* 4. add header to file */
+ memcpy(image.file_data, header.file_data, header.file_size);
+
+ /* 5. do a checksum run, and compute checksum */
+ char chksum = getCheckSum(image.file_data, image.file_size);
+#ifdef DEBUG
+ printf("Checksum for Image: %X.\n", chksum);
+#endif
+
+ /* 6. write the checksum invert into byte 511 to bring it to 0 */
+ chksum = (chksum ^ 0xFF) + 1;
+ memcpy(image.file_data+511, &chksum, 1);
+
+ chksum = getCheckSum(image.file_data, image.file_size);
+#ifdef DEBUG
+ printf("Checksum for after fix: %X.\n", chksum);
+#endif
+ /* 7. pray that the updater will accept the file */
+ writeFile(&image);
+ return 0;
+}
diff --git a/tools/firmware-utils/src/mktplinkfw-lib.c b/tools/firmware-utils/src/mktplinkfw-lib.c
new file mode 100644
index 00000000000..e3213274c19
--- /dev/null
+++ b/tools/firmware-utils/src/mktplinkfw-lib.c
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This tool was based on:
+ * TP-Link WR941 V2 firmware checksum fixing tool.
+ * Copyright (C) 2008,2009 Wang Jian <lark@linux.net.cn>
+ *
+ * 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 <stdbool.h>
+#include <endian.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#include "mktplinkfw-lib.h"
+#include "md5.h"
+
+extern char *ofname;
+extern char *progname;
+extern uint32_t kernel_len;
+extern struct file_info kernel_info;
+extern struct file_info rootfs_info;
+extern struct flash_layout *layout;
+extern uint32_t rootfs_ofs;
+extern uint32_t rootfs_align;
+extern int combined;
+extern int strip_padding;
+extern int add_jffs2_eof;
+
+static unsigned char jffs2_eof_mark[4] = {0xde, 0xad, 0xc0, 0xde};
+
+void fill_header(char *buf, int len);
+
+struct flash_layout *find_layout(struct flash_layout *layouts, const char *id)
+{
+ struct flash_layout *ret;
+ struct flash_layout *l;
+
+ ret = NULL;
+ for (l = layouts; l->id != NULL; l++){
+ if (strcasecmp(id, l->id) == 0) {
+ ret = l;
+ break;
+ }
+ };
+
+ return ret;
+}
+
+void get_md5(const char *data, int size, uint8_t *md5)
+{
+ MD5_CTX ctx;
+
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, data, size);
+ MD5_Final(md5, &ctx);
+}
+
+int get_file_stat(struct file_info *fdata)
+{
+ struct stat st;
+ int res;
+
+ if (fdata->file_name == NULL)
+ return 0;
+
+ res = stat(fdata->file_name, &st);
+ if (res){
+ ERRS("stat failed on %s", fdata->file_name);
+ return res;
+ }
+
+ fdata->file_size = st.st_size;
+ return 0;
+}
+
+int read_to_buf(const struct file_info *fdata, char *buf)
+{
+ FILE *f;
+ int ret = EXIT_FAILURE;
+
+ f = fopen(fdata->file_name, "r");
+ if (f == NULL) {
+ ERRS("could not open \"%s\" for reading", fdata->file_name);
+ goto out;
+ }
+
+ errno = 0;
+ fread(buf, fdata->file_size, 1, f);
+ if (errno != 0) {
+ ERRS("unable to read from file \"%s\"", fdata->file_name);
+ goto out_close;
+ }
+
+ ret = EXIT_SUCCESS;
+
+out_close:
+ fclose(f);
+out:
+ return ret;
+}
+
+static int pad_jffs2(char *buf, int currlen, int maxlen)
+{
+ int len;
+ uint32_t pad_mask;
+
+ len = currlen;
+ pad_mask = (4 * 1024) | (64 * 1024); /* EOF at 4KB and at 64KB */
+ while ((len < maxlen) && (pad_mask != 0)) {
+ uint32_t mask;
+ int i;
+
+ for (i = 10; i < 32; i++) {
+ mask = 1 << i;
+ if (pad_mask & mask)
+ break;
+ }
+
+ len = ALIGN(len, mask);
+
+ for (i = 10; i < 32; i++) {
+ mask = 1 << i;
+ if ((len & (mask - 1)) == 0)
+ pad_mask &= ~mask;
+ }
+
+ for (i = 0; i < sizeof(jffs2_eof_mark); i++)
+ buf[len + i] = jffs2_eof_mark[i];
+
+ len += sizeof(jffs2_eof_mark);
+ }
+
+ return len;
+}
+
+int write_fw(const char *ofname, const char *data, int len)
+{
+ FILE *f;
+ int ret = EXIT_FAILURE;
+
+ f = fopen(ofname, "w");
+ if (f == NULL) {
+ ERRS("could not open \"%s\" for writing", ofname);
+ goto out;
+ }
+
+ errno = 0;
+ fwrite(data, len, 1, f);
+ if (errno) {
+ ERRS("unable to write output file");
+ goto out_flush;
+ }
+
+ DBG("firmware file \"%s\" completed", ofname);
+
+ ret = EXIT_SUCCESS;
+
+out_flush:
+ fflush(f);
+ fclose(f);
+ if (ret != EXIT_SUCCESS) {
+ unlink(ofname);
+ }
+out:
+ return ret;
+}
+
+/* Helper functions to inspect_fw() representing different output formats */
+inline void inspect_fw_pstr(const char *label, const char *str)
+{
+ printf("%-23s: %s\n", label, str);
+}
+
+inline void inspect_fw_phex(const char *label, uint32_t val)
+{
+ printf("%-23s: 0x%08x\n", label, val);
+}
+
+inline void inspect_fw_phexdec(const char *label, uint32_t val)
+{
+ printf("%-23s: 0x%08x / %8u bytes\n", label, val, val);
+}
+
+inline void inspect_fw_pmd5sum(const char *label, const uint8_t *val, const char *text)
+{
+ int i;
+
+ printf("%-23s:", label);
+ for (i=0; i<MD5SUM_LEN; i++)
+ printf(" %02x", val[i]);
+ printf(" %s\n", text);
+}
+
+// header_size = sizeof(struct fw_header)
+int build_fw(size_t header_size)
+{
+ int buflen;
+ char *buf;
+ char *p;
+ int ret = EXIT_FAILURE;
+ int writelen = 0;
+
+ writelen = header_size + kernel_len;
+
+ if (combined)
+ buflen = writelen;
+ else
+ buflen = layout->fw_max_len;
+
+ buf = malloc(buflen);
+ if (!buf) {
+ ERR("no memory for buffer\n");
+ goto out;
+ }
+
+ memset(buf, 0xff, buflen);
+ p = buf + header_size;
+ ret = read_to_buf(&kernel_info, p);
+ if (ret)
+ goto out_free_buf;
+
+ if (!combined) {
+ p = buf + rootfs_ofs;
+
+ ret = read_to_buf(&rootfs_info, p);
+ if (ret)
+ goto out_free_buf;
+
+ writelen = rootfs_ofs + rootfs_info.file_size;
+
+ if (add_jffs2_eof)
+ writelen = pad_jffs2(buf, writelen, layout->fw_max_len);
+ }
+
+ if (!strip_padding)
+ writelen = buflen;
+
+ fill_header(buf, writelen);
+ ret = write_fw(ofname, buf, writelen);
+ if (ret)
+ goto out_free_buf;
+
+ ret = EXIT_SUCCESS;
+
+out_free_buf:
+ free(buf);
+out:
+ return ret;
+}
diff --git a/tools/firmware-utils/src/mktplinkfw-lib.h b/tools/firmware-utils/src/mktplinkfw-lib.h
new file mode 100644
index 00000000000..31e6d0b1e6b
--- /dev/null
+++ b/tools/firmware-utils/src/mktplinkfw-lib.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This tool was based on:
+ * TP-Link WR941 V2 firmware checksum fixing tool.
+ * Copyright (C) 2008,2009 Wang Jian <lark@linux.net.cn>
+ *
+ * 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.
+ *
+ */
+
+
+#ifndef mktplinkfw_lib_h
+#define mktplinkfw_lib_h
+
+#define ALIGN(x,a) ({ typeof(a) __a = (a); (((x) + __a - 1) & ~(__a - 1)); })
+#define ARRAY_SIZE(a) (sizeof((a)) / sizeof((a)[0]))
+
+#define MD5SUM_LEN 16
+
+/*
+ * 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 DBG(fmt, ...) do { \
+ fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
+} while (0)
+
+
+struct file_info {
+ char *file_name; /* name of the file */
+ uint32_t file_size; /* length of the file */
+};
+
+struct flash_layout {
+ char *id;
+ uint32_t fw_max_len;
+ uint32_t kernel_la;
+ uint32_t kernel_ep;
+ uint32_t rootfs_ofs;
+};
+
+struct flash_layout *find_layout(struct flash_layout *layouts, const char *id);
+void get_md5(const char *data, int size, uint8_t *md5);
+int get_file_stat(struct file_info *fdata);
+int read_to_buf(const struct file_info *fdata, char *buf);
+int write_fw(const char *ofname, const char *data, int len);
+inline void inspect_fw_pstr(const char *label, const char *str);
+inline void inspect_fw_phex(const char *label, uint32_t val);
+inline void inspect_fw_phexdec(const char *label, uint32_t val);
+inline void inspect_fw_pmd5sum(const char *label, const uint8_t *val, const char *text);
+int build_fw(size_t header_size);
+
+#endif /* mktplinkfw_lib_h */
diff --git a/tools/firmware-utils/src/mktplinkfw.c b/tools/firmware-utils/src/mktplinkfw.c
index f8fa2f14b40..ce2acc20c93 100644
--- a/tools/firmware-utils/src/mktplinkfw.c
+++ b/tools/firmware-utils/src/mktplinkfw.c
@@ -19,6 +19,8 @@
#include <libgen.h>
#include <getopt.h> /* for getopt() */
#include <stdarg.h>
+#include <stdbool.h>
+#include <endian.h>
#include <errno.h>
#include <sys/stat.h>
@@ -26,37 +28,10 @@
#include <netinet/in.h>
#include "md5.h"
-
-#define ALIGN(x,a) ({ typeof(a) __a = (a); (((x) + __a - 1) & ~(__a - 1)); })
+#include "mktplinkfw-lib.h"
#define HEADER_VERSION_V1 0x01000000
-#define HWID_TL_MR3020_V1 0x30200001
-#define HWID_TL_MR3220_V1 0x32200001
-#define HWID_TL_MR3420_V1 0x34200001
-#define HWID_TL_WA701N_V1 0x07010001
-#define HWID_TL_WA901ND_V1 0x09010001
-#define HWID_TL_WA901ND_V2 0x09010002
-#define HWID_TL_WR703N_V1 0x07030101
-#define HWID_TL_WR741ND_V1 0x07410001
-#define HWID_TL_WR741ND_V4 0x07410004
-#define HWID_TL_WR740N_V1 0x07400001
-#define HWID_TL_WR740N_V3 0x07400003
-#define HWID_TL_WR743ND_V1 0x07430001
-#define HWID_TL_WR841N_V1_5 0x08410002
-#define HWID_TL_WR841ND_V3 0x08410003
-#define HWID_TL_WR841ND_V5 0x08410005
-#define HWID_TL_WR841ND_V7 0x08410007
-#define HWID_TL_WR941ND_V2 0x09410002
-#define HWID_TL_WR941ND_V4 0x09410004
-#define HWID_TL_WR1043ND_V1 0x10430001
-#define HWID_TL_WR2543N_V1 0x25430001
-
-#define MD5SUM_LEN 16
-
-struct file_info {
- char *file_name; /* name of the file */
- uint32_t file_size; /* length of the file */
-};
+#define HEADER_VERSION_V2 0x02000000
struct fw_header {
uint32_t version; /* header version */
@@ -64,7 +39,7 @@ struct fw_header {
char fw_version[36];
uint32_t hw_id; /* hardware id */
uint32_t hw_rev; /* hardware revision */
- uint32_t unk1;
+ uint32_t region_code; /* region code */
uint8_t md5sum1[MD5SUM_LEN];
uint32_t unk2;
uint8_t md5sum2[MD5SUM_LEN];
@@ -78,62 +53,68 @@ struct fw_header {
uint32_t rootfs_len; /* rootfs data length */
uint32_t boot_ofs; /* bootloader data offset */
uint32_t boot_len; /* bootloader data length */
- uint8_t pad[360];
+ uint16_t ver_hi;
+ uint16_t ver_mid;
+ uint16_t ver_lo;
+ uint8_t pad[130];
+ char region_str1[32];
+ char region_str2[32];
+ uint8_t pad2[160];
} __attribute__ ((packed));
-struct flash_layout {
- char *id;
- uint32_t fw_max_len;
- uint32_t kernel_la;
- uint32_t kernel_ep;
- uint32_t rootfs_ofs;
+struct fw_region {
+ char name[4];
+ uint32_t code;
};
-struct board_info {
- char *id;
- uint32_t hw_id;
- uint32_t hw_rev;
- char *layout_id;
-};
/*
* Globals
*/
-static char *ofname;
-static char *progname;
+char *ofname;
+char *progname;
static char *vendor = "TP-LINK Technologies";
static char *version = "ver. 1.0";
+static char *fw_ver = "0.0.0";
+static uint32_t hdr_ver = HEADER_VERSION_V1;
-static char *board_id;
-static struct board_info *board;
static char *layout_id;
-static struct flash_layout *layout;
+struct flash_layout *layout;
static char *opt_hw_id;
static uint32_t hw_id;
static char *opt_hw_rev;
static uint32_t hw_rev;
-static struct file_info kernel_info;
+static uint32_t opt_hdr_ver = 1;
+static char *country;
+static const struct fw_region *region;
+static int fw_ver_lo;
+static int fw_ver_mid;
+static int fw_ver_hi;
+struct file_info kernel_info;
static uint32_t kernel_la = 0;
static uint32_t kernel_ep = 0;
-static uint32_t kernel_len = 0;
-static struct file_info rootfs_info;
-static uint32_t rootfs_ofs = 0;
-static uint32_t rootfs_align;
+uint32_t kernel_len = 0;
+struct file_info rootfs_info;
+uint32_t rootfs_ofs = 0;
+uint32_t rootfs_align;
static struct file_info boot_info;
-static int combined;
-static int strip_padding;
-static int add_jffs2_eof;
-static unsigned char jffs2_eof_mark[4] = {0xde, 0xad, 0xc0, 0xde};
+int combined;
+int strip_padding;
+int add_jffs2_eof;
+static uint32_t fw_max_len;
+static uint32_t reserved_space;
static struct file_info inspect_info;
static int extract = 0;
+static bool endian_swap = false;
+static bool rootfs_ofs_calc = false;
-char md5salt_normal[MD5SUM_LEN] = {
+static const char md5salt_normal[MD5SUM_LEN] = {
0xdc, 0xd7, 0x3a, 0xa5, 0xc3, 0x95, 0x98, 0xfb,
0xdd, 0xf9, 0xe7, 0xf4, 0x0e, 0xae, 0x47, 0x38,
};
-char md5salt_boot[MD5SUM_LEN] = {
+static const char md5salt_boot[MD5SUM_LEN] = {
0x8c, 0xef, 0x33, 0x5b, 0xd5, 0xc5, 0xce, 0xfa,
0xa7, 0x9c, 0x28, 0xda, 0xb2, 0xe9, 0x0f, 0x42,
};
@@ -164,268 +145,85 @@ static struct flash_layout layouts[] = {
.kernel_ep = 0x80060000,
.rootfs_ofs = 0x100000,
}, {
- /* terminating entry */
- }
-};
-
-static struct board_info boards[] = {
- {
- .id = "TL-MR3020v1",
- .hw_id = HWID_TL_MR3020_V1,
- .hw_rev = 1,
- .layout_id = "4Mlzma",
- }, {
- .id = "TL-MR3220v1",
- .hw_id = HWID_TL_MR3220_V1,
- .hw_rev = 1,
- .layout_id = "4M",
- }, {
- .id = "TL-MR3420v1",
- .hw_id = HWID_TL_MR3420_V1,
- .hw_rev = 1,
- .layout_id = "4M",
- }, {
- .id = "TL-WA701Nv1",
- .hw_id = HWID_TL_WA701N_V1,
- .hw_rev = 1,
- .layout_id = "4M",
- }, {
- .id = "TL-WA901NDv1",
- .hw_id = HWID_TL_WA901ND_V1,
- .hw_rev = 1,
- .layout_id = "4M",
- }, {
- .id = "TL-WA901NDv2",
- .hw_id = HWID_TL_WA901ND_V2,
- .hw_rev = 1,
- .layout_id = "4M",
- }, {
- .id = "TL-WR741NDv1",
- .hw_id = HWID_TL_WR741ND_V1,
- .hw_rev = 1,
- .layout_id = "4M",
- }, {
- .id = "TL-WR741NDv4",
- .hw_id = HWID_TL_WR741ND_V4,
- .hw_rev = 1,
- .layout_id = "4Mlzma",
- }, {
- .id = "TL-WR740Nv1",
- .hw_id = HWID_TL_WR740N_V1,
- .hw_rev = 1,
- .layout_id = "4M",
- }, {
- .id = "TL-WR740Nv3",
- .hw_id = HWID_TL_WR740N_V3,
- .hw_rev = 1,
- .layout_id = "4M",
- }, {
- .id = "TL-WR743NDv1",
- .hw_id = HWID_TL_WR743ND_V1,
- .hw_rev = 1,
- .layout_id = "4M",
- }, {
- .id = "TL-WR841Nv1.5",
- .hw_id = HWID_TL_WR841N_V1_5,
- .hw_rev = 2,
- .layout_id = "4M",
- }, {
- .id = "TL-WR841NDv3",
- .hw_id = HWID_TL_WR841ND_V3,
- .hw_rev = 3,
- .layout_id = "4M",
- }, {
- .id = "TL-WR841NDv5",
- .hw_id = HWID_TL_WR841ND_V5,
- .hw_rev = 1,
- .layout_id = "4M",
- }, {
- .id = "TL-WR841NDv7",
- .hw_id = HWID_TL_WR841ND_V7,
- .hw_rev = 1,
- .layout_id = "4M",
- }, {
- .id = "TL-WR941NDv2",
- .hw_id = HWID_TL_WR941ND_V2,
- .hw_rev = 2,
- .layout_id = "4M",
- }, {
- .id = "TL-WR941NDv4",
- .hw_id = HWID_TL_WR941ND_V4,
- .hw_rev = 1,
- .layout_id = "4M",
- }, {
- .id = "TL-WR1043NDv1",
- .hw_id = HWID_TL_WR1043ND_V1,
- .hw_rev = 1,
- .layout_id = "8M",
+ .id = "16M",
+ .fw_max_len = 0xf80000,
+ .kernel_la = 0x80060000,
+ .kernel_ep = 0x80060000,
+ .rootfs_ofs = 0x140000,
}, {
- .id = "TL-WR2543Nv1",
- .hw_id = HWID_TL_WR2543N_V1,
- .hw_rev = 1,
- .layout_id = "8Mlzma",
+ .id = "16Mlzma",
+ .fw_max_len = 0xf80000,
+ .kernel_la = 0x80060000,
+ .kernel_ep = 0x80060000,
+ .rootfs_ofs = 0x100000,
}, {
- .id = "TL-WR703Nv1",
- .hw_id = HWID_TL_WR703N_V1,
- .hw_rev = 1,
- .layout_id = "4Mlzma",
+ .id = "16Mppc",
+ .fw_max_len = 0xf80000,
+ .kernel_la = 0x00000000 ,
+ .kernel_ep = 0xc0000000,
+ .rootfs_ofs = 0x2a0000,
}, {
/* terminating entry */
}
};
-/*
- * 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 DBG(fmt, ...) do { \
- fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
-} while (0)
-
-static struct board_info *find_board(char *id)
-{
- struct board_info *ret;
- struct board_info *board;
-
- ret = NULL;
- for (board = boards; board->id != NULL; board++){
- if (strcasecmp(id, board->id) == 0) {
- ret = board;
- break;
- }
- };
-
- return ret;
-}
+static const struct fw_region regions[] = {
+ /* Default region (universal) uses code 0 as well */
+ {"US", 1},
+ {"EU", 0},
+ {"BR", 0},
+};
-static struct board_info *find_board_by_hwid(uint32_t hw_id)
-{
- struct board_info *board;
+static const struct fw_region * find_region(const char *country) {
+ size_t i;
- for (board = boards; board->id != NULL; board++) {
- if (hw_id == board->hw_id)
- return board;
- };
+ for (i = 0; i < ARRAY_SIZE(regions); i++) {
+ if (strcasecmp(regions[i].name, country) == 0)
+ return &regions[i];
+ }
return NULL;
}
-static struct flash_layout *find_layout(char *id)
-{
- struct flash_layout *ret;
- struct flash_layout *l;
-
- ret = NULL;
- for (l = layouts; l->id != NULL; l++){
- if (strcasecmp(id, l->id) == 0) {
- ret = l;
- break;
- }
- };
-
- return ret;
-}
-
static void usage(int status)
{
- FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
- struct board_info *board;
-
- fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
- fprintf(stream,
+ fprintf(stderr, "Usage: %s [OPTIONS...]\n", progname);
+ fprintf(stderr,
"\n"
"Options:\n"
-" -B <board> create image for the board specified with <board>\n"
" -c use combined kernel image\n"
+" -e swap endianness in kernel load address and entry point\n"
" -E <ep> overwrite kernel entry point with <ep> (hexval prefixed with 0x)\n"
" -L <la> overwrite kernel load address with <la> (hexval prefixed with 0x)\n"
" -H <hwid> use hardware id specified with <hwid>\n"
+" -W <hwrev> use hardware revision specified with <hwrev>\n"
+" -C <country> set region code to <country>\n"
" -F <id> use flash layout specified with <id>\n"
" -k <file> read kernel image from the file <file>\n"
" -r <file> read rootfs image from the file <file>\n"
" -a <align> align the rootfs start on an <align> bytes boundary\n"
" -R <offset> overwrite rootfs offset with <offset> (hexval prefixed with 0x)\n"
+" -O calculate rootfs offset for combined images\n"
" -o <file> write output to the file <file>\n"
" -s strip padding from the end of the image\n"
" -j add jffs2 end-of-filesystem markers\n"
" -N <vendor> set image vendor to <vendor>\n"
" -V <version> set image version to <version>\n"
+" -v <version> set firmware version to <version>\n"
+" -m <version> set header version to <version>\n"
" -i <file> inspect given firmware file <file>\n"
" -x extract kernel and rootfs while inspecting (requires -i)\n"
+" -X <size> reserve <size> bytes in the firmware image (hexval prefixed with 0x)\n"
" -h show this screen\n"
);
exit(status);
}
-static int get_md5(char *data, int size, char *md5)
-{
- MD5_CTX ctx;
-
- MD5_Init(&ctx);
- MD5_Update(&ctx, data, size);
- MD5_Final(md5, &ctx);
-}
-
-static int get_file_stat(struct file_info *fdata)
-{
- struct stat st;
- int res;
-
- if (fdata->file_name == NULL)
- return 0;
-
- res = stat(fdata->file_name, &st);
- if (res){
- ERRS("stat failed on %s", fdata->file_name);
- return res;
- }
-
- fdata->file_size = st.st_size;
- return 0;
-}
-
-static int read_to_buf(struct file_info *fdata, char *buf)
-{
- FILE *f;
- int ret = EXIT_FAILURE;
-
- f = fopen(fdata->file_name, "r");
- if (f == NULL) {
- ERRS("could not open \"%s\" for reading", fdata->file_name);
- goto out;
- }
-
- errno = 0;
- fread(buf, fdata->file_size, 1, f);
- if (errno != 0) {
- ERRS("unable to read from file \"%s\"", fdata->file_name);
- goto out_close;
- }
-
- ret = EXIT_SUCCESS;
-
- out_close:
- fclose(f);
- out:
- return ret;
-}
-
static int check_options(void)
{
int ret;
+ int exceed_bytes;
if (inspect_info.file_name) {
ret = get_file_stat(&inspect_info);
@@ -438,48 +236,55 @@ static int check_options(void)
return -1;
}
- if (board_id == NULL && opt_hw_id == NULL) {
- ERR("either board or hardware id must be specified");
+ if (opt_hw_id == NULL) {
+ ERR("hardware id not specified");
+ return -1;
+ }
+ hw_id = strtoul(opt_hw_id, NULL, 0);
+
+ if (!combined && layout_id == NULL) {
+ ERR("flash layout is not specified");
return -1;
}
- if (board_id) {
- board = find_board(board_id);
- if (board == NULL) {
- ERR("unknown/unsupported board id \"%s\"", board_id);
+ if (opt_hw_rev)
+ hw_rev = strtoul(opt_hw_rev, NULL, 0);
+ else
+ hw_rev = 1;
+
+ if (country) {
+ region = find_region(country);
+ if (!region) {
+ ERR("unknown region code \"%s\"", country);
return -1;
}
- if (layout_id == NULL)
- layout_id = board->layout_id;
+ }
- hw_id = board->hw_id;
- hw_rev = board->hw_rev;
+ if (combined) {
+ if (!kernel_la || !kernel_ep) {
+ ERR("kernel loading address and entry point must be specified for combined image");
+ return -1;
+ }
} else {
- if (layout_id == NULL) {
- ERR("flash layout is not specified");
+ layout = find_layout(layouts, layout_id);
+ if (layout == NULL) {
+ ERR("unknown flash layout \"%s\"", layout_id);
return -1;
}
- hw_id = strtoul(opt_hw_id, NULL, 0);
- if (opt_hw_rev)
- hw_rev = strtoul(opt_hw_rev, NULL, 0);
- else
- hw_rev = 1;
- }
+ if (!kernel_la)
+ kernel_la = layout->kernel_la;
+ if (!kernel_ep)
+ kernel_ep = layout->kernel_ep;
+ if (!rootfs_ofs)
+ rootfs_ofs = layout->rootfs_ofs;
- layout = find_layout(layout_id);
- if (layout == NULL) {
- ERR("unknown flash layout \"%s\"", layout_id);
- return -1;
+ if (reserved_space > layout->fw_max_len) {
+ ERR("reserved space is not valid");
+ return -1;
+ }
}
- if (!kernel_la)
- kernel_la = layout->kernel_la;
- if (!kernel_ep)
- kernel_ep = layout->kernel_ep;
- if (!rootfs_ofs)
- rootfs_ofs = layout->rootfs_ofs;
-
if (kernel_info.file_name == NULL) {
ERR("no kernel image specified");
return -1;
@@ -491,13 +296,9 @@ static int check_options(void)
kernel_len = kernel_info.file_size;
- if (combined) {
- if (kernel_info.file_size >
- layout->fw_max_len - sizeof(struct fw_header)) {
- ERR("kernel image is too big");
- return -1;
- }
- } else {
+ if (!combined) {
+ fw_max_len = layout->fw_max_len - reserved_space;
+
if (rootfs_info.file_name == NULL) {
ERR("no rootfs image specified");
return -1;
@@ -509,26 +310,26 @@ static int check_options(void)
if (rootfs_align) {
kernel_len += sizeof(struct fw_header);
- kernel_len = ALIGN(kernel_len, rootfs_align);
+ rootfs_ofs = ALIGN(kernel_len, rootfs_align);
kernel_len -= sizeof(struct fw_header);
- DBG("kernel length aligned to %u", kernel_len);
+ DBG("rootfs offset aligned to 0x%u", rootfs_ofs);
- if (kernel_len + rootfs_info.file_size >
- layout->fw_max_len - sizeof(struct fw_header)) {
- ERR("images are too big");
+ exceed_bytes = kernel_len + rootfs_info.file_size - (fw_max_len - sizeof(struct fw_header));
+ if (exceed_bytes > 0) {
+ ERR("images are too big by %i bytes", exceed_bytes);
return -1;
}
} else {
- if (kernel_info.file_size >
- rootfs_ofs - sizeof(struct fw_header)) {
- ERR("kernel image is too big");
+ exceed_bytes = kernel_info.file_size - (rootfs_ofs - sizeof(struct fw_header));
+ if (exceed_bytes > 0) {
+ ERR("kernel image is too big by %i bytes", exceed_bytes);
return -1;
}
- if (rootfs_info.file_size >
- (layout->fw_max_len - rootfs_ofs)) {
- ERR("rootfs image is too big");
+ exceed_bytes = rootfs_info.file_size - (fw_max_len - rootfs_ofs);
+ if (exceed_bytes > 0) {
+ ERR("rootfs image is too big by %i bytes", exceed_bytes);
return -1;
}
}
@@ -539,227 +340,79 @@ static int check_options(void)
return -1;
}
+ ret = sscanf(fw_ver, "%d.%d.%d", &fw_ver_hi, &fw_ver_mid, &fw_ver_lo);
+ if (ret != 3) {
+ ERR("invalid firmware version '%s'", fw_ver);
+ return -1;
+ }
+
+ if (opt_hdr_ver == 1) {
+ hdr_ver = HEADER_VERSION_V1;
+ } else if (opt_hdr_ver == 2) {
+ hdr_ver = HEADER_VERSION_V2;
+ } else {
+ ERR("invalid header version '%u'", opt_hdr_ver);
+ return -1;
+ }
+
return 0;
}
-static void fill_header(char *buf, int len)
+void fill_header(char *buf, int len)
{
struct fw_header *hdr = (struct fw_header *)buf;
memset(hdr, 0, sizeof(struct fw_header));
- hdr->version = htonl(HEADER_VERSION_V1);
+ hdr->version = htonl(hdr_ver);
strncpy(hdr->vendor_name, vendor, sizeof(hdr->vendor_name));
strncpy(hdr->fw_version, version, sizeof(hdr->fw_version));
hdr->hw_id = htonl(hw_id);
hdr->hw_rev = htonl(hw_rev);
- if (boot_info.file_size == 0)
- memcpy(hdr->md5sum1, md5salt_normal, sizeof(hdr->md5sum1));
- else
- memcpy(hdr->md5sum1, md5salt_boot, sizeof(hdr->md5sum1));
-
hdr->kernel_la = htonl(kernel_la);
hdr->kernel_ep = htonl(kernel_ep);
- hdr->fw_length = htonl(layout->fw_max_len);
hdr->kernel_ofs = htonl(sizeof(struct fw_header));
hdr->kernel_len = htonl(kernel_len);
+
if (!combined) {
+ if (boot_info.file_size == 0)
+ memcpy(hdr->md5sum1, md5salt_normal, sizeof(hdr->md5sum1));
+ else
+ memcpy(hdr->md5sum1, md5salt_boot, sizeof(hdr->md5sum1));
+
+ hdr->fw_length = htonl(layout->fw_max_len);
hdr->rootfs_ofs = htonl(rootfs_ofs);
hdr->rootfs_len = htonl(rootfs_info.file_size);
}
- get_md5(buf, len, hdr->md5sum1);
-}
-
-static int pad_jffs2(char *buf, int currlen)
-{
- int len;
- uint32_t pad_mask;
-
- len = currlen;
- pad_mask = (64 * 1024);
- while ((len < layout->fw_max_len) && (pad_mask != 0)) {
- uint32_t mask;
- int i;
-
- for (i = 10; i < 32; i++) {
- mask = 1 << i;
- if (pad_mask & mask)
- break;
- }
-
- len = ALIGN(len, mask);
-
- for (i = 10; i < 32; i++) {
- mask = 1 << i;
- if ((len & (mask - 1)) == 0)
- pad_mask &= ~mask;
- }
-
- for (i = 0; i < sizeof(jffs2_eof_mark); i++)
- buf[len + i] = jffs2_eof_mark[i];
-
- len += sizeof(jffs2_eof_mark);
- }
-
- return len;
-}
-
-static int write_fw(char *data, int len)
-{
- FILE *f;
- int ret = EXIT_FAILURE;
-
- f = fopen(ofname, "w");
- if (f == NULL) {
- ERRS("could not open \"%s\" for writing", ofname);
- goto out;
- }
-
- errno = 0;
- fwrite(data, len, 1, f);
- if (errno) {
- ERRS("unable to write output file");
- goto out_flush;
- }
-
- DBG("firmware file \"%s\" completed", ofname);
-
- ret = EXIT_SUCCESS;
-
- out_flush:
- fflush(f);
- fclose(f);
- if (ret != EXIT_SUCCESS) {
- unlink(ofname);
+ if (combined && rootfs_ofs_calc) {
+ hdr->rootfs_ofs = htonl(sizeof(struct fw_header) + kernel_len);
}
- out:
- return ret;
-}
-static int build_fw(void)
-{
- int buflen;
- char *buf;
- char *p;
- int ret = EXIT_FAILURE;
- int writelen = 0;
-
- buflen = layout->fw_max_len;
-
- buf = malloc(buflen);
- if (!buf) {
- ERR("no memory for buffer\n");
- goto out;
+ hdr->ver_hi = htons(fw_ver_hi);
+ hdr->ver_mid = htons(fw_ver_mid);
+ hdr->ver_lo = htons(fw_ver_lo);
+
+ if (region) {
+ hdr->region_code = htonl(region->code);
+ snprintf(
+ hdr->region_str1, sizeof(hdr->region_str1), "00000000;%02X%02X%02X%02X;",
+ region->name[0], region->name[1], region->name[2], region->name[3]
+ );
+ snprintf(
+ hdr->region_str2, sizeof(hdr->region_str2), "%02X%02X%02X%02X",
+ region->name[0], region->name[1], region->name[2], region->name[3]
+ );
}
- memset(buf, 0xff, buflen);
- p = buf + sizeof(struct fw_header);
- ret = read_to_buf(&kernel_info, p);
- if (ret)
- goto out_free_buf;
-
- writelen = sizeof(struct fw_header) + kernel_len;
-
- if (!combined) {
- if (rootfs_align)
- p = buf + writelen;
- else
- p = buf + rootfs_ofs;
-
- ret = read_to_buf(&rootfs_info, p);
- if (ret)
- goto out_free_buf;
-
- if (rootfs_align)
- writelen += rootfs_info.file_size;
- else
- writelen = rootfs_ofs + rootfs_info.file_size;
-
- if (add_jffs2_eof)
- writelen = pad_jffs2(buf, writelen);
+ if (endian_swap) {
+ hdr->kernel_la = bswap_32(hdr->kernel_la);
+ hdr->kernel_ep = bswap_32(hdr->kernel_ep);
}
- if (!strip_padding)
- writelen = buflen;
-
- fill_header(buf, writelen);
- ret = write_fw(buf, writelen);
- if (ret)
- goto out_free_buf;
-
- ret = EXIT_SUCCESS;
-
- out_free_buf:
- free(buf);
- out:
- return ret;
-}
-
-/* Helper functions to inspect_fw() representing different output formats */
-static inline void inspect_fw_pstr(char *label, char *str)
-{
- printf("%-23s: %s\n", label, str);
-}
-
-static inline void inspect_fw_phex(char *label, uint32_t val)
-{
- printf("%-23s: 0x%08x\n", label, val);
-}
-
-static inline void inspect_fw_phexpost(char *label,
- uint32_t val, char *post)
-{
- printf("%-23s: 0x%08x (%s)\n", label, val, post);
-}
-
-static inline void inspect_fw_phexdef(char *label,
- uint32_t val, uint32_t defval)
-{
- printf("%-23s: 0x%08x ", label, val);
-
- if (val == defval)
- printf("(== OpenWrt default)\n");
- else
- printf("(OpenWrt default: 0x%08x)\n", defval);
-}
-
-static inline void inspect_fw_phexexp(char *label,
- uint32_t val, uint32_t expval)
-{
- printf("%-23s: 0x%08x ", label, val);
-
- if (val == expval)
- printf("(ok)\n");
- else
- printf("(expected: 0x%08x)\n", expval);
-}
-
-static inline void inspect_fw_phexdec(char *label, uint32_t val)
-{
- printf("%-23s: 0x%08x / %8u bytes\n", label, val, val);
-}
-
-static inline void inspect_fw_phexdecdef(char *label,
- uint32_t val, uint32_t defval)
-{
- printf("%-23s: 0x%08x / %8u bytes ", label, val, val);
-
- if (val == defval)
- printf("(== OpenWrt default)\n");
- else
- printf("(OpenWrt default: 0x%08x)\n", defval);
-}
-
-static inline void inspect_fw_pmd5sum(char *label, uint8_t *val, char *text)
-{
- int i;
-
- printf("%-23s:", label);
- for (i=0; i<MD5SUM_LEN; i++)
- printf(" %02x", val[i]);
- printf(" %s\n", text);
+ if (!combined)
+ get_md5(buf, len, hdr->md5sum1);
}
static int inspect_fw(void)
@@ -767,7 +420,6 @@ static int inspect_fw(void)
char *buf;
struct fw_header *hdr;
uint8_t md5sum[MD5SUM_LEN];
- struct board_info *board;
int ret = EXIT_FAILURE;
buf = malloc(inspect_info.file_size);
@@ -784,16 +436,14 @@ static int inspect_fw(void)
inspect_fw_pstr("File name", inspect_info.file_name);
inspect_fw_phexdec("File size", inspect_info.file_size);
- if (ntohl(hdr->version) != HEADER_VERSION_V1) {
- ERR("file does not seem to have V1 header!\n");
+ if ((ntohl(hdr->version) != HEADER_VERSION_V1) &&
+ (ntohl(hdr->version) != HEADER_VERSION_V2)) {
+ ERR("file does not seem to have V1/V2 header!\n");
goto out_free_buf;
}
inspect_fw_phexdec("Version 1 Header size", sizeof(struct fw_header));
- if (ntohl(hdr->unk1) != 0)
- inspect_fw_phexdec("Unknown value 1", hdr->unk1);
-
memcpy(md5sum, hdr->md5sum1, sizeof(md5sum));
if (ntohl(hdr->boot_len) == 0)
memcpy(hdr->md5sum1, md5salt_normal, sizeof(md5sum));
@@ -818,19 +468,9 @@ static int inspect_fw(void)
inspect_fw_pstr("Vendor name", hdr->vendor_name);
inspect_fw_pstr("Firmware version", hdr->fw_version);
- board = find_board_by_hwid(ntohl(hdr->hw_id));
- if (board) {
- layout = find_layout(board->layout_id);
- inspect_fw_phexpost("Hardware ID",
- ntohl(hdr->hw_id), board->id);
- inspect_fw_phexexp("Hardware Revision",
- ntohl(hdr->hw_rev), board->hw_rev);
- } else {
- inspect_fw_phexpost("Hardware ID",
- ntohl(hdr->hw_id), "unknown");
- inspect_fw_phex("Hardware Revision",
- ntohl(hdr->hw_rev));
- }
+ inspect_fw_phex("Hardware ID", ntohl(hdr->hw_id));
+ inspect_fw_phex("Hardware Revision", ntohl(hdr->hw_rev));
+ inspect_fw_phex("Region code", ntohl(hdr->region_code));
printf("\n");
@@ -838,24 +478,12 @@ static int inspect_fw(void)
ntohl(hdr->kernel_ofs));
inspect_fw_phexdec("Kernel data length",
ntohl(hdr->kernel_len));
- if (board) {
- inspect_fw_phexdef("Kernel load address",
- ntohl(hdr->kernel_la),
- layout ? layout->kernel_la : 0xffffffff);
- inspect_fw_phexdef("Kernel entry point",
- ntohl(hdr->kernel_ep),
- layout ? layout->kernel_ep : 0xffffffff);
- inspect_fw_phexdecdef("Rootfs data offset",
- ntohl(hdr->rootfs_ofs),
- layout ? layout->rootfs_ofs : 0xffffffff);
- } else {
- inspect_fw_phex("Kernel load address",
- ntohl(hdr->kernel_la));
- inspect_fw_phex("Kernel entry point",
- ntohl(hdr->kernel_ep));
- inspect_fw_phexdec("Rootfs data offset",
- ntohl(hdr->rootfs_ofs));
- }
+ inspect_fw_phex("Kernel load address",
+ ntohl(hdr->kernel_la));
+ inspect_fw_phex("Kernel entry point",
+ ntohl(hdr->kernel_ep));
+ inspect_fw_phexdec("Rootfs data offset",
+ ntohl(hdr->rootfs_ofs));
inspect_fw_phexdec("Rootfs data length",
ntohl(hdr->rootfs_len));
inspect_fw_phexdec("Boot loader data offset",
@@ -911,16 +539,13 @@ static int inspect_fw(void)
int main(int argc, char *argv[])
{
int ret = EXIT_FAILURE;
- int err;
-
- FILE *outfile;
progname = basename(argv[0]);
while ( 1 ) {
int c;
- c = getopt(argc, argv, "a:B:H:E:F:L:V:N:W:ci:k:r:R:o:xhsj");
+ c = getopt(argc, argv, "a:H:E:F:L:m:V:N:W:C:ci:k:r:R:o:OxX:ehsjv:");
if (c == -1)
break;
@@ -928,9 +553,6 @@ int main(int argc, char *argv[])
case 'a':
sscanf(optarg, "0x%x", &rootfs_align);
break;
- case 'B':
- board_id = optarg;
- break;
case 'H':
opt_hw_id = optarg;
break;
@@ -943,12 +565,21 @@ int main(int argc, char *argv[])
case 'W':
opt_hw_rev = optarg;
break;
+ case 'C':
+ country = optarg;
+ break;
case 'L':
sscanf(optarg, "0x%x", &kernel_la);
break;
+ case 'm':
+ sscanf(optarg, "%u", &opt_hdr_ver);
+ break;
case 'V':
version = optarg;
break;
+ case 'v':
+ fw_ver = optarg;
+ break;
case 'N':
vendor = optarg;
break;
@@ -967,6 +598,9 @@ int main(int argc, char *argv[])
case 'o':
ofname = optarg;
break;
+ case 'O':
+ rootfs_ofs_calc = 1;
+ break;
case 's':
strip_padding = 1;
break;
@@ -979,9 +613,15 @@ int main(int argc, char *argv[])
case 'x':
extract = 1;
break;
+ case 'e':
+ endian_swap = true;
+ break;
case 'h':
usage(EXIT_SUCCESS);
break;
+ case 'X':
+ sscanf(optarg, "0x%x", &reserved_space);
+ break;
default:
usage(EXIT_FAILURE);
break;
@@ -993,11 +633,10 @@ int main(int argc, char *argv[])
goto out;
if (!inspect_info.file_name)
- ret = build_fw();
+ ret = build_fw(sizeof(struct fw_header));
else
ret = inspect_fw();
out:
return ret;
}
-
diff --git a/tools/firmware-utils/src/mktplinkfw2.c b/tools/firmware-utils/src/mktplinkfw2.c
new file mode 100644
index 00000000000..dead49e7af8
--- /dev/null
+++ b/tools/firmware-utils/src/mktplinkfw2.c
@@ -0,0 +1,628 @@
+/*
+ * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This tool was based on:
+ * TP-Link WR941 V2 firmware checksum fixing tool.
+ * Copyright (C) 2008,2009 Wang Jian <lark@linux.net.cn>
+ *
+ * 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 <stdbool.h>
+#include <endian.h>
+#include <sys/stat.h>
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#include "md5.h"
+#include "mktplinkfw-lib.h"
+
+struct fw_header {
+ uint32_t version; /* 0x00: header version */
+ char fw_version[48]; /* 0x04: fw version string */
+ uint32_t hw_id; /* 0x34: hardware id */
+ uint32_t hw_rev; /* 0x38: FIXME: hardware revision? */
+ uint32_t hw_ver_add; /* 0x3c: additional hardware version */
+ uint8_t md5sum1[MD5SUM_LEN]; /* 0x40 */
+ uint32_t unk2; /* 0x50: 0x00000000 */
+ uint8_t md5sum2[MD5SUM_LEN]; /* 0x54 */
+ uint32_t unk3; /* 0x64: 0xffffffff */
+
+ uint32_t kernel_la; /* 0x68: kernel load address */
+ uint32_t kernel_ep; /* 0x6c: kernel entry point */
+ uint32_t fw_length; /* 0x70: total length of the image */
+ uint32_t kernel_ofs; /* 0x74: kernel data offset */
+ uint32_t kernel_len; /* 0x78: kernel data length */
+ uint32_t rootfs_ofs; /* 0x7c: rootfs data offset */
+ uint32_t rootfs_len; /* 0x80: rootfs data length */
+ uint32_t boot_ofs; /* 0x84: bootloader offset */
+ uint32_t boot_len; /* 0x88: bootloader length */
+ uint16_t unk4; /* 0x8c: 0x55aa */
+ uint8_t sver_hi; /* 0x8e */
+ uint8_t sver_lo; /* 0x8f */
+ uint8_t unk5; /* 0x90: magic: 0xa5 */
+ uint8_t ver_hi; /* 0x91 */
+ uint8_t ver_mid; /* 0x92 */
+ uint8_t ver_lo; /* 0x93 */
+ uint8_t pad[364];
+} __attribute__ ((packed));
+
+#define FLAG_LE_KERNEL_LA_EP 0x00000001 /* Little-endian used for kernel load address & entry point */
+
+struct board_info {
+ char *id;
+ uint32_t hw_id;
+ uint32_t hw_rev;
+ uint32_t hw_ver_add;
+ char *layout_id;
+ uint32_t hdr_ver;
+ uint32_t flags;
+};
+
+/*
+ * Globals
+ */
+char *ofname;
+char *progname;
+static char *vendor = "TP-LINK Technologies";
+static char *version = "ver. 1.0";
+static char *fw_ver = "0.0.0";
+static char *sver = "1.0";
+static uint32_t hdr_ver = 2;
+
+static struct board_info custom_board;
+
+static struct board_info *board;
+static char *layout_id;
+struct flash_layout *layout;
+static char *opt_hw_id;
+static char *opt_hw_rev;
+static char *opt_hw_ver_add;
+static int fw_ver_lo;
+static int fw_ver_mid;
+static int fw_ver_hi;
+static int sver_lo;
+static int sver_hi;
+struct file_info kernel_info;
+static uint32_t kernel_la = 0;
+static uint32_t kernel_ep = 0;
+uint32_t kernel_len = 0;
+struct file_info rootfs_info;
+uint32_t rootfs_ofs = 0;
+uint32_t rootfs_align;
+static struct file_info boot_info;
+int combined;
+int strip_padding;
+int add_jffs2_eof;
+
+static struct file_info inspect_info;
+static int extract = 0;
+
+char md5salt_normal[MD5SUM_LEN] = {
+ 0xdc, 0xd7, 0x3a, 0xa5, 0xc3, 0x95, 0x98, 0xfb,
+ 0xdc, 0xf9, 0xe7, 0xf4, 0x0e, 0xae, 0x47, 0x37,
+};
+
+char md5salt_boot[MD5SUM_LEN] = {
+ 0x8c, 0xef, 0x33, 0x5f, 0xd5, 0xc5, 0xce, 0xfa,
+ 0xac, 0x9c, 0x28, 0xda, 0xb2, 0xe9, 0x0f, 0x42,
+};
+
+static struct flash_layout layouts[] = {
+ {
+ .id = "4Mmtk",
+ .fw_max_len = 0x3d0000,
+ .kernel_la = 0x80000000,
+ .kernel_ep = 0x80000000,
+ .rootfs_ofs = 0x140000,
+ }, {
+ .id = "8Mltq",
+ .fw_max_len = 0x7a0000,
+ .kernel_la = 0x80002000,
+ .kernel_ep = 0x80002000,
+ .rootfs_ofs = 0x140000,
+ }, {
+ .id = "16Mltq",
+ .fw_max_len = 0xf90000,
+ .kernel_la = 0x80002000,
+ .kernel_ep = 0x800061b0,
+ .rootfs_ofs = 0x140000,
+ }, {
+ .id = "8Mmtk",
+ .fw_max_len = 0x7a0000,
+ .kernel_la = 0x80000000,
+ .kernel_ep = 0x80000000,
+ .rootfs_ofs = 0x140000,
+ }, {
+ .id = "8MLmtk",
+ .fw_max_len = 0x7b0000,
+ .kernel_la = 0x80000000,
+ .kernel_ep = 0x80000000,
+ .rootfs_ofs = 0x140000,
+ }, {
+ /* terminating entry */
+ }
+};
+
+static 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"
+" -c use combined kernel image\n"
+" -e swap endianness in kernel load address and entry point\n"
+" -E <ep> overwrite kernel entry point with <ep> (hexval prefixed with 0x)\n"
+" -L <la> overwrite kernel load address with <la> (hexval prefixed with 0x)\n"
+" -H <hwid> use hardware id specified with <hwid>\n"
+" -W <hwrev> use hardware revision specified with <hwrev>\n"
+" -w <hwveradd> use additional hardware version specified with <hwveradd>\n"
+" -F <id> use flash layout specified with <id>\n"
+" -k <file> read kernel image from the file <file>\n"
+" -r <file> read rootfs image from the file <file>\n"
+" -a <align> align the rootfs start on an <align> bytes boundary\n"
+" -R <offset> overwrite rootfs offset with <offset> (hexval prefixed with 0x)\n"
+" -o <file> write output to the file <file>\n"
+" -s strip padding from the end of the image\n"
+" -j add jffs2 end-of-filesystem markers\n"
+" -N <vendor> set image vendor to <vendor>\n"
+" -T <version> set header version to <version>\n"
+" -V <version> set image version to <version>\n"
+" -v <version> set firmware version to <version>\n"
+" -y <version> set secondary version to <version>\n"
+" -i <file> inspect given firmware file <file>\n"
+" -x extract kernel and rootfs while inspecting (requires -i)\n"
+" -h show this screen\n"
+ );
+
+ exit(status);
+}
+
+static int check_options(void)
+{
+ int ret;
+
+ if (inspect_info.file_name) {
+ ret = get_file_stat(&inspect_info);
+ if (ret)
+ return ret;
+
+ return 0;
+ } else if (extract) {
+ ERR("no firmware for inspection specified");
+ return -1;
+ }
+
+ if (opt_hw_id == NULL) {
+ ERR("hardware id must be specified");
+ return -1;
+ }
+
+ board = &custom_board;
+
+ if (layout_id == NULL) {
+ ERR("flash layout is not specified");
+ return -1;
+ }
+
+ board->hw_id = strtoul(opt_hw_id, NULL, 0);
+
+ board->hw_rev = 1;
+ board->hw_ver_add = 0;
+
+ if (opt_hw_rev)
+ board->hw_rev = strtoul(opt_hw_rev, NULL, 0);
+ if (opt_hw_ver_add)
+ board->hw_ver_add = strtoul(opt_hw_ver_add, NULL, 0);
+
+ layout = find_layout(layouts, layout_id);
+ if (layout == NULL) {
+ ERR("unknown flash layout \"%s\"", layout_id);
+ return -1;
+ }
+
+ if (!kernel_la)
+ kernel_la = layout->kernel_la;
+ if (!kernel_ep)
+ kernel_ep = layout->kernel_ep;
+ if (!rootfs_ofs)
+ rootfs_ofs = layout->rootfs_ofs;
+
+ if (kernel_info.file_name == NULL) {
+ ERR("no kernel image specified");
+ return -1;
+ }
+
+ ret = get_file_stat(&kernel_info);
+ if (ret)
+ return ret;
+
+ kernel_len = kernel_info.file_size;
+
+ if (combined) {
+ if (kernel_info.file_size >
+ layout->fw_max_len - sizeof(struct fw_header)) {
+ ERR("kernel image is too big");
+ return -1;
+ }
+ } else {
+ if (rootfs_info.file_name == NULL) {
+ ERR("no rootfs image specified");
+ return -1;
+ }
+
+ ret = get_file_stat(&rootfs_info);
+ if (ret)
+ return ret;
+
+ if (rootfs_align) {
+ kernel_len += sizeof(struct fw_header);
+ rootfs_ofs = ALIGN(kernel_len, rootfs_align);
+ kernel_len -= sizeof(struct fw_header);
+
+ DBG("rootfs offset aligned to 0x%u", rootfs_ofs);
+
+ if (kernel_len + rootfs_info.file_size >
+ layout->fw_max_len - sizeof(struct fw_header)) {
+ ERR("images are too big");
+ return -1;
+ }
+ } else {
+ if (kernel_info.file_size >
+ rootfs_ofs - sizeof(struct fw_header)) {
+ ERR("kernel image is too big");
+ return -1;
+ }
+
+ if (rootfs_info.file_size >
+ (layout->fw_max_len - rootfs_ofs)) {
+ ERR("rootfs image is too big");
+ return -1;
+ }
+ }
+ }
+
+ if (ofname == NULL) {
+ ERR("no output file specified");
+ return -1;
+ }
+
+ ret = sscanf(fw_ver, "%d.%d.%d", &fw_ver_hi, &fw_ver_mid, &fw_ver_lo);
+ if (ret != 3) {
+ ERR("invalid firmware version '%s'", fw_ver);
+ return -1;
+ }
+
+ ret = sscanf(sver, "%d.%d", &sver_hi, &sver_lo);
+ if (ret != 2) {
+ ERR("invalid secondary version '%s'", sver);
+ return -1;
+ }
+
+ return 0;
+}
+
+void fill_header(char *buf, int len)
+{
+ struct fw_header *hdr = (struct fw_header *)buf;
+ unsigned ver_len;
+
+ memset(hdr, '\xff', sizeof(struct fw_header));
+
+ hdr->version = htonl(bswap_32(hdr_ver));
+ ver_len = strlen(version);
+ if (ver_len > (sizeof(hdr->fw_version) - 1))
+ ver_len = sizeof(hdr->fw_version) - 1;
+
+ memcpy(hdr->fw_version, version, ver_len);
+ hdr->fw_version[ver_len] = 0;
+
+ hdr->hw_id = htonl(board->hw_id);
+ hdr->hw_rev = htonl(board->hw_rev);
+ hdr->hw_ver_add = htonl(board->hw_ver_add);
+
+ if (boot_info.file_size == 0) {
+ memcpy(hdr->md5sum1, md5salt_normal, sizeof(hdr->md5sum1));
+ hdr->boot_ofs = htonl(0);
+ hdr->boot_len = htonl(0);
+ } else {
+ memcpy(hdr->md5sum1, md5salt_boot, sizeof(hdr->md5sum1));
+ hdr->boot_ofs = htonl(rootfs_ofs + rootfs_info.file_size);
+ hdr->boot_len = htonl(rootfs_info.file_size);
+ }
+
+ hdr->kernel_la = htonl(kernel_la);
+ hdr->kernel_ep = htonl(kernel_ep);
+ hdr->fw_length = htonl(layout->fw_max_len);
+ hdr->kernel_ofs = htonl(sizeof(struct fw_header));
+ hdr->kernel_len = htonl(kernel_len);
+ if (!combined) {
+ hdr->rootfs_ofs = htonl(rootfs_ofs);
+ hdr->rootfs_len = htonl(rootfs_info.file_size);
+ }
+
+ hdr->boot_ofs = htonl(0);
+ hdr->boot_len = htonl(boot_info.file_size);
+
+ hdr->unk2 = htonl(0);
+ hdr->unk3 = htonl(0xffffffff);
+ hdr->unk4 = htons(0x55aa);
+ hdr->unk5 = 0xa5;
+
+ hdr->sver_hi = sver_hi;
+ hdr->sver_lo = sver_lo;
+
+ hdr->ver_hi = fw_ver_hi;
+ hdr->ver_mid = fw_ver_mid;
+ hdr->ver_lo = fw_ver_lo;
+
+ if (board->flags & FLAG_LE_KERNEL_LA_EP) {
+ hdr->kernel_la = bswap_32(hdr->kernel_la);
+ hdr->kernel_ep = bswap_32(hdr->kernel_ep);
+ }
+
+ get_md5(buf, len, hdr->md5sum1);
+}
+
+static int inspect_fw(void)
+{
+ char *buf;
+ struct fw_header *hdr;
+ uint8_t md5sum[MD5SUM_LEN];
+ struct board_info *board;
+ int ret = EXIT_FAILURE;
+
+ buf = malloc(inspect_info.file_size);
+ if (!buf) {
+ ERR("no memory for buffer!\n");
+ goto out;
+ }
+
+ ret = read_to_buf(&inspect_info, buf);
+ if (ret)
+ goto out_free_buf;
+ hdr = (struct fw_header *)buf;
+
+ board = &custom_board;
+
+ if (board->flags & FLAG_LE_KERNEL_LA_EP) {
+ hdr->kernel_la = bswap_32(hdr->kernel_la);
+ hdr->kernel_ep = bswap_32(hdr->kernel_ep);
+ }
+
+ inspect_fw_pstr("File name", inspect_info.file_name);
+ inspect_fw_phexdec("File size", inspect_info.file_size);
+
+ switch(bswap_32(ntohl(hdr->version))) {
+ case 2:
+ case 3:
+ break;
+ default:
+ ERR("file does not seem to have V2/V3 header!\n");
+ goto out_free_buf;
+ }
+
+ inspect_fw_phexdec("Version 2 Header size", sizeof(struct fw_header));
+
+ memcpy(md5sum, hdr->md5sum1, sizeof(md5sum));
+ if (ntohl(hdr->boot_len) == 0)
+ memcpy(hdr->md5sum1, md5salt_normal, sizeof(md5sum));
+ else
+ memcpy(hdr->md5sum1, md5salt_boot, sizeof(md5sum));
+ get_md5(buf, inspect_info.file_size, hdr->md5sum1);
+
+ if (memcmp(md5sum, hdr->md5sum1, sizeof(md5sum))) {
+ inspect_fw_pmd5sum("Header MD5Sum1", md5sum, "(*ERROR*)");
+ inspect_fw_pmd5sum(" --> expected", hdr->md5sum1, "");
+ } else {
+ inspect_fw_pmd5sum("Header MD5Sum1", md5sum, "(ok)");
+ }
+ if (ntohl(hdr->unk2) != 0)
+ inspect_fw_phexdec("Unknown value 2", hdr->unk2);
+ inspect_fw_pmd5sum("Header MD5Sum2", hdr->md5sum2,
+ "(purpose yet unknown, unchecked here)");
+
+ if (ntohl(hdr->unk3) != 0xffffffff)
+ inspect_fw_phexdec("Unknown value 3", hdr->unk3);
+
+ if (ntohs(hdr->unk4) != 0x55aa)
+ inspect_fw_phexdec("Unknown value 4", hdr->unk4);
+
+ if (hdr->unk5 != 0xa5)
+ inspect_fw_phexdec("Unknown value 5", hdr->unk5);
+
+ printf("\n");
+
+ inspect_fw_pstr("Firmware version", hdr->fw_version);
+ inspect_fw_phex("Hardware ID", ntohl(hdr->hw_id));
+ inspect_fw_phex("Hardware Revision",
+ ntohl(hdr->hw_rev));
+ inspect_fw_phex("Additional HW Version",
+ ntohl(hdr->hw_ver_add));
+
+ printf("%-23s: %d.%d.%d-%d.%d\n", "Software version",
+ hdr->ver_hi, hdr->ver_mid, hdr->ver_lo,
+ hdr->sver_hi, hdr->sver_lo);
+
+ printf("\n");
+
+ inspect_fw_phexdec("Kernel data offset",
+ ntohl(hdr->kernel_ofs));
+ inspect_fw_phexdec("Kernel data length",
+ ntohl(hdr->kernel_len));
+ inspect_fw_phex("Kernel load address",
+ ntohl(hdr->kernel_la));
+ inspect_fw_phex("Kernel entry point",
+ ntohl(hdr->kernel_ep));
+ inspect_fw_phexdec("Rootfs data offset",
+ ntohl(hdr->rootfs_ofs));
+ inspect_fw_phexdec("Rootfs data length",
+ ntohl(hdr->rootfs_len));
+ inspect_fw_phexdec("Boot loader data offset",
+ ntohl(hdr->boot_ofs));
+ inspect_fw_phexdec("Boot loader data length",
+ ntohl(hdr->boot_len));
+ inspect_fw_phexdec("Total firmware length",
+ ntohl(hdr->fw_length));
+
+ if (extract) {
+ FILE *fp;
+ char *filename;
+
+ printf("\n");
+
+ filename = malloc(strlen(inspect_info.file_name) + 8);
+ sprintf(filename, "%s-kernel", inspect_info.file_name);
+ printf("Extracting kernel to \"%s\"...\n", filename);
+ fp = fopen(filename, "w");
+ if (fp) {
+ if (!fwrite(buf + ntohl(hdr->kernel_ofs),
+ ntohl(hdr->kernel_len), 1, fp)) {
+ ERR("error in fwrite(): %s", strerror(errno));
+ }
+ fclose(fp);
+ } else {
+ ERR("error in fopen(): %s", strerror(errno));
+ }
+ free(filename);
+
+ filename = malloc(strlen(inspect_info.file_name) + 8);
+ sprintf(filename, "%s-rootfs", inspect_info.file_name);
+ printf("Extracting rootfs to \"%s\"...\n", filename);
+ fp = fopen(filename, "w");
+ if (fp) {
+ if (!fwrite(buf + ntohl(hdr->rootfs_ofs),
+ ntohl(hdr->rootfs_len), 1, fp)) {
+ ERR("error in fwrite(): %s", strerror(errno));
+ }
+ fclose(fp);
+ } else {
+ ERR("error in fopen(): %s", strerror(errno));
+ }
+ free(filename);
+ }
+
+ out_free_buf:
+ free(buf);
+ out:
+ return ret;
+}
+
+int main(int argc, char *argv[])
+{
+ int ret = EXIT_FAILURE;
+
+ progname = basename(argv[0]);
+
+ while ( 1 ) {
+ int c;
+
+ c = getopt(argc, argv, "a:H:E:F:L:V:N:W:w:ci:k:r:R:o:xhsjv:y:T:e");
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'a':
+ sscanf(optarg, "0x%x", &rootfs_align);
+ break;
+ case 'H':
+ opt_hw_id = optarg;
+ break;
+ case 'E':
+ sscanf(optarg, "0x%x", &kernel_ep);
+ break;
+ case 'F':
+ layout_id = optarg;
+ break;
+ case 'W':
+ opt_hw_rev = optarg;
+ break;
+ case 'w':
+ opt_hw_ver_add = optarg;
+ break;
+ case 'L':
+ sscanf(optarg, "0x%x", &kernel_la);
+ break;
+ case 'V':
+ version = optarg;
+ break;
+ case 'v':
+ fw_ver = optarg;
+ break;
+ case 'y':
+ sver = optarg;
+ break;
+ case 'N':
+ vendor = optarg;
+ break;
+ case 'c':
+ combined++;
+ break;
+ case 'k':
+ kernel_info.file_name = optarg;
+ break;
+ case 'r':
+ rootfs_info.file_name = optarg;
+ break;
+ case 'R':
+ sscanf(optarg, "0x%x", &rootfs_ofs);
+ break;
+ case 'o':
+ ofname = optarg;
+ break;
+ case 's':
+ strip_padding = 1;
+ break;
+ case 'i':
+ inspect_info.file_name = optarg;
+ break;
+ case 'j':
+ add_jffs2_eof = 1;
+ break;
+ case 'x':
+ extract = 1;
+ break;
+ case 'T':
+ hdr_ver = atoi(optarg);
+ break;
+ case 'e':
+ custom_board.flags = FLAG_LE_KERNEL_LA_EP;
+ break;
+ case 'h':
+ usage(EXIT_SUCCESS);
+ break;
+ default:
+ usage(EXIT_FAILURE);
+ break;
+ }
+ }
+
+ ret = check_options();
+ if (ret)
+ goto out;
+
+ if (!inspect_info.file_name)
+ ret = build_fw(sizeof(struct fw_header));
+ else
+ ret = inspect_fw();
+
+ out:
+ return ret;
+}
+
diff --git a/tools/firmware-utils/src/mkwrggimg.c b/tools/firmware-utils/src/mkwrggimg.c
new file mode 100644
index 00000000000..9995b9a13d8
--- /dev/null
+++ b/tools/firmware-utils/src/mkwrggimg.c
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2016 Stijn Tintel <stijn@linux-ipv6.be>
+ *
+ * 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.
+ *
+ */
+
+#define _ANSI_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <libgen.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include "md5.h"
+
+#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 WRGG03_MAGIC 0x20080321
+
+struct wrgg03_header {
+ char signature[32];
+ uint32_t magic1;
+ uint32_t magic2;
+ char version[16];
+ char model[16];
+ uint32_t flag[2];
+ uint32_t reserve[2];
+ char buildno[16];
+ uint32_t size;
+ uint32_t offset;
+ char devname[32];
+ char digest[16];
+} __attribute__ ((packed));
+
+static char *progname;
+static char *ifname;
+static char *ofname;
+static char *signature;
+static char *version;
+static char *model;
+static uint32_t flag = 0;
+static uint32_t reserve = 0;
+static char *buildno;
+static uint32_t offset;
+static char *devname;
+static int big_endian;
+
+void usage(int status)
+{
+ FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+
+ fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+ fprintf(stream,
+"\n"
+"Options:\n"
+" -b create image in big endian format\n"
+" -B <buildno> build number\n"
+" -i <file> read input from the file <file>\n"
+" -d <name> set device name to <name>\n"
+" -m <model> model name\n"
+" -o <file> write output to the file <file>\n"
+" -O <offset> set offset to <offset>\n"
+" -s <sig> set image signature to <sig>\n"
+" -h show this screen\n"
+ );
+
+ exit(status);
+}
+
+static void put_u32(void *data, uint32_t val, int swap)
+{
+ unsigned char *p = data;
+
+ if (swap) {
+ p[0] = (val >> 24) & 0xff;
+ p[1] = (val >> 16) & 0xff;
+ p[2] = (val >> 8) & 0xff;
+ p[3] = val & 0xff;
+ } else {
+ p[3] = (val >> 24) & 0xff;
+ p[2] = (val >> 16) & 0xff;
+ p[1] = (val >> 8) & 0xff;
+ p[0] = val & 0xff;
+ }
+}
+
+static void get_digest(struct wrgg03_header *header, char *data, int size)
+{
+ MD5_CTX ctx;
+
+ MD5_Init(&ctx);
+
+ MD5_Update(&ctx, (char *)&header->offset, sizeof(header->offset));
+ MD5_Update(&ctx, (char *)&header->devname, sizeof(header->devname));
+ MD5_Update(&ctx, data, size);
+
+ MD5_Final(header->digest, &ctx);
+}
+
+int main(int argc, char *argv[])
+{
+ struct wrgg03_header *header;
+ char *buf;
+ struct stat st;
+ int buflen;
+ int err;
+ int res = EXIT_FAILURE;
+
+ FILE *outfile, *infile;
+
+ progname = basename(argv[0]);
+
+ while ( 1 ) {
+ int c;
+
+ c = getopt(argc, argv, "bd:i:m:o:s:v:B:O:h");
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'b':
+ big_endian = 1;
+ break;
+ case 'B':
+ buildno = optarg;
+ break;
+ case 'd':
+ devname = optarg;
+ break;
+ case 'i':
+ ifname = optarg;
+ break;
+ case 'm':
+ model = optarg;
+ break;
+ case 'o':
+ ofname = optarg;
+ break;
+ case 's':
+ signature = optarg;
+ break;
+ case 'v':
+ version = optarg;
+ break;
+ case 'O':
+ offset = strtoul(optarg, NULL, 0);
+ break;
+ case 'h':
+ usage(EXIT_SUCCESS);
+ break;
+
+ default:
+ usage(EXIT_FAILURE);
+ break;
+ }
+ }
+
+ if (signature == NULL) {
+ ERR("no signature specified");
+ goto err;
+ }
+
+ if (ifname == NULL) {
+ ERR("no input file specified");
+ goto err;
+ }
+
+ if (ofname == NULL) {
+ ERR("no output file specified");
+ goto err;
+ }
+
+ if (devname == NULL) {
+ ERR("no device name specified");
+ goto err;
+ }
+
+ if (model == NULL) {
+ ERR("no model name specified");
+ goto err;
+ }
+
+ if (buildno == NULL) {
+ ERR("no build number specified");
+ goto err;
+ }
+
+ if (version == NULL) {
+ ERR("no version specified");
+ goto err;
+ }
+
+ err = stat(ifname, &st);
+ if (err){
+ ERRS("stat failed on %s", ifname);
+ goto err;
+ }
+
+ buflen = st.st_size + sizeof(struct wrgg03_header);
+ buf = malloc(buflen);
+ if (!buf) {
+ ERR("no memory for buffer\n");
+ goto err;
+ }
+
+ infile = fopen(ifname, "r");
+ if (infile == NULL) {
+ ERRS("could not open \"%s\" for reading", ifname);
+ goto err_free;
+ }
+
+ errno = 0;
+ fread(buf + sizeof(struct wrgg03_header), st.st_size, 1, infile);
+ if (errno != 0) {
+ ERRS("unable to read from file %s", ifname);
+ goto close_in;
+ }
+
+ header = (struct wrgg03_header *) buf;
+ memset(header, '\0', sizeof(struct wrgg03_header));
+
+ strncpy(header->signature, signature, sizeof(header->signature));
+ put_u32(&header->magic1, WRGG03_MAGIC, 0);
+ put_u32(&header->magic2, WRGG03_MAGIC, 0);
+ strncpy(header->version, version, sizeof(header->version));
+ strncpy(header->model, model, sizeof(header->model));
+ put_u32(&header->flag, flag, 0);
+ put_u32(&header->reserve, reserve, 0);
+ strncpy(header->buildno, buildno, sizeof(header->buildno));
+ put_u32(&header->size, st.st_size, big_endian);
+ put_u32(&header->offset, offset, big_endian);
+ strncpy(header->devname, devname, sizeof(header->devname));
+
+ get_digest(header, buf + sizeof(struct wrgg03_header), st.st_size);
+
+ outfile = fopen(ofname, "w");
+ if (outfile == NULL) {
+ ERRS("could not open \"%s\" for writing", ofname);
+ goto close_in;
+ }
+
+ errno = 0;
+ fwrite(buf, buflen, 1, outfile);
+ if (errno) {
+ ERRS("unable to write to file %s", ofname);
+ goto close_out;
+ }
+
+ fflush(outfile);
+
+ res = EXIT_SUCCESS;
+
+close_out:
+ fclose(outfile);
+ if (res != EXIT_SUCCESS)
+ unlink(ofname);
+close_in:
+ fclose(infile);
+err_free:
+ free(buf);
+err:
+ return res;
+}
diff --git a/tools/firmware-utils/src/mkzcfw.c b/tools/firmware-utils/src/mkzcfw.c
index 7674e706c99..2326f1ff5c5 100644
--- a/tools/firmware-utils/src/mkzcfw.c
+++ b/tools/firmware-utils/src/mkzcfw.c
@@ -100,7 +100,7 @@ static struct board_info boards[] = {
#define ERRS(fmt, ...) do { \
int save = errno; \
fflush(0); \
- fprintf(stderr, "[%s] *** error: " fmt "\n", \
+ fprintf(stderr, "[%s] *** error: " fmt ": %s\n", \
progname, ## __VA_ARGS__, strerror(save)); \
} while (0)
diff --git a/tools/firmware-utils/src/mkzynfw.c b/tools/firmware-utils/src/mkzynfw.c
index 36c176f4325..ccbabfe7f20 100644
--- a/tools/firmware-utils/src/mkzynfw.c
+++ b/tools/firmware-utils/src/mkzynfw.c
@@ -27,6 +27,7 @@
#if defined(__CYGWIN__)
# include <byteswap.h>
#endif
+#include <inttypes.h>
#include "zynos.h"
@@ -687,7 +688,7 @@ write_out_file(FILE *outfile, char *name, size_t len, struct csum_state *css)
FILE *f;
int res;
- DBG(2, "writing out file, name=%s, len=%d",
+ DBG(2, "writing out file, name=%s, len=%zu",
name, len);
errno = 0;
@@ -988,7 +989,7 @@ calc_block_offsets(int type, uint32_t *offset)
uint32_t avail;
int i, res;
- DBG(1,"calculating block offsets, starting with %lu",
+ DBG(1,"calculating block offsets, starting with %" PRIu32,
*offset);
res = 0;
diff --git a/tools/firmware-utils/src/nand_ecc.c b/tools/firmware-utils/src/nand_ecc.c
index b1e9305158c..58fb6ce0db4 100644
--- a/tools/firmware-utils/src/nand_ecc.c
+++ b/tools/firmware-utils/src/nand_ecc.c
@@ -2,7 +2,7 @@
* calculate ecc code for nand flash
*
* Copyright (C) 2008 yajin <yajin@vm-kernel.org>
- * Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2009 Felix Fietkau <nbd@nbd.name>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
diff --git a/tools/firmware-utils/src/osbridge-crc.c b/tools/firmware-utils/src/osbridge-crc.c
index f2e3920a48c..5fd236a0746 100644
--- a/tools/firmware-utils/src/osbridge-crc.c
+++ b/tools/firmware-utils/src/osbridge-crc.c
@@ -51,7 +51,7 @@ static char *ofname;
#define ERRS(fmt, ...) do { \
int save = errno; \
fflush(0); \
- fprintf(stderr, "[%s] *** error: " fmt "\n", \
+ fprintf(stderr, "[%s] *** error: " fmt ": %s\n", \
progname, ## __VA_ARGS__, strerror(save)); \
} while (0)
diff --git a/tools/firmware-utils/src/oseama.c b/tools/firmware-utils/src/oseama.c
new file mode 100644
index 00000000000..4434b11162e
--- /dev/null
+++ b/tools/firmware-utils/src/oseama.c
@@ -0,0 +1,556 @@
+/*
+ * oseama
+ *
+ * Copyright (C) 2016 Rafał Miłecki <zajec5@gmail.com>
+ *
+ * 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.
+ */
+
+#include <byteswap.h>
+#include <endian.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "md5.h"
+
+#if !defined(__BYTE_ORDER)
+#error "Unknown byte order"
+#endif
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define cpu_to_be32(x) (x)
+#define be32_to_cpu(x) (x)
+#define cpu_to_be16(x) (x)
+#define be16_to_cpu(x) (x)
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+#define cpu_to_be32(x) bswap_32(x)
+#define be32_to_cpu(x) bswap_32(x)
+#define cpu_to_be16(x) bswap_16(x)
+#define be16_to_cpu(x) bswap_16(x)
+#else
+#error "Unsupported endianness"
+#endif
+
+#define SEAMA_MAGIC 0x5ea3a417
+
+struct seama_seal_header {
+ uint32_t magic;
+ uint16_t reserved;
+ uint16_t metasize;
+ uint32_t imagesize;
+} __attribute__ ((packed));
+
+struct seama_entity_header {
+ uint32_t magic;
+ uint16_t reserved;
+ uint16_t metasize;
+ uint32_t imagesize;
+ uint8_t md5[16];
+} __attribute__ ((packed));
+
+char *seama_path;
+int entity_idx = -1;
+char *out_path;
+
+static inline size_t oseama_min(size_t x, size_t y) {
+ return x < y ? x : y;
+}
+
+/**************************************************
+ * Info
+ **************************************************/
+
+static void oseama_info_parse_options(int argc, char **argv) {
+ int c;
+
+ while ((c = getopt(argc, argv, "e:")) != -1) {
+ switch (c) {
+ case 'e':
+ entity_idx = atoi(optarg);
+ break;
+ }
+ }
+}
+
+static int oseama_info_entities(FILE *seama) {
+ struct seama_entity_header hdr;
+ size_t bytes, metasize, imagesize;
+ uint8_t buf[1024];
+ char *end, *tmp;
+ int i = 0;
+ int err = 0;
+
+ while ((bytes = fread(&hdr, 1, sizeof(hdr), seama)) == sizeof(hdr)) {
+ if (be32_to_cpu(hdr.magic) != SEAMA_MAGIC) {
+ fprintf(stderr, "Invalid Seama magic: 0x%08x\n", be32_to_cpu(hdr.magic));
+ err = -EINVAL;
+ goto err_out;
+ }
+ metasize = be16_to_cpu(hdr.metasize);
+ imagesize = be32_to_cpu(hdr.imagesize);
+
+ if (entity_idx >= 0 && i != entity_idx) {
+ fseek(seama, metasize + imagesize, SEEK_CUR);
+ i++;
+ continue;
+ }
+
+ if (metasize >= sizeof(buf)) {
+ fprintf(stderr, "Too small buffer (%zu B) to read all meta info (%zd B)\n", sizeof(buf), metasize);
+ err = -EINVAL;
+ goto err_out;
+ }
+
+ if (entity_idx < 0)
+ printf("\n");
+ printf("Entity offset:\t%ld\n", ftell(seama) - sizeof(hdr));
+ printf("Entity size:\t%zd\n", sizeof(hdr) + metasize + imagesize);
+ printf("Meta size:\t%zd\n", metasize);
+ printf("Image size:\t%zd\n", imagesize);
+
+ bytes = fread(buf, 1, metasize, seama);
+ if (bytes != metasize) {
+ fprintf(stderr, "Couldn't read %zd B of meta\n", metasize);
+ err = -EIO;
+ goto err_out;
+ }
+
+ end = (char *)&buf[metasize - 1];
+ *end = '\0';
+ for (tmp = (char *)buf; tmp < end && strlen(tmp); tmp += strlen(tmp) + 1) {
+ printf("Meta entry:\t%s\n", tmp);
+ }
+
+ fseek(seama, imagesize, SEEK_CUR);
+ i++;
+ }
+
+err_out:
+ return err;
+}
+
+static int oseama_info(int argc, char **argv) {
+ FILE *seama;
+ struct seama_seal_header hdr;
+ size_t bytes;
+ uint16_t metasize;
+ uint32_t imagesize;
+ uint8_t buf[1024];
+ int err = 0;
+
+ if (argc < 3) {
+ fprintf(stderr, "No Seama file passed\n");
+ err = -EINVAL;
+ goto out;
+ }
+ seama_path = argv[2];
+
+ optind = 3;
+ oseama_info_parse_options(argc, argv);
+
+ seama = fopen(seama_path, "r");
+ if (!seama) {
+ fprintf(stderr, "Couldn't open %s\n", seama_path);
+ err = -EACCES;
+ goto out;
+ }
+
+ bytes = fread(&hdr, 1, sizeof(hdr), seama);
+ if (bytes != sizeof(hdr)) {
+ fprintf(stderr, "Couldn't read %s header\n", seama_path);
+ err = -EIO;
+ goto err_close;
+ }
+ metasize = be16_to_cpu(hdr.metasize);
+ imagesize = be32_to_cpu(hdr.imagesize);
+
+ if (be32_to_cpu(hdr.magic) != SEAMA_MAGIC) {
+ fprintf(stderr, "Invalid Seama magic: 0x%08x\n", be32_to_cpu(hdr.magic));
+ err = -EINVAL;
+ goto err_close;
+ }
+
+ if (metasize >= sizeof(buf)) {
+ fprintf(stderr, "Too small buffer (%zu B) to read all meta info (%d B)\n", sizeof(buf), metasize);
+ err = -EINVAL;
+ goto err_close;
+ }
+
+ if (imagesize) {
+ fprintf(stderr, "Invalid Seama image size: 0x%08x (should be 0)\n", imagesize);
+ err = -EINVAL;
+ goto err_close;
+ }
+
+ bytes = fread(buf, 1, metasize, seama);
+ if (bytes != metasize) {
+ fprintf(stderr, "Couldn't read %d B of meta\n", metasize);
+ err = -EIO;
+ goto err_close;
+ }
+
+ if (entity_idx < 0) {
+ char *end, *tmp;
+
+ printf("Meta size:\t%d\n", metasize);
+ printf("Image size:\t%d\n", imagesize);
+
+ end = (char *)&buf[metasize - 1];
+ *end = '\0';
+ for (tmp = (char *)buf; tmp < end && strlen(tmp); tmp += strlen(tmp) + 1) {
+ printf("Meta entry:\t%s\n", tmp);
+ }
+ }
+
+ oseama_info_entities(seama);
+
+err_close:
+ fclose(seama);
+out:
+ return err;
+}
+
+/**************************************************
+ * Create
+ **************************************************/
+
+static ssize_t oseama_entity_append_file(FILE *seama, const char *in_path) {
+ FILE *in;
+ size_t bytes;
+ ssize_t length = 0;
+ uint8_t buf[128];
+
+ in = fopen(in_path, "r");
+ if (!in) {
+ fprintf(stderr, "Couldn't open %s\n", in_path);
+ return -EACCES;
+ }
+
+ while ((bytes = fread(buf, 1, sizeof(buf), in)) > 0) {
+ if (fwrite(buf, 1, bytes, seama) != bytes) {
+ fprintf(stderr, "Couldn't write %zu B to %s\n", bytes, seama_path);
+ length = -EIO;
+ break;
+ }
+ length += bytes;
+ }
+
+ fclose(in);
+
+ return length;
+}
+
+static ssize_t oseama_entity_append_zeros(FILE *seama, size_t length) {
+ uint8_t *buf;
+
+ buf = malloc(length);
+ if (!buf)
+ return -ENOMEM;
+ memset(buf, 0, length);
+
+ if (fwrite(buf, 1, length, seama) != length) {
+ fprintf(stderr, "Couldn't write %zu B to %s\n", length, seama_path);
+ return -EIO;
+ }
+
+ return length;
+}
+
+static ssize_t oseama_entity_align(FILE *seama, size_t curr_offset, size_t alignment) {
+ if (curr_offset & (alignment - 1)) {
+ size_t length = alignment - (curr_offset % alignment);
+
+ return oseama_entity_append_zeros(seama, length);
+ }
+
+ return 0;
+}
+
+static int oseama_entity_write_hdr(FILE *seama, size_t metasize, size_t imagesize) {
+ struct seama_entity_header hdr = {};
+ uint8_t buf[128];
+ size_t length = imagesize;
+ size_t bytes;
+ MD5_CTX ctx;
+
+ fseek(seama, sizeof(hdr) + metasize, SEEK_SET);
+ MD5_Init(&ctx);
+ while ((bytes = fread(buf, 1, oseama_min(sizeof(buf), length), seama)) > 0) {
+ MD5_Update(&ctx, buf, bytes);
+ length -= bytes;
+ }
+ MD5_Final(hdr.md5, &ctx);
+
+ hdr.magic = cpu_to_be32(SEAMA_MAGIC);
+ hdr.metasize = cpu_to_be16(metasize);
+ hdr.imagesize = cpu_to_be32(imagesize);
+
+ fseek(seama, 0, SEEK_SET);
+ bytes = fwrite(&hdr, 1, sizeof(hdr), seama);
+ if (bytes != sizeof(hdr)) {
+ fprintf(stderr, "Couldn't write Seama entity header to %s\n", seama_path);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int oseama_entity(int argc, char **argv) {
+ FILE *seama;
+ ssize_t sbytes;
+ size_t curr_offset = sizeof(struct seama_entity_header);
+ size_t metasize = 0, imagesize = 0;
+ int c;
+ int err = 0;
+
+ if (argc < 3) {
+ fprintf(stderr, "No Seama file passed\n");
+ err = -EINVAL;
+ goto out;
+ }
+ seama_path = argv[2];
+
+ seama = fopen(seama_path, "w+");
+ if (!seama) {
+ fprintf(stderr, "Couldn't open %s\n", seama_path);
+ err = -EACCES;
+ goto out;
+ }
+ fseek(seama, curr_offset, SEEK_SET);
+
+ optind = 3;
+ while ((c = getopt(argc, argv, "m:f:b:")) != -1) {
+ switch (c) {
+ case 'm':
+ sbytes = fwrite(optarg, 1, strlen(optarg) + 1, seama);
+ if (sbytes < 0) {
+ fprintf(stderr, "Failed to write meta %s\n", optarg);
+ } else {
+ curr_offset += sbytes;
+ metasize += sbytes;
+ }
+
+ sbytes = oseama_entity_align(seama, curr_offset, 4);
+ if (sbytes < 0) {
+ fprintf(stderr, "Failed to append zeros\n");
+ } else {
+ curr_offset += sbytes;
+ metasize += sbytes;
+ }
+
+ break;
+ case 'f':
+ case 'b':
+ break;
+ }
+ }
+
+ optind = 3;
+ while ((c = getopt(argc, argv, "m:f:b:")) != -1) {
+ switch (c) {
+ case 'm':
+ break;
+ case 'f':
+ sbytes = oseama_entity_append_file(seama, optarg);
+ if (sbytes < 0) {
+ fprintf(stderr, "Failed to append file %s\n", optarg);
+ } else {
+ curr_offset += sbytes;
+ imagesize += sbytes;
+ }
+ break;
+ case 'b':
+ sbytes = strtol(optarg, NULL, 0) - curr_offset;
+ if (sbytes < 0) {
+ fprintf(stderr, "Current Seama entity length is 0x%zx, can't pad it with zeros to 0x%lx\n", curr_offset, strtol(optarg, NULL, 0));
+ } else {
+ sbytes = oseama_entity_append_zeros(seama, sbytes);
+ if (sbytes < 0) {
+ fprintf(stderr, "Failed to append zeros\n");
+ } else {
+ curr_offset += sbytes;
+ imagesize += sbytes;
+ }
+ }
+ break;
+ }
+ if (err)
+ break;
+ }
+
+ oseama_entity_write_hdr(seama, metasize, imagesize);
+
+ fclose(seama);
+out:
+ return err;
+}
+
+/**************************************************
+ * Extract
+ **************************************************/
+
+static void oseama_extract_parse_options(int argc, char **argv) {
+ int c;
+
+ while ((c = getopt(argc, argv, "e:o:")) != -1) {
+ switch (c) {
+ case 'e':
+ entity_idx = atoi(optarg);
+ break;
+ case 'o':
+ out_path = optarg;
+ break;
+ }
+ }
+}
+
+static int oseama_extract_entity(FILE *seama, FILE *out) {
+ struct seama_entity_header hdr;
+ size_t bytes, metasize, imagesize, length;
+ uint8_t buf[1024];
+ int i = 0;
+ int err = 0;
+
+ while ((bytes = fread(&hdr, 1, sizeof(hdr), seama)) == sizeof(hdr)) {
+ if (be32_to_cpu(hdr.magic) != SEAMA_MAGIC) {
+ fprintf(stderr, "Invalid Seama magic: 0x%08x\n", be32_to_cpu(hdr.magic));
+ err = -EINVAL;
+ break;
+ }
+ metasize = be16_to_cpu(hdr.metasize);
+ imagesize = be32_to_cpu(hdr.imagesize);
+
+ if (i != entity_idx) {
+ fseek(seama, metasize + imagesize, SEEK_CUR);
+ i++;
+ continue;
+ }
+
+ fseek(seama, -sizeof(hdr), SEEK_CUR);
+
+ length = sizeof(hdr) + metasize + imagesize;
+ while ((bytes = fread(buf, 1, oseama_min(sizeof(buf), length), seama)) > 0) {
+ if (fwrite(buf, 1, bytes, out) != bytes) {
+ fprintf(stderr, "Couldn't write %zu B to %s\n", bytes, out_path);
+ err = -EIO;
+ break;
+ }
+ length -= bytes;
+ }
+
+ if (length) {
+ fprintf(stderr, "Couldn't extract whole entity %d from %s (%zu B left)\n", entity_idx, seama_path, length);
+ err = -EIO;
+ break;
+ }
+
+ break;
+ }
+
+ return err;
+}
+
+static int oseama_extract(int argc, char **argv) {
+ FILE *seama;
+ FILE *out;
+ struct seama_seal_header hdr;
+ size_t bytes;
+ uint16_t metasize;
+ int err = 0;
+
+ if (argc < 3) {
+ fprintf(stderr, "No Seama file passed\n");
+ err = -EINVAL;
+ goto out;
+ }
+ seama_path = argv[2];
+
+ optind = 3;
+ oseama_extract_parse_options(argc, argv);
+ if (entity_idx < 0) {
+ fprintf(stderr, "No entity specified\n");
+ err = -EINVAL;
+ goto out;
+ } else if (!out_path) {
+ fprintf(stderr, "No output file specified\n");
+ err = -EINVAL;
+ goto out;
+ }
+
+ seama = fopen(seama_path, "r");
+ if (!seama) {
+ fprintf(stderr, "Couldn't open %s\n", seama_path);
+ err = -EACCES;
+ goto out;
+ }
+
+ out = fopen(out_path, "w");
+ if (!out) {
+ fprintf(stderr, "Couldn't open %s\n", out_path);
+ err = -EACCES;
+ goto err_close_seama;
+ }
+
+ bytes = fread(&hdr, 1, sizeof(hdr), seama);
+ if (bytes != sizeof(hdr)) {
+ fprintf(stderr, "Couldn't read %s header\n", seama_path);
+ err = -EIO;
+ goto err_close_out;
+ }
+ metasize = be16_to_cpu(hdr.metasize);
+
+ fseek(seama, metasize, SEEK_CUR);
+
+ oseama_extract_entity(seama, out);
+
+err_close_out:
+ fclose(out);
+err_close_seama:
+ fclose(seama);
+out:
+ return err;
+}
+
+/**************************************************
+ * Start
+ **************************************************/
+
+static void usage() {
+ printf("Usage:\n");
+ printf("\n");
+ printf("Info about Seama seal (container):\n");
+ printf("\toseama info <file> [options]\n");
+ printf("\t-e\t\t\t\tprint info about specified entity only\n");
+ printf("\n");
+ printf("Create Seama entity:\n");
+ printf("\toseama entity <file> [options]\n");
+ printf("\t-m meta\t\t\t\tmeta into to put in header\n");
+ printf("\t-f file\t\t\t\tappend content from file\n");
+ printf("\t-b offset\t\t\tappend zeros till reaching absolute offset\n");
+ printf("\n");
+ printf("Extract from Seama seal (container):\n");
+ printf("\toseama extract <file> [options]\n");
+ printf("\t-e\t\t\t\tindex of entity to extract\n");
+ printf("\t-o file\t\t\t\toutput file\n");
+}
+
+int main(int argc, char **argv) {
+ if (argc > 1) {
+ if (!strcmp(argv[1], "info"))
+ return oseama_info(argc, argv);
+ else if (!strcmp(argv[1], "entity"))
+ return oseama_entity(argc, argv);
+ else if (!strcmp(argv[1], "extract"))
+ return oseama_extract(argc, argv);
+ }
+
+ usage();
+ return 0;
+}
diff --git a/tools/firmware-utils/src/otrx.c b/tools/firmware-utils/src/otrx.c
new file mode 100644
index 00000000000..223e032f2b5
--- /dev/null
+++ b/tools/firmware-utils/src/otrx.c
@@ -0,0 +1,592 @@
+/*
+ * otrx
+ *
+ * Copyright (C) 2015-2017 Rafał Miłecki <zajec5@gmail.com>
+ *
+ * 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.
+ */
+
+#include <byteswap.h>
+#include <endian.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#if !defined(__BYTE_ORDER)
+#error "Unknown byte order"
+#endif
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define cpu_to_le32(x) bswap_32(x)
+#define le32_to_cpu(x) bswap_32(x)
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+#define cpu_to_le32(x) (x)
+#define le32_to_cpu(x) (x)
+#else
+#error "Unsupported endianness"
+#endif
+
+#define TRX_MAGIC 0x30524448
+#define TRX_FLAGS_OFFSET 12
+#define TRX_MAX_PARTS 3
+
+struct trx_header {
+ uint32_t magic;
+ uint32_t length;
+ uint32_t crc32;
+ uint16_t flags;
+ uint16_t version;
+ uint32_t offset[3];
+};
+
+char *trx_path;
+size_t trx_offset = 0;
+char *partition[TRX_MAX_PARTS] = {};
+
+static inline size_t otrx_min(size_t x, size_t y) {
+ return x < y ? x : y;
+}
+
+/**************************************************
+ * CRC32
+ **************************************************/
+
+static const uint32_t crc32_tbl[] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
+ 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+ 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+ 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
+ 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+ 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
+ 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
+ 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+ 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+ 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
+ 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
+ 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+ 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
+ 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+ 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+ 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
+ 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
+ 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+ 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+ 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
+ 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+ 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
+ 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
+ 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+ 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+ 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
+ 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
+ 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+ 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
+ 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+ 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+ 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
+ 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
+ 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+ 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
+};
+
+uint32_t otrx_crc32(uint32_t crc, uint8_t *buf, size_t len) {
+ while (len) {
+ crc = crc32_tbl[(crc ^ *buf) & 0xff] ^ (crc >> 8);
+ buf++;
+ len--;
+ }
+
+ return crc;
+}
+
+/**************************************************
+ * Check
+ **************************************************/
+
+static void otrx_check_parse_options(int argc, char **argv) {
+ int c;
+
+ while ((c = getopt(argc, argv, "o:")) != -1) {
+ switch (c) {
+ case 'o':
+ trx_offset = atoi(optarg);
+ break;
+ }
+ }
+}
+
+static int otrx_check(int argc, char **argv) {
+ FILE *trx;
+ struct trx_header hdr;
+ size_t bytes, length;
+ uint8_t buf[1024];
+ uint32_t crc32;
+ int err = 0;
+
+ if (argc < 3) {
+ fprintf(stderr, "No TRX file passed\n");
+ err = -EINVAL;
+ goto out;
+ }
+ trx_path = argv[2];
+
+ optind = 3;
+ otrx_check_parse_options(argc, argv);
+
+ trx = fopen(trx_path, "r");
+ if (!trx) {
+ fprintf(stderr, "Couldn't open %s\n", trx_path);
+ err = -EACCES;
+ goto out;
+ }
+
+ fseek(trx, trx_offset, SEEK_SET);
+ bytes = fread(&hdr, 1, sizeof(hdr), trx);
+ if (bytes != sizeof(hdr)) {
+ fprintf(stderr, "Couldn't read %s header\n", trx_path);
+ err = -EIO;
+ goto err_close;
+ }
+
+ if (le32_to_cpu(hdr.magic) != TRX_MAGIC) {
+ fprintf(stderr, "Invalid TRX magic: 0x%08x\n", le32_to_cpu(hdr.magic));
+ err = -EINVAL;
+ goto err_close;
+ }
+
+ length = le32_to_cpu(hdr.length);
+ if (length < sizeof(hdr)) {
+ fprintf(stderr, "Length read from TRX too low (%zu B)\n", length);
+ err = -EINVAL;
+ goto err_close;
+ }
+
+ crc32 = 0xffffffff;
+ fseek(trx, trx_offset + TRX_FLAGS_OFFSET, SEEK_SET);
+ length -= TRX_FLAGS_OFFSET;
+ while ((bytes = fread(buf, 1, otrx_min(sizeof(buf), length), trx)) > 0) {
+ crc32 = otrx_crc32(crc32, buf, bytes);
+ length -= bytes;
+ }
+
+ if (length) {
+ fprintf(stderr, "Couldn't read last %zd B of data from %s\n", length, trx_path);
+ err = -EIO;
+ goto err_close;
+ }
+
+ if (crc32 != le32_to_cpu(hdr.crc32)) {
+ fprintf(stderr, "Invalid data crc32: 0x%08x instead of 0x%08x\n", crc32, le32_to_cpu(hdr.crc32));
+ err = -EINVAL;
+ goto err_close;
+ }
+
+ printf("Found a valid TRX version %d\n", le32_to_cpu(hdr.version));
+
+err_close:
+ fclose(trx);
+out:
+ return err;
+}
+
+/**************************************************
+ * Create
+ **************************************************/
+
+static ssize_t otrx_create_append_file(FILE *trx, const char *in_path) {
+ FILE *in;
+ size_t bytes;
+ ssize_t length = 0;
+ uint8_t buf[1024];
+
+ in = fopen(in_path, "r");
+ if (!in) {
+ fprintf(stderr, "Couldn't open %s\n", in_path);
+ return -EACCES;
+ }
+
+ while ((bytes = fread(buf, 1, sizeof(buf), in)) > 0) {
+ if (fwrite(buf, 1, bytes, trx) != bytes) {
+ fprintf(stderr, "Couldn't write %zu B to %s\n", bytes, trx_path);
+ length = -EIO;
+ break;
+ }
+ length += bytes;
+ }
+
+ fclose(in);
+
+ return length;
+}
+
+static ssize_t otrx_create_append_zeros(FILE *trx, size_t length) {
+ uint8_t *buf;
+
+ buf = malloc(length);
+ if (!buf)
+ return -ENOMEM;
+ memset(buf, 0, length);
+
+ if (fwrite(buf, 1, length, trx) != length) {
+ fprintf(stderr, "Couldn't write %zu B to %s\n", length, trx_path);
+ free(buf);
+ return -EIO;
+ }
+
+ free(buf);
+
+ return length;
+}
+
+static ssize_t otrx_create_align(FILE *trx, size_t curr_offset, size_t alignment) {
+ if (curr_offset & (alignment - 1)) {
+ size_t length = alignment - (curr_offset % alignment);
+ return otrx_create_append_zeros(trx, length);
+ }
+
+ return 0;
+}
+
+static int otrx_create_write_hdr(FILE *trx, struct trx_header *hdr) {
+ size_t bytes, length;
+ uint8_t buf[1024];
+ uint32_t crc32;
+
+ hdr->magic = cpu_to_le32(TRX_MAGIC);
+ hdr->version = 1;
+
+ fseek(trx, 0, SEEK_SET);
+ bytes = fwrite(hdr, 1, sizeof(struct trx_header), trx);
+ if (bytes != sizeof(struct trx_header)) {
+ fprintf(stderr, "Couldn't write TRX header to %s\n", trx_path);
+ return -EIO;
+ }
+
+ length = le32_to_cpu(hdr->length);
+
+ crc32 = 0xffffffff;
+ fseek(trx, TRX_FLAGS_OFFSET, SEEK_SET);
+ length -= TRX_FLAGS_OFFSET;
+ while ((bytes = fread(buf, 1, otrx_min(sizeof(buf), length), trx)) > 0) {
+ crc32 = otrx_crc32(crc32, buf, bytes);
+ length -= bytes;
+ }
+ hdr->crc32 = cpu_to_le32(crc32);
+
+ fseek(trx, 0, SEEK_SET);
+ bytes = fwrite(hdr, 1, sizeof(struct trx_header), trx);
+ if (bytes != sizeof(struct trx_header)) {
+ fprintf(stderr, "Couldn't write TRX header to %s\n", trx_path);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int otrx_create(int argc, char **argv) {
+ FILE *trx;
+ struct trx_header hdr = {};
+ ssize_t sbytes;
+ size_t curr_idx = 0;
+ size_t curr_offset = sizeof(hdr);
+ int c;
+ int err = 0;
+
+ if (argc < 3) {
+ fprintf(stderr, "No TRX file passed\n");
+ err = -EINVAL;
+ goto out;
+ }
+ trx_path = argv[2];
+
+ trx = fopen(trx_path, "w+");
+ if (!trx) {
+ fprintf(stderr, "Couldn't open %s\n", trx_path);
+ err = -EACCES;
+ goto out;
+ }
+ fseek(trx, curr_offset, SEEK_SET);
+
+ optind = 3;
+ while ((c = getopt(argc, argv, "f:A:a:b:")) != -1) {
+ switch (c) {
+ case 'f':
+ if (curr_idx >= TRX_MAX_PARTS) {
+ err = -ENOSPC;
+ fprintf(stderr, "Reached TRX partitions limit, no place for %s\n", optarg);
+ goto err_close;
+ }
+
+ sbytes = otrx_create_append_file(trx, optarg);
+ if (sbytes < 0) {
+ fprintf(stderr, "Failed to append file %s\n", optarg);
+ } else {
+ hdr.offset[curr_idx++] = curr_offset;
+ curr_offset += sbytes;
+ }
+
+ sbytes = otrx_create_align(trx, curr_offset, 4);
+ if (sbytes < 0)
+ fprintf(stderr, "Failed to append zeros\n");
+ else
+ curr_offset += sbytes;
+
+ break;
+ case 'A':
+ sbytes = otrx_create_append_file(trx, optarg);
+ if (sbytes < 0) {
+ fprintf(stderr, "Failed to append file %s\n", optarg);
+ } else {
+ curr_offset += sbytes;
+ }
+
+ sbytes = otrx_create_align(trx, curr_offset, 4);
+ if (sbytes < 0)
+ fprintf(stderr, "Failed to append zeros\n");
+ else
+ curr_offset += sbytes;
+ break;
+ case 'a':
+ sbytes = otrx_create_align(trx, curr_offset, strtol(optarg, NULL, 0));
+ if (sbytes < 0)
+ fprintf(stderr, "Failed to append zeros\n");
+ else
+ curr_offset += sbytes;
+ break;
+ case 'b':
+ sbytes = strtol(optarg, NULL, 0) - curr_offset;
+ if (sbytes < 0) {
+ fprintf(stderr, "Current TRX length is 0x%zx, can't pad it with zeros to 0x%lx\n", curr_offset, strtol(optarg, NULL, 0));
+ } else {
+ sbytes = otrx_create_append_zeros(trx, sbytes);
+ if (sbytes < 0)
+ fprintf(stderr, "Failed to append zeros\n");
+ else
+ curr_offset += sbytes;
+ }
+ break;
+ }
+ if (err)
+ break;
+ }
+
+ sbytes = otrx_create_align(trx, curr_offset, 0x1000);
+ if (sbytes < 0)
+ fprintf(stderr, "Failed to append zeros\n");
+ else
+ curr_offset += sbytes;
+
+ hdr.length = curr_offset;
+ otrx_create_write_hdr(trx, &hdr);
+err_close:
+ fclose(trx);
+out:
+ return err;
+}
+
+/**************************************************
+ * Extract
+ **************************************************/
+
+static void otrx_extract_parse_options(int argc, char **argv) {
+ int c;
+
+ while ((c = getopt(argc, argv, "c:e:o:1:2:3:")) != -1) {
+ switch (c) {
+ case 'o':
+ trx_offset = atoi(optarg);
+ break;
+ case '1':
+ partition[0] = optarg;
+ break;
+ case '2':
+ partition[1] = optarg;
+ break;
+ case '3':
+ partition[2] = optarg;
+ break;
+ }
+ }
+}
+
+static int otrx_extract_copy(FILE *trx, size_t offset, size_t length, char *out_path) {
+ FILE *out;
+ size_t bytes;
+ uint8_t *buf;
+ int err = 0;
+
+ out = fopen(out_path, "w");
+ if (!out) {
+ fprintf(stderr, "Couldn't open %s\n", out_path);
+ err = -EACCES;
+ goto out;
+ }
+
+ buf = malloc(length);
+ if (!buf) {
+ fprintf(stderr, "Couldn't alloc %zu B buffer\n", length);
+ err = -ENOMEM;
+ goto err_close;
+ }
+
+ fseek(trx, offset, SEEK_SET);
+ bytes = fread(buf, 1, length, trx);
+ if (bytes != length) {
+ fprintf(stderr, "Couldn't read %zu B of data from %s\n", length, trx_path);
+ err = -ENOMEM;
+ goto err_free_buf;
+ };
+
+ bytes = fwrite(buf, 1, length, out);
+ if (bytes != length) {
+ fprintf(stderr, "Couldn't write %zu B to %s\n", length, out_path);
+ err = -ENOMEM;
+ goto err_free_buf;
+ }
+
+ printf("Extracted 0x%zx bytes into %s\n", length, out_path);
+
+err_free_buf:
+ free(buf);
+err_close:
+ fclose(out);
+out:
+ return err;
+}
+
+static int otrx_extract(int argc, char **argv) {
+ FILE *trx;
+ struct trx_header hdr;
+ size_t bytes;
+ int i;
+ int err = 0;
+
+ if (argc < 3) {
+ fprintf(stderr, "No TRX file passed\n");
+ err = -EINVAL;
+ goto out;
+ }
+ trx_path = argv[2];
+
+ optind = 3;
+ otrx_extract_parse_options(argc, argv);
+
+ trx = fopen(trx_path, "r");
+ if (!trx) {
+ fprintf(stderr, "Couldn't open %s\n", trx_path);
+ err = -EACCES;
+ goto out;
+ }
+
+ fseek(trx, trx_offset, SEEK_SET);
+ bytes = fread(&hdr, 1, sizeof(hdr), trx);
+ if (bytes != sizeof(hdr)) {
+ fprintf(stderr, "Couldn't read %s header\n", trx_path);
+ err = -EIO;
+ goto err_close;
+ }
+
+ if (le32_to_cpu(hdr.magic) != TRX_MAGIC) {
+ fprintf(stderr, "Invalid TRX magic: 0x%08x\n", le32_to_cpu(hdr.magic));
+ err = -EINVAL;
+ goto err_close;
+ }
+
+ for (i = 0; i < TRX_MAX_PARTS; i++) {
+ size_t length;
+
+ if (!partition[i])
+ continue;
+ if (!hdr.offset[i]) {
+ printf("TRX doesn't contain partition %d, can't extract %s\n", i + 1, partition[i]);
+ continue;
+ }
+
+ if (i + 1 >= TRX_MAX_PARTS || !hdr.offset[i + 1])
+ length = le32_to_cpu(hdr.length) - le32_to_cpu(hdr.offset[i]);
+ else
+ length = le32_to_cpu(hdr.offset[i + 1]) - le32_to_cpu(hdr.offset[i]);
+
+ otrx_extract_copy(trx, trx_offset + le32_to_cpu(hdr.offset[i]), length, partition[i]);
+ }
+
+err_close:
+ fclose(trx);
+out:
+ return err;
+}
+
+/**************************************************
+ * Start
+ **************************************************/
+
+static void usage() {
+ printf("Usage:\n");
+ printf("\n");
+ printf("Checking TRX file:\n");
+ printf("\totrx check <file> [options]\tcheck if file is a valid TRX\n");
+ printf("\t-o offset\t\t\toffset of TRX data in file (default: 0)\n");
+ printf("\n");
+ printf("Creating new TRX file:\n");
+ printf("\totrx create <file> [options] [partitions]\n");
+ printf("\t-f file\t\t\t\t[partition] start new partition with content copied from file\n");
+ printf("\t-A file\t\t\t\t[partition] append current partition with content copied from file\n");
+ printf("\t-a alignment\t\t\t[partition] align current partition\n");
+ printf("\t-b offset\t\t\t[partition] append zeros to partition till reaching absolute offset\n");
+ printf("\n");
+ printf("Extracting from TRX file:\n");
+ printf("\totrx extract <file> [options]\textract partitions from TRX file\n");
+ printf("\t-o offset\t\t\toffset of TRX data in file (default: 0)\n");
+ printf("\t-1 file\t\t\t\tfile to extract 1st partition to (optional)\n");
+ printf("\t-2 file\t\t\t\tfile to extract 2nd partition to (optional)\n");
+ printf("\t-3 file\t\t\t\tfile to extract 3rd partition to (optional)\n");
+}
+
+int main(int argc, char **argv) {
+ if (argc > 1) {
+ if (!strcmp(argv[1], "check"))
+ return otrx_check(argc, argv);
+ else if (!strcmp(argv[1], "create"))
+ return otrx_create(argc, argv);
+ else if (!strcmp(argv[1], "extract"))
+ return otrx_extract(argc, argv);
+ }
+
+ usage();
+ return 0;
+}
diff --git a/tools/firmware-utils/src/pc1crypt.c b/tools/firmware-utils/src/pc1crypt.c
index 9c2eb83f666..fe41b3dab5c 100644
--- a/tools/firmware-utils/src/pc1crypt.c
+++ b/tools/firmware-utils/src/pc1crypt.c
@@ -208,7 +208,7 @@ static int decrypt;
#define ERRS(fmt, ...) do { \
int save = errno; \
fflush(0); \
- fprintf(stderr, "[%s] *** error: " fmt "\n", \
+ fprintf(stderr, "[%s] *** error: " fmt ": %s\n", \
progname, ## __VA_ARGS__, strerror(save)); \
} while (0)
diff --git a/tools/firmware-utils/src/ptgen.c b/tools/firmware-utils/src/ptgen.c
index d94aabb5fcf..13e0eda6222 100644
--- a/tools/firmware-utils/src/ptgen.c
+++ b/tools/firmware-utils/src/ptgen.c
@@ -1,6 +1,6 @@
-/*
+/*
* ptgen - partition table generator
- * Copyright (C) 2006 by Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2006 by Felix Fietkau <nbd@nbd.name>
*
* uses parts of afdisk
* Copyright (C) 2002 by David Roetzel <david@roetzel.de>
@@ -9,12 +9,12 @@
* 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 St, Fifth Floor, Boston, MA 02110-1301 USA
@@ -26,25 +26,27 @@
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
+#include <stdint.h>
#include <ctype.h>
#include <fcntl.h>
+#include <stdint.h>
#if __BYTE_ORDER == __BIG_ENDIAN
-#define cpu_to_le16(x) bswap_16(x)
+#define cpu_to_le32(x) bswap_32(x)
#elif __BYTE_ORDER == __LITTLE_ENDIAN
-#define cpu_to_le16(x) (x)
+#define cpu_to_le32(x) (x)
#else
#error unknown endianness!
#endif
/* Partition table entry */
-struct pte {
- unsigned char active;
- unsigned char chs_start[3];
- unsigned char type;
- unsigned char chs_end[3];
- unsigned int start;
- unsigned int length;
+struct pte {
+ uint8_t active;
+ uint8_t chs_start[3];
+ uint8_t type;
+ uint8_t chs_end[3];
+ uint32_t start;
+ uint32_t length;
};
struct partinfo {
@@ -56,29 +58,31 @@ int verbose = 0;
int active = 1;
int heads = -1;
int sectors = -1;
+int kb_align = 0;
struct partinfo parts[4];
char *filename = NULL;
-/*
+/*
* parse the size argument, which is either
* a simple number (K assumed) or
* K, M or G
*
* returns the size in KByte
*/
-static long to_kbytes(const char *string) {
+static long to_kbytes(const char *string)
+{
int exp = 0;
long result;
char *end;
result = strtoul(string, &end, 0);
switch (tolower(*end)) {
- case 'k' :
- case '\0' : exp = 0; break;
- case 'm' : exp = 1; break;
- case 'g' : exp = 2; break;
- default: return 0;
+ case 'k' :
+ case '\0' : exp = 0; break;
+ case 'm' : exp = 1; break;
+ case 'g' : exp = 2; break;
+ default: return 0;
}
if (*end)
@@ -90,13 +94,16 @@ static long to_kbytes(const char *string) {
}
/* result: number + 1024^(exp) */
- return result * ((2 << ((10 * exp) - 1)) ?: 1);
+ if (exp == 0)
+ return result;
+ return result * (2 << ((10 * exp) - 1));
}
/* convert the sector number into a CHS value for the partition table */
-static void to_chs(long sect, unsigned char chs[3]) {
+static void to_chs(long sect, unsigned char chs[3])
+{
int c,h,s;
-
+
s = (sect % sectors) + 1;
sect = sect / sectors;
h = sect % heads;
@@ -111,17 +118,23 @@ static void to_chs(long sect, unsigned char chs[3]) {
}
/* round the sector number up to the next cylinder */
-static inline unsigned long round_to_cyl(long sect) {
+static inline unsigned long round_to_cyl(long sect)
+{
int cyl_size = heads * sectors;
- return sect + cyl_size - (sect % cyl_size);
+ return sect + cyl_size - (sect % cyl_size);
+}
+
+/* round the sector number up to the kb_align boundary */
+static inline unsigned long round_to_kb(long sect) {
+ return ((sect - 1) / kb_align + 1) * kb_align;
}
/* check the partition sizes and write the partition table */
-static int gen_ptable(int nr)
+static int gen_ptable(uint32_t signature, int nr)
{
struct pte pte[4];
- unsigned long sect = 0;
+ unsigned long sect = 0;
int i, fd, ret = -1, start, len;
memset(pte, 0, sizeof(struct pte) * 4);
@@ -130,17 +143,27 @@ static int gen_ptable(int nr)
fprintf(stderr, "Invalid size in partition %d!\n", i);
return -1;
}
+
pte[i].active = ((i + 1) == active) ? 0x80 : 0;
pte[i].type = parts[i].type;
- pte[i].start = cpu_to_le16(start = sect + sectors);
- sect = round_to_cyl(start + parts[i].size * 2);
- pte[i].length = cpu_to_le16(len = sect - start);
+
+ start = sect + sectors;
+ if (kb_align != 0)
+ start = round_to_kb(start);
+ pte[i].start = cpu_to_le32(start);
+
+ sect = start + parts[i].size * 2;
+ if (kb_align == 0)
+ sect = round_to_cyl(sect);
+ pte[i].length = cpu_to_le32(len = sect - start);
+
to_chs(start, pte[i].chs_start);
to_chs(start + len - 1, pte[i].chs_end);
+
if (verbose)
- fprintf(stderr, "Partition %d: start=%ld, end=%ld, size=%ld\n", i, (long) start * 512, ((long) start + (long) len) * 512, (long) len * 512);
- printf("%ld\n", ((long) start * 512));
- printf("%ld\n", ((long) len * 512));
+ fprintf(stderr, "Partition %d: start=%ld, end=%ld, size=%ld\n", i, (long)start * 512, ((long)start + (long)len) * 512, (long)len * 512);
+ printf("%ld\n", (long)start * 512);
+ printf("%ld\n", (long)len * 512);
}
if ((fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0) {
@@ -148,6 +171,12 @@ static int gen_ptable(int nr)
return -1;
}
+ lseek(fd, 440, SEEK_SET);
+ if (write(fd, &signature, sizeof(signature)) != sizeof(signature)) {
+ fprintf(stderr, "write failed.\n");
+ goto fail;
+ }
+
lseek(fd, 446, SEEK_SET);
if (write(fd, pte, sizeof(struct pte) * 4) != sizeof(struct pte) * 4) {
fprintf(stderr, "write failed.\n");
@@ -158,7 +187,7 @@ static int gen_ptable(int nr)
fprintf(stderr, "write failed.\n");
goto fail;
}
-
+
ret = 0;
fail:
close(fd);
@@ -167,8 +196,8 @@ fail:
static void usage(char *prog)
{
- fprintf(stderr, "Usage: %s [-v] -h <heads> -s <sectors> -o <outputfile> [-a 0..4] [[-t <type>] -p <size>...] \n", prog);
- exit(1);
+ fprintf(stderr, "Usage: %s [-v] -h <heads> -s <sectors> -o <outputfile> [-a 0..4] [-l <align kB>] [[-t <type>] -p <size>...] \n", prog);
+ exit(EXIT_FAILURE);
}
int main (int argc, char **argv)
@@ -176,8 +205,9 @@ int main (int argc, char **argv)
char type = 0x83;
int ch;
int part = 0;
+ uint32_t signature = 0x5452574F; /* 'OWRT' */
- while ((ch = getopt(argc, argv, "h:s:p:a:t:o:v")) != -1) {
+ while ((ch = getopt(argc, argv, "h:s:p:a:t:o:vl:S:")) != -1) {
switch (ch) {
case 'o':
filename = optarg;
@@ -186,35 +216,41 @@ int main (int argc, char **argv)
verbose++;
break;
case 'h':
- heads = (int) strtoul(optarg, NULL, 0);
+ heads = (int)strtoul(optarg, NULL, 0);
break;
case 's':
- sectors = (int) strtoul(optarg, NULL, 0);
+ sectors = (int)strtoul(optarg, NULL, 0);
break;
case 'p':
if (part > 3) {
fprintf(stderr, "Too many partitions\n");
- exit(1);
+ exit(EXIT_FAILURE);
}
parts[part].size = to_kbytes(optarg);
parts[part++].type = type;
break;
case 't':
- type = (char) strtoul(optarg, NULL, 16);
+ type = (char)strtoul(optarg, NULL, 16);
break;
case 'a':
- active = (int) strtoul(optarg, NULL, 0);
+ active = (int)strtoul(optarg, NULL, 0);
if ((active < 0) || (active > 4))
active = 0;
break;
+ case 'l':
+ kb_align = (int)strtoul(optarg, NULL, 0) * 2;
+ break;
+ case 'S':
+ signature = strtoul(optarg, NULL, 0);
+ break;
case '?':
default:
usage(argv[0]);
}
}
argc -= optind;
- if (argc || (heads <= 0) || (sectors <= 0) || !filename)
+ if (argc || (heads <= 0) || (sectors <= 0) || !filename)
usage(argv[0]);
-
- return gen_ptable(part);
+
+ return gen_ptable(signature, part) ? EXIT_FAILURE : EXIT_SUCCESS;
}
diff --git a/tools/firmware-utils/src/seama.c b/tools/firmware-utils/src/seama.c
new file mode 100644
index 00000000000..05aee8e76aa
--- /dev/null
+++ b/tools/firmware-utils/src/seama.c
@@ -0,0 +1,529 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright (C) 2008, Alpha Networks, Inc.
+ * Created by David Hsieh <david_hsieh@alphanetworks.com>
+ * All right reserved.
+ *
+ * (SEA)ttle i(MA)ge is the image which used in project seattle.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+#include <arpa/inet.h>
+
+#include "md5.h"
+#include "seama.h"
+
+#define PROGNAME "seama"
+#define VERSION "0.20"
+#define MAX_SEAMA_META_SIZE 1024
+#define MAX_META 128
+#define MAX_IMAGE 128
+
+extern int optind;
+extern char * optarg;
+
+static int o_verbose = 0; /* verbose mode. */
+static char * o_dump = NULL; /* Seama file to dump. */
+static char * o_seal = NULL; /* Seal the input images when file name exist. */
+static char * o_extract = NULL; /* Extract the seama file. */
+static char * o_images[MAX_IMAGE];/* The image files to pack or seal */
+static int o_isize = 0; /* number of images */
+static char * o_meta[MAX_META]; /* meta data array */
+static int o_msize = 0; /* size of meta array */
+
+static void verbose(const char * format, ...)
+{
+ va_list marker;
+ if (o_verbose)
+ {
+ va_start(marker, format);
+ vfprintf(stdout, format, marker);
+ va_end(marker);
+ }
+}
+
+static void cleanup_exit(int exit_code)
+{
+ verbose("%s: exit with code %d\n", PROGNAME, exit_code);
+ exit(exit_code);
+}
+
+static void show_usage(int exit_code)
+{
+ printf( PROGNAME " version " VERSION "\n"
+ "usage: " PROGNAME " [OPTIONS]\n"
+ " -h show this help message.\n"
+ " -v verbose mode.\n"
+ " -m {META data} META data.\n"
+ " -d {file} dump the info of the seama file.\n"
+ " -i {input file} image file name.\n"
+ " -s {file} Seal the images to the seama file.\n"
+ " -x {seama file} Extract the seama file.\n"
+ "\n"
+ " SEAMA can pack the input file (with -i) into a seama file.\n"
+ " ex: seama -i target.file\n"
+ " SEAMA can also seal multiple seama files into a single seama file.\n"
+ " ex: seama -s final.file -i taget1.seama -i target2.seama\n"
+ " To extract the raw image from SEAMA, you need to specify the meta.\n"
+ " The first image match the specified meta will be extract to\n"
+ " the output file which was specified with '-x'.\n"
+ " ex: seama -x output -i seama.image -m file=sealpac\n"
+ );
+ cleanup_exit(exit_code);
+}
+
+static int parse_args(int argc, char * argv[])
+{
+ int opt;
+
+ while ((opt = getopt(argc, argv, "hvd:s:i:m:x:")) > 0)
+ {
+ switch (opt)
+ {
+ default: show_usage(-1); break;
+ case 'h': show_usage(0); break;
+ case 'v': o_verbose++; break;
+ case 'd': o_dump = optarg; break;
+ case 's': o_seal = optarg; break;
+ case 'x': o_extract = optarg; break;
+ case 'i':
+ if (o_isize < MAX_IMAGE) o_images[o_isize++] = optarg;
+ else printf("Exceed the maximum acceptable image files.!\n");
+ break;
+ case 'm':
+ if (o_msize < MAX_META) o_meta[o_msize++] = optarg;
+ else printf("Exceed the maximum acceptable META data.!\n");
+ break;
+ }
+ }
+ return 0;
+}
+
+/*******************************************************************/
+
+static size_t calculate_digest(FILE * fh, size_t size, uint8_t * digest)
+{
+ MD5_CTX ctx;
+ size_t bytes_left, bytes_read, i;
+ uint8_t buf[MAX_SEAMA_META_SIZE];
+
+ bytes_left = size ? size : sizeof(buf);
+ bytes_read = 0;
+
+ MD5_Init(&ctx);
+ while (!feof(fh) && !ferror(fh) && bytes_left > 0)
+ {
+ i = bytes_left < sizeof(buf) ? bytes_left : sizeof(buf);
+ i = fread(buf, sizeof(char), i, fh);
+ if (i > 0)
+ {
+ MD5_Update(&ctx, buf, i);
+ bytes_read += i;
+ }
+ if (size) bytes_left -= i;
+ }
+ MD5_Final(digest, &ctx);
+ return bytes_read;
+}
+
+#define READ_BUFF_SIZE 8*1024
+static size_t copy_file(FILE * to, FILE * from)
+{
+ size_t i, fsize = 0;
+ uint8_t buf[READ_BUFF_SIZE];
+
+ while (!feof(from) && !ferror(from))
+ {
+ i = fread(buf, sizeof(uint8_t), READ_BUFF_SIZE, from);
+ if (i > 0)
+ {
+ fsize += i;
+ fwrite(buf, sizeof(uint8_t), i, to);
+ }
+ }
+ return fsize;
+}
+
+static int verify_seama(const char * fname, int msg)
+{
+ FILE * fh = NULL;
+ struct stat st;
+ seamahdr_t shdr;
+ uint8_t checksum[16];
+ uint8_t digest[16];
+ uint8_t buf[MAX_SEAMA_META_SIZE];
+ size_t msize, isize, i;
+ int ret = -1;
+
+#define ERRBREAK(fmt, args...) { if (msg) printf(fmt, ##args); break; }
+
+ do
+ {
+ if (stat(fname, &st) < 0) ERRBREAK("Unable to get the info of '%s'\n",fname);
+ if ((fh = fopen(fname, "r+"))==NULL) ERRBREAK("Unable to open '%s' for reading!\n",fname);
+
+ /* Dump SEAMA header */
+ if (msg) printf("FILE - %s (%d bytes)\n", fname, (int)st.st_size);
+
+ /* SEAMA */
+ while (!feof(fh) && !ferror(fh))
+ {
+ /* read header */
+ if (fread(&shdr, sizeof(shdr), 1, fh) != 1) break;
+
+ /* Check the magic number */
+ if (shdr.magic != htonl(SEAMA_MAGIC)) ERRBREAK("Invalid SEAMA magic. Probably no more SEAMA!\n");
+
+ /* Get the size */
+ isize = ntohl(shdr.size);
+ msize = ntohs(shdr.metasize);
+
+ /* The checksum exist only if size is greater than zero. */
+ if (isize > 0)
+ {
+ if (fread(checksum, sizeof(checksum), 1, fh) != 1)
+ ERRBREAK("Error reading checksum !\n");
+ }
+
+ /* Check the META size. */
+ if (msize > sizeof(buf)) ERRBREAK("META data in SEAMA header is too large!\n");
+
+ /* Read META data. */
+ if (fread(buf, sizeof(char), msize, fh) != msize)
+ ERRBREAK("Unable to read SEAMA META data!\n");
+
+ /* dump header */
+ if (msg)
+ {
+ printf("SEAMA ==========================================\n");
+ printf(" magic : %08x\n", ntohl(shdr.magic));
+ printf(" meta size : %zu bytes\n", msize);
+ for (i=0; i<msize; i+=(strlen((const char *)&buf[i])+1))
+ printf(" meta data : %s\n", &buf[i]);
+ printf(" image size : %zu bytes\n", isize);
+ }
+
+ /* verify checksum */
+ if (isize > 0)
+ {
+ if (msg)
+ {
+ printf(" checksum : ");
+ for (i=0; i<16; i++) printf("%02X", checksum[i]);
+ printf("\n");
+ }
+
+ /* Calculate the checksum */
+ calculate_digest(fh, isize, digest);
+ if (msg)
+ {
+ printf(" digest : ");
+ for (i=0; i<16; i++) printf("%02X", digest[i]);
+ printf("\n");
+ }
+
+ if (memcmp(checksum, digest, 16)!=0) ERRBREAK("!!ERROR!! checksum error !!\n");
+ ret = 0;
+ }
+ }
+ if (msg) printf("================================================\n");
+ } while (0);
+ if (fh) fclose(fh);
+ return ret;
+}
+
+static size_t write_seama_header(FILE * fh, char * meta[], size_t msize, size_t size)
+{
+ seamahdr_t shdr;
+ size_t i;
+ uint16_t metasize = 0;
+
+ /* Calculate the META size */
+ for (i=0; i<msize; i++) metasize += (strlen(meta[i]) + 1);
+ //+++ let meta data end on 4 alignment by siyou. 2010/3/1 03:58pm
+ metasize = ((metasize+3)/4)*4;
+ verbose("SEAMA META : %d bytes\n", metasize);
+
+ /* Fill up the header, all the data endian should be network byte order. */
+ shdr.magic = htonl(SEAMA_MAGIC);
+ shdr.reserved = 0;
+ shdr.metasize = htons(metasize);
+ shdr.size = htonl(size);
+
+ /* Write the header */
+ return fwrite(&shdr, sizeof(seamahdr_t), 1, fh);
+}
+
+static size_t write_checksum(FILE * fh, uint8_t * checksum)
+{
+ return fwrite(checksum, sizeof(uint8_t), 16, fh);
+}
+
+static size_t write_meta_data(FILE * fh, char * meta[], size_t size)
+{
+ size_t i,j;
+ size_t ret = 0;
+
+ for (i=0; i<size; i++)
+ {
+ verbose("SEAMA META data : %s\n", meta[i]);
+ j = fwrite(meta[i], sizeof(char), strlen(meta[i])+1, fh);
+ if (j != strlen(meta[i])+1) return 0;
+ ret += j;
+ }
+ //+++ let meta data end on 4 alignment by siyou. 2010/3/1 03:58pm
+ j = ((ret+3)/4)*4;
+ for ( ; ret < j; ret++)
+ fwrite("", sizeof(char), 1, fh);
+
+ return ret;
+}
+
+/*******************************************************************/
+
+static void dump_seama(const char * fname)
+{
+ verify_seama(fname, 1);
+}
+
+static void seal_files(const char * file)
+{
+ FILE * fh;
+ FILE * ifh;
+ size_t i;
+
+ /* Each image should be seama. */
+ for (i = 0; i < o_isize; i++)
+ {
+ if (verify_seama(o_images[i], 0) < 0)
+ {
+ printf("'%s' is not a seama file !\n",o_images[i]);
+ return;
+ }
+ }
+
+ /* Open file for write */
+ fh = fopen(file, "w+");
+ if (fh)
+ {
+ /* Write the header. */
+ write_seama_header(fh, o_meta, o_msize, 0);
+ write_meta_data(fh, o_meta, o_msize);
+
+ /* Write image files */
+ for (i=0; i<o_isize; i++)
+ {
+ ifh = fopen(o_images[i], "r+");
+ if (ifh)
+ {
+ copy_file(fh, ifh);
+ fclose(ifh);
+ }
+ }
+
+ fclose(fh);
+ }
+}
+
+static void pack_files(void)
+{
+ FILE * fh;
+ FILE * ifh;
+ size_t i, fsize;
+ char filename[512];
+ uint8_t digest[16];
+
+ for (i=0; i<o_isize; i++)
+ {
+ /* Open the input file. */
+ ifh = fopen(o_images[i], "r+");
+ if (ifh)
+ {
+ fsize = calculate_digest(ifh, 0, digest);
+ verbose("file size (%s) : %d\n", o_images[i], fsize);
+ rewind(ifh);
+
+ /* Open the output file. */
+ sprintf(filename, "%s.seama", o_images[i]);
+ fh = fopen(filename, "w+");
+ if (fh)
+ {
+ write_seama_header(fh, o_meta, o_msize, fsize);
+ write_checksum(fh, digest);
+ write_meta_data(fh, o_meta, o_msize);
+ copy_file(fh, ifh);
+ fclose(fh);
+ }
+ fclose(ifh);
+ }
+ else
+ {
+ printf("Unable to open image file '%s'\n",o_images[i]);
+ }
+ }
+}
+
+/**************************************************************************/
+
+static int match_meta(const char * meta, size_t size)
+{
+ size_t i, j;
+ int match;
+
+ for (i = 0; i < o_msize; i++)
+ {
+ for (match = 0, j = 0; j < size; j += (strlen(&meta[j])+1))
+ if (strcmp(&meta[j], o_meta[i])==0) { match++; break; }
+ if (!match) return 0;
+ }
+ return 1;
+}
+
+
+static void extract_file(const char * output)
+{
+ FILE * ifh = NULL;
+ FILE * ofh = NULL;
+ size_t msize, isize, i, m;
+ seamahdr_t shdr;
+ uint8_t buf[MAX_SEAMA_META_SIZE];
+ int done = 0;
+
+ /* We need meta for searching the target image. */
+ if (o_msize == 0)
+ {
+ printf("SEAMA: need meta for searching image.\n");
+ return;
+ }
+
+ /* Walk through each input file */
+ for (i = 0; i < o_isize; i++)
+ {
+ /* verify the input file */
+ if (verify_seama(o_images[i], 0) < 0)
+ {
+ printf("SEAMA: '%s' is not a seama file !\n", o_images[i]);
+ continue;
+ }
+ /* open the input file */
+ ifh = fopen(o_images[i], "r");
+ if (!ifh) continue;
+ /* read file */
+ while (!feof(ifh) && !ferror(ifh))
+ {
+ /* read header */
+ fread(&shdr, sizeof(shdr), 1, ifh);
+ if (shdr.magic != htonl(SEAMA_MAGIC)) break;
+ /* Get the size */
+ isize = ntohl(shdr.size);
+ msize = ntohs(shdr.metasize);
+ if (isize == 0)
+ {
+ while (msize > 0)
+ {
+ m = fread(buf, sizeof(char), (msize < MAX_SEAMA_META_SIZE) ? msize : MAX_SEAMA_META_SIZE, ifh);
+ if (m <= 0) break;
+ msize -= m;
+ }
+ continue;
+ }
+ /* read checksum */
+ fread(buf, sizeof(char), 16, ifh);
+ if (msize > 0)
+ {
+ /* read META */
+ fread(buf, sizeof(char), msize, ifh);
+ if (match_meta((const char *)buf, msize))
+ {
+ printf("SEAMA: found image @ '%s', image size: %zu\n", o_images[i], isize);
+ /* open output file */
+ ofh = fopen(output, "w");
+ if (!ofh) printf("SEAMA: unable to open '%s' for writting.\n",output);
+ else
+ {
+ while (isize > 0)
+ {
+ m = fread(buf, sizeof(char), (isize < MAX_SEAMA_META_SIZE) ? isize : MAX_SEAMA_META_SIZE, ifh);
+ if (m <= 0) break;
+ fwrite(buf, sizeof(char), m, ofh);
+ isize -= m;
+ }
+ fclose(ofh);
+ }
+ done++;
+ break;
+ }
+ }
+ while (isize > 0)
+ {
+ m = fread(buf, sizeof(char), (isize < MAX_SEAMA_META_SIZE) ? isize : MAX_SEAMA_META_SIZE, ifh);
+ if (m <= 0) break;
+ isize -= m;
+ }
+ }
+ /* close the file. */
+ fclose(ifh);
+ if (done) break;
+ }
+ return;
+}
+
+/*******************************************************************/
+#ifdef RGBIN_BOX
+int seama_main(int argc, char * argv[], char * env[])
+#else
+int main(int argc, char * argv[], char * env[])
+#endif
+{
+ verbose("SEAMA version " VERSION "\n");
+
+ /* parse the arguments */
+ if (parse_args(argc, argv) < 0) show_usage(9);
+
+ /* Do the works */
+ if (o_dump) dump_seama(o_dump);
+ else if (o_seal) seal_files(o_seal);
+ else if (o_extract) extract_file(o_extract);
+ else pack_files();
+
+ cleanup_exit(0);
+ return 0;
+}
diff --git a/tools/firmware-utils/src/seama.h b/tools/firmware-utils/src/seama.h
new file mode 100644
index 00000000000..02683b6e98d
--- /dev/null
+++ b/tools/firmware-utils/src/seama.h
@@ -0,0 +1,108 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * (SEA)ttle i(MA)ge is the image which used in project seattle.
+ *
+ * Created by David Hsieh <david_hsieh@alphanetworks.com>
+ * Copyright (C) 2008-2009 Alpha Networks, Inc.
+ *
+ * This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either'
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * The GNU C Library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the GNU C Library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA.
+ */
+
+#ifndef __SEAMA_HEADER_FILE__
+#define __SEAMA_HEADER_FILE__
+
+#include <stdint.h>
+
+#define SEAMA_MAGIC 0x5EA3A417
+
+/*
+ * SEAMA looks like the following map.
+ * All the data of the header should be in network byte order.
+ *
+ * +-------------+-------------+------------
+ * | SEAMA magic | ^
+ * +-------------+-------------+ |
+ * | reserved | meta size | |
+ * +-------------+-------------+ header
+ * | image size (0 bytes) | |
+ * +-------------+-------------+ |
+ * ~ Meta data ~ v
+ * +-------------+-------------+------------
+ * | SEAMA magic | ^ ^
+ * +-------------+-------------+ | |
+ * | reserved | meta size | | |
+ * +-------------+-------------+ | |
+ * | image size | | |
+ * +-------------+-------------+ header |
+ * | | | |
+ * | 16 bytes of MD5 digest | | |
+ * | | | |
+ * | | | |
+ * +-------------+-------------+ | |
+ * ~ Meta data ~ v |
+ * +-------------+-------------+------- |
+ * | | |
+ * | Image of the 1st entity | |
+ * ~ ~ 1st entity
+ * | | |
+ * | | v
+ * +-------------+-------------+-------------
+ * | SEAMA magic | ^ ^
+ * +-------------+-------------+ | |
+ * | reserved | meta size | | |
+ * +-------------+-------------+ | |
+ * | image size | | |
+ * +-------------+-------------+ header |
+ * | | | |
+ * | 16 bytes of MD5 digest | | |
+ * | | | |
+ * | | | |
+ * +-------------+-------------+ | |
+ * ~ Meta data ~ v |
+ * +-------------+-------------+------- |
+ * | | |
+ * | Image of the 2nd entity | |
+ * ~ ~ 2nd entity
+ * | | |
+ * | | v
+ * +-------------+-------------+-------------
+ */
+
+
+/*
+ * SEAMA header
+ *
+ * |<-------- 32 bits -------->|
+ * +-------------+-------------+
+ * | SEAMA magic |
+ * +-------------+-------------+
+ * | reserved | meta size |
+ * +-------------+-------------+
+ * | image size |
+ * +-------------+-------------+
+ */
+/* seama header */
+typedef struct seama_hdr seamahdr_t;
+struct seama_hdr
+{
+ uint32_t magic; /* should always be SEAMA_MAGIC. */
+ uint16_t reserved; /* reserved for */
+ uint16_t metasize; /* size of the META data */
+ uint32_t size; /* size of the image */
+} __attribute__ ((packed));
+
+
+#endif
diff --git a/tools/firmware-utils/src/spw303v.c b/tools/firmware-utils/src/spw303v.c
index ae34a1ebddc..684532d7e11 100644
--- a/tools/firmware-utils/src/spw303v.c
+++ b/tools/firmware-utils/src/spw303v.c
@@ -18,11 +18,11 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
-#include <time.h>
#include <unistd.h>
#include <sys/stat.h>
diff --git a/tools/firmware-utils/src/srec2bin.c b/tools/firmware-utils/src/srec2bin.c
index 1cffbaed969..5cc71bda220 100644
--- a/tools/firmware-utils/src/srec2bin.c
+++ b/tools/firmware-utils/src/srec2bin.c
@@ -513,7 +513,7 @@ int srec2bin(int argc,char *argv[],int verbose)
return(1);
}
-main(int argc, char *argv[])
+int main(int argc, char *argv[])
{
debug = TRUE;
debug = FALSE;
diff --git a/tools/firmware-utils/src/tplink-safeloader.c b/tools/firmware-utils/src/tplink-safeloader.c
new file mode 100644
index 00000000000..78092bc535c
--- /dev/null
+++ b/tools/firmware-utils/src/tplink-safeloader.c
@@ -0,0 +1,2084 @@
+/*
+ Copyright (c) 2014, Matthias Schiffer <mschiffer@universe-factory.net>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+/*
+ tplink-safeloader
+
+ Image generation tool for the TP-LINK SafeLoader as seen on
+ TP-LINK Pharos devices (CPE210/220/510/520)
+*/
+
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <arpa/inet.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <limits.h>
+
+#include "md5.h"
+
+
+#define ALIGN(x,a) ({ typeof(a) __a = (a); (((x) + __a - 1) & ~(__a - 1)); })
+
+
+#define MAX_PARTITIONS 32
+
+/** An image partition table entry */
+struct image_partition_entry {
+ const char *name;
+ size_t size;
+ uint8_t *data;
+};
+
+/** A flash partition table entry */
+struct flash_partition_entry {
+ char *name;
+ uint32_t base;
+ uint32_t size;
+};
+
+/** Firmware layout description */
+struct device_info {
+ const char *id;
+ const char *vendor;
+ const char *support_list;
+ char support_trail;
+ const char *soft_ver;
+ struct flash_partition_entry partitions[MAX_PARTITIONS+1];
+ const char *first_sysupgrade_partition;
+ const char *last_sysupgrade_partition;
+};
+
+/** The content of the soft-version structure */
+struct __attribute__((__packed__)) soft_version {
+ uint32_t magic;
+ uint32_t zero;
+ uint8_t pad1;
+ uint8_t version_major;
+ uint8_t version_minor;
+ uint8_t version_patch;
+ uint8_t year_hi;
+ uint8_t year_lo;
+ uint8_t month;
+ uint8_t day;
+ uint32_t rev;
+ uint8_t pad2;
+};
+
+
+static const uint8_t jffs2_eof_mark[4] = {0xde, 0xad, 0xc0, 0xde};
+
+
+/**
+ Salt for the MD5 hash
+
+ Fortunately, TP-LINK seems to use the same salt for most devices which use
+ the new image format.
+*/
+static const uint8_t md5_salt[16] = {
+ 0x7a, 0x2b, 0x15, 0xed,
+ 0x9b, 0x98, 0x59, 0x6d,
+ 0xe5, 0x04, 0xab, 0x44,
+ 0xac, 0x2a, 0x9f, 0x4e,
+};
+
+
+/** Firmware layout table */
+static struct device_info boards[] = {
+ /** Firmware layout for the CPE210/220 */
+ {
+ .id = "CPE210",
+ .vendor = "CPE510(TP-LINK|UN|N300-5):1.0\r\n",
+ .support_list =
+ "SupportList:\r\n"
+ "CPE210(TP-LINK|UN|N300-2):1.0\r\n"
+ "CPE210(TP-LINK|UN|N300-2):1.1\r\n"
+ "CPE210(TP-LINK|US|N300-2):1.1\r\n"
+ "CPE210(TP-LINK|EU|N300-2):1.1\r\n"
+ "CPE220(TP-LINK|UN|N300-2):1.1\r\n"
+ "CPE220(TP-LINK|US|N300-2):1.1\r\n"
+ "CPE220(TP-LINK|EU|N300-2):1.1\r\n",
+ .support_trail = '\xff',
+ .soft_ver = NULL,
+
+ .partitions = {
+ {"fs-uboot", 0x00000, 0x20000},
+ {"partition-table", 0x20000, 0x02000},
+ {"default-mac", 0x30000, 0x00020},
+ {"product-info", 0x31100, 0x00100},
+ {"signature", 0x32000, 0x00400},
+ {"os-image", 0x40000, 0x1c0000},
+ {"file-system", 0x200000, 0x5b0000},
+ {"soft-version", 0x7b0000, 0x00100},
+ {"support-list", 0x7b1000, 0x00400},
+ {"user-config", 0x7c0000, 0x10000},
+ {"default-config", 0x7d0000, 0x10000},
+ {"log", 0x7e0000, 0x10000},
+ {"radio", 0x7f0000, 0x10000},
+ {NULL, 0, 0}
+ },
+
+ .first_sysupgrade_partition = "os-image",
+ .last_sysupgrade_partition = "support-list",
+ },
+
+ /** Firmware layout for the CPE210 V2 */
+ {
+ .id = "CPE210V2",
+ .vendor = "CPE210(TP-LINK|UN|N300-2|00000000):2.0\r\n",
+ .support_list =
+ "SupportList:\r\n"
+ "CPE210(TP-LINK|EU|N300-2|00000000):2.0\r\n"
+ "CPE210(TP-LINK|EU|N300-2|45550000):2.0\r\n"
+ "CPE210(TP-LINK|EU|N300-2|55530000):2.0\r\n"
+ "CPE210(TP-LINK|UN|N300-2|00000000):2.0\r\n"
+ "CPE210(TP-LINK|UN|N300-2|45550000):2.0\r\n"
+ "CPE210(TP-LINK|UN|N300-2|55530000):2.0\r\n"
+ "CPE210(TP-LINK|US|N300-2|55530000):2.0\r\n"
+ "CPE210(TP-LINK|UN|N300-2):2.0\r\n"
+ "CPE210(TP-LINK|EU|N300-2):2.0\r\n"
+ "CPE210(TP-LINK|US|N300-2):2.0\r\n",
+ .support_trail = '\xff',
+ .soft_ver = NULL,
+
+ .partitions = {
+ {"fs-uboot", 0x00000, 0x20000},
+ {"partition-table", 0x20000, 0x02000},
+ {"default-mac", 0x30000, 0x00020},
+ {"product-info", 0x31100, 0x00100},
+ {"device-info", 0x31400, 0x00400},
+ {"signature", 0x32000, 0x00400},
+ {"device-id", 0x33000, 0x00100},
+ {"os-image", 0x40000, 0x1c0000},
+ {"file-system", 0x200000, 0x5b0000},
+ {"soft-version", 0x7b0000, 0x00100},
+ {"support-list", 0x7b1000, 0x01000},
+ {"user-config", 0x7c0000, 0x10000},
+ {"default-config", 0x7d0000, 0x10000},
+ {"log", 0x7e0000, 0x10000},
+ {"radio", 0x7f0000, 0x10000},
+ {NULL, 0, 0}
+ },
+
+ .first_sysupgrade_partition = "os-image",
+ .last_sysupgrade_partition = "support-list",
+ },
+
+ /** Firmware layout for the CPE510/520 */
+ {
+ .id = "CPE510",
+ .vendor = "CPE510(TP-LINK|UN|N300-5):1.0\r\n",
+ .support_list =
+ "SupportList:\r\n"
+ "CPE510(TP-LINK|UN|N300-5):1.0\r\n"
+ "CPE510(TP-LINK|UN|N300-5):1.1\r\n"
+ "CPE510(TP-LINK|UN|N300-5):1.1\r\n"
+ "CPE510(TP-LINK|US|N300-5):1.1\r\n"
+ "CPE510(TP-LINK|EU|N300-5):1.1\r\n"
+ "CPE520(TP-LINK|UN|N300-5):1.1\r\n"
+ "CPE520(TP-LINK|US|N300-5):1.1\r\n"
+ "CPE520(TP-LINK|EU|N300-5):1.1\r\n"
+ "CPE510(TP-LINK|EU|N300-5|00000000):2.0\r\n"
+ "CPE510(TP-LINK|EU|N300-5|45550000):2.0\r\n"
+ "CPE510(TP-LINK|EU|N300-5|55530000):2.0\r\n"
+ "CPE510(TP-LINK|UN|N300-5|00000000):2.0\r\n"
+ "CPE510(TP-LINK|UN|N300-5|45550000):2.0\r\n"
+ "CPE510(TP-LINK|UN|N300-5|55530000):2.0\r\n"
+ "CPE510(TP-LINK|US|N300-5|55530000):2.0\r\n"
+ "CPE510(TP-LINK|UN|N300-5):2.0\r\n"
+ "CPE510(TP-LINK|EU|N300-5):2.0\r\n"
+ "CPE510(TP-LINK|US|N300-5):2.0\r\n",
+ .support_trail = '\xff',
+ .soft_ver = NULL,
+
+ .partitions = {
+ {"fs-uboot", 0x00000, 0x20000},
+ {"partition-table", 0x20000, 0x02000},
+ {"default-mac", 0x30000, 0x00020},
+ {"product-info", 0x31100, 0x00100},
+ {"signature", 0x32000, 0x00400},
+ {"os-image", 0x40000, 0x1c0000},
+ {"file-system", 0x200000, 0x5b0000},
+ {"soft-version", 0x7b0000, 0x00100},
+ {"support-list", 0x7b1000, 0x00400},
+ {"user-config", 0x7c0000, 0x10000},
+ {"default-config", 0x7d0000, 0x10000},
+ {"log", 0x7e0000, 0x10000},
+ {"radio", 0x7f0000, 0x10000},
+ {NULL, 0, 0}
+ },
+
+ .first_sysupgrade_partition = "os-image",
+ .last_sysupgrade_partition = "support-list",
+ },
+
+ {
+ .id = "WBS210",
+ .vendor = "CPE510(TP-LINK|UN|N300-5):1.0\r\n",
+ .support_list =
+ "SupportList:\r\n"
+ "WBS210(TP-LINK|UN|N300-2):1.20\r\n"
+ "WBS210(TP-LINK|US|N300-2):1.20\r\n"
+ "WBS210(TP-LINK|EU|N300-2):1.20\r\n",
+ .support_trail = '\xff',
+ .soft_ver = NULL,
+
+ .partitions = {
+ {"fs-uboot", 0x00000, 0x20000},
+ {"partition-table", 0x20000, 0x02000},
+ {"default-mac", 0x30000, 0x00020},
+ {"product-info", 0x31100, 0x00100},
+ {"signature", 0x32000, 0x00400},
+ {"os-image", 0x40000, 0x1c0000},
+ {"file-system", 0x200000, 0x5b0000},
+ {"soft-version", 0x7b0000, 0x00100},
+ {"support-list", 0x7b1000, 0x00400},
+ {"user-config", 0x7c0000, 0x10000},
+ {"default-config", 0x7d0000, 0x10000},
+ {"log", 0x7e0000, 0x10000},
+ {"radio", 0x7f0000, 0x10000},
+ {NULL, 0, 0}
+ },
+
+ .first_sysupgrade_partition = "os-image",
+ .last_sysupgrade_partition = "support-list",
+ },
+
+ {
+ .id = "WBS510",
+ .vendor = "CPE510(TP-LINK|UN|N300-5):1.0\r\n",
+ .support_list =
+ "SupportList:\r\n"
+ "WBS510(TP-LINK|UN|N300-5):1.20\r\n"
+ "WBS510(TP-LINK|US|N300-5):1.20\r\n"
+ "WBS510(TP-LINK|EU|N300-5):1.20\r\n",
+ .support_trail = '\xff',
+ .soft_ver = NULL,
+
+ .partitions = {
+ {"fs-uboot", 0x00000, 0x20000},
+ {"partition-table", 0x20000, 0x02000},
+ {"default-mac", 0x30000, 0x00020},
+ {"product-info", 0x31100, 0x00100},
+ {"signature", 0x32000, 0x00400},
+ {"os-image", 0x40000, 0x1c0000},
+ {"file-system", 0x200000, 0x5b0000},
+ {"soft-version", 0x7b0000, 0x00100},
+ {"support-list", 0x7b1000, 0x00400},
+ {"user-config", 0x7c0000, 0x10000},
+ {"default-config", 0x7d0000, 0x10000},
+ {"log", 0x7e0000, 0x10000},
+ {"radio", 0x7f0000, 0x10000},
+ {NULL, 0, 0}
+ },
+
+ .first_sysupgrade_partition = "os-image",
+ .last_sysupgrade_partition = "support-list",
+ },
+
+ /** Firmware layout for the C2600 */
+ {
+ .id = "C2600",
+ .vendor = "",
+ .support_list =
+ "SupportList:\r\n"
+ "{product_name:Archer C2600,product_ver:1.0.0,special_id:00000000}\r\n",
+ .support_trail = '\x00',
+ .soft_ver = NULL,
+
+ /**
+ We use a bigger os-image partition than the stock images (and thus
+ smaller file-system), as our kernel doesn't fit in the stock firmware's
+ 2 MB os-image since kernel 4.14.
+ */
+ .partitions = {
+ {"SBL1", 0x00000, 0x20000},
+ {"MIBIB", 0x20000, 0x20000},
+ {"SBL2", 0x40000, 0x20000},
+ {"SBL3", 0x60000, 0x30000},
+ {"DDRCONFIG", 0x90000, 0x10000},
+ {"SSD", 0xa0000, 0x10000},
+ {"TZ", 0xb0000, 0x30000},
+ {"RPM", 0xe0000, 0x20000},
+ {"fs-uboot", 0x100000, 0x70000},
+ {"uboot-env", 0x170000, 0x40000},
+ {"radio", 0x1b0000, 0x40000},
+ {"os-image", 0x1f0000, 0x400000}, /* Stock: base 0x1f0000 size 0x200000 */
+ {"file-system", 0x5f0000, 0x1900000}, /* Stock: base 0x3f0000 size 0x1b00000 */
+ {"default-mac", 0x1ef0000, 0x00200},
+ {"pin", 0x1ef0200, 0x00200},
+ {"product-info", 0x1ef0400, 0x0fc00},
+ {"partition-table", 0x1f00000, 0x10000},
+ {"soft-version", 0x1f10000, 0x10000},
+ {"support-list", 0x1f20000, 0x10000},
+ {"profile", 0x1f30000, 0x10000},
+ {"default-config", 0x1f40000, 0x10000},
+ {"user-config", 0x1f50000, 0x40000},
+ {"qos-db", 0x1f90000, 0x40000},
+ {"usb-config", 0x1fd0000, 0x10000},
+ {"log", 0x1fe0000, 0x20000},
+ {NULL, 0, 0}
+ },
+
+ .first_sysupgrade_partition = "os-image",
+ .last_sysupgrade_partition = "file-system"
+ },
+
+ /** Firmware layout for the C25v1 */
+ {
+ .id = "ARCHER-C25-V1",
+ .support_list =
+ "SupportList:\n"
+ "{product_name:ArcherC25,product_ver:1.0.0,special_id:00000000}\n"
+ "{product_name:ArcherC25,product_ver:1.0.0,special_id:55530000}\n"
+ "{product_name:ArcherC25,product_ver:1.0.0,special_id:45550000}\n",
+ .support_trail = '\x00',
+ .soft_ver = "soft_ver:1.0.0\n",
+
+ /**
+ We use a bigger os-image partition than the stock images (and thus
+ smaller file-system), as our kernel doesn't fit in the stock firmware's
+ 1MB os-image.
+ */
+ .partitions = {
+ {"factory-boot", 0x00000, 0x20000},
+ {"fs-uboot", 0x20000, 0x10000},
+ {"os-image", 0x30000, 0x180000}, /* Stock: base 0x30000 size 0x100000 */
+ {"file-system", 0x1b0000, 0x620000}, /* Stock: base 0x130000 size 0x6a0000 */
+ {"user-config", 0x7d0000, 0x04000},
+ {"default-mac", 0x7e0000, 0x00100},
+ {"device-id", 0x7e0100, 0x00100},
+ {"extra-para", 0x7e0200, 0x00100},
+ {"pin", 0x7e0300, 0x00100},
+ {"support-list", 0x7e0400, 0x00400},
+ {"soft-version", 0x7e0800, 0x00400},
+ {"product-info", 0x7e0c00, 0x01400},
+ {"partition-table", 0x7e2000, 0x01000},
+ {"profile", 0x7e3000, 0x01000},
+ {"default-config", 0x7e4000, 0x04000},
+ {"merge-config", 0x7ec000, 0x02000},
+ {"qos-db", 0x7ee000, 0x02000},
+ {"radio", 0x7f0000, 0x10000},
+ {NULL, 0, 0}
+ },
+
+ .first_sysupgrade_partition = "os-image",
+ .last_sysupgrade_partition = "file-system",
+ },
+
+ /** Firmware layout for the C58v1 */
+ {
+ .id = "ARCHER-C58-V1",
+ .vendor = "",
+ .support_list =
+ "SupportList:\r\n"
+ "{product_name:Archer C58,product_ver:1.0.0,special_id:00000000}\r\n"
+ "{product_name:Archer C58,product_ver:1.0.0,special_id:45550000}\r\n"
+ "{product_name:Archer C58,product_ver:1.0.0,special_id:55530000}\r\n",
+ .support_trail = '\x00',
+ .soft_ver = "soft_ver:1.0.0\n",
+
+ .partitions = {
+ {"fs-uboot", 0x00000, 0x10000},
+ {"default-mac", 0x10000, 0x00200},
+ {"pin", 0x10200, 0x00200},
+ {"product-info", 0x10400, 0x00100},
+ {"partition-table", 0x10500, 0x00800},
+ {"soft-version", 0x11300, 0x00200},
+ {"support-list", 0x11500, 0x00100},
+ {"device-id", 0x11600, 0x00100},
+ {"profile", 0x11700, 0x03900},
+ {"default-config", 0x15000, 0x04000},
+ {"user-config", 0x19000, 0x04000},
+ {"os-image", 0x20000, 0x180000},
+ {"file-system", 0x1a0000, 0x648000},
+ {"certyficate", 0x7e8000, 0x08000},
+ {"radio", 0x7f0000, 0x10000},
+ {NULL, 0, 0}
+ },
+
+ .first_sysupgrade_partition = "os-image",
+ .last_sysupgrade_partition = "file-system",
+ },
+
+ /** Firmware layout for the C59v1 */
+ {
+ .id = "ARCHER-C59-V1",
+ .vendor = "",
+ .support_list =
+ "SupportList:\r\n"
+ "{product_name:Archer C59,product_ver:1.0.0,special_id:00000000}\r\n"
+ "{product_name:Archer C59,product_ver:1.0.0,special_id:45550000}\r\n"
+ "{product_name:Archer C59,product_ver:1.0.0,special_id:52550000}\r\n"
+ "{product_name:Archer C59,product_ver:1.0.0,special_id:55530000}\r\n",
+ .support_trail = '\x00',
+ .soft_ver = "soft_ver:1.0.0\n",
+
+ .partitions = {
+ {"fs-uboot", 0x00000, 0x10000},
+ {"default-mac", 0x10000, 0x00200},
+ {"pin", 0x10200, 0x00200},
+ {"device-id", 0x10400, 0x00100},
+ {"product-info", 0x10500, 0x0fb00},
+ {"os-image", 0x20000, 0x180000},
+ {"file-system", 0x1a0000, 0xcb0000},
+ {"partition-table", 0xe50000, 0x10000},
+ {"soft-version", 0xe60000, 0x10000},
+ {"support-list", 0xe70000, 0x10000},
+ {"profile", 0xe80000, 0x10000},
+ {"default-config", 0xe90000, 0x10000},
+ {"user-config", 0xea0000, 0x40000},
+ {"usb-config", 0xee0000, 0x10000},
+ {"certificate", 0xef0000, 0x10000},
+ {"qos-db", 0xf00000, 0x40000},
+ {"log", 0xfe0000, 0x10000},
+ {"radio", 0xff0000, 0x10000},
+ {NULL, 0, 0}
+ },
+
+ .first_sysupgrade_partition = "os-image",
+ .last_sysupgrade_partition = "file-system",
+ },
+
+ /** Firmware layout for the C59v2 */
+ {
+ .id = "ARCHER-C59-V2",
+ .vendor = "",
+ .support_list =
+ "SupportList:\r\n"
+ "{product_name:Archer C59,product_ver:2.0.0,special_id:00000000}\r\n"
+ "{product_name:Archer C59,product_ver:2.0.0,special_id:45550000}\r\n"
+ "{product_name:Archer C59,product_ver:2.0.0,special_id:55530000}\r\n",
+ .support_trail = '\x00',
+ .soft_ver = "soft_ver:2.0.0 Build 20161206 rel.7303\n",
+
+ /** We're using a dynamic kernel/rootfs split here */
+ .partitions = {
+ {"factory-boot", 0x00000, 0x20000},
+ {"fs-uboot", 0x20000, 0x10000},
+ {"default-mac", 0x30000, 0x00200},
+ {"pin", 0x30200, 0x00200},
+ {"device-id", 0x30400, 0x00100},
+ {"product-info", 0x30500, 0x0fb00},
+ {"firmware", 0x40000, 0xe10000},
+ {"partition-table", 0xe50000, 0x10000},
+ {"soft-version", 0xe60000, 0x10000},
+ {"support-list", 0xe70000, 0x10000},
+ {"profile", 0xe80000, 0x10000},
+ {"default-config", 0xe90000, 0x10000},
+ {"user-config", 0xea0000, 0x40000},
+ {"usb-config", 0xee0000, 0x10000},
+ {"certificate", 0xef0000, 0x10000},
+ {"extra-para", 0xf00000, 0x10000},
+ {"qos-db", 0xf10000, 0x30000},
+ {"log", 0xfe0000, 0x10000},
+ {"radio", 0xff0000, 0x10000},
+ {NULL, 0, 0}
+ },
+
+ .first_sysupgrade_partition = "os-image",
+ .last_sysupgrade_partition = "file-system",
+ },
+
+ /** Firmware layout for the C60v1 */
+ {
+ .id = "ARCHER-C60-V1",
+ .vendor = "",
+ .support_list =
+ "SupportList:\r\n"
+ "{product_name:Archer C60,product_ver:1.0.0,special_id:00000000}\r\n"
+ "{product_name:Archer C60,product_ver:1.0.0,special_id:45550000}\r\n"
+ "{product_name:Archer C60,product_ver:1.0.0,special_id:55530000}\r\n",
+ .support_trail = '\x00',
+ .soft_ver = "soft_ver:1.0.0\n",
+
+ .partitions = {
+ {"fs-uboot", 0x00000, 0x10000},
+ {"default-mac", 0x10000, 0x00200},
+ {"pin", 0x10200, 0x00200},
+ {"product-info", 0x10400, 0x00100},
+ {"partition-table", 0x10500, 0x00800},
+ {"soft-version", 0x11300, 0x00200},
+ {"support-list", 0x11500, 0x00100},
+ {"device-id", 0x11600, 0x00100},
+ {"profile", 0x11700, 0x03900},
+ {"default-config", 0x15000, 0x04000},
+ {"user-config", 0x19000, 0x04000},
+ {"os-image", 0x20000, 0x180000},
+ {"file-system", 0x1a0000, 0x648000},
+ {"certyficate", 0x7e8000, 0x08000},
+ {"radio", 0x7f0000, 0x10000},
+ {NULL, 0, 0}
+ },
+
+ .first_sysupgrade_partition = "os-image",
+ .last_sysupgrade_partition = "file-system",
+ },
+
+ /** Firmware layout for the C60v2 */
+ {
+ .id = "ARCHER-C60-V2",
+ .vendor = "",
+ .support_list =
+ "SupportList:\r\n"
+ "{product_name:Archer C60,product_ver:2.0.0,special_id:42520000}\r\n"
+ "{product_name:Archer C60,product_ver:2.0.0,special_id:45550000}\r\n"
+ "{product_name:Archer C60,product_ver:2.0.0,special_id:55530000}\r\n",
+ .support_trail = '\x00',
+ .soft_ver = "soft_ver:2.0.0\n",
+
+ .partitions = {
+ {"factory-boot", 0x00000, 0x1fb00},
+ {"default-mac", 0x1fb00, 0x00200},
+ {"pin", 0x1fd00, 0x00100},
+ {"product-info", 0x1fe00, 0x00100},
+ {"device-id", 0x1ff00, 0x00100},
+ {"fs-uboot", 0x20000, 0x10000},
+ {"os-image", 0x30000, 0x180000},
+ {"file-system", 0x1b0000, 0x620000},
+ {"soft-version", 0x7d9500, 0x00100},
+ {"support-list", 0x7d9600, 0x00100},
+ {"extra-para", 0x7d9700, 0x00100},
+ {"profile", 0x7d9800, 0x03000},
+ {"default-config", 0x7dc800, 0x03000},
+ {"partition-table", 0x7df800, 0x00800},
+ {"user-config", 0x7e0000, 0x0c000},
+ {"certificate", 0x7ec000, 0x04000},
+ {"radio", 0x7f0000, 0x10000},
+ {NULL, 0, 0}
+ },
+
+ .first_sysupgrade_partition = "os-image",
+ .last_sysupgrade_partition = "file-system",
+ },
+
+ /** Firmware layout for the C5 */
+ {
+ .id = "ARCHER-C5-V2",
+ .vendor = "",
+ .support_list =
+ "SupportList:\r\n"
+ "{product_name:ArcherC5,product_ver:2.0.0,special_id:00000000}\r\n"
+ "{product_name:ArcherC5,product_ver:2.0.0,special_id:55530000}\r\n"
+ "{product_name:ArcherC5,product_ver:2.0.0,special_id:4A500000}\r\n", /* JP version */
+ .support_trail = '\x00',
+ .soft_ver = NULL,
+
+ .partitions = {
+ {"fs-uboot", 0x00000, 0x40000},
+ {"os-image", 0x40000, 0x200000},
+ {"file-system", 0x240000, 0xc00000},
+ {"default-mac", 0xe40000, 0x00200},
+ {"pin", 0xe40200, 0x00200},
+ {"product-info", 0xe40400, 0x00200},
+ {"partition-table", 0xe50000, 0x10000},
+ {"soft-version", 0xe60000, 0x00200},
+ {"support-list", 0xe61000, 0x0f000},
+ {"profile", 0xe70000, 0x10000},
+ {"default-config", 0xe80000, 0x10000},
+ {"user-config", 0xe90000, 0x50000},
+ {"log", 0xee0000, 0x100000},
+ {"radio_bk", 0xfe0000, 0x10000},
+ {"radio", 0xff0000, 0x10000},
+ {NULL, 0, 0}
+ },
+
+ .first_sysupgrade_partition = "os-image",
+ .last_sysupgrade_partition = "file-system"
+ },
+
+ /** Firmware layout for the C7 */
+ {
+ .id = "ARCHER-C7-V4",
+ .support_list =
+ "SupportList:\n"
+ "{product_name:Archer C7,product_ver:4.0.0,special_id:00000000}\n"
+ "{product_name:Archer C7,product_ver:4.0.0,special_id:41550000}\n"
+ "{product_name:Archer C7,product_ver:4.0.0,special_id:45550000}\n"
+ "{product_name:Archer C7,product_ver:4.0.0,special_id:4B520000}\n"
+ "{product_name:Archer C7,product_ver:4.0.0,special_id:42520000}\n"
+ "{product_name:Archer C7,product_ver:4.0.0,special_id:4A500000}\n"
+ "{product_name:Archer C7,product_ver:4.0.0,special_id:52550000}\n"
+ "{product_name:Archer C7,product_ver:4.0.0,special_id:54570000}\n"
+ "{product_name:Archer C7,product_ver:4.0.0,special_id:55530000}\n"
+ "{product_name:Archer C7,product_ver:4.0.0,special_id:43410000}\n",
+ .support_trail = '\x00',
+ .soft_ver = "soft_ver:1.0.0\n",
+
+ /**
+ We use a bigger os-image partition than the stock images (and thus
+ smaller file-system), as our kernel doesn't fit in the stock firmware's
+ 1MB os-image.
+ */
+ .partitions = {
+ {"factory-boot", 0x00000, 0x20000},
+ {"fs-uboot", 0x20000, 0x20000},
+ {"os-image", 0x40000, 0x180000}, /* Stock: base 0x40000 size 0x120000 */
+ {"file-system", 0x1c0000, 0xd40000}, /* Stock: base 0x160000 size 0xda0000 */
+ {"default-mac", 0xf00000, 0x00200},
+ {"pin", 0xf00200, 0x00200},
+ {"device-id", 0xf00400, 0x00100},
+ {"product-info", 0xf00500, 0x0fb00},
+ {"soft-version", 0xf10000, 0x00100},
+ {"extra-para", 0xf11000, 0x01000},
+ {"support-list", 0xf12000, 0x0a000},
+ {"profile", 0xf1c000, 0x04000},
+ {"default-config", 0xf20000, 0x10000},
+ {"user-config", 0xf30000, 0x40000},
+ {"qos-db", 0xf70000, 0x40000},
+ {"certificate", 0xfb0000, 0x10000},
+ {"partition-table", 0xfc0000, 0x10000},
+ {"log", 0xfd0000, 0x20000},
+ {"radio", 0xff0000, 0x10000},
+ {NULL, 0, 0}
+ },
+
+ .first_sysupgrade_partition = "os-image",
+ .last_sysupgrade_partition = "file-system",
+ },
+
+ /** Firmware layout for the C7 v5*/
+ {
+ .id = "ARCHER-C7-V5",
+ .support_list =
+ "SupportList:\n"
+ "{product_name:Archer C7,product_ver:5.0.0,special_id:00000000}\n"
+ "{product_name:Archer C7,product_ver:5.0.0,special_id:55530000}\n",
+
+ .support_trail = '\x00',
+ .soft_ver = "soft_ver:1.0.0\n",
+
+ /**
+ We use a bigger os-image partition than the stock images (and thus
+ smaller file-system), as our kernel doesn't fit in the stock firmware's
+ 1MB os-image.
+ */
+ .partitions = {
+ {"factory-boot", 0x00000, 0x20000},
+ {"fs-uboot", 0x20000, 0x20000},
+ {"partition-table", 0x40000, 0x10000},
+ {"radio", 0x50000, 0x10000},
+ {"default-mac", 0x60000, 0x00200},
+ {"pin", 0x60200, 0x00200},
+ {"device-id", 0x60400, 0x00100},
+ {"product-info", 0x60500, 0x0fb00},
+ {"soft-version", 0x70000, 0x01000},
+ {"extra-para", 0x71000, 0x01000},
+ {"support-list", 0x72000, 0x0a000},
+ {"profile", 0x7c000, 0x04000},
+ {"user-config", 0x80000, 0x40000},
+
+
+ {"os-image", 0xc0000, 0x180000}, /* Stock: base 0xc0000 size 0x120000 */
+ {"file-system", 0x240000, 0xd80000}, /* Stock: base 0x1e0000 size 0xde0000 */
+
+ {"log", 0xfc0000, 0x20000},
+ {"certificate", 0xfe0000, 0x10000},
+ {"default-config", 0xff0000, 0x10000},
+ {NULL, 0, 0}
+
+ },
+
+ .first_sysupgrade_partition = "os-image",
+ .last_sysupgrade_partition = "file-system",
+ },
+
+ /** Firmware layout for the C9 */
+ {
+ .id = "ARCHERC9",
+ .vendor = "",
+ .support_list =
+ "SupportList:\n"
+ "{product_name:ArcherC9,"
+ "product_ver:1.0.0,"
+ "special_id:00000000}\n",
+ .support_trail = '\x00',
+ .soft_ver = NULL,
+
+ .partitions = {
+ {"fs-uboot", 0x00000, 0x40000},
+ {"os-image", 0x40000, 0x200000},
+ {"file-system", 0x240000, 0xc00000},
+ {"default-mac", 0xe40000, 0x00200},
+ {"pin", 0xe40200, 0x00200},
+ {"product-info", 0xe40400, 0x00200},
+ {"partition-table", 0xe50000, 0x10000},
+ {"soft-version", 0xe60000, 0x00200},
+ {"support-list", 0xe61000, 0x0f000},
+ {"profile", 0xe70000, 0x10000},
+ {"default-config", 0xe80000, 0x10000},
+ {"user-config", 0xe90000, 0x50000},
+ {"log", 0xee0000, 0x100000},
+ {"radio_bk", 0xfe0000, 0x10000},
+ {"radio", 0xff0000, 0x10000},
+ {NULL, 0, 0}
+ },
+
+ .first_sysupgrade_partition = "os-image",
+ .last_sysupgrade_partition = "file-system"
+ },
+
+ /** Firmware layout for the EAP120 */
+ {
+ .id = "EAP120",
+ .vendor = "EAP120(TP-LINK|UN|N300-2):1.0\r\n",
+ .support_list =
+ "SupportList:\r\n"
+ "EAP120(TP-LINK|UN|N300-2):1.0\r\n",
+ .support_trail = '\xff',
+ .soft_ver = NULL,
+
+ .partitions = {
+ {"fs-uboot", 0x00000, 0x20000},
+ {"partition-table", 0x20000, 0x02000},
+ {"default-mac", 0x30000, 0x00020},
+ {"support-list", 0x31000, 0x00100},
+ {"product-info", 0x31100, 0x00100},
+ {"soft-version", 0x32000, 0x00100},
+ {"os-image", 0x40000, 0x180000},
+ {"file-system", 0x1c0000, 0x600000},
+ {"user-config", 0x7c0000, 0x10000},
+ {"backup-config", 0x7d0000, 0x10000},
+ {"log", 0x7e0000, 0x10000},
+ {"radio", 0x7f0000, 0x10000},
+ {NULL, 0, 0}
+ },
+
+ .first_sysupgrade_partition = "os-image",
+ .last_sysupgrade_partition = "file-system"
+ },
+
+ /** Firmware layout for the TL-WA850RE v2 */
+ {
+ .id = "TLWA850REV2",
+ .vendor = "",
+ .support_list =
+ "SupportList:\n"
+ "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:55530000}\n"
+ "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:00000000}\n"
+ "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:55534100}\n"
+ "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:45550000}\n"
+ "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:4B520000}\n"
+ "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:42520000}\n"
+ "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:4A500000}\n"
+ "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:43410000}\n"
+ "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:41550000}\n"
+ "{product_name:TL-WA850RE,product_ver:2.0.0,special_id:52550000}\n",
+ .support_trail = '\x00',
+ .soft_ver = NULL,
+
+ /**
+ 576KB were moved from file-system to os-image
+ in comparison to the stock image
+ */
+ .partitions = {
+ {"fs-uboot", 0x00000, 0x20000},
+ {"os-image", 0x20000, 0x150000},
+ {"file-system", 0x170000, 0x240000},
+ {"partition-table", 0x3b0000, 0x02000},
+ {"default-mac", 0x3c0000, 0x00020},
+ {"pin", 0x3c0100, 0x00020},
+ {"product-info", 0x3c1000, 0x01000},
+ {"soft-version", 0x3c2000, 0x00100},
+ {"support-list", 0x3c3000, 0x01000},
+ {"profile", 0x3c4000, 0x08000},
+ {"user-config", 0x3d0000, 0x10000},
+ {"default-config", 0x3e0000, 0x10000},
+ {"radio", 0x3f0000, 0x10000},
+ {NULL, 0, 0}
+ },
+
+ .first_sysupgrade_partition = "os-image",
+ .last_sysupgrade_partition = "file-system"
+ },
+
+ /** Firmware layout for the TL-WA855RE v1 */
+ {
+ .id = "TLWA855REV1",
+ .vendor = "",
+ .support_list =
+ "SupportList:\n"
+ "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:00000000}\n"
+ "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:55530000}\n"
+ "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:45550000}\n"
+ "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:4B520000}\n"
+ "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:42520000}\n"
+ "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:4A500000}\n"
+ "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:43410000}\n"
+ "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:41550000}\n"
+ "{product_name:TL-WA855RE,product_ver:1.0.0,special_id:52550000}\n",
+ .support_trail = '\x00',
+ .soft_ver = NULL,
+
+ .partitions = {
+ {"fs-uboot", 0x00000, 0x20000},
+ {"os-image", 0x20000, 0x150000},
+ {"file-system", 0x170000, 0x240000},
+ {"partition-table", 0x3b0000, 0x02000},
+ {"default-mac", 0x3c0000, 0x00020},
+ {"pin", 0x3c0100, 0x00020},
+ {"product-info", 0x3c1000, 0x01000},
+ {"soft-version", 0x3c2000, 0x00100},
+ {"support-list", 0x3c3000, 0x01000},
+ {"profile", 0x3c4000, 0x08000},
+ {"user-config", 0x3d0000, 0x10000},
+ {"default-config", 0x3e0000, 0x10000},
+ {"radio", 0x3f0000, 0x10000},
+ {NULL, 0, 0}
+ },
+
+ .first_sysupgrade_partition = "os-image",
+ .last_sysupgrade_partition = "file-system"
+ },
+
+ /** Firmware layout for the TL-WR1043 v5 */
+ {
+ .id = "TLWR1043NV5",
+ .vendor = "",
+ .support_list =
+ "SupportList:\n"
+ "{product_name:TL-WR1043N,product_ver:5.0.0,special_id:45550000}\n"
+ "{product_name:TL-WR1043N,product_ver:5.0.0,special_id:55530000}\n",
+ .support_trail = '\x00',
+ .soft_ver = "soft_ver:1.0.0\n",
+ .partitions = {
+ {"factory-boot", 0x00000, 0x20000},
+ {"fs-uboot", 0x20000, 0x20000},
+ {"os-image", 0x40000, 0x180000},
+ {"file-system", 0x1c0000, 0xd40000},
+ {"default-mac", 0xf00000, 0x00200},
+ {"pin", 0xf00200, 0x00200},
+ {"device-id", 0xf00400, 0x00100},
+ {"product-info", 0xf00500, 0x0fb00},
+ {"soft-version", 0xf10000, 0x01000},
+ {"extra-para", 0xf11000, 0x01000},
+ {"support-list", 0xf12000, 0x0a000},
+ {"profile", 0xf1c000, 0x04000},
+ {"default-config", 0xf20000, 0x10000},
+ {"user-config", 0xf30000, 0x40000},
+ {"qos-db", 0xf70000, 0x40000},
+ {"certificate", 0xfb0000, 0x10000},
+ {"partition-table", 0xfc0000, 0x10000},
+ {"log", 0xfd0000, 0x20000},
+ {"radio", 0xff0000, 0x10000},
+ {NULL, 0, 0}
+ },
+ .first_sysupgrade_partition = "os-image",
+ .last_sysupgrade_partition = "file-system"
+ },
+
+ /** Firmware layout for the TL-WR1043 v4 */
+ {
+ .id = "TLWR1043NDV4",
+ .vendor = "",
+ .support_list =
+ "SupportList:\n"
+ "{product_name:TL-WR1043ND,product_ver:4.0.0,special_id:45550000}\n",
+ .support_trail = '\x00',
+ .soft_ver = NULL,
+
+ /* We're using a dynamic kernel/rootfs split here */
+ .partitions = {
+ {"fs-uboot", 0x00000, 0x20000},
+ {"firmware", 0x20000, 0xf30000},
+ {"default-mac", 0xf50000, 0x00200},
+ {"pin", 0xf50200, 0x00200},
+ {"product-info", 0xf50400, 0x0fc00},
+ {"soft-version", 0xf60000, 0x0b000},
+ {"support-list", 0xf6b000, 0x04000},
+ {"profile", 0xf70000, 0x04000},
+ {"default-config", 0xf74000, 0x0b000},
+ {"user-config", 0xf80000, 0x40000},
+ {"partition-table", 0xfc0000, 0x10000},
+ {"log", 0xfd0000, 0x20000},
+ {"radio", 0xff0000, 0x10000},
+ {NULL, 0, 0}
+ },
+
+ .first_sysupgrade_partition = "os-image",
+ .last_sysupgrade_partition = "file-system"
+ },
+
+ /** Firmware layout for the TL-WR902AC v1 */
+ {
+ .id = "TL-WR902AC-V1",
+ .vendor = "",
+ .support_list =
+ "SupportList:\n"
+ "{product_name:TL-WR902AC,product_ver:1.0.0,special_id:45550000}\n"
+ "{product_name:TL-WR902AC,product_ver:1.0.0,special_id:55530000}\n",
+ .support_trail = '\x00',
+ .soft_ver = NULL,
+
+ /**
+ 384KB were moved from file-system to os-image
+ in comparison to the stock image
+ */
+ .partitions = {
+ {"fs-uboot", 0x00000, 0x20000},
+ {"os-image", 0x20000, 0x180000},
+ {"file-system", 0x1a0000, 0x5b0000},
+ {"default-mac", 0x750000, 0x00200},
+ {"pin", 0x750200, 0x00200},
+ {"product-info", 0x750400, 0x0fc00},
+ {"soft-version", 0x760000, 0x0b000},
+ {"support-list", 0x76b000, 0x04000},
+ {"profile", 0x770000, 0x04000},
+ {"default-config", 0x774000, 0x0b000},
+ {"user-config", 0x780000, 0x40000},
+ {"partition-table", 0x7c0000, 0x10000},
+ {"log", 0x7d0000, 0x20000},
+ {"radio", 0x7f0000, 0x10000},
+ {NULL, 0, 0}
+ },
+
+ .first_sysupgrade_partition = "os-image",
+ .last_sysupgrade_partition = "file-system",
+ },
+
+ /** Firmware layout for the TL-WR942N V1 */
+ {
+ .id = "TLWR942NV1",
+ .vendor = "",
+ .support_list =
+ "SupportList:\r\n"
+ "{product_name:TL-WR942N,product_ver:1.0.0,special_id:00000000}\r\n"
+ "{product_name:TL-WR942N,product_ver:1.0.0,special_id:52550000}\r\n",
+ .support_trail = '\x00',
+ .soft_ver = NULL,
+
+ .partitions = {
+ {"fs-uboot", 0x00000, 0x20000},
+ {"os-image", 0x20000, 0x180000},
+ {"file-system", 0x1a0000, 0xca0000},
+ {"default-mac", 0xe40000, 0x00200},
+ {"pin", 0xe40200, 0x00200},
+ {"product-info", 0xe40400, 0x0fc00},
+ {"partition-table", 0xe50000, 0x10000},
+ {"soft-version", 0xe60000, 0x10000},
+ {"support-list", 0xe70000, 0x10000},
+ {"profile", 0xe80000, 0x10000},
+ {"default-config", 0xe90000, 0x10000},
+ {"user-config", 0xea0000, 0x40000},
+ {"qos-db", 0xee0000, 0x40000},
+ {"certificate", 0xf20000, 0x10000},
+ {"usb-config", 0xfb0000, 0x10000},
+ {"log", 0xfc0000, 0x20000},
+ {"radio-bk", 0xfe0000, 0x10000},
+ {"radio", 0xff0000, 0x10000},
+ {NULL, 0, 0}
+ },
+
+ .first_sysupgrade_partition = "os-image",
+ .last_sysupgrade_partition = "file-system",
+ },
+
+ /** Firmware layout for the RE350 v1 */
+ {
+ .id = "RE350-V1",
+ .vendor = "",
+ .support_list =
+ "SupportList:\n"
+ "{product_name:RE350,product_ver:1.0.0,special_id:45550000}\n"
+ "{product_name:RE350,product_ver:1.0.0,special_id:00000000}\n"
+ "{product_name:RE350,product_ver:1.0.0,special_id:41550000}\n"
+ "{product_name:RE350,product_ver:1.0.0,special_id:55530000}\n"
+ "{product_name:RE350,product_ver:1.0.0,special_id:43410000}\n"
+ "{product_name:RE350,product_ver:1.0.0,special_id:4b520000}\n"
+ "{product_name:RE350,product_ver:1.0.0,special_id:4a500000}\n",
+ .support_trail = '\x00',
+ .soft_ver = NULL,
+
+ /** We're using a dynamic kernel/rootfs split here */
+ .partitions = {
+ {"fs-uboot", 0x00000, 0x20000},
+ {"firmware", 0x20000, 0x5e0000},
+ {"partition-table", 0x600000, 0x02000},
+ {"default-mac", 0x610000, 0x00020},
+ {"pin", 0x610100, 0x00020},
+ {"product-info", 0x611100, 0x01000},
+ {"soft-version", 0x620000, 0x01000},
+ {"support-list", 0x621000, 0x01000},
+ {"profile", 0x622000, 0x08000},
+ {"user-config", 0x630000, 0x10000},
+ {"default-config", 0x640000, 0x10000},
+ {"radio", 0x7f0000, 0x10000},
+ {NULL, 0, 0}
+ },
+
+ .first_sysupgrade_partition = "os-image",
+ .last_sysupgrade_partition = "file-system"
+ },
+
+ /** Firmware layout for the RE355 */
+ {
+ .id = "RE355",
+ .vendor = "",
+ .support_list =
+ "SupportList:\r\n"
+ "{product_name:RE355,product_ver:1.0.0,special_id:00000000}\r\n"
+ "{product_name:RE355,product_ver:1.0.0,special_id:55530000}\r\n"
+ "{product_name:RE355,product_ver:1.0.0,special_id:45550000}\r\n"
+ "{product_name:RE355,product_ver:1.0.0,special_id:4A500000}\r\n"
+ "{product_name:RE355,product_ver:1.0.0,special_id:43410000}\r\n"
+ "{product_name:RE355,product_ver:1.0.0,special_id:41550000}\r\n"
+ "{product_name:RE355,product_ver:1.0.0,special_id:4B520000}\r\n"
+ "{product_name:RE355,product_ver:1.0.0,special_id:55534100}\r\n",
+ .support_trail = '\x00',
+ .soft_ver = NULL,
+
+ /**
+ The flash partition table for RE355;
+ it is almost the same as the one used by the stock images,
+ 576KB were moved from file-system to os-image.
+ */
+ .partitions = {
+ {"fs-uboot", 0x00000, 0x20000},
+ {"os-image", 0x20000, 0x180000},
+ {"file-system", 0x1a0000, 0x460000},
+ {"partition-table", 0x600000, 0x02000},
+ {"default-mac", 0x610000, 0x00020},
+ {"pin", 0x610100, 0x00020},
+ {"product-info", 0x611100, 0x01000},
+ {"soft-version", 0x620000, 0x01000},
+ {"support-list", 0x621000, 0x01000},
+ {"profile", 0x622000, 0x08000},
+ {"user-config", 0x630000, 0x10000},
+ {"default-config", 0x640000, 0x10000},
+ {"radio", 0x7f0000, 0x10000},
+ {NULL, 0, 0}
+ },
+
+ .first_sysupgrade_partition = "os-image",
+ .last_sysupgrade_partition = "file-system"
+ },
+
+ /** Firmware layout for the RE450 */
+ {
+ .id = "RE450",
+ .vendor = "",
+ .support_list =
+ "SupportList:\r\n"
+ "{product_name:RE450,product_ver:1.0.0,special_id:00000000}\r\n"
+ "{product_name:RE450,product_ver:1.0.0,special_id:55530000}\r\n"
+ "{product_name:RE450,product_ver:1.0.0,special_id:45550000}\r\n"
+ "{product_name:RE450,product_ver:1.0.0,special_id:4A500000}\r\n"
+ "{product_name:RE450,product_ver:1.0.0,special_id:43410000}\r\n"
+ "{product_name:RE450,product_ver:1.0.0,special_id:41550000}\r\n"
+ "{product_name:RE450,product_ver:1.0.0,special_id:4B520000}\r\n"
+ "{product_name:RE450,product_ver:1.0.0,special_id:55534100}\r\n",
+ .support_trail = '\x00',
+ .soft_ver = NULL,
+
+ /**
+ The flash partition table for RE450;
+ it is almost the same as the one used by the stock images,
+ 576KB were moved from file-system to os-image.
+ */
+ .partitions = {
+ {"fs-uboot", 0x00000, 0x20000},
+ {"os-image", 0x20000, 0x180000},
+ {"file-system", 0x1a0000, 0x460000},
+ {"partition-table", 0x600000, 0x02000},
+ {"default-mac", 0x610000, 0x00020},
+ {"pin", 0x610100, 0x00020},
+ {"product-info", 0x611100, 0x01000},
+ {"soft-version", 0x620000, 0x01000},
+ {"support-list", 0x621000, 0x01000},
+ {"profile", 0x622000, 0x08000},
+ {"user-config", 0x630000, 0x10000},
+ {"default-config", 0x640000, 0x10000},
+ {"radio", 0x7f0000, 0x10000},
+ {NULL, 0, 0}
+ },
+
+ .first_sysupgrade_partition = "os-image",
+ .last_sysupgrade_partition = "file-system"
+ },
+
+ /** Firmware layout for the RE450 v2 */
+ {
+ .id = "RE450-V2",
+ .vendor = "",
+ .support_list =
+ "SupportList:\r\n"
+ "{product_name:RE450,product_ver:2.0.0,special_id:00000000}\r\n"
+ "{product_name:RE450,product_ver:2.0.0,special_id:55530000}\r\n"
+ "{product_name:RE450,product_ver:2.0.0,special_id:45550000}\r\n"
+ "{product_name:RE450,product_ver:2.0.0,special_id:4A500000}\r\n"
+ "{product_name:RE450,product_ver:2.0.0,special_id:43410000}\r\n"
+ "{product_name:RE450,product_ver:2.0.0,special_id:41550000}\r\n"
+ "{product_name:RE450,product_ver:2.0.0,special_id:41530000}\r\n"
+ "{product_name:RE450,product_ver:2.0.0,special_id:4B520000}\r\n"
+ "{product_name:RE450,product_ver:2.0.0,special_id:42520000}\r\n",
+ .support_trail = '\x00',
+ .soft_ver = NULL,
+
+ /* We're using a dynamic kernel/rootfs split here */
+ .partitions = {
+ {"fs-uboot", 0x00000, 0x20000},
+ {"firmware", 0x20000, 0x5e0000},
+ {"partition-table", 0x600000, 0x02000},
+ {"default-mac", 0x610000, 0x00020},
+ {"pin", 0x610100, 0x00020},
+ {"product-info", 0x611100, 0x01000},
+ {"soft-version", 0x620000, 0x01000},
+ {"support-list", 0x621000, 0x01000},
+ {"profile", 0x622000, 0x08000},
+ {"user-config", 0x630000, 0x10000},
+ {"default-config", 0x640000, 0x10000},
+ {"radio", 0x7f0000, 0x10000},
+
+ {NULL, 0, 0}
+ },
+
+ .first_sysupgrade_partition = "os-image",
+ .last_sysupgrade_partition = "file-system"
+ },
+
+ {}
+};
+
+#define error(_ret, _errno, _str, ...) \
+ do { \
+ fprintf(stderr, _str ": %s\n", ## __VA_ARGS__, \
+ strerror(_errno)); \
+ if (_ret) \
+ exit(_ret); \
+ } while (0)
+
+
+/** Stores a uint32 as big endian */
+static inline void put32(uint8_t *buf, uint32_t val) {
+ buf[0] = val >> 24;
+ buf[1] = val >> 16;
+ buf[2] = val >> 8;
+ buf[3] = val;
+}
+
+/** Allocates a new image partition */
+static struct image_partition_entry alloc_image_partition(const char *name, size_t len) {
+ struct image_partition_entry entry = {name, len, malloc(len)};
+ if (!entry.data)
+ error(1, errno, "malloc");
+
+ return entry;
+}
+
+/** Frees an image partition */
+static void free_image_partition(struct image_partition_entry entry) {
+ free(entry.data);
+}
+
+static time_t source_date_epoch = -1;
+static void set_source_date_epoch() {
+ char *env = getenv("SOURCE_DATE_EPOCH");
+ char *endptr = env;
+ errno = 0;
+ if (env && *env) {
+ source_date_epoch = strtoull(env, &endptr, 10);
+ if (errno || (endptr && *endptr != '\0')) {
+ fprintf(stderr, "Invalid SOURCE_DATE_EPOCH");
+ exit(1);
+ }
+ }
+}
+
+/** Generates the partition-table partition */
+static struct image_partition_entry make_partition_table(const struct flash_partition_entry *p) {
+ struct image_partition_entry entry = alloc_image_partition("partition-table", 0x800);
+
+ char *s = (char *)entry.data, *end = (char *)(s+entry.size);
+
+ *(s++) = 0x00;
+ *(s++) = 0x04;
+ *(s++) = 0x00;
+ *(s++) = 0x00;
+
+ size_t i;
+ for (i = 0; p[i].name; i++) {
+ size_t len = end-s;
+ size_t w = snprintf(s, len, "partition %s base 0x%05x size 0x%05x\n", p[i].name, p[i].base, p[i].size);
+
+ if (w > len-1)
+ error(1, 0, "flash partition table overflow?");
+
+ s += w;
+ }
+
+ s++;
+
+ memset(s, 0xff, end-s);
+
+ return entry;
+}
+
+
+/** Generates a binary-coded decimal representation of an integer in the range [0, 99] */
+static inline uint8_t bcd(uint8_t v) {
+ return 0x10 * (v/10) + v%10;
+}
+
+
+/** Generates the soft-version partition */
+static struct image_partition_entry make_soft_version(uint32_t rev) {
+ struct image_partition_entry entry = alloc_image_partition("soft-version", sizeof(struct soft_version));
+ struct soft_version *s = (struct soft_version *)entry.data;
+
+ time_t t;
+
+ if (source_date_epoch != -1)
+ t = source_date_epoch;
+ else if (time(&t) == (time_t)(-1))
+ error(1, errno, "time");
+
+ struct tm *tm = localtime(&t);
+
+ s->magic = htonl(0x0000000c);
+ s->zero = 0;
+ s->pad1 = 0xff;
+
+ s->version_major = 0;
+ s->version_minor = 0;
+ s->version_patch = 0;
+
+ s->year_hi = bcd((1900+tm->tm_year)/100);
+ s->year_lo = bcd(tm->tm_year%100);
+ s->month = bcd(tm->tm_mon+1);
+ s->day = bcd(tm->tm_mday);
+ s->rev = htonl(rev);
+
+ s->pad2 = 0xff;
+
+ return entry;
+}
+
+static struct image_partition_entry make_soft_version_from_string(const char *soft_ver) {
+ /** String length _including_ the terminating zero byte */
+ uint32_t ver_len = strlen(soft_ver) + 1;
+ /** Partition contains 64 bit header, the version string, and one additional null byte */
+ size_t partition_len = 2*sizeof(uint32_t) + ver_len + 1;
+ struct image_partition_entry entry = alloc_image_partition("soft-version", partition_len);
+
+ uint32_t *len = (uint32_t *)entry.data;
+ len[0] = htonl(ver_len);
+ len[1] = 0;
+ memcpy(&len[2], soft_ver, ver_len);
+
+ entry.data[partition_len - 1] = 0;
+
+ return entry;
+}
+
+/** Generates the support-list partition */
+static struct image_partition_entry make_support_list(struct device_info *info) {
+ size_t len = strlen(info->support_list);
+ struct image_partition_entry entry = alloc_image_partition("support-list", len + 9);
+
+ put32(entry.data, len);
+ memset(entry.data+4, 0, 4);
+ memcpy(entry.data+8, info->support_list, len);
+ entry.data[len+8] = info->support_trail;
+
+ return entry;
+}
+
+/** Creates a new image partition with an arbitrary name from a file */
+static struct image_partition_entry read_file(const char *part_name, const char *filename, bool add_jffs2_eof, struct flash_partition_entry *file_system_partition) {
+ struct stat statbuf;
+
+ if (stat(filename, &statbuf) < 0)
+ error(1, errno, "unable to stat file `%s'", filename);
+
+ size_t len = statbuf.st_size;
+
+ if (add_jffs2_eof)
+ if (file_system_partition)
+ len = ALIGN(len + file_system_partition->base, 0x10000) + sizeof(jffs2_eof_mark) - file_system_partition->base;
+ else
+ len = ALIGN(len, 0x10000) + sizeof(jffs2_eof_mark);
+
+ struct image_partition_entry entry = alloc_image_partition(part_name, len);
+
+ FILE *file = fopen(filename, "rb");
+ if (!file)
+ error(1, errno, "unable to open file `%s'", filename);
+
+ if (fread(entry.data, statbuf.st_size, 1, file) != 1)
+ error(1, errno, "unable to read file `%s'", filename);
+
+ if (add_jffs2_eof) {
+ uint8_t *eof = entry.data + statbuf.st_size, *end = entry.data+entry.size;
+
+ memset(eof, 0xff, end - eof - sizeof(jffs2_eof_mark));
+ memcpy(end - sizeof(jffs2_eof_mark), jffs2_eof_mark, sizeof(jffs2_eof_mark));
+ }
+
+ fclose(file);
+
+ return entry;
+}
+
+/** Creates a new image partition from arbitrary data */
+static struct image_partition_entry put_data(const char *part_name, const char *datain, size_t len) {
+
+ struct image_partition_entry entry = alloc_image_partition(part_name, len);
+
+ memcpy(entry.data, datain, len);
+
+ return entry;
+}
+
+/**
+ Copies a list of image partitions into an image buffer and generates the image partition table while doing so
+
+ Example image partition table:
+
+ fwup-ptn partition-table base 0x00800 size 0x00800
+ fwup-ptn os-image base 0x01000 size 0x113b45
+ fwup-ptn file-system base 0x114b45 size 0x1d0004
+ fwup-ptn support-list base 0x2e4b49 size 0x000d1
+
+ Each line of the partition table is terminated with the bytes 09 0d 0a ("\t\r\n"),
+ the end of the partition table is marked with a zero byte.
+
+ The firmware image must contain at least the partition-table and support-list partitions
+ to be accepted. There aren't any alignment constraints for the image partitions.
+
+ The partition-table partition contains the actual flash layout; partitions
+ from the image partition table are mapped to the corresponding flash partitions during
+ the firmware upgrade. The support-list partition contains a list of devices supported by
+ the firmware image.
+
+ The base offsets in the firmware partition table are relative to the end
+ of the vendor information block, so the partition-table partition will
+ actually start at offset 0x1814 of the image.
+
+ I think partition-table must be the first partition in the firmware image.
+*/
+static void put_partitions(uint8_t *buffer, const struct flash_partition_entry *flash_parts, const struct image_partition_entry *parts) {
+ size_t i, j;
+ char *image_pt = (char *)buffer, *end = image_pt + 0x800;
+
+ size_t base = 0x800;
+ for (i = 0; parts[i].name; i++) {
+ for (j = 0; flash_parts[j].name; j++) {
+ if (!strcmp(flash_parts[j].name, parts[i].name)) {
+ if (parts[i].size > flash_parts[j].size)
+ error(1, 0, "%s partition too big (more than %u bytes)", flash_parts[j].name, (unsigned)flash_parts[j].size);
+ break;
+ }
+ }
+
+ assert(flash_parts[j].name);
+
+ memcpy(buffer + base, parts[i].data, parts[i].size);
+
+ size_t len = end-image_pt;
+ size_t w = snprintf(image_pt, len, "fwup-ptn %s base 0x%05x size 0x%05x\t\r\n", parts[i].name, (unsigned)base, (unsigned)parts[i].size);
+
+ if (w > len-1)
+ error(1, 0, "image partition table overflow?");
+
+ image_pt += w;
+
+ base += parts[i].size;
+ }
+}
+
+/** Generates and writes the image MD5 checksum */
+static void put_md5(uint8_t *md5, uint8_t *buffer, unsigned int len) {
+ MD5_CTX ctx;
+
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, md5_salt, (unsigned int)sizeof(md5_salt));
+ MD5_Update(&ctx, buffer, len);
+ MD5_Final(md5, &ctx);
+}
+
+
+/**
+ Generates the firmware image in factory format
+
+ Image format:
+
+ Bytes (hex) Usage
+ ----------- -----
+ 0000-0003 Image size (4 bytes, big endian)
+ 0004-0013 MD5 hash (hash of a 16 byte salt and the image data starting with byte 0x14)
+ 0014-0017 Vendor information length (without padding) (4 bytes, big endian)
+ 0018-1013 Vendor information (4092 bytes, padded with 0xff; there seem to be older
+ (VxWorks-based) TP-LINK devices which use a smaller vendor information block)
+ 1014-1813 Image partition table (2048 bytes, padded with 0xff)
+ 1814-xxxx Firmware partitions
+*/
+static void * generate_factory_image(struct device_info *info, const struct image_partition_entry *parts, size_t *len) {
+ *len = 0x1814;
+
+ size_t i;
+ for (i = 0; parts[i].name; i++)
+ *len += parts[i].size;
+
+ uint8_t *image = malloc(*len);
+ if (!image)
+ error(1, errno, "malloc");
+
+ memset(image, 0xff, *len);
+ put32(image, *len);
+
+ if (info->vendor) {
+ size_t vendor_len = strlen(info->vendor);
+ put32(image+0x14, vendor_len);
+ memcpy(image+0x18, info->vendor, vendor_len);
+ }
+
+ put_partitions(image + 0x1014, info->partitions, parts);
+ put_md5(image+0x04, image+0x14, *len-0x14);
+
+ return image;
+}
+
+/**
+ Generates the firmware image in sysupgrade format
+
+ This makes some assumptions about the provided flash and image partition tables and
+ should be generalized when TP-LINK starts building its safeloader into hardware with
+ different flash layouts.
+*/
+static void * generate_sysupgrade_image(struct device_info *info, const struct image_partition_entry *image_parts, size_t *len) {
+ size_t i, j;
+ size_t flash_first_partition_index = 0;
+ size_t flash_last_partition_index = 0;
+ const struct flash_partition_entry *flash_first_partition = NULL;
+ const struct flash_partition_entry *flash_last_partition = NULL;
+ const struct image_partition_entry *image_last_partition = NULL;
+
+ /** Find first and last partitions */
+ for (i = 0; info->partitions[i].name; i++) {
+ if (!strcmp(info->partitions[i].name, info->first_sysupgrade_partition)) {
+ flash_first_partition = &info->partitions[i];
+ flash_first_partition_index = i;
+ } else if (!strcmp(info->partitions[i].name, info->last_sysupgrade_partition)) {
+ flash_last_partition = &info->partitions[i];
+ flash_last_partition_index = i;
+ }
+ }
+
+ assert(flash_first_partition && flash_last_partition);
+ assert(flash_first_partition_index < flash_last_partition_index);
+
+ /** Find last partition from image to calculate needed size */
+ for (i = 0; image_parts[i].name; i++) {
+ if (!strcmp(image_parts[i].name, info->last_sysupgrade_partition)) {
+ image_last_partition = &image_parts[i];
+ break;
+ }
+ }
+
+ assert(image_last_partition);
+
+ *len = flash_last_partition->base - flash_first_partition->base + image_last_partition->size;
+
+ uint8_t *image = malloc(*len);
+ if (!image)
+ error(1, errno, "malloc");
+
+ memset(image, 0xff, *len);
+
+ for (i = flash_first_partition_index; i <= flash_last_partition_index; i++) {
+ for (j = 0; image_parts[j].name; j++) {
+ if (!strcmp(info->partitions[i].name, image_parts[j].name)) {
+ if (image_parts[j].size > info->partitions[i].size)
+ error(1, 0, "%s partition too big (more than %u bytes)", info->partitions[i].name, (unsigned)info->partitions[i].size);
+ memcpy(image + info->partitions[i].base - flash_first_partition->base, image_parts[j].data, image_parts[j].size);
+ break;
+ }
+
+ assert(image_parts[j].name);
+ }
+ }
+
+ return image;
+}
+
+/** Generates an image according to a given layout and writes it to a file */
+static void build_image(const char *output,
+ const char *kernel_image,
+ const char *rootfs_image,
+ uint32_t rev,
+ bool add_jffs2_eof,
+ bool sysupgrade,
+ struct device_info *info) {
+
+ size_t i;
+
+ struct image_partition_entry parts[7] = {};
+
+ struct flash_partition_entry *firmware_partition = NULL;
+ struct flash_partition_entry *os_image_partition = NULL;
+ struct flash_partition_entry *file_system_partition = NULL;
+ size_t firmware_partition_index = 0;
+
+ for (i = 0; info->partitions[i].name; i++) {
+ if (!strcmp(info->partitions[i].name, "firmware"))
+ {
+ firmware_partition = &info->partitions[i];
+ firmware_partition_index = i;
+ }
+ }
+
+ if (firmware_partition)
+ {
+ os_image_partition = &info->partitions[firmware_partition_index];
+ file_system_partition = &info->partitions[firmware_partition_index + 1];
+
+ struct stat kernel;
+ if (stat(kernel_image, &kernel) < 0)
+ error(1, errno, "unable to stat file `%s'", kernel_image);
+
+ if (kernel.st_size > firmware_partition->size)
+ error(1, 0, "kernel overflowed firmware partition\n");
+
+ for (i = MAX_PARTITIONS-1; i >= firmware_partition_index + 1; i--)
+ info->partitions[i+1] = info->partitions[i];
+
+ file_system_partition->name = "file-system";
+ file_system_partition->base = firmware_partition->base + kernel.st_size;
+
+ /* Align partition start to erase blocks for factory images only */
+ if (!sysupgrade)
+ file_system_partition->base = ALIGN(firmware_partition->base + kernel.st_size, 0x10000);
+
+ file_system_partition->size = firmware_partition->size - file_system_partition->base;
+
+ os_image_partition->name = "os-image";
+ os_image_partition->size = kernel.st_size;
+ }
+
+ parts[0] = make_partition_table(info->partitions);
+ if (info->soft_ver)
+ parts[1] = make_soft_version_from_string(info->soft_ver);
+ else
+ parts[1] = make_soft_version(rev);
+
+ parts[2] = make_support_list(info);
+ parts[3] = read_file("os-image", kernel_image, false, NULL);
+ parts[4] = read_file("file-system", rootfs_image, add_jffs2_eof, file_system_partition);
+
+ /* Some devices need the extra-para partition to accept the firmware */
+ if (strcasecmp(info->id, "ARCHER-C25-V1") == 0 ||
+ strcasecmp(info->id, "ARCHER-C59-V2") == 0 ||
+ strcasecmp(info->id, "ARCHER-C60-V2") == 0 ||
+ strcasecmp(info->id, "TLWR1043NV5") == 0) {
+ const char mdat[11] = {0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00};
+ parts[5] = put_data("extra-para", mdat, 11);
+ } else if (strcasecmp(info->id, "ARCHER-C7-V4") == 0 || strcasecmp(info->id, "ARCHER-C7-V5") == 0) {
+ const char mdat[11] = {0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0xca, 0x00, 0x01, 0x00, 0x00};
+ parts[5] = put_data("extra-para", mdat, 11);
+ }
+
+ size_t len;
+ void *image;
+ if (sysupgrade)
+ image = generate_sysupgrade_image(info, parts, &len);
+ else
+ image = generate_factory_image(info, parts, &len);
+
+ FILE *file = fopen(output, "wb");
+ if (!file)
+ error(1, errno, "unable to open output file");
+
+ if (fwrite(image, len, 1, file) != 1)
+ error(1, 0, "unable to write output file");
+
+ fclose(file);
+
+ free(image);
+
+ for (i = 0; parts[i].name; i++)
+ free_image_partition(parts[i]);
+}
+
+/** Usage output */
+static void usage(const char *argv0) {
+ fprintf(stderr,
+ "Usage: %s [OPTIONS...]\n"
+ "\n"
+ "Options:\n"
+ " -h show this help\n"
+ "\n"
+ "Create a new image:\n"
+ " -B <board> create image for the board specified with <board>\n"
+ " -k <file> read kernel image from the file <file>\n"
+ " -r <file> read rootfs image from the file <file>\n"
+ " -o <file> write output to the file <file>\n"
+ " -V <rev> sets the revision number to <rev>\n"
+ " -j add jffs2 end-of-filesystem markers\n"
+ " -S create sysupgrade instead of factory image\n"
+ "Extract an old image:\n"
+ " -x <file> extract all oem firmware partition\n"
+ " -d <dir> destination to extract the firmware partition\n"
+ " -z <file> convert an oem firmware into a sysupgade file. Use -o for output file\n",
+ argv0
+ );
+};
+
+
+static struct device_info *find_board(const char *id)
+{
+ struct device_info *board = NULL;
+
+ for (board = boards; board->id != NULL; board++)
+ if (strcasecmp(id, board->id) == 0)
+ return board;
+
+ return NULL;
+}
+
+static int add_flash_partition(
+ struct flash_partition_entry *part_list,
+ size_t max_entries,
+ const char *name,
+ unsigned long base,
+ unsigned long size)
+{
+ int ptr;
+ /* check if the list has a free entry */
+ for (ptr = 0; ptr < max_entries; ptr++, part_list++) {
+ if (part_list->name == NULL &&
+ part_list->base == 0 &&
+ part_list->size == 0)
+ break;
+ }
+
+ if (ptr == max_entries) {
+ error(1, 0, "No free flash part entry available.");
+ }
+
+ part_list->name = calloc(1, strlen(name) + 1);
+ if (!part_list->name) {
+ error(1, 0, "Unable to allocate memory");
+ }
+
+ memcpy((char *)part_list->name, name, strlen(name));
+ part_list->base = base;
+ part_list->size = size;
+
+ return 0;
+}
+
+/** read the partition table into struct flash_partition_entry */
+static int read_partition_table(
+ FILE *file, long offset,
+ struct flash_partition_entry *entries, size_t max_entries,
+ int type)
+{
+ char buf[2048];
+ char *ptr, *end;
+ const char *parthdr = NULL;
+ const char *fwuphdr = "fwup-ptn";
+ const char *flashhdr = "partition";
+
+ /* TODO: search for the partition table */
+
+ switch(type) {
+ case 0:
+ parthdr = fwuphdr;
+ break;
+ case 1:
+ parthdr = flashhdr;
+ break;
+ default:
+ error(1, 0, "Invalid partition table");
+ }
+
+ if (fseek(file, offset, SEEK_SET) < 0)
+ error(1, errno, "Can not seek in the firmware");
+
+ if (fread(buf, 1, 2048, file) < 0)
+ error(1, errno, "Can not read fwup-ptn from the firmware");
+
+ buf[2047] = '\0';
+
+ /* look for the partition header */
+ if (memcmp(buf, parthdr, strlen(parthdr)) != 0) {
+ fprintf(stderr, "DEBUG: can not find fwuphdr\n");
+ return 1;
+ }
+
+ ptr = buf;
+ end = buf + sizeof(buf);
+ while ((ptr + strlen(parthdr)) < end &&
+ memcmp(ptr, parthdr, strlen(parthdr)) == 0) {
+ char *end_part;
+ char *end_element;
+
+ char name[32] = { 0 };
+ int name_len = 0;
+ unsigned long base = 0;
+ unsigned long size = 0;
+
+ end_part = memchr(ptr, '\n', (end - ptr));
+ if (end_part == NULL) {
+ /* in theory this should never happen, because a partition always ends with 0x09, 0x0D, 0x0A */
+ break;
+ }
+
+ for (int i = 0; i <= 4; i++) {
+ if (end_part <= ptr)
+ break;
+
+ end_element = memchr(ptr, 0x20, (end_part - ptr));
+ if (end_element == NULL) {
+ error(1, errno, "Ignoring the rest of the partition entries.");
+ break;
+ }
+
+ switch (i) {
+ /* partition header */
+ case 0:
+ ptr = end_element + 1;
+ continue;
+ /* name */
+ case 1:
+ name_len = (end_element - ptr) > 31 ? 31 : (end_element - ptr);
+ strncpy(name, ptr, name_len);
+ name[name_len] = '\0';
+ ptr = end_element + 1;
+ continue;
+
+ /* string "base" */
+ case 2:
+ ptr = end_element + 1;
+ continue;
+
+ /* actual base */
+ case 3:
+ base = strtoul(ptr, NULL, 16);
+ ptr = end_element + 1;
+ continue;
+
+ /* string "size" */
+ case 4:
+ ptr = end_element + 1;
+ /* actual size. The last element doesn't have a sepeartor */
+ size = strtoul(ptr, NULL, 16);
+ /* the part ends with 0x09, 0x0d, 0x0a */
+ ptr = end_part + 1;
+ add_flash_partition(entries, max_entries, name, base, size);
+ continue;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static void write_partition(
+ FILE *input_file,
+ size_t firmware_offset,
+ struct flash_partition_entry *entry,
+ FILE *output_file)
+{
+ char buf[4096];
+ size_t offset;
+
+ fseek(input_file, entry->base + firmware_offset, SEEK_SET);
+
+ for (offset = 0; sizeof(buf) + offset <= entry->size; offset += sizeof(buf)) {
+ if (fread(buf, sizeof(buf), 1, input_file) < 0)
+ error(1, errno, "Can not read partition from input_file");
+
+ if (fwrite(buf, sizeof(buf), 1, output_file) < 0)
+ error(1, errno, "Can not write partition to output_file");
+ }
+ /* write last chunk smaller than buffer */
+ if (offset < entry->size) {
+ offset = entry->size - offset;
+ if (fread(buf, offset, 1, input_file) < 0)
+ error(1, errno, "Can not read partition from input_file");
+ if (fwrite(buf, offset, 1, output_file) < 0)
+ error(1, errno, "Can not write partition to output_file");
+ }
+}
+
+static int extract_firmware_partition(FILE *input_file, size_t firmware_offset, struct flash_partition_entry *entry, const char *output_directory)
+{
+ FILE *output_file;
+ char output[PATH_MAX];
+
+ snprintf(output, PATH_MAX, "%s/%s", output_directory, entry->name);
+ output_file = fopen(output, "wb+");
+ if (output_file == NULL) {
+ error(1, errno, "Can not open output file %s", output);
+ }
+
+ write_partition(input_file, firmware_offset, entry, output_file);
+
+ fclose(output_file);
+
+ return 0;
+}
+
+/** extract all partitions from the firmware file */
+static int extract_firmware(const char *input, const char *output_directory)
+{
+ struct flash_partition_entry entries[16] = { 0 };
+ size_t max_entries = 16;
+ size_t firmware_offset = 0x1014;
+ FILE *input_file;
+
+ struct stat statbuf;
+
+ /* check input file */
+ if (stat(input, &statbuf)) {
+ error(1, errno, "Can not read input firmware %s", input);
+ }
+
+ /* check if output directory exists */
+ if (stat(output_directory, &statbuf)) {
+ error(1, errno, "Failed to stat output directory %s", output_directory);
+ }
+
+ if ((statbuf.st_mode & S_IFMT) != S_IFDIR) {
+ error(1, errno, "Given output directory is not a directory %s", output_directory);
+ }
+
+ input_file = fopen(input, "rb");
+
+ if (read_partition_table(input_file, firmware_offset, entries, 16, 0) != 0) {
+ error(1, 0, "Error can not read the partition table (fwup-ptn)");
+ }
+
+ for (int i = 0; i < max_entries; i++) {
+ if (entries[i].name == NULL &&
+ entries[i].base == 0 &&
+ entries[i].size == 0)
+ continue;
+
+ extract_firmware_partition(input_file, firmware_offset, &entries[i], output_directory);
+ }
+
+ return 0;
+}
+
+static struct flash_partition_entry *find_partition(
+ struct flash_partition_entry *entries, size_t max_entries,
+ const char *name, const char *error_msg)
+{
+ for (int i = 0; i < max_entries; i++, entries++) {
+ if (strcmp(entries->name, name) == 0)
+ return entries;
+ }
+
+ error(1, 0, "%s", error_msg);
+ return NULL;
+}
+
+static void write_ff(FILE *output_file, size_t size)
+{
+ char buf[4096];
+ int offset;
+
+ memset(buf, 0xff, sizeof(buf));
+
+ for (offset = 0; offset + sizeof(buf) < size ; offset += sizeof(buf)) {
+ if (fwrite(buf, sizeof(buf), 1, output_file) < 0)
+ error(1, errno, "Can not write 0xff to output_file");
+ }
+
+ /* write last chunk smaller than buffer */
+ if (offset < size) {
+ offset = size - offset;
+ if (fwrite(buf, offset, 1, output_file) < 0)
+ error(1, errno, "Can not write partition to output_file");
+ }
+}
+
+static void convert_firmware(const char *input, const char *output)
+{
+ struct flash_partition_entry fwup[MAX_PARTITIONS] = { 0 };
+ struct flash_partition_entry flash[MAX_PARTITIONS] = { 0 };
+ struct flash_partition_entry *fwup_os_image = NULL, *fwup_file_system = NULL;
+ struct flash_partition_entry *flash_os_image = NULL, *flash_file_system = NULL;
+ struct flash_partition_entry *fwup_partition_table = NULL;
+ size_t firmware_offset = 0x1014;
+ FILE *input_file, *output_file;
+
+ struct stat statbuf;
+
+ /* check input file */
+ if (stat(input, &statbuf)) {
+ error(1, errno, "Can not read input firmware %s", input);
+ }
+
+ input_file = fopen(input, "rb");
+ if (!input_file)
+ error(1, 0, "Can not open input firmware %s", input);
+
+ output_file = fopen(output, "wb");
+ if (!output_file)
+ error(1, 0, "Can not open output firmware %s", output);
+
+ if (read_partition_table(input_file, firmware_offset, fwup, MAX_PARTITIONS, 0) != 0) {
+ error(1, 0, "Error can not read the partition table (fwup-ptn)");
+ }
+
+ fwup_os_image = find_partition(fwup, MAX_PARTITIONS,
+ "os-image", "Error can not find os-image partition (fwup)");
+ fwup_file_system = find_partition(fwup, MAX_PARTITIONS,
+ "file-system", "Error can not find file-system partition (fwup)");
+ fwup_partition_table = find_partition(fwup, MAX_PARTITIONS,
+ "partition-table", "Error can not find partition-table partition");
+
+ /* the flash partition table has a 0x00000004 magic haeder */
+ if (read_partition_table(input_file, firmware_offset + fwup_partition_table->base + 4, flash, MAX_PARTITIONS, 1) != 0)
+ error(1, 0, "Error can not read the partition table (flash)");
+
+ flash_os_image = find_partition(flash, MAX_PARTITIONS,
+ "os-image", "Error can not find os-image partition (flash)");
+ flash_file_system = find_partition(flash, MAX_PARTITIONS,
+ "file-system", "Error can not find file-system partition (flash)");
+
+ /* write os_image to 0x0 */
+ write_partition(input_file, firmware_offset, fwup_os_image, output_file);
+ write_ff(output_file, flash_os_image->size - fwup_os_image->size);
+
+ /* write file-system behind os_image */
+ fseek(output_file, flash_file_system->base - flash_os_image->base, SEEK_SET);
+ write_partition(input_file, firmware_offset, fwup_file_system, output_file);
+ write_ff(output_file, flash_file_system->size - fwup_file_system->size);
+
+ fclose(output_file);
+ fclose(input_file);
+}
+
+int main(int argc, char *argv[]) {
+ const char *board = NULL, *kernel_image = NULL, *rootfs_image = NULL, *output = NULL;
+ const char *extract_image = NULL, *output_directory = NULL, *convert_image = NULL;
+ bool add_jffs2_eof = false, sysupgrade = false;
+ unsigned rev = 0;
+ struct device_info *info;
+ set_source_date_epoch();
+
+ while (true) {
+ int c;
+
+ c = getopt(argc, argv, "B:k:r:o:V:jSh:x:d:z:");
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'B':
+ board = optarg;
+ break;
+
+ case 'k':
+ kernel_image = optarg;
+ break;
+
+ case 'r':
+ rootfs_image = optarg;
+ break;
+
+ case 'o':
+ output = optarg;
+ break;
+
+ case 'V':
+ sscanf(optarg, "r%u", &rev);
+ break;
+
+ case 'j':
+ add_jffs2_eof = true;
+ break;
+
+ case 'S':
+ sysupgrade = true;
+ break;
+
+ case 'h':
+ usage(argv[0]);
+ return 0;
+
+ case 'd':
+ output_directory = optarg;
+ break;
+
+ case 'x':
+ extract_image = optarg;
+ break;
+
+ case 'z':
+ convert_image = optarg;
+ break;
+
+ default:
+ usage(argv[0]);
+ return 1;
+ }
+ }
+
+ if (extract_image || output_directory) {
+ if (!extract_image)
+ error(1, 0, "No factory/oem image given via -x <file>. Output directory is only valid with -x");
+ if (!output_directory)
+ error(1, 0, "Can not extract an image without output directory. Use -d <dir>");
+ extract_firmware(extract_image, output_directory);
+ } else if (convert_image) {
+ if (!output)
+ error(1, 0, "Can not convert a factory/oem image into sysupgrade image without output file. Use -o <file>");
+ convert_firmware(convert_image, output);
+ } else {
+ if (!board)
+ error(1, 0, "no board has been specified");
+ if (!kernel_image)
+ error(1, 0, "no kernel image has been specified");
+ if (!rootfs_image)
+ error(1, 0, "no rootfs image has been specified");
+ if (!output)
+ error(1, 0, "no output filename has been specified");
+
+ info = find_board(board);
+
+ if (info == NULL)
+ error(1, 0, "unsupported board %s", board);
+
+ build_image(output, kernel_image, rootfs_image, rev, add_jffs2_eof, sysupgrade, info);
+ }
+
+ return 0;
+}
diff --git a/tools/firmware-utils/src/trx.c b/tools/firmware-utils/src/trx.c
index 8e95d98d7ae..dc5bb672aeb 100644
--- a/tools/firmware-utils/src/trx.c
+++ b/tools/firmware-utils/src/trx.c
@@ -68,7 +68,7 @@ uint32_t crc32buf(char *buf, size_t len);
#define TRX_MAGIC 0x30524448 /* "HDR0" */
#define TRX_MAX_LEN 0x720000
-#define TRX_NO_HEADER 1 /* Do not write TRX header */
+#define TRX_NO_HEADER 1 /* Do not write TRX header */
struct trx_header {
uint32_t magic; /* "HDR0" */
@@ -100,7 +100,7 @@ int main(int argc, char **argv)
int c, i, append = 0;
size_t n;
ssize_t n2;
- uint32_t cur_len, fsmark=0;
+ uint32_t cur_len, fsmark=0, magic;
unsigned long maxlen = TRX_MAX_LEN;
struct trx_header *p;
char trx_version = 1;
@@ -121,7 +121,7 @@ int main(int argc, char **argv)
in = NULL;
i = 0;
- while ((c = getopt(argc, argv, "-:2o:m:a:x:b:f:A:F:")) != -1) {
+ while ((c = getopt(argc, argv, "-:2o:m:a:x:b:f:A:F:M:")) != -1) {
switch (c) {
case '2':
/* take care that nothing was written to buf so far */
@@ -243,6 +243,15 @@ int main(int argc, char **argv)
}
break;
+ case 'M':
+ errno = 0;
+ magic = strtoul(optarg, &e, 0);
+ if (errno || (e == optarg) || *e) {
+ fprintf(stderr, "illegal numeric string\n");
+ usage();
+ }
+ p->magic = STORE32_LE(magic);
+ break;
default:
usage();
}
@@ -262,7 +271,7 @@ int main(int argc, char **argv)
cur_len += ROUND - n;
}
- /* for TRXv2 set bin-header Flags to 0xFF for CRC calculation like CFE does */
+ /* for TRXv2 set bin-header Flags to 0xFF for CRC calculation like CFE does */
if (trx_version == 2) {
if(cur_len - LOAD32_LE(p->offsets[3]) < sizeof(binheader)) {
fprintf(stderr, "TRXv2 binheader too small!\n");
@@ -273,11 +282,10 @@ int main(int argc, char **argv)
}
p->crc32 = crc32buf((char *) &p->flag_version,
- (fsmark)?fsmark:cur_len - offsetof(struct trx_header, flag_version));
+ ((fsmark)?fsmark:cur_len) - offsetof(struct trx_header, flag_version));
p->crc32 = STORE32_LE(p->crc32);
p->len = STORE32_LE((fsmark) ? fsmark : cur_len);
- p->len = STORE32_LE(p->len);
/* restore TRXv2 bin-header */
if (trx_version == 2) {
@@ -290,7 +298,7 @@ int main(int argc, char **argv)
}
fclose(out);
-
+
return EXIT_SUCCESS;
}
diff --git a/tools/firmware-utils/src/wndr3700.c b/tools/firmware-utils/src/wndr3700.c
deleted file mode 100644
index 97b5f1d4558..00000000000
--- a/tools/firmware-utils/src/wndr3700.c
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * wndr3700.c - partially based on OpenWrt's add_header.c
- *
- * Copyright (C) 2009 Anael Orlinski <naouel@naouel.org>
- *
- * 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.
- *
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-/*
- * The add_header utility used by various vendors preprends the buf
- * image with a header containing a CRC32 value which is generated for the
- * model id + reserved space for CRC32 + buf, then replaces the reserved
- * area with the actual CRC32. This replacement tool mimics this behavior.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-#include <string.h>
-#include <netinet/in.h>
-#include <inttypes.h>
-
-#define BPB 8 /* bits/byte */
-
-#define WNDR3700_MAGIC_LEN 4
-
-static uint32_t crc32[1<<BPB];
-static char *magic = "3700";
-
-static void init_crc32()
-{
- const uint32_t poly = ntohl(0x2083b8ed);
- int n;
-
- for (n = 0; n < 1<<BPB; n++) {
- uint32_t crc = n;
- int bit;
-
- for (bit = 0; bit < BPB; bit++)
- crc = (crc & 1) ? (poly ^ (crc >> 1)) : (crc >> 1);
- crc32[n] = crc;
- }
-}
-
-static uint32_t crc32buf(unsigned char *buf, size_t len)
-{
- uint32_t crc = 0xFFFFFFFF;
-
- for (; len; len--, buf++)
- crc = crc32[(uint8_t)crc ^ *buf] ^ (crc >> BPB);
- return ~crc;
-}
-
-struct header {
- unsigned char magic[WNDR3700_MAGIC_LEN];
- uint32_t crc;
- unsigned char stuff[56];
-};
-
-static void usage(const char *) __attribute__ (( __noreturn__ ));
-
-static void usage(const char *mess)
-{
- fprintf(stderr, "Error: %s\n", mess);
- fprintf(stderr, "Usage: wndr3700 input_file output_file [magic]\n");
- fprintf(stderr, "\n");
- exit(1);
-}
-
-int main(int argc, char **argv)
-{
- off_t len; // of original buf
- off_t buflen; // of the output file
- int fd;
- void *input_file; // pointer to the input file (mmmapped)
- struct header header;
- unsigned char *buf; // pointer to prefix + copy of original buf
-
- // verify parameters
-
- if (argc < 3)
- usage("wrong number of arguments");
-
- if (argc > 3)
- magic = argv[3];
-
- if (strlen(magic) != WNDR3700_MAGIC_LEN) {
- fprintf(stderr, "Invalid magic: '%s'\n", magic);
- exit(1);
- }
-
- // mmap input_file
- if ((fd = open(argv[1], O_RDONLY)) < 0
- || (len = lseek(fd, 0, SEEK_END)) < 0
- || (input_file = mmap(0, len, PROT_READ, MAP_SHARED, fd, 0)) == (void *) (-1)
- || close(fd) < 0)
- {
- fprintf(stderr, "Error loading file %s: %s\n", argv[1], strerror(errno));
- exit(1);
- }
-
- buflen = len;
-
- init_crc32();
-
- // preload header
- memcpy(&header, input_file, sizeof(header));
-
- memcpy(header.magic, magic, WNDR3700_MAGIC_LEN);
- header.crc = 0;
-
- // create a firmware image in memory and copy the input_file to it
- buf = malloc(buflen);
- memcpy(buf, input_file, len);
-
- // CRC of temporary header
- header.crc = htonl(crc32buf((unsigned char*)&header, sizeof(header)));
-
- memcpy(buf, &header, sizeof(header));
-
- // write the buf
- if ((fd = open(argv[2], O_CREAT|O_WRONLY|O_TRUNC,0644)) < 0
- || write(fd, buf, buflen) != buflen
- || close(fd) < 0)
- {
- fprintf(stderr, "Error storing file %s: %s\n", argv[2], strerror(errno));
- exit(2);
- }
-
- free(buf);
-
- munmap(input_file,len);
-
- return 0;
-}
diff --git a/tools/firmware-utils/src/wrt400n.c b/tools/firmware-utils/src/wrt400n.c
index a9a4908060c..1cf1debc893 100644
--- a/tools/firmware-utils/src/wrt400n.c
+++ b/tools/firmware-utils/src/wrt400n.c
@@ -7,12 +7,14 @@
*
* Author: Sandeep Mistry
*/
+#include <arpa/inet.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <unistd.h>
#include "cyg_crc.h"
diff --git a/tools/firmware-utils/src/xorimage.c b/tools/firmware-utils/src/xorimage.c
index b5ab83fa7a6..ca6e43742a1 100644
--- a/tools/firmware-utils/src/xorimage.c
+++ b/tools/firmware-utils/src/xorimage.c
@@ -21,7 +21,6 @@
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
-#include <time.h>
#include <unistd.h>
#include <sys/stat.h>
diff --git a/tools/firmware-utils/src/zyimage.c b/tools/firmware-utils/src/zyimage.c
new file mode 100644
index 00000000000..6aacf2ff1bd
--- /dev/null
+++ b/tools/firmware-utils/src/zyimage.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2014 Soul Trace <S-trace@list.ru>
+ *
+ * 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.
+ *
+ */
+
+#define _POSIX_SOURCE
+#define _POSIX_C_SOURCE 199309L /* getopt */
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <string.h>
+#include <unistd.h>
+
+#define szbuf 32768
+
+u_int32_t crc_tab[256];
+
+u_int32_t chksum_crc32 (FILE *f)
+{
+ register unsigned long crc;
+ unsigned long i, j;
+ char *buffer = malloc(szbuf);
+ char *buf;
+
+ crc = 0xFFFFFFFF;
+ while (!feof(f))
+ {
+ j = fread(buffer, 1, szbuf, f);
+ buf = buffer;
+ for (i = 0; i < j; i++)
+ crc = ((crc >> 8) & 0x00FFFFFF) ^ crc_tab[(crc ^ *buf++) & 0xFF];
+ }
+ free(buffer);
+ return crc;
+}
+
+void chksum_crc32gentab ()
+{
+ unsigned long crc, poly;
+ int i, j;
+
+ poly = 0xEDB88320L;
+ for (i = 0; i < 256; i++)
+ {
+ crc = i;
+ for (j = 8; j > 0; j--)
+ {
+ if (crc & 1)
+ crc = (crc >> 1) ^ poly;
+ else
+ crc >>= 1;
+ }
+ crc_tab[i] = crc;
+ }
+}
+
+void usage(char *progname)
+{
+ printf("Usage: %s [ -v Version ] [ -d Device_ID ] <input file>\n", progname);
+ exit(1);
+}
+
+int main(int argc, char *argv[]) {
+ struct signature
+ {
+ const char magic[4];
+ unsigned int device_id;
+ char firmware_version[48];
+ unsigned int crc32;
+ }
+ sign =
+ {
+ { 'Z', 'N', 'B', 'G' },
+ 1,
+ { "V.1.0.0(1.0.0)" },
+ 0
+ };
+ FILE *f;
+ struct signature oldsign;
+ char *filename;
+ static const char *optString;
+ int opt;
+
+ if (argc < 1)
+ usage(argv[0]);
+
+ optString = "v:d:h";
+ opt = getopt( argc, argv, optString );
+ while( opt != -1 ) {
+ switch( opt ) {
+ case 'v':
+ if (optarg == NULL)
+ usage(argv[0]);
+ strncpy(sign.firmware_version, optarg, sizeof(sign.firmware_version)-1);
+ sign.firmware_version[sizeof(sign.firmware_version)-1]='\0'; /* Make sure that string is terminated correctly */
+ break;
+
+ case 'd':
+ sign.device_id = atoi(optarg);
+ if (sign.device_id == 0)
+ sign.device_id = (int)strtol(optarg, NULL, 16);
+ break;
+
+ case '?':
+ case 'h':
+ usage(argv[0]);
+ break;
+
+ default:
+ break;
+ }
+
+ opt = getopt( argc, argv, optString );
+ }
+
+ chksum_crc32gentab();
+
+ filename=argv[optind];
+ if (access(filename, W_OK) || access(filename, R_OK))
+ {
+ printf("Not open input file %s\n", filename);
+ exit(1);
+ }
+ f = fopen(argv[optind], "r+");
+ if (f != NULL)
+ {
+ fseek(f, sizeof(sign)*-1, SEEK_END);
+ fread(&oldsign, sizeof(oldsign), 1, f);
+
+ if (strncmp(oldsign.magic,"ZNBG", sizeof(oldsign.magic)) == 0 )
+ {
+ printf("Image is already signed as:\nDevice ID: 0x%08x\nFirmware version: %s\nImage CRC32: 0x%x\n", oldsign.device_id, oldsign.firmware_version, oldsign.crc32);
+ exit(0);
+ }
+
+ fseek(f, 0, SEEK_SET);
+ sign.crc32 = chksum_crc32(f);
+ fwrite(&sign, sizeof(sign), 1, f);
+ fclose(f);
+
+ printf("Image signed as:\nDevice ID: 0x%08x\nFirmware version: %s\nImage CRC32: 0x%x\n", sign.device_id, sign.firmware_version, sign.crc32);
+ }
+ return 0;
+}
diff --git a/tools/firmware-utils/src/zyxbcm.c b/tools/firmware-utils/src/zyxbcm.c
new file mode 100644
index 00000000000..1a2926bfd31
--- /dev/null
+++ b/tools/firmware-utils/src/zyxbcm.c
@@ -0,0 +1,259 @@
+/*
+ * zyxbcm.c - based on Jonas Gorski's spw303v.c
+ *
+ * Copyright (C) 2014 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#define TAGVER_LEN 4 /* Length of Tag Version */
+#define SIG1_LEN 20 /* Company Signature 1 Length */
+#define SIG2_LEN 14 /* Company Signature 2 Lenght */
+#define BOARDID_LEN 16 /* Length of BoardId */
+#define ENDIANFLAG_LEN 2 /* Endian Flag Length */
+#define CHIPID_LEN 6 /* Chip Id Length */
+#define IMAGE_LEN 10 /* Length of Length Field */
+#define ADDRESS_LEN 12 /* Length of Address field */
+#define DUALFLAG_LEN 2 /* Dual Image flag Length */
+#define INACTIVEFLAG_LEN 2 /* Inactie Flag Length */
+#define RSASIG_LEN 20 /* Length of RSA Signature in tag */
+#define TAGINFO1_LEN 30 /* Length of vendor information field1 in tag */
+#define ZYX_TAGINFO1_LEN 20 /* Length of vendor information field1 in tag */
+#define FLASHLAYOUTVER_LEN 4 /* Length of Flash Layout Version String tag */
+#define TAGINFO2_LEN 16 /* Length of vendor information field2 in tag */
+#define CRC_LEN 4 /* Length of CRC in bytes */
+
+#define IMAGETAG_CRC_START 0xFFFFFFFF
+
+struct bcm_tag {
+ char tagVersion[TAGVER_LEN]; // 0-3: Version of the image tag
+ char sig_1[SIG1_LEN]; // 4-23: Company Line 1
+ char sig_2[SIG2_LEN]; // 24-37: Company Line 2
+ char chipid[CHIPID_LEN]; // 38-43: Chip this image is for
+ char boardid[BOARDID_LEN]; // 44-59: Board name
+ char big_endian[ENDIANFLAG_LEN]; // 60-61: Map endianness -- 1 BE 0 LE
+ char totalLength[IMAGE_LEN]; // 62-71: Total length of image
+ char cfeAddress[ADDRESS_LEN]; // 72-83: Address in memory of CFE
+ char cfeLength[IMAGE_LEN]; // 84-93: Size of CFE
+ char flashImageStart[ADDRESS_LEN]; // 94-105: Address in memory of image start (kernel for OpenWRT, rootfs for stock firmware)
+ char flashRootLength[IMAGE_LEN]; // 106-115: Size of rootfs for flashing
+ char kernelAddress[ADDRESS_LEN]; // 116-127: Address in memory of kernel
+ char kernelLength[IMAGE_LEN]; // 128-137: Size of kernel
+ char dualImage[DUALFLAG_LEN]; // 138-139: Unused at present
+ char inactiveFlag[INACTIVEFLAG_LEN]; // 140-141: Unused at present
+ char rsa_signature[RSASIG_LEN]; // 142-161: RSA Signature (unused at present; some vendors may use this)
+ char information1[TAGINFO1_LEN]; // 162-191: Compilation and related information (not generated/used by OpenWRT)
+ char flashLayoutVer[FLASHLAYOUTVER_LEN]; // 192-195: Version flash layout
+ char fskernelCRC[CRC_LEN]; // 196-199: kernel+rootfs CRC32
+ char information2[TAGINFO2_LEN]; // 200-215: Unused at present except Alice Gate where is is information
+ char imageCRC[CRC_LEN]; // 216-219: CRC32 of image less imagetag (kernel for Alice Gate)
+ char rootfsCRC[CRC_LEN]; // 220-223: CRC32 of rootfs partition
+ char kernelCRC[CRC_LEN]; // 224-227: CRC32 of kernel partition
+ char imageSequence[4]; // 228-231: Image sequence number
+ char rootLength[4]; // 232-235: steal from reserved1 to keep the real root length so we can use in the flash map even after we have change the rootLength to 0 to satisfy devices that check CRC on every boot
+ char headerCRC[CRC_LEN]; // 236-239: CRC32 of header excluding tagVersion
+ char reserved2[16]; // 240-255: Unused at present
+};
+
+struct zyxbcm_tag {
+ char tagVersion[TAGVER_LEN]; // 0-3: Version of the image tag
+ char sig_1[SIG1_LEN]; // 4-23: Company Line 1
+ char sig_2[SIG2_LEN]; // 24-37: Company Line 2
+ char chipid[CHIPID_LEN]; // 38-43: Chip this image is for
+ char boardid[BOARDID_LEN]; // 44-59: Board name
+ char big_endian[ENDIANFLAG_LEN]; // 60-61: Map endianness -- 1 BE 0 LE
+ char totalLength[IMAGE_LEN]; // 62-71: Total length of image
+ char cfeAddress[ADDRESS_LEN]; // 72-83: Address in memory of CFE
+ char cfeLength[IMAGE_LEN]; // 84-93: Size of CFE
+ char flashImageStart[ADDRESS_LEN]; // 94-105: Address in memory of image start (kernel for OpenWRT, rootfs for stock firmware)
+ char flashRootLength[IMAGE_LEN]; // 106-115: Size of rootfs for flashing
+ char kernelAddress[ADDRESS_LEN]; // 116-127: Address in memory of kernel
+ char kernelLength[IMAGE_LEN]; // 128-137: Size of kernel
+ char dualImage[DUALFLAG_LEN]; // 138-139: Unused at present
+ char inactiveFlag[INACTIVEFLAG_LEN]; // 140-141: Unused at present
+ char rsa_signature[RSASIG_LEN]; // 142-161: RSA Signature (unused at present; some vendors may use this)
+ char information1[ZYX_TAGINFO1_LEN]; // 162-181: Compilation and related information (not generated/used by OpenWRT)
+ char flashImageEnd[ADDRESS_LEN]; // 182-193: Address in memory of image end
+ char fskernelCRC[CRC_LEN]; // 194-197: kernel+rootfs CRC32
+ char reserved1[2]; // 198-199: Unused at present
+ char information2[TAGINFO2_LEN]; // 200-215: Unused at present except Alice Gate where is is information
+ char imageCRC[CRC_LEN]; // 216-219: CRC32 of image less imagetag (kernel for Alice Gate)
+ char rootfsCRC[CRC_LEN]; // 220-223: CRC32 of rootfs partition
+ char kernelCRC[CRC_LEN]; // 224-227: CRC32 of kernel partition
+ char imageSequence[4]; // 228-231: Image sequence number
+ char rootLength[4]; // 232-235: steal from reserved1 to keep the real root length so we can use in the flash map even after we have change the rootLength to 0 to satisfy devices that check CRC on every boot
+ char headerCRC[CRC_LEN]; // 236-239: CRC32 of header excluding tagVersion
+ char reserved2[16]; // 240-255: Unused at present
+};
+
+static uint32_t crc32tab[256] = {
+ 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
+ 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
+ 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
+ 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
+ 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
+ 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
+ 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
+ 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
+ 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
+ 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
+ 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
+ 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
+ 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
+ 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
+ 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
+ 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
+ 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
+ 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
+ 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
+ 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
+ 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
+ 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
+ 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
+ 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
+ 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
+ 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
+ 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
+ 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
+ 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
+ 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
+ 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
+ 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
+};
+
+uint32_t crc32(uint32_t crc, uint8_t *data, size_t len)
+{
+ while (len--)
+ crc = (crc >> 8) ^ crc32tab[(crc ^ *data++) & 0xFF];
+
+ return crc;
+}
+
+void fix_header(void *buf)
+{
+ struct bcm_tag *bcmtag = buf;
+ struct zyxbcm_tag *zyxtag = buf;
+ uint8_t fskernel_crc[CRC_LEN];
+ uint32_t crc;
+ uint64_t flash_start, rootfs_len, kernel_len;
+
+ /* Backup values */
+ flash_start = strtoul(bcmtag->flashImageStart, NULL, 10);
+ rootfs_len = strtoul(bcmtag->flashRootLength, NULL, 10);
+ kernel_len = strtoul(bcmtag->kernelLength, NULL, 10);
+ memcpy(fskernel_crc, bcmtag->fskernelCRC, CRC_LEN);
+
+ /* Clear values */
+ zyxtag->information1[ZYX_TAGINFO1_LEN - 1] = 0;
+ memset(zyxtag->flashImageEnd, 0, ADDRESS_LEN);
+ memset(zyxtag->fskernelCRC, 0, CRC_LEN);
+ memset(zyxtag->reserved1, 0, 2);
+
+ /* Replace values */
+ sprintf(zyxtag->flashImageEnd, "%lu", flash_start + rootfs_len + kernel_len);
+ memcpy(zyxtag->fskernelCRC, fskernel_crc, CRC_LEN);
+
+ /* Update tag crc */
+ crc = htonl(crc32(IMAGETAG_CRC_START, buf, 236));
+ memcpy(zyxtag->headerCRC, &crc, 4);
+}
+
+void usage(void) __attribute__ (( __noreturn__ ));
+
+void usage(void)
+{
+ fprintf(stderr, "Usage: zyxbcm [-i <inputfile>] [-o <outputfile>]\n");
+ exit(EXIT_FAILURE);
+}
+
+int main(int argc, char **argv)
+{
+ char buf[1024]; /* keep this at 1k or adjust garbage calc below */
+ FILE *in = stdin, *out = stdout;
+ char *ifn = NULL, *ofn = NULL;
+ size_t n;
+ int c, first_block = 1;
+
+ while ((c = getopt(argc, argv, "i:o:h")) != -1) {
+ switch (c) {
+ case 'i':
+ ifn = optarg;
+ break;
+ case 'o':
+ ofn = optarg;
+ break;
+ case 'h':
+ default:
+ usage();
+ }
+ }
+
+ if (optind != argc || optind == 1) {
+ fprintf(stderr, "illegal arg \"%s\"\n", argv[optind]);
+ usage();
+ }
+
+ if (ifn && !(in = fopen(ifn, "r"))) {
+ fprintf(stderr, "can not open \"%s\" for reading\n", ifn);
+ usage();
+ }
+
+ if (ofn && !(out = fopen(ofn, "w"))) {
+ fprintf(stderr, "can not open \"%s\" for writing\n", ofn);
+ usage();
+ }
+
+ while ((n = fread(buf, 1, sizeof(buf), in)) > 0) {
+ if (n < sizeof(buf)) {
+ if (ferror(in)) {
+ FREAD_ERROR:
+ fprintf(stderr, "fread error\n");
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (first_block && n >= 256) {
+ fix_header(buf);
+ first_block = 0;
+ }
+
+ if (!fwrite(buf, n, 1, out)) {
+ FWRITE_ERROR:
+ fprintf(stderr, "fwrite error\n");
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (ferror(in)) {
+ goto FREAD_ERROR;
+ }
+
+ if (fflush(out)) {
+ goto FWRITE_ERROR;
+ }
+
+ fclose(in);
+ fclose(out);
+
+ return EXIT_SUCCESS;
+}