summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVadim Bendebury <vbendeb@chromium.org>2020-05-27 10:26:27 -0700
committerCommit Bot <commit-bot@chromium.org>2020-06-05 04:29:38 +0000
commitdd15f8676d55ef1c78f78016ce6c6175d3806174 (patch)
treec7e39fca212acee742f8dd668953d4c6446ad471
parent398315c41f2111135f2510e88d55ad3dbe83b5d6 (diff)
downloadchrome-ec-dd15f8676d55ef1c78f78016ce6c6175d3806174.tar.gz
ap_ro: add handling of the corrupted hash
This patch closes the AP RO verification loop on the Cr50 side. If the check is triggered, the valid AP hash is found, and the RO contents is found to not match the hash, the Cr50 will - assert the EC reset; - set a flag to prevent the code from deasserting EC reset; - start a periodic hook to reassert EC reset in case the user hits power+refresh. This will prevent the Chrome OS device from booting. A new CLI command is being added to display the verification state. In developer images the new command would allow to clear the failure state, when running prod images the only way out of the failure state would be the powercycle. BUG=b:153764696 TEST=verified that erasing or programming AP RO hash when board ID is set is impossible. Verified proper shutdown in case AP RO has is present and the AP RO space is corrupted and recovery using the new cli command when running a dev image. Verified that 'ecrst off' properly reports the override. Signed-off-by: Vadim Bendebury <vbendeb@chromium.org> Change-Id: I1029114126a9a79f80385af7bc8d5467738e04ca Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2218676 Reviewed-by: Mary Ruthven <mruthven@chromium.org>
-rw-r--r--board/cr50/board.c6
-rw-r--r--board/cr50/board.h6
-rw-r--r--board/cr50/power_button.c74
-rw-r--r--include/system.h3
4 files changed, 87 insertions, 2 deletions
diff --git a/board/cr50/board.c b/board/cr50/board.c
index 6843673662..defb033d52 100644
--- a/board/cr50/board.c
+++ b/board/cr50/board.c
@@ -1175,6 +1175,12 @@ void assert_ec_rst(void)
void deassert_ec_rst(void)
{
+ if (ec_rst_override()) {
+ ccprintf("EC un-reset blocked, try powercycle or Cr50 reboot."
+ "\n");
+ return;
+ }
+
wait_ec_rst(0);
if (uart_bitbang_is_enabled())
diff --git a/board/cr50/board.h b/board/cr50/board.h
index fea738f7d2..b9dc15e988 100644
--- a/board/cr50/board.h
+++ b/board/cr50/board.h
@@ -364,6 +364,12 @@ int ec_is_rx_allowed(void);
int servo_is_connected(void);
/*
+ * Returns nonzero value if EC reset line is taken over and should not be
+ * touched by the 'standard' EC reset functions.
+ */
+int ec_rst_override(void);
+
+/*
* Assert INT_AP_L to acknowledge AP that cr50 is ready for next TPM command.
* NOTE: must be called by ISR only.
*
diff --git a/board/cr50/power_button.c b/board/cr50/power_button.c
index 6aca820caf..6dab74d134 100644
--- a/board/cr50/power_button.c
+++ b/board/cr50/power_button.c
@@ -60,6 +60,71 @@ static void power_button_press_enable_interrupt(int enable)
#ifdef CONFIG_AP_RO_VERIFICATION
/*
+ * A hook used to keep the EC in reset, no matter what keys the user presses,
+ * the only way out is the Cr50 reboot, most likely through power cycle by
+ * battery cutoff.
+ *
+ * Cr50 console over SuzyQ would still be available in case the user has the
+ * cable and wants to see what happens with the system. The easiest way to see
+ * the system is in this state to run the 'flog' command and examine the flash
+ * log.
+ */
+static void keep_ec_in_reset(void);
+static bool ap_ro_verification_failed_;
+
+DECLARE_DEFERRED(keep_ec_in_reset);
+
+static void keep_ec_in_reset(void)
+{
+ if (!ap_ro_verification_failed_) {
+ enable_sleep(SLEEP_MASK_AP_RO_VERIFICATION);
+ return;
+ }
+
+ assert_ec_rst();
+ hook_call_deferred(&keep_ec_in_reset_data, 100 * MSEC);
+}
+
+static int ver_state_cmd(int argc, char **argv)
+{
+#ifdef CR50_DEV
+ int const max_args = 2;
+#else
+ int const max_args = 1;
+#endif
+
+ if (argc > max_args)
+ return EC_ERROR_PARAM_COUNT;
+#ifdef CR50_DEV
+ if (argc == max_args) {
+ if (strcasecmp(argv[1], "clear"))
+ return EC_ERROR_PARAM1;
+ if (ap_ro_verification_failed_) {
+ ap_ro_verification_failed_ = false;
+ deassert_ec_rst();
+ }
+ }
+#endif
+ ccprintf("%sAP RO verification failure detected\n",
+ ap_ro_verification_failed_ ? "" : "NO ");
+
+ return EC_SUCCESS;
+}
+DECLARE_SAFE_CONSOLE_COMMAND(ver_state, ver_state_cmd,
+#ifdef CR50_DEV
+ "[clear]",
+ "Display and/or clear AP RO validation state"
+#else
+ "", "Display AP RO validation state"
+#endif
+);
+
+int ec_rst_override(void)
+{
+ return ap_ro_verification_failed_;
+}
+
+/*
* Implement sequence detecting trigger for starting AP RO verification.
*
* 'RCTD' is short for 'RO check trigger detection'.
@@ -169,7 +234,14 @@ static int rctd_poll_handler(void)
CPRINTS("RO Validation triggered");
ap_ro_add_flash_event(APROF_CHECK_TRIGGERED);
- validate_ap_ro();
+
+ if (validate_ap_ro() == EC_ERROR_CRC) {
+ /* Validation failed, no go. */
+ ap_ro_verification_failed_ = true;
+ disable_sleep(SLEEP_MASK_AP_RO_VERIFICATION);
+ keep_ec_in_reset();
+ }
+
return 0;
}
diff --git a/include/system.h b/include/system.h
index 1df48cf28e..4862ad2dc0 100644
--- a/include/system.h
+++ b/include/system.h
@@ -425,7 +425,8 @@ enum {
SLEEP_MASK_USB_PD = BIT(5), /* USB PD device connected */
SLEEP_MASK_SPI = BIT(6), /* SPI communications ongoing */
SLEEP_MASK_I2C_SLAVE = BIT(7), /* I2C slave communication ongoing */
- SLEEP_MASK_FAN = BIT(8), /* Fan control loop ongoing */
+ SLEEP_MASK_AP_RO_VERIFICATION
+ = BIT(8), /* AP RO verification failure. */
SLEEP_MASK_USB_DEVICE = BIT(9), /* Generic USB device in use */
SLEEP_MASK_PWM = BIT(10), /* PWM output is enabled */
SLEEP_MASK_PHYSICAL_PRESENCE = BIT(11), /* Physical presence