[firmware-utils] asus_qca_fix_checksum: new tool for ASUS QCA/QCN uImage
Enrico Mioso
mrkiko.rs at gmail.com
Mon Nov 29 05:00:46 PST 2021
Sorry, the real name is required to be specified in the commit.
Enrico
On Mon, 29 Nov 2021, webmaster at playmp3.kr wrote:
> Date: Mon, 29 Nov 2021 11:56:09
> From: webmaster at playmp3.kr
> To: openwrt-devel at lists.openwrt.org
> Cc: daebo01 <daebo01 at playmp3.kr>
> Subject: [firmware-utils] asus_qca_fix_checksum: new tool for ASUS QCA/QCN
> uImage
>
> From: daebo01 <daebo01 at playmp3.kr>
>
> Fix checksum of Asus QCA/QCN devices.
> Tested on ac59u v1
>
> Signed-off-by: daebo01 <daebo01 at playmp3.kr>
> ---
> CMakeLists.txt | 1 +
> src/asus_qca_fix_checksum.c | 205 ++++++++++++++++++++++++++++++++++++
> 2 files changed, 206 insertions(+)
> create mode 100644 src/asus_qca_fix_checksum.c
>
> diff --git a/CMakeLists.txt b/CMakeLists.txt
> index f406520..f551b88 100644
> --- a/CMakeLists.txt
> +++ b/CMakeLists.txt
> @@ -28,6 +28,7 @@ ENDMACRO(FW_UTIL)
>
> FW_UTIL(add_header "" "" "")
> FW_UTIL(addpattern "" "" "")
> +FW_UTIL(asus_qca_fix_checksum "" "" "${ZLIB_LIBRARIES}")
> FW_UTIL(asustrx "" "" "")
> FW_UTIL(bcm4908asus "" "" "")
> FW_UTIL(bcm4908kernel "" "" "")
> diff --git a/src/asus_qca_fix_checksum.c b/src/asus_qca_fix_checksum.c
> new file mode 100644
> index 0000000..8bb4420
> --- /dev/null
> +++ b/src/asus_qca_fix_checksum.c
> @@ -0,0 +1,205 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * asus_qca_fix_checksum.c : checksum fix for ASUS QCA/QCN SoC uImage
> + *
> + * Copyright (C) 2021 daebo01 <daebo01 at playmp3.kr>
> + *
> + * Based on:
> + * uimage_padhdr.c : add zero paddings after the tail of uimage header
> + * Copyright (C) 2019 NOGUCHI Hiroshi <drvlabo at gmail.com>
> + *
> + */
> +
> +#include <stdio.h>
> +#include <errno.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <fcntl.h>
> +#include <arpa/inet.h>
> +#include <zlib.h>
> +
> +/* from asuswrt opensource */
> +#define MAX_STRING 12
> +#define MAX_VER 5
> +
> +typedef struct
> +{
> + uint8_t major;
> + uint8_t minor;
> +} version_t;
> +
> +/*
> + * ASUS QCA/QCN Custom Header
> + */
> +typedef struct
> +{
> + version_t kernel;
> + version_t fs;
> + char productid[MAX_STRING];
> + uint16_t sn;
> + uint16_t en;
> + uint8_t pkey;
> + uint8_t key;
> + version_t hw[MAX_VER];
> +} TAIL;
> +
> +/* from u-boot/include/image.h */
> +#define IH_MAGIC 0x27051956 /* Image Magic Number */
> +#define IH_NMLEN 32 /* Image Name Length */
> +
> +/*
> + * Legacy format image header,
> + * all data in network byte order (aka natural aka bigendian).
> + */
> +typedef struct image_header
> +{
> + uint32_t ih_magic; /* Image Header Magic Number */
> + uint32_t ih_hcrc; /* Image Header CRC Checksum */
> + uint32_t ih_time; /* Image Creation Timestamp */
> + uint32_t ih_size; /* Image Data Size */
> + uint32_t ih_load; /* Data Load Address */
> + uint32_t ih_ep; /* Entry Point Address */
> + uint32_t ih_dcrc; /* Image Data CRC Checksum */
> + uint8_t ih_os; /* Operating System */
> + uint8_t ih_arch; /* CPU architecture */
> + uint8_t ih_type; /* Image Type */
> + uint8_t ih_comp; /* Compression Type */
> + union
> + {
> + uint8_t ih_name[IH_NMLEN]; /* Image Name */
> + TAIL tail; /* Asuswrt Custom Tail */
> + } u;
> +} image_header_t;
> +
> +void fix_checksum(uint8_t *image, off_t image_len, TAIL *tail)
> +{
> + image_header_t *header = (image_header_t *)image;
> +
> + uint32_t checksum_a_offset = 0; // image first byte
> + uint32_t checksum_b_offset = (ntohl(header->ih_size) + sizeof(image_header_t)) >> 1;
> +
> + uint8_t checksum_a = image[checksum_a_offset];
> + uint8_t checksum_b;
> +
> + uint32_t recalc_crc;
> +
> + if (image_len < checksum_b_offset)
> + {
> + fprintf(stderr, "too small uImage size\n");
> + exit(1);
> + }
> +
> + checksum_b = image[checksum_b_offset];
> +
> + tail->key = checksum_a + ~checksum_b;
> +
> + // copy an existing image name
> + memcpy(&tail->productid, &header->u.ih_name, sizeof(tail->productid) - 1);
> +
> + // overwrite asus custom header to image name field
> + header->u.tail = *tail;
> +
> + header->ih_hcrc = 0;
> + recalc_crc = crc32(0, image, sizeof(image_header_t));
> + header->ih_hcrc = htonl(recalc_crc);
> +}
> +
> +void usage(char *prog)
> +{
> + fprintf(stderr, "%s -i <input_uimage_file> -o <output_file>\n", prog);
> + fprintf(stderr, " -v <asuswrt version (ex. 3.0.0.4.382.52482)>");
> +}
> +
> +int main(int argc, char *argv[])
> +{
> + struct stat statbuf;
> + uint8_t *filebuf;
> + int ifd;
> + int ofd;
> + ssize_t rsz;
> + int opt;
> + char *infname = NULL;
> + char *outfname = NULL;
> + char *version = NULL;
> + TAIL tail = {};
> +
> + while ((opt = getopt(argc, argv, "i:o:v:")) != -1)
> + {
> + switch (opt)
> + {
> + case 'i':
> + infname = optarg;
> + break;
> + case 'o':
> + outfname = optarg;
> + break;
> + case 'v':
> + version = optarg;
> + if (6 != sscanf(
> + version, "%hhu.%hhu.%hhu.%hhu.%hu.%hu",
> + &tail.kernel.major, &tail.kernel.minor,
> + &tail.fs.major, &tail.fs.minor,
> + &tail.sn, &tail.en))
> + fprintf(stderr, "Version %s doesn't match suppored 6-digits format\n", version);
> + break;
> + default:
> + break;
> + }
> + }
> +
> + if (!infname || !outfname || !version)
> + {
> + usage(argv[0]);
> + exit(1);
> + }
> +
> + ifd = open(infname, O_RDONLY);
> + if (ifd < 0)
> + {
> + fprintf(stderr,
> + "could not open input file. (errno = %d)\n", errno);
> + exit(1);
> + }
> +
> + ofd = open(outfname, O_WRONLY | O_CREAT, 0644);
> + if (ofd < 0)
> + {
> + fprintf(stderr,
> + "could not open output file. (errno = %d)\n", errno);
> + exit(1);
> + }
> +
> + if (fstat(ifd, &statbuf) < 0)
> + {
> + fprintf(stderr,
> + "could not fstat input file. (errno = %d)\n", errno);
> + exit(1);
> + }
> +
> + filebuf = malloc(statbuf.st_size);
> + if (!filebuf)
> + {
> + fprintf(stderr, "buffer allocation failed\n");
> + exit(1);
> + }
> +
> + rsz = read(ifd, filebuf, statbuf.st_size);
> + if (rsz != statbuf.st_size)
> + {
> + fprintf(stderr,
> + "could not read input file (errno = %d).\n", errno);
> + exit(1);
> + }
> +
> + fix_checksum(filebuf, statbuf.st_size, &tail);
> +
> + rsz = write(ofd, filebuf, statbuf.st_size);
> + if (rsz != statbuf.st_size)
> + {
> + fprintf(stderr,
> + "could not write output file (errnor = %d).\n", errno);
> + exit(1);
> + }
> +
> + return 0;
> +}
> --
> 2.20.1
>
>
> _______________________________________________
> openwrt-devel mailing list
> openwrt-devel at lists.openwrt.org
> https://lists.openwrt.org/mailman/listinfo/openwrt-devel
>
More information about the openwrt-devel
mailing list