From patchwork Mon May 16 11:00:37 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahisa Kojima X-Patchwork-Id: 572969 Delivered-To: patch@linaro.org Received: by 2002:a5d:5051:0:0:0:0:0 with SMTP id h17csp499763wrt; Mon, 16 May 2022 04:01:54 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwAlEt8+CPCuPYuh96fEcJAqqZdQHPTg1y63kZXsfGhx7TBkxi8nDWL3uD42bEry1f37Txu X-Received: by 2002:a05:6512:3b26:b0:473:a671:eff2 with SMTP id f38-20020a0565123b2600b00473a671eff2mr13381484lfv.500.1652698914193; Mon, 16 May 2022 04:01:54 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1652698914; cv=none; d=google.com; s=arc-20160816; b=kMfhS4YmZkRCQk+sX9vr0WA0b8zuiTR13il4cS1Nnehl4AIj1ifEfdNK27R3SB584U vbggShfPI/YBcT6eqIw4/tT6qYo3M8EXU2luos4foQglADRWLSTrgNcdImn0W5Svq3fK kU3nIhfimlQiBJGNLWybYe278DjSWXQmBXMnkGWRT+dsc7CW40vy9jiWDOskZdjW51oi TRJE+yECSndeTpaA4eHRuIySSv2IzS30ARY6TKIMsuKt5tC9K9pN4TGws57crOP836MU 6op+HBGYqS8rsy6oyfoLYs6GAatgb0R6J/nrTdzgebgYFaUm86QqQ0PESc+o0YPXR9dO ZfbQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=vIWxRZ/iOuEBylRcVeZpnFYC2w0XokVVbKwZMZh8XOA=; b=nCO/1A4Z8/TMtKdcpHK5qo9u/CMPf4DLiq55MGpslqba7I/E/zu00/GSusL52AuiT0 ih89WOgr4Mor0YGubod+oRBYI1UscA3iFSYQ4MB0iYe4SFMLYpH6R4FXR2HI6kZ13wEr Ui5s5azniDpL2lpJyPCnXIOjf86TWhNfI2wzxooZl2AgZs/sSQ6c3AvnlvKPktNfq/vz LVszVBzVqlZJzZdqYawmjblfOshRhbIxeUEBrg2pV5psjsPwyKmRXajFZFrIlPTXv4l+ RdiS+vjva3zJO0oMD8RHGAopWeoooqRkQP7mTZNUIGE5oHnZ7o4Iiy9NGSaLVmwEbXcJ GXBQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=Toi9h4SD; spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 85.214.62.61 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from phobos.denx.de (phobos.denx.de. [85.214.62.61]) by mx.google.com with ESMTPS id g14-20020a2ea4ae000000b0024dd43af724si11295964ljm.317.2022.05.16.04.01.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 16 May 2022 04:01:54 -0700 (PDT) Received-SPF: pass (google.com: domain of u-boot-bounces@lists.denx.de designates 85.214.62.61 as permitted sender) client-ip=85.214.62.61; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=Toi9h4SD; spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 85.214.62.61 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 7B8CD8425D; Mon, 16 May 2022 13:01:39 +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="Toi9h4SD"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id CAF4A8419A; Mon, 16 May 2022 13:00:58 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE,SPF_PASS, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-pj1-x1036.google.com (mail-pj1-x1036.google.com [IPv6:2607:f8b0:4864:20::1036]) (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 91DCA801C3 for ; Mon, 16 May 2022 13:00:29 +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=masahisa.kojima@linaro.org Received: by mail-pj1-x1036.google.com with SMTP id gg20so4051815pjb.1 for ; Mon, 16 May 2022 04:00:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=vIWxRZ/iOuEBylRcVeZpnFYC2w0XokVVbKwZMZh8XOA=; b=Toi9h4SDX1t0R8dksMw77U6j/jFC8sMWHn68BDLIYTZlsk5DzTY7yypYyS04yQTXIG 5b7dLZmae58Gt1E4qLFS7eYRiOVPPEnjV7xRmggKzS4/rwMoczHvkAWH+VF/xvEYUTnW 7+G4r2VzBxKWBMlFlUBIJrfMhRp/yt4/8ylGRbJ7O216KD5KE1eDqAOrGe/vMAecPkGP RxtU1jWSvWhgAoji6hAfuDlRrblIKAINGrvUS+hAQzks5476TE7cmEbPPb5lT111wUP5 TslUZ7TbtFIIFkDuGMeWYEKySLLF9MPoQXADumT9dHYG4fMv1jcA70A98WrtjRR0Q5KT 9e5Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=vIWxRZ/iOuEBylRcVeZpnFYC2w0XokVVbKwZMZh8XOA=; b=jGE14st1PbjgMWvsxBsGmruBNo1hy9cWgQL70VfCqXLTO5Jz6jzb5l+Xd3WalyQWMU 1oDKNhXwWcSJVQTWMdzPe3+4h+8m1m9AaPudVER9RB25Y2hLOpjs5p8HF6kR6LkAESSB 9hXF09QMqE9SynPwM7F32bISH7h0RSLiI8NJ/1yv25rKRsL5ewGsn5JRomiKnjVjn4Zj d+W/pBiB/wASx0W/lw35rYjjaqIbv1QIjCVelHYOFEh4aONuvbK+AIQXRVs7NzU5zOTt cD75WiZnYX+0ktlHJyBAmN4BIUMzitxrev2Y+C//7G0qN7L5iCJ7Ed7l6ERhVbKLY0cE Gcxg== X-Gm-Message-State: AOAM530pC4tGlOW/dmy1tChlHbXfrqdwgaSs4snxed9pjCeMTA2FYhdG N/7WFbnkYoIKq/TNPTH74c0bIoRVZ5nB2w== X-Received: by 2002:a17:90b:4c0a:b0:1dc:e81a:f0c with SMTP id na10-20020a17090b4c0a00b001dce81a0f0cmr19153763pjb.2.1652698827032; Mon, 16 May 2022 04:00:27 -0700 (PDT) Received: from localhost.localdomain ([240d:1a:cf7:5800:82fa:5bff:fe4b:26b1]) by smtp.gmail.com with ESMTPSA id q2-20020a170902edc200b0016173113c50sm2446480plk.92.2022.05.16.04.00.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 16 May 2022 04:00:26 -0700 (PDT) From: Masahisa Kojima To: u-boot@lists.denx.de Cc: Heinrich Schuchardt , Ilias Apalodimas , Simon Glass , Takahiro Akashi , Francois Ozog , Mark Kettenis , Masahisa Kojima Subject: [PATCH v6 1/6] efi_loader: menu-driven addition of UEFI boot option Date: Mon, 16 May 2022 20:00:37 +0900 Message-Id: <20220516110043.31480-2-masahisa.kojima@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220516110043.31480-1-masahisa.kojima@linaro.org> References: <20220516110043.31480-1-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 This commit supports the menu-driven UEFI boot option addition. User can select the block device volume having efi_simple_file_system_protocol and select the file corresponding to the Boot#### variable. Then user enter the label of the BOOT#### variable in utf8. Signed-off-by: Masahisa Kojima --- Changes in v6: - fix typos - modify volume name to match U-Boot syntax - compile in CONFIG_EFI_LOADER=n and CONFIG_CMD_BOOTEFI_BOOTMGR=n - simplify u16_strncmp() usage - support "a\b.efi" file path, use link list to handle filepath - modify length check condition - UEFI related menu items only appears with CONFIG_AUTOBOOT_MENU_SHOW=y Changes in v5: - remove forward declarations - add const qualifier for menu items - fix the possible unaligned access for directory info access - split into three commit 1)add boot option 2) delete boot option 3)change boot order This commit is 1)add boot option. - fix file name buffer allocation size, it should be EFI_BOOTMENU_FILE_PATH_MAX * sizeof(u16) - fix wrong size checking for file selection Chanes in v4: - UEFI boot option maintenance menu is integrated into bootmenu - display the simplified volume name(e.g. usb0:1, nvme1:2) for the volume selection - instead of extending lib/efi_loader/efi_bootmgr.c, newly create lib/efi_loader/efi_bootmenu_maintenance.c and implement boot variable maintenance into it. Changes in RFC v3: not included in v3 series Changes in RFC v2: - enable utf8 user input for boot option name - create lib/efi_loader/efi_console.c::efi_console_get_u16_string() for utf8 user input handling - use u16_strlcat instead of u16_strcat - remove the EFI_CALLs, and newly create or expose the following xxx_int() functions. efi_locate_handle_buffer_int(), efi_open_volume_int(), efi_file_open_int(), efi_file_close_int(), efi_file_read_int() and efi_file_setpos_int(). Note that EFI_CALLs still exist for EFI_DEVICE_PATH_TO_TEXT_PROTOCOL and EFI_SIMPLE_TEXT_INPUT/OUTPUT_PROTOCOL - use efi_search_protocol() instead of calling locate_protocol() to get the device_path_to_text_protocol interface. - remove unnecessary puts(ANSI_CLEAR_LINE), this patch is still depends on puts(ANSI_CLEAR_CONSOLE) - skip SetVariable() if the bootorder is not changed cmd/bootmenu.c | 73 +- include/efi_loader.h | 37 + lib/efi_loader/Makefile | 3 + lib/efi_loader/efi_bootmenu_maintenance.c | 906 ++++++++++++++++++++++ lib/efi_loader/efi_boottime.c | 52 +- lib/efi_loader/efi_console.c | 81 ++ lib/efi_loader/efi_disk.c | 11 + lib/efi_loader/efi_file.c | 75 +- 8 files changed, 1184 insertions(+), 54 deletions(-) create mode 100644 lib/efi_loader/efi_bootmenu_maintenance.c diff --git a/cmd/bootmenu.c b/cmd/bootmenu.c index 8859eebea5..4b846332b0 100644 --- a/cmd/bootmenu.c +++ b/cmd/bootmenu.c @@ -19,6 +19,12 @@ /* maximum bootmenu entries */ #define MAX_COUNT 99 +#if defined(CONFIG_CMD_BOOTEFI_BOOTMGR) && defined(CONFIG_AUTOBOOT_MENU_SHOW) +#define STATIC_ENTRY 2 +#else +#define STATIC_ENTRY 1 +#endif +#define MAX_DYNAMIC_ENTRY (MAX_COUNT - STATIC_ENTRY) /* maximal size of bootmenu env * 9 = strlen("bootmenu_") @@ -38,10 +44,11 @@ enum boot_type { BOOTMENU_TYPE_NONE = 0, BOOTMENU_TYPE_BOOTMENU, BOOTMENU_TYPE_UEFI_BOOT_OPTION, + BOOTMENU_TYPE_UEFI_MAINTENANCE, }; struct bootmenu_entry { - unsigned short int num; /* unique number 0 .. MAX_COUNT */ + unsigned short int num; /* unique number 0 .. (MAX_COUNT - 1) */ char key[3]; /* key identifier of number */ u16 *title; /* title of entry */ char *command; /* hush command of entry */ @@ -55,7 +62,7 @@ static char *bootmenu_getoption(unsigned short int n) { char name[MAX_ENV_SIZE]; - if (n > MAX_COUNT) + if (n > MAX_DYNAMIC_ENTRY) return NULL; sprintf(name, "bootmenu_%d", n); @@ -217,7 +224,7 @@ static int prepare_bootmenu_entry(struct bootmenu_data *menu, iter = entry; ++i; - if (i == MAX_COUNT - 1) + if (i == MAX_DYNAMIC_ENTRY) break; } @@ -305,7 +312,7 @@ static int prepare_uefi_bootorder_entry(struct bootmenu_data *menu, free(load_option); - if (i == MAX_COUNT - 1) + if (i == MAX_DYNAMIC_ENTRY) break; } @@ -341,14 +348,51 @@ 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) { + if (IS_ENABLED(CONFIG_CMD_BOOTEFI_BOOTMGR) && IS_ENABLED(CONFIG_AUTOBOOT_MENU_SHOW)) { + if (i < MAX_DYNAMIC_ENTRY) { ret = prepare_uefi_bootorder_entry(menu, &iter, &i); if (ret < 0 && ret != -ENOENT) goto cleanup; } } + if (IS_ENABLED(CONFIG_CMD_BOOTEFI_BOOTMGR) && IS_ENABLED(CONFIG_AUTOBOOT_MENU_SHOW)) { + /* Add UEFI Boot Manager Maintenance entry */ + if (i <= MAX_DYNAMIC_ENTRY) { + entry = malloc(sizeof(struct bootmenu_entry)); + if (!entry) + goto cleanup; + + entry->title = u16_strdup(u"UEFI Boot Manager Maintenance"); + if (!entry->title) { + free(entry); + goto cleanup; + } + + entry->command = strdup(""); + if (!entry->command) { + free(entry->title); + free(entry); + goto cleanup; + } + + sprintf(entry->key, "%d", i); + + entry->num = i; + entry->menu = menu; + entry->type = BOOTMENU_TYPE_UEFI_MAINTENANCE; + entry->next = NULL; + + if (!iter) + menu->first = entry; + else + iter->next = entry; + + iter = entry; + i++; + } + } + /* Add U-Boot console entry at the end */ if (i <= MAX_COUNT - 1) { entry = malloc(sizeof(struct bootmenu_entry)); @@ -520,6 +564,14 @@ static enum bootmenu_ret bootmenu_show(int delay) title = u16_strdup(iter->title); command = strdup(iter->command); + if (IS_ENABLED(CONFIG_CMD_BOOTEFI_BOOTMGR)) { + if (iter->type == BOOTMENU_TYPE_UEFI_MAINTENANCE) { + efi_bootmenu_show_maintenance_menu(); + ret = BOOTMENU_RET_UPDATED; + goto cleanup; + } + } + /* last entry is U-Boot console or Quit */ if (iter->num == iter->menu->count - 1) { ret = BOOTMENU_RET_QUIT; @@ -610,6 +662,7 @@ int do_bootmenu(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { char *delay_str = NULL; int delay = 10; + int ret; #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) delay = CONFIG_BOOTDELAY; @@ -624,7 +677,13 @@ int do_bootmenu(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) if (delay_str) delay = (int)simple_strtol(delay_str, NULL, 10); - bootmenu_show(delay); + while (1) { + ret = bootmenu_show(delay); + delay = -1; + if (ret != BOOTMENU_RET_UPDATED) + break; + } + return 0; } diff --git a/include/efi_loader.h b/include/efi_loader.h index 733ee03cd7..49f326e585 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -226,6 +226,9 @@ const char *__efi_nesting_dec(void); #define EFI_CACHELINE_SIZE 128 #endif +/* max bootmenu title size for volume selection */ +#define BOOTMENU_DEVICE_NAME_MAX 16 + /* Key identifying current memory map */ extern efi_uintn_t efi_memory_map_key; @@ -314,6 +317,9 @@ extern const efi_guid_t efi_guid_firmware_management_protocol; extern const efi_guid_t efi_esrt_guid; /* GUID of the SMBIOS table */ extern const efi_guid_t smbios_guid; +/*GUID of console */ +extern const efi_guid_t efi_guid_text_input_protocol; +extern const efi_guid_t efi_guid_text_output_protocol; extern char __efi_runtime_start[], __efi_runtime_stop[]; extern char __efi_runtime_rel_start[], __efi_runtime_rel_stop[]; @@ -877,6 +883,8 @@ efi_status_t efi_set_load_options(efi_handle_t handle, void *load_options); efi_status_t efi_bootmgr_load(efi_handle_t *handle, void **load_options); +efi_status_t efi_bootmenu_show_maintenance_menu(void); + /** * struct efi_image_regions - A list of memory regions * @@ -1048,4 +1056,33 @@ efi_status_t efi_esrt_populate(void); efi_status_t efi_load_capsule_drivers(void); efi_status_t platform_get_eventlog(struct udevice *dev, u64 *addr, u32 *sz); + +efi_status_t efi_locate_handle_buffer_int(enum efi_locate_search_type search_type, + const efi_guid_t *protocol, void *search_key, + efi_uintn_t *no_handles, efi_handle_t **buffer); + +efi_status_t efi_open_volume_int(struct efi_simple_file_system_protocol *this, + struct efi_file_handle **root); +efi_status_t efi_file_open_int(struct efi_file_handle *this, + struct efi_file_handle **new_handle, + u16 *file_name, u64 open_mode, + u64 attributes); +efi_status_t efi_file_close_int(struct efi_file_handle *file); +efi_status_t efi_file_read_int(struct efi_file_handle *this, + efi_uintn_t *buffer_size, void *buffer); +efi_status_t efi_file_setpos_int(struct efi_file_handle *file, u64 pos); + +typedef efi_status_t (*efi_console_filter_func)(struct efi_input_key *key); +efi_status_t efi_console_get_u16_string + (struct efi_simple_text_input_protocol *cin, + struct efi_simple_text_output_protocol *cout, + u16 *buf, efi_uintn_t count, efi_console_filter_func filer_func, + int row, int col); + +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_disk_get_device_name(struct efi_block_io *this, char *buf, int size); + #endif /* _EFI_LOADER_H */ diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index aaaa25cefe..807e9a4319 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -77,6 +77,9 @@ obj-$(CONFIG_EFI_TCG2_PROTOCOL) += efi_tcg2.o obj-$(CONFIG_EFI_RISCV_BOOT_PROTOCOL) += efi_riscv.o obj-$(CONFIG_EFI_LOAD_FILE2_INITRD) += efi_load_initrd.o obj-$(CONFIG_EFI_SIGNATURE_SUPPORT) += efi_signature.o +ifeq ($(CONFIG_CMD_BOOTEFI_BOOTMGR),y) +obj-$(CONFIG_CMD_BOOTMENU) += efi_bootmenu_maintenance.o +endif EFI_VAR_SEED_FILE := $(subst $\",,$(CONFIG_EFI_VAR_SEED_FILE)) $(obj)/efi_var_seed.o: $(srctree)/$(EFI_VAR_SEED_FILE) diff --git a/lib/efi_loader/efi_bootmenu_maintenance.c b/lib/efi_loader/efi_bootmenu_maintenance.c new file mode 100644 index 0000000000..e5124a8a21 --- /dev/null +++ b/lib/efi_loader/efi_bootmenu_maintenance.c @@ -0,0 +1,906 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Menu-driven UEFI Boot Variable maintenance + * + * Copyright (c) 2022 Masahisa Kojima, Linaro Limited + */ + +#define LOG_CATEGORY LOGC_EFI + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct efi_simple_text_input_protocol *cin; +static struct efi_simple_text_output_protocol *cout; + +#define EFI_BOOTMENU_ENTRY_NUM_MAX 99 +#define EFI_BOOTMENU_FILE_PATH_MAX 512 +#define EFI_BOOTMENU_FILE_PATH_BUF_SIZE (EFI_BOOTMENU_FILE_PATH_MAX * sizeof(u16)) +#define EFI_BOOTMENU_BOOT_NAME_MAX 32 +#define EFI_BOOT_ORDER_MAX_SIZE_IN_DECIMAL 6 + +typedef efi_status_t (*efi_bootmenu_entry_func)(void *data, bool *exit); + +/** + * struct efi_bootmenu_entry - menu entry structure + * + * @num: menu entry index + * @title: title of entry + * @key: unique key + * @bootmgr_menu: pointer to the menu structure + * @next: pointer to the next entry + * @func: callback function to be called when this entry is selected + * @data: data to be passed to the callback function + */ +struct efi_bootmenu_entry { + u32 num; + u16 *title; + char key[6]; + struct efi_bootmenu *bootmgr_menu; + struct efi_bootmenu_entry *next; + efi_bootmenu_entry_func func; + void *data; +}; + +/** + * struct efi_bootmenu - bootmgr menu structure + * + * @delay: delay for autoboot + * @active: active menu entry index + * @count: total count of menu entry + * @first: pointer to the first menu entry + */ +struct efi_bootmenu { + int delay; + int active; + int count; + struct efi_bootmenu_entry *first; +}; + +struct efi_bootmenu_item { + u16 *title; + efi_bootmenu_entry_func func; + void *data; +}; + +struct efi_bootmenu_boot_selection_data { + u16 bootorder_index; + void *load_option; + int *selected; +}; + +struct efi_bootmenu_filepath_info { + u16 *name; + struct list_head list; +}; + +struct efi_bootmenu_boot_option { + struct efi_simple_file_system_protocol *current_volume; + struct efi_device_path *dp_volume; + u16 *current_path; + struct list_head filepath_list; + u16 *boot_name; + bool file_selected; +}; + +static const struct efi_device_path END = { + .type = DEVICE_PATH_TYPE_END, + .sub_type = DEVICE_PATH_SUB_TYPE_END, + .length = sizeof(END), +}; + +struct efi_bootmenu_volume_entry_data { + struct efi_bootmenu_boot_option *bo; + struct efi_simple_file_system_protocol *v; + struct efi_device_path *dp; +}; + +struct efi_bootmenu_file_entry_data { + struct efi_bootmenu_boot_option *bo; + bool is_directory; + u16 *file_name; +}; + +static void efi_bootmenu_print_entry(void *data) +{ + struct efi_bootmenu_entry *entry = data; + int reverse = (entry->bootmgr_menu->active == entry->num); + + /* TODO: support scroll or page for many entries */ + + /* + * Move cursor to line where the entry will be drawn (entry->count) + * First 3 lines contain bootmgr menu header + one empty line + * For the last "Quit" entry, add one empty line + */ + if (entry->num == (entry->bootmgr_menu->count - 1)) + printf(ANSI_CURSOR_POSITION, entry->num + 5, 1); + else + printf(ANSI_CURSOR_POSITION, entry->num + 4, 1); + + puts(" "); + + if (reverse) + puts(ANSI_COLOR_REVERSE); + + printf("%ls", entry->title); + + if (reverse) + puts(ANSI_COLOR_RESET); +} + +static void efi_bootmenu_display_statusline(struct menu *m) +{ + struct efi_bootmenu_entry *entry; + struct efi_bootmenu *bootmgr_menu; + + if (menu_default_choice(m, (void *)&entry) < 0) + return; + + bootmgr_menu = entry->bootmgr_menu; + + printf(ANSI_CURSOR_POSITION, 1, 1); + puts(ANSI_CLEAR_LINE); + printf(ANSI_CURSOR_POSITION, 2, 1); + puts(" *** U-Boot EFI Boot Manager ***"); + puts(ANSI_CLEAR_LINE_TO_END); + printf(ANSI_CURSOR_POSITION, 3, 1); + puts(ANSI_CLEAR_LINE); + + /* First 3 lines are bootmgr_menu header + 2 empty lines between entries */ + printf(ANSI_CURSOR_POSITION, bootmgr_menu->count + 5, 1); + puts(ANSI_CLEAR_LINE); + printf(ANSI_CURSOR_POSITION, bootmgr_menu->count + 6, 1); + puts(" Press UP/DOWN to move, ENTER to select, ESC/CTRL+C to quit"); + puts(ANSI_CLEAR_LINE_TO_END); + printf(ANSI_CURSOR_POSITION, bootmgr_menu->count + 7, 1); + puts(ANSI_CLEAR_LINE); +} + +static char *efi_bootmenu_choice_entry(void *data) +{ + int i; + int esc = 0; + struct efi_bootmenu_entry *iter; + enum bootmenu_key key = KEY_NONE; + struct efi_bootmenu *bootmgr_menu = data; + + while (1) { + if (bootmgr_menu->delay >= 0) { + /* Autoboot was not stopped */ + bootmenu_autoboot_loop((struct bootmenu_data *)bootmgr_menu, &key, &esc); + } else { + /* Some key was pressed, so autoboot was stopped */ + bootmenu_loop((struct bootmenu_data *)bootmgr_menu, &key, &esc); + } + + if (bootmgr_menu->delay == 0) + key = KEY_QUIT; + + switch (key) { + case KEY_UP: + if (bootmgr_menu->active > 0) + --bootmgr_menu->active; + /* no menu key selected, regenerate menu */ + return NULL; + case KEY_DOWN: + if (bootmgr_menu->active < bootmgr_menu->count - 1) + ++bootmgr_menu->active; + /* no menu key selected, regenerate menu */ + return NULL; + case KEY_SELECT: + iter = bootmgr_menu->first; + for (i = 0; i < bootmgr_menu->active; ++i) + iter = iter->next; + return iter->key; + case KEY_QUIT: + /* Quit by choosing the last entry */ + iter = bootmgr_menu->first; + while (iter->next) + iter = iter->next; + return iter->key; + default: + break; + } + } + + /* never happens */ + debug("bootmgr menu: this should not happen"); + return NULL; +} + +static void efi_bootmenu_destroy(struct efi_bootmenu *bootmgr_menu) +{ + struct efi_bootmenu_entry *next; + struct efi_bootmenu_entry *iter = bootmgr_menu->first; + + while (iter) { + next = iter->next; + free(iter); + iter = next; + } + free(bootmgr_menu); +} + +/** + * efi_bootmenu_process_common() - main handler for uefi bootmgr menu + * + * Construct the structures required to show the menu, then handle + * the user input intracting with u-boot menu functions. + * + * @items: pointer to the structure of each menu entry + * @count: the number of menu entry + * @delay: delay for autoboot/autoselect + * Return: status code + */ +static efi_status_t efi_bootmenu_process_common(const struct efi_bootmenu_item *items, + int count, int delay) +{ + u32 i; + bool exit = false; + efi_status_t ret; + struct menu *menu; + void *choice = NULL; + struct efi_bootmenu_entry *entry; + struct efi_bootmenu *bootmgr_menu; + struct efi_bootmenu_entry *iter = NULL; + + if (count > EFI_BOOTMENU_ENTRY_NUM_MAX) + return EFI_OUT_OF_RESOURCES; + + bootmgr_menu = calloc(1, sizeof(struct efi_bootmenu)); + if (!bootmgr_menu) + return EFI_OUT_OF_RESOURCES; + + bootmgr_menu->delay = delay; + bootmgr_menu->active = 0; + bootmgr_menu->first = NULL; + + for (i = 0; i < count; i++) { + entry = calloc(1, sizeof(struct efi_bootmenu_entry)); + if (!entry) { + ret = EFI_LOAD_ERROR; + goto out; + } + + entry->num = i; + entry->title = items->title; + snprintf(entry->key, sizeof(entry->key), "%04X", i); + entry->bootmgr_menu = bootmgr_menu; + entry->func = items->func; + entry->data = items->data; + entry->next = NULL; + + if (!iter) + bootmgr_menu->first = entry; + else + iter->next = entry; + + iter = entry; + items++; + } + bootmgr_menu->count = count; + + menu = menu_create(NULL, 0, 1, efi_bootmenu_display_statusline, + efi_bootmenu_print_entry, efi_bootmenu_choice_entry, + bootmgr_menu); + if (!menu) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + + for (entry = bootmgr_menu->first; entry; entry = entry->next) { + if (!menu_item_add(menu, entry->key, entry)) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + } + + menu_default_set(menu, bootmgr_menu->first->key); + + while (!exit) { + puts(ANSI_CURSOR_HIDE); + puts(ANSI_CLEAR_CONSOLE); + printf(ANSI_CURSOR_POSITION, 1, 1); + + if (menu_get_choice(menu, &choice)) { + entry = choice; + if (entry->func) + ret = entry->func(entry->data, &exit); + + /* last entry "Quit" is selected, exit this menu */ + if (entry->num == (entry->bootmgr_menu->count - 1)) { + ret = EFI_ABORTED; + break; + } + } + } + +out: + menu_destroy(menu); + efi_bootmenu_destroy(bootmgr_menu); + + puts(ANSI_CLEAR_CONSOLE); + printf(ANSI_CURSOR_POSITION, 1, 1); + puts(ANSI_CURSOR_SHOW); + + return ret; +} + +static efi_status_t efi_bootmenu_volume_selected(void *data, bool *exit) +{ + struct efi_bootmenu_volume_entry_data *info = data; + + *exit = true; + + if (info) { + info->bo->current_volume = info->v; + info->bo->dp_volume = info->dp; + } + + return EFI_SUCCESS; +} + +static efi_status_t efi_bootmenu_file_selected(void *data, bool *exit) +{ + struct efi_bootmenu_file_entry_data *info = data; + + *exit = true; + + if (!info) + return EFI_INVALID_PARAMETER; + + if (u16_strcmp(info->file_name, u".") == 0 && + u16_strlen(info->file_name) == 1) { + /* stay current path */ + } else if (u16_strcmp(info->file_name, u"..") == 0 && + u16_strlen(info->file_name) == 2) { + struct efi_bootmenu_filepath_info *iter; + struct list_head *pos, *n; + int is_last; + + memset(info->bo->current_path, 0, EFI_BOOTMENU_FILE_PATH_BUF_SIZE); + list_for_each_safe(pos, n, &info->bo->filepath_list) { + iter = list_entry(pos, struct efi_bootmenu_filepath_info, list); + + is_last = list_is_last(&iter->list, &info->bo->filepath_list); + if (is_last) { + list_del(&iter->list); + free(iter->name); + free(iter); + break; + } + u16_strlcat(info->bo->current_path, iter->name, + EFI_BOOTMENU_FILE_PATH_MAX); + u16_strlcat(info->bo->current_path, u"\\", + EFI_BOOTMENU_FILE_PATH_MAX); + } + } else { + size_t new_len; + struct efi_bootmenu_filepath_info *filepath; + + new_len = u16_strlen(info->bo->current_path) + + u16_strlen(info->file_name); + if (new_len >= EFI_BOOTMENU_FILE_PATH_MAX) { + /* TODO: show error notification to user */ + log_err("file path is too long\n"); + return EFI_INVALID_PARAMETER; + } + u16_strlcat(info->bo->current_path, info->file_name, + EFI_BOOTMENU_FILE_PATH_MAX); + + filepath = calloc(1, sizeof(struct efi_bootmenu_filepath_info)); + if (!filepath) + return EFI_OUT_OF_RESOURCES; + + filepath->name = u16_strdup(info->file_name); + if (!filepath->name) { + free(filepath); + return EFI_OUT_OF_RESOURCES; + } + list_add_tail(&filepath->list, &info->bo->filepath_list); + + if (info->is_directory) { + /* + * Remainig buffer should have enough space to contain u"\\" and + * at least one character for file name + */ + if (new_len + 2 >= EFI_BOOTMENU_FILE_PATH_MAX) { + log_err("directory path is too long\n"); + return EFI_INVALID_PARAMETER; + } + u16_strlcat(info->bo->current_path, u"\\", + EFI_BOOTMENU_FILE_PATH_MAX); + } else { + info->bo->file_selected = true; + } + } + return EFI_SUCCESS; +} + +static efi_status_t efi_bootmenu_select_volume(struct efi_bootmenu_boot_option *bo) +{ + u32 i; + efi_status_t ret; + efi_uintn_t count; + struct efi_handler *handler; + struct efi_device_path *device_path; + efi_handle_t *volume_handles = NULL; + struct efi_simple_file_system_protocol *v; + struct efi_bootmenu_item *menu_item, *iter; + + 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; + + menu_item = calloc(count + 1, sizeof(struct efi_bootmenu_item)); + if (!menu_item) { + ret = EFI_OUT_OF_RESOURCES; + goto out1; + } + + iter = menu_item; + for (i = 0; i < count; i++) { + u16 *dev_name, *p; + struct efi_block_io *block_io; + char buf[BOOTMENU_DEVICE_NAME_MAX]; + struct efi_bootmenu_volume_entry_data *info; + + ret = efi_search_protocol(volume_handles[i], + &efi_simple_file_system_protocol_guid, &handler); + if (ret != EFI_SUCCESS) + continue; + ret = efi_protocol_open(handler, (void **)&v, efi_root, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret != EFI_SUCCESS) + continue; + + 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; + + info = calloc(1, sizeof(struct efi_bootmenu_volume_entry_data)); + if (!info) { + ret = EFI_OUT_OF_RESOURCES; + goto out2; + } + + efi_disk_get_device_name(block_io, buf, BOOTMENU_DEVICE_NAME_MAX); + dev_name = calloc(1, (strlen(buf) + 1) * sizeof(u16)); + if (!dev_name) { + free(info); + ret = EFI_OUT_OF_RESOURCES; + goto out2; + } + p = dev_name; + utf8_utf16_strncpy(&p, buf, strlen(buf)); + + info->v = v; + info->dp = device_path; + info->bo = bo; + iter->title = dev_name; + iter->func = efi_bootmenu_volume_selected; + iter->data = info; + iter++; + } + + iter->title = u16_strdup(u"Quit"); + iter->func = NULL; + iter->data = NULL; + count += 1; + + ret = efi_bootmenu_process_common(menu_item, count, -1); + +out2: + iter = menu_item; + for (i = 0; i < count; i++) { + struct efi_bootmenu_volume_entry_data *p; + + p = (struct efi_bootmenu_volume_entry_data *)(iter->data); + free(iter->title); + free(p); + iter++; + } + + free(menu_item); + +out1: + efi_free_pool(volume_handles); + + return ret; +} + +static efi_status_t efi_bootmenu_select_file(struct efi_bootmenu_boot_option *bo, + struct efi_file_handle *root) +{ + u32 i; + struct efi_file_info *buf; + u32 count = 0; + efi_uintn_t len; + efi_status_t ret; + struct efi_file_handle *f; + struct efi_bootmenu_item *menu_item, *iter; + + buf = calloc(1, sizeof(struct efi_file_info) + EFI_BOOTMENU_FILE_PATH_BUF_SIZE); + if (!buf) + return EFI_OUT_OF_RESOURCES; + + while (!bo->file_selected) { + count = 0; + + ret = efi_file_open_int(root, &f, bo->current_path, EFI_FILE_MODE_READ, 0); + if (ret != EFI_SUCCESS) + return ret; + + /* calculate directory information total count */ + for (;;) { + len = sizeof(struct efi_file_info) + EFI_BOOTMENU_FILE_PATH_BUF_SIZE; + ret = efi_file_read_int(f, &len, buf); + if (ret != EFI_SUCCESS || len == 0) + break; + + count++; + } + + menu_item = calloc(count + 1, sizeof(struct efi_bootmenu_item)); + if (!menu_item) { + efi_file_close_int(f); + ret = EFI_OUT_OF_RESOURCES; + goto out; + } + + /* read directory and construct menu structure */ + efi_file_setpos_int(f, 0); + iter = menu_item; + for (i = 0; i < count; i++) { + u16 *name; + int name_len; + struct efi_bootmenu_file_entry_data *info; + + len = sizeof(struct efi_file_info) + EFI_BOOTMENU_FILE_PATH_BUF_SIZE; + ret = efi_file_read_int(f, &len, buf); + if (ret != EFI_SUCCESS || len == 0) + goto err; + + info = calloc(1, sizeof(struct efi_bootmenu_file_entry_data)); + if (!info) { + ret = EFI_OUT_OF_RESOURCES; + goto err; + } + + if (buf->attribute & EFI_FILE_DIRECTORY) { + /* append u'/' at the end of directory name */ + name_len = u16_strsize(buf->file_name) + sizeof(u16); + name = calloc(1, name_len); + if (!name) { + ret = EFI_OUT_OF_RESOURCES; + goto err; + } + u16_strcpy(name, buf->file_name); + name[u16_strlen(buf->file_name)] = u'/'; + + info->is_directory = true; + } else { + name_len = u16_strsize(buf->file_name); + name = calloc(1, name_len); + if (!name) { + ret = EFI_OUT_OF_RESOURCES; + goto err; + } + u16_strcpy(name, buf->file_name); + } + + info->file_name = u16_strdup(buf->file_name); + info->bo = bo; + iter->title = name; + iter->func = efi_bootmenu_file_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); +err: + efi_file_close_int(f); + iter = menu_item; + for (i = 0; i < count - 1; i++, iter++) { + free(((struct efi_bootmenu_file_entry_data *)(iter->data))->file_name); + free(iter->title); + free(iter->data); + } + + free(menu_item); + + if (ret != EFI_SUCCESS) + break; + } + +out: + free(buf); + return ret; +} + +static efi_status_t efi_bootmenu_boot_add_enter_name(struct efi_bootmenu_boot_option *bo) +{ + efi_status_t ret; + + printf(ANSI_CURSOR_POSITION, 2, 1); + puts(" *** U-Boot EFI Boot Manager Menu ***"); + printf(ANSI_CURSOR_POSITION, 4, 1); + puts(" enter name:"); + + printf(ANSI_CURSOR_POSITION, 8, 1); + puts(" ENTER to complete, ESC/CTRL+C to quit"); + + ret = efi_console_get_u16_string(cin, cout, bo->boot_name, + EFI_BOOTMENU_BOOT_NAME_MAX, NULL, 4, 15); + + return ret; +} + +static efi_status_t efi_bootmenu_select_file_handler(struct efi_bootmenu_boot_option *bo) +{ + efi_status_t ret; + struct efi_file_handle *root; + + bo->file_selected = false; + + while (!bo->file_selected) { + bo->current_volume = NULL; + memset(bo->current_path, 0, EFI_BOOTMENU_FILE_PATH_BUF_SIZE); + + ret = efi_bootmenu_select_volume(bo); + if (ret != EFI_SUCCESS) + return ret; + + if (!bo->current_volume) + return EFI_INVALID_PARAMETER; + + ret = efi_open_volume_int(bo->current_volume, &root); + if (ret != EFI_SUCCESS) + return ret; + + ret = efi_bootmenu_select_file(bo, root); + if (ret != EFI_SUCCESS) + return ret; + } + + ret = efi_bootmenu_boot_add_enter_name(bo); + + return ret; +} + +efi_status_t efi_bootmenu_get_unused_bootoption(u16 *buf, + efi_uintn_t buf_size, u32 *index) +{ + u32 i; + efi_status_t ret; + efi_uintn_t size; + + if (buf_size < u16_strsize(u"Boot####")) + return EFI_BUFFER_TOO_SMALL; + + for (i = 0; i <= 0xFFFF; i++) { + size = 0; + efi_create_indexed_name(buf, buf_size, "Boot", i); + ret = efi_get_variable_int(buf, &efi_global_variable_guid, + NULL, &size, NULL, NULL); + if (ret == EFI_BUFFER_TOO_SMALL) + continue; + else + break; + } + + if (i > 0xFFFF) + return EFI_OUT_OF_RESOURCES; + + *index = i; + + return EFI_SUCCESS; +} + +static efi_status_t efi_bootmenu_set_boot_option(u16 *var_name, struct efi_device_path *dp, + u16 *label, char *optional_data) +{ + void *p = NULL; + efi_status_t ret; + efi_uintn_t size; + struct efi_load_option lo; + + lo.file_path = dp; + lo.file_path_length = efi_dp_size(dp) + sizeof(END); + lo.attributes = LOAD_OPTION_ACTIVE; + lo.optional_data = optional_data; + lo.label = label; + + size = efi_serialize_load_option(&lo, (u8 **)&p); + if (!size) + return EFI_INVALID_PARAMETER; + + ret = efi_set_variable_int(var_name, &efi_global_variable_guid, + EFI_VARIABLE_NON_VOLATILE | + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, + size, p, false); + free(p); + + return ret; +} + +efi_status_t efi_bootmenu_append_bootorder(u16 index) +{ + u16 *bootorder; + efi_status_t ret; + u16 *new_bootorder = NULL; + efi_uintn_t last, size, new_size; + + /* append new boot option */ + bootorder = efi_get_var(u"BootOrder", &efi_global_variable_guid, &size); + last = size / sizeof(u16); + new_size = size + sizeof(u16); + new_bootorder = calloc(1, new_size); + if (!new_bootorder) { + ret = EFI_OUT_OF_RESOURCES; + goto out; + } + memcpy(new_bootorder, bootorder, size); + new_bootorder[last] = index; + + ret = efi_set_variable_int(u"BootOrder", &efi_global_variable_guid, + EFI_VARIABLE_NON_VOLATILE | + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, + new_size, new_bootorder, false); + if (ret != EFI_SUCCESS) + goto out; + +out: + free(bootorder); + free(new_bootorder); + + return ret; +} + +static efi_status_t efi_bootmenu_process_add_boot_option(void *data, bool *exit) +{ + u32 index; + u16 var_name[9]; + char *buf = NULL; + efi_status_t ret; + char *iter = NULL; + struct list_head *pos, *n; + efi_uintn_t dp_size, fp_size; + struct efi_bootmenu_boot_option bo; + struct efi_device_path_file_path *fp; + struct efi_bootmenu_filepath_info *item; + + ret = efi_bootmenu_get_unused_bootoption(var_name, sizeof(var_name), + &index); + if (ret != EFI_SUCCESS) + return ret; + + bo.current_path = calloc(1, EFI_BOOTMENU_FILE_PATH_BUF_SIZE); + if (!bo.current_path) + goto out; + + bo.boot_name = calloc(1, EFI_BOOTMENU_BOOT_NAME_MAX * sizeof(u16)); + if (!bo.boot_name) + goto out; + + INIT_LIST_HEAD(&bo.filepath_list); + + ret = efi_bootmenu_select_file_handler(&bo); + if (ret != EFI_SUCCESS) + goto out; + + dp_size = efi_dp_size(bo.dp_volume); + fp_size = sizeof(struct efi_device_path) + + ((u16_strlen(bo.current_path) + 1) * sizeof(u16)); + buf = calloc(1, dp_size + fp_size + sizeof(END)); + if (!buf) + goto out; + + iter = buf; + memcpy(iter, bo.dp_volume, dp_size); + iter += dp_size; + + fp = (struct efi_device_path_file_path *)iter; + fp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE; + fp->dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH; + fp->dp.length = (u16)fp_size; + u16_strcpy(fp->str, bo.current_path); + iter += fp_size; + *((struct efi_device_path *)iter) = END; + + ret = efi_bootmenu_set_boot_option(var_name, (struct efi_device_path *)buf, + bo.boot_name, NULL); + if (ret != EFI_SUCCESS) + goto out; + + efi_bootmenu_append_bootorder((u16)index); + if (ret != EFI_SUCCESS) + goto out; + +out: + free(buf); + free(bo.boot_name); + free(bo.current_path); + + list_for_each_safe(pos, n, &bo.filepath_list) { + item = list_entry(pos, struct efi_bootmenu_filepath_info, list); + list_del(&item->list); + free(item->name); + free(item); + } + + return ret; +} + +static efi_status_t efi_bootmenu_init(void) +{ + efi_status_t ret; + struct efi_handler *handler; + + ret = efi_search_protocol(efi_root, &efi_guid_text_input_protocol, &handler); + if (ret != EFI_SUCCESS) + return ret; + + ret = efi_protocol_open(handler, (void **)&cin, efi_root, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret != EFI_SUCCESS) + return ret; + + ret = efi_search_protocol(efi_root, &efi_guid_text_output_protocol, &handler); + if (ret != EFI_SUCCESS) + return ret; + + ret = efi_protocol_open(handler, (void **)&cout, efi_root, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret != EFI_SUCCESS) + return ret; + + return ret; +} + +static const struct efi_bootmenu_item maintenance_menu_items[] = { + {u"Add Boot Option", efi_bootmenu_process_add_boot_option}, + {u"Quit", NULL}, +}; + +efi_status_t efi_bootmenu_show_maintenance_menu(void) +{ + efi_status_t ret; + + ret = efi_bootmenu_init(); + if (ret != EFI_SUCCESS) + return ret; + + return efi_bootmenu_process_common(maintenance_menu_items, + ARRAY_SIZE(maintenance_menu_items), + -1); +} diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 4da64b5d29..1233418e77 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -2453,6 +2453,35 @@ static efi_status_t EFIAPI efi_protocols_per_handle( return EFI_EXIT(EFI_SUCCESS); } +efi_status_t efi_locate_handle_buffer_int(enum efi_locate_search_type search_type, + const efi_guid_t *protocol, void *search_key, + efi_uintn_t *no_handles, efi_handle_t **buffer) +{ + efi_status_t r; + efi_uintn_t buffer_size = 0; + + if (!no_handles || !buffer) { + r = EFI_INVALID_PARAMETER; + goto out; + } + *no_handles = 0; + *buffer = NULL; + r = efi_locate_handle(search_type, protocol, search_key, &buffer_size, + *buffer); + if (r != EFI_BUFFER_TOO_SMALL) + goto out; + r = efi_allocate_pool(EFI_BOOT_SERVICES_DATA, buffer_size, + (void **)buffer); + if (r != EFI_SUCCESS) + goto out; + r = efi_locate_handle(search_type, protocol, search_key, &buffer_size, + *buffer); + if (r == EFI_SUCCESS) + *no_handles = buffer_size / sizeof(efi_handle_t); +out: + return r; +} + /** * efi_locate_handle_buffer() - locate handles implementing a protocol * @search_type: selection criterion @@ -2474,30 +2503,13 @@ efi_status_t EFIAPI efi_locate_handle_buffer( efi_uintn_t *no_handles, efi_handle_t **buffer) { efi_status_t r; - efi_uintn_t buffer_size = 0; EFI_ENTRY("%d, %pUs, %p, %p, %p", search_type, protocol, search_key, no_handles, buffer); - if (!no_handles || !buffer) { - r = EFI_INVALID_PARAMETER; - goto out; - } - *no_handles = 0; - *buffer = NULL; - r = efi_locate_handle(search_type, protocol, search_key, &buffer_size, - *buffer); - if (r != EFI_BUFFER_TOO_SMALL) - goto out; - r = efi_allocate_pool(EFI_BOOT_SERVICES_DATA, buffer_size, - (void **)buffer); - if (r != EFI_SUCCESS) - goto out; - r = efi_locate_handle(search_type, protocol, search_key, &buffer_size, - *buffer); - if (r == EFI_SUCCESS) - *no_handles = buffer_size / sizeof(efi_handle_t); -out: + r = efi_locate_handle_buffer_int(search_type, protocol, search_key, + no_handles, buffer); + return EFI_EXIT(r); } diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c index 60a3fc85ac..cf9622ed1a 100644 --- a/lib/efi_loader/efi_console.c +++ b/lib/efi_loader/efi_console.c @@ -5,6 +5,7 @@ * Copyright (c) 2016 Alexander Graf */ +#include #include #include #include @@ -1312,3 +1313,83 @@ out_of_memory: printf("ERROR: Out of memory\n"); return r; } + +/** + * efi_console_get_u16_string() - get user input string + * + * @cin: protocol interface to EFI_SIMPLE_TEXT_INPUT_PROTOCOL + * @cout: protocol interface to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL + * @buf: buffer to store user input string in UTF16 + * @size: buffer size including NULL terminator + * @filter_func: callback to filter user input + * @row: row number to locate user input form + * @col: column number to locate user input form + * Return: status code + */ +efi_status_t efi_console_get_u16_string(struct efi_simple_text_input_protocol *cin, + struct efi_simple_text_output_protocol *cout, + u16 *buf, efi_uintn_t size, + efi_console_filter_func filter_func, + int row, int col) +{ + efi_status_t ret; + efi_uintn_t len = 0; + struct efi_input_key key; + + printf(ANSI_CURSOR_POSITION, row, col); + puts(ANSI_CLEAR_LINE_TO_END); + puts(ANSI_CURSOR_SHOW); + + ret = EFI_CALL(cin->reset(cin, false)); + if (ret != EFI_SUCCESS) + return ret; + + for (;;) { + do { + ret = EFI_CALL(cin->read_key_stroke(cin, &key)); + mdelay(10); + } while (ret == EFI_NOT_READY); + + if (key.unicode_char == u'\b') { + if (len > 0) + buf[--len] = u'\0'; + + printf(ANSI_CURSOR_POSITION, row, col); + ret = EFI_CALL(cout->output_string(cout, buf)); + if (ret != EFI_SUCCESS) + return ret; + + puts(ANSI_CLEAR_LINE_TO_END); + continue; + } else if (key.unicode_char == u'\r') { + if (len == 0) /* no user input */ + continue; + + buf[len] = u'\0'; + return EFI_SUCCESS; + } else if (key.unicode_char == 0x3 || key.scan_code == 23) { + return EFI_ABORTED; + } else if (key.unicode_char < 0x20) { + /* ignore control codes other than Ctrl+C, '\r' and '\b' */ + continue; + } else if (key.scan_code != 0) { + /* only accept single ESC press for cancel */ + continue; + } + + if (filter_func) { + if (filter_func(&key) != EFI_SUCCESS) + continue; + } + + if (len >= (size - 1)) + continue; + + buf[len] = key.unicode_char; + len++; + printf(ANSI_CURSOR_POSITION, row, col); + ret = EFI_CALL(cout->output_string(cout, buf)); + if (ret != EFI_SUCCESS) + return ret; + } +} diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c index f5b462fb16..01576c8ed2 100644 --- a/lib/efi_loader/efi_disk.c +++ b/lib/efi_loader/efi_disk.c @@ -751,3 +751,14 @@ efi_status_t efi_disk_init(void) return EFI_SUCCESS; } + +efi_status_t efi_disk_get_device_name(struct efi_block_io *this, char *buf, int size) +{ + struct efi_disk_obj *diskobj; + + diskobj = container_of(this, struct efi_disk_obj, ops); + + snprintf(buf, size, "%s %d:%d", diskobj->ifname, diskobj->dev_index, diskobj->part); + + return EFI_SUCCESS; +} diff --git a/lib/efi_loader/efi_file.c b/lib/efi_loader/efi_file.c index 7a7077e6d0..c96a7f7ca3 100644 --- a/lib/efi_loader/efi_file.c +++ b/lib/efi_loader/efi_file.c @@ -246,10 +246,10 @@ error: return NULL; } -static efi_status_t efi_file_open_int(struct efi_file_handle *this, - struct efi_file_handle **new_handle, - u16 *file_name, u64 open_mode, - u64 attributes) +efi_status_t efi_file_open_int(struct efi_file_handle *this, + struct efi_file_handle **new_handle, + u16 *file_name, u64 open_mode, + u64 attributes) { struct file_handle *fh = to_fh(this); efi_status_t ret; @@ -369,11 +369,17 @@ static efi_status_t file_close(struct file_handle *fh) return EFI_SUCCESS; } -static efi_status_t EFIAPI efi_file_close(struct efi_file_handle *file) +efi_status_t efi_file_close_int(struct efi_file_handle *file) { struct file_handle *fh = to_fh(file); + + return file_close(fh); +} + +static efi_status_t EFIAPI efi_file_close(struct efi_file_handle *file) +{ EFI_ENTRY("%p", file); - return EFI_EXIT(file_close(fh)); + return EFI_EXIT(efi_file_close_int(file)); } static efi_status_t EFIAPI efi_file_delete(struct efi_file_handle *file) @@ -562,8 +568,8 @@ static efi_status_t dir_read(struct file_handle *fh, u64 *buffer_size, return EFI_SUCCESS; } -static efi_status_t efi_file_read_int(struct efi_file_handle *this, - efi_uintn_t *buffer_size, void *buffer) +efi_status_t efi_file_read_int(struct efi_file_handle *this, + efi_uintn_t *buffer_size, void *buffer) { struct file_handle *fh = to_fh(this); efi_status_t ret = EFI_SUCCESS; @@ -773,24 +779,11 @@ out: return EFI_EXIT(ret); } -/** - * efi_file_setpos() - set current position in file - * - * This function implements the SetPosition service of the EFI file protocol. - * See the UEFI spec for details. - * - * @file: file handle - * @pos: new file position - * Return: status code - */ -static efi_status_t EFIAPI efi_file_setpos(struct efi_file_handle *file, - u64 pos) +efi_status_t efi_file_setpos_int(struct efi_file_handle *file, u64 pos) { struct file_handle *fh = to_fh(file); efi_status_t ret = EFI_SUCCESS; - EFI_ENTRY("%p, %llu", file, pos); - if (fh->isdir) { if (pos != 0) { ret = EFI_UNSUPPORTED; @@ -812,6 +805,28 @@ static efi_status_t EFIAPI efi_file_setpos(struct efi_file_handle *file, fh->offset = pos; error: + return ret; +} + +/** + * efi_file_setpos() - set current position in file + * + * This function implements the SetPosition service of the EFI file protocol. + * See the UEFI spec for details. + * + * @file: file handle + * @pos: new file position + * Return: status code + */ +static efi_status_t EFIAPI efi_file_setpos(struct efi_file_handle *file, + u64 pos) +{ + efi_status_t ret = EFI_SUCCESS; + + EFI_ENTRY("%p, %llu", file, pos); + + ret = efi_file_setpos_int(file, pos); + return EFI_EXIT(ret); } @@ -1138,17 +1153,23 @@ struct efi_file_handle *efi_file_from_path(struct efi_device_path *fp) return f; } +efi_status_t efi_open_volume_int(struct efi_simple_file_system_protocol *this, + struct efi_file_handle **root) +{ + struct file_system *fs = to_fs(this); + + *root = file_open(fs, NULL, NULL, 0, 0); + + return EFI_SUCCESS; +} + static efi_status_t EFIAPI efi_open_volume(struct efi_simple_file_system_protocol *this, struct efi_file_handle **root) { - struct file_system *fs = to_fs(this); - EFI_ENTRY("%p, %p", this, root); - *root = file_open(fs, NULL, NULL, 0, 0); - - return EFI_EXIT(EFI_SUCCESS); + return EFI_EXIT(efi_open_volume_int(this, root)); } struct efi_simple_file_system_protocol * From patchwork Mon May 16 11:00:38 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahisa Kojima X-Patchwork-Id: 572965 Delivered-To: patch@linaro.org Received: by 2002:a5d:5051:0:0:0:0:0 with SMTP id h17csp499306wrt; Mon, 16 May 2022 04:00:56 -0700 (PDT) X-Google-Smtp-Source: ABdhPJz0q9Ar1f9L7816rqbgd0N0EbC66YXxtJjTFjc/dJwUU0KGeqZCxIgVaw8eTCbHRntpG7CC X-Received: by 2002:ac2:456e:0:b0:472:12c9:42b5 with SMTP id k14-20020ac2456e000000b0047212c942b5mr12564635lfm.211.1652698856418; Mon, 16 May 2022 04:00:56 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1652698856; cv=none; d=google.com; s=arc-20160816; b=FDtguYSPCRV3R+Sjl3hRQqj0M1Jcw49FTYUQUyO/tHhEx0t9YGThXYxGd3O0N8kkLF SXPSollaGoXWBSwrqF6CaK8NJyJ31WHo1vl6JCQuLK/aF9hrk1E8jl8wpLjCYJV4h9AI q2Zs8K6yD4WMvEZOeLpS8TrpoPskQNogdINO7BhKL5IrDiqINppmYa8Ga/B4xcY8OSn4 SKeR7nsMKFcwZdNRLBQkyqrpZsTu/D+SDouJ78YVjPeFEPvi9mHDdbCfW2wy5PiMaqHu z4re0hLGj2+JHeGrf1YP2EwlQZ52ewNFXc8XRVLj/J4I3uqydD0Os34HRLT9i1MPa9nY ms8g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=TbM8M76th8Lcwt6380876PJmTxre9hCFZOUodC16uQ8=; b=NPElOjN7peaDy9kDkIWrXRSGlPfTvOO9xYdxPAtIyAZ32GaHSveM1d1rCXmoRR3CYt zhVUdItxvLC9x/A7yqt9H6oah+umk86vhbBGofW7yK9tNhjZ9VgO43aDHFO16X7ksLBQ 1cgmXyCNFymHEwK0nwluckqLoS4LQ6uHkepXzoR6lCqR1w9nnNFFjiofQ70oXk/cyhup nF0jAI+Q8SevH9VMhzzRI2fftK0la0G3BVY2NtYIWg3tGiTWN7LbGYTN2Em+ZZ9+vnRt +nYKnO3FFgocZufvDRBzJqAw3Xhx2Z2MZ24/WToJaSGqhhAHO8OhFzZCwW2ooZKhSYK4 /yXw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=OUR6NV+s; spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 85.214.62.61 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from phobos.denx.de (phobos.denx.de. [85.214.62.61]) by mx.google.com with ESMTPS id k9-20020a05651210c900b004778ecb218esi5224005lfg.467.2022.05.16.04.00.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 16 May 2022 04:00:56 -0700 (PDT) Received-SPF: pass (google.com: domain of u-boot-bounces@lists.denx.de designates 85.214.62.61 as permitted sender) client-ip=85.214.62.61; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=OUR6NV+s; spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 85.214.62.61 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 18EC584197; Mon, 16 May 2022 13:00:55 +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="OUR6NV+s"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id CC3DE84199; Mon, 16 May 2022 13:00:36 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE,SPF_PASS, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-pl1-x62f.google.com (mail-pl1-x62f.google.com [IPv6:2607:f8b0:4864:20::62f]) (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 D248A84099 for ; Mon, 16 May 2022 13:00: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=masahisa.kojima@linaro.org Received: by mail-pl1-x62f.google.com with SMTP id d17so14096908plg.0 for ; Mon, 16 May 2022 04:00:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=TbM8M76th8Lcwt6380876PJmTxre9hCFZOUodC16uQ8=; b=OUR6NV+sjp/YE+X9bN+MWZYQO7QeVPnYaqR4h7v6JfTor4xHvacNn1TsBb2MTKI7cQ HA4Cih4LdEk/Gb6TuwMTRmU+hLWg7Kz64F47ZDG4vTRLd4f8XxqT9UdhouwSbXG1xZyr lHucCUfPbwgb6VaBktv8VluwRjRdrnKzBL6J6S/b+ki1DIyEb+3HbMGG76Cpl2hIko8H XTH+T6cByFw0J/ouIbn8I+lwO31gQKCxQ1W2aOAzfis4zfjD/XoJoYvCKT5Tun7ki6Sz J3OduKdnrzlwpflVdIwTHJ42ouuUssGN4j+n6ytNregXZIawkcY3tTCLGy46XZrfx2GD J0Dw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=TbM8M76th8Lcwt6380876PJmTxre9hCFZOUodC16uQ8=; b=ZKQhmMFTogXik5xMMx/uyfaXQsH5Lim970C1GXmR6y996ZADK8oauq00Mm/N/0A+SC UG4/BwdbLvaHbWQtyvnHl5ZB0kImy2gEYVsRpR3c2z1bOtY4aGaEcgSy+bbzu0wWFmcm eJF9hD3fsnbaj95OGAbElTEkIgC3RZTmQj93tzVcG/3kEPnvY5ViPpTgurfjQ0LuUNFJ MynhaHYong8Kip738AG9HP+xT1oKH20j7o2LZr84PMfgsM3QcNv5mgDW5DRw+dJ6Sicd 8js1YRmhiY/ZUi++c+ffvLRbZbilaIOyaTmY6fuWqWbM54ldcLmAKHoXvtwFF4WAoHNX +kew== X-Gm-Message-State: AOAM530rQsgvCEfxe40fQkOW48STWw8y/NWAsTiyc3W8tlhr5mkNxjI5 49DtKmfRpQ0f7/+Ioa0kqz8RECrD6vQT2w== X-Received: by 2002:a17:903:22ce:b0:15e:bd57:5bec with SMTP id y14-20020a17090322ce00b0015ebd575becmr16857089plg.114.1652698829507; Mon, 16 May 2022 04:00:29 -0700 (PDT) Received: from localhost.localdomain ([240d:1a:cf7:5800:82fa:5bff:fe4b:26b1]) by smtp.gmail.com with ESMTPSA id q2-20020a170902edc200b0016173113c50sm2446480plk.92.2022.05.16.04.00.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 16 May 2022 04:00:29 -0700 (PDT) From: Masahisa Kojima To: u-boot@lists.denx.de Cc: Heinrich Schuchardt , Ilias Apalodimas , Simon Glass , Takahiro Akashi , Francois Ozog , Mark Kettenis , Masahisa Kojima Subject: [PATCH v6 2/6] efi_loader: menu-driven deletion of UEFI boot variable Date: Mon, 16 May 2022 20:00:38 +0900 Message-Id: <20220516110043.31480-3-masahisa.kojima@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220516110043.31480-1-masahisa.kojima@linaro.org> References: <20220516110043.31480-1-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 This commit adds the menu-driven deletion of UEFI boot variable. Signed-off-by: Masahisa Kojima --- (no update sinch v5) changes in v5: - split into the separate patch lib/efi_loader/efi_bootmenu_maintenance.c | 136 ++++++++++++++++++++++ 1 file changed, 136 insertions(+) diff --git a/lib/efi_loader/efi_bootmenu_maintenance.c b/lib/efi_loader/efi_bootmenu_maintenance.c index e5124a8a21..96306cd2cc 100644 --- a/lib/efi_loader/efi_bootmenu_maintenance.c +++ b/lib/efi_loader/efi_bootmenu_maintenance.c @@ -334,6 +334,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; @@ -861,6 +944,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; @@ -889,6 +1024,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}, }; From patchwork Mon May 16 11:00:39 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahisa Kojima X-Patchwork-Id: 572966 Delivered-To: patch@linaro.org Received: by 2002:a5d:5051:0:0:0:0:0 with SMTP id h17csp499444wrt; Mon, 16 May 2022 04:01:12 -0700 (PDT) X-Google-Smtp-Source: ABdhPJyuGnZsKOmp1YaCaGZcMQ7wSfmI6jmiYSsjoGB2wSG6C1PtFSdkVDpSpikFbIC+tN6dxntR X-Received: by 2002:a2e:b8cc:0:b0:24f:501b:af80 with SMTP id s12-20020a2eb8cc000000b0024f501baf80mr10947698ljp.328.1652698872132; Mon, 16 May 2022 04:01:12 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1652698872; cv=none; d=google.com; s=arc-20160816; b=lfKg96GM7iG7rmjZsghpxUWx1I2MSJRmZnecqFR/56kSxw/qhmWTse5UNWDWwVJsv7 Dodjzkr4n4IiCK/Xs8GVzVgZOXUXAvPPiY4SBVVXrIfrmT+V3ozGfYO6d6PTw/o9Bk53 kloGj26WxZ8zUYwBjJGedLTSNnbFFrByYdKpHuUl/8j55nrnBVz71tbtttBbTmjoqNx7 b+VHrY8nTdGNIUEI7b3aWS9dw67fg8Pzy2/fCAf7NNY3derAYyZ2iJTKoc7AlU5iAFQS lwdpK5Y8ghdvsD2j+pRj6/QK91EH0X8YlA+MeP5SdDSZIGKAkKhPh6tn1i91C0L8KWWv HgjA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=ifhMVyuup3/BtDvzEmObvgR+zLMyrl4yM0ZoKj2cHmw=; b=v+mF5tZfpcyz+E5uyjtRgkLqDIsAGj0JMinMDW3fV3EBPTr0jl2rQUqJPYiYlifgnV GEBFinRTGZtMH0gp10XzQxBldgIDbHsf0zPLdoLK8eVPHS1Ch+9fgr+UiqWY4fQIFSFA SmLrDJwlb8HFpKagQyJZABKN20PE9n8QqScMOO9BD3fTNIuyvEMqHCGGtov7qalS2cRl JxDk1aE0pHMLEUlNriftSPCo2/wQfi6IvLoNzNNHuCf3vkXh8mrx1NrRZt4VZcd0PkOa XiIrdlpdHNV8Z8Cf0fkhpMX9yEZOkIdEE8cL/YkqhdrgKBhijndd6IBoBlc0vfJkW9fc z/Ig== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=LSs6VBfU; spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 2a01:238:438b:c500:173d:9f52:ddab:ee01 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from phobos.denx.de (phobos.denx.de. [2a01:238:438b:c500:173d:9f52:ddab:ee01]) by mx.google.com with ESMTPS id a11-20020a05651c210b00b0024952f7bd21si12794414ljq.636.2022.05.16.04.01.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 16 May 2022 04:01:12 -0700 (PDT) Received-SPF: pass (google.com: domain of u-boot-bounces@lists.denx.de designates 2a01:238:438b:c500:173d:9f52:ddab:ee01 as permitted sender) client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=LSs6VBfU; spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 2a01:238:438b:c500:173d:9f52:ddab:ee01 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 2E87484239; Mon, 16 May 2022 13:01:03 +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="LSs6VBfU"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 4DC1484245; Mon, 16 May 2022 13:00:49 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE,SPF_PASS, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-pl1-x62b.google.com (mail-pl1-x62b.google.com [IPv6:2607:f8b0:4864:20::62b]) (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 04D44840DF for ; Mon, 16 May 2022 13:00:34 +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=masahisa.kojima@linaro.org Received: by mail-pl1-x62b.google.com with SMTP id q4so14049936plr.11 for ; Mon, 16 May 2022 04:00:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=ifhMVyuup3/BtDvzEmObvgR+zLMyrl4yM0ZoKj2cHmw=; b=LSs6VBfUpcIiB93gERD4LeZ5CW/jNf7bt6hqqu3ad+UN6/NRGdLPpBjLeE+AjWvj39 7or0ulzuTYDFaYUVSGNGt32LUEcCdZLRKn63OOldeDV9/JeW2ZG5ApAtoGFpRILX3+oT xp6f2TXO0Zbcvem25ckhBfmNygHE41/6xKdywHn9BsviQUwsF7ELEUZW6rAfaZp2j4Oa ZlkNTHXGG14v/8BslFwG27lQ7jopB2d6PkR6WsJPGod9nPYqVXkxU+LkATQANrk7ay5J BmWBMMOyHSJPIkzT3xikX2hZXogzajPl/sL7v1P6R8SJb7o4hCiVXIrnq3Df/1PT+4cq 7CjQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=ifhMVyuup3/BtDvzEmObvgR+zLMyrl4yM0ZoKj2cHmw=; b=CWSStSegqwgYiigo3tP+SKL9T5cTKcB2xMjaIz2e0xokbahcqwu3+J1wRwz3mvA6kh AL6bZIvyfM4bCkvq2wV+Vll3QTi9sLDXg/1L7Z3BuVRjNtABwbEO4PcAaDnBp/uFZ2F/ FIWKHL+1NHMvoqGIXSX5+Ip3JvryKTE6T/GoG3oQ8sNFCwrwfq3ABFVo+NxxFaBYGVhO d0bGAcRIB0//89ZAh0og8wjdOwBi/YJSmYW5CXxnqKiRCuT1vVvH0n1VG1+njFHGXmTc RvipumNz6au2vsu6+VPIMnUIclP2DjGOu6Al80QZZOIszPGPtLsT4dIXPrifxdI+/Tr+ Kx6g== X-Gm-Message-State: AOAM531nh5qhc2CHXl+WDiu2HVl3YJP/tQqzFq+3t/NN0gJY9mwpQeU/ FRnGyxL0/DDRXySWB0q6X5d/trJrhfFLFQ== X-Received: by 2002:a17:90b:1bd1:b0:1dc:7118:cf28 with SMTP id oa17-20020a17090b1bd100b001dc7118cf28mr19131432pjb.3.1652698831951; Mon, 16 May 2022 04:00:31 -0700 (PDT) Received: from localhost.localdomain ([240d:1a:cf7:5800:82fa:5bff:fe4b:26b1]) by smtp.gmail.com with ESMTPSA id q2-20020a170902edc200b0016173113c50sm2446480plk.92.2022.05.16.04.00.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 16 May 2022 04:00:31 -0700 (PDT) From: Masahisa Kojima To: u-boot@lists.denx.de Cc: Heinrich Schuchardt , Ilias Apalodimas , Simon Glass , Takahiro Akashi , Francois Ozog , Mark Kettenis , Masahisa Kojima Subject: [PATCH v6 3/6] efi_loader: menu-driven update of UEFI bootorder variable Date: Mon, 16 May 2022 20:00:39 +0900 Message-Id: <20220516110043.31480-4-masahisa.kojima@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220516110043.31480-1-masahisa.kojima@linaro.org> References: <20220516110043.31480-1-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 This commit adds the menu-driven update of UEFI bootorder variable. Signed-off-by: Masahisa Kojima --- (no update since v5) Changes in v5: - split into the separate patch lib/efi_loader/efi_bootmenu_maintenance.c | 102 ++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/lib/efi_loader/efi_bootmenu_maintenance.c b/lib/efi_loader/efi_bootmenu_maintenance.c index 96306cd2cc..be67fca95f 100644 --- a/lib/efi_loader/efi_bootmenu_maintenance.c +++ b/lib/efi_loader/efi_bootmenu_maintenance.c @@ -746,6 +746,56 @@ static efi_status_t efi_bootmenu_boot_add_enter_name(struct efi_bootmenu_boot_op return ret; } +static efi_status_t allow_decimal(struct efi_input_key *key) +{ + if (u'0' <= key->unicode_char && key->unicode_char <= u'9') + return EFI_SUCCESS; + + return EFI_INVALID_PARAMETER; +} + +static efi_status_t efi_bootmenu_change_boot_order(int selected, int max, int *new) +{ + efi_status_t ret; + u16 new_order[EFI_BOOT_ORDER_MAX_SIZE_IN_DECIMAL] = {0}; + + printf(ANSI_CURSOR_POSITION, 2, 1); + puts(" *** U-Boot EFI Boot Manager Menu ***"); + printf(ANSI_CURSOR_POSITION, 4, 1); + printf(" current boot order : %d", selected); + + printf(ANSI_CURSOR_POSITION, 6, 1); + printf(" new boot order(0 - %4d): ", max); + + printf(ANSI_CURSOR_POSITION, 8, 1); + puts(" ENTER to complete, ESC/CTRL+C to quit"); + + printf(ANSI_CURSOR_POSITION, 6, 29); + puts(ANSI_CURSOR_SHOW); + + for (;;) { + memset(new_order, 0, sizeof(new_order)); + ret = efi_console_get_u16_string(cin, cout, new_order, 6, allow_decimal, 6, 29); + if (ret == EFI_SUCCESS) { + int i; + int val = 0; + + for (i = 0; + i < u16_strnlen(new_order, EFI_BOOT_ORDER_MAX_SIZE_IN_DECIMAL - 1); + i++) + val = (val * 10) + (new_order[i] - u'0'); + + if (val > max) + continue; + + *new = val; + return EFI_SUCCESS; + } else { + return ret; + } + } +} + static efi_status_t efi_bootmenu_select_file_handler(struct efi_bootmenu_boot_option *bo) { efi_status_t ret; @@ -996,6 +1046,57 @@ static efi_status_t efi_bootmenu_process_delete_boot_option(void *data, bool *ex return ret; } +static efi_status_t efi_bootmenu_process_change_boot_order(void *data, bool *exit) +{ + int selected; + int new_order; + efi_status_t ret; + efi_uintn_t num, size; + u16 *bootorder = NULL; + u16 *new_bootorder = NULL; + + bootorder = efi_get_var(u"BootOrder", &efi_global_variable_guid, &size); + if (!bootorder) + return EFI_NOT_FOUND; + + num = size / sizeof(u16); + ret = efi_bootmenu_show_boot_selection(bootorder, num, &selected); + if (ret != EFI_SUCCESS) + goto out; + + ret = efi_bootmenu_change_boot_order(selected, num - 1, &new_order); + if (ret != EFI_SUCCESS) + goto out; + + new_bootorder = calloc(1, size); + if (!new_bootorder) + goto out; + + memcpy(new_bootorder, bootorder, size); + if (selected > new_order) { + new_bootorder[new_order] = bootorder[selected]; + memcpy(&new_bootorder[new_order + 1], &bootorder[new_order], + (selected - new_order) * sizeof(u16)); + } else if (selected < new_order) { + new_bootorder[new_order] = bootorder[selected]; + memcpy(&new_bootorder[selected], &bootorder[selected + 1], + (new_order - selected) * sizeof(u16)); + } else { + /* nothing to change */ + goto out; + } + 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); +out: + free(new_bootorder); + free(bootorder); + + return ret; +} + static efi_status_t efi_bootmenu_init(void) { efi_status_t ret; @@ -1025,6 +1126,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"Change Boot Order", efi_bootmenu_process_change_boot_order}, {u"Quit", NULL}, }; From patchwork Mon May 16 11:00:40 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahisa Kojima X-Patchwork-Id: 572967 Delivered-To: patch@linaro.org Received: by 2002:a5d:5051:0:0:0:0:0 with SMTP id h17csp499568wrt; Mon, 16 May 2022 04:01:29 -0700 (PDT) X-Google-Smtp-Source: ABdhPJzDXnY+Efn0+MZx1vqNwRg6oZ2SWtGrVeIqU1PkERTCgj9OzaHEe9phUygMbS7cisp93DgB X-Received: by 2002:ac2:4f03:0:b0:443:5d9d:819d with SMTP id k3-20020ac24f03000000b004435d9d819dmr12462596lfr.165.1652698888863; Mon, 16 May 2022 04:01:28 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1652698888; cv=none; d=google.com; s=arc-20160816; b=OPLIpeA1iHLRLwbz4Rlv5iKP+wDg2mAla8gB0kpWW2kd17SrDnGp+29gbt/Piosin+ TntIeakp3AwsNPYHna6uQcWD/7bEsXPFgB/6amCpQ2dHIPS4rX4lQKFTmHRjqH1b1m6a wVlP9Cdx6W/glZVMjxWlSpESboTJib1WTeQoJvdMd9fYf0rEmcVjogWdVdSqzc2bnPu3 X/iTw5Z9DL4JXKQYshvoFCWUyGDi8iBz8kx4fM0xdOMHlkdH8I8O4S1kvifKQ7nlsKZj 5DnXkmCRzhg+NpVzW/x4HFqsmU1un/asxdu6MuJft6T4HPReDodKdNLzRUY+PLMzni+J 1Ttg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=VvQitp4hSLlU0qNDdKaJ/ultuui2EoYaspq0srhJx4k=; b=DhJyHgR++WeyYQ278qLOfwJzBxu6hWVsKvENRia/5k5iwsvBwOGIq1Q2la88OCu6l8 0GV5LA4m9xtmtM8pdOXGXFqnaWyoGZmtKWFQI+tJW2UNLTkJtMjmMVEbK8ilzFNVKZQB w6eK2Zkkivs4Q3CyqpiHJEizGbBo77l8VGzYbN1bm97LArsTPaf8tGM4UnyijrUnGT7e HM52sYymzX2TK0t+j4d3jzupX14oONp+NQL59leXxurYqc+Uzbz+cdjl8NBDcX5T6nqu wcRNqTtfXJ2+dTLhT4kYtV/HFuCyrUXF6Xkmwqr3aO2ezxB6xqmy4PkddyHn7868/UWd 6R6Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=nquXIjL+; spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 2a01:238:438b:c500:173d:9f52:ddab:ee01 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from phobos.denx.de (phobos.denx.de. [2a01:238:438b:c500:173d:9f52:ddab:ee01]) by mx.google.com with ESMTPS id c28-20020ac25f7c000000b00473ac8732e5si10374328lfc.432.2022.05.16.04.01.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 16 May 2022 04:01:28 -0700 (PDT) Received-SPF: pass (google.com: domain of u-boot-bounces@lists.denx.de designates 2a01:238:438b:c500:173d:9f52:ddab:ee01 as permitted sender) client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=nquXIjL+; spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 2a01:238:438b:c500:173d:9f52:ddab:ee01 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 5C43B84010; Mon, 16 May 2022 13:01:27 +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="nquXIjL+"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id F33C384245; Mon, 16 May 2022 13:00:53 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE,SPF_PASS, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-pj1-x1033.google.com (mail-pj1-x1033.google.com [IPv6:2607:f8b0:4864:20::1033]) (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 4B22B84099 for ; Mon, 16 May 2022 13:00:37 +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=masahisa.kojima@linaro.org Received: by mail-pj1-x1033.google.com with SMTP id pq9-20020a17090b3d8900b001df622bf81dso1548834pjb.3 for ; Mon, 16 May 2022 04:00:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=VvQitp4hSLlU0qNDdKaJ/ultuui2EoYaspq0srhJx4k=; b=nquXIjL+lX2fcdasJ3QI5oYzPcAR9jpSpIlhuOFRHJJIEnHJUFMp2mYEZCG70TnXOM 4zXljODuo0Zg+HWBHrsujj8Tgm8uixlnTY4MmysowaFEhi9gXVFRkLT6jMamF+aqW4UE q+XpGygKkbPEWn4ewInicQlaWZ2i2hkoJ1t9PdiPHMTW3v18JcpKsNOGPw9ShG3cFmqM JMjGvn6uG3xqAUpUdrPKM1qAbl+s1D93CbVPapguaneadyBhmRp5+l4sTduHHWvQ5/z+ exz/gTk+KOwKq/Mgd2e4R51S2mmSddzGcGsM2JCL3sCRf/xa8ZZjhnYbnrqr2hY5OAJ6 LI1g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=VvQitp4hSLlU0qNDdKaJ/ultuui2EoYaspq0srhJx4k=; b=UgiY4TpRJgr5VxcKhERyqQ8Z72fBxW3WRhVnKYwb2DTHVnZtoFpfSB/0hVafU3czHc IiEv5fJYuwfYbrrytmxUyTO6ljgZ1JEFb30YzI5a7pm+QdfkZrgvL5j4LrggsUi2mmqm 8G9ZXp2y2k6TBjOH3UBXW0IKQeabI/E+Oc3rcRr3EU5RcrLR/gTzkdmHQOQY7wHAjmVb 8iNNoIFuj0b3S6xHqmwt2nQb1GkkMb8z4WVSe91p10uBM+nXqhu3dA5C+d6Wfw4nfcjY zfZKftU7M2Pra9u0EDyg7f+9sBrDZ+SPZYHsFruoGoByl74RIwfxtKEaS6rcm369Srzp vgZg== X-Gm-Message-State: AOAM5318SVaUYew2YwuweWEUyTkdfk7hEXUGphNKji3RiFJdRK3z1ZMu rtRB/QnNmN5ZynGfctWiw/uzLneXHpYJqA== X-Received: by 2002:a17:90b:1808:b0:1dc:8904:76a1 with SMTP id lw8-20020a17090b180800b001dc890476a1mr18794987pjb.202.1652698834623; Mon, 16 May 2022 04:00:34 -0700 (PDT) Received: from localhost.localdomain ([240d:1a:cf7:5800:82fa:5bff:fe4b:26b1]) by smtp.gmail.com with ESMTPSA id q2-20020a170902edc200b0016173113c50sm2446480plk.92.2022.05.16.04.00.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 16 May 2022 04:00:34 -0700 (PDT) From: Masahisa Kojima To: u-boot@lists.denx.de Cc: Heinrich Schuchardt , Ilias Apalodimas , Simon Glass , Takahiro Akashi , Francois Ozog , Mark Kettenis , Masahisa Kojima Subject: [PATCH v6 4/6] bootmenu: add removable media entries Date: Mon, 16 May 2022 20:00:40 +0900 Message-Id: <20220516110043.31480-5-masahisa.kojima@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220516110043.31480-1-masahisa.kojima@linaro.org> References: <20220516110043.31480-1-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 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. This automatically generated UEFI boot option has the dedicated guid in the optional_data to distinguish it from the UEFI boot option user adds manually. This optional_data is removed when the efi bootmgr loads the selected UEFI boot option. This commit also provides the BOOT#### variable maintenance feature. Depending on the system hardware setup, some devices may not exist at a later system boot, so bootmenu checks the available device in each bootmenu invocation and automatically removes the BOOT#### variable corrensponding to the non-existent media device. Signed-off-by: Masahisa Kojima --- Changes in v6: - optional_data size is changed to 16bytes - check the load option size before comparison - remove guid included in optional_data of auto generated entry when loading Changes in v5: - Return EFI_SUCCESS if there is no BootOrder defined - correctly handle the case if no removable device found - use guid to identify the automatically generated entry by bootmenu Newly created in v4 cmd/bootmenu.c | 94 +++++++++++++++ include/efi_loader.h | 23 ++++ lib/efi_loader/efi_bootmenu_maintenance.c | 138 ++++++++++++++++++++++ lib/efi_loader/efi_bootmgr.c | 4 + 4 files changed, 259 insertions(+) diff --git a/cmd/bootmenu.c b/cmd/bootmenu.c index 4b846332b0..911086c97e 100644 --- a/cmd/bootmenu.c +++ b/cmd/bootmenu.c @@ -234,6 +234,89 @@ static int prepare_bootmenu_entry(struct bootmenu_data *menu, return 1; } +/** + * prepare_media_device_entry() - generate the media device entries + * + * This function enumerates all devices supporting EFI_SIMPLE_FILE_SYSTEM_PROTOCOL + * and generate the bootmenu entries. + * This function also provide the BOOT#### variable maintenance for + * the media device entries. + * - Automatically create the BOOT#### variable for the newly detected device, + * this BOOT#### variable is distinguished by the special GUID + * stored in the EFI_LOAD_OPTION.optional_data + * - If the device is not attached to the system, the associated BOOT#### variable + * is automatically deleted. + * + * Return: status code + */ +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); + 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; +} + /** * prepare_uefi_bootorder_entry() - generate the uefi bootmenu entries * @@ -326,6 +409,7 @@ static int prepare_uefi_bootorder_entry(struct bootmenu_data *menu, static struct bootmenu_data *bootmenu_create(int delay) { int ret; + efi_status_t efi_ret; unsigned short int i = 0; struct bootmenu_data *menu; struct bootmenu_entry *iter = NULL; @@ -349,6 +433,16 @@ static struct bootmenu_data *bootmenu_create(int delay) goto cleanup; if (IS_ENABLED(CONFIG_CMD_BOOTEFI_BOOTMGR) && IS_ENABLED(CONFIG_AUTOBOOT_MENU_SHOW)) { + if (i < MAX_DYNAMIC_ENTRY) { + /* + * UEFI specification requires booting from removal media using + * a architecture-specific default image name such as BOOTAA64.EFI. + */ + efi_ret = prepare_media_device_entry(); + if (efi_ret != EFI_SUCCESS && efi_ret != EFI_NOT_FOUND) + 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 49f326e585..48485e8da9 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -252,6 +252,9 @@ extern const struct efi_hii_string_protocol efi_hii_string; uint16_t *efi_dp_str(struct efi_device_path *dp); +/* GUID for the auto generated boot menu entry */ +extern const efi_guid_t efi_guid_bootmenu_auto_generated; + /* GUID of the U-Boot root node */ extern const efi_guid_t efi_u_boot_guid; #ifdef CONFIG_SANDBOX @@ -934,6 +937,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); @@ -1082,6 +1101,10 @@ 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 be67fca95f..58f2999c61 100644 --- a/lib/efi_loader/efi_bootmenu_maintenance.c +++ b/lib/efi_loader/efi_bootmenu_maintenance.c @@ -26,6 +26,13 @@ static struct efi_simple_text_output_protocol *cout; #define EFI_BOOTMENU_BOOT_NAME_MAX 32 #define EFI_BOOT_ORDER_MAX_SIZE_IN_DECIMAL 6 +#define EFI_BOOTMENU_AUTO_GENERATED_ENTRY_GUID \ + EFI_GUID(0x38c1acc1, 0x9fc0, 0x41f0, \ + 0xb9, 0x01, 0xfa, 0x74, 0xd6, 0xd6, 0xe4, 0xde) + +const efi_guid_t efi_guid_bootmenu_auto_generated = + EFI_BOOTMENU_AUTO_GENERATED_ENTRY_GUID; + typedef efi_status_t (*efi_bootmenu_entry_func)(void *data, bool *exit); /** @@ -1142,3 +1149,134 @@ 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++) { + char *optional_data; + 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); + /* + * Set the dedicated guid to optional_data, it is used to identify + * the boot option that automatically generated by the bootmenu. + * efi_serialize_load_option() expects optional_data is null-terminated + * utf8 string, so set the "1234567" string to allocate enough space + * to store guid, instead of realloc the load_option. + */ + lo.optional_data = "1234567"; + 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; + } + /* set the guid */ + optional_data = (char *)opt[i].lo + (opt[i].size - u16_strsize(u"1234567")); + memcpy(optional_data, &efi_guid_bootmenu_auto_generated, sizeof(efi_guid_t)); + 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_SUCCESS; /* BootOrder is not defined, nothing to do */ + + 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, &size); + if (ret != EFI_SUCCESS) + goto next; + + if (size >= sizeof(efi_guid_bootmenu_auto_generated)) { + if (guidcmp(lo.optional_data, &efi_guid_bootmenu_auto_generated) == 0) { + for (j = 0; j < count; j++) { + if (opt[j].size == tmp && + memcmp(opt[j].lo, load_option, tmp) == 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; +} diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c index 631a25d76e..ca2fbd26ce 100644 --- a/lib/efi_loader/efi_bootmgr.c +++ b/lib/efi_loader/efi_bootmgr.c @@ -146,6 +146,10 @@ static efi_status_t try_load_entry(u16 n, efi_handle_t *handle, } /* Set load options */ + if (size >= sizeof(efi_guid_t) && + !guidcmp(lo.optional_data, &efi_guid_bootmenu_auto_generated)) + size = 0; + if (size) { *load_options = malloc(size); if (!*load_options) { From patchwork Mon May 16 11:00:41 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahisa Kojima X-Patchwork-Id: 572970 Delivered-To: patch@linaro.org Received: by 2002:a5d:5051:0:0:0:0:0 with SMTP id h17csp499899wrt; Mon, 16 May 2022 04:02:09 -0700 (PDT) X-Google-Smtp-Source: ABdhPJzX4u7sZNUr677UDjYYxokpQG0yiPsqplIhjcI8+gBEHptDCxTEgOYeykqK0I9dBWOb6qnX X-Received: by 2002:a05:6512:1188:b0:473:a4b3:8479 with SMTP id g8-20020a056512118800b00473a4b38479mr12765141lfr.247.1652698929078; Mon, 16 May 2022 04:02:09 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1652698929; cv=none; d=google.com; s=arc-20160816; b=eF4QcI4vGplCZEgoqisRvsjJ/u/PusoIHXnfYOWe3c6S+++44i4XaIspsrkrD9RzFA 29umA/XLwtaJCSCxKkybQXWKoP/2zSf+ZXiOYG0SqSvSrCffc/Y+mwKL46Vmht225WSQ 5nT18zUmUmzsdSx7i1v+q/M7ppiAJbnzFYiCOd1qR8uj2OLMAuLHOsd+nKBUOqKQ2aAX P+nHzOgRxH8pQFgdjqGKBVkAvWh718i4NShDnpbSYdpR6WXb5Wv4mdJlExpaV+N3Vdpc WC3OneWOD9mw5JlqNO+5f/y2xAeNJypGOY923wvQHfV1bnQ+Znb7+UDpGprCEDsMqFR7 uVfQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=8D/m/PwRdq12czqT2TARvabqRQWCwscAL2b6uWg3Nxw=; b=GaXIGwtdunm7oTuFZWK8wHo+yKn4KsNkxx/27Rnxbd7EWcBLwMzzMa4UNVs0/bukHe y328qBlvStf3JqrON6M2Ac1ii8GWcziTxHIn5neGkpGKlBWNz5yvU5mk6DkTNU1whAwR 3WwJHRBDYEP971C6epFRjrYHn9Ici7yXXEzxAmEqFEvYrgwDQY/nTsmsemhLPNSpxpB8 otqhdIcpteGrExl/LHdwlzbA9eHJzqjyyj0zHMqFeSjhNC5giXq0LWOMOXyWIS7QmRYi kemZy/j1oBBdiiUWrbW72VNp4wrxnApGTPojeLhI+I6/W1nA57x+C48HoFlmP5Hy2Hmn Mbew== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=ZCgiOS2Q; spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 2a01:238:438b:c500:173d:9f52:ddab:ee01 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from phobos.denx.de (phobos.denx.de. [2a01:238:438b:c500:173d:9f52:ddab:ee01]) by mx.google.com with ESMTPS id x34-20020a056512132200b00471fc8f7704si12923356lfu.8.2022.05.16.04.02.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 16 May 2022 04:02:09 -0700 (PDT) Received-SPF: pass (google.com: domain of u-boot-bounces@lists.denx.de designates 2a01:238:438b:c500:173d:9f52:ddab:ee01 as permitted sender) client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=ZCgiOS2Q; spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 2a01:238:438b:c500:173d:9f52:ddab:ee01 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 61AF884268; Mon, 16 May 2022 13:01:49 +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="ZCgiOS2Q"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 75AD884248; Mon, 16 May 2022 13:00:56 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE,SPF_PASS, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-pl1-x62b.google.com (mail-pl1-x62b.google.com [IPv6:2607:f8b0:4864:20::62b]) (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 2CEAD8419A for ; Mon, 16 May 2022 13:00:38 +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=masahisa.kojima@linaro.org Received: by mail-pl1-x62b.google.com with SMTP id q4so14049936plr.11 for ; Mon, 16 May 2022 04:00:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=8D/m/PwRdq12czqT2TARvabqRQWCwscAL2b6uWg3Nxw=; b=ZCgiOS2QmQ0eU78CPL+axzzXCh4WAhDETjfCMhdEnE7TQ69UTJjSZ2EwYwL5U64sC1 h7Xq68ADuIsRzXg+fHMknlGO+RB8q6yak20eyQjRZHnPD/bOjLcIRSNiZR17UE2py2NZ kBEEbnayNGjuZGxGA3vZ8apsH23MbflcIXCQn7/I+IqGjwCt5tPmwfCoNruZvQRj3U5g KxZJU7YX/gLhw54iOFA3xwaUwAhtzW11dsdE+am2QNP0A0SfAdvhtJ+dJ+gCIwwy/J9S csud3GHqL3876d9qVnWDXK9lsg1RmDlw47SKXQM6kGvywLLU8PRGJTkhGOWmSxuDdmCR +vMQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=8D/m/PwRdq12czqT2TARvabqRQWCwscAL2b6uWg3Nxw=; b=QCy+tEN4AjPFhxk1tWynRrg8pOTLvLd7ydGrSSq/inr60UTvSQf3G4OSS+c2WkDGba 6RMdQji2suoZl7ZOwI/InJqVkz1AoYKOBnJbOhRkfGVqHtKaAIVBKFoDTVRVlp9jfls9 2MTxMWpB0UpStLm5MHFjkdyG2XHsiICCeutZNxh9RQchGnOfl5dGj/T1krOKtzROqqsf 9NRCE5d3R7wm8QZNf5ZM7uKOL2JjIM7kQFG2pP5gpj9AWmMnj+H1ex/fSFiw9OCsFrTp QbrzVWF5mD1sVWWoI46UEfCDmV8QZOiug7K4la9uYJE05Ff3OQBUN8v5NvirzFt/QvHO VxMA== X-Gm-Message-State: AOAM532J6uOkpNPQLWeag3Y7pV8HIknnlFm7sFpz0JFb3vMcXDwW4qSJ 0tw5n1qiLnMj9ph+Cmqvnpr43D6ZIEa7Kg== X-Received: by 2002:a17:902:f549:b0:15e:aa35:425a with SMTP id h9-20020a170902f54900b0015eaa35425amr17094160plf.1.1652698837396; Mon, 16 May 2022 04:00:37 -0700 (PDT) Received: from localhost.localdomain ([240d:1a:cf7:5800:82fa:5bff:fe4b:26b1]) by smtp.gmail.com with ESMTPSA id q2-20020a170902edc200b0016173113c50sm2446480plk.92.2022.05.16.04.00.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 16 May 2022 04:00:37 -0700 (PDT) From: Masahisa Kojima To: u-boot@lists.denx.de Cc: Heinrich Schuchardt , Ilias Apalodimas , Simon Glass , Takahiro Akashi , Francois Ozog , Mark Kettenis , Masahisa Kojima , Bin Meng Subject: [PATCH v6 5/6] doc:bootmenu: add description for UEFI boot support Date: Mon, 16 May 2022 20:00:41 +0900 Message-Id: <20220516110043.31480-6-masahisa.kojima@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220516110043.31480-1-masahisa.kojima@linaro.org> References: <20220516110043.31480-1-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 The bootmenu enumerates the UEFI boot options for boot device selection. This commit adds the description how the UEFI boot work in bootmenu. This commit also adds "Synopsis", "Description" and "Configuration" sections to follow the U-Boot command documentation format. Signed-off-by: Masahisa Kojima --- Changes in v6: - remove distro boot related contents because the distro boot support in bootmenu is dropped - update uefi entry example - add [delay] argument of bootmenu command - add description to enable uefi boot entry Changes in v5: - follow the cmd documentation format same as other command, add "Synopsis", "Description" add "Configuration" sections Newly created in v4 doc/usage/cmd/bootmenu.rst | 55 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/doc/usage/cmd/bootmenu.rst b/doc/usage/cmd/bootmenu.rst index 9430f8c9aa..6b154d9655 100644 --- a/doc/usage/cmd/bootmenu.rst +++ b/doc/usage/cmd/bootmenu.rst @@ -4,6 +4,16 @@ bootmenu command ================ +Synopsis +-------- + +:: + + bootmenu [delay] + +Description +----------- + The "bootmenu" command uses U-Boot menu interfaces and provides a simple mechanism for creating menus with different boot items. The cursor keys "Up" and "Down" are used for navigation through @@ -79,6 +89,35 @@ The above example will be rendered as below:: The selected menu entry will be highlighted - it will have inverted background and text colors. +UEFI boot variable enumeration +'''''''''''''''''''''''''''''' + +The bootmenu automatically generates the UEFI boot variable("BOOT####") +in order of "BootOrder". When the user selects the UEFI boot +variable entry, bootmenu sets the selected boot variable index +to "BootNext", then call the uefi boot manager with the command +"bootefi bootmgr". + +The bootmenu automatically enumerates the possible bootable +media devices supporting EFI_SIMPLE_FILE_SYSTEM_PROTOCOL. +This auto generated entry is named as " :" format. +(e.g. "usb 0:1") + +Example bootmenu is as below:: + + *** U-Boot Boot Menu *** + + mmc 0:1 + mmc 0:2 + debian + nvme 0:1 + ubuntu + nvme 0:2 + usb 0:2 + +Configuration +------------- + The "bootmenu" command is enabled by:: CONFIG_CMD_BOOTMENU=y @@ -88,3 +127,19 @@ To run the bootmenu at startup add these additional settings:: CONFIG_AUTOBOOT_KEYED=y CONFIG_BOOTDELAY=30 CONFIG_AUTOBOOT_MENU_SHOW=y + +UEFI boot variable enumeration is enabled by:: + + CONFIG_AUTOBOOT_MENU_SHOW=y + +To improve the product security, entering U-Boot console from bootmenu +can be disabled by:: + + CONFIG_CMD_BOOTMENU_ENTER_UBOOT_CONSOLE=n + +To scan the discoverable devices connected to the buses such as +USB and PCIe prior to bootmenu showing up, CONFIG_PREBOOT can be +used to run the command before showing the bootmenu, i.e.:: + + CONFIG_USE_PREBOOT=y + CONFIG_PREBOOT="pci enum; usb start; scsi scan; nvme scan; virtio scan" From patchwork Mon May 16 11:00:42 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahisa Kojima X-Patchwork-Id: 572968 Delivered-To: patch@linaro.org Received: by 2002:a5d:5051:0:0:0:0:0 with SMTP id h17csp499642wrt; Mon, 16 May 2022 04:01:41 -0700 (PDT) X-Google-Smtp-Source: ABdhPJyvsUtWnMN68i2wRJuk1+yc18/Pnb0hqtEiOwP85wRp7Yud8QhV5S71IbE4QmxrtiFNUjmU X-Received: by 2002:a19:fc0e:0:b0:471:ff7d:ab35 with SMTP id a14-20020a19fc0e000000b00471ff7dab35mr12820505lfi.345.1652698901122; Mon, 16 May 2022 04:01:41 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1652698901; cv=none; d=google.com; s=arc-20160816; b=LakuoEYtoFrIqvcdEhgXRipOXduQe6ZtQiA9sMs1GDj1Om8uFmfXcEJAjMMTugiMwt L9t5BVp4E76YN806AYi/2Ukm/Dt1HMeR++bdSYXshhhWyUVsaJawd6e4YCPiAKLV8C6F 9t3YkzQXc0bACZRxsIglGIB1nz6e/KLl0y6srarca57yaluZe98YDTCKv9ljj8GZRb/Q 07vnTkJO3Y2pCb78I4wjjCuv1DTjUgbhHGvyS40ma4CJkryuyji8Qgc8vZ/DO5RbkJ6d JYZBOGBDTNg/Urgp+397d91oyaTb7uHdVvg2ageSS/zai/xC1wK+An2DDotUe8bqs34V Eyzw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=Glss3yLcLvVhnaoTlv4ckavYbVTzQ9QT8UabKywuM74=; b=B24Ckpma9hafI/yyKaHDV1PXG3dIGOErpzR849skFqj4ibgPINyoHyyagtogmRTm6j DufWDcoPVZ8eMWaL2JfCkoZolbwh5C6t7Mk95U5jh+l+bOf87tegrsFGgiCQabbWkySR OCLWjS+KVXh+X9kjTE2hDRK7HxmL/GqdIpSxuAvC+Pm68i/2jS58l0Mlso5s4CiJZH/x cbbzfL8ik9sBrNYTh0TzVl4NxcwSFwJRhlMt9DjDuKUkRE8aOSLKbc+UYJh+kLVad9wu tCyb8Rt0pTx3y6Iu6ir2X8VpxdWAXB2+NpCFG1r262PgVbg/ZGOr1Ta+SPj9ZE0wnZxQ UQcA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=TT8czj1x; spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 2a01:238:438b:c500:173d:9f52:ddab:ee01 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from phobos.denx.de (phobos.denx.de. [2a01:238:438b:c500:173d:9f52:ddab:ee01]) by mx.google.com with ESMTPS id b32-20020a2ebc20000000b00250896df902si11858635ljf.173.2022.05.16.04.01.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 16 May 2022 04:01:41 -0700 (PDT) Received-SPF: pass (google.com: domain of u-boot-bounces@lists.denx.de designates 2a01:238:438b:c500:173d:9f52:ddab:ee01 as permitted sender) client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=TT8czj1x; spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 2a01:238:438b:c500:173d:9f52:ddab:ee01 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id ED21084203; Mon, 16 May 2022 13:01: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="TT8czj1x"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 6748584099; Mon, 16 May 2022 13:00:54 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE,SPF_PASS, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-pf1-x433.google.com (mail-pf1-x433.google.com [IPv6:2607:f8b0:4864:20::433]) (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 E553F84197 for ; Mon, 16 May 2022 13:00:41 +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=masahisa.kojima@linaro.org Received: by mail-pf1-x433.google.com with SMTP id 204so13706843pfx.3 for ; Mon, 16 May 2022 04:00:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=Glss3yLcLvVhnaoTlv4ckavYbVTzQ9QT8UabKywuM74=; b=TT8czj1xrCvtjkqRdiXLsZh+4aK5bvs81DdWos/Z0/m2X5gskb4rctnhRTL0coRqOr p4rwlWwlfOeE9/MT6yargssZD8wjUH8QKlCFrIbmqbBtA7qxiSvdHak+mJI5c1Oe/TCp W6xZQR95NqMFheA4S3hm8yGHfnmX+tHk9Ov4rjPAzSvnEZT0ImnkWpRjeYGIQU7woOGR yC1hmXWf9TJ7tK5J1koYem8+mbTRRxuQ0xYv8rWKH6cBnmJI88jmmtRsbfpTVEyA14RT hcnk1GHHuZYcvEJMIML6NnS18SxOR7Zp/zXJM/zYFgymH5IGP1HRGB5/JRMttn9qOtyI U1tg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=Glss3yLcLvVhnaoTlv4ckavYbVTzQ9QT8UabKywuM74=; b=k4Yxk3kN/FXAsVBmUhWpKFqhzPDrko3pnZFU6aHlhb+SsseO6/a9FFolmCTg1y4S8p 48DpgDSQfWE+vYItNy7bDn6Tq3T/okPaC3lHzQECrzO4AKmmWk4xYAn00eenHH3x/EST RyJv0jKOUD6Iz8D4+1iTobJqBFM+ghujZ9NoaQ3dKeAyX8B5AOz+45vdhW2/cpZD+z36 n7pPfVBQLFNPJcwPT/H9hVI6cyI2MWd9H1SszJzCh1C/ohClL4CDNHxBD/xdui6yXLGH ThenqIR8N6ma0dnzm+75cvNHq88MMfpPyi1h3z+AYQHcp0IJDs1iaNUcAw2L75I64wm0 dftg== X-Gm-Message-State: AOAM5324qHBGxKxE0zFS2sOFuKE7bShgEW8WnuH5Y+Kok/34+9Y572hC eRuXMkJ+dsPbWkYxNw5ZOvzcYNdGvt5UMA== X-Received: by 2002:a05:6a00:f8a:b0:517:cafd:bef7 with SMTP id ct10-20020a056a000f8a00b00517cafdbef7mr10388424pfb.68.1652698839841; Mon, 16 May 2022 04:00:39 -0700 (PDT) Received: from localhost.localdomain ([240d:1a:cf7:5800:82fa:5bff:fe4b:26b1]) by smtp.gmail.com with ESMTPSA id q2-20020a170902edc200b0016173113c50sm2446480plk.92.2022.05.16.04.00.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 16 May 2022 04:00:39 -0700 (PDT) From: Masahisa Kojima To: u-boot@lists.denx.de Cc: Heinrich Schuchardt , Ilias Apalodimas , Simon Glass , Takahiro Akashi , Francois Ozog , Mark Kettenis , Masahisa Kojima Subject: [PATCH v6 6/6] lib/charset: fix compile warnings Date: Mon, 16 May 2022 20:00:42 +0900 Message-Id: <20220516110043.31480-7-masahisa.kojima@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220516110043.31480-1-masahisa.kojima@linaro.org> References: <20220516110043.31480-1-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 This commit fixes the following compile warnings for the documentation. ./include/charset.h:276: warning: Function parameter or member 'size' not described in 'u16_strlcat' ./include/charset.h:276: warning: Excess function parameter 'count' description in 'u16_strlcat' Signed-off-by: Masahisa Kojima --- Newly created in v6 include/charset.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/charset.h b/include/charset.h index 20abfbe752..e900fd789a 100644 --- a/include/charset.h +++ b/include/charset.h @@ -273,7 +273,7 @@ u16 *u16_strdup(const void *src); * Return: required size including trailing 0x0000 in u16 words * If return value >= count, truncation occurred. */ -size_t u16_strlcat(u16 *dest, const u16 *src, size_t size); +size_t u16_strlcat(u16 *dest, const u16 *src, size_t count); /** * utf16_to_utf8() - Convert an utf16 string to utf8