[U-Boot] [PATCH 10/23] efi_loader: open_info in OpenProtocol

Simon Glass sjg at chromium.org
Thu Aug 31 12:51:43 UTC 2017


Hi Heinrich,

On 27 August 2017 at 06:53, Heinrich Schuchardt <xypron.glpk at gmx.de> wrote:
> efi_open_protocol and close_protocol have to keep track of
> opened protocols.
>
> So we add an array open_info to each protocol of each handle.
>
> OpenProtocol has enter the agent and controller handle
> information into this array.
>
> Signed-off-by: Heinrich Schuchardt <xypron.glpk at gmx.de>
> ---
>  include/efi_loader.h          |   1 +
>  lib/efi_loader/efi_boottime.c | 130 +++++++++++++++++++++++++++++++-----------
>  2 files changed, 99 insertions(+), 32 deletions(-)
>

Reviewed-by: Simon Glass <sjg at chromium.org>

Please see below.

> diff --git a/include/efi_loader.h b/include/efi_loader.h
> index 193fca24ce..2c3360534b 100644
> --- a/include/efi_loader.h
> +++ b/include/efi_loader.h
> @@ -87,6 +87,7 @@ extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop;
>  struct efi_handler {
>         const efi_guid_t *guid;
>         void *protocol_interface;
> +       struct efi_open_protocol_info_entry open_info[4];
>  };
>
>  /*
> diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
> index a483b827cd..294bc1f138 100644
> --- a/lib/efi_loader/efi_boottime.c
> +++ b/lib/efi_loader/efi_boottime.c
> @@ -1152,24 +1152,111 @@ static void EFIAPI efi_set_mem(void *buffer, unsigned long size, uint8_t value)
>         memset(buffer, value, size);
>  }
>
> +static efi_status_t efi_protocol_open(
> +                       struct efi_handler *protocol,
> +                       void **protocol_interface, void *agent_handle,
> +                       void *controller_handle, uint32_t attributes)
> +{
> +       bool opened_exclusive = false;
> +       bool opened_by_driver = false;
> +       int i;
> +       struct efi_open_protocol_info_entry *open_info;
> +       struct efi_open_protocol_info_entry *match = NULL;
> +
> +       if (attributes !=
> +           EFI_OPEN_PROTOCOL_TEST_PROTOCOL) {
> +               *protocol_interface = NULL;
> +       }
> +
> +       for (i = 0; i < ARRAY_SIZE(protocol->open_info); ++i) {
> +               open_info = &protocol->open_info[i];
> +
> +               if (!open_info->open_count)
> +                       continue;
> +               if (open_info->agent_handle == agent_handle) {
> +                       if ((attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) &&
> +                           (open_info->attributes == attributes))
> +                               return EFI_ALREADY_STARTED;
> +                       if (open_info->controller_handle == controller_handle)
> +                               match = open_info;
> +               }
> +               if (open_info->attributes & EFI_OPEN_PROTOCOL_EXCLUSIVE)
> +                       opened_exclusive = true;
> +       }
> +
> +       if (attributes &
> +           (EFI_OPEN_PROTOCOL_EXCLUSIVE | EFI_OPEN_PROTOCOL_BY_DRIVER) &&
> +           opened_exclusive)
> +               return EFI_ACCESS_DENIED;
> +
> +       if (attributes & EFI_OPEN_PROTOCOL_EXCLUSIVE) {
> +               for (i = 0; i < ARRAY_SIZE(protocol->open_info); ++i) {

Is it possible to put this search in a utility function with suitable
parameters and call it? This function is very long.

> +                       open_info = &protocol->open_info[i];
> +
> +                       if (!open_info->open_count)
> +                               continue;
> +                       if (open_info->attributes ==
> +                                       EFI_OPEN_PROTOCOL_BY_DRIVER)
> +                               EFI_CALL(efi_disconnect_controller(
> +                                               open_info->controller_handle,
> +                                               open_info->agent_handle,
> +                                               NULL));
> +               }
> +               opened_by_driver = false;
> +               for (i = 0; i < ARRAY_SIZE(protocol->open_info); ++i) {
> +                       open_info = &protocol->open_info[i];
> +
> +                       if (!open_info->open_count)
> +                               continue;
> +                       if (open_info->attributes & EFI_OPEN_PROTOCOL_BY_DRIVER)
> +                               opened_by_driver = true;
> +               }
> +               if (opened_by_driver)
> +                       return EFI_ACCESS_DENIED;
> +               if (match && !match->open_count)
> +                       match = NULL;
> +       }
> +
> +       /*
> +        * Find an empty slot.
> +        */
> +       if (!match) {
> +               for (i = 0; i < ARRAY_SIZE(protocol->open_info); ++i) {
> +                       open_info = &protocol->open_info[i];
> +
> +                       if (!open_info->open_count) {
> +                               match = open_info;
> +                               break;
> +                       }
> +               }
> +       }
> +       if (!match)
> +               return EFI_OUT_OF_RESOURCES;
> +
> +       match->agent_handle = agent_handle;
> +       match->controller_handle = controller_handle;
> +       match->attributes = attributes;
> +       match->open_count++;
> +       *protocol_interface = protocol->protocol_interface;
> +
> +       return EFI_SUCCESS;
> +}
> +
>  static efi_status_t EFIAPI efi_open_protocol(
>                         void *handle, efi_guid_t *protocol,
>                         void **protocol_interface, void *agent_handle,
>                         void *controller_handle, uint32_t attributes)
>  {
> -       struct list_head *lhandle;
> -       int i;
> +       struct efi_handler *handler;
>         efi_status_t r = EFI_INVALID_PARAMETER;
>
>         EFI_ENTRY("%p, %p, %p, %p, %p, 0x%x", handle, protocol,
>                   protocol_interface, agent_handle, controller_handle,
>                   attributes);
>
> -       if (!handle || !protocol ||
> -           (!protocol_interface && attributes !=
> -            EFI_OPEN_PROTOCOL_TEST_PROTOCOL)) {
> +       if (!protocol_interface && attributes !=
> +           EFI_OPEN_PROTOCOL_TEST_PROTOCOL)
>                 goto out;
> -       }
>
>         switch (attributes) {
>         case EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL:
> @@ -1191,33 +1278,12 @@ static efi_status_t EFIAPI efi_open_protocol(
>                 goto out;
>         }
>
> -       list_for_each(lhandle, &efi_obj_list) {
> -               struct efi_object *efiobj;
> -               efiobj = list_entry(lhandle, struct efi_object, link);
> -
> -               if (efiobj->handle != handle)
> -                       continue;
> -
> -               for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) {
> -                       struct efi_handler *handler = &efiobj->protocols[i];
> -                       const efi_guid_t *hprotocol = handler->guid;
> -                       if (!hprotocol)
> -                               continue;
> -                       if (!guidcmp(hprotocol, protocol)) {
> -                               if (attributes !=
> -                                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL) {
> -                                       *protocol_interface =
> -                                               handler->protocol_interface;
> -                               }
> -                               r = EFI_SUCCESS;
> -                               goto out;
> -                       }
> -               }
> -               goto unsupported;
> -       }
> +       r = efi_search_protocol(handle, protocol, &handler);
> +       if (r != EFI_SUCCESS)
> +               goto out;
>
> -unsupported:
> -       r = EFI_UNSUPPORTED;
> +       r = efi_protocol_open(handler, protocol_interface, agent_handle,
> +                             controller_handle, attributes);
>  out:
>         return EFI_EXIT(r);
>  }
> --
> 2.14.1
>


More information about the U-Boot mailing list