Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 2 Dec 2016 12:02:57 -0500
From:      Eric McCorkle <eric@metricspace.net>
To:        freebsd-hackers@FreeBSD.org, freebsd-amd64@freebsd.org, "current@freebsd.org" <current@freebsd.org>
Subject:   CFT EFI Boot Refactoring
Message-ID:  <d3aad5ef-2d6c-3d79-0fe8-91ee086ed2f8@metricspace.net>

next in thread | raw e-mail | index | archive | help
This is an OpenPGP/MIME signed message (RFC 4880 and 3156)
--2nIKx7PRAmhO47MXFmT0MDKUV6UMsh1v9
Content-Type: multipart/mixed; boundary="7wWD2JXas7wNKFk1Kr7Jd8JHbiuG3wULI";
 protected-headers="v1"
From: Eric McCorkle <eric@metricspace.net>
To: freebsd-hackers@FreeBSD.org, freebsd-amd64@freebsd.org,
 "current@freebsd.org" <current@freebsd.org>
Message-ID: <d3aad5ef-2d6c-3d79-0fe8-91ee086ed2f8@metricspace.net>
Subject: CFT EFI Boot Refactoring

--7wWD2JXas7wNKFk1Kr7Jd8JHbiuG3wULI
Content-Type: multipart/mixed;
 boundary="------------689B5840033FA59B553C984F"

This is a multi-part message in MIME format.
--------------689B5840033FA59B553C984F
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable

Hello everyone,

My work to refactor the EFI boot loader has been in review for some time
now.  This work is a behavior-neutral refactoring which eliminates
duplicated code in boot1, provides better integration of boot1 and
loader with the EFI API, and moves towards better compliance with the
recommendations of the UEFI driver writer's guide.  This work also
serves as a precursor to more work, such as GELI, hot-plugging, and
other things.

One of the reviewers was able to trigger a hang on his setup; however,
it's not clear whether this is a problem in the refactoring, or whether
it's due to a related bug:

https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=3D214423

Therefore, I would like to issue a CFT for this changeset.  We need
people using the boot1/loader EFI boot setup to test their setup using
boot1 and loader as built with this patch applied.

You can also get the source tree directly from my github
(https://github.com/emc2/freebsd.git).  Use the efize_new branch to get
this changeset.  Note that I am maintaining the state of this branch in
a single change at this point using rebase -i, so there *will* be forced
pushes to this branch.


Here are some notes on testing the changeset:

* To test it, just do a buildworld, then copy loader.efi in place and
copy boot1.efi to /efi/BOOT/BOOTX64.EFI on your ESP.  If your system
boots, then the test was successful (there are no new features in this
changeset).

* The output of boot1 is slightly different, so you'll be able to tell
if you installed it correctly.

* I recommend keeping a copy of the basic boot1 around on your ESP, just
in case something goes wrong.  On my setup, I have a backup at
/efi/BOOT/BOOTX64.BAK (with the main program at /efi/BOOT/BOOTX64.EFI,
of course)

* I have been using this on a machine with two disks, a ZFS pool
spanning both disks, and a dummy UFS filesystem for months now, so it
can be considered relatively safe.

* This has also been tested on basic setups without incident, so
priority is on complex or odd setups.

* If something goes wrong, you will most likely get a boot-hang.  If
this happens, please contact me directly with the details, and I'll
coordinate on diagnosis.

--------------689B5840033FA59B553C984F
Content-Type: text/x-patch;
 name="efize.diff"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
 filename="efize.diff"

diff --git a/lib/libstand/Makefile b/lib/libstand/Makefile
index 0ebcaf1..3b608c5 100644
--- a/lib/libstand/Makefile
+++ b/lib/libstand/Makefile
@@ -41,7 +41,7 @@ SRCS+=3D ntoh.c
 .PATH: ${LIBC_SRC}/string
 SRCS+=3D	bcmp.c bcopy.c bzero.c ffs.c fls.c \
 	memccpy.c memchr.c memcmp.c memcpy.c memmove.c memset.c \
-	qdivrem.c strcat.c strchr.c strcmp.c strcpy.c \
+	qdivrem.c strcat.c strchr.c strcmp.c strcpy.c stpcpy.c stpncpy.c \
 	strcspn.c strlcat.c strlcpy.c strlen.c strncat.c strncmp.c strncpy.c \
 	strpbrk.c strrchr.c strsep.c strspn.c strstr.c strtok.c swab.c
 .if ${MACHINE_CPUARCH} =3D=3D "arm"
diff --git a/lib/libstand/stand.h b/lib/libstand/stand.h
index f77a586..066aff0 100644
--- a/lib/libstand/stand.h
+++ b/lib/libstand/stand.h
@@ -24,7 +24,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD$
- * From	$NetBSD: stand.h,v 1.22 1997/06/26 19:17:40 drochner Exp $=09
+ * From	$NetBSD: stand.h,v 1.22 1997/06/26 19:17:40 drochner Exp $
  */
=20
 /*-
@@ -131,7 +131,7 @@ extern struct fs_ops pkgfs_fsops;
 #define	SEEK_CUR	1	/* set file offset to current plus offset */
 #define	SEEK_END	2	/* set file offset to EOF plus offset */
=20
-/*=20
+/*
  * Device switch
  */
 struct devsw {
@@ -166,8 +166,9 @@ struct devdesc
 #define DEVT_NONE	0
 #define DEVT_DISK	1
 #define DEVT_NET	2
-#define DEVT_CD		3
+#define DEVT_CD	3
 #define DEVT_ZFS	4
+#define DEVT_EFI	5
     int			d_unit;
     void		*d_opendata;
 };
@@ -279,7 +280,7 @@ extern struct	dirent *readdirfd(int);
=20
 extern void	srandom(u_long seed);
 extern u_long	random(void);
-   =20
+
 /* imports from stdlib, locally modified */
 extern long	strtol(const char *, char **, int);
 extern unsigned long	strtoul(const char *, char **, int);
@@ -368,9 +369,9 @@ extern int	null_stat(struct open_file *f, struct stat=
 *sb);
 extern int	null_readdir(struct open_file *f, struct dirent *d);
=20
=20
-/*=20
- * Machine dependent functions and data, must be provided or stubbed by =

- * the consumer=20
+/*
+ * Machine dependent functions and data, must be provided or stubbed by
+ * the consumer
  */
 extern int		getchar(void);
 extern int		ischar(void);
diff --git a/sys/boot/efi/Makefile b/sys/boot/efi/Makefile
index 66481f8..00490d0 100644
--- a/sys/boot/efi/Makefile
+++ b/sys/boot/efi/Makefile
@@ -15,7 +15,7 @@ SUBDIR+=3D	fdt
 .if ${MACHINE_CPUARCH} =3D=3D "aarch64" || \
     ${MACHINE_CPUARCH} =3D=3D "amd64" || \
     ${MACHINE_CPUARCH} =3D=3D "arm"
-SUBDIR+=3D	libefi loader boot1
+SUBDIR+=3D	libefi drivers loader boot1
 .endif
=20
 .endif # ${COMPILER_TYPE} !=3D "gcc" || ${COMPILER_VERSION} >=3D 40500
diff --git a/sys/boot/efi/boot1/Makefile b/sys/boot/efi/boot1/Makefile
index 110a857..7480c9c 100644
--- a/sys/boot/efi/boot1/Makefile
+++ b/sys/boot/efi/boot1/Makefile
@@ -8,34 +8,50 @@ MK_SSP=3D		no
=20
 PROG=3D		boot1.sym
 INTERNALPROG=3D
-WARNS?=3D		6
+WARNS?=3D		3
+
+# Include bcache code.
+HAVE_BCACHE=3D    yes
=20
 .if ${MK_ZFS} !=3D "no"
 # Disable warnings that are currently incompatible with the zfs boot cod=
e
-CWARNFLAGS.zfs_module.c +=3D -Wno-array-bounds
-CWARNFLAGS.zfs_module.c +=3D -Wno-cast-align
-CWARNFLAGS.zfs_module.c +=3D -Wno-cast-qual
-CWARNFLAGS.zfs_module.c +=3D -Wno-missing-prototypes
-CWARNFLAGS.zfs_module.c +=3D -Wno-sign-compare
-CWARNFLAGS.zfs_module.c +=3D -Wno-unused-parameter
-CWARNFLAGS.zfs_module.c +=3D -Wno-unused-function
+CWARNFLAGS.boot1.c +=3D -Wno-missing-variable-declarations
+CWARNFLAGS.zfs.c +=3D -Wno-incompatible-pointer-types-discards-qualifier=
s
+CWARNFLAGS.zfs.c +=3D -Wno-missing-variable-declarations
+CWARNFLAGS.zfs.c +=3D -Wno-array-bounds
+CWARNFLAGS.zfs.c +=3D -Wno-cast-align
+CWARNFLAGS.zfs.c +=3D -Wno-cast-qual
+CWARNFLAGS.zfs.c +=3D -Wno-missing-prototypes
+CWARNFLAGS.zfs.c +=3D -Wno-sign-compare
+CWARNFLAGS.zfs.c +=3D -Wno-unused-parameter
+CWARNFLAGS.zfs.c +=3D -Wno-unused-function
 CWARNFLAGS.skein.c +=3D -Wno-cast-align
 CWARNFLAGS.skein.c +=3D -Wno-missing-variable-declarations
 .endif
=20
+
 # architecture-specific loader code
-SRCS=3D	boot1.c self_reloc.c start.S ufs_module.c
+SRCS=3D	boot1.c self_reloc.c start.S
 .if ${MK_ZFS} !=3D "no"
-SRCS+=3D		zfs_module.c
+.PATH:		${.CURDIR}/../../../crypto/skein
 SRCS+=3D		skein.c skein_block.c
 # Do not unroll skein loops, reduce code size
 CFLAGS+=3D	-DSKEIN_LOOP=3D111
-.PATH:		${.CURDIR}/../../../crypto/skein
+.PATH:		${.CURDIR}/../../zfs
+SRCS+=3D		zfs.c
 .endif
=20
+# Always add MI sources
+.PATH:		${.CURDIR}/../../common
+.include	"${.CURDIR}/../../common/Makefile.inc"
+CFLAGS+=3D	-I${.CURDIR}/../../common
+
+.PATH: ${.CURDIR}/arch/${MACHINE}
+
 CFLAGS+=3D	-I.
 CFLAGS+=3D	-I${.CURDIR}/../include
 CFLAGS+=3D	-I${.CURDIR}/../include/${MACHINE}
+CFLAGS+=3D	-I${.CURDIR}/../drivers/
 CFLAGS+=3D	-I${.CURDIR}/../../../contrib/dev/acpica/include
 CFLAGS+=3D	-I${.CURDIR}/../../..
 CFLAGS+=3D	-DEFI_UFS_BOOT
@@ -56,6 +72,20 @@ CFLAGS+=3D	-DEFI_ZFS_BOOT
 .PATH:		${.CURDIR}/../../common
 CFLAGS+=3D	-I${.CURDIR}/../../common
=20
+# make buildenv doesn't set DESTDIR, this means LIBSTAND
+# will be wrong when crossbuilding.
+.if exists(${.OBJDIR}/../../../../lib/libstand/libstand.a)
+LIBSTAND=3D	${.OBJDIR}/../../../../lib/libstand/libstand.a
+.endif
+
+# Add libefi
+.PATH:		${.CURDIR}/../libefi
+LIBEFI=3D		${.OBJDIR}/../libefi/libefi.a
+
+.PATH:		${.CURDIR}/../drivers
+LIBEFI_DRIVERS=3D	${.OBJDIR}/../drivers/libefi_drivers.a
+
+
 FILES=3D	boot1.efi boot1.efifat
 FILESMODE_boot1.efi=3D	${BINMODE}
=20
@@ -75,8 +105,8 @@ LDFLAGS+=3D	-Wl,-znocombreloc
 # __aeabi_* (arm) or __divdi3 (i386).
 # as well as required string and memory functions for all platforms.
 #
-DPADD+=3D		${LIBSTAND}
-LDADD+=3D		-lstand
+DPADD+=3D		${LIBEFI_DRIVERS} ${LIBEFI} ${LIBSTAND}
+LDADD+=3D		${LIBEFI_DRIVERS} ${LIBEFI} ${LIBSTAND}
=20
 DPADD+=3D		${LDSCRIPT}
=20
@@ -102,7 +132,7 @@ boot1.efi: ${PROG}
 	SOURCE_DATE_EPOCH=3D${SOURCE_DATE_EPOCH} \
 	${OBJCOPY} -j .peheader -j .text -j .sdata -j .data \
 		-j .dynamic -j .dynsym -j .rel.dyn \
-		-j .rela.dyn -j .reloc -j .eh_frame \
+		-j .rela.dyn -j .reloc -j .eh_frame -j set_Xcommand_set \
 		--output-target=3D${EFI_TARGET} ${.ALLSRC} ${.TARGET}
=20
 boot1.o: ${.CURDIR}/../../common/ufsread.c
@@ -111,7 +141,7 @@ boot1.o: ${.CURDIR}/../../common/ufsread.c
 # created by generate-fat.sh
=20
 .include "${.CURDIR}/Makefile.fat"
-BOOT1_MAXSIZE?=3D	131072
+BOOT1_MAXSIZE?=3D	524288
=20
 boot1.efifat: boot1.efi
 	@set -- `ls -l boot1.efi`; \
diff --git a/sys/boot/efi/boot1/Makefile.fat b/sys/boot/efi/boot1/Makefil=
e.fat
index c86a7c3..e2cda1c 100644
--- a/sys/boot/efi/boot1/Makefile.fat
+++ b/sys/boot/efi/boot1/Makefile.fat
@@ -1,4 +1,4 @@
 # This file autogenerated by generate-fat.sh - DO NOT EDIT
 # $FreeBSD$
 BOOT1_OFFSET=3D0x2d
-BOOT1_MAXSIZE=3D131072
+BOOT1_MAXSIZE=3D524288
diff --git a/sys/boot/efi/boot1/boot1.c b/sys/boot/efi/boot1/boot1.c
index 80b1895..9e02bfa 100644
--- a/sys/boot/efi/boot1/boot1.c
+++ b/sys/boot/efi/boot1/boot1.c
@@ -26,62 +26,118 @@ __FBSDID("$FreeBSD$");
 #include <machine/elf.h>
 #include <machine/stdarg.h>
 #include <stand.h>
+#include <string16.h>
=20
 #include <efi.h>
+#include <efilib.h>
+#include <efiprot.h>
 #include <eficonsctl.h>
+#ifdef EFI_ZFS_BOOT
+#include <libzfs.h>
+#endif
+
+#include <bootstrap.h>
=20
-#include "boot_module.h"
+#include "efi_drivers.h"
 #include "paths.h"
=20
-static const boot_module_t *boot_modules[] =3D
-{
-#ifdef EFI_ZFS_BOOT
-	&zfs_module,
-#endif
-#ifdef EFI_UFS_BOOT
-	&ufs_module
+#ifdef EFI_DEBUG
+#define DPRINTF(fmt, args...) printf(fmt, ##args)
+#define DSTALL(d) bs->Stall(d)
+#else
+#define DPRINTF(fmt, ...) {}
+#define DSTALL(d) {}
 #endif
+
+struct arch_switch archsw;	/* MI/MD interface boundary */
+
+static const efi_driver_t *efi_drivers[] =3D {
+        &fs_driver,
+        NULL
 };
=20
-#define	NUM_BOOT_MODULES	nitems(boot_modules)
-/* The initial number of handles used to query EFI for partitions. */
-#define NUM_HANDLES_INIT	24
+extern struct console efi_console;
+#if defined(__amd64__) || defined(__i386__)
+extern struct console comconsole;
+extern struct console nullconsole;
+#endif
=20
-void putchar(int c);
-EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab);
+struct fs_ops *file_system[] =3D {
+	&dosfs_fsops,
+	&ufs_fsops,
+	&cd9660_fsops,
+	&nfs_fsops,
+	&gzipfs_fsops,
+	&bzipfs_fsops,
+	NULL
+};
=20
-EFI_SYSTEM_TABLE *systab;
-EFI_BOOT_SERVICES *bs;
-static EFI_HANDLE *image;
+struct devsw *devsw[] =3D {
+	&efipart_dev,
+#ifdef EFI_ZFS_BOOT
+	&zfs_dev,
+#endif
+	NULL
+};
=20
-static EFI_GUID BlockIoProtocolGUID =3D BLOCK_IO_PROTOCOL;
-static EFI_GUID DevicePathGUID =3D DEVICE_PATH_PROTOCOL;
-static EFI_GUID LoadedImageGUID =3D LOADED_IMAGE_PROTOCOL;
-static EFI_GUID ConsoleControlGUID =3D EFI_CONSOLE_CONTROL_PROTOCOL_GUID=
;
+struct console *consoles[] =3D {
+	&efi_console,
+	NULL
+};
=20
-/*
- * Provide Malloc / Free backed by EFIs AllocatePool / FreePool which en=
sures
- * memory is correctly aligned avoiding EFI_INVALID_PARAMETER returns fr=
om
- * EFI methods.
+/* Definitions we don't actually need for boot, but we need to define
+ * to make the linker happy.
  */
-void *
-Malloc(size_t len, const char *file __unused, int line __unused)
+struct file_format *file_formats[] =3D { NULL };
+
+struct netif_driver *netif_drivers[] =3D { NULL };
+
+static int
+efi_autoload(void)
 {
-	void *out;
+  printf("******** Boot block should not call autoload\n");
+  return (-1);
+}
=20
-	if (bs->AllocatePool(EfiLoaderData, len, &out) =3D=3D EFI_SUCCESS)
-		return (out);
+static int efi_getdev(void **vdev __unused, const char *devspec __unused=
,
+    const char **path __unused)
+{
+  printf("******** Boot block should not call getdev\n");
+  return (-1);
+}
=20
-	return (NULL);
+static ssize_t
+efi_copyin(const void *src __unused, vm_offset_t dest __unused,
+    const size_t len __unused)
+{
+  printf("******** Boot block should not call copyin\n");
+  return (-1);
 }
=20
-void
-Free(void *buf, const char *file __unused, int line __unused)
+static ssize_t
+efi_copyout(vm_offset_t src __unused, void *dest __unused,
+    const size_t len __unused)
 {
-	if (buf !=3D NULL)
-		(void)bs->FreePool(buf);
+  printf("******** Boot block should not call copyout\n");
+  return (-1);
+}
+
+static ssize_t
+efi_readin(int fd __unused, vm_offset_t dest __unused,
+    const size_t len __unused)
+{
+  printf("******** Boot block should not call readin\n");
+  return (-1);
 }
=20
+/* The initial number of handles used to query EFI for partitions. */
+#define NUM_HANDLES_INIT	24
+
+static EFI_GUID DevicePathGUID =3D DEVICE_PATH_PROTOCOL;
+static EFI_GUID LoadedImageGUID =3D LOADED_IMAGE_PROTOCOL;
+static EFI_GUID SimpleFileSystemProtocolGUID =3D SIMPLE_FILE_SYSTEM_PROT=
OCOL;
+static EFI_GUID FileInfoGUID =3D EFI_FILE_INFO_ID;;
+
 /*
  * nodes_match returns TRUE if the imgpath isn't NULL and the nodes matc=
h,
  * FALSE otherwise.
@@ -142,6 +198,7 @@ devpath_last(EFI_DEVICE_PATH *devpath)
 	return (devpath);
 }
=20
+#ifdef EFI_DEBUG
 /*
  * devpath_node_str is a basic output method for a devpath node which
  * only understands a subset of the available sub types.
@@ -273,7 +330,7 @@ devpath_node_str(char *buf, size_t size, EFI_DEVICE_P=
ATH *devpath)
  * devpath_strlcat appends a text description of devpath to buf but not =
more
  * than size - 1 characters followed by NUL-terminator.
  */
-int
+static int
 devpath_strlcat(char *buf, size_t size, EFI_DEVICE_PATH *devpath)
 {
 	size_t len, used;
@@ -304,48 +361,207 @@ devpath_strlcat(char *buf, size_t size, EFI_DEVICE=
_PATH *devpath)
  * devpath_str is convenience method which returns the text description =
of
  * devpath using a static buffer, so it isn't thread safe!
  */
-char *
+static char *
 devpath_str(EFI_DEVICE_PATH *devpath)
 {
 	static char buf[256];
=20
 	devpath_strlcat(buf, sizeof(buf), devpath);
=20
-	return buf;
+	return (buf);
+}
+#endif
+
+static EFI_STATUS
+efi_load(EFI_HANDLE dev, const char *filepath, void **bufp, size_t *bufs=
ize)
+{
+        UINTN infosize =3D sizeof(EFI_FILE_INFO) +
+          ((strlen(filepath) + 1) * sizeof(CHAR16));
+        EFI_FILE_INFO *finfo;
+	EFI_STATUS status;
+        EFI_FILE_IO_INTERFACE *iface;
+        EFI_FILE_HANDLE root;
+        EFI_FILE_HANDLE target;
+        CHAR16 path16[strlen(filepath) + 1];
+	void *buf;
+
+        finfo =3D malloc(infosize);
+
+        if (finfo =3D=3D NULL) {
+                return (EFI_OUT_OF_RESOURCES);
+        }
+
+	status =3D BS->OpenProtocol(dev, &SimpleFileSystemProtocolGUID,
+            (void **)&iface, IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+
+        if (status !=3D EFI_SUCCESS) {
+                free(finfo);
+                printf("Open protocol failed! %ld\n", EFI_ERROR_CODE(sta=
tus));
+                return (status);
+        }
+
+        status =3D iface->OpenVolume(iface, &root);
+
+        if (status !=3D EFI_SUCCESS) {
+                BS->CloseProtocol(dev, &SimpleFileSystemProtocolGUID, IH=
, NULL);
+                free(finfo);
+                printf("Open volume failed! %ld\n", EFI_ERROR_CODE(statu=
s));
+                return (status);
+        }
+
+        strcpy_to_16(path16, filepath);
+        status =3D root->Open(root, &target, path16, EFI_FILE_MODE_READ,=
 0);
+
+        if (status !=3D EFI_SUCCESS) {
+                BS->CloseProtocol(dev, &SimpleFileSystemProtocolGUID, IH=
, NULL);
+                free(finfo);
+
+                return (status);
+        }
+
+        *bufsize =3D infosize;
+        status =3D target->GetInfo(target, &FileInfoGUID, bufsize, finfo=
);
+
+        if (status !=3D EFI_SUCCESS) {
+                BS->CloseProtocol(dev, &SimpleFileSystemProtocolGUID, IH=
, NULL);
+                free(finfo);
+                printf("Get info failed! %ld\n", EFI_ERROR_CODE(status))=
;
+                return (status);
+        }
+
+        *bufsize =3D finfo->FileSize;
+
+        if ((buf =3D malloc(finfo->FileSize)) =3D=3D NULL) {
+                BS->CloseProtocol(dev, &SimpleFileSystemProtocolGUID, IH=
, NULL);
+                free(finfo);
+                printf("Failed to allocate load buffer %zd for '%s' "
+                       "(%lu)\n", finfo->FileSize, filepath, EFI_ERROR_C=
ODE(status));
+                return (EFI_OUT_OF_RESOURCES);
+        }
+
+        *bufp =3D buf;
+        status =3D target->Read(target, bufsize, buf);
+        BS->CloseProtocol(dev, &SimpleFileSystemProtocolGUID, IH, NULL);=

+        free(finfo);
+
+        if (status !=3D EFI_SUCCESS) {
+                printf("Read failed! %ld\n", EFI_ERROR_CODE(status));
+                return (status);
+        }
+
+        return (EFI_SUCCESS);
 }
=20
 /*
  * load_loader attempts to load the loader image data.
  *
- * It tries each module and its respective devices, identified by mod->p=
robe,
- * in order until a successful load occurs at which point it returns EFI=
_SUCCESS
- * and EFI_NOT_FOUND otherwise.
+ * This tries all handles which support the EFI_SIMPLE_FILE_SYSTEM inter=
face.
+ * It is expected that the drivers will have installed this interface on=
 every
+ * handle representing a device containing a supported file system.
+ *
+ * Note: In the future, this may be altered to use the EFI_LOAD_FILE int=
erface,
+ * which should work transparently with network booting.
  *
  * Only devices which have preferred matching the preferred parameter ar=
e tried.
  */
 static EFI_STATUS
-load_loader(const boot_module_t **modp, dev_info_t **devinfop, void **bu=
fp,
-    size_t *bufsize, BOOLEAN preferred)
+load_loader(EFI_HANDLE *handlep, void **bufp, size_t *bufsize)
 {
-	UINTN i;
-	dev_info_t *dev;
-	const boot_module_t *mod;
-
-	for (i =3D 0; i < NUM_BOOT_MODULES; i++) {
-		mod =3D boot_modules[i];
-		for (dev =3D mod->devices(); dev !=3D NULL; dev =3D dev->next) {
-			if (dev->preferred !=3D preferred)
-				continue;
-
-			if (mod->load(PATH_LOADER_EFI, dev, bufp, bufsize) =3D=3D
-			    EFI_SUCCESS) {
-				*devinfop =3D dev;
-				*modp =3D mod;
-				return (EFI_SUCCESS);
-			}
+	EFI_DEVICE_PATH *imgpath;
+	EFI_DEVICE_PATH *devpath;
+	EFI_LOADED_IMAGE *boot_image;
+        EFI_HANDLE *boot_handle;
+	EFI_HANDLE *preferred;
+	EFI_HANDLE *handles;
+        EFI_STATUS status;
+	UINTN i, hsize, nhandles, npreferred;
+
+	if ((status =3D BS->OpenProtocol(IH, &LoadedImageGUID,
+            (VOID**)&boot_image, IH, NULL,
+            EFI_OPEN_PROTOCOL_GET_PROTOCOL)) !=3D EFI_SUCCESS) {
+		panic("Failed to query LoadedImage (%lu)\n",
+		    EFI_ERROR_CODE(status));
+	}
+
+        boot_handle =3D boot_image->DeviceHandle;
+
+	if ((status =3D BS->OpenProtocol(boot_handle, &DevicePathGUID,
+            (void **)&imgpath, IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL)=
)) {
+                panic("Failed to get image DevicePath (%lu)\n",
+                    EFI_ERROR_CODE(status));
+        }
+        DPRINTF("boot1 imagepath: %s\n", devpath_str(imgpath));
+
+        /* Allocate space for the handles */
+	hsize =3D (UINTN)NUM_HANDLES_INIT * sizeof(EFI_HANDLE);
+	if ((handles =3D malloc(hsize)) =3D=3D NULL)
+		panic("Failed to allocate %d handles (%lu)", NUM_HANDLES_INIT,
+		    EFI_ERROR_CODE(status));
+
+	status =3D BS->LocateHandle(ByProtocol, &SimpleFileSystemProtocolGUID, =
NULL,
+	    &hsize, handles);
+
+	switch (status) {
+	case EFI_SUCCESS:
+		break;
+	case EFI_BUFFER_TOO_SMALL:
+		(void)BS->FreePool(handles);
+		if ((handles =3D malloc(hsize)) =3D=3D NULL) {
+			panic("Failed to allocate %zu handles (%lu)", hsize /
+			    sizeof(*handles), EFI_ERROR_CODE(status));
 		}
+		status =3D BS->LocateHandle(ByProtocol,
+                    &SimpleFileSystemProtocolGUID, NULL, &hsize, handles=
);
+		if (status !=3D EFI_SUCCESS)
+			panic("Failed to get device handles (%lu)\n",
+			    EFI_ERROR_CODE(status));
+		break;
+	default:
+		panic("Failed to get device handles (%lu)",
+		    EFI_ERROR_CODE(status));
 	}
=20
+	if ((preferred =3D malloc(hsize)) =3D=3D NULL)
+		panic("Failed to allocate %d handles (%lu)", NUM_HANDLES_INIT,
+		    EFI_ERROR_CODE(status));
+
+        npreferred =3D 0;
+	nhandles =3D hsize / sizeof(*handles);
+
+        /* Figure out which handles are preferred */
+        for (i =3D 0; i < nhandles; i++) {
+                if (BS->OpenProtocol(handles[i], &DevicePathGUID,
+                    (void **)&devpath, IH, NULL, EFI_OPEN_PROTOCOL_GET_P=
ROTOCOL) =3D=3D
+                    EFI_SUCCESS) {
+                        if (device_paths_match(imgpath, devpath)) {
+                                preferred[npreferred] =3D handles[i];
+                                npreferred++;
+                        }
+                        BS->CloseProtocol(handles[i], &DevicePathGUID, I=
H, NULL);
+                }
+        }
+
+        BS->CloseProtocol(boot_handle, &DevicePathGUID, IH, NULL);
+
+        /* Try the preferred handles first, then all the handles */
+        for (i =3D 0; i < npreferred; i++) {
+                if (efi_load(preferred[i], PATH_LOADER_EFI, bufp, bufsiz=
e) =3D=3D
+                   EFI_SUCCESS) {
+                        *handlep =3D preferred[i];
+                        return (EFI_SUCCESS);
+                }
+        }
+
+        for (i =3D 0; i < nhandles; i++) {
+                if (efi_load(handles[i], PATH_LOADER_EFI, bufp, bufsize)=
 =3D=3D
+                   EFI_SUCCESS) {
+                        *handlep =3D handles[i];
+                        return (EFI_SUCCESS);
+                }
+        }
+
+        printf("Failed to load %s from any device!\n", PATH_LOADER_EFI);=

+
 	return (EFI_NOT_FOUND);
 }
=20
@@ -359,20 +575,27 @@ try_boot(void)
 	size_t bufsize, loadersize, cmdsize;
 	void *buf, *loaderbuf;
 	char *cmd;
-	dev_info_t *dev;
-	const boot_module_t *mod;
+        EFI_HANDLE fshandle;
 	EFI_HANDLE loaderhandle;
 	EFI_LOADED_IMAGE *loaded_image;
 	EFI_STATUS status;
+        EFI_DEVICE_PATH *fspath;
+
+	status =3D load_loader(&fshandle, &loaderbuf, &loadersize);
=20
-	status =3D load_loader(&mod, &dev, &loaderbuf, &loadersize, TRUE);
-	if (status !=3D EFI_SUCCESS) {
-		status =3D load_loader(&mod, &dev, &loaderbuf, &loadersize,
-		    FALSE);
+        if (status !=3D EFI_SUCCESS) {
+                return (status);
+        }
+
+	fspath =3D NULL;
+	if (status =3D=3D EFI_SUCCESS) {
+		status =3D BS->OpenProtocol(fshandle, &DevicePathGUID,
+                    (void **)&fspath, IH, NULL, EFI_OPEN_PROTOCOL_GET_PR=
OTOCOL);
 		if (status !=3D EFI_SUCCESS) {
-			printf("Failed to load '%s'\n", PATH_LOADER_EFI);
-			return (status);
-		}
+			DPRINTF("Failed to get image DevicePath (%lu)\n",
+			    EFI_ERROR_CODE(status));
+                }
+		DPRINTF("filesystem device path: %s\n", devpath_str(fspath));
 	}
=20
 	/*
@@ -387,9 +610,9 @@ try_boot(void)
 	 */
 	cmd =3D NULL;
 	cmdsize =3D 0;
-	status =3D mod->load(PATH_DOTCONFIG, dev, &buf, &bufsize);
+	status =3D efi_load(fshandle, PATH_DOTCONFIG, &buf, &bufsize);
 	if (status =3D=3D EFI_NOT_FOUND)
-		status =3D mod->load(PATH_CONFIG, dev, &buf, &bufsize);
+		status =3D efi_load(fshandle, PATH_CONFIG, &buf, &bufsize);
 	if (status =3D=3D EFI_SUCCESS) {
 		cmdsize =3D bufsize + 1;
 		cmd =3D malloc(cmdsize);
@@ -401,24 +624,25 @@ try_boot(void)
 		buf =3D NULL;
 	}
=20
-	if ((status =3D bs->LoadImage(TRUE, image, devpath_last(dev->devpath),
+	if ((status =3D BS->LoadImage(TRUE, IH, devpath_last(fspath),
 	    loaderbuf, loadersize, &loaderhandle)) !=3D EFI_SUCCESS) {
-		printf("Failed to load image provided by %s, size: %zu, (%lu)\n",
-		     mod->name, loadersize, EFI_ERROR_CODE(status));
+		printf("Failed to load image, size: %zu, (%lu)\n",
+		     loadersize, EFI_ERROR_CODE(status));
 		goto errout;
 	}
=20
-	if ((status =3D bs->HandleProtocol(loaderhandle, &LoadedImageGUID,
-	    (VOID**)&loaded_image)) !=3D EFI_SUCCESS) {
-		printf("Failed to query LoadedImage provided by %s (%lu)\n",
-		    mod->name, EFI_ERROR_CODE(status));
+	if ((status =3D BS->OpenProtocol(loaderhandle, &LoadedImageGUID,
+            (VOID**)&loaded_image, IH, NULL,
+            EFI_OPEN_PROTOCOL_GET_PROTOCOL)) !=3D EFI_SUCCESS) {
+		printf("Failed to query LoadedImage (%lu)\n",
+		    EFI_ERROR_CODE(status));
 		goto errout;
 	}
=20
 	if (cmd !=3D NULL)
 		printf("    command args: %s\n", cmd);
=20
-	loaded_image->DeviceHandle =3D dev->devhandle;
+	loaded_image->DeviceHandle =3D fshandle;
 	loaded_image->LoadOptionsSize =3D cmdsize;
 	loaded_image->LoadOptions =3D cmd;
=20
@@ -434,10 +658,10 @@ try_boot(void)
 	DSTALL(1000000);
 	DPRINTF(".\n");
=20
-	if ((status =3D bs->StartImage(loaderhandle, NULL, NULL)) !=3D
+	if ((status =3D BS->StartImage(loaderhandle, NULL, NULL)) !=3D
 	    EFI_SUCCESS) {
-		printf("Failed to start image provided by %s (%lu)\n",
-		    mod->name, EFI_ERROR_CODE(status));
+		printf("Failed to start image (%lu)\n",
+		    EFI_ERROR_CODE(status));
 		loaded_image->LoadOptionsSize =3D 0;
 		loaded_image->LoadOptions =3D NULL;
 	}
@@ -453,134 +677,19 @@ errout:
 	return (status);
 }
=20
-/*
- * probe_handle determines if the passed handle represents a logical par=
tition
- * if it does it uses each module in order to probe it and if successful=
 it
- * returns EFI_SUCCESS.
- */
-static EFI_STATUS
-probe_handle(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath, BOOLEAN *preferred)=

-{
-	dev_info_t *devinfo;
-	EFI_BLOCK_IO *blkio;
-	EFI_DEVICE_PATH *devpath;
-	EFI_STATUS status;
-	UINTN i;
-
-	/* Figure out if we're dealing with an actual partition. */
-	status =3D bs->HandleProtocol(h, &DevicePathGUID, (void **)&devpath);
-	if (status =3D=3D EFI_UNSUPPORTED)
-		return (status);
-
-	if (status !=3D EFI_SUCCESS) {
-		DPRINTF("\nFailed to query DevicePath (%lu)\n",
-		    EFI_ERROR_CODE(status));
-		return (status);
-	}
-
-	DPRINTF("probing: %s\n", devpath_str(devpath));
-
-	status =3D bs->HandleProtocol(h, &BlockIoProtocolGUID, (void **)&blkio)=
;
-	if (status =3D=3D EFI_UNSUPPORTED)
-		return (status);
-
-	if (status !=3D EFI_SUCCESS) {
-		DPRINTF("\nFailed to query BlockIoProtocol (%lu)\n",
-		    EFI_ERROR_CODE(status));
-		return (status);
-	}
-
-	if (!blkio->Media->LogicalPartition)
-		return (EFI_UNSUPPORTED);
-
-	*preferred =3D device_paths_match(imgpath, devpath);
-
-	/* Run through each module, see if it can load this partition */
-	for (i =3D 0; i < NUM_BOOT_MODULES; i++) {
-		if ((status =3D bs->AllocatePool(EfiLoaderData,
-		    sizeof(*devinfo), (void **)&devinfo)) !=3D
-		    EFI_SUCCESS) {
-			DPRINTF("\nFailed to allocate devinfo (%lu)\n",
-			    EFI_ERROR_CODE(status));
-			continue;
-		}
-		devinfo->dev =3D blkio;
-		devinfo->devpath =3D devpath;
-		devinfo->devhandle =3D h;
-		devinfo->devdata =3D NULL;
-		devinfo->preferred =3D *preferred;
-		devinfo->next =3D NULL;
-
-		status =3D boot_modules[i]->probe(devinfo);
-		if (status =3D=3D EFI_SUCCESS)
-			return (EFI_SUCCESS);
-		(void)bs->FreePool(devinfo);
-	}
-
-	return (EFI_UNSUPPORTED);
-}
-
-/*
- * probe_handle_status calls probe_handle and outputs the returned statu=
s
- * of the call.
- */
-static void
-probe_handle_status(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath)
-{
-	EFI_STATUS status;
-	BOOLEAN preferred;
-
-	status =3D probe_handle(h, imgpath, &preferred);
-=09
-	DPRINTF("probe: ");
-	switch (status) {
-	case EFI_UNSUPPORTED:
-		printf(".");
-		DPRINTF(" not supported\n");
-		break;
-	case EFI_SUCCESS:
-		if (preferred) {
-			printf("%c", '*');
-			DPRINTF(" supported (preferred)\n");
-		} else {
-			printf("%c", '+');
-			DPRINTF(" supported\n");
-		}
-		break;
-	default:
-		printf("x");
-		DPRINTF(" error (%lu)\n", EFI_ERROR_CODE(status));
-		break;
-	}
-	DSTALL(500000);
-}
-
 EFI_STATUS
-efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab)
+main(int argc __unused, CHAR16 *argv[] __unused)
 {
-	EFI_HANDLE *handles;
-	EFI_LOADED_IMAGE *img;
-	EFI_DEVICE_PATH *imgpath;
 	EFI_STATUS status;
-	EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl =3D NULL;
 	SIMPLE_TEXT_OUTPUT_INTERFACE *conout =3D NULL;
-	UINTN i, max_dim, best_mode, cols, rows, hsize, nhandles;
-
-	/* Basic initialization*/
-	systab =3D Xsystab;
-	image =3D Ximage;
-	bs =3D Xsystab->BootServices;
-
-	/* Set up the console, so printf works. */
-	status =3D bs->LocateProtocol(&ConsoleControlGUID, NULL,
-	    (VOID **)&ConsoleControl);
-	if (status =3D=3D EFI_SUCCESS)
-		(void)ConsoleControl->SetMode(ConsoleControl,
-		    EfiConsoleControlScreenText);
+	UINTN i, max_dim, best_mode, cols, rows;
+
+	cons_probe();
+
 	/*
 	 * Reset the console and find the best text mode.
 	 */
-	conout =3D systab->ConOut;
+	conout =3D ST->ConOut;
 	conout->Reset(conout, TRUE);
 	max_dim =3D best_mode =3D 0;
 	for (i =3D 0; ; i++) {
@@ -597,123 +706,31 @@ efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsys=
tab)
 	conout->EnableCursor(conout, TRUE);
 	conout->ClearScreen(conout);
=20
-	printf("\n>> FreeBSD EFI boot block\n");
-	printf("   Loader path: %s\n\n", PATH_LOADER_EFI);
-	printf("   Initializing modules:");
-	for (i =3D 0; i < NUM_BOOT_MODULES; i++) {
-		printf(" %s", boot_modules[i]->name);
-		if (boot_modules[i]->init !=3D NULL)
-			boot_modules[i]->init();
-	}
-	putchar('\n');
-
-	/* Get all the device handles */
-	hsize =3D (UINTN)NUM_HANDLES_INIT * sizeof(EFI_HANDLE);
-	if ((status =3D bs->AllocatePool(EfiLoaderData, hsize, (void **)&handle=
s))
-	    !=3D EFI_SUCCESS)
-		panic("Failed to allocate %d handles (%lu)", NUM_HANDLES_INIT,
-		    EFI_ERROR_CODE(status));
-
-	status =3D bs->LocateHandle(ByProtocol, &BlockIoProtocolGUID, NULL,
-	    &hsize, handles);
-	switch (status) {
-	case EFI_SUCCESS:
-		break;
-	case EFI_BUFFER_TOO_SMALL:
-		(void)bs->FreePool(handles);
-		if ((status =3D bs->AllocatePool(EfiLoaderData, hsize,
-		    (void **)&handles)) !=3D EFI_SUCCESS) {
-			panic("Failed to allocate %zu handles (%lu)", hsize /
-			    sizeof(*handles), EFI_ERROR_CODE(status));
-		}
-		status =3D bs->LocateHandle(ByProtocol, &BlockIoProtocolGUID,
-		    NULL, &hsize, handles);
-		if (status !=3D EFI_SUCCESS)
-			panic("Failed to get device handles (%lu)\n",
-			    EFI_ERROR_CODE(status));
-		break;
-	default:
-		panic("Failed to get device handles (%lu)",
-		    EFI_ERROR_CODE(status));
-	}
+	/*
+	 * Initialise the block cache. Set the upper limit.
+	 */
+	bcache_init(32768, 512);
=20
-	/* Scan all partitions, probing with all modules. */
-	nhandles =3D hsize / sizeof(*handles);
-	printf("   Probing %zu block devices...", nhandles);
-	DPRINTF("\n");
+	printf("\n>> FreeBSD EFI boot block\n");
=20
-	/* Determine the devpath of our image so we can prefer it. */
-	status =3D bs->HandleProtocol(image, &LoadedImageGUID, (VOID**)&img);
-	imgpath =3D NULL;
-	if (status =3D=3D EFI_SUCCESS) {
-		status =3D bs->HandleProtocol(img->DeviceHandle, &DevicePathGUID,
-		    (void **)&imgpath);
-		if (status !=3D EFI_SUCCESS)
-			DPRINTF("Failed to get image DevicePath (%lu)\n",
-			    EFI_ERROR_CODE(status));
-		DPRINTF("boot1 imagepath: %s\n", devpath_str(imgpath));
-	}
+	archsw.arch_autoload =3D efi_autoload;
+	archsw.arch_getdev =3D efi_getdev;
+	archsw.arch_copyin =3D efi_copyin;
+	archsw.arch_copyout =3D efi_copyout;
+	archsw.arch_readin =3D efi_readin;
=20
-	for (i =3D 0; i < nhandles; i++)
-		probe_handle_status(handles[i], imgpath);
-	printf(" done\n");
+	printf("   Loader path: %s\n\n", PATH_LOADER_EFI);
+	printf("   Initializing modules:");
=20
-	/* Status summary. */
-	for (i =3D 0; i < NUM_BOOT_MODULES; i++) {
-		printf("    ");
-		boot_modules[i]->status();
+	for (i =3D 0; efi_drivers[i] !=3D NULL; i++) {
+		printf(" %s", efi_drivers[i]->name);
+		if (efi_drivers[i]->init !=3D NULL)
+			efi_drivers[i]->init();
 	}
+	putchar('\n');
=20
 	try_boot();
=20
 	/* If we get here, we're out of luck... */
 	panic("No bootable partitions found!");
 }
-
-/*
- * add_device adds a device to the passed devinfo list.
- */
-void
-add_device(dev_info_t **devinfop, dev_info_t *devinfo)
-{
-	dev_info_t *dev;
-
-	if (*devinfop =3D=3D NULL) {
-		*devinfop =3D devinfo;
-		return;
-	}
-
-	for (dev =3D *devinfop; dev->next !=3D NULL; dev =3D dev->next)
-		;
-
-	dev->next =3D devinfo;
-}
-
-void
-panic(const char *fmt, ...)
-{
-	va_list ap;
-
-	printf("panic: ");
-	va_start(ap, fmt);
-	vprintf(fmt, ap);
-	va_end(ap);
-	printf("\n");
-
-	while (1) {}
-}
-
-void
-putchar(int c)
-{
-	CHAR16 buf[2];
-
-	if (c =3D=3D '\n') {
-		buf[0] =3D '\r';
-		buf[1] =3D 0;
-		systab->ConOut->OutputString(systab->ConOut, buf);
-	}
-	buf[0] =3D c;
-	buf[1] =3D 0;
-	systab->ConOut->OutputString(systab->ConOut, buf);
-}
diff --git a/sys/boot/efi/boot1/boot_module.h b/sys/boot/efi/boot1/boot_m=
odule.h
deleted file mode 100644
index 296d5a6..0000000
--- a/sys/boot/efi/boot1/boot_module.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/*-
- * Copyright (c) 2015 Eric McCorkle
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in th=
e
- *    documentation and/or other materials provided with the distributio=
n.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AN=
D
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE=

- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PU=
RPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIAB=
LE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUE=
NTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOO=
DS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)=

- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, S=
TRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY=
 WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY O=
F
- * SUCH DAMAGE.
- *
- * $FreeBSD$
- */
-
-#ifndef _BOOT_MODULE_H_
-#define _BOOT_MODULE_H_
-
-#include <stdbool.h>
-
-#include <efi.h>
-#include <efilib.h>
-#include <eficonsctl.h>
-
-#ifdef EFI_DEBUG
-#define DPRINTF(fmt, args...) printf(fmt, ##args)
-#define DSTALL(d) bs->Stall(d)
-#else
-#define DPRINTF(fmt, ...) {}
-#define DSTALL(d) {}
-#endif
-
-/* EFI device info */
-typedef struct dev_info
-{
-	EFI_BLOCK_IO *dev;
-	EFI_DEVICE_PATH *devpath;
-	EFI_HANDLE *devhandle;
-	void *devdata;
-	BOOLEAN preferred;
-	struct dev_info *next;
-} dev_info_t;
-
-/*
- * A boot loader module.
- *
- * This is a standard interface for filesystem modules in the EFI system=
=2E
- */
-typedef struct boot_module_t
-{
-	const char *name;
-
-	/* init is the optional initialiser for the module. */
-	void (*init)();
-
-	/*
-	 * probe checks to see if the module can handle dev.
-	 *
-	 * Return codes:
-	 * EFI_SUCCESS =3D The module can handle the device.
-	 * EFI_NOT_FOUND =3D The module can not handle the device.
-	 * Other =3D The module encountered an error.
-	 */
-	EFI_STATUS (*probe)(dev_info_t* dev);
-
-	/*
-	 * load should select the best out of a set of devices that probe
-	 * indicated were loadable and load the specified file.
-	 *
-	 * Return codes:
-	 * EFI_SUCCESS =3D The module can handle the device.
-	 * EFI_NOT_FOUND =3D The module can not handle the device.
-	 * Other =3D The module encountered an error.
-	 */
-	EFI_STATUS (*load)(const char *filepath, dev_info_t *devinfo,
-	    void **buf, size_t *bufsize);
-
-	/* status outputs information about the probed devices. */
-	void (*status)();
-
-	/* valid devices as found by probe. */
-	dev_info_t *(*devices)();
-} boot_module_t;
-
-/* Standard boot modules. */
-#ifdef EFI_UFS_BOOT
-extern const boot_module_t ufs_module;
-#endif
-#ifdef EFI_ZFS_BOOT
-extern const boot_module_t zfs_module;
-#endif
-
-/* Functions available to modules. */
-extern void add_device(dev_info_t **devinfop, dev_info_t *devinfo);
-extern void panic(const char *fmt, ...) __dead2;
-extern int printf(const char *fmt, ...);
-extern int vsnprintf(char *str, size_t sz, const char *fmt, va_list ap);=

-
-extern EFI_SYSTEM_TABLE *systab;
-extern EFI_BOOT_SERVICES *bs;
-
-extern int devpath_strlcat(char *buf, size_t size, EFI_DEVICE_PATH *devp=
ath);
-extern char *devpath_str(EFI_DEVICE_PATH *devpath);
-#endif
diff --git a/sys/boot/efi/boot1/fat-amd64.tmpl.bz2.uu b/sys/boot/efi/boot=
1/fat-amd64.tmpl.bz2.uu
index a3ec32d..c7308a4 100644
--- a/sys/boot/efi/boot1/fat-amd64.tmpl.bz2.uu
+++ b/sys/boot/efi/boot1/fat-amd64.tmpl.bz2.uu
@@ -2,25 +2,50 @@ FAT template boot filesystem created by generate-fat.sh=

 DO NOT EDIT
 $FreeBSD$
 begin 644 fat-amd64.tmpl.bz2
-M0EIH.3%!62936?$)3$,`&U9_____Z^KJZ_^N_^O^Z_^[ON_NK^JJ^KZNKNNJ
-MZNKNZOJ^P`+\#$!0$#1D-,@#)DT#1B&AIDQ,AD:#1HTR`-#)D80Q!D:,)D``
-M#1@F30```&@`$JJ9!_HU4:",3!,F0&C(83`F30T`T!B&!,F`(P3`"#0,@`/2
-M::`#0!D`,C1`T9#3(`R9-`T8AH:9,3(9&@T:-,@#0R9&$,09&C"9```T8)DT
-M```!H``JBD@_2B:FF9)IHQ/1#:@-`:`R#(T`&@:-`!H8FAH:::'J::-`9&1Z
-MFF!'HAB8U/1/*8---3EV+*<ZL\S9BXEC[6I",BE$0BDA$1$%G66TH6PF$0(0
-MXDA!"&<HJ,=3D-W=3DK>PZ5:L^\19>>T2K3OA>TUS8M>VJ_;9P7"8;&7&8R51N>F
-M1E%A#6+F9*H@$(9J<K2V7=3DDH[YSK)LDN618]0S$3"M6JK5JU:M9J*5)44444
-M45JU%:5::U:M6K<:T42HHHHHHYI:J)44444,+B;R5>%%%%%%%$>!!!!!!!!!
-M!!!!!!!#76C@<C1HT:-&C1!!!!!!!!!TX&#!@P8,&#J8Y*BBBBBBBB'@<#!@
-MP8,&#"$4*******.?ZO)U59NW9Y_5RB9=3DSGK%AO91D/,RW:JUEWJ7CICT$M,
-M]]>OM;-N%^W[!<=3DH[<-1<QY)W<`%BRT<D`+3375[\FOS\YBD0`RSL8,UV51>
-MRR"SVLL>LG*Z1G+K%N;);>IIYL-7L*D<B5U+2/2:5J6K7K+ON7S<-ZW[`8;$
-M9ESS6Y>[Q-SH;5D;RU_+ZK.+TEMX%K(QQ813V:GS1ZT;"R\!H$K/Z:=3D%386M
-MPJL.<K?C*J6@DI)\#6KU=3D,@V3:-JW3>.`X;BN0SS2,I;U*I;;.]O5ZMI9CMV
-MY(;8*\CXX-SPW(^Z5WIWPW0V@?7DLGZ@QJQHC6!J-\U[>@T$2F)3"7UM2V+:
-M+YMFW;MO6^<-@L)R7+<WLVJEO,&HNI+>XU0JB(L,KI:F[OD%ZUC=3D-0WB\7C?
-M."P'%83CL1BM$RLHD):&7,DOSLY1=3D2Y,H_EOG`<%YS0,!Q&$XS]')8CXEXP_
-MFX2-7*,#%P;!Q]V)E#BO"83#?\V3C..Y#E,1?L5S&,NC%DQI>;+`DS>NQL5?
-?+6IF915V$0"$)@`M+"Q)@(_9+!?^+N2*<*$AXA*8A@``
+M0EIH.3%!629363$"%&\`'YA______________^O^Z_^[_N[^J^NK^KZOKONJ
+MZNK^ZN[^X`C_%-``HH`%41"1(*)`BJ!H:```?M5```#0````````-`:-#0``
+M`````````````555$_2@!O_U2J/_TJA_JJ>4!H````T``````&@`````:```
+M!H``>H`&@!HR`0,F3(!DR``TP0T`:``#0Q#30#(``-`-`R&@&@!D!H&FC$&C
+M0``&@`#0@9,F0#)D`!I@AH`T``&AB&F@&0``:`:!D-`-`#(#0--&(-&@``-`
+M`&A`R9,@&3(`#3!#0!H``-#$--`,@``T`T#(:`:`&0&@::,0:-```:``-`55
+M(_23]"13-3TIZJ?[*D:$_]5-3TVBFU-J;1&3)A'H0\F2/4Q&GJ!ZF`3U#U'E
+M/031B8U#$9'J!ZAM(\*#R#0,4S4_5,U/0VJ>$\B*9O7.9HQ&K@F!RV88885S
+M,&#####&POFPP!@<W-@R&;#`PPP'JJLYET/0LJ/Q4O7O:*/<NO9^T?#=3DJ^2_
+MP?TNZ?0=3DX\)X;Q7EM7G/.YW1L-K_B,,,,,,,`%@W4$\J!`.@(!`*@0"!#`("
+M`@("`@("`@("`@("Z!^`\PXGK&QR'F\,S<S-S<EN;E6Y.YN;FYN;FYN;FYN;
+MFYN;G`Y'/<B'(Y%'(Y'(Y'(Y'(Y%UUUUUUUUUUV.LQU,=3DFL9CLJQF5LU%@RS
+M4\;0JS*JJJJJN@:E6IF79EUUUUUW\7J[?\YL+KKKKKKI:56E&&=3D999999*4I
+M2E*4K*K.F[3,Q49,F3)DR2E*4I2E+)5DUT0NNNNNNX/2=3DK=3D=3D=3D=3D=3D=3D=3D=3D=
+4JU.\
+MHA=3D=3D=3D=3D=3D=3DQJLEF2&=3D=3D=3D=3D=3D=3D=3DS/09M>?ILGJGM'9/CNX=3D\=
\1]7S2JJJJJJJ7IE7
+M7(9UEEEEEDI2E*4I2LJLAG6666662E*4I2E*RJR&=3D999999?K++++++++)9*
+MLD,ZRRRRRS*JJJJJJJJ5U5W@=3D3BHR9,F3)DY555555554M*K2AG6666662E*
+M4I2E*RJR&=3D999999*RJR&=3D999999M]ST6EDR8Z75L[4S8=3DBSC1D=3DPZ]J#RWA
+M*>XSS+OI9+,OP:!G,`[#(RG-'!93*8`$4]KF#`!H][S_R?Y_E]3FG`P`><?@
+MNJ;UF]O;V]O;V]O;V]O;V]O;V]O;V]SSV3B>;;6UBVMK0VMK:VMK:VMK:VMK
+M:VMK:VMK:Z^ZZZZZZZZZZZZZZZZZZZZZZZ[+MSB;FU1#B<MPN4TLDI2E*4I2
+MNJNAG6666663A*4I2E*5E5GGZ(777777=3D955555555+)5DAG6666662E*4I2
+ME*RJR&=3D999999\BJJJJJJJJ5U5W1.57,Z%+0TM+2EI:4M*K2AG6666662[!V
+MCX[MW>/J/_7C^C55555552ZG]E9V3I_)YDL6IJ:FIJ:DI2E*4I2TJM+G^S^#
+MFT,6EI:6EI:4I2E*4I2TJM+^;^[%1DR9,F3)*4I2E*4LE62&=3D999999*4I2E
+M*4K*K(9UEEEEEDI2E*4I2LJL^[1"ZZZZZZ4I2E*4I7570SK+++++/R*KK+H9
+MUUUUUUUE55G3M,9UIK<&G/7:>^5EGWHT*,&#!$1$1$<#@<#@=3D(_=3D<MT;HN@=3D
+MMQN-QN-QN-QN-QN-QN-QN-QLPS6P_W[?"V6666666666666669#(9#(9;=3D=3D2
+M\CT]5554?T&9111]'`7S#H#0T-#0A"$(0A#+][%BQ8NGP]UA\R?SW:OXWQ6M
+M11117Y?*YF7S+[&>',TM+2TO\J***,:***(0A"$(0O1C,9C,3$Q,3,,'G/3>
+MP]YDOJ9]^;^6Z(B(B(B(B(B(Y=3DWCP6;9%EEEEEEEEEEEEEEEFEQ$1$:0B(B(
+MB(LLLXG%111WF+U'JX['EU555=3DUW6+%BQ<_U&K0T-#0M1111^K^EBQ8L7*Z'
+MJNBLU,.M?M.S=3DNIP]AGY<I2EV>SL.W_;U+ZLF3)DA"$.D]GIK*4I0A"'*HHH
+MHA"$(0A#_-W+NW>N^>`^L^RYKQ7CORG#PN%PN%PL&#!@P8,&#!@P>,\UY3/*
+M4I2E*4I2E*4I2(B(B(B(B(B*4IL=3D_XF+%BQ0A"$(0A"$(0A"'F>UQ8L6+O>X
+M=3DL_D=3DVA"$(0A#]BBBBB$(0A"$(0A#F^%\(9\,,-#0T-"$(0^$^>Z5TKZSPV?
+M?D_1H&B?XB(B(B(B(B(CC6=3D?"R5*4I2E*4I2E*;/99@P8,&#!@X7"X7"X7"X
+M7`X'$XG$XD(0A"$(0A"'6T444>51111"$(?]._?2?30A"'K****/-!1111"$
+M(;J***/O44440A"$(0A]=3DX3JWV'-?;>,[I]YSGQ'H'B]MK:VMK:VMK:VMK:V
+MMK:VMK>"\-]ET[8V-C8V-C8V-C8V-C8V*4B(B(B(B(B(BE*4Q,3$A\&BBBB$
+M(0A"$/^_(_3T-#0T(0A#[G?O$>Q<U"$(0A"$(0A2BBBB$(0A"$(0A"$(0^T^
+MV[UXS[C[KQW.?/>0\EY;@<#@1$1$1$1$1F6A=3D*T2E*4I2E*4I2E*4B(B(B(B
+M(B(BFQL;'@T4440A"'E4444>BHHHH\.BBBB$(0ZCKO*YSG.<YR$(0[ET>+%B
+MQ=3D;11113L;YQY+#P?@66666KA@888#-AA@`>5H:&AH:****(?:4440>6S/_G
++WQ=3DR13A0D#$"%&\`
 `
 end
diff --git a/sys/boot/efi/boot1/fat-arm.tmpl.bz2.uu b/sys/boot/efi/boot1/=
fat-arm.tmpl.bz2.uu
index 23e063e..ee2ee99 100644
--- a/sys/boot/efi/boot1/fat-arm.tmpl.bz2.uu
+++ b/sys/boot/efi/boot1/fat-arm.tmpl.bz2.uu
@@ -2,25 +2,50 @@ FAT template boot filesystem created by generate-fat.sh=

 DO NOT EDIT
 $FreeBSD$
 begin 644 fat-arm.tmpl.bz2
-M0EIH.3%!62936>#67)H`&U9_____Z^KJZ_ZN_^O^J_^[OJ[NK^JJ^KZNKNNJ
-MZNKNZOJ^P`+\```"``:`T::-`:8@P@&1D-!H:808)B:#0`T``,$T#!,@PC09
-M#33"9,0`T(`!H#1IHT!IB#"`9&0T&AIA!@F)H-`#0``P30,$R#"-!D--,)DQ
-M`#0@`&@-&FC0&F(,(!D9#0:&F$&"8F@T`-``#!-`P3(,(T&0TTPF3$`-`522
-M$_(H2-DT0T:8C(T!H!ZC30R-&@-`,@&C1H:`:#1M3(T,@:::/1#331FII@)@
-M)Z:)RK5N6<7,O<%[)S4ZD(ODD1"*2"(B(+E99)"P2A$"$.#(((0Z^BHO)97*
-MKNTS2;//!6_,:)5IVI>LPGUM8_)MV&_QO'$<Q>Y;`J/TETR.=3D50:\2B`0AF9
-M<_.ME;:;0N<9%D%\Q['*&6B4*U:JM6K5JUQ12I)1111116K45I*TJU:M6K<:
-MZ424444448Y-1)111111[F<_6R+%BQ8L6+$X3333333333333333=3D7Z\E2M6
-MK5JU:M--------->R44444447N#[%BQ8L6+%BQ-M)*******,!0HHHHHHHY[
-M-RR5757;.MS?HE)GL[:M-Q)&/TG09Q6MZ%)XJ4><D]5[S5M>^]M6W8C@..T=3D
-MV&HOX\@T$`%JWHY$`-/ZV!A?)K>YEEZ1`#*,&#,]G484F/7/RDR%Y<?]FG8X
-M&-?VUWJ*AR)+Z32//:9[#4M6R;8-FVK<,1OG$8K*LE&JR>4Q?U[J:^S$]EPK
-MD81)^D"<A>%H^>2OU:FLC31KK??,_$ES74S%+)U7JU5D:VQD)R-2U3"7[FWW
-M-DPVV;ANV^9-R&"T;G,A>6EJ3:=3DEVE6ENKC#PZG.]=3D9:75*G=3D>-4N\OA]'=3D-
-M`L[RN\MM/>Z'8:6Q.RAWU+=3DHOHDCZ6H?8_!^+:-JVS^6Z;UP'#<ERG-[$W'`
-MJ+^19>>T*HB+3GM+4VVS(NQ)&K?`_9IW\,PS#$;QOG"<-QV*QFB8^2)!)H).
-M7(_@P9(R$G)DC<L1NV\;UGV_<)Q'&?FY+%?$Z1Q?DWR/?DC@8W"M'(_<RTBJ
-M2'#=3D^XK8.,U[CN0Q'_,5MV,Y;F,`QI',DW7EU-_(S>MYF,_-.IT<D58,0"$)
-60`75I:D;]&V2<%_XNY(IPH2'!K+DT```
+M0EIH.3%!629363'ZIQP`'Z#______________^O^J_^[OJ[^J^JK^KZNKONZ
+MZNK^ZN[^X`C_```:*`!()"1(2)!!H&@&09!H&@:,3(T#0`8@`T#"&C0-````
+M-`9&C0````#1D9,F)H!DT8%552:!D9/_]453_]53_54_]53]4``-````````
+M``&@````!H```&@`T:``T!H:`0:!H!D&0:!H&C$R-`T`&(`-`PAHT#0```#0
+M&1HT`````T9&3)B:`9-&(-`T`R#(-`T#1B9&@:`#$`&@80T:!H```!H#(T:`
+M````:,C)DQ-`,FC$&@:`9!D&@:!HQ,C0-`!B`#0,(:-`T````T!D:-`````-
+M&1DR8F@&31@55(_2/0E-&HVE-XJ9ZJ3:G_JDC90]3(:&C0:-/4]0/4>H]0;4
+M`#0-&@VIZFFF:FC0:>IHVH>H!IHWHIH>2::#U/4]3#4]&3:FD[$4T=3DT[;+$:
+MN:8'3:!AAA70P8,,,,,;"^A@#`N-'Q-`PPPP'K:M)GVO:LZ/HDN[1WS1^6_`
+M:?U'@N_>Z>(\)[YX[_!_T\EYCYC5@>EXZ7BZ.V8;VEA@PPP'IM'5[.SK*.LZ
+MRKK.L[UP<'!P<'!P<'!P<'!P<'!U'9MCN7.VGI<-#>T-[>EO;U6].]O;V]O;
+MV]O;V]O;V]O;W,VNC:AM;5&UM;6UM;6UM;6UM;6UM;6UM;6UO;&]SM[M*-[0
+MHT;'3:W*U/-R5:%555557!J5:FA?#0NNNNNN]K]=3DXU\+KKKKKKI<BKD1AI66
+M66662E*4I2E*RJSN._T,5&;-FS9LTI2E*4I2S59NE1"ZZZZZ[F]7X%UUUUUU
+MUTM2K4]_1"ZZZZZ[LE6:S-#2NNNNNN[;U&CI:>XS>M??OTGN7]#X#RWP_2*J
+MJJJJJI>L5=3DZAI6666662E*4I2E*RJS5R#PV';_R52Y7*Y7*Y7*E*4I2E*7*J
+MY4-*RRRRRSFJJJJJJJJE=3D5=3DWE$+KKKKKLZJJJJJJJI9JLWP:(777777=3DUTK+
+M++++++)<BKD0TK+++++)2E*4I2E959#2LLLLLLE959#2LLLLLLZOYW;<C-FQ
+MS#B659EI&4ZEG&51WCM&+S'BJ>X]59]#/KOP:)G,`]MV>'L#N\,,`"*?E:`P
+M`>T]KU?=3D^%[SNM$X&`#M'S;[=3DQ6<7%Q<7%Q<7%Q<7%Q<7%Q<7%Q<70[YL?--
+MS<Q;FYDW-S<W-S<W-S<W-S<W,C(R,C(NNNNNNNNNNNNNNNNNNNNZCJ.HZCH;
+MFQN;E$-CIM;E<C-*4I2E*4KJKH:5EEEEEDX2E*4I2E959ZBB%UUUUUW>5555
+M55552S59H:5EEEEEDI2E*4I2LJLAI666666>[JJJJJJJJE=3D5=3DZ9RUT/G>TJE
+MJ:FI5J:DM2K4AI6666662]@]H_??S/?OA/BO/^H55555552[K\A9W[U/R^WE
+MBU-34U-34E*4I2E*7(JY'5]QBHS9LV;-FE*4I2E*6:K-#2LLLLLLE*4I2E*5
+ME5D-*RRRRRR4I2E*4I6560TK+++++)2E*4I2E959\FB%UUUUUTI2E*4I2NJN
+MAI666666?3U7670TKKKKKKK,LRS+NK:<SK3VWLPSS,M`U!]Z/Y1@P8(B(B(B
+M(B,VZAJ+86J93.V666666666666=3D#H=3D#AZ?L=3DSW>QL;&QL;&QL;&QL;&QL;&
+MQO;V]O<OK-W8[ZJJJJ/"-"BBCR,!?0.!DR9,D(0A[RBBBCD_1Q8L6+N,/S,/
+M#G[IX#P7[CN<*****^'R]OGKOIYT:>WY'(Y'(_LHHHHA"$(0A"$(0O1111"$
+M(=3DDUOZGO77?Y/@O^7E/C/.?4N9S.9$1$1$1$1'-N^>(\EJM[++++++++++++
+M+++,O$1$1IB(B(B(CH=3D#H=3D#HHHH\7%]5];'LNG5555U^OBQ8L75]5JR9,F2V
+M>+%BQ?@^OQ8L6+E[7[/YRS[AX3]5XC7^+S=3D.4I2\#G_&\3V6I?5FS9LT(0A]
+M]G.3)DR0A"&VBBBB$(0A"$/>O?/%>,_T?ZO]WE/_7F//>N:];6UM;!@P8,&#
+M!@P8,&#RG7/-9Y2E*4I2E*4I2E*1$1$1$1$1$12G.YWD>7BQ8L4(0A"$(0A"
+M$(0AV3#J^!DR9,F3X'];W3P7C(0A"$(0A"$/PJ***(0A"$(0Y^CVXTX889,F
+M3)"$(>W>.S;-OG?4^UH7Y-$T;_$1$1$1$1$1$<>]YGV@4I2E*4I2E*4IDS3-
+M,&#!@UM;6UM;6UM;6UN9S-C8V-B$(0A"$(0A#[:BBBCT:***(0A#_-X[X3X:
+M$(0]=3D1111"$(>D"BBBC?\C%BQ8O.HHHHA"$(0A#R7_;[5_X^*^.\U[%YSY3W
+M#U+_[W/2=3D)TG2=3D)BQ8L6+%BQ8L6+['W-"VQ2E*4I2E*4I2E*1$1$1$1$1$12
+ME.=3D"$(>VHHHHA"$.%%%%'E]CU^3)DR0A"'7\A\1WKXR$(0A"$(0A"E%%%$(0
+MA"$(0A"$(0AUWF/Z7FOD/DO/?*>.[#Y;_D1$1$1$1$1$7:-T[^E*4I2E*4I2
+ME*4I$1$1$1$1',YG,YW.YW.\FBBBB$(0]&BBBCK4444>51111"$(>J^[]'T'
+MH/0>@A"$/[GI\6+%B[RBBBBGL<6+%BICA@888#1AA@`>CDR9,F5%%%$/CJ**
+1(/F-#S7_XNY(IPH2!C]4XX``
 `
 end
diff --git a/sys/boot/efi/boot1/fat-arm64.tmpl.bz2.uu b/sys/boot/efi/boot=
1/fat-arm64.tmpl.bz2.uu
index 1101deb..1fa4138 100644
--- a/sys/boot/efi/boot1/fat-arm64.tmpl.bz2.uu
+++ b/sys/boot/efi/boot1/fat-arm64.tmpl.bz2.uu
@@ -2,25 +2,49 @@ FAT template boot filesystem created by generate-fat.sh=

 DO NOT EDIT
 $FreeBSD$
 begin 644 fat-arm64.tmpl.bz2
-M0EIH.3%!629364C65#T`&U;_____Z^KJZ_^N_^O^J_^[OJ[NK^JJ^KZNKNNJ
-MZNKNZOJ^P`+\#0``0`#0#)D&@TR8AD`,0!D--&`@:!H&@`!B#)IHR:--#(9,
-MAA`8F@Q,0,#52`_U4?J@`&AH```:`:``````T-`T&@R&@T``````````$``T
-M`R9!H-,F(9`#$`9#31@(&@:!H``8@R::,FC30R&3(80&)H,3$#`521(]I1I)
-MF*:8C1Z`F0:`TR,@:&C30:`R!HTT,$!DTT-J:&@R&C)IA,:F33(S4]-3`--$
-MZ--B6=3D6F1M!<28FJA"+E)$0B<@B(B"TK+:2%L)0B!"'(D$$(9F:@LRO+Q;TL
-MNJ9YY2QZK1*-0US5+UM6R;E?-T_QQG*=3D-<9#J:#>R[!&-40;(2B`0AE9=3D956
-MO+"IH&,8M=3DKEBF(3,A$H5JU%:M6K5K1-.A)------6K35I*TJU:M6K<RU323
-M333338A4FDFFFFFFMX;;,<,#`P,#`P,".`@0($"!`@0($"!`@0J5,OJY*%:M
-M6K5JU:I4J5*E2I4J*E2I4J5*EQ<9OW>[LK*RLK*RLK*INY)IIIIIIL6F3333
-M333=3D7VLL91VEN[UP[M$I,5X--+@R1:XKTL?G%LL>,D\Y*-*DU+6MB^YMF\7S
-MB,!S6CMPUEU'H'B0`4V-'(@!JKN]^?Z<]*UB`&/9J#*9N@O9.H6FYDN5AT,L
-MS-UAW-A;:O3J61R=3D".=3D)EY-(TK3M8US8NM;1N&\<%Q%^Y3"9%=3D8Z-AUMYA;W
-MPYKK)5;?@6D;$DWL"J0LE*.Q]RA>Q[,;.QH%VDM/KGE)[.JBX4T=3D56_.0JD:
-MUL&Q73$OR;=3DNF^?PXKCL%SF=3D:1FKO&W%A1)O,YWU&FM;1N]W0QW=3D6U*UDS]Q
-M0M\CN\G:L^KT%O2U%G0;335JJYFAG8I,5$D?:UC\'Z/U;QO7`<)_3CL!R7/=3D
-M%B=3DL<+`H+J1;6??%$1%*H8[34M_N$+V0O6O;YJ7!95E7%<9?L%R7-83#:)BY
-M(D$F?DZ4B^,W)%W)SY(X;B/[<9?L\P'_-*YC<N>PGRLLY=3D[?HU\D?[A\BDOL
-MP)20P6A<ERG+;5S'-<YT&$OF&Z3IKLPY'3DPI,"1F-ET\-^SUZ&2DBC-1`(0
-6E`!:TJ9&`C?I,%_XNY(IPH2"1K*AZ```
+M0EIH.3%!629366M+$VP`'Z%______________^O^J_^[OJ[^J^NK^KZNK_NJ
+MZNK^ZN[^X`C_%``&B@`)"0D2$B0&JJ:8F`F``>]5````````````````````
+M``````````*JJDT`&G_^J2I_^I4_RJGJ``!H``-````````&@-`````````&
+M@#0`&AH!`:!H!H`:#30R`&FA@F@T-!IB!H#(#3$``9```:`#",`@`,@:````
+M0&@:`:`&@TT,@!IH8)H-#0:8@:`R`TQ``&0``&@`PC`(`#(&@```$!H&@&@!
+MH--#(`::&":#0T&F(&@,@-,0`!D``!H`,(P"``R!H````*JD?I'H1*;293/%
+M*FVJ;?JJ?JFGM2&F0VB`/4'J`>2&@R:#0#1H-'H3)IY0'J'I`T:&@TTT_1(T
+MVIFH'I-I/334]&3)E/-BFK[5U\L1LVS`Z+4,,,*ZF#!AAAAC87U88`P+CQM8
+MPPPP';U:S/K=3D9G1]*EW*/6M7YKUS7^J[U[-W[^I_$]^\)V'B/BO(>>V8':L.
+MF[3K4>#JPPP888`5#1,2SH&`V!@,!X#`8(,$"!`@0($"!`@0($"=3DFZ;LW.[A
+MS-QZ'#4X-3@X)<'!5P3P<'!P<'!P<'!P<'!P<'!R-SLMR&YN4;FYN;FYN;FY
+MN;FYN;FYN;FYN;G!SN#F<':4<&I1JYW1;70;'DY*M2JJJJJKLVQ5L:E\-2ZZ
+MZZZ[]?[#X%\+KKKKKKI:*M$8:UEEEEEDI2E*4I2LJLZ_L]3%1FS9LV;-*4I2
+ME*4LU6:&M999999R\GU'M<V;-FS9LV:6Q5L=3DBB%UUUUUW259K,T-:ZZZZZ[K
+M_2:N77Z3-V[\)[)^Z]X^"^._XZJJJJJJJJ7U:KU:&M999999*4I2E*4K*K(:
+MUEEEEEDI2E*4I2LJLAK6666667JJJJJJJJE=3D5=3DW5$+KKKKKLZJJJJJJJI9JL
+MWQ-G<9,6C1HT:-$I2E*4I2T5:(:UEEEEEFW0>LPP];FS9LV;-FS2V*MB&M99
+M9999*RJR&M999999U/8=3DKHS9L=3D'=3D,NS#1,MG'.,NCMG7,CR7@*>V]-F7T,\N
+M^]H'/8!V'4P_+.YPPP`(I^9J#`![;J>Y_A_D^TU98&`#T+M'<N*SBXN+BXN+
+MBXN+BXN+BXN+BXN+B[)ZQSNJWM[%O;V3>WM[>WM[>WM[>WM[>WM[*93*7777
+M777777777777777777=3D-TW9-[G;V]1#G=3D%M=3D!HS2E*4I2E*ZJZ&M999999.$
+MI2E*4I656>DHA=3D=3D=3D=3D=3D=3DZJJJJJJJJJ6:K-#6LLLLLLE*4I2E*5E5D-:RRRRR=
S
+MW-55555554KJKNLZ%=3D3T2631HT2T:):*M$-:RRRRRR7Y3VCOG\[L/]WR'E^I
+M55555552[C\A9W;TOS>O+%L;&QL;&Q*4I2E*4M%6CJ=3DYVV3%KT:-&C1H]3AA
+M99555555+8JV+^C^BR8M&C1HT:)2E*4I2EHJT0UK+++++)2E*4I2E959#6LL
+MLLLLE*4I2E*5E5GRZ(7777772E*4I2E*ZJZ&M999999LJNLNAK7777776556
+M>R7?OLW;-'OVQX;H/CN1Y;D;6UM<CD<B(B(B(C-,XU!L*VJY;N[+++++++++
+M++++++-9S7]^UPF+%BQ8L6+%BQ8L6+%BQ:FZCJ.HZ&K=3DYOQI2EDCOS4HHH^'
+M@+:AZ`R9,F2$(0A"$/K_T\6+%B]+A[##W4_=3DO:N]=3DR^@44445_FZ'7S]U?7S
+M(U^CT:-&C^ZBBBB$(0A"$(0A"]%%%$(0ATFU_8]Z[#X+XCQ'BO'>4^L<B(B(
+MB(B(B(CDG=3D/!9MF[ZI9999999999999999I<1$1&D(B(B.1R.1TG2=3D)TG/11
+M1X&+ZWMX]CT:JJJNQV,6+%B]!VVS)DR9+4444>NZN+%BQ=3D#K?;^BL[IW[NWN
+MW)Z_ER9,F3N^CZ_W?L=3D%],V;-FA"$/P,YR9,F2$(0Z=3D%%%$(0A"$(?WO?/`>
+M"_U>&_Z>*\9Y#RWV3;M;6#!@P8,&#!@P8,&#!XSJGD/54I2E*4I2E*4I2D1$
+M1$1$1$1$<SF<SF>%_[BQ8L4(0A"$(0A"$(0A\Y[3%BQ8O@>\=3D\[QX"$(0A"$
+M/>T444?XT4440A"$(0AS=3DEWHUX889,F3)"$(=3DZ^$Z[8GS,^^U^+\V@:%_B(B
+M(B(B(B(B.-9E\#/*4I2E*4I2E*4V;%BP8,&#:VMK:VMK:VMK:Y'(YW.YW.A"
+M$(0A"$(0^ZHHHH\ZBBBB$(0_T?"?#>&A"$/L:***(0A#JA1111PHHHH\JBBB
+MCQZ***(0A#_M\5]P^,\9\EY+L/*?,?N/3/([[E<KE<KE<K(R,C(R,C(R,C(S
+M[['W-J4I2E*4I2E*4I2D1$1$1$1$1$4I2D(0AWE%%%$(0A"$(>+YOX.3)DR0
+MA"'RO"=3D5]Z^0A"$(0A"$(0I1111"$(0A"$(0A"$(?)>0\%Y+Y3Y;RWS'A/-?
+M->>B(B(B(B(B(B[0ND?TI2E*4I2E*4I2E(B(B(B(B(CD<CF<SF<SQ****(0A
+M#SJ***/34444?^44440A"'TWJ_.\QYCS'F(0A#WSM<6+%B]511113\_%BQ8J
+G8X8&&&`U888`'G9,F3)E1111#QU%%$'GM3_Y_^+N2*<*$@UI8FV`
 `
 end
diff --git a/sys/boot/efi/boot1/fat-i386.tmpl.bz2.uu b/sys/boot/efi/boot1=
/fat-i386.tmpl.bz2.uu
index 74c734d..c0440ca 100644
--- a/sys/boot/efi/boot1/fat-i386.tmpl.bz2.uu
+++ b/sys/boot/efi/boot1/fat-i386.tmpl.bz2.uu
@@ -2,25 +2,49 @@ FAT template boot filesystem created by generate-fat.sh=

 DO NOT EDIT
 $FreeBSD$
 begin 644 fat-i386.tmpl.bz2
-M0EIH.3%!629361/"1&$`&U;_____Z^KJZ_ZN_^O^J_^[OJ[NK^JJ^KZNKNNJ
-MZNKNZOJ^P`+\#0``0`#0&C31H#3$&$`R,AH-#3"#!,30:`&@`!@F@8)D&$:#
-M(::83)B`&@:J0:?ZJ/U30`,@```-`,F@``````R-```R``````````$``T!H
-MTT:`TQ!A`,C(:#0TP@P3$T&@!H``8)H&"9!A&@R&FF$R8@!H"JB(GM*:(3VI
-MJ:;29-DF)ZC1H#)IA&0,C1H`R`VH#3$#(#R(R#(T8FFR$P(R8&AHQ3TTU.M/
-M4CH56XJBSBR%$R"%HBA""$HA"$(0*M)8Q06(C!"`@@OXA`@@[^28LHY?+JTZ
-MY4-*\Q4]=3DJDWP-DUR\;EM6^<1OW+<Q@,99V]K,<"*#>(;UG$,HJ0@""#-QRL
-MK%;U%@U#)LDM5=3D:+-(N(1@I4IJ5*E2I54DID4DDDDDE*E)2BI1I4J5*EU;!)
-M%))))))CE"2*222222VAMLQPP,#`P,#`P(X"!`@0($"!`@0($"!"A0[?7Q3*
-M5*E2I4J5"A0H4*%"A04*%"A0H4+.ST&QK*RLK*RLK*RA>Q22222226J1))))
-M)))E.[CDIL[6:1_=3D=3D<1)HM-I)YW&BA1::S+:)65-0B]%&'M(M<V2\;ANU\XC
-MDN@P6KK!L*\/4/(@`3U-7$@`^+([2[^_Q8V$(`,J\&!FM!,;2+'JN_BM,?5?
-M]<L]7Q:]TM\Q0QVOF&%%<Q:Q[:EL&S7C+-RWS@N,Y+G,!B+A<VSZ\M;XG"\:
-M2OF*-[X56%V1<"`HB+(LZB&<]^9>0NH;>IIW;(JNVEFI;>C')YXV5+]XBB)\
-M[ZEVKL@W3>-^_IQW*<UT6$T3U7N9.RG317VA\.:ZL*J]MKV=3D;9^M.HBT^EF6
-M68O<S8-.I\NM.KV7E;C6TJ*9&IE4G.PA%#\6O?HW;^%\X#AN0Y3FN@Z;#=3D9D
-M/V./M9BO$L;+8B:$(3K:ZF<+>(%VV;@O/<5F69<ES'/=3D%TV"Q&*U3*10B$7C
-MQ3(=3D>*8X9GXH9&+#BAR'^.4Y;FM,Y[HL!@OY8;$?8S;J7G.0^F*'/Q;^<WV%
-MPQ&*#I-2P'4=3D5NF"PF&_UB.*Q778RU,6)C18D5_$SNVQL5?-;,[6*$V>A`$$
-7$8`%A.GB7Z'$1=3D)_XNY(IPH2`GA(C"``
+M0EIH.3%!62936=3DSO#C@`'YC______________^O^J_^[OJ[^J^NK^KZOKONJ
+MZNK^ZN[^X`C_*``&B@`4"0D2(B0&I*````````#0```````#(-``R```````
+M```````"JJE'ZH`:?_ZDJG_ZJ>JG_JJ````````````````#0``T```````#
+M0:&AZ@$!H&@&@!H--#(`::&":#0T&F(&@,@-,0`!D``!H`,(P"``R!H```!`
+M:!H!H`:#30R`&FA@F@T-!IB!H#(#3$``9```:`#",`@`,@:````0&@:`:`&@
+MTT,@!IH8)H-#0:8@:`R`TQ``&0``&@`PC`(`#(&@````JJ1^E'Z:22>E-/U3
+MU*?_I2GM2)_ZJF3TVJ>H>IH:,C0,T@:;4'J&@:#U--`:`9`>H!ZC30:`>H`>
+MU3U&3TCU--&AZ3T33#4]J:3M1;5],[S;L'-SS`ZK4,LLKZF3)EEEELH8U99`
+MR/+U#+++(9CZ.Z#/T/H6=3DGI$O6OLUGWK[5KIA8"H%V,<7HTANC4'..@>0_@A
+MKX(FK!2V=3D#7*(0A"$(`%PKSW6IUUG7=3D=3DAUW7>"Z72Z72Z72Z72Z72Z72Z72Z
+M7<NEP>K=3DN^0//Y:G%J<7%+BXKN*>+BXN+BXN+BXN+BXN+BXM[O]'1HLT:+-&
+MC1HT:-&C1HT:-&C1HT:-'6<'6=3DNXN5G%J6:N#JN=3DU',^%M7:EUUUUUW=3D.9=3DS
+M-3#4PPPPPP_-]37^&K+######"6Y=3DN1EK4I2E*2E*4I2E*EU.Q^3J;%F;-FS
+M9LTI2E*4I2S79H:U*4I2G;;_3^TS9LV;-FS9I<R[F=3DFR&&&&&&'0NS4S0UL,
+M,,,,.QWVKMM?R^;Z1]H_%?JO%>Y>^?Z]TNNNNNNNEZA=3DX*&M2E*4I*4I2E*4
+MJ74AK4I2E*2E*4I2E*EU(:U*4I2F/JZ4I2E*4EFNS0UJ4I2E,[KKKKKKKI87
+M8>3S>KVMC<W-S<W-R4I2E*4I;EVY#6I2E*4E*4I2E*5+J0UJ4I2E)4NI#6I2
+ME*4T^^^3W,V;9N>M:W,U9>R>P:"CMW8,'DLXI[;TV+Z7QKOP9]SE@S>HY7-G
+M"965E`$6]AJ#(!^7UO;>U_<[_5MR,@'H'R+ZIR4Y.3DY.3DY.3DY.3DY.3DY
+M.3DY.X>N<'=3D-&C8T:-K1HT:-&C1HT:-&C1HT:-&CN7<KKKKKKKKKKKKKKKKK
+MKKKKKL6GLMHT60X.JYW4;F:4I2E*4I8780UJ4I2E)RE*4I2E*EU.]LAAAAAA
+MAX%UUUUUUUTLUV:&M2E*4I*4I2E*4J74AK4I2E*>O]M2E*4I2DLUV;T3??4[
+MNTMK<W-R[<W);EU(:U*4I2DONWLWB/WW9>[>_>9Z5=3D=3D=3D=3D=3D=3D=3D+O_"4_&?,=
?&[
+M$MCF<SF<SF8YFJ[T?8PPPPPPPIU%V;K^'L69LV;-FS2E*4I2E+-=3DFAK4I2E*
+M2E*4I2E*EU(:U*4I2DI2E*4I2I=3D2&M2E*4I*4I2E*4J74^)9######"4I2E*
+M4I878>F960PPPPPPNNPIA#6PPPG###"E-(=3D.TEWK2FVLT]9FGRM+9U'\HLLL
+MB(B(C>WM[>WNP]DZKNWT'7>)T.AT.AT.AT.AT.AT.AT.AT.AZ#L=3DKQ_6<'!P
+M<'!P<'!P<'!P<'!P<'6=3D9UG6=3D3O=3D.UJE*4H]J:EEEG^60K4.N=3D,I2E"$(0A"
+M'T7X>QL;&QWV7L<O;SX#V;\]^F[U9999?]WJ=3DC/V^."(U=3D7<W-S<_FLLLLA"
+M$(0A"$(0Q9999"$(=3D#G>*_H>,]P_S?[O*?`?%>H;V]O;V]$1$1$1$<J[MG'B
+M.EU+%BQ8L6+%BQ8L6+%BQ8M'B(B(T1$1$1$1B[AW#N'"RRSL['T/J8_"ZMUU
+MUWC=3D?QMK:VMKK^EZFUM;6UBRRRSU_?[&QL;&_T7K.[I]8\)^._@;_"[;:VMK
+M:[OJ_=3D?J?@;F-V;-FS0A"'V.<[6UM;4(0AW-EEED(0A"$(?SOZG9?W/<O)>\
+M>4\M\%YCU3GYW.YW.YW.LLLLLLLLLL\5YCR'J*4I2E*4I2E*4I2(B(B(B(B(
+MB*4I3R/?;&QL;$(0A"$(0A"$(0AY[VFQL;&QX_BO$>&[*$(0A"$*LLLLA"$(
+M0A"$(0\OWOZ`UY99;6UM;4(0A[%[IWCO'O'_#RGY,\S[,?XB(B(B(B(B(CC6
+M;?"^12E*4I2E*4I2FS9;+66666666<[G<[G<[G;V]P<'!P0A"$(0A"$(>!99
+M99YUEEED(0A[AY#R7NT(0AZJRRRSN@LLLLA"$.-EEEGQ;+++(0A"$,C(^I]C
+M@WW/Q9Y^SUW\,QW+!^G>8,&#!@P8,&#!@P8,&#!];[6=3D;.I2E*4I2E*4I2E(
+MB(B(B(B(B(I2E,C(R,CP[+++(0A"$(0_Z[7KMK:VMJ$(0^'Y#_MX+WZ$(0A"
+M$(0A"UEEED(0A"$(0A"$(0A_X^"\=3D\)\-\1YC_Y[IVGQGQV]O;V]$1$1$1$1
+M=3DF.F?TI2E*4I2E*4I2E(B(B(B(B(B(I3MW;O>V6660A"'G6666=3D]9999_S99
+M99"$(>D^N\[S7FO->:A"$/['H]C8V-CP+++++?@[&QL;%MF61EED-6660!YV
+A<#S[+FVTI2&VRRRR'P%EED'QVI_Z__%W)%.%"0W.\..`
 `
 end
diff --git a/sys/boot/efi/boot1/generate-fat.sh b/sys/boot/efi/boot1/gene=
rate-fat.sh
index d9dfb27..7c46e92 100755
--- a/sys/boot/efi/boot1/generate-fat.sh
+++ b/sys/boot/efi/boot1/generate-fat.sh
@@ -13,7 +13,7 @@
=20
 FAT_SIZE=3D1600 			#Size in 512-byte blocks of the produced image
=20
-BOOT1_SIZE=3D128k
+BOOT1_SIZE=3D512k
=20
 #
 # Known filenames
diff --git a/sys/boot/efi/boot1/ufs_module.c b/sys/boot/efi/boot1/ufs_mod=
ule.c
deleted file mode 100644
index 0860a86..0000000
--- a/sys/boot/efi/boot1/ufs_module.c
+++ /dev/null
@@ -1,180 +0,0 @@
-/*-
- * Copyright (c) 1998 Robert Nordier
- * All rights reserved.
- * Copyright (c) 2001 Robert Drehmel
- * All rights reserved.
- * Copyright (c) 2014 Nathan Whitehorn
- * All rights reserved.
- * Copyright (c) 2015 Eric McCorkle
- * All rights reverved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in th=
e
- *    documentation and/or other materials provided with the distributio=
n.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AN=
D
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE=

- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PU=
RPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIAB=
LE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUE=
NTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOO=
DS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)=

- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, S=
TRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY=
 WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY O=
F
- * SUCH DAMAGE.
- *
- * $FreeBSD$
- */
-
-#include <stdarg.h>
-#include <stdbool.h>
-#include <sys/cdefs.h>
-#include <sys/param.h>
-#include <efi.h>
-
-#include "boot_module.h"
-
-static dev_info_t *devinfo;
-static dev_info_t *devices;
-
-static int
-dskread(void *buf, u_int64_t lba, int nblk)
-{
-	int size;
-	EFI_STATUS status;
-
-	lba =3D lba / (devinfo->dev->Media->BlockSize / DEV_BSIZE);
-	size =3D nblk * DEV_BSIZE;
-
-	status =3D devinfo->dev->ReadBlocks(devinfo->dev,
-	    devinfo->dev->Media->MediaId, lba, size, buf);
-
-	if (status !=3D EFI_SUCCESS) {
-		DPRINTF("dskread: failed dev: %p, id: %u, lba: %ju, size: %d, "
-		    "status: %lu\n", devinfo->dev,
-		    devinfo->dev->Media->MediaId, (uintmax_t)lba, size,
-		    EFI_ERROR_CODE(status));
-		return (-1);
-	}
-
-	return (0);
-}
-
-#include "ufsread.c"
-
-static struct dmadat __dmadat;
-
-static int
-init_dev(dev_info_t* dev)
-{
-
-	devinfo =3D dev;
-	dmadat =3D &__dmadat;
-
-	return fsread(0, NULL, 0);
-}
-
-static EFI_STATUS
-probe(dev_info_t* dev)
-{
-
-	if (init_dev(dev) < 0)
-		return (EFI_UNSUPPORTED);
-
-	add_device(&devices, dev);
-
-	return (EFI_SUCCESS);
-}
-
-static EFI_STATUS
-load(const char *filepath, dev_info_t *dev, void **bufp, size_t *bufsize=
)
-{
-	ufs_ino_t ino;
-	EFI_STATUS status;
-	size_t size;
-	ssize_t read;
-	void *buf;
-
-	DPRINTF("Loading '%s' from %s\n", filepath, devpath_str(dev->devpath));=

-
-	if (init_dev(dev) < 0) {
-		DPRINTF("Failed to init device\n");
-		return (EFI_UNSUPPORTED);
-	}
-
-	if ((ino =3D lookup(filepath)) =3D=3D 0) {
-		DPRINTF("Failed to lookup '%s' (file not found?)\n", filepath);
-		return (EFI_NOT_FOUND);
-	}
-
-	if (fsread_size(ino, NULL, 0, &size) < 0 || size <=3D 0) {
-		printf("Failed to read size of '%s' ino: %d\n", filepath, ino);
-		return (EFI_INVALID_PARAMETER);
-	}
-
-	if ((status =3D bs->AllocatePool(EfiLoaderData, size, &buf)) !=3D
-	    EFI_SUCCESS) {
-		printf("Failed to allocate read buffer %zu for '%s' (%lu)\n",
-		    size, filepath, EFI_ERROR_CODE(status));
-		return (status);
-	}
-
-	read =3D fsread(ino, buf, size);
-	if ((size_t)read !=3D size) {
-		printf("Failed to read '%s' (%zd !=3D %zu)\n", filepath, read,
-		    size);
-		(void)bs->FreePool(buf);
-		return (EFI_INVALID_PARAMETER);
-	}
-
-	DPRINTF("Load complete\n");
-
-	*bufp =3D buf;
-	*bufsize =3D size;
-
-	return (EFI_SUCCESS);
-}
-
-static void
-status(void)
-{
-	int i;
-	dev_info_t *dev;
-
-	for (dev =3D devices, i =3D 0; dev !=3D NULL; dev =3D dev->next, i++)
-		;
-
-	printf("%s found ", ufs_module.name);
-	switch (i) {
-	case 0:
-		printf("no partitions\n");
-		break;
-	case 1:
-		printf("%d partition\n", i);
-		break;
-	default:
-		printf("%d partitions\n", i);
-	}
-}
-
-static dev_info_t *
-_devices(void)
-{
-
-	return (devices);
-}
-
-const boot_module_t ufs_module =3D
-{
-	.name =3D "UFS",
-	.probe =3D probe,
-	.load =3D load,
-	.status =3D status,
-	.devices =3D _devices
-};
diff --git a/sys/boot/efi/boot1/zfs_module.c b/sys/boot/efi/boot1/zfs_mod=
ule.c
deleted file mode 100644
index 1926a33..0000000
--- a/sys/boot/efi/boot1/zfs_module.c
+++ /dev/null
@@ -1,196 +0,0 @@
-/*-
- * Copyright (c) 2015 Eric McCorkle
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in th=
e
- *    documentation and/or other materials provided with the distributio=
n.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AN=
D
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE=

- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PU=
RPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIAB=
LE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUE=
NTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOO=
DS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)=

- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, S=
TRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY=
 WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY O=
F
- * SUCH DAMAGE.
- *
- * $FreeBSD$
- */
-#include <stddef.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <sys/cdefs.h>
-#include <sys/param.h>
-#include <sys/queue.h>
-#include <efi.h>
-
-#include "boot_module.h"
-
-#include "libzfs.h"
-#include "zfsimpl.c"
-
-static dev_info_t *devices;
-
-static int
-vdev_read(vdev_t *vdev, void *priv, off_t off, void *buf, size_t bytes)
-{
-	dev_info_t *devinfo;
-	off_t lba;
-	EFI_STATUS status;
-
-	devinfo =3D (dev_info_t *)priv;
-	lba =3D off / devinfo->dev->Media->BlockSize;
-
-	status =3D devinfo->dev->ReadBlocks(devinfo->dev,
-	    devinfo->dev->Media->MediaId, lba, bytes, buf);
-	if (status !=3D EFI_SUCCESS) {
-		DPRINTF("vdev_read: failed dev: %p, id: %u, lba: %jd, size: %zu,"
-		    " status: %lu\n", devinfo->dev,
-		    devinfo->dev->Media->MediaId, (intmax_t)lba, bytes,
-		    EFI_ERROR_CODE(status));
-		return (-1);
-	}
-
-	return (0);
-}
-
-static EFI_STATUS
-probe(dev_info_t *dev)
-{
-	spa_t *spa;
-	dev_info_t *tdev;
-	EFI_STATUS status;
-
-	/* ZFS consumes the dev on success so we need a copy. */
-	if ((status =3D bs->AllocatePool(EfiLoaderData, sizeof(*dev),
-	    (void**)&tdev)) !=3D EFI_SUCCESS) {
-		DPRINTF("Failed to allocate tdev (%lu)\n",
-		    EFI_ERROR_CODE(status));
-		return (status);
-	}
-	memcpy(tdev, dev, sizeof(*dev));
-
-	if (vdev_probe(vdev_read, tdev, &spa) !=3D 0) {
-		(void)bs->FreePool(tdev);
-		return (EFI_UNSUPPORTED);
-	}
-
-	dev->devdata =3D spa;
-	add_device(&devices, dev);
-
-	return (EFI_SUCCESS);
-}
-
-static EFI_STATUS
-load(const char *filepath, dev_info_t *devinfo, void **bufp, size_t *buf=
size)
-{
-	spa_t *spa;
-	struct zfsmount zfsmount;
-	dnode_phys_t dn;
-	struct stat st;
-	int err;
-	void *buf;
-	EFI_STATUS status;
-
-	spa =3D devinfo->devdata;
-
-	DPRINTF("load: '%s' spa: '%s', devpath: %s\n", filepath, spa->spa_name,=

-	    devpath_str(devinfo->devpath));
-
-	if ((err =3D zfs_spa_init(spa)) !=3D 0) {
-		DPRINTF("Failed to load pool '%s' (%d)\n", spa->spa_name, err);
-		return (EFI_NOT_FOUND);
-	}
-
-	if ((err =3D zfs_mount(spa, 0, &zfsmount)) !=3D 0) {
-		DPRINTF("Failed to mount pool '%s' (%d)\n", spa->spa_name, err);
-		return (EFI_NOT_FOUND);
-	}
-
-	if ((err =3D zfs_lookup(&zfsmount, filepath, &dn)) !=3D 0) {
-		if (err =3D=3D ENOENT) {
-			DPRINTF("Failed to find '%s' on pool '%s' (%d)\n",
-			    filepath, spa->spa_name, err);
-			return (EFI_NOT_FOUND);
-		}
-		printf("Failed to lookup '%s' on pool '%s' (%d)\n", filepath,
-		    spa->spa_name, err);
-		return (EFI_INVALID_PARAMETER);
-	}
-
-	if ((err =3D zfs_dnode_stat(spa, &dn, &st)) !=3D 0) {
-		printf("Failed to stat '%s' on pool '%s' (%d)\n", filepath,
-		    spa->spa_name, err);
-		return (EFI_INVALID_PARAMETER);
-	}
-
-	if ((status =3D bs->AllocatePool(EfiLoaderData, (UINTN)st.st_size, &buf=
))
-	    !=3D EFI_SUCCESS) {
-		printf("Failed to allocate load buffer %zd for pool '%s' for '%s' "
-		    "(%lu)\n", st.st_size, spa->spa_name, filepath, EFI_ERROR_CODE(sta=
tus));
-		return (EFI_INVALID_PARAMETER);
-	}
-
-	if ((err =3D dnode_read(spa, &dn, 0, buf, st.st_size)) !=3D 0) {
-		printf("Failed to read node from %s (%d)\n", spa->spa_name,
-		    err);
-		(void)bs->FreePool(buf);
-		return (EFI_INVALID_PARAMETER);
-	}
-
-	*bufsize =3D st.st_size;
-	*bufp =3D buf;
-
-	return (EFI_SUCCESS);
-}
-
-static void
-status(void)
-{
-	spa_t *spa;
-
-	spa =3D STAILQ_FIRST(&zfs_pools);
-	if (spa =3D=3D NULL) {
-		printf("%s found no pools\n", zfs_module.name);
-		return;
-	}
-
-	printf("%s found the following pools:", zfs_module.name);
-	STAILQ_FOREACH(spa, &zfs_pools, spa_link)
-		printf(" %s", spa->spa_name);
-
-	printf("\n");
-}
-
-static void
-init(void)
-{
-
-	zfs_init();
-}
-
-static dev_info_t *
-_devices(void)
-{
-
-	return (devices);
-}
-
-const boot_module_t zfs_module =3D
-{
-	.name =3D "ZFS",
-	.init =3D init,
-	.probe =3D probe,
-	.load =3D load,
-	.status =3D status,
-	.devices =3D _devices
-};
diff --git a/sys/boot/efi/drivers/Makefile b/sys/boot/efi/drivers/Makefil=
e
new file mode 100644
index 0000000..5e1f18b
--- /dev/null
+++ b/sys/boot/efi/drivers/Makefile
@@ -0,0 +1,34 @@
+# $FreeBSD$
+
+.include <src.opts.mk>
+
+LIB=3D	efi_drivers
+INTERNALLIB=3D
+WARNS?=3D	2
+
+SRCS=3D	efipart.c fs_driver.c
+
+.if ${MACHINE_CPUARCH} =3D=3D "aarch64"
+CFLAGS+=3D	-msoft-float -mgeneral-regs-only
+.endif
+.if ${MACHINE_ARCH} =3D=3D "amd64"
+CFLAGS+=3D -fPIC -mno-red-zone
+.endif
+.if ${MK_ZFS} !=3D "no"
+CFLAGS+=3D	-I${.CURDIR}/../../zfs
+CFLAGS+=3D	-I${.CURDIR}/../../../cddl/boot/zfs
+CFLAGS+=3D	-DEFI_ZFS_BOOT
+.endif
+
+CFLAGS+=3D -I${.CURDIR}/../include
+CFLAGS+=3D -I${.CURDIR}/../include/${MACHINE}
+CFLAGS+=3D -I${.CURDIR}/../../../../lib/libstand
+
+# Pick up the bootstrap header for some interface items
+CFLAGS+=3D -I${.CURDIR}/../../common
+
+# Handle FreeBSD specific %b and %D printf format specifiers
+CFLAGS+=3D ${FORMAT_EXTENSIONS}
+CFLAGS+=3D -DTERM_EMU
+
+.include <bsd.lib.mk>
diff --git a/sys/boot/efi/drivers/efi_drivers.h b/sys/boot/efi/drivers/ef=
i_drivers.h
new file mode 100644
index 0000000..0c599d1
--- /dev/null
+++ b/sys/boot/efi/drivers/efi_drivers.h
@@ -0,0 +1,42 @@
+/*-
+ * Copyright (c) 2016 Eric McCorkle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in th=
e
+ *    documentation and/or other materials provided with the distributio=
n.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AN=
D
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE=

+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PU=
RPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIAB=
LE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUE=
NTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOO=
DS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)=

+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, S=
TRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY=
 WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY O=
F
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _EFI_DRIVERS_H_
+#define _EFI_DRIVERS_H_
+
+typedef struct efi_driver_t {
+        const char *name;
+        void (*init)(void);
+} efi_driver_t;
+
+extern struct devsw efipart_dev;
+
+/* EFI drivers. */
+extern const efi_driver_t fs_driver;
+
+#endif
diff --git a/sys/boot/efi/libefi/efipart.c b/sys/boot/efi/drivers/efipart=
=2Ec
similarity index 75%
rename from sys/boot/efi/libefi/efipart.c
rename to sys/boot/efi/drivers/efipart.c
index 5a99381..3e3a9c0 100644
--- a/sys/boot/efi/libefi/efipart.c
+++ b/sys/boot/efi/drivers/efipart.c
@@ -74,90 +74,109 @@ static int npdinfo =3D 0;
=20
 #define PD(dev)         (pdinfo[(dev)->d_unit])
=20
+static EFI_STATUS
+efipart_supported(EFI_DRIVER_BINDING *This, EFI_HANDLE handle,
+                  EFI_DEVICE_PATH *RemainingDevicePath __unused)
+{
+        return BS->OpenProtocol(handle, &blkio_guid,
+                                NULL, IH, handle,
+                                EFI_OPEN_PROTOCOL_TEST_PROTOCOL);
+}
+
+static EFI_STATUS
+efipart_start(EFI_DRIVER_BINDING *This, EFI_HANDLE handle,
+              EFI_DEVICE_PATH *RemainingDevicePath __unused,
+              u_int* ndisk, uint* nrdisk)
+{
+        EFI_BLOCK_IO *blkio;
+        EFI_DEVICE_PATH *devpath, *devpathcpy, *tmpdevpath, *node;
+	EFI_STATUS status;
+        EFI_HANDLE alias;
+
+        devpath =3D efi_lookup_devpath(handle);
+
+        if (devpath =3D=3D NULL) {
+                return (EFI_DEVICE_ERROR);
+        }
+
+        status =3D BS->HandleProtocol(handle, &blkio_guid,
+                                    (void**)&blkio);
+        if (EFI_ERROR(status))
+                return (status);
+
+        if (!blkio->Media->LogicalPartition) {
+                *nrdisk++;
+                return (EFI_UNSUPPORTED);
+        }
+
+        /*
+         * If we come across a logical partition of subtype CDROM
+         * it doesn't refer to the CD filesystem itself, but rather
+         * to any usable El Torito boot image on it. In this case
+         * we try to find the parent device and add that instead as
+         * that will be the CD filesystem.
+         */
+        node =3D efi_devpath_last_node(devpath);
+        if (DevicePathType(node) =3D=3D MEDIA_DEVICE_PATH &&
+            DevicePathSubType(node) =3D=3D MEDIA_CDROM_DP) {
+                devpathcpy =3D efi_devpath_trim(devpath);
+                tmpdevpath =3D devpathcpy;
+                status =3D BS->LocateDevicePath(&blkio_guid, &tmpdevpath=
,
+                                              &alias);
+                free(devpathcpy);
+
+                if (EFI_ERROR(status))
+                        return (status);
+
+                efi_register_handle(&efipart_dev, handle, alias);
+        } else
+                efi_register_handle(&efipart_dev, handle, NULL);
+
+        pdinfo[npdinfo].pd_open =3D 0;
+        pdinfo[npdinfo].pd_bcache =3D NULL;
+        pdinfo[npdinfo].pd_unit =3D npdinfo;
+        npdinfo++;
+        *ndisk++;
+
+        return (EFI_SUCCESS);
+}
+
 static int
-efipart_init(void)=20
+efipart_init(void)
 {
-	EFI_BLOCK_IO *blkio;
-	EFI_DEVICE_PATH *devpath, *devpathcpy, *tmpdevpath, *node;
-	EFI_HANDLE *hin, *hout, *aliases, handle;
+	EFI_HANDLE *handles;
 	EFI_STATUS status;
 	UINTN sz;
-	u_int n, nin, nout, nrdisk;
+        u_int n, nin, ndisk, nrdisk;
 	int err;
=20
 	sz =3D 0;
-	hin =3D NULL;
+	handles =3D NULL;
 	status =3D BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz, 0);
 	if (status =3D=3D EFI_BUFFER_TOO_SMALL) {
-		hin =3D (EFI_HANDLE *)malloc(sz * 3);
+		handles =3D (EFI_HANDLE *)malloc(sz);
 		status =3D BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz,
-		    hin);
+		    handles);
 		if (EFI_ERROR(status))
-			free(hin);
+			free(handles);
 	}
 	if (EFI_ERROR(status))
 		return (efi_status_to_errno(status));
=20
 	/* Filter handles to only include FreeBSD partitions. */
 	nin =3D sz / sizeof(EFI_HANDLE);
-	hout =3D hin + nin;
-	aliases =3D hout + nin;
-	nout =3D 0;
-	nrdisk =3D 0;
-
-	bzero(aliases, nin * sizeof(EFI_HANDLE));
 	pdinfo =3D malloc(nin * sizeof(*pdinfo));
-	if (pdinfo =3D=3D NULL)
-		return (ENOMEM);
+        ndisk =3D 0;
+        nrdisk =3D 0;
=20
 	for (n =3D 0; n < nin; n++) {
-		devpath =3D efi_lookup_devpath(hin[n]);
-		if (devpath =3D=3D NULL) {
-			continue;
-		}
-
-		status =3D BS->HandleProtocol(hin[n], &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
-		 * to any usable El Torito boot image on it. In this case
-		 * we try to find the parent device and add that instead as
-		 * that will be the CD filesystem.
-		 */
-		node =3D efi_devpath_last_node(devpath);
-		if (DevicePathType(node) =3D=3D MEDIA_DEVICE_PATH &&
-		    DevicePathSubType(node) =3D=3D MEDIA_CDROM_DP) {
-			devpathcpy =3D efi_devpath_trim(devpath);
-			tmpdevpath =3D devpathcpy;
-			status =3D BS->LocateDevicePath(&blkio_guid, &tmpdevpath,
-			    &handle);
-			free(devpathcpy);
-			if (EFI_ERROR(status))
-				continue;
-			hout[nout] =3D handle;
-			aliases[nout] =3D hin[n];
-		} else
-			hout[nout] =3D hin[n];
-		nout++;
-		pdinfo[npdinfo].pd_open =3D 0;
-		pdinfo[npdinfo].pd_bcache =3D NULL;
-		pdinfo[npdinfo].pd_unit =3D npdinfo;
-		npdinfo++;
+                efipart_start(NULL, handles[n], NULL, &ndisk, &nrdisk);
 	}
=20
 	bcache_add_dev(npdinfo);
-	err =3D efi_register_handles(&efipart_dev, hout, aliases, nout);
-	free(hin);
+	free(handles);
=20
-	if (nout =3D=3D 0 && nrdisk > 0)
+	if (ndisk =3D=3D 0 && nrdisk > 0)
 		printf("Found %d disk(s) but no logical partition\n", nrdisk);
 	return (err);
 }
diff --git a/sys/boot/efi/drivers/fs_driver.c b/sys/boot/efi/drivers/fs_d=
river.c
new file mode 100644
index 0000000..b9c8536
--- /dev/null
+++ b/sys/boot/efi/drivers/fs_driver.c
@@ -0,0 +1,853 @@
+/*-
+ * Copyright (c) 2016 Eric McCorkle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in th=
e
+ *    documentation and/or other materials provided with the distributio=
n.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AN=
D
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE=

+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PU=
RPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIAB=
LE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUE=
NTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOO=
DS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)=

+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, S=
TRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY=
 WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY O=
F
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <stddef.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <efi.h>
+#include <efilib.h>
+#include <efiprot.h>
+#include <string16.h>
+#ifdef EFI_ZFS_BOOT
+#include <libzfs.h>
+#endif
+#include <bootstrap.h>
+
+#include "efi_drivers.h"
+
+static EFI_GUID SimpleFileSystemProtocolGUID =3D SIMPLE_FILE_SYSTEM_PROT=
OCOL;
+
+static struct fs_ops *backend_file_system[] =3D {
+	&dosfs_fsops,
+	&ufs_fsops,
+	&cd9660_fsops,
+	&tftp_fsops,
+	&nfs_fsops,
+	&gzipfs_fsops,
+	&bzipfs_fsops,
+	NULL
+};
+
+static struct devsw *backend_devsw[] =3D {
+	&efipart_dev,
+#ifdef EFI_ZFS_BOOT
+	&zfs_dev,
+#endif
+	NULL
+};
+
+typedef struct volinfo_t {
+        struct fs_ops *fsops;
+        struct devdesc *dev;
+} volinfo_t;
+
+typedef struct fileinfo_t {
+        const volinfo_t* vinfo;
+        struct open_file fdata;
+        char path[];
+} fileinfo_t;
+
+static EFI_GUID FileInfoGUID =3D EFI_FILE_INFO_ID;;
+
+static EFIAPI EFI_STATUS
+file_open_impl(EFI_FILE_HANDLE File, EFI_FILE_HANDLE *NewHandle,
+               CHAR16 *FileName, UINT64 OpenMode, UINT64 Attributes);
+
+static EFIAPI EFI_STATUS
+file_close_impl(EFI_FILE_HANDLE File);
+
+static EFIAPI EFI_STATUS
+file_delete_impl(EFI_FILE_HANDLE File);
+
+static EFIAPI EFI_STATUS
+dir_read_impl(EFI_FILE_HANDLE File, UINTN *BufferSize, VOID *Buffer);
+
+static EFIAPI EFI_STATUS
+dir_write_impl(EFI_FILE_HANDLE File, UINTN *BufferSize,
+               VOID *Buffer);
+
+static EFIAPI EFI_STATUS
+file_read_impl(EFI_FILE_HANDLE File, UINTN *BufferSize, VOID *Buffer);
+
+static EFIAPI EFI_STATUS
+file_write_impl(EFI_FILE_HANDLE File, UINTN *BufferSize,
+                VOID *Buffer);
+
+static EFIAPI EFI_STATUS
+file_set_position_impl(EFI_FILE_HANDLE File, UINT64 Position);
+
+static EFIAPI EFI_STATUS
+file_get_position_impl(EFI_FILE_HANDLE File, UINT64 *Position);
+
+static EFIAPI EFI_STATUS
+file_get_info_impl(EFI_FILE_HANDLE File, EFI_GUID *InformationType,
+                   UINTN *BufferSize, VOID *Buffer);
+
+static EFIAPI EFI_STATUS
+file_set_info_impl(EFI_FILE_HANDLE File, EFI_GUID *InformationType,
+                   UINTN BufferSize, VOID *Buffer);
+
+static EFIAPI EFI_STATUS
+file_flush_impl(EFI_FILE_HANDLE File);
+
+static struct devdesc*
+clone_devdesc(struct devdesc *dev)
+{
+        struct devdesc *out;
+
+        switch(dev->d_dev->dv_type) {
+        case DEVT_ZFS:
+                out =3D malloc(sizeof(struct zfs_devdesc));
+
+                if (out =3D=3D NULL) {
+                        return NULL;
+                }
+
+                memcpy(out, dev, sizeof(struct zfs_devdesc));
+
+                return out;
+
+        default:
+                out =3D malloc(sizeof(struct devdesc));
+
+                if (out =3D=3D NULL) {
+                        return NULL;
+                }
+
+                memcpy(out, dev, sizeof(struct devdesc));
+
+                return out;
+        }
+}
+
+static EFI_STATUS
+do_file_open(const volinfo_t *vinfo, const char filepath[],
+             int mode, EFI_FILE_HANDLE *out)
+{
+        EFI_FILE_HANDLE fhandle;
+        fileinfo_t *finfo;
+        struct stat st;
+        struct devdesc *tmpdev;
+	int err;
+
+        memset(&st, 0, sizeof(struct stat));
+        fhandle =3D malloc(sizeof(EFI_FILE) + sizeof(fileinfo_t) +
+                         strlen(filepath) + 1);
+
+        if (fhandle =3D=3D NULL) {
+                return (EFI_OUT_OF_RESOURCES);
+        }
+
+        tmpdev =3D clone_devdesc(vinfo->dev);
+
+        if (tmpdev =3D=3D NULL) {
+                free(fhandle);
+                return (EFI_OUT_OF_RESOURCES);
+        }
+
+        finfo =3D (fileinfo_t*)(fhandle + 1);
+        finfo->fdata.f_flags =3D mode + 1;
+        finfo->fdata.f_dev =3D NULL;
+        finfo->fdata.f_ops =3D NULL;
+        finfo->fdata.f_offset =3D 0;
+        finfo->fdata.f_devdata =3D NULL;
+
+        if ((err =3D vinfo->dev->d_dev->dv_open(&(finfo->fdata), tmpdev)=
) !=3D 0) {
+                free(fhandle);
+                return (errno_to_efi_status(err));
+        }
+
+        finfo->fdata.f_dev =3D vinfo->dev->d_dev;
+
+        if ((err =3D vinfo->fsops->fo_open(filepath, &(finfo->fdata))) !=
=3D 0) {
+                free(fhandle);
+                return (errno_to_efi_status(err));
+        }
+
+        finfo->fdata.f_ops =3D vinfo->fsops;
+
+        if ((err =3D vinfo->fsops->fo_stat(&(finfo->fdata), &st)) !=3D 0=
) {
+                free(fhandle);
+                return (errno_to_efi_status(err));
+        }
+
+        strcpy(finfo->path, filepath);
+        finfo->vinfo =3D vinfo;
+        fhandle->Revision =3D EFI_FILE_HANDLE_REVISION;
+        fhandle->Open =3D file_open_impl;
+        fhandle->Close =3D file_close_impl;
+        fhandle->Delete =3D file_delete_impl;
+        fhandle->SetPosition =3D file_set_position_impl;
+        fhandle->GetPosition =3D file_get_position_impl;
+        fhandle->GetInfo =3D file_get_info_impl;
+        fhandle->SetInfo =3D file_set_info_impl;
+        fhandle->Flush =3D file_flush_impl;
+
+        if (S_ISDIR(st.st_mode)) {
+                fhandle->Read =3D dir_read_impl;
+                fhandle->Write =3D dir_write_impl;
+        } else {
+                fhandle->Read =3D file_read_impl;
+                fhandle->Write =3D file_write_impl;
+        }
+
+        *out =3D fhandle;
+
+        return (EFI_SUCCESS);
+}
+
+static int
+mode_from_efi(UINT64 efi_mode)
+{
+        int mode =3D 0;
+
+        if (efi_mode & EFI_FILE_MODE_WRITE) {
+                mode |=3D O_WRONLY;
+        } else if (efi_mode & EFI_FILE_MODE_READ) {
+                mode |=3D O_RDONLY;
+        } else if (efi_mode & EFI_FILE_MODE_READ &&
+                   efi_mode & EFI_FILE_MODE_WRITE) {
+                mode |=3D O_RDWR;
+        }
+
+        return mode;
+}
+
+static UINT64
+mode_to_efi(int mode)
+{
+        UINT64 efi_mode =3D 0;
+
+        if (mode & O_WRONLY) {
+                efi_mode |=3D EFI_FILE_MODE_WRITE;
+        } else if (mode & O_RDONLY) {
+                efi_mode |=3D EFI_FILE_MODE_READ;
+        } else if (mode & O_RDWR) {
+                efi_mode |=3D EFI_FILE_MODE_READ;
+                efi_mode |=3D EFI_FILE_MODE_WRITE;
+        }
+
+        return (efi_mode);
+}
+
+static EFIAPI EFI_STATUS
+file_open_impl(EFI_FILE_HANDLE File, EFI_FILE_HANDLE *NewHandle,
+               CHAR16 *FileName, UINT64 OpenMode, UINT64 Attributes)
+{
+        fileinfo_t *finfo =3D (fileinfo_t*)(File + 1);
+        char buf[strlen(finfo->path) + strlen16(FileName) + 1];
+
+        strcpy_from_16(stpcpy(buf, finfo->path), FileName);
+
+        return do_file_open(finfo->vinfo, buf,
+                            mode_from_efi(OpenMode), NewHandle);
+}
+
+static EFIAPI EFI_STATUS
+file_close_impl(EFI_FILE_HANDLE File)
+{
+        fileinfo_t *finfo =3D (fileinfo_t*)(File + 1);
+        int res;
+
+        if ((res =3D finfo->fdata.f_ops->fo_close(&(finfo->fdata))) !=3D=
 0) {
+                return (errno_to_efi_status(res));
+        }
+
+        if ((res =3D finfo->vinfo->dev->d_dev->dv_close(&(finfo->fdata))=
) !=3D 0) {
+                return (errno_to_efi_status(res));
+        }
+
+        free(File);
+        return (EFI_SUCCESS);
+}
+
+static EFIAPI EFI_STATUS
+file_delete_impl(EFI_FILE_HANDLE File)
+{
+        file_close_impl(File);
+
+        return (EFI_WARN_DELETE_FAILURE);
+}
+
+static EFIAPI EFI_STATUS
+dir_read_impl(EFI_FILE_HANDLE File, UINTN *BufferSize, VOID *Buffer)
+{
+        fileinfo_t *finfo =3D (fileinfo_t*)(File + 1);
+        fileinfo_t *entinfo;
+        struct dirent d;
+        struct stat st;
+        int err;
+        UINTN currsize =3D *BufferSize;
+        UINTN reqsize;
+        EFI_FILE_INFO *out =3D (EFI_FILE_INFO*)Buffer;
+        EFI_FILE_HANDLE enthandle;
+        EFI_STATUS status;
+        off_t currpos;
+
+        /* Record teh current position so we can rewind if we have to */=

+        if ((currpos =3D finfo->fdata.f_ops->fo_seek(&(finfo->fdata),
+                                                  0, SEEK_CUR)) < 0) {
+                return (errno_to_efi_status(errno));
+        }
+
+	if ((err =3D finfo->fdata.f_ops->fo_readdir(&(finfo->fdata), &d)) !=3D =
0) {
+		return (errno_to_efi_status(errno));
+	}
+
+        reqsize =3D sizeof(EFI_FILE_INFO) +
+          ((strlen(d.d_name) + 1) * sizeof(CHAR16));
+
+        if (Buffer =3D=3D NULL || currsize < reqsize) {
+                finfo->fdata.f_ops->fo_seek(&(finfo->fdata), currpos, SE=
EK_SET);
+                *BufferSize =3D reqsize;
+
+                return (EFI_BUFFER_TOO_SMALL);
+        }
+
+        // We have to actually open the file, since EFI directory
+        // reads are supposed to return stat information.
+        CHAR16 buf[d.d_namlen];
+        strcpy_to_16(buf, d.d_name);
+        status =3D file_open_impl(File, &enthandle, buf, EFI_FILE_READ_O=
NLY, 0);
+
+        if (EFI_ERROR(status)) {
+                finfo->fdata.f_ops->fo_seek(&(finfo->fdata), currpos, SE=
EK_SET);
+                return (status);
+        }
+
+        entinfo =3D (fileinfo_t*)(enthandle + 1);
+
+        if ((err =3D finfo->fdata.f_ops->fo_stat(&(entinfo->fdata), &st)=
) !=3D 0) {
+                finfo->fdata.f_ops->fo_seek(&(finfo->fdata), currpos, SE=
EK_SET);
+		return (errno_to_efi_status(errno));
+        }
+
+        status =3D file_close_impl(enthandle);
+
+        if (EFI_ERROR(status)) {
+                finfo->fdata.f_ops->fo_seek(&(finfo->fdata), currpos, SE=
EK_SET);
+                return (status);
+        }
+
+        // We're good at this point, copy everything into place.
+        out->Size =3D reqsize;
+        out->FileSize =3D st.st_size;
+        out->PhysicalSize =3D st.st_blocks * st.st_blksize;
+        out->Attribute =3D mode_to_efi(st.st_mode);
+        to_efi_time(&(out->LastAccessTime), st.st_atime);
+        to_efi_time(&(out->ModificationTime), st.st_mtime);
+        to_efi_time(&(out->CreateTime), st.st_ctime);
+
+        if (S_ISDIR(st.st_mode)) {
+                out->Attribute |=3D EFI_FILE_DIRECTORY;
+        }
+
+        strcpy_to_16(out->FileName, d.d_name);
+        *BufferSize =3D reqsize;
+
+        return (EFI_SUCCESS);
+}
+
+static EFIAPI EFI_STATUS
+dir_write_impl(EFI_FILE_HANDLE File __unused, UINTN *BufferSize __unused=
,
+               VOID *Buffer __unused)
+{
+        // EFI API doesn't allow writing to directories
+        return (EFI_UNSUPPORTED);
+}
+
+static EFIAPI EFI_STATUS
+file_read_impl(EFI_FILE_HANDLE File, UINTN *BufferSize, VOID *Buffer)
+{
+        fileinfo_t *finfo =3D (fileinfo_t*)(File + 1);
+        size_t readsize =3D *BufferSize;
+        size_t resid;
+        int err;
+
+	if ((err =3D finfo->fdata.f_ops->fo_read(&(finfo->fdata), Buffer,
+                                               readsize, &resid)) !=3D 0=
) {
+		return (errno_to_efi_status(errno));
+	}
+
+        *BufferSize =3D readsize - resid;
+
+        return (EFI_SUCCESS);
+}
+
+static EFIAPI EFI_STATUS
+file_write_impl(EFI_FILE_HANDLE File, UINTN *BufferSize, VOID *Buffer)
+{
+        fileinfo_t *finfo =3D (fileinfo_t*)(File + 1);
+        size_t writesize =3D *BufferSize;
+        size_t resid;
+        int err;
+
+	if ((err =3D finfo->fdata.f_ops->fo_write(&(finfo->fdata), Buffer,
+                                                writesize, &resid)) !=3D=
 0) {
+		return (errno_to_efi_status(errno));
+	}
+
+        *BufferSize =3D writesize - resid;
+
+        return (EFI_SUCCESS);
+}
+
+static EFIAPI EFI_STATUS
+file_set_position_impl(EFI_FILE_HANDLE File, UINT64 Position)
+{
+        fileinfo_t *finfo =3D (fileinfo_t*)(File + 1);
+        int res;
+
+        if (Position !=3D 0xffffffffffffffffLL) {
+                res =3D finfo->fdata.f_ops->fo_seek(&(finfo->fdata),
+                                                  Position, SEEK_SET);
+        } else {
+                res =3D finfo->fdata.f_ops->fo_seek(&(finfo->fdata),
+                                                  0, SEEK_END);
+        }
+
+        if (res > 0) {
+                return (EFI_SUCCESS);
+        } else {
+                return (errno_to_efi_status(res));
+        }
+}
+
+
+static EFIAPI EFI_STATUS
+file_get_position_impl(EFI_FILE_HANDLE File, UINT64 *Position)
+{
+        fileinfo_t *finfo =3D (fileinfo_t*)(File + 1);
+        off_t res;
+
+        res =3D finfo->fdata.f_ops->fo_seek(&(finfo->fdata), 0, SEEK_CUR=
);
+
+        if (res > 0) {
+                *Position =3D res;
+
+                return (EFI_SUCCESS);
+        } else {
+                return (errno_to_efi_status(errno));
+        }
+}
+
+static EFIAPI EFI_STATUS
+file_get_info_impl(EFI_FILE_HANDLE File, EFI_GUID *InformationType,
+                   UINTN *BufferSize, VOID *Buffer)
+{
+        fileinfo_t *finfo =3D (fileinfo_t*)(File + 1);
+
+        if (!memcmp(InformationType, &FileInfoGUID, sizeof(EFI_GUID))) {=

+                EFI_FILE_INFO *out =3D (EFI_FILE_INFO*)Buffer;
+                UINTN str16len =3D(strlen(finfo->path) + 1) * sizeof(CHA=
R16);
+                UINTN currsize =3D *BufferSize;
+                UINTN reqsize =3D sizeof(EFI_FILE_INFO) + str16len;
+                struct stat st;
+                int err;
+
+                memset(&st, 0, sizeof(struct stat));
+                *BufferSize =3D reqsize;
+
+                if (Buffer =3D=3D NULL ||
+                       currsize < sizeof(EFI_FILE_INFO) + str16len) {
+                        *BufferSize =3D sizeof(EFI_FILE_INFO) + str16len=
;
+                        return (EFI_BUFFER_TOO_SMALL);
+                }
+
+                if ((err =3D finfo->fdata.f_ops->fo_stat(&(finfo->fdata)=
,
+                                                      &st)) !=3D 0) {
+       		return (errno_to_efi_status(errno));
+                }
+
+                out->Size =3D sizeof(EFI_FILE_INFO) + str16len;
+                out->FileSize =3D st.st_size;
+                out->PhysicalSize =3D st.st_blocks * st.st_blksize;
+                to_efi_time(&(out->LastAccessTime), st.st_atime);
+                to_efi_time(&(out->ModificationTime), st.st_mtime);
+                to_efi_time(&(out->CreateTime), st.st_ctime);
+                out->Attribute =3D mode_to_efi(st.st_mode);
+
+                if (S_ISDIR(st.st_mode)) {
+                        out->Attribute |=3D EFI_FILE_DIRECTORY;
+                }
+
+                strcpy_to_16(out->FileName, finfo->path);
+        } else {
+                return (EFI_UNSUPPORTED);
+        }
+
+        return (EFI_SUCCESS);
+}
+
+static EFIAPI EFI_STATUS
+file_set_info_impl(EFI_FILE_HANDLE File __unused,
+                   EFI_GUID *InformationType __unused,
+                   UINTN BufferSize __unused, VOID *Buffer __unused)
+{
+        return (EFI_WRITE_PROTECTED);
+}
+
+static EFIAPI EFI_STATUS
+file_flush_impl(EFI_FILE_HANDLE File __unused)
+{
+        return (EFI_SUCCESS);
+}
+
+static EFIAPI EFI_STATUS
+open_volume_impl(EFI_FILE_IO_INTERFACE *This, EFI_FILE_HANDLE *Root)
+{
+        volinfo_t *vinfo =3D (volinfo_t*)(This + 1);
+
+        return do_file_open(vinfo, "", O_RDONLY, Root);
+}
+
+static struct fs_ops*
+fs_probe(struct devdesc *dev)
+{
+        struct open_file f;
+	int err, i;
+
+        f.f_flags =3D O_RDONLY + 1;
+        f.f_dev =3D (struct devsw *)0;
+        f.f_ops =3D (struct fs_ops *)0;
+        f.f_offset =3D 0;
+        f.f_devdata =3D dev;
+
+        if ((err =3D dev->d_dev->dv_open(&f, dev)) !=3D 0) {
+                return NULL;
+        }
+
+        for (i =3D 0; backend_file_system[i] !=3D NULL; i++) {
+                f.f_ops =3D backend_file_system[i];
+
+                if ((err =3D f.f_ops->fo_open("/", &f)) =3D=3D 0) {
+                        return backend_file_system[i];
+                }
+        }
+
+        return NULL;
+}
+
+static EFI_STATUS
+make_fs_file_io_iface(struct devdesc *dev, EFI_FILE_IO_INTERFACE **out)
+{
+        static struct fs_ops* fsops;
+        EFI_FILE_IO_INTERFACE* fiface;
+        volinfo_t *vinfo;
+
+        switch (dev->d_type) {
+#ifdef EFI_ZFS_BOOT
+	case DEVT_ZFS:
+                fsops =3D &zfs_fsops;
+                break;
+#endif
+        default:
+                fsops =3D fs_probe(dev);
+                break;
+        }
+
+        if (fsops =3D=3D NULL) {
+                return (EFI_UNSUPPORTED);
+        }
+
+        fiface =3D malloc(sizeof(EFI_FILE_IO_INTERFACE) + sizeof(volinfo=
_t));
+
+        if (fiface =3D=3D NULL) {
+                return (EFI_OUT_OF_RESOURCES);
+        }
+
+        vinfo =3D (volinfo_t*)(fiface + 1);
+
+        fiface->Revision =3D EFI_FILE_IO_INTERFACE_REVISION;
+        fiface->OpenVolume =3D open_volume_impl;
+        vinfo->dev =3D dev;
+        vinfo->fsops =3D fsops;
+
+        *out =3D fiface;
+
+        return (EFI_SUCCESS);
+}
+
+static EFIAPI EFI_STATUS
+bind_iface(EFI_HANDLE handle, struct devdesc *dev)
+{
+        EFI_STATUS status;
+        EFI_FILE_IO_INTERFACE *iface;
+
+        // Check if there is already a filesystem interface
+        status =3D BS->OpenProtocol(handle, &SimpleFileSystemProtocolGUI=
D,
+            NULL, IH, handle, EFI_OPEN_PROTOCOL_TEST_PROTOCOL);
+
+        if (!EFI_ERROR(status)) {
+                return (EFI_ACCESS_DENIED);
+        } else if (status !=3D EFI_UNSUPPORTED) {
+                return (status);
+        }
+
+        status =3D make_fs_file_io_iface(dev, &iface);
+
+        if (EFI_ERROR(status)) {
+                return (status);
+        }
+
+        status =3D BS->InstallMultipleProtocolInterfaces(&handle,
+            &SimpleFileSystemProtocolGUID, iface, NULL);
+
+        if (EFI_ERROR(status)) {
+                free(iface);
+
+                return (status);
+        }
+
+	return (status);
+}
+
+static EFIAPI EFI_STATUS
+stop_impl(EFI_DRIVER_BINDING *This __unused, EFI_HANDLE ControllerHandle=
 __unused,
+          UINTN NumberOfChildren __unused, EFI_HANDLE *ChildHandleBuffer=
 __unused)
+{
+        // Get the protocol inteface, uninstall it, and free it
+        return (EFI_SUCCESS);
+}
+
+#ifdef EFI_ZFS_BOOT
+static void
+efi_zfs_probe(void)
+{
+	EFI_HANDLE h;
+	u_int unit;
+	int i;
+	char dname[SPECNAMELEN + 1];
+	uint64_t guid;
+
+	unit =3D 0;
+	h =3D efi_find_handle(&efipart_dev, 0);
+	for (i =3D 0; h !=3D NULL; h =3D efi_find_handle(&efipart_dev, ++i)) {
+		snprintf(dname, sizeof(dname), "%s%d:", efipart_dev.dv_name, i);
+		if (zfs_probe_dev(dname, &guid) =3D=3D 0) {
+			(void)efi_handle_update_dev(h, &zfs_dev, unit++, guid);
+                }
+	}
+}
+#endif
+
+static int
+backend_parsedev(struct devdesc **dev, const char *devspec, const char *=
*path)
+{
+	struct devdesc *idev;
+	struct devsw *dv;
+	char *cp;
+	const char *np;
+	int i;
+
+	/* minimum length check */
+	if (strlen(devspec) < 2)
+		return (EINVAL);
+
+	/* look for a device that matches */
+	for (i =3D 0; backend_devsw[i] !=3D NULL; i++) {
+		dv =3D backend_devsw[i];
+		if (!strncmp(devspec, dv->dv_name, strlen(dv->dv_name)))
+			break;
+	}
+	if (backend_devsw[i] =3D=3D NULL) {
+		return (ENOENT);
+        }
+
+	np =3D devspec + strlen(dv->dv_name);
+
+#ifdef EFI_ZFS_BOOT
+	if (dv->dv_type =3D=3D DEVT_ZFS) {
+		int err;
+
+		idev =3D malloc(sizeof(struct zfs_devdesc));
+		if (idev =3D=3D NULL)
+			return (ENOMEM);
+
+		err =3D zfs_parsedev((struct zfs_devdesc*)idev, np, path);
+		if (err !=3D 0) {
+			free(idev);
+			return (err);
+		}
+		*dev =3D idev;
+		cp =3D strchr(np + 1, ':');
+	} else
+#endif
+	{
+		idev =3D malloc(sizeof(struct devdesc));
+		if (idev =3D=3D NULL)
+			return (ENOMEM);
+
+		idev->d_dev =3D dv;
+		idev->d_type =3D dv->dv_type;
+		idev->d_unit =3D -1;
+		if (*np !=3D '\0' && *np !=3D ':') {
+			idev->d_unit =3D strtol(np, &cp, 0);
+			if (cp =3D=3D np) {
+				idev->d_unit =3D -1;
+				free(idev);
+				return (EUNIT);
+			}
+		}
+	}
+
+	if (*cp !=3D '\0' && *cp !=3D ':') {
+		free(idev);
+		return (EINVAL);
+	}
+
+	if (path !=3D NULL)
+		*path =3D (*cp =3D=3D 0) ? cp : cp + 1;
+	if (dev !=3D NULL)
+		*dev =3D idev;
+	else
+		free(idev);
+	return (0);
+}
+
+static int
+backend_getdev(void **vdev, const char *devspec, const char **path)
+{
+	struct devdesc **dev =3D (struct devdesc **)vdev;
+	int rv;
+
+	/*
+	 * If it looks like this is just a path and no device, then
+	 * use the current device instead.
+	 */
+	if (devspec =3D=3D NULL || *devspec =3D=3D '/' || !strchr(devspec, ':')=
) {
+		rv =3D backend_parsedev(dev, getenv("currdev"), NULL);
+		if (rv =3D=3D 0 && path !=3D NULL)
+			*path =3D devspec;
+		return (rv);
+	}
+
+	/* Parse the device name off the beginning of the devspec. */
+	return (backend_parsedev(dev, devspec, path));
+}
+
+static void
+init(void)
+{
+	EFI_HANDLE h;
+        EFI_STATUS status;
+	u_int unit;
+        int i;
+	struct devsw *dev;
+	uint64_t pool_guid;
+        int (*old_getdev)(void **, const char *, const char **) =3D
+          archsw.arch_getdev;
+
+	archsw.arch_getdev =3D backend_getdev;
+#ifdef EFI_ZFS_BOOT
+	/* Note this needs to be set before ZFS init. */
+	archsw.arch_zfs_probe =3D efi_zfs_probe;
+#endif
+
+        /* Initialize all the backend drivers */
+	for (i =3D 0; backend_devsw[i] !=3D NULL; i++) {
+		if (backend_devsw[i]->dv_init !=3D NULL)
+			(backend_devsw[i]->dv_init)();
+        }
+
+        /* Attach SIMPLE_FILE_SYSTEM interfaces to all efipart devices *=
/
+	unit =3D 0;
+	h =3D efi_find_handle(&efipart_dev, 0);
+	for (i =3D 0; h !=3D NULL; h =3D efi_find_handle(&efipart_dev, ++i)) {
+		struct devdesc *currdev;
+
+                currdev =3D malloc(sizeof(struct devdesc));
+
+                if (currdev =3D=3D NULL) {
+                        continue;
+                }
+
+                if (efi_handle_lookup(h, &dev, &unit, &pool_guid) !=3D 0=
) {
+                        free(currdev);
+                        continue;
+                }
+
+		currdev->d_dev =3D dev;
+		currdev->d_unit =3D unit;
+		currdev->d_opendata =3D NULL;
+		currdev->d_type =3D currdev->d_dev->dv_type;
+
+                status =3D bind_iface(h, currdev);
+
+                if (EFI_ERROR(status) && status !=3D EFI_UNSUPPORTED &&
+                   status !=3D EFI_ACCESS_DENIED) {
+                         printf("Failed to attach filesystem interface t=
o efipart%u (%ld)\n",
+                                unit, EFI_ERROR_CODE(status));
+                         free(currdev);
+                }
+        }
+
+        /* Attach SIMPLE_FILE_SYSTEM interface to all ZFS devices */
+#ifdef EFI_ZFS_BOOT
+	unit =3D 0;
+	h =3D efi_find_handle(&zfs_dev, 0);
+	for (i =3D 0; h !=3D NULL; h =3D efi_find_handle(&zfs_dev, ++i)) {
+		struct zfs_devdesc *currdev;
+
+                currdev =3D malloc(sizeof(struct zfs_devdesc));
+
+                if (currdev =3D=3D NULL) {
+                        continue;
+                }
+
+                if (efi_handle_lookup(h, &dev, &unit, &pool_guid) !=3D 0=
) {
+                        free(currdev);
+                        continue;
+                }
+
+		currdev->d_dev =3D dev;
+		currdev->d_unit =3D unit;
+		currdev->d_opendata =3D NULL;
+		currdev->d_type =3D currdev->d_dev->dv_type;
+                currdev->pool_guid =3D pool_guid;
+                currdev->root_guid =3D 0;
+
+                status =3D bind_iface(h, (struct devdesc*)currdev);
+
+                if (EFI_ERROR(status)) {
+                  printf("Failed to attach filesystem interface to zfs%u=
 (%ld)\n",
+                         unit, EFI_ERROR_CODE(status));
+                }
+        }
+#endif
+        archsw.arch_getdev =3D old_getdev;
+}
+
+const efi_driver_t fs_driver =3D
+{
+	.name =3D "FS Backend",
+	.init =3D init,
+};
diff --git a/sys/boot/efi/include/efilib.h b/sys/boot/efi/include/efilib.=
h
index 09ccc2f..15d4b48 100644
--- a/sys/boot/efi/include/efilib.h
+++ b/sys/boot/efi/include/efilib.h
@@ -31,22 +31,26 @@
 #define	_LOADER_EFILIB_H
=20
 #include <stand.h>
+#include <time.h>
=20
 extern EFI_HANDLE		IH;
-extern EFI_SYSTEM_TABLE		*ST;
+extern EFI_SYSTEM_TABLE	*ST;
 extern EFI_BOOT_SERVICES	*BS;
 extern EFI_RUNTIME_SERVICES	*RS;
=20
-extern struct devsw efipart_dev;
+extern struct devsw efifs_dev;
 extern struct devsw efinet_dev;
+extern struct fs_ops efifs_fsops;
 extern struct netif_driver efinetif;
=20
 void *efi_get_table(EFI_GUID *tbl);
=20
 int efi_register_handles(struct devsw *, EFI_HANDLE *, EFI_HANDLE *, int=
);
+int efi_register_handle(struct devsw *, EFI_HANDLE, EFI_HANDLE);
 EFI_HANDLE efi_find_handle(struct devsw *, int);
 int efi_handle_lookup(EFI_HANDLE, struct devsw **, int *,  uint64_t *);
 int efi_handle_update_dev(EFI_HANDLE, struct devsw *, int, uint64_t);
+int efi_handle_remove_dev(EFI_HANDLE);
=20
 EFI_DEVICE_PATH *efi_lookup_image_devpath(EFI_HANDLE);
 EFI_DEVICE_PATH *efi_lookup_devpath(EFI_HANDLE);
@@ -57,6 +61,7 @@ CHAR16 *efi_devpath_name(EFI_DEVICE_PATH *);
 void efi_free_devpath_name(CHAR16 *);
=20
 int efi_status_to_errno(EFI_STATUS);
+EFI_STATUS errno_to_efi_status(int errno);
=20
 void efi_time_init(void);
 void efi_time_fini(void);
@@ -65,4 +70,7 @@ EFI_STATUS main(int argc, CHAR16 *argv[]);
 void exit(EFI_STATUS status);
 void delay(int usecs);
=20
+time_t from_efi_time(EFI_TIME *efi_time);
+void to_efi_time(EFI_TIME *efi_time, time_t time);
+
 #endif	/* _LOADER_EFILIB_H */
diff --git a/sys/boot/efi/include/efiprot.h b/sys/boot/efi/include/efipro=
t.h
index 28cec59..2221577 100644
--- a/sys/boot/efi/include/efiprot.h
+++ b/sys/boot/efi/include/efiprot.h
@@ -27,6 +27,8 @@ Revision History
=20
 --*/
=20
+#include <efidef.h>
+
 //
 // Device Path protocol
 //
@@ -307,9 +309,9 @@ typedef struct {
 //
 // The FileName field of the EFI_FILE_INFO data structure is variable le=
ngth.
 // Whenever code needs to know the size of the EFI_FILE_INFO data struct=
ure, it needs to
-// be the size of the data structure without the FileName field.  The fo=
llowing macro=20
+// be the size of the data structure without the FileName field.  The fo=
llowing macro
 // computes this size correctly no matter how big the FileName array is =
declared.
-// This is required to make the EFI_FILE_INFO data structure ANSI compil=
ant.=20
+// This is required to make the EFI_FILE_INFO data structure ANSI compil=
ant.
 //
=20
 #define SIZE_OF_EFI_FILE_INFO EFI_FIELD_OFFSET(EFI_FILE_INFO,FileName)
@@ -329,9 +331,9 @@ typedef struct {
 //
 // The VolumeLabel field of the EFI_FILE_SYSTEM_INFO data structure is v=
ariable length.
 // Whenever code needs to know the size of the EFI_FILE_SYSTEM_INFO data=
 structure, it needs
-// to be the size of the data structure without the VolumeLable field.  =
The following macro=20
+// to be the size of the data structure without the VolumeLable field.  =
The following macro
 // computes this size correctly no matter how big the VolumeLable array =
is declared.
-// This is required to make the EFI_FILE_SYSTEM_INFO data structure ANSI=
 compilant.=20
+// This is required to make the EFI_FILE_SYSTEM_INFO data structure ANSI=
 compilant.
 //
=20
 #define SIZE_OF_EFI_FILE_SYSTEM_INFO EFI_FIELD_OFFSET(EFI_FILE_SYSTEM_IN=
FO,VolumeLabel)
@@ -411,7 +413,7 @@ typedef struct {
     EFI_DEVICE_IO                   Write;
 } EFI_IO_ACCESS;
=20
-typedef=20
+typedef
 EFI_STATUS
 (EFIAPI *EFI_PCI_DEVICE_PATH) (
     IN struct _EFI_DEVICE_IO_INTERFACE  *This,
@@ -555,4 +557,47 @@ typedef struct _EFI_UNICODE_COLLATION_INTERFACE {
     CHAR8                               *SupportedLanguages;
 } EFI_UNICODE_COLLATION_INTERFACE;
=20
+//
+// Driver Binding protocol
+//
+
+#define DRIVER_BINDING_PROTOCOL \
+  { 0x18a031ab, 0xb443, 0x4d1a, {0xa5, 0xc0, 0x0c, 0x09, 0x26, 0x1e, 0x9=
f, 0x71} }
+
+INTERFACE_DECL(_EFI_DRIVER_BINDING);
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_DRIVER_BINDING_SUPPORTED) (
+    IN struct _EFI_DRIVER_BINDING *This,
+    IN EFI_HANDLE ControllerHandle,
+    IN EFI_DEVICE_PATH *RemainingPath
+    );
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_DRIVER_BINDING_START) (
+    IN struct _EFI_DRIVER_BINDING *This,
+    IN EFI_HANDLE ControllerHandle,
+    IN EFI_DEVICE_PATH *RemainingPath
+    );
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_DRIVER_BINDING_STOP) (
+    IN struct _EFI_DRIVER_BINDING *This,
+    IN EFI_HANDLE ControllerHandle,
+    IN UINTN NumberOfChildren,
+    IN EFI_HANDLE *ChildHandleBuffer
+    );
+
+typedef struct _EFI_DRIVER_BINDING {
+  EFI_DRIVER_BINDING_SUPPORTED Supported;
+  EFI_DRIVER_BINDING_START Start;
+  EFI_DRIVER_BINDING_STOP Stop;
+  UINT32 Version;
+  EFI_HANDLE ImageHandle;
+  EFI_HANDLE DriverBindingHandle;
+} EFI_DRIVER_BINDING;
+
 #endif
diff --git a/sys/boot/efi/include/string16.h b/sys/boot/efi/include/strin=
g16.h
new file mode 100644
index 0000000..5e4f9c1
--- /dev/null
+++ b/sys/boot/efi/include/string16.h
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 2016 Eric McCorkle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in th=
e
+ *    documentation and/or other materials provided with the distributio=
n.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AN=
D
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE=

+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PU=
RPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIAB=
LE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUE=
NTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOO=
DS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)=

+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, S=
TRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY=
 WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY O=
F
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _STRING16_H_
+#define _STRING16_H_
+
+#include <efi.h>
+#include <stddef.h>
+
+/*
+ * These are 16-bit variants of string,h functions for use with EFI code=
=2E
+ */
+
+extern size_t strlen16(const CHAR16 *str);
+extern CHAR16* strcpy16(CHAR16 *dst, const CHAR16 *src);
+extern CHAR16* stpcpy16(CHAR16 *dst, const CHAR16 *src);
+extern CHAR16* strcpy_to_16(CHAR16 *dst, const char *src);
+extern char* strcpy_from_16(char *dst, const CHAR16 *src);
+
+#endif
diff --git a/sys/boot/efi/libefi/Makefile b/sys/boot/efi/libefi/Makefile
index d9619be..8684403 100644
--- a/sys/boot/efi/libefi/Makefile
+++ b/sys/boot/efi/libefi/Makefile
@@ -10,8 +10,8 @@ LIB=3D	efi
 INTERNALLIB=3D
 WARNS?=3D	2
=20
-SRCS=3D	delay.c devpath.c efi_console.c efinet.c efipart.c errno.c \
-	handles.c libefi.c
+SRCS=3D	delay.c devpath.c efi_console.c efifs.c efinet.c env.c errno.c \=

+	handles.c libefi.c string16.c
=20
 .if ${MACHINE_CPUARCH} =3D=3D "amd64" || ${MACHINE_CPUARCH} =3D=3D "i386=
"
 SRCS+=3D	time.c
diff --git a/sys/boot/efi/libefi/efifs.c b/sys/boot/efi/libefi/efifs.c
new file mode 100644
index 0000000..dd9fb0f
--- /dev/null
+++ b/sys/boot/efi/libefi/efifs.c
@@ -0,0 +1,464 @@
+/*-
+ * Copyright (c) 2016 Eric McCorkle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in th=
e
+ *    documentation and/or other materials provided with the distributio=
n.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AN=
D
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE=

+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PU=
RPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIAB=
LE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUE=
NTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOO=
DS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)=

+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, S=
TRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY=
 WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY O=
F
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <efi.h>
+#include <efilib.h>
+#include <efiprot.h>
+#include <stand.h>
+#include <stdarg.h>
+#include <bootstrap.h>
+#include <string16.h>
+
+static EFI_GUID FileInfoGUID =3D EFI_FILE_INFO_ID;;
+static EFI_GUID SimpleFileSystemProtocolGUID =3D SIMPLE_FILE_SYSTEM_PROT=
OCOL;
+static EFI_GUID BlockIoProtocolGUID =3D BLOCK_IO_PROTOCOL;
+static EFI_GUID DevicePathGUID =3D DEVICE_PATH_PROTOCOL;
+
+static int efifs_open(const char *path, struct open_file *f);
+static int efifs_write(struct open_file *f, void *buf, size_t size, size=
_t *resid);
+static int efifs_close(struct open_file *f);
+static int efifs_read(struct open_file *f, void *buf, size_t size, size_=
t *resid);
+static off_t efifs_seek(struct open_file *f, off_t offset, int where);
+static int efifs_stat(struct open_file *f, struct stat *sb);
+static int efifs_readdir(struct open_file *f, struct dirent *d);
+
+static int efifs_dev_init(void);
+static int efifs_dev_strategy(void *, int, daddr_t, size_t, size_t, char=
 *, size_t *);
+static int efifs_dev_open(struct open_file *, ...);
+static int efifs_dev_close(struct open_file *);
+static int efifs_dev_print(int);
+
+struct devsw efifs_dev =3D {
+	.dv_name =3D "EFI",
+	.dv_type =3D DEVT_EFI,
+	.dv_init =3D efifs_dev_init,
+	.dv_strategy =3D efifs_dev_strategy,
+	.dv_open =3D efifs_dev_open,
+	.dv_close =3D efifs_dev_close,
+	.dv_ioctl =3D noioctl,
+	.dv_print =3D efifs_dev_print,
+	.dv_cleanup =3D NULL
+};
+
+struct fs_ops efifs_fsops =3D {
+	"EFI",
+	efifs_open,
+	efifs_close,
+	efifs_read,
+	efifs_write,
+	efifs_seek,
+	efifs_stat,
+	efifs_readdir
+};
+
+static int
+efifs_dev_init(void)
+{
+	EFI_HANDLE *hin;
+	EFI_STATUS status;
+	UINTN sz;
+	u_int n, nin, unit;
+	int err;
+
+	sz =3D 0;
+	hin =3D NULL;
+	status =3D BS->LocateHandle(ByProtocol, &SimpleFileSystemProtocolGUID,
+                                  0, &sz, 0);
+	if (status =3D=3D EFI_BUFFER_TOO_SMALL) {
+		hin =3D (EFI_HANDLE *)malloc(sz);
+		status =3D BS->LocateHandle(ByProtocol,
+                    &SimpleFileSystemProtocolGUID, 0, &sz, hin);
+		if (EFI_ERROR(status))
+			free(hin);
+	}
+	if (EFI_ERROR(status))
+		return (efi_status_to_errno(status));
+
+	/* Filter handles to only include FreeBSD partitions. */
+	nin =3D sz / sizeof(EFI_HANDLE);
+	unit =3D 0;
+
+	for (n =3D 0; n < nin; n++) {
+		status =3D BS->OpenProtocol(hin[n], &SimpleFileSystemProtocolGUID,
+                                          NULL, IH, NULL,
+                                          EFI_OPEN_PROTOCOL_TEST_PROTOCO=
L);
+		if (EFI_ERROR(status))
+			continue;
+
+                efi_handle_update_dev(hin[n], &efifs_dev, unit++, 0);
+	}
+
+	free(hin);
+	return (err);
+}
+
+
+static int
+efifs_dev_print(int verbose)
+{
+	char line[80];
+        EFI_DEVICE_PATH *devpath;
+        EFI_BLOCK_IO *blkio;
+	EFI_HANDLE h, *hin;
+	EFI_STATUS status;
+	u_int unit, n;
+
+	for (unit =3D 0, h =3D efi_find_handle(&efifs_dev, 0);
+	    h !=3D NULL; h =3D efi_find_handle(&efifs_dev, ++unit)) {
+		sprintf(line, "    %s%d:", efifs_dev.dv_name, unit);
+		pager_output(line);
+                pager_output("    EFI(SIMPLE_FILE_SYSTEM");
+
+		status =3D BS->HandleProtocol(hin[n], &DevicePathGUID,
+		    (void **)&devpath);
+		if (!EFI_ERROR(status)) {
+                        pager_output(", DEVICE_PATH");
+		}
+
+		status =3D BS->HandleProtocol(hin[n], &BlockIoProtocolGUID,
+		    (void **)&blkio);
+		if (!EFI_ERROR(status)) {
+                        pager_output(", BLOCK_IO");
+		}
+		pager_output(")\n");
+	}
+        return (0);
+}
+
+static int
+efifs_dev_open(struct open_file *f, ...)
+{
+	va_list args;
+	struct devdesc *dev;
+	EFI_FILE_IO_INTERFACE *fsiface;
+	EFI_HANDLE h;
+	EFI_STATUS status;
+
+	va_start(args, f);
+	dev =3D va_arg(args, struct devdesc*);
+	va_end(args);
+
+	h =3D efi_find_handle(&efifs_dev, dev->d_unit);
+
+	if (h =3D=3D NULL)
+		return (EINVAL);
+
+        status =3D BS->OpenProtocol(h, &SimpleFileSystemProtocolGUID,
+            (void**)&fsiface, IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);=

+
+        if (EFI_ERROR(status)) {
+		return (efi_status_to_errno(status));
+        }
+
+        dev->d_opendata =3D fsiface;
+	return (0);
+}
+
+static int
+efifs_dev_close(struct open_file *f)
+{
+	struct devdesc *dev;
+	EFI_HANDLE h;
+        EFI_STATUS status;
+
+	dev =3D (struct devdesc *)(f->f_devdata);
+	h =3D efi_find_handle(&efifs_dev, dev->d_unit);
+
+	if (h =3D=3D NULL)
+		return (EINVAL);
+
+	if (dev->d_opendata =3D=3D NULL)
+		return (EINVAL);
+
+        status =3D BS->CloseProtocol(h, &SimpleFileSystemProtocolGUID, I=
H, NULL);
+
+        if (EFI_ERROR(status))
+		return (efi_status_to_errno(status));
+
+	dev->d_opendata =3D NULL;
+	return (0);
+}
+
+
+/* Raw I/O isn't supported on EFI FS devices, as they talk through
+ * SIMPLE_FILE_SYSTEM_INTERFACE.
+ */
+static int
+efifs_dev_strategy(void *devdata __unused, int rw __unused, daddr_t blk =
__unused,
+                   size_t offset, size_t size __unused, char *buf __unus=
ed,
+                   size_t *rsize __unused)
+{
+        printf("Raw I/O not supported on EFI FS interface\n");
+	return ENOTSUP;
+}
+
+/*
+ * Open a file.
+ */
+static int
+efifs_open(const char *upath, struct open_file *f)
+{
+	struct devdesc *dev;
+	EFI_FILE_IO_INTERFACE *fsiface;
+	EFI_FILE_HANDLE root;
+        EFI_STATUS status;
+        CHAR16 path[strlen(upath) + 1];
+
+	dev =3D (struct devdesc *)(f->f_devdata);
+        fsiface =3D dev->d_opendata;
+
+        if (!strcmp(upath, "") || !strcmp(upath, "/")) {
+                return (fsiface->OpenVolume(fsiface,
+                                            (EFI_FILE_HANDLE*)&(f->f_fsd=
ata)));
+        } else {
+                status =3D fsiface->OpenVolume(fsiface, &root);
+
+                if (EFI_ERROR(status)) {
+                        return (efi_status_to_errno(status));
+                }
+
+                strcpy_to_16(path, upath);
+                status =3D root->Open(root, (EFI_FILE_HANDLE*)&(f->f_fsd=
ata), path,
+                                    EFI_FILE_MODE_READ, 0);
+
+                root->Close(root);
+
+                if (EFI_ERROR(status)) {
+                        return (efi_status_to_errno(status));
+                }
+
+                return 0;
+        }
+}
+
+static int
+efifs_close(struct open_file *f)
+{
+        EFI_FILE_HANDLE file =3D (EFI_FILE_HANDLE)f->f_fsdata;
+        EFI_STATUS status;
+
+        status =3D file->Close(file);
+
+        if (EFI_ERROR(status))
+		return (efi_status_to_errno(status));
+
+        return (0);
+}
+
+static int
+efifs_read(struct open_file *f, void *start, size_t size, size_t *resid =
/* out */)
+{
+        EFI_FILE_HANDLE file =3D (EFI_FILE_HANDLE)f->f_fsdata;
+        UINTN readsize =3D size;
+        EFI_STATUS status;
+
+        status =3D file->Read(file, &readsize, start);
+
+        if (EFI_ERROR(status))
+		return (efi_status_to_errno(status));
+
+	if (resid)
+		*resid =3D size - readsize;
+
+	return (0);
+}
+
+static int
+efifs_write(struct open_file *f, void *start, size_t size,
+            size_t *resid /* out */)
+{
+        EFI_FILE_HANDLE file =3D (EFI_FILE_HANDLE)f->f_fsdata;
+        UINTN writesize =3D size;
+        EFI_STATUS status;
+
+        status =3D file->Write(file, &writesize, start);
+
+        if (EFI_ERROR(status))
+		return (efi_status_to_errno(status));
+
+	if (resid)
+		*resid =3D size - writesize;
+
+	return (0);
+}
+
+static off_t
+efifs_seek(struct open_file *f, off_t offset, int where)
+{
+        EFI_FILE_HANDLE file =3D (EFI_FILE_HANDLE)f->f_fsdata;
+        UINT64 pos;
+        EFI_STATUS status;
+
+	switch (where) {
+	case SEEK_SET:
+                status =3D file->SetPosition(file, offset);
+
+                if (status !=3D EFI_SUCCESS) {
+                        errno =3D (efi_status_to_errno(status));
+                        return -1;
+                }
+
+		break;
+	case SEEK_CUR:
+                status =3D file->GetPosition(file, &pos);
+
+                if (status !=3D EFI_SUCCESS) {
+                        errno =3D (efi_status_to_errno(status));
+                        return -1;
+                }
+
+                status =3D file->SetPosition(file, pos + offset);
+
+                if (status !=3D EFI_SUCCESS) {
+                        errno =3D (efi_status_to_errno(status));
+                        return -1;
+                }
+
+		break;
+	case SEEK_END:
+                status =3D file->SetPosition(file, 0xffffffffffffffff);
+
+                if (status !=3D EFI_SUCCESS) {
+                        errno =3D (efi_status_to_errno(status));
+                        return -1;
+                }
+	default:
+		errno =3D EINVAL;
+		return (-1);
+	}
+
+        status =3D file->GetPosition(file, &pos);
+
+        if (status !=3D EFI_SUCCESS) {
+                errno =3D (efi_status_to_errno(status));
+                return -1;
+        }
+
+	return (pos);
+}
+
+/* SIMPLE_FILE_SYSTEM_PROTOCOL is geared towards FAT, so we can't
+ * reproduce stat with absolute fidelity.
+ */
+static int
+efifs_stat(struct open_file *f, struct stat *sb)
+{
+        EFI_FILE_HANDLE file;
+        UINTN size =3D 0;
+        EFI_FILE_INFO *finfo;;
+        EFI_STATUS status;
+
+        file =3D (EFI_FILE_HANDLE)f->f_fsdata;
+        status =3D file->GetInfo(file, &FileInfoGUID, &size, NULL);
+
+        if (status !=3D EFI_BUFFER_TOO_SMALL) {
+                errno =3D (efi_status_to_errno(status));
+                return -1;
+        }
+
+        finfo =3D malloc(size);
+        status =3D file->GetInfo(file, &FileInfoGUID, &size, finfo);
+
+        if (status !=3D EFI_SUCCESS) {
+                errno =3D (efi_status_to_errno(status));
+                return -1;
+        }
+
+        /* We can't properly fill these in... */
+        sb->st_ino =3D 0;
+        sb->st_nlink =3D 0;
+        sb->st_uid =3D 0;
+        sb->st_gid =3D 0;
+        sb->st_blksize =3D 512;
+        /* Build the mode field */
+        if (finfo->Attribute & EFI_FILE_DIRECTORY) {
+                sb->st_mode =3D S_IFDIR;
+        } else {
+                sb->st_mode =3D S_IFREG;
+        }
+
+        if (finfo->Attribute & EFI_FILE_MODE_READ) {
+          sb->st_mode =3D S_IRUSR | S_IXUSR | S_IRGRP |
+            S_IXGRP | S_IROTH | S_IXOTH;
+        }
+
+        if (finfo->Attribute & EFI_FILE_MODE_READ) {
+          sb->st_mode =3D S_IWUSR | S_IWGRP | S_IWOTH;
+        }
+        /* This may or may not be supported, depending on the FS driver =
*/
+        sb->st_blocks =3D finfo->PhysicalSize / 512;
+        /* These fields we can get right */
+        sb->st_size =3D finfo->FileSize;
+        sb->st_atime =3D from_efi_time(&(finfo->LastAccessTime));
+        sb->st_mtime =3D from_efi_time(&(finfo->ModificationTime));
+        sb->st_ctime =3D from_efi_time(&(finfo->CreateTime));
+
+        free(finfo);
+
+        return (0);
+}
+
+static int
+efifs_readdir(struct open_file *f, struct dirent *d)
+{
+        EFI_FILE_HANDLE file;
+        UINTN size =3D 0;
+        EFI_FILE_INFO *finfo;;
+        EFI_STATUS status;
+
+        file =3D (EFI_FILE_HANDLE)f->f_fsdata;
+        status =3D file->Read(file, &size, NULL);
+
+        if (status !=3D EFI_BUFFER_TOO_SMALL) {
+                errno =3D (efi_status_to_errno(status));
+                return -1;
+        }
+
+        if (size =3D=3D 0) {
+                return (ENOENT);
+        }
+
+        finfo =3D malloc(size);
+        status =3D file->Read(file, &size, finfo);
+
+        if (status !=3D EFI_SUCCESS) {
+                errno =3D (efi_status_to_errno(status));
+                return -1;
+        }
+
+        strcpy_from_16(d->d_name, finfo->FileName);
+        d->d_namlen =3D strlen(d->d_name);
+        d->d_reclen =3D sizeof(struct dirent);
+        /* We can't faithfully reproduce this due to the limitations
+         * of the SIMPLE_FILE_SYSTEM interface */
+        d->d_fileno =3D 0;
+
+        free(finfo);
+
+        return (0);
+}
diff --git a/sys/boot/efi/libefi/errno.c b/sys/boot/efi/libefi/errno.c
index fac903f..0f354c3 100644
--- a/sys/boot/efi/libefi/errno.c
+++ b/sys/boot/efi/libefi/errno.c
@@ -30,6 +30,69 @@ __FBSDID("$FreeBSD$");
 #include <efi.h>
 #include <efilib.h>
=20
+EFI_STATUS
+errno_to_efi_status(int errno)
+{
+        EFI_STATUS status;
+
+        switch (errno) {
+        case EPERM:
+                status =3D EFI_ACCESS_DENIED;
+                break;
+
+        case EOVERFLOW:
+                status =3D EFI_BUFFER_TOO_SMALL;
+                break;
+
+        case EIO:
+                status =3D EFI_DEVICE_ERROR;
+                break;
+
+        case EINVAL:
+                status =3D EFI_INVALID_PARAMETER;
+                break;
+
+        case ESTALE:
+                status =3D EFI_MEDIA_CHANGED;
+                break;
+
+        case ENXIO:
+                status =3D EFI_NO_MEDIA;
+                break;
+
+        case ENOENT:
+                status =3D EFI_NOT_FOUND;
+                break;
+
+        case ENOMEM:
+                status =3D EFI_OUT_OF_RESOURCES;
+                break;
+
+        case ENOTSUP:
+        case ENODEV:
+                status =3D EFI_UNSUPPORTED;
+                break;
+
+        case ENOSPC:
+                status =3D EFI_VOLUME_FULL;
+                break;
+
+        case EACCES:
+                status =3D EFI_WRITE_PROTECTED;
+                break;
+
+        case 0:
+                status =3D EFI_SUCCESS;
+                break;
+
+        default:
+                status =3D EFI_DEVICE_ERROR;
+                break;
+        }
+
+        return (status);
+}
+
 int
 efi_status_to_errno(EFI_STATUS status)
 {
diff --git a/sys/boot/efi/libefi/handles.c b/sys/boot/efi/libefi/handles.=
c
index 1e4ef6f..c118085 100644
--- a/sys/boot/efi/libefi/handles.c
+++ b/sys/boot/efi/libefi/handles.c
@@ -41,21 +41,36 @@ struct entry {
 struct entry *entry;
 int nentries;
=20
+static int
+get_next_unit(struct devsw *sw)
+{
+        int i, idx;
+
+        for (i =3D 0, idx =3D 0; i < nentries; i++) {
+                if (entry[i].dev =3D=3D sw) {
+                        idx++;
+                }
+        }
+
+        return (idx);
+}
+
 int
 efi_register_handles(struct devsw *sw, EFI_HANDLE *handles,
     EFI_HANDLE *aliases, int count)
 {
 	size_t sz;
-	int idx, unit;
+	int idx, unit, i;
=20
 	idx =3D nentries;
 	nentries +=3D count;
 	sz =3D nentries * sizeof(struct entry);
+        unit =3D get_next_unit(sw);
 	entry =3D (entry =3D=3D NULL) ? malloc(sz) : realloc(entry, sz);
-	for (unit =3D 0; idx < nentries; idx++, unit++) {
-		entry[idx].handle =3D handles[unit];
+	for (i =3D 0; idx < nentries; idx++, unit++, i++) {
+		entry[idx].handle =3D handles[i];
 		if (aliases !=3D NULL)
-			entry[idx].alias =3D aliases[unit];
+			entry[idx].alias =3D aliases[i];
 		else
 			entry[idx].alias =3D NULL;
 		entry[idx].dev =3D sw;
@@ -64,6 +79,16 @@ efi_register_handles(struct devsw *sw, EFI_HANDLE *han=
dles,
 	return (0);
 }
=20
+int
+efi_register_handle(struct devsw *sw, EFI_HANDLE handle, EFI_HANDLE alia=
s)
+{
+        if (alias =3D=3D NULL) {
+                return efi_register_handles(sw, &handle, NULL, 1);
+        } else {
+                return efi_register_handles(sw, &handle, &alias, 1);
+        }
+}
+
 EFI_HANDLE
 efi_find_handle(struct devsw *dev, int unit)
 {
@@ -116,3 +141,29 @@ efi_handle_update_dev(EFI_HANDLE h, struct devsw *de=
v, int unit,
=20
 	return (ENOENT);
 }
+
+int
+efi_handle_remove_dev(EFI_HANDLE h)
+{
+	int idx;
+
+        /* Find the entry */
+	for (idx =3D 0; idx < nentries; idx++) {
+		if (entry[idx].handle !=3D h)
+			continue;
+	}
+
+        if (idx >=3D nentries)
+                return (ENOENT);
+        else if (idx =3D=3D nentries - 1) {
+                nentries--;
+                entry =3D realloc(entry, nentries * sizeof(struct entry)=
);
+        } else {
+                memcpy(entry + idx, entry + idx + 1,
+                       sizeof(struct entry) * (nentries - (idx + 1)));
+                nentries--;
+                entry =3D realloc(entry, nentries * sizeof(struct entry)=
);
+        }
+
+        return (0);
+}
diff --git a/sys/boot/efi/libefi/string16.c b/sys/boot/efi/libefi/string1=
6.c
new file mode 100644
index 0000000..299d72d
--- /dev/null
+++ b/sys/boot/efi/libefi/string16.c
@@ -0,0 +1,88 @@
+/*-
+ * Copyright (c) 2016 Eric McCorkle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in th=
e
+ *    documentation and/or other materials provided with the distributio=
n.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AN=
D
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE=

+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PU=
RPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIAB=
LE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUE=
NTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOO=
DS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)=

+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, S=
TRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY=
 WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY O=
F
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include "string16.h"
+#include <stddef.h>
+
+size_t
+strlen16(const CHAR16 *str)
+{
+        size_t i;
+
+        for (i =3D 0; str[i] !=3D 0; i++);
+
+        return i;
+}
+
+CHAR16 *
+strcpy16(CHAR16 *dst, const CHAR16 *src)
+{
+        stpcpy16(dst, src);
+
+        return (dst);
+}
+
+CHAR16 *
+stpcpy16(CHAR16 *dst, const CHAR16 *src)
+{
+        for (; *src !=3D 0; src++, dst++) {
+                *dst =3D *src;
+        }
+
+        *dst =3D *src;
+
+        return dst;
+}
+
+char *
+strcpy_from_16(char *dst, const CHAR16 *src)
+{
+        int i;
+
+        for (i =3D 0; src[i] !=3D 0; i++) {
+                dst[i] =3D src[i];
+        }
+
+        dst[i] =3D 0;
+
+        return (dst);
+}
+
+CHAR16 *
+strcpy_to_16(CHAR16 *dst, const char *src)
+{
+        int i;
+
+        for (i =3D 0; src[i] !=3D 0; i++) {
+                dst[i] =3D src[i];
+        }
+
+        dst[i] =3D 0;
+
+        return (dst);
+}
diff --git a/sys/boot/efi/libefi/time.c b/sys/boot/efi/libefi/time.c
index 99831e1..2df466e 100644
--- a/sys/boot/efi/libefi/time.c
+++ b/sys/boot/efi/libefi/time.c
@@ -2,28 +2,28 @@
  * Copyright (c) 1999, 2000
  * Intel Corporation.
  * All rights reserved.
- *=20
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
- *=20
+ *
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
- *=20
+ *
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in th=
e
  *    documentation and/or other materials provided with the distributio=
n.
- *=20
+ *
  * 3. All advertising materials mentioning features or use of this softw=
are
  *    must display the following acknowledgement:
- *=20
+ *
  *    This product includes software developed by Intel Corporation and
  *    its contributors.
- *=20
+ *
  * 4. Neither the name of Intel Corporation or its contributors may be
  *    used to endorse or promote products derived from this software
  *    without specific prior written permission.
- *=20
+ *
  * THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION AND CONTRIBUTORS ``AS =
IS''
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,=
 THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PU=
RPOSE
@@ -35,7 +35,7 @@
  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWIS=
E)
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED O=
F
  * THE POSSIBILITY OF SUCH DAMAGE.
- *=20
+ *
  */
=20
 #include <sys/cdefs.h>
@@ -58,6 +58,41 @@ __FBSDID("$FreeBSD$");
 #define SECSPERHOUR ( 60*60 )
 #define SECSPERDAY	(24 * SECSPERHOUR)
=20
+/*
+//  These arrays give the cumulative number of days up to the first of t=
he
+//  month number used as the index (1 -> 12) for regular and leap years.=

+//  The value at index 13 is for the whole year.
+*/
+static const time_t CumulativeDays[2][14] =3D {
+  {0,
+   0,
+   31,
+   31 + 28,
+   31 + 28 + 31,
+   31 + 28 + 31 + 30,
+   31 + 28 + 31 + 30 + 31,
+   31 + 28 + 31 + 30 + 31 + 30,
+   31 + 28 + 31 + 30 + 31 + 30 + 31,
+   31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
+   31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
+   31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
+   31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
+   31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31 },
+  {0,
+   0,
+   31,
+   31 + 29,
+   31 + 29 + 31,
+   31 + 29 + 31 + 30,
+   31 + 29 + 31 + 30 + 31,
+   31 + 29 + 31 + 30 + 31 + 30,
+   31 + 29 + 31 + 30 + 31 + 30 + 31,
+   31 + 29 + 31 + 30 + 31 + 30 + 31 + 31,
+   31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
+   31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
+   31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
+   31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31 }};
+
 void
 efi_time_init(void)
 {
@@ -68,45 +103,46 @@ efi_time_fini(void)
 {
 }
=20
-static time_t
-efi_time(EFI_TIME *ETime)
+void
+to_efi_time(EFI_TIME *efi_time, time_t time)
 {
-    /*
-    //  These arrays give the cumulative number of days up to the first =
of the
-    //  month number used as the index (1 -> 12) for regular and leap ye=
ars.
-    //  The value at index 13 is for the whole year.
-    */
-    static time_t CumulativeDays[2][14] =3D {
-    {0,
-     0,
-     31,
-     31 + 28,
-     31 + 28 + 31,
-     31 + 28 + 31 + 30,
-     31 + 28 + 31 + 30 + 31,
-     31 + 28 + 31 + 30 + 31 + 30,
-     31 + 28 + 31 + 30 + 31 + 30 + 31,
-     31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
-     31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
-     31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
-     31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
-     31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31 },
-    {0,
-     0,
-     31,
-     31 + 29,
-     31 + 29 + 31,
-     31 + 29 + 31 + 30,
-     31 + 29 + 31 + 30 + 31,
-     31 + 29 + 31 + 30 + 31 + 30,
-     31 + 29 + 31 + 30 + 31 + 30 + 31,
-     31 + 29 + 31 + 30 + 31 + 30 + 31 + 31,
-     31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
-     31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
-     31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
-     31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31 }};
-
-    time_t  UTime;=20
+        if (time >=3D 0) {
+                for (efi_time->Year =3D 1970;
+                    time > CumulativeDays[isleap(efi_time->Year)][13] * =
SECSPERDAY;
+                    time -=3D CumulativeDays[isleap(efi_time->Year)][13]=
 * SECSPERDAY,
+                    efi_time->Year++);
+
+                for (efi_time->Month =3D 0;
+                    time > CumulativeDays[isleap(efi_time->Year)][efi_ti=
me->Month] *
+                      SECSPERDAY;
+                    efi_time->Month++);
+
+                time -=3D CumulativeDays[isleap(efi_time->Year)][efi_tim=
e->Month - 1] *
+                    SECSPERDAY;
+
+                for (efi_time->Day =3D 0; time > SECSPERDAY;
+                    time -=3D SECSPERDAY, efi_time->Day++);
+
+                for (efi_time->Hour =3D 0; time > SECSPERHOUR;
+                    time -=3D SECSPERHOUR, efi_time->Hour++);
+
+                for (efi_time->Minute =3D 0; time > 60;
+                    time -=3D 60, efi_time->Minute++);
+
+                efi_time->Second =3D time;
+                efi_time->Nanosecond =3D 0;
+                efi_time->TimeZone =3D 0;
+                efi_time->Daylight =3D 0;
+        } else {
+                memset(efi_time, 0, sizeof(EFI_TIME));
+        }
+}
+
+time_t
+from_efi_time(EFI_TIME *ETime)
+{
+
+    time_t  UTime;
     int     Year;
=20
     /*
@@ -134,7 +170,7 @@ efi_time(EFI_TIME *ETime)
     /*
     // UTime should now be set to 00:00:00 on Jan 1 of the file's year.
     //
-    // Months =20
+    // Months
     */
     UTime +=3D (CumulativeDays[isleap(ETime->Year)][ETime->Month] * SECS=
PERDAY);
=20
@@ -170,7 +206,7 @@ efi_time(EFI_TIME *ETime)
     	*/
     	UTime +=3D (ETime->TimeZone * 60);
     }
-   =20
+
     return UTime;
 }
=20
@@ -196,7 +232,7 @@ EFI_GetTimeOfDay(
 	//  Convert to UNIX time (ie seconds since the epoch
 	*/
=20
-	tp->tv_sec  =3D efi_time( &EfiTime );
+	tp->tv_sec  =3D from_efi_time( &EfiTime );
 	tp->tv_usec =3D 0; /* EfiTime.Nanosecond * 1000; */
=20
 	/*
@@ -221,7 +257,7 @@ time(time_t *tloc)
 {
 	struct timeval tv;
 	EFI_GetTimeOfDay(&tv, 0);
-=09
+
 	if (tloc)
 		*tloc =3D tv.tv_sec;
 	return tv.tv_sec;
diff --git a/sys/boot/efi/loader/Makefile b/sys/boot/efi/loader/Makefile
index d9d3532..300c65b 100644
--- a/sys/boot/efi/loader/Makefile
+++ b/sys/boot/efi/loader/Makefile
@@ -50,6 +50,7 @@ CWARNFLAGS.main.c+=3D	-Wno-format
 CFLAGS+=3D	-I${.CURDIR}
 CFLAGS+=3D	-I${.CURDIR}/arch/${MACHINE}
 CFLAGS+=3D	-I${.CURDIR}/../include
+CFLAGS+=3D	-I${.CURDIR}/../drivers
 CFLAGS+=3D	-I${.CURDIR}/../include/${MACHINE}
 CFLAGS+=3D	-I${.CURDIR}/../../../contrib/dev/acpica/include
 CFLAGS+=3D	-I${.CURDIR}/../../..
@@ -68,6 +69,8 @@ CFLAGS+=3D	-DNO_PCI -DEFI
 LIBSTAND=3D	${.OBJDIR}/../../../../lib/libstand/libstand.a
 .endif
=20
+LIBEFI_DRIVERS=3D	${.OBJDIR}/../drivers/libefi_drivers.a
+
 .if !defined(BOOT_HIDE_SERIAL_NUMBERS)
 # Export serial numbers, UUID, and asset tag from loader.
 CFLAGS+=3D -DSMBIOS_SERIAL_NUMBERS
@@ -150,9 +153,10 @@ loader.efi: ${PROG}
=20
 LIBEFI=3D		${.OBJDIR}/../libefi/libefi.a
=20
-DPADD=3D		${LIBFICL} ${LIBEFI} ${LIBFDT} ${LIBEFI_FDT} ${LIBSTAND} \
-		${LDSCRIPT}
-LDADD=3D		${LIBFICL} ${LIBEFI} ${LIBFDT} ${LIBEFI_FDT} ${LIBSTAND}
+DPADD=3D		${LIBFICL} ${LIBEFI} ${LIBEFI_DRIVERS} ${LIBFDT} ${LIBEFI_FDT}=
 \
+		${LIBSTAND} ${LDSCRIPT}
+LDADD=3D		${LIBFICL} ${LIBEFI} ${LIBEFI_DRIVERS} ${LIBFDT} ${LIBEFI_FDT}=
 \
+		${LIBSTAND}
=20
 .include <bsd.prog.mk>
=20
diff --git a/sys/boot/efi/loader/conf.c b/sys/boot/efi/loader/conf.c
index 3596a63..56733ff 100644
--- a/sys/boot/efi/loader/conf.c
+++ b/sys/boot/efi/loader/conf.c
@@ -31,30 +31,22 @@ __FBSDID("$FreeBSD$");
 #include <bootstrap.h>
 #include <efi.h>
 #include <efilib.h>
-#ifdef EFI_ZFS_BOOT
-#include <libzfs.h>
-#endif
+
+#include "efi_drivers.h"
+
+const efi_driver_t *efi_drivers[] =3D {
+        &fs_driver,
+        NULL
+};
=20
 struct devsw *devsw[] =3D {
-	&efipart_dev,
+        &efifs_dev,
 	&efinet_dev,
-#ifdef EFI_ZFS_BOOT
-	&zfs_dev,
-#endif
 	NULL
 };
=20
 struct fs_ops *file_system[] =3D {
-#ifdef EFI_ZFS_BOOT
-	&zfs_fsops,
-#endif
-	&dosfs_fsops,
-	&ufs_fsops,
-	&cd9660_fsops,
-	&tftp_fsops,
-	&nfs_fsops,
-	&gzipfs_fsops,
-	&bzipfs_fsops,
+        &efifs_fsops,
 	NULL
 };
=20
diff --git a/sys/boot/efi/loader/loader_efi.h b/sys/boot/efi/loader/loade=
r_efi.h
index ee7c4bb..dbd36bf 100644
--- a/sys/boot/efi/loader/loader_efi.h
+++ b/sys/boot/efi/loader/loader_efi.h
@@ -33,6 +33,10 @@
=20
 #include <stand.h>
=20
+#include "efi_drivers.h"
+
+extern const efi_driver_t *efi_drivers[];
+
 int	efi_autoload(void);
=20
 int	efi_getdev(void **vdev, const char *devspec, const char **path);
diff --git a/sys/boot/efi/loader/main.c b/sys/boot/efi/loader/main.c
index b97f2af..42e3ebe1 100644
--- a/sys/boot/efi/loader/main.c
+++ b/sys/boot/efi/loader/main.c
@@ -87,10 +87,6 @@ EFI_GUID debugimg =3D DEBUG_IMAGE_INFO_TABLE_GUID;
 EFI_GUID fdtdtb =3D FDT_TABLE_GUID;
 EFI_GUID inputid =3D SIMPLE_TEXT_INPUT_PROTOCOL;
=20
-#ifdef EFI_ZFS_BOOT
-static void efi_zfs_probe(void);
-#endif
-
 /*
  * cpy8to16 copies a traditional C string into a CHAR16 string and
  * 0 terminates it. len is the size of *dst in bytes.
@@ -125,7 +121,7 @@ has_keyboard(void)
 	EFI_HANDLE *hin, *hin_end, *walker;
 	UINTN sz;
 	int retval =3D 0;
-=09
+
 	/*
 	 * Find all the handles that support the SIMPLE_TEXT_INPUT_PROTOCOL and=

 	 * do the typical dance to get the right sized buffer.
@@ -182,7 +178,7 @@ has_keyboard(void)
 			} else if (DevicePathType(path) =3D=3D MESSAGING_DEVICE_PATH &&
 			    DevicePathSubType(path) =3D=3D MSG_USB_CLASS_DP) {
 				USB_CLASS_DEVICE_PATH *usb;
-			      =20
+
 				usb =3D (USB_CLASS_DEVICE_PATH *)(void *)path;
 				if (usb->DeviceClass =3D=3D 3 && /* HID */
 				    usb->DeviceSubClass =3D=3D 1 && /* Boot devices */
@@ -263,10 +259,6 @@ main(int argc, CHAR16 *argv[])
 	archsw.arch_copyin =3D efi_copyin;
 	archsw.arch_copyout =3D efi_copyout;
 	archsw.arch_readin =3D efi_readin;
-#ifdef EFI_ZFS_BOOT
-	/* Note this needs to be set before ZFS init. */
-	archsw.arch_zfs_probe =3D efi_zfs_probe;
-#endif
=20
 	/* Init the time source */
 	efi_time_init();
@@ -391,6 +383,10 @@ main(int argc, CHAR16 *argv[])
 	/*
 	 * March through the device switch probing for things.
 	 */
+	for (i =3D 0; efi_drivers[i] !=3D NULL; i++)
+		if (efi_drivers[i]->init !=3D NULL)
+			(efi_drivers[i]->init)();
+
 	for (i =3D 0; devsw[i] !=3D NULL; i++)
 		if (devsw[i]->dv_init !=3D NULL)
 			(devsw[i]->dv_init)();
@@ -427,6 +423,7 @@ main(int argc, CHAR16 *argv[])
 	if (find_currdev(img, &dev, &unit, &pool_guid) !=3D 0)
 		return (EFI_NOT_FOUND);
=20
+        printf("Found efi device under %s\n", dev->dv_name);
 	switch (dev->dv_type) {
 #ifdef EFI_ZFS_BOOT
 	case DEVT_ZFS: {
@@ -1093,23 +1090,3 @@ command_fdt(int argc, char *argv[])
=20
 COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt);
 #endif
-
-#ifdef EFI_ZFS_BOOT
-static void
-efi_zfs_probe(void)
-{
-	EFI_HANDLE h;
-	u_int unit;
-	int i;
-	char dname[SPECNAMELEN + 1];
-	uint64_t guid;
-
-	unit =3D 0;
-	h =3D efi_find_handle(&efipart_dev, 0);
-	for (i =3D 0; h !=3D NULL; h =3D efi_find_handle(&efipart_dev, ++i)) {
-		snprintf(dname, sizeof(dname), "%s%d:", efipart_dev.dv_name, i);
-		if (zfs_probe_dev(dname, &guid) =3D=3D 0)
-			(void)efi_handle_update_dev(h, &zfs_dev, unit++, guid);
-	}
-}
-#endif

--------------689B5840033FA59B553C984F--

--7wWD2JXas7wNKFk1Kr7Jd8JHbiuG3wULI--

--2nIKx7PRAmhO47MXFmT0MDKUV6UMsh1v9
Content-Type: application/pgp-signature; name="signature.asc"
Content-Description: OpenPGP digital signature
Content-Disposition: attachment; filename="signature.asc"

-----BEGIN PGP SIGNATURE-----

iF4EARYIAAYFAlhBqUEACgkQVsKIQKqABI0NwwD+O1MDmogaR5FqsK+h8rSwmZNi
dwlYfTF2UPTht+5a2o4A/jhsOjEJ94T0YMrmbe2ly2cq708HCkidkkRtMjE/CbwM
=gnu+
-----END PGP SIGNATURE-----

--2nIKx7PRAmhO47MXFmT0MDKUV6UMsh1v9--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?d3aad5ef-2d6c-3d79-0fe8-91ee086ed2f8>