mirror of
https://github.com/smaeul/u-boot.git
synced 2025-10-14 04:46:01 +01:00
Pull request for efi-2022-07-rc2-2
* Test Unit test for 'bootmenu' command * UEFI Preparatory patches for implementing a UEFI boot options based menu -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEbcT5xx8ppvoGt20zxIHbvCwFGsQFAmJyoMcACgkQxIHbvCwF GsTbjA/+J+mQg5Rl8AkWwxnBynshNbOsQjsekJjoQTKN9XdvA4Rest2cP7AZ7LP7 yi2jks4qMKex5NyGSt2wV51snwZJ6ikZshYpEl59wzoOa4DNlBktH/emOVPNhHqm n+By+m1Uer7I1NBATfGLjgp7Pwk910OkX9sXdFBtg3OlQwBnoCgNARmxxz7ifWwa BxZP2w7l8BfejeZyS/HBzvUc8tPHljukidZoXANXJ/wbJmiU1JR+MBU4+iJmAwCi rt4loje8ynIiPd0NsfDdasqsNGXNtKf1ikY9xH7UBmv8lmkM1BLE+SSufb+8ihUV 5/hn4Q/nXze4klNM/owkglfsiBzs1tGIh1EBmuD9BBjBKKTHMUqSCU1f30cqc+oh 80heH8J6GicqlQlaN5WyYbimH7WvGz48dr8VrWM5AuFf8FjZlNfIlkt86h4yQBjc v6aTvNOXyLriFUh1p9DaQi1+U2ZdB2UO7wpEuWdVbgTE/yH9ZqmBNCB8kGTH1TPk pOwMDZPIFTvHp3WirztpxZRcPus/Eo7s1noMGzM/gdQjmIMRlkEbP8T617hoXWdZ /T4xwRyArQFCkx5xhd5nNqpLd3Lgq4ezpw5ZFAmULJZaGYpp6Iaf+IWiTYghrZ2/ z5cfeQZVL7Sb7vb/yajtVdaZzKg8Eq1FeZdDnoBayvL9UdFTBWA= =bl7A -----END PGP SIGNATURE----- Merge tag 'efi-2022-07-rc2-2' of https://source.denx.de/u-boot/custodians/u-boot-efi Pull request for efi-2022-07-rc2-2 * Test Unit test for 'bootmenu' command * UEFI Preparatory patches for implementing a UEFI boot options based menu
This commit is contained in:
commit
1739a6db54
11
cmd/Kconfig
11
cmd/Kconfig
@ -353,9 +353,20 @@ source lib/efi_selftest/Kconfig
|
|||||||
config CMD_BOOTMENU
|
config CMD_BOOTMENU
|
||||||
bool "bootmenu"
|
bool "bootmenu"
|
||||||
select MENU
|
select MENU
|
||||||
|
select CHARSET
|
||||||
help
|
help
|
||||||
Add an ANSI terminal boot menu command.
|
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
|
config CMD_ADTIMG
|
||||||
bool "adtimg"
|
bool "adtimg"
|
||||||
help
|
help
|
||||||
|
341
cmd/bootmenu.c
341
cmd/bootmenu.c
@ -3,9 +3,12 @@
|
|||||||
* (C) Copyright 2011-2013 Pali Rohár <pali@kernel.org>
|
* (C) Copyright 2011-2013 Pali Rohár <pali@kernel.org>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <charset.h>
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
#include <command.h>
|
#include <command.h>
|
||||||
#include <ansi.h>
|
#include <ansi.h>
|
||||||
|
#include <efi_loader.h>
|
||||||
|
#include <efi_variable.h>
|
||||||
#include <env.h>
|
#include <env.h>
|
||||||
#include <log.h>
|
#include <log.h>
|
||||||
#include <menu.h>
|
#include <menu.h>
|
||||||
@ -24,11 +27,26 @@
|
|||||||
*/
|
*/
|
||||||
#define MAX_ENV_SIZE (9 + 2 + 1)
|
#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,
|
||||||
|
};
|
||||||
|
|
||||||
struct bootmenu_entry {
|
struct bootmenu_entry {
|
||||||
unsigned short int num; /* unique number 0 .. MAX_COUNT */
|
unsigned short int num; /* unique number 0 .. MAX_COUNT */
|
||||||
char key[3]; /* key identifier of number */
|
char key[3]; /* key identifier of number */
|
||||||
char *title; /* title of entry */
|
u16 *title; /* title of entry */
|
||||||
char *command; /* hush command 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_data *menu; /* this bootmenu */
|
||||||
struct bootmenu_entry *next; /* next menu entry (num+1) */
|
struct bootmenu_entry *next; /* next menu entry (num+1) */
|
||||||
};
|
};
|
||||||
@ -68,14 +86,12 @@ static void bootmenu_print_entry(void *data)
|
|||||||
* Move cursor to line where the entry will be drown (entry->num)
|
* Move cursor to line where the entry will be drown (entry->num)
|
||||||
* First 3 lines contain bootmenu header + 1 empty line
|
* First 3 lines contain bootmenu header + 1 empty line
|
||||||
*/
|
*/
|
||||||
printf(ANSI_CURSOR_POSITION, entry->num + 4, 1);
|
printf(ANSI_CURSOR_POSITION, entry->num + 4, 7);
|
||||||
|
|
||||||
puts(" ");
|
|
||||||
|
|
||||||
if (reverse)
|
if (reverse)
|
||||||
puts(ANSI_COLOR_REVERSE);
|
puts(ANSI_COLOR_REVERSE);
|
||||||
|
|
||||||
puts(entry->title);
|
printf("%ls", entry->title);
|
||||||
|
|
||||||
if (reverse)
|
if (reverse)
|
||||||
puts(ANSI_COLOR_RESET);
|
puts(ANSI_COLOR_RESET);
|
||||||
@ -86,12 +102,9 @@ static void bootmenu_autoboot_loop(struct bootmenu_data *menu,
|
|||||||
{
|
{
|
||||||
int i, c;
|
int i, c;
|
||||||
|
|
||||||
if (menu->delay > 0) {
|
|
||||||
printf(ANSI_CURSOR_POSITION, menu->count + 5, 1);
|
|
||||||
printf(" Hit any key to stop autoboot: %2d ", menu->delay);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (menu->delay > 0) {
|
while (menu->delay > 0) {
|
||||||
|
printf(ANSI_CURSOR_POSITION, menu->count + 5, 3);
|
||||||
|
printf("Hit any key to stop autoboot: %d ", menu->delay);
|
||||||
for (i = 0; i < 100; ++i) {
|
for (i = 0; i < 100; ++i) {
|
||||||
if (!tstc()) {
|
if (!tstc()) {
|
||||||
WATCHDOG_RESET();
|
WATCHDOG_RESET();
|
||||||
@ -125,7 +138,6 @@ static void bootmenu_autoboot_loop(struct bootmenu_data *menu,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
--menu->delay;
|
--menu->delay;
|
||||||
printf("\b\b\b%2d ", menu->delay);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(ANSI_CURSOR_POSITION, menu->count + 5, 1);
|
printf(ANSI_CURSOR_POSITION, menu->count + 5, 1);
|
||||||
@ -275,31 +287,32 @@ static void bootmenu_destroy(struct bootmenu_data *menu)
|
|||||||
free(menu);
|
free(menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct bootmenu_data *bootmenu_create(int delay)
|
/**
|
||||||
|
* prepare_bootmenu_entry() - generate the bootmenu_xx entries
|
||||||
|
*
|
||||||
|
* This function read the "bootmenu_x" U-Boot environment variable
|
||||||
|
* and generate the bootmenu entries.
|
||||||
|
*
|
||||||
|
* @menu: pointer to the bootmenu structure
|
||||||
|
* @current: pointer to the last bootmenu entry list
|
||||||
|
* @index: pointer to the index of the last bootmenu entry,
|
||||||
|
* the number of bootmenu entry is added by this function
|
||||||
|
* Return: 1 on success, negative value on error
|
||||||
|
*/
|
||||||
|
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;
|
int len;
|
||||||
char *sep;
|
char *sep;
|
||||||
char *default_str;
|
const char *option;
|
||||||
struct bootmenu_entry *entry;
|
unsigned short int i = *index;
|
||||||
|
struct bootmenu_entry *entry = NULL;
|
||||||
menu = malloc(sizeof(struct bootmenu_data));
|
struct bootmenu_entry *iter = *current;
|
||||||
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);
|
|
||||||
|
|
||||||
while ((option = bootmenu_getoption(i))) {
|
while ((option = bootmenu_getoption(i))) {
|
||||||
|
u16 *buf;
|
||||||
|
|
||||||
sep = strchr(option, '=');
|
sep = strchr(option, '=');
|
||||||
if (!sep) {
|
if (!sep) {
|
||||||
printf("Invalid bootmenu entry: %s\n", option);
|
printf("Invalid bootmenu entry: %s\n", option);
|
||||||
@ -308,23 +321,23 @@ static struct bootmenu_data *bootmenu_create(int delay)
|
|||||||
|
|
||||||
entry = malloc(sizeof(struct bootmenu_entry));
|
entry = malloc(sizeof(struct bootmenu_entry));
|
||||||
if (!entry)
|
if (!entry)
|
||||||
goto cleanup;
|
return -ENOMEM;
|
||||||
|
|
||||||
len = sep-option;
|
len = sep-option;
|
||||||
entry->title = malloc(len + 1);
|
buf = calloc(1, (len + 1) * sizeof(u16));
|
||||||
|
entry->title = buf;
|
||||||
if (!entry->title) {
|
if (!entry->title) {
|
||||||
free(entry);
|
free(entry);
|
||||||
goto cleanup;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
memcpy(entry->title, option, len);
|
utf8_utf16_strncpy(&buf, option, len);
|
||||||
entry->title[len] = 0;
|
|
||||||
|
|
||||||
len = strlen(sep + 1);
|
len = strlen(sep + 1);
|
||||||
entry->command = malloc(len + 1);
|
entry->command = malloc(len + 1);
|
||||||
if (!entry->command) {
|
if (!entry->command) {
|
||||||
free(entry->title);
|
free(entry->title);
|
||||||
free(entry);
|
free(entry);
|
||||||
goto cleanup;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
memcpy(entry->command, sep + 1, len);
|
memcpy(entry->command, sep + 1, len);
|
||||||
entry->command[len] = 0;
|
entry->command[len] = 0;
|
||||||
@ -333,6 +346,8 @@ static struct bootmenu_data *bootmenu_create(int delay)
|
|||||||
|
|
||||||
entry->num = i;
|
entry->num = i;
|
||||||
entry->menu = menu;
|
entry->menu = menu;
|
||||||
|
entry->type = BOOTMENU_TYPE_BOOTMENU;
|
||||||
|
entry->bootorder = i;
|
||||||
entry->next = NULL;
|
entry->next = NULL;
|
||||||
|
|
||||||
if (!iter)
|
if (!iter)
|
||||||
@ -347,13 +362,146 @@ static struct bootmenu_data *bootmenu_create(int delay)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*index = i;
|
||||||
|
*current = iter;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* prepare_uefi_bootorder_entry() - generate the uefi bootmenu entries
|
||||||
|
*
|
||||||
|
* This function read the "BootOrder" UEFI variable
|
||||||
|
* and generate the bootmenu entries in the order of "BootOrder".
|
||||||
|
*
|
||||||
|
* @menu: pointer to the bootmenu structure
|
||||||
|
* @current: pointer to the last bootmenu entry list
|
||||||
|
* @index: pointer to the index of the last bootmenu entry,
|
||||||
|
* the number of uefi entry is added by this function
|
||||||
|
* Return: 1 on success, negative value on error
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
free(bootorder);
|
||||||
|
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 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Add U-Boot console entry at the end */
|
/* Add U-Boot console entry at the end */
|
||||||
if (i <= MAX_COUNT - 1) {
|
if (i <= MAX_COUNT - 1) {
|
||||||
entry = malloc(sizeof(struct bootmenu_entry));
|
entry = malloc(sizeof(struct bootmenu_entry));
|
||||||
if (!entry)
|
if (!entry)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
entry->title = strdup("U-Boot console");
|
/* Add Quit 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"Quit");
|
||||||
|
|
||||||
if (!entry->title) {
|
if (!entry->title) {
|
||||||
free(entry);
|
free(entry);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@ -370,6 +518,7 @@ static struct bootmenu_data *bootmenu_create(int delay)
|
|||||||
|
|
||||||
entry->num = i;
|
entry->num = i;
|
||||||
entry->menu = menu;
|
entry->menu = menu;
|
||||||
|
entry->type = BOOTMENU_TYPE_NONE;
|
||||||
entry->next = NULL;
|
entry->next = NULL;
|
||||||
|
|
||||||
if (!iter)
|
if (!iter)
|
||||||
@ -407,7 +556,7 @@ static void menu_display_statusline(struct menu *m)
|
|||||||
|
|
||||||
printf(ANSI_CURSOR_POSITION, 1, 1);
|
printf(ANSI_CURSOR_POSITION, 1, 1);
|
||||||
puts(ANSI_CLEAR_LINE);
|
puts(ANSI_CLEAR_LINE);
|
||||||
printf(ANSI_CURSOR_POSITION, 2, 1);
|
printf(ANSI_CURSOR_POSITION, 2, 3);
|
||||||
puts("*** U-Boot Boot Menu ***");
|
puts("*** U-Boot Boot Menu ***");
|
||||||
puts(ANSI_CLEAR_LINE_TO_END);
|
puts(ANSI_CLEAR_LINE_TO_END);
|
||||||
printf(ANSI_CURSOR_POSITION, 3, 1);
|
printf(ANSI_CURSOR_POSITION, 3, 1);
|
||||||
@ -416,50 +565,81 @@ static void menu_display_statusline(struct menu *m)
|
|||||||
/* First 3 lines are bootmenu header + 2 empty lines between entries */
|
/* First 3 lines are bootmenu header + 2 empty lines between entries */
|
||||||
printf(ANSI_CURSOR_POSITION, menu->count + 5, 1);
|
printf(ANSI_CURSOR_POSITION, menu->count + 5, 1);
|
||||||
puts(ANSI_CLEAR_LINE);
|
puts(ANSI_CLEAR_LINE);
|
||||||
printf(ANSI_CURSOR_POSITION, menu->count + 6, 1);
|
printf(ANSI_CURSOR_POSITION, menu->count + 6, 3);
|
||||||
puts("Press UP/DOWN to move, ENTER to select, ESC/CTRL+C to quit");
|
puts("Press UP/DOWN to move, ENTER to select, ESC/CTRL+C to quit");
|
||||||
puts(ANSI_CLEAR_LINE_TO_END);
|
puts(ANSI_CLEAR_LINE_TO_END);
|
||||||
printf(ANSI_CURSOR_POSITION, menu->count + 7, 1);
|
printf(ANSI_CURSOR_POSITION, menu->count + 7, 1);
|
||||||
puts(ANSI_CLEAR_LINE);
|
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;
|
int init = 0;
|
||||||
void *choice = NULL;
|
void *choice = NULL;
|
||||||
char *title = NULL;
|
u16 *title = NULL;
|
||||||
char *command = NULL;
|
char *command = NULL;
|
||||||
struct menu *menu;
|
struct menu *menu;
|
||||||
struct bootmenu_data *bootmenu;
|
|
||||||
struct bootmenu_entry *iter;
|
struct bootmenu_entry *iter;
|
||||||
|
int ret = BOOTMENU_RET_SUCCESS;
|
||||||
|
struct bootmenu_data *bootmenu;
|
||||||
|
efi_status_t efi_ret = EFI_SUCCESS;
|
||||||
char *option, *sep;
|
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 is 0 do not create menu, just run first entry */
|
||||||
if (delay == 0) {
|
if (delay == 0) {
|
||||||
option = bootmenu_getoption(0);
|
option = bootmenu_getoption(0);
|
||||||
if (!option) {
|
if (!option) {
|
||||||
puts("bootmenu option 0 was not found\n");
|
puts("bootmenu option 0 was not found\n");
|
||||||
return;
|
return BOOTMENU_RET_FAIL;
|
||||||
}
|
}
|
||||||
sep = strchr(option, '=');
|
sep = strchr(option, '=');
|
||||||
if (!sep) {
|
if (!sep) {
|
||||||
puts("bootmenu option 0 is invalid\n");
|
puts("bootmenu option 0 is invalid\n");
|
||||||
return;
|
return BOOTMENU_RET_FAIL;
|
||||||
}
|
}
|
||||||
run_command(sep+1, 0);
|
cmd_ret = run_command(sep + 1, 0);
|
||||||
return;
|
return (cmd_ret == CMD_RET_SUCCESS ? BOOTMENU_RET_SUCCESS : BOOTMENU_RET_FAIL);
|
||||||
}
|
}
|
||||||
|
|
||||||
bootmenu = bootmenu_create(delay);
|
bootmenu = bootmenu_create(delay);
|
||||||
if (!bootmenu)
|
if (!bootmenu)
|
||||||
return;
|
return BOOTMENU_RET_FAIL;
|
||||||
|
|
||||||
menu = menu_create(NULL, bootmenu->delay, 1, menu_display_statusline,
|
menu = menu_create(NULL, bootmenu->delay, 1, menu_display_statusline,
|
||||||
bootmenu_print_entry, bootmenu_choice_entry,
|
bootmenu_print_entry, bootmenu_choice_entry,
|
||||||
bootmenu);
|
bootmenu);
|
||||||
if (!menu) {
|
if (!menu) {
|
||||||
bootmenu_destroy(bootmenu);
|
bootmenu_destroy(bootmenu);
|
||||||
return;
|
return BOOTMENU_RET_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (iter = bootmenu->first; iter; iter = iter->next) {
|
for (iter = bootmenu->first; iter; iter = iter->next) {
|
||||||
@ -478,8 +658,37 @@ static void bootmenu_show(int delay)
|
|||||||
|
|
||||||
if (menu_get_choice(menu, &choice) == 1) {
|
if (menu_get_choice(menu, &choice) == 1) {
|
||||||
iter = choice;
|
iter = choice;
|
||||||
title = strdup(iter->title);
|
title = u16_strdup(iter->title);
|
||||||
command = strdup(iter->command);
|
command = strdup(iter->command);
|
||||||
|
|
||||||
|
/* last entry is U-Boot console or Quit */
|
||||||
|
if (iter->num == iter->menu->count - 1) {
|
||||||
|
ret = BOOTMENU_RET_QUIT;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
} 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) {
|
||||||
|
/*
|
||||||
|
* UEFI specification requires BootNext variable needs non-volatile
|
||||||
|
* attribute, but this BootNext is only used inside of U-Boot and
|
||||||
|
* removed by efi bootmgr once BootNext is processed.
|
||||||
|
* So this BootNext can be volatile.
|
||||||
|
*/
|
||||||
|
efi_ret = efi_set_variable_int(u"BootNext", &efi_global_variable_guid,
|
||||||
|
EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
||||||
|
EFI_VARIABLE_RUNTIME_ACCESS,
|
||||||
|
sizeof(u16), &iter->bootorder, false);
|
||||||
|
if (efi_ret != EFI_SUCCESS)
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
@ -493,21 +702,47 @@ cleanup:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (title && command) {
|
if (title && command) {
|
||||||
debug("Starting entry '%s'\n", title);
|
debug("Starting entry '%ls'\n", title);
|
||||||
free(title);
|
free(title);
|
||||||
run_command(command, 0);
|
if (efi_ret == EFI_SUCCESS)
|
||||||
|
cmd_ret = run_command(command, 0);
|
||||||
free(command);
|
free(command);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_POSTBOOTMENU
|
#ifdef CONFIG_POSTBOOTMENU
|
||||||
run_command(CONFIG_POSTBOOTMENU, 0);
|
run_command(CONFIG_POSTBOOTMENU, 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (efi_ret != EFI_SUCCESS || cmd_ret != CMD_RET_SUCCESS)
|
||||||
|
ret = BOOTMENU_RET_FAIL;
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_AUTOBOOT_MENU_SHOW
|
#ifdef CONFIG_AUTOBOOT_MENU_SHOW
|
||||||
int menu_show(int bootdelay)
|
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 */
|
return -1; /* -1 - abort boot and run monitor code */
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -271,7 +271,10 @@ int menu_get_choice(struct menu *m, void **choice)
|
|||||||
if (!m || !choice)
|
if (!m || !choice)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (!m->prompt || m->item_cnt == 1)
|
if (!m->item_cnt)
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
|
if (!m->prompt)
|
||||||
return menu_default_choice(m, choice);
|
return menu_default_choice(m, choice);
|
||||||
|
|
||||||
return menu_interactive_choice(m, choice);
|
return menu_interactive_choice(m, choice);
|
||||||
|
@ -39,6 +39,7 @@ CONFIG_CMD_LICENSE=y
|
|||||||
CONFIG_CMD_BOOTM_PRE_LOAD=y
|
CONFIG_CMD_BOOTM_PRE_LOAD=y
|
||||||
CONFIG_CMD_BOOTZ=y
|
CONFIG_CMD_BOOTZ=y
|
||||||
CONFIG_CMD_BOOTEFI_HELLO=y
|
CONFIG_CMD_BOOTEFI_HELLO=y
|
||||||
|
CONFIG_CMD_BOOTMENU=y
|
||||||
CONFIG_CMD_ABOOTIMG=y
|
CONFIG_CMD_ABOOTIMG=y
|
||||||
# CONFIG_CMD_ELF is not set
|
# CONFIG_CMD_ELF is not set
|
||||||
CONFIG_CMD_ASKENV=y
|
CONFIG_CMD_ASKENV=y
|
||||||
|
@ -12,7 +12,7 @@ selected using the "Enter" key. The selection of the highlighted
|
|||||||
menu entry invokes an U-Boot command (or a list of commands)
|
menu entry invokes an U-Boot command (or a list of commands)
|
||||||
associated with this menu entry.
|
associated with this menu entry.
|
||||||
|
|
||||||
The "bootmenu" command interprets ANSI escape sequencies, so
|
The "bootmenu" command interprets ANSI escape sequences, so
|
||||||
an ANSI terminal is required for proper menu rendering and item
|
an ANSI terminal is required for proper menu rendering and item
|
||||||
selection.
|
selection.
|
||||||
|
|
||||||
@ -79,7 +79,7 @@ The above example will be rendered as below::
|
|||||||
The selected menu entry will be highlighted - it will have inverted
|
The selected menu entry will be highlighted - it will have inverted
|
||||||
background and text colors.
|
background and text colors.
|
||||||
|
|
||||||
The "bootmenu" cammand is enabled by::
|
The "bootmenu" command is enabled by::
|
||||||
|
|
||||||
CONFIG_CMD_BOOTMENU=y
|
CONFIG_CMD_BOOTMENU=y
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ menu "UFS Host Controller Support"
|
|||||||
config UFS
|
config UFS
|
||||||
bool "Support UFS controllers"
|
bool "Support UFS controllers"
|
||||||
depends on DM_SCSI
|
depends on DM_SCSI
|
||||||
|
select CHARSET
|
||||||
help
|
help
|
||||||
This selects support for Universal Flash Subsystem (UFS).
|
This selects support for Universal Flash Subsystem (UFS).
|
||||||
Say Y here if you want UFS Support.
|
Say Y here if you want UFS Support.
|
||||||
|
@ -261,6 +261,20 @@ u16 *u16_strcpy(u16 *dest, const u16 *src);
|
|||||||
*/
|
*/
|
||||||
u16 *u16_strdup(const void *src);
|
u16 *u16_strdup(const void *src);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* u16_strlcat() - Append a length-limited, %NUL-terminated string to another
|
||||||
|
*
|
||||||
|
* Append the source string @src to the destination string @dest, overwriting
|
||||||
|
* null word at the end of @dest adding a terminating null word.
|
||||||
|
*
|
||||||
|
* @dest: zero terminated u16 destination string
|
||||||
|
* @src: zero terminated u16 source string
|
||||||
|
* @count: size of buffer in u16 words including taling 0x0000
|
||||||
|
* 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);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* utf16_to_utf8() - Convert an utf16 string to utf8
|
* utf16_to_utf8() - Convert an utf16 string to utf8
|
||||||
*
|
*
|
||||||
|
45
include/efi_default_filename.h
Normal file
45
include/efi_default_filename.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||||
|
/*
|
||||||
|
* When a boot option does not provide a file path the EFI file to be
|
||||||
|
* booted is \EFI\BOOT\$(BOOTEFI_NAME).EFI. The architecture specific
|
||||||
|
* file name is defined in this include.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022, Heinrich Schuchardt <xypron.glpk@gmx.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _EFI_DEFAULT_FILENAME_H
|
||||||
|
#define _EFI_DEFAULT_FILENAME_H
|
||||||
|
|
||||||
|
#include <host_arch.h>
|
||||||
|
|
||||||
|
#undef BOOTEFI_NAME
|
||||||
|
|
||||||
|
#if HOST_ARCH == HOST_ARCH_X86_64
|
||||||
|
#define BOOTEFI_NAME "BOOTX64.EFI"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if HOST_ARCH == HOST_ARCH_X86
|
||||||
|
#define BOOTEFI_NAME "BOOTIA32.EFI"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if HOST_ARCH == HOST_ARCH_AARCH64
|
||||||
|
#define BOOTEFI_NAME "BOOTAA64.EFI"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if HOST_ARCH == HOST_ARCH_ARM
|
||||||
|
#define BOOTEFI_NAME "BOOTARM.EFI"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if HOST_ARCH == HOST_ARCH_RISCV32
|
||||||
|
#define BOOTEFI_NAME "BOOTRISCV32.EFI"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if HOST_ARCH == HOST_ARCH_RISCV64
|
||||||
|
#define BOOTEFI_NAME "BOOTRISCV64.EFI"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef BOOTEFI_NAME
|
||||||
|
#error Unsupported UEFI architecture
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
@ -595,6 +595,10 @@ efi_status_t efi_create_handle(efi_handle_t *handle);
|
|||||||
void efi_delete_handle(efi_handle_t obj);
|
void efi_delete_handle(efi_handle_t obj);
|
||||||
/* Call this to validate a handle and find the EFI object for it */
|
/* Call this to validate a handle and find the EFI object for it */
|
||||||
struct efi_object *efi_search_obj(const efi_handle_t handle);
|
struct efi_object *efi_search_obj(const efi_handle_t handle);
|
||||||
|
/* Locate device_path handle */
|
||||||
|
efi_status_t EFIAPI efi_locate_device_path(const efi_guid_t *protocol,
|
||||||
|
struct efi_device_path **device_path,
|
||||||
|
efi_handle_t *device);
|
||||||
/* Load image */
|
/* Load image */
|
||||||
efi_status_t EFIAPI efi_load_image(bool boot_policy,
|
efi_status_t EFIAPI efi_load_image(bool boot_policy,
|
||||||
efi_handle_t parent_image,
|
efi_handle_t parent_image,
|
||||||
|
@ -52,11 +52,6 @@ config CC_OPTIMIZE_LIBS_FOR_SPEED
|
|||||||
|
|
||||||
config CHARSET
|
config CHARSET
|
||||||
bool
|
bool
|
||||||
default y if UT_UNICODE || EFI_LOADER || UFS || EFI_APP
|
|
||||||
help
|
|
||||||
Enables support for various conversions between different
|
|
||||||
character sets, such as between unicode representations and
|
|
||||||
different 'code pages'.
|
|
||||||
|
|
||||||
config DYNAMIC_CRC_TABLE
|
config DYNAMIC_CRC_TABLE
|
||||||
bool "Enable Dynamic tables for CRC"
|
bool "Enable Dynamic tables for CRC"
|
||||||
|
@ -416,6 +416,22 @@ u16 *u16_strdup(const void *src)
|
|||||||
return new;
|
return new;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t u16_strlcat(u16 *dest, const u16 *src, size_t count)
|
||||||
|
{
|
||||||
|
size_t destlen = u16_strlen(dest);
|
||||||
|
size_t srclen = u16_strlen(src);
|
||||||
|
size_t ret = destlen + srclen + 1;
|
||||||
|
|
||||||
|
if (destlen >= count)
|
||||||
|
return ret;
|
||||||
|
if (ret > count)
|
||||||
|
srclen -= ret - count;
|
||||||
|
memcpy(&dest[destlen], src, 2 * srclen);
|
||||||
|
dest[destlen + srclen] = 0x0000;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* Convert UTF-16 to UTF-8. */
|
/* Convert UTF-16 to UTF-8. */
|
||||||
uint8_t *utf16_to_utf8(uint8_t *dest, const uint16_t *src, size_t size)
|
uint8_t *utf16_to_utf8(uint8_t *dest, const uint16_t *src, size_t size)
|
||||||
{
|
{
|
||||||
|
@ -14,6 +14,7 @@ choice
|
|||||||
|
|
||||||
config EFI_APP
|
config EFI_APP
|
||||||
bool "Support running as an EFI application"
|
bool "Support running as an EFI application"
|
||||||
|
select CHARSET
|
||||||
help
|
help
|
||||||
Build U-Boot as an application which can be started from EFI. This
|
Build U-Boot as an application which can be started from EFI. This
|
||||||
is useful for examining a platform in the early stages of porting
|
is useful for examining a platform in the early stages of porting
|
||||||
|
@ -14,6 +14,7 @@ config EFI_LOADER
|
|||||||
depends on DM_ETH || !NET
|
depends on DM_ETH || !NET
|
||||||
depends on !EFI_APP
|
depends on !EFI_APP
|
||||||
default y if !ARM || SYS_CPU = armv7 || SYS_CPU = armv8
|
default y if !ARM || SYS_CPU = armv7 || SYS_CPU = armv8
|
||||||
|
select CHARSET
|
||||||
select DM_EVENT
|
select DM_EVENT
|
||||||
select EVENT_DYNAMIC
|
select EVENT_DYNAMIC
|
||||||
select LIB_UUID
|
select LIB_UUID
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include <charset.h>
|
#include <charset.h>
|
||||||
#include <log.h>
|
#include <log.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
|
#include <efi_default_filename.h>
|
||||||
#include <efi_loader.h>
|
#include <efi_loader.h>
|
||||||
#include <efi_variable.h>
|
#include <efi_variable.h>
|
||||||
#include <asm/unaligned.h>
|
#include <asm/unaligned.h>
|
||||||
@ -30,6 +31,51 @@ static const struct efi_runtime_services *rs;
|
|||||||
* should do normal or recovery boot.
|
* should do normal or recovery boot.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* expand_media_path() - expand a device path for default file name
|
||||||
|
* @device_path: device path to check against
|
||||||
|
*
|
||||||
|
* If @device_path is a media or disk partition which houses a file
|
||||||
|
* system, this function returns a full device path which contains
|
||||||
|
* an architecture-specific default file name for removable media.
|
||||||
|
*
|
||||||
|
* Return: a newly allocated device path
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
struct efi_device_path *expand_media_path(struct efi_device_path *device_path)
|
||||||
|
{
|
||||||
|
struct efi_device_path *dp, *full_path;
|
||||||
|
efi_handle_t handle;
|
||||||
|
efi_status_t ret;
|
||||||
|
|
||||||
|
if (!device_path)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If device_path is a (removable) media or partition which provides
|
||||||
|
* simple file system protocol, append a default file name to support
|
||||||
|
* booting from removable media.
|
||||||
|
*/
|
||||||
|
dp = device_path;
|
||||||
|
ret = EFI_CALL(efi_locate_device_path(
|
||||||
|
&efi_simple_file_system_protocol_guid,
|
||||||
|
&dp, &handle));
|
||||||
|
if (ret == EFI_SUCCESS) {
|
||||||
|
if (dp->type == DEVICE_PATH_TYPE_END) {
|
||||||
|
dp = efi_dp_from_file(NULL, 0,
|
||||||
|
"/EFI/BOOT/" BOOTEFI_NAME);
|
||||||
|
full_path = efi_dp_append(device_path, dp);
|
||||||
|
efi_free_pool(dp);
|
||||||
|
} else {
|
||||||
|
full_path = efi_dp_dup(device_path);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
full_path = efi_dp_dup(device_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
return full_path;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* try_load_entry() - try to load image for boot option
|
* try_load_entry() - try to load image for boot option
|
||||||
*
|
*
|
||||||
@ -64,13 +110,16 @@ static efi_status_t try_load_entry(u16 n, efi_handle_t *handle,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (lo.attributes & LOAD_OPTION_ACTIVE) {
|
if (lo.attributes & LOAD_OPTION_ACTIVE) {
|
||||||
|
struct efi_device_path *file_path;
|
||||||
u32 attributes;
|
u32 attributes;
|
||||||
|
|
||||||
log_debug("trying to load \"%ls\" from %pD\n", lo.label,
|
log_debug("trying to load \"%ls\" from %pD\n", lo.label,
|
||||||
lo.file_path);
|
lo.file_path);
|
||||||
|
|
||||||
ret = EFI_CALL(efi_load_image(true, efi_root, lo.file_path,
|
file_path = expand_media_path(lo.file_path);
|
||||||
|
ret = EFI_CALL(efi_load_image(true, efi_root, file_path,
|
||||||
NULL, 0, handle));
|
NULL, 0, handle));
|
||||||
|
efi_free_pool(file_path);
|
||||||
if (ret != EFI_SUCCESS) {
|
if (ret != EFI_SUCCESS) {
|
||||||
log_warning("Loading %ls '%ls' failed\n",
|
log_warning("Loading %ls '%ls' failed\n",
|
||||||
varname, lo.label);
|
varname, lo.label);
|
||||||
|
@ -1799,8 +1799,7 @@ failure:
|
|||||||
*
|
*
|
||||||
* Return: status code
|
* Return: status code
|
||||||
*/
|
*/
|
||||||
static efi_status_t EFIAPI efi_locate_device_path(
|
efi_status_t EFIAPI efi_locate_device_path(const efi_guid_t *protocol,
|
||||||
const efi_guid_t *protocol,
|
|
||||||
struct efi_device_path **device_path,
|
struct efi_device_path **device_path,
|
||||||
efi_handle_t *device)
|
efi_handle_t *device)
|
||||||
{
|
{
|
||||||
|
@ -522,11 +522,11 @@ static efi_status_t EFIAPI efi_cout_reset(
|
|||||||
{
|
{
|
||||||
EFI_ENTRY("%p, %d", this, extended_verification);
|
EFI_ENTRY("%p, %d", this, extended_verification);
|
||||||
|
|
||||||
/* Clear screen */
|
|
||||||
EFI_CALL(efi_cout_clear_screen(this));
|
|
||||||
/* Set default colors */
|
/* Set default colors */
|
||||||
efi_con_mode.attribute = 0x07;
|
efi_con_mode.attribute = 0x07;
|
||||||
printf(ESC "[0;37;40m");
|
printf(ESC "[0;37;40m");
|
||||||
|
/* Clear screen */
|
||||||
|
EFI_CALL(efi_cout_clear_screen(this));
|
||||||
|
|
||||||
return EFI_EXIT(EFI_SUCCESS);
|
return EFI_EXIT(EFI_SUCCESS);
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,9 @@ obj-$(CONFIG_EFI_DEVICE_PATH_TO_TEXT) += efi_selftest_devicepath.o
|
|||||||
obj-$(CONFIG_EFI_UNICODE_COLLATION_PROTOCOL2) += \
|
obj-$(CONFIG_EFI_UNICODE_COLLATION_PROTOCOL2) += \
|
||||||
efi_selftest_unicode_collation.o
|
efi_selftest_unicode_collation.o
|
||||||
|
|
||||||
obj-$(CONFIG_CPU_V7) += efi_selftest_unaligned.o
|
ifeq ($(CONFIG_CPU_V7A)$(CONFIG_CPU_V7M)$(CONFIG_CPU_V7R),y)
|
||||||
|
obj-y += efi_selftest_unaligned.o
|
||||||
|
endif
|
||||||
obj-$(CONFIG_EFI_LOADER_HII) += efi_selftest_hii.o
|
obj-$(CONFIG_EFI_LOADER_HII) += efi_selftest_hii.o
|
||||||
obj-$(CONFIG_EFI_RNG_PROTOCOL) += efi_selftest_rng.o
|
obj-$(CONFIG_EFI_RNG_PROTOCOL) += efi_selftest_rng.o
|
||||||
obj-$(CONFIG_EFI_GET_TIME) += efi_selftest_rtc.o
|
obj-$(CONFIG_EFI_GET_TIME) += efi_selftest_rtc.o
|
||||||
|
@ -631,8 +631,10 @@ static int efi_st_tcg2_setup(const efi_handle_t img_handle,
|
|||||||
sizeof(struct efi_tcg2_event) +
|
sizeof(struct efi_tcg2_event) +
|
||||||
sizeof(struct uefi_image_load_event),
|
sizeof(struct uefi_image_load_event),
|
||||||
(void **)&efi_tcg2_event);
|
(void **)&efi_tcg2_event);
|
||||||
if (!efi_tcg2_event)
|
if (ret != EFI_SUCCESS) {
|
||||||
|
efi_st_error("Out of memory\n");
|
||||||
return EFI_ST_FAILURE;
|
return EFI_ST_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
efi_tcg2_event->size = sizeof(struct efi_tcg2_event) +
|
efi_tcg2_event->size = sizeof(struct efi_tcg2_event) +
|
||||||
sizeof(struct uefi_image_load_event);
|
sizeof(struct uefi_image_load_event);
|
||||||
@ -659,8 +661,10 @@ static int efi_st_tcg2_setup(const efi_handle_t img_handle,
|
|||||||
(EFI_TCG2_MAX_PCR_INDEX + 1) *
|
(EFI_TCG2_MAX_PCR_INDEX + 1) *
|
||||||
TPM2_SHA256_DIGEST_SIZE,
|
TPM2_SHA256_DIGEST_SIZE,
|
||||||
(void **)&pcrs);
|
(void **)&pcrs);
|
||||||
if (!pcrs)
|
if (ret != EFI_SUCCESS) {
|
||||||
|
efi_st_error("Out of memory\n");
|
||||||
return EFI_ST_FAILURE;
|
return EFI_ST_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
boottime->set_mem(pcrs, (EFI_TCG2_MAX_PCR_INDEX + 1) * TPM2_SHA256_DIGEST_SIZE, 0);
|
boottime->set_mem(pcrs, (EFI_TCG2_MAX_PCR_INDEX + 1) * TPM2_SHA256_DIGEST_SIZE, 0);
|
||||||
|
|
||||||
|
@ -14,14 +14,14 @@ struct aligned_buffer {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return an u32 at a give address.
|
* Return an u32 at a given address.
|
||||||
* If the address is not four byte aligned, an unaligned memory access
|
* If the address is not four byte aligned, an unaligned memory access
|
||||||
* occurs.
|
* occurs.
|
||||||
*
|
*
|
||||||
* @addr: address to read
|
* @addr: address to read
|
||||||
* Return: value at the address
|
* Return: value at the address
|
||||||
*/
|
*/
|
||||||
static inline u32 deref(u32 *addr)
|
static inline u32 deref(void *addr)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@ -44,11 +44,10 @@ static int execute(void)
|
|||||||
struct aligned_buffer buf = {
|
struct aligned_buffer buf = {
|
||||||
{0, 1, 2, 3, 4, 5, 6, 7},
|
{0, 1, 2, 3, 4, 5, 6, 7},
|
||||||
};
|
};
|
||||||
void *v = &buf;
|
|
||||||
u32 r = 0;
|
u32 r = 0;
|
||||||
|
|
||||||
/* Read an unaligned address */
|
/* Read an unaligned address */
|
||||||
r = deref(v + 1);
|
r = deref(&buf.a[1]);
|
||||||
|
|
||||||
/* UEFI only supports low endian systems */
|
/* UEFI only supports low endian systems */
|
||||||
if (r != 0x04030201) {
|
if (r != 0x04030201) {
|
||||||
|
@ -6,6 +6,7 @@ test_tests_test_android_test_ab.py 6.50
|
|||||||
test_tests_test_android_test_abootimg.py 6.09
|
test_tests_test_android_test_abootimg.py 6.09
|
||||||
test_tests_test_android_test_avb.py 5.52
|
test_tests_test_android_test_avb.py 5.52
|
||||||
test_tests_test_bind.py -2.99
|
test_tests_test_bind.py -2.99
|
||||||
|
test_tests_test_bootmenu.py 10.00
|
||||||
test_tests_test_button.py 3.33
|
test_tests_test_button.py 3.33
|
||||||
test_tests_test_dfu.py 5.45
|
test_tests_test_dfu.py 5.45
|
||||||
test_tests_test_dm.py 9.52
|
test_tests_test_dm.py 9.52
|
||||||
|
@ -91,6 +91,7 @@ config UT_UNICODE
|
|||||||
bool "Unit tests for Unicode functions"
|
bool "Unit tests for Unicode functions"
|
||||||
depends on UNIT_TEST
|
depends on UNIT_TEST
|
||||||
default y
|
default y
|
||||||
|
select CHARSET
|
||||||
help
|
help
|
||||||
Enables the 'ut unicode' command which tests that the functions for
|
Enables the 'ut unicode' command which tests that the functions for
|
||||||
manipulating Unicode strings work correctly.
|
manipulating Unicode strings work correctly.
|
||||||
|
46
test/py/tests/test_bootmenu.py
Normal file
46
test/py/tests/test_bootmenu.py
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0+
|
||||||
|
|
||||||
|
"""Test bootmenu"""
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
@pytest.mark.buildconfigspec('cmd_bootmenu')
|
||||||
|
def test_bootmenu(u_boot_console):
|
||||||
|
"""Test bootmenu
|
||||||
|
|
||||||
|
u_boot_console -- U-Boot console
|
||||||
|
"""
|
||||||
|
|
||||||
|
u_boot_console.p.timeout = 500
|
||||||
|
u_boot_console.run_command('setenv bootmenu_default 1')
|
||||||
|
u_boot_console.run_command('setenv bootmenu_0 test 1=echo ok 1')
|
||||||
|
u_boot_console.run_command('setenv bootmenu_1 test 2=echo ok 2')
|
||||||
|
u_boot_console.run_command('setenv bootmenu_2 test 3=echo ok 3')
|
||||||
|
u_boot_console.run_command('bootmenu 2', wait_for_prompt=False)
|
||||||
|
for i in ('U-Boot Boot Menu', 'test 1', 'test 2', 'test 3', 'autoboot'):
|
||||||
|
u_boot_console.p.expect([i])
|
||||||
|
# Press enter key to execute default entry
|
||||||
|
response = u_boot_console.run_command(cmd='\x0d', wait_for_echo=False, send_nl=False)
|
||||||
|
assert 'ok 2' in response
|
||||||
|
u_boot_console.run_command('bootmenu 2', wait_for_prompt=False)
|
||||||
|
u_boot_console.p.expect(['autoboot'])
|
||||||
|
# Press up key to select prior entry followed by the enter key
|
||||||
|
response = u_boot_console.run_command(cmd='\x1b\x5b\x41\x0d', wait_for_echo=False,
|
||||||
|
send_nl=False)
|
||||||
|
assert 'ok 1' in response
|
||||||
|
u_boot_console.run_command('bootmenu 2', wait_for_prompt=False)
|
||||||
|
u_boot_console.p.expect(['autoboot'])
|
||||||
|
# Press down key to select next entry followed by the enter key
|
||||||
|
response = u_boot_console.run_command(cmd='\x1b\x5b\x42\x0d', wait_for_echo=False,
|
||||||
|
send_nl=False)
|
||||||
|
assert 'ok 3' in response
|
||||||
|
u_boot_console.run_command('bootmenu 2; echo rc:$?', wait_for_prompt=False)
|
||||||
|
u_boot_console.p.expect(['autoboot'])
|
||||||
|
# Press the escape key
|
||||||
|
response = u_boot_console.run_command(cmd='\x1b', wait_for_echo=False, send_nl=False)
|
||||||
|
assert 'ok' not in response
|
||||||
|
assert 'rc:0' in response
|
||||||
|
u_boot_console.run_command('setenv bootmenu_default')
|
||||||
|
u_boot_console.run_command('setenv bootmenu_0')
|
||||||
|
u_boot_console.run_command('setenv bootmenu_1')
|
||||||
|
u_boot_console.run_command('setenv bootmenu_2')
|
@ -1,17 +1,13 @@
|
|||||||
# SPDX-License-Identifier: GPL-2.0+
|
# SPDX-License-Identifier: GPL-2.0+
|
||||||
# Copyright (c) 2020, Linaro Limited
|
# Copyright (c) 2020, Linaro Limited
|
||||||
# Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
|
# Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
|
||||||
#
|
|
||||||
# U-Boot UEFI: Firmware Update Test
|
|
||||||
|
|
||||||
"""
|
""" U-Boot UEFI: Firmware Update Test
|
||||||
This test verifies capsule-on-disk firmware update for raw images
|
This test verifies capsule-on-disk firmware update for raw images
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from subprocess import check_call, check_output, CalledProcessError
|
|
||||||
import pytest
|
import pytest
|
||||||
from capsule_defs import *
|
from capsule_defs import CAPSULE_DATA_DIR, CAPSULE_INSTALL_DIR
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.boardspec('sandbox')
|
@pytest.mark.boardspec('sandbox')
|
||||||
@pytest.mark.buildconfigspec('efi_capsule_firmware_raw')
|
@pytest.mark.buildconfigspec('efi_capsule_firmware_raw')
|
||||||
@ -24,11 +20,14 @@ from capsule_defs import *
|
|||||||
@pytest.mark.buildconfigspec('cmd_nvedit_efi')
|
@pytest.mark.buildconfigspec('cmd_nvedit_efi')
|
||||||
@pytest.mark.buildconfigspec('cmd_sf')
|
@pytest.mark.buildconfigspec('cmd_sf')
|
||||||
@pytest.mark.slow
|
@pytest.mark.slow
|
||||||
class TestEfiCapsuleFirmwareRaw(object):
|
class TestEfiCapsuleFirmwareRaw:
|
||||||
|
""" Tests verifying capsule-on-disk firmware update for raw images
|
||||||
|
"""
|
||||||
|
|
||||||
def test_efi_capsule_fw1(
|
def test_efi_capsule_fw1(
|
||||||
self, u_boot_config, u_boot_console, efi_capsule_data):
|
self, u_boot_config, u_boot_console, efi_capsule_data):
|
||||||
"""
|
""" Test Case 1
|
||||||
Test Case 1 - Update U-Boot and U-Boot environment on SPI Flash
|
Update U-Boot and U-Boot environment on SPI Flash
|
||||||
but with an incorrect GUID value in the capsule
|
but with an incorrect GUID value in the capsule
|
||||||
No update should happen
|
No update should happen
|
||||||
0x100000-0x150000: U-Boot binary (but dummy)
|
0x100000-0x150000: U-Boot binary (but dummy)
|
||||||
@ -106,9 +105,8 @@ class TestEfiCapsuleFirmwareRaw(object):
|
|||||||
|
|
||||||
def test_efi_capsule_fw2(
|
def test_efi_capsule_fw2(
|
||||||
self, u_boot_config, u_boot_console, efi_capsule_data):
|
self, u_boot_config, u_boot_console, efi_capsule_data):
|
||||||
"""
|
""" Test Case 2
|
||||||
Test Case 2 - Update U-Boot and U-Boot environment on SPI Flash
|
Update U-Boot and U-Boot environment on SPI Flash but with OsIndications unset
|
||||||
but with OsIndications unset
|
|
||||||
No update should happen
|
No update should happen
|
||||||
0x100000-0x150000: U-Boot binary (but dummy)
|
0x100000-0x150000: U-Boot binary (but dummy)
|
||||||
0x150000-0x200000: U-Boot environment (but dummy)
|
0x150000-0x200000: U-Boot environment (but dummy)
|
||||||
@ -191,8 +189,8 @@ class TestEfiCapsuleFirmwareRaw(object):
|
|||||||
|
|
||||||
def test_efi_capsule_fw3(
|
def test_efi_capsule_fw3(
|
||||||
self, u_boot_config, u_boot_console, efi_capsule_data):
|
self, u_boot_config, u_boot_console, efi_capsule_data):
|
||||||
"""
|
""" Test Case 3
|
||||||
Test Case 3 - Update U-Boot on SPI Flash, raw image format
|
Update U-Boot on SPI Flash, raw image format
|
||||||
0x100000-0x150000: U-Boot binary (but dummy)
|
0x100000-0x150000: U-Boot binary (but dummy)
|
||||||
"""
|
"""
|
||||||
disk_img = efi_capsule_data
|
disk_img = efi_capsule_data
|
||||||
|
@ -758,6 +758,56 @@ static int unicode_test_efi_create_indexed_name(struct unit_test_state *uts)
|
|||||||
UNICODE_TEST(unicode_test_efi_create_indexed_name);
|
UNICODE_TEST(unicode_test_efi_create_indexed_name);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static int unicode_test_u16_strlcat(struct unit_test_state *uts)
|
||||||
|
{
|
||||||
|
u16 buf[40];
|
||||||
|
u16 dest[] = {0x3053, 0x3093, 0x306b, 0x3061, 0x306f, 0};
|
||||||
|
u16 src[] = {0x03B1, 0x2172, 0x6F5C, 0x8247, 0};
|
||||||
|
u16 concat_str[] = {0x3053, 0x3093, 0x306b, 0x3061, 0x306f,
|
||||||
|
0x03B1, 0x2172, 0x6F5C, 0x8247, 0};
|
||||||
|
u16 null_src = u'\0';
|
||||||
|
size_t ret, expected;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* dest and src are empty string */
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
ret = u16_strlcat(buf, &null_src, sizeof(buf));
|
||||||
|
ut_asserteq(1, ret);
|
||||||
|
|
||||||
|
/* dest is empty string */
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
ret = u16_strlcat(buf, src, sizeof(buf));
|
||||||
|
ut_asserteq(5, ret);
|
||||||
|
ut_assert(!unicode_test_u16_strcmp(buf, src, 40));
|
||||||
|
|
||||||
|
/* src is empty string */
|
||||||
|
memset(buf, 0xCD, (sizeof(buf) - sizeof(u16)));
|
||||||
|
buf[39] = 0;
|
||||||
|
memcpy(buf, dest, sizeof(dest));
|
||||||
|
ret = u16_strlcat(buf, &null_src, sizeof(buf));
|
||||||
|
ut_asserteq(6, ret);
|
||||||
|
ut_assert(!unicode_test_u16_strcmp(buf, dest, 40));
|
||||||
|
|
||||||
|
for (i = 0; i <= 40; i++) {
|
||||||
|
memset(buf, 0xCD, (sizeof(buf) - sizeof(u16)));
|
||||||
|
buf[39] = 0;
|
||||||
|
memcpy(buf, dest, sizeof(dest));
|
||||||
|
expected = 10;
|
||||||
|
ret = u16_strlcat(buf, src, i);
|
||||||
|
ut_asserteq(expected, ret);
|
||||||
|
if (i <= 6) {
|
||||||
|
ut_assert(!unicode_test_u16_strcmp(buf, dest, 40));
|
||||||
|
} else if (i < 10) {
|
||||||
|
ut_assert(!unicode_test_u16_strcmp(buf, concat_str, i - 1));
|
||||||
|
} else {
|
||||||
|
ut_assert(!unicode_test_u16_strcmp(buf, concat_str, 40));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
UNICODE_TEST(unicode_test_u16_strlcat);
|
||||||
|
|
||||||
int do_ut_unicode(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
int do_ut_unicode(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
||||||
{
|
{
|
||||||
struct unit_test *tests = UNIT_TEST_SUITE_START(unicode_test);
|
struct unit_test *tests = UNIT_TEST_SUITE_START(unicode_test);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user