From f137f2493db5b5ee27ffc784538b766d5192704d Mon Sep 17 00:00:00 2001 From: Keith Short Date: Tue, 7 Jul 2020 16:53:15 -0600 Subject: util: add gen_bmi_config utility Add the gen_bmi_config utility used to generate a compressed version of the configuration file required by the BMI260 IMU sensor. This is expected to be a temporary solution until the 8 KiB BMI configuration file can be moved out of the EC code. BUG=b:160330682 BRANCH=none TEST=make utils TEST=run "gen_bmi_config compress BMI260_main.tbin bmi260_compressed.bin" TEST=run "gen_bmi_config decrompress bmi260_compressed.bin bmi260_uncompressed.bin", verify uncompressed file matches original file. Signed-off-by: Keith Short Change-Id: I7ef06414f84169f2e16f26df4f83455c3df37e51 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2289215 Commit-Queue: Abe Levkoy Reviewed-by: Abe Levkoy --- util/build.mk | 2 +- util/gen_bmi_config.c | 307 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 308 insertions(+), 1 deletion(-) create mode 100644 util/gen_bmi_config.c (limited to 'util') diff --git a/util/build.mk b/util/build.mk index f21a71b39f..5ae12bc8c6 100644 --- a/util/build.mk +++ b/util/build.mk @@ -8,7 +8,7 @@ host-util-bin=ectool lbplay stm32mon ec_sb_firmware_update lbcc \ ec_parse_panicinfo cbi-util iteflash -build-util-bin=ec_uartd +build-util-bin=ec_uartd gen_bmi_config build-util-art+=util/export_taskinfo.so ifeq ($(CHIP),npcx) build-util-bin+=ecst diff --git a/util/gen_bmi_config.c b/util/gen_bmi_config.c new file mode 100644 index 0000000000..44456cf1cc --- /dev/null +++ b/util/gen_bmi_config.c @@ -0,0 +1,307 @@ +/* + * Copyright 2020 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* + * TODO(b/160330682): Eliminate or reduce size of BMI260 initialization file. + * + * Once the BMI260 initialization file is moved to the kernel's rootfs, this + * entire file can be deleted. + */ + +/* + * This utility is used to generate a compressed version of the BMI260 + * configuration file. + * + * This uses a very simple, but lightweight compression algorithm to detect + * duplicated 32-bit words in the configuration data. + * + * Compression scheme: + * Repeated 32-bit words are replaced by a 16-bit key, 16-bit count, and + * the 32-bit data word. All values stored big-endian. + * + * For example, if the uncompressed file had the following data words: + * 0x89ABCDEF 0x89ABCDEF 0x89ABCDEF + * + * This is represented compressed as (key 0xE9EA): + * 0xE9EA0003 0x89ABCDEF + * + * Key value (0xE9EA) chosen as it wasn't found in the BMI configuration + * data. + */ +#include +#include +#include +#include +#include "endian.h" + +/* + * This key is chosen because it isn't used by the BMI260 config file. + */ +#define COMPRESS_KEY 0xE9EA + +static int word_compress(uint32_t *buffer, int word_length, + const char *outfilename) +{ + FILE *file_p; + const uint16_t key = COMPRESS_KEY; + uint16_t out16; + uint16_t in16; + unsigned int outsize; + uint32_t prev_word; + int repeat_count; + int i; + + file_p = fopen(outfilename, "wb+"); + if (!file_p) { + fprintf(stderr, "Failed to open output file %s\n", outfilename); + return -1; + } + + prev_word = ~buffer[0]; + repeat_count = 1; + outsize = 0; + + for (i = 0; i < word_length; i++) { + in16 = *(uint16_t *)&buffer[i]; + in16 = be16toh(in16); + + if (in16 == COMPRESS_KEY) { + fprintf(stderr, "ERROR: input data contains " + "compression key value 0x%04x\n", + COMPRESS_KEY); + fprintf(stderr, "Compression of input data not " + "supported.\n"); + outsize = -1; + goto early_exit; + } + + if (buffer[i] == prev_word && (repeat_count < 255)) { + repeat_count++; + } else { + if (repeat_count > 2) { + printf("Offset 0x%08lx: Write repeated " + "signature: 0x%04x 0x%04x 0x%08x\n", + ftell(file_p), key, repeat_count, + prev_word); + out16 = htobe16(key); + fwrite(&out16, sizeof(out16), 1, file_p); + out16 = htobe16(repeat_count); + fwrite(&out16, sizeof(out16), 1, file_p); + outsize += 2 * sizeof(out16); + + /* + * Write out original data as bytes + * to preserve original order. + */ + fwrite(&prev_word, 1, sizeof(prev_word), + file_p); + outsize += sizeof(prev_word); + } else if (i != 0) { + do { + fwrite(&prev_word, 1, sizeof(prev_word), + file_p); + outsize += sizeof(prev_word); + } while (--repeat_count > 0); + } + + prev_word = buffer[i]; + repeat_count = 1; + } + } + + /* Write the last word or repeated words */ + if (repeat_count > 2) { + printf("Offset 0x%08lx: Write repeated signature: " + "0x%04x 0x%04x 0x%08x\n", + ftell(file_p), key, repeat_count, prev_word); + fwrite(&out16, sizeof(out16), 1, file_p); + out16 = htobe16(repeat_count); + fwrite(&out16, sizeof(out16), 1, file_p); + outsize += 2 * sizeof(out16); + + fwrite(&prev_word, 1, sizeof(prev_word), file_p); + outsize += sizeof(prev_word); + } else if (i != 0) { + do { + fwrite(&prev_word, 1, sizeof(prev_word), file_p); + outsize += sizeof(prev_word); + } while (--repeat_count > 0); + } + + if (outsize != ftell(file_p)) { + fprintf(stderr, "Compression failed, write %d bytes, but file " + "size is only %ld bytes\n", + outsize, ftell(file_p)); + outsize = -1; + goto early_exit; + } + +early_exit: + fclose(file_p); + + return outsize; +} + +static int word_decompress(uint32_t *buffer, + int word_length, + const char *outfilename) +{ + FILE *file_p; + uint16_t *buf16; + uint16_t key; + uint16_t repeat_count; + unsigned int outsize; + uint32_t out_word; + int i; + + file_p = fopen(outfilename, "wb+"); + if (!file_p) { + fprintf(stderr, "Failed to open output file %s\n", outfilename); + return -1; + } + + repeat_count = 0; + outsize = 0; + + for (i = 0; i < word_length; i++) { + buf16 = (uint16_t *)&buffer[i]; + key = be16toh(*buf16); + + if (key == COMPRESS_KEY) { + repeat_count = be16toh(*++buf16); + + if (repeat_count == 0) { + fprintf(stderr, "Incorrect repeat count found " + "in compressed file\n"); + outsize = -1; + goto early_exit; + } + + /* + * Note - this advances the loop to the next word + * in the buffer. + */ + if (++i >= word_length) { + fprintf(stderr, "Unexpected file end during " + "decompress\n"); + outsize = -1; + goto early_exit; + } + + out_word = buffer[i]; + while (repeat_count-- > 0) { + fwrite(&out_word, 4, 1, file_p); + outsize += sizeof(out_word); + } + } else { + fwrite(&buffer[i], 4, 1, file_p); + outsize += sizeof(buffer[i]); + } + } + +early_exit: + fclose(file_p); + + return outsize; +} + +static void print_help(char *cmd_name) +{ + printf("\nUsage: %s \n" + "\n" + "Utility to compress/decompress BMI IMU config binaries.\n", + cmd_name); +} + +int main(int argc, char *argv[]) +{ + uint32_t *buffer; + int outsize; + char *infilename; + char *outfilename; + FILE *f; + long size; + size_t read_words; + + if (argc < 4) { + fprintf(stderr, "Unknown option or missing value\n"); + print_help(argv[0]); + return EXIT_FAILURE; + } + + infilename = argv[2]; + outfilename = argv[3]; + + printf("Input (%s), output (%s)\n", infilename, outfilename); + + f = fopen(infilename, "rb"); + + if (!f) { + fprintf(stderr, "Failed to open input file %s\n", infilename); + print_help(argv[0]); + return EXIT_FAILURE; + } + + fseek(f, 0, SEEK_END); + size = ftell(f); + rewind(f); + + printf("Infile (%s) size %ld (bytes)\n", infilename, size); + buffer = malloc(size); + size /= 4; + if (!buffer) { + fprintf(stderr, "Failed to allocate memory. " + "Input file size %ld bytes\n", + size * 4); + fclose(f); + return EXIT_FAILURE; + } + + read_words = fread(buffer, 4, size, f); + if (read_words != size) { + fprintf(stderr, "Unable to read from %s, " + "words read %ld, needed %ld\n", + infilename, read_words, size); + fclose(f); + free(buffer); + return EXIT_FAILURE; + } + + fclose(f); + + printf("Input file closed\n"); + + if (!strncmp(argv[1], "compress", sizeof("compress"))) { + outsize = word_compress(buffer, size, outfilename); + if (outsize < 0) { + free(buffer); + return EXIT_FAILURE; + } + + printf("Compressed file %s created - %d bytes " + "(saves %ld bytes)\n", + outfilename, outsize, (size * 4) - outsize); + } else if (!strncmp(argv[1], "decompress", sizeof("decompress"))) { + outsize = word_decompress(buffer, size, outfilename); + if (outsize < 0) { + free(buffer); + return EXIT_FAILURE; + } + + printf("Decompressed file %s created - %d bytes\n", + outfilename, outsize); + } else { + fprintf(stderr, "Invalid parameter 1, " + "must be compress/decoompress\n"); + print_help(argv[0]); + free(buffer); + return EXIT_FAILURE; + } + + free(buffer); + + return EXIT_SUCCESS; +} -- cgit v1.2.1