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