From 755bf33ad1081322cff612a531b3edc74ecfcb3c Mon Sep 17 00:00:00 2001 From: Shelley Chen Date: Tue, 27 Dec 2016 14:10:26 -0800 Subject: firmware: Add recovery menu support for detachables Adding in basic menu support (using arrow keys) for detachables. This is specifically for the recovery menu. BUG=chrome-os-partner:61275 BRANCH=None TEST=reboot into recovery and try booting into developer mode. Change-Id: I9596cde62f2748928b4b796bde0a0226dc981235 Signed-off-by: Shelley Chen Reviewed-on: https://chromium-review.googlesource.com/424354 --- firmware/lib/vboot_ui_menu.c | 240 +++++++++++++++++++++++++++++++------------ 1 file changed, 176 insertions(+), 64 deletions(-) diff --git a/firmware/lib/vboot_ui_menu.c b/firmware/lib/vboot_ui_menu.c index 7fa44edd..252d27e7 100644 --- a/firmware/lib/vboot_ui_menu.c +++ b/firmware/lib/vboot_ui_menu.c @@ -162,6 +162,8 @@ typedef enum _VB_MENU { VB_MENU_DEV_WARNING, VB_MENU_DEV, VB_MENU_TO_NORM, + VB_MENU_RECOVERY, + VB_MENU_TO_DEV, VB_MENU_COUNT, } VB_MENU; @@ -193,6 +195,22 @@ typedef enum _VB_TO_NORM_MENU { VB_TO_NORM_COUNT, } VB_TO_NORM_MENU; +typedef enum _VB_RECOVERY_MENU { + VB_RECOVERY_TO_DEV, + VB_RECOVERY_DBG_INFO, + VB_RECOVERY_POWER_OFF, + VB_RECOVERY_LANGUAGE, + VB_RECOVERY_COUNT, +} VB_RECOVERY_MENU; + +typedef enum _VB_TO_DEV_MENU { + VB_TO_DEV_CONFIRM, + VB_TO_DEV_CANCEL, + VB_TO_DEV_POWER_OFF, + VB_TO_DEV_LANGUAGE, + VB_TO_DEV_COUNT, +} VB_TO_DEV_MENU; + static VB_MENU current_menu = VB_MENU_DEV_WARNING; static int current_menu_idx = 0; static int selected = 0; @@ -223,6 +241,20 @@ static char *to_normal_menu[] = { "Language\n" }; +static char *recovery_menu[] = { + "Enable developer mode\n", + "Show Debug Info\n", + "Power Off\n", + "Language\n" +}; + +static char *to_dev_menu[] = { + "Confirm enabling developer mode\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) @@ -242,6 +274,14 @@ VbError_t vb2_get_current_menu_size(VB_MENU menu, char ***menu_array, int *size) *size = VB_TO_NORM_COUNT; temp_menu = to_normal_menu; break; + case VB_MENU_RECOVERY: + *size = VB_RECOVERY_COUNT; + temp_menu = recovery_menu; + break; + case VB_MENU_TO_DEV: + *size = VB_TO_DEV_COUNT; + temp_menu = to_dev_menu; + break; default: *size = 0; return VBERROR_UNKNOWN; @@ -286,7 +326,7 @@ VbError_t vb2_print_current_menu() } VB2_DEBUG("%s", m_str); - return VbExDisplayText(0,0,m_str); + return VbExDisplayText(0,50,m_str); } // This updates current_menu and current_menu_idx, @@ -381,6 +421,46 @@ VbError_t vb2_update_menu() break; } break; + case VB_MENU_RECOVERY: + switch(current_menu_idx) { + case VB_RECOVERY_TO_DEV: + // switch to TO_DEV menu + current_menu = VB_MENU_TO_DEV; + current_menu_idx = 0; + selected = 0; + break; + case VB_RECOVERY_DBG_INFO: + break; + case VB_RECOVERY_POWER_OFF: + ret = VBERROR_SHUTDOWN_REQUESTED; + break; + case VB_RECOVERY_LANGUAGE: + break; + default: + // invalid menu item. don't update anything + break; + } + break; + case VB_MENU_TO_DEV: + switch(current_menu_idx) { + case VB_TO_DEV_CONFIRM: + // confirm enabling dev mode + break; + case VB_TO_DEV_CANCEL: + current_menu = VB_MENU_RECOVERY; + current_menu_idx = 0; + selected = 0; + break; + case VB_TO_DEV_POWER_OFF: + ret = VBERROR_SHUTDOWN_REQUESTED; + break; + case VB_TO_DEV_LANGUAGE: + break; + default: + // invalid menu item. don't update anything. + break; + } + break; default: VB2_DEBUG("Current Menu Invalid!"); } @@ -662,8 +742,10 @@ VbError_t vb2_recovery_menu(struct vb2_context *ctx, VbCommonParams *cparams) uint32_t retval; uint32_t key; int i; + VbError_t ret; + int menu_size; - VBDEBUG(("VbBootRecoveryMenu() start\n")); + VB2_DEBUG("VbBootRecoveryMenu() start\n"); /* * If the dev-mode switch is off and the user didn't press the recovery @@ -681,8 +763,8 @@ VbError_t vb2_recovery_menu(struct vb2_context *ctx, VbCommonParams *cparams) * 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_DEBUG("VbBootRecoveryMenu() saving recovery reason (%#x)\n", + shared->recovery_reason); vb2_nv_set(ctx, VB2_NV_RECOVERY_SUBCODE, shared->recovery_reason); /* @@ -692,7 +774,7 @@ VbError_t vb2_recovery_menu(struct vb2_context *ctx, VbCommonParams *cparams) vb2_nv_commit(ctx); VbDisplayScreen(ctx, cparams, VB_SCREEN_OS_BROKEN, 0); - VBDEBUG(("VbBootRecoveryMenu() waiting for manual recovery\n")); + VB2_DEBUG("VbBootRecoveryMenu() waiting for manual recovery\n"); while (1) { VbCheckDisplayKey(ctx, cparams, VbExKeyboardRead()); if (VbWantShutdownMenu(cparams->gbb->flags)) @@ -702,9 +784,13 @@ VbError_t vb2_recovery_menu(struct vb2_context *ctx, VbCommonParams *cparams) } /* Loop and wait for a recovery image */ - VBDEBUG(("VbBootRecoveryMenu() waiting for a recovery image\n")); + VB2_DEBUG("VbBootRecoveryMenu() waiting for a recovery image\n"); + // initialize menu to recovery menu. + current_menu = VB_MENU_RECOVERY; + current_menu_idx = 0; + while (1) { - VBDEBUG(("VbBootRecoveryMenu() attempting to load kernel2\n")); + VB2_DEBUG("VbBootRecoveryMenu() attempting to load kernel2\n"); retval = VbTryLoadKernel(ctx, cparams, VB_DISK_FLAG_REMOVABLE); /* @@ -723,6 +809,10 @@ VbError_t vb2_recovery_menu(struct vb2_context *ctx, VbCommonParams *cparams) VB_SCREEN_RECOVERY_INSERT : VB_SCREEN_RECOVERY_NO_GOOD, 0); + if (current_menu != VB_MENU_RECOVERY || + current_menu_idx != VB_RECOVERY_DBG_INFO) { + vb2_print_current_menu(); + } /* * Scan keyboard more frequently than media, since x86 @@ -730,72 +820,94 @@ VbError_t vb2_recovery_menu(struct vb2_context *ctx, VbCommonParams *cparams) */ 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; + switch (key) { + case 0: + /* nothing pressed */ + break; + case VB_KEY_UP: + VB2_DEBUG("VbBootRecoveryMenu() - pressed key VB_KEY_UP\n"); + 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_DEBUG("VbBootRecoveryMenu() - pressed key VB_KEY_DOWN\n"); + vb2_get_current_menu_size(current_menu, NULL, &menu_size); + current_menu_idx = (current_menu_idx+1) % menu_size; + vb2_print_current_menu(); + break; + case VB_KEY_RIGHT: + // temporarily using this as a stand in for + // power button until get power button bypassed + VB2_DEBUG("VbBootRecoveryMenu() - pressed key VB_KEY_RIGHT (SELECT)\n"); + selected = 1; + + ret = vb2_update_menu(); + if (current_menu != VB_MENU_RECOVERY || + current_menu_idx != VB_RECOVERY_DBG_INFO) { + vb2_print_current_menu(); } - /* 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__)); + // probably shutting down + if (ret != VBERROR_SUCCESS) { + VB2_DEBUG("VbBootRecoveryMenu() - update_menu - shutting down!\n"); + return ret; + } + + // nothing selected, skip everything else. + if (selected == 0) + break; + + /* Display debug information */ + if (current_menu == VB_MENU_RECOVERY && + current_menu_idx == VB_RECOVERY_DBG_INFO) { + VbDisplayDebugInfo(ctx, cparams); + } + + /* Confirm going into developer mode */ + /* + * 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 + */ + // TODO: let's put an error here if we're + // already in dev mode. + if (current_menu == VB_MENU_TO_DEV && + current_menu_idx == 0 && + 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. + */ + VB2_DEBUG("%s() - ^D but rec switch " + "is pressed\n", __func__); + VbExBeep(120, 400); + continue; + } + + VB2_DEBUG("%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__)); + VB2_DEBUG("%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; -- cgit v1.2.1