diff options
-rw-r--r-- | common/main.c | 11 | ||||
-rw-r--r-- | common/rwsig.c | 85 | ||||
-rw-r--r-- | include/config.h | 7 | ||||
-rw-r--r-- | 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 @@ -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__ */ |