diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/2lib/2misc.c | 44 | ||||
-rw-r--r-- | firmware/2lib/include/2api.h | 20 |
2 files changed, 58 insertions, 6 deletions
diff --git a/firmware/2lib/2misc.c b/firmware/2lib/2misc.c index c14aab55..92a3452e 100644 --- a/firmware/2lib/2misc.c +++ b/firmware/2lib/2misc.c @@ -82,17 +82,31 @@ vb2_error_t vb2_read_gbb_header(struct vb2_context *ctx, return VB2_SUCCESS; } -test_mockable -void vb2api_fail(struct vb2_context *ctx, uint8_t reason, uint8_t subcode) +static void fail_impl(struct vb2_context *ctx, + uint8_t reason, uint8_t subcode, bool previous_boot) { struct vb2_shared_data *sd = vb2_get_sd(ctx); + uint32_t last_fw_slot, last_fw_result, fw_slot; /* If NV data hasn't been initialized, initialize it now */ if (!(sd->status & VB2_SD_STATUS_NV_INIT)) vb2_nv_init(ctx); + /* + * Donot overwrite any existing failure with a new failure reported + * through vb2api_previous_boot_fail(). Existing failure might have + * been set through vb2api_fail() in the previous boot and the new + * failure can stand. + */ + if (previous_boot && + vb2_nv_get(ctx, VB2_NV_FW_RESULT) == VB2_FW_RESULT_FAILURE) + return; + /* See if we were far enough in the boot process to choose a slot */ - if (sd->status & VB2_SD_STATUS_CHOSE_SLOT) { + if (previous_boot || (sd->status & VB2_SD_STATUS_CHOSE_SLOT)) { + last_fw_slot = vb2_nv_get(ctx, VB2_NV_FW_PREV_TRIED); + last_fw_result = vb2_nv_get(ctx, VB2_NV_FW_PREV_RESULT); + fw_slot = vb2_nv_get(ctx, VB2_NV_FW_TRIED); /* Boot failed */ vb2_nv_set(ctx, VB2_NV_FW_RESULT, VB2_FW_RESULT_FAILURE); @@ -105,14 +119,14 @@ void vb2api_fail(struct vb2_context *ctx, uint8_t reason, uint8_t subcode) * between slots, which may help if one or both slots is * flaky. */ - vb2_nv_set(ctx, VB2_NV_TRY_NEXT, 1 - sd->fw_slot); + vb2_nv_set(ctx, VB2_NV_TRY_NEXT, 1 - fw_slot); /* * If we didn't try the other slot last boot, or we tried it * and it didn't fail, try it next boot. */ - if (sd->last_fw_slot != 1 - sd->fw_slot || - sd->last_fw_result != VB2_FW_RESULT_FAILURE) + if (last_fw_slot != 1 - fw_slot || + last_fw_result != VB2_FW_RESULT_FAILURE) return; } @@ -132,6 +146,24 @@ void vb2api_fail(struct vb2_context *ctx, uint8_t reason, uint8_t subcode) } } +test_mockable +void vb2api_fail(struct vb2_context *ctx, uint8_t reason, uint8_t subcode) +{ + fail_impl(ctx, reason, subcode, false); +} + +test_mockable +void vb2api_previous_boot_fail(struct vb2_context *ctx, + uint8_t reason, uint8_t subcode) +{ + struct vb2_shared_data *sd = vb2_get_sd(ctx); + + VB2_ASSERT(!(sd->status & VB2_SD_STATUS_NV_INIT) && + !(sd->status & VB2_SD_STATUS_CHOSE_SLOT)); + + fail_impl(ctx, reason, subcode, true); +} + void vb2_check_recovery(struct vb2_context *ctx) { struct vb2_shared_data *sd = vb2_get_sd(ctx); diff --git a/firmware/2lib/include/2api.h b/firmware/2lib/include/2api.h index 643bc986..dd8af7b3 100644 --- a/firmware/2lib/include/2api.h +++ b/firmware/2lib/include/2api.h @@ -404,6 +404,26 @@ vb2_error_t vb2api_secdata_fwmp_check(struct vb2_context *ctx, uint8_t *size); void vb2api_fail(struct vb2_context *ctx, uint8_t reason, uint8_t subcode); /** + * Report firmware failure from previous boot to vboot. + * + * This function can only be called before vb2api_fw_phase1 (nvdata is + * initialized). Otherwise an assert is raised. This function is required to be + * called in the following environment: + * - Context has to be initialized using vb2api_init + * - NV data has to be read into context + * - Secdata may or may not have been read + * - vb2api_fw_phase1 must not have been called. + * + * If the other slot is not known bad then try the other firmware slot. + * If both the slots are known bad, then request recovery. + * + * @param reason Recovery reason + * @param subcode Recovery subcode + */ +void vb2api_previous_boot_fail(struct vb2_context *ctx, + uint8_t reason, uint8_t subcode); + +/** * Entry point for setting up a context that can only load and verify a kernel. * * The only allowed usage is to call vb2api_init, then this entry point, |