summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--board/cr50/board.c6
-rw-r--r--board/cr50/board.h14
-rw-r--r--board/cr50/scratch_reg1.h10
-rw-r--r--board/cr50/wp.c82
-rw-r--r--common/nvmem_vars.c73
-rw-r--r--common/tpm_registers.c7
-rw-r--r--include/tpm_registers.h8
-rw-r--r--test/nvmem_vars.c7
-rw-r--r--test/test_config.h4
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 */