Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:wenbowang
grub
grub-0.97-efimap.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File grub-0.97-efimap.patch of Package grub
From f344803d5e03b81e06a882df5745014a0d5b1629 Mon Sep 17 00:00:00 2001 From: Peter Jones <pjones@redhat.com> Date: Mon, 19 Jul 2010 17:28:53 -0400 Subject: [PATCH 2/2] Make "device" on EFI allow you to specify device by efi device path (#598572) Make it so we can rename devices at runtime (from the config) on UEFI so we can map everything consistently accross reboots. --- efi/Makefile.am | 2 +- efi/eficore.c | 420 ---------------------- efi/efidisk.c | 268 ++++++++++----- efi/efidp.c | 985 +++++++++++++++++++++++++++++++++++++++++++++++++++ efi/efimisc.c | 73 ++++ efi/grub/efi/api.h | 14 +- efi/grub/efi/misc.h | 12 + efi/grub/misc.h | 4 + stage2/builtins.c | 37 ++- stage2/shared.h | 2 + 10 files changed, 1295 insertions(+), 522 deletions(-) create mode 100644 efi/efidp.c diff --git a/efi/Makefile.am b/efi/Makefile.am index d856040..4cffe7d 100644 --- a/efi/Makefile.am +++ b/efi/Makefile.am @@ -68,7 +68,7 @@ RELOC_FLAGS = $(STAGE2_CFLAGS) -I$(top_srcdir)/stage1 \ noinst_LIBRARIES = libgrubefi.a libgrubefi_a_SOURCES = $(EFI_ARCH)/callwrap.c eficore.c efimm.c efimisc.c \ - eficon.c efidisk.c graphics.c efigraph.c efiuga.c \ + eficon.c efidisk.c graphics.c efigraph.c efiuga.c efidp.c \ font_8x16.c efiserial.c $(EFI_ARCH)/loader/linux.c efichainloader.c \ xpm.c pxe.c efitftp.c libgrubefi_a_CFLAGS = $(RELOC_FLAGS) -nostdinc diff --git a/efi/eficore.c b/efi/eficore.c index f763be6..5141c53 100644 --- a/efi/eficore.c +++ b/efi/eficore.c @@ -229,423 +229,3 @@ grub_efi_get_device_path (grub_efi_handle_t handle) GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); } -/* 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, - mmapped.start_address, - 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)", - fc.wwn, 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)", 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(%x:%x:%x:%x:%x:%x,%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 */ - ib.remote_id, - ib.target_port_id, - 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)", - 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, - hd.partition_start, - 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, - cd.partition_start, - 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); - } -} diff --git a/efi/efidisk.c b/efi/efidisk.c index 885ae1b..145ed16 100644 --- a/efi/efidisk.c +++ b/efi/efidisk.c @@ -38,100 +38,12 @@ struct grub_efidisk_data /* GUIDs. */ static grub_efi_guid_t disk_io_guid = GRUB_EFI_DISK_IO_GUID; static grub_efi_guid_t block_io_guid = GRUB_EFI_BLOCK_IO_GUID; +static grub_efi_guid_t device_path_from_text_guid = GRUB_EFI_DEVICE_PATH_FROM_TEXT_GUID; static struct grub_efidisk_data *fd_devices; static struct grub_efidisk_data *hd_devices; static struct grub_efidisk_data *cd_devices; -/* Duplicate a device path. */ -static grub_efi_device_path_t * -duplicate_device_path (const grub_efi_device_path_t *dp) -{ - grub_efi_device_path_t *p; - grub_size_t total_size = 0; - - for (p = (grub_efi_device_path_t *) dp; - ; - p = GRUB_EFI_NEXT_DEVICE_PATH (p)) - { - total_size += GRUB_EFI_DEVICE_PATH_LENGTH (p); - if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (p)) - break; - } - - p = grub_malloc (total_size); - if (! p) - return 0; - - grub_memcpy (p, dp, total_size); - return p; -} - -/* Return the device path node right before the end node. */ -static grub_efi_device_path_t * -find_last_device_path (const grub_efi_device_path_t *dp) -{ - grub_efi_device_path_t *next, *p; - - if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp)) - return 0; - - for (p = (grub_efi_device_path_t *) dp, next = GRUB_EFI_NEXT_DEVICE_PATH (p); - ! GRUB_EFI_END_ENTIRE_DEVICE_PATH (next); - p = next, next = GRUB_EFI_NEXT_DEVICE_PATH (next)) - ; - - return p; -} - -/* Compare device paths. */ -static int -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 ((char *)dp1, (char *)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; -} - static struct grub_efidisk_data * make_devices (void) { @@ -648,3 +560,181 @@ grub_get_drive_partition_from_bdev_handle (grub_efi_handle_t handle, return 0; } + +int +check_device (const char *device) +{ + grub_efi_device_path_t *dp; + + dp = device_path_from_utf8(device); + if (dp == NULL) + return 0; + + grub_free(dp); + return 1; +} + +static void +swap_devices (struct grub_efidisk_data *d0, + struct grub_efidisk_data *d1) +{ + struct grub_efidisk_data tmp; + + if (!d0 || !d1) + return; + + memcpy(&tmp, d1, sizeof(*d1)); + + memcpy(&d0->handle, &d1->handle, sizeof(d1->handle)); + d0->device_path = d1->device_path; + d0->last_device_path = d1->last_device_path; + d0->block_io = d1->block_io; + d0->disk_io = d1->disk_io; + + memcpy(d1->handle, tmp.handle, sizeof(tmp.handle)); + d1->device_path = tmp.device_path; + d1->last_device_path = tmp.last_device_path; + d1->block_io = tmp.block_io; + d1->disk_io = tmp.disk_io; +} + +static int +compare_hd_device_paths(grub_efi_hard_drive_device_path_t *hd0, + grub_efi_hard_drive_device_path_t *hd1) +{ + grub_efi_uint64_t x; + int sigsize; + + if ((x = hd1->partition_number - hd0->partition_number)) + return x; + + if ((x = hd1->partition_start - hd0->partition_start)) + return x; + + + if ((x = hd1->partition_size - hd0->partition_size)) + return x; + + if ((x = hd1->signature_type - hd0->signature_type)) + return x; + + switch (hd0->signature_type) + { + case 1: + sigsize = 4; + break; + case 2: + sigsize = 16; + break; + default: + sigsize = 0; + break; + } + x = grub_memcmp((char *)hd0->partition_signature, + (char *)hd1->partition_signature, sigsize); + return x; +} + +static grub_efi_device_path_t * +get_parent_of_disk(grub_efi_device_path_t *hd) +{ + grub_efi_uintn_t num_handles; + grub_efi_handle_t *handles; + grub_efi_handle_t *handle; + grub_efi_device_path_t *ret; + + handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, + &simple_file_system_guid, + 0, &num_handles); + for (handle = handles; num_handles--; handle++) + { + grub_efi_device_path_t *fsdp, *hddp; + + fsdp = grub_efi_get_device_path (*handle); + if (!fsdp) + continue; + hddp = find_last_device_path(fsdp); + + if (compare_hd_device_paths((grub_efi_hard_drive_device_path_t *)hddp, + (grub_efi_hard_drive_device_path_t *)hd) == 0) + { + grub_efi_device_path_t *p; + ret = duplicate_device_path((grub_efi_device_path_t *)fsdp); + if (!ret) + return NULL; + for (p = ret; ; p = GRUB_EFI_NEXT_DEVICE_PATH(p)) + { + if (GRUB_EFI_END_ENTIRE_DEVICE_PATH(p)) + break; + if ((GRUB_EFI_DEVICE_PATH_TYPE(p) == + GRUB_EFI_MEDIA_DEVICE_PATH_TYPE) + && (GRUB_EFI_DEVICE_PATH_SUBTYPE(p) == + GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE)) + { + p->type = GRUB_EFI_END_DEVICE_PATH_TYPE; + p->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; + p->length[0] = 4; + p->length[1] = 0; + break; + } + } + return ret; + } + } + return NULL; +} + +void +assign_device_name (int drive, const char *device) +{ + grub_efi_device_path_t *dp0, *dp1; + struct grub_efidisk_data *devices; + struct grub_efidisk_data *d, *d0 = NULL, *d1 = NULL; + int n = -1; + + dp0 = device_path_from_utf8(device); + if (!dp0) + return; + + dp1 = get_parent_of_disk(dp0); + grub_free(dp0); + if (!dp1) + return; + + if (drive & 0x80) + { + drive -= 0x80; + devices = hd_devices; + } + else + { + devices = cd_devices; + drive -= 0x100; + } + + for (d = devices; d; d = d->next) + { + if (!d->device_path) + continue; + + if (++n == drive) + d0 = d; + + int x; + if (!(x = compare_device_paths(dp1, d->device_path))) + d1 = d; + + if (d0 && d1) + { + /* if they're the same node, that just means it's already at + * the right position. */ + if (d0 != d1) + { + swap_devices(d0, d1); + grub_free(dp1); + return; + } + } + } + grub_free(dp1); +} diff --git a/efi/efidp.c b/efi/efidp.c new file mode 100644 index 0000000..af6cdd5 --- /dev/null +++ b/efi/efidp.c @@ -0,0 +1,984 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <grub/types.h> +#include <grub/misc.h> +#include <grub/efi/api.h> +#include <grub/efi/efi.h> +#include <grub/efi/misc.h> + +#include <shared.h> + +/* Duplicate a device path. */ +grub_efi_device_path_t * +duplicate_device_path (const grub_efi_device_path_t *dp) +{ + grub_efi_device_path_t *p; + grub_size_t total_size = 0; + + for (p = (grub_efi_device_path_t *) dp; + ; + p = GRUB_EFI_NEXT_DEVICE_PATH (p)) + { + total_size += GRUB_EFI_DEVICE_PATH_LENGTH (p); + if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (p)) + break; + } + + p = grub_malloc (total_size); + if (! p) + return 0; + + grub_memcpy (p, dp, total_size); + return p; +} + +/* Return the device path node right before the end node. */ +grub_efi_device_path_t * +find_last_device_path (const grub_efi_device_path_t *dp) +{ + grub_efi_device_path_t *next, *p; + + if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp)) + return 0; + + for (p = (grub_efi_device_path_t *) dp, next = GRUB_EFI_NEXT_DEVICE_PATH (p); + ! GRUB_EFI_END_ENTIRE_DEVICE_PATH (next); + p = next, next = GRUB_EFI_NEXT_DEVICE_PATH (next)) + ; + + return p; +} + +/* Compare device paths. */ +int +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 ((char *)dp1, (char *)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; +} + +/* 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, + mmapped.start_address, + 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)", + fc.wwn, 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)", 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(%x:%x:%x:%x:%x:%x,%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 */ + ib.remote_id, + ib.target_port_id, + 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)", + 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-%02x%02x-%02x%02x%02x%02x%02x%02x)", + hd.partition_number, + hd.partition_start, + hd.partition_size, + (unsigned) hd.partition_signature[3], + (unsigned) hd.partition_signature[2], + (unsigned) hd.partition_signature[1], + (unsigned) hd.partition_signature[0], + (unsigned) hd.partition_signature[5], + (unsigned) hd.partition_signature[4], + (unsigned) hd.partition_signature[7], + (unsigned) hd.partition_signature[6], + (unsigned) hd.partition_signature[9], + (unsigned) hd.partition_signature[8], + (unsigned) hd.partition_signature[10], + (unsigned) hd.partition_signature[11], + (unsigned) hd.partition_signature[12], + (unsigned) hd.partition_signature[13], + (unsigned) hd.partition_signature[14], + (unsigned) hd.partition_signature[15]); + } + 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, + cd.partition_start, + 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); + } +} + +static inline int +dpname_matches(char *str, char *candidate) +{ + grub_size_t clen = grub_strlen(candidate); + char scratch[clen + 2]; + int rc; + + grub_strncpy(scratch, candidate, clen); + scratch[clen+1] = '\0'; + if (scratch[clen-1] == '$') + { + scratch[--clen] = '\0'; + rc = !grub_strncasecmp(str, scratch, clen); + return rc; + } + + grub_strncpy(scratch+clen, "(", 2); + clen = grub_strlen(scratch); + rc = !grub_strncasecmp(str, scratch, clen); + return rc; +} + +static void +finish_param_parse(char *pos, char **end, char *tmp) +{ + if (!pos || !end || !tmp) + return; + + if (*end) + **end = *tmp; +} + +static char * +get_next_param(char *pos, char **end, char *tmp) +{ + char *comma = NULL; + char *openparen = NULL; + char *closeparen = NULL; + + if (!pos || !end || !tmp) + return NULL; + + if (*end) + **end = *tmp; + + openparen = grub_strchr(pos, '('); + if (*openparen) + { + pos = grub_strnchr(openparen + 1, ' '); + comma = grub_strchr(pos, ','); + closeparen = grub_strchr(pos, ')'); + + if (*comma) + { + *tmp = *comma; + *comma = '\0'; + *end = comma; + } + else if (*closeparen) + { + *tmp = *closeparen; + *closeparen = '\0'; + *end = closeparen; + } + return pos; + } + + comma = grub_strchr(pos, ','); + if (*comma) + { + pos = grub_strnchr(comma + 1, ' '); + comma = grub_strchr(pos, ','); + closeparen = grub_strchr(pos, ')'); + + if (*comma) + { + *tmp = *comma; + *comma = '\0'; + *end = comma; + } + else if (*closeparen) + { + *tmp = *closeparen; + *closeparen = '\0'; + *end = closeparen; + } + return pos; + } + + closeparen = grub_strchr(pos, ')'); + if (*closeparen) + pos = grub_strnchr(closeparen + 1, ' '); + + return pos; +} + +struct generic_device_path + { + grub_efi_uint8_t type; + grub_efi_uint8_t subtype; + grub_efi_uint16_t length; + } __attribute__((packed)); + +struct hd_media_device_path + { + grub_efi_uint8_t type; + grub_efi_uint8_t subtype; + grub_efi_uint16_t length; + grub_efi_uint32_t partition; + grub_efi_uint64_t startlba; + grub_efi_uint64_t size; + grub_efi_uint8_t signature[16]; + grub_efi_uint8_t mbr_type; + grub_efi_uint8_t signature_type; + } __attribute__((packed)); + +static inline int +parse_device_path_component(const char *orig_str, void *data) +{ + int orig_str_len = strlen(orig_str) + 1; + char str[orig_str_len]; + char tmp; + char *pos = str; + int ret = 0; + + grub_strcpy(str, orig_str); + if (dpname_matches(str, "pci")) + { + } + else if (dpname_matches(str, "pccard")) + { + } + else if (dpname_matches(str, "mmap")) + { + } + else if (dpname_matches(str, "ctrl")) + { + } + else if (dpname_matches(str, "acpi")) + { + } + /* XXX what about _ADR? */ + /* messaging device paths */ + else if (dpname_matches(str, "atapi")) + { + } + else if (dpname_matches(str, "scsi")) + { + } + else if (dpname_matches(str, "fibrechannel")) + { + } + else if (dpname_matches(str, "1394")) + { + } + else if (dpname_matches(str, "usb")) + { + } + else if (dpname_matches(str, "sata")) + { + } + /* XXX what about usb-wwid */ + /* XXX what about lun */ + else if (dpname_matches(str, "usbclass")) + { + } + else if (dpname_matches(str, "i2o")) + { + } + else if (dpname_matches(str, "macaddr")) + { + } + else if (dpname_matches(str, "ipv4")) + { + } + else if (dpname_matches(str, "ipv6")) + { + } + /* XXX what about vlan */ + else if (dpname_matches(str, "infiniband")) + { + } + else if (dpname_matches(str, "uart")) + { + } + else if (dpname_matches(str, "uartflowctrl")) + { + } + else if (dpname_matches(str, "sas")) + { + } + else if (dpname_matches(str, "iscsi")) + { + } + /* media device paths */ + else if (dpname_matches(str, "hd")) + { + /* these look roughly like: + * HD(Partition,Type,Signature,Start, Size) + * but: + * - type may be optional. 1 or "MBR" means MBR. 2 or "GPT" means GPT. + * - start and size are optional + * - there can be random spaces + */ + struct hd_media_device_path hddp; + unsigned long tmpul; + char *end = NULL, c; + char tmps[19] = "0x"; + char *tmpsp; + + ret = 42; + + hddp.type = GRUB_EFI_MEDIA_DEVICE_PATH_TYPE; + hddp.subtype = GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE; + hddp.length = ret; + + //pos += grub_strcspn(pos, '('); + pos = get_next_param(pos, &end, &c); + if (!*pos) + { +broken_hd: + finish_param_parse(pos, &end, &c); + return 0; + } + grub_strncpy(tmps+2, pos, 16); + tmps[18] = '\0'; + tmpsp = tmps; + safe_parse_maxulong(&tmpsp, &tmpul); + hddp.partition = tmpul; + + pos = get_next_param(pos, &end, &c); + if (!*pos) + goto broken_hd; + grub_strcpy(tmps+2, pos); + tmpsp = tmps; + safe_parse_maxulong(&tmpsp, &tmpul); + hddp.startlba = tmpul; + + pos = get_next_param(pos, &end, &c); + if (!*pos) + goto broken_hd; + grub_strcpy(tmps+2, pos); + tmpsp = tmps; + safe_parse_maxulong(&tmpsp, &tmpul); + hddp.size = tmpul; + + pos = get_next_param(pos, &end, &c); + if (!*pos) + goto broken_hd; + if (!grub_strcmp(pos, "None")) + { + hddp.signature_type = 0; + grub_memset(hddp.signature, '\0', sizeof(hddp.signature)); + } + else if (grub_strnlen(pos, 36) == 8) + { + grub_efi_uint32_t tmpu32; + grub_strncpy(tmps+2, pos, 8); + tmps[10] = '\0'; + tmpsp = tmps; + safe_parse_maxulong(&tmpsp, &tmpul); + tmpu32 = tmpul; + hddp.signature_type = 1; + grub_memcpy(hddp.signature, &tmpu32, sizeof(tmpu32)); + } + else if (grub_strnlen(pos, 36) == 36) + { + grub_efi_uint32_t tmpu32; + grub_efi_uint16_t tmpu16; + grub_efi_uint8_t tmpu8; + + grub_strncpy(tmps+2, pos, 8); + tmps[10] = '\0'; + tmpsp = tmps; + safe_parse_maxulong(&tmpsp, &tmpul); + tmpu32 = tmpul; + grub_memcpy(hddp.signature, &tmpu32, sizeof(tmpu32)); + + grub_strncpy(tmps+2, pos+9, 4); + tmps[6] = '\0'; + tmpsp = tmps; + safe_parse_maxulong(&tmpsp, &tmpul); + tmpu16 = tmpul; + grub_memcpy(hddp.signature + 4, &tmpu16, sizeof(tmpu16)); + + grub_strncpy(tmps+2, pos+14, 4); + tmps[6] = '\0'; + tmpsp = tmps; + safe_parse_maxulong(&tmpsp, &tmpul); + tmpu16 = tmpul; + grub_memcpy(hddp.signature + 6, &tmpu16, sizeof(tmpu16)); + + /* these are displayed like a u16, but they're a u8. thanks. */ + grub_strncpy(tmps+2, pos+19, 2); + tmps[4] = '\0'; + tmpsp = tmps; + safe_parse_maxulong(&tmpsp, &tmpul); + tmpu8 = tmpul; + grub_memcpy(hddp.signature + 8, &tmpu8, sizeof(tmpu8)); + grub_strncpy(tmps+2, pos+21, 2); + tmps[4] = '\0'; + tmpsp = tmps; + safe_parse_maxulong(&tmpsp, &tmpul); + tmpu8 = tmpul; + grub_memcpy(hddp.signature + 9, &tmpu8, sizeof(tmpu8)); + + grub_strncpy(tmps+2, pos+24, 2); + tmps[4] = '\0'; + tmpsp = tmps; + safe_parse_maxulong(&tmpsp, &tmpul); + tmpu8 = tmpul; + grub_memcpy(hddp.signature + 10, &tmpu8, sizeof(tmpu8)); + + grub_strncpy(tmps+2, pos+26, 2); + tmps[4] = '\0'; + tmpsp = tmps; + safe_parse_maxulong(&tmpsp, &tmpul); + tmpu8 = tmpul; + grub_memcpy(hddp.signature + 11, &tmpu8, sizeof(tmpu8)); + + grub_strncpy(tmps+2, pos+28, 2); + tmps[4] = '\0'; + tmpsp = tmps; + safe_parse_maxulong(&tmpsp, &tmpul); + tmpu8 = tmpul; + grub_memcpy(hddp.signature + 12, &tmpu8, sizeof(tmpu8)); + + grub_strncpy(tmps+2, pos+30, 2); + tmps[4] = '\0'; + tmpsp = tmps; + safe_parse_maxulong(&tmpsp, &tmpul); + tmpu8 = tmpul; + grub_memcpy(hddp.signature + 13, &tmpu8, sizeof(tmpu8)); + + grub_strncpy(tmps+2, pos+32, 2); + tmps[4] = '\0'; + tmpsp = tmps; + safe_parse_maxulong(&tmpsp, &tmpul); + tmpu8 = tmpul; + grub_memcpy(hddp.signature + 14, &tmpu8, sizeof(tmpu8)); + + grub_strncpy(tmps+2, pos+34, 2); + tmps[4] = '\0'; + tmpsp = tmps; + safe_parse_maxulong(&tmpsp, &tmpul); + tmpu8 = tmpul; + grub_memcpy(hddp.signature + 15, &tmpu8, sizeof(tmpu8)); + + hddp.signature_type = 2; + } + else + goto broken_hd; + + hddp.mbr_type = hddp.signature_type; + + if (data) + grub_memcpy(data, &hddp, sizeof(hddp)); + } + else if (dpname_matches(str, "cd")) + { + } + else if (dpname_matches(str, "file")) + { + } + else if (dpname_matches(str, "protocol")) + { + } + /* what about piwg firmware file? */ + /* what about piwg firmware volume? */ + /* what about relative offset media */ + else if (dpname_matches(str, "bios")) + { + } + /* This is the end beautiful friend */ + else if (dpname_matches(str, "EndEntire$")) + { + struct generic_device_path gdp = { + .type = GRUB_EFI_END_DEVICE_PATH_TYPE, + .subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE, + .length = 4 + }; + ret = 4; + if (data) + grub_memmove(data, &gdp, sizeof(gdp)); + } + else if (dpname_matches(str, "EndThis$")) + { + struct generic_device_path gdp = { + .type = GRUB_EFI_END_DEVICE_PATH_TYPE, + .subtype = GRUB_EFI_END_THIS_DEVICE_PATH_SUBTYPE, + .length = 4 + }; + ret = 4; + if (data) + grub_memmove(data, &gdp, sizeof(gdp)); + } + else if (dpname_matches(str, "EndUnknown$")) + { + struct generic_device_path gdp = { + .type = GRUB_EFI_END_DEVICE_PATH_TYPE, + .subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE, + .length = 4 + }; + ret = 4; + if (data) + grub_memmove(data, &gdp, sizeof(gdp)); + } + /* handle anything we didn't recognize */ + else if (dpname_matches(str, "vendor")) + { + /* needs to handle: + * 1) hw vendor + * 2) messaging vendor + * 3) media vendor + */ + } + else + { + } + + return ret; +} + +grub_efi_device_path_t * +device_path_from_utf8 (const char *device) +{ + grub_size_t device_len; + grub_efi_device_path_t *dp = NULL; + + device_len = parse_device_path_component(device, dp); + device_len += parse_device_path_component("EndEntire", dp); + dp = grub_malloc(device_len); + if (!dp) + return NULL; + device_len = parse_device_path_component(device, dp); + device_len += parse_device_path_component("EndEntire", + (void *)((unsigned long)dp + device_len)); + + + return dp; +} diff --git a/efi/efimisc.c b/efi/efimisc.c index a319fdd..480ba25 100644 --- a/efi/efimisc.c +++ b/efi/efimisc.c @@ -108,6 +108,79 @@ grub_real_dprintf (const char *file, const int line, const char *condition, va_end (args); } +grub_size_t +grub_utf8_char_len(grub_uint8_t ch) +{ + return ((0xe5000000 >> ((ch >> 3) & 0x1e)) & 3) + 1; +} + +#define UTF8_SHIFT_AND_MASK(unicode, byte) (unicode)<<=6; (unicode) |= (0x3f & (byte)) + +/* convert utf8 to utf32 */ +grub_uint32_t +grub_utf8_to_utf32(const grub_uint8_t *src, grub_size_t length) +{ + grub_uint32_t unicode; + + switch (length) + { + case 1: + return src[0]; + case 2: + unicode = src[0] & 0x1f; + UTF8_SHIFT_AND_MASK(unicode, src[1]); + return unicode; + case 3: + unicode = src[0] & 0x0f; + UTF8_SHIFT_AND_MASK(unicode, src[1]); + UTF8_SHIFT_AND_MASK(unicode, src[2]); + return unicode; + case 4: + unicode = src[0] & 0x07; + UTF8_SHIFT_AND_MASK(unicode, src[1]); + UTF8_SHIFT_AND_MASK(unicode, src[2]); + UTF8_SHIFT_AND_MASK(unicode, src[3]); + return unicode; + default: + return 0xffff; + } +} + +/* convert utf8 to utf16 */ +void +grub_utf8_to_utf16(const grub_uint8_t *src, grub_size_t srclen, + grub_uint16_t *dst, grub_size_t dstlen) +{ + const grub_uint8_t *end = src + srclen; + grub_efi_char16_t *dstend = dst + dstlen; + + while (src < end && dst < dstend) + { + grub_size_t len = grub_utf8_char_len(*src); + /* get the utf32 codepoint */ + grub_uint32_t codepoint = grub_utf8_to_utf32(src, len); + + /* convert that codepoint to utf16 codepoints */ + if (codepoint <= 0xffff) + { + /* it's a single utf16 character */ + *dst++ = (grub_efi_char16_t) codepoint; + } + else + { + /* it's multiple utf16 characters, with surrogate pairs */ + codepoint = codepoint - 0x10000; + *dst++ = (grub_efi_char16_t) ((codepoint >> 10) + 0xd800); + *dst++ = (grub_efi_char16_t) ((codepoint & 0x3ff) + 0xdc00); + } + + src += len; + } + + if (dst < dstend) + *dst = 0; +} + /* Convert UTF-16 to UTF-8. */ grub_uint8_t * grub_utf16_to_utf8 (grub_uint8_t *dest, grub_uint16_t *src, diff --git a/efi/grub/efi/api.h b/efi/grub/efi/api.h index 6743a0b..8f75a68 100644 --- a/efi/grub/efi/api.h +++ b/efi/grub/efi/api.h @@ -90,6 +90,11 @@ { 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \ } +#define GRUB_EFI_DEVICE_PATH_FROM_TEXT_GUID \ + { 0x05c99a21, 0xc70f, 0x4ad2, \ + { 0x8a, 0x5f, 0x35, 0xdf, 0x33, 0x43, 0xf5, 0x1e } \ + } + #define GRUB_EFI_GRAPHICS_OUTPUT_GUID \ { 0x9042a9de, 0x23dc, 0x4a38, \ { 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a } \ @@ -553,7 +558,7 @@ struct grub_efi_hard_drive_device_path grub_efi_uint32_t partition_number; grub_efi_lba_t partition_start; grub_efi_lba_t partition_size; - grub_efi_uint8_t partition_signature[8]; + grub_efi_uint8_t partition_signature[16]; grub_efi_uint8_t mbr_type; grub_efi_uint8_t signature_type; }; @@ -615,6 +620,13 @@ struct grub_efi_bios_device_path }; typedef struct grub_efi_bios_device_path grub_efi_bios_device_path_t; +struct grub_efi_device_path_from_text +{ + grub_efi_device_path_t * (*convert_text_to_device_node) (const grub_efi_char16_t *text_device_node); + grub_efi_device_path_t * (*convert_text_to_device_path) (const grub_efi_char16_t *text_device_path); +}; +typedef struct grub_efi_device_path_from_text grub_efi_device_path_from_text_t; + struct grub_efi_open_protocol_information_entry { grub_efi_handle_t agent_handle; diff --git a/efi/grub/efi/misc.h b/efi/grub/efi/misc.h index b089904..7dc34e7 100644 --- a/efi/grub/efi/misc.h +++ b/efi/grub/efi/misc.h @@ -43,4 +43,16 @@ int grub_get_drive_partition_from_bdev_handle (grub_efi_handle_t handle, char *grub_efi_file_path_to_path_name (grub_efi_device_path_t *file_path); void grub_load_saved_default (grub_efi_handle_t dev_handle); +grub_efi_device_path_t * +find_last_device_path (const grub_efi_device_path_t *dp); +grub_efi_device_path_t * +duplicate_device_path (const grub_efi_device_path_t *dp); +int +compare_device_paths (const grub_efi_device_path_t *dp1, + const grub_efi_device_path_t *dp2); +grub_efi_device_path_t * +device_path_from_utf8 (const char *device); + +extern grub_efi_guid_t simple_file_system_guid; + #endif /* ! GRUB_EFI_MISC_HEADER */ diff --git a/efi/grub/misc.h b/efi/grub/misc.h index 5ec54d5..5ef2226 100644 --- a/efi/grub/misc.h +++ b/efi/grub/misc.h @@ -36,6 +36,10 @@ void grub_real_dprintf (const char *file, void grub_exit (void) __attribute__ ((noreturn)); void grub_abort (void) __attribute__ ((noreturn)); void grub_fatal (const char *fmt, ...) __attribute__ ((noreturn)); +grub_size_t grub_utf8_char_len(grub_uint8_t ch); +grub_uint32_t grub_utf8_to_utf32(const grub_uint8_t *src, grub_size_t length); +void grub_utf8_to_utf16(const grub_uint8_t *src, grub_size_t srclen, + grub_uint16_t *dst, grub_size_t dstlen); grub_uint8_t *grub_utf16_to_utf8 (grub_uint8_t * dest, grub_uint16_t * src, grub_size_t size); diff --git a/stage2/builtins.c b/stage2/builtins.c index de356d4..ad856f8 100644 --- a/stage2/builtins.c +++ b/stage2/builtins.c @@ -905,7 +905,7 @@ static struct builtin builtin_default = }; -#ifdef GRUB_UTIL +#if defined(GRUB_UTIL) || defined(PLATFORM_EFI) /* device */ static int device_func (char *arg, int flags) @@ -913,16 +913,17 @@ device_func (char *arg, int flags) char *drive = arg; char *device; - /* Get the drive number from DRIVE. */ - if (! set_device (drive)) - return 1; - /* Get the device argument. */ device = skip_to (0, drive); - + + nul_terminate (drive); /* Terminate DEVICE. */ nul_terminate (device); + /* Get the drive number from DRIVE. */ + if (! set_device (drive)) + return 1; + if (! *device || ! check_device (device)) { errnum = ERR_FILE_NOT_FOUND; @@ -930,7 +931,7 @@ device_func (char *arg, int flags) } assign_device_name (current_drive, device); - + return 0; } @@ -941,9 +942,20 @@ static struct builtin builtin_device = BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST, "device DRIVE DEVICE", "Specify DEVICE as the actual drive for a BIOS drive DRIVE. This command" - " can be used only in the grub shell." + " can be used only in the grub shell and in EFI." }; -#endif /* GRUB_UTIL */ +#endif /* defined(GRUB_UTIL) || defined(PLATFORM_EFI) */ +#ifdef PLATFORM_EFI +static struct builtin builtin_efimap = +{ + "efimap", + device_func, + BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST, + "efimap DRIVE DEVICE", + "Specify DEVICE as the actual drive for a BIOS drive DRIVE. This command" + " can be used only in EFI." +}; +#endif /* PLATFORM_EFI */ #ifdef SUPPORT_NETBOOT @@ -5169,9 +5181,9 @@ struct builtin *builtin_table[] = &builtin_configfile, &builtin_debug, &builtin_default, -#ifdef GRUB_UTIL +#if defined(GRUB_UTIL) || defined(PLATFORM_EFI) &builtin_device, -#endif /* GRUB_UTIL */ +#endif /* defined(GRUB_UTIL) || defined(PLATFORM_EFI) */ #ifdef SUPPORT_NETBOOT &builtin_dhcp, #endif /* SUPPORT_NETBOOT */ @@ -5182,6 +5194,9 @@ struct builtin *builtin_table[] = #ifdef GRUB_UTIL &builtin_dump, #endif /* GRUB_UTIL */ +#ifdef PLATFORM_EFI + &builtin_efimap, +#endif #ifndef PLATFORM_EFI &builtin_embed, #endif diff --git a/stage2/shared.h b/stage2/shared.h index 6882027..08964a3 100644 --- a/stage2/shared.h +++ b/stage2/shared.h @@ -1043,6 +1043,8 @@ void init_bios_info (void); #ifdef PLATFORM_EFI void grub_set_config_file (char *path_name); int grub_save_saved_default (int new_default); +extern int check_device (const char *device); +extern void assign_device_name (int drive, const char *device); #endif int grub_load_linux (char *kernel, char *arg); int grub_load_initrd (char *initrd); -- 1.7.2
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor