diff options
-rw-r--r-- | board/cr50/board.c | 6 | ||||
-rw-r--r-- | board/cr50/board.h | 14 | ||||
-rw-r--r-- | board/cr50/scratch_reg1.h | 10 | ||||
-rw-r--r-- | board/cr50/wp.c | 82 | ||||
-rw-r--r-- | common/nvmem_vars.c | 73 | ||||
-rw-r--r-- | common/tpm_registers.c | 7 | ||||
-rw-r--r-- | include/tpm_registers.h | 8 | ||||
-rw-r--r-- | test/nvmem_vars.c | 7 | ||||
-rw-r--r-- | test/test_config.h | 4 |
9 files changed, 186 insertions, 25 deletions
diff --git a/board/cr50/board.c b/board/cr50/board.c index 0d1e9b8a4f..609d35766b 100644 --- a/board/cr50/board.c +++ b/board/cr50/board.c @@ -20,6 +20,7 @@ #include "i2cs.h" #include "init_chip.h" #include "nvmem.h" +#include "nvmem_vars.h" #include "rdd.h" #include "registers.h" #include "scratch_reg1.h" @@ -63,7 +64,6 @@ #define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ## args) -#define NVMEM_CR50_SIZE 272 #define NVMEM_TPM_SIZE ((sizeof((struct nvmem_partition *)0)->buffer) \ - NVMEM_CR50_SIZE) @@ -72,6 +72,8 @@ * should be set to * * NVMEM_PARTITION_SIZE - NVMEM_CR50_SIZE - 8 + * + * Both of these macros are defined in board.h. */ BUILD_ASSERT(NVMEM_TPM_SIZE == NV_MEMORY_SIZE); @@ -532,6 +534,8 @@ static void board_init(void) init_runlevel(PERMISSION_MEDIUM); /* Initialize NvMem partitions */ nvmem_init(); + /* Initialize the persistent storage. */ + initvars(); /* Indication that firmware is running, for debug purposes. */ GREG32(PMU, PWRDN_SCRATCH16) = 0xCAFECAFE; diff --git a/board/cr50/board.h b/board/cr50/board.h index 7b1b7f9665..1cf4b70bef 100644 --- a/board/cr50/board.h +++ b/board/cr50/board.h @@ -57,6 +57,10 @@ #define NVMEM_PARTITION_SIZE CFG_TOP_SIZE /* Size in bytes of NvMem area */ #define CONFIG_FLASH_NVMEM_SIZE (CFG_TOP_SIZE * NVMEM_NUM_PARTITIONS) +/* Enable <key, value> variable support. */ +#define CONFIG_FLASH_NVMEM_VARS +#define NVMEM_CR50_SIZE 272 +#define CONFIG_FLASH_NVMEM_VARS_USER_SIZE NVMEM_CR50_SIZE /* Go to sleep when nothing else is happening */ @@ -157,6 +161,14 @@ enum usb_spi { USB_SPI_EC, }; +/* NVMem variables. */ +enum nvmem_vars { + NVMEM_VAR_CONSOLE_LOCKED = 0, + NVMEM_VAR_TEST_VAR, + + NVMEM_VARS_COUNT +}; + void board_configure_deep_sleep_wakepins(void); /* Interrupt handler */ void tpm_rst_deasserted(enum gpio_signal signal); @@ -219,6 +231,8 @@ enum nvmem_users { }; #endif +#define CONFIG_FLASH_NVMEM_VARS_USER_NUM NVMEM_CR50 + /* * Let's be on the lookout for stack overflow, while debugging. * diff --git a/board/cr50/scratch_reg1.h b/board/cr50/scratch_reg1.h index 0383766dc2..405cdd2785 100644 --- a/board/cr50/scratch_reg1.h +++ b/board/cr50/scratch_reg1.h @@ -16,8 +16,8 @@ #define BOARD_USB_AP (1 << 2) /* One of the USB PHYs is */ /* connected to the AP */ /* - * This gap is left to enusre backwards compatibility with the earliest cr50 - * code releases. It will be possible to safely reuse this gap if and when the + * The gaps are left to enusre backwards compatibility with the earliest cr50 + * code releases. It will be possible to safely reuse these gaps if and when the * rest of the bits are taken. */ @@ -27,11 +27,7 @@ /* sys_rst_l to monitor the */ /* system resets */ -/* - * Bits to store console and write protect bit states across deep sleep and - * resets. - */ -#define BOARD_CONSOLE_UNLOCKED (1 << 7) +/* Bits to store write protect bit state across deep sleep and resets. */ #define BOARD_WP_ASSERTED (1 << 8) #define BOARD_FORCING_WP (1 << 9) diff --git a/board/cr50/wp.c b/board/cr50/wp.c index 2effdbb750..c381f81b3b 100644 --- a/board/cr50/wp.c +++ b/board/cr50/wp.c @@ -9,6 +9,7 @@ #include "gpio.h" #include "hooks.h" #include "nvmem.h" +#include "nvmem_vars.h" #include "registers.h" #include "scratch_reg1.h" #include "system.h" @@ -115,7 +116,10 @@ static int console_restricted_state = LOCK_ENABLED; static void set_console_lock_state(int lock_state) { - console_restricted_state = lock_state; + uint8_t nv_console_lock_state; + uint8_t key; + const struct tuple *t; + int rv; /* * Assert WP unconditionally on locked console. Keep this invocation @@ -125,17 +129,41 @@ static void set_console_lock_state(int lock_state) if (lock_state == LOCK_ENABLED) set_wp_state(1); - /* Enable writing to the long life register */ - GWRITE_FIELD(PMU, LONG_LIFE_SCRATCH_WR_EN, REG1, 1); + /* Retrieve the console locked state. */ + key = NVMEM_VAR_CONSOLE_LOCKED; + t = getvar((const uint8_t *)&key, sizeof(key)); + if (t == NULL) { + CPRINTS("Failed to read lock state from nvmem!"); + /* + * It's possible that the tuple doesn't (yet) exist. Set the + * value to some unknown. + */ + nv_console_lock_state = '?'; + } else { + nv_console_lock_state = *tuple_val(t); + } - /* Save the lock state in long life scratch */ - if (lock_state == LOCK_ENABLED) - GREG32(PMU, LONG_LIFE_SCRATCH1) &= ~BOARD_CONSOLE_UNLOCKED; - else - GREG32(PMU, LONG_LIFE_SCRATCH1) |= BOARD_CONSOLE_UNLOCKED; + /* Update the NVMem state if it differs. */ + if (lock_state != nv_console_lock_state) { + uint8_t val = lock_state == LOCK_ENABLED; - /* Disable writing to the long life register */ - GWRITE_FIELD(PMU, LONG_LIFE_SCRATCH_WR_EN, REG1, 0); + rv = setvar((const uint8_t *)&key, 1, (const uint8_t *)&val, 1); + if (rv) { + CPRINTS("Failed to save nvmem tuple in RAM buffer!" + " (rv: %d)", rv); + return; + } + + rv = writevars(); + if (rv) { + CPRINTS("Failed to save lock state in nvmem! (rv:%d)", + rv); + return; + } + } + + /* Update our RAM copy. */ + console_restricted_state = lock_state; CPRINTS("The console is %s", lock_state == LOCK_ENABLED ? "locked" : "unlocked"); @@ -166,18 +194,29 @@ static void unlock_the_console(void) } CPRINTS("TPM is erased"); + + /* Tell the TPM task to re-enable NvMem commits. */ + tpm_reinstate_nvmem_commits(); + + /* Unlock the console. */ set_console_lock_state(!LOCK_ENABLED); } static void init_console_lock_and_wp(void) { + uint8_t key; + const struct tuple *t; + uint8_t lock_state; + /* * On an unexpected reboot or a system rollback reset the console lock * and write protect states. */ if (system_rollback_detected() || - !(system_get_reset_flags() & RESET_FLAG_HIBERNATE)) { + !(system_get_reset_flags() & + (RESET_FLAG_HIBERNATE | RESET_FLAG_POWER_ON))) { /* Reset the console lock to the default value */ + CPRINTS("Setting console lock to default."); set_console_lock_state(console_restricted_state); /* Use BATT_PRES_L as the source for write protect. */ @@ -185,17 +224,27 @@ static void init_console_lock_and_wp(void) return; } - if (GREG32(PMU, LONG_LIFE_SCRATCH1) & BOARD_CONSOLE_UNLOCKED) - set_console_lock_state(!LOCK_ENABLED); - else - set_console_lock_state(LOCK_ENABLED); + key = NVMEM_VAR_CONSOLE_LOCKED; + t = getvar((const uint8_t *)&key, 1); + if (t == NULL) { + /* + * If the tuple doesn't exist, just use the default value (which + * will also create the tuple). + */ + CPRINTS("No tuple in nvmem. Setting console lock to default."); + set_console_lock_state(console_restricted_state); + } else { + lock_state = *tuple_val(t); + set_console_lock_state(lock_state); + } if (GREG32(PMU, LONG_LIFE_SCRATCH1) & BOARD_WP_ASSERTED) set_wp_state(1); else set_wp_state(0); } -DECLARE_HOOK(HOOK_INIT, init_console_lock_and_wp, HOOK_PRIO_DEFAULT); +/* This must run after initializing the NVMem partitions. */ +DECLARE_HOOK(HOOK_INIT, init_console_lock_and_wp, HOOK_PRIO_DEFAULT+1); int console_is_restricted(void) { @@ -238,6 +287,7 @@ static void unlock_sequence_is_over(void) } else { /* The last poke was after the final deadline, so we're done */ CPRINTS("Unlock process completed successfully"); + cflush(); unlock_the_console(); } diff --git a/common/nvmem_vars.c b/common/nvmem_vars.c index f67a2053db..af0981f1f0 100644 --- a/common/nvmem_vars.c +++ b/common/nvmem_vars.c @@ -5,6 +5,7 @@ */ #include "common.h" +#include "console.h" #include "nvmem.h" #include "nvmem_vars.h" #include "printf.h" @@ -427,10 +428,82 @@ static int command_dump(int argc, char **argv) for (i = 0; i < CONFIG_FLASH_NVMEM_VARS_USER_SIZE; i++) ccprintf(" %02x", rbuf[i]); ccprintf("\n"); + release_local_copy(); return EC_SUCCESS; } DECLARE_CONSOLE_COMMAND(dump, command_dump, "", "Dump the variable memory"); + +static int command_clear_nvmem_vars(int argc, char **argv) +{ + int rv; + + rv = nvmem_erase_user_data(CONFIG_FLASH_NVMEM_VARS_USER_NUM); + if (rv) + ccprintf("Error clearing nvmem vars! (rv: %d)\n", rv); + else + ccprintf("NvMem vars cleared successfully.\n"); + + /* + * Invalidate the cache buffer since we just erased the backing + * store. + */ + writevars(); + + /* + * Re-initialize the NvMem vars space so that it's ready for + * immediate use. + */ + initvars(); + + /* + * TODO(aaboagye): For "V1", this is where you might want to call and + * reset the defaults. + */ + + return rv; +} +DECLARE_CONSOLE_COMMAND(clr_nvmem_vars, command_clear_nvmem_vars, + "", + "Clear the NvMem variables."); + +static int command_nv_test_var(int argc, char **argv) +{ + const struct tuple *t; + uint8_t key; + uint8_t val; + int rv; + + key = NVMEM_VAR_TEST_VAR; + + if (argc > 1) { + val = (uint8_t)atoi(argv[1]); + rv = setvar(&key, 1, &val, 1); + if (rv) + ccprintf("setvar err %d", rv); + + rv = writevars(); + if (rv) + ccprintf("writevar err %d", rv); + } + + t = getvar(&key, 1); + if (t) { + val = *tuple_val(t); + } else { + ccprintf("No value set.\n"); + return EC_SUCCESS; + } + + /* Invalidate RAM buffer. */ + writevars(); + ccprintf("test_var: %d\n", val); + + return EC_SUCCESS; +} +DECLARE_SAFE_CONSOLE_COMMAND(nvtestvar, command_nv_test_var, + "[0-255]", + "Get/Set an NvMem test variable."); #endif diff --git a/common/tpm_registers.c b/common/tpm_registers.c index cac79c725d..6a914aabb0 100644 --- a/common/tpm_registers.c +++ b/common/tpm_registers.c @@ -709,10 +709,15 @@ int tpm_reset_request(int wait_until_done, int wipe_nvmem_first) */ static void reinstate_nvmem_commits(void) { - task_set_event(TASK_ID_TPM, TPM_EVENT_COMMIT, 0); + tpm_reinstate_nvmem_commits(); } DECLARE_DEFERRED(reinstate_nvmem_commits); +void tpm_reinstate_nvmem_commits(void) +{ + task_set_event(TASK_ID_TPM, TPM_EVENT_COMMIT, 0); +} + static void tpm_reset_now(int wipe_first) { /* This is more related to TPM task activity than TPM transactions */ diff --git a/include/tpm_registers.h b/include/tpm_registers.h index 9d5fba4cf5..9812c7c131 100644 --- a/include/tpm_registers.h +++ b/include/tpm_registers.h @@ -43,6 +43,14 @@ void tpm_register_interface(interface_restart_func interface_restart); int tpm_reset_request(int wait_until_done, int wipe_nvmem_first); /* + * Tell the TPM task to re-enable nvmem commits. + * + * NOTE: This function is NOT to be used freely, but only meant to be used in + * exceptional cases such as unlocking the console following a TPM wipe. + */ +void tpm_reinstate_nvmem_commits(void); + +/* * This structure describes the header of all commands and responses sent and * received over TPM FIFO. * diff --git a/test/nvmem_vars.c b/test/nvmem_vars.c index 5e31d6a2aa..99e059215e 100644 --- a/test/nvmem_vars.c +++ b/test/nvmem_vars.c @@ -82,6 +82,13 @@ int nvmem_commit(void) return EC_SUCCESS; } +int nvmem_erase_user_data(enum nvmem_users user) +{ + memset(ram_buffer, 0xff, sizeof(ram_buffer)); + memset(flash_buffer, 0xff, sizeof(flash_buffer)); + return EC_SUCCESS; +} + /****************************************************************************/ /* Helper routines */ diff --git a/test/test_config.h b/test/test_config.h index 029ce9bd70..d59652ec2b 100644 --- a/test/test_config.h +++ b/test/test_config.h @@ -199,6 +199,10 @@ enum nvmem_users { CONFIG_FLASH_NVMEM_VARS_USER_NUM, NVMEM_NUM_USERS }; +/* Define a test var. */ +enum nvmem_vars { + NVMEM_VAR_TEST_VAR, +}; #endif #define CONFIG_FLASH_NVMEM_VARS_USER_SIZE 600 #endif /* TEST_NVMEM_VARS */ |