summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile1
-rw-r--r--firmware/lib/include/vboot_kernel.h10
-rw-r--r--firmware/lib/vboot_ui_menu.c814
3 files changed, 825 insertions, 0 deletions
diff --git a/Makefile b/Makefile
index 29cba202..3ce74c11 100644
--- a/Makefile
+++ b/Makefile
@@ -340,6 +340,7 @@ VBSLK_SRCS = \
firmware/lib/vboot_display.c \
firmware/lib/vboot_kernel.c \
firmware/lib/vboot_ui.c \
+ firmware/lib/vboot_ui_menu.c \
firmware/lib/region-kernel.c \
# Code common to both vboot 2.0 (old structs) and 2.1 (new structs)
diff --git a/firmware/lib/include/vboot_kernel.h b/firmware/lib/include/vboot_kernel.h
index f117fa77..2195e0cf 100644
--- a/firmware/lib/include/vboot_kernel.h
+++ b/firmware/lib/include/vboot_kernel.h
@@ -73,6 +73,16 @@ VbError_t VbBootDeveloper(struct vb2_context *ctx, VbCommonParams *cparams);
VbError_t VbBootRecovery(struct vb2_context *ctx, VbCommonParams *cparams);
/**
+ * Handle a developer-mode boot using detachable menu ui
+ */
+VbError_t VbBootDeveloperMenu(struct vb2_context *ctx, VbCommonParams *cparams);
+
+/**
+ * Handle a recovery-mode boot using detachable menu ui
+ */
+VbError_t VbBootRecoveryMenu(struct vb2_context *ctx, VbCommonParams *cparams);
+
+/**
* Return the current FWMP flags. Valid only inside VbSelectAndLoadKernel().
*/
uint32_t vb2_get_fwmp_flags(void);
diff --git a/firmware/lib/vboot_ui_menu.c b/firmware/lib/vboot_ui_menu.c
new file mode 100644
index 00000000..7fa44edd
--- /dev/null
+++ b/firmware/lib/vboot_ui_menu.c
@@ -0,0 +1,814 @@
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * High-level firmware wrapper API - user interface for RW firmware
+ */
+
+#include "2sysincludes.h"
+#include "2common.h"
+#include "2misc.h"
+#include "2nvstorage.h"
+#include "2rsa.h"
+#include "ec_sync.h"
+#include "gbb_access.h"
+#include "gbb_header.h"
+#include "load_kernel_fw.h"
+#include "region.h"
+#include "rollback_index.h"
+#include "utility.h"
+#include "vb2_common.h"
+#include "vboot_api.h"
+#include "vboot_audio.h"
+#include "vboot_common.h"
+#include "vboot_display.h"
+#include "vboot_kernel.h"
+#include "vboot_nvstorage.h"
+
+static void VbAllowUsbBootMenu(struct vb2_context *ctx)
+{
+ VB2_DEBUG("%s\n", __func__);
+ vb2_nv_set(ctx, VB2_NV_DEV_BOOT_USB, 1);
+}
+
+/**
+ * Checks GBB flags against VbExIsShutdownRequested() shutdown request to
+ * determine if a shutdown is required.
+ *
+ * Returns true if a shutdown is required and false if no shutdown is required.
+ */
+static int VbWantShutdownMenu(uint32_t gbb_flags)
+{
+ uint32_t shutdown_request = VbExIsShutdownRequested();
+
+ /* If desired, ignore shutdown request due to lid closure. */
+ if (gbb_flags & GBB_FLAG_DISABLE_LID_SHUTDOWN)
+ shutdown_request &= ~VB_SHUTDOWN_REQUEST_LID_CLOSED;
+
+ return !!shutdown_request;
+}
+
+static void VbTryLegacyMenu(int allowed)
+{
+ if (!allowed)
+ VB2_DEBUG("VbBootDeveloperMenu() - Legacy boot is disabled\n");
+ else if (0 != RollbackKernelLock(0))
+ VB2_DEBUG("Error locking kernel versions on legacy boot.\n");
+ else
+ VbExLegacy(); /* will not return if successful */
+
+ /* If legacy boot fails, beep and return to calling UI loop. */
+ VbExBeep(120, 400);
+ VbExSleepMs(120);
+ VbExBeep(120, 400);
+}
+
+uint32_t VbTryUsbMenu(struct vb2_context *ctx, VbCommonParams *cparams)
+{
+ uint32_t retval = VbTryLoadKernel(ctx, cparams, VB_DISK_FLAG_REMOVABLE);
+ if (VBERROR_SUCCESS == retval) {
+ VB2_DEBUG("VbBootDeveloperMenu() - booting USB\n");
+ } else {
+ VB2_DEBUG("VbBootDeveloperMenu() - no kernel found on USB\n");
+ VbExBeep(250, 200);
+ VbExSleepMs(120);
+ /*
+ * Clear recovery requests from failed
+ * kernel loading, so that powering off
+ * at this point doesn't put us into
+ * recovery mode.
+ */
+ vb2_nv_set(ctx, VB2_NV_RECOVERY_REQUEST,
+ VBNV_RECOVERY_NOT_REQUESTED);
+ }
+ return retval;
+}
+
+#define CONFIRM_KEY_DELAY 20 /* Check confirm screen keys every 20ms */
+
+int VbUserConfirmsMenu(struct vb2_context *ctx, VbCommonParams *cparams,
+ uint32_t confirm_flags)
+{
+ VbSharedDataHeader *shared =
+ (VbSharedDataHeader *)cparams->shared_data_blob;
+ uint32_t key;
+ uint32_t key_flags;
+ uint32_t button;
+ int rec_button_was_pressed = 0;
+
+ VB2_DEBUG("Entering %s(0x%x)\n", __func__, confirm_flags);
+
+ /* Await further instructions */
+ while (1) {
+ if (VbWantShutdownMenu(cparams->gbb->flags))
+ return -1;
+ key = VbExKeyboardReadWithFlags(&key_flags);
+ button = VbExGetSwitches(VB_INIT_FLAG_REC_BUTTON_PRESSED);
+ switch (key) {
+ case '\r':
+ /* If we require a trusted keyboard for confirmation,
+ * but the keyboard may be faked (for instance, a USB
+ * device), beep and keep waiting.
+ */
+ if (confirm_flags & VB_CONFIRM_MUST_TRUST_KEYBOARD &&
+ !(key_flags & VB_KEY_FLAG_TRUSTED_KEYBOARD)) {
+ VbExBeep(120, 400);
+ break;
+ }
+
+ VB2_DEBUG("%s() - Yes (1)\n", __func__);
+ return 1;
+ break;
+ case ' ':
+ VB2_DEBUG("%s() - Space (%d)\n", __func__,
+ confirm_flags & VB_CONFIRM_SPACE_MEANS_NO);
+ if (confirm_flags & VB_CONFIRM_SPACE_MEANS_NO)
+ return 0;
+ break;
+ case 0x1b:
+ VB2_DEBUG("%s() - No (0)\n", __func__);
+ return 0;
+ break;
+ default:
+ /* If the recovery button is physical, and is pressed,
+ * this is also a YES, but must wait for release.
+ */
+ if (!(shared->flags & VBSD_BOOT_REC_SWITCH_VIRTUAL)) {
+ if (button) {
+ VB2_DEBUG("%s() - Rec button pressed\n",
+ __func__);
+ rec_button_was_pressed = 1;
+ } else if (rec_button_was_pressed) {
+ VB2_DEBUG("%s() - Rec button (1)\n",
+ __func__);
+ return 1;
+ }
+ }
+ VbCheckDisplayKey(ctx, cparams, key);
+ }
+ VbExSleepMs(CONFIRM_KEY_DELAY);
+ }
+
+ /* Not reached, but compiler will complain without it */
+ return -1;
+}
+
+static const char dev_disable_msg[] =
+ "Developer mode is disabled on this device by system policy.\n"
+ "For more information, see http://dev.chromium.org/chromium-os/fwmp\n"
+ "\n";
+
+typedef enum _VB_MENU {
+ VB_MENU_DEV_WARNING,
+ VB_MENU_DEV,
+ VB_MENU_TO_NORM,
+ VB_MENU_COUNT,
+} VB_MENU;
+
+typedef enum _VB_DEV_WARNING_MENU {
+ VB_WARN_OPTIONS,
+ VB_WARN_DBG_INFO,
+ VB_WARN_ENABLE_VER,
+ VB_WARN_POWER_OFF,
+ VB_WARN_LANGUAGE,
+ VB_WARN_COUNT,
+} VB_DEV_WARNING_MENU;
+
+typedef enum _VB_DEV_MENU {
+ VB_DEV_NETWORK,
+ VB_DEV_LEGACY,
+ VB_DEV_USB,
+ VB_DEV_DISK,
+ VB_DEV_CANCEL,
+ VB_DEV_POWER_OFF,
+ VB_DEV_LANGUAGE,
+ VB_DEV_COUNT,
+} VB_DEV_MENU;
+
+typedef enum _VB_TO_NORM_MENU {
+ VB_TO_NORM_CONFIRM,
+ VB_TO_NORM_CANCEL,
+ VB_TO_NORM_POWER_OFF,
+ VB_TO_NORM_LANGUAGE,
+ VB_TO_NORM_COUNT,
+} VB_TO_NORM_MENU;
+
+static VB_MENU current_menu = VB_MENU_DEV_WARNING;
+static int current_menu_idx = 0;
+static int selected = 0;
+
+// TODO: add in consts
+static char *dev_warning_menu[] = {
+ "Developer Options\n",
+ "Show Debug Info\n",
+ "Enable Root Verification\n",
+ "Power Off\n",
+ "Language\n"
+};
+
+static char *dev_menu[] = {
+ "Boot Network Image\n",
+ "Boot Legacy BIOS\n",
+ "Boot USB Image\n",
+ "Boot Developer Image\n",
+ "Cancel\n",
+ "Power Off\n",
+ "Language\n"
+};
+
+static char *to_normal_menu[] = {
+ "Confirm Enabling Verified Boot\n",
+ "Cancel\n",
+ "Power Off\n",
+ "Language\n"
+};
+
+// function that gets the current menu string array and size.
+// can set menu_array to NULL and only return string size.
+VbError_t vb2_get_current_menu_size(VB_MENU menu, char ***menu_array, int *size)
+{
+ char **temp_menu;
+
+ switch(menu) {
+ case VB_MENU_DEV_WARNING:
+ *size = VB_WARN_COUNT;
+ temp_menu = dev_warning_menu;
+ break;
+ case VB_MENU_DEV:
+ *size = VB_DEV_COUNT;
+ temp_menu = dev_menu;
+ break;
+ case VB_MENU_TO_NORM:
+ *size = VB_TO_NORM_COUNT;
+ temp_menu = to_normal_menu;
+ break;
+ default:
+ *size = 0;
+ return VBERROR_UNKNOWN;
+ }
+ *menu_array = temp_menu;
+
+ return VBERROR_SUCCESS;
+}
+
+// TODO: will probably have to print menu a
+// line at a time to center the text at X.
+// Otherwise, only the first line will be lined up
+// vertically properly.
+// which is why x is currently 0.
+// also, want to calculate what center is eventually instead of
+// hard-coding it.
+// at least right now there's no overlapping with the debug
+// printouts.
+VbError_t vb2_print_current_menu()
+{
+ // create menu string
+ char m_str[1024];
+ const char *selected = "==> ";
+ const char *deselected = " ";
+ int size = 0;
+ int i = 0;
+ static char **m = NULL;
+
+ memset(m_str, 0, strlen(m_str));
+ // TODO: need to check for error code.
+ vb2_get_current_menu_size(current_menu, &m, &size);
+ VB2_DEBUG("vb2_print_current_menu:\n");
+
+ for (i = 0; i < size; i++) {
+ if (current_menu_idx == i) {
+ // add selection to indicate current selection
+ strncat(m_str, selected, strlen(selected));
+ } else {
+ strncat(m_str, deselected, strlen(deselected));
+ }
+ strncat(m_str, m[i], strlen(m[i]));
+ }
+ VB2_DEBUG("%s", m_str);
+
+ return VbExDisplayText(0,0,m_str);
+}
+
+// This updates current_menu and current_menu_idx,
+// (as necessary)
+// which are used to determine what to do.
+VbError_t vb2_update_menu()
+{
+ VbError_t ret = VBERROR_SUCCESS;
+ switch(current_menu) {
+ case VB_MENU_DEV_WARNING:
+ switch(current_menu_idx) {
+ case VB_WARN_OPTIONS:
+ // select dev menu
+ current_menu = VB_MENU_DEV;
+ current_menu_idx = 0;
+ selected = 0;
+ break;
+ case VB_WARN_DBG_INFO:
+ // show debug info
+ break;
+ case VB_WARN_ENABLE_VER:
+ // enable boot verification
+ current_menu = VB_MENU_TO_NORM;
+ current_menu_idx = 0;
+ selected = 0;
+ break;
+ case VB_WARN_POWER_OFF:
+ // power off machine
+ ret = VBERROR_SHUTDOWN_REQUESTED;
+ break;
+ case VB_WARN_LANGUAGE:
+ // Languages
+ // we'll have to figure out how to display this
+ break;
+ default:
+ // invalid menu item. Don't update anything.
+ break;
+ }
+ break;
+ case VB_MENU_DEV:
+ switch(current_menu_idx) {
+ case VB_DEV_NETWORK:
+ // boot network image
+ break;
+ case VB_DEV_LEGACY:
+ // boot legacy BIOS
+ break;
+ case VB_DEV_USB:
+ // book USB image
+ break;
+ case VB_DEV_DISK:
+ // boot developer image
+ break;
+ case VB_DEV_CANCEL:
+ // cancel (go back to developer warning menu)
+ current_menu = VB_MENU_DEV_WARNING;
+ current_menu_idx = 0;
+ selected = 0;
+ break;
+ case VB_DEV_POWER_OFF:
+ // power off
+ ret = VBERROR_SHUTDOWN_REQUESTED;
+ break;
+ case VB_DEV_LANGUAGE:
+ // Language
+ break;
+ default:
+ // invalid menu item. don't update anything.
+ break;
+ }
+ break;
+ case VB_MENU_TO_NORM:
+ switch(current_menu_idx) {
+ case VB_TO_NORM_CONFIRM:
+ // confirm enabling verified boot
+ break;
+ case VB_TO_NORM_CANCEL:
+ // cancel (go back to developer warning menu)
+ current_menu = VB_MENU_DEV_WARNING;
+ current_menu_idx = 0;
+ selected = 0;
+ break;
+ case VB_TO_NORM_POWER_OFF:
+ // power off
+ ret = VBERROR_SHUTDOWN_REQUESTED;
+ break;
+ case VB_TO_NORM_LANGUAGE:
+ // Language
+ break;
+ default:
+ // invalid menu item. don't update anything
+ break;
+ }
+ break;
+ default:
+ VB2_DEBUG("Current Menu Invalid!");
+ }
+ return ret;
+}
+
+VbError_t vb2_developer_menu(struct vb2_context *ctx, VbCommonParams *cparams)
+{
+ GoogleBinaryBlockHeader *gbb = cparams->gbb;
+#if defined(VBOOT_DEBUG)
+ VbSharedDataHeader *shared =
+ (VbSharedDataHeader *)cparams->shared_data_blob;
+#endif
+
+ uint32_t disable_dev_boot = 0;
+ uint32_t use_usb = 0;
+ uint32_t use_legacy = 0;
+ uint32_t ctrl_d_pressed = 0;
+
+ VbAudioContext *audio = 0;
+ VbError_t ret;
+
+ VB2_DEBUG("Entering %s()\n", __func__);
+
+ /* Check if USB booting is allowed */
+ uint32_t allow_usb = vb2_nv_get(ctx, VB2_NV_DEV_BOOT_USB);
+ uint32_t allow_legacy = vb2_nv_get(ctx, VB2_NV_DEV_BOOT_LEGACY);
+
+ /* Check if the default is to boot using disk, usb, or legacy */
+ uint32_t default_boot = vb2_nv_get(ctx, VB2_NV_DEV_DEFAULT_BOOT);
+
+ if(default_boot == VBNV_DEV_DEFAULT_BOOT_USB)
+ use_usb = 1;
+ if(default_boot == VBNV_DEV_DEFAULT_BOOT_LEGACY)
+ use_legacy = 1;
+
+ /* Handle GBB flag override */
+ if (gbb->flags & GBB_FLAG_FORCE_DEV_BOOT_USB)
+ allow_usb = 1;
+ if (gbb->flags & GBB_FLAG_FORCE_DEV_BOOT_LEGACY)
+ allow_legacy = 1;
+ if (gbb->flags & GBB_FLAG_DEFAULT_DEV_BOOT_LEGACY) {
+ use_legacy = 1;
+ use_usb = 0;
+ }
+
+ /* Handle FWMP override */
+ uint32_t fwmp_flags = vb2_get_fwmp_flags();
+ if (fwmp_flags & FWMP_DEV_ENABLE_USB)
+ allow_usb = 1;
+ if (fwmp_flags & FWMP_DEV_ENABLE_LEGACY)
+ allow_legacy = 1;
+ if (fwmp_flags & FWMP_DEV_DISABLE_BOOT) {
+ if (gbb->flags & GBB_FLAG_FORCE_DEV_SWITCH_ON) {
+ VB2_DEBUG("%s() - FWMP_DEV_DISABLE_BOOT rejected by"
+ "FORCE_DEV_SWITCH_ON\n",
+ __func__);
+ } else {
+ disable_dev_boot = 1;
+ }
+ }
+
+ /* If dev mode is disabled, only allow TONORM */
+ while (disable_dev_boot) {
+ VB2_DEBUG("%s() - dev_disable_boot is set.\n", __func__);
+ VbDisplayScreen(ctx, cparams, VB_SCREEN_DEVELOPER_TO_NORM, 0);
+ VbExDisplayDebugInfo(dev_disable_msg);
+
+ /* Ignore space in VbUserConfirmsMenu()... */
+ switch (VbUserConfirmsMenu(ctx, cparams, 0)) {
+ case 1:
+ VB2_DEBUG("%s() - leaving dev-mode.\n", __func__);
+ vb2_nv_set(ctx, VB2_NV_DISABLE_DEV_REQUEST, 1);
+ VbDisplayScreen(ctx, cparams,
+ VB_SCREEN_TO_NORM_CONFIRMED,
+ 0);
+ VbExSleepMs(5000);
+ return VBERROR_REBOOT_REQUIRED;
+ case -1:
+ VB2_DEBUG("%s() - shutdown requested\n", __func__);
+ return VBERROR_SHUTDOWN_REQUESTED;
+ default:
+ /* Ignore user attempt to cancel */
+ VB2_DEBUG("%s() - ignore cancel TONORM\n", __func__);
+ }
+ }
+
+ /* Show the dev mode warning screen */
+ /* TODO: change this to blank screen? */
+ VbDisplayScreen(ctx, cparams, VB_SCREEN_DEVELOPER_WARNING, 0);
+ vb2_print_current_menu();
+
+ /* Get audio/delay context */
+ audio = VbAudioOpen(cparams);
+
+ /* We'll loop until we finish the delay or are interrupted */
+ do {
+ uint32_t key;
+ int menu_size;
+
+ if (VbWantShutdownMenu(gbb->flags)) {
+ VB2_DEBUG("shutdown requested!\n");
+ VbAudioClose(audio);
+ return VBERROR_SHUTDOWN_REQUESTED;
+ }
+
+ key = VbExKeyboardRead();
+ switch (key) {
+ case 0:
+ /* nothing pressed */
+ break;
+ case '\r':
+ /* Only disable virtual dev switch if allowed by GBB */
+ if (!(gbb->flags & GBB_FLAG_ENTER_TRIGGERS_TONORM))
+ break;
+ case VB_KEY_UP:
+ vb2_get_current_menu_size(current_menu,
+ NULL, &menu_size);
+ current_menu_idx = (current_menu_idx+menu_size-1) %
+ menu_size;
+ vb2_print_current_menu();
+ break;
+ case VB_KEY_DOWN:
+ vb2_get_current_menu_size(current_menu,
+ NULL, &menu_size);
+ current_menu_idx = (current_menu_idx+1) % menu_size;
+ VbDisplayScreen(ctx, cparams, VB_SCREEN_DEVELOPER_WARNING, 0);
+ vb2_print_current_menu();
+ break;
+ case VB_KEY_RIGHT:
+ // temporarily using this as a stand in for power button
+ // until get power button bypassed
+ selected = 1;
+
+ ret = vb2_update_menu();
+ // unfortunately, we need the blanking to get rid of
+ // artifacts from previous menu printing.
+ VbDisplayScreen(ctx, cparams, VB_SCREEN_BLANK, 0);
+ VbDisplayScreen(ctx, cparams,
+ VB_SCREEN_DEVELOPER_WARNING, 0);
+ vb2_print_current_menu();
+
+ // probably shutting down
+ if (ret != VBERROR_SUCCESS) {
+ VB2_DEBUG("VbBootDeveloperMenu() - shutting down!\n");
+ return ret;
+ }
+
+ // nothing selected, skip everything else.
+ if (selected == 0)
+ break;
+
+ // below is all the selection actions
+ // Display debug information = tab on most chromebooks
+ if (current_menu == VB_MENU_DEV_WARNING &&
+ current_menu_idx == VB_WARN_DBG_INFO) {
+ VbDisplayDebugInfo(ctx, cparams);
+ }
+
+ // Ctrl+L = legacy mode
+ if (current_menu == VB_MENU_DEV &&
+ current_menu_idx == VB_DEV_LEGACY) {
+ VB2_DEBUG("VbBootDeveloperMenu() - "
+ "user pressed Ctrl+L; "
+ "Try legacy boot\n");
+ VbTryLegacyMenu(allow_legacy);
+ }
+
+ // Ctrl+U = try USB boot, or beep if failure
+ if (current_menu == VB_MENU_DEV &&
+ current_menu_idx == VB_DEV_USB) {
+ VB2_DEBUG("VbBootDeveloperMenu() - "
+ "user pressed Ctrl+U; try USB\n");
+ if (!allow_usb) {
+ VB2_DEBUG("VbBootDeveloperMenu() - "
+ "USB booting is disabled\n");
+ VbExDisplayDebugInfo(
+ "WARNING: Booting from external media "
+ "(USB/SD) has not been enabled. Refer "
+ "to the developer-mode documentation "
+ "for details.\n");
+ VbExBeep(120, 400);
+ VbExSleepMs(120);
+ VbExBeep(120, 400);
+ } else {
+ // Clear the screen to show we get the
+ // Ctrl+U key press.
+ VbDisplayScreen(ctx,
+ cparams, VB_SCREEN_BLANK, 0);
+ if (VBERROR_SUCCESS ==
+ VbTryUsbMenu(ctx, cparams)) {
+ VbAudioClose(audio);
+ return VBERROR_SUCCESS;
+ } else {
+ // Show dev mode warning screen
+ // again
+ VbDisplayScreen(ctx,
+ cparams,
+ VB_SCREEN_DEVELOPER_WARNING,
+ 0);
+ }
+ }
+ }
+
+ /* Ctrl+D = dismiss warning; advance to timeout */
+ if (current_menu == VB_MENU_DEV &&
+ current_menu_idx == VB_DEV_DISK) {
+ VB2_DEBUG("VbBootDeveloperMenu() - "
+ "user pressed Ctrl+D; skip delay\n");
+ ctrl_d_pressed = 1;
+ goto fallout;
+ }
+
+ /* enabling verified boot */
+ if (current_menu == VB_MENU_TO_NORM &&
+ current_menu_idx == VB_TO_NORM_CONFIRM) {
+ // See if we should disable virtual dev-mode
+ // switch.
+ VB2_DEBUG("%s shared->flags=0x%x\n",
+ __func__, shared->flags);
+ // Ignore space in VbUserConfirmsMenu()...
+ VB2_DEBUG("%s() - leaving dev-mode.\n",
+ __func__);
+ vb2_nv_set(ctx, VB2_NV_DISABLE_DEV_REQUEST,
+ 1);
+ VbDisplayScreen(ctx,
+ cparams,
+ VB_SCREEN_TO_NORM_CONFIRMED,
+ 0);
+ VbExSleepMs(5000);
+ return VBERROR_REBOOT_REQUIRED;
+ }
+ break;
+ default:
+ VB2_DEBUG("VbBootDeveloperMenu() - pressed key %d\n",
+ key);
+ VbCheckDisplayKey(ctx, cparams, key);
+ break;
+ }
+ } while(VbAudioLooping(audio));
+
+fallout:
+
+ /* If defaulting to legacy boot, try that unless Ctrl+D was pressed */
+ if (use_legacy && !ctrl_d_pressed) {
+ VB2_DEBUG("VbBootDeveloperMenu() - defaulting to legacy\n");
+ VbTryLegacyMenu(allow_legacy);
+ }
+
+ if ((use_usb && !ctrl_d_pressed) && allow_usb) {
+ if (VBERROR_SUCCESS == VbTryUsbMenu(ctx, cparams)) {
+ VbAudioClose(audio);
+ return VBERROR_SUCCESS;
+ }
+ }
+
+ /* Timeout or Ctrl+D; attempt loading from fixed disk */
+ VB2_DEBUG("VbBootDeveloperMenu() - trying fixed disk\n");
+ VbAudioClose(audio);
+ return VbTryLoadKernel(ctx, cparams, VB_DISK_FLAG_FIXED);
+}
+
+VbError_t VbBootDeveloperMenu(struct vb2_context *ctx, VbCommonParams *cparams)
+{
+ VbError_t retval = vb2_developer_menu(ctx, cparams);
+ VbDisplayScreen(ctx, cparams, VB_SCREEN_BLANK, 0);
+ return retval;
+}
+
+/* Delay in recovery mode */
+#define REC_DISK_DELAY 1000 /* Check disks every 1s */
+#define REC_KEY_DELAY 20 /* Check keys every 20ms */
+#define REC_MEDIA_INIT_DELAY 500 /* Check removable media every 500ms */
+
+VbError_t vb2_recovery_menu(struct vb2_context *ctx, VbCommonParams *cparams)
+{
+ VbSharedDataHeader *shared =
+ (VbSharedDataHeader *)cparams->shared_data_blob;
+ uint32_t retval;
+ uint32_t key;
+ int i;
+
+ VBDEBUG(("VbBootRecoveryMenu() start\n"));
+
+ /*
+ * If the dev-mode switch is off and the user didn't press the recovery
+ * button (recovery was triggerred automatically), show 'broken' screen.
+ * The user can either only shutdown to abort or hit esc+refresh+power
+ * to initiate recovery as instructed on the screen.
+ */
+ if (!(shared->flags & VBSD_BOOT_DEV_SWITCH_ON) &&
+ !(shared->flags & VBSD_BOOT_REC_SWITCH_ON)) {
+ /*
+ * 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(("VbBootRecoveryMenu() saving recovery reason (%#x)\n",
+ shared->recovery_reason));
+ vb2_nv_set(ctx, VB2_NV_RECOVERY_SUBCODE,
+ shared->recovery_reason);
+ /*
+ * Commit NV now, because it won't get saved if the user forces
+ * manual recovery via the three-finger salute.
+ */
+ vb2_nv_commit(ctx);
+
+ VbDisplayScreen(ctx, cparams, VB_SCREEN_OS_BROKEN, 0);
+ VBDEBUG(("VbBootRecoveryMenu() waiting for manual recovery\n"));
+ while (1) {
+ VbCheckDisplayKey(ctx, cparams, VbExKeyboardRead());
+ if (VbWantShutdownMenu(cparams->gbb->flags))
+ return VBERROR_SHUTDOWN_REQUESTED;
+ VbExSleepMs(REC_KEY_DELAY);
+ }
+ }
+
+ /* Loop and wait for a recovery image */
+ VBDEBUG(("VbBootRecoveryMenu() waiting for a recovery image\n"));
+ while (1) {
+ VBDEBUG(("VbBootRecoveryMenu() attempting to load kernel2\n"));
+ retval = VbTryLoadKernel(ctx, cparams, VB_DISK_FLAG_REMOVABLE);
+
+ /*
+ * Clear recovery requests from failed kernel loading, since
+ * we're already in recovery mode. Do this now, so that
+ * powering off after inserting an invalid disk doesn't leave
+ * us stuck in recovery mode.
+ */
+ vb2_nv_set(ctx, VB2_NV_RECOVERY_REQUEST,
+ VBNV_RECOVERY_NOT_REQUESTED);
+
+ if (VBERROR_SUCCESS == retval)
+ break; /* Found a recovery kernel */
+
+ VbDisplayScreen(ctx, cparams, VBERROR_NO_DISK_FOUND == retval ?
+ VB_SCREEN_RECOVERY_INSERT :
+ VB_SCREEN_RECOVERY_NO_GOOD,
+ 0);
+
+ /*
+ * Scan keyboard more frequently than media, since x86
+ * platforms don't like to scan USB too rapidly.
+ */
+ for (i = 0; i < REC_DISK_DELAY; i += REC_KEY_DELAY) {
+ key = VbExKeyboardRead();
+ /*
+ * We might want to enter dev-mode from the Insert
+ * screen if all of the following are true:
+ * - user pressed Ctrl-D
+ * - 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)) {
+ if (!(shared->flags &
+ VBSD_BOOT_REC_SWITCH_VIRTUAL) &&
+ VbExGetSwitches(
+ VB_INIT_FLAG_REC_BUTTON_PRESSED)) {
+ /*
+ * Is the recovery button stuck? In
+ * any case we don't like this. Beep
+ * and ignore.
+ */
+ VBDEBUG(("%s() - ^D but rec switch "
+ "is pressed\n", __func__));
+ VbExBeep(120, 400);
+ continue;
+ }
+
+ /* Ask the user to confirm entering dev-mode */
+ VbDisplayScreen(ctx, cparams,
+ VB_SCREEN_RECOVERY_TO_DEV,
+ 0);
+ /* SPACE means no... */
+ uint32_t vbc_flags =
+ VB_CONFIRM_SPACE_MEANS_NO |
+ VB_CONFIRM_MUST_TRUST_KEYBOARD;
+ switch (VbUserConfirmsMenu(ctx, cparams,
+ vbc_flags)) {
+ case 1:
+ VBDEBUG(("%s() Enabling dev-mode...\n",
+ __func__));
+ if (TPM_SUCCESS != SetVirtualDevMode(1))
+ return VBERROR_TPM_SET_BOOT_MODE_STATE;
+ VBDEBUG(("%s() Reboot so it will take "
+ "effect\n", __func__));
+ if (VbExGetSwitches
+ (VB_INIT_FLAG_ALLOW_USB_BOOT))
+ VbAllowUsbBootMenu(ctx);
+ return VBERROR_REBOOT_REQUIRED;
+ case -1:
+ VBDEBUG(("%s() - Shutdown requested\n",
+ __func__));
+ return VBERROR_SHUTDOWN_REQUESTED;
+ default: /* zero, actually */
+ VBDEBUG(("%s() - Not enabling "
+ "dev-mode\n", __func__));
+ /*
+ * Jump out of the outer loop to
+ * refresh the display quickly.
+ */
+ i = 4;
+ break;
+ }
+ } else {
+ VbCheckDisplayKey(ctx, cparams, key);
+ }
+ if (VbWantShutdownMenu(cparams->gbb->flags))
+ return VBERROR_SHUTDOWN_REQUESTED;
+ VbExSleepMs(REC_KEY_DELAY);
+ }
+ }
+
+ return VBERROR_SUCCESS;
+}
+
+VbError_t VbBootRecoveryMenu(struct vb2_context *ctx, VbCommonParams *cparams)
+{
+ VbError_t retval = vb2_recovery_menu(ctx, cparams);
+ VbDisplayScreen(ctx, cparams, VB_SCREEN_BLANK, 0);
+ return retval;
+}