summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMary Ruthven <mruthven@chromium.org>2023-03-22 14:58:09 -0500
committerChromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com>2023-04-14 21:01:30 +0000
commit37fa38296266e62adfe10226b7b1a22ac9335537 (patch)
treeb27f394e393eae05bf28186ae0f8e0db8b70a50a
parenta5f1053242499cf10d55dfa1124392aa92830426 (diff)
downloadchrome-ec-37fa38296266e62adfe10226b7b1a22ac9335537.tar.gz
cr50: add a factory config space
Add a 64 bit write once factory config space to info1. If the factory has something they want to configure, they can use part of the space to store that configration. Right now nothing in cr50 uses the factory config space. If we need to modify cr50 behavior based on the space value, we can add functionality later. The factory just needs to set the bit in the factory config. BUG=b:214065944 TEST=manual Clear the Board ID set the config to 0. Verify it does nothing gsctool -a --factory_config 0 gsctool -a --factory_config 0 Set the flags gsctool -ai 0xffffffff:0x10 Set the config to something gsctool -a --factory_config 0x12345678cafecafe gsctool -a --factory_config 12345678CAFECAFE # Set it to the same thing. Verify cr50 returns EC_SUCCESS. gsctool -a --factory_config 0x12345678cafecafe gsctool -a --factory_config 12345678CAFECAFE [40.114944 write_factory_config: ok.] Try to set it to something else. Verify it's rejected because the space is set. gsctool -a --factory_config 0xcafe [43.331302 write_factory_config: factory cfg already programmed] gsctool -a --factory_config 12345678CAFECAFE Set the Board ID Type gsctool -ai ZZCR:0x10 Try to set the config again. Verify it's rejected because the board id type is set. gsctool -a --factory_config 0x12345678cafecafe Factory config failed. (7) gsctool -a --factory_config 12345678CAFECAFE Change-Id: Ie816ebffcf6c24ad94bbcd2dc2f0c3936caafb11 Signed-off-by: Mary Ruthven <mruthven@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/4424873 Reviewed-by: Vadim Bendebury <vbendeb@chromium.org>
-rw-r--r--board/cr50/board.c2
-rw-r--r--chip/g/board_space.h9
-rw-r--r--chip/g/build.mk1
-rw-r--r--chip/g/factory_config.c167
-rw-r--r--chip/g/factory_config.h16
-rw-r--r--common/extension.c2
6 files changed, 197 insertions, 0 deletions
diff --git a/board/cr50/board.c b/board/cr50/board.c
index 7fa4ced4c5..dff0b7bfac 100644
--- a/board/cr50/board.c
+++ b/board/cr50/board.c
@@ -14,6 +14,7 @@
#include "ec_version.h"
#include "endian.h"
#include "extension.h"
+#include "factory_config.h"
#include "fips_rand.h"
#include "fips.h"
#include "flash.h"
@@ -1900,6 +1901,7 @@ static int command_board_properties(int argc, char **argv)
*/
ccprintf("properties = 0x%x\n", GREG32(PMU, LONG_LIFE_SCRATCH1));
ccprintf("tpm board cfg = 0x%x\n", board_cfg_reg_read());
+ print_factory_config();
return EC_SUCCESS;
}
DECLARE_SAFE_CONSOLE_COMMAND(brdprop, command_board_properties,
diff --git a/chip/g/board_space.h b/chip/g/board_space.h
index 6e04a2452d..0c15bde5bf 100644
--- a/chip/g/board_space.h
+++ b/chip/g/board_space.h
@@ -51,6 +51,9 @@ struct info1_board_space {
* to be enforced.
*/
uint32_t aprv_not_needed;
+ /* Pad so that aprv_not_needed occupies it's full 'protect' size */
+ uint8_t aprv_padding[4];
+ uint64_t factory_cfg;
};
/*
@@ -83,6 +86,9 @@ BUILD_ASSERT(sizeof(struct info1_layout) == FLASH_INFO_SIZE);
#define INFO_APRV_DATA_SIZE sizeof(uint32_t)
#define INFO_APRV_DATA_OFFSET INFO_SPACE_OFFSET(aprv_not_needed)
+#define INFO_FACTORY_CFG_SIZE sizeof(uint64_t)
+#define INFO_FACTORY_CFG_OFFSET INFO_SPACE_OFFSET(factory_cfg)
+
/*
* Write protection for the INFO1 space allows windows with sizes that are
* powers of 2 to be protected. Given the different write restrictions on
@@ -104,4 +110,7 @@ BUILD_ASSERT(INFO_SN_DATA_SIZE <= INFO_SN_DATA_PROTECT_SIZE);
BUILD_ASSERT((INFO_APRV_DATA_SIZE & 3) == 0);
BUILD_ASSERT((INFO_APRV_DATA_OFFSET & 3) == 0);
+BUILD_ASSERT((INFO_FACTORY_CFG_SIZE & 7) == 0);
+BUILD_ASSERT((INFO_FACTORY_CFG_OFFSET & 7) == 0);
+
#endif /* ! __EC_CHIP_G_BOARD_SPACE_H */
diff --git a/chip/g/build.mk b/chip/g/build.mk
index 6f863169fc..358b1e640a 100644
--- a/chip/g/build.mk
+++ b/chip/g/build.mk
@@ -24,6 +24,7 @@ endif
# Required chip modules
chip-y = clock.o gpio.o hwtimer.o pre_init.o system.o
chip-$(CONFIG_BOARD_ID_SUPPORT) += board_id.o
+chip-$(CONFIG_BOARD_ID_SUPPORT) += factory_config.o
chip-$(CONFIG_SN_BITS_SUPPORT) += sn_bits.o
ifeq ($(CONFIG_POLLING_UART),y)
chip-y += polling_uart.o
diff --git a/chip/g/factory_config.c b/chip/g/factory_config.c
new file mode 100644
index 0000000000..4e30b79e8c
--- /dev/null
+++ b/chip/g/factory_config.c
@@ -0,0 +1,167 @@
+/* Copyright 2023 The ChromiumOS Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "common.h"
+#include "board_id.h"
+#include "endian.h"
+#include "extension.h"
+#include "flash_info.h"
+#include "system.h"
+#include "util.h"
+
+#define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ## args)
+#define CPRINTF(format, args...) cprintf(CC_SYSTEM, format, ## args)
+
+static int factory_config_is_blank(uint64_t fc)
+{
+ return fc == 0;
+}
+
+/**
+ * Read the INFO1 factory config value into fc.
+ *
+ * @return EC_SUCCESS or an error code in cases of various failures to read the
+ * flash space.
+ */
+static int read_factory_config(uint64_t *fc)
+{
+ uint32_t *fc_p;
+ int i;
+
+ /*
+ * The factory config offset is guaranteed to be divisible by 4, and it
+ * is guaranteed to be aligned at 8 bytes.
+ */
+
+ fc_p = (uint32_t *)fc;
+
+ for (i = 0; i < sizeof(*fc); i += sizeof(uint32_t)) {
+ int rv;
+
+ rv = flash_physical_info_read_word
+ (INFO_FACTORY_CFG_OFFSET + i, fc_p);
+ if (rv != EC_SUCCESS) {
+ CPRINTF("%s: failed to read word %d, error %d\n",
+ __func__, i, rv);
+ return rv;
+ }
+ fc_p++;
+ }
+ /* The config is stored inverted. Invert the value. */
+ *fc = ~(*fc);
+ return EC_SUCCESS;
+}
+
+void print_factory_config(void)
+{
+ uint64_t fc;
+ int rv;
+
+ rv = read_factory_config(&fc);
+ ccprintf("fc = ");
+ if (rv)
+ ccprintf("invalid (%d)\n", rv);
+ else
+ ccprintf("0x%016llx\n", fc);
+ ccprintf("\n");
+}
+
+/**
+ * Write the factory config into the flash INFO1 space.
+ *
+ * @param fc Pointer to the factory config to copy into info1
+ *
+ * @return EC_SUCCESS or an error code in cases of various failures to read or
+ * if the space has been already initialized.
+ */
+static int write_factory_config(uint64_t *new_fc)
+{
+ uint64_t fc;
+ uint32_t rv;
+#ifndef CR50_DEV
+ struct board_id id;
+
+ /* Fail if Board ID Type is already programmed */
+ if (read_board_id(&id) || !board_id_type_is_blank(&id))
+ return EC_ERROR_ACCESS_DENIED;
+#endif
+
+ rv = read_factory_config(&fc);
+ if (rv != EC_SUCCESS) {
+ CPRINTS("%s: error reading cfg", __func__);
+ return rv;
+ }
+
+ if (*new_fc == fc) {
+ CPRINTS("%s: ok.", __func__);
+ return EC_SUCCESS;
+ }
+ if (!factory_config_is_blank(fc)) {
+ CPRINTS("%s: factory cfg already programmed", __func__);
+ return EC_ERROR_ACCESS_DENIED;
+ }
+
+ CPRINTS("Set FC - 0x%llx ", *new_fc);
+ /* The config is stored inverted. */
+ *new_fc = ~(*new_fc);
+
+ flash_info_write_enable();
+
+ /* Write Board ID */
+ rv = flash_info_physical_write(INFO_FACTORY_CFG_OFFSET,
+ sizeof(*new_fc), (const char *)new_fc);
+ if (rv != EC_SUCCESS)
+ CPRINTS("%s: write failed", __func__);
+
+ flash_info_write_disable();
+
+ return rv;
+}
+
+static enum vendor_cmd_rc vc_set_factory_config(enum vendor_cmd_cc code,
+ void *buf,
+ size_t input_size,
+ size_t *response_size)
+{
+ uint64_t fc;
+ uint8_t *pbuf = buf;
+ int rv;
+
+ *response_size = 0;
+
+ if (input_size != INFO_FACTORY_CFG_SIZE)
+ return VENDOR_RC_BOGUS_ARGS;
+
+ memcpy(&fc, pbuf, INFO_FACTORY_CFG_SIZE);
+ /* Convert to line representation. */
+ fc = be64toh(fc);
+
+ rv = write_factory_config(&fc);
+ if (rv == EC_ERROR_ACCESS_DENIED)
+ return VENDOR_RC_NOT_ALLOWED;
+ else if (rv)
+ return VENDOR_RC_INTERNAL_ERROR;
+ return VENDOR_RC_SUCCESS;
+}
+DECLARE_VENDOR_COMMAND(VENDOR_CC_SET_FACTORY_CONFIG, vc_set_factory_config);
+
+static enum vendor_cmd_rc vc_get_factory_config(enum vendor_cmd_cc code,
+ void *buf,
+ size_t input_size,
+ size_t *response_size)
+{
+ uint64_t fc;
+
+ *response_size = 0;
+ if (read_factory_config(&fc))
+ return VENDOR_RC_READ_FLASH_FAIL;
+
+ fc = htobe64(fc);
+ memcpy(buf, &fc, sizeof(fc));
+ *response_size = sizeof(fc);
+
+ return VENDOR_RC_SUCCESS;
+}
+DECLARE_VENDOR_COMMAND(VENDOR_CC_GET_FACTORY_CONFIG, vc_get_factory_config);
diff --git a/chip/g/factory_config.h b/chip/g/factory_config.h
new file mode 100644
index 0000000000..26345c1eb9
--- /dev/null
+++ b/chip/g/factory_config.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2023 The ChromiumOS Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef __EC_CHIP_G_FACTORY_CONFIG_H
+#define __EC_CHIP_G_FACTORY_CONFIG_H
+
+#include "board_space.h"
+/**
+ * Print the factory config value.
+ */
+void print_factory_config(void);
+
+#endif /* ! __EC_CHIP_G_FACTORY_CONFIG_H */
diff --git a/common/extension.c b/common/extension.c
index 80cd94c06d..847149e830 100644
--- a/common/extension.c
+++ b/common/extension.c
@@ -39,6 +39,8 @@ uint32_t extension_route_command(struct vendor_cmd_params *p)
case VENDOR_CC_DS_DIS_TEMP:
case VENDOR_CC_USER_PRES:
case VENDOR_CC_WP:
+ case VENDOR_CC_GET_FACTORY_CONFIG:
+ case VENDOR_CC_SET_FACTORY_CONFIG:
#endif /* defined(CR50_DEV) */
case EXTENSION_POST_RESET: /* Always need to reset. */
case VENDOR_CC_CCD: