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