
On 7/22/22 04:39, Masahisa Kojima wrote:
This commit adds the menu entry to update UEFI BootOrder variable. User moves the entry with UP/DOWN key, changes the order with PLUS/MINUS key, then finalizes the order by ENTER key.
The U-Boot menu framework is well designed for static menu, this commit implements the own menu display and key handling for dynamically change the order of menu entry.
Signed-off-by: Masahisa Kojima masahisa.kojima@linaro.org
If BootOrder is not defined efidebug does no allow to edit the boot order. It just shows an error message
BootOrder is not defined!
If BootOrder is defined I can only change the sequence but neither add not delete an entry.
eficonfig must allow:
* add any boot option to the sequence including autogenerated ones * delete any boot option from the sequence including autogenerated ones
Best regards
Heinrich
No update since v9
Changes in v9:
- add function comment
Changes in v8:
- add "Save" and "Quit" entries
Changes in v7:
- use UP/DOWN and PLUS/MINUS key to change to order
no update in v6:
cmd/eficonfig.c | 265 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 265 insertions(+)
diff --git a/cmd/eficonfig.c b/cmd/eficonfig.c index dc552e7ae1..482efc33d1 100644 --- a/cmd/eficonfig.c +++ b/cmd/eficonfig.c @@ -92,6 +92,21 @@ struct eficonfig_boot_selection_data { int *selected; };
+/**
- struct eficonfig_boot_order - structure to be used to update BootOrder variable
- @num: index in the menu entry
- @description: pointer to the description string
- @prev_index: index in the BootOrder variable before changing order
- @list: list structure
- */
+struct eficonfig_boot_order {
- u32 num;
- u16 *description;
- u32 prev_index;
- struct list_head list;
+};
- /**
- eficonfig_print_msg() - print message
@@ -1548,6 +1563,255 @@ out: return ret; }
+/**
- eficonfig_display_change_boot_order() - display the BootOrder list
- @bo_list: pointer to the list structure
- @efi_menu: pointer to the efimenu structure
- Return: status code
- */
+static void eficonfig_display_change_boot_order(struct list_head *bo_list,
struct efimenu *efi_menu)
+{
- bool reverse;
- struct list_head *pos, *n;
- struct eficonfig_boot_order *entry;
- printf(ANSI_CLEAR_CONSOLE
ANSI_CURSOR_POSITION
"\n ** Change Boot Order **\n"
ANSI_CURSOR_POSITION
"\n"
" Press UP/DOWN to move, +/- to change order\n ENTER to complete, ESC/CTRL+C to quit"
ANSI_CURSOR_POSITION,
0, 1, efi_menu->count + 5, 1, 4, 1);
- /* draw boot order list */
- list_for_each_safe(pos, n, bo_list) {
entry = list_entry(pos, struct eficonfig_boot_order, list);
reverse = (entry->num == efi_menu->active);
puts(" ");
if (reverse)
puts(ANSI_COLOR_REVERSE);
printf("%ls\n", entry->description);
if (reverse)
puts(ANSI_COLOR_RESET);
- }
+}
+/**
- eficonfig_choice_change_boot_order() - handle the BootOrder update
- @bo_list: pointer to the list structure
- @efi_menu: pointer to the efimenu structure
- Return: status code
- */
+static efi_status_t eficonfig_choice_change_boot_order(struct list_head *bo_list,
struct efimenu *efi_menu)
+{
- int esc = 0;
- struct list_head *pos, *n;
- struct eficonfig_boot_order *tmp;
- enum bootmenu_key key = KEY_NONE;
- struct eficonfig_boot_order *entry;
- while (1) {
bootmenu_loop(NULL, &key, &esc);
switch (key) {
case KEY_PLUS:
if (efi_menu->active > 0) {
list_for_each_safe(pos, n, bo_list) {
entry = list_entry(pos, struct eficonfig_boot_order, list);
if (entry->num == efi_menu->active)
break;
}
tmp = list_entry(pos->prev, struct eficonfig_boot_order, list);
entry->num--;
tmp->num++;
list_del(&tmp->list);
list_add(&tmp->list, &entry->list);
}
fallthrough;
case KEY_UP:
if (efi_menu->active > 0)
--efi_menu->active;
return EFI_NOT_READY;
case KEY_MINUS:
if (efi_menu->active < efi_menu->count - 3) {
list_for_each_safe(pos, n, bo_list) {
entry = list_entry(pos, struct eficonfig_boot_order, list);
if (entry->num == efi_menu->active)
break;
}
tmp = list_entry(pos->next, struct eficonfig_boot_order, list);
entry->num++;
tmp->num--;
list_del(&entry->list);
list_add(&entry->list, &tmp->list);
++efi_menu->active;
}
return EFI_NOT_READY;
case KEY_DOWN:
if (efi_menu->active < efi_menu->count - 1)
++efi_menu->active;
return EFI_NOT_READY;
case KEY_SELECT:
/* "Save" */
if (efi_menu->active == efi_menu->count - 2)
return EFI_SUCCESS;
/* "Quit" */
if (efi_menu->active == efi_menu->count - 1)
return EFI_ABORTED;
break;
case KEY_QUIT:
return EFI_ABORTED;
default:
break;
}
- }
+}
+/**
- eficonfig_process_change_boot_order() - handler to change boot order
- @data: pointer to the data for each entry
- Return: status code
- */
+static efi_status_t eficonfig_process_change_boot_order(void *data) +{
- u32 i;
- u16 *bootorder;
- efi_status_t ret;
- efi_uintn_t num, size;
- struct list_head bo_list;
- struct list_head *pos, *n;
- struct eficonfig_boot_order *entry;
- struct efimenu efi_menu;
- bootorder = efi_get_var(u"BootOrder", &efi_global_variable_guid, &size);
- if (!bootorder) {
eficonfig_print_msg("BootOrder is not defined!");
ret = EFI_NOT_FOUND;
return ret;
- }
- INIT_LIST_HEAD(&bo_list);
- num = size / sizeof(u16);
- for (i = 0; i < num; i++) {
void *load_option;
struct efi_load_option lo;
u16 varname[] = u"Boot####";
efi_create_indexed_name(varname, sizeof(varname),
"Boot", bootorder[i]);
load_option = efi_get_var(varname, &efi_global_variable_guid, &size);
if (!load_option) {
ret = EFI_NOT_FOUND;
goto out;
}
ret = efi_deserialize_load_option(&lo, load_option, &size);
if (ret != EFI_SUCCESS) {
free(load_option);
goto out;
}
entry = calloc(1, sizeof(struct eficonfig_boot_order));
if (!entry) {
free(load_option);
goto out;
}
entry->num = i;
entry->description = u16_strdup(lo.label);
entry->prev_index = i;
list_add_tail(&entry->list, &bo_list);
free(load_option);
- }
- /* add "Save" and "Quit" entries */
- entry = calloc(1, sizeof(struct eficonfig_boot_order));
- if (!entry)
goto out;
- entry->num = i++;
- entry->description = u16_strdup(u"Save");
- entry->prev_index = 0;
- list_add_tail(&entry->list, &bo_list);
- entry = calloc(1, sizeof(struct eficonfig_boot_order));
- if (!entry)
goto out;
- entry->num = i++;
- entry->description = u16_strdup(u"Quit");
- entry->prev_index = 0;
- list_add_tail(&entry->list, &bo_list);
- efi_menu.delay = -1;
- efi_menu.active = 0;
- efi_menu.count = i;
- while (1) {
eficonfig_display_change_boot_order(&bo_list, &efi_menu);
ret = eficonfig_choice_change_boot_order(&bo_list, &efi_menu);
if (ret == EFI_SUCCESS) {
u32 i = 0;
u16 *new_bootorder;
/* update the BootOrder variable */
size = num * sizeof(u16);
new_bootorder = calloc(1, size);
if (!new_bootorder) {
ret = EFI_OUT_OF_RESOURCES;
goto out;
}
list_for_each_safe(pos, n, &bo_list) {
entry = list_entry(pos, struct eficonfig_boot_order, list);
new_bootorder[i] = bootorder[entry->prev_index];
i++;
}
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);
free(new_bootorder);
goto out;
} else if (ret == EFI_NOT_READY) {
continue;
} else {
goto out;
}
- }
+out:
- list_for_each_safe(pos, n, &bo_list) {
entry = list_entry(pos, struct eficonfig_boot_order, list);
list_del(&entry->list);
free(entry->description);
free(entry);
- }
- free(bootorder);
- /* to stay the parent menu */
- ret = (ret == EFI_ABORTED) ? EFI_NOT_READY : ret;
- return ret;
+}
- /**
- eficonfig_init() - do required initialization for eficonfig command
@@ -1578,6 +1842,7 @@ static efi_status_t eficonfig_init(void) static const struct eficonfig_item maintenance_menu_items[] = { {"Add Boot Option", eficonfig_process_add_boot_option}, {"Edit Boot Option", eficonfig_process_edit_boot_option},
- {"Change Boot Order", eficonfig_process_change_boot_order}, {"Quit", eficonfig_process_quit}, };