From c62060d9d987285c541c58e752c51d18bd7162a2 Mon Sep 17 00:00:00 2001 From: Daisuke Nojiri Date: Tue, 3 Oct 2017 18:28:57 -0700 Subject: CBI: Add cbi-util cbi-util is a build command line tool, which creates a blob containing board information. When invoked with '--show' option, it prints the information stored in a blob and validates the data. BUG=b:70294260 BRANCH=none TEST=Run the command as follows: $ cbi-util --create /path/to/cbi.bin \ --board_version 0xabcd --oem_id 2 --sku_id 3 --size 256 $ cbi-util --show /path/to/cbi.bin CBI blob: /path/to/cbi.bin BOARD_VERSION: 0.1 (0xab.cd) OEM_ID: 2 (0x02) SKU_ID: 3 (0x03) Data validated successfully $ cbi-util --create /path/to/cbi.bin \ --board_version 0xabcd --oem_id 2 --sku_id 3 Missing required arguments $ cbi-util --create /path/to/cbi.bin --board_version 0xabcde Invalid --board_version Change-Id: I7e7b439c50943523039c3cafda3bdf7d08962c61 Signed-off-by: Daisuke Nojiri Reviewed-on: https://chromium-review.googlesource.com/860961 Reviewed-by: Randall Spangler --- util/build.mk | 6 + util/cbi-util.c | 338 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 344 insertions(+) create mode 100644 util/cbi-util.c (limited to 'util') diff --git a/util/build.mk b/util/build.mk index e92f76a8e7..eccea4f7c9 100644 --- a/util/build.mk +++ b/util/build.mk @@ -57,6 +57,12 @@ $(out)/util/gen_touchpad_hash: BUILD_CFLAGS += $(OPENSSL_CFLAGS) $(out)/util/gen_touchpad_hash: BUILD_LDFLAGS += $(OPENSSL_LDFLAGS) endif # CONFIG_TOUCHPAD_VIRTUAL_OFF +build-util-bin += cbi-util +$(out)/util/cbi-util: $(out)/util/crc8.o +$(out)/util/cbi-util: BUILD_LDFLAGS=$(out)/util/crc8.o -static +$(out)/util/crc8.o: common/crc8.c + $(call quiet,c_to_vif,BUILDCC) + $(out)/util/export_taskinfo.so: $(out)/util/export_taskinfo_ro.o \ $(out)/util/export_taskinfo_rw.o $(call quiet,link_taskinfo,BUILDLD) diff --git a/util/cbi-util.c b/util/cbi-util.c new file mode 100644 index 0000000000..e5ad554a03 --- /dev/null +++ b/util/cbi-util.c @@ -0,0 +1,338 @@ +/* Copyright 2018 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. + * + * Cros Board Info utility + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cros_board_info.h" +#include "crc8.h" + +#define REQUIRED_MASK_BOARD_VERSION (1 << 0) +#define REQUIRED_MASK_OEM_ID (1 << 1) +#define REQUIRED_MASK_SKU_ID (1 << 2) +#define REQUIRED_MASK_SIZE (1 << 3) +#define REQUIRED_MASK_FILENAME (1 << 4) +#define REQUIRED_MASK_CREATE (REQUIRED_MASK_BOARD_VERSION | \ + REQUIRED_MASK_OEM_ID | \ + REQUIRED_MASK_SKU_ID | \ + REQUIRED_MASK_SIZE | \ + REQUIRED_MASK_FILENAME) +#define REQUIRED_MASK_SHOW (REQUIRED_MASK_FILENAME) + +/* Command line options */ +enum { + /* mode options */ + OPT_MODE_NONE, + OPT_MODE_CREATE, + OPT_MODE_SHOW, + OPT_BOARD_VERSION, + OPT_OEM_ID, + OPT_SKU_ID, + OPT_SIZE, + OPT_ERASE_BYTE, + OPT_SHOW_ALL, + OPT_HELP, +}; + +static const struct option long_opts[] = { + {"create", 1, 0, OPT_MODE_CREATE}, + {"show", 1, 0, OPT_MODE_SHOW}, + {"board_version", 1, 0, OPT_BOARD_VERSION}, + {"oem_id", 1, 0, OPT_OEM_ID}, + {"sku_id", 1, 0, OPT_SKU_ID}, + {"size", 1, 0, OPT_SIZE}, + {"erase_byte", 1, 0, OPT_ERASE_BYTE}, + {"all", 0, 0, OPT_SHOW_ALL}, + {"help", 0, 0, OPT_HELP}, + {NULL, 0, 0, 0} +}; + +static int write_file(const char *filename, const char *buf, int size) +{ + FILE *f; + int i; + + /* Write to file */ + f = fopen(filename, "wb"); + if (!f) { + perror("Error opening output file"); + return -1; + } + i = fwrite(buf, 1, size, f); + fclose(f); + if (i != size) { + perror("Error writing to file"); + return -1; + } + + return 0; +} + +static uint8_t *read_file(const char *filename, uint32_t *size_ptr) +{ + FILE *f; + uint8_t *buf; + long size; + + *size_ptr = 0; + + f = fopen(filename, "rb"); + if (!f) { + fprintf(stderr, "Unable to open file %s\n", filename); + return NULL; + } + + fseek(f, 0, SEEK_END); + size = ftell(f); + rewind(f); + + if (size < 0 || size > UINT32_MAX) { + fclose(f); + return NULL; + } + + buf = malloc(size); + if (!buf) { + fclose(f); + return NULL; + } + + if (1 != fread(buf, size, 1, f)) { + fprintf(stderr, "Unable to read file %s\n", filename); + fclose(f); + free(buf); + return NULL; + } + + fclose(f); + + *size_ptr = size; + return buf; +} + +static int cbi_crc8(const struct board_info *bi) +{ + return crc8((uint8_t *)&bi->head.crc + 1, bi->head.total_size - 4); +} + +/* + * Create a CBI blob + */ +static int do_create(const char *cbi_filename, uint32_t size, uint8_t erase, + struct board_info *bi) +{ + int rv; + uint8_t *buf; + + buf = malloc(size); + if (!buf) { + fprintf(stderr, "Failed to allocate memory\n"); + return -1; + } + memset(buf, erase, size); + + memcpy(bi->head.magic, cbi_magic, sizeof(bi->head.magic)); + bi->head.major_version = CBI_VERSION_MAJOR; + bi->head.minor_version = CBI_VERSION_MINOR; + bi->head.total_size = sizeof(*bi); + bi->head.crc = cbi_crc8(bi); + memcpy(buf, bi, sizeof(*bi)); + + /* Output blob */ + rv = write_file(cbi_filename, buf, size); + if (rv) { + fprintf(stderr, "Unable to write CBI blob\n"); + return rv; + } + + fprintf(stderr, "CBI blob is created successfully\n"); + + return 0; +} + +static int do_show(const char *cbi_filename, int show_all) +{ + uint8_t *buf; + uint32_t size; + struct board_info *bi; + + if (!cbi_filename) { + fprintf(stderr, "Missing arguments\n"); + return -1; + } + + buf = read_file(cbi_filename, &size); + if (!buf) { + fprintf(stderr, "Unable to read CBI blob\n"); + return -1; + } + + bi = (struct board_info *)buf; + printf("CBI blob: %s\n", cbi_filename); + printf(" BOARD_VERSION: %d.%d (0x%02x.%02x)\n", + bi->major_version, bi->minor_version, + bi->major_version, bi->minor_version); + printf(" OEM_ID: %d (0x%02x)\n", bi->oem_id, bi->oem_id); + printf(" SKU_ID: %d (0x%02x)\n", bi->sku_id, bi->sku_id); + + if (memcmp(bi->head.magic, cbi_magic, sizeof(cbi_magic))) { + fprintf(stderr, "Invalid Magic\n"); + return -1; + } + + if (cbi_crc8(bi) != bi->head.crc) { + fprintf(stderr, "Invalid CRC\n"); + return -1; + } + + printf("Data validated successfully\n"); + return 0; +} + +/* Print help and return error */ +static void print_help(int argc, char *argv[]) +{ + printf("\nUsage: cbi %s <--create|--show>\n" + "\n" + "Utility for managing Cros Board Info (CBIs).\n" + "\n" + "For '--create [OPTIONS]', required OPTIONS are:\n" + " --board_version Board version\n" + " --oem_id OEM ID\n" + " --sku_id SKU ID\n" + " --size Size of output file\n" + "Optional OPTIONS are:\n" + " --erase_byte Byte used for empty space\n" + " --format_version Data format version\n" + "\n" + "For '--show [OPTIONS]', OPTIONS are:\n" + " --all Dump all information\n" + " It also validates the contents against the checksum and\n" + " returns non-zero if validation fails.\n" + "\n", + argv[0]); +} + +int main(int argc, char **argv) +{ + int mode = OPT_MODE_NONE; + const char *cbi_filename = NULL; + struct board_info bi; + uint32_t size; + uint8_t erase = 0xff; + int show_all = 0; + int parse_error = 0; + uint32_t required_mask = 0; + uint32_t set_mask = 0; + uint64_t val; + char *e; + int i; + + memset(&bi, 0, sizeof(bi)); + + while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) { + switch (i) { + case '?': + /* Unhandled option */ + fprintf(stderr, "Unknown option or missing value\n"); + parse_error = 1; + break; + case OPT_HELP: + print_help(argc, argv); + return !!parse_error; + case OPT_MODE_CREATE: + mode = i; + cbi_filename = optarg; + required_mask = REQUIRED_MASK_CREATE; + set_mask |= REQUIRED_MASK_FILENAME; + break; + case OPT_MODE_SHOW: + mode = i; + cbi_filename = optarg; + required_mask = REQUIRED_MASK_SHOW; + set_mask |= REQUIRED_MASK_FILENAME; + break; + case OPT_BOARD_VERSION: + val = strtoul(optarg, &e, 0); + if (val > USHRT_MAX || !*optarg || (e && *e)) { + fprintf(stderr, "Invalid --board_version\n"); + parse_error = 1; + } + bi.version = val; + set_mask |= REQUIRED_MASK_BOARD_VERSION; + break; + case OPT_OEM_ID: + val = strtoul(optarg, &e, 0); + if (val > UCHAR_MAX || !*optarg || (e && *e)) { + fprintf(stderr, "Invalid --oem_id\n"); + parse_error = 1; + } + bi.oem_id = val; + set_mask |= REQUIRED_MASK_OEM_ID; + break; + case OPT_SKU_ID: + val = strtoul(optarg, &e, 0); + if (val > UCHAR_MAX || !*optarg || (e && *e)) { + fprintf(stderr, "Invalid --sku_id\n"); + parse_error = 1; + } + bi.sku_id = val; + set_mask |= REQUIRED_MASK_SKU_ID; + break; + case OPT_SIZE: + val = strtoul(optarg, &e, 0); + if (val > USHRT_MAX || !*optarg || (e && *e)) { + fprintf(stderr, "Invalid --size\n"); + parse_error = 1; + } + size = val; + set_mask |= REQUIRED_MASK_SIZE; + break; + case OPT_ERASE_BYTE: + erase = strtoul(optarg, &e, 0); + if (!*optarg || (e && *e)) { + fprintf(stderr, "Invalid --erase_byte\n"); + parse_error = 1; + } + break; + case OPT_SHOW_ALL: + show_all = 1; + break; + } + } + + if (parse_error) { + print_help(argc, argv); + return 1; + } + + if (set_mask != required_mask) { + fprintf(stderr, "Missing required arguments\n"); + print_help(argc, argv); + return 1; + } + + switch (mode) { + case OPT_MODE_CREATE: + return do_create(cbi_filename, size, erase, &bi); + case OPT_MODE_SHOW: + return do_show(cbi_filename, show_all); + case OPT_MODE_NONE: + default: + fprintf(stderr, "Must specify a mode.\n"); + print_help(argc, argv); + return 1; + } +} -- cgit v1.2.1