[PATCH v11 4/9] eficonfig: add "Change Boot Order" menu entry
Masahisa Kojima
masahisa.kojima at linaro.org
Thu Aug 18 09:34:11 CEST 2022
Hi Heinrich,
On Thu, 18 Aug 2022 at 15:50, Heinrich Schuchardt <xypron.glpk at gmx.de> wrote:
>
> On 8/18/22 08:17, Heinrich Schuchardt wrote:
> > On 8/17/22 11:36, 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, press SPACE to activate or deactivate
> >> the entry, then finalizes the order by ENTER key.
> >> If the entry is activated, the boot index is added into the
> >> BootOrder variable in the order of the list.
> >>
> >> 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 at linaro.org>
> >
> > Hello Masahisa,
> >
> > not all boot option will necessarily be in the boot order.
> >
> > It must be possible to add an existing boot option to the boot order.
> >
> > It must be possible to delete a boot option from the boot order without
> > deleting the boot option.
> >
> > I can't see how to do this inside the eficonfig command with the patch
> > series applied
>
> Sorry, I got this wrong. The inclusion/exclusion is done via the
> checkmark. This works fine.
Thank you for your quick check!
Regrads,
Masahisa Kojima
>
> Best regards
>
> Heinrich
>
> >
> >> ---
> >> Changes in v11:
> >> - remove BootOrder variable dependency
> >> - use ANSI_CURSOR_POSITION and ANSI_CLEAR_LINE instead of printf("\n")
> >> since current eficonfig implementation does not handle console size
> >> correctly.
> >> printf("\n") at the outside of console size breaks the console output.
> >> - add KEY_SPACE to toggle the boot option active status
> >>
> >> 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 | 346 ++++++++++++++++++++++++++++++++++++++++++++++++
> >> 1 file changed, 346 insertions(+)
> >>
> >> diff --git a/cmd/eficonfig.c b/cmd/eficonfig.c
> >> index 938d46374e..f6152495c8 100644
> >> --- a/cmd/eficonfig.c
> >> +++ b/cmd/eficonfig.c
> >> @@ -91,6 +91,23 @@ 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
> >> + * @boot_index: boot option index
> >> + * @active: flag to include the boot option into BootOrder
> >> variable
> >> + * @list: list structure
> >> + */
> >> +struct eficonfig_boot_order {
> >> + u32 num;
> >> + u16 *description;
> >> + u32 boot_index;
> >> + bool active;
> >> + struct list_head list;
> >> +};
> >> +
> >> /**
> >> * eficonfig_print_msg() - print message
> >> *
> >> @@ -1665,6 +1682,334 @@ out:
> >> return ret;
> >> }
> >>
> >> +/**
> >> + * eficonfig_display_change_boot_order() - display the BootOrder list
> >> + *
> >> + * @efi_menu: pointer to the efimenu structure
> >> + * Return: status code
> >> + */
> >> +static void eficonfig_display_change_boot_order(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
> >> + " Press UP/DOWN to move, +/- to change order"
> >> + ANSI_CURSOR_POSITION
> >> + " Press SPACE to activate or deactivate the entry"
> >> + ANSI_CURSOR_POSITION
> >> + " Select [Save] to complete, ESC/CTRL+C to quit"
> >> + ANSI_CURSOR_POSITION ANSI_CLEAR_LINE,
> >> + 1, 1, efi_menu->count + 5, 1, efi_menu->count + 6, 1,
> >> + efi_menu->count + 7, 1, efi_menu->count + 8, 1);
> >> +
> >> + /* draw boot option list */
> >> + list_for_each_safe(pos, n, &efi_menu->list) {
> >> + entry = list_entry(pos, struct eficonfig_boot_order, list);
> >> + reverse = (entry->num == efi_menu->active);
> >> +
> >> + printf(ANSI_CURSOR_POSITION, entry->num + 4, 7);
> >> +
> >> + if (reverse)
> >> + puts(ANSI_COLOR_REVERSE);
> >> +
> >> + if (entry->num < efi_menu->count - 2) {
> >> + if (entry->active)
> >> + printf("[*] ");
> >> + else
> >> + printf("[ ] ");
> >> + }
> >> +
> >> + printf("%ls", entry->description);
> >> +
> >> + if (reverse)
> >> + puts(ANSI_COLOR_RESET);
> >> + }
> >> +}
> >> +
> >> +/**
> >> + * eficonfig_choice_change_boot_order() - handle the BootOrder update
> >> + *
> >> + * @efi_menu: pointer to the efimenu structure
> >> + * Return: status code
> >> + */
> >> +static efi_status_t eficonfig_choice_change_boot_order(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, &efi_menu->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, &efi_menu->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_SPACE:
> >> + if (efi_menu->active < efi_menu->count - 2) {
> >> + list_for_each_safe(pos, n, &efi_menu->list) {
> >> + entry = list_entry(pos, struct
> >> eficonfig_boot_order, list);
> >> + if (entry->num == efi_menu->active) {
> >> + entry->active = entry->active ? false : true;
> >> + return EFI_NOT_READY;
> >> + }
> >> + }
> >> + }
> >> + break;
> >> + case KEY_QUIT:
> >> + return EFI_ABORTED;
> >> + default:
> >> + break;
> >> + }
> >> + }
> >> +}
> >> +
> >> +/**
> >> + * eficonfig_add_change_boot_order_entry() - add boot order entry
> >> + *
> >> + * @efi_menu: pointer to the efimenu structure
> >> + * @boot_index: boot option index to be added
> >> + * @active: flag to include the boot option into BootOrder
> >> + * Return: status code
> >> + */
> >> +static efi_status_t eficonfig_add_change_boot_order_entry(struct
> >> efimenu *efi_menu,
> >> + u32 boot_index, bool active)
> >> +{
> >> + efi_status_t ret;
> >> + efi_uintn_t size;
> >> + void *load_option;
> >> + struct efi_load_option lo;
> >> + u16 varname[] = u"Boot####";
> >> + struct eficonfig_boot_order *entry;
> >> +
> >> + efi_create_indexed_name(varname, sizeof(varname), "Boot",
> >> boot_index);
> >> + load_option = efi_get_var(varname, &efi_global_variable_guid,
> >> &size);
> >> + if (!load_option)
> >> + return EFI_SUCCESS;
> >> +
> >> + ret = efi_deserialize_load_option(&lo, load_option, &size);
> >> + if (ret != EFI_SUCCESS) {
> >> + free(load_option);
> >> + return ret;
> >> + }
> >> +
> >> + entry = calloc(1, sizeof(struct eficonfig_boot_order));
> >> + if (!entry) {
> >> + free(load_option);
> >> + return EFI_OUT_OF_RESOURCES;
> >> + }
> >> +
> >> + entry->description = u16_strdup(lo.label);
> >> + if (!entry->description) {
> >> + free(load_option);
> >> + free(entry);
> >> + return EFI_OUT_OF_RESOURCES;
> >> + }
> >> + entry->num = efi_menu->count++;
> >> + entry->boot_index = boot_index;
> >> + entry->active = active;
> >> + list_add_tail(&entry->list, &efi_menu->list);
> >> +
> >> + free(load_option);
> >> +
> >> + return EFI_SUCCESS;
> >> +}
> >> +
> >> +/**
> >> + * eficonfig_create_change_boot_order_entry() - create boot order entry
> >> + *
> >> + * @efi_menu: pointer to the efimenu structure
> >> + * @bootorder: pointer to the BootOrder variable
> >> + * @num: number of BootOrder entry
> >> + * Return: status code
> >> + */
> >> +static efi_status_t eficonfig_create_change_boot_order_entry(struct
> >> efimenu *efi_menu,
> >> + u16 *bootorder, efi_uintn_t num)
> >> +{
> >> + u32 i;
> >> + efi_status_t ret;
> >> + struct eficonfig_boot_order *entry;
> >> +
> >> + /* list the load option in the order of BootOrder variable */
> >> + for (i = 0; i < num; i++) {
> >> + if (efi_menu->count >= EFICONFIG_ENTRY_NUM_MAX - 2)
> >> + break;
> >> +
> >> + ret = eficonfig_add_change_boot_order_entry(efi_menu,
> >> bootorder[i], true);
> >> + if (ret != EFI_SUCCESS)
> >> + goto out;
> >> + }
> >> +
> >> + /* list the remaining load option not included in the BootOrder */
> >> + for (i = 0; i < 0xFFFF; i++) {
> >> + if (efi_menu->count >= EFICONFIG_ENTRY_NUM_MAX - 2)
> >> + break;
> >> +
> >> + /* If the index is included in the BootOrder, skip it */
> >> + if (search_bootorder(bootorder, num, i, NULL))
> >> + continue;
> >> +
> >> + ret = eficonfig_add_change_boot_order_entry(efi_menu, i, false);
> >> + if (ret != EFI_SUCCESS)
> >> + goto out;
> >> + }
> >> +
> >> + /* add "Save" and "Quit" entries */
> >> + entry = calloc(1, sizeof(struct eficonfig_boot_order));
> >> + if (!entry)
> >> + goto out;
> >> +
> >> + entry->num = efi_menu->count++;
> >> + entry->description = u16_strdup(u"Save");
> >> + list_add_tail(&entry->list, &efi_menu->list);
> >> +
> >> + entry = calloc(1, sizeof(struct eficonfig_boot_order));
> >> + if (!entry)
> >> + goto out;
> >> +
> >> + entry->num = efi_menu->count++;
> >> + entry->description = u16_strdup(u"Quit");
> >> + list_add_tail(&entry->list, &efi_menu->list);
> >> +
> >> + efi_menu->active = 0;
> >> +
> >> + return EFI_SUCCESS;
> >> +out:
> >> + return EFI_OUT_OF_RESOURCES;
> >> +}
> >> +
> >> +/**
> >> + * 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 count;
> >> + u16 *bootorder;
> >> + efi_status_t ret;
> >> + efi_uintn_t num, size;
> >> + struct list_head *pos, *n;
> >> + struct eficonfig_boot_order *entry;
> >> + struct efimenu *efi_menu;
> >> +
> >> + efi_menu = calloc(1, sizeof(struct efimenu));
> >> + if (!efi_menu)
> >> + return EFI_OUT_OF_RESOURCES;
> >> +
> >> + bootorder = efi_get_var(u"BootOrder", &efi_global_variable_guid,
> >> &size);
> >> +
> >> + INIT_LIST_HEAD(&efi_menu->list);
> >> + num = size / sizeof(u16);
> >> + ret = eficonfig_create_change_boot_order_entry(efi_menu,
> >> bootorder, num);
> >> + if (ret != EFI_SUCCESS)
> >> + goto out;
> >> +
> >> + while (1) {
> >> + eficonfig_display_change_boot_order(efi_menu);
> >> +
> >> + ret = eficonfig_choice_change_boot_order(efi_menu);
> >> + if (ret == EFI_SUCCESS) {
> >> + u16 *new_bootorder;
> >> +
> >> + new_bootorder = calloc(1, (efi_menu->count - 2) *
> >> sizeof(u16));
> >> + if (!new_bootorder) {
> >> + ret = EFI_OUT_OF_RESOURCES;
> >> + goto out;
> >> + }
> >> +
> >> + /* create new BootOrder */
> >> + count = 0;
> >> + list_for_each_safe(pos, n, &efi_menu->list) {
> >> + entry = list_entry(pos, struct eficonfig_boot_order,
> >> list);
> >> + if (entry->active)
> >> + new_bootorder[count++] = entry->boot_index;
> >> + }
> >> +
> >> + size = count * sizeof(u16);
> >> + 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, &efi_menu->list) {
> >> + entry = list_entry(pos, struct eficonfig_boot_order, list);
> >> + list_del(&entry->list);
> >> + free(entry->description);
> >> + free(entry);
> >> + }
> >> +
> >> + free(bootorder);
> >> + free(efi_menu);
> >> +
> >> + /* to stay the parent menu */
> >> + ret = (ret == EFI_ABORTED) ? EFI_NOT_READY : ret;
> >> +
> >> + return ret;
> >> +}
> >> +
> >> /**
> >> * eficonfig_init() - do required initialization for eficonfig command
> >> *
> >> @@ -1695,6 +2040,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},
> >> };
> >>
> >
>
More information about the U-Boot
mailing list