summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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: