From patchwork Mon Nov 29 14:54:55 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: daebo01 X-Patchwork-Id: 1561262 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=pass (2048-bit key; secure) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=bombadil.20210309 header.b=rPnmVLF6; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.openwrt.org (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; envelope-from=openwrt-devel-bounces+incoming=patchwork.ozlabs.org@lists.openwrt.org; receiver=) Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4J2pNQ0ZTRz9sCD for ; Tue, 30 Nov 2021 01:57:09 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:Message-Id:Date:Subject:Cc :To:From:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References: List-Owner; bh=u4KdQmpMvhoxPneY+8DTFq35v1bnc5Gz0vUooq9NROg=; b=rPnmVLF6DjF784 iRsK5zQFVILa6a1pBX6JR7zZQ9rm5r7PCPlOiiK1vNxO3hEnezYGEPmGAFUpazsZ5F2IBZwaJX3Qf bp8LG9FG4Kh2tTyZPWYv39rJApEMHzkF6T1BCvX7BI6vOoseb2y7o/Nm4qjRj5hxgC5CXe+ZH9suH roTUFRCgl4IK9WF8wyAIA64oJVDAdUHNLVLHN0VLMTQdyiB7b0eoCebHJZDtMolFcWXP8TaOkwLGM rhIqOj79xWXCvVv8fXr9yfMbEjxGHpvb0MzTbi7ssywylX3HiAFcg30wXvhWaKL0d2nRJb7pNx+kV xGNn83uLLY+4hOxSnCUA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1mri3m-001BuK-Lt; Mon, 29 Nov 2021 14:55:14 +0000 Received: from mail-pf1-f181.google.com ([209.85.210.181]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1mri3i-001Bsx-AE for openwrt-devel@lists.openwrt.org; Mon, 29 Nov 2021 14:55:12 +0000 Received: by mail-pf1-f181.google.com with SMTP id g18so17134270pfk.5 for ; Mon, 29 Nov 2021 06:55:09 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=mnR/+ZE+Xal0vRAarRl4Nwbk0WnYr3seVmpGhzAh7xg=; b=lJFvF32HqfsgEJxVjSZ0y7cwqDi33QEWJ2iO+z6VdclOuzgELO15NyGqATR3NRUueW TQGDtHibuhdEGy0CaB2K2jAgnBNTWmRpL1eaAK1oiPZCHpG4HIRZ/+o4dQ5/XVexJBWr Us/4L7miQkZGlnNYgbqffiFQxOzZHw/5iqhjYIzbmgwWsi9MARWt0pbbtRyXZrksA/7p byX9QS+RI9z1Hg2z3OhwbqKdy6z4pneJcG9H3Wh1rZZcScb81g8iGjc0tMaFd07lqEeb kksx2jynMiIVjIqNzpgPbt942dTu3qOd97wah+dH/JFbQTDg3HDZD0qpeG9zTY36W6P+ wWwg== X-Gm-Message-State: AOAM532a/IoRw7gbm6b7GJ7mD7D4ynLWSiqiOAdc8Qlmysa+Voi1K99G 67IupAKV7Pcx9IzE1jlqorFUxo6wewHqBqL/ X-Google-Smtp-Source: ABdhPJzKPF9JrS/UIWz/8QqA8m3xdPVuu9EBqlQNx6woTp6LkrtoFQ2rgKG2XTklbB7z+tswqgr4rQ== X-Received: by 2002:a05:6a00:1584:b0:49f:e5dd:f904 with SMTP id u4-20020a056a00158400b0049fe5ddf904mr40415605pfk.55.1638197708817; Mon, 29 Nov 2021 06:55:08 -0800 (PST) Received: from localhost.localdomain ([219.255.6.194]) by smtp.googlemail.com with ESMTPSA id b4sm18125319pfl.60.2021.11.29.06.55.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 29 Nov 2021 06:55:08 -0800 (PST) From: daebo01@playmp3.kr To: openwrt-devel@lists.openwrt.org Cc: Alisha Kim Subject: [firmware-utils v2] asus_qca_fix_checksum: new tool for ASUS QCA/QCN uImage Date: Mon, 29 Nov 2021 09:54:55 -0500 Message-Id: <20211129145455.1454-1-daebo01@playmp3.kr> X-Mailer: git-send-email 2.20.1 MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20211129_065510_381197_775AD2BE X-CRM114-Status: GOOD ( 17.55 ) X-Spam-Score: 0.0 (/) X-Spam-Report: Spam detection software, running on the system "bombadil.infradead.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: From: Alisha Kim Fix checksum of Asus QCA/QCN devices. Tested on ac59u v1 Signed-off-by: Alisha Kim --- CMakeLists.txt | 1 + src/asus_qca_fix_checksum.c | 205 ++++++++++++++++++++++++++++++++++++ 2 files changed, 206 insertions(+) create mode 100644 src [...] Content analysis details: (0.0 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [209.85.210.181 listed in list.dnswl.org] 0.0 RCVD_IN_MSPIKE_H3 RBL: Good reputation (+3) [209.85.210.181 listed in wl.mailspike.net] -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.0 RCVD_IN_MSPIKE_WL Mailspike good senders X-BeenThere: openwrt-devel@lists.openwrt.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: OpenWrt Development List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "openwrt-devel" Errors-To: openwrt-devel-bounces+incoming=patchwork.ozlabs.org@lists.openwrt.org From: Alisha Kim Fix checksum of Asus QCA/QCN devices. Tested on ac59u v1 Signed-off-by: Alisha Kim --- 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..511f101 --- /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 Alisha Kim + * + * Based on: + * uimage_padhdr.c : add zero paddings after the tail of uimage header + * Copyright (C) 2019 NOGUCHI Hiroshi + * + */ + +#include +#include +#include +#include +#include +#include +#include + +/* 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 -o \n", prog); + fprintf(stderr, " -v "); +} + +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; +}