提交 3053b781 编写于 作者: T Tom Rini

Merge tag 'efi-2022-07-rc4-3' of https://source.denx.de/u-boot/custodians/u-boot-efi

Pull request for efi-2022-07-rc4-3

UEFI:

* fix a problem in loading an image from a short-path
* fix building the bootmenu command for CONFIG_EFI_LOADER=n
* correct the bootefi command syntax
* add firmware management protocol to the documentation

Others:

* bootmenu: fix bootmenu title handling

Tested-by: Pali Rohár <pali@kernel.org> [n900, for bootmenu working as before]
......@@ -305,6 +305,7 @@ config TPL_SYS_MALLOC_F_LEN
config VALGRIND
bool "Inform valgrind about memory allocations"
depends on !RISCV
help
Valgrind is an instrumentation framework for building dynamic analysis
tools. In particular, it may be used to detect memory management bugs
......
......@@ -1143,6 +1143,13 @@ config AUTOBOOT_MENU_SHOW
environmnent variable (if enabled) and before handling the boot delay.
See README.bootmenu for more details.
config BOOTMENU_DISABLE_UBOOT_CONSOLE
bool "Disallow bootmenu to enter the U-Boot console"
depends on AUTOBOOT_MENU_SHOW
help
If this option is enabled, user can not enter the U-Boot console from
bootmenu. It increases the system security.
config BOOT_RETRY
bool "Boot retry feature"
help
......
......@@ -357,16 +357,6 @@ config CMD_BOOTMENU
help
Add an ANSI terminal boot menu command.
config CMD_BOOTMENU_ENTER_UBOOT_CONSOLE
bool "Allow Bootmenu to enter the U-Boot console"
depends on CMD_BOOTMENU
default n
help
Add an entry to enter U-Boot console in bootmenu.
If this option is disabled, user can not enter
the U-Boot console from bootmenu. It increases
the system security.
config CMD_ADTIMG
bool "adtimg"
help
......
......@@ -649,6 +649,7 @@ static int do_bootefi(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
efi_status_t ret;
char *img_addr, *img_size, *str_copy, *pos;
void *fdt;
if (argc < 2)
......@@ -662,7 +663,7 @@ static int do_bootefi(struct cmd_tbl *cmdtp, int flag, int argc,
return CMD_RET_FAILURE;
}
if (argc > 2 && strcmp(argv[2], "-")) {
if (argc > 2) {
uintptr_t fdt_addr;
fdt_addr = hextoul(argv[2], NULL);
......@@ -684,16 +685,24 @@ static int do_bootefi(struct cmd_tbl *cmdtp, int flag, int argc,
if (!strcmp(argv[1], "selftest"))
return do_efi_selftest();
#endif
str_copy = strdup(argv[1]);
if (!str_copy) {
log_err("Out of memory\n");
return CMD_RET_FAILURE;
}
pos = str_copy;
img_addr = strsep(&pos, ":");
img_size = strsep(&pos, ":");
ret = do_bootefi_image(img_addr, img_size);
free(str_copy);
return do_bootefi_image(argv[1], argc > 3 ? argv[3] : NULL);
return ret;
}
#ifdef CONFIG_SYS_LONGHELP
static char bootefi_help_text[] =
"<image address> [fdt address [image size]]\n"
" - boot EFI payload stored at <image address>\n"
" fdt address, address of device-tree or '-'\n"
" image size, required if image not preloaded\n"
"<image address>[:<image size>] [<fdt address>]\n"
" - boot EFI payload\n"
#ifdef CONFIG_CMD_BOOTEFI_HELLO
"bootefi hello\n"
" - boot a sample Hello World application stored within U-Boot\n"
......
......@@ -43,7 +43,7 @@ enum boot_type {
struct bootmenu_entry {
unsigned short int num; /* unique number 0 .. MAX_COUNT */
char key[3]; /* key identifier of number */
u16 *title; /* title of entry */
char *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 */
......@@ -76,7 +76,7 @@ static void bootmenu_print_entry(void *data)
if (reverse)
puts(ANSI_COLOR_REVERSE);
printf("%ls", entry->title);
printf("%s", entry->title);
if (reverse)
puts(ANSI_COLOR_RESET);
......@@ -162,7 +162,6 @@ static int prepare_bootmenu_entry(struct bootmenu_data *menu,
struct bootmenu_entry **current,
unsigned short int *index)
{
int len;
char *sep;
const char *option;
unsigned short int i = *index;
......@@ -170,8 +169,8 @@ static int prepare_bootmenu_entry(struct bootmenu_data *menu,
struct bootmenu_entry *iter = *current;
while ((option = bootmenu_getoption(i))) {
u16 *buf;
/* bootmenu_[num] format is "[title]=[commands]" */
sep = strchr(option, '=');
if (!sep) {
printf("Invalid bootmenu entry: %s\n", option);
......@@ -182,24 +181,18 @@ static int prepare_bootmenu_entry(struct bootmenu_data *menu,
if (!entry)
return -ENOMEM;
len = sep-option;
buf = calloc(1, (len + 1) * sizeof(u16));
entry->title = buf;
entry->title = strndup(option, sep - option);
if (!entry->title) {
free(entry);
return -ENOMEM;
}
utf8_utf16_strncpy(&buf, option, len);
len = strlen(sep + 1);
entry->command = malloc(len + 1);
entry->command = strdup(sep + 1);
if (!entry->command) {
free(entry->title);
free(entry);
return -ENOMEM;
}
memcpy(entry->command, sep + 1, len);
entry->command[len] = 0;
sprintf(entry->key, "%d", i);
......@@ -227,6 +220,7 @@ static int prepare_bootmenu_entry(struct bootmenu_data *menu,
return 1;
}
#if (CONFIG_IS_ENABLED(CMD_BOOTEFI_BOOTMGR))
/**
* prepare_uefi_bootorder_entry() - generate the uefi bootmenu entries
*
......@@ -279,13 +273,17 @@ static int prepare_uefi_bootorder_entry(struct bootmenu_data *menu,
}
if (lo.attributes & LOAD_OPTION_ACTIVE) {
entry->title = u16_strdup(lo.label);
if (!entry->title) {
char *buf;
buf = calloc(1, utf16_utf8_strlen(lo.label) + 1);
if (!buf) {
free(load_option);
free(entry);
free(bootorder);
return -ENOMEM;
}
entry->title = buf;
utf16_utf8_strncpy(&buf, lo.label, u16_strlen(lo.label));
entry->command = strdup("bootefi bootmgr");
sprintf(entry->key, "%d", i);
entry->num = i;
......@@ -315,6 +313,7 @@ static int prepare_uefi_bootorder_entry(struct bootmenu_data *menu,
return 1;
}
#endif
static struct bootmenu_data *bootmenu_create(int delay)
{
......@@ -341,13 +340,13 @@ static struct bootmenu_data *bootmenu_create(int delay)
if (ret < 0)
goto cleanup;
if (IS_ENABLED(CONFIG_CMD_BOOTEFI_BOOTMGR)) {
if (i < MAX_COUNT - 1) {
#if (CONFIG_IS_ENABLED(CMD_BOOTEFI_BOOTMGR))
if (i < MAX_COUNT - 1) {
ret = prepare_uefi_bootorder_entry(menu, &iter, &i);
if (ret < 0 && ret != -ENOENT)
goto cleanup;
}
}
#endif
/* Add U-Boot console entry at the end */
if (i <= MAX_COUNT - 1) {
......@@ -356,10 +355,10 @@ static struct bootmenu_data *bootmenu_create(int delay)
goto cleanup;
/* 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");
if (!IS_ENABLED(CONFIG_BOOTMENU_DISABLE_UBOOT_CONSOLE))
entry->title = strdup("U-Boot console");
else
entry->title = u16_strdup(u"Quit");
entry->title = strdup("Quit");
if (!entry->title) {
free(entry);
......@@ -461,7 +460,7 @@ static enum bootmenu_ret bootmenu_show(int delay)
int cmd_ret;
int init = 0;
void *choice = NULL;
u16 *title = NULL;
char *title = NULL;
char *command = NULL;
struct menu *menu;
struct bootmenu_entry *iter;
......@@ -517,7 +516,7 @@ static enum bootmenu_ret bootmenu_show(int delay)
if (menu_get_choice(menu, &choice) == 1) {
iter = choice;
title = u16_strdup(iter->title);
title = strdup(iter->title);
command = strdup(iter->command);
/* last entry is U-Boot console or Quit */
......@@ -561,7 +560,7 @@ cleanup:
}
if (title && command) {
debug("Starting entry '%ls'\n", title);
debug("Starting entry '%s'\n", title);
free(title);
if (efi_ret == EFI_SUCCESS)
cmd_ret = run_command(command, 0);
......@@ -589,7 +588,7 @@ int menu_show(int bootdelay)
if (ret == BOOTMENU_RET_UPDATED)
continue;
if (!IS_ENABLED(CONFIG_CMD_BOOTMENU_ENTER_UBOOT_CONSOLE)) {
if (IS_ENABLED(CONFIG_BOOTMENU_DISABLE_UBOOT_CONSOLE)) {
if (ret == BOOTMENU_RET_QUIT) {
/* default boot process */
if (IS_ENABLED(CONFIG_CMD_BOOTEFI_BOOTMGR))
......
......@@ -1061,10 +1061,8 @@ static int is_gpt_valid(struct blk_desc *dev_desc, u64 lba,
/* Read and allocate Partition Table Entries */
*pgpt_pte = alloc_read_gpt_entries(dev_desc, pgpt_head);
if (*pgpt_pte == NULL) {
printf("GPT: Failed to allocate memory for PTE\n");
if (!*pgpt_pte)
return 0;
}
if (validate_gpt_entries(pgpt_head, *pgpt_pte)) {
free(*pgpt_pte);
......
......@@ -166,6 +166,12 @@ Unicode Collation protocol
.. kernel-doc:: lib/efi_loader/efi_unicode_collation.c
:internal:
Firmware management protocol
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. kernel-doc:: lib/efi_loader/efi_firmware.c
:internal:
Unit testing
------------
......
......@@ -143,7 +143,7 @@ UBOOT_SB_TIME_OFFSET
Memory Emulation
----------------
Memory emulation is supported, with the size set by CONFIG_SYS_SDRAM_SIZE.
Memory emulation is supported, with the size set by CONFIG_SANDBOX_RAM_SIZE_MB.
The -m option can be used to read memory from a file on start-up and write
it when shutting down. This allows preserving of memory contents across
test runs. You can tell U-Boot to remove the memory file after it is read
......@@ -477,6 +477,9 @@ board_init_f() and board_init_r().
This approach can be used on normal boards as well as sandbox.
For debugging with GDB or LLDB, it is preferable to reduce the compiler
optimization level (CONFIG_CC_OPTIMIZE_FOR_DEBUG=y) and to disable Link Time
Optimization (CONFIG_LTO=n).
SDL_CONFIG
----------
......@@ -492,18 +495,104 @@ It is possible to run U-Boot under valgrind to check memory allocations::
valgrind ./u-boot
For more detailed results, enable `CONFIG_VALGRIND`. There are many false
positives due to `malloc` itself. Suppress these with::
However, this does not give very useful results. The sandbox allocates a memory
pool via mmap(). U-Boot's internal malloc() and free() work on this memory pool.
Custom allocators and deallocators are invisible to valgrind by default. To
expose U-Boot's malloc() and free() to valgrind, enable ``CONFIG_VALGRIND``.
Enabling this option will inject placeholder assembler code which valgrind
interprets. This is used to annotate sections of memory as safe or unsafe, and
to inform valgrind about malloc()s and free()s. There are currently no standard
placeholder assembly sequences for RISC-V, so this option cannot be enabled on
that architecture.
Malloc's bookkeeping information is marked as unsafe by default. However, this
will generate many false positives when malloc itself accesses this information.
These warnings can be suppressed with::
valgrind --suppressions=scripts/u-boot.supp ./u-boot
If you are running sandbox SPL or TPL, then valgrind will not by default
notice when U-Boot jumps from TPL to SPL, or from SPL to U-Boot proper. To
fix this, use `--trace-children=yes`. To show who alloc'd some troublesome
memory, use `--track-origins=yes`. To uncover possible errors, try running all
unit tests with::
Additionally, you may experience false positives if U-Boot is using a smaller
pointer size than your host architecture. This is because the pointers used by
U-Boot will only contain 32 bits of addressing information. When interpreted as
64-bit pointers, valgrind will think that they are not initialized properly. To
fix this, enable ``CONFIG_SANDBOX64`` (such as via ``sandbox64_defconfig``)
when running on a 64-bit host.
Additional options
^^^^^^^^^^^^^^^^^^
The following valgrind options are useful in addition to the above examples:
``--trace-childen=yes``
tells valgrind to keep tracking subprocesses, such
as when U-Boot jumps from TPL to SPL, or from SPL to U-Boot proper.
``--track-origins=yes``
will (for a small overhead) tell valgrind to keep
track of who allocated some troublesome memory.
``--error-limit``
will enable printing more than 1000 errors in a single session.
``--vgdb=yes --vgdb-error=0``
will let you use GDB to attach like::
gdb -ex "target remote | vgdb" u-boot
This is very helpful for inspecting the program state when there is
an error.
The following U-Boot option are also helpful:
``-Tc 'ut all'``
lets U-Boot run unit tests automatically. Note
that not all unit tests will succeed in the default configuration.
``-t cooked``
will keep the console in a sane state if you
terminate it early (instead of having to run tset).
Future work
^^^^^^^^^^^
The biggest limitation to the current approach is that supressions don't
"un-taint" uninitialized memory accesses. Currently, dlmalloc's bookkeeping
information is marked as a "red zone." This means that all reads to that zone
are marked as illegal by valgrind. This is fine for regular code, but dlmalloc
really does need to access this area, so we suppress its violations. However, if
dlmalloc then passes a result calculated from a "tainted" access, that result is
still tainted. So the first accessor will raise a warning. This means that every
construct like
.. code-block::
foo = malloc(sizeof(*foo));
if (!foo)
return -ENOMEM;
will raise a warning when we check the result of malloc. Whoops.
There are at least four possible ways to address this:
* Don't mark dlmalloc bookkeeping information as a red zone. This is the
simplest solution, but reduces the power of valgrind immensely, since we can
no longer determine that (e.g.) access past the end of an array is undefined.
* Implement red zones properly. This would involve growing every allocation by a
fixed amount (16 bytes or so) and then using that extra space for a real red
zone that neither regular code nor dlmalloc needs to access. Unfortunately,
this would probably some fairly intensive surgery to dlmalloc to add/remove
the offset appropriately.
* Mark bookkeeping information as valid before we use it in dlmalloc, and then
mark it invalid before returning. This would be the most correct, but it would
be very tricky to implement since there are so many code paths to mark. I
think it would be the most effort out of the three options here.
* Use the host malloc and free instead of U-Boot's custom allocator. This will
eliminate the need to annotate dlmalloc. However, using a different allocator
for sandbox will mean that bugs in dlmalloc will only be tested when running
on read (or emulated) hardware.
valgrind --track-origins=yes --suppressions=scripts/u-boot.supp ./u-boot -Tc 'ut all'
Until one of the above options are implemented, it will remain difficult
to sift through the massive amount of spurious warnings.
Testing
-------
......
......@@ -27,10 +27,10 @@ Depending on the build targets further packages maybe needed
device-tree-compiler dfu-util efitools flex gdisk graphviz imagemagick \
liblz4-tool libgnutls28-dev libguestfs-tools libncurses-dev \
libpython3-dev libsdl2-dev libssl-dev lz4 lzma lzma-alone openssl \
pkg-config python3 python3-coverage python3-pkg-resources \
python3-pycryptodome python3-pyelftools python3-pytest \
python3-sphinxcontrib.apidoc python3-sphinx-rtd-theme python3-virtualenv \
swig
pkg-config python3 python3-asteval python3-coverage \
python3-pkg-resources python3-pycryptodome python3-pyelftools \
python3-pytest python3-sphinxcontrib.apidoc python3-sphinx-rtd-theme \
python3-subunit python3-testtools python3-virtualenv swig
SUSE based
~~~~~~~~~~
......
......@@ -9,10 +9,10 @@ Synopsis
::
bootefi [image_addr] [fdt_addr [image_size]]
bootefi bootmgr [fdt_addr]
bootefi hello [fdt_addr]
bootefi selftest [fdt_addr]
bootefi <image_addr>[:<image_size>] [<fdt_addr>]
bootefi bootmgr [<fdt_addr>]
bootefi hello [<fdt_addr>]
bootefi selftest [<fdt_addr>]
Description
-----------
......
......@@ -273,7 +273,7 @@ u16 *u16_strdup(const void *src);
* 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);
size_t u16_strlcat(u16 *dest, const u16 *src, size_t count);
/**
* utf16_to_utf8() - Convert an utf16 string to utf8
......
......@@ -663,6 +663,9 @@ efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type,
/* Call this to signal an event */
void efi_signal_event(struct efi_event *event);
/* return true if the device is removable */
bool efi_disk_is_removable(efi_handle_t handle);
/* open file system: */
struct efi_simple_file_system_protocol *efi_simple_file_system(
struct blk_desc *desc, int part, struct efi_device_path *dp);
......
......@@ -76,6 +76,100 @@ struct efi_device_path *expand_media_path(struct efi_device_path *device_path)
return full_path;
}
/**
* try_load_from_file_path() - try to load a file
*
* Given a file media path iterate through a list of handles and try to
* to load the file from each of them until the first success.
*
* @fs_handles: array of handles with the simple file protocol
* @num: number of handles in fs_handles
* @fp: file path to open
* @handle: on return pointer to handle for loaded image
* @removable: if true only consider removable media, else only non-removable
*/
static efi_status_t try_load_from_file_path(efi_handle_t *fs_handles,
efi_uintn_t num,
struct efi_device_path *fp,
efi_handle_t *handle,
bool removable)
{
struct efi_handler *handler;
struct efi_device_path *dp;
int i;
efi_status_t ret;
for (i = 0; i < num; i++) {
if (removable != efi_disk_is_removable(fs_handles[i]))
continue;
ret = efi_search_protocol(fs_handles[i], &efi_guid_device_path,
&handler);
if (ret != EFI_SUCCESS)
continue;
dp = handler->protocol_interface;
if (!dp)
continue;
dp = efi_dp_append(dp, fp);
if (!dp)
continue;
ret = EFI_CALL(efi_load_image(true, efi_root, dp, NULL, 0,
handle));
efi_free_pool(dp);
if (ret == EFI_SUCCESS)
return ret;
}
return EFI_NOT_FOUND;
}
/**
* try_load_from_short_path
* @fp: file path
* @handle: pointer to handle for newly installed image
*
* Enumerate all the devices which support file system operations,
* prepend its media device path to the file path, @fp, and
* try to load the file.
* This function should be called when handling a short-form path
* which is starting with a file device path.
*
* Return: status code
*/
static efi_status_t try_load_from_short_path(struct efi_device_path *fp,
efi_handle_t *handle)
{
efi_handle_t *fs_handles;
efi_uintn_t num;
efi_status_t ret;
ret = EFI_CALL(efi_locate_handle_buffer(
BY_PROTOCOL,
&efi_simple_file_system_protocol_guid,
NULL,
&num, &fs_handles));
if (ret != EFI_SUCCESS)
return ret;
if (!num)
return EFI_NOT_FOUND;
/* removable media first */
ret = try_load_from_file_path(fs_handles, num, fp, handle, true);
if (ret == EFI_SUCCESS)
goto out;
/* fixed media */
ret = try_load_from_file_path(fs_handles, num, fp, handle, false);
if (ret == EFI_SUCCESS)
goto out;
out:
return ret;
}
/**
* try_load_entry() - try to load image for boot option
*
......@@ -116,10 +210,15 @@ static efi_status_t try_load_entry(u16 n, efi_handle_t *handle,
log_debug("trying to load \"%ls\" from %pD\n", lo.label,
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 (EFI_DP_TYPE(lo.file_path, MEDIA_DEVICE, FILE_PATH)) {
/* file_path doesn't contain a device path */
ret = try_load_from_short_path(lo.file_path, handle);
} else {
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);
......
......@@ -73,6 +73,33 @@ static efi_status_t EFIAPI efi_disk_reset(struct efi_block_io *this,
return EFI_EXIT(EFI_SUCCESS);
}
/**
* efi_disk_is_removable() - check if the device is removable media
* @handle: efi object handle;
*
* Examine the device and determine if the device is a local block device
* and removable media.
*
* Return: true if removable, false otherwise
*/
bool efi_disk_is_removable(efi_handle_t handle)
{
struct efi_handler *handler;
struct efi_block_io *io;
efi_status_t ret;
ret = efi_search_protocol(handle, &efi_block_io_guid, &handler);
if (ret != EFI_SUCCESS)
return false;
io = handler->protocol_interface;
if (!io || !io->media)
return false;
return (bool)io->media->removable_media;
}
enum efi_disk_direction {
EFI_DISK_READ,
EFI_DISK_WRITE,
......
......@@ -197,8 +197,8 @@ static efi_status_t efi_fill_image_desc_array(
* @descriptor_version: Pointer to version number
* @descriptor_count: Pointer to number of descriptors
* @descriptor_size: Pointer to descriptor size
* package_version: Package version
* package_version_name: Package version's name
* @package_version: Package version
* @package_version_name: Package version's name
*
* Return information bout the current firmware image in @image_info.
* @image_info will consist of a number of descriptors.
......@@ -296,15 +296,15 @@ const struct efi_firmware_management_protocol efi_fmp_fit = {
/**
* efi_firmware_raw_get_image_info - return information about the current
firmware image
* firmware image
* @this: Protocol instance
* @image_info_size: Size of @image_info
* @image_info: Image information
* @descriptor_version: Pointer to version number
* @descriptor_count: Pointer to number of descriptors
* @descriptor_size: Pointer to descriptor size
* package_version: Package version
* package_version_name: Package version's name
* @package_version: Package version
* @package_version_name: Package version's name
*
* Return information bout the current firmware image in @image_info.
* @image_info will consist of a number of descriptors.
......
......@@ -11,36 +11,36 @@ def test_bootmenu(u_boot_console):
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')
with u_boot_console.temporary_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')
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2017, Heinrich Schuchardt <xypron.glpk@gmx.de>
"""
Test UEFI API implementation
""" Test UEFI API implementation
"""
import pytest
......@@ -11,14 +10,13 @@ import pytest
def test_efi_selftest(u_boot_console):
"""Run UEFI unit tests
:param u_boot_console: U-Boot console
u_boot_console -- U-Boot console
This function executes all selftests that are not marked as on request.
"""
u_boot_console.run_command(cmd='setenv efi_selftest')
u_boot_console.run_command(cmd='bootefi selftest', wait_for_prompt=False)
m = u_boot_console.p.expect(['Summary: 0 failures', 'Press any key'])
if m != 0:
if u_boot_console.p.expect(['Summary: 0 failures', 'Press any key']):
raise Exception('Failures occurred during the EFI selftest')
u_boot_console.restart_uboot()
......@@ -29,7 +27,7 @@ def test_efi_selftest(u_boot_console):
def test_efi_selftest_device_tree(u_boot_console):
"""Test the device tree support in the UEFI sub-system
:param u_boot_console: U-Boot console
u_boot_console -- U-Boot console
This test executes the UEFI unit test by calling 'bootefi selftest'.
"""
......@@ -41,8 +39,7 @@ def test_efi_selftest_device_tree(u_boot_console):
u_boot_console.run_command(cmd='setenv efi_test "${serial#}x"')
u_boot_console.run_command(cmd='test "${efi_test}" = x && setenv serial# 0')
u_boot_console.run_command(cmd='bootefi selftest ${fdtcontroladdr}', wait_for_prompt=False)
m = u_boot_console.p.expect(['serial-number:', 'U-Boot'])
if m != 0:
if u_boot_console.p.expect(['serial-number:', 'U-Boot']):
raise Exception('serial-number missing in device tree')
u_boot_console.restart_uboot()
......@@ -50,7 +47,7 @@ def test_efi_selftest_device_tree(u_boot_console):
def test_efi_selftest_watchdog_reboot(u_boot_console):
"""Test the watchdog timer
:param u_boot_console: U-Boot console
u_boot_console -- U-Boot console
This function executes the 'watchdog reboot' unit test.
"""
......@@ -59,8 +56,7 @@ def test_efi_selftest_watchdog_reboot(u_boot_console):
assert '\'watchdog reboot\'' in output
u_boot_console.run_command(cmd='setenv efi_selftest watchdog reboot')
u_boot_console.run_command(cmd='bootefi selftest', wait_for_prompt=False)
m = u_boot_console.p.expect(['resetting', 'U-Boot'])
if m != 0:
if u_boot_console.p.expect(['resetting', 'U-Boot']):
raise Exception('Reset failed in \'watchdog reboot\' test')
u_boot_console.restart_uboot()
......@@ -68,68 +64,54 @@ def test_efi_selftest_watchdog_reboot(u_boot_console):
def test_efi_selftest_text_input(u_boot_console):
"""Test the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
:param u_boot_console: U-Boot console
u_boot_console -- U-Boot console
This function calls the text input EFI selftest.
"""
u_boot_console.run_command(cmd='setenv efi_selftest text input')
u_boot_console.run_command(cmd='bootefi selftest', wait_for_prompt=False)
m = u_boot_console.p.expect([r'To terminate type \'x\''])
if m != 0:
if u_boot_console.p.expect([r'To terminate type \'x\'']):
raise Exception('No prompt for \'text input\' test')
u_boot_console.drain_console()
u_boot_console.p.timeout = 500
# EOT
u_boot_console.run_command(cmd=chr(4), wait_for_echo=False,
send_nl=False, wait_for_prompt=False)
m = u_boot_console.p.expect(
[r'Unicode char 4 \(unknown\), scan code 0 \(Null\)'])
if m != 0:
if u_boot_console.p.expect([r'Unicode char 4 \(unknown\), scan code 0 \(Null\)']):
raise Exception('EOT failed in \'text input\' test')
u_boot_console.drain_console()
# BS
u_boot_console.run_command(cmd=chr(8), wait_for_echo=False,
send_nl=False, wait_for_prompt=False)
m = u_boot_console.p.expect(
[r'Unicode char 8 \(BS\), scan code 0 \(Null\)'])
if m != 0:
if u_boot_console.p.expect([r'Unicode char 8 \(BS\), scan code 0 \(Null\)']):
raise Exception('BS failed in \'text input\' test')
u_boot_console.drain_console()
# TAB
u_boot_console.run_command(cmd=chr(9), wait_for_echo=False,
send_nl=False, wait_for_prompt=False)
m = u_boot_console.p.expect(
[r'Unicode char 9 \(TAB\), scan code 0 \(Null\)'])
if m != 0:
if u_boot_console.p.expect([r'Unicode char 9 \(TAB\), scan code 0 \(Null\)']):
raise Exception('BS failed in \'text input\' test')
u_boot_console.drain_console()
# a
u_boot_console.run_command(cmd='a', wait_for_echo=False, send_nl=False,
wait_for_prompt=False)
m = u_boot_console.p.expect(
[r'Unicode char 97 \(\'a\'\), scan code 0 \(Null\)'])
if m != 0:
if u_boot_console.p.expect([r'Unicode char 97 \(\'a\'\), scan code 0 \(Null\)']):
raise Exception('\'a\' failed in \'text input\' test')
u_boot_console.drain_console()
# UP escape sequence
u_boot_console.run_command(cmd=chr(27) + '[A', wait_for_echo=False,
send_nl=False, wait_for_prompt=False)
m = u_boot_console.p.expect(
[r'Unicode char 0 \(Null\), scan code 1 \(Up\)'])
if m != 0:
if u_boot_console.p.expect([r'Unicode char 0 \(Null\), scan code 1 \(Up\)']):
raise Exception('UP failed in \'text input\' test')
u_boot_console.drain_console()
# Euro sign
u_boot_console.run_command(cmd=b'\xe2\x82\xac'.decode(), wait_for_echo=False,
send_nl=False, wait_for_prompt=False)
m = u_boot_console.p.expect([r'Unicode char 8364 \(\''])
if m != 0:
if u_boot_console.p.expect([r'Unicode char 8364 \(\'']):
raise Exception('Euro sign failed in \'text input\' test')
u_boot_console.drain_console()
u_boot_console.run_command(cmd='x', wait_for_echo=False, send_nl=False,
wait_for_prompt=False)
m = u_boot_console.p.expect(['Summary: 0 failures', 'Press any key'])
if m != 0:
if u_boot_console.p.expect(['Summary: 0 failures', 'Press any key']):
raise Exception('Failures occurred during the EFI selftest')
u_boot_console.restart_uboot()
......@@ -137,77 +119,61 @@ def test_efi_selftest_text_input(u_boot_console):
def test_efi_selftest_text_input_ex(u_boot_console):
"""Test the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
:param u_boot_console: U-Boot console
u_boot_console -- U-Boot console
This function calls the extended text input EFI selftest.
"""
u_boot_console.run_command(cmd='setenv efi_selftest extended text input')
u_boot_console.run_command(cmd='bootefi selftest', wait_for_prompt=False)
m = u_boot_console.p.expect([r'To terminate type \'CTRL\+x\''])
if m != 0:
if u_boot_console.p.expect([r'To terminate type \'CTRL\+x\'']):
raise Exception('No prompt for \'text input\' test')
u_boot_console.drain_console()
u_boot_console.p.timeout = 500
# EOT
u_boot_console.run_command(cmd=chr(4), wait_for_echo=False,
send_nl=False, wait_for_prompt=False)
m = u_boot_console.p.expect(
[r'Unicode char 100 \(\'d\'\), scan code 0 \(CTRL\+Null\)'])
if m != 0:
if u_boot_console.p.expect([r'Unicode char 100 \(\'d\'\), scan code 0 \(CTRL\+Null\)']):
raise Exception('EOT failed in \'text input\' test')
u_boot_console.drain_console()
# BS
u_boot_console.run_command(cmd=chr(8), wait_for_echo=False,
send_nl=False, wait_for_prompt=False)
m = u_boot_console.p.expect(
[r'Unicode char 8 \(BS\), scan code 0 \(\+Null\)'])
if m != 0:
if u_boot_console.p.expect([r'Unicode char 8 \(BS\), scan code 0 \(\+Null\)']):
raise Exception('BS failed in \'text input\' test')
u_boot_console.drain_console()
# TAB
u_boot_console.run_command(cmd=chr(9), wait_for_echo=False,
send_nl=False, wait_for_prompt=False)
m = u_boot_console.p.expect(
[r'Unicode char 9 \(TAB\), scan code 0 \(\+Null\)'])
if m != 0:
if u_boot_console.p.expect([r'Unicode char 9 \(TAB\), scan code 0 \(\+Null\)']):
raise Exception('TAB failed in \'text input\' test')
u_boot_console.drain_console()
# a
u_boot_console.run_command(cmd='a', wait_for_echo=False, send_nl=False,
wait_for_prompt=False)
m = u_boot_console.p.expect(
[r'Unicode char 97 \(\'a\'\), scan code 0 \(Null\)'])
if m != 0:
if u_boot_console.p.expect([r'Unicode char 97 \(\'a\'\), scan code 0 \(Null\)']):
raise Exception('\'a\' failed in \'text input\' test')
u_boot_console.drain_console()
# UP escape sequence
u_boot_console.run_command(cmd=chr(27) + '[A', wait_for_echo=False,
send_nl=False, wait_for_prompt=False)
m = u_boot_console.p.expect(
[r'Unicode char 0 \(Null\), scan code 1 \(\+Up\)'])
if m != 0:
if u_boot_console.p.expect([r'Unicode char 0 \(Null\), scan code 1 \(\+Up\)']):
raise Exception('UP failed in \'text input\' test')
u_boot_console.drain_console()
# Euro sign
u_boot_console.run_command(cmd=b'\xe2\x82\xac'.decode(), wait_for_echo=False,
send_nl=False, wait_for_prompt=False)
m = u_boot_console.p.expect([r'Unicode char 8364 \(\''])
if m != 0:
if u_boot_console.p.expect([r'Unicode char 8364 \(\'']):
raise Exception('Euro sign failed in \'text input\' test')
u_boot_console.drain_console()
# SHIFT+ALT+FN 5
u_boot_console.run_command(cmd=b'\x1b\x5b\x31\x35\x3b\x34\x7e'.decode(),
wait_for_echo=False, send_nl=False,
wait_for_prompt=False)
m = u_boot_console.p.expect(
[r'Unicode char 0 \(Null\), scan code 15 \(SHIFT\+ALT\+FN 5\)'])
if m != 0:
if u_boot_console.p.expect([r'Unicode char 0 \(Null\), scan code 15 \(SHIFT\+ALT\+FN 5\)']):
raise Exception('SHIFT+ALT+FN 5 failed in \'text input\' test')
u_boot_console.drain_console()
u_boot_console.run_command(cmd=chr(24), wait_for_echo=False, send_nl=False,
wait_for_prompt=False)
m = u_boot_console.p.expect(['Summary: 0 failures', 'Press any key'])
if m != 0:
if u_boot_console.p.expect(['Summary: 0 failures', 'Press any key']):
raise Exception('Failures occurred during the EFI selftest')
u_boot_console.restart_uboot()
......@@ -216,7 +182,7 @@ def test_efi_selftest_text_input_ex(u_boot_console):
def test_efi_selftest_tcg2(u_boot_console):
"""Test the EFI_TCG2 PROTOCOL
:param u_boot_console: U-Boot console
u_boot_console -- U-Boot console
This function executes the 'tcg2' unit test.
"""
......@@ -226,7 +192,6 @@ def test_efi_selftest_tcg2(u_boot_console):
assert '\'tcg2\'' in output
u_boot_console.run_command(cmd='setenv efi_selftest tcg2')
u_boot_console.run_command(cmd='bootefi selftest', wait_for_prompt=False)
m = u_boot_console.p.expect(['Summary: 0 failures', 'Press any key'])
if m != 0:
if u_boot_console.p.expect(['Summary: 0 failures', 'Press any key']):
raise Exception('Failures occurred during the EFI selftest')
u_boot_console.restart_uboot()
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册