On 19.01.18 20:24, 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 partitions 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> > --- > v3 > Initalize EFI uclass from bootefi command. > Fix typos. > v2 > Print to console only in debug mode. > Provide more comments. > Add commit message. > --- > cmd/bootefi.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/cmd/bootefi.c b/cmd/bootefi.c > index 78ff109835..f16d56eb59 100644 > --- a/cmd/bootefi.c > +++ b/cmd/bootefi.c > @@ -32,6 +32,9 @@ static void efi_init_obj_list(void) > { > efi_obj_list_initalized = 1; > > + /* Initialize EFI driver uclass */ > + efi_driver_init(); > + > efi_console_register(); > #ifdef CONFIG_PARTITIONS > efi_disk_register(); > 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 035b04fef4..8b11f30edf 100644 > --- a/include/efi_loader.h > +++ b/include/efi_loader.h > @@ -271,6 +271,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..f614560abc > --- /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 partitions 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_partitions(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++;
Can you store this in the "EFI block driver" instance? Maybe you want to pass a pointer to that to the bind function anyway? > + sprintf(name, "efi#%d", devnum); > + /* Create U-Boot DM device for the EFI block backing device */ > + 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; Can you instead create a priv struct that contains the pointer to interface as a member? Then use that instead of platdata. Platdata really is supposed to store information that lives in device tree these days. Parameters to your device basically. > + obj->dev = bdev; Please integrate my patches to remove all references to obj->dev. > + > + ret = blk_prepare_device(bdev); > + /* Also create EFI devices for all partitions on top of the EFI block device */ > + disks = efi_bl_bind_partitions(handle); > + EFI_PRINT("Found %d partitions\n", disks); > + > + return 0; Alex _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot