[U-Boot] [PATCH v2 16/18] efi_driver: EFI block driver
Alexander Graf
agraf at suse.de
Fri Jan 19 17:03:40 UTC 2018
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.glpk at 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
More information about the U-Boot
mailing list