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:
Tom Rini 2022-05-04 12:08:40 -04:00
commit 1739a6db54
24 changed files with 576 additions and 100 deletions

View File

@ -353,9 +353,20 @@ source lib/efi_selftest/Kconfig
config CMD_BOOTMENU
bool "bootmenu"
select MENU
select CHARSET
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

View File

@ -3,9 +3,12 @@
* (C) Copyright 2011-2013 Pali Rohár <pali@kernel.org>
*/
#include <charset.h>
#include <common.h>
#include <command.h>
#include <ansi.h>
#include <efi_loader.h>
#include <efi_variable.h>
#include <env.h>
#include <log.h>
#include <menu.h>
@ -24,11 +27,26 @@
*/
#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 {
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) */
};
@ -68,14 +86,12 @@ static void bootmenu_print_entry(void *data)
* Move cursor to line where the entry will be drown (entry->num)
* First 3 lines contain bootmenu header + 1 empty line
*/
printf(ANSI_CURSOR_POSITION, entry->num + 4, 1);
puts(" ");
printf(ANSI_CURSOR_POSITION, entry->num + 4, 7);
if (reverse)
puts(ANSI_COLOR_REVERSE);
puts(entry->title);
printf("%ls", entry->title);
if (reverse)
puts(ANSI_COLOR_RESET);
@ -86,12 +102,9 @@ static void bootmenu_autoboot_loop(struct bootmenu_data *menu,
{
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) {
printf(ANSI_CURSOR_POSITION, menu->count + 5, 3);
printf("Hit any key to stop autoboot: %d ", menu->delay);
for (i = 0; i < 100; ++i) {
if (!tstc()) {
WATCHDOG_RESET();
@ -125,7 +138,6 @@ static void bootmenu_autoboot_loop(struct bootmenu_data *menu,
break;
--menu->delay;
printf("\b\b\b%2d ", menu->delay);
}
printf(ANSI_CURSOR_POSITION, menu->count + 5, 1);
@ -275,31 +287,32 @@ static void bootmenu_destroy(struct bootmenu_data *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;
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 +321,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 +346,8 @@ 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)
@ -347,13 +362,146 @@ static struct bootmenu_data *bootmenu_create(int delay)
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 */
if (i <= MAX_COUNT - 1) {
entry = malloc(sizeof(struct bootmenu_entry));
if (!entry)
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) {
free(entry);
goto cleanup;
@ -370,6 +518,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)
@ -407,8 +556,8 @@ static void menu_display_statusline(struct menu *m)
printf(ANSI_CURSOR_POSITION, 1, 1);
puts(ANSI_CLEAR_LINE);
printf(ANSI_CURSOR_POSITION, 2, 1);
puts(" *** U-Boot Boot Menu ***");
printf(ANSI_CURSOR_POSITION, 2, 3);
puts("*** U-Boot Boot Menu ***");
puts(ANSI_CLEAR_LINE_TO_END);
printf(ANSI_CURSOR_POSITION, 3, 1);
puts(ANSI_CLEAR_LINE);
@ -416,50 +565,81 @@ static void menu_display_statusline(struct menu *m)
/* First 3 lines are bootmenu header + 2 empty lines between entries */
printf(ANSI_CURSOR_POSITION, menu->count + 5, 1);
puts(ANSI_CLEAR_LINE);
printf(ANSI_CURSOR_POSITION, menu->count + 6, 1);
puts(" Press UP/DOWN to move, ENTER to select, ESC/CTRL+C to quit");
printf(ANSI_CURSOR_POSITION, menu->count + 6, 3);
puts("Press UP/DOWN to move, ENTER to select, ESC/CTRL+C to quit");
puts(ANSI_CLEAR_LINE_TO_END);
printf(ANSI_CURSOR_POSITION, menu->count + 7, 1);
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;
int ret = BOOTMENU_RET_SUCCESS;
struct bootmenu_data *bootmenu;
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 +658,37 @@ static void bootmenu_show(int delay)
if (menu_get_choice(menu, &choice) == 1) {
iter = choice;
title = strdup(iter->title);
title = u16_strdup(iter->title);
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:
@ -493,21 +702,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)
ret = BOOTMENU_RET_FAIL;
return ret;
}
#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

View File

@ -271,7 +271,10 @@ int menu_get_choice(struct menu *m, void **choice)
if (!m || !choice)
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_interactive_choice(m, choice);

View File

@ -39,6 +39,7 @@ CONFIG_CMD_LICENSE=y
CONFIG_CMD_BOOTM_PRE_LOAD=y
CONFIG_CMD_BOOTZ=y
CONFIG_CMD_BOOTEFI_HELLO=y
CONFIG_CMD_BOOTMENU=y
CONFIG_CMD_ABOOTIMG=y
# CONFIG_CMD_ELF is not set
CONFIG_CMD_ASKENV=y

View File

@ -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)
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
selection.
@ -79,7 +79,7 @@ The above example will be rendered as below::
The selected menu entry will be highlighted - it will have inverted
background and text colors.
The "bootmenu" cammand is enabled by::
The "bootmenu" command is enabled by::
CONFIG_CMD_BOOTMENU=y

View File

@ -3,6 +3,7 @@ menu "UFS Host Controller Support"
config UFS
bool "Support UFS controllers"
depends on DM_SCSI
select CHARSET
help
This selects support for Universal Flash Subsystem (UFS).
Say Y here if you want UFS Support.

View File

@ -261,6 +261,20 @@ u16 *u16_strcpy(u16 *dest, const u16 *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
*

View 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

View File

@ -595,6 +595,10 @@ efi_status_t efi_create_handle(efi_handle_t *handle);
void efi_delete_handle(efi_handle_t obj);
/* Call this to validate a handle and find the EFI object for it */
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 */
efi_status_t EFIAPI efi_load_image(bool boot_policy,
efi_handle_t parent_image,

View File

@ -52,11 +52,6 @@ config CC_OPTIMIZE_LIBS_FOR_SPEED
config CHARSET
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
bool "Enable Dynamic tables for CRC"

View File

@ -416,6 +416,22 @@ u16 *u16_strdup(const void *src)
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. */
uint8_t *utf16_to_utf8(uint8_t *dest, const uint16_t *src, size_t size)
{

View File

@ -14,6 +14,7 @@ choice
config EFI_APP
bool "Support running as an EFI application"
select CHARSET
help
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

View File

@ -14,6 +14,7 @@ config EFI_LOADER
depends on DM_ETH || !NET
depends on !EFI_APP
default y if !ARM || SYS_CPU = armv7 || SYS_CPU = armv8
select CHARSET
select DM_EVENT
select EVENT_DYNAMIC
select LIB_UUID

View File

@ -11,6 +11,7 @@
#include <charset.h>
#include <log.h>
#include <malloc.h>
#include <efi_default_filename.h>
#include <efi_loader.h>
#include <efi_variable.h>
#include <asm/unaligned.h>
@ -30,6 +31,51 @@ static const struct efi_runtime_services *rs;
* 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
*
@ -64,13 +110,16 @@ static efi_status_t try_load_entry(u16 n, efi_handle_t *handle,
}
if (lo.attributes & LOAD_OPTION_ACTIVE) {
struct efi_device_path *file_path;
u32 attributes;
log_debug("trying to load \"%ls\" from %pD\n", lo.label,
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));
efi_free_pool(file_path);
if (ret != EFI_SUCCESS) {
log_warning("Loading %ls '%ls' failed\n",
varname, lo.label);

View File

@ -1799,10 +1799,9 @@ failure:
*
* Return: status code
*/
static efi_status_t EFIAPI efi_locate_device_path(
const efi_guid_t *protocol,
struct efi_device_path **device_path,
efi_handle_t *device)
efi_status_t EFIAPI efi_locate_device_path(const efi_guid_t *protocol,
struct efi_device_path **device_path,
efi_handle_t *device)
{
struct efi_device_path *dp;
size_t i;

View File

@ -522,11 +522,11 @@ static efi_status_t EFIAPI efi_cout_reset(
{
EFI_ENTRY("%p, %d", this, extended_verification);
/* Clear screen */
EFI_CALL(efi_cout_clear_screen(this));
/* Set default colors */
efi_con_mode.attribute = 0x07;
printf(ESC "[0;37;40m");
/* Clear screen */
EFI_CALL(efi_cout_clear_screen(this));
return EFI_EXIT(EFI_SUCCESS);
}

View File

@ -55,7 +55,9 @@ obj-$(CONFIG_EFI_DEVICE_PATH_TO_TEXT) += efi_selftest_devicepath.o
obj-$(CONFIG_EFI_UNICODE_COLLATION_PROTOCOL2) += \
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_RNG_PROTOCOL) += efi_selftest_rng.o
obj-$(CONFIG_EFI_GET_TIME) += efi_selftest_rtc.o

View File

@ -631,8 +631,10 @@ static int efi_st_tcg2_setup(const efi_handle_t img_handle,
sizeof(struct efi_tcg2_event) +
sizeof(struct uefi_image_load_event),
(void **)&efi_tcg2_event);
if (!efi_tcg2_event)
if (ret != EFI_SUCCESS) {
efi_st_error("Out of memory\n");
return EFI_ST_FAILURE;
}
efi_tcg2_event->size = sizeof(struct efi_tcg2_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) *
TPM2_SHA256_DIGEST_SIZE,
(void **)&pcrs);
if (!pcrs)
if (ret != EFI_SUCCESS) {
efi_st_error("Out of memory\n");
return EFI_ST_FAILURE;
}
boottime->set_mem(pcrs, (EFI_TCG2_MAX_PCR_INDEX + 1) * TPM2_SHA256_DIGEST_SIZE, 0);

View File

@ -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
* occurs.
*
* @addr: address to read
* Return: value at the address
*/
static inline u32 deref(u32 *addr)
static inline u32 deref(void *addr)
{
int ret;
@ -43,12 +43,11 @@ static int execute(void)
{
struct aligned_buffer buf = {
{0, 1, 2, 3, 4, 5, 6, 7},
};
void *v = &buf;
};
u32 r = 0;
/* Read an unaligned address */
r = deref(v + 1);
r = deref(&buf.a[1]);
/* UEFI only supports low endian systems */
if (r != 0x04030201) {

View File

@ -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_avb.py 5.52
test_tests_test_bind.py -2.99
test_tests_test_bootmenu.py 10.00
test_tests_test_button.py 3.33
test_tests_test_dfu.py 5.45
test_tests_test_dm.py 9.52

View File

@ -91,6 +91,7 @@ config UT_UNICODE
bool "Unit tests for Unicode functions"
depends on UNIT_TEST
default y
select CHARSET
help
Enables the 'ut unicode' command which tests that the functions for
manipulating Unicode strings work correctly.

View 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')

View File

@ -1,17 +1,13 @@
# SPDX-License-Identifier: GPL-2.0+
# Copyright (c) 2020, Linaro Limited
# 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
"""
from subprocess import check_call, check_output, CalledProcessError
import pytest
from capsule_defs import *
from capsule_defs import CAPSULE_DATA_DIR, CAPSULE_INSTALL_DIR
@pytest.mark.boardspec('sandbox')
@pytest.mark.buildconfigspec('efi_capsule_firmware_raw')
@ -24,15 +20,18 @@ from capsule_defs import *
@pytest.mark.buildconfigspec('cmd_nvedit_efi')
@pytest.mark.buildconfigspec('cmd_sf')
@pytest.mark.slow
class TestEfiCapsuleFirmwareRaw(object):
class TestEfiCapsuleFirmwareRaw:
""" Tests verifying capsule-on-disk firmware update for raw images
"""
def test_efi_capsule_fw1(
self, u_boot_config, u_boot_console, efi_capsule_data):
"""
Test Case 1 - Update U-Boot and U-Boot environment on SPI Flash
but with an incorrect GUID value in the capsule
No update should happen
0x100000-0x150000: U-Boot binary (but dummy)
0x150000-0x200000: U-Boot environment (but dummy)
""" Test Case 1
Update U-Boot and U-Boot environment on SPI Flash
but with an incorrect GUID value in the capsule
No update should happen
0x100000-0x150000: U-Boot binary (but dummy)
0x150000-0x200000: U-Boot environment (but dummy)
"""
# other tests might have run and the
@ -106,12 +105,11 @@ class TestEfiCapsuleFirmwareRaw(object):
def test_efi_capsule_fw2(
self, u_boot_config, u_boot_console, efi_capsule_data):
"""
Test Case 2 - Update U-Boot and U-Boot environment on SPI Flash
but with OsIndications unset
No update should happen
0x100000-0x150000: U-Boot binary (but dummy)
0x150000-0x200000: U-Boot environment (but dummy)
""" Test Case 2
Update U-Boot and U-Boot environment on SPI Flash but with OsIndications unset
No update should happen
0x100000-0x150000: U-Boot binary (but dummy)
0x150000-0x200000: U-Boot environment (but dummy)
"""
disk_img = efi_capsule_data
with u_boot_console.log.section('Test Case 2-a, before reboot'):
@ -191,9 +189,9 @@ class TestEfiCapsuleFirmwareRaw(object):
def test_efi_capsule_fw3(
self, u_boot_config, u_boot_console, efi_capsule_data):
"""
Test Case 3 - Update U-Boot on SPI Flash, raw image format
0x100000-0x150000: U-Boot binary (but dummy)
""" Test Case 3
Update U-Boot on SPI Flash, raw image format
0x100000-0x150000: U-Boot binary (but dummy)
"""
disk_img = efi_capsule_data
with u_boot_console.log.section('Test Case 3-a, before reboot'):

View File

@ -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);
#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[])
{
struct unit_test *tests = UNIT_TEST_SUITE_START(unicode_test);