diff options
author | Mary Ruthven <mruthven@chromium.org> | 2016-12-15 14:21:56 -0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2016-12-21 00:43:38 -0800 |
commit | 4692be2957e102ad937d34c9eeccb76dca06ecff (patch) | |
tree | 980423d6b9c4a0a90d57064f35a04d9aa955cb39 /board/cr50 | |
parent | 167f7e51d8e7693a277077d6c24294d2997e1c55 (diff) | |
download | chrome-ec-4692be2957e102ad937d34c9eeccb76dca06ecff.tar.gz |
cr50: keep wp and console state through deep sleep
After every reboot, we were resetting the write protect and console
lock states back to default. With this change the wp and lock states
will be preserved through deep sleep. They will still be reset on any
other type of reboot (like Power On reset or panic).
The states are also cleared if the system detects a rollback even when
booting from the deep sleep.
With this patch it is going to be impossible to remove hardware write
protection guarding writes into AP and EC firmware flash, unless the
cr50 console is unlocked.
Locking the console would reinstate hardware write protection
automatically even if it was disabled when the console was unlocked.
Two long life scratch register 1 bits are used to keep the console and
write protect states over resets. To make code cleaner bitmap
assignments of the long life scratch register is put in its own
include file.
BUG=chrome-os-partner:58961
BRANCH=none
TEST=manual
On prod/dev images verify that the default wp and console lock
states are still correct.
change the lock and write protect states from the default and
verify they are preserved through deep sleep.
reboot cr50 and make sure that they are reset.
unlock the console and enable flash writes, then set fallback
counter on cr50 to the value of 6 (rw 0x40000128 1; rw
0x4000012c 6) and put the AP into deep sleep by hitting
Alt-H-VolUp.
In five minutes press the power button on the device to bring
it back from s5. Observe cr50 fall back to an older image and
console lock and wp disabled.
Change-Id: Ie7e62cb0b2eda49b04a592ee1d0903e83246b045
Signed-off-by: Mary Ruthven <mruthven@chromium.org>
Signed-off-by: Vadim Bendebury <vbendeb@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/420812
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Diffstat (limited to 'board/cr50')
-rw-r--r-- | board/cr50/board.c | 16 | ||||
-rw-r--r-- | board/cr50/scratch_reg1.h | 35 | ||||
-rw-r--r-- | board/cr50/wp.c | 105 |
3 files changed, 128 insertions, 28 deletions
diff --git a/board/cr50/board.c b/board/cr50/board.c index 956d7283c1..ab3f959a62 100644 --- a/board/cr50/board.c +++ b/board/cr50/board.c @@ -22,6 +22,7 @@ #include "nvmem.h" #include "rdd.h" #include "registers.h" +#include "scratch_reg1.h" #include "signed_header.h" #include "spi.h" #include "system.h" @@ -80,18 +81,6 @@ uint32_t nvmem_user_sizes[NVMEM_NUM_USERS] = { static uint32_t board_properties; static uint8_t reboot_request_posted; -/* - * Bit assignments of the LONG_LIFE_SCRATCH1 register. This register survives - * all kinds of resets, it is cleared only on the Power ON event. - */ -#define BOARD_SLAVE_CONFIG_SPI (1 << 0) /* TPM uses SPI interface */ -#define BOARD_SLAVE_CONFIG_I2C (1 << 1) /* TPM uses I2C interface */ -#define BOARD_USB_AP (1 << 2) /* One of the USB PHYs is */ - /* connected to the AP */ - -/* TODO(crosbug.com/p/56945): Remove when sys_rst_l has an external pullup */ -#define BOARD_NEEDS_SYS_RST_PULL_UP (1 << 5) /* Add a pullup to sys_rst_l */ -#define BOARD_USE_PLT_RESET (1 << 6) /* Platform reset exists */ int board_has_ap_usb(void) { return !!(board_properties & BOARD_USB_AP); @@ -325,9 +314,6 @@ static void board_init(void) /* Initialize NvMem partitions */ nvmem_init(); - /* Enable write protect on production images. Disable it on dev */ - GREG32(RBOX, EC_WP_L) = !console_is_restricted(); - /* Indication that firmware is running, for debug purposes. */ GREG32(PMU, PWRDN_SCRATCH16) = 0xCAFECAFE; } diff --git a/board/cr50/scratch_reg1.h b/board/cr50/scratch_reg1.h new file mode 100644 index 0000000000..b0c3a12431 --- /dev/null +++ b/board/cr50/scratch_reg1.h @@ -0,0 +1,35 @@ +/* + * Copyright 2016 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef __EC_BOARD_CR50_SCRATCH_REG1_H +#define __EC_BOARD_CR50_SCRATCH_REG1_H + +/* + * Bit assignments of the LONG_LIFE_SCRATCH1 register. This register survives + * all kinds of resets, it is cleared only on the Power ON event. + */ +#define BOARD_SLAVE_CONFIG_SPI (1 << 0) /* TPM uses SPI interface */ +#define BOARD_SLAVE_CONFIG_I2C (1 << 1) /* TPM uses I2C interface */ +#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 + * rest of the bits are taken. + */ + +/* TODO(crosbug.com/p/56945): Remove when sys_rst_l has an external pullup */ +#define BOARD_NEEDS_SYS_RST_PULL_UP (1 << 5) /* Add a pullup to sys_rst_l */ +#define BOARD_USE_PLT_RESET (1 << 6) /* Platform reset exists */ + +/* + * Bits to store console and write protect bit states across deep sleep and + * resets. + */ +#define BOARD_CONSOLE_UNLOCKED (1 << 7) +#define BOARD_WP_ASSERTED (1 << 8) + +#endif /* ! __EC_BOARD_CR50_SCRATCH_REG1_H */ diff --git a/board/cr50/wp.c b/board/cr50/wp.c index 28268f4cca..65e2344aee 100644 --- a/board/cr50/wp.c +++ b/board/cr50/wp.c @@ -10,6 +10,7 @@ #include "hooks.h" #include "nvmem.h" #include "registers.h" +#include "scratch_reg1.h" #include "system.h" #include "task.h" #include "timer.h" @@ -18,16 +19,36 @@ #define CPRINTS(format, args...) cprints(CC_RBOX, format, ## args) #define CPRINTF(format, args...) cprintf(CC_RBOX, format, ## args) +static void set_wp_state(int asserted) +{ + /* Enable writing to the long life register */ + GWRITE_FIELD(PMU, LONG_LIFE_SCRATCH_WR_EN, REG1, 1); + + if (asserted) { + GREG32(PMU, LONG_LIFE_SCRATCH1) |= BOARD_WP_ASSERTED; + GREG32(RBOX, EC_WP_L) = 0; + } else { + GREG32(PMU, LONG_LIFE_SCRATCH1) &= ~BOARD_WP_ASSERTED; + GREG32(RBOX, EC_WP_L) = 1; + } + + /* Disable writing to the long life register */ + GWRITE_FIELD(PMU, LONG_LIFE_SCRATCH_WR_EN, REG1, 0); +} + static int command_wp(int argc, char **argv) { int val; if (argc > 1) { - if (!parse_bool(argv[1], &val)) - return EC_ERROR_PARAM1; + if (console_is_restricted()) { + ccprintf("Console is locked, no parameters allowed\n"); + } else { + if (!parse_bool(argv[1], &val)) + return EC_ERROR_PARAM1; - /* Invert, because active low */ - GREG32(RBOX, EC_WP_L) = !val; + set_wp_state(!!val); + } } /* Invert, because active low */ @@ -37,24 +58,53 @@ static int command_wp(int argc, char **argv) return EC_SUCCESS; } -DECLARE_CONSOLE_COMMAND(wp, command_wp, - "[<BOOLEAN>]", - "Get/set the flash HW write-protect signal"); +DECLARE_SAFE_CONSOLE_COMMAND(wp, command_wp, + "[<BOOLEAN>]", + "Get/set the flash HW write-protect signal"); /* When the system is locked down, provide a means to unlock it */ #ifdef CONFIG_RESTRICTED_CONSOLE_COMMANDS +#define LOCK_ENABLED 1 + /* Hand-built images may be initially unlocked; Buildbot images are not. */ #ifdef CR50_DEV -static int console_restricted_state; +static int console_restricted_state = !LOCK_ENABLED; #else -static int console_restricted_state = 1; +static int console_restricted_state = LOCK_ENABLED; #endif +static void set_console_lock_state(int lock_state) +{ + console_restricted_state = lock_state; + + /* + * Assert WP unconditionally on locked console. Keep this invocation + * separate, as it will also enable/disable writes into + * LONG_LIFE_SCRATCH1 + */ + 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); + + /* 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; + + /* Disable writing to the long life register */ + GWRITE_FIELD(PMU, LONG_LIFE_SCRATCH_WR_EN, REG1, 0); + + CPRINTS("The console is %s", + lock_state == LOCK_ENABLED ? "locked" : "unlocked"); +} + static void lock_the_console(void) { - CPRINTS("The console is locked"); - console_restricted_state = 1; + set_console_lock_state(LOCK_ENABLED); } static void unlock_the_console(void) @@ -71,12 +121,41 @@ static void unlock_the_console(void) * bet for fixing the problem. */ CPRINTS("%s: Couldn't wipe nvmem! (rc %d)", __func__, rc); + cflush(); system_reset(SYSTEM_RESET_HARD); } - CPRINTS("TPM is erased, console is unlocked"); - console_restricted_state = 0; + CPRINTS("TPM is erased"); + set_console_lock_state(!LOCK_ENABLED); +} + +static void init_console_lock_and_wp(void) +{ + /* + * On an unexpected reboot or a system rollback reset the console and + * write protect states. + */ + if (system_rollback_detected() || + !(system_get_reset_flags() & RESET_FLAG_HIBERNATE)) { + /* Reset the console lock to the default value */ + set_console_lock_state(console_restricted_state); + + /* Always assert WP on H1 cold resets, reboots or fallbacks. */ + set_wp_state(1); + return; + } + + if (GREG32(PMU, LONG_LIFE_SCRATCH1) & BOARD_CONSOLE_UNLOCKED) + set_console_lock_state(!LOCK_ENABLED); + else + set_console_lock_state(LOCK_ENABLED); + + 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); int console_is_restricted(void) { |