aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorHeinrich Schuchardt2019-05-29 18:06:46 +0200
committerHeinrich Schuchardt2019-05-31 23:27:12 +0200
commite31b3b16226c6f6847238e1f7006724abf1220df (patch)
treea2a340097c4c4e4e2a4a4267b018d31e3f9ebf35 /lib
parentb8abd743ff1669e07e4e022e5793720d875d8e13 (diff)
efi_loader: registration key in LocateProtocol()
In LocateProtocol() implement searching by the registration key returned by RegisterNotifyProtocol(). Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Diffstat (limited to 'lib')
-rw-r--r--lib/efi_loader/efi_boottime.c49
1 files changed, 39 insertions, 10 deletions
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index dd5f706af76..df57b3a984a 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -2259,29 +2259,58 @@ static efi_status_t EFIAPI efi_locate_protocol(const efi_guid_t *protocol,
void *registration,
void **protocol_interface)
{
- struct list_head *lhandle;
+ struct efi_handler *handler;
efi_status_t ret;
+ struct efi_object *efiobj;
EFI_ENTRY("%pUl, %p, %p", protocol, registration, protocol_interface);
+ /*
+ * The UEFI spec explicitly requires a protocol even if a registration
+ * key is provided. This differs from the logic in LocateHandle().
+ */
if (!protocol || !protocol_interface)
return EFI_EXIT(EFI_INVALID_PARAMETER);
- list_for_each(lhandle, &efi_obj_list) {
- struct efi_object *efiobj;
- struct efi_handler *handler;
-
- efiobj = list_entry(lhandle, struct efi_object, link);
+ if (registration) {
+ struct efi_register_notify_event *event;
+ struct efi_protocol_notification *handle;
+ event = efi_check_register_notify_event(registration);
+ if (!event)
+ return EFI_EXIT(EFI_INVALID_PARAMETER);
+ /*
+ * The UEFI spec requires to return EFI_NOT_FOUND if no
+ * protocol instance matches protocol and registration.
+ * So let's do the same for a mismatch between protocol and
+ * registration.
+ */
+ if (guidcmp(&event->protocol, protocol))
+ goto not_found;
+ if (list_empty(&event->handles))
+ goto not_found;
+ handle = list_first_entry(&event->handles,
+ struct efi_protocol_notification,
+ link);
+ efiobj = handle->handle;
+ list_del(&handle->link);
+ free(handle);
ret = efi_search_protocol(efiobj, protocol, &handler);
- if (ret == EFI_SUCCESS) {
- *protocol_interface = handler->protocol_interface;
- return EFI_EXIT(EFI_SUCCESS);
+ if (ret == EFI_SUCCESS)
+ goto found;
+ } else {
+ list_for_each_entry(efiobj, &efi_obj_list, link) {
+ ret = efi_search_protocol(efiobj, protocol, &handler);
+ if (ret == EFI_SUCCESS)
+ goto found;
}
}
+not_found:
*protocol_interface = NULL;
-
return EFI_EXIT(EFI_NOT_FOUND);
+found:
+ *protocol_interface = handler->protocol_interface;
+ return EFI_EXIT(EFI_SUCCESS);
}
/**