From: Alexander Couzens Date: Wed, 25 Apr 2018 09:42:43 +0000 (+0200) Subject: tools/mktplinkfw2: add support to pack bootloader X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=0bd4a1251caa048a95ea55254fc7c4e6294cc3da;p=openwrt%2Fstaging%2Flynxis.git tools/mktplinkfw2: add support to pack bootloader The 841v13 and 841v14 can not flash any image without bootloader over the WebUI due a bug in the oem firmware upgrade software. Allow mktplinkfw2 to integrate bootloaders. An image with the bootloader looks: |------------| |image header| |------------| |bootloader | |------------| |optional pad| |------------| |image header| |------------| |kernel image| |------------| |rootfs image| |------------| The padding depends on the bootloader size. The 2nd image header must start on a 64k boundary. Signed-off-by: Alexander Couzens --- diff --git a/tools/firmware-utils/src/mktplinkfw2.c b/tools/firmware-utils/src/mktplinkfw2.c index cec7c87126..9eb226fba8 100644 --- a/tools/firmware-utils/src/mktplinkfw2.c +++ b/tools/firmware-utils/src/mktplinkfw2.c @@ -103,7 +103,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; @@ -194,6 +194,7 @@ static void usage(int status) " -F use flash layout specified with \n" " -k read kernel image from the file \n" " -r read rootfs image from the file \n" +" -b read bootloader image from the file \n" " -a align the rootfs start on an bytes boundary\n" " -R overwrite rootfs offset with (hexval prefixed with 0x)\n" " -o write output to the file \n" @@ -262,11 +263,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; @@ -336,10 +349,20 @@ 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) { + /* ensure the bootloader is padded to 64k */ + offset = boot_info.file_size & (64 * 1024); + if (offset < boot_info.file_size) + offset += 64 * 1024; + + offset += sizeof(struct fw_header); + } memset(hdr, '\xff', sizeof(struct fw_header)); @@ -355,29 +378,29 @@ 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); } 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->boot_ofs = htonl(0); + hdr->boot_len = htonl(boot_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->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); } - 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); @@ -398,6 +421,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; @@ -559,6 +587,75 @@ static int inspect_fw(void) return ret; } +/* prepend a second image header and the bootloader. + * + * |------------| + * |image header| + * |------------| + * |bootloader | + * |------------| + * |optional pad| + * |------------| + * |image header| + * |------------| + * |kernel image| + * |------------| + * |rootfs image| + * |------------| + * + * The padding is optional. The second image header should begin a 64k boundary. + */ +int prepend_bootloader() { + unsigned int buflen = 0; + int ret = 0, bootloader_padded = 0; + char *buf = 0, *p = 0; + struct file_info image; + + /* calculate blocks to ensure padding */ + bootloader_padded = boot_info.file_size & (64 * 1024); + if (bootloader_padded < boot_info.file_size) + bootloader_padded += 64 * 1024; + + image.file_name = ofname; + ret = get_file_stat(&image); + if (ret) { + ERR("Can not load the output image"); + return ret; + } + + buflen = image.file_size + bootloader_padded + sizeof(struct fw_header); + 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 + bootloader_padded + sizeof(struct fw_header); + 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; @@ -568,7 +665,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; @@ -576,6 +673,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; @@ -652,12 +752,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; } -