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
This commit is contained in:
Daisuke Nojiri
2017-08-15 16:34:52 -07:00
committed by chrome-bot
parent a52cfbc80c
commit 4dcee1c545
9 changed files with 170 additions and 44 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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