All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/9] efi_loader: booting via short-form device-path
@ 2022-03-19  9:11 Heinrich Schuchardt
  2022-03-19  9:11 ` [PATCH v2 1/9] efi_loader: export efi_dp_shorten() Heinrich Schuchardt
                   ` (9 more replies)
  0 siblings, 10 replies; 19+ messages in thread
From: Heinrich Schuchardt @ 2022-03-19  9:11 UTC (permalink / raw)
  To: u-boot; +Cc: Ilias Apalodimas, AKASHI Takahiro, Heinrich Schuchardt

The GUID of partitions is sufficient for identification and will stay
constant in the lifetime of a boot option. The preceding path of the
device-path may change due to changes in the enumeration of devices.
Therefore it is preferable to use the short-form of device-paths in load
options.


With this series booting via short-form device-paths is reenable.
The 'efidebug boot add' command is adjusted to create either short-form
or long-form device paths.

The check for the EFI System Partition used for capsule updates is
corrected.

A unit test for the boot manager is added.

v2:
	merge multiple patches to a series
	fix ESP detection

Heinrich Schuchardt (9):
  efi_loader: export efi_dp_shorten()
  efi_loader: fix efi_dp_find_obj()
  efi_loader: efi_dp_find_obj() add protocol check
  efi_loader: support booting via short-form device-path
  efi_loader: use short-form DP for load options
  efi_loader: export efi_system_partition_guid
  efi_loader: remove efi_disk_is_system_part()
  efi_loader: move dtbdump.c, initrddump.c to lib/efi_loader
  test: test UEFI boot manager

 cmd/efidebug.c                                |  70 ++-
 include/efi_loader.h                          |  12 +-
 lib/efi_loader/Makefile                       |  12 +
 lib/efi_loader/dtbdump.c                      | 539 ++++++++++++++++++
 lib/efi_loader/efi_boottime.c                 |  22 +-
 lib/efi_loader/efi_capsule.c                  |  13 +-
 lib/efi_loader/efi_device_path.c              | 138 +++--
 lib/efi_loader/efi_disk.c                     |  31 +-
 lib/efi_loader/initrddump.c                   | 449 +++++++++++++++
 lib/efi_selftest/Makefile                     |  12 -
 lib/efi_selftest/dtbdump.c                    | 539 ------------------
 lib/efi_selftest/initrddump.c                 | 449 ---------------
 test/py/tests/test_efi_bootmgr/conftest.py    |  42 ++
 .../test_efi_bootmgr/test_efi_bootmgr.py      |  31 +
 14 files changed, 1232 insertions(+), 1127 deletions(-)
 create mode 100644 lib/efi_loader/dtbdump.c
 create mode 100644 lib/efi_loader/initrddump.c
 delete mode 100644 lib/efi_selftest/dtbdump.c
 delete mode 100644 lib/efi_selftest/initrddump.c
 create mode 100644 test/py/tests/test_efi_bootmgr/conftest.py
 create mode 100644 test/py/tests/test_efi_bootmgr/test_efi_bootmgr.py

-- 
2.34.1


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v2 1/9] efi_loader: export efi_dp_shorten()
  2022-03-19  9:11 [PATCH v2 0/9] efi_loader: booting via short-form device-path Heinrich Schuchardt
@ 2022-03-19  9:11 ` Heinrich Schuchardt
  2022-03-21  7:41   ` Ilias Apalodimas
  2022-03-23  6:55   ` AKASHI Takahiro
  2022-03-19  9:11 ` [PATCH v2 2/9] efi_loader: fix efi_dp_find_obj() Heinrich Schuchardt
                   ` (8 subsequent siblings)
  9 siblings, 2 replies; 19+ messages in thread
From: Heinrich Schuchardt @ 2022-03-19  9:11 UTC (permalink / raw)
  To: u-boot
  Cc: Ilias Apalodimas, AKASHI Takahiro, Heinrich Schuchardt,
	Heinrich Schuchardt

From: Heinrich Schuchardt <xypron.glpk@gmx.de>

Rename function shorten_path() to efi_dp_shorten() and export it.

Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
---
v2:
	new patch split off
---
 include/efi_loader.h             |  3 ++-
 lib/efi_loader/efi_device_path.c | 21 +++++++++++++--------
 2 files changed, 15 insertions(+), 9 deletions(-)

diff --git a/include/efi_loader.h b/include/efi_loader.h
index 110d8ae79c..1ffcdfc485 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -725,7 +725,8 @@ extern void *efi_bounce_buffer;
 #define EFI_LOADER_BOUNCE_BUFFER_SIZE (64 * 1024 * 1024)
 #endif
 
-
+/* shorten device path */
+struct efi_device_path *efi_dp_shorten(struct efi_device_path *dp);
 struct efi_device_path *efi_dp_next(const struct efi_device_path *dp);
 int efi_dp_match(const struct efi_device_path *a,
 		 const struct efi_device_path *b);
diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
index dc787b4d3d..ddd5f132ec 100644
--- a/lib/efi_loader/efi_device_path.c
+++ b/lib/efi_loader/efi_device_path.c
@@ -122,20 +122,25 @@ int efi_dp_match(const struct efi_device_path *a,
 	}
 }
 
-/*
+/**
+ * efi_dp_shorten() - shorten device-path
+ *
  * We can have device paths that start with a USB WWID or a USB Class node,
  * and a few other cases which don't encode the full device path with bus
  * hierarchy:
  *
- *   - MESSAGING:USB_WWID
- *   - MESSAGING:USB_CLASS
- *   - MEDIA:FILE_PATH
- *   - MEDIA:HARD_DRIVE
- *   - MESSAGING:URI
+ * * MESSAGING:USB_WWID
+ * * MESSAGING:USB_CLASS
+ * * MEDIA:FILE_PATH
+ * * MEDIA:HARD_DRIVE
+ * * MESSAGING:URI
  *
  * See UEFI spec (section 3.1.2, about short-form device-paths)
+ *
+ * @dp:		original devie-path
+ * @Return:	shortened device-path or NULL
  */
-static struct efi_device_path *shorten_path(struct efi_device_path *dp)
+struct efi_device_path *efi_dp_shorten(struct efi_device_path *dp)
 {
 	while (dp) {
 		/*
@@ -189,7 +194,7 @@ static struct efi_object *find_obj(struct efi_device_path *dp, bool short_path,
 				}
 			}
 
-			obj_dp = shorten_path(efi_dp_next(obj_dp));
+			obj_dp = efi_dp_shorten(efi_dp_next(obj_dp));
 		} while (short_path && obj_dp);
 	}
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 2/9] efi_loader: fix efi_dp_find_obj()
  2022-03-19  9:11 [PATCH v2 0/9] efi_loader: booting via short-form device-path Heinrich Schuchardt
  2022-03-19  9:11 ` [PATCH v2 1/9] efi_loader: export efi_dp_shorten() Heinrich Schuchardt
@ 2022-03-19  9:11 ` Heinrich Schuchardt
  2022-03-23  7:18   ` AKASHI Takahiro
  2022-03-19  9:11 ` [PATCH v2 3/9] efi_loader: efi_dp_find_obj() add protocol check Heinrich Schuchardt
                   ` (7 subsequent siblings)
  9 siblings, 1 reply; 19+ messages in thread
From: Heinrich Schuchardt @ 2022-03-19  9:11 UTC (permalink / raw)
  To: u-boot; +Cc: Ilias Apalodimas, AKASHI Takahiro, Heinrich Schuchardt

efi_dp_find_obj() should not return any handle with a partially matching
device path but the handle with the maximum matching device path.

Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
---
v2:
	new patch
---
 include/efi_loader.h             |   4 +-
 lib/efi_loader/efi_device_path.c | 110 +++++++++++++++++--------------
 2 files changed, 63 insertions(+), 51 deletions(-)

diff --git a/include/efi_loader.h b/include/efi_loader.h
index 1ffcdfc485..6271d40125 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -730,8 +730,8 @@ struct efi_device_path *efi_dp_shorten(struct efi_device_path *dp);
 struct efi_device_path *efi_dp_next(const struct efi_device_path *dp);
 int efi_dp_match(const struct efi_device_path *a,
 		 const struct efi_device_path *b);
-struct efi_object *efi_dp_find_obj(struct efi_device_path *dp,
-				   struct efi_device_path **rem);
+efi_handle_t efi_dp_find_obj(struct efi_device_path *dp,
+			     struct efi_device_path **rem);
 /* get size of the first device path instance excluding end node */
 efi_uintn_t efi_dp_instance_size(const struct efi_device_path *dp);
 /* size of multi-instance device path excluding end node */
diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
index ddd5f132ec..aeb5264820 100644
--- a/lib/efi_loader/efi_device_path.c
+++ b/lib/efi_loader/efi_device_path.c
@@ -159,69 +159,81 @@ struct efi_device_path *efi_dp_shorten(struct efi_device_path *dp)
 	return dp;
 }
 
-static struct efi_object *find_obj(struct efi_device_path *dp, bool short_path,
-				   struct efi_device_path **rem)
+/**
+ * find_handle() - find handle by device path
+ *
+ * If @rem is provided, the handle with the longest partial match is returned.
+ *
+ * @dp:		device path to search
+ * @short_path:	use short form device path for matching
+ * @rem:	pointer to receive remaining device path
+ * Return:	matching handle
+ */
+static efi_handle_t find_handle(struct efi_device_path *dp, bool short_path,
+			        struct efi_device_path **rem)
 {
-	struct efi_object *efiobj;
-	efi_uintn_t dp_size = efi_dp_instance_size(dp);
+	efi_handle_t handle, best_handle = NULL;
+	efi_uintn_t len, best_len = 0;
+
+	len = efi_dp_instance_size(dp);
 
-	list_for_each_entry(efiobj, &efi_obj_list, link) {
+	list_for_each_entry(handle, &efi_obj_list, link) {
 		struct efi_handler *handler;
-		struct efi_device_path *obj_dp;
+		struct efi_device_path *dp_current;
+		efi_uintn_t len_current;
 		efi_status_t ret;
 
-		ret = efi_search_protocol(efiobj,
-					  &efi_guid_device_path, &handler);
+		ret = efi_search_protocol(handle, &efi_guid_device_path,
+					  &handler);
 		if (ret != EFI_SUCCESS)
 			continue;
-		obj_dp = handler->protocol_interface;
-
-		do {
-			if (efi_dp_match(dp, obj_dp) == 0) {
-				if (rem) {
-					/*
-					 * Allow partial matches, but inform
-					 * the caller.
-					 */
-					*rem = ((void *)dp) +
-						efi_dp_instance_size(obj_dp);
-					return efiobj;
-				} else {
-					/* Only return on exact matches */
-					if (efi_dp_instance_size(obj_dp) ==
-					    dp_size)
-						return efiobj;
-				}
-			}
-
-			obj_dp = efi_dp_shorten(efi_dp_next(obj_dp));
-		} while (short_path && obj_dp);
+		dp_current = handler->protocol_interface;
+		if (short_path) {
+			dp_current = efi_dp_shorten(dp_current);
+			if (!dp_current)
+				continue;
+		}
+		len_current = efi_dp_instance_size(dp_current);
+		if (rem) {
+			if (len_current < len)
+				continue;
+		} else {
+			if (len_current != len)
+				continue;
+		}
+		if (memcmp(dp_current, dp, len))
+			continue;
+		if (!rem)
+			return handle;
+		if (len_current > best_len) {
+			best_len = len_current;
+			best_handle = handle;
+			*rem = (void*)((u8 *)dp + len_current);
+		}
 	}
-
-	return NULL;
+	return best_handle;
 }
 
-/*
- * Find an efiobj from device-path, if 'rem' is not NULL, returns the
- * remaining part of the device path after the matched object.
+/**
+ * efi_dp_find_obj() - find handle by device path
+ *
+ * If @rem is provided, the handle with the longest partial match is returned.
+ *
+ * @dp:		device path to search
+ * @rem:	pointer to receive remaining device path
+ * Return:	matching handle
  */
-struct efi_object *efi_dp_find_obj(struct efi_device_path *dp,
-				   struct efi_device_path **rem)
+efi_handle_t efi_dp_find_obj(struct efi_device_path *dp,
+			     struct efi_device_path **rem)
 {
-	struct efi_object *efiobj;
-
-	/* Search for an exact match first */
-	efiobj = find_obj(dp, false, NULL);
-
-	/* Then for a fuzzy match */
-	if (!efiobj)
-		efiobj = find_obj(dp, false, rem);
+	efi_handle_t handle;
 
-	/* And now for a fuzzy short match */
-	if (!efiobj)
-		efiobj = find_obj(dp, true, rem);
+	handle = find_handle(dp, false, rem);
+	if (!handle)
+		/* Match short form device path */
+		handle = find_handle(dp, true, rem);
 
-	return efiobj;
+	return handle;
 }
 
 /*
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 3/9] efi_loader: efi_dp_find_obj() add protocol check
  2022-03-19  9:11 [PATCH v2 0/9] efi_loader: booting via short-form device-path Heinrich Schuchardt
  2022-03-19  9:11 ` [PATCH v2 1/9] efi_loader: export efi_dp_shorten() Heinrich Schuchardt
  2022-03-19  9:11 ` [PATCH v2 2/9] efi_loader: fix efi_dp_find_obj() Heinrich Schuchardt
@ 2022-03-19  9:11 ` Heinrich Schuchardt
  2022-03-23  7:26   ` AKASHI Takahiro
  2022-03-19  9:11 ` [PATCH v2 4/9] efi_loader: support booting via short-form device-path Heinrich Schuchardt
                   ` (6 subsequent siblings)
  9 siblings, 1 reply; 19+ messages in thread
From: Heinrich Schuchardt @ 2022-03-19  9:11 UTC (permalink / raw)
  To: u-boot; +Cc: Ilias Apalodimas, AKASHI Takahiro, Heinrich Schuchardt

Let function efi_dp_find_obj() additionally check if a given protocol is
installed on the handle relating to the device-path.

Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
---
v2:
	new patch
---
 include/efi_loader.h             |  1 +
 lib/efi_loader/efi_boottime.c    |  2 +-
 lib/efi_loader/efi_capsule.c     |  2 +-
 lib/efi_loader/efi_device_path.c | 23 ++++++++++++++++-------
 lib/efi_loader/efi_disk.c        |  2 +-
 5 files changed, 20 insertions(+), 10 deletions(-)

diff --git a/include/efi_loader.h b/include/efi_loader.h
index 6271d40125..1ae47a8713 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -731,6 +731,7 @@ struct efi_device_path *efi_dp_next(const struct efi_device_path *dp);
 int efi_dp_match(const struct efi_device_path *a,
 		 const struct efi_device_path *b);
 efi_handle_t efi_dp_find_obj(struct efi_device_path *dp,
+			     const efi_guid_t *guid,
 			     struct efi_device_path **rem);
 /* get size of the first device path instance excluding end node */
 efi_uintn_t efi_dp_instance_size(const struct efi_device_path *dp);
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index d0f3e05e70..a7bc371f54 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -1750,7 +1750,7 @@ efi_status_t efi_setup_loaded_image(struct efi_device_path *device_path,
 	info->system_table = &systab;
 
 	if (device_path) {
-		info->device_handle = efi_dp_find_obj(device_path, NULL);
+		info->device_handle = efi_dp_find_obj(device_path, NULL, NULL);
 
 		dp = efi_dp_append(device_path, file_path);
 		if (!dp) {
diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c
index c8e2d510a5..3d80d98c1f 100644
--- a/lib/efi_loader/efi_capsule.c
+++ b/lib/efi_loader/efi_capsule.c
@@ -681,7 +681,7 @@ static bool device_is_present_and_system_part(struct efi_device_path *dp)
 {
 	efi_handle_t handle;
 
-	handle = efi_dp_find_obj(dp, NULL);
+	handle = efi_dp_find_obj(dp, NULL, NULL);
 	if (!handle)
 		return false;
 
diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
index aeb5264820..0a8802903d 100644
--- a/lib/efi_loader/efi_device_path.c
+++ b/lib/efi_loader/efi_device_path.c
@@ -160,17 +160,19 @@ struct efi_device_path *efi_dp_shorten(struct efi_device_path *dp)
 }
 
 /**
- * find_handle() - find handle by device path
+ * find_handle() - find handle by device path and installed protocol
  *
  * If @rem is provided, the handle with the longest partial match is returned.
  *
  * @dp:		device path to search
+ * @guid:	GUID of protocol that must be installed on path or NULL
  * @short_path:	use short form device path for matching
  * @rem:	pointer to receive remaining device path
  * Return:	matching handle
  */
-static efi_handle_t find_handle(struct efi_device_path *dp, bool short_path,
-			        struct efi_device_path **rem)
+static efi_handle_t find_handle(struct efi_device_path *dp,
+				const efi_guid_t *guid, bool short_path,
+				struct efi_device_path **rem)
 {
 	efi_handle_t handle, best_handle = NULL;
 	efi_uintn_t len, best_len = 0;
@@ -183,6 +185,11 @@ static efi_handle_t find_handle(struct efi_device_path *dp, bool short_path,
 		efi_uintn_t len_current;
 		efi_status_t ret;
 
+		if (guid) {
+			ret = efi_search_protocol(handle, guid, &handler);
+			if (ret != EFI_SUCCESS)
+				continue;
+		}
 		ret = efi_search_protocol(handle, &efi_guid_device_path,
 					  &handler);
 		if (ret != EFI_SUCCESS)
@@ -195,13 +202,13 @@ static efi_handle_t find_handle(struct efi_device_path *dp, bool short_path,
 		}
 		len_current = efi_dp_instance_size(dp_current);
 		if (rem) {
-			if (len_current < len)
+			if (len_current > len)
 				continue;
 		} else {
 			if (len_current != len)
 				continue;
 		}
-		if (memcmp(dp_current, dp, len))
+		if (memcmp(dp_current, dp, len_current))
 			continue;
 		if (!rem)
 			return handle;
@@ -220,18 +227,20 @@ static efi_handle_t find_handle(struct efi_device_path *dp, bool short_path,
  * If @rem is provided, the handle with the longest partial match is returned.
  *
  * @dp:		device path to search
+ * @guid:	GUID of protocol that must be installed on path or NULL
  * @rem:	pointer to receive remaining device path
  * Return:	matching handle
  */
 efi_handle_t efi_dp_find_obj(struct efi_device_path *dp,
+			     const efi_guid_t *guid,
 			     struct efi_device_path **rem)
 {
 	efi_handle_t handle;
 
-	handle = find_handle(dp, false, rem);
+	handle = find_handle(dp, guid, false, rem);
 	if (!handle)
 		/* Match short form device path */
-		handle = find_handle(dp, true, rem);
+		handle = find_handle(dp, guid, true, rem);
 
 	return handle;
 }
diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c
index 45127d1768..d36a35d94f 100644
--- a/lib/efi_loader/efi_disk.c
+++ b/lib/efi_loader/efi_disk.c
@@ -302,7 +302,7 @@ efi_fs_from_path(struct efi_device_path *full_path)
 	efi_free_pool(file_path);
 
 	/* Get the EFI object for the partition */
-	efiobj = efi_dp_find_obj(device_path, NULL);
+	efiobj = efi_dp_find_obj(device_path, NULL, NULL);
 	efi_free_pool(device_path);
 	if (!efiobj)
 		return NULL;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 4/9] efi_loader: support booting via short-form device-path
  2022-03-19  9:11 [PATCH v2 0/9] efi_loader: booting via short-form device-path Heinrich Schuchardt
                   ` (2 preceding siblings ...)
  2022-03-19  9:11 ` [PATCH v2 3/9] efi_loader: efi_dp_find_obj() add protocol check Heinrich Schuchardt
@ 2022-03-19  9:11 ` Heinrich Schuchardt
  2022-03-23  7:50   ` AKASHI Takahiro
  2022-03-19  9:11 ` [PATCH v2 5/9] efi_loader: use short-form DP for load options Heinrich Schuchardt
                   ` (5 subsequent siblings)
  9 siblings, 1 reply; 19+ messages in thread
From: Heinrich Schuchardt @ 2022-03-19  9:11 UTC (permalink / raw)
  To: u-boot; +Cc: Ilias Apalodimas, AKASHI Takahiro, Heinrich Schuchardt

The boot manager must support loading from boot options using a short-form
device-path, e.g. one where the first element is a hard drive media path.

See '3.1.2 Load Options Processing' in UEFI specification version 2.9.

Fixes: 0e074d12393b ("efi_loader: carve out efi_load_image_from_file()")
Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
---
v2:
	path correct remaining paths to LOAD_FILE(2) protocol
---
 lib/efi_loader/efi_boottime.c | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index a7bc371f54..5bcb8253ed 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -1940,7 +1940,7 @@ efi_status_t efi_load_image_from_path(bool boot_policy,
 {
 	efi_handle_t device;
 	efi_status_t ret;
-	struct efi_device_path *dp;
+	struct efi_device_path *dp, *rem;
 	struct efi_load_file_protocol *load_file_protocol = NULL;
 	efi_uintn_t buffer_size;
 	uint64_t addr, pages;
@@ -1951,18 +1951,18 @@ efi_status_t efi_load_image_from_path(bool boot_policy,
 	*size = 0;
 
 	dp = file_path;
-	ret = EFI_CALL(efi_locate_device_path(
-		       &efi_simple_file_system_protocol_guid, &dp, &device));
+	device = efi_dp_find_obj(dp, NULL, &rem);
+	ret = efi_search_protocol(device, &efi_simple_file_system_protocol_guid,
+				  NULL);
 	if (ret == EFI_SUCCESS)
 		return efi_load_image_from_file(file_path, buffer, size);
 
-	ret = EFI_CALL(efi_locate_device_path(
-		       &efi_guid_load_file_protocol, &dp, &device));
+	ret = efi_search_protocol(device, &efi_guid_load_file_protocol, NULL);
 	if (ret == EFI_SUCCESS) {
 		guid = &efi_guid_load_file_protocol;
 	} else if (!boot_policy) {
 		guid = &efi_guid_load_file2_protocol;
-		ret = EFI_CALL(efi_locate_device_path(guid, &dp, &device));
+		ret = efi_search_protocol(device, guid, NULL);
 	}
 	if (ret != EFI_SUCCESS)
 		return EFI_NOT_FOUND;
@@ -1971,9 +1971,9 @@ efi_status_t efi_load_image_from_path(bool boot_policy,
 	if (ret != EFI_SUCCESS)
 		return EFI_NOT_FOUND;
 	buffer_size = 0;
-	ret = load_file_protocol->load_file(load_file_protocol, dp,
-					    boot_policy, &buffer_size,
-					    NULL);
+	ret = EFI_CALL(load_file_protocol->load_file(
+					load_file_protocol, rem, boot_policy,
+					&buffer_size, NULL));
 	if (ret != EFI_BUFFER_TOO_SMALL)
 		goto out;
 	pages = efi_size_in_pages(buffer_size);
@@ -1984,7 +1984,7 @@ efi_status_t efi_load_image_from_path(bool boot_policy,
 		goto out;
 	}
 	ret = EFI_CALL(load_file_protocol->load_file(
-					load_file_protocol, dp, boot_policy,
+					load_file_protocol, rem, boot_policy,
 					&buffer_size, (void *)(uintptr_t)addr));
 	if (ret != EFI_SUCCESS)
 		efi_free_pages(addr, pages);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 5/9] efi_loader: use short-form DP for load options
  2022-03-19  9:11 [PATCH v2 0/9] efi_loader: booting via short-form device-path Heinrich Schuchardt
                   ` (3 preceding siblings ...)
  2022-03-19  9:11 ` [PATCH v2 4/9] efi_loader: support booting via short-form device-path Heinrich Schuchardt
@ 2022-03-19  9:11 ` Heinrich Schuchardt
  2022-03-23  8:18   ` AKASHI Takahiro
  2022-03-19  9:11 ` [PATCH v2 6/9] efi_loader: export efi_system_partition_guid Heinrich Schuchardt
                   ` (4 subsequent siblings)
  9 siblings, 1 reply; 19+ messages in thread
From: Heinrich Schuchardt @ 2022-03-19  9:11 UTC (permalink / raw)
  To: u-boot
  Cc: Ilias Apalodimas, AKASHI Takahiro, Heinrich Schuchardt,
	Heinrich Schuchardt

From: Heinrich Schuchardt <xypron.glpk@gmx.de>

The GUID of partitions is sufficient for identification and will stay
constant in the lifetime of a boot option. The preceding path of the
device-path may change due to changes in the enumeration of devices.
Therefore it is preferable to use the short-form of device-paths in load
options. Adjust the 'efidebug boot add' command accordingly.

Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
---
v2:
	support both short and long form device paths
	split off exporting efi_dp_shorten() into a separate patch
---
 cmd/efidebug.c | 70 ++++++++++++++++++++++++++++++++++----------------
 1 file changed, 48 insertions(+), 22 deletions(-)

diff --git a/cmd/efidebug.c b/cmd/efidebug.c
index 401d13cc4c..51e2850d21 100644
--- a/cmd/efidebug.c
+++ b/cmd/efidebug.c
@@ -734,20 +734,20 @@ static int do_efi_show_tables(struct cmd_tbl *cmdtp, int flag,
 }
 
 /**
- * create_initrd_dp() - Create a special device for our Boot### option
- *
- * @dev:	Device
- * @part:	Disk partition
- * @file:	Filename
- * Return:	Pointer to the device path or ERR_PTR
+ * create_initrd_dp() - create a special device for our Boot### option
  *
+ * @dev:	device
+ * @part:	disk partition
+ * @file:	filename
+ * @shortform:	create short form device path
+ * Return:	pointer to the device path or ERR_PTR
  */
 static
 struct efi_device_path *create_initrd_dp(const char *dev, const char *part,
-					 const char *file)
+					 const char *file, int shortform)
 
 {
-	struct efi_device_path *tmp_dp = NULL, *tmp_fp = NULL;
+	struct efi_device_path *tmp_dp = NULL, *tmp_fp = NULL, *short_fp = NULL;
 	struct efi_device_path *initrd_dp = NULL;
 	efi_status_t ret;
 	const struct efi_initrd_dp id_dp = {
@@ -771,9 +771,13 @@ struct efi_device_path *create_initrd_dp(const char *dev, const char *part,
 		printf("Cannot create device path for \"%s %s\"\n", part, file);
 		goto out;
 	}
+	if (shortform)
+		short_fp = efi_dp_shorten(tmp_fp);
+	if (!short_fp)
+		short_fp = tmp_fp;
 
 	initrd_dp = efi_dp_append((const struct efi_device_path *)&id_dp,
-				  tmp_fp);
+				  short_fp);
 
 out:
 	efi_free_pool(tmp_dp);
@@ -807,6 +811,7 @@ static int do_efi_boot_add(struct cmd_tbl *cmdtp, int flag,
 	size_t label_len, label_len16;
 	u16 *label;
 	struct efi_device_path *device_path = NULL, *file_path = NULL;
+	struct efi_device_path *fp_free = NULL;
 	struct efi_device_path *final_fp = NULL;
 	struct efi_device_path *initrd_dp = NULL;
 	struct efi_load_option lo;
@@ -826,7 +831,18 @@ static int do_efi_boot_add(struct cmd_tbl *cmdtp, int flag,
 	argc--;
 	argv++; /* 'add' */
 	for (; argc > 0; argc--, argv++) {
-		if (!strcmp(argv[0], "-b")) {
+		int shortform;
+
+		if (*argv[0] != '-' || strlen(argv[0]) != 2) {
+				r = CMD_RET_USAGE;
+				goto out;
+		}
+		shortform = 0;
+		switch (argv[0][1]) {
+		case 'b':
+			shortform = 1;
+			/* fallthrough */
+		case 'B':
 			if (argc <  5 || lo.label) {
 				r = CMD_RET_USAGE;
 				goto out;
@@ -849,24 +865,33 @@ static int do_efi_boot_add(struct cmd_tbl *cmdtp, int flag,
 
 			/* file path */
 			ret = efi_dp_from_name(argv[3], argv[4], argv[5],
-					       &device_path, &file_path);
+					       &device_path, &fp_free);
 			if (ret != EFI_SUCCESS) {
 				printf("Cannot create device path for \"%s %s\"\n",
 				       argv[3], argv[4]);
 				r = CMD_RET_FAILURE;
 				goto out;
 			}
+			if (shortform)
+				file_path = efi_dp_shorten(fp_free);
+			if (!file_path)
+				file_path = fp_free;
 			fp_size += efi_dp_size(file_path) +
 				sizeof(struct efi_device_path);
 			argc -= 5;
 			argv += 5;
-		} else if (!strcmp(argv[0], "-i")) {
+			break;
+		case 'i':
+			shortform = 1;
+			/* fallthrough */
+		case 'I':
 			if (argc < 3 || initrd_dp) {
 				r = CMD_RET_USAGE;
 				goto out;
 			}
 
-			initrd_dp = create_initrd_dp(argv[1], argv[2], argv[3]);
+			initrd_dp = create_initrd_dp(argv[1], argv[2], argv[3],
+						     shortform);
 			if (!initrd_dp) {
 				printf("Cannot add an initrd\n");
 				r = CMD_RET_FAILURE;
@@ -876,7 +901,8 @@ static int do_efi_boot_add(struct cmd_tbl *cmdtp, int flag,
 			argv += 3;
 			fp_size += efi_dp_size(initrd_dp) +
 				sizeof(struct efi_device_path);
-		} else if (!strcmp(argv[0], "-s")) {
+			break;
+		case 's':
 			if (argc < 1 || lo.optional_data) {
 				r = CMD_RET_USAGE;
 				goto out;
@@ -884,7 +910,8 @@ static int do_efi_boot_add(struct cmd_tbl *cmdtp, int flag,
 			lo.optional_data = (const u8 *)argv[1];
 			argc -= 1;
 			argv += 1;
-		} else {
+			break;
+		default:
 			r = CMD_RET_USAGE;
 			goto out;
 		}
@@ -927,7 +954,7 @@ out:
 	efi_free_pool(final_fp);
 	efi_free_pool(initrd_dp);
 	efi_free_pool(device_path);
-	efi_free_pool(file_path);
+	efi_free_pool(fp_free);
 	free(lo.label);
 
 	return r;
@@ -1571,12 +1598,11 @@ static int do_efidebug(struct cmd_tbl *cmdtp, int flag,
 static char efidebug_help_text[] =
 	"  - UEFI Shell-like interface to configure UEFI environment\n"
 	"\n"
-	"efidebug boot add "
-	"-b <bootid> <label> <interface> <devnum>[:<part>] <file path> "
-	"-i <interface> <devnum>[:<part>] <initrd file path> "
-	"-s '<optional data>'\n"
-	"  - set UEFI BootXXXX variable\n"
-	"    <load options> will be passed to UEFI application\n"
+	"efidebug boot add - set UEFI BootXXXX variable\n"
+	"  -b|-B <bootid> <label> <interface> <devnum>[:<part>] <file path>\n"
+	"  -i|-I <interface> <devnum>[:<part>] <initrd file path>\n"
+	"  (-b, -i for short form device path)\n"
+	"  -s '<optional data>'\n"
 	"efidebug boot rm <bootid#1> [<bootid#2> [<bootid#3> [...]]]\n"
 	"  - delete UEFI BootXXXX variables\n"
 	"efidebug boot dump\n"
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 6/9] efi_loader: export efi_system_partition_guid
  2022-03-19  9:11 [PATCH v2 0/9] efi_loader: booting via short-form device-path Heinrich Schuchardt
                   ` (4 preceding siblings ...)
  2022-03-19  9:11 ` [PATCH v2 5/9] efi_loader: use short-form DP for load options Heinrich Schuchardt
@ 2022-03-19  9:11 ` Heinrich Schuchardt
  2022-03-19  9:11 ` [PATCH v2 7/9] efi_loader: remove efi_disk_is_system_part() Heinrich Schuchardt
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 19+ messages in thread
From: Heinrich Schuchardt @ 2022-03-19  9:11 UTC (permalink / raw)
  To: u-boot; +Cc: Ilias Apalodimas, AKASHI Takahiro, Heinrich Schuchardt

The efi_system_partition_guid is needed in multiple places. Export it.

Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
---
v2:
	new patch
---
 include/efi_loader.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/efi_loader.h b/include/efi_loader.h
index 1ae47a8713..156056fcd3 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -260,6 +260,8 @@ extern const efi_guid_t efi_block_io_guid;
 extern const efi_guid_t efi_global_variable_guid;
 extern const efi_guid_t efi_guid_console_control;
 extern const efi_guid_t efi_guid_device_path;
+/* GUID of the EFI system partition */
+extern const efi_guid_t efi_system_partition_guid;
 /* GUID of the EFI_DRIVER_BINDING_PROTOCOL */
 extern const efi_guid_t efi_guid_driver_binding_protocol;
 /* event group ExitBootServices() invoked */
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 7/9] efi_loader: remove efi_disk_is_system_part()
  2022-03-19  9:11 [PATCH v2 0/9] efi_loader: booting via short-form device-path Heinrich Schuchardt
                   ` (5 preceding siblings ...)
  2022-03-19  9:11 ` [PATCH v2 6/9] efi_loader: export efi_system_partition_guid Heinrich Schuchardt
@ 2022-03-19  9:11 ` Heinrich Schuchardt
  2022-03-19  9:11 ` [PATCH v2 8/9] efi_loader: move dtbdump.c, initrddump.c to lib/efi_loader Heinrich Schuchardt
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 19+ messages in thread
From: Heinrich Schuchardt @ 2022-03-19  9:11 UTC (permalink / raw)
  To: u-boot; +Cc: Ilias Apalodimas, AKASHI Takahiro, Heinrich Schuchardt

The block IO protocol may be installed on any handle. We should make
no assumption about the structure the handle points to.

efi_disk_is_system_part() makes an illegal widening cast from a handle
to a struct efi_disk_obj. Remove the function.

Fixes: Fixes: 41fd506842c2 ("efi_loader: disk: add efi_disk_is_system_part()")
Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
---
v2:
	correctly detect ESP
---
 include/efi_loader.h         |  2 --
 lib/efi_loader/efi_capsule.c | 11 +++++++++--
 lib/efi_loader/efi_disk.c    | 29 -----------------------------
 3 files changed, 9 insertions(+), 33 deletions(-)

diff --git a/include/efi_loader.h b/include/efi_loader.h
index 156056fcd3..af36639ec6 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -541,8 +541,6 @@ efi_status_t tcg2_measure_pe_image(void *efi, u64 efi_size,
 int efi_disk_create_partitions(efi_handle_t parent, struct blk_desc *desc,
 			       const char *if_typename, int diskid,
 			       const char *pdevname);
-/* Check if it is EFI system partition */
-bool efi_disk_is_system_part(efi_handle_t handle);
 /* Called by bootefi to make GOP (graphical) interface available */
 efi_status_t efi_gop_register(void);
 /* Called by bootefi to make the network interface available */
diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c
index 3d80d98c1f..ae4a278bad 100644
--- a/lib/efi_loader/efi_capsule.c
+++ b/lib/efi_loader/efi_capsule.c
@@ -670,22 +670,29 @@ static efi_status_t get_dp_device(u16 *boot_var,
 
 /**
  * device_is_present_and_system_part - check if a device exists
- * @dp		Device path
  *
  * Check if a device pointed to by the device path, @dp, exists and is
  * located in UEFI system partition.
  *
+ * @dp		device path
  * Return:	true - yes, false - no
  */
 static bool device_is_present_and_system_part(struct efi_device_path *dp)
 {
 	efi_handle_t handle;
+	struct efi_device_path *rem;
 
+	/* Check device exists */
 	handle = efi_dp_find_obj(dp, NULL, NULL);
 	if (!handle)
 		return false;
 
-	return efi_disk_is_system_part(handle);
+	/* Check device is on system partition */
+	handle = efi_dp_find_obj(dp, &efi_system_partition_guid, &rem);
+	if (!handle)
+		return false;
+
+	return true;
 }
 
 /**
diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c
index d36a35d94f..c905c12abc 100644
--- a/lib/efi_loader/efi_disk.c
+++ b/lib/efi_loader/efi_disk.c
@@ -587,32 +587,3 @@ efi_status_t efi_disk_register(void)
 
 	return EFI_SUCCESS;
 }
-
-/**
- * efi_disk_is_system_part() - check if handle refers to an EFI system partition
- *
- * @handle:	handle of partition
- *
- * Return:	true if handle refers to an EFI system partition
- */
-bool efi_disk_is_system_part(efi_handle_t handle)
-{
-	struct efi_handler *handler;
-	struct efi_disk_obj *diskobj;
-	struct disk_partition info;
-	efi_status_t ret;
-	int r;
-
-	/* check if this is a block device */
-	ret = efi_search_protocol(handle, &efi_block_io_guid, &handler);
-	if (ret != EFI_SUCCESS)
-		return false;
-
-	diskobj = container_of(handle, struct efi_disk_obj, header);
-
-	r = part_get_info(diskobj->desc, diskobj->part, &info);
-	if (r)
-		return false;
-
-	return !!(info.bootable & PART_EFI_SYSTEM_PARTITION);
-}
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 8/9] efi_loader: move dtbdump.c, initrddump.c to lib/efi_loader
  2022-03-19  9:11 [PATCH v2 0/9] efi_loader: booting via short-form device-path Heinrich Schuchardt
                   ` (6 preceding siblings ...)
  2022-03-19  9:11 ` [PATCH v2 7/9] efi_loader: remove efi_disk_is_system_part() Heinrich Schuchardt
@ 2022-03-19  9:11 ` Heinrich Schuchardt
  2022-03-23  7:01   ` AKASHI Takahiro
  2022-03-19  9:11 ` [PATCH v2 9/9] test: test UEFI boot manager Heinrich Schuchardt
  2022-03-25  9:12   ` AKASHI Takahiro
  9 siblings, 1 reply; 19+ messages in thread
From: Heinrich Schuchardt @ 2022-03-19  9:11 UTC (permalink / raw)
  To: u-boot; +Cc: Ilias Apalodimas, AKASHI Takahiro, Heinrich Schuchardt

The tools dtbdump.efi and initrddump.efi are useful for Python testing even
if CONFIG_EFI_SELFTEST=y.

Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
---
v2:
	new patch
---
 lib/efi_loader/Makefile       |  12 +
 lib/efi_loader/dtbdump.c      | 539 ++++++++++++++++++++++++++++++++++
 lib/efi_loader/initrddump.c   | 449 ++++++++++++++++++++++++++++
 lib/efi_selftest/Makefile     |  12 -
 lib/efi_selftest/dtbdump.c    | 539 ----------------------------------
 lib/efi_selftest/initrddump.c | 449 ----------------------------
 6 files changed, 1000 insertions(+), 1000 deletions(-)
 create mode 100644 lib/efi_loader/dtbdump.c
 create mode 100644 lib/efi_loader/initrddump.c
 delete mode 100644 lib/efi_selftest/dtbdump.c
 delete mode 100644 lib/efi_selftest/initrddump.c

diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
index b2c664d108..befed7144e 100644
--- a/lib/efi_loader/Makefile
+++ b/lib/efi_loader/Makefile
@@ -14,12 +14,24 @@ CFLAGS_efi_boottime.o += \
   -DFW_PATCHLEVEL="0x$(PATCHLEVEL)"
 CFLAGS_helloworld.o := $(CFLAGS_EFI) -Os -ffreestanding
 CFLAGS_REMOVE_helloworld.o := $(CFLAGS_NON_EFI)
+CFLAGS_dtbdump.o := $(CFLAGS_EFI) -Os -ffreestanding
+CFLAGS_REMOVE_dtbdump.o := $(CFLAGS_NON_EFI)
+CFLAGS_initrddump_exit.o := $(CFLAGS_EFI) -Os -ffreestanding
+CFLAGS_REMOVE_initrddump.o := $(CFLAGS_NON_EFI)
 
 ifneq ($(CONFIG_CMD_BOOTEFI_HELLO_COMPILE),)
 always += helloworld.efi
 targets += helloworld.o
 endif
 
+ifeq ($(CONFIG_GENERATE_ACPI_TABLE),)
+always += dtbdump.efi
+endif
+
+ifdef CONFIG_EFI_LOAD_FILE2_INITRD
+always += initrddump.efi
+endif
+
 obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o
 obj-$(CONFIG_CMD_BOOTEFI_BOOTMGR) += efi_bootmgr.o
 obj-y += efi_boottime.o
diff --git a/lib/efi_loader/dtbdump.c b/lib/efi_loader/dtbdump.c
new file mode 100644
index 0000000000..3ce2a07f9e
--- /dev/null
+++ b/lib/efi_loader/dtbdump.c
@@ -0,0 +1,539 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2020, Heinrich Schuchardt <xypron.glpk@gmx.de>
+ *
+ * dtbdump.efi saves the device tree provided as a configuration table
+ * to a file.
+ */
+
+#include <common.h>
+#include <efi_api.h>
+#include <efi_dt_fixup.h>
+#include <part.h>
+#include <linux/libfdt.h>
+
+#define BUFFER_SIZE 64
+#define ESC 0x17
+
+#define efi_size_in_pages(size) ((size + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT)
+
+static struct efi_simple_text_output_protocol *cerr;
+static struct efi_simple_text_output_protocol *cout;
+static struct efi_simple_text_input_protocol *cin;
+static struct efi_boot_services *bs;
+static const efi_guid_t fdt_guid = EFI_FDT_GUID;
+static const efi_guid_t loaded_image_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
+static const efi_guid_t guid_simple_file_system_protocol =
+					EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
+static efi_handle_t handle;
+static struct efi_system_table *systable;
+static const efi_guid_t efi_dt_fixup_protocol_guid = EFI_DT_FIXUP_PROTOCOL_GUID;
+static const efi_guid_t efi_file_info_guid = EFI_FILE_INFO_GUID;
+static const efi_guid_t efi_system_partition_guid = PARTITION_SYSTEM_GUID;
+
+/**
+ * print() - print string
+ *
+ * @string:	text
+ */
+static void print(u16 *string)
+{
+	cout->output_string(cout, string);
+}
+
+/**
+ * error() - print error string
+ *
+ * @string:	error text
+ */
+static void error(u16 *string)
+{
+	cout->set_attribute(cout, EFI_LIGHTRED | EFI_BACKGROUND_BLACK);
+	print(string);
+	cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
+}
+
+/**
+ * efi_input_yn() - get answer to yes/no question
+ *
+ * Return:
+ * y or Y
+ *     EFI_SUCCESS
+ * n or N
+ *     EFI_ACCESS_DENIED
+ * ESC
+ *     EFI_ABORTED
+ */
+static efi_status_t efi_input_yn(void)
+{
+	struct efi_input_key key = {0};
+	efi_uintn_t index;
+	efi_status_t ret;
+
+	/* Drain the console input */
+	ret = cin->reset(cin, true);
+	for (;;) {
+		ret = bs->wait_for_event(1, &cin->wait_for_key, &index);
+		if (ret != EFI_SUCCESS)
+			continue;
+		ret = cin->read_key_stroke(cin, &key);
+		if (ret != EFI_SUCCESS)
+			continue;
+		switch (key.scan_code) {
+		case 0x17: /* Escape */
+			return EFI_ABORTED;
+		default:
+			break;
+		}
+		/* Convert to lower case */
+		switch (key.unicode_char | 0x20) {
+		case 'y':
+			return EFI_SUCCESS;
+		case 'n':
+			return EFI_ACCESS_DENIED;
+		default:
+			break;
+		}
+	}
+}
+
+/**
+ * efi_input() - read string from console
+ *
+ * @buffer:		input buffer
+ * @buffer_size:	buffer size
+ * Return:		status code
+ */
+static efi_status_t efi_input(u16 *buffer, efi_uintn_t buffer_size)
+{
+	struct efi_input_key key = {0};
+	efi_uintn_t index;
+	efi_uintn_t pos = 0;
+	u16 outbuf[2] = u" ";
+	efi_status_t ret;
+
+	/* Drain the console input */
+	ret = cin->reset(cin, true);
+	*buffer = 0;
+	for (;;) {
+		ret = bs->wait_for_event(1, &cin->wait_for_key, &index);
+		if (ret != EFI_SUCCESS)
+			continue;
+		ret = cin->read_key_stroke(cin, &key);
+		if (ret != EFI_SUCCESS)
+			continue;
+		switch (key.scan_code) {
+		case 0x17: /* Escape */
+			print(u"\r\nAborted\r\n");
+			return EFI_ABORTED;
+		default:
+			break;
+		}
+		switch (key.unicode_char) {
+		case 0x08: /* Backspace */
+			if (pos) {
+				buffer[pos--] = 0;
+				print(u"\b \b");
+			}
+			break;
+		case 0x0a: /* Linefeed */
+		case 0x0d: /* Carriage return */
+			print(u"\r\n");
+			return EFI_SUCCESS;
+		default:
+			break;
+		}
+		/* Ignore surrogate codes */
+		if (key.unicode_char >= 0xD800 && key.unicode_char <= 0xDBFF)
+			continue;
+		if (key.unicode_char >= 0x20 &&
+		    pos < buffer_size - 1) {
+			*outbuf = key.unicode_char;
+			buffer[pos++] = key.unicode_char;
+			buffer[pos] = 0;
+			print(outbuf);
+		}
+	}
+}
+
+/*
+ * Convert FDT value to host endianness.
+ *
+ * @val		FDT value
+ * Return:	converted value
+ */
+static u32 f2h(fdt32_t val)
+{
+	char *buf = (char *)&val;
+	char i;
+
+	/* Swap the bytes */
+	i = buf[0]; buf[0] = buf[3]; buf[3] = i;
+	i = buf[1]; buf[1] = buf[2]; buf[2] = i;
+	return *(u32 *)buf;
+}
+
+/**
+ * get_dtb() - get device tree
+ *
+ * @systable:	system table
+ * Return:	device tree or NULL
+ */
+void *get_dtb(struct efi_system_table *systable)
+{
+	void *dtb = NULL;
+	efi_uintn_t i;
+
+	for (i = 0; i < systable->nr_tables; ++i) {
+		if (!memcmp(&systable->tables[i].guid, &fdt_guid,
+			    sizeof(efi_guid_t))) {
+			dtb = systable->tables[i].table;
+			break;
+		}
+	}
+	return dtb;
+}
+
+/**
+ * skip_whitespace() - skip over leading whitespace
+ *
+ * @pos:	UTF-16 string
+ * Return:	pointer to first non-whitespace
+ */
+u16 *skip_whitespace(u16 *pos)
+{
+	for (; *pos && *pos <= 0x20; ++pos)
+		;
+	return pos;
+}
+
+/**
+ * starts_with() - check if @string starts with @keyword
+ *
+ * @string:	string to search for keyword
+ * @keyword:	keyword to be searched
+ * Return:	true fi @string starts with the keyword
+ */
+bool starts_with(u16 *string, u16 *keyword)
+{
+	for (; *keyword; ++string, ++keyword) {
+		if (*string != *keyword)
+			return false;
+	}
+	return true;
+}
+
+/**
+ * do_help() - print help
+ */
+void do_help(void)
+{
+	error(u"load <dtb> - load device-tree from file\r\n");
+	error(u"save <dtb> - save device-tree to file\r\n");
+	error(u"exit       - exit the shell\r\n");
+}
+
+/**
+ * open_file_system() - open simple file system protocol
+ *
+ * file_system:	interface of the simple file system protocol
+ * Return:	status code
+ */
+static efi_status_t
+open_file_system(struct efi_simple_file_system_protocol **file_system)
+{
+	struct efi_loaded_image *loaded_image;
+	efi_status_t ret;
+	efi_handle_t *handle_buffer = NULL;
+	efi_uintn_t count;
+
+	ret = bs->open_protocol(handle, &loaded_image_guid,
+				(void **)&loaded_image, NULL, NULL,
+				EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+	if (ret != EFI_SUCCESS) {
+		error(u"Loaded image protocol not found\r\n");
+		return ret;
+	}
+
+	/* Open the simple file system protocol on the same partition */
+	ret = bs->open_protocol(loaded_image->device_handle,
+				&guid_simple_file_system_protocol,
+				(void **)file_system, NULL, NULL,
+				EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+	if (ret == EFI_SUCCESS)
+		return ret;
+
+	/* Open the simple file system protocol on the UEFI system partition */
+	ret = bs->locate_handle_buffer(BY_PROTOCOL, &efi_system_partition_guid,
+				       NULL, &count, &handle_buffer);
+	if (ret == EFI_SUCCESS && handle_buffer)
+		ret = bs->open_protocol(handle_buffer[0],
+					&guid_simple_file_system_protocol,
+					(void **)file_system, NULL, NULL,
+					EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+	if (ret != EFI_SUCCESS)
+		error(u"Failed to open simple file system protocol\r\n");
+	if (handle)
+		bs->free_pool(handle_buffer);
+
+	return ret;
+}
+
+/**
+ * do_load() - load and install device-tree
+ *
+ * @filename:	file name
+ * Return:	status code
+ */
+efi_status_t do_load(u16 *filename)
+{
+	struct efi_dt_fixup_protocol *dt_fixup_prot;
+	struct efi_simple_file_system_protocol *file_system;
+	struct efi_file_handle *root = NULL, *file = NULL;
+	u64 addr = 0;
+	struct efi_file_info *info;
+	struct fdt_header *dtb;
+	efi_uintn_t buffer_size;
+	efi_uintn_t pages;
+	efi_status_t ret, ret2;
+
+	ret = bs->locate_protocol(&efi_dt_fixup_protocol_guid, NULL,
+				  (void **)&dt_fixup_prot);
+	if (ret != EFI_SUCCESS) {
+		error(u"Device-tree fix-up protocol not found\r\n");
+		return ret;
+	}
+
+	filename = skip_whitespace(filename);
+
+	ret = open_file_system(&file_system);
+	if (ret != EFI_SUCCESS)
+		goto out;
+
+	/* Open volume */
+	ret = file_system->open_volume(file_system, &root);
+	if (ret != EFI_SUCCESS) {
+		error(u"Failed to open volume\r\n");
+		goto out;
+	}
+
+	/* Open file */
+	ret = root->open(root, &file, filename, EFI_FILE_MODE_READ, 0);
+	if (ret != EFI_SUCCESS) {
+		error(u"File not found\r\n");
+		goto out;
+	}
+	/* Get file size */
+	buffer_size = 0;
+	ret = file->getinfo(file, &efi_file_info_guid, &buffer_size, NULL);
+	if (ret != EFI_BUFFER_TOO_SMALL) {
+		error(u"Can't get file info size\r\n");
+		goto out;
+	}
+	ret = bs->allocate_pool(EFI_LOADER_DATA, buffer_size, (void **)&info);
+	if (ret != EFI_SUCCESS) {
+		error(u"Out of memory\r\n");
+		goto out;
+	}
+	ret = file->getinfo(file, &efi_file_info_guid, &buffer_size, info);
+	if (ret != EFI_SUCCESS) {
+		error(u"Can't get file info\r\n");
+		goto out;
+	}
+	buffer_size = info->file_size;
+	pages = efi_size_in_pages(buffer_size);
+	ret = bs->free_pool(info);
+	if (ret != EFI_SUCCESS)
+		error(u"Can't free memory pool\r\n");
+	/* Read file */
+	ret = bs->allocate_pages(EFI_ALLOCATE_ANY_PAGES,
+				 EFI_ACPI_RECLAIM_MEMORY,
+				 pages, &addr);
+	if (ret != EFI_SUCCESS) {
+		error(u"Out of memory\r\n");
+		goto out;
+	}
+	dtb = (struct fdt_header *)(uintptr_t)addr;
+	ret = file->read(file, &buffer_size, dtb);
+	if (ret != EFI_SUCCESS) {
+		error(u"Can't read file\r\n");
+		goto out;
+	}
+	/* Fixup file, expecting EFI_BUFFER_TOO_SMALL */
+	ret = dt_fixup_prot->fixup(dt_fixup_prot, dtb, &buffer_size,
+				   EFI_DT_APPLY_FIXUPS | EFI_DT_RESERVE_MEMORY |
+				   EFI_DT_INSTALL_TABLE);
+	if (ret == EFI_BUFFER_TOO_SMALL) {
+		/* Read file into larger buffer */
+		ret = bs->free_pages(addr, pages);
+		if (ret != EFI_SUCCESS)
+			error(u"Can't free memory pages\r\n");
+		pages = efi_size_in_pages(buffer_size);
+		ret = bs->allocate_pages(EFI_ALLOCATE_ANY_PAGES,
+					 EFI_ACPI_RECLAIM_MEMORY,
+					 pages, &addr);
+		if (ret != EFI_SUCCESS) {
+			error(u"Out of memory\r\n");
+			goto out;
+		}
+		dtb = (struct fdt_header *)(uintptr_t)addr;
+		ret = file->setpos(file, 0);
+		if (ret != EFI_SUCCESS) {
+			error(u"Can't position file\r\n");
+			goto out;
+		}
+		ret = file->read(file, &buffer_size, dtb);
+		if (ret != EFI_SUCCESS) {
+			error(u"Can't read file\r\n");
+			goto out;
+		}
+		buffer_size = pages << EFI_PAGE_SHIFT;
+		ret = dt_fixup_prot->fixup(
+				dt_fixup_prot, dtb, &buffer_size,
+				EFI_DT_APPLY_FIXUPS | EFI_DT_RESERVE_MEMORY |
+				EFI_DT_INSTALL_TABLE);
+	}
+	if (ret == EFI_SUCCESS)
+		print(u"device-tree installed\r\n");
+	else
+		error(u"Device-tree fix-up failed\r\n");
+out:
+	if (addr) {
+		ret2 = bs->free_pages(addr, pages);
+		if (ret2 != EFI_SUCCESS)
+			error(u"Can't free memory pages\r\n");
+	}
+	if (file) {
+		ret2 = file->close(file);
+		if (ret2 != EFI_SUCCESS)
+			error(u"Can't close file\r\n");
+	}
+	if (root) {
+		ret2 = root->close(root);
+		if (ret2 != EFI_SUCCESS)
+			error(u"Can't close volume\r\n");
+	}
+	return ret;
+}
+
+/**
+ * do_save() - save current device-tree
+ *
+ * @filename:	file name
+ * Return:	status code
+ */
+efi_status_t do_save(u16 *filename)
+{
+	struct efi_simple_file_system_protocol *file_system;
+	efi_uintn_t dtb_size;
+	struct efi_file_handle *root, *file;
+	struct fdt_header *dtb;
+	efi_uintn_t ret;
+
+	dtb = get_dtb(systable);
+	if (!dtb) {
+		error(u"DTB not found\r\n");
+		return EFI_NOT_FOUND;
+	}
+	if (f2h(dtb->magic) != FDT_MAGIC) {
+		error(u"Wrong device tree magic\r\n");
+		return EFI_NOT_FOUND;
+	}
+	dtb_size = f2h(dtb->totalsize);
+
+	filename = skip_whitespace(filename);
+
+	ret = open_file_system(&file_system);
+	if (ret != EFI_SUCCESS)
+		return ret;
+
+	/* Open volume */
+	ret = file_system->open_volume(file_system, &root);
+	if (ret != EFI_SUCCESS) {
+		error(u"Failed to open volume\r\n");
+		return ret;
+	}
+	/* Check if file already exists */
+	ret = root->open(root, &file, filename, EFI_FILE_MODE_READ, 0);
+	if (ret == EFI_SUCCESS) {
+		file->close(file);
+		print(u"Overwrite existing file (y/n)? ");
+		ret = efi_input_yn();
+		print(u"\r\n");
+		if (ret != EFI_SUCCESS) {
+			root->close(root);
+			error(u"Aborted by user\r\n");
+			return ret;
+		}
+	}
+
+	/* Create file */
+	ret = root->open(root, &file, filename,
+			 EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE |
+			 EFI_FILE_MODE_CREATE, EFI_FILE_ARCHIVE);
+	if (ret == EFI_SUCCESS) {
+		/* Write file */
+		ret = file->write(file, &dtb_size, dtb);
+		if (ret != EFI_SUCCESS)
+			error(u"Failed to write file\r\n");
+		file->close(file);
+	} else {
+		error(u"Failed to open file\r\n");
+	}
+	root->close(root);
+
+	if (ret == EFI_SUCCESS) {
+		print(filename);
+		print(u" written\r\n");
+	}
+
+	return ret;
+}
+
+/**
+ * efi_main() - entry point of the EFI application.
+ *
+ * @handle:	handle of the loaded image
+ * @systab:	system table
+ * Return:	status code
+ */
+efi_status_t EFIAPI efi_main(efi_handle_t image_handle,
+			     struct efi_system_table *systab)
+{
+	handle = image_handle;
+	systable = systab;
+	cerr = systable->std_err;
+	cout = systable->con_out;
+	cin = systable->con_in;
+	bs = systable->boottime;
+
+	cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
+	cout->clear_screen(cout);
+	cout->set_attribute(cout, EFI_WHITE | EFI_BACKGROUND_BLACK);
+	print(u"DTB Dump\r\n========\r\n\r\n");
+	cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
+
+	for (;;) {
+		u16 command[BUFFER_SIZE];
+		u16 *pos;
+		efi_uintn_t ret;
+
+		print(u"=> ");
+		ret = efi_input(command, sizeof(command));
+		if (ret == EFI_ABORTED)
+			break;
+		pos = skip_whitespace(command);
+		if (starts_with(pos, u"exit"))
+			break;
+		else if (starts_with(pos, u"load "))
+			do_load(pos + 5);
+		else if (starts_with(pos, u"save "))
+			do_save(pos + 5);
+		else
+			do_help();
+	}
+
+	cout->set_attribute(cout, EFI_LIGHTGRAY | EFI_BACKGROUND_BLACK);
+	cout->clear_screen(cout);
+	return EFI_SUCCESS;
+}
diff --git a/lib/efi_loader/initrddump.c b/lib/efi_loader/initrddump.c
new file mode 100644
index 0000000000..7de43bcfff
--- /dev/null
+++ b/lib/efi_loader/initrddump.c
@@ -0,0 +1,449 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2020, Heinrich Schuchardt <xypron.glpk@gmx.de>
+ *
+ * initrddump.efi saves the initial RAM disk provided via the
+ * EFI_LOAD_FILE2_PROTOCOL.
+ */
+
+#include <common.h>
+#include <efi_api.h>
+#include <efi_load_initrd.h>
+
+#define BUFFER_SIZE 64
+#define ESC 0x17
+
+#define efi_size_in_pages(size) (((size) + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT)
+
+static struct efi_system_table *systable;
+static struct efi_boot_services *bs;
+static struct efi_simple_text_output_protocol *cerr;
+static struct efi_simple_text_output_protocol *cout;
+static struct efi_simple_text_input_protocol *cin;
+static const efi_guid_t loaded_image_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
+static const efi_guid_t guid_simple_file_system_protocol =
+					EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
+static const efi_guid_t load_file2_guid = EFI_LOAD_FILE2_PROTOCOL_GUID;
+static efi_handle_t handle;
+
+/*
+ * Device path defined by Linux to identify the handle providing the
+ * EFI_LOAD_FILE2_PROTOCOL used for loading the initial ramdisk.
+ */
+static const struct efi_initrd_dp initrd_dp = {
+	.vendor = {
+		{
+		   DEVICE_PATH_TYPE_MEDIA_DEVICE,
+		   DEVICE_PATH_SUB_TYPE_VENDOR_PATH,
+		   sizeof(initrd_dp.vendor),
+		},
+		EFI_INITRD_MEDIA_GUID,
+	},
+	.end = {
+		DEVICE_PATH_TYPE_END,
+		DEVICE_PATH_SUB_TYPE_END,
+		sizeof(initrd_dp.end),
+	}
+};
+
+/**
+ * print() - print string
+ *
+ * @string:	text
+ */
+static void print(u16 *string)
+{
+	cout->output_string(cout, string);
+}
+
+/**
+ * error() - print error string
+ *
+ * @string:	error text
+ */
+static void error(u16 *string)
+{
+	cout->set_attribute(cout, EFI_LIGHTRED | EFI_BACKGROUND_BLACK);
+	print(string);
+	cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
+}
+
+/*
+ * printx() - print hexadecimal number
+ *
+ * @val:	value to print;
+ * @prec:	minimum number of digits to print
+ */
+static void printx(u64 val, u32 prec)
+{
+	int i;
+	u16 c;
+	u16 buf[16];
+	u16 *pos = buf;
+
+	for (i = 2 * sizeof(val) - 1; i >= 0; --i) {
+		c = (val >> (4 * i)) & 0x0f;
+		if (c || pos != buf || !i || i < prec) {
+			c += '0';
+			if (c > '9')
+				c += 'a' - '9' - 1;
+			*pos++ = c;
+		}
+	}
+	*pos = 0;
+	print(buf);
+}
+
+/**
+ * efi_input_yn() - get answer to yes/no question
+ *
+ * Return:
+ * y or Y
+ *     EFI_SUCCESS
+ * n or N
+ *     EFI_ACCESS_DENIED
+ * ESC
+ *     EFI_ABORTED
+ */
+static efi_status_t efi_input_yn(void)
+{
+	struct efi_input_key key = {0};
+	efi_uintn_t index;
+	efi_status_t ret;
+
+	/* Drain the console input */
+	ret = cin->reset(cin, true);
+	for (;;) {
+		ret = bs->wait_for_event(1, &cin->wait_for_key, &index);
+		if (ret != EFI_SUCCESS)
+			continue;
+		ret = cin->read_key_stroke(cin, &key);
+		if (ret != EFI_SUCCESS)
+			continue;
+		switch (key.scan_code) {
+		case 0x17: /* Escape */
+			return EFI_ABORTED;
+		default:
+			break;
+		}
+		/* Convert to lower case */
+		switch (key.unicode_char | 0x20) {
+		case 'y':
+			return EFI_SUCCESS;
+		case 'n':
+			return EFI_ACCESS_DENIED;
+		default:
+			break;
+		}
+	}
+}
+
+/**
+ * efi_input() - read string from console
+ *
+ * @buffer:		input buffer
+ * @buffer_size:	buffer size
+ * Return:		status code
+ */
+static efi_status_t efi_input(u16 *buffer, efi_uintn_t buffer_size)
+{
+	struct efi_input_key key = {0};
+	efi_uintn_t index;
+	efi_uintn_t pos = 0;
+	u16 outbuf[2] = u" ";
+	efi_status_t ret;
+
+	/* Drain the console input */
+	ret = cin->reset(cin, true);
+	*buffer = 0;
+	for (;;) {
+		ret = bs->wait_for_event(1, &cin->wait_for_key, &index);
+		if (ret != EFI_SUCCESS)
+			continue;
+		ret = cin->read_key_stroke(cin, &key);
+		if (ret != EFI_SUCCESS)
+			continue;
+		switch (key.scan_code) {
+		case 0x17: /* Escape */
+			print(u"\r\nAborted\r\n");
+			return EFI_ABORTED;
+		default:
+			break;
+		}
+		switch (key.unicode_char) {
+		case 0x08: /* Backspace */
+			if (pos) {
+				buffer[pos--] = 0;
+				print(u"\b \b");
+			}
+			break;
+		case 0x0a: /* Linefeed */
+		case 0x0d: /* Carriage return */
+			print(u"\r\n");
+			return EFI_SUCCESS;
+		default:
+			break;
+		}
+		/* Ignore surrogate codes */
+		if (key.unicode_char >= 0xD800 && key.unicode_char <= 0xDBFF)
+			continue;
+		if (key.unicode_char >= 0x20 &&
+		    pos < buffer_size - 1) {
+			*outbuf = key.unicode_char;
+			buffer[pos++] = key.unicode_char;
+			buffer[pos] = 0;
+			print(outbuf);
+		}
+	}
+}
+
+/**
+ * skip_whitespace() - skip over leading whitespace
+ *
+ * @pos:	UTF-16 string
+ * Return:	pointer to first non-whitespace
+ */
+static u16 *skip_whitespace(u16 *pos)
+{
+	for (; *pos && *pos <= 0x20; ++pos)
+		;
+	return pos;
+}
+
+/**
+ * starts_with() - check if @string starts with @keyword
+ *
+ * @string:	string to search for keyword
+ * @keyword:	keyword to be searched
+ * Return:	true fi @string starts with the keyword
+ */
+static bool starts_with(u16 *string, u16 *keyword)
+{
+	for (; *keyword; ++string, ++keyword) {
+		if (*string != *keyword)
+			return false;
+	}
+	return true;
+}
+
+/**
+ * do_help() - print help
+ */
+static void do_help(void)
+{
+	error(u"load          - show length and CRC32 of initial RAM disk\r\n");
+	error(u"save <initrd> - save initial RAM disk to file\r\n");
+	error(u"exit          - exit the shell\r\n");
+}
+
+/**
+ * get_initrd() - read initial RAM disk via EFI_LOAD_FILE2_PROTOCOL
+ *
+ * @initrd:		on return buffer with initial RAM disk
+ * @initrd_size:	size of initial RAM disk
+ * Return:		status code
+ */
+static efi_status_t get_initrd(void **initrd, efi_uintn_t *initrd_size)
+{
+	struct efi_device_path *dp = (struct efi_device_path *)&initrd_dp;
+	struct efi_load_file_protocol *load_file2_prot;
+	u64 buffer;
+	efi_handle_t handle;
+	efi_status_t ret;
+
+	*initrd = NULL;
+	*initrd_size = 0;
+	ret = bs->locate_device_path(&load_file2_guid, &dp, &handle);
+	if (ret != EFI_SUCCESS) {
+		error(u"Load File2 protocol not found\r\n");
+		return ret;
+	}
+	ret = bs->handle_protocol(handle, &load_file2_guid,
+				 (void **)&load_file2_prot);
+	ret = load_file2_prot->load_file(load_file2_prot, dp, false,
+					 initrd_size, NULL);
+	if (ret != EFI_BUFFER_TOO_SMALL) {
+		error(u"Load File2 protocol does not provide file length\r\n");
+		return EFI_LOAD_ERROR;
+	}
+	ret = bs->allocate_pages(EFI_ALLOCATE_ANY_PAGES, EFI_LOADER_DATA,
+				 efi_size_in_pages(*initrd_size), &buffer);
+	if (ret != EFI_SUCCESS) {
+		error(u"Out of memory\r\n");
+		return ret;
+	}
+	*initrd = (void *)(uintptr_t)buffer;
+	ret = load_file2_prot->load_file(load_file2_prot, dp, false,
+					 initrd_size, *initrd);
+	if (ret != EFI_SUCCESS) {
+		error(u"Load File2 protocol failed to provide file\r\n");
+		bs->free_pages(buffer, efi_size_in_pages(*initrd_size));
+		return EFI_LOAD_ERROR;
+	}
+	return ret;
+}
+
+/**
+ * do_load() - load initial RAM disk and display CRC32 and length
+ *
+ * @filename:	file name
+ * Return:	status code
+ */
+static efi_status_t do_load(void)
+{
+	void *initrd;
+	efi_uintn_t initrd_size;
+	u32 crc32;
+	efi_uintn_t ret;
+
+	ret =  get_initrd(&initrd, &initrd_size);
+	if (ret != EFI_SUCCESS)
+		return ret;
+	print(u"length: 0x");
+	printx(initrd_size, 1);
+	print(u"\r\n");
+
+	ret = bs->calculate_crc32(initrd, initrd_size, &crc32);
+	if (ret != EFI_SUCCESS) {
+		error(u"Calculating CRC32 failed\r\n");
+		return EFI_LOAD_ERROR;
+	}
+	print(u"crc32: 0x");
+	printx(crc32, 8);
+	print(u"\r\n");
+
+	return EFI_SUCCESS;
+}
+
+/**
+ * do_save() - save initial RAM disk
+ *
+ * @filename:	file name
+ * Return:	status code
+ */
+static efi_status_t do_save(u16 *filename)
+{
+	struct efi_loaded_image *loaded_image;
+	struct efi_simple_file_system_protocol *file_system;
+	struct efi_file_handle *root, *file;
+	void *initrd;
+	efi_uintn_t initrd_size;
+	efi_uintn_t ret;
+
+	ret = get_initrd(&initrd, &initrd_size);
+	if (ret != EFI_SUCCESS)
+		return ret;
+
+	filename = skip_whitespace(filename);
+
+	ret = bs->open_protocol(handle, &loaded_image_guid,
+				(void **)&loaded_image, NULL, NULL,
+				EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+	if (ret != EFI_SUCCESS) {
+		error(u"Loaded image protocol not found\r\n");
+		goto out;
+	}
+
+	/* Open the simple file system protocol */
+	ret = bs->open_protocol(loaded_image->device_handle,
+				&guid_simple_file_system_protocol,
+				(void **)&file_system, NULL, NULL,
+				EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+	if (ret != EFI_SUCCESS) {
+		error(u"Failed to open simple file system protocol\r\n");
+		goto out;
+	}
+
+	/* Open volume */
+	ret = file_system->open_volume(file_system, &root);
+	if (ret != EFI_SUCCESS) {
+		error(u"Failed to open volume\r\n");
+		goto out;
+	}
+	/* Check if file already exists */
+	ret = root->open(root, &file, filename, EFI_FILE_MODE_READ, 0);
+	if (ret == EFI_SUCCESS) {
+		file->close(file);
+		print(u"Overwrite existing file (y/n)? ");
+		ret = efi_input_yn();
+		print(u"\r\n");
+		if (ret != EFI_SUCCESS) {
+			root->close(root);
+			error(u"Aborted by user\r\n");
+			goto out;
+		}
+	}
+
+	/* Create file */
+	ret = root->open(root, &file, filename,
+			 EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE |
+			 EFI_FILE_MODE_CREATE, EFI_FILE_ARCHIVE);
+	if (ret == EFI_SUCCESS) {
+		/* Write file */
+		ret = file->write(file, &initrd_size, initrd);
+		if (ret != EFI_SUCCESS) {
+			error(u"Failed to write file\r\n");
+		} else {
+			print(filename);
+			print(u" written\r\n");
+		}
+		file->close(file);
+	} else {
+		error(u"Failed to open file\r\n");
+	}
+	root->close(root);
+
+out:
+	if (initrd)
+		bs->free_pages((uintptr_t)initrd,
+			       efi_size_in_pages(initrd_size));
+	return ret;
+}
+
+/**
+ * efi_main() - entry point of the EFI application.
+ *
+ * @handle:	handle of the loaded image
+ * @systab:	system table
+ * Return:	status code
+ */
+efi_status_t EFIAPI efi_main(efi_handle_t image_handle,
+			     struct efi_system_table *systab)
+{
+	handle = image_handle;
+	systable = systab;
+	cerr = systable->std_err;
+	cout = systable->con_out;
+	cin = systable->con_in;
+	bs = systable->boottime;
+
+	cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
+	cout->clear_screen(cout);
+	cout->set_attribute(cout, EFI_WHITE | EFI_BACKGROUND_BLACK);
+	print(u"INITRD Dump\r\n===========\r\n\r\n");
+	cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
+
+	for (;;) {
+		u16 command[BUFFER_SIZE];
+		u16 *pos;
+		efi_uintn_t ret;
+
+		print(u"=> ");
+		ret = efi_input(command, sizeof(command));
+		if (ret == EFI_ABORTED)
+			break;
+		pos = skip_whitespace(command);
+		if (starts_with(pos, u"exit"))
+			break;
+		else if (starts_with(pos, u"load"))
+			do_load();
+		else if (starts_with(pos, u"save "))
+			do_save(pos + 5);
+		else
+			do_help();
+	}
+
+	cout->set_attribute(cout, EFI_LIGHTGRAY | EFI_BACKGROUND_BLACK);
+	cout->clear_screen(cout);
+	return EFI_SUCCESS;
+}
diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile
index 9ff6e1760c..be8040d1c7 100644
--- a/lib/efi_selftest/Makefile
+++ b/lib/efi_selftest/Makefile
@@ -8,16 +8,12 @@
 asflags-y += -DHOST_ARCH="$(HOST_ARCH)"
 ccflags-y += -DHOST_ARCH="$(HOST_ARCH)"
 
-CFLAGS_dtbdump.o := $(CFLAGS_EFI) -Os -ffreestanding
-CFLAGS_REMOVE_dtbdump.o := $(CFLAGS_NON_EFI)
 CFLAGS_efi_selftest_miniapp_exception.o := $(CFLAGS_EFI) -Os -ffreestanding
 CFLAGS_REMOVE_efi_selftest_miniapp_exception.o := $(CFLAGS_NON_EFI)
 CFLAGS_efi_selftest_miniapp_exit.o := $(CFLAGS_EFI) -Os -ffreestanding
 CFLAGS_REMOVE_efi_selftest_miniapp_exit.o := $(CFLAGS_NON_EFI)
 CFLAGS_efi_selftest_miniapp_return.o := $(CFLAGS_EFI) -Os -ffreestanding
 CFLAGS_REMOVE_efi_selftest_miniapp_return.o := $(CFLAGS_NON_EFI)
-CFLAGS_initrddump_exit.o := $(CFLAGS_EFI) -Os -ffreestanding
-CFLAGS_REMOVE_initrddump.o := $(CFLAGS_NON_EFI)
 
 obj-y += \
 efi_selftest.o \
@@ -83,14 +79,6 @@ efi_selftest_miniapp_exception.efi \
 efi_selftest_miniapp_exit.efi \
 efi_selftest_miniapp_return.efi
 
-ifeq ($(CONFIG_GENERATE_ACPI_TABLE),)
-always += dtbdump.efi
-endif
-
-ifdef CONFIG_EFI_LOAD_FILE2_INITRD
-always += initrddump.efi
-endif
-
 $(obj)/efi_miniapp_file_image_exception.h: $(obj)/efi_selftest_miniapp_exception.efi
 	$(obj)/../../tools/file2include $(obj)/efi_selftest_miniapp_exception.efi > \
 	$(obj)/efi_miniapp_file_image_exception.h
diff --git a/lib/efi_selftest/dtbdump.c b/lib/efi_selftest/dtbdump.c
deleted file mode 100644
index 3ce2a07f9e..0000000000
--- a/lib/efi_selftest/dtbdump.c
+++ /dev/null
@@ -1,539 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright 2020, Heinrich Schuchardt <xypron.glpk@gmx.de>
- *
- * dtbdump.efi saves the device tree provided as a configuration table
- * to a file.
- */
-
-#include <common.h>
-#include <efi_api.h>
-#include <efi_dt_fixup.h>
-#include <part.h>
-#include <linux/libfdt.h>
-
-#define BUFFER_SIZE 64
-#define ESC 0x17
-
-#define efi_size_in_pages(size) ((size + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT)
-
-static struct efi_simple_text_output_protocol *cerr;
-static struct efi_simple_text_output_protocol *cout;
-static struct efi_simple_text_input_protocol *cin;
-static struct efi_boot_services *bs;
-static const efi_guid_t fdt_guid = EFI_FDT_GUID;
-static const efi_guid_t loaded_image_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
-static const efi_guid_t guid_simple_file_system_protocol =
-					EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
-static efi_handle_t handle;
-static struct efi_system_table *systable;
-static const efi_guid_t efi_dt_fixup_protocol_guid = EFI_DT_FIXUP_PROTOCOL_GUID;
-static const efi_guid_t efi_file_info_guid = EFI_FILE_INFO_GUID;
-static const efi_guid_t efi_system_partition_guid = PARTITION_SYSTEM_GUID;
-
-/**
- * print() - print string
- *
- * @string:	text
- */
-static void print(u16 *string)
-{
-	cout->output_string(cout, string);
-}
-
-/**
- * error() - print error string
- *
- * @string:	error text
- */
-static void error(u16 *string)
-{
-	cout->set_attribute(cout, EFI_LIGHTRED | EFI_BACKGROUND_BLACK);
-	print(string);
-	cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
-}
-
-/**
- * efi_input_yn() - get answer to yes/no question
- *
- * Return:
- * y or Y
- *     EFI_SUCCESS
- * n or N
- *     EFI_ACCESS_DENIED
- * ESC
- *     EFI_ABORTED
- */
-static efi_status_t efi_input_yn(void)
-{
-	struct efi_input_key key = {0};
-	efi_uintn_t index;
-	efi_status_t ret;
-
-	/* Drain the console input */
-	ret = cin->reset(cin, true);
-	for (;;) {
-		ret = bs->wait_for_event(1, &cin->wait_for_key, &index);
-		if (ret != EFI_SUCCESS)
-			continue;
-		ret = cin->read_key_stroke(cin, &key);
-		if (ret != EFI_SUCCESS)
-			continue;
-		switch (key.scan_code) {
-		case 0x17: /* Escape */
-			return EFI_ABORTED;
-		default:
-			break;
-		}
-		/* Convert to lower case */
-		switch (key.unicode_char | 0x20) {
-		case 'y':
-			return EFI_SUCCESS;
-		case 'n':
-			return EFI_ACCESS_DENIED;
-		default:
-			break;
-		}
-	}
-}
-
-/**
- * efi_input() - read string from console
- *
- * @buffer:		input buffer
- * @buffer_size:	buffer size
- * Return:		status code
- */
-static efi_status_t efi_input(u16 *buffer, efi_uintn_t buffer_size)
-{
-	struct efi_input_key key = {0};
-	efi_uintn_t index;
-	efi_uintn_t pos = 0;
-	u16 outbuf[2] = u" ";
-	efi_status_t ret;
-
-	/* Drain the console input */
-	ret = cin->reset(cin, true);
-	*buffer = 0;
-	for (;;) {
-		ret = bs->wait_for_event(1, &cin->wait_for_key, &index);
-		if (ret != EFI_SUCCESS)
-			continue;
-		ret = cin->read_key_stroke(cin, &key);
-		if (ret != EFI_SUCCESS)
-			continue;
-		switch (key.scan_code) {
-		case 0x17: /* Escape */
-			print(u"\r\nAborted\r\n");
-			return EFI_ABORTED;
-		default:
-			break;
-		}
-		switch (key.unicode_char) {
-		case 0x08: /* Backspace */
-			if (pos) {
-				buffer[pos--] = 0;
-				print(u"\b \b");
-			}
-			break;
-		case 0x0a: /* Linefeed */
-		case 0x0d: /* Carriage return */
-			print(u"\r\n");
-			return EFI_SUCCESS;
-		default:
-			break;
-		}
-		/* Ignore surrogate codes */
-		if (key.unicode_char >= 0xD800 && key.unicode_char <= 0xDBFF)
-			continue;
-		if (key.unicode_char >= 0x20 &&
-		    pos < buffer_size - 1) {
-			*outbuf = key.unicode_char;
-			buffer[pos++] = key.unicode_char;
-			buffer[pos] = 0;
-			print(outbuf);
-		}
-	}
-}
-
-/*
- * Convert FDT value to host endianness.
- *
- * @val		FDT value
- * Return:	converted value
- */
-static u32 f2h(fdt32_t val)
-{
-	char *buf = (char *)&val;
-	char i;
-
-	/* Swap the bytes */
-	i = buf[0]; buf[0] = buf[3]; buf[3] = i;
-	i = buf[1]; buf[1] = buf[2]; buf[2] = i;
-	return *(u32 *)buf;
-}
-
-/**
- * get_dtb() - get device tree
- *
- * @systable:	system table
- * Return:	device tree or NULL
- */
-void *get_dtb(struct efi_system_table *systable)
-{
-	void *dtb = NULL;
-	efi_uintn_t i;
-
-	for (i = 0; i < systable->nr_tables; ++i) {
-		if (!memcmp(&systable->tables[i].guid, &fdt_guid,
-			    sizeof(efi_guid_t))) {
-			dtb = systable->tables[i].table;
-			break;
-		}
-	}
-	return dtb;
-}
-
-/**
- * skip_whitespace() - skip over leading whitespace
- *
- * @pos:	UTF-16 string
- * Return:	pointer to first non-whitespace
- */
-u16 *skip_whitespace(u16 *pos)
-{
-	for (; *pos && *pos <= 0x20; ++pos)
-		;
-	return pos;
-}
-
-/**
- * starts_with() - check if @string starts with @keyword
- *
- * @string:	string to search for keyword
- * @keyword:	keyword to be searched
- * Return:	true fi @string starts with the keyword
- */
-bool starts_with(u16 *string, u16 *keyword)
-{
-	for (; *keyword; ++string, ++keyword) {
-		if (*string != *keyword)
-			return false;
-	}
-	return true;
-}
-
-/**
- * do_help() - print help
- */
-void do_help(void)
-{
-	error(u"load <dtb> - load device-tree from file\r\n");
-	error(u"save <dtb> - save device-tree to file\r\n");
-	error(u"exit       - exit the shell\r\n");
-}
-
-/**
- * open_file_system() - open simple file system protocol
- *
- * file_system:	interface of the simple file system protocol
- * Return:	status code
- */
-static efi_status_t
-open_file_system(struct efi_simple_file_system_protocol **file_system)
-{
-	struct efi_loaded_image *loaded_image;
-	efi_status_t ret;
-	efi_handle_t *handle_buffer = NULL;
-	efi_uintn_t count;
-
-	ret = bs->open_protocol(handle, &loaded_image_guid,
-				(void **)&loaded_image, NULL, NULL,
-				EFI_OPEN_PROTOCOL_GET_PROTOCOL);
-	if (ret != EFI_SUCCESS) {
-		error(u"Loaded image protocol not found\r\n");
-		return ret;
-	}
-
-	/* Open the simple file system protocol on the same partition */
-	ret = bs->open_protocol(loaded_image->device_handle,
-				&guid_simple_file_system_protocol,
-				(void **)file_system, NULL, NULL,
-				EFI_OPEN_PROTOCOL_GET_PROTOCOL);
-	if (ret == EFI_SUCCESS)
-		return ret;
-
-	/* Open the simple file system protocol on the UEFI system partition */
-	ret = bs->locate_handle_buffer(BY_PROTOCOL, &efi_system_partition_guid,
-				       NULL, &count, &handle_buffer);
-	if (ret == EFI_SUCCESS && handle_buffer)
-		ret = bs->open_protocol(handle_buffer[0],
-					&guid_simple_file_system_protocol,
-					(void **)file_system, NULL, NULL,
-					EFI_OPEN_PROTOCOL_GET_PROTOCOL);
-	if (ret != EFI_SUCCESS)
-		error(u"Failed to open simple file system protocol\r\n");
-	if (handle)
-		bs->free_pool(handle_buffer);
-
-	return ret;
-}
-
-/**
- * do_load() - load and install device-tree
- *
- * @filename:	file name
- * Return:	status code
- */
-efi_status_t do_load(u16 *filename)
-{
-	struct efi_dt_fixup_protocol *dt_fixup_prot;
-	struct efi_simple_file_system_protocol *file_system;
-	struct efi_file_handle *root = NULL, *file = NULL;
-	u64 addr = 0;
-	struct efi_file_info *info;
-	struct fdt_header *dtb;
-	efi_uintn_t buffer_size;
-	efi_uintn_t pages;
-	efi_status_t ret, ret2;
-
-	ret = bs->locate_protocol(&efi_dt_fixup_protocol_guid, NULL,
-				  (void **)&dt_fixup_prot);
-	if (ret != EFI_SUCCESS) {
-		error(u"Device-tree fix-up protocol not found\r\n");
-		return ret;
-	}
-
-	filename = skip_whitespace(filename);
-
-	ret = open_file_system(&file_system);
-	if (ret != EFI_SUCCESS)
-		goto out;
-
-	/* Open volume */
-	ret = file_system->open_volume(file_system, &root);
-	if (ret != EFI_SUCCESS) {
-		error(u"Failed to open volume\r\n");
-		goto out;
-	}
-
-	/* Open file */
-	ret = root->open(root, &file, filename, EFI_FILE_MODE_READ, 0);
-	if (ret != EFI_SUCCESS) {
-		error(u"File not found\r\n");
-		goto out;
-	}
-	/* Get file size */
-	buffer_size = 0;
-	ret = file->getinfo(file, &efi_file_info_guid, &buffer_size, NULL);
-	if (ret != EFI_BUFFER_TOO_SMALL) {
-		error(u"Can't get file info size\r\n");
-		goto out;
-	}
-	ret = bs->allocate_pool(EFI_LOADER_DATA, buffer_size, (void **)&info);
-	if (ret != EFI_SUCCESS) {
-		error(u"Out of memory\r\n");
-		goto out;
-	}
-	ret = file->getinfo(file, &efi_file_info_guid, &buffer_size, info);
-	if (ret != EFI_SUCCESS) {
-		error(u"Can't get file info\r\n");
-		goto out;
-	}
-	buffer_size = info->file_size;
-	pages = efi_size_in_pages(buffer_size);
-	ret = bs->free_pool(info);
-	if (ret != EFI_SUCCESS)
-		error(u"Can't free memory pool\r\n");
-	/* Read file */
-	ret = bs->allocate_pages(EFI_ALLOCATE_ANY_PAGES,
-				 EFI_ACPI_RECLAIM_MEMORY,
-				 pages, &addr);
-	if (ret != EFI_SUCCESS) {
-		error(u"Out of memory\r\n");
-		goto out;
-	}
-	dtb = (struct fdt_header *)(uintptr_t)addr;
-	ret = file->read(file, &buffer_size, dtb);
-	if (ret != EFI_SUCCESS) {
-		error(u"Can't read file\r\n");
-		goto out;
-	}
-	/* Fixup file, expecting EFI_BUFFER_TOO_SMALL */
-	ret = dt_fixup_prot->fixup(dt_fixup_prot, dtb, &buffer_size,
-				   EFI_DT_APPLY_FIXUPS | EFI_DT_RESERVE_MEMORY |
-				   EFI_DT_INSTALL_TABLE);
-	if (ret == EFI_BUFFER_TOO_SMALL) {
-		/* Read file into larger buffer */
-		ret = bs->free_pages(addr, pages);
-		if (ret != EFI_SUCCESS)
-			error(u"Can't free memory pages\r\n");
-		pages = efi_size_in_pages(buffer_size);
-		ret = bs->allocate_pages(EFI_ALLOCATE_ANY_PAGES,
-					 EFI_ACPI_RECLAIM_MEMORY,
-					 pages, &addr);
-		if (ret != EFI_SUCCESS) {
-			error(u"Out of memory\r\n");
-			goto out;
-		}
-		dtb = (struct fdt_header *)(uintptr_t)addr;
-		ret = file->setpos(file, 0);
-		if (ret != EFI_SUCCESS) {
-			error(u"Can't position file\r\n");
-			goto out;
-		}
-		ret = file->read(file, &buffer_size, dtb);
-		if (ret != EFI_SUCCESS) {
-			error(u"Can't read file\r\n");
-			goto out;
-		}
-		buffer_size = pages << EFI_PAGE_SHIFT;
-		ret = dt_fixup_prot->fixup(
-				dt_fixup_prot, dtb, &buffer_size,
-				EFI_DT_APPLY_FIXUPS | EFI_DT_RESERVE_MEMORY |
-				EFI_DT_INSTALL_TABLE);
-	}
-	if (ret == EFI_SUCCESS)
-		print(u"device-tree installed\r\n");
-	else
-		error(u"Device-tree fix-up failed\r\n");
-out:
-	if (addr) {
-		ret2 = bs->free_pages(addr, pages);
-		if (ret2 != EFI_SUCCESS)
-			error(u"Can't free memory pages\r\n");
-	}
-	if (file) {
-		ret2 = file->close(file);
-		if (ret2 != EFI_SUCCESS)
-			error(u"Can't close file\r\n");
-	}
-	if (root) {
-		ret2 = root->close(root);
-		if (ret2 != EFI_SUCCESS)
-			error(u"Can't close volume\r\n");
-	}
-	return ret;
-}
-
-/**
- * do_save() - save current device-tree
- *
- * @filename:	file name
- * Return:	status code
- */
-efi_status_t do_save(u16 *filename)
-{
-	struct efi_simple_file_system_protocol *file_system;
-	efi_uintn_t dtb_size;
-	struct efi_file_handle *root, *file;
-	struct fdt_header *dtb;
-	efi_uintn_t ret;
-
-	dtb = get_dtb(systable);
-	if (!dtb) {
-		error(u"DTB not found\r\n");
-		return EFI_NOT_FOUND;
-	}
-	if (f2h(dtb->magic) != FDT_MAGIC) {
-		error(u"Wrong device tree magic\r\n");
-		return EFI_NOT_FOUND;
-	}
-	dtb_size = f2h(dtb->totalsize);
-
-	filename = skip_whitespace(filename);
-
-	ret = open_file_system(&file_system);
-	if (ret != EFI_SUCCESS)
-		return ret;
-
-	/* Open volume */
-	ret = file_system->open_volume(file_system, &root);
-	if (ret != EFI_SUCCESS) {
-		error(u"Failed to open volume\r\n");
-		return ret;
-	}
-	/* Check if file already exists */
-	ret = root->open(root, &file, filename, EFI_FILE_MODE_READ, 0);
-	if (ret == EFI_SUCCESS) {
-		file->close(file);
-		print(u"Overwrite existing file (y/n)? ");
-		ret = efi_input_yn();
-		print(u"\r\n");
-		if (ret != EFI_SUCCESS) {
-			root->close(root);
-			error(u"Aborted by user\r\n");
-			return ret;
-		}
-	}
-
-	/* Create file */
-	ret = root->open(root, &file, filename,
-			 EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE |
-			 EFI_FILE_MODE_CREATE, EFI_FILE_ARCHIVE);
-	if (ret == EFI_SUCCESS) {
-		/* Write file */
-		ret = file->write(file, &dtb_size, dtb);
-		if (ret != EFI_SUCCESS)
-			error(u"Failed to write file\r\n");
-		file->close(file);
-	} else {
-		error(u"Failed to open file\r\n");
-	}
-	root->close(root);
-
-	if (ret == EFI_SUCCESS) {
-		print(filename);
-		print(u" written\r\n");
-	}
-
-	return ret;
-}
-
-/**
- * efi_main() - entry point of the EFI application.
- *
- * @handle:	handle of the loaded image
- * @systab:	system table
- * Return:	status code
- */
-efi_status_t EFIAPI efi_main(efi_handle_t image_handle,
-			     struct efi_system_table *systab)
-{
-	handle = image_handle;
-	systable = systab;
-	cerr = systable->std_err;
-	cout = systable->con_out;
-	cin = systable->con_in;
-	bs = systable->boottime;
-
-	cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
-	cout->clear_screen(cout);
-	cout->set_attribute(cout, EFI_WHITE | EFI_BACKGROUND_BLACK);
-	print(u"DTB Dump\r\n========\r\n\r\n");
-	cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
-
-	for (;;) {
-		u16 command[BUFFER_SIZE];
-		u16 *pos;
-		efi_uintn_t ret;
-
-		print(u"=> ");
-		ret = efi_input(command, sizeof(command));
-		if (ret == EFI_ABORTED)
-			break;
-		pos = skip_whitespace(command);
-		if (starts_with(pos, u"exit"))
-			break;
-		else if (starts_with(pos, u"load "))
-			do_load(pos + 5);
-		else if (starts_with(pos, u"save "))
-			do_save(pos + 5);
-		else
-			do_help();
-	}
-
-	cout->set_attribute(cout, EFI_LIGHTGRAY | EFI_BACKGROUND_BLACK);
-	cout->clear_screen(cout);
-	return EFI_SUCCESS;
-}
diff --git a/lib/efi_selftest/initrddump.c b/lib/efi_selftest/initrddump.c
deleted file mode 100644
index 4648d54b13..0000000000
--- a/lib/efi_selftest/initrddump.c
+++ /dev/null
@@ -1,449 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright 2020, Heinrich Schuchardt <xypron.glpk@gmx.de>
- *
- * initrddump.efi saves the initial RAM disk provided via the
- * EFI_LOAD_FILE2_PROTOCOL.
- */
-
-#include <common.h>
-#include <efi_api.h>
-#include <efi_load_initrd.h>
-
-#define BUFFER_SIZE 64
-#define ESC 0x17
-
-#define efi_size_in_pages(size) (((size) + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT)
-
-static struct efi_system_table *systable;
-static struct efi_boot_services *bs;
-static struct efi_simple_text_output_protocol *cerr;
-static struct efi_simple_text_output_protocol *cout;
-static struct efi_simple_text_input_protocol *cin;
-static const efi_guid_t loaded_image_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
-static const efi_guid_t guid_simple_file_system_protocol =
-					EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
-static const efi_guid_t load_file2_guid = EFI_LOAD_FILE2_PROTOCOL_GUID;
-static efi_handle_t handle;
-
-/*
- * Device path defined by Linux to identify the handle providing the
- * EFI_LOAD_FILE2_PROTOCOL used for loading the initial ramdisk.
- */
-static const struct efi_initrd_dp initrd_dp = {
-	.vendor = {
-		{
-		   DEVICE_PATH_TYPE_MEDIA_DEVICE,
-		   DEVICE_PATH_SUB_TYPE_VENDOR_PATH,
-		   sizeof(initrd_dp.vendor),
-		},
-		EFI_INITRD_MEDIA_GUID,
-	},
-	.end = {
-		DEVICE_PATH_TYPE_END,
-		DEVICE_PATH_SUB_TYPE_END,
-		sizeof(initrd_dp.end),
-	}
-};
-
-/**
- * print() - print string
- *
- * @string:	text
- */
-static void print(u16 *string)
-{
-	cout->output_string(cout, string);
-}
-
-/**
- * error() - print error string
- *
- * @string:	error text
- */
-static void error(u16 *string)
-{
-	cout->set_attribute(cout, EFI_LIGHTRED | EFI_BACKGROUND_BLACK);
-	print(string);
-	cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
-}
-
-/*
- * printx() - print hexadecimal number
- *
- * @val:	value to print;
- * @prec:	minimum number of digits to print
- */
-static void printx(u64 val, u32 prec)
-{
-	int i;
-	u16 c;
-	u16 buf[16];
-	u16 *pos = buf;
-
-	for (i = 2 * sizeof(val) - 1; i >= 0; --i) {
-		c = (val >> (4 * i)) & 0x0f;
-		if (c || pos != buf || !i || i < prec) {
-			c += '0';
-			if (c > '9')
-				c += 'a' - '9' - 1;
-			*pos++ = c;
-		}
-	}
-	*pos = 0;
-	print(buf);
-}
-
-/**
- * efi_input_yn() - get answer to yes/no question
- *
- * Return:
- * y or Y
- *     EFI_SUCCESS
- * n or N
- *     EFI_ACCESS_DENIED
- * ESC
- *     EFI_ABORTED
- */
-static efi_status_t efi_input_yn(void)
-{
-	struct efi_input_key key = {0};
-	efi_uintn_t index;
-	efi_status_t ret;
-
-	/* Drain the console input */
-	ret = cin->reset(cin, true);
-	for (;;) {
-		ret = bs->wait_for_event(1, &cin->wait_for_key, &index);
-		if (ret != EFI_SUCCESS)
-			continue;
-		ret = cin->read_key_stroke(cin, &key);
-		if (ret != EFI_SUCCESS)
-			continue;
-		switch (key.scan_code) {
-		case 0x17: /* Escape */
-			return EFI_ABORTED;
-		default:
-			break;
-		}
-		/* Convert to lower case */
-		switch (key.unicode_char | 0x20) {
-		case 'y':
-			return EFI_SUCCESS;
-		case 'n':
-			return EFI_ACCESS_DENIED;
-		default:
-			break;
-		}
-	}
-}
-
-/**
- * efi_input() - read string from console
- *
- * @buffer:		input buffer
- * @buffer_size:	buffer size
- * Return:		status code
- */
-static efi_status_t efi_input(u16 *buffer, efi_uintn_t buffer_size)
-{
-	struct efi_input_key key = {0};
-	efi_uintn_t index;
-	efi_uintn_t pos = 0;
-	u16 outbuf[2] = u" ";
-	efi_status_t ret;
-
-	/* Drain the console input */
-	ret = cin->reset(cin, true);
-	*buffer = 0;
-	for (;;) {
-		ret = bs->wait_for_event(1, &cin->wait_for_key, &index);
-		if (ret != EFI_SUCCESS)
-			continue;
-		ret = cin->read_key_stroke(cin, &key);
-		if (ret != EFI_SUCCESS)
-			continue;
-		switch (key.scan_code) {
-		case 0x17: /* Escape */
-			print(u"\r\nAborted\r\n");
-			return EFI_ABORTED;
-		default:
-			break;
-		}
-		switch (key.unicode_char) {
-		case 0x08: /* Backspace */
-			if (pos) {
-				buffer[pos--] = 0;
-				print(u"\b \b");
-			}
-			break;
-		case 0x0a: /* Linefeed */
-		case 0x0d: /* Carriage return */
-			print(u"\r\n");
-			return EFI_SUCCESS;
-		default:
-			break;
-		}
-		/* Ignore surrogate codes */
-		if (key.unicode_char >= 0xD800 && key.unicode_char <= 0xDBFF)
-			continue;
-		if (key.unicode_char >= 0x20 &&
-		    pos < buffer_size - 1) {
-			*outbuf = key.unicode_char;
-			buffer[pos++] = key.unicode_char;
-			buffer[pos] = 0;
-			print(outbuf);
-		}
-	}
-}
-
-/**
- * skip_whitespace() - skip over leading whitespace
- *
- * @pos:	UTF-16 string
- * Return:	pointer to first non-whitespace
- */
-static u16 *skip_whitespace(u16 *pos)
-{
-	for (; *pos && *pos <= 0x20; ++pos)
-		;
-	return pos;
-}
-
-/**
- * starts_with() - check if @string starts with @keyword
- *
- * @string:	string to search for keyword
- * @keyword:	keyword to be searched
- * Return:	true fi @string starts with the keyword
- */
-static bool starts_with(u16 *string, u16 *keyword)
-{
-	for (; *keyword; ++string, ++keyword) {
-		if (*string != *keyword)
-			return false;
-	}
-	return true;
-}
-
-/**
- * do_help() - print help
- */
-static void do_help(void)
-{
-	error(u"load          - show length and CRC32 of initial RAM disk\r\n");
-	error(u"save <initrd> - save initial RAM disk to file\r\n");
-	error(u"exit          - exit the shell\r\n");
-}
-
-/**
- * get_initrd() - read initial RAM disk via EFI_LOAD_FILE2_PROTOCOL
- *
- * @initrd:		on return buffer with initial RAM disk
- * @initrd_size:	size of initial RAM disk
- * Return:		status code
- */
-static efi_status_t get_initrd(void **initrd, efi_uintn_t *initrd_size)
-{
-	struct efi_device_path *dp = (struct efi_device_path *)&initrd_dp;
-	struct efi_load_file_protocol *load_file2_prot;
-	u64 buffer;
-	efi_handle_t handle;
-	efi_status_t ret;
-
-	*initrd = NULL;
-	*initrd_size = 0;
-	ret = bs->locate_device_path(&load_file2_guid, &dp, &handle);
-	if (ret != EFI_SUCCESS) {
-		error(u"Load File2 protocol not found\r\n");
-		return ret;
-	}
-	ret = bs->handle_protocol(handle, &load_file2_guid,
-				 (void **)&load_file2_prot);
-	ret = load_file2_prot->load_file(load_file2_prot, dp, false,
-					 initrd_size, NULL);
-	if (ret != EFI_BUFFER_TOO_SMALL) {
-		error(u"Load File2 protocol does not provide file length\r\n");
-		return EFI_LOAD_ERROR;
-	}
-	ret = bs->allocate_pages(EFI_ALLOCATE_ANY_PAGES, EFI_LOADER_DATA,
-				 efi_size_in_pages(*initrd_size), &buffer);
-	if (ret != EFI_SUCCESS) {
-		error(u"Out of memory\r\n");
-		return ret;
-	}
-	*initrd = (void *)(uintptr_t)buffer;
-	ret = load_file2_prot->load_file(load_file2_prot, dp, false,
-					 initrd_size, *initrd);
-	if (ret != EFI_SUCCESS) {
-		error(u"Load File2 protocol failed to provide file\r\n");
-		bs->free_pages(buffer, efi_size_in_pages(*initrd_size));
-		return EFI_LOAD_ERROR;
-	}
-	return ret;
-}
-
-/**
- * do_load() - load initial RAM disk and display CRC32 and length
- *
- * @filename:	file name
- * Return:	status code
- */
-static efi_status_t do_load(void)
-{
-	void *initrd;
-	efi_uintn_t initrd_size;
-	u32 crc32;
-	efi_uintn_t ret;
-
-	ret =  get_initrd(&initrd, &initrd_size);
-	if (ret != EFI_SUCCESS)
-		return ret;
-	print(u"length: 0x");
-	printx(initrd_size, 1);
-	print(u"\r\n");
-
-	ret = bs->calculate_crc32(initrd, initrd_size, &crc32);
-	if (ret != EFI_SUCCESS) {
-		error(u"Calculating CRC32 failed\r\n");
-		return EFI_LOAD_ERROR;
-	}
-	print(u"crc32: 0x");
-	printx(crc32, 8);
-	print(u"\r\n");
-
-	return EFI_SUCCESS;
-}
-
-/**
- * do_save() - save initial RAM disk
- *
- * @filename:	file name
- * Return:	status code
- */
-static efi_status_t do_save(u16 *filename)
-{
-	struct efi_loaded_image *loaded_image;
-	struct efi_simple_file_system_protocol *file_system;
-	struct efi_file_handle *root, *file;
-	void *initrd;
-	efi_uintn_t initrd_size;
-	efi_uintn_t ret;
-
-	ret = get_initrd(&initrd, &initrd_size);
-	if (ret != EFI_SUCCESS)
-		return ret;
-
-	filename = skip_whitespace(filename);
-
-	ret = bs->open_protocol(handle, &loaded_image_guid,
-				(void **)&loaded_image, NULL, NULL,
-				EFI_OPEN_PROTOCOL_GET_PROTOCOL);
-	if (ret != EFI_SUCCESS) {
-		error(u"Loaded image protocol not found\r\n");
-		goto out;
-	}
-
-	/* Open the simple file system protocol */
-	ret = bs->open_protocol(loaded_image->device_handle,
-				&guid_simple_file_system_protocol,
-				(void **)&file_system, NULL, NULL,
-				EFI_OPEN_PROTOCOL_GET_PROTOCOL);
-	if (ret != EFI_SUCCESS) {
-		error(u"Failed to open simple file system protocol\r\n");
-		goto out;
-	}
-
-	/* Open volume */
-	ret = file_system->open_volume(file_system, &root);
-	if (ret != EFI_SUCCESS) {
-		error(u"Failed to open volume\r\n");
-		goto out;
-	}
-	/* Check if file already exists */
-	ret = root->open(root, &file, filename, EFI_FILE_MODE_READ, 0);
-	if (ret == EFI_SUCCESS) {
-		file->close(file);
-		print(u"Overwrite existing file (y/n)? ");
-		ret = efi_input_yn();
-		print(u"\r\n");
-		if (ret != EFI_SUCCESS) {
-			root->close(root);
-			error(u"Aborted by user\r\n");
-			goto out;
-		}
-	}
-
-	/* Create file */
-	ret = root->open(root, &file, filename,
-			 EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE |
-			 EFI_FILE_MODE_CREATE, EFI_FILE_ARCHIVE);
-	if (ret == EFI_SUCCESS) {
-		/* Write file */
-		ret = file->write(file, &initrd_size, initrd);
-		if (ret != EFI_SUCCESS) {
-			error(u"Failed to write file\r\n");
-		} else {
-			print(filename);
-			print(u" written\r\n");
-		}
-		file->close(file);
-	} else {
-		error(u"Failed to open file\r\n");
-	}
-	root->close(root);
-
-out:
-	if (initrd)
-		bs->free_pages((uintptr_t)initrd,
-			       efi_size_in_pages(initrd_size));
-	return ret;
-}
-
-/**
- * efi_main() - entry point of the EFI application.
- *
- * @handle:	handle of the loaded image
- * @systab:	system table
- * Return:	status code
- */
-efi_status_t EFIAPI efi_main(efi_handle_t image_handle,
-			     struct efi_system_table *systab)
-{
-	handle = image_handle;
-	systable = systab;
-	cerr = systable->std_err;
-	cout = systable->con_out;
-	cin = systable->con_in;
-	bs = systable->boottime;
-
-	cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
-	cout->clear_screen(cout);
-	cout->set_attribute(cout, EFI_WHITE | EFI_BACKGROUND_BLACK);
-	print(u"INITRD Dump\r\n========\r\n\r\n");
-	cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
-
-	for (;;) {
-		u16 command[BUFFER_SIZE];
-		u16 *pos;
-		efi_uintn_t ret;
-
-		print(u"=> ");
-		ret = efi_input(command, sizeof(command));
-		if (ret == EFI_ABORTED)
-			break;
-		pos = skip_whitespace(command);
-		if (starts_with(pos, u"exit"))
-			break;
-		else if (starts_with(pos, u"load"))
-			do_load();
-		else if (starts_with(pos, u"save "))
-			do_save(pos + 5);
-		else
-			do_help();
-	}
-
-	cout->set_attribute(cout, EFI_LIGHTGRAY | EFI_BACKGROUND_BLACK);
-	cout->clear_screen(cout);
-	return EFI_SUCCESS;
-}
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 9/9] test: test UEFI boot manager
  2022-03-19  9:11 [PATCH v2 0/9] efi_loader: booting via short-form device-path Heinrich Schuchardt
                   ` (7 preceding siblings ...)
  2022-03-19  9:11 ` [PATCH v2 8/9] efi_loader: move dtbdump.c, initrddump.c to lib/efi_loader Heinrich Schuchardt
@ 2022-03-19  9:11 ` Heinrich Schuchardt
  2022-03-25  9:12   ` AKASHI Takahiro
  9 siblings, 0 replies; 19+ messages in thread
From: Heinrich Schuchardt @ 2022-03-19  9:11 UTC (permalink / raw)
  To: u-boot; +Cc: Ilias Apalodimas, AKASHI Takahiro, Heinrich Schuchardt

Provide a unit test for

* efidebug boot add
* efidebug bootmgr
* initrd via EFI_LOAD_FILE2_PROTOCOL

Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
---
v2:
	new patch
---
 test/py/tests/test_efi_bootmgr/conftest.py    | 42 +++++++++++++++++++
 .../test_efi_bootmgr/test_efi_bootmgr.py      | 31 ++++++++++++++
 2 files changed, 73 insertions(+)
 create mode 100644 test/py/tests/test_efi_bootmgr/conftest.py
 create mode 100644 test/py/tests/test_efi_bootmgr/test_efi_bootmgr.py

diff --git a/test/py/tests/test_efi_bootmgr/conftest.py b/test/py/tests/test_efi_bootmgr/conftest.py
new file mode 100644
index 0000000000..69008fddce
--- /dev/null
+++ b/test/py/tests/test_efi_bootmgr/conftest.py
@@ -0,0 +1,42 @@
+# SPDX-License-Identifier:      GPL-2.0+
+
+"""Fixture for UEFI bootmanager test
+"""
+
+import os
+import pytest
+import shutil
+from subprocess import call, check_call
+
+@pytest.fixture(scope='session')
+def efi_bootmgr_data(u_boot_config):
+    """Set up a file system to be used in UEFI bootmanager
+       tests
+
+    Args:
+        u_boot_config: U-boot configuration.
+
+    Return:
+        A path to disk image to be used for testing
+    """
+    mnt_point = u_boot_config.persistent_data_dir + '/test_efi_bootmgr'
+    image_path = u_boot_config.persistent_data_dir + '/efi_bootmgr.img'
+
+    shutil.rmtree(mnt_point, ignore_errors=True)
+    os.mkdir(mnt_point, mode = 0o755)
+
+    with open(mnt_point + '/initrd-1.img', 'w', encoding = 'ascii') as file:
+        file.write("initrd 1")
+
+    with open(mnt_point + '/initrd-2.img', 'w', encoding = 'ascii') as file:
+        file.write("initrd 2")
+
+    shutil.copyfile(u_boot_config.build_dir + '/lib/efi_loader/initrddump.efi',
+                    mnt_point + '/initrddump.efi')
+
+    check_call('virt-make-fs --partition=gpt --size=+1M --type=vfat {} {}'
+               .format(mnt_point, image_path), shell=True)
+
+    print(image_path)
+
+    yield image_path
diff --git a/test/py/tests/test_efi_bootmgr/test_efi_bootmgr.py b/test/py/tests/test_efi_bootmgr/test_efi_bootmgr.py
new file mode 100644
index 0000000000..bf11bbebed
--- /dev/null
+++ b/test/py/tests/test_efi_bootmgr/test_efi_bootmgr.py
@@ -0,0 +1,31 @@
+# SPDX-License-Identifier:      GPL-2.0+
+
+import pytest
+
+@pytest.mark.boardspec('sandbox')
+@pytest.mark.buildconfigspec('efi_loader')
+def test_efi_bootmgr(u_boot_console, efi_bootmgr_data):
+    u_boot_console.run_command(cmd = 'host bind 0 {}'.format(efi_bootmgr_data))
+
+    u_boot_console.run_command(cmd = 'efidebug boot add ' \
+        '-b 0001 label-1 host 0:1 initrddump.efi ' \
+        '-i host 0:1 initrd-1.img')
+    u_boot_console.run_command(cmd = 'efidebug boot dump')
+    u_boot_console.run_command(cmd = 'efidebug boot order 0001')
+    u_boot_console.run_command(cmd = 'bootefi bootmgr')
+    output = u_boot_console.run_command(cmd = 'load')
+    assert('0x181464af' in output)
+    output = u_boot_console.run_command(cmd = 'exit')
+
+    u_boot_console.run_command(cmd = 'efidebug boot add ' \
+        '-B 0002 label-2 host 0:1 initrddump.efi ' \
+        '-I host 0:1 initrd-2.img')
+    u_boot_console.run_command(cmd = 'efidebug boot dump')
+    u_boot_console.run_command(cmd = 'efidebug boot order 0002')
+    u_boot_console.run_command(cmd = 'bootefi bootmgr')
+    output = u_boot_console.run_command(cmd = 'load')
+    assert('0x811d3515' in output)
+    output = u_boot_console.run_command(cmd = 'exit')
+
+    u_boot_console.run_command(cmd = 'efidebug boot rm 0001')
+    u_boot_console.run_command(cmd = 'efidebug boot rm 0002')
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 1/9] efi_loader: export efi_dp_shorten()
  2022-03-19  9:11 ` [PATCH v2 1/9] efi_loader: export efi_dp_shorten() Heinrich Schuchardt
@ 2022-03-21  7:41   ` Ilias Apalodimas
  2022-03-23  6:55   ` AKASHI Takahiro
  1 sibling, 0 replies; 19+ messages in thread
From: Ilias Apalodimas @ 2022-03-21  7:41 UTC (permalink / raw)
  To: Heinrich Schuchardt; +Cc: u-boot, AKASHI Takahiro, Heinrich Schuchardt

On Sat, 19 Mar 2022 at 11:12, Heinrich Schuchardt
<heinrich.schuchardt@canonical.com> wrote:
>
> From: Heinrich Schuchardt <xypron.glpk@gmx.de>
>
> Rename function shorten_path() to efi_dp_shorten() and export it.
>
> Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
> ---
> v2:
>         new patch split off
> ---
>  include/efi_loader.h             |  3 ++-
>  lib/efi_loader/efi_device_path.c | 21 +++++++++++++--------
>  2 files changed, 15 insertions(+), 9 deletions(-)
>
> diff --git a/include/efi_loader.h b/include/efi_loader.h
> index 110d8ae79c..1ffcdfc485 100644
> --- a/include/efi_loader.h
> +++ b/include/efi_loader.h
> @@ -725,7 +725,8 @@ extern void *efi_bounce_buffer;
>  #define EFI_LOADER_BOUNCE_BUFFER_SIZE (64 * 1024 * 1024)
>  #endif
>
> -
> +/* shorten device path */
> +struct efi_device_path *efi_dp_shorten(struct efi_device_path *dp);
>  struct efi_device_path *efi_dp_next(const struct efi_device_path *dp);
>  int efi_dp_match(const struct efi_device_path *a,
>                  const struct efi_device_path *b);
> diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
> index dc787b4d3d..ddd5f132ec 100644
> --- a/lib/efi_loader/efi_device_path.c
> +++ b/lib/efi_loader/efi_device_path.c
> @@ -122,20 +122,25 @@ int efi_dp_match(const struct efi_device_path *a,
>         }
>  }
>
> -/*
> +/**
> + * efi_dp_shorten() - shorten device-path
> + *
>   * We can have device paths that start with a USB WWID or a USB Class node,
>   * and a few other cases which don't encode the full device path with bus
>   * hierarchy:
>   *
> - *   - MESSAGING:USB_WWID
> - *   - MESSAGING:USB_CLASS
> - *   - MEDIA:FILE_PATH
> - *   - MEDIA:HARD_DRIVE
> - *   - MESSAGING:URI
> + * * MESSAGING:USB_WWID
> + * * MESSAGING:USB_CLASS
> + * * MEDIA:FILE_PATH
> + * * MEDIA:HARD_DRIVE
> + * * MESSAGING:URI
>   *
>   * See UEFI spec (section 3.1.2, about short-form device-paths)
> + *
> + * @dp:                original devie-path

Typo device

> + * @Return:    shortened device-path or NULL
>   */
> -static struct efi_device_path *shorten_path(struct efi_device_path *dp)
> +struct efi_device_path *efi_dp_shorten(struct efi_device_path *dp)
>  {
>         while (dp) {
>                 /*
> @@ -189,7 +194,7 @@ static struct efi_object *find_obj(struct efi_device_path *dp, bool short_path,
>                                 }
>                         }
>
> -                       obj_dp = shorten_path(efi_dp_next(obj_dp));
> +                       obj_dp = efi_dp_shorten(efi_dp_next(obj_dp));
>                 } while (short_path && obj_dp);
>         }
>
> --
> 2.34.1
>
Otherwise
Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 1/9] efi_loader: export efi_dp_shorten()
  2022-03-19  9:11 ` [PATCH v2 1/9] efi_loader: export efi_dp_shorten() Heinrich Schuchardt
  2022-03-21  7:41   ` Ilias Apalodimas
@ 2022-03-23  6:55   ` AKASHI Takahiro
  1 sibling, 0 replies; 19+ messages in thread
From: AKASHI Takahiro @ 2022-03-23  6:55 UTC (permalink / raw)
  To: Heinrich Schuchardt; +Cc: u-boot, Ilias Apalodimas, Heinrich Schuchardt

On Sat, Mar 19, 2022 at 10:11:40AM +0100, Heinrich Schuchardt wrote:
> From: Heinrich Schuchardt <xypron.glpk@gmx.de>
> 
> Rename function shorten_path() to efi_dp_shorten() and export it.

If you really want to rename the function for export, please give it a more proper name
as "shorten" is quite vague. Say, clip_short_form_path() or drop_media_device_path().

-Takahiro Akashi


> Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
> ---
> v2:
> 	new patch split off
> ---
>  include/efi_loader.h             |  3 ++-
>  lib/efi_loader/efi_device_path.c | 21 +++++++++++++--------
>  2 files changed, 15 insertions(+), 9 deletions(-)
> 
> diff --git a/include/efi_loader.h b/include/efi_loader.h
> index 110d8ae79c..1ffcdfc485 100644
> --- a/include/efi_loader.h
> +++ b/include/efi_loader.h
> @@ -725,7 +725,8 @@ extern void *efi_bounce_buffer;
>  #define EFI_LOADER_BOUNCE_BUFFER_SIZE (64 * 1024 * 1024)
>  #endif
>  
> -
> +/* shorten device path */
> +struct efi_device_path *efi_dp_shorten(struct efi_device_path *dp);
>  struct efi_device_path *efi_dp_next(const struct efi_device_path *dp);
>  int efi_dp_match(const struct efi_device_path *a,
>  		 const struct efi_device_path *b);
> diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
> index dc787b4d3d..ddd5f132ec 100644
> --- a/lib/efi_loader/efi_device_path.c
> +++ b/lib/efi_loader/efi_device_path.c
> @@ -122,20 +122,25 @@ int efi_dp_match(const struct efi_device_path *a,
>  	}
>  }
>  
> -/*
> +/**
> + * efi_dp_shorten() - shorten device-path
> + *
>   * We can have device paths that start with a USB WWID or a USB Class node,
>   * and a few other cases which don't encode the full device path with bus
>   * hierarchy:
>   *
> - *   - MESSAGING:USB_WWID
> - *   - MESSAGING:USB_CLASS
> - *   - MEDIA:FILE_PATH
> - *   - MEDIA:HARD_DRIVE
> - *   - MESSAGING:URI
> + * * MESSAGING:USB_WWID
> + * * MESSAGING:USB_CLASS
> + * * MEDIA:FILE_PATH
> + * * MEDIA:HARD_DRIVE
> + * * MESSAGING:URI
>   *
>   * See UEFI spec (section 3.1.2, about short-form device-paths)
> + *
> + * @dp:		original devie-path
> + * @Return:	shortened device-path or NULL
>   */
> -static struct efi_device_path *shorten_path(struct efi_device_path *dp)
> +struct efi_device_path *efi_dp_shorten(struct efi_device_path *dp)
>  {
>  	while (dp) {
>  		/*
> @@ -189,7 +194,7 @@ static struct efi_object *find_obj(struct efi_device_path *dp, bool short_path,
>  				}
>  			}
>  
> -			obj_dp = shorten_path(efi_dp_next(obj_dp));
> +			obj_dp = efi_dp_shorten(efi_dp_next(obj_dp));
>  		} while (short_path && obj_dp);
>  	}
>  
> -- 
> 2.34.1
> 

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 8/9] efi_loader: move dtbdump.c, initrddump.c to lib/efi_loader
  2022-03-19  9:11 ` [PATCH v2 8/9] efi_loader: move dtbdump.c, initrddump.c to lib/efi_loader Heinrich Schuchardt
@ 2022-03-23  7:01   ` AKASHI Takahiro
  0 siblings, 0 replies; 19+ messages in thread
From: AKASHI Takahiro @ 2022-03-23  7:01 UTC (permalink / raw)
  To: Heinrich Schuchardt; +Cc: u-boot, Ilias Apalodimas

On Sat, Mar 19, 2022 at 10:11:47AM +0100, Heinrich Schuchardt wrote:
> The tools dtbdump.efi and initrddump.efi are useful for Python testing even
> if CONFIG_EFI_SELFTEST=y.

-> CONFIG_EFI_SELFTEST=n

> Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
> ---
> v2:
> 	new patch
> ---
>  lib/efi_loader/Makefile       |  12 +
>  lib/efi_loader/dtbdump.c      | 539 ++++++++++++++++++++++++++++++++++
>  lib/efi_loader/initrddump.c   | 449 ++++++++++++++++++++++++++++

I don't think "lib/efi_loader" is the right place to put those *real*
applications. The directory should be solely for library code.

If we have more and more EFI (sample) applications, we should have
a dedicated directory.

-Takahiro Akashi


>  lib/efi_selftest/Makefile     |  12 -
>  lib/efi_selftest/dtbdump.c    | 539 ----------------------------------
>  lib/efi_selftest/initrddump.c | 449 ----------------------------
>  6 files changed, 1000 insertions(+), 1000 deletions(-)
>  create mode 100644 lib/efi_loader/dtbdump.c
>  create mode 100644 lib/efi_loader/initrddump.c
>  delete mode 100644 lib/efi_selftest/dtbdump.c
>  delete mode 100644 lib/efi_selftest/initrddump.c
> 
> diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
> index b2c664d108..befed7144e 100644
> --- a/lib/efi_loader/Makefile
> +++ b/lib/efi_loader/Makefile
> @@ -14,12 +14,24 @@ CFLAGS_efi_boottime.o += \
>    -DFW_PATCHLEVEL="0x$(PATCHLEVEL)"
>  CFLAGS_helloworld.o := $(CFLAGS_EFI) -Os -ffreestanding
>  CFLAGS_REMOVE_helloworld.o := $(CFLAGS_NON_EFI)
> +CFLAGS_dtbdump.o := $(CFLAGS_EFI) -Os -ffreestanding
> +CFLAGS_REMOVE_dtbdump.o := $(CFLAGS_NON_EFI)
> +CFLAGS_initrddump_exit.o := $(CFLAGS_EFI) -Os -ffreestanding
> +CFLAGS_REMOVE_initrddump.o := $(CFLAGS_NON_EFI)
>  
>  ifneq ($(CONFIG_CMD_BOOTEFI_HELLO_COMPILE),)
>  always += helloworld.efi
>  targets += helloworld.o
>  endif
>  
> +ifeq ($(CONFIG_GENERATE_ACPI_TABLE),)
> +always += dtbdump.efi
> +endif
> +
> +ifdef CONFIG_EFI_LOAD_FILE2_INITRD
> +always += initrddump.efi
> +endif
> +
>  obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o
>  obj-$(CONFIG_CMD_BOOTEFI_BOOTMGR) += efi_bootmgr.o
>  obj-y += efi_boottime.o
> diff --git a/lib/efi_loader/dtbdump.c b/lib/efi_loader/dtbdump.c
> new file mode 100644
> index 0000000000..3ce2a07f9e
> --- /dev/null
> +++ b/lib/efi_loader/dtbdump.c
> @@ -0,0 +1,539 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright 2020, Heinrich Schuchardt <xypron.glpk@gmx.de>
> + *
> + * dtbdump.efi saves the device tree provided as a configuration table
> + * to a file.
> + */
> +
> +#include <common.h>
> +#include <efi_api.h>
> +#include <efi_dt_fixup.h>
> +#include <part.h>
> +#include <linux/libfdt.h>
> +
> +#define BUFFER_SIZE 64
> +#define ESC 0x17
> +
> +#define efi_size_in_pages(size) ((size + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT)
> +
> +static struct efi_simple_text_output_protocol *cerr;
> +static struct efi_simple_text_output_protocol *cout;
> +static struct efi_simple_text_input_protocol *cin;
> +static struct efi_boot_services *bs;
> +static const efi_guid_t fdt_guid = EFI_FDT_GUID;
> +static const efi_guid_t loaded_image_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
> +static const efi_guid_t guid_simple_file_system_protocol =
> +					EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
> +static efi_handle_t handle;
> +static struct efi_system_table *systable;
> +static const efi_guid_t efi_dt_fixup_protocol_guid = EFI_DT_FIXUP_PROTOCOL_GUID;
> +static const efi_guid_t efi_file_info_guid = EFI_FILE_INFO_GUID;
> +static const efi_guid_t efi_system_partition_guid = PARTITION_SYSTEM_GUID;
> +
> +/**
> + * print() - print string
> + *
> + * @string:	text
> + */
> +static void print(u16 *string)
> +{
> +	cout->output_string(cout, string);
> +}
> +
> +/**
> + * error() - print error string
> + *
> + * @string:	error text
> + */
> +static void error(u16 *string)
> +{
> +	cout->set_attribute(cout, EFI_LIGHTRED | EFI_BACKGROUND_BLACK);
> +	print(string);
> +	cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
> +}
> +
> +/**
> + * efi_input_yn() - get answer to yes/no question
> + *
> + * Return:
> + * y or Y
> + *     EFI_SUCCESS
> + * n or N
> + *     EFI_ACCESS_DENIED
> + * ESC
> + *     EFI_ABORTED
> + */
> +static efi_status_t efi_input_yn(void)
> +{
> +	struct efi_input_key key = {0};
> +	efi_uintn_t index;
> +	efi_status_t ret;
> +
> +	/* Drain the console input */
> +	ret = cin->reset(cin, true);
> +	for (;;) {
> +		ret = bs->wait_for_event(1, &cin->wait_for_key, &index);
> +		if (ret != EFI_SUCCESS)
> +			continue;
> +		ret = cin->read_key_stroke(cin, &key);
> +		if (ret != EFI_SUCCESS)
> +			continue;
> +		switch (key.scan_code) {
> +		case 0x17: /* Escape */
> +			return EFI_ABORTED;
> +		default:
> +			break;
> +		}
> +		/* Convert to lower case */
> +		switch (key.unicode_char | 0x20) {
> +		case 'y':
> +			return EFI_SUCCESS;
> +		case 'n':
> +			return EFI_ACCESS_DENIED;
> +		default:
> +			break;
> +		}
> +	}
> +}
> +
> +/**
> + * efi_input() - read string from console
> + *
> + * @buffer:		input buffer
> + * @buffer_size:	buffer size
> + * Return:		status code
> + */
> +static efi_status_t efi_input(u16 *buffer, efi_uintn_t buffer_size)
> +{
> +	struct efi_input_key key = {0};
> +	efi_uintn_t index;
> +	efi_uintn_t pos = 0;
> +	u16 outbuf[2] = u" ";
> +	efi_status_t ret;
> +
> +	/* Drain the console input */
> +	ret = cin->reset(cin, true);
> +	*buffer = 0;
> +	for (;;) {
> +		ret = bs->wait_for_event(1, &cin->wait_for_key, &index);
> +		if (ret != EFI_SUCCESS)
> +			continue;
> +		ret = cin->read_key_stroke(cin, &key);
> +		if (ret != EFI_SUCCESS)
> +			continue;
> +		switch (key.scan_code) {
> +		case 0x17: /* Escape */
> +			print(u"\r\nAborted\r\n");
> +			return EFI_ABORTED;
> +		default:
> +			break;
> +		}
> +		switch (key.unicode_char) {
> +		case 0x08: /* Backspace */
> +			if (pos) {
> +				buffer[pos--] = 0;
> +				print(u"\b \b");
> +			}
> +			break;
> +		case 0x0a: /* Linefeed */
> +		case 0x0d: /* Carriage return */
> +			print(u"\r\n");
> +			return EFI_SUCCESS;
> +		default:
> +			break;
> +		}
> +		/* Ignore surrogate codes */
> +		if (key.unicode_char >= 0xD800 && key.unicode_char <= 0xDBFF)
> +			continue;
> +		if (key.unicode_char >= 0x20 &&
> +		    pos < buffer_size - 1) {
> +			*outbuf = key.unicode_char;
> +			buffer[pos++] = key.unicode_char;
> +			buffer[pos] = 0;
> +			print(outbuf);
> +		}
> +	}
> +}
> +
> +/*
> + * Convert FDT value to host endianness.
> + *
> + * @val		FDT value
> + * Return:	converted value
> + */
> +static u32 f2h(fdt32_t val)
> +{
> +	char *buf = (char *)&val;
> +	char i;
> +
> +	/* Swap the bytes */
> +	i = buf[0]; buf[0] = buf[3]; buf[3] = i;
> +	i = buf[1]; buf[1] = buf[2]; buf[2] = i;
> +	return *(u32 *)buf;
> +}
> +
> +/**
> + * get_dtb() - get device tree
> + *
> + * @systable:	system table
> + * Return:	device tree or NULL
> + */
> +void *get_dtb(struct efi_system_table *systable)
> +{
> +	void *dtb = NULL;
> +	efi_uintn_t i;
> +
> +	for (i = 0; i < systable->nr_tables; ++i) {
> +		if (!memcmp(&systable->tables[i].guid, &fdt_guid,
> +			    sizeof(efi_guid_t))) {
> +			dtb = systable->tables[i].table;
> +			break;
> +		}
> +	}
> +	return dtb;
> +}
> +
> +/**
> + * skip_whitespace() - skip over leading whitespace
> + *
> + * @pos:	UTF-16 string
> + * Return:	pointer to first non-whitespace
> + */
> +u16 *skip_whitespace(u16 *pos)
> +{
> +	for (; *pos && *pos <= 0x20; ++pos)
> +		;
> +	return pos;
> +}
> +
> +/**
> + * starts_with() - check if @string starts with @keyword
> + *
> + * @string:	string to search for keyword
> + * @keyword:	keyword to be searched
> + * Return:	true fi @string starts with the keyword
> + */
> +bool starts_with(u16 *string, u16 *keyword)
> +{
> +	for (; *keyword; ++string, ++keyword) {
> +		if (*string != *keyword)
> +			return false;
> +	}
> +	return true;
> +}
> +
> +/**
> + * do_help() - print help
> + */
> +void do_help(void)
> +{
> +	error(u"load <dtb> - load device-tree from file\r\n");
> +	error(u"save <dtb> - save device-tree to file\r\n");
> +	error(u"exit       - exit the shell\r\n");
> +}
> +
> +/**
> + * open_file_system() - open simple file system protocol
> + *
> + * file_system:	interface of the simple file system protocol
> + * Return:	status code
> + */
> +static efi_status_t
> +open_file_system(struct efi_simple_file_system_protocol **file_system)
> +{
> +	struct efi_loaded_image *loaded_image;
> +	efi_status_t ret;
> +	efi_handle_t *handle_buffer = NULL;
> +	efi_uintn_t count;
> +
> +	ret = bs->open_protocol(handle, &loaded_image_guid,
> +				(void **)&loaded_image, NULL, NULL,
> +				EFI_OPEN_PROTOCOL_GET_PROTOCOL);
> +	if (ret != EFI_SUCCESS) {
> +		error(u"Loaded image protocol not found\r\n");
> +		return ret;
> +	}
> +
> +	/* Open the simple file system protocol on the same partition */
> +	ret = bs->open_protocol(loaded_image->device_handle,
> +				&guid_simple_file_system_protocol,
> +				(void **)file_system, NULL, NULL,
> +				EFI_OPEN_PROTOCOL_GET_PROTOCOL);
> +	if (ret == EFI_SUCCESS)
> +		return ret;
> +
> +	/* Open the simple file system protocol on the UEFI system partition */
> +	ret = bs->locate_handle_buffer(BY_PROTOCOL, &efi_system_partition_guid,
> +				       NULL, &count, &handle_buffer);
> +	if (ret == EFI_SUCCESS && handle_buffer)
> +		ret = bs->open_protocol(handle_buffer[0],
> +					&guid_simple_file_system_protocol,
> +					(void **)file_system, NULL, NULL,
> +					EFI_OPEN_PROTOCOL_GET_PROTOCOL);
> +	if (ret != EFI_SUCCESS)
> +		error(u"Failed to open simple file system protocol\r\n");
> +	if (handle)
> +		bs->free_pool(handle_buffer);
> +
> +	return ret;
> +}
> +
> +/**
> + * do_load() - load and install device-tree
> + *
> + * @filename:	file name
> + * Return:	status code
> + */
> +efi_status_t do_load(u16 *filename)
> +{
> +	struct efi_dt_fixup_protocol *dt_fixup_prot;
> +	struct efi_simple_file_system_protocol *file_system;
> +	struct efi_file_handle *root = NULL, *file = NULL;
> +	u64 addr = 0;
> +	struct efi_file_info *info;
> +	struct fdt_header *dtb;
> +	efi_uintn_t buffer_size;
> +	efi_uintn_t pages;
> +	efi_status_t ret, ret2;
> +
> +	ret = bs->locate_protocol(&efi_dt_fixup_protocol_guid, NULL,
> +				  (void **)&dt_fixup_prot);
> +	if (ret != EFI_SUCCESS) {
> +		error(u"Device-tree fix-up protocol not found\r\n");
> +		return ret;
> +	}
> +
> +	filename = skip_whitespace(filename);
> +
> +	ret = open_file_system(&file_system);
> +	if (ret != EFI_SUCCESS)
> +		goto out;
> +
> +	/* Open volume */
> +	ret = file_system->open_volume(file_system, &root);
> +	if (ret != EFI_SUCCESS) {
> +		error(u"Failed to open volume\r\n");
> +		goto out;
> +	}
> +
> +	/* Open file */
> +	ret = root->open(root, &file, filename, EFI_FILE_MODE_READ, 0);
> +	if (ret != EFI_SUCCESS) {
> +		error(u"File not found\r\n");
> +		goto out;
> +	}
> +	/* Get file size */
> +	buffer_size = 0;
> +	ret = file->getinfo(file, &efi_file_info_guid, &buffer_size, NULL);
> +	if (ret != EFI_BUFFER_TOO_SMALL) {
> +		error(u"Can't get file info size\r\n");
> +		goto out;
> +	}
> +	ret = bs->allocate_pool(EFI_LOADER_DATA, buffer_size, (void **)&info);
> +	if (ret != EFI_SUCCESS) {
> +		error(u"Out of memory\r\n");
> +		goto out;
> +	}
> +	ret = file->getinfo(file, &efi_file_info_guid, &buffer_size, info);
> +	if (ret != EFI_SUCCESS) {
> +		error(u"Can't get file info\r\n");
> +		goto out;
> +	}
> +	buffer_size = info->file_size;
> +	pages = efi_size_in_pages(buffer_size);
> +	ret = bs->free_pool(info);
> +	if (ret != EFI_SUCCESS)
> +		error(u"Can't free memory pool\r\n");
> +	/* Read file */
> +	ret = bs->allocate_pages(EFI_ALLOCATE_ANY_PAGES,
> +				 EFI_ACPI_RECLAIM_MEMORY,
> +				 pages, &addr);
> +	if (ret != EFI_SUCCESS) {
> +		error(u"Out of memory\r\n");
> +		goto out;
> +	}
> +	dtb = (struct fdt_header *)(uintptr_t)addr;
> +	ret = file->read(file, &buffer_size, dtb);
> +	if (ret != EFI_SUCCESS) {
> +		error(u"Can't read file\r\n");
> +		goto out;
> +	}
> +	/* Fixup file, expecting EFI_BUFFER_TOO_SMALL */
> +	ret = dt_fixup_prot->fixup(dt_fixup_prot, dtb, &buffer_size,
> +				   EFI_DT_APPLY_FIXUPS | EFI_DT_RESERVE_MEMORY |
> +				   EFI_DT_INSTALL_TABLE);
> +	if (ret == EFI_BUFFER_TOO_SMALL) {
> +		/* Read file into larger buffer */
> +		ret = bs->free_pages(addr, pages);
> +		if (ret != EFI_SUCCESS)
> +			error(u"Can't free memory pages\r\n");
> +		pages = efi_size_in_pages(buffer_size);
> +		ret = bs->allocate_pages(EFI_ALLOCATE_ANY_PAGES,
> +					 EFI_ACPI_RECLAIM_MEMORY,
> +					 pages, &addr);
> +		if (ret != EFI_SUCCESS) {
> +			error(u"Out of memory\r\n");
> +			goto out;
> +		}
> +		dtb = (struct fdt_header *)(uintptr_t)addr;
> +		ret = file->setpos(file, 0);
> +		if (ret != EFI_SUCCESS) {
> +			error(u"Can't position file\r\n");
> +			goto out;
> +		}
> +		ret = file->read(file, &buffer_size, dtb);
> +		if (ret != EFI_SUCCESS) {
> +			error(u"Can't read file\r\n");
> +			goto out;
> +		}
> +		buffer_size = pages << EFI_PAGE_SHIFT;
> +		ret = dt_fixup_prot->fixup(
> +				dt_fixup_prot, dtb, &buffer_size,
> +				EFI_DT_APPLY_FIXUPS | EFI_DT_RESERVE_MEMORY |
> +				EFI_DT_INSTALL_TABLE);
> +	}
> +	if (ret == EFI_SUCCESS)
> +		print(u"device-tree installed\r\n");
> +	else
> +		error(u"Device-tree fix-up failed\r\n");
> +out:
> +	if (addr) {
> +		ret2 = bs->free_pages(addr, pages);
> +		if (ret2 != EFI_SUCCESS)
> +			error(u"Can't free memory pages\r\n");
> +	}
> +	if (file) {
> +		ret2 = file->close(file);
> +		if (ret2 != EFI_SUCCESS)
> +			error(u"Can't close file\r\n");
> +	}
> +	if (root) {
> +		ret2 = root->close(root);
> +		if (ret2 != EFI_SUCCESS)
> +			error(u"Can't close volume\r\n");
> +	}
> +	return ret;
> +}
> +
> +/**
> + * do_save() - save current device-tree
> + *
> + * @filename:	file name
> + * Return:	status code
> + */
> +efi_status_t do_save(u16 *filename)
> +{
> +	struct efi_simple_file_system_protocol *file_system;
> +	efi_uintn_t dtb_size;
> +	struct efi_file_handle *root, *file;
> +	struct fdt_header *dtb;
> +	efi_uintn_t ret;
> +
> +	dtb = get_dtb(systable);
> +	if (!dtb) {
> +		error(u"DTB not found\r\n");
> +		return EFI_NOT_FOUND;
> +	}
> +	if (f2h(dtb->magic) != FDT_MAGIC) {
> +		error(u"Wrong device tree magic\r\n");
> +		return EFI_NOT_FOUND;
> +	}
> +	dtb_size = f2h(dtb->totalsize);
> +
> +	filename = skip_whitespace(filename);
> +
> +	ret = open_file_system(&file_system);
> +	if (ret != EFI_SUCCESS)
> +		return ret;
> +
> +	/* Open volume */
> +	ret = file_system->open_volume(file_system, &root);
> +	if (ret != EFI_SUCCESS) {
> +		error(u"Failed to open volume\r\n");
> +		return ret;
> +	}
> +	/* Check if file already exists */
> +	ret = root->open(root, &file, filename, EFI_FILE_MODE_READ, 0);
> +	if (ret == EFI_SUCCESS) {
> +		file->close(file);
> +		print(u"Overwrite existing file (y/n)? ");
> +		ret = efi_input_yn();
> +		print(u"\r\n");
> +		if (ret != EFI_SUCCESS) {
> +			root->close(root);
> +			error(u"Aborted by user\r\n");
> +			return ret;
> +		}
> +	}
> +
> +	/* Create file */
> +	ret = root->open(root, &file, filename,
> +			 EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE |
> +			 EFI_FILE_MODE_CREATE, EFI_FILE_ARCHIVE);
> +	if (ret == EFI_SUCCESS) {
> +		/* Write file */
> +		ret = file->write(file, &dtb_size, dtb);
> +		if (ret != EFI_SUCCESS)
> +			error(u"Failed to write file\r\n");
> +		file->close(file);
> +	} else {
> +		error(u"Failed to open file\r\n");
> +	}
> +	root->close(root);
> +
> +	if (ret == EFI_SUCCESS) {
> +		print(filename);
> +		print(u" written\r\n");
> +	}
> +
> +	return ret;
> +}
> +
> +/**
> + * efi_main() - entry point of the EFI application.
> + *
> + * @handle:	handle of the loaded image
> + * @systab:	system table
> + * Return:	status code
> + */
> +efi_status_t EFIAPI efi_main(efi_handle_t image_handle,
> +			     struct efi_system_table *systab)
> +{
> +	handle = image_handle;
> +	systable = systab;
> +	cerr = systable->std_err;
> +	cout = systable->con_out;
> +	cin = systable->con_in;
> +	bs = systable->boottime;
> +
> +	cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
> +	cout->clear_screen(cout);
> +	cout->set_attribute(cout, EFI_WHITE | EFI_BACKGROUND_BLACK);
> +	print(u"DTB Dump\r\n========\r\n\r\n");
> +	cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
> +
> +	for (;;) {
> +		u16 command[BUFFER_SIZE];
> +		u16 *pos;
> +		efi_uintn_t ret;
> +
> +		print(u"=> ");
> +		ret = efi_input(command, sizeof(command));
> +		if (ret == EFI_ABORTED)
> +			break;
> +		pos = skip_whitespace(command);
> +		if (starts_with(pos, u"exit"))
> +			break;
> +		else if (starts_with(pos, u"load "))
> +			do_load(pos + 5);
> +		else if (starts_with(pos, u"save "))
> +			do_save(pos + 5);
> +		else
> +			do_help();
> +	}
> +
> +	cout->set_attribute(cout, EFI_LIGHTGRAY | EFI_BACKGROUND_BLACK);
> +	cout->clear_screen(cout);
> +	return EFI_SUCCESS;
> +}
> diff --git a/lib/efi_loader/initrddump.c b/lib/efi_loader/initrddump.c
> new file mode 100644
> index 0000000000..7de43bcfff
> --- /dev/null
> +++ b/lib/efi_loader/initrddump.c
> @@ -0,0 +1,449 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright 2020, Heinrich Schuchardt <xypron.glpk@gmx.de>
> + *
> + * initrddump.efi saves the initial RAM disk provided via the
> + * EFI_LOAD_FILE2_PROTOCOL.
> + */
> +
> +#include <common.h>
> +#include <efi_api.h>
> +#include <efi_load_initrd.h>
> +
> +#define BUFFER_SIZE 64
> +#define ESC 0x17
> +
> +#define efi_size_in_pages(size) (((size) + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT)
> +
> +static struct efi_system_table *systable;
> +static struct efi_boot_services *bs;
> +static struct efi_simple_text_output_protocol *cerr;
> +static struct efi_simple_text_output_protocol *cout;
> +static struct efi_simple_text_input_protocol *cin;
> +static const efi_guid_t loaded_image_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
> +static const efi_guid_t guid_simple_file_system_protocol =
> +					EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
> +static const efi_guid_t load_file2_guid = EFI_LOAD_FILE2_PROTOCOL_GUID;
> +static efi_handle_t handle;
> +
> +/*
> + * Device path defined by Linux to identify the handle providing the
> + * EFI_LOAD_FILE2_PROTOCOL used for loading the initial ramdisk.
> + */
> +static const struct efi_initrd_dp initrd_dp = {
> +	.vendor = {
> +		{
> +		   DEVICE_PATH_TYPE_MEDIA_DEVICE,
> +		   DEVICE_PATH_SUB_TYPE_VENDOR_PATH,
> +		   sizeof(initrd_dp.vendor),
> +		},
> +		EFI_INITRD_MEDIA_GUID,
> +	},
> +	.end = {
> +		DEVICE_PATH_TYPE_END,
> +		DEVICE_PATH_SUB_TYPE_END,
> +		sizeof(initrd_dp.end),
> +	}
> +};
> +
> +/**
> + * print() - print string
> + *
> + * @string:	text
> + */
> +static void print(u16 *string)
> +{
> +	cout->output_string(cout, string);
> +}
> +
> +/**
> + * error() - print error string
> + *
> + * @string:	error text
> + */
> +static void error(u16 *string)
> +{
> +	cout->set_attribute(cout, EFI_LIGHTRED | EFI_BACKGROUND_BLACK);
> +	print(string);
> +	cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
> +}
> +
> +/*
> + * printx() - print hexadecimal number
> + *
> + * @val:	value to print;
> + * @prec:	minimum number of digits to print
> + */
> +static void printx(u64 val, u32 prec)
> +{
> +	int i;
> +	u16 c;
> +	u16 buf[16];
> +	u16 *pos = buf;
> +
> +	for (i = 2 * sizeof(val) - 1; i >= 0; --i) {
> +		c = (val >> (4 * i)) & 0x0f;
> +		if (c || pos != buf || !i || i < prec) {
> +			c += '0';
> +			if (c > '9')
> +				c += 'a' - '9' - 1;
> +			*pos++ = c;
> +		}
> +	}
> +	*pos = 0;
> +	print(buf);
> +}
> +
> +/**
> + * efi_input_yn() - get answer to yes/no question
> + *
> + * Return:
> + * y or Y
> + *     EFI_SUCCESS
> + * n or N
> + *     EFI_ACCESS_DENIED
> + * ESC
> + *     EFI_ABORTED
> + */
> +static efi_status_t efi_input_yn(void)
> +{
> +	struct efi_input_key key = {0};
> +	efi_uintn_t index;
> +	efi_status_t ret;
> +
> +	/* Drain the console input */
> +	ret = cin->reset(cin, true);
> +	for (;;) {
> +		ret = bs->wait_for_event(1, &cin->wait_for_key, &index);
> +		if (ret != EFI_SUCCESS)
> +			continue;
> +		ret = cin->read_key_stroke(cin, &key);
> +		if (ret != EFI_SUCCESS)
> +			continue;
> +		switch (key.scan_code) {
> +		case 0x17: /* Escape */
> +			return EFI_ABORTED;
> +		default:
> +			break;
> +		}
> +		/* Convert to lower case */
> +		switch (key.unicode_char | 0x20) {
> +		case 'y':
> +			return EFI_SUCCESS;
> +		case 'n':
> +			return EFI_ACCESS_DENIED;
> +		default:
> +			break;
> +		}
> +	}
> +}
> +
> +/**
> + * efi_input() - read string from console
> + *
> + * @buffer:		input buffer
> + * @buffer_size:	buffer size
> + * Return:		status code
> + */
> +static efi_status_t efi_input(u16 *buffer, efi_uintn_t buffer_size)
> +{
> +	struct efi_input_key key = {0};
> +	efi_uintn_t index;
> +	efi_uintn_t pos = 0;
> +	u16 outbuf[2] = u" ";
> +	efi_status_t ret;
> +
> +	/* Drain the console input */
> +	ret = cin->reset(cin, true);
> +	*buffer = 0;
> +	for (;;) {
> +		ret = bs->wait_for_event(1, &cin->wait_for_key, &index);
> +		if (ret != EFI_SUCCESS)
> +			continue;
> +		ret = cin->read_key_stroke(cin, &key);
> +		if (ret != EFI_SUCCESS)
> +			continue;
> +		switch (key.scan_code) {
> +		case 0x17: /* Escape */
> +			print(u"\r\nAborted\r\n");
> +			return EFI_ABORTED;
> +		default:
> +			break;
> +		}
> +		switch (key.unicode_char) {
> +		case 0x08: /* Backspace */
> +			if (pos) {
> +				buffer[pos--] = 0;
> +				print(u"\b \b");
> +			}
> +			break;
> +		case 0x0a: /* Linefeed */
> +		case 0x0d: /* Carriage return */
> +			print(u"\r\n");
> +			return EFI_SUCCESS;
> +		default:
> +			break;
> +		}
> +		/* Ignore surrogate codes */
> +		if (key.unicode_char >= 0xD800 && key.unicode_char <= 0xDBFF)
> +			continue;
> +		if (key.unicode_char >= 0x20 &&
> +		    pos < buffer_size - 1) {
> +			*outbuf = key.unicode_char;
> +			buffer[pos++] = key.unicode_char;
> +			buffer[pos] = 0;
> +			print(outbuf);
> +		}
> +	}
> +}
> +
> +/**
> + * skip_whitespace() - skip over leading whitespace
> + *
> + * @pos:	UTF-16 string
> + * Return:	pointer to first non-whitespace
> + */
> +static u16 *skip_whitespace(u16 *pos)
> +{
> +	for (; *pos && *pos <= 0x20; ++pos)
> +		;
> +	return pos;
> +}
> +
> +/**
> + * starts_with() - check if @string starts with @keyword
> + *
> + * @string:	string to search for keyword
> + * @keyword:	keyword to be searched
> + * Return:	true fi @string starts with the keyword
> + */
> +static bool starts_with(u16 *string, u16 *keyword)
> +{
> +	for (; *keyword; ++string, ++keyword) {
> +		if (*string != *keyword)
> +			return false;
> +	}
> +	return true;
> +}
> +
> +/**
> + * do_help() - print help
> + */
> +static void do_help(void)
> +{
> +	error(u"load          - show length and CRC32 of initial RAM disk\r\n");
> +	error(u"save <initrd> - save initial RAM disk to file\r\n");
> +	error(u"exit          - exit the shell\r\n");
> +}
> +
> +/**
> + * get_initrd() - read initial RAM disk via EFI_LOAD_FILE2_PROTOCOL
> + *
> + * @initrd:		on return buffer with initial RAM disk
> + * @initrd_size:	size of initial RAM disk
> + * Return:		status code
> + */
> +static efi_status_t get_initrd(void **initrd, efi_uintn_t *initrd_size)
> +{
> +	struct efi_device_path *dp = (struct efi_device_path *)&initrd_dp;
> +	struct efi_load_file_protocol *load_file2_prot;
> +	u64 buffer;
> +	efi_handle_t handle;
> +	efi_status_t ret;
> +
> +	*initrd = NULL;
> +	*initrd_size = 0;
> +	ret = bs->locate_device_path(&load_file2_guid, &dp, &handle);
> +	if (ret != EFI_SUCCESS) {
> +		error(u"Load File2 protocol not found\r\n");
> +		return ret;
> +	}
> +	ret = bs->handle_protocol(handle, &load_file2_guid,
> +				 (void **)&load_file2_prot);
> +	ret = load_file2_prot->load_file(load_file2_prot, dp, false,
> +					 initrd_size, NULL);
> +	if (ret != EFI_BUFFER_TOO_SMALL) {
> +		error(u"Load File2 protocol does not provide file length\r\n");
> +		return EFI_LOAD_ERROR;
> +	}
> +	ret = bs->allocate_pages(EFI_ALLOCATE_ANY_PAGES, EFI_LOADER_DATA,
> +				 efi_size_in_pages(*initrd_size), &buffer);
> +	if (ret != EFI_SUCCESS) {
> +		error(u"Out of memory\r\n");
> +		return ret;
> +	}
> +	*initrd = (void *)(uintptr_t)buffer;
> +	ret = load_file2_prot->load_file(load_file2_prot, dp, false,
> +					 initrd_size, *initrd);
> +	if (ret != EFI_SUCCESS) {
> +		error(u"Load File2 protocol failed to provide file\r\n");
> +		bs->free_pages(buffer, efi_size_in_pages(*initrd_size));
> +		return EFI_LOAD_ERROR;
> +	}
> +	return ret;
> +}
> +
> +/**
> + * do_load() - load initial RAM disk and display CRC32 and length
> + *
> + * @filename:	file name
> + * Return:	status code
> + */
> +static efi_status_t do_load(void)
> +{
> +	void *initrd;
> +	efi_uintn_t initrd_size;
> +	u32 crc32;
> +	efi_uintn_t ret;
> +
> +	ret =  get_initrd(&initrd, &initrd_size);
> +	if (ret != EFI_SUCCESS)
> +		return ret;
> +	print(u"length: 0x");
> +	printx(initrd_size, 1);
> +	print(u"\r\n");
> +
> +	ret = bs->calculate_crc32(initrd, initrd_size, &crc32);
> +	if (ret != EFI_SUCCESS) {
> +		error(u"Calculating CRC32 failed\r\n");
> +		return EFI_LOAD_ERROR;
> +	}
> +	print(u"crc32: 0x");
> +	printx(crc32, 8);
> +	print(u"\r\n");
> +
> +	return EFI_SUCCESS;
> +}
> +
> +/**
> + * do_save() - save initial RAM disk
> + *
> + * @filename:	file name
> + * Return:	status code
> + */
> +static efi_status_t do_save(u16 *filename)
> +{
> +	struct efi_loaded_image *loaded_image;
> +	struct efi_simple_file_system_protocol *file_system;
> +	struct efi_file_handle *root, *file;
> +	void *initrd;
> +	efi_uintn_t initrd_size;
> +	efi_uintn_t ret;
> +
> +	ret = get_initrd(&initrd, &initrd_size);
> +	if (ret != EFI_SUCCESS)
> +		return ret;
> +
> +	filename = skip_whitespace(filename);
> +
> +	ret = bs->open_protocol(handle, &loaded_image_guid,
> +				(void **)&loaded_image, NULL, NULL,
> +				EFI_OPEN_PROTOCOL_GET_PROTOCOL);
> +	if (ret != EFI_SUCCESS) {
> +		error(u"Loaded image protocol not found\r\n");
> +		goto out;
> +	}
> +
> +	/* Open the simple file system protocol */
> +	ret = bs->open_protocol(loaded_image->device_handle,
> +				&guid_simple_file_system_protocol,
> +				(void **)&file_system, NULL, NULL,
> +				EFI_OPEN_PROTOCOL_GET_PROTOCOL);
> +	if (ret != EFI_SUCCESS) {
> +		error(u"Failed to open simple file system protocol\r\n");
> +		goto out;
> +	}
> +
> +	/* Open volume */
> +	ret = file_system->open_volume(file_system, &root);
> +	if (ret != EFI_SUCCESS) {
> +		error(u"Failed to open volume\r\n");
> +		goto out;
> +	}
> +	/* Check if file already exists */
> +	ret = root->open(root, &file, filename, EFI_FILE_MODE_READ, 0);
> +	if (ret == EFI_SUCCESS) {
> +		file->close(file);
> +		print(u"Overwrite existing file (y/n)? ");
> +		ret = efi_input_yn();
> +		print(u"\r\n");
> +		if (ret != EFI_SUCCESS) {
> +			root->close(root);
> +			error(u"Aborted by user\r\n");
> +			goto out;
> +		}
> +	}
> +
> +	/* Create file */
> +	ret = root->open(root, &file, filename,
> +			 EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE |
> +			 EFI_FILE_MODE_CREATE, EFI_FILE_ARCHIVE);
> +	if (ret == EFI_SUCCESS) {
> +		/* Write file */
> +		ret = file->write(file, &initrd_size, initrd);
> +		if (ret != EFI_SUCCESS) {
> +			error(u"Failed to write file\r\n");
> +		} else {
> +			print(filename);
> +			print(u" written\r\n");
> +		}
> +		file->close(file);
> +	} else {
> +		error(u"Failed to open file\r\n");
> +	}
> +	root->close(root);
> +
> +out:
> +	if (initrd)
> +		bs->free_pages((uintptr_t)initrd,
> +			       efi_size_in_pages(initrd_size));
> +	return ret;
> +}
> +
> +/**
> + * efi_main() - entry point of the EFI application.
> + *
> + * @handle:	handle of the loaded image
> + * @systab:	system table
> + * Return:	status code
> + */
> +efi_status_t EFIAPI efi_main(efi_handle_t image_handle,
> +			     struct efi_system_table *systab)
> +{
> +	handle = image_handle;
> +	systable = systab;
> +	cerr = systable->std_err;
> +	cout = systable->con_out;
> +	cin = systable->con_in;
> +	bs = systable->boottime;
> +
> +	cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
> +	cout->clear_screen(cout);
> +	cout->set_attribute(cout, EFI_WHITE | EFI_BACKGROUND_BLACK);
> +	print(u"INITRD Dump\r\n===========\r\n\r\n");
> +	cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
> +
> +	for (;;) {
> +		u16 command[BUFFER_SIZE];
> +		u16 *pos;
> +		efi_uintn_t ret;
> +
> +		print(u"=> ");
> +		ret = efi_input(command, sizeof(command));
> +		if (ret == EFI_ABORTED)
> +			break;
> +		pos = skip_whitespace(command);
> +		if (starts_with(pos, u"exit"))
> +			break;
> +		else if (starts_with(pos, u"load"))
> +			do_load();
> +		else if (starts_with(pos, u"save "))
> +			do_save(pos + 5);
> +		else
> +			do_help();
> +	}
> +
> +	cout->set_attribute(cout, EFI_LIGHTGRAY | EFI_BACKGROUND_BLACK);
> +	cout->clear_screen(cout);
> +	return EFI_SUCCESS;
> +}
> diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile
> index 9ff6e1760c..be8040d1c7 100644
> --- a/lib/efi_selftest/Makefile
> +++ b/lib/efi_selftest/Makefile
> @@ -8,16 +8,12 @@
>  asflags-y += -DHOST_ARCH="$(HOST_ARCH)"
>  ccflags-y += -DHOST_ARCH="$(HOST_ARCH)"
>  
> -CFLAGS_dtbdump.o := $(CFLAGS_EFI) -Os -ffreestanding
> -CFLAGS_REMOVE_dtbdump.o := $(CFLAGS_NON_EFI)
>  CFLAGS_efi_selftest_miniapp_exception.o := $(CFLAGS_EFI) -Os -ffreestanding
>  CFLAGS_REMOVE_efi_selftest_miniapp_exception.o := $(CFLAGS_NON_EFI)
>  CFLAGS_efi_selftest_miniapp_exit.o := $(CFLAGS_EFI) -Os -ffreestanding
>  CFLAGS_REMOVE_efi_selftest_miniapp_exit.o := $(CFLAGS_NON_EFI)
>  CFLAGS_efi_selftest_miniapp_return.o := $(CFLAGS_EFI) -Os -ffreestanding
>  CFLAGS_REMOVE_efi_selftest_miniapp_return.o := $(CFLAGS_NON_EFI)
> -CFLAGS_initrddump_exit.o := $(CFLAGS_EFI) -Os -ffreestanding
> -CFLAGS_REMOVE_initrddump.o := $(CFLAGS_NON_EFI)
>  
>  obj-y += \
>  efi_selftest.o \
> @@ -83,14 +79,6 @@ efi_selftest_miniapp_exception.efi \
>  efi_selftest_miniapp_exit.efi \
>  efi_selftest_miniapp_return.efi
>  
> -ifeq ($(CONFIG_GENERATE_ACPI_TABLE),)
> -always += dtbdump.efi
> -endif
> -
> -ifdef CONFIG_EFI_LOAD_FILE2_INITRD
> -always += initrddump.efi
> -endif
> -
>  $(obj)/efi_miniapp_file_image_exception.h: $(obj)/efi_selftest_miniapp_exception.efi
>  	$(obj)/../../tools/file2include $(obj)/efi_selftest_miniapp_exception.efi > \
>  	$(obj)/efi_miniapp_file_image_exception.h
> diff --git a/lib/efi_selftest/dtbdump.c b/lib/efi_selftest/dtbdump.c
> deleted file mode 100644
> index 3ce2a07f9e..0000000000
> --- a/lib/efi_selftest/dtbdump.c
> +++ /dev/null
> @@ -1,539 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0+
> -/*
> - * Copyright 2020, Heinrich Schuchardt <xypron.glpk@gmx.de>
> - *
> - * dtbdump.efi saves the device tree provided as a configuration table
> - * to a file.
> - */
> -
> -#include <common.h>
> -#include <efi_api.h>
> -#include <efi_dt_fixup.h>
> -#include <part.h>
> -#include <linux/libfdt.h>
> -
> -#define BUFFER_SIZE 64
> -#define ESC 0x17
> -
> -#define efi_size_in_pages(size) ((size + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT)
> -
> -static struct efi_simple_text_output_protocol *cerr;
> -static struct efi_simple_text_output_protocol *cout;
> -static struct efi_simple_text_input_protocol *cin;
> -static struct efi_boot_services *bs;
> -static const efi_guid_t fdt_guid = EFI_FDT_GUID;
> -static const efi_guid_t loaded_image_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
> -static const efi_guid_t guid_simple_file_system_protocol =
> -					EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
> -static efi_handle_t handle;
> -static struct efi_system_table *systable;
> -static const efi_guid_t efi_dt_fixup_protocol_guid = EFI_DT_FIXUP_PROTOCOL_GUID;
> -static const efi_guid_t efi_file_info_guid = EFI_FILE_INFO_GUID;
> -static const efi_guid_t efi_system_partition_guid = PARTITION_SYSTEM_GUID;
> -
> -/**
> - * print() - print string
> - *
> - * @string:	text
> - */
> -static void print(u16 *string)
> -{
> -	cout->output_string(cout, string);
> -}
> -
> -/**
> - * error() - print error string
> - *
> - * @string:	error text
> - */
> -static void error(u16 *string)
> -{
> -	cout->set_attribute(cout, EFI_LIGHTRED | EFI_BACKGROUND_BLACK);
> -	print(string);
> -	cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
> -}
> -
> -/**
> - * efi_input_yn() - get answer to yes/no question
> - *
> - * Return:
> - * y or Y
> - *     EFI_SUCCESS
> - * n or N
> - *     EFI_ACCESS_DENIED
> - * ESC
> - *     EFI_ABORTED
> - */
> -static efi_status_t efi_input_yn(void)
> -{
> -	struct efi_input_key key = {0};
> -	efi_uintn_t index;
> -	efi_status_t ret;
> -
> -	/* Drain the console input */
> -	ret = cin->reset(cin, true);
> -	for (;;) {
> -		ret = bs->wait_for_event(1, &cin->wait_for_key, &index);
> -		if (ret != EFI_SUCCESS)
> -			continue;
> -		ret = cin->read_key_stroke(cin, &key);
> -		if (ret != EFI_SUCCESS)
> -			continue;
> -		switch (key.scan_code) {
> -		case 0x17: /* Escape */
> -			return EFI_ABORTED;
> -		default:
> -			break;
> -		}
> -		/* Convert to lower case */
> -		switch (key.unicode_char | 0x20) {
> -		case 'y':
> -			return EFI_SUCCESS;
> -		case 'n':
> -			return EFI_ACCESS_DENIED;
> -		default:
> -			break;
> -		}
> -	}
> -}
> -
> -/**
> - * efi_input() - read string from console
> - *
> - * @buffer:		input buffer
> - * @buffer_size:	buffer size
> - * Return:		status code
> - */
> -static efi_status_t efi_input(u16 *buffer, efi_uintn_t buffer_size)
> -{
> -	struct efi_input_key key = {0};
> -	efi_uintn_t index;
> -	efi_uintn_t pos = 0;
> -	u16 outbuf[2] = u" ";
> -	efi_status_t ret;
> -
> -	/* Drain the console input */
> -	ret = cin->reset(cin, true);
> -	*buffer = 0;
> -	for (;;) {
> -		ret = bs->wait_for_event(1, &cin->wait_for_key, &index);
> -		if (ret != EFI_SUCCESS)
> -			continue;
> -		ret = cin->read_key_stroke(cin, &key);
> -		if (ret != EFI_SUCCESS)
> -			continue;
> -		switch (key.scan_code) {
> -		case 0x17: /* Escape */
> -			print(u"\r\nAborted\r\n");
> -			return EFI_ABORTED;
> -		default:
> -			break;
> -		}
> -		switch (key.unicode_char) {
> -		case 0x08: /* Backspace */
> -			if (pos) {
> -				buffer[pos--] = 0;
> -				print(u"\b \b");
> -			}
> -			break;
> -		case 0x0a: /* Linefeed */
> -		case 0x0d: /* Carriage return */
> -			print(u"\r\n");
> -			return EFI_SUCCESS;
> -		default:
> -			break;
> -		}
> -		/* Ignore surrogate codes */
> -		if (key.unicode_char >= 0xD800 && key.unicode_char <= 0xDBFF)
> -			continue;
> -		if (key.unicode_char >= 0x20 &&
> -		    pos < buffer_size - 1) {
> -			*outbuf = key.unicode_char;
> -			buffer[pos++] = key.unicode_char;
> -			buffer[pos] = 0;
> -			print(outbuf);
> -		}
> -	}
> -}
> -
> -/*
> - * Convert FDT value to host endianness.
> - *
> - * @val		FDT value
> - * Return:	converted value
> - */
> -static u32 f2h(fdt32_t val)
> -{
> -	char *buf = (char *)&val;
> -	char i;
> -
> -	/* Swap the bytes */
> -	i = buf[0]; buf[0] = buf[3]; buf[3] = i;
> -	i = buf[1]; buf[1] = buf[2]; buf[2] = i;
> -	return *(u32 *)buf;
> -}
> -
> -/**
> - * get_dtb() - get device tree
> - *
> - * @systable:	system table
> - * Return:	device tree or NULL
> - */
> -void *get_dtb(struct efi_system_table *systable)
> -{
> -	void *dtb = NULL;
> -	efi_uintn_t i;
> -
> -	for (i = 0; i < systable->nr_tables; ++i) {
> -		if (!memcmp(&systable->tables[i].guid, &fdt_guid,
> -			    sizeof(efi_guid_t))) {
> -			dtb = systable->tables[i].table;
> -			break;
> -		}
> -	}
> -	return dtb;
> -}
> -
> -/**
> - * skip_whitespace() - skip over leading whitespace
> - *
> - * @pos:	UTF-16 string
> - * Return:	pointer to first non-whitespace
> - */
> -u16 *skip_whitespace(u16 *pos)
> -{
> -	for (; *pos && *pos <= 0x20; ++pos)
> -		;
> -	return pos;
> -}
> -
> -/**
> - * starts_with() - check if @string starts with @keyword
> - *
> - * @string:	string to search for keyword
> - * @keyword:	keyword to be searched
> - * Return:	true fi @string starts with the keyword
> - */
> -bool starts_with(u16 *string, u16 *keyword)
> -{
> -	for (; *keyword; ++string, ++keyword) {
> -		if (*string != *keyword)
> -			return false;
> -	}
> -	return true;
> -}
> -
> -/**
> - * do_help() - print help
> - */
> -void do_help(void)
> -{
> -	error(u"load <dtb> - load device-tree from file\r\n");
> -	error(u"save <dtb> - save device-tree to file\r\n");
> -	error(u"exit       - exit the shell\r\n");
> -}
> -
> -/**
> - * open_file_system() - open simple file system protocol
> - *
> - * file_system:	interface of the simple file system protocol
> - * Return:	status code
> - */
> -static efi_status_t
> -open_file_system(struct efi_simple_file_system_protocol **file_system)
> -{
> -	struct efi_loaded_image *loaded_image;
> -	efi_status_t ret;
> -	efi_handle_t *handle_buffer = NULL;
> -	efi_uintn_t count;
> -
> -	ret = bs->open_protocol(handle, &loaded_image_guid,
> -				(void **)&loaded_image, NULL, NULL,
> -				EFI_OPEN_PROTOCOL_GET_PROTOCOL);
> -	if (ret != EFI_SUCCESS) {
> -		error(u"Loaded image protocol not found\r\n");
> -		return ret;
> -	}
> -
> -	/* Open the simple file system protocol on the same partition */
> -	ret = bs->open_protocol(loaded_image->device_handle,
> -				&guid_simple_file_system_protocol,
> -				(void **)file_system, NULL, NULL,
> -				EFI_OPEN_PROTOCOL_GET_PROTOCOL);
> -	if (ret == EFI_SUCCESS)
> -		return ret;
> -
> -	/* Open the simple file system protocol on the UEFI system partition */
> -	ret = bs->locate_handle_buffer(BY_PROTOCOL, &efi_system_partition_guid,
> -				       NULL, &count, &handle_buffer);
> -	if (ret == EFI_SUCCESS && handle_buffer)
> -		ret = bs->open_protocol(handle_buffer[0],
> -					&guid_simple_file_system_protocol,
> -					(void **)file_system, NULL, NULL,
> -					EFI_OPEN_PROTOCOL_GET_PROTOCOL);
> -	if (ret != EFI_SUCCESS)
> -		error(u"Failed to open simple file system protocol\r\n");
> -	if (handle)
> -		bs->free_pool(handle_buffer);
> -
> -	return ret;
> -}
> -
> -/**
> - * do_load() - load and install device-tree
> - *
> - * @filename:	file name
> - * Return:	status code
> - */
> -efi_status_t do_load(u16 *filename)
> -{
> -	struct efi_dt_fixup_protocol *dt_fixup_prot;
> -	struct efi_simple_file_system_protocol *file_system;
> -	struct efi_file_handle *root = NULL, *file = NULL;
> -	u64 addr = 0;
> -	struct efi_file_info *info;
> -	struct fdt_header *dtb;
> -	efi_uintn_t buffer_size;
> -	efi_uintn_t pages;
> -	efi_status_t ret, ret2;
> -
> -	ret = bs->locate_protocol(&efi_dt_fixup_protocol_guid, NULL,
> -				  (void **)&dt_fixup_prot);
> -	if (ret != EFI_SUCCESS) {
> -		error(u"Device-tree fix-up protocol not found\r\n");
> -		return ret;
> -	}
> -
> -	filename = skip_whitespace(filename);
> -
> -	ret = open_file_system(&file_system);
> -	if (ret != EFI_SUCCESS)
> -		goto out;
> -
> -	/* Open volume */
> -	ret = file_system->open_volume(file_system, &root);
> -	if (ret != EFI_SUCCESS) {
> -		error(u"Failed to open volume\r\n");
> -		goto out;
> -	}
> -
> -	/* Open file */
> -	ret = root->open(root, &file, filename, EFI_FILE_MODE_READ, 0);
> -	if (ret != EFI_SUCCESS) {
> -		error(u"File not found\r\n");
> -		goto out;
> -	}
> -	/* Get file size */
> -	buffer_size = 0;
> -	ret = file->getinfo(file, &efi_file_info_guid, &buffer_size, NULL);
> -	if (ret != EFI_BUFFER_TOO_SMALL) {
> -		error(u"Can't get file info size\r\n");
> -		goto out;
> -	}
> -	ret = bs->allocate_pool(EFI_LOADER_DATA, buffer_size, (void **)&info);
> -	if (ret != EFI_SUCCESS) {
> -		error(u"Out of memory\r\n");
> -		goto out;
> -	}
> -	ret = file->getinfo(file, &efi_file_info_guid, &buffer_size, info);
> -	if (ret != EFI_SUCCESS) {
> -		error(u"Can't get file info\r\n");
> -		goto out;
> -	}
> -	buffer_size = info->file_size;
> -	pages = efi_size_in_pages(buffer_size);
> -	ret = bs->free_pool(info);
> -	if (ret != EFI_SUCCESS)
> -		error(u"Can't free memory pool\r\n");
> -	/* Read file */
> -	ret = bs->allocate_pages(EFI_ALLOCATE_ANY_PAGES,
> -				 EFI_ACPI_RECLAIM_MEMORY,
> -				 pages, &addr);
> -	if (ret != EFI_SUCCESS) {
> -		error(u"Out of memory\r\n");
> -		goto out;
> -	}
> -	dtb = (struct fdt_header *)(uintptr_t)addr;
> -	ret = file->read(file, &buffer_size, dtb);
> -	if (ret != EFI_SUCCESS) {
> -		error(u"Can't read file\r\n");
> -		goto out;
> -	}
> -	/* Fixup file, expecting EFI_BUFFER_TOO_SMALL */
> -	ret = dt_fixup_prot->fixup(dt_fixup_prot, dtb, &buffer_size,
> -				   EFI_DT_APPLY_FIXUPS | EFI_DT_RESERVE_MEMORY |
> -				   EFI_DT_INSTALL_TABLE);
> -	if (ret == EFI_BUFFER_TOO_SMALL) {
> -		/* Read file into larger buffer */
> -		ret = bs->free_pages(addr, pages);
> -		if (ret != EFI_SUCCESS)
> -			error(u"Can't free memory pages\r\n");
> -		pages = efi_size_in_pages(buffer_size);
> -		ret = bs->allocate_pages(EFI_ALLOCATE_ANY_PAGES,
> -					 EFI_ACPI_RECLAIM_MEMORY,
> -					 pages, &addr);
> -		if (ret != EFI_SUCCESS) {
> -			error(u"Out of memory\r\n");
> -			goto out;
> -		}
> -		dtb = (struct fdt_header *)(uintptr_t)addr;
> -		ret = file->setpos(file, 0);
> -		if (ret != EFI_SUCCESS) {
> -			error(u"Can't position file\r\n");
> -			goto out;
> -		}
> -		ret = file->read(file, &buffer_size, dtb);
> -		if (ret != EFI_SUCCESS) {
> -			error(u"Can't read file\r\n");
> -			goto out;
> -		}
> -		buffer_size = pages << EFI_PAGE_SHIFT;
> -		ret = dt_fixup_prot->fixup(
> -				dt_fixup_prot, dtb, &buffer_size,
> -				EFI_DT_APPLY_FIXUPS | EFI_DT_RESERVE_MEMORY |
> -				EFI_DT_INSTALL_TABLE);
> -	}
> -	if (ret == EFI_SUCCESS)
> -		print(u"device-tree installed\r\n");
> -	else
> -		error(u"Device-tree fix-up failed\r\n");
> -out:
> -	if (addr) {
> -		ret2 = bs->free_pages(addr, pages);
> -		if (ret2 != EFI_SUCCESS)
> -			error(u"Can't free memory pages\r\n");
> -	}
> -	if (file) {
> -		ret2 = file->close(file);
> -		if (ret2 != EFI_SUCCESS)
> -			error(u"Can't close file\r\n");
> -	}
> -	if (root) {
> -		ret2 = root->close(root);
> -		if (ret2 != EFI_SUCCESS)
> -			error(u"Can't close volume\r\n");
> -	}
> -	return ret;
> -}
> -
> -/**
> - * do_save() - save current device-tree
> - *
> - * @filename:	file name
> - * Return:	status code
> - */
> -efi_status_t do_save(u16 *filename)
> -{
> -	struct efi_simple_file_system_protocol *file_system;
> -	efi_uintn_t dtb_size;
> -	struct efi_file_handle *root, *file;
> -	struct fdt_header *dtb;
> -	efi_uintn_t ret;
> -
> -	dtb = get_dtb(systable);
> -	if (!dtb) {
> -		error(u"DTB not found\r\n");
> -		return EFI_NOT_FOUND;
> -	}
> -	if (f2h(dtb->magic) != FDT_MAGIC) {
> -		error(u"Wrong device tree magic\r\n");
> -		return EFI_NOT_FOUND;
> -	}
> -	dtb_size = f2h(dtb->totalsize);
> -
> -	filename = skip_whitespace(filename);
> -
> -	ret = open_file_system(&file_system);
> -	if (ret != EFI_SUCCESS)
> -		return ret;
> -
> -	/* Open volume */
> -	ret = file_system->open_volume(file_system, &root);
> -	if (ret != EFI_SUCCESS) {
> -		error(u"Failed to open volume\r\n");
> -		return ret;
> -	}
> -	/* Check if file already exists */
> -	ret = root->open(root, &file, filename, EFI_FILE_MODE_READ, 0);
> -	if (ret == EFI_SUCCESS) {
> -		file->close(file);
> -		print(u"Overwrite existing file (y/n)? ");
> -		ret = efi_input_yn();
> -		print(u"\r\n");
> -		if (ret != EFI_SUCCESS) {
> -			root->close(root);
> -			error(u"Aborted by user\r\n");
> -			return ret;
> -		}
> -	}
> -
> -	/* Create file */
> -	ret = root->open(root, &file, filename,
> -			 EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE |
> -			 EFI_FILE_MODE_CREATE, EFI_FILE_ARCHIVE);
> -	if (ret == EFI_SUCCESS) {
> -		/* Write file */
> -		ret = file->write(file, &dtb_size, dtb);
> -		if (ret != EFI_SUCCESS)
> -			error(u"Failed to write file\r\n");
> -		file->close(file);
> -	} else {
> -		error(u"Failed to open file\r\n");
> -	}
> -	root->close(root);
> -
> -	if (ret == EFI_SUCCESS) {
> -		print(filename);
> -		print(u" written\r\n");
> -	}
> -
> -	return ret;
> -}
> -
> -/**
> - * efi_main() - entry point of the EFI application.
> - *
> - * @handle:	handle of the loaded image
> - * @systab:	system table
> - * Return:	status code
> - */
> -efi_status_t EFIAPI efi_main(efi_handle_t image_handle,
> -			     struct efi_system_table *systab)
> -{
> -	handle = image_handle;
> -	systable = systab;
> -	cerr = systable->std_err;
> -	cout = systable->con_out;
> -	cin = systable->con_in;
> -	bs = systable->boottime;
> -
> -	cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
> -	cout->clear_screen(cout);
> -	cout->set_attribute(cout, EFI_WHITE | EFI_BACKGROUND_BLACK);
> -	print(u"DTB Dump\r\n========\r\n\r\n");
> -	cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
> -
> -	for (;;) {
> -		u16 command[BUFFER_SIZE];
> -		u16 *pos;
> -		efi_uintn_t ret;
> -
> -		print(u"=> ");
> -		ret = efi_input(command, sizeof(command));
> -		if (ret == EFI_ABORTED)
> -			break;
> -		pos = skip_whitespace(command);
> -		if (starts_with(pos, u"exit"))
> -			break;
> -		else if (starts_with(pos, u"load "))
> -			do_load(pos + 5);
> -		else if (starts_with(pos, u"save "))
> -			do_save(pos + 5);
> -		else
> -			do_help();
> -	}
> -
> -	cout->set_attribute(cout, EFI_LIGHTGRAY | EFI_BACKGROUND_BLACK);
> -	cout->clear_screen(cout);
> -	return EFI_SUCCESS;
> -}
> diff --git a/lib/efi_selftest/initrddump.c b/lib/efi_selftest/initrddump.c
> deleted file mode 100644
> index 4648d54b13..0000000000
> --- a/lib/efi_selftest/initrddump.c
> +++ /dev/null
> @@ -1,449 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0+
> -/*
> - * Copyright 2020, Heinrich Schuchardt <xypron.glpk@gmx.de>
> - *
> - * initrddump.efi saves the initial RAM disk provided via the
> - * EFI_LOAD_FILE2_PROTOCOL.
> - */
> -
> -#include <common.h>
> -#include <efi_api.h>
> -#include <efi_load_initrd.h>
> -
> -#define BUFFER_SIZE 64
> -#define ESC 0x17
> -
> -#define efi_size_in_pages(size) (((size) + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT)
> -
> -static struct efi_system_table *systable;
> -static struct efi_boot_services *bs;
> -static struct efi_simple_text_output_protocol *cerr;
> -static struct efi_simple_text_output_protocol *cout;
> -static struct efi_simple_text_input_protocol *cin;
> -static const efi_guid_t loaded_image_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
> -static const efi_guid_t guid_simple_file_system_protocol =
> -					EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
> -static const efi_guid_t load_file2_guid = EFI_LOAD_FILE2_PROTOCOL_GUID;
> -static efi_handle_t handle;
> -
> -/*
> - * Device path defined by Linux to identify the handle providing the
> - * EFI_LOAD_FILE2_PROTOCOL used for loading the initial ramdisk.
> - */
> -static const struct efi_initrd_dp initrd_dp = {
> -	.vendor = {
> -		{
> -		   DEVICE_PATH_TYPE_MEDIA_DEVICE,
> -		   DEVICE_PATH_SUB_TYPE_VENDOR_PATH,
> -		   sizeof(initrd_dp.vendor),
> -		},
> -		EFI_INITRD_MEDIA_GUID,
> -	},
> -	.end = {
> -		DEVICE_PATH_TYPE_END,
> -		DEVICE_PATH_SUB_TYPE_END,
> -		sizeof(initrd_dp.end),
> -	}
> -};
> -
> -/**
> - * print() - print string
> - *
> - * @string:	text
> - */
> -static void print(u16 *string)
> -{
> -	cout->output_string(cout, string);
> -}
> -
> -/**
> - * error() - print error string
> - *
> - * @string:	error text
> - */
> -static void error(u16 *string)
> -{
> -	cout->set_attribute(cout, EFI_LIGHTRED | EFI_BACKGROUND_BLACK);
> -	print(string);
> -	cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
> -}
> -
> -/*
> - * printx() - print hexadecimal number
> - *
> - * @val:	value to print;
> - * @prec:	minimum number of digits to print
> - */
> -static void printx(u64 val, u32 prec)
> -{
> -	int i;
> -	u16 c;
> -	u16 buf[16];
> -	u16 *pos = buf;
> -
> -	for (i = 2 * sizeof(val) - 1; i >= 0; --i) {
> -		c = (val >> (4 * i)) & 0x0f;
> -		if (c || pos != buf || !i || i < prec) {
> -			c += '0';
> -			if (c > '9')
> -				c += 'a' - '9' - 1;
> -			*pos++ = c;
> -		}
> -	}
> -	*pos = 0;
> -	print(buf);
> -}
> -
> -/**
> - * efi_input_yn() - get answer to yes/no question
> - *
> - * Return:
> - * y or Y
> - *     EFI_SUCCESS
> - * n or N
> - *     EFI_ACCESS_DENIED
> - * ESC
> - *     EFI_ABORTED
> - */
> -static efi_status_t efi_input_yn(void)
> -{
> -	struct efi_input_key key = {0};
> -	efi_uintn_t index;
> -	efi_status_t ret;
> -
> -	/* Drain the console input */
> -	ret = cin->reset(cin, true);
> -	for (;;) {
> -		ret = bs->wait_for_event(1, &cin->wait_for_key, &index);
> -		if (ret != EFI_SUCCESS)
> -			continue;
> -		ret = cin->read_key_stroke(cin, &key);
> -		if (ret != EFI_SUCCESS)
> -			continue;
> -		switch (key.scan_code) {
> -		case 0x17: /* Escape */
> -			return EFI_ABORTED;
> -		default:
> -			break;
> -		}
> -		/* Convert to lower case */
> -		switch (key.unicode_char | 0x20) {
> -		case 'y':
> -			return EFI_SUCCESS;
> -		case 'n':
> -			return EFI_ACCESS_DENIED;
> -		default:
> -			break;
> -		}
> -	}
> -}
> -
> -/**
> - * efi_input() - read string from console
> - *
> - * @buffer:		input buffer
> - * @buffer_size:	buffer size
> - * Return:		status code
> - */
> -static efi_status_t efi_input(u16 *buffer, efi_uintn_t buffer_size)
> -{
> -	struct efi_input_key key = {0};
> -	efi_uintn_t index;
> -	efi_uintn_t pos = 0;
> -	u16 outbuf[2] = u" ";
> -	efi_status_t ret;
> -
> -	/* Drain the console input */
> -	ret = cin->reset(cin, true);
> -	*buffer = 0;
> -	for (;;) {
> -		ret = bs->wait_for_event(1, &cin->wait_for_key, &index);
> -		if (ret != EFI_SUCCESS)
> -			continue;
> -		ret = cin->read_key_stroke(cin, &key);
> -		if (ret != EFI_SUCCESS)
> -			continue;
> -		switch (key.scan_code) {
> -		case 0x17: /* Escape */
> -			print(u"\r\nAborted\r\n");
> -			return EFI_ABORTED;
> -		default:
> -			break;
> -		}
> -		switch (key.unicode_char) {
> -		case 0x08: /* Backspace */
> -			if (pos) {
> -				buffer[pos--] = 0;
> -				print(u"\b \b");
> -			}
> -			break;
> -		case 0x0a: /* Linefeed */
> -		case 0x0d: /* Carriage return */
> -			print(u"\r\n");
> -			return EFI_SUCCESS;
> -		default:
> -			break;
> -		}
> -		/* Ignore surrogate codes */
> -		if (key.unicode_char >= 0xD800 && key.unicode_char <= 0xDBFF)
> -			continue;
> -		if (key.unicode_char >= 0x20 &&
> -		    pos < buffer_size - 1) {
> -			*outbuf = key.unicode_char;
> -			buffer[pos++] = key.unicode_char;
> -			buffer[pos] = 0;
> -			print(outbuf);
> -		}
> -	}
> -}
> -
> -/**
> - * skip_whitespace() - skip over leading whitespace
> - *
> - * @pos:	UTF-16 string
> - * Return:	pointer to first non-whitespace
> - */
> -static u16 *skip_whitespace(u16 *pos)
> -{
> -	for (; *pos && *pos <= 0x20; ++pos)
> -		;
> -	return pos;
> -}
> -
> -/**
> - * starts_with() - check if @string starts with @keyword
> - *
> - * @string:	string to search for keyword
> - * @keyword:	keyword to be searched
> - * Return:	true fi @string starts with the keyword
> - */
> -static bool starts_with(u16 *string, u16 *keyword)
> -{
> -	for (; *keyword; ++string, ++keyword) {
> -		if (*string != *keyword)
> -			return false;
> -	}
> -	return true;
> -}
> -
> -/**
> - * do_help() - print help
> - */
> -static void do_help(void)
> -{
> -	error(u"load          - show length and CRC32 of initial RAM disk\r\n");
> -	error(u"save <initrd> - save initial RAM disk to file\r\n");
> -	error(u"exit          - exit the shell\r\n");
> -}
> -
> -/**
> - * get_initrd() - read initial RAM disk via EFI_LOAD_FILE2_PROTOCOL
> - *
> - * @initrd:		on return buffer with initial RAM disk
> - * @initrd_size:	size of initial RAM disk
> - * Return:		status code
> - */
> -static efi_status_t get_initrd(void **initrd, efi_uintn_t *initrd_size)
> -{
> -	struct efi_device_path *dp = (struct efi_device_path *)&initrd_dp;
> -	struct efi_load_file_protocol *load_file2_prot;
> -	u64 buffer;
> -	efi_handle_t handle;
> -	efi_status_t ret;
> -
> -	*initrd = NULL;
> -	*initrd_size = 0;
> -	ret = bs->locate_device_path(&load_file2_guid, &dp, &handle);
> -	if (ret != EFI_SUCCESS) {
> -		error(u"Load File2 protocol not found\r\n");
> -		return ret;
> -	}
> -	ret = bs->handle_protocol(handle, &load_file2_guid,
> -				 (void **)&load_file2_prot);
> -	ret = load_file2_prot->load_file(load_file2_prot, dp, false,
> -					 initrd_size, NULL);
> -	if (ret != EFI_BUFFER_TOO_SMALL) {
> -		error(u"Load File2 protocol does not provide file length\r\n");
> -		return EFI_LOAD_ERROR;
> -	}
> -	ret = bs->allocate_pages(EFI_ALLOCATE_ANY_PAGES, EFI_LOADER_DATA,
> -				 efi_size_in_pages(*initrd_size), &buffer);
> -	if (ret != EFI_SUCCESS) {
> -		error(u"Out of memory\r\n");
> -		return ret;
> -	}
> -	*initrd = (void *)(uintptr_t)buffer;
> -	ret = load_file2_prot->load_file(load_file2_prot, dp, false,
> -					 initrd_size, *initrd);
> -	if (ret != EFI_SUCCESS) {
> -		error(u"Load File2 protocol failed to provide file\r\n");
> -		bs->free_pages(buffer, efi_size_in_pages(*initrd_size));
> -		return EFI_LOAD_ERROR;
> -	}
> -	return ret;
> -}
> -
> -/**
> - * do_load() - load initial RAM disk and display CRC32 and length
> - *
> - * @filename:	file name
> - * Return:	status code
> - */
> -static efi_status_t do_load(void)
> -{
> -	void *initrd;
> -	efi_uintn_t initrd_size;
> -	u32 crc32;
> -	efi_uintn_t ret;
> -
> -	ret =  get_initrd(&initrd, &initrd_size);
> -	if (ret != EFI_SUCCESS)
> -		return ret;
> -	print(u"length: 0x");
> -	printx(initrd_size, 1);
> -	print(u"\r\n");
> -
> -	ret = bs->calculate_crc32(initrd, initrd_size, &crc32);
> -	if (ret != EFI_SUCCESS) {
> -		error(u"Calculating CRC32 failed\r\n");
> -		return EFI_LOAD_ERROR;
> -	}
> -	print(u"crc32: 0x");
> -	printx(crc32, 8);
> -	print(u"\r\n");
> -
> -	return EFI_SUCCESS;
> -}
> -
> -/**
> - * do_save() - save initial RAM disk
> - *
> - * @filename:	file name
> - * Return:	status code
> - */
> -static efi_status_t do_save(u16 *filename)
> -{
> -	struct efi_loaded_image *loaded_image;
> -	struct efi_simple_file_system_protocol *file_system;
> -	struct efi_file_handle *root, *file;
> -	void *initrd;
> -	efi_uintn_t initrd_size;
> -	efi_uintn_t ret;
> -
> -	ret = get_initrd(&initrd, &initrd_size);
> -	if (ret != EFI_SUCCESS)
> -		return ret;
> -
> -	filename = skip_whitespace(filename);
> -
> -	ret = bs->open_protocol(handle, &loaded_image_guid,
> -				(void **)&loaded_image, NULL, NULL,
> -				EFI_OPEN_PROTOCOL_GET_PROTOCOL);
> -	if (ret != EFI_SUCCESS) {
> -		error(u"Loaded image protocol not found\r\n");
> -		goto out;
> -	}
> -
> -	/* Open the simple file system protocol */
> -	ret = bs->open_protocol(loaded_image->device_handle,
> -				&guid_simple_file_system_protocol,
> -				(void **)&file_system, NULL, NULL,
> -				EFI_OPEN_PROTOCOL_GET_PROTOCOL);
> -	if (ret != EFI_SUCCESS) {
> -		error(u"Failed to open simple file system protocol\r\n");
> -		goto out;
> -	}
> -
> -	/* Open volume */
> -	ret = file_system->open_volume(file_system, &root);
> -	if (ret != EFI_SUCCESS) {
> -		error(u"Failed to open volume\r\n");
> -		goto out;
> -	}
> -	/* Check if file already exists */
> -	ret = root->open(root, &file, filename, EFI_FILE_MODE_READ, 0);
> -	if (ret == EFI_SUCCESS) {
> -		file->close(file);
> -		print(u"Overwrite existing file (y/n)? ");
> -		ret = efi_input_yn();
> -		print(u"\r\n");
> -		if (ret != EFI_SUCCESS) {
> -			root->close(root);
> -			error(u"Aborted by user\r\n");
> -			goto out;
> -		}
> -	}
> -
> -	/* Create file */
> -	ret = root->open(root, &file, filename,
> -			 EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE |
> -			 EFI_FILE_MODE_CREATE, EFI_FILE_ARCHIVE);
> -	if (ret == EFI_SUCCESS) {
> -		/* Write file */
> -		ret = file->write(file, &initrd_size, initrd);
> -		if (ret != EFI_SUCCESS) {
> -			error(u"Failed to write file\r\n");
> -		} else {
> -			print(filename);
> -			print(u" written\r\n");
> -		}
> -		file->close(file);
> -	} else {
> -		error(u"Failed to open file\r\n");
> -	}
> -	root->close(root);
> -
> -out:
> -	if (initrd)
> -		bs->free_pages((uintptr_t)initrd,
> -			       efi_size_in_pages(initrd_size));
> -	return ret;
> -}
> -
> -/**
> - * efi_main() - entry point of the EFI application.
> - *
> - * @handle:	handle of the loaded image
> - * @systab:	system table
> - * Return:	status code
> - */
> -efi_status_t EFIAPI efi_main(efi_handle_t image_handle,
> -			     struct efi_system_table *systab)
> -{
> -	handle = image_handle;
> -	systable = systab;
> -	cerr = systable->std_err;
> -	cout = systable->con_out;
> -	cin = systable->con_in;
> -	bs = systable->boottime;
> -
> -	cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
> -	cout->clear_screen(cout);
> -	cout->set_attribute(cout, EFI_WHITE | EFI_BACKGROUND_BLACK);
> -	print(u"INITRD Dump\r\n========\r\n\r\n");
> -	cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
> -
> -	for (;;) {
> -		u16 command[BUFFER_SIZE];
> -		u16 *pos;
> -		efi_uintn_t ret;
> -
> -		print(u"=> ");
> -		ret = efi_input(command, sizeof(command));
> -		if (ret == EFI_ABORTED)
> -			break;
> -		pos = skip_whitespace(command);
> -		if (starts_with(pos, u"exit"))
> -			break;
> -		else if (starts_with(pos, u"load"))
> -			do_load();
> -		else if (starts_with(pos, u"save "))
> -			do_save(pos + 5);
> -		else
> -			do_help();
> -	}
> -
> -	cout->set_attribute(cout, EFI_LIGHTGRAY | EFI_BACKGROUND_BLACK);
> -	cout->clear_screen(cout);
> -	return EFI_SUCCESS;
> -}
> -- 
> 2.34.1
> 

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 2/9] efi_loader: fix efi_dp_find_obj()
  2022-03-19  9:11 ` [PATCH v2 2/9] efi_loader: fix efi_dp_find_obj() Heinrich Schuchardt
@ 2022-03-23  7:18   ` AKASHI Takahiro
  0 siblings, 0 replies; 19+ messages in thread
From: AKASHI Takahiro @ 2022-03-23  7:18 UTC (permalink / raw)
  To: Heinrich Schuchardt; +Cc: u-boot, Ilias Apalodimas

On Sat, Mar 19, 2022 at 10:11:41AM +0100, Heinrich Schuchardt wrote:
> efi_dp_find_obj() should not return any handle with a partially matching
> device path

If so, please describe so explicitly in the function's description.
See below.

> but the handle with the maximum matching device path.
> 
> Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
> ---
> v2:
> 	new patch
> ---
>  include/efi_loader.h             |   4 +-
>  lib/efi_loader/efi_device_path.c | 110 +++++++++++++++++--------------
>  2 files changed, 63 insertions(+), 51 deletions(-)
> 
> diff --git a/include/efi_loader.h b/include/efi_loader.h
> index 1ffcdfc485..6271d40125 100644
> --- a/include/efi_loader.h
> +++ b/include/efi_loader.h
> @@ -730,8 +730,8 @@ struct efi_device_path *efi_dp_shorten(struct efi_device_path *dp);
>  struct efi_device_path *efi_dp_next(const struct efi_device_path *dp);
>  int efi_dp_match(const struct efi_device_path *a,
>  		 const struct efi_device_path *b);
> -struct efi_object *efi_dp_find_obj(struct efi_device_path *dp,
> -				   struct efi_device_path **rem);
> +efi_handle_t efi_dp_find_obj(struct efi_device_path *dp,
> +			     struct efi_device_path **rem);
>  /* get size of the first device path instance excluding end node */
>  efi_uintn_t efi_dp_instance_size(const struct efi_device_path *dp);
>  /* size of multi-instance device path excluding end node */
> diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
> index ddd5f132ec..aeb5264820 100644
> --- a/lib/efi_loader/efi_device_path.c
> +++ b/lib/efi_loader/efi_device_path.c
> @@ -159,69 +159,81 @@ struct efi_device_path *efi_dp_shorten(struct efi_device_path *dp)
>  	return dp;
>  }
>  
> -static struct efi_object *find_obj(struct efi_device_path *dp, bool short_path,
> -				   struct efi_device_path **rem)
> +/**
> + * find_handle() - find handle by device path
> + *
> + * If @rem is provided, the handle with the longest partial match is returned.
> + *
> + * @dp:		device path to search
> + * @short_path:	use short form device path for matching
> + * @rem:	pointer to receive remaining device path
> + * Return:	matching handle
> + */
> +static efi_handle_t find_handle(struct efi_device_path *dp, bool short_path,
> +			        struct efi_device_path **rem)
>  {
> -	struct efi_object *efiobj;
> -	efi_uintn_t dp_size = efi_dp_instance_size(dp);
> +	efi_handle_t handle, best_handle = NULL;
> +	efi_uintn_t len, best_len = 0;
> +
> +	len = efi_dp_instance_size(dp);
>  
> -	list_for_each_entry(efiobj, &efi_obj_list, link) {
> +	list_for_each_entry(handle, &efi_obj_list, link) {
>  		struct efi_handler *handler;
> -		struct efi_device_path *obj_dp;
> +		struct efi_device_path *dp_current;
> +		efi_uintn_t len_current;
>  		efi_status_t ret;
>  
> -		ret = efi_search_protocol(efiobj,
> -					  &efi_guid_device_path, &handler);
> +		ret = efi_search_protocol(handle, &efi_guid_device_path,
> +					  &handler);
>  		if (ret != EFI_SUCCESS)
>  			continue;
> -		obj_dp = handler->protocol_interface;
> -
> -		do {
> -			if (efi_dp_match(dp, obj_dp) == 0) {
> -				if (rem) {
> -					/*
> -					 * Allow partial matches, but inform
> -					 * the caller.
> -					 */
> -					*rem = ((void *)dp) +
> -						efi_dp_instance_size(obj_dp);
> -					return efiobj;
> -				} else {
> -					/* Only return on exact matches */
> -					if (efi_dp_instance_size(obj_dp) ==
> -					    dp_size)
> -						return efiobj;
> -				}
> -			}
> -
> -			obj_dp = efi_dp_shorten(efi_dp_next(obj_dp));
> -		} while (short_path && obj_dp);
> +		dp_current = handler->protocol_interface;
> +		if (short_path) {
> +			dp_current = efi_dp_shorten(dp_current);
> +			if (!dp_current)
> +				continue;
> +		}
> +		len_current = efi_dp_instance_size(dp_current);
> +		if (rem) {
> +			if (len_current < len)
> +				continue;
> +		} else {
> +			if (len_current != len)
> +				continue;
> +		}
> +		if (memcmp(dp_current, dp, len))
> +			continue;
> +		if (!rem)
> +			return handle;
> +		if (len_current > best_len) {
> +			best_len = len_current;
> +			best_handle = handle;
> +			*rem = (void*)((u8 *)dp + len_current);
> +		}
>  	}
> -
> -	return NULL;
> +	return best_handle;
>  }
>  
> -/*
> - * Find an efiobj from device-path, if 'rem' is not NULL, returns the
> - * remaining part of the device path after the matched object.
> +/**
> + * efi_dp_find_obj() - find handle by device path
> + *
> + * If @rem is provided, the handle with the longest partial match is returned.

What if @rem == NULL.

> + *
> + * @dp:		device path to search
> + * @rem:	pointer to receive remaining device path
> + * Return:	matching handle
>   */
> -struct efi_object *efi_dp_find_obj(struct efi_device_path *dp,
> -				   struct efi_device_path **rem)
> +efi_handle_t efi_dp_find_obj(struct efi_device_path *dp,
> +			     struct efi_device_path **rem)

The return type was also changed.
Why not change the function name to, say, efi_dp_find_handle()
"object" is an internal representation.

-Takahiro Akashi

>  {
> -	struct efi_object *efiobj;
> -
> -	/* Search for an exact match first */
> -	efiobj = find_obj(dp, false, NULL);
> -
> -	/* Then for a fuzzy match */
> -	if (!efiobj)
> -		efiobj = find_obj(dp, false, rem);
> +	efi_handle_t handle;
>  
> -	/* And now for a fuzzy short match */
> -	if (!efiobj)
> -		efiobj = find_obj(dp, true, rem);
> +	handle = find_handle(dp, false, rem);
> +	if (!handle)
> +		/* Match short form device path */
> +		handle = find_handle(dp, true, rem);
>  
> -	return efiobj;
> +	return handle;
>  }
>  
>  /*
> -- 
> 2.34.1
> 

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 3/9] efi_loader: efi_dp_find_obj() add protocol check
  2022-03-19  9:11 ` [PATCH v2 3/9] efi_loader: efi_dp_find_obj() add protocol check Heinrich Schuchardt
@ 2022-03-23  7:26   ` AKASHI Takahiro
  0 siblings, 0 replies; 19+ messages in thread
From: AKASHI Takahiro @ 2022-03-23  7:26 UTC (permalink / raw)
  To: Heinrich Schuchardt; +Cc: u-boot, Ilias Apalodimas

On Sat, Mar 19, 2022 at 10:11:42AM +0100, Heinrich Schuchardt wrote:
> Let function efi_dp_find_obj() additionally check if a given protocol is
> installed on the handle relating to the device-path.

Please describe why you want to add another parameter to the function.
Otherwise, we don't understand why the change is necessary.
The caller can simply call efi_search_protocol() to determine whether the given
protocol is installed or not on the handle.

> Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
> ---
> v2:
> 	new patch
> ---
>  include/efi_loader.h             |  1 +
>  lib/efi_loader/efi_boottime.c    |  2 +-
>  lib/efi_loader/efi_capsule.c     |  2 +-
>  lib/efi_loader/efi_device_path.c | 23 ++++++++++++++++-------
>  lib/efi_loader/efi_disk.c        |  2 +-
>  5 files changed, 20 insertions(+), 10 deletions(-)
> 
> diff --git a/include/efi_loader.h b/include/efi_loader.h
> index 6271d40125..1ae47a8713 100644
> --- a/include/efi_loader.h
> +++ b/include/efi_loader.h
> @@ -731,6 +731,7 @@ struct efi_device_path *efi_dp_next(const struct efi_device_path *dp);
>  int efi_dp_match(const struct efi_device_path *a,
>  		 const struct efi_device_path *b);
>  efi_handle_t efi_dp_find_obj(struct efi_device_path *dp,
> +			     const efi_guid_t *guid,
>  			     struct efi_device_path **rem);
>  /* get size of the first device path instance excluding end node */
>  efi_uintn_t efi_dp_instance_size(const struct efi_device_path *dp);
> diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
> index d0f3e05e70..a7bc371f54 100644
> --- a/lib/efi_loader/efi_boottime.c
> +++ b/lib/efi_loader/efi_boottime.c
> @@ -1750,7 +1750,7 @@ efi_status_t efi_setup_loaded_image(struct efi_device_path *device_path,
>  	info->system_table = &systab;
>  
>  	if (device_path) {
> -		info->device_handle = efi_dp_find_obj(device_path, NULL);
> +		info->device_handle = efi_dp_find_obj(device_path, NULL, NULL);
>  
>  		dp = efi_dp_append(device_path, file_path);
>  		if (!dp) {
> diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c
> index c8e2d510a5..3d80d98c1f 100644
> --- a/lib/efi_loader/efi_capsule.c
> +++ b/lib/efi_loader/efi_capsule.c
> @@ -681,7 +681,7 @@ static bool device_is_present_and_system_part(struct efi_device_path *dp)
>  {
>  	efi_handle_t handle;
>  
> -	handle = efi_dp_find_obj(dp, NULL);
> +	handle = efi_dp_find_obj(dp, NULL, NULL);
>  	if (!handle)
>  		return false;
>  
> diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
> index aeb5264820..0a8802903d 100644
> --- a/lib/efi_loader/efi_device_path.c
> +++ b/lib/efi_loader/efi_device_path.c
> @@ -160,17 +160,19 @@ struct efi_device_path *efi_dp_shorten(struct efi_device_path *dp)
>  }
>  
>  /**
> - * find_handle() - find handle by device path
> + * find_handle() - find handle by device path and installed protocol
>   *
>   * If @rem is provided, the handle with the longest partial match is returned.
>   *
>   * @dp:		device path to search
> + * @guid:	GUID of protocol that must be installed on path or NULL
>   * @short_path:	use short form device path for matching
>   * @rem:	pointer to receive remaining device path
>   * Return:	matching handle
>   */
> -static efi_handle_t find_handle(struct efi_device_path *dp, bool short_path,
> -			        struct efi_device_path **rem)
> +static efi_handle_t find_handle(struct efi_device_path *dp,
> +				const efi_guid_t *guid, bool short_path,
> +				struct efi_device_path **rem)
>  {
>  	efi_handle_t handle, best_handle = NULL;
>  	efi_uintn_t len, best_len = 0;
> @@ -183,6 +185,11 @@ static efi_handle_t find_handle(struct efi_device_path *dp, bool short_path,
>  		efi_uintn_t len_current;
>  		efi_status_t ret;
>  
> +		if (guid) {
> +			ret = efi_search_protocol(handle, guid, &handler);
> +			if (ret != EFI_SUCCESS)
> +				continue;
> +		}
>  		ret = efi_search_protocol(handle, &efi_guid_device_path,
>  					  &handler);
>  		if (ret != EFI_SUCCESS)
> @@ -195,13 +202,13 @@ static efi_handle_t find_handle(struct efi_device_path *dp, bool short_path,
>  		}
>  		len_current = efi_dp_instance_size(dp_current);
>  		if (rem) {
> -			if (len_current < len)
> +			if (len_current > len)

It looks a bug fix, but it's not related to this patch?

-Takahiro Akashi

>  				continue;
>  		} else {
>  			if (len_current != len)
>  				continue;
>  		}
> -		if (memcmp(dp_current, dp, len))
> +		if (memcmp(dp_current, dp, len_current))
>  			continue;
>  		if (!rem)
>  			return handle;
> @@ -220,18 +227,20 @@ static efi_handle_t find_handle(struct efi_device_path *dp, bool short_path,
>   * If @rem is provided, the handle with the longest partial match is returned.
>   *
>   * @dp:		device path to search
> + * @guid:	GUID of protocol that must be installed on path or NULL
>   * @rem:	pointer to receive remaining device path
>   * Return:	matching handle
>   */
>  efi_handle_t efi_dp_find_obj(struct efi_device_path *dp,
> +			     const efi_guid_t *guid,
>  			     struct efi_device_path **rem)
>  {
>  	efi_handle_t handle;
>  
> -	handle = find_handle(dp, false, rem);
> +	handle = find_handle(dp, guid, false, rem);
>  	if (!handle)
>  		/* Match short form device path */
> -		handle = find_handle(dp, true, rem);
> +		handle = find_handle(dp, guid, true, rem);
>  
>  	return handle;
>  }
> diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c
> index 45127d1768..d36a35d94f 100644
> --- a/lib/efi_loader/efi_disk.c
> +++ b/lib/efi_loader/efi_disk.c
> @@ -302,7 +302,7 @@ efi_fs_from_path(struct efi_device_path *full_path)
>  	efi_free_pool(file_path);
>  
>  	/* Get the EFI object for the partition */
> -	efiobj = efi_dp_find_obj(device_path, NULL);
> +	efiobj = efi_dp_find_obj(device_path, NULL, NULL);
>  	efi_free_pool(device_path);
>  	if (!efiobj)
>  		return NULL;
> -- 
> 2.34.1
> 

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 4/9] efi_loader: support booting via short-form device-path
  2022-03-19  9:11 ` [PATCH v2 4/9] efi_loader: support booting via short-form device-path Heinrich Schuchardt
@ 2022-03-23  7:50   ` AKASHI Takahiro
  0 siblings, 0 replies; 19+ messages in thread
From: AKASHI Takahiro @ 2022-03-23  7:50 UTC (permalink / raw)
  To: Heinrich Schuchardt; +Cc: u-boot, Ilias Apalodimas

On Sat, Mar 19, 2022 at 10:11:43AM +0100, Heinrich Schuchardt wrote:
> The boot manager must support loading from boot options using a short-form
> device-path, e.g. one where the first element is a hard drive media path.
> 
> See '3.1.2 Load Options Processing' in UEFI specification version 2.9.

Thank you for adding this feature.
Just reminder; a hard drive media path is not the only case for allowing
short-form paths. In particular,  booting from a short-form path starting
with a *file path* device path is also, in my opinion, valuable.

So we should have some description, in the commit message or the comment,
about this sort of limitation or TODO in handling short-form paths even
after this commit.

> Fixes: 0e074d12393b ("efi_loader: carve out efi_load_image_from_file()")
> Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
> ---
> v2:
> 	path correct remaining paths to LOAD_FILE(2) protocol
> ---
>  lib/efi_loader/efi_boottime.c | 20 ++++++++++----------
>  1 file changed, 10 insertions(+), 10 deletions(-)
> 
> diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
> index a7bc371f54..5bcb8253ed 100644
> --- a/lib/efi_loader/efi_boottime.c
> +++ b/lib/efi_loader/efi_boottime.c
> @@ -1940,7 +1940,7 @@ efi_status_t efi_load_image_from_path(bool boot_policy,
>  {
>  	efi_handle_t device;
>  	efi_status_t ret;
> -	struct efi_device_path *dp;
> +	struct efi_device_path *dp, *rem;
>  	struct efi_load_file_protocol *load_file_protocol = NULL;
>  	efi_uintn_t buffer_size;
>  	uint64_t addr, pages;
> @@ -1951,18 +1951,18 @@ efi_status_t efi_load_image_from_path(bool boot_policy,
>  	*size = 0;
>  
>  	dp = file_path;
> -	ret = EFI_CALL(efi_locate_device_path(
> -		       &efi_simple_file_system_protocol_guid, &dp, &device));
> +	device = efi_dp_find_obj(dp, NULL, &rem);
> +	ret = efi_search_protocol(device, &efi_simple_file_system_protocol_guid,
> +				  NULL);

I think that you intended to use your *new* efi_dp_find_obj() in patch#3 here.

-Takahiro Akashi


>  	if (ret == EFI_SUCCESS)
>  		return efi_load_image_from_file(file_path, buffer, size);
>  
> -	ret = EFI_CALL(efi_locate_device_path(
> -		       &efi_guid_load_file_protocol, &dp, &device));
> +	ret = efi_search_protocol(device, &efi_guid_load_file_protocol, NULL);
>  	if (ret == EFI_SUCCESS) {
>  		guid = &efi_guid_load_file_protocol;
>  	} else if (!boot_policy) {
>  		guid = &efi_guid_load_file2_protocol;
> -		ret = EFI_CALL(efi_locate_device_path(guid, &dp, &device));
> +		ret = efi_search_protocol(device, guid, NULL);
>  	}
>  	if (ret != EFI_SUCCESS)
>  		return EFI_NOT_FOUND;
> @@ -1971,9 +1971,9 @@ efi_status_t efi_load_image_from_path(bool boot_policy,
>  	if (ret != EFI_SUCCESS)
>  		return EFI_NOT_FOUND;
>  	buffer_size = 0;
> -	ret = load_file_protocol->load_file(load_file_protocol, dp,
> -					    boot_policy, &buffer_size,
> -					    NULL);
> +	ret = EFI_CALL(load_file_protocol->load_file(
> +					load_file_protocol, rem, boot_policy,
> +					&buffer_size, NULL));
>  	if (ret != EFI_BUFFER_TOO_SMALL)
>  		goto out;
>  	pages = efi_size_in_pages(buffer_size);
> @@ -1984,7 +1984,7 @@ efi_status_t efi_load_image_from_path(bool boot_policy,
>  		goto out;
>  	}
>  	ret = EFI_CALL(load_file_protocol->load_file(
> -					load_file_protocol, dp, boot_policy,
> +					load_file_protocol, rem, boot_policy,
>  					&buffer_size, (void *)(uintptr_t)addr));
>  	if (ret != EFI_SUCCESS)
>  		efi_free_pages(addr, pages);
> -- 
> 2.34.1
> 

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 5/9] efi_loader: use short-form DP for load options
  2022-03-19  9:11 ` [PATCH v2 5/9] efi_loader: use short-form DP for load options Heinrich Schuchardt
@ 2022-03-23  8:18   ` AKASHI Takahiro
  0 siblings, 0 replies; 19+ messages in thread
From: AKASHI Takahiro @ 2022-03-23  8:18 UTC (permalink / raw)
  To: Heinrich Schuchardt; +Cc: u-boot, Ilias Apalodimas, Heinrich Schuchardt

On Sat, Mar 19, 2022 at 10:11:44AM +0100, Heinrich Schuchardt wrote:
> From: Heinrich Schuchardt <xypron.glpk@gmx.de>
> 
> The GUID of partitions is sufficient for identification and will stay
> constant in the lifetime of a boot option. The preceding path of the
> device-path may change due to changes in the enumeration of devices.
> Therefore it is preferable to use the short-form of device-paths in load
> options. Adjust the 'efidebug boot add' command accordingly.
> 
> Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
> ---
> v2:
> 	support both short and long form device paths
> 	split off exporting efi_dp_shorten() into a separate patch
> ---
>  cmd/efidebug.c | 70 ++++++++++++++++++++++++++++++++++----------------
>  1 file changed, 48 insertions(+), 22 deletions(-)
> 
> diff --git a/cmd/efidebug.c b/cmd/efidebug.c
> index 401d13cc4c..51e2850d21 100644
> --- a/cmd/efidebug.c
> +++ b/cmd/efidebug.c
> @@ -734,20 +734,20 @@ static int do_efi_show_tables(struct cmd_tbl *cmdtp, int flag,
>  }
>  
>  /**
> - * create_initrd_dp() - Create a special device for our Boot### option
> - *
> - * @dev:	Device
> - * @part:	Disk partition
> - * @file:	Filename
> - * Return:	Pointer to the device path or ERR_PTR
> + * create_initrd_dp() - create a special device for our Boot### option
>   *
> + * @dev:	device
> + * @part:	disk partition
> + * @file:	filename
> + * @shortform:	create short form device path
> + * Return:	pointer to the device path or ERR_PTR
>   */
>  static
>  struct efi_device_path *create_initrd_dp(const char *dev, const char *part,
> -					 const char *file)
> +					 const char *file, int shortform)
>  
>  {
> -	struct efi_device_path *tmp_dp = NULL, *tmp_fp = NULL;
> +	struct efi_device_path *tmp_dp = NULL, *tmp_fp = NULL, *short_fp = NULL;
>  	struct efi_device_path *initrd_dp = NULL;
>  	efi_status_t ret;
>  	const struct efi_initrd_dp id_dp = {
> @@ -771,9 +771,13 @@ struct efi_device_path *create_initrd_dp(const char *dev, const char *part,
>  		printf("Cannot create device path for \"%s %s\"\n", part, file);
>  		goto out;
>  	}
> +	if (shortform)
> +		short_fp = efi_dp_shorten(tmp_fp);
> +	if (!short_fp)
> +		short_fp = tmp_fp;
>  
>  	initrd_dp = efi_dp_append((const struct efi_device_path *)&id_dp,
> -				  tmp_fp);
> +				  short_fp);
>  
>  out:
>  	efi_free_pool(tmp_dp);
> @@ -807,6 +811,7 @@ static int do_efi_boot_add(struct cmd_tbl *cmdtp, int flag,
>  	size_t label_len, label_len16;
>  	u16 *label;
>  	struct efi_device_path *device_path = NULL, *file_path = NULL;
> +	struct efi_device_path *fp_free = NULL;
>  	struct efi_device_path *final_fp = NULL;
>  	struct efi_device_path *initrd_dp = NULL;
>  	struct efi_load_option lo;
> @@ -826,7 +831,18 @@ static int do_efi_boot_add(struct cmd_tbl *cmdtp, int flag,
>  	argc--;
>  	argv++; /* 'add' */
>  	for (; argc > 0; argc--, argv++) {
> -		if (!strcmp(argv[0], "-b")) {
> +		int shortform;
> +
> +		if (*argv[0] != '-' || strlen(argv[0]) != 2) {
> +				r = CMD_RET_USAGE;
> +				goto out;
> +		}
> +		shortform = 0;
> +		switch (argv[0][1]) {
> +		case 'b':
> +			shortform = 1;
> +			/* fallthrough */
> +		case 'B':
>  			if (argc <  5 || lo.label) {
>  				r = CMD_RET_USAGE;
>  				goto out;
> @@ -849,24 +865,33 @@ static int do_efi_boot_add(struct cmd_tbl *cmdtp, int flag,
>  
>  			/* file path */
>  			ret = efi_dp_from_name(argv[3], argv[4], argv[5],
> -					       &device_path, &file_path);
> +					       &device_path, &fp_free);

The semantics of efi_dp_from_name() seems odd as both "device_path" and
"file_path" (or "fp_free") may partially contain a duplicated device path.
That is why "device_path" is not used after this line.

Although this behavior has not changed since my initial implementation,
"file_path" should not have included preceding device path components
other than the file path media device path.

Anyhow, we can pass NULL instead of "&device_path" for now.

>  			if (ret != EFI_SUCCESS) {
>  				printf("Cannot create device path for \"%s %s\"\n",
>  				       argv[3], argv[4]);
>  				r = CMD_RET_FAILURE;
>  				goto out;
>  			}
> +			if (shortform)
> +				file_path = efi_dp_shorten(fp_free);
> +			if (!file_path)
> +				file_path = fp_free;
>  			fp_size += efi_dp_size(file_path) +
>  				sizeof(struct efi_device_path);
>  			argc -= 5;
>  			argv += 5;
> -		} else if (!strcmp(argv[0], "-i")) {
> +			break;
> +		case 'i':
> +			shortform = 1;
> +			/* fallthrough */
> +		case 'I':
>  			if (argc < 3 || initrd_dp) {
>  				r = CMD_RET_USAGE;
>  				goto out;
>  			}
>  
> -			initrd_dp = create_initrd_dp(argv[1], argv[2], argv[3]);
> +			initrd_dp = create_initrd_dp(argv[1], argv[2], argv[3],
> +						     shortform);
>  			if (!initrd_dp) {
>  				printf("Cannot add an initrd\n");
>  				r = CMD_RET_FAILURE;
> @@ -876,7 +901,8 @@ static int do_efi_boot_add(struct cmd_tbl *cmdtp, int flag,
>  			argv += 3;
>  			fp_size += efi_dp_size(initrd_dp) +
>  				sizeof(struct efi_device_path);
> -		} else if (!strcmp(argv[0], "-s")) {
> +			break;
> +		case 's':
>  			if (argc < 1 || lo.optional_data) {
>  				r = CMD_RET_USAGE;
>  				goto out;
> @@ -884,7 +910,8 @@ static int do_efi_boot_add(struct cmd_tbl *cmdtp, int flag,
>  			lo.optional_data = (const u8 *)argv[1];
>  			argc -= 1;
>  			argv += 1;
> -		} else {
> +			break;
> +		default:
>  			r = CMD_RET_USAGE;
>  			goto out;
>  		}
> @@ -927,7 +954,7 @@ out:
>  	efi_free_pool(final_fp);
>  	efi_free_pool(initrd_dp);
>  	efi_free_pool(device_path);
> -	efi_free_pool(file_path);
> +	efi_free_pool(fp_free);
>  	free(lo.label);
>  
>  	return r;
> @@ -1571,12 +1598,11 @@ static int do_efidebug(struct cmd_tbl *cmdtp, int flag,
>  static char efidebug_help_text[] =
>  	"  - UEFI Shell-like interface to configure UEFI environment\n"
>  	"\n"
> -	"efidebug boot add "
> -	"-b <bootid> <label> <interface> <devnum>[:<part>] <file path> "
> -	"-i <interface> <devnum>[:<part>] <initrd file path> "
> -	"-s '<optional data>'\n"
> -	"  - set UEFI BootXXXX variable\n"
> -	"    <load options> will be passed to UEFI application\n"
> +	"efidebug boot add - set UEFI BootXXXX variable\n"
> +	"  -b|-B <bootid> <label> <interface> <devnum>[:<part>] <file path>\n"
> +	"  -i|-I <interface> <devnum>[:<part>] <initrd file path>\n"
> +	"  (-b, -i for short form device path)\n"

I know you want to use short-forms (-b/-i) as default, but this change of meanings
potentially breaks the backward compatibility of command syntax although it's not a bug fix.

-Takahiro Akashi


> +	"  -s '<optional data>'\n"
>  	"efidebug boot rm <bootid#1> [<bootid#2> [<bootid#3> [...]]]\n"
>  	"  - delete UEFI BootXXXX variables\n"
>  	"efidebug boot dump\n"
> -- 
> 2.34.1
> 

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 0/9] efi_loader: booting via short-form device-path
@ 2022-03-25  9:12   ` AKASHI Takahiro
  0 siblings, 0 replies; 19+ messages in thread
From: AKASHI Takahiro @ 2022-03-25  7:01 UTC (permalink / raw)
  To: Heinrich Schuchardt; +Cc: u-boot, Ilias Apalodimas

Heinrich,

I made the same complaint several times in the past.
If I made some comments on your patches, don't merge them
until we have reached the agreement even you are the maintainer.
It's not the way how the community development should work.

This happened again with this patch series.

-Takahiro Akashi

On Sat, Mar 19, 2022 at 10:11:39AM +0100, Heinrich Schuchardt wrote:
> The GUID of partitions is sufficient for identification and will stay
> constant in the lifetime of a boot option. The preceding path of the
> device-path may change due to changes in the enumeration of devices.
> Therefore it is preferable to use the short-form of device-paths in load
> options.
> 
> 
> With this series booting via short-form device-paths is reenable.
> The 'efidebug boot add' command is adjusted to create either short-form
> or long-form device paths.
> 
> The check for the EFI System Partition used for capsule updates is
> corrected.
> 
> A unit test for the boot manager is added.
> 
> v2:
> 	merge multiple patches to a series
> 	fix ESP detection
> 
> Heinrich Schuchardt (9):
>   efi_loader: export efi_dp_shorten()
>   efi_loader: fix efi_dp_find_obj()
>   efi_loader: efi_dp_find_obj() add protocol check
>   efi_loader: support booting via short-form device-path
>   efi_loader: use short-form DP for load options
>   efi_loader: export efi_system_partition_guid
>   efi_loader: remove efi_disk_is_system_part()
>   efi_loader: move dtbdump.c, initrddump.c to lib/efi_loader
>   test: test UEFI boot manager
> 
>  cmd/efidebug.c                                |  70 ++-
>  include/efi_loader.h                          |  12 +-
>  lib/efi_loader/Makefile                       |  12 +
>  lib/efi_loader/dtbdump.c                      | 539 ++++++++++++++++++
>  lib/efi_loader/efi_boottime.c                 |  22 +-
>  lib/efi_loader/efi_capsule.c                  |  13 +-
>  lib/efi_loader/efi_device_path.c              | 138 +++--
>  lib/efi_loader/efi_disk.c                     |  31 +-
>  lib/efi_loader/initrddump.c                   | 449 +++++++++++++++
>  lib/efi_selftest/Makefile                     |  12 -
>  lib/efi_selftest/dtbdump.c                    | 539 ------------------
>  lib/efi_selftest/initrddump.c                 | 449 ---------------
>  test/py/tests/test_efi_bootmgr/conftest.py    |  42 ++
>  .../test_efi_bootmgr/test_efi_bootmgr.py      |  31 +
>  14 files changed, 1232 insertions(+), 1127 deletions(-)
>  create mode 100644 lib/efi_loader/dtbdump.c
>  create mode 100644 lib/efi_loader/initrddump.c
>  delete mode 100644 lib/efi_selftest/dtbdump.c
>  delete mode 100644 lib/efi_selftest/initrddump.c
>  create mode 100644 test/py/tests/test_efi_bootmgr/conftest.py
>  create mode 100644 test/py/tests/test_efi_bootmgr/test_efi_bootmgr.py
> 
> -- 
> 2.34.1
> 

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 0/9] efi_loader: booting via short-form device-path
@ 2022-03-25  9:12   ` AKASHI Takahiro
  0 siblings, 0 replies; 19+ messages in thread
From: AKASHI Takahiro @ 2022-03-25  9:12 UTC (permalink / raw)
  To: Heinrich Schuchardt; +Cc: u-boot, Ilias Apalodimas

Heinrich,

I made the same complaint several times in the past.
If I made some comments on your patches, don't merge them
until we have reached the agreement even you are the maintainer.
It's not the way how the community development should work.

This happened again with this patch series.

-Takahiro Akashi

On Sat, Mar 19, 2022 at 10:11:39AM +0100, Heinrich Schuchardt wrote:
> The GUID of partitions is sufficient for identification and will stay
> constant in the lifetime of a boot option. The preceding path of the
> device-path may change due to changes in the enumeration of devices.
> Therefore it is preferable to use the short-form of device-paths in load
> options.
> 
> 
> With this series booting via short-form device-paths is reenable.
> The 'efidebug boot add' command is adjusted to create either short-form
> or long-form device paths.
> 
> The check for the EFI System Partition used for capsule updates is
> corrected.
> 
> A unit test for the boot manager is added.
> 
> v2:
> 	merge multiple patches to a series
> 	fix ESP detection
> 
> Heinrich Schuchardt (9):
>   efi_loader: export efi_dp_shorten()
>   efi_loader: fix efi_dp_find_obj()
>   efi_loader: efi_dp_find_obj() add protocol check
>   efi_loader: support booting via short-form device-path
>   efi_loader: use short-form DP for load options
>   efi_loader: export efi_system_partition_guid
>   efi_loader: remove efi_disk_is_system_part()
>   efi_loader: move dtbdump.c, initrddump.c to lib/efi_loader
>   test: test UEFI boot manager
> 
>  cmd/efidebug.c                                |  70 ++-
>  include/efi_loader.h                          |  12 +-
>  lib/efi_loader/Makefile                       |  12 +
>  lib/efi_loader/dtbdump.c                      | 539 ++++++++++++++++++
>  lib/efi_loader/efi_boottime.c                 |  22 +-
>  lib/efi_loader/efi_capsule.c                  |  13 +-
>  lib/efi_loader/efi_device_path.c              | 138 +++--
>  lib/efi_loader/efi_disk.c                     |  31 +-
>  lib/efi_loader/initrddump.c                   | 449 +++++++++++++++
>  lib/efi_selftest/Makefile                     |  12 -
>  lib/efi_selftest/dtbdump.c                    | 539 ------------------
>  lib/efi_selftest/initrddump.c                 | 449 ---------------
>  test/py/tests/test_efi_bootmgr/conftest.py    |  42 ++
>  .../test_efi_bootmgr/test_efi_bootmgr.py      |  31 +
>  14 files changed, 1232 insertions(+), 1127 deletions(-)
>  create mode 100644 lib/efi_loader/dtbdump.c
>  create mode 100644 lib/efi_loader/initrddump.c
>  delete mode 100644 lib/efi_selftest/dtbdump.c
>  delete mode 100644 lib/efi_selftest/initrddump.c
>  create mode 100644 test/py/tests/test_efi_bootmgr/conftest.py
>  create mode 100644 test/py/tests/test_efi_bootmgr/test_efi_bootmgr.py
> 
> -- 
> 2.34.1
> 

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2022-03-25  9:12 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-03-19  9:11 [PATCH v2 0/9] efi_loader: booting via short-form device-path Heinrich Schuchardt
2022-03-19  9:11 ` [PATCH v2 1/9] efi_loader: export efi_dp_shorten() Heinrich Schuchardt
2022-03-21  7:41   ` Ilias Apalodimas
2022-03-23  6:55   ` AKASHI Takahiro
2022-03-19  9:11 ` [PATCH v2 2/9] efi_loader: fix efi_dp_find_obj() Heinrich Schuchardt
2022-03-23  7:18   ` AKASHI Takahiro
2022-03-19  9:11 ` [PATCH v2 3/9] efi_loader: efi_dp_find_obj() add protocol check Heinrich Schuchardt
2022-03-23  7:26   ` AKASHI Takahiro
2022-03-19  9:11 ` [PATCH v2 4/9] efi_loader: support booting via short-form device-path Heinrich Schuchardt
2022-03-23  7:50   ` AKASHI Takahiro
2022-03-19  9:11 ` [PATCH v2 5/9] efi_loader: use short-form DP for load options Heinrich Schuchardt
2022-03-23  8:18   ` AKASHI Takahiro
2022-03-19  9:11 ` [PATCH v2 6/9] efi_loader: export efi_system_partition_guid Heinrich Schuchardt
2022-03-19  9:11 ` [PATCH v2 7/9] efi_loader: remove efi_disk_is_system_part() Heinrich Schuchardt
2022-03-19  9:11 ` [PATCH v2 8/9] efi_loader: move dtbdump.c, initrddump.c to lib/efi_loader Heinrich Schuchardt
2022-03-23  7:01   ` AKASHI Takahiro
2022-03-19  9:11 ` [PATCH v2 9/9] test: test UEFI boot manager Heinrich Schuchardt
2022-03-25  7:01 ` [PATCH v2 0/9] efi_loader: booting via short-form device-path AKASHI Takahiro
2022-03-25  9:12   ` AKASHI Takahiro

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.