diff options
-rw-r--r-- | board/cr50/board.c | 2 | ||||
-rw-r--r-- | chip/g/board_space.h | 9 | ||||
-rw-r--r-- | chip/g/build.mk | 1 | ||||
-rw-r--r-- | chip/g/factory_config.c | 167 | ||||
-rw-r--r-- | chip/g/factory_config.h | 16 | ||||
-rw-r--r-- | common/extension.c | 2 |
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: |