[PATCH v1 1/2] efi_loader: improve device path matching for partition lookup

Balaji Selvanathan balaji.selvanathan at oss.qualcomm.com
Thu Jul 24 11:00:08 CEST 2025


- Refactor find_handle() to improve device path comparison logic.
- Original logic only compared paths when len_current <= len.
- This fails when searching for ESP inside a larger boot device.
- ESP partition path is longer than boot device path by design.
- New logic allows matching when dp is a prefix of dp_current.
- Without this change, it was not able to find ESP and capsule
  update fails to start.

- Also update efi_fs_from_path() to use system partition GUID.
- Above ensures ESP's EFI handle is returned which contains
  file system protocol.
- Without this change, it was returning a wrong EFI handle
  that was not ESP handle.

- These changes improves reliability for capsule updates.

Signed-off-by: Balaji Selvanathan <balaji.selvanathan at oss.qualcomm.com>
---
 lib/efi_loader/efi_device_path.c | 62 ++++++++++++++++++++++----------
 lib/efi_loader/efi_disk.c        |  2 +-
 2 files changed, 45 insertions(+), 19 deletions(-)

diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
index b3fb20b2501..3716165e963 100644
--- a/lib/efi_loader/efi_device_path.c
+++ b/lib/efi_loader/efi_device_path.c
@@ -107,54 +107,80 @@ struct efi_device_path *efi_dp_shorten(struct efi_device_path *dp)
  * @rem:	pointer to receive remaining device path
  * Return:	matching handle
  */
+
 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;
+	efi_uintn_t len, len_current, best_len = 0;
+	efi_status_t ret;
+	struct efi_device_path *dp_current;
+	struct efi_handler *handler;
 
 	len = efi_dp_instance_size(dp);
 
 	list_for_each_entry(handle, &efi_obj_list, link) {
-		struct efi_handler *handler;
-		struct efi_device_path *dp_current;
-		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);
+
+		ret = efi_search_protocol(handle, &efi_guid_device_path, &handler);
 		if (ret != EFI_SUCCESS)
 			continue;
+
 		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)
+			/* If current path is shorter than or equal to input path */
+			if (len_current <= len) {
+				if (memcmp(dp_current, dp, len_current))
+					continue;
+				if (!rem)
+					return handle;
+				if (len_current > best_len) {
+					best_len = len_current;
+					best_handle = handle;
+					*rem = (void *)((u8 *)dp + len_current);
+				}
+			}
+			/* If current path is greater than input path */
+			else if (len_current > len) {
+				if (memcmp(dp, dp_current, len))
+					continue;
+				if (len > best_len) {
+					best_len = len;
+					best_handle = handle;
+					*rem = (struct efi_device_path *)((u8 *)dp_current + len);
+				}
+			} else {
 				continue;
+			}
 		} else {
-			if (len_current != len)
+			if (len_current == len) {
+				if (memcmp(dp_current, dp, len_current))
+					continue;
+			}
+			/* If current path is greater than input path */
+			else if (len_current > len) {
+				if (memcmp(dp, dp_current, len))
+					continue;
+			} else {
 				continue;
-		}
-		if (memcmp(dp_current, dp, len_current))
-			continue;
-		if (!rem)
+			}
 			return handle;
-		if (len_current > best_len) {
-			best_len = len_current;
-			best_handle = handle;
-			*rem = (void*)((u8 *)dp + len_current);
 		}
 	}
+
 	return best_handle;
 }
 
diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c
index 130c4db9606..49f8b5935f4 100644
--- a/lib/efi_loader/efi_disk.c
+++ b/lib/efi_loader/efi_disk.c
@@ -339,7 +339,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, NULL);
+	efiobj = efi_dp_find_obj(device_path, &efi_system_partition_guid, NULL);
 	efi_free_pool(device_path);
 	if (!efiobj)
 		return NULL;
-- 
2.34.1



More information about the U-Boot mailing list