diff options
author | Daisuke Nojiri <dnojiri@chromium.org> | 2019-10-21 10:07:48 -0700 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-02-09 08:31:43 +0000 |
commit | 37151225f4d791204a75173eec64ebfdaf2cbdec (patch) | |
tree | a9680e1fd0897c1ea6e0461055760c42944fdee7 /common/vboot_hash.c | |
parent | a4f7c8ef7c0b9b3206f67299414c2cbd2a5fe84a (diff) | |
download | chrome-ec-37151225f4d791204a75173eec64ebfdaf2cbdec.tar.gz |
EFS2: Implement Early Firmware Selection ver.2
EFS v1 allowed Chromeboxes to verify RW without AP. EFS v2 will bring
the benefts to Chromebooks, which are:
- Reduce RO dependency and presence. Allow more code to be updated
in the fields.
- Remove jumptag and workarounds needed for late sysjump.
Major imporvements over v1 are:
- No A/B slot required.
- No signature in RW or public key in RO.
- Rollback-attack protection.
- Verifies only RW being used instead of whole RW section.
For battery-equipped devices, additional benefts are:
- Immediate boot on drained battery.
- Support recovery mode regardless of battery condition.
- Faster charge in S5/G3.
EC-Cr50 communication is based on the shared UART (go/ec-cr50-comm).
EFS2 is documented in go/ec-efs2.
Signed-off-by: Daisuke Nojiri <dnojiri@chromium.org>
BUG=chromium:1045217,chromium:141143112
BRANCH=none
TEST=Boot Helios in NORMAL/NO_BOOT/NO_BOOT_RECOVERY/RECOVERY mode.
TEST=Wake up EC from hibernate.
TEST=Make EC assert PACKET_MODE to wake up Cr50 from deepsleep.
Change-Id: I98a4fe1ecc59d106810a75daec3c424f953ff880
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2015357
Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
Commit-Queue: Daisuke Nojiri <dnojiri@chromium.org>
Tested-by: Daisuke Nojiri <dnojiri@chromium.org>
Auto-Submit: Daisuke Nojiri <dnojiri@chromium.org>
Diffstat (limited to 'common/vboot_hash.c')
-rw-r--r-- | common/vboot_hash.c | 89 |
1 files changed, 69 insertions, 20 deletions
diff --git a/common/vboot_hash.c b/common/vboot_hash.c index 0642e09e3c..0387040670 100644 --- a/common/vboot_hash.c +++ b/common/vboot_hash.c @@ -13,6 +13,7 @@ #include "host_command.h" #include "sha256.h" #include "shared_mem.h" +#include "stdbool.h" #include "system.h" #include "task.h" #include "timer.h" @@ -44,6 +45,8 @@ static uint32_t curr_pos; static const uint8_t *hash; /* Hash, or NULL if not valid */ static int want_abort; static int in_progress; +#define VBOOT_HASH_DEFERRED true +#define VBOOT_HASH_BLOCKING false static struct sha256_ctx ctx; @@ -109,6 +112,35 @@ static int read_and_hash_chunk(int offset, int size) #define SHA256_PRINT_SIZE 4 #endif +static void hash_next_chunk(size_t size) +{ +#ifdef CONFIG_MAPPED_STORAGE + flash_lock_mapped_storage(1); + SHA256_update(&ctx, (const uint8_t *)(CONFIG_MAPPED_STORAGE_BASE + + data_offset + curr_pos), size); + flash_lock_mapped_storage(0); +#else + if (read_and_hash_chunk(data_offset + curr_pos, size) != EC_SUCCESS) + return; +#endif +} + +static void vboot_hash_all_chunks(void) +{ + do { + size_t size = MIN(CHUNK_SIZE, data_size - curr_pos); + hash_next_chunk(size); + curr_pos += size; + } while (curr_pos < data_size); + + hash = SHA256_final(&ctx); + CPRINTS("hash done %ph", HEX_BUF(hash, SHA256_PRINT_SIZE)); + in_progress = 0; + clock_enable_module(MODULE_FAST_CPU, 0); + + return; +} + /** * Do next chunk of hashing work, if any. */ @@ -126,16 +158,7 @@ static void vboot_hash_next_chunk(void) /* Compute the next chunk of hash */ size = MIN(CHUNK_SIZE, data_size - curr_pos); - -#ifdef CONFIG_MAPPED_STORAGE - flash_lock_mapped_storage(1); - SHA256_update(&ctx, (const uint8_t *)(CONFIG_MAPPED_STORAGE_BASE + - data_offset + curr_pos), size); - flash_lock_mapped_storage(0); -#else - if (read_and_hash_chunk(data_offset + curr_pos, size) != EC_SUCCESS) - return; -#endif + hash_next_chunk(size); curr_pos += size; if (curr_pos >= data_size) { @@ -159,13 +182,23 @@ static void vboot_hash_next_chunk(void) } /** - * Start computing a hash of <size> bytes of data at flash offset <offset>. * * If nonce_size is non-zero, prefixes the <nonce> onto the data to be hashed. * Returns non-zero if error. */ +/** + * Start computing a hash of <size> bytes of data at flash offset <offset>. + * + * @param offset start address of data on flash to compute hash for. + * @param size size of data to compute hash for. + * @param nonce nonce to differentiate hash. + * @param nonce_size size of nonce. + * @param deferred True to hash progressively through deferred calls. + * False to hash with a blocking single call. + * @return ec_error_list. + */ static int vboot_hash_start(uint32_t offset, uint32_t size, - const uint8_t *nonce, int nonce_size) + const uint8_t *nonce, int nonce_size, bool deferred) { /* Fail if hash computation is already in progress */ if (in_progress) @@ -195,7 +228,10 @@ static int vboot_hash_start(uint32_t offset, uint32_t size, if (nonce_size) SHA256_update(&ctx, nonce, nonce_size); - hook_call_deferred(&vboot_hash_next_chunk_data, 0); + if (deferred) + hook_call_deferred(&vboot_hash_next_chunk_data, 0); + else + vboot_hash_all_chunks(); return EC_SUCCESS; } @@ -232,7 +268,9 @@ int vboot_hash_invalidate(int offset, int size) */ static uint32_t get_rw_size(void) { -#ifdef CONFIG_VBOOT_EFS +#ifdef CONFIG_VBOOT_EFS /* Only needed for EFS, which signs and verifies + * entire RW, thus not needed for EFS2, which + * verifies only the used image size. */ return CONFIG_RW_SIZE; #else return system_get_image_used(SYSTEM_IMAGE_RW); @@ -270,11 +308,19 @@ static void vboot_hash_init(void) { /* Start computing the hash of RW firmware */ vboot_hash_start(flash_get_rw_offset(system_get_active_copy()), - get_rw_size(), NULL, 0); + get_rw_size(), NULL, 0, VBOOT_HASH_DEFERRED); } } DECLARE_HOOK(HOOK_INIT, vboot_hash_init, HOOK_PRIO_INIT_VBOOT_HASH); +int vboot_get_rw_hash(const uint8_t **dst) +{ + int rv = vboot_hash_start(flash_get_rw_offset(system_get_active_copy()), + get_rw_size(), NULL, 0, VBOOT_HASH_BLOCKING); + *dst = hash; + return rv; +} + #ifdef CONFIG_SAVE_VBOOT_HASH static int vboot_hash_preserve_state(void) @@ -345,13 +391,14 @@ static int command_hash(int argc, char **argv) } else if (!strcasecmp(argv[1], "rw")) { return vboot_hash_start( get_offset(EC_VBOOT_HASH_OFFSET_ACTIVE), - get_rw_size(), NULL, 0); + get_rw_size(), + NULL, 0, VBOOT_HASH_DEFERRED); } else if (!strcasecmp(argv[1], "ro")) { return vboot_hash_start( CONFIG_EC_PROTECTED_STORAGE_OFF + CONFIG_RO_STORAGE_OFF, system_get_image_used(SYSTEM_IMAGE_RO), - NULL, 0); + NULL, 0, VBOOT_HASH_DEFERRED); } return EC_ERROR_PARAM2; } @@ -373,9 +420,10 @@ static int command_hash(int argc, char **argv) return vboot_hash_start(offset, size, (const uint8_t *)&nonce, - sizeof(nonce)); + sizeof(nonce), VBOOT_HASH_DEFERRED); } else - return vboot_hash_start(offset, size, NULL, 0); + return vboot_hash_start(offset, size, + NULL, 0, VBOOT_HASH_DEFERRED); } DECLARE_CONSOLE_COMMAND(hash, command_hash, "[abort | ro | rw] | [<offset> <size> [<nonce>]]", @@ -428,7 +476,8 @@ static int host_start_hash(const struct ec_params_vboot_hash *p) (offset == EC_VBOOT_HASH_OFFSET_UPDATE)) size = get_rw_size(); offset = get_offset(offset); - rv = vboot_hash_start(offset, size, p->nonce_data, p->nonce_size); + rv = vboot_hash_start(offset, size, p->nonce_data, p->nonce_size, + VBOOT_HASH_DEFERRED); if (rv == EC_SUCCESS) return EC_RES_SUCCESS; |