uboot/lib/efi_driver/efi_block_device.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 *  EFI block driver
   4 *
   5 *  Copyright (c) 2017 Heinrich Schuchardt
   6 *
   7 * The EFI uclass creates a handle for this driver and installs the
   8 * driver binding protocol on it.
   9 *
  10 * The EFI block driver binds to controllers implementing the block io
  11 * protocol.
  12 *
  13 * When the bind function of the EFI block driver is called it creates a
  14 * new U-Boot block device. It installs child handles for all partitions and
  15 * installs the simple file protocol on these.
  16 *
  17 * The read and write functions of the EFI block driver delegate calls to the
  18 * controller that it is bound to.
  19 *
  20 * A usage example is as following:
  21 *
  22 * U-Boot loads the iPXE snp.efi executable. iPXE connects an iSCSI drive and
  23 * exposes a handle with the block IO protocol. It calls ConnectController.
  24 *
  25 * Now the EFI block driver installs the partitions with the simple file
  26 * protocol.
  27 *
  28 * iPXE uses the simple file protocol to load Grub or the Linux Kernel.
  29 */
  30
  31#include <efi_driver.h>
  32#include <dm/device-internal.h>
  33#include <dm/root.h>
  34
  35/*
  36 * EFI attributes of the udevice handled by this driver.
  37 *
  38 * handle       handle of the controller on which this driver is installed
  39 * io           block io protocol proxied by this driver
  40 */
  41struct efi_blk_platdata {
  42        efi_handle_t            handle;
  43        struct efi_block_io     *io;
  44};
  45
  46/*
  47 * Read from block device
  48 *
  49 * @dev         device
  50 * @blknr       first block to be read
  51 * @blkcnt      number of blocks to read
  52 * @buffer      output buffer
  53 * @return      number of blocks transferred
  54 */
  55static ulong efi_bl_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
  56                         void *buffer)
  57{
  58        struct efi_blk_platdata *platdata = dev_get_platdata(dev);
  59        struct efi_block_io *io = platdata->io;
  60        efi_status_t ret;
  61
  62        EFI_PRINT("%s: read '%s', from block " LBAFU ", " LBAFU " blocks\n",
  63                  __func__, dev->name, blknr, blkcnt);
  64        ret = EFI_CALL(io->read_blocks(
  65                                io, io->media->media_id, (u64)blknr,
  66                                (efi_uintn_t)blkcnt *
  67                                (efi_uintn_t)io->media->block_size, buffer));
  68        EFI_PRINT("%s: r = %u\n", __func__,
  69                  (unsigned int)(ret & ~EFI_ERROR_MASK));
  70        if (ret != EFI_SUCCESS)
  71                return 0;
  72        return blkcnt;
  73}
  74
  75/*
  76 * Write to block device
  77 *
  78 * @dev         device
  79 * @blknr       first block to be write
  80 * @blkcnt      number of blocks to write
  81 * @buffer      input buffer
  82 * @return      number of blocks transferred
  83 */
  84static ulong efi_bl_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
  85                          const void *buffer)
  86{
  87        struct efi_blk_platdata *platdata = dev_get_platdata(dev);
  88        struct efi_block_io *io = platdata->io;
  89        efi_status_t ret;
  90
  91        EFI_PRINT("%s: write '%s', from block " LBAFU ", " LBAFU " blocks\n",
  92                  __func__, dev->name, blknr, blkcnt);
  93        ret = EFI_CALL(io->write_blocks(
  94                                io, io->media->media_id, (u64)blknr,
  95                                (efi_uintn_t)blkcnt *
  96                                (efi_uintn_t)io->media->block_size,
  97                                (void *)buffer));
  98        EFI_PRINT("%s: r = %u\n", __func__,
  99                  (unsigned int)(ret & ~EFI_ERROR_MASK));
 100        if (ret != EFI_SUCCESS)
 101                return 0;
 102        return blkcnt;
 103}
 104
 105/*
 106 * Create partions for the block device.
 107 *
 108 * @handle      EFI handle of the block device
 109 * @dev         udevice of the block device
 110 */
 111static int efi_bl_bind_partitions(efi_handle_t handle, struct udevice *dev)
 112{
 113        struct blk_desc *desc;
 114        const char *if_typename;
 115
 116        desc = dev_get_uclass_platdata(dev);
 117        if_typename = blk_get_if_type_name(desc->if_type);
 118
 119        return efi_disk_create_partitions(handle, desc, if_typename,
 120                                          desc->devnum, dev->name);
 121}
 122
 123/*
 124 * Create a block device for a handle
 125 *
 126 * @handle      handle
 127 * @interface   block io protocol
 128 * @return      0 = success
 129 */
 130static int efi_bl_bind(efi_handle_t handle, void *interface)
 131{
 132        struct udevice *bdev, *parent = dm_root();
 133        int ret, devnum;
 134        char *name;
 135        struct efi_object *obj = efi_search_obj(handle);
 136        struct efi_block_io *io = interface;
 137        int disks;
 138        struct efi_blk_platdata *platdata;
 139
 140        EFI_PRINT("%s: handle %p, interface %p\n", __func__, handle, io);
 141
 142        if (!obj)
 143                return -ENOENT;
 144
 145        devnum = blk_find_max_devnum(IF_TYPE_EFI);
 146        if (devnum == -ENODEV)
 147                devnum = 0;
 148        else if (devnum < 0)
 149                return devnum;
 150
 151        name = calloc(1, 18); /* strlen("efiblk#2147483648") + 1 */
 152        if (!name)
 153                return -ENOMEM;
 154        sprintf(name, "efiblk#%d", devnum);
 155
 156        /* Create driver model udevice for the EFI block io device */
 157        ret = blk_create_device(parent, "efi_blk", name, IF_TYPE_EFI, devnum,
 158                                io->media->block_size,
 159                                (lbaint_t)io->media->last_block, &bdev);
 160        if (ret)
 161                return ret;
 162        if (!bdev)
 163                return -ENOENT;
 164        /* Set the DM_FLAG_NAME_ALLOCED flag to avoid a memory leak */
 165        device_set_name_alloced(bdev);
 166
 167        platdata = dev_get_platdata(bdev);
 168        platdata->handle = handle;
 169        platdata->io = interface;
 170
 171        ret = device_probe(bdev);
 172        if (ret)
 173                return ret;
 174        EFI_PRINT("%s: block device '%s' created\n", __func__, bdev->name);
 175
 176        /* Create handles for the partions of the block device */
 177        disks = efi_bl_bind_partitions(handle, bdev);
 178        EFI_PRINT("Found %d partitions\n", disks);
 179
 180        return 0;
 181}
 182
 183/* Block device driver operators */
 184static const struct blk_ops efi_blk_ops = {
 185        .read   = efi_bl_read,
 186        .write  = efi_bl_write,
 187};
 188
 189/* Identify as block device driver */
 190U_BOOT_DRIVER(efi_blk) = {
 191        .name                   = "efi_blk",
 192        .id                     = UCLASS_BLK,
 193        .ops                    = &efi_blk_ops,
 194        .platdata_auto_alloc_size = sizeof(struct efi_blk_platdata),
 195};
 196
 197/* EFI driver operators */
 198static const struct efi_driver_ops driver_ops = {
 199        .protocol       = &efi_block_io_guid,
 200        .child_protocol = &efi_block_io_guid,
 201        .bind           = efi_bl_bind,
 202};
 203
 204/* Identify as EFI driver */
 205U_BOOT_DRIVER(efi_block) = {
 206        .name           = "EFI block driver",
 207        .id             = UCLASS_EFI,
 208        .ops            = &driver_ops,
 209};
 210