/* Name the devices. */ static void name_devices (struct grub_efidisk_data *devices) { struct grub_efidisk_data *d; /* Let's see what can be added more. */ for (d = devices; d; d = d->next) { grub_efi_device_path_t *dp; grub_efi_block_io_media_t *m; dp = d->last_device_path; if (! dp) continue; m = d->block_io->media; if (GRUB_EFI_DEVICE_PATH_TYPE(dp) == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE) { /* XXX FIXME this won't work if we see write-protected disks with * 4k sectors */ if (m->read_only && m->block_size > 0x200) { add_device (&cd_devices, d); } else { add_device (&hd_devices, d); } } if (GRUB_EFI_DEVICE_PATH_TYPE(dp) == GRUB_EFI_ACPI_DEVICE_PATH_TYPE) { add_device (&fd_devices, d); } } }
char * grub_efi_get_filename (grub_efi_device_path_t *dp) { char *name = 0; while (1) { grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp); grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp); if (type == GRUB_EFI_END_DEVICE_PATH_TYPE) break; else if (type == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE && subtype == GRUB_EFI_FILE_PATH_DEVICE_PATH_SUBTYPE) { grub_efi_file_path_device_path_t *fp; grub_efi_uint16_t len; char *p; grub_size_t size; if (name) { size = grub_strlen (name); name[size] = '/'; size++; } else size = 0; len = ((GRUB_EFI_DEVICE_PATH_LENGTH (dp) - 4) / sizeof (grub_efi_char16_t)); p = grub_realloc (name, size + len * 4 + 1); if (! p) { grub_free (name); return 0; } name = p; fp = (grub_efi_file_path_device_path_t *) dp; *grub_utf16_to_utf8 ((grub_uint8_t *) name + size, fp->path_name, len) = '\0'; } dp = GRUB_EFI_NEXT_DEVICE_PATH (dp); } if (name) { /* EFI breaks paths with backslashes. */ char *p; for (p = name; *p; p++) if (*p == '\\') *p = '/'; } return name; }
/* Compare device paths. */ int grub_efi_compare_device_paths (const grub_efi_device_path_t *dp1, const grub_efi_device_path_t *dp2) { if (! dp1 || ! dp2) /* Return non-zero. */ return 1; while (1) { grub_efi_uint8_t type1, type2; grub_efi_uint8_t subtype1, subtype2; grub_efi_uint16_t len1, len2; int ret; type1 = GRUB_EFI_DEVICE_PATH_TYPE (dp1); type2 = GRUB_EFI_DEVICE_PATH_TYPE (dp2); if (type1 != type2) return (int) type2 - (int) type1; subtype1 = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp1); subtype2 = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp2); if (subtype1 != subtype2) return (int) subtype1 - (int) subtype2; len1 = GRUB_EFI_DEVICE_PATH_LENGTH (dp1); len2 = GRUB_EFI_DEVICE_PATH_LENGTH (dp2); if (len1 != len2) return (int) len1 - (int) len2; ret = grub_memcmp (dp1, dp2, len1); if (ret != 0) return ret; if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp1)) break; dp1 = (grub_efi_device_path_t *) ((char *) dp1 + len1); dp2 = (grub_efi_device_path_t *) ((char *) dp2 + len2); } return 0; }
/* Some utility functions to map GRUB devices with EFI devices. */ grub_efi_handle_t grub_efidisk_get_current_bdev_handle (void) { struct grub_efidisk_data *d; d = get_device_from_drive (current_drive); if (d == NULL) return NULL; if (current_drive == GRUB_INVALID_DRIVE) return NULL; if (current_drive == cdrom_drive) return d->handle; if (! (current_drive & 0x80)) return d->handle; /* If this is the whole disk, just return its own data. */ else if (current_partition == 0xFFFFFF) return d->handle; /* Otherwise, we must query the corresponding device to the firmware. */ else { struct grub_efidisk_data *devices; grub_efi_handle_t handle = 0; auto int find_partition (struct grub_efidisk_data *c); int find_partition (struct grub_efidisk_data *c) { grub_efi_hard_drive_device_path_t hd; grub_memcpy (&hd, c->last_device_path, sizeof (hd)); if ((GRUB_EFI_DEVICE_PATH_TYPE (c->last_device_path) == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE) && (GRUB_EFI_DEVICE_PATH_SUBTYPE (c->last_device_path) == GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE) && (part_start == hd.partition_start)) { handle = c->handle; return 1; } return 0; } devices = make_devices (); iterate_child_devices (devices, d, find_partition); free_devices (devices); if (handle != 0) return handle; }
/* Print the chain of Device Path nodes. This is mainly for debugging. */ void grub_efi_print_device_path (grub_efi_device_path_t *dp) { while (1) { grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp); grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp); grub_efi_uint16_t len = GRUB_EFI_DEVICE_PATH_LENGTH (dp); switch (type) { case GRUB_EFI_END_DEVICE_PATH_TYPE: switch (subtype) { case GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE: grub_printf ("/EndEntire\n"); //grub_putchar ('\n'); break; case GRUB_EFI_END_THIS_DEVICE_PATH_SUBTYPE: grub_printf ("/EndThis\n"); //grub_putchar ('\n'); break; default: grub_printf ("/EndUnknown(%x)\n", (unsigned) subtype); break; } break; case GRUB_EFI_HARDWARE_DEVICE_PATH_TYPE: switch (subtype) { case GRUB_EFI_PCI_DEVICE_PATH_SUBTYPE: { grub_efi_pci_device_path_t pci; grub_memcpy (&pci, dp, len); grub_printf ("/PCI(%x,%x)", (unsigned) pci.function, (unsigned) pci.device); } break; case GRUB_EFI_PCCARD_DEVICE_PATH_SUBTYPE: { grub_efi_pccard_device_path_t pccard; grub_memcpy (&pccard, dp, len); grub_printf ("/PCCARD(%x)", (unsigned) pccard.function); } break; case GRUB_EFI_MEMORY_MAPPED_DEVICE_PATH_SUBTYPE: { grub_efi_memory_mapped_device_path_t mmapped; grub_memcpy (&mmapped, dp, len); grub_printf ("/MMap(%x,%llx,%llx)", (unsigned) mmapped.memory_type, (unsigned long long) mmapped.start_address, (unsigned long long) mmapped.end_address); } break; case GRUB_EFI_VENDOR_DEVICE_PATH_SUBTYPE: { grub_efi_vendor_device_path_t vendor; grub_memcpy (&vendor, dp, sizeof (vendor)); grub_printf ("/Vendor(%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x)", (unsigned) vendor.vendor_guid.data1, (unsigned) vendor.vendor_guid.data2, (unsigned) vendor.vendor_guid.data3, (unsigned) vendor.vendor_guid.data4[0], (unsigned) vendor.vendor_guid.data4[1], (unsigned) vendor.vendor_guid.data4[2], (unsigned) vendor.vendor_guid.data4[3], (unsigned) vendor.vendor_guid.data4[4], (unsigned) vendor.vendor_guid.data4[5], (unsigned) vendor.vendor_guid.data4[6], (unsigned) vendor.vendor_guid.data4[7]); } break; case GRUB_EFI_CONTROLLER_DEVICE_PATH_SUBTYPE: { grub_efi_controller_device_path_t controller; grub_memcpy (&controller, dp, len); grub_printf ("/Ctrl(%x)", (unsigned) controller.controller_number); } break; default: grub_printf ("/UnknownHW(%x)", (unsigned) subtype); break; } break; case GRUB_EFI_ACPI_DEVICE_PATH_TYPE: switch (subtype) { case GRUB_EFI_ACPI_DEVICE_PATH_SUBTYPE: { grub_efi_acpi_device_path_t acpi; grub_memcpy (&acpi, dp, len); grub_printf ("/ACPI(%x,%x)", (unsigned) acpi.hid, (unsigned) acpi.uid); } break; case GRUB_EFI_EXPANDED_ACPI_DEVICE_PATH_SUBTYPE: { grub_efi_expanded_acpi_device_path_t eacpi; grub_memcpy (&eacpi, dp, sizeof (eacpi)); grub_printf ("/ACPI("); if (GRUB_EFI_EXPANDED_ACPI_HIDSTR (dp)[0] == '\0') grub_printf ("%x,", (unsigned) eacpi.hid); else grub_printf ("%s,", GRUB_EFI_EXPANDED_ACPI_HIDSTR (dp)); if (GRUB_EFI_EXPANDED_ACPI_UIDSTR (dp)[0] == '\0') grub_printf ("%x,", (unsigned) eacpi.uid); else grub_printf ("%s,", GRUB_EFI_EXPANDED_ACPI_UIDSTR (dp)); if (GRUB_EFI_EXPANDED_ACPI_CIDSTR (dp)[0] == '\0') grub_printf ("%x)", (unsigned) eacpi.cid); else grub_printf ("%s)", GRUB_EFI_EXPANDED_ACPI_CIDSTR (dp)); } break; default: grub_printf ("/UnknownACPI(%x)", (unsigned) subtype); break; } break; case GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE: switch (subtype) { case GRUB_EFI_ATAPI_DEVICE_PATH_SUBTYPE: { grub_efi_atapi_device_path_t atapi; grub_memcpy (&atapi, dp, len); grub_printf ("/ATAPI(%x,%x,%x)", (unsigned) atapi.primary_secondary, (unsigned) atapi.slave_master, (unsigned) atapi.lun); } break; case GRUB_EFI_SCSI_DEVICE_PATH_SUBTYPE: { grub_efi_scsi_device_path_t scsi; grub_memcpy (&scsi, dp, len); grub_printf ("/SCSI(%x,%x)", (unsigned) scsi.pun, (unsigned) scsi.lun); } break; case GRUB_EFI_FIBRE_CHANNEL_DEVICE_PATH_SUBTYPE: { grub_efi_fibre_channel_device_path_t fc; grub_memcpy (&fc, dp, len); grub_printf ("/FibreChannel(%llx,%llx)", (unsigned long long) fc.wwn, (unsigned long long) fc.lun); } break; case GRUB_EFI_1394_DEVICE_PATH_SUBTYPE: { grub_efi_1394_device_path_t firewire; grub_memcpy (&firewire, dp, len); grub_printf ("/1394(%llx)", (unsigned long long) firewire.guid); } break; case GRUB_EFI_USB_DEVICE_PATH_SUBTYPE: { grub_efi_usb_device_path_t usb; grub_memcpy (&usb, dp, len); grub_printf ("/USB(%x,%x)", (unsigned) usb.parent_port_number, (unsigned) usb.interface); } break; case GRUB_EFI_USB_CLASS_DEVICE_PATH_SUBTYPE: { grub_efi_usb_class_device_path_t usb_class; grub_memcpy (&usb_class, dp, len); grub_printf ("/USBClass(%x,%x,%x,%x,%x)", (unsigned) usb_class.vendor_id, (unsigned) usb_class.product_id, (unsigned) usb_class.device_class, (unsigned) usb_class.device_subclass, (unsigned) usb_class.device_protocol); } break; case GRUB_EFI_I2O_DEVICE_PATH_SUBTYPE: { grub_efi_i2o_device_path_t i2o; grub_memcpy (&i2o, dp, len); grub_printf ("/I2O(%x)", (unsigned) i2o.tid); } break; case GRUB_EFI_MAC_ADDRESS_DEVICE_PATH_SUBTYPE: { grub_efi_mac_address_device_path_t mac; grub_memcpy (&mac, dp, len); grub_printf ("/MacAddr(%02x:%02x:%02x:%02x:%02x:%02x,%x)", (unsigned) mac.mac_address[0], (unsigned) mac.mac_address[1], (unsigned) mac.mac_address[2], (unsigned) mac.mac_address[3], (unsigned) mac.mac_address[4], (unsigned) mac.mac_address[5], (unsigned) mac.if_type); } break; case GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE: { grub_efi_ipv4_device_path_t ipv4; grub_memcpy (&ipv4, dp, len); grub_printf ("/IPv4(%u.%u.%u.%u,%u.%u.%u.%u,%u,%u,%x,%x)", (unsigned) ipv4.local_ip_address[0], (unsigned) ipv4.local_ip_address[1], (unsigned) ipv4.local_ip_address[2], (unsigned) ipv4.local_ip_address[3], (unsigned) ipv4.remote_ip_address[0], (unsigned) ipv4.remote_ip_address[1], (unsigned) ipv4.remote_ip_address[2], (unsigned) ipv4.remote_ip_address[3], (unsigned) ipv4.local_port, (unsigned) ipv4.remote_port, (unsigned) ipv4.protocol, (unsigned) ipv4.static_ip_address); } break; case GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE: { grub_efi_ipv6_device_path_t ipv6; grub_memcpy (&ipv6, dp, len); grub_printf ("/IPv6(%x:%x:%x:%x:%x:%x:%x:%x,%x:%x:%x:%x:%x:%x:%x:%x,%u,%u,%x,%x)", (unsigned) ipv6.local_ip_address[0], (unsigned) ipv6.local_ip_address[1], (unsigned) ipv6.local_ip_address[2], (unsigned) ipv6.local_ip_address[3], (unsigned) ipv6.local_ip_address[4], (unsigned) ipv6.local_ip_address[5], (unsigned) ipv6.local_ip_address[6], (unsigned) ipv6.local_ip_address[7], (unsigned) ipv6.remote_ip_address[0], (unsigned) ipv6.remote_ip_address[1], (unsigned) ipv6.remote_ip_address[2], (unsigned) ipv6.remote_ip_address[3], (unsigned) ipv6.remote_ip_address[4], (unsigned) ipv6.remote_ip_address[5], (unsigned) ipv6.remote_ip_address[6], (unsigned) ipv6.remote_ip_address[7], (unsigned) ipv6.local_port, (unsigned) ipv6.remote_port, (unsigned) ipv6.protocol, (unsigned) ipv6.static_ip_address); } break; case GRUB_EFI_INFINIBAND_DEVICE_PATH_SUBTYPE: { grub_efi_infiniband_device_path_t ib; grub_memcpy (&ib, dp, len); grub_printf ("/InfiniBand(%x,%llx,%llx,%llx)", (unsigned) ib.port_gid[0], /* XXX */ (unsigned long long) ib.remote_id, (unsigned long long) ib.target_port_id, (unsigned long long) ib.device_id); } break; case GRUB_EFI_UART_DEVICE_PATH_SUBTYPE: { grub_efi_uart_device_path_t uart; grub_memcpy (&uart, dp, len); grub_printf ("/UART(%llu,%u,%x,%x)", (unsigned long long) uart.baud_rate, uart.data_bits, uart.parity, uart.stop_bits); } break; case GRUB_EFI_VENDOR_MESSAGING_DEVICE_PATH_SUBTYPE: { grub_efi_vendor_messaging_device_path_t vendor; grub_memcpy (&vendor, dp, sizeof (vendor)); grub_printf ("/Vendor(%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x)", (unsigned) vendor.vendor_guid.data1, (unsigned) vendor.vendor_guid.data2, (unsigned) vendor.vendor_guid.data3, (unsigned) vendor.vendor_guid.data4[0], (unsigned) vendor.vendor_guid.data4[1], (unsigned) vendor.vendor_guid.data4[2], (unsigned) vendor.vendor_guid.data4[3], (unsigned) vendor.vendor_guid.data4[4], (unsigned) vendor.vendor_guid.data4[5], (unsigned) vendor.vendor_guid.data4[6], (unsigned) vendor.vendor_guid.data4[7]); } break; default: grub_printf ("/UnknownMessaging(%x)", (unsigned) subtype); break; } break; case GRUB_EFI_MEDIA_DEVICE_PATH_TYPE: switch (subtype) { case GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE: { grub_efi_hard_drive_device_path_t hd; grub_memcpy (&hd, dp, len); grub_printf ("/HD(%u,%llx,%llx,%02x%02x%02x%02x%02x%02x%02x%02x,%x,%x)", hd.partition_number, (unsigned long long) hd.partition_start, (unsigned long long) hd.partition_size, (unsigned) hd.partition_signature[0], (unsigned) hd.partition_signature[1], (unsigned) hd.partition_signature[2], (unsigned) hd.partition_signature[3], (unsigned) hd.partition_signature[4], (unsigned) hd.partition_signature[5], (unsigned) hd.partition_signature[6], (unsigned) hd.partition_signature[7], (unsigned) hd.mbr_type, (unsigned) hd.signature_type); } break; case GRUB_EFI_CDROM_DEVICE_PATH_SUBTYPE: { grub_efi_cdrom_device_path_t cd; grub_memcpy (&cd, dp, len); grub_printf ("/CD(%u,%llx,%llx)", cd.boot_entry, (unsigned long long) cd.partition_start, (unsigned long long) cd.partition_size); } break; case GRUB_EFI_VENDOR_MEDIA_DEVICE_PATH_SUBTYPE: { grub_efi_vendor_media_device_path_t vendor; grub_memcpy (&vendor, dp, sizeof (vendor)); grub_printf ("/Vendor(%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x)", (unsigned) vendor.vendor_guid.data1, (unsigned) vendor.vendor_guid.data2, (unsigned) vendor.vendor_guid.data3, (unsigned) vendor.vendor_guid.data4[0], (unsigned) vendor.vendor_guid.data4[1], (unsigned) vendor.vendor_guid.data4[2], (unsigned) vendor.vendor_guid.data4[3], (unsigned) vendor.vendor_guid.data4[4], (unsigned) vendor.vendor_guid.data4[5], (unsigned) vendor.vendor_guid.data4[6], (unsigned) vendor.vendor_guid.data4[7]); } break; case GRUB_EFI_FILE_PATH_DEVICE_PATH_SUBTYPE: { grub_efi_file_path_device_path_t *fp; grub_uint8_t buf[(len - 4) * 2 + 1]; fp = (grub_efi_file_path_device_path_t *) dp; *grub_utf16_to_utf8 (buf, fp->path_name, (len - 4) / sizeof (grub_efi_char16_t)) = '\0'; grub_printf ("/File(%s)", buf); } break; case GRUB_EFI_PROTOCOL_DEVICE_PATH_SUBTYPE: { grub_efi_protocol_device_path_t proto; grub_memcpy (&proto, dp, sizeof (proto)); grub_printf ("/Protocol(%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x)", (unsigned) proto.guid.data1, (unsigned) proto.guid.data2, (unsigned) proto.guid.data3, (unsigned) proto.guid.data4[0], (unsigned) proto.guid.data4[1], (unsigned) proto.guid.data4[2], (unsigned) proto.guid.data4[3], (unsigned) proto.guid.data4[4], (unsigned) proto.guid.data4[5], (unsigned) proto.guid.data4[6], (unsigned) proto.guid.data4[7]); } break; default: grub_printf ("/UnknownMedia(%x)", (unsigned) subtype); break; } break; case GRUB_EFI_BIOS_DEVICE_PATH_TYPE: switch (subtype) { case GRUB_EFI_BIOS_DEVICE_PATH_SUBTYPE: { grub_efi_bios_device_path_t bios; grub_memcpy (&bios, dp, sizeof (bios)); grub_printf ("/BIOS(%x,%x,%s)", (unsigned) bios.device_type, (unsigned) bios.status_flags, (char *) (dp + 1)); } break; default: grub_printf ("/UnknownBIOS(%x)", (unsigned) subtype); break; } break; default: grub_printf ("/UnknownType(%x,%x)\n", (unsigned) type, (unsigned) subtype); return; break; } if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp)) break; dp = (grub_efi_device_path_t *) ((char *) dp + len); } }
/* Name the devices. */ static void name_devices (struct grub_efidisk_data *devices) { struct grub_efidisk_data *d; /* First, identify devices by media device paths. */ for (d = devices; d; d = d->next) { grub_efi_device_path_t *dp; dp = d->last_device_path; if (! dp) continue; if (GRUB_EFI_DEVICE_PATH_TYPE (dp) == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE) { int is_hard_drive = 0; switch (GRUB_EFI_DEVICE_PATH_SUBTYPE (dp)) { case GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE: is_hard_drive = 1; /* Fall through by intention. */ case GRUB_EFI_CDROM_DEVICE_PATH_SUBTYPE: { struct grub_efidisk_data *parent, *parent2; parent = find_parent_device (devices, d); if (!parent) { #ifdef DEBUG_NAMES grub_printf ("skipping orphaned partition: "); grub_efi_print_device_path (d->device_path); #endif break; } parent2 = find_parent_device (devices, parent); if (parent2) { #ifdef DEBUG_NAMES grub_printf ("skipping subpartition: "); grub_efi_print_device_path (d->device_path); #endif /* Mark itself as used. */ d->last_device_path = 0; break; } if (!parent->last_device_path) { d->last_device_path = 0; break; } if (is_hard_drive) { #ifdef DEBUG_NAMES grub_printf ("adding a hard drive by a partition: "); grub_efi_print_device_path (parent->device_path); #endif add_device (&hd_devices, parent); } else { #ifdef DEBUG_NAMES grub_printf ("adding a cdrom by a partition: "); grub_efi_print_device_path (parent->device_path); #endif add_device (&cd_devices, parent); } /* Mark the parent as used. */ parent->last_device_path = 0; } /* Mark itself as used. */ d->last_device_path = 0; break; default: #ifdef DEBUG_NAMES grub_printf ("skipping other type: "); grub_efi_print_device_path (d->device_path); #endif /* For now, ignore the others. */ break; } } else { #ifdef DEBUG_NAMES grub_printf ("skipping non-media: "); grub_efi_print_device_path (d->device_path); #endif } } /* Let's see what can be added more. */ for (d = devices; d; d = d->next) { grub_efi_device_path_t *dp; grub_efi_block_io_media_t *m; int is_floppy = 0; dp = d->last_device_path; if (! dp) continue; m = d->block_io->media; if (GRUB_EFI_DEVICE_PATH_TYPE (dp) == GRUB_EFI_ACPI_DEVICE_PATH_TYPE && GRUB_EFI_DEVICE_PATH_SUBTYPE (dp) == GRUB_EFI_ACPI_DEVICE_PATH_SUBTYPE) { grub_efi_acpi_device_path_t *acpi = (grub_efi_acpi_device_path_t *) dp; /* Floppy EISA ID. */ if (acpi->hid == 0x60441d0 || acpi->hid == 0x70041d0 || acpi->hid == 0x70141d1) is_floppy = 1; } if (is_floppy) { #ifdef DEBUG_NAMES grub_printf ("adding a floppy: "); grub_efi_print_device_path (d->device_path); #endif add_device (&fd_devices, d); } else if (m->read_only && m->block_size > GRUB_DISK_SECTOR_SIZE) { /* This check is too heuristic, but assume that this is a CDROM drive. */ #ifdef DEBUG_NAMES grub_printf ("adding a cdrom by guessing: "); grub_efi_print_device_path (d->device_path); #endif add_device (&cd_devices, d); } else { /* The default is a hard drive. */ #ifdef DEBUG_NAMES grub_printf ("adding a hard drive by guessing: "); grub_efi_print_device_path (d->device_path); #endif add_device (&hd_devices, d); } } }
/* Print the chain of Device Path nodes. This is mainly for debugging. */ void grub_efi_print_device_path (grub_efi_device_path_t *dp) { while (1) { grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp); grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp); grub_efi_uint16_t len = GRUB_EFI_DEVICE_PATH_LENGTH (dp); switch (type) { case GRUB_EFI_END_DEVICE_PATH_TYPE: switch (subtype) { case GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE: grub_printf ("/EndEntire\n"); //grub_putchar ('\n'); break; case GRUB_EFI_END_THIS_DEVICE_PATH_SUBTYPE: grub_printf ("/EndThis\n"); //grub_putchar ('\n'); break; default: grub_printf ("/EndUnknown(%x)\n", (unsigned) subtype); break; } break; case GRUB_EFI_HARDWARE_DEVICE_PATH_TYPE: switch (subtype) { case GRUB_EFI_PCI_DEVICE_PATH_SUBTYPE: { grub_efi_pci_device_path_t *pci = (grub_efi_pci_device_path_t *) dp; grub_printf ("/PCI(%x,%x)", (unsigned) pci->function, (unsigned) pci->device); } break; case GRUB_EFI_PCCARD_DEVICE_PATH_SUBTYPE: { grub_efi_pccard_device_path_t *pccard = (grub_efi_pccard_device_path_t *) dp; grub_printf ("/PCCARD(%x)", (unsigned) pccard->function); } break; case GRUB_EFI_MEMORY_MAPPED_DEVICE_PATH_SUBTYPE: { grub_efi_memory_mapped_device_path_t *mmapped = (grub_efi_memory_mapped_device_path_t *) dp; grub_printf ("/MMap(%x,%llx,%llx)", (unsigned) mmapped->memory_type, (unsigned long long) mmapped->start_address, (unsigned long long) mmapped->end_address); } break; case GRUB_EFI_VENDOR_DEVICE_PATH_SUBTYPE: dump_vendor_path ("Hardware", (grub_efi_vendor_device_path_t *) dp); break; case GRUB_EFI_CONTROLLER_DEVICE_PATH_SUBTYPE: { grub_efi_controller_device_path_t *controller = (grub_efi_controller_device_path_t *) dp; grub_printf ("/Ctrl(%x)", (unsigned) controller->controller_number); } break; default: grub_printf ("/UnknownHW(%x)", (unsigned) subtype); break; } break; case GRUB_EFI_ACPI_DEVICE_PATH_TYPE: switch (subtype) { case GRUB_EFI_ACPI_DEVICE_PATH_SUBTYPE: { grub_efi_acpi_device_path_t *acpi = (grub_efi_acpi_device_path_t *) dp; grub_printf ("/ACPI(%x,%x)", (unsigned) acpi->hid, (unsigned) acpi->uid); } break; case GRUB_EFI_EXPANDED_ACPI_DEVICE_PATH_SUBTYPE: { grub_efi_expanded_acpi_device_path_t *eacpi = (grub_efi_expanded_acpi_device_path_t *) dp; grub_printf ("/ACPI("); if (GRUB_EFI_EXPANDED_ACPI_HIDSTR (dp)[0] == '\0') grub_printf ("%x,", (unsigned) eacpi->hid); else grub_printf ("%s,", GRUB_EFI_EXPANDED_ACPI_HIDSTR (dp)); if (GRUB_EFI_EXPANDED_ACPI_UIDSTR (dp)[0] == '\0') grub_printf ("%x,", (unsigned) eacpi->uid); else grub_printf ("%s,", GRUB_EFI_EXPANDED_ACPI_UIDSTR (dp)); if (GRUB_EFI_EXPANDED_ACPI_CIDSTR (dp)[0] == '\0') grub_printf ("%x)", (unsigned) eacpi->cid); else grub_printf ("%s)", GRUB_EFI_EXPANDED_ACPI_CIDSTR (dp)); } break; default: grub_printf ("/UnknownACPI(%x)", (unsigned) subtype); break; } break; case GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE: switch (subtype) { case GRUB_EFI_ATAPI_DEVICE_PATH_SUBTYPE: { grub_efi_atapi_device_path_t *atapi = (grub_efi_atapi_device_path_t *) dp; grub_printf ("/ATAPI(%x,%x,%x)", (unsigned) atapi->primary_secondary, (unsigned) atapi->slave_master, (unsigned) atapi->lun); } break; case GRUB_EFI_SCSI_DEVICE_PATH_SUBTYPE: { grub_efi_scsi_device_path_t *scsi = (grub_efi_scsi_device_path_t *) dp; grub_printf ("/SCSI(%x,%x)", (unsigned) scsi->pun, (unsigned) scsi->lun); } break; case GRUB_EFI_FIBRE_CHANNEL_DEVICE_PATH_SUBTYPE: { grub_efi_fibre_channel_device_path_t *fc = (grub_efi_fibre_channel_device_path_t *) dp; grub_printf ("/FibreChannel(%llx,%llx)", (unsigned long long) fc->wwn, (unsigned long long) fc->lun); } break; case GRUB_EFI_1394_DEVICE_PATH_SUBTYPE: { grub_efi_1394_device_path_t *firewire = (grub_efi_1394_device_path_t *) dp; grub_printf ("/1394(%llx)", (unsigned long long) firewire->guid); } break; case GRUB_EFI_USB_DEVICE_PATH_SUBTYPE: { grub_efi_usb_device_path_t *usb = (grub_efi_usb_device_path_t *) dp; grub_printf ("/USB(%x,%x)", (unsigned) usb->parent_port_number, (unsigned) usb->usb_interface); } break; case GRUB_EFI_USB_CLASS_DEVICE_PATH_SUBTYPE: { grub_efi_usb_class_device_path_t *usb_class = (grub_efi_usb_class_device_path_t *) dp; grub_printf ("/USBClass(%x,%x,%x,%x,%x)", (unsigned) usb_class->vendor_id, (unsigned) usb_class->product_id, (unsigned) usb_class->device_class, (unsigned) usb_class->device_subclass, (unsigned) usb_class->device_protocol); } break; case GRUB_EFI_I2O_DEVICE_PATH_SUBTYPE: { grub_efi_i2o_device_path_t *i2o = (grub_efi_i2o_device_path_t *) dp; grub_printf ("/I2O(%x)", (unsigned) i2o->tid); } break; case GRUB_EFI_MAC_ADDRESS_DEVICE_PATH_SUBTYPE: { grub_efi_mac_address_device_path_t *mac = (grub_efi_mac_address_device_path_t *) dp; grub_printf ("/MacAddr(%02x:%02x:%02x:%02x:%02x:%02x,%x)", (unsigned) mac->mac_address[0], (unsigned) mac->mac_address[1], (unsigned) mac->mac_address[2], (unsigned) mac->mac_address[3], (unsigned) mac->mac_address[4], (unsigned) mac->mac_address[5], (unsigned) mac->if_type); } break; case GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE: { grub_efi_ipv4_device_path_t *ipv4 = (grub_efi_ipv4_device_path_t *) dp; grub_printf ("/IPv4(%u.%u.%u.%u,%u.%u.%u.%u,%u,%u,%x,%x)", (unsigned) ipv4->local_ip_address[0], (unsigned) ipv4->local_ip_address[1], (unsigned) ipv4->local_ip_address[2], (unsigned) ipv4->local_ip_address[3], (unsigned) ipv4->remote_ip_address[0], (unsigned) ipv4->remote_ip_address[1], (unsigned) ipv4->remote_ip_address[2], (unsigned) ipv4->remote_ip_address[3], (unsigned) ipv4->local_port, (unsigned) ipv4->remote_port, (unsigned) ipv4->protocol, (unsigned) ipv4->static_ip_address); } break; case GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE: { grub_efi_ipv6_device_path_t *ipv6 = (grub_efi_ipv6_device_path_t *) dp; grub_printf ("/IPv6(%x:%x:%x:%x:%x:%x:%x:%x,%x:%x:%x:%x:%x:%x:%x:%x,%u,%u,%x,%x)", (unsigned) ipv6->local_ip_address[0], (unsigned) ipv6->local_ip_address[1], (unsigned) ipv6->local_ip_address[2], (unsigned) ipv6->local_ip_address[3], (unsigned) ipv6->local_ip_address[4], (unsigned) ipv6->local_ip_address[5], (unsigned) ipv6->local_ip_address[6], (unsigned) ipv6->local_ip_address[7], (unsigned) ipv6->remote_ip_address[0], (unsigned) ipv6->remote_ip_address[1], (unsigned) ipv6->remote_ip_address[2], (unsigned) ipv6->remote_ip_address[3], (unsigned) ipv6->remote_ip_address[4], (unsigned) ipv6->remote_ip_address[5], (unsigned) ipv6->remote_ip_address[6], (unsigned) ipv6->remote_ip_address[7], (unsigned) ipv6->local_port, (unsigned) ipv6->remote_port, (unsigned) ipv6->protocol, (unsigned) ipv6->static_ip_address); } break; case GRUB_EFI_INFINIBAND_DEVICE_PATH_SUBTYPE: { grub_efi_infiniband_device_path_t *ib = (grub_efi_infiniband_device_path_t *) dp; grub_printf ("/InfiniBand(%x,%llx,%llx,%llx)", (unsigned) ib->port_gid[0], /* XXX */ (unsigned long long) ib->remote_id, (unsigned long long) ib->target_port_id, (unsigned long long) ib->device_id); } break; case GRUB_EFI_UART_DEVICE_PATH_SUBTYPE: { grub_efi_uart_device_path_t *uart = (grub_efi_uart_device_path_t *) dp; grub_printf ("/UART(%llu,%u,%x,%x)", (unsigned long long) uart->baud_rate, uart->data_bits, uart->parity, uart->stop_bits); } break; case GRUB_EFI_SATA_DEVICE_PATH_SUBTYPE: { grub_efi_sata_device_path_t *sata; sata = (grub_efi_sata_device_path_t *) dp; grub_printf ("/Sata(%x,%x,%x)", sata->hba_port, sata->multiplier_port, sata->lun); } break; case GRUB_EFI_VENDOR_MESSAGING_DEVICE_PATH_SUBTYPE: dump_vendor_path ("Messaging", (grub_efi_vendor_device_path_t *) dp); break; default: grub_printf ("/UnknownMessaging(%x)", (unsigned) subtype); break; } break; case GRUB_EFI_MEDIA_DEVICE_PATH_TYPE: switch (subtype) { case GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE: { grub_efi_hard_drive_device_path_t *hd = (grub_efi_hard_drive_device_path_t *) dp; grub_printf ("/HD(%u,%llx,%llx,%02x%02x%02x%02x%02x%02x%02x%02x,%x,%x)", hd->partition_number, (unsigned long long) hd->partition_start, (unsigned long long) hd->partition_size, (unsigned) hd->partition_signature[0], (unsigned) hd->partition_signature[1], (unsigned) hd->partition_signature[2], (unsigned) hd->partition_signature[3], (unsigned) hd->partition_signature[4], (unsigned) hd->partition_signature[5], (unsigned) hd->partition_signature[6], (unsigned) hd->partition_signature[7], (unsigned) hd->partmap_type, (unsigned) hd->signature_type); } break; case GRUB_EFI_CDROM_DEVICE_PATH_SUBTYPE: { grub_efi_cdrom_device_path_t *cd = (grub_efi_cdrom_device_path_t *) dp; grub_printf ("/CD(%u,%llx,%llx)", cd->boot_entry, (unsigned long long) cd->partition_start, (unsigned long long) cd->partition_size); } break; case GRUB_EFI_VENDOR_MEDIA_DEVICE_PATH_SUBTYPE: dump_vendor_path ("Media", (grub_efi_vendor_device_path_t *) dp); break; case GRUB_EFI_FILE_PATH_DEVICE_PATH_SUBTYPE: { grub_efi_file_path_device_path_t *fp; grub_uint8_t *buf; fp = (grub_efi_file_path_device_path_t *) dp; buf = grub_malloc ((len - 4) * 2 + 1); if (buf) *grub_utf16_to_utf8 (buf, fp->path_name, (len - 4) / sizeof (grub_efi_char16_t)) = '\0'; else grub_errno = GRUB_ERR_NONE; grub_printf ("/File(%s)", buf); grub_free (buf); } break; case GRUB_EFI_PROTOCOL_DEVICE_PATH_SUBTYPE: { grub_efi_protocol_device_path_t *proto = (grub_efi_protocol_device_path_t *) dp; grub_printf ("/Protocol(%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x)", (unsigned) proto->guid.data1, (unsigned) proto->guid.data2, (unsigned) proto->guid.data3, (unsigned) proto->guid.data4[0], (unsigned) proto->guid.data4[1], (unsigned) proto->guid.data4[2], (unsigned) proto->guid.data4[3], (unsigned) proto->guid.data4[4], (unsigned) proto->guid.data4[5], (unsigned) proto->guid.data4[6], (unsigned) proto->guid.data4[7]); } break; default: grub_printf ("/UnknownMedia(%x)", (unsigned) subtype); break; } break; case GRUB_EFI_BIOS_DEVICE_PATH_TYPE: switch (subtype) { case GRUB_EFI_BIOS_DEVICE_PATH_SUBTYPE: { grub_efi_bios_device_path_t *bios = (grub_efi_bios_device_path_t *) dp; grub_printf ("/BIOS(%x,%x,%s)", (unsigned) bios->device_type, (unsigned) bios->status_flags, (char *) (dp + 1)); } break; default: grub_printf ("/UnknownBIOS(%x)", (unsigned) subtype); break; } break; default: grub_printf ("/UnknownType(%x,%x)\n", (unsigned) type, (unsigned) subtype); return; break; } if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp)) break; dp = (grub_efi_device_path_t *) ((char *) dp + len); } }
char * grub_efi_get_filename (grub_efi_device_path_t *dp0) { char *name = 0, *p, *pi; grub_size_t filesize = 0; grub_efi_device_path_t *dp; dp = dp0; while (1) { grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp); grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp); if (type == GRUB_EFI_END_DEVICE_PATH_TYPE) break; if (type == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE && subtype == GRUB_EFI_FILE_PATH_DEVICE_PATH_SUBTYPE) { grub_efi_uint16_t len; len = ((GRUB_EFI_DEVICE_PATH_LENGTH (dp) - 4) / sizeof (grub_efi_char16_t)); filesize += GRUB_MAX_UTF8_PER_UTF16 * len + 2; } dp = GRUB_EFI_NEXT_DEVICE_PATH (dp); } if (!filesize) return NULL; dp = dp0; p = name = grub_malloc (filesize); if (!name) return NULL; while (1) { grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp); grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp); if (type == GRUB_EFI_END_DEVICE_PATH_TYPE) break; else if (type == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE && subtype == GRUB_EFI_FILE_PATH_DEVICE_PATH_SUBTYPE) { grub_efi_file_path_device_path_t *fp; grub_efi_uint16_t len; *p++ = '/'; len = ((GRUB_EFI_DEVICE_PATH_LENGTH (dp) - 4) / sizeof (grub_efi_char16_t)); fp = (grub_efi_file_path_device_path_t *) dp; p = (char *) grub_utf16_to_utf8 ((unsigned char *) p, fp->path_name, len); } dp = GRUB_EFI_NEXT_DEVICE_PATH (dp); } *p = '\0'; for (pi = name, p = name; *pi;) { /* EFI breaks paths with backslashes. */ if (*pi == '\\' || *pi == '/') { *p++ = '/'; while (*pi == '\\' || *pi == '/') pi++; continue; } *p++ = *pi++; } *p = '\0'; return name; }
/* Name the devices. */ static void name_devices (struct grub_efidisk_data *devices) { struct grub_efidisk_data *d; /* First, identify devices by media device paths. */ for (d = devices; d; d = d->next) { grub_efi_device_path_t *dp; dp = d->last_device_path; if (! dp) continue; if (GRUB_EFI_DEVICE_PATH_TYPE (dp) == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE) { int is_hard_drive = 0; switch (GRUB_EFI_DEVICE_PATH_SUBTYPE (dp)) { case GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE: is_hard_drive = 1; /* Fall through by intention. */ case GRUB_EFI_CDROM_DEVICE_PATH_SUBTYPE: { struct grub_efidisk_data *parent; parent = find_parent_device (devices, d); if (parent) { if (is_hard_drive) { #if 0 grub_printf ("adding a hard drive by a partition: "); grub_print_device_path (parent->device_path); #endif add_device (&hd_devices, parent); } else { #if 0 grub_printf ("adding a cdrom by a partition: "); grub_print_device_path (parent->device_path); #endif add_device (&cd_devices, parent); } /* Mark the parent as used. */ parent->last_device_path = 0; } } /* Mark itself as used. */ d->last_device_path = 0; break; default: /* For now, ignore the others. */ break; } } } /* Let's see what can be added more. */ for (d = devices; d; d = d->next) { grub_efi_device_path_t *dp; grub_efi_block_io_media_t *m; dp = d->last_device_path; if (! dp) continue; m = d->block_io->media; if (m->logical_partition) { /* Only one partition in a non-media device. Assume that this is a floppy drive. */ #if 0 grub_printf ("adding a floppy by guessing: "); grub_print_device_path (d->device_path); #endif add_device (&fd_devices, d); } else if (m->read_only && m->block_size > GRUB_DISK_SECTOR_SIZE) { /* This check is too heuristic, but assume that this is a CDROM drive. */ #if 0 grub_printf ("adding a cdrom by guessing: "); grub_print_device_path (d->device_path); #endif add_device (&cd_devices, d); } else { /* The default is a hard drive. */ #if 0 grub_printf ("adding a hard drive by guessing: "); grub_print_device_path (d->device_path); #endif add_device (&hd_devices, d); } } }