]> Git Repo - u-boot.git/blob - lib/efi_loader/efi_disk.c
efi_loader: correct block IO alignment check
[u-boot.git] / lib / efi_loader / efi_disk.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  *  EFI application disk support
4  *
5  *  Copyright (c) 2016 Alexander Graf
6  */
7
8 #define LOG_CATEGORY LOGC_EFI
9
10 #include <common.h>
11 #include <blk.h>
12 #include <dm.h>
13 #include <efi_loader.h>
14 #include <fs.h>
15 #include <log.h>
16 #include <part.h>
17 #include <malloc.h>
18
19 struct efi_system_partition efi_system_partition;
20
21 const efi_guid_t efi_block_io_guid = EFI_BLOCK_IO_PROTOCOL_GUID;
22
23 /**
24  * struct efi_disk_obj - EFI disk object
25  *
26  * @header:     EFI object header
27  * @ops:        EFI disk I/O protocol interface
28  * @ifname:     interface name for block device
29  * @dev_index:  device index of block device
30  * @media:      block I/O media information
31  * @dp:         device path to the block device
32  * @part:       partition
33  * @volume:     simple file system protocol of the partition
34  * @offset:     offset into disk for simple partition
35  * @desc:       internal block device descriptor
36  */
37 struct efi_disk_obj {
38         struct efi_object header;
39         struct efi_block_io ops;
40         const char *ifname;
41         int dev_index;
42         struct efi_block_io_media media;
43         struct efi_device_path *dp;
44         unsigned int part;
45         struct efi_simple_file_system_protocol *volume;
46         lbaint_t offset;
47         struct blk_desc *desc;
48 };
49
50 /**
51  * efi_disk_reset() - reset block device
52  *
53  * This function implements the Reset service of the EFI_BLOCK_IO_PROTOCOL.
54  *
55  * As U-Boot's block devices do not have a reset function simply return
56  * EFI_SUCCESS.
57  *
58  * See the Unified Extensible Firmware Interface (UEFI) specification for
59  * details.
60  *
61  * @this:                       pointer to the BLOCK_IO_PROTOCOL
62  * @extended_verification:      extended verification
63  * Return:                      status code
64  */
65 static efi_status_t EFIAPI efi_disk_reset(struct efi_block_io *this,
66                         char extended_verification)
67 {
68         EFI_ENTRY("%p, %x", this, extended_verification);
69         return EFI_EXIT(EFI_SUCCESS);
70 }
71
72 enum efi_disk_direction {
73         EFI_DISK_READ,
74         EFI_DISK_WRITE,
75 };
76
77 static efi_status_t efi_disk_rw_blocks(struct efi_block_io *this,
78                         u32 media_id, u64 lba, unsigned long buffer_size,
79                         void *buffer, enum efi_disk_direction direction)
80 {
81         struct efi_disk_obj *diskobj;
82         struct blk_desc *desc;
83         int blksz;
84         int blocks;
85         unsigned long n;
86
87         diskobj = container_of(this, struct efi_disk_obj, ops);
88         desc = (struct blk_desc *) diskobj->desc;
89         blksz = desc->blksz;
90         blocks = buffer_size / blksz;
91         lba += diskobj->offset;
92
93         EFI_PRINT("blocks=%x lba=%llx blksz=%x dir=%d\n",
94                   blocks, lba, blksz, direction);
95
96         /* We only support full block access */
97         if (buffer_size & (blksz - 1))
98                 return EFI_BAD_BUFFER_SIZE;
99
100         if (direction == EFI_DISK_READ)
101                 n = blk_dread(desc, lba, blocks, buffer);
102         else
103                 n = blk_dwrite(desc, lba, blocks, buffer);
104
105         /* We don't do interrupts, so check for timers cooperatively */
106         efi_timer_check();
107
108         EFI_PRINT("n=%lx blocks=%x\n", n, blocks);
109
110         if (n != blocks)
111                 return EFI_DEVICE_ERROR;
112
113         return EFI_SUCCESS;
114 }
115
116 /**
117  * efi_disk_read_blocks() - reads blocks from device
118  *
119  * This function implements the ReadBlocks service of the EFI_BLOCK_IO_PROTOCOL.
120  *
121  * See the Unified Extensible Firmware Interface (UEFI) specification for
122  * details.
123  *
124  * @this:                       pointer to the BLOCK_IO_PROTOCOL
125  * @media_id:                   id of the medium to be read from
126  * @lba:                        starting logical block for reading
127  * @buffer_size:                size of the read buffer
128  * @buffer:                     pointer to the destination buffer
129  * Return:                      status code
130  */
131 static efi_status_t EFIAPI efi_disk_read_blocks(struct efi_block_io *this,
132                         u32 media_id, u64 lba, efi_uintn_t buffer_size,
133                         void *buffer)
134 {
135         void *real_buffer = buffer;
136         efi_status_t r;
137
138         if (!this)
139                 return EFI_INVALID_PARAMETER;
140         /* TODO: check for media changes */
141         if (media_id != this->media->media_id)
142                 return EFI_MEDIA_CHANGED;
143         if (!this->media->media_present)
144                 return EFI_NO_MEDIA;
145         /* media->io_align is a power of 2 or 0 */
146         if (this->media->io_align &&
147             (uintptr_t)buffer & (this->media->io_align - 1))
148                 return EFI_INVALID_PARAMETER;
149         if (lba * this->media->block_size + buffer_size >
150             this->media->last_block * this->media->block_size)
151                 return EFI_INVALID_PARAMETER;
152
153 #ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER
154         if (buffer_size > EFI_LOADER_BOUNCE_BUFFER_SIZE) {
155                 r = efi_disk_read_blocks(this, media_id, lba,
156                         EFI_LOADER_BOUNCE_BUFFER_SIZE, buffer);
157                 if (r != EFI_SUCCESS)
158                         return r;
159                 return efi_disk_read_blocks(this, media_id, lba +
160                         EFI_LOADER_BOUNCE_BUFFER_SIZE / this->media->block_size,
161                         buffer_size - EFI_LOADER_BOUNCE_BUFFER_SIZE,
162                         buffer + EFI_LOADER_BOUNCE_BUFFER_SIZE);
163         }
164
165         real_buffer = efi_bounce_buffer;
166 #endif
167
168         EFI_ENTRY("%p, %x, %llx, %zx, %p", this, media_id, lba,
169                   buffer_size, buffer);
170
171         r = efi_disk_rw_blocks(this, media_id, lba, buffer_size, real_buffer,
172                                EFI_DISK_READ);
173
174         /* Copy from bounce buffer to real buffer if necessary */
175         if ((r == EFI_SUCCESS) && (real_buffer != buffer))
176                 memcpy(buffer, real_buffer, buffer_size);
177
178         return EFI_EXIT(r);
179 }
180
181 /**
182  * efi_disk_write_blocks() - writes blocks to device
183  *
184  * This function implements the WriteBlocks service of the
185  * EFI_BLOCK_IO_PROTOCOL.
186  *
187  * See the Unified Extensible Firmware Interface (UEFI) specification for
188  * details.
189  *
190  * @this:                       pointer to the BLOCK_IO_PROTOCOL
191  * @media_id:                   id of the medium to be written to
192  * @lba:                        starting logical block for writing
193  * @buffer_size:                size of the write buffer
194  * @buffer:                     pointer to the source buffer
195  * Return:                      status code
196  */
197 static efi_status_t EFIAPI efi_disk_write_blocks(struct efi_block_io *this,
198                         u32 media_id, u64 lba, efi_uintn_t buffer_size,
199                         void *buffer)
200 {
201         void *real_buffer = buffer;
202         efi_status_t r;
203
204         if (!this)
205                 return EFI_INVALID_PARAMETER;
206         if (this->media->read_only)
207                 return EFI_WRITE_PROTECTED;
208         /* TODO: check for media changes */
209         if (media_id != this->media->media_id)
210                 return EFI_MEDIA_CHANGED;
211         if (!this->media->media_present)
212                 return EFI_NO_MEDIA;
213         /* media->io_align is a power of 2 or 0 */
214         if (this->media->io_align &&
215             (uintptr_t)buffer & (this->media->io_align - 1))
216                 return EFI_INVALID_PARAMETER;
217         if (lba * this->media->block_size + buffer_size >
218             this->media->last_block * this->media->block_size)
219                 return EFI_INVALID_PARAMETER;
220
221 #ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER
222         if (buffer_size > EFI_LOADER_BOUNCE_BUFFER_SIZE) {
223                 r = efi_disk_write_blocks(this, media_id, lba,
224                         EFI_LOADER_BOUNCE_BUFFER_SIZE, buffer);
225                 if (r != EFI_SUCCESS)
226                         return r;
227                 return efi_disk_write_blocks(this, media_id, lba +
228                         EFI_LOADER_BOUNCE_BUFFER_SIZE / this->media->block_size,
229                         buffer_size - EFI_LOADER_BOUNCE_BUFFER_SIZE,
230                         buffer + EFI_LOADER_BOUNCE_BUFFER_SIZE);
231         }
232
233         real_buffer = efi_bounce_buffer;
234 #endif
235
236         EFI_ENTRY("%p, %x, %llx, %zx, %p", this, media_id, lba,
237                   buffer_size, buffer);
238
239         /* Populate bounce buffer if necessary */
240         if (real_buffer != buffer)
241                 memcpy(real_buffer, buffer, buffer_size);
242
243         r = efi_disk_rw_blocks(this, media_id, lba, buffer_size, real_buffer,
244                                EFI_DISK_WRITE);
245
246         return EFI_EXIT(r);
247 }
248
249 /**
250  * efi_disk_flush_blocks() - flushes modified data to the device
251  *
252  * This function implements the FlushBlocks service of the
253  * EFI_BLOCK_IO_PROTOCOL.
254  *
255  * As we always write synchronously nothing is done here.
256  *
257  * See the Unified Extensible Firmware Interface (UEFI) specification for
258  * details.
259  *
260  * @this:                       pointer to the BLOCK_IO_PROTOCOL
261  * Return:                      status code
262  */
263 static efi_status_t EFIAPI efi_disk_flush_blocks(struct efi_block_io *this)
264 {
265         EFI_ENTRY("%p", this);
266         return EFI_EXIT(EFI_SUCCESS);
267 }
268
269 static const struct efi_block_io block_io_disk_template = {
270         .reset = &efi_disk_reset,
271         .read_blocks = &efi_disk_read_blocks,
272         .write_blocks = &efi_disk_write_blocks,
273         .flush_blocks = &efi_disk_flush_blocks,
274 };
275
276 /**
277  * efi_fs_from_path() - retrieve simple file system protocol
278  *
279  * Gets the simple file system protocol for a file device path.
280  *
281  * The full path provided is split into device part and into a file
282  * part. The device part is used to find the handle on which the
283  * simple file system protocol is installed.
284  *
285  * @full_path:  device path including device and file
286  * Return:      simple file system protocol
287  */
288 struct efi_simple_file_system_protocol *
289 efi_fs_from_path(struct efi_device_path *full_path)
290 {
291         struct efi_object *efiobj;
292         struct efi_handler *handler;
293         struct efi_device_path *device_path;
294         struct efi_device_path *file_path;
295         efi_status_t ret;
296
297         /* Split the path into a device part and a file part */
298         ret = efi_dp_split_file_path(full_path, &device_path, &file_path);
299         if (ret != EFI_SUCCESS)
300                 return NULL;
301         efi_free_pool(file_path);
302
303         /* Get the EFI object for the partition */
304         efiobj = efi_dp_find_obj(device_path, NULL);
305         efi_free_pool(device_path);
306         if (!efiobj)
307                 return NULL;
308
309         /* Find the simple file system protocol */
310         ret = efi_search_protocol(efiobj, &efi_simple_file_system_protocol_guid,
311                                   &handler);
312         if (ret != EFI_SUCCESS)
313                 return NULL;
314
315         /* Return the simple file system protocol for the partition */
316         return handler->protocol_interface;
317 }
318
319 /**
320  * efi_fs_exists() - check if a partition bears a file system
321  *
322  * @desc:       block device descriptor
323  * @part:       partition number
324  * Return:      1 if a file system exists on the partition
325  *              0 otherwise
326  */
327 static int efi_fs_exists(struct blk_desc *desc, int part)
328 {
329         if (fs_set_blk_dev_with_part(desc, part))
330                 return 0;
331
332         if (fs_get_type() == FS_TYPE_ANY)
333                 return 0;
334
335         fs_close();
336
337         return 1;
338 }
339
340 /**
341  * efi_disk_add_dev() - create a handle for a partition or disk
342  *
343  * @parent:             parent handle
344  * @dp_parent:          parent device path
345  * @if_typename:        interface name for block device
346  * @desc:               internal block device
347  * @dev_index:          device index for block device
348  * @part_info:          partition info
349  * @part:               partition
350  * @disk:               pointer to receive the created handle
351  * Return:              disk object
352  */
353 static efi_status_t efi_disk_add_dev(
354                                 efi_handle_t parent,
355                                 struct efi_device_path *dp_parent,
356                                 const char *if_typename,
357                                 struct blk_desc *desc,
358                                 int dev_index,
359                                 struct disk_partition *part_info,
360                                 unsigned int part,
361                                 struct efi_disk_obj **disk)
362 {
363         struct efi_disk_obj *diskobj;
364         struct efi_object *handle;
365         efi_status_t ret;
366
367         /* Don't add empty devices */
368         if (!desc->lba)
369                 return EFI_NOT_READY;
370
371         diskobj = calloc(1, sizeof(*diskobj));
372         if (!diskobj)
373                 return EFI_OUT_OF_RESOURCES;
374
375         /* Hook up to the device list */
376         efi_add_handle(&diskobj->header);
377
378         /* Fill in object data */
379         if (part_info) {
380                 struct efi_device_path *node = efi_dp_part_node(desc, part);
381                 struct efi_handler *handler;
382                 void *protocol_interface;
383
384                 /* Parent must expose EFI_BLOCK_IO_PROTOCOL */
385                 ret = efi_search_protocol(parent, &efi_block_io_guid, &handler);
386                 if (ret != EFI_SUCCESS)
387                         goto error;
388
389                 /*
390                  * Link the partition (child controller) to the block device
391                  * (controller).
392                  */
393                 ret = efi_protocol_open(handler, &protocol_interface, NULL,
394                                         &diskobj->header,
395                                         EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER);
396                 if (ret != EFI_SUCCESS)
397                                 goto error;
398
399                 diskobj->dp = efi_dp_append_node(dp_parent, node);
400                 efi_free_pool(node);
401                 diskobj->offset = part_info->start;
402                 diskobj->media.last_block = part_info->size - 1;
403         } else {
404                 diskobj->dp = efi_dp_from_part(desc, part);
405                 diskobj->offset = 0;
406                 diskobj->media.last_block = desc->lba - 1;
407         }
408         diskobj->part = part;
409
410         /*
411          * Install the device path and the block IO protocol.
412          *
413          * InstallMultipleProtocolInterfaces() checks if the device path is
414          * already installed on an other handle and returns EFI_ALREADY_STARTED
415          * in this case.
416          */
417         handle = &diskobj->header;
418         ret = EFI_CALL(efi_install_multiple_protocol_interfaces(
419                         &handle, &efi_guid_device_path, diskobj->dp,
420                         &efi_block_io_guid, &diskobj->ops, NULL));
421         if (ret != EFI_SUCCESS)
422                 return ret;
423
424         /*
425          * On partitions or whole disks without partitions install the
426          * simple file system protocol if a file system is available.
427          */
428         if ((part || desc->part_type == PART_TYPE_UNKNOWN) &&
429             efi_fs_exists(desc, part)) {
430                 diskobj->volume = efi_simple_file_system(desc, part,
431                                                          diskobj->dp);
432                 ret = efi_add_protocol(&diskobj->header,
433                                        &efi_simple_file_system_protocol_guid,
434                                        diskobj->volume);
435                 if (ret != EFI_SUCCESS)
436                         return ret;
437         }
438         diskobj->ops = block_io_disk_template;
439         diskobj->ifname = if_typename;
440         diskobj->dev_index = dev_index;
441         diskobj->desc = desc;
442
443         /* Fill in EFI IO Media info (for read/write callbacks) */
444         diskobj->media.removable_media = desc->removable;
445         diskobj->media.media_present = 1;
446         /*
447          * MediaID is just an arbitrary counter.
448          * We have to change it if the medium is removed or changed.
449          */
450         diskobj->media.media_id = 1;
451         diskobj->media.block_size = desc->blksz;
452         diskobj->media.io_align = desc->blksz;
453         if (part)
454                 diskobj->media.logical_partition = 1;
455         diskobj->ops.media = &diskobj->media;
456         if (disk)
457                 *disk = diskobj;
458
459         EFI_PRINT("BlockIO: part %u, present %d, logical %d, removable %d"
460                   ", offset " LBAF ", last_block %llu\n",
461                   diskobj->part,
462                   diskobj->media.media_present,
463                   diskobj->media.logical_partition,
464                   diskobj->media.removable_media,
465                   diskobj->offset,
466                   diskobj->media.last_block);
467
468         /* Store first EFI system partition */
469         if (part && !efi_system_partition.if_type) {
470                 int r;
471                 struct disk_partition info;
472
473                 r = part_get_info(desc, part, &info);
474                 if (r)
475                         return EFI_DEVICE_ERROR;
476                 if (info.bootable & PART_EFI_SYSTEM_PARTITION) {
477                         efi_system_partition.if_type = desc->if_type;
478                         efi_system_partition.devnum = desc->devnum;
479                         efi_system_partition.part = part;
480                         EFI_PRINT("EFI system partition: %s %d:%d\n",
481                                   blk_get_if_type_name(desc->if_type),
482                                   desc->devnum, part);
483                 }
484         }
485         return EFI_SUCCESS;
486 error:
487         efi_delete_handle(&diskobj->header);
488         return ret;
489 }
490
491 /**
492  * efi_disk_create_partitions() - create handles and protocols for partitions
493  *
494  * Create handles and protocols for the partitions of a block device.
495  *
496  * @parent:             handle of the parent disk
497  * @desc:               block device
498  * @if_typename:        interface type
499  * @diskid:             device number
500  * @pdevname:           device name
501  * Return:              number of partitions created
502  */
503 int efi_disk_create_partitions(efi_handle_t parent, struct blk_desc *desc,
504                                const char *if_typename, int diskid,
505                                const char *pdevname)
506 {
507         int disks = 0;
508         char devname[32] = { 0 }; /* dp->str is u16[32] long */
509         int part;
510         struct efi_device_path *dp = NULL;
511         efi_status_t ret;
512         struct efi_handler *handler;
513
514         /* Get the device path of the parent */
515         ret = efi_search_protocol(parent, &efi_guid_device_path, &handler);
516         if (ret == EFI_SUCCESS)
517                 dp = handler->protocol_interface;
518
519         /* Add devices for each partition */
520         for (part = 1; part <= MAX_SEARCH_PARTITIONS; part++) {
521                 struct disk_partition info;
522
523                 if (part_get_info(desc, part, &info))
524                         continue;
525                 snprintf(devname, sizeof(devname), "%s:%d", pdevname,
526                          part);
527                 ret = efi_disk_add_dev(parent, dp, if_typename, desc, diskid,
528                                        &info, part, NULL);
529                 if (ret != EFI_SUCCESS) {
530                         log_err("Adding partition %s failed\n", pdevname);
531                         continue;
532                 }
533                 disks++;
534         }
535
536         return disks;
537 }
538
539 /**
540  * efi_disk_register() - register block devices
541  *
542  * U-Boot doesn't have a list of all online disk devices. So when running our
543  * EFI payload, we scan through all of the potentially available ones and
544  * store them in our object pool.
545  *
546  * This function is called in efi_init_obj_list().
547  *
548  * TODO([email protected]): Actually with CONFIG_BLK, U-Boot does have this.
549  * Consider converting the code to look up devices as needed. The EFI device
550  * could be a child of the UCLASS_BLK block device, perhaps.
551  *
552  * Return:      status code
553  */
554 efi_status_t efi_disk_register(void)
555 {
556         struct efi_disk_obj *disk;
557         int disks = 0;
558         efi_status_t ret;
559 #ifdef CONFIG_BLK
560         struct udevice *dev;
561
562         for (uclass_first_device_check(UCLASS_BLK, &dev); dev;
563              uclass_next_device_check(&dev)) {
564                 struct blk_desc *desc = dev_get_uclass_plat(dev);
565                 const char *if_typename = blk_get_if_type_name(desc->if_type);
566
567                 /* Add block device for the full device */
568                 log_info("Scanning disk %s...\n", dev->name);
569                 ret = efi_disk_add_dev(NULL, NULL, if_typename,
570                                         desc, desc->devnum, NULL, 0, &disk);
571                 if (ret == EFI_NOT_READY) {
572                         log_notice("Disk %s not ready\n", dev->name);
573                         continue;
574                 }
575                 if (ret) {
576                         log_err("ERROR: failure to add disk device %s, r = %lu\n",
577                                 dev->name, ret & ~EFI_ERROR_MASK);
578                         return ret;
579                 }
580                 disks++;
581
582                 /* Partitions show up as block devices in EFI */
583                 disks += efi_disk_create_partitions(
584                                         &disk->header, desc, if_typename,
585                                         desc->devnum, dev->name);
586         }
587 #else
588         int i, if_type;
589
590         /* Search for all available disk devices */
591         for (if_type = 0; if_type < IF_TYPE_COUNT; if_type++) {
592                 const struct blk_driver *cur_drvr;
593                 const char *if_typename;
594
595                 cur_drvr = blk_driver_lookup_type(if_type);
596                 if (!cur_drvr)
597                         continue;
598
599                 if_typename = cur_drvr->if_typename;
600                 log_info("Scanning disks on %s...\n", if_typename);
601                 for (i = 0; i < 4; i++) {
602                         struct blk_desc *desc;
603                         char devname[32] = { 0 }; /* dp->str is u16[32] long */
604
605                         desc = blk_get_devnum_by_type(if_type, i);
606                         if (!desc)
607                                 continue;
608                         if (desc->type == DEV_TYPE_UNKNOWN)
609                                 continue;
610
611                         snprintf(devname, sizeof(devname), "%s%d",
612                                  if_typename, i);
613
614                         /* Add block device for the full device */
615                         ret = efi_disk_add_dev(NULL, NULL, if_typename, desc,
616                                                i, NULL, 0, &disk);
617                         if (ret == EFI_NOT_READY) {
618                                 log_notice("Disk %s not ready\n", devname);
619                                 continue;
620                         }
621                         if (ret) {
622                                 log_err("ERROR: failure to add disk device %s, r = %lu\n",
623                                         devname, ret & ~EFI_ERROR_MASK);
624                                 return ret;
625                         }
626                         disks++;
627
628                         /* Partitions show up as block devices in EFI */
629                         disks += efi_disk_create_partitions
630                                                 (&disk->header, desc,
631                                                  if_typename, i, devname);
632                 }
633         }
634 #endif
635         log_info("Found %d disks\n", disks);
636
637         return EFI_SUCCESS;
638 }
639
640 /**
641  * efi_disk_is_system_part() - check if handle refers to an EFI system partition
642  *
643  * @handle:     handle of partition
644  *
645  * Return:      true if handle refers to an EFI system partition
646  */
647 bool efi_disk_is_system_part(efi_handle_t handle)
648 {
649         struct efi_handler *handler;
650         struct efi_disk_obj *diskobj;
651         struct disk_partition info;
652         efi_status_t ret;
653         int r;
654
655         /* check if this is a block device */
656         ret = efi_search_protocol(handle, &efi_block_io_guid, &handler);
657         if (ret != EFI_SUCCESS)
658                 return false;
659
660         diskobj = container_of(handle, struct efi_disk_obj, header);
661
662         r = part_get_info(diskobj->desc, diskobj->part, &info);
663         if (r)
664                 return false;
665
666         return !!(info.bootable & PART_EFI_SYSTEM_PARTITION);
667 }
This page took 0.101101 seconds and 4 git commands to generate.