[U-Boot] [PATCH 12/13] efi_loader: manage protocols in a linked list

Alexander Graf agraf at suse.de
Wed Nov 8 15:43:50 UTC 2017


On 11/01/2017 09:31 AM, Heinrich Schuchardt wrote:
> Signed-off-by: Heinrich Schuchardt <xypron.glpk at gmx.de>
> ---
>   include/efi_loader.h          |   6 ++-
>   lib/efi_loader/efi_boottime.c | 107 ++++++++++++++++++++----------------------
>   lib/efi_loader/efi_disk.c     |   1 +
>   lib/efi_loader/efi_gop.c      |   1 +
>   lib/efi_loader/efi_net.c      |   1 +
>   5 files changed, 58 insertions(+), 58 deletions(-)
>
> diff --git a/include/efi_loader.h b/include/efi_loader.h
> index e1f0af3496..a73bbc1269 100644
> --- a/include/efi_loader.h
> +++ b/include/efi_loader.h
> @@ -101,6 +101,8 @@ extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop;
>    * interface (usually a struct with callback functions), this struct maps the
>    * protocol GUID to the respective protocol interface */
>   struct efi_handler {
> +	/* Link to the list of protocols of a handle */
> +	struct list_head link;
>   	const efi_guid_t *guid;
>   	void *protocol_interface;
>   };
> @@ -115,8 +117,8 @@ struct efi_handler {
>   struct efi_object {
>   	/* Every UEFI object is part of a global object list */
>   	struct list_head link;
> -	/* We support up to 16 "protocols" an object can be accessed through */
> -	struct efi_handler protocols[16];
> +	/* The list of protocols */
> +	struct list_head protocols;
>   	/* The object spawner can either use this for data or as identifier */
>   	void *handle;
>   };
> diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
> index 2b3db162a1..cee0cb1390 100644
> --- a/lib/efi_loader/efi_boottime.c
> +++ b/lib/efi_loader/efi_boottime.c
> @@ -339,6 +339,7 @@ efi_status_t efi_create_handle(void **handle)
>   		return r;
>   	memset(obj, 0, sizeof(struct efi_object));
>   	obj->handle = obj;
> +	INIT_LIST_HEAD(&obj->protocols);
>   	list_add_tail(&obj->link, &efi_obj_list);
>   	*handle = obj;
>   	return r;
> @@ -715,18 +716,17 @@ efi_status_t efi_search_protocol(const void *handle,
>   				 struct efi_handler **handler)
>   {
>   	struct efi_object *efiobj;
> -	size_t i;
> -	struct efi_handler *protocol;
> +	struct list_head *lhandle;
>   
>   	if (!handle || !protocol_guid)
>   		return EFI_INVALID_PARAMETER;
>   	efiobj = efi_search_obj(handle);
>   	if (!efiobj)
>   		return EFI_INVALID_PARAMETER;
> -	for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) {
> -		protocol = &efiobj->protocols[i];
> -		if (!protocol->guid)
> -			continue;
> +	list_for_each(lhandle, &efiobj->protocols) {
> +		struct efi_handler *protocol;
> +
> +		protocol = list_entry(lhandle, struct efi_handler, link);
>   		if (!guidcmp(protocol->guid, protocol_guid)) {
>   			if (handler)
>   				*handler = protocol;
> @@ -750,7 +750,6 @@ efi_status_t efi_add_protocol(const void *handle, const efi_guid_t *protocol,
>   	struct efi_object *efiobj;
>   	struct efi_handler *handler;
>   	efi_status_t ret;
> -	size_t i;
>   
>   	efiobj = efi_search_obj(handle);
>   	if (!efiobj)
> @@ -761,16 +760,10 @@ efi_status_t efi_add_protocol(const void *handle, const efi_guid_t *protocol,
>   	handler = calloc(1, sizeof(struct efi_handler));
>   	if (!handler)
>   		return EFI_OUT_OF_RESOURCES;
> -	/* Install protocol in first empty slot. */
> -	for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) {
> -		handler = &efiobj->protocols[i];
> -		if (handler->guid)
> -			continue;
> -		handler->guid = protocol;
> -		handler->protocol_interface = protocol_interface;
> -		return EFI_SUCCESS;
> -	}
> -	return EFI_OUT_OF_RESOURCES;
> +	handler->guid = protocol;
> +	handler->protocol_interface = protocol_interface;
> +	list_add_tail(&handler->link, &efiobj->protocols);
> +	return EFI_SUCCESS;
>   }
>   
>   /*
> @@ -790,10 +783,10 @@ efi_status_t efi_remove_protocol(const void *handle, const efi_guid_t *protocol,
>   	ret = efi_search_protocol(handle, protocol, &handler);
>   	if (ret != EFI_SUCCESS)
>   		return ret;
> -	if (handler->protocol_interface != protocol_interface)
> -		return EFI_NOT_FOUND;
> -	handler->guid = NULL;
> -	handler->protocol_interface = NULL;
> +	if (guidcmp(handler->guid, protocol))
> +		return EFI_INVALID_PARAMETER;
> +	list_del(&handler->link);
> +	free(handler);
>   	return EFI_SUCCESS;
>   }
>   
> @@ -806,17 +799,22 @@ efi_status_t efi_remove_protocol(const void *handle, const efi_guid_t *protocol,
>   efi_status_t efi_remove_all_protocols(const void *handle)
>   {
>   	struct efi_object *efiobj;
> -	struct efi_handler *handler;
> -	size_t i;
> +	struct list_head *lhandle;
> +	struct list_head *pos;
>   
>   	efiobj = efi_search_obj(handle);
>   	if (!efiobj)
>   		return EFI_INVALID_PARAMETER;
> +	list_for_each_safe(lhandle, pos, &efiobj->protocols) {
> +		struct efi_handler *protocol;
> +		efi_status_t ret;
>   
> -	for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) {
> -		handler = &efiobj->protocols[i];
> -		handler->guid = NULL;
> -		handler->protocol_interface = NULL;
> +		protocol = list_entry(lhandle, struct efi_handler, link);
> +
> +		ret = efi_remove_protocol(handle, protocol->guid,
> +					  protocol->protocol_interface);
> +		if (ret != EFI_SUCCESS)
> +			return ret;
>   	}
>   	return EFI_SUCCESS;
>   }
> @@ -1171,6 +1169,7 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *ob
>   	if (device_path)
>   		info->device_handle = efi_dp_find_obj(device_path, NULL);
>   
> +	INIT_LIST_HEAD(&obj->protocols);
>   	list_add_tail(&obj->link, &efi_obj_list);
>   	/*
>   	 * When asking for the device path interface, return
> @@ -1648,8 +1647,7 @@ static efi_status_t EFIAPI efi_protocols_per_handle(void *handle,
>   {
>   	unsigned long buffer_size;
>   	struct efi_object *efiobj;
> -	unsigned long i, j;
> -	struct list_head *lhandle;
> +	struct list_head *protocol_handle;
>   	efi_status_t r;
>   
>   	EFI_ENTRY("%p, %p, %p", handle, protocol_buffer,
> @@ -1660,36 +1658,33 @@ static efi_status_t EFIAPI efi_protocols_per_handle(void *handle,
>   
>   	*protocol_buffer = NULL;
>   	*protocol_buffer_count = 0;
> -	list_for_each(lhandle, &efi_obj_list) {
> -		efiobj = list_entry(lhandle, struct efi_object, link);
>   
> -		if (efiobj->handle != handle)
> -			continue;
> +	efiobj = efi_search_obj(handle);
> +	if (!efiobj)
> +		return EFI_EXIT(EFI_INVALID_PARAMETER);
>   
> -		/* Count protocols */
> -		for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) {
> -			if (efiobj->protocols[i].guid)
> -				++*protocol_buffer_count;
> -		}
> -		/* Copy guids */
> -		if (*protocol_buffer_count) {
> -			buffer_size = sizeof(efi_guid_t *) *
> -					*protocol_buffer_count;
> -			r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES,
> -					      buffer_size,
> -					      (void **)protocol_buffer);
> -			if (r != EFI_SUCCESS)
> -				return EFI_EXIT(r);
> -			j = 0;
> -			for (i = 0; i < ARRAY_SIZE(efiobj->protocols); ++i) {
> -				if (efiobj->protocols[i].guid) {
> -					(*protocol_buffer)[j] = (void *)
> -						efiobj->protocols[i].guid;
> -					++j;
> -				}
> -			}
> +	/* Count protocols */
> +	list_for_each(protocol_handle, &efiobj->protocols) {
> +		++*protocol_buffer_count;
> +	}
> +
> +	/* Copy guids */
> +	if (*protocol_buffer_count) {
> +		size_t j = 0;
> +
> +		buffer_size = sizeof(efi_guid_t *) * *protocol_buffer_count;
> +		r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, buffer_size,
> +				      (void **)protocol_buffer);
> +		if (r != EFI_SUCCESS)
> +			return EFI_EXIT(r);
> +		list_for_each(protocol_handle, &efiobj->protocols) {
> +			struct efi_handler *protocol;
> +
> +			protocol = list_entry(protocol_handle,
> +					      struct efi_handler, link);
> +			(*protocol_buffer)[j] = (void *)protocol->guid;
> +			++j;
>   		}
> -		break;
>   	}
>   
>   	return EFI_EXIT(EFI_SUCCESS);
> diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c
> index 1d6cf3122f..af8db40e19 100644
> --- a/lib/efi_loader/efi_disk.c
> +++ b/lib/efi_loader/efi_disk.c
> @@ -224,6 +224,7 @@ static void efi_disk_add_dev(const char *name,
>   		goto out_of_memory;
>   
>   	/* Hook up to the device list */
> +	INIT_LIST_HEAD(&diskobj->parent.protocols);
>   	list_add_tail(&diskobj->parent.link, &efi_obj_list);

This seems to have become quite a common theme now. Maybe it's about 
time we add a helper function to manually add a precreated object to the 
object list (and clear the protocol list along the way)?


Alex



More information about the U-Boot mailing list