From 68a537e4666e51ecc8a99a5362de1c3229bace89 Mon Sep 17 00:00:00 2001 From: Nicolas Boichat Date: Tue, 28 Mar 2017 17:53:48 +0800 Subject: [PATCH] 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 Tested-by: Nicolas Boichat Reviewed-by: Vincent Palatin --- common/main.c | 11 ++++--- common/rwsig.c | 85 ++++++++++++++++++++++++++++++++++++++++-------- include/config.h | 7 ++++ include/rwsig.h | 41 +++++++++++++++++++++-- 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 @@ -1818,6 +1818,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. 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__ */