Page MenuHomeFreeBSD

D13784.id40090.diff
No OneTemporary

D13784.id40090.diff

Index: stand/efi/include/efilib.h
===================================================================
--- stand/efi/include/efilib.h
+++ stand/efi/include/efilib.h
@@ -59,10 +59,13 @@
uint32_t pd_unit; /* unit number */
uint32_t pd_open; /* reference counter */
void *pd_bcache; /* buffer cache data */
+ struct pdinfo *pd_parent; /* Linked items (eg partitions) */
+ struct devsw *pd_devsw; /* Back pointer to devsw */
} pdinfo_t;
pdinfo_list_t *efiblk_get_pdinfo_list(struct devsw *dev);
pdinfo_t *efiblk_get_pdinfo(struct devdesc *dev);
+pdinfo_t *efiblk_get_pdinfo_by_handle(EFI_HANDLE h);
void *efi_get_table(EFI_GUID *tbl);
Index: stand/efi/include/efizfs.h
===================================================================
--- stand/efi/include/efizfs.h
+++ stand/efi/include/efizfs.h
@@ -48,6 +48,7 @@
extern zfsinfo_list_t *efizfs_get_zfsinfo_list(void);
extern bool efi_zfs_is_preferred(EFI_HANDLE *h);
extern EFI_HANDLE efizfs_get_handle_by_guid(uint64_t);
+extern bool efizfs_get_guid_by_handle(EFI_HANDLE, uint64_t *);
#endif
Index: stand/efi/libefi/devicename.c
===================================================================
--- stand/efi/libefi/devicename.c
+++ stand/efi/libefi/devicename.c
@@ -161,7 +161,6 @@
}
idev->d_dev = dv;
- idev->d_type = dv->dv_type;
if (dev != NULL)
*dev = idev;
@@ -180,7 +179,7 @@
struct devdesc *dev = (struct devdesc *)vdev;
static char buf[SPECNAMELEN + 1];
- switch(dev->d_type) {
+ switch(dev->d_dev->dv_type) {
case DEVT_NONE:
strcpy(buf, "(no device)");
break;
Index: stand/efi/libefi/efipart.c
===================================================================
--- stand/efi/libefi/efipart.c
+++ stand/efi/libefi/efipart.c
@@ -136,6 +136,40 @@
return (pd);
}
+static bool
+same_handle(pdinfo_t *pd, EFI_HANDLE h)
+{
+
+ return (pd->pd_handle == h || pd->pd_alias == h);
+}
+
+pdinfo_t *
+efiblk_get_pdinfo_by_handle(EFI_HANDLE h)
+{
+ pdinfo_t *dp, *pp;
+
+ /*
+ * Check hard disks, then cd, then floppy
+ */
+ STAILQ_FOREACH(dp, &hdinfo, pd_link) {
+ if (same_handle(dp, h))
+ return (dp);
+ STAILQ_FOREACH(pp, &dp->pd_part, pd_link) {
+ if (same_handle(pp, h))
+ return (pp);
+ }
+ }
+ STAILQ_FOREACH(dp, &cdinfo, pd_link) {
+ if (same_handle(dp, h))
+ return (dp);
+ }
+ STAILQ_FOREACH(dp, &fdinfo, pd_link) {
+ if (same_handle(dp, h))
+ return (dp);
+ }
+ return (NULL);
+}
+
static int
efiblk_pdinfo_count(pdinfo_list_t *pdi)
{
@@ -294,6 +328,8 @@
fd->pd_unit = uid;
fd->pd_handle = handle;
fd->pd_devpath = devpath;
+ fd->pd_parent = NULL;
+ fd->pd_devsw = &efipart_fddev;
STAILQ_INSERT_TAIL(&fdinfo, fd, pd_link);
return (0);
}
@@ -364,6 +400,8 @@
cd->pd_unit = unit;
cd->pd_alias = alias;
cd->pd_devpath = devpath;
+ cd->pd_parent = NULL;
+ cd->pd_devsw = &efipart_cddev;
STAILQ_INSERT_TAIL(&cdinfo, cd, pd_link);
return (0);
}
@@ -489,6 +527,8 @@
pd->pd_handle = part_handle;
pd->pd_unit = node->PartitionNumber;
pd->pd_devpath = part_devpath;
+ pd->pd_parent = hd;
+ pd->pd_devsw = &efipart_hddev;
STAILQ_INSERT_TAIL(&hd->pd_part, pd, pd_link);
return (0);
}
@@ -505,6 +545,8 @@
hd->pd_handle = disk_handle;
hd->pd_unit = unit;
hd->pd_devpath = disk_devpath;
+ hd->pd_parent = NULL;
+ hd->pd_devsw = &efipart_hddev;
STAILQ_INSERT_TAIL(&hdinfo, hd, pd_link);
if (part_devpath == NULL)
@@ -521,6 +563,8 @@
pd->pd_handle = part_handle;
pd->pd_unit = node->PartitionNumber;
pd->pd_devpath = part_devpath;
+ pd->pd_parent = hd;
+ pd->pd_devsw = &efipart_hddev;
STAILQ_INSERT_TAIL(&hd->pd_part, pd, pd_link);
return (0);
@@ -579,6 +623,8 @@
pd->pd_handle = disk_handle;
pd->pd_unit = unit;
pd->pd_devpath = devpath;
+ pd->pd_parent = NULL;
+ pd->pd_devsw = &efipart_hddev;
STAILQ_INSERT_TAIL(&hdinfo, pd, pd_link);
free(pathname);
return (0);
@@ -609,6 +655,8 @@
pd->pd_handle = disk_handle;
pd->pd_unit = unit;
pd->pd_devpath = devpath;
+ pd->pd_parent = last;
+ pd->pd_devsw = &efipart_hddev;
STAILQ_INSERT_TAIL(&last->pd_part, pd, pd_link);
free(pathname);
return (0);
Index: stand/efi/libefi/efizfs.c
===================================================================
--- stand/efi/libefi/efizfs.c
+++ stand/efi/libefi/efizfs.c
@@ -65,6 +65,22 @@
return (NULL);
}
+bool
+efizfs_get_guid_by_handle(EFI_HANDLE handle, uint64_t *guid)
+{
+ zfsinfo_t *zi;
+
+ if (guid == NULL)
+ return (1);
+ STAILQ_FOREACH(zi, &zfsinfo, zi_link) {
+ if (zi->zi_handle == handle) {
+ *guid = zi->zi_pool_guid;
+ return (true);
+ }
+ }
+ return (false);
+}
+
static void
insert_zfs(EFI_HANDLE handle, uint64_t guid)
{
Index: stand/efi/loader/main.c
===================================================================
--- stand/efi/loader/main.c
+++ stand/efi/loader/main.c
@@ -78,6 +78,15 @@
static EFI_LOADED_IMAGE *img;
+/*
+ * Number of seconds to wait for a keystroke before exiting with failure
+ * in the event no currdev is found. -2 means always break, -1 means
+ * never break, 0 means poll once and then reboot, > 0 means wait for
+ * that many seconds. "fail_timeout" can be set in the environment as
+ * well.
+ */
+static int fail_timeout = 5;
+
#ifdef EFI_ZFS_BOOT
bool
efi_zfs_is_preferred(EFI_HANDLE *h)
@@ -169,119 +178,169 @@
}
static void
-set_devdesc_currdev(struct devsw *dev, int unit)
+set_currdev_devdesc(struct devdesc *currdev)
{
- struct devdesc currdev;
char *devname;
+ 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 void
+set_currdev_devsw(struct devsw *dev, int unit)
+{
+ struct devdesc currdev;
+
currdev.d_dev = dev;
- currdev.d_type = currdev.d_dev->dv_type;
currdev.d_unit = unit;
currdev.d_opendata = NULL;
+
+ set_currdev_devdesc(&currdev);
+}
+
+static void
+set_currdev_pdinfo(pdinfo_t *dp)
+{
+
+ /*
+ * Disks are special: they have partitions. if the parent
+ * pointer is non-null, we're a partition not a full disk
+ * and we need to adjust currdev appropriately.
+ */
+ if (dp->pd_devsw->dv_type == DEVT_DISK) {
+ struct disk_devdesc currdev;
+
+ currdev.d_dev = dp->pd_devsw;
+ currdev.d_opendata = NULL;
+ currdev.d_partition = -1;
+ if (dp->pd_parent == NULL) {
+ currdev.d_unit = dp->pd_unit;
+ currdev.d_slice = -1;
+ } else {
+ currdev.d_unit = dp->pd_parent->pd_unit;
+ currdev.d_slice = dp->pd_unit;
+ }
+ set_currdev_devdesc((struct devdesc *)&currdev);
+ } else {
+ set_currdev_devsw(dp->pd_devsw, dp->pd_unit);
+ }
+}
+
+static bool
+sanity_check_currdev(void)
+{
+ struct stat st;
+
+ return (stat("/boot/defaults/loader.conf", &st) == 0);
+}
+
+#ifdef EFI_ZFS_BOOT
+static bool
+probe_zfs_currdev(uint64_t guid)
+{
+ char *devname;
+ struct zfs_devdesc currdev;
+
+ currdev.d_dev = &zfs_dev;
+ currdev.d_unit = 0;
+ currdev.d_opendata = NULL;
+ currdev.pool_guid = guid;
+ currdev.root_guid = 0;
+ set_currdev_devdesc((struct devdesc *)&currdev);
devname = efi_fmtdev(&currdev);
+ init_zfs_bootenv(devname);
- env_setenv("currdev", EV_VOLATILE, devname, efi_setcurrdev,
- env_nounset);
- env_setenv("loaddev", EV_VOLATILE, devname, env_noset, env_nounset);
+ return (sanity_check_currdev());
+}
+#endif
+
+static bool
+try_as_currdev(pdinfo_t *hd, pdinfo_t *pp)
+{
+ uint64_t guid;
+
+#ifdef EFI_ZFS_BOOT
+ /*
+ * If there's a zpool on this device, try it as a ZFS
+ * filesystem, which has somewhat different setup than all
+ * other types of fs due to imperfect loader integration.
+ * This all stems from ZFS being both a device (zpool) and
+ * a filesystem, plus the boot env feature.
+ */
+ if (efizfs_get_guid_by_handle(pp->pd_handle, &guid))
+ return (probe_zfs_currdev(guid));
+#endif
+ /*
+ * All other filesystems just need the pdinfo
+ * initialized in the standard way.
+ */
+ set_currdev_pdinfo(pp);
+ return (sanity_check_currdev());
}
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;
#ifdef EFI_ZFS_BOOT
- /* Did efi_zfs_probe() detect the boot pool? */
+ /*
+ * Did efi_zfs_probe() detect the boot pool? If so, use the zpool
+ * it found, if it's sane. ZFS is the only thing that looks for
+ * disks and pools to boot. This may change in the future, however,
+ * if we allow specifying which pool to boot from via UEFI variables
+ * rather than the bootenv stuff that FreeBSD uses today.
+ */
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);
- init_zfs_bootenv(devname);
- return (0);
+ if (probe_zfs_currdev(pool_guid))
+ return (0);
}
#endif /* EFI_ZFS_BOOT */
- /* 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);
+ /*
+ * Try to find the block device by its handle based on the
+ * image we're booting. If we can't find a sane partition,
+ * search all the other partitions of the disk. We do not
+ * search other disks because it's a violation of the UEFI
+ * boot protocol to do so. We fail and let UEFI go on to
+ * the next candidate.
+ */
+ dp = efiblk_get_pdinfo_by_handle(img->DeviceHandle);
+ if (dp != NULL) {
+ set_currdev_pdinfo(dp);
+ if (sanity_check_currdev())
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);
+ if (dp->pd_parent != NULL) {
+ dp = dp->pd_parent;
+ STAILQ_FOREACH(pp, &dp->pd_part, pd_link) {
+ /*
+ * Roll up the ZFS special case
+ * for those partitions that have
+ * zpools on them
+ */
+ if (try_as_currdev(dp, pp))
+ 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
* fails, use the device path from the loaded image and see if
* any of the nodes in that path match one of the enumerated
- * handles.
+ * handles. Currently, this handle list is only for netboot.
*/
if (efi_handle_lookup(img->DeviceHandle, &dev, &unit, &extra) == 0) {
- set_devdesc_currdev(dev, unit);
- return (0);
+ set_currdev_devsw(dev, unit);
+ if (sanity_check_currdev())
+ return (0);
}
copy = NULL;
@@ -295,8 +354,9 @@
copy = NULL;
if (efi_handle_lookup(h, &dev, &unit, &extra) == 0) {
- set_devdesc_currdev(dev, unit);
- return (0);
+ set_currdev_devsw(dev, unit);
+ if (sanity_check_currdev())
+ return (0);
}
devpath = efi_lookup_devpath(h);
@@ -310,6 +370,33 @@
return (ENOENT);
}
+static bool
+interactive_interrupt(const char *msg)
+{
+ time_t now, then, last;
+
+ last = 0;
+ now = then = getsecs();
+ printf("%s\n", msg);
+ if (fail_timeout == -2) /* Always break to OK */
+ return (true);
+ if (fail_timeout == -1) /* Never break to OK */
+ return (false);
+ do {
+ if (last != now) {
+ printf("press any key to interrupt reboot in %d seconds\r",
+ fail_timeout - (int)(now - then));
+ last = now;
+ }
+
+ /* XXX no pause or timeout wait for char */
+ if (ischar())
+ return (true);
+ now = getsecs();
+ } while (now - then < fail_timeout);
+ return (false);
+}
+
EFI_STATUS
main(int argc, CHAR16 *argv[])
{
@@ -318,6 +405,7 @@
int i, j, vargood, howto;
UINTN k;
int has_kbd;
+ char *s;
#if !defined(__arm__)
char buf[40];
#endif
@@ -356,12 +444,15 @@
/*
* Parse the args to set the console settings, etc
* boot1.efi passes these in, if it can read /boot.config or /boot/config
- * or iPXE may be setup to pass these in.
+ * or iPXE may be setup to pass these in. Or the optional argument in the
+ * boot environment was used to pass these arguments in (in which case
+ * neither /boot.config nor /boot/config are consulted).
*
* Loop through the args, and for each one that contains an '=' that is
* not the first character, add it to the environment. This allows
* loader and kernel env vars to be passed on the command line. Convert
- * args from UCS-2 to ASCII (16 to 8 bit) as they are copied.
+ * args from UCS-2 to ASCII (16 to 8 bit) as they are copied (though this
+ * method is flawed for non-ASCII characters).
*/
howto = 0;
for (i = 1; i < argc; i++) {
@@ -441,6 +532,9 @@
for (i = 0; howto_names[i].ev != NULL; i++)
if (howto & howto_names[i].mask)
setenv(howto_names[i].ev, "YES", 1);
+ /*
+ * XXX we need fallback to this stuff after looking at the ConIn, ConOut and ConErr variables
+ */
if (howto & RB_MULTIPLE) {
if (howto & RB_SERIAL)
setenv("console", "comconsole efi" , 1);
@@ -455,6 +549,9 @@
return (EFI_BUFFER_TOO_SMALL);
}
+ if ((s = getenv("fail_timeout")) != NULL)
+ fail_timeout = strtol(s, NULL, 10);
+
/*
* Scan the BLOCK IO MEDIA handles then
* march through the device switch probing for things.
@@ -490,8 +587,16 @@
*/
BS->SetWatchdogTimer(0, 0, 0, NULL);
+ /*
+ * Try and find a good currdev based on the image that was booted.
+ * It might be desirable here to have a short pause to allow falling
+ * through to the boot loader instead of returning instantly to follow
+ * the boot protocol and also allow an escape hatch for users wishing
+ * to try something different.
+ */
if (find_currdev(img) != 0)
- return (EFI_NOT_FOUND);
+ if (!interactive_interrupt("Failed to find bootable partition"))
+ return (EFI_NOT_FOUND);
efi_init_environment();
setenv("LINES", "24", 1); /* optional */
@@ -848,7 +953,7 @@
struct disk_devdesc *d_dev;
pdinfo_t *hd, *pd;
- switch (dev->d_type) {
+ switch (dev->d_dev->dv_type) {
#ifdef EFI_ZFS_BOOT
case DEVT_ZFS:
z_dev = (struct zfs_devdesc *)dev;
Index: stand/libsa/stand.h
===================================================================
--- stand/libsa/stand.h
+++ stand/libsa/stand.h
@@ -138,6 +138,12 @@
struct devsw {
const char dv_name[8];
int dv_type; /* opaque type constant, arch-dependant */
+#define DEVT_NONE 0
+#define DEVT_DISK 1
+#define DEVT_NET 2
+#define DEVT_CD 3
+#define DEVT_ZFS 4
+#define DEVT_FD 5
int (*dv_init)(void); /* early probe call */
int (*dv_strategy)(void *devdata, int rw, daddr_t blk,
size_t size, char *buf, size_t *rsize);
@@ -163,13 +169,6 @@
struct devdesc
{
struct devsw *d_dev;
- int d_type;
-#define DEVT_NONE 0
-#define DEVT_DISK 1
-#define DEVT_NET 2
-#define DEVT_CD 3
-#define DEVT_ZFS 4
-#define DEVT_FD 5
int d_unit;
void *d_opendata;
};
Index: stand/zfs/zfs.c
===================================================================
--- stand/zfs/zfs.c
+++ stand/zfs/zfs.c
@@ -701,7 +701,7 @@
spa_t *spa;
buf[0] = '\0';
- if (dev->d_type != DEVT_ZFS)
+ if (dev->d_dev->dv_type != DEVT_ZFS)
return (buf);
if (dev->pool_guid == 0) {

File Metadata

Mime Type
text/plain
Expires
Fri, Nov 21, 7:08 PM (33 m, 52 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
25790150
Default Alt Text
D13784.id40090.diff (16 KB)

Event Timeline