On 18.01.18 21:08, Heinrich Schuchardt wrote:
> On 01/17/2018 08:16 PM, Heinrich Schuchardt wrote:
>> This patch provides
>> * a uclass for EFI drivers
>> * a EFI driver for block devices
>>
>> For each EFI driver the uclass
>> * creates a handle
>> * adds the driver binding protocol
>>
>> The uclass provides the bind, start, and stop entry points for the driver
>> binding protocol.
>>
>> In bind() and stop() it checks if the controller implements the protocol
>> supported by the EFI driver. In the start() function it calls the bind()
>> function of the EFI driver. In the stop() function it destroys the child
>> controllers.
>>
>> The EFI block driver binds to controllers implementing the block io
>> protocol.
>>
>> When the bind function of the EFI block driver is called it creates a
>> new U-Boot block device. It installs child handles for all partitions and
>> installs the simple file protocol on these.
>>
>> The read and write functions of the EFI block driver delegate calls to the
>> controller that it is bound to.
>>
>> A usage example is as following:
>>
>> U-Boot loads the iPXE snp.efi executable. iPXE connects an iSCSI drive and
>> exposes a handle with the block IO protocol. It calls ConnectController.
>>
>> Now the EFI block driver installs the partions with the simple file
>> protocol.
>>
>> iPXE uses the simple file protocol to load Grub or the Linux Kernel.
>>
>> Signed-off-by: Heinrich Schuchardt <xypron.g...@gmx.de>
>> ---
>> v2
>>      Print to console only in debug mode.
>>      Provide more comments.
>>      Add commit message.
>> ---
>>  common/board_r.c                  |   3 +
>>  drivers/block/blk-uclass.c        |   4 +-
>>  include/blk.h                     |   1 +
>>  include/config_fallbacks.h        |   1 +
>>  include/dm/uclass-id.h            |   1 +
>>  include/efi_driver.h              |  30 ++++
>>  include/efi_loader.h              |   2 +
>>  lib/Makefile                      |   1 +
>>  lib/efi_driver/Makefile           |  13 ++
>>  lib/efi_driver/efi_block_device.c | 175 ++++++++++++++++++++
>>  lib/efi_driver/efi_uclass.c       | 330 
>> ++++++++++++++++++++++++++++++++++++++
>>  11 files changed, 560 insertions(+), 1 deletion(-)
>>  create mode 100644 include/efi_driver.h
>>  create mode 100644 lib/efi_driver/Makefile
>>  create mode 100644 lib/efi_driver/efi_block_device.c
>>  create mode 100644 lib/efi_driver/efi_uclass.c
>>
>> diff --git a/common/board_r.c b/common/board_r.c
>> index 2baa47f3a0..4ad37ee31a 100644
>> --- a/common/board_r.c
>> +++ b/common/board_r.c
>> @@ -715,7 +715,10 @@ static init_fnc_t init_sequence_r[] = {
>>      set_cpu_clk_info, /* Setup clock information */
>>  #endif
>>  #ifdef CONFIG_EFI_LOADER
>> +    /* Setup EFI memory before any other EFI related code */
>>      efi_memory_init,
>> +    /* Install EFI drivers */
>> +    efi_driver_init,
>>  #endif
>>      stdio_init_tables,
>>      initr_serial,
>> diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c
>> index 010ed32d3a..bfda2211f0 100644
>> --- a/drivers/block/blk-uclass.c
>> +++ b/drivers/block/blk-uclass.c
>> @@ -24,6 +24,7 @@ static const char *if_typename_str[IF_TYPE_COUNT] = {
>>      [IF_TYPE_HOST]          = "host",
>>      [IF_TYPE_SYSTEMACE]     = "ace",
>>      [IF_TYPE_NVME]          = "nvme",
>> +    [IF_TYPE_EFI]           = "efi",
>>  };
>>  
>>  static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = {
>> @@ -36,8 +37,9 @@ static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = {
>>      [IF_TYPE_SD]            = UCLASS_INVALID,
>>      [IF_TYPE_SATA]          = UCLASS_AHCI,
>>      [IF_TYPE_HOST]          = UCLASS_ROOT,
>> -    [IF_TYPE_NVME]          = UCLASS_NVME,
>>      [IF_TYPE_SYSTEMACE]     = UCLASS_INVALID,
>> +    [IF_TYPE_NVME]          = UCLASS_NVME,
>> +    [IF_TYPE_EFI]           = UCLASS_EFI,
>>  };
>>  
>>  static enum if_type if_typename_to_iftype(const char *if_typename)
>> diff --git a/include/blk.h b/include/blk.h
>> index 41b4d7efa8..69b5a98e56 100644
>> --- a/include/blk.h
>> +++ b/include/blk.h
>> @@ -34,6 +34,7 @@ enum if_type {
>>      IF_TYPE_HOST,
>>      IF_TYPE_SYSTEMACE,
>>      IF_TYPE_NVME,
>> +    IF_TYPE_EFI,
>>  
>>      IF_TYPE_COUNT,                  /* Number of interface types */
>>  };
>> diff --git a/include/config_fallbacks.h b/include/config_fallbacks.h
>> index 2c4d43d672..524313d5aa 100644
>> --- a/include/config_fallbacks.h
>> +++ b/include/config_fallbacks.h
>> @@ -52,6 +52,7 @@
>>      defined(CONFIG_MMC) || \
>>      defined(CONFIG_NVME) || \
>>      defined(CONFIG_SYSTEMACE) || \
>> +    (defined(CONFIG_EFI_LOADER) && !defined(CONFIG_SPL_BUILD)) || \
>>      defined(CONFIG_SANDBOX)
>>  #define HAVE_BLOCK_DEVICE
>>  #endif
>> diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
>> index 3fc20834ae..07fabc3ce6 100644
>> --- a/include/dm/uclass-id.h
>> +++ b/include/dm/uclass-id.h
>> @@ -34,6 +34,7 @@ enum uclass_id {
>>      UCLASS_CROS_EC,         /* Chrome OS EC */
>>      UCLASS_DISPLAY,         /* Display (e.g. DisplayPort, HDMI) */
>>      UCLASS_DMA,             /* Direct Memory Access */
>> +    UCLASS_EFI,             /* EFI managed devices */
>>      UCLASS_ETH,             /* Ethernet device */
>>      UCLASS_GPIO,            /* Bank of general-purpose I/O pins */
>>      UCLASS_FIRMWARE,        /* Firmware */
>> diff --git a/include/efi_driver.h b/include/efi_driver.h
>> new file mode 100644
>> index 0000000000..2bbe26c6e3
>> --- /dev/null
>> +++ b/include/efi_driver.h
>> @@ -0,0 +1,30 @@
>> +/*
>> + *  EFI application loader
>> + *
>> + *  Copyright (c) 2017 Heinrich Schuchardt
>> + *
>> + *  SPDX-License-Identifier:     GPL-2.0+
>> + */
>> +
>> +#ifndef _EFI_DRIVER_H
>> +#define _EFI_DRIVER_H 1
>> +
>> +#include <common.h>
>> +#include <dm.h>
>> +#include <efi_loader.h>
>> +
>> +struct efi_driver_ops {
>> +    const efi_guid_t *protocol;
>> +    const efi_guid_t *child_protocol;
>> +    int (*bind)(efi_handle_t handle, void *interface);
>> +};
>> +
>> +/*
>> + * This structure adds internal fields to the driver binding protocol.
>> + */
>> +struct efi_driver_binding_extended_protocol {
>> +    struct efi_driver_binding_protocol bp;
>> +    const struct efi_driver_ops *ops;
>> +};
>> +
>> +#endif /* _EFI_DRIVER_H */
>> diff --git a/include/efi_loader.h b/include/efi_loader.h
>> index 711c901eda..a465175d1f 100644
>> --- a/include/efi_loader.h
>> +++ b/include/efi_loader.h
>> @@ -273,6 +273,8 @@ efi_status_t efi_get_memory_map(efi_uintn_t 
>> *memory_map_size,
>>  /* Adds a range into the EFI memory map */
>>  uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
>>                          bool overlap_only_ram);
>> +/* Called by board init to initialize the EFI drivers */
>> +int efi_driver_init(void);
>>  /* Called by board init to initialize the EFI memory map */
>>  int efi_memory_init(void);
>>  /* Adds new or overrides configuration table entry to the system table */
>> diff --git a/lib/Makefile b/lib/Makefile
>> index 8cd779f8ca..0db41c19f3 100644
>> --- a/lib/Makefile
>> +++ b/lib/Makefile
>> @@ -8,6 +8,7 @@
>>  ifndef CONFIG_SPL_BUILD
>>  
>>  obj-$(CONFIG_EFI) += efi/
>> +obj-$(CONFIG_EFI_LOADER) += efi_driver/
>>  obj-$(CONFIG_EFI_LOADER) += efi_loader/
>>  obj-$(CONFIG_EFI_LOADER) += efi_selftest/
>>  obj-$(CONFIG_LZMA) += lzma/
>> diff --git a/lib/efi_driver/Makefile b/lib/efi_driver/Makefile
>> new file mode 100644
>> index 0000000000..e35529a952
>> --- /dev/null
>> +++ b/lib/efi_driver/Makefile
>> @@ -0,0 +1,13 @@
>> +#
>> +# (C) Copyright 2017 Heinrich Schuchardt
>> +#
>> +#  SPDX-License-Identifier:     GPL-2.0+
>> +#
>> +
>> +# This file only gets included with CONFIG_EFI_LOADER set, so all
>> +# object inclusion implicitly depends on it
>> +
>> +obj-y += efi_uclass.o
>> +ifeq ($(CONFIG_BLK)$(CONFIG_PARTITIONS),yy)
>> +obj-y += efi_block_device.o
>> +endif
>> diff --git a/lib/efi_driver/efi_block_device.c 
>> b/lib/efi_driver/efi_block_device.c
>> new file mode 100644
>> index 0000000000..837787d563
>> --- /dev/null
>> +++ b/lib/efi_driver/efi_block_device.c
>> @@ -0,0 +1,175 @@
>> +/*
>> + *  EFI block driver
>> + *
>> + *  Copyright (c) 2017 Heinrich Schuchardt
>> + *
>> + *  SPDX-License-Identifier:     GPL-2.0+
>> + *
>> + * The EFI uclass creates a handle for this driver and installs the
>> + * driver binding protocol on it.
>> + *
>> + * The EFI block driver binds to controllers implementing the block io
>> + * protocol.
>> + *
>> + * When the bind function of the EFI block driver is called it creates a
>> + * new U-Boot block device. It installs child handles for all partitions and
>> + * installs the simple file protocol on these.
>> + *
>> + * The read and write functions of the EFI block driver delegate calls to 
>> the
>> + * controller that it is bound to.
>> + *
>> + * A usage example is as following:
>> + *
>> + * U-Boot loads the iPXE snp.efi executable. iPXE connects an iSCSI drive 
>> and
>> + * exposes a handle with the block IO protocol. It calls ConnectController.
>> + *
>> + * Now the EFI block driver installs the partions with the simple file
>> + * protocol.
>> + *
>> + * iPXE uses the simple file protocol to load Grub or the Linux Kernel.
>> + */
>> +
>> +#include <efi_driver.h>
>> +#include <dm/root.h>
>> +
>> +static int efi_blk_max_devnum;
>> +
>> +/*
>> + * Read from block device
>> + *
>> + * @dev             device
>> + * @blknr   first block to be read
>> + * @blkcnt  number of blocks to read
>> + * @buffer  output buffer
>> + * @return  number of blocks transferred
>> + */
>> +static ulong efi_bl_read(struct udevice *dev, lbaint_t blknr, lbaint_t 
>> blkcnt,
>> +                     void *buffer)
>> +{
>> +    struct efi_block_io *io = dev->platdata;
>> +    efi_status_t ret;
>> +
>> +    EFI_PRINT("%s: read '%s', from block " LBAFU ", " LBAFU " blocks\n",
>> +              __func__, dev->name, blknr, blkcnt);
>> +    ret = EFI_CALL(io->read_blocks(
>> +                            io, io->media->media_id, (u64)blknr,
>> +                            (efi_uintn_t)blkcnt *
>> +                            (efi_uintn_t)io->media->block_size, buffer));
>> +    EFI_PRINT("%s: r = %u\n", __func__,
>> +              (unsigned int)(ret & ~EFI_ERROR_MASK));
>> +    if (ret != EFI_SUCCESS)
>> +            return 0;
>> +    return blkcnt;
>> +}
>> +
>> +/*
>> + * Write to block device
>> + *
>> + * @dev             device
>> + * @blknr   first block to be write
>> + * @blkcnt  number of blocks to write
>> + * @buffer  input buffer
>> + * @return  number of blocks transferred
>> + */
>> +static ulong efi_bl_write(struct udevice *dev, lbaint_t blknr, lbaint_t 
>> blkcnt,
>> +                      const void *buffer)
>> +{
>> +    struct efi_block_io *io = dev->platdata;
>> +    efi_status_t ret;
>> +
>> +    EFI_PRINT("%s: write '%s', from block " LBAFU ", " LBAFU " blocks\n",
>> +              __func__, dev->name, blknr, blkcnt);
>> +    ret = EFI_CALL(io->write_blocks(
>> +                            io, io->media->media_id, (u64)blknr,
>> +                            (efi_uintn_t)blkcnt *
>> +                            (efi_uintn_t)io->media->block_size,
>> +                            (void *)buffer));
>> +    EFI_PRINT("%s: r = %u\n", __func__,
>> +              (unsigned int)(ret & ~EFI_ERROR_MASK));
>> +    if (ret != EFI_SUCCESS)
>> +            return 0;
>> +    return blkcnt;
>> +}
>> +
>> +static int efi_bl_bind_partions(efi_handle_t handle)
>> +{
>> +    struct efi_object *obj = efi_search_obj(handle);
>> +    struct blk_desc *desc;
>> +    const char *if_typename;
>> +
>> +    if (!obj || !obj->dev)
>> +            return -ENOENT;
>> +    desc = dev_get_uclass_platdata(obj->dev);
>> +    if_typename = blk_get_if_type_name(desc->if_type);
>> +
>> +    return efi_disk_create_partitions(handle, desc, if_typename,
>> +                                      desc->devnum, obj->dev->name);
>> +}
>> +
>> +/*
>> + * Create a block device for a handle
>> + *
>> + * @handle  handle
>> + * @interface       block io protocol
>> + * @return  0 = success
>> + */
>> +static int efi_bl_bind(efi_handle_t handle, void *interface)
>> +{
>> +    struct udevice *bdev, *parent = dm_root();
>> +    int ret, devnum;
>> +    char name[20];
>> +    struct efi_object *obj = efi_search_obj(handle);
>> +    struct efi_block_io *io = interface;
>> +    int disks;
>> +
>> +    EFI_PRINT("%s: handle %p, interface %p\n", __func__, handle, io);
>> +
>> +    if (!obj)
>> +            return -ENOENT;
>> +
>> +    devnum = efi_blk_max_devnum++;
>> +    sprintf(name, "efi#%d", devnum);
>> +
>> +    ret = blk_create_device(parent, "efi_blk", name, IF_TYPE_EFI, devnum,
>> +                            io->media->block_size,
>> +                            (lbaint_t)io->media->last_block, &bdev);
>> +    if (ret)
>> +            return ret;
>> +    EFI_PRINT("%s: block device '%s' created\n", __func__, bdev->name);
>> +    bdev->platdata = interface;
>> +    obj->dev = bdev;
>> +
>> +    ret = blk_prepare_device(bdev);
>> +
>> +    disks = efi_bl_bind_partions(handle);
>> +    EFI_PRINT("Found %d partions\n", disks);
>> +
>> +    return 0;
>> +}
>> +
>> +/* Block device driver operators */
>> +static const struct blk_ops efi_blk_ops = {
>> +    .read   = efi_bl_read,
>> +    .write  = efi_bl_write,
>> +};
>> +
>> +/* Identify as block device driver */
>> +U_BOOT_DRIVER(efi_blk) = {
>> +    .name           = "efi_blk",
>> +    .id             = UCLASS_BLK,
>> +    .ops            = &efi_blk_ops,
>> +};
>> +
>> +/* EFI driver operators */
>> +static const struct efi_driver_ops driver_ops = {
>> +    .protocol       = &efi_block_io_guid,
>> +    .child_protocol = &efi_block_io_guid,
>> +    .bind           = efi_bl_bind,
>> +};
>> +
>> +/* Identify as EFI driver */
>> +U_BOOT_DRIVER(efi_block) = {
>> +    .name           = "EFI block driver",
>> +    .id             = UCLASS_EFI,
>> +    .ops            = &driver_ops,
>> +};
>> diff --git a/lib/efi_driver/efi_uclass.c b/lib/efi_driver/efi_uclass.c
>> new file mode 100644
>> index 0000000000..798431ae74
>> --- /dev/null
>> +++ b/lib/efi_driver/efi_uclass.c
>> @@ -0,0 +1,330 @@
>> +/*
>> + *  Uclass for EFI drivers
>> + *
>> + *  Copyright (c) 2017 Heinrich Schuchardt
>> + *
>> + *  SPDX-License-Identifier:     GPL-2.0+
>> + *
>> + * For each EFI driver the uclass
>> + * - creates a handle
>> + * - installs the driver binding protocol
>> + *
>> + * The uclass provides the bind, start, and stop entry points for the driver
>> + * binding protocol.
>> + *
>> + * In bind() and stop() it checks if the controller implements the protocol
>> + * supported by the EFI driver. In the start() function it calls the bind()
>> + * function of the EFI driver. In the stop() function it destroys the child
>> + * controllers.
>> + */
>> +
>> +#include <efi_driver.h>
>> +
>> +/*
>> + * Check node type. We do not support partions as controller handles.
>> + *
>> + * @handle  handle to be checked
>> + * @return  status code
>> + */
>> +static efi_status_t check_node_type(efi_handle_t handle)
>> +{
>> +    efi_status_t r, ret = EFI_SUCCESS;
>> +    const struct efi_device_path *dp;
>> +
>> +    /* Open the device path protocol */
>> +    r = EFI_CALL(systab.boottime->open_protocol(
>> +                    handle, &efi_guid_device_path, (void **)&dp,
>> +                    NULL, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL));
>> +    if (r == EFI_SUCCESS && dp) {
>> +            /* Get the last node */
>> +            const struct efi_device_path *node = efi_dp_last_node(dp);
>> +            /* We do not support partitions as controller */
>> +            if (!node || node->type == DEVICE_PATH_TYPE_MEDIA_DEVICE)
>> +                    ret = EFI_UNSUPPORTED;
>> +    }
>> +    return ret;
>> +}
>> +
>> +/*
>> + * Check if the driver supports the controller.
>> + *
>> + * @this                    driver binding protocol
>> + * @controller_handle               handle of the controller
>> + * @remaining_device_path   path specifying the child controller
>> + * @return                  status code
>> + */
>> +static efi_status_t EFIAPI efi_uc_supported(
>> +            struct efi_driver_binding_protocol *this,
>> +            efi_handle_t controller_handle,
>> +            struct efi_device_path *remaining_device_path)
>> +{
>> +    efi_status_t r, ret;
>> +    void *interface;
>> +    struct efi_driver_binding_extended_protocol *bp =
>> +                    (struct efi_driver_binding_extended_protocol *)this;
>> +
>> +    EFI_ENTRY("%p, %p, %ls", this, controller_handle,
>> +              efi_dp_str(remaining_device_path));
>> +
>> +    ret = EFI_CALL(systab.boottime->open_protocol(
>> +                    controller_handle, bp->ops->protocol,
>> +                    &interface, this->driver_binding_handle,
>> +                    controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER));
>> +    switch (ret) {
>> +    case EFI_ACCESS_DENIED:
>> +    case EFI_ALREADY_STARTED:
>> +            goto out;
>> +    case EFI_SUCCESS:
>> +            break;
>> +    default:
>> +            ret = EFI_UNSUPPORTED;
>> +            goto out;
>> +    }
>> +
>> +    ret = check_node_type(controller_handle);
>> +
>> +    r = EFI_CALL(systab.boottime->close_protocol(
>> +                            controller_handle, bp->ops->protocol,
>> +                            this->driver_binding_handle,
>> +                            controller_handle));
>> +    if (r != EFI_SUCCESS)
>> +            ret = EFI_UNSUPPORTED;
>> +out:
>> +    return EFI_EXIT(ret);
>> +}
>> +
>> +/*
>> + * Create child controllers and attach driver.
>> + *
>> + * @this                    driver binding protocol
>> + * @controller_handle               handle of the controller
>> + * @remaining_device_path   path specifying the child controller
>> + * @return                  status code
>> + */
>> +static efi_status_t EFIAPI efi_uc_start(
>> +            struct efi_driver_binding_protocol *this,
>> +            efi_handle_t controller_handle,
>> +            struct efi_device_path *remaining_device_path)
>> +{
>> +    efi_status_t r, ret;
>> +    void *interface = NULL;
>> +    struct efi_driver_binding_extended_protocol *bp =
>> +                    (struct efi_driver_binding_extended_protocol *)this;
>> +
>> +    EFI_ENTRY("%p, %pUl, %ls", this, controller_handle,
>> +              efi_dp_str(remaining_device_path));
>> +
>> +    /* Attach driver to controller */
>> +    ret = EFI_CALL(systab.boottime->open_protocol(
>> +                    controller_handle, bp->ops->protocol,
>> +                    &interface, this->driver_binding_handle,
>> +                    controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER));
>> +    switch (ret) {
>> +    case EFI_ACCESS_DENIED:
>> +    case EFI_ALREADY_STARTED:
>> +            goto out;
>> +    case EFI_SUCCESS:
>> +            break;
>> +    default:
>> +            ret =  EFI_UNSUPPORTED;
>> +            goto out;
>> +    }
>> +    ret = check_node_type(controller_handle);
>> +    if (ret != EFI_SUCCESS) {
>> +            r = EFI_CALL(systab.boottime->close_protocol(
>> +                            controller_handle, bp->ops->protocol,
>> +                            this->driver_binding_handle,
>> +                            controller_handle));
>> +            if (r != EFI_SUCCESS)
>> +                    EFI_PRINT("Failure to close handle\n");
>> +            goto out;
>> +    }
>> +
>> +    /* TODO: driver specific stuff */
>> +    bp->ops->bind(controller_handle, interface);
>> +
>> +out:
>> +    return EFI_EXIT(ret);
>> +}
>> +
>> +/*
>> + * Remove a single child controller from the parent controller.
>> + *
>> + * @controller_handle       parent controller
>> + * @child_handle    child controller
>> + * @return          status code
>> + */
>> +static efi_status_t disconnect_child(efi_handle_t controller_handle,
>> +                                 efi_handle_t child_handle)
>> +{
>> +    efi_status_t ret;
>> +    efi_guid_t *guid_controller = NULL;
>> +    efi_guid_t *guid_child_controller = NULL;
>> +
>> +    ret = EFI_CALL(systab.boottime->close_protocol(
>> +                            controller_handle, guid_controller,
>> +                            child_handle, child_handle));
>> +    if (ret != EFI_SUCCESS) {
>> +            EFI_PRINT("Cannot close protocol\n");
>> +            return ret;
>> +    }
>> +    ret = EFI_CALL(systab.boottime->uninstall_protocol_interface(
>> +                            child_handle, guid_child_controller, NULL));
>> +    if (ret != EFI_SUCCESS) {
>> +            EFI_PRINT("Cannot uninstall protocol interface\n");
>> +            return ret;
>> +    }
>> +    return ret;
>> +}
>> +
>> +/*
>> + * Remove child controllers and disconnect the controller.
>> + *
>> + * @this                    driver binding protocol
>> + * @controller_handle               handle of the controller
>> + * @number_of_children              number of child controllers to remove
>> + * @child_handle_buffer             handles of the child controllers to 
>> remove
>> + * @return                  status code
>> + */
>> +static efi_status_t EFIAPI efi_uc_stop(
>> +            struct efi_driver_binding_protocol *this,
>> +            efi_handle_t controller_handle,
>> +            size_t number_of_children,
>> +            efi_handle_t *child_handle_buffer)
>> +{
>> +    efi_status_t ret;
>> +    efi_uintn_t count;
>> +    struct efi_open_protocol_info_entry *entry_buffer;
>> +    efi_guid_t *guid_controller = NULL;
>> +
>> +    EFI_ENTRY("%p, %pUl, %zu, %p", this, controller_handle,
>> +              number_of_children, child_handle_buffer);
>> +
>> +    /* Destroy provided child controllers */
>> +    if (number_of_children) {
>> +            efi_uintn_t i;
>> +
>> +            for (i = 0; i < number_of_children; ++i) {
>> +                    ret = disconnect_child(controller_handle,
>> +                                           child_handle_buffer[i]);
>> +                    if (ret != EFI_SUCCESS)
>> +                            return ret;
>> +            }
>> +            return EFI_SUCCESS;
>> +    }
>> +
>> +    /* Destroy all children */
>> +    ret = EFI_CALL(systab.boottime->open_protocol_information(
>> +                                    controller_handle, guid_controller,
>> +                                    &entry_buffer, &count));
>> +    if (ret != EFI_SUCCESS)
>> +            goto out;
>> +    while (count) {
>> +            if (entry_buffer[--count].attributes &
>> +                EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) {
>> +                    ret = disconnect_child(
>> +                                    controller_handle,
>> +                                    entry_buffer[count].agent_handle);
>> +                    if (ret != EFI_SUCCESS)
>> +                            goto out;
>> +            }
>> +    }
>> +    ret = EFI_CALL(systab.boottime->free_pool(entry_buffer));
>> +    if (ret != EFI_SUCCESS)
>> +            printf("%s(%u) %s: ERROR: Cannot free pool\n",
>> +                   __FILE__, __LINE__, __func__);
>> +
>> +    /* Detach driver from controller */
>> +    ret = EFI_CALL(systab.boottime->close_protocol(
>> +                    controller_handle, guid_controller,
>> +                    this->driver_binding_handle, controller_handle));
>> +out:
>> +    return EFI_EXIT(ret);
>> +}
>> +
>> +static efi_status_t efi_add_driver(struct driver *drv)
>> +{
>> +    efi_status_t ret;
>> +    const struct efi_driver_ops *ops = drv->ops;
>> +    struct efi_driver_binding_extended_protocol *bp;
>> +
>> +    debug("EFI: Adding driver '%s'\n", drv->name);
>> +    if (!ops->protocol) {
>> +            printf("EFI: ERROR: protocol GUID missing for driver '%s'\n",
>> +                   drv->name);
>> +            return EFI_INVALID_PARAMETER;
>> +    }
>> +    bp = calloc(1, sizeof(struct efi_driver_binding_extended_protocol));
>> +    if (!bp)
>> +            return EFI_OUT_OF_RESOURCES;
>> +
>> +    bp->bp.supported = efi_uc_supported;
>> +    bp->bp.start = efi_uc_start;
>> +    bp->bp.stop = efi_uc_stop;
>> +    bp->bp.version = 0xffffffff;
>> +    bp->ops = drv->ops;
>> +
>> +    ret = efi_create_handle(&bp->bp.driver_binding_handle);
>> +    if (ret != EFI_SUCCESS) {
>> +            free(bp);
>> +            goto out;
>> +    }
>> +    bp->bp.image_handle = bp->bp.driver_binding_handle;
>> +    ret = efi_add_protocol(bp->bp.driver_binding_handle,
>> +                           &efi_guid_driver_binding_protocol, bp);
>> +    if (ret != EFI_SUCCESS) {
>> +            efi_delete_handle(bp->bp.driver_binding_handle);
>> +            free(bp);
>> +            goto out;
>> +    }
>> +out:
>> +    return ret;
>> +}
>> +
>> +/*
>> + * Initialize the EFI drivers.
>> + * Called by board_init_r().
> 
> Hello Alex,
> 
> in a chat you asked why this is not called in efi_init_obj_list() after
> entering the bootefi command.
> 
> My architectural perspective is that in future we will create the EFI
> handles from the device tree in parallel to creating the udevices and
> use ConnectController to install the EFI drivers (e.g. for the simple
> network protocol in the case of network interfaces). This is only
> possible if the EFI uclass exists before udevices are created.

I'm not 100% sure that's the right direction yet, let's just leave it in
bootefi for now.


Alex
_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
https://lists.denx.de/listinfo/u-boot

Reply via email to