changeset 18784:b8cee8e8b6fe

8796 loader.efi: efipart does not recognize partitionless disks
author Toomas Soome <tsoome@me.com>
date Fri, 10 Nov 2017 13:41:53 +0200
parents 7ab45e4db310
children 7d491a386173
files usr/src/boot/sys/boot/efi/libefi/efipart.c
diffstat 1 files changed, 100 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/boot/sys/boot/efi/libefi/efipart.c	Fri Nov 10 14:03:43 2017 +0200
+++ b/usr/src/boot/sys/boot/efi/libefi/efipart.c	Fri Nov 10 13:41:53 2017 +0200
@@ -178,6 +178,72 @@
 }
 
 /*
+ * Determine if the provided device path is hdd.
+ *
+ * There really is no simple fool proof way to classify the devices.
+ * Since we do build three lists of devices - floppy, cd and hdd, we
+ * will try to see  if the device is floppy or cd, and list anything else
+ * as hdd.
+ */
+static bool
+efipart_hdd(EFI_DEVICE_PATH *dp)
+{
+	unsigned i, nin;
+	EFI_DEVICE_PATH *devpath, *node;
+	EFI_BLOCK_IO *blkio;
+	EFI_STATUS status;
+
+	if (dp == NULL)
+		return (false);
+
+	if ((node = efi_devpath_last_node(dp)) == NULL)
+		return (false);
+
+	if (efipart_floppy(node) != NULL)
+		return (false);
+
+	/*
+	 * Test every EFI BLOCK IO handle to make sure dp is not device path
+	 * for CD/DVD.
+	 */
+	nin = efipart_nhandles / sizeof (*efipart_handles);
+	for (i = 0; i < nin; i++) {
+		devpath = efi_lookup_devpath(efipart_handles[i]);
+		if (devpath == NULL)
+			return (false);
+
+		/* Only continue testing when dp is prefix in devpath. */
+		if (!efi_devpath_is_prefix(dp, devpath))
+			continue;
+
+		/*
+		 * The device path has to have last node describing the
+		 *  device, or we can not test the type.
+		 */
+		if ((node = efi_devpath_last_node(devpath)) == NULL)
+			return (false);
+
+		if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
+		    DevicePathSubType(node) == MEDIA_CDROM_DP) {
+			return (false);
+		}
+
+		/* Make sure we do have the media. */
+		status = BS->HandleProtocol(efipart_handles[i],
+		    &blkio_guid, (void **)&blkio);
+		if (EFI_ERROR(status))
+			return (false);
+
+		/* USB or SATA cd without the media. */
+		if (blkio->Media->RemovableMedia &&
+		    !blkio->Media->MediaPresent) {
+			return (false);
+		}
+	}
+	return (true);
+}
+
+/*
  * Add or update entries with new handle data.
  */
 static int
@@ -290,9 +356,13 @@
 
 		if ((node = efi_devpath_last_node(devpath)) == NULL)
 			continue;
+
 		if (efipart_floppy(node) != NULL)
 			continue;
 
+		if (efipart_hdd(devpath))
+			continue;
+
 		status = BS->HandleProtocol(efipart_handles[i],
 		    &blkio_guid, (void **)&blkio);
 		if (EFI_ERROR(status))
@@ -362,13 +432,21 @@
 	pdinfo_t *hd, *pd, *last;
 
 	disk_devpath = efi_lookup_devpath(disk_handle);
-	part_devpath = efi_lookup_devpath(part_handle);
-	if (disk_devpath == NULL || part_devpath == NULL) {
+	if (disk_devpath == NULL)
 		return (ENOENT);
+
+	if (part_handle != NULL) {
+		part_devpath = efi_lookup_devpath(part_handle);
+		if (part_devpath == NULL)
+			return (ENOENT);
+		node = (HARDDRIVE_DEVICE_PATH *)
+		    efi_devpath_last_node(part_devpath);
+		if (node == NULL)
+			return (ENOENT);	/* This should not happen. */
+	} else {
+		part_devpath = NULL;
+		node = NULL;
 	}
-	node = (HARDDRIVE_DEVICE_PATH *)efi_devpath_last_node(part_devpath);
-	if (node == NULL)
-		return (ENOENT);	/* This should not happen. */
 
 	pd = calloc(1, sizeof(pdinfo_t));
 	if (pd == NULL) {
@@ -379,6 +457,9 @@
 
 	STAILQ_FOREACH(hd, &hdinfo, pd_link) {
 		if (efi_devpath_match(hd->pd_devpath, disk_devpath) == true) {
+			if (part_devpath == NULL)
+				return (0);
+
 			/* Add the partition. */
 			pd->pd_handle = part_handle;
 			pd->pd_unit = node->PartitionNumber;
@@ -401,6 +482,9 @@
 	hd->pd_devpath = disk_devpath;
 	STAILQ_INSERT_TAIL(&hdinfo, hd, pd_link);
 
+	if (part_devpath == NULL)
+		return (0);
+
 	pd = calloc(1, sizeof(pdinfo_t));
 	if (pd == NULL) {
 		printf("Failed to add partition, out of memory\n");
@@ -523,7 +607,8 @@
 
 		if ((node = efi_devpath_last_node(devpath)) == NULL)
 			continue;
-		if (efipart_floppy(node) != NULL)
+
+		if (!efipart_hdd(devpath))
 			continue;
 
 		status = BS->HandleProtocol(efipart_handles[i],
@@ -532,6 +617,12 @@
 			continue;
 
 		if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
+		    DevicePathSubType(node) == MEDIA_FILEPATH_DP) {
+			efipart_hdinfo_add_filepath(efipart_handles[i]);
+			continue;
+		}
+
+		if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
 		    DevicePathSubType(node) == MEDIA_HARDDRIVE_DP) {
 			devpathcpy = efi_devpath_trim(devpath);
 			if (devpathcpy == NULL)
@@ -550,18 +641,16 @@
 				continue;
 			if ((node = efi_devpath_last_node(devpathcpy)) == NULL)
 				continue;
+
 			if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
 			    DevicePathSubType(node) == MEDIA_HARDDRIVE_DP)
 				continue;
+
 			efipart_hdinfo_add(handle, efipart_handles[i]);
 			continue;
 		}
 
-		if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
-		    DevicePathSubType(node) == MEDIA_FILEPATH_DP) {
-			efipart_hdinfo_add_filepath(efipart_handles[i]);
-			continue;
-		}
+		efipart_hdinfo_add(efipart_handles[i], NULL);
 	}
 }