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>
This commit is contained in:
Nicolas Boichat
2017-03-28 17:53:48 +08:00
committed by chrome-bot
parent 629c3964a2
commit 68a537e466
4 changed files with 124 additions and 20 deletions

View File

@@ -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
/*

View File

@@ -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

View File

@@ -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.

View File

@@ -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__ */