diff mbox series

[v5,15/17] efi_loader: menu-driven update of UEFI bootorder variable

Message ID 20220428080950.23509-16-masahisa.kojima@linaro.org
State Superseded
Headers show
Series enable menu-driven boot device selection | expand

Commit Message

Masahisa Kojima April 28, 2022, 8:09 a.m. UTC
This commit adds the menu-driven update of UEFI bootorder
variable.

Signed-off-by: Masahisa Kojima <masahisa.kojima@linaro.org>
---
Changes in v5:
- split into the separate patch

 lib/efi_loader/efi_bootmenu_maintenance.c | 102 ++++++++++++++++++++++
 1 file changed, 102 insertions(+)
diff mbox series

Patch

diff --git a/lib/efi_loader/efi_bootmenu_maintenance.c b/lib/efi_loader/efi_bootmenu_maintenance.c
index 26320a8b73..8c3f94c695 100644
--- a/lib/efi_loader/efi_bootmenu_maintenance.c
+++ b/lib/efi_loader/efi_bootmenu_maintenance.c
@@ -719,6 +719,56 @@  static efi_status_t efi_bootmenu_boot_add_enter_name(struct efi_bootmenu_boot_op
 	return ret;
 }
 
+static efi_status_t allow_decimal(struct efi_input_key *key)
+{
+	if (u'0' <= key->unicode_char && key->unicode_char <= u'9')
+		return EFI_SUCCESS;
+
+	return EFI_INVALID_PARAMETER;
+}
+
+static efi_status_t efi_bootmenu_change_boot_order(int selected, int max, int *new)
+{
+	efi_status_t ret;
+	u16 new_order[EFI_BOOT_ORDER_MAX_SIZE_IN_DECIMAL] = {0};
+
+	printf(ANSI_CURSOR_POSITION, 2, 1);
+	puts("  *** U-Boot EFI Boot Manager Menu ***");
+	printf(ANSI_CURSOR_POSITION, 4, 1);
+	printf("  current boot order      : %d", selected);
+
+	printf(ANSI_CURSOR_POSITION, 6, 1);
+	printf("  new boot order(0 - %4d): ", max);
+
+	printf(ANSI_CURSOR_POSITION, 8, 1);
+	puts("  ENTER to complete, ESC/CTRL+C to quit");
+
+	printf(ANSI_CURSOR_POSITION, 6, 29);
+	puts(ANSI_CURSOR_SHOW);
+
+	for (;;) {
+		memset(new_order, 0, sizeof(new_order));
+		ret = efi_console_get_u16_string(cin, cout, new_order, 6, allow_decimal, 6, 29);
+		if (ret == EFI_SUCCESS) {
+			int i;
+			int val = 0;
+
+			for (i = 0;
+			     i < u16_strnlen(new_order, EFI_BOOT_ORDER_MAX_SIZE_IN_DECIMAL - 1);
+			     i++)
+				val = (val * 10) + (new_order[i] - u'0');
+
+			if (val > max)
+				continue;
+
+			*new = val;
+			return EFI_SUCCESS;
+		} else {
+			return ret;
+		}
+	}
+}
+
 static efi_status_t efi_bootmenu_select_file_handler(struct efi_bootmenu_boot_option *bo)
 {
 	efi_status_t ret;
@@ -958,6 +1008,57 @@  static efi_status_t efi_bootmenu_process_delete_boot_option(void *data, bool *ex
 	return ret;
 }
 
+static efi_status_t efi_bootmenu_process_change_boot_order(void *data, bool *exit)
+{
+	int selected;
+	int new_order;
+	efi_status_t ret;
+	efi_uintn_t num, size;
+	u16 *bootorder = NULL;
+	u16 *new_bootorder = NULL;
+
+	bootorder = efi_get_var(u"BootOrder", &efi_global_variable_guid, &size);
+	if (!bootorder)
+		return EFI_NOT_FOUND;
+
+	num = size / sizeof(u16);
+	ret = efi_bootmenu_show_boot_selection(bootorder, num, &selected);
+	if (ret != EFI_SUCCESS)
+		goto out;
+
+	ret = efi_bootmenu_change_boot_order(selected, num - 1, &new_order);
+	if (ret != EFI_SUCCESS)
+		goto out;
+
+	new_bootorder = calloc(1, size);
+	if (!new_bootorder)
+		goto out;
+
+	memcpy(new_bootorder, bootorder, size);
+	if (selected > new_order) {
+		new_bootorder[new_order] = bootorder[selected];
+		memcpy(&new_bootorder[new_order + 1], &bootorder[new_order],
+		       (selected - new_order) * sizeof(u16));
+	} else if (selected < new_order) {
+		new_bootorder[new_order] = bootorder[selected];
+		memcpy(&new_bootorder[selected], &bootorder[selected + 1],
+		       (new_order - selected) * sizeof(u16));
+	} else {
+		/* nothing to change */
+		goto out;
+	}
+	ret = efi_set_variable_int(u"BootOrder", &efi_global_variable_guid,
+				   EFI_VARIABLE_NON_VOLATILE |
+				   EFI_VARIABLE_BOOTSERVICE_ACCESS |
+				   EFI_VARIABLE_RUNTIME_ACCESS,
+				   size, new_bootorder, false);
+out:
+	free(new_bootorder);
+	free(bootorder);
+
+	return ret;
+}
+
 static efi_status_t efi_bootmenu_init(void)
 {
 	efi_status_t ret;
@@ -987,6 +1088,7 @@  static efi_status_t efi_bootmenu_init(void)
 static const struct efi_bootmenu_item maintenance_menu_items[] = {
 	{u"Add Boot Option", efi_bootmenu_process_add_boot_option},
 	{u"Delete Boot Option", efi_bootmenu_process_delete_boot_option},
+	{u"Change Boot Order", efi_bootmenu_process_change_boot_order},
 	{u"Quit", NULL},
 };