
Hi Heinrich,
On Tue, 2 Aug 2022 at 16:43, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
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
Both are supported in the next version. Thank you for your feedback.
Regards, Masahisa Kojima
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},