Save recovery reason before user three-finger-salutes
authorDaisuke Nojiri <dnojiri@chromium.org>
Wed, 21 Oct 2015 01:31:10 +0000 (18:31 -0700)
committerchrome-bot <chrome-bot@chromium.org>
Mon, 26 Oct 2015 18:24:18 +0000 (11:24 -0700)
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 <dnojiri@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/307586
Reviewed-by: Randall Spangler <rspangler@chromium.org>
firmware/2lib/2misc.c
firmware/lib/vboot_api_kernel.c

index a856775..a955f53 100644 (file)
@@ -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;
        }
 
index 7b47dc6..fcec4cb 100644 (file)
@@ -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__));