cmd/eficonfig.c | 2 +-
include/efi_device_path.h | 10 +++---
lib/efi_loader/efi_bootmgr.c | 6 ++--
lib/efi_loader/efi_boottime.c | 5 +--
lib/efi_loader/efi_capsule.c | 20 +++++++-----
lib/efi_loader/efi_device_path.c | 55 +++++++++++++++++++++++++-------
lib/efi_loader/efi_disk.c | 2 +-
7 files changed, 70 insertions(+), 30 deletions(-)
diff --git a/cmd/eficonfig.c b/cmd/eficonfig.c
index d8d946c87ac8..e317f3c90c14 100644
--- a/cmd/eficonfig.c
+++ b/cmd/eficonfig.c
@@ -1321,7 +1321,7 @@ static efi_status_t prepare_file_selection_entry(struct
efimenu *efi_menu, char
return EFI_OUT_OF_RESOURCES;
/* get the device name only when the user already selected the file
path */
- handle = efi_dp_find_obj(file_info->dp_volume, NULL, NULL);
+ handle = efi_dp_find_obj(file_info->dp_volume, NULL, NULL, false);
if (handle) {
ret = efi_disk_get_device_name(handle, devname,
EFICONFIG_VOLUME_PATH_MAX);
if (ret != EFI_SUCCESS)
diff --git a/include/efi_device_path.h b/include/efi_device_path.h
index aae85228f681..f9c538730c94 100644
--- a/include/efi_device_path.h
+++ b/include/efi_device_path.h
@@ -73,13 +73,15 @@ struct efi_device_path *efi_dp_shorten(struct
efi_device_path *dp);
*
* 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
+ * @dp: device path to search
+ * @guid: GUID of protocol that must be installed on path or NULL
+ * @rem: pointer to receive remaining device path
+ * @inversed_match: Match even if the dp is shorter. rem will stil hoild the
+ * 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);
+ struct efi_device_path **rem, bool inversed_match);
/**
* efi_dp_last_node() - Determine the last device path node before the end
node
diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c
index a687f4d8e85c..df7500a94876 100644
--- a/lib/efi_loader/efi_bootmgr.c
+++ b/lib/efi_loader/efi_bootmgr.c
@@ -84,7 +84,8 @@ struct efi_device_path *expand_media_path(struct
efi_device_path *device_path)
* booting from removable media.
*/
handle = efi_dp_find_obj(device_path,
- &efi_simple_file_system_protocol_guid, &rem);
+ &efi_simple_file_system_protocol_guid, &rem,
+ false);
if (handle) {
if (rem->type == DEVICE_PATH_TYPE_END) {
char fname[30];
@@ -625,7 +626,8 @@ static efi_status_t try_load_from_media(struct
efi_device_path *file_path,
struct efi_device_path *rem, *dp = NULL;
struct efi_device_path *final_dp = file_path;
- handle_blkdev = efi_dp_find_obj(file_path, &efi_block_io_guid, &rem);
+ handle_blkdev = efi_dp_find_obj(file_path, &efi_block_io_guid, &rem,
+ false);
if (handle_blkdev) {
if (rem->type == DEVICE_PATH_TYPE_END) {
/* no file name present, try default file */
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index ddc935d22409..0391b92a8be4 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -1816,7 +1816,8 @@ 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, NULL);
+ info->device_handle = efi_dp_find_obj(device_path, NULL, NULL,
+ false);
dp = efi_dp_concat(device_path, file_path, 0);
if (!dp) {
@@ -2016,7 +2017,7 @@ efi_status_t efi_load_image_from_path(bool boot_policy,
*size = 0;
dp = file_path;
- device = efi_dp_find_obj(dp, NULL, &rem);
+ device = efi_dp_find_obj(dp, NULL, &rem, false);
ret = efi_search_protocol(device, &efi_simple_file_system_protocol_guid,
NULL);
if (ret == EFI_SUCCESS)
diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c
index eafc647f558f..103328c76a6e 100644
--- a/lib/efi_loader/efi_capsule.c
+++ b/lib/efi_loader/efi_capsule.c
@@ -886,18 +886,18 @@ static efi_status_t get_dp_device(u16 *boot_var,
* @dp device path
* Return: true - yes, false - no
*/
-static bool device_is_present_and_system_part(struct efi_device_path *dp)
+static bool device_is_present_and_system_part(struct efi_device_path *dp,
+ struct efi_device_path **rem)
{
efi_handle_t handle;
- struct efi_device_path *rem;
/* Check device exists */
- handle = efi_dp_find_obj(dp, NULL, NULL);
+ handle = efi_dp_find_obj(dp, NULL, NULL, false);
if (!handle)
return false;
/* Check device is on system partition */
- handle = efi_dp_find_obj(dp, &efi_system_partition_guid, &rem);
+ handle = efi_dp_find_obj(dp, &efi_system_partition_guid, rem, true);
if (!handle)
return false;
@@ -919,7 +919,7 @@ static efi_status_t find_boot_device(void)
efi_uintn_t size;
int i, num;
struct efi_simple_file_system_protocol *volume;
- struct efi_device_path *boot_dev = NULL;
+ struct efi_device_path *boot_dev = NULL, *rem = NULL;
efi_status_t ret;
/* find active boot device in BootNext */
@@ -940,7 +940,7 @@ static efi_status_t find_boot_device(void)
ret = get_dp_device(boot_var16, &boot_dev);
if (ret == EFI_SUCCESS) {
- if (device_is_present_and_system_part(boot_dev)) {
+ if (device_is_present_and_system_part(boot_dev, &rem)) {
goto found;
} else {
efi_free_pool(boot_dev);
@@ -967,7 +967,7 @@ skip:
if (ret != EFI_SUCCESS)
continue;
- if (device_is_present_and_system_part(boot_dev))
+ if (device_is_present_and_system_part(boot_dev, &rem))
break;
efi_free_pool(boot_dev);
@@ -977,7 +977,11 @@ found:
if (boot_dev) {
log_debug("Boot device %pD\n", boot_dev);
- volume = efi_fs_from_path(boot_dev);
+ if (rem->type == DEVICE_PATH_TYPE_END)
+ volume = efi_fs_from_path(boot_dev);
+ else
+ volume = efi_fs_from_path(rem);
+
if (!volume)
ret = EFI_DEVICE_ERROR;
else
diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
index b3fb20b2501e..ad7f452c411b 100644
--- a/lib/efi_loader/efi_device_path.c
+++ b/lib/efi_loader/efi_device_path.c
@@ -30,6 +30,12 @@ const struct efi_device_path EFI_DP_END = {
.length = sizeof(EFI_DP_END),
};
+enum match {
+ EXACT,
+ SHORTER,
+ LONGER
+};
+
#if defined(CONFIG_MMC)
/*
* Determine if an MMC device is an SD card.
@@ -109,10 +115,11 @@ struct efi_device_path *efi_dp_shorten(struct
efi_device_path *dp)
*/
static efi_handle_t find_handle(struct efi_device_path *dp,
const efi_guid_t *guid, bool short_path,
- struct efi_device_path **rem)
+ struct efi_device_path **rem,
+ enum match match)
{
efi_handle_t handle, best_handle = NULL;
- efi_uintn_t len, best_len = 0;
+ efi_uintn_t len, match_len = 0, best_len = 0;
len = efi_dp_instance_size(dp);
@@ -137,22 +144,35 @@ static efi_handle_t find_handle(struct efi_device_path
*dp,
if (!dp_current)
continue;
}
- len_current = efi_dp_instance_size(dp_current);
- if (rem) {
+
+ match_len = len_current = efi_dp_instance_size(dp_current);
+ switch (match) {
+ case EXACT:
+ if (len_current != len)
+ continue;
+ break;
+ case SHORTER:
if (len_current > len)
continue;
- } else {
- if (len_current != len)
+ break;
+ case LONGER:
+ if (len_current < len)
continue;
+ match_len = len;
+ break;
}
- if (memcmp(dp_current, dp, len_current))
+
+ if (memcmp(dp_current, dp, match_len))
continue;
if (!rem)
return handle;
if (len_current > best_len) {
best_len = len_current;
best_handle = handle;
- *rem = (void*)((u8 *)dp + len_current);
+ if (len_current <= len)
+ *rem = (void *)((uintptr_t)dp + len_current);
+ else
+ *rem = (void *)((uintptr_t)dp_current +
match_len);
}
}
return best_handle;
@@ -160,14 +180,25 @@ static efi_handle_t find_handle(struct efi_device_path
*dp,
efi_handle_t efi_dp_find_obj(struct efi_device_path *dp,
const efi_guid_t *guid,
- struct efi_device_path **rem)
+ struct efi_device_path **rem, bool inversed_match)
{
efi_handle_t handle;
- handle = find_handle(dp, guid, false, rem);
+ handle = find_handle(dp, guid, false, rem, EXACT);
if (!handle)
- /* Match short form device path */
- handle = find_handle(dp, guid, true, rem);
+ handle = find_handle(dp, guid, true, rem, EXACT);
+ if (handle)
+ return handle;
+
+ handle = find_handle(dp, guid, false, rem, SHORTER);
+ if (!handle)
+ handle = find_handle(dp, guid, true, rem, SHORTER);
+
+ if (inversed_match && !handle) {
+ handle = find_handle(dp, guid, false, rem, LONGER);
+ if (!handle)
+ handle = find_handle(dp, guid, true, rem, LONGER);
+ }
return handle;
}
diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c
index 130c4db9606f..0d3d7c187d72 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, NULL, NULL, false);
efi_free_pool(device_path);
if (!efiobj)
return NULL;
--
2.51.0