summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--firmware/lib/ec_sync.c29
-rw-r--r--firmware/lib/vboot_common.c7
-rw-r--r--firmware/lib/vboot_ui.c4
-rw-r--r--firmware/lib/vboot_ui_menu.c4
-rw-r--r--tests/ec_sync_tests.c15
5 files changed, 47 insertions, 12 deletions
diff --git a/firmware/lib/ec_sync.c b/firmware/lib/ec_sync.c
index baf3cfc2..35fae2de 100644
--- a/firmware/lib/ec_sync.c
+++ b/firmware/lib/ec_sync.c
@@ -202,11 +202,29 @@ static VbError_t update_ec(struct vb2_context *ctx, int devidx,
* @param ctx Vboot2 context
* @param devidx Which device (EC=0, PD=1)
*/
-static void check_ec_active(struct vb2_context *ctx, int devidx)
+static VbError_t check_ec_active(struct vb2_context *ctx, int devidx)
{
struct vb2_shared_data *sd = vb2_get_sd(ctx);
- if (!VbExTrustEC(devidx))
+ int in_rw = 0;
+ /*
+ * We don't use VbExTrustEC, which checks EC_IN_RW. It is controlled by
+ * cr50 but on some platforms, cr50 can't know when a EC resets. So, we
+ * trust what EC-RW says. If it lies it's in RO, we'll flash RW while
+ * it's in RW.
+ */
+ int rv = VbExEcRunningRW(devidx, &in_rw);
+
+ /* If we couldn't determine where the EC was, reboot to recovery. */
+ if (rv != VBERROR_SUCCESS) {
+ VB2_DEBUG("VbExEcRunningRW() returned %d\n", rv);
+ request_recovery(ctx, VB2_RECOVERY_EC_UNKNOWN_IMAGE);
+ return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
+ }
+
+ if (in_rw)
sd->flags |= IN_RW(devidx);
+
+ return VBERROR_SUCCESS;
}
#define RO_RETRIES 2 /* Maximum times to retry flashing RO */
@@ -341,9 +359,10 @@ VbError_t ec_sync_phase1(struct vb2_context *ctx, VbCommonParams *cparams)
#endif
/* Set IN_RW flags */
- check_ec_active(ctx, 0);
- if (do_pd_sync)
- check_ec_active(ctx, 1);
+ if (check_ec_active(ctx, 0))
+ return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
+ if (do_pd_sync && check_ec_active(ctx, 1))
+ return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
/* Check if we need to update RW. Failures trigger recovery mode. */
if (check_ec_hash(ctx, 0, VB_SELECT_FIRMWARE_EC_ACTIVE))
diff --git a/firmware/lib/vboot_common.c b/firmware/lib/vboot_common.c
index 1c826667..60483b2c 100644
--- a/firmware/lib/vboot_common.c
+++ b/firmware/lib/vboot_common.c
@@ -217,7 +217,12 @@ int vb2_allow_recovery(uint32_t flags)
if (flags & VBSD_BOOT_DEV_SWITCH_ON)
return 1;
- /* If EC is in RW, it implies recovery wasn't manually requested. */
+ /*
+ * If EC is in RW, it implies recovery wasn't manually requested.
+ * On some platforms, EC_IN_RW can't be reset by the EC, thus, this may
+ * return false (=RW). That's ok because if recovery is manual, we will
+ * get the right signal and that's the case we care about.
+ */
if (!VbExTrustEC(0))
return 0;
diff --git a/firmware/lib/vboot_ui.c b/firmware/lib/vboot_ui.c
index c3a3e9e9..a99945e5 100644
--- a/firmware/lib/vboot_ui.c
+++ b/firmware/lib/vboot_ui.c
@@ -488,13 +488,11 @@ static VbError_t recovery_ui(struct vb2_context *ctx, VbCommonParams *cparams)
* - we can honor the virtual dev switch
* - not already in dev mode
* - user forced recovery mode
- * - EC isn't pwned
*/
if (key == 0x04 &&
shared->flags & VBSD_HONOR_VIRT_DEV_SWITCH &&
!(shared->flags & VBSD_BOOT_DEV_SWITCH_ON) &&
- (shared->flags & VBSD_BOOT_REC_SWITCH_ON) &&
- VbExTrustEC(0)) {
+ (shared->flags & VBSD_BOOT_REC_SWITCH_ON)) {
if (!(shared->flags &
VBSD_BOOT_REC_SWITCH_VIRTUAL) &&
VbExGetSwitches(
diff --git a/firmware/lib/vboot_ui_menu.c b/firmware/lib/vboot_ui_menu.c
index 82ef4220..2e3b17b7 100644
--- a/firmware/lib/vboot_ui_menu.c
+++ b/firmware/lib/vboot_ui_menu.c
@@ -1213,14 +1213,12 @@ static VbError_t recovery_ui(struct vb2_context *ctx, VbCommonParams *cparams)
* - we can honor the virtual dev switch
* - not already in dev mode
* - user forced recovery mode
- * - EC isn't pwned
*/
if (current_menu == VB_MENU_TO_DEV &&
current_menu_idx == 0 &&
shared->flags & VBSD_HONOR_VIRT_DEV_SWITCH &&
!(shared->flags & VBSD_BOOT_DEV_SWITCH_ON) &&
- (shared->flags & VBSD_BOOT_REC_SWITCH_ON) &&
- VbExTrustEC(0)) {
+ (shared->flags & VBSD_BOOT_REC_SWITCH_ON)) {
if (!(shared->flags &
VBSD_BOOT_REC_SWITCH_VIRTUAL) &&
VbExGetSwitches(
diff --git a/tests/ec_sync_tests.c b/tests/ec_sync_tests.c
index 56f3baae..1d5f8c1b 100644
--- a/tests/ec_sync_tests.c
+++ b/tests/ec_sync_tests.c
@@ -33,6 +33,7 @@ static VbSharedDataHeader *shared = (VbSharedDataHeader *)shared_data;
static GoogleBinaryBlockHeader gbb;
static int mock_in_rw;
+static VbError_t in_rw_retval;
static int protect_retval;
static int ec_ro_protected;
static int ec_rw_protected;
@@ -94,6 +95,7 @@ static void ResetMocks(void)
ec_run_image = 0; /* 0 = RO, 1 = RW */
ec_ro_updated = 0;
ec_rw_updated = 0;
+ in_rw_retval = VBERROR_SUCCESS;
protect_retval = VBERROR_SUCCESS;
update_retval = VBERROR_SUCCESS;
run_retval = VBERROR_SUCCESS;
@@ -142,6 +144,12 @@ int VbExTrustEC(int devidx)
return !mock_in_rw;
}
+VbError_t VbExEcRunningRW(int devidx, int *in_rw)
+{
+ *in_rw = mock_in_rw;
+ return in_rw_retval;
+}
+
VbError_t VbExEcProtect(int devidx, enum VbSelectFirmware_t select)
{
if (select == VB_SELECT_FIRMWARE_READONLY)
@@ -159,6 +167,7 @@ VbError_t VbExEcDisableJump(int devidx)
VbError_t VbExEcJumpToRW(int devidx)
{
ec_run_image = 1;
+ mock_in_rw = 1;
return run_retval;
}
@@ -237,6 +246,12 @@ static void test_ssync(VbError_t retval, int recovery_reason, const char *desc)
static void VbSoftwareSyncTest(void)
{
+ /* AP-RO cases */
+ ResetMocks();
+ in_rw_retval = VBERROR_SIMULATED;
+ test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
+ VBNV_RECOVERY_EC_UNKNOWN_IMAGE, "Unknown EC image");
+
/* Calculate hashes */
ResetMocks();
mock_ec_rw_hash_size = 0;