1f739fcd8STom Rini // SPDX-License-Identifier: GPL-2.0+ 205ef48a2SHeinrich Schuchardt /* 305ef48a2SHeinrich Schuchardt * EFI block driver 405ef48a2SHeinrich Schuchardt * 505ef48a2SHeinrich Schuchardt * Copyright (c) 2017 Heinrich Schuchardt 605ef48a2SHeinrich Schuchardt * 705ef48a2SHeinrich Schuchardt * The EFI uclass creates a handle for this driver and installs the 805ef48a2SHeinrich Schuchardt * driver binding protocol on it. 905ef48a2SHeinrich Schuchardt * 1005ef48a2SHeinrich Schuchardt * The EFI block driver binds to controllers implementing the block io 1105ef48a2SHeinrich Schuchardt * protocol. 1205ef48a2SHeinrich Schuchardt * 1305ef48a2SHeinrich Schuchardt * When the bind function of the EFI block driver is called it creates a 1405ef48a2SHeinrich Schuchardt * new U-Boot block device. It installs child handles for all partitions and 1505ef48a2SHeinrich Schuchardt * installs the simple file protocol on these. 1605ef48a2SHeinrich Schuchardt * 1705ef48a2SHeinrich Schuchardt * The read and write functions of the EFI block driver delegate calls to the 1805ef48a2SHeinrich Schuchardt * controller that it is bound to. 1905ef48a2SHeinrich Schuchardt * 2005ef48a2SHeinrich Schuchardt * A usage example is as following: 2105ef48a2SHeinrich Schuchardt * 2205ef48a2SHeinrich Schuchardt * U-Boot loads the iPXE snp.efi executable. iPXE connects an iSCSI drive and 2305ef48a2SHeinrich Schuchardt * exposes a handle with the block IO protocol. It calls ConnectController. 2405ef48a2SHeinrich Schuchardt * 2505ef48a2SHeinrich Schuchardt * Now the EFI block driver installs the partitions with the simple file 2605ef48a2SHeinrich Schuchardt * protocol. 2705ef48a2SHeinrich Schuchardt * 2805ef48a2SHeinrich Schuchardt * iPXE uses the simple file protocol to load Grub or the Linux Kernel. 2905ef48a2SHeinrich Schuchardt */ 3005ef48a2SHeinrich Schuchardt 3105ef48a2SHeinrich Schuchardt #include <efi_driver.h> 3205ef48a2SHeinrich Schuchardt #include <dm/device-internal.h> 3305ef48a2SHeinrich Schuchardt #include <dm/root.h> 3405ef48a2SHeinrich Schuchardt 3505ef48a2SHeinrich Schuchardt /* 3605ef48a2SHeinrich Schuchardt * EFI attributes of the udevice handled by this driver. 3705ef48a2SHeinrich Schuchardt * 3805ef48a2SHeinrich Schuchardt * handle handle of the controller on which this driver is installed 3905ef48a2SHeinrich Schuchardt * io block io protocol proxied by this driver 4005ef48a2SHeinrich Schuchardt */ 41*f26ce03bSBin Meng struct efi_blk_platdata { 4205ef48a2SHeinrich Schuchardt efi_handle_t handle; 4305ef48a2SHeinrich Schuchardt struct efi_block_io *io; 4405ef48a2SHeinrich Schuchardt }; 4505ef48a2SHeinrich Schuchardt 4605ef48a2SHeinrich Schuchardt /* 4705ef48a2SHeinrich Schuchardt * Read from block device 4805ef48a2SHeinrich Schuchardt * 4905ef48a2SHeinrich Schuchardt * @dev device 5005ef48a2SHeinrich Schuchardt * @blknr first block to be read 5105ef48a2SHeinrich Schuchardt * @blkcnt number of blocks to read 5205ef48a2SHeinrich Schuchardt * @buffer output buffer 5305ef48a2SHeinrich Schuchardt * @return number of blocks transferred 5405ef48a2SHeinrich Schuchardt */ 5505ef48a2SHeinrich Schuchardt static ulong efi_bl_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, 5605ef48a2SHeinrich Schuchardt void *buffer) 5705ef48a2SHeinrich Schuchardt { 58*f26ce03bSBin Meng struct efi_blk_platdata *platdata = dev_get_platdata(dev); 59*f26ce03bSBin Meng struct efi_block_io *io = platdata->io; 6005ef48a2SHeinrich Schuchardt efi_status_t ret; 6105ef48a2SHeinrich Schuchardt 6205ef48a2SHeinrich Schuchardt EFI_PRINT("%s: read '%s', from block " LBAFU ", " LBAFU " blocks\n", 6305ef48a2SHeinrich Schuchardt __func__, dev->name, blknr, blkcnt); 6405ef48a2SHeinrich Schuchardt ret = EFI_CALL(io->read_blocks( 6505ef48a2SHeinrich Schuchardt io, io->media->media_id, (u64)blknr, 6605ef48a2SHeinrich Schuchardt (efi_uintn_t)blkcnt * 6705ef48a2SHeinrich Schuchardt (efi_uintn_t)io->media->block_size, buffer)); 6805ef48a2SHeinrich Schuchardt EFI_PRINT("%s: r = %u\n", __func__, 6905ef48a2SHeinrich Schuchardt (unsigned int)(ret & ~EFI_ERROR_MASK)); 7005ef48a2SHeinrich Schuchardt if (ret != EFI_SUCCESS) 7105ef48a2SHeinrich Schuchardt return 0; 7205ef48a2SHeinrich Schuchardt return blkcnt; 7305ef48a2SHeinrich Schuchardt } 7405ef48a2SHeinrich Schuchardt 7505ef48a2SHeinrich Schuchardt /* 7605ef48a2SHeinrich Schuchardt * Write to block device 7705ef48a2SHeinrich Schuchardt * 7805ef48a2SHeinrich Schuchardt * @dev device 7905ef48a2SHeinrich Schuchardt * @blknr first block to be write 8005ef48a2SHeinrich Schuchardt * @blkcnt number of blocks to write 8105ef48a2SHeinrich Schuchardt * @buffer input buffer 8205ef48a2SHeinrich Schuchardt * @return number of blocks transferred 8305ef48a2SHeinrich Schuchardt */ 8405ef48a2SHeinrich Schuchardt static ulong efi_bl_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, 8505ef48a2SHeinrich Schuchardt const void *buffer) 8605ef48a2SHeinrich Schuchardt { 87*f26ce03bSBin Meng struct efi_blk_platdata *platdata = dev_get_platdata(dev); 88*f26ce03bSBin Meng struct efi_block_io *io = platdata->io; 8905ef48a2SHeinrich Schuchardt efi_status_t ret; 9005ef48a2SHeinrich Schuchardt 9105ef48a2SHeinrich Schuchardt EFI_PRINT("%s: write '%s', from block " LBAFU ", " LBAFU " blocks\n", 9205ef48a2SHeinrich Schuchardt __func__, dev->name, blknr, blkcnt); 9305ef48a2SHeinrich Schuchardt ret = EFI_CALL(io->write_blocks( 9405ef48a2SHeinrich Schuchardt io, io->media->media_id, (u64)blknr, 9505ef48a2SHeinrich Schuchardt (efi_uintn_t)blkcnt * 9605ef48a2SHeinrich Schuchardt (efi_uintn_t)io->media->block_size, 9705ef48a2SHeinrich Schuchardt (void *)buffer)); 9805ef48a2SHeinrich Schuchardt EFI_PRINT("%s: r = %u\n", __func__, 9905ef48a2SHeinrich Schuchardt (unsigned int)(ret & ~EFI_ERROR_MASK)); 10005ef48a2SHeinrich Schuchardt if (ret != EFI_SUCCESS) 10105ef48a2SHeinrich Schuchardt return 0; 10205ef48a2SHeinrich Schuchardt return blkcnt; 10305ef48a2SHeinrich Schuchardt } 10405ef48a2SHeinrich Schuchardt 10505ef48a2SHeinrich Schuchardt /* 10605ef48a2SHeinrich Schuchardt * Create partions for the block device. 10705ef48a2SHeinrich Schuchardt * 10805ef48a2SHeinrich Schuchardt * @handle EFI handle of the block device 10905ef48a2SHeinrich Schuchardt * @dev udevice of the block device 11005ef48a2SHeinrich Schuchardt */ 11105ef48a2SHeinrich Schuchardt static int efi_bl_bind_partitions(efi_handle_t handle, struct udevice *dev) 11205ef48a2SHeinrich Schuchardt { 11305ef48a2SHeinrich Schuchardt struct blk_desc *desc; 11405ef48a2SHeinrich Schuchardt const char *if_typename; 11505ef48a2SHeinrich Schuchardt 11605ef48a2SHeinrich Schuchardt desc = dev_get_uclass_platdata(dev); 11705ef48a2SHeinrich Schuchardt if_typename = blk_get_if_type_name(desc->if_type); 11805ef48a2SHeinrich Schuchardt 11905ef48a2SHeinrich Schuchardt return efi_disk_create_partitions(handle, desc, if_typename, 12005ef48a2SHeinrich Schuchardt desc->devnum, dev->name); 12105ef48a2SHeinrich Schuchardt } 12205ef48a2SHeinrich Schuchardt 12305ef48a2SHeinrich Schuchardt /* 12405ef48a2SHeinrich Schuchardt * Create a block device for a handle 12505ef48a2SHeinrich Schuchardt * 12605ef48a2SHeinrich Schuchardt * @handle handle 12705ef48a2SHeinrich Schuchardt * @interface block io protocol 12805ef48a2SHeinrich Schuchardt * @return 0 = success 12905ef48a2SHeinrich Schuchardt */ 13005ef48a2SHeinrich Schuchardt static int efi_bl_bind(efi_handle_t handle, void *interface) 13105ef48a2SHeinrich Schuchardt { 13205ef48a2SHeinrich Schuchardt struct udevice *bdev, *parent = dm_root(); 13305ef48a2SHeinrich Schuchardt int ret, devnum; 13405ef48a2SHeinrich Schuchardt char *name; 13505ef48a2SHeinrich Schuchardt struct efi_object *obj = efi_search_obj(handle); 13605ef48a2SHeinrich Schuchardt struct efi_block_io *io = interface; 13705ef48a2SHeinrich Schuchardt int disks; 138*f26ce03bSBin Meng struct efi_blk_platdata *platdata; 13905ef48a2SHeinrich Schuchardt 14005ef48a2SHeinrich Schuchardt EFI_PRINT("%s: handle %p, interface %p\n", __func__, handle, io); 14105ef48a2SHeinrich Schuchardt 14205ef48a2SHeinrich Schuchardt if (!obj) 14305ef48a2SHeinrich Schuchardt return -ENOENT; 14405ef48a2SHeinrich Schuchardt 14505ef48a2SHeinrich Schuchardt devnum = blk_find_max_devnum(IF_TYPE_EFI); 14605ef48a2SHeinrich Schuchardt if (devnum == -ENODEV) 14705ef48a2SHeinrich Schuchardt devnum = 0; 14805ef48a2SHeinrich Schuchardt else if (devnum < 0) 14905ef48a2SHeinrich Schuchardt return devnum; 15005ef48a2SHeinrich Schuchardt 15105ef48a2SHeinrich Schuchardt name = calloc(1, 18); /* strlen("efiblk#2147483648") + 1 */ 15205ef48a2SHeinrich Schuchardt if (!name) 15305ef48a2SHeinrich Schuchardt return -ENOMEM; 15405ef48a2SHeinrich Schuchardt sprintf(name, "efiblk#%d", devnum); 15505ef48a2SHeinrich Schuchardt 15605ef48a2SHeinrich Schuchardt /* Create driver model udevice for the EFI block io device */ 15705ef48a2SHeinrich Schuchardt ret = blk_create_device(parent, "efi_blk", name, IF_TYPE_EFI, devnum, 15805ef48a2SHeinrich Schuchardt io->media->block_size, 15905ef48a2SHeinrich Schuchardt (lbaint_t)io->media->last_block, &bdev); 16005ef48a2SHeinrich Schuchardt if (ret) 16105ef48a2SHeinrich Schuchardt return ret; 16205ef48a2SHeinrich Schuchardt if (!bdev) 16305ef48a2SHeinrich Schuchardt return -ENOENT; 164df76431bSHeinrich Schuchardt /* Set the DM_FLAG_NAME_ALLOCED flag to avoid a memory leak */ 165df76431bSHeinrich Schuchardt device_set_name_alloced(bdev); 166*f26ce03bSBin Meng 167*f26ce03bSBin Meng platdata = dev_get_platdata(bdev); 168*f26ce03bSBin Meng platdata->handle = handle; 169*f26ce03bSBin Meng platdata->io = interface; 170*f26ce03bSBin Meng 17105ef48a2SHeinrich Schuchardt ret = device_probe(bdev); 17205ef48a2SHeinrich Schuchardt if (ret) 17305ef48a2SHeinrich Schuchardt return ret; 17405ef48a2SHeinrich Schuchardt EFI_PRINT("%s: block device '%s' created\n", __func__, bdev->name); 17505ef48a2SHeinrich Schuchardt 17605ef48a2SHeinrich Schuchardt ret = blk_prepare_device(bdev); 17705ef48a2SHeinrich Schuchardt 17805ef48a2SHeinrich Schuchardt /* Create handles for the partions of the block device */ 17905ef48a2SHeinrich Schuchardt disks = efi_bl_bind_partitions(handle, bdev); 18005ef48a2SHeinrich Schuchardt EFI_PRINT("Found %d partitions\n", disks); 18105ef48a2SHeinrich Schuchardt 18205ef48a2SHeinrich Schuchardt return 0; 18305ef48a2SHeinrich Schuchardt } 18405ef48a2SHeinrich Schuchardt 18505ef48a2SHeinrich Schuchardt /* Block device driver operators */ 18605ef48a2SHeinrich Schuchardt static const struct blk_ops efi_blk_ops = { 18705ef48a2SHeinrich Schuchardt .read = efi_bl_read, 18805ef48a2SHeinrich Schuchardt .write = efi_bl_write, 18905ef48a2SHeinrich Schuchardt }; 19005ef48a2SHeinrich Schuchardt 19105ef48a2SHeinrich Schuchardt /* Identify as block device driver */ 19205ef48a2SHeinrich Schuchardt U_BOOT_DRIVER(efi_blk) = { 19305ef48a2SHeinrich Schuchardt .name = "efi_blk", 19405ef48a2SHeinrich Schuchardt .id = UCLASS_BLK, 19505ef48a2SHeinrich Schuchardt .ops = &efi_blk_ops, 196*f26ce03bSBin Meng .platdata_auto_alloc_size = sizeof(struct efi_blk_platdata), 19705ef48a2SHeinrich Schuchardt }; 19805ef48a2SHeinrich Schuchardt 19905ef48a2SHeinrich Schuchardt /* EFI driver operators */ 20005ef48a2SHeinrich Schuchardt static const struct efi_driver_ops driver_ops = { 20105ef48a2SHeinrich Schuchardt .protocol = &efi_block_io_guid, 20205ef48a2SHeinrich Schuchardt .child_protocol = &efi_block_io_guid, 20305ef48a2SHeinrich Schuchardt .bind = efi_bl_bind, 20405ef48a2SHeinrich Schuchardt }; 20505ef48a2SHeinrich Schuchardt 20605ef48a2SHeinrich Schuchardt /* Identify as EFI driver */ 20705ef48a2SHeinrich Schuchardt U_BOOT_DRIVER(efi_block) = { 20805ef48a2SHeinrich Schuchardt .name = "EFI block driver", 20905ef48a2SHeinrich Schuchardt .id = UCLASS_EFI, 21005ef48a2SHeinrich Schuchardt .ops = &driver_ops, 21105ef48a2SHeinrich Schuchardt }; 212