loader.efi: efipart does not recognize partitionless disks

Rework the block device handle check to allow more robust device
classification. This is mostly usability issue - it can be quite confusing
for user when no disks are listed with lsdev.

Add more comments about what and why is done.

Reviewed by:	imp
Differential Revision:	https://reviews.freebsd.org/D13026
This commit is contained in:
Toomas Soome 2017-11-22 08:48:00 +00:00
parent 7143bb7626
commit cdadbf0971

View File

@ -195,6 +195,72 @@ efipart_floppy(EFI_DEVICE_PATH *node)
return (NULL);
}
/*
* 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.
*/
@ -308,9 +374,13 @@ efipart_updatecd(void)
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))
@ -380,13 +450,21 @@ efipart_hdinfo_add(EFI_HANDLE disk_handle, EFI_HANDLE part_handle)
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) {
@ -397,6 +475,9 @@ efipart_hdinfo_add(EFI_HANDLE disk_handle, EFI_HANDLE part_handle)
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;
@ -419,6 +500,9 @@ efipart_hdinfo_add(EFI_HANDLE disk_handle, EFI_HANDLE part_handle)
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");
@ -541,7 +625,8 @@ efipart_updatehd(void)
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],
@ -549,6 +634,12 @@ efipart_updatehd(void)
if (EFI_ERROR(status))
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);
@ -568,18 +659,16 @@ efipart_updatehd(void)
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);
}
}