summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Kitching <kitching@google.com>2020-05-05 11:02:46 +0800
committerCommit Bot <commit-bot@chromium.org>2020-05-07 14:18:53 +0000
commitee0b2f7e2e49fbb6fe895d41869078ff1b85b0d1 (patch)
tree491af2aba7112fac82ee952f9a9b2bcfbacc2e49
parent54ca8c3a2516bde0097d439bd6a85ddb1ce320fa (diff)
downloadvboot-ee0b2f7e2e49fbb6fe895d41869078ff1b85b0d1.tar.gz
vboot/ui: implement to_dev transition flow
Introduce three new action hooks: - vb2_screen_info.init Init function runs once when changing to the screen. - vb2_screen_info.action Action function runs repeatedly while on the screen. - vb2_menu_item: Action function takes precedence over target screen if non-NULL. Create the VB2_SCREEN_RECOVERY_TO_DEV screen, and add a keyboard shortcut to get to that screen directly when in manual recovery mode: Ctrl+D. The TO_DEV screen repeatedly checks for the correct physical verification state. When that state is triggered, it switches to dev mode and reboots. The trigger depends on physical presence type: - PHYSICAL_PRESENCE_KEYBOARD: wait for ENTER key on the confirm button, pressed by internal keyboard - !PHYSICAL_PRESENCE_KEYBOARD: wait for the physical presence button (recovery or power) to be pressed and released - SPACE character also cancels in order to preserve prior behaviour Note that currently there is no way to exit developer mode once it has been enabled. BUG=b:146399181 TEST=make clean && make runtests BRANCH=none Change-Id: If3ff248d98859d530c3a24524618c6282a5ac5b5 Signed-off-by: Joel Kitching <kitching@google.com> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/2168072 Reviewed-by: Joel Kitching <kitching@chromium.org> Commit-Queue: Joel Kitching <kitching@chromium.org> Tested-by: Joel Kitching <kitching@chromium.org>
-rw-r--r--firmware/2lib/2ui.c67
-rw-r--r--firmware/2lib/2ui_screens.c100
-rw-r--r--firmware/2lib/include/2api.h2
-rw-r--r--firmware/2lib/include/2ui.h13
-rw-r--r--firmware/2lib/include/2ui_private.h5
-rw-r--r--tests/vb2_ui_utility_tests.c6
6 files changed, 170 insertions, 23 deletions
diff --git a/firmware/2lib/2ui.c b/firmware/2lib/2ui.c
index 3c54ecca..6f90135b 100644
--- a/firmware/2lib/2ui.c
+++ b/firmware/2lib/2ui.c
@@ -132,29 +132,42 @@ vb2_error_t menu_select_action(struct vb2_ui_context *ui)
menu_item = &ui->state.screen->items[ui->state.selected_item];
- VB2_DEBUG("Select <%s> menu item <%s>\n",
- ui->state.screen->name, menu_item->text);
-
- if (menu_item->target) {
- VB2_DEBUG("Changing to target screen %#x for menu item <%s>\n",
- menu_item->target, menu_item->text);
+ if (menu_item->action) {
+ VB2_DEBUG("Menu item <%s> run action\n", menu_item->text);
+ return menu_item->action(ui);
+ } else if (menu_item->target) {
+ VB2_DEBUG("Menu item <%s> to target screen %#x\n",
+ menu_item->text, menu_item->target);
return change_screen(ui, menu_item->target);
}
- VB2_DEBUG("No target screen for menu item <%s>\n", menu_item->text);
-
+ VB2_DEBUG("Menu item <%s> no action or target screen\n",
+ menu_item->text);
return VB2_REQUEST_UI_CONTINUE;
}
/**
* Return back to the previous screen.
*/
-vb2_error_t menu_back_action(struct vb2_ui_context *ui)
+vb2_error_t vb2_ui_back_action(struct vb2_ui_context *ui)
{
/* TODO(kitching): Return to previous screen instead of root screen. */
return change_screen(ui, ui->root_screen->id);
}
+/**
+ * Context-dependent keyboard shortcut Ctrl+D.
+ *
+ * - Manual recovery mode: Change to dev mode transition screen.
+ * - Developer mode: Boot from internal disk (TODO).
+ */
+vb2_error_t ctrl_d_action(struct vb2_ui_context *ui)
+{
+ if (vb2_allow_recovery(ui->ctx))
+ return change_screen(ui, VB2_SCREEN_RECOVERY_TO_DEV);
+ return VB2_REQUEST_UI_CONTINUE;
+}
+
/*****************************************************************************/
/* Action lookup tables */
@@ -165,7 +178,9 @@ static struct input_action action_table[] = {
{ VB_BUTTON_VOL_UP_SHORT_PRESS, menu_up_action },
{ VB_BUTTON_VOL_DOWN_SHORT_PRESS, menu_down_action },
{ VB_BUTTON_POWER_SHORT_PRESS, menu_select_action },
- { VB_KEY_ESC, menu_back_action },
+ { VB_KEY_ESC, vb2_ui_back_action },
+ { VB_KEY_CTRL('D'), ctrl_d_action },
+ { ' ', vb2_ui_recovery_to_dev_action },
};
vb2_error_t (*input_action_lookup(int key))(struct vb2_ui_context *ui)
@@ -192,6 +207,9 @@ vb2_error_t change_screen(struct vb2_ui_context *ui, enum vb2_screen id)
memset(&ui->state, 0, sizeof(ui->state));
ui->state.screen = new_screen_info;
+ if (ui->state.screen->init)
+ return ui->state.screen->init(ui);
+
return VB2_REQUEST_UI_CONTINUE;
}
@@ -200,7 +218,6 @@ vb2_error_t ui_loop(struct vb2_context *ctx, enum vb2_screen root_screen_id,
{
struct vb2_ui_context ui;
struct vb2_screen_state prev_state;
- uint32_t key;
uint32_t key_flags;
vb2_error_t (*action)(struct vb2_ui_context *ui);
vb2_error_t rv;
@@ -231,26 +248,38 @@ vb2_error_t ui_loop(struct vb2_context *ctx, enum vb2_screen root_screen_id,
ui.state.disabled_item_mask);
}
+ /* Run screen action. */
+ if (ui.state.screen->action) {
+ rv = ui.state.screen->action(&ui);
+ if (rv != VB2_REQUEST_UI_CONTINUE)
+ return rv;
+ }
+
+ /* Grab new keyboard input. */
+ ui.key = VbExKeyboardReadWithFlags(&key_flags);
+ ui.key_trusted = !!(key_flags & VB_KEY_FLAG_TRUSTED_KEYBOARD);
+
/* Check for shutdown request. */
- key = VbExKeyboardReadWithFlags(&key_flags);
- if (shutdown_required(ctx, key)) {
+ if (shutdown_required(ctx, ui.key)) {
VB2_DEBUG("Shutdown required!\n");
return VB2_REQUEST_SHUTDOWN;
}
/* Run input action function if found. */
- action = input_action_lookup(key);
+ action = input_action_lookup(ui.key);
if (action) {
- ui.key = key;
rv = action(&ui);
- ui.key = 0;
if (rv != VB2_REQUEST_UI_CONTINUE)
return rv;
- } else if (key) {
- VB2_DEBUG("Pressed key %#x, trusted? %d\n", key,
- !!(key_flags & VB_KEY_FLAG_TRUSTED_KEYBOARD));
+ } else if (ui.key) {
+ VB2_DEBUG("Pressed key %#x, trusted? %d\n",
+ ui.key, ui.key_trusted);
}
+ /* Reset keyboard input. */
+ ui.key = 0;
+ ui.key_trusted = 0;
+
/* Run global action function if available. */
if (global_action) {
rv = global_action(&ui);
diff --git a/firmware/2lib/2ui_screens.c b/firmware/2lib/2ui_screens.c
index 5b235c24..a6fffb5e 100644
--- a/firmware/2lib/2ui_screens.c
+++ b/firmware/2lib/2ui_screens.c
@@ -6,7 +6,11 @@
*/
#include "2common.h"
+#include "2misc.h"
+#include "2nvstorage.h"
#include "2ui.h"
+#include "2ui_private.h"
+#include "vboot_api.h" /* for VB_KEY_ */
#define MENU_ITEMS(a) \
.num_items = ARRAY_SIZE(a), \
@@ -62,6 +66,101 @@ static const struct vb2_screen_info recovery_invalid_screen = {
};
/******************************************************************************/
+/* VB2_SCREEN_RECOVERY_TO_DEV */
+
+#define RECOVERY_TO_DEV_ITEM_CONFIRM 0
+
+vb2_error_t recovery_to_dev_init(struct vb2_ui_context *ui)
+{
+ if (vb2_get_sd(ui->ctx)->flags & VB2_SD_FLAG_DEV_MODE_ENABLED) {
+ VB2_DEBUG("Dev mode already enabled?\n");
+ return vb2_ui_back_action(ui);
+ }
+
+ if (!PHYSICAL_PRESENCE_KEYBOARD && vb2ex_physical_presence_pressed()) {
+ VB2_DEBUG("Presence button stuck?\n");
+ return vb2_ui_back_action(ui);
+ }
+
+ /* Disable "Confirm" button for other physical presence types. */
+ if (!PHYSICAL_PRESENCE_KEYBOARD)
+ ui->state.disabled_item_mask =
+ 1 << RECOVERY_TO_DEV_ITEM_CONFIRM;
+
+ return VB2_REQUEST_UI_CONTINUE;
+}
+
+vb2_error_t vb2_ui_recovery_to_dev_action(struct vb2_ui_context *ui)
+{
+ static int pressed_last;
+ int pressed;
+
+ if (ui->state.screen->id != VB2_SCREEN_RECOVERY_TO_DEV) {
+ VB2_DEBUG("Action needs RECOVERY_TO_DEV screen\n");
+ return VB2_REQUEST_UI_CONTINUE;
+ }
+
+ if (ui->key == ' ') {
+ VB2_DEBUG("SPACE means cancel dev mode transition\n");
+ return vb2_ui_back_action(ui);
+ }
+
+ if (PHYSICAL_PRESENCE_KEYBOARD) {
+ if (ui->key != VB_KEY_ENTER &&
+ ui->key != VB_BUTTON_POWER_SHORT_PRESS)
+ return VB2_REQUEST_UI_CONTINUE;
+ if (!ui->key_trusted) {
+ VB2_DEBUG("Reject untrusted %s confirmation\n",
+ ui->key == VB_KEY_ENTER ?
+ "ENTER" : "POWER");
+ return VB2_REQUEST_UI_CONTINUE;
+ }
+ } else {
+ pressed = vb2ex_physical_presence_pressed();
+ if (pressed) {
+ VB2_DEBUG("Physical presence button pressed, "
+ "awaiting release\n");
+ pressed_last = 1;
+ return VB2_REQUEST_UI_CONTINUE;
+ }
+ if (!pressed_last)
+ return VB2_REQUEST_UI_CONTINUE;
+ VB2_DEBUG("Physical presence button released\n");
+ }
+ VB2_DEBUG("Physical presence confirmed!\n");
+
+ /* Sanity check, should never happen. */
+ if ((vb2_get_sd(ui->ctx)->flags & VB2_SD_FLAG_DEV_MODE_ENABLED) ||
+ !vb2_allow_recovery(ui->ctx)) {
+ VB2_DEBUG("ERROR: dev transition sanity check failed\n");
+ return VB2_REQUEST_UI_CONTINUE;
+ }
+
+ VB2_DEBUG("Enabling dev mode and rebooting...\n");
+ vb2_enable_developer_mode(ui->ctx);
+ return VB2_REQUEST_REBOOT_EC_TO_RO;
+}
+
+static const struct vb2_menu_item recovery_to_dev_items[] = {
+ [RECOVERY_TO_DEV_ITEM_CONFIRM] = {
+ .text = "Confirm",
+ .action = vb2_ui_recovery_to_dev_action,
+ },
+ {
+ .text = "Cancel",
+ .action = vb2_ui_back_action,
+ },
+};
+
+static const struct vb2_screen_info recovery_to_dev_screen = {
+ .id = VB2_SCREEN_RECOVERY_TO_DEV,
+ .name = "Transition to developer mode",
+ .init = recovery_to_dev_init,
+ .action = vb2_ui_recovery_to_dev_action,
+ MENU_ITEMS(recovery_to_dev_items),
+};
+
+/******************************************************************************/
/* VB2_SCREEN_RECOVERY_PHONE_STEP1 */
static const struct vb2_screen_info recovery_phone_step1_screen = {
@@ -92,6 +191,7 @@ static const struct vb2_screen_info *screens[] = {
&recovery_broken_screen,
&recovery_select_screen,
&recovery_invalid_screen,
+ &recovery_to_dev_screen,
&recovery_phone_step1_screen,
&recovery_disk_step1_screen,
};
diff --git a/firmware/2lib/include/2api.h b/firmware/2lib/include/2api.h
index 416e2aa5..6b51c54c 100644
--- a/firmware/2lib/include/2api.h
+++ b/firmware/2lib/include/2api.h
@@ -1181,6 +1181,8 @@ enum vb2_screen {
VB2_SCREEN_RECOVERY_SELECT = 0x200,
/* Invalid recovery media inserted */
VB2_SCREEN_RECOVERY_INVALID = 0x201,
+ /* Confirm transition to developer mode */
+ VB2_SCREEN_RECOVERY_TO_DEV = 0x202,
/* Recovery using disk */
VB2_SCREEN_RECOVERY_DISK_STEP1 = 0x210,
VB2_SCREEN_RECOVERY_DISK_STEP2 = 0x211,
diff --git a/firmware/2lib/include/2ui.h b/firmware/2lib/include/2ui.h
index c0e2b634..b5754020 100644
--- a/firmware/2lib/include/2ui.h
+++ b/firmware/2lib/include/2ui.h
@@ -14,11 +14,17 @@
/*****************************************************************************/
/* Data structures */
+struct vb2_ui_context; /* Forward declaration */
+
struct vb2_screen_info {
/* Screen id */
enum vb2_screen id;
/* Screen name for printing to console only */
const char *name;
+ /* Init function runs once when changing to the screen. */
+ vb2_error_t (*init)(struct vb2_ui_context *ui);
+ /* Action function runs repeatedly while on the screen. */
+ vb2_error_t (*action)(struct vb2_ui_context *ui);
/* Number of menu items */
uint16_t num_items;
/* List of menu items */
@@ -30,6 +36,8 @@ struct vb2_menu_item {
const char *text;
/* Target screen */
enum vb2_screen target;
+ /* Action function takes precedence over target screen if non-NULL. */
+ vb2_error_t (*action)(struct vb2_ui_context *ui);
};
struct vb2_screen_state {
@@ -44,8 +52,13 @@ struct vb2_ui_context {
struct vb2_screen_state state;
uint32_t locale_id;
uint32_t key;
+ int key_trusted;
};
+vb2_error_t vb2_ui_change_screen(struct vb2_ui_context *ui, enum vb2_screen id);
+vb2_error_t vb2_ui_back_action(struct vb2_ui_context *ui);
+vb2_error_t vb2_ui_recovery_to_dev_action(struct vb2_ui_context *ui);
+
/**
* Get info struct of a screen.
*
diff --git a/firmware/2lib/include/2ui_private.h b/firmware/2lib/include/2ui_private.h
index 00534492..f7c4e247 100644
--- a/firmware/2lib/include/2ui_private.h
+++ b/firmware/2lib/include/2ui_private.h
@@ -28,7 +28,7 @@ struct input_action {
vb2_error_t menu_up_action(struct vb2_ui_context *ui);
vb2_error_t menu_down_action(struct vb2_ui_context *ui);
vb2_error_t menu_select_action(struct vb2_ui_context *ui);
-vb2_error_t menu_back_action(struct vb2_ui_context *ui);
+vb2_error_t ctrl_d_action(struct vb2_ui_context *ui);
vb2_error_t (*input_action_lookup(int key))(struct vb2_ui_context *ui);
vb2_error_t change_screen(struct vb2_ui_context *ui, enum vb2_screen id);
@@ -37,4 +37,7 @@ vb2_error_t ui_loop(struct vb2_context *ctx, enum vb2_screen root_screen_id,
vb2_error_t try_recovery_action(struct vb2_ui_context *ui);
+/* From 2ui_screens.c */
+vb2_error_t recovery_to_dev_init(struct vb2_ui_context *ui);
+
#endif /* VBOOT_REFERENCE_2UI_PRIVATE_H_ */
diff --git a/tests/vb2_ui_utility_tests.c b/tests/vb2_ui_utility_tests.c
index e62f6c05..08b537f5 100644
--- a/tests/vb2_ui_utility_tests.c
+++ b/tests/vb2_ui_utility_tests.c
@@ -595,11 +595,11 @@ static void menu_action_tests(void)
screen_state_eq(mock_state, MOCK_SCREEN_MENU, 1, MOCK_IGNORE);
}
- /* menu_back_action */
+ /* vb2_ui_back_action */
reset_common_data();
mock_ui_context.key = VB_KEY_ESC;
- TEST_EQ(menu_back_action(&mock_ui_context), VB2_REQUEST_UI_CONTINUE,
- "menu_back_action");
+ TEST_EQ(vb2_ui_back_action(&mock_ui_context), VB2_REQUEST_UI_CONTINUE,
+ "vb2_ui_back_action");
screen_state_eq(mock_state, VB2_SCREEN_BLANK, 0, MOCK_IGNORE);
VB2_DEBUG("...done.\n");