blob: c905c12abc2f5ef02fd18b662a3ba58b7a30cd11 [file] [log] [blame]
Tom Rinif739fcd2018-05-07 17:02:21 -04001// SPDX-License-Identifier: GPL-2.0+
Alexander Graf2a22d052016-03-04 01:10:02 +01002/*
3 * EFI application disk support
4 *
5 * Copyright (c) 2016 Alexander Graf
Alexander Graf2a22d052016-03-04 01:10:02 +01006 */
7
Heinrich Schuchardtaf457cf2020-07-17 20:33:05 +02008#define LOG_CATEGORY LOGC_EFI
9
Alexander Graf2a22d052016-03-04 01:10:02 +010010#include <common.h>
Simon Glass6dd9faf2016-05-01 13:52:32 -060011#include <blk.h>
Simon Glass487d7562016-05-14 14:03:05 -060012#include <dm.h>
Alexander Graf2a22d052016-03-04 01:10:02 +010013#include <efi_loader.h>
AKASHI Takahiro86740062019-10-07 14:59:38 +090014#include <fs.h>
Heinrich Schuchardtaf457cf2020-07-17 20:33:05 +020015#include <log.h>
Alexander Graf2a22d052016-03-04 01:10:02 +010016#include <part.h>
17#include <malloc.h>
18
Heinrich Schuchardt11078bb2020-03-19 15:16:31 +010019struct efi_system_partition efi_system_partition;
20
Heinrich Schuchardtdec88e42019-04-20 07:39:11 +020021const efi_guid_t efi_block_io_guid = EFI_BLOCK_IO_PROTOCOL_GUID;
Heinrich Schuchardtb9b0ea32021-02-02 17:53:14 +010022const efi_guid_t efi_system_partition_guid = PARTITION_SYSTEM_GUID;
Alexander Graf2a22d052016-03-04 01:10:02 +010023
Heinrich Schuchardtd39646a2018-09-26 05:27:56 +020024/**
25 * struct efi_disk_obj - EFI disk object
26 *
27 * @header: EFI object header
28 * @ops: EFI disk I/O protocol interface
29 * @ifname: interface name for block device
30 * @dev_index: device index of block device
31 * @media: block I/O media information
32 * @dp: device path to the block device
33 * @part: partition
34 * @volume: simple file system protocol of the partition
35 * @offset: offset into disk for simple partition
36 * @desc: internal block device descriptor
37 */
Alexander Graf2a22d052016-03-04 01:10:02 +010038struct efi_disk_obj {
Heinrich Schuchardtd39646a2018-09-26 05:27:56 +020039 struct efi_object header;
Alexander Graf2a22d052016-03-04 01:10:02 +010040 struct efi_block_io ops;
Alexander Graf2a22d052016-03-04 01:10:02 +010041 const char *ifname;
Alexander Graf2a22d052016-03-04 01:10:02 +010042 int dev_index;
Alexander Graf2a22d052016-03-04 01:10:02 +010043 struct efi_block_io_media media;
Rob Clark884bcf62017-09-13 18:05:31 -040044 struct efi_device_path *dp;
Rob Clark884bcf62017-09-13 18:05:31 -040045 unsigned int part;
Rob Clark2a920802017-09-13 18:05:34 -040046 struct efi_simple_file_system_protocol *volume;
Alexander Graf8c3df0b2016-04-11 16:16:18 +020047 lbaint_t offset;
Rob Clark884bcf62017-09-13 18:05:31 -040048 struct blk_desc *desc;
Alexander Graf2a22d052016-03-04 01:10:02 +010049};
50
Heinrich Schuchardtcda9b352019-09-05 20:13:46 +020051/**
52 * efi_disk_reset() - reset block device
53 *
54 * This function implements the Reset service of the EFI_BLOCK_IO_PROTOCOL.
55 *
56 * As U-Boot's block devices do not have a reset function simply return
57 * EFI_SUCCESS.
58 *
59 * See the Unified Extensible Firmware Interface (UEFI) specification for
60 * details.
61 *
62 * @this: pointer to the BLOCK_IO_PROTOCOL
63 * @extended_verification: extended verification
64 * Return: status code
65 */
Alexander Graf2a22d052016-03-04 01:10:02 +010066static efi_status_t EFIAPI efi_disk_reset(struct efi_block_io *this,
67 char extended_verification)
68{
69 EFI_ENTRY("%p, %x", this, extended_verification);
Heinrich Schuchardtcda9b352019-09-05 20:13:46 +020070 return EFI_EXIT(EFI_SUCCESS);
Alexander Graf2a22d052016-03-04 01:10:02 +010071}
72
73enum efi_disk_direction {
74 EFI_DISK_READ,
75 EFI_DISK_WRITE,
76};
77
Heinrich Schuchardta80a2322017-08-26 22:33:13 +020078static efi_status_t efi_disk_rw_blocks(struct efi_block_io *this,
Alexander Graf2a22d052016-03-04 01:10:02 +010079 u32 media_id, u64 lba, unsigned long buffer_size,
80 void *buffer, enum efi_disk_direction direction)
81{
82 struct efi_disk_obj *diskobj;
83 struct blk_desc *desc;
84 int blksz;
85 int blocks;
86 unsigned long n;
87
Alexander Graf2a22d052016-03-04 01:10:02 +010088 diskobj = container_of(this, struct efi_disk_obj, ops);
Alexander Graff9d334b2016-08-05 14:49:53 +020089 desc = (struct blk_desc *) diskobj->desc;
Alexander Graf2a22d052016-03-04 01:10:02 +010090 blksz = desc->blksz;
91 blocks = buffer_size / blksz;
Alexander Graf8c3df0b2016-04-11 16:16:18 +020092 lba += diskobj->offset;
Alexander Graf2a22d052016-03-04 01:10:02 +010093
Heinrich Schuchardt9d3f3392019-09-05 19:43:17 +020094 EFI_PRINT("blocks=%x lba=%llx blksz=%x dir=%d\n",
95 blocks, lba, blksz, direction);
Alexander Graf2a22d052016-03-04 01:10:02 +010096
97 /* We only support full block access */
98 if (buffer_size & (blksz - 1))
Heinrich Schuchardtf59f0822019-09-05 19:31:23 +020099 return EFI_BAD_BUFFER_SIZE;
Alexander Graf2a22d052016-03-04 01:10:02 +0100100
101 if (direction == EFI_DISK_READ)
Simon Glass487d7562016-05-14 14:03:05 -0600102 n = blk_dread(desc, lba, blocks, buffer);
Alexander Graf2a22d052016-03-04 01:10:02 +0100103 else
Simon Glass487d7562016-05-14 14:03:05 -0600104 n = blk_dwrite(desc, lba, blocks, buffer);
Alexander Graf2a22d052016-03-04 01:10:02 +0100105
106 /* We don't do interrupts, so check for timers cooperatively */
107 efi_timer_check();
108
Heinrich Schuchardt9d3f3392019-09-05 19:43:17 +0200109 EFI_PRINT("n=%lx blocks=%x\n", n, blocks);
Alexander Grafedcef3b2016-06-02 11:38:27 +0200110
Alexander Graf2a22d052016-03-04 01:10:02 +0100111 if (n != blocks)
Rob Clark33049902017-07-25 20:28:29 -0400112 return EFI_DEVICE_ERROR;
Alexander Graf2a22d052016-03-04 01:10:02 +0100113
Rob Clark33049902017-07-25 20:28:29 -0400114 return EFI_SUCCESS;
Alexander Graf2a22d052016-03-04 01:10:02 +0100115}
116
Heinrich Schuchardt55976b72020-04-10 17:10:34 +0200117/**
118 * efi_disk_read_blocks() - reads blocks from device
119 *
120 * This function implements the ReadBlocks service of the EFI_BLOCK_IO_PROTOCOL.
121 *
122 * See the Unified Extensible Firmware Interface (UEFI) specification for
123 * details.
124 *
125 * @this: pointer to the BLOCK_IO_PROTOCOL
126 * @media_id: id of the medium to be read from
127 * @lba: starting logical block for reading
128 * @buffer_size: size of the read buffer
129 * @buffer: pointer to the destination buffer
130 * Return: status code
131 */
Simon Glasse2754582016-09-25 15:27:32 -0600132static efi_status_t EFIAPI efi_disk_read_blocks(struct efi_block_io *this,
Heinrich Schuchardt4f948652018-01-19 20:24:48 +0100133 u32 media_id, u64 lba, efi_uintn_t buffer_size,
Alexander Graf2a22d052016-03-04 01:10:02 +0100134 void *buffer)
135{
Alexander Graf51735ae2016-05-11 18:25:48 +0200136 void *real_buffer = buffer;
137 efi_status_t r;
138
Heinrich Schuchardtf59f0822019-09-05 19:31:23 +0200139 if (!this)
140 return EFI_INVALID_PARAMETER;
141 /* TODO: check for media changes */
142 if (media_id != this->media->media_id)
143 return EFI_MEDIA_CHANGED;
144 if (!this->media->media_present)
145 return EFI_NO_MEDIA;
Heinrich Schuchardt688e8822021-01-23 19:33:11 +0100146 /* media->io_align is a power of 2 or 0 */
147 if (this->media->io_align &&
148 (uintptr_t)buffer & (this->media->io_align - 1))
Heinrich Schuchardtf59f0822019-09-05 19:31:23 +0200149 return EFI_INVALID_PARAMETER;
150 if (lba * this->media->block_size + buffer_size >
Jesper Schmitz Mouridsene67beff2021-02-09 17:17:17 +0100151 (this->media->last_block + 1) * this->media->block_size)
Heinrich Schuchardtf59f0822019-09-05 19:31:23 +0200152 return EFI_INVALID_PARAMETER;
153
Alexander Graf51735ae2016-05-11 18:25:48 +0200154#ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER
155 if (buffer_size > EFI_LOADER_BOUNCE_BUFFER_SIZE) {
156 r = efi_disk_read_blocks(this, media_id, lba,
157 EFI_LOADER_BOUNCE_BUFFER_SIZE, buffer);
158 if (r != EFI_SUCCESS)
159 return r;
160 return efi_disk_read_blocks(this, media_id, lba +
161 EFI_LOADER_BOUNCE_BUFFER_SIZE / this->media->block_size,
162 buffer_size - EFI_LOADER_BOUNCE_BUFFER_SIZE,
163 buffer + EFI_LOADER_BOUNCE_BUFFER_SIZE);
164 }
165
166 real_buffer = efi_bounce_buffer;
167#endif
168
Masahiro Yamadadee37fc2018-08-06 20:47:40 +0900169 EFI_ENTRY("%p, %x, %llx, %zx, %p", this, media_id, lba,
Alexander Graf51735ae2016-05-11 18:25:48 +0200170 buffer_size, buffer);
171
172 r = efi_disk_rw_blocks(this, media_id, lba, buffer_size, real_buffer,
173 EFI_DISK_READ);
174
175 /* Copy from bounce buffer to real buffer if necessary */
176 if ((r == EFI_SUCCESS) && (real_buffer != buffer))
177 memcpy(buffer, real_buffer, buffer_size);
178
179 return EFI_EXIT(r);
Alexander Graf2a22d052016-03-04 01:10:02 +0100180}
181
Heinrich Schuchardt55976b72020-04-10 17:10:34 +0200182/**
183 * efi_disk_write_blocks() - writes blocks to device
184 *
185 * This function implements the WriteBlocks service of the
186 * EFI_BLOCK_IO_PROTOCOL.
187 *
188 * See the Unified Extensible Firmware Interface (UEFI) specification for
189 * details.
190 *
191 * @this: pointer to the BLOCK_IO_PROTOCOL
192 * @media_id: id of the medium to be written to
193 * @lba: starting logical block for writing
194 * @buffer_size: size of the write buffer
195 * @buffer: pointer to the source buffer
196 * Return: status code
197 */
Simon Glasse2754582016-09-25 15:27:32 -0600198static efi_status_t EFIAPI efi_disk_write_blocks(struct efi_block_io *this,
Heinrich Schuchardt4f948652018-01-19 20:24:48 +0100199 u32 media_id, u64 lba, efi_uintn_t buffer_size,
Alexander Graf2a22d052016-03-04 01:10:02 +0100200 void *buffer)
201{
Alexander Graf51735ae2016-05-11 18:25:48 +0200202 void *real_buffer = buffer;
203 efi_status_t r;
204
Heinrich Schuchardtf59f0822019-09-05 19:31:23 +0200205 if (!this)
206 return EFI_INVALID_PARAMETER;
207 if (this->media->read_only)
208 return EFI_WRITE_PROTECTED;
209 /* TODO: check for media changes */
210 if (media_id != this->media->media_id)
211 return EFI_MEDIA_CHANGED;
212 if (!this->media->media_present)
213 return EFI_NO_MEDIA;
Heinrich Schuchardt688e8822021-01-23 19:33:11 +0100214 /* media->io_align is a power of 2 or 0 */
215 if (this->media->io_align &&
216 (uintptr_t)buffer & (this->media->io_align - 1))
Heinrich Schuchardtf59f0822019-09-05 19:31:23 +0200217 return EFI_INVALID_PARAMETER;
218 if (lba * this->media->block_size + buffer_size >
Jesper Schmitz Mouridsene67beff2021-02-09 17:17:17 +0100219 (this->media->last_block + 1) * this->media->block_size)
Heinrich Schuchardtf59f0822019-09-05 19:31:23 +0200220 return EFI_INVALID_PARAMETER;
221
Alexander Graf51735ae2016-05-11 18:25:48 +0200222#ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER
223 if (buffer_size > EFI_LOADER_BOUNCE_BUFFER_SIZE) {
224 r = efi_disk_write_blocks(this, media_id, lba,
225 EFI_LOADER_BOUNCE_BUFFER_SIZE, buffer);
226 if (r != EFI_SUCCESS)
227 return r;
228 return efi_disk_write_blocks(this, media_id, lba +
229 EFI_LOADER_BOUNCE_BUFFER_SIZE / this->media->block_size,
230 buffer_size - EFI_LOADER_BOUNCE_BUFFER_SIZE,
231 buffer + EFI_LOADER_BOUNCE_BUFFER_SIZE);
232 }
233
234 real_buffer = efi_bounce_buffer;
235#endif
236
Masahiro Yamadadee37fc2018-08-06 20:47:40 +0900237 EFI_ENTRY("%p, %x, %llx, %zx, %p", this, media_id, lba,
Alexander Graf51735ae2016-05-11 18:25:48 +0200238 buffer_size, buffer);
239
240 /* Populate bounce buffer if necessary */
241 if (real_buffer != buffer)
242 memcpy(real_buffer, buffer, buffer_size);
243
244 r = efi_disk_rw_blocks(this, media_id, lba, buffer_size, real_buffer,
245 EFI_DISK_WRITE);
246
247 return EFI_EXIT(r);
Alexander Graf2a22d052016-03-04 01:10:02 +0100248}
249
Heinrich Schuchardt55976b72020-04-10 17:10:34 +0200250/**
251 * efi_disk_flush_blocks() - flushes modified data to the device
252 *
253 * This function implements the FlushBlocks service of the
254 * EFI_BLOCK_IO_PROTOCOL.
255 *
256 * As we always write synchronously nothing is done here.
257 *
258 * See the Unified Extensible Firmware Interface (UEFI) specification for
259 * details.
260 *
261 * @this: pointer to the BLOCK_IO_PROTOCOL
262 * Return: status code
263 */
Alexander Graf2a22d052016-03-04 01:10:02 +0100264static efi_status_t EFIAPI efi_disk_flush_blocks(struct efi_block_io *this)
265{
Alexander Graf2a22d052016-03-04 01:10:02 +0100266 EFI_ENTRY("%p", this);
267 return EFI_EXIT(EFI_SUCCESS);
268}
269
270static const struct efi_block_io block_io_disk_template = {
271 .reset = &efi_disk_reset,
272 .read_blocks = &efi_disk_read_blocks,
273 .write_blocks = &efi_disk_write_blocks,
274 .flush_blocks = &efi_disk_flush_blocks,
275};
276
Heinrich Schuchardt47a95962020-03-19 13:49:34 +0100277/**
278 * efi_fs_from_path() - retrieve simple file system protocol
279 *
280 * Gets the simple file system protocol for a file device path.
Heinrich Schuchardt110d80a2018-01-19 20:24:39 +0100281 *
282 * The full path provided is split into device part and into a file
283 * part. The device part is used to find the handle on which the
284 * simple file system protocol is installed.
285 *
Heinrich Schuchardt47a95962020-03-19 13:49:34 +0100286 * @full_path: device path including device and file
287 * Return: simple file system protocol
Rob Clark2a920802017-09-13 18:05:34 -0400288 */
289struct efi_simple_file_system_protocol *
Heinrich Schuchardt110d80a2018-01-19 20:24:39 +0100290efi_fs_from_path(struct efi_device_path *full_path)
Rob Clark2a920802017-09-13 18:05:34 -0400291{
292 struct efi_object *efiobj;
Heinrich Schuchardt110d80a2018-01-19 20:24:39 +0100293 struct efi_handler *handler;
294 struct efi_device_path *device_path;
295 struct efi_device_path *file_path;
296 efi_status_t ret;
Rob Clark2a920802017-09-13 18:05:34 -0400297
Heinrich Schuchardt110d80a2018-01-19 20:24:39 +0100298 /* Split the path into a device part and a file part */
299 ret = efi_dp_split_file_path(full_path, &device_path, &file_path);
300 if (ret != EFI_SUCCESS)
301 return NULL;
302 efi_free_pool(file_path);
303
304 /* Get the EFI object for the partition */
Heinrich Schuchardte46ef1d2022-03-19 06:35:43 +0100305 efiobj = efi_dp_find_obj(device_path, NULL, NULL);
Heinrich Schuchardt110d80a2018-01-19 20:24:39 +0100306 efi_free_pool(device_path);
Rob Clark2a920802017-09-13 18:05:34 -0400307 if (!efiobj)
308 return NULL;
309
Heinrich Schuchardt110d80a2018-01-19 20:24:39 +0100310 /* Find the simple file system protocol */
311 ret = efi_search_protocol(efiobj, &efi_simple_file_system_protocol_guid,
312 &handler);
313 if (ret != EFI_SUCCESS)
314 return NULL;
Rob Clark2a920802017-09-13 18:05:34 -0400315
Heinrich Schuchardt110d80a2018-01-19 20:24:39 +0100316 /* Return the simple file system protocol for the partition */
317 return handler->protocol_interface;
Rob Clark2a920802017-09-13 18:05:34 -0400318}
319
AKASHI Takahiro86740062019-10-07 14:59:38 +0900320/**
321 * efi_fs_exists() - check if a partition bears a file system
322 *
323 * @desc: block device descriptor
324 * @part: partition number
325 * Return: 1 if a file system exists on the partition
326 * 0 otherwise
327 */
328static int efi_fs_exists(struct blk_desc *desc, int part)
329{
330 if (fs_set_blk_dev_with_part(desc, part))
331 return 0;
332
333 if (fs_get_type() == FS_TYPE_ANY)
334 return 0;
335
336 fs_close();
337
338 return 1;
339}
340
Heinrich Schuchardt55976b72020-04-10 17:10:34 +0200341/**
Heinrich Schuchardt47a95962020-03-19 13:49:34 +0100342 * efi_disk_add_dev() - create a handle for a partition or disk
Heinrich Schuchardt93945f22017-10-26 19:25:46 +0200343 *
Heinrich Schuchardt47a95962020-03-19 13:49:34 +0100344 * @parent: parent handle
345 * @dp_parent: parent device path
346 * @if_typename: interface name for block device
347 * @desc: internal block device
348 * @dev_index: device index for block device
Heinrich Schuchardt8d0949b2021-01-23 06:52:21 +0100349 * @part_info: partition info
Heinrich Schuchardt55976b72020-04-10 17:10:34 +0200350 * @part: partition
351 * @disk: pointer to receive the created handle
Heinrich Schuchardt47a95962020-03-19 13:49:34 +0100352 * Return: disk object
Heinrich Schuchardt93945f22017-10-26 19:25:46 +0200353 */
Heinrich Schuchardtdf9cf562018-02-09 20:55:47 +0100354static efi_status_t efi_disk_add_dev(
Heinrich Schuchardt64e4db02018-01-19 20:24:47 +0100355 efi_handle_t parent,
356 struct efi_device_path *dp_parent,
357 const char *if_typename,
358 struct blk_desc *desc,
359 int dev_index,
Heinrich Schuchardt8d0949b2021-01-23 06:52:21 +0100360 struct disk_partition *part_info,
Heinrich Schuchardtdf9cf562018-02-09 20:55:47 +0100361 unsigned int part,
362 struct efi_disk_obj **disk)
Alexander Graf4a12a972016-04-11 16:16:17 +0200363{
364 struct efi_disk_obj *diskobj;
Heinrich Schuchardt0a87e052020-05-21 09:22:06 +0200365 struct efi_object *handle;
Heinrich Schuchardtb9b0ea32021-02-02 17:53:14 +0100366 const efi_guid_t *guid = NULL;
Heinrich Schuchardt4b9f7aa2017-11-26 14:05:12 +0100367 efi_status_t ret;
Alexander Graf4a12a972016-04-11 16:16:17 +0200368
Alexander Graf0812d1a2016-08-05 14:51:47 +0200369 /* Don't add empty devices */
370 if (!desc->lba)
Heinrich Schuchardtdf9cf562018-02-09 20:55:47 +0100371 return EFI_NOT_READY;
Alexander Graf0812d1a2016-08-05 14:51:47 +0200372
Rob Clark884bcf62017-09-13 18:05:31 -0400373 diskobj = calloc(1, sizeof(*diskobj));
Heinrich Schuchardt4b9f7aa2017-11-26 14:05:12 +0100374 if (!diskobj)
Heinrich Schuchardtdf9cf562018-02-09 20:55:47 +0100375 return EFI_OUT_OF_RESOURCES;
Heinrich Schuchardt4b9f7aa2017-11-26 14:05:12 +0100376
377 /* Hook up to the device list */
Heinrich Schuchardtd39646a2018-09-26 05:27:56 +0200378 efi_add_handle(&diskobj->header);
Alexander Graf4a12a972016-04-11 16:16:17 +0200379
380 /* Fill in object data */
Heinrich Schuchardt8d0949b2021-01-23 06:52:21 +0100381 if (part_info) {
Heinrich Schuchardt64e4db02018-01-19 20:24:47 +0100382 struct efi_device_path *node = efi_dp_part_node(desc, part);
Heinrich Schuchardt26448512020-01-10 12:36:01 +0100383 struct efi_handler *handler;
384 void *protocol_interface;
385
386 /* Parent must expose EFI_BLOCK_IO_PROTOCOL */
387 ret = efi_search_protocol(parent, &efi_block_io_guid, &handler);
388 if (ret != EFI_SUCCESS)
389 goto error;
390
391 /*
392 * Link the partition (child controller) to the block device
393 * (controller).
394 */
395 ret = efi_protocol_open(handler, &protocol_interface, NULL,
396 &diskobj->header,
397 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER);
398 if (ret != EFI_SUCCESS)
399 goto error;
Heinrich Schuchardt64e4db02018-01-19 20:24:47 +0100400
401 diskobj->dp = efi_dp_append_node(dp_parent, node);
402 efi_free_pool(node);
Heinrich Schuchardt8d0949b2021-01-23 06:52:21 +0100403 diskobj->offset = part_info->start;
404 diskobj->media.last_block = part_info->size - 1;
Heinrich Schuchardtb9b0ea32021-02-02 17:53:14 +0100405 if (part_info->bootable & PART_EFI_SYSTEM_PARTITION)
406 guid = &efi_system_partition_guid;
Heinrich Schuchardt64e4db02018-01-19 20:24:47 +0100407 } else {
408 diskobj->dp = efi_dp_from_part(desc, part);
Heinrich Schuchardt8d0949b2021-01-23 06:52:21 +0100409 diskobj->offset = 0;
410 diskobj->media.last_block = desc->lba - 1;
Heinrich Schuchardt64e4db02018-01-19 20:24:47 +0100411 }
Rob Clark884bcf62017-09-13 18:05:31 -0400412 diskobj->part = part;
Heinrich Schuchardt0a87e052020-05-21 09:22:06 +0200413
414 /*
415 * Install the device path and the block IO protocol.
416 *
417 * InstallMultipleProtocolInterfaces() checks if the device path is
418 * already installed on an other handle and returns EFI_ALREADY_STARTED
419 * in this case.
420 */
421 handle = &diskobj->header;
422 ret = EFI_CALL(efi_install_multiple_protocol_interfaces(
423 &handle, &efi_guid_device_path, diskobj->dp,
Heinrich Schuchardtb9b0ea32021-02-02 17:53:14 +0100424 &efi_block_io_guid, &diskobj->ops,
425 guid, NULL, NULL));
Heinrich Schuchardt4b9f7aa2017-11-26 14:05:12 +0100426 if (ret != EFI_SUCCESS)
Heinrich Schuchardtcd9a26b2021-11-20 13:56:02 +0100427 goto error;
Heinrich Schuchardt0a87e052020-05-21 09:22:06 +0200428
429 /*
430 * On partitions or whole disks without partitions install the
431 * simple file system protocol if a file system is available.
432 */
AKASHI Takahiro89cb6a52019-10-07 14:59:39 +0900433 if ((part || desc->part_type == PART_TYPE_UNKNOWN) &&
434 efi_fs_exists(desc, part)) {
Rob Clark2a920802017-09-13 18:05:34 -0400435 diskobj->volume = efi_simple_file_system(desc, part,
436 diskobj->dp);
Heinrich Schuchardtd39646a2018-09-26 05:27:56 +0200437 ret = efi_add_protocol(&diskobj->header,
Heinrich Schuchardt4b9f7aa2017-11-26 14:05:12 +0100438 &efi_simple_file_system_protocol_guid,
Heinrich Schuchardt22de1de2018-01-19 20:24:38 +0100439 diskobj->volume);
Heinrich Schuchardt4b9f7aa2017-11-26 14:05:12 +0100440 if (ret != EFI_SUCCESS)
Heinrich Schuchardtdf9cf562018-02-09 20:55:47 +0100441 return ret;
Rob Clark2a920802017-09-13 18:05:34 -0400442 }
Alexander Graf4a12a972016-04-11 16:16:17 +0200443 diskobj->ops = block_io_disk_template;
Simon Glass487d7562016-05-14 14:03:05 -0600444 diskobj->ifname = if_typename;
Alexander Graf4a12a972016-04-11 16:16:17 +0200445 diskobj->dev_index = dev_index;
Alexander Graff9d334b2016-08-05 14:49:53 +0200446 diskobj->desc = desc;
Alexander Graf4a12a972016-04-11 16:16:17 +0200447
448 /* Fill in EFI IO Media info (for read/write callbacks) */
449 diskobj->media.removable_media = desc->removable;
450 diskobj->media.media_present = 1;
Heinrich Schuchardtf59f0822019-09-05 19:31:23 +0200451 /*
452 * MediaID is just an arbitrary counter.
453 * We have to change it if the medium is removed or changed.
454 */
455 diskobj->media.media_id = 1;
Alexander Graf4a12a972016-04-11 16:16:17 +0200456 diskobj->media.block_size = desc->blksz;
457 diskobj->media.io_align = desc->blksz;
Heinrich Schuchardt9f888962020-03-19 15:45:52 +0100458 if (part)
Emmanuel Vadot5f770832017-12-11 19:22:33 +0100459 diskobj->media.logical_partition = 1;
Alexander Graf4a12a972016-04-11 16:16:17 +0200460 diskobj->ops.media = &diskobj->media;
Heinrich Schuchardtdf9cf562018-02-09 20:55:47 +0100461 if (disk)
462 *disk = diskobj;
Heinrich Schuchardt11078bb2020-03-19 15:16:31 +0100463
Heinrich Schuchardt8d0949b2021-01-23 06:52:21 +0100464 EFI_PRINT("BlockIO: part %u, present %d, logical %d, removable %d"
465 ", offset " LBAF ", last_block %llu\n",
466 diskobj->part,
467 diskobj->media.media_present,
468 diskobj->media.logical_partition,
469 diskobj->media.removable_media,
470 diskobj->offset,
471 diskobj->media.last_block);
472
Heinrich Schuchardt11078bb2020-03-19 15:16:31 +0100473 /* Store first EFI system partition */
474 if (part && !efi_system_partition.if_type) {
Heinrich Schuchardtb9b0ea32021-02-02 17:53:14 +0100475 if (part_info->bootable & PART_EFI_SYSTEM_PARTITION) {
Heinrich Schuchardt11078bb2020-03-19 15:16:31 +0100476 efi_system_partition.if_type = desc->if_type;
477 efi_system_partition.devnum = desc->devnum;
478 efi_system_partition.part = part;
Heinrich Schuchardt3dca77b2021-05-25 18:00:13 +0200479 EFI_PRINT("EFI system partition: %s %x:%x\n",
Heinrich Schuchardt11078bb2020-03-19 15:16:31 +0100480 blk_get_if_type_name(desc->if_type),
481 desc->devnum, part);
482 }
483 }
Heinrich Schuchardtdf9cf562018-02-09 20:55:47 +0100484 return EFI_SUCCESS;
Heinrich Schuchardt26448512020-01-10 12:36:01 +0100485error:
486 efi_delete_handle(&diskobj->header);
487 return ret;
Alexander Graf4a12a972016-04-11 16:16:17 +0200488}
489
Heinrich Schuchardt47a95962020-03-19 13:49:34 +0100490/**
491 * efi_disk_create_partitions() - create handles and protocols for partitions
Heinrich Schuchardt64e4db02018-01-19 20:24:47 +0100492 *
Heinrich Schuchardt47a95962020-03-19 13:49:34 +0100493 * Create handles and protocols for the partitions of a block device.
494 *
495 * @parent: handle of the parent disk
Heinrich Schuchardt55976b72020-04-10 17:10:34 +0200496 * @desc: block device
Heinrich Schuchardt47a95962020-03-19 13:49:34 +0100497 * @if_typename: interface type
498 * @diskid: device number
499 * @pdevname: device name
500 * Return: number of partitions created
Heinrich Schuchardt64e4db02018-01-19 20:24:47 +0100501 */
502int efi_disk_create_partitions(efi_handle_t parent, struct blk_desc *desc,
503 const char *if_typename, int diskid,
504 const char *pdevname)
Alexander Graf8c3df0b2016-04-11 16:16:18 +0200505{
506 int disks = 0;
Alexander Grafecbe1a02016-04-11 16:16:20 +0200507 char devname[32] = { 0 }; /* dp->str is u16[32] long */
Jonathan Gray16a73b22017-10-10 13:55:26 +1100508 int part;
Heinrich Schuchardt64e4db02018-01-19 20:24:47 +0100509 struct efi_device_path *dp = NULL;
510 efi_status_t ret;
511 struct efi_handler *handler;
512
513 /* Get the device path of the parent */
514 ret = efi_search_protocol(parent, &efi_guid_device_path, &handler);
515 if (ret == EFI_SUCCESS)
516 dp = handler->protocol_interface;
Alexander Graf8c3df0b2016-04-11 16:16:18 +0200517
Alexander Grafc034b7f2017-12-01 16:10:33 +0100518 /* Add devices for each partition */
Jonathan Gray16a73b22017-10-10 13:55:26 +1100519 for (part = 1; part <= MAX_SEARCH_PARTITIONS; part++) {
Heinrich Schuchardt8d0949b2021-01-23 06:52:21 +0100520 struct disk_partition info;
521
Jonathan Gray16a73b22017-10-10 13:55:26 +1100522 if (part_get_info(desc, part, &info))
523 continue;
Heinrich Schuchardt3dca77b2021-05-25 18:00:13 +0200524 snprintf(devname, sizeof(devname), "%s:%x", pdevname,
Alexander Graff9d334b2016-08-05 14:49:53 +0200525 part);
Heinrich Schuchardtdf9cf562018-02-09 20:55:47 +0100526 ret = efi_disk_add_dev(parent, dp, if_typename, desc, diskid,
Heinrich Schuchardt8d0949b2021-01-23 06:52:21 +0100527 &info, part, NULL);
Heinrich Schuchardtdf9cf562018-02-09 20:55:47 +0100528 if (ret != EFI_SUCCESS) {
Heinrich Schuchardtaf457cf2020-07-17 20:33:05 +0200529 log_err("Adding partition %s failed\n", pdevname);
Heinrich Schuchardtdf9cf562018-02-09 20:55:47 +0100530 continue;
531 }
Alexander Graf8c3df0b2016-04-11 16:16:18 +0200532 disks++;
533 }
Rob Clark884bcf62017-09-13 18:05:31 -0400534
Alexander Graf8c3df0b2016-04-11 16:16:18 +0200535 return disks;
536}
537
Heinrich Schuchardt47a95962020-03-19 13:49:34 +0100538/**
539 * efi_disk_register() - register block devices
540 *
Alexander Graf2a22d052016-03-04 01:10:02 +0100541 * U-Boot doesn't have a list of all online disk devices. So when running our
542 * EFI payload, we scan through all of the potentially available ones and
543 * store them in our object pool.
544 *
Heinrich Schuchardt47a95962020-03-19 13:49:34 +0100545 * This function is called in efi_init_obj_list().
546 *
Simon Glass487d7562016-05-14 14:03:05 -0600547 * TODO(sjg@chromium.org): Actually with CONFIG_BLK, U-Boot does have this.
548 * Consider converting the code to look up devices as needed. The EFI device
549 * could be a child of the UCLASS_BLK block device, perhaps.
550 *
Heinrich Schuchardt47a95962020-03-19 13:49:34 +0100551 * Return: status code
Alexander Graf2a22d052016-03-04 01:10:02 +0100552 */
Heinrich Schuchardtdf9cf562018-02-09 20:55:47 +0100553efi_status_t efi_disk_register(void)
Alexander Graf2a22d052016-03-04 01:10:02 +0100554{
Heinrich Schuchardt64e4db02018-01-19 20:24:47 +0100555 struct efi_disk_obj *disk;
Alexander Graf2a22d052016-03-04 01:10:02 +0100556 int disks = 0;
Heinrich Schuchardtdf9cf562018-02-09 20:55:47 +0100557 efi_status_t ret;
Simon Glass487d7562016-05-14 14:03:05 -0600558 struct udevice *dev;
559
Heinrich Schuchardtdf9cf562018-02-09 20:55:47 +0100560 for (uclass_first_device_check(UCLASS_BLK, &dev); dev;
xypron.glpk@gmx.de70bfcdc2017-06-20 19:10:27 +0000561 uclass_next_device_check(&dev)) {
Simon Glasscaa4daa2020-12-03 16:55:18 -0700562 struct blk_desc *desc = dev_get_uclass_plat(dev);
Heinrich Schuchardt9bfca9f2018-01-19 20:24:44 +0100563 const char *if_typename = blk_get_if_type_name(desc->if_type);
Simon Glass487d7562016-05-14 14:03:05 -0600564
Alexander Grafc034b7f2017-12-01 16:10:33 +0100565 /* Add block device for the full device */
Heinrich Schuchardtaf457cf2020-07-17 20:33:05 +0200566 log_info("Scanning disk %s...\n", dev->name);
Heinrich Schuchardtdf9cf562018-02-09 20:55:47 +0100567 ret = efi_disk_add_dev(NULL, NULL, if_typename,
Heinrich Schuchardt8d0949b2021-01-23 06:52:21 +0100568 desc, desc->devnum, NULL, 0, &disk);
Heinrich Schuchardtdf9cf562018-02-09 20:55:47 +0100569 if (ret == EFI_NOT_READY) {
Heinrich Schuchardtaf457cf2020-07-17 20:33:05 +0200570 log_notice("Disk %s not ready\n", dev->name);
Heinrich Schuchardtdf9cf562018-02-09 20:55:47 +0100571 continue;
572 }
573 if (ret) {
Heinrich Schuchardtaf457cf2020-07-17 20:33:05 +0200574 log_err("ERROR: failure to add disk device %s, r = %lu\n",
575 dev->name, ret & ~EFI_ERROR_MASK);
Heinrich Schuchardtcd9a26b2021-11-20 13:56:02 +0100576 continue;
Heinrich Schuchardtdf9cf562018-02-09 20:55:47 +0100577 }
Simon Glass487d7562016-05-14 14:03:05 -0600578 disks++;
579
Alexander Grafc034b7f2017-12-01 16:10:33 +0100580 /* Partitions show up as block devices in EFI */
Heinrich Schuchardt64e4db02018-01-19 20:24:47 +0100581 disks += efi_disk_create_partitions(
Heinrich Schuchardtd39646a2018-09-26 05:27:56 +0200582 &disk->header, desc, if_typename,
Heinrich Schuchardt64e4db02018-01-19 20:24:47 +0100583 desc->devnum, dev->name);
Simon Glass487d7562016-05-14 14:03:05 -0600584 }
Alexander Graf2a22d052016-03-04 01:10:02 +0100585
Heinrich Schuchardtaf457cf2020-07-17 20:33:05 +0200586 log_info("Found %d disks\n", disks);
Alexander Graf2a22d052016-03-04 01:10:02 +0100587
Heinrich Schuchardtdf9cf562018-02-09 20:55:47 +0100588 return EFI_SUCCESS;
Alexander Graf2a22d052016-03-04 01:10:02 +0100589}