loader: Replace EFI part devices.
Rewrite EFI part device interface to present disk devices in more user friendly way. We keep list of three types of devices: floppy, cd and disk, the visible names: fdX: cdX: and diskX: Use common/disk.c and common/part.c interfaces to manage the partitioning. The lsdev -l will additionally list the device path. Reviewed by: imp, allanjude Approved by: imp (mentor), allanjude (mentor) Differential Revision: https://reviews.freebsd.org/D8581 git-svn-id: svn+ssh://svn.freebsd.org/base/head@313333 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f
This commit is contained in:
parent
3fd6269950
commit
23bf6bc1ed
@ -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;
|
||||
};
|
||||
|
@ -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_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 *);
|
||||
int efi_devpath_match(EFI_DEVICE_PATH *, EFI_DEVICE_PATH *);
|
||||
CHAR16 *efi_devpath_name(EFI_DEVICE_PATH *);
|
||||
void efi_free_devpath_name(CHAR16 *);
|
||||
|
||||
|
@ -138,3 +138,31 @@ efi_devpath_handle(EFI_DEVICE_PATH *devpath)
|
||||
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);
|
||||
}
|
||||
|
@ -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,57 +39,110 @@ __FBSDID("$FreeBSD$");
|
||||
#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_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
|
||||
};
|
||||
static struct pdinfo *pdinfo;
|
||||
static int npdinfo = 0;
|
||||
|
||||
#define PD(dev) (pdinfo[(dev)->d_unit])
|
||||
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 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))
|
||||
@ -96,33 +151,150 @@ efipart_init(void)
|
||||
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;
|
||||
efipart_handles = hin;
|
||||
efipart_nhandles = sz;
|
||||
return (0);
|
||||
}
|
||||
|
||||
bzero(aliases, nin * sizeof(EFI_HANDLE));
|
||||
pdinfo = malloc(nin * sizeof(*pdinfo));
|
||||
if (pdinfo == NULL)
|
||||
return (ENOMEM);
|
||||
static ACPI_HID_DEVICE_PATH *
|
||||
efipart_floppy(EFI_DEVICE_PATH *node)
|
||||
{
|
||||
ACPI_HID_DEVICE_PATH *acpi = NULL;
|
||||
|
||||
for (n = 0; n < nin; n++) {
|
||||
devpath = efi_lookup_devpath(hin[n]);
|
||||
if (devpath == NULL) {
|
||||
continue;
|
||||
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);
|
||||
}
|
||||
|
||||
status = BS->HandleProtocol(hin[n], &blkio_guid,
|
||||
(void**)&blkio);
|
||||
/*
|
||||
* 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);
|
||||
|
||||
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;
|
||||
|
||||
if ((node = efi_devpath_last_node(devpath)) == NULL)
|
||||
continue;
|
||||
if ((acpi = efipart_floppy(node)) != NULL) {
|
||||
efipart_fdinfo_add(efipart_handles[i], acpi->UID,
|
||||
devpath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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 (!blkio->Media->LogicalPartition) {
|
||||
nrdisk++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we come across a logical partition of subtype CDROM
|
||||
* it doesn't refer to the CD filesystem itself, but rather
|
||||
@ -130,8 +302,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);
|
||||
@ -143,109 +313,400 @@ 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++;
|
||||
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);
|
||||
|
||||
if (nout == 0 && nrdisk > 0)
|
||||
printf("Found %d disk(s) but no logical partition\n", nrdisk);
|
||||
return (err);
|
||||
}
|
||||
|
||||
static int
|
||||
efipart_print(int verbose)
|
||||
efipart_initcd(void)
|
||||
{
|
||||
char line[80];
|
||||
EFI_BLOCK_IO *blkio;
|
||||
EFI_HANDLE h;
|
||||
EFI_STATUS status;
|
||||
u_int unit;
|
||||
int ret = 0;
|
||||
int rv;
|
||||
|
||||
printf("%s devices:", efipart_dev.dv_name);
|
||||
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);
|
||||
}
|
||||
|
||||
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_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 (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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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:", 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);
|
||||
|
||||
h = efi_find_handle(&efipart_dev, dev->d_unit);
|
||||
if (h == NULL)
|
||||
if (dev == NULL)
|
||||
return (EINVAL);
|
||||
|
||||
status = BS->HandleProtocol(h, &blkio_guid, (void **)&blkio);
|
||||
if (EFI_ERROR(status))
|
||||
return (efi_status_to_errno(status));
|
||||
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 (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);
|
||||
}
|
||||
|
||||
@ -294,12 +755,29 @@ 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);
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
@ -307,7 +785,9 @@ 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;
|
||||
off_t off;
|
||||
char *blkbuf;
|
||||
@ -317,7 +797,15 @@ efipart_realstrategy(void *devdata, int rw, daddr_t blk, size_t size,
|
||||
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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$");
|
||||
#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 @@ efi_parsedev(struct devdesc **dev, const char *devspec, const char **path)
|
||||
struct devsw *dv;
|
||||
char *cp;
|
||||
const char *np;
|
||||
int i;
|
||||
int i, err;
|
||||
|
||||
/* minimum length check */
|
||||
if (strlen(devspec) < 2)
|
||||
@ -106,11 +107,26 @@ efi_parsedev(struct devdesc **dev, const char *devspec, const char **path)
|
||||
return (ENOENT);
|
||||
|
||||
np = devspec + strlen(dv->dv_name);
|
||||
err = 0;
|
||||
|
||||
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
|
||||
if (dv->dv_type == DEVT_ZFS) {
|
||||
int err;
|
||||
|
||||
case DEVT_ZFS:
|
||||
idev = malloc(sizeof(struct zfs_devdesc));
|
||||
if (idev == NULL)
|
||||
return (ENOMEM);
|
||||
@ -120,34 +136,35 @@ efi_parsedev(struct devdesc **dev, const char *devspec, const char **path)
|
||||
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 (path != NULL)
|
||||
*path = (*cp == 0) ? cp : cp + 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (*cp != '\0' && *cp != ':') {
|
||||
free(idev);
|
||||
return (EINVAL);
|
||||
}
|
||||
idev->d_dev = dv;
|
||||
idev->d_type = dv->dv_type;
|
||||
|
||||
if (path != NULL)
|
||||
*path = (*cp == 0) ? cp : cp + 1;
|
||||
if (dev != NULL)
|
||||
*dev = idev;
|
||||
else
|
||||
@ -162,14 +179,17 @@ efi_fmtdev(void *vdev)
|
||||
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;
|
||||
|
@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <stand.h>
|
||||
#include <string.h>
|
||||
#include <setjmp.h>
|
||||
#include <disk.h>
|
||||
|
||||
#include <efi.h>
|
||||
#include <efilib.h>
|
||||
@ -70,6 +71,7 @@ EFI_GUID inputid = SIMPLE_TEXT_INPUT_PROTOCOL;
|
||||
|
||||
#ifdef EFI_ZFS_BOOT
|
||||
static void efi_zfs_probe(void);
|
||||
static uint64_t pool_guid;
|
||||
#endif
|
||||
|
||||
static int
|
||||
@ -154,12 +156,107 @@ has_keyboard(void)
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int
|
||||
find_currdev(EFI_LOADED_IMAGE *img, struct devsw **dev, int *unit,
|
||||
uint64_t *extra)
|
||||
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)
|
||||
{
|
||||
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
|
||||
@ -167,8 +264,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);
|
||||
@ -180,8 +279,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) {
|
||||
@ -191,11 +292,6 @@ find_currdev(EFI_LOADED_IMAGE *img, struct devsw **dev, int *unit,
|
||||
}
|
||||
free(copy);
|
||||
|
||||
/* Try to fallback on first device */
|
||||
if (devsw[0] != NULL) {
|
||||
*dev = devsw[0];
|
||||
return (0);
|
||||
}
|
||||
return (ENOENT);
|
||||
}
|
||||
|
||||
@ -205,9 +301,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;
|
||||
UINTN k;
|
||||
int has_kbd;
|
||||
char buf[40];
|
||||
@ -376,43 +470,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);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
efi_init_environment();
|
||||
setenv("LINES", "24", 1); /* optional */
|
||||
|
||||
@ -733,21 +793,67 @@ COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt);
|
||||
#endif
|
||||
|
||||
#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];
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
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
|
||||
|
@ -486,6 +486,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);
|
||||
@ -493,6 +495,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)
|
||||
@ -508,6 +511,8 @@ zfs_probe_dev(const char *devname, uint64_t *pool_guid)
|
||||
}
|
||||
}
|
||||
close(pa.fd);
|
||||
if (pool_guid && *pool_guid == 0)
|
||||
ret = ENXIO;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user