summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAseda Aboagye <aaboagye@google.com>2017-02-21 17:12:35 -0800
committerchrome-bot <chrome-bot@chromium.org>2017-02-27 18:50:12 -0800
commit2a7683af41a65907ed81f4a448390c5d0b09cedc (patch)
treeeb482f4b6c68da76e7aca732856346236b1746a6
parentec98dbfb35bb22bb6b9096eceedda93c9f88f85c (diff)
downloadchrome-ec-2a7683af41a65907ed81f4a448390c5d0b09cedc.tar.gz
cr50: Store console lock state in NvMem vars.
This commit enables the use of the nvmem vars module. The console lock state is migrated from using the long life scratch register, to nvmem vars instead which will persist across power on reboots. BUG=b:35586145 BRANCH=None TEST=Flash a dev image. Lock the console. Remove all power from the system. Power on system and verify that console is still locked. Unlock the console, remove power from the system, power on the system, verify that the console is now unlocked. TEST=Repeat the above test, but using the nvtestvar console command instead. Change-Id: I03a2098bb0017cfca59889457a332eafb0e95db6 Signed-off-by: Aseda Aboagye <aaboagye@google.com> Reviewed-on: https://chromium-review.googlesource.com/445804 Commit-Ready: Aseda Aboagye <aaboagye@chromium.org> Tested-by: Aseda Aboagye <aaboagye@chromium.org> Reviewed-by: Vadim Bendebury <vbendeb@chromium.org>
-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 */