summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--board/cr50/board.c16
-rw-r--r--board/cr50/scratch_reg1.h35
-rw-r--r--board/cr50/wp.c105
-rw-r--r--chip/g/system.c52
-rw-r--r--include/system.h6
5 files changed, 171 insertions, 43 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)
{
diff --git a/chip/g/system.c b/chip/g/system.c
index 5ab69abda1..a6a67cc5f1 100644
--- a/chip/g/system.c
+++ b/chip/g/system.c
@@ -310,7 +310,7 @@ static int a_is_newer_than_b(const struct SignedHeader *a,
* apparently failing image from being considered as a candidate to load and
* run on the following reboots.
*/
-static int corrupt_other_header(volatile struct SignedHeader *header)
+static int corrupt_header(volatile struct SignedHeader *header)
{
int rv;
const char zero[4] = {}; /* value to write to magic. */
@@ -344,19 +344,15 @@ static int corrupt_other_header(volatile struct SignedHeader *header)
*/
#define RW_BOOT_MAX_RETRY_COUNT 5
-int system_process_retry_counter(void)
+/*
+ * Check if the current running image is newer. Set the passed in pointer, if
+ * supplied, to point to the newer image in case the running image is the
+ * older one.
+ */
+static int current_image_is_newer(struct SignedHeader **newer_image)
{
- unsigned retry_counter;
struct SignedHeader *me, *other;
- retry_counter = GREG32(PMU, LONG_LIFE_SCRATCH0);
- system_clear_retry_counter();
-
- ccprintf("%s:retry counter %d\n", __func__, retry_counter);
-
- if (retry_counter <= RW_BOOT_MAX_RETRY_COUNT)
- return EC_SUCCESS;
-
if (system_get_image_copy() == SYSTEM_IMAGE_RW) {
me = (struct SignedHeader *)
get_program_memory_addr(SYSTEM_IMAGE_RW);
@@ -369,17 +365,43 @@ int system_process_retry_counter(void)
get_program_memory_addr(SYSTEM_IMAGE_RW);
}
- if (a_is_newer_than_b(me, other)) {
+ if (a_is_newer_than_b(me, other))
+ return 1;
+
+ if (newer_image)
+ *newer_image = other;
+ return 0;
+}
+
+int system_rollback_detected(void)
+{
+ return !current_image_is_newer(NULL);
+}
+
+int system_process_retry_counter(void)
+{
+ unsigned retry_counter;
+ struct SignedHeader *newer_image;
+
+ retry_counter = GREG32(PMU, LONG_LIFE_SCRATCH0);
+ system_clear_retry_counter();
+
+ ccprintf("%s:retry counter %d\n", __func__, retry_counter);
+
+ if (retry_counter <= RW_BOOT_MAX_RETRY_COUNT)
+ return EC_SUCCESS;
+
+ if (current_image_is_newer(&newer_image)) {
ccprintf("%s: "
"this is odd, I am newer, but retry counter was %d\n",
__func__, retry_counter);
return EC_SUCCESS;
}
/*
- * let's corrupt the "other" guy so that the next restart is happening
- * straight into this version.
+ * let's corrupt the newer image so that the next restart is happening
+ * straight into the current version.
*/
- return corrupt_other_header(other);
+ return corrupt_header(newer_image);
}
int system_rolling_reboot_suspected(void)
diff --git a/include/system.h b/include/system.h
index c8b7c8ee97..4df0fb1bad 100644
--- a/include/system.h
+++ b/include/system.h
@@ -488,4 +488,10 @@ void system_clear_retry_counter(void);
*/
int system_rolling_reboot_suspected(void);
+/**
+ * Compare the rw headers to check if there was a rollback.
+ *
+ * @return a boolean, set to True if a rollback is detected.
+ */
+int system_rollback_detected(void);
#endif /* __CROS_EC_SYSTEM_H */