diff options
author | Tom Rini <trini@konsulko.com> | 2022-05-31 13:05:53 -0400 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2022-05-31 13:05:53 -0400 |
commit | 3053b781465711fd05b88ab141b1f2b55a875516 (patch) | |
tree | 1dcb95f0c4f5c3428375e0a50999f2c462b71888 | |
parent | 4fe629d2e8bbda5f265e870d771b92be26e885f6 (diff) | |
parent | e85727ddb68b3b23382ea2d78d857ffa870bb0b7 (diff) | |
download | u-boot-3053b781465711fd05b88ab141b1f2b55a875516.tar.gz u-boot-3053b781465711fd05b88ab141b1f2b55a875516.tar.bz2 u-boot-3053b781465711fd05b88ab141b1f2b55a875516.zip |
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]
-rw-r--r-- | Kconfig | 1 | ||||
-rw-r--r-- | boot/Kconfig | 7 | ||||
-rw-r--r-- | cmd/Kconfig | 10 | ||||
-rw-r--r-- | cmd/bootefi.c | 21 | ||||
-rw-r--r-- | cmd/bootmenu.c | 47 | ||||
-rw-r--r-- | disk/part_efi.c | 4 | ||||
-rw-r--r-- | doc/api/efi.rst | 6 | ||||
-rw-r--r-- | doc/arch/sandbox.rst | 107 | ||||
-rw-r--r-- | doc/build/gcc.rst | 8 | ||||
-rw-r--r-- | doc/usage/cmd/bootefi.rst | 8 | ||||
-rw-r--r-- | include/charset.h | 2 | ||||
-rw-r--r-- | include/efi_loader.h | 3 | ||||
-rw-r--r-- | lib/efi_loader/efi_bootmgr.c | 107 | ||||
-rw-r--r-- | lib/efi_loader/efi_disk.c | 27 | ||||
-rw-r--r-- | lib/efi_loader/efi_firmware.c | 10 | ||||
-rw-r--r-- | test/py/tests/test_bootmenu.py | 66 | ||||
-rw-r--r-- | test/py/tests/test_efi_selftest.py | 91 |
17 files changed, 359 insertions, 166 deletions
@@ -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 dff4d23b88..08451c65a5 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 69c1814d24..09193b61b9 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 d80353fa71..827fcd97df 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 8859eebea5..704d36debe 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 829ccb6bd1..5090efd119 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 cb2a1c897e..2b96783828 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 bc670b98b7..068d4a3be4 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 470a7aa349..682051abeb 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 4cc8c0718c..cb03df4e1c 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 20abfbe752..e900fd789a 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 733ee03cd7..f6651e2c60 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 631a25d76e..93f6590530 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 f5b462fb16..1e82f52dc0 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 27953fe769..fe4e084106 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 b4baa534aa..70f51de699 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 a48cd3290c..e92d63cde6 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() |