[PATCH v5 09/17] bootmenu: add UEFI boot entry into bootmenu
Masahisa Kojima
masahisa.kojima at linaro.org
Mon May 9 10:59:26 CEST 2022
Hi Heinrich,
On Mon, 2 May 2022 at 06:44, Heinrich Schuchardt <xypron.glpk at gmx.de> wrote:
>
> On 4/28/22 10:09, Masahisa Kojima wrote:
> > This commit adds the UEFI related menu entries
> > into the bootmenu.
> >
> > User can select which UEFI "Boot####" option to execute
> > from bootmenu, then bootmenu sets the "BootNext" UEFI
> > variable and invoke efi bootmgr. The efi bootmgr
> > will handle the "BootNext" UEFI variable.
> >
> > If the "BootNext" UEFI variable is preset and efi bootmgr is enabled,
> > bootmenu invokes efi bootmgr to handle "BootNext" as first priority.
> >
> > The UEFI boot entry has the "UEFI BOOTXXXX" prefix as below.
>
> This prefix provides no value.
>
> >
> > *** U-Boot Boot Menu ***
> >
> > UEFI BOOT0000 : debian
> > UEFI BOOT0001 : ubuntu
> >
> > Signed-off-by: Masahisa Kojima <masahisa.kojima at linaro.org>
> > ---
> > Changes in v5:
> > - split into the separate patch
> > - add function description comment
> > - remove non-volatile attribute for BootNext variable to minimize
> > the access to the non-volatile storage
> >
> > cmd/bootmenu.c | 155 ++++++++++++++++++++++++++++++++++++++++++++++++-
> > 1 file changed, 154 insertions(+), 1 deletion(-)
> >
> > diff --git a/cmd/bootmenu.c b/cmd/bootmenu.c
> > index 15ad621c9f..da688e6213 100644
> > --- a/cmd/bootmenu.c
> > +++ b/cmd/bootmenu.c
> > @@ -7,6 +7,8 @@
> > #include <common.h>
> > #include <command.h>
> > #include <ansi.h>
> > +#include <efi_loader.h>
> > +#include <efi_variable.h>
> > #include <env.h>
> > #include <log.h>
> > #include <menu.h>
> > @@ -28,6 +30,7 @@
> > enum boot_type {
> > BOOTMENU_TYPE_NONE = 0,
> > BOOTMENU_TYPE_BOOTMENU,
> > + BOOTMENU_TYPE_UEFI_BOOT_OPTION,
> > };
> >
> > struct bootmenu_entry {
> > @@ -85,6 +88,8 @@ static void bootmenu_print_entry(void *data)
> >
> > if (entry->type == BOOTMENU_TYPE_BOOTMENU)
> > printf("bootmenu_%02d : %ls", entry->bootorder, entry->title);
> > + else if (entry->type == BOOTMENU_TYPE_UEFI_BOOT_OPTION)
> > + printf("UEFI BOOT%04X : %ls", entry->bootorder, entry->title);
>
> Please, remove this hunk.
Thank you for requesting to merge this patch into u-boot/master.
You have removed the "UEFI BOOTXXXX" prefix from
the bootmenu title, but the commit message still says that there is
"UEFI BOOTXXXX" prefix for UEFI entries.
Thanks,
Masahisa Kojima
>
> Best regards
>
> Heinrich
>
> > else
> > printf("%ls", entry->title);
> >
> > @@ -371,6 +376,95 @@ static int prepare_bootmenu_entry(struct bootmenu_data *menu,
> > return 1;
> > }
> >
> > +/**
> > + * prepare_uefi_bootorder_entry() - generate the uefi bootmenu entries
> > + *
> > + * This function read the "BootOrder" UEFI variable
> > + * and generate the bootmenu entries in the order of "BootOrder".
> > + *
> > + * @menu: pointer to the bootmenu structure
> > + * @current: pointer to the last bootmenu entry list
> > + * @index: pointer to the index of the last bootmenu entry,
> > + * the number of uefi entry is added by this function
> > + * Return: 1 on success, negative value on error
> > + */
> > +static int prepare_uefi_bootorder_entry(struct bootmenu_data *menu,
> > + struct bootmenu_entry **current,
> > + unsigned short int *index)
> > +{
> > + u16 *bootorder;
> > + efi_status_t ret;
> > + unsigned short j;
> > + efi_uintn_t num, size;
> > + void *load_option;
> > + struct efi_load_option lo;
> > + u16 varname[] = u"Boot####";
> > + unsigned short int i = *index;
> > + struct bootmenu_entry *entry = NULL;
> > + struct bootmenu_entry *iter = *current;
> > +
> > + bootorder = efi_get_var(u"BootOrder", &efi_global_variable_guid, &size);
> > + if (!bootorder)
> > + return -ENOENT;
> > +
> > + num = size / sizeof(u16);
> > + for (j = 0; j < num; j++) {
> > + entry = malloc(sizeof(struct bootmenu_entry));
> > + if (!entry)
> > + return -ENOMEM;
> > +
> > + efi_create_indexed_name(varname, sizeof(varname),
> > + "Boot", bootorder[j]);
> > + load_option = efi_get_var(varname, &efi_global_variable_guid, &size);
> > + if (!load_option)
> > + continue;
> > +
> > + ret = efi_deserialize_load_option(&lo, load_option, &size);
> > + if (ret != EFI_SUCCESS) {
> > + log_warning("Invalid load option for %ls\n", varname);
> > + free(load_option);
> > + free(entry);
> > + continue;
> > + }
> > +
> > + if (lo.attributes & LOAD_OPTION_ACTIVE) {
> > + entry->title = u16_strdup(lo.label);
> > + if (!entry->title) {
> > + free(load_option);
> > + free(entry);
> > + free(bootorder);
> > + return -ENOMEM;
> > + }
> > + entry->command = strdup("bootefi bootmgr");
> > + sprintf(entry->key, "%d", i);
> > + entry->num = i;
> > + entry->menu = menu;
> > + entry->type = BOOTMENU_TYPE_UEFI_BOOT_OPTION;
> > + entry->bootorder = bootorder[j];
> > + entry->next = NULL;
> > +
> > + if (!iter)
> > + menu->first = entry;
> > + else
> > + iter->next = entry;
> > +
> > + iter = entry;
> > + i++;
> > + }
> > +
> > + free(load_option);
> > +
> > + if (i == MAX_COUNT - 1)
> > + break;
> > + }
> > +
> > + free(bootorder);
> > + *index = i;
> > + *current = iter;
> > +
> > + return 1;
> > +}
> > +
> > static struct bootmenu_data *bootmenu_create(int delay)
> > {
> > int ret;
> > @@ -396,6 +490,14 @@ static struct bootmenu_data *bootmenu_create(int delay)
> > if (ret < 0)
> > goto cleanup;
> >
> > + if (IS_ENABLED(CONFIG_CMD_BOOTEFI_BOOTMGR)) {
> > + if (i < MAX_COUNT - 1) {
> > + ret = prepare_uefi_bootorder_entry(menu, &iter, &i);
> > + if (ret < 0 && ret != -ENOENT)
> > + goto cleanup;
> > + }
> > + }
> > +
> > /* Add U-Boot console entry at the end */
> > if (i <= MAX_COUNT - 1) {
> > entry = malloc(sizeof(struct bootmenu_entry));
> > @@ -473,6 +575,31 @@ static void menu_display_statusline(struct menu *m)
> > puts(ANSI_CLEAR_LINE);
> > }
> >
> > +static void handle_uefi_bootnext(void)
> > +{
> > + u16 bootnext;
> > + efi_status_t ret;
> > + efi_uintn_t size;
> > +
> > + /* Initialize EFI drivers */
> > + ret = efi_init_obj_list();
> > + if (ret != EFI_SUCCESS) {
> > + log_err("Error: Cannot initialize UEFI sub-system, r = %lu\n",
> > + ret & ~EFI_ERROR_MASK);
> > +
> > + return;
> > + }
> > +
> > + /* If UEFI BootNext variable is set, boot the BootNext load option */
> > + size = sizeof(u16);
> > + ret = efi_get_variable_int(u"BootNext",
> > + &efi_global_variable_guid,
> > + NULL, &size, &bootnext, NULL);
> > + if (ret == EFI_SUCCESS)
> > + /* BootNext does exist here, try to boot */
> > + run_command("bootefi bootmgr", 0);
> > +}
> > +
> > static void bootmenu_show(int delay)
> > {
> > int init = 0;
> > @@ -482,8 +609,12 @@ static void bootmenu_show(int delay)
> > struct menu *menu;
> > struct bootmenu_data *bootmenu;
> > struct bootmenu_entry *iter;
> > + efi_status_t efi_ret = EFI_SUCCESS;
> > char *option, *sep;
> >
> > + if (IS_ENABLED(CONFIG_CMD_BOOTEFI_BOOTMGR))
> > + handle_uefi_bootnext();
> > +
> > /* If delay is 0 do not create menu, just run first entry */
> > if (delay == 0) {
> > option = bootmenu_getoption(0);
> > @@ -532,6 +663,27 @@ static void bootmenu_show(int delay)
> > command = strdup(iter->command);
> > }
> >
> > + /*
> > + * If the selected entry is UEFI BOOT####, set the BootNext variable.
> > + * Then uefi bootmgr is invoked by the preset command in iter->command.
> > + */
> > + if (IS_ENABLED(CONFIG_CMD_BOOTEFI_BOOTMGR)) {
> > + if (iter->type == BOOTMENU_TYPE_UEFI_BOOT_OPTION) {
> > + /*
> > + * UEFI specification requires BootNext variable needs non-volatile
> > + * attribute, but this BootNext is only used inside of U-Boot and
> > + * removed by efi bootmgr once BootNext is processed.
> > + * So this BootNext can be volatile.
> > + */
> > + efi_ret = efi_set_variable_int(u"BootNext", &efi_global_variable_guid,
> > + EFI_VARIABLE_BOOTSERVICE_ACCESS |
> > + EFI_VARIABLE_RUNTIME_ACCESS,
> > + sizeof(u16), &iter->bootorder, false);
> > + if (efi_ret != EFI_SUCCESS)
> > + goto cleanup;
> > + }
> > + }
> > +
> > cleanup:
> > menu_destroy(menu);
> > bootmenu_destroy(bootmenu);
> > @@ -545,7 +697,8 @@ cleanup:
> > if (title && command) {
> > debug("Starting entry '%ls'\n", title);
> > free(title);
> > - run_command(command, 0);
> > + if (efi_ret == EFI_SUCCESS)
> > + run_command(command, 0);
> > free(command);
> > }
> >
>
More information about the U-Boot
mailing list