summaryrefslogtreecommitdiff
path: root/firmware/lib
diff options
context:
space:
mode:
authorSimon Glass <sjg@chromium.org>2018-10-16 19:36:48 -0600
committerchrome-bot <chrome-bot@chromium.org>2018-11-16 05:01:45 -0800
commita0ae31871275b389ea0f8b99ee4de359970b7db6 (patch)
treef8a5a5867dfbe1fa9f1ee5ed21928bd8daa392e9 /firmware/lib
parent4586b0c1dea8af8fd603ee7f1a0f6271bdcc1963 (diff)
downloadvboot-a0ae31871275b389ea0f8b99ee4de359970b7db6.tar.gz
Add a screen showing a menu for alternative firmware
At present we allow the user to press a keypad number to boot into another bootloader but there is no indication which one is which. Add a new screen for this. It is entered via Ctrl-L and shows the available bootloaders, along with the number to press for each. The contents of the screen is rendered by the bootloader, as usual. This is supported by two new screens, one for the keyboard UI and one for the menu UI. Also a new function, VbExGetAltFwIdxMask(), is added to find out what bootloaders are available. Note: This CL combines changes for both UIs. The changes may be easier to review separately. CQ-DEPEND=CL:1273269 BUG=chromium:837018 BRANCH=none TEST=FEATURES=test emerge-grunt --nodeps vboot_reference Change-Id: Ib3227545dc677c8f9587944753e32f3b49647360 Signed-off-by: Simon Glass <sjg@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/1273268 Reviewed-by: Julius Werner <jwerner@chromium.org>
Diffstat (limited to 'firmware/lib')
-rw-r--r--firmware/lib/include/vboot_ui_common.h17
-rw-r--r--firmware/lib/include/vboot_ui_menu_private.h1
-rw-r--r--firmware/lib/vboot_display.c5
-rw-r--r--firmware/lib/vboot_ui.c97
-rw-r--r--firmware/lib/vboot_ui_common.c17
-rw-r--r--firmware/lib/vboot_ui_menu.c100
6 files changed, 201 insertions, 36 deletions
diff --git a/firmware/lib/include/vboot_ui_common.h b/firmware/lib/include/vboot_ui_common.h
index 19c3809d..30ade5a6 100644
--- a/firmware/lib/include/vboot_ui_common.h
+++ b/firmware/lib/include/vboot_ui_common.h
@@ -28,4 +28,21 @@ void vb2_error_beep(enum vb2_beep_type beep);
*/
void vb2_run_altfw(int altfw_num);
+/** Display an error and beep to indicate that altfw is not available */
+void vb2_error_no_altfw(void);
+
+/**
+ * Jump to a bootloader if possible
+ *
+ * This checks if the operation is permitted. If it is, then it jumps to the
+ * selected bootloader and execution continues there, never returning.
+ *
+ * If the operation is not permitted, or it is permitted but the bootloader
+ * cannot be found, it beeps and returns.
+ *
+ * @allowed 1 if allowed, 0 if not allowed
+ * @altfw_num Number of bootloader to start (0=any, 1=first, etc.)
+ */
+void vb2_try_alt_fw(int allowed, int altfw_num);
+
#endif /* VBOOT_REFERENCE_VBOOT_UI_COMMON_H_ */
diff --git a/firmware/lib/include/vboot_ui_menu_private.h b/firmware/lib/include/vboot_ui_menu_private.h
index e07ece07..828a4a0f 100644
--- a/firmware/lib/include/vboot_ui_menu_private.h
+++ b/firmware/lib/include/vboot_ui_menu_private.h
@@ -33,6 +33,7 @@ typedef enum _VB_MENU {
VB_MENU_RECOVERY_NO_GOOD,
VB_MENU_RECOVERY_BROKEN,
VB_MENU_TO_NORM_CONFIRMED,
+ VB_MENU_ALT_FW,
VB_MENU_COUNT,
} VB_MENU;
diff --git a/firmware/lib/vboot_display.c b/firmware/lib/vboot_display.c
index b34976d1..c7607726 100644
--- a/firmware/lib/vboot_display.c
+++ b/firmware/lib/vboot_display.c
@@ -30,6 +30,11 @@ VbError_t VbExGetLocalizationCount(uint32_t *count) {
return VBERROR_UNKNOWN;
}
+__attribute__((weak))
+VbError_t VbExGetAltFwIdxMask(void) {
+ return 0;
+}
+
VbError_t VbDisplayScreen(struct vb2_context *ctx, uint32_t screen, int force)
{
uint32_t locale;
diff --git a/firmware/lib/vboot_ui.c b/firmware/lib/vboot_ui.c
index 63ae9cc5..71a7ceb3 100644
--- a/firmware/lib/vboot_ui.c
+++ b/firmware/lib/vboot_ui.c
@@ -73,31 +73,6 @@ static int VbWantShutdown(struct vb2_context *ctx, uint32_t key)
return !!shutdown_request;
}
-/**
- * Jump to a bootloader if possible
- *
- * This checks if the operation is permitted. If it is, then it jumps to the
- * selected bootloader and execution continues there, never returning.
- *
- * If the operation is not permitted, or it is permitted but the bootloader
- * cannot be found, it beeps and returns.
- *
- * @allowed 1 if allowed, 0 if not allowed
- * @altfw_num Number of bootloader to start (0=any, 1=first, etc.)
- */
-static void vb2_try_alt_fw(int allowed, int altfw_num)
-{
- if (allowed) {
- vb2_run_altfw(altfw_num); /* will not return if found */
- } else {
- VB2_DEBUG("VbBootDeveloper() - Legacy boot is disabled\n");
- VbExDisplayDebugInfo("WARNING: Booting legacy BIOS has not "
- "been enabled. Refer to the developer"
- "-mode documentation for details.\n");
- vb2_error_beep(VB_BEEP_NOT_ALLOWED);
- }
-}
-
uint32_t VbTryUsb(struct vb2_context *ctx)
{
uint32_t retval = VbTryLoadKernel(ctx, VB_DISK_FLAG_REMOVABLE);
@@ -186,6 +161,62 @@ int VbUserConfirms(struct vb2_context *ctx, uint32_t confirm_flags)
/* Delay in developer ui */
#define DEV_KEY_DELAY 20 /* Check keys every 20ms */
+/*
+ * 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.
+ */
+VbError_t vb2_altfw_ui(struct vb2_context *ctx)
+{
+ int active = 1;
+
+ VbDisplayScreen(ctx, VB_SCREEN_ALT_FW_PICK, 0);
+
+ /* We'll loop until the user decides what to do */
+ do {
+ uint32_t key = VbExKeyboardRead();
+
+ if (VbWantShutdown(ctx, key)) {
+ VB2_DEBUG("VbBootDeveloper() - 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("VbBootDeveloper() - 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("VbBootDeveloper() - "
+ "user pressed key '%c': Boot alternative "
+ "firmware\n", key);
+ /*
+ * This will not return if successful. Drop out to
+ * developer mode on failure.
+ */
+ vb2_run_altfw(key - '0');
+ active = 0;
+ break;
+ default:
+ VB2_DEBUG("VbBootDeveloper() - pressed key %d\n", key);
+ VbCheckDisplayKey(ctx, key);
+ break;
+ }
+ VbExSleepMs(DEV_KEY_DELAY);
+ } while (active);
+
+ /* Back to developer screen */
+ VbDisplayScreen(ctx, VB_SCREEN_DEVELOPER_WARNING, 0);
+
+ 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"
@@ -349,10 +380,17 @@ VbError_t vb2_developer_ui(struct vb2_context *ctx)
break;
case 0x0c:
VB2_DEBUG("VbBootDeveloper() - "
- "user pressed Ctrl+L; Try legacy boot\n");
- vb2_try_alt_fw(allow_legacy, 0);
- break;
+ "user pressed Ctrl+L; Try alt firmware\n");
+ if (allow_legacy) {
+ int 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;
@@ -386,7 +424,8 @@ VbError_t vb2_developer_ui(struct vb2_context *ctx)
}
}
break;
- case '1'...'9':
+ /* We allow selection of the default '0' bootloader here */
+ case '0'...'9':
VB2_DEBUG("VbBootDeveloper() - "
"user pressed key '%c': Boot alternative "
"firmware\n", key);
diff --git a/firmware/lib/vboot_ui_common.c b/firmware/lib/vboot_ui_common.c
index 727ed779..df1615d1 100644
--- a/firmware/lib/vboot_ui_common.c
+++ b/firmware/lib/vboot_ui_common.c
@@ -38,3 +38,20 @@ void vb2_run_altfw(int altfw_num)
VbExLegacy(altfw_num); /* will not return if found */
vb2_error_beep(VB_BEEP_FAILED);
}
+
+void vb2_error_no_altfw(void)
+{
+ VB2_DEBUG("Legacy boot is disabled\n");
+ VbExDisplayDebugInfo("WARNING: Booting legacy BIOS has not been "
+ "enabled. Refer to the developer-mode "
+ "documentation for details.\n");
+ vb2_error_beep(VB_BEEP_NOT_ALLOWED);
+}
+
+void vb2_try_alt_fw(int allowed, int altfw_num)
+{
+ if (allowed)
+ vb2_run_altfw(altfw_num); /* will not return if found */
+ else
+ vb2_error_no_altfw();
+}
diff --git a/firmware/lib/vboot_ui_menu.c b/firmware/lib/vboot_ui_menu.c
index 9bbc2c70..e547f38a 100644
--- a/firmware/lib/vboot_ui_menu.c
+++ b/firmware/lib/vboot_ui_menu.c
@@ -36,6 +36,7 @@ static uint32_t default_boot;
static uint32_t disable_dev_boot;
static uint32_t altfw_allowed;
static struct vb2_menu menus[];
+static const char no_legacy[] = "Legacy boot failed. Missing BIOS?\n";
/**
* Checks GBB flags against VbExIsShutdownRequested() shutdown request to
@@ -86,7 +87,6 @@ static void vb2_change_menu(VB_MENU new_current_menu,
{
prev_menu = current_menu;
current_menu = new_current_menu;
- current_menu_idx = new_current_menu_idx;
/* Reconfigure disabled_idx_mask for the new menu */
disabled_idx_mask = 0;
@@ -97,6 +97,19 @@ static void vb2_change_menu(VB_MENU new_current_menu,
if (current_menu == VB_MENU_TO_NORM &&
disable_dev_boot == 1)
disabled_idx_mask |= 1 << VB_TO_NORM_CANCEL;
+
+ /* Enable menu items for the selected bootloaders */
+ if (current_menu == VB_MENU_ALT_FW) {
+ disabled_idx_mask = ~(VbExGetAltFwIdxMask() >> 1);
+
+ /* Make sure 'cancel' is shown even with an invalid mask */
+ disabled_idx_mask &= (1 << VB_ALTFW_COUNT) - 1;
+ }
+ /* We assume that there is at least one enabled item */
+ while ((1 << new_current_menu_idx) & disabled_idx_mask)
+ new_current_menu_idx++;
+ if (new_current_menu_idx < menus[current_menu].size)
+ current_menu_idx = new_current_menu_idx;
}
/************************
@@ -118,8 +131,6 @@ static VbError_t boot_disk_action(struct vb2_context *ctx)
/* Boot legacy BIOS if allowed and available. */
static VbError_t boot_legacy_action(struct vb2_context *ctx)
{
- const char no_legacy[] = "Legacy boot failed. Missing BIOS?\n";
-
if (disable_dev_boot) {
vb2_flash_screen(ctx);
vb2_error_beep(VB_BEEP_NOT_ALLOWED);
@@ -258,6 +269,26 @@ static VbError_t enter_to_norm_menu(struct vb2_context *ctx)
return VBERROR_KEEP_LOOPING;
}
+/* Boot alternative bootloader if allowed and available. */
+static VbError_t enter_altfw_menu(struct vb2_context *ctx)
+{
+ VB2_DEBUG("enter_altfw_menu()\n");
+ if (disable_dev_boot) {
+ vb2_flash_screen(ctx);
+ vb2_error_beep(VB_BEEP_NOT_ALLOWED);
+ return VBERROR_KEEP_LOOPING;
+ }
+ if (!altfw_allowed) {
+ vb2_flash_screen(ctx);
+ vb2_error_no_altfw();
+ return VBERROR_KEEP_LOOPING;
+ }
+ vb2_change_menu(VB_MENU_ALT_FW, 0);
+ vb2_draw_current_screen(ctx);
+
+ return VBERROR_KEEP_LOOPING;
+}
+
static VbError_t debug_info_action(struct vb2_context *ctx)
{
VbDisplayDebugInfo(ctx);
@@ -298,6 +329,17 @@ static VbError_t language_action(struct vb2_context *ctx)
}
}
+/* Action when selecting a bootloader in the alternative firmware menu. */
+static VbError_t altfw_action(struct vb2_context *ctx)
+{
+ vb2_run_altfw(current_menu_idx + 1);
+ vb2_flash_screen(ctx);
+ VB2_DEBUG(no_legacy);
+ VbExDisplayDebugInfo(no_legacy);
+
+ return VBERROR_KEEP_LOOPING;
+}
+
/* Action that enables developer mode and reboots. */
static VbError_t to_dev_action(struct vb2_context *ctx)
{
@@ -481,7 +523,7 @@ static struct vb2_menu menus[VB_MENU_COUNT] = {
},
[VB_DEV_LEGACY] = {
.text = "Boot Legacy BIOS",
- .action = boot_legacy_action,
+ .action = enter_altfw_menu,
},
[VB_DEV_USB] = {
.text = "Boot From USB or SD Card",
@@ -595,6 +637,42 @@ static struct vb2_menu menus[VB_MENU_COUNT] = {
.screen = VB_SCREEN_TO_NORM_CONFIRMED,
.items = NULL,
},
+ [VB_MENU_ALT_FW] = {
+ .screen = VB_SCREEN_ALT_FW_MENU,
+ .size = VB_ALTFW_COUNT + 1,
+ .items = (struct vb2_menu_item[]) {{
+ .text = "Bootloader 1",
+ .action = altfw_action,
+ }, {
+ .text = "Bootloader 2",
+ .action = altfw_action,
+ }, {
+ .text = "Bootloader 3",
+ .action = altfw_action,
+ }, {
+ .text = "Bootloader 4",
+ .action = altfw_action,
+ }, {
+ .text = "Bootloader 5",
+ .action = altfw_action,
+ }, {
+ .text = "Bootloader 6",
+ .action = altfw_action,
+ }, {
+ .text = "Bootloader 7",
+ .action = altfw_action,
+ }, {
+ .text = "Bootloader 8",
+ .action = altfw_action,
+ }, {
+ .text = "Bootloader 9",
+ .action = altfw_action,
+ }, {
+ .text = "Cancel",
+ .action = enter_developer_menu,
+ },
+ },
+ },
};
/* Initialize menu state. Must be called once before displaying any menus. */
@@ -614,6 +692,7 @@ static VbError_t vb2_init_menus(struct vb2_context *ctx)
return VBERROR_UNKNOWN;
for (i = 0; i < count; i++) {
+ /* The actual language is drawn by the bootloader */
items[i].text = "Some Language";
items[i].action = language_action;
}
@@ -679,14 +758,21 @@ static VbError_t vb2_developer_menu(struct vb2_context *ctx)
ret = boot_disk_action(ctx);
break;
case 'L' & 0x1f:
- /* Ctrl+L = boot legacy BIOS */
- ret = boot_legacy_action(ctx);
+ /* Ctrl+L = boot alternative bootloader */
+ ret = enter_altfw_menu(ctx);
break;
case VB_BUTTON_VOL_UP_LONG_PRESS:
case 'U' & 0x1f:
/* Ctrl+U = boot from USB or SD card */
ret = boot_usb_action(ctx);
break;
+ /* We allow selection of the default '0' bootloader here */
+ case '0'...'9':
+ VB2_DEBUG("VbBootDeveloper() - "
+ "user pressed key '%c': Boot alternative "
+ "firmware\n", key);
+ vb2_try_alt_fw(altfw_allowed, key - '0');
+ break;
default:
ret = vb2_handle_menu_input(ctx, key, 0);
break;
@@ -703,7 +789,7 @@ static VbError_t vb2_developer_menu(struct vb2_context *ctx)
VbExSleepMs(DEV_KEY_DELAY);
/* If dev mode was disabled, loop forever (never timeout) */
- } while(disable_dev_boot ? 1 : vb2_audio_looping());
+ } while (disable_dev_boot ? 1 : vb2_audio_looping());
if (default_boot == VB2_DEV_DEFAULT_BOOT_LEGACY)
boot_legacy_action(ctx); /* Doesn't return on success. */