diff --git a/board/cr50/board.c b/board/cr50/board.c index c967871c8e..1bb6ce46ec 100644 --- a/board/cr50/board.c +++ b/board/cr50/board.c @@ -450,6 +450,27 @@ int is_ec_rst_asserted(void) return GREAD(RBOX, ASSERT_EC_RST); } +void nvmem_wipe_or_reboot(void) +{ + /* + * Blindly zapping the TPM space while the AP is awake and poking at it + * will bork the TPM task and the AP itself, so force the whole system + * off by holding the EC in reset. + */ + assert_ec_rst(); + + /* + * If we can't clear the NVMEM or can't reset the TPM task, something + * is unexpectedly wrong. To be safe, let's reboot the Cr50 (which also + * reboots the EC and AP). + */ + if (nvmem_setup(0) != EC_SUCCESS || tpm_reset() != 1) + system_reset(SYSTEM_RESET_HARD); + + /* Wipe & reset is complete. Allow the EC and AP to reboot */ + deassert_ec_rst(); +} + void nvmem_compute_sha(uint8_t *p_buf, int num_bytes, uint8_t *p_sha, int sha_len) { diff --git a/board/cr50/wp.c b/board/cr50/wp.c index 2800338555..8467370eb2 100644 --- a/board/cr50/wp.c +++ b/board/cr50/wp.c @@ -6,6 +6,7 @@ #include "common.h" #include "console.h" #include "hooks.h" +#include "nvmem.h" #include "registers.h" #include "system.h" #include "task.h" @@ -62,22 +63,25 @@ static int unlock_in_progress; /* Only invoked when the unlock sequence is done, either good or bad. */ static void unlock_sequence_is_over(void) { + /* Disable the power button interrupt so we aren't bothered */ + GWRITE_FIELD(RBOX, INT_ENABLE, INTR_PWRB_IN_FED, 0); + task_disable_irq(GC_IRQNUM_RBOX0_INTR_PWRB_IN_FED_INT); + if (unlock_in_progress) { + /* We didn't poke the button fast enough */ CPRINTS("Unlock process failed"); } else { + /* The last poke was after the final deadline, so we're done */ CPRINTS("Unlock process completed successfully"); + nvmem_wipe_or_reboot(); console_restricted_state = 0; + CPRINTS("TPM is erased, console is unlocked."); } unlock_in_progress = 0; - /* Disable power button interrupt */ - GWRITE_FIELD(RBOX, INT_ENABLE, INTR_PWRB_IN_FED, 0); - task_disable_irq(GC_IRQNUM_RBOX0_INTR_PWRB_IN_FED_INT); - /* Allow sleeping again */ enable_sleep(SLEEP_MASK_FORCE_NO_DSLEEP); - } DECLARE_DEFERRED(unlock_sequence_is_over); @@ -91,7 +95,7 @@ static void power_button_poked(void) } else { /* Wait for the next poke */ hook_call_deferred(&unlock_sequence_is_over_data, UNLOCK_BEAT); - CPRINTS("poke"); + CPRINTS("poke: not yet %.6ld", unlock_deadline); } GWRITE_FIELD(RBOX, INT_STATE, INTR_PWRB_IN_FED, 1); @@ -131,6 +135,10 @@ static int start_the_unlock_process(void) } /****************************************************************************/ +static const char warning[] = "\n\t!!! WARNING !!!\n\n" + "\tThe AP will be impolitely shut down and the TPM persistent memory\n" + "\tERASED before the console is unlocked. If this is not what you\n" + "\twant, simply do nothing and the unlock process will fail.\n\n"; static int command_lock(int argc, char **argv) { @@ -164,9 +172,12 @@ static int command_lock(int argc, char **argv) return EC_ERROR_BUSY; } + /* Warn about the side effects of wiping nvmem */ + ccputs(warning); + /* Now the user has to sit there and poke the button */ ccprintf("Start poking the power button in "); - for (i = 5; i; i--) { + for (i = 10; i; i--) { ccprintf("%d ", i); sleep(1); } diff --git a/common/nvmem.c b/common/nvmem.c index b3470b9889..3696d00279 100644 --- a/common/nvmem.c +++ b/common/nvmem.c @@ -314,14 +314,13 @@ int nvmem_setup(uint8_t starting_version) * both corrupted */ for (part = 0; part < NVMEM_NUM_PARTITIONS; part++) { - /* Set active partition variable */ - nvmem_act_partition = part; /* Get the cache buffer */ if (nvmem_lock_cache() != EC_SUCCESS) { CPRINTF("NvMem: Cache ram not available!\n"); return EC_ERROR_TIMEOUT; } - + /* Set active partition variable */ + nvmem_act_partition = part; /* Fill entire partition to 0xFFs */ memset(cache.base_ptr, 0xff, NVMEM_PARTITION_SIZE); /* Get pointer to start of partition */ diff --git a/include/nvmem.h b/include/nvmem.h index 781ea219f0..354e763c8d 100644 --- a/include/nvmem.h +++ b/include/nvmem.h @@ -51,9 +51,10 @@ * CONFIG_FLASH_NVMEM_BASE_(A|B) -> address of start of each partition * * The board.h file must define a macro or enum named NVMEM_NUM_USERS. - * The board.c file must include 1 function and an array of user buffer lengths + * The board.c file must implement: * nvmem_user_sizes[] -> array of user buffer lengths * nvmem_compute_sha() -> function used to compute 4 byte sha (or equivalent) + * nvmem_wipe() -> function to erase and reformat the users' storage * * Note that total length of user buffers must satisfy the following: * sum(user sizes) <= (NVMEM_PARTITION_SIZE) - sizeof(struct nvmem_tag) @@ -176,4 +177,11 @@ int nvmem_setup(uint8_t version); void nvmem_compute_sha(uint8_t *p_buf, int num_bytes, uint8_t *p_sha, int sha_len); +/* + * Erase and reformat the entire nvmem storage space. This returns only if it + * was successful. If it fails, we can't be certain of the state of the system, + * so it should do a hard reboot to be safe. + */ +void nvmem_wipe_or_reboot(void); + #endif /* __CROS_EC_NVMEM_UTILS_H */