summaryrefslogtreecommitdiffstats
path: root/sys/boot/efi/loader
diff options
context:
space:
mode:
authorsmh <smh@FreeBSD.org>2016-01-15 02:33:47 +0000
committersmh <smh@FreeBSD.org>2016-01-15 02:33:47 +0000
commit6ae16528e7c8ff4e67aaf8484925db9c31b61246 (patch)
treeffe4426159f416d44f69c0ad8a2d289077eea9ac /sys/boot/efi/loader
parent532a8c64da1f6ab1b23700919a2199a3a5f98b72 (diff)
downloadFreeBSD-src-6ae16528e7c8ff4e67aaf8484925db9c31b61246.zip
FreeBSD-src-6ae16528e7c8ff4e67aaf8484925db9c31b61246.tar.gz
Add EFI ZFS boot support
This builds on the modular EFI loader support added r294060 adding a module to provide ZFS boot support on EFI systems. It should be noted that EFI uses a fixed size memory block for all allocations performed by the loader so it may be necessary to tune this size. For example when building an image which uses mfs_root e.g. mfsbsd, adding the following to /etc/make.conf would be needed to prevent EFI from running out of memory when loading the mfs_root image. EFI_STAGING_SIZE=128 Submitted by: Eric McCorkle MFC after: 2 weeks X-MFC-With: r293268 Sponsored by: Multiplay
Diffstat (limited to 'sys/boot/efi/loader')
-rw-r--r--sys/boot/efi/loader/Makefile15
-rw-r--r--sys/boot/efi/loader/conf.c9
-rw-r--r--sys/boot/efi/loader/devicename.c24
-rw-r--r--sys/boot/efi/loader/main.c75
4 files changed, 122 insertions, 1 deletions
diff --git a/sys/boot/efi/loader/Makefile b/sys/boot/efi/loader/Makefile
index 59d32ff..d36e54b 100644
--- a/sys/boot/efi/loader/Makefile
+++ b/sys/boot/efi/loader/Makefile
@@ -21,6 +21,16 @@ SRCS= autoload.c \
smbios.c \
vers.c
+.if ${MK_ZFS} != "no"
+SRCS+= zfs.c
+.PATH: ${.CURDIR}/../../zfs
+
+# Disable warnings that are currently incompatible with the zfs boot code
+CWARNFLAGS.zfs.c+= -Wno-sign-compare
+CWARNFLAGS.zfs.c+= -Wno-array-bounds
+CWARNFLAGS.zfs.c+= -Wno-missing-prototypes
+.endif
+
.PATH: ${.CURDIR}/arch/${MACHINE}
# For smbios.c
.PATH: ${.CURDIR}/../../i386/libi386
@@ -33,6 +43,11 @@ CFLAGS+= -I${.CURDIR}/../include/${MACHINE}
CFLAGS+= -I${.CURDIR}/../../../contrib/dev/acpica/include
CFLAGS+= -I${.CURDIR}/../../..
CFLAGS+= -I${.CURDIR}/../../i386/libi386
+.if ${MK_ZFS} != "no"
+CFLAGS+= -I${.CURDIR}/../../zfs
+CFLAGS+= -I${.CURDIR}/../../../cddl/boot/zfs
+CFLAGS+= -DEFI_ZFS_BOOT
+.endif
CFLAGS+= -DNO_PCI -DEFI
# make buildenv doesn't set DESTDIR, this means LIBSTAND
diff --git a/sys/boot/efi/loader/conf.c b/sys/boot/efi/loader/conf.c
index 8bb9d5f..ecbf8b0 100644
--- a/sys/boot/efi/loader/conf.c
+++ b/sys/boot/efi/loader/conf.c
@@ -31,14 +31,23 @@ __FBSDID("$FreeBSD$");
#include <bootstrap.h>
#include <efi.h>
#include <efilib.h>
+#ifdef EFI_ZFS_BOOT
+#include <libzfs.h>
+#endif
struct devsw *devsw[] = {
&efipart_dev,
&efinet_dev,
+#ifdef EFI_ZFS_BOOT
+ &zfs_dev,
+#endif
NULL
};
struct fs_ops *file_system[] = {
+#ifdef EFI_ZFS_BOOT
+ &zfs_fsops,
+#endif
&dosfs_fsops,
&ufs_fsops,
&cd9660_fsops,
diff --git a/sys/boot/efi/loader/devicename.c b/sys/boot/efi/loader/devicename.c
index c6591c8..8fc80eb 100644
--- a/sys/boot/efi/loader/devicename.c
+++ b/sys/boot/efi/loader/devicename.c
@@ -33,6 +33,9 @@ __FBSDID("$FreeBSD$");
#include <sys/disklabel.h>
#include <sys/param.h>
#include <bootstrap.h>
+#ifdef EFI_ZFS_BOOT
+#include <libzfs.h>
+#endif
#include <efi.h>
#include <efilib.h>
@@ -104,6 +107,23 @@ efi_parsedev(struct devdesc **dev, const char *devspec, const char **path)
np = devspec + strlen(dv->dv_name);
+#ifdef EFI_ZFS_BOOT
+ if (dv->dv_type == DEVT_ZFS) {
+ int err;
+
+ idev = malloc(sizeof(struct zfs_devdesc));
+ if (idev == NULL)
+ return (ENOMEM);
+
+ err = zfs_parsedev((struct zfs_devdesc*)idev, np, path);
+ if (err != 0) {
+ free(idev);
+ return (err);
+ }
+ *dev = idev;
+ cp = strchr(np + 1, ':');
+ } else
+#endif
{
idev = malloc(sizeof(struct devdesc));
if (idev == NULL)
@@ -143,6 +163,10 @@ efi_fmtdev(void *vdev)
static char buf[SPECNAMELEN + 1];
switch(dev->d_type) {
+#ifdef EFI_ZFS_BOOT
+ case DEVT_ZFS:
+ return (zfs_fmtdev(dev));
+#endif
case DEVT_NONE:
strcpy(buf, "(no device)");
break;
diff --git a/sys/boot/efi/loader/main.c b/sys/boot/efi/loader/main.c
index 43a015d..4ba42d9 100644
--- a/sys/boot/efi/loader/main.c
+++ b/sys/boot/efi/loader/main.c
@@ -39,6 +39,10 @@ __FBSDID("$FreeBSD$");
#include <bootstrap.h>
#include <smbios.h>
+#ifdef EFI_ZFS_BOOT
+#include <libzfs.h>
+#endif
+
#include "loader_efi.h"
extern char bootprog_name[];
@@ -61,6 +65,10 @@ EFI_GUID memtype = MEMORY_TYPE_INFORMATION_TABLE_GUID;
EFI_GUID debugimg = DEBUG_IMAGE_INFO_TABLE_GUID;
EFI_GUID fdtdtb = FDT_TABLE_GUID;
+#ifdef EFI_ZFS_BOOT
+static void efi_zfs_probe(void);
+#endif
+
/*
* Need this because EFI uses UTF-16 unicode string constants, but we
* use UTF-8. We can't use printf due to the possiblity of \0 and we
@@ -83,6 +91,7 @@ main(int argc, CHAR16 *argv[])
EFI_GUID *guid;
int i, j, vargood, unit;
struct devsw *dev;
+ uint64_t pool_guid;
UINTN k;
archsw.arch_autoload = efi_autoload;
@@ -90,6 +99,10 @@ main(int argc, CHAR16 *argv[])
archsw.arch_copyin = efi_copyin;
archsw.arch_copyout = efi_copyout;
archsw.arch_readin = efi_readin;
+#ifdef EFI_ZFS_BOOT
+ /* Note this needs to be set before ZFS init. */
+ archsw.arch_zfs_probe = efi_zfs_probe;
+#endif
/*
* XXX Chicken-and-egg problem; we want to have console output
@@ -168,10 +181,27 @@ main(int argc, CHAR16 *argv[])
*/
BS->SetWatchdogTimer(0, 0, 0, NULL);
- if (efi_handle_lookup(img->DeviceHandle, &dev, &unit) != 0)
+ if (efi_handle_lookup(img->DeviceHandle, &dev, &unit, &pool_guid) != 0)
return (EFI_NOT_FOUND);
switch (dev->dv_type) {
+#ifdef EFI_ZFS_BOOT
+ case DEVT_ZFS: {
+ struct zfs_devdesc currdev;
+
+ currdev.d_dev = dev;
+ currdev.d_unit = unit;
+ currdev.d_type = currdev.d_dev->dv_type;
+ currdev.d_opendata = NULL;
+ currdev.pool_guid = pool_guid;
+ currdev.root_guid = 0;
+ env_setenv("currdev", EV_VOLATILE, efi_fmtdev(&currdev),
+ efi_setcurrdev, env_nounset);
+ env_setenv("loaddev", EV_VOLATILE, efi_fmtdev(&currdev), env_noset,
+ env_nounset);
+ break;
+ }
+#endif
default: {
struct devdesc currdev;
@@ -456,6 +486,29 @@ command_nvram(int argc, char *argv[])
return (CMD_OK);
}
+#ifdef EFI_ZFS_BOOT
+COMMAND_SET(lszfs, "lszfs", "list child datasets of a zfs dataset",
+ command_lszfs);
+
+static int
+command_lszfs(int argc, char *argv[])
+{
+ int err;
+
+ if (argc != 2) {
+ command_errmsg = "wrong number of arguments";
+ return (CMD_ERROR);
+ }
+
+ err = zfs_list(argv[1]);
+ if (err != 0) {
+ command_errmsg = strerror(err);
+ return (CMD_ERROR);
+ }
+ return (CMD_OK);
+}
+#endif
+
#ifdef LOADER_FDT_SUPPORT
extern int command_fdt_internal(int argc, char *argv[]);
@@ -474,3 +527,23 @@ command_fdt(int argc, char *argv[])
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 = 0;
+ h = efi_find_handle(&efipart_dev, 0);
+ for (i = 0; h != NULL; h = efi_find_handle(&efipart_dev, ++i)) {
+ snprintf(dname, sizeof(dname), "%s%d:", efipart_dev.dv_name, i);
+ if (zfs_probe_dev(dname, &guid) == 0)
+ (void)efi_handle_update_dev(h, &zfs_dev, unit++, guid);
+ }
+}
+#endif
OpenPOWER on IntegriCloud