diff options
-rw-r--r-- | firmware/include/vboot_api.h | 17 | ||||
-rw-r--r-- | firmware/include/vboot_struct.h | 2 | ||||
-rw-r--r-- | firmware/lib/ec_sync.c | 57 | ||||
-rw-r--r-- | firmware/lib/ec_sync_all.c | 11 |
4 files changed, 59 insertions, 28 deletions
diff --git a/firmware/include/vboot_api.h b/firmware/include/vboot_api.h index ccd65961..3df025e2 100644 --- a/firmware/include/vboot_api.h +++ b/firmware/include/vboot_api.h @@ -108,6 +108,8 @@ enum VbErrorPredefined_t { VBERROR_NO_SOUND = 0x10018, /* VbExBeep() can't make sound in the background */ VBERROR_NO_BACKGROUND_SOUND = 0x10019, + /* Need EC to reboot to read-only code to switch RW slot */ + VBERROR_EC_REBOOT_TO_SWITCH_RW = 0x1001A, /* Developer has requested a BIOS shell */ VBERROR_BIOS_SHELL_REQUESTED = 0x10020, /* Need VGA and don't have it, or vice-versa */ @@ -303,12 +305,17 @@ typedef struct VbInitParams { enum VbSelectFirmware_t { /* Recovery mode */ VB_SELECT_FIRMWARE_RECOVERY = 0, - /* Rewritable firmware A/B for normal or developer path */ + /* DEPRECATED: Rewritable firmware A/B for normal or developer path */ VB_SELECT_FIRMWARE_A = 1, VB_SELECT_FIRMWARE_B = 2, /* Read only firmware for normal or developer path. */ VB_SELECT_FIRMWARE_READONLY = 3, - VB_SELECT_FIRMWARE_COUNT, + /* Rewritable EC firmware currently set active */ + VB_SELECT_FIRMWARE_EC_ACTIVE = 4, + /* Rewritable EC firmware currently not set active thus updatable */ + VB_SELECT_FIRMWARE_EC_UPDATE = 5, + /* Keep this at the end */ + VB_SELECT_FIRMWARE_COUNT, }; /* Data only used by VbSelectFirmware() */ @@ -961,6 +968,12 @@ VbError_t VbExEcDisableJump(int devidx); /** * Read the SHA-256 hash of the selected EC image. + * + * @param devidx Device index. 0: EC, 1: PD. + * @param select Image to get hash of. RO or RW. + * @param hash Pointer to the hash. + * @param hash_size Pointer to the hash size. + * @return VBERROR_... error, VBERROR_SUCCESS on success. */ VbError_t VbExEcHashImage(int devidx, enum VbSelectFirmware_t select, const uint8_t **hash, int *hash_size); diff --git a/firmware/include/vboot_struct.h b/firmware/include/vboot_struct.h index 08910d13..3f0d888c 100644 --- a/firmware/include/vboot_struct.h +++ b/firmware/include/vboot_struct.h @@ -241,6 +241,8 @@ typedef struct VbKernelPreambleHeader { #define VBSD_OPROM_LOADED 0x00020000 /* Don't try for boot failures */ #define VBSD_NOFAIL_BOOT 0x00040000 +/* VbInit() was told that the EC firmware supports EFS */ +#define VBSD_EC_EFS 0x00080000 /* * Supported flags by header version. It's ok to add new flags while keeping diff --git a/firmware/lib/ec_sync.c b/firmware/lib/ec_sync.c index 3f90ba5f..10ce5576 100644 --- a/firmware/lib/ec_sync.c +++ b/firmware/lib/ec_sync.c @@ -31,6 +31,9 @@ ((select) == VB_SELECT_FIRMWARE_READONLY ? VB2_SD_FLAG_ECSYNC_EC_RO : \ ((devidx) ? VB2_SD_FLAG_ECSYNC_PD_RW : VB2_SD_FLAG_ECSYNC_EC_RW)) +/* PD doesn't support RW A/B */ +#define RW_AB(devidx) ((devidx) ? 0 : VBSD_EC_EFS) + static void request_recovery(struct vb2_context *ctx, uint32_t recovery_request) { VB2_DEBUG("request_recovery(%u)\n", recovery_request); @@ -73,6 +76,20 @@ static void print_hash(const uint8_t *hash, uint32_t hash_size, VB2_DEBUG_RAW("\n"); } +static const char *image_name_to_string(enum VbSelectFirmware_t select) +{ + switch (select) { + case VB_SELECT_FIRMWARE_READONLY: + return "RO"; + case VB_SELECT_FIRMWARE_EC_ACTIVE: + return "RW(active)"; + case VB_SELECT_FIRMWARE_EC_UPDATE: + return "RW(update)"; + default: + return "UNKNOWN"; + } +} + /** * Check if the hash of the EC code matches the expected hash. * @@ -95,8 +112,7 @@ static int check_ec_hash(struct vb2_context *ctx, int devidx, request_recovery(ctx, VB2_RECOVERY_EC_HASH_FAILED); return VB2_ERROR_EC_HASH_IMAGE; } - print_hash(ec_hash, ec_hash_size, - select == VB_SELECT_FIRMWARE_READONLY ? "RO" : "RW"); + print_hash(ec_hash, ec_hash_size, image_name_to_string(select)); /* Get expected EC hash. */ const uint8_t *hash = NULL; @@ -135,8 +151,7 @@ static VbError_t update_ec(struct vb2_context *ctx, int devidx, { struct vb2_shared_data *sd = vb2_get_sd(ctx); - VB2_DEBUG("updating %s...\n", - select == VB_SELECT_FIRMWARE_READONLY ? "RO" : "RW"); + VB2_DEBUG("Updating %s...\n", image_name_to_string(select)); /* Get expected EC image */ const uint8_t *want = NULL; @@ -252,17 +267,24 @@ static VbError_t sync_one_ec(struct vb2_context *ctx, int devidx, VbSharedDataHeader *shared = (VbSharedDataHeader *)cparams->shared_data_blob; struct vb2_shared_data *sd = vb2_get_sd(ctx); - const enum VbSelectFirmware_t select_rw = - shared->firmware_index ? VB_SELECT_FIRMWARE_B : - VB_SELECT_FIRMWARE_A; + int is_rw_ab = shared->flags & RW_AB(devidx); int rv; - VB2_DEBUG("devidx=%d\n", devidx); + const enum VbSelectFirmware_t select_rw = is_rw_ab ? + VB_SELECT_FIRMWARE_EC_UPDATE : + VB_SELECT_FIRMWARE_EC_ACTIVE; + VB2_DEBUG("devidx=%d select_rw=%d\n", devidx, select_rw); /* Update the RW Image */ - if (sd->flags & VB2_SD_FLAG_ECSYNC_RW) { + if (sd->flags & WHICH_EC(devidx, select_rw)) { if (VB2_SUCCESS != update_ec(ctx, devidx, select_rw)) return VBERROR_EC_REBOOT_TO_RO_REQUIRED; + /* Updated successfully. Cold reboot to switch to the new RW. + * TODO: Switch slot and proceed if EC is still in RO. */ + if (is_rw_ab) { + VB2_DEBUG("Rebooting to jump to new EC-RW\n"); + return VBERROR_EC_REBOOT_TO_SWITCH_RW; + } } /* Tell EC to jump to its RW image */ @@ -374,13 +396,10 @@ VbError_t ec_sync_phase1(struct vb2_context *ctx, VbCommonParams *cparams) if (sd->recovery_reason) return VBERROR_SUCCESS; - /* See if we need to update RW. Failures trigger recovery mode. */ - const enum VbSelectFirmware_t select_rw = - shared->firmware_index ? VB_SELECT_FIRMWARE_B : - VB_SELECT_FIRMWARE_A; - if (check_ec_hash(ctx, 0, select_rw)) + /* Check if we need to update RW. Failures trigger recovery mode. */ + if (check_ec_hash(ctx, 0, VB_SELECT_FIRMWARE_EC_ACTIVE)) return VBERROR_EC_REBOOT_TO_RO_REQUIRED; - if (do_pd_sync && check_ec_hash(ctx, 1, select_rw)) + if (do_pd_sync && check_ec_hash(ctx, 1, VB_SELECT_FIRMWARE_EC_ACTIVE)) return VBERROR_EC_REBOOT_TO_RO_REQUIRED; /* * See if we need to update EC-RO (devidx=0). @@ -399,12 +418,12 @@ VbError_t ec_sync_phase1(struct vb2_context *ctx, VbCommonParams *cparams) * If we're in RW, we need to reboot back to RO because RW can't be * updated while we're running it. * - * TODO: Technically this isn't true for ECs which don't execute from - * flash. For example, if the EC loads code from SPI into RAM before - * executing it. + * If EC supports RW-A/B slots, we can proceed but we need + * to jump to the new RW version later. */ if ((sd->flags & VB2_SD_FLAG_ECSYNC_RW) && - (sd->flags & VB2_SD_FLAG_ECSYNC_IN_RW)) { + (sd->flags & VB2_SD_FLAG_ECSYNC_IN_RW) && + !(shared->flags & VBSD_EC_EFS)) { return VBERROR_EC_REBOOT_TO_RO_REQUIRED; } diff --git a/firmware/lib/ec_sync_all.c b/firmware/lib/ec_sync_all.c index aeec6079..1d9c7f71 100644 --- a/firmware/lib/ec_sync_all.c +++ b/firmware/lib/ec_sync_all.c @@ -28,7 +28,7 @@ VbError_t ec_sync_all(struct vb2_context *ctx, struct VbCommonParams *cparams) if (rv) return rv; - /* Do EC sync phase 1; this determines if we need an update */ + /* Phase 1; this determines if we need an update */ VbError_t phase1_rv = ec_sync_phase1(ctx, cparams); int need_wait_screen = ec_will_update_slowly(ctx, cparams) || (fw_update == VB_AUX_FW_SLOW_UPDATE); @@ -60,16 +60,13 @@ VbError_t ec_sync_all(struct vb2_context *ctx, struct VbCommonParams *cparams) VbDisplayScreen(ctx, cparams, VB_SCREEN_WAIT, 0); } - /* - * Do EC sync phase 2; this applies the update and/or jumps to the - * correct EC image. - */ + /* Phase 2; Applies update and/or jumps to the correct EC image */ rv = ec_sync_phase2(ctx, cparams); if (rv) return rv; /* - * Do software sync for devices tunneled throught the EC. + * Do software sync for devices tunneled through the EC. */ rv = VbExUpdateAuxFw(); if (rv) @@ -91,7 +88,7 @@ VbError_t ec_sync_all(struct vb2_context *ctx, struct VbCommonParams *cparams) return VBERROR_VGA_OPROM_MISMATCH; } - /* Do EC sync phase 3; this completes sync and handles battery cutoff */ + /* Phase 3; Completes sync and handles battery cutoff */ rv = ec_sync_phase3(ctx, cparams); if (rv) return rv; |