2 * WRT400n - Firmware Generation Creator
4 * Creates a firmware image for the Linksys WRT400n router,
5 * that can be uploaded via the firmware upload page,
6 * from a kernel image file and root fs file
8 * Author: Sandeep Mistry
10 * - remove size limit on kernel and rootfs part
12 #include <arpa/inet.h>
19 #include <sys/types.h>
25 // Prelimiary test shows that the OEM upgrade program only checks checksum of
26 // the whole firmware image, ignoring specific checksums of kernel and rootfs
27 // part. But we are computing crc32 sums of fixed length of data here in lieu
28 // of read_fw utility found in OEM SDK
29 #define CRC_SZ_KERNEL 0x100000
30 #define CRC_SZ_ROOTFS 0x2fffc4
31 // OEM firmware has size limit on "linux" and "rootfs" partition. That's also
32 // the limit for factory firmware images as fwupgrade utility in the OEM system
33 // needs to write kernel and rootfs to those two partitions (/dev/mtd2 and
34 // /dev/mtd3 to be exact)
35 #define SZ_MAX_KERNEL (0x180000 - 0x40000)
36 #define SZ_MAX_ROOTFS (0x7b0000 - 0x18000)
41 // GPL Tarball: http://downloads.linksysbycisco.com/downloads/WRT400N_1.0.01.19_US.tar,0.gz
42 // File: WRT400N_1.0.01.19_US/FW_WRT400N_1.0.01.19_US_20081229/GTK/user/include/fw_upgrade.h
45 // - checksum: CRC32 of kernel and root fs, back to back
46 // - magic: GMTKRT400N
47 // - kernel_length: kernel length in bytes
48 // - kernel_upgrade_flag: should we upgrade the kernel - set to 1
49 // - rootfs_length: root fs length in byte
50 // - rootfs_upgrade_flag: should we upgrade the root fs - set to 1
51 // - kernel_checksum: Gary S. Brown's 32 bit CRC algorithm for kernel, with remaining bits
52 // set to 0xFF upto 0x100000 bytes (total length)
53 // - rootfs_checksum: Gary S. Brown's 32 bit CRC algorithm for root fs, with remaining bits
54 // set to 0xFF upto 0x2FFFC4 bytes (total length)
55 // - fw_totalsize: total firmware image file length (header length + kernel length + root fs length)
56 // - reserved[4]: reserved ??? - set to all 0xFF
59 uint32_t checksum
; /* CRC32 */
60 uint8_t magic
[12]; /* The value of GTIMG_MAGIC */
61 uint32_t kernel_length
; /* The length of the kernel image */
62 //uint32_t kernel_entry_point; /* Kernel's entry point for RedBoot's information */
63 uint32_t kernel_upgrade_flag
; /* Set to 1 if we need to upgrade the kernel parition of the Flash */
64 uint32_t rootfs_length
; /* The length of the rootfs image */
65 //uint32_t rootfs_entry_point; /* Not in use */
66 uint32_t rootfs_upgrade_flag
; /* Set to 1 if we need to upgrade the rootfs parition of the Flash */
68 // Add 3 items by Vic Yu, 2006-05/10
69 uint32_t kernel_checksum
;
70 uint32_t rootfs_checksum
;
71 uint32_t fw_totalsize
;
83 int get_file_info(struct file_info
*fi
, uint32_t *crc32_acc
)
87 uint32_t crc32sum
= 0;
89 int crc_rem
= fi
->crc_sz
;
94 _crc32_acc
= *crc32_acc
;
98 fd
= open(fi
->filename
, O_RDONLY
);
100 fprintf(stderr
, "error: opening '%s'\n", fi
->filename
);
104 sz
= read(fd
, buf
, sizeof(buf
));
107 _crc32_acc
= cyg_crc32_accumulate(_crc32_acc
, buf
, sz
);
110 crc32sum
= cyg_crc32_accumulate(crc32sum
, buf
, crc_rem
);
113 crc32sum
= cyg_crc32_accumulate(crc32sum
, buf
, sz
);
118 } else if (sz
== 0) {
121 fprintf(stderr
, "error read '%s'", strerror(errno
));
127 memset(buf
, 0xff, sizeof(buf
));
128 while (crc_rem
> 0) {
129 if (crc_rem
> sizeof(buf
)) {
130 crc32sum
= cyg_crc32_accumulate(crc32sum
, buf
, sizeof(buf
));
131 crc_rem
-= sizeof(buf
);
133 crc32sum
= cyg_crc32_accumulate(crc32sum
, buf
, crc_rem
);
141 fi
->filesize
= filesize
;
142 fi
->crc32sum
= crc32sum
;
144 *crc32_acc
= _crc32_acc
;
148 int copy_file(int fromfd
, int tofd
)
153 if (lseek(fromfd
, SEEK_SET
, 0) < 0) {
154 fprintf(stderr
, "lseek: %s\n", strerror(errno
));
158 szr
= read(fromfd
, buf
, sizeof(buf
));
160 szw
= write(tofd
, buf
, szr
);
162 fprintf(stderr
, "copy_file: error writing %d bytes: %s\n", szr
, strerror(errno
));
165 } else if (szr
== 0) {
168 fprintf(stderr
, "copy_file: error reading: %s\n", strerror(errno
));
175 int main(int argc
, char *argv
[])
177 struct file_info kernel_fi
;
178 struct file_info rootfs_fi
;
179 struct file_info output_fi
;
185 printf("Usage:\n\t%s <kernel file> <rootfs file> <output file>\n", argv
[0]);
189 kernel_fi
.crc_sz
= CRC_SZ_KERNEL
;
190 rootfs_fi
.crc_sz
= CRC_SZ_ROOTFS
;
196 kernel_fi
.filename
= argv
[1];
197 rootfs_fi
.filename
= argv
[2];
198 output_fi
.filename
= argv
[3];
200 kernel_fi
.crc32sum
= 0;
201 rootfs_fi
.crc32sum
= 0;
202 output_fi
.crc32sum
= 0xffffffff;
204 if (get_file_info(&kernel_fi
, &output_fi
.crc32sum
) < 0)
206 if (get_file_info(&rootfs_fi
, &output_fi
.crc32sum
) < 0)
208 output_fi
.crc32sum
= ~output_fi
.crc32sum
;
211 fprintf(stderr
, "%s: size %d (0x%x), crc32 = 0x%x\n",
212 kernel_fi
.filename
, kernel_fi
.filesize
, kernel_fi
.filesize
, kernel_fi
.crc32sum
);
213 fprintf(stderr
, "%s: size %d (0x%x), crc32 = 0x%x\n",
214 rootfs_fi
.filename
, rootfs_fi
.filesize
, rootfs_fi
.filesize
, rootfs_fi
.crc32sum
);
215 if (kernel_fi
.filesize
> SZ_MAX_KERNEL
) {
216 fprintf(stderr
, "%s: filesize exceeds 0x%x limit\n", SZ_MAX_KERNEL
);
219 if (rootfs_fi
.filesize
> SZ_MAX_ROOTFS
) {
220 fprintf(stderr
, "%s: filesize exceeds 0x%x limit\n", SZ_MAX_ROOTFS
);
224 // now for the header ...
225 memset(&ih
, 0xff, sizeof(ih
));
226 strcpy(ih
.magic
, "GMTKRT400N");
227 ih
.checksum
= htonl(output_fi
.crc32sum
);
228 ih
.kernel_length
= htonl(kernel_fi
.filesize
);
229 ih
.rootfs_length
= htonl(rootfs_fi
.filesize
);
230 ih
.kernel_upgrade_flag
= htonl(0x1);
231 ih
.rootfs_upgrade_flag
= htonl(0x1);
232 ih
.kernel_checksum
= htonl(kernel_fi
.crc32sum
);
233 ih
.rootfs_checksum
= htonl(rootfs_fi
.crc32sum
);
234 ih
.fw_totalsize
= htonl(kernel_fi
.filesize
+ rootfs_fi
.filesize
+ sizeof(ih
));
236 output_fi
.fd
= open(output_fi
.filename
, O_WRONLY
| O_CREAT
| O_TRUNC
,
237 S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
);
238 sz
= write(output_fi
.fd
, &ih
, sizeof(ih
));
239 if (sz
!= sizeof(ih
)) {
240 fprintf(stderr
, "error writing imghdr to output: %s\n", strerror(errno
));
243 if (copy_file(kernel_fi
.fd
, output_fi
.fd
)) {
244 fprintf(stderr
, "error copying %s to %s\n", kernel_fi
.filename
, output_fi
.filename
);
247 if (copy_file(rootfs_fi
.fd
, output_fi
.fd
)) {
248 fprintf(stderr
, "error copying %s to %s\n", rootfs_fi
.filename
, output_fi
.filename
);
251 // print some stats out
252 fprintf(stderr
, "crc = 0x%x, total size = %d (0x%x)\n",
253 output_fi
.crc32sum
, ntohl(ih
.fw_totalsize
), ntohl(ih
.fw_totalsize
));
257 #define CLOSE_FI_FD(fi) do { \
258 if ((fi).fd >= 0) { \
263 CLOSE_FI_FD(kernel_fi
);
264 CLOSE_FI_FD(rootfs_fi
);
265 CLOSE_FI_FD(output_fi
);