diff options
author | Daisuke Nojiri <dnojiri@chromium.org> | 2017-08-15 16:34:52 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2017-09-12 01:11:59 -0700 |
commit | 4dcee1c545c31d288b23221d8e07bc452214ce7b (patch) | |
tree | 1ddab11d51dcd5c0571f6f777b655ba333cd84e6 | |
parent | a52cfbc80c060d9883aee9de4e764e0b250d184a (diff) | |
download | chrome-ec-4dcee1c545c31d288b23221d8e07bc452214ce7b.tar.gz |
EFS: Add support for early firmware selection
Chromebox ECs performs EFS: verifying firmware before the AP boots.
This patch updates host commands which are required for the EFS.
The change includes:
* Update EC_CMD_FLASH_REGION_INFO to accept EC_FLASH_REGION_UPDATE
* Update EC_CMD_VBOOT_HASH to accept EC_VBOOT_HASH_OFFSET_UPDATE
When EC_FLASHS_REGION_UPDATE is specified, EC_CMD_FLASH_REGION_INFO
returns the slot which currently is not hosting a running RW copy.
When EC_VBOOT_HASH_OFFSET_UPDATE is specified, EC_CMD_VBOOT_HASH
computs the hash of the update slot. This hash covers the entire
region, including the signature at the end.
This patch undefines CONFIG_CMD_USBMUX and CONFIG_CMD_TYPEC
for gru to create space.
BUG=b:65028930
BRANCH=none
CQ-DEPEND=CL:648071
TEST=On Fizz, verify:
1. RW_B is old and updated by soft sync. RW_B is activated and
executed after reboot. System continues to boot to OS.
2. RW_A is old and updated by soft sync. RW_A is activated and
executed after reboot. System continues to boot to OS.
Change-Id: I9ece907b764d07ce94054ba27996e048c665a80a
Signed-off-by: Daisuke Nojiri <dnojiri@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/648448
-rw-r--r-- | board/kevin/board.h | 2 | ||||
-rw-r--r-- | common/flash.c | 34 | ||||
-rw-r--r-- | common/system.c | 41 | ||||
-rw-r--r-- | common/vboot_hash.c | 64 | ||||
-rw-r--r-- | include/ec_commands.h | 26 | ||||
-rw-r--r-- | include/flash.h | 25 | ||||
-rw-r--r-- | include/system.h | 15 | ||||
-rw-r--r-- | test/flash.c | 5 | ||||
-rw-r--r-- | util/ectool.c | 2 |
9 files changed, 170 insertions, 44 deletions
diff --git a/board/kevin/board.h b/board/kevin/board.h index bc07195d64..1f49105386 100644 --- a/board/kevin/board.h +++ b/board/kevin/board.h @@ -205,6 +205,8 @@ #undef CONFIG_CMD_ACCELSPOOF #undef CONFIG_CMD_I2C_XFER #undef CONFIG_CMD_SHMEM +#undef CONFIG_CMD_USBMUX +#undef CONFIG_CMD_TYPEC #endif /* diff --git a/common/flash.c b/common/flash.c index 36c4701264..3d6f579834 100644 --- a/common/flash.c +++ b/common/flash.c @@ -1286,6 +1286,28 @@ static int flash_command_protect(struct host_cmd_handler_args *args) return EC_RES_SUCCESS; } +enum flash_rw_slot flash_get_active_slot(void) +{ + uint8_t slot; + if (system_get_bbram(SYSTEM_BBRAM_IDX_TRY_SLOT, &slot)) + slot = FLASH_RW_SLOT_A; + return slot; +} + +enum flash_rw_slot flash_get_update_slot(void) +{ +#ifdef CONFIG_VBOOT_EFS + return 1 - flash_get_active_slot(); +#else + return FLASH_RW_SLOT_A; +#endif +} + +enum system_image_copy_t flash_slot_to_image(enum flash_rw_slot slot) +{ + return slot == FLASH_RW_SLOT_A ? SYSTEM_IMAGE_RW_A : SYSTEM_IMAGE_RW_B; +} + /* * TODO(crbug.com/239197) : Adding both versions to the version mask is a * temporary workaround for a problem in the cros_ec driver. Drop @@ -1307,10 +1329,9 @@ static int flash_command_region_info(struct host_cmd_handler_args *args) EC_FLASH_REGION_START; r->size = CONFIG_RO_SIZE; break; - case EC_FLASH_REGION_RW: - r->offset = CONFIG_EC_WRITABLE_STORAGE_OFF + - CONFIG_RW_STORAGE_OFF - - EC_FLASH_REGION_START; + case EC_FLASH_REGION_ACTIVE: + r->offset = flash_get_rw_offset(flash_get_active_slot()) - + EC_FLASH_REGION_START; r->size = CONFIG_RW_SIZE; break; case EC_FLASH_REGION_WP_RO: @@ -1318,6 +1339,11 @@ static int flash_command_region_info(struct host_cmd_handler_args *args) EC_FLASH_REGION_START; r->size = CONFIG_WP_STORAGE_SIZE; break; + case EC_FLASH_REGION_UPDATE: + r->offset = flash_get_rw_offset(flash_get_update_slot()) - + EC_FLASH_REGION_START; + r->size = CONFIG_RW_SIZE; + break; default: return EC_RES_INVALID_PARAM; } diff --git a/common/system.c b/common/system.c index 07d43da38b..62c036baf9 100644 --- a/common/system.c +++ b/common/system.c @@ -420,14 +420,19 @@ test_mockable int system_unsafe_to_overwrite(uint32_t offset, uint32_t size) r_size = CONFIG_RO_SIZE; break; case SYSTEM_IMAGE_RW: - r_offset = CONFIG_EC_WRITABLE_STORAGE_OFF + - CONFIG_RW_STORAGE_OFF; + r_offset = flash_get_rw_offset(FLASH_RW_SLOT_A); r_size = CONFIG_RW_SIZE; #ifdef CONFIG_RWSIG /* Allow RW sig to be overwritten */ r_size -= CONFIG_RW_SIG_SIZE; #endif break; +#ifdef CONFIG_VBOOT_EFS + case SYSTEM_IMAGE_RW_B: + r_offset = flash_get_rw_offset(FLASH_RW_SLOT_B); + r_size = CONFIG_RW_SIZE - CONFIG_RW_SIG_SIZE; + break; +#endif default: return 0; } @@ -614,6 +619,19 @@ int system_run_image_copy(enum system_image_copy_t copy) return EC_ERROR_UNKNOWN; } +/* + * This is defined in system.c instead of flash.c because it's called even + * on the boards which don't include flash.o. (e.g. hadoken, stm32l476g-eval) + */ +uint32_t flash_get_rw_offset(enum flash_rw_slot slot) +{ +#ifdef CONFIG_VBOOT_EFS + if (slot == FLASH_RW_SLOT_B) + return CONFIG_EC_WRITABLE_STORAGE_OFF + CONFIG_RW_B_STORAGE_OFF; +#endif + return CONFIG_EC_WRITABLE_STORAGE_OFF + CONFIG_RW_STORAGE_OFF; +} + static const struct image_data *system_get_image_data( enum system_image_copy_t copy) { @@ -639,9 +657,17 @@ static const struct image_data *system_get_image_data( * Read the version information from the proper location * on storage. */ - addr += (is_rw_image(copy)) ? - CONFIG_EC_WRITABLE_STORAGE_OFF + CONFIG_RW_STORAGE_OFF : - CONFIG_EC_PROTECTED_STORAGE_OFF + CONFIG_RO_STORAGE_OFF; + switch (copy) { + case SYSTEM_IMAGE_RW: + addr += flash_get_rw_offset(FLASH_RW_SLOT_A); + break; + case SYSTEM_IMAGE_RW_B: + addr += flash_get_rw_offset(FLASH_RW_SLOT_B); + break; + default: + addr += CONFIG_EC_PROTECTED_STORAGE_OFF + CONFIG_RO_STORAGE_OFF; + break; + } #ifdef CONFIG_MAPPED_STORAGE addr += CONFIG_MAPPED_STORAGE_BASE; @@ -1198,10 +1224,12 @@ DECLARE_CONSOLE_COMMAND(sysrq, command_sysrq, static int host_command_get_version(struct host_cmd_handler_args *args) { struct ec_response_get_version *r = args->response; + enum flash_rw_slot active_slot = flash_get_active_slot(); strzcpy(r->version_string_ro, system_get_version(SYSTEM_IMAGE_RO), sizeof(r->version_string_ro)); - strzcpy(r->version_string_rw, system_get_version(SYSTEM_IMAGE_RW), + strzcpy(r->version_string_rw, + system_get_version(flash_slot_to_image(active_slot)), sizeof(r->version_string_rw)); switch (system_get_image_copy()) { @@ -1209,6 +1237,7 @@ static int host_command_get_version(struct host_cmd_handler_args *args) r->current_image = EC_IMAGE_RO; break; case SYSTEM_IMAGE_RW: + case SYSTEM_IMAGE_RW_B: r->current_image = EC_IMAGE_RW; break; default: diff --git a/common/vboot_hash.c b/common/vboot_hash.c index 81d60725aa..fab56c1d0a 100644 --- a/common/vboot_hash.c +++ b/common/vboot_hash.c @@ -219,6 +219,18 @@ int vboot_hash_invalidate(int offset, int size) /*****************************************************************************/ /* Hooks */ +/** + * Returns the size of a RW copy to be hashed as expected by Softsync. + */ +static uint32_t get_rw_size(void) +{ +#ifdef CONFIG_VBOOT_EFS + return CONFIG_RW_SIZE; +#else + return system_get_image_used(SYSTEM_IMAGE_RW); +#endif +} + static void vboot_hash_init(void) { #ifdef CONFIG_SAVE_VBOOT_HASH @@ -249,10 +261,8 @@ static void vboot_hash_init(void) #endif { /* Start computing the hash of RW firmware */ - vboot_hash_start(CONFIG_EC_WRITABLE_STORAGE_OFF + - CONFIG_RW_STORAGE_OFF, - system_get_image_used(SYSTEM_IMAGE_RW), - NULL, 0); + vboot_hash_start(flash_get_rw_offset(flash_get_active_slot()), + get_rw_size(), NULL, 0); } } DECLARE_HOOK(HOOK_INIT, vboot_hash_init, HOOK_PRIO_INIT_VBOOT_HASH); @@ -279,6 +289,21 @@ DECLARE_HOOK(HOOK_SYSJUMP, vboot_hash_preserve_state, HOOK_PRIO_DEFAULT); #endif +/** + * Returns the offset of RO or RW image if the either region is specifically + * requested otherwise return the current hash offset. + */ +static int get_offset(int offset) +{ + if (offset == EC_VBOOT_HASH_OFFSET_RO) + return CONFIG_EC_PROTECTED_STORAGE_OFF + CONFIG_RO_STORAGE_OFF; + if (offset == EC_VBOOT_HASH_OFFSET_ACTIVE) + return flash_get_rw_offset(flash_get_active_slot()); + if (offset == EC_VBOOT_HASH_OFFSET_UPDATE) + return flash_get_rw_offset(flash_get_update_slot()); + return offset; +} + /****************************************************************************/ /* Console commands */ #ifdef CONFIG_CMD_HASH @@ -311,10 +336,8 @@ static int command_hash(int argc, char **argv) return EC_SUCCESS; } else if (!strcasecmp(argv[1], "rw")) { return vboot_hash_start( - CONFIG_EC_WRITABLE_STORAGE_OFF + - CONFIG_RW_STORAGE_OFF, - system_get_image_used(SYSTEM_IMAGE_RW), - NULL, 0); + get_offset(EC_VBOOT_HASH_OFFSET_ACTIVE), + get_rw_size(), NULL, 0); } else if (!strcasecmp(argv[1], "ro")) { return vboot_hash_start( CONFIG_EC_PROTECTED_STORAGE_OFF + @@ -352,19 +375,6 @@ DECLARE_CONSOLE_COMMAND(hash, command_hash, /****************************************************************************/ /* Host commands */ -/** - * Return the offset of the RO or RW region if the either region is specifically - * requested otherwise return the current hash offset. - */ -static int get_offset(int offset) -{ - if (offset == EC_VBOOT_HASH_OFFSET_RO) - return CONFIG_EC_PROTECTED_STORAGE_OFF + CONFIG_RO_STORAGE_OFF; - if (offset == EC_VBOOT_HASH_OFFSET_RW) - return CONFIG_EC_WRITABLE_STORAGE_OFF + CONFIG_RW_STORAGE_OFF; - return data_offset; -} - /* Fill in the response with the current hash status */ static void fill_response(struct ec_response_vboot_hash *r, int request_offset) @@ -403,14 +413,12 @@ static int host_start_hash(const struct ec_params_vboot_hash *p) return EC_RES_INVALID_PARAM; /* Handle special offset values */ - if (offset == EC_VBOOT_HASH_OFFSET_RO) { - offset = CONFIG_EC_PROTECTED_STORAGE_OFF + - CONFIG_RO_STORAGE_OFF; + if (offset == EC_VBOOT_HASH_OFFSET_RO) size = system_get_image_used(SYSTEM_IMAGE_RO); - } else if (p->offset == EC_VBOOT_HASH_OFFSET_RW) { - offset = CONFIG_EC_WRITABLE_STORAGE_OFF + CONFIG_RW_STORAGE_OFF; - size = system_get_image_used(SYSTEM_IMAGE_RW); - } + else if ((offset == EC_VBOOT_HASH_OFFSET_ACTIVE) || + (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); if (rv == EC_SUCCESS) diff --git a/include/ec_commands.h b/include/ec_commands.h index 223a25fcbe..3eab0a8354 100644 --- a/include/ec_commands.h +++ b/include/ec_commands.h @@ -1381,16 +1381,29 @@ struct __ec_align4 ec_response_flash_protect { enum ec_flash_region { /* Region which holds read-only EC image */ EC_FLASH_REGION_RO = 0, - /* Region which holds rewritable EC image */ - EC_FLASH_REGION_RW, + /* + * Region which holds active RW image. 'Active' is different from + * 'running'. Active means 'scheduled-to-run'. Since RO image always + * scheduled to run, active/non-active applies only to RW images (for + * the same reason 'update' applies only to RW images. It's a state of + * an image on a flash. Running image can be RO, RW_A, RW_B but active + * image can only be RW_A or RW_B. In recovery mode, an active RW image + * doesn't enter 'running' state but it's still active on a flash. + */ + EC_FLASH_REGION_ACTIVE, /* * Region which should be write-protected in the factory (a superset of * EC_FLASH_REGION_RO) */ EC_FLASH_REGION_WP_RO, + /* Region which holds updatable (non-active) RW image */ + EC_FLASH_REGION_UPDATE, /* Number of regions */ EC_FLASH_REGION_COUNT, }; +/* 'RW' is vague if there are multiple RW images; we mean the active one, + * so the old constant is deprecated */ +#define EC_FLASH_REGION_RW EC_FLASH_REGION_ACTIVE struct __ec_align4 ec_params_flash_region_info { uint32_t region; /* enum ec_flash_region */ @@ -1951,8 +1964,13 @@ enum ec_vboot_hash_status { * If one of these is specified, the EC will automatically update offset and * size to the correct values for the specified image (RO or RW). */ -#define EC_VBOOT_HASH_OFFSET_RO 0xfffffffe -#define EC_VBOOT_HASH_OFFSET_RW 0xfffffffd +#define EC_VBOOT_HASH_OFFSET_RO 0xfffffffe +#define EC_VBOOT_HASH_OFFSET_ACTIVE 0xfffffffd +#define EC_VBOOT_HASH_OFFSET_UPDATE 0xfffffffc + +/* 'RW' is vague if there are multiple RW images; we mean the active one, + * so the old constant is deprecated */ +#define EC_VBOOT_HASH_OFFSET_RW EC_VBOOT_HASH_OFFSET_ACTIVE /*****************************************************************************/ /* diff --git a/include/flash.h b/include/flash.h index c769f5753d..d52f1f7ce7 100644 --- a/include/flash.h +++ b/include/flash.h @@ -102,6 +102,31 @@ enum flash_region { FLASH_REGION_COUNT }; +/** + * Get active slot + * + * Active slot contains an image which is being executed or will be executed + * after sysjump. + * + * @return Active slot index + */ +enum flash_rw_slot flash_get_active_slot(void); + +/** + * Get updatable (non-active) slot + * + * @return Updatable slot index + */ +enum flash_rw_slot flash_get_update_slot(void); + +/** + * Translate slot index to image index + * + * @param slot Slot index to convert. + * @return Image index converted from <slot> + */ +enum system_image_copy_t flash_slot_to_image(enum flash_rw_slot slot); + /*****************************************************************************/ /* Low-level methods, for use by flash_common. */ diff --git a/include/system.h b/include/system.h index 2a229a68ef..d44cb315b1 100644 --- a/include/system.h +++ b/include/system.h @@ -42,6 +42,7 @@ enum system_image_copy_t { SYSTEM_IMAGE_UNKNOWN = 0, SYSTEM_IMAGE_RO, SYSTEM_IMAGE_RW, + SYSTEM_IMAGE_RW_A = SYSTEM_IMAGE_RW, /* Some systems may have these too */ SYSTEM_IMAGE_RO_B, SYSTEM_IMAGE_RW_B, @@ -561,4 +562,18 @@ static inline void system_print_extended_version_info(void) */ int system_can_boot_ap(void); +enum flash_rw_slot { + /* Must be 0 and 1 because they are converted by 1 - slot_x. */ + FLASH_RW_SLOT_A = 0, + FLASH_RW_SLOT_B = 1, +}; + +/** + * Get flash offset of a RW slot + * + * @param slot Slot index to get the flash offset of. + * @return Flash offset of the slot specified by <slot> + */ +uint32_t flash_get_rw_offset(enum flash_rw_slot slot); + #endif /* __CROS_EC_SYSTEM_H */ diff --git a/test/flash.c b/test/flash.c index b3bad5e984..3ee3384619 100644 --- a/test/flash.c +++ b/test/flash.c @@ -364,11 +364,14 @@ static int test_region_info(void) VERIFY_REGION_INFO(EC_FLASH_REGION_RO, CONFIG_EC_PROTECTED_STORAGE_OFF + CONFIG_RO_STORAGE_OFF, CONFIG_RO_SIZE); - VERIFY_REGION_INFO(EC_FLASH_REGION_RW, + VERIFY_REGION_INFO(EC_FLASH_REGION_ACTIVE, CONFIG_EC_WRITABLE_STORAGE_OFF + CONFIG_RW_STORAGE_OFF, CONFIG_RW_SIZE); VERIFY_REGION_INFO(EC_FLASH_REGION_WP_RO, CONFIG_WP_STORAGE_OFF, CONFIG_WP_STORAGE_SIZE); + VERIFY_REGION_INFO(EC_FLASH_REGION_UPDATE, + CONFIG_EC_WRITABLE_STORAGE_OFF + + CONFIG_RW_STORAGE_OFF, CONFIG_RW_SIZE); return EC_SUCCESS; } diff --git a/util/ectool.c b/util/ectool.c index 449e4ec818..89b3b6e028 100644 --- a/util/ectool.c +++ b/util/ectool.c @@ -6232,7 +6232,7 @@ int cmd_ec_hash(int argc, char *argv[]) p.size = 0; printf("Hashing EC-RO...\n"); } else if (!strcasecmp(argv[2], "rw")) { - p.offset = EC_VBOOT_HASH_OFFSET_RW; + p.offset = EC_VBOOT_HASH_OFFSET_ACTIVE; p.size = 0; printf("Hashing EC-RW...\n"); } else if (argc < 4) { |