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