diff options
author | Joel Kitching <kitching@google.com> | 2020-08-03 23:52:27 +0800 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-09-11 10:47:08 +0000 |
commit | f573cf6669b5f2972f29f511efead068b8c3b38e (patch) | |
tree | a294e9fafe4ddf4692ac79820abaa6c4a67d0509 /firmware/2lib | |
parent | ade6151a678c59e270c89bcca37f61cfdd41700d (diff) | |
download | vboot-f573cf6669b5f2972f29f511efead068b8c3b38e.tar.gz |
vboot: Introduce alternate boot functionality
Introduce alternate boot functionality both via keyboard shortcut
("Ctrl+L") to directly boot into the default alternate bootloader,
and via menu ("Alternate bootloader" on dev screen) to show a screen
listing available bootloaders.
BUG=b:146399181, b:161092974
TEST=make clean && make runtests
BRANCH=puff, zork
Cq-Depend: chromium:2339040
Signed-off-by: Joel Kitching <kitching@google.com>
Change-Id: I28f157936017719dc95656db147967f5e61a1407
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/2335017
Commit-Queue: Yu-Ping Wu <yupingso@chromium.org>
Tested-by: Hsuan Ting Chen <roccochen@chromium.org>
Reviewed-by: Yu-Ping Wu <yupingso@chromium.org>
Reviewed-by: Joel Kitching <kitching@chromium.org>
Diffstat (limited to 'firmware/2lib')
-rw-r--r-- | firmware/2lib/2ui.c | 2 | ||||
-rw-r--r-- | firmware/2lib/2ui_screens.c | 117 | ||||
-rw-r--r-- | firmware/2lib/include/2api.h | 9 | ||||
-rw-r--r-- | firmware/2lib/include/2ui.h | 5 |
4 files changed, 133 insertions, 0 deletions
diff --git a/firmware/2lib/2ui.c b/firmware/2lib/2ui.c index d80002d5..4ddbcef0 100644 --- a/firmware/2lib/2ui.c +++ b/firmware/2lib/2ui.c @@ -410,6 +410,8 @@ vb2_error_t developer_action(struct vb2_ui_context *ui) if (ui->key == VB_KEY_CTRL('D') || (DETACHABLE && ui->key == VB_BUTTON_VOL_DOWN_LONG_PRESS)) return vb2_ui_developer_mode_boot_internal_action(ui); + if (ui->key == VB_KEY_CTRL('L')) + return vb2_ui_developer_mode_boot_alternate_action(ui); if (ui->key == '\t') return vb2_ui_screen_change(ui, VB2_SCREEN_DEBUG_INFO); diff --git a/firmware/2lib/2ui_screens.c b/firmware/2lib/2ui_screens.c index 2e5dbfaf..e1b02d0a 100644 --- a/firmware/2lib/2ui_screens.c +++ b/firmware/2lib/2ui_screens.c @@ -642,6 +642,7 @@ static const struct vb2_screen_info recovery_disk_step3_screen = { #define DEVELOPER_MODE_ITEM_RETURN_TO_SECURE 1 #define DEVELOPER_MODE_ITEM_BOOT_INTERNAL 2 #define DEVELOPER_MODE_ITEM_BOOT_EXTERNAL 3 +#define DEVELOPER_MODE_ITEM_SELECT_BOOTLOADER 4 vb2_error_t developer_mode_init(struct vb2_ui_context *ui) { @@ -662,11 +663,20 @@ vb2_error_t developer_mode_init(struct vb2_ui_context *ui) ui->state->disabled_item_mask |= 1 << DEVELOPER_MODE_ITEM_BOOT_EXTERNAL; + /* Don't show "Select alternate bootloader" button if not allowed. */ + if (!vb2_dev_boot_legacy_allowed(ui->ctx)) + ui->state->disabled_item_mask |= + 1 << DEVELOPER_MODE_ITEM_SELECT_BOOTLOADER; + /* Choose the default selection. */ switch (default_boot) { case VB2_DEV_DEFAULT_BOOT_TARGET_EXTERNAL: ui->state->selected_item = DEVELOPER_MODE_ITEM_BOOT_EXTERNAL; break; + case VB2_DEV_DEFAULT_BOOT_TARGET_LEGACY: + ui->state->selected_item = + DEVELOPER_MODE_ITEM_SELECT_BOOTLOADER; + break; default: ui->state->selected_item = DEVELOPER_MODE_ITEM_BOOT_INTERNAL; break; @@ -781,6 +791,10 @@ static const struct vb2_menu_item developer_mode_items[] = { .text = "Boot from external disk", .action = vb2_ui_developer_mode_boot_external_action, }, + [DEVELOPER_MODE_ITEM_SELECT_BOOTLOADER] = { + .text = "Select alternate bootloader", + .target = VB2_SCREEN_DEVELOPER_SELECT_BOOTLOADER, + }, ADVANCED_OPTIONS_ITEM, POWER_OFF_ITEM, }; @@ -860,6 +874,108 @@ static const struct vb2_screen_info developer_invalid_disk_screen = { }; /******************************************************************************/ +/* VB2_SCREEN_DEVELOPER_SELECT_BOOTLOADER */ + +const struct vb2_menu_item developer_select_bootloader_items_before[] = { + LANGUAGE_SELECT_ITEM, +}; + +const struct vb2_menu_item developer_select_bootloader_items_after[] = { + BACK_ITEM, + POWER_OFF_ITEM, +}; + +vb2_error_t vb2_ui_developer_mode_boot_alternate_action( + struct vb2_ui_context *ui) +{ + uint32_t altfw_num; + const size_t menu_before_len = + ARRAY_SIZE(developer_select_bootloader_items_before); + + if (!(ui->ctx->flags & VB2_CONTEXT_DEVELOPER_MODE) || + !vb2_dev_boot_allowed(ui->ctx) || + !vb2_dev_boot_legacy_allowed(ui->ctx)) { + VB2_DEBUG("ERROR: Dev mode alternate bootloader not allowed\n"); + ui->error_beep = 1; + return VB2_REQUEST_UI_CONTINUE; + } + + if (vb2ex_get_bootloader_count() == 0) { + VB2_DEBUG("ERROR: No bootloader was found\n"); + ui->error_beep = 1; + return VB2_REQUEST_UI_CONTINUE; + } + + if (ui->key == VB_KEY_CTRL('L')) { + altfw_num = 0; + VB2_DEBUG("Try booting from default bootloader\n"); + } else { + altfw_num = ui->state->selected_item - menu_before_len + 1; + VB2_DEBUG("Try booting from bootloader #%u\n", altfw_num); + } + + /* VbExLegacy will not return if successful */ + VbExLegacy(altfw_num); + + VB2_DEBUG("ERROR: Alternate bootloader failed\n"); + /* TODO(b/161092974): Leverage the error dialog on error. */ + ui->error_beep = 1; + return VB2_REQUEST_UI_CONTINUE; +} + +static const struct vb2_menu *get_bootloader_menu(struct vb2_ui_context *ui) +{ + int i; + uint32_t num_bootloaders, num_items; + struct vb2_menu_item *items; + const size_t menu_before_len = + ARRAY_SIZE(developer_select_bootloader_items_before); + const size_t menu_after_len = + ARRAY_SIZE(developer_select_bootloader_items_after); + + if (ui->bootloader_menu.num_items > 0) + return &ui->bootloader_menu; + + /* TODO(b/161092974): Show error dialog if no bootloader. */ + num_bootloaders = vb2ex_get_bootloader_count(); + VB2_DEBUG("num_bootloaders: %u\n", num_bootloaders); + num_items = num_bootloaders + menu_before_len + menu_after_len; + items = malloc(num_items * sizeof(struct vb2_menu_item)); + if (!items) { + VB2_DEBUG("ERROR: malloc failed for bootloader items\n"); + return NULL; + } + + /* Copy prefix items to the begin. */ + memcpy(&items[0], + developer_select_bootloader_items_before, + menu_before_len * sizeof(struct vb2_menu_item)); + + /* Copy bootloaders. */ + for (i = 0; i < num_bootloaders; i++) { + items[i + menu_before_len].text = "Some bootloader"; + items[i + menu_before_len].action = + vb2_ui_developer_mode_boot_alternate_action; + } + + /* Copy postfix items to the end. */ + memcpy(&items[num_items - menu_after_len], + developer_select_bootloader_items_after, + menu_after_len * sizeof(struct vb2_menu_item)); + + ui->bootloader_menu.num_items = num_items; + ui->bootloader_menu.items = items; + + return &ui->bootloader_menu; +} + +static const struct vb2_screen_info developer_select_bootloader_screen = { + .id = VB2_SCREEN_DEVELOPER_SELECT_BOOTLOADER, + .name = "Select alternate bootloader", + .get_menu = get_bootloader_menu, +}; + +/******************************************************************************/ /* VB2_SCREEN_DIAGNOSTICS */ static const struct vb2_menu_item diagnostics_items[] = { @@ -1071,6 +1187,7 @@ static const struct vb2_screen_info *screens[] = { &developer_to_norm_screen, &developer_boot_external_screen, &developer_invalid_disk_screen, + &developer_select_bootloader_screen, &diagnostics_screen, &diagnostics_storage_screen, &diagnostics_memory_quick_screen, diff --git a/firmware/2lib/include/2api.h b/firmware/2lib/include/2api.h index ee3bb53e..56c0b80c 100644 --- a/firmware/2lib/include/2api.h +++ b/firmware/2lib/include/2api.h @@ -1316,6 +1316,8 @@ enum vb2_screen { VB2_SCREEN_DEVELOPER_BOOT_EXTERNAL = 0x320, /* Invalid external disk inserted */ VB2_SCREEN_DEVELOPER_INVALID_DISK = 0x330, + /* Select alternate bootloader ("legacy boot") */ + VB2_SCREEN_DEVELOPER_SELECT_BOOTLOADER = 0x340, /* Diagnostic tools */ VB2_SCREEN_DIAGNOSTICS = 0x400, /* Storage diagnostic screen */ @@ -1380,6 +1382,13 @@ int vb2ex_physical_presence_pressed(void); uint32_t vb2ex_get_locale_count(void); /** + * Return the number of available alternate bootloaders. + * + * @returns Number of alternate bootloaders. 0 if none or on error. + */ +uint32_t vb2ex_get_bootloader_count(void); + +/** * Delay for at least the specified number of milliseconds. * * @param msec Duration in milliseconds. diff --git a/firmware/2lib/include/2ui.h b/firmware/2lib/include/2ui.h index cc21f580..2fefaf32 100644 --- a/firmware/2lib/include/2ui.h +++ b/firmware/2lib/include/2ui.h @@ -103,6 +103,9 @@ struct vb2_ui_context { /* For language selection screen. */ struct vb2_menu language_menu; + /* For bootloader selection screen. */ + struct vb2_menu bootloader_menu; + /* For error beep sound. */ int error_beep; @@ -118,6 +121,8 @@ vb2_error_t vb2_ui_developer_mode_boot_internal_action( struct vb2_ui_context *ui); vb2_error_t vb2_ui_developer_mode_boot_external_action( struct vb2_ui_context *ui); +vb2_error_t vb2_ui_developer_mode_boot_alternate_action( + struct vb2_ui_context *ui); /** * Get info struct of a screen. |