From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id AFBF7C433EF for ; Thu, 31 Mar 2022 08:48:34 +0000 (UTC) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id C7BB58417E; Thu, 31 Mar 2022 10:48:31 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="xl1L0X3i"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 31D4E8417E; Thu, 31 Mar 2022 10:48:29 +0200 (CEST) Received: from mail-wr1-x42a.google.com (mail-wr1-x42a.google.com [IPv6:2a00:1450:4864:20::42a]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 31EF183C6D for ; Thu, 31 Mar 2022 10:48:19 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=ilias.apalodimas@linaro.org Received: by mail-wr1-x42a.google.com with SMTP id h23so32685242wrb.8 for ; Thu, 31 Mar 2022 01:48:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to; bh=u+f+coS4dH3TYDSAc5iQEIvEB6OF0EyP2lGRqN1bLuc=; b=xl1L0X3iB5dDLnUZDPIQ/iLIv+mwE08zdWnemK+VbvW2TPCnCzEbTWxfB4SHVWUw5B zchE4h7grkDI3TPdH5xRJSV+xBx49D6RkcsTX0hY7lNzjUk28Mrv7yU2FR20oYf5sRO5 0gPTlsvonRtVNDACnPeAl0PopVYExZFBDzRMyaR8sIlY3Ap0zX5EVSeaBSpYinL2eisO vyDLxqsn03aLBjw7WcgAsHrqpqMlt7ba4ak31kJg7SsyXni2au/ESCCbcojnMkYJng1Y SnVyzTK0B2aAksZy19aKGZuV7geslCPVhliSnbPLtzxMpdhv3I9bGgeAs2GBYo8DMrAn yZ6Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to; bh=u+f+coS4dH3TYDSAc5iQEIvEB6OF0EyP2lGRqN1bLuc=; b=fib+LimwGFO1jmmMm/dIsQF6TPFraUToGTee1YJ9jaX0IXasGcGkQIGMQdhBYee0Ya V2C5IpFqDLCa+rB3h9/u4YoO+fzPZQuBnCQRR7Ifeuk3cSVrRKlh+48k3Z8b5qCSQtk7 tIs6c5Z80cMdj4woU34gtmZirIciVK/YOmA9kGWpgK62JWMVZi4X7HEZtnempE+49qIM s3QuhEHwICqadQM9y/7KyOzS4l1pPyb8o/TI3Yoh/FheuzGm8BBj71PlpIEvT2Eg2pyP xtTmLUylYE4zaeVMBwGl97EtxQTLYYWf7M5uukbKB/swSvXkueXqpZ40CX95FDMZd6dI GXgA== X-Gm-Message-State: AOAM532ZmbIap/k4TVpgdmo03smcICeW/GCKKwXMoRrJwiIt9Jc2yWrW 7fBJTWTDwUU50GRfungTQNitlw== X-Google-Smtp-Source: ABdhPJyWEwnGToa1DXJ8DJ6I6JiGA4My79qucr9Rt3Hdx85r5M9edyqoHoi7I8rdL2S1ztSDfwojWg== X-Received: by 2002:a5d:6244:0:b0:1e7:686d:41e7 with SMTP id m4-20020a5d6244000000b001e7686d41e7mr3298340wrv.491.1648716498627; Thu, 31 Mar 2022 01:48:18 -0700 (PDT) Received: from hades (athedsl-4461682.home.otenet.gr. [94.71.4.98]) by smtp.gmail.com with ESMTPSA id o19-20020a05600c511300b0038d0d8f67e5sm6865968wms.16.2022.03.31.01.48.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 31 Mar 2022 01:48:18 -0700 (PDT) Date: Thu, 31 Mar 2022 11:48:15 +0300 From: Ilias Apalodimas To: Masahisa Kojima Cc: u-boot@lists.denx.de, Heinrich Schuchardt , Simon Glass , Takahiro Akashi , Francois Ozog , Mark Kettenis Subject: Re: [PATCH v4 10/11] bootmenu: add removable media entries Message-ID: References: <20220324135443.1571-1-masahisa.kojima@linaro.org> <20220324135443.1571-11-masahisa.kojima@linaro.org> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20220324135443.1571-11-masahisa.kojima@linaro.org> X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.5 at phobos.denx.de X-Virus-Status: Clean On Thu, Mar 24, 2022 at 10:54:42PM +0900, Masahisa Kojima wrote: > UEFI specification requires booting from removal media using > a architecture-specific default image name such as BOOTAA64.EFI. > This commit adds the removable media entries into bootmenu, > so that user can select the removable media and boot with > default image. > > The bootmenu automatically enumerates the possible bootable > media devices supporting EFI_SIMPLE_FILE_SYSTEM_PROTOCOL, > add it as new UEFI boot option(BOOT####) and update BootOrder > variable. Depending on the system hardware setup, some devices > may not exist at a later system boot, so invalid BOOT#### variable > must be deleted. > > Signed-off-by: Masahisa Kojima > --- > Newly created in v4 > > cmd/bootmenu.c | 78 +++++++++++++ > include/efi_loader.h | 22 ++++ > lib/efi_loader/efi_bootmenu_maintenance.c | 128 ++++++++++++++++++++++ > 3 files changed, 228 insertions(+) > > diff --git a/cmd/bootmenu.c b/cmd/bootmenu.c > index 458eb90b63..7357cfeae5 100644 > --- a/cmd/bootmenu.c > +++ b/cmd/bootmenu.c > @@ -304,6 +304,74 @@ static int prepare_uefi_bootorder_entry(struct bootmenu_data *menu, > return 1; > } > > +static efi_status_t prepare_media_device_entry(void) > +{ > + u32 i; > + efi_status_t ret; > + efi_uintn_t count; > + efi_handle_t *volume_handles = NULL; > + struct efi_bootmenu_media_boot_option *opt = NULL; > + > + ret = efi_locate_handle_buffer_int(BY_PROTOCOL, &efi_simple_file_system_protocol_guid, > + NULL, &count, (efi_handle_t **)&volume_handles); > + if (ret != EFI_SUCCESS) > + return ret; > + > + opt = calloc(count, sizeof(struct efi_bootmenu_media_boot_option)); > + if (!opt) > + goto out; > + > + /* enumerate all devices supporting EFI_SIMPLE_FILE_SYSTEM_PROTOCOL */ > + ret = efi_bootmenu_enumerate_boot_option(opt, volume_handles, count); > + if (ret != EFI_SUCCESS) > + goto out; > + > + /* > + * System hardware configuration may vary depending on the user setup. > + * The boot option is automatically added by the bootmenu. > + * If the device is not attached to the system, the boot option needs > + * to be deleted. > + */ > + ret = efi_bootmenu_delete_invalid_boot_option(opt, count); Won't that fail on first boot if the BootOrder is undefined? efi_bootmenu_delete_invalid_boot_option() should return EFI_SUCCESS if it doesn't have a boot order maybe? > + if (ret != EFI_SUCCESS) > + goto out; > + > + /* add non-existent boot option */ > + for (i = 0; i < count; i++) { > + u32 boot_index; > + u16 var_name[9]; > + > + if (!opt[i].exist) { > + ret = efi_bootmenu_get_unused_bootoption(var_name, sizeof(var_name), > + &boot_index); > + if (ret != EFI_SUCCESS) > + goto out; > + > + ret = efi_set_variable_int(var_name, &efi_global_variable_guid, > + EFI_VARIABLE_NON_VOLATILE | > + EFI_VARIABLE_BOOTSERVICE_ACCESS | > + EFI_VARIABLE_RUNTIME_ACCESS, > + opt[i].size, opt[i].lo, false); > + if (ret != EFI_SUCCESS) > + goto out; > + > + ret = efi_bootmenu_append_bootorder(boot_index); > + if (ret != EFI_SUCCESS) > + goto out; > + } > + } > + > +out: > + if (opt) { > + for (i = 0; i < count; i++) > + free(opt[i].lo); > + } > + free(opt); > + efi_free_pool(volume_handles); > + > + return ret; > +} > + > static int prepare_distro_boot_entry(struct bootmenu_data *menu, > struct bootmenu_entry **current, > unsigned short int *index) > @@ -408,6 +476,16 @@ static struct bootmenu_data *bootmenu_create(int delay) > goto cleanup; > > if (IS_ENABLED(CONFIG_CMD_BOOTEFI_BOOTMGR)) { > + if (i < MAX_DYNAMIC_ENTRY) { > + /* > + * UEFI specification requires booting from removal media using > + * a architecture-specific default image name such as BOOTAA64.EFI. > + */ > + ret = prepare_media_device_entry(); > + if (ret != EFI_SUCCESS) > + goto cleanup; > + } > + > if (i < MAX_DYNAMIC_ENTRY) { > ret = prepare_uefi_bootorder_entry(menu, &iter, &i); > if (ret < 0 && ret != -ENOENT) > diff --git a/include/efi_loader.h b/include/efi_loader.h > index 7b100ca030..c326dfdaf2 100644 > --- a/include/efi_loader.h > +++ b/include/efi_loader.h > @@ -926,6 +926,22 @@ struct efi_signature_store { > struct x509_certificate; > struct pkcs7_message; > > +/** > + * struct efi_bootmenu_media_boot_option - boot option for (removable) media device > + * > + * This structure is used to enumerate possible boot option > + * > + * @lo: Serialized load option data > + * @size: Size of serialized load option data > + * @exist: Flag to indicate the load option already exists > + * in Non-volatile load option > + */ > +struct efi_bootmenu_media_boot_option { > + void *lo; > + efi_uintn_t size; > + bool exist; > +}; > + > bool efi_signature_lookup_digest(struct efi_image_regions *regs, > struct efi_signature_store *db, > bool dbx); > @@ -1038,6 +1054,12 @@ efi_status_t efi_console_get_u16_string > efi_status_t efi_bootmenu_get_unused_bootoption(u16 *buf, > efi_uintn_t buf_size, u32 *index); > efi_status_t efi_bootmenu_append_bootorder(u16 index); > +efi_status_t efi_bootmenu_enumerate_boot_option( > + struct efi_bootmenu_media_boot_option *opt, > + efi_handle_t *volume_handles, efi_status_t count); > +efi_status_t efi_bootmenu_delete_invalid_boot_option( > + struct efi_bootmenu_media_boot_option *opt, > + efi_status_t count); > > efi_status_t efi_disk_get_device_name(struct efi_block_io *this, char *buf, int size); > > diff --git a/lib/efi_loader/efi_bootmenu_maintenance.c b/lib/efi_loader/efi_bootmenu_maintenance.c > index 2ce5a47b10..3a64cf767a 100644 > --- a/lib/efi_loader/efi_bootmenu_maintenance.c > +++ b/lib/efi_loader/efi_bootmenu_maintenance.c > @@ -24,6 +24,8 @@ static struct efi_simple_text_output_protocol *cout; > #define EFI_BOOTMENU_FILE_PATH_MAX 512 > #define EFI_BOOTMENU_BOOT_NAME_MAX 32 > #define EFI_BOOT_ORDER_MAX_SIZE_IN_DECIMAL 6 > +#define BOOTMENU_AUTO_ADD_OPTION_DATA "bootmenu" > +#define BOOTMENU_AUTO_ADD_OPTION_DATA_U16 u"bootmenu" > > typedef efi_status_t (*efi_bootmenu_entry_func)(void *data, bool *exit); > > @@ -1114,3 +1116,129 @@ efi_status_t efi_bootmenu_show_maintenance_menu(void) > ARRAY_SIZE(maintenance_menu_items), > -1); > } > + > +efi_status_t efi_bootmenu_enumerate_boot_option( > + struct efi_bootmenu_media_boot_option *opt, > + efi_handle_t *volume_handles, efi_status_t count) > +{ > + u32 i; > + struct efi_handler *handler; > + efi_status_t ret = EFI_SUCCESS; > + > + for (i = 0; i < count; i++) { > + u16 *dev_name, *p; > + struct efi_load_option lo; > + struct efi_block_io *block_io; > + char buf[BOOTMENU_DEVICE_NAME_MAX]; > + struct efi_device_path *device_path; > + > + ret = efi_search_protocol(volume_handles[i], &efi_guid_device_path, &handler); > + if (ret != EFI_SUCCESS) > + continue; > + ret = efi_protocol_open(handler, (void **)&device_path, > + efi_root, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); > + if (ret != EFI_SUCCESS) > + continue; > + > + ret = efi_search_protocol(volume_handles[i], &efi_block_io_guid, &handler); > + if (ret != EFI_SUCCESS) > + continue; > + ret = efi_protocol_open(handler, (void **)&block_io, > + efi_root, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); > + if (ret != EFI_SUCCESS) > + continue; > + > + efi_disk_get_device_name(block_io, buf, BOOTMENU_DEVICE_NAME_MAX); > + dev_name = calloc(1, (strlen(buf) + 1) * sizeof(u16)); > + if (!dev_name) { > + ret = EFI_OUT_OF_RESOURCES; > + goto out; > + } > + p = dev_name; > + utf8_utf16_strncpy(&p, buf, strlen(buf)); > + > + lo.label = dev_name; > + lo.attributes = LOAD_OPTION_ACTIVE; > + lo.file_path = device_path; > + lo.file_path_length = efi_dp_size(device_path) + sizeof(END); > + /* > + * To identify the boot option that automatically added by > + * the bootmenu, optional_data has special string. > + * optional_data will be converted into u16 string > + * in efi_serialize_load_option(). > + */ > + lo.optional_data = BOOTMENU_AUTO_ADD_OPTION_DATA; > + opt[i].size = efi_serialize_load_option(&lo, (u8 **)&opt[i].lo); > + if (!opt[i].size) { > + ret = EFI_OUT_OF_RESOURCES; > + free(dev_name); > + goto out; > + } > + free(dev_name); > + } > + > +out: > + return ret; > +} > + > +efi_status_t efi_bootmenu_delete_invalid_boot_option( > + struct efi_bootmenu_media_boot_option *opt, > + efi_status_t count) > +{ > + u16 *bootorder; > + u32 i, j; > + efi_status_t ret; > + efi_uintn_t num, size, bootorder_size; > + void *load_option; > + struct efi_load_option lo; > + u16 varname[] = u"Boot####"; > + > + bootorder = efi_get_var(u"BootOrder", &efi_global_variable_guid, &bootorder_size); > + if (!bootorder) > + return EFI_NOT_FOUND; > + > + num = bootorder_size / sizeof(u16); > + for (i = 0; i < num;) { > + efi_uintn_t tmp; > + > + efi_create_indexed_name(varname, sizeof(varname), > + "Boot", bootorder[i]); > + load_option = efi_get_var(varname, &efi_global_variable_guid, &size); > + if (!load_option) > + goto next; > + > + tmp = size; > + ret = efi_deserialize_load_option(&lo, load_option, &tmp); > + if (ret != EFI_SUCCESS) > + goto next; > + > + if (u16_strncmp((u16 *)lo.optional_data, BOOTMENU_AUTO_ADD_OPTION_DATA_U16, You should convert the lo.optional_data to a u16 before doing the check here, other wise this might cause an unaligned access > + u16_strlen(BOOTMENU_AUTO_ADD_OPTION_DATA_U16)) == 0) { > + for (j = 0; j < count; j++) { > + if (memcmp(opt[j].lo, load_option, size) == 0) { > + opt[j].exist = true; > + break; > + } > + } > + > + if (j == count) { > + ret = delete_boot_option(bootorder, i, bootorder_size); > + if (ret != EFI_SUCCESS) { > + free(load_option); > + goto out; > + } > + > + num--; > + bootorder_size -= sizeof(u16); > + free(load_option); > + continue; > + } > + } > +next: > + free(load_option); > + i++; > + } > + > +out: > + return ret; > +} > -- > 2.17.1 > Thanks /Ilias