summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Boichat <drinkcat@google.com>2017-03-28 17:53:48 +0800
committerchrome-bot <chrome-bot@chromium.org>2017-04-11 20:22:32 -0700
commit68a537e4666e51ecc8a99a5362de1c3229bace89 (patch)
tree9ec9a0c6564948f73287b41a6f6cc9e18983b174
parent629c3964a2bd8a92d61daaef633fc0cc5e65bc10 (diff)
downloadchrome-ec-68a537e4666e51ecc8a99a5362de1c3229bace89.tar.gz
rwsig: Make it possible to run as a task
(Optionally) split rwsig verification into a separate task. This allows us to initialize other components (e.g. USB) while the verification is in progress, speeding up the boot process to active USB in RO case. After CONFIG_RWSIG_JUMP_TIMEOUT, the EC will jump to the RW section if no action is taken by the AP (such as a forced request to jump to RW, or starting an update). Note: This comes with a ~36ms boot time regression, as other code gets to run before verification starts. BRANCH=none BUG=b:35587171 TEST=Flash, board boots to RW after 1s TEST=Change jump timeout to 5s, add 5s delay in check_signature, add console command to manually abort/continue rwsig verification. 'rwsig continue' works => Board jumps to RW after check_signature is completed (or immediately while waiting for timeout) 'rwsig abort' works => Board does not jump to RW. Change-Id: Ica5732b9298bb4d3b743cae2ba78df259db915ef Reviewed-on: https://chromium-review.googlesource.com/468709 Commit-Ready: Nicolas Boichat <drinkcat@chromium.org> Tested-by: Nicolas Boichat <drinkcat@chromium.org> Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r--common/main.c11
-rw-r--r--common/rwsig.c85
-rw-r--r--include/config.h7
-rw-r--r--include/rwsig.h41
4 files changed, 124 insertions, 20 deletions
diff --git a/common/main.c b/common/main.c
index dff6c6a126..d517636f0e 100644
--- a/common/main.c
+++ b/common/main.c
@@ -162,12 +162,15 @@ test_mockable __keep int main(void)
button_init();
#endif
-#ifdef CONFIG_RWSIG
+#if defined(CONFIG_RWSIG) && !defined(HAS_TASK_RWSIG)
/*
- * Check the RW firmware signature
- * and eventually jump to it if it is good.
+ * Check the RW firmware signature and jump to it if it is good.
+ *
+ * Only the Read-Only firmware needs to do the signature check.
*/
- check_rw_signature();
+ if (system_get_image_copy() == SYSTEM_IMAGE_RO &&
+ rwsig_check_signature())
+ rwsig_jump_now();
#endif
/*
diff --git a/common/rwsig.c b/common/rwsig.c
index 931a74cbf2..244e201ad4 100644
--- a/common/rwsig.c
+++ b/common/rwsig.c
@@ -15,6 +15,7 @@
#include "sha256.h"
#include "shared_mem.h"
#include "system.h"
+#include "task.h"
#include "usb_pd.h"
#include "util.h"
#include "vb21_struct.h"
@@ -28,6 +29,15 @@
static uint32_t * const rw_rst =
(uint32_t *)(CONFIG_PROGRAM_MEMORY_BASE + CONFIG_RW_MEM_OFF + 4);
+
+void rwsig_jump_now(void)
+{
+ /*
+ * TODO(b/35587171): This should also check RW flash is protected.
+ */
+ system_run_image_copy(SYSTEM_IMAGE_RW);
+}
+
/*
* Check that memory between rwdata[start] and rwdata[len-1] is filled
* with ones. data, start and len must be aligned on 4-byte boundary.
@@ -49,14 +59,14 @@ static int check_padding(const uint8_t *data,
return 1;
}
-void check_rw_signature(void)
+int rwsig_check_signature(void)
{
struct sha256_ctx ctx;
int res;
const struct rsa_public_key *key;
const uint8_t *sig;
uint8_t *hash;
- uint32_t *rsa_workbuf;
+ uint32_t *rsa_workbuf = NULL;
const uint8_t *rwdata = (uint8_t *)CONFIG_PROGRAM_MEMORY_BASE
+ CONFIG_RW_MEM_OFF;
int good = 0;
@@ -71,13 +81,9 @@ void check_rw_signature(void)
int32_t min_rollback_version;
#endif
- /* Only the Read-Only firmware needs to do the signature check */
- if (system_get_image_copy() != SYSTEM_IMAGE_RO)
- return;
-
/* Check if we have a RW firmware flashed */
if (*rw_rst == 0xffffffff)
- return;
+ goto out;
CPRINTS("Verifying RW image...");
@@ -89,7 +95,7 @@ void check_rw_signature(void)
rw_rollback_version < min_rollback_version) {
CPRINTS("Rollback error (%d < %d)",
rw_rollback_version, min_rollback_version);
- return;
+ goto out;
}
#endif
@@ -97,7 +103,7 @@ void check_rw_signature(void)
res = shared_mem_acquire(3 * RSANUMBYTES, (char **)&rsa_workbuf);
if (res) {
CPRINTS("No memory for RW verification");
- return;
+ goto out;
}
#ifdef CONFIG_RWSIG_TYPE_USBPD1
@@ -186,14 +192,65 @@ void check_rw_signature(void)
out:
CPRINTS("RW verify %s", good ? "OK" : "FAILED");
- if (good) {
- /* Jump to the RW firmware */
- system_run_image_copy(SYSTEM_IMAGE_RW);
- } else {
+ if (!good) {
pd_log_event(PD_EVENT_ACC_RW_FAIL, 0, 0, NULL);
/* RW firmware is invalid : do not jump there */
if (system_is_locked())
system_disable_jump();
}
- shared_mem_release(rsa_workbuf);
+ if (rsa_workbuf)
+ shared_mem_release(rsa_workbuf);
+
+ return good;
+}
+
+#ifdef HAS_TASK_RWSIG
+#define TASK_EVENT_ABORT TASK_EVENT_CUSTOM(1)
+#define TASK_EVENT_CONTINUE TASK_EVENT_CUSTOM(2)
+
+static enum rwsig_status rwsig_status;
+
+enum rwsig_status rwsig_get_status(void)
+{
+ return rwsig_status;
}
+
+void rwsig_abort(void)
+{
+ task_set_event(TASK_ID_RWSIG, TASK_EVENT_ABORT, 0);
+}
+
+void rwsig_continue(void)
+{
+ task_set_event(TASK_ID_RWSIG, TASK_EVENT_CONTINUE, 0);
+}
+
+void rwsig_task(void)
+{
+ uint32_t evt;
+
+ if (system_get_image_copy() != SYSTEM_IMAGE_RO)
+ goto exit;
+
+ rwsig_status = RWSIG_IN_PROGRESS;
+ if (!rwsig_check_signature()) {
+ rwsig_status = RWSIG_INVALID;
+ goto exit;
+ }
+ rwsig_status = RWSIG_VALID;
+
+ /* Jump to RW after a timeout */
+ evt = task_wait_event(CONFIG_RWSIG_JUMP_TIMEOUT);
+
+ /* Jump now if we timed out, or were told to continue. */
+ if (evt == TASK_EVENT_TIMER || evt == TASK_EVENT_CONTINUE)
+ rwsig_jump_now();
+ else
+ rwsig_status = RWSIG_ABORTED;
+
+exit:
+ /* We're done, yield forever. */
+ while (1)
+ task_wait_event(-1);
+}
+#endif
diff --git a/include/config.h b/include/config.h
index 27afcbfb48..b94fef6eeb 100644
--- a/include/config.h
+++ b/include/config.h
@@ -1819,6 +1819,13 @@
#undef CONFIG_RWSIG
/*
+ * When RWSIG verification is performed as a task, time to wait from signature
+ * verification to an automatic jump to RW (if AP does not request the wait to
+ * be interrupted).
+ */
+#define CONFIG_RWSIG_JUMP_TIMEOUT (1000 * MSEC)
+
+/*
* Defines what type of futility signature type should be used.
* RWSIG should be used for new designs.
* Old adapters use the USBPD1 futility signature type.
diff --git a/include/rwsig.h b/include/rwsig.h
index 138751d3cc..bb70077732 100644
--- a/include/rwsig.h
+++ b/include/rwsig.h
@@ -10,9 +10,46 @@
#include "rsa.h"
#ifndef __ASSEMBLER__
+#ifdef HAS_TASK_RWSIG
+/* The functions below only make sense if RWSIG task is defined. */
-/* Checks RW signature. */
-void check_rw_signature(void);
+/* Current status of RW signature verification */
+enum rwsig_status {
+ RWSIG_UNKNOWN = 0, /* Unknown/not started */
+ RWSIG_IN_PROGRESS,
+ RWSIG_VALID,
+ RWSIG_INVALID,
+ RWSIG_ABORTED,
+};
+
+/* Returns current rwsig verification status. */
+enum rwsig_status rwsig_get_status(void);
+
+/*
+ * Aborts current verification, also prevents RWSIG task from automatically
+ * jumping to RW.
+ * This is used by usb_updater when a RW update is required, giving it enough
+ * time to actually perform the update.
+ */
+void rwsig_abort(void);
+
+/*
+ * Tells RWSIG task to jump to RW immediately, if the signature is correct.
+ * This is used by usb_updater when no RW update is required, to speed up
+ * boot time.
+ */
+void rwsig_continue(void);
+
+#else /* !HAS_TASK_RWSIG */
+/* These functions can only be called directly if RWSIG task is not defined. */
+
+/* Checks RW signature. Returns a boolean indicating success. */
+int rwsig_check_signature(void);
+
+/* Jumps to RW, if signature is fine, returns on error (otherwise, jumps). */
+void rwsig_jump_now(void);
+
+#endif
#endif /* !__ASSEMBLER__ */