• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/firmware-utils/src/mktplinkfw2.c

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
  4  *
  5  * This tool was based on:
  6  *   TP-Link WR941 V2 firmware checksum fixing tool.
  7  *   Copyright (C) 2008,2009 Wang Jian <lark@linux.net.cn>
  8  */
  9 
 10 #include <stdio.h>
 11 #include <stdlib.h>
 12 #include <stdint.h>
 13 #include <string.h>
 14 #include <byteswap.h>
 15 #include <unistd.h>     /* for unlink() */
 16 #include <libgen.h>
 17 #include <getopt.h>     /* for getopt() */
 18 #include <stdarg.h>
 19 #include <errno.h>
 20 #include <stdbool.h>
 21 #include <endian.h>
 22 #include <sys/stat.h>
 23 
 24 #include <arpa/inet.h>
 25 #include <netinet/in.h>
 26 
 27 #include "md5.h"
 28 #include "mktplinkfw-lib.h"
 29 
 30 struct fw_header {
 31         uint32_t        version;                        /* 0x00: header version */
 32         char            fw_version[48];                 /* 0x04: fw version string */
 33         uint32_t        hw_id;                          /* 0x34: hardware id */
 34         uint32_t        hw_rev;                         /* 0x38: FIXME: hardware revision? */
 35         uint32_t        hw_ver_add;                     /* 0x3c: additional hardware version */
 36         uint8_t         md5sum1[MD5SUM_LEN];            /* 0x40 */
 37         uint32_t        unk2;                           /* 0x50: 0x00000000 */
 38         uint8_t         md5sum2[MD5SUM_LEN];            /* 0x54 */
 39         uint32_t        unk3;                           /* 0x64: 0xffffffff */
 40 
 41         uint32_t        kernel_la;                      /* 0x68: kernel load address */
 42         uint32_t        kernel_ep;                      /* 0x6c: kernel entry point */
 43         uint32_t        fw_length;                      /* 0x70: total length of the image */
 44         uint32_t        kernel_ofs;                     /* 0x74: kernel data offset */
 45         uint32_t        kernel_len;                     /* 0x78: kernel data length */
 46         uint32_t        rootfs_ofs;                     /* 0x7c: rootfs data offset */
 47         uint32_t        rootfs_len;                     /* 0x80: rootfs data length */
 48         uint32_t        boot_ofs;                       /* 0x84: bootloader offset */
 49         uint32_t        boot_len;                       /* 0x88: bootloader length */
 50         uint16_t        unk4;                           /* 0x8c: 0x55aa */
 51         uint8_t         sver_hi;                        /* 0x8e */
 52         uint8_t         sver_lo;                        /* 0x8f */
 53         uint8_t         unk5;                           /* 0x90: magic: 0xa5 */
 54         uint8_t         ver_hi;                         /* 0x91 */
 55         uint8_t         ver_mid;                        /* 0x92 */
 56         uint8_t         ver_lo;                         /* 0x93 */
 57         uint8_t         pad[364];
 58 } __attribute__ ((packed));
 59 
 60 #define FLAG_LE_KERNEL_LA_EP                    0x00000001      /* Little-endian used for kernel load address & entry point */
 61 
 62 struct board_info {
 63         char            *id;
 64         uint32_t        hw_id;
 65         uint32_t        hw_rev;
 66         uint32_t        hw_ver_add;
 67         char            *layout_id;
 68         uint32_t        hdr_ver;
 69         uint32_t        flags;
 70 };
 71 
 72 /*
 73  * Globals
 74  */
 75 char *ofname;
 76 char *progname;
 77 static char *vendor = "TP-LINK Technologies";
 78 static char *version = "ver. 1.0";
 79 static char *fw_ver = "0.0.0";
 80 static char *sver = "1.0";
 81 static uint32_t hdr_ver = 2;
 82 
 83 static struct board_info custom_board;
 84 
 85 static struct board_info *board;
 86 static char *layout_id;
 87 struct flash_layout *layout;
 88 static char *opt_hw_id;
 89 static char *opt_hw_rev;
 90 static char *opt_hw_ver_add;
 91 static int fw_ver_lo;
 92 static int fw_ver_mid;
 93 static int fw_ver_hi;
 94 static int sver_lo;
 95 static int sver_hi;
 96 struct file_info kernel_info;
 97 static uint32_t kernel_la = 0;
 98 static uint32_t kernel_ep = 0;
 99 uint32_t kernel_len = 0;
100 struct file_info rootfs_info;
101 uint32_t rootfs_ofs = 0;
102 uint32_t rootfs_align;
103 static struct file_info boot_info = { 0 };
104 int combined;
105 int strip_padding;
106 int add_jffs2_eof;
107 
108 static struct file_info inspect_info;
109 static int extract = 0;
110 
111 char md5salt_normal[MD5SUM_LEN] = {
112         0xdc, 0xd7, 0x3a, 0xa5, 0xc3, 0x95, 0x98, 0xfb,
113         0xdc, 0xf9, 0xe7, 0xf4, 0x0e, 0xae, 0x47, 0x37,
114 };
115 
116 char md5salt_boot[MD5SUM_LEN] = {
117         0x8c, 0xef, 0x33, 0x5f, 0xd5, 0xc5, 0xce, 0xfa,
118         0xac, 0x9c, 0x28, 0xda, 0xb2, 0xe9, 0x0f, 0x42,
119 };
120 
121 static struct flash_layout layouts[] = {
122         {
123                 .id             = "4Mmtk",
124                 .fw_max_len     = 0x3c0000,
125                 .kernel_la      = 0x80000000,
126                 .kernel_ep      = 0x80000000,
127                 .rootfs_ofs     = 0x140000,
128         }, {
129                 .id             = "4MLmtk",
130                 .fw_max_len     = 0x3d0000,
131                 .kernel_la      = 0x80000000,
132                 .kernel_ep      = 0x80000000,
133                 .rootfs_ofs     = 0x140000,
134         }, {
135                 .id             = "8Mltq",
136                 .fw_max_len     = 0x7a0000,
137                 .kernel_la      = 0x80002000,
138                 .kernel_ep      = 0x80002000,
139                 .rootfs_ofs     = 0x140000,
140         }, {
141                 .id             = "16Mltq",
142                 .fw_max_len     = 0xf90000,
143                 .kernel_la      = 0x80002000,
144                 .kernel_ep      = 0x800061b0,
145                 .rootfs_ofs     = 0x140000,
146         }, {
147                 .id             = "8Mmtk",
148                 .fw_max_len     = 0x7a0000,
149                 .kernel_la      = 0x80000000,
150                 .kernel_ep      = 0x80000000,
151                 .rootfs_ofs     = 0x140000,
152         }, {
153                 .id             = "16MLmtk",
154                 .fw_max_len     = 0xe90000,
155                 .kernel_la      = 0x80000000,
156                 .kernel_ep      = 0x80000000,
157                 .rootfs_ofs     = 0x140000,
158         }, {
159                 .id             = "16Mmtk",
160                 .fw_max_len     = 0xfa0000,
161                 .kernel_la      = 0x80000000,
162                 .kernel_ep      = 0x80000000,
163                 .rootfs_ofs     = 0x140000,
164         }, {
165                 .id             = "8MSUmtk", /* Split U-Boot OS */
166                 .fw_max_len     = 0x770000,
167                 .kernel_la      = 0x80000000,
168                 .kernel_ep      = 0x80000000,
169                 .rootfs_ofs     = 0x140000,
170         }, {
171                 .id             = "8MLmtk",
172                 .fw_max_len     = 0x7b0000,
173                 .kernel_la      = 0x80000000,
174                 .kernel_ep      = 0x80000000,
175                 .rootfs_ofs     = 0x140000,
176         }, {
177                 .id             = "8Mqca",
178                 .fw_max_len     = 0x7a0000,
179                 .kernel_la      = 0x80060000,
180                 .kernel_ep      = 0x80060000,
181                 .rootfs_ofs     = 0x140000,
182         }, {
183                 .id             = "16Mqca",
184                 .fw_max_len     = 0xf90000,
185                 .kernel_la      = 0x80060000,
186                 .kernel_ep      = 0x80060000,
187                 .rootfs_ofs     = 0x140000,
188         }, {
189                 /* terminating entry */
190         }
191 };
192 
193 static void usage(int status)
194 {
195         FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
196 
197         fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
198         fprintf(stream,
199 "\n"
200 "Options:\n"
201 "  -c              use combined kernel image\n"
202 "  -e              swap endianness in kernel load address and entry point\n"
203 "  -E <ep>         overwrite kernel entry point with <ep> (hexval prefixed with 0x)\n"
204 "  -L <la>         overwrite kernel load address with <la> (hexval prefixed with 0x)\n"
205 "  -H <hwid>       use hardware id specified with <hwid>\n"
206 "  -W <hwrev>      use hardware revision specified with <hwrev>\n"
207 "  -w <hwveradd>   use additional hardware version specified with <hwveradd>\n"
208 "  -F <id>         use flash layout specified with <id>\n"
209 "  -k <file>       read kernel image from the file <file>\n"
210 "  -r <file>       read rootfs image from the file <file>\n"
211 "  -b <file>       read bootloader image from the file <file>\n"
212 "  -a <align>      align the rootfs start on an <align> bytes boundary\n"
213 "  -R <offset>     overwrite rootfs offset with <offset> (hexval prefixed with 0x)\n"
214 "  -o <file>       write output to the file <file>\n"
215 "  -s              strip padding from the end of the image\n"
216 "  -j              add jffs2 end-of-filesystem markers\n"
217 "  -N <vendor>     set image vendor to <vendor>\n"
218 "  -T <version>    set header version to <version>\n"
219 "  -V <version>    set image version to <version>\n"
220 "  -v <version>    set firmware version to <version>\n"
221 "  -y <version>    set secondary version to <version>\n"
222 "  -i <file>       inspect given firmware file <file>\n"
223 "  -x              extract bootloader, kernel and rootfs while inspecting (requires -i)\n"
224 "  -h              show this screen\n"
225         );
226 
227         exit(status);
228 }
229 
230 static int check_options(void)
231 {
232         int ret;
233         int exceed_bytes;
234 
235         if (inspect_info.file_name) {
236                 ret = get_file_stat(&inspect_info);
237                 if (ret)
238                         return ret;
239 
240                 return 0;
241         } else if (extract) {
242                 ERR("no firmware for inspection specified");
243                 return -1;
244         }
245 
246         if (opt_hw_id == NULL) {
247                 ERR("hardware id must be specified");
248                 return -1;
249         }
250 
251         board = &custom_board;
252 
253         if (layout_id == NULL) {
254                 ERR("flash layout is not specified");
255                 return -1;
256         }
257 
258         board->hw_id = strtoul(opt_hw_id, NULL, 0);
259 
260         board->hw_rev = 1;
261         board->hw_ver_add = 0;
262 
263         if (opt_hw_rev)
264                 board->hw_rev = strtoul(opt_hw_rev, NULL, 0);
265         if (opt_hw_ver_add)
266                 board->hw_ver_add = strtoul(opt_hw_ver_add, NULL, 0);
267 
268         layout = find_layout(layouts, layout_id);
269         if (layout == NULL) {
270                 ERR("unknown flash layout \"%s\"", layout_id);
271                 return -1;
272         }
273 
274         if (!kernel_la)
275                 kernel_la = layout->kernel_la;
276         if (!kernel_ep)
277                 kernel_ep = layout->kernel_ep;
278         if (!rootfs_ofs)
279                 rootfs_ofs = layout->rootfs_ofs;
280 
281         /* check bootloader */
282         ret = get_file_stat(&boot_info);
283         if (ret) {
284                 ERR("Can not load bootloader image.");
285                 return ret;
286         }
287 
288         if (boot_info.file_size > 2 * 64 * 1024) {
289                 /* the offset in fill_header is hardcoded to 128k */
290                 ERR("Bootloader image is bigger than 128k.");
291                 return -1;
292         }
293 
294         if (kernel_info.file_name == NULL) {
295                 ERR("no kernel image specified");
296                 return -1;
297         }
298         ret = get_file_stat(&kernel_info);
299         if (ret)
300                 return ret;
301 
302         kernel_len = kernel_info.file_size;
303 
304         if (combined) {
305                 if (kernel_info.file_size >
306                     layout->fw_max_len - sizeof(struct fw_header)) {
307                         ERR("kernel image is too big");
308                         return -1;
309                 }
310         } else {
311                 if (rootfs_info.file_name == NULL) {
312                         ERR("no rootfs image specified");
313                         return -1;
314                 }
315 
316                 ret = get_file_stat(&rootfs_info);
317                 if (ret)
318                         return ret;
319 
320                 if (rootfs_align) {
321                         kernel_len += sizeof(struct fw_header);
322                         rootfs_ofs = ALIGN(kernel_len, rootfs_align);
323                         kernel_len -= sizeof(struct fw_header);
324 
325                         DBG("rootfs offset aligned to 0x%u", rootfs_ofs);
326 
327                         exceed_bytes = (kernel_len + rootfs_info.file_size) -
328                                 (layout->fw_max_len - sizeof(struct fw_header));
329                         if (exceed_bytes > 0) {
330                                 ERR("images are too big by %i bytes", exceed_bytes);
331                                 return -1;
332                         }
333                 } else {
334                         exceed_bytes = kernel_info.file_size -
335                                 (rootfs_ofs - sizeof(struct fw_header));
336                         if (exceed_bytes > 0) {
337                                 ERR("images are too big by %i bytes", exceed_bytes);
338                                 return -1;
339                         }
340 
341                         exceed_bytes = rootfs_info.file_size -
342                                 (layout->fw_max_len - rootfs_ofs);
343                         if (exceed_bytes > 0) {
344                                 ERR("images are too big by %i bytes", exceed_bytes);
345                                 return -1;
346                         }
347                 }
348         }
349 
350         if (ofname == NULL) {
351                 ERR("no output file specified");
352                 return -1;
353         }
354 
355         ret = sscanf(fw_ver, "%d.%d.%d", &fw_ver_hi, &fw_ver_mid, &fw_ver_lo);
356         if (ret != 3) {
357                 ERR("invalid firmware version '%s'", fw_ver);
358                 return -1;
359         }
360 
361         ret = sscanf(sver, "%d.%d", &sver_hi, &sver_lo);
362         if (ret != 2) {
363                 ERR("invalid secondary version '%s'", sver);
364                 return -1;
365         }
366 
367         return 0;
368 }
369 
370 void fill_header_bootloader(char *buf, int len, int with_bootloader)
371 {
372         struct fw_header *hdr = (struct fw_header *)buf;
373         unsigned ver_len;
374         unsigned int offset = 0;
375 
376         if (with_bootloader) {
377                 /* ensure the bootloader is padded to 64k */
378                 offset = boot_info.file_size & (64 * 1024);
379                 if (offset < boot_info.file_size)
380                         offset += 64 * 1024;
381 
382                 offset += sizeof(struct fw_header);
383         }
384 
385         memset(hdr, '\xff', sizeof(struct fw_header));
386 
387         hdr->version = htonl(bswap_32(hdr_ver));
388         ver_len = strlen(version);
389         if (ver_len > (sizeof(hdr->fw_version) - 1))
390                 ver_len = sizeof(hdr->fw_version) - 1;
391 
392         memcpy(hdr->fw_version, version, ver_len);
393         hdr->fw_version[ver_len] = 0;
394 
395         hdr->hw_id = htonl(board->hw_id);
396         hdr->hw_rev = htonl(board->hw_rev);
397         hdr->hw_ver_add = htonl(board->hw_ver_add);
398 
399         if (boot_info.file_size == 0 || !with_bootloader) {
400                 memcpy(hdr->md5sum1, md5salt_normal, sizeof(hdr->md5sum1));
401                 hdr->boot_ofs = htonl(0);
402                 hdr->boot_len = htonl(0);
403         } else {
404                 memcpy(hdr->md5sum1, md5salt_boot, sizeof(hdr->md5sum1));
405                 hdr->boot_ofs = htonl(0);
406                 hdr->boot_len = htonl(boot_info.file_size);
407         }
408 
409         hdr->kernel_la = htonl(kernel_la);
410         hdr->kernel_ep = htonl(kernel_ep);
411         hdr->fw_length = htonl(layout->fw_max_len + offset);
412         hdr->kernel_ofs = htonl(sizeof(struct fw_header) + offset);
413         hdr->kernel_len = htonl(kernel_len);
414         if (!combined) {
415                 /* even the bootloader doesnt increased the root_ofs. Unsure if this parser
416                  * always ignores the rootfs or only in the 841v13
417                  */
418                 hdr->rootfs_ofs = htonl(rootfs_ofs);
419                 hdr->rootfs_len = htonl(rootfs_info.file_size);
420         }
421 
422         hdr->unk2 = htonl(0);
423         hdr->unk3 = htonl(0xffffffff);
424         hdr->unk4 = htons(0x55aa);
425         hdr->unk5 = 0xa5;
426 
427         hdr->sver_hi = sver_hi;
428         hdr->sver_lo = sver_lo;
429 
430         hdr->ver_hi = fw_ver_hi;
431         hdr->ver_mid = fw_ver_mid;
432         hdr->ver_lo = fw_ver_lo;
433 
434         if (board->flags & FLAG_LE_KERNEL_LA_EP) {
435                 hdr->kernel_la = bswap_32(hdr->kernel_la);
436                 hdr->kernel_ep = bswap_32(hdr->kernel_ep);
437         }
438 
439         get_md5(buf, len, hdr->md5sum1);
440 }
441 
442 /* fill_header get called by mktplinkfw_lib to fill the header in front of the kernel. */
443 void fill_header(char *buf, int len) {
444         fill_header_bootloader(buf, len, 0);
445 }
446 
447 static int inspect_fw(void)
448 {
449         char *buf;
450         struct fw_header *hdr;
451         uint8_t md5sum[MD5SUM_LEN];
452         struct board_info *board;
453         int ret = EXIT_FAILURE;
454 
455         buf = malloc(inspect_info.file_size);
456         if (!buf) {
457                 ERR("no memory for buffer!\n");
458                 goto out;
459         }
460 
461         ret = read_to_buf(&inspect_info, buf);
462         if (ret)
463                 goto out_free_buf;
464         hdr = (struct fw_header *)buf;
465 
466         board = &custom_board;
467 
468         if (board->flags & FLAG_LE_KERNEL_LA_EP) {
469                 hdr->kernel_la = bswap_32(hdr->kernel_la);
470                 hdr->kernel_ep = bswap_32(hdr->kernel_ep);
471         }
472 
473         inspect_fw_pstr("File name", inspect_info.file_name);
474         inspect_fw_phexdec("File size", inspect_info.file_size);
475 
476         switch(bswap_32(ntohl(hdr->version))) {
477         case 2:
478         case 3:
479                 break;
480         default:
481                 ERR("file does not seem to have V2/V3 header!\n");
482                 goto out_free_buf;
483         }
484 
485         inspect_fw_phexdec("Version 2 Header size", sizeof(struct fw_header));
486 
487         memcpy(md5sum, hdr->md5sum1, sizeof(md5sum));
488         if (ntohl(hdr->boot_len) == 0)
489                 memcpy(hdr->md5sum1, md5salt_normal, sizeof(md5sum));
490         else
491                 memcpy(hdr->md5sum1, md5salt_boot, sizeof(md5sum));
492         get_md5(buf, inspect_info.file_size, hdr->md5sum1);
493 
494         if (memcmp(md5sum, hdr->md5sum1, sizeof(md5sum))) {
495                 inspect_fw_pmd5sum("Header MD5Sum1", md5sum, "(*ERROR*)");
496                 inspect_fw_pmd5sum("          --> expected", hdr->md5sum1, "");
497         } else {
498                 inspect_fw_pmd5sum("Header MD5Sum1", md5sum, "(ok)");
499         }
500         if (ntohl(hdr->unk2) != 0)
501                 inspect_fw_phexdec("Unknown value 2", hdr->unk2);
502         inspect_fw_pmd5sum("Header MD5Sum2", hdr->md5sum2,
503                            "(purpose yet unknown, unchecked here)");
504 
505         if (ntohl(hdr->unk3) != 0xffffffff)
506                 inspect_fw_phexdec("Unknown value 3", hdr->unk3);
507 
508         if (ntohs(hdr->unk4) != 0x55aa)
509                 inspect_fw_phexdec("Unknown value 4", hdr->unk4);
510 
511         if (hdr->unk5 != 0xa5)
512                 inspect_fw_phexdec("Unknown value 5", hdr->unk5);
513 
514         printf("\n");
515 
516         inspect_fw_pstr("Firmware version", hdr->fw_version);
517         inspect_fw_phex("Hardware ID", ntohl(hdr->hw_id));
518         inspect_fw_phex("Hardware Revision",
519                         ntohl(hdr->hw_rev));
520         inspect_fw_phex("Additional HW Version",
521                         ntohl(hdr->hw_ver_add));
522 
523         printf("%-23s: %d.%d.%d-%d.%d\n", "Software version",
524                hdr->ver_hi, hdr->ver_mid, hdr->ver_lo,
525                hdr->sver_hi, hdr->sver_lo);
526 
527         printf("\n");
528 
529         inspect_fw_phexdec("Kernel data offset",
530                            ntohl(hdr->kernel_ofs));
531         inspect_fw_phexdec("Kernel data length",
532                            ntohl(hdr->kernel_len));
533         inspect_fw_phex("Kernel load address",
534                         ntohl(hdr->kernel_la));
535         inspect_fw_phex("Kernel entry point",
536                         ntohl(hdr->kernel_ep));
537         inspect_fw_phexdec("Rootfs data offset",
538                            ntohl(hdr->rootfs_ofs));
539         inspect_fw_phexdec("Rootfs data length",
540                            ntohl(hdr->rootfs_len));
541         inspect_fw_phexdec("Boot loader data offset",
542                            ntohl(hdr->boot_ofs));
543         inspect_fw_phexdec("Boot loader data length",
544                            ntohl(hdr->boot_len));
545         inspect_fw_phexdec("Total firmware length",
546                            ntohl(hdr->fw_length));
547 
548         if (extract) {
549                 FILE *fp;
550                 char *filename;
551 
552                 printf("\n");
553 
554                 if (hdr->boot_len) {
555                         filename = malloc(strlen(inspect_info.file_name) + 8);
556                         sprintf(filename, "%s-bootloader", inspect_info.file_name);
557                         printf("Extracting bootloader to \"%s\"...\n", filename);
558                         fp = fopen(filename, "w");
559                         if (fp) {
560                                 if (!fwrite(buf + sizeof(struct fw_header) + ntohl(hdr->boot_ofs),
561                                         ntohl(hdr->boot_len), 1, fp)) {
562                                         ERR("error in fwrite(): %s", strerror(errno));
563                                 }
564                                 fclose(fp);
565                         } else {
566                                 ERR("error in fopen(): %s", strerror(errno));
567                         }
568                         free(filename);
569                 }
570 
571                 filename = malloc(strlen(inspect_info.file_name) + 8);
572                 sprintf(filename, "%s-kernel", inspect_info.file_name);
573                 printf("Extracting kernel to \"%s\"...\n", filename);
574                 fp = fopen(filename, "w");
575                 if (fp) {
576                         if (!fwrite(buf + ntohl(hdr->kernel_ofs),
577                                     ntohl(hdr->kernel_len), 1, fp)) {
578                                 ERR("error in fwrite(): %s", strerror(errno));
579                         }
580                         fclose(fp);
581                 } else {
582                         ERR("error in fopen(): %s", strerror(errno));
583                 }
584                 free(filename);
585 
586                 filename = malloc(strlen(inspect_info.file_name) + 8);
587                 sprintf(filename, "%s-rootfs", inspect_info.file_name);
588                 printf("Extracting rootfs to \"%s\"...\n", filename);
589                 fp = fopen(filename, "w");
590                 if (fp) {
591                         if (!fwrite(buf + ntohl(hdr->rootfs_ofs),
592                                     ntohl(hdr->rootfs_len), 1, fp)) {
593                                 ERR("error in fwrite(): %s", strerror(errno));
594                         }
595                         fclose(fp);
596                 } else {
597                         ERR("error in fopen(): %s", strerror(errno));
598                 }
599                 free(filename);
600         }
601 
602  out_free_buf:
603         free(buf);
604  out:
605         return ret;
606 }
607 
608 /* prepend a second image header and the bootloader.
609  *
610  * |------------|
611  * |image header|
612  * |------------|
613  * |bootloader  |
614  * |------------|
615  * |optional pad|
616  * |------------|
617  * |image header|
618  * |------------|
619  * |kernel image|
620  * |------------|
621  * |rootfs image|
622  * |------------|
623  *
624  * The padding is optional. The second image header should begin a 64k boundary.
625  */
626 int prepend_bootloader() {
627         unsigned int buflen = 0;
628         int ret = 0, bootloader_padded = 0;
629         char *buf = 0, *p = 0;
630         struct file_info image;
631 
632         /* calculate blocks to ensure padding */
633         bootloader_padded = boot_info.file_size & (64 * 1024);
634         if (bootloader_padded < boot_info.file_size)
635                 bootloader_padded += 64 * 1024;
636 
637         image.file_name = ofname;
638         ret = get_file_stat(&image);
639         if (ret) {
640                 ERR("Can not load the output image");
641                 return ret;
642         }
643 
644         buflen = image.file_size + bootloader_padded + sizeof(struct fw_header);
645         buf = malloc(buflen);
646         if (buf == NULL) {
647                 ERR("Can not allocate buffer %d bytes", buflen);
648                 return -1;
649         }
650         memset(buf, 0xff, buflen);
651 
652         /* load old image */
653         p = buf + bootloader_padded + sizeof(struct fw_header);
654         ret = read_to_buf(&image, p);
655         if (ret) {
656                 ERR("Can not read output image");
657                 goto out_free_buf;
658         }
659 
660         p = buf + sizeof(struct fw_header);
661         ret = read_to_buf(&boot_info, p);
662 
663         fill_header_bootloader(buf, buflen, 1);
664 
665         ret = write_fw(ofname, buf, buflen);
666         if (ret)
667                 goto out_free_buf;
668 
669         ret = EXIT_SUCCESS;
670 
671 out_free_buf:
672         free(buf);
673 
674         return ret;
675 }
676 
677 int main(int argc, char *argv[])
678 {
679         int ret = EXIT_FAILURE;
680 
681         progname = basename(argv[0]);
682 
683         while ( 1 ) {
684                 int c;
685 
686                 c = getopt(argc, argv, "a:b:H:E:F:L:V:N:W:w:ci:k:r:R:o:xhsjv:y:T:e");
687                 if (c == -1)
688                         break;
689 
690                 switch (c) {
691                 case 'a':
692                         sscanf(optarg, "0x%x", &rootfs_align);
693                         break;
694                 case 'b':
695                         boot_info.file_name = optarg;
696                         break;
697                 case 'H':
698                         opt_hw_id = optarg;
699                         break;
700                 case 'E':
701                         sscanf(optarg, "0x%x", &kernel_ep);
702                         break;
703                 case 'F':
704                         layout_id = optarg;
705                         break;
706                 case 'W':
707                         opt_hw_rev = optarg;
708                         break;
709                 case 'w':
710                         opt_hw_ver_add = optarg;
711                         break;
712                 case 'L':
713                         sscanf(optarg, "0x%x", &kernel_la);
714                         break;
715                 case 'V':
716                         version = optarg;
717                         break;
718                 case 'v':
719                         fw_ver = optarg;
720                         break;
721                 case 'y':
722                         sver = optarg;
723                         break;
724                 case 'N':
725                         vendor = optarg;
726                         break;
727                 case 'c':
728                         combined++;
729                         break;
730                 case 'k':
731                         kernel_info.file_name = optarg;
732                         break;
733                 case 'r':
734                         rootfs_info.file_name = optarg;
735                         break;
736                 case 'R':
737                         sscanf(optarg, "0x%x", &rootfs_ofs);
738                         break;
739                 case 'o':
740                         ofname = optarg;
741                         break;
742                 case 's':
743                         strip_padding = 1;
744                         break;
745                 case 'i':
746                         inspect_info.file_name = optarg;
747                         break;
748                 case 'j':
749                         add_jffs2_eof = 1;
750                         break;
751                 case 'x':
752                         extract = 1;
753                         break;
754                 case 'T':
755                         hdr_ver = atoi(optarg);
756                         break;
757                 case 'e':
758                         custom_board.flags = FLAG_LE_KERNEL_LA_EP;
759                         break;
760                 case 'h':
761                         usage(EXIT_SUCCESS);
762                         break;
763                 default:
764                         usage(EXIT_FAILURE);
765                         break;
766                 }
767         }
768 
769         ret = check_options();
770         if (ret)
771                 goto out;
772 
773         if (!inspect_info.file_name) {
774                 ret = build_fw(sizeof(struct fw_header));
775                 if (ret == 0 && boot_info.file_size > 0)
776                         ret = prepend_bootloader();
777         }
778         else
779                 ret = inspect_fw();
780 
781  out:
782         return ret;
783 }
784 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt