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