[PATCH v11 4/9] eficonfig: add "Change Boot Order" menu entry

Heinrich Schuchardt xypron.glpk at gmx.de
Thu Aug 18 08:50:01 CEST 2022


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.

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