From patchwork Tue Mar 8 14:07:45 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Masahisa Kojima X-Patchwork-Id: 549288 Delivered-To: patch@linaro.org Received: by 2002:a05:7000:6713:0:0:0:0 with SMTP id u19csp2656092mag; Tue, 8 Mar 2022 06:08:39 -0800 (PST) X-Google-Smtp-Source: ABdhPJzSEefwRXlb1BmyP0lOOMErAY+7fzG272839/5vrhKJBuzAd+yocgvdW7u8E8efHvWpbep2 X-Received: by 2002:a17:907:3e22:b0:6da:83fd:418 with SMTP id hp34-20020a1709073e2200b006da83fd0418mr13648854ejc.321.1646748518968; Tue, 08 Mar 2022 06:08:38 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1646748518; cv=none; d=google.com; s=arc-20160816; b=owVP+mKhilrviP4ouJESnO8/CIh9QFU10Nz++wPT39qaTfBvgyMH7wFzWP/iHzupuQ yS1/FvWXC9il8WQVLW9kl49m6ip4PYBuzI5jH1RcwlYpPuKJyNSI2vKLYG6tX07RHU9L WplBXNpCKFrYYaL/qfwefsEZ/eT+ir25i7w0brjEsoWGNtXwN3ZfKO3L96m6t9OsYRU6 68MCndSVpClSGPPTol0eZ6SxmkUCiqDwYWFpe4/tPkaEDxLnL4QGpd5zrLeC0cGyURKZ dNNiVAs2AAXBQaZYp6LfJZazVES2K3zo1tWBMOVAZ+63mnKIHnENIM96nH8oWmd1VM0y XXSw== 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:content-transfer-encoding :mime-version:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=FeterVYany2pC8QVjP8gnF1/h1e87YyyrEj8rCADLlA=; b=LiKq/mqRUCEQvQbNQuYvBbUIIQHEXfN/zwSswN/JJCyGX25tafxLjv4gHrXvh5G5XR 7Jl44zynnNEIEH6EMFu/rGUCRdMfddkOai9YGUwqO9b6X/hxD5ifwG/2C0dpOWFap3Ye kjgOE0UtDz8UT/DTlM8moiM77m8wL/PuTBPIOR2ZiyJJcXXTiwQ39gQUAuCu4uh1HGU4 WPNawINuGFeKr4Ivan/Ymewo1raNqwLpv3g/fyNePyimhVB91FmYHZR7T+n3+ZZorkAP lKvNF6JMg/B7GwTFBK7E6anfcxEgGOcRBSvbPQcpT7Ks5EbdA9So6lYtO5lbon5twYp1 IMtA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=RVHyIvxa; 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 o4-20020a50fd84000000b0041599071e8asi10745723edt.24.2022.03.08.06.08.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 08 Mar 2022 06:08:38 -0800 (PST) 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=RVHyIvxa; 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 61FEE83995; Tue, 8 Mar 2022 15:08:20 +0100 (CET) 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="RVHyIvxa"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id E0E2983977; Tue, 8 Mar 2022 15:08:09 +0100 (CET) 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-x102b.google.com (mail-pj1-x102b.google.com [IPv6:2607:f8b0:4864:20::102b]) (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 68C52836A9 for ; Tue, 8 Mar 2022 15:07:58 +0100 (CET) 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-x102b.google.com with SMTP id mg21-20020a17090b371500b001bef9e4657cso2372685pjb.0 for ; Tue, 08 Mar 2022 06:07:58 -0800 (PST) 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 :mime-version:content-transfer-encoding; bh=FeterVYany2pC8QVjP8gnF1/h1e87YyyrEj8rCADLlA=; b=RVHyIvxaeQUrt35LVF+ok48Ta/cbhd72mktXsTqMYtu+iGK/OfbqupYDOrVhN09Jaq 05r4cJwwqwlr7PSoA++0UlcoqcN4gEH48RvIIVVq9xrPZXctwQS0VADy2dWxQVl+vvgq yHOsdNGoqR0Ag1jig3KTlUzSQiMVTePZWv7f/KDzwCpl3XGCjHsu1YEq3mf5qqJPQY/k zC3I4pVlTYAnbVMfUCNznJTg/m4cw55EF/6Y/u6Uq9Utwzu57kHS6/+J0XJq3kS1CwbJ +DYyAvsA4bZjlGEqZtPyBZQ0/JqEDomFMLXb+nUV9QbJzt6pPD9b/WFMLeTjtVtOjEZq U/xg== 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:mime-version:content-transfer-encoding; bh=FeterVYany2pC8QVjP8gnF1/h1e87YyyrEj8rCADLlA=; b=ic52gOgdpSCYh3USVsUxw0MGFnKfczE86oY3WpshH/QPNRBZXlEHpQ+2VyEbWHrFSn uahN3jEdEqG6NhqtakK1H2Q3O1aEZrBxSSnae6+bYXqx3bmGn7BdxuUjR5pBJ9qi/4RO /4g2lXUXqh1x+Spa2TQn07fXX/05C5l3Y6Whu8xx7deoGmS9ViAERHJH4jU21BHY0Xov VrK9m2nXBooUlRo6qfMKc1lJ1dzmThWojAJnSCDe84bK5XODjon0BNOxDEEhKPVl/S+b Knl8n8H9ddqFznByurs4Rio9FSqe27VHqbK6xDcNnC6ZduDEWDKF27zetMJhsNK2XXf8 koAg== X-Gm-Message-State: AOAM530hQE+MkCTEEEvqjYtbOzqzO/hMIVA7jqE4Ve0RbwjOfNmx6/tN 0VJuvAOeDRZwgDVowv4/SRhfk2tfIbMIFQ== X-Received: by 2002:a17:90a:dc18:b0:1bf:50c7:a4fa with SMTP id i24-20020a17090adc1800b001bf50c7a4famr4768636pjv.187.1646748476785; Tue, 08 Mar 2022 06:07:56 -0800 (PST) Received: from localhost.localdomain ([240d:1a:cf7:5800:82fa:5bff:fe4b:26b1]) by smtp.gmail.com with ESMTPSA id k62-20020a17090a4cc400b001bf0d92e1c7sm3142989pjh.41.2022.03.08.06.07.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 08 Mar 2022 06:07:56 -0800 (PST) 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: [RFC PATCH v3 2/2] bootmenu: add UEFI and disto_boot entries Date: Tue, 8 Mar 2022 23:07:45 +0900 Message-Id: <20220308140745.26180-3-masahisa.kojima@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220308140745.26180-1-masahisa.kojima@linaro.org> References: <20220308140745.26180-1-masahisa.kojima@linaro.org> MIME-Version: 1.0 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 UEFI related menu entries and distro_boot entries into the bootmenu. For UEFI, user can select which UEFI "Boot####" option to execute, call UEFI bootmgr and UEFI boot variable maintenance menu. UEFI bootmgr entry is required to correctly handle "BootNext" variable. For distro_boot, user can select the boot device included in "boot_targets" u-boot environment variable. The menu example is as follows. *** U-Boot Boot Menu *** Boot 1. kernel (bootmenu_0) Boot 2. kernel (bootmenu_1) Reset board (bootmenu_2) debian (BOOT0000) ubuntu (BOOT0001) UEFI Boot Manager usb0 scsi0 virtio0 dhcp UEFI Boot Manager Maintenance U-Boot console Press UP/DOWN to move, ENTER to select, ESC/CTRL+C to quit Signed-off-by: Masahisa Kojima --- Changes in v3: - newly created cmd/bootmenu.c | 268 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 259 insertions(+), 9 deletions(-) diff --git a/cmd/bootmenu.c b/cmd/bootmenu.c index 409ef9a848..a8dc50dcaa 100644 --- a/cmd/bootmenu.c +++ b/cmd/bootmenu.c @@ -3,9 +3,12 @@ * (C) Copyright 2011-2013 Pali Rohár */ +#include #include #include #include +#include +#include #include #include #include @@ -24,11 +27,20 @@ */ #define MAX_ENV_SIZE (9 + 2 + 1) +enum boot_type { + BOOT_TYPE_NONE = 0, + BOOT_TYPE_BOOTMENU, + BOOT_TYPE_UEFI, + BOOT_TYPE_DISTRO_BOOT, +}; + struct bootmenu_entry { unsigned short int num; /* unique number 0 .. MAX_COUNT */ char key[3]; /* key identifier of number */ - char *title; /* title of entry */ + u16 *title; /* title of entry */ char *command; /* hush command of entry */ + enum boot_type type; + u16 bootorder; struct bootmenu_data *menu; /* this bootmenu */ struct bootmenu_entry *next; /* next menu entry (num+1) */ }; @@ -75,7 +87,12 @@ static void bootmenu_print_entry(void *data) if (reverse) puts(ANSI_COLOR_REVERSE); - puts(entry->title); + if (entry->type == BOOT_TYPE_BOOTMENU) + printf("%ls (bootmenu_%d)", entry->title, entry->bootorder); + else if (entry->type == BOOT_TYPE_UEFI) + printf("%ls (BOOT%04X)", entry->title, entry->bootorder); + else + printf("%ls", entry->title); if (reverse) puts(ANSI_COLOR_RESET); @@ -87,6 +104,10 @@ static void bootmenu_autoboot_loop(struct bootmenu_data *menu, int i, c; if (menu->delay > 0) { + /* flush input */ + while (tstc()) + getchar(); + printf(ANSI_CURSOR_POSITION, menu->count + 5, 1); printf(" Hit any key to stop autoboot: %2d ", menu->delay); } @@ -300,6 +321,8 @@ static struct bootmenu_data *bootmenu_create(int delay) menu->active = (int)simple_strtol(default_str, NULL, 10); while ((option = bootmenu_getoption(i))) { + u16 *buf; + sep = strchr(option, '='); if (!sep) { printf("Invalid bootmenu entry: %s\n", option); @@ -311,13 +334,13 @@ static struct bootmenu_data *bootmenu_create(int delay) goto cleanup; len = sep-option; - entry->title = malloc(len + 1); + buf = calloc(1, (len + 1) * sizeof(u16)); + entry->title = buf; if (!entry->title) { free(entry); goto cleanup; } - memcpy(entry->title, option, len); - entry->title[len] = 0; + utf8_utf16_strncpy(&buf, option, len); len = strlen(sep + 1); entry->command = malloc(len + 1); @@ -333,6 +356,190 @@ static struct bootmenu_data *bootmenu_create(int delay) entry->num = i; entry->menu = menu; + entry->type = BOOT_TYPE_BOOTMENU; + entry->bootorder = i; + entry->next = NULL; + + if (!iter) + menu->first = entry; + else + iter->next = entry; + + iter = entry; + ++i; + + if (i == MAX_COUNT - 1) + break; + } + +{ + u16 *bootorder; + efi_status_t ret; + unsigned short j; + efi_uintn_t num, size; + void *load_option; + struct efi_load_option lo; + u16 varname[] = u"Boot####"; + + /* Initialize EFI drivers */ + ret = efi_init_obj_list(); + if (ret != EFI_SUCCESS) { + log_err("Error: Cannot initialize UEFI sub-system, r = %lu\n", + ret & ~EFI_ERROR_MASK); + goto cleanup; + } + + bootorder = efi_get_var(u"BootOrder", &efi_global_variable_guid, &size); + if (!bootorder) + goto bootmgr; + + num = size / sizeof(u16); + for (j = 0; j < num; j++) { + entry = malloc(sizeof(struct bootmenu_entry)); + if (!entry) + goto cleanup; + + efi_create_indexed_name(varname, sizeof(varname), + "Boot", bootorder[j]); + 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) { + char *command; + int command_size; + + entry->title = u16_strdup(lo.label); + if (!entry->title) { + free(load_option); + free(entry); + goto cleanup; + } + command_size = strlen("bootefi bootindex XXXX") + 1; + command = calloc(1, command_size); + if (!command) { + free(entry->title); + free(load_option); + free(entry); + goto cleanup; + } + snprintf(command, command_size, "bootefi bootindex %X", bootorder[j]); + entry->command = command; + sprintf(entry->key, "%d", i); + entry->num = i; + entry->menu = menu; + entry->type = BOOT_TYPE_UEFI; + entry->bootorder = bootorder[j]; + entry->next = NULL; + + if (!iter) + menu->first = entry; + else + iter->next = entry; + + iter = entry; + ++i; + } + + if (i == MAX_COUNT - 1) + break; + } + free(bootorder); +} + +bootmgr: + /* Add UEFI Boot Manager entry if available */ + if (IS_ENABLED(CONFIG_CMD_BOOTEFI_BOOTMGR)) { + if (i <= MAX_COUNT - 1) { + entry = malloc(sizeof(struct bootmenu_entry)); + if (!entry) + goto cleanup; + + entry->title = u16_strdup(u"UEFI Boot Manager"); + if (!entry->title) { + free(entry); + goto cleanup; + } + + entry->command = strdup("bootefi bootmgr"); + if (!entry->command) { + free(entry->title); + free(entry); + goto cleanup; + } + + sprintf(entry->key, "%d", i); + + entry->num = i; + entry->menu = menu; + entry->type = BOOT_TYPE_NONE; + entry->next = NULL; + + if (!iter) + menu->first = entry; + else + iter->next = entry; + + iter = entry; + ++i; + } + } + +{ + char *p; + char *token; + char *boot_targets; + int len; + + /* list the distro boot "boot_targets" */ + boot_targets = env_get("boot_targets"); + if (!boot_targets) + goto exit_boot_targets; + + len = strlen(boot_targets); + p = calloc(1, len + 1); + strncpy(p, boot_targets, len); + + token = strtok(p, " "); + + do { + u16 *buf; + char *command; + int command_size; + + entry = malloc(sizeof(struct bootmenu_entry)); + if (!entry) + goto cleanup; + + len = strlen(token); + buf = calloc(1, (len + 1) * sizeof(u16)); + entry->title = buf; + if (!entry->title) { + free(entry); + goto cleanup; + } + utf8_utf16_strncpy(&buf, token,len); + sprintf(entry->key, "%d", i); + entry->num = i; + entry->menu = menu; + + command_size = strlen("run bootcmd_") + len + 1; + command = calloc(1, command_size); + if (!command) { + free(entry->title); + free(entry); + goto cleanup; + } + snprintf(command, command_size, "run bootcmd_%s", token); + entry->command = command; + entry->type = BOOT_TYPE_DISTRO_BOOT; entry->next = NULL; if (!iter) @@ -345,6 +552,48 @@ static struct bootmenu_data *bootmenu_create(int delay) if (i == MAX_COUNT - 1) break; + + token = strtok(NULL, " "); + } while (token); + + free(p); +} + +exit_boot_targets: + + /* Add UEFI Boot Manager Maintenance entry */ + if (i <= MAX_COUNT - 1) { + 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("echo TODO: Not implemented"); + if (!entry->command) { + free(entry->title); + free(entry); + goto cleanup; + } + + sprintf(entry->key, "%d", i); + + entry->num = i; + entry->menu = menu; + entry->type = BOOT_TYPE_NONE; + entry->next = NULL; + + if (!iter) + menu->first = entry; + else + iter->next = entry; + + iter = entry; + ++i; } /* Add U-Boot console entry at the end */ @@ -353,7 +602,7 @@ static struct bootmenu_data *bootmenu_create(int delay) if (!entry) goto cleanup; - entry->title = strdup("U-Boot console"); + entry->title = u16_strdup(u"U-Boot console"); if (!entry->title) { free(entry); goto cleanup; @@ -370,6 +619,7 @@ static struct bootmenu_data *bootmenu_create(int delay) entry->num = i; entry->menu = menu; + entry->type = BOOT_TYPE_NONE; entry->next = NULL; if (!iter) @@ -427,7 +677,7 @@ static void bootmenu_show(int delay) { int init = 0; void *choice = NULL; - char *title = NULL; + u16 *title = NULL; char *command = NULL; struct menu *menu; struct bootmenu_data *bootmenu; @@ -478,7 +728,7 @@ static void bootmenu_show(int delay) if (menu_get_choice(menu, &choice)) { iter = choice; - title = strdup(iter->title); + title = u16_strdup(iter->title); command = strdup(iter->command); } @@ -493,7 +743,7 @@ cleanup: } if (title && command) { - debug("Starting entry '%s'\n", title); + debug("Starting entry '%ls'\n", title); free(title); run_command(command, 0); free(command);