From patchwork Fri Sep 2 14:23:46 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahisa Kojima X-Patchwork-Id: 602177 Delivered-To: patch@linaro.org Received: by 2002:a05:7000:4388:0:0:0:0 with SMTP id w8csp1509652mae; Fri, 2 Sep 2022 07:23:33 -0700 (PDT) X-Google-Smtp-Source: AA6agR54g+f+JUa5rKUKvMMosZClqDr1oxQkVBsml6MKb7djQL2BoJfP/4l6Y5KZsMzIT1V4duo7 X-Received: by 2002:a05:6402:524b:b0:448:6824:8788 with SMTP id t11-20020a056402524b00b0044868248788mr21842676edd.227.1662128613134; Fri, 02 Sep 2022 07:23:33 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1662128613; cv=none; d=google.com; s=arc-20160816; b=H9ntI04V7c0NjvwEuf4EAAkPXGOswcHPmDEJw6etqzog5N/ST2OF1YYGjo6ugxGRN9 Rfcsi/aV/GaCQXewq3ovT6kQ22Cn1ca8sXRiRvjPQthevcYLPsMYP6k1O3f23rdQ1IG9 jDT71zoHAAfmd3cE473r+6kAiQMNgZdSgkvn4oiAh4ilB3FcvxGeI2Aw1C3lyOEdK7fp y8vzXptuwIrDflyPmLAS54wnu7Xa340Swby3RMI67XGYZC9nG+kPVrqzgrJ8lx3OAUJE gzgm1xRick3KbVlo986oxloKkQT16jWp0LWgt0lh4MIMT+DnPa77J23d8scJFSE7Iads cU4Q== 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=XDW+KZXsC3hIYACbgM/QHrvF8AX9hg2rj4YUL9nZ434=; b=RKwEMADDAI4s/OWr7vT7Y0swCjUYTUUIhoZoXtfINmr5DcfCUQ3GdN2WAf47P/yjQs Bp39ULYXxvfGnB8hE5H1vuWVU3ZOUKmd+vYR2asMhhpS3pRqCzM0hWxCa5tWWFy25yF4 XqzbLjC43TuIbb0y3yK0fwpm3j++21elz45BvtgtKoZcEBOhGOS5PZh9EXarRfhIA0Dg tMqKo0eJuePpg8QWqqw6KuiLrCgfUvmRjtHRw2tDmtRO6P8HaRbpBFLiG7iSBb4BbbuF yECulk5jQ35AdstvZC2G6N6EZjnhX4cKiO7WNtTQzAxKfYpvZepeuHQVLE4xSx1N7BfT efjQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=P8VCDPhj; 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 he12-20020a1709073d8c00b0073d8e16fd75si2184816ejc.567.2022.09.02.07.23.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 02 Sep 2022 07:23:33 -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=P8VCDPhj; 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 BD48584AF0; Fri, 2 Sep 2022 16:22:32 +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="P8VCDPhj"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id ABF1784AFD; Fri, 2 Sep 2022 16:22:30 +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-x435.google.com (mail-pf1-x435.google.com [IPv6:2607:f8b0:4864:20::435]) (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 2F8CC84AEF for ; Fri, 2 Sep 2022 16:22: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=masahisa.kojima@linaro.org Received: by mail-pf1-x435.google.com with SMTP id y127so2026869pfy.5 for ; Fri, 02 Sep 2022 07:22:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=references:in-reply-to:message-id:date:subject:cc:to:from:from:to :cc:subject:date; bh=XDW+KZXsC3hIYACbgM/QHrvF8AX9hg2rj4YUL9nZ434=; b=P8VCDPhjPoWLzSmITOefGSu6UOs17mN/xlEgLkUEGYtdDLzqhxRX5vyKM8+ZqI53Zd OXuBJwPyY716W2amG4Fzat6Qt7+OKrFuQ1d4zodIcF4jH8WPVkwqcU4zGPdJM5MldGab u6dDvzaXR3tCe3aaAeMJgrE+X7s32A3Ws7DyCDk1PFTuKljfUd5/emr45lAWJHyxEBq7 CYqlblYUcaljUF9eSyR2v9qsrs+SoKWjuna7WFiiWD0P22TjjBZvZHbmqpTr2/wCFWwM RPfQaljkMlete3v9vXXoiuoemQ/mo5NoRQrnCCScETzrrVzpnNoeVeYp0E3gEeYGHeUy FbNg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=references:in-reply-to:message-id:date:subject:cc:to:from :x-gm-message-state:from:to:cc:subject:date; bh=XDW+KZXsC3hIYACbgM/QHrvF8AX9hg2rj4YUL9nZ434=; b=crQ7wkfFPSncyra1ptmRlkzBqsAv/l8ZouiRdn/DXrcinAR1oOSp/Y6zkRmyscVG0L dSOKalfXwMYnfGSOQJbuEaKwK69B71r3uThmh0uCAhfxq9IXasoocY7bQdtaE5K2S9Nx P3PKzEVdPuVbTFVtD2IGkuz66LWd1+ag+mxa5+bnu24PCgIaYB5gK/HZ5RUR0Xql0uMh 57n+z670Xg5FVfu8eIq1UjeskNSrRdXt3YUyO949jn2Jv05Y9u9TRVhs2vlPHhj7ej2z JByhonor6AgI3v0OvqclguIbyIjpOPoTXcffNF4gggTKW5TylZ9k8CCglnbnUpvxJSjZ ysEg== X-Gm-Message-State: ACgBeo1Kr6XIy1u8Ca5zcym0PRTzuPKy6grcMpDfFDnvrAGr56EmOGuG QJblBQpmR1Hs6fc+H8BgE6QQQ4y2o7Obsg== X-Received: by 2002:a63:1a16:0:b0:430:581d:827f with SMTP id a22-20020a631a16000000b00430581d827fmr9552917pga.276.1662128544840; Fri, 02 Sep 2022 07:22:24 -0700 (PDT) Received: from localhost.localdomain ([240d:1a:cf7:5800:82fa:5bff:fe4b:26b1]) by smtp.gmail.com with ESMTPSA id i8-20020a17090332c800b0017272667a56sm1678485plr.196.2022.09.02.07.22.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 02 Sep 2022 07:22:24 -0700 (PDT) From: Masahisa Kojima To: u-boot@lists.denx.de Cc: Heinrich Schuchardt , Ilias Apalodimas , Simon Glass , Takahiro Akashi , Mark Kettenis , Masahisa Kojima Subject: [PATCH v15 07/10] eficonfig: add "Change Boot Order" menu entry Date: Fri, 2 Sep 2022 23:23:46 +0900 Message-Id: <20220902142349.16722-8-masahisa.kojima@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220902142349.16722-1-masahisa.kojima@linaro.org> References: <20220902142349.16722-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.6 at phobos.denx.de X-Virus-Status: Clean This commit adds the menu entry to update UEFI BootOrder variable. User moves the entry with UP/DOWN key, changes the order with PLUS/MINUS key, press SPACE to activate or deactivate the entry, then finalizes the order by ENTER key. If the entry is activated, the boot index is added into the BootOrder variable in the order of the list. The U-Boot menu framework is well designed for static menu, this commit implements the own menu display and key handling for dynamically change the order of menu entry. Signed-off-by: Masahisa Kojima --- No update since v15 Changes in v14: - remove scan of media device, it is moved into eficonfig startup - add comment in default case for key handling - add missing break in eficonfig_choice_entry Changes in v12: - enumerate removable media device Changes in v11: - remove BootOrder variable dependency - use ANSI_CURSOR_POSITION and ANSI_CLEAR_LINE instead of printf("\n") since current eficonfig implementation does not handle console size correctly. printf("\n") at the outside of console size breaks the console output. - add KEY_SPACE to toggle the boot option active status No update since v9 Changes in v9: - add function comment Changes in v8: - add "Save" and "Quit" entries Changes in v7: - use UP/DOWN and PLUS/MINUS key to change to order no update in v6: cmd/eficonfig.c | 348 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 347 insertions(+), 1 deletion(-) diff --git a/cmd/eficonfig.c b/cmd/eficonfig.c index dda45a8364..2e1f2bfd8b 100644 --- a/cmd/eficonfig.c +++ b/cmd/eficonfig.c @@ -91,6 +91,23 @@ struct eficonfig_boot_selection_data { int *selected; }; +/** + * struct eficonfig_boot_order - structure to be used to update BootOrder variable + * + * @num: index in the menu entry + * @description: pointer to the description string + * @boot_index: boot option index + * @active: flag to include the boot option into BootOrder variable + * @list: list structure + */ +struct eficonfig_boot_order { + u32 num; + u16 *description; + u32 boot_index; + bool active; + struct list_head list; +}; + /** * eficonfig_print_msg() - print message * @@ -1748,6 +1765,335 @@ out: return ret; } +/** + * eficonfig_display_change_boot_order() - display the BootOrder list + * + * @efi_menu: pointer to the efimenu structure + * Return: status code + */ +static void eficonfig_display_change_boot_order(struct efimenu *efi_menu) +{ + bool reverse; + struct list_head *pos, *n; + struct eficonfig_boot_order *entry; + + printf(ANSI_CLEAR_CONSOLE ANSI_CURSOR_POSITION + "\n ** Change Boot Order **\n" + ANSI_CURSOR_POSITION + " Press UP/DOWN to move, +/- to change order" + ANSI_CURSOR_POSITION + " Press SPACE to activate or deactivate the entry" + ANSI_CURSOR_POSITION + " Select [Save] to complete, ESC/CTRL+C to quit" + ANSI_CURSOR_POSITION ANSI_CLEAR_LINE, + 1, 1, efi_menu->count + 5, 1, efi_menu->count + 6, 1, + efi_menu->count + 7, 1, efi_menu->count + 8, 1); + + /* draw boot option list */ + list_for_each_safe(pos, n, &efi_menu->list) { + entry = list_entry(pos, struct eficonfig_boot_order, list); + reverse = (entry->num == efi_menu->active); + + printf(ANSI_CURSOR_POSITION, entry->num + 4, 7); + + if (reverse) + puts(ANSI_COLOR_REVERSE); + + if (entry->num < efi_menu->count - 2) { + if (entry->active) + printf("[*] "); + else + printf("[ ] "); + } + + printf("%ls", entry->description); + + if (reverse) + puts(ANSI_COLOR_RESET); + } +} + +/** + * eficonfig_choice_change_boot_order() - handle the BootOrder update + * + * @efi_menu: pointer to the efimenu structure + * Return: status code + */ +static efi_status_t eficonfig_choice_change_boot_order(struct efimenu *efi_menu) +{ + int esc = 0; + struct list_head *pos, *n; + struct eficonfig_boot_order *tmp; + enum bootmenu_key key = KEY_NONE; + struct eficonfig_boot_order *entry; + + while (1) { + bootmenu_loop(NULL, &key, &esc); + + switch (key) { + case KEY_PLUS: + if (efi_menu->active > 0) { + list_for_each_safe(pos, n, &efi_menu->list) { + entry = list_entry(pos, struct eficonfig_boot_order, list); + if (entry->num == efi_menu->active) + break; + } + tmp = list_entry(pos->prev, struct eficonfig_boot_order, list); + entry->num--; + tmp->num++; + list_del(&tmp->list); + list_add(&tmp->list, &entry->list); + } + fallthrough; + case KEY_UP: + if (efi_menu->active > 0) + --efi_menu->active; + return EFI_NOT_READY; + case KEY_MINUS: + if (efi_menu->active < efi_menu->count - 3) { + list_for_each_safe(pos, n, &efi_menu->list) { + entry = list_entry(pos, struct eficonfig_boot_order, list); + if (entry->num == efi_menu->active) + break; + } + tmp = list_entry(pos->next, struct eficonfig_boot_order, list); + entry->num++; + tmp->num--; + list_del(&entry->list); + list_add(&entry->list, &tmp->list); + + ++efi_menu->active; + } + return EFI_NOT_READY; + case KEY_DOWN: + if (efi_menu->active < efi_menu->count - 1) + ++efi_menu->active; + return EFI_NOT_READY; + case KEY_SELECT: + /* "Save" */ + if (efi_menu->active == efi_menu->count - 2) + return EFI_SUCCESS; + + /* "Quit" */ + if (efi_menu->active == efi_menu->count - 1) + return EFI_ABORTED; + + break; + case KEY_SPACE: + if (efi_menu->active < efi_menu->count - 2) { + list_for_each_safe(pos, n, &efi_menu->list) { + entry = list_entry(pos, struct eficonfig_boot_order, list); + if (entry->num == efi_menu->active) { + entry->active = entry->active ? false : true; + return EFI_NOT_READY; + } + } + } + break; + case KEY_QUIT: + return EFI_ABORTED; + default: + /* Pressed key is not valid, no need to regenerate the menu */ + break; + } + } +} + +/** + * eficonfig_add_change_boot_order_entry() - add boot order entry + * + * @efi_menu: pointer to the efimenu structure + * @boot_index: boot option index to be added + * @active: flag to include the boot option into BootOrder + * Return: status code + */ +static efi_status_t eficonfig_add_change_boot_order_entry(struct efimenu *efi_menu, + u32 boot_index, bool active) +{ + efi_status_t ret; + efi_uintn_t size; + void *load_option; + struct efi_load_option lo; + u16 varname[] = u"Boot####"; + struct eficonfig_boot_order *entry; + + efi_create_indexed_name(varname, sizeof(varname), "Boot", boot_index); + load_option = efi_get_var(varname, &efi_global_variable_guid, &size); + if (!load_option) + return EFI_SUCCESS; + + ret = efi_deserialize_load_option(&lo, load_option, &size); + if (ret != EFI_SUCCESS) { + free(load_option); + return ret; + } + + entry = calloc(1, sizeof(struct eficonfig_boot_order)); + if (!entry) { + free(load_option); + return EFI_OUT_OF_RESOURCES; + } + + entry->description = u16_strdup(lo.label); + if (!entry->description) { + free(load_option); + free(entry); + return EFI_OUT_OF_RESOURCES; + } + entry->num = efi_menu->count++; + entry->boot_index = boot_index; + entry->active = active; + list_add_tail(&entry->list, &efi_menu->list); + + free(load_option); + + return EFI_SUCCESS; +} + +/** + * eficonfig_create_change_boot_order_entry() - create boot order entry + * + * @efi_menu: pointer to the efimenu structure + * @bootorder: pointer to the BootOrder variable + * @num: number of BootOrder entry + * Return: status code + */ +static efi_status_t eficonfig_create_change_boot_order_entry(struct efimenu *efi_menu, + u16 *bootorder, efi_uintn_t num) +{ + u32 i; + efi_status_t ret; + struct eficonfig_boot_order *entry; + + /* list the load option in the order of BootOrder variable */ + for (i = 0; i < num; i++) { + if (efi_menu->count >= EFICONFIG_ENTRY_NUM_MAX - 2) + break; + + ret = eficonfig_add_change_boot_order_entry(efi_menu, bootorder[i], true); + if (ret != EFI_SUCCESS) + goto out; + } + + /* list the remaining load option not included in the BootOrder */ + for (i = 0; i < 0xFFFF; i++) { + if (efi_menu->count >= EFICONFIG_ENTRY_NUM_MAX - 2) + break; + + /* If the index is included in the BootOrder, skip it */ + if (search_bootorder(bootorder, num, i, NULL)) + continue; + + ret = eficonfig_add_change_boot_order_entry(efi_menu, i, false); + if (ret != EFI_SUCCESS) + goto out; + } + + /* add "Save" and "Quit" entries */ + entry = calloc(1, sizeof(struct eficonfig_boot_order)); + if (!entry) + goto out; + + entry->num = efi_menu->count++; + entry->description = u16_strdup(u"Save"); + list_add_tail(&entry->list, &efi_menu->list); + + entry = calloc(1, sizeof(struct eficonfig_boot_order)); + if (!entry) + goto out; + + entry->num = efi_menu->count++; + entry->description = u16_strdup(u"Quit"); + list_add_tail(&entry->list, &efi_menu->list); + + efi_menu->active = 0; + + return EFI_SUCCESS; +out: + return EFI_OUT_OF_RESOURCES; +} + +/** + * eficonfig_process_change_boot_order() - handler to change boot order + * + * @data: pointer to the data for each entry + * Return: status code + */ +static efi_status_t eficonfig_process_change_boot_order(void *data) +{ + u32 count; + u16 *bootorder; + efi_status_t ret; + efi_uintn_t num, size; + struct list_head *pos, *n; + struct eficonfig_boot_order *entry; + struct efimenu *efi_menu; + + efi_menu = calloc(1, sizeof(struct efimenu)); + if (!efi_menu) + return EFI_OUT_OF_RESOURCES; + + bootorder = efi_get_var(u"BootOrder", &efi_global_variable_guid, &size); + + INIT_LIST_HEAD(&efi_menu->list); + num = size / sizeof(u16); + ret = eficonfig_create_change_boot_order_entry(efi_menu, bootorder, num); + if (ret != EFI_SUCCESS) + goto out; + + while (1) { + eficonfig_display_change_boot_order(efi_menu); + + ret = eficonfig_choice_change_boot_order(efi_menu); + if (ret == EFI_SUCCESS) { + u16 *new_bootorder; + + new_bootorder = calloc(1, (efi_menu->count - 2) * sizeof(u16)); + if (!new_bootorder) { + ret = EFI_OUT_OF_RESOURCES; + goto out; + } + + /* create new BootOrder */ + count = 0; + list_for_each_safe(pos, n, &efi_menu->list) { + entry = list_entry(pos, struct eficonfig_boot_order, list); + if (entry->active) + new_bootorder[count++] = entry->boot_index; + } + + size = count * sizeof(u16); + ret = efi_set_variable_int(u"BootOrder", &efi_global_variable_guid, + EFI_VARIABLE_NON_VOLATILE | + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, + size, new_bootorder, false); + + free(new_bootorder); + goto out; + } else if (ret == EFI_NOT_READY) { + continue; + } else { + goto out; + } + } +out: + list_for_each_safe(pos, n, &efi_menu->list) { + entry = list_entry(pos, struct eficonfig_boot_order, list); + list_del(&entry->list); + free(entry->description); + free(entry); + } + + free(bootorder); + free(efi_menu); + + /* to stay the parent menu */ + ret = (ret == EFI_ABORTED) ? EFI_NOT_READY : ret; + + return ret; +} + /** * delete_boot_option() - delete selected boot option * @@ -2025,7 +2371,6 @@ out: return ret; } - /** * eficonfig_init() - do required initialization for eficonfig command * @@ -2056,6 +2401,7 @@ static efi_status_t eficonfig_init(void) static const struct eficonfig_item maintenance_menu_items[] = { {"Add Boot Option", eficonfig_process_add_boot_option}, {"Edit Boot Option", eficonfig_process_edit_boot_option}, + {"Change Boot Order", eficonfig_process_change_boot_order}, {"Delete Boot Option", eficonfig_process_delete_boot_option}, {"Quit", eficonfig_process_quit}, };