loader.efi: efipart should be more careful about constructing block device lists

The cd handles should be collected as list of partitions. Some systems also
provide base name for block device (like PciRoot(0x0)/Pci(0x5,0x0)), we need
to be careful about those.

To make out life a bit easier, we prepare not just an array of handles, but we
allocate pdinfo struct for each handle and devicepath, then we can simplify
our work to sort the devices.

Differential Revision:	https://reviews.freebsd.org/D21187
This commit is contained in:
Toomas Soome 2019-08-20 19:31:11 +00:00
parent 98dc8da58c
commit a15a23234d
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=351274

View File

@ -100,12 +100,18 @@ struct devsw efipart_hddev = {
.dv_cleanup = NULL
};
static pdinfo_list_t fdinfo;
static pdinfo_list_t cdinfo;
static pdinfo_list_t hdinfo;
static pdinfo_list_t fdinfo = STAILQ_HEAD_INITIALIZER(fdinfo);
static pdinfo_list_t cdinfo = STAILQ_HEAD_INITIALIZER(cdinfo);
static pdinfo_list_t hdinfo = STAILQ_HEAD_INITIALIZER(hdinfo);
static EFI_HANDLE *efipart_handles = NULL;
static UINTN efipart_nhandles = 0;
/*
* efipart_inithandles() is used to build up the pdinfo list from
* block device handles. Then each devsw init callback is used to
* pick items from pdinfo and move to proper device list.
* In ideal world, we should end up with empty pdinfo once all
* devsw initializers are called.
*/
static pdinfo_list_t pdinfo = STAILQ_HEAD_INITIALIZER(pdinfo);
pdinfo_list_t *
efiblk_get_pdinfo_list(struct devsw *dev)
@ -141,9 +147,11 @@ pdinfo_t *
efiblk_get_pdinfo_by_device_path(EFI_DEVICE_PATH *path)
{
EFI_HANDLE h;
EFI_STATUS status;
EFI_DEVICE_PATH *devp = path;
h = efi_devpath_to_handle(path, efipart_handles, efipart_nhandles);
if (h == NULL)
status = BS->LocateDevicePath(&blkio_guid, &devp, &h);
if (EFI_ERROR(status))
return (NULL);
return (efiblk_get_pdinfo_by_handle(h));
}
@ -174,6 +182,10 @@ efiblk_get_pdinfo_by_handle(EFI_HANDLE h)
STAILQ_FOREACH(dp, &cdinfo, pd_link) {
if (same_handle(dp, h))
return (dp);
STAILQ_FOREACH(pp, &dp->pd_part, pd_link) {
if (same_handle(pp, h))
return (pp);
}
}
STAILQ_FOREACH(dp, &fdinfo, pd_link) {
if (same_handle(dp, h))
@ -197,15 +209,16 @@ efiblk_pdinfo_count(pdinfo_list_t *pdi)
int
efipart_inithandles(void)
{
unsigned i, nin;
UINTN sz;
EFI_HANDLE *hin;
EFI_DEVICE_PATH *devpath;
EFI_BLOCK_IO *blkio;
EFI_STATUS status;
pdinfo_t *pd;
if (efipart_nhandles != 0) {
free(efipart_handles);
efipart_handles = NULL;
efipart_nhandles = 0;
}
if (!STAILQ_EMPTY(&pdinfo))
return (0);
sz = 0;
hin = NULL;
@ -220,12 +233,51 @@ efipart_inithandles(void)
if (EFI_ERROR(status))
return (efi_status_to_errno(status));
efipart_handles = hin;
efipart_nhandles = sz / sizeof(*hin);
nin = sz / sizeof(*hin);
#ifdef EFIPART_DEBUG
printf("%s: Got %d BLOCK IO MEDIA handle(s)\n", __func__,
efipart_nhandles);
printf("%s: Got %d BLOCK IO MEDIA handle(s)\n", __func__, nin);
#endif
for (i = 0; i < nin; i++) {
/*
* Get devpath and open protocol.
* We should not get errors here
*/
if ((devpath = efi_lookup_devpath(hin[i])) == NULL)
continue;
status = OpenProtocolByHandle(hin[i], &blkio_guid,
(void **)&blkio);
if (EFI_ERROR(status)) {
printf("error %lu\n", EFI_ERROR_CODE(status));
continue;
}
/*
* We assume the block size 512 or greater power of 2.
* iPXE is known to insert stub BLOCK IO device with
* BlockSize 1.
*/
if (blkio->Media->BlockSize < 512 ||
!powerof2(blkio->Media->BlockSize)) {
continue;
}
/* This is bad. */
if ((pd = calloc(1, sizeof(*pd))) == NULL) {
printf("efipart_inithandles: Out of memory.\n");
free(hin);
return (ENOMEM);
}
STAILQ_INIT(&pd->pd_part);
pd->pd_handle = hin[i];
pd->pd_devpath = devpath;
pd->pd_blkio = blkio;
STAILQ_INSERT_TAIL(&pdinfo, pd, pd_link);
}
free(hin);
return (0);
}
@ -246,133 +298,48 @@ 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)
static pdinfo_t *
efipart_find_parent(pdinfo_list_t *pdi, EFI_DEVICE_PATH *devpath)
{
unsigned i;
EFI_DEVICE_PATH *devpath, *node;
EFI_BLOCK_IO *blkio;
EFI_STATUS status;
pdinfo_t *pd;
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.
*/
for (i = 0; i < efipart_nhandles; 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 = OpenProtocolByHandle(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);
}
/*
* We assume the block size 512 or greater power of 2.
* iPXE is known to insert stub BLOCK IO device with
* BlockSize 1.
*/
if (blkio->Media->BlockSize < 512 ||
!powerof2(blkio->Media->BlockSize)) {
return (false);
}
}
return (true);
}
/*
* Add or update entries with new handle data.
*/
static int
efipart_fdinfo_add(EFI_HANDLE handle, uint32_t uid, EFI_DEVICE_PATH *devpath)
{
pdinfo_t *fd;
fd = calloc(1, sizeof(pdinfo_t));
if (fd == NULL) {
printf("Failed to register floppy %d, out of memory\n", uid);
return (ENOMEM);
}
STAILQ_INIT(&fd->pd_part);
fd->pd_unit = uid;
fd->pd_handle = handle;
fd->pd_devpath = devpath;
fd->pd_parent = NULL;
fd->pd_devsw = &efipart_fddev;
STAILQ_INSERT_TAIL(&fdinfo, fd, pd_link);
return (0);
}
static void
efipart_updatefd(void)
{
EFI_DEVICE_PATH *devpath, *node;
ACPI_HID_DEVICE_PATH *acpi;
int i;
for (i = 0; i < efipart_nhandles; i++) {
devpath = efi_lookup_devpath(efipart_handles[i]);
if (devpath == NULL)
continue;
if ((node = efi_devpath_last_node(devpath)) == NULL)
continue;
if ((acpi = efipart_floppy(node)) != NULL) {
efipart_fdinfo_add(efipart_handles[i], acpi->UID,
devpath);
}
STAILQ_FOREACH(pd, pdi, pd_link) {
if (efi_devpath_is_prefix(pd->pd_devpath, devpath))
return (pd);
}
return (NULL);
}
static int
efipart_initfd(void)
{
EFI_DEVICE_PATH *node;
ACPI_HID_DEVICE_PATH *acpi;
pdinfo_t *parent, *fd;
STAILQ_INIT(&fdinfo);
restart:
STAILQ_FOREACH(fd, &pdinfo, pd_link) {
if ((node = efi_devpath_last_node(fd->pd_devpath)) == NULL)
continue;
efipart_updatefd();
if ((acpi = efipart_floppy(node)) == NULL)
continue;
STAILQ_REMOVE(&pdinfo, fd, pdinfo, pd_link);
parent = efipart_find_parent(&pdinfo, fd->pd_devpath);
if (parent != NULL) {
STAILQ_REMOVE(&pdinfo, parent, pdinfo, pd_link);
parent->pd_alias = fd->pd_handle;
parent->pd_unit = acpi->UID;
free(fd);
fd = parent;
} else {
fd->pd_unit = acpi->UID;
}
fd->pd_devsw = &efipart_fddev;
STAILQ_INSERT_TAIL(&fdinfo, fd, pd_link);
goto restart;
}
bcache_add_dev(efiblk_pdinfo_count(&fdinfo));
return (0);
@ -381,68 +348,90 @@ efipart_initfd(void)
/*
* Add or update entries with new handle data.
*/
static int
efipart_cdinfo_add(EFI_HANDLE handle, EFI_HANDLE alias,
EFI_DEVICE_PATH *devpath)
static void
efipart_cdinfo_add(pdinfo_t *cd)
{
int unit;
pdinfo_t *cd;
pdinfo_t *pd;
pdinfo_t *pd, *last;
unit = 0;
STAILQ_FOREACH(pd, &cdinfo, pd_link) {
if (efi_devpath_match(pd->pd_devpath, devpath) == true) {
pd->pd_handle = handle;
pd->pd_alias = alias;
return (0);
if (efi_devpath_is_prefix(pd->pd_devpath, cd->pd_devpath)) {
last = STAILQ_LAST(&pd->pd_part, pdinfo, pd_link);
if (last != NULL)
cd->pd_unit = last->pd_unit + 1;
else
cd->pd_unit = 0;
cd->pd_parent = pd;
cd->pd_devsw = &efipart_cddev;
STAILQ_INSERT_TAIL(&pd->pd_part, cd, pd_link);
return;
}
unit++;
}
cd = calloc(1, sizeof(pdinfo_t));
if (cd == NULL) {
printf("Failed to add cd %d, out of memory\n", unit);
return (ENOMEM);
}
STAILQ_INIT(&cd->pd_part);
last = STAILQ_LAST(&cdinfo, pdinfo, pd_link);
if (last != NULL)
cd->pd_unit = last->pd_unit + 1;
else
cd->pd_unit = 0;
cd->pd_handle = handle;
cd->pd_unit = unit;
cd->pd_alias = alias;
cd->pd_devpath = devpath;
cd->pd_parent = NULL;
cd->pd_devsw = &efipart_cddev;
STAILQ_INSERT_TAIL(&cdinfo, cd, pd_link);
return (0);
}
static bool
efipart_testcd(EFI_DEVICE_PATH *node, EFI_BLOCK_IO *blkio)
{
if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
DevicePathSubType(node) == MEDIA_CDROM_DP) {
return (true);
}
/* cd drive without the media. */
if (blkio->Media->RemovableMedia &&
!blkio->Media->MediaPresent) {
return (true);
}
return (false);
}
static void
efipart_updatecd(void)
{
int i;
EFI_DEVICE_PATH *devpath, *devpathcpy, *tmpdevpath, *node;
EFI_HANDLE handle;
EFI_BLOCK_IO *blkio;
EFI_DEVICE_PATH *devpath, *node;
EFI_STATUS status;
pdinfo_t *parent, *cd;
for (i = 0; i < efipart_nhandles; i++) {
devpath = efi_lookup_devpath(efipart_handles[i]);
if (devpath == NULL)
continue;
if ((node = efi_devpath_last_node(devpath)) == NULL)
restart:
STAILQ_FOREACH(cd, &pdinfo, pd_link) {
if ((node = efi_devpath_last_node(cd->pd_devpath)) == NULL)
continue;
if (efipart_floppy(node) != NULL)
continue;
if (efipart_hdd(devpath))
/* Is parent of this device already registered? */
parent = efipart_find_parent(&cdinfo, cd->pd_devpath);
if (parent != NULL) {
STAILQ_REMOVE(&pdinfo, cd, pdinfo, pd_link);
efipart_cdinfo_add(cd);
goto restart;
}
if (!efipart_testcd(node, cd->pd_blkio))
continue;
status = OpenProtocolByHandle(efipart_handles[i], &blkio_guid,
(void **)&blkio);
if (EFI_ERROR(status))
continue;
/* Find parent and unlink both parent and cd from pdinfo */
STAILQ_REMOVE(&pdinfo, cd, pdinfo, pd_link);
parent = efipart_find_parent(&pdinfo, cd->pd_devpath);
if (parent != NULL) {
STAILQ_REMOVE(&pdinfo, parent, pdinfo, pd_link);
efipart_cdinfo_add(parent);
}
if (parent == NULL)
parent = efipart_find_parent(&cdinfo, cd->pd_devpath);
/*
* If we come across a logical partition of subtype CDROM
* it doesn't refer to the CD filesystem itself, but rather
@ -451,132 +440,79 @@ efipart_updatecd(void)
* that will be the CD filesystem.
*/
if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
DevicePathSubType(node) == MEDIA_CDROM_DP) {
devpathcpy = efi_devpath_trim(devpath);
if (devpathcpy == NULL)
continue;
tmpdevpath = devpathcpy;
status = BS->LocateDevicePath(&blkio_guid, &tmpdevpath,
&handle);
free(devpathcpy);
if (EFI_ERROR(status))
continue;
devpath = efi_lookup_devpath(handle);
efipart_cdinfo_add(handle, efipart_handles[i],
devpath);
continue;
DevicePathSubType(node) == MEDIA_CDROM_DP &&
parent == NULL) {
parent = calloc(1, sizeof(*parent));
if (parent == NULL) {
printf("efipart_updatecd: out of memory\n");
/* this device is lost but try again. */
free(cd);
goto restart;
}
devpath = efi_devpath_trim(cd->pd_devpath);
if (devpath == NULL) {
printf("efipart_updatecd: out of memory\n");
/* this device is lost but try again. */
free(parent);
free(cd);
goto restart;
}
parent->pd_devpath = devpath;
status = BS->LocateDevicePath(&blkio_guid,
&parent->pd_devpath, &parent->pd_handle);
free(devpath);
if (EFI_ERROR(status)) {
printf("efipart_updatecd: error %lu\n",
EFI_ERROR_CODE(status));
free(parent);
free(cd);
goto restart;
}
parent->pd_devpath =
efi_lookup_devpath(parent->pd_handle);
efipart_cdinfo_add(parent);
}
if (DevicePathType(node) == MESSAGING_DEVICE_PATH &&
DevicePathSubType(node) == MSG_ATAPI_DP) {
efipart_cdinfo_add(efipart_handles[i], NULL,
devpath);
continue;
}
/* USB or SATA cd without the media. */
if (blkio->Media->RemovableMedia &&
!blkio->Media->MediaPresent) {
efipart_cdinfo_add(efipart_handles[i], NULL,
devpath);
}
efipart_cdinfo_add(cd);
goto restart;
}
}
static int
efipart_initcd(void)
{
STAILQ_INIT(&cdinfo);
efipart_updatecd();
bcache_add_dev(efiblk_pdinfo_count(&cdinfo));
return (0);
}
static int
efipart_hdinfo_add(EFI_HANDLE disk_handle, EFI_HANDLE part_handle)
static void
efipart_hdinfo_add(pdinfo_t *hd, HARDDRIVE_DEVICE_PATH *node)
{
EFI_DEVICE_PATH *disk_devpath, *part_devpath;
HARDDRIVE_DEVICE_PATH *node;
int unit;
pdinfo_t *hd, *pd, *last;
disk_devpath = efi_lookup_devpath(disk_handle);
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;
}
pd = calloc(1, sizeof(pdinfo_t));
if (pd == NULL) {
printf("Failed to add disk, out of memory\n");
return (ENOMEM);
}
STAILQ_INIT(&pd->pd_part);
STAILQ_FOREACH(hd, &hdinfo, pd_link) {
if (efi_devpath_match(hd->pd_devpath, disk_devpath) == true) {
if (part_devpath == NULL)
return (0);
pdinfo_t *pd, *last;
STAILQ_FOREACH(pd, &hdinfo, pd_link) {
if (efi_devpath_is_prefix(pd->pd_devpath, hd->pd_devpath)) {
/* Add the partition. */
pd->pd_handle = part_handle;
pd->pd_unit = node->PartitionNumber;
pd->pd_devpath = part_devpath;
pd->pd_parent = hd;
pd->pd_devsw = &efipart_hddev;
STAILQ_INSERT_TAIL(&hd->pd_part, pd, pd_link);
return (0);
hd->pd_unit = node->PartitionNumber;
hd->pd_parent = pd;
hd->pd_devsw = &efipart_hddev;
STAILQ_INSERT_TAIL(&pd->pd_part, hd, pd_link);
return;
}
}
last = STAILQ_LAST(&hdinfo, pdinfo, pd_link);
if (last != NULL)
unit = last->pd_unit + 1;
hd->pd_unit = last->pd_unit + 1;
else
unit = 0;
hd->pd_unit = 0;
/* Add the disk. */
hd = pd;
hd->pd_handle = disk_handle;
hd->pd_unit = unit;
hd->pd_devpath = disk_devpath;
hd->pd_parent = NULL;
hd->pd_devsw = &efipart_hddev;
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");
return (ENOMEM);
}
STAILQ_INIT(&pd->pd_part);
/* Add the partition. */
pd->pd_handle = part_handle;
pd->pd_unit = node->PartitionNumber;
pd->pd_devpath = part_devpath;
pd->pd_parent = hd;
pd->pd_devsw = &efipart_hddev;
STAILQ_INSERT_TAIL(&hd->pd_part, pd, pd_link);
return (0);
}
/*
@ -585,40 +521,25 @@ efipart_hdinfo_add(EFI_HANDLE disk_handle, EFI_HANDLE part_handle)
* of typeN:M, where type is interface type, N is disk id
* and M is partition id.
*/
static int
efipart_hdinfo_add_filepath(EFI_HANDLE disk_handle)
static void
efipart_hdinfo_add_filepath(pdinfo_t *hd, FILEPATH_DEVICE_PATH *node)
{
EFI_DEVICE_PATH *devpath;
FILEPATH_DEVICE_PATH *node;
char *pathname, *p;
int unit, len;
pdinfo_t *pd, *last;
int len;
pdinfo_t *last;
/* First collect and verify all the data */
if ((devpath = efi_lookup_devpath(disk_handle)) == NULL)
return (ENOENT);
node = (FILEPATH_DEVICE_PATH *)efi_devpath_last_node(devpath);
if (node == NULL)
return (ENOENT); /* This should not happen. */
pd = calloc(1, sizeof(pdinfo_t));
if (pd == NULL) {
printf("Failed to add disk, out of memory\n");
return (ENOMEM);
}
STAILQ_INIT(&pd->pd_part);
last = STAILQ_LAST(&hdinfo, pdinfo, pd_link);
if (last != NULL)
unit = last->pd_unit + 1;
hd->pd_unit = last->pd_unit + 1;
else
unit = 0;
hd->pd_unit = 0;
/* FILEPATH_DEVICE_PATH has 0 terminated string */
len = ucs2len(node->PathName);
if ((pathname = malloc(len + 1)) == NULL) {
printf("Failed to add disk, out of memory\n");
free(pd);
return (ENOMEM);
free(hd);
return;
}
cpy16to8(node->PathName, pathname, len + 1);
p = strchr(pathname, ':');
@ -629,23 +550,19 @@ efipart_hdinfo_add_filepath(EFI_HANDLE disk_handle)
* false, this code would need update.
*/
if (p == NULL) { /* no colon, add the disk */
pd->pd_handle = disk_handle;
pd->pd_unit = unit;
pd->pd_devpath = devpath;
pd->pd_parent = NULL;
pd->pd_devsw = &efipart_hddev;
STAILQ_INSERT_TAIL(&hdinfo, pd, pd_link);
hd->pd_devsw = &efipart_hddev;
STAILQ_INSERT_TAIL(&hdinfo, hd, pd_link);
free(pathname);
return (0);
return;
}
p++; /* skip the colon */
errno = 0;
unit = (int)strtol(p, NULL, 0);
hd->pd_unit = (int)strtol(p, NULL, 0);
if (errno != 0) {
printf("Bad unit number for partition \"%s\"\n", pathname);
free(pathname);
free(pd);
return (EUNIT);
free(hd);
return;
}
/*
@ -657,80 +574,98 @@ efipart_hdinfo_add_filepath(EFI_HANDLE disk_handle)
if (last == NULL) {
printf("BUG: No disk for partition \"%s\"\n", pathname);
free(pathname);
free(pd);
return (EINVAL);
free(hd);
return;
}
/* Add the partition. */
pd->pd_handle = disk_handle;
pd->pd_unit = unit;
pd->pd_devpath = devpath;
pd->pd_parent = last;
pd->pd_devsw = &efipart_hddev;
STAILQ_INSERT_TAIL(&last->pd_part, pd, pd_link);
hd->pd_parent = last;
hd->pd_devsw = &efipart_hddev;
STAILQ_INSERT_TAIL(&last->pd_part, hd, pd_link);
free(pathname);
return (0);
}
static void
efipart_updatehd(void)
{
int i;
EFI_DEVICE_PATH *devpath, *devpathcpy, *tmpdevpath, *node;
EFI_HANDLE handle;
EFI_BLOCK_IO *blkio;
EFI_DEVICE_PATH *devpath, *node;
EFI_STATUS status;
pdinfo_t *parent, *hd;
for (i = 0; i < efipart_nhandles; i++) {
devpath = efi_lookup_devpath(efipart_handles[i]);
if (devpath == NULL)
restart:
STAILQ_FOREACH(hd, &pdinfo, pd_link) {
if ((node = efi_devpath_last_node(hd->pd_devpath)) == NULL)
continue;
if ((node = efi_devpath_last_node(devpath)) == NULL)
if (efipart_floppy(node) != NULL)
continue;
if (!efipart_hdd(devpath))
if (efipart_testcd(node, hd->pd_blkio))
continue;
status = OpenProtocolByHandle(efipart_handles[i], &blkio_guid,
(void **)&blkio);
if (EFI_ERROR(status))
continue;
if (DevicePathType(node) == HARDWARE_DEVICE_PATH &&
DevicePathSubType(node) == HW_PCI_DP) {
STAILQ_REMOVE(&pdinfo, hd, pdinfo, pd_link);
efipart_hdinfo_add(hd, NULL);
goto restart;
}
if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
DevicePathSubType(node) == MEDIA_FILEPATH_DP) {
efipart_hdinfo_add_filepath(efipart_handles[i]);
continue;
STAILQ_REMOVE(&pdinfo, hd, pdinfo, pd_link);
efipart_hdinfo_add_filepath(hd,
(FILEPATH_DEVICE_PATH *)node);
goto restart;
}
STAILQ_REMOVE(&pdinfo, hd, pdinfo, pd_link);
parent = efipart_find_parent(&pdinfo, hd->pd_devpath);
if (parent != NULL) {
STAILQ_REMOVE(&pdinfo, parent, pdinfo, pd_link);
efipart_hdinfo_add(parent, NULL);
} else {
parent = efipart_find_parent(&hdinfo, hd->pd_devpath);
}
if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
DevicePathSubType(node) == MEDIA_HARDDRIVE_DP) {
devpathcpy = efi_devpath_trim(devpath);
if (devpathcpy == NULL)
continue;
tmpdevpath = devpathcpy;
status = BS->LocateDevicePath(&blkio_guid, &tmpdevpath,
&handle);
free(devpathcpy);
if (EFI_ERROR(status))
continue;
/*
* We do not support nested partitions.
*/
devpathcpy = efi_lookup_devpath(handle);
if (devpathcpy == NULL)
continue;
if ((node = efi_devpath_last_node(devpathcpy)) == NULL)
continue;
DevicePathSubType(node) == MEDIA_HARDDRIVE_DP &&
parent == NULL) {
parent = calloc(1, sizeof(*parent));
if (parent == NULL) {
printf("efipart_updatehd: out of memory\n");
/* this device is lost but try again. */
free(hd);
goto restart;
}
if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
DevicePathSubType(node) == MEDIA_HARDDRIVE_DP)
continue;
devpath = efi_devpath_trim(hd->pd_devpath);
if (devpath == NULL) {
printf("efipart_updatehd: out of memory\n");
/* this device is lost but try again. */
free(parent);
free(hd);
goto restart;
}
efipart_hdinfo_add(handle, efipart_handles[i]);
continue;
parent->pd_devpath = devpath;
status = BS->LocateDevicePath(&blkio_guid,
&parent->pd_devpath, &parent->pd_handle);
free(devpath);
if (EFI_ERROR(status)) {
printf("efipart_updatehd: error %lu\n",
EFI_ERROR_CODE(status));
free(parent);
free(hd);
goto restart;
}
parent->pd_devpath =
efi_lookup_devpath(&parent->pd_handle);
efipart_hdinfo_add(parent, NULL);
}
efipart_hdinfo_add(efipart_handles[i], NULL);
efipart_hdinfo_add(hd, (HARDDRIVE_DEVICE_PATH *)node);
goto restart;
}
}
@ -738,8 +673,6 @@ static int
efipart_inithd(void)
{
STAILQ_INIT(&hdinfo);
efipart_updatehd();
bcache_add_dev(efiblk_pdinfo_count(&hdinfo));
@ -852,7 +785,7 @@ efipart_open(struct open_file *f, ...)
EFI_STATUS status;
va_start(args, f);
dev = va_arg(args, struct disk_devdesc*);
dev = va_arg(args, struct disk_devdesc *);
va_end(args);
if (dev == NULL)
return (EINVAL);
@ -1044,7 +977,7 @@ efipart_realstrategy(void *devdata, int rw, daddr_t blk, size_t size,
char *blkbuf;
size_t blkoff, blksz;
int error;
size_t diskend, readstart;
uint64_t diskend, readstart;
if (dev == NULL || blk < 0)
return (EINVAL);
@ -1101,7 +1034,7 @@ efipart_realstrategy(void *devdata, int rw, daddr_t blk, size_t size,
size / blkio->Media->BlockSize, buf));
/*
* The block size of the media is not a multiple of I/O.
* The buffer size is not a multiple of the media block size.
*/
blkbuf = malloc(blkio->Media->BlockSize);
if (blkbuf == NULL)