1
0
mirror of https://xff.cz/git/u-boot/ synced 2025-10-26 16:13:55 +01:00

efi_loader: implement RegisterProtocolNotify()

The RegisterProtocolNotify() boot service registers an event to be
notified upon the installation of a protocol interface with the
specified GUID.

Add the missing implementation.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
This commit is contained in:
Heinrich Schuchardt
2019-05-04 17:27:54 +02:00
parent 3626e53990
commit ab15d4149e
2 changed files with 88 additions and 14 deletions

View File

@@ -271,6 +271,25 @@ extern struct list_head efi_obj_list;
/* List of all events */ /* List of all events */
extern struct list_head efi_events; extern struct list_head efi_events;
/**
* efi_register_notify_event - event registered by RegisterProtocolNotify()
*
* The address of this structure serves as registration value.
*
* @link: link to list of all registered events
* @event: registered event. The same event may registered for
* multiple GUIDs.
* @protocol: protocol for which the event is registered
*/
struct efi_register_notify_event {
struct list_head link;
struct efi_event *event;
efi_guid_t protocol;
};
/* List of all events registered by RegisterProtocolNotify() */
extern struct list_head efi_register_notify_events;
/* Initialize efi execution environment */ /* Initialize efi execution environment */
efi_status_t efi_init_obj_list(void); efi_status_t efi_init_obj_list(void);
/* Called by bootefi to initialize root node */ /* Called by bootefi to initialize root node */

View File

@@ -27,6 +27,9 @@ LIST_HEAD(efi_obj_list);
/* List of all events */ /* List of all events */
LIST_HEAD(efi_events); LIST_HEAD(efi_events);
/* List of all events registered by RegisterProtocolNotify() */
LIST_HEAD(efi_register_notify_events);
/* Handle of the currently executing image */ /* Handle of the currently executing image */
static efi_handle_t current_image; static efi_handle_t current_image;
@@ -908,9 +911,21 @@ static efi_status_t EFIAPI efi_signal_event_ext(struct efi_event *event)
*/ */
static efi_status_t EFIAPI efi_close_event(struct efi_event *event) static efi_status_t EFIAPI efi_close_event(struct efi_event *event)
{ {
struct efi_register_notify_event *item, *next;
EFI_ENTRY("%p", event); EFI_ENTRY("%p", event);
if (efi_is_event(event) != EFI_SUCCESS) if (efi_is_event(event) != EFI_SUCCESS)
return EFI_EXIT(EFI_INVALID_PARAMETER); return EFI_EXIT(EFI_INVALID_PARAMETER);
/* Remove protocol notify registrations for the event */
list_for_each_entry_safe(item, next, &efi_register_notify_events,
link) {
if (event == item->event) {
list_del(&item->link);
free(item);
}
}
list_del(&event->link); list_del(&event->link);
free(event); free(event);
return EFI_EXIT(EFI_SUCCESS); return EFI_EXIT(EFI_SUCCESS);
@@ -1014,6 +1029,7 @@ efi_status_t efi_add_protocol(const efi_handle_t handle,
struct efi_object *efiobj; struct efi_object *efiobj;
struct efi_handler *handler; struct efi_handler *handler;
efi_status_t ret; efi_status_t ret;
struct efi_register_notify_event *event;
efiobj = efi_search_obj(handle); efiobj = efi_search_obj(handle);
if (!efiobj) if (!efiobj)
@@ -1028,6 +1044,13 @@ efi_status_t efi_add_protocol(const efi_handle_t handle,
handler->protocol_interface = protocol_interface; handler->protocol_interface = protocol_interface;
INIT_LIST_HEAD(&handler->open_infos); INIT_LIST_HEAD(&handler->open_infos);
list_add_tail(&handler->link, &efiobj->protocols); list_add_tail(&handler->link, &efiobj->protocols);
/* Notify registered events */
list_for_each_entry(event, &efi_register_notify_events, link) {
if (!guidcmp(protocol, &event->protocol))
efi_signal_event(event->event, true);
}
if (!guidcmp(&efi_guid_device_path, protocol)) if (!guidcmp(&efi_guid_device_path, protocol))
EFI_PRINT("installed device path '%pD'\n", protocol_interface); EFI_PRINT("installed device path '%pD'\n", protocol_interface);
return EFI_SUCCESS; return EFI_SUCCESS;
@@ -1291,8 +1314,30 @@ static efi_status_t EFIAPI efi_register_protocol_notify(
struct efi_event *event, struct efi_event *event,
void **registration) void **registration)
{ {
struct efi_register_notify_event *item;
efi_status_t ret = EFI_SUCCESS;
EFI_ENTRY("%pUl, %p, %p", protocol, event, registration); EFI_ENTRY("%pUl, %p, %p", protocol, event, registration);
return EFI_EXIT(EFI_OUT_OF_RESOURCES);
if (!protocol || !event || !registration) {
ret = EFI_INVALID_PARAMETER;
goto out;
}
item = calloc(1, sizeof(struct efi_register_notify_event));
if (!item) {
ret = EFI_OUT_OF_RESOURCES;
goto out;
}
item->event = event;
memcpy(&item->protocol, protocol, sizeof(efi_guid_t));
list_add_tail(&item->link, &efi_register_notify_events);
*registration = item;
out:
return EFI_EXIT(ret);
} }
/** /**
@@ -1307,8 +1352,7 @@ static efi_status_t EFIAPI efi_register_protocol_notify(
* Return: 0 if the handle implements the protocol * Return: 0 if the handle implements the protocol
*/ */
static int efi_search(enum efi_locate_search_type search_type, static int efi_search(enum efi_locate_search_type search_type,
const efi_guid_t *protocol, void *search_key, const efi_guid_t *protocol, efi_handle_t handle)
efi_handle_t handle)
{ {
efi_status_t ret; efi_status_t ret;
@@ -1316,8 +1360,6 @@ static int efi_search(enum efi_locate_search_type search_type,
case ALL_HANDLES: case ALL_HANDLES:
return 0; return 0;
case BY_REGISTER_NOTIFY: case BY_REGISTER_NOTIFY:
/* TODO: RegisterProtocolNotify is not implemented yet */
return -1;
case BY_PROTOCOL: case BY_PROTOCOL:
ret = efi_search_protocol(handle, protocol, NULL); ret = efi_search_protocol(handle, protocol, NULL);
return (ret != EFI_SUCCESS); return (ret != EFI_SUCCESS);
@@ -1329,11 +1371,12 @@ static int efi_search(enum efi_locate_search_type search_type,
/** /**
* efi_locate_handle() - locate handles implementing a protocol * efi_locate_handle() - locate handles implementing a protocol
* @search_type: selection criterion *
* @protocol: GUID of the protocol * @search_type: selection criterion
* @search_key: registration key * @protocol: GUID of the protocol
* @buffer_size: size of the buffer to receive the handles in bytes * @search_key: registration key
* @buffer: buffer to receive the relevant handles * @buffer_size: size of the buffer to receive the handles in bytes
* @buffer: buffer to receive the relevant handles
* *
* This function is meant for U-Boot internal calls. For the API implementation * This function is meant for U-Boot internal calls. For the API implementation
* of the LocateHandle service see efi_locate_handle_ext. * of the LocateHandle service see efi_locate_handle_ext.
@@ -1347,6 +1390,7 @@ static efi_status_t efi_locate_handle(
{ {
struct efi_object *efiobj; struct efi_object *efiobj;
efi_uintn_t size = 0; efi_uintn_t size = 0;
struct efi_register_notify_event *item, *event = NULL;
/* Check parameters */ /* Check parameters */
switch (search_type) { switch (search_type) {
@@ -1355,8 +1399,19 @@ static efi_status_t efi_locate_handle(
case BY_REGISTER_NOTIFY: case BY_REGISTER_NOTIFY:
if (!search_key) if (!search_key)
return EFI_INVALID_PARAMETER; return EFI_INVALID_PARAMETER;
/* RegisterProtocolNotify is not implemented yet */ /* Check that the registration key is valid */
return EFI_UNSUPPORTED; list_for_each_entry(item, &efi_register_notify_events, link) {
if (item ==
(struct efi_register_notify_event *)search_key) {
event = item;
break;
}
}
if (!event)
return EFI_INVALID_PARAMETER;
protocol = &event->protocol;
break;
case BY_PROTOCOL: case BY_PROTOCOL:
if (!protocol) if (!protocol)
return EFI_INVALID_PARAMETER; return EFI_INVALID_PARAMETER;
@@ -1367,7 +1422,7 @@ static efi_status_t efi_locate_handle(
/* Count how much space we need */ /* Count how much space we need */
list_for_each_entry(efiobj, &efi_obj_list, link) { list_for_each_entry(efiobj, &efi_obj_list, link) {
if (!efi_search(search_type, protocol, search_key, efiobj)) if (!efi_search(search_type, protocol, efiobj))
size += sizeof(void *); size += sizeof(void *);
} }
@@ -1390,7 +1445,7 @@ static efi_status_t efi_locate_handle(
/* Then fill the array */ /* Then fill the array */
list_for_each_entry(efiobj, &efi_obj_list, link) { list_for_each_entry(efiobj, &efi_obj_list, link) {
if (!efi_search(search_type, protocol, search_key, efiobj)) if (!efi_search(search_type, protocol, efiobj))
*buffer++ = efiobj; *buffer++ = efiobj;
} }