tools/mktplinkfw2: add support for bootloader images
authorAlexander Couzens <lynxis@fe80.eu>
Wed, 25 Apr 2018 09:42:43 +0000 (11:42 +0200)
committerAlexander Couzens <lynxis@fe80.eu>
Fri, 25 May 2018 22:43:01 +0000 (00:43 +0200)
Some boards require a bootloader to create a working
factory update image. E.g. the tplink 1043v1.

Signed-off-by: Alexander Couzens <lynxis@fe80.eu>
tools/firmware-utils/src/mktplinkfw2.c

index dead49e..46db5b3 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2018 Alexander Couzens <lynxis@fe80.eu>
  *
  * This tool was based on:
  *   TP-Link WR941 V2 firmware checksum fixing tool.
@@ -103,7 +104,7 @@ 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 struct file_info boot_info = { 0 };
 int combined;
 int strip_padding;
 int add_jffs2_eof;
@@ -176,6 +177,7 @@ static void usage(int status)
 "  -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"
+"  -b <file>       read bootloader 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"
@@ -244,11 +246,23 @@ static int check_options(void)
        if (!rootfs_ofs)
                rootfs_ofs = layout->rootfs_ofs;
 
+       /* check bootloader */
+       ret = get_file_stat(&boot_info);
+       if (ret) {
+               ERR("Can not load bootloader image.");
+               return ret;
+       }
+
+       if (boot_info.file_size > 2 * 64 * 1024) {
+               /* the offset in fill_header is hardcoded to 128k */
+               ERR("Bootloader image is bigger than 128k.");
+               return -1;
+       }
+
        if (kernel_info.file_name == NULL) {
                ERR("no kernel image specified");
                return -1;
        }
-
        ret = get_file_stat(&kernel_info);
        if (ret)
                return ret;
@@ -318,10 +332,14 @@ static int check_options(void)
        return 0;
 }
 
-void fill_header(char *buf, int len)
+void _fill_header(char *buf, int len, int with_bootloader)
 {
        struct fw_header *hdr = (struct fw_header *)buf;
        unsigned ver_len;
+       unsigned int offset = 0;
+
+       if (with_bootloader)
+               offset = 2 * 64 * 1024 + sizeof(struct fw_header);
 
        memset(hdr, '\xff', sizeof(struct fw_header));
 
@@ -337,7 +355,7 @@ void fill_header(char *buf, int len)
        hdr->hw_rev = htonl(board->hw_rev);
        hdr->hw_ver_add = htonl(board->hw_ver_add);
 
-       if (boot_info.file_size == 0) {
+       if (boot_info.file_size == 0 || !with_bootloader) {
                memcpy(hdr->md5sum1, md5salt_normal, sizeof(hdr->md5sum1));
                hdr->boot_ofs = htonl(0);
                hdr->boot_len = htonl(0);
@@ -349,10 +367,13 @@ void fill_header(char *buf, int len)
 
        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->fw_length = htonl(layout->fw_max_len + offset);
+       hdr->kernel_ofs = htonl(sizeof(struct fw_header) + offset);
        hdr->kernel_len = htonl(kernel_len);
        if (!combined) {
+               /* even the bootloader doesnt increased the root_ofs. Unsure if this parser
+                * always ignores the rootfs or only in the 841v13
+                */
                hdr->rootfs_ofs = htonl(rootfs_ofs);
                hdr->rootfs_len = htonl(rootfs_info.file_size);
        }
@@ -380,6 +401,11 @@ void fill_header(char *buf, int len)
        get_md5(buf, len, hdr->md5sum1);
 }
 
+/* fill_header get called by mktplinkfw_lib to fill the header in front of the kernel. */
+void fill_header(char *buf, int len) {
+       _fill_header(buf, len, 0);
+}
+
 static int inspect_fw(void)
 {
        char *buf;
@@ -524,6 +550,52 @@ static int inspect_fw(void)
        return ret;
 }
 
+int prepend_bootloader() {
+       unsigned int buflen = 0;
+       int ret = 0;
+       char *buf = 0, *p = 0;
+       struct file_info image;
+
+       image.file_name = ofname;
+       ret = get_file_stat(&image);
+       if (!ret) {
+               ERR("Can not load the output image");
+               return ret;
+       }
+
+       buflen = image.file_size + 0x20200;
+       buf = malloc(buflen);
+       if (buf == NULL) {
+               ERR("Can not allocate buffer %d bytes", buflen);
+               return -1;
+       }
+       memset(buf, 0xff, buflen);
+
+       /* load old image */
+       p = buf + 0x20200;
+       ret = read_to_buf(&image, p);
+       if (ret) {
+               ERR("Can not read output image");
+               goto out_free_buf;
+       }
+
+       p = buf + sizeof(struct fw_header);
+       ret = read_to_buf(&boot_info, p);
+
+       _fill_header(buf, buflen, 1);
+
+       ret = write_fw(ofname, buf, buflen);
+       if (ret)
+               goto out_free_buf;
+
+       ret = EXIT_SUCCESS;
+
+out_free_buf:
+       free(buf);
+
+       return ret;
+}
+
 int main(int argc, char *argv[])
 {
        int ret = EXIT_FAILURE;
@@ -533,7 +605,7 @@ int main(int argc, char *argv[])
        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");
+               c = getopt(argc, argv, "a:b:H:E:F:L:V:N:W:w:ci:k:r:R:o:xhsjv:y:T:e");
                if (c == -1)
                        break;
 
@@ -541,6 +613,9 @@ int main(int argc, char *argv[])
                case 'a':
                        sscanf(optarg, "0x%x", &rootfs_align);
                        break;
+               case 'b':
+                       boot_info.file_name = optarg;
+                       break;
                case 'H':
                        opt_hw_id = optarg;
                        break;
@@ -617,12 +692,14 @@ int main(int argc, char *argv[])
        if (ret)
                goto out;
 
-       if (!inspect_info.file_name)
+       if (!inspect_info.file_name) {
                ret = build_fw(sizeof(struct fw_header));
+               if (ret == 0 && boot_info.file_size > 0)
+                       ret = prepend_bootloader();
+       }
        else
                ret = inspect_fw();
 
  out:
        return ret;
 }
-