From 3a631486bddaeab1e8cc2abe0fb725721f2a0be0 Mon Sep 17 00:00:00 2001 From: Daisuke Nojiri Date: Tue, 20 Oct 2015 18:31:10 -0700 Subject: Save recovery reason before user three-finger-salutes When a user hits esc+refresh+power to start recovery, the true recovery reason will be lost after reboot. (It would always look like VB2_RECOVERY_RO_MANUAL.) This patch makes VbBootRecovery save the reason in the subcode area before entering the new 'broken' loop. BUG=chromium:501060 BRANCH=tot TEST=test_that -b veyron_jerry suite:faft_bios Change-Id: Ib536daa0633721bfc975381782d348f122b3d337 Signed-off-by: Daisuke Nojiri Reviewed-on: https://chromium-review.googlesource.com/307586 Reviewed-by: Randall Spangler --- firmware/2lib/2misc.c | 35 ++++++++++++++++++++--------------- firmware/lib/vboot_api_kernel.c | 35 ++++++++++++++++++++++++++++------- 2 files changed, 48 insertions(+), 22 deletions(-) diff --git a/firmware/2lib/2misc.c b/firmware/2lib/2misc.c index a8567758..a955f536 100644 --- a/firmware/2lib/2misc.c +++ b/firmware/2lib/2misc.c @@ -139,29 +139,34 @@ int vb2_init_context(struct vb2_context *ctx) void vb2_check_recovery(struct vb2_context *ctx) { struct vb2_shared_data *sd = vb2_get_sd(ctx); + uint32_t reason = vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST); + uint32_t subcode = vb2_nv_get(ctx, VB2_NV_RECOVERY_SUBCODE); + + VB2_DEBUG("Recovery reason from previous boot: %#x / %#x\n", + reason, subcode); /* - * Read the current recovery request, unless there's already been a + * Sets the current recovery request, unless there's already been a * failure earlier in the boot process. */ if (!sd->recovery_reason) - sd->recovery_reason = vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST); + sd->recovery_reason = reason; - /* Clear the recovery request so we don't get stuck in recovery mode */ - if (sd->recovery_reason) { - vb2_nv_set(ctx, VB2_NV_RECOVERY_REQUEST, - VB2_RECOVERY_NOT_REQUESTED); - /* - * Note that we ignore failures clearing the request. We only - * hit this code path if recovery mode has already been - * requested, so what more can we do? Don't want to obscure - * the original reason for going into recovery mode. - */ - } + /* Clear request and subcode so we don't get stuck in recovery mode */ + vb2_nv_set(ctx, VB2_NV_RECOVERY_REQUEST, VB2_RECOVERY_NOT_REQUESTED); + vb2_nv_set(ctx, VB2_NV_RECOVERY_SUBCODE, VB2_RECOVERY_NOT_REQUESTED); - /* If forcing recovery, override recovery reason */ if (ctx->flags & VB2_CONTEXT_FORCE_RECOVERY_MODE) { - sd->recovery_reason = VB2_RECOVERY_RO_MANUAL; + VB2_DEBUG("Recovery was requested manually\n"); + if (subcode && !sd->recovery_reason) + /* + * Recovery was requested at 'broken' screen. + * Promote subcode to reason. + */ + sd->recovery_reason = subcode; + else + /* Recovery was forced. Override recovery reason */ + sd->recovery_reason = VB2_RECOVERY_RO_MANUAL; sd->flags |= VB2_SD_FLAG_MANUAL_RECOVERY; } diff --git a/firmware/lib/vboot_api_kernel.c b/firmware/lib/vboot_api_kernel.c index 7b47dc69..fcec4cb7 100644 --- a/firmware/lib/vboot_api_kernel.c +++ b/firmware/lib/vboot_api_kernel.c @@ -41,6 +41,19 @@ static void VbSetRecoveryRequest(uint32_t recovery_request) VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, recovery_request); } +static void VbSetRecoverySubcode(uint32_t recovery_request) +{ + VBDEBUG(("VbSetRecoverySubcode(%d)\n", (int)recovery_request)); + VbNvSet(&vnc, VBNV_RECOVERY_SUBCODE, recovery_request); +} + +static void VbNvCommit(void) +{ + VbNvTeardown(&vnc); + if (vnc.raw_changed) + VbExNvStorageWrite(vnc.raw); +} + static void VbAllowUsbBoot(void) { VBDEBUG(("%s\n", __func__)); @@ -500,8 +513,20 @@ VbError_t VbBootRecovery(VbCommonParams *cparams, LoadKernelParams *p) */ if (!(shared->flags & VBSD_BOOT_DEV_SWITCH_ON) && !(shared->flags & VBSD_BOOT_REC_SWITCH_ON)) { - VBDEBUG(("VbBootRecovery() waiting for manual recovery\n")); + /* + * We have to save the reason here so that it will survive + * coming up three-finger-salute. We're saving it in + * VBNV_RECOVERY_SUBCODE to avoid a recovery loop. + * If we save the reason in VBNV_RECOVERY_REQUEST, we will come + * back here, thus, we won't be able to give a user a chance to + * reboot to workaround boot hicups. + */ + VBDEBUG(("VbBootRecovery() saving recovery reason (%#x)\n", + shared->recovery_reason)); + VbSetRecoverySubcode(shared->recovery_reason); + VbNvCommit(); VbDisplayScreen(cparams, VB_SCREEN_OS_BROKEN, 0, &vnc); + VBDEBUG(("VbBootRecovery() waiting for manual recovery\n")); while (1) { VbCheckDisplayKey(cparams, VbExKeyboardRead(), &vnc); if (VbWantShutdown(cparams->gbb->flags)) @@ -1171,9 +1196,7 @@ VbError_t VbSelectAndLoadKernel(VbCommonParams *cparams, VbApiKernelFree(cparams); - VbNvTeardown(&vnc); - if (vnc.raw_changed) - VbExNvStorageWrite(vnc.raw); + VbNvCommit(); /* Stop timer */ shared->timer_vb_select_and_load_kernel_exit = VbExGetTimer(); @@ -1343,9 +1366,7 @@ VbError_t VbLockDevice(void) VbNvSet(&vnc, VBNV_DISABLE_DEV_REQUEST, 1); - VbNvTeardown(&vnc); - if (vnc.raw_changed) - VbExNvStorageWrite(vnc.raw); + VbNvCommit(); VBDEBUG(("%s() Mode change will take effect on next reboot.\n", __func__)); -- cgit v1.2.1