From: Takahiro Akashi <takahiro.akashi@linaro.org>
To: Masahisa Kojima <masahisa.kojima@linaro.org>
Cc: u-boot@lists.denx.de, Heinrich Schuchardt <xypron.glpk@gmx.de>,
Ilias Apalodimas <ilias.apalodimas@linaro.org>,
Simon Glass <sjg@chromium.org>,
Mark Kettenis <mark.kettenis@xs4all.nl>
Subject: Re: [PATCH v13 6/9] eficonfig: add "Change Boot Order" menu entry
Date: Thu, 25 Aug 2022 09:11:00 +0900 [thread overview]
Message-ID: <20220825001100.GA118663@laputa> (raw)
In-Reply-To: <20220824063740.5760-7-masahisa.kojima@linaro.org>
On Wed, Aug 24, 2022 at 03:37:37PM +0900, 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@linaro.org>
> ---
> No update since v12
Well, a minor issue.
When BootOrder is not defined, nothing happens by selecting
"Change Boot Order". For "Edit" or "Delete Boot Option", however,
it causes a menu transition and shows something like:
** Select Boot Option **
Quit
even if no applicable option is available.
I hope a consistent behavior for "Change Boot Order" as well,
or printing some error message will be better.
-Takahiro Akashi
> Changes in v12:
> - enumerate removable media device
>
> 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 | 351 +++++++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 350 insertions(+), 1 deletion(-)
>
> diff --git a/cmd/eficonfig.c b/cmd/eficonfig.c
> index 92171c4894..0922115138 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
> *
> @@ -1716,6 +1733,338 @@ 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;
> +
> + ret = eficonfig_generate_media_device_boot_option();
> + if (ret != EFI_SUCCESS)
> + return ret;
> +
> + 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;
> +}
> +
> /**
> * delete_boot_option() - delete selected boot option
> *
> @@ -1994,7 +2343,6 @@ out:
> return ret;
> }
>
> -
> /**
> * eficonfig_init() - do required initialization for eficonfig command
> *
> @@ -2025,6 +2373,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},
> {"Delete Boot Option", eficonfig_process_delete_boot_option},
> {"Quit", eficonfig_process_quit},
> };
> --
> 2.17.1
>
next prev parent reply other threads:[~2022-08-25 0:11 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-08-24 6:37 [PATCH v13 0/9] enable menu-driven UEFI variable maintenance Masahisa Kojima
2022-08-24 6:37 ` [PATCH v13 1/9] eficonfig: menu-driven addition of UEFI boot option Masahisa Kojima
2022-08-24 11:15 ` Ilias Apalodimas
2022-08-25 3:16 ` Masahisa Kojima
2022-08-24 14:19 ` Ilias Apalodimas
2022-08-25 3:17 ` Masahisa Kojima
2022-08-24 6:37 ` [PATCH v13 2/9] eficonfig: add "Edit Boot Option" menu entry Masahisa Kojima
2022-08-24 6:37 ` [PATCH v13 3/9] menu: add KEY_PLUS, KEY_MINUS and KEY_SPACE handling Masahisa Kojima
2022-08-24 6:37 ` [PATCH v13 4/9] eficonfig: add "Delete Boot Option" menu entry Masahisa Kojima
2022-08-24 6:37 ` [PATCH v13 5/9] bootmenu: add removable media entries Masahisa Kojima
2022-08-24 13:25 ` Ilias Apalodimas
2022-08-25 3:25 ` Masahisa Kojima
2022-08-25 8:03 ` Ilias Apalodimas
2022-08-25 8:26 ` Masahisa Kojima
2022-08-24 14:17 ` Ilias Apalodimas
2022-08-25 3:27 ` Masahisa Kojima
2022-08-24 6:37 ` [PATCH v13 6/9] eficonfig: add "Change Boot Order" menu entry Masahisa Kojima
2022-08-25 0:11 ` Takahiro Akashi [this message]
2022-08-25 2:36 ` Masahisa Kojima
2022-08-24 6:37 ` [PATCH v13 7/9] doc:bootmenu: add description for UEFI boot support Masahisa Kojima
2022-08-24 6:37 ` [PATCH v13 8/9] doc:eficonfig: add documentation for eficonfig command Masahisa Kojima
2022-08-24 9:13 ` Ilias Apalodimas
2022-08-25 2:11 ` Masahisa Kojima
2022-08-24 6:37 ` [PATCH v13 9/9] test: unit test for eficonfig Masahisa Kojima
2022-08-24 9:09 ` Ilias Apalodimas
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220825001100.GA118663@laputa \
--to=takahiro.akashi@linaro.org \
--cc=ilias.apalodimas@linaro.org \
--cc=mark.kettenis@xs4all.nl \
--cc=masahisa.kojima@linaro.org \
--cc=sjg@chromium.org \
--cc=u-boot@lists.denx.de \
--cc=xypron.glpk@gmx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.