Indentation fix, cleanup.
[AROS.git] / arch / all-pc / boot / grub2-aros / grub-core / disk / efi / efidisk.c
blob60a6d3c507edd50ff029338d022ec1647dbbf8b6
1 /*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2006,2007,2008 Free Software Foundation, Inc.
5 * GRUB is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * GRUB is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
19 #include <grub/disk.h>
20 #include <grub/partition.h>
21 #include <grub/mm.h>
22 #include <grub/types.h>
23 #include <grub/misc.h>
24 #include <grub/err.h>
25 #include <grub/term.h>
26 #include <grub/efi/api.h>
27 #include <grub/efi/efi.h>
28 #include <grub/efi/disk.h>
30 struct grub_efidisk_data
32 grub_efi_handle_t handle;
33 grub_efi_device_path_t *device_path;
34 grub_efi_device_path_t *last_device_path;
35 grub_efi_block_io_t *block_io;
36 struct grub_efidisk_data *next;
39 /* GUID. */
40 static grub_efi_guid_t block_io_guid = GRUB_EFI_BLOCK_IO_GUID;
42 static struct grub_efidisk_data *fd_devices;
43 static struct grub_efidisk_data *hd_devices;
44 static struct grub_efidisk_data *cd_devices;
46 /* Duplicate a device path. */
47 static grub_efi_device_path_t *
48 duplicate_device_path (const grub_efi_device_path_t *dp)
50 grub_efi_device_path_t *p;
51 grub_size_t total_size = 0;
53 for (p = (grub_efi_device_path_t *) dp;
55 p = GRUB_EFI_NEXT_DEVICE_PATH (p))
57 total_size += GRUB_EFI_DEVICE_PATH_LENGTH (p);
58 if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (p))
59 break;
62 p = grub_malloc (total_size);
63 if (! p)
64 return 0;
66 grub_memcpy (p, dp, total_size);
67 return p;
70 /* Return the device path node right before the end node. */
71 static grub_efi_device_path_t *
72 find_last_device_path (const grub_efi_device_path_t *dp)
74 grub_efi_device_path_t *next, *p;
76 if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp))
77 return 0;
79 for (p = (grub_efi_device_path_t *) dp, next = GRUB_EFI_NEXT_DEVICE_PATH (p);
80 ! GRUB_EFI_END_ENTIRE_DEVICE_PATH (next);
81 p = next, next = GRUB_EFI_NEXT_DEVICE_PATH (next))
84 return p;
87 static struct grub_efidisk_data *
88 make_devices (void)
90 grub_efi_uintn_t num_handles;
91 grub_efi_handle_t *handles;
92 grub_efi_handle_t *handle;
93 struct grub_efidisk_data *devices = 0;
95 /* Find handles which support the disk io interface. */
96 handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &block_io_guid,
97 0, &num_handles);
98 if (! handles)
99 return 0;
101 /* Make a linked list of devices. */
102 for (handle = handles; num_handles--; handle++)
104 grub_efi_device_path_t *dp;
105 grub_efi_device_path_t *ldp;
106 struct grub_efidisk_data *d;
107 grub_efi_block_io_t *bio;
109 dp = grub_efi_get_device_path (*handle);
110 if (! dp)
111 continue;
113 ldp = find_last_device_path (dp);
114 if (! ldp)
115 /* This is empty. Why? */
116 continue;
118 bio = grub_efi_open_protocol (*handle, &block_io_guid,
119 GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
120 if (! bio)
121 /* This should not happen... Why? */
122 continue;
124 d = grub_malloc (sizeof (*d));
125 if (! d)
127 /* Uggh. */
128 grub_free (handles);
129 return 0;
132 d->handle = *handle;
133 d->device_path = dp;
134 d->last_device_path = ldp;
135 d->block_io = bio;
136 d->next = devices;
137 devices = d;
140 grub_free (handles);
142 return devices;
145 /* Find the parent device. */
146 static struct grub_efidisk_data *
147 find_parent_device (struct grub_efidisk_data *devices,
148 struct grub_efidisk_data *d)
150 grub_efi_device_path_t *dp, *ldp;
151 struct grub_efidisk_data *parent;
153 dp = duplicate_device_path (d->device_path);
154 if (! dp)
155 return 0;
157 ldp = find_last_device_path (dp);
158 ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
159 ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
160 ldp->length = sizeof (*ldp);
162 for (parent = devices; parent; parent = parent->next)
164 /* Ignore itself. */
165 if (parent == d)
166 continue;
168 if (grub_efi_compare_device_paths (parent->device_path, dp) == 0)
169 break;
172 grub_free (dp);
173 return parent;
176 static int
177 is_child (struct grub_efidisk_data *child,
178 struct grub_efidisk_data *parent)
180 grub_efi_device_path_t *dp, *ldp;
181 int ret;
183 dp = duplicate_device_path (child->device_path);
184 if (! dp)
185 return 0;
187 ldp = find_last_device_path (dp);
188 ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
189 ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
190 ldp->length = sizeof (*ldp);
192 ret = (grub_efi_compare_device_paths (dp, parent->device_path) == 0);
193 grub_free (dp);
194 return ret;
197 #define FOR_CHILDREN(p, dev) for (p = dev; p; p = p->next) if (is_child (p, d))
199 /* Add a device into a list of devices in an ascending order. */
200 static void
201 add_device (struct grub_efidisk_data **devices, struct grub_efidisk_data *d)
203 struct grub_efidisk_data **p;
204 struct grub_efidisk_data *n;
206 for (p = devices; *p; p = &((*p)->next))
208 int ret;
210 ret = grub_efi_compare_device_paths (find_last_device_path ((*p)->device_path),
211 find_last_device_path (d->device_path));
212 if (ret == 0)
213 ret = grub_efi_compare_device_paths ((*p)->device_path,
214 d->device_path);
215 if (ret == 0)
216 return;
217 else if (ret > 0)
218 break;
221 n = grub_malloc (sizeof (*n));
222 if (! n)
223 return;
225 grub_memcpy (n, d, sizeof (*n));
226 n->next = (*p);
227 (*p) = n;
230 /* Name the devices. */
231 static void
232 name_devices (struct grub_efidisk_data *devices)
234 struct grub_efidisk_data *d;
236 /* First, identify devices by media device paths. */
237 for (d = devices; d; d = d->next)
239 grub_efi_device_path_t *dp;
241 dp = d->last_device_path;
242 if (! dp)
243 continue;
245 if (GRUB_EFI_DEVICE_PATH_TYPE (dp) == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE)
247 int is_hard_drive = 0;
249 switch (GRUB_EFI_DEVICE_PATH_SUBTYPE (dp))
251 case GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE:
252 is_hard_drive = 1;
253 /* Fall through by intention. */
254 case GRUB_EFI_CDROM_DEVICE_PATH_SUBTYPE:
256 struct grub_efidisk_data *parent, *parent2;
258 parent = find_parent_device (devices, d);
259 if (!parent)
261 #ifdef DEBUG_NAMES
262 grub_printf ("skipping orphaned partition: ");
263 grub_efi_print_device_path (d->device_path);
264 #endif
265 break;
267 parent2 = find_parent_device (devices, parent);
268 if (parent2)
270 #ifdef DEBUG_NAMES
271 grub_printf ("skipping subpartition: ");
272 grub_efi_print_device_path (d->device_path);
273 #endif
274 /* Mark itself as used. */
275 d->last_device_path = 0;
276 break;
278 if (!parent->last_device_path)
280 d->last_device_path = 0;
281 break;
283 if (is_hard_drive)
285 #ifdef DEBUG_NAMES
286 grub_printf ("adding a hard drive by a partition: ");
287 grub_efi_print_device_path (parent->device_path);
288 #endif
289 add_device (&hd_devices, parent);
291 else
293 #ifdef DEBUG_NAMES
294 grub_printf ("adding a cdrom by a partition: ");
295 grub_efi_print_device_path (parent->device_path);
296 #endif
297 add_device (&cd_devices, parent);
300 /* Mark the parent as used. */
301 parent->last_device_path = 0;
303 /* Mark itself as used. */
304 d->last_device_path = 0;
305 break;
307 default:
308 #ifdef DEBUG_NAMES
309 grub_printf ("skipping other type: ");
310 grub_efi_print_device_path (d->device_path);
311 #endif
312 /* For now, ignore the others. */
313 break;
316 else
318 #ifdef DEBUG_NAMES
319 grub_printf ("skipping non-media: ");
320 grub_efi_print_device_path (d->device_path);
321 #endif
325 /* Let's see what can be added more. */
326 for (d = devices; d; d = d->next)
328 grub_efi_device_path_t *dp;
329 grub_efi_block_io_media_t *m;
330 int is_floppy = 0;
332 dp = d->last_device_path;
333 if (! dp)
334 continue;
336 /* Ghosts proudly presented by Apple. */
337 if (GRUB_EFI_DEVICE_PATH_TYPE (dp) == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE
338 && GRUB_EFI_DEVICE_PATH_SUBTYPE (dp)
339 == GRUB_EFI_VENDOR_MEDIA_DEVICE_PATH_SUBTYPE)
341 grub_efi_vendor_device_path_t *vendor = (grub_efi_vendor_device_path_t *) dp;
342 const struct grub_efi_guid apple = GRUB_EFI_VENDOR_APPLE_GUID;
344 if (vendor->header.length == sizeof (*vendor)
345 && grub_memcmp (&vendor->vendor_guid, &apple,
346 sizeof (vendor->vendor_guid)) == 0
347 && find_parent_device (devices, d))
348 continue;
351 m = d->block_io->media;
352 if (GRUB_EFI_DEVICE_PATH_TYPE (dp) == GRUB_EFI_ACPI_DEVICE_PATH_TYPE
353 && GRUB_EFI_DEVICE_PATH_SUBTYPE (dp)
354 == GRUB_EFI_ACPI_DEVICE_PATH_SUBTYPE)
356 grub_efi_acpi_device_path_t *acpi
357 = (grub_efi_acpi_device_path_t *) dp;
358 /* Floppy EISA ID. */
359 if (acpi->hid == 0x60441d0 || acpi->hid == 0x70041d0
360 || acpi->hid == 0x70141d1)
361 is_floppy = 1;
363 if (is_floppy)
365 #ifdef DEBUG_NAMES
366 grub_printf ("adding a floppy: ");
367 grub_efi_print_device_path (d->device_path);
368 #endif
369 add_device (&fd_devices, d);
371 else if (m->read_only && m->block_size > GRUB_DISK_SECTOR_SIZE)
373 /* This check is too heuristic, but assume that this is a
374 CDROM drive. */
375 #ifdef DEBUG_NAMES
376 grub_printf ("adding a cdrom by guessing: ");
377 grub_efi_print_device_path (d->device_path);
378 #endif
379 add_device (&cd_devices, d);
381 else
383 /* The default is a hard drive. */
384 #ifdef DEBUG_NAMES
385 grub_printf ("adding a hard drive by guessing: ");
386 grub_efi_print_device_path (d->device_path);
387 #endif
388 add_device (&hd_devices, d);
393 static void
394 free_devices (struct grub_efidisk_data *devices)
396 struct grub_efidisk_data *p, *q;
398 for (p = devices; p; p = q)
400 q = p->next;
401 grub_free (p);
405 /* Enumerate all disks to name devices. */
406 static void
407 enumerate_disks (void)
409 struct grub_efidisk_data *devices;
411 devices = make_devices ();
412 if (! devices)
413 return;
415 name_devices (devices);
416 free_devices (devices);
419 static int
420 grub_efidisk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data,
421 grub_disk_pull_t pull)
423 struct grub_efidisk_data *d;
424 char buf[16];
425 int count;
427 switch (pull)
429 case GRUB_DISK_PULL_NONE:
430 for (d = hd_devices, count = 0; d; d = d->next, count++)
432 grub_snprintf (buf, sizeof (buf), "hd%d", count);
433 grub_dprintf ("efidisk", "iterating %s\n", buf);
434 if (hook (buf, hook_data))
435 return 1;
437 break;
438 case GRUB_DISK_PULL_REMOVABLE:
439 for (d = fd_devices, count = 0; d; d = d->next, count++)
441 grub_snprintf (buf, sizeof (buf), "fd%d", count);
442 grub_dprintf ("efidisk", "iterating %s\n", buf);
443 if (hook (buf, hook_data))
444 return 1;
447 for (d = cd_devices, count = 0; d; d = d->next, count++)
449 grub_snprintf (buf, sizeof (buf), "cd%d", count);
450 grub_dprintf ("efidisk", "iterating %s\n", buf);
451 if (hook (buf, hook_data))
452 return 1;
454 break;
455 default:
456 return 0;
459 return 0;
462 static int
463 get_drive_number (const char *name)
465 unsigned long drive;
467 if ((name[0] != 'f' && name[0] != 'h' && name[0] != 'c') || name[1] != 'd')
468 goto fail;
470 drive = grub_strtoul (name + 2, 0, 10);
471 if (grub_errno != GRUB_ERR_NONE)
472 goto fail;
474 return (int) drive ;
476 fail:
477 grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a efidisk");
478 return -1;
481 static struct grub_efidisk_data *
482 get_device (struct grub_efidisk_data *devices, int num)
484 struct grub_efidisk_data *d;
486 for (d = devices; d && num; d = d->next, num--)
489 if (num == 0)
490 return d;
492 return 0;
495 static grub_err_t
496 grub_efidisk_open (const char *name, struct grub_disk *disk)
498 int num;
499 struct grub_efidisk_data *d = 0;
500 grub_efi_block_io_media_t *m;
502 grub_dprintf ("efidisk", "opening %s\n", name);
504 num = get_drive_number (name);
505 if (num < 0)
506 return grub_errno;
508 switch (name[0])
510 case 'f':
511 d = get_device (fd_devices, num);
512 break;
513 case 'c':
514 d = get_device (cd_devices, num);
515 break;
516 case 'h':
517 d = get_device (hd_devices, num);
518 break;
519 default:
520 /* Never reach here. */
521 break;
524 if (! d)
525 return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such device");
527 disk->id = ((num << GRUB_CHAR_BIT) | name[0]);
528 m = d->block_io->media;
529 /* FIXME: Probably it is better to store the block size in the disk,
530 and total sectors should be replaced with total blocks. */
531 grub_dprintf ("efidisk", "m = %p, last block = %llx, block size = %x\n",
532 m, (unsigned long long) m->last_block, m->block_size);
533 disk->total_sectors = m->last_block + 1;
534 /* Don't increase this value due to bug in some EFI. */
535 disk->max_agglomerate = 0xa0000 >> (GRUB_DISK_CACHE_BITS + GRUB_DISK_SECTOR_BITS);
536 if (m->block_size & (m->block_size - 1) || !m->block_size)
537 return grub_error (GRUB_ERR_IO, "invalid sector size %d",
538 m->block_size);
539 for (disk->log_sector_size = 0;
540 (1U << disk->log_sector_size) < m->block_size;
541 disk->log_sector_size++);
542 disk->data = d;
544 grub_dprintf ("efidisk", "opening %s succeeded\n", name);
546 return GRUB_ERR_NONE;
549 static void
550 grub_efidisk_close (struct grub_disk *disk __attribute__ ((unused)))
552 /* EFI disks do not allocate extra memory, so nothing to do here. */
553 grub_dprintf ("efidisk", "closing %s\n", disk->name);
556 static grub_efi_status_t
557 grub_efidisk_readwrite (struct grub_disk *disk, grub_disk_addr_t sector,
558 grub_size_t size, char *buf, int wr)
560 struct grub_efidisk_data *d;
561 grub_efi_block_io_t *bio;
563 d = disk->data;
564 bio = d->block_io;
566 return efi_call_5 ((wr ? bio->write_blocks : bio->read_blocks), bio,
567 bio->media->media_id,
568 (grub_efi_uint64_t) sector,
569 (grub_efi_uintn_t) size << disk->log_sector_size,
570 buf);
573 static grub_err_t
574 grub_efidisk_read (struct grub_disk *disk, grub_disk_addr_t sector,
575 grub_size_t size, char *buf)
577 grub_efi_status_t status;
579 grub_dprintf ("efidisk",
580 "reading 0x%lx sectors at the sector 0x%llx from %s\n",
581 (unsigned long) size, (unsigned long long) sector, disk->name);
583 status = grub_efidisk_readwrite (disk, sector, size, buf, 0);
585 if (status != GRUB_EFI_SUCCESS)
586 return grub_error (GRUB_ERR_READ_ERROR,
587 N_("failure reading sector 0x%llx from `%s'"),
588 (unsigned long long) sector,
589 disk->name);
591 return GRUB_ERR_NONE;
594 static grub_err_t
595 grub_efidisk_write (struct grub_disk *disk, grub_disk_addr_t sector,
596 grub_size_t size, const char *buf)
598 grub_efi_status_t status;
600 grub_dprintf ("efidisk",
601 "writing 0x%lx sectors at the sector 0x%llx to %s\n",
602 (unsigned long) size, (unsigned long long) sector, disk->name);
604 status = grub_efidisk_readwrite (disk, sector, size, (char *) buf, 1);
606 if (status != GRUB_EFI_SUCCESS)
607 return grub_error (GRUB_ERR_WRITE_ERROR,
608 N_("failure writing sector 0x%llx to `%s'"),
609 (unsigned long long) sector, disk->name);
611 return GRUB_ERR_NONE;
614 static struct grub_disk_dev grub_efidisk_dev =
616 .name = "efidisk",
617 .id = GRUB_DISK_DEVICE_EFIDISK_ID,
618 .iterate = grub_efidisk_iterate,
619 .open = grub_efidisk_open,
620 .close = grub_efidisk_close,
621 .read = grub_efidisk_read,
622 .write = grub_efidisk_write,
623 .next = 0
626 void
627 grub_efidisk_fini (void)
629 free_devices (fd_devices);
630 free_devices (hd_devices);
631 free_devices (cd_devices);
632 fd_devices = 0;
633 hd_devices = 0;
634 cd_devices = 0;
635 grub_disk_dev_unregister (&grub_efidisk_dev);
638 void
639 grub_efidisk_init (void)
641 grub_disk_firmware_fini = grub_efidisk_fini;
643 enumerate_disks ();
644 grub_disk_dev_register (&grub_efidisk_dev);
647 /* Some utility functions to map GRUB devices with EFI devices. */
648 grub_efi_handle_t
649 grub_efidisk_get_device_handle (grub_disk_t disk)
651 struct grub_efidisk_data *d;
652 char type;
654 if (disk->dev->id != GRUB_DISK_DEVICE_EFIDISK_ID)
655 return 0;
657 d = disk->data;
658 type = disk->name[0];
660 switch (type)
662 case 'f':
663 /* This is the simplest case. */
664 return d->handle;
666 case 'c':
667 /* FIXME: probably this is not correct. */
668 return d->handle;
670 case 'h':
671 /* If this is the whole disk, just return its own data. */
672 if (! disk->partition)
673 return d->handle;
675 /* Otherwise, we must query the corresponding device to the firmware. */
677 struct grub_efidisk_data *devices;
678 grub_efi_handle_t handle = 0;
679 struct grub_efidisk_data *c;
681 devices = make_devices ();
682 FOR_CHILDREN (c, devices)
684 grub_efi_hard_drive_device_path_t *hd;
686 hd = (grub_efi_hard_drive_device_path_t *) c->last_device_path;
688 if ((GRUB_EFI_DEVICE_PATH_TYPE (c->last_device_path)
689 == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE)
690 && (GRUB_EFI_DEVICE_PATH_SUBTYPE (c->last_device_path)
691 == GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE)
692 && (grub_partition_get_start (disk->partition)
693 == (hd->partition_start << (disk->log_sector_size
694 - GRUB_DISK_SECTOR_BITS)))
695 && (grub_partition_get_len (disk->partition)
696 == (hd->partition_size << (disk->log_sector_size
697 - GRUB_DISK_SECTOR_BITS))))
699 handle = c->handle;
700 break;
704 free_devices (devices);
706 if (handle != 0)
707 return handle;
709 break;
711 default:
712 break;
715 return 0;
718 #define NEEDED_BUFLEN sizeof ("XdXXXXXXXXXX")
719 static inline int
720 get_diskname_from_path_real (const grub_efi_device_path_t *path,
721 struct grub_efidisk_data *head,
722 char *buf)
724 int count = 0;
725 struct grub_efidisk_data *d;
726 for (d = head, count = 0; d; d = d->next, count++)
727 if (grub_efi_compare_device_paths (d->device_path, path) == 0)
729 grub_snprintf (buf, NEEDED_BUFLEN - 1, "d%d", count);
730 return 1;
732 return 0;
735 static inline int
736 get_diskname_from_path (const grub_efi_device_path_t *path,
737 char *buf)
739 if (get_diskname_from_path_real (path, hd_devices, buf + 1))
741 buf[0] = 'h';
742 return 1;
745 if (get_diskname_from_path_real (path, fd_devices, buf + 1))
747 buf[0] = 'f';
748 return 1;
751 if (get_diskname_from_path_real (path, cd_devices, buf + 1))
753 buf[0] = 'c';
754 return 1;
756 return 0;
759 /* Context for grub_efidisk_get_device_name. */
760 struct grub_efidisk_get_device_name_ctx
762 char *partition_name;
763 grub_efi_hard_drive_device_path_t *hd;
766 /* Helper for grub_efidisk_get_device_name.
767 Find the identical partition. */
768 static int
769 grub_efidisk_get_device_name_iter (grub_disk_t disk,
770 const grub_partition_t part, void *data)
772 struct grub_efidisk_get_device_name_ctx *ctx = data;
774 if (grub_partition_get_start (part)
775 == (ctx->hd->partition_start << (disk->log_sector_size
776 - GRUB_DISK_SECTOR_BITS))
777 && grub_partition_get_len (part)
778 == (ctx->hd->partition_size << (disk->log_sector_size
779 - GRUB_DISK_SECTOR_BITS)))
781 ctx->partition_name = grub_partition_get_name (part);
782 return 1;
785 return 0;
788 char *
789 grub_efidisk_get_device_name (grub_efi_handle_t *handle)
791 grub_efi_device_path_t *dp, *ldp;
792 char device_name[NEEDED_BUFLEN];
794 dp = grub_efi_get_device_path (handle);
795 if (! dp)
796 return 0;
798 ldp = find_last_device_path (dp);
799 if (! ldp)
800 return 0;
802 if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE
803 && (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_CDROM_DEVICE_PATH_SUBTYPE
804 || GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE))
806 struct grub_efidisk_get_device_name_ctx ctx;
807 char *dev_name;
808 grub_efi_device_path_t *dup_dp;
809 grub_disk_t parent = 0;
811 /* It is necessary to duplicate the device path so that GRUB
812 can overwrite it. */
813 dup_dp = duplicate_device_path (dp);
814 if (! dup_dp)
815 return 0;
817 while (1)
819 grub_efi_device_path_t *dup_ldp;
820 dup_ldp = find_last_device_path (dup_dp);
821 if (!(GRUB_EFI_DEVICE_PATH_TYPE (dup_ldp) == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE
822 && (GRUB_EFI_DEVICE_PATH_SUBTYPE (dup_ldp) == GRUB_EFI_CDROM_DEVICE_PATH_SUBTYPE
823 || GRUB_EFI_DEVICE_PATH_SUBTYPE (dup_ldp) == GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE)))
824 break;
826 dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
827 dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
828 dup_ldp->length = sizeof (*dup_ldp);
831 if (!get_diskname_from_path (dup_dp, device_name))
833 grub_free (dup_dp);
834 return 0;
837 parent = grub_disk_open (device_name);
838 grub_free (dup_dp);
840 if (! parent)
841 return 0;
843 /* Find a partition which matches the hard drive device path. */
844 ctx.partition_name = NULL;
845 ctx.hd = (grub_efi_hard_drive_device_path_t *) ldp;
846 if (ctx.hd->partition_start == 0
847 && (ctx.hd->partition_size << (parent->log_sector_size
848 - GRUB_DISK_SECTOR_BITS))
849 == grub_disk_get_size (parent))
851 dev_name = grub_strdup (parent->name);
853 else
855 grub_partition_iterate (parent, grub_efidisk_get_device_name_iter,
856 &ctx);
858 if (! ctx.partition_name)
860 /* No partition found. In most cases partition is embed in
861 the root path anyway, so this is not critical.
862 This happens only if partition is on partmap that GRUB
863 doesn't need to access root.
865 grub_disk_close (parent);
866 return grub_strdup (device_name);
869 dev_name = grub_xasprintf ("%s,%s", parent->name,
870 ctx.partition_name);
871 grub_free (ctx.partition_name);
873 grub_disk_close (parent);
875 return dev_name;
877 /* This may be guessed device - floppy, cdrom or entire disk. */
878 if (!get_diskname_from_path (dp, device_name))
879 return 0;
880 return grub_strdup (device_name);