diff options
Diffstat (limited to 'tools/firmware-utils/src/mkdlinkfw.c')
-rw-r--r-- | tools/firmware-utils/src/mkdlinkfw.c | 664 |
1 files changed, 0 insertions, 664 deletions
diff --git a/tools/firmware-utils/src/mkdlinkfw.c b/tools/firmware-utils/src/mkdlinkfw.c deleted file mode 100644 index 6dbaf4ae27..0000000000 --- a/tools/firmware-utils/src/mkdlinkfw.c +++ /dev/null @@ -1,664 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * mkdlinkfw - * - * Copyright (C) 2018 Paweł Dembicki <paweldembicki@gmail.com> - * - * This tool is based on mktplinkfw. - * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org> - * Copyright (C) 2008,2009 Wang Jian <lark@linux.net.cn> - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <string.h> -#include <unistd.h> /* for unlink() */ -#include <libgen.h> -#include <getopt.h> /* for getopt() */ -#include <stdarg.h> -#include <stdbool.h> -#include <endian.h> -#include <errno.h> -#include <sys/stat.h> -#include <zlib.h> /*for crc32 */ - -#include "mkdlinkfw-lib.h" - -/* ARM update header 2.0 - * used only in factory images to erase and flash selected area - */ -struct auh_header { - uint8_t rom_id[12]; /* 12-bit rom-id unique per router type */ - uint16_t derange; /* used for scramble header */ - uint16_t image_checksum; /* jboot_checksum of flashed data */ - - uint32_t space1; /* zeros */ - uint32_t space2; /* zeros */ - uint16_t space3; /* zerosu */ - uint8_t lpvs; /* must be 0x01 */ - uint8_t mbz; /* bust be 0 */ - uint32_t time_stamp; /* timestamp calculated in jboot way */ - - uint32_t erase_start; /* erase start address */ - uint32_t erase_length; /* erase length address */ - uint32_t data_offset; /* data start address */ - uint32_t data_length; /* data length address */ - - uint32_t space4; /* zeros */ - uint32_t space5; /* zeros */ - uint32_t space6; /* zeros */ - uint32_t space7; /* zeros */ - - uint16_t header_id; /* magic 0x4842 */ - uint16_t header_version; /* 0x02 for 2.0 */ - uint16_t space8; /* zeros */ - uint8_t section_id; /* section id */ - uint8_t image_info_type; /* (?) 0x04 in factory images */ - uint32_t image_info_offset; /* (?) zeros in factory images */ - uint16_t family_member; /* unique per router type */ - uint16_t header_checksum; /* negated jboot_checksum of header data */ -}; - -struct stag_header { /* used only of sch2 wrapped kernel data */ - uint8_t cmark; /* in factory 0xFF ,in sysuograde must be the same as id */ - uint8_t id; /* 0x04 */ - uint16_t magic; /* magic 0x2B24 */ - uint32_t time_stamp; /* timestamp calculated in jboot way */ - uint32_t image_length; /* lentgh of kernel + sch2 header */ - uint16_t image_checksum; /* negated jboot_checksum of sch2 + kernel */ - uint16_t tag_checksum; /* negated jboot_checksum of stag header data */ -}; - -struct sch2_header { /* used only in kernel partitions */ - uint16_t magic; /* magic 0x2124 */ - uint8_t cp_type; /* 0x00 for flat, 0x01 for jz, 0x02 for gzip, 0x03 for lzma */ - uint8_t version; /* 0x02 for sch2 */ - uint32_t ram_addr; /* ram entry address */ - uint32_t image_len; /* kernel image length */ - uint32_t image_crc32; /* kernel image crc */ - uint32_t start_addr; /* ram start address */ - uint32_t rootfs_addr; /* rootfs flash address */ - uint32_t rootfs_len; /* rootfls length */ - uint32_t rootfs_crc32; /* rootfs crc32 */ - uint32_t header_crc32; /* sch2 header crc32, durring calculation this area is replaced by zero */ - uint16_t header_length; /* sch2 header length: 0x28 */ - uint16_t cmd_line_length; /* cmd line length, known zeros */ -}; - -/* globals */ -static struct file_info inspect_info; -struct file_info kernel_info; -struct file_info rootfs_info; -struct file_info image_info; - -char *ofname; -char *progname; -uint32_t firmware_size; -uint32_t image_offset; -uint16_t family_member; -char *rom_id[12] = { 0 }; -char image_type; - -static void usage(int status) -{ - fprintf(stderr, "Usage: %s [OPTIONS...]\n", progname); - fprintf(stderr, - "\n" - "Options:\n" - " -i <file> inspect given firmware file <file>\n" - " -f set family member id (hexval prefixed with 0x)\n" - " -F <file> read image and convert it to FACTORY\n" - " -k <file> read kernel image from the file <file>\n" - " -r <file> read rootfs image from the file <file>\n" - " -o <file> write output to the file <file>\n" - " -s <size> set firmware partition size\n" - " -m <version> set rom id to <version> (12-bit string val: \"DLK*********\")\n" - " -h show this screen\n"); - - exit(status); -} - -void print_auh_header(struct auh_header *printed_header) -{ - printf("\trom_id: %s\n" - "\tderange: 0x%04X\n" - "\timage_checksum: 0x%04X\n" - "\tspace1: 0x%08X\n" - "\tspace2: 0x%08X\n" - "\tspace3: 0x%04X\n" - "\tlpvs: 0x%02X\n" - "\tmbz: 0x%02X\n" - "\ttime_stamp: 0x%08X\n" - "\terase_start: 0x%08X\n" - "\terase_length: 0x%08X\n" - "\tdata_offset: 0x%08X\n" - "\tdata_length: 0x%08X\n" - "\tspace4: 0x%08X\n" - "\tspace5: 0x%08X\n" - "\tspace6: 0x%08X\n" - "\tspace7: 0x%08X\n" - "\theader_id: 0x%04X\n" - "\theader_version: 0x%02X\n" - "\tspace8: 0x%04X\n" - "\tsection_id: 0x%02X\n" - "\timage_info_type: 0x%02X\n" - "\timage_info_offset 0x%08X\n" - "\tfamily_member: 0x%04X\n" - "\theader_checksum: 0x%04X\n", - printed_header->rom_id, - printed_header->derange, - printed_header->image_checksum, - printed_header->space1, - printed_header->space2, - printed_header->space3, - printed_header->lpvs, - printed_header->mbz, - printed_header->time_stamp, - printed_header->erase_start, - printed_header->erase_length, - printed_header->data_offset, - printed_header->data_length, - printed_header->space4, - printed_header->space5, - printed_header->space6, - printed_header->space7, - printed_header->header_id, - printed_header->header_version, - printed_header->space8, - printed_header->section_id, - printed_header->image_info_type, - printed_header->image_info_offset, - printed_header->family_member, printed_header->header_checksum); -} - -void print_stag_header(struct stag_header *printed_header) -{ - printf("\tcmark: 0x%02X\n" - "\tid: 0x%02X\n" - "\tmagic: 0x%04X\n" - "\ttime_stamp: 0x%08X\n" - "\timage_length: 0x%04X\n" - "\timage_checksum: 0x%04X\n" - "\ttag_checksum: 0x%04X\n", - printed_header->cmark, - printed_header->id, - printed_header->magic, - printed_header->time_stamp, - printed_header->image_length, - printed_header->image_checksum, printed_header->tag_checksum); -} - -void print_sch2_header(struct sch2_header *printed_header) -{ - printf("\tmagic: 0x%04X\n" - "\tcp_type: 0x%02X\n" - "\tversion: 0x%02X\n" - "\tram_addr: 0x%08X\n" - "\timage_len: 0x%08X\n" - "\timage_crc32: 0x%08X\n" - "\tstart_addr: 0x%08X\n" - "\trootfs_addr: 0x%08X\n" - "\trootfs_len: 0x%08X\n" - "\trootfs_crc32: 0x%08X\n" - "\theader_crc32: 0x%08X\n" - "\theader_length: 0x%04X\n" - "\tcmd_line_length: 0x%04X\n", - printed_header->magic, - printed_header->cp_type, - printed_header->version, - printed_header->ram_addr, - printed_header->image_len, - printed_header->image_crc32, - printed_header->start_addr, - printed_header->rootfs_addr, - printed_header->rootfs_len, - printed_header->rootfs_crc32, - printed_header->header_crc32, - printed_header->header_length, printed_header->cmd_line_length); -} - -static int find_auh_headers(char *buf) -{ - char *tmp_buf = buf; - struct auh_header *tmp_header[MAX_HEADER_COUNTER]; - int header_counter = 0; - - int ret = EXIT_FAILURE; - - while (tmp_buf - buf <= inspect_info.file_size - AUH_SIZE) { - if (!memcmp(tmp_buf, AUH_MAGIC, 3)) { - if (((struct auh_header *)tmp_buf)->header_checksum == - (uint16_t) ~jboot_checksum(0, (uint16_t *) tmp_buf, - AUH_SIZE - 2)) { - uint16_t checksum = 0; - printf("Find proper AUH header at: 0x%lX!\n", - tmp_buf - buf); - tmp_header[header_counter] = - (struct auh_header *)tmp_buf; - checksum = - jboot_checksum(0, (uint16_t *) ((char *) - tmp_header - [header_counter] - + AUH_SIZE), - tmp_header - [header_counter]->data_length); - if (tmp_header[header_counter]->image_checksum - == checksum) - printf("Image checksum ok.\n"); - else - ERR("Image checksum incorrect! Stored: 0x%X Calculated: 0x%X\n", tmp_header[header_counter]->image_checksum, checksum); - header_counter++; - if (header_counter > MAX_HEADER_COUNTER) - break; - } - } - tmp_buf++; - } - - if (header_counter == 0) - ERR("Can't find proper AUH header!\n"); - else if (header_counter > MAX_HEADER_COUNTER) - ERR("To many AUH headers!\n"); - else { - for (int i = 0; i < header_counter; i++) { - printf("AUH %d:\n", i); - print_auh_header(tmp_header[i]); - } - - ret = EXIT_SUCCESS; - } - - return ret; -} - -static int check_stag_header(char *buf, struct stag_header *header) -{ - - int ret = EXIT_FAILURE; - - uint8_t cmark_tmp = header->cmark; - header->cmark = header->id; - - if (header->tag_checksum == - (uint16_t) ~jboot_checksum(0, (uint16_t *) header, - STAG_SIZE - 2)) { - uint16_t checksum = 0; - printf("Find proper STAG header at: 0x%lX!\n", - (char *)header - buf); - checksum = - jboot_checksum(0, (uint16_t *) ((char *)header + STAG_SIZE), - header->image_length); - if (header->image_checksum == checksum) { - printf("Image checksum ok.\n"); - header->cmark = cmark_tmp; - print_stag_header(header); - ret = EXIT_SUCCESS; - } else - ERR("Image checksum incorrect! Stored: 0x%X Calculated: 0x%X\n", header->image_checksum, checksum); - } else - ERR("STAG header checksum incorrect!"); - - header->cmark = cmark_tmp; - return ret; -} - -static int check_sch2_header(char *buf, struct sch2_header *header) -{ - - int ret = EXIT_FAILURE; - - uint32_t crc32_tmp = header->header_crc32; - header->header_crc32 = 0; - - if (crc32_tmp == crc32(0, (uint8_t *) header, header->header_length)) { - uint32_t crc32_val; - printf("Find proper SCH2 header at: 0x%lX!\n", - (char *)header - buf); - - crc32_val = - crc32(0, (uint8_t *) header + header->header_length, - header->image_len); - if (header->image_crc32 == crc32_val) { - printf("Kernel checksum ok.\n"); - - header->header_crc32 = crc32_tmp; - print_sch2_header(header); - ret = EXIT_SUCCESS; - } else - ERR("Kernel checksum incorrect! Stored: 0x%X Calculated: 0x%X\n", header->image_crc32, crc32_val); - - } else - ERR("SCH2 header checksum incorrect!"); - - header->header_crc32 = crc32_tmp; - return ret; -} - -static int inspect_fw(void) -{ - char *buf; - struct stag_header *stag_header_kernel; - struct sch2_header *sch2_header_kernel; - int ret = EXIT_FAILURE; - - buf = malloc(inspect_info.file_size); - if (!buf) { - ERR("no memory for buffer!\n"); - goto out; - } - - ret = read_to_buf(&inspect_info, buf); - if (ret) - goto out_free_buf; - - ret = find_auh_headers(buf); - if (ret) - goto out_free_buf; - - stag_header_kernel = (struct stag_header *)(buf + AUH_SIZE); - - ret = check_stag_header(buf, stag_header_kernel); - if (ret) - goto out_free_buf; - - sch2_header_kernel = (struct sch2_header *)(buf + AUH_SIZE + STAG_SIZE); - - ret = check_sch2_header(buf, sch2_header_kernel); - if (ret) - goto out_free_buf; - - out_free_buf: - free(buf); - out: - return ret; -} - -static int check_options(void) -{ - int ret; - - if (inspect_info.file_name) { - ret = get_file_stat(&inspect_info); - if (ret) - return ret; - - return 0; - } - - return 0; -} - -int fill_sch2(struct sch2_header *header, char *kernel_ptr, char *rootfs_ptr) -{ - - header->magic = SCH2_MAGIC; - header->cp_type = LZMA; - header->version = SCH2_VER; - header->ram_addr = RAM_LOAD_ADDR; - header->image_len = kernel_info.file_size; - header->image_crc32 = crc32(0, (uint8_t *) kernel_ptr, kernel_info.file_size); - header->start_addr = RAM_ENTRY_ADDR; - header->rootfs_addr = - image_offset + STAG_SIZE + SCH2_SIZE + kernel_info.file_size; - header->rootfs_len = rootfs_info.file_size; - header->rootfs_crc32 = crc32(0, (uint8_t *) rootfs_ptr, rootfs_info.file_size); - header->header_crc32 = 0; - header->header_length = SCH2_SIZE; - header->cmd_line_length = 0; - - header->header_crc32 = crc32(0, (uint8_t *) header, header->header_length); - - return EXIT_SUCCESS; -} - -int fill_stag(struct stag_header *header, uint32_t length) -{ - header->cmark = STAG_ID; - header->id = STAG_ID; - header->magic = STAG_MAGIC; - header->time_stamp = jboot_timestamp(); - header->image_length = length + SCH2_SIZE; - header->image_checksum = - jboot_checksum(0, (uint16_t *) ((char *)header + STAG_SIZE), - header->image_length); - header->tag_checksum = - ~jboot_checksum(0, (uint16_t *) header, STAG_SIZE - 2); - - if (image_type == FACTORY) - header->cmark = STAG_CMARK_FACTORY; - - return EXIT_SUCCESS; -}; - -int fill_auh(struct auh_header *header, uint32_t length) -{ - memcpy(header->rom_id, rom_id, 12); - header->derange = 0; - header->image_checksum = - jboot_checksum(0, (uint16_t *) ((char *)header + AUH_SIZE), length); - header->space1 = 0; - header->space2 = 0; - header->space3 = 0; - header->lpvs = AUH_LVPS; - header->mbz = 0; - header->time_stamp = jboot_timestamp(); - header->erase_start = image_offset; - header->erase_length = firmware_size; - header->data_offset = image_offset; - header->data_length = length; - header->space4 = 0; - header->space5 = 0; - header->space6 = 0; - header->space7 = 0; - header->header_id = AUH_HDR_ID; - header->header_version = AUH_HDR_VER; - header->space8 = 0; - header->section_id = AUH_SEC_ID; - header->image_info_type = AUH_INFO_TYPE; - header->image_info_offset = 0; - header->family_member = family_member; - header->header_checksum = - ~jboot_checksum(0, (uint16_t *) header, AUH_SIZE - 2); - - return EXIT_SUCCESS; -} - -int build_fw(void) -{ - char *buf; - char *kernel_ptr; - char *rootfs_ptr; - int ret = EXIT_FAILURE; - int writelen; - - struct stag_header *stag_header_kernel; - struct sch2_header *sch2_header_kernel; - - if (!kernel_info.file_name | !rootfs_info.file_name) - goto out; - - ret = get_file_stat(&kernel_info); - if (ret) - goto out; - ret = get_file_stat(&rootfs_info); - if (ret) - goto out; - - buf = malloc(firmware_size); - if (!buf) { - ERR("no memory for buffer\n"); - goto out; - } - - if (rootfs_info.file_size + kernel_info.file_size + ALL_HEADERS_SIZE > - firmware_size) { - ERR("data is bigger than firmware_size!\n"); - goto out; - } - - memset(buf, 0xff, firmware_size); - - stag_header_kernel = (struct stag_header *)buf; - - sch2_header_kernel = - (struct sch2_header *)((char *)stag_header_kernel + STAG_SIZE); - kernel_ptr = (char *)sch2_header_kernel + SCH2_SIZE; - - ret = read_to_buf(&kernel_info, kernel_ptr); - if (ret) - goto out_free_buf; - - rootfs_ptr = kernel_ptr + kernel_info.file_size; - - ret = read_to_buf(&rootfs_info, rootfs_ptr); - if (ret) - goto out_free_buf; - - writelen = rootfs_ptr + rootfs_info.file_size - buf; - - fill_sch2(sch2_header_kernel, kernel_ptr, rootfs_ptr); - fill_stag(stag_header_kernel, kernel_info.file_size); - - ret = write_fw(ofname, buf, writelen); - if (ret) - goto out_free_buf; - - ret = EXIT_SUCCESS; - - out_free_buf: - free(buf); - out: - return ret; -} - -int wrap_fw(void) -{ - char *buf; - char *image_ptr; - int ret = EXIT_FAILURE; - int writelen; - - struct auh_header *auh_header_kernel; - - if (!image_info.file_name) - goto out; - - ret = get_file_stat(&image_info); - if (ret) - goto out; - - buf = malloc(firmware_size); - if (!buf) { - ERR("no memory for buffer\n"); - goto out; - } - - if (image_info.file_size + AUH_SIZE > - firmware_size) { - ERR("data is bigger than firmware_size!\n"); - goto out; - } - if (!family_member) { - ERR("No family_member!\n"); - goto out; - } - if (!(rom_id[0])) { - ERR("No rom_id!\n"); - goto out; - } - memset(buf, 0xff, firmware_size); - - image_ptr = (char *)(buf + AUH_SIZE); - - ret = read_to_buf(&image_info, image_ptr); - if (ret) - goto out_free_buf; - - writelen = image_ptr + image_info.file_size - buf; - - auh_header_kernel = (struct auh_header *)buf; - fill_auh(auh_header_kernel, writelen - AUH_SIZE); - - ret = write_fw(ofname, buf, writelen); - if (ret) - goto out_free_buf; - - ret = EXIT_SUCCESS; - - out_free_buf: - free(buf); - out: - return ret; -} - -int main(int argc, char *argv[]) -{ - int ret = EXIT_FAILURE; - - progname = basename(argv[0]); - image_type = SYSUPGRADE; - family_member = 0; - firmware_size = 0; - image_offset = JBOOT_SIZE; - - while (1) { - int c; - - c = getopt(argc, argv, "f:F:i:hk:m:o:O:r:s:"); - if (c == -1) - break; - - switch (c) { - case 'f': - sscanf(optarg, "0x%hx", &family_member); - break; - case 'F': - image_info.file_name = optarg; - image_type = FACTORY; - break; - case 'i': - inspect_info.file_name = optarg; - break; - case 'k': - kernel_info.file_name = optarg; - break; - case 'm': - if (strlen(optarg) == 12) - memcpy(rom_id, optarg, 12); - break; - case 'r': - rootfs_info.file_name = optarg; - break; - case 'O': - sscanf(optarg, "0x%x", &image_offset); - break; - case 'o': - ofname = optarg; - break; - case 's': - sscanf(optarg, "0x%x", &firmware_size); - break; - default: - usage(EXIT_FAILURE); - break; - } - } - - ret = check_options(); - if (ret) - goto out; - - if (!inspect_info.file_name) { - if (image_type == FACTORY) - ret = wrap_fw(); - else - ret = build_fw(); - } - else - ret = inspect_fw(); - - out: - return ret; - -} |