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>
Reviewed-on: https://chromium-review.googlesource.com/448720
Tested-by: Vadim Bendebury <vbendeb@chromium.org>
Reviewed-by: Aseda Aboagye <aaboagye@chromium.org>
Reviewed-by: Mary Ruthven <mruthven@chromium.org>
Commit-Queue: Vadim Bendebury <vbendeb@chromium.org>
This commit is contained in:
Aseda Aboagye 2017-02-21 17:12:35 -08:00 committed by ChromeOS Commit Bot
parent bd6effdebc
commit f750d1a998
9 changed files with 186 additions and 25 deletions

View File

@ -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;

View File

@ -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.
*

View File

@ -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)

View File

@ -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();
}

View File

@ -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

View File

@ -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 */

View File

@ -42,6 +42,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.

View File

@ -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 */

View File

@ -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 */