summaryrefslogtreecommitdiff
path: root/common/cbi.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/cbi.c')
-rw-r--r--common/cbi.c578
1 files changed, 0 insertions, 578 deletions
diff --git a/common/cbi.c b/common/cbi.c
deleted file mode 100644
index 345e313c54..0000000000
--- a/common/cbi.c
+++ /dev/null
@@ -1,578 +0,0 @@
-/* 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
- */
-
-#include "common.h"
-#include "console.h"
-#include "crc8.h"
-#include "cros_board_info.h"
-#include "gpio.h"
-#include "host_command.h"
-#include "i2c.h"
-#include "timer.h"
-
-#ifdef HOST_TOOLS_BUILD
-#include <string.h>
-#else
-#include "util.h"
-#endif
-
-/*
- * Functions and variables defined here shared with host tools (e.g. cbi-util).
- * TODO: Move these to common/cbi/cbi.c and common/cbi/utils.c if they grow.
- */
-uint8_t cbi_crc8(const struct cbi_header *h)
-{
- return cros_crc8((uint8_t *)&h->crc + 1,
- h->total_size - sizeof(h->magic) - sizeof(h->crc));
-}
-
-uint8_t *cbi_set_data(uint8_t *p, enum cbi_data_tag tag,
- const void *buf, int size)
-{
- struct cbi_data *d = (struct cbi_data *)p;
-
- /*
- * If size of the data to be added is zero, then no need to add the tag
- * as well.
- */
- if (size == 0)
- return p;
-
- d->tag = tag;
- d->size = size;
- memcpy(d->value, buf, size);
- p += sizeof(*d) + size;
- return p;
-}
-
-uint8_t *cbi_set_string(uint8_t *p, enum cbi_data_tag tag, const char *str)
-{
- if (str == NULL)
- return p;
-
- return cbi_set_data(p, tag, str, strlen(str) + 1);
-}
-
-struct cbi_data *cbi_find_tag(const void *buf, enum cbi_data_tag tag)
-{
- struct cbi_data *d;
- const struct cbi_header *h = buf;
- const uint8_t *p;
- for (p = h->data; p + sizeof(*d) < (uint8_t *)buf + h->total_size;) {
- d = (struct cbi_data *)p;
- if (d->tag == tag)
- return d;
- p += sizeof(*d) + d->size;
- }
- return NULL;
-}
-
-/*
- * Functions and variables specific to EC firmware
- */
-#ifndef HOST_TOOLS_BUILD
-
-#define CPRINTS(format, args...) cprints(CC_SYSTEM, "CBI " format, ## args)
-
-static int cache_status = CBI_CACHE_STATUS_INVALID;
-static uint8_t cbi[CBI_IMAGE_SIZE];
-static struct cbi_header * const head = (struct cbi_header *)cbi;
-
-int cbi_create(void)
-{
- memset(cbi, 0, sizeof(cbi));
- memcpy(head->magic, cbi_magic, sizeof(cbi_magic));
- head->total_size = sizeof(*head);
- head->major_version = CBI_VERSION_MAJOR;
- head->minor_version = CBI_VERSION_MINOR;
- head->crc = cbi_crc8(head);
- cache_status = CBI_CACHE_STATUS_SYNCED;
-
- return EC_SUCCESS;
-}
-
-void cbi_invalidate_cache(void)
-{
- cache_status = CBI_CACHE_STATUS_INVALID;
-}
-
-int cbi_get_cache_status(void)
-{
- return cache_status;
-}
-
-static int do_cbi_read(void)
-{
- CPRINTS("Reading board info");
-
- /* Read header */
- if (cbi_config.drv->load(0, cbi, sizeof(*head))) {
- CPRINTS("Failed to read header");
- return EC_ERROR_INVAL;
- }
-
- /* Check magic */
- if (memcmp(head->magic, cbi_magic, sizeof(head->magic))) {
- CPRINTS("Bad magic");
- return EC_ERROR_INVAL;
- }
-
- /* check version */
- if (head->major_version > CBI_VERSION_MAJOR) {
- CPRINTS("Version mismatch");
- return EC_ERROR_INVAL;
- }
-
- /*
- * Check the data size. It's expected to support up to 64k but our
- * buffer has practical limitation.
- */
- if (head->total_size < sizeof(*head) ||
- head->total_size > CBI_IMAGE_SIZE) {
- CPRINTS("Bad size: %d", head->total_size);
- return EC_ERROR_OVERFLOW;
- }
-
- /* Read the data */
- if (cbi_config.drv->load(sizeof(*head), head->data,
- head->total_size - sizeof(*head))) {
- CPRINTS("Failed to read body");
- return EC_ERROR_INVAL;
- }
-
- /* Check CRC. This supports new fields unknown to this parser. */
- if (cbi_config.storage_type != CBI_STORAGE_TYPE_GPIO &&
- cbi_crc8(head) != head->crc) {
- CPRINTS("Bad CRC");
- return EC_ERROR_INVAL;
- }
-
- return EC_SUCCESS;
-}
-
-static int cbi_read(void)
-{
- int i;
- int rv;
-
- if (cbi_get_cache_status() == CBI_CACHE_STATUS_SYNCED)
- return EC_SUCCESS;
-
- for (i = 0; i < 2; i++) {
- rv = do_cbi_read();
- if (rv == EC_SUCCESS) {
- cache_status = CBI_CACHE_STATUS_SYNCED;
- return EC_SUCCESS;
- }
- /* On error (I2C or bad contents), retry a read */
- }
-
- return rv;
-}
-
-__attribute__((weak))
-int cbi_board_override(enum cbi_data_tag tag, uint8_t *buf, uint8_t *size)
-{
- return EC_SUCCESS;
-}
-
-int cbi_get_board_info(enum cbi_data_tag tag, uint8_t *buf, uint8_t *size)
-{
- const struct cbi_data *d;
-
- if (cbi_read())
- return EC_ERROR_UNKNOWN;
-
- d = cbi_find_tag(cbi, tag);
- if (!d)
- /* Not found */
- return EC_ERROR_UNKNOWN;
- if (*size < d->size)
- /* Insufficient buffer size */
- return EC_ERROR_INVAL;
-
- /* Clear the buffer in case len < *size */
- memset(buf, 0, *size);
- /* Copy the value */
- memcpy(buf, d->value, d->size);
- *size = d->size;
-
- return cbi_board_override(tag, buf, size);
-}
-
-static void cbi_remove_tag(void *const cbi, struct cbi_data *const d)
-{
- struct cbi_header *const h = cbi;
- const size_t size = sizeof(*d) + d->size;
- const uint8_t *next = (uint8_t *)d + size;
- const size_t bytes_after = ((uint8_t *)cbi + h->total_size) - next;
-
- memmove(d, next, bytes_after);
- h->total_size -= size;
-}
-
-int cbi_set_board_info(enum cbi_data_tag tag, const uint8_t *buf, uint8_t size)
-{
- struct cbi_data *d;
-
- d = cbi_find_tag(cbi, tag);
-
- /* If we found the entry, but the size doesn't match, delete it */
- if (d && d->size != size) {
- cbi_remove_tag(cbi, d);
- d = NULL;
- }
-
- if (!d) {
- uint8_t *p;
- /* Not found. Check if new item would fit */
- if (sizeof(cbi) < head->total_size + sizeof(*d) + size)
- return EC_ERROR_OVERFLOW;
- /* Append new item */
- p = cbi_set_data(&cbi[head->total_size], tag, buf, size);
- head->total_size = p - cbi;
- } else {
- /* Overwrite existing item */
- memcpy(d->value, buf, d->size);
- }
-
- return EC_SUCCESS;
-}
-
-int cbi_write(void)
-{
- if (cbi_config.drv->is_protected()) {
- CPRINTS("Failed to write due to WP");
- return EC_ERROR_ACCESS_DENIED;
- }
-
- return cbi_config.drv->store(cbi);
-}
-
-int cbi_get_board_version(uint32_t *ver)
-{
- uint8_t size = sizeof(*ver);
-
- return cbi_get_board_info(CBI_TAG_BOARD_VERSION, (uint8_t *)ver, &size);
-}
-
-int cbi_get_sku_id(uint32_t *id)
-{
- uint8_t size = sizeof(*id);
-
- return cbi_get_board_info(CBI_TAG_SKU_ID, (uint8_t *)id, &size);
-}
-
-int cbi_get_oem_id(uint32_t *id)
-{
- uint8_t size = sizeof(*id);
-
- return cbi_get_board_info(CBI_TAG_OEM_ID, (uint8_t *)id, &size);
-}
-
-int cbi_get_model_id(uint32_t *id)
-{
- uint8_t size = sizeof(*id);
-
- return cbi_get_board_info(CBI_TAG_MODEL_ID, (uint8_t *)id, &size);
-}
-
-int cbi_get_fw_config(uint32_t *fw_config)
-{
- uint8_t size = sizeof(*fw_config);
-
- return cbi_get_board_info(CBI_TAG_FW_CONFIG, (uint8_t *)fw_config,
- &size);
-}
-
-int cbi_get_ssfc(uint32_t *ssfc)
-{
- uint8_t size = sizeof(*ssfc);
-
- return cbi_get_board_info(CBI_TAG_SSFC, (uint8_t *)ssfc,
- &size);
-}
-
-int cbi_get_pcb_supplier(uint32_t *pcb_supplier)
-{
- uint8_t size = sizeof(*pcb_supplier);
-
- return cbi_get_board_info(CBI_TAG_PCB_SUPPLIER, (uint8_t *)pcb_supplier,
- &size);
-}
-
-int cbi_get_rework_id(uint64_t *id)
-{
- uint8_t size = sizeof(*id);
- return cbi_get_board_info(CBI_TAG_REWORK_ID, (uint8_t *)id, &size);
-}
-
-static enum ec_status hc_cbi_get(struct host_cmd_handler_args *args)
-{
- const struct __ec_align4 ec_params_get_cbi *p = args->params;
- uint8_t size = MIN(args->response_max, UINT8_MAX);
-
- if (p->flag & CBI_GET_RELOAD)
- cbi_invalidate_cache();
-
- if (cbi_get_board_info(p->tag, args->response, &size))
- return EC_RES_INVALID_PARAM;
-
- args->response_size = size;
- return EC_RES_SUCCESS;
-}
-DECLARE_HOST_COMMAND(EC_CMD_GET_CROS_BOARD_INFO,
- hc_cbi_get,
- EC_VER_MASK(0));
-
-static enum ec_status common_cbi_set(const struct __ec_align4
- ec_params_set_cbi * p)
-{
- /*
- * If we ultimately cannot write to the flash, then fail early unless
- * we are explicitly trying to write to the in-memory CBI only
- */
- if (cbi_config.drv->is_protected() &&
- !(p->flag & CBI_SET_NO_SYNC)) {
- CPRINTS("Failed to write due to WP");
- return EC_RES_ACCESS_DENIED;
- }
-
-#ifndef CONFIG_SYSTEM_UNLOCKED
- /*
- * These fields are not allowed to be reprogrammed regardless the
- * hardware WP state. They're considered as a part of the hardware.
- */
- if (p->tag == CBI_TAG_BOARD_VERSION || p->tag == CBI_TAG_OEM_ID)
- return EC_RES_ACCESS_DENIED;
-#endif
-
- if (p->flag & CBI_SET_INIT) {
- memset(cbi, 0, sizeof(cbi));
- memcpy(head->magic, cbi_magic, sizeof(cbi_magic));
- head->total_size = sizeof(*head);
- } else {
- if (cbi_read())
- return EC_RES_ERROR;
- }
-
- if (cbi_set_board_info(p->tag, p->data, p->size))
- return EC_RES_INVALID_PARAM;
-
- /*
- * Whether we're modifying existing data or creating new one,
- * we take over the format.
- */
- head->major_version = CBI_VERSION_MAJOR;
- head->minor_version = CBI_VERSION_MINOR;
- head->crc = cbi_crc8(head);
- cache_status = CBI_CACHE_STATUS_SYNCED;
-
- /* Skip write if client asks so. */
- if (p->flag & CBI_SET_NO_SYNC)
- return EC_RES_SUCCESS;
-
- /* We already checked write protect failure case. */
- if (cbi_write())
- return EC_RES_ERROR;
-
- return EC_RES_SUCCESS;
-}
-
-static enum ec_status hc_cbi_set(struct host_cmd_handler_args *args)
-{
- const struct __ec_align4 ec_params_set_cbi * p = args->params;
-
- /* Given data size exceeds the packet size. */
- if (args->params_size < sizeof(*p) + p->size)
- return EC_RES_INVALID_PARAM;
-
- return common_cbi_set(p);
-}
-DECLARE_HOST_COMMAND(EC_CMD_SET_CROS_BOARD_INFO,
- hc_cbi_set,
- EC_VER_MASK(0));
-
-#ifdef CONFIG_CMD_CBI
-static void print_tag(const char * const tag, int rv, const uint32_t *val)
-{
- ccprintf("%s", tag);
- if (rv == EC_SUCCESS && val)
- ccprintf(": %u (0x%x)\n", *val, *val);
- else
- ccprintf(": (Error %d)\n", rv);
-}
-
-static void print_uint64_tag(const char * const tag, int rv,
- const uint64_t *lval)
-{
- ccprintf("%s", tag);
- if (rv == EC_SUCCESS && lval)
- ccprintf(": %llu (0x%llx)\n", *(unsigned long long *)lval,
- *(unsigned long long *)lval);
- else
- ccprintf(": (Error %d)\n", rv);
-}
-
-static void dump_cbi(void)
-{
- uint32_t val;
- uint64_t lval;
-
- /* Ensure we read the latest data from flash. */
- cbi_invalidate_cache();
- cbi_read();
-
- if (cbi_get_cache_status() != CBI_CACHE_STATUS_SYNCED) {
- ccprintf("Cannot Read CBI (Error %d)\n", cbi_get_cache_status());
- return;
- }
-
- ccprintf("CBI_VERSION: 0x%04x\n", head->version);
- ccprintf("TOTAL_SIZE: %u\n", head->total_size);
-
- print_tag("BOARD_VERSION", cbi_get_board_version(&val), &val);
- print_tag("OEM_ID", cbi_get_oem_id(&val), &val);
- print_tag("MODEL_ID", cbi_get_model_id(&val), &val);
- print_tag("SKU_ID", cbi_get_sku_id(&val), &val);
- print_tag("FW_CONFIG", cbi_get_fw_config(&val), &val);
- print_tag("PCB_SUPPLIER", cbi_get_pcb_supplier(&val), &val);
- print_tag("SSFC", cbi_get_ssfc(&val), &val);
- print_uint64_tag("REWORK_ID", cbi_get_rework_id(&lval), &lval);
-}
-
-/*
- * Space for the set command (does not include data space) plus maximum
- * possible console input
- */
-static uint8_t buf[sizeof(struct ec_params_set_cbi) + \
- CONFIG_CONSOLE_INPUT_LINE_SIZE];
-
-static int cc_cbi(int argc, char **argv)
-{
- struct __ec_align4 ec_params_set_cbi * setter =
- (struct __ec_align4 ec_params_set_cbi *)buf;
- int last_arg;
- char *e;
-
- if (argc == 1) {
- dump_cbi();
- if (cbi_get_cache_status() == CBI_CACHE_STATUS_SYNCED)
- hexdump(cbi, CBI_IMAGE_SIZE);
- return EC_SUCCESS;
- }
-
- if (strcasecmp(argv[1], "set") == 0) {
- if (argc < 5) {
- ccprintf("Set requires: <tag> <value> <size>\n");
- return EC_ERROR_PARAM_COUNT;
- }
-
- setter->tag = strtoi(argv[2], &e, 0);
- if (*e)
- return EC_ERROR_PARAM2;
-
- if (setter->tag == CBI_TAG_DRAM_PART_NUM ||
- setter->tag == CBI_TAG_OEM_NAME) {
- setter->size = strlen(argv[3]) + 1;
- memcpy(setter->data, argv[3], setter->size);
- } else {
- uint64_t val = strtoull(argv[3], &e, 0);
-
- if (*e)
- return EC_ERROR_PARAM3;
-
- setter->size = strtoi(argv[4], &e, 0);
- if (*e)
- return EC_ERROR_PARAM4;
-
- if (setter->size < 1) {
- ccprintf("Set size too small\n");
- return EC_ERROR_PARAM4;
- } else if (setter->tag == CBI_TAG_REWORK_ID &&
- setter->size > 8) {
- ccprintf("Set size too large\n");
- return EC_ERROR_PARAM4;
- } else if (setter->size > 4) {
- ccprintf("Set size too large\n");
- return EC_ERROR_PARAM4;
- }
-
- memcpy(setter->data, &val, setter->size);
- }
-
- last_arg = 5;
- } else if (strcasecmp(argv[1], "remove") == 0) {
- if (argc < 3) {
- ccprintf("Remove requires: <tag>\n");
- return EC_ERROR_PARAM_COUNT;
- }
-
- setter->tag = strtoi(argv[2], &e, 0);
- if (*e)
- return EC_ERROR_PARAM2;
-
- setter->size = 0;
- last_arg = 3;
- } else {
- return EC_ERROR_PARAM1;
- }
-
- setter->flag = 0;
-
- if (argc > last_arg) {
- int i;
-
- for (i = last_arg; i < argc; i++) {
- if (strcasecmp(argv[i], "init") == 0) {
- setter->flag |= CBI_SET_INIT;
- } else if (strcasecmp(argv[i], "skip_write") == 0) {
- setter->flag |= CBI_SET_NO_SYNC;
- } else {
- ccprintf("Invalid additional option\n");
- return EC_ERROR_PARAM1 + i - 1;
- }
- }
- }
-
- if (common_cbi_set(setter) == EC_RES_SUCCESS)
- return EC_SUCCESS;
-
- return EC_ERROR_UNKNOWN;
-}
-DECLARE_CONSOLE_COMMAND(cbi, cc_cbi, "[set <tag> <value> <size> | "
- "remove <tag>] [init | skip_write]",
- "Print or change Cros Board Info from flash");
-#endif /* CONFIG_CMD_CBI */
-
-#ifndef HAS_TASK_CHIPSET
-int cbi_set_fw_config(uint32_t fw_config)
-{
- /* Check write protect status */
- if (cbi_config.drv->is_protected())
- return EC_ERROR_ACCESS_DENIED;
-
- /* Ensure that CBI has been configured */
- if (cbi_read())
- cbi_create();
-
- /* Update the FW_CONFIG field */
- cbi_set_board_info(CBI_TAG_FW_CONFIG, (uint8_t *)&fw_config,
- sizeof(int));
-
- /* Update CRC calculation and write to the storage */
- head->crc = cbi_crc8(head);
- if (cbi_write())
- return EC_ERROR_UNKNOWN;
-
- dump_cbi();
-
- return EC_SUCCESS;
-}
-#endif
-
-#endif /* !HOST_TOOLS_BUILD */