Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F157155460
D13784.id37598.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
14 KB
Referenced Files
None
Subscribers
None
D13784.id37598.diff
View Options
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/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)
{
@@ -290,6 +324,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);
}
@@ -493,6 +531,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);
}
@@ -509,6 +549,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)
@@ -525,6 +567,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);
@@ -583,6 +627,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);
@@ -613,6 +659,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/loader/main.c
===================================================================
--- stand/efi/loader/main.c
+++ stand/efi/loader/main.c
@@ -74,6 +74,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)
@@ -165,20 +174,62 @@
}
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;
- devname = efi_fmtdev(&currdev);
- env_setenv("currdev", EV_VOLATILE, devname, efi_setcurrdev,
- env_nounset);
- env_setenv("loaddev", EV_VOLATILE, devname, env_noset, env_nounset);
+ 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/laoder.conf", &st) == 0);
}
static int
@@ -194,90 +245,62 @@
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;
+ set_currdev_devdesc((struct devdesc *)&currdev);
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 (sanity_check_currdev())
+ 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) {
+ set_currdev_pdinfo(dp);
+ if (sanity_check_currdev())
+ 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;
@@ -291,8 +314,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);
@@ -306,6 +330,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",
+ now - then + fail_timeout);
+ 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[])
{
@@ -314,6 +365,7 @@
int i, j, vargood, howto;
UINTN k;
int has_kbd;
+ char *s;
#if !defined(__arm__)
char buf[40];
#endif
@@ -352,12 +404,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++) {
@@ -437,6 +492,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);
@@ -451,6 +509,9 @@
return (EFI_BUFFER_TOO_SMALL);
}
+ if ((s = getenv("fail_timeout")) != NULL)
+ fail_timeout = strtol(s, NULL, 10);
+
/*
* March through the device switch probing for things.
*/
@@ -482,8 +543,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 */
@@ -887,7 +956,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/net.h
===================================================================
--- stand/libsa/net.h
+++ stand/libsa/net.h
@@ -128,6 +128,4 @@
char *intoa(n_long); /* similar to inet_ntoa */
n_long inet_addr(char *);
-/* Machine-dependent functions: */
-time_t getsecs(void);
#endif /* ! _STAND_NET_H */
Index: stand/libsa/stand.h
===================================================================
--- stand/libsa/stand.h
+++ stand/libsa/stand.h
@@ -137,6 +137,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);
@@ -162,13 +168,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;
};
@@ -394,6 +393,7 @@
extern int devopen(struct open_file *, const char *, const char **);
extern int devclose(struct open_file *f);
extern void panic(const char *, ...) __dead2 __printflike(1, 2);
+extern time_t getsecs(void);
extern struct fs_ops *file_system[];
extern struct fs_ops *exclusive_file_system;
extern struct devsw *devsw[];
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, May 19, 8:35 PM (17 h, 13 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33327520
Default Alt Text
D13784.id37598.diff (14 KB)
Attached To
Mode
D13784: Make loader.efi dual boot, step 1
Attached
Detach File
Event Timeline
Log In to Comment