@@ -70,6 +70,12 @@ struct efi_bootmenu_item {
void *data;
};
+struct efi_bootmenu_boot_selection_data {
+ u16 bootorder_index;
+ void *load_option;
+ int *selected;
+};
+
struct efi_bootmenu_boot_option {
struct efi_simple_file_system_protocol *current_volume;
struct efi_device_path *dp_volume;
@@ -322,6 +328,89 @@ out:
return ret;
}
+static efi_status_t efi_bootmenu_process_boot_selected(void *data, bool *exit)
+{
+ struct efi_bootmenu_boot_selection_data *info = data;
+
+ *exit = true;
+
+ if (info)
+ *info->selected = info->bootorder_index;
+
+ return EFI_SUCCESS;
+}
+
+static efi_status_t efi_bootmenu_show_boot_selection(u16 *bootorder, efi_uintn_t count,
+ int *selected)
+{
+ u32 i;
+ efi_status_t ret;
+ efi_uintn_t size;
+ void *load_option;
+ struct efi_load_option lo;
+ u16 varname[] = u"Boot####";
+ struct efi_bootmenu_item *menu_item, *iter;
+
+ menu_item = calloc(count + 1, sizeof(struct efi_bootmenu_item));
+ if (!menu_item) {
+ ret = EFI_OUT_OF_RESOURCES;
+ goto out;
+ }
+
+ iter = menu_item;
+ for (i = 0; i < count; i++) {
+ efi_create_indexed_name(varname, sizeof(varname),
+ "Boot", bootorder[i]);
+ 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);
+ continue;
+ }
+
+ if (lo.attributes & LOAD_OPTION_ACTIVE) {
+ struct efi_bootmenu_boot_selection_data *info;
+
+ info = calloc(1, sizeof(struct efi_bootmenu_boot_selection_data));
+ if (!info) {
+ ret = EFI_OUT_OF_RESOURCES;
+ goto out;
+ }
+
+ info->bootorder_index = i;
+ info->load_option = load_option;
+ info->selected = selected;
+ iter->title = lo.label;
+ iter->func = efi_bootmenu_process_boot_selected;
+ iter->data = info;
+ iter++;
+ }
+ }
+
+ /* add "Quit" entry */
+ iter->title = u"Quit";
+ iter->func = NULL;
+ iter->data = NULL;
+ count += 1;
+
+ ret = efi_bootmenu_process_common(menu_item, count, -1);
+
+out:
+ iter = menu_item;
+ for (i = 0; i < count - 1; i++, iter++) {
+ free(((struct efi_bootmenu_boot_selection_data *)iter->data)->load_option);
+ free(iter->data);
+ }
+
+ free(menu_item);
+
+ return ret;
+}
+
static efi_status_t efi_bootmenu_volume_selected(void *data, bool *exit)
{
struct efi_bootmenu_volume_entry_data *info = data;
@@ -817,6 +906,58 @@ out:
return ret;
}
+static efi_status_t delete_boot_option(u16 *bootorder, u16 index, efi_uintn_t size)
+{
+ u16 var_name[9];
+ efi_status_t ret;
+ efi_uintn_t num;
+
+ efi_create_indexed_name(var_name, sizeof(var_name),
+ "Boot", bootorder[index]);
+ ret = efi_set_variable_int(var_name, &efi_global_variable_guid,
+ 0, 0, NULL, false);
+ if (ret != EFI_SUCCESS) {
+ log_err("delete boot option(%ls) failed\n", var_name);
+ return ret;
+ }
+
+ /* update BootOrder */
+ num = size / sizeof(u16);
+ memmove(&bootorder[index], &bootorder[index + 1],
+ (num - index - 1) * sizeof(u16));
+ size -= 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, bootorder, false);
+
+ return ret;
+}
+
+static efi_status_t efi_bootmenu_process_delete_boot_option(void *data, bool *exit)
+{
+ int selected;
+ u16 *bootorder;
+ efi_status_t ret;
+ efi_uintn_t num, size;
+
+ bootorder = efi_get_var(u"BootOrder", &efi_global_variable_guid, &size);
+ if (!bootorder) {
+ ret = EFI_NOT_FOUND;
+ return ret;
+ }
+
+ num = size / sizeof(u16);
+ ret = efi_bootmenu_show_boot_selection(bootorder, num, &selected);
+ if (ret == EFI_SUCCESS)
+ ret = delete_boot_option(bootorder, selected, size);
+
+ free(bootorder);
+
+ return ret;
+}
+
static efi_status_t efi_bootmenu_init(void)
{
efi_status_t ret;
@@ -845,6 +986,7 @@ static efi_status_t efi_bootmenu_init(void)
static const struct efi_bootmenu_item maintenance_menu_items[] = {
{u"Add Boot Option", efi_bootmenu_process_add_boot_option},
+ {u"Delete Boot Option", efi_bootmenu_process_delete_boot_option},
{u"Quit", NULL},
};
This commit adds the menu-driven deletion of UEFI boot variable. Signed-off-by: Masahisa Kojima <masahisa.kojima@linaro.org> --- Changes in v5: - split into the separate patch lib/efi_loader/efi_bootmenu_maintenance.c | 142 ++++++++++++++++++++++ 1 file changed, 142 insertions(+)