2 * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
3 * Copyright (C) 2016 Tal Keren <kooolk@gmail.com>
5 * Stripped down version of the regular tplink firmware that is only used
6 * for compressing and booting the kernel.
8 * This tool was based on:
9 * TP-Link WR941 V2 firmware checksum fixing tool.
10 * Copyright (C) 2008,2009 Wang Jian <lark@linux.net.cn>
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License version 2 as published
14 * by the Free Software Foundation.
22 #include <unistd.h> /* for unlink() */
24 #include <getopt.h> /* for getopt() */
29 #include <arpa/inet.h>
30 #include <netinet/in.h>
32 #define ALIGN(x,a) ({ typeof(a) __a = (a); (((x) + __a - 1) & ~(__a - 1)); })
34 #define HEADER_VERSION_V1 0x01000000
39 char *file_name
; /* name of the file */
40 uint32_t file_size
; /* length of the file */
44 uint32_t version
; /* header version */
47 uint32_t hw_id
; /* hardware id */
48 uint32_t hw_rev
; /* hardware revision */
50 uint8_t md5sum1
[MD5SUM_LEN
];
52 uint8_t md5sum2
[MD5SUM_LEN
];
54 uint32_t kernel_la
; /* kernel load address */
55 uint32_t kernel_ep
; /* kernel entry point */
56 uint32_t fw_length
; /* total length of the firmware */
57 uint32_t kernel_ofs
; /* kernel data offset */
58 uint32_t kernel_len
; /* kernel data length */
59 uint32_t rootfs_ofs
; /* rootfs data offset */
60 uint32_t rootfs_len
; /* rootfs data length */
61 uint32_t boot_ofs
; /* bootloader data offset */
62 uint32_t boot_len
; /* bootloader data length */
67 } __attribute__ ((packed
));
74 static char *progname
;
75 static char *vendor
= "TP-LINK Technologies";
76 static char *version
= "ver. 1.0";
77 static char *fw_ver
= "0.0.0";
78 static uint32_t hdr_ver
= HEADER_VERSION_V1
;
80 static char *opt_hw_id
;
81 static uint32_t hw_id
= 0;
82 static struct file_info kernel_info
;
83 static uint32_t kernel_la
= 0;
84 static uint32_t kernel_ep
= 0;
85 static uint32_t kernel_len
= 0;
90 #define ERR(fmt, ...) do { \
92 fprintf(stderr, "[%s] *** error: " fmt "\n", \
93 progname, ## __VA_ARGS__ ); \
96 #define ERRS(fmt, ...) do { \
99 fprintf(stderr, "[%s] *** error: " fmt ": %s\n", \
100 progname, ## __VA_ARGS__, strerror(save)); \
103 #define DBG(fmt, ...) do { \
104 fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
107 static void usage(int status
)
109 FILE *stream
= (status
!= EXIT_SUCCESS
) ? stderr
: stdout
;
110 struct board_info
*board
;
112 fprintf(stream
, "Usage: %s [OPTIONS...]\n", progname
);
116 " -E <ep> kernel entry point with <ep> (hexval prefixed with 0x)\n"
117 " -L <la> kernel load address with <la> (hexval prefixed with 0x)\n"
118 " -H <hwid> use hardware id specified with <hwid>\n"
119 " -k <file> read kernel image from the file <file>\n"
120 " -o <file> write output to the file <file>\n"
121 " -N <vendor> set image vendor to <vendor>\n"
122 " -V <version> set image version to <version>\n"
123 " -h show this screen\n"
129 static int get_file_stat(struct file_info
*fdata
)
134 if (fdata
->file_name
== NULL
)
137 res
= stat(fdata
->file_name
, &st
);
139 ERRS("stat failed on %s", fdata
->file_name
);
143 fdata
->file_size
= st
.st_size
;
147 static int read_to_buf(struct file_info
*fdata
, char *buf
)
150 int ret
= EXIT_FAILURE
;
152 f
= fopen(fdata
->file_name
, "r");
154 ERRS("could not open \"%s\" for reading", fdata
->file_name
);
159 fread(buf
, fdata
->file_size
, 1, f
);
161 ERRS("unable to read from file \"%s\"", fdata
->file_name
);
173 static int check_options(void)
178 hw_id
= strtoul(opt_hw_id
, NULL
, 0);
181 if (!kernel_la
|| !kernel_ep
) {
182 ERR("kernel loading address and entry point must be specified");
186 if (kernel_info
.file_name
== NULL
) {
187 ERR("no kernel image specified");
191 ret
= get_file_stat(&kernel_info
);
195 kernel_len
= kernel_info
.file_size
;
197 if (ofname
== NULL
) {
198 ERR("no output file specified");
205 static void fill_header(char *buf
)
207 struct fw_header
*hdr
= (struct fw_header
*)buf
;
209 memset(hdr
, 0, sizeof(struct fw_header
));
211 hdr
->version
= htonl(hdr_ver
);
212 strncpy(hdr
->vendor_name
, vendor
, sizeof(hdr
->vendor_name
));
213 strncpy(hdr
->fw_version
, version
, sizeof(hdr
->fw_version
));
216 * This field is ignored and not specified in stock firmware
217 * It is specified here to ensure sysupgrade hardware compatibility
218 * The hardware id of a device is in the product-info partition
220 hdr
->hw_id
= htonl(hw_id
);
222 hdr
->kernel_la
= htonl(kernel_la
);
223 hdr
->kernel_ep
= htonl(kernel_ep
);
225 hdr
->kernel_ofs
= htonl(sizeof(struct fw_header
));
226 hdr
->kernel_len
= htonl(kernel_len
);
229 static int write_fw(char *data
, int len
)
232 int ret
= EXIT_FAILURE
;
234 f
= fopen(ofname
, "w");
236 ERRS("could not open \"%s\" for writing", ofname
);
241 fwrite(data
, len
, 1, f
);
243 ERRS("unable to write output file");
247 DBG("firmware file \"%s\" completed", ofname
);
254 if (ret
!= EXIT_SUCCESS
) {
261 static int build_fw(void)
266 int ret
= EXIT_FAILURE
;
268 buflen
= sizeof(struct fw_header
) + kernel_len
;
269 buflen
= ALIGN(buflen
, 0x4);
271 buf
= malloc(buflen
);
273 ERR("no memory for buffer\n");
277 memset(buf
, 0, buflen
);
278 p
= buf
+ sizeof(struct fw_header
);
279 ret
= read_to_buf(&kernel_info
, p
);
284 ret
= write_fw(buf
, buflen
);
296 int main(int argc
, char *argv
[])
298 int ret
= EXIT_FAILURE
;
303 progname
= basename(argv
[0]);
308 c
= getopt(argc
, argv
, "H:E:L:V:N:k:o:h");
317 sscanf(optarg
, "0x%x", &kernel_ep
);
320 sscanf(optarg
, "0x%x", &kernel_la
);
329 kernel_info
.file_name
= optarg
;
343 ret
= check_options();