aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2022-05-31 13:05:53 -0400
committerTom Rini <trini@konsulko.com>2022-05-31 13:05:53 -0400
commit3053b781465711fd05b88ab141b1f2b55a875516 (patch)
tree1dcb95f0c4f5c3428375e0a50999f2c462b71888
parent4fe629d2e8bbda5f265e870d771b92be26e885f6 (diff)
parente85727ddb68b3b23382ea2d78d857ffa870bb0b7 (diff)
downloadu-boot-3053b781465711fd05b88ab141b1f2b55a875516.zip
u-boot-3053b781465711fd05b88ab141b1f2b55a875516.tar.gz
u-boot-3053b781465711fd05b88ab141b1f2b55a875516.tar.bz2
Merge tag 'efi-2022-07-rc4-3' of https://source.denx.de/u-boot/custodians/u-boot-efiWIP/31May2022
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]
-rw-r--r--Kconfig1
-rw-r--r--boot/Kconfig7
-rw-r--r--cmd/Kconfig10
-rw-r--r--cmd/bootefi.c21
-rw-r--r--cmd/bootmenu.c47
-rw-r--r--disk/part_efi.c4
-rw-r--r--doc/api/efi.rst6
-rw-r--r--doc/arch/sandbox.rst107
-rw-r--r--doc/build/gcc.rst8
-rw-r--r--doc/usage/cmd/bootefi.rst8
-rw-r--r--include/charset.h2
-rw-r--r--include/efi_loader.h3
-rw-r--r--lib/efi_loader/efi_bootmgr.c107
-rw-r--r--lib/efi_loader/efi_disk.c27
-rw-r--r--lib/efi_loader/efi_firmware.c10
-rw-r--r--test/py/tests/test_bootmenu.py66
-rw-r--r--test/py/tests/test_efi_selftest.py91
17 files changed, 359 insertions, 166 deletions
diff --git a/Kconfig b/Kconfig
index 797038b..f7e3c33 100644
--- a/Kconfig
+++ b/Kconfig
@@ -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
diff --git a/boot/Kconfig b/boot/Kconfig
index dff4d23..08451c6 100644
--- a/boot/Kconfig
+++ b/boot/Kconfig
@@ -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
diff --git a/cmd/Kconfig b/cmd/Kconfig
index 69c1814..09193b6 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -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
diff --git a/cmd/bootefi.c b/cmd/bootefi.c
index d80353f..827fcd9 100644
--- a/cmd/bootefi.c
+++ b/cmd/bootefi.c
@@ -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"
diff --git a/cmd/bootmenu.c b/cmd/bootmenu.c
index 8859eeb..704d36d 100644
--- a/cmd/bootmenu.c
+++ b/cmd/bootmenu.c
@@ -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))
diff --git a/disk/part_efi.c b/disk/part_efi.c
index 829ccb6..5090efd 100644
--- a/disk/part_efi.c
+++ b/disk/part_efi.c
@@ -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);
diff --git a/doc/api/efi.rst b/doc/api/efi.rst
index cb2a1c8..2b96783 100644
--- a/doc/api/efi.rst
+++ b/doc/api/efi.rst
@@ -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
------------
diff --git a/doc/arch/sandbox.rst b/doc/arch/sandbox.rst
index bc670b9..068d4a3 100644
--- a/doc/arch/sandbox.rst
+++ b/doc/arch/sandbox.rst
@@ -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
-------
diff --git a/doc/build/gcc.rst b/doc/build/gcc.rst
index 470a7aa..682051a 100644
--- a/doc/build/gcc.rst
+++ b/doc/build/gcc.rst
@@ -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
~~~~~~~~~~
diff --git a/doc/usage/cmd/bootefi.rst b/doc/usage/cmd/bootefi.rst
index 4cc8c07..cb03df4 100644
--- a/doc/usage/cmd/bootefi.rst
+++ b/doc/usage/cmd/bootefi.rst
@@ -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
-----------
diff --git a/include/charset.h b/include/charset.h
index 20abfbe..e900fd7 100644
--- a/include/charset.h
+++ b/include/charset.h
@@ -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
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 733ee03..f6651e2 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -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);
diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c
index 631a25d..93f6590 100644
--- a/lib/efi_loader/efi_bootmgr.c
+++ b/lib/efi_loader/efi_bootmgr.c
@@ -77,6 +77,100 @@ struct efi_device_path *expand_media_path(struct efi_device_path *device_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
*
* Attempt to load load-option number 'n', returning device_path and file_path
@@ -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);
diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c
index f5b462f..1e82f52 100644
--- a/lib/efi_loader/efi_disk.c
+++ b/lib/efi_loader/efi_disk.c
@@ -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,
diff --git a/lib/efi_loader/efi_firmware.c b/lib/efi_loader/efi_firmware.c
index 27953fe..fe4e084 100644
--- a/lib/efi_loader/efi_firmware.c
+++ b/lib/efi_loader/efi_firmware.c
@@ -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.
diff --git a/test/py/tests/test_bootmenu.py b/test/py/tests/test_bootmenu.py
index b4baa53..70f51de 100644
--- a/test/py/tests/test_bootmenu.py
+++ b/test/py/tests/test_bootmenu.py
@@ -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')
diff --git a/test/py/tests/test_efi_selftest.py b/test/py/tests/test_efi_selftest.py
index a48cd32..e92d63c 100644
--- a/test/py/tests/test_efi_selftest.py
+++ b/test/py/tests/test_efi_selftest.py
@@ -1,8 +1,7 @@
# 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()