mirror of
https://github.com/u-boot/u-boot.git
synced 2025-05-08 19:11:53 +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
|
@ -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);
|
struct efi_device_path *efi_dp_next(const struct efi_device_path *dp);
|
||||||
int efi_dp_match(const struct efi_device_path *a,
|
int efi_dp_match(const struct efi_device_path *a,
|
||||||
const struct efi_device_path *b);
|
const struct efi_device_path *b);
|
||||||
struct efi_object *efi_dp_find_obj(struct efi_device_path *dp,
|
efi_handle_t efi_dp_find_obj(struct efi_device_path *dp,
|
||||||
struct efi_device_path **rem);
|
struct efi_device_path **rem);
|
||||||
/* get size of the first device path instance excluding end node */
|
/* get size of the first device path instance excluding end node */
|
||||||
efi_uintn_t efi_dp_instance_size(const struct efi_device_path *dp);
|
efi_uintn_t efi_dp_instance_size(const struct efi_device_path *dp);
|
||||||
/* size of multi-instance device path excluding end node */
|
/* size of multi-instance device path excluding end node */
|
||||||
|
|
|
@ -159,69 +159,81 @@ struct efi_device_path *efi_dp_shorten(struct efi_device_path *dp)
|
||||||
return 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_handle_t handle, best_handle = NULL;
|
||||||
efi_uintn_t dp_size = efi_dp_instance_size(dp);
|
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_handler *handler;
|
||||||
struct efi_device_path *obj_dp;
|
struct efi_device_path *dp_current;
|
||||||
|
efi_uintn_t len_current;
|
||||||
efi_status_t ret;
|
efi_status_t ret;
|
||||||
|
|
||||||
ret = efi_search_protocol(efiobj,
|
ret = efi_search_protocol(handle, &efi_guid_device_path,
|
||||||
&efi_guid_device_path, &handler);
|
&handler);
|
||||||
if (ret != EFI_SUCCESS)
|
if (ret != EFI_SUCCESS)
|
||||||
continue;
|
continue;
|
||||||
obj_dp = handler->protocol_interface;
|
dp_current = handler->protocol_interface;
|
||||||
|
if (short_path) {
|
||||||
do {
|
dp_current = efi_dp_shorten(dp_current);
|
||||||
if (efi_dp_match(dp, obj_dp) == 0) {
|
if (!dp_current)
|
||||||
if (rem) {
|
continue;
|
||||||
/*
|
}
|
||||||
* Allow partial matches, but inform
|
len_current = efi_dp_instance_size(dp_current);
|
||||||
* the caller.
|
if (rem) {
|
||||||
*/
|
if (len_current < len)
|
||||||
*rem = ((void *)dp) +
|
continue;
|
||||||
efi_dp_instance_size(obj_dp);
|
} else {
|
||||||
return efiobj;
|
if (len_current != len)
|
||||||
} else {
|
continue;
|
||||||
/* Only return on exact matches */
|
}
|
||||||
if (efi_dp_instance_size(obj_dp) ==
|
if (memcmp(dp_current, dp, len))
|
||||||
dp_size)
|
continue;
|
||||||
return efiobj;
|
if (!rem)
|
||||||
}
|
return handle;
|
||||||
}
|
if (len_current > best_len) {
|
||||||
|
best_len = len_current;
|
||||||
obj_dp = efi_dp_shorten(efi_dp_next(obj_dp));
|
best_handle = handle;
|
||||||
} while (short_path && obj_dp);
|
*rem = (void*)((u8 *)dp + len_current);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return best_handle;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Find an efiobj from device-path, if 'rem' is not NULL, returns the
|
* efi_dp_find_obj() - find handle by device path
|
||||||
* remaining part of the device path after the matched object.
|
*
|
||||||
|
* 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,
|
efi_handle_t efi_dp_find_obj(struct efi_device_path *dp,
|
||||||
struct efi_device_path **rem)
|
struct efi_device_path **rem)
|
||||||
{
|
{
|
||||||
struct efi_object *efiobj;
|
efi_handle_t handle;
|
||||||
|
|
||||||
/* Search for an exact match first */
|
handle = find_handle(dp, false, rem);
|
||||||
efiobj = find_obj(dp, false, NULL);
|
if (!handle)
|
||||||
|
/* Match short form device path */
|
||||||
|
handle = find_handle(dp, true, rem);
|
||||||
|
|
||||||
/* Then for a fuzzy match */
|
return handle;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue