mirror of
https://github.com/u-boot/u-boot.git
synced 2025-05-08 10:39:08 +00:00
efi_loader: fix efi_dp_find_obj()
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>
This commit is contained in:
parent
8399488672
commit
c409593d08
2 changed files with 63 additions and 51 deletions
|
@ -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;
|
||||
|
||||
list_for_each_entry(efiobj, &efi_obj_list, link) {
|
||||
len = efi_dp_instance_size(dp);
|
||||
|
||||
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;
|
||||
efi_handle_t handle;
|
||||
|
||||
/* Search for an exact match first */
|
||||
efiobj = find_obj(dp, false, NULL);
|
||||
handle = find_handle(dp, false, rem);
|
||||
if (!handle)
|
||||
/* Match short form device path */
|
||||
handle = find_handle(dp, true, rem);
|
||||
|
||||
/* Then for a fuzzy match */
|
||||
if (!efiobj)
|
||||
efiobj = find_obj(dp, false, rem);
|
||||
|
||||
/* And now for a fuzzy short match */
|
||||
if (!efiobj)
|
||||
efiobj = find_obj(dp, true, rem);
|
||||
|
||||
return efiobj;
|
||||
return handle;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue