// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2020 Andreas Boehler * * This tool was based on: * firmware-crc.pl by Atheros Communications * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * */ #include #include #include #include #include /* for getopt() */ #include char *infile; char *outfile; char *progname; enum { MODEL_3390, MODEL_X490 } model; #define CHUNK_SIZE 256 uint32_t crc32_for_byte(uint32_t r) { for (int j = 0; j < 8; ++j) r = (r & 1 ? 0 : (uint32_t)0xEDB88320L) ^ r >> 1; return r ^ (uint32_t)0xFF000000L; } void crc32(const void *data, size_t n_bytes, uint32_t *crc) { static uint32_t table[0x100]; if (!*table) for (size_t i = 0; i < 0x100; ++i) table[i] = crc32_for_byte(i); for (size_t i = 0; i < n_bytes; ++i) *crc = table[(uint8_t)*crc ^ ((uint8_t *)data)[i]] ^ *crc >> 8; } static void usage(int status) { fprintf(stderr, "Usage: %s [OPTIONS...]\n", progname); fprintf(stderr, "\n" "Options:\n" " -i input file name\n" " -o output file name\n" " -m model (3390, x490 for 3490/5490/7490)\n" " -h show this screen\n" ); exit(status); } int main(int argc, char *argv[]) { uint32_t crc = 0; FILE *in_fp; FILE *out_fp; uint32_t buf[CHUNK_SIZE]; size_t read; progname = argv[0]; while (1) { int c; c = getopt(argc, argv, "i:o:m:h"); if (c == -1) break; switch (c) { case 'i': infile = optarg; break; case 'o': outfile = optarg; break; case 'm': if (strcmp(optarg, "3390") == 0) model = MODEL_3390; else if (strcmp(optarg, "x490") == 0) model = MODEL_X490; else usage(EXIT_FAILURE); break; case 'h': usage(EXIT_SUCCESS); default: usage(EXIT_FAILURE); break; } } if (!infile || !outfile) usage(EXIT_FAILURE); in_fp = fopen(infile, "r"); if (!in_fp) { fprintf(stderr, "Error opening input file: %s\n", infile); return EXIT_FAILURE; } out_fp = fopen(outfile, "w"); if (!out_fp) { fprintf(stderr, "Error opening output file: %s\n", outfile); fclose(in_fp); return EXIT_FAILURE; } while (!feof(in_fp)) { switch (model) { case MODEL_3390: read = fread(buf, sizeof(uint32_t), CHUNK_SIZE, in_fp); if (ferror(in_fp)) { fprintf(stderr, "Error reading input file: %s\n", infile); fclose(in_fp); fclose(out_fp); return EXIT_FAILURE; } for (int i = 0; i < read; i++) crc = crc ^ buf[i]; fwrite(buf, sizeof(uint32_t), read, out_fp); if (ferror(out_fp)) { fprintf(stderr, "Error writing output file: %s\n", outfile); fclose(in_fp); fclose(out_fp); return EXIT_FAILURE; } break; case MODEL_X490: read = fread(buf, 1, sizeof(uint32_t) * CHUNK_SIZE, in_fp); if (ferror(in_fp)) { fprintf(stderr, "Error reading input file: %s\n", infile); fclose(in_fp); fclose(out_fp); return EXIT_FAILURE; } crc32(buf, read, &crc); fwrite(buf, 1, read, out_fp); if (ferror(out_fp)) { fprintf(stderr, "Error writing output file: %s\n", outfile); fclose(in_fp); fclose(out_fp); return EXIT_FAILURE; } break; } } if (model == MODEL_X490) crc = bswap_32(crc); fwrite(&crc, sizeof(uint32_t), 1, out_fp); if (ferror(out_fp)) { fprintf(stderr, "Error writing checksum to output file: %s\n", outfile); fclose(in_fp); fclose(out_fp); return EXIT_FAILURE; } fclose(in_fp); fclose(out_fp); printf("Done.\n"); return EXIT_SUCCESS; }