[PATCH v2] efi_loader: make efi_delete_handle() follow the EFI spec

Heinrich Schuchardt xypron.glpk at gmx.de
Fri Jul 28 09:06:16 CEST 2023


On 7/24/23 12:17, Ilias Apalodimas wrote:
> The EFI doesn't allow removal of handles, unless all hosted protocols
> are cleanly removed.  Our efi_delete_handle() is a bit intrusive.
> Although it does try to delete protocols before removing a handle,
> it doesn't care if that fails.  Instead it only returns an error if the
> handle is invalid. On top of that none of the callers of that function
> check the return code.
>
> So let's rewrite this in a way that fits the EFI spec better.  Instead
> of forcing the handle removal, gracefully uninstall all the handle
> protocols.  According to the EFI spec when the last protocol is removed
> the handle will be deleted.  Also switch all the callers and check the
> return code. Some callers can't do anything useful apart from reporting
> an error.  The disk related functions on the other hand, can prevent a
> medium that is being used by EFI from removal.
>
> The only function that doesn't check the result is efi_delete_image().
> But that function needs a bigger rework anyway, so we can clean it up in
> the future
>
> Signed-off-by: Ilias Apalodimas <ilias.apalodimas at linaro.org>
> ---
> Changes since v1:
> - only report errors internally in efi_delete_handle()
>
>   cmd/bootefi.c                 | 21 ++++++---------------
>   include/efi_loader.h          |  2 +-
>   lib/efi_driver/efi_uclass.c   | 12 +++++-------
>   lib/efi_loader/efi_boottime.c | 20 ++++++++++++++------
>   lib/efi_loader/efi_disk.c     |  6 +++++-
>   5 files changed, 31 insertions(+), 30 deletions(-)
>
> diff --git a/cmd/bootefi.c b/cmd/bootefi.c
> index 5c0afec1544d..f73d6eb0e2d8 100644
> --- a/cmd/bootefi.c
> +++ b/cmd/bootefi.c
> @@ -606,20 +606,6 @@ failure:
>   	return ret;
>   }
>
> -/**
> - * bootefi_run_finish() - finish up after running an EFI test
> - *
> - * @loaded_image_info: Pointer to a struct which holds the loaded image info
> - * @image_obj: Pointer to a struct which holds the loaded image object
> - */
> -static void bootefi_run_finish(struct efi_loaded_image_obj *image_obj,
> -			       struct efi_loaded_image *loaded_image_info)
> -{
> -	efi_restore_gd();
> -	free(loaded_image_info->load_options);
> -	efi_delete_handle(&image_obj->header);
> -}
> -
>   /**
>    * do_efi_selftest() - execute EFI selftest
>    *
> @@ -638,7 +624,12 @@ static int do_efi_selftest(void)
>
>   	/* Execute the test */
>   	ret = EFI_CALL(efi_selftest(&image_obj->header, &systab));
> -	bootefi_run_finish(image_obj, loaded_image_info);
> +	efi_restore_gd();
> +	free(loaded_image_info->load_options);
> +	if (ret != EFI_SUCCESS)
> +		efi_delete_handle(&image_obj->header);
> +	else
> +		ret = efi_delete_handle(&image_obj->header);
>
>   	return ret != EFI_SUCCESS;
>   }
> diff --git a/include/efi_loader.h b/include/efi_loader.h
> index b5fa0fe01ded..3a64eb9c6672 100644
> --- a/include/efi_loader.h
> +++ b/include/efi_loader.h
> @@ -629,7 +629,7 @@ void efi_add_handle(efi_handle_t obj);
>   /* Create handle */
>   efi_status_t efi_create_handle(efi_handle_t *handle);
>   /* Delete handle */
> -void efi_delete_handle(efi_handle_t obj);
> +efi_status_t efi_delete_handle(efi_handle_t obj);
>   /* Call this to validate a handle and find the EFI object for it */
>   struct efi_object *efi_search_obj(const efi_handle_t handle);
>   /* Locate device_path handle */
> diff --git a/lib/efi_driver/efi_uclass.c b/lib/efi_driver/efi_uclass.c
> index 45f935198874..66a45e156d60 100644
> --- a/lib/efi_driver/efi_uclass.c
> +++ b/lib/efi_driver/efi_uclass.c
> @@ -285,10 +285,8 @@ static efi_status_t efi_add_driver(struct driver *drv)
>   	bp->ops = ops;
>
>   	ret = efi_create_handle(&bp->bp.driver_binding_handle);
> -	if (ret != EFI_SUCCESS) {
> -		free(bp);
> -		goto out;
> -	}
> +	if (ret != EFI_SUCCESS)
> +		goto err;
>   	bp->bp.image_handle = bp->bp.driver_binding_handle;
>   	ret = efi_add_protocol(bp->bp.driver_binding_handle,
>   			       &efi_guid_driver_binding_protocol, bp);
> @@ -299,11 +297,11 @@ static efi_status_t efi_add_driver(struct driver *drv)
>   		if (ret != EFI_SUCCESS)
>   			goto err;
>   	}
> -out:
> -	return ret;
>
> +	return ret;
>   err:
> -	efi_delete_handle(bp->bp.driver_binding_handle);
> +	if (bp->bp.driver_binding_handle)
> +		efi_delete_handle(bp->bp.driver_binding_handle);
>   	free(bp);
>   	return ret;
>   }
> diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
> index 052fe481e473..0e89c8505b11 100644
> --- a/lib/efi_loader/efi_boottime.c
> +++ b/lib/efi_loader/efi_boottime.c
> @@ -59,6 +59,10 @@ static efi_handle_t current_image;
>   static volatile gd_t *efi_gd, *app_gd;
>   #endif
>
> +static efi_status_t efi_uninstall_protocol
> +			(efi_handle_t handle, const efi_guid_t *protocol,
> +			 void *protocol_interface);
> +
>   /* 1 if inside U-Boot code, 0 if inside EFI payload code */
>   static int entry_count = 1;
>   static int nesting_level;
> @@ -610,8 +614,8 @@ static efi_status_t efi_remove_all_protocols(const efi_handle_t handle)
>   	list_for_each_entry_safe(protocol, pos, &efiobj->protocols, link) {
>   		efi_status_t ret;
>
> -		ret = efi_remove_protocol(handle, &protocol->guid,
> -					  protocol->protocol_interface);
> +		ret = efi_uninstall_protocol(handle, &protocol->guid,
> +					     protocol->protocol_interface);
>   		if (ret != EFI_SUCCESS)
>   			return ret;
>   	}
> @@ -622,19 +626,23 @@ static efi_status_t efi_remove_all_protocols(const efi_handle_t handle)
>    * efi_delete_handle() - delete handle
>    *
>    * @handle: handle to delete
> + *
> + * Return: status code
>    */
> -void efi_delete_handle(efi_handle_t handle)
> +efi_status_t efi_delete_handle(efi_handle_t handle)
>   {
>   	efi_status_t ret;
>
>   	ret = efi_remove_all_protocols(handle);
> -	if (ret == EFI_INVALID_PARAMETER) {
> -		log_err("Can't remove invalid handle %p\n", handle);
> -		return;
> +	if (ret != EFI_SUCCESS) {
> +		log_err("Handle %p has protocols installed. Unable to delete\n", handle);
> +		return ret;
>   	}
>
>   	list_del(&handle->link);
>   	free(handle);
> +
> +	return ret;
>   }
>
>   /**
> diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c
> index 28c8cdf7100e..8983b86886b3 100644
> --- a/lib/efi_loader/efi_disk.c
> +++ b/lib/efi_loader/efi_disk.c
> @@ -708,6 +708,7 @@ int efi_disk_remove(void *ctx, struct event *event)
>   	efi_handle_t handle;
>   	struct blk_desc *desc;
>   	struct efi_disk_obj *diskobj = NULL;
> +	efi_status_t ret;
>
>   	if (dev_tag_get_ptr(dev, DM_TAG_EFI, (void **)&handle))
>   		return 0;
> @@ -727,10 +728,13 @@ int efi_disk_remove(void *ctx, struct event *event)
>   		return 0;
>   	}
>
> +	ret = efi_delete_handle(handle);
> +	if (ret != EFI_SUCCESS)
> +		return -1;

I guess we should add a comment here explaining that the DM device
should not be removed if there still are open protocols for the handle.

Reviewed-by: Heinrich Schuchardt <xypron.glpk at gmx.de>

> +
>   	if (diskobj)
>   		efi_free_pool(diskobj->dp);
>
> -	efi_delete_handle(handle);
>   	dev_tag_del(dev, DM_TAG_EFI);
>
>   	return 0;
> --
> 2.40.1
>



More information about the U-Boot mailing list