Merge tag '2019.01-next' of https://github.com/mbgg/u-boot
[oweals/u-boot.git] / lib / efi_driver / efi_block_device.c
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  */
41 struct 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  */
55 static 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  */
84 static 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  */
111 static 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  */
130 static 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 */
184 static 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 */
190 U_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 */
198 static 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 */
205 U_BOOT_DRIVER(efi_block) = {
206         .name           = "EFI block driver",
207         .id             = UCLASS_EFI,
208         .ops            = &driver_ops,
209 };