From patchwork Thu Mar 24 13:54:39 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Masahisa Kojima X-Patchwork-Id: 553918 Delivered-To: patch@linaro.org Received: by 2002:a05:7000:1248:0:0:0:0 with SMTP id z8csp4438986mag; Thu, 24 Mar 2022 06:56:20 -0700 (PDT) X-Google-Smtp-Source: ABdhPJyONZeRCWxgHkVp5X4zrF4i62fjp0tBEG7s0x4AWX/nt6xQRqyIeL/zqvsSYaWoBppknz4U X-Received: by 2002:a17:906:2a0c:b0:6df:ec76:af8c with SMTP id j12-20020a1709062a0c00b006dfec76af8cmr5759801eje.269.1648130180377; Thu, 24 Mar 2022 06:56:20 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1648130180; cv=none; d=google.com; s=arc-20160816; b=sVwTHDfayfRhZb3LQQdq1R+if0N0dGkAZlIS1getr+YiQyeYq+m/RmFwGVtVFFFuO3 hwqcjDEGLaG9j9rJoJ3A3u+ALGmkoun7en8xAgH9zEP9+dFu7W/p7CHjsYJUBp95SKYY e8HuMqfWSn7sUBoVtVXm5qTe38MpbdrcoIsCV/uE4GWmdY/jhZEviF8otQCKO9w0kG3F HYetDDwr3YRa0QvB/6a4sPc9PwJ88ttXfbpcqnyhfNaeXWvq7s0qf6oQZZojeOc4/lfA 3FRWl0I7SsOb88RayjfOK4YYcw0Zxd0ooGegtT1J1nX+p3d6H2fttdDHFHH63zhUCjPk +bRw== 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=ipuQmM3oZLP1WmIxqKmCEQhRJj1SQDrjEpvrIgBOu5w=; b=s74MIJ8R+mT/0DPBYLqBkuXed78xiLb2uUwgwErj0t9aHAbltXYj9bBr+GgcqjgbIv V42qph6OipxgR7DzqV5eDEBBQh47HyOsYhMrNJ6hIxaBD4cvzJjIiIS35s6/V5udZPdG BzspKxXHpzkJeG/zER5HX7FrD5952TGVffL+GH9wSTVYBEGOqCEKLzbkST8oL/Thd8Ky R426SZbBQ0P4pgiZR5aIxvl9gXXo/rqK1p6+CPBJU6x5ECktqsH4uWvqLvyDVIiz/+uV VsqCCbv7K4it7j2oJqWCIA/3uMB6ouOlWwxUYStKbYioMKZowsrexvjzUo9oZkx+0RuB pO6Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=X6TIZxmA; 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 z2-20020a170906270200b006df76385e97si15655618ejc.823.2022.03.24.06.56.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 24 Mar 2022 06:56:20 -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=X6TIZxmA; 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 0BE6B840D4; Thu, 24 Mar 2022 14:55:24 +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="X6TIZxmA"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 0A9B7840D1; Thu, 24 Mar 2022 14:55:11 +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-x102c.google.com (mail-pj1-x102c.google.com [IPv6:2607:f8b0:4864:20::102c]) (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 9754A840BB for ; Thu, 24 Mar 2022 14:55:00 +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-x102c.google.com with SMTP id mp6-20020a17090b190600b001c6841b8a52so9527920pjb.5 for ; Thu, 24 Mar 2022 06:55:00 -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 :mime-version:content-transfer-encoding; bh=ipuQmM3oZLP1WmIxqKmCEQhRJj1SQDrjEpvrIgBOu5w=; b=X6TIZxmAYeyr8+to3wze0iw7+qRRYDKMxavGE11fM/hVSSvu5K306HCm1H14k4pJX5 +rDj8IIiwceHuRFWlh4Dk44kT4mUP+Y5Kxd8S7RoRcIdfUT6C7ZxBs3rewbT7K1XMrfV g5eGD/6jVCtFjijYpld9CFi9p8jtr8N3NIPkqQS6bXC30XXr1qAy7wFK799LUe/u73FN rpeJduNrKsA0l8nuPxtZfWvlge1flO98RAEFVFscZHO8mafBBtOnfrls9JYVIexqUoMz fTLXtrEb2ibYG1+z8o1mEEMd5jtjEVwtFHezittB1ltUzgpFLdPjc6aLs2eWqdRAZ4sj JfkA== 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=ipuQmM3oZLP1WmIxqKmCEQhRJj1SQDrjEpvrIgBOu5w=; b=uMrxBAyBjO1CNRd342vjscrkiZrYNj+rDq2RQ35YHxLo2XDP1+qUiFZv27U3cClQr/ fCmfW0Q4Oy7oNCX+BsdCwvI4uPyqtFnF04XJHhsixcha+NdpYDw1u3FZybeyLolgcSup q1cPdPvEKnDtdtbImNNB7qI8uDBfXksLeg52Cp45HKTJPvftwnGOUEolv+5KnycaaJfU a5uhGHHEUgE5OSXR0jECQuyGXaqmsOHdJ+tGzoBGPzNtWJl/EhvMQyMmtE5eZYtueuWP ObfdYB4LwDCEiK5H6faUA4mkS3TKiWjdL81DwonzXTK+9zckxjYxWnZsM5Vmej36pKLl 9oyA== X-Gm-Message-State: AOAM532fd8a6tODNUWqX5kX3KYppZDfDl7DZUfTipRgYLN12GgWv3een 9eNa+xY00eFWJMbpV1hrQ5EKu2sfbjsQPnHM X-Received: by 2002:a17:90b:1a87:b0:1c7:3d66:8cb with SMTP id ng7-20020a17090b1a8700b001c73d6608cbmr18677167pjb.142.1648130098704; Thu, 24 Mar 2022 06:54:58 -0700 (PDT) Received: from localhost.localdomain ([240d:1a:cf7:5800:82fa:5bff:fe4b:26b1]) by smtp.gmail.com with ESMTPSA id p15-20020a056a000a0f00b004f7c63cba5asm3974609pfh.21.2022.03.24.06.54.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 24 Mar 2022 06:54:58 -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 , Peng Fan , Jaehoon Chung , Michal Simek , Kory Maincent , Aswath Govindraju , Ovidiu Panait , Ashok Reddy Soma , Franck LENORMAND Subject: [PATCH v4 07/11] bootmenu: add UEFI and disto_boot entries Date: Thu, 24 Mar 2022 22:54:39 +0900 Message-Id: <20220324135443.1571-8-masahisa.kojima@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220324135443.1571-1-masahisa.kojima@linaro.org> References: <20220324135443.1571-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 *** bootmenu_00 : Boot 1. kernel bootmenu_01 : Boot 2. kernel bootmenu_02 : Reset board UEFI BOOT0000 : debian UEFI BOOT0001 : ubuntu distro_boot : usb0 distro_boot : scsi0 distro_boot : virtio0 distro_boot : dhcp Press UP/DOWN to move, ENTER to select, ESC/CTRL+C to quit Signed-off-by: Masahisa Kojima --- Changes in v4: - add Kconfig option "CMD_BOOTMENU_ENTER_UBOOT_CONSOLE" to disable to enter U-Boot console from bootmenu - update the menu entry display format - create local function to create menu entry for bootmenu, UEFI boot option and distro boot command - handle "BootNext" before showing bootmenu - call "bootefi bootmgr" instead of "bootefi bootindex" - move bootmenu_show() into loop - add default boot behavior(run "bootefi bootmgr" then "run bootcmd") when user quit the bootmenu if U-Boot console is disabled Changes in v3: - newly created cmd/Kconfig | 10 ++ cmd/bootmenu.c | 393 +++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 360 insertions(+), 43 deletions(-) diff --git a/cmd/Kconfig b/cmd/Kconfig index 5e25e45fd2..5fbeab266f 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -300,6 +300,16 @@ config CMD_BOOTMENU help Add an ANSI terminal boot menu command. +config CMD_BOOTMENU_ENTER_UBOOT_CONSOLE + bool "Allow Bootmenu to enter the U-Boot console" + depends on CMD_BOOTMENU + default n + help + Add an entry to enter U-Boot console in bootmenu. + If this option is disabled, user can not enter + the U-Boot console from bootmenu. It increases + the system security. + config CMD_ADTIMG bool "adtimg" help diff --git a/cmd/bootmenu.c b/cmd/bootmenu.c index d573487272..947b3a49ff 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,27 @@ */ #define MAX_ENV_SIZE (9 + 2 + 1) +enum bootmenu_ret { + BOOTMENU_RET_SUCCESS = 0, + BOOTMENU_RET_FAIL, + BOOTMENU_RET_QUIT, + BOOTMENU_RET_UPDATED, +}; + +enum boot_type { + BOOTMENU_TYPE_NONE = 0, + BOOTMENU_TYPE_BOOTMENU, + BOOTMENU_TYPE_UEFI_BOOT_OPTION, + BOOTMENU_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; /* boot type of entry */ + u16 bootorder; /* order for each boot type */ struct bootmenu_data *menu; /* this bootmenu */ struct bootmenu_entry *next; /* next menu entry (num+1) */ }; @@ -75,7 +94,14 @@ static void bootmenu_print_entry(void *data) if (reverse) puts(ANSI_COLOR_REVERSE); - puts(entry->title); + if (entry->type == BOOTMENU_TYPE_BOOTMENU) + printf("bootmenu_%02d : %ls", entry->bootorder, entry->title); + else if (entry->type == BOOTMENU_TYPE_UEFI_BOOT_OPTION) + printf("UEFI BOOT%04X : %ls", entry->bootorder, entry->title); + else if (entry->type == BOOTMENU_TYPE_DISTRO_BOOT) + printf("distro_boot : %ls", entry->title); + else + printf("%ls", entry->title); if (reverse) puts(ANSI_COLOR_RESET); @@ -87,6 +113,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); } @@ -275,31 +305,20 @@ static void bootmenu_destroy(struct bootmenu_data *menu) free(menu); } -static struct bootmenu_data *bootmenu_create(int delay) +static int prepare_bootmenu_entry(struct bootmenu_data *menu, + struct bootmenu_entry **current, + unsigned short int *index) { - unsigned short int i = 0; - const char *option; - struct bootmenu_data *menu; - struct bootmenu_entry *iter = NULL; - int len; char *sep; - char *default_str; - struct bootmenu_entry *entry; - - menu = malloc(sizeof(struct bootmenu_data)); - if (!menu) - return NULL; - - menu->delay = delay; - menu->active = 0; - menu->first = NULL; - - default_str = env_get("bootmenu_default"); - if (default_str) - menu->active = (int)simple_strtol(default_str, NULL, 10); + const char *option; + unsigned short int i = *index; + struct bootmenu_entry *entry = NULL; + struct bootmenu_entry *iter = *current; while ((option = bootmenu_getoption(i))) { + u16 *buf; + sep = strchr(option, '='); if (!sep) { printf("Invalid bootmenu entry: %s\n", option); @@ -308,23 +327,23 @@ static struct bootmenu_data *bootmenu_create(int delay) entry = malloc(sizeof(struct bootmenu_entry)); if (!entry) - goto cleanup; + return -ENOMEM; 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; + return -ENOMEM; } - memcpy(entry->title, option, len); - entry->title[len] = 0; + utf8_utf16_strncpy(&buf, option, len); len = strlen(sep + 1); entry->command = malloc(len + 1); if (!entry->command) { free(entry->title); free(entry); - goto cleanup; + return -ENOMEM; } memcpy(entry->command, sep + 1, len); entry->command[len] = 0; @@ -333,6 +352,158 @@ static struct bootmenu_data *bootmenu_create(int delay) entry->num = i; entry->menu = menu; + entry->type = BOOTMENU_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; + } + + *index = i; + *current = iter; + + return 1; +} + +static int prepare_uefi_bootorder_entry(struct bootmenu_data *menu, + struct bootmenu_entry **current, + unsigned short int *index) +{ + 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####"; + unsigned short int i = *index; + struct bootmenu_entry *entry = NULL; + struct bootmenu_entry *iter = *current; + + bootorder = efi_get_var(u"BootOrder", &efi_global_variable_guid, &size); + if (!bootorder) + return -ENOENT; + + num = size / sizeof(u16); + for (j = 0; j < num; j++) { + entry = malloc(sizeof(struct bootmenu_entry)); + if (!entry) + return -ENOMEM; + + 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); + free(entry); + continue; + } + + if (lo.attributes & LOAD_OPTION_ACTIVE) { + entry->title = u16_strdup(lo.label); + if (!entry->title) { + free(load_option); + free(entry); + return -ENOMEM; + } + entry->command = strdup("bootefi bootmgr"); + sprintf(entry->key, "%d", i); + entry->num = i; + entry->menu = menu; + entry->type = BOOTMENU_TYPE_UEFI_BOOT_OPTION; + entry->bootorder = bootorder[j]; + entry->next = NULL; + + if (!iter) + menu->first = entry; + else + iter->next = entry; + + iter = entry; + i++; + } + + free(load_option); + + if (i == MAX_COUNT - 1) + break; + } + + free(bootorder); + *index = i; + *current = iter; + + return 1; +} + +static int prepare_distro_boot_entry(struct bootmenu_data *menu, + struct bootmenu_entry **current, + unsigned short int *index) +{ + char *p; + int len; + char *token; + char *boot_targets; + unsigned short int i = *index; + struct bootmenu_entry *entry = NULL; + struct bootmenu_entry *iter = *current; + + /* list the distro boot "boot_targets" */ + boot_targets = env_get("boot_targets"); + if (!boot_targets) + return -ENOENT; + + len = strlen(boot_targets); + p = calloc(1, len + 1); + strlcpy(p, boot_targets, len); + + token = strtok(p, " "); + + do { + u16 *buf; + char *command; + int command_size; + + entry = malloc(sizeof(struct bootmenu_entry)); + if (!entry) + return -ENOMEM; + + len = strlen(token); + buf = calloc(1, (len + 1) * sizeof(u16)); + entry->title = buf; + if (!entry->title) { + free(entry); + return -ENOMEM; + } + utf8_utf16_strncpy(&buf, token, len); + sprintf(entry->key, "%d", i); + entry->num = i; + entry->menu = menu; + + command_size = sizeof("run bootcmd_") + len; + command = calloc(1, command_size); + if (!command) { + free(entry->title); + free(entry); + return -ENOMEM; + } + snprintf(command, command_size, "run bootcmd_%s", token); + entry->command = command; + entry->type = BOOTMENU_TYPE_DISTRO_BOOT; entry->next = NULL; if (!iter) @@ -341,10 +512,59 @@ static struct bootmenu_data *bootmenu_create(int delay) iter->next = entry; iter = entry; - ++i; + i++; if (i == MAX_COUNT - 1) break; + + token = strtok(NULL, " "); + } while (token); + + free(p); + *index = i; + *current = iter; + + return 1; +} + +static struct bootmenu_data *bootmenu_create(int delay) +{ + int ret; + unsigned short int i = 0; + struct bootmenu_data *menu; + struct bootmenu_entry *iter = NULL; + struct bootmenu_entry *entry; + + char *default_str; + + menu = malloc(sizeof(struct bootmenu_data)); + if (!menu) + return NULL; + + menu->delay = delay; + menu->active = 0; + menu->first = NULL; + + default_str = env_get("bootmenu_default"); + if (default_str) + menu->active = (int)simple_strtol(default_str, NULL, 10); + + ret = prepare_bootmenu_entry(menu, &iter, &i); + if (ret < 0) + goto cleanup; + + if (IS_ENABLED(CONFIG_CMD_BOOTEFI_BOOTMGR)) { + if (i < MAX_COUNT - 1) { + ret = prepare_uefi_bootorder_entry(menu, &iter, &i); + if (ret < 0 && ret != -ENOENT) + goto cleanup; + } + } + + if (i < MAX_COUNT - 1) { + ret = prepare_distro_boot_entry(menu, &iter, &i); + if (ret < 0 && ret != -ENOENT) + goto cleanup; } /* Add U-Boot console entry at the end */ @@ -353,7 +573,12 @@ static struct bootmenu_data *bootmenu_create(int delay) if (!entry) goto cleanup; - entry->title = strdup("U-Boot console"); + /* Add dummy entry if entering U-Boot console is disabled */ + if (IS_ENABLED(CONFIG_CMD_BOOTMENU_ENTER_UBOOT_CONSOLE)) + entry->title = u16_strdup(u"U-Boot console"); + else + entry->title = u16_strdup(u""); + if (!entry->title) { free(entry); goto cleanup; @@ -370,6 +595,7 @@ static struct bootmenu_data *bootmenu_create(int delay) entry->num = i; entry->menu = menu; + entry->type = BOOTMENU_TYPE_NONE; entry->next = NULL; if (!iter) @@ -378,7 +604,7 @@ static struct bootmenu_data *bootmenu_create(int delay) iter->next = entry; iter = entry; - ++i; + i++; } menu->count = i; @@ -423,43 +649,73 @@ static void menu_display_statusline(struct menu *m) puts(ANSI_CLEAR_LINE); } -static void bootmenu_show(int delay) +static void handle_uefi_bootnext(void) { + u16 bootnext; + efi_status_t ret; + efi_uintn_t size; + + /* 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); + + return; + } + + /* If UEFI BootNext variable is set, boot the BootNext load option */ + size = sizeof(u16); + ret = efi_get_variable_int(u"BootNext", + &efi_global_variable_guid, + NULL, &size, &bootnext, NULL); + if (ret == EFI_SUCCESS) + /* BootNext does exist here, try to boot */ + run_command("bootefi bootmgr", 0); +} + +static enum bootmenu_ret bootmenu_show(int delay) +{ + int cmd_ret; int init = 0; void *choice = NULL; - char *title = NULL; + u16 *title = NULL; char *command = NULL; struct menu *menu; struct bootmenu_data *bootmenu; struct bootmenu_entry *iter; + efi_status_t efi_ret = EFI_SUCCESS; char *option, *sep; + if (IS_ENABLED(CONFIG_CMD_BOOTEFI_BOOTMGR)) + handle_uefi_bootnext(); + /* If delay is 0 do not create menu, just run first entry */ if (delay == 0) { option = bootmenu_getoption(0); if (!option) { puts("bootmenu option 0 was not found\n"); - return; + return BOOTMENU_RET_FAIL; } sep = strchr(option, '='); if (!sep) { puts("bootmenu option 0 is invalid\n"); - return; + return BOOTMENU_RET_FAIL; } - run_command(sep+1, 0); - return; + cmd_ret = run_command(sep + 1, 0); + return (cmd_ret == CMD_RET_SUCCESS ? BOOTMENU_RET_SUCCESS : BOOTMENU_RET_FAIL); } bootmenu = bootmenu_create(delay); if (!bootmenu) - return; + return BOOTMENU_RET_FAIL; menu = menu_create(NULL, bootmenu->delay, 1, menu_display_statusline, bootmenu_print_entry, bootmenu_choice_entry, bootmenu); if (!menu) { bootmenu_destroy(bootmenu); - return; + return BOOTMENU_RET_FAIL; } for (iter = bootmenu->first; iter; iter = iter->next) { @@ -478,8 +734,33 @@ static void bootmenu_show(int delay) if (menu_get_choice(menu, &choice) == 1) { iter = choice; - title = strdup(iter->title); + /* last entry is U-Boot console or Quit */ + if (iter->num == iter->menu->count - 1) { + menu_destroy(menu); + bootmenu_destroy(bootmenu); + return BOOTMENU_RET_QUIT; + } + + title = u16_strdup(iter->title); command = strdup(iter->command); + } else { + goto cleanup; + } + + /* + * If the selected entry is UEFI BOOT####, set the BootNext variable. + * Then uefi bootmgr is invoked by the preset command in iter->command. + */ + if (IS_ENABLED(CONFIG_CMD_BOOTEFI_BOOTMGR)) { + if (iter->type == BOOTMENU_TYPE_UEFI_BOOT_OPTION) { + efi_ret = efi_set_variable_int(u"BootNext", &efi_global_variable_guid, + EFI_VARIABLE_NON_VOLATILE | + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, + sizeof(u16), &iter->bootorder, false); + if (efi_ret != EFI_SUCCESS) + goto cleanup; + } } cleanup: @@ -493,21 +774,47 @@ cleanup: } if (title && command) { - debug("Starting entry '%s'\n", title); + debug("Starting entry '%ls'\n", title); free(title); - run_command(command, 0); + if (efi_ret == EFI_SUCCESS) + cmd_ret = run_command(command, 0); free(command); } #ifdef CONFIG_POSTBOOTMENU run_command(CONFIG_POSTBOOTMENU, 0); #endif + + if (efi_ret == EFI_SUCCESS && cmd_ret == CMD_RET_SUCCESS) + return BOOTMENU_RET_SUCCESS; + + return BOOTMENU_RET_FAIL; } #ifdef CONFIG_AUTOBOOT_MENU_SHOW int menu_show(int bootdelay) { - bootmenu_show(bootdelay); + int ret; + + while (1) { + ret = bootmenu_show(bootdelay); + bootdelay = -1; + if (ret == BOOTMENU_RET_UPDATED) + continue; + + if (!IS_ENABLED(CONFIG_CMD_BOOTMENU_ENTER_UBOOT_CONSOLE)) { + if (ret == BOOTMENU_RET_QUIT) { + /* default boot process */ + if (IS_ENABLED(CONFIG_CMD_BOOTEFI_BOOTMGR)) + run_command("bootefi bootmgr", 0); + + run_command("run bootcmd", 0); + } + } else { + break; + } + } + return -1; /* -1 - abort boot and run monitor code */ } #endif