summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--util/build.mk6
-rw-r--r--util/cbi-util.c338
2 files changed, 344 insertions, 0 deletions
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 <errno.h>
+#include <dirent.h>
+#include <getopt.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#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 <cbi_file> [OPTIONS]', required OPTIONS are:\n"
+ " --board_version <uint16> Board version\n"
+ " --oem_id <uint8> OEM ID\n"
+ " --sku_id <uint8> SKU ID\n"
+ " --size <uint16> Size of output file\n"
+ "Optional OPTIONS are:\n"
+ " --erase_byte <uint8> Byte used for empty space\n"
+ " --format_version <uint16> Data format version\n"
+ "\n"
+ "For '--show <cbi_file> [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;
+ }
+}