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]
diff --git a/Kconfig b/Kconfig
index 797038b..f7e3c33 100644
--- a/Kconfig
+++ b/Kconfig
@@ -305,6 +305,7 @@
 
 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 @@
 	  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 @@
 	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 @@
 		      char *const argv[])
 {
 	efi_status_t ret;
+	char *img_addr, *img_size, *str_copy, *pos;
 	void *fdt;
 
 	if (argc < 2)
@@ -662,7 +663,7 @@
 		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 @@
 	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 @@
 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 @@
 	if (reverse)
 		puts(ANSI_COLOR_REVERSE);
 
-	printf("%ls", entry->title);
+	printf("%s", entry->title);
 
 	if (reverse)
 		puts(ANSI_COLOR_RESET);
@@ -162,7 +162,6 @@
 				  struct bootmenu_entry **current,
 				  unsigned short int *index)
 {
-	int len;
 	char *sep;
 	const char *option;
 	unsigned short int i = *index;
@@ -170,8 +169,8 @@
 	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 @@
 		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 @@
 	return 1;
 }
 
+#if (CONFIG_IS_ENABLED(CMD_BOOTEFI_BOOTMGR))
 /**
  * prepare_uefi_bootorder_entry() - generate the uefi bootmenu entries
  *
@@ -279,13 +273,17 @@
 		}
 
 		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 @@
 
 	return 1;
 }
+#endif
 
 static struct bootmenu_data *bootmenu_create(int delay)
 {
@@ -341,13 +340,13 @@
 	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 @@
 			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 @@
 	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 @@
 
 	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 @@
 	}
 
 	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 @@
 		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 @@
 
 	/* 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 @@
 .. 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 @@
 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 @@
 
 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 @@
 
     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
 
+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.
+
-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::
+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 @@
       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 @@
 
 ::
 
-    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 @@
  * 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 @@
 /* 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 @@
 }
 
 /**
+ * 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 @@
 		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 @@
 	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 @@
  * @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 @@
 
 /**
  * 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 @@
     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 @@
 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_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 @@
     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_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 @@
     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_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_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_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 @@
     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()