summaryrefslogtreecommitdiff
path: root/util
diff options
context:
space:
mode:
authorKeith Short <keithshort@chromium.org>2020-07-07 16:53:15 -0600
committerCommit Bot <commit-bot@chromium.org>2020-07-10 01:29:47 +0000
commitf137f2493db5b5ee27ffc784538b766d5192704d (patch)
treeaddc8e85b248c66d650883142aa46a56b4e2e245 /util
parentbf7c46cfad31de55f62133c1e19c4d9e5e92d799 (diff)
downloadchrome-ec-f137f2493db5b5ee27ffc784538b766d5192704d.tar.gz
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 <keithshort@chromium.org> Change-Id: I7ef06414f84169f2e16f26df4f83455c3df37e51 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2289215 Commit-Queue: Abe Levkoy <alevkoy@chromium.org> Reviewed-by: Abe Levkoy <alevkoy@chromium.org>
Diffstat (limited to 'util')
-rw-r--r--util/build.mk2
-rw-r--r--util/gen_bmi_config.c307
2 files changed, 308 insertions, 1 deletions
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 <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#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 <compress|decompress> <infile> <outfile>\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;
+}