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>
This commit is contained in:
Keith Short 2020-07-07 16:53:15 -06:00 committed by Commit Bot
parent bf7c46cfad
commit f137f2493d
4 changed files with 308 additions and 1 deletions

BIN
third_party/bmi260/BMI260_main.tbin vendored Normal file

Binary file not shown.

Binary file not shown.

View File

@ -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

307
util/gen_bmi_config.c Normal file
View File

@ -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;
}