From: Coia Prant Date: Sun, 5 Jan 2025 09:16:54 +0000 (+0800) Subject: build: add mkqdimg X-Git-Url: http://git.openwrt.org/?a=commitdiff_plain;h=3346d7711c9aac561beefa2879db9e0b071ccdca;p=project%2Ffirmware-utils.git build: add mkqdimg The mkqdimg is used for Qding QC202 device. This tool is a reverse engineering of /lib/upgrade/platform.sh and deqdimg programs that come with the original firmware. It has been tested on Qding QC202 U-Boot WebUI. The mkqdimg is also compatible with other qding devices. Signed-off-by: Coia Prant Tested-by: Coia Prant Link: https://github.com/openwrt/firmware-utils/pull/38 [style fixes and init some vars] Signed-off-by: Hauke Mehrtens --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 71c604c..eed563f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,6 +79,7 @@ FW_UTIL(mkmerakifw-old "" "" "") FW_UTIL(mkmylofw "" "" "") FW_UTIL(mkplanexfw src/sha1.c "" "") FW_UTIL(mkporayfw "" "" "") +FW_UTIL(mkqdimg src/sha1.c "" "") FW_UTIL(mkrasimage "" --std=gnu99 "") FW_UTIL(mkrtn56uimg "" "" "${ZLIB_LIBRARIES}") FW_UTIL(mksenaofw src/md5.c --std=gnu99 "") diff --git a/src/mkqdimg.c b/src/mkqdimg.c new file mode 100644 index 0000000..46ecb72 --- /dev/null +++ b/src/mkqdimg.c @@ -0,0 +1,269 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2025 Coia Prant + * + * The golang version can be found at: + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sha1.h" + +#define HDR_PADDING_BYTE 0x00 +#define PADDING_BYTE 0xff + +#define MAX_LENGTH 16647168 +#define BOARD_ID_LENGTH 8 +#define VERSION_LENGTH 8 +#define UBOOT_LENGTH 196608 + +#define HDR_LENGTH 0x00000400 +#define HDR_OFF_BOARD_ID 0 +#define HDR_OFF_VERSION 8 +#define HDR_OFF_UBOOT 16 +#define HDR_OFF_FIRMWARE 32 +#define HDR_OFF_MAGIC 48 +#define HDR_OFF_CHECKSUM 52 +#define HDR_OFF_UBOOT_LEN 72 +#define HDR_OFF_FIRMWARE_LEN 76 +#define HDR_MAGIC 538248722 + +/* + * Globals + */ +static char *progname; + +/* + * Message macros + */ +#define ERR(fmt, ...) do { \ + fflush(0); \ + fprintf(stderr, "[%s] *** error: " fmt "\n", \ + progname, ## __VA_ARGS__); \ +} while (0) + +#define ERRS(fmt, ...) do { \ + int save = errno; \ + fflush(0); \ + fprintf(stderr, "[%s] *** error: " fmt "\n", \ + progname, ## __VA_ARGS__, strerror(save)); \ +} while (0) + +static void usage(int status) +{ + FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout; + + fprintf(stream, "Usage: %s [OPTIONS...]\n", progname); + fprintf(stream, +"\n" +"Options:\n" +" -B create image for the board specified with \n" +" -V version string\n" +" -u read uboot image from the file \n" +" -f read firmware image from the file \n" +" -o write output to the file \n" +" -h show this screen\n" + ); + + exit(status); +} + +void writele(unsigned char *buf, size_t offset, uint32_t value) +{ + value = htole32(value); + memcpy(buf + offset, &value, sizeof(uint32_t)); +} + +int main(int argc, char *argv[]) +{ + int ret = EXIT_FAILURE; + long ulen, flen, buflen = HDR_LENGTH, fspace; + unsigned char *buf; + char *board_id = NULL, *version = NULL, *ufname = NULL, *ffname = NULL, *ofname = NULL; + FILE *out, *uboot = NULL, *firmware = NULL; + + progname = basename(argv[0]); + + while (1) { + int c; + + c = getopt(argc, argv, "B:V:u:f:o:h"); + if (c == -1) + break; + + switch (c) { + case 'B': + board_id = optarg; + break; + case 'V': + version = optarg; + break; + case 'u': + ufname = optarg; + break; + case 'f': + ffname = optarg; + break; + case 'o': + ofname = optarg; + break; + case 'h': + usage(EXIT_SUCCESS); + break; + default: + usage(EXIT_FAILURE); + break; + } + } + + if (board_id == NULL) { + ERR("no board specified"); + goto err; + } + + if (strlen(board_id) > BOARD_ID_LENGTH) { + ERR("board_id \"%s\" is too long - max length: 8\n", + board_id); + goto err; + } + + if (version != NULL && strlen(version) > VERSION_LENGTH) { + ERR("version \"%s\" is too long - max length: 8\n", + version); + goto err; + } + + if (ofname == NULL) { + ERR("no output file specified"); + goto err; + } + + if (ufname != NULL) { + uboot = fopen(ufname, "r"); + if (uboot == NULL) { + ERRS("could not open \"%s\" for reading: %s", ufname); + goto err; + } + + /* Get uboot length */ + fseek(uboot, 0, SEEK_END); + ulen = ftell(uboot); + rewind(uboot); + + if (ulen > UBOOT_LENGTH) { + fclose(uboot); + ERR("file \"%s\" is too big - max size: 0x%08d\n", + ufname, UBOOT_LENGTH); + goto err; + } + + buflen += UBOOT_LENGTH; + } + + if (ffname != NULL) { + firmware = fopen(ffname, "r"); + if (firmware == NULL) { + ERRS("could not open \"%s\" for reading: %s", ffname); + goto err; + } + + /* Get firmware length */ + fseek(firmware, 0, SEEK_END); + flen = ftell(firmware); + rewind(firmware); + + fspace = MAX_LENGTH - buflen; + if (flen > fspace) { + ERR("file \"%s\" is too big - max size: 0x%08ld\n", + ffname, fspace); + goto err_close; + } + + buflen += flen; + } + + /* Allocate and initialize buffer for final image */ + buf = malloc(buflen); + if (buf == NULL) { + ERRS("no memory for buffer: %s\n"); + goto err_close; + } + memset(buf, HDR_PADDING_BYTE, HDR_LENGTH); + memset(buf + HDR_LENGTH, PADDING_BYTE, buflen - HDR_LENGTH); + + /* Write board id */ + memcpy(buf + HDR_OFF_BOARD_ID, board_id, strlen(board_id)); + + /* Write version */ + if (version != NULL) { + memcpy(buf + HDR_OFF_VERSION, version, strlen(version)); + } + + if (uboot != NULL) { + /* Write UBOOT ID */ + memcpy(buf + HDR_OFF_UBOOT, "UBOOT", 5); + + /* Load U-Boot */ + fread(buf + HDR_LENGTH, ulen, 1, uboot); + + /* Write U-Boot Length */ + writele(buf, HDR_OFF_UBOOT_LEN, UBOOT_LENGTH); + } + + if (firmware != NULL) { + /* Write FIRMWARE ID */ + memcpy(buf + HDR_OFF_FIRMWARE, "FIRMWARE", 8); + + /* Load Firmware */ + if (uboot != NULL) { + fread(buf + HDR_LENGTH + UBOOT_LENGTH, flen, 1, firmware); + } else { + fread(buf + HDR_LENGTH, flen, 1, firmware); + } + + /* Write Firmware Length */ + writele(buf, HDR_OFF_FIRMWARE_LEN, flen); + } + + /* Write magic */ + writele(buf, HDR_OFF_MAGIC, HDR_MAGIC); + + /* Write checksum and static hash */ + sha1_csum(buf + HDR_LENGTH, buflen - HDR_LENGTH, buf + HDR_OFF_CHECKSUM); + + /* Save finished image */ + out = fopen(ofname, "w"); + if (out == NULL) { + ERRS("could not open \"%s\" for writing: %s", ofname); + goto err_free; + } + fwrite(buf, buflen, 1, out); + + ret = EXIT_SUCCESS; + + fclose(out); + +err_free: + free(buf); + +err_close: + if (uboot != NULL) { + fclose(uboot); + } + + if (firmware != NULL) { + fclose(firmware); + } + +err: + return ret; +}