diff options
Diffstat (limited to 'firmware/lib/vboot_ui_legacy_clamshell.c')
-rw-r--r-- | firmware/lib/vboot_ui_legacy_clamshell.c | 556 |
1 files changed, 556 insertions, 0 deletions
diff --git a/firmware/lib/vboot_ui_legacy_clamshell.c b/firmware/lib/vboot_ui_legacy_clamshell.c new file mode 100644 index 00000000..cc0c4175 --- /dev/null +++ b/firmware/lib/vboot_ui_legacy_clamshell.c @@ -0,0 +1,556 @@ +/* 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 "2common.h" +#include "2misc.h" +#include "2nvstorage.h" +#include "2rsa.h" +#include "2secdata.h" +#include "2sysincludes.h" +#include "load_kernel_fw.h" +#include "tlcl.h" +#include "utility.h" +#include "vb2_common.h" +#include "vboot_api.h" +#include "vboot_audio.h" +#include "vboot_display.h" +#include "vboot_kernel.h" +#include "vboot_struct.h" +#include "vboot_test.h" +#include "vboot_ui_legacy_common.h" +#include "vboot_ui_legacy_wilco.h" + +static vb2_error_t VbTryUsb(struct vb2_context *ctx) +{ + int retval = VbTryLoadKernel(ctx, VB_DISK_FLAG_REMOVABLE); + if (VB2_SUCCESS == retval) { + VB2_DEBUG("developer UI - booting USB\n"); + } else { + vb2_error_notify("Could not boot from USB\n", + "developer UI - no kernel found on USB\n", + VB_BEEP_FAILED); + } + return retval; +} + +int VbUserConfirms(struct vb2_context *ctx, uint32_t confirm_flags) +{ + uint32_t key; + uint32_t key_flags; + uint32_t btn; + int phys_presence_button_was_pressed = 0; + int shutdown_requested = 0; + + VB2_DEBUG("Entering(%x)\n", confirm_flags); + + /* Await further instructions */ + do { + key = VbExKeyboardReadWithFlags(&key_flags); + shutdown_requested = vb2_want_shutdown(ctx, key); + switch (key) { + case VB_KEY_ENTER: + /* If we are using a trusted keyboard or a trusted + * keyboard is not required then return yes, otherwise + * keep waiting (for instance if the user is using a + * USB keyboard). + */ + if (!(confirm_flags & VB_CONFIRM_MUST_TRUST_KEYBOARD) || + (key_flags & VB_KEY_FLAG_TRUSTED_KEYBOARD)) { + VB2_DEBUG("Yes (1)\n"); + return 1; + } + + /* + * If physical presence is confirmed using the keyboard, + * beep and notify the user when the ENTER key comes + * from an untrusted keyboard. + * + * If physical presence is confirmed using a physical + * button, the existing message on the screen will + * instruct the user which button to push. Silently + * ignore any ENTER presses. + */ + if (PHYSICAL_PRESENCE_KEYBOARD) + vb2_error_notify("Please use internal keyboard " + "to confirm\n", + "VbUserConfirms() - " + "Trusted keyboard is required\n", + VB_BEEP_NOT_ALLOWED); + + break; + case ' ': + VB2_DEBUG("Space (%d)\n", + confirm_flags & VB_CONFIRM_SPACE_MEANS_NO); + if (confirm_flags & VB_CONFIRM_SPACE_MEANS_NO) + return 0; + break; + case VB_KEY_ESC: + VB2_DEBUG("No (0)\n"); + return 0; + default: + /* If the physical presence button is physical, and is + * pressed, this is also a YES, but must wait for + * release. + */ + if (!PHYSICAL_PRESENCE_KEYBOARD) { + btn = VbExGetSwitches( + VB_SWITCH_FLAG_PHYS_PRESENCE_PRESSED); + if (btn) { + VB2_DEBUG("Presence button pressed, " + "awaiting release\n"); + phys_presence_button_was_pressed = 1; + } else if (phys_presence_button_was_pressed) { + VB2_DEBUG("Presence button released " + "(1)\n"); + return 1; + } + } + VbCheckDisplayKey(ctx, key, NULL); + } + VbExSleepMs(KEY_DELAY_MS); + } while (!shutdown_requested); + + return -1; +} + +/* + * User interface for selecting alternative firmware + * + * This shows the user a list of bootloaders and allows selection of one of + * them. We loop forever until something is chosen or Escape is pressed. + */ +static vb2_error_t vb2_altfw_ui(struct vb2_context *ctx) +{ + int active = 1; + + VbDisplayScreen(ctx, VB_SCREEN_ALT_FW_PICK, 0, NULL); + + /* We'll loop until the user decides what to do */ + do { + uint32_t key = VbExKeyboardRead(); + + if (vb2_want_shutdown(ctx, key)) { + VB2_DEBUG("developer UI - shutdown requested!\n"); + return VBERROR_SHUTDOWN_REQUESTED; + } + switch (key) { + case 0: + /* nothing pressed */ + break; + case VB_KEY_ESC: + /* Escape pressed - return to developer screen */ + VB2_DEBUG("developer UI - user pressed Esc; " + "exit to Developer screen\n"); + active = 0; + break; + /* We allow selection of the default '0' bootloader here */ + case '0'...'9': + VB2_DEBUG("developer UI - user pressed key '%c';" + "Boot alternative firmware\n", key); + /* + * This will not return if successful. Drop out to + * developer mode on failure. + */ + vb2_try_altfw(ctx, 1, key - '0'); + active = 0; + break; + default: + VB2_DEBUG("developer UI - pressed key %#x\n", key); + VbCheckDisplayKey(ctx, key, NULL); + break; + } + VbExSleepMs(KEY_DELAY_MS); + } while (active); + + /* Back to developer screen */ + VbDisplayScreen(ctx, VB_SCREEN_DEVELOPER_WARNING, 0, NULL); + + return 0; +} + +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"; + +static vb2_error_t vb2_developer_ui(struct vb2_context *ctx) +{ + struct vb2_shared_data *sd = vb2_get_sd(ctx); + struct vb2_gbb_header *gbb = vb2_get_gbb(ctx); + + uint32_t disable_dev_boot = 0; + uint32_t use_usb = 0; + uint32_t use_legacy = 0; + uint32_t ctrl_d_pressed = 0; + + VB2_DEBUG("Entering\n"); + + /* 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 == VB2_DEV_DEFAULT_BOOT_USB) + use_usb = 1; + if (default_boot == VB2_DEV_DEFAULT_BOOT_LEGACY) + use_legacy = 1; + + /* Handle GBB flag override */ + if (gbb->flags & VB2_GBB_FLAG_FORCE_DEV_BOOT_USB) + allow_usb = 1; + if (gbb->flags & VB2_GBB_FLAG_FORCE_DEV_BOOT_LEGACY) + allow_legacy = 1; + if (gbb->flags & VB2_GBB_FLAG_DEFAULT_DEV_BOOT_LEGACY) { + use_legacy = 1; + use_usb = 0; + } + + /* Handle FWMP override */ + if (vb2_secdata_fwmp_get_flag(ctx, VB2_SECDATA_FWMP_DEV_ENABLE_USB)) + allow_usb = 1; + if (vb2_secdata_fwmp_get_flag(ctx, VB2_SECDATA_FWMP_DEV_ENABLE_LEGACY)) + allow_legacy = 1; + if (vb2_secdata_fwmp_get_flag(ctx, VB2_SECDATA_FWMP_DEV_DISABLE_BOOT)) { + if (gbb->flags & VB2_GBB_FLAG_FORCE_DEV_SWITCH_ON) { + VB2_DEBUG("FWMP_DEV_DISABLE_BOOT rejected by " + "FORCE_DEV_SWITCH_ON\n"); + } else { + disable_dev_boot = 1; + } + } + + /* If dev mode is disabled, only allow TONORM */ + while (disable_dev_boot) { + VB2_DEBUG("dev_disable_boot is set\n"); + VbDisplayScreen(ctx, + VB_SCREEN_DEVELOPER_TO_NORM, 0, NULL); + VbExDisplayDebugInfo(dev_disable_msg, 0); + + /* Ignore space in VbUserConfirms()... */ + switch (VbUserConfirms(ctx, 0)) { + case 1: + VB2_DEBUG("leaving dev-mode\n"); + vb2_nv_set(ctx, VB2_NV_DISABLE_DEV_REQUEST, 1); + VbDisplayScreen(ctx, + VB_SCREEN_TO_NORM_CONFIRMED, 0, NULL); + VbExSleepMs(5000); + return VBERROR_REBOOT_REQUIRED; + case -1: + VB2_DEBUG("shutdown requested\n"); + return VBERROR_SHUTDOWN_REQUESTED; + default: + /* Ignore user attempt to cancel */ + VB2_DEBUG("ignore cancel TONORM\n"); + } + } + + if ((ctx->flags & VB2_CONTEXT_VENDOR_DATA_SETTABLE) && + VENDOR_DATA_LENGTH > 0) { + vb2_error_t ret; + VB2_DEBUG("developer UI - Vendor data not set\n"); + ret = vb2_vendor_data_ui(ctx); + if (ret) + return ret; + } + + /* Show the dev mode warning screen */ + VbDisplayScreen(ctx, VB_SCREEN_DEVELOPER_WARNING, 0, NULL); + + /* Initialize audio/delay context */ + vb2_audio_start(ctx); + + /* We'll loop until we finish the delay or are interrupted */ + do { + uint32_t key = VbExKeyboardRead(); + if (vb2_want_shutdown(ctx, key)) { + VB2_DEBUG("developer UI - shutdown requested!\n"); + return VBERROR_SHUTDOWN_REQUESTED; + } + + switch (key) { + case 0: + /* nothing pressed */ + break; + case VB_KEY_ENTER: + /* Only disable virtual dev switch if allowed by GBB */ + if (!(gbb->flags & VB2_GBB_FLAG_ENTER_TRIGGERS_TONORM)) + break; + __attribute__ ((fallthrough)); + case ' ': + /* See if we should disable virtual dev-mode switch. */ + VB2_DEBUG("sd->flags=%#x\n", sd->flags); + + /* Sanity check, should never fail. */ + VB2_ASSERT(sd->flags & VB2_SD_FLAG_DEV_MODE_ENABLED); + + /* Stop the countdown while we go ask... */ + if (gbb->flags & VB2_GBB_FLAG_FORCE_DEV_SWITCH_ON) { + /* + * TONORM won't work (only for + * non-shipping devices). + */ + vb2_error_notify( + "WARNING: TONORM prohibited by " + "GBB FORCE_DEV_SWITCH_ON.\n", + NULL, VB_BEEP_NOT_ALLOWED); + break; + } + VbDisplayScreen(ctx, VB_SCREEN_DEVELOPER_TO_NORM, + 0, NULL); + /* Ignore space in VbUserConfirms()... */ + switch (VbUserConfirms(ctx, 0)) { + case 1: + VB2_DEBUG("leaving dev-mode\n"); + vb2_nv_set(ctx, VB2_NV_DISABLE_DEV_REQUEST, 1); + VbDisplayScreen(ctx, + VB_SCREEN_TO_NORM_CONFIRMED, 0, NULL); + VbExSleepMs(5000); + return VBERROR_REBOOT_REQUIRED; + case -1: + VB2_DEBUG("shutdown requested\n"); + return VBERROR_SHUTDOWN_REQUESTED; + default: + /* Stay in dev-mode */ + VB2_DEBUG("stay in dev-mode\n"); + VbDisplayScreen(ctx, + VB_SCREEN_DEVELOPER_WARNING, 0, NULL); + /* Start new countdown */ + vb2_audio_start(ctx); + } + break; + case VB_KEY_CTRL('D'): + /* Ctrl+D = dismiss warning; advance to timeout */ + VB2_DEBUG("developer UI - user pressed Ctrl+D; " + "skip delay\n"); + ctrl_d_pressed = 1; + goto fallout; + case VB_KEY_CTRL('L'): + VB2_DEBUG("developer UI - user pressed Ctrl+L; " + "Try alt firmware\n"); + if (allow_legacy) { + vb2_error_t ret; + + ret = vb2_altfw_ui(ctx); + if (ret) + return ret; + } else { + vb2_error_no_altfw(); + } + break; + case VB_KEY_CTRL_ENTER: + /* + * The Ctrl-Enter is special for Lumpy test purpose; + * fall through to Ctrl+U handler. + */ + case VB_KEY_CTRL('U'): + /* Ctrl+U = try USB boot, or beep if failure */ + VB2_DEBUG("developer UI - user pressed Ctrl+U; " + "try USB\n"); + if (!allow_usb) { + vb2_error_notify( + "WARNING: Booting from external media " + "(USB/SD) has not been enabled. Refer " + "to the developer-mode documentation " + "for details.\n", + "developer UI - " + "USB booting is disabled\n", + VB_BEEP_NOT_ALLOWED); + } else { + /* + * Clear the screen to show we get the Ctrl+U + * key press. + */ + VbDisplayScreen(ctx, VB_SCREEN_BLANK, 0, NULL); + if (VB2_SUCCESS == VbTryUsb(ctx)) { + return VB2_SUCCESS; + } else { + /* Show dev mode warning screen again */ + VbDisplayScreen(ctx, + VB_SCREEN_DEVELOPER_WARNING, + 0, NULL); + } + } + break; + /* We allow selection of the default '0' bootloader here */ + case '0'...'9': + VB2_DEBUG("developer UI - user pressed key '%c'; " + "Boot alternative firmware\n", key); + vb2_try_altfw(ctx, allow_legacy, key - '0'); + break; + default: + VB2_DEBUG("developer UI - pressed key %#x\n", key); + VbCheckDisplayKey(ctx, key, NULL); + break; + } + + VbExSleepMs(KEY_DELAY_MS); + } while(vb2_audio_looping()); + + fallout: + + /* If defaulting to legacy boot, try that unless Ctrl+D was pressed */ + if (use_legacy && !ctrl_d_pressed) { + VB2_DEBUG("developer UI - defaulting to legacy\n"); + vb2_try_altfw(ctx, allow_legacy, 0); + } + + if ((use_usb && !ctrl_d_pressed) && allow_usb) { + if (VB2_SUCCESS == VbTryUsb(ctx)) { + return VB2_SUCCESS; + } + } + + /* Timeout or Ctrl+D; attempt loading from fixed disk */ + VB2_DEBUG("developer UI - trying fixed disk\n"); + return VbTryLoadKernel(ctx, VB_DISK_FLAG_FIXED); +} + +vb2_error_t VbBootDeveloperLegacyClamshell(struct vb2_context *ctx) +{ + vb2_reset_power_button(); + vb2_error_t retval = vb2_developer_ui(ctx); + VbDisplayScreen(ctx, VB_SCREEN_BLANK, 0, NULL); + return retval; +} + +vb2_error_t VbBootDiagnosticLegacyClamshell(struct vb2_context *ctx) +{ + vb2_reset_power_button(); + vb2_error_t retval = vb2_diagnostics_ui(ctx); + VbDisplayScreen(ctx, VB_SCREEN_BLANK, 0, NULL); + return retval; +} + +static vb2_error_t recovery_ui(struct vb2_context *ctx) +{ + struct vb2_shared_data *sd = vb2_get_sd(ctx); + uint32_t retval; + uint32_t key; + const char release_button_msg[] = + "Release the recovery button and try again\n"; + const char recovery_pressed_msg[] = + "^D but recovery switch is pressed\n"; + + VB2_DEBUG("recovery UI - start\n"); + + if (!vb2_allow_recovery(ctx)) { + /* + * We have to save the reason here so that it will survive + * coming up three-finger-salute. We're saving it in + * VB2_RECOVERY_SUBCODE to avoid a recovery loop. + * If we save the reason in VB2_RECOVERY_REQUEST, we will come + * back here, thus, we won't be able to give a user a chance to + * reboot to workaround a boot hiccup. + */ + VB2_DEBUG("recovery UI - saving recovery reason (%#x)\n", + sd->recovery_reason); + vb2_nv_set(ctx, VB2_NV_RECOVERY_SUBCODE, sd->recovery_reason); + + /* + * Non-manual recovery mode is meant to be left via three-finger + * salute (into manual recovery mode). Need to commit nvdata + * changes immediately. Ignore commit errors in recovery mode. + */ + vb2_commit_data(ctx); + + VbDisplayScreen(ctx, VB_SCREEN_OS_BROKEN, 0, NULL); + VB2_DEBUG("recovery UI - waiting for manual recovery\n"); + while (1) { + key = VbExKeyboardRead(); + VbCheckDisplayKey(ctx, key, NULL); + if (vb2_want_shutdown(ctx, key)) + return VBERROR_SHUTDOWN_REQUESTED; + else if ((retval = + vb2_check_diagnostic_key(ctx, key)) != + VB2_SUCCESS) + return retval; + VbExSleepMs(KEY_DELAY_MS); + } + } + + /* Loop and wait for a recovery image */ + VB2_DEBUG("recovery UI - waiting for a recovery image\n"); + while (1) { + retval = VbTryLoadKernel(ctx, VB_DISK_FLAG_REMOVABLE); + + if (VB2_SUCCESS == retval) + break; /* Found a recovery kernel */ + + enum VbScreenType_t next_screen = + retval == VB2_ERROR_LK_NO_DISK_FOUND ? + VB_SCREEN_RECOVERY_INSERT : VB_SCREEN_RECOVERY_NO_GOOD; + VbDisplayScreen(ctx, next_screen, 0, NULL); + + 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 + */ + if (key == VB_KEY_CTRL('D') && + !(sd->flags & VB2_SD_FLAG_DEV_MODE_ENABLED) && + (sd->flags & VB2_SD_FLAG_MANUAL_RECOVERY)) { + if (!PHYSICAL_PRESENCE_KEYBOARD && + VbExGetSwitches( + VB_SWITCH_FLAG_PHYS_PRESENCE_PRESSED)) { + /* + * Is the presence button stuck? In any case + * we don't like this. Beep and ignore. + */ + vb2_error_notify(release_button_msg, + recovery_pressed_msg, + VB_BEEP_NOT_ALLOWED); + continue; + } + + /* Ask the user to confirm entering dev-mode */ + VbDisplayScreen(ctx, VB_SCREEN_RECOVERY_TO_DEV, + 0, NULL); + /* SPACE means no... */ + uint32_t vbc_flags = VB_CONFIRM_SPACE_MEANS_NO | + VB_CONFIRM_MUST_TRUST_KEYBOARD; + switch (VbUserConfirms(ctx, vbc_flags)) { + case 1: + VB2_DEBUG("Enabling dev-mode...\n"); + if (VB2_SUCCESS != vb2_enable_developer_mode(ctx)) + return VBERROR_TPM_SET_BOOT_MODE_STATE; + VB2_DEBUG("Reboot so it will take effect\n"); + if (USB_BOOT_ON_DEV) + vb2_nv_set(ctx, VB2_NV_DEV_BOOT_USB, 1); + return VBERROR_EC_REBOOT_TO_RO_REQUIRED; + case -1: + VB2_DEBUG("Shutdown requested\n"); + return VBERROR_SHUTDOWN_REQUESTED; + default: /* zero, actually */ + VB2_DEBUG("Not enabling dev-mode\n"); + break; + } + } else if ((retval = vb2_check_diagnostic_key(ctx, key)) != + VB2_SUCCESS) { + return retval; + } else { + VbCheckDisplayKey(ctx, key, NULL); + } + if (vb2_want_shutdown(ctx, key)) + return VBERROR_SHUTDOWN_REQUESTED; + VbExSleepMs(KEY_DELAY_MS); + } + + return VB2_SUCCESS; +} + +vb2_error_t VbBootRecoveryLegacyClamshell(struct vb2_context *ctx) +{ + vb2_error_t retval = recovery_ui(ctx); + VbDisplayScreen(ctx, VB_SCREEN_BLANK, 0, NULL); + return retval; +} |