Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F146841479
D8581.id22355.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
34 KB
Referenced Files
None
Subscribers
None
D8581.id22355.diff
View Options
Index: lib/libstand/stand.h
===================================================================
--- lib/libstand/stand.h
+++ lib/libstand/stand.h
@@ -168,6 +168,7 @@
#define DEVT_NET 2
#define DEVT_CD 3
#define DEVT_ZFS 4
+#define DEVT_FD 5
int d_unit;
void *d_opendata;
};
Index: sys/boot/common/disk.c
===================================================================
--- sys/boot/common/disk.c
+++ sys/boot/common/disk.c
@@ -46,6 +46,7 @@
struct open_disk {
struct ptable *table;
off_t mediasize;
+ off_t entrysize;
u_int sectorsize;
u_int flags;
int rcnt;
@@ -264,13 +265,25 @@
}
int
-disk_ioctl(struct disk_devdesc *dev, u_long cmd, void *buf)
+disk_ioctl(struct disk_devdesc *dev, u_long cmd, void *data)
{
+ struct open_disk *od = dev->d_opendata;
- if (dev->d_dev->dv_ioctl)
- return ((*dev->d_dev->dv_ioctl)(dev->d_opendata, cmd, buf));
+ switch (cmd) {
+ case DIOCGSECTORSIZE:
+ *(u_int *)data = od->sectorsize;
+ break;
+ case DIOCGMEDIASIZE:
+ if (dev->d_offset == 0)
+ *(off_t *)data = od->mediasize;
+ else
+ *(off_t *)data = od->entrysize * od->sectorsize;
+ break;
+ default:
+ return (ENOTTY);
+ }
- return (ENXIO);
+ return (0);
}
int
@@ -315,6 +328,7 @@
}
dev->d_opendata = od;
od->rcnt = 0;
+ od->entrysize = 0;
}
od->mediasize = mediasize;
od->sectorsize = sectorsize;
@@ -336,8 +350,10 @@
partition >= 0) {
/* It doesn't matter what value has d_slice */
rc = ptable_getpart(od->table, &part, partition);
- if (rc == 0)
+ if (rc == 0) {
dev->d_offset = part.start;
+ od->entrysize = part.end - part.start + 1;
+ }
} else if (slice >= 0) {
/* Try to get information about partition */
if (slice == 0)
@@ -347,6 +363,7 @@
if (rc != 0) /* Partition doesn't exist */
goto out;
dev->d_offset = part.start;
+ od->entrysize = part.end - part.start + 1;
slice = part.index;
if (ptable_gettype(od->table) == PTABLE_GPT) {
partition = 255;
@@ -389,6 +406,7 @@
if (rc != 0)
goto out;
dev->d_offset += part.start;
+ od->entrysize = part.end - part.start + 1;
}
out:
if (table != NULL)
Index: sys/boot/efi/include/efilib.h
===================================================================
--- sys/boot/efi/include/efilib.h
+++ sys/boot/efi/include/efilib.h
@@ -31,16 +31,37 @@
#define _LOADER_EFILIB_H
#include <stand.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; /* link of partitions */
+ EFI_HANDLE pd_handle;
+ EFI_HANDLE pd_alias;
+ EFI_DEVICE_PATH *pd_devpath;
+ EFI_BLOCK_IO *pd_blkio;
+ int pd_unit; /* unit number */
+ int 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);
@@ -53,6 +74,7 @@
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 *);
+int efi_devpath_match(EFI_DEVICE_PATH *, EFI_DEVICE_PATH *);
CHAR16 *efi_devpath_name(EFI_DEVICE_PATH *);
void efi_free_devpath_name(CHAR16 *);
Index: sys/boot/efi/libefi/devpath.c
===================================================================
--- sys/boot/efi/libefi/devpath.c
+++ sys/boot/efi/libefi/devpath.c
@@ -165,3 +165,31 @@
return (NULL);
return (h);
}
+
+int
+efi_devpath_match(EFI_DEVICE_PATH *devpath1, EFI_DEVICE_PATH *devpath2)
+{
+ int len;
+
+ if (devpath1 == NULL || devpath2 == NULL)
+ return (0);
+
+ while (1) {
+ if (DevicePathType(devpath1) != DevicePathType(devpath2) ||
+ DevicePathSubType(devpath1) != DevicePathSubType(devpath2))
+ return (0);
+
+ len = DevicePathNodeLength(devpath1);
+ if (len != DevicePathNodeLength(devpath2))
+ return (0);
+
+ if (memcmp(devpath1, devpath2, (size_t)len) != 0)
+ return (0);
+
+ if (IsDevicePathEnd(devpath1))
+ break;
+ devpath1 = NextDevicePathNode(devpath1);
+ devpath2 = NextDevicePathNode(devpath2);
+ }
+ return (1);
+}
Index: sys/boot/efi/libefi/efipart.c
===================================================================
--- sys/boot/efi/libefi/efipart.c
+++ sys/boot/efi/libefi/efipart.c
@@ -27,8 +27,10 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include <sys/disk.h>
#include <sys/param.h>
#include <sys/time.h>
+#include <sys/queue.h>
#include <stddef.h>
#include <stdarg.h>
@@ -37,59 +39,112 @@
#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, size_t, char *,
size_t *);
static int efipart_realstrategy(void *, int, daddr_t, size_t, size_t, char *,
size_t *);
+
static int efipart_open(struct open_file *, ...);
static int efipart_close(struct open_file *);
-static int efipart_print(int);
+static int efipart_ioctl(struct open_file *, u_long, void *);
-struct devsw efipart_dev = {
- .dv_name = "part",
- .dv_type = DEVT_DISK,
- .dv_init = efipart_init,
+static int efipart_printfd(int);
+static int efipart_printcd(int);
+static int efipart_printhd(int);
+
+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 = noioctl,
- .dv_print = efipart_print,
+ .dv_ioctl = efipart_ioctl,
+ .dv_print = efipart_printfd,
.dv_cleanup = NULL
};
-/*
- * info structure to support bcache
- */
-struct pdinfo {
- int pd_unit; /* unit number */
- int pd_open; /* reference counter */
- void *pd_bcache; /* buffer cache data */
+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_inithd,
+ .dv_strategy = efipart_strategy,
+ .dv_open = efipart_open,
+ .dv_close = efipart_close,
+ .dv_ioctl = efipart_ioctl,
+ .dv_print = efipart_printhd,
+ .dv_cleanup = NULL
};
-static struct pdinfo *pdinfo;
-static int npdinfo = 0;
-#define PD(dev) (pdinfo[(dev)->d_unit])
+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)
+{
+ pdinfo_t *pd;
+
+ 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, nrdisk;
- 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,33 +153,148 @@
if (EFI_ERROR(status))
return (efi_status_to_errno(status));
- /* Filter handles to only include FreeBSD partitions. */
- nin = sz / sizeof(EFI_HANDLE);
- hout = hin + nin;
- aliases = hout + nin;
- nout = 0;
- nrdisk = 0;
-
- bzero(aliases, nin * sizeof(EFI_HANDLE));
- pdinfo = malloc(nin * sizeof(*pdinfo));
- if (pdinfo == NULL)
+ efipart_handles = hin;
+ efipart_nhandles = sz;
+ return (0);
+}
+
+static ACPI_HID_DEVICE_PATH *
+efipart_floppy(EFI_DEVICE_PATH *node)
+{
+ ACPI_HID_DEVICE_PATH *acpi = NULL;
+
+ if (DevicePathType(node) == ACPI_DEVICE_PATH &&
+ DevicePathSubType(node) == ACPI_DP) {
+ acpi = (ACPI_HID_DEVICE_PATH *) node;
+ if (acpi->HID == EISA_PNP_ID(0x604) ||
+ acpi->HID == EISA_PNP_ID(0x700) ||
+ acpi->HID == EISA_ID(0x41d1, 0x701)) {
+ return (acpi);
+ }
+ }
+ return (acpi);
+}
+
+/*
+ * 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 = malloc(sizeof(pdinfo_t));
+ if (fd == NULL) {
+ printf("Failed to register floppy %d, out of memory\n", uid);
return (ENOMEM);
+ }
+ memset(fd, 0, sizeof(pdinfo_t));
+ STAILQ_INIT(&fd->pd_part);
- for (n = 0; n < nin; n++) {
- devpath = efi_lookup_devpath(hin[n]);
- if (devpath == NULL) {
+ fd->pd_unit = uid;
+ fd->pd_handle = handle;
+ fd->pd_devpath = devpath;
+ 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, nin;
+
+ nin = efipart_nhandles / sizeof (*efipart_handles);
+ for (i = 0; i < nin; i++) {
+ devpath = efi_lookup_devpath(efipart_handles[i]);
+ if (devpath == NULL)
continue;
+
+ node = efi_devpath_last_node(devpath);
+ 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))
- continue;
- if (!blkio->Media->LogicalPartition) {
- nrdisk++;
- continue;
+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) != 0) {
+ pd->pd_handle = handle;
+ pd->pd_alias = alias;
+ return (0);
}
+ unit++;
+ }
+
+ cd = malloc(sizeof(pdinfo_t));
+ if (cd == NULL) {
+ printf("Failed to add cd %d, out of memory\n", unit);
+ return (ENOMEM);
+ }
+ memset(cd, 0, sizeof(pdinfo_t));
+ 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;
+
+ node = efi_devpath_last_node(devpath);
+ 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
@@ -142,109 +312,386 @@
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++;
+ 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);
+ }
}
+}
- bcache_add_dev(npdinfo);
- err = efi_register_handles(&efipart_dev, hout, aliases, nout);
- free(hin);
+static int
+efipart_initcd(void)
+{
+ int rv;
+
+ rv = efipart_inithandles();
+ if (rv != 0)
+ return (rv);
+ STAILQ_INIT(&cdinfo);
+
+ efipart_updatecd();
- if (nout == 0 && nrdisk > 0)
- printf("Found %d disk(s) but no logical partition\n", nrdisk);
- return (err);
+ bcache_add_dev(efiblk_pdinfo_count(&cdinfo));
+ return (0);
}
static int
-efipart_print(int verbose)
+efipart_hdinfo_add(EFI_HANDLE disk_handle, EFI_HANDLE part_handle)
{
- char line[80];
+ 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);
+ }
+
+ pd = malloc(sizeof(pdinfo_t));
+ if (pd == NULL) {
+ printf("Failed to add disk, out of memory\n");
+ return (ENOMEM);
+ }
+ memset(pd, 0, sizeof(pdinfo_t));
+ STAILQ_INIT(&pd->pd_part);
+ node = (HARDDRIVE_DEVICE_PATH *)efi_devpath_last_node(part_devpath);
+
+ STAILQ_FOREACH(hd, &hdinfo, pd_link) {
+ if (efi_devpath_match(hd->pd_devpath, disk_devpath) != 0) {
+ /* 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 = malloc(sizeof(pdinfo_t));
+ if (pd == NULL) {
+ printf("Failed to add partition, out of memory\n");
+ return (ENOMEM);
+ }
+ memset(pd, 0, sizeof(pdinfo_t));
+ 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);
+}
+
+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;
+
+ node = efi_devpath_last_node(devpath);
+ 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);
+ tmpdevpath = devpathcpy;
+ status = BS->LocateDevicePath(&blkio_guid, &tmpdevpath,
+ &handle);
+ free(devpathcpy);
+ if (EFI_ERROR(status))
+ continue;
+ efipart_hdinfo_add(handle, 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];
- printf("%s devices:", efipart_dev.dv_name);
+ if (STAILQ_EMPTY(pdlist))
+ return (0);
+
+ 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)) {
- snprintf(line, sizeof(line), " %s%d:",
- efipart_dev.dv_name, unit);
- if ((ret = pager_output(line)) != 0)
- break;
-
+ 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)) {
- snprintf(line, sizeof(line), " %llu blocks",
- (unsigned long long)(blkio->Media->LastBlock + 1));
- if ((ret = pager_output(line)) != 0)
+ 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,
+ blkio->Media->RemovableMedia? DISK_F_NOCACHE: 0);
+ 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;
- if (blkio->Media->RemovableMedia)
- if ((ret = pager_output(" (removable)")) != 0)
- break;
}
- if ((ret = pager_output("\n")) != 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) {
+ return (disk_open(dev,
+ blkio->Media->BlockSize * (blkio->Media->LastBlock + 1),
+ blkio->Media->BlockSize,
+ blkio->Media->RemovableMedia? DISK_F_NOCACHE: 0));
+ }
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);
- 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 = efiblk_get_pdinfo(pdi, dev->d_unit);
+ if (pd == NULL)
+ return (EINVAL);
+
+ 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 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);
+ 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 = pd->pd_blkio->Media->BlockSize;
+ break;
+ case DIOCGMEDIASIZE:
+ *(off_t *)data = pd->pd_blkio->Media->BlockSize *
+ (pd->pd_blkio->Media->LastBlock + 1);
+ break;
+ default:
+ return (ENOTTY);
+ }
+
return (0);
}
@@ -293,21 +740,39 @@
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);
- dev = (struct devdesc *)devdata;
bcd.dv_strategy = efipart_realstrategy;
bcd.dv_devdata = devdata;
- bcd.dv_cache = PD(dev).pd_bcache;
- return (bcache_strategy(&bcd, rw, blk, offset, size,
- buf, rsize));
+ bcd.dv_cache = pd->pd_bcache;
+
+ if (dev->d_dev->dv_type == DEVT_DISK) {
+ return (bcache_strategy(&bcd, rw, blk + dev->d_offset, offset,
+ size, buf, rsize));
+ }
+ return (bcache_strategy(&bcd, rw, blk, offset, size, buf, rsize));
}
static int
efipart_realstrategy(void *devdata, int rw, daddr_t blk, size_t offset,
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;
off_t off;
char *blkbuf;
@@ -317,7 +782,15 @@
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);
Index: sys/boot/efi/loader/conf.c
===================================================================
--- sys/boot/efi/loader/conf.c
+++ sys/boot/efi/loader/conf.c
@@ -36,7 +36,9 @@
#endif
struct devsw *devsw[] = {
- &efipart_dev,
+ &efipart_fddev,
+ &efipart_cddev,
+ &efipart_hddev,
&efinet_dev,
#ifdef EFI_ZFS_BOOT
&zfs_dev,
Index: sys/boot/efi/loader/devicename.c
===================================================================
--- sys/boot/efi/loader/devicename.c
+++ sys/boot/efi/loader/devicename.c
@@ -33,6 +33,7 @@
#include <sys/disklabel.h>
#include <sys/param.h>
#include <bootstrap.h>
+#include <disk.h>
#ifdef EFI_ZFS_BOOT
#include <libzfs.h>
#endif
@@ -90,7 +91,7 @@
struct devsw *dv;
char *cp;
const char *np;
- int i;
+ int i, err;
/* minimum length check */
if (strlen(devspec) < 2)
@@ -106,11 +107,26 @@
return (ENOENT);
np = devspec + strlen(dv->dv_name);
+ err = 0;
-#ifdef EFI_ZFS_BOOT
- 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) {
+ free(idev);
+ return (err);
+ }
+ break;
+#ifdef EFI_ZFS_BOOT
+ case DEVT_ZFS:
idev = malloc(sizeof(struct zfs_devdesc));
if (idev == NULL)
return (ENOMEM);
@@ -120,34 +136,35 @@
free(idev);
return (err);
}
- cp = strchr(np + 1, ':');
- } else
+ break;
#endif
- {
+ 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;
+ 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);
}
}
- }
+ if (*cp != '\0' && *cp != ':') {
+ free(idev);
+ return (EINVAL);
+ }
- if (*cp != '\0' && *cp != ':') {
- free(idev);
- return (EINVAL);
+ 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
@@ -162,14 +179,17 @@
static char buf[SPECNAMELEN + 1];
switch(dev->d_type) {
-#ifdef EFI_ZFS_BOOT
- case DEVT_ZFS:
- return (zfs_fmtdev(dev));
-#endif
case DEVT_NONE:
strcpy(buf, "(no device)");
break;
+ case DEVT_DISK:
+ return (disk_fmtdev(vdev));
+
+#ifdef EFI_ZFS_BOOT
+ case DEVT_ZFS:
+ return (zfs_fmtdev(dev));
+#endif
default:
sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit);
break;
Index: sys/boot/efi/loader/main.c
===================================================================
--- sys/boot/efi/loader/main.c
+++ sys/boot/efi/loader/main.c
@@ -35,6 +35,7 @@
#include <stand.h>
#include <string.h>
#include <setjmp.h>
+#include <disk.h>
#include <efi.h>
#include <efilib.h>
@@ -89,6 +90,7 @@
#ifdef EFI_ZFS_BOOT
static void efi_zfs_probe(void);
+static uint64_t pool_guid;
#endif
/*
@@ -199,12 +201,107 @@
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
@@ -212,8 +309,10 @@
* 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);
@@ -222,7 +321,8 @@
if (h == NULL)
break;
- if (efi_handle_lookup(h, dev, unit, extra) == 0) {
+ if (efi_handle_lookup(h, &dev, &unit, &extra) == 0) {
+ set_devdesc_currdev(dev, unit);
if (copy != NULL)
free(copy);
return (0);
@@ -237,11 +337,6 @@
}
}
- /* Try to fallback on first device */
- if (devsw[0] != NULL) {
- *dev = devsw[0];
- return (0);
- }
return (ENOENT);
}
@@ -251,9 +346,7 @@
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;
UINTN k;
int has_kbd;
char buf[40];
@@ -424,43 +517,9 @@
*/
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);
- init_zfs_bootenv(zfs_fmtdev(&currdev));
- 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;
- }
- }
-
snprintf(var, sizeof(var), "%d.%02d", ST->Hdr.Revision >> 16,
ST->Hdr.Revision & 0xffff);
env_setenv("efi-version", EV_VOLATILE, var, env_noset, env_nounset);
@@ -1096,20 +1155,66 @@
#ifdef EFI_ZFS_BOOT
static void
+efipart_probe_img(pdinfo_list_t *hdi)
+{
+ EFI_GUID imgid = LOADED_IMAGE_PROTOCOL;
+ EFI_LOADED_IMAGE *img;
+ pdinfo_t *hd, *pd = NULL;
+ char devname[SPECNAMELEN + 1];
+
+ BS->HandleProtocol(IH, &imgid, (VOID**)&img);
+
+ /*
+ * Search for the booted image device handle from hard disk list.
+ * Note, this does also include usb sticks, and we assume there is no
+ * ZFS on floppies nor cd.
+ * However, we might have booted from floppy (unlikely) or CD,
+ * so we should not surprised if we can not find the handle.
+ */
+ STAILQ_FOREACH(hd, hdi, pd_link) {
+ if (hd->pd_handle == img->DeviceHandle)
+ break;
+ STAILQ_FOREACH(pd, &hd->pd_part, pd_link) {
+ if (pd->pd_handle == img->DeviceHandle)
+ break;
+ }
+ if (pd != NULL)
+ break;
+ }
+ if (hd != NULL) {
+ if (pd != NULL) {
+ snprintf(devname, sizeof(devname), "%s%dp%d:",
+ efipart_hddev.dv_name, hd->pd_unit, pd->pd_unit);
+ } else {
+ snprintf(devname, sizeof(devname), "%s%d:",
+ efipart_hddev.dv_name, hd->pd_unit);
+ }
+ (void) zfs_probe_dev(devname, &pool_guid);
+ }
+}
+
+static void
efi_zfs_probe(void)
{
- EFI_HANDLE h;
- u_int unit;
- int i;
- char dname[SPECNAMELEN + 1];
- uint64_t guid;
+ pdinfo_list_t *hdi;
+ pdinfo_t *hd;
+ char devname[SPECNAMELEN + 1];
+
+ hdi = efiblk_get_pdinfo_list(&efipart_hddev);
+ /*
+ * First probe the boot device (from where loader.efi was read),
+ * and set pool_guid global variable if we are booting from zfs.
+ * Since loader is running, we do have an access to the device,
+ * however, it might not be zfs.
+ */
+
+ if (pool_guid == 0)
+ efipart_probe_img(hdi);
- 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);
+ STAILQ_FOREACH(hd, hdi, pd_link) {
+ snprintf(devname, sizeof(devname), "%s%d:",
+ efipart_hddev.dv_name, hd->pd_unit);
+ (void) zfs_probe_dev(devname, NULL);
}
}
#endif
Index: sys/boot/zfs/zfs.c
===================================================================
--- sys/boot/zfs/zfs.c
+++ sys/boot/zfs/zfs.c
@@ -486,6 +486,8 @@
off_t mediasz;
int ret;
+ if (pool_guid)
+ *pool_guid = 0;
pa.fd = open(devname, O_RDONLY);
if (pa.fd == -1)
return (ENXIO);
@@ -493,6 +495,7 @@
ret = zfs_probe(pa.fd, pool_guid);
if (ret == 0)
return (0);
+
/* Probe each partition */
ret = ioctl(pa.fd, DIOCGMEDIASIZE, &mediasz);
if (ret == 0)
@@ -508,6 +511,8 @@
}
}
close(pa.fd);
+ if (pool_guid && *pool_guid == 0)
+ ret = ENXIO;
return (ret);
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Mar 7, 2:18 AM (15 h, 54 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29349016
Default Alt Text
D8581.id22355.diff (34 KB)
Attached To
Mode
D8581: Replace EFI part devices.
Attached
Detach File
Event Timeline
Log In to Comment