mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-14 00:47:26 +00:00
Pull request for efi next
UEFI: Implement a command eficonfig to maintain Load Options and boot order via menus. -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEbcT5xx8ppvoGt20zxIHbvCwFGsQFAmMh/kQACgkQxIHbvCwF GsSYVhAAlhyCiAQudBJtrOyAA0HDPMio/Fx9F3YV1Laay//6+xHhEh5H94fMr7jP BHOrpE+IDKQTiQ8X3FpJpm3FzgQBzu0s4gQ+8fCKwkXCkaPTtWhs3s5SdHN0TWmv qGlNbuPdoU+4i7PeBWw87EvOCzh4+snn+l3t+npMxUlZJInGy+6xj0irnSEXTvXV lpDRw2UDq3/smAS8tAcR+zriTH5o1Lx+0qPIO9Hw8BSDHOcvZD+S9d6cd6j+M+Wz rWk1Bshol6anIZWS5Gnx14ddKF8SQcSiPsDXg2Uj2DvFg7lWepKxAbDJD5CVF9R9 aEu6THCurc+769A/IHAS9M0EDNnWoUGFSxe0JuEHdYVuGj30RRfzSaciKkNxsxUZ UGvDnQ+zdRoj6bTVi4Zf8SeZUTm/04lWMoIF05uhZFDiwxidbMowoNsk9FeKria/ 4vXybfj/IhRwbiAhOUqyDjGuoLj8iVeOAyzin4FnDvBwdshIkSsB+4y1sX1aQv02 HQbP6WXkiYoYNkw5i9E9ZChioxkzMrn2za3GxWhkTBMJArDw6xSuHMdQsgwWWoqU fCKjwe+D96lHq5cKt3DmGTvGxQtx9ckSJGK5r+US5y1udzotjOKc1jqMkMvS3Jyg ureTj0wvLYSx+/UirVAZ4IDviDMBVEar79VS2xi+SYBMLeQPy3I= =P89S -----END PGP SIGNATURE----- Merge tag 'efi-next-2022-09-14' of https://source.denx.de/u-boot/custodians/u-boot-efi into next Pull request for efi next UEFI: Implement a command eficonfig to maintain Load Options and boot order via menus.
This commit is contained in:
commit
1520af3f84
19 changed files with 3437 additions and 53 deletions
|
@ -1928,6 +1928,13 @@ config CMD_EFIDEBUG
|
||||||
particularly for managing boot parameters as well as examining
|
particularly for managing boot parameters as well as examining
|
||||||
various EFI status for debugging.
|
various EFI status for debugging.
|
||||||
|
|
||||||
|
config CMD_EFICONFIG
|
||||||
|
bool "eficonfig - provide menu-driven uefi variables maintenance interface"
|
||||||
|
depends on CMD_BOOTEFI_BOOTMGR
|
||||||
|
help
|
||||||
|
Enable the 'eficonfig' command which provides the menu-driven UEFI
|
||||||
|
variable maintenance interface.
|
||||||
|
|
||||||
config CMD_EXCEPTION
|
config CMD_EXCEPTION
|
||||||
bool "exception - raise exception"
|
bool "exception - raise exception"
|
||||||
depends on ARM || RISCV || SANDBOX || X86
|
depends on ARM || RISCV || SANDBOX || X86
|
||||||
|
|
|
@ -64,6 +64,7 @@ obj-$(CONFIG_ENV_IS_IN_EEPROM) += eeprom.o
|
||||||
obj-$(CONFIG_CMD_EEPROM) += eeprom.o
|
obj-$(CONFIG_CMD_EEPROM) += eeprom.o
|
||||||
obj-$(CONFIG_EFI) += efi.o
|
obj-$(CONFIG_EFI) += efi.o
|
||||||
obj-$(CONFIG_CMD_EFIDEBUG) += efidebug.o
|
obj-$(CONFIG_CMD_EFIDEBUG) += efidebug.o
|
||||||
|
obj-$(CONFIG_CMD_EFICONFIG) += eficonfig.o
|
||||||
obj-$(CONFIG_CMD_ELF) += elf.o
|
obj-$(CONFIG_CMD_ELF) += elf.o
|
||||||
obj-$(CONFIG_CMD_EROFS) += erofs.o
|
obj-$(CONFIG_CMD_EROFS) += erofs.o
|
||||||
obj-$(CONFIG_HUSH_PARSER) += exit.o
|
obj-$(CONFIG_HUSH_PARSER) += exit.o
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
#include <command.h>
|
#include <command.h>
|
||||||
#include <ansi.h>
|
#include <ansi.h>
|
||||||
#include <efi_loader.h>
|
#include <efi_config.h>
|
||||||
#include <efi_variable.h>
|
#include <efi_variable.h>
|
||||||
#include <env.h>
|
#include <env.h>
|
||||||
#include <log.h>
|
#include <log.h>
|
||||||
|
@ -220,7 +220,7 @@ static int prepare_bootmenu_entry(struct bootmenu_data *menu,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if (CONFIG_IS_ENABLED(CMD_BOOTEFI_BOOTMGR))
|
#if (CONFIG_IS_ENABLED(CMD_BOOTEFI_BOOTMGR)) && (CONFIG_IS_ENABLED(CMD_EFICONFIG))
|
||||||
/**
|
/**
|
||||||
* prepare_uefi_bootorder_entry() - generate the uefi bootmenu entries
|
* prepare_uefi_bootorder_entry() - generate the uefi bootmenu entries
|
||||||
*
|
*
|
||||||
|
@ -340,11 +340,21 @@ static struct bootmenu_data *bootmenu_create(int delay)
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
#if (CONFIG_IS_ENABLED(CMD_BOOTEFI_BOOTMGR))
|
#if (CONFIG_IS_ENABLED(CMD_BOOTEFI_BOOTMGR)) && (CONFIG_IS_ENABLED(CMD_EFICONFIG))
|
||||||
if (i < MAX_COUNT - 1) {
|
if (i < MAX_COUNT - 1) {
|
||||||
ret = prepare_uefi_bootorder_entry(menu, &iter, &i);
|
efi_status_t efi_ret;
|
||||||
if (ret < 0 && ret != -ENOENT)
|
|
||||||
goto cleanup;
|
/*
|
||||||
|
* UEFI specification requires booting from removal media using
|
||||||
|
* a architecture-specific default image name such as BOOTAA64.EFI.
|
||||||
|
*/
|
||||||
|
efi_ret = eficonfig_generate_media_device_boot_option();
|
||||||
|
if (efi_ret != EFI_SUCCESS && efi_ret != EFI_NOT_FOUND)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
ret = prepare_uefi_bootorder_entry(menu, &iter, &i);
|
||||||
|
if (ret < 0 && ret != -ENOENT)
|
||||||
|
goto cleanup;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
2502
cmd/eficonfig.c
Normal file
2502
cmd/eficonfig.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -548,4 +548,13 @@ void bootmenu_loop(struct bootmenu_data *menu,
|
||||||
/* ^C was pressed */
|
/* ^C was pressed */
|
||||||
if (c == 0x3)
|
if (c == 0x3)
|
||||||
*key = KEY_QUIT;
|
*key = KEY_QUIT;
|
||||||
|
|
||||||
|
if (c == '+')
|
||||||
|
*key = KEY_PLUS;
|
||||||
|
|
||||||
|
if (c == '-')
|
||||||
|
*key = KEY_MINUS;
|
||||||
|
|
||||||
|
if (c == ' ')
|
||||||
|
*key = KEY_SPACE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,6 +93,7 @@ CONFIG_CMD_LINK_LOCAL=y
|
||||||
CONFIG_CMD_ETHSW=y
|
CONFIG_CMD_ETHSW=y
|
||||||
CONFIG_CMD_BMP=y
|
CONFIG_CMD_BMP=y
|
||||||
CONFIG_CMD_BOOTCOUNT=y
|
CONFIG_CMD_BOOTCOUNT=y
|
||||||
|
CONFIG_CMD_EFICONFIG=y
|
||||||
CONFIG_CMD_EFIDEBUG=y
|
CONFIG_CMD_EFIDEBUG=y
|
||||||
CONFIG_CMD_RTC=y
|
CONFIG_CMD_RTC=y
|
||||||
CONFIG_CMD_TIME=y
|
CONFIG_CMD_TIME=y
|
||||||
|
|
|
@ -4,6 +4,15 @@
|
||||||
bootmenu command
|
bootmenu command
|
||||||
================
|
================
|
||||||
|
|
||||||
|
Synopsis
|
||||||
|
--------
|
||||||
|
::
|
||||||
|
|
||||||
|
bootmenu [delay]
|
||||||
|
|
||||||
|
Description
|
||||||
|
-----------
|
||||||
|
|
||||||
The "bootmenu" command uses U-Boot menu interfaces and provides
|
The "bootmenu" command uses U-Boot menu interfaces and provides
|
||||||
a simple mechanism for creating menus with different boot items.
|
a simple mechanism for creating menus with different boot items.
|
||||||
The cursor keys "Up" and "Down" are used for navigation through
|
The cursor keys "Up" and "Down" are used for navigation through
|
||||||
|
@ -79,6 +88,55 @@ 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.
|
||||||
|
|
||||||
|
UEFI boot variable enumeration
|
||||||
|
''''''''''''''''''''''''''''''
|
||||||
|
If enabled, the bootmenu command will automatically generate and add
|
||||||
|
UEFI-related boot menu entries for the following items.
|
||||||
|
|
||||||
|
* possible bootable media with default file names
|
||||||
|
* user-defined UEFI boot options
|
||||||
|
|
||||||
|
The bootmenu automatically enumerates the possible bootable
|
||||||
|
media devices supporting EFI_SIMPLE_FILE_SYSTEM_PROTOCOL.
|
||||||
|
This auto generated entry is named as "<interface> <devnum>:<part>" format.
|
||||||
|
(e.g. "usb 0:1")
|
||||||
|
|
||||||
|
The bootmenu displays the UEFI-related menu entries in order of "BootOrder".
|
||||||
|
When the user selects the UEFI boot menu entry, the bootmenu sets
|
||||||
|
the selected boot variable index to "BootNext" without non-volatile attribute,
|
||||||
|
then call the uefi boot manager with the command "bootefi bootmgr".
|
||||||
|
|
||||||
|
Example bootmenu is as below::
|
||||||
|
|
||||||
|
*** U-Boot Boot Menu ***
|
||||||
|
|
||||||
|
mmc 0:1
|
||||||
|
mmc 0:2
|
||||||
|
debian
|
||||||
|
nvme 0:1
|
||||||
|
ubuntu
|
||||||
|
nvme 0:2
|
||||||
|
usb 0:2
|
||||||
|
U-Boot console
|
||||||
|
|
||||||
|
Default behavior when user exits from the bootmenu
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
User can exit from bootmenu by selecting the last entry
|
||||||
|
"U-Boot console"/"Quit" or ESC/CTRL+C key.
|
||||||
|
|
||||||
|
When the CONFIG_BOOTMENU_DISABLE_UBOOT_CONSOLE is disabled,
|
||||||
|
user exits from the bootmenu and returns to the U-Boot console.
|
||||||
|
|
||||||
|
When the CONFIG_BOOTMENU_DISABLE_UBOOT_CONSOLE is enabled, user can not
|
||||||
|
enter the U-Boot console. When the user exits from the bootmenu,
|
||||||
|
the bootmenu invokes the following default behavior.
|
||||||
|
|
||||||
|
* if CONFIG_CMD_BOOTEFI_BOOTMGR is enabled, execute "bootefi bootmgr" command
|
||||||
|
* "bootefi bootmgr" fails or is not enabled, then execute "run bootcmd" command.
|
||||||
|
|
||||||
|
Configuration
|
||||||
|
-------------
|
||||||
|
|
||||||
The "bootmenu" command is enabled by::
|
The "bootmenu" command is enabled by::
|
||||||
|
|
||||||
CONFIG_CMD_BOOTMENU=y
|
CONFIG_CMD_BOOTMENU=y
|
||||||
|
@ -88,3 +146,19 @@ To run the bootmenu at startup add these additional settings::
|
||||||
CONFIG_AUTOBOOT_KEYED=y
|
CONFIG_AUTOBOOT_KEYED=y
|
||||||
CONFIG_BOOTDELAY=30
|
CONFIG_BOOTDELAY=30
|
||||||
CONFIG_AUTOBOOT_MENU_SHOW=y
|
CONFIG_AUTOBOOT_MENU_SHOW=y
|
||||||
|
|
||||||
|
UEFI boot variable enumeration is enabled by::
|
||||||
|
|
||||||
|
CONFIG_CMD_BOOTEFI_BOOTMGR=y
|
||||||
|
|
||||||
|
To improve the product security, entering U-Boot console from bootmenu
|
||||||
|
can be disabled by::
|
||||||
|
|
||||||
|
CONFIG_BOOTMENU_DISABLE_UBOOT_CONSOLE=y
|
||||||
|
|
||||||
|
To scan the discoverable devices connected to the buses such as
|
||||||
|
USB and PCIe prior to bootmenu showing up, CONFIG_PREBOOT can be
|
||||||
|
used to run the command before showing the bootmenu, i.e.::
|
||||||
|
|
||||||
|
CONFIG_USE_PREBOOT=y
|
||||||
|
CONFIG_PREBOOT="pci enum; usb start; scsi scan; nvme scan; virtio scan"
|
||||||
|
|
71
doc/usage/cmd/eficonfig.rst
Normal file
71
doc/usage/cmd/eficonfig.rst
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
.. SPDX-License-Identifier: GPL-2.0+
|
||||||
|
.. (C) Copyright 2022, Masahisa Kojima <masahisa.kojima@linaro.org>
|
||||||
|
|
||||||
|
eficonfig command
|
||||||
|
=================
|
||||||
|
|
||||||
|
Synopsis
|
||||||
|
--------
|
||||||
|
::
|
||||||
|
|
||||||
|
eficonfig
|
||||||
|
|
||||||
|
Description
|
||||||
|
-----------
|
||||||
|
|
||||||
|
The "eficonfig" command uses U-Boot menu interface and provides
|
||||||
|
a menu-driven UEFI variable maintenance feature.
|
||||||
|
The "eficonfig" has the following menu entries.
|
||||||
|
|
||||||
|
Add Boot Option
|
||||||
|
Add new UEFI Boot Option.
|
||||||
|
User can edit description, file path, and optional_data.
|
||||||
|
|
||||||
|
Edit Boot Option
|
||||||
|
Edit the existing UEFI Boot Option
|
||||||
|
User can edit description, file path, and optional_data.
|
||||||
|
|
||||||
|
Change Boot Order
|
||||||
|
Change the order of UEFI BootOrder variable.
|
||||||
|
|
||||||
|
Delete Boot Option
|
||||||
|
Delete the UEFI Boot Option
|
||||||
|
|
||||||
|
Configuration
|
||||||
|
-------------
|
||||||
|
|
||||||
|
The "eficonfig" command is enabled by::
|
||||||
|
|
||||||
|
CONFIG_CMD_EFICONFIG=y
|
||||||
|
|
||||||
|
If CONFIG_BOOTMENU_DISABLE_UBOOT_CONSOLE is enabled, user can not enter
|
||||||
|
U-Boot console. In this case, bootmenu can be used to invoke "eficonfig"::
|
||||||
|
|
||||||
|
CONFIG_USE_PREBOOT=y
|
||||||
|
CONFIG_PREBOOT="setenv bootmenu_0 UEFI Maintenance Menu=eficonfig"
|
||||||
|
|
||||||
|
How to boot the system with newly added UEFI Boot Option
|
||||||
|
''''''''''''''''''''''''''''''''''''''''''''''''''''''''
|
||||||
|
|
||||||
|
"eficonfig" command is responsible for configuring the UEFI variables,
|
||||||
|
not directly handle the system boot.
|
||||||
|
The new Boot Option added by "eficonfig" is appended at the last entry
|
||||||
|
of UEFI BootOrder variable, user may want to change the boot order
|
||||||
|
through "Change Boot Order".
|
||||||
|
If the bootmenu is enabled, CONFIG_BOOTMENU_DISABLE_UBOOT_CONSOLE is enabled,
|
||||||
|
and "eficonfig" is configured as preboot command, the newly added Boot Options
|
||||||
|
are enumerated in the bootmenu when user exits from the eficonfig menu.
|
||||||
|
User may select the entry in the bootmenu to boot the system, or follow
|
||||||
|
the U-Boot configuration the system already has.
|
||||||
|
|
||||||
|
Auto boot with the UEFI Boot Option
|
||||||
|
'''''''''''''''''''''''''''''''''''
|
||||||
|
|
||||||
|
To do auto boot according to the UEFI BootOrder variable,
|
||||||
|
add "bootefi bootmgr" entry as a default or first bootmenu entry::
|
||||||
|
|
||||||
|
CONFIG_PREBOOT="setenv bootmenu_0 UEFI Boot Manager=bootefi bootmgr; setenv bootmenu_1 UEFI Maintenance Menu=eficonfig"
|
||||||
|
|
||||||
|
See also
|
||||||
|
--------
|
||||||
|
* :doc:`bootmenu<bootmenu>` provides a simple mechanism for creating menus with different boot items
|
|
@ -36,6 +36,7 @@ Shell commands
|
||||||
cmd/cyclic
|
cmd/cyclic
|
||||||
cmd/dm
|
cmd/dm
|
||||||
cmd/echo
|
cmd/echo
|
||||||
|
cmd/eficonfig
|
||||||
cmd/env
|
cmd/env
|
||||||
cmd/event
|
cmd/event
|
||||||
cmd/exception
|
cmd/exception
|
||||||
|
|
98
include/efi_config.h
Normal file
98
include/efi_config.h
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||||
|
/*
|
||||||
|
* Menu-driven UEFI Variable maintenance
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 Masahisa Kojima, Linaro Limited
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _EFI_CONFIG_H
|
||||||
|
#define _EFI_CONFIG_H
|
||||||
|
|
||||||
|
#include <efi_loader.h>
|
||||||
|
|
||||||
|
#define EFICONFIG_ENTRY_NUM_MAX 99
|
||||||
|
#define EFICONFIG_VOLUME_PATH_MAX 512
|
||||||
|
#define EFICONFIG_FILE_PATH_MAX 512
|
||||||
|
#define EFICONFIG_FILE_PATH_BUF_SIZE (EFICONFIG_FILE_PATH_MAX * sizeof(u16))
|
||||||
|
|
||||||
|
typedef efi_status_t (*eficonfig_entry_func)(void *data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct eficonfig_entry - menu entry structure
|
||||||
|
*
|
||||||
|
* @num: menu entry index
|
||||||
|
* @title: title of entry
|
||||||
|
* @key: unique key
|
||||||
|
* @efi_menu: pointer to the menu structure
|
||||||
|
* @func: callback function to be called when this entry is selected
|
||||||
|
* @data: data to be passed to the callback function, caller must free() this pointer
|
||||||
|
* @list: list structure
|
||||||
|
*/
|
||||||
|
struct eficonfig_entry {
|
||||||
|
u32 num;
|
||||||
|
char *title;
|
||||||
|
char key[3];
|
||||||
|
struct efimenu *efi_menu;
|
||||||
|
eficonfig_entry_func func;
|
||||||
|
void *data;
|
||||||
|
struct list_head list;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct efimenu - efi menu structure
|
||||||
|
*
|
||||||
|
* @delay: delay for autoboot
|
||||||
|
* @active: active menu entry index
|
||||||
|
* @count: total count of menu entry
|
||||||
|
* @menu_header: menu header string
|
||||||
|
* @list: menu entry list structure
|
||||||
|
*/
|
||||||
|
struct efimenu {
|
||||||
|
int delay;
|
||||||
|
int active;
|
||||||
|
int count;
|
||||||
|
char *menu_header;
|
||||||
|
struct list_head list;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct eficonfig_item - structure to construct eficonfig_entry
|
||||||
|
*
|
||||||
|
* @title: title of entry
|
||||||
|
* @func: callback function to be called when this entry is selected
|
||||||
|
* @data: data to be passed to the callback function
|
||||||
|
*/
|
||||||
|
struct eficonfig_item {
|
||||||
|
char *title;
|
||||||
|
eficonfig_entry_func func;
|
||||||
|
void *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct eficonfig_select_file_info - structure to be used for file selection
|
||||||
|
*
|
||||||
|
* @current_volume: pointer to the efi_simple_file_system_protocol
|
||||||
|
* @dp_volume: pointer to device path of the selected device
|
||||||
|
* @current_path: pointer to the selected file path string
|
||||||
|
* @filepath_list: list_head structure for file path list
|
||||||
|
* @file_selectred: flag indicates file selecting status
|
||||||
|
*/
|
||||||
|
struct eficonfig_select_file_info {
|
||||||
|
struct efi_simple_file_system_protocol *current_volume;
|
||||||
|
struct efi_device_path *dp_volume;
|
||||||
|
u16 *current_path;
|
||||||
|
struct list_head filepath_list;
|
||||||
|
bool file_selected;
|
||||||
|
};
|
||||||
|
|
||||||
|
void eficonfig_print_msg(char *msg);
|
||||||
|
void eficonfig_destroy(struct efimenu *efi_menu);
|
||||||
|
efi_status_t eficonfig_process_quit(void *data);
|
||||||
|
efi_status_t eficonfig_process_common(struct efimenu *efi_menu, char *menu_header);
|
||||||
|
efi_status_t eficonfig_select_file_handler(void *data);
|
||||||
|
efi_status_t eficonfig_get_unused_bootoption(u16 *buf,
|
||||||
|
efi_uintn_t buf_size, u32 *index);
|
||||||
|
efi_status_t eficonfig_append_bootorder(u16 index);
|
||||||
|
efi_status_t eficonfig_generate_media_device_boot_option(void);
|
||||||
|
|
||||||
|
#endif
|
|
@ -142,6 +142,11 @@ static inline efi_status_t efi_launch_capsules(void)
|
||||||
EFI_GUID(0x63293792, 0xadf5, 0x9325, \
|
EFI_GUID(0x63293792, 0xadf5, 0x9325, \
|
||||||
0xb9, 0x9f, 0x4e, 0x0e, 0x45, 0x5c, 0x1b, 0x1e)
|
0xb9, 0x9f, 0x4e, 0x0e, 0x45, 0x5c, 0x1b, 0x1e)
|
||||||
|
|
||||||
|
/* GUID for the auto generated boot menu entry */
|
||||||
|
#define EFICONFIG_AUTO_GENERATED_ENTRY_GUID \
|
||||||
|
EFI_GUID(0x38c1acc1, 0x9fc0, 0x41f0, \
|
||||||
|
0xb9, 0x01, 0xfa, 0x74, 0xd6, 0xd6, 0xe4, 0xde)
|
||||||
|
|
||||||
/* Use internal device tree when starting UEFI application */
|
/* Use internal device tree when starting UEFI application */
|
||||||
#define EFI_FDT_USE_INTERNAL NULL
|
#define EFI_FDT_USE_INTERNAL NULL
|
||||||
|
|
||||||
|
@ -226,6 +231,9 @@ const char *__efi_nesting_dec(void);
|
||||||
#define EFI_CACHELINE_SIZE 128
|
#define EFI_CACHELINE_SIZE 128
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* max bootmenu title size for volume selection */
|
||||||
|
#define BOOTMENU_DEVICE_NAME_MAX 16
|
||||||
|
|
||||||
/* Key identifying current memory map */
|
/* Key identifying current memory map */
|
||||||
extern efi_uintn_t efi_memory_map_key;
|
extern efi_uintn_t efi_memory_map_key;
|
||||||
|
|
||||||
|
@ -249,6 +257,9 @@ extern const struct efi_hii_string_protocol efi_hii_string;
|
||||||
|
|
||||||
uint16_t *efi_dp_str(struct efi_device_path *dp);
|
uint16_t *efi_dp_str(struct efi_device_path *dp);
|
||||||
|
|
||||||
|
/* GUID for the auto generated boot menu entry */
|
||||||
|
extern const efi_guid_t efi_guid_bootmenu_auto_generated;
|
||||||
|
|
||||||
/* GUID of the U-Boot root node */
|
/* GUID of the U-Boot root node */
|
||||||
extern const efi_guid_t efi_u_boot_guid;
|
extern const efi_guid_t efi_u_boot_guid;
|
||||||
#ifdef CONFIG_SANDBOX
|
#ifdef CONFIG_SANDBOX
|
||||||
|
@ -314,6 +325,8 @@ extern const efi_guid_t efi_guid_firmware_management_protocol;
|
||||||
extern const efi_guid_t efi_esrt_guid;
|
extern const efi_guid_t efi_esrt_guid;
|
||||||
/* GUID of the SMBIOS table */
|
/* GUID of the SMBIOS table */
|
||||||
extern const efi_guid_t smbios_guid;
|
extern const efi_guid_t smbios_guid;
|
||||||
|
/*GUID of console */
|
||||||
|
extern const efi_guid_t efi_guid_text_input_protocol;
|
||||||
|
|
||||||
extern char __efi_runtime_start[], __efi_runtime_stop[];
|
extern char __efi_runtime_start[], __efi_runtime_stop[];
|
||||||
extern char __efi_runtime_rel_start[], __efi_runtime_rel_stop[];
|
extern char __efi_runtime_rel_start[], __efi_runtime_rel_stop[];
|
||||||
|
@ -940,6 +953,22 @@ struct efi_signature_store {
|
||||||
struct x509_certificate;
|
struct x509_certificate;
|
||||||
struct pkcs7_message;
|
struct pkcs7_message;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct eficonfig_media_boot_option - boot option for (removable) media device
|
||||||
|
*
|
||||||
|
* This structure is used to enumerate possible boot option
|
||||||
|
*
|
||||||
|
* @lo: Serialized load option data
|
||||||
|
* @size: Size of serialized load option data
|
||||||
|
* @exist: Flag to indicate the load option already exists
|
||||||
|
* in Non-volatile load option
|
||||||
|
*/
|
||||||
|
struct eficonfig_media_boot_option {
|
||||||
|
void *lo;
|
||||||
|
efi_uintn_t size;
|
||||||
|
bool exist;
|
||||||
|
};
|
||||||
|
|
||||||
bool efi_hash_regions(struct image_region *regs, int count,
|
bool efi_hash_regions(struct image_region *regs, int count,
|
||||||
void **hash, const char *hash_algo, int *len);
|
void **hash, const char *hash_algo, int *len);
|
||||||
bool efi_signature_lookup_digest(struct efi_image_regions *regs,
|
bool efi_signature_lookup_digest(struct efi_image_regions *regs,
|
||||||
|
@ -1064,4 +1093,28 @@ efi_status_t efi_esrt_populate(void);
|
||||||
efi_status_t efi_load_capsule_drivers(void);
|
efi_status_t efi_load_capsule_drivers(void);
|
||||||
|
|
||||||
efi_status_t platform_get_eventlog(struct udevice *dev, u64 *addr, u32 *sz);
|
efi_status_t platform_get_eventlog(struct udevice *dev, u64 *addr, u32 *sz);
|
||||||
|
|
||||||
|
efi_status_t efi_locate_handle_buffer_int(enum efi_locate_search_type search_type,
|
||||||
|
const efi_guid_t *protocol, void *search_key,
|
||||||
|
efi_uintn_t *no_handles, efi_handle_t **buffer);
|
||||||
|
|
||||||
|
efi_status_t efi_open_volume_int(struct efi_simple_file_system_protocol *this,
|
||||||
|
struct efi_file_handle **root);
|
||||||
|
efi_status_t efi_file_open_int(struct efi_file_handle *this,
|
||||||
|
struct efi_file_handle **new_handle,
|
||||||
|
u16 *file_name, u64 open_mode,
|
||||||
|
u64 attributes);
|
||||||
|
efi_status_t efi_file_close_int(struct efi_file_handle *file);
|
||||||
|
efi_status_t efi_file_read_int(struct efi_file_handle *this,
|
||||||
|
efi_uintn_t *buffer_size, void *buffer);
|
||||||
|
efi_status_t efi_file_setpos_int(struct efi_file_handle *file, u64 pos);
|
||||||
|
|
||||||
|
typedef efi_status_t (*efi_console_filter_func)(struct efi_input_key *key);
|
||||||
|
efi_status_t efi_console_get_u16_string
|
||||||
|
(struct efi_simple_text_input_protocol *cin,
|
||||||
|
u16 *buf, efi_uintn_t count, efi_console_filter_func filer_func,
|
||||||
|
int row, int col);
|
||||||
|
|
||||||
|
efi_status_t efi_disk_get_device_name(const efi_handle_t handle, char *buf, int size);
|
||||||
|
|
||||||
#endif /* _EFI_LOADER_H */
|
#endif /* _EFI_LOADER_H */
|
||||||
|
|
|
@ -48,6 +48,9 @@ enum bootmenu_key {
|
||||||
KEY_DOWN,
|
KEY_DOWN,
|
||||||
KEY_SELECT,
|
KEY_SELECT,
|
||||||
KEY_QUIT,
|
KEY_QUIT,
|
||||||
|
KEY_PLUS,
|
||||||
|
KEY_MINUS,
|
||||||
|
KEY_SPACE,
|
||||||
};
|
};
|
||||||
|
|
||||||
void bootmenu_autoboot_loop(struct bootmenu_data *menu,
|
void bootmenu_autoboot_loop(struct bootmenu_data *menu,
|
||||||
|
|
|
@ -19,6 +19,9 @@
|
||||||
static const struct efi_boot_services *bs;
|
static const struct efi_boot_services *bs;
|
||||||
static const struct efi_runtime_services *rs;
|
static const struct efi_runtime_services *rs;
|
||||||
|
|
||||||
|
const efi_guid_t efi_guid_bootmenu_auto_generated =
|
||||||
|
EFICONFIG_AUTO_GENERATED_ENTRY_GUID;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* bootmgr implements the logic of trying to find a payload to boot
|
* bootmgr implements the logic of trying to find a payload to boot
|
||||||
* based on the BootOrder + BootXXXX variables, and then loading it.
|
* based on the BootOrder + BootXXXX variables, and then loading it.
|
||||||
|
@ -243,6 +246,10 @@ static efi_status_t try_load_entry(u16 n, efi_handle_t *handle,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set load options */
|
/* Set load options */
|
||||||
|
if (size >= sizeof(efi_guid_t) &&
|
||||||
|
!guidcmp(lo.optional_data, &efi_guid_bootmenu_auto_generated))
|
||||||
|
size = 0;
|
||||||
|
|
||||||
if (size) {
|
if (size) {
|
||||||
*load_options = malloc(size);
|
*load_options = malloc(size);
|
||||||
if (!*load_options) {
|
if (!*load_options) {
|
||||||
|
|
|
@ -2453,6 +2453,35 @@ static efi_status_t EFIAPI efi_protocols_per_handle(
|
||||||
return EFI_EXIT(EFI_SUCCESS);
|
return EFI_EXIT(EFI_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
efi_status_t efi_locate_handle_buffer_int(enum efi_locate_search_type search_type,
|
||||||
|
const efi_guid_t *protocol, void *search_key,
|
||||||
|
efi_uintn_t *no_handles, efi_handle_t **buffer)
|
||||||
|
{
|
||||||
|
efi_status_t r;
|
||||||
|
efi_uintn_t buffer_size = 0;
|
||||||
|
|
||||||
|
if (!no_handles || !buffer) {
|
||||||
|
r = EFI_INVALID_PARAMETER;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
*no_handles = 0;
|
||||||
|
*buffer = NULL;
|
||||||
|
r = efi_locate_handle(search_type, protocol, search_key, &buffer_size,
|
||||||
|
*buffer);
|
||||||
|
if (r != EFI_BUFFER_TOO_SMALL)
|
||||||
|
goto out;
|
||||||
|
r = efi_allocate_pool(EFI_BOOT_SERVICES_DATA, buffer_size,
|
||||||
|
(void **)buffer);
|
||||||
|
if (r != EFI_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
r = efi_locate_handle(search_type, protocol, search_key, &buffer_size,
|
||||||
|
*buffer);
|
||||||
|
if (r == EFI_SUCCESS)
|
||||||
|
*no_handles = buffer_size / sizeof(efi_handle_t);
|
||||||
|
out:
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* efi_locate_handle_buffer() - locate handles implementing a protocol
|
* efi_locate_handle_buffer() - locate handles implementing a protocol
|
||||||
* @search_type: selection criterion
|
* @search_type: selection criterion
|
||||||
|
@ -2474,30 +2503,13 @@ efi_status_t EFIAPI efi_locate_handle_buffer(
|
||||||
efi_uintn_t *no_handles, efi_handle_t **buffer)
|
efi_uintn_t *no_handles, efi_handle_t **buffer)
|
||||||
{
|
{
|
||||||
efi_status_t r;
|
efi_status_t r;
|
||||||
efi_uintn_t buffer_size = 0;
|
|
||||||
|
|
||||||
EFI_ENTRY("%d, %pUs, %p, %p, %p", search_type, protocol, search_key,
|
EFI_ENTRY("%d, %pUs, %p, %p, %p", search_type, protocol, search_key,
|
||||||
no_handles, buffer);
|
no_handles, buffer);
|
||||||
|
|
||||||
if (!no_handles || !buffer) {
|
r = efi_locate_handle_buffer_int(search_type, protocol, search_key,
|
||||||
r = EFI_INVALID_PARAMETER;
|
no_handles, buffer);
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
*no_handles = 0;
|
|
||||||
*buffer = NULL;
|
|
||||||
r = efi_locate_handle(search_type, protocol, search_key, &buffer_size,
|
|
||||||
*buffer);
|
|
||||||
if (r != EFI_BUFFER_TOO_SMALL)
|
|
||||||
goto out;
|
|
||||||
r = efi_allocate_pool(EFI_BOOT_SERVICES_DATA, buffer_size,
|
|
||||||
(void **)buffer);
|
|
||||||
if (r != EFI_SUCCESS)
|
|
||||||
goto out;
|
|
||||||
r = efi_locate_handle(search_type, protocol, search_key, &buffer_size,
|
|
||||||
*buffer);
|
|
||||||
if (r == EFI_SUCCESS)
|
|
||||||
*no_handles = buffer_size / sizeof(efi_handle_t);
|
|
||||||
out:
|
|
||||||
return EFI_EXIT(r);
|
return EFI_EXIT(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
#define LOG_CATEGORY LOGC_EFI
|
#define LOG_CATEGORY LOGC_EFI
|
||||||
|
|
||||||
|
#include <ansi.h>
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
#include <charset.h>
|
#include <charset.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
|
@ -1318,3 +1319,72 @@ out_of_memory:
|
||||||
printf("ERROR: Out of memory\n");
|
printf("ERROR: Out of memory\n");
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* efi_console_get_u16_string() - get user input string
|
||||||
|
*
|
||||||
|
* @cin: protocol interface to EFI_SIMPLE_TEXT_INPUT_PROTOCOL
|
||||||
|
* @buf: buffer to store user input string in UTF16
|
||||||
|
* @count: number of u16 string including NULL terminator that buf has
|
||||||
|
* @filter_func: callback to filter user input
|
||||||
|
* @row: row number to locate user input form
|
||||||
|
* @col: column number to locate user input form
|
||||||
|
* Return: status code
|
||||||
|
*/
|
||||||
|
efi_status_t efi_console_get_u16_string(struct efi_simple_text_input_protocol *cin,
|
||||||
|
u16 *buf, efi_uintn_t count,
|
||||||
|
efi_console_filter_func filter_func,
|
||||||
|
int row, int col)
|
||||||
|
{
|
||||||
|
efi_status_t ret;
|
||||||
|
efi_uintn_t len = 0;
|
||||||
|
struct efi_input_key key;
|
||||||
|
|
||||||
|
printf(ANSI_CURSOR_POSITION
|
||||||
|
ANSI_CLEAR_LINE_TO_END
|
||||||
|
ANSI_CURSOR_SHOW, row, col);
|
||||||
|
|
||||||
|
ret = EFI_CALL(cin->reset(cin, false));
|
||||||
|
if (ret != EFI_SUCCESS)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
do {
|
||||||
|
ret = EFI_CALL(cin->read_key_stroke(cin, &key));
|
||||||
|
mdelay(10);
|
||||||
|
} while (ret == EFI_NOT_READY);
|
||||||
|
|
||||||
|
if (key.unicode_char == u'\b') {
|
||||||
|
if (len > 0)
|
||||||
|
buf[--len] = u'\0';
|
||||||
|
|
||||||
|
printf(ANSI_CURSOR_POSITION
|
||||||
|
"%ls"
|
||||||
|
ANSI_CLEAR_LINE_TO_END, row, col, buf);
|
||||||
|
continue;
|
||||||
|
} else if (key.unicode_char == u'\r') {
|
||||||
|
buf[len] = u'\0';
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
} else if (key.unicode_char == 0x3 || key.scan_code == 23) {
|
||||||
|
return EFI_ABORTED;
|
||||||
|
} else if (key.unicode_char < 0x20) {
|
||||||
|
/* ignore control codes other than Ctrl+C, '\r' and '\b' */
|
||||||
|
continue;
|
||||||
|
} else if (key.scan_code != 0) {
|
||||||
|
/* only accept single ESC press for cancel */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filter_func) {
|
||||||
|
if (filter_func(&key) != EFI_SUCCESS)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len >= (count - 1))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
buf[len] = key.unicode_char;
|
||||||
|
len++;
|
||||||
|
printf(ANSI_CURSOR_POSITION "%ls", row, col, buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -760,3 +760,53 @@ efi_status_t efi_disk_init(void)
|
||||||
|
|
||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* efi_disk_get_device_name() - get U-Boot device name associated with EFI handle
|
||||||
|
*
|
||||||
|
* @handle: pointer to the EFI handle
|
||||||
|
* @buf: pointer to the buffer to store the string
|
||||||
|
* @size: size of buffer
|
||||||
|
* Return: status code
|
||||||
|
*/
|
||||||
|
efi_status_t efi_disk_get_device_name(const efi_handle_t handle, char *buf, int size)
|
||||||
|
{
|
||||||
|
int count;
|
||||||
|
int diskid;
|
||||||
|
enum uclass_id id;
|
||||||
|
unsigned int part;
|
||||||
|
struct udevice *dev;
|
||||||
|
struct blk_desc *desc;
|
||||||
|
const char *if_typename;
|
||||||
|
bool is_partition = false;
|
||||||
|
struct disk_part *part_data;
|
||||||
|
|
||||||
|
if (!handle || !buf || !size)
|
||||||
|
return EFI_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
dev = handle->dev;
|
||||||
|
id = device_get_uclass_id(dev);
|
||||||
|
if (id == UCLASS_BLK) {
|
||||||
|
desc = dev_get_uclass_plat(dev);
|
||||||
|
} else if (id == UCLASS_PARTITION) {
|
||||||
|
desc = dev_get_uclass_plat(dev_get_parent(dev));
|
||||||
|
is_partition = true;
|
||||||
|
} else {
|
||||||
|
return EFI_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
if_typename = blk_get_if_type_name(desc->if_type);
|
||||||
|
diskid = desc->devnum;
|
||||||
|
|
||||||
|
if (is_partition) {
|
||||||
|
part_data = dev_get_uclass_plat(dev);
|
||||||
|
part = part_data->partnum;
|
||||||
|
count = snprintf(buf, size, "%s %d:%d", if_typename, diskid, part);
|
||||||
|
} else {
|
||||||
|
count = snprintf(buf, size, "%s %d", if_typename, diskid);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count < 0 || (count + 1) > size)
|
||||||
|
return EFI_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
|
@ -246,10 +246,10 @@ error:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static efi_status_t efi_file_open_int(struct efi_file_handle *this,
|
efi_status_t efi_file_open_int(struct efi_file_handle *this,
|
||||||
struct efi_file_handle **new_handle,
|
struct efi_file_handle **new_handle,
|
||||||
u16 *file_name, u64 open_mode,
|
u16 *file_name, u64 open_mode,
|
||||||
u64 attributes)
|
u64 attributes)
|
||||||
{
|
{
|
||||||
struct file_handle *fh = to_fh(this);
|
struct file_handle *fh = to_fh(this);
|
||||||
efi_status_t ret;
|
efi_status_t ret;
|
||||||
|
@ -369,11 +369,17 @@ static efi_status_t file_close(struct file_handle *fh)
|
||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static efi_status_t EFIAPI efi_file_close(struct efi_file_handle *file)
|
efi_status_t efi_file_close_int(struct efi_file_handle *file)
|
||||||
{
|
{
|
||||||
struct file_handle *fh = to_fh(file);
|
struct file_handle *fh = to_fh(file);
|
||||||
|
|
||||||
|
return file_close(fh);
|
||||||
|
}
|
||||||
|
|
||||||
|
static efi_status_t EFIAPI efi_file_close(struct efi_file_handle *file)
|
||||||
|
{
|
||||||
EFI_ENTRY("%p", file);
|
EFI_ENTRY("%p", file);
|
||||||
return EFI_EXIT(file_close(fh));
|
return EFI_EXIT(efi_file_close_int(file));
|
||||||
}
|
}
|
||||||
|
|
||||||
static efi_status_t EFIAPI efi_file_delete(struct efi_file_handle *file)
|
static efi_status_t EFIAPI efi_file_delete(struct efi_file_handle *file)
|
||||||
|
@ -562,8 +568,8 @@ static efi_status_t dir_read(struct file_handle *fh, u64 *buffer_size,
|
||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static efi_status_t efi_file_read_int(struct efi_file_handle *this,
|
efi_status_t efi_file_read_int(struct efi_file_handle *this,
|
||||||
efi_uintn_t *buffer_size, void *buffer)
|
efi_uintn_t *buffer_size, void *buffer)
|
||||||
{
|
{
|
||||||
struct file_handle *fh = to_fh(this);
|
struct file_handle *fh = to_fh(this);
|
||||||
efi_status_t ret = EFI_SUCCESS;
|
efi_status_t ret = EFI_SUCCESS;
|
||||||
|
@ -773,24 +779,11 @@ out:
|
||||||
return EFI_EXIT(ret);
|
return EFI_EXIT(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
efi_status_t efi_file_setpos_int(struct efi_file_handle *file, u64 pos)
|
||||||
* efi_file_setpos() - set current position in file
|
|
||||||
*
|
|
||||||
* This function implements the SetPosition service of the EFI file protocol.
|
|
||||||
* See the UEFI spec for details.
|
|
||||||
*
|
|
||||||
* @file: file handle
|
|
||||||
* @pos: new file position
|
|
||||||
* Return: status code
|
|
||||||
*/
|
|
||||||
static efi_status_t EFIAPI efi_file_setpos(struct efi_file_handle *file,
|
|
||||||
u64 pos)
|
|
||||||
{
|
{
|
||||||
struct file_handle *fh = to_fh(file);
|
struct file_handle *fh = to_fh(file);
|
||||||
efi_status_t ret = EFI_SUCCESS;
|
efi_status_t ret = EFI_SUCCESS;
|
||||||
|
|
||||||
EFI_ENTRY("%p, %llu", file, pos);
|
|
||||||
|
|
||||||
if (fh->isdir) {
|
if (fh->isdir) {
|
||||||
if (pos != 0) {
|
if (pos != 0) {
|
||||||
ret = EFI_UNSUPPORTED;
|
ret = EFI_UNSUPPORTED;
|
||||||
|
@ -812,6 +805,28 @@ static efi_status_t EFIAPI efi_file_setpos(struct efi_file_handle *file,
|
||||||
fh->offset = pos;
|
fh->offset = pos;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* efi_file_setpos() - set current position in file
|
||||||
|
*
|
||||||
|
* This function implements the SetPosition service of the EFI file protocol.
|
||||||
|
* See the UEFI spec for details.
|
||||||
|
*
|
||||||
|
* @file: file handle
|
||||||
|
* @pos: new file position
|
||||||
|
* Return: status code
|
||||||
|
*/
|
||||||
|
static efi_status_t EFIAPI efi_file_setpos(struct efi_file_handle *file,
|
||||||
|
u64 pos)
|
||||||
|
{
|
||||||
|
efi_status_t ret = EFI_SUCCESS;
|
||||||
|
|
||||||
|
EFI_ENTRY("%p, %llu", file, pos);
|
||||||
|
|
||||||
|
ret = efi_file_setpos_int(file, pos);
|
||||||
|
|
||||||
return EFI_EXIT(ret);
|
return EFI_EXIT(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1138,17 +1153,23 @@ struct efi_file_handle *efi_file_from_path(struct efi_device_path *fp)
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
efi_status_t efi_open_volume_int(struct efi_simple_file_system_protocol *this,
|
||||||
|
struct efi_file_handle **root)
|
||||||
|
{
|
||||||
|
struct file_system *fs = to_fs(this);
|
||||||
|
|
||||||
|
*root = file_open(fs, NULL, NULL, 0, 0);
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static efi_status_t EFIAPI
|
static efi_status_t EFIAPI
|
||||||
efi_open_volume(struct efi_simple_file_system_protocol *this,
|
efi_open_volume(struct efi_simple_file_system_protocol *this,
|
||||||
struct efi_file_handle **root)
|
struct efi_file_handle **root)
|
||||||
{
|
{
|
||||||
struct file_system *fs = to_fs(this);
|
|
||||||
|
|
||||||
EFI_ENTRY("%p, %p", this, root);
|
EFI_ENTRY("%p, %p", this, root);
|
||||||
|
|
||||||
*root = file_open(fs, NULL, NULL, 0, 0);
|
return EFI_EXIT(efi_open_volume_int(this, root));
|
||||||
|
|
||||||
return EFI_EXIT(EFI_SUCCESS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct efi_simple_file_system_protocol *
|
struct efi_simple_file_system_protocol *
|
||||||
|
|
40
test/py/tests/test_eficonfig/conftest.py
Normal file
40
test/py/tests/test_eficonfig/conftest.py
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0+
|
||||||
|
|
||||||
|
"""Fixture for UEFI eficonfig test
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
from subprocess import check_call
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
@pytest.fixture(scope='session')
|
||||||
|
def efi_eficonfig_data(u_boot_config):
|
||||||
|
"""Set up a file system to be used in UEFI "eficonfig" command
|
||||||
|
tests
|
||||||
|
|
||||||
|
Args:
|
||||||
|
u_boot_config -- U-boot configuration.
|
||||||
|
|
||||||
|
Return:
|
||||||
|
A path to disk image to be used for testing
|
||||||
|
"""
|
||||||
|
mnt_point = u_boot_config.persistent_data_dir + '/test_efi_eficonfig'
|
||||||
|
image_path = u_boot_config.persistent_data_dir + '/efi_eficonfig.img'
|
||||||
|
|
||||||
|
shutil.rmtree(mnt_point, ignore_errors=True)
|
||||||
|
os.mkdir(mnt_point, mode = 0o755)
|
||||||
|
|
||||||
|
with open(mnt_point + '/initrd-1.img', 'w', encoding = 'ascii') as file:
|
||||||
|
file.write("initrd 1")
|
||||||
|
|
||||||
|
with open(mnt_point + '/initrd-2.img', 'w', encoding = 'ascii') as file:
|
||||||
|
file.write("initrd 2")
|
||||||
|
|
||||||
|
shutil.copyfile(u_boot_config.build_dir + '/lib/efi_loader/initrddump.efi',
|
||||||
|
mnt_point + '/initrddump.efi')
|
||||||
|
|
||||||
|
check_call(f'virt-make-fs --partition=gpt --size=+1M --type=vfat {mnt_point} {image_path}',
|
||||||
|
shell=True)
|
||||||
|
|
||||||
|
return image_path
|
354
test/py/tests/test_eficonfig/test_eficonfig.py
Normal file
354
test/py/tests/test_eficonfig/test_eficonfig.py
Normal file
|
@ -0,0 +1,354 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0+
|
||||||
|
""" Unit test for UEFI menu-driven configuration
|
||||||
|
"""
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
import time
|
||||||
|
|
||||||
|
@pytest.mark.boardspec('sandbox')
|
||||||
|
@pytest.mark.buildconfigspec('cmd_eficonfig')
|
||||||
|
@pytest.mark.buildconfigspec('cmd_bootefi_bootmgr')
|
||||||
|
def test_efi_eficonfig(u_boot_console, efi_eficonfig_data):
|
||||||
|
|
||||||
|
def send_user_input_and_wait(user_str, expect_str):
|
||||||
|
time.sleep(0.1) # TODO: does not work correctly without sleep
|
||||||
|
u_boot_console.run_command(cmd=user_str, wait_for_prompt=False,
|
||||||
|
wait_for_echo=True, send_nl=False)
|
||||||
|
u_boot_console.run_command(cmd='\x0d', wait_for_prompt=False,
|
||||||
|
wait_for_echo=False, send_nl=False)
|
||||||
|
if expect_str is not None:
|
||||||
|
for i in expect_str:
|
||||||
|
u_boot_console.p.expect([i])
|
||||||
|
|
||||||
|
def press_up_down_enter_and_wait(up_count, down_count, enter, expect_str):
|
||||||
|
# press UP key
|
||||||
|
for i in range(up_count):
|
||||||
|
u_boot_console.run_command(cmd='\x1b\x5b\x41', wait_for_prompt=False,
|
||||||
|
wait_for_echo=False, send_nl=False)
|
||||||
|
# press DOWN key
|
||||||
|
for i in range(down_count):
|
||||||
|
u_boot_console.run_command(cmd='\x1b\x5b\x42', wait_for_prompt=False,
|
||||||
|
wait_for_echo=False, send_nl=False)
|
||||||
|
# press ENTER if requested
|
||||||
|
if enter:
|
||||||
|
u_boot_console.run_command(cmd='\x0d', wait_for_prompt=False,
|
||||||
|
wait_for_echo=False, send_nl=False)
|
||||||
|
# wait expected output
|
||||||
|
if expect_str is not None:
|
||||||
|
for i in expect_str:
|
||||||
|
u_boot_console.p.expect([i])
|
||||||
|
|
||||||
|
def press_escape_key(wait_prompt):
|
||||||
|
u_boot_console.run_command(cmd='\x1b', wait_for_prompt=wait_prompt, wait_for_echo=False, send_nl=False)
|
||||||
|
|
||||||
|
def press_enter_key(wait_prompt):
|
||||||
|
u_boot_console.run_command(cmd='\x0d', wait_for_prompt=wait_prompt,
|
||||||
|
wait_for_echo=False, send_nl=False)
|
||||||
|
|
||||||
|
def check_current_is_maintenance_menu():
|
||||||
|
for i in ('UEFI Maintenance Menu', 'Add Boot Option', 'Edit Boot Option',
|
||||||
|
'Change Boot Order', 'Delete Boot Option', 'Quit'):
|
||||||
|
u_boot_console.p.expect([i])
|
||||||
|
|
||||||
|
""" Unit test for "eficonfig" command
|
||||||
|
The menu-driven interface is used to set up UEFI load options.
|
||||||
|
The bootefi bootmgr loads initrddump.efi as a payload.
|
||||||
|
The crc32 of the loaded initrd.img is checked
|
||||||
|
|
||||||
|
Args:
|
||||||
|
u_boot_console -- U-Boot console
|
||||||
|
efi__data -- Path to the disk image used for testing.
|
||||||
|
Test disk image has following files.
|
||||||
|
initrd-1.img
|
||||||
|
initrd-2.img
|
||||||
|
initrddump.efi
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Restart the system to clean the previous state
|
||||||
|
u_boot_console.restart_uboot()
|
||||||
|
|
||||||
|
with u_boot_console.temporary_timeout(500):
|
||||||
|
#
|
||||||
|
# Test Case 1: Check the menu is displayed
|
||||||
|
#
|
||||||
|
u_boot_console.run_command('eficonfig', wait_for_prompt=False)
|
||||||
|
for i in ('UEFI Maintenance Menu', 'Add Boot Option', 'Edit Boot Option',
|
||||||
|
'Change Boot Order', 'Delete Boot Option', 'Quit'):
|
||||||
|
u_boot_console.p.expect([i])
|
||||||
|
# Select "Add Boot Option"
|
||||||
|
press_enter_key(False)
|
||||||
|
for i in ('Add Boot Option', 'Description:', 'File', 'Initrd File', 'Optional Data',
|
||||||
|
'Save', 'Quit'):
|
||||||
|
u_boot_console.p.expect([i])
|
||||||
|
press_escape_key(False)
|
||||||
|
check_current_is_maintenance_menu()
|
||||||
|
# return to U-Boot console
|
||||||
|
press_escape_key(True)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Test Case 2: check auto generated media device entry
|
||||||
|
#
|
||||||
|
|
||||||
|
# bind the test disk image for succeeding tests
|
||||||
|
u_boot_console.run_command(cmd = f'host bind 0 {efi_eficonfig_data}')
|
||||||
|
|
||||||
|
u_boot_console.run_command('eficonfig', wait_for_prompt=False)
|
||||||
|
|
||||||
|
# Change the Boot Order
|
||||||
|
press_up_down_enter_and_wait(0, 2, True, 'Quit')
|
||||||
|
for i in ('host 0:1', 'Save', 'Quit'):
|
||||||
|
u_boot_console.p.expect([i])
|
||||||
|
# disable auto generated boot option for succeeding test
|
||||||
|
u_boot_console.run_command(cmd=' ', wait_for_prompt=False,
|
||||||
|
wait_for_echo=False, send_nl=False)
|
||||||
|
# Save the BootOrder
|
||||||
|
press_up_down_enter_and_wait(0, 1, True, None)
|
||||||
|
check_current_is_maintenance_menu()
|
||||||
|
|
||||||
|
#
|
||||||
|
# Test Case 3: Add first Boot Option and load it
|
||||||
|
#
|
||||||
|
|
||||||
|
# Select 'Add Boot Option'
|
||||||
|
press_up_down_enter_and_wait(0, 0, True, 'Quit')
|
||||||
|
|
||||||
|
# Press the enter key to select 'Description:' entry, then enter Description
|
||||||
|
press_up_down_enter_and_wait(0, 0, True, 'enter description:')
|
||||||
|
# Send Description user input, press ENTER key to complete
|
||||||
|
send_user_input_and_wait('test 1', 'Quit')
|
||||||
|
|
||||||
|
# Set EFI image(initrddump.efi)
|
||||||
|
press_up_down_enter_and_wait(0, 1, True, 'Quit')
|
||||||
|
press_up_down_enter_and_wait(0, 0, True, 'host 0:1')
|
||||||
|
# Select 'host 0:1'
|
||||||
|
press_up_down_enter_and_wait(0, 0, True, 'Quit')
|
||||||
|
# Press down key to select "initrddump.efi" entry followed by the enter key
|
||||||
|
press_up_down_enter_and_wait(0, 2, True, 'Quit')
|
||||||
|
|
||||||
|
# Set Initrd file(initrd-1.img)
|
||||||
|
press_up_down_enter_and_wait(0, 2, True, 'Quit')
|
||||||
|
press_up_down_enter_and_wait(0, 0, True, 'host 0:1')
|
||||||
|
# Select 'host 0:1'
|
||||||
|
press_up_down_enter_and_wait(0, 0, True, 'Quit')
|
||||||
|
# Press down key to select "initrd-1.img" entry followed by the enter key
|
||||||
|
press_up_down_enter_and_wait(0, 0, True, 'Quit')
|
||||||
|
|
||||||
|
# Set optional_data
|
||||||
|
press_up_down_enter_and_wait(0, 3, True, 'Optional Data:')
|
||||||
|
# Send Description user input, press ENTER key to complete
|
||||||
|
send_user_input_and_wait('nocolor', None)
|
||||||
|
for i in ('Description: test 1', 'File: host 0:1/initrddump.efi',
|
||||||
|
'Initrd File: host 0:1/initrd-1.img', 'Optional Data: nocolor', 'Save', 'Quit'):
|
||||||
|
u_boot_console.p.expect([i])
|
||||||
|
|
||||||
|
# Save the Boot Option
|
||||||
|
press_up_down_enter_and_wait(0, 4, True, None)
|
||||||
|
check_current_is_maintenance_menu()
|
||||||
|
|
||||||
|
# Check the newly added Boot Option is handled correctly
|
||||||
|
# Return to U-Boot console
|
||||||
|
press_escape_key(True)
|
||||||
|
u_boot_console.run_command(cmd = 'bootefi bootmgr')
|
||||||
|
response = u_boot_console.run_command(cmd = 'load', wait_for_echo=False)
|
||||||
|
assert 'crc32: 0x181464af' in response
|
||||||
|
u_boot_console.run_command(cmd = 'exit', wait_for_echo=False)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Test Case 4: Add second Boot Option and load it
|
||||||
|
#
|
||||||
|
u_boot_console.run_command('eficonfig', wait_for_prompt=False)
|
||||||
|
|
||||||
|
# Select 'Add Boot Option'
|
||||||
|
press_up_down_enter_and_wait(0, 0, True, 'Quit')
|
||||||
|
|
||||||
|
# Press the enter key to select 'Description:' entry, then enter Description
|
||||||
|
press_up_down_enter_and_wait(0, 0, True, 'enter description:')
|
||||||
|
# Send Description user input, press ENTER key to complete
|
||||||
|
send_user_input_and_wait('test 2', 'Quit')
|
||||||
|
|
||||||
|
# Set EFI image(initrddump.efi)
|
||||||
|
press_up_down_enter_and_wait(0, 1, True, 'Quit')
|
||||||
|
press_up_down_enter_and_wait(0, 0, True, 'host 0:1')
|
||||||
|
# Select 'host 0:1'
|
||||||
|
press_up_down_enter_and_wait(0, 0, True, 'Quit')
|
||||||
|
# Press down key to select "initrddump.efi" entry followed by the enter key
|
||||||
|
press_up_down_enter_and_wait(0, 2, True, 'Quit')
|
||||||
|
|
||||||
|
# Set Initrd file(initrd-2.img)
|
||||||
|
press_up_down_enter_and_wait(0, 2, True, 'Quit')
|
||||||
|
press_up_down_enter_and_wait(0, 0, True, 'host 0:1')
|
||||||
|
# Select 'host 0:1'
|
||||||
|
press_up_down_enter_and_wait(0, 0, True, 'Quit')
|
||||||
|
# Press down key to select "initrd-2.img" entry followed by the enter key
|
||||||
|
press_up_down_enter_and_wait(0, 1, True, 'Quit')
|
||||||
|
|
||||||
|
# Set optional_data
|
||||||
|
press_up_down_enter_and_wait(0, 3, True, 'Optional Data:')
|
||||||
|
# Send Description user input, press ENTER key to complete
|
||||||
|
send_user_input_and_wait('nocolor', None)
|
||||||
|
for i in ('Description: test 2', 'File: host 0:1/initrddump.efi',
|
||||||
|
'Initrd File: host 0:1/initrd-2.img', 'Optional Data: nocolor', 'Save', 'Quit'):
|
||||||
|
u_boot_console.p.expect([i])
|
||||||
|
|
||||||
|
# Save the Boot Option
|
||||||
|
press_up_down_enter_and_wait(0, 4, True, 'Quit')
|
||||||
|
|
||||||
|
# Change the Boot Order
|
||||||
|
press_up_down_enter_and_wait(0, 2, True, 'Quit')
|
||||||
|
press_up_down_enter_and_wait(0, 1, False, 'Quit')
|
||||||
|
# move 'test 1' to the second entry
|
||||||
|
u_boot_console.run_command(cmd='+', wait_for_prompt=False,
|
||||||
|
wait_for_echo=False, send_nl=False)
|
||||||
|
for i in ('test 2', 'test 1', 'host 0:1', 'Save', 'Quit'):
|
||||||
|
u_boot_console.p.expect([i])
|
||||||
|
# Save the BootOrder
|
||||||
|
press_up_down_enter_and_wait(0, 3, True, None)
|
||||||
|
check_current_is_maintenance_menu()
|
||||||
|
|
||||||
|
# Check the newly added Boot Option is handled correctly
|
||||||
|
# Return to U-Boot console
|
||||||
|
press_escape_key(True)
|
||||||
|
u_boot_console.run_command(cmd = 'bootefi bootmgr')
|
||||||
|
response = u_boot_console.run_command(cmd = 'load', wait_for_echo=False)
|
||||||
|
assert 'crc32: 0x811d3515' in response
|
||||||
|
u_boot_console.run_command(cmd = 'exit', wait_for_echo=False)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Test Case 5: Change BootOrder and load it
|
||||||
|
#
|
||||||
|
u_boot_console.run_command('eficonfig', wait_for_prompt=False)
|
||||||
|
|
||||||
|
# Change the Boot Order
|
||||||
|
press_up_down_enter_and_wait(0, 2, True, None)
|
||||||
|
# Check the curren BootOrder
|
||||||
|
for i in ('test 2', 'test 1', 'host 0:1', 'Save', 'Quit'):
|
||||||
|
u_boot_console.p.expect([i])
|
||||||
|
# move 'test 2' to the second entry
|
||||||
|
u_boot_console.run_command(cmd='-', wait_for_prompt=False,
|
||||||
|
wait_for_echo=False, send_nl=False)
|
||||||
|
for i in ('test 1', 'test 2', 'host 0:1', 'Save', 'Quit'):
|
||||||
|
u_boot_console.p.expect([i])
|
||||||
|
# Save the BootOrder
|
||||||
|
press_up_down_enter_and_wait(0, 2, True, None)
|
||||||
|
check_current_is_maintenance_menu()
|
||||||
|
|
||||||
|
# Return to U-Boot console
|
||||||
|
press_escape_key(True)
|
||||||
|
u_boot_console.run_command(cmd = 'bootefi bootmgr')
|
||||||
|
response = u_boot_console.run_command(cmd = 'load', wait_for_echo=False)
|
||||||
|
assert 'crc32: 0x181464af' in response
|
||||||
|
u_boot_console.run_command(cmd = 'exit', wait_for_echo=False)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Test Case 6: Delete Boot Option(label:test 2)
|
||||||
|
#
|
||||||
|
u_boot_console.run_command('eficonfig', wait_for_prompt=False)
|
||||||
|
|
||||||
|
# Select 'Delete Boot Option'
|
||||||
|
press_up_down_enter_and_wait(0, 3, True, None)
|
||||||
|
# Check the current BootOrder
|
||||||
|
for i in ('test 1', 'test 2', 'Quit'):
|
||||||
|
u_boot_console.p.expect([i])
|
||||||
|
|
||||||
|
# Delete 'test 2'
|
||||||
|
press_up_down_enter_and_wait(0, 1, True, None)
|
||||||
|
for i in ('test 1', 'Quit'):
|
||||||
|
u_boot_console.p.expect([i])
|
||||||
|
press_escape_key(False)
|
||||||
|
check_current_is_maintenance_menu()
|
||||||
|
# Return to U-Boot console
|
||||||
|
press_escape_key(True)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Test Case 7: Edit Boot Option
|
||||||
|
#
|
||||||
|
u_boot_console.run_command('eficonfig', wait_for_prompt=False)
|
||||||
|
# Select 'Edit Boot Option'
|
||||||
|
press_up_down_enter_and_wait(0, 1, True, None)
|
||||||
|
# Check the curren BootOrder
|
||||||
|
for i in ('test 1', 'Quit'):
|
||||||
|
u_boot_console.p.expect([i])
|
||||||
|
press_up_down_enter_and_wait(0, 0, True, None)
|
||||||
|
for i in ('Description: test 1', 'File: host 0:1/initrddump.efi',
|
||||||
|
'Initrd File: host 0:1/initrd-1.img', 'Optional Data: nocolor', 'Save', 'Quit'):
|
||||||
|
u_boot_console.p.expect([i])
|
||||||
|
|
||||||
|
# Press the enter key to select 'Description:' entry, then enter Description
|
||||||
|
press_up_down_enter_and_wait(0, 0, True, 'enter description:')
|
||||||
|
# Send Description user input, press ENTER key to complete
|
||||||
|
send_user_input_and_wait('test 3', 'Quit')
|
||||||
|
|
||||||
|
# Set EFI image(initrddump.efi)
|
||||||
|
press_up_down_enter_and_wait(0, 1, True, 'Quit')
|
||||||
|
press_up_down_enter_and_wait(0, 0, True, 'host 0:1')
|
||||||
|
# Select 'host 0:1'
|
||||||
|
press_up_down_enter_and_wait(0, 0, True, 'Quit')
|
||||||
|
# Press down key to select "initrddump.efi" entry followed by the enter key
|
||||||
|
press_up_down_enter_and_wait(0, 2, True, 'Quit')
|
||||||
|
|
||||||
|
# Set Initrd file(initrd-2.img)
|
||||||
|
press_up_down_enter_and_wait(0, 2, True, 'Quit')
|
||||||
|
press_up_down_enter_and_wait(0, 0, True, 'host 0:1')
|
||||||
|
# Select 'host 0:1'
|
||||||
|
press_up_down_enter_and_wait(0, 0, True, 'Quit')
|
||||||
|
# Press down key to select "initrd-1.img" entry followed by the enter key
|
||||||
|
press_up_down_enter_and_wait(0, 1, True, 'Quit')
|
||||||
|
|
||||||
|
# Set optional_data
|
||||||
|
press_up_down_enter_and_wait(0, 3, True, 'Optional Data:')
|
||||||
|
# Send Description user input, press ENTER key to complete
|
||||||
|
send_user_input_and_wait('', None)
|
||||||
|
for i in ('Description: test 3', 'File: host 0:1/initrddump.efi',
|
||||||
|
'Initrd File: host 0:1/initrd-2.img', 'Optional Data:', 'Save', 'Quit'):
|
||||||
|
u_boot_console.p.expect([i])
|
||||||
|
|
||||||
|
# Save the Boot Option
|
||||||
|
press_up_down_enter_and_wait(0, 4, True, 'Quit')
|
||||||
|
press_escape_key(False)
|
||||||
|
check_current_is_maintenance_menu()
|
||||||
|
|
||||||
|
# Check the updated Boot Option is handled correctly
|
||||||
|
# Return to U-Boot console
|
||||||
|
press_escape_key(True)
|
||||||
|
u_boot_console.run_command(cmd = 'bootefi bootmgr')
|
||||||
|
response = u_boot_console.run_command(cmd = 'load', wait_for_echo=False)
|
||||||
|
assert 'crc32: 0x811d3515' in response
|
||||||
|
u_boot_console.run_command(cmd = 'exit', wait_for_echo=False)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Test Case 8: Delete Boot Option(label:test 3)
|
||||||
|
#
|
||||||
|
u_boot_console.run_command('eficonfig', wait_for_prompt=False)
|
||||||
|
|
||||||
|
# Select 'Delete Boot Option'
|
||||||
|
press_up_down_enter_and_wait(0, 3, True, None)
|
||||||
|
# Check the curren BootOrder
|
||||||
|
for i in ('test 3', 'Quit'):
|
||||||
|
u_boot_console.p.expect([i])
|
||||||
|
|
||||||
|
# Delete 'test 3'
|
||||||
|
press_up_down_enter_and_wait(0, 0, True, 'Quit')
|
||||||
|
press_escape_key(False)
|
||||||
|
check_current_is_maintenance_menu()
|
||||||
|
# Return to U-Boot console
|
||||||
|
press_escape_key(True)
|
||||||
|
|
||||||
|
# remove the host device
|
||||||
|
u_boot_console.run_command(cmd = f'host bind -r 0')
|
||||||
|
|
||||||
|
#
|
||||||
|
# Test Case 9: No block device found
|
||||||
|
#
|
||||||
|
u_boot_console.run_command('eficonfig', wait_for_prompt=False)
|
||||||
|
|
||||||
|
# Select 'Add Boot Option'
|
||||||
|
press_up_down_enter_and_wait(0, 0, True, 'Quit')
|
||||||
|
|
||||||
|
# Set EFI image
|
||||||
|
press_up_down_enter_and_wait(0, 1, True, 'Quit')
|
||||||
|
press_up_down_enter_and_wait(0, 0, True, 'No block device found!')
|
||||||
|
press_escape_key(False)
|
||||||
|
check_current_is_maintenance_menu()
|
||||||
|
# Return to U-Boot console
|
||||||
|
press_escape_key(True)
|
Loading…
Reference in a new issue