summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--firmware/include/vboot_api.h17
-rw-r--r--firmware/include/vboot_struct.h2
-rw-r--r--firmware/lib/ec_sync.c57
-rw-r--r--firmware/lib/ec_sync_all.c11
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;