Automatically determine prefix when netbooted on EFI
This commit is contained in:
		
							parent
							
								
									574618a2e9
								
							
						
					
					
						commit
						cae730b452
					
				
					 8 changed files with 237 additions and 123 deletions
				
			
		|  | @ -84,54 +84,6 @@ find_last_device_path (const grub_efi_device_path_t *dp) | |||
|   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 (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; | ||||
| } | ||||
| 
 | ||||
| static struct grub_efidisk_data * | ||||
| make_devices (void) | ||||
| { | ||||
|  | @ -214,7 +166,7 @@ find_parent_device (struct grub_efidisk_data *devices, | |||
|       if (parent == d) | ||||
| 	continue; | ||||
| 
 | ||||
|       if (compare_device_paths (parent->device_path, dp) == 0) | ||||
|       if (grub_efi_compare_device_paths (parent->device_path, dp) == 0) | ||||
| 	{ | ||||
| 	  /* Found.  */ | ||||
| 	  if (! parent->last_device_path) | ||||
|  | @ -249,7 +201,7 @@ iterate_child_devices (struct grub_efidisk_data *devices, | |||
|       ldp->length[0] = sizeof (*ldp); | ||||
|       ldp->length[1] = 0; | ||||
| 
 | ||||
|       if (compare_device_paths (dp, d->device_path) == 0) | ||||
|       if (grub_efi_compare_device_paths (dp, d->device_path) == 0) | ||||
| 	if (hook (p)) | ||||
| 	  { | ||||
| 	    grub_free (dp); | ||||
|  | @ -273,11 +225,11 @@ add_device (struct grub_efidisk_data **devices, struct grub_efidisk_data *d) | |||
|     { | ||||
|       int ret; | ||||
| 
 | ||||
|       ret = compare_device_paths (find_last_device_path ((*p)->device_path), | ||||
| 				  find_last_device_path (d->device_path)); | ||||
|       ret = grub_efi_compare_device_paths (find_last_device_path ((*p)->device_path), | ||||
| 					   find_last_device_path (d->device_path)); | ||||
|       if (ret == 0) | ||||
| 	ret = compare_device_paths ((*p)->device_path, | ||||
| 				    d->device_path); | ||||
| 	ret = grub_efi_compare_device_paths ((*p)->device_path, | ||||
| 					     d->device_path); | ||||
|       if (ret == 0) | ||||
| 	return; | ||||
|       else if (ret > 0) | ||||
|  | @ -706,7 +658,35 @@ grub_efidisk_get_device_handle (grub_disk_t disk) | |||
| char * | ||||
| grub_efidisk_get_device_name (grub_efi_handle_t *handle) | ||||
| { | ||||
|   grub_efi_device_path_t *dp, *ldp; | ||||
|   grub_efi_device_path_t *dp, *ldp, *sdp; | ||||
|   /* This is a hard disk partition.  */ | ||||
|   grub_disk_t parent = 0; | ||||
|   auto int find_parent_disk (const char *name); | ||||
| 
 | ||||
|   /* Find the disk which is the parent of a given hard disk partition.  */ | ||||
|   int find_parent_disk (const char *name) | ||||
|   { | ||||
|     grub_disk_t disk; | ||||
| 
 | ||||
|     disk = grub_disk_open (name); | ||||
|     if (! disk) | ||||
|       return 1; | ||||
| 
 | ||||
|     if (disk->dev->id == GRUB_DISK_DEVICE_EFIDISK_ID) | ||||
|       { | ||||
| 	struct grub_efidisk_data *d; | ||||
| 
 | ||||
| 	d = disk->data; | ||||
| 	if (grub_efi_compare_device_paths (d->device_path, sdp) == 0) | ||||
| 	  { | ||||
| 	    parent = disk; | ||||
| 	    return 1; | ||||
| 	  } | ||||
|       } | ||||
| 
 | ||||
|     grub_disk_close (disk); | ||||
|     return 0; | ||||
|   } | ||||
| 
 | ||||
|   dp = grub_efi_get_device_path (handle); | ||||
|   if (! dp) | ||||
|  | @ -720,40 +700,12 @@ grub_efidisk_get_device_name (grub_efi_handle_t *handle) | |||
|       && (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) | ||||
| 	  == GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE)) | ||||
|     { | ||||
|       /* This is a hard disk partition.  */ | ||||
|       grub_disk_t parent = 0; | ||||
|       grub_partition_t tpart = NULL; | ||||
|       char *device_name; | ||||
|       grub_efi_device_path_t *dup_dp, *dup_ldp; | ||||
|       grub_efi_hard_drive_device_path_t hd; | ||||
|       auto int find_parent_disk (const char *name); | ||||
|       auto int find_partition (grub_disk_t disk, const grub_partition_t part); | ||||
| 
 | ||||
|       /* Find the disk which is the parent of a given hard disk partition.  */ | ||||
|       int find_parent_disk (const char *name) | ||||
| 	{ | ||||
| 	  grub_disk_t disk; | ||||
| 
 | ||||
| 	  disk = grub_disk_open (name); | ||||
| 	  if (! disk) | ||||
| 	    return 1; | ||||
| 
 | ||||
| 	  if (disk->dev->id == GRUB_DISK_DEVICE_EFIDISK_ID) | ||||
| 	    { | ||||
| 	      struct grub_efidisk_data *d; | ||||
| 
 | ||||
| 	      d = disk->data; | ||||
| 	      if (compare_device_paths (d->device_path, dup_dp) == 0) | ||||
| 		{ | ||||
| 		  parent = disk; | ||||
| 		  return 1; | ||||
| 		} | ||||
| 	    } | ||||
| 
 | ||||
| 	  grub_disk_close (disk); | ||||
| 	  return 0; | ||||
| 	} | ||||
| 
 | ||||
|       /* Find the identical partition.  */ | ||||
|       int find_partition (grub_disk_t disk __attribute__ ((unused)), | ||||
| 			  const grub_partition_t part) | ||||
|  | @ -780,6 +732,8 @@ grub_efidisk_get_device_name (grub_efi_handle_t *handle) | |||
|       dup_ldp->length[0] = sizeof (*dup_ldp); | ||||
|       dup_ldp->length[1] = 0; | ||||
| 
 | ||||
|       sdp = dup_dp; | ||||
| 
 | ||||
|       grub_efidisk_iterate (find_parent_disk); | ||||
|       grub_free (dup_dp); | ||||
| 
 | ||||
|  | @ -816,36 +770,15 @@ grub_efidisk_get_device_name (grub_efi_handle_t *handle) | |||
|   else | ||||
|     { | ||||
|       /* This should be an entire disk.  */ | ||||
|       auto int find_disk (const char *name); | ||||
|       char *device_name = 0; | ||||
| 
 | ||||
|       int find_disk (const char *name) | ||||
| 	{ | ||||
| 	  grub_disk_t disk; | ||||
|       sdp = dp; | ||||
| 
 | ||||
| 	  disk = grub_disk_open (name); | ||||
| 	  if (! disk) | ||||
| 	    return 1; | ||||
| 
 | ||||
| 	  if (disk->dev->id == GRUB_DISK_DEVICE_EFIDISK_ID) | ||||
| 	    { | ||||
| 	      struct grub_efidisk_data *d; | ||||
| 
 | ||||
| 	      d = disk->data; | ||||
| 	      if (compare_device_paths (d->device_path, dp) == 0) | ||||
| 		{ | ||||
| 		  device_name = grub_strdup (disk->name); | ||||
| 		  grub_disk_close (disk); | ||||
| 		  return 1; | ||||
| 		} | ||||
| 	    } | ||||
| 
 | ||||
| 	  grub_disk_close (disk); | ||||
| 	  return 0; | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
|       grub_efidisk_iterate (find_disk); | ||||
|       grub_efidisk_iterate (find_parent_disk); | ||||
|       if (!parent) | ||||
| 	return NULL; | ||||
|       device_name = grub_strdup (parent->name); | ||||
|       grub_disk_close (parent); | ||||
|       return device_name; | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -746,3 +746,51 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp) | |||
|       dp = (grub_efi_device_path_t *) ((char *) dp + len); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /* 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; | ||||
| } | ||||
|  |  | |||
|  | @ -42,6 +42,10 @@ grub_efi_init (void) | |||
|   grub_efidisk_init (); | ||||
| } | ||||
| 
 | ||||
| void (*grub_efi_net_config) (grub_efi_handle_t hnd,  | ||||
| 			     char **device, | ||||
| 			     char **path); | ||||
| 
 | ||||
| void | ||||
| grub_machine_get_bootlocation (char **device, char **path) | ||||
| { | ||||
|  | @ -53,6 +57,8 @@ grub_machine_get_bootlocation (char **device, char **path) | |||
|     return; | ||||
|   *device = grub_efidisk_get_device_name (image->device_handle); | ||||
|   *path = grub_efi_get_filename (image->file_path); | ||||
|   if (!*device && grub_efi_net_config) | ||||
|     grub_efi_net_config (image->device_handle, device, path); | ||||
| 
 | ||||
|   /* Get the directory.  */ | ||||
|   p = grub_strrchr (*path, '/'); | ||||
|  |  | |||
|  | @ -27,14 +27,14 @@ GRUB_MOD_LICENSE ("GPLv3+"); | |||
| 
 | ||||
| /* GUID.  */ | ||||
| static grub_efi_guid_t net_io_guid = GRUB_EFI_SIMPLE_NETWORK_GUID; | ||||
| 
 | ||||
| static grub_efi_guid_t pxe_io_guid = GRUB_EFI_PXE_GUID; | ||||
| 
 | ||||
| static grub_err_t | ||||
| send_card_buffer (const struct grub_net_card *dev, | ||||
| 		  struct grub_net_buff *pack) | ||||
| { | ||||
|   grub_efi_status_t st; | ||||
|   grub_efi_simple_network_t *net = dev->data; | ||||
|   grub_efi_simple_network_t *net = dev->efi_net; | ||||
|   st = efi_call_7 (net->transmit, net, 0, pack->tail - pack->data, | ||||
| 		   pack->data, NULL, NULL, NULL); | ||||
|   if (st != GRUB_EFI_SUCCESS) | ||||
|  | @ -46,7 +46,7 @@ static grub_ssize_t | |||
| get_card_packet (const struct grub_net_card *dev, | ||||
| 		 struct grub_net_buff *nb) | ||||
| { | ||||
|   grub_efi_simple_network_t *net = dev->data; | ||||
|   grub_efi_simple_network_t *net = dev->efi_net; | ||||
|   grub_err_t err; | ||||
|   grub_efi_status_t st; | ||||
|   grub_efi_uintn_t bufsize = 1500; | ||||
|  | @ -139,21 +139,62 @@ grub_efinet_findcards (void) | |||
|       grub_memcpy (card->default_address.mac, | ||||
| 		   net->mode->current_address, | ||||
| 		   sizeof (card->default_address.mac)); | ||||
|       card->data = net; | ||||
|       card->efi_net = net; | ||||
|       card->efi_handle = *handle; | ||||
| 
 | ||||
|       grub_net_card_register (card); | ||||
|     } | ||||
|   grub_free (handles); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, | ||||
| 			  char **path) | ||||
| { | ||||
|   struct grub_net_card *card; | ||||
|   grub_efi_device_path_t *dp; | ||||
| 
 | ||||
|   dp = grub_efi_get_device_path (hnd); | ||||
|   if (! dp) | ||||
|     return; | ||||
| 
 | ||||
|   FOR_NET_CARDS (card) | ||||
|   { | ||||
|     grub_efi_device_path_t *cdp; | ||||
|     struct grub_efi_pxe *pxe; | ||||
|     struct grub_efi_pxe_mode *pxe_mode; | ||||
|     if (card->driver != &efidriver) | ||||
|       continue; | ||||
|     cdp = grub_efi_get_device_path (card->efi_handle); | ||||
|     if (! cdp) | ||||
|       continue; | ||||
|     if (grub_efi_compare_device_paths (dp, cdp) != 0) | ||||
|       continue; | ||||
|     pxe = grub_efi_open_protocol (hnd, &pxe_io_guid, | ||||
| 				  GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); | ||||
|     if (! pxe) | ||||
|       continue; | ||||
|     pxe_mode = pxe->mode; | ||||
|     grub_net_configure_by_dhcp_ack (card->name, card, 0, | ||||
| 				    (struct grub_net_bootp_packet *) | ||||
| 				    &pxe_mode->dhcp_ack, | ||||
| 				    sizeof (pxe_mode->dhcp_ack), | ||||
| 				    1, device, path); | ||||
|     return; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| GRUB_MOD_INIT(efinet) | ||||
| { | ||||
|   grub_efinet_findcards (); | ||||
|   grub_efi_net_config = grub_efi_net_config_real; | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(ofnet) | ||||
| { | ||||
|   struct grub_net_card *card; | ||||
|   grub_efi_net_config = 0; | ||||
|   FOR_NET_CARDS (card)  | ||||
|     if (card->driver && !grub_strcmp (card->driver->name, "efinet")) | ||||
|       { | ||||
|  |  | |||
|  | @ -936,7 +936,8 @@ grub_net_configure_by_dhcp_ack (const char *name, | |||
| 				const struct grub_net_card *card, | ||||
| 				grub_net_interface_flags_t flags, | ||||
| 				const struct grub_net_bootp_packet *bp, | ||||
| 				grub_size_t size) | ||||
| 				grub_size_t size, | ||||
| 				int is_def, char **device, char **path) | ||||
| { | ||||
|   grub_net_network_level_address_t addr; | ||||
|   grub_net_link_level_address_t hwaddr; | ||||
|  | @ -945,6 +946,11 @@ grub_net_configure_by_dhcp_ack (const char *name, | |||
|   addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4; | ||||
|   addr.ipv4 = bp->your_ip; | ||||
| 
 | ||||
|   if (device) | ||||
|     *device = 0; | ||||
|   if (path) | ||||
|     *path = 0; | ||||
| 
 | ||||
|   grub_memcpy (hwaddr.mac, bp->mac_addr, | ||||
| 	       bp->hw_len < sizeof (hwaddr.mac) ? bp->hw_len | ||||
| 	       : sizeof (hwaddr.mac)); | ||||
|  | @ -975,26 +981,57 @@ grub_net_configure_by_dhcp_ack (const char *name, | |||
|   if (size > OFFSET_OF (boot_file, bp)) | ||||
|     set_env_limn_ro (name, "boot_file", (char *) bp->boot_file, | ||||
| 		     sizeof (bp->boot_file)); | ||||
|   if (is_def) | ||||
|     default_server = 0; | ||||
|   if (size > OFFSET_OF (server_name, bp) | ||||
|       && bp->server_name[0]) | ||||
|     { | ||||
|       set_env_limn_ro (name, "dhcp_server_name", (char *) bp->server_name, | ||||
| 		       sizeof (bp->server_name)); | ||||
|       if (!default_server) | ||||
|       if (is_def && !default_server) | ||||
| 	{ | ||||
| 	  default_server = grub_strdup (bp->server_name); | ||||
| 	  grub_errno = GRUB_ERR_NONE; | ||||
| 	}	   | ||||
| 	  grub_print_error (); | ||||
| 	} | ||||
|       if (device && !*device) | ||||
| 	{ | ||||
| 	  *device = grub_xasprintf ("tftp,%s", bp->server_name); | ||||
| 	  grub_print_error (); | ||||
| 	} | ||||
|     } | ||||
|   if (!default_server) | ||||
|   if (is_def && !default_server) | ||||
|     { | ||||
|       default_server = grub_xasprintf ("%d.%d.%d.%d", | ||||
| 				       ((grub_uint8_t *) &bp->server_ip)[0], | ||||
| 				       ((grub_uint8_t *) &bp->server_ip)[1], | ||||
| 				       ((grub_uint8_t *) &bp->server_ip)[2], | ||||
| 				       ((grub_uint8_t *) &bp->server_ip)[3]); | ||||
|       grub_errno = GRUB_ERR_NONE; | ||||
|     }	   | ||||
|       grub_print_error (); | ||||
|     } | ||||
| 
 | ||||
|   if (device && !*device) | ||||
|     { | ||||
|       *device = grub_xasprintf ("tftp,%d.%d.%d.%d", | ||||
| 				((grub_uint8_t *) &bp->server_ip)[0], | ||||
| 				((grub_uint8_t *) &bp->server_ip)[1], | ||||
| 				((grub_uint8_t *) &bp->server_ip)[2], | ||||
| 				((grub_uint8_t *) &bp->server_ip)[3]); | ||||
|       grub_print_error (); | ||||
|     } | ||||
|   if (size > OFFSET_OF (boot_file, bp) && path) | ||||
|     { | ||||
|       *path = grub_strndup (bp->boot_file, sizeof (bp->boot_file)); | ||||
|       grub_print_error (); | ||||
|       if (*path) | ||||
| 	{ | ||||
| 	  char *slash; | ||||
| 	  slash = grub_strrchr (*path, '/'); | ||||
| 	  if (slash) | ||||
| 	    *slash = 0; | ||||
| 	  else | ||||
| 	    **path = 0; | ||||
| 	} | ||||
|     } | ||||
|   if (size > OFFSET_OF (vendor, bp)) | ||||
|     parse_dhcp_vendor (name, &bp->vendor, size - OFFSET_OF (vendor, bp)); | ||||
| 
 | ||||
|  | @ -1025,7 +1062,7 @@ grub_net_process_dhcp (struct grub_net_buff *nb, | |||
|     } | ||||
|   grub_net_configure_by_dhcp_ack (name, card, | ||||
| 				  0, (const struct grub_net_bootp_packet *) nb->data, | ||||
| 				  (nb->tail - nb->data)); | ||||
| 				  (nb->tail - nb->data), 0, 0, 0); | ||||
|   grub_free (name); | ||||
|   if (grub_errno) | ||||
|     grub_print_error (); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue