This commit adds the menu-driven update of UEFI bootorder
variable.

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

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

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},
 };
 
-- 
2.17.1

Reply via email to