loader.efi: chain loader should provide proper device handle

Since the efipart rewrite, the chain command was looking for device
handle using interface applicable only for net devices. Disk
partitions and zfs pools need their own approach to find the proper handle.

Reviewed by:	imp
Differential Revision:	https://reviews.freebsd.org/D12287
This commit is contained in:
Toomas Soome 2017-09-10 13:53:42 +00:00
parent 263f801fef
commit 44832ad99d
5 changed files with 77 additions and 47 deletions

View File

@ -61,6 +61,7 @@ typedef struct pdinfo
} pdinfo_t;
pdinfo_list_t *efiblk_get_pdinfo_list(struct devsw *dev);
pdinfo_t *efiblk_get_pdinfo(struct devdesc *dev);
void *efi_get_table(EFI_GUID *tbl);

View File

@ -45,6 +45,7 @@ extern uint64_t pool_guid;
extern void efi_zfs_probe(void);
extern zfsinfo_list_t *efizfs_get_zfsinfo_list(void);
extern EFI_HANDLE efizfs_get_handle_by_guid(uint64_t);
#endif

View File

@ -101,16 +101,33 @@ static pdinfo_list_t hdinfo;
static EFI_HANDLE *efipart_handles = NULL;
static UINTN efipart_nhandles = 0;
static pdinfo_t *
efiblk_get_pdinfo(pdinfo_list_t *pdi, int unit)
pdinfo_list_t *
efiblk_get_pdinfo_list(struct devsw *dev)
{
pdinfo_t *pd;
if (dev->dv_type == DEVT_DISK)
return (&hdinfo);
if (dev->dv_type == DEVT_CD)
return (&cdinfo);
if (dev->dv_type == DEVT_FD)
return (&fdinfo);
return (NULL);
}
pdinfo_t *
efiblk_get_pdinfo(struct devdesc *dev)
{
pdinfo_list_t *pdi;
pdinfo_t *pd = NULL;
pdi = efiblk_get_pdinfo_list(dev->d_dev);
if (pdi == NULL)
return (pd);
STAILQ_FOREACH(pd, pdi, pd_link) {
if (pd->pd_unit == unit)
if (pd->pd_unit == dev->d_unit)
return (pd);
}
return (NULL);
return (pd);
}
static int
@ -671,24 +688,11 @@ efipart_printhd(int verbose)
return (efipart_print_common(&efipart_hddev, &hdinfo, verbose));
}
pdinfo_list_t *
efiblk_get_pdinfo_list(struct devsw *dev)
{
if (dev->dv_type == DEVT_DISK)
return (&hdinfo);
if (dev->dv_type == DEVT_CD)
return (&cdinfo);
if (dev->dv_type == DEVT_FD)
return (&fdinfo);
return (NULL);
}
static int
efipart_open(struct open_file *f, ...)
{
va_list args;
struct disk_devdesc *dev;
pdinfo_list_t *pdi;
pdinfo_t *pd;
EFI_BLOCK_IO *blkio;
EFI_STATUS status;
@ -699,11 +703,7 @@ efipart_open(struct open_file *f, ...)
if (dev == NULL)
return (EINVAL);
pdi = efiblk_get_pdinfo_list(dev->d_dev);
if (pdi == NULL)
return (EINVAL);
pd = efiblk_get_pdinfo(pdi, dev->d_unit);
pd = efiblk_get_pdinfo((struct devdesc *)dev);
if (pd == NULL)
return (EIO);
@ -734,17 +734,13 @@ static int
efipart_close(struct open_file *f)
{
struct disk_devdesc *dev;
pdinfo_list_t *pdi;
pdinfo_t *pd;
dev = (struct disk_devdesc *)(f->f_devdata);
if (dev == NULL)
return (EINVAL);
pdi = efiblk_get_pdinfo_list(dev->d_dev);
if (pdi == NULL)
return (EINVAL);
pd = efiblk_get_pdinfo(pdi, dev->d_unit);
pd = efiblk_get_pdinfo((struct devdesc *)dev);
if (pd == NULL)
return (EINVAL);
@ -763,18 +759,14 @@ static int
efipart_ioctl(struct open_file *f, u_long cmd, void *data)
{
struct disk_devdesc *dev;
pdinfo_list_t *pdi;
pdinfo_t *pd;
int rc;
dev = (struct disk_devdesc *)(f->f_devdata);
if (dev == NULL)
return (EINVAL);
pdi = efiblk_get_pdinfo_list(dev->d_dev);
if (pdi == NULL)
return (EINVAL);
pd = efiblk_get_pdinfo(pdi, dev->d_unit);
pd = efiblk_get_pdinfo((struct devdesc *)dev);
if (pd == NULL)
return (EINVAL);
@ -847,17 +839,13 @@ efipart_strategy(void *devdata, int rw, daddr_t blk, size_t size,
{
struct bcache_devdata bcd;
struct disk_devdesc *dev;
pdinfo_list_t *pdi;
pdinfo_t *pd;
dev = (struct disk_devdesc *)devdata;
if (dev == NULL)
return (EINVAL);
pdi = efiblk_get_pdinfo_list(dev->d_dev);
if (pdi == NULL)
return (EINVAL);
pd = efiblk_get_pdinfo(pdi, dev->d_unit);
pd = efiblk_get_pdinfo((struct devdesc *)dev);
if (pd == NULL)
return (EINVAL);
@ -881,7 +869,6 @@ efipart_realstrategy(void *devdata, int rw, daddr_t blk, size_t size,
char *buf, size_t *rsize)
{
struct disk_devdesc *dev = (struct disk_devdesc *)devdata;
pdinfo_list_t *pdi;
pdinfo_t *pd;
EFI_BLOCK_IO *blkio;
uint64_t off, disk_blocks, d_offset = 0;
@ -893,11 +880,7 @@ efipart_realstrategy(void *devdata, int rw, daddr_t blk, size_t size,
if (dev == NULL || blk < 0)
return (EINVAL);
pdi = efiblk_get_pdinfo_list(dev->d_dev);
if (pdi == NULL)
return (EINVAL);
pd = efiblk_get_pdinfo(pdi, dev->d_unit);
pd = efiblk_get_pdinfo((struct devdesc *)dev);
if (pd == NULL)
return (EINVAL);

View File

@ -52,6 +52,19 @@ efizfs_get_zfsinfo_list(void)
return (&zfsinfo);
}
EFI_HANDLE
efizfs_get_handle_by_guid(uint64_t guid)
{
zfsinfo_t *zi;
STAILQ_FOREACH(zi, &zfsinfo, zi_link) {
if (zi->zi_pool_guid == guid) {
return (zi->zi_handle);
}
}
return (NULL);
}
static void
insert_zfs(EFI_HANDLE handle, uint64_t guid)
{

View File

@ -871,9 +871,41 @@ command_chain(int argc, char *argv[])
*(--argv) = 0;
}
if (efi_getdev((void **)&dev, name, (const char **)&path) == 0)
loaded_image->DeviceHandle =
efi_find_handle(dev->d_dev, dev->d_unit);
if (efi_getdev((void **)&dev, name, (const char **)&path) == 0) {
struct zfs_devdesc *z_dev;
struct disk_devdesc *d_dev;
pdinfo_t *hd, *pd;
switch (dev->d_type) {
case DEVT_ZFS:
z_dev = (struct zfs_devdesc *)dev;
loaded_image->DeviceHandle =
efizfs_get_handle_by_guid(z_dev->pool_guid);
break;
case DEVT_NET:
loaded_image->DeviceHandle =
efi_find_handle(dev->d_dev, dev->d_unit);
break;
default:
hd = efiblk_get_pdinfo(dev);
if (STAILQ_EMPTY(&hd->pd_part)) {
loaded_image->DeviceHandle = hd->pd_handle;
break;
}
d_dev = (struct disk_devdesc *)dev;
STAILQ_FOREACH(pd, &hd->pd_part, pd_link) {
/*
* d_partition should be 255
*/
if (pd->pd_unit == d_dev->d_slice) {
loaded_image->DeviceHandle =
pd->pd_handle;
break;
}
}
break;
}
}
dev_cleanup();
status = BS->StartImage(loaderhandle, NULL, NULL);