[U-Boot] [PATCH 09/16] efi_loader: implement ConnectController
Simon Glass
sjg at chromium.org
Mon Jan 8 03:35:24 UTC 2018
Hi Heinrick,
On 17 December 2017 at 08:43, Heinrich Schuchardt <xypron.glpk at gmx.de> wrote:
> Implement the ConnectController boot service.
>
> Signed-off-by: Heinrich Schuchardt <xypron.glpk at gmx.de>
> ---
> include/efi_api.h | 22 ++++++
> include/efi_loader.h | 2 +
> lib/efi_loader/efi_boottime.c | 178 ++++++++++++++++++++++++++++++++++++------
> 3 files changed, 178 insertions(+), 24 deletions(-)
Reviewed-by: Simon Glass <sjg at chromium.org>
Please see below. Also please mention when tests come for these.
>
> diff --git a/include/efi_api.h b/include/efi_api.h
> index 46963f2891..81e580dbbc 100644
> --- a/include/efi_api.h
> +++ b/include/efi_api.h
> @@ -805,4 +805,26 @@ struct efi_file_info {
> s16 file_name[0];
> };
>
> +#define EFI_DRIVER_BINDING_PROTOCOL_GUID \
> + EFI_GUID(0x18a031ab, 0xb443, 0x4d1a,\
> + 0xa5, 0xc0, 0x0c, 0x09, 0x26, 0x1e, 0x9f, 0x71)
> +struct efi_driver_binding_protocol {
> + efi_status_t (EFIAPI * supported)(
> + struct efi_driver_binding_protocol *this,
> + efi_handle_t controller_handle,
> + struct efi_device_path *remaining_device_path);
> + efi_status_t (EFIAPI * start)(
> + struct efi_driver_binding_protocol *this,
> + efi_handle_t controller_handle,
> + struct efi_device_path *remaining_device_path);
> + efi_status_t (EFIAPI * stop)(
> + struct efi_driver_binding_protocol *this,
> + efi_handle_t controller_handle,
> + efi_uintn_t number_of_children,
> + efi_handle_t *child_handle_buffer);
> + u32 version;
> + efi_handle_t image_handle;
> + efi_handle_t driver_binding_handle;
> +};
> +
> #endif
> diff --git a/include/efi_loader.h b/include/efi_loader.h
> index 637e6e166d..9e1ae8866b 100644
> --- a/include/efi_loader.h
> +++ b/include/efi_loader.h
> @@ -88,6 +88,8 @@ uint16_t *efi_dp_str(struct efi_device_path *dp);
> extern const efi_guid_t efi_global_variable_guid;
> extern const efi_guid_t efi_guid_console_control;
> extern const efi_guid_t efi_guid_device_path;
> +/* GUID of the EFI_DRIVER_BINDING_PROTOCOL */
> +extern const efi_guid_t efi_guid_driver_binding_protocol;
> extern const efi_guid_t efi_guid_loaded_image;
> extern const efi_guid_t efi_guid_device_path_to_text_protocol;
> extern const efi_guid_t efi_simple_file_system_protocol_guid;
> diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
> index b5d6808bf7..6cc0659eb9 100644
> --- a/lib/efi_loader/efi_boottime.c
> +++ b/lib/efi_loader/efi_boottime.c
> @@ -56,6 +56,9 @@ static volatile void *efi_gd, *app_gd;
>
> static int entry_count;
> static int nesting_level;
> +/* GUID of the EFI_DRIVER_BINDING_PROTOCOL */
> +const efi_guid_t efi_guid_driver_binding_protocol =
> + EFI_DRIVER_BINDING_PROTOCOL_GUID;
>
> /* Called on every callback entry */
> int __efi_entry_check(void)
> @@ -1619,30 +1622,6 @@ static efi_status_t EFIAPI efi_set_watchdog_timer(unsigned long timeout,
> return EFI_EXIT(efi_set_watchdog(timeout));
> }
>
> -/*
> - * Connect a controller to a driver.
> - *
> - * This function implements the ConnectController service.
> - * See the Unified Extensible Firmware Interface (UEFI) specification
> - * for details.
> - *
> - * @controller_handle handle of the controller
> - * @driver_image_handle handle of the driver
> - * @remain_device_path device path of a child controller
> - * @recursive true to connect all child controllers
> - * @return status code
> - */
> -static efi_status_t EFIAPI efi_connect_controller(
> - efi_handle_t controller_handle,
> - efi_handle_t *driver_image_handle,
> - struct efi_device_path *remain_device_path,
> - bool recursive)
> -{
> - EFI_ENTRY("%p, %p, %p, %d", controller_handle, driver_image_handle,
> - remain_device_path, recursive);
> - return EFI_EXIT(EFI_NOT_FOUND);
> -}
> -
> /*
> * Disconnect a controller from a driver.
> *
> @@ -2352,6 +2331,157 @@ static efi_status_t EFIAPI efi_handle_protocol(void *handle,
> NULL, EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL);
> }
>
> +static efi_status_t efi_bind_controller(
> + efi_handle_t controller_handle,
> + efi_handle_t driver_image_handle,
> + struct efi_device_path *remain_device_path)
> +{
> + struct efi_driver_binding_protocol *binding_protocol;
> + efi_status_t r;
> +
> + r = EFI_CALL(efi_open_protocol(driver_image_handle,
> + &efi_guid_driver_binding_protocol,
> + (void **)&binding_protocol,
> + driver_image_handle, NULL,
> + EFI_OPEN_PROTOCOL_GET_PROTOCOL));
> + if (r != EFI_SUCCESS)
> + return r;
> + r = EFI_CALL(binding_protocol->supported(binding_protocol,
> + controller_handle,
> + remain_device_path));
> + if (r == EFI_SUCCESS)
> + r = EFI_CALL(binding_protocol->start(binding_protocol,
> + controller_handle,
> + remain_device_path));
> + EFI_CALL(efi_close_protocol(driver_image_handle,
> + &efi_guid_driver_binding_protocol,
> + driver_image_handle, NULL));
> + return r;
> +}
> +
> +static efi_status_t efi_connect_single_controller(
> + efi_handle_t controller_handle,
> + efi_handle_t *driver_image_handle,
> + struct efi_device_path *remain_device_path)
> +{
> + efi_handle_t *buffer;
> + size_t count;
> + size_t i;
> + efi_status_t r;
> + size_t connected = 0;
> +
> + /* Get buffer with all handles with driver binding protocol */
> + r = EFI_CALL(efi_locate_handle_buffer(BY_PROTOCOL,
> + &efi_guid_driver_binding_protocol,
> + NULL, &count, &buffer));
> + if (r != EFI_SUCCESS)
> + return r;
> +
> + /* Context Override */
> + if (driver_image_handle) {
> + for (; *driver_image_handle; ++driver_image_handle) {
> + for (i = 0; i < count; ++i) {
> + if (buffer[i] == *driver_image_handle) {
> + buffer[i] = NULL;
> + r = efi_bind_controller(
> + controller_handle,
> + *driver_image_handle,
> + remain_device_path);
> + if (r == EFI_SUCCESS)
> + ++connected;
What happens to any error here?
> + }
> + }
> + }
> + }
> +
> + /*
> + * TODO: Some overrides are not yet implemented:
> + * - Platform Driver Override
> + * - Driver Family Override Search
> + * - Bus Specific Driver Override
Bus-specific ?
> + */
> +
> + /* Driver Binding Search */
> + for (i = 0; i < count; ++i) {
> + if (buffer[i]) {
> + r = efi_bind_controller(controller_handle,
> + buffer[i],
> + remain_device_path);
> + if (r == EFI_SUCCESS)
> + ++connected;
> + }
> + }
> +
> + efi_free_pool(buffer);
> + if (!connected)
> + return EFI_NOT_FOUND;
> + return EFI_SUCCESS;
> +}
> +
> +/*
> + * Connect a controller to a driver.
> + *
> + * This function implements the ConnectController service.
> + * See the Unified Extensible Firmware Interface (UEFI) specification
> + * for details.
Well I think it would be good to explain briefly what it does.
> + *
> + * @controller_handle handle of the controller
> + * @driver_image_handle handle of the driver
> + * @remain_device_path device path of a child controller
> + * @recursive true to connect all child controllers
> + * @return status code
> + */
> +static efi_status_t EFIAPI efi_connect_controller(
> + efi_handle_t controller_handle,
> + efi_handle_t *driver_image_handle,
> + struct efi_device_path *remain_device_path,
> + bool recursive)
> +{
> + efi_status_t r;
> + efi_status_t ret = EFI_NOT_FOUND;
> + struct efi_object *efiobj;
> +
> + EFI_ENTRY("%p, %p, %p, %d", controller_handle, driver_image_handle,
> + remain_device_path, recursive);
> +
> + efiobj = efi_search_obj(controller_handle);
> + if (!efiobj) {
> + ret = EFI_INVALID_PARAMETER;
> + goto out;
> + }
> +
> + r = efi_connect_single_controller(controller_handle,
> + driver_image_handle,
> + remain_device_path);
> + if (r == EFI_SUCCESS)
> + ret = EFI_SUCCESS;
> + if (recursive) {
> + struct efi_handler *handler;
> + struct efi_open_protocol_info_item *item;
> +
> + list_for_each_entry(handler, &efiobj->protocols, link) {
> + list_for_each_entry(item, &handler->open_infos, link) {
> + if (item->info.attributes &
> + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) {
> + r = EFI_CALL(efi_connect_controller(
> + item->info.controller_handle,
> + driver_image_handle,
> + remain_device_path,
> + recursive));
> + if (r == EFI_SUCCESS)
> + ret = EFI_SUCCESS;
> + }
> + }
> + }
> + }
> + /* Check for child controller specified by end node */
> + if (ret != EFI_SUCCESS && remain_device_path &&
> + remain_device_path->type == DEVICE_PATH_TYPE_END)
> + ret = EFI_SUCCESS;
> +out:
> + return EFI_EXIT(ret);
> +}
> +
> static const struct efi_boot_services efi_boot_services = {
> .hdr = {
> .headersize = sizeof(struct efi_table_hdr),
> --
> 2.14.2
>
Regards,
Simon
More information about the U-Boot
mailing list