blob: 070747de5156bb6df8eba25dd0184b9228d3f3fc [file] [log] [blame]
Tom Rini70df9d62018-05-07 17:02:21 -04001// SPDX-License-Identifier: GPL-2.0+
Heinrich Schuchardt11206f42018-01-21 19:29:30 +01002/*
3 * EFI block driver
4 *
5 * Copyright (c) 2017 Heinrich Schuchardt
6 *
Heinrich Schuchardt11206f42018-01-21 19:29:30 +01007 * 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
Heinrich Schuchardt955a3212025-01-16 20:26:59 +010031#define LOG_CATEGORY LOGC_EFI
32
Simon Glass655306c2020-05-10 11:39:58 -060033#include <blk.h>
Simon Glassf6977c12020-07-19 10:15:43 -060034#include <dm.h>
Heinrich Schuchardt11206f42018-01-21 19:29:30 +010035#include <efi_driver.h>
Simon Glass9bc15642020-02-03 07:36:16 -070036#include <malloc.h>
Heinrich Schuchardt11206f42018-01-21 19:29:30 +010037#include <dm/device-internal.h>
Heinrich Schuchardt41ae6f02025-02-15 16:22:06 +010038#include <dm/lists.h>
Heinrich Schuchardt11206f42018-01-21 19:29:30 +010039#include <dm/root.h>
AKASHI Takahiro2381f2e2022-04-19 10:05:12 +090040#include <dm/tag.h>
Heinrich Schuchardt41ae6f02025-02-15 16:22:06 +010041#include <dm/uclass-internal.h>
Heinrich Schuchardt11206f42018-01-21 19:29:30 +010042
Heinrich Schuchardt35679a92022-10-04 18:53:34 +020043/**
44 * struct efi_blk_plat - attributes of a block device
Heinrich Schuchardt11206f42018-01-21 19:29:30 +010045 *
Heinrich Schuchardt35679a92022-10-04 18:53:34 +020046 * @handle: handle of the controller on which this driver is installed
47 * @io: block io protocol proxied by this driver
Heinrich Schuchardt11206f42018-01-21 19:29:30 +010048 */
Simon Glassb75b15b2020-12-03 16:55:23 -070049struct efi_blk_plat {
Heinrich Schuchardt11206f42018-01-21 19:29:30 +010050 efi_handle_t handle;
51 struct efi_block_io *io;
52};
53
Heinrich Schuchardt6492dad2019-07-14 11:52:33 +020054/**
Heinrich Schuchardt35679a92022-10-04 18:53:34 +020055 * efi_bl_read() - read from block device
Heinrich Schuchardt11206f42018-01-21 19:29:30 +010056 *
Heinrich Schuchardt6492dad2019-07-14 11:52:33 +020057 * @dev: device
58 * @blknr: first block to be read
59 * @blkcnt: number of blocks to read
60 * @buffer: output buffer
61 * Return: number of blocks transferred
Heinrich Schuchardt11206f42018-01-21 19:29:30 +010062 */
63static ulong efi_bl_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
64 void *buffer)
65{
Simon Glassb75b15b2020-12-03 16:55:23 -070066 struct efi_blk_plat *plat = dev_get_plat(dev);
Simon Glass71fa5b42020-12-03 16:55:18 -070067 struct efi_block_io *io = plat->io;
Heinrich Schuchardt11206f42018-01-21 19:29:30 +010068 efi_status_t ret;
69
70 EFI_PRINT("%s: read '%s', from block " LBAFU ", " LBAFU " blocks\n",
71 __func__, dev->name, blknr, blkcnt);
72 ret = EFI_CALL(io->read_blocks(
73 io, io->media->media_id, (u64)blknr,
74 (efi_uintn_t)blkcnt *
75 (efi_uintn_t)io->media->block_size, buffer));
76 EFI_PRINT("%s: r = %u\n", __func__,
77 (unsigned int)(ret & ~EFI_ERROR_MASK));
78 if (ret != EFI_SUCCESS)
79 return 0;
80 return blkcnt;
81}
82
Heinrich Schuchardt6492dad2019-07-14 11:52:33 +020083/**
Heinrich Schuchardt35679a92022-10-04 18:53:34 +020084 * efi_bl_write() - write to block device
Heinrich Schuchardt11206f42018-01-21 19:29:30 +010085 *
Heinrich Schuchardt6492dad2019-07-14 11:52:33 +020086 * @dev: device
87 * @blknr: first block to be write
88 * @blkcnt: number of blocks to write
89 * @buffer: input buffer
90 * Return: number of blocks transferred
Heinrich Schuchardt11206f42018-01-21 19:29:30 +010091 */
92static ulong efi_bl_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
93 const void *buffer)
94{
Simon Glassb75b15b2020-12-03 16:55:23 -070095 struct efi_blk_plat *plat = dev_get_plat(dev);
Simon Glass71fa5b42020-12-03 16:55:18 -070096 struct efi_block_io *io = plat->io;
Heinrich Schuchardt11206f42018-01-21 19:29:30 +010097 efi_status_t ret;
98
99 EFI_PRINT("%s: write '%s', from block " LBAFU ", " LBAFU " blocks\n",
100 __func__, dev->name, blknr, blkcnt);
101 ret = EFI_CALL(io->write_blocks(
102 io, io->media->media_id, (u64)blknr,
103 (efi_uintn_t)blkcnt *
104 (efi_uintn_t)io->media->block_size,
105 (void *)buffer));
106 EFI_PRINT("%s: r = %u\n", __func__,
107 (unsigned int)(ret & ~EFI_ERROR_MASK));
108 if (ret != EFI_SUCCESS)
109 return 0;
110 return blkcnt;
111}
112
Heinrich Schuchardt6492dad2019-07-14 11:52:33 +0200113/**
Heinrich Schuchardt35679a92022-10-04 18:53:34 +0200114 * efi_bl_create_block_device() - create a block device for a handle
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100115 *
Heinrich Schuchardt6492dad2019-07-14 11:52:33 +0200116 * @handle: handle
117 * @interface: block io protocol
Heinrich Schuchardt3f712db2022-10-03 10:35:35 +0200118 * Return: status code
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100119 */
Heinrich Schuchardtcc00eb42022-10-04 16:19:30 +0200120static efi_status_t
121efi_bl_create_block_device(efi_handle_t handle, void *interface)
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100122{
Heinrich Schuchardt41ae6f02025-02-15 16:22:06 +0100123 struct udevice *bdev = NULL, *parent;
Heinrich Schuchardt3f712db2022-10-03 10:35:35 +0200124 efi_status_t ret;
Heinrich Schuchardt41ae6f02025-02-15 16:22:06 +0100125 int r;
Heinrich Schuchardt3f712db2022-10-03 10:35:35 +0200126 int devnum;
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100127 char *name;
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100128 struct efi_block_io *io = interface;
Simon Glassb75b15b2020-12-03 16:55:23 -0700129 struct efi_blk_plat *plat;
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100130
Heinrich Schuchardt41ae6f02025-02-15 16:22:06 +0100131 r = uclass_find_first_device(UCLASS_EFI_LOADER, &parent);
132 if (r)
133 return EFI_OUT_OF_RESOURCES;
134
Masahisa Kojima676c2742023-07-03 15:08:45 +0900135 devnum = blk_next_free_devnum(UCLASS_EFI_LOADER);
136 if (devnum < 0)
Heinrich Schuchardt3f712db2022-10-03 10:35:35 +0200137 return EFI_OUT_OF_RESOURCES;
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100138
139 name = calloc(1, 18); /* strlen("efiblk#2147483648") + 1 */
140 if (!name)
Heinrich Schuchardt3f712db2022-10-03 10:35:35 +0200141 return EFI_OUT_OF_RESOURCES;
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100142 sprintf(name, "efiblk#%d", devnum);
143
144 /* Create driver model udevice for the EFI block io device */
Heinrich Schuchardtda87af92024-10-18 03:30:14 +0200145 if (blk_create_devicef(parent, "efi_blk", name, UCLASS_EFI_LOADER,
146 devnum, io->media->block_size,
147 (lbaint_t)io->media->last_block, &bdev)) {
Heinrich Schuchardt3f712db2022-10-03 10:35:35 +0200148 ret = EFI_OUT_OF_RESOURCES;
149 free(name);
150 goto err;
151 }
Bin Meng91938632018-10-15 02:21:06 -0700152
Simon Glassfa20e932020-12-03 16:55:20 -0700153 plat = dev_get_plat(bdev);
Simon Glass71fa5b42020-12-03 16:55:18 -0700154 plat->handle = handle;
155 plat->io = interface;
Bin Meng91938632018-10-15 02:21:06 -0700156
Heinrich Schuchardt3f712db2022-10-03 10:35:35 +0200157 if (efi_link_dev(handle, bdev)) {
158 ret = EFI_OUT_OF_RESOURCES;
159 goto err;
160 }
AKASHI Takahiro2381f2e2022-04-19 10:05:12 +0900161
Heinrich Schuchardt3f712db2022-10-03 10:35:35 +0200162 if (device_probe(bdev)) {
163 ret = EFI_DEVICE_ERROR;
164 goto err;
165 }
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100166 EFI_PRINT("%s: block device '%s' created\n", __func__, bdev->name);
167
Heinrich Schuchardt3f712db2022-10-03 10:35:35 +0200168 return EFI_SUCCESS;
169
170err:
171 efi_unlink_dev(handle);
172 if (bdev)
173 device_unbind(bdev);
174
175 return ret;
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100176}
177
Heinrich Schuchardtcc00eb42022-10-04 16:19:30 +0200178/**
179 * efi_bl_bind() - bind to a block io protocol
180 *
Heinrich Schuchardtff1d50b2022-10-04 19:12:59 +0200181 * @this: driver binding protocol
Heinrich Schuchardtcc00eb42022-10-04 16:19:30 +0200182 * @handle: handle
183 * @interface: block io protocol
184 * Return: status code
185 */
Heinrich Schuchardtff1d50b2022-10-04 19:12:59 +0200186static efi_status_t efi_bl_bind(
187 struct efi_driver_binding_extended_protocol *this,
188 efi_handle_t handle, void *interface)
Heinrich Schuchardtcc00eb42022-10-04 16:19:30 +0200189{
190 efi_status_t ret = EFI_SUCCESS;
191 struct efi_object *obj = efi_search_obj(handle);
192
193 EFI_PRINT("%s: handle %p, interface %p\n", __func__, handle, interface);
194
195 if (!obj || !interface)
196 return EFI_INVALID_PARAMETER;
197
198 if (!handle->dev)
199 ret = efi_bl_create_block_device(handle, interface);
200
201 return ret;
202}
203
Heinrich Schuchardt6c5fd212022-10-05 11:28:47 +0200204/**
205 * efi_bl_init() - initialize block device driver
206 *
207 * @this: extended driver binding protocol
208 */
209static efi_status_t
210efi_bl_init(struct efi_driver_binding_extended_protocol *this)
211{
Heinrich Schuchardtda620cf2022-10-06 07:29:41 +0200212 int ret;
213
214 ret = event_register("efi_disk add", EVT_DM_POST_PROBE,
215 efi_disk_probe, this);
216 if (ret) {
217 log_err("Event registration for efi_disk add failed\n");
218 return EFI_OUT_OF_RESOURCES;
219 }
220
221 ret = event_register("efi_disk del", EVT_DM_PRE_REMOVE,
222 efi_disk_remove, this);
223 if (ret) {
224 log_err("Event registration for efi_disk del failed\n");
225 return EFI_OUT_OF_RESOURCES;
226 }
227
Heinrich Schuchardt6c5fd212022-10-05 11:28:47 +0200228 return EFI_SUCCESS;
229}
230
Heinrich Schuchardt41ae6f02025-02-15 16:22:06 +0100231/**
232 * efi_block_device_create() - create parent for EFI block devices
233 *
234 * Create a device that serves as parent for all block devices created via
235 * ConnectController().
236 *
237 * Return: 0 for success
238 */
239static int efi_block_device_create(void)
240{
241 int ret;
242 struct udevice *dev;
243
244 ret = device_bind_driver(gd->dm_root, "EFI block driver", "efi", &dev);
245
246 return ret;
247}
248
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100249/* Block device driver operators */
250static const struct blk_ops efi_blk_ops = {
251 .read = efi_bl_read,
252 .write = efi_bl_write,
253};
254
255/* Identify as block device driver */
256U_BOOT_DRIVER(efi_blk) = {
Heinrich Schuchardt35679a92022-10-04 18:53:34 +0200257 .name = "efi_blk",
258 .id = UCLASS_BLK,
259 .ops = &efi_blk_ops,
Simon Glassb75b15b2020-12-03 16:55:23 -0700260 .plat_auto = sizeof(struct efi_blk_plat),
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100261};
262
263/* EFI driver operators */
264static const struct efi_driver_ops driver_ops = {
265 .protocol = &efi_block_io_guid,
266 .child_protocol = &efi_block_io_guid,
Heinrich Schuchardt6c5fd212022-10-05 11:28:47 +0200267 .init = efi_bl_init,
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100268 .bind = efi_bl_bind,
269};
270
271/* Identify as EFI driver */
272U_BOOT_DRIVER(efi_block) = {
273 .name = "EFI block driver",
Simon Glass15c4d672021-12-04 08:56:30 -0700274 .id = UCLASS_EFI_LOADER,
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100275 .ops = &driver_ops,
276};
Heinrich Schuchardt41ae6f02025-02-15 16:22:06 +0100277
278EVENT_SPY_SIMPLE(EVT_LAST_STAGE_INIT, efi_block_device_create);