diff --git a/tools/Makefile b/tools/Makefile index da16ddea1f..32a07080db 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -26,6 +26,7 @@ tools-y += e2fsprogs fakeroot findutils firmware-utils flex gengetopt tools-y += libressl libtool lzma m4 make-ext4fs missing-macros mkimage tools-y += mklibs mm-macros mtd-utils mtools ninja padjffs2 patch-image tools-y += patchelf pkgconf quilt squashfskit4 sstrip zip zlib zstd +tools-y += crc32sum tools-$(BUILD_B43_TOOLS) += b43-tools tools-$(BUILD_ISL) += isl tools-$(BUILD_TOOLCHAIN) += expat gmp libelf mpc mpfr diff --git a/tools/crc32sum/Makefile b/tools/crc32sum/Makefile new file mode 100644 index 0000000000..bc13ecf92b --- /dev/null +++ b/tools/crc32sum/Makefile @@ -0,0 +1,23 @@ +# +# Copyright (C) 2021 MediaTek Inc. All rights reserved. +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# +include $(TOPDIR)/rules.mk + +PKG_NAME:=crc32sum +PKG_VERSION:=1.0 + +include $(INCLUDE_DIR)/host-build.mk + +define Host/Prepare + mkdir -p $(HOST_BUILD_DIR) + $(CP) -a ./src/* $(HOST_BUILD_DIR)/ +endef + +define Host/Install + $(INSTALL_BIN) $(HOST_BUILD_DIR)/crc32sum $(STAGING_DIR_HOST)/bin/ +endef + +$(eval $(call HostBuild)) diff --git a/tools/crc32sum/src/Makefile b/tools/crc32sum/src/Makefile new file mode 100644 index 0000000000..f66cc398b4 --- /dev/null +++ b/tools/crc32sum/src/Makefile @@ -0,0 +1,18 @@ +# +# Copyright (C) 2021 MediaTek Inc. All rights reserved. +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +all: crc32sum + +crc32sum: crc32sum.c + $(CC) $(CFLAGS) -O2 -ggdb -MD -o $@ $< $(LDFLAGS) + +clean: + rm -f crc32sum crc32sum.d + +.PHONY: clean + +-include crc32sum.d \ No newline at end of file diff --git a/tools/crc32sum/src/crc32sum.c b/tools/crc32sum/src/crc32sum.c new file mode 100644 index 0000000000..381c7a95a7 --- /dev/null +++ b/tools/crc32sum/src/crc32sum.c @@ -0,0 +1,282 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 MediaTek Inc. All Rights Reserved. + * + * Author: Weijie Gao + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 +#include +#include +#define SET_BINARY_MODE(_f) _setmode(_fileno(_f, O_BINARY) +#else +#define SET_BINARY_MODE(_f) ((void)0) +#endif + +#define CRC32_LE_POLY_DEFAULT 0xedb88320 +#define CRC32_BE_POLY_DEFAULT 0x04c11db7 +#define CRC32_TABLE_ITEMS 256 + +static uint32_t crc32_le_calc(uint32_t crc, const uint8_t *data, size_t length, + const uint32_t *crc_table) +{ + while (length--) + crc = crc_table[(uint8_t)(crc ^ *data++)] ^ (crc >> 8); + + return crc; +} + +static void crc32_le_init(uint32_t *crc_table, uint32_t poly) +{ + uint32_t i, j, v; + + for (i = 0; i < CRC32_TABLE_ITEMS; i++) { + v = i; + + for (j = 0; j < 8; j++) + v = (v >> 1) ^ ((v & 1) ? poly : 0); + + crc_table[i] = v; + } +} + +static uint32_t crc32_be_calc(uint32_t crc, const uint8_t *data, size_t length, + const uint32_t *crc_table) +{ + while (length--) + crc = crc_table[(uint8_t)((crc >> 24) ^ *data++)] ^ (crc << 8); + + return crc; +} + +static void crc32_be_init(uint32_t *crc_table, uint32_t poly) +{ + uint32_t i, j, v; + + for (i = 0; i < CRC32_TABLE_ITEMS; i++) { + v = i << 24; + + for (j = 0; j < 8; j++) + v = (v << 1) ^ ((v & (1 << 31)) ? poly : 0); + + crc_table[i] = v; + } +} + +struct crc_funcs { + uint32_t poly; + + void (*init)(uint32_t *crc_table, uint32_t poly); + uint32_t (*calc)(uint32_t crc, const uint8_t *data, size_t length, + const uint32_t *crc_table); +}; + +static const struct crc_funcs crc32_le = { + .poly = CRC32_LE_POLY_DEFAULT, + .init = crc32_le_init, + .calc = crc32_le_calc, +}; + +static const struct crc_funcs crc32_be = { + .poly = CRC32_BE_POLY_DEFAULT, + .init = crc32_be_init, + .calc = crc32_be_calc, +}; + +static const struct crc_funcs *crc32_algo = &crc32_le; +static uint32_t crc32_poly; +static uint32_t crc32_val; +static const char *input_file; +static bool output_decimal; +static bool no_comp; + +static void err(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + fprintf(stderr, "Error: "); + vfprintf(stderr, fmt, ap); + va_end(ap); +} + +static void usage(FILE *con, const char *progname, int exitcode) +{ + const char *prog; + size_t len; + + len = strlen(progname); + prog = progname + len - 1; + + while (prog > progname) { + if (*prog == '\\' || *prog == '/') { + prog++; + break; + } + + prog--; + } + + fprintf(con, "CRC32 checksum tool\n"); + fprintf(con, "\n"); + fprintf(con, "Usage: %s [options] \n", prog); + fprintf(con, "\n"); + fprintf(con, "Options:\n"); + fprintf(con, "\t-h display help message\n"); + fprintf(con, "\t-i crc value for incremental calculation\n"); + fprintf(con, "\t (default is 0)\n"); + fprintf(con, "\t-p polynomial for calculation\n"); + fprintf(con, "\t (default is 0x%08x for LE, 0x%08x for BE)\n", + crc32_le.poly, crc32_be.poly); + fprintf(con, "\t-b use big-endian mode\n"); + fprintf(con, "\t-n do not use one's complement\n"); + fprintf(con, "\t-d use decimal output\n"); + fprintf(con, "\n"); + + exit(exitcode); +} + +static int parse_args(int argc, char *argv[]) +{ + int opt; + + static const char *optstring = "i:p:bndh"; + + opterr = 0; + + while ((opt = getopt(argc, argv, optstring)) >= 0) { + switch (opt) { + case 'i': + if (!isxdigit(optarg[0])) { + err("Invalid crc value - %s\n", optarg); + return -EINVAL; + } + + crc32_val = strtoul(optarg, NULL, 0); + break; + + case 'p': + if (!isxdigit(optarg[0])) { + err("Invalid polynomial value - %s\n", optarg); + return -EINVAL; + } + + crc32_poly = strtoul(optarg, NULL, 0); + break; + + case 'b': + crc32_algo = &crc32_be; + break; + + case 'n': + no_comp = true; + break; + + case 'd': + output_decimal = true; + break; + + case 'h': + usage(stdout, argv[0], 0); + break; + + default: + usage(stderr, argv[0], EXIT_FAILURE); + } + } + + if (!crc32_poly) + crc32_poly = crc32_algo->poly; + + if (optind >= argc) + input_file = "-"; + else + input_file = argv[optind]; + + if (!input_file[0]) { + err("Input file must not be empty\n"); + return -EINVAL; + } + + return 0; +} + +static int crc32_calc(void) +{ + uint32_t crc_table[CRC32_TABLE_ITEMS]; + bool using_stdin = false; + uint8_t buf[4096]; + size_t size; + int ret, i; + FILE *f; + + if (!strcmp(input_file, "-")) { + SET_BINARY_MODE(stdin); + using_stdin = true; + f = stdin; + } else { + f = fopen(input_file, "rb"); + } + + if (!f) { + err("Failed to open file '%s'\n", input_file); + return -EINVAL; + } + + crc32_algo->init(crc_table, crc32_poly); + + if (!no_comp) + crc32_val ^= 0xffffffff; + + do { + size = fread(buf, 1, sizeof(buf), f); + + if (size) { + crc32_val = crc32_algo->calc(crc32_val, buf, size, + crc_table); + } + + if (size < sizeof(buf)) { + ret = ferror(f); + + if (!ret && feof(f)) + break; + + err("Error while reading file: %d\n", ret); + break; + } + } while (true); + + if (!using_stdin) + fclose(f); + + if (ret) + return ret; + + if (!no_comp) + crc32_val ^= 0xffffffff; + + if (output_decimal) + printf("%u\n", crc32_val); + else + printf("%08x\n", crc32_val); + + return 0; +} + +int main(int argc, char *argv[]) +{ + if (parse_args(argc, argv)) + return 1; + + return crc32_calc(); +}