summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorToomas Soome <tsoome@me.com>2016-11-17 17:02:22 +0200
committerDan McDonald <danmcd@joyent.com>2017-09-25 14:37:10 -0400
commitdbacaf56963d687dced1eddb2d3beb695f5ebc7e (patch)
tree3b4c38e49c376eb341dda5152e545e5f33c68e9d
parente984c70bc7d741cd0663924c95c15fed9f645565 (diff)
downloadillumos-joyent-dbacaf56963d687dced1eddb2d3beb695f5ebc7e.tar.gz
8646 loader: replace EFI part devices.
Reviewed by: Robert Mustacchi <rm@joyent.com> Reviewed by: Igor Kozhukhov <igor@dilos.org> Approved by: Dan McDonald <danmcd@joyent.com>
-rw-r--r--usr/src/boot/lib/libstand/stand.h1
-rw-r--r--usr/src/boot/sys/boot/efi/include/efilib.h24
-rw-r--r--usr/src/boot/sys/boot/efi/libefi/devpath.c28
-rw-r--r--usr/src/boot/sys/boot/efi/libefi/efipart.c837
-rw-r--r--usr/src/boot/sys/boot/efi/loader/conf.c4
-rw-r--r--usr/src/boot/sys/boot/efi/loader/devicename.c78
-rw-r--r--usr/src/boot/sys/boot/efi/loader/main.c188
-rw-r--r--usr/src/boot/sys/boot/zfs/zfs.c5
8 files changed, 966 insertions, 199 deletions
diff --git a/usr/src/boot/lib/libstand/stand.h b/usr/src/boot/lib/libstand/stand.h
index 9a7e070bdc..00b4ac210c 100644
--- a/usr/src/boot/lib/libstand/stand.h
+++ b/usr/src/boot/lib/libstand/stand.h
@@ -168,6 +168,7 @@ struct devdesc
#define DEVT_NET 2
#define DEVT_CD 3
#define DEVT_ZFS 4
+#define DEVT_FD 5
int d_unit;
void *d_opendata;
};
diff --git a/usr/src/boot/sys/boot/efi/include/efilib.h b/usr/src/boot/sys/boot/efi/include/efilib.h
index 6a94fd172a..e5eadf6a5d 100644
--- a/usr/src/boot/sys/boot/efi/include/efilib.h
+++ b/usr/src/boot/sys/boot/efi/include/efilib.h
@@ -30,16 +30,37 @@
#include <stand.h>
#include <stdbool.h>
+#include <sys/queue.h>
extern EFI_HANDLE IH;
extern EFI_SYSTEM_TABLE *ST;
extern EFI_BOOT_SERVICES *BS;
extern EFI_RUNTIME_SERVICES *RS;
-extern struct devsw efipart_dev;
+extern struct devsw efipart_fddev;
+extern struct devsw efipart_cddev;
+extern struct devsw efipart_hddev;
extern struct devsw efinet_dev;
extern struct netif_driver efinetif;
+/* EFI block device data, included here to help efi_zfs_probe() */
+typedef STAILQ_HEAD(pdinfo_list, pdinfo) pdinfo_list_t;
+
+typedef struct pdinfo
+{
+ STAILQ_ENTRY(pdinfo) pd_link; /* link in device list */
+ pdinfo_list_t pd_part; /* list of partitions */
+ EFI_HANDLE pd_handle;
+ EFI_HANDLE pd_alias;
+ EFI_DEVICE_PATH *pd_devpath;
+ EFI_BLOCK_IO *pd_blkio;
+ uint32_t pd_unit; /* unit number */
+ uint32_t pd_open; /* reference counter */
+ void *pd_bcache; /* buffer cache data */
+} pdinfo_t;
+
+pdinfo_list_t *efiblk_get_pdinfo_list(struct devsw *dev);
+
void *efi_get_table(EFI_GUID *tbl);
int efi_register_handles(struct devsw *, EFI_HANDLE *, EFI_HANDLE *, int);
@@ -52,6 +73,7 @@ EFI_DEVICE_PATH *efi_lookup_devpath(EFI_HANDLE);
EFI_HANDLE efi_devpath_handle(EFI_DEVICE_PATH *);
EFI_DEVICE_PATH *efi_devpath_last_node(EFI_DEVICE_PATH *);
EFI_DEVICE_PATH *efi_devpath_trim(EFI_DEVICE_PATH *);
+bool efi_devpath_match(EFI_DEVICE_PATH *, EFI_DEVICE_PATH *);
CHAR16 *efi_devpath_name(EFI_DEVICE_PATH *);
void efi_free_devpath_name(CHAR16 *);
diff --git a/usr/src/boot/sys/boot/efi/libefi/devpath.c b/usr/src/boot/sys/boot/efi/libefi/devpath.c
index dbf55f5059..ab56d97a9a 100644
--- a/usr/src/boot/sys/boot/efi/libefi/devpath.c
+++ b/usr/src/boot/sys/boot/efi/libefi/devpath.c
@@ -137,3 +137,31 @@ efi_devpath_handle(EFI_DEVICE_PATH *devpath)
return (NULL);
return (h);
}
+
+bool
+efi_devpath_match(EFI_DEVICE_PATH *devpath1, EFI_DEVICE_PATH *devpath2)
+{
+ size_t len;
+
+ if (devpath1 == NULL || devpath2 == NULL)
+ return (false);
+
+ while (true) {
+ if (DevicePathType(devpath1) != DevicePathType(devpath2) ||
+ DevicePathSubType(devpath1) != DevicePathSubType(devpath2))
+ return (false);
+
+ len = DevicePathNodeLength(devpath1);
+ if (len != DevicePathNodeLength(devpath2))
+ return (false);
+
+ if (memcmp(devpath1, devpath2, len) != 0)
+ return (false);
+
+ if (IsDevicePathEnd(devpath1))
+ break;
+ devpath1 = NextDevicePathNode(devpath1);
+ devpath2 = NextDevicePathNode(devpath2);
+ }
+ return (true);
+}
diff --git a/usr/src/boot/sys/boot/efi/libefi/efipart.c b/usr/src/boot/sys/boot/efi/libefi/efipart.c
index fb65fe82cc..b72f273337 100644
--- a/usr/src/boot/sys/boot/efi/libefi/efipart.c
+++ b/usr/src/boot/sys/boot/efi/libefi/efipart.c
@@ -29,6 +29,7 @@
#include <sys/disk.h>
#include <sys/param.h>
#include <sys/time.h>
+#include <sys/queue.h>
#include <stddef.h>
#include <stdarg.h>
@@ -37,59 +38,115 @@
#include <efi.h>
#include <efilib.h>
#include <efiprot.h>
+#include <disk.h>
static EFI_GUID blkio_guid = BLOCK_IO_PROTOCOL;
-static int efipart_init(void);
+static int efipart_initfd(void);
+static int efipart_initcd(void);
+static int efipart_inithd(void);
+
static int efipart_strategy(void *, int, daddr_t, size_t, char *, size_t *);
static int efipart_realstrategy(void *, int, daddr_t, size_t, char *, size_t *);
+
static int efipart_open(struct open_file *, ...);
static int efipart_close(struct open_file *);
static int efipart_ioctl(struct open_file *, u_long, void *);
-static int efipart_print(int);
-struct devsw efipart_dev = {
- .dv_name = "part",
+static int efipart_printfd(int);
+static int efipart_printcd(int);
+static int efipart_printhd(int);
+
+/* EISA PNP ID's for floppy controllers */
+#define PNP0604 0x604
+#define PNP0700 0x700
+#define PNP0701 0x701
+
+struct devsw efipart_fddev = {
+ .dv_name = "fd",
+ .dv_type = DEVT_FD,
+ .dv_init = efipart_initfd,
+ .dv_strategy = efipart_strategy,
+ .dv_open = efipart_open,
+ .dv_close = efipart_close,
+ .dv_ioctl = efipart_ioctl,
+ .dv_print = efipart_printfd,
+ .dv_cleanup = NULL
+};
+
+struct devsw efipart_cddev = {
+ .dv_name = "cd",
+ .dv_type = DEVT_CD,
+ .dv_init = efipart_initcd,
+ .dv_strategy = efipart_strategy,
+ .dv_open = efipart_open,
+ .dv_close = efipart_close,
+ .dv_ioctl = efipart_ioctl,
+ .dv_print = efipart_printcd,
+ .dv_cleanup = NULL
+};
+
+struct devsw efipart_hddev = {
+ .dv_name = "disk",
.dv_type = DEVT_DISK,
- .dv_init = efipart_init,
+ .dv_init = efipart_inithd,
.dv_strategy = efipart_strategy,
.dv_open = efipart_open,
.dv_close = efipart_close,
.dv_ioctl = efipart_ioctl,
- .dv_print = efipart_print,
+ .dv_print = efipart_printhd,
.dv_cleanup = NULL
};
-/*
- * info structure to support bcache
- */
-struct pdinfo
+static pdinfo_list_t fdinfo;
+static pdinfo_list_t cdinfo;
+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)
{
- int pd_unit; /* unit number */
- int pd_open; /* reference counter */
- void *pd_bcache; /* buffer cache data */
-};
-static struct pdinfo *pdinfo;
-static int npdinfo = 0;
+ pdinfo_t *pd;
-#define PD(dev) (pdinfo[(dev)->d_unit])
+ STAILQ_FOREACH(pd, pdi, pd_link) {
+ if (pd->pd_unit == unit)
+ return (pd);
+ }
+ return (NULL);
+}
static int
-efipart_init(void)
+efiblk_pdinfo_count(pdinfo_list_t *pdi)
+{
+ pdinfo_t *pd;
+ int i = 0;
+
+ STAILQ_FOREACH(pd, pdi, pd_link) {
+ i++;
+ }
+ return (i);
+}
+
+static int
+efipart_inithandles(void)
{
- EFI_BLOCK_IO *blkio;
- EFI_DEVICE_PATH *devpath, *devpathcpy, *tmpdevpath, *node;
- EFI_HANDLE *hin, *hout, *aliases, handle;
- EFI_STATUS status;
UINTN sz;
- u_int n, nin, nout;
- int err;
+ EFI_HANDLE *hin;
+ EFI_STATUS status;
+
+ if (efipart_nhandles != 0) {
+ free(efipart_handles);
+ efipart_handles = NULL;
+ efipart_nhandles = 0;
+ }
sz = 0;
hin = NULL;
- status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz, 0);
+ status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz, hin);
if (status == EFI_BUFFER_TOO_SMALL) {
- hin = (EFI_HANDLE *)malloc(sz * 3);
+ hin = malloc(sz);
status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz,
hin);
if (EFI_ERROR(status))
@@ -98,30 +155,148 @@ efipart_init(void)
if (EFI_ERROR(status))
return (efi_status_to_errno(status));
- /* Filter handles to only include illumos partitions. */
- nin = sz / sizeof(EFI_HANDLE);
- hout = hin + nin;
- aliases = hout + nin;
- nout = 0;
+ efipart_handles = hin;
+ efipart_nhandles = sz;
+ return (0);
+}
+
+static ACPI_HID_DEVICE_PATH *
+efipart_floppy(EFI_DEVICE_PATH *node)
+{
+ ACPI_HID_DEVICE_PATH *acpi;
+
+ if (DevicePathType(node) == ACPI_DEVICE_PATH &&
+ DevicePathSubType(node) == ACPI_DP) {
+ acpi = (ACPI_HID_DEVICE_PATH *) node;
+ if (acpi->HID == EISA_PNP_ID(PNP0604) ||
+ acpi->HID == EISA_PNP_ID(PNP0700) ||
+ acpi->HID == EISA_PNP_ID(PNP0701)) {
+ return (acpi);
+ }
+ }
+ return (NULL);
+}
+
+/*
+ * 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;
- bzero(aliases, nin * sizeof(EFI_HANDLE));
- pdinfo = malloc(nin * sizeof(*pdinfo));
- if (pdinfo == NULL)
+ 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;
+ STAILQ_INSERT_TAIL(&fdinfo, fd, pd_link);
+ return (0);
+}
- for (n = 0; n < nin; n++) {
- devpath = efi_lookup_devpath(hin[n]);
- if (devpath == NULL) {
+static void
+efipart_updatefd(void)
+{
+ EFI_DEVICE_PATH *devpath, *node;
+ ACPI_HID_DEVICE_PATH *acpi;
+ int i, nin;
+
+ nin = efipart_nhandles / sizeof (*efipart_handles);
+ for (i = 0; i < nin; 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);
}
+ }
+}
- status = BS->HandleProtocol(hin[n], &blkio_guid,
- (void**)&blkio);
- if (EFI_ERROR(status))
+static int
+efipart_initfd(void)
+{
+ int rv;
+
+ rv = efipart_inithandles();
+ if (rv != 0)
+ return (rv);
+ STAILQ_INIT(&fdinfo);
+
+ efipart_updatefd();
+
+ bcache_add_dev(efiblk_pdinfo_count(&fdinfo));
+ return (0);
+}
+
+/*
+ * Add or update entries with new handle data.
+ */
+static int
+efipart_cdinfo_add(EFI_HANDLE handle, EFI_HANDLE alias,
+ EFI_DEVICE_PATH *devpath)
+{
+ int unit;
+ pdinfo_t *cd;
+ pdinfo_t *pd;
+
+ 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);
+ }
+ 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);
+
+ cd->pd_handle = handle;
+ cd->pd_unit = unit;
+ cd->pd_alias = alias;
+ cd->pd_devpath = devpath;
+ STAILQ_INSERT_TAIL(&cdinfo, cd, pd_link);
+ return (0);
+}
+
+static void
+efipart_updatecd(void)
+{
+ int i, nin;
+ EFI_DEVICE_PATH *devpath, *devpathcpy, *tmpdevpath, *node;
+ EFI_HANDLE handle;
+ EFI_BLOCK_IO *blkio;
+ EFI_STATUS status;
+
+ nin = efipart_nhandles / sizeof (*efipart_handles);
+ for (i = 0; i < nin; i++) {
+ devpath = efi_lookup_devpath(efipart_handles[i]);
+ if (devpath == NULL)
+ continue;
+
+ if ((node = efi_devpath_last_node(devpath)) == NULL)
continue;
- if (!blkio->Media->LogicalPartition)
+ if (efipart_floppy(node) != NULL)
continue;
+ status = BS->HandleProtocol(efipart_handles[i],
+ &blkio_guid, (void **)&blkio);
+ if (EFI_ERROR(status))
+ continue;
/*
* If we come across a logical partition of subtype CDROM
* it doesn't refer to the CD filesystem itself, but rather
@@ -129,8 +304,6 @@ efipart_init(void)
* we try to find the parent device and add that instead as
* that will be the CD filesystem.
*/
- if ((node = efi_devpath_last_node(devpath)) == NULL)
- continue;
if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
DevicePathSubType(node) == MEDIA_CDROM_DP) {
devpathcpy = efi_devpath_trim(devpath);
@@ -142,124 +315,500 @@ efipart_init(void)
free(devpathcpy);
if (EFI_ERROR(status))
continue;
- hout[nout] = handle;
- aliases[nout] = hin[n];
- } else
- hout[nout] = hin[n];
- nout++;
- pdinfo[npdinfo].pd_open = 0;
- pdinfo[npdinfo].pd_bcache = NULL;
- pdinfo[npdinfo].pd_unit = npdinfo;
- npdinfo++;
- }
-
- bcache_add_dev(npdinfo);
- err = efi_register_handles(&efipart_dev, hout, aliases, nout);
- free(hin);
- return (err);
+ devpath = efi_lookup_devpath(handle);
+ efipart_cdinfo_add(handle, efipart_handles[i],
+ devpath);
+ continue;
+ }
+
+ 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);
+ }
+ }
}
static int
-efipart_print(int verbose)
+efipart_initcd(void)
{
- char line[80];
+ int rv;
+
+ rv = efipart_inithandles();
+ if (rv != 0)
+ return (rv);
+ 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)
+{
+ 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);
+ part_devpath = efi_lookup_devpath(part_handle);
+ if (disk_devpath == NULL || part_devpath == NULL) {
+ return (ENOENT);
+ }
+ 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) {
+ 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) {
+ /* Add the partition. */
+ pd->pd_handle = part_handle;
+ pd->pd_unit = node->PartitionNumber;
+ pd->pd_devpath = part_devpath;
+ STAILQ_INSERT_TAIL(&hd->pd_part, pd, pd_link);
+ return (0);
+ }
+ }
+
+ last = STAILQ_LAST(&hdinfo, pdinfo, pd_link);
+ if (last != NULL)
+ unit = last->pd_unit + 1;
+ else
+ unit = 0;
+
+ /* Add the disk. */
+ hd = pd;
+ hd->pd_handle = disk_handle;
+ hd->pd_unit = unit;
+ hd->pd_devpath = disk_devpath;
+ STAILQ_INSERT_TAIL(&hdinfo, hd, pd_link);
+
+ 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;
+ STAILQ_INSERT_TAIL(&hd->pd_part, pd, pd_link);
+
+ return (0);
+}
+
+/*
+ * The MEDIA_FILEPATH_DP has device name.
+ * From U-Boot sources it looks like names are in the form
+ * 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)
+{
+ EFI_DEVICE_PATH *devpath;
+ FILEPATH_DEVICE_PATH *node;
+ char *pathname, *p;
+ int unit, len;
+ pdinfo_t *pd, *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;
+ else
+ unit = 0;
+
+ /* FILEPATH_DEVICE_PATH has 0 terminated string */
+ for (len = 0; node->PathName[len] != 0; len++)
+ ;
+ if ((pathname = malloc(len + 1)) == NULL) {
+ printf("Failed to add disk, out of memory\n");
+ free(pd);
+ return (ENOMEM);
+ }
+ cpy16to8(node->PathName, pathname, len + 1);
+ p = strchr(pathname, ':');
+
+ /*
+ * Assume we are receiving handles in order, first disk handle,
+ * then partitions for this disk. If this assumption proves
+ * 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;
+ STAILQ_INSERT_TAIL(&hdinfo, pd, pd_link);
+ free(pathname);
+ return (0);
+ }
+ p++; /* skip the colon */
+ errno = 0;
+ unit = (int)strtol(p, NULL, 0);
+ if (errno != 0) {
+ printf("Bad unit number for partition \"%s\"\n", pathname);
+ free(pathname);
+ free(pd);
+ return (EUNIT);
+ }
+
+ /*
+ * We should have disk registered, if not, we are receiving
+ * handles out of order, and this code should be reworked
+ * to create "blank" disk for partition, and to find the
+ * disk based on PathName compares.
+ */
+ if (last == NULL) {
+ printf("BUG: No disk for partition \"%s\"\n", pathname);
+ free(pathname);
+ free(pd);
+ return (EINVAL);
+ }
+ /* Add the partition. */
+ pd->pd_handle = disk_handle;
+ pd->pd_unit = unit;
+ pd->pd_devpath = devpath;
+ STAILQ_INSERT_TAIL(&last->pd_part, pd, pd_link);
+ free(pathname);
+ return (0);
+}
+
+static void
+efipart_updatehd(void)
+{
+ int i, nin;
+ EFI_DEVICE_PATH *devpath, *devpathcpy, *tmpdevpath, *node;
+ EFI_HANDLE handle;
EFI_BLOCK_IO *blkio;
- EFI_HANDLE h;
EFI_STATUS status;
- u_int unit;
+
+ nin = efipart_nhandles / sizeof (*efipart_handles);
+ for (i = 0; i < nin; i++) {
+ devpath = efi_lookup_devpath(efipart_handles[i]);
+ if (devpath == NULL)
+ continue;
+
+ if ((node = efi_devpath_last_node(devpath)) == NULL)
+ continue;
+ if (efipart_floppy(node) != NULL)
+ continue;
+
+ status = BS->HandleProtocol(efipart_handles[i],
+ &blkio_guid, (void **)&blkio);
+ if (EFI_ERROR(status))
+ continue;
+
+ 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;
+ 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;
+ }
+ }
+}
+
+static int
+efipart_inithd(void)
+{
+ int rv;
+
+ rv = efipart_inithandles();
+ if (rv != 0)
+ return (rv);
+ STAILQ_INIT(&hdinfo);
+
+ efipart_updatehd();
+
+ bcache_add_dev(efiblk_pdinfo_count(&hdinfo));
+ return (0);
+}
+
+static int
+efipart_print_common(struct devsw *dev, pdinfo_list_t *pdlist, int verbose)
+{
int ret = 0;
+ EFI_BLOCK_IO *blkio;
+ EFI_STATUS status;
+ EFI_HANDLE h;
+ pdinfo_t *pd;
+ CHAR16 *text;
+ struct disk_devdesc pd_dev;
+ char line[80];
+
+ if (STAILQ_EMPTY(pdlist))
+ return (0);
- printf("%s devices:", efipart_dev.dv_name);
+ printf("%s devices:", dev->dv_name);
if ((ret = pager_output("\n")) != 0)
return (ret);
- for (unit = 0, h = efi_find_handle(&efipart_dev, 0);
- h != NULL; h = efi_find_handle(&efipart_dev, ++unit)) {
- sprintf(line, " %s%d:", efipart_dev.dv_name, unit);
- ret = pager_output(line);
-
+ STAILQ_FOREACH(pd, pdlist, pd_link) {
+ h = pd->pd_handle;
+ if (verbose) { /* Output the device path. */
+ text = efi_devpath_name(efi_lookup_devpath(h));
+ if (text != NULL) {
+ printf(" %S", text);
+ efi_free_devpath_name(text);
+ if ((ret = pager_output("\n")) != 0)
+ break;
+ }
+ }
+ snprintf(line, sizeof(line),
+ " %s%d", dev->dv_name, pd->pd_unit);
+ printf("%s:", line);
status = BS->HandleProtocol(h, &blkio_guid, (void **)&blkio);
if (!EFI_ERROR(status)) {
- sprintf(line, " %llu blocks",
- (unsigned long long)(blkio->Media->LastBlock + 1));
- ret = pager_output(line);
- if (blkio->Media->RemovableMedia)
- ret = pager_output(" (removable)");
+ printf(" %llu",
+ blkio->Media->LastBlock == 0? 0:
+ (unsigned long long) (blkio->Media->LastBlock + 1));
+ if (blkio->Media->LastBlock != 0) {
+ printf(" X %u", blkio->Media->BlockSize);
+ }
+ printf(" blocks");
+ if (blkio->Media->MediaPresent) {
+ if (blkio->Media->RemovableMedia)
+ printf(" (removable)");
+ } else {
+ printf(" (no media)");
+ }
+ if ((ret = pager_output("\n")) != 0)
+ break;
+ if (!blkio->Media->MediaPresent)
+ continue;
+
+ pd->pd_blkio = blkio;
+ pd_dev.d_dev = dev;
+ pd_dev.d_unit = pd->pd_unit;
+ pd_dev.d_slice = -1;
+ pd_dev.d_partition = -1;
+ pd_dev.d_opendata = blkio;
+ ret = disk_open(&pd_dev, blkio->Media->BlockSize *
+ (blkio->Media->LastBlock + 1),
+ blkio->Media->BlockSize);
+ if (ret == 0) {
+ ret = disk_print(&pd_dev, line, verbose);
+ disk_close(&pd_dev);
+ if (ret != 0)
+ return (ret);
+ } else {
+ /* Do not fail from disk_open() */
+ ret = 0;
+ }
+ } else {
+ if ((ret = pager_output("\n")) != 0)
+ break;
}
- ret = pager_output("\n");
- if (ret != 0)
- break;
}
return (ret);
}
static int
+efipart_printfd(int verbose)
+{
+ return (efipart_print_common(&efipart_fddev, &fdinfo, verbose));
+}
+
+static int
+efipart_printcd(int verbose)
+{
+ return (efipart_print_common(&efipart_cddev, &cdinfo, verbose));
+}
+
+static int
+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 devdesc *dev;
+ struct disk_devdesc *dev;
+ pdinfo_list_t *pdi;
+ pdinfo_t *pd;
EFI_BLOCK_IO *blkio;
- EFI_HANDLE h;
EFI_STATUS status;
va_start(args, f);
- dev = va_arg(args, struct devdesc*);
+ dev = va_arg(args, struct disk_devdesc*);
va_end(args);
+ if (dev == NULL)
+ return (EINVAL);
- h = efi_find_handle(&efipart_dev, dev->d_unit);
- if (h == NULL)
+ pdi = efiblk_get_pdinfo_list(dev->d_dev);
+ if (pdi == NULL)
return (EINVAL);
- status = BS->HandleProtocol(h, &blkio_guid, (void **)&blkio);
- if (EFI_ERROR(status))
- return (efi_status_to_errno(status));
+ pd = efiblk_get_pdinfo(pdi, dev->d_unit);
+ if (pd == NULL)
+ return (EIO);
+
+ if (pd->pd_blkio == NULL) {
+ status = BS->HandleProtocol(pd->pd_handle, &blkio_guid,
+ (void **)&pd->pd_blkio);
+ if (EFI_ERROR(status))
+ return (efi_status_to_errno(status));
+ }
+ blkio = pd->pd_blkio;
if (!blkio->Media->MediaPresent)
return (EAGAIN);
- dev->d_opendata = blkio;
- PD(dev).pd_open++;
- if (PD(dev).pd_bcache == NULL)
- PD(dev).pd_bcache = bcache_allocate();
+ pd->pd_open++;
+ if (pd->pd_bcache == NULL)
+ pd->pd_bcache = bcache_allocate();
+
+ if (dev->d_dev->dv_type == DEVT_DISK) {
+ int rc;
+
+ rc = disk_open(dev,
+ blkio->Media->BlockSize * (blkio->Media->LastBlock + 1),
+ blkio->Media->BlockSize);
+ if (rc != 0) {
+ pd->pd_open--;
+ if (pd->pd_open == 0) {
+ pd->pd_blkio = NULL;
+ bcache_free(pd->pd_bcache);
+ pd->pd_bcache = NULL;
+ }
+ }
+ return (rc);
+ }
return (0);
}
static int
efipart_close(struct open_file *f)
{
- struct devdesc *dev;
+ struct disk_devdesc *dev;
+ pdinfo_list_t *pdi;
+ pdinfo_t *pd;
- dev = (struct devdesc *)(f->f_devdata);
- if (dev->d_opendata == NULL)
+ 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);
+ if (pd == NULL)
return (EINVAL);
- dev->d_opendata = NULL;
- PD(dev).pd_open--;
- if (PD(dev).pd_open == 0) {
- bcache_free(PD(dev).pd_bcache);
- PD(dev).pd_bcache = NULL;
+ pd->pd_open--;
+ if (pd->pd_open == 0) {
+ pd->pd_blkio = NULL;
+ bcache_free(pd->pd_bcache);
+ pd->pd_bcache = NULL;
}
+ if (dev->d_dev->dv_type == DEVT_DISK)
+ return (disk_close(dev));
return (0);
}
static int
efipart_ioctl(struct open_file *f, u_long cmd, void *data)
{
- struct devdesc *dev;
- EFI_BLOCK_IO *blkio;
+ struct disk_devdesc *dev;
+ pdinfo_list_t *pdi;
+ pdinfo_t *pd;
+ int rc;
- dev = (struct devdesc *)(f->f_devdata);
- if (dev->d_opendata == NULL)
+ dev = (struct disk_devdesc *)(f->f_devdata);
+ if (dev == NULL)
return (EINVAL);
- blkio = dev->d_opendata;
+ pdi = efiblk_get_pdinfo_list(dev->d_dev);
+ if (pdi == NULL)
+ return (EINVAL);
+
+ pd = efiblk_get_pdinfo(pdi, dev->d_unit);
+ if (pd == NULL)
+ return (EINVAL);
+
+ if (dev->d_dev->dv_type == DEVT_DISK) {
+ rc = disk_ioctl(dev, cmd, data);
+ if (rc != ENOTTY)
+ return (rc);
+ }
switch (cmd) {
case DIOCGSECTORSIZE:
- *(u_int *)data = blkio->Media->BlockSize;
+ *(u_int *)data = pd->pd_blkio->Media->BlockSize;
break;
case DIOCGMEDIASIZE:
- *(uint64_t *)data = blkio->Media->BlockSize *
- (blkio->Media->LastBlock + 1);
+ *(uint64_t *)data = pd->pd_blkio->Media->BlockSize *
+ (pd->pd_blkio->Media->LastBlock + 1);
break;
default:
return (ENOTTY);
@@ -303,8 +852,10 @@ efipart_readwrite(EFI_BLOCK_IO *blkio, int rw, daddr_t blk, daddr_t nblks,
return (ENOSYS);
}
- if (EFI_ERROR(status))
- printf("%s: rw=%d, status=%lu\n", __func__, rw, (u_long)status);
+ if (EFI_ERROR(status)) {
+ printf("%s: rw=%d, blk=%ju size=%ju status=%lu\n", __func__, rw,
+ blk, nblks, EFI_ERROR_CODE(status));
+ }
return (efi_status_to_errno(status));
}
@@ -313,12 +864,33 @@ efipart_strategy(void *devdata, int rw, daddr_t blk, size_t size,
char *buf, size_t *rsize)
{
struct bcache_devdata bcd;
- struct devdesc *dev;
+ 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);
+ if (pd == NULL)
+ return (EINVAL);
+
+ if (pd->pd_blkio->Media->RemovableMedia &&
+ !pd->pd_blkio->Media->MediaPresent)
+ return (ENXIO);
- dev = (struct devdesc *)devdata;
bcd.dv_strategy = efipart_realstrategy;
bcd.dv_devdata = devdata;
- bcd.dv_cache = PD(dev).pd_bcache;
+ bcd.dv_cache = pd->pd_bcache;
+
+ if (dev->d_dev->dv_type == DEVT_DISK) {
+ return (bcache_strategy(&bcd, rw, blk + dev->d_offset,
+ size, buf, rsize));
+ }
return (bcache_strategy(&bcd, rw, blk, size, buf, rsize));
}
@@ -326,17 +898,28 @@ static int
efipart_realstrategy(void *devdata, int rw, daddr_t blk, size_t size,
char *buf, size_t *rsize)
{
- struct devdesc *dev = (struct devdesc *)devdata;
+ struct disk_devdesc *dev = (struct disk_devdesc *)devdata;
+ pdinfo_list_t *pdi;
+ pdinfo_t *pd;
EFI_BLOCK_IO *blkio;
- uint64_t off;
+ uint64_t off, disk_blocks, d_offset = 0;
char *blkbuf;
size_t blkoff, blksz;
int error;
+ uint64_t diskend, readstart;
if (dev == NULL || blk < 0)
return (EINVAL);
- blkio = dev->d_opendata;
+ pdi = efiblk_get_pdinfo_list(dev->d_dev);
+ if (pdi == NULL)
+ return (EINVAL);
+
+ pd = efiblk_get_pdinfo(pdi, dev->d_unit);
+ if (pd == NULL)
+ return (EINVAL);
+
+ blkio = pd->pd_blkio;
if (blkio == NULL)
return (ENXIO);
@@ -344,11 +927,33 @@ efipart_realstrategy(void *devdata, int rw, daddr_t blk, size_t size,
return (EIO);
off = blk * 512;
+ /*
+ * Get disk blocks, this value is either for whole disk or for
+ * partition.
+ */
+ disk_blocks = 0;
+ if (dev->d_dev->dv_type == DEVT_DISK) {
+ if (disk_ioctl(dev, DIOCGMEDIASIZE, &disk_blocks) == 0) {
+ /* DIOCGMEDIASIZE does return bytes. */
+ disk_blocks /= blkio->Media->BlockSize;
+ }
+ d_offset = dev->d_offset;
+ }
+ if (disk_blocks == 0)
+ disk_blocks = blkio->Media->LastBlock + 1 - d_offset;
+
/* make sure we don't read past disk end */
- if ((off + size) / blkio->Media->BlockSize - 1 >
- blkio->Media->LastBlock) {
- size = blkio->Media->LastBlock + 1 -
- off / blkio->Media->BlockSize;
+ if ((off + size) / blkio->Media->BlockSize > d_offset + disk_blocks) {
+ diskend = d_offset + disk_blocks;
+ readstart = off / blkio->Media->BlockSize;
+
+ if (diskend <= readstart) {
+ if (rsize != NULL)
+ *rsize = 0;
+
+ return (EIO);
+ }
+ size = diskend - readstart;
size = size * blkio->Media->BlockSize;
}
diff --git a/usr/src/boot/sys/boot/efi/loader/conf.c b/usr/src/boot/sys/boot/efi/loader/conf.c
index 7da0afc6ca..6b24517c98 100644
--- a/usr/src/boot/sys/boot/efi/loader/conf.c
+++ b/usr/src/boot/sys/boot/efi/loader/conf.c
@@ -36,7 +36,9 @@ __FBSDID("$FreeBSD$");
#endif
struct devsw *devsw[] = {
- &efipart_dev,
+ &efipart_fddev,
+ &efipart_cddev,
+ &efipart_hddev,
&efinet_dev,
#ifdef EFI_ZFS_BOOT
&zfs_dev,
diff --git a/usr/src/boot/sys/boot/efi/loader/devicename.c b/usr/src/boot/sys/boot/efi/loader/devicename.c
index 72588b08f5..1e499c0b1b 100644
--- a/usr/src/boot/sys/boot/efi/loader/devicename.c
+++ b/usr/src/boot/sys/boot/efi/loader/devicename.c
@@ -32,6 +32,7 @@
#include <sys/disklabel.h>
#include <sys/param.h>
#include <bootstrap.h>
+#include <disk.h>
#include <libzfs.h>
#include <efi.h>
@@ -85,9 +86,9 @@ efi_parsedev(struct devdesc **dev, const char *devspec, const char **path)
{
struct devdesc *idev;
struct devsw *dv;
+ int i, unit, err;
char *cp;
const char *np;
- int i;
/* minimum length check */
if (strlen(devspec) < 2)
@@ -103,50 +104,73 @@ efi_parsedev(struct devdesc **dev, const char *devspec, const char **path)
return (ENOENT);
np = devspec + strlen(dv->dv_name);
+ idev = NULL;
+ err = 0;
- if (dv->dv_type == DEVT_ZFS) {
- int err;
+ switch (dv->dv_type) {
+ case DEVT_NONE:
+ break;
+
+ case DEVT_DISK:
+ idev = malloc(sizeof (struct disk_devdesc));
+ if (idev == NULL)
+ return (ENOMEM);
+
+ err = disk_parsedev((struct disk_devdesc *)idev, np, path);
+ if (err != 0)
+ goto fail;
+ break;
+ case DEVT_ZFS:
idev = malloc(sizeof (struct zfs_devdesc));
if (idev == NULL)
return (ENOMEM);
err = zfs_parsedev((struct zfs_devdesc *)idev, np, path);
- if (err != 0) {
- free(idev);
- return (err);
- }
- cp = strchr(np + 1, ':');
- } else {
+ if (err != 0)
+ goto fail;
+ break;
+
+ default:
idev = malloc(sizeof (struct devdesc));
if (idev == NULL)
return (ENOMEM);
- idev->d_dev = dv;
- idev->d_type = dv->dv_type;
- idev->d_unit = -1;
+ unit = 0;
+ cp = (char *)np;
+
if (*np != '\0' && *np != ':') {
- idev->d_unit = strtol(np, &cp, 0);
- if (cp == np) {
- idev->d_unit = -1;
- free(idev);
- return (EUNIT);
+ /* get unit number if present */
+ errno = 0;
+ unit = strtol(np, &cp, 0);
+ if (errno != 0 || cp == np) {
+ err = EUNIT;
+ goto fail;
}
}
- }
+ if (*cp != '\0' && *cp != ':') {
+ err = EINVAL;
+ goto fail;
+ }
- if (*cp != '\0' && *cp != ':') {
- free(idev);
- return (EINVAL);
+ idev->d_unit = unit;
+ if (path != NULL)
+ *path = (*cp == '\0') ? cp : cp + 1;
+ break;
}
- if (path != NULL)
- *path = (*cp == '\0') ? cp : cp + 1;
+ idev->d_dev = dv;
+ idev->d_type = dv->dv_type;
+
if (dev != NULL)
*dev = idev;
else
free(idev);
return (0);
+
+fail:
+ free(idev);
+ return (err);
}
char *
@@ -156,12 +180,16 @@ efi_fmtdev(void *vdev)
static char buf[SPECNAMELEN + 1];
switch (dev->d_type) {
- case DEVT_ZFS:
- return (zfs_fmtdev(dev));
case DEVT_NONE:
strlcpy(buf, "(no device)", sizeof (buf));
break;
+ case DEVT_DISK:
+ return (disk_fmtdev(vdev));
+
+ case DEVT_ZFS:
+ return (zfs_fmtdev(dev));
+
default:
snprintf(buf, sizeof (buf), "%s%d:", dev->d_dev->dv_name,
dev->d_unit);
diff --git a/usr/src/boot/sys/boot/efi/loader/main.c b/usr/src/boot/sys/boot/efi/loader/main.c
index 3ef635fd91..7db2db1f64 100644
--- a/usr/src/boot/sys/boot/efi/loader/main.c
+++ b/usr/src/boot/sys/boot/efi/loader/main.c
@@ -35,6 +35,7 @@
#include <inttypes.h>
#include <string.h>
#include <setjmp.h>
+#include <disk.h>
#include <efi.h>
#include <efilib.h>
@@ -65,6 +66,7 @@ extern void acpi_detect(void);
extern void efi_getsmap(void);
#ifdef EFI_ZFS_BOOT
static void efi_zfs_probe(void);
+static uint64_t pool_guid;
#endif
static int
@@ -149,12 +151,107 @@ out:
return retval;
}
+static void
+set_devdesc_currdev(struct devsw *dev, int unit)
+{
+ struct devdesc currdev;
+ char *devname;
+
+ currdev.d_dev = dev;
+ currdev.d_type = currdev.d_dev->dv_type;
+ currdev.d_unit = unit;
+ currdev.d_opendata = NULL;
+ devname = efi_fmtdev(&currdev);
+
+ env_setenv("currdev", EV_VOLATILE, devname, efi_setcurrdev,
+ env_nounset);
+ env_setenv("loaddev", EV_VOLATILE, devname, env_noset, env_nounset);
+}
+
static int
-find_currdev(EFI_LOADED_IMAGE *img, struct devsw **dev, int *unit,
- uint64_t *extra)
+find_currdev(EFI_LOADED_IMAGE *img)
{
+ pdinfo_list_t *pdi_list;
+ pdinfo_t *dp, *pp;
EFI_DEVICE_PATH *devpath, *copy;
EFI_HANDLE h;
+ char *devname;
+ struct devsw *dev;
+ int unit;
+ uint64_t extra;
+
+ /* Did efi_zfs_probe() detect the boot pool? */
+ if (pool_guid != 0) {
+ struct zfs_devdesc currdev;
+
+ currdev.d_dev = &zfs_dev;
+ currdev.d_unit = 0;
+ currdev.d_type = currdev.d_dev->dv_type;
+ currdev.d_opendata = NULL;
+ currdev.pool_guid = pool_guid;
+ currdev.root_guid = 0;
+ devname = efi_fmtdev(&currdev);
+
+ env_setenv("currdev", EV_VOLATILE, devname, efi_setcurrdev,
+ env_nounset);
+ env_setenv("loaddev", EV_VOLATILE, devname, env_noset,
+ env_nounset);
+ return (0);
+ }
+
+ /* We have device lists for hd, cd, fd, walk them all. */
+ pdi_list = efiblk_get_pdinfo_list(&efipart_hddev);
+ STAILQ_FOREACH(dp, pdi_list, pd_link) {
+ struct disk_devdesc currdev;
+
+ currdev.d_dev = &efipart_hddev;
+ currdev.d_type = currdev.d_dev->dv_type;
+ currdev.d_unit = dp->pd_unit;
+ currdev.d_opendata = NULL;
+ currdev.d_slice = -1;
+ currdev.d_partition = -1;
+
+ if (dp->pd_handle == img->DeviceHandle) {
+ devname = efi_fmtdev(&currdev);
+
+ env_setenv("currdev", EV_VOLATILE, devname,
+ efi_setcurrdev, env_nounset);
+ env_setenv("loaddev", EV_VOLATILE, devname,
+ env_noset, env_nounset);
+ return (0);
+ }
+ /* Assuming GPT partitioning. */
+ STAILQ_FOREACH(pp, &dp->pd_part, pd_link) {
+ if (pp->pd_handle == img->DeviceHandle) {
+ currdev.d_slice = pp->pd_unit;
+ currdev.d_partition = 255;
+ devname = efi_fmtdev(&currdev);
+
+ env_setenv("currdev", EV_VOLATILE, devname,
+ efi_setcurrdev, env_nounset);
+ env_setenv("loaddev", EV_VOLATILE, devname,
+ env_noset, env_nounset);
+ return (0);
+ }
+ }
+ }
+
+ pdi_list = efiblk_get_pdinfo_list(&efipart_cddev);
+ STAILQ_FOREACH(dp, pdi_list, pd_link) {
+ if (dp->pd_handle == img->DeviceHandle ||
+ dp->pd_alias == img->DeviceHandle) {
+ set_devdesc_currdev(&efipart_cddev, dp->pd_unit);
+ return (0);
+ }
+ }
+
+ pdi_list = efiblk_get_pdinfo_list(&efipart_fddev);
+ STAILQ_FOREACH(dp, pdi_list, pd_link) {
+ if (dp->pd_handle == img->DeviceHandle) {
+ set_devdesc_currdev(&efipart_fddev, dp->pd_unit);
+ return (0);
+ }
+ }
/*
* Try the device handle from our loaded image first. If that
@@ -162,8 +259,10 @@ find_currdev(EFI_LOADED_IMAGE *img, struct devsw **dev, int *unit,
* any of the nodes in that path match one of the enumerated
* handles.
*/
- if (efi_handle_lookup(img->DeviceHandle, dev, unit, extra) == 0)
+ if (efi_handle_lookup(img->DeviceHandle, &dev, &unit, &extra) == 0) {
+ set_devdesc_currdev(dev, unit);
return (0);
+ }
copy = NULL;
devpath = efi_lookup_image_devpath(IH);
@@ -175,8 +274,10 @@ find_currdev(EFI_LOADED_IMAGE *img, struct devsw **dev, int *unit,
free(copy);
copy = NULL;
- if (efi_handle_lookup(h, dev, unit, extra) == 0)
+ if (efi_handle_lookup(h, &dev, &unit, &extra) == 0) {
+ set_devdesc_currdev(dev, unit);
return (0);
+ }
devpath = efi_lookup_devpath(h);
if (devpath != NULL) {
@@ -195,9 +296,7 @@ main(int argc, CHAR16 *argv[])
char var[128];
EFI_LOADED_IMAGE *img;
EFI_GUID *guid;
- int i, j, vargood, unit, howto;
- struct devsw *dev;
- uint64_t pool_guid;
+ int i, j, vargood, howto;
void *ptr;
UINTN k;
int has_kbd;
@@ -365,45 +464,9 @@ main(int argc, CHAR16 *argv[])
*/
BS->SetWatchdogTimer(0, 0, 0, NULL);
- if (find_currdev(img, &dev, &unit, &pool_guid) != 0)
+ if (find_currdev(img) != 0)
return (EFI_NOT_FOUND);
- switch (dev->dv_type) {
-#ifdef EFI_ZFS_BOOT
- case DEVT_ZFS: {
- struct zfs_devdesc currdev;
-
- currdev.d_dev = dev;
- currdev.d_unit = unit;
- currdev.d_type = currdev.d_dev->dv_type;
- currdev.d_opendata = NULL;
- currdev.pool_guid = pool_guid;
- currdev.root_guid = 0;
- env_setenv("currdev", EV_VOLATILE, efi_fmtdev(&currdev),
- efi_setcurrdev, env_nounset);
- env_setenv("loaddev", EV_VOLATILE, efi_fmtdev(&currdev), env_noset,
- env_nounset);
-#ifdef __FreeBSD__
- init_zfs_bootenv(zfs_fmtdev(&currdev));
-#endif
- break;
- }
-#endif
- default: {
- struct devdesc currdev;
-
- currdev.d_dev = dev;
- currdev.d_unit = unit;
- currdev.d_opendata = NULL;
- currdev.d_type = currdev.d_dev->dv_type;
- env_setenv("currdev", EV_VOLATILE, efi_fmtdev(&currdev),
- efi_setcurrdev, env_nounset);
- env_setenv("loaddev", EV_VOLATILE, efi_fmtdev(&currdev), env_noset,
- env_nounset);
- break;
- }
- }
-
efi_init_environment();
setenv("ISADIR", "amd64", 1); /* we only build 64bit */
acpi_detect();
@@ -842,18 +905,31 @@ COMMAND_SET(chain, "chain", "chain load file", command_chain);
static void
efi_zfs_probe(void)
{
- EFI_HANDLE h;
- u_int unit;
- int i;
- char dname[SPECNAMELEN + 1];
- uint64_t guid;
-
- unit = 0;
- h = efi_find_handle(&efipart_dev, 0);
- for (i = 0; h != NULL; h = efi_find_handle(&efipart_dev, ++i)) {
- snprintf(dname, sizeof(dname), "%s%d:", efipart_dev.dv_name, i);
- if (zfs_probe_dev(dname, &guid) == 0)
- (void)efi_handle_update_dev(h, &zfs_dev, unit++, guid);
+ pdinfo_list_t *hdi;
+ pdinfo_t *hd, *pd = NULL;
+ EFI_GUID imgid = LOADED_IMAGE_PROTOCOL;
+ EFI_LOADED_IMAGE *img;
+ char devname[SPECNAMELEN + 1];
+
+ BS->HandleProtocol(IH, &imgid, (VOID**)&img);
+ hdi = efiblk_get_pdinfo_list(&efipart_hddev);
+
+ /*
+ * Find the handle for the boot device. The boot1 did find the
+ * device with loader binary, now we need to search for the
+ * same device and if it is part of the zfs pool, we record the
+ * pool GUID for currdev setup.
+ */
+ STAILQ_FOREACH(hd, hdi, pd_link) {
+ STAILQ_FOREACH(pd, &hd->pd_part, pd_link) {
+
+ snprintf(devname, sizeof(devname), "%s%dp%d:",
+ efipart_hddev.dv_name, hd->pd_unit, pd->pd_unit);
+ if (pd->pd_handle == img->DeviceHandle)
+ (void) zfs_probe_dev(devname, &pool_guid);
+ else
+ (void) zfs_probe_dev(devname, NULL);
+ }
}
}
diff --git a/usr/src/boot/sys/boot/zfs/zfs.c b/usr/src/boot/sys/boot/zfs/zfs.c
index d4b7e8ef40..adfa9caf5a 100644
--- a/usr/src/boot/sys/boot/zfs/zfs.c
+++ b/usr/src/boot/sys/boot/zfs/zfs.c
@@ -490,6 +490,8 @@ zfs_probe_dev(const char *devname, uint64_t *pool_guid)
uint64_t mediasz;
int ret;
+ if (pool_guid)
+ *pool_guid = 0;
pa.fd = open(devname, O_RDONLY);
if (pa.fd == -1)
return (ENXIO);
@@ -497,6 +499,7 @@ zfs_probe_dev(const char *devname, uint64_t *pool_guid)
ret = zfs_probe(pa.fd, pool_guid);
if (ret == 0)
return (0);
+
/* Probe each partition */
ret = ioctl(pa.fd, DIOCGMEDIASIZE, &mediasz);
if (ret == 0)
@@ -512,6 +515,8 @@ zfs_probe_dev(const char *devname, uint64_t *pool_guid)
}
}
close(pa.fd);
+ if (pool_guid && *pool_guid == 0)
+ ret = ENXIO;
return (ret);
}